From 15f2c6c0bacd6cdf19e79c3f668cd706a899318e Mon Sep 17 00:00:00 2001 From: balakrishna-deriv <56330681+balakrishna-deriv@users.noreply.github.com> Date: Thu, 10 Aug 2023 11:50:32 +0800 Subject: [PATCH 01/16] Bala/Flutter charts integration setup (#1325) * chore: remove chartiq * chore: add adapter store * refactor timeperiod * chore: add more calls in the adapter * fix chartType * savetoLocalstorage * chore: remove unwanted fn * update context * chore: remove stx * chore: update feed calls * chore: remove unused core * remove few props from timestore * chore: remove unused code * chore: remove chartiq related code * chore: store changes * chore: barriers integration #1 * remove barriers and integrate it with flutter * fix: last digit * feat: markers integration * chore: fix fast markers * feat: add crosshair integration * chore: set crosshair cursor * chore: fix crosshair hover * chore: add ignore css * Revert "remove barriers and integrate it with flutter" This reverts commit b043b2519d1dcf884d3db40c7b6036773cd23934. * chore: barrier integration * chore: fix digits markers placement * fix: check chart load state * fix: get interpolated tick * chore: add dataFitEnabled flag * chore: fix chart adapter granularity * chore: update isLive & dateFitEnabled * chore: add actions * fix: duplicate tick * add indicator config * add guid * feat: indicators integration * chore: transform color codes * fix: download as png and csv * refactor: use html2canvas from npm * fix: indicator configs * refactor: chart adapter store * refactor: chart interops * chore: update chart props and fix studies * refactor: remove current spot * chore: remove stx * chore: add flutter chart app * remove: chartiq scripts * chore: add chart_app to git * chore: integrate more chart types * chore: fix chart type and theme on int * chore: add indicator bars * add ma and fieldtype short code * feat: add indicator options * chore: update crosshair visibility * chore: cleanup crosshair and fix issues * chore: fix warnings * refactor * chore: remove chartiq injections * chore: trackpad zoom * chore: fix time store * chore: add documentation * refactor: currentClsoe * refactor: stores * refactor: remove ciq refs * chore: update webpack and assets * chore: format sass files * chore: remove inline source map * fix: more bugs * chore: add copy pattern * fix: contract replay request and remove comparison data * chore: follow mode check * fix: empty granularity set * fix: review comments * fix: bottom widgets height * update name id to flutter_chart_id * refactor: change name to flutter_chart_id * chore: remove console * add shortname * refactor: move web related painters * refactor: move marker icon painters * refactor: move marker painting to smartcharts * refactor: add web marker * delete studies by index * chore: add custom color for marker * chore: update marker paintings * feat: accumulators painter * chore: update color from string * restore layout after the chart is loaded * fix: restore chart * chore: add marker type * add hasPersistentBorders config * move isChartLoaded * add maxCurrentTickOffset * fix: late initialization error * fix dart issues * fix: unsubscribe issue * gator series * add macd config * chore: add indicator options * refactor: getDrawTools to func * refactor: indicator configs * fix: chartType change to undefined * fix: granularity issue * new layout id * chore: remove CIQ * chore: remove unused script * refactor: adjust timer * move epoch conversion * chore: add title * feat: add expand/collapse and move icons * fix: indicator removal and title * refactor: cleanup * refactor: add_ons_repository * fix: crosshair on restore * chore: fix drawing tools icon in the main screen * feat: add scale and scroll * chore: prevent zooming on barriers * chore: customize msPerPx and leftMargin * chore: fix clear all indicators * chore: add clear all indicators function * chore: add rainbow colors * refactor: indicators and add tooltip * fix: tooltip bugs * refoctor: fix typo and add gator tooltip * chore: add macd tooltips and refactor * chore: add smi tooltip values * chore: add indicators * fix: index out of bound exception * chore: switch theme for indicators * fix: tslint issue * fix: channel fix and donchian * chore: add pipsize * fix: indicator bugs * chore: change to upper case * fix: feed issue for 2 second intervals * fix: crosshair decimal places * fix: new tick barrier * chore: fix dark theme container * fix: high/low barrier width * fix: feed issue * chore: fix draggable barrier * chore: fix barrier issues and symbol close * refactor: helpers * fix: price line width * fix: price line width * fix: chart live status update on contract close * chore: fix chart close issue * chore: remove lodash dependency * chore: add showLastIndicator config * chore: add decimal places for indicator tooltip content * fix: adx indicator config * refactor: initial chart data loaded * chore: set initial chart data * chore: add mount prop * chore: add yAxisWidth to api * refactor: chart_app * refactor: chart app * chore: pass isMobile to drawings * fix: indicator index and accumulator drawing * chore: fix streams * fix: feed issue * refactor: controller functions * refactor: scale * fix: prevent datafit contract from being scrolled * chore: add chart margin * fix: tick contract issue * fix: vertical padding fraction * fix: granularity issues * fix: offset issue * chore: reset msPerPx on granularity change * fix: chart type change reaction * fix: chart type issue * fix: contract close reload issue * chore: paint on each line series paint * fix: late init * fix: template restore * chore: ignore chart_app bundle * fix: min interval width * chore: fix tick animation in data fit mode * chore: fix data fit mode in 2s ticks * fix: accumulator height offset * fix: alternative source * refactor: controller getter * fix: field options * chore: check granularity for chart style * refactor: accumulator contract painting * chore: add fast marker limit * chore: add fast marker limit #2 * chore: add wrapper controller * chore: add PainterProps * chore: add opacity and zoom * fix: font size * fix: types * fix: lint errors * fix: eslint errors * chore: refactor chart controller * fix: catch all errors * chore: add binary search * fix: crosshair position * chore: add max interval width for candles style * chore: add webpack ignore * chore: simplify network reconnect * chore: add loading animation color * chore: fix mobile scaling * chore: remove touch listeners * chore: add scroll to recent component * chore: add crosshair getter functions * chore: indicator index * chore: clamp deltaY values to fix scaling on wheel * chore: add rainbow line styles --------- Co-authored-by: balakrishna-binary <56330681+balakrishna-binary@users.noreply.github.com> --- .eslintignore | 1 - .gitignore | 2 + .npmignore | 2 +- .stylelintrc | 225 +- app/index.html | 34 +- app/index.tsx | 14 +- app/test.tsx | 9 +- chart_app/.gitignore | 107 + chart_app/.metadata | 10 + chart_app/README.md | 16 + chart_app/analysis_options.yaml | 4 + chart_app/lib/main.dart | 277 + .../lib/src/add_ons/add_ons_repository.dart | 95 + chart_app/lib/src/chart_app.dart | 101 + chart_app/lib/src/helpers/chart.dart | 22 + chart_app/lib/src/helpers/color.dart | 49 + chart_app/lib/src/helpers/marker_painter.dart | 19 + chart_app/lib/src/helpers/series.dart | 45 + chart_app/lib/src/interop/dart_interop.dart | 202 + chart_app/lib/src/interop/js_interop.dart | 183 + .../paint_functions/paint_end_marker.dart | 96 + .../paint_functions/paint_start_line.dart | 37 + .../paint_functions/paint_start_marker.dart | 22 + .../paint_functions/paint_vertical_line.dart | 27 + chart_app/lib/src/markers/marker_group.dart | 46 + .../markers/marker_group_icon_painter.dart | 29 + .../lib/src/markers/marker_group_painter.dart | 58 + .../lib/src/markers/marker_group_series.dart | 62 + .../accumulator_marker_icon_painter.dart | 245 + .../digit_marker_icon_painter.dart | 163 + .../tick_marker_icon_painter.dart | 220 + chart_app/lib/src/markers/painter_props.dart | 14 + chart_app/lib/src/markers/web_marker.dart | 61 + .../lib/src/misc/crosshair_controller.dart | 64 + .../lib/src/misc/wrapped_controller.dart | 119 + chart_app/lib/src/models/chart_config.dart | 158 + chart_app/lib/src/models/chart_feed.dart | 104 + chart_app/lib/src/models/indicators.dart | 356 + .../lib/src/painters/custom_line_painter.dart | 21 + .../src/series/current_tick_indicator.dart | 21 + .../lib/src/series/custom_line_series.dart | 23 + chart_app/pubspec.yaml | 25 + chart_app/web/favicon.png | Bin 0 -> 917 bytes chart_app/web/index.html | 100 + chart_app/web/manifest.json | 12 + chartiq/development/index.js | 5 - chartiq/development/js/addOns.js | 4982 --- chartiq/development/js/advanced.js | 16390 ---------- chartiq/development/js/chartiq.js | 22205 -------------- chartiq/development/js/deprecated.js | 2864 -- chartiq/development/js/standard.js | 25348 ---------------- chartiq/hammer.js | 6 - chartiq/html2canvas.min.js | 20 - chartiq/intl.js | 2952 -- chartiq/production/index.js | 5 - chartiq/production/js/addOns.js | 4982 --- chartiq/production/js/advanced.js | 25 - chartiq/production/js/chartiq.js | 88 - chartiq/production/js/deprecated.js | 2864 -- chartiq/production/js/standard.js | 25 - chartiq/splines.js | 129 - declarations.d.ts | 1 - package-lock.json | 20885 ++++++++++++- package.json | 4 + sass/components/_barrier.scss | 28 +- sass/components/_crosshair.scss | 86 +- sass/components/_toolbar-widget.scss | 1 - sass/styles/chart.scss | 345 +- sass/styles/main.scss | 27 +- scripts/extract-indicator-translations.js | 21 - src/Constant.tsx | 1749 +- src/SplinePlotter.ts | 95 - src/binaryapi/ActiveSymbols.ts | 45 +- src/binaryapi/BinaryAPI.ts | 2 +- src/chartiq_injections/backingStore.ts | 37 - src/chartiq_injections/calculateAwesome.ts | 31 - src/chartiq_injections/createXAxis.ts | 13 - src/chartiq_injections/currentHR.ts | 98 - .../drawingClickChartEngine.ts | 54 - src/chartiq_injections/findHighlights.ts | 545 - src/chartiq_injections/headsUpHR.ts | 11 - src/chartiq_injections/index.ts | 38 - .../manageMasterDataLength.ts | 15 - src/chartiq_injections/plotterDrawText.ts | 37 - src/chartiq_injections/renderChannel.ts | 49 - src/chartiq_injections/renderEllipse.ts | 55 - src/chartiq_injections/renderGartley.ts | 86 - src/chartiq_injections/renderPitchfork.ts | 64 - src/chartiq_injections/renderRectangle.ts | 53 - src/chartiq_injections/renderSegment.ts | 92 - src/chartiq_injections/resizeObserver.ts | 38 - src/chartiq_injections/setMeasure.ts | 95 - src/components/Barrier.tsx | 15 +- src/components/BottomWidgetsContainer.tsx | 8 +- src/components/Chart.tsx | 30 +- src/components/ChartMode.tsx | 9 +- src/components/ChartTypes.tsx | 4 +- src/components/Crosshair.tsx | 53 +- src/components/DrawTools.tsx | 8 +- src/components/FastMarker.tsx | 103 +- src/components/Form.tsx | 34 +- src/components/NavigationWidget.tsx | 15 +- src/components/PriceLine.tsx | 8 +- src/components/RawMarker.tsx | 166 - src/components/RenderInsideChart.tsx | 7 +- src/components/ScrollToRecent.tsx | 35 + src/components/SettingsDialog.tsx | 141 +- src/components/StudyLegend.tsx | 119 +- src/components/Timeperiod.tsx | 40 +- .../categoricaldisplay/FilterPanel.tsx | 49 +- .../categoricaldisplay/ResultsPanel.tsx | 4 +- src/components/ui/Animation.ts | 339 - src/components/ui/Context.ts | 86 +- src/components/ui/Helper.ts | 41 - src/components/ui/Keystroke.ts | 226 - src/components/ui/KeystrokeHub.ts | 173 - src/components/ui/utils.ts | 16 + src/feed/Feed.ts | 406 +- src/feed/TickHistoryFormatter.ts | 28 +- src/feed/subscription/DelayedSubscription.ts | 5 +- src/feed/subscription/RealtimeSubscription.ts | 7 +- src/feed/subscription/Subscription.ts | 5 +- src/flutter-chart/index.ts | 34 + src/flutter-chart/painter.ts | 18 + src/index.ts | 3 +- src/overrides.ts | 10 + src/store/BarrierStore.ts | 116 +- src/store/BottomWidgetsContainerStore.ts | 59 +- src/store/ChartAdapterStore.ts | 332 + src/store/ChartSettingStore.ts | 16 +- src/store/ChartSizeStore.ts | 27 +- src/store/ChartState.ts | 369 +- src/store/ChartStore.ts | 912 +- src/store/ChartTypeStore.ts | 197 +- src/store/CrosshairStore.ts | 543 +- src/store/CurrentSpotStore.ts | 91 - src/store/DrawToolsStore.ts | 144 +- src/store/FavoriteStore.ts | 6 +- src/store/HighestLowestStore.ts | 41 +- src/store/IndicatorPredictionDialogStore.ts | 3 +- src/store/LastDigitStatsStore.ts | 34 +- src/store/MarkerStore.ts | 264 +- src/store/MenuStore.ts | 15 +- src/store/NavigationWidgetStore.ts | 31 +- src/store/PaginationLoaderStore.ts | 20 +- src/store/PriceLineStore.ts | 145 +- src/store/SettingsDialogStore.ts | 58 +- src/store/ShareStore.ts | 24 +- src/store/StudyLegendStore.ts | 536 +- src/store/TimeperiodStore.ts | 134 +- src/store/ToolbarWidgetStore.ts | 8 +- src/store/ViewStore.ts | 115 +- src/store/index.ts | 5 +- src/types/chartiq.types.ts | 20 - src/types/index.ts | 1 - src/types/props.types.ts | 291 +- src/types/stores.types.ts | 4 +- src/utils/ServerTime.ts | 3 +- src/utils/date.ts | 100 + src/utils/index.ts | 277 +- sw.js | 53 +- webpack.config.js | 33 +- 162 files changed, 28655 insertions(+), 89707 deletions(-) create mode 100644 chart_app/.gitignore create mode 100644 chart_app/.metadata create mode 100644 chart_app/README.md create mode 100644 chart_app/analysis_options.yaml create mode 100644 chart_app/lib/main.dart create mode 100644 chart_app/lib/src/add_ons/add_ons_repository.dart create mode 100644 chart_app/lib/src/chart_app.dart create mode 100644 chart_app/lib/src/helpers/chart.dart create mode 100644 chart_app/lib/src/helpers/color.dart create mode 100644 chart_app/lib/src/helpers/marker_painter.dart create mode 100644 chart_app/lib/src/helpers/series.dart create mode 100644 chart_app/lib/src/interop/dart_interop.dart create mode 100644 chart_app/lib/src/interop/js_interop.dart create mode 100644 chart_app/lib/src/markers/helpers/paint_functions/paint_end_marker.dart create mode 100644 chart_app/lib/src/markers/helpers/paint_functions/paint_start_line.dart create mode 100644 chart_app/lib/src/markers/helpers/paint_functions/paint_start_marker.dart create mode 100644 chart_app/lib/src/markers/helpers/paint_functions/paint_vertical_line.dart create mode 100644 chart_app/lib/src/markers/marker_group.dart create mode 100644 chart_app/lib/src/markers/marker_group_icon_painter.dart create mode 100644 chart_app/lib/src/markers/marker_group_painter.dart create mode 100644 chart_app/lib/src/markers/marker_group_series.dart create mode 100644 chart_app/lib/src/markers/marker_icon_painters/accumulator_marker_icon_painter.dart create mode 100644 chart_app/lib/src/markers/marker_icon_painters/digit_marker_icon_painter.dart create mode 100644 chart_app/lib/src/markers/marker_icon_painters/tick_marker_icon_painter.dart create mode 100644 chart_app/lib/src/markers/painter_props.dart create mode 100644 chart_app/lib/src/markers/web_marker.dart create mode 100644 chart_app/lib/src/misc/crosshair_controller.dart create mode 100644 chart_app/lib/src/misc/wrapped_controller.dart create mode 100644 chart_app/lib/src/models/chart_config.dart create mode 100644 chart_app/lib/src/models/chart_feed.dart create mode 100644 chart_app/lib/src/models/indicators.dart create mode 100644 chart_app/lib/src/painters/custom_line_painter.dart create mode 100644 chart_app/lib/src/series/current_tick_indicator.dart create mode 100644 chart_app/lib/src/series/custom_line_series.dart create mode 100644 chart_app/pubspec.yaml create mode 100644 chart_app/web/favicon.png create mode 100644 chart_app/web/index.html create mode 100644 chart_app/web/manifest.json delete mode 100644 chartiq/development/index.js delete mode 100644 chartiq/development/js/addOns.js delete mode 100644 chartiq/development/js/advanced.js delete mode 100644 chartiq/development/js/chartiq.js delete mode 100644 chartiq/development/js/deprecated.js delete mode 100644 chartiq/development/js/standard.js delete mode 100644 chartiq/hammer.js delete mode 100644 chartiq/html2canvas.min.js delete mode 100644 chartiq/intl.js delete mode 100644 chartiq/production/index.js delete mode 100644 chartiq/production/js/addOns.js delete mode 100644 chartiq/production/js/advanced.js delete mode 100644 chartiq/production/js/chartiq.js delete mode 100644 chartiq/production/js/deprecated.js delete mode 100644 chartiq/production/js/standard.js delete mode 100644 chartiq/splines.js delete mode 100644 scripts/extract-indicator-translations.js delete mode 100644 src/SplinePlotter.ts delete mode 100644 src/chartiq_injections/backingStore.ts delete mode 100644 src/chartiq_injections/calculateAwesome.ts delete mode 100644 src/chartiq_injections/createXAxis.ts delete mode 100644 src/chartiq_injections/currentHR.ts delete mode 100644 src/chartiq_injections/drawingClickChartEngine.ts delete mode 100644 src/chartiq_injections/findHighlights.ts delete mode 100644 src/chartiq_injections/headsUpHR.ts delete mode 100644 src/chartiq_injections/index.ts delete mode 100644 src/chartiq_injections/manageMasterDataLength.ts delete mode 100644 src/chartiq_injections/plotterDrawText.ts delete mode 100644 src/chartiq_injections/renderChannel.ts delete mode 100644 src/chartiq_injections/renderEllipse.ts delete mode 100644 src/chartiq_injections/renderGartley.ts delete mode 100644 src/chartiq_injections/renderPitchfork.ts delete mode 100644 src/chartiq_injections/renderRectangle.ts delete mode 100644 src/chartiq_injections/renderSegment.ts delete mode 100644 src/chartiq_injections/resizeObserver.ts delete mode 100644 src/chartiq_injections/setMeasure.ts delete mode 100644 src/components/RawMarker.tsx create mode 100644 src/components/ScrollToRecent.tsx delete mode 100644 src/components/ui/Animation.ts delete mode 100644 src/components/ui/Helper.ts delete mode 100644 src/components/ui/Keystroke.ts delete mode 100644 src/components/ui/KeystrokeHub.ts create mode 100644 src/flutter-chart/index.ts create mode 100644 src/flutter-chart/painter.ts create mode 100644 src/overrides.ts create mode 100644 src/store/ChartAdapterStore.ts delete mode 100644 src/store/CurrentSpotStore.ts delete mode 100644 src/types/chartiq.types.ts create mode 100644 src/utils/date.ts diff --git a/.eslintignore b/.eslintignore index 2ab769f474..53488d86cf 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,5 +1,4 @@ dist -chartiq node_modules design /**/*.d.ts diff --git a/.gitignore b/.gitignore index dcdf390764..f5a5f4b243 100644 --- a/.gitignore +++ b/.gitignore @@ -30,3 +30,5 @@ jsconfig.json CNAME .nyc_output **/*.swp + +chart_app/build/** diff --git a/.npmignore b/.npmignore index 6d551c36a8..7a4bfc70ba 100644 --- a/.npmignore +++ b/.npmignore @@ -3,7 +3,7 @@ .eslintrc .tern-project .travis.yml -chartiq/ +chart_app/ crowdin.yml css/ design-v1.js diff --git a/.stylelintrc b/.stylelintrc index 88fe9d5d13..e57a1d0677 100644 --- a/.stylelintrc +++ b/.stylelintrc @@ -1,88 +1,141 @@ { - "plugins": [ - "stylelint-no-unsupported-browser-features" - ], - "rules": { - "at-rule-name-case" : "lower", - "at-rule-name-space-after" : "always", - "at-rule-semicolon-newline-after" : "always", - "block-closing-brace-newline-after" : "always", - "block-closing-brace-newline-before" : "always", - "block-no-empty" : true, - "block-opening-brace-newline-after" : "always", - "block-opening-brace-space-before" : "always", - "color-hex-case" : "lower", - "color-named" : "never", - "color-no-invalid-hex" : true, - "declaration-bang-space-after" : "never", - "declaration-bang-space-before" : "always", - "declaration-block-no-duplicate-properties" : [true, { "ignore": ["consecutive-duplicates"] }], - "declaration-block-no-shorthand-property-overrides": true, - "declaration-block-semicolon-newline-after" : "always", - "declaration-block-semicolon-newline-before" : "never-multi-line", - "declaration-block-semicolon-space-after" : "always-single-line", - "declaration-block-semicolon-space-before" : "never", - "declaration-block-trailing-semicolon" : "always", - "declaration-colon-space-after" : "always", - "declaration-colon-space-before" : "never", - "font-family-name-quotes" : "always-unless-keyword", - "function-calc-no-unspaced-operator" : true, - "function-comma-space-after" : "always", - "function-comma-space-before" : "never", - "function-name-case" : "lower", - "function-parentheses-space-inside" : "never", - "function-url-quotes" : "always", - "indentation" : 4, - "max-empty-lines" : 1, - "media-feature-colon-space-after" : "always", - "media-feature-colon-space-before" : "never", - "media-feature-range-operator-space-after" : "always", - "media-feature-range-operator-space-before" : "always", - "media-query-list-comma-newline-after" : "never-multi-line", - "media-query-list-comma-newline-before" : "never-multi-line", - "media-query-list-comma-space-after" : "always", - "media-query-list-comma-space-before" : "never", - "no-duplicate-selectors" : true, - "no-eol-whitespace" : true, - "no-extra-semicolons" : true, - "no-invalid-double-slash-comments" : true, - "number-leading-zero" : "always", - "number-max-precision" : 2, - "number-no-trailing-zeros" : true, - "property-case" : "lower", - "plugin/no-unsupported-browser-features" : [true, { - "severity": "error", - "ignore": ["calc", "user-select-none", "multicolumn", "css-appearance", "intrinsic-width"] - }], - "rule-empty-line-before" : ["always", { "ignore": ["after-comment"], "except": ["inside-block-and-after-rule", "first-nested"] }], - "selector-attribute-brackets-space-inside" : "never", - "selector-attribute-operator-space-after" : "never", - "selector-attribute-operator-space-before" : "never", - "selector-combinator-space-after" : "always", - "selector-combinator-space-before" : "always", - "selector-list-comma-newline-before" : "never-multi-line", - "selector-list-comma-space-before" : "never", - "selector-max-empty-lines" : 0, - "selector-pseudo-class-case" : "lower", - "selector-pseudo-class-no-unknown" : [true, { - "ignorePseudoClasses": ["export"] - }], - "selector-pseudo-class-parentheses-space-inside" : "never", - "selector-pseudo-element-case" : "lower", - "selector-pseudo-element-colon-notation" : "single", - "selector-pseudo-element-no-unknown" : true, - "selector-type-case" : "lower", - "selector-type-no-unknown" : [true, { "ignoreTypes": ["from", "to", "0%", "50%", "100%", "_"] }], - "shorthand-property-no-redundant-values" : true, - "string-no-newline" : true, - "string-quotes" : "single", - "time-min-milliseconds" : 100, - "unit-case" : "lower", - "unit-whitelist" : ["fr", "px", "em", "rem", "%", "vw", "vh", "deg", "ms", "s"], - "value-keyword-case" : "lower", - "value-list-comma-newline-after" : "never-multi-line", - "value-list-comma-newline-before" : "never-multi-line", - "value-list-comma-space-after" : "always", - "value-list-comma-space-before" : "never" - } + "plugins": [ + "stylelint-no-unsupported-browser-features" + ], + "rules": { + "at-rule-name-case": "lower", + "at-rule-name-space-after": "always", + "at-rule-semicolon-newline-after": "always", + "block-closing-brace-newline-after": "always", + "block-closing-brace-newline-before": "always", + "block-no-empty": true, + "block-opening-brace-newline-after": "always", + "block-opening-brace-space-before": "always", + "color-hex-case": "lower", + "color-named": "never", + "color-no-invalid-hex": true, + "declaration-bang-space-after": "never", + "declaration-bang-space-before": "always", + "declaration-block-no-duplicate-properties": [ + true, + { + "ignore": [ + "consecutive-duplicates" + ] + } + ], + "declaration-block-no-shorthand-property-overrides": true, + "declaration-block-semicolon-newline-after": "always", + "declaration-block-semicolon-newline-before": "never-multi-line", + "declaration-block-semicolon-space-after": "always-single-line", + "declaration-block-semicolon-space-before": "never", + "declaration-block-trailing-semicolon": "always", + "declaration-colon-space-after": "always", + "declaration-colon-space-before": "never", + "font-family-name-quotes": "always-unless-keyword", + "function-calc-no-unspaced-operator": true, + "function-comma-space-before": "never", + "function-name-case": "lower", + "function-url-quotes": "always", + "indentation": 4, + "max-empty-lines": 1, + "media-feature-colon-space-after": "always", + "media-feature-colon-space-before": "never", + "media-feature-range-operator-space-after": "always", + "media-feature-range-operator-space-before": "always", + "media-query-list-comma-newline-after": "never-multi-line", + "media-query-list-comma-newline-before": "never-multi-line", + "media-query-list-comma-space-after": "always", + "media-query-list-comma-space-before": "never", + "no-duplicate-selectors": true, + "no-eol-whitespace": true, + "no-extra-semicolons": true, + "no-invalid-double-slash-comments": true, + "number-leading-zero": "always", + "number-max-precision": 2, + "number-no-trailing-zeros": true, + "property-case": "lower", + "plugin/no-unsupported-browser-features": [ + true, + { + "severity": "error", + "ignore": [ + "calc", + "user-select-none", + "multicolumn", + "css-appearance", + "intrinsic-width" + ] + } + ], + "rule-empty-line-before": [ + "always", + { + "ignore": [ + "after-comment" + ], + "except": [ + "inside-block-and-after-rule", + "first-nested" + ] + } + ], + "selector-attribute-brackets-space-inside": "never", + "selector-attribute-operator-space-after": "never", + "selector-attribute-operator-space-before": "never", + "selector-combinator-space-after": "always", + "selector-combinator-space-before": "always", + "selector-list-comma-newline-before": "never-multi-line", + "selector-list-comma-space-before": "never", + "selector-max-empty-lines": 0, + "selector-pseudo-class-case": "lower", + "selector-pseudo-class-no-unknown": [ + true, + { + "ignorePseudoClasses": [ + "export" + ] + } + ], + "selector-pseudo-class-parentheses-space-inside": "never", + "selector-pseudo-element-case": "lower", + "selector-pseudo-element-colon-notation": "single", + "selector-pseudo-element-no-unknown": true, + "selector-type-case": "lower", + "selector-type-no-unknown": [ + true, + { + "ignoreTypes": [ + "from", + "to", + "0%", + "50%", + "100%", + "_" + ] + } + ], + "shorthand-property-no-redundant-values": true, + "string-no-newline": true, + "string-quotes": "single", + "time-min-milliseconds": 100, + "unit-case": "lower", + "unit-whitelist": [ + "fr", + "px", + "em", + "rem", + "%", + "vw", + "vh", + "deg", + "ms", + "s" + ], + "value-keyword-case": "lower", + "value-list-comma-newline-after": "never-multi-line", + "value-list-comma-newline-before": "never-multi-line", + "value-list-comma-space-after": "always", + "value-list-comma-space-before": "never" + } } diff --git a/app/index.html b/app/index.html index ac95dfb7e5..f003d6dcb6 100644 --- a/app/index.html +++ b/app/index.html @@ -1,20 +1,20 @@ - + + + + + + + + + Library Test + - - - - - - - - Library Test - - - -
- - - - + +
+ + diff --git a/app/index.tsx b/app/index.tsx index d28cb6e9cc..b36b9c784a 100644 --- a/app/index.tsx +++ b/app/index.tsx @@ -124,10 +124,11 @@ const App = () => { const memoizedValues = React.useMemo(() => { let endEpoch: number | undefined, granularity: number | undefined, - chartType = ''; + chartType = '', + symbol = ''; if (settingsRef.current.historical) { endEpoch = new Date(`${today}:00Z`).valueOf() / 1000; - chartType = 'mountain'; + chartType = 'line'; granularity = 0; if (layout) { granularity = @@ -137,17 +138,19 @@ const App = () => { (layout.interval * IntervalEnum[layout.timeUnit as keyof typeof IntervalEnum]).toString(), 10 ); // eslint-disable-line - if (layout.chartType === 'candle' && layout.aggregationType !== 'ohlc') { + if (layout.chartType === 'candles' && layout.aggregationType !== 'ohlc') { chartType = layout.aggregationType; } else { chartType = layout.chartType; } + symbol = layout.symbol; } } return { chartType, granularity, endEpoch, + symbol, }; }, [layout]); const [chartType, setChartType] = React.useState(memoizedValues.chartType); @@ -155,7 +158,7 @@ const App = () => { const [endEpoch, setEndEpoch] = React.useState(memoizedValues.endEpoch); const [isConnectionOpened, setIsConnectionOpened] = React.useState(true); const [networkStatus, setNetworkStatus] = React.useState(); - const [symbol, setSymbol] = React.useState(''); + const [symbol, setSymbol] = React.useState(memoizedValues.symbol); const allTicks: keyof AuditDetailsForExpiredContract | [] = []; const contractInfo: keyof ProposalOpenContract | {} = {}; React.useEffect(() => { @@ -176,7 +179,7 @@ const App = () => { console.log('settings updated:', newSettings); localStorage.setItem('smartchart-setting', JSON.stringify(newSettings)); if (!prevSetting.historical && newSettings.historical) { - setChartType('mountain'); + setChartType('line'); setGranularity(0); setEndEpoch(new Date(`${today}:00Z`).valueOf() / 1000); } else if (!newSettings.historical) { @@ -236,6 +239,7 @@ const App = () => { }); } }; + return ( { const startingLanguageRef = React.useRef('en'); const openMarketRef = React.useRef({}); const [notifier] = React.useState(new ChartNotifier()); - const [layoutString] = React.useState(localStorage.getItem(`layout-${chartId}`) || ''); + const [layoutString] = React.useState(localStorage.getItem(`layout-new-${chartId}`) || ''); const [layout] = React.useState(JSON.parse(layoutString !== '' ? layoutString : '{}')); const initialSettings = React.useMemo(() => { let _settings: TSettings = createObjectFromLocalStorage('smartchart-setting'); @@ -184,12 +184,12 @@ const App = () => { (layout.interval * IntervalEnum[layout.timeUnit as keyof typeof IntervalEnum]).toString(), 10 ); - if (layout.chartType === 'candle' && layout.aggregationType !== 'ohlc') { + if (layout.chartType === 'candles' && layout.aggregationType !== 'ohlc') { chartType = layout.aggregationType; } else { chartType = layout.chartType; } - if (['mountain', 'line', 'colored_line', 'spline', 'baseline'].indexOf(chartType) === -1) { + if (['line', 'colored_line', 'spline', 'baseline'].indexOf(chartType) === -1) { isChartTypeCandle = true; } } @@ -268,7 +268,7 @@ const App = () => { console.log('settings updated:', newSettings); localStorage.setItem('smartchart-setting', JSON.stringify(newSettings)); if (!prevSetting.historical && newSettings.historical) { - setChartType('mountain'); + setChartType('line'); setIsChartTypeCandle(false); setGranularity(0); setEndEpoch(new Date(`${today}:00Z`).valueOf() / 1000); @@ -550,6 +550,7 @@ const App = () => { const barriers = barrierType ? [ { + key: 'barrier_1', shade: barrierType, shadeColor, foregroundColor: foregroundColor || null, diff --git a/chart_app/.gitignore b/chart_app/.gitignore new file mode 100644 index 0000000000..fd120481b4 --- /dev/null +++ b/chart_app/.gitignore @@ -0,0 +1,107 @@ +# Dart +.dart_tool/ +.packages +build/* +!build/ +!build/web +build/web/assets/assets/icons/symbols/ +build/web/assets/packages +pubspec.lock +.flutter-plugins +.flutter-plugins-dependencies +.last_build_id + +# Mac +.DS_Store + +# Built application files +*.apk +*.aar +*.ap_ +*.aab + +# Files for the ART/Dalvik VM +*.dex + +# Java class files +*.class + +# Generated files +bin/ +gen/ +out/ +# Uncomment the following line in case you need and you don't have the release build type files in your app +# release/ + +# Gradle files +.gradle/ + +# Local configuration file (sdk path, etc) +local.properties + +# Proguard folder generated by Eclipse +proguard/ + +# Log Files +*.log + +# Android Studio Navigation editor temp files +.navigation/ + +# Android Studio captures folder +captures/ + +# Visual Studio code +launch.json + +# IntelliJ +*.iml +.idea/workspace.xml +.idea/tasks.xml +.idea/gradle.xml +.idea/assetWizardSettings.xml +.idea/dictionaries +.idea/libraries +# Android Studio 3 in .gitignore file. +.idea/caches +.idea/modules.xml +# Comment next line if keeping position of elements in Navigation Editor is relevant for you +.idea/navEditor.xml +.idea/codeStyles +.idea/misc.xml + +# Keystore files +# Uncomment the following lines if you do not want to check your keystore files in. +#*.jks +#*.keystore + +# External native build folder generated in Android Studio 2.2 and later +.externalNativeBuild +.cxx/ + +# Google Services (e.g. APIs or Firebase) +# google-services.json + +# Freeline +freeline.py +freeline/ +freeline_project_description.json + +# fastlane +fastlane/report.xml +fastlane/Preview.html +fastlane/screenshots +fastlane/test_output +fastlane/readme.md + +# Version control +vcs.xml + +# lint +lint/intermediates/ +lint/generated/ +lint/outputs/ +lint/tmp/ +# lint/reports/ +coverage +.fvm/ \ No newline at end of file diff --git a/chart_app/.metadata b/chart_app/.metadata new file mode 100644 index 0000000000..3c3e4b52f7 --- /dev/null +++ b/chart_app/.metadata @@ -0,0 +1,10 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: 5464c5bac742001448fe4fc0597be939379f88ea + channel: stable + +project_type: app diff --git a/chart_app/README.md b/chart_app/README.md new file mode 100644 index 0000000000..69b97bdb6a --- /dev/null +++ b/chart_app/README.md @@ -0,0 +1,16 @@ +# chart_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/chart_app/analysis_options.yaml b/chart_app/analysis_options.yaml new file mode 100644 index 0000000000..f55005fb0f --- /dev/null +++ b/chart_app/analysis_options.yaml @@ -0,0 +1,4 @@ +include: package:deriv_lint/analysis_options.yaml +analyzer: + exclude: + - test diff --git a/chart_app/lib/main.dart b/chart_app/lib/main.dart new file mode 100644 index 0000000000..9eb873326e --- /dev/null +++ b/chart_app/lib/main.dart @@ -0,0 +1,277 @@ +import 'dart:collection'; +import 'dart:js'; +import 'dart:math'; +import 'dart:ui'; +import 'package:chart_app/src/chart_app.dart'; +import 'package:chart_app/src/helpers/marker_painter.dart'; +import 'package:chart_app/src/helpers/series.dart'; +import 'package:chart_app/src/misc/crosshair_controller.dart'; +import 'package:chart_app/src/models/indicators.dart'; +import 'package:chart_app/src/series/current_tick_indicator.dart'; +import 'package:deriv_chart/deriv_chart.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:provider/provider.dart'; + +// ignore: avoid_web_libraries_in_flutter +import 'dart:html' as html; + +import 'src/models/chart_feed.dart'; +import 'src/models/chart_config.dart'; +import 'src/interop/dart_interop.dart'; +import 'src/interop/js_interop.dart'; +import 'src/markers/marker_group_series.dart'; + +// ignore_for_file: avoid_catches_without_on_clauses + +void main() { + runApp(const DerivChartApp()); +} + +/// The start of the application. +class DerivChartApp extends StatelessWidget { + /// Initialize + const DerivChartApp({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) => MaterialApp( + theme: ThemeData.light(), + home: const _DerivChartWebAdapter(), + ); +} + +class _DerivChartWebAdapter extends StatefulWidget { + const _DerivChartWebAdapter({Key? key}) : super(key: key); + + @override + State<_DerivChartWebAdapter> createState() => _DerivChartWebAdapterState(); +} + +class _DerivChartWebAdapterState extends State<_DerivChartWebAdapter> { + _DerivChartWebAdapterState() { + app = ChartApp( + configModel, + feedModel, + indicatorsModel, + ); + initDartInterop(app); + JsInterop.onChartLoad(); + } + + final ChartFeedModel feedModel = ChartFeedModel(); + final ChartConfigModel configModel = ChartConfigModel(); + final IndicatorsModel indicatorsModel = IndicatorsModel(); + + late final ChartApp app; + int? rightBoundEpoch; + bool isFollowMode = false; + + void onVisibilityChange(html.Event ev) { + if (configModel.startWithDataFitMode || feedModel.ticks.isEmpty) { + return; + } + + if (html.document.visibilityState == 'visible' && isFollowMode) { + app.wrappedController.scrollToLastTick(); + } + + if (html.document.visibilityState == 'hidden' && rightBoundEpoch != null) { + isFollowMode = rightBoundEpoch! > feedModel.ticks.last.epoch; + } + } + + @override + void initState() { + super.initState(); + html.document.addEventListener('visibilitychange', onVisibilityChange); + } + + @override + void dispose() { + super.dispose(); + html.document.removeEventListener('visibilitychange', onVisibilityChange); + } + + double? _getVerticalPaddingFraction(double height) { + if (configModel.yAxisMargin != null && height != 0) { + final double verticalPaddingFraction = max( + configModel.yAxisMargin!.top ?? 0, + configModel.yAxisMargin!.bottom ?? 0) / + height; + + return max(verticalPaddingFraction, 0.1); + } + return null; + } + + double _getMaxCurrentTickOffset() { + final double currentTickOffset = + configModel.startWithDataFitMode ? 150 : 300; + return configModel.isMobile ? currentTickOffset / 1.25 : currentTickOffset; + } + + double? _getMinIntervalWidth() { + if (configModel.startWithDataFitMode && + configModel.style == ChartStyle.line) { + return 0.1; + } + return null; + } + + double? _getMaxIntervalWidth() { + if (configModel.style == ChartStyle.candles) { + return 240; + } + return null; + } + + void _onCrosshairHover( + PointerHoverEvent ev, + EpochToX epochToX, + QuoteToY quoteToY, + EpochFromX epochFromX, + QuoteFromY quoteFromY, + AddOnConfig? config, + ) { + final CrosshairController controller = + app.wrappedController.getCrosshairController(); + + int? index; + + if (config != null) { + index = indicatorsModel.indicatorsRepo.items + .indexOf(config as IndicatorConfig); + } + + // ignore: cascade_invocations + controller + ..getEpochFromX_ = epochFromX + ..getQuoteFromY_ = quoteFromY + ..getXFromEpoch_ = epochToX + ..getYFromQuote_ = quoteToY; + + JsInterop.onCrosshairHover( + ev.position.dx, + ev.position.dy, + ev.localPosition.dx, + ev.localPosition.dy, + index, + ); + } + + @override + Widget build(BuildContext _) => MultiProvider( + providers: >[ + ChangeNotifierProvider.value(value: configModel), + ChangeNotifierProvider.value(value: feedModel) + ], + child: Scaffold( + body: LayoutBuilder( + builder: (BuildContext _, BoxConstraints constraints) => Center( + child: Column(children: [ + Expanded( + child: Consumer2(builder: + (BuildContext context, ChartConfigModel configModel, + ChartFeedModel feedModel, Widget? child) { + final bool showChart = app.getChartVisibilitity(); + + if (showChart == false) { + return Container( + color: configModel.theme is ChartDefaultLightTheme + ? Colors.white + : Colors.black, + constraints: const BoxConstraints.expand(), + ); + } + + final int granularity = app.getQuotesInterval() ?? 1000; + + final DataSeries mainSeries = + getDataSeries(feedModel, configModel, granularity); + + final Color latestTickColor = Color.fromRGBO( + 255, 68, 81, configModel.isSymbolClosed ? 0.32 : 1); + + return DerivChart( + mainSeries: mainSeries, + annotations: feedModel.ticks.isNotEmpty + ? [ + if (configModel.isLive) + CurrentTickIndicator( + feedModel.ticks.last, + id: 'last_tick_indicator', + style: HorizontalBarrierStyle( + color: latestTickColor, + labelShape: LabelShape.pentagon, + hasBlinkingDot: + !configModel.isSymbolClosed, + hasArrow: false, + textStyle: const TextStyle( + fontSize: 12, + height: 1.3, + fontWeight: FontWeight.w600, + color: Colors.white, + fontFeatures: [ + FontFeature.tabularFigures() + ], + )), + visibility: HorizontalBarrierVisibility + .keepBarrierLabelVisible, + ), + ] + : null, + pipSize: configModel.pipSize, + granularity: granularity, + controller: app.wrappedController.getChartController(), + theme: configModel.theme, + onVisibleAreaChanged: (int leftEpoch, int rightEpoch) { + if (!feedModel.waitingForHistory && + feedModel.ticks.isNotEmpty && + leftEpoch < feedModel.ticks.first.epoch) { + feedModel.loadHistory(2500); + } + rightBoundEpoch = rightEpoch; + JsInterop.onVisibleAreaChanged(leftEpoch, rightEpoch); + }, + onQuoteAreaChanged: + (double topQuote, double bottomQuote) { + JsInterop.onQuoteAreaChanged(topQuote, bottomQuote); + }, + markerSeries: MarkerGroupSeries( + SplayTreeSet(), + markerGroupList: configModel.markerGroupList, + markerGroupIconPainter: getMarkerGroupPainter(app), + controller: app.wrappedController, + yAxisWidth: app.yAxisWidth, + isMobile: app.configModel.isMobile, + ), + drawingToolsRepo: indicatorsModel.drawingToolsRepo, + indicatorsRepo: indicatorsModel.indicatorsRepo, + dataFitEnabled: configModel.startWithDataFitMode, + showCrosshair: configModel.showCrosshair, + isLive: configModel.isLive, + onCrosshairDisappeared: JsInterop.onCrosshairDisappeared, + onCrosshairHover: _onCrosshairHover, + maxCurrentTickOffset: _getMaxCurrentTickOffset(), + msPerPx: configModel.startWithDataFitMode + ? null + : configModel.msPerPx, + minIntervalWidth: _getMinIntervalWidth(), + maxIntervalWidth: _getMaxIntervalWidth(), + bottomChartTitleMargin: configModel.leftMargin != null + ? EdgeInsets.only(left: configModel.leftMargin!) + : null, + verticalPaddingFraction: + _getVerticalPaddingFraction(constraints.maxHeight), + showDataFitButton: false, + showScrollToLastTickButton: false, + loadingAnimationColor: Colors.transparent, + ); + }), + ), + ]), + ), + ), + ), + ); +} diff --git a/chart_app/lib/src/add_ons/add_ons_repository.dart b/chart_app/lib/src/add_ons/add_ons_repository.dart new file mode 100644 index 0000000000..83ae159500 --- /dev/null +++ b/chart_app/lib/src/add_ons/add_ons_repository.dart @@ -0,0 +1,95 @@ +import 'package:flutter/material.dart'; +import 'package:collection/collection.dart'; +import 'package:deriv_chart/deriv_chart.dart'; + +/// Storage key of saved indicators. +const String addOnsKey = 'addOns'; + +/// Called when an addOn is to be edited +/// +/// [id] is the id of the addOn to be edited +typedef OnEditCallback = void Function(int index); + +/// Swaps two elements of a list. +typedef OnSwapCallback = void Function(int index1, int index2); + +/// Holds indicators/drawing tools that were added to the Chart during runtime. +class AddOnsRepository extends ChangeNotifier + implements Repository { + /// Initializes + AddOnsRepository({ + this.onEditCallback, + this.onRemoveCallback, + this.onSwapCallback, + }) : _addOns = []; + + final List _addOns; + + /// List of indicators or drawing tools. + @override + List get items => _addOns; + + /// Callback to open edit dialog. + OnEditCallback? onEditCallback; + + /// Callback to remove an indicator. + OnEditCallback? onRemoveCallback; + + /// Callback to swap two elements of a list. + OnSwapCallback? onSwapCallback; + + /// Adds a new indicator or drawing tool. + @override + void add(T addOnConfig) { + _addOns.add(addOnConfig); + notifyListeners(); + } + + /// Updates indicator or drawing tool at [index]. + @override + void editAt(int index) { + onEditCallback?.call(index); + } + + /// Updates indicator or drawing tool at [index]. + @override + void updateAt(int index, T addOnConfig) { + if (index < 0 || index >= _addOns.length) { + return; + } + _addOns[index] = addOnConfig; + + notifyListeners(); + } + + /// Removes indicator/drawing tool at [index] from repository and calls `onRemoveCallback` + @override + void removeAt(int index) { + remove(index); + onRemoveCallback?.call(index); + } + + /// Removes indicator/drawing tool at [index] from repository. + void remove(int index) { + if (index < 0 || index >= _addOns.length) { + return; + } + _addOns.removeAt(index); + + notifyListeners(); + } + + /// Swaps two elements of this list. + @override + void swap(int index1, int index2) { + _addOns.swap(index1, index2); + onSwapCallback?.call(index1, index2); + notifyListeners(); + } + + /// To clear all indicators + void clear() { + _addOns.clear(); + notifyListeners(); + } +} diff --git a/chart_app/lib/src/chart_app.dart b/chart_app/lib/src/chart_app.dart new file mode 100644 index 0000000000..795d5707a1 --- /dev/null +++ b/chart_app/lib/src/chart_app.dart @@ -0,0 +1,101 @@ +import 'package:chart_app/src/helpers/chart.dart'; +import 'package:chart_app/src/interop/js_interop.dart'; +import 'package:chart_app/src/misc/wrapped_controller.dart'; +import 'package:chart_app/src/models/chart_config.dart'; +import 'package:chart_app/src/models/chart_feed.dart'; +import 'package:chart_app/src/models/indicators.dart'; +import 'package:deriv_chart/deriv_chart.dart'; +import 'package:flutter/material.dart'; + +/// ChartApp +class ChartApp { + /// Constructor + ChartApp( + this.configModel, + this.feedModel, + this.indicatorsModel, + ); + + /// ChartConfigModel + ChartConfigModel configModel; + + /// ChartFeedModel + ChartFeedModel feedModel; + + /// Indicators config + IndicatorsModel indicatorsModel; + + /// WrappedController + WrappedController wrappedController = WrappedController(); + + bool _prevShowChart = false; + + /// width of yAxis + double yAxisWidth = 60; + + /// Whether chart is mounted or not. + bool isMounted = false; + + void _processChartVisibilityChange(bool showChart) { + yAxisWidth = calculateYAxisWidth( + feedModel.ticks, + configModel.theme, + configModel.pipSize, + ); + + if (showChart) { + /// To prevent controller functions being called before mount. + WidgetsBinding.instance.addPostFrameCallback((_) { + isMounted = true; + }); + } else { + isMounted = false; + } + } + + /// Gets the chart visibility + bool getChartVisibilitity() { + final bool showChart = feedModel.isFeedLoaded; + + if (showChart != _prevShowChart) { + _processChartVisibilityChange(showChart); + } + + _prevShowChart = showChart; + return showChart; + } + + /// Initialize new chart + void newChart(JSNewChart payload) { + configModel.newChart(payload); + feedModel.newChart(); + } + + /// Gets the tooltip content for indicator series + List? getTooltipContent(int epoch, int pipSize) { + final List seriesList = + wrappedController.getSeriesList() ?? []; + final List indicatorConfigsList = + wrappedController.getConfigsList() as List? ?? + []; + + return indicatorsModel.getTooltipContent( + seriesList, + indicatorConfigsList, + epoch, + pipSize, + ); + } + + /// Gets the quote interval as granularity to fix 2s ticks. + int? getQuotesInterval() { + if (feedModel.isFeedLoaded && feedModel.ticks.length > 1) { + final Tick previousTick = feedModel.ticks[feedModel.ticks.length - 2]; + final Tick lastTick = feedModel.ticks.last; + if (previousTick.epoch != lastTick.epoch) { + return feedModel.ticks.last.epoch - previousTick.epoch; + } + } + return configModel.granularity; + } +} diff --git a/chart_app/lib/src/helpers/chart.dart b/chart_app/lib/src/helpers/chart.dart new file mode 100644 index 0000000000..926e973203 --- /dev/null +++ b/chart_app/lib/src/helpers/chart.dart @@ -0,0 +1,22 @@ +import 'dart:math'; + +import 'package:deriv_chart/deriv_chart.dart'; + +/// Calculates the width of yAxis +double calculateYAxisWidth(List ticks, ChartTheme theme, int pipSize) { + if (ticks.isEmpty) { + return 60; + } else { + final double width = labelWidth( + ticks.first.close, + theme.gridStyle.yLabelStyle, + pipSize, + ); + + return width + theme.gridStyle.labelHorizontalPadding * 2; + } +} + +/// Calculates opacity of the markers +double calculateOpacity(double from, double to) => + min(max(to - from - 10, 0) / 6, 1); diff --git a/chart_app/lib/src/helpers/color.dart b/chart_app/lib/src/helpers/color.dart new file mode 100644 index 0000000000..433cd11e10 --- /dev/null +++ b/chart_app/lib/src/helpers/color.dart @@ -0,0 +1,49 @@ +import 'package:flutter/material.dart'; + +/// Converts a hex, rgb, or rgba color string to Color object. +// Works with opacity values as well. +// e.g.: +// "#000" -> Color(0xff000000) +// "#cc3333" -> Color(0xffcc3333) +// "#cc3333dd" -> Color(0xddcc3333) +// "rgb(204, 44, 81)" -> Color(0xffcc2c51) +// "rgba(204, 44, 81, 0.20)" -> Color(0x33cc2c51) +// "rgba(204, 44, 81, 0.80)" -> Color(0xcccc2c51) +Color getColorFromString(String color) { + String colorStr = color; + final RegExp hexColorRegex = + RegExp(r'^#?([0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$'); + if (colorStr.startsWith('rgba')) { + final List rgbaList = + colorStr.substring(5, colorStr.length - 1).split(','); + return Color.fromRGBO(int.parse(rgbaList[0]), int.parse(rgbaList[1]), + int.parse(rgbaList[2]), double.parse(rgbaList[3])); + } else if (colorStr.startsWith('rgb')) { + final List rgbList = colorStr + .substring(4, colorStr.length - 1) + .split(',') + .map((String c) => int.parse(c)) + .toList(); + return Color.fromRGBO(rgbList[0], rgbList[1], rgbList[2], 1); + } else if (hexColorRegex.hasMatch(colorStr)) { + if (colorStr.length == 4) { + colorStr = colorStr + colorStr.substring(1, 4); + } + if (colorStr.length == 7) { + final int colorValue = int.parse(colorStr.substring(1), radix: 16); + return Color(colorValue).withOpacity(1); + } else { + final int colorValue = int.parse(colorStr.substring(1, 7), radix: 16); + final double opacityValue = + int.parse(colorStr.substring(7), radix: 16).toDouble() / 255; + return Color(colorValue).withOpacity(opacityValue); + } + } else if (colorStr.isEmpty) { + throw UnsupportedError('Empty color field found.'); + } else if (colorStr == 'none') { + return Colors.transparent; + } else { + throw UnsupportedError( + 'Only hex, rgb, or rgba color format currently supported.'); + } +} diff --git a/chart_app/lib/src/helpers/marker_painter.dart b/chart_app/lib/src/helpers/marker_painter.dart new file mode 100644 index 0000000000..a0bc5b7507 --- /dev/null +++ b/chart_app/lib/src/helpers/marker_painter.dart @@ -0,0 +1,19 @@ +import 'package:chart_app/src/chart_app.dart'; +import 'package:chart_app/src/markers/marker_group_icon_painter.dart'; +import 'package:chart_app/src/markers/marker_icon_painters/accumulator_marker_icon_painter.dart'; +import 'package:chart_app/src/markers/marker_icon_painters/digit_marker_icon_painter.dart'; +import 'package:chart_app/src/markers/marker_icon_painters/tick_marker_icon_painter.dart'; + +/// Gets painter for a contract based on the contract type +MarkerGroupIconPainter getMarkerGroupPainter(ChartApp app) { + switch (app.configModel.contractType) { + case 'DigitContract': + return DigitMarkerIconPainter(); + + case 'AccumulatorContract': + return AccumulatorMarkerIconPainter(); + + default: + return TickMarkerIconPainter(); + } +} diff --git a/chart_app/lib/src/helpers/series.dart b/chart_app/lib/src/helpers/series.dart new file mode 100644 index 0000000000..a7fc06bc6e --- /dev/null +++ b/chart_app/lib/src/helpers/series.dart @@ -0,0 +1,45 @@ +import 'package:chart_app/src/models/chart_config.dart'; +import 'package:chart_app/src/models/chart_feed.dart'; +import 'package:chart_app/src/series/custom_line_series.dart'; +import 'package:deriv_chart/deriv_chart.dart'; +import 'package:flutter/material.dart'; + +/// Gets the data series +DataSeries getDataSeries( + ChartFeedModel feedModel, ChartConfigModel configModel, int granularity) { + final List ticks = feedModel.ticks; + final double opacity = configModel.isSymbolClosed ? 0.32 : 1; + + // Min granularity 1m + if (ticks is List && granularity >= 60000) { + final CandleStyle? style = configModel.theme is ChartDefaultLightTheme + ? CandleStyle( + positiveColor: Color.fromRGBO(76, 175, 79, opacity), + negativeColor: Color.fromRGBO(249, 83, 83, opacity), + neutralColor: Color.fromRGBO(62, 62, 62, opacity), + ) + : CandleStyle( + positiveColor: Color.fromRGBO(0, 167, 159, opacity), + negativeColor: Color.fromRGBO(204, 46, 62, opacity), + neutralColor: Color.fromRGBO(110, 110, 110, opacity), + ); + + switch (configModel.style) { + case ChartStyle.candles: + return CandleSeries(ticks, style: style); + case ChartStyle.hollow: + return HollowCandleSeries(ticks, style: style); + case ChartStyle.ohlc: + return OhlcCandleSeries(ticks, style: style); + default: + break; + } + } + return CustomLineSeries( + ticks, + style: LineStyle( + color: Color.fromRGBO(133, 172, 176, opacity), + hasArea: true, + ), + ); +} diff --git a/chart_app/lib/src/interop/dart_interop.dart b/chart_app/lib/src/interop/dart_interop.dart new file mode 100644 index 0000000000..afd7adda40 --- /dev/null +++ b/chart_app/lib/src/interop/dart_interop.dart @@ -0,0 +1,202 @@ +import 'dart:js'; + +import 'dart:html' as html; +import 'dart:js_util'; + +import 'package:chart_app/src/chart_app.dart'; +import 'package:chart_app/src/misc/crosshair_controller.dart'; +import 'package:chart_app/src/models/indicators.dart'; +import 'package:chart_app/src/models/chart_config.dart'; +import 'package:chart_app/src/models/chart_feed.dart'; + +/// Refactor the code later with JSExport once the below issue is resolved. +/// https://github.com/dart-lang/sdk/issues/50721 + +/// Initialize +void initDartInterop(ChartApp app) { + final JsObject dartInterop = JsObject(context['Object']); + setProperty(dartInterop, 'config', _exposeConfigModel(app.configModel)); + setProperty( + dartInterop, 'indicators', _exposeIndicatorsModel(app.indicatorsModel)); + setProperty(dartInterop, 'feed', _exposeDataModel(app.feedModel)); + setProperty(dartInterop, 'app', _exposeApp(app)); + setProperty(dartInterop, 'crosshair', _exposeCrosshair(app)); + setProperty(html.window, 'flutterChart', dartInterop); +} + +JsObject _exposeApp(ChartApp app) { + final JsObject jsObject = JsObject(context['Object']); + + setProperty( + jsObject, + 'getYAxisWidth', + allowInterop(() => app.yAxisWidth), + ); + + setProperty( + jsObject, + 'newChart', + allowInterop(app.newChart), + ); + + setProperty( + jsObject, + 'getTooltipContent', + allowInterop(app.getTooltipContent), + ); + + setProperty(jsObject, 'getXFromEpoch', + allowInterop(app.wrappedController.getXFromEpoch)); + + setProperty(jsObject, 'getYFromQuote', + allowInterop(app.wrappedController.getYFromQuote)); + + setProperty(jsObject, 'getEpochFromX', + allowInterop(app.wrappedController.getEpochFromX)); + + setProperty(jsObject, 'getQuoteFromY', + allowInterop(app.wrappedController.getQuoteFromY)); + + setProperty(jsObject, 'scale', allowInterop(app.wrappedController.scale)); + + setProperty(jsObject, 'scroll', allowInterop(app.wrappedController.scroll)); + + setProperty( + jsObject, + 'scrollToLastTick', + allowInterop( + app.wrappedController.scrollToLastTick, + ), + ); + + setProperty( + jsObject, + 'toggleDataFitMode', + allowInterop(app.wrappedController.toggleDataFitMode), + ); + + return jsObject; +} + +JsObject _exposeCrosshair(ChartApp app) { + final JsObject crosshair = JsObject(context['Object']); + + final CrosshairController controller = + app.wrappedController.getCrosshairController(); + + setProperty( + crosshair, 'getXFromEpoch', allowInterop(controller.getXFromEpoch)); + + setProperty( + crosshair, 'getYFromQuote', allowInterop(controller.getYFromQuote)); + + setProperty( + crosshair, 'getEpochFromX', allowInterop(controller.getEpochFromX)); + + setProperty( + crosshair, 'getQuoteFromY', allowInterop(controller.getQuoteFromY)); + + return crosshair; +} + +JsObject _exposeDataModel(ChartFeedModel model) { + final JsObject feedModel = JsObject(context['Object']); + + setProperty( + feedModel, + 'onTickHistory', + allowInterop(model.onTickHistory), + ); + + setProperty( + feedModel, + 'onNewTick', + allowInterop(model.onNewTick), + ); + + setProperty( + feedModel, + 'onNewCandle', + allowInterop(model.onNewCandle), + ); + + return feedModel; +} + +JsObject _exposeConfigModel(ChartConfigModel model) { + final JsObject chartConfig = JsObject(context['Object']); + + setProperty( + chartConfig, + 'updateTheme', + allowInterop(model.updateTheme), + ); + + setProperty( + chartConfig, + 'newChart', + allowInterop(model.newChart), + ); + + setProperty( + chartConfig, + 'updateChartStyle', + allowInterop(model.updateChartStyle), + ); + + setProperty( + chartConfig, + 'updateMarkers', + allowInterop(model.updateMarkers), + ); + + setProperty( + chartConfig, + 'updateLiveStatus', + allowInterop(model.updateLiveStatus), + ); + + setProperty( + chartConfig, + 'updateCrosshairVisibility', + allowInterop(model.updateCrosshairVisibility), + ); + + setProperty( + chartConfig, + 'updateLeftMargin', + allowInterop(model.updateLeftMargin), + ); + + setProperty( + chartConfig, + 'setSymbolClosed', + allowInterop(model.setSymbolClosed), + ); + + return chartConfig; +} + +JsObject _exposeIndicatorsModel(IndicatorsModel model) { + final JsObject chartConfig = JsObject(context['Object']); + + setProperty( + chartConfig, + 'addOrUpdateIndicator', + allowInterop(model.addOrUpdateIndicator), + ); + + setProperty( + chartConfig, + 'removeIndicator', + allowInterop(model.removeIndicator), + ); + + setProperty( + chartConfig, + 'clearIndicators', + allowInterop(model.clearIndicators), + ); + + return chartConfig; +} diff --git a/chart_app/lib/src/interop/js_interop.dart b/chart_app/lib/src/interop/js_interop.dart new file mode 100644 index 0000000000..c49dc559e5 --- /dev/null +++ b/chart_app/lib/src/interop/js_interop.dart @@ -0,0 +1,183 @@ +import 'dart:js'; + +import 'package:chart_app/src/add_ons/add_ons_repository.dart'; +import 'package:js/js.dart'; + +/// JS Interop +@JS('window.jsInterop') +class JsInterop { + /// Called when the chart has loaded + external static void onChartLoad(); + + /// Called on each line series paint + external static void onMainSeriesPaint(); + + /// Called when visible area is change + external static void onVisibleAreaChanged(int leftEpoch, int rightEpoch); + + /// Called when visible quote area is change + external static void onQuoteAreaChanged(double topQuote, double bottomQuote); + + /// Called to load additional history + external static void loadHistory(JsLoadHistoryReq request); + + /// Called when candle or point is dismissed. + external static void onCrosshairDisappeared(); + + /// Called when the crosshair is moved. + external static void onCrosshairHover(double dx, double dy, double dxLocal, + double dyLocal, int? indicatorIndex); + + /// Indicator options + external static JsIndicators? indicators; +} + +@JS() +@anonymous + +/// Load history props +class JsLoadHistoryReq { + /// JsLoadHistoryReq Object + external factory JsLoadHistoryReq({int count, int end}); + + /// No of ticks/candles + external int count; + + /// End time + external int end; +} + +@JS() +@anonymous + +/// Payload for new chart init +class JSNewChart { + /// Whether the chart should be showing live data or not. + external bool get isLive; + + /// Whether data fit mode is enabled. + external bool get startWithDataFitMode; + + /// Granularity of the chart data + external int get granularity; + + /// Style of the chart + external String? get chartType; + + /// Dart theme or light theme + external String? get theme; + + /// Specifies the zoom level of the chart. + external double? get msPerPx; + + /// Pipsize of the chart. + external int? get pipSize; + + /// Specified if it is in mobile mode. + external bool get isMobile; + + /// Specifies the margin of yAxis. + external JSYAxisMargin get yAxisMargin; +} + +@JS() +@anonymous + +/// Marker group props +class JSMarkerGroupUpdate { + /// List of markers belongs to a contract + external List markers; + + /// Contract type + external String type; + + /// Color of the markers + external String? get color; + + /// Extra props needed to customize contract painting + external JsObject? props; +} + +@JS() +@anonymous + +/// Marker props +class JsMarker { + /// Quote + external double get quote; + + /// Epoch + external int get epoch; + + /// Marker text + external String get text; + + /// Marker type + external String get type; + + /// Marker color + external String? get color; +} + +@JS() +@anonymous + +/// Quote props +class JsQuote { + /// Close value of the candle/tick + external double get Close; + + /// High value of the candle + external double? get High; + + /// Low value of the candle + external double? get Low; + + /// Open value of the candle + external double? get Open; + + /// Date of the quote data + external String get Date; +} + +@JS() +@anonymous + +/// Indicator props +class JsIndicators { + /// Called when an indicator is to be removed + external OnEditCallback? onRemove; + + /// Called when an indicator is to be edited + external OnEditCallback? onEdit; + + /// Callback to swap two elements of a list. + external OnSwapCallback? onSwap; +} + +@JS() +@anonymous + +/// JsIndicatorTooltip +class JsIndicatorTooltip { + /// JsLoadHistoryReq Object + external factory JsIndicatorTooltip({String name, List values}); + + /// Name + external String name; + + /// Value + external List values; +} + +@JS() +@anonymous + +/// JSYAxisMargin +class JSYAxisMargin { + /// Top + external double? top; + + /// Bottom + external double? bottom; +} diff --git a/chart_app/lib/src/markers/helpers/paint_functions/paint_end_marker.dart b/chart_app/lib/src/markers/helpers/paint_functions/paint_end_marker.dart new file mode 100644 index 0000000000..6a78940aef --- /dev/null +++ b/chart_app/lib/src/markers/helpers/paint_functions/paint_end_marker.dart @@ -0,0 +1,96 @@ +import 'package:deriv_chart/deriv_chart.dart'; +import 'package:flutter/material.dart'; + +/// Paints expiry/end tick marker +void paintEndMarker( + Canvas canvas, ChartTheme theme, Offset center, Color color, double zoom) { + canvas + ..save() + ..translate( + center.dx, + center.dy, + ) + ..scale(1 * zoom); + + final Paint paint = Paint() + ..style = PaintingStyle.fill + ..color = theme.base08Color.withOpacity(1); + + // This path was generated with http://demo.qunee.com/svg2canvas/. + final Path path = Path() + ..moveTo(2, 2) + ..lineTo(18, 2) + ..lineTo(18, 12) + ..lineTo(2, 12) + ..close(); + + final Path flagPath = Path() + ..moveTo(2, 0) + ..lineTo(2, 1) + ..lineTo(19, 1) + ..lineTo(19, 12) + ..lineTo(2, 12) + ..lineTo(2, 20) + ..lineTo(1, 20) + ..lineTo(1, 0) + ..lineTo(2, 0) + ..close() + ..moveTo(18, 8) + ..lineTo(15, 8) + ..lineTo(15, 11) + ..lineTo(18, 11) + ..lineTo(18, 8) + ..close() + ..moveTo(12, 8) + ..lineTo(9, 8) + ..lineTo(9, 11) + ..lineTo(12, 11) + ..lineTo(12, 8) + ..close() + ..moveTo(6, 8) + ..lineTo(3, 8) + ..lineTo(3, 11) + ..lineTo(6, 11) + ..lineTo(6, 8) + ..close() + ..moveTo(15, 5) + ..lineTo(12, 5) + ..lineTo(12, 8) + ..lineTo(15, 8) + ..lineTo(15, 5) + ..close() + ..moveTo(9, 5) + ..lineTo(6, 5) + ..lineTo(6, 8) + ..lineTo(9, 8) + ..lineTo(9, 5) + ..close() + ..moveTo(6, 2) + ..lineTo(3, 2) + ..lineTo(3, 5) + ..lineTo(6, 5) + ..lineTo(6, 2) + ..close() + ..moveTo(18, 2) + ..lineTo(15, 2) + ..lineTo(15, 5) + ..lineTo(18, 5) + ..lineTo(18, 2) + ..close() + ..moveTo(12, 2) + ..lineTo(9, 2) + ..lineTo(9, 5) + ..lineTo(12, 5) + ..lineTo(12, 2) + ..close() + ..fillType = PathFillType.evenOdd; + + final Paint flagPaint = Paint() + ..style = PaintingStyle.fill + ..color = color; + + canvas + ..drawPath(path, paint) + ..drawPath(flagPath, flagPaint) + ..restore(); +} diff --git a/chart_app/lib/src/markers/helpers/paint_functions/paint_start_line.dart b/chart_app/lib/src/markers/helpers/paint_functions/paint_start_line.dart new file mode 100644 index 0000000000..75bdbc59e9 --- /dev/null +++ b/chart_app/lib/src/markers/helpers/paint_functions/paint_start_line.dart @@ -0,0 +1,37 @@ +import 'package:chart_app/src/markers/web_marker.dart'; +import 'package:deriv_chart/deriv_chart.dart'; +import 'package:flutter/material.dart'; + +/// Paints start time line +void paintStartLine(Canvas canvas, Size size, WebMarker marker, Offset anchor, + MarkerStyle style, double zoom) { + paintVerticalDashedLine( + canvas, + anchor.dx, + 10, + size.height - 10, + style.backgroundColor, + 1, + dashWidth: 6, + ); + + if (marker.text != null) { + final TextStyle textStyle = TextStyle( + color: style.backgroundColor, + fontSize: style.activeMarkerText.fontSize! * zoom, + fontWeight: FontWeight.normal, + ); + + final TextPainter textPainter = makeTextPainter(marker.text!, textStyle); + + final Offset iconShift = + Offset(anchor.dx - textPainter.width - 5, size.height - 20); + + paintWithTextPainter( + canvas, + painter: textPainter, + anchor: iconShift, + anchorAlignment: Alignment.centerLeft, + ); + } +} diff --git a/chart_app/lib/src/markers/helpers/paint_functions/paint_start_marker.dart b/chart_app/lib/src/markers/helpers/paint_functions/paint_start_marker.dart new file mode 100644 index 0000000000..f5361912ff --- /dev/null +++ b/chart_app/lib/src/markers/helpers/paint_functions/paint_start_marker.dart @@ -0,0 +1,22 @@ +import 'package:flutter/material.dart'; + +/// Paints start time marker +void paintStartMarker( + Canvas canvas, Offset offset, Color color, double iconSize) { + const IconData icon = Icons.location_on; + + TextPainter(textDirection: TextDirection.ltr) + ..text = TextSpan( + text: String.fromCharCode(icon.codePoint), + style: TextStyle( + fontSize: iconSize, + fontFamily: icon.fontFamily, + color: color, + ), + ) + ..layout() + ..paint( + canvas, + offset, + ); +} diff --git a/chart_app/lib/src/markers/helpers/paint_functions/paint_vertical_line.dart b/chart_app/lib/src/markers/helpers/paint_functions/paint_vertical_line.dart new file mode 100644 index 0000000000..dbaad82c27 --- /dev/null +++ b/chart_app/lib/src/markers/helpers/paint_functions/paint_vertical_line.dart @@ -0,0 +1,27 @@ +import 'package:deriv_chart/deriv_chart.dart'; +import 'package:flutter/material.dart'; + +/// Paints vertical line +void paintVerticalLine( + Canvas canvas, + Offset point1, + Offset point2, + Color color, + double lineThickness, { + double dashWidth = 3, + double dashSpace = 3, +}) { + final Offset _topOffset = point1.dy < point2.dy ? point1 : point2; + final Offset _bottomOffset = point1.dy > point2.dy ? point1 : point2; + + paintVerticalDashedLine( + canvas, + point1.dx, + _topOffset.dy, + _bottomOffset.dy, + color, + lineThickness, + dashWidth: 2, + dashSpace: 2, + ); +} diff --git a/chart_app/lib/src/markers/marker_group.dart b/chart_app/lib/src/markers/marker_group.dart new file mode 100644 index 0000000000..b468cf65be --- /dev/null +++ b/chart_app/lib/src/markers/marker_group.dart @@ -0,0 +1,46 @@ +import 'dart:js'; + +import 'package:chart_app/src/markers/web_marker.dart'; +import 'package:deriv_chart/deriv_chart.dart'; +import 'package:flutter/material.dart'; + +/// Chart open position marker. +class MarkerGroup implements Comparable { + /// Initialize marker group + MarkerGroup( + this.markers, { + required this.type, + this.id, + this.props, + this.style = const MarkerStyle( + activeMarkerText: TextStyle( + color: Colors.black, + fontSize: 12, + height: 1.4, + ), + ), + }); + + /// Marker entries. + final List markers; + + /// Marker group id. + final String? id; + + /// The `MarkerStyle` to paint the markers. + final MarkerStyle style; + + /// Marker group type. + final String type; + + /// Extra props + final JsObject? props; + + @override + int compareTo(covariant MarkerGroup other) { + final int epoch = markers.isNotEmpty ? markers.first.epoch : 0; + final int otherEpoch = + other.markers.isNotEmpty ? other.markers.first.epoch : 0; + return epoch.compareTo(otherEpoch); + } +} diff --git a/chart_app/lib/src/markers/marker_group_icon_painter.dart b/chart_app/lib/src/markers/marker_group_icon_painter.dart new file mode 100644 index 0000000000..5891de4642 --- /dev/null +++ b/chart_app/lib/src/markers/marker_group_icon_painter.dart @@ -0,0 +1,29 @@ +import 'dart:ui'; + +import 'package:chart_app/src/markers/marker_group.dart'; +import 'package:chart_app/src/markers/painter_props.dart'; +import 'package:deriv_chart/deriv_chart.dart'; + +/// Foundation class for painting marker group on canvas +abstract class MarkerGroupIconPainter extends MarkerIconPainter { + /// Paints single marker + @override + void paintMarker( + Canvas canvas, + Offset center, + Offset anchor, + MarkerDirection direction, + MarkerStyle style, + ) {} + + /// Paints marker group + void paintMarkerGroup( + Canvas canvas, + Size size, + ChartTheme theme, + MarkerGroup markerGroup, + EpochToX epochToX, + QuoteToY quoteToY, + PainterProps painterProps, + ); +} diff --git a/chart_app/lib/src/markers/marker_group_painter.dart b/chart_app/lib/src/markers/marker_group_painter.dart new file mode 100644 index 0000000000..010e8b46d4 --- /dev/null +++ b/chart_app/lib/src/markers/marker_group_painter.dart @@ -0,0 +1,58 @@ +import 'dart:math'; +import 'dart:ui'; + +import 'package:deriv_chart/deriv_chart.dart'; +import 'package:chart_app/src/markers/marker_group.dart'; +import 'package:chart_app/src/markers/marker_group_icon_painter.dart'; +import 'package:chart_app/src/markers/painter_props.dart'; +import 'package:chart_app/src/misc/wrapped_controller.dart'; +import 'package:chart_app/src/markers/marker_group_series.dart'; + +/// A [SeriesPainter] for painting [MarkerGroupPainter] data. +class MarkerGroupPainter extends SeriesPainter { + /// Initializes + MarkerGroupPainter( + MarkerGroupSeries series, + this.markerGroupIconPainter, { + required this.controller, + required this.yAxisWidth, + required this.isMobile, + }) : super(series); + + /// Marker painter which is based on trade type + final MarkerGroupIconPainter markerGroupIconPainter; + + /// WrappedController + final WrappedController controller; + + /// yAxisWidth + final double yAxisWidth; + + /// Whether it is in mobile mode or not. + final bool isMobile; + + @override + void onPaint({ + required Canvas canvas, + required Size size, + required EpochToX epochToX, + required QuoteToY quoteToY, + required AnimationInfo animationInfo, + }) { + final double? msPerPx = controller.getMsPerPx(); + final double zoom = + msPerPx != null ? max(min(2 / pow(msPerPx, 1 / 8), 1.2), 0.8) : 1; + + for (final MarkerGroup markerGroup in series.visibleMarkerGroupList) { + markerGroupIconPainter.paintMarkerGroup( + canvas, + size, + theme, + markerGroup, + epochToX, + quoteToY, + PainterProps(zoom, yAxisWidth, isMobile: isMobile), + ); + } + } +} diff --git a/chart_app/lib/src/markers/marker_group_series.dart b/chart_app/lib/src/markers/marker_group_series.dart new file mode 100644 index 0000000000..0d9c3a0786 --- /dev/null +++ b/chart_app/lib/src/markers/marker_group_series.dart @@ -0,0 +1,62 @@ +import 'dart:collection'; + +import 'package:chart_app/src/markers/marker_group.dart'; +import 'package:chart_app/src/markers/marker_group_icon_painter.dart'; +import 'package:chart_app/src/markers/marker_group_painter.dart'; +import 'package:chart_app/src/misc/wrapped_controller.dart'; +import 'package:deriv_chart/deriv_chart.dart'; + +/// Marker Group series +class MarkerGroupSeries extends MarkerSeries { + /// Initializes. + MarkerGroupSeries( + SplayTreeSet entries, { + required this.markerGroupIconPainter, + required this.controller, + required this.yAxisWidth, + required this.isMobile, + this.markerGroupList, + }) : super(entries, markerIconPainter: markerGroupIconPainter); + + /// Painter that draw corresponding marker icon. + final MarkerGroupIconPainter markerGroupIconPainter; + + /// List of related grouped markers. + final List? markerGroupList; + + /// WrappedController + final WrappedController controller; + + /// The width of y-axis + final double yAxisWidth; + + /// Whether it is in mobile mode or not. + final bool isMobile; + + /// Visible marker entries. + List visibleMarkerGroupList = []; + + @override + SeriesPainter createPainter() => MarkerGroupPainter( + this, + markerGroupIconPainter, + controller: controller, + yAxisWidth: yAxisWidth, + isMobile: isMobile, + ); + + @override + void onUpdate(int leftEpoch, int rightEpoch) { + if (markerGroupList != null) { + visibleMarkerGroupList = markerGroupList! + .where( + (MarkerGroup group) => + group.markers.isNotEmpty && + group.markers.last.epoch >= leftEpoch, + ) + .toList(); + } else { + visibleMarkerGroupList = []; + } + } +} diff --git a/chart_app/lib/src/markers/marker_icon_painters/accumulator_marker_icon_painter.dart b/chart_app/lib/src/markers/marker_icon_painters/accumulator_marker_icon_painter.dart new file mode 100644 index 0000000000..6dbbc1334b --- /dev/null +++ b/chart_app/lib/src/markers/marker_icon_painters/accumulator_marker_icon_painter.dart @@ -0,0 +1,245 @@ +import 'dart:js'; +import 'dart:js_util'; + +import 'package:chart_app/src/markers/marker_group.dart'; +import 'package:chart_app/src/markers/marker_icon_painters/tick_marker_icon_painter.dart'; +import 'package:chart_app/src/markers/painter_props.dart'; +import 'package:chart_app/src/markers/web_marker.dart'; +import 'package:deriv_chart/deriv_chart.dart'; +import 'package:flutter/material.dart'; + +/// Accumulator contract painter +class AccumulatorMarkerIconPainter extends TickMarkerIconPainter { + /// Constructor + AccumulatorMarkerIconPainter(); + + Offset _getOffset( + WebMarker marker, + EpochToX epochToX, + QuoteToY quoteToY, + ) => + Offset( + epochToX(marker.epoch), + quoteToY(marker.quote), + ); + + @override + void paintMarkerGroup( + Canvas canvas, + Size size, + ChartTheme theme, + MarkerGroup markerGroup, + EpochToX epochToX, + QuoteToY quoteToY, + PainterProps painterProps, + ) { + super.paintMarkerGroup( + canvas, + size, + theme, + markerGroup, + epochToX, + quoteToY, + painterProps, + ); + + final Map markers = {}; + + for (final WebMarker marker in markerGroup.markers) { + if (marker.markerType != null) { + markers[marker.markerType!] = marker; + } + } + + final WebMarker? lowMarker = markers[MarkerType.lowBarrier]; + final WebMarker? highMarker = markers[MarkerType.highBarrier]; + + final WebMarker? previousTickMarker = markers[MarkerType.previousTick]; + + if (lowMarker != null && highMarker != null) { + final Offset lowOffset = _getOffset(lowMarker, epochToX, quoteToY); + final Offset highOffset = _getOffset(highMarker, epochToX, quoteToY); + + _drawShadedBarriers( + canvas: canvas, + size: size, + painterProps: painterProps, + lowMarker: lowMarker, + highMarker: highMarker, + startLeft: lowOffset.dx, + top: highOffset.dy, + markerGroup: markerGroup, + bottom: lowOffset.dy, + previousTickMarker: previousTickMarker, + ); + } + } + + bool _hasPersistentBorders(JsObject? props) { + if (props == null) { + return false; + } + + final bool? hasPersistentBorders = + getProperty(props, 'hasPersistentBorders'); + + return hasPersistentBorders ?? false; + } + + void _drawShadedBarriers({ + required Canvas canvas, + required Size size, + required PainterProps painterProps, + required WebMarker lowMarker, + required WebMarker highMarker, + required double startLeft, + required double top, + required MarkerGroup markerGroup, + required double bottom, + WebMarker? previousTickMarker, + }) { + final double endLeft = size.width - painterProps.yAxisWidth - 15; + final double endTop = size.height; + + final bool hasPersistentBorders = _hasPersistentBorders(markerGroup.props); + + final MarkerStyle style = markerGroup.style; + + final bool isTopVisible = + top < endTop && (top >= 0 || !hasPersistentBorders); + final bool isBottomVisible = bottom < endTop; + // using 2 instead of 0 to distance the top barrier line + // from the top of the chart and make it clearly visible: + final double persistentTop = top < 0 && hasPersistentBorders ? 2 : endTop; + final double displayedTop = isTopVisible ? top : persistentTop; + final double displayedBottom = isBottomVisible ? bottom : endTop; + final bool isStartLeftVisible = startLeft < endLeft; + + final double middleTop = bottom - (bottom - top).abs() / 2; + + final Color barrierColor = lowMarker.color ?? Colors.blue; + final Paint paint = Paint() + ..color = barrierColor + ..style = PaintingStyle.fill; + + if (!isStartLeftVisible) { + return; + } + + final TextStyle textStyle = TextStyle( + color: barrierColor, + fontSize: painterProps.isMobile ? 10 : 14, + ); + + if (previousTickMarker != null && previousTickMarker.color != null) { + _drawPreviousTickBarrier( + canvas, + startLeft, + endLeft, + middleTop, + previousTickMarker.color!, + barrierColor, + ); + } + + if (isTopVisible || hasPersistentBorders) { + final Path path = Path() + ..moveTo(startLeft + 2.5, displayedTop) + ..lineTo(startLeft - 2.5, displayedTop) + ..lineTo(startLeft, displayedTop + 4.5) + ..lineTo(startLeft + 2.5, displayedTop) + ..close(); + + canvas.drawPath(path, paint); + + paintHorizontalDashedLine( + canvas, + startLeft - 2.5, + endLeft, + displayedTop, + barrierColor, + 1.5, + dashSpace: 0, + ); + + // draw difference between high barrier and previous spot price + if (highMarker.text != null) { + final TextPainter textPainter = + makeTextPainter(highMarker.text!, textStyle); + + paintWithTextPainter( + canvas, + painter: textPainter, + anchor: Offset(endLeft - 1, displayedTop - 10), + anchorAlignment: Alignment.centerRight, + ); + } + } + if (isBottomVisible || hasPersistentBorders) { + final Path path = Path() + ..moveTo(startLeft + 2.5, displayedBottom) + ..lineTo(startLeft - 2.5, displayedBottom) + ..lineTo(startLeft, displayedBottom - 4.5) + ..lineTo(startLeft + 2.5, displayedBottom) + ..close(); + + canvas.drawPath(path, paint); + + paintHorizontalDashedLine( + canvas, + startLeft - 2.5, + endLeft, + displayedBottom, + barrierColor, + 1.5, + dashSpace: 0, + ); + + // draw difference between low barrier and previous spot price + if (lowMarker.text != null) { + final TextPainter textPainter = + makeTextPainter(lowMarker.text!, textStyle); + + paintWithTextPainter( + canvas, + painter: textPainter, + anchor: Offset(endLeft - 1, displayedBottom + 12), + anchorAlignment: Alignment.centerRight, + ); + } + } + + final Paint rectPaint = Paint()..color = style.backgroundColor; + + canvas.drawRect( + Rect.fromLTRB(startLeft, displayedTop, endLeft, displayedBottom), + rectPaint, + ); + } + + void _drawPreviousTickBarrier( + Canvas canvas, + double startX, + double endX, + double y, + Color circleColor, + Color barrierColor, + ) { + canvas.drawCircle( + Offset(startX, y), + 1.5, + Paint()..color = circleColor, + ); + + paintHorizontalDashedLine( + canvas, + startX, + endX, + y, + barrierColor, + 1.5, + dashWidth: 2, + dashSpace: 4, + ); + } +} diff --git a/chart_app/lib/src/markers/marker_icon_painters/digit_marker_icon_painter.dart b/chart_app/lib/src/markers/marker_icon_painters/digit_marker_icon_painter.dart new file mode 100644 index 0000000000..4d5f5b3e5f --- /dev/null +++ b/chart_app/lib/src/markers/marker_icon_painters/digit_marker_icon_painter.dart @@ -0,0 +1,163 @@ +import 'package:chart_app/src/helpers/chart.dart'; +import 'package:chart_app/src/markers/marker_group.dart'; +import 'package:chart_app/src/markers/marker_group_icon_painter.dart'; +import 'package:chart_app/src/markers/painter_props.dart'; +import 'package:chart_app/src/markers/web_marker.dart'; +import 'package:flutter/material.dart'; +import 'package:deriv_chart/deriv_chart.dart'; +import 'package:chart_app/src/markers/helpers/paint_functions/paint_end_marker.dart'; +import 'package:chart_app/src/markers/helpers/paint_functions/paint_start_marker.dart'; +import 'package:chart_app/src/markers/helpers/paint_functions/paint_start_line.dart'; + +/// Digits contract painter +class DigitMarkerIconPainter extends MarkerGroupIconPainter { + @override + void paintMarkerGroup( + Canvas canvas, + Size size, + ChartTheme theme, + MarkerGroup markerGroup, + EpochToX epochToX, + QuoteToY quoteToY, + PainterProps painterProps, + ) { + final Map points = {}; + + for (final WebMarker marker in markerGroup.markers) { + final Offset center = Offset( + epochToX(marker.epoch), + quoteToY(marker.quote), + ); + + if (marker.markerType != null) { + points[marker.markerType!] = center; + } + } + + final Offset? startPoint = points[MarkerType.start]; + final Offset? exitPoint = points[MarkerType.exit]; + final Offset? endPoint = points[MarkerType.end]; + + double opacity = 1; + + if (startPoint != null && (endPoint != null || exitPoint != null)) { + opacity = + calculateOpacity(startPoint.dx, (endPoint?.dx ?? exitPoint?.dx)!); + } + + for (final WebMarker marker in markerGroup.markers) { + final Offset center = points[marker.markerType!]!; + _drawMarker(canvas, size, theme, marker, center, markerGroup.style, + painterProps.zoom, opacity); + } + } + + void _drawMarker(Canvas canvas, Size size, ChartTheme theme, WebMarker marker, + Offset anchor, MarkerStyle style, double zoom, double opacity) { + switch (marker.markerType) { + case MarkerType.activeStart: + paintStartLine(canvas, size, marker, anchor, style, zoom); + break; + + case MarkerType.start: + _drawStartPoint( + canvas, size, theme, marker, anchor, style, zoom, opacity); + break; + + case MarkerType.exit: + final Paint paint = Paint()..color = style.backgroundColor; + + paintEndMarker(canvas, theme, anchor - Offset(1, 20 * zoom + 5), + style.backgroundColor, zoom); + + final Color fontColor = theme.base08Color; + _drawTick(canvas, marker, anchor, style, paint, fontColor, zoom); + break; + case MarkerType.tick: + final Paint paint = Paint() + ..color = style.backgroundColor + ..style = PaintingStyle.stroke + ..strokeWidth = 1.5; + + final Color fontColor = style.backgroundColor; + _drawTick(canvas, marker, anchor, style, paint, fontColor, zoom); + break; + default: + break; + } + } + + void _drawTick(Canvas canvas, Marker marker, Offset anchor, MarkerStyle style, + Paint paint, Color fontColor, double zoom) { + canvas + ..drawCircle( + anchor, + 8 * zoom, + Paint()..color = Colors.white, + ) + ..drawCircle( + anchor, + 8 * zoom, + paint, + ); + + final String lastChar = marker.quote.toString().characters.last; + final TextSpan span = TextSpan( + text: lastChar, + style: TextStyle( + fontSize: 10 * zoom, + color: fontColor, + fontWeight: FontWeight.bold, + ), + ); + + final TextPainter painter = TextPainter(textDirection: TextDirection.ltr) + ..text = span + ..layout(); + + painter.paint( + canvas, + anchor - Offset(painter.width / 2, painter.height / 2), + ); + } + + void _drawStartPoint( + Canvas canvas, + Size size, + ChartTheme theme, + WebMarker marker, + Offset anchor, + MarkerStyle style, + double zoom, + double opacity) { + if (marker.quote != 0) { + paintStartMarker( + canvas, + anchor - Offset(20 * zoom / 2, 20 * zoom), + style.backgroundColor.withOpacity(opacity), + 20 * zoom, + ); + } + + if (marker.text != null) { + final TextStyle textStyle = TextStyle( + color: style.backgroundColor.withOpacity(opacity), + fontSize: style.activeMarkerText.fontSize! * zoom, + fontWeight: FontWeight.bold, + backgroundColor: theme.base08Color, + ); + + final TextPainter textPainter = makeTextPainter(marker.text!, textStyle); + + final Offset iconShift = + Offset(textPainter.width / 2, 20 * zoom + textPainter.height); + + paintWithTextPainter( + canvas, + painter: textPainter, + anchor: anchor - iconShift, + anchorAlignment: Alignment.centerLeft, + ); + } + } +} diff --git a/chart_app/lib/src/markers/marker_icon_painters/tick_marker_icon_painter.dart b/chart_app/lib/src/markers/marker_icon_painters/tick_marker_icon_painter.dart new file mode 100644 index 0000000000..98cd8349af --- /dev/null +++ b/chart_app/lib/src/markers/marker_icon_painters/tick_marker_icon_painter.dart @@ -0,0 +1,220 @@ +import 'package:chart_app/src/helpers/chart.dart'; +import 'package:chart_app/src/markers/helpers/paint_functions/paint_vertical_line.dart'; +import 'package:chart_app/src/markers/marker_group.dart'; +import 'package:chart_app/src/markers/marker_group_icon_painter.dart'; +import 'package:chart_app/src/markers/painter_props.dart'; +import 'package:chart_app/src/markers/web_marker.dart'; +import 'package:flutter/material.dart'; +import 'package:deriv_chart/deriv_chart.dart'; +import 'package:chart_app/src/markers/helpers/paint_functions/paint_end_marker.dart'; +import 'package:chart_app/src/markers/helpers/paint_functions/paint_start_marker.dart'; +import 'package:chart_app/src/markers/helpers/paint_functions/paint_start_line.dart'; + +/// Tick contract painter +class TickMarkerIconPainter extends MarkerGroupIconPainter { + @override + void paintMarkerGroup( + Canvas canvas, + Size size, + ChartTheme theme, + MarkerGroup markerGroup, + EpochToX epochToX, + QuoteToY quoteToY, + PainterProps painterProps, + ) { + final Map points = {}; + + for (final WebMarker marker in markerGroup.markers) { + final Offset center = Offset( + epochToX(marker.epoch), + quoteToY(marker.quote), + ); + + if (marker.markerType != null) { + points[marker.markerType!] = center; + } + } + + final Offset? startPoint = points[MarkerType.start]; + final Offset? exitPoint = points[MarkerType.exit]; + final Offset? endPoint = points[MarkerType.end]; + + double opacity = 1; + + if (startPoint != null && (endPoint != null || exitPoint != null)) { + opacity = + calculateOpacity(startPoint.dx, (endPoint?.dx ?? exitPoint?.dx)!); + } + + _drawBarriers( + canvas, size, points, markerGroup.style, opacity, painterProps); + + for (final WebMarker marker in markerGroup.markers) { + final Offset center = points[marker.markerType!]!; + _drawMarker(canvas, size, theme, marker, center, markerGroup.style, + painterProps.zoom, opacity); + } + } + + void _drawBarriers(Canvas canvas, Size size, Map points, + MarkerStyle style, double opacity, PainterProps painterProps) { + final Color color = style.backgroundColor.withOpacity(opacity); + final Paint paint = Paint()..color = color; + final Offset? _entryOffset = points[MarkerType.entry]; + final Offset? _entryTickOffset = points[MarkerType.entryTick]; + final Offset? _startOffset = points[MarkerType.start]; + final Offset? _latestOffset = points[MarkerType.latestTick]; + final Offset? _endOffset = points[MarkerType.end]; + final Offset? _exitOffset = points[MarkerType.exit]; + + if (_entryOffset != null && _startOffset != null) { + paintHorizontalDashedLine( + canvas, + _startOffset.dx, + _entryOffset.dx, + _startOffset.dy, + color, + 1, + dashWidth: 1, + dashSpace: 1, + ); + } + + if (_entryOffset != null && (_latestOffset != null || _endOffset != null)) { + final double dx = (_latestOffset?.dx ?? _endOffset?.dx)!; + final double dy = (_latestOffset?.dy ?? _endOffset?.dy)!; + + canvas.drawLine(_entryOffset, Offset(dx, dy), paint); + } + + if (_entryOffset != null && _entryTickOffset != null) { + paintVerticalLine( + canvas, + _entryOffset, + _entryTickOffset, + color, + 1, + dashWidth: 2, + dashSpace: 2, + ); + } + + if (_exitOffset != null && _endOffset != null) { + paintVerticalLine( + canvas, + _exitOffset, + _endOffset, + color, + 1, + dashWidth: 2, + dashSpace: 2, + ); + } + } + + void _drawMarker(Canvas canvas, Size size, ChartTheme theme, WebMarker marker, + Offset anchor, MarkerStyle style, double zoom, double opacity) { + final Color color = style.backgroundColor.withOpacity(opacity); + + final Paint paint = Paint()..color = color; + + switch (marker.markerType) { + case MarkerType.activeStart: + paintStartLine(canvas, size, marker, anchor, style, zoom); + break; + case MarkerType.start: + _drawStartPoint( + canvas, size, theme, marker, anchor, style, zoom, opacity); + break; + case MarkerType.entry: + _drawEntryPoint(canvas, theme, anchor, color, zoom, opacity); + break; + case MarkerType.end: + paintEndMarker(canvas, theme, anchor - Offset(1, 20 * zoom), + style.backgroundColor, zoom); + break; + case MarkerType.exit: + canvas.drawCircle( + anchor, + 1.5 * zoom, + paint, + ); + break; + case MarkerType.tick: + _drawTickPoint(canvas, anchor, paint, zoom); + break; + default: + break; + } + } + + void _drawTickPoint(Canvas canvas, Offset anchor, Paint paint, double zoom) { + canvas.drawCircle( + anchor, + 1.5 * zoom, + paint, + ); + } + + void _drawEntryPoint(Canvas canvas, ChartTheme theme, Offset anchor, + Color color, double zoom, double opacity) { + final Paint paint = Paint() + ..color = theme.base08Color.withOpacity(opacity) + ..style = PaintingStyle.fill; + final double radius = 1.5 * zoom; + canvas.drawCircle( + anchor, + radius, + paint, + ); + final Paint strokePaint = Paint() + ..color = color + ..style = PaintingStyle.stroke; + canvas.drawCircle( + anchor, + radius, + strokePaint, + ); + } + + void _drawStartPoint( + Canvas canvas, + Size size, + ChartTheme theme, + WebMarker marker, + Offset anchor, + MarkerStyle style, + double zoom, + double opacity, + ) { + if (marker.quote != 0) { + paintStartMarker( + canvas, + anchor - Offset(20 * zoom / 2, 20 * zoom), + style.backgroundColor.withOpacity(opacity), + 20 * zoom, + ); + } + + if (marker.text != null) { + final TextStyle textStyle = TextStyle( + color: (marker.color ?? style.backgroundColor).withOpacity(opacity), + fontSize: style.activeMarkerText.fontSize! * zoom, + fontWeight: FontWeight.bold, + backgroundColor: theme.base08Color, + ); + + final TextPainter textPainter = makeTextPainter(marker.text!, textStyle); + + final Offset iconShift = + Offset(textPainter.width / 2, 20 * zoom + textPainter.height); + + paintWithTextPainter( + canvas, + painter: textPainter, + anchor: anchor - iconShift, + anchorAlignment: Alignment.centerLeft, + ); + } + } +} diff --git a/chart_app/lib/src/markers/painter_props.dart b/chart_app/lib/src/markers/painter_props.dart new file mode 100644 index 0000000000..32fdb6864f --- /dev/null +++ b/chart_app/lib/src/markers/painter_props.dart @@ -0,0 +1,14 @@ +/// PainterProps +class PainterProps { + /// Initialize + PainterProps(this.zoom, this.yAxisWidth, {required this.isMobile}); + + /// Specifies zoom of the chart w.r.t to msPerPx. + final double zoom; + + /// Width of y-axis + final double yAxisWidth; + + /// Whether it is in mobile mode or not. + final bool isMobile; +} diff --git a/chart_app/lib/src/markers/web_marker.dart b/chart_app/lib/src/markers/web_marker.dart new file mode 100644 index 0000000000..0e31c00446 --- /dev/null +++ b/chart_app/lib/src/markers/web_marker.dart @@ -0,0 +1,61 @@ +import 'package:flutter/material.dart'; +import 'package:deriv_chart/deriv_chart.dart'; + +/// Type of the marker. +enum MarkerType { + /// Active start marker. + activeStart, + + /// Start marker. + start, + + /// Entry marker. + entry, + + /// Entry marker tick. + entryTick, + + /// Latest tick marker. + latestTick, + + /// Previous tick marker. + previousTick, + + /// Tick marker. + tick, + + /// End marker. + end, + + /// Exit marker. + exit, + + /// High Barrier. + highBarrier, + + /// Low Barrier. + lowBarrier, +} + +/// Chart open position marker. +// ignore: must_be_immutable +class WebMarker extends Marker { + /// Initializes. + WebMarker({ + required int epoch, + required double quote, + required MarkerDirection direction, + this.markerType, + this.text, + this.color, + }) : super(epoch: epoch, quote: quote, direction: direction); + + /// Type of marker. + final MarkerType? markerType; + + /// Text displayed on the marker. + final String? text; + + /// Color of the marker + final Color? color; +} diff --git a/chart_app/lib/src/misc/crosshair_controller.dart b/chart_app/lib/src/misc/crosshair_controller.dart new file mode 100644 index 0000000000..5bd5a302a4 --- /dev/null +++ b/chart_app/lib/src/misc/crosshair_controller.dart @@ -0,0 +1,64 @@ +/// To get X position +typedef GetXFromEpoch = double? Function(int); + +/// To get Y position +typedef GetYFromQuote = double? Function(double); + +/// To get epoch +typedef GetEpochFromX = int? Function(double); + +/// To get quote +typedef GetQuoteFromY = double? Function(double); + +// ignore_for_file: avoid_catches_without_on_clauses + +/// CrosshairController +class CrosshairController { + /// Called to get X position from epoch + GetXFromEpoch? getXFromEpoch_; + + /// Called to get Y position from quote + GetYFromQuote? getYFromQuote_; + + /// Called to get epoch from x position + GetEpochFromX? getEpochFromX_; + + /// Called to get quote from y position + GetQuoteFromY? getQuoteFromY_; + + /// Called to get epoch from x position + int? getEpochFromX(double x) { + try { + return getEpochFromX_?.call(x); + } catch (_) { + return null; + } + } + + /// Called to get quote from y position + double? getQuoteFromY(double y) { + try { + return getQuoteFromY_?.call(y); + } catch (_) { + return null; + } + } + + /// Called to get X position from epoch + double? getXFromEpoch(int epoch) { + try { + return getXFromEpoch_?.call(epoch); + } catch (_) { + return null; + } + } + + /// Called to get Y position from quote + double? getYFromQuote(double quote) { + try { + return getYFromQuote_?.call(quote); + } catch (_) { + return null; + } + } +} diff --git a/chart_app/lib/src/misc/wrapped_controller.dart b/chart_app/lib/src/misc/wrapped_controller.dart new file mode 100644 index 0000000000..870d6a015e --- /dev/null +++ b/chart_app/lib/src/misc/wrapped_controller.dart @@ -0,0 +1,119 @@ +import 'package:chart_app/src/misc/crosshair_controller.dart'; +import 'package:deriv_chart/deriv_chart.dart'; + +// ignore_for_file: avoid_catches_without_on_clauses + +/// WrappedController +/// To prevent controller exceptions +class WrappedController { + /// ChartController + final ChartController _chartController = ChartController(); + + final CrosshairController _crosshairController = CrosshairController(); + + /// Gets chart controller + ChartController getChartController() => _chartController; + + /// Gets crosshair controller + CrosshairController getCrosshairController() => _crosshairController; + + /// Scales the chart. + double? scale(double scale) { + try { + return _chartController.onScale?.call(scale); + } catch (_) { + return null; + } + } + + /// Scroll chart visible area. + void scroll(double pxShift) { + try { + _chartController.onScroll?.call(pxShift); + } catch (_) { + return; + } + } + + /// Scroll chart visible area to the newest data. + void scrollToLastTick() { + try { + _chartController.scrollToLastTick(); + } catch (_) { + return; + } + } + + /// Scroll chart visible area to the newest data. + // ignore: avoid_positional_boolean_parameters + void toggleDataFitMode(bool dataFitMode) { + try { + _chartController.toggleDataFitMode?.call(enableDataFit: dataFitMode); + } catch (_) { + return; + } + } + + /// Called to get epoch from x position + int? getEpochFromX(double x) { + try { + return _chartController.getEpochFromX?.call(x); + } catch (_) { + return null; + } + } + + /// Called to get quote from y position + double? getQuoteFromY(double y) { + try { + return _chartController.getQuoteFromY?.call(y); + } catch (_) { + return null; + } + } + + /// Called to get X position from epoch + double? getXFromEpoch(int epoch) { + try { + return _chartController.getXFromEpoch?.call(epoch); + } catch (_) { + return null; + } + } + + /// Called to get Y position from quote + double? getYFromQuote(double quote) { + try { + return _chartController.getYFromQuote?.call(quote); + } catch (_) { + return null; + } + } + + /// Called to get msPerPx + double? getMsPerPx() { + try { + return _chartController.getMsPerPx?.call(); + } catch (_) { + return null; + } + } + + /// Called to get List of Series + List? getSeriesList() { + try { + return _chartController.getSeriesList?.call(); + } catch (_) { + return null; + } + } + + /// Called to get List of Configs + List? getConfigsList() { + try { + return _chartController.getConfigsList?.call(); + } catch (_) { + return null; + } + } +} diff --git a/chart_app/lib/src/models/chart_config.dart b/chart_app/lib/src/models/chart_config.dart new file mode 100644 index 0000000000..bc08b1c402 --- /dev/null +++ b/chart_app/lib/src/models/chart_config.dart @@ -0,0 +1,158 @@ +import 'package:chart_app/src/helpers/color.dart'; +import 'package:chart_app/src/markers/marker_group.dart'; +import 'package:chart_app/src/markers/web_marker.dart'; +import 'package:deriv_chart/deriv_chart.dart'; +import 'package:flutter/material.dart'; +import 'package:chart_app/src/interop/js_interop.dart'; + +/// State and methods of chart web adapter config. +class ChartConfigModel extends ChangeNotifier { + /// Initialize + ChartConfigModel(); + + /// Style of the chart + ChartStyle style = ChartStyle.line; + + /// Granularity + int? granularity; + + /// Theme of the chart + ChartTheme theme = ChartDefaultLightTheme(); + + /// Markers + List markerGroupList = []; + + /// Whether the chart should be showing live data or not. + bool isLive = true; + + /// Starts in data fit mode and adds a data-fit button. + bool startWithDataFitMode = false; + + /// Specifies whether the symbol is closed or not. + bool isSymbolClosed = false; + + /// Specifies the zoom level of the chart. + double? msPerPx; + + /// Specifies the left margin to prevent overlap. + double? leftMargin; + + /// Type of the contract + String? contractType; + + /// Pip size of the chart + int pipSize = 4; + + /// Whether the crosshair cursor should be shown or not. + bool showCrosshair = true; + + /// Specifies if it is in mobile mode + bool isMobile = false; + + /// Specifies the margin of yAxis. + JSYAxisMargin? yAxisMargin; + + /// To update style of the chart + // ignore: avoid_positional_boolean_parameters + void updateLiveStatus(bool _isLive) { + isLive = _isLive; + notifyListeners(); + } + + /// To update style of the chart + void updateChartStyle(String chartStyle) { + style = ChartStyle.values.byName(chartStyle); + notifyListeners(); + } + + /// Update markers + void updateMarkers(List _markerGroupList) { + markerGroupList = []; + + for (final JSMarkerGroupUpdate _markerGroup in _markerGroupList) { + final List markers = []; + + contractType = _markerGroup.type; + + for (final JsMarker _marker in _markerGroup.markers) { + markers.add(WebMarker( + quote: _marker.quote, + epoch: _marker.epoch * 1000, + text: _marker.text, + markerType: MarkerType.values.byName(_marker.type), + direction: MarkerDirection.up, + color: + _marker.color != null ? getColorFromString(_marker.color!) : null, + )); + } + + Color _bgColor = Colors.white; + + if (_markerGroup.color != null) { + _bgColor = getColorFromString(_markerGroup.color!); + } + + markerGroupList.add( + MarkerGroup( + markers, + type: _markerGroup.type, + style: MarkerStyle( + backgroundColor: _bgColor, + ), + props: _markerGroup.props, + ), + ); + } + notifyListeners(); + } + + /// To update the theme of the chart + void updateTheme(String _theme) { + theme = + _theme == 'dark' ? ChartDefaultDarkTheme() : ChartDefaultLightTheme(); + notifyListeners(); + } + + /// To update the theme of the chart + // ignore: avoid_positional_boolean_parameters + void updateCrosshairVisibility(bool _showCrosshair) { + showCrosshair = _showCrosshair; + notifyListeners(); + } + + /// To update leftMargin + void updateLeftMargin(double _leftMargin) { + leftMargin = _leftMargin; + notifyListeners(); + } + + /// To update the symbol open status + // ignore: avoid_positional_boolean_parameters + void setSymbolClosed(bool _isSymbolClosed) { + isSymbolClosed = _isSymbolClosed; + notifyListeners(); + } + + /// Initialize new chart + void newChart(JSNewChart payload) { + granularity = payload.granularity; + isLive = payload.isLive; + startWithDataFitMode = payload.startWithDataFitMode; + msPerPx = payload.msPerPx; + pipSize = payload.pipSize ?? 4; + isMobile = payload.isMobile; + yAxisMargin = payload.yAxisMargin; + + if (payload.chartType != null && payload.chartType!.isNotEmpty) { + style = ChartStyle.values.byName(payload.chartType!); + } + + if (payload.theme != null && payload.theme!.isNotEmpty) { + theme = payload.theme == 'dark' + ? ChartDefaultDarkTheme() + : ChartDefaultLightTheme(); + } + + notifyListeners(); + } +} diff --git a/chart_app/lib/src/models/chart_feed.dart b/chart_app/lib/src/models/chart_feed.dart new file mode 100644 index 0000000000..b516121268 --- /dev/null +++ b/chart_app/lib/src/models/chart_feed.dart @@ -0,0 +1,104 @@ +import 'package:deriv_chart/deriv_chart.dart'; +import 'package:flutter/material.dart'; +import 'package:chart_app/src/interop/js_interop.dart'; + +/// State and methods of chart web adapter data. +class ChartFeedModel extends ChangeNotifier { + /// Tick data. + List ticks = []; + + /// Flag to indicate the status of ticks network request. + bool waitingForHistory = false; + + /// Flag to indicate the status of ticks load of a new symbol. + bool isFeedLoaded = false; + + /// Reinitialize + void newChart() { + ticks = []; + waitingForHistory = false; + isFeedLoaded = false; + + notifyListeners(); + } + + Tick _parseTick(JsQuote item) => Tick( + epoch: DateTime.parse('${item.Date}Z').millisecondsSinceEpoch, + quote: item.Close, + ); + + Candle _parseCandle(JsQuote item) => Candle( + epoch: DateTime.parse('${item.Date}Z').millisecondsSinceEpoch, + high: item.High!, + low: item.Low!, + open: item.Open!, + close: item.Close, + ); + + /// Updates the chart with new tick + void onNewTick(JsQuote quote) { + final Tick tick = _parseTick(quote); + ticks = ticks + [tick]; + notifyListeners(); + } + + /// Updates the chart with new candle + void onNewCandle(JsQuote quote) { + final Candle newCandle = _parseCandle(quote); + final List previousCandles = + ticks.isNotEmpty && ticks.last.epoch == newCandle.epoch + ? ticks.sublist(0, ticks.length - 1) + : ticks; + + // Don't modify candles in place, otherwise Chart's didUpdateWidget won't + // see the difference. + ticks = previousCandles + [newCandle]; + notifyListeners(); + } + + /// To update the tick history + // ignore: avoid_positional_boolean_parameters + void onTickHistory(List quotes, bool append) { + List newTicks = quotes + .map((JsQuote item) => + item.Open != null ? _parseCandle(item) : _parseTick(item)) + .toList(); + + if (quotes.isNotEmpty && quotes.first.Open != null) { + newTicks = quotes.map((JsQuote item) => _parseCandle(item)).toList(); + } else { + newTicks = quotes.map((JsQuote item) => _parseTick(item)).toList(); + } + + if (append) { + while (newTicks.isNotEmpty && + ticks.isNotEmpty && + newTicks.last.epoch >= ticks.first.epoch) { + newTicks.removeLast(); + } + + ticks.insertAll(0, newTicks); + } else { + ticks = newTicks; + isFeedLoaded = true; + } + + if (append) { + waitingForHistory = false; + } + + notifyListeners(); + } + + /// Loads old chart history + void loadHistory(int count) { + waitingForHistory = true; + + JsInterop.loadHistory(JsLoadHistoryReq( + count: count, + end: ticks.first.epoch ~/ 1000, + )); + + notifyListeners(); + } +} diff --git a/chart_app/lib/src/models/indicators.dart b/chart_app/lib/src/models/indicators.dart new file mode 100644 index 0000000000..8261798771 --- /dev/null +++ b/chart_app/lib/src/models/indicators.dart @@ -0,0 +1,356 @@ +import 'dart:convert'; +import 'dart:math'; + +import 'package:deriv_chart/deriv_chart.dart' hide AddOnsRepository; +import 'package:chart_app/src/add_ons/add_ons_repository.dart'; +import 'package:chart_app/src/interop/js_interop.dart'; +import 'package:collection/collection.dart' show IterableExtension; + +/// State and methods of chart web adapter config. +class IndicatorsModel { + /// Initialize + IndicatorsModel(); + + /// Indicators repo + final AddOnsRepository indicatorsRepo = + AddOnsRepository( + onEditCallback: (int i) => JsInterop.indicators?.onEdit?.call(i), + onRemoveCallback: (int i) => JsInterop.indicators?.onRemove?.call(i), + onSwapCallback: (int x, int y) => JsInterop.indicators?.onSwap?.call(x, y), + ); + + /// Drawing tools repo + final AddOnsRepository drawingToolsRepo = + AddOnsRepository(); + + /// To add or update an indicator + void addOrUpdateIndicator(String dataString, int? index) { + final Map config = json.decode(dataString)..remove('id'); + + final IndicatorConfig? indicatorConfig = IndicatorConfig.fromJson(config); + + if (indicatorConfig != null) { + index != null && index > -1 + ? indicatorsRepo.updateAt(index, indicatorConfig) + : indicatorsRepo.add(indicatorConfig); + } + } + + /// To remove an existing indicator + void removeIndicator(int index) { + indicatorsRepo.remove(index); + } + + /// To clear all indicators + void clearIndicators() { + indicatorsRepo.clear(); + } + + /// Binary search + int? binarySearch(List ticks, int epoch, int min, int max) { + if (max >= min) { + final int mid = ((max + min) / 2).floor(); + if (epoch == ticks[mid].epoch) { + return mid; + } else if (epoch > ticks[mid].epoch) { + return binarySearch(ticks, epoch, mid + 1, max); + } else { + return binarySearch(ticks, epoch, min, mid - 1); + } + } + return null; + } + + String? _getQuote(List? entries, int epoch, int pipSize, + {int offset = 0}) { + final List ticks = entries ?? []; + + final int? index = binarySearch(ticks, epoch, 0, ticks.length - 1); + + final Tick? tick = index != null ? ticks[index - offset] : null; + + return tick?.quote.toStringAsFixed(pipSize); + } + + /// Gets the tooltip content for indicator series + List? getTooltipContent( + List seriesList, + List indicatorConfigsList, + int epoch, + int pipSize, + ) { + final List sortedSeriesList = [...seriesList]; + + indicatorConfigsList.forEachIndexed((int index, IndicatorConfig config) { + final int configIndex = indicatorsRepo.items.indexOf(config); + if (configIndex > -1) { + sortedSeriesList[configIndex] = seriesList[index]; + } + }); + + final List tooltipContent = []; + + for (final ChartData item in sortedSeriesList) { + if (item is AwesomeOscillatorSeries) { + tooltipContent.add(JsIndicatorTooltip( + name: AwesomeOscillatorIndicatorConfig.name, + values: [_getQuote(item.entries, epoch, pipSize)], + )); + } else if (item is DPOSeries) { + tooltipContent.add( + JsIndicatorTooltip(name: DPOIndicatorConfig.name, values: [ + _getQuote( + item.dpoSeries.entries, + epoch, + pipSize, + offset: item.dpoSeries.offset, + ) + ])); + } else if (item is GatorSeries) { + tooltipContent.add(JsIndicatorTooltip( + name: GatorIndicatorConfig.name, + values: [ + _getQuote( + item.gatorTopSeries.entries, + epoch, + pipSize, + offset: min( + item.gatorConfig.jawOffset, item.gatorConfig.teethOffset), + ), + _getQuote( + item.gatorBottomSeries.entries, + epoch, + pipSize, + offset: min( + item.gatorConfig.teethOffset, item.gatorConfig.lipsOffset), + ) + ])); + } else if (item is MACDSeries) { + tooltipContent.add(JsIndicatorTooltip( + name: MACDIndicatorConfig.name, + values: [ + _getQuote(item.macdSeries.entries, epoch, pipSize), + _getQuote(item.signalMACDSeries.entries, epoch, pipSize), + _getQuote(item.macdHistogramSeries.entries, epoch, pipSize) + ])); + } else if (item is ROCSeries) { + tooltipContent.add( + JsIndicatorTooltip(name: ROCIndicatorConfig.name, values: [ + _getQuote(item.entries, epoch, pipSize), + ])); + } else if (item is RSISeries) { + tooltipContent.add( + JsIndicatorTooltip(name: RSIIndicatorConfig.name, values: [ + _getQuote(item.entries, epoch, pipSize), + ])); + } else if (item is StochasticOscillatorSeries) { + tooltipContent.add(JsIndicatorTooltip( + name: StochasticOscillatorIndicatorConfig.name, + values: [ + _getQuote(item.fastPercentStochasticIndicatorSeries.entries, + epoch, pipSize), + _getQuote( + item.slowStochasticIndicatorSeries.entries, epoch, pipSize), + ])); + } else if (item is SMISeries) { + tooltipContent.add( + JsIndicatorTooltip(name: SMIIndicatorConfig.name, values: [ + _getQuote(item.smiSeries.entries, epoch, pipSize), + _getQuote(item.smiSignalSeries.entries, epoch, pipSize), + ])); + } else if (item is WilliamsRSeries) { + tooltipContent.add(JsIndicatorTooltip( + name: WilliamsRIndicatorConfig.name, + values: [_getQuote(item.entries, epoch, pipSize)])); + } else if (item is AroonSeries) { + tooltipContent.add(JsIndicatorTooltip( + name: AroonIndicatorConfig.name, + values: [ + _getQuote(item.aroonUpSeries.entries, epoch, pipSize), + _getQuote(item.aroonDownSeries.entries, epoch, pipSize), + ])); + } else if (item is ADXSeries) { + tooltipContent.add( + JsIndicatorTooltip(name: ADXIndicatorConfig.name, values: [ + _getQuote(item.positiveDISeries.entries, epoch, pipSize), + _getQuote(item.negativeDISeries.entries, epoch, pipSize), + _getQuote(item.adxSeries.entries, epoch, pipSize), + if (item.config.showHistogram) + _getQuote(item.adxHistogramSeries.entries, epoch, pipSize), + ])); + } else if (item is CCISeries) { + tooltipContent.add(JsIndicatorTooltip( + name: CCIIndicatorConfig.name, + values: [_getQuote(item.entries, epoch, pipSize)])); + } else if (item is IchimokuCloudSeries) { + tooltipContent.add(JsIndicatorTooltip( + name: IchimokuCloudIndicatorConfig.name, + values: [ + _getQuote( + item.conversionLineSeries.entries, + epoch, + pipSize, + ), + _getQuote( + item.baseLineSeries.entries, + epoch, + pipSize, + ), + _getQuote( + item.spanASeries.entries, + epoch, + pipSize, + offset: item.config.baseLinePeriod, + ), + _getQuote( + item.spanBSeries.entries, + epoch, + pipSize, + offset: item.config.baseLinePeriod, + ), + _getQuote( + item.laggingSpanSeries.entries, + epoch, + pipSize, + offset: item.config.laggingSpanOffset, + ), + ])); + } else if (item is ParabolicSARSeries) { + tooltipContent.add( + JsIndicatorTooltip(name: ParabolicSARConfig.name, values: [ + _getQuote( + item.entries, + epoch, + pipSize, + ) + ])); + } else if (item is BollingerBandSeries) { + tooltipContent.add(JsIndicatorTooltip( + name: BollingerBandsIndicatorConfig.name, + values: [ + _getQuote( + item.upperSeries.entries, + epoch, + pipSize, + ), + _getQuote( + item.middleSeries.entries, + epoch, + pipSize, + ), + _getQuote( + item.lowerSeries.entries, + epoch, + pipSize, + ) + ])); + } else if (item is DonchianChannelsSeries) { + tooltipContent.add(JsIndicatorTooltip( + name: DonchianChannelIndicatorConfig.name, + values: [ + _getQuote( + item.upperChannelSeries.entries, + epoch, + pipSize, + ), + _getQuote( + item.middleChannelSeries.entries, + epoch, + pipSize, + ), + _getQuote( + item.lowerChannelSeries.entries, + epoch, + pipSize, + ) + ])); + } else if (item is MASeries) { + tooltipContent.add( + JsIndicatorTooltip(name: MAIndicatorConfig.name, values: [ + _getQuote( + item.entries, + epoch, + pipSize, + ) + ])); + } else if (item is MAEnvSeries) { + tooltipContent.add(JsIndicatorTooltip( + name: MAEnvIndicatorConfig.name, + values: [ + _getQuote( + item.upperSeries.entries, + epoch, + pipSize, + ), + _getQuote( + item.middleSeries.entries, + epoch, + pipSize, + ), + _getQuote( + item.lowerSeries.entries, + epoch, + pipSize, + ) + ])); + } else if (item is RainbowSeries) { + final List values = item.rainbowSeries + .map((DataSeries series) => _getQuote( + series.entries, + epoch, + pipSize, + )) + .toList(); + + tooltipContent.add(JsIndicatorTooltip( + name: RainbowIndicatorConfig.name, + values: values, + )); + } else if (item is AlligatorSeries) { + tooltipContent.add(JsIndicatorTooltip( + name: AlligatorIndicatorConfig.name, + values: [ + if (item.jawSeries != null) + _getQuote( + item.jawSeries!.entries, + epoch, + pipSize, + offset: item.alligatorOptions.jawOffset, + ), + if (item.teethSeries != null) + _getQuote( + item.teethSeries!.entries, + epoch, + pipSize, + offset: item.alligatorOptions.teethOffset, + ), + if (item.lipsSeries != null) + _getQuote( + item.lipsSeries!.entries, + epoch, + pipSize, + offset: item.alligatorOptions.lipsOffset, + ) + ])); + } else if (item is FractalChaosBandSeries) { + tooltipContent.add(JsIndicatorTooltip( + name: FractalChaosBandIndicatorConfig.name, + values: [ + _getQuote( + item.fcbHighSeries.entries, + epoch, + pipSize, + ), + _getQuote( + item.fcbLowSeries.entries, + epoch, + pipSize, + ) + ])); + } else { + tooltipContent.add(null); + } + } + return tooltipContent; + } +} diff --git a/chart_app/lib/src/painters/custom_line_painter.dart b/chart_app/lib/src/painters/custom_line_painter.dart new file mode 100644 index 0000000000..5f7432d75b --- /dev/null +++ b/chart_app/lib/src/painters/custom_line_painter.dart @@ -0,0 +1,21 @@ +import 'package:chart_app/src/interop/js_interop.dart'; +import 'package:deriv_chart/deriv_chart.dart'; +import 'package:flutter/material.dart'; + +/// CustomLinePainter +class CustomLinePainter extends LinePainter { + /// Intialize + CustomLinePainter(DataSeries series) : super(series); + + @override + void onPaintData( + Canvas canvas, + Size size, + EpochToX epochToX, + QuoteToY quoteToY, + AnimationInfo animationInfo, + ) { + super.onPaintData(canvas, size, epochToX, quoteToY, animationInfo); + JsInterop.onMainSeriesPaint(); + } +} diff --git a/chart_app/lib/src/series/current_tick_indicator.dart b/chart_app/lib/src/series/current_tick_indicator.dart new file mode 100644 index 0000000000..383a5b0347 --- /dev/null +++ b/chart_app/lib/src/series/current_tick_indicator.dart @@ -0,0 +1,21 @@ +import 'package:deriv_chart/deriv_chart.dart'; + +/// CurrentTickIndicator +class CurrentTickIndicator extends TickIndicator { + /// Initializes a CurrentTickIndicator. + CurrentTickIndicator( + Tick tick, { + String? id, + HorizontalBarrierStyle? style, + HorizontalBarrierVisibility visibility = HorizontalBarrierVisibility.normal, + }) : super( + tick, + id: id, + style: style, + visibility: visibility, + ); + + // To fix the animation issue when the chart is in data fit mode. + @override + bool shouldRepaint(ChartData? previous) => true; +} diff --git a/chart_app/lib/src/series/custom_line_series.dart b/chart_app/lib/src/series/custom_line_series.dart new file mode 100644 index 0000000000..5b0f6d781f --- /dev/null +++ b/chart_app/lib/src/series/custom_line_series.dart @@ -0,0 +1,23 @@ +import 'package:chart_app/src/painters/custom_line_painter.dart'; +import 'package:deriv_chart/deriv_chart.dart'; + +/// CustomLineSeries +class CustomLineSeries extends LineSeries { + /// Initializes a line series. + CustomLineSeries( + List entries, { + String? id, + LineStyle? style, + HorizontalBarrierStyle? lastTickIndicatorStyle, + }) : super( + entries, + id: id, + style: style, + lastTickIndicatorStyle: lastTickIndicatorStyle, + ); + + @override + SeriesPainter> createPainter() => CustomLinePainter( + this, + ); +} diff --git a/chart_app/pubspec.yaml b/chart_app/pubspec.yaml new file mode 100644 index 0000000000..4a6b4b1abe --- /dev/null +++ b/chart_app/pubspec.yaml @@ -0,0 +1,25 @@ +name: chart_app +description: Chart App +publish_to: 'none' +version: 1.0.0+1 + +environment: + sdk: '>=2.16.2 <3.0.0' + +dependencies: + flutter: + sdk: flutter + deriv_chart: + path: ../../flutter-chart + +dev_dependencies: + deriv_lint: + git: + url: git@github.com:regentmarkets/flutter-deriv-packages.git + path: packages/deriv_lint + ref: dev + flutter_test: + sdk: flutter + +flutter: + uses-material-design: true diff --git a/chart_app/web/favicon.png b/chart_app/web/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..8aaa46ac1ae21512746f852a42ba87e4165dfdd1 GIT binary patch literal 917 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|I14-?iy0X7 zltGxWVyS%@P(fs7NJL45ua8x7ey(0(N`6wRUPW#JP&EUCO@$SZnVVXYs8ErclUHn2 zVXFjIVFhG^g!Ppaz)DK8ZIvQ?0~DO|i&7O#^-S~(l1AfjnEK zjFOT9D}DX)@^Za$W4-*MbbUihOG|wNBYh(yU7!lx;>x^|#0uTKVr7USFmqf|i<65o z3raHc^AtelCMM;Vme?vOfh>Xph&xL%(-1c06+^uR^q@XSM&D4+Kp$>4P^%3{)XKjo zGZknv$b36P8?Z_gF{nK@`XI}Z90TzwSQO}0J1!f2c(B=V`5aP@1P1a|PZ!4!3&Gl8 zTYqUsf!gYFyJnXpu0!n&N*SYAX-%d(5gVjrHJWqXQshj@!Zm{!01WsQrH~9=kTxW#6SvuapgMqt>$=j#%eyGrQzr zP{L-3gsMA^$I1&gsBAEL+vxi1*Igl=8#8`5?A-T5=z-sk46WA1IUT)AIZHx1rdUrf zVJrJn<74DDw`j)Ki#gt}mIT-Q`XRa2-jQXQoI%w`nb|XblvzK${ZzlV)m-XcwC(od z71_OEC5Bt9GEXosOXaPTYOia#R4ID2TiU~`zVMl08TV_C%DnU4^+HE>9(CE4D6?Fz oujB08i7adh9xk7*FX66dWH6F5TM;?E2b5PlUHx3vIVCg!0Dx9vYXATM literal 0 HcmV?d00001 diff --git a/chart_app/web/index.html b/chart_app/web/index.html new file mode 100644 index 0000000000..26749c3f1b --- /dev/null +++ b/chart_app/web/index.html @@ -0,0 +1,100 @@ + + + + + + + + + + + + + + + + + + + chart_app + + + + + + + diff --git a/chart_app/web/manifest.json b/chart_app/web/manifest.json new file mode 100644 index 0000000000..de67a3ad15 --- /dev/null +++ b/chart_app/web/manifest.json @@ -0,0 +1,12 @@ +{ + "name": "chart_app", + "short_name": "chart_app", + "start_url": ".", + "display": "standalone", + "background_color": "#0175C2", + "theme_color": "#0175C2", + "description": "Chart app", + "orientation": "portrait-primary", + "prefer_related_applications": false, + "icons": [] +} diff --git a/chartiq/development/index.js b/chartiq/development/index.js deleted file mode 100644 index 33002125de..0000000000 --- a/chartiq/development/index.js +++ /dev/null @@ -1,5 +0,0 @@ -export * from './js/chartiq.js'; -export * from './js/standard.js'; -export * from './js/advanced.js'; -export * from './js/deprecated.js'; -export * from './js/addOns.js'; diff --git a/chartiq/development/js/addOns.js b/chartiq/development/js/addOns.js deleted file mode 100644 index 2e56e630a1..0000000000 --- a/chartiq/development/js/addOns.js +++ /dev/null @@ -1,4982 +0,0 @@ -/**! - * 8.2.0 - * Generation date: 2023-03-23T15:05:01.971Z - * Client name: deriv limited - * Package Type: Technical Analysis - * License type: annual - * Expiration date: "2024/04/01" - * Domain lock: ["127.0.0.1","localhost","deriv.com","deriv.app","deriv.me","binary.com","binary.sx","binary.me","binary.bot","deriv.be"] - * iFrame lock: true - */ - -/***********************************************************! - * Copyright by ChartIQ, Inc. - * Licensed under the ChartIQ, Inc. Developer License Agreement https://www.chartiq.com/developer-license-agreement -*************************************************************/ -/*************************************! DO NOT MAKE CHANGES TO THIS LIBRARY FILE!! !************************************* -* If you wish to overwrite default functionality, create a separate file with a copy of the methods you are overwriting * -* and load that file right after the library has been loaded, but before the chart engine is instantiated. * -* Directly modifying library files will prevent upgrades and the ability for ChartIQ to support your solution. * -*************************************************************************************************************************/ -/* eslint-disable no-extra-parens */ - - -import {CIQ as __CIQ_} from "../js/chartiq.js"; - - -let __js_addons_standard_extendedHours_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -/** - * Use this constructor to initialize filtering and visualization styles of extended hours by the use of shading and delimitation lines. - * - * Requires *addOns.js*. - * - * This visualization will only work if data for the corresponding sessions is provided from your quote feed and the market definitions have the corresponding entries. - * See {@link CIQ.Market} for details on how to define extended (non-default) hours. - * - * By default all extended hour sessions are disabled unless explicitly enabled using {@link CIQ.ExtendedHours.prepare} or {@link CIQ.ExtendedHours.set}. - * - * All possible market sessions needed to be shaded at any given time should be enabled at once with this method. - * - * Your fetch should load the required data based on the `params.stx.layout.extended` and `params.stx.layout.marketSessions` settings. - * - * Remember that when `params.filter` is set to true, this module performs a filter of already loaded masterData when {@link CIQ.ExtendedHours.set} is invoked, - * rather than calling {@link CIQ.ChartEngine#loadChart} to reload the data from the server every time you enable or disable this feature. - * So you must always return all requested sessions on your fetch responses if this flag is set. - * - * CSS info: - * - The styles for the shading of each session is determined by the corresponding CSS class in the form of "stx_market_session."+session_name (Example: `stx_market_session.pre`) - * - The divider line is determined by the CSS class "stx_market_session.divider". - * - * **Important:** This module must be initialized before {@link CIQ.ChartEngine#importLayout} or the sessions will not be able to be restored. - * - * Example: - * - * - * @param {object} params The constructor parameters. - * @param {CIQ.ChartEngine} [params.stx] The chart object. - * @param {boolean} [params.filter] Setting to true performs a filter of masterData when - * {@link CIQ.ExtendedHours.set} is invoked, rather than calling - * {@link CIQ.ChartEngine#loadChart} to reload the data from the server. - * @param {string} [params.menuContextClass] A CSS class name used to query the menu DOM - * element that contains the UI control for the extended hours add-on. In a multi-chart - * document, the add-on is available only on charts that have a menu DOM element with - * the value for `menuContextClass` as a class attribute. - * - * @constructor - * @name CIQ.ExtendedHours - * @since - * - 06-2016-02 - * - 3.0.0 Changed argument to an object to support `filter`. - * - 3.0.0 No longer necessary to explicitly call new Chart to reload data. Instead call {@link CIQ.ExtendedHours.set} function. - * - 5.0.0 No longer necessary to explicitly set `stx.layout.marketSessions` or `1stx.layout.extended` to manage sessions; instead call {@link CIQ.ExtendedHours.prepare} or {@link CIQ.ExtendedHours.set}. - * - 8.0.0 Added `params.menuContextClass`. - * - * @example - * // Call this only once to initialize the market sessions display manager. - * new CIQ.ExtendedHours({stx:stxx, filter:true}); - * - * // By default all sessions are disabled unless explicitly enabled. - * // This forces the extended hours sessions ["pre","post"] to be enabled when the chart is initially loaded. - * stxx.extendedHours.prepare(true); - * - * // Now display your chart. - * stxx.loadChart(stxx.chart.symbol, {}, function() {}); - * - * @example - * // Once your chart is displayed, you can call this from any UI interface to turn on extended hours. - * stx.extendedHours.set(true); - * - * // Or call this from any UI interface to turn off extended hours. - * stx.extendedHours.set(false); - * - * @example - * // CSS entries for a session divider and sessions named "pre" and "post". - * .stx_market_session.divider { - * background-color: rgba(0,255,0,0.8); - * width: 1px; - * } - * .stx_market_session.pre { - * background-color: rgba(255,255,0,0.1); - * } - * .stx_market_session.post { - * background-color: rgba(0,0,255,0.2); - * } - */ -CIQ.ExtendedHours = - CIQ.ExtendedHours || - function (params) { - var stx = params.stx; - this.filter = params.filter; - if (!stx) { - // backwards compatibility - stx = params; - this.filter = false; - } - var styles = {}; - this.stx = stx; - this.stx.extendedHours = this; - this.cssRequired = true; - - stx.addEventListener("theme", function (tObject) { - // reinitialize the session colors after a theme change - styles = {}; - for (var sess in stx.layout.marketSessions) { - if (!styles.session) styles.session = {}; - styles.session[sess] = stx.canvasStyle("stx_market_session " + sess); - } - }); - - stx.addEventListener("symbolChange", function (tObject) { - // check if extended hours exists for this security - if ( - tObject.action == "master" && - stx.layout.extended && - !(stx.chart.market.market_def && stx.chart.market.sessions.length) - ) { - CIQ.alert("There are no Extended Hours for this instrument."); - } - }); - - /** - * Prepares the extended hours settings and classes for the session names enumerated in the arguments without actually displaying or loading the data. - * - * This method can be used to force a particular session to load by default by calling it before {@link CIQ.ChartEngine#loadChart}. - * Otherwise the chart will be loaded with all sessions disabled until {@link CIQ.ExtendedHours.set} is invoked. - * - * {@link CIQ.ChartEngine#importLayout} will also call this method to ensure the sessions are restored as previously saved. - * - * @param {boolean} enable Set to turn on/off the extended-hours visualization. - * @param {array} sessions The sessions to visualize when enable is true. Any sessions previously visualized will be disabled. If set to null, will default to ["pre","post"]. - * @memberof CIQ.ExtendedHours - * @method prepare - * @since 5.0.0 - */ - this.prepare = function (enable, sessions) { - stx.layout.extended = enable; - for (var sess in stx.layout.marketSessions) { - styles.session = {}; - stx.chart.market.disableSession(sess); - } - stx.layout.marketSessions = {}; - if (enable) { - if (!sessions) sessions = ["pre", "post"]; - if (sessions.length) { - for (var s = 0; s < sessions.length; s++) { - stx.layout.marketSessions[sessions[s]] = true; - } - } else { - stx.layout.marketSessions = sessions; - } - } - for (sess in stx.layout.marketSessions) { - if (!styles.session) styles.session = {}; - styles.session[sess] = stx.canvasStyle("stx_market_session " + sess); - stx.chart.market.disableSession(sess, true); - } - }; - - /** - * gathers and renders the extended hours for the preset session names enumerated in prepare(). - * @param {function} cb Optional callback function to be invoked once chart is reloaded with extended hours data. - * @memberof CIQ.ExtendedHours - * @method complete - * @private - * @since 5.0.0 - */ - this.complete = function (cb) { - stx.changeOccurred("layout"); - if (!stx.chart.market.market_def) { - // possibly a 24 hours Market. Not necessarily an error but nothing to do for ExtendedHours - if (cb) cb(); - return; - } - if (this.filter) { - stx.createDataSet(); - stx.draw(); - if (cb) cb(); - } else { - stx.loadChart(stx.chart.symbol, cb); - } - }; - - /** - * Turns on or off extended hours for the session names enumerated in the arguments. - * @param {boolean} enable Set to turn on/off the extended-hours visualization. - * @param {array} sessions The sessions to visualize when enable is true. Any sessions previously visualized will be disabled. If set to null, will default to ["pre","post"]. - * @param {function} cb Optional callback function to be invoked once chart is reloaded with extended hours data. - * @memberof CIQ.ExtendedHours - * @method set - */ - this.set = function (enable, sessions, cb) { - this.prepare(enable, sessions); - this.complete(cb); - }; - - // This injection shades the after hours portion of the chart for each yaxis. - // Only the panel to which the yaxis belongs will get shading. - // This means yaxes of overlays will bypass the shading block. - this.stx.append("drawYAxis", function (panel, parameters) { - if (!this.layout.extended) return; - if ( - panel.yAxis != parameters.yAxis || - panel.shareChartXAxis === false || - panel.hidden - ) - return; - var chart = panel.chart; - if (CIQ.ChartEngine.isDailyInterval(this.layout.interval)) return; - styles.divider = this.canvasStyle("stx_market_session divider"); - if (styles.session) { - var m = chart.market; - var ranges = []; - var range = {}; - var nextBoundary, thisSession; - for (var i = 0; i < chart.dataSegment.length; i++) { - var ds = chart.dataSegment[i]; - if (!ds || !ds.DT) continue; - var c = null; - if (m.market_def) { - if (!nextBoundary || nextBoundary <= ds.DT) { - thisSession = m.getSession(ds.DT); - var filterSession = - thisSession !== "" && - (!this.layout.marketSessions || - !this.layout.marketSessions[thisSession]); - nextBoundary = m[filterSession ? "getNextOpen" : "getNextClose"]( - ds.DT - ); - } - } - - var s = styles.session[thisSession]; - if (s) c = s.backgroundColor; - if (range.color && range.color != c) { - ranges.push({ - start: range.start, - end: range.end, - color: range.color - }); - range = {}; - } - if (c) { - var cw = this.layout.candleWidth; - if (ds.candleWidth) cw = ds.candleWidth; - range.end = this.pixelFromBar(i, chart) + cw / 2; - if (!range.start && range.start !== 0) - range.start = range.end - cw + 1; - range.color = c; - } else { - range = {}; - } - } - if (range.start || range.start === 0) - ranges.push({ - start: range.start, - end: range.end, - color: range.color - }); - var noDashes = CIQ.isTransparent(styles.divider.backgroundColor); - var dividerLineWidth = styles.divider.width.replace(/px/g, ""); - var dividerStyle = { - y0: panel.bottom, - y1: panel.top, - color: styles.divider.backgroundColor, - type: "line", - context: chart.context, - confineToPanel: panel, - pattern: "dashed", - lineWidth: dividerLineWidth, - deferStroke: true - }; - this.startClip(panel.name); - chart.context.beginPath(); - if (stx.highlightedDraggable) chart.context.globalAlpha *= 0.3; - for (i = 0; i < ranges.length; i++) { - chart.context.fillStyle = ranges[i].color; - if (!noDashes && ranges[i].start > chart.left) - this.plotLine( - CIQ.extend( - { x0: ranges[i].start, x1: ranges[i].start }, - dividerStyle - ) - ); - chart.context.fillRect( - ranges[i].start, - panel.top, - ranges[i].end - ranges[i].start, - panel.bottom - panel.top - ); - if (!noDashes && ranges[i].end < chart.right) - this.plotLine( - CIQ.extend({ x0: ranges[i].end, x1: ranges[i].end }, dividerStyle) - ); - } - chart.context.stroke(); - this.endClip(); - } - }); - }; - -}; - - -let __js_addons_standard_fullScreen_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -/** - * Creates an add-on that sets the chart UI to full-screen mode. In full-screen mode, a class - * `full-screen` is added to the context element used for styling. In addition, elements with the - * class `full-screen-hide` are hidden. Elements with the class `full-screen-show` that are - * normally hidden are shown. - * - * Requires *addOns.js*. - * - * ![Full-screen display](./img-Full-Screen-Chart.png) - * - * @param {object} params Configuration parameters. - * @param {CIQ.ChartEngine} [params.stx] The chart object. - * - * @constructor - * @name CIQ.FullScreen - * @since 7.3.0 - * - * @example - * new CIQ.FullScreen({ stx: stxx }); - */ -CIQ.FullScreen = - CIQ.FullScreen || - function (params) { - if (!params) params = {}; - if (!params.stx) { - console.warn("The Full Screen addon requires an stx parameter"); - return; - } - // Check for loading within an iframe from another origin - try { - if (window.location.host !== window.top.location.host) - throw new Error( - window.location.host + " does not match " + window.top.location.host - ); - } catch (exception) { - console.warn("Full screen mode disabled."); - return; - } - this.stx = params.stx; - this.stx.fullScreen = this; - this.fullScreenButton = null; - this.fullScreenState = false; - - //Attaches FullScreen button to HTML DOM inside .chartSize element - this.addFullScreenButton = function () { - if (this.stx.registerChartControl) - this.fullScreenButton = this.stx.registerChartControl( - "stx-full-screen", - "Full Screen", - (function (self) { - return function (e) { - self.fullScreenToggle(e); - e.stopPropagation(); - }; - })(this) - ); - }; - - //Click event handler for the Full Screen button. - this.fullScreenToggle = function (e) { - // First check for availability of the requestFullScreen function - if ( - document.documentElement.requestFullscreen || - document.documentElement.webkitRequestFullscreen || - document.documentElement.mozRequestFullscreen || - document.documentElement.msRequestFullscreen - ) { - // Check if full screen is already enabled - if (this.getFullScreenElement()) { - if (document.exitFullscreen) document.exitFullscreen(); - else if (document.webkitExitFullscreen) - document.webkitExitFullscreen(); - else if (document.mozCancelFullScreen) document.mozCancelFullScreen(); - else if (document.msExitFullscreen) document.msExitFullscreen(); - } else { - // requestFullscreen methods need to be checked for again here because the browser will not allow the method to be stored in a local var - if (document.documentElement.requestFullscreen) - document.documentElement.requestFullscreen(); - else if (document.documentElement.webkitRequestFullscreen) - document.documentElement.webkitRequestFullscreen(); - else if (document.documentElement.mozRequestFullscreen) - document.documentElement.mozRequestFullscreen(); - else if (document.documentElement.msRequestFullscreen) - document.documentElement.msRequestFullscreen(); - } - } else { - //If the full screen api isn't available, manually trigger the fullScreen styling - this.fullScreenState = !this.fullScreenState; - this.fullScreenRender(); - } - }; - - // Append/remove full-screen class to context or body and update button state - this.fullScreenRender = function () { - var containerElement = null; - containerElement = this.stx.container.closest( - "*[cq-context], cq-context, body" - ); - if (containerElement) { - if (this.fullScreenState === true) { - if (this.fullScreenButton) - this.fullScreenButton.classList.add("active"); - containerElement.classList.add("full-screen"); - } else { - if (this.fullScreenButton) - this.fullScreenButton.classList.remove("active"); - containerElement.classList.remove("full-screen"); - } - // Trigger a resize event to update the chart size - window.dispatchEvent(new Event("resize")); - } - }; - - //Handle full screen change - this.onFullScreenChange = function () { - if (this.getFullScreenElement()) { - this.fullScreenState = true; - } else { - this.fullScreenState = false; - } - this.fullScreenRender(); - }; - - this.getFullScreenElement = function () { - return ( - document.fullscreenElement || - document.webkitCurrentFullScreenElement || - document.mozFullScreenElement || - document.msFullscreenElement - ); - }; - - document.addEventListener( - "fullscreenchange", - this.onFullScreenChange.bind(this), - false - ); - document.addEventListener( - "webkitfullscreenchange", - this.onFullScreenChange.bind(this), - false - ); - document.addEventListener( - "mozfullscreenchange", - this.onFullScreenChange.bind(this), - false - ); - document.addEventListener( - "MSFullscreenChange", - this.onFullScreenChange.bind(this), - false - ); - - // Add the FullScreen button to chartControls - this.addFullScreenButton(); - }; - -}; - - -let __js_addons_standard_inactivityTimer_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -/** - * Add-On that puts the chart into "sleep mode" after a period of inactivity. - * - * Requires *addOns.js*. - * - * In sleep mode, a class "ciq-sleeping" will be added to the body. This will dim out the chart. - * Sleep mode is ended when interaction with the chart is detected. - * - * @param {object} params Configuration parameters - * @param {CIQ.ChartEngine} [params.stx] The chart object - * @param {number} [params.minutes] Inactivity period in _minutes_. Set to 0 to disable the sleep mode. - * @param {number} [params.interval] Sleeping quote update interval in _seconds_. During sleep mode, this is used for the update loop. - * Set to non-zero positive number or defaults to 60. - * @param {function} [params.wakeCB] Optional callback function after waking - * @param {function} [params.sleepCB] Optional callback function after sleeping - * @constructor - * @name CIQ.InactivityTimer - * @since 3.0.0 - * @example - * new CIQ.InactivityTimer({stx:stxx, minutes:30, interval:15}); //30 minutes of inactivity will put chart into sleep mode, updating every 15 seconds - * - */ -CIQ.InactivityTimer = - CIQ.InactivityTimer || - function (params) { - if (!params.minutes) return; - if (!params.interval || params.interval < 0) params.interval = 60; - this.stx = params.stx; - this.timeout = params.minutes; - this.interval = params.interval; - this.wakeCB = params.wakeCB; - this.sleepCB = params.sleepCB; - this.sleepTimer = null; - this.sleeping = false; - this.last = new Date().getTime(); - this.wakeChart = function () { - clearTimeout(this.sleepTimer); - this.last = new Date().getTime(); - if (this.sleeping) { - if (this.stx.quoteDriver) this.stx.quoteDriver.updateChartLoop(); - this.sleeping = false; - document.body.classList.remove("ciq-sleeping"); - } - this.sleepTimer = setTimeout( - this.sleepChart.bind(this), - this.timeout * 60000 - ); - if (this.wakeCB) this.wakeCB(); - }; - this.sleepChart = function () { - if (!this.sleeping) { - if (this.stx.quoteDriver) - this.stx.quoteDriver.updateChartLoop(this.interval); - this.sleeping = true; - document.body.classList.add("ciq-sleeping"); - } - if (this.sleepCB) this.sleepCB(); - }; - - var self = this; - [ - "mousemove", - "mousedown", - "touchstart", - "touchmove", - "pointerdown", - "pointermove", - "keydown", - "wheel" - ].forEach(function (ev) { - document.body.addEventListener(ev, function (e) { - self.wakeChart(); - }); - }); - this.wakeChart(); - }; - -}; - - -let __js_addons_standard_rangeSlider_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -/** - * Add-on that puts a range slider under the chart. - * - * This allows the `dataSegment` to be selectable as a portion of the dataset. - * - * Requires *addOns.js*. - * - * It also requires additional CSS. - * - * Either add: - * ``` - * - * ``` - * Or explicitly include this CSS: - * ``` - * .stx_range_slider.shading { - * background-color: rgba(128, 128, 128, 0.3); - * border: solid 2px #0090b7; - * width: 5px; - * } - * ``` - * Once instantiated, it can be displayed or hidden by simply setting the `rangeSlider` parameter - * of the primary chart's **layout object**, and then issuing a layout change event to trigger the - * new status. Make sure to use the callback to enable the slider on initial load to prevent - * "out of sequence" issues. See examples for exact syntax. - * - * Remember, a range slider is simply just another chart. So you configure it and customize it - * using the same parameters as you would the primary chart. The only difference is that the - * slider object will be a sub element of the primary chart, living inside the `slider.slider` - * object. - * - * For example, if you wanted to turn off the x-axis on the slider, assuming a chart instantiated - * as `stxx`, you would execute: - * ``` - * stxx.slider.slider.xaxisHeight = 0; - * ``` - * - * If using chartIQ web components, the slider needs to be created **before** the UI manager - * (startUI) is called for custom themes to apply. - * - * It is important to note that the range slider chart container will create itself **under** the - * primary chart container, not **inside**. As such, to ensure styling is shared between the two - * containers and they match in look and feel, all the styling must be on a parent `div` container - * rather than the primary chart container itself. - * - * For example, do this: - * ``` - *
- *
- *
- *
- * - *
- *
- *
- * ``` - * - * Not this: - * ``` - *
- *
- *
- *
- *
- * ``` - * - * Range slider working example: - * - * - * @param {object} params Configuration parameters. - * @param {CIQ.ChartEngine} [params.stx] The chart object. - * @param {number} [params.height="95px"] Height of the range slider panel. Must include a CSS - * unit, such as "px". - * @param {object} [params.yAxis] Y-axis parameters. - * @param {number} [params.chartContainer] Handle to the main chart container. Defaults to - * `stxx.container`. - * @param {string} [params.menuContextClass] A CSS class name used to query the menu DOM element - * that contains the UI control for the range slider add-on. In a multi-chart document, the - * add-on is available only on charts that have a menu DOM element with the value for - * `menuContextClass` as a class attribute. - * - * @constructor - * @name CIQ.RangeSlider - * @since - * - 4.0.0 - * - 6.1.0 Added `params.yAxis`. - * - 8.0.0 Added `params.menuContextClass`. - * - * @example - * - * Create a range slider and enable it by default using the loadChart callback. - * - * const stxx = new CIQ.ChartEngine({ container: document.querySelector(".chartContainer") }); - * - * stxx.attachQuoteFeed(quoteFeedSimulator,{ refreshInterval: 1, bufferSize: 200 }); - * - * // Instantiate a range slider. - * new CIQ.RangeSlider({ stx: stxx }); - * - * function displayChart(){ - * stxx.loadChart("SPY", null, function() { - * // For smoother visualization, enable after the main chart has completed loading its data. - * stxx.layout.rangeSlider = true; // Show the slider. - * stxx.changeOccurred("layout"); // Signal the change to force a redraw. - * }); - * } - * - * @example - * - * Create a range slider and enable/disable it using commands to be triggered from a menu. - * - * const stxx = new CIQ.ChartEngine({ container: document.querySelector(".chartContainer") }); - * - * // Instantiate a range slider. - * new CIQ.RangeSlider({ stx: stxx }); - * - * // To display the slider from a menu use: - * stxx.layout.rangeSlider = true; // Show the slider. - * stxx.changeOccurred("layout"); // Signal the change to force a redraw. - * - * // To hide the slider from a menu use: - * stxx.layout.rangeSlider = false; // Hide the slider. - * stxx.changeOccurred("layout"); // Signal the change to force a redraw. - */ -CIQ.RangeSlider = - CIQ.RangeSlider || - function (params) { - this.cssRequired = true; - - var stx = params.stx; - stx.slider = this; - var sliderHeight = params.height ? params.height : "95px"; - var chartContainer = params.chartContainer - ? params.chartContainer - : params.stx.container; - - var ciqSlider = document.createElement("div"); - ciqSlider.className = "ciq-chart"; - var sliderContainer = document.createElement("div"); - sliderContainer.className = "chartContainer"; - ciqSlider.appendChild(sliderContainer); - chartContainer.parentElement.parentElement.insertBefore( - ciqSlider, - chartContainer.parentElement.nextSibling - ); - Object.assign(ciqSlider.style, { - height: sliderHeight, - paddingTop: "5px", - display: "none" - }); - sliderContainer.style.height = "100%"; - sliderContainer.dimensionlessCanvas = true; - var self = (this.slider = new CIQ.ChartEngine({ - container: sliderContainer, - preferences: { labels: false, whitespace: 0 } - })); - self.xaxisHeight = 30; - self.manageTouchAndMouse = false; - self.minimumCandleWidth = 0; - self.chart.panel.subholder.style.cursor = "ew-resize"; - var yAxis = self.chart.panel.yAxis; - yAxis.drawCurrentPriceLabel = false; - Object.defineProperty(yAxis, "position", { - get: function () { - return stx.slider.yAxisPosition || stx.chart.panel.yAxis.position; - }, - set: function (position) { - stx.slider.yAxisPosition = position; - } - }); - const { get, set } = Object.getOwnPropertyDescriptor( - CIQ.ChartEngine.YAxis.prototype, - "width" - ); - Object.defineProperty(yAxis, "width", { - get: function () { - return Math.max(get.call(yAxis), stx.chart.yAxis.width); - }, - set: function (width) { - set.call(yAxis, width); - } - }); - CIQ.extend(yAxis, params.yAxis); - self.chart.baseline.userLevel = false; - if (self.controls.home) self.controls.home.style.width = 0; - self.initializeChart(); - var subholder = self.chart.panel.subholder; - - /** - * Dynamically updates the styling of the range slider. - * - * This method can be used to update CSS styles if you are injecting stylesheets using - * JavaScript. - * - * @param {string} obj The CSS selector for which a style property is changed. - * @param {string} attribute The style property changed in the CSS selector rule-set. - * @param {string} value The value to apply to the CSS property. - * - * @alias updateStyles - * @memberof CIQ.RangeSlider.prototype - * @since 8.0.0 - * - * @example - * // Set the shading of the range slider. - * stxx.slider.updateStyles( - * 'stx_range_slider shading', - * 'backgroundColor', - * 'rgba(200, 50, 50, 0.45)' - * ); - * - * @example - * // Set the color of the bars of the range slider to red. - * stxx.slider.updateStyles( - * 'stx_range_slider shading', - * 'borderTopColor', - * 'rgba(255, 0, 0)' - * ); - */ - this.updateStyles = function (obj, attribute, value) { - stx.setStyle(obj, attribute, value); - this.style = stx.canvasStyle("stx_range_slider shading"); - }; - - this.display = function (on) { - if (stx.layout.rangeSlider !== on) { - // do this the way it was intended - stx.layout.rangeSlider = on; - stx.changeOccurred("layout"); - return; - } - ciqSlider.style.display = on ? "" : "none"; - stx.resizeChart(); - window.dispatchEvent(new Event("resize")); - if (!on) return; - self.resizeChart(); - self.initializeChart(); - self.draw(); - this.drawSlider(); - }; - this.setSymbol = function (symbol) { - self.chart.panel.display = self.chart.symbol = symbol; - self.setMainSeriesRenderer(); - self.resizeChart(); - this.adjustRange(stx.chart); - self.draw(); - this.drawSlider(); - }; - this.acceptLayoutChange = function (layout) { - var doDraw = false; - if (self.layout.rangeSlider !== layout.rangeSlider) { - stx.slider.display(layout.rangeSlider); - } - var relevantLayoutPropertiesForRedraw = [ - "chartType", - "aggregationType", - "periodicity", - "interval", - "timeUnit", - "chartScale", - "rangeSlider", - "flipped", - "extended", - "marketSessions", - "kagi", - "rangebars", - "renko", - "priceLines", - "pandf" - ]; - relevantLayoutPropertiesForRedraw.forEach(function (x) { - if (!CIQ.equals(self.layout[x], layout[x])) { - self.layout[x] = layout[x]; - doDraw = true; - } - }); - if (!CIQ.trulyVisible(ciqSlider)) return; - if (doDraw) { - self.setMainSeriesRenderer(); - self.draw(); - this.drawSlider(); - } - }; - this.adjustRange = function (chart) { - if (!chart.dataSet) return; - if (!chart.endPoints || !chart.endPoints.begin) return; - var myChart = self.chart; - if (!myChart.width) return; - var scrollOffset = 0, - ticksOffset = 0; - if (stx.quoteDriver) { - var behaviorParams = { - symbol: chart.symbol, - symbolObject: chart.symbolObject, - interval: stx.layout.interval - }; - if ( - (behaviorParams.interval == "month" || - behaviorParams.interval == "week") && - !stx.dontRoll - ) { - behaviorParams.interval = "day"; - } - var behavior = stx.quoteDriver.getQuoteFeed(behaviorParams).behavior; - if (behavior && behavior.bufferSize) { - if (chart.moreAvailable) scrollOffset = behavior.bufferSize; - if (stx.isHistoricalMode()) ticksOffset = behavior.bufferSize; - } - } - myChart.baseline.defaultLevel = chart.baseline.actualLevel; - myChart.scroll = - Math.max( - 0, - chart.dataSet.length - - stx.tickFromDate(chart.endPoints.begin) - - scrollOffset - ) + 1; - myChart.maxTicks = myChart.scroll - ticksOffset + 1; - self.layout.candleWidth = myChart.width / myChart.maxTicks; - }; - this.copyData = function (chart) { - if (!chart.dataSet) return; - var myChart = self.chart; - myChart.masterData = self.masterData = chart.masterData; - myChart.dataSet = chart.dataSet; - myChart.state = chart.state; - self.draw(); - this.drawSlider(); - }; - this.calculateYAxisPosition = function () { - var panel = self.chart.panel; - var currentPosition = self.getYAxisCurrentPosition(panel.yAxis, panel); - if (currentPosition != panel.yAxis.position) - self.calculateYAxisPositions(); - }; - this.drawSlider = function () { - if (!CIQ.trulyVisible(ciqSlider)) return; - if (!stx.chart.dataSet || !stx.chart.dataSet.length) return; - var style = this.style; - if (!style) - style = this.style = stx.canvasStyle("stx_range_slider shading"); - var chartPanel = stx.chart.panel, - ctx = self.chart.context, - segmentImage = self.chart.segmentImage || [], - halfCandle = self.layout.candleWidth / 2; - var left = (self.tickLeft = Math.max( - stx.tickFromPixel(chartPanel.left + halfCandle), - 0 - )); - var right = (self.tickRight = Math.min( - stx.tickFromPixel(chartPanel.right - halfCandle), - stx.chart.dataSet.length - 1 - )); - var pLeft = (self.pixelLeft = - self.pixelFromTick(left) - - (segmentImage[left] ? segmentImage[left].candleWidth / 2 : halfCandle)); - var pRight = (self.pixelRight = - self.pixelFromTick(right) + - (segmentImage[right] - ? segmentImage[right].candleWidth / 2 - : halfCandle)); - var leftBoundary = subholder.offsetLeft, - rightBoundary = leftBoundary + subholder.offsetWidth; - ctx.save(); - ctx.beginPath(); - ctx.fillStyle = style.backgroundColor; - ctx.fillRect( - leftBoundary, - subholder.offsetTop, - pLeft - leftBoundary, - subholder.offsetHeight - ); - ctx.fillRect( - rightBoundary, - subholder.offsetTop, - pRight - rightBoundary, - subholder.offsetHeight - ); - ctx.strokeStyle = style.borderTopColor; - ctx.lineWidth = parseInt(style.borderWidth, 10); - ctx.moveTo(pLeft, subholder.offsetTop); - ctx.lineTo(pLeft, subholder.offsetTop + subholder.offsetHeight); - ctx.moveTo(pRight, subholder.offsetTop); - ctx.lineTo(pRight, subholder.offsetTop + subholder.offsetHeight); - ctx.stroke(); - ctx.beginPath(); - ctx.lineWidth = parseInt(style.width, 10); - ctx.lineCap = "round"; - ctx.moveTo(pLeft, subholder.offsetTop + subholder.offsetHeight / 4); - ctx.lineTo(pLeft, subholder.offsetTop + (3 * subholder.offsetHeight) / 4); - ctx.moveTo(pRight, subholder.offsetTop + subholder.offsetHeight / 4); - ctx.lineTo( - pRight, - subholder.offsetTop + (3 * subholder.offsetHeight) / 4 - ); - ctx.stroke(); - ctx.restore(); - }; - stx.addEventListener("layout", function (obj) { - obj.stx.slider.acceptLayoutChange(obj.stx.layout); - }); - stx.addEventListener("preferences", function (obj) { - const { language } = obj.stx.preferences; - if (CIQ.I18N && self.preferences.language != language) { - CIQ.I18N.setLocale(self, language); - } - self.preferences.language = language; - self.draw(); - }); - stx.addEventListener("symbolChange", function (obj) { - if (obj.action == "master") obj.stx.slider.setSymbol(obj.symbol); - }); - stx.addEventListener("symbolImport", function (obj) { - if (obj.action == "master") obj.stx.slider.setSymbol(obj.symbol); - obj.stx.slider.acceptLayoutChange(obj.stx.layout); - }); - stx.addEventListener("theme", function (obj) { - self.clearPixelCache(); - self.styles = {}; - self.chart.container.style.backgroundColor = ""; - if (CIQ.ThemeHelper) { - var helper = new CIQ.ThemeHelper({ stx: obj.stx }); - helper.params.stx = self; - helper.update(); - } - }); - stx.append("createDataSet", function () { - this.slider.adjustRange(this.chart); - this.slider.copyData(this.chart); - }); - stx.append("draw", function () { - if (!CIQ.trulyVisible(ciqSlider)) return; - if (!self.chart.dataSet) return; - this.slider.adjustRange(this.chart); - this.slider.calculateYAxisPosition(); - self.draw(); - this.slider.drawSlider(); - }); - stx.prepend("resizeChart", function () { - var ciqChart = chartContainer.parentElement, - chartArea = ciqChart.parentElement; - var heightOffset = - parseFloat(getComputedStyle(ciqChart).height) - - parseFloat(getComputedStyle(chartContainer).height); - var totalHeightOfContainers = CIQ.elementDimensions(chartArea).height; - var chartContainers = chartArea.querySelectorAll(".chartContainer"); - Array.from(chartContainers).forEach(function (container) { - if (container !== chartContainer && CIQ.trulyVisible(container)) { - totalHeightOfContainers -= CIQ.elementDimensions(container, { - border: 1, - padding: 1, - margin: 1 - }).height; - } - }); - ciqChart.style.height = totalHeightOfContainers + "px"; - if (this.layout.rangeSlider) { - if (self.chart.breakpoint !== this.chart.breakpoint) { - self.notifyBreakpoint(this.chart.breakpoint); - } - ciqSlider.style.display = ""; - self.resizeChart(); - self.initializeChart(); - self.draw(); - this.slider.drawSlider(); - } else { - ciqSlider.style.display = "none"; - } - }); - ["mousedown", "touchstart", "pointerdown"].forEach(function (ev) { - subholder.addEventListener( - ev, - function (e) { - var start = self.backOutX(e.pageX); - if (!start && start !== 0) return; // wrong event - start -= e.target.offsetLeft; - self.startDrag = start; - self.startPixelLeft = self.pixelLeft; - self.startPixelRight = self.pixelRight; - var style = stx.slider.style; - if (!style) - style = stx.slider.style = stx.canvasStyle( - "stx_range_slider shading" - ); - var bw = parseInt(style.borderLeftWidth, 10); - start += this.offsetLeft; - if (start < self.pixelRight - bw) self.needsLeft = true; - if (start > self.pixelLeft + bw) self.needsRight = true; - if (CIQ.touchDevice) return; - if (self.needsLeft && self.needsRight) { - // change to grab only if drag started from viewport - e.target.classList.add("stx-drag-chart"); - } - }, - { passive: false } - ); - }); - ["mouseup", "mouseover", "touchend", "pointerup"].forEach(function (ev) { - subholder.addEventListener(ev, function (e) { - const { which, type } = e; - if (which === 1 && type !== "pointerup" && type !== "mouseup") return; - e.target.classList.remove("stx-drag-chart"); - self.chart.panel.subholder.style.cursor = "ew-resize"; - self.startDrag = null; - self.needsLeft = false; - self.needsRight = false; - }); - }); - ["mousemove", "touchmove", "pointermove"].forEach(function (ev) { - subholder.addEventListener( - ev, - function (e) { - var startDrag = self.startDrag; - if (!startDrag && startDrag !== 0) return; - var touches = e.touches; - var movement = - (touches && touches.length - ? self.backOutX(touches[0].pageX) - : self.backOutX(e.pageX)) - e.target.offsetLeft; - if (!movement && movement !== 0) return; // wrong event - movement -= startDrag; - var tickLeft = self.tickLeft, - tickRight = self.tickRight; - var startPixelLeft = self.startPixelLeft, - startPixelRight = self.startPixelRight; - var needsLeft = self.needsLeft, - needsRight = self.needsRight; - if (needsLeft) { - if (startPixelLeft + movement < self.chart.left) - movement = self.chart.left - startPixelLeft; - if (needsRight && startPixelRight + movement >= self.chart.right) { - movement = self.chart.right - startPixelRight; - if (!self.isHome()) movement += self.layout.candleWidth / 2; // force a right scroll - } - tickLeft = self.tickFromPixel(startPixelLeft + movement); - if (needsRight) - tickRight = tickLeft + self.tickRight - self.tickLeft; - } else if (needsRight) { - tickRight = Math.min( - self.tickFromPixel(startPixelRight + movement), - stx.chart.dataSet.length - 1 - ); - } else return; - - var newCandleWidth = stx.chart.width / (tickRight - tickLeft + 1); - if ( - tickRight >= tickLeft && - newCandleWidth >= stx.minimumCandleWidth - ) { - self.tickLeft = tickLeft; - self.tickRight = tickRight; - stx.chart.scroll = stx.chart.dataSet.length - tickLeft; - if (!needsLeft || !needsRight) { - stx.setCandleWidth(newCandleWidth); - } - stx.micropixels = 0; - stx.draw(); - } - }, - { passive: false } - ); - }); - this.adjustRange(stx.chart); - this.copyData(stx.chart); - }; - -}; - - -let __js_addons_standard_shortcuts_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -/** - * Displays a legend of keyboard shortcuts and the actions the shortcuts perform. - * - * Delegates display of the legend to the - * [cq-floating-window]{@link WebComponents.cq-floating-window} web component by dispatching a - * "floatingWindow" event (see - * [floatingWindowEventListener]{@link CIQ.ChartEngine~floatingWindowEventListener}). - * - * Creates the legend from keyboard shortcut specifications contained in a configuration object; - * for example, the default chart configuration object (see the {@tutorial Chart Configuration} - * tutorial). - * - * Requires *addOns.js*. - * - * @param {object} params The constructor parameters. - * @param {CIQ.ChartEngine} params.stx The chart engine instance for which the keyboard shortcuts - * legend is created. - * @param {object} params.config A configuration object that includes specifications for hot keys - * and drawing tool keyboard shortcuts. Typically, this object is the chart configuration - * object. See the {@tutorial Chart Configuration} tutorial for the data format for keyboard - * shortcuts. - * @param {number} [params.width="580"] The width of the floating window that contains the - * keyboard shortcuts legend. - * @param {boolean} [params.windowForEachChart=true] A flag that indicates whether each chart - * instance in a multi-chart document has its own keyboard shortcuts legend. If false, all - * charts share the same legend. - * - * @constructor - * @name CIQ.Shortcuts - * @since 8.2.0 - * - * @example - * new CIQ.Shortcuts( - * stx: stxx, - * config: { - * drawingTools: [{ label: "line", shortcut: "l" }], - * hotkeyConfig: { - * hotkeys: [{ label: "Pan chart up", action: "up", commands: ["ArrowUp", "Up"] }] - * } - * } - * ); - */ -CIQ.Shortcuts = - CIQ.Shortcuts || - function ({ stx, width = 580, windowForEachChart = true, config } = {}) { - if (!stx) { - console.warn("The Shortcuts addon requires an stx parameter"); - return; - } - /** - * The chart engine instance for which the keyboard shortcuts legend is created. - * - * @type {CIQ.ChartEngine} - * @memberof CIQ.Shortcuts# - * @alias stx - * @since 8.2.0 - */ - this.stx = stx; - /** - * Width of the floating window that contains the keyboard shortcuts legend. - * - * @type {number} - * @memberof CIQ.Shortcuts# - * @alias width - * @since 8.2.0 - */ - this.width = width; - /** - * In a multi-chart document, indicates whether each chart has its own keyboard shortcuts - * legend. If false, all charts share the same legend. - * - * @type {boolean} - * @memberof CIQ.Shortcuts# - * @alias windowForEachChart - * @since 8.2.0 - */ - this.windowForEachChart = windowForEachChart; - this.content = this.getShortcutContent(config); - this.enclosingContainer = stx.container.querySelector(".stx-subholder"); - - this.ensureMessagingAvailable(stx); - this.enableUI(stx); - this.cssRequired = true; - - stx.shortcuts = this; - }; - -/** - * Enables the keyboard shortcuts legend user interface. - * - * Adds a `showShortCuts` function to the {@link CIQ.UI.Layout} helper. The `showShortCuts` - * function calls this class's [toggle]{@link CIQ.Shortcuts#toggle} function to show and hide the - * keyboard shortcuts legend. Call `showShortCuts` in your application's user interface (see - * example). - * - * This function is called when the add-on is instantiated. - * - * @param {CIQ.ChartEngine} stx The chart engine that provides the UI context for the keyboard - * shortcuts legend. - * - * @memberof CIQ.Shortcuts - * @since 8.2.0 - * - * @example Create a button that shows and hides the keyboard shortcuts legend. - * - */ -CIQ.Shortcuts.prototype.enableUI = function (stx) { - if (!(stx && CIQ.UI)) return; - setTimeout(() => { - const layout = stx.uiContext.getAdvertised("Layout"); - layout.showShortcuts = (node, value) => this.toggle(value); - }); -}; - -/** - * Ensures that an instance of the [cq-floating-window]{@link WebComponents.cq-floating-window} - * web component is available to handle event messaging and create the shortcuts legend floating - * window. - * - * This function is called when the add-on is instantiated. - * - * @param {CIQ.ChartEngine} stx The chart engine that provides the UI context, which contains the - * [cq-floating-window]{@link WebComponents.cq-floating-window} web component. - * - * @memberof CIQ.Shortcuts - * @since 8.2.0 - */ -CIQ.Shortcuts.prototype.ensureMessagingAvailable = function (stx) { - setTimeout(() => { - const contextContainer = stx.uiContext.topNode; - if (!contextContainer.querySelector("cq-floating-window")) { - contextContainer.append(document.createElement("cq-floating-window")); - } - }); -}; - -/** - * Creates the contents of the keyboard shortcuts legend based on specifications contained in a - * configuration object. The contents are displayed in a - * [cq-floating-window]{@link WebComponents.cq-floating-window} web component. - * - * This function is called when the add-on is instantiated. - * - * @param {object} config A configuration object that includes specifications for drawing tool - * keyboard shortcuts and hot keys. Typically, this object is the chart configuration object - * (see the {@tutorial Chart Configuration} tutorial). - * @return {string} The keyboard shortcuts legend as HTML. - * - * @memberof CIQ.Shortcuts - * @since 8.2.0 - */ -CIQ.Shortcuts.prototype.getShortcutContent = function (config) { - const drawingToolShortcuts = (config.drawingTools || []) - .filter((tool) => tool.shortcut) - .map( - ({ label, shortcut }) => - `
-
${label}
-
Alt + ${shortcut.toUpperCase()}
-
` - ) - .join(""); - - // Alt + key combination produces unpredictable accent characters depending on keyboard mapping - // default hotkeys include them for better coverage, avoid displaying them in legend - const isAscii = (str) => str.charCodeAt(str.length - 1) < 127; - const wrapKeys = (str) => - str === " + " - ? "+" - : str - .split("+") - .map((el) => (el && el !== " " ? "" + el + "" : "")) - .join(" + "); - - const commandsToString = (commands) => { - return commands - .map((command) => command.replace(/Arrow|Key|Digit|^ | $/g, "")) - .map((command) => command.replace(/\+/, " + ")) - .reduce( - (acc, command) => - !acc.includes(command) && isAscii(command) - ? acc.concat(command) - : acc, - [] - ) - .map(wrapKeys) - .join("
"); - }; - - const container = this.stx.container.closest("cq-context"); - const extensionAvailable = (name) => - container.hasAttribute(name.toLowerCase() + "-active"); - const hotkeys = ((config.hotkeyConfig && config.hotkeyConfig.hotkeys) || []) - .map(({ label, action, commands, extension }) => { - if (extension && !extensionAvailable(extension)) { - return ""; - } - return `
${ - label || action - }
${commandsToString(commands)}
`; - }) - .join(""); - - return ` -
-
-
Drawing tools shortcuts
-
${drawingToolShortcuts}
-
-
-
-
Hotkeys
-
${hotkeys}
-
-
- `; -}; - -/** - * Opens and closes the floating window that contains the keyboard shortcuts legend. - * - * @param {boolean} [value] If true, the window is opened. If false, the window is closed. - * If not provided, the window state is toggled. That is, the window is opened if it is - * currently closed; closed, if it is currently open. - * - * @memberof CIQ.Shortcuts - * @since 8.2.0 - */ -CIQ.Shortcuts.prototype.toggle = function (value) { - this.stx.dispatch("floatingWindow", { - type: "shortcut", - title: "Shortcuts", - content: this.content, - container: this.enclosingContainer, - onClose: () => (this.closed = true), - width: this.width, - status: value, - tag: this.windowForEachChart ? undefined : "shortcut" - }); -}; - -}; - - -let __js_addons_standard_tableView_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -/** - * Creates an overlay that displays the visible chart data segment as a table. - * - * The overlay includes controls that enable users to copy the table data to the clipboard or - * download the data as a character-separated values (CSV) file. See - * {@link TableViewBuilder.dataToCsv} for the default separator character. - * - * The table view can be opened using the Alt+K keystroke combination and closed using the Escape - * key (see the `tableView` action in `hotkeyConfig.hotkeys` in *js/defaultConfiguration.js*). - * - * Requires *addOns.js*. - * - * @param {object} params Configuration parameters. - * @param {CIQ.ChartEngine} params.stx A reference to the chart engine that contains the chart for - * which the table view is created. - * @param {string} [params.minColumnWidth="84px"] The minimum width (including units) of the - * table columns. **Note:** The units can be any CSS unit acceptable by the CSS `calc` - * function. - * @param {number} [params.coverUIMaxWidth=400] The chart width (in pixels) below which the table - * view covers the entire chart, including user interface elements (symbol input field, - * menus, etc.). For example, if the value of this parameter is 1000, the table view covers - * the entire chart area if the chart width is <= 999 pixels. - * @param {string} [params.coverContainer] A CSS selector used to obtain the DOM element that - * ultimately contains the table view; for example, ".chartContainer". - * @param {boolean} [params.usePreviousCloseForChange=true] Indicates whether the closing price of - * the previous data point should be used instead of the opening price of the current data - * point to determine the amount of change for the current data point; that is, - * (current close - previous close) or (current close - current open). - * - * @constructor - * @name CIQ.TableView - * @since 8.1.0 - * - * @example - * new CIQ.TableView({ stx: stxx }); - */ -CIQ.TableView = - CIQ.TableView || - function ({ - stx, - minColumnWidth = "84px", - coverUIMaxWidth = 400, - coverContainer, - usePreviousCloseForChange = true - } = {}) { - if (!stx) { - console.warn("The TableView addon requires an stx parameter"); - return; - } - - /** - * The chart engine instance that contains the chart for which the table view is created. - * - * @type CIQ.ChartEngine - * @memberof CIQ.TableView# - * @alias stx - * @since 8.1.0 - */ - this.stx = stx; - /** - * Toggle to display and hide additional table view columns, such as % Change and Volume. - * - * **Note:** Data in the additional columns might not be present in the chart view because - * the data is calculated (for example, % Change) or is not part of the standard chart - * display (for example, Volume — which can be displayed with the - * [Volume Chart]{@link CIQ.Studies.createVolumeChart} study). - * - * @type boolean - * @memberof CIQ.TableView# - * @alias viewAdditionalColumns - * @since 8.1.0 - */ - this.viewAdditionalColumns = false; - /** - * Minimum width of the table view columns, including units. The units can be any CSS - * unit acceptable by the CSS `calc` function. - * - * @type string - * @memberof CIQ.TableView# - * @alias minColumnWidth - * @since 8.1.0 - */ - this.minColumnWidth = minColumnWidth; - /** - * The chart width in pixels below which the table view covers the entire chart, including - * user interface elements, such as the menus and footer. - * - * @type number - * @memberof CIQ.TableView# - * @alias coverUIMaxWidth - * @since 8.1.0 - */ - this.coverUIMaxWidth = coverUIMaxWidth; - /** - * A CSS selector used to obtain the DOM element that hosts the table view. - * - * @type string - * @memberof CIQ.TableView# - * @alias coverContainer - * @since 8.1.0 - */ - this.coverContainer = coverContainer; - /** - * If true, the closing price of the previous data point is used instead of the opening - * price of the current data point to determine the amount of change for the current data - * point. - * - * @type boolean - * @memberof CIQ.TableView# - * @alias usePreviousCloseForChange - * @since 8.1.0 - */ - this.usePreviousCloseForChange = usePreviousCloseForChange; - /** - * A reference to the {@link TableViewBuilder} namespace for access to the namespace - * static methods. - * - * @type TableViewBuilder - * @memberof CIQ.TableView# - * @alias builder - * @since 8.1.0 - */ - this.builder = TableViewBuilder; - - this.listeners = []; - - stx.tableView = this; - this.cssRequired = true; - - if (CIQ.UI) { - CIQ.UI.observeProperty("uiContext", stx, ({ value: uiContext }) => { - if (!uiContext) return; - - setTimeout(() => { - this.subscribeToChanges(uiContext); - - // Updated hotkey alias if available to action - const tableViewKeyEntry = CIQ.getFromNS( - uiContext.config, - "hotkeyConfig.hotkeys", - [] - ).find(({ action }) => action === "tableView"); - if (tableViewKeyEntry) { - tableViewKeyEntry.action = () => { - const { tableView } = document.body.keystrokeHub.context.stx; - if (tableView) { - tableView.toggle(); - return true; - } - }; - } - }); - }); - } - }; - -/** - * Displays the table view. - * - * @param {object} [params] Configuration parameters. - * @param {object} [params.config] Table column information. - * @param {function} [params.onClose] Callback function to execute on closing the table view. The - * callback enables synchronization of state in the application when the table view is - * closed. - * - * @memberof CIQ.TableView - * @since 8.1.0 - */ -CIQ.TableView.prototype.open = function (params) { - if (params) { - this.params = params; - } - const { config = {}, onClose } = this.params || {}; - if (this.view) { - this.close(false); - } - config.minColumnWidth = this.minColumnWidth; - config.coverUIMaxWidth = this.coverUIMaxWidth; - config.coverContainer = this.coverContainer; - this.onClose = onClose; - this.view = this.builder.createTable(this.stx, config); - if (!this.view) return; - if (CIQ.I18N) CIQ.I18N.translateUI(null, this.view); - const { stx } = this; - const close = this.close.bind(this); - - setTimeout(() => (this.removeCloseListener = getCloseListener(this))); - - const scrollbarStyling = CIQ.getFromNS( - stx, - "uiContext.config.scrollbarStyling" - ); - if (scrollbarStyling) { - scrollbarStyling.refresh(this.view.querySelector("tbody")); - scrollbarStyling.refresh( - this.view.querySelector(".ciq-data-table-wrapper"), - { suppressScrollY: true } - ); - } - - function getCloseListener(self) { - const contextNode = stx.uiContext.topNode; - const withinTable = (el) => el.closest(".ciq-data-table-container"); - - const closeHandler = ({ target }) => !withinTable(target) && close(); - contextNode.addEventListener("click", closeHandler); - const handleKeydown = (e) => { - if (e.code === "Escape") { - const { tableView } = document.body.keystrokeHub.context.stx; - if (tableView) { - tableView.close(); - e.preventDefault(); - } - } - }; - document.body.addEventListener("keydown", handleKeydown); - - // Use modal functionality available in menu - const uiManager = CIQ.getFn("UI.getUIManager")(); - if (uiManager) { - // Menu item requires show and hide providing no-op functions - self.view.show = self.view.hide = function () {}; - uiManager.openMenu(self.view, {}); - } - return () => { - contextNode.removeEventListener("click", closeHandler); - document.body.removeEventListener("keydown", handleKeydown); - if (uiManager) uiManager.closeMenu(self.view); - }; - } -}; - -/** - * Closes the table view. - * - * @param {boolean} [notify=true] Indicates whether the `onClose` callback function is set (see - * [open]{@link CIQ.TableView#open}). - * - * @memberof CIQ.TableView - * @since 8.1.0 - */ -CIQ.TableView.prototype.close = function (notify = true) { - if (this.view) { - this.view.remove(); - this.view = null; - } - if (notify && this.onClose) { - this.onClose(); - } - - if (this.removeCloseListener) { - this.removeCloseListener(); - this.removeCloseListener = null; - } -}; - -/** - * Opens the table view if it is closed. Closes the table view if it is open. - * - * @memberof CIQ.TableView - * @since 8.1.0 - */ -CIQ.TableView.prototype.toggle = function () { - this[this.view ? "close" : "open"](); -}; - -/** - * Subscribes to changes in the table view component communication channel, which enables other - * components to open and close the table view. - * - * @param {CIQ.UI.Context} uiContext The user interface context of the table view. Provides the - * communication channel path that identifies the table view channel. - * @param {string} [channelPath] Specifies the channel path if the path is not available in the - * context configuration provided by `uiContext`. - * - * @memberof CIQ.TableView - * @since 8.1.0 - */ -CIQ.TableView.prototype.subscribeToChanges = function ( - uiContext, - channelPath = "channels.tableView" -) { - const { channelSubscribe, channelWrite } = CIQ.UI.BaseComponent.prototype; - const { channels: { tableView = channelPath } = {} } = uiContext.config || {}; - const { stx } = this; - - channelSubscribe( - tableView, - (value) => { - if (value) { - stx.tableView.open({ - onClose: () => { - channelWrite(tableView, false, stx); - } - }); - } else { - stx.tableView.close(); - } - }, - stx - ); -}; - -/** - * Namespace for {@link CIQ.TableView} creation–related properties and functions. - * - * @namespace - * @name TableViewBuilder - * @since 8.1.0 - */ -function TableViewBuilder() {} - -/** - * The column header configuration for the table view. - * - * Can be used for rearranging the column order, removing columns, and updating labels. - * - * **Note:** Adding new columns has no effect. - * - * @type Object. - * @memberof TableViewBuilder - * @since 8.1.0 - */ -TableViewBuilder.colHeaders = { - date: { label: "Date" }, - open: { label: "Open" }, - high: { label: "High" }, - low: { label: "Low" }, - close: { label: "Close" }, - pctChange: { label: "% Change", cls: "ciq-extra" }, - pctChangeVsAvg: { label: "% Change vs Average", cls: "ciq-extra" }, - volume: { label: "Volume", cls: "ciq-extra" } -}; - -/** - * Number of decimal places to display for percent formatted columns - * - * @type number - * @memberof TableViewBuilder - * @since 8.1.0 - */ -TableViewBuilder.percentDecimalPlaces = 2; - -/** - * Creates a table view as an HTMLElement overlay over a chart container. The table view displays - * a snapshot of the visible chart data segment. - * - * The overlay contains buttons for copying and saving the table data and for displaying - * additional table columns. - * - * @param {CIQ.ChartEngine} stx A reference to the chart engine that contains the chart for which - * the table view is created. - * @param {object} [config] Configuration parameters. - * @param {function} [config.dateFormatter] Formats table date fields. - * @param {function} [config.valueFormatter] Formats table values. - * @param {function} [config.volumeFormatter] Formats the table volume field. - * @param {function} [config.fileNameFormatter] Formats the name of the file that contains the - * downloaded table data. - * @param {string} [config.minColumnWidth="84px"] The minimum width (including units) of the - * table columns. **Note:** The units can be any CSS unit acceptable by the CSS `calc` - * function. - * @return {HTMLElement} - * - * @memberof TableViewBuilder - * @since 8.1.0 - */ -TableViewBuilder.createTable = function (stx, config = {}) { - if (!stx.chart || !stx.chart.dataSegment) return; - - const { builder } = stx.tableView; - const { - getChartData, - dataToHtml, - dataToCsv, - downloadCsv, - getDateFormatter, - getValueFormatter, - getVolumeFormatter, - getFilenameFormatter, - getSeriesDataNames, - getStudyDataNames, - getChartCover - } = builder; - - const colHeaders = Object.assign({}, this.colHeaders); - - if (!stx.chart.highLowBars) { - delete colHeaders.open; - delete colHeaders.high; - delete colHeaders.low; - } - - if (!stx.tableView.viewAdditionalColumns) { - for (let key in colHeaders) { - if (colHeaders[key].cls) { - delete colHeaders[key]; - } - } - } - - const labels = Object.values(colHeaders).map((item) => item.label); - - const seriesNames = getSeriesDataNames(stx); - seriesNames.forEach((item) => (colHeaders[item] = { label: item })); - - const studyNames = getStudyDataNames(stx); - studyNames.forEach((item) => { - if (!labels.includes(item)) colHeaders[item] = { label: item }; - }); - - const additionalDataFields = seriesNames.concat(studyNames); - - const { - dateFormatter = getDateFormatter(stx), - valueFormatter = getValueFormatter(stx), - percentFormatter = getValueFormatter(stx, this.percentDecimalPlaces), - volumeFormatter = getVolumeFormatter(stx), - fileNameFormatter = getFilenameFormatter(stx), - minColumnWidth = "84px" - } = config; - - const arr = getChartData(stx, { - dateFormatter, - valueFormatter, - percentFormatter, - volumeFormatter, - additionalDataFields - }); - - const cover = getChartCover(stx, config); - const { symbolDisplay, symbol } = stx.chart; - - const toolbar = builder.getCoverToolbar({ - symbol: symbolDisplay || symbol, - viewAdditionalColumns: stx.tableView.viewAdditionalColumns, - copyFn, - downloadFn, - toggleAdditionalColumnsFn: () => { - const { tableView } = stx; - tableView.viewAdditionalColumns = !tableView.viewAdditionalColumns; - tableView.open(); - }, - closeFn: () => stx.tableView.close() - }); - cover.appendChild(toolbar); - const htmlTable = dataToHtml(arr, { colHeaders, minColumnWidth }); - cover.appendChild(htmlTable); - - return cover; - - function copyFn() { - const contentEl = document.createElement("textArea"); - document.body.appendChild(contentEl); - contentEl.textContent = dataToCsv(arr, { colHeaders }); - contentEl.select(); - document.execCommand("copy"); - contentEl.remove(); - stx.dispatch("notification", "copytoclipboard"); - } - - function downloadFn() { - const csvData = dataToCsv(arr, { colHeaders }); - const fileName = fileNameFormatter(csvData); - downloadCsv(csvData, fileName); - } -}; - -/** - * Creates an HTML table containing the chart data and column headers (see - * {@link TableViewBuilder.colHeaders}). - * - * @param {object[]} data The chart data. - * @param {object} params Configuration parameters. - * @param {Object.} params.colHeaders The column - * headers as defined in {@link TableViewBuilder.colHeaders}. - * @param {string} [params.minColumnWidth] The minimum width of the table columns, including units. - * **Note:** The units can be any CSS unit acceptable by the CSS `calc` function. - * @return {HTMLElement} A table containing the chart data and column headers. - * - * @memberof TableViewBuilder - * @since 8.1.0 - */ -TableViewBuilder.dataToHtml = function (data, { colHeaders, minColumnWidth }) { - const keyLength = Object.keys(colHeaders).length; - const colWidth = `calc((100% - ${10 + keyLength * 4}px ) / ${keyLength})`; - const tableHeader = Object.entries(colHeaders).map(([, { label }], index) => { - return `${label.replace("(", " (")}`; - }); - - const tableRows = data.map((row) => { - const htmlRow = Object.keys(colHeaders) - .map((key, index) => { - const value = row[key]; - return index === 0 - ? `${value}` - : `${value}`; - }) - .join(""); - return `${htmlRow}`; - }); - - const tableWrapper = document.createElement("div"); - tableWrapper.classList.add("ciq-data-table-wrapper"); - const minWidth = minColumnWidth - ? `calc(${keyLength} * ${minColumnWidth})` - : ""; - tableWrapper.innerHTML = ` - - ${tableHeader.join("")} - ${tableRows.join("")} -
`; - return tableWrapper; -}; - -/** - * Transforms the chart data into a character-separated values (CSV) file, including column headers. - * - * @param {object[]} data The chart data. - * @param {object} params Configuration parameters. - * @param {Object.} params.colHeaders The column - * headers as defined in {@link TableViewBuilder.colHeaders}. - * @param {string} params.colSeparator="\t" The column separator for the CSV format. - * @return {string} The column headers and chart data as a CSV file. - * - * @memberof TableViewBuilder - * @since 8.1.0 - */ -TableViewBuilder.dataToCsv = function ( - data, - { colHeaders, colSeparator = "\t" } -) { - const tableHeader = Object.entries(colHeaders) - .map(([, { label }]) => `"${label}"`) - .join(colSeparator); - - const tableRows = data.map((row) => { - return Object.keys(colHeaders) - .map((key) => `"${row[key]}"`) - .join(colSeparator); - }); - - return `${tableHeader}\n${tableRows.join("\n")}`; -}; - -/** - * Downloads the table view as a character-separated values (CSV) file. - * - * @param {string} csvString The table view in the form of character-separated data. - * @param {string} filename The name given to the download file. - * - * @memberof TableViewBuilder - * @since 8.1.0 - */ -TableViewBuilder.downloadCsv = function (csvString, filename = "filename") { - const blob = new Blob([csvString], { type: "text/csv;charset=utf-8;" }); - - const a = document.createElement("a"); - a.href = window.URL.createObjectURL(blob, { type: "text/plain" }); - a.download = `${filename}.csv`; - a.style.display = "none"; - document.body.appendChild(a); - a.click(); - document.body.removeChild(a); -}; - -/** - * Extracts OHLC (open, high, low, close) data from the chart. - * - * @param {CIQ.ChartEngine} stx A reference to the chart engine that contains the chart from which - * the data is extracted. - * @param {object} params Configuration parameters. - * @param {function} [params.dateFormatter] Formats date fields. - * @param {function} [params.valueFormatter] Formats OHLC and other values. - * @param {function} [params.percentFormatter] Formats percent fields. - * @param {function} [params.volumeFormatter] Formats the volume field. - * @param {string[]} [params.additionalDataFields] An array of additional data field names for - * comparison series and study data. - * @return {object[]} The formatted chart data. - * - * @memberof TableViewBuilder - * @since 8.1.0 - */ -TableViewBuilder.getChartData = function ( - stx, - { - dateFormatter, - valueFormatter, - percentFormatter, - volumeFormatter, - additionalDataFields - } -) { - const data = stx.chart.dataSegment.filter((item) => item !== null); - const { usePreviousCloseForChange } = stx.tableView; - let out = []; - let length = 0; - const avgPctChange = - data.reduce((acc, { Close, iqPrevClose, Open }) => { - const Base = usePreviousCloseForChange ? iqPrevClose : Open; - if ( - typeof Close === "undefined" || - Number.isNaN(Close) || - typeof Base === "undefined" || - Number.isNaN(Base) - ) { - return acc; - } - length++; - return acc + (Close - Base) / Base; - }, 0) / length; - data.forEach((item, index) => { - const { - DT, - displayDate, - High, - Low, - Open, - Close, - iqPrevClose, - Volume - } = item; - const Base = usePreviousCloseForChange ? iqPrevClose : Open; - const pctChange = (Close - Base) / Base; - const date = - displayDate || - (stx.displayZone - ? CIQ.convertTimeZone(DT, stx.dataZone, stx.displayZone) - : DT); - const obj = { - DT, - date: dateFormatter(date), - open: valueFormatter(Open), - close: valueFormatter(Close), - change: valueFormatter(Close - Base), - pctChange: percentFormatter(pctChange * 100), - pctChangeVsAvg: percentFormatter((pctChange - avgPctChange) * 100), - high: valueFormatter(High), - low: valueFormatter(Low), - volume: volumeFormatter(Volume) - }; - additionalDataFields.forEach((fieldName) => { - let value = item[fieldName]; - if (value == null) { - obj[fieldName] = ""; - return; - } - if (typeof value === "object") { - value = value.Close; - } - obj[fieldName] = valueFormatter(value); - }); - - out.push(obj); - }); - out.sort((a, b) => b.DT - a.DT); - return out; -}; - -/** - * Creates a function that formats table view date fields. - * - * @param {CIQ.ChartEngine} stx A reference to the chart engine that contains the chart for which - * the date fields are formatted. - * @return {function} A date formatter. - * - * @memberof TableViewBuilder - * @since 8.1.0 - */ -TableViewBuilder.getDateFormatter = function (stx) { - return (dt, panel) => { - if (!dt) return ""; - - return CIQ.displayableDate(stx, stx.chart, dt, true); - }; -}; - -/** - * Creates a function that formats table view value fields. - * - * @param {CIQ.ChartEngine} stx A reference to the chart engine that contains the chart for which - * the value fields are formatted. - * @param {number} [decimalPlaces] Number of decimal places to use, overrides any auto-detection of decimal places in data. - * @return {function} A value formatter. - * - * @memberof TableViewBuilder - * @since 8.1.0 - */ -TableViewBuilder.getValueFormatter = function (stx, decimalPlaces) { - const { - chart: { panel, yAxis }, - layout: { chartScale } - } = stx; - let formatValue; - - if (yAxis.originalPriceFormatter && yAxis.originalPriceFormatter.func) { - formatValue = (value) => - yAxis.originalPriceFormatter.func(stx, panel, value, decimalPlaces); - } else if ( - yAxis.priceFormatter && - chartScale != "percent" && - chartScale != "relative" - ) { - formatValue = (value) => - yAxis.priceFormatter(stx, panel, value, decimalPlaces); - } else { - formatValue = (value) => stx.formatYAxisPrice(value, panel, decimalPlaces); - } - - return (value) => formatValue(value).replace(/^-*0\.0*$/, "0"); // display 0.00 as 0 -}; - -/** - * Creates a function that formats the table view volume field. - * - * @param {CIQ.ChartEngine} stx A reference to the chart engine that contains the chart for which - * the volume field is formatted. - * @return {function} A volume field formatter. - * - * @memberof TableViewBuilder - * @since 8.1.0 - */ -TableViewBuilder.getVolumeFormatter = function (stx) { - return (num) => { - if (num == null) return ""; - - if (stx.internationalizer) { - return stx.internationalizer.priceFormatters[0].format(num); - } - - const num_parts = num.toString().split("."); - num_parts[0] = num_parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ","); - return num_parts[0]; - }; -}; - -/** - * Creates a function that creates and formats a file name from the chart symbol and table view - * data. - * - * @param {CIQ.ChartEngine} stx A reference to the chart engine that contains the chart whose - * symbol and data is included in the file name. - * @return {function} A function that creates and formats a file name. - * - * @memberof TableViewBuilder - * @since 8.1.0 - */ -TableViewBuilder.getFilenameFormatter = function (stx) { - return (csvData) => { - const symbol = stx.chart.symbolDisplay || stx.chart.symbol; - let firstDate, lastDate; - if (csvData) { - const rows = csvData.split("\n"); - if (rows.length > 1) { - [, firstDate = ""] = rows[1].match(/^"([^"]*)"/) || []; - [, lastDate = ""] = rows[rows.length - 1].match(/^"([^"]*)"/) || []; - firstDate = firstDate.replace(/:/g, ".").replace(/\//g, "-"); - lastDate = lastDate.replace(/:/g, ".").replace(/\//g, "-"); - } - } - return `${symbol}${firstDate ? ` (${firstDate} _ ${lastDate})` : ""}`; - }; -}; - -/** - * Creates and attaches an HTML container element to the DOM. The element covers the chart and - * contains the table view. - * - * @param {CIQ.ChartEngine} stx A reference to the chart engine that contains the chart over which - * the cover is placed. - * @param {object} params Configuration parameters. - * @param {number} [params.coverUIMaxWidth] The width of the chart (in pixels) below which the - * cover element overlays the entire chart, including user interface elements. - * @param {string} [params.coverContainer] A CSS selector used to obtain the DOM element that - * serves as the parent element of the cover element; for example, ".chartContainer". - * @return {HTMLElement} The cover element. - * - * @memberof TableViewBuilder - * @since 8.1.0 - */ -TableViewBuilder.getChartCover = function ( - stx, - { coverUIMaxWidth, coverContainer } -) { - const parentElement = - (coverContainer && document.querySelector(coverContainer)) || - (stx.uiContext && stx.container.offsetWidth < coverUIMaxWidth - ? stx.uiContext.topNode - : stx.container.parentElement.parentElement); - - const cover = document.createElement("div"); - Object.assign(cover.style, { top: 0, left: 0, right: 0, bottom: 0 }); - - cover.classList.add("ciq-data-table-container"); - parentElement.appendChild(cover); - return cover; -}; - -/** - * Creates a toolbar containing the table title and controls used to copy and download the table - * data and add additional table columns. - * - * @param {object} params Function parameters. - * @param {string} params.symbol An instrument symbol, which is used as the table title in the - * toolbar. Should be the symbol of the chart main series. - * @param {boolean} params.viewAdditionalColumns Toggle that specifies whether the label for the - * additional columns button should indicate that additional columns will be shown or hidden. - * If this parameter is true, the label indicates additional table columns will be shown; if - * false, hidden. - * @param {function} [params.copyFn] Event handler for selection of the copy control. - * @param {function} [params.downloadFn] Event handler for selection of the download control. - * @param {function} [params.toggleAdditionalColumnsFn] Event handler for selection of the - * additional column control. - * @param {function} [params.closeFn] Event handler for selection of the table view close (X) - * control. - * @return {HTMLElement} The toolbar, containing title and controls. - * - * @memberof TableViewBuilder - * @since 8.1.0 - */ -TableViewBuilder.getCoverToolbar = function ({ - symbol, - viewAdditionalColumns, - copyFn, - downloadFn, - toggleAdditionalColumnsFn, - closeFn -}) { - const toolBar = document.createElement("div"); - toolBar.classList.add("ciq-data-table-toolbar"); - toolBar.innerHTML = ` -
- - - - - `; - const titleEl = toolBar.querySelector(".ciq-data-table-title"); - titleEl.textContent = symbol; - - const btnCopy = toolBar.querySelector(".ciq-data-table-copy"); - if (copyFn) { - btnCopy.addEventListener("click", copyFn); - } else { - btnCopy.style.display = "none"; - } - - const btnDownload = toolBar.querySelector(".ciq-data-table-download"); - if (downloadFn) { - btnDownload.addEventListener("click", function () { - btnDownload.blur(); - downloadFn(); - }); - } else { - btnDownload.style.display = "none"; - } - - const btnAdditionalColumns = toolBar.querySelector( - ".ciq-data-table-additionalColumns" - ); - if (toggleAdditionalColumnsFn) { - btnAdditionalColumns.addEventListener("click", toggleAdditionalColumnsFn); - } else { - btnAdditionalColumns.style.display = "none"; - } - - toolBar.close = closeFn; - - return toolBar; -}; - -/** - * Label for the copy button on the table view toolbar. - * - * @type string - * @memberof TableViewBuilder - * @since 8.1.0 - */ -TableViewBuilder.copyLabel = "Copy"; - -/** - * Label for the download button on the table view toolbar. - * - * @type string - * @memberof TableViewBuilder - * @since 8.1.0 - */ -TableViewBuilder.downloadLabel = "Download"; - -/** - * Gets the label of the additional columns button on the table view toolbar. - * - * @param {boolean} viewingAdditionalColumns If this parameter is true, the label should indicate - * additional table columns will be shown; if false, hidden. - * @return {string} The button label. - * - * @memberof TableViewBuilder - * @since 8.1.0 - */ -TableViewBuilder.getAdditionalColumnLabel = function ( - viewingAdditionalColumns -) { - return `${ - viewingAdditionalColumns ? "- " : "+ " - }Additional columns`; -}; - -/** - * Obtains the names of all studies that have data in the chart's visible data segment. - * - * @param {CIQ.ChartEngine} stx A reference to the chart engine that contains the chart studies. - * @return {string[]} The names of all studies that are in the visible portion of the chart. - * - * @memberof TableViewBuilder - * @since 8.1.0 - */ -TableViewBuilder.getStudyDataNames = function (stx) { - return Object.values(stx.layout.studies || {}) - .map(getDataNames) - .reduce((acc, item) => acc.concat(item), []); - - function getDataNames(study) { - return Object.keys(study.outputMap).filter(hasData); - } - - function hasData(name) { - return stx.chart.dataSegment.some((data) => data && data[name]); - } -}; - -/** - * Obtains the symbols of all comparison series that have data in the chart's visible data - * segment. - * - * @param {CIQ.ChartEngine} stx A reference to the chart engine that contains the comparison - * series. - * @return {string[]} The names (symbols) of all comparison series that are in the visible - * portion of the chart. - * - * @memberof TableViewBuilder - * @since 8.1.0 - */ -TableViewBuilder.getSeriesDataNames = function (stx) { - return Object.values(stx.chart.seriesRenderers || {}) - .filter((item) => item.params.name !== "_main_series") - .map((item) => { - return item.seriesParams.map(({ symbol }) => symbol); - }) - .reduce((acc, item) => acc.concat(item), []); -}; - -/** - * CIQ.UI.Context interface placeholder to be augmented in *componentUI.js* with properties. - * - * @tsinterface CIQ.UI~Context - */ - -}; - - -let __js_addons_standard_tooltip_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -if (!CIQ.Marker) { - console.error("tooltip addon requires first activating markers feature."); -} else { - /** - * Add-on that creates a detailed tooltip as the user's mouse hovers over data points on the - * chart. The tooltip contains information such as the open, high, low, and close prices of - * stock quotes. - * - * Tooltip example: - * - * - * **Note:** Prior to version 8.2.0, the tooltip was directly linked to the crosshairs. The - * crosshairs had to be active for the tooltip to be displayed. - * - * Requires *addOns.js* and *markers.js*, or the bundle *standard.js*. - * - * There can be only one `CIQ.Tooltip` per chart. - * - * Color and layout can be customized by overriding the CSS rule-sets defined for the - * `stx-hu-tooltip` and related type selectors in *stx-chart.css*. Do not modify - * *stx-chart.css*; create a separate style sheet file that overrides *stx-chart.css* in the - * CSS cascade. See the example below. - * - * `CIQ.Tooltip` automatically creates its own HTML inside the chart container. Here is an - * example of the structure (there will be one field tag per displayed element): - * ``` - * - * - * - * - * - * - * ``` - * By default, the `stx-hu-tooltip-field` elements are inserted in the following order: - * - DT - * - Open - * - High - * - Low - * - Close - * - Volume - * - series - * - studies - * - * But the default layout can be changed. You can override the order of fields or change the - * labels by manually inserting the HTML that the tooltip would otherwise have created for - * that field. If no override HTML is found for a particular field, the default is used. - * **Note:** This HTML must be placed inside the chart container. - * - * All of the code is provided in *addOns.js* and can be fully customized by copying the - * source code from the library and overriding the functions with your changes. Be sure to - * never modify a library file, as this will hinder upgrades. - * - * For example, concatenating the field name (e.g., "Jaw") with the study name (e.g., - * "Alligator" ) is the default behavior of the tooltip for displaying the value title. Feel - * free to override this behavior by creating your own custom version of the `renderFunction()` - * for the `CIQ.Tooltip`. To do this, copy the entire `CIQ.Tooltip` code (found in *addOns.js*) - * and make the changes to your custom version. Load your custom version instead. Specifically, - * look for the following code in the `renderFunction()` that pushes out the text for each - * study field: - * ``` - * let newFieldName = document.createElement("stx-hu-tooltip-field-name"); - * newFieldName.innerHTML = this.translateIf(fieldName); - * newField.appendChild(newFieldName); - * ``` - * Replace `fieldName` with anything you want to use as the field title and push that instead. - * - * Visual Reference:
- * ![stx-hu-tooltip](stx-hu-tooltip.png "stx-hu-tooltip") - * - * @param {object} tooltipParams The constructor parameters. - * @param {CIQ.ChartEngine} [tooltipParams.stx] The chart object. - * @param {boolean} [tooltipParams.ohl] Set to true to show OHL data (Close is always shown). - * @param {boolean} [tooltipParams.volume] Set to true to show Volume. - * @param {boolean} [tooltipParams.series] Set to true to show value of series. - * @param {boolean} [tooltipParams.studies] Set to true to show value of studies. - * @param {boolean} [tooltipParams.showOverBarOnly] Set to true to show the tooltip only when - * the mouse is over the primary line/bars. - * @param {boolean} [tooltipParams.change] Set to true to show the change in daily value - * when the internal chart periodicity is a daily interval (see - * {@link CIQ.ChartEngine.isDailyInterval}). - * @param {boolean} [tooltipParams.interpolation] Set to true to show the estimated value when - * there is no data between bars. **Note:** A value of `null` is not considered missing - * data. - * @param {boolean} [tooltipParams.useDataZone] Set to true to show the date in the `dataZone` - * time zone; false, to use the `displayZone` time zone (see - * {@link CIQ.ChartEngine#setTimeZone}). - * @param {boolean} [tooltipParams.showBarHighlight=true] Specifies whether the bar (data - * point) the mouse is hovering over is highlighted. Applies to the floating tooltip only - * (the dynamic tooltip points to the bar). If the crosshairs are active, this parameter - * is ignored. - * - * @constructor - * @name CIQ.Tooltip - * @since - * - 09-2016-19 - * - 5.0.0 Now `tooltipParams.showOverBarOnly` is available to show tooltip only when over the - * primary line/bars. - * - 5.1.1 `tooltipParams.change` set to true to show the change in daily value when - * displaying a daily interval. - * - 6.2.5 New `tooltipParams.interpolation` flag to show estimated value for missing series - * data points. - * - 7.0.0 New `tooltipParams.useDataZone` flag to show the date in either the `dataZone` or - * `displayZone` date/time. - * - 8.2.0 Decoupled `CIQ.Tooltip` from the crosshairs and added highlighting of the data - * point (or bar) the mouse is hovering over. The new `tooltipParams.showBarHighlight` - * parameter enables or disables the highlighting. - * - * @example Add a tooltip to a chart: - * // First declare your chart engine. - * const stxx = new CIQ.ChartEngine({ container: document.querySelector(".chartContainer")[0] }); - * - * // Then link the tooltip to that chart. - * // Note how we've enabled OHL, Volume, Series and Studies. - * new CIQ.Tooltip({ stx: stxx, ohl: true, volume: true, series: true, studies: true }); - * - * @example Customize the order, layout, or text in tooltip labels: - * // In this example, we've rearranged the HTML to display the Close field first, then the DT. - * // We are also labeling the DT 'Date/Time' and the Close 'Last'. - * // The rest of the fields are displayed in their default order. - * - * - * - * Last - * - * - * - * Date/Time - * - * - * - * - * @example Customize the CSS for the tooltip (see stx-chart.css): - * stx-hu-tooltip { - * position: absolute; - * left: -50000px; - * z-index: 30; - * white-space: nowrap; - * padding: 6px; - * border: 1px solid gray; - * background-color: rgba(42,81,208,.5); - * color: white; - * } - * - * stx-hu-tooltip-field { - * display:table-row; - * } - * - * stx-hu-tooltip-field-name { - * display:table-cell; - * font-weight:bold; - * padding-right:5px; - * } - * - * stx-hu-tooltip-field-name:after { - * content:':'; - * } - * - * stx-hu-tooltip-field-value { - * display:table-cell; - * text-align:right; - * } - */ - CIQ.Tooltip = - CIQ.Tooltip || - function (tooltipParams) { - if (!CIQ.Marker) { - console.warn( - "CIQ.Tooltip addon requires CIQ.Marker module to be enabled." - ); - return; - } - - this.cssRequired = true; - - const { - stx, - ohl: showOhl, - change: showChange, - volume: showVolume, - series: showSeries, - studies: showStudies, - interpolation: showInterpolation, - showOverBarOnly, - showBarHighlight = true, - useDataZone - } = tooltipParams; - const { container } = stx.chart; - - let node = container.querySelector("stx-hu-tooltip"); - if (!node) { - node = document.createElement("stx-hu-tooltip"); - container.appendChild(node); - } - - let highlightEl = container.querySelector(".stx-hu-tooltip-highlight"); - if (!highlightEl) { - highlightEl = document.createElement("div"); - highlightEl.classList.add("stx-hu-tooltip-highlight"); - container.appendChild(highlightEl); - } - - CIQ.Marker.Tooltip = function (params) { - if (!this.className) this.className = "CIQ.Marker.Tooltip"; - this.highlightEl = highlightEl; - params.label = "tooltip"; - CIQ.Marker.call(this, params); - }; - - CIQ.inheritsFrom(CIQ.Marker.Tooltip, CIQ.Marker, false); - - CIQ.Marker.Tooltip.sameBar = function (bar1, bar2) { - if (!bar1 || !bar2) return false; - if (+bar1.DT != +bar2.DT) return false; - if (bar1.Close != bar2.Close) return false; - if (bar1.Open != bar2.Open) return false; - if (bar1.Volume != bar2.Volume) return false; - return true; - }; - - CIQ.Marker.Tooltip.placementFunction = function (params) { - if (hideIfDisabled()) return; - var offset = 30; - var stx = params.stx; - for (var i = 0; i < params.arr.length; i++) { - var marker = params.arr[i]; - var bar = stx.barFromPixel(stx.cx); - var quote = stx.chart.dataSegment[bar]; - var goodBar; - var overBar = true; - var highPx, lowPx; - - if (quote != "undefined" && quote && quote.DT) { - goodBar = true; - if (quote.High) highPx = stx.pixelFromPrice(quote.High); - if (quote.Low) lowPx = stx.pixelFromPrice(quote.Low); - if (!stx.chart.highLowBars) { - if (quote.Close) { - highPx = stx.pixelFromPrice(quote.Close) - 15; - lowPx = stx.pixelFromPrice(quote.Close) + 15; - } - } - if (showOverBarOnly && !(stx.cy >= highPx && stx.cy <= lowPx)) - overBar = false; - } - - if ( - !( - stx.insideChart && - !stx.openDialog && - !stx.activeDrawing && - !stx.grabbingScreen && - goodBar && - overBar - ) - ) { - highlightEl.style.display = "none"; - marker.node.style.left = "-50000px"; - marker.node.style.right = "auto"; - marker.lastBar = {}; - return; - } - if ( - CIQ.Marker.Tooltip.sameBar( - stx.chart.dataSegment[bar], - marker.lastBar - ) && - bar != stx.chart.dataSegment.length - 1 - ) { - return; - } - - marker.lastBar = stx.chart.dataSegment[bar]; - var cw = marker.lastBar.candleWidth || stx.layout.candleWidth; - if ( - parseInt(getComputedStyle(marker.node).width, 10) + - stx.chart.panel.left + - offset + - cw < - stx.backOutX(CIQ.ChartEngine.crosshairX) - ) { - marker.node.style.left = "auto"; - marker.node.style.right = - Math.round( - container.clientWidth - stx.pixelFromBar(bar) + offset - ) + "px"; - } else { - marker.node.style.left = - Math.round(stx.pixelFromBar(bar) + offset) + "px"; - marker.node.style.right = "auto"; - } - var height = parseInt(getComputedStyle(marker.node).height, 10); - var top = Math.round( - CIQ.ChartEngine.crosshairY - stx.top - height / 2 - ); - if (top + height > stx.height) top = stx.height - height; - if (top < 0) top = 0; - marker.node.style.top = top + "px"; - - if (showBarHighlight && !stx.layout.crosshair) { - const candleWidth = - marker.lastBar.candleWidth || stx.layout.candleWidth; - const left = stx.pixelFromBar(bar) - candleWidth / 2; - let width = candleWidth; - - if (left + width > stx.chart.width) { - // adjust width of last bar so it does not highlight past the edge of the chart into the y axis - width = stx.chart.width - left; - } - - highlightEl.style.display = "block"; - highlightEl.style.left = left + "px"; - highlightEl.style.width = width + "px"; - } else { - highlightEl.style.display = "none"; - } - } - // temporarily disable overXAxis, overYAxis so the crosshairs don't hide if touch device and over Y axis (this can happen - // due to the offset which we apply) - var overXAxis = stx.overXAxis, - overYAxis = stx.overYAxis; - stx.overXAxis = stx.overYAxis = false; - stx.overXAxis = overXAxis; - stx.overYAxis = overYAxis; - }; - - function hideIfDisabled() { - const { headsUp } = stx.layout; - const instantiated = !!stx.huTooltip; - const noLayoutObject = typeof headsUp !== "object"; - const layoutFalse = headsUp === false; // backwards compatibility - const enabled = headsUp && (headsUp === "floating" || headsUp.floating); - - if (instantiated && (!(enabled || noLayoutObject) || layoutFalse)) { - const { huTooltip: tt } = stx; - const { node } = tt || {}; - - if (node) { - node.style.left = "-50000px"; - node.style.right = "auto"; - tt.lastBar = {}; - if (tt.highlightEl) tt.highlightEl.style.display = "none"; - } - - return true; - } - - return false; - } - - function renderFunction() { - // the tooltip has not been initialized with this chart. - if (hideIfDisabled()) return; - - var bar = this.barFromPixel(this.cx), - data = this.chart.dataSegment[bar]; - if (!data) { - this.positionMarkers(); - return; - } - if ( - CIQ.Marker.Tooltip.sameBar(data, this.huTooltip.lastBar) && - bar != this.chart.dataSegment.length - 1 - ) { - return; - } - var node = this.huTooltip.node; - Array.from(node.parentElement.querySelectorAll("[auto]")).forEach( - function (i) { - i.remove(); - } - ); - Array.from( - node.parentElement.querySelectorAll("stx-hu-tooltip-field-value") - ).forEach(function (i) { - i.innerHTML = ""; - }); - - var panel = this.chart.panel; - var yAxis = panel.yAxis; - var dupMap = {}; - var fields = []; - fields.push({ - member: "DT", - display: "DT", - panel: panel, - yAxis: yAxis - }); - fields.push({ - member: "Close", - display: "Close", - panel: panel, - yAxis: yAxis - }); - dupMap.DT = dupMap.Close = 1; - if ( - showChange && - CIQ.ChartEngine.isDailyInterval(this.layout.interval) - ) { - fields.push({ - member: "Change", - display: "Change", - panel: panel, - yAxis: yAxis - }); - } - if (showOhl) { - fields.push({ - member: "Open", - display: "Open", - panel: panel, - yAxis: yAxis - }); - fields.push({ - member: "High", - display: "High", - panel: panel, - yAxis: yAxis - }); - fields.push({ - member: "Low", - display: "Low", - panel: panel, - yAxis: yAxis - }); - dupMap.Open = dupMap.High = dupMap.Low = 1; - } - if (showVolume) { - fields.push({ - member: "Volume", - display: "Volume", - panel: null, - yAxis: null - }); // null yAxis use raw value - dupMap.Volume = 1; - } - if (showSeries) { - var renderers = this.chart.seriesRenderers; - for (var renderer in renderers) { - var rendererToDisplay = renderers[renderer]; - if (rendererToDisplay === this.mainSeriesRenderer) continue; - panel = this.panels[rendererToDisplay.params.panel]; - yAxis = rendererToDisplay.params.yAxis; - if (!yAxis && rendererToDisplay.params.shareYAxis) - yAxis = panel.yAxis; - for (var id = 0; id < rendererToDisplay.seriesParams.length; id++) { - var seriesParams = rendererToDisplay.seriesParams[id]; - // if a series has a symbol and a field then it maybe a object chain - var sKey = seriesParams.symbol; - var subField = seriesParams.field; - if (!sKey) sKey = subField; - else if (subField && sKey != subField) - sKey = CIQ.createObjectChainNames(sKey, subField)[0]; - var display = - seriesParams.display || - seriesParams.symbol || - seriesParams.field; - if (sKey && !dupMap[display]) { - fields.push({ - member: sKey, - display: display, - panel: panel, - yAxis: yAxis, - isSeries: true - }); - dupMap[display] = 1; - } - } - } - } - if (showStudies) { - for (var study in this.layout.studies) { - var sd = this.layout.studies[study]; - panel = this.panels[sd.panel]; - yAxis = panel && sd.getYAxis(this); - for (var output in this.layout.studies[study].outputMap) { - if (output && !dupMap[output]) { - fields.push({ - member: output, - display: output, - panel: panel, - yAxis: yAxis - }); - dupMap[output] = 1; - } - } - if (!dupMap[study + "_hist"]) { - fields.push({ - member: study + "_hist", - display: study + "_hist", - panel: panel, - yAxis: yAxis - }); - fields.push({ - member: study + "_hist1", - display: study + "_hist1", - panel: panel, - yAxis: yAxis - }); - fields.push({ - member: study + "_hist2", - display: study + "_hist2", - panel: panel, - yAxis: yAxis - }); - dupMap[study + "_hist"] = 1; - } - } - } - for (var f = 0; f < fields.length; f++) { - var obj = fields[f]; - var name = obj.member; - var displayName = obj.display; - var isRecordDate = name == "DT"; - if ( - isRecordDate && - !useDataZone && - !CIQ.ChartEngine.isDailyInterval(stx.layout.interval) - ) - name = "displayDate"; // display date is timezone adjusted - panel = obj.panel; - yAxis = obj.yAxis; - var labelDecimalPlaces = null; - if (yAxis) { - if (!panel || panel !== panel.chart.panel) { - // If a study panel, use yAxis settings to determine decimal places - if (yAxis.decimalPlaces || yAxis.decimalPlaces === 0) - labelDecimalPlaces = yAxis.decimalPlaces; - else if (yAxis.maxDecimalPlaces || yAxis.maxDecimalPlaces === 0) - labelDecimalPlaces = yAxis.maxDecimalPlaces; - } else { - // If a chart panel, then always display at least the number of decimal places as calculated by masterData (panel.chart.decimalPlaces) - // but if we are zoomed to high granularity then expand all the way out to the y-axis significant digits (panel.yAxis.printDecimalPlaces) - labelDecimalPlaces = Math.max( - yAxis.printDecimalPlaces, - panel.chart.decimalPlaces - ); - // ... and never display more decimal places than the symbol is supposed to be quoting at - if (yAxis.maxDecimalPlaces || yAxis.maxDecimalPlaces === 0) - labelDecimalPlaces = Math.min( - labelDecimalPlaces, - yAxis.maxDecimalPlaces - ); - } - } - var dsField = null; - // account for object chains - var tuple = CIQ.existsInObjectChain(data, name); - if (tuple) dsField = tuple.obj[tuple.member]; - else if (name == "Change") dsField = data.Close - data.iqPrevClose; - - var fieldName = displayName.replace(/^(Result )(.*)/, "$2"); - - if ( - showInterpolation && - fields[f].isSeries && - (dsField === null || typeof dsField == "undefined") - ) { - // do this only for additional series and not the main series - var seriesPrice = this.valueFromInterpolation( - bar, - fieldName, - "Close", - panel, - yAxis - ); - if (seriesPrice === null) break; - dsField = seriesPrice; - } - if ( - (dsField || dsField === 0) && - (isRecordDate || - typeof dsField !== "object" || - dsField.Close || - dsField.Close === 0) - ) { - var fieldValue = ""; - if (dsField.Close || dsField.Close === 0) dsField = dsField.Close; - if (dsField.constructor == Number) { - if (!yAxis) { - // raw value - fieldValue = dsField; - } else if ( - yAxis.originalPriceFormatter && - yAxis.originalPriceFormatter.func - ) { - // in comparison mode with custom formatter - fieldValue = yAxis.originalPriceFormatter.func( - this, - panel, - dsField, - labelDecimalPlaces - ); - } else if ( - yAxis.priceFormatter && - yAxis.priceFormatter != CIQ.Comparison.priceFormat - ) { - // using custom formatter - fieldValue = yAxis.priceFormatter( - this, - panel, - dsField, - labelDecimalPlaces - ); - } else { - fieldValue = this.formatYAxisPrice( - dsField, - panel, - labelDecimalPlaces, - yAxis - ); - } - } else if (dsField.constructor == Date) { - if ( - isRecordDate && - this.controls.floatDate && - this.controls.floatDate.innerHTML - ) { - if (this.chart.xAxis.noDraw) fieldValue = "N/A"; - else - fieldValue = CIQ.displayableDate(this, panel.chart, dsField); - } else { - fieldValue = CIQ.yyyymmdd(dsField); - if (!CIQ.ChartEngine.isDailyInterval(this.layout.interval)) { - fieldValue += " " + dsField.toTimeString().substr(0, 8); - } - } - } else { - fieldValue = dsField; - } - var dedicatedField = node.querySelector( - 'stx-hu-tooltip-field[field="' + fieldName + '"]' - ); - - if (dedicatedField) { - dedicatedField.querySelector( - "stx-hu-tooltip-field-value" - ).innerHTML = fieldValue; - var fieldNameField = dedicatedField.querySelector( - "stx-hu-tooltip-field-name" - ); - if (fieldNameField.innerHTML === "") - fieldNameField.innerHTML = this.translateIf(fieldName); - } else { - var newField = document.createElement("stx-hu-tooltip-field"); - newField.setAttribute("auto", true); - var newFieldName = document.createElement( - "stx-hu-tooltip-field-name" - ); - newFieldName.innerHTML = this.translateIf(fieldName); - newField.appendChild(newFieldName); - var newFieldValue = document.createElement( - "stx-hu-tooltip-field-value" - ); - newFieldValue.innerHTML = fieldValue; - newField.appendChild(newFieldValue); - node.appendChild(newField); - } - } else { - var naField = node.querySelector( - 'stx-hu-tooltip-field[field="' + fieldName + '"]' - ); - if (naField) { - var naFieldNameField = naField.querySelector( - "stx-hu-tooltip-field-name" - ); - if (naFieldNameField.innerHTML !== "") - naField.querySelector("stx-hu-tooltip-field-value").innerHTML = - "n/a"; - } - } - } - this.huTooltip.render(); - } - - stx.append("deleteHighlighted", function () { - this.huTooltip.lastBar = {}; - this.headsUpHR(); - }); - stx.append("headsUpHR", renderFunction); - stx.append("createDataSegment", renderFunction); - stx.huTooltip = new CIQ.Marker.Tooltip({ - stx: stx, - xPositioner: "bar", - chartContainer: true, - node: node - }); - }; -} - -}; - - -let __js_addons_advanced_animation_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -/** - * Add-On that animates the chart. - * - * Requires *addOns.js*. - * - * The chart is animated in three ways: - * 1. The current price pulsates - * 2. The current price appears to move smoothly from the previous price - * 3. The chart's y-axis smoothly expands/contracts when a new high or low is reached - * - * The following chart types are supported: line, mountain, baseline_delta. - * - * Chart aggregations such as Kagi, Renko, Range Bars, etc. are not supported. - * - * **Animation displays more gracefully when updates are sent into the chart one at a time using {@link CIQ.ChartEngine#updateChartData} - * instead of in batches using a [QuoteFeed]{@link CIQ.ChartEngine#attachQuoteFeed}. Sending data in batches will produce a ‘jumping’ effect.** - * - * By default, there will be a flashing beacon created using a canvas circle. If instead you want to use a custom animation beacon, you will be able to extend the functionality yourself as follows: - * - In js/addOns.js, at the bottom of the CIQ.Animation function, there is an stx.append("draw") function. - * - Make a copy of this function so you can override the behavior. - * - In there you will see it determine var x and y, which are the coordinates for the center of the beacon. - * - At the bottom of this append function, we draw the beacon by using the Canvas arc() function to draw a circle and then fill() to make the circle solid. - * - You can replace the canvas circle with an image using [CanvasRenderingContext2D.drawImage()](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D#Drawing_images) . - * - Example: - * - * ``` - * var image = document.getElementById('beacon'); // include a hidden image on your HTML - * context.drawImage(image, x-10, y-10, 20, 20); // add the image on the canvas. Offset the x and y values by the radius of the beacon. - * ``` - * - * Animation Example - * - * You can disable animation after each different [chart type is activated]{@link CIQ.ChartEngine#setChartType} by calling: - * ``` - * stxx.mainSeriesRenderer.supportsAnimation=false; - * ``` - * Keep in mind that changing to a different chart type, may once again enable animation. You can override this by [adding an event listener]{@link CIQ.ChartEngine#addEventListener} on [layout changes]{@link CIQ.ChartEngine~layoutEventListener}. - * - * @param {object} config The constructor parameters - * @param {CIQ.ChartEngine} config.stx The chart object - * @param {object} [config.animationParameters] Configuration parameters - * @param {boolean} [config.animationParameters.stayPut=false] Set to true for last tick to stay in position it was scrolled and have rest of the chart move backwards as new ticks are added instead of having new ticks advance forward and leave the rest of the chart in place. - * @param {number} [config.animationParameters.ticksFromEdgeOfScreen=5] Number of ticks from the right edge the chart should stop moving forward so the last tick never goes off screen (only applicable if stayPut=false) - * @param {number} [config.animationParameters.granularity=1000000] Set to a value that will give enough granularity for the animation. The larger the number the smaller the price jump between frames, which is good for charts that need a very slow smooth animation either because the price jumps between ticks are very small, or because the animation was set up to run over a large number of frames when instantiating the CIQ.EaseMachine. - * @param {number} [config.animationParameters.tension=null] Splining tension for smooth curves around data points (range 0-1). - * @param {CIQ.EaseMachine} config.easeMachine Override the default easeMachine. Default is `new CIQ.EaseMachine(Math.easeOutCubic, 1000);` - * @constructor - * @name CIQ.Animation - * @since - * - 3.0.0 Now part of *addOns.js*. Previously provided as a standalone *animation.js* file. - * - 4.0.0 Beacon only flashes for line charts. On candles or bars, it is suppressed as it produces an unnatural effect. - * - 7.0.2 Now takes one configuration object as its constructor. Must have a reference to a chart engine. - * @example - * new CIQ.Animation({stx: stxx, animationParameters: {tension:0.3}}); //Default animation with splining tension of 0.3 - * - */ -CIQ.Animation = - CIQ.Animation || - function (config) { - if (!config) throw new Error("Invalid constructor arguments."); - var stx, animationParameters, easeMachine; - if (config instanceof CIQ.ChartEngine) { - // legacy constructor - stx = arguments[0]; - animationParameters = arguments[1]; - easeMachine = arguments[2]; - } else { - stx = config.stx; - animationParameters = config.animationParameters; - easeMachine = config.easeMachine; - } - if (!stx) - return console.warn( - "No CIQ.ChartEngine provided. Cannot properly create CIQ.Animation instance" - ); - var params = { - stayPut: false, - ticksFromEdgeOfScreen: 5, - granularity: 1000000 - }; - animationParameters = CIQ.extend(params, animationParameters); - - if (params.tension) stx.chart.tension = animationParameters.tension; - stx.tickAnimator = - easeMachine || new CIQ.EaseMachine(Math.easeOutCubic, 1000); - var scrollAnimator = new CIQ.EaseMachine(Math.easeInOutCubic, 1000); - - var flashingColors = ["#0298d3", "#19bcfc", "#5dcffc", "#9ee3ff"]; - var flashingColorIndex = 0; - var flashingColorThrottle = 20; - var flashingColorThrottleCounter = 0; - - var filterSession = false; - var nextBoundary = null; - - function initMarketSessionFlags() { - filterSession = false; - nextBoundary = null; - } - - stx.addEventListener(["symbolChange", "layout"], function (obj) { - initMarketSessionFlags(); - }); - - stx.prepend("updateCurrentMarketData", function ( - data, - chart, - symbol, - params - ) { - if (!chart) chart = this.chart; - if ( - params && - params.fromTrade && - (chart.closePendingAnimation || chart.closePendingAnimation === 0) - ) { - params.finalClose = chart.closePendingAnimation; - } - }); - - stx.prepend("updateChartData", function (appendQuotes, chart, params) { - var self = this; - if (!chart) { - chart = self.chart; - } - if ( - !chart || - !chart.defaultChartStyleConfig || - chart.defaultChartStyleConfig == "none" - ) - return; - - if (params !== undefined) { - if (params.animationEntry || params.secondarySeries) return; - } - - if (!chart.dataSegment) return; - - function completeLastBar(record) { - if (!chart.masterData) return; - for (var md = chart.masterData.length - 1; md >= 0; md--) { - var bar = chart.masterData[md]; - if (bar.Close || bar.Close === 0) { - bar.Close = record.Close; - if (record.LastSize) bar.LastSize = record.LastSize; - if (record.LastTime) bar.LastTime = record.LastTime; - self.updateCurrentMarketData({ - Close: bar.Close, - DT: bar.DT, - LastSize: bar.LastSize, - LastTime: bar.LastTime - }); - self.createDataSet(null, null, { appending: true }); - return; - } - } - } - function unanimateScroll() { - if (chart.animatingHorizontalScroll) { - chart.animatingHorizontalScroll = false; - self.micropixels = self.nextMicroPixels = self.previousMicroPixels; // <-- Reset self.nextMicroPixels here - chart.lastTickOffset = 0; - } - if (chart.closePendingAnimation !== null) { - var close = chart.closePendingAnimation; - chart.closePendingAnimation = null; - completeLastBar({ Close: close }); - } - } - var tickAnimator = self.tickAnimator; - // These chart types are the only types supported by animation - var supportedChartType = - this.mainSeriesRenderer && this.mainSeriesRenderer.supportsAnimation; - if (supportedChartType) { - if (!tickAnimator) { - console.warn( - "Animation plug-in can not run because the tickAnimator has not been declared. See instructions in animation.js" - ); - return; - } - - // If symbol changes then reset all of our variables - if (this.prevSymbol != chart.symbol) { - this.prevQuote = 0; - chart.closePendingAnimation = null; - this.prevSymbol = chart.symbol; - } - unanimateScroll(); - tickAnimator.stop(); - if (appendQuotes.length > 2) { - return; - } - } - var newParams = CIQ.clone(params); - if (!newParams) newParams = {}; - newParams.animationEntry = true; - newParams.bypassGovernor = true; - newParams.noCreateDataSet = false; - newParams.appending = true; - //newParams.allowReplaceOHL = true; - newParams.firstLoop = true; - var symbol = this.chart.symbol; - var period = this.layout.periodicity; - var interval = this.layout.interval; - var timeUnit = this.layout.timeUnit; - - function cb(quote, prevQuote, chartJustAdvanced) { - return function (newData) { - var newClose = newData.Close; - if ( - !chart.dataSet.length || - symbol != chart.symbol || - period != self.layout.periodicity || - interval != self.layout.interval || - timeUnit != self.layout.timeUnit - ) { - //console.log ("---- STOP animating: Old",symbol,' New : ',chart.symbol, Date()) - tickAnimator.stop(); - unanimateScroll(); - return; // changed symbols mid animation - } - var q = CIQ.clone(quote); - q.Adj_Close = null; // Don't use this, it will mess up our calculated close - q.Close = - Math.round(newClose * animationParameters.granularity) / - animationParameters.granularity; //<<------ IMPORTANT! Use 1000000 for small price increments, otherwise animation will be in increments of .0001 - //q.Close = Math.round(newClose*chart.roundit)/chart.roundit; // to ensure decimal points don't go out too far for interim values - if (chartJustAdvanced) { - if (!q.Open && q.Open !== 0) q.Open = q.Close; - if (!q.High && q.High !== 0) q.High = Math.max(q.Open, q.Close); - if (!q.Low && q.Low !== 0) q.Low = Math.min(q.Open, q.Close); - } else { - if (quote.Close > prevQuote.High) q.High = q.Close; - if (quote.Close < prevQuote.Low) q.Low = q.Close; - } - if (chart.animatingHorizontalScroll) { - self.micropixels = newData.micropixels; - chart.lastTickOffset = newData.lineOffset; - } - newParams.updateDataSegmentInPlace = !tickAnimator.hasCompleted; - //console.log("animating: Old",symbol,' New : ',chart.symbol); - var updateQuotes = [q]; - // Don't include previous quote if tick mode. It will append, duplicating the quote - if (chartJustAdvanced && self.layout.interval !== "tick") - updateQuotes.unshift(prevQuote); - self.updateChartData(updateQuotes, chart, newParams); - newParams.firstLoop = false; - if (tickAnimator.hasCompleted) { - //console.log( 'animator has completed') ; - //self.pendingScrollAdvance=false; - //var possibleYAxisChange = chart.animatingHorizontalScroll; - unanimateScroll(); - /*if (possibleYAxisChange) { // <---- Logic no longer necessary - // After completion, one more draw for good measure in case our - // displayed high and low have changed, which would trigger - // the y-axis animation - setTimeout(function(){ - self.draw(); - }, 0); - }*/ - } - }; - } - if (supportedChartType) { - var quote = appendQuotes[appendQuotes.length - 1]; - this.prevQuote = this.currentQuote(); // <---- prevQuote logic has been changed to prevent forward/back jitter when more than one tick comes in between animations - var chartJustAdvanced = false; // When advancing, we need special logic to deal with the open - var dontScroll = false; - if (period == 1 && appendQuotes.length == 2) { - // Don't do this if consolidating - this.prevQuote = appendQuotes[0]; - var dataSetLength = chart.dataSet.length; - completeLastBar(this.prevQuote); - if (dataSetLength == chart.dataSet.length) dontScroll = true; - } - if (!quote || !quote.Close || !this.prevQuote || !this.prevQuote.Close) - return false; - - if (this.extendedHours && chart.market.market_def) { - // Filter out unwanted sessions - var dtToFilter = quote.DT; - if (CIQ.ChartEngine.isDailyInterval(interval)) { - filterSession = !chart.market.isMarketDate(dtToFilter); - } else { - if (!nextBoundary || nextBoundary <= dtToFilter) { - var session = chart.market.getSession(dtToFilter); - filterSession = - session !== "" && - (!this.layout.marketSessions || - !this.layout.marketSessions[session]); - nextBoundary = chart.market[ - filterSession ? "getNextOpen" : "getNextClose" - ](dtToFilter); - } - } - if (filterSession) { - this.draw(); - return false; - } - } - - var barSpan = period; - if (interval == "second" || timeUnit == "second") barSpan *= 1000; - else if (interval == "minute" || timeUnit == "minute") barSpan *= 60000; - if (!isNaN(interval)) barSpan *= interval; - if (interval == "day" || timeUnit == "day") - chartJustAdvanced = quote.DT.getDate() != this.prevQuote.DT.getDate(); - else if (interval == "week" || timeUnit == "week") - chartJustAdvanced = - quote.DT.getDate() >= this.prevQuote.DT.getDate() + 7; - else if (interval == "month" || timeUnit == "month") - chartJustAdvanced = - quote.DT.getMonth() != this.prevQuote.DT.getMonth(); - else - chartJustAdvanced = - quote.DT.getTime() >= this.prevQuote.DT.getTime() + barSpan; - - var linearChart = - !this.mainSeriesRenderer || !this.mainSeriesRenderer.standaloneBars; - - var beginningOffset = 0; - if (chartJustAdvanced) { - if (this.animations.zoom.hasCompleted) { - var candleWidth = this.layout.candleWidth; - if (chart.scroll <= chart.maxTicks) { - while (this.micropixels > 0) { - // If micropixels is larger than a candle then scroll back further - chart.scroll++; - this.micropixels -= candleWidth; - } - } - if (chart.scroll <= chart.maxTicks) { - this.previousMicroPixels = this.micropixels; - this.nextMicroPixels = this.micropixels + candleWidth; - beginningOffset = candleWidth * -1; - if ( - chart.dataSegment.length < - chart.maxTicks - animationParameters.ticksFromEdgeOfScreen && - !animationParameters.stayPut - ) { - this.nextMicroPixels = this.micropixels; - chart.scroll++; - } - chart.animatingHorizontalScroll = linearChart; // When the chart advances we also animate the horizontal scroll by incrementing micropixels - chart.previousDataSetLength = chart.dataSet.length; - } else { - if (!dontScroll) chart.scroll++; - } - } else { - return false; - } - } - chart.closePendingAnimation = quote.Close; - var start = - chartJustAdvanced && !linearChart ? quote.Open : this.prevQuote.Close; - tickAnimator.run( - cb(quote, CIQ.clone(this.prevQuote), chartJustAdvanced), - { - Close: start, - micropixels: this.nextMicroPixels, - lineOffset: beginningOffset - }, - { Close: quote.Close, micropixels: this.micropixels, lineOffset: 0 } - ); - return true; // bypass default behavior in favor of animation - } - }); - - stx.prepend("renderYAxis", function (chart) { - if (this.grabbingScreen || !this.isHome()) return; - // When display style doesn't support animation - var supportedChartType = - this.mainSeriesRenderer && this.mainSeriesRenderer.supportsAnimation; - if (!supportedChartType) return; - - var panel = chart.panel; - var yAxis = panel.yAxis; - if (CIQ.Comparison && yAxis.priceFormatter == CIQ.Comparison.priceFormat) - return; // too difficult to animate y-axis change when it changes on every tick due to percentage axis on comparison - - function closure(self) { - return function (values) { - chart.animatedLow = values.low; - chart.animatedHigh = values.high; - self.draw(); - }; - } - // initialize prev values - if (!chart.prevLowValue && chart.prevLowValue !== 0) { - chart.prevLowValue = chart.animatedLow = chart.lowValue; - } - if (!chart.prevHighValue && chart.prevHighValue !== 0) { - chart.prevHighValue = chart.animatedHigh = chart.highValue; - } - - // check for a change, if so we will spin off an animation - if (!scrollAnimator.running) chart.animatingVerticalScroll = false; - if ( - chart.prevLowValue >= chart.lowValue && - chart.prevHighValue <= chart.highValue - ) { - if (chart.animatingVerticalScroll) { - yAxis.highValue = chart.animatedHigh; - yAxis.lowValue = chart.animatedLow; - } - return; - } - if (scrollAnimator.running) scrollAnimator.stop(); - if (!chart.lowValue && !chart.highValue) return; // chart just reset, don't animate yet - var prevLow = chart.prevLowValue, - prevHigh = chart.prevHighValue; - chart.prevLowValue = chart.lowValue; - chart.prevHighValue = chart.highValue; - chart.animatingVerticalScroll = true; - scrollAnimator.run( - closure(this), - { low: prevLow, high: prevHigh }, - { low: chart.lowValue, high: chart.highValue } - ); - - yAxis.lowValue = chart.animatedLow; - yAxis.highValue = chart.animatedHigh; - }); - - /*stx.prepend("draw", function() { - if(this.chart.animatingVerticalScroll) { - this.renderYAxis(this.chart); - return true; - } - });*/ - - stx.append("draw", function () { - if (filterSession) return; - if ( - this.chart.dataSet && - this.chart.dataSet.length && - this.mainSeriesRenderer && - this.mainSeriesRenderer.supportsAnimation - ) { - if (flashingColorThrottleCounter % flashingColorThrottle === 0) { - flashingColorIndex++; - flashingColorThrottleCounter = 0; - } - flashingColorThrottleCounter++; - - var context = this.chart.context; - var panel = this.chart.panel; - var currentQuote = this.currentQuote(); - if (!currentQuote) return; - var price = currentQuote.Close; - var x = this.pixelFromTick(currentQuote.tick, this.chart); - if (this.chart.lastTickOffset) x = x + this.chart.lastTickOffset; - var y = this.pixelFromPrice(price, panel); - if ( - this.chart.yAxis.left > x && - this.chart.yAxis.top <= y && - this.chart.yAxis.bottom >= y - ) { - if (flashingColorIndex >= flashingColors.length) - flashingColorIndex = 0; - context.beginPath(); - context.moveTo(x, y); - context.arc( - x, - y, - 2 + flashingColorIndex * 1.07, - 0, - Math.PI * 2, - false - ); - context.fillStyle = flashingColors[flashingColorIndex]; - context.fill(); - } - } - }); - }; - -/** - * CIQ.EaseMachine interface placeholder to be augmented in *standard.js* with properties. - * - * @tsinterface CIQ~EaseMachine - */ - -}; - - -let __js_addons_advanced_continuousZoom_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -/** - * Add-on that responds to the chart zoom action, changing periodicities as the number of ticks and/or candle width - * hits a set boundary. - * - * Although this feature is available for all chart styles, it shows best on continuous renderings - * such as lines and mountains vs. candles and bars. This is because some users may find the - * changes in candle width that take place as the same range is displayed in a different - * periodicity, inappropriate. The effect can be mitigated by increasing the number of boundaries - * so periodicities change more often, preventing large candle width changes, and by using the - * periodicity roll up feature instead of fetching new data from a quote feed. See examples. - * - * See {@link CIQ.ChartEngine#setPeriodicity} and {@link CIQ.ChartEngine#createDataSet} - * - * Requires *addOns.js*. - * - * The feature will not work without supplying at least one element within the periodicities array - * and at least one property within the boundaries object. - * - * @param {object} params Configuration parameters. - * @param {CIQ.ChartEngine} params.stx The chart object. - * @param {array} params.periodicities Set this array with eligible periodicities in any order. - * These will be the periodicities which will be used by the continuous zooming once a - * boundary is hit. The periodicities are objects with `period`, `interval`, and optional - * `timeUnit` properties (see {@link CIQ.ChartEngine#setPeriodicity}). - * @param {object} params.boundaries Optional boundary cases to trigger the periodicity change. - * Hitting a maximum boundary switches to the next larger periodicity; hitting a minimum - * boundary switches to the next smaller periodicity. - * @param {number} [params.boundaries.maxCandleWidth] Largest size of candle in pixels to display - * before switching periodicity. - * @param {number} [params.boundaries.minCandleWidth] Smallest size of candle in pixels to display - * before switching periodicity. - * @param {number} [params.boundaries.maxTicks] Most number of ticks to display before switching - * periodicity. - * @param {number} [params.boundaries.minTicks] Least number of ticks to display before switching - * periodicity. - * - * @constructor - * @name CIQ.ContinuousZoom - * @since 7.0.0 - * - * @example - * new CIQ.ContinuousZoom({ - * stx: stxx, - * periodicities: [ - * { period:1, interval:"month" }, - * { period:1, interval:"day" }, - * { period:2, interval:30 }, - * { period:1, interval:5 }, - * { period:15, interval:1, timeUnit:"second" }, - * { period:1, interval:1, timeUnit:"second" } - * ], - * boundaries: { - * maxCandleWidth: 100, - * minCandleWidth: 3, - * maxTicks: 500, - * minTicks: 10 - * } - * }); - * - * @example - * // Smother periodicity change by rolling daily into weekly and monthly. - * // Also try reusing the same interval data and have the chart roll it instead of fetching new data. - * stxx.dontRoll = false; - * new CIQ.ContinuousZoom({ - * stx: stxx, - * periodicities: [ - * // Daily interval data - * {period:1, interval:"month"}, - * {period:2, interval:"week"}, - * {period:1, interval:"week"}, - * {period:3, interval:"day"}, - * {period:1, interval:"day"}, - * // 30 minute interval data - * {period:16, interval:30}, - * {period:8, interval:30}, - * {period:4, interval:30}, - * {period:2, interval:30}, - * // one minute interval data - * {period:30, interval:1}, - * {period:15, interval:1}, - * {period:10, interval:1}, - * {period:5, interval:1}, - * {period:2, interval:1}, - * {period:1, interval:1}, - * // One second interval data - * {period:30,interval:1, timeUnit:"second"}, - * {period:15,interval:1, timeUnit:"second"}, - * {period:5, interval:1, timeUnit:"second"}, - * {period:2, interval:1, timeUnit:"second"}, - * {period:1, interval:1, timeUnit:"second"}, - * ], - * boundaries: { - * maxCandleWidth: 15, - * minCandleWidth: 3 - * } - * }); - */ -CIQ.ContinuousZoom = - CIQ.ContinuousZoom || - function (params) { - this.cssRequired = true; - this.update(params); - this.stx.continuousZoom = this; - - //Attaches SmartZoom button to HTML DOM inside .chartSize element - this.addSmartZoomButton = function () { - // Don't add a button if one already exists - var smartZoomButton = - this.stx.registerChartControl && - this.stx.registerChartControl( - "stx-smart-zoom", - "SmartZoom (Alt + 0)", - (function (self) { - return function (e) { - self.smartZoomToggle(e); - e.stopPropagation(); - }; - })(this) - ); - if (smartZoomButton) { - // Listen for a layout changed event and refresh the toggle state of the button - this.stx.addEventListener("layout", function (event) { - if (event.stx.layout.smartzoom === true) { - smartZoomButton.classList.add("active"); - } else { - smartZoomButton.classList.remove("active"); - } - }); - // Piggyback off of symbolImport event to detect smartzoom set to false from layout import - this.stx.addEventListener("symbolImport", function (event) { - if (event.stx.layout.smartzoom === false) - smartZoomButton.classList.remove("active"); - }); - } - }; - - //Click event handler for the Smart Zoom button. Sets smartzoom property of layout to its inverse - this.smartZoomToggle = function (e) { - this.smartZoomEnable(!this.stx.layout.smartzoom); - }; - - //Sets smartzoom property of layout and notifies attached ChartEngine of change - this.smartZoomEnable = function (state) { - this.stx.layout.smartzoom = state; - this.stx.changeOccurred("layout"); - }; - - // Add the SmartZoom button to chartControls - this.addSmartZoomButton(); - // Enable SmartZoom by default - this.smartZoomEnable(true); - }; - -/** - * Updates continuous zoom parameters - * @param {object} params Configuration parameters. See constructor for details - * @memberof CIQ.ContinuousZoom - * @since 7.0.0 - * @private - */ -CIQ.ContinuousZoom.prototype.update = function (params) { - if (!params) params = {}; - this.stx = params.stx; - this.periodicities = params.periodicities; - this.boundaries = params.boundaries; -}; - -/** - * Potentially performs a continuous zoom after a zoom event - * @param {boolean} [zoomOut] True for a zoomOut operation, otherwise zoomIn - * @memberof CIQ.ContinuousZoom - * @since 7.0.0 - * @private - */ -CIQ.ContinuousZoom.prototype.execute = function (zoomOut) { - // assign a weight to a periodicity setting, the higher the length, the higher the weight - function valuate(periodicity) { - var period = periodicity.period || periodicity.periodicity, - interval = periodicity.interval, - timeUnit = periodicity.timeUnit || "minute"; - if (isNaN(interval)) { - timeUnit = interval; - interval = 1; - } - switch (timeUnit) { - case "month": - interval *= 4.35; /* falls through */ - case "week": - interval *= 7; /* falls through */ - case "day": - interval *= 1440; /* falls through */ - case "minute": - interval *= 60; /* falls through */ - case "second": - break; - case "millisecond": - interval /= 1000; - break; - default: - return null; - } - return period * interval; - } - if (!this.stx || !this.stx.layout.smartzoom) return; - var periodicities = this.periodicities, - boundaries = this.boundaries, - stx = this.stx, - layout = stx.layout, - chart = stx.chart; - if (!periodicities || !boundaries) return; - - if ( - (!zoomOut && - boundaries.maxCandleWidth && - layout.candleWidth > boundaries.maxCandleWidth) || - (zoomOut && - boundaries.minCandleWidth && - layout.candleWidth < boundaries.minCandleWidth) || - (!zoomOut && boundaries.minTicks && chart.maxTicks < boundaries.minTicks) || - (zoomOut && boundaries.maxTicks && chart.maxTicks > boundaries.maxTicks) - ) { - var next = { value: zoomOut ? Number.MAX_VALUE : 0 }; - var myValue = valuate(layout); - for (var p = 0; p < periodicities.length; p++) { - var value = valuate(periodicities[p]); - if ( - (value > myValue && value < next.value && zoomOut) || - (value < myValue && value > next.value && !zoomOut) - ) { - next = { value: value, periodicity: periodicities[p] }; - } - } - var newPeriodicity = next.periodicity; - if (newPeriodicity) { - stx.setRange({ - dtLeft: chart.xaxis[0].DT, - dtRight: chart.xaxis[chart.xaxis.length - 1].DT, - dontSaveRangeToLayout: true, - periodicity: newPeriodicity - }); - } - } -}; - -}; - - -let __js_addons_advanced_outliers_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -/** - * Creates the outliers add-on which scales the y-axis to the main trend, hiding outlier - * values. Markers are placed at the location of the outlier values enabling the user to - * restore the full extent of the y-axis by selecting the markers. - * - * Requires *addOns.js*. - * - * ![Chart with hidden outliers](./img-Chart-with-Hidden-Outliers.png "Chart with hidden outliers") - * - * @param {object} params Configuration parameters. - * @param {CIQ.ChartEngine} [params.stx] A reference to the chart object. - * @param {number} [params.multiplier=3] Sets the threshold for outliers by multiplying the - * normal data range. The default value hides only extreme outliers. - * @param {Array} [params.altColors] An array of hexadecimal color values used to style - * outlier markers when multiple y-axes share the same panel. Markers for the first - * additional y-axis are styled with the value at index 0; markers for the second - * additional y-axis, the value at index 1; and so forth. If not provided, a default - * array of colors is assigned. - * @param {string} [params.menuContextClass] A CSS class name used to query the menu DOM element - * that contains the UI control for the outliers add-on. In a multi-chart document, the - * add-on is available only on charts that have a menu DOM element with the value for - * `menuContextClass` as a class attribute. - * - * @constructor - * @name CIQ.Outliers - * @since - * - 7.5.0 - * - 8.0.0 Added `params.altColors` and `params.menuContextClass`. - * - * @example - * new CIQ.Outliers({ stx: stxx }); - */ -CIQ.Outliers = - CIQ.Outliers || - function (params) { - if (!params) params = {}; - if (!params.stx) { - console.warn("The Outliers addon requires an stx parameter"); - return; - } - // Set default marker colors - if (!Array.isArray(params.altColors)) { - params.altColors = [ - "#323390", - "#66308f", - "#0073ba", - "#f4932f", - "#0056a4", - "#00a99c", - "#00a553", - "#ea1d2c", - "#e9088c", - "#fff126", - "#912a8e", - "#ee652e", - "#00afed", - "#8ec648" - ]; - } - this.stx = params.stx; - this.stx.outliers = this; - this.cssRequired = true; - - this.multiplier = params.multiplier || 3; // Default to 3 for extreme outliers - this.altColors = params.altColors; - - this.axisData = {}; - - // Listen for a layout changed event and reset the markers - this.stx.addEventListener("layout", function (event) { - Object.keys(event.stx.outliers.axisData).forEach( - function (key) { - this.removeAllMarkers(this.axisData[key]); - delete this.axisData[key]; - }.bind(event.stx.outliers) - ); - }); - - /** - * Checks for outlier values in `dataSet`, and adds outlier markers (data point markers - * and axis markers) to `axis`. - * - * @param {Array} dataSet An array of objects of the form `{value: Number, quote: Object}`. - * Each object contains a value and its associated quote. The value is checked to - * determine whether it is an outlier of the data set. When checking more than one - * value for a quote (such as an OHLC quote), each value is included in a separate - * object; for example, `[{value: open, quote: quote}, {value: high, quote: quote}, - * {value: low, quote: quote}, {value: close, quote: quote}...]`. - * @param {object} panel The panel where `dataSet` is rendered. - * @param {object} axis The y-axis against which `dataSet` is rendered. **Note:** Charts - * and panels can have multiple y-axes; each y-axis has its own set of outlier - * markers based on the data rendered on the axis. - * @return {Array} A tuple consisting of the outlier minimum and maximum — or trend - * minimum and maximum, if no outliers are found — to be handled by the - * {@link CIQ.ChartEngine#determineMinMax} method. See the return value of the - * [find]{@link CIQ.Outliers#find} function for a description of outlier and trend - * minimum and maximum. - * - * @alias processDataSet - * @memberOf CIQ.Outliers.prototype - * @since 8.0.0 - */ - this.processDataSet = function (dataSet, panel, axis) { - if (!dataSet.length || dataSet.length <= 1) return false; - - var result = [0, 0]; // Min/Max axis values to return - - // Create an axis reference if one does not exist - if (!this.axisData[axis.name]) { - var markerColor = ""; - var axisDepth = -1; - // Check for another axis using this panel - Object.keys(this.axisData).forEach( - function (key) { - if (this.axisData[key].panel.name == panel.name) { - axisDepth++; - } - }.bind(this) - ); - if (axisDepth > -1 && axisDepth < this.altColors.length) - markerColor = this.altColors[axisDepth]; - - this.axisData[axis.name] = { - axis: axis, - panel: panel, - displayState: "none", - isFlipped: false, - originalZoom: axis.zoom, - markerColor: markerColor, - markers: {}, - axisMarkers: {} - }; - } - - var currentAxis = this.axisData[axis.name]; - // Attach the min/max values to the current axis data - Object.assign(currentAxis, this.find(dataSet)); - - // Update/add necessary markers - this.refreshMarkerArray(currentAxis); - - // Update marker display and labels - this.refreshMarkers(currentAxis); - - // Return either trendMin or outlierMin based on the axis displayState - if ( - (currentAxis.displayState === "low" || - currentAxis.displayState === "all") && - currentAxis.outlierMin !== null - ) - result[0] = currentAxis.outlierMin; - else result[0] = currentAxis.trendMin; - // Return either trendMax or outlierMax based on the axis displayState - if ( - (currentAxis.displayState === "high" || - currentAxis.displayState === "all") && - currentAxis.outlierMax !== null - ) - result[1] = currentAxis.outlierMax; - else result[1] = currentAxis.trendMax; - - return result; - }; - - /** - * Finds the outliers contained in `dataSet`. - * - * **Note:** This function may be overridden to provide a custom algorithm for finding - * outliers. - * - * @param {Array} dataSet An array of objects of the form `{value: Number, quote: Object}`. - * Each object contains a value and its associated quote. The value is checked to - * determine whether it is an outlier of the data set. When checking more than one - * value for a quote (such as an OHLC quote), each value is included in a separate - * object; for example, `[{value: open, quote: quote}, {value: high, quote: quote}, - * {value: low, quote: quote}, {value: close, quote: quote}...]`. - * @return {object} An object of the form: - * ``` - * { - * // Minimum and maximum threshold values of dataSet to be considered an outlier. - * minValue: null, - * maxValue: null, - * // Mininum and maximum values of dataSet that are not considered outliers. - * // Will be the least and greatest values in dataSet if no outliers are found. - * trendMin: null, - * trendMax: null, - * // Minimum and maximum values of dataSet that are considered outliers. - * // Will remain null if no outliers are found. - * outlierMin: null, - * outlierMax: null, - * // Array of individual outlier information for marker placement, in the format {DT:DateTime, value:Number, position:String} - * // (position is either 'high' or 'low'). - * activeOutliers: [] - * } - * ``` - * - * @alias find - * @memberOf CIQ.Outliers.prototype - * @since - * - 7.5.0 - * - 8.0.0 Added return value. - */ - this.find = function (dataSet) { - if (!dataSet.length || dataSet.length <= 0) return; - - var createMarkerPlaceholder = function (data, position) { - return { - quote: data.quote, - DT: data.quote.DT, - value: data.value, - position: position - }; - }; - - // The minimum and maximum threshold values to be considered an outlier. - var minValue = null; - var maxValue = null; - // min/max values of available data that are not considered outliers. Will be the least and greatest values in the available data if no outliers are found. - var trendMin = null; - var trendMax = null; - // min/max values of available data that are considered outliers. Will remain null if no outlier is found. - var outlierMin = null; - var outlierMax = null; - // Array of outlier information in the format - // {DT:DateTime, value:Number, position:String} - var activeOutliers = []; - - var dataSorted = dataSet.slice(); - dataSorted.sort(function (a, b) { - return a.value - b.value; - }); - var dataLength = dataSorted.length; - - // Outlier threshold values are defined as more than the interquartile range above the third quartile - // or below the first quartile, of the sorted dataSet, multiplied by the value of the - // stxx.outlierMultiplier property. - var q1 = dataSorted[Math.floor(dataLength / 4)].value; - var q3 = dataSorted[Math.floor(dataLength * (3 / 4))].value; - var iqr = q3 - q1; - - minValue = q1 - iqr * this.multiplier; - maxValue = q3 + iqr * this.multiplier; - - // Loop through the sorted data and find the outliers as well as the trend min/max - for (var idx = 0; idx < dataLength; idx++) { - // Attack the array from both ends - var dataLow = dataSorted[idx]; - var dataHigh = dataSorted[dataLength - (idx + 1)]; - - // Find and mark outliers. Existing merkers will be refreshed in setMarker. - if (dataLow.value <= minValue) - activeOutliers.push(createMarkerPlaceholder(dataLow, "low")); - if (dataHigh.value >= maxValue) - activeOutliers.push(createMarkerPlaceholder(dataHigh, "high")); - - // Find the first low value that's less than or equal to outlier threshold min - if (outlierMin === null && dataLow.value <= minValue) - outlierMin = dataLow.value; - // Find the first high value that's greater than or equal to outlier threshold max - if (outlierMax === null && dataHigh.value >= maxValue) - outlierMax = dataHigh.value; - - // Find the first low value that's greater than the outlier threshold min - if (trendMin === null && dataLow.value > minValue) - trendMin = dataLow.value; - // Find the first high value that's less than the outlier threshold max - if (trendMax === null && dataHigh.value < maxValue) - trendMax = dataHigh.value; - - // No need to loop through the entire array. Once the trend min/max are found we're done. - if (trendMin !== null && trendMax !== null) break; - } - - return { - minValue: minValue, - maxValue: maxValue, - trendMin: trendMin, - trendMax: trendMax, - outlierMin: outlierMin, - outlierMax: outlierMax, - activeOutliers: activeOutliers - }; - }; - - /** - * Updates the freshness status of outlier markers belonging to `targetAxis`. - * - * Sets the status to fresh if the markers represent data points in the `activeOutliers` - * list of `targetAxis` or a marker is an axis marker for high or low outliers and high or - * low outliers exist. (See the return value of the [find]{@link CIQ.Outliers#find} - * function for a description of the `activeOutliers` list.) - * - * Adds new markers to `targetAxis` for data points in the `activeOutliers` list not - * already represented by a marker (see [markOutlier]{@link CIQ.Outliers#markOutlier}). - * Adds new axis markers if the data set rendered on `targetAxis` contains high or low - * outliers and the respective axis marker does not exist (see - * [markAxis]{@link CIQ.Outliers#markAxis}). - * - * Sets the status of all other markers belonging to `targetAxis` to stale, or unfresh - * (these markers are ultimately removed). - * - * @param {object} targetAxis The y-axis for which the markers are refreshed. - * **Note:** Charts and panels can have multiple y-axes, each with its own array of - * outlier markers. - * - * @alias refreshMarkerArray - * @memberOf CIQ.Outliers.prototype - * @since 8.0.0 - */ - this.refreshMarkerArray = function (targetAxis) { - this.deprecateMarkers(targetAxis); // If a marker isn't refreshed below, it will be deleted in the next call - - var targetMarkers = targetAxis.markers; - targetAxis.activeOutliers.forEach( - function (outlier) { - var quoteTime = outlier.DT.getTime().toString(); - // Add a quote marker if there isn't one already - if (!targetMarkers[quoteTime]) { - targetMarkers[quoteTime] = { - isFresh: true, - type: "quote", - value: outlier.value, - marker: this.markOutlier(outlier, outlier.position, targetAxis) - }; - } - // Always refresh the status of the marker - targetMarkers[quoteTime].isFresh = true; - }.bind(this) - ); - if (targetAxis.outlierMax !== null) { - // Add the high axis marker if there isn't one - if (!targetMarkers.axisHigh) { - targetMarkers.axisHigh = { - isFresh: true, - type: "axis", - value: targetAxis.outlierMax, - marker: this.markAxis("high", targetAxis) - }; - } - // Always refresh the status of the marker - targetMarkers.axisHigh.isFresh = true; - } - if (targetAxis.outlierMin !== null) { - // Add the low axis marker if there isn't one - if (!targetMarkers.axisLow) { - targetMarkers.axisLow = { - isFresh: true, - type: "axis", - value: targetAxis.outlierMin, - marker: this.markAxis("low", targetAxis) - }; - } - // Always refresh the status of the marker - targetMarkers.axisLow.isFresh = true; - } - }; - - /** - * Sets the outlier display state, which determines whether to display outlier markers. - * - * @param {string} newState The intended display state; should be one of: - *
    - *
  • "high" — Show high outliers; hide high outlier markers.
  • - *
  • "low" — Show low outliers; hide low outlier markers.
  • - *
  • "all" — Show high and low outliers; hide high and low outlier markers.
  • - *
  • "none" — Hide high and low outliers; show high and low outlier markers.
  • - *
- * If none of the above is provided, "none" is assumed. - * @param {object} targetAxis The y-axis on which the outlier state is set. **Note:** A - * chart or panel can have multiple y-axes. - * - * @alias setDisplayState - * @memberOf CIQ.Outliers.prototype - * @since - * - 7.5.0 - * - 8.0.0 Added `targetAxis` parameter. - */ - this.setDisplayState = function (newState, targetAxis) { - if (newState != "high" && newState != "low" && newState != "all") - newState = "none"; - - var displayState = newState; - // Set the value of displayState to show the intended state, based on its existing state. This - // allows the markers to toggle between states without concern for what is currently displayed. - // For example: if the current display state is showing low outlier only, and the intent is to - // now display high outliers as well, then the display state will change to 'all'. - // This will toggle the high/low state off as well. - if (targetAxis.displayState == "all" && newState == "high") - displayState = "low"; - else if (targetAxis.displayState == "all" && newState == "low") - displayState = "high"; - else if (targetAxis.displayState == "high" && newState == "low") - displayState = "all"; - else if (targetAxis.displayState == "low" && newState == "high") - displayState = "all"; - else if (targetAxis.displayState == newState) displayState = "none"; - - targetAxis.displayState = displayState; - // Reset the axis zoom state - targetAxis.axis.zoom = targetAxis.originalZoom; - - this.refreshMarkers(targetAxis); - this.stx.draw(); - }; - - /** - * Removes all markers from `targetAxis` that are no longer fresh; that is, markers that - * do not represent data points in the current data set, or axis markers that are - * irrelevant because high or low outliers no longer exist. Sets the status of all - * remaining outlier markers to stale, or not fresh (the freshness status should - * subsequently be reevaluated). - * - * @param {object} targetAxis The y-axis for which the markers are deprecated. **Note:** - * A chart or panel can have multiple y-axes; each y-axis has its own outlier - * markers based on the data rendered on the axis. - * - * @alias deprecateMarkers - * @memberOf CIQ.Outliers.prototype - * @since - * - 7.5.0 - * - 8.0.0 Added `targetAxis` parameter. - */ - this.deprecateMarkers = function (targetAxis) { - var removeMarker = function (marker) { - if (marker.marker && !marker.isFresh) { - if (marker.marker.remove) marker.marker.remove(); - marker.marker = null; - } else { - marker.isFresh = false; - } - }; - - // Handle the outlier markers - Object.keys(targetAxis.markers).forEach( - function (key) { - removeMarker(this.markers[key]); - // Remove the marker property if its marker has been removed - if (!this.markers[key].marker) { - delete this.markers[key]; - } - }.bind(targetAxis) - ); - }; - - /** - * Removes all outlier markers from `targetAxis`, including data point markers and y-axis - * markers. - * - * @param {object} targetAxis The y-axis from which the markers are removed. **Note:** - * Charts and panels can have multiple y-axes, each with its own outlier markers. - * - * @alias removeAllMarkers - * @memberOf CIQ.Outliers.prototype - * @since - * - 7.5.0 - * - 8.0.0 Added `targetAxis` parameter. - */ - this.removeAllMarkers = function (targetAxis) { - Object.keys(targetAxis.markers).forEach(function (key) { - var targetMarker = targetAxis.markers[key].marker; - if (targetMarker) { - if (targetMarker.remove) targetMarker.remove(); - targetMarker = null; - } - // Remove the marker property if its marker has been removed - if (!targetMarker) { - delete targetAxis.markers[key]; - } - }); - }; - - /** - * Shows or hides outlier markers based on the display state. - * - * See [setDisplayState]{@link CIQ.Outliers#setDisplayState}. - * - * @alias updateMarkerVisibility - * @memberOf CIQ.Outliers.prototype - * @since 7.5.0 - */ - this.updateMarkerVisibility = function () { - Object.keys(this.markers).forEach( - function (key) { - if ( - this.displayState == "all" || - this.markers[key].marker.node.classList.contains(this.displayState) - ) - this.markers[key].marker.node.style.display = "none"; - else this.markers[key].marker.node.style.display = "block"; - }.bind(this) - ); - }; - - /** - * Updates the position of the axis outlier marker represented by `node`. - * - * @param {HTMLElement} node The axis marker to position. - * @param {object} targetAxis The y-axis on which the axis marker is positioned. - * - * @alias refreshAxisMarkers - * @memberOf CIQ.Outliers.prototype - * @since - * - 7.5.0 - * - 8.0.0 Added `targetAxis` parameter. - */ - this.refreshAxisMarkers = function (node, targetAxis) { - var isHigh = false; - var positionClass = "low"; - if (node.classList.contains("high")) { - isHigh = true; - positionClass = "high"; - } - var posTop = targetAxis.axis.top; - // Set the low marker of reverse the value if the axis is flipped - if ( - (!targetAxis.isFlipped && !isHigh) || - (targetAxis.isFlipped && isHigh) - ) { - posTop = targetAxis.axis.bottom - 50; - } - // Overlap the markers in the center for nano size because it's all or nothing at that size. - if (node.classList.contains("nano")) { - posTop = targetAxis.axis.top + targetAxis.axis.height / 2 - 22; - } - - var xFormLeft = Math.floor(targetAxis.axis.left).toString() + "px"; - var xFormTop = Math.floor(posTop).toString() + "px"; - // Use the vlaue property instead - var labelPrice = isHigh ? targetAxis.outlierMax : targetAxis.outlierMin; - - // Set marker positioning relative to the y-axis - node.style.transform = "translate(" + xFormLeft + ", " + xFormTop + ")"; - node.querySelector( - ".outlier-value" - ).innerText = this.stx.formatYAxisPrice(labelPrice); - // Apply .right class when axis is on the left to right position child elements - if (xFormLeft === "0px") node.classList.add("right"); - else node.classList.remove("right"); - }; - - /** - * Updates the display styles of all outlier markers belonging to `targetAxis`, including - * data point markers and axis markers. Shows the markers if outliers are hidden and the - * marked outliers exceed the bounds of `targetAxis`. Flips the markers if `targetAxis` - * has been inverted (see [flipMarkers]{@link CIQ.Outliers#flipMarkers}). - * - * @param {object} targetAxis The y-axis on which the markers are refreshed. **Note:** - * Charts and panels can have multiple y-axes, each with its own outlier markers. - * - * @alias refreshMarkers - * @memberOf CIQ.Outliers.prototype - * @since 8.0.0 - */ - this.refreshMarkers = function (targetAxis) { - Object.keys(targetAxis.markers).forEach( - function (targetAxis, key) { - var targetMarker = targetAxis.markers[key].marker; - var targetValue = targetAxis.markers[key].value; - var targetType = targetAxis.markers[key].type; - // Check the marker value against the actual axis min/max. This accounts for yaxis scaling - // in addition to the outlier display state. - if ( - (targetValue > targetAxis.trendMax && - targetAxis.axis.high >= targetValue) || - (targetValue < targetAxis.trendMin && - targetAxis.axis.low <= targetValue) - ) { - if (targetType == "quote") { - targetMarker.node.style.display = "none"; - } else if (targetType == "axis") { - targetMarker.node.classList.add("compress"); - } - } else { - if (targetType == "quote") { - targetMarker.node.style.display = "block"; - } else if (targetType == "axis") { - targetMarker.node.classList.remove("compress"); - } - } - - if (targetType == "axis") { - this.refreshAxisMarkers(targetMarker.node, targetAxis); - } - - // Update the marker responsive style - if (targetAxis.axis.height < 100) - targetMarker.node.classList.add("nano"); - else targetMarker.node.classList.remove("nano"); - - if (targetAxis.axis.height < 250) - targetMarker.node.classList.add("micro"); - else targetMarker.node.classList.remove("micro"); - }.bind(this, targetAxis) - ); - - // Check for a change in the flipped state of the axis - if (targetAxis.isFlipped !== targetAxis.axis.flipped) - this.flipMarkers(targetAxis); - }; - - /** - * Places markers on the y-axis when high or low outliers exist. - * - * @param {string} position The position of the marker; either "high" or "low". If the - * position is "high", the marker is placed at the top of the axis; if "low", at the - * bottom of the axis. - * @param {object} targetAxis The y-axis on which the markers are placed. **Note:** - * Charts and panels can have multiple y-axes, each with its own outlier markers. - * @return {CIQ.Marker} The axis outlier marker, which is added to the display. - * - * @alias markAxis - * @memberOf CIQ.Outliers.prototype - * @since - * - 7.5.0 - * - 8.0.0 Added `position` and `targetAxis` parameters and return value. - */ - this.markAxis = function (position, targetAxis) { - // Create a marker positioned on the Y axis and return it. - var axisMarker = document.createElement("div"); - axisMarker.classList.add("outlier-sticker", "axis", "mini", position); - axisMarker.innerHTML = - '
'; - - this.matchYAxisStyle(axisMarker); - this.setMarkerColor(axisMarker, targetAxis.markerColor); - - var activate = this.handleMarkerClick.bind( - this, - position, - targetAxis, - axisMarker - ); - axisMarker.addEventListener("click", activate); - axisMarker.addEventListener("touchend", activate); - - return new CIQ.Marker({ - stx: this.stx, - xPositioner: "none", - yPositioner: "none", - label: "expand", - permanent: true, - chartContainer: true, - node: axisMarker - }); - }; - - /** - * Adds an outlier marker to a tick (data point). - * - * @param {object} data Represents the tick that is marked as an outlier. Contains the - * outlier value and its associated quote; for example, - * `{value: Number, quote: Object}`. - * @param {string} position The position of the marker; either "high" or "low". If the - * position is "high", the marker is placed at the top of the chart; if "low", at the - * bottom of the chart. - * @param {object} targetAxis The y-axis to which the marker is added. **Note:** A chart - * or panel can have multiple y-axes; each y-axis has its own outlier markers. - * @return {CIQ.Marker} The outlier marker, which is added to the display. - * - * @alias markOutlier - * @memberOf CIQ.Outliers.prototype - * @since - * - 7.5.0 - * - 8.0.0 Added `targetAxis` parameter. - */ - this.markOutlier = function (data, position, targetAxis) { - if (!data) return; - if (!targetAxis) targetAxis = { panel: this.stx.panels.chart }; - position = position || "high"; - - // Create a marker - var outlierMarker = document.createElement("div"); - outlierMarker.classList.add("outlier-sticker", "quote", "mini", position); - outlierMarker.innerHTML = - '
' + - this.stx.formatYAxisPrice(data.value, targetAxis.panel) + - ""; - - this.matchYAxisStyle(outlierMarker); - this.setMarkerColor(outlierMarker, targetAxis.markerColor); - - var activate = this.handleMarkerClick.bind( - this, - position, - targetAxis, - outlierMarker - ); - outlierMarker.addEventListener("click", activate); - outlierMarker.addEventListener("touchend", activate); - - return new CIQ.Marker({ - stx: this.stx, - xPositioner: "date", - yPositioner: position == "high" ? "top" : "bottom", - x: data.quote.DT, - panelName: targetAxis.panel.name, - node: outlierMarker - }); - }; - - /** - * Calls [setDisplayState]{@link CIQ.Outliers#setDisplayState} in response to selecting an - * outlier marker. - * - * @param {string} position The position of the marker; either "high" or "low". - * @param {object} targetAxis The y-axis that contains the selected marker. **Note:** - * Charts and panels can have multiple y-axes; each y-axis has its own outlier - * markers. - * @param {HTMLElement} targetNode The selected outlier marker DOM node. - * - * @alias handleMarkerClick - * @memberOf CIQ.Outliers.prototype - * @since 8.0.0 - */ - this.handleMarkerClick = function (position, targetAxis, targetNode) { - if (targetNode.classList.contains("nano")) position = "all"; // not concerned about differentiation between high and low at the nano size - this.setDisplayState(position, targetAxis); - this.stx.draw(); - }; - - /** - * Sets the CSS style properties of the y-axis outlier marker to match the CSS styling of - * the y-axis itself. - * - * @param {HTMLElement} node The y-axis marker to style. - * - * @alias matchYAxisStyle - * @memberOf CIQ.Outliers.prototype - * @since 7.5.0 - */ - this.matchYAxisStyle = function (node) { - // Apply styles from the yAxis - if (this.stx.styles.stx_yaxis) { - var styles = this.stx.styles.stx_yaxis; - node.style.fontSize = styles.fontSize; - node.style.fontFamily = styles.fontFamily; - node.style.color = styles.color; - node.style.borderColor = styles.color; - } - }; - - /** - * Applies a background color to an outlier data point marker. - * - * @param {HTMLElement} node The outlier marker DOM node to which the background color is - * applied. - * @param {string} color The hexadecimal color value set as the node background color. - * - * @alias setMarkerColor - * @memberOf CIQ.Outliers.prototype - * @since 8.0.0 - */ - this.setMarkerColor = function (node, color) { - if (color == "") return; - //Set marker color - var markerPills = node.querySelectorAll(".pill"); - for (var markerIdx = 0; markerIdx < markerPills.length; markerIdx++) { - markerPills[markerIdx].style.backgroundColor = color; - } - }; - - /** - * Repositions outlier markers from the top of the display to the bottom (or vice versa) - * when the associated y-axis has been flipped (inverted). - * - * @param {object} targetAxis The y-axis that has been flipped. - * - * @alias flipMarkers - * @memberOf CIQ.Outliers.prototype - * @since 8.0.0 - */ - this.flipMarkers = function (targetAxis) { - targetAxis.isFlipped = targetAxis.axis.flipped; - - Object.keys(targetAxis.markers).forEach( - function (targetAxis, key) { - var targetMarker = targetAxis.markers[key].marker; - var targetValue = targetAxis.markers[key].value; - var targetType = targetAxis.markers[key].type; - // Check for flipped state and add/remove flipped class - if (targetAxis.isFlipped) { - targetMarker.node.classList.add("flipped"); - } else { - targetMarker.node.classList.remove("flipped"); - } - - // Set Y positioning of quote markers - if (targetType == "quote") { - if (targetValue > targetAxis.trendMax) { - // High marker - if (targetAxis.isFlipped) - targetMarker.params.yPositioner = "bottom"; - else targetMarker.params.yPositioner = "top"; - } else if (targetValue < targetAxis.trendMin) { - // Low marker - if (targetAxis.isFlipped) targetMarker.params.yPositioner = "top"; - else targetMarker.params.yPositioner = "bottom"; - } - } - }.bind(this, targetAxis) - ); - }; - - var originalDetermineMinMax = CIQ.ChartEngine.prototype.determineMinMax.bind( - this.stx - ); - /** - * Overrides the default `CIQ.ChartEngine.prototype.determineMinMax` function when the - * Outliers add-on is active. Injects the local {@link CIQ.Outliers#processDataSet} - * function as a data filter and passes the filter along to the original `determineMinMax` - * function (see below). - * - * @param {Array} quotes The array of quotes (typically - * `CIQ.ChartEngine.chart.dataSegment`) to evaluate for minimum and maximum values. - * @param {Array} fields A list of fields to compare. - * @param {boolean|Array} [sum] If true, then compute maximum sum rather than the maximum - * single value across all fields. If an array, compute sum over just the fields in - * the array. - * @param {boolean} [bypassTransform] If true, bypass any transformations. - * @param {number} [length] Specifies how many elements of the quotes array to process. - * @param {boolean} [checkArray] If true, the type of the value used to determine the - * min/max is checked to ascertain whether it is an array; if so, the first element - * of the array is retrieved for use in the min/max determination. - * @param {CIQ.ChartEngine.Panel} [panel] A reference to the panel rendering the quotes. - * @param {CIQ.ChartEngine.YAxis} [axis] A reference to the y-axis rendered for the quotes. - * @param {Array} [filters] Array of functions to process the min/max values before - * returning. Filter functions must return a valid min/max tuple or false. - * @return {function} A reference to the original - * `CIQ.ChartEngine.prototype.determineMinMax` library function. - * - * @memberof CIQ.ChartEngine - * @since - * - 7.5.0 - * - 8.0.0 Allow the `sum` parameter to be an array of valid fields to sum over. - * Added the `panel`, `axis`, and `filters` parameters. - * @private - */ - CIQ.ChartEngine.prototype.determineMinMax = function ( - quotes, - fields, - sum, - bypassTransform, - length, - checkArray, - panel, - axis, - filters - ) { - if (!filters) filters = []; - if (panel && axis && this.layout.outliers) - filters.push(this.outliers.processDataSet.bind(this.outliers)); - return originalDetermineMinMax( - quotes, - fields, - sum, - bypassTransform, - length, - checkArray, - panel, - axis, - filters - ); - }; - }; - -/** - * CIQ.Marker interface placeholder to be augmented in *standard.js* with properties. - * - * @tsinterface CIQ~Marker - */ - -}; - - -let __js_addons_advanced_plotComplementer_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -/** - * Creates an add-on that enables a series to complement another series. - * - * ![Plot Complementer](./img-Data-Forecasting.png) - * - * The complementary series is a permanent fixture of the series which it complements. It moves - * in tandem with the series, and gets removed with the series. In all other respects, though, it - * behaves like its own series. It shows separately in the panel legend and plots using its own - * renderer. - * - * Charts can have multiple `PlotComplementer` instances. Each instance is attached to the chart - * engine as a member of a `PlotComplementer` collection. - * - * Multiple `PlotComplementer` instances can be associated with a time series. To link a - * `PlotComplementer` to a series, specify the series instrument in the `params.filter` function. - * See `[setQuoteFeed]{@link CIQ.PlotComplementer#setQuoteFeed}`. - * - * **Note:** The series created by this add-on is not exported with the layout, since it is - * created in tandem with the series it complements. Currently, this feature works only with - * non-comparison series. - * - * Requires *addOns.js*. - * - * @param {object} params Configuration parameters. - * @param {CIQ.ChartEngine} params.stx The chart object. - * @param {string} [params.id] Unique key used by the add-on to identify itself. If not supplied, - * a random key is chosen. - * @param {object} [params.quoteFeed] Attaches the quote feed to the quote driver to satisfy any - * quote requests for any series created by the add-on. - * @param {object} [params.behavior] Used as the behavior for the quote feed supplied in this - * parameter list. - * @param {function} [params.filter] Used as the filter for the quote feed supplied in this - * parameter list. See `[setQuoteFeed]{@link CIQ.PlotComplementer#setQuoteFeed}`. - * @param {object} [params.decorator] Container object for the `symbol` and `display` properties. - * The `decorator` provides the label (`symbol`) for the complementary series and a short - * description (`display`) that is appended to the label; for example: - * ``` - * decorator: {symbol:"_fcst", display:" Forecast"} - * ``` - * @param {string} [params.decorator.symbol] Adds this string onto the ID when creating the - * complementary series. Otherwise, a unique ID is used. - * @param {string} [params.decorator.display] Customizes the display value of the series. - * @param {object} [params.renderingParameters={chartType: "line", width: 1, opacity: 0.5}] A - * collection of parameters that override the default rendering parameters. The - * `renderingParameters` object can be set or changed at any time. The default parameters - * can be restored by calling {@link CIQ.PlotComplementer#resetRenderingParameters}. - *

Here are a few examples of rendering parameters:

- * ``` - * // Assuming a PlotComplementer declared as "forecaster": - * forecaster.renderingParameters = {chartType:"scatterplot", opacity:0.5, field:"Certainty"} - * forecaster.renderingParameters = {chartType:"histogram", border_color:"transparent", opacity:0.3} - * forecaster.renderingParameters = {chartType:"channel", opacity:0.5, pattern:"dotted"} - * forecaster.renderingParameters = {chartType:"candle", opacity:0.5, color:"blue", border_color:"blue"} - * ``` - * - * @constructor - * @name CIQ.PlotComplementer - * @since 7.3.0 - * - * @example Forecasting - * let forecaster = new CIQ.PlotComplementer({ - * stx:stxx, - * id:"forecast", - * quoteFeed: fcstFeed.quoteFeedForecastSimulator, - * behavior: {refreshInterval:60}, - * decorator: {symbol:"_fcst", display:" Forecast"}, - * renderingParameters: {chartType:"channel", opacity:0.5, pattern:"dotted"} - * }); - */ -CIQ.PlotComplementer = - CIQ.PlotComplementer || - function (params) { - var stx = params.stx; - var unique = CIQ.uniqueID(); - if (!params.decorator) params.decorator = {}; - var symbolDecorator = params.decorator.symbol || "_" + unique; - var displayDecorator = params.decorator.display || " (addl)"; - if (!stx.plotComplementers) stx.plotComplementers = []; - stx.plotComplementers.push(this); - - this.id = params.id || unique; - - this.defaultRenderingParameters = { - chartType: "line", - width: 1, - opacity: 0.5 - }; - - if (params.renderingParameters) - this.defaultRenderingParameters = params.renderingParameters; - - var self = this; - function addSeries(stx, symbol, parameters, id) { - function verifyQuoteFeed(stx) { - if (!stx.quoteDriver) return; - if (!params.quoteFeed) return; - for (var qf = 0; qf < stx.quoteDriver.quoteFeeds.length; qf++) { - if (stx.quoteDriver.quoteFeeds[qf].engine == params.quoteFeed) return; - } - return "err"; - } - if (verifyQuoteFeed(stx) == "err") return; - if (!id) id = symbol; - if (stx.isEquationChart(symbol)) return; - if (!parameters) parameters = {}; - if (parameters.isComparison) return; - if (id && id.indexOf(symbolDecorator) == -1) { - var fId = id + symbolDecorator, - fSymbol = symbol + symbolDecorator; - var masterRenderer = stx.getRendererFromSeries(id); - var myParms = CIQ.extend( - { - display: symbol + displayDecorator, - name: fId, - symbol: fSymbol, - symbolObject: { - symbol: fSymbol, - generator: self.id, - masterSymbol: symbol - }, - overChart: false, - gapDisplayStyle: true, - permanent: true, - panel: parameters.panel, - yAxis: parameters.yAxis, - shareYAxis: true, - loadData: !!self.quoteFeed, - dependentOf: masterRenderer - ? masterRenderer.params.name - : stx.mainSeriesRenderer.params.name - }, - self.renderingParameters - ); - if (!myParms.color) myParms.color = parameters.color || "auto"; - stx.addSeries(fId, myParms, function (error, obj) { - if (error) stx.removeSeries(fId, stx.chart); - if (stx.chart.seriesRenderers[fId]) { - stx.chart.seriesRenderers[fId].params.display = myParms.display; - } - }); - } - } - - function removeSeries(stx, id, chart) { - if (id && id.indexOf(symbolDecorator) == -1) - stx.removeSeries(id + symbolDecorator, chart); - } - - function symbolChange(obj) { - if (obj.action == "master") { - if (!obj.prevSymbol) obj.prevSymbol = obj.symbol; - removeSeries(obj.stx, obj.prevSymbol, obj.stx.chart); - addSeries(obj.stx, obj.symbol); - } else if (obj.action == "add-series") { - removeSeries(obj.stx, obj.id, obj.stx.chart); - addSeries(obj.stx, obj.symbol, obj.parameters, obj.id); - } else if (obj.action == "remove-series") { - removeSeries(obj.stx, obj.id, obj.stx.chart); - } - } - - stx.addEventListener("symbolChange", symbolChange); - stx.addEventListener("symbolImport", symbolChange); - - /** - * Resets the `PlotComplementer` rendering values to the default settings. - * - * Default settings can be provided in the parameters passed to the `PlotComplementer` constructor. If no settings are - * provided to the constructor, `PlotComplementer` uses the following defaults: `{ chartType:"line", width:1, opacity:0.5 }`. - * - * The rendering parameters may be set anytime after creating `PlotComplementer`; for example, to set an ad-hoc rendering - * right before adding a series. - * - * @alias resetRenderingParameters - * @memberof CIQ.PlotComplementer.prototype - * @since 7.3.0 - */ - this.resetRenderingParameters = function () { - this.renderingParameters = this.defaultRenderingParameters; - }; - - /** - * Sets a quote feed for the `PlotComplementer`. - * - * Automatically called when a quote feed is provided in the constructor argument. If a - * quote feed or `behavior` object is not specified in `params`, this function returns - * without doing anything. - * - * @param {object} params Configuration parameters. - * @param {object} params.quoteFeed Quote feed to attach to the quote driver to satisfy - * any quote requests for any series created by the add-on. This quote feed is like - * any time series quote feed object. See the - * [Data Integration Overview]{@tutorial DataIntegrationOverview}. - * @param {object} params.behavior Behavior for the quote feed supplied in this parameter - * list. This object is like any `behavior` object associated with a quote feed. - * See {@link CIQ.ChartEngine#attachQuoteFeed} for more information on `behavior` - * objects. - * @param {function} [params.filter] Filters the quote feed supplied in this parameter - * list. The filter function takes as an argument an object typically containing - * `symbolObject`, `symbol`, and `interval` properties. The properties associate the - * `PlotComplementer` with an instrument. If the `filter` function returns true, the - * `PlotComplementer` quote feed is used for the instrument. - *

This `filter` function is like the `filter` in basic quote feeds. - * See {@link CIQ.ChartEngine#attachQuoteFeed} for more information on quote feed - * `filter` functions.

- * @alias setQuoteFeed - * @memberof CIQ.PlotComplementer.prototype - * @since 7.3.0 - */ - this.setQuoteFeed = function (params) { - if (!params.quoteFeed || !params.behavior) return; - var behavior = CIQ.clone(params.behavior); - behavior.generator = this.id; - var existingFilter = params.filter; - var filter = function (params) { - if (existingFilter && !existingFilter(params)) return false; - return params.symbolObject.generator == behavior.generator; - }; - stx.attachQuoteFeed(params.quoteFeed, behavior, filter); - this.quoteFeed = params.quoteFeed; - }; - - this.setQuoteFeed(params); - this.resetRenderingParameters(); - }; - -}; - - -let _exports = {CIQ:__CIQ_}; -export {__js_addons_standard_extendedHours_ as extendedHours}; -export {__js_addons_standard_fullScreen_ as fullScreen}; -export {__js_addons_standard_inactivityTimer_ as inactivityTimer}; -export {__js_addons_standard_rangeSlider_ as rangeSlider}; -export {__js_addons_standard_shortcuts_ as shortcuts}; -export {__js_addons_standard_tableView_ as tableView}; -export {__js_addons_standard_tooltip_ as tooltip}; -export {__js_addons_advanced_animation_ as animation}; -export {__js_addons_advanced_continuousZoom_ as continuousZoom}; -export {__js_addons_advanced_outliers_ as outliers}; -export {__js_addons_advanced_plotComplementer_ as plotComplementer}; - -export {__CIQ_ as CIQ}; - -/* global __TREE_SHAKE__ */ -if (typeof __TREE_SHAKE__ === "undefined" || !__TREE_SHAKE__) { - _exports.CIQ.activateImports( - __js_addons_standard_extendedHours_, - __js_addons_standard_fullScreen_, - __js_addons_standard_inactivityTimer_, - __js_addons_standard_rangeSlider_, - __js_addons_standard_shortcuts_, - __js_addons_standard_tableView_, - __js_addons_standard_tooltip_, - __js_addons_advanced_animation_, - __js_addons_advanced_continuousZoom_, - __js_addons_advanced_outliers_, - __js_addons_advanced_plotComplementer_, - null - ); -} \ No newline at end of file diff --git a/chartiq/development/js/advanced.js b/chartiq/development/js/advanced.js deleted file mode 100644 index ac8329ed1b..0000000000 --- a/chartiq/development/js/advanced.js +++ /dev/null @@ -1,16390 +0,0 @@ -/***************************************************************************! - WARNING: this file is for internal development and debugging purposes only! - It may *not* be posted publicly under any circumstances without explicit - consent from ChartIQ. -****************************************************************************/ -/**! - * 8.2.0 - * Generation date: 2023-03-23T15:05:01.971Z - * Client name: deriv limited - * Package Type: Technical Analysis - * License type: annual - * Expiration date: "2024/04/01" - * Domain lock: ["127.0.0.1","localhost","deriv.com","deriv.app","deriv.me","binary.com","binary.sx","binary.me","binary.bot","deriv.be"] - * iFrame lock: true - */ - -/***********************************************************! - * Copyright by ChartIQ, Inc. - * Licensed under the ChartIQ, Inc. Developer License Agreement https://www.chartiq.com/developer-license-agreement -*************************************************************/ -/*************************************! DO NOT MAKE CHANGES TO THIS LIBRARY FILE!! !************************************* -* If you wish to overwrite default functionality, create a separate file with a copy of the methods you are overwriting * -* and load that file right after the library has been loaded, but before the chart engine is instantiated. * -* Directly modifying library files will prevent upgrades and the ability for ChartIQ to support your solution. * -*************************************************************************************************************************/ -/* eslint-disable no-extra-parens */ - - -import {CIQ as __CIQ_, SplinePlotter as __SplinePlotter_, timezoneJS as __timezoneJS_, $$ as __$$_, $$$ as __$$$_} from "../js/standard.js"; - - -let __js_advanced_drawingAdvanced_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; -var timezoneJS = - typeof _timezoneJS !== "undefined" ? _timezoneJS : _exports.timezoneJS; - -if (!CIQ.Drawing) { - console.error( - "drawingAdvanced feature requires first activating drawing feature." - ); -} else { - /** - * Ray drawing tool. A ray is defined by two points. It travels infinitely past the second point. - * - * It inherits its properties from {@link CIQ.Drawing.line}. - * @constructor - * @name CIQ.Drawing.ray - */ - CIQ.Drawing.ray = function () { - this.name = "ray"; - }; - - CIQ.inheritsFrom(CIQ.Drawing.ray, CIQ.Drawing.line); - - CIQ.Drawing.ray.prototype.calculateOuterSet = function (panel) { - if ( - this.p0[0] == this.p1[0] || - this.p0[1] == this.p1[1] || - CIQ.ChartEngine.isDailyInterval(this.stx.layout.interval) - ) { - return; - } - - var vector = { - x0: this.p0[0], - y0: this.p0[1], - x1: this.p1[0], - y1: this.p1[1] - }; - - var endOfRay = vector.x1 + 1000; - if (vector.x0 > vector.x1) { - endOfRay = vector.x1 - 1000; - } - - this.v0B = this.v0; - this.v1B = CIQ.yIntersection(vector, endOfRay); - this.d0B = this.d0; - this.d1B = this.stx.dateFromTick(endOfRay, panel.chart); - }; - - CIQ.Drawing.ray.prototype.adjust = function () { - var panel = this.stx.panels[this.panelName]; - if (!panel) return; - this.setPoint(0, this.d0, this.v0, panel.chart); - this.setPoint(1, this.d1, this.v1, panel.chart); - // Use outer set if original drawing was on intraday but now displaying on daily - if (CIQ.ChartEngine.isDailyInterval(this.stx.layout.interval) && this.d0B) { - this.setPoint(1, this.d1B, this.v1B, panel.chart); - } - }; - - /** - * Continuous line drawing tool. Creates a series of connected line segments, each one completed with a user click. - * - * It inherits its properties from {@link CIQ.Drawing.segment}. - * @constructor - * @name CIQ.Drawing.continuous - */ - CIQ.Drawing.continuous = function () { - this.name = "continuous"; - this.dragToDraw = false; - this.maxSegments = null; - }; - - CIQ.inheritsFrom(CIQ.Drawing.continuous, CIQ.Drawing.segment); - - CIQ.Drawing.continuous.prototype.click = function (context, tick, value) { - var panel = this.stx.panels[this.panelName]; - if (!panel) return; - this.copyConfig(); - if (!this.penDown) { - this.setPoint(0, tick, value, panel.chart); - this.penDown = true; - return false; - } - if (this.accidentalClick(tick, value)) { - this.stx.undo(); //abort - return true; - } - - this.setPoint(1, tick, value, panel.chart); - - // render a segment - var Segment = CIQ.Drawing.segment; - var segment = new Segment(); - var obj = this.serialize(this.stx); - segment.reconstruct(this.stx, obj); - this.stx.addDrawing(segment); - this.stx.changeOccurred("vector"); - this.stx.draw(); - this.segment++; - - if (this.maxSegments && this.segment > this.maxSegments) return true; - this.setPoint(0, tick, value, panel.chart); // reset initial point for next segment, copy by value - return false; - }; - - /** - * Ellipse drawing tool. - * - * It inherits its properties from {@link CIQ.Drawing.BaseTwoPoint}. - * @constructor - * @name CIQ.Drawing.ellipse - */ - CIQ.Drawing.ellipse = function () { - this.name = "ellipse"; - }; - - CIQ.inheritsFrom(CIQ.Drawing.ellipse, CIQ.Drawing.BaseTwoPoint); - - CIQ.Drawing.ellipse.prototype.render = function (context) { - var panel = this.stx.panels[this.panelName]; - if (!panel) return; - var x0 = this.stx.pixelFromTick(this.p0[0], panel.chart); - var x1 = this.stx.pixelFromTick(this.p1[0], panel.chart); - var y0 = this.stx.pixelFromValueAdjusted(panel, this.p0[0], this.p0[1]); - var y1 = this.stx.pixelFromValueAdjusted(panel, this.p1[0], this.p1[1]); - - var left = x0 - (x1 - x0); - var right = x1; - var middle = y0; - var bottom = y1; - var top = y0 - (y1 - y0); - var weight = (bottom - top) / 6; - var lineWidth = this.lineWidth; - if (!lineWidth) lineWidth = 1.1; - var edgeColor = this.color; - if (edgeColor == "auto" || CIQ.isTransparent(edgeColor)) - edgeColor = this.stx.defaultColor; - if (this.highlighted) { - edgeColor = this.stx.getCanvasColor("stx_highlight_vector"); - if (lineWidth == 0.1) lineWidth = 1.1; - } - - var fillColor = this.fillColor; - - context.beginPath(); - context.moveTo(left, middle); - context.bezierCurveTo( - left, - bottom + weight, - right, - bottom + weight, - right, - middle - ); - context.bezierCurveTo( - right, - top - weight, - left, - top - weight, - left, - middle - ); - - if (fillColor && !CIQ.isTransparent(fillColor) && fillColor != "auto") { - context.fillStyle = fillColor; - context.globalAlpha = 0.2; - context.fill(); - context.globalAlpha = 1; - } - - if (edgeColor && this.pattern != "none") { - context.strokeStyle = edgeColor; - context.lineWidth = lineWidth; - if (context.setLineDash) { - context.setLineDash(CIQ.borderPatternToArray(lineWidth, this.pattern)); - context.lineDashOffset = 0; //start point in array - } - context.stroke(); - } - context.closePath(); - if (this.highlighted) { - var p1Fill = this.highlighted == "p1" ? true : false; - this.littleCircle(context, x1, y1, p1Fill); - } - }; - - CIQ.Drawing.ellipse.prototype.intersected = function (tick, value, box) { - if (!this.p0 || !this.p1) return null; // in case invalid drawing (such as from panel that no longer exists) - if (this.pointIntersection(this.p1[0], this.p1[1], box)) { - this.highlighted = "p1"; - return { - action: "drag", - point: "p1" - }; - } - var left = this.p0[0] - (this.p1[0] - this.p0[0]); - var right = this.p1[0]; - var bottom = this.p1[1]; - var top = this.p0[1] - (this.p1[1] - this.p0[1]); - - if (box.x0 > Math.max(left, right) || box.x1 < Math.min(left, right)) - return false; - if (box.y1 > Math.max(top, bottom) || box.y0 < Math.min(top, bottom)) - return false; - this.highlighted = true; - return { - action: "move", - p0: CIQ.clone(this.p0), - p1: CIQ.clone(this.p1), - tick: tick, - value: value - }; - }; - - CIQ.Drawing.ellipse.prototype.configs = [ - "color", - "fillColor", - "lineWidth", - "pattern" - ]; - - /** - * Reconstruct an ellipse - * @param {CIQ.ChartEngine} stx The chart object - * @param {object} [obj] A drawing descriptor - * @param {string} [obj.col] The border color - * @param {string} [obj.fc] The fill color - * @param {string} [obj.pnl] The panel name - * @param {string} [obj.ptrn] Optional pattern for line "solid","dotted","dashed". Defaults to solid. - * @param {number} [obj.lw] Optional line width. Defaults to 1. - * @param {number} [obj.v0] Value (price) for the center point - * @param {number} [obj.v1] Value (price) for the outside point - * @param {number} [obj.d0] Date (string form) for the center point - * @param {number} [obj.d1] Date (string form) for the outside point - * @param {number} [obj.tzo0] Offset of UTC from d0 in minutes - * @param {number} [obj.tzo1] Offset of UTC from d1 in minutes - * @memberOf CIQ.Drawing.ellipse - */ - CIQ.Drawing.ellipse.prototype.reconstruct = function (stx, obj) { - this.stx = stx; - this.color = obj.col; - this.fillColor = obj.fc; - this.panelName = obj.pnl; - this.pattern = obj.ptrn; - this.lineWidth = obj.lw; - this.d0 = obj.d0; - this.d1 = obj.d1; - this.tzo0 = obj.tzo0; - this.tzo1 = obj.tzo1; - this.v0 = obj.v0; - this.v1 = obj.v1; - this.adjust(); - }; - - CIQ.Drawing.ellipse.prototype.serialize = function () { - return { - name: this.name, - pnl: this.panelName, - col: this.color, - fc: this.fillColor, - ptrn: this.pattern, - lw: this.lineWidth, - d0: this.d0, - d1: this.d1, - tzo0: this.tzo0, - tzo1: this.tzo1, - v0: this.v0, - v1: this.v1 - }; - }; - - /** - * Channel drawing tool. Creates a channel within 2 parallel line segments. - * - * It inherits its properties from {@link CIQ.Drawing.segment}. - * @constructor - * @name CIQ.Drawing.channel - * @version ChartIQ Advanced Package - */ - CIQ.Drawing.channel = function () { - this.name = "channel"; - this.dragToDraw = false; - this.p2 = null; - }; - - CIQ.inheritsFrom(CIQ.Drawing.channel, CIQ.Drawing.segment); - - CIQ.Drawing.channel.prototype.configs = [ - "color", - "fillColor", - "lineWidth", - "pattern" - ]; - - CIQ.Drawing.channel.prototype.move = function (context, tick, value) { - if (!this.penDown) return; - - this.copyConfig(); - if (this.p2 === null) this.p1 = [tick, value]; - else { - var y = - value - - ((this.p1[1] - this.p0[1]) / (this.p1[0] - this.p0[0])) * - (tick - this.p1[0]); - this.p2 = [this.p1[0], y]; - } - this.render(context); - }; - - CIQ.Drawing.channel.prototype.click = function (context, tick, value) { - var panel = this.stx.panels[this.panelName]; - if (!panel) return; - this.copyConfig(); - if (!this.penDown) { - this.setPoint(0, tick, value, panel.chart); - this.penDown = true; - return false; - } - if (this.accidentalClick(tick, value)) { - this.stx.undo(); //abort - return true; - } - - if (this.p2 !== null) { - this.setPoint(2, this.p2[0], this.p2[1], panel.chart); - this.penDown = false; - return true; - } - this.setPoint(1, tick, value, panel.chart); - if (this.p0[0] == this.p1[0]) { - // don't allow vertical line - this.p1 = null; - return false; - } - this.p2 = [this.p1[0], this.p1[1]]; - return false; - }; - - CIQ.Drawing.channel.prototype.boxIntersection = function (tick, value, box) { - var p0 = this.p0, - p1 = this.p1, - p2 = this.p2; - if (!p0 || !p1 || !p2) return false; - if (box.x0 > Math.max(p0[0], p1[0]) || box.x1 < Math.min(p0[0], p1[0])) - return false; - - // http://stackoverflow.com/questions/1560492/how-to-tell-whether-a-point-is-to-the-right-or-left-side-of-a-line - var s1 = - (p1[0] - p0[0]) * ((p2[1] < p0[1] ? box.y1 : box.y0) - p0[1]) - - (p1[1] - p0[1]) * (tick - p0[0]); - var s2 = - (p2[0] - p0[0]) * - ((p2[1] > p0[1] ? box.y1 : box.y0) - (p0[1] + p2[1] - p1[1])) - - (p1[1] - p0[1]) * (tick - p0[0]); - return s1 * s2 < 0; - }; - - CIQ.Drawing.channel.prototype.intersected = function (tick, value, box) { - if (!this.p0 || !this.p1 || !this.p2) return null; // in case invalid drawing (such as from panel that no longer exists) - var pointsToCheck = { 0: this.p0, 1: this.p1, 2: this.p2 }; - for (var pt in pointsToCheck) { - if ( - this.pointIntersection(pointsToCheck[pt][0], pointsToCheck[pt][1], box) - ) { - this.highlighted = "p" + pt; - return { - action: "drag", - point: "p" + pt - }; - } - } - if (this.boxIntersection(tick, value, box)) { - this.highlighted = true; - // This object will be used for repositioning - return { - action: "move", - p0: CIQ.clone(this.p0), - p1: CIQ.clone(this.p1), - p2: CIQ.clone(this.p2), - tick: tick, // save original tick - value: value // save original value - }; - } - return null; - }; - - CIQ.Drawing.channel.prototype.render = function (context) { - var panel = this.stx.panels[this.panelName]; - if (!panel) return; - var x0 = this.stx.pixelFromTick(this.p0[0], panel.chart); - var x1 = this.stx.pixelFromTick(this.p1[0], panel.chart); - var y0 = this.stx.pixelFromValueAdjusted(panel, this.p0[0], this.p0[1]); - var y1 = this.stx.pixelFromValueAdjusted(panel, this.p1[0], this.p1[1]); - var y = null; - if (this.p2) { - y = this.stx.pixelFromValueAdjusted(panel, this.p2[0], this.p2[1]); - } - - var width = this.lineWidth; - var color = this.getLineColor(); - - var fillColor = this.fillColor; - if ( - this.p2 && - fillColor && - !CIQ.isTransparent(fillColor) && - fillColor != "auto" - ) { - context.beginPath(); - context.moveTo(x0, y0); - context.lineTo(x1, y1); - context.lineTo(x1, y); - context.lineTo(x0, y0 + (y - y1)); - context.closePath(); - context.globalAlpha = 0.2; - context.fillStyle = fillColor; - context.fill(); - context.globalAlpha = 1; - } - - var parameters = { - pattern: this.pattern, - lineWidth: width - }; - if ((this.penDown || this.highlighted) && this.pattern == "none") - parameters.pattern = "dotted"; - this.stx.plotLine( - x0, - x1, - y0, - y1, - color, - "segment", - context, - panel, - parameters - ); - if (this.p2) - this.stx.plotLine( - x0, - x1, - y0 + (y - y1), - y, - color, - "segment", - context, - panel, - parameters - ); - - if (this.highlighted) { - var p0Fill = this.highlighted == "p0" ? true : false; - var p1Fill = this.highlighted == "p1" ? true : false; - var p2Fill = this.highlighted == "p2" ? true : false; - this.littleCircle(context, x0, y0, p0Fill); - this.littleCircle(context, x1, y1, p1Fill); - this.littleCircle(context, x1, y, p2Fill); - } - }; - - CIQ.Drawing.channel.prototype.reposition = function ( - context, - repositioner, - tick, - value - ) { - if (!repositioner) return; - var panel = this.stx.panels[this.panelName]; - var tickDiff = repositioner.tick - tick; - var valueDiff = repositioner.value - value; - if (repositioner.action == "move") { - this.setPoint( - 0, - repositioner.p0[0] - tickDiff, - repositioner.p0[1] - valueDiff, - panel.chart - ); - this.setPoint( - 1, - repositioner.p1[0] - tickDiff, - repositioner.p1[1] - valueDiff, - panel.chart - ); - this.setPoint( - 2, - repositioner.p2[0] - tickDiff, - repositioner.p2[1] - valueDiff, - panel.chart - ); - this.render(context); - } else if (repositioner.action == "drag") { - this[repositioner.point] = [tick, value]; - this.setPoint(0, this.p0[0], this.p0[1], panel.chart); - this.setPoint(1, this.p1[0], this.p1[1], panel.chart); - this.setPoint(2, this.p2[0], this.p2[1], panel.chart); - this.render(context); - } - }; - - CIQ.Drawing.channel.prototype.adjust = function () { - var panel = this.stx.panels[this.panelName]; - if (!panel) return; - this.setPoint(0, this.d0, this.v0, panel.chart); - this.setPoint(1, this.d1, this.v1, panel.chart); - this.setPoint(2, this.d1, this.v2, panel.chart); //not an error, should be d1 here - }; - - /** - * Reconstruct a channel - * @memberOf CIQ.Drawing.channel - * @param {CIQ.ChartEngine} stx The chart object - * @param {object} [obj] A drawing descriptor - * @param {string} [obj.col] The line color - * @param {string} [obj.fc] The fill color - * @param {string} [obj.pnl] The panel name - * @param {string} [obj.ptrn] Pattern for line "solid","dotted","dashed". Defaults to solid. - * @param {number} [obj.lw] Line width. Defaults to 1. - * @param {number} [obj.v0] Value (price) for the first point - * @param {number} [obj.v1] Value (price) for the second point - * @param {number} [obj.v2] Value (price) for the second point of the opposing parallel channel line - * @param {number} [obj.d0] Date (string form) for the first point - * @param {number} [obj.d1] Date (string form) for the second point - * @param {number} [obj.tzo0] Offset of UTC from d0 in minutes - * @param {number} [obj.tzo1] Offset of UTC from d1 in minutes - */ - CIQ.Drawing.channel.prototype.reconstruct = function (stx, obj) { - this.stx = stx; - this.color = obj.col; - this.fillColor = obj.fc; - this.panelName = obj.pnl; - this.pattern = obj.ptrn; - this.lineWidth = obj.lw; - this.d0 = obj.d0; - this.d1 = obj.d1; - this.tzo0 = obj.tzo0; - this.tzo1 = obj.tzo1; - this.v0 = obj.v0; - this.v1 = obj.v1; - this.v2 = obj.v2; - this.adjust(); - }; - - CIQ.Drawing.channel.prototype.serialize = function () { - return { - name: this.name, - pnl: this.panelName, - col: this.color, - fc: this.fillColor, - ptrn: this.pattern, - lw: this.lineWidth, - d0: this.d0, - d1: this.d1, - tzo0: this.tzo0, - tzo1: this.tzo1, - v0: this.v0, - v1: this.v1, - v2: this.v2 - }; - }; - - /** - * Andrews' Pitchfork drawing tool. A Pitchfork is defined by three parallel rays. The center ray is equidistant from the two outer rays. - * - * It inherits its properties from {@link CIQ.Drawing.channel}. - * @constructor - * @name CIQ.Drawing.pitchfork - * @version ChartIQ Advanced Package - */ - CIQ.Drawing.pitchfork = function () { - this.name = "pitchfork"; - this.dragToDraw = false; - this.p2 = null; - }; - - CIQ.inheritsFrom(CIQ.Drawing.pitchfork, CIQ.Drawing.channel); - - CIQ.Drawing.pitchfork.prototype.configs = ["color", "lineWidth", "pattern"]; - - CIQ.Drawing.pitchfork.prototype.move = function (context, tick, value) { - if (!this.penDown) return; - - this.copyConfig(); - if (this.p2 === null) this.p1 = [tick, value]; - else this.p2 = [tick, value]; - this.render(context); - }; - - CIQ.Drawing.pitchfork.prototype.intersected = function (tick, value, box) { - if (!this.p0 || !this.p1 || !this.p2) return null; // in case invalid drawing (such as from panel that no longer exists) - var pointsToCheck = { 0: this.p0, 1: this.p1, 2: this.p2 }; - for (var pt in pointsToCheck) { - if ( - this.pointIntersection(pointsToCheck[pt][0], pointsToCheck[pt][1], box) - ) { - this.highlighted = "p" + pt; - return { - action: "drag", - point: "p" + pt - }; - } - } - var rays = this.rays; - for (var i = 0; i < rays.length; i++) { - if ( - this.lineIntersection( - tick, - value, - box, - i ? "ray" : "segment", - rays[i][0], - rays[i][1], - true - ) - ) { - this.highlighted = true; - // This object will be used for repositioning - return { - action: "move", - p0: CIQ.clone(this.p0), - p1: CIQ.clone(this.p1), - p2: CIQ.clone(this.p2), - tick: tick, // save original tick - value: value // save original value - }; - } - } - return null; - }; - - CIQ.Drawing.pitchfork.prototype.render = function (context) { - var panel = this.stx.panels[this.panelName]; - if (!panel) return; - var stx = this.stx; - var p2 = this.p2; - if (!p2) p2 = this.p1; - var x0 = stx.pixelFromTick(this.p0[0], panel.chart); - var x1 = stx.pixelFromTick(this.p1[0], panel.chart); - var x2 = stx.pixelFromTick(p2[0], panel.chart); - var y0 = stx.pixelFromValueAdjusted(panel, this.p0[0], this.p0[1]); - var y1 = stx.pixelFromValueAdjusted(panel, this.p1[0], this.p1[1]); - var y2 = stx.pixelFromValueAdjusted(panel, p2[0], p2[1]); - - var width = this.lineWidth; - var color = this.getLineColor(); - - var parameters = { - pattern: this.pattern, - lineWidth: width - }; - var z = 50; - var yp = 2 * y0 - y1 - y2; - var denom = 2 * x0 - x1 - x2; - if (denom < 0) z *= -1; - yp *= z / denom; - this.rays = [ - [ - [x1, y1], - [x2, y2] - ], - [ - [x0, y0], - [(x1 + x2) / 2, (y1 + y2) / 2] - ] - ]; - if (!(x1 == x2 && y1 == y2)) { - this.rays.push( - [ - [x1, y1], - [x1 - z, y1 - yp] - ], - [ - [x2, y2], - [x2 - z, y2 - yp] - ] - ); - } - for (var i = 0; i < this.rays.length; i++) { - var ray = this.rays[i], - type = i ? "ray" : "segment"; - stx.plotLine( - ray[0][0], - ray[1][0], - ray[0][1], - ray[1][1], - color, - type, - context, - panel, - parameters - ); - } - if (this.highlighted) { - var p0Fill = this.highlighted == "p0" ? true : false; - var p1Fill = this.highlighted == "p1" ? true : false; - var p2Fill = this.highlighted == "p2" ? true : false; - this.littleCircle(context, x0, y0, p0Fill); - this.littleCircle(context, x1, y1, p1Fill); - this.littleCircle(context, x2, y2, p2Fill); - } - }; - - CIQ.Drawing.pitchfork.prototype.adjust = function () { - var panel = this.stx.panels[this.panelName]; - if (!panel) return; - this.setPoint(0, this.d0, this.v0, panel.chart); - this.setPoint(1, this.d1, this.v1, panel.chart); - this.setPoint(2, this.d2, this.v2, panel.chart); - }; - - /** - * Reconstruct a pitchfork - * @memberOf CIQ.Drawing.pitchfork - * @param {CIQ.ChartEngine} stx The chart object - * @param {object} [obj] A drawing descriptor - * @param {string} [obj.col] The line color - * @param {string} [obj.pnl] The panel name - * @param {string} [obj.ptrn] Pattern for line "solid","dotted","dashed". Defaults to solid. - * @param {number} [obj.lw] Line width. Defaults to 1. - * @param {number} [obj.v0] Value (price) for the first point - * @param {number} [obj.v1] Value (price) for the second point - * @param {number} [obj.v2] Value (price) for the third point - * @param {number} [obj.d0] Date (string form) for the first point - * @param {number} [obj.d1] Date (string form) for the second point - * @param {number} [obj.d2] Date (string form) for the third point - * @param {number} [obj.tzo0] Offset of UTC from d0 in minutes - * @param {number} [obj.tzo1] Offset of UTC from d1 in minutes - * @param {number} [obj.tzo2] Offset of UTC from d2 in minutes - */ - CIQ.Drawing.pitchfork.prototype.reconstruct = function (stx, obj) { - this.stx = stx; - this.color = obj.col; - this.panelName = obj.pnl; - this.pattern = obj.ptrn; - this.lineWidth = obj.lw; - this.d0 = obj.d0; - this.d1 = obj.d1; - this.d2 = obj.d2; - this.tzo0 = obj.tzo0; - this.tzo1 = obj.tzo1; - this.tzo2 = obj.tzo2; - this.v0 = obj.v0; - this.v1 = obj.v1; - this.v2 = obj.v2; - this.adjust(); - }; - - CIQ.Drawing.pitchfork.prototype.serialize = function () { - return { - name: this.name, - pnl: this.panelName, - col: this.color, - ptrn: this.pattern, - lw: this.lineWidth, - d0: this.d0, - d1: this.d1, - d2: this.d2, - tzo0: this.tzo0, - tzo1: this.tzo1, - tzo2: this.tzo2, - v0: this.v0, - v1: this.v1, - v2: this.v2 - }; - }; - - /** - * Gartley drawing tool. Creates a series of four connected line segments, each one completed with a user click. - * Will adhere to Gartley requirements vis-a-vis fibonacci levels etc.. - * - * It inherits its properties from {@link CIQ.Drawing.continuous}. - * @constructor - * @name CIQ.Drawing.gartley - * @version ChartIQ Advanced Package - * @since 04-2015-15 - */ - CIQ.Drawing.gartley = function () { - this.name = "gartley"; - this.dragToDraw = false; - this.maxSegments = 4; - this.shape = null; - this.points = []; - }; - - CIQ.inheritsFrom(CIQ.Drawing.gartley, CIQ.Drawing.continuous); - - CIQ.Drawing.gartley.prototype.check = function (first, second) { - if (!second) return true; - if (first[0] >= second[0] || first[1] == second[1]) return false; - if (this.segment == 1) { - if (first[1] < second[1]) this.shape = "M"; - else this.shape = "W"; - } else if (this.segment == 2) { - if (this.shape == "M" && first[1] < second[1]) return false; - else if (this.shape == "W" && first[1] > second[1]) return false; - else if ((second[1] - first[1]) / (this.points[0][1] - first[1]) < 0.618) - return false; - else if ((second[1] - first[1]) / (this.points[0][1] - first[1]) >= 0.786) - return false; - } else if (this.segment == 3) { - if (this.shape == "M" && first[1] > second[1]) return false; - else if (this.shape == "W" && first[1] < second[1]) return false; - else if ((second[1] - first[1]) / (this.points[1][1] - first[1]) < 0.618) - return false; - else if ((second[1] - first[1]) / (this.points[1][1] - first[1]) >= 0.786) - return false; - } else if (this.segment == 4) { - if ( - this.shape == "M" && - (first[1] < second[1] || second[1] < this.points[0][1]) - ) - return false; - else if ( - this.shape == "W" && - (first[1] > second[1] || second[1] > this.points[0][1]) - ) - return false; - else if ( - (this.points[1][1] - second[1]) / - (this.points[1][1] - this.points[2][1]) < - 1.27 - ) - return false; - else if ( - (this.points[1][1] - second[1]) / - (this.points[1][1] - this.points[2][1]) >= - 1.618 - ) - return false; - } - return true; - }; - - CIQ.Drawing.gartley.prototype.click = function (context, tick, value) { - var panel = this.stx.panels[this.panelName]; - if (!panel) return; - this.copyConfig(); - if (!this.penDown) { - this.setPoint(0, tick, value, panel.chart); - this.pts = []; - this.penDown = true; - this.segment = 1; - return false; - } - if (this.accidentalClick(tick, value)) { - this.penDown = true; - return false; - } - if (this.check(this.p0, this.p1)) { - if (this.segment == 1) this.points.push(this.p0); - this.points.push(this.p1); - this.setPoint(1, tick, value, panel.chart); - this.segment++; - - if (this.segment > this.maxSegments) { - this.setPoint(0, this.points[0][0], this.points[0][1], panel.chart); - this.penDown = false; - return true; - } - this.pts.push(this.d1, this.tzo1, this.v1); - this.setPoint(0, tick, value, panel.chart); // reset initial point for next segment, copy by value - } - return false; - }; - - CIQ.Drawing.gartley.prototype.render = function (context) { - var panel = this.stx.panels[this.panelName]; - if (!panel) return; - var x0 = this.stx.pixelFromTick(this.p0[0], panel.chart); - var x1 = this.stx.pixelFromTick(this.p1[0], panel.chart); - var y0 = this.stx.pixelFromValueAdjusted(panel, this.p0[0], this.p0[1]); - var y1 = this.stx.pixelFromValueAdjusted(panel, this.p1[0], this.p1[1]); - - if (this.segment == 2) { - this.drawDropZone( - context, - 0.618 * this.points[0][1] + 0.382 * this.p0[1], - 0.786 * this.points[0][1] + 0.214 * this.p0[1], - this.p0[0] - ); - } else if (this.segment == 3) { - this.drawDropZone( - context, - 0.618 * this.points[1][1] + 0.382 * this.p0[1], - 0.786 * this.points[1][1] + 0.214 * this.p0[1], - this.p0[0] - ); - } else if (this.segment == 4) { - var bound = 1.618 * this.points[2][1] - 0.618 * this.points[1][1]; - if (this.shape == "M") bound = Math.max(bound, this.points[0][1]); - else bound = Math.min(bound, this.points[0][1]); - this.drawDropZone( - context, - bound, - 1.27 * this.points[2][1] - 0.27 * this.points[1][1], - this.p0[0] - ); - } - - var width = this.lineWidth; - var color = this.getLineColor(); - - var parameters = { - pattern: this.pattern, - lineWidth: width - }; - if ((this.penDown || this.highlighted) && this.pattern == "none") - parameters.pattern = "dotted"; - if (this.segment <= this.maxSegments) - this.stx.plotLine( - x0, - x1, - y0, - y1, - color, - this.name, - context, - panel, - parameters - ); - - var fillColor = this.fillColor; - var coords = []; - if (this.points.length) { - context.beginPath(); - for (var fp = 1; fp < this.points.length && fp <= 4; fp++) { - var xx0 = this.stx.pixelFromTick(this.points[fp - 1][0], panel.chart); - var xx1 = this.stx.pixelFromTick(this.points[fp][0], panel.chart); - var yy0 = this.stx.pixelFromValueAdjusted( - panel, - this.points[fp - 1][0], - this.points[fp - 1][1] - ); - var yy1 = this.stx.pixelFromValueAdjusted( - panel, - this.points[fp][0], - this.points[fp][1] - ); - if (fp == 1) coords.push(xx0, yy0); - coords.push(xx1, yy1); - this.stx.plotLine( - xx0, - xx1, - yy0, - yy1, - color, - this.name, - context, - panel, - parameters - ); - } - if (this.points.length == 2 || this.points.length == 4) { - coords.push(x1, y1); - } - if (this.points[2]) { - coords.push( - this.stx.pixelFromTick(this.points[2][0], panel.chart), - this.stx.pixelFromValueAdjusted( - panel, - this.points[2][0], - this.points[2][1] - ) - ); - } - if (fillColor && fillColor != "auto" && !CIQ.isTransparent(fillColor)) { - for (var c = 0; c < coords.length; c += 2) { - if (c === 0) context.moveTo(coords[0], coords[1]); - context.lineTo(coords[c], coords[c + 1]); - } - context.fillStyle = fillColor; - context.globalAlpha = 0.2; - context.closePath(); - context.fill(); - context.globalAlpha = 1; - } - } - - /*if(this.highlighted){ - var p0Fill=this.highlighted=="p0"?true:false; - var p1Fill=this.highlighted=="p1"?true:false; - this.littleCircle(context, x0, y0, p0Fill); - this.littleCircle(context, x1, y1, p1Fill); - }*/ - }; - - CIQ.Drawing.gartley.prototype.lineIntersection = function ( - tick, - value, - box, - type - ) { - var points = this.points, - panel = this.stx.panels[this.panelName]; - if (points.length != this.maxSegments + 1 || !panel) return false; - for (var pt = 0; pt < points.length - 1; pt++) { - if ( - CIQ.Drawing.BaseTwoPoint.prototype.lineIntersection.call( - this, - tick, - value, - box, - "segment", - points[pt], - points[pt + 1] - ) - ) - return true; - } - return false; - }; - - CIQ.Drawing.gartley.prototype.boxIntersection = function (tick, value, box) { - if (!this.p0 || !this.p1) return false; - if ( - box.x0 > Math.max(this.p0[0], this.p1[0]) || - box.x1 < Math.min(this.p0[0], this.p1[0]) - ) - return false; - var lowPoint = Math.min(this.p0[1], this.p1[1]); - var highPoint = Math.max(this.p0[1], this.p1[1]); - for (var pt = 0; pt < this.points.length; pt++) { - lowPoint = Math.min(lowPoint, this.points[pt][1]); - highPoint = Math.max(highPoint, this.points[pt][1]); - } - if (box.y1 > highPoint || box.y0 < lowPoint) return false; - return true; - }; - - CIQ.Drawing.gartley.prototype.reposition = function ( - context, - repositioner, - tick, - value - ) { - if (!repositioner) return; - var panel = this.stx.panels[this.panelName]; - var tickDiff = repositioner.tick - tick; - repositioner.tick = tick; - var valueDiff = repositioner.value - value; - repositioner.value = value; - if (repositioner.action == "move") { - this.pts = []; - for (var pt = 0; pt < this.points.length; pt++) { - this.points[pt][0] -= tickDiff; - this.points[pt][1] -= valueDiff; - this.setPoint(1, this.points[pt][0], this.points[pt][1], panel.chart); - if (pt && pt < this.points.length - 1) - this.pts.push(this.d1, this.tzo1, this.v1); - this.points[pt] = this.p1; - } - this.setPoint(0, this.points[0][0], this.points[0][1], panel.chart); - this.render(context); - /*}else if(repositioner.action=="drag"){ - this[repositioner.point]=[tick, value]; - this.setPoint(0, this.p0[0], this.p0[1], panel.chart); - this.setPoint(1, this.p1[0], this.p1[1], panel.chart); - this.render(context);*/ - } - }; - - CIQ.Drawing.gartley.prototype.configs = [ - "color", - "fillColor", - "lineWidth", - "pattern" - ]; - - CIQ.Drawing.gartley.prototype.adjust = function () { - // If the drawing's panel doesn't exist then we'll check to see - // whether the panel has been added. If not then there's no way to adjust - var panel = this.stx.panels[this.panelName]; - if (!panel) return; - this.reconstructPoints(); - - this.setPoint(0, this.d0, this.v0, panel.chart); - this.points.unshift(this.p0); - - this.setPoint(1, this.d1, this.v1, panel.chart); - this.points.push(this.p1); - }; - - CIQ.Drawing.gartley.prototype.reconstructPoints = function () { - var panel = this.stx.panels[this.panelName]; - if (!panel) return; - this.points = []; - for (var a = 0; a < this.pts.length; a += 3) { - var d = CIQ.strToDateTime(this.pts[a]); - d.setMinutes( - d.getMinutes() + Number(this.pts[a + 1]) - d.getTimezoneOffset() - ); - this.points.push([ - this.stx.tickFromDate(CIQ.yyyymmddhhmmssmmm(d), panel.chart), - this.pts[a + 2] - ]); - } - }; - - /** - * Reconstruct a gartley - * @memberOf CIQ.Drawing.gartley - * @param {CIQ.ChartEngine} stx The chart object - * @param {object} [obj] A drawing descriptor - * @param {string} [obj.col] The line color - * @param {string} [obj.fc] The fill color - * @param {string} [obj.pnl] The panel name - * @param {string} [obj.ptrn] Pattern for line "solid","dotted","dashed". Defaults to solid. - * @param {number} [obj.lw] Line width. Defaults to 1. - * @param {number} [obj.v0] Value (price) for the first point - * @param {number} [obj.v1] Value (price) for the last point - * @param {number} [obj.d0] Date (string form) for the first point - * @param {number} [obj.d1] Date (string form) for the last point - * @param {number} [obj.tzo0] Offset of UTC from d0 in minutes - * @param {number} [obj.tzo1] Offset of UTC from d1 in minutes - * @param {number} [obj.pts] a serialized list of dates,offsets,values for the 3 intermediate points of the gartley (should be 9 items in list) - */ - CIQ.Drawing.gartley.prototype.reconstruct = function (stx, obj) { - this.stx = stx; - this.color = obj.col; - this.fillColor = obj.fc; - this.panelName = obj.pnl; - this.pattern = obj.ptrn; - this.lineWidth = obj.lw; - this.d0 = obj.d0; - this.d1 = obj.d1; - this.tzo0 = obj.tzo0; - this.tzo1 = obj.tzo1; - this.v0 = obj.v0; - this.v1 = obj.v1; - this.pts = obj.pts.split(","); - this.adjust(); - }; - - CIQ.Drawing.gartley.prototype.serialize = function () { - return { - name: this.name, - pnl: this.panelName, - col: this.color, - fc: this.fillColor, - ptrn: this.pattern, - lw: this.lineWidth, - d0: this.d0, - d1: this.d1, - tzo0: this.tzo0, - tzo1: this.tzo1, - v0: this.v0, - v1: this.v1, - pts: this.pts.join(",") - }; - }; - - /** - * Freeform drawing tool. Set splineTension to a value from 0 to 1 (default .3). This is a dragToDraw function - * and automatically disables the crosshairs while enabled. - * - * It inherits its properties from {@link CIQ.Drawing.segment}. - * @constructor - * @name CIQ.Drawing.freeform - * @version ChartIQ Advanced Package - */ - CIQ.Drawing.freeform = function () { - this.name = "freeform"; - this.splineTension = 0.3; //set to -1 to not use splines at all - this.dragToDraw = true; - }; - - CIQ.inheritsFrom(CIQ.Drawing.freeform, CIQ.Drawing.segment); - - CIQ.Drawing.freeform.prototype.measure = function () {}; - - CIQ.Drawing.freeform.prototype.intersected = function (tick, value, box) { - if (box.x0 > this.hiX || box.x1 < this.lowX) return null; - if (box.y1 > this.hiY || box.y0 < this.lowY) return null; - this.highlighted = true; - // This object will be used for repositioning - return { - action: "move", - p0: CIQ.clone(this.p0), - tick: tick, // save original tick - value: value // save original value - }; - }; - - CIQ.Drawing.freeform.prototype.reposition = function ( - context, - repositioner, - tick, - value - ) { - if (!repositioner) return; - var panel = this.stx.panels[this.panelName]; - var tickDiff = repositioner.tick - tick; - var valueDiff = repositioner.value - value; - if (repositioner.action == "move") { - this.setPoint( - 0, - repositioner.p0[0] - tickDiff, - repositioner.p0[1] - valueDiff, - panel.chart - ); - this.adjust(); - this.render(context); - } - }; - - CIQ.Drawing.freeform.prototype.click = function (context, tick, value) { - var panel = this.stx.panels[this.panelName]; - if (!panel) return; - - if (this.penDown === false) { - this.copyConfig(); - this.startX = Math.round( - this.stx.resolveX(this.stx.pixelFromTick(tick, panel.chart)) - ); - this.startY = Math.round( - this.stx.resolveY(this.stx.pixelFromValueAdjusted(panel, tick, value)) - ); - var d = this.stx.dateFromTick(tick, panel.chart, true); - this.d0 = CIQ.yyyymmddhhmmssmmm(d); - this.tzo0 = d.getTimezoneOffset(); - this.v0 = value; - this.p0 = [ - CIQ.ChartEngine.crosshairX - this.startX, - CIQ.ChartEngine.crosshairY - this.startY - ]; - this.nodes = [this.p0[0], this.p0[1]]; - this.pNodes = [this.p0]; - this.candleWidth = this.stx.layout.candleWidth; - this.multiplier = panel.yAxis.multiplier; - this.interval = this.stx.layout.interval; - this.periodicity = this.stx.layout.periodicity; - this.tempSplineTension = this.splineTension; - this.splineTension = -1; - document.body.style.cursor = "pointer"; - this.penDown = true; - return false; - } - this.penDown = false; - this.splineTension = this.tempSplineTension; - document.body.style.cursor = "auto"; - return true; - }; - - CIQ.Drawing.freeform.prototype.move = function (context, tick, value) { - if (!this.penDown) return; - - var panel = this.stx.panels[this.panelName]; - var d1 = this.stx.dateFromTick(tick, panel.chart, true); - this.d1 = CIQ.yyyymmddhhmmssmmm(d1); - this.tzo1 = d1.getTimezoneOffset(); - this.v1 = value; - this.p1 = [ - CIQ.ChartEngine.crosshairX - this.startX, - panel.yAxis.flipped - ? this.startY - CIQ.ChartEngine.crosshairY - : CIQ.ChartEngine.crosshairY - this.startY - ]; - - if (this.pNodes.length > 2) { - if ( - this.p1[0] == this.pNodes[this.pNodes.length - 2][0] && - this.p1[0] == this.pNodes[this.pNodes.length - 1][0] - ) { - this.pNodes.length--; - this.nodes.length -= 2; - } else if ( - this.p1[1] == this.pNodes[this.pNodes.length - 2][1] && - this.p1[1] == this.pNodes[this.pNodes.length - 1][1] - ) { - this.pNodes.length--; - this.nodes.length -= 2; - } - } - - this.nodes.push(this.p1[0], this.p1[1]); - this.pNodes.push(this.p1); - - this.render(context); - return false; - }; - - //This function does not compute exactly, it uses rough ratios to resize the drawing based on the interval. - CIQ.Drawing.freeform.prototype.intervalRatio = function ( - oldInterval, - newInterval, - oldPeriodicity, - newPeriodicity, - startDate, - symbol - ) { - //approximating functions - function weeksInMonth(startDate, symbol) { - return 5; - } - function daysInWeek(startDate, symbol) { - return 5; - } - function daysInMonth(startDate, symbol) { - return 30; - } - function minPerDay(startDate, symbol) { - if (CIQ.Market.Symbology.isForexSymbol(symbol)) return 1440; - return 390; - } - //1,3,5,10,15,30,"day","week","month" - var returnValue = 0; - if (oldInterval == newInterval) returnValue = 1; - else if (!isNaN(oldInterval) && !isNaN(newInterval)) - returnValue = oldInterval / newInterval; - //two intraday intervals - else if (isNaN(oldInterval)) { - //was daily - if (oldInterval == "month") { - if (newInterval == "week") - returnValue = weeksInMonth(startDate, symbol); - else if (newInterval == "day") - returnValue = daysInMonth(startDate, symbol); - else if (!isNaN(newInterval)) - returnValue = - (daysInMonth(startDate, symbol) * minPerDay(startDate, symbol)) / - newInterval; - } else if (oldInterval == "week") { - if (newInterval == "month") - returnValue = 1 / weeksInMonth(startDate, symbol); - if (newInterval == "day") returnValue = daysInWeek(startDate, symbol); - else if (!isNaN(newInterval)) - returnValue = - (daysInWeek(startDate, symbol) * minPerDay(startDate, symbol)) / - newInterval; - } else if (oldInterval == "day") { - if (newInterval == "week") - returnValue = 1 / daysInWeek(startDate, symbol); - else if (newInterval == "month") - returnValue = 1 / daysInMonth(startDate, symbol); - else if (!isNaN(newInterval)) - returnValue = minPerDay(startDate, symbol) / newInterval; - } - } else if (!isNaN(oldInterval)) { - //switching from intraday to daily - if (newInterval == "month") - returnValue = - oldInterval / - (daysInMonth(startDate, symbol) * minPerDay(startDate, symbol)); - else if (newInterval == "week") - returnValue = - oldInterval / - (daysInWeek(startDate, symbol) * minPerDay(startDate, symbol)); - else if (newInterval == "day") - returnValue = oldInterval / minPerDay(startDate, symbol); - } - returnValue *= oldPeriodicity / newPeriodicity; - return returnValue; - }; - - CIQ.Drawing.freeform.prototype.render = function (context) { - var panel = this.stx.panels[this.panelName]; - if (!panel) return; - - var intvl = this.intervalRatio( - this.interval, - this.stx.layout.interval, - this.periodicity, - this.stx.layout.periodicity, - this.d0, - panel.chart.symbol - ); - if (intvl === 0) return; - - var cwr = this.stx.layout.candleWidth / this.candleWidth; - var mlt = panel.yAxis.multiplier / this.multiplier; - this.setPoint(0, this.d0, this.v0, panel.chart); - var spx = this.stx.pixelFromTick(this.p0[0], panel.chart); - var spy = this.stx.pixelFromValueAdjusted(panel, this.p0[0], this.p0[1]); - var arrPoints = []; - - var width = this.lineWidth; - var color = this.getLineColor(); - - var parameters = { - pattern: this.pattern, - lineWidth: width - }; - - for (var n = 0; n < this.pNodes.length; n++) { - var x0 = intvl * cwr * this.pNodes[n][0] + spx; - var y0 = mlt * this.pNodes[n][1]; - if (panel.yAxis.flipped) y0 = spy - y0; - else y0 += spy; - arrPoints.push(x0, y0); - } - - if (!arrPoints.length) return; - if (this.splineTension < 0) { - this.stx.connectTheDots( - arrPoints, - color, - this.name, - context, - panel, - parameters - ); - } else { - this.stx.plotSpline( - arrPoints, - this.splineTension, - color, - this.name, - context, - true, - parameters - ); - } - }; - - CIQ.Drawing.freeform.prototype.adjust = function () { - // If the drawing's panel doesn't exist then we'll check to see - // whether the panel has been added. If not then there's no way to adjust - var panel = this.stx.panels[this.panelName]; - if (!panel) return; - - var p0 = [this.nodes[0], this.nodes[1]]; - this.pNodes = [p0]; - this.lowX = this.nodes[0]; - this.hiX = this.nodes[0]; - this.lowY = this.nodes[1]; - this.hiY = this.nodes[1]; - - for (var n = 2; n < this.nodes.length; n += 2) { - var p1 = [this.nodes[n], this.nodes[n + 1]]; - this.pNodes.push(p1); - this.lowX = Math.min(this.lowX, p1[0]); - this.hiX = Math.max(this.hiX, p1[0]); - this.lowY = Math.max(this.lowY, p1[1]); //reversed because price axis goes bottom to top - this.hiY = Math.min(this.hiY, p1[1]); - } - - var intvl = this.intervalRatio( - this.interval, - this.stx.layout.interval, - this.periodicity, - this.stx.layout.periodicity, - this.d0, - panel.chart.symbol - ); - if (intvl === 0) return; - - var cwr = this.stx.layout.candleWidth / this.candleWidth; - var mlt = panel.yAxis.multiplier / this.multiplier; - this.setPoint(0, this.d0, this.v0, panel.chart); - var spx = this.stx.pixelFromTick(this.p0[0], panel.chart); - var spy = this.stx.pixelFromValueAdjusted(panel, this.p0[0], this.p0[1]); - - this.lowX = this.stx.tickFromPixel( - Math.floor(intvl * cwr * this.lowX) + spx, - panel.chart - ); - this.hiX = this.stx.tickFromPixel( - Math.ceil(intvl * cwr * this.hiX) + spx, - panel.chart - ); - if (panel.yAxis.flipped) { - this.lowY = this.stx.valueFromPixel( - spy - Math.floor(mlt * this.lowY), - panel - ); - this.hiY = this.stx.valueFromPixel( - spy - Math.ceil(mlt * this.hiY), - panel - ); - } else { - this.lowY = this.stx.valueFromPixel( - Math.floor(mlt * this.lowY) + spy, - panel - ); - this.hiY = this.stx.valueFromPixel( - Math.ceil(mlt * this.hiY) + spy, - panel - ); - } - }; - - CIQ.Drawing.freeform.prototype.serialize = function () { - return { - name: this.name, - pnl: this.panelName, - col: this.color, - ptrn: this.pattern, - lw: this.lineWidth, - cw: Number(this.candleWidth.toFixed(4)), - mlt: Number(this.multiplier.toFixed(4)), - d0: this.d0, - tzo0: this.tzo0, - v0: this.v0, - inter: this.interval, - pd: this.periodicity, - nodes: this.nodes - }; - }; - - /** - * Reconstruct a freeform drawing. It is not recommended to do this programmatically. - * @param {CIQ.ChartEngine} stx The chart object - * @param {object} [obj] A drawing descriptor - * @param {string} [obj.col] The line color - * @param {string} [obj.pnl] The panel name - * @param {string} [obj.ptrn] Pattern for line "solid","dotted","dashed". Defaults to solid. - * @param {number} [obj.lw] Line width. Defaults to 1. - * @param {number} [obj.cw] Candle width from original drawing - * @param {number} [obj.mlt] Y-axis multiplier from original drawing - * @param {number} [obj.v0] Value (price) for the first point - * @param {number} [obj.d0] Date (string form) for the first point - * @param {number} [obj.int] Interval from original drawing - * @param {number} [obj.pd] Periodicity from original drawing - * @param {number} [obj.tzo0] Offset of UTC from d0 in minutes - * @param {array} [obj.nodes] An array of nodes in form [x0a,x0b,y0a,y0b, x1a, x1b, y1a, y1b, ....] - * @memberOf CIQ.Drawing.freeform - */ - CIQ.Drawing.freeform.prototype.reconstruct = function (stx, obj) { - this.stx = stx; - this.color = obj.col; - this.panelName = obj.pnl; - this.pattern = obj.ptrn; - this.lineWidth = obj.lw; - this.candleWidth = obj.cw; - this.multiplier = obj.mlt; - this.d0 = obj.d0; - this.tzo0 = obj.tzo0; - this.v0 = obj.v0; - this.interval = obj.inter; - this.periodicity = obj.pd; - this.nodes = obj.nodes; - this.adjust(); - }; - - /** - * Callout drawing tool. This is like an annotation except it draws a stem and offers a background color and line style. - * - * @constructor - * @name CIQ.Drawing.callout - * @since 2015-11-1 - * @version ChartIQ Advanced Package - * @see {@link CIQ.Drawing.annotation} - */ - CIQ.Drawing.callout = function () { - this.name = "callout"; - this.arr = []; - this.w = 0; - this.h = 0; - this.padding = 4; - this.text = ""; - this.ta = null; - this.fontSize = 0; - this.font = {}; - this.stemEntry = ""; - this.defaultWidth = 50; - this.defaultHeight = 10; - //this.dragToDraw=true; - }; - - CIQ.inheritsFrom(CIQ.Drawing.callout, CIQ.Drawing.annotation); - - CIQ.Drawing.callout.prototype.configs = [ - "color", - "fillColor", - "lineWidth", - "pattern", - "font" - ]; - - CIQ.Drawing.callout.prototype.copyConfig = function (withPreferences) { - CIQ.Drawing.copyConfig(this, withPreferences); - this.borderColor = this.color; - }; - - CIQ.Drawing.callout.prototype.move = function (context, tick, value) { - if (!this.penDown) return; - - this.copyConfig(); - this.p0 = [tick, value]; - this.render(context); - }; - - CIQ.Drawing.callout.prototype.onChange = function (e) { - var panel = this.stx.panels[this.panelName]; - if (!panel) return; - var textarea = e.target; - this.w = textarea.clientWidth; - this.h = textarea.clientHeight; - //textarea.style.left=(this.stx.pixelFromTick(this.p0[0])-this.w/2) + "px"; - //textarea.style.top=(this.stx.pixelFromPrice(this.p0[1],panel)-this.h/2) + "px"; - var context = this.context || this.stx.chart.tempCanvas.context; - CIQ.clearCanvas(context.canvas, this.stx); - this.render(context); - this.edit(context); - }; - - CIQ.Drawing.callout.prototype.render = function (context) { - this.context = context; // remember last context - var panel = this.stx.panels[this.panelName]; - if (!panel) return; - var x0 = this.stx.pixelFromTick(this.p0[0], panel.chart); - var y0 = this.stx.pixelFromValueAdjusted(panel, this.p0[0], this.p0[1]); - if (isNaN(y0)) return; - - context.font = this.fontString; - context.textBaseline = "top"; - var x = x0; - var y = y0; - var w = this.w / 2; - var h = this.h / 2; - if (this.penDown) { - w = this.defaultWidth; - h = this.defaultHeight; - if (!h) h = this.fontSize; - } - var lineWidth = this.lineWidth; - if (!lineWidth) lineWidth = 1.1; - var color = this.color; - if (color == "auto" || CIQ.isTransparent(color)) - color = this.stx.defaultColor; - var borderColor = this.borderColor; - if (borderColor == "auto" || CIQ.isTransparent(borderColor)) - borderColor = this.stx.defaultColor; - if (this.highlighted) - borderColor = this.stx.getCanvasColor("stx_highlight_vector"); - var sx0, sx1, sy0, sy1; - var r = Math.min(Math.min(w, h) / 2, 8); - if (this.stem) { - if (this.stem.t) { - // absolute positioning of stem - sx0 = this.stx.pixelFromTick(this.stem.t); // bottom of stem - sy0 = this.stx.pixelFromValueAdjusted(panel, this.stem.t, this.stem.v); - } else if (this.stem.x) { - // stem with relative offset positioning - sx0 = x; - sy0 = y; - x += this.stem.x; - y += this.stem.y; - } - - var state = ""; - if (sx0 >= x + w) { - sx1 = x + w; - state = "r"; - } // right of text - else if (sx0 > x - w && sx0 < x + w) { - sx1 = x; - state = "c"; - } // center of text - else if (sx0 <= x - w) { - sx1 = x - w; - state = "l"; - } // left of text - - if (sy0 >= y + h) { - sy1 = y + h; - state += "b"; - } // bottom of text - else if (sy0 > y - h && sy0 < y + h) { - sy1 = y; - state += "m"; - } // middle of text - else if (sy0 <= y - h) { - sy1 = y - h; - state += "t"; - } // top of text - - this.stemEntry = state; - - if (state != "cm") { - // make sure stem does not originate underneath the annotation - sx0 = Math.round(sx0); - sx1 = Math.round(sx1); - sy0 = Math.round(sy0); - sy1 = Math.round(sy1); - } - } - if (this.highlighted) { - this.stx.canvasColor("stx_annotation_highlight_bg", context); - } else { - if (this.fillColor) { - context.fillStyle = this.fillColor; - context.globalAlpha = 0.4; - } else if (this.stem) { - // If there's a stem then use the container color otherwise the stem will show through - context.fillStyle = this.stx.containerColor; - } - } - context.strokeStyle = borderColor; - if (context.setLineDash) { - context.setLineDash(CIQ.borderPatternToArray(lineWidth, this.pattern)); - context.lineDashOffset = 0; //start point in array - } - - if (borderColor) { - context.beginPath(); - context.lineWidth = lineWidth; - context.moveTo(x + w - r, y - h); - if (this.stemEntry != "rt") { - context.quadraticCurveTo(x + w, y - h, x + w, y - h + r); //top right - } else { - context.lineTo(sx0, sy0); - context.lineTo(x + w, y - h + r); - } - context.lineTo(x + w, y - r / 2); - if (this.stemEntry == "rm") context.lineTo(sx0, sy0); - context.lineTo(x + w, y + r / 2); - context.lineTo(x + w, y + h - r); - if (this.stemEntry != "rb") { - context.quadraticCurveTo(x + w, y + h, x + w - r, y + h); //bottom right - } else { - context.lineTo(sx0, sy0); - context.lineTo(x + w - r, y + h); - } - context.lineTo(x + r / 2, y + h); - if (this.stemEntry == "cb") context.lineTo(sx0, sy0); - context.lineTo(x - r / 2, y + h); - context.lineTo(x - w + r, y + h); - if (this.stemEntry != "lb") { - context.quadraticCurveTo(x - w, y + h, x - w, y + h - r); //bottom left - } else { - context.lineTo(sx0, sy0); - context.lineTo(x - w, y + h - r); - } - context.lineTo(x - w, y + r / 2); - if (this.stemEntry == "lm") context.lineTo(sx0, sy0); - context.lineTo(x - w, y - r / 2); - context.lineTo(x - w, y - h + r); - if (this.stemEntry != "lt") { - context.quadraticCurveTo(x - w, y - h, x - w + r, y - h); //top left - } else { - context.lineTo(sx0, sy0); - context.lineTo(x - w + r, y - h); - } - context.lineTo(x - r / 2, y - h); - if (this.stemEntry == "ct") context.lineTo(sx0, sy0); - context.lineTo(x + r / 2, y - h); - context.lineTo(x + w - r, y - h); - context.fill(); - context.globalAlpha = 1; - if (this.pattern != "none") context.stroke(); - } - if (this.highlighted) { - this.stx.canvasColor("stx_annotation_highlight", context); - } else { - context.fillStyle = color; - } - y += this.padding; - if (!this.ta) { - for (var i = 0; i < this.arr.length; i++) { - context.fillText(this.arr[i], x - w + this.padding, y - h); - y += this.fontSize; - } - } - context.textBaseline = "alphabetic"; - - if (this.highlighted && !this.noHandles) { - var p0Fill = this.highlighted == "p0" ? true : false; - this.littleCircle(context, sx0, sy0, p0Fill); - } - /*if(this.penDown){ - context.globalAlpha=0.2; - context.fillText("[Your text here]", x-w+this.padding, y-h); - context.globalAlpha=1; - }*/ - }; - - CIQ.Drawing.callout.prototype.click = function (context, tick, value) { - //don't allow user to add callout on the axis. - if (this.stx.overXAxis || this.stx.overYAxis) return; - var panel = this.stx.panels[this.panelName]; - this.copyConfig(); - //this.getFontString(); - this.setPoint(0, tick, value, panel.chart); - if (!this.penDown) { - this.stem = { - d: this.d0, - v: this.v0 - }; - this.penDown = true; - this.adjust(); - return false; - } - this.adjust(); - this.edit(context); - this.penDown = false; - return false; - }; - - CIQ.Drawing.callout.prototype.reposition = function ( - context, - repositioner, - tick, - value - ) { - if (!repositioner) return; - var panel = this.stx.panels[this.panelName]; - var tickDiff = repositioner.tick - tick; - var valueDiff = repositioner.value - value; - if (repositioner.stem) { - if (repositioner.action == "drag") { - this.stem = { - d: this.stx.dateFromTick(tick, panel.chart, true), - v: value - }; - } else if (repositioner.action == "move") { - this.setPoint( - 0, - repositioner.p0[0] - tickDiff, - repositioner.p0[1] - valueDiff, - panel.chart - ); - this.stem = { - d: this.stx.dateFromTick( - this.stx.tickFromDate(repositioner.stem.d, panel.chart) - tickDiff - ), - v: repositioner.stem.v - valueDiff - }; - } - this.adjust(); - } else { - this.setPoint( - 0, - repositioner.p0[0] - tickDiff, - repositioner.p0[1] - valueDiff, - panel.chart - ); - } - this.render(context); - }; - - CIQ.Drawing.callout.prototype.lineIntersection = function ( - tick, - value, - box, - type - ) { - var panel = this.stx.panels[this.panelName]; - var stem = this.stem, - p0 = this.p0, - stx = this.stx; - if (!p0 || !stem || !panel) return false; - var stemTick = stem.t || this.stx.tickFromDate(stem.d, panel.chart); - var pObj = { x0: p0[0], x1: stemTick, y0: p0[1], y1: stem.v }; - var pixelPoint = CIQ.convertBoxToPixels(stx, this.panelName, pObj); - var x0 = pixelPoint.x0; - var y0 = pixelPoint.y0; - var x1 = pixelPoint.x1; - var y1 = pixelPoint.y1; - if (typeof this.stemEntry == "string") { - if (this.stemEntry.indexOf("l") > -1) x0 -= this.w / 2; - else if (this.stemEntry.indexOf("r") > -1) x0 += this.w / 2; - if (this.stemEntry.indexOf("t") > -1) y0 -= this.h / 2; - else if (this.stemEntry.indexOf("b") > -1) y0 += this.h / 2; - } - var pixelBox = CIQ.convertBoxToPixels(stx, this.panelName, box); - return CIQ.boxIntersects( - pixelBox.x0, - pixelBox.y0, - pixelBox.x1, - pixelBox.y1, - x0, - y0, - x1, - y1, - type - ); - }; - - CIQ.Drawing.callout.prototype.intersected = function (tick, value, box) { - var panel = this.stx.panels[this.panelName]; - if (!this.p0) return null; // in case invalid drawing (such as from panel that no longer exists) - if (this.pointIntersection(this.stem.t, this.stem.v, box)) { - this.highlighted = "p0"; - return { - action: "drag", - stem: true - }; - } - var x0 = this.stx.pixelFromTick(this.p0[0], panel.chart) - this.w / 2; - var y0 = - this.stx.pixelFromValueAdjusted(panel, this.p0[0], this.p0[1]) - - this.h / 2; - var x1 = x0 + this.w; - var y1 = y0 + this.h; - if (this.stem && this.stem.x) { - x0 += this.stem.x; - x1 += this.stem.x; - y0 += this.stem.y; - y1 += this.stem.y; - } - var x = this.stx.pixelFromTick(tick, panel.chart); - var y = this.stx.pixelFromValueAdjusted(panel, tick, value); - if ( - x + box.r >= x0 && - x - box.r <= x1 && - y + box.r >= y0 && - y - box.r <= y1 - ) { - this.highlighted = true; - return { - p0: CIQ.clone(this.p0), - tick: tick, - value: value - }; - } - var isIntersected = this.lineIntersection(tick, value, box, "segment"); - if (isIntersected) { - this.highlighted = true; - // This object will be used for repositioning - return { - action: "move", - stem: CIQ.clone(this.stem), - p0: CIQ.clone(this.p0), - tick: tick, // save original tick - value: value // save original value - }; - } - return null; - }; - - /** - * Fibonacci drawing tool. - * - * It inherits its properties from {@link CIQ.Drawing.BaseTwoPoint} - * @constructor - * @name CIQ.Drawing.fibonacci - */ - CIQ.Drawing.fibonacci = function () { - this.name = "fibonacci"; - this.configurator = "fibonacci"; - }; - - CIQ.inheritsFrom(CIQ.Drawing.fibonacci, CIQ.Drawing.BaseTwoPoint); - - CIQ.Drawing.fibonacci.mapping = { - trend: "t", - color: "c", - parameters: "p", - pattern: "pt", - opacity: "o", - lineWidth: "lw", - level: "l", - extendLeft: "e", - printLevels: "pl", - printValues: "pv", - timezone: "tz", - display: "d" - }; - - /** - * Levels to enable by default. - * @memberOf CIQ.Drawing.fibonacci - * @default - * @since 5.2.0 - */ - CIQ.Drawing.fibonacci.prototype.recommendedLevels = [ - -0.618, - -0.382, - 0, - 0.382, - 0.5, - 0.618, - 1, - 1.382, - 1.618 - ]; - - CIQ.Drawing.fibonacci.prototype.configs = [ - "color", - "fillColor", - "lineWidth", - "pattern", - "parameters" - ]; - - /** - * Set the default fib settings for the type of fib tool selected. References {@link CIQ.Drawing.fibonacci#recommendedLevels}. - * @param {CIQ.ChartEngine} stx Chart object - * @memberOf CIQ.Drawing.fibonacci - * @since 5.2.0 - */ - CIQ.Drawing.fibonacci.prototype.initializeSettings = function (stx) { - var recommendedLevels = this.recommendedLevels; - if ( - recommendedLevels && - !stx.currentVectorParameters.fibonacci.fibsAlreadySet - ) { - var fibs = stx.currentVectorParameters.fibonacci.fibs; - for (var index = 0; index < fibs.length; index++) { - delete fibs[index].display; - for (var rIndex = 0; rIndex < recommendedLevels.length; rIndex++) { - if (fibs[index].level == recommendedLevels[rIndex]) - fibs[index].display = true; - } - } - } - }; - - /* - * Calculate the outer points of the fib series, which are used to detect highlighting - */ - CIQ.Drawing.fibonacci.prototype.setOuter = function () { - var stx = this.stx, - panel = stx.panels[this.panelName]; - if (!panel) return; - var max = Math.max(this.p0[1], this.p1[1]); - var min = Math.min(this.p0[1], this.p1[1]); - var dist = max - min; - - this.outer = { - p0: CIQ.clone(this.p0), - p1: CIQ.clone(this.p1) - }; - var y0 = stx.pixelFromValueAdjusted(panel, this.p0[0], this.p0[1]); - var y1 = stx.pixelFromValueAdjusted(panel, this.p1[0], this.p1[1]); - var x0 = stx.pixelFromTick(this.p0[0], panel.chart); - var x1 = stx.pixelFromTick(this.p1[0], panel.chart); - - var minFib = 0; - var maxFib = 1; - for (var i = 0; i < this.parameters.fibs.length; i++) { - var fib = this.parameters.fibs[i]; - if ((fib.level >= minFib && fib.level <= maxFib) || !fib.display) - continue; - var y = stx.pixelFromValueAdjusted( - panel, - this.p0[0], - y1 < y0 ? max - dist * fib.level : min + dist * fib.level - ); - var x = CIQ.xIntersection({ x0: x0, x1: x1, y0: y0, y1: y1 }, y); - if (fib.level < minFib) { - minFib = fib.level; - this.outer.p1[1] = stx.valueFromPixel(y, panel); - this.outer.p1[0] = stx.tickFromPixel(x, panel.chart); - } else if (fib.level > maxFib) { - maxFib = fib.level; - this.outer.p0[1] = stx.valueFromPixel(y, panel); - this.outer.p0[0] = stx.tickFromPixel(x, panel.chart); - } - } - }; - - CIQ.Drawing.fibonacci.prototype.click = function (context, tick, value) { - var panel = this.stx.panels[this.panelName]; - if (!panel) return; - this.copyConfig(); - if (!this.penDown) { - this.setPoint(0, tick, value, panel.chart); - this.penDown = true; - return false; - } - if (this.accidentalClick(tick, value)) return this.dragToDraw; - - this.setPoint(1, tick, value, panel.chart); - this.setOuter(); - this.parameters = CIQ.clone(this.parameters); // separate from the global object - this.penDown = false; - - return true; // kernel will call render after this - }; - - CIQ.Drawing.fibonacci.prototype.render = function (context) { - var panel = this.stx.panels[this.panelName]; - if (!panel) return; - var yAxis = panel.yAxis; - if (!this.p1) return; - var max = Math.max(this.p0[1], this.p1[1]); - var min = Math.min(this.p0[1], this.p1[1]); - var dist = yAxis.flipped ? min - max : max - min; - var x0 = this.stx.pixelFromTick(this.p0[0], panel.chart); - var x1 = this.stx.pixelFromTick(this.p1[0], panel.chart); - var y0 = this.stx.pixelFromValueAdjusted(panel, this.p0[0], this.p0[1]); - var y1 = this.stx.pixelFromValueAdjusted(panel, this.p1[0], this.p1[1]); - var top = Math.min(y1, y0); - var bottom = Math.max(y1, y0); - var height = bottom - top; - var isUpTrend = (y1 - y0) / (x1 - x0) > 0; - - //old drawings missing parameters.trend - var trend = { - color: "auto", - parameters: { pattern: "solid", opacity: 0.25, lineWidth: 1 } - }; - if (!this.parameters.trend) this.parameters.trend = trend; - var trendLineColor = this.getLineColor(this.parameters.trend.color); - context.textBaseline = "middle"; - this.stx.canvasFont("stx_yaxis", context); // match font from y axis so it looks cohesive - var w = context.measureText("161.8%").width + 10; // give it extra space so it does not overlap with the price labels. - var minX = Number.MAX_VALUE, - minY = Number.MAX_VALUE, - maxX = Number.MAX_VALUE * -1, - maxY = Number.MAX_VALUE * -1; - var txtColor = this.color; - if (txtColor == "auto" || CIQ.isTransparent(txtColor)) - txtColor = this.stx.defaultColor; - this.rays = []; - for (var i = 0; i < this.parameters.fibs.length; i++) { - context.textAlign = "left"; - context.fillStyle = txtColor; - var fib = this.parameters.fibs[i]; - if (!fib.display) continue; - var y = this.stx.pixelFromValueAdjusted( - panel, - this.p0[0], - y1 < y0 ? max - dist * fib.level : min + dist * fib.level - ); - var x = CIQ.xIntersection({ x0: x0, x1: x1, y0: y0, y1: y1 }, y); - var nearX = this.parameters.extendLeft ? 0 : x; - var farX = panel.left + panel.width; - if (this.parameters.printLevels) { - var txt = Math.round(fib.level * 1000) / 10 + "%"; - farX -= w; - if (this.parameters.printValues) { - context.fillStyle = txtColor; // the price labels screw up the color and font size...so reset before rendering the text - this.stx.canvasFont("stx_yaxis", context); // use the same context as the y axis so they match. - } - if (farX < nearX) context.textAlign = "right"; - context.fillText(txt, farX, y); - if (farX < nearX) farX += 5; - else farX -= 5; - } - if (this.parameters.printValues) { - if (x < panel.width) { - // just use the actual price that segment will render on regardless of 'isUpTrend' since the values must match the prices on the y axis, and can not be reversed. - var price = this.stx.transformedPriceFromPixel(y, panel); - if (yAxis.priceFormatter) { - price = yAxis.priceFormatter(this.stx, panel, price); - } else { - price = this.stx.formatYAxisPrice(price, panel); - } - if (context == this.stx.chart.context) this.stx.endClip(); - this.stx.createYAxisLabel(panel, price, y, txtColor, null, context); - if (context == this.stx.chart.context) this.stx.startClip(panel.name); - } - } - var fibColor = fib.color; - if (fibColor == "auto" || CIQ.isTransparent(fibColor)) - fibColor = this.color; - if (fibColor == "auto" || CIQ.isTransparent(fibColor)) - fibColor = this.stx.defaultColor; - var fillColor = fib.color; - if (fillColor == "auto" || CIQ.isTransparent(fillColor)) - fillColor = this.fillColor; - if (fillColor == "auto" || CIQ.isTransparent(fillColor)) - fillColor = this.stx.defaultColor; - context.fillStyle = fillColor; - var fibParameters = CIQ.clone(fib.parameters); - if (this.highlighted) fibParameters.opacity = 1; - this.stx.plotLine( - nearX, - farX, - y, - y, - this.highlighted ? trendLineColor : fibColor, - "segment", - context, - panel, - fibParameters - ); - this.rays.push([ - [nearX, y], - [farX, y] - ]); - context.globalAlpha = 0.05; - context.beginPath(); - context.moveTo(farX, y); - context.lineTo(nearX, y); - if (nearX) context.lineTo(x1, y1); - else context.lineTo(nearX, y1); - context.lineTo(farX, y1); - if (typeof fillColor != "undefined") context.fill(); // so legacy fibs continue to have no fill color. - context.globalAlpha = 1; - if (y < minY) { - minX = x; - minY = y; - } - if (y > maxY) { - maxX = x; - maxY = y; - } - } - // ensure we at least draw trend line from zero to 100 - for (var level = 0; level <= 1; level++) { - var yy = isUpTrend ? bottom - height * level : top + height * level; - yy = Math.round(yy); - if (yy < minY) { - minX = CIQ.xIntersection({ x0: x0, x1: x1, y0: y0, y1: y1 }, yy); - minY = yy; - } - if (yy > maxY) { - maxX = CIQ.xIntersection({ x0: x0, x1: x1, y0: y0, y1: y1 }, yy); - maxY = yy; - } - } - var trendParameters = CIQ.clone(this.parameters.trend.parameters); - if (this.highlighted) trendParameters.opacity = 1; - this.stx.plotLine( - minX, - maxX, - minY, - maxY, - trendLineColor, - "segment", - context, - panel, - trendParameters - ); - if (this.highlighted) { - var p0Fill = this.highlighted == "p0" ? true : false; - var p1Fill = this.highlighted == "p1" ? true : false; - this.littleCircle(context, x0, y0, p0Fill); - this.littleCircle(context, x1, y1, p1Fill); - } - }; - - CIQ.Drawing.fibonacci.prototype.reposition = function ( - context, - repositioner, - tick, - value - ) { - if (!repositioner) return; - CIQ.Drawing.BaseTwoPoint.prototype.reposition.apply(this, arguments); - this.adjust(); - }; - - CIQ.Drawing.fibonacci.prototype.intersected = function (tick, value, box) { - var p0 = this.p0, - p1 = this.p1; - if (!p0 || !p1) return null; // in case invalid drawing (such as from panel that no longer exists) - var pointsToCheck = { 0: p0, 1: p1 }; - for (var pt in pointsToCheck) { - if ( - this.pointIntersection(pointsToCheck[pt][0], pointsToCheck[pt][1], box) - ) { - this.highlighted = "p" + pt; - return { - action: "drag", - point: "p" + pt - }; - } - } - var outer = this.outer, - rays = this.rays; - var isIntersected = - outer && - this.lineIntersection(tick, value, box, "segment", outer.p0, outer.p1); - if (!isIntersected) { - for (var i = 0; i < rays.length; i++) { - if ( - this.lineIntersection( - tick, - value, - box, - "ray", - rays[i][0], - rays[i][1], - true - ) - ) { - isIntersected = true; - break; - } - } - } - if (isIntersected) { - this.highlighted = true; - // This object will be used for repositioning - return { - action: "move", - p0: CIQ.clone(p0), - p1: CIQ.clone(p1), - tick: tick, // save original tick - value: value // save original value - }; - } - return null; - }; - - /** - * Reconstruct a fibonacci - * @param {CIQ.ChartEngine} stx The chart object - * @param {object} [obj] A drawing descriptor - * @param {string} [obj.col] The border color - * @param {string} [obj.fc] The fill color - * @param {string} [obj.pnl] The panel name - * @param {number} [obj.v0] Value (price) for the first point - * @param {number} [obj.v1] Value (price) for the second point - * @param {number} [obj.v2] Value (price) for the third point (if used) - * @param {number} [obj.d0] Date (string form) for the first point - * @param {number} [obj.d1] Date (string form) for the second point - * @param {number} [obj.d2] Date (string form) for the third point (if used) - * @param {number} [obj.tzo0] Offset of UTC from d0 in minutes - * @param {number} [obj.tzo1] Offset of UTC from d1 in minutes - * @param {number} [obj.tzo2] Offset of UTC from d2 in minutes (if used) - * @param {object} [obj.parameters] Configuration parameters - * @param {object} [obj.parameters.trend] Describes the trend line - * @param {string} [obj.parameters.trend.color] The color for the trend line (Defaults to "auto") - * @param {object} [obj.parameters.trend.parameters] Line description object (pattern, opacity, lineWidth) - * @param {array} [obj.parameters.fibs] A fib description object for each fib (level, color, parameters, display) - * @param {boolean} [obj.parameters.extendLeft] True to extend the fib lines to the left of the screen. Defaults to false. - * @param {boolean} [obj.parameters.printLevels] True (default) to print text for each percentage level - * @param {boolean} [obj.parameters.printValues] True to print text for each price level - * @memberOf CIQ.Drawing.fibonacci - */ - CIQ.Drawing.fibonacci.prototype.reconstruct = function (stx, obj) { - obj = CIQ.replaceFields( - obj, - CIQ.reverseObject(CIQ.Drawing.fibonacci.mapping) - ); - this.stx = stx; - this.parameters = obj.parameters; - if (!this.parameters) - this.parameters = CIQ.clone(this.stx.currentVectorParameters.fibonacci); // For legacy fibs that didn't include parameters - this.color = obj.col; - this.fillColor = obj.fc; - this.panelName = obj.pnl; - this.d0 = obj.d0; - this.d1 = obj.d1; - this.d2 = obj.d2; - this.tzo0 = obj.tzo0; - this.tzo1 = obj.tzo1; - this.tzo2 = obj.tzo2; - this.v0 = obj.v0; - this.v1 = obj.v1; - this.v2 = obj.v2; - this.adjust(); - }; - - CIQ.Drawing.fibonacci.prototype.adjust = function () { - var panel = this.stx.panels[this.panelName]; - if (!panel) return; - this.setPoint(0, this.d0, this.v0, panel.chart); - this.setPoint(1, this.d1, this.v1, panel.chart); - this.setOuter(); - }; - - CIQ.Drawing.fibonacci.prototype.serialize = function () { - var obj = { - name: this.name, - parameters: this.parameters, - pnl: this.panelName, - col: this.color, - fc: this.fillColor, - d0: this.d0, - d1: this.d1, - d2: this.d2, - tzo0: this.tzo0, - tzo1: this.tzo1, - tzo2: this.tzo2, - v0: this.v0, - v1: this.v1, - v2: this.v2 - }; - return CIQ.replaceFields(obj, CIQ.Drawing.fibonacci.mapping); - }; - - /** - * Retracement drawing tool. - * - * It inherits its properties from {@link CIQ.Drawing.fibonacci} - * @constructor - * @name CIQ.Drawing.retracement - */ - CIQ.Drawing.retracement = function () { - this.name = "retracement"; - }; - - CIQ.inheritsFrom(CIQ.Drawing.retracement, CIQ.Drawing.fibonacci); - - /** - * Fibonacci projection drawing tool. - * - * It inherits its properties from {@link CIQ.Drawing.fibonacci} - * @constructor - * @name CIQ.Drawing.fibprojection - * @version ChartIQ Advanced Package - * @since 5.2.0 - */ - CIQ.Drawing.fibprojection = function () { - this.name = "fibprojection"; - this.dragToDraw = false; - this.p2 = null; - }; - - CIQ.inheritsFrom(CIQ.Drawing.fibprojection, CIQ.Drawing.fibonacci); - - CIQ.Drawing.fibprojection.prototype.recommendedLevels = [ - 0, - 0.618, - 1, - 1.272, - 1.618, - 2.618, - 4.236 - ]; - - CIQ.Drawing.fibprojection.prototype.click = function (context, tick, value) { - var panel = this.stx.panels[this.panelName]; - if (!panel) return; - this.copyConfig(); - if (!this.penDown) { - this.setPoint(0, tick, value, panel.chart); - this.penDown = true; - return false; - } - if (this.accidentalClick(tick, value)) { - this.stx.undo(); //abort - return true; - } - - if (this.p2 !== null) { - this.setPoint(2, this.p2[0], this.p2[1], panel.chart); - this.parameters = CIQ.clone(this.parameters); // separate from the global object - return true; - } - this.setPoint(1, tick, value, panel.chart); - - this.p2 = [this.p1[0], this.p1[1]]; - return false; // kernel will call render after this - }; - - CIQ.Drawing.fibprojection.prototype.render = function (context) { - var panel = this.stx.panels[this.panelName]; - if (!panel) return; - var yAxis = panel.yAxis; - if (!this.p1) return; - var dist = this.p1[1] - this.p0[1]; - var x0 = this.stx.pixelFromTick(this.p0[0], panel.chart); - var x1 = this.stx.pixelFromTick(this.p1[0], panel.chart); - var y0 = this.stx.pixelFromValueAdjusted(panel, this.p0[0], this.p0[1]); - var y1 = this.stx.pixelFromValueAdjusted(panel, this.p1[0], this.p1[1]); - var x2 = null, - y2 = null; - if (this.p2) { - x2 = this.stx.pixelFromTick(this.p2[0], panel.chart); - y2 = this.stx.pixelFromValueAdjusted(panel, this.p2[0], this.p2[1]); - } - //old drawings missing parameters.trend - var trend = { - color: "auto", - parameters: { pattern: "solid", opacity: 0.25, lineWidth: 1 } - }; - if (!this.parameters.trend) this.parameters.trend = trend; - var trendLineColor = this.getLineColor(this.parameters.trend.color); - context.textBaseline = "middle"; - this.stx.canvasFont("stx_yaxis", context); // match font from y axis so it looks cohesive - var w = context.measureText("161.8%").width + 10; // give it extra space so it does not overlap with the price labels. - var txtColor = this.color; - if (txtColor == "auto" || CIQ.isTransparent(txtColor)) - txtColor = this.stx.defaultColor; - if (this.p2) { - this.rays = []; - for (var i = 0; i < this.parameters.fibs.length; i++) { - context.textAlign = "left"; - context.fillStyle = txtColor; - var fib = this.parameters.fibs[i]; - if (!fib.display) continue; - var y = this.stx.pixelFromValueAdjusted( - panel, - this.p2[0], - this.p2[1] + dist * fib.level - ); - var x = CIQ.xIntersection({ x0: x0, x1: x1, y0: y0, y1: y1 }, y); - var nearX = this.parameters.extendLeft ? 0 : x0; - var farX = panel.left + panel.width; - if (this.parameters.printLevels) { - var txt = Math.round(fib.level * 1000) / 10 + "%"; - farX -= w; - if (this.parameters.printValues) { - context.fillStyle = txtColor; // the price labels screw up the color and font size...so reset before rendering the text - this.stx.canvasFont("stx_yaxis", context); // use the same context as the y axis so they match. - } - if (farX < nearX) context.textAlign = "right"; - context.fillText(txt, farX, y); - if (farX < nearX) farX += 5; - else farX -= 5; - } - if (this.parameters.printValues) { - if (x < panel.width) { - // just use the actual price that segment will render on regardless of 'isUpTrend' since the values must match the prices on the y axis, and can not be reversed. - var price = this.stx.transformedPriceFromPixel(y, panel); - if (yAxis.priceFormatter) { - price = yAxis.priceFormatter(this.stx, panel, price); - } else { - price = this.stx.formatYAxisPrice(price, panel); - } - if (context == this.stx.chart.context) this.stx.endClip(); - this.stx.createYAxisLabel(panel, price, y, txtColor, null, context); - if (context == this.stx.chart.context) - this.stx.startClip(panel.name); - } - } - var fibColor = fib.color; - if (fibColor == "auto" || CIQ.isTransparent(fibColor)) - fibColor = this.color; - if (fibColor == "auto" || CIQ.isTransparent(fibColor)) - fibColor = this.stx.defaultColor; - var fillColor = fib.color; - if (fillColor == "auto" || CIQ.isTransparent(fillColor)) - fillColor = this.fillColor; - if (fillColor == "auto" || CIQ.isTransparent(fillColor)) - fillColor = this.stx.defaultColor; - context.fillStyle = fillColor; - var fibParameters = CIQ.clone(fib.parameters); - if (this.highlighted) fibParameters.opacity = 1; - this.stx.plotLine( - nearX, - farX, - y, - y, - this.highlighted ? trendLineColor : fibColor, - "segment", - context, - panel, - fibParameters - ); - this.rays.push([ - [nearX, y], - [farX, y] - ]); - context.globalAlpha = 0.05; - context.beginPath(); - context.moveTo(farX, y); - context.lineTo(nearX, y); - if (nearX) context.lineTo(x0, y2); - else context.lineTo(nearX, y2); - context.lineTo(farX, y2); - if (typeof fillColor != "undefined") context.fill(); // so legacy fibs continue to have no fill color. - context.globalAlpha = 1; - } - } - var trendParameters = CIQ.clone(this.parameters.trend.parameters); - if (this.highlighted) trendParameters.opacity = 1; - this.stx.plotLine( - x0, - x1, - y0, - y1, - trendLineColor, - "segment", - context, - panel, - trendParameters - ); - if (this.p2) - this.stx.plotLine( - x1, - x2, - y1, - y2, - trendLineColor, - "segment", - context, - panel, - trendParameters - ); - if (this.highlighted) { - var p0Fill = this.highlighted == "p0" ? true : false; - var p1Fill = this.highlighted == "p1" ? true : false; - var p2Fill = this.highlighted == "p2" ? true : false; - this.littleCircle(context, x0, y0, p0Fill); - this.littleCircle(context, x1, y1, p1Fill); - this.littleCircle(context, x2, y2, p2Fill); - } - }; - - CIQ.Drawing.fibprojection.prototype.move = function (context, tick, value) { - if (!this.penDown) return; - this.copyConfig(); - if (this.p2 === null) this.p1 = [tick, value]; - else this.p2 = [tick, value]; - this.render(context); - }; - - CIQ.Drawing.fibprojection.prototype.reposition = function ( - context, - repositioner, - tick, - value - ) { - if (!repositioner) return; - var panel = this.stx.panels[this.panelName]; - var tickDiff = repositioner.tick - tick; - var valueDiff = repositioner.value - value; - if (repositioner.action == "move") { - this.setPoint( - 0, - repositioner.p0[0] - tickDiff, - repositioner.p0[1] - valueDiff, - panel.chart - ); - this.setPoint( - 1, - repositioner.p1[0] - tickDiff, - repositioner.p1[1] - valueDiff, - panel.chart - ); - this.setPoint( - 2, - repositioner.p2[0] - tickDiff, - repositioner.p2[1] - valueDiff, - panel.chart - ); - this.render(context); - } else if (repositioner.action == "drag") { - this[repositioner.point] = [tick, value]; - this.setPoint(0, this.p0[0], this.p0[1], panel.chart); - this.setPoint(1, this.p1[0], this.p1[1], panel.chart); - this.setPoint(2, this.p2[0], this.p2[1], panel.chart); - this.render(context); - } - }; - - CIQ.Drawing.fibprojection.prototype.intersected = function ( - tick, - value, - box - ) { - var p0 = this.p0, - p1 = this.p1, - p2 = this.p2; - if (!p0 || !p1 || !p2) return null; // in case invalid drawing (such as from panel that no longer exists) - var pointsToCheck = { 0: p0, 1: p1, 2: p2 }; - for (var pt in pointsToCheck) { - if ( - this.pointIntersection(pointsToCheck[pt][0], pointsToCheck[pt][1], box) - ) { - this.highlighted = "p" + pt; - return { - action: "drag", - point: "p" + pt - }; - } - } - var rays = this.rays; - var isIntersected = - this.lineIntersection(tick, value, box, "segment", p0, p1) || - this.lineIntersection(tick, value, box, "segment", p1, p2); - if (!isIntersected) { - for (var i = 0; i < rays.length; i++) { - if ( - this.lineIntersection( - tick, - value, - box, - "ray", - rays[i][0], - rays[i][1], - true - ) - ) { - isIntersected = true; - break; - } - } - } - if (isIntersected) { - this.highlighted = true; - // This object will be used for repositioning - return { - action: "move", - p0: CIQ.clone(p0), - p1: CIQ.clone(p1), - p2: CIQ.clone(p2), - tick: tick, // save original tick - value: value // save original value - }; - } - return null; - }; - - CIQ.Drawing.fibprojection.prototype.adjust = function () { - var panel = this.stx.panels[this.panelName]; - if (!panel) return; - this.setPoint(0, this.d0, this.v0, panel.chart); - this.setPoint(1, this.d1, this.v1, panel.chart); - this.setPoint(2, this.d2, this.v2, panel.chart); - }; - - /** - * Fibonacci Arc drawing tool. - * - * It inherits its properties from {@link CIQ.Drawing.fibonacci} - * @constructor - * @name CIQ.Drawing.fibarc - * @since 2015-11-1 - * @version ChartIQ Advanced Package - */ - CIQ.Drawing.fibarc = function () { - this.name = "fibarc"; - //this.dragToDraw=true; - }; - - CIQ.inheritsFrom(CIQ.Drawing.fibarc, CIQ.Drawing.fibonacci); - - CIQ.Drawing.fibarc.prototype.recommendedLevels = [0.382, 0.5, 0.618, 1]; - - CIQ.Drawing.fibarc.prototype.setOuter = function () { - var panel = this.stx.panels[this.panelName]; - if (!panel) return; - - this.outer = { - p0: CIQ.clone(this.p0), - p1: CIQ.clone(this.p1) - }; - var y0 = this.stx.pixelFromValueAdjusted(panel, this.p0[0], this.p0[1]); - var y1 = this.stx.pixelFromValueAdjusted(panel, this.p1[0], this.p1[1]); - var x0 = this.stx.pixelFromTick(this.p0[0], panel.chart); - var x1 = this.stx.pixelFromTick(this.p1[0], panel.chart); - var y = 2 * y0 - y1; - var x = CIQ.xIntersection({ x0: x0, x1: x1, y0: y0, y1: y1 }, y); - this.outer.p0[1] = this.stx.valueFromPixel(y, panel); - this.outer.p0[0] = this.stx.tickFromPixel(x, panel.chart); - }; - - CIQ.Drawing.fibarc.prototype.intersected = function (tick, value, box) { - var panel = this.stx.panels[this.panelName]; - if (!panel) return; - var p0 = this.p0, - p1 = this.p1, - outer = this.outer; - if (!p0 || !p1) return null; // in case invalid drawing (such as from panel that no longer exists) - var pointsToCheck = { 0: p0, 1: p1 }; - for (var pt in pointsToCheck) { - if ( - this.pointIntersection(pointsToCheck[pt][0], pointsToCheck[pt][1], box) - ) { - this.highlighted = "p" + pt; - return { - action: "drag", - point: "p" + pt - }; - } - } - if ( - this.lineIntersection(tick, value, box, "segment", outer.p0, outer.p1) - ) { - this.highlighted = true; - // This object will be used for repositioning - return { - action: "move", - p0: CIQ.clone(p0), - p1: CIQ.clone(p1), - tick: tick, // save original tick - value: value // save original value - }; - } - // Just test the box circumscribing the arcs - var points = { x0: p0[0], x1: p1[0], y0: p0[1], y1: p1[1] }; - var pixelArea = CIQ.convertBoxToPixels(this.stx, this.panelName, points); - var extend = { - x: Math.abs(Math.sqrt(2) * (pixelArea.x1 - pixelArea.x0)), - y: Math.abs(Math.sqrt(2) * (pixelArea.y1 - pixelArea.y0)) - }; - var x = this.stx.pixelFromTick(tick, panel.chart); - var y = this.stx.pixelFromValueAdjusted(panel, tick, value); - - if ( - x + box.r < pixelArea.x1 - extend.x || - x - box.r > pixelArea.x1 + extend.x - ) - return null; - if ( - y + box.r < pixelArea.y1 - extend.y || - y - box.r > pixelArea.y1 + extend.y - ) - return null; - if (pixelArea.y0 < pixelArea.y1 && y - box.r > pixelArea.y1) return null; - if (pixelArea.y0 > pixelArea.y1 && y + box.r < pixelArea.y1) return null; - this.highlighted = true; - return { - action: "move", - p0: CIQ.clone(this.p0), - p1: CIQ.clone(this.p1), - tick: tick, - value: value - }; - }; - - CIQ.Drawing.fibarc.prototype.render = function (context) { - var panel = this.stx.panels[this.panelName]; - if (!panel) return; - var yAxis = panel.yAxis; - if (!this.p1) return; - var x0 = this.stx.pixelFromTick(this.p0[0], panel.chart); - var x1 = this.stx.pixelFromTick(this.p1[0], panel.chart); - var y0 = this.stx.pixelFromValueAdjusted(panel, this.p0[0], this.p0[1]); - var y1 = this.stx.pixelFromValueAdjusted(panel, this.p1[0], this.p1[1]); - var isUpTrend = y1 < y0; - var factor = Math.abs((y1 - y0) / (x1 - x0)); - - var trendLineColor = this.getLineColor(this.parameters.trend.color); - context.textBaseline = "middle"; - this.stx.canvasFont("stx_yaxis", context); // match font from y axis so it looks cohesive - var txtColor = this.color; - if (txtColor == "auto" || CIQ.isTransparent(txtColor)) - txtColor = this.stx.defaultColor; - for (var i = 0; i < this.parameters.fibs.length; i++) { - context.fillStyle = txtColor; - var fib = this.parameters.fibs[i]; - if (fib.level < 0 || !fib.display) continue; - var radius = Math.abs(this.p1[1] - this.p0[1]) * Math.sqrt(2) * fib.level; - var value = - this.p1[1] + radius * (isUpTrend ? -1 : 1) * (yAxis.flipped ? -1 : 1); - var y = this.stx.pixelFromValueAdjusted(panel, this.p0[0], value); - var x = CIQ.xIntersection({ x0: x0, x1: x1, y0: y0, y1: y1 }, y); - if (this.parameters.printLevels) { - context.textAlign = "center"; - var txt = Math.round(fib.level * 1000) / 10 + "%"; - if (this.parameters.printValues) { - context.fillStyle = txtColor; // the price labels screw up the color and font size...so reset before rendering the text - this.stx.canvasFont("stx_yaxis", context); // use the same context as the y axis so they match. - } - context.fillText(txt, x1, Math.round(y - 5)); - } - context.textAlign = "left"; - if (this.parameters.printValues) { - if (x < panel.width) { - // just use the actual price that segment will render on regardless of 'isUpTrend' since the values must match the prices on the y axis, and can not be reversed. - var price = value; - if (yAxis.priceFormatter) { - price = yAxis.priceFormatter(this.stx, panel, price); - } else { - price = this.stx.formatYAxisPrice(price, panel); - } - if (context == this.stx.chart.context) this.stx.endClip(); - this.stx.createYAxisLabel(panel, price, y, txtColor, null, context); - if (context == this.stx.chart.context) this.stx.startClip(panel.name); - } - } - var fibColor = fib.color; - if (fibColor == "auto" || CIQ.isTransparent(fibColor)) - fibColor = this.color; - if (fibColor == "auto" || CIQ.isTransparent(fibColor)) - fibColor = this.stx.defaultColor; - context.strokeStyle = this.highlight ? trendLineColor : fibColor; - var fillColor = fib.color; - if (fillColor == "auto" || CIQ.isTransparent(fillColor)) - fillColor = this.fillColor; - if (fillColor == "auto" || CIQ.isTransparent(fillColor)) - fillColor = this.stx.defaultColor; - context.fillStyle = fillColor; - context.globalAlpha = this.highlighted ? 1 : fib.parameters.opacity; - context.lineWidth = fib.parameters.lineWidth; - if (context.setLineDash) { - context.setLineDash( - CIQ.borderPatternToArray(context.lineWidth, fib.parameters.pattern) - ); - context.lineDashOffset = 0; //start point in array - } - context.save(); - context.beginPath(); - context.scale(1 / factor, 1); - context.arc(x1 * factor, y1, Math.abs(y - y1), 0, Math.PI, !isUpTrend); - if (this.pattern != "none") context.stroke(); - context.globalAlpha = 0.05; - context.fill(); - context.restore(); - if (context.setLineDash) context.setLineDash([]); - context.globalAlpha = 1; - } - context.textAlign = "left"; - // ensure we at least draw trend line from zero to 100 - var trendParameters = CIQ.clone(this.parameters.trend.parameters); - if (this.highlighted) trendParameters.opacity = 1; - this.stx.plotLine( - x1, - 2 * x0 - x1, - y1, - 2 * y0 - y1, - trendLineColor, - "segment", - context, - panel, - trendParameters - ); - if (this.highlighted) { - var p0Fill = this.highlighted == "p0" ? true : false; - var p1Fill = this.highlighted == "p1" ? true : false; - this.littleCircle(context, x0, y0, p0Fill); - this.littleCircle(context, x1, y1, p1Fill); - } - }; - - /** - * Fibonacci Fan drawing tool. - * - * It inherits its properties from {@link CIQ.Drawing.fibonacci} - * @constructor - * @name CIQ.Drawing.fibfan - * @since 2015-11-1 - * @version ChartIQ Advanced Package - */ - CIQ.Drawing.fibfan = function () { - this.name = "fibfan"; - //this.dragToDraw=true; - }; - - CIQ.inheritsFrom(CIQ.Drawing.fibfan, CIQ.Drawing.fibonacci); - - CIQ.Drawing.fibfan.prototype.recommendedLevels = [0, 0.382, 0.5, 0.618, 1]; - - CIQ.Drawing.fibfan.prototype.setOuter = function () {}; - - CIQ.Drawing.fibfan.prototype.render = function (context) { - var panel = this.stx.panels[this.panelName]; - if (!panel) return; - var yAxis = panel.yAxis; - if (!this.p1) return; - var x0 = this.stx.pixelFromTick(this.p0[0], panel.chart); - var x1 = this.stx.pixelFromTick(this.p1[0], panel.chart); - var y0 = this.stx.pixelFromValueAdjusted(panel, this.p0[0], this.p0[1]); - var y1 = this.stx.pixelFromValueAdjusted(panel, this.p1[0], this.p1[1]); - var top = Math.min(y1, y0); - var bottom = Math.max(y1, y0); - var height = bottom - top; - var isUpTrend = (y1 - y0) / (x1 - x0) > 0; - - var trendLineColor = this.getLineColor(this.parameters.trend.color); - - context.textBaseline = "middle"; - this.stx.canvasFont("stx_yaxis", context); // match font from y axis so it looks cohesive - var w = context.measureText("161.8%").width + 10; // give it extra space so it does not overlap with the price labels. - var /*minX=Number.MAX_VALUE,*/ minY = Number.MAX_VALUE, - /*maxX=Number.MAX_VALUE*-1,*/ maxY = Number.MAX_VALUE * -1; - var txtColor = this.color; - if (txtColor == "auto" || CIQ.isTransparent(txtColor)) - txtColor = this.stx.defaultColor; - this.rays = []; - for (var i = 0; i < this.parameters.fibs.length; i++) { - context.fillStyle = txtColor; - var fib = this.parameters.fibs[i]; - if (!fib.display) continue; - //var y=(y0-y1)*fib.level+y1; - var y = this.stx.pixelFromValueAdjusted( - panel, - this.p0[0], - (this.p0[1] - this.p1[1]) * fib.level + this.p1[1] - ); - var x = CIQ.xIntersection({ x0: x1, x1: x1, y0: y0, y1: y1 }, y); - var farX = panel.left; - if (x1 > x0) farX += panel.width; - var farY = ((farX - x0) * (y - y0)) / (x - x0) + y0; - if (x0 > farX - (this.parameters.printLevels ? w + 5 : 0) && x1 > x0) - continue; - else if (x0 < farX + (this.parameters.printLevels ? w + 5 : 0) && x1 < x0) - continue; - if (this.parameters.printLevels) { - var txt = Math.round(fib.level * 1000) / 10 + "%"; - if (x1 > x0) { - farX -= w; - context.textAlign = "left"; - } else { - farX += w; - context.textAlign = "right"; - } - if (this.parameters.printValues) { - context.fillStyle = txtColor; // the price labels screw up the color and font size...so reset before rendering the text - this.stx.canvasFont("stx_yaxis", context); // use the same context as the y axis so they match. - } - farY = ((farX - x0) * (y - y0)) / (x - x0) + y0; - context.fillText(txt, farX, farY); - if (x1 > x0) farX -= 5; - else farX += 5; - } - context.textAlign = "left"; - if (this.parameters.printValues) { - if (x < panel.width) { - // just use the actual price that segment will render on regardless of 'isUpTrend' since the values must match the prices on the y axis, and can not be reversed. - var price = this.stx.transformedPriceFromPixel(y, panel); - if (yAxis.priceFormatter) { - price = yAxis.priceFormatter(this.stx, panel, price); - } else { - price = this.stx.formatYAxisPrice(price, panel); - } - if (context == this.stx.chart.context) this.stx.endClip(); - this.stx.createYAxisLabel(panel, price, y, txtColor, null, context); - if (context == this.stx.chart.context) this.stx.startClip(panel.name); - } - } - var fibColor = fib.color; - if (fibColor == "auto" || CIQ.isTransparent(fibColor)) - fibColor = this.color; - if (fibColor == "auto" || CIQ.isTransparent(fibColor)) - fibColor = this.stx.defaultColor; - var fillColor = fib.color; - if (fillColor == "auto" || CIQ.isTransparent(fillColor)) - fillColor = this.fillColor; - if (fillColor == "auto" || CIQ.isTransparent(fillColor)) - fillColor = this.stx.defaultColor; - context.fillStyle = fillColor; - if (this.parameters.printLevels) - farY = ((farX - x0) * (y - y0)) / (x - x0) + y0; - var fibParameters = CIQ.clone(fib.parameters); - if (this.highlighted) fibParameters.opacity = 1; - this.stx.plotLine( - x0, - farX, - y0, - farY, - this.highlighted ? trendLineColor : fibColor, - "segment", - context, - panel, - fibParameters - ); - this.rays.push([ - [x0, y0], - [farX, farY] - ]); - context.globalAlpha = 0.05; - context.beginPath(); - context.moveTo(farX, farY); - context.lineTo(x0, y0); - context.lineTo(farX, y0); - context.fill(); - context.globalAlpha = 1; - if (y < minY) { - //minX=x; - minY = y; - } - if (y > maxY) { - //maxX=x; - maxY = y; - } - } - // ensure we at least draw trend line from zero to 100 - for (var level = 0; level <= 1; level++) { - var yy = isUpTrend ? bottom - height * level : top + height * level; - yy = Math.round(yy); - if (yy < minY) { - //minX=CIQ.xIntersection({x0:x1,x1:x1,y0:y0,y1:y1}, yy); - minY = yy; - } - if (yy > maxY) { - //maxX=CIQ.xIntersection({x0:x1,x1:x1,y0:y0,y1:y1}, yy); - maxY = yy; - } - } - //this.stx.plotLine(minX, maxX, minY, maxY, trendLineColor, "segment", context, panel, this.parameters.trend.parameters); - if (this.highlighted) { - var p0Fill = this.highlighted == "p0" ? true : false; - var p1Fill = this.highlighted == "p1" ? true : false; - this.littleCircle(context, x0, y0, p0Fill); - this.littleCircle(context, x1, y1, p1Fill); - } - }; - - /** - * Fibonacci Time Zone drawing tool. - * - * It inherits its properties from {@link CIQ.Drawing.fibonacci} - * @constructor - * @name CIQ.Drawing.fibtimezone - * @since 2015-11-1 - * @version ChartIQ Advanced Package - */ - CIQ.Drawing.fibtimezone = function () { - this.name = "fibtimezone"; - //this.dragToDraw=true; - }; - - CIQ.inheritsFrom(CIQ.Drawing.fibtimezone, CIQ.Drawing.fibonacci); - - CIQ.Drawing.fibtimezone.prototype.render = function (context) { - var panel = this.stx.panels[this.panelName]; - if (!panel) return; - if (!this.p1) return; - var x0 = this.stx.pixelFromTick(this.p0[0], panel.chart); - var x1 = this.stx.pixelFromTick(this.p1[0], panel.chart); - var y0 = this.stx.pixelFromValueAdjusted(panel, this.p0[0], this.p0[1]); - var y1 = this.stx.pixelFromValueAdjusted(panel, this.p1[0], this.p1[1]); - var fibs = [1, 0]; - - var trendLineColor = this.getLineColor(this.parameters.trend.color); - - context.textBaseline = "middle"; - this.stx.canvasFont("stx_yaxis", context); // match font from y axis so it looks cohesive - var h = 20; // give it extra space so it does not overlap with the date labels. - var mult = this.p1[0] - this.p0[0]; - var txtColor = this.color; - if (txtColor == "auto" || CIQ.isTransparent(txtColor)) - txtColor = this.stx.defaultColor; - context.textAlign = "center"; - - var x = x0; - var top = panel.yAxis.top; - var farY = panel.yAxis.bottom; - var txt = 0; - var fibColor = this.parameters.timezone.color; - if (fibColor == "auto" || CIQ.isTransparent(fibColor)) - fibColor = this.color; - if (fibColor == "auto" || CIQ.isTransparent(fibColor)) - fibColor = this.stx.defaultColor; - var fillColor = this.parameters.timezone.color; - if (fillColor == "auto" || CIQ.isTransparent(fillColor)) - fillColor = this.fillColor; - if (fillColor == "auto" || CIQ.isTransparent(fillColor)) - fillColor = this.stx.defaultColor; - - if (this.parameters.printLevels) farY -= h - 7; - - var tzParameters = CIQ.clone(this.parameters.timezone.parameters); - if (this.highlighted) tzParameters.opacity = 1; - do { - x = this.stx.pixelFromTick(this.p0[0] + txt * mult, panel.chart); - if (x0 < x1 && x > panel.left + panel.width) break; - else if (x0 > x1 && x < panel.left) break; - if (this.parameters.printLevels) { - context.fillStyle = txtColor; - context.fillText(x1 > x0 ? txt : txt * -1, x, farY + 7); - } - context.fillStyle = fillColor; - this.stx.plotLine( - x, - x, - 0, - farY, - this.highlighted ? trendLineColor : fibColor, - "segment", - context, - panel, - tzParameters - ); - context.globalAlpha = 0.05; - context.beginPath(); - context.moveTo(x0, top); - context.lineTo(x, top); - context.lineTo(x, farY); - context.lineTo(x0, farY); - context.fill(); - context.globalAlpha = 1; - txt = fibs[0] + fibs[1]; - fibs.unshift(txt); - } while (mult); - context.textAlign = "left"; - this.stx.plotLine( - x0, - x1, - y0, - y1, - trendLineColor, - "segment", - context, - panel, - tzParameters - ); - if (this.highlighted) { - var p0Fill = this.highlighted == "p0" ? true : false; - var p1Fill = this.highlighted == "p1" ? true : false; - this.littleCircle(context, x0, y0, p0Fill); - this.littleCircle(context, x1, y1, p1Fill); - } else { - // move points so always accessible - var yVal = this.stx.valueFromPixel(panel.height / 2, panel); - this.setPoint(0, this.p0[0], yVal, panel.chart); - this.setPoint(1, this.p1[0], yVal, panel.chart); - } - }; - - CIQ.Drawing.fibtimezone.prototype.intersected = function (tick, value, box) { - var p0 = this.p0, - p1 = this.p1, - panel = this.stx.panels[this.panelName]; - if (!p0 || !p1 || !panel) return null; // in case invalid drawing (such as from panel that no longer exists) - var pointsToCheck = { 0: p0, 1: p1 }; - for (var pt in pointsToCheck) { - if ( - this.pointIntersection(pointsToCheck[pt][0], pointsToCheck[pt][1], box) - ) { - this.highlighted = "p" + pt; - return { - action: "drag", - point: "p" + pt - }; - } - } - // Check for over the trend line or the 0 vertical line - var trendIntersects = this.lineIntersection(tick, value, box, "segment"); - if (trendIntersects || (box.x0 <= this.p0[0] && box.x1 >= p0[0])) { - this.highlighted = true; - return { - action: "move", - p0: CIQ.clone(p0), - p1: CIQ.clone(p1), - tick: tick, // save original tick - value: value // save original value - }; - } - return null; - }; - - // Backwards compatibility for drawings - CIQ.Drawing.arrow_v0 = function () { - this.name = "arrow"; - this.dimension = [11, 11]; - this.points = [ - [ - "M", - 3, - 0, - "L", - 7, - 0, - "L", - 7, - 5, - "L", - 10, - 5, - "L", - 5, - 10, - "L", - 0, - 5, - "L", - 3, - 5, - "L", - 3, - 0 - ] - ]; - }; - CIQ.inheritsFrom(CIQ.Drawing.arrow_v0, CIQ.Drawing.shape); - - /* Drawing specific shapes - * - * this.dimension: overall dimension of shape as designed, as a pair [dx,dy] where dx is length and dy is width, in pixels - * this.points: array of arrays. Each array represents a closed loop subshape. - * within each array is a series of values representing coordinates. - * For example, ["M",0,0,"L",1,1,"L",2,1,"Q",3,3,4,1,"B",5,5,0,0,3,3] - * The array will be parsed by the render function: - * "M" - move to the xy coordinates represented by the next 2 array elements - * "L" - draw line to xy coordinates represented by the next 2 array elements - * "Q" - draw quadratic curve where next 2 elements are the control point and following 2 elements are the end coordinates - * "B" - draw bezier curve where next 2 elements are first control point, next 2 elements are second control point, and next 2 elements are the end coordinates - * See sample shapes below. - * - */ - - CIQ.Drawing.xcross = function () { - this.name = "xcross"; - this.dimension = [7, 7]; - this.points=[ - [ - "M", 1, 0, - "L", 3, 2, - "L", 5, 0, - "L", 6, 1, - "L", 4, 3, - "L", 6, 5, - "L" ,5, 6, - "L", 3, 4, - "L", 1, 6, - "L", 0, 5, - "L", 2, 3, - "L", 0, 1, - "L", 1, 0 - ] - ]; // prettier-ignore - }; - CIQ.inheritsFrom(CIQ.Drawing.xcross, CIQ.Drawing.shape); - - CIQ.Drawing.check = function () { - this.name = "check"; - this.dimension = [8, 9]; - this.points = [ - [ - "M", 1, 5, - "L", 0, 6, - "L", 2, 8, - "L", 7, 1, - "L", 6, 0, - "L", 2, 6, - "L", 1, 5 - ] - ]; // prettier-ignore - }; - CIQ.inheritsFrom(CIQ.Drawing.check, CIQ.Drawing.shape); - - CIQ.Drawing.star = function () { - this.name = "star"; - this.dimension = [12, 12]; - this.points=[ - [ - "M", 0, 4, - "L", 4, 4, - "L", 5.5, 0, - "L", 7, 4, - "L", 11, 4, - "L" ,8, 7, - "L", 9, 11, - "L", 5.5, 9, - "L", 2, 11, - "L", 3, 7, - "L", 0, 4 - ] - ]; // prettier-ignore - }; - CIQ.inheritsFrom(CIQ.Drawing.star, CIQ.Drawing.shape); - - CIQ.Drawing.heart = function () { - this.name = "heart"; - this.dimension = [23, 20]; - this.points=[ - [ - "M", 11, 3, - "B", 11, 2.4, 10, 0, 6 ,0, - "B", 0, 0, 0, 7.5, 0, 7.5, - "B", 0, 11, 4, 15.4, 11, 19, - "B", 18, 15.4, 22, 11, 22, 7.5, - "B", 22, 7.5, 22, 0, 16, 0, - "B", 13, 0, 11, 2.4, 11, 3 - ] - ]; // prettier-ignore - }; - CIQ.inheritsFrom(CIQ.Drawing.heart, CIQ.Drawing.shape); - - CIQ.Drawing.focusarrow = function () { - this.name = "focusarrow"; - this.dimension = [7, 5]; - this.points = [ - [ - "M", 0, 0, - "L", 2, 2, - "L", 0, 4, - "L", 0, 0 - ], - [ - "M", 6, 0, - "L", 4, 2, - "L", 6, 4, - "L", 6, 0 - ] - ]; // prettier-ignore - }; - CIQ.inheritsFrom(CIQ.Drawing.focusarrow, CIQ.Drawing.shape); - - /** - * Crossline drawing tool. - * - * It inherits its properties from {@link CIQ.Drawing.horizontal} - * @constructor - * @name CIQ.Drawing.crossline - * @since 2016-09-19 - * @version ChartIQ Advanced Package - */ - CIQ.Drawing.crossline = function () { - this.name = "crossline"; - }; - CIQ.inheritsFrom(CIQ.Drawing.crossline, CIQ.Drawing.horizontal); - CIQ.extend( - CIQ.Drawing.crossline.prototype, - { - measure: function () {}, - accidentalClick: function (tick, value) { - return false; - }, - adjust: function () { - var panel = this.stx.panels[this.panelName]; - if (!panel) return; - this.setPoint(0, this.d0, this.v0, panel.chart); - this.p1 = CIQ.clone(this.p0); - }, - intersected: function (tick, value, box) { - if (!this.p0 || !this.p1) return null; - this.p1[0] += 1; - var isIntersected = this.lineIntersection(tick, value, box, "line"); - this.p1 = CIQ.clone(this.p0); - if (!isIntersected) { - this.p1[1] += 1; - isIntersected = this.lineIntersection(tick, value, box, "line"); - this.p1 = CIQ.clone(this.p0); - if (!isIntersected) return null; - } - this.highlighted = true; - if (this.pointIntersection(this.p0[0], this.p0[1], box)) { - this.highlighted = "p0"; - } - // This object will be used for repositioning - return { - action: "move", - p0: CIQ.clone(this.p0), - p1: CIQ.clone(this.p1), - tick: tick, // save original tick - value: value // save original value - }; - }, - render: function (context) { - var panel = this.stx.panels[this.panelName]; - if (!panel) return; - var x0 = this.stx.pixelFromTick(this.p0[0], panel.chart); - var y0 = this.stx.pixelFromValueAdjusted(panel, this.p0[0], this.p0[1]); - - var color = this.getLineColor(); - - var parameters = { - pattern: this.pattern, - lineWidth: this.lineWidth - }; - this.stx.plotLine( - x0, - x0 + 100, - y0, - y0, - color, - "horizontal", - context, - panel, - parameters - ); - this.stx.plotLine( - x0, - x0, - y0, - y0 + 100, - color, - "vertical", - context, - panel, - parameters - ); - - if (this.axisLabel && !this.repositioner) { - this.stx.endClip(); - var txt = this.p0[1]; - if (panel.chart.transformFunc) - txt = panel.chart.transformFunc(this.stx, panel.chart, txt); - if (panel.yAxis.priceFormatter) - txt = panel.yAxis.priceFormatter(this.stx, panel, txt); - else txt = this.stx.formatYAxisPrice(txt, panel); - this.stx.createYAxisLabel(panel, txt, y0, color); - this.stx.startClip(panel.name); - if (this.p0[0] >= 0 && !this.stx.chart.xAxis.noDraw) { - // don't try to compute dates from before dataSet - var dt, newDT; - /* set d0 to the right timezone */ - dt = this.stx.dateFromTick(this.p0[0], panel.chart, true); - if (!CIQ.ChartEngine.isDailyInterval(this.stx.layout.interval)) { - var milli = dt.getSeconds() * 1000 + dt.getMilliseconds(); - if (timezoneJS.Date && this.stx.displayZone) { - // this converts from the quote feed timezone to the chart specified time zone - newDT = new timezoneJS.Date(dt.getTime(), this.stx.displayZone); - dt = new Date( - newDT.getFullYear(), - newDT.getMonth(), - newDT.getDate(), - newDT.getHours(), - newDT.getMinutes() - ); - dt = new Date(dt.getTime() + milli); - } - } else { - dt.setHours(0, 0, 0, 0); - } - var myDate = CIQ.mmddhhmm(CIQ.yyyymmddhhmm(dt)); - /***********/ - if (panel.chart.xAxis.formatter) { - myDate = panel.chart.xAxis.formatter( - dt, - this.name, - null, - null, - myDate - ); - } else if (this.stx.internationalizer) { - var str; - if (dt.getHours() !== 0 || dt.getMinutes() !== 0) { - str = this.stx.internationalizer.monthDay.format(dt); - str += " " + this.stx.internationalizer.hourMinute.format(dt); - } else { - str = this.stx.internationalizer.yearMonthDay.format(dt); - } - myDate = str; - } - this.stx.endClip(); - this.stx.createXAxisLabel({ - panel: panel, - txt: myDate, - x: x0, - backgroundColor: color, - color: null, - pointed: true, - padding: 2 - }); - this.stx.startClip(panel.name); - } - } - if (this.highlighted) { - var p0Fill = this.highlighted == "p0" ? true : false; - this.littleCircle(context, x0, y0, p0Fill); - } - } - }, - true - ); - - /** - * Speed Resistance Arc drawing tool. - * - * It inherits its properties from {@link CIQ.Drawing.segment} - * @constructor - * @name CIQ.Drawing.speedarc - * @since 2016-09-19 - * @version ChartIQ Advanced Package - */ - CIQ.Drawing.speedarc = function () { - this.name = "speedarc"; - this.printLevels = true; - }; - CIQ.inheritsFrom(CIQ.Drawing.speedarc, CIQ.Drawing.segment); - CIQ.extend( - CIQ.Drawing.speedarc.prototype, - { - defaultOpacity: 0.25, - configs: ["color", "fillColor", "lineWidth", "pattern"], - copyConfig: function () { - this.color = this.stx.currentVectorParameters.currentColor; - this.fillColor = this.stx.currentVectorParameters.fillColor; - this.lineWidth = this.stx.currentVectorParameters.lineWidth; - this.pattern = this.stx.currentVectorParameters.pattern; - }, - intersected: function (tick, value, box) { - if (!this.p0 || !this.p1) return null; // in case invalid drawing (such as from panel that no longer exists) - var pointsToCheck = { 0: this.p0, 1: this.p1 }; - for (var pt in pointsToCheck) { - if ( - this.pointIntersection( - pointsToCheck[pt][0], - pointsToCheck[pt][1], - box - ) - ) { - this.highlighted = "p" + pt; - return { - action: "drag", - point: "p" + pt - }; - } - } - var isIntersected = this.lineIntersection(tick, value, box, this.name); - if (isIntersected) { - this.highlighted = true; - // This object will be used for repositioning - return { - action: "move", - p0: CIQ.clone(this.p0), - p1: CIQ.clone(this.p1), - tick: tick, // save original tick - value: value // save original value - }; - } - - // Just test the box circumscribing the arcs - var left = this.p1[0] - (this.p0[0] - this.p1[0]); - var right = this.p0[0]; - var bottom = this.p1[1]; - var top = this.p0[1]; - - if (tick > Math.max(left, right) || tick < Math.min(left, right)) - return null; - if (value > Math.max(top, bottom) || value < Math.min(top, bottom)) - return null; - this.highlighted = true; - return { - action: "move", - p0: CIQ.clone(this.p0), - p1: CIQ.clone(this.p1), - tick: tick, - value: value - }; - }, - render: function (context) { - var panel = this.stx.panels[this.panelName]; - if (!panel) return; - if (!this.p1) return; - var x0 = this.stx.pixelFromTick(this.p0[0], panel.chart); - var x1 = this.stx.pixelFromTick(this.p1[0], panel.chart); - var y0 = this.stx.pixelFromValueAdjusted(panel, this.p0[0], this.p0[1]); - var y1 = this.stx.pixelFromValueAdjusted(panel, this.p1[0], this.p1[1]); - var isUpTrend = y1 < y0; - var factor = Math.abs((y1 - y0) / (x1 - x0)); - - var color = this.getLineColor(); - context.strokeStyle = color; - var fillColor = this.fillColor; - if (fillColor == "auto" || CIQ.isTransparent(fillColor)) - fillColor = this.stx.defaultColor; - context.fillStyle = fillColor; - if (context.setLineDash) { - context.setLineDash( - CIQ.borderPatternToArray(this.lineWidth, this.pattern) - ); - context.lineDashOffset = 0; //start point in array - } - this.stx.canvasFont("stx_yaxis", context); - for (var i = 1; i < 3; i++) { - var radius = - (Math.abs(this.p1[1] - this.p0[1]) * Math.sqrt(2) * i) / 3; - var value = - this.p1[1] + - radius * (isUpTrend ? -1 : 1) * (panel.yAxis.flipped ? -1 : 1); - var y = this.stx.pixelFromValueAdjusted(panel, this.p0[0], value); - - context.save(); - context.beginPath(); - context.scale(1 / factor, 1); - context.arc( - x1 * factor, - y1, - Math.abs(y - y1), - 0, - Math.PI, - !isUpTrend - ); - context.globalAlpha = this.highlighted ? 1 : this.defaultOpacity; - if (this.pattern != "none") context.stroke(); - context.globalAlpha = 0.1; - context.fill(); - context.restore(); - context.globalAlpha = 1; - if (this.printLevels) { - context.fillStyle = color; - context.textAlign = "center"; - var txt = i + "/3"; - context.fillText(txt, x1, Math.round(y - 5)); - context.fillStyle = fillColor; - } - } - context.textAlign = "left"; - var parameters = { - pattern: this.pattern, - lineWidth: this.lineWidth, - opacity: this.highlighted ? 1 : this.defaultOpacity - }; - this.stx.plotLine( - x0, - x1, - y0, - y1, - color, - "segment", - context, - panel, - parameters - ); - if (context.setLineDash) context.setLineDash([]); - if (this.highlighted) { - var p0Fill = this.highlighted == "p0" ? true : false; - var p1Fill = this.highlighted == "p1" ? true : false; - this.littleCircle(context, x0, y0, p0Fill); - this.littleCircle(context, x1, y1, p1Fill); - } - }, - reconstruct: function (stx, obj) { - this.stx = stx; - this.color = obj.col; - this.fillColor = obj.fc; - this.panelName = obj.pnl; - this.pattern = obj.ptrn; - this.lineWidth = obj.lw; - this.d0 = obj.d0; - this.d1 = obj.d1; - this.tzo0 = obj.tzo0; - this.tzo1 = obj.tzo1; - this.v0 = obj.v0; - this.v1 = obj.v1; - this.adjust(); - }, - serialize: function () { - return { - name: this.name, - pnl: this.panelName, - col: this.color, - fc: this.fillColor, - ptrn: this.pattern, - lw: this.lineWidth, - d0: this.d0, - d1: this.d1, - tzo0: this.tzo0, - tzo1: this.tzo1, - v0: this.v0, - v1: this.v1 - }; - } - }, - true - ); - - /** - * Speed Resistance Lines drawing tool. - * - * It inherits its properties from {@link CIQ.Drawing.speedarc} - * @constructor - * @name CIQ.Drawing.speedline - * @since 2016-09-19 - * @version ChartIQ Advanced Package - */ - CIQ.Drawing.speedline = function () { - this.name = "speedline"; - this.printLevels = true; - }; - CIQ.inheritsFrom(CIQ.Drawing.speedline, CIQ.Drawing.speedarc); - CIQ.extend( - CIQ.Drawing.speedline.prototype, - { - intersected: function (tick, value, box) { - var p0 = this.p0, - p1 = this.p1; - if (!p0 || !p1) return null; // in case invalid drawing (such as from panel that no longer exists) - var pointsToCheck = { 0: p0, 1: p1 }; - for (var pt in pointsToCheck) { - if ( - this.pointIntersection( - pointsToCheck[pt][0], - pointsToCheck[pt][1], - box - ) - ) { - this.highlighted = "p" + pt; - return { - action: "drag", - point: "p" + pt - }; - } - } - var rays = this.rays; - for (var i = 0; i < rays.length; i++) { - if ( - this.lineIntersection( - tick, - value, - box, - "ray", - rays[i][0], - rays[i][1], - true - ) - ) { - this.highlighted = true; - // This object will be used for repositioning - return { - action: "move", - p0: CIQ.clone(p0), - p1: CIQ.clone(p1), - tick: tick, // save original tick - value: value // save original value - }; - } - } - return null; - }, - render: function (context) { - var panel = this.stx.panels[this.panelName]; - if (!panel) return; - if (!this.p1) return; - var x0 = this.stx.pixelFromTick(this.p0[0], panel.chart); - var x1 = this.stx.pixelFromTick(this.p1[0], panel.chart); - var y0 = this.stx.pixelFromValueAdjusted(panel, this.p0[0], this.p0[1]); - var y1 = this.stx.pixelFromValueAdjusted(panel, this.p1[0], this.p1[1]); - this.stx.canvasFont("stx_yaxis", context); // match font from y axis so it looks cohesive - var trendLineColor = this.getLineColor(); - var color = this.color; - if (color == "auto" || CIQ.isTransparent(color)) - color = this.stx.defaultColor; - context.strokeStyle = color; - var fillColor = this.fillColor; - if (fillColor == "auto" || CIQ.isTransparent(fillColor)) - fillColor = this.stx.defaultColor; - context.fillStyle = fillColor; - var parameters = { - pattern: this.pattern, - lineWidth: this.lineWidth, - opacity: this.highlighted ? 1 : this.defaultOpacity - }; - var farX0, farY0; - var levels = ["1", "2/3", "1/3", "3/2", "3"]; - var levelValues = [1, 2 / 3, 1 / 3, 3 / 2, 3]; - var grids = []; - this.rays = []; - for (var i = 0; i < levelValues.length; i++) { - var level = levelValues[i]; - if (level > 1 && !this.extension) continue; - var y = this.stx.pixelFromValueAdjusted( - panel, - this.p0[0], - this.p0[1] - (this.p0[1] - this.p1[1]) * level - ); - var x; - if (level > 1) { - x = CIQ.xIntersection({ x0: x0, x1: x1, y0: y0, y1: y }, y1); - grids.push(x); - } else { - x = CIQ.xIntersection({ x0: x1, x1: x1, y0: y0, y1: y1 }, y); - grids.push(y); - } - //var x=x0+(x1-x0)/level; - //var y=y0-level*(y0-y1); - var farX = level > 1 ? x : x1; - var farY = level > 1 ? y1 : y; - if (!this.confineToGrid) { - farX = panel.left; - if (x1 > x0) farX += panel.width; - farY = ((farX - x0) * (y - y0)) / (x1 - x0) + y0; - } - if (this.printLevels) { - if (level != 1 || this.extension) { - context.fillStyle = color; - var perturbX = 0, - perturbY = 0; - if (y0 > y1) { - perturbY = -5; - context.textBaseline = "bottom"; - } else { - perturbY = 5; - context.textBaseline = "top"; - } - if (x0 > x1) { - perturbX = 5; - context.textAlign = "right"; - } else { - perturbX = -5; - context.textAlign = "left"; - } - if (level > 1) - context.fillText( - levels[i], - x + (this.confineToGrid ? 0 : perturbX), - y1 - ); - else - context.fillText( - levels[i], - x1, - y + (this.confineToGrid ? 0 : perturbY) - ); - context.fillStyle = fillColor; - } - } - this.stx.plotLine( - x0, - farX, - y0, - farY, - this.highlighted ? trendLineColor : color, - "segment", - context, - panel, - parameters - ); - if (level == 1) { - farX0 = farX; - farY0 = farY; - } - this.rays.push([ - [x0, y0], - [farX, farY] - ]); - context.globalAlpha = 0.1; - context.beginPath(); - context.moveTo(farX, farY); - context.lineTo(x0, y0); - context.lineTo(farX0, farY0); - context.fill(); - context.globalAlpha = 1; - } - context.textAlign = "left"; - context.textBaseline = "middle"; - if (this.confineToGrid) { - context.globalAlpha = 0.3; - context.beginPath(); - context.strokeRect(x0, y0, x1 - x0, y1 - y0); - context.moveTo(x0, grids[1]); - context.lineTo(x1, grids[1]); - context.moveTo(x0, grids[2]); - context.lineTo(x1, grids[2]); - if (this.extension) { - context.moveTo(grids[3], y0); - context.lineTo(grids[3], y1); - context.moveTo(grids[4], y0); - context.lineTo(grids[4], y1); - } - context.stroke(); - context.globalAlpha = 1; - } - if (this.highlighted) { - var p0Fill = this.highlighted == "p0" ? true : false; - var p1Fill = this.highlighted == "p1" ? true : false; - this.littleCircle(context, x0, y0, p0Fill); - this.littleCircle(context, x1, y1, p1Fill); - } - } - }, - true - ); - - /** - * Gann Fan drawing tool. - * - * It inherits its properties from {@link CIQ.Drawing.speedarc} - * @constructor - * @name CIQ.Drawing.gannfan - * @since 2016-09-19 - * @version ChartIQ Advanced Package - */ - CIQ.Drawing.gannfan = function () { - this.name = "gannfan"; - this.printLevels = true; - }; - CIQ.inheritsFrom(CIQ.Drawing.gannfan, CIQ.Drawing.speedline); - CIQ.extend( - CIQ.Drawing.gannfan.prototype, - { - render: function (context) { - var panel = this.stx.panels[this.panelName]; - if (!panel) return; - if (!this.p1) return; - var x0 = this.stx.pixelFromTick(this.p0[0], panel.chart); - var x1 = this.stx.pixelFromTick(this.p1[0], panel.chart); - var y0 = this.stx.pixelFromValueAdjusted(panel, this.p0[0], this.p0[1]); - var y1 = this.stx.pixelFromValueAdjusted(panel, this.p1[0], this.p1[1]); - this.stx.canvasFont("stx_yaxis", context); // match font from y axis so it looks cohesive - var trendLineColor = this.getLineColor(); - var color = this.color; - if (color == "auto" || CIQ.isTransparent(color)) - color = this.stx.defaultColor; - context.strokeStyle = color; - var fillColor = this.fillColor; - if (fillColor == "auto" || CIQ.isTransparent(fillColor)) - fillColor = this.stx.defaultColor; - context.fillStyle = fillColor; - var parameters = { - pattern: this.pattern, - lineWidth: this.lineWidth, - opacity: this.highlighted ? 1 : this.defaultOpacity - }; - var farX0, farY0; - var levels = [1, 2, 3, 4, 8, 1 / 2, 1 / 3, 1 / 4, 1 / 8]; - this.rays = []; - for (var i = 0; i < levels.length; i++) { - var level = levels[i]; - var x = x0 + (x1 - x0) / level; - var y = y0 - level * (y0 - y1); - var farX = panel.left; - if (x1 > x0) farX += panel.width; - var farY = ((farX - x0) * (y - y0)) / (x1 - x0) + y0; - if (this.printLevels) { - context.fillStyle = color; - var perturbX = 0, - perturbY = 0; - if (y0 > y1) { - perturbY = 5; - context.textBaseline = "top"; - } else { - perturbY = -5; - context.textBaseline = "bottom"; - } - if (x0 > x1) { - perturbX = 5; - context.textAlign = "left"; - } else { - perturbX = -5; - context.textAlign = "right"; - } - if (level > 1) { - context.fillText(level + "x1", x + perturbX, y1); - } else { - context.fillText("1x" + 1 / level, x1, y + perturbY); - } - context.fillStyle = fillColor; - } - this.stx.plotLine( - x0, - farX, - y0, - farY, - this.highlighted ? trendLineColor : color, - "segment", - context, - panel, - parameters - ); - this.rays.push([ - [x0, y0], - [farX, farY] - ]); - if (level == 1) { - farX0 = farX; - farY0 = farY; - } - context.globalAlpha = 0.1; - context.beginPath(); - context.moveTo(farX, farY); - context.lineTo(x0, y0); - context.lineTo(farX0, farY0); - context.fill(); - context.globalAlpha = 1; - } - context.textAlign = "left"; - context.textBaseline = "middle"; - if (this.highlighted) { - var p0Fill = this.highlighted == "p0" ? true : false; - var p1Fill = this.highlighted == "p1" ? true : false; - this.littleCircle(context, x0, y0, p0Fill); - this.littleCircle(context, x1, y1, p1Fill); - } - } - }, - true - ); - - /** - * Time Cycle drawing tool. - * - * It inherits its properties from {@link CIQ.Drawing.speedarc} - * @constructor - * @name CIQ.Drawing.timecycle - * @since 2016-09-19 - * @version ChartIQ Advanced Package - */ - CIQ.Drawing.timecycle = function () { - this.name = "timecycle"; - this.printLevels = true; - }; - CIQ.inheritsFrom(CIQ.Drawing.timecycle, CIQ.Drawing.speedarc); - CIQ.extend( - CIQ.Drawing.timecycle.prototype, - { - intersected: function (tick, value, box) { - var p0 = this.p0, - p1 = this.p1, - panel = this.stx.panels[this.panelName]; - if (!p0 || !p1 || !panel) return null; // in case invalid drawing (such as from panel that no longer exists) - var pointsToCheck = { 0: p0, 1: p1 }; - for (var pt in pointsToCheck) { - if ( - this.pointIntersection( - pointsToCheck[pt][0], - pointsToCheck[pt][1], - box - ) - ) { - this.highlighted = "p" + pt; - return { - action: "drag", - point: "p" + pt - }; - } - } - // Check for over the trend line or the 0 vertical line - var trendIntersects = this.lineIntersection( - tick, - value, - box, - "segment" - ); - if (trendIntersects || (box.x0 <= this.p0[0] && box.x1 >= p0[0])) { - this.highlighted = true; - return { - action: "move", - p0: CIQ.clone(p0), - p1: CIQ.clone(p1), - tick: tick, // save original tick - value: value // save original value - }; - } - return null; - }, - render: function (context) { - var panel = this.stx.panels[this.panelName]; - if (!panel) return; - if (!this.p1) return; - - var x0 = this.stx.pixelFromTick(this.p0[0], panel.chart); - var x1 = this.stx.pixelFromTick(this.p1[0], panel.chart); - var y0 = this.stx.pixelFromValueAdjusted(panel, this.p0[0], this.p0[1]); - var y1 = this.stx.pixelFromValueAdjusted(panel, this.p1[0], this.p1[1]); - var count = 0; - - var trendLineColor = this.getLineColor(); - context.textBaseline = "middle"; - this.stx.canvasFont("stx_yaxis", context); // match font from y axis so it looks cohesive - var h = 20; // give it extra space so it does not overlap with the date labels. - var mult = this.p1[0] - this.p0[0]; - context.textAlign = "center"; - - var x = x0; - var top = panel.yAxis.top; - var farY = panel.yAxis.bottom; - var color = this.color; - if (color == "auto" || CIQ.isTransparent(color)) - color = this.stx.defaultColor; - var fillColor = this.fillColor; - if (fillColor == "auto" || CIQ.isTransparent(fillColor)) - fillColor = this.stx.defaultColor; - - if (this.printLevels) farY -= h - 7; - - var parameters = { - pattern: this.pattern, - lineWidth: this.lineWidth, - opacity: this.highlighted ? 1 : this.defaultOpacity - }; - - var x_s = []; - context.save(); - context.fillStyle = fillColor; - context.globalAlpha = 0.05; - //context.globalCompositeOperation="destination-over"; - do { - x = this.stx.pixelFromTick(this.p0[0] + count * mult, panel.chart); - count++; - - if (x0 < x1 && x > panel.left + panel.width) break; - else if (x0 > x1 && x < panel.left) break; - else if (x < panel.left || x > panel.left + panel.width) continue; - - context.beginPath(); - context.moveTo(x0, top); - context.lineTo(x, top); - context.lineTo(x, farY); - context.lineTo(x0, farY); - context.fill(); - x_s.push({ c: count, x: x }); - } while (mult); - context.globalAlpha = 1; - var slack = 0; - for (var pt = 0; pt < x_s.length; pt++) { - this.stx.plotLine( - x_s[pt].x, - x_s[pt].x, - 0, - farY, - this.highlighted ? trendLineColor : color, - "segment", - context, - panel, - parameters - ); - if (this.printLevels) { - context.fillStyle = color; - var m = this.stx.chart.context.measureText(x_s[pt].c).width + 3; - if (m < this.stx.layout.candleWidth + slack) { - context.fillText(x_s[pt].c, x_s[pt].x, farY + 7); - slack = 0; - } else { - slack += this.stx.layout.candleWidth; - } - } - } - context.restore(); - context.textAlign = "left"; - - this.stx.plotLine( - x0, - x1, - y0, - y1, - trendLineColor, - "segment", - context, - panel, - parameters - ); - if (this.highlighted) { - var p0Fill = this.highlighted == "p0" ? true : false; - var p1Fill = this.highlighted == "p1" ? true : false; - this.littleCircle(context, x0, y0, p0Fill); - this.littleCircle(context, x1, y1, p1Fill); - } else { - // move points so always accessible - var yVal = this.stx.valueFromPixel(panel.height / 2, panel); - this.setPoint(0, this.p0[0], yVal, panel.chart); - this.setPoint(1, this.p1[0], yVal, panel.chart); - } - } - }, - true - ); - - /** - * Regression Line drawing tool. - * - * It inherits its properties from {@link CIQ.Drawing.segment} - * @constructor - * @name CIQ.Drawing.regression - * @since 2016-09-19 - * @version ChartIQ Advanced Package - */ - CIQ.Drawing.regression = function () { - this.name = "regression"; - }; - CIQ.inheritsFrom(CIQ.Drawing.regression, CIQ.Drawing.segment); - CIQ.extend( - CIQ.Drawing.regression.prototype, - { - configs: [ - // primary line - "color", - "lineWidth", - "pattern", - // stddev * 1 - "active1", - "color1", - "lineWidth1", - "pattern1", - // stddev * 2 - "active2", - "color2", - "lineWidth2", - "pattern2", - // stddev * 3 - "active3", - "color3", - "lineWidth3", - "pattern3" - ], - copyConfig: function (withPreferences) { - CIQ.Drawing.copyConfig(this, withPreferences); - var cvp = this.stx.currentVectorParameters; - this.active1 = !!cvp.active1; - this.active2 = !!cvp.active2; - this.active3 = !!cvp.active3; - this.color1 = cvp.color1 || "auto"; - this.color2 = cvp.color2 || "auto"; - this.color3 = cvp.color3 || "auto"; - this.lineWidth1 = cvp.lineWidth1; - this.lineWidth2 = cvp.lineWidth2; - this.lineWidth3 = cvp.lineWidth3; - this.pattern1 = cvp.pattern1; - this.pattern2 = cvp.pattern2; - this.pattern3 = cvp.pattern3; - }, - $controls: [ - 'cq-cvp-controller[cq-cvp-header="1"]', - 'cq-cvp-controller[cq-cvp-header="2"]', - 'cq-cvp-controller[cq-cvp-header="3"]' - ], - click: function (context, tick, value) { - if (tick < 0) return; - this.copyConfig(); - var panel = this.stx.panels[this.panelName]; - if (!this.penDown) { - this.setPoint(0, tick, value, panel.chart); - this.penDown = true; - var stx = this.stx; - this.field = stx.highlightedDataSetField; - if (!this.field && panel != stx.chart.panel) { - for (var sr in stx.chart.seriesRenderers) { - var renderer = stx.chart.seriesRenderers[sr]; - if (renderer.params.panel == panel.name) { - this.field = renderer.seriesParams[0].field; - break; - } - } - for (var st in stx.layout.studies) { - var study = stx.layout.studies[st]; // find a default study on this panel - if (study.panel == panel.name) { - this.field = Object.keys(study.outputMap)[0]; - break; - } - } - } - return false; - } - if (this.accidentalClick(tick, value)) return this.dragToDraw; - - this.setPoint(1, tick, value, panel.chart); - this.penDown = false; - return true; // kernel will call render after this - }, - // Returns both the transformed and untransformed value of the drawing's field attribute - getYValue: function (i) { - var record = this.stx.chart.dataSet[i], - transformedRecord = this.stx.chart.dataSet[i]; - if (!record) return null; - - var panel = this.stx.panels[this.panelName]; - var yAxis = this.stx.getYAxisByField(panel, this.field) || panel.yAxis; - if ( - this.stx.charts[panel.name] && - panel.chart.transformFunc && - yAxis == panel.yAxis - ) - transformedRecord = record.transform; - if (!transformedRecord) return null; - - var price = null, - transformedPrice = null, - defaultField = this.stx.defaultPlotField || "Close"; - if (this.field) { - transformedPrice = CIQ.existsInObjectChain( - transformedRecord, - this.field - ); - if (!transformedPrice) return null; - price = transformedPrice = - transformedPrice.obj[transformedPrice.member]; - if (record != transformedRecord) { - price = CIQ.existsInObjectChain(record, this.field); - price = price.obj[price.member]; - } - if (typeof transformedPrice == "object") { - transformedPrice = transformedPrice[defaultField]; - price = price[defaultField]; - } - } else { - transformedPrice = transformedRecord[defaultField]; - price = record[defaultField]; - } - return { transformed: transformedPrice, untransformed: price }; - }, - render: function (context) { - var panel = this.stx.panels[this.panelName]; - if (!panel) return; - if (!this.p1) return; - if (this.p0[0] < 0 || this.p1[0] < 0) return; - var x0 = this.stx.pixelFromTick(this.p0[0], panel.chart); - var x1 = this.stx.pixelFromTick(this.p1[0], panel.chart); - if (x0 < panel.left && x1 < panel.left) return; - if (x0 > panel.right && x1 > panel.right) return; - var yAxis = this.stx.getYAxisByField(panel, this.field); - - var prices = [], - rawPrices = []; // rawPrices used solely for measure - var sumCloses = 0, - sumRawCloses = 0; - var sumWeightedCloses = 0, - sumWeightedRawCloses = 0; - var start = Math.min(this.p1[0], this.p0[0]); - var end = Math.max(this.p1[0], this.p0[0]) + 1; - var rawTicks = end - start; - for (var i = start; i < end; i++) { - var price = this.getYValue(i); - if (price) { - prices.push(price.transformed); - rawPrices.push(price.untransformed); - } - } - - var ticks = prices.length; - var sumWeights = (ticks * (ticks + 1)) / 2; - var squaredSumWeights = Math.pow(sumWeights, 2); - var sumWeightsSquared = (sumWeights * (2 * ticks + 1)) / 3; - - for (i = 0; i < ticks; i++) { - sumWeightedCloses += ticks * prices[i] - sumCloses; - sumCloses += prices[i]; - sumWeightedRawCloses += ticks * rawPrices[i] - sumRawCloses; - sumRawCloses += rawPrices[i]; - } - - var slope = - (ticks * sumWeightedCloses - sumWeights * sumCloses) / - (ticks * sumWeightsSquared - squaredSumWeights); - var intercept = (sumCloses - slope * sumWeights) / ticks; - var rawSlope = - (ticks * sumWeightedRawCloses - sumWeights * sumRawCloses) / - (ticks * sumWeightsSquared - squaredSumWeights); - var rawIntercept = (sumRawCloses - slope * sumWeights) / ticks; - var v0, v1; - if (this.p0[0] < this.p1[0]) { - v0 = intercept; - v1 = slope * rawTicks + intercept; - this.p0[1] = rawIntercept; - this.p1[1] = rawSlope * rawTicks + rawIntercept; - } else { - v0 = slope * rawTicks + intercept; - v1 = intercept; - this.p0[1] = rawSlope * rawTicks + rawIntercept; - this.p1[1] = rawIntercept; - } - - var y0 = this.stx.pixelFromTransformedValue(v0, panel, yAxis); - var y1 = this.stx.pixelFromTransformedValue(v1, panel, yAxis); - var trendLineColor = this.getLineColor(); - var parameters = { - pattern: this.pattern, - lineWidth: this.lineWidth - }; - this.stx.plotLine( - x0, - x1, - y0, - y1, - trendLineColor, - "segment", - context, - panel, - parameters - ); - this.stx.plotLine( - x0, - x0, - y0 - 20, - y0 + 20, - trendLineColor, - "segment", - context, - panel, - parameters - ); - this.stx.plotLine( - x1, - x1, - y1 - 20, - y1 + 20, - trendLineColor, - "segment", - context, - panel, - parameters - ); - - if (this.active1 || this.active2 || this.active3) { - var average = sumCloses / ticks; - var sumStddev = 0; - - for (i = 0; i < ticks; i++) { - sumStddev += Math.pow(prices[i] - average, 2); - } - - var stddev = Math.sqrt(sumStddev / ticks); - var params = { - context: context, - panel: panel, - points: { - 0: { x: x0, v: v0 }, - 1: { x: x1, v: v1 } - }, - stddev: stddev, - yAxis: yAxis - }; - - this.lines = {}; - - if (this.active1) { - this.renderStddev("1", "p", params); - this.renderStddev("1", "n", params); - } - - if (this.active2) { - this.renderStddev("2", "p", params); - this.renderStddev("2", "n", params); - } - - if (this.active3) { - this.renderStddev("3", "p", params); - this.renderStddev("3", "n", params); - } - } - - if (!this.highlighted) { - this.pixelX = [x0, x1]; - this.pixelY = [y0, y1]; - } else { - var p0Fill = this.highlighted == "p0" ? true : false; - var p1Fill = this.highlighted == "p1" ? true : false; - this.littleCircle(context, x0, y0, p0Fill); - this.littleCircle(context, x1, y1, p1Fill); - } - }, - renderStddev: function (scope, sign, parameters) { - var name = "stddev" + scope + sign; - var colorKey = "color" + scope; - var patternKey = "pattern" + scope; - var lineWidthKey = "lineWidth" + scope; - var points = parameters.points; - var v0 = points[0].v; - var v1 = points[1].v; - var stddev = parameters.stddev; - var stddevMult = sign === "n" ? scope * -1 : scope * 1; - var stx = this.stx; - var panel = parameters.panel; - var yAxis = parameters.yAxis; - var line = { - name: name, - color: this.getLineColor(this[colorKey]), - type: "segment", - y0: stx.pixelFromTransformedValue( - v0 + stddev * stddevMult, - panel, - yAxis - ), - y1: stx.pixelFromTransformedValue( - v1 + stddev * stddevMult, - panel, - yAxis - ), - params: { - pattern: this[patternKey], - lineWidth: this[lineWidthKey] - } - }; - - // set line for intersected method - if (this.lines) { - this.lines[name] = line; - } - - var context = parameters.context; - var x0 = points[0].x; - var x1 = points[1].x; - - stx.plotLine( - x0, - x1, - line.y0, - line.y1, - line.color, - line.type, - context, - panel, - line.params - ); - stx.plotLine( - x0, - x0, - line.y0 - 10, - line.y0 + 10, - line.color, - line.type, - context, - panel, - line.params - ); - stx.plotLine( - x1, - x1, - line.y1 - 10, - line.y1 + 10, - line.color, - line.type, - context, - panel, - line.params - ); - - var label = scope + "\u03c3"; - var labelX = Math.max(x0, x1) + 5; - var labelY = x0 < x1 ? line.y1 : line.y0; - - context.fillStyle = line.color; - context.save(); - context.textBaseline = "middle"; - context.fillText(label, labelX, labelY); - context.restore(); - - // derived class `average` has an axisLabel - if ( - parameters.formatPrice && - this.axisLabel && - !this.highlighted && - !this.penDown - ) { - if ( - (x0 >= panel.chart.left && x0 <= panel.chart.right) || - (x1 >= panel.chart.left && x1 <= panel.chart.right) - ) { - var displayPrice = (x0 < x1 ? v1 : v0) + stddev * stddevMult; - stx.endClip(); - stx.createYAxisLabel( - panel, - parameters.formatPrice(displayPrice, yAxis), - labelY, - line.color, - null, - context, - yAxis - ); - stx.startClip(panel.name); - } - } - }, - intersected: function (tick, value, box) { - if (!this.pixelX || !this.pixelY) return null; - - var repositionIntersection = this.repositionIntersection(tick, value); - if (repositionIntersection) return repositionIntersection; - - // check for point intersection - var pointsToCheck = { 0: this.pixelX, 1: this.pixelY }; - for (var pt = 0; pt < 2; pt++) { - if ( - this.pointIntersection( - pointsToCheck[0][pt], - pointsToCheck[1][pt], - box, - true - ) - ) { - this.highlighted = "p" + pt; - return { - action: "drag", - point: "p" + pt - }; - } - } - - // check for line intersection - var self = this; - var x0 = this.pixelX[0]; - var x1 = this.pixelX[1]; - var lineIntersection = function (line) { - var p0 = [x0, line.y0]; - var p1 = [x1, line.y1]; - - return self.lineIntersection( - tick, - value, - box, - self.name, - p0, - p1, - true - ); - }; - var isIntersected = lineIntersection({ - y0: this.pixelY[0], - y1: this.pixelY[1] - }); - - if (!isIntersected && this.lines) { - for (var key in this.lines) { - if (lineIntersection(this.lines[key])) { - isIntersected = true; - break; - } - } - } - - if (isIntersected) { - this.highlighted = true; - // This object will be used for repositioning - return { - action: "move", - p0: CIQ.clone(this.p0), - p1: CIQ.clone(this.p1), - tick: tick, // save original tick - value: value // save original value - }; - } - - return null; - }, - repositionIntersection: function (tick, value) { - if (!this.p0 || !this.p1) return false; // in case invalid drawing (such as from panel that no longer exists) - if (this == this.stx.repositioningDrawing && this.highlighted) { - // already moving or dragging, continue - if (this.highlighted === true) { - return { - action: "move", - p0: CIQ.clone(this.p0), - p1: CIQ.clone(this.p1), - tick: tick, // save original tick - value: value // save original value - }; - } - return { - action: "drag", - point: this.highlighted - }; - } - return false; - }, - lineIntersection: function (tick, value, box, type, p0, p1, isPixels) { - if (!isPixels) { - console.log( - type + - " lineIntersection must accept p0 and p1 in pixels. Please verify and set isPixels=true." - ); - return false; - } - if (!p0) p0 = this.p0; - if (!p1) p1 = this.p1; - if (!(p0 && p1)) return false; - var stx = this.stx; - var pixelBox = CIQ.convertBoxToPixels(stx, this.panelName, box); - if (pixelBox.x0 === undefined) return false; - var pixelPoint = { x0: p0[0], x1: p1[0], y0: p0[1], y1: p1[1] }; - return CIQ.boxIntersects( - pixelBox.x0, - pixelBox.y0, - pixelBox.x1, - pixelBox.y1, - pixelPoint.x0, - pixelPoint.y0, - pixelPoint.x1, - pixelPoint.y1 - ); - }, - boxIntersection: function (tick, value, box) { - if ( - box.cx0 > Math.max(this.pixelX[0], this.pixelX[1]) || - box.cx1 < Math.min(this.pixelX[0], this.pixelX[1]) - ) - return false; - if ( - !this.stx.repositioningDrawing && - (box.cy1 < this.pixelY[0] || box.cy0 > this.pixelY[1]) - ) - return false; - return true; - }, - reconstruct: function (stx, obj) { - this.stx = stx; - this.color = obj.col; - this.color1 = obj.col1; - this.color2 = obj.col2; - this.color3 = obj.col3; - this.active1 = obj.dev1; - this.active2 = obj.dev2; - this.active3 = obj.dev3; - this.panelName = obj.pnl; - this.pattern = obj.ptrn; - this.pattern1 = obj.ptrn1; - this.pattern2 = obj.ptrn2; - this.pattern3 = obj.ptrn3; - this.lineWidth = obj.lw; - this.lineWidth1 = obj.lw1; - this.lineWidth2 = obj.lw2; - this.lineWidth3 = obj.lw3; - this.d0 = obj.d0; - this.d1 = obj.d1; - this.tzo0 = obj.tzo0; - this.tzo1 = obj.tzo1; - this.field = obj.fld; - this.adjust(); - }, - serialize: function () { - return { - name: this.name, - pnl: this.panelName, - dev1: this.active1, - dev2: this.active2, - dev3: this.active3, - col: this.color, - col1: this.color1, - col2: this.color2, - col3: this.color3, - ptrn: this.pattern, - ptrn1: this.pattern1, - ptrn2: this.pattern2, - ptrn3: this.pattern3, - lw: this.lineWidth, - lw1: this.lineWidth1, - lw2: this.lineWidth2, - lw3: this.lineWidth3, - d0: this.d0, - d1: this.d1, - tzo0: this.tzo0, - tzo1: this.tzo1, - fld: this.field - }; - } - }, - true - ); - - /** - * trendline is an implementation of a {@link CIQ.Drawing.segment} drawing. - * - * Extends {@link CIQ.Drawing.segment} and automatically renders a {@link CIQ.Drawing.callout} - * containing trend information. - * @constructor - * @name CIQ.Drawing.trendline - * @since 5.1.2 - * @version ChartIQ Advanced Package - */ - CIQ.Drawing.trendline = function () { - this.name = "trendline"; - }; - - CIQ.inheritsFrom(CIQ.Drawing.trendline, CIQ.Drawing.segment); - - // allow configuration of font for trendline info in callout, which is then assigned later - CIQ.Drawing.trendline.prototype.configs = [ - "color", - "fillColor", - "lineWidth", - "pattern", - "font" - ]; - - CIQ.Drawing.trendline.prototype.measure = function () { - // empty function since the text will now display in a callout - }; - - CIQ.Drawing.trendline.prototype.reconstruct = function (stx, obj) { - // reconstruct segment as usual, then add callout as property - CIQ.Drawing.segment.prototype.reconstruct.call(this, stx, obj); - this.callout = new CIQ.Drawing.callout(); - this.callout.reconstruct(stx, obj.callout); - }; - - CIQ.Drawing.trendline.prototype.serialize = function () { - // serialize segment as usual, then add callout as property - var obj = CIQ.Drawing.segment.prototype.serialize.call(this); - obj.callout = this.callout.serialize(); - return obj; - }; - - CIQ.Drawing.trendline.prototype.render = function (context) { - var panel = this.stx.panels[this.panelName]; - if (!panel) return; - - // render segment as usual - CIQ.Drawing.segment.prototype.render.call(this, context); - - // only create and initialize callout once - if (!this.callout) { - this.callout = new CIQ.Drawing.callout(); - var obj = CIQ.Drawing.segment.prototype.serialize.call(this); - this.callout.reconstruct(this.stx, obj); - } - - // always render the callout perpendicular above / below the segment / trendline - this.callout.p0 = CIQ.clone(this.p0); - - // extract segment coordinates - var x0 = this.stx.pixelFromTick(this.p0[0], panel.chart); - var x1 = this.stx.pixelFromTick(this.p1[0], panel.chart); - var y0 = this.stx.pixelFromValueAdjusted(panel, this.p0[0], this.p0[1]); - var y1 = this.stx.pixelFromValueAdjusted(panel, this.p1[0], this.p1[1]); - - // return if we are off the screen axes else insanity ensues - if (!isFinite(y0) || !isFinite(y1)) return; - - // calculate midpoint (for stem of callout) - var xmid = (x0 + x1) / 2; - var ymid = (y0 + y1) / 2; - - // determine length of segment and multiplier / direction of normal vector to give fixed length depending on stem location - this.fontSize = CIQ.stripPX((this.font && this.font.size) || 13); - var stemDist = - this.callout.w * 1.2 + (this.callout.stemEntry[0] == "c" ? 0 : 50); - var segmentDist = Math.sqrt(Math.pow(x1 - x0, 2) + Math.pow(y1 - y0, 2)); - var scalar = - (stemDist / (segmentDist || stemDist)) * - (this.p1[1] < this.p0[1] ? 1 : -1); - - // normal vector (see e.g. http://mathworld.wolfram.com/NormalVector.html) - var nX = -(y1 - ymid) * scalar + xmid; - var nY = (x1 - xmid) * scalar + ymid; - - // assign callout coordinates - this.callout.p0[0] = this.stx.tickFromPixel(nX, panel.chart); - this.callout.p0[1] = this.stx.priceFromPixel(nY, panel); - this.callout.v0 = this.callout.p0[1]; - this.callout.p1 = CIQ.clone(this.p0); - - // assign callout properties - this.callout.stx = this.stx; - this.callout.fillColor = this.fillColor || this.callout.fillColor; - this.callout.borderColor = this.color; - this.callout.font = this.font || this.callout.font; - this.callout.noHandles = true; - - // calculate trend and assign to callout text; only show percent if not Inf - var deltaV = this.p1[1] - this.p0[1]; - this.callout.text = - "" + - Number(deltaV).toFixed(2) + - (this.p0[1] === 0 - ? "" - : " (" + Number((100 * deltaV) / this.p0[1]).toFixed(2) + "%) ") + - "" + - Math.abs(this.p1[0] - this.p0[0]) + - " Bars"; - - // calculate stem as midpoint of segment - var midtickIdx = Math.floor((this.p0[0] + this.p1[0]) / 2), - midV; - if ( - Math.abs(this.p0[0] - this.p1[0]) > 1 && - Math.abs(this.p0[0] - this.p1[0]) < 20 - ) { - // because of math.floor, we may be grabbing a bar off of center, - // so calculate price based on slope of trendline - var midtickXpixel = this.stx.pixelFromTick(midtickIdx, panel.chart); - var midtickYpixel = y0 + ((y1 - y0) / (x1 - x0)) * (midtickXpixel - x0); - midV = this.stx.priceFromPixel(midtickYpixel, panel) || ymid; - } else { - midV = this.stx.priceFromPixel(ymid, panel); - } - - this.callout.stem = { - t: midtickIdx, - v: midV - }; - - // render callout and text - this.callout.renderText(); - this.callout.render(context); - - // paint the handle circles based on highlighting - if (this.highlighted) { - var p0Fill = this.highlighted == "p0" ? true : false; - var p1Fill = this.highlighted == "p1" ? true : false; - this.littleCircle(context, x0, y0, p0Fill); - this.littleCircle(context, x1, y1, p1Fill); - } - }; - - CIQ.Drawing.trendline.prototype.lineIntersection = function ( - tick, - value, - box, - type - ) { - // override type as segment to preserve lineIntersection functionality - return CIQ.Drawing.BaseTwoPoint.prototype.lineIntersection.call( - this, - tick, - value, - box, - "segment" - ); - }; - - CIQ.Drawing.trendline.prototype.intersected = function (tick, value, box) { - // in case invalid drawing (such as from panel that no longer exists) - if (!this.p0 || !this.p1) return null; - - // call and store intersection methods on both callout and segment - var calloutIntersected = this.callout.intersected(tick, value, box); - var segmentIntersected = CIQ.Drawing.segment.prototype.intersected.call( - this, - tick, - value, - box - ); - - // synchronize highlighting - this.callout.highlighted = !!(calloutIntersected || segmentIntersected); - //this.highlighted = segmentIntersected || calloutIntersected; - - if (segmentIntersected) { - // If segment is highlighted, return as usual; - return segmentIntersected; - } else if (calloutIntersected) { - // Otherwise, if callout is highlighted, move segment (callout will follow / rerender) - return { - action: "move", - p0: CIQ.clone(this.p0), - p1: CIQ.clone(this.p1), - tick: tick, // save original tick - value: value // save original value - }; - } - - // neither are intersected - return null; - }; - - /** - * Average Line drawing tool. - * - * It inherits its properties from {@link CIQ.Drawing.regression} - * @constructor - * @name CIQ.Drawing.average - * @since 4.0.0 - * @version ChartIQ Advanced Package - */ - CIQ.Drawing.average = function () { - this.name = "average"; - }; - CIQ.inheritsFrom(CIQ.Drawing.average, CIQ.Drawing.regression); - CIQ.extend( - CIQ.Drawing.average.prototype, - { - configs: CIQ.Drawing.regression.prototype.configs.concat("axisLabel"), - measure: function () { - if (this.p0 && this.p1) { - this.stx.setMeasure( - 0, - false, - this.p0[0], - this.p1[0], - true, - this.name - ); - var txt = [], - html = ""; - if (this.active1) txt.push("1"); - if (this.active2) txt.push("2"); - if (this.active3) txt.push("3"); - if (txt.length) html = " " + txt.join(", ") + " σ"; - var mMeasure = (this.stx.drawingContainer || document).querySelector( - ".mMeasure" - ); - var mSticky = this.stx.controls.mSticky; - var mStickyInterior = - mSticky && mSticky.querySelector(".mStickyInterior"); - if (mMeasure) mMeasure.innerHTML += html; - if (mStickyInterior) { - var lines = []; - lines.push(CIQ.capitalize(this.name)); - lines.push(this.field || this.stx.defaultPlotField || "Close"); - lines.push(mStickyInterior.innerHTML + html); - mStickyInterior.innerHTML = lines.join("
"); - } - } - }, - render: function (context) { - var panel = this.stx.panels[this.panelName]; - if (!panel) return; - if (!this.p1) return; - if (this.p0[0] < 0 || this.p1[0] < 0) return; - var x0 = this.stx.pixelFromTick(this.p0[0], panel.chart); - var x1 = this.stx.pixelFromTick(this.p1[0], panel.chart); - if (x0 < panel.left && x1 < panel.left) return; - if (x0 > panel.right && x1 > panel.right) return; - var yAxis = this.stx.getYAxisByField(panel, this.field); - - var stx = this.stx; - var start = Math.min(this.p1[0], this.p0[0]); - var end = Math.max(this.p1[0], this.p0[0]) + 1; - var rawTicks = end - start; - var sumCloses = 0; - var prices = []; - var i, price; - - for (i = start; i < end; i++) { - price = this.getYValue(i); - if (price !== null) { - sumCloses += price.transformed; - prices.push(price); - } - } - - var validTicks = prices.length; - if (!validTicks) return; - - var average = sumCloses / validTicks; - var y = stx.pixelFromTransformedValue(average, panel, yAxis); - var color = this.getLineColor(); - var params = { - pattern: this.pattern, - lineWidth: this.lineWidth - }; - - stx.plotLine(x0, x1, y, y, color, "segment", context, panel, params); - stx.plotLine( - x0, - x0, - y - 20, - y + 20, - color, - "segment", - context, - panel, - params - ); - stx.plotLine( - x1, - x1, - y - 20, - y + 20, - color, - "segment", - context, - panel, - params - ); - - function formatPrice(price, yAxis) { - if (yAxis && yAxis.priceFormatter) - price = yAxis.priceFormatter(stx, panel, price); - else price = stx.formatYAxisPrice(price, panel, null, yAxis); - return price; - } - - if (this.axisLabel && !this.highlighted && !this.penDown) { - if ( - (x0 >= panel.chart.left && x0 <= panel.chart.right) || - (x1 >= panel.chart.left && x1 <= panel.chart.right) - ) { - stx.endClip(); - stx.createYAxisLabel( - panel, - formatPrice(average, yAxis), - y, - color, - null, - context, - yAxis - ); - stx.startClip(panel.name); - } - } - - if (this.active1 || this.active2 || this.active3) { - var sumStddev = 0; - for (i = 0; i < validTicks; i++) { - price = prices[i]; - sumStddev += Math.pow(price.transformed - average, 2); - } - var stddev = Math.sqrt(sumStddev / validTicks); - var parameters = { - context: context, - formatPrice: formatPrice, - panel: panel, - points: { - 0: { x: x0, v: average }, - 1: { x: x1, v: average } - }, - stddev: stddev, - yAxis: yAxis - }; - - this.lines = {}; - - if (this.active1) { - this.renderStddev("1", "p", parameters); - this.renderStddev("1", "n", parameters); - } - - if (this.active2) { - this.renderStddev("2", "p", parameters); - this.renderStddev("2", "n", parameters); - } - - if (this.active3) { - this.renderStddev("3", "p", parameters); - this.renderStddev("3", "n", parameters); - } - } - - if (!this.highlighted) { - this.pixelX = [x0, x1]; - this.pixelY = [y, y]; - } else { - var p0Fill = this.highlighted == "p0" ? true : false; - var p1Fill = this.highlighted == "p1" ? true : false; - this.littleCircle(context, x0, y, p0Fill); - this.littleCircle(context, x1, y, p1Fill); - } - }, - reconstruct: function (stx, obj) { - this.axisLabel = obj.al; - CIQ.Drawing.regression.prototype.reconstruct.call(this, stx, obj); - }, - serialize: function () { - var obj = CIQ.Drawing.regression.prototype.serialize.call(this); - obj.al = this.axisLabel; - return obj; - } - }, - true - ); - - /** - * Quadrant Lines drawing tool. - * - * It inherits its properties from {@link CIQ.Drawing.speedarc} - * @constructor - * @name CIQ.Drawing.quadrant - * @since 2016-09-19 - * @version ChartIQ Advanced Package - */ - CIQ.Drawing.quadrant = function () { - this.name = "quadrant"; - }; - CIQ.inheritsFrom(CIQ.Drawing.quadrant, CIQ.Drawing.regression); - CIQ.extend( - CIQ.Drawing.quadrant.prototype, - { - configs: ["color", "fillColor", "lineWidth", "pattern"], - copyConfig: function () { - this.color = this.stx.currentVectorParameters.currentColor; - this.fillColor = this.stx.currentVectorParameters.fillColor; - this.lineWidth = this.stx.currentVectorParameters.lineWidth; - this.pattern = this.stx.currentVectorParameters.pattern; - }, - // turn off cvp controls used by regression - $controls: [], - render: function (context) { - var stx = this.stx; - var panel = stx.panels[this.panelName]; - if (!panel) return; - if (!this.p1) return; - var x0 = stx.pixelFromTick(this.p0[0], panel.chart); - var x1 = stx.pixelFromTick(this.p1[0], panel.chart); - if (x0 < panel.left && x1 < panel.left) return; - if (x0 > panel.right && x1 > panel.right) return; - var yAxis = this.stx.getYAxisByField(panel, this.field); - - var highest = null, - lowest = null; - for ( - var i = Math.min(this.p1[0], this.p0[0]); - i <= Math.max(this.p1[0], this.p0[0]); - i++ - ) { - var price = this.getYValue(i); - if (price !== null) { - if (highest === null || price.transformed > highest) { - highest = price.transformed; - } - if (lowest === null || price.transformed < lowest) { - lowest = price.transformed; - } - } - } - - var y0 = stx.pixelFromTransformedValue(highest, panel, yAxis); - var y25 = stx.pixelFromTransformedValue( - (3 * highest + lowest) / 4, - panel, - yAxis - ); - var y33 = stx.pixelFromTransformedValue( - (2 * highest + lowest) / 3, - panel, - yAxis - ); - var y50 = stx.pixelFromTransformedValue( - (highest + lowest) / 2, - panel, - yAxis - ); - var y66 = stx.pixelFromTransformedValue( - (highest + 2 * lowest) / 3, - panel, - yAxis - ); - var y75 = stx.pixelFromTransformedValue( - (highest + 3 * lowest) / 4, - panel, - yAxis - ); - var y100 = stx.pixelFromTransformedValue(lowest, panel, yAxis); - - this.p0[1] = 0; - this.p1[1] = false; // only used for setMeasure - - var trendLineColor = this.getLineColor(); - - var fillColor = this.fillColor; - if (fillColor == "auto" || CIQ.isTransparent(fillColor)) - fillColor = stx.defaultColor; - context.fillStyle = fillColor; - - var parameters = { - pattern: this.pattern, - lineWidth: this.lineWidth - }; - stx.plotLine( - x0, - x1, - y0, - y0, - trendLineColor, - "segment", - context, - panel, - parameters - ); - stx.plotLine( - x0, - x1, - y100, - y100, - trendLineColor, - "segment", - context, - panel, - parameters - ); - if (this.name == "quadrant") { - stx.plotLine( - x0, - x1, - y25, - y25, - trendLineColor, - "segment", - context, - panel, - parameters - ); - stx.plotLine( - x0, - x1, - y75, - y75, - trendLineColor, - "segment", - context, - panel, - parameters - ); - } else if (this.name == "tirone") { - stx.plotLine( - x0, - x1, - y33, - y33, - trendLineColor, - "segment", - context, - panel, - parameters - ); - stx.plotLine( - x0, - x1, - y66, - y66, - trendLineColor, - "segment", - context, - panel, - parameters - ); - } - stx.plotLine( - x0, - x0, - y0, - y100, - trendLineColor, - "segment", - context, - panel, - parameters - ); - stx.plotLine( - x1, - x1, - y0, - y100, - trendLineColor, - "segment", - context, - panel, - parameters - ); - stx.plotLine( - x0, - x1, - y50, - y50, - trendLineColor, - "segment", - context, - panel, - CIQ.extend(parameters, { opacity: this.name == "tirone" ? 0.2 : 1 }) - ); - - context.globalAlpha = 0.1; - context.beginPath(); - context.fillRect(x0, y0, x1 - x0, y100 - y0); - if (this.name == "quadrant") { - context.fillRect(x0, y25, x1 - x0, y75 - y25); - } else if (this.name == "tirone") { - context.fillRect(x0, y33, x1 - x0, y66 - y33); - } - context.globalAlpha = 1; - - if (!this.highlighted) { - //move points - this.pixelX = [x0, x1]; - this.pixelY = [y0, y100, y50]; - if (this.name === "quadrant") this.pixelY.push(y25, y75); - if (this.name === "tirone") this.pixelY.push(y33, y66); - } else { - var p0Fill = this.highlighted == "p0" ? true : false; - var p1Fill = this.highlighted == "p1" ? true : false; - this.littleCircle(context, x0, y50, p0Fill); - this.littleCircle(context, x1, y50, p1Fill); - } - }, - intersected: function (tick, value, box) { - const { pixelX, pixelY } = this; - if (!pixelX || !pixelY) return null; - - const repositionIntersection = this.repositionIntersection(tick, value); - if (repositionIntersection) return repositionIntersection; - - // check for point intersection - for (let pt = 0; pt < 2; pt++) { - if (this.pointIntersection(pixelX[pt], pixelY[2], box, true)) { - this.highlighted = "p" + pt; - return { - action: "drag", - point: "p" + pt - }; - } - } - - const lines = []; - pixelX.forEach((x) => { - lines.push({ p0: [x, pixelY[0]], p1: [x, pixelY[1]] }); - }); - pixelY.forEach((y) => { - lines.push({ p0: [pixelX[0], y], p1: [pixelX[1], y] }); - }); - - const anyIntersected = lines.some(({ p0, p1 }) => { - return this.lineIntersection( - tick, - value, - box, - this.name, - p0, - p1, - true - ); - }); - - if (anyIntersected) { - this.highlighted = true; - return { - action: "move", - p0: CIQ.clone(this.p0), - p1: CIQ.clone(this.p1), - tick: tick, - value: value - }; - } - return null; - }, - reconstruct: function (stx, obj) { - this.stx = stx; - this.color = obj.col; - this.fillColor = obj.fc; - this.panelName = obj.pnl; - this.pattern = obj.ptrn; - this.lineWidth = obj.lw; - this.d0 = obj.d0; - this.d1 = obj.d1; - this.tzo0 = obj.tzo0; - this.tzo1 = obj.tzo1; - this.field = obj.fld; - this.adjust(); - }, - serialize: function () { - return { - name: this.name, - pnl: this.panelName, - col: this.color, - fc: this.fillColor, - ptrn: this.pattern, - lw: this.lineWidth, - d0: this.d0, - d1: this.d1, - tzo0: this.tzo0, - tzo1: this.tzo1, - fld: this.field - }; - } - }, - true - ); - - /** - * Tirone Levels drawing tool. - * - * It inherits its properties from {@link CIQ.Drawing.quadrant} - * @constructor - * @name CIQ.Drawing.tirone - * @since 2016-09-19 - * @version ChartIQ Advanced Package - */ - CIQ.Drawing.tirone = function () { - this.name = "tirone"; - }; - CIQ.inheritsFrom(CIQ.Drawing.tirone, CIQ.Drawing.quadrant); - - /** - * Creates the Elliott Wave drawing tool. - * - * @property {Array} points Contains a sub-array of ticks and values for each point. - * @property {Array} pts Contains a sub-array of pixel positions for the (x, y) coordinates of - * a point and the (x, y) annotation origin point. - * @property {Array} annotationPoints Contains an annotation for each point along the wave. - * The length of the wave is determined by the length of this array. Always starts with 0. - * @property {number} [dx=0] X-axis offset value away from the point that determines the - * x-coordinate origin of the annotaion. - * @property {number} [dy=-20] Y-axis offset value away from the point that determines the - * y-coordinate origin of the annotation. - * @property {Boolean} dragToDraw=false Sets the drawing mode to multi-point-draw rather than - * drag-to-draw. Elliott waves are multiple-point drawings; and so, are incompatible with - * dragging to draw points. See {@link CIQ.Drawing#dragToDraw}. - * @property {number} enclosedRadius The width of the largest text string enclosed in the - * wave annotations. By default `undefined`. - * See {@link CIQ.Drawing.elliottwave#calculateRadius}. - * - * @constructor - * @name CIQ.Drawing.elliottwave - * @since 7.4.0 - */ - CIQ.Drawing.elliottwave = function () { - this.name = "elliottwave"; - this.lastPoint = 0; - this.points = []; - this.pts = []; - this.dx = 0; - this.dy = -20; - this.dragToDraw = false; - this.annotationPoints = []; - this.edit = null; - }; - - CIQ.inheritsFrom(CIQ.Drawing.elliottwave, CIQ.Drawing.annotation); - - CIQ.Drawing.elliottwave.defaultTemplate = { - impulse: ["I", "II", "III", "IV", "V"], - corrective: ["A", "B", "C"], - decoration: "enclosed", - showLines: true - }; - - CIQ.Drawing.elliottwave.prototype.initializeSettings = function (stx) { - stx.currentVectorParameters.waveParameters = CIQ.clone( - CIQ.Drawing.elliottwave.defaultTemplate - ); - }; - - /** - * The initial configuration settings of the drawing. - * - * @memberof CIQ.Drawing.elliottwave - * @since 7.4.0 - * @private - */ - CIQ.Drawing.elliottwave.prototype.configs = [ - "color", - "lineWidth", - "lineColor", - "pattern", - "font", - "waveParameters" - ]; - - /** - * The query strings that are activated by the {@link CIQ.UI.DrawingSettings} component. - * - * @memberof CIQ.Drawing.elliottwave - * @since 7.4.0 - * @private - */ - CIQ.Drawing.elliottwave.prototype.$controls = [ - "br[cq-wave-parameters]", - "cq-wave-parameters" - ]; - - /** - * Initializes the drawing. Assigns the `waveParameters` object of - * {@link CIQ.ChartEngine#currentVectorParameters} to the current drawing instance. - * - * @param {CIQ.ChartEngine} stx A reference to the chart engine. - * @param {CIQ.ChartEngine.Panel} panel The panel that contains the drawing. - * @memberOf CIQ.Drawing.elliottwave - * @since 7.4.0 - */ - CIQ.Drawing.elliottwave.prototype.construct = function (stx, panel) { - this.stx = stx; - this.panelName = panel.name; - var cvp = stx.currentVectorParameters; - Object.assign(this, cvp.waveParameters); - }; - - /** - * Serializes the drawing to an object that can be restored with - * {@link CIQ.Drawing.elliottwave#reconstruct}. To store a drawing, convert the object returned - * by this function to a JSON string. - * - * @return {object} An object that contains the serialized state of the drawing. - * @memberOf CIQ.Drawing.elliottwave - * @since 7.4.0 - */ - CIQ.Drawing.elliottwave.prototype.serialize = function () { - var points = {}; - for (var i = 0; i < this.points.length; i++) { - points["d" + i] = this["d" + i]; - points["tzo" + i] = this["tzo" + i]; - points["v" + i] = this["v" + i]; - } - - points.annotations = this.annotationPoints.join(","); - - return Object.assign( - { - name: this.name, - pnl: this.panelName, - col: this.color, - ptrn: this.pattern, - lw: this.lineWidth, - mxSeg: this.maxSegments, - show: this.showLines, - decor: this.decoration, - dx: this.dx, - dy: this.dy, - trend: this.trend, - fnt: CIQ.removeNullValues( - CIQ.replaceFields(this.font, { - style: "st", - size: "sz", - weight: "wt", - family: "fl" - }) - ) - }, - points - ); - }; - - /** - * Reconstructs the drawing from an object returned from {@link CIQ.Drawing.elliottwave#serialize}. - * - * @param {CIQ.ChartEngine} stx A reference to the chart engine. - * @param {object} obj The object that contains the serialized drawing. - * @memberOf CIQ.Drawing.elliottwave - * @since 7.4.0 - */ - CIQ.Drawing.elliottwave.prototype.reconstruct = function (stx, obj) { - this.stx = stx; - this.color = obj.col; - this.panelName = obj.pnl; - this.pattern = obj.ptrn; - this.lineWidth = obj.lw; - this.font = CIQ.replaceFields(obj.fnt, { - st: "style", - sz: "size", - wt: "weight", - fl: "family" - }); - this.decoration = obj.decor; - this.showLines = obj.show; - this.dx = obj.dx; - this.dy = obj.dy; - this.trend = obj.trend; - this.annotationPoints = obj.annotations.split(","); - if (obj.decor === "enclosed") - this.calculateRadius(stx.chart.tempCanvas.context); - this.maxSegments = obj.mxSeg; - this.reconstructPoints(obj); - this.adjust(); - }; - - /** - * Reconstructs the points of a wave and sets points so the drawing can be rendered. - * - * @param {object} obj The object passed into {@link CIQ.Drawing.elliottwave#reconstruct}. - * @memberof CIQ.Drawing.elliottwave - * @since 7.4.0 - * @private - */ - CIQ.Drawing.elliottwave.prototype.reconstructPoints = function (obj) { - var panel = this.stx.panels[this.panelName]; - if (!panel) return; - // this.points=[]; - for (var p = 0; p < this.annotationPoints.length; p++) { - // var d=CIQ.strToDateTime(this.annotationPoints[p]); - this["d" + p] = obj["d" + p]; - this["v" + p] = obj["v" + p]; - this["tzo" + p] = obj["tzo" + p]; - var dt = CIQ.strToDateTime(obj["d" + p]); - var tick = this.stx.tickFromDate(dt, panel.chart); - // d.setMinutes(d.getMinutes()+Number(this.annotationPoints[p+1])-d.getTimezoneOffset()); - this.points.push([tick, obj["v" + p]]); - } - }; - - /** - * Calculates the width of the text enclosed in the annotation decorations. Iterates through the - * annotation points of the wave, measures the text of each annotation, and sets - * {@link CIQ.Drawing.elliottwave.enclosedRadius} to the width of the largest measurement. - * - * If you would like to customize the radius, override this function with another that sets the - * value of `enclosedRadius`. - * - * @param {external:CanvasRenderingContext2D} context The rendering context, which does the calculations. - * @memberof CIQ.Drawing.elliottwave - * @since 7.4.0 - */ - CIQ.Drawing.elliottwave.prototype.calculateRadius = function (context) { - this.getFontString(); - context.font = this.fontString; - var measure = 0; - for (var p = 0; p < this.annotationPoints.length; p++) { - var width = context.measureText(this.annotationPoints[p]).width; - if (measure < width) measure = width; - } - this.enclosedRadius = measure; - }; - - /** - * Ensures that each successive data point is positioned correctly in the Elliott Wave progression. - * Called by {@link CIQ.ChartEngine#drawingClick}. - * - * @param {Number} tick The tick where the wave data point is to be positioned. - * @param {Number} value The value (price) indicated by the tick where the wave data point is to be positioned. - * @param {Number} pt Represents whether the previous line was a gain or loss wave. If equal to 1, represents - * the first segment of the wave, which always results in a return value of true. - * @return {Boolean} Indicates whether or not the current wave data point has been positioned correctly. - * @memberof CIQ.Drawing.elliottwave - * @since 7.4.0 - */ - CIQ.Drawing.elliottwave.prototype.check = function (tick, value, pt) { - function isValidTrend(y) { - for (var i = 2; i < y.length; i++) { - if ( - Math.sign(y[i][1] - y[i - 1][1]) == - Math.sign(y[i - 1][1] - y[i - 2][1]) - ) - return false; - } - return true; - } - // setting first point is always true - if (pt === 1 && this.points.length === 2) return true; - var prev = this.points[pt - 1]; - if (prev && tick <= prev[0]) return false; - var next = this.points[pt + 1]; - if (next && tick >= next[0]) return false; - if (!isValidTrend(this.points)) return false; - return true; - }; - - /** - * Renders the movement when the user moves the drawing. - * - * @param {external:CanvasRenderingContext2D} context The canvas context in which to render the moving drawing. - * @param {Number} tick The tick to which the drawing is being moved. - * @param {Number} value The value to which the drawing is being moved. - * @memberof CIQ.Drawing.elliottwave - * @since 7.4.0 - */ - CIQ.Drawing.elliottwave.prototype.move = function (context, tick, value) { - this.copyConfig(); - this.points[this.lastPoint + 1] = [tick, value]; - this.render(context); - }; - - /** - * Resets the points of the drawing when the periodicity changes or the underlying ticks change - * (either from pagination or from moving the points). - * - * @memberof CIQ.Drawing.elliottwave - * @since 7.4.0 - */ - CIQ.Drawing.elliottwave.prototype.adjust = function () { - // If the drawing's panel doesn't exist then we'll check to see - // whether the panel has been added. If not then there's no way to adjust - var panel = this.stx.panels[this.panelName]; - if (!panel) return; - for (var p = 0; this.maxSegments + 1 > p; p++) { - var dt = this["d" + p]; - this.setPoint(p, dt, this["v" + p], panel.chart); - this.points[p][0] = this.stx.tickFromDate( - CIQ.strToDateTime(dt), - panel.chart - ); - this.points[p][1] = this["v" + p]; - } - }; - - /** - * Responds to click events on the drawing. - * - * @param {external:CanvasRenderingContext2D} context Canvas context in which to render the drawing. - * @param {Number} tick The tick where the click occurred. - * @param {Number} value The value where the click occurred. - * @memberof CIQ.Drawing.elliottwave - * @since 7.4.0 - */ - CIQ.Drawing.elliottwave.prototype.click = function (context, tick, value) { - var panel = this.stx.panels[this.panelName]; - if (!panel) return; - this.copyConfig(); - if (!this.penDown) { - this.setPoint(0, tick, value, panel.chart); - this.points.push(this.p0); - this.penDown = true; - this.segment = 0; - this.lastPoint = 0; - if (this.impulse) - this.annotationPoints = this.annotationPoints.concat(this.impulse); - if (this.corrective) - this.annotationPoints = this.annotationPoints.concat(this.corrective); - this.annotationPoints.unshift("0"); - if (this.decoration === "enclosed") this.calculateRadius(context); - this.maxSegments = this.annotationPoints.length - 1; - // will be reset on next click for now set here to avoid an additional check in every render loop - this.trend = 1; - return false; - } - if (this.accidentalClick(tick, value)) { - this.penDown = true; - return false; - } - - if (this.check(tick, value, this.lastPoint + 1)) { - this.lastPoint++; - this.setPoint(this.lastPoint, tick, value, panel.chart); - if (this.lastPoint === 1) { - this.trend = Math.sign(this.v1 - this.v0); - } - this.segment++; - - if (this.segment >= this.maxSegments) { - this.penDown = false; - return true; - } - } - return false; - }; - - /** - * Renders the wave on the chart. - * - * @param {external:CanvasRenderingContext2D} context The context in which the drawing is rendered. - * @memberof CIQ.Drawing.elliottwave - * @since 7.4.0 - */ - CIQ.Drawing.elliottwave.prototype.render = function (context) { - var panel = this.stx.panels[this.panelName]; - if (!panel) return; - var stx = this.stx; - var annotationPoints = this.annotationPoints; - var pattern = this.pattern - ? CIQ.borderPatternToArray(this.lineWidth, this.pattern) - : []; - this.getFontString(); - context.font = this.fontString; - context.textAlign = "center"; - context.textBaseline = "middle"; - context.lineWidth = this.lineWidth; - if (this.fontString !== this.lastFontString) this.calculateRadius(context); - this.lastFontString = this.fontString; - var color = this.getLineColor(); - context.fillStyle = context.strokeStyle = color; - context.save(); - context.setLineDash(pattern); - var dx = this.dx; - var dy = this.dy; - - var points = this.points; - var pts = this.pts; - var justHighlights = !this.showLines && this.highlighted; - //gather and set all pixel coordinates also used in intersection calculations - var l = points.length, - highlightIndexAboveNeighbors; - if (this.penDown && this.segment) { - highlightIndexAboveNeighbors = this.trend * ((l % 2) - 0.5) < 0; - if (panel.yAxis.flipped) - highlightIndexAboveNeighbors = !highlightIndexAboveNeighbors; - this.drawDropZone( - context, - points[l - 2][1], - this.stx.priceFromPixel( - panel.yAxis[highlightIndexAboveNeighbors ? "top" : "bottom"] - ), - points[l - 2][0] - ); - } else if ( - typeof this.highlighted === "string" && - this.stx.repositioningDrawing - ) { - var highlightIndex = parseInt( - this.highlighted.substring(1, this.highlighted.length), - 10 - ); - highlightIndexAboveNeighbors = - this.trend * ((highlightIndex % 2) - 0.5) > 0; - var pointToLeft = points[highlightIndex - 1], - pointToRight = points[highlightIndex + 1]; - var dragY = highlightIndex > 0 ? pointToLeft[1] : pointToRight[1]; - if (pointToRight) - dragY = Math[highlightIndexAboveNeighbors ? "max" : "min"]( - dragY, - pointToRight[1] - ); - if (panel.yAxis.flipped) - highlightIndexAboveNeighbors = !highlightIndexAboveNeighbors; - this.drawDropZone( - context, - dragY, - this.stx.priceFromPixel( - panel.yAxis[highlightIndexAboveNeighbors ? "top" : "bottom"] - ), - pointToLeft ? pointToLeft[0] : null, - pointToRight ? pointToRight[0] : null - ); - } - for (var p = 0; p < l; p++) { - var last = points[p]; - var xx = stx.pixelFromTick(last[0], panel.chart); - var yy = stx.pixelFromValueAdjusted(panel, last[0], last[1]); - pts[p] = [xx, yy]; - } - p = 0; - - if (this.showLines || justHighlights) { - context.beginPath(); - if (justHighlights) context.globalAlpha = 0.3; - for (; p < pts.length; p++) { - context.lineTo(pts[p][0], pts[p][1]); - } - context.stroke(); - p = 0; - } - - // Reset for Enclosed Annnotations - context.restore(); - // Has to be a separate loop otherwise you have a line coming from the center point of the enclosed decoration - // and your annotations have the oppacity of 0.3 when showLines is false - for (; p < l; p++) { - var pdx = p % 2 ? dx : -dx; - var pdy = p % 2 ? dy : -dy; - // Places the annotation above or below the based on wave trend - pdx *= this.trend; - pdy *= this.trend; - if (panel.yAxis.flipped) { - pdx *= -1; - pdy *= -1; - } - var pt = pts[p]; - var x = (pt[2] = pt[0] + pdx); - var y = (pt[3] = pt[1] + pdy); - var radius = this.enclosedRadius || 8; - var content = annotationPoints[p]; - if (this.decoration === "parentheses") content = "(" + content + ")"; - context.fillText(content, x, y); - if (this.decoration === "enclosed") { - context.beginPath(); - context.arc(x, y, radius, 0, 2 * Math.PI, false); - context.stroke(); - } - if (this.highlighted) { - context.save(); - this.littleCircle( - context, - this.pts[p][0], - this.pts[p][1], - this.highlighted === "p" + p - ); - context.restore(); - } - } - }; - - /** - * Repositions the drawing on drag (user moves an individual point of the drawing) or move - * (user moves the whole drawing) interactions. - * - * @param {external:CanvasRenderingContext2D} context The canvas context on which to render the drawing. - * @param {Object} repositioner The object containing data on how to reposition the drawing. - * @param {Number} tick The tick to which the drawing is repositioned. - * @param {Number} value The value to which the drawing is repositioned. - * @memberof CIQ.Drawing.elliottwave - * @since 7.4.0 - */ - CIQ.Drawing.elliottwave.prototype.reposition = function ( - context, - repositioner, - tick, - value - ) { - if (!repositioner) return; - var panel = this.stx.panels[this.panelName]; - var tickDiff = repositioner.tick - tick; - var valueDiff = repositioner.value - value; - if (repositioner.action === "move") { - for (var p = 0; repositioner.points.length > p; p++) { - var pt = repositioner.points[p]; - this.setPoint(p, pt[0] - tickDiff, pt[1] - valueDiff, panel.chart); - this.points[p] = [pt[0] - tickDiff, pt[1] - valueDiff]; - } - } - if (repositioner.action === "drag") { - var point = repositioner.point; - var points = this.points; - points[point] = [tick, value]; - if (this.check(tick, value, point)) { - // if(this.check(points[point], points[point+1], point)) { - this.setPoint(point, tick, value, panel.chart); - // } - } - // else this.points[point]=this["p"+point]; - } - this.render(context); - }; - - /** - * Detects when the wave drawing has been intersected at either a point or the segments of the wave. - * - * @param {Number} tick The tick under the mouse cursor. - * @param {Number} value The value under the mouse cursor. - * @param {Object} box A rectangular area around the mouse cursor. - * @memberof CIQ.Drawing.elliottwave - * @since 7.4.0 - */ - CIQ.Drawing.elliottwave.prototype.intersected = function (tick, value, box) { - if (!this.p0 || !this.p1) return null; - var positioning; - - for (var i = 0; this.points.length > i; i++) { - var pt = this.points[i]; - if (this.pointIntersection(pt[0], pt[1], box)) { - this.highlighted = "p" + i; - return { - action: "drag", - point: i, - tick: tick, - value: value - }; - } - - if ( - this.points[i + 1] && - this.lineIntersection( - tick, - value, - box, - "segment", - pt, - this.points[i + 1] - ) - ) { - this.highlighted = true; - // This object will be used for repositioning - positioning = { - action: "move", - points: CIQ.clone(this.points), - tick: tick, // save original tick - value: value // save original value - }; - } - } - return positioning; - }; - - /** - * Displays the following: - * - The value at the last point in the drawing or at the drawing cursor position minus the value at the original wave point - * - The percentage change: (value at the last point or drawing cursor position - the value at the original wave point) / value at the original wave point - * - Number of data points included in the wave drawing - * - * @memberof CIQ.Drawing.elliottwave - * @since 7.4.0 - */ - CIQ.Drawing.elliottwave.prototype.measure = function () { - if (this.points.length >= 2) { - var points = this.points; - this.stx.setMeasure( - points[0][1], - points[points.length - 1][1], - points[0][0], - points[points.length - 1][0], - true - ); - var mSticky = this.stx.controls.mSticky; - var mStickyInterior = - mSticky && mSticky.querySelector(".mStickyInterior"); - if (mStickyInterior) { - var lines = []; - lines.push(CIQ.capitalize("Elliott Wave")); - if (this.getYValue) - lines.push(this.field || this.stx.defaultPlotField || "Close"); - lines.push(mStickyInterior.innerHTML); - mStickyInterior.innerHTML = lines.join("
"); - } - } - }; - - /** - * @private - */ - CIQ.Drawing.printProjection = function (self, projection, tmpHist) { - var nd = projection.arr; - if (nd.length > 1) { - var dt = nd[0][0]; - var maxTicks = Math.round(self.chart.maxTicks * 0.75); - for (var i = 1; i < nd.length; i++) { - var dt0 = nd[i - 1][0]; - var dt1 = nd[i][0]; - - // Figure length in days - var d = CIQ.strToDateTime(dt0); - var m1 = CIQ.strToDateTime(dt1).getTime(); - var iter = self.standardMarketIterator(d); - var l = 0; - while (d.getTime() < m1) { - d = iter.next(); - l += 1; - } - // Find beginning position in existing data set - var m = CIQ.strToDateTime(dt0).getTime(); - var tick; - if (m > CIQ.strToDateTime(tmpHist[tmpHist.length - 1].Date).getTime()) { - // This can only happen if the projection is drawn before intraday tick arrives - tick = tmpHist.length - 1; - l += 1; - } else { - for (tick = tmpHist.length - 1; tick >= 0; tick--) { - if (m <= CIQ.strToDateTime(tmpHist[tick].Date).getTime()) break; - } - } - - var v = { - x0: 0, - x1: l, - y0: tmpHist[tick].Close, - y1: nd[i][1] - }; - - // Iterate, calculate prices and append to data set - dt = CIQ.strToDateTime(dt0); - iter = self.standardMarketIterator(dt); - var first = false; - for (var t = 0; t <= l; t++) { - if (!first) { - first = true; - } else { - dt = iter.next(); - } - if (dt.getTime() <= tmpHist[tmpHist.length - 1].DT.getTime()) - continue; - - var y = CIQ.yIntersection(v, t); - if (!y) y = 0; - var price = Math.round(y * 10000) / 10000; - if (price === 0) price = nd[i][1]; - - var prices = { - Date: CIQ.yyyymmddhhmmssmmm(dt), - DT: dt, - Open: price, - Close: price, - High: price, - Low: price, - Volume: 0, - Adj_Close: price, - Split_Close: price, - projection: true - }; - if (self.layout.interval == "minute") if (maxTicks-- < 0) break; - tmpHist[tmpHist.length] = prices; - } - } - } - }; -} - -}; - - -let __js_advanced_equationsAdvanced_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -if (!CIQ.computeEquationChart) { - console.error( - "equationsAdvanced feature requires first activating equations feature." - ); -} else { - /** - * Extracts symbols from an equation. An equation can consist of symbols and the following operators: +-/*%() - * PEMDAS order is followed. Additionally, symbols can be enclosed in brackets [] to treat them as literal non-parseables. - * @param {string} equation The equation to parse (e.g. IBM+GE) - * @return {object} Parsed equation, {equation: [formatted equation], symbols: [array of symbols found in the equation]} - * @memberOf CIQ - * @version ChartIQ Advanced Package - */ - CIQ.formatEquation = function (equation) { - var eq = ""; - var syms = []; - var thisSym = ""; - var lockSymbol = false; - for (var j = 1; j < equation.length; j++) { - var c = equation[j].toUpperCase(); - if (c == "[" && !lockSymbol) { - lockSymbol = true; - } else if (c == "]" && lockSymbol) { - lockSymbol = false; - if (thisSym !== "") { - syms.push(thisSym); - eq += "[" + thisSym + "]"; - } - thisSym = ""; - } else if (lockSymbol) { - thisSym += c; - } else if ( - c == "+" || - c == "-" || - c == "*" || - c == "/" || - c == ":" || - c == "%" || - c == "(" || - c == ")" - ) { - if (thisSym !== "" && isNaN(thisSym)) { - syms.push(thisSym); - eq += "[" + thisSym + "]"; - } else { - eq += thisSym; - } - if (c == ":") c = "/"; - eq += c; - thisSym = ""; - } else if (c != " ") { - thisSym += c; - } - } - if (thisSym !== "" && isNaN(thisSym)) { - syms.push(thisSym); - eq += "[" + thisSym + "]"; - } else { - eq += thisSym; - } - return { equation: eq, symbols: syms }; - }; - - /** - * Extracts symbols from an equation and fetches the quotes for them. - * @param {object} params Parameters used for the fetch - * @param {function} cb Callback function once all quotes are fetched - * @memberOf CIQ - * @version ChartIQ Advanced Package - */ - CIQ.fetchEquationChart = function (params, cb) { - var formEq = CIQ.formatEquation(params.symbol); - var syms = formEq.symbols; - var arr = []; - // jump through hoops with stx so that CIQ.clone doesn't choke on it - var stx = params.stx; - params.stx = null; - for (var i = 0; i < syms.length; i++) { - var newParams = CIQ.shallowClone(params); - newParams.stx = stx; - newParams.symbol = syms[i]; - newParams.symbolObject = { symbol: syms[i] }; - arr.push(newParams); - } - params.stx = stx; - // multi fetch the symbols we need - stx.quoteDriver.multiFetch(arr, function (results) { - var map = {}; - params.loadMoreReplace = true; - var attribution = { charge: 0 }; - // error on any symbol then error out. Otherwise construct map. - for (var i = 0; i < results.length; i++) { - var result = results[i]; - if (result.dataCallback.error) { - cb({ error: result.dataCallback.error }); - return; - } - map[result.params.symbol] = result.dataCallback.quotes; - params.loadMoreReplace = - params.loadMoreReplace && result.params.loadMoreReplace; - params.moreToLoad = - params.moreToLoad || result.dataCallback.moreAvailable; - var dataCallbackAttribution = result.dataCallback.attribution; - if (dataCallbackAttribution) { - if (dataCallbackAttribution.charge) - attribution.charge += dataCallbackAttribution.charge; - attribution.source = dataCallbackAttribution.source; - if (attribution.exchange === undefined) - attribution.exchange = dataCallbackAttribution.exchange; - else if (attribution.exchange != dataCallbackAttribution.exchange) - attribution.exchange = ""; // mixed exchanges - } - } - // compute the result and then pass to the response - if (arr.length || !(params.loadMore || params.update)) { - try { - var equQuotes = CIQ.computeEquationChart(formEq.equation, map); - cb({ - quotes: equQuotes, - moreAvailable: params.moreToLoad, - attribution: attribution - }); - } catch (e) { - var error = { error: "Invalid equation: " + formEq.equation }; - if (e.name && e.name == "NoException") error.suppressAlert = true; - cb(error); - } - } - }); - }; -} - -}; - - -let __js_advanced_highPerformanceMarkers_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -if (!CIQ.Marker) { - console.error( - "highPerformanceMarkers feature requires first activating markers feature." - ); -} else if (!CIQ.Marker.Performance) { - /** - * Removes a high performance canvas marker from the `markerHelper.domMarkers` Array. - * We use this instead of {@link CIQ.ChartEngine#removeFromHolder} because that will remove the whole marker instead of just removing the DOM node. - * - * @private - * @since - * - 7.1.0 - * - 7.2.0 Scheduled for deprecation in a future release. See {@link CIQ.Marker.Performance#remove} instead. - */ - CIQ.ChartEngine.prototype.removeDOMMarker = function (marker) { - console.warn( - "CIQ.ChartEngine#removeDOMMarker is scheduled for deprecation in a future release\n Please use CIQ.Marker.Performance#remove instead." - ); - CIQ.Marker.Performance.prototype.removeDOMMarker.call( - marker.params.node, - marker - ); - }; - - /** - * Animation Loop - * - * Iterates through all [high performance canvas]{@link CIQ.Marker.Performance} markers and draws them on the canvas. - * - * See {@tutorial Markers} tutorials for additional implementation instructions. - * - * @memberOf CIQ.ChartEngine - * @since - * - 7.1.0 - * - 7.2.0 Scheduled for deprecation in a future release. See {@link CIQ.Marker.Performance.drawMarkers} instead. - */ - CIQ.ChartEngine.prototype.drawMarkers = function () { - console.warn( - "CIQ.ChartEngine#drawMarkers is scheduled for deprecation in a future release\n Please use CIQ.Marker.Performance.drawMarkers instead." - ); - CIQ.Marker.Performance.drawMarkers(this); - }; - - /** - * Calculates the styles used in drawing [high performance canvas]{@link CIQ.Marker.Performance} markers. - * We use this method instead of other chart styling methods because markers expect styles to cascade down and then be calculated. - * Other style methods are for adding or calculating a single property. - * This will save styles to the engine's style object where they can be adjusted with {@link CIQ.ChartEngine#setStyle}. - * - * @memberof CIQ.ChartEngine - * @param {CIQ.Marker} marker The marker from which to compute the styles. - * @param {string} style Name to save to {@link CIQ.ChartEngine#styles}. - * @private - * @since - * - 7.1.0 - * - 7.2.0 Scheduled for deprecation in a future release. See {@link CIQ.Marker.Performance.calculateMarkerStyles}. - */ - CIQ.ChartEngine.prototype.calculateMarkerStyles = function (marker, style) { - console.warn( - "CIQ.ChartEngine#calculateMarkerStyles is scheduled for deprecation in a future release\n Please use CIQ.Marker.Performance.calculateStyles instead." - ); - CIQ.Marker.Performance.calculateMarkerStyles(this, marker, style); - }; - - /** - * Draws a circle for a [high performance canvas]{@link CIQ.Marker.Performance} marker. - * - * @param {CIQ.Marker} marker - * @param {object} style - * @param {object} params - * @private - * @since - * - 7.1.0 - * - 7.2.0 Scheduled for deprecation in a future release. See {@link CIQ.Marker.Performance.drawCircleMarker}. - */ - CIQ.ChartEngine.prototype.drawCircleMarker = function ( - marker, - style, - params - ) { - console.warn( - "CIQ.ChartEngine#drawCircleMarker is scheduled for deprecation in a future release\n Please use CIQ.Marker.Performance.drawCircleMarker instead." - ); - CIQ.Marker.Performance.drawCircleMarker(marker, style, params); - }; - - /** - * Draws a square for a [high performance canvas]{@link CIQ.Marker.Performance} marker. - * - * @param {CIQ.Marker} marker - * @param {object} style - * @param {object} params - * @private - * @since - * - 7.1.0 - * - 7.2.0 Scheduled for deprecation in a future release. See {@link CIQ.Marker.Performance.drawSquareMarker}. - */ - CIQ.ChartEngine.prototype.drawSquareMarker = function ( - marker, - style, - params - ) { - console.warn( - "CIQ.ChartEngine#drawSquareMarker is scheduled for deprecation in a future release\n Please use CIQ.Marker.Performance.drawSquareMarker instead." - ); - CIQ.Marker.Performance.drawSquareMarker(marker, style, params); - }; - - /** - * Draws callout (rectangular) a [high performance canvas]{@link CIQ.Marker.Performance} marker. - * - * @param {CIQ.Marker} marker - * @param {object} style - * @param {object} params - * @private - * @since - * - 7.1.0 - * - 7.2.0 Scheduled for deprecation in a future release. See {@link CIQ.Marker.Performance.drawCalloutMarker}. - */ - CIQ.ChartEngine.prototype.drawCalloutMarker = function ( - marker, - style, - params - ) { - console.warn( - "CIQ.ChartEngine#drawCalloutMarker is scheduled for deprecation in a future release\n Please use CIQ.Marker.Performance.drawCalloutMarker instead." - ); - CIQ.Marker.Performance.drawCalloutMarker(marker, style, params); - }; - - /** - * Draws a stem for a [high performance canvas]{@link CIQ.Marker.Performance} marker. - * - * @param {CIQ.Marker} marker - * @param {object} style - * @param {object} params - * @private - * @since - * - 7.1.0 - * - 7.2.0 Scheduled for deprecation in a future release. See {@link CIQ.Marker.Performance.drawMarkerStem}. - */ - CIQ.ChartEngine.prototype.drawMarkerStem = function (marker, style, params) { - console.warn( - "CIQ.ChartEngine#drawMarkerStem is scheduled for deprecation in a future release\n Please use CIQ.Marker.Performance.drawMarkerStem instead." - ); - CIQ.Marker.Performance.drawMarkerStem(marker, style, params); - }; - - /** - * Positions any markers that have DOM elements appended to the chart so that they follow their same canvas marker. - * - * @private - * @since - * - 7.1.0 - * - 7.2.0 Scheduled for deprecation in a future release. See {@link CIQ.Marker.Performance.drawMarkers}. - */ - CIQ.ChartEngine.prototype.positionDOMMarkers = function () { - console.warn( - "CIQ.ChartEngine#positionDOMMarkers is scheduled for deprecation in a future release\n Please use CIQ.Marker.Performance.drawMarkers instead." - ); - CIQ.Marker.Performance.drawMarkers(this); - }; - - /** - * Creates high performance canvas nodes that can be used with a {@link CIQ.Marker}. - * - * Use this class if you need to add hundreds or thousands of markers to a chart. When a - * marker is created, this class creates a node from the built-in template but does not attach - * the node to the DOM until you hover over the canvas drawing. Once you intersect the drawing, - * the node is appended and you can interact with it like other markers. - * - * The canvas draws the marker based on the classes that you append to the template (which - * come from `params.type` and `params.category`) being added to `stx-marker` class. - * See {@link CIQ.ChartEngine#calculateMarkerStyles} for more information. - * - * This class takes the same params as {@link CIQ.Marker.Simple} so that the appended DOM - * marker works the same. This means that you can reuse all of the default styles you've - * created for `CIQ.Marker.Simple` with `CIQ.Marker.Performance`. **Note:** If you do not pass - * in either a `headline` or a `story` or both, your marker will not create a pop-up display - * when the marker is selected. - * - * See the {@tutorial Markers} tutorial for additional implementation instructions. - * - * @param {Object} params Parameters to describe the marker. - * @param {string} params.type The marker type to be drawn. - *
Available options are: - * - "circle" - * - "square" - * - "callout" - * @param {string} [params.headline] The headline text to pop up when clicked. - * @param {string} [params.category] The category class to add to your marker. - *
Available options are: - * - "news" - * - "earningsUp" - * - "earningsDown" - * - "dividend" - * - "filing" - * - "split" - * - * Other custom categories require a corresponding CSS entry. See example. - * - * @param {boolean} [params.displayCategory=true] Set to false to not draw the first letter of - * the category in the marker. - * @param {string} [params.story] The story to pop up when clicked. If left undefined, the - * marker displays an empty DOM node when clicked. - * @param {string} [params.color] Background color to make your marker. Overrides any style - * set by `params.category`. - * @param {boolean} [params.displayStem=true] Set to false to draw the marker at a specific - * point and not include the stem. - * @param {boolean} [params.invert=false] Set to true to invert the stem and point downward. - * @param {boolean} [params.infoOnLeft] If true, the information pop-up box is positioned on - * the left when possible. - * @param {number} [params.infoOffset] Distance to offset the information pop-up box. - * - * @constructor - * @name CIQ.Marker.Performance - * @since - * - 7.1.0 - * - 7.2.0 Markers without both a `headline` and `story` are not interactive. - * You must provide either or both properties for a node (which is the marker pop-up - * display) to be appended to the DOM. Performance markers now can be positioned anywhere - * that a DOM marker can be positioned (above, below, or on a candle; at a value; or at - * the top or bottom of a chart). - * - 8.0.0 Added `params.infoOnLeft`, `params.infoOffset`, and `params.invert`. - * - * - * @example - * Required CSS entry for a custom category ("trade"), not included in the default - * CSS styles. - * - * .stx-marker.trade .stx-visual { - * background: #C950d7; - * width: 5px; - * height: 5px; - * } - * - * // Corresponding code: - * - * new CIQ.Marker({ - * stx: stxx, - * label: "trade", - * xPositioner: "date", - * x: OHLCData.DT, - * node: new CIQ.Marker.Performance({ - * type: "circle", - * category: "trade", - * displayCategory: false, - * displayStem: false, - * headline: "Executed at $" + OHLCData.Close, - * story: "Like all ChartIQ markers, the object itself is managed by the chart." - * }) - * }); - */ - CIQ.Marker.Performance = function (params) { - this.params = { - displayCategory: true, - displayStem: true, - invert: false, - story: "", - headline: "" - }; - CIQ.extend(this.params, params); - var template = (this.template = document.createElement("TEMPLATE")); - template.innerHTML = - '
' + - '
' + - '
' + - '

' + - "
" + - "
" + - '
' + - "
"; - var n = this.template.content.cloneNode(true); - var marker = n.querySelector(".stx-marker", template); - marker.classList.add(params.type); - marker.classList.add(params.category); - var visual = n.querySelector(".stx-visual", template); - var expand = n.querySelector(".stx-marker-expand"); - var header = n.querySelector("h4", template); - var text = n.querySelector("p", template); - header.innerText = this.params.headline; - text.innerText = this.params.story; - this.hasText = !!params.headline || !!params.story; - - this.deferAttach = true; - - this.node = n.firstChild; - this.node.params = this.params; - this.visual = visual; - this.expand = expand; - if (params.type === "callout") { - var h = expand.removeChild(header); - n.querySelector(".stx-marker-content", template).insertBefore(h, expand); - } - }; - - CIQ.inheritsFrom(CIQ.Marker.Performance, CIQ.Marker.NodeCreator, false); - - /** - * This function keeps you from having a ton of marker expand dialogs from overlapping each other and becoming too hard to read. - * Checks the markers that have been marked as highlighted by the chart engine and combines the text of their expands into the last one highlighted. - * - * @param {CIQ.ChartEngine} stx - * @static - * @private - * @since 7.2.0 - */ - CIQ.Marker.Performance.consolidateExpanded = function (stx) { - var highlighted = stx.markerHelper.highlighted; - if (!highlighted.length) return; - - function findInner(marker) { - var node = marker.params.node, - expand = node.expand; - if (!expand) return ""; - var inner = expand.style.display !== "none" ? expand.innerHTML : ""; - return inner; - } - - var focusedMarker = highlighted[highlighted.length - 1], - fnode = focusedMarker.params.node; - if (!focusedMarker.consolidated) focusedMarker.consolidated = []; - for (var i = highlighted.length - 2; i >= 0; i--) { - var inner = findInner(highlighted[i]); - var consolidated = "" + inner + ""; - if (inner.length) fnode.expand.innerHTML += consolidated; - } - focusedMarker.stxNodeCreator.quickCache(focusedMarker); - }; - - /** - * Resets any highlighted markers to their default display state and removes any consolidated text from the marker. - * - * @param {CIQ.ChartEngine} stx - * @static - * @private - * @since 7.2.0 - */ - CIQ.Marker.Performance.reconstituteExpanded = function (stx) { - var reset = stx.markerHelper.highlighted; - if (!reset.length || !stx.activeMarker) return; - reset = [stx.activeMarker]; - - for (var i = reset.length - 1; i >= 0; i--) { - var marker = reset[i]; - var node = marker.params.node, - expand = node.expand; - while (expand.lastElementChild.nodeName === "CONSOLIDATED") { - expand.removeChild(expand.lastElementChild); - } - } - }; - - /** - * Animation Loop - * - * Iterates through all [high performance canvas]{@link CIQ.Marker.Performance} markers and - * draws them on the canvas. - * - * See {@tutorial Markers} tutorials for additional implementation instructions. - * - * @param {CIQ.ChartEngine} stx A reference to the chart object. - * - * @memberof CIQ.Marker.Performance - * @static - * @since 7.2.0 Replaces {@link CIQ.ChartEngine#drawMarkers}. - */ - CIQ.Marker.Performance.drawMarkers = function (stx) { - var markers = stx.getMarkerArray("all"); - var chart = stx.chart; - for (var i = 0; i < markers.length; i++) { - var marker = markers[i], - nodeCreator = marker.stxNodeCreator; - var startingTick = chart.dataSegment[0].tick, - endingTick = chart.dataSegment[chart.dataSegment.length - 1].tick; - if (startingTick <= marker.tick <= endingTick) { - // if markers are off screen don't draw them - if (nodeCreator && nodeCreator.drawMarker) - nodeCreator.drawMarker(marker); - } - } - }; - - /** - * Calculates the styles used in drawing [high performance canvas]{@link CIQ.Marker.Performance} markers. - * We use this method instead of other chart styling methods because Markers expect styles to cascade down and then be calculated. - * Other style methods are for adding or calculating a single property. - * This will save styles to the engine's style object where they can be adjusted with {@link CIQ.ChartEngine#setStyle}. - * - * @member CIQ.Marker.Performance - * @param {CIQ.ChartEngine} stx The chart engine. - * @param {CIQ.Marker} marker The marker to compute the styles from. - * @param {string} style Name to save to {@link CIQ.ChartEngine#styles}. - * @private - * @static - * @since 7.2.0 - */ - CIQ.Marker.Performance.calculateMarkerStyles = function (stx, marker, style) { - var testArea = document.querySelector(".stx-marker-templates"); - if (!testArea) { - testArea = document.createElement("DIV"); - testArea.style.visibility = "hidden"; - testArea.style.left = "-1000px"; - document.body.append(testArea); - } - testArea.appendChild(marker.node); - var s = getComputedStyle(marker.stxNodeCreator.visual); - if (!stx.styles.stx_marker_stem) { - var stem = getComputedStyle( - document.querySelector(".stx-stem", marker.node) - ); - stx.styles.stx_marker_stem = stx.cloneStyle(stem); - } - stx.styles[style] = stx.cloneStyle(s); - testArea.removeChild(marker.node); - }; - - /** - * Draws circular canvas markers based on the styles for {@link CIQ.Marker.Performance} markers. - * - * @param {CIQ.Marker} marker - * @param {object} style - * @param {object} params - * @static - * @private - * @since 7.2.0 - */ - CIQ.Marker.Performance.drawCircleMarker = function (marker, style, params) { - var stx = marker.params.stx, - chart = stx.chart, - ctx = chart.context; - var x = params.x, - y = params.y, - radius = params.radius, - label = params.label; - var color = params.color ? params.color : style.backgroundColor; - - // Draw Circle - ctx.beginPath(); - ctx.setLineDash([]); - ctx.lineWidth = 1; - ctx.fillStyle = color; - ctx.strokeStyle = color; - ctx.font = "normal bold 12px Roboto, Helvetica, sans-serif"; - ctx.arc(x, y, radius, 0, 2 * Math.PI, false); - ctx.fill(); - ctx.stroke(); - ctx.closePath(); - - // Write text - if (label) { - ctx.fillStyle = CIQ.colorsEqual("white", ctx.fillStyle) - ? "black" - : "white"; - ctx.fillText(label.charAt(0).toUpperCase(), x - 4, y + 1); - } - - if (marker.highlight || marker.active) { - ctx.beginPath(); - ctx.arc(x, y, radius + 4, 0, 2 * Math.PI, false); // 4 pixels just chosen for giving slight space around marker - ctx.stroke(); - ctx.closePath(); - } - }; - - /** - * Draws square canvas markers based on the styles for {@link CIQ.Marker.Performance} markers. - * - * @param {CIQ.Marker} marker - * @param {object} style - * @param {object} params - * @static - * @private - * @since 7.2.0 - */ - CIQ.Marker.Performance.drawSquareMarker = function (marker, style, params) { - var stx = marker.params.stx, - chart = stx.chart, - ctx = chart.context; - var x = params.x, - y = params.y, - half = params.half, - label = params.label; - var color = params.color ? params.color : style.backgroundColor; - var whole = half * 2; - - // Draw Square - ctx.beginPath(); - ctx.setLineDash([]); - ctx.lineWidth = 1; - ctx.fillStyle = color; - ctx.strokeStyle = color; - ctx.font = "normal bold 12px Roboto, Helvetica, sans-serif"; - ctx.rect(x - half, y - half, whole, whole); - ctx.fill(); - if (marker.highlight || marker.active) - ctx.rect(x - half - 4, y - half - 4, whole + 8, whole + 8); // whole + 4 + 4 for the highlighted box - ctx.stroke(); - ctx.closePath(); - - // Write text - if (label) { - ctx.fillStyle = CIQ.colorsEqual("white", ctx.fillStyle) - ? "black" - : "white"; - ctx.fillText(label.charAt(0).toUpperCase(), x - 4, y + 1); - } - }; - - /** - * Draws callout (rectangular) canvas marker based on the style for a {@link CIQ.Marker.Performance} markers. - * - * @param {CIQ.Marker} marker - * @param {object} style - * @param {object} params - * @static - * @private - * @since 7.2.0 - */ - CIQ.Marker.Performance.drawCalloutMarker = function (marker, style, params) { - var stx = marker.params.stx, - chart = stx.chart, - ctx = chart.context, - mParams = marker.params; - var x = params.x, - y = params.y, - half = params.half, - calloutMid = params.midWidth, - headline = params.headline; - var color = params.color ? params.color : style.backgroundColor; - - var height = half * 2 || 25; - var headlineLength = Math.round(ctx.measureText(headline).width); - // If there's no length use the text measurement plus some padding - var calloutWidth = calloutMid ? calloutMid * 2 : headlineLength + 8; - - // Draw the rectangle - ctx.beginPath(); - ctx.setLineDash([]); - ctx.lineWidth = 1; - ctx.fillStyle = color; - ctx.strokeStyle = color; - ctx.font = "normal bold 12px Roboto, Helvetica, sans-serif"; - ctx.rect(mParams.box.x0, mParams.box.y0, calloutWidth, height); - ctx.fill(); - ctx.stroke(); - ctx.closePath(); - - // draw the "background" box that text apears in - ctx.beginPath(); - ctx.fillStyle = - marker.highlight || marker.active - ? "rgba(255,255,255,0.8)" - : "rgba(255,255,255,0.65)"; - var xx = (calloutWidth - (headlineLength + 20)) / 2; - ctx.rect(mParams.box.x0 + xx, y - half, headlineLength + 40, 22); - ctx.fill(); - ctx.stroke(); - ctx.closePath(); - - ctx.fillStyle = "black"; - ctx.fillText(headline, mParams.box.x0 + xx + 10, y); - }; - - /** - * Draws marker stems for a based on a style for {@link CIQ.Marker.Performance} markers. - * - * @param {CIQ.Marker} marker - * @param {object} style - * @param {object} params - * @static - * @private - * @since 7.2.0 - */ - CIQ.Marker.Performance.drawMarkerStem = function (marker, style, params) { - var stx = marker.params.stx, - chart = stx.chart, - ctx = chart.context; - var x = params.x, - y = params.y; - - ctx.beginPath(); - ctx.strokeStyle = style.borderLeftColor; - // ctx.setLineDash(CIQ.borderPatternToArray(stemStyle.borderLeftWidth, stemStyle.borderLeftStyle)); - ctx.setLineDash([1, 1]); - let stemHeight = CIQ.stripPX(style.height); - let startY = params.invert ? marker.params.box.y0 : marker.params.box.y1; - let endY = params.invert - ? marker.params.box.y0 - stemHeight - : marker.params.box.y1 + stemHeight; - ctx.moveTo(x, startY); - ctx.lineTo(x, endY); - ctx.stroke(); - ctx.closePath(); - }; - - /** - * Draws a canvas marker on the chart and positions the pop-up for the marker if necessary. - * - * @memberof CIQ.Marker.Performance - * @param {CIQ.Marker} marker The marker to be drawn. - * @since 7.2.0 - */ - CIQ.Marker.Performance.prototype.drawMarker = function (marker) { - var mParams = marker.params, - stx = marker.params.stx; - if (!stx) return; - - var chart = stx.chart, - dataSegment = chart.dataSegment; - if (!dataSegment.length) return; - - var panel = stx.panels[marker.params.panelName]; - var nParams = marker.stxNodeCreator.params; - var type = nParams.type, - category = nParams.category, - headline = nParams.headline, - display = nParams.displayCategory, - color = nParams.color, - invert = nParams.invert; - var style = "stx_marker_" + type + "_" + category; - if (!stx.styles[style]) - CIQ.Marker.Performance.calculateMarkerStyles(stx, marker, style); - var markerStyle = (marker.style = stx.styles[style]), - stemStyle = stx.styles.stx_marker_stem; - - var halfSide = parseInt(markerStyle.height, 10) / 2, - halfWidth = parseInt(markerStyle.width, 10) / 2; - var stemHeight = nParams.displayStem - ? parseInt(stemStyle.height, 10) + parseInt(stemStyle.marginBottom, 10) - : 0; - var markerHeight = stemHeight + parseInt(markerStyle.height, 10); - var stemOffset = stemHeight ? stemHeight + halfSide : 0; - - var x = stx.pixelFromDate(mParams.x); - var y = mParams.node.calculateYPosition({ - marker: marker, - panel: panel, - height: markerHeight, - half: halfSide, - offset: stemOffset, - inverted: invert - }); - - // This can happen if for some reason the marker is missing a tick. - //It's possible but rare, in that scenario just abort the drawing to prevent throwing errors - if (!marker.tick && marker.tick !== 0) return; - - mParams.box = { - x0: x - (halfWidth || halfSide), - y0: y - halfSide, - x1: x + (halfWidth || halfSide), - y1: y + halfSide, - midY: halfSide, - midX: halfWidth || halfSide, - stemHeight: stemHeight - }; - - if (!display) category = display; - stx.startClip(panel.name); - - if (type === "circle") { - CIQ.Marker.Performance.drawCircleMarker(marker, markerStyle, { - x: x, - y: y, - radius: halfSide, - label: category, - color: color - }); - } else if (type === "square") { - CIQ.Marker.Performance.drawSquareMarker(marker, markerStyle, { - x: x, - y: y, - half: halfSide, - label: category, - color: color - }); - } else if (type === "callout") { - CIQ.Marker.Performance.drawCalloutMarker(marker, markerStyle, { - x: x, - y: y, - half: halfSide, - midWidth: halfWidth, - headline: headline, - color: color - }); - } else { - console.warn( - "Marker type: " + - type + - " is unsupported with canvas markers!\nSupported Styles are Square, Circle, and Callout." - ); - } - - if (nParams.displayStem) - CIQ.Marker.Performance.drawMarkerStem(marker, stemStyle, { - x: x, - y: y, - invert: invert - }); - - stx.endClip(); - if (marker.attached) this.positionPopUpNode(marker); - }; - - /** - * Positions a marker's pop-up `div` that has been appended to the chart so that it follows the canvas marker. - * This is the replacement for {@link CIQ.ChartEngine#positionDOMMarkers}, but it is now an instance method for the individual performance marker. - * - * @private - * @since 7.2.0 - */ - CIQ.Marker.Performance.prototype.positionPopUpNode = function (marker) { - if (!marker.attached || !marker.params.box) return; - var mparams = marker.params, - stx = mparams.stx, - mbox = mparams.box, - expand = marker.params.node.expand; - var dataSet = stx.chart.dataSet, - dataSegment = stx.chart.dataSegment; - - var markerVisible; - if (marker.tick) { - var startBuffer = [ - dataSet[dataSegment[0] && dataSegment[0].tick - 1], - dataSet[dataSegment[0] && dataSegment[0].tick - 2] - ]; // check two ticks ahead the dataSegment b/c markers sometimes extend past ticks - var first = stx.getFirstLastDataRecord( - startBuffer.concat(dataSegment), - "Date" - ); - var endBuffer = [ - dataSet[dataSegment[dataSegment.length - 1].tick + 1], - dataSet[dataSegment[dataSegment.length - 1].tick + 2] - ]; // check two ticks behind the dataSegment b/c markers sometimes extend past ticks - var last = stx.getFirstLastDataRecord( - dataSegment.concat(endBuffer), - "Date", - true - ); - markerVisible = - first.DT <= dataSet[marker.tick].DT && - dataSet[marker.tick].DT <= last.DT; - } else { - markerVisible = false; - } - - if (!marker.highlight && !marker.active) markerVisible = false; - expand.style.visibility = markerVisible ? "" : "hidden"; - if (!markerVisible) return; // don't continue if the marker is off the screen - - var panel = stx.panels[mparams.panelName]; - var expandRect = expand.rects; - var medianHeight = expandRect.height / 2; - - var tx; - var offset = marker.node.params.infoOffset || 0; - if (marker.node.params.infoOnLeft) { - tx = - mbox.x0 - expandRect.width - offset < panel.left - ? mbox.x1 + offset - : mbox.x0 - expandRect.width - offset; - } else { - tx = - mbox.x0 + expandRect.width > panel.right - ? mbox.x0 - expandRect.width - offset - : mbox.x1 + offset; - } - tx -= stx.chart.left; - var ty = - mbox.y0 - medianHeight >= panel.top - ? mbox.y0 + mbox.midY - medianHeight - : mbox.y0; - // case where the marker is set to "bottom" alignment. We make the marker flush with the bottom of the yAxis unless the expand height is shorter than the marker height (ie a short marker label on a marker with a stem) - if ( - !mparams.avoidFlush && - mbox.y1 + mbox.stemHeight === panel.yAxis.bottom && - expandRect.height > mbox.y1 - mbox.y0 + mbox.stemHeight - ) - ty = mbox.y1 - expandRect.height + mbox.stemHeight; - ty -= stx.chart.panel.top; - var transform = - "translateX(" + - Math.floor(tx) + - "px) translateY(" + - Math.floor(ty) + - "px) translateZ(0)"; - expand.style.transform = transform; - // cache values for later use to determine x/y location of the expand popup - expand.transform = { translateX: tx, translateY: ty }; - }; - - /** - * Performs and caches some necessary calculations when the expand popup is first appended to the DOM. - * We do these calculations here once instead of on every call of the draw loop when we iterate thru the markers. - * The only thing that will change is the X/Y transform position which we already calculate in CIQ.Marker.Performance#drawMarker. - * So we can safely add the transform values we cache there to the default X/Y calculated here and find position without trashing the layout. - * - * **NOTE** You will notice that if you remove a marker and add it back, the values should be correct for X/Y (or at least the same as what it was before + translateX/Y). - * While this is true, it's only true if you add a marker back, so we can't reliably assume that the values are correct for X/Y. - * - * @param {CIQ.Marker} marker - * @private - * @since 7.2.0 - */ - CIQ.Marker.Performance.prototype.quickCache = function (marker) { - var node = marker.params.node, - expand = node.expand, - style = marker.style; - var notScroll = - CIQ.stripPX(style.marginLeft) + - CIQ.stripPX(style.marginRight) + - CIQ.stripPX(style.borderRight) + - CIQ.stripPX(style.borderLeft); - expand.rects = expand.getBoundingClientRect(); - expand.scrollBarWidth = expand.rects.width - expand.clientWidth - notScroll; - }; - - /** - * Calculates the initial y-axis positioning when drawing a canvas marker. - * - * @param {object} params - * @param {CIQ.Marker} params.marker The marker for which the y-axis position is calculated. - * @param {CIQ.ChartEngine.Panel} params.panel Panel on which the marker appears. - * @param {number} params.tick The tick of the quote in the chart's data set. - * @param {number} params.height Total height of the marker as defined by marker height plus - * stem height. - * @param {number} params.half Half the height of the marker as defined by the marker CSS - * style. - * @param {number} params.offset Height of the marker stem offset as defined by the marker - * stem CSS style height plus margin bottom. - * @param {boolean} params.inverted Indicates whether the marker stem is inverted; that is, - * pointing downward. - * @return {number} Initial y-coordinate positioning for drawing the canvas marker. - * - * @memberof CIQ.Marker.Performance - * @since - * - 7.2.0 - * - 8.0.0 Added `params.inverted`. - */ - CIQ.Marker.Performance.prototype.calculateYPosition = function (params) { - var marker = params.marker, - panel = params.panel, - height = params.height, - side = params.half, - offset = params.offset, - inverted = params.inverted; - var stx = marker.params.stx, - chart = stx.chart; - - // this code finds the actual tick or the one right before to put the marker on. - var useHighs = stx.chart.highLowBars; - var quote = chart.dataSet[marker.tick]; - if (!quote) return; - - var price = useHighs ? quote.High : quote.Close; - var position = marker.params.yPositioner, - y; - switch (position) { - case "value": // this is actuallly our default case - if (marker.params.y || marker.params.y === 0) - y = stx.pixelFromPrice(marker.params.y, panel) - height * 0.5 + side; - else y = stx.pixelFromPrice(price, panel) - offset; - break; - case "above_candle": - y = stx.pixelFromPrice(price, panel) - offset; - break; - case "below_candle": - y = stx.pixelFromPrice(quote.Low || price, panel); - if (inverted && offset) y += offset; - else y += side; - break; - case "on_candle": - var h = quote.High || quote.Close, - l = quote.Low || quote.Low === 0 || quote.Close; - y = stx.pixelFromPrice((h + l) / 2, panel) - height * 0.5 + side; - break; - case "top": - y = stx.pixelFromPrice(panel.yAxis.high, panel); - if (inverted && offset) y += offset; - else y += side; - break; - case "bottom": - y = stx.pixelFromPrice(panel.yAxis.low, panel) - (offset || side); // if no stem offset use half so the whole marker is above the axis - break; - default: - break; - } - return y; - }; - - /** - * Method to setup the actual DOM node that gets appended to the chart for Performance markers. - * Performance markers require the entire DOM of the template for the styles to be calculated correctly but we only want to append the "pop-up" expand `div`. - * - * @param {CIQ.Marker} marker The marker to which this node belongs. - * @return {HTMLElement} Expand the pop-up node that will be appended to the chart for the performance marker. - * @private - */ - CIQ.Marker.Performance.prototype.prepareForHolder = function (marker) { - var expand = this.expand, - stx = marker.params.stx; - expand.classList.add(this.params.type); - stx.markerHelper.domMarkers.push(marker); - return expand; - }; - - /** - * Adds click and touch events to the marker pop-up when it is appended to the chart. - * - * @param {CIQ.Marker} marker - * @private - * @since 7.2.0 - */ - CIQ.Marker.Performance.prototype.addToHolder = function (marker) { - var expand = this.expand, - stx = marker.params.stx; - - CIQ.Marker.Performance.reconstituteExpanded(stx); - CIQ.Marker.Performance.consolidateExpanded(stx); - this.quickCache(marker); - - if (expand.clickClosure) return; - - function clickClosure(e) { - stx.activeMarker = marker; - stx.activeMarker.click({ - cx: e.clientX, - cy: e.clientY, - panel: stx.currentPanel - }); - e.stopPropagation(); - } - // CIQ.safeClickTouch, in this case, attaches clickClosure to the pointerup event - // Attaching the listener explicitly here to ensure stopPropagation and prevent accidental triggering of other markers - expand.addEventListener("mousedown", clickClosure); - expand.addEventListener("touchstart", clickClosure); - expand.clickClosure = clickClosure; - }; - - /** - * Removes a high performance canvas markers from the `markerHelper.domMarkers` array. - * We use this instead of {@link CIQ.ChartEngine#removeFromHolder} because that will remove the whole marker instead of just removing the DOM node. - * - * @private - * @since 7.2.0 - */ - CIQ.Marker.Performance.prototype.remove = function (marker) { - var stx = marker.params.stx; - if (!stx) return; - if (!stx.markerHelper.domMarkers) return; // if never anything appended return - - var idx = stx.markerHelper.domMarkers.indexOf(marker); - if (idx != -1) stx.markerHelper.domMarkers.splice(idx, 1); - if (marker.attached) { - var panel = stx.panels[marker.params.panelName]; - var expand = marker.params.node.expand; - if (expand.parentNode === panel.subholder) - panel.subholder.removeChild(expand); - expand.removeEventListener("click", expand.clickClosure); - } - }; - - /** - * Click event handler for performance markers when they are clicked in the canvas. - * Adds or removes the marker's pop-up expand `div` to the chart, depending on whether it has already been activated. - * - * @memberof CIQ.Marker.Performance - * @param {object} params Configuration parameters. - * @param {number} params.cx Client x-coordinate of click. - * @param {number} params.cy Client y-coordinate of click. - * @param {CIQ.Marker} params.marker Marker that was clicked. - * @param {CIQ.ChartEngine.Panel} params.panel Panel where the click occurred. - * @since 7.2.0 - */ - CIQ.Marker.Performance.prototype.click = function (params) { - if (!this.hasText) return; // don't display anything if there's nothing to display! - - if (typeof arguments[0] === "number") { - params = { - cx: arguments[0], - cy: arguments[1], - marker: arguments[2], - panel: arguments[3] - }; - } - const { cx, cy, marker, panel } = params; - var stx = marker.params.stx; - - var position; - if (marker.attached) { - var expand = this.expand; - // checks to see if we clicked on the scroll bar and if we did return - if ( - expand.rects.width - - expand.scrollBarWidth + - expand.transform.translateX < - stx.backOutX(cx) && - stx.backOutX(cx) < expand.rects.width + expand.transform.translateX - ) - return; - this.remove(marker); - } else { - stx.addToHolder(marker); - position = true; - } - marker.attached = !marker.attached; - marker.active = !marker.active; - if (position) marker.stxNodeCreator.positionPopUpNode(marker); - }; -} - -}; - - -let __js_advanced_renderersAdvanced_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -/* - * SEE OVERWRITTEN METHOD FOR FULL DOCUMENTATION IN core/renderer.js - */ -CIQ.Renderer.OHLC.requestNew = function (featureList, params) { - var type = null, - isHlc = params.hlc, - isColored = params.colored, - isHollow = params.hollow, - isVolume = params.volume, - histogram = params.histogram; - for (var pt = 0; pt < featureList.length; pt++) { - var pType = featureList[pt]; - switch (pType) { - case "bar": - case "candle": - type = pType; - break; - case "volume": - isVolume = true; - break; - case "hollow": - isHollow = true; - break; - case "colored": - isColored = true; - break; - case "histogram": - histogram = true; - type = "candle"; - break; - case "hlc": - isHlc = true; - type = "bar"; - break; - default: - return null; // invalid chartType for this renderer - } - } - if (type === null) return null; - - return new CIQ.Renderer.OHLC({ - params: CIQ.extend(params, { - type: type, - hlc: isHlc, - colored: isColored, - hollow: isHollow, - volume: isVolume, - histogram: histogram - }) - }); -}; - -/* - * Overrides method in core.js - */ -CIQ.Renderer.OHLC.getChartParts = function (style, colorUseOpen) { - var CLOSEUP = 1; // today's close greater than yesterday's close - var CLOSEDOWN = 2; // today's close less than yesterday's close - var CLOSEEVEN = 4; // today's close the same as yesterday's close - var CANDLEUP = 8; // today's close greater than today's open - var CANDLEDOWN = 16; // today's close less than today's open - var CANDLEEVEN = 32; // today's close equal to today's open - return [ - {type:"histogram", drawType:"histogram", style:"stx_histogram_up", condition:CANDLEUP, fill:"fill_color_up", border:"border_color_up", useColorInMap:true, useBorderStyleProp:true}, - {type:"histogram", drawType:"histogram", style:"stx_histogram_down", condition:CANDLEDOWN, fill:"fill_color_down", border:"border_color_down", useColorInMap:true, useBorderStyleProp:true}, - {type:"histogram", drawType:"histogram", style:"stx_histogram_even", condition:CANDLEEVEN, fill:"fill_color_even", border:"border_color_even", skipIfPass:true, useColorInMap:true, useBorderStyleProp:true}, - {type:"bar", drawType:"bar", style:style||"stx_bar_chart", border:"border_color", useColorInMap:true}, - {type:"bar", drawType:"bar", style:"stx_bar_up", condition:colorUseOpen?CANDLEUP:CLOSEUP, border:"border_color_up", useColorInMap:true}, - {type:"bar", drawType:"bar", style:"stx_bar_down", condition:colorUseOpen?CANDLEDOWN:CLOSEDOWN, border:"border_color_down", useColorInMap:true}, - {type:"bar", drawType:"bar", style:"stx_bar_even", condition:colorUseOpen?CANDLEEVEN:CLOSEEVEN, border:"border_color_even", skipIfPass:true, useColorInMap:true}, - {type:"candle", drawType:"shadow", style:"stx_candle_shadow", border:"border_color_up"}, - {type:"candle", drawType:"shadow", style:"stx_candle_shadow_up", condition:CANDLEUP, border:"border_color_up"}, - {type:"candle", drawType:"shadow", style:"stx_candle_shadow_down", condition:CANDLEDOWN, border:"border_color_down"}, - {type:"candle", drawType:"shadow", style:"stx_candle_shadow_even", condition:CANDLEEVEN, border:"border_color_even", skipIfPass:true}, - {type:"candle", drawType:"candle", style:"stx_candle_up", condition:CANDLEUP, fill:"fill_color_up", border:"border_color_up", useColorInMap:true, useBorderStyleProp:true}, - {type:"candle", drawType:"candle", style:"stx_candle_down", condition:CANDLEDOWN, fill:"fill_color_down", border:"border_color_down", useColorInMap:true, useBorderStyleProp:true}, - {type:"hollow", drawType:"shadow", style:"stx_hollow_candle_up", condition:CLOSEUP, border:"border_color_up"}, - {type:"hollow", drawType:"shadow", style:"stx_hollow_candle_down", condition:CLOSEDOWN, border:"border_color_down"}, - {type:"hollow", drawType:"shadow", style:"stx_hollow_candle_even", condition:CLOSEEVEN, border:"border_color_even", skipIfPass:true}, - {type:"hollow", drawType:"candle", style:"stx_hollow_candle_up", condition:CLOSEUP|CANDLEDOWN, fill:"fill_color_up", border:"border_color_up", useColorInMap:true}, - {type:"hollow", drawType:"candle", style:"stx_hollow_candle_down", condition:CLOSEDOWN|CANDLEDOWN, fill:"fill_color_down", border:"border_color_down", useColorInMap:true}, - {type:"hollow", drawType:"candle", style:"stx_hollow_candle_even", condition:CLOSEEVEN|CANDLEDOWN, fill:"fill_color_even", border:"border_color_even", skipIfPass:true, useColorInMap:true}, - {type:"hollow", drawType:"candle", style:"stx_hollow_candle_up", condition:CLOSEUP|CANDLEUP, fill:"fill_color_up", border:"border_color_up"}, - {type:"hollow", drawType:"candle", style:"stx_hollow_candle_down", condition:CLOSEDOWN|CANDLEUP, fill:"fill_color_down", border:"border_color_down"}, - {type:"hollow", drawType:"candle", style:"stx_hollow_candle_even", condition:CLOSEEVEN|CANDLEUP, fill:"fill_color_even", border:"border_color_even"}, - ]; // prettier-ignore -}; - -/** - * Creates a Bars renderer, a derivation of the OHLC renderer. - * - * Note: by default the renderer will display bars as underlays. As such, they will appear below any other studies or drawings. - * - * The Bars renderer is used to create the following drawing types: bar, colored bar. - * - * See {@link CIQ.Renderer#construct} for parameters required by all renderers - * @param {object} config Config for renderer - * @param {object} [config.params] Parameters to control the renderer itself - * @param {boolean} [config.params.useChartLegend=false] Set to true to use the built in canvas legend renderer. See {@link CIQ.ChartEngine.Chart#legendRenderer}; - * @param {string} [config.params.style] Style name to use in lieu of defaults for the type - * @param {boolean} [config.params.colored] For bar or hlc, specifies using a condition or colorFunction to determine color - * @param {string} [config.params.colorBasis="close"] Will compute color based on whether current close is higher or lower than previous close. Set to "open" to compute this off the open rather than yesterday's close. - * @param {function} [config.params.colorFunction] Override function (or string) used to determine color of bar. May be an actual function or a string name of the registered function (see {@link CIQ.Renderer.registerColorFunction}) - * - * Common valid parameters for use by attachSeries.:
- * `border_color` - Color to use for uncolored bars.
- * `border_color_up` - Color to use for up bars.
- * `border_color_down` - Color to use for down bars.
- * `border_color_even` - Color to use for even bars.
- * - * @constructor - * @name CIQ.Renderer.Bars - * @since 5.1.1, creates only Bar type charts - * @example - // Colored bar chart - var renderer=stxx.setSeriesRenderer(new CIQ.Renderer.Bars({params:{name:"bars", colored:true}})); - */ - -CIQ.Renderer.Bars = function (config) { - this.construct(config); - var params = this.params; - params.type = "bar"; - this.highLowBars = this.barsHaveWidth = this.standaloneBars = true; - params.hlc = params.volume = params.hollow = params.histogram = false; -}; -CIQ.inheritsFrom(CIQ.Renderer.Bars, CIQ.Renderer.OHLC, false); - -/** - * Creates a HLC renderer, a derivation of the Bars renderer. - * - * Note: by default the renderer will display bars as underlays. As such, they will appear below any other studies or drawings. - * - * The HLC renderer is used to create the following drawing types: hlc, colored hlc. - * - * See {@link CIQ.Renderer#construct} for parameters required by all renderers - * @param {object} config Config for renderer - * @param {object} [config.params] Parameters to control the renderer itself - * @param {boolean} [config.params.useChartLegend=false] Set to true to use the built in canvas legend renderer. See {@link CIQ.ChartEngine.Chart#legendRenderer}; - * @param {string} [config.params.style] Style name to use in lieu of defaults for the type - * @param {boolean} [config.params.colored] For bar or hlc, specifies using a condition or colorFunction to determine color - * @param {string} [config.params.colorBasis="close"] Will compute color based on whether current close is higher or lower than previous close. Set to "open" to compute this off the open rather than yesterday's close. - * @param {function} [config.params.colorFunction] Override function (or string) used to determine color of bar. May be an actual function or a string name of the registered function (see {@link CIQ.Renderer.registerColorFunction}) - * - * Common valid parameters for use by attachSeries.:
- * `border_color` - Color to use for uncolored bars.
- * `border_color_up` - Color to use for up bars.
- * `border_color_down` - Color to use for down bars.
- * `border_color_even` - Color to use for even bars.
- * - * @constructor - * @name CIQ.Renderer.HLC - * @since 5.1.1 - * @example - // Colored hlc chart - var renderer=stxx.setSeriesRenderer(new CIQ.Renderer.HLC({params:{name:"hlc", colored:true}})); - */ - -CIQ.Renderer.HLC = function (config) { - this.construct(config); - var params = this.params; - params.type = "bar"; - params.hlc = true; - this.highLowBars = this.barsHaveWidth = this.standaloneBars = true; - params.volume = params.hollow = params.histogram = false; -}; -CIQ.inheritsFrom(CIQ.Renderer.HLC, CIQ.Renderer.Bars, false); - -/** - * Creates a Shading renderer - * This is just like Lines renderer except it will allow shading between lines connected by a common y axis. - * - * Notes: - * - By default the renderer will display lines as underlays. As such, they will appear below the chart ticks and any other studies or drawings. - * - Series not linked to an explicit y axis through a custom renderer must have 'shareYAxis' set to true to use this feature. - * - * See {@link CIQ.Renderer#construct} for parameters required by all renderers - * - * Example:
- * - * @param {Object} config Config for renderer - * @param {object} [config.params] Parameters to control the renderer itself - * @param {number} [config.params.width] Width of the rendered line - * - * Common valid parameters for use by attachSeries.:
- * `color` - Specify the color for the line and shading in rgba, hex or by name.
- * `pattern` - Specify the pattern as an array. For instance [5,5] would be five pixels and then five empty pixels.
- * `width` - Specify the width of the line.
- * - * @constructor - * @name CIQ.Renderer.Shading - * @version ChartIQ Advanced Package - */ -CIQ.Renderer.Shading = function (config) { - this.construct(config); - this.beenSetup = false; - this.errTimeout = null; - this.params.useChartLegend = false; - this.shading = []; - if (this.params.type == "rangechannel") this.highLowBars = true; -}; -CIQ.inheritsFrom(CIQ.Renderer.Shading, CIQ.Renderer.Lines, false); - -/** - * Returns a new Shading renderer if the featureList calls for it - * FeatureList should contain "rangechannel" (draws high and low plots and shades between) - * Called by {@link CIQ.Renderer.produce} to create a renderer for the main series - * @param {array} featureList List of rendering terms requested by the user, parsed from the chartType - * @param {object} [params] Parameters used for the series to be created, used to create the renderer - * @return {CIQ.Renderer.Shading} A new instance of the Shading renderer, if the featureList matches - * @memberof CIQ.Renderer.Shading - * @private - * @since 5.1.0 - */ -CIQ.Renderer.Shading.requestNew = function (featureList, params) { - let type = null, - step = null; - for (let pt = 0; pt < featureList.length; pt++) { - let pType = featureList[pt]; - if (pType == "rangechannel") type = "rangechannel"; - else if (pType == "step") step = true; - } - if (type === null) return null; - - return new CIQ.Renderer.Shading({ - params: CIQ.extend(params, { type, step }) - }); -}; - -/** - * Sets the shading scheme of the renderer. Lines must be connected by a common y axis. - * - * Example:
- * - * - * @param {array} scheme single object or array of objects denoting shading. - * @param {string} [scheme.primary] left series for comparison; if omitted, use chart.dataSegment[i].Close. - * @param {string} [scheme.secondary] right series for comparison; if omitted, use first series in the seriesMap. - * @param {string} [scheme.color] color in hex, rgb, rgba, etc to shade between primary and secondary. - * @param {string} [scheme.greater] color in hex, rgb, rgba, etc to shade between primary and secondary if primary is greater in price than secondary. - * @param {string} [scheme.lesser] color in hex, rgb, rgba, etc to shade between primary and secondary if primary is lesser in price than secondary. - *
Notes: - * - If scheme.greater _and_ scheme.lesser are omitted, scheme.color is used. - * - If scheme.greater _or_ scheme.lesser are omitted, stx.containerColor is used for the missing color. - * - At a bare minimum, scheme.color is required. It is not required if scheme.greater and scheme.lesser are supplied. - * - If scheme.primary is omitted, the shading will only occur if the series share the same axis as the chart.dataSegment[i].Close. - * - If shading cannot occur for any reason, series lines will still be drawn. - * @memberOf CIQ.Renderer.Shading - * @example - * renderer.setShading([ - * {primary:'ibm', secondary:'ge', greater:'green', lesser:'red'}, // switches shading based on crossover of values - * {primary:'aapl', secondary:'ge', greater:'orange'}, // same as above, but lesser color not specified, so shade that area the container color. - * {primary:'t', secondary:'intc', color:'blue'}, // color always blue between them regardless of which is higher or lower - * {secondary:'t', color:'yellow'}, // compares masterData with the named series - * {color:'yellow'} // automatically shades between master and the first series - * ]); - * @version ChartIQ Advanced Package - */ -CIQ.Renderer.Shading.prototype.setShading = function (scheme) { - if (scheme.constructor != Array) { - scheme = [scheme]; - } - this.shading = scheme; -}; - -CIQ.Renderer.Shading.prototype.draw = function () { - var stx = this.stx, - params = this.params, - chart = stx.panels[params.panel].chart; - if (params.type == "rangechannel") { - if (this.beenSetup) { - if (this.seriesParams.length > 2) - this.removeSeries(this.seriesParams[2].id); - } else { - this.beenSetup = true; - params.display = this.seriesParams[0].display; - params.yAxis = this.seriesParams[0].yAxis; - var shadeColor = this.seriesParams[0].color || "auto"; - var symbol = this.seriesParams[0].symbol, - prefix = ""; - if (symbol) prefix = symbol + "."; - this.removeAllSeries(true); - var name = params.name; - stx.addSeries(null, { - symbol: symbol, - loadData: !!symbol, - field: "High", - renderer: "Shading", - name: name, - style: "stx_line_up", - display: params.display, - shareYAxis: true - }); - stx.addSeries(null, { - symbol: symbol, - loadData: !!symbol, - field: "Low", - renderer: "Shading", - name: name, - style: "stx_line_down", - display: params.display, - shareYAxis: true - }); - this.setShading({ - primary: this.seriesParams[0].id, - secondary: this.seriesParams[1].id, - color: shadeColor - }); - } - } - if (!this.shading) { - if (!this.errTimeout) { - console.log( - "Warning: no shading scheme set. Use myRenderer.setShading(scheme) to set." - ); - var self = this; - this.errTimeout = setTimeout(function () { - self.errTimeout = null; - }, 10000); - } - } - var seriesMap = {}; - var s; - for (s = 0; s < this.seriesParams.length; s++) { - var defaultParams = {}; - if (chart.series[this.seriesParams[s].id]) { - // make sure the series is still there. - defaultParams = CIQ.clone( - chart.series[this.seriesParams[s].id].parameters - ); - } - seriesMap[this.seriesParams[s].id] = { - parameters: CIQ.extend( - CIQ.extend(defaultParams, params), - this.seriesParams[s] - ), - yValueCache: this.caches[this.seriesParams[s].id] - }; - } - stx.drawSeries(chart, seriesMap, params.yAxis, this); - - if (chart.legend && params.type == "rangechannel") { - if (!chart.legend.colorMap) chart.legend.colorMap = {}; - var display = params.display; - var colors = [ - stx.getCanvasColor("stx_line_up"), - stx.getCanvasColor("stx_line_down") - ]; - chart.legend.colorMap[display] = { - color: colors, - display: display, - isBase: this == stx.mainSeriesRenderer - }; // add in the optional display text to send into the legendRenderer function - } - - for (s in seriesMap) { - this.caches[s] = seriesMap[s].yValueCache; - } - - function joinFields(series) { - var map = seriesMap[series]; - if (map) { - var fld = map.parameters.field; - var subFld = map.parameters.subField; - return fld + (subFld ? "." + subFld : ""); - } - return series; - } - - for (s = 0; s < this.shading.length; s++) { - var scheme = this.shading[s]; - var color = scheme.color; - if (scheme.color == "auto") color = stx.defaultColor; - if (!scheme.primary) scheme.primary = "Close"; - if (!scheme.secondary && this.seriesParams[0]) - scheme.secondary = this.seriesParams[0].field; - - if (!scheme.secondary) continue; - else if (!seriesMap[scheme.primary] && scheme.primary != "Close") continue; - else if (!seriesMap[scheme.secondary]) continue; - else if ( - scheme.primary == "Close" && - params.yAxis && - params.yAxis != chart.yAxis - ) - continue; //don't allow shading across axes - - var topFields = joinFields(scheme.primary).split("."); - var bottomFields = joinFields(scheme.secondary).split("."); - var parameters = { - topBand: topFields[0], - topSubBand: topFields[1], - topColor: scheme.greater || color || stx.containerColor, - topAxis: params.yAxis, - bottomBand: bottomFields[0], - bottomSubBand: bottomFields[1], - bottomColor: scheme.lesser || color || stx.containerColor, - bottomAxis: scheme.primary == "Close" ? null : params.yAxis, - tension: params.tension || chart.tension, - opacity: 0.1, - step: params.step - }; - if (!parameters.topColor && !parameters.bottomColor) continue; - if (!params.highlight && stx.highlightedDraggable) - parameters.opacity *= 0.3; - CIQ.fillIntersecting(stx, params.panel, parameters); - } -}; - -/** - * Creates a multi-part histogram renderer where bars can be stacked one on top of the other, clustered next to each other, or overlaid over each other. - * - * See {@link CIQ.Renderer#construct} for parameters required by all renderers. - * - * See {@link CIQ.ChartEngine#drawHistogram} for more details. - * - * @param {Object} config Config for renderer - * @param {object} [config.params] Parameters to control the renderer itself - * @param {boolean} [config.params.defaultBorders =false] Whether to draw a border for each bar as a whole. Can be overridden by a border set for a series. - * @param {number} [config.params.widthFactor =.8] Width of each bar as a percentage of the candleWidth. Valid values are 0.00-1.00. - * @param {number} [config.params.heightPercentage =.7] The amount of vertical space to use, valid values are 0.00-1.00. - * @param {boolean} [config.params.bindToYAxis =true] Set to true to bind the rendering to the y-axis and to draw it. Automatically set if params.yAxis is present. - * @param {string} [config.params.subtype="overlaid"] Subtype of rendering "stacked", "clustered", "overlaid" - * - * Common valid parameters for use by attachSeries.:
- * `fill_color_up` - Color to use for up histogram bars.
- * `fill_color_down` - Color to use for down histogram bars.
- * `border_color_up` - Color to use for the border of up histogram bars.
- * `border_color_down` - Color to use for the order of down histogram bars.
- * - * @constructor - * @name CIQ.Renderer.Histogram - * @example - // configure the histogram display - var params={ - name: "Sentiment Data", - subtype: "stacked", - heightPercentage: .7, // how high to go. 1 = 100% - widthFactor: .8 // to control space between bars. 1 = no space in between - }; - - //legend creation callback (optional) - function histogramLegend(colors){ - stxx.chart.legendRenderer(stxx,{legendColorMap:colors, coordinates:{x:260, y:stxx.panels["chart"].yAxis.top+30}, noBase:true}); - } - - // set the renderer - var histRenderer=stxx.setSeriesRenderer(new CIQ.Renderer.Histogram({params: params, callback: histogramLegend})); - - // add data and attach. - stxx.addSeries("^NIOALL", {display:"Symbol 1"}, function() {histRenderer.attachSeries("^NIOALL","#6B9CF7").ready();}); - stxx.addSeries("^NIOAFN", {display:"Symbol 2"}, function() {histRenderer.attachSeries("^NIOAFN","#95B7F6").ready();}); - stxx.addSeries("^NIOAMD", {display:"Symbol 3"}, function() {histRenderer.attachSeries("^NIOAMD","#B9D0F5").ready();}); - * - * @example - // this is an example on how completely remove a renderer and all associated data. - // This should only be necessary if you are also removing the chart itself - - // Remove all series from the renderer including series data from the masterData - renderer.removeAllSeries(true); - - // detach the series renderer from the chart. - stxx.removeSeriesRenderer(renderer); - - // delete the renderer itself. - delete renderer; - - * @example Set a baseline value, allowing negative bars. - * const yax = new CIQ.ChartEngine.YAxis({ - * baseline: 0 - * }); - * const rndr = stxx.setSeriesRenderer( - * new CIQ.Renderer.Histogram({ - * params: { - * // Can be an overlaid or clustered histogram. - * subtype: 'clustered', - * yAxis: yax - * } - * }) - * ); - * - * @example Render a horizontal line at the baseline value. - * const yax = new CIQ.ChartEngine.YAxis({ - * baseline: { - * value: 0, - * // Must provide color to render the horizontal line, - * // and can optionally provide pattern, lineWidth, and opacity. - * color: "red", - * pattern: "dotted", - * lineWidth: 2, - * opacity: 1 - * } - * }); - * - * @version ChartIQ Advanced Package - * @since 7.5.0 Added the ability to draw negative bars when `yAxis.baseline` is set to zero - * or some other value (see examples). - */ -CIQ.Renderer.Histogram = function (config) { - this.construct(config); - this.params.type = "histogram"; - this.barsHaveWidth = this.standaloneBars = true; - - if (this.params.yAxis) { - this.params.bindToYAxis = true; - - if (typeof this.params.yAxis.baseline == "number") { - this.params.yAxis.baseline = { - value: this.params.yAxis.baseline - }; - } - } -}; - -CIQ.inheritsFrom(CIQ.Renderer.Histogram, CIQ.Renderer, false); - -CIQ.Renderer.Histogram.prototype.adjustYAxis = function () { - const yAxis = this.params.yAxis; - - if (!yAxis || yAxis.baseline) return; - - yAxis.min = 0; - yAxis.highValue /= this.params.heightPercentage || 1; -}; - -CIQ.Renderer.Histogram.prototype.draw = function () { - var params = CIQ.clone(this.params); - params.type = params.subtype; - this.useSum = params.subtype == "stacked"; - if (!params.yAxis || params.yAxis == this.stx.chart.yAxis) - params.bindToYAxis = true; - this.stx.drawHistogram(params, this.seriesParams); - - const baseline = params.yAxis && params.yAxis.baseline; - - if (baseline && baseline.color) { - const panel = this.stx.panels[this.params.panel]; - const baselineY = - this.stx.pixelFromPrice(baseline.value, panel, this.params.yAxis) - 0.5; - - this.stx.plotLine({ - x0: panel.left, - x1: panel.right, - y0: baselineY, - y1: baselineY, - color: baseline.color, - type: "line", - context: panel.chart.context, - confineToPanel: panel, - pattern: baseline.pattern || "solid", - lineWidth: baseline.lineWidth || 1, - opacity: baseline.opacity || 0.8, - globalCompositeOperation: "destination-over" - }); - } -}; - -CIQ.Renderer.Histogram.prototype.getBasis = function (quote, field, subField) { - var value = 0; - if (quote && this.useSum) { - for (var j = 0; j < this.seriesParams.length; j++) { - var seriesField = this.seriesParams[j].field; - if (seriesField === field) break; - var f = quote[seriesField]; - if (f && typeof f === "object") - f = - f[ - subField || - this.seriesParams[j].subField || - this.stx.chart.defaultPlotField || - "Close" - ]; - if (f) value += f; - } - } - return value; -}; - -/** - * Creates a Heatmap renderer. - * - * See {@link CIQ.Renderer#construct} for parameters required by all renderers. - * - * Each attached series will represent a stream of colors for the heatmap. - * - * **Note special data formatting when using [addSeries]{@link CIQ.ChartEngine#addSeries}, where the custom field that will be used for the stream of datapoints (`Bids` in our example), is an array of values.** - * - * Visual Reference - single color series:
- * ![img-histogram-single-color](img-histogram-single-color.png "img-histogram-single-color") - * - * For advanced heatmap implementations where all the data is received already with a color for each datapoint, use an injection that directly calls {@link CIQ.ChartEngine#drawHeatmap} as outlined in this example:
- * - * - * @param {Object} config Config for renderer - * @param {object} [config.params] Parameters to control the renderer itself - * @param {number} [config.params.widthFactor=1] Width of each bar as a percentage of the candleWidth. Valid values are 0.00-1.00. - * @param {number} [config.params.height] The amount of vertical space to use, in price units. For example, 2=>2 unit increments on yaxis. - * @constructor - * @name CIQ.Renderer.Heatmap - * @version ChartIQ Advanced Package - * @example - * // note special data formatting, where the custom field name that will be used for the stream of datapoints, is an array of values. - * var renderer=stxx.setSeriesRenderer(new CIQ.Renderer.Heatmap()); - * stxx.addSeries( - * "L2", - * { data:[ - * {DT:"2019-01-04",Bids:[100,100.3,100.2,101]}, - * {DT:"2019-01-07",Bids:[101,101.5,102,103]}, - * {DT:"2019-01-08",Bids:[101.2,101.5,101.7,102]}, - * {DT:"2019-01-09",Bids:[101.3,101.7,101.9]}, - * {DT:"2019-01-10",Bids:[102]}] - * }, - * function(){ - * renderer.attachSeries("L2", {field:"Bids",color:"#FF9300"}).ready(); - * } - * ); - */ -CIQ.Renderer.Heatmap = function (config) { - this.construct(config); - this.params.type = "heatmap"; - this.params.highlightable = false; - this.barsHaveWidth = this.standaloneBars = true; -}; - -CIQ.inheritsFrom(CIQ.Renderer.Heatmap, CIQ.Renderer, false); - -/** - * Returns a new `Heatmap` renderer if the `featureList` calls for it; `featureList` should contain "heatmap". - * Called by {@link CIQ.Renderer.produce} to create a renderer for the main series. - * - * @param {array} featureList List of rendering terms requested by the user, parsed from the chart type. - * @param {object} [params] Parameters used for the series to be created, used to create the renderer. - * @return {CIQ.Renderer.Heatmap} A new instance of the `Heatmap` renderer, if the `featureList` matches. - * @memberof CIQ.Renderer.Heatmap - * @private - * @since 7.3.0 - */ -CIQ.Renderer.Heatmap.requestNew = function (featureList, params) { - var type = null; - for (var pt = 0; pt < featureList.length; pt++) { - var pType = featureList[pt]; - if (pType == "heatmap") type = "heatmap"; - } - if (type === null) return null; - - return new CIQ.Renderer.Heatmap({ - params: CIQ.extend(params, { type: type }) - }); -}; - -CIQ.Renderer.Heatmap.prototype.draw = function () { - this.stx.drawHeatmap(CIQ.clone(this.params), this.seriesParams); -}; - -/** - * Creates a Scatter plot renderer - * See {@link CIQ.Renderer#construct} for parameters required by all renderers - * @param {Object} config Config for renderer - * @param {object} [config.params] Parameters to control the renderer itself - * @constructor - * @name CIQ.Renderer.Scatter - * @version ChartIQ Advanced Package - */ -CIQ.Renderer.Scatter = function (config) { - this.construct(config); - this.standaloneBars = this.barsHaveWidth = true; - this.bounded = true; -}; - -CIQ.inheritsFrom(CIQ.Renderer.Scatter, CIQ.Renderer.Lines, false); - -/** - * Returns a new Scatter renderer if the featureList calls for it - * FeatureList should contain "scatter" - * Called by {@link CIQ.Renderer.produce} to create a renderer for the main series - * @param {array} featureList List of rendering terms requested by the user, parsed from the chartType - * @param {object} [params] Parameters used for the series to be created, used to create the renderer - * @return {CIQ.Renderer.Scatter} A new instance of the Scatter renderer, if the featureList matches - * @memberof CIQ.Renderer.Scatter - * @since 5.1.0 - */ -CIQ.Renderer.Scatter.requestNew = function (featureList, params) { - var type = null; - for (var pt = 0; pt < featureList.length; pt++) { - var pType = featureList[pt]; - if (pType == "scatterplot") type = "scatter"; - } - if (type === null) return null; - - return new CIQ.Renderer.Scatter({ - params: CIQ.extend(params, { type: type }) - }); -}; - -CIQ.Renderer.Scatter.prototype.drawIndividualSeries = function ( - chart, - parameters -) { - var panel = this.stx.panels[parameters.panel] || chart.panel; - var rc = { colors: [] }; - if (this.stx.scatter) rc = this.stx.scatter(panel, parameters); - else console.warn("Error, Scatter renderer requires customChart.js"); - return rc; -}; - -}; - - -let __js_advanced_studies_accumulationDistribution_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -if (!CIQ.Studies) { - console.error( - "accumulationDistribution feature requires first activating studies feature." - ); -} else { - CIQ.Studies.calculateAccumulationDistribution = function (stx, sd) { - var quotes = sd.chart.scrubbed; - for (var i = sd.startFrom; i < quotes.length; i++) { - if (!i) continue; - var quote = quotes[i]; - if (quote.futureTick) break; - var quote1 = quotes[i - 1]; - var todayAD = 0; - if (quote.Close > quote1.Close) { - todayAD = quote.Close - Math.min(quote.Low, quote1.Close); - } else if (quote.Close < quote1.Close) { - todayAD = quote.Close - Math.max(quote.High, quote1.Close); - } - if (sd.inputs["Use Volume"]) todayAD *= quote.Volume; - - var total = quote1["Result " + sd.name]; - if (!total) total = 0; - total += todayAD; - if (!isNaN(quote.Close)) quote["Result " + sd.name] = total; - } - }; - - CIQ.Studies.studyLibrary = CIQ.extend(CIQ.Studies.studyLibrary, { - "W Acc Dist": { - name: "Accumulation/Distribution", - calculateFN: CIQ.Studies.calculateAccumulationDistribution, - inputs: { "Use Volume": false } - } - }); -} - -}; - - -let __js_advanced_studies_adx_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -if (!CIQ.Studies) { - console.error("adx feature requires first activating studies feature."); -} else { - CIQ.Studies.calculateADX = function (stx, sd) { - CIQ.Studies.calculateStudyATR(stx, sd); - - var quotes = sd.chart.scrubbed; - var period = sd.days; - var smoothing = parseInt(sd.inputs["Smoothing Period"], 10); - if (!smoothing && smoothing !== 0) smoothing = period; - - if (quotes.length < sd.days + 1) { - sd.error = true; - return; - } - - var smoothTR = 0; - var smoothPlusDM = 0; - var smoothMinusDM = 0; - var runningDX = 0; - var quote; - for (var i = Math.max(1, sd.startFrom); i < quotes.length; i++) { - quote = quotes[i]; - var plusDM = Math.max(0, quote.High - quotes[i - 1].High); - var minusDM = Math.max(0, quotes[i - 1].Low - quote.Low); - if (plusDM > minusDM) minusDM = 0; - else if (minusDM > plusDM) plusDM = 0; - else plusDM = minusDM = 0; - - if (i <= period) { - smoothPlusDM += plusDM; - smoothMinusDM += minusDM; - smoothTR += quote["True Range " + sd.name]; - } else { - smoothPlusDM = - (quotes[i - 1]["_sm+DM " + sd.name] * (period - 1)) / period + plusDM; - smoothMinusDM = - (quotes[i - 1]["_sm-DM " + sd.name] * (period - 1)) / period + - minusDM; - smoothTR = - (quotes[i - 1]["_smTR " + sd.name] * (period - 1)) / period + - quote["True Range " + sd.name]; - } - quote["_sm+DM " + sd.name] = smoothPlusDM; - quote["_sm-DM " + sd.name] = smoothMinusDM; - quote["_smTR " + sd.name] = smoothTR; - - if (i < period) continue; - - var plusDI = (100 * smoothPlusDM) / smoothTR; - var minusDI = (100 * smoothMinusDM) / smoothTR; - var DX = (100 * Math.abs(plusDI - minusDI)) / (plusDI + minusDI); - - quote["+DI " + sd.name] = plusDI; - quote["-DI " + sd.name] = minusDI; - if (sd.inputs.Series !== false && smoothing) { - if (i < period + smoothing - 1) { - if (i == sd.startFrom) { - for (var j = period; j < sd.startFrom; j++) { - runningDX += - (100 * - Math.abs( - quotes[j]["+DI " + sd.name] - quotes[j]["-DI " + sd.name] - )) / - (quotes[j]["+DI " + sd.name] + quotes[j]["-DI " + sd.name]); - } - } - runningDX += DX; - } else if (i == period + smoothing - 1) { - quote["ADX " + sd.name] = runningDX / smoothing; - } else { - quote["ADX " + sd.name] = - (quotes[i - 1]["ADX " + sd.name] * (smoothing - 1) + DX) / - smoothing; - } - } - if (sd.inputs.Histogram) { - var histogram = sd.name + "_hist"; - if (!quote["+DI " + sd.name] && quote["+DI " + sd.name] !== 0) continue; - if (!quote["-DI " + sd.name] && quote["-DI " + sd.name] !== 0) continue; - quote[histogram] = quote["+DI " + sd.name] - quote["-DI " + sd.name]; - if (sd.inputs.Series === false) { - //delete these so yAxis computes max/min correctly - quote["+DI " + sd.name] = null; - quote["-DI " + sd.name] = null; - } - sd.outputMap[histogram] = ""; - } - } - }; - - CIQ.Studies.displayADX = function (stx, sd, quotes) { - var opacity = sd.underlay ? 0.3 : sd.inputs.Series ? 0.4 : 1; - if (sd.inputs.Series && sd.inputs.Shading) { - var topBand = "+DI " + sd.name, - bottomBand = "-DI " + sd.name; - var topColor = CIQ.Studies.determineColor( - sd.outputs[sd.outputMap[topBand]] - ), - bottomColor = CIQ.Studies.determineColor( - sd.outputs[sd.outputMap[bottomBand]] - ); - var yAxis = sd.getYAxis(stx); - var parameters = { - topBand: topBand, - bottomBand: bottomBand, - topColor: topColor, - bottomColor: bottomColor, - skipTransform: stx.panels[sd.panel].name != sd.chart.name, - topAxis: yAxis, - bottomAxis: yAxis, - opacity: 0.3 - }; - if (!sd.highlight && stx.highlightedDraggable) parameters.opacity *= 0.3; - CIQ.fillIntersecting(stx, sd.panel, parameters); - } - if (sd.inputs.Histogram) - CIQ.Studies.createHistogram(stx, sd, quotes, false, opacity); - if (sd.inputs.Series !== false) - CIQ.Studies.displaySeriesAsLine(stx, sd, quotes); - else if (!sd.inputs.Series && !sd.inputs.Histogram) - stx.displayErrorAsWatermark( - sd.panel, - stx.translateIf(sd.name) + ": " + stx.translateIf("Nothing to display") - ); - }; - - CIQ.Studies.studyLibrary = CIQ.extend(CIQ.Studies.studyLibrary, { - ADX: { - name: "ADX/DMS", - calculateFN: CIQ.Studies.calculateADX, - seriesFN: CIQ.Studies.displayADX, - inputs: { - Period: 14, - "Smoothing Period": 14, - Series: true, - Shading: false, - Histogram: false - }, - outputs: { - "+DI": "#00FF00", - "-DI": "#FF0000", - ADX: "auto", - "Positive Bar": "#00DD00", - "Negative Bar": "#FF0000" - } - } - }); -} - -}; - - -let __js_advanced_studies_alligator_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -if (!CIQ.Studies) { - console.error("alligator feature requires first activating studies feature."); -} else { - CIQ.Studies.calculateAlligator = function (stx, sd) { - var periods = { - J: Number(sd.inputs["Jaw Period"]), - T: Number(sd.inputs["Teeth Period"]), - L: Number(sd.inputs["Lips Period"]) - }; - var quotes = sd.chart.scrubbed; - if (quotes.length < Math.max(periods.J, periods.T, periods.L) + 1) { - sd.error = true; - return; - } - - if (sd.type === "Gator" || sd.inputs["Show Lines"]) { - // Gator always displays lines - CIQ.Studies.MA( - "welles wilder", - periods.J, - "hl/2", - sd.inputs["Jaw Offset"], - "Jaw", - stx, - sd - ); - CIQ.Studies.MA( - "welles wilder", - periods.T, - "hl/2", - sd.inputs["Teeth Offset"], - "Teeth", - stx, - sd - ); - CIQ.Studies.MA( - "welles wilder", - periods.L, - "hl/2", - sd.inputs["Lips Offset"], - "Lips", - stx, - sd - ); - } - - for (var i = sd.startFrom; i < quotes.length; i++) { - if (!quotes[i]) continue; - if (sd.type == "Gator") { - var jaw = quotes[i]["Jaw " + sd.name], - lips = quotes[i]["Lips " + sd.name], - teeth = quotes[i]["Teeth " + sd.name]; - if (teeth || teeth === 0) { - if (jaw || jaw === 0) - quotes[i][sd.name + "_hist1"] = Math.abs(jaw - teeth); - if (lips || lips === 0) - quotes[i][sd.name + "_hist2"] = -Math.abs(teeth - lips); - } - sd.outputMap = {}; - sd.outputMap[sd.name + "_hist1"] = ""; - sd.outputMap[sd.name + "_hist2"] = ""; - } - if (sd.inputs["Show Fractals"]) { - if ( - !quotes[i - 2] || - !quotes[i - 1] || - !quotes[i] || - !quotes[i + 1] || - !quotes[i + 2] - ) - continue; - if ( - quotes[i - 2].High && - quotes[i - 1].High && - quotes[i].High && - quotes[i + 1].High && - quotes[i + 2].High - ) { - if ( - quotes[i].High > quotes[i - 1].High && - quotes[i].High > quotes[i - 2].High && - quotes[i].High > quotes[i + 1].High && - quotes[i].High > quotes[i + 2].High - ) { - quotes[i]["Fractal High " + sd.name] = 1; - } - } - if ( - quotes[i - 2].Low && - quotes[i - 1].Low && - quotes[i].Low && - quotes[i + 1].Low && - quotes[i + 2].Low - ) { - if ( - quotes[i].Low < quotes[i - 1].Low && - quotes[i].Low < quotes[i - 2].Low && - quotes[i].Low < quotes[i + 1].Low && - quotes[i].Low < quotes[i + 2].Low - ) { - quotes[i]["Fractal Low " + sd.name] = 1; - } - } - } - } - }; - - CIQ.Studies.displayAlligator = function (stx, sd, quotes) { - function drawFractal(highLow, index) { - //stx.canvasFont("???"); - var y; - var flipped = stx.chart.panel.yAxis.flipped; - if (highLow == "high") { - context.fillStyle = stx.defaultColor; - context.textBaseline = flipped ? "top" : "bottom"; - y = stx.pixelFromPrice(quotes[index].High); - context.fillText( - flipped ? "\u25BC" : "\u25B2", - stx.pixelFromBar(i, stx.chart) - - context.measureText("\u25B2").width / 2 + - 1, - flipped ? y + 5 : y - 5 - ); // up arrow - } else if (highLow == "low") { - context.fillStyle = stx.defaultColor; - context.textBaseline = flipped ? "bottom" : "top"; - y = stx.pixelFromPrice(quotes[index].Low); - context.fillText( - flipped ? "\u25B2" : "\u25BC", - stx.pixelFromBar(i, stx.chart) - - context.measureText("\u25BC").width / 2 + - 1, - flipped ? y - 5 : y + 5 - ); // down arrow - } - } - var context = sd.getContext(stx); - if (sd.inputs["Show Lines"]) - CIQ.Studies.displaySeriesAsLine(stx, sd, quotes); - if (sd.inputs["Show Fractals"]) { - stx.startClip(); // Fractals always stay on the chart panel - context.globalAlpha = sd.underlay ? 0.3 : 1; - if (!sd.highlight && stx.highlightedDraggable) context.globalAlpha *= 0.3; - for (var i = 2; i < quotes.length - 2; i++) { - if (quotes[i]) { - if (quotes[i]["Fractal High " + sd.name]) drawFractal("high", i); - if (quotes[i]["Fractal Low " + sd.name]) drawFractal("low", i); - } - } - stx.endClip(); - } - }; - - CIQ.Studies.displayGator = function (stx, sd, quotes) { - var panel = stx.panels[sd.panel], - context = sd.getContext(stx); - var yAxis = sd.getYAxis(stx); - var y = stx.pixelFromPrice(0, panel, yAxis); - - var myWidth = stx.layout.candleWidth - 2; - if (myWidth < 2) myWidth = 1; - - var upColor = CIQ.Studies.determineColor(sd.outputs["Increasing Bar"]); - var downColor = CIQ.Studies.determineColor(sd.outputs["Decreasing Bar"]); - stx.canvasColor("stx_histogram"); - if (!sd.underlay) context.globalAlpha = 1; - context.fillStyle = "#CCCCCC"; - stx.startClip(sd.panel); - if (!sd.highlight && stx.highlightedDraggable) context.globalAlpha *= 0.3; - for (var i = 0; i < quotes.length; i++) { - var quote = quotes[i], - quote_1 = quotes[i - 1]; - if (!quote) continue; - for (var j = 1; j <= 2; j++) { - if (!quote_1) - quote_1 = stx.getPreviousBar(stx.chart, sd.name + "_hist" + j, i); - if (!quote_1) context.fillStyle = "#CCCCCC"; - else if ( - Math.abs(quote_1[sd.name + "_hist" + j]) < - Math.abs(quote[sd.name + "_hist" + j]) - ) - context.fillStyle = upColor; - else if ( - Math.abs(quote_1[sd.name + "_hist" + j]) > - Math.abs(quote[sd.name + "_hist" + j]) - ) - context.fillStyle = downColor; - if (quote.candleWidth) - myWidth = Math.floor(Math.max(1, quote.candleWidth - 2)); - context.fillRect( - Math.floor(stx.pixelFromBar(i, panel.chart) - myWidth / 2), - Math.floor(y), - Math.floor(myWidth), - Math.floor( - stx.pixelFromPrice(quote[sd.name + "_hist" + j], panel, yAxis) - y - ) - ); - } - } - stx.endClip(); - }; - - CIQ.Studies.studyLibrary = CIQ.extend(CIQ.Studies.studyLibrary, { - Alligator: { - name: "Alligator", - overlay: true, - seriesFN: CIQ.Studies.displayAlligator, - calculateFN: CIQ.Studies.calculateAlligator, - inputs: { - "Show Lines": true, - "Jaw Period": 13, - "Jaw Offset": 8, - "Teeth Period": 8, - "Teeth Offset": 5, - "Lips Period": 5, - "Lips Offset": 3, - "Show Fractals": false - }, - outputs: { Jaw: "#0000FF", Teeth: "#FF0000", Lips: "#00DD00" } - }, - Gator: { - name: "Gator Oscillator", - seriesFN: CIQ.Studies.displayGator, - calculateFN: CIQ.Studies.calculateAlligator, - inputs: { - "Jaw Period": 13, - "Jaw Offset": 8, - "Teeth Period": 8, - "Teeth Offset": 5, - "Lips Period": 5, - "Lips Offset": 3 - }, - outputs: { "Increasing Bar": "#00DD00", "Decreasing Bar": "#FF0000" }, - centerline: 0 - } - }); -} - -}; - - -let __js_advanced_studies_aroon_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -if (!CIQ.Studies) { - console.error("aroon feature requires first activating studies feature."); -} else { - CIQ.Studies.calculateAroon = function (stx, sd) { - var quotes = sd.chart.scrubbed; - if (quotes.length < sd.days + 1) { - sd.error = true; - return; - } - var daysSinceHigh = 0, - daysSinceLow = 0; - var xDayHigh = null, - xDayLow = null; - if (sd.startFrom > 0) { - var state = quotes[sd.startFrom - 1]["_state " + sd.name]; - if (state) { - daysSinceHigh = state[0]; - daysSinceLow = state[1]; - xDayHigh = state[2]; - xDayLow = state[3]; - } - } - var j; - for (var i = sd.startFrom; i < quotes.length; i++) { - var quote = quotes[i]; - if (quote.futureTick) break; - if (xDayHigh === null) xDayHigh = quote.High; - if (xDayLow === null) xDayLow = quote.Low; - xDayHigh = Math.max(xDayHigh, quote.High); - if (xDayHigh == quote.High) { - daysSinceHigh = 0; - } else { - daysSinceHigh++; - if (daysSinceHigh > sd.days) { - xDayHigh = quote.High; - daysSinceHigh = 0; - for (j = 1; j <= sd.days; j++) { - xDayHigh = Math.max(xDayHigh, quotes[i - j].High); - if (xDayHigh == quotes[i - j].High) { - daysSinceHigh = j; - } - } - } - } - xDayLow = Math.min(xDayLow, quote.Low); - if (xDayLow == quote.Low) { - daysSinceLow = 0; - } else { - daysSinceLow++; - if (daysSinceLow > sd.days) { - xDayLow = quote.Low; - daysSinceLow = 0; - for (j = 1; j <= sd.days; j++) { - xDayLow = Math.min(xDayLow, quotes[i - j].Low); - if (xDayLow == quotes[i - j].Low) { - daysSinceLow = j; - } - } - } - } - var nHi = !isNaN(quote.High), - nLo = !isNaN(quote.Low); - var up = 100 * (1 - daysSinceHigh / sd.days); - if (nHi) quote["Aroon Up " + sd.name] = up; - var down = 100 * (1 - daysSinceLow / sd.days); - if (nLo) quote["Aroon Down " + sd.name] = down; - if (nHi && nLo) - quote["Aroon Oscillator " + sd.name] = - quote["Aroon Up " + sd.name] - quote["Aroon Down " + sd.name]; - quote["_state " + sd.name] = [ - daysSinceHigh, - daysSinceLow, - xDayHigh, - xDayLow - ]; - } - }; - - CIQ.Studies.studyLibrary = CIQ.extend(CIQ.Studies.studyLibrary, { - Aroon: { - name: "Aroon", - range: "0 to 100", - calculateFN: CIQ.Studies.calculateAroon, - outputs: { "Aroon Up": "#00DD00", "Aroon Down": "#FF0000" } - }, - "Aroon Osc": { - name: "Aroon Oscillator", - calculateFN: CIQ.Studies.calculateAroon, - outputs: { "Aroon Oscillator": "auto" } - } - }); -} - -}; - - -let __js_advanced_studies_atr_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -if (!CIQ.Studies) { - console.error("atr feature requires first activating studies feature."); -} else { - CIQ.Studies.calculateATRBands = function (stx, sd) { - CIQ.Studies.calculateStudyATR(stx, sd); - var field = sd.inputs.Field; - if (!field || field == "field") field = "Close"; - CIQ.Studies.calculateGenericEnvelope( - stx, - sd, - sd.inputs.Shift, - field, - "ATR " + sd.name - ); - }; - - CIQ.Studies.calculateSTARCBands = function (stx, sd) { - CIQ.Studies.calculateStudyATR(stx, sd); - CIQ.Studies.MA( - "simple", - sd.inputs["MA Period"], - "Close", - 0, - "_MA", - stx, - sd - ); - CIQ.Studies.calculateGenericEnvelope( - stx, - sd, - sd.inputs.Multiplier, - "_MA " + sd.name, - "ATR " + sd.name - ); - }; - - CIQ.Studies.calculateATRStops = function (stx, sd) { - var quotes = sd.chart.scrubbed; - if (!quotes) return; - CIQ.Studies.calculateStudyATR(stx, sd); - var useHighLow = sd.inputs.HighLow; - for (var i = Math.max(sd.startFrom - 1, 1); i < quotes.length - 1; i++) { - var prices = quotes[i]; - var pd = quotes[i - 1]; - var prev = prices["Buy Stops " + sd.name]; - if (!prev) prev = prices["Sell Stops " + sd.name]; - if (!prev) prev = 0; - if (!prices || !pd) continue; - var base = prices.Close; - var result = base; - var offset = prices["ATR " + sd.name] * sd.inputs.Multiplier; - if (prices.Close > prev && pd.Close > prev) { - if (useHighLow) base = prices.High; - result = Math.max(prev, base - offset); - } else if (prices.Close <= prev && pd.Close <= prev) { - if (useHighLow) base = prices.Low; - result = Math.min(prev, base + offset); - } else if (prices.Close > prev) { - if (useHighLow) base = prices.High; - result = base - offset; - } else if (prices.Close <= prev) { - if (useHighLow) base = prices.Low; - result = base + offset; - } - if (base <= result) { - quotes[i + 1]["Buy Stops " + sd.name] = result; - delete quotes[i + 1]["Sell Stops " + sd.name]; - } else if (base > result) { - quotes[i + 1]["Sell Stops " + sd.name] = result; - delete quotes[i + 1]["Buy Stops " + sd.name]; - } - quotes[i + 1]["All Stops " + sd.name] = result; - } - sd.referenceOutput = "All Stops"; //so PSAR2 can draw a square wave - sd.outputMap = {}; - sd.outputMap["All Stops " + sd.name] = ""; - }; - - CIQ.Studies.studyLibrary = CIQ.extend(CIQ.Studies.studyLibrary, { - ATR: { - name: "Average True Range", - calculateFN: CIQ.Studies.calculateStudyATR, - outputs: { ATR: "auto" } - }, - "ATR Bands": { - name: "ATR Bands", - overlay: true, - seriesFN: CIQ.Studies.displayChannel, - calculateFN: CIQ.Studies.calculateATRBands, - inputs: { Period: 5, Field: "field", Shift: 3, "Channel Fill": true }, - outputs: { - "ATR Bands Top": "auto", - "ATR Bands Bottom": "auto", - "ATR Bands Channel": "auto" - }, - attributes: { - Shift: { min: 0.1, step: 0.1 } - } - }, - "STARC Bands": { - name: "STARC Bands", - overlay: true, - seriesFN: CIQ.Studies.displayChannel, - calculateFN: CIQ.Studies.calculateSTARCBands, - inputs: { - Period: 15, - "MA Period": 5, - Multiplier: 1.3, - "Channel Fill": true - }, - outputs: { - "STARC Bands Top": "auto", - "STARC Bands Median": "auto", - "STARC Bands Bottom": "auto" - }, - attributes: { - Multiplier: { min: 0.1, step: 0.1 } - } - }, - "ATR Trailing Stop": { - name: "ATR Trailing Stops", - overlay: true, - seriesFN: CIQ.Studies.displayPSAR2, - calculateFN: CIQ.Studies.calculateATRStops, - inputs: { - Period: 21, - Multiplier: 3, - "Plot Type": ["points", "squarewave"], - HighLow: false - }, - outputs: { "Buy Stops": "#FF0000", "Sell Stops": "#00FF00" }, - attributes: { - Multiplier: { min: 0.1, step: 0.1 } - } - } - }); -} - -}; - - -let __js_advanced_studies_awesomeOscillator_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -if (!CIQ.Studies) { - console.error( - "awesomeOscillator feature requires first activating studies feature." - ); -} else { - CIQ.Studies.calculateAwesomeOscillator = function (stx, sd) { - var quotes = sd.chart.scrubbed; - if (quotes.length < 33) { - sd.error = true; - return; - } - - CIQ.Studies.MA("simple", 5, "hl/2", 0, "_MA5", stx, sd); - CIQ.Studies.MA("simple", 34, "hl/2", 0, "_MA34", stx, sd); - - for (var i = Math.max(sd.startFrom, 33); i < quotes.length; i++) { - if (!quotes[i]) continue; - quotes[i][sd.name + "_hist"] = - quotes[i]["_MA5 " + sd.name] - quotes[i]["_MA34 " + sd.name]; - } - sd.outputMap = {}; - sd.outputMap[sd.name + "_hist"] = ""; - }; - - CIQ.Studies.displayAwesomeOscillator = function (stx, sd, quotes) { - var panel = stx.panels[sd.panel], - context = sd.getContext(stx); - var yAxis = sd.getYAxis(stx); - - var y = stx.pixelFromPrice(0, panel, yAxis); - - var myWidth = stx.layout.candleWidth - 2; - if (myWidth < 2) myWidth = 1; - - var upColor = CIQ.Studies.determineColor(sd.outputs["Increasing Bar"]); - var downColor = CIQ.Studies.determineColor(sd.outputs["Decreasing Bar"]); - stx.canvasColor("stx_histogram"); - if (!sd.underlay) context.globalAlpha = 1; - context.fillStyle = "#CCCCCC"; - stx.startClip(sd.panel); - if (!sd.highlight && stx.highlightedDraggable) context.globalAlpha *= 0.3; - for (var i = 0; i < quotes.length; i++) { - var quote = quotes[i], - quote_1 = quotes[i - 1]; - if (!quote_1) - quote_1 = stx.getPreviousBar(stx.chart, sd.name + "_hist", i); - if (!quote) continue; - if (!quote_1); - else if (quote_1[sd.name + "_hist"] < quote[sd.name + "_hist"]) - context.fillStyle = upColor; - else if (quote_1[sd.name + "_hist"] > quote[sd.name + "_hist"]) - context.fillStyle = downColor; - if (quote.candleWidth) - myWidth = Math.floor(Math.max(1, quote.candleWidth - 2)); - context.fillRect( - Math.floor(stx.pixelFromBar(i, panel.chart) - myWidth / 2), - Math.floor(y), - Math.floor(myWidth), - Math.floor( - stx.pixelFromPrice(quote[sd.name + "_hist"], panel, yAxis) - y - ) - ); - } - stx.endClip(); - }; - - CIQ.Studies.studyLibrary = CIQ.extend(CIQ.Studies.studyLibrary, { - Awesome: { - name: "Awesome Oscillator", - seriesFN: CIQ.Studies.displayAwesomeOscillator, - calculateFN: CIQ.Studies.calculateAwesomeOscillator, - inputs: {}, - outputs: { "Increasing Bar": "#00DD00", "Decreasing Bar": "#FF0000" } - } - }); -} - -}; - - -let __js_advanced_studies_balanceOfPower_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -if (!CIQ.Studies) { - console.error( - "balanceOfPower feature requires first activating studies feature." - ); -} else { - CIQ.Studies.calculateBalanceOfPower = function (stx, sd) { - var quotes = sd.chart.scrubbed; - if (quotes.length < sd.days + 1) { - sd.error = true; - return; - } - for (var i = sd.startFrom; i < quotes.length; i++) { - var quote = quotes[i]; - quote["_Ratio " + sd.name] = quote.Close - quote.Open; - if (quote.High - quote.Low !== 0) - // avoid division by zero - quote["_Ratio " + sd.name] /= quote.High - quote.Low; - } - CIQ.Studies.MA( - sd.inputs["Moving Average Type"], - sd.days, - "_Ratio " + sd.name, - 0, - "Result", - stx, - sd - ); - }; - - CIQ.Studies.studyLibrary = CIQ.extend(CIQ.Studies.studyLibrary, { - "Bal Pwr": { - name: "Balance of Power", - range: "-1 to 1", - centerline: 0, - calculateFN: CIQ.Studies.calculateBalanceOfPower, - inputs: { Period: 14, "Moving Average Type": "ma" } - } - }); -} - -}; - - -let __js_advanced_studies_bollinger_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -if (!CIQ.Studies) { - console.error("bollinger feature requires first activating studies feature."); -} else { - CIQ.Studies.calculateBollinger = function (stx, sd) { - var field = sd.inputs.Field; - if (!field || field == "field") field = "Close"; - - CIQ.Studies.MA( - sd.inputs["Moving Average Type"], - sd.days, - field, - 0, - "_MA", - stx, - sd - ); - - sd.std = new CIQ.Studies.StudyDescriptor(sd.name, "STD Dev", sd.panel); - sd.std.chart = sd.chart; - sd.std.startFrom = sd.startFrom; - sd.std.days = sd.days; - sd.std.inputs = { - Field: field, - "Standard Deviations": 1, - Type: sd.inputs["Moving Average Type"] - }; - sd.std.outputs = { "_STD Dev": null }; - CIQ.Studies.calculateStandardDeviation(stx, sd.std); - - CIQ.Studies.calculateGenericEnvelope( - stx, - sd, - sd.inputs["Standard Deviations"], - "_MA " + sd.name, - "_STD Dev " + sd.name - ); - if (sd.type == "Boll %b") sd.zoneOutput = "%b"; - }; - - CIQ.Studies.studyLibrary = CIQ.extend(CIQ.Studies.studyLibrary, { - "Bollinger Bands": { - name: "Bollinger Bands", - overlay: true, - calculateFN: CIQ.Studies.calculateBollinger, - seriesFN: CIQ.Studies.displayChannel, - inputs: { - Period: 20, - Field: "field", - "Standard Deviations": 2, - "Moving Average Type": "ma", - "Channel Fill": true - }, - outputs: { - "Bollinger Bands Top": "auto", - "Bollinger Bands Median": "auto", - "Bollinger Bands Bottom": "auto" - }, - attributes: { - "Standard Deviations": { min: 0.1, step: 0.1 } - } - }, - "Boll %b": { - name: "Bollinger %b", - calculateFN: CIQ.Studies.calculateBollinger, - inputs: { - Period: 20, - Field: "field", - "Standard Deviations": 2, - "Moving Average Type": "ma" - }, - outputs: { "%b": "auto" }, - parameters: { - init: { - studyOverZonesEnabled: true, - studyOverBoughtValue: 100, - studyOverBoughtColor: "auto", - studyOverSoldValue: 0, - studyOverSoldColor: "auto" - } - }, - attributes: { - "Standard Deviations": { min: 0.1, step: 0.1 } - } - }, - "Boll BW": { - name: "Bollinger Bandwidth", - calculateFN: CIQ.Studies.calculateBollinger, - inputs: { - Period: 20, - Field: "field", - "Standard Deviations": 2, - "Moving Average Type": "ma" - }, - outputs: { Bandwidth: "auto" }, - attributes: { - "Standard Deviations": { min: 0.1, step: 0.1 } - } - } - }); -} - -}; - - -let __js_advanced_studies_cci_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -if (!CIQ.Studies) { - console.error("cci feature requires first activating studies feature."); -} else { - CIQ.Studies.calculateCCI = function (stx, sd) { - var quotes = sd.chart.scrubbed; - if (quotes.length < sd.days + 1) { - sd.error = true; - return; - } - - CIQ.Studies.MA("simple", sd.days, "hlc/3", 0, "MA", stx, sd); - - for (var i = Math.max(sd.startFrom, sd.days - 1); i < quotes.length; i++) { - var quote = quotes[i]; - if (!quote) continue; - var md = 0; - for (var j = 0; j < sd.days; j++) { - md += Math.abs(quotes[i - j]["hlc/3"] - quote["MA " + sd.name]); - } - md /= sd.days; - if (Math.abs(md) < 0.00000001) quote["Result " + sd.name] = 0; - else - quote["Result " + sd.name] = - (quote["hlc/3"] - quote["MA " + sd.name]) / (0.015 * md); - } - }; - - CIQ.Studies.studyLibrary = CIQ.extend(CIQ.Studies.studyLibrary, { - CCI: { - name: "Commodity Channel Index", - calculateFN: CIQ.Studies.calculateCCI, - inputs: { Period: 20 }, - parameters: { - init: { - studyOverZonesEnabled: true, - studyOverBoughtValue: 100, - studyOverBoughtColor: "auto", - studyOverSoldValue: -100, - studyOverSoldColor: "auto" - } - }, - attributes: { - Period: { min: 2 } - } - } - }); -} - -}; - - -let __js_advanced_studies_centerOfGravity_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -if (!CIQ.Studies) { - console.error( - "centerOfGravity feature requires first activating studies feature." - ); -} else { - CIQ.Studies.calculateCenterOfGravity = function (stx, sd) { - var quotes = sd.chart.scrubbed; - if (quotes.length < sd.days) { - sd.error = true; - return; - } - var field = sd.inputs.Field; - if (!field || field == "field") field = "Close"; - for (var i = Math.max(sd.startFrom, sd.days - 1); i < quotes.length; i++) { - var num = 0, - den = 0; - for (var j = 0; j < sd.days; j++) { - var val = quotes[i - j][field]; - num -= (j + 1) * val; - den += val; - } - if (den) quotes[i]["Result " + sd.name] = num / den; - } - }; - - CIQ.Studies.studyLibrary = CIQ.extend(CIQ.Studies.studyLibrary, { - COG: { - name: "Center Of Gravity", - calculateFN: CIQ.Studies.calculateCenterOfGravity, - inputs: { Period: 10, Field: "field" } - } - }); -} - -}; - - -let __js_advanced_studies_chaikin_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -if (!CIQ.Studies) { - console.error("chaikin feature requires first activating studies feature."); -} else { - CIQ.Studies.calculateChaikinMoneyFlow = function (stx, sd) { - var quotes = sd.chart.scrubbed; - if (quotes.length < sd.days) { - sd.error = true; - return; - } - var sumMoneyFlow = 0, - sumVolume = 0; - var startQuote = quotes[sd.startFrom - 1]; - if (startQuote) { - if (startQuote["_sumMF " + sd.name]) - sumMoneyFlow = startQuote["_sumMF " + sd.name]; - if (startQuote["_sumV " + sd.name]) - sumVolume = startQuote["_sumV " + sd.name]; - } - for (var i = sd.startFrom; i < quotes.length; i++) { - if (quotes[i].High == quotes[i].Low) quotes[i]["_MFV " + sd.name] = 0; - else - quotes[i]["_MFV " + sd.name] = - (quotes[i].Volume * - (2 * quotes[i].Close - quotes[i].High - quotes[i].Low)) / - (quotes[i].High - quotes[i].Low); - sumMoneyFlow += quotes[i]["_MFV " + sd.name]; - sumVolume += quotes[i].Volume; - if (i > sd.days - 1) { - sumMoneyFlow -= quotes[i - sd.days]["_MFV " + sd.name]; - sumVolume -= quotes[i - sd.days].Volume; - if (sumVolume) - quotes[i]["Result " + sd.name] = sumMoneyFlow / sumVolume; - } - quotes[i]["_sumMF " + sd.name] = sumMoneyFlow; - quotes[i]["_sumV " + sd.name] = sumVolume; - } - }; - - CIQ.Studies.calculateChaikinVolatility = function (stx, sd) { - var quotes = sd.chart.scrubbed; - if (quotes.length < sd.days) { - sd.error = true; - return; - } - var i; - for (i = sd.startFrom; i < quotes.length; i++) { - if (quotes[i].futureTick) break; - quotes[i]["_High-Low " + sd.name] = quotes[i].High - quotes[i].Low; - } - CIQ.Studies.MA( - sd.inputs["Moving Average Type"], - sd.days, - "_High-Low " + sd.name, - 0, - "_MA", - stx, - sd - ); - - var roc = sd.inputs["Rate Of Change"]; - if (!roc) roc = sd.days; - for (i = Math.max(sd.startFrom, roc); i < quotes.length; i++) { - if (!quotes[i - roc]["_MA " + sd.name]) continue; - if (quotes[i].futureTick) break; - quotes[i]["Result " + sd.name] = - 100 * - (quotes[i]["_MA " + sd.name] / quotes[i - roc]["_MA " + sd.name] - 1); - } - }; - - CIQ.Studies.studyLibrary = CIQ.extend(CIQ.Studies.studyLibrary, { - "Chaikin MF": { - name: "Chaikin Money Flow", - calculateFN: CIQ.Studies.calculateChaikinMoneyFlow, - inputs: { Period: 20 } - }, - "Chaikin Vol": { - name: "Chaikin Volatility", - calculateFN: CIQ.Studies.calculateChaikinVolatility, - inputs: { Period: 14, "Rate Of Change": 2, "Moving Average Type": "ma" } - } - }); -} - -}; - - -let __js_advanced_studies_chande_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -if (!CIQ.Studies) { - console.error("chande feature requires first activating studies feature."); -} else { - CIQ.Studies.prettify.variable = "vma"; - CIQ.Studies.movingAverage.conversions.vma = "variable"; - CIQ.Studies.movingAverage.translations.variable = "Variable"; - CIQ.Studies.movingAverage.typeMap.vma = "Variable"; - CIQ.Studies.movingAverage.typeMap.variable = "Variable"; - - CIQ.Studies.calculateChandeForecast = function (stx, sd) { - var quotes = sd.chart.scrubbed; - if (quotes.length < sd.days + 1) { - sd.error = true; - return; - } - var field = sd.inputs.Field; - if (!field || field == "field") field = "Close"; - CIQ.Studies.MA("time series", sd.days, field, 0, "MA", stx, sd); - for (var i = Math.max(1, sd.startFrom); i < quotes.length; i++) { - var val = quotes[i][field]; - if (val && typeof val == "object") val = val[sd.subField]; - quotes[i]["Result " + sd.name] = - 100 * (1 - quotes[i]["MA " + sd.name] / val); - } - }; - - CIQ.Studies.calculateChandeMomentum = function (stx, sd) { - var name = sd.name; - for (var p in sd.outputs) { - name = p + " " + name; - } - var quotes = sd.chart.scrubbed; - if (quotes.length < sd.days + 1) { - sd.error = true; - return; - } - - var field = sd.inputs.Field; - if (!field || field == "field") field = "Close"; // only used when called from VMA - - var sumMomentum = 0, - absSumMomentum = 0; - var history = []; - for (var i = sd.startFrom - sd.days + 1; i < quotes.length; i++) { - if (i < 1) continue; - var q = quotes[i][field], - q1 = quotes[i - 1][field]; - if (q && typeof q == "object") q = q.Close; - if (q1 && typeof q1 == "object") q1 = q1.Close; - if (q1 === undefined) continue; // the field is not defined yet - - var diff = q - q1; - history.push(diff); - sumMomentum += diff; - absSumMomentum += Math.abs(diff); - if (history.length == sd.days) { - quotes[i][name] = (100 * sumMomentum) / absSumMomentum; - var old = history.shift(); - sumMomentum -= old; - absSumMomentum -= Math.abs(old); - } - } - }; - - /** - * Calculate function for variable moving average. - * - * The resulting values will be added to the dataSet using the field name provided by the `sd.outputMap` entry. - * - * **Notes:** - * - This function calculates a single value, so it expects `sd.outputMap` to contain a single mapping. - * - To leverage as part of a larger study calculation, use {@link CIQ.Studies.MA} instead. - * - If no `outputs` object is defined in the library entry, the study will default to a single output named `Result`, which will then be used in lieu of `sd.outputs` to build the field name. - * - The study name may contain the unprintable character `‌`, see {@link studyDescriptor} documentation. - * - * @param {CIQ.ChartEngine} stx Chart object - * @param {CIQ.Studies.StudyDescriptor} sd Study Descriptor - * @private - * @memberof CIQ.Studies - * @since 5.2.1 Moved `VIYDA` to `calculateMovingAverageVIDYA`. - */ - CIQ.Studies.calculateMovingAverageVariable = function (stx, sd) { - var type = sd.inputs.Type; - var quotes = sd.chart.scrubbed; - var alpha = 2 / (sd.days + 1); - - var vmaPreviousDay = null; - var name = sd.name; - for (var p in sd.outputs) { - name = p + " " + name; - } - - var field = sd.inputs.Field; - if (!field || field == "field") field = "Close"; // Handle when the default inputs are passed in - - sd.cmo = new CIQ.Studies.StudyDescriptor(sd.name, "cmo", sd.panel); - sd.cmo.chart = sd.chart; - sd.cmo.days = 9; - sd.cmo.inputs = { Field: field }; - sd.cmo.startFrom = sd.startFrom; - sd.cmo.outputs = { _CMO: null }; - CIQ.Studies.calculateChandeMomentum(stx, sd.cmo); - - var offset = parseInt(sd.inputs.Offset, 10); - if (isNaN(offset)) offset = 0; - - var i, val, ft; - var start = sd.startFrom; - // find vmaPreviousDay - var offsetBack = offset; - for (i = sd.startFrom - 1; i >= 0; i--) { - val = quotes[i][name]; - if (!val && val !== 0) continue; - if (vmaPreviousDay === null) vmaPreviousDay = val; - if (offsetBack <= 0) break; - offsetBack--; - start = i; - } - if (vmaPreviousDay === null) { - vmaPreviousDay = start = 0; - } - var futureTicks = []; - for (i = start; i < quotes.length; i++) { - var quote = quotes[i]; - val = quote[field]; - if (val && typeof val == "object") val = val[sd.subField]; - var notOverflowing = i + offset >= 0 && i + offset < quotes.length; - var offsetQuote = notOverflowing ? quotes[i + offset] : null; - if (!val && val !== 0) { - if (offsetQuote) offsetQuote[name] = null; - else if (i + offset >= quotes.length) { - ft = {}; - ft[name] = null; - futureTicks.push(ft); - } - continue; - } - if (!quote["_CMO " + sd.name] && quote["_CMO " + sd.name] !== 0) continue; - var vi = Math.abs(quote["_CMO " + sd.name]) / 100; - var vma = alpha * vi * val + (1 - alpha * vi) * vmaPreviousDay; - vmaPreviousDay = vma; - if (i < sd.days) vma = null; - if (offsetQuote) offsetQuote[name] = vma; - else if (i + offset >= quotes.length) { - ft = {}; - ft[name] = vma; - futureTicks.push(ft); - } - } - sd.appendFutureTicks(stx, futureTicks); - }; - - CIQ.Studies.studyLibrary = CIQ.extend(CIQ.Studies.studyLibrary, { - "Chande Fcst": { - name: "Chande Forecast Oscillator", - calculateFN: CIQ.Studies.calculateChandeForecast, - inputs: { Period: 14, Field: "field" } - }, - "Chande Mtm": { - name: "Chande Momentum Oscillator", - calculateFN: CIQ.Studies.calculateChandeMomentum, - inputs: { Period: 9 }, - parameters: { - init: { - studyOverZonesEnabled: true, - studyOverBoughtValue: 50, - studyOverBoughtColor: "auto", - studyOverSoldValue: -50, - studyOverSoldColor: "auto" - } - } - } - }); -} - -}; - - -let __js_advanced_studies_choppiness_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -if (!CIQ.Studies) { - console.error( - "choppiness feature requires first activating studies feature." - ); -} else { - CIQ.Studies.calculateChoppiness = function (stx, sd) { - CIQ.Studies.calculateStudyATR(stx, sd); - - var quotes = sd.chart.scrubbed; - if (quotes.length < sd.days + 1) { - sd.error = true; - return; - } - - function getLLVHHV(p, x) { - var h = Number.MAX_VALUE * -1, - l = Number.MAX_VALUE; - for (var j = x - p + 1; j <= x; j++) { - if (j < 0) continue; - h = Math.max(h, quotes[j].High); - l = Math.min(l, quotes[j].Low); - } - return [l, h]; - } - for (var i = Math.max(sd.startFrom, sd.days); i < quotes.length; i++) { - var quote = quotes[i]; - if (!quote) continue; - if (quote.futureTick) break; - var lh = getLLVHHV(sd.days, i); - if (quote["Sum True Range " + sd.name]) { - quote["Result " + sd.name] = - (100 * - Math.log( - quote["Sum True Range " + sd.name] / - Math.max(0.000001, lh[1] - lh[0]) - )) / - Math.log(sd.days); - } else if (!isNaN(quote)) { - quote["Result " + sd.name] = 0; - } - } - }; - - CIQ.Studies.studyLibrary = CIQ.extend(CIQ.Studies.studyLibrary, { - Choppiness: { - name: "Choppiness Index", - calculateFN: CIQ.Studies.calculateChoppiness, - centerline: 50, - parameters: { - init: { - studyOverZonesEnabled: true, - studyOverBoughtValue: 61.8, - studyOverBoughtColor: "auto", - studyOverSoldValue: 38.2, - studyOverSoldColor: "auto" - } - }, - attributes: { - studyOverBoughtValue: { min: 50, step: "0.1" }, - studyOverSoldValue: { max: 50, step: "0.1" } - } - } - }); -} - -}; - - -let __js_advanced_studies_comparisonStudies_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - - - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -if (!CIQ.Studies) { - console.error( - "comparisonStudies feature requires first activating studies feature." - ); -} else if (!CIQ.Studies.initPriceRelative) { - console.error( - "comparisonStudies feature requires first activating priceRelative feature." - ); -} else { - /** - * Calculate function for correlation coefficient - * @param {CIQ.ChartEngine} stx Chart object - * @param {object} sd Study Descriptor - * @memberOf CIQ.Studies - */ - CIQ.Studies.calculateCorrelationCoefficient = function (stx, sd) { - var quotes = sd.chart.scrubbed; - var period = sd.days; - if (quotes.length < period + 1) { - sd.error = true; - return; - } - //var base=stx.chart.symbol; - sd.compare = sd.inputs["Compare To"]; - if (!sd.compare) { - sd.compare = []; - sd.outputs = {}; - sd.outputMap = {}; - for (var s in stx.chart.series) { - var series = stx.chart.series[s]; - if (series.parameters.color) { - sd.compare.push(series.display); - sd.outputs["Result " + series.display] = series.parameters.color; - sd.outputMap["Result " + series.display + " " + sd.name] = - "Result " + series.display; - } - } - } else { - sd.compare = [sd.compare]; - } - if (!sd.compare.length) { - sd.error = - "Correlation Coefficient requires at least one comparison symbol"; - return; - } - for (var sym = 0; sym < sd.compare.length; sym++) { - var sB = 0; - var sC = 0; - var sB2 = 0; - var sC2 = 0; - var sBC = 0; - var thisCompare = sd.compare[sym]; - var iters = 0; - for (var i = sd.startFrom - period; i < quotes.length; i++) { - //last tick has no compare data - if (!quotes[i]) continue; - var comparisonQuote = quotes[i][thisCompare]; - if (comparisonQuote && typeof comparisonQuote == "object") - comparisonQuote = comparisonQuote.Close; - if (!comparisonQuote && comparisonQuote !== 0) { - if ( - i > 0 && - quotes[i - 1] && - quotes[i - 1]["_temps " + sd.name] && - quotes[i - 1]["_temps " + sd.name].c - ) - comparisonQuote = quotes[i - 1]["_temps " + sd.name].c; - else comparisonQuote = 0; - } - if (comparisonQuote && typeof comparisonQuote == "object") - comparisonQuote = comparisonQuote.Close; - quotes[i]["_temps " + sd.name] = {}; - sB += quotes[i]["_temps " + sd.name].b = quotes[i].Close; - sC += quotes[i]["_temps " + sd.name].c = comparisonQuote; - sB2 += quotes[i]["_temps " + sd.name].b2 = Math.pow(quotes[i].Close, 2); - sC2 += quotes[i]["_temps " + sd.name].c2 = Math.pow(comparisonQuote, 2); - sBC += quotes[i]["_temps " + sd.name].bc = - quotes[i].Close * comparisonQuote; - if (iters >= period) { - sB -= quotes[i - period]["_temps " + sd.name].b; - sC -= quotes[i - period]["_temps " + sd.name].c; - sB2 -= quotes[i - period]["_temps " + sd.name].b2; - sC2 -= quotes[i - period]["_temps " + sd.name].c2; - sBC -= quotes[i - period]["_temps " + sd.name].bc; - - var vb = sB2 / period - Math.pow(sB / period, 2); - var vc = sC2 / period - Math.pow(sC / period, 2); - var cv = sBC / period - (sB * sC) / Math.pow(period, 2); - var cc = cv / Math.sqrt(vb * vc); - quotes[i]["Result " + thisCompare + " " + sd.name] = cc; - } - iters++; - } - } - }; - - CIQ.Studies.calculatePerformance = function (stx, sd) { - var quotes = sd.chart.scrubbed; - var cSym = sd.inputs["Comparison Symbol"].toUpperCase(); - if (!cSym) cSym = sd.study.inputs["Comparison Symbol"]; - if (!sd.days) sd.days = sd.study.inputs.Period; - if (quotes.length < sd.days + 1) { - sd.error = true; - return; - } - - CIQ.Studies.MA("ma", sd.days, "Close", 0, "_MA Base", stx, sd); - CIQ.Studies.MA("ma", sd.days, cSym, 0, "_MA Comp", stx, sd); - for (var i = sd.startFrom; i < quotes.length; i++) { - var cSymQ = quotes[i][cSym]; - if (cSymQ && (cSymQ.Close || cSymQ.Close === 0)) cSymQ = cSymQ.Close; - quotes[i]["Result " + sd.name] = - (quotes[i].Close / cSymQ) * - (quotes[i]["_MA Comp " + sd.name] / quotes[i]["_MA Base " + sd.name]); - } - }; - - CIQ.Studies.calculateBeta = function (stx, sd) { - var quotes = sd.chart.scrubbed; - var cSym = sd.inputs["Comparison Symbol"].toUpperCase(); - if (!cSym) cSym = sd.study.inputs["Comparison Symbol"]; - if (!sd.days) sd.days = sd.study.inputs.Period; - if (quotes.length < sd.days + 1) { - sd.error = true; - return; - } - - for (var i = Math.max(sd.startFrom, 1); i < quotes.length; i++) { - quotes[i]["_BaseChange " + sd.name] = - quotes[i].Close / quotes[i - 1].Close - 1; - var cSymQ = quotes[i][cSym]; - if (cSymQ && (cSymQ.Close || cSymQ.Close === 0)) cSymQ = cSymQ.Close; - var cSymQ1 = quotes[i - 1][cSym]; - if (cSymQ1 && (cSymQ1.Close || cSymQ1.Close === 0)) cSymQ1 = cSymQ1.Close; - quotes[i]["_CompChange " + sd.name] = cSymQ / cSymQ1 - 1; - } - CIQ.Studies.MA( - "ma", - sd.days, - "_BaseChange " + sd.name, - 0, - "_MA Base", - stx, - sd - ); - CIQ.Studies.MA( - "ma", - sd.days, - "_CompChange " + sd.name, - 0, - "_MA Comp", - stx, - sd - ); - for (i = Math.max(sd.startFrom, sd.days); i < quotes.length; i++) { - quotes[i]["_COVARn " + sd.name] = - (quotes[i]["_BaseChange " + sd.name] - - quotes[i]["_MA Base " + sd.name]) * - (quotes[i]["_CompChange " + sd.name] - - quotes[i]["_MA Comp " + sd.name]); - quotes[i]["_VARn " + sd.name] = Math.pow( - quotes[i]["_CompChange " + sd.name] - quotes[i]["_MA Comp " + sd.name], - 2 - ); - } - CIQ.Studies.MA("ma", sd.days, "_COVARn " + sd.name, 0, "_COVAR", stx, sd); - CIQ.Studies.MA("ma", sd.days, "_VARn " + sd.name, 0, "_VAR", stx, sd); - for (i = Math.max(sd.startFrom, sd.days * 2 - 1); i < quotes.length; i++) { - quotes[i]["Result " + sd.name] = - quotes[i]["_COVAR " + sd.name] / quotes[i]["_VAR " + sd.name]; - } - }; - - CIQ.Studies.studyLibrary = CIQ.extend(CIQ.Studies.studyLibrary, { - correl: { - name: "Correlation Coefficient", - range: "-1 to 1", - calculateFN: CIQ.Studies.calculateCorrelationCoefficient, - outputs: {} - }, - "Perf Idx": { - name: "Performance Index", - centerline: 1, - initializeFN: CIQ.Studies.initPriceRelative, - seriesFN: CIQ.Studies.displayVsComparisonSymbol, - calculateFN: CIQ.Studies.calculatePerformance, - inputs: { Period: 120, "Comparison Symbol": "SPY" }, - outputs: { Result: "auto", Gain: "#00DD00", Loss: "#FF0000" }, - deferUpdate: true - }, - Beta: { - name: "Beta", - centerline: 1, - initializeFN: CIQ.Studies.initPriceRelative, - seriesFN: CIQ.Studies.displayVsComparisonSymbol, - calculateFN: CIQ.Studies.calculateBeta, - inputs: { Period: 20, "Comparison Symbol": "SPY" }, - deferUpdate: true - } - }); -} - -}; - - -let __js_advanced_studies_coppock_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -if (!CIQ.Studies) { - console.error("coppock feature requires first activating studies feature."); -} else { - CIQ.Studies.calculateCoppock = function (stx, sd) { - var quotes = sd.chart.scrubbed; - var field = sd.inputs.Field; - if (!field || field == "field") field = "Close"; - - var longDays = parseInt(sd.inputs["Long RoC"], 10); - if (!longDays) longDays = 14; - var shortDays = parseInt(sd.inputs["Short RoC"], 10); - if (!shortDays) shortDays = 11; - var period = sd.days; - if (!period) period = 10; - if (longDays < shortDays) return; - - if (quotes.length < Math.max(shortDays, longDays, period) + 1) { - sd.error = true; - return; - } - for (var i = Math.max(sd.startFrom, longDays); i < quotes.length; i++) { - var denom1 = quotes[i - shortDays][field]; - var denom2 = quotes[i - longDays][field]; - if (denom1 && denom2) { - // skip if denominator is 0 -- - quotes[i]["_Sum " + sd.name] = - 100 * (quotes[i][field] / denom1 + quotes[i][field] / denom2 - 2); - } - } - - CIQ.Studies.MA("weighted", period, "_Sum " + sd.name, 0, "Result", stx, sd); - }; - - CIQ.Studies.studyLibrary = CIQ.extend(CIQ.Studies.studyLibrary, { - Coppock: { - name: "Coppock Curve", - calculateFN: CIQ.Studies.calculateCoppock, - inputs: { Period: 10, Field: "field", "Short RoC": 11, "Long RoC": 14 } - } - }); -} - -}; - - -let __js_advanced_studies_darvasBox_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -if (!CIQ.Studies) { - console.error("darvasBox feature requires first activating studies feature."); -} else { - CIQ.Studies.calculateDarvas = function (stx, sd) { - var quotes = sd.chart.scrubbed; - var allTimeHigh = 0; - var allTimeHighPeriods = parseInt(sd.inputs["ATH Lookback Period"], 10); - if (sd.inputs["Volume Spike"]) { - CIQ.Studies.MA("simple", allTimeHighPeriods, "Volume", 0, "ADV", stx, sd); - } - var spikePercentage = parseFloat(sd.inputs["Volume % of Avg"]) / 100; - var boxState = "none"; - var boxData = {}; - var ghost = null; - var buy = null, - sell = null; - var offset = parseFloat(sd.inputs["Level Offset"]); - var debug = false; - if (debug) console.log("*****************"); - var i; - var lbl = {}; //labels - ["Darvas", "Ghost", "Profit", "Loss", "ATH", "ADV", "Spike"].forEach( - function (v) { - lbl[v] = v + " " + sd.name; - } - ); - for (i = sd.startFrom - 1; i > 0; i--) { - var q = quotes[i]; - if (q[lbl.Darvas] || q[lbl.Ghost]) { - for (var l in lbl) q[l] = null; - } else { - allTimeHigh = q[lbl.ATH] || 0; - buy = q[lbl.Profit]; - sell = q[lbl.Loss]; - break; - } - } - for (i; i < quotes.length; i++) { - var quote = quotes[i]; - if (!quote) continue; - - if (parseFloat(sd.inputs["Price Minimum"]) <= quotes[allTimeHigh].Close) { - if (ghost && (!ghost.End || i == ghost.End + 1)) { - if (quotes[i - 1].Close > boxData.High) { - boxData = { - State: 1, - High: 2 * boxData.High - boxData.Low, - Low: boxData.High, - Start: i, - End: 2 * boxData.End - boxData.Start + 1 - }; - } else { - ghost = null; - //boxData={State:1,High:boxData.High,Low:boxData.Low,Start:i,End:2*boxData.End-boxData.Start+1}; - } - if (ghost) { - quote[lbl.Ghost] = CIQ.clone(boxData); - if (debug) console.log("Ghost begin:" + quote.DT); - boxData.State = 0; - if (quotes[boxData.End]) { - quotes[boxData.End][lbl.Ghost] = CIQ.clone(boxData); - if (debug) console.log("Ghost end:" + quotes[boxData.End].DT); - } - ghost = { Start: boxData.Start, End: boxData.End }; - buy = boxData.High + offset; - if (!sell || sell < boxData.Low - offset) { - sell = boxData.Low - offset; - } - } - } - - quote[lbl.Profit] = buy; - quote[lbl.Loss] = sell; - if (quote.Close >= buy) buy = null; - else if (sd.inputs["Exit Field"] == "high/low" && quote.High >= buy) - buy = null; - - if (boxState == "none") { - if (i == allTimeHigh + 3) { - if ( - !quotes[allTimeHigh + 2][lbl.Darvas] && - !quotes[allTimeHigh + 1][lbl.Darvas] && - !quotes[allTimeHigh][lbl.Darvas] && - quotes[allTimeHigh].High > quote.High - ) { - boxState = "high"; - //if(sell) buy=Math.max(buy,quotes[allTimeHigh].High+offset); - } - } - } - - if (boxState == "high") { - if (quote.High > quotes[allTimeHigh].High) { - boxState = "none"; - } else if ( - quotes[i - 3].Low < quotes[i - 2].Low && - quotes[i - 3].Low < quotes[i - 1].Low && - quotes[i - 3].Low < quote.Low - ) { - boxData = { - State: 1, - High: quotes[allTimeHigh].High, - Low: quotes[i - 3].Low, - Start: allTimeHigh - }; - quotes[allTimeHigh][lbl.Darvas] = CIQ.clone(boxData); - boxState = "darvas"; - if (debug) console.log("Darvas begin:" + quotes[allTimeHigh].DT); - if (debug) console.log("Darvas established:" + quote.DT); - if (ghost) { - if (ghost.End > i && quotes[ghost.Start]) { - quote[lbl.Ghost] = CIQ.clone(quotes[ghost.Start][lbl.Ghost]); - quote[lbl.Ghost].End = i; - if (quotes[ghost.End]) { - delete quotes[ghost.End][lbl.Ghost]; - if (debug) - console.log("Ghost End removed:" + quotes[ghost.End].DT); - } - } - quote[lbl.Ghost].State = 0; - quotes[ghost.Start][lbl.Ghost].End = i; - if (debug) console.log("Ghost end:" + quote.DT); - ghost = null; - } - buy = boxData.High + offset; - if (!sell || sell < boxData.Low - offset) { - sell = boxData.Low - offset; - } - } - } - - if (boxState == "darvas") { - if (quote.Close > boxData.High) ghost = {}; - else if ( - sd.inputs["Exit Field"] == "high/low" && - quote.High > boxData.High - ) - ghost = {}; - else if (quote.Close < boxData.Low) boxState = "none"; - else if ( - sd.inputs["Exit Field"] == "high/low" && - quote.Low < boxData.Low - ) - boxState = "none"; - if (ghost) boxState = "none"; - else if (boxState == "none") { - buy = null; - sell = null; - } - if (!sd.inputs["Ghost Boxes"]) ghost = null; - if (boxState == "none") { - for (var d = boxData.Start + 1; d < i; d++) { - quotes[d][lbl.Darvas] = CIQ.clone(boxData); - } - boxData.State = 0; - boxData.End = i; - quote[lbl.Darvas] = CIQ.clone(boxData); - if (debug) console.log("Darvas end:" + quote.DT); - quote[lbl.ATH] = allTimeHigh; - continue; - } - } - - if (sell) { - if ( - quote.Close < boxData.Low || - (sd.inputs["Exit Field"] == "high/low" && quote.Low < boxData.Low) - ) { - if (boxState == "darvas") boxState = "none"; - if ( - quote.Close < sell || - (sd.inputs["Exit Field"] == "high/low" && quote.Low < sell) - ) { - buy = null; - sell = null; - } - if (ghost) { - if (ghost.End > i && quotes[ghost.Start]) { - quote[lbl.Ghost] = CIQ.clone(quotes[ghost.Start][lbl.Ghost]); - quote[lbl.Ghost].End = i; - if (quotes[ghost.End]) { - delete quotes[ghost.End][lbl.Ghost]; - if (debug) - console.log("Ghost End removed:" + quotes[ghost.End].DT); - } - } - quote[lbl.Ghost].State = 0; - quotes[ghost.Start][lbl.Ghost].End = i; - if (debug) console.log("Ghost end:" + quote.DT); - ghost = null; - } - } - } - } - - if (quote.High >= quotes[allTimeHigh].High) { - allTimeHigh = i; - if (debug) console.log("All Time High:" + quote.DT); - } - - if ( - i < 3 || - (quote.High >= quotes[i - 1].High && - quote.High >= quotes[i - 2].High && - quote.High >= quotes[i - 3].High) - ) { - if (i - allTimeHigh >= allTimeHighPeriods) { - allTimeHigh = i; - for (var j = 0; j < allTimeHighPeriods; j++) { - if (i - j < 0) break; - if (quotes[i - j].High > quotes[allTimeHigh].High) { - allTimeHigh = i - j; - } - } - if (debug) console.log("All Time High:" + quote.DT); - } - } - - if ( - sd.inputs["Volume Spike"] && - i > allTimeHighPeriods && - i == allTimeHigh - ) { - if (quote[lbl.ADV] * spikePercentage < quote.Volume) { - quote[lbl.Spike] = 1; - if (debug) console.log("Volume Spike:" + quote.DT); - } - } - quote[lbl.ATH] = allTimeHigh; - } - }; - - // NOTE: Darvas will only display on the chart panel sharing the yAxis. - CIQ.Studies.displayDarvas = function (stx, sd, quotes) { - var levelsColor = CIQ.Studies.determineColor(sd.outputs.Levels); - if (!levelsColor || levelsColor == "auto" || CIQ.isTransparent(levelsColor)) - levelsColor = stx.defaultColor; - var darvasColor = CIQ.Studies.determineColor(sd.outputs.Darvas); - if (!darvasColor || darvasColor == "auto" || CIQ.isTransparent(darvasColor)) - darvasColor = stx.defaultColor; - var ghostColor = CIQ.Studies.determineColor(sd.outputs.Ghost); - if (!ghostColor || ghostColor == "auto" || CIQ.isTransparent(ghostColor)) - ghostColor = stx.defaultColor; - - var panel = stx.panels[sd.panel], - context = sd.getContext(stx); - var i, q; - var slyh1, slyl1; - var myWidth = stx.layout.candleWidth - 2; - if (myWidth < 2) myWidth = 1; - stx.startClip(sd.panel); - if (sd.inputs["Stop Levels"]) { - if (context.setLineDash) { - context.setLineDash([2, 2]); - } - context.lineWidth = 2; - context.strokeStyle = levelsColor; - /* Don't display the take profit levels - context.beginPath(); - for(i=0;i= slyl1) context.lineTo(slxl0, slyl1); - else if (i === 0) context.moveTo(stx.chart.left, slyl1); - else context.moveTo(slxl0, slyl1); - context.lineTo(slxl1, slyl1); - } - } - context.stroke(); - if (context.setLineDash) { - context.setLineDash([]); - } - context.lineWidth = 1; - } - var dx = -10, - dy, - dw = 0, - dh, - gx = -10, - gy, - gw = 0, - gh; - var inDarvas = false, - inGhost = false; - var signalWidth = context.measureText("\u25B2").width / 2; - var lastBarWithClose = 0; - for (i = 0; i < quotes.length; i++) { - if (!quotes[i]) continue; - if (quotes[i].Close || quotes[i].Close === 0) lastBarWithClose = i; - if (quotes[i]["Spike " + sd.name]) { - context.fillStyle = darvasColor; - context.textBaseline = "bottom"; - var y = stx.pixelFromPrice(quotes[i].High, stx.chart.panel); - context.fillText("\u25BC", stx.pixelFromBar(i) - signalWidth, y - 5); // down arrow - } - - if (quotes[i].candleWidth) - myWidth = Math.floor(Math.max(1, quotes[i].candleWidth)); - if (quotes[i]["Darvas " + sd.name]) { - q = quotes[i]["Darvas " + sd.name]; - if (q.State == 1 && !inDarvas) { - dx = Math.floor(stx.pixelFromBar(i, panel.chart) - myWidth / 2); - dy = Math.floor(stx.pixelFromPrice(q.High, panel)); - dh = Math.floor(stx.pixelFromPrice(q.Low, panel)) - dy; - inDarvas = true; - } else if (q.State === 0) { - dw = Math.floor(stx.pixelFromBar(i, panel.chart) + myWidth / 2) - dx; - dy = Math.floor(stx.pixelFromPrice(q.High, panel)); - dh = Math.floor(stx.pixelFromPrice(q.Low, panel)) - dy; - context.strokeStyle = darvasColor; - context.fillStyle = darvasColor; - if (!sd.inputs["Stop Levels"]) { - context.strokeRect(dx, dy, dw, dh); - context.globalAlpha = 0.2; - } else { - context.globalAlpha = 0.3; - } - context.fillRect(dx, dy, dw, dh); - context.globalAlpha = 1; - inDarvas = false; - } - } - if (quotes[i]["Ghost " + sd.name] && sd.inputs["Ghost Boxes"]) { - q = quotes[i]["Ghost " + sd.name]; - if (q.State == 1 && !inGhost) { - gx = Math.floor(stx.pixelFromBar(i, panel.chart) - myWidth / 2); - gy = Math.floor(stx.pixelFromPrice(q.High, panel)); - gw = Math.floor( - (q.End - q.Start + 1) * stx.layout.candleWidth + myWidth / 2 - ); - gh = Math.floor(stx.pixelFromPrice(q.Low, panel)) - gy; - inGhost = true; - } else if (q.State === 0) { - if (q.Start == q.End) - gx = Math.floor(stx.pixelFromBar(i, panel.chart) - myWidth / 2); - gw = Math.floor(stx.pixelFromBar(i, panel.chart) + myWidth / 2) - gx; - gy = Math.floor(stx.pixelFromPrice(q.High, panel)); - gh = Math.floor(stx.pixelFromPrice(q.Low, panel)) - gy; - context.strokeStyle = ghostColor; - context.fillStyle = ghostColor; - if (!sd.inputs["Stop Levels"]) { - context.strokeRect(gx, gy, gw, gh); - context.globalAlpha = 0.2; - } else { - context.globalAlpha = 0.3; - } - context.fillRect(gx, gy, gw, gh); - context.globalAlpha = 1; - inGhost = false; - } - } - } - if (inDarvas) { - dw = - Math.floor( - stx.pixelFromBar(lastBarWithClose, panel.chart) + myWidth / 2 - ) - dx; - context.strokeStyle = darvasColor; - context.fillStyle = darvasColor; - if (!sd.inputs["Stop Levels"]) { - context.beginPath(); - context.moveTo(dx + 2 * dw, dy); - context.lineTo(dx, dy); - context.lineTo(dx, dy + dh); - context.lineTo(dx + 2 * dw, dy + dh); - context.stroke(); - context.globalAlpha = 0.2; - } else { - context.globalAlpha = 0.3; - } - context.fillRect(dx, dy, 2 * dw, dh); - context.globalAlpha = 1; - } - if (inGhost) { - context.strokeStyle = ghostColor; - context.fillStyle = ghostColor; - if (!sd.inputs["Stop Levels"]) { - context.strokeRect(gx, gy, gw, gh); - context.globalAlpha = 0.2; - } else { - context.globalAlpha = 0.3; - } - context.fillRect(gx, gy, gw, gh); - context.globalAlpha = 1; - } - if (inDarvas || inGhost) { - if (sd.inputs["Stop Levels"]) { - if (context.setLineDash) { - context.setLineDash([2, 2]); - } - context.lineWidth = 2; - context.strokeStyle = levelsColor; - var x = Math.floor( - stx.pixelFromBar(lastBarWithClose - 1, panel.chart) + myWidth / 2 - ); - if (slyh1) { - context.beginPath(); - context.moveTo(x, slyh1); - context.lineTo(inDarvas ? dx + 2 * dw : gx + gw, slyh1); - context.stroke(); - } - if (slyl1) { - context.beginPath(); - context.moveTo(x, slyl1); - context.lineTo(inDarvas ? dx + 2 * dw : gx + gw, slyl1); - context.stroke(); - } - if (context.setLineDash) { - context.setLineDash([]); - } - context.lineWidth = 1; - } - inDarvas = false; - inGhost = false; - } - stx.endClip(); - }; - - CIQ.Studies.studyLibrary = CIQ.extend(CIQ.Studies.studyLibrary, { - Darvas: { - name: "Darvas Box", - underlay: true, - calculateFN: CIQ.Studies.calculateDarvas, - seriesFN: CIQ.Studies.displayDarvas, - inputs: { - "ATH Lookback Period": 100, - "Exit Field": ["close", "high/low"], - "Ghost Boxes": true, - "Stop Levels": false, - "Level Offset": 0.01, - "Price Minimum": 5, - "Volume Spike": false, - "Volume % of Avg": 400 - }, - outputs: { Darvas: "#5F7CB8", Ghost: "#699158", Levels: "auto" }, - customRemoval: true, - attributes: { - "Price Minimum": { min: 0.01, step: 0.01 }, - yaxisDisplayValue: { hidden: true }, - panelName: { hidden: true }, - flippedEnabled: { hidden: true } - } - } - }); -} - -}; - - -let __js_advanced_studies_detrended_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -if (!CIQ.Studies) { - console.error("detrended feature requires first activating studies feature."); -} else { - CIQ.Studies.calculateDetrendedPrice = function (stx, sd) { - var quotes = sd.chart.scrubbed; - if (quotes.length < sd.days + 1) { - sd.error = true; - return; - } - var field = sd.inputs.Field; - if (!field || field == "field") field = "Close"; - var offset = Math.floor(sd.days / 2 + 1); - CIQ.Studies.MA( - sd.inputs["Moving Average Type"], - sd.days, - field, - -offset, - "MA", - stx, - sd - ); - - for ( - var i = Math.max(sd.days - offset - 1, sd.startFrom - offset); - i < quotes.length - offset; - i++ - ) { - if (i < 0) continue; - var val = quotes[i][field]; - if (val && typeof val == "object") val = val[sd.subField]; - var maVal = quotes[i]["MA " + sd.name]; - if ((val || val === 0) && (maVal || maVal === 0)) - quotes[i]["Result " + sd.name] = val - maVal; - } - }; - - CIQ.Studies.studyLibrary = CIQ.extend(CIQ.Studies.studyLibrary, { - Detrended: { - name: "Detrended Price Oscillator", - calculateFN: CIQ.Studies.calculateDetrendedPrice, - inputs: { Period: 14, Field: "field", "Moving Average Type": "ma" } - } - }); -} - -}; - - -let __js_advanced_studies_disparity_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -if (!CIQ.Studies) { - console.error("disparity feature requires first activating studies feature."); -} else { - CIQ.Studies.calculateDisparity = function (stx, sd) { - var quotes = sd.chart.scrubbed; - if (quotes.length < sd.days + 1) { - sd.error = true; - return; - } - var field = sd.inputs.Field; - if (!field || field == "field") field = "Close"; - - CIQ.Studies.MA( - sd.inputs["Moving Average Type"], - sd.days, - field, - 0, - "_MA", - stx, - sd - ); - for (var i = Math.max(sd.startFrom, sd.days - 1); i < quotes.length; i++) { - if (!quotes[i]) continue; - var qMA = quotes[i]["_MA " + sd.name]; - if (qMA) - quotes[i]["Result " + sd.name] = 100 * (quotes[i][field] / qMA - 1); - } - }; - - CIQ.Studies.studyLibrary = CIQ.extend(CIQ.Studies.studyLibrary, { - Disparity: { - name: "Disparity Index", - calculateFN: CIQ.Studies.calculateDisparity, - inputs: { Period: 14, Field: "field", "Moving Average Type": "ma" } - } - }); -} - -}; - - -let __js_advanced_studies_easeOfMovement_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -if (!CIQ.Studies) { - console.error( - "easeOfMovement feature requires first activating studies feature." - ); -} else { - CIQ.Studies.calculateEaseOfMovement = function (stx, sd) { - var quotes = sd.chart.scrubbed; - if (quotes.length < sd.days) { - sd.error = true; - return; - } - for (var i = Math.max(1, sd.startFrom); i < quotes.length; i++) { - var avgCurrent = (quotes[i].High + quotes[i].Low) / 2; - var avgPrior = (quotes[i - 1].High + quotes[i - 1].Low) / 2; - var dm = avgCurrent - avgPrior; - var br = quotes[i].Volume / 100000000 / (quotes[i].High - quotes[i].Low); - var result = dm / br; - if (!isFinite(result)) quotes[i]["_EOM1 " + sd.name] = NaN; - //With NaN, the study plotter will plot from the previous point - //directly to the next point after the current tick. Infinity was making the - //study not plot in the panel at all while the data point was in dataSegement. - else quotes[i]["_EOM1 " + sd.name] = result; - } - CIQ.Studies.MA( - sd.inputs["Moving Average Type"], - sd.days, - "_EOM1 " + sd.name, - 0, - "Result", - stx, - sd - ); - }; - - CIQ.Studies.studyLibrary = CIQ.extend(CIQ.Studies.studyLibrary, { - EOM: { - name: "Ease of Movement", - calculateFN: CIQ.Studies.calculateEaseOfMovement, - inputs: { Period: 14, "Moving Average Type": "ma" } - } - }); -} - -}; - - -let __js_advanced_studies_ehlerFisher_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -if (!CIQ.Studies) { - console.error( - "ehlerFisher feature requires first activating studies feature." - ); -} else { - CIQ.Studies.calculateEhlerFisher = function (stx, sd) { - var quotes = sd.chart.scrubbed; - if (quotes.length < sd.days + 1) { - sd.error = true; - return; - } - - function getLLVHHV(p, x) { - var l = Number.MAX_VALUE, - h = Number.MAX_VALUE * -1; - for (var j = x - p + 1; j <= x; j++) { - var d = (quotes[j].High + quotes[j].Low) / 2; - l = Math.min(l, d); - h = Math.max(h, d); - } - return [l, h]; - } - - var n = 0; - if (sd.startFrom > 1) n = quotes[sd.startFrom - 1]["_n " + sd.name]; - for (var i = sd.startFrom; i < quotes.length; i++) { - var quote = quotes[i]; - if (quote.futureTick) break; - if (i < sd.days - 1) { - quote["EF " + sd.name] = quote["EF Trigger " + sd.name] = n; - continue; - } - var lh = getLLVHHV(sd.days, i); - n = - 0.33 * - 2 * - (((quotes[i].High + quotes[i].Low) / 2 - lh[0]) / - Math.max(0.000001, lh[1] - lh[0]) - - 0.5) + - 0.67 * n; - if (n > 0) n = Math.min(n, 0.9999); - else if (n < 0) n = Math.max(n, -0.9999); - var previous = i ? quotes[i - 1]["EF " + sd.name] : 0; - quote["EF " + sd.name] = - 0.5 * Math.log((1 + n) / (1 - n)) + 0.5 * previous; - quote["EF Trigger " + sd.name] = previous; - quote["_n " + sd.name] = n; - } - }; - - CIQ.Studies.studyLibrary = CIQ.extend(CIQ.Studies.studyLibrary, { - "Ehler Fisher": { - name: "Ehler Fisher Transform", - calculateFN: CIQ.Studies.calculateEhlerFisher, - inputs: { Period: 10 }, - outputs: { EF: "auto", "EF Trigger": "#FF0000" } - } - }); -} - -}; - - -let __js_advanced_studies_elder_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -if (!CIQ.Studies) { - console.error("elder feature requires first activating studies feature."); -} else { - CIQ.Studies.calculateElderImpulse = function (stx, sd) { - var quotes = sd.chart.scrubbed; - var bull = sd.outputs.Bullish; - var bear = sd.outputs.Bearish; - var neutral = sd.outputs.Neutral; - - CIQ.Studies.MA("exponential", 13, "Close", 0, "_MA", stx, sd); - sd.macd = new CIQ.Studies.StudyDescriptor("_" + sd.name, "macd", sd.panel); - sd.macd.chart = sd.chart; - sd.macd.days = sd.days; - sd.macd.startFrom = sd.startFrom; - sd.macd.inputs = { - "Fast MA Period": 12, - "Slow MA Period": 26, - "Signal Period": 9 - }; - sd.macd.outputs = { _MACD: null, _Signal: null }; - CIQ.Studies.calculateMACD(stx, sd.macd); - - var color; - for (var i = sd.startFrom; i < quotes.length; i++) { - if (i === 0) color = neutral; - else if ( - quotes[i]["_MA " + sd.name] > quotes[i - 1]["_MA " + sd.name] && - quotes[i]["_" + sd.name + "_hist"] > - quotes[i - 1]["_" + sd.name + "_hist"] - ) - color = bull; - else if ( - quotes[i]["_MA " + sd.name] < quotes[i - 1]["_MA " + sd.name] && - quotes[i]["_" + sd.name + "_hist"] < - quotes[i - 1]["_" + sd.name + "_hist"] - ) - color = bear; - else color = neutral; - quotes[i]["Result " + sd.name] = color; - //if(i) quotes[i-1][sd.name+"_hist"]=null; - } - }; - - CIQ.Studies.calculateElderRay = function (stx, sd) { - var quotes = sd.chart.scrubbed; - if (quotes.length < sd.days) { - sd.error = true; - return; - } - CIQ.Studies.MA("exponential", sd.days, "Close", 0, "_EMA", stx, sd); - - for (var i = Math.max(sd.startFrom, sd.days - 1); i < quotes.length; i++) { - quotes[i][sd.name + "_hist1"] = - quotes[i].High - quotes[i]["_EMA " + sd.name]; - quotes[i][sd.name + "_hist2"] = - quotes[i].Low - quotes[i]["_EMA " + sd.name]; - } - sd.outputMap = {}; - sd.outputMap[sd.name + "_hist1"] = ""; - sd.outputMap[sd.name + "_hist2"] = ""; - }; - - CIQ.Studies.calculateElderForce = function (stx, sd) { - var quotes = sd.chart.scrubbed; - if (quotes.length < sd.days) { - sd.error = true; - return; - } - for (var i = Math.max(1, sd.startFrom); i < quotes.length; i++) { - quotes[i]["_EF1 " + sd.name] = - quotes[i].Volume * (quotes[i].Close - quotes[i - 1].Close); - } - CIQ.Studies.MA( - "exponential", - sd.days, - "_EF1 " + sd.name, - 0, - "Result", - stx, - sd - ); - }; - - CIQ.Studies.initElderImpulse = function ( - stx, - type, - inputs, - outputs, - parameters, - panel - ) { - var sd = CIQ.Studies.initializeFN( - stx, - type, - inputs, - outputs, - parameters, - panel - ); - if (parameters.calculateOnly) return sd; - stx.chart.customChart = { - chartType: "colored_bar", - colorFunction: function (stx, quote, mode) { - var color = quote["Result " + sd.name]; - if (color && typeof color == "object") color = color.color; - return color; - } - }; - stx.setMainSeriesRenderer(); - return sd; - }; - - CIQ.Studies.displayElderForce = function (stx, sd, quotes) { - CIQ.Studies.displaySeriesAsLine(stx, sd, quotes); - var color = CIQ.Studies.determineColor(sd.outputs.Result); - var panel = stx.panels[sd.panel]; - var yAxis = sd.getYAxis(stx); - var params = { - skipTransform: panel.name != sd.chart.name, - panelName: sd.panel, - band: "Result " + sd.name, - threshold: 0, - color: color, - yAxis: yAxis - }; - if (!sd.highlight && stx.highlightedDraggable) params.opacity = 0.3; - params.direction = 1; - CIQ.preparePeakValleyFill(stx, params); - params.direction = -1; - CIQ.preparePeakValleyFill(stx, params); - }; - - CIQ.Studies.displayElderRay = function (stx, sd, quotes) { - var panel = stx.panels[sd.panel], - context = sd.getContext(stx); - var yAxis = sd.getYAxis(stx); - var y = stx.pixelFromPrice(0, panel, yAxis); - - var myWidth = stx.layout.candleWidth - 2; - if (myWidth < 2) myWidth = 1; - function drawBar(i, reduction, output, hist) { - context.fillStyle = CIQ.Studies.determineColor(sd.outputs[output]); - context.fillRect( - Math.floor( - stx.pixelFromBar(i, panel.chart) - myWidth / 2 + myWidth * reduction - ), - Math.floor(y), - Math.floor(myWidth * (1 - 2 * reduction)), - Math.floor(stx.pixelFromPrice(quote[sd.name + hist], panel, yAxis) - y) - ); - } - - stx.canvasColor("stx_histogram"); - var fillStyle = context.fillStyle; - if (!sd.underlay) context.globalAlpha = 1; - stx.startClip(sd.panel); - if (!sd.highlight && stx.highlightedDraggable) context.globalAlpha *= 0.3; - for (var i = 0; i < quotes.length; i++) { - var quote = quotes[i]; - if (!quote) continue; - if (quote.candleWidth) - myWidth = Math.floor(Math.max(1, quote.candleWidth - 2)); - if (quote[sd.name + "_hist1"] > 0) - drawBar(i, 0, "Elder Bull Power", "_hist1"); - if (quote[sd.name + "_hist2"] < 0) - drawBar(i, 0, "Elder Bear Power", "_hist2"); - if (quote[sd.name + "_hist1"] < 0) - drawBar(i, 0.1, "Elder Bull Power", "_hist1"); - if (quote[sd.name + "_hist2"] > 0) - drawBar(i, 0.1, "Elder Bear Power", "_hist2"); - } - stx.endClip(); - context.fillStyle = fillStyle; - }; - - CIQ.Studies.studyLibrary = CIQ.extend(CIQ.Studies.studyLibrary, { - "Elder Force": { - name: "Elder Force Index", - calculateFN: CIQ.Studies.calculateElderForce, - seriesFN: CIQ.Studies.displayElderForce, - inputs: { Period: 13 } - }, - "Elder Ray": { - name: "Elder Ray Index", - seriesFN: CIQ.Studies.displayElderRay, - calculateFN: CIQ.Studies.calculateElderRay, - centerline: 0, - inputs: { Period: 13 }, - outputs: { "Elder Bull Power": "#00DD00", "Elder Bear Power": "#FF0000" } - }, - "Elder Impulse": { - name: "Elder Impulse System", - calculateFN: CIQ.Studies.calculateElderImpulse, - initializeFN: CIQ.Studies.initElderImpulse, - seriesFN: null, - customRemoval: true, - underlay: true, - inputs: {}, - outputs: { Bullish: "#8BC176", Bearish: "#DD3E39", Neutral: "#5F7CB8" }, - removeFN: function (stx, sd) { - stx.chart.customChart = null; - stx.setMainSeriesRenderer(); - } - } - }); -} - -}; - - -let __js_advanced_studies_fractalChaos_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -if (!CIQ.Studies) { - console.error( - "fractalChaos feature requires first activating studies feature." - ); -} else { - CIQ.Studies.calculateFractalChaos = function (stx, sd) { - var quotes = sd.chart.scrubbed; - - var fractalHigh = 0; - var fractalLow = 0; - var test = 0; - if (sd.startFrom && sd.type == "Fractal Chaos Bands") { - fractalHigh = quotes[sd.startFrom - 1]["Fractal High " + sd.name]; - fractalLow = quotes[sd.startFrom - 1]["Fractal Low " + sd.name]; - } - for (var i = Math.max(4, sd.startFrom); i < quotes.length; i++) { - if (quotes[i].futureTick) break; - var nHi = !isNaN(quotes[i].High), - nLo = !isNaN(quotes[i].Low); - if (nHi || nLo) quotes[i]["Result " + sd.name] = 0; - var j; - test = 0; - for (j = 0; j <= i; j++) { - if (!quotes[i - j]) break; - if (quotes[i - j].High > quotes[i - 2].High) break; - if (j < 2 && quotes[i - j].High == quotes[i - 2].High) break; - if (quotes[i - j].High < quotes[i - 2].High) test++; - if (test == 4) { - fractalHigh = quotes[i - 2].High; - break; - } - } - if (sd.type == "Fractal Chaos Bands") { - if (nHi) - quotes[i]["Fractal High " + sd.name] = - fractalHigh > 0 ? fractalHigh : null; - } else if (test == 4) { - //oscillator - quotes[i]["Result " + sd.name] = 1; - } - test = 0; - for (j = 0; j <= i; j++) { - if (!quotes[i - j]) break; - if (quotes[i - j].Low < quotes[i - 2].Low) break; - if (j < 2 && quotes[i - j].Low == quotes[i - 2].Low) break; - if (quotes[i - j].Low > quotes[i - 2].Low) test++; - if (test == 4) { - fractalLow = quotes[i - 2].Low; - break; - } - } - if (sd.type == "Fractal Chaos Bands") { - if (nLo) - quotes[i]["Fractal Low " + sd.name] = - fractalLow > 0 ? fractalLow : null; - } else if (test == 4) { - //oscillator - quotes[i]["Result " + sd.name] = -1; - } - } - }; - - CIQ.Studies.studyLibrary = CIQ.extend(CIQ.Studies.studyLibrary, { - "Fractal Chaos": { - name: "Fractal Chaos Oscillator", - range: "-1 to 1", - calculateFN: CIQ.Studies.calculateFractalChaos, - inputs: {}, - centerline: null // so centerline is drawn but not included in the range calculation - }, - "Fractal Chaos Bands": { - name: "Fractal Chaos Bands", - overlay: true, - calculateFN: CIQ.Studies.calculateFractalChaos, - seriesFN: CIQ.Studies.displayChannel, - inputs: { "Channel Fill": true }, - outputs: { - "Fractal High": "auto", - "Fractal Low": "auto", - "Fractal Channel": "auto" - } - } - }); -} - -}; - - -let __js_advanced_studies_highLowStudies_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -if (!CIQ.Studies) { - console.error( - "highLowStudies feature requires first activating studies feature." - ); -} else { - CIQ.Studies.calculateMaxHighMinLow = function (stx, sd) { - var quotes = sd.chart.scrubbed; - var highPeriod = sd.days, - lowPeriod = sd.days; - if (sd.inputs["High Period"]) highPeriod = sd.inputs["High Period"]; - if (sd.inputs["Low Period"]) lowPeriod = sd.inputs["Low Period"]; - if (quotes.length < Math.max(highPeriod, lowPeriod) + 1) { - sd.error = true; - return; - } - - var low = Number.MAX_VALUE, - high = Number.MAX_VALUE * -1; - var j; - if (sd.startFrom > 1) { - for (j = 1; j < highPeriod; j++) { - if (sd.startFrom - j >= 0) - high = Math.max(high, quotes[sd.startFrom - j].High); - } - for (j = 1; j < lowPeriod; j++) { - if (sd.startFrom - j >= 0) - low = Math.min(low, quotes[sd.startFrom - j].Low); - } - } - for (var i = Math.max(0, sd.startFrom - 1); i < quotes.length; i++) { - high = Math.max(high, quotes[i].High); - low = Math.min(low, quotes[i].Low); - if (i >= highPeriod) { - if (quotes[i - highPeriod].High == high) { - high = quotes[i].High; - for (j = 1; j < highPeriod; j++) { - high = Math.max(high, quotes[i - j].High); - } - } - } - if (i >= lowPeriod) { - if (quotes[i - lowPeriod].Low == low) { - low = quotes[i].Low; - for (j = 1; j < lowPeriod; j++) { - low = Math.min(low, quotes[i - j].Low); - } - } - } - var result = 0; - if (sd.type == "HHV") { - result = high; - } else if (sd.type == "LLV") { - result = low; - } else if (sd.type == "Donchian Width") { - result = high - low; - } else if (sd.type == "GAPO" || sd.type == "Gopala") { - result = Math.log(high - low) / Math.log(lowPeriod); - } else if (sd.type == "VT HZ Filter") { - result = high - low; - quotes[i]["_MHML " + sd.name] = result; - continue; - } else if (sd.type == "Williams %R") { - result = (-100 * (high - quotes[i].Close)) / (high - low); - quotes[i]["Result " + sd.name] = result; - continue; - } - if (i == quotes.length - 1) break; - - if (!quotes[i + 1].futureTick) { - if (sd.type == "Donchian Channel") { - quotes[i + 1]["Donchian High " + sd.name] = high; - quotes[i + 1]["Donchian Low " + sd.name] = low; - quotes[i + 1]["Donchian Median " + sd.name] = (high + low) / 2; - } else { - //width - quotes[i + 1]["Result " + sd.name] = result; - } - } - } - }; - - CIQ.Studies.calculateVerticalHorizontalFilter = function (stx, sd) { - var quotes = sd.chart.scrubbed; - if (quotes.length < sd.days + 1) { - sd.error = true; - return; - } - sd.mhml = new CIQ.Studies.StudyDescriptor(sd.name, sd.type, sd.panel); - sd.mhml.chart = sd.chart; - sd.mhml.days = sd.days; - sd.mhml.startFrom = sd.startFrom; - sd.mhml.inputs = {}; - sd.mhml.outputs = { _MHML: null }; - CIQ.Studies.calculateMaxHighMinLow(stx, sd.mhml); - var sumChanges = 0; - var changes = []; - for (var i = Math.max(1, sd.startFrom - sd.days); i < quotes.length; i++) { - var change = Math.abs(quotes[i].Close - quotes[i - 1].Close); - changes.push(change); - sumChanges += change; - if (changes.length == sd.days) { - quotes[i]["Result " + sd.name] = - quotes[i]["_MHML " + sd.name] / sumChanges; - sumChanges -= changes.shift(); - } - } - }; - - CIQ.Studies.studyLibrary = CIQ.extend(CIQ.Studies.studyLibrary, { - "Donchian Channel": { - name: "Donchian Channel", - overlay: true, - calculateFN: CIQ.Studies.calculateMaxHighMinLow, - seriesFN: CIQ.Studies.displayChannel, - inputs: { "High Period": 20, "Low Period": 20, "Channel Fill": true }, - outputs: { - "Donchian High": "auto", - "Donchian Median": "auto", - "Donchian Low": "auto" - } - }, - "Donchian Width": { - name: "Donchian Width", - calculateFN: CIQ.Studies.calculateMaxHighMinLow, - inputs: { "High Period": 20, "Low Period": 20 } - }, - GAPO: { - name: "Gopalakrishnan Range Index", - calculateFN: CIQ.Studies.calculateMaxHighMinLow - }, - HHV: { - name: "Highest High Value", - calculateFN: CIQ.Studies.calculateMaxHighMinLow, - inputs: { Period: 14 } - }, - LLV: { - name: "Lowest Low Value", - calculateFN: CIQ.Studies.calculateMaxHighMinLow, - inputs: { Period: 14 } - }, - "Williams %R": { - name: "Williams %R", - calculateFN: CIQ.Studies.calculateMaxHighMinLow, - inputs: { Period: 14 }, - parameters: { - init: { - studyOverZonesEnabled: true, - studyOverBoughtValue: -20, - studyOverBoughtColor: "auto", - studyOverSoldValue: -80, - studyOverSoldColor: "auto" - } - } - }, - "VT HZ Filter": { - name: "Vertical Horizontal Filter", - calculateFN: CIQ.Studies.calculateVerticalHorizontalFilter, - inputs: { Period: 28 } - }, - "High-Low": { - name: "High Minus Low", - calculateFN: function (stx, sd) { - var quotes = sd.chart.scrubbed; - for (var i = sd.startFrom; i < quotes.length; i++) { - quotes[i]["Result " + sd.name] = quotes[i].High - quotes[i].Low; - } - }, - inputs: {} - } - }); -} - -}; - - -let __js_advanced_studies_ichimoku_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -if (!CIQ.Studies) { - console.error("ichimoku feature requires first activating studies feature."); -} else { - CIQ.Studies.calculateIchimoku = function (stx, sd) { - var quotes = sd.chart.scrubbed; - var periods = { - Base: Number(sd.inputs["Base Line Period"]), - Conv: Number(sd.inputs["Conversion Line Period"]), - LeadB: Number(sd.inputs["Leading Span B Period"]), - Lag: Number(sd.inputs["Lagging Span Period"]) - }; - - function getLLVHHV(p, x) { - var l = Number.MAX_VALUE, - h = Number.MAX_VALUE * -1; - for (var j = x - p + 1; j <= x; j++) { - if (j < 0) continue; - l = Math.min(l, quotes[j].Low); - h = Math.max(h, quotes[j].High); - } - return [l, h]; - } - - var i, hl; - for (i = sd.startFrom; i < quotes.length; i++) { - if (!quotes[i]) continue; - - hl = getLLVHHV(periods.Conv, i); - quotes[i]["Conversion Line " + sd.name] = (hl[1] + hl[0]) / 2; - - hl = getLLVHHV(periods.Base, i); - quotes[i]["Base Line " + sd.name] = (hl[1] + hl[0]) / 2; - - if (i < periods.Lag) continue; - quotes[i - periods.Lag]["Lagging Span " + sd.name] = quotes[i].Close; - } - var futureTicks = []; - for (i = Math.max(0, sd.startFrom - periods.Base); i < quotes.length; i++) { - hl = getLLVHHV(periods.LeadB, i); - var lsa = - (quotes[i]["Conversion Line " + sd.name] + - quotes[i]["Base Line " + sd.name]) / - 2; - var lsb = (hl[1] + hl[0]) / 2; - if (quotes[i + periods.Base]) { - quotes[i + periods.Base]["Leading Span A " + sd.name] = lsa; - quotes[i + periods.Base]["Leading Span B " + sd.name] = lsb; - } else { - var ft = {}; - ft["Leading Span A " + sd.name] = lsa; - ft["Leading Span B " + sd.name] = lsb; - futureTicks.push(ft); - } - } - sd.appendFutureTicks(stx, futureTicks); - }; - - CIQ.Studies.displayIchimoku = function (stx, sd, quotes) { - var topBand = "Leading Span A " + sd.name, - bottomBand = "Leading Span B " + sd.name; - var topColor = CIQ.Studies.determineColor( - sd.outputs[sd.outputMap[topBand]] - ); - var bottomColor = CIQ.Studies.determineColor( - sd.outputs[sd.outputMap[bottomBand]] - ); - var panel = stx.panels[sd.panel]; - var yAxis = sd.getYAxis(stx); - var parameters = { - topBand: topBand, - bottomBand: bottomBand, - topColor: topColor, - bottomColor: bottomColor, - skipTransform: panel.name != sd.chart.name, - topAxis: yAxis, - bottomAxis: yAxis, - opacity: 0.3 - }; - if (!sd.highlight && stx.highlightedDraggable) parameters.opacity *= 0.3; - CIQ.fillIntersecting(stx, sd.panel, parameters); - CIQ.Studies.displaySeriesAsLine(stx, sd, quotes); - }; - - CIQ.Studies.studyLibrary = CIQ.extend(CIQ.Studies.studyLibrary, { - "Ichimoku Clouds": { - name: "Ichimoku Clouds", - overlay: true, - calculateFN: CIQ.Studies.calculateIchimoku, - seriesFN: CIQ.Studies.displayIchimoku, - inputs: { - "Conversion Line Period": 9, - "Base Line Period": 26, - "Leading Span B Period": 52, - "Lagging Span Period": 26 - }, - outputs: { - "Conversion Line": "#0000FF", - "Base Line": "#FF0000", - "Leading Span A": "#00FF00", - "Leading Span B": "#FF0000", - "Lagging Span": "#808000" - } - } - }); -} - -}; - - -let __js_advanced_studies_intradayMomentum_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -if (!CIQ.Studies) { - console.error( - "intradayMomentum feature requires first activating studies feature." - ); -} else { - CIQ.Studies.calculateIntradayMomentum = function (stx, sd) { - var quotes = sd.chart.scrubbed; - var period = sd.days; - if (quotes.length < period + 1) { - sd.error = true; - return; - } - - var totalUp = 0; - var totalDown = 0; - if (sd.startFrom > 1) { - totalUp = quotes[sd.startFrom - 1]["_totUp " + sd.name]; - totalDown = quotes[sd.startFrom - 1]["_totDn " + sd.name]; - } - for (var i = sd.startFrom; i < quotes.length; i++) { - var diff = quotes[i].Close - quotes[i].Open; - if (diff > 0) totalUp += diff; - else totalDown -= diff; - if (i >= period) { - var pDiff = quotes[i - period].Close - quotes[i - period].Open; - if (pDiff > 0) totalUp -= pDiff; - else totalDown += pDiff; - } - quotes[i]["Result " + sd.name] = (100 * totalUp) / (totalUp + totalDown); - quotes[i]["_totUp " + sd.name] = totalUp; - quotes[i]["_totDn " + sd.name] = totalDown; - } - }; - - CIQ.Studies.studyLibrary = CIQ.extend(CIQ.Studies.studyLibrary, { - "Intraday Mtm": { - name: "Intraday Momentum Index", - calculateFN: CIQ.Studies.calculateIntradayMomentum, - inputs: { Period: 20 }, - parameters: { - init: { - studyOverZonesEnabled: true, - studyOverBoughtValue: 70, - studyOverBoughtColor: "auto", - studyOverSoldValue: 30, - studyOverSoldColor: "auto" - } - } - } - }); -} - -}; - - -let __js_advanced_studies_keltner_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -if (!CIQ.Studies) { - console.error("keltner feature requires first activating studies feature."); -} else { - CIQ.Studies.calculateKeltner = function (stx, sd) { - CIQ.Studies.MA( - sd.inputs["Moving Average Type"], - sd.days, - "Close", - 0, - "MA", - stx, - sd - ); - CIQ.Studies.calculateStudyATR(stx, sd); - CIQ.Studies.calculateGenericEnvelope( - stx, - sd, - sd.inputs.Shift, - "MA " + sd.name, - "ATR " + sd.name - ); - }; - - CIQ.Studies.studyLibrary = CIQ.extend(CIQ.Studies.studyLibrary, { - Keltner: { - name: "Keltner Channel", - overlay: true, - seriesFN: CIQ.Studies.displayChannel, - calculateFN: CIQ.Studies.calculateKeltner, - inputs: { - Period: 50, - Shift: 5, - "Moving Average Type": "ema", - "Channel Fill": true - }, - outputs: { - "Keltner Top": "auto", - "Keltner Median": "auto", - "Keltner Bottom": "auto" - }, - attributes: { - Shift: { min: 0.1, step: 0.1 } - } - } - }); -} - -}; - - -let __js_advanced_studies_klinger_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -if (!CIQ.Studies) { - console.error("klinger feature requires first activating studies feature."); -} else { - /** - * Calculate function for klinger - * @param {CIQ.ChartEngine} stx Chart object - * @param {CIQ.Studies.StudyDescriptor} sd Study Descriptor - * @memberOf CIQ.Studies - */ - CIQ.Studies.calculateKlinger = function (stx, sd) { - var quotes = sd.chart.scrubbed; - var shortCycle = Number(sd.inputs["Short Cycle"]); - var longCycle = Number(sd.inputs["Long Cycle"]); - if (quotes.length < Math.max(shortCycle, longCycle) + 1) { - sd.error = true; - return; - } - - var field = sd.name + "_hist", - klinger = "Klinger " + sd.name, - klingerSignal = "KlingerSignal " + sd.name, - signedVolume = "_SV " + sd.name, - shortEMA = "_EMA-S " + sd.name, - longEMA = "_EMA-L " + sd.name, - i; - for (i = Math.max(1, sd.startFrom); i < quotes.length; i++) { - var sv = quotes[i].Volume; - if (quotes[i]["hlc/3"] < quotes[i - 1]["hlc/3"]) sv *= -1; - if (sv) quotes[i][signedVolume] = sv; - } - - CIQ.Studies.MA( - "exponential", - shortCycle, - signedVolume, - 0, - "_EMA-S", - stx, - sd - ); - CIQ.Studies.MA( - "exponential", - longCycle, - signedVolume, - 0, - "_EMA-L", - stx, - sd - ); - - for (i = Math.max(longCycle, sd.startFrom); i < quotes.length; i++) { - if ( - quotes[i].futureTick || - quotes[i][shortEMA] === null || - quotes[i][longEMA] === null - ) - break; - quotes[i][klinger] = quotes[i][shortEMA] - quotes[i][longEMA]; - } - - CIQ.Studies.MA( - "exponential", - Number(sd.inputs["Signal Periods"]), - klinger, - 0, - "KlingerSignal", - stx, - sd - ); - - for (i = sd.startFrom; i < quotes.length; i++) { - quotes[i][field] = quotes[i][klinger] - quotes[i][klingerSignal]; - } - sd.outputMap[field] = ""; - }; - - CIQ.Studies.studyLibrary = CIQ.extend(CIQ.Studies.studyLibrary, { - Klinger: { - name: "Klinger Volume Oscillator", - seriesFN: CIQ.Studies.displayHistogramWithSeries, - calculateFN: CIQ.Studies.calculateKlinger, - inputs: { "Signal Periods": 13, "Short Cycle": 34, "Long Cycle": 55 }, - outputs: { - Klinger: "auto", - KlingerSignal: "#FF0000", - "Increasing Bar": "#00DD00", - "Decreasing Bar": "#FF0000" - } - } - }); -} - -}; - - -let __js_advanced_studies_linearRegression_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -if (!CIQ.Studies) { - console.error( - "linearRegression feature requires first activating studies feature." - ); -} else { - CIQ.Studies.prettify["time series"] = "tsma"; - CIQ.Studies.movingAverage.conversions.tsma = "time series"; - CIQ.Studies.movingAverage.translations["time series"] = "Time Series"; - CIQ.Studies.movingAverage.typeMap.tsma = "TimeSeries"; - CIQ.Studies.movingAverage.typeMap["time series"] = "TimeSeries"; - - /** - * Calculate function for time series moving average. - * - * The resulting values will be added to the dataSet using the field name provided by the `sd.outputMap` entry. - * - * **Notes:** - * - This function calculates a single value, so it expects `sd.outputMap` to contain a single mapping. - * - To leverage as part of a larger study calculation, use {@link CIQ.Studies.MA} instead. - * - If no `outputs` object is defined in the library entry, the study will default to a single output named `Result`, which will then be used in lieu of `sd.outputs` to build the field name. - * - The study name may contain the unprintable character `‌`, see {@link studyDescriptor} documentation. - * - * @param {CIQ.ChartEngine} stx Chart object - * @param {CIQ.Studies.StudyDescriptor} sd Study Descriptor - * @private - * @memberof CIQ.Studies - */ - CIQ.Studies.calculateMovingAverageTimeSeries = function (stx, sd) { - sd.ma = new CIQ.Studies.StudyDescriptor(sd.name, "ma", sd.panel); - sd.ma.chart = sd.chart; - sd.ma.days = sd.days; - sd.ma.startFrom = sd.startFrom; - sd.ma.inputs = sd.inputs; - CIQ.Studies.calculateLinearRegressionIndicator(stx, sd.ma); - - var name = sd.name; - for (var p in sd.outputs) { - name = p + " " + name; - } - var offset = parseInt(sd.inputs.Offset, 10); - if (isNaN(offset)) offset = 0; - - var quotes = sd.chart.scrubbed; - // find start - var offsetBack = offset; - for (var i = sd.startFrom - 1; i >= 0; i--) { - var val = quotes[i][name]; - if (!val && val !== 0) continue; - if (offsetBack > 0) { - offsetBack--; - continue; - } - break; - } - var futureTicks = []; - for (i++; i < quotes.length; i++) { - var quote = quotes[i]; - if (i + offset >= 0) { - if (i + offset < quotes.length) - quotes[i + offset][name] = quote["Forecast " + sd.name]; - else { - var ft = {}; - ft[name] = quote["Forecast " + sd.name]; - futureTicks.push(ft); - } - } - } - sd.appendFutureTicks(stx, futureTicks); - }; - - CIQ.Studies.calculateLinearRegressionIndicator = function (stx, sd) { - var quotes = sd.chart.scrubbed; - if (quotes.length < sd.days + 1) { - sd.error = true; - return; - } - var field = sd.inputs.Field; - if (!field || field == "field") field = "Close"; - - var sumWeights = (sd.days * (sd.days + 1)) / 2; - var squaredSumWeights = Math.pow(sumWeights, 2); - var sumWeightsSquared = (sumWeights * (2 * sd.days + 1)) / 3; - - var sumCloses = 0; - var sumWeightedCloses = 0; - var sumClosesSquared = 0; - if (sd.startFrom) { - var sums = quotes[sd.startFrom - 1]["_sums " + sd.name]; - if (sums) { - sumWeightedCloses = sums[0]; - sumCloses = sums[1]; - sumClosesSquared = sums[2]; - } - } - for (var i = sd.startFrom; i < quotes.length; i++) { - var currentQuote = quotes[i][field]; - if (currentQuote && typeof currentQuote == "object") - currentQuote = currentQuote[sd.subField]; - if (!currentQuote && currentQuote !== 0) continue; - sumWeightedCloses += sd.days * currentQuote - sumCloses; - sumCloses += currentQuote; - sumClosesSquared += Math.pow(currentQuote, 2); - if (i < sd.days - 1) continue; - else if (i > sd.days - 1) { - var daysAgoQuote = quotes[i - sd.days][field]; - if (daysAgoQuote && typeof daysAgoQuote == "object") - daysAgoQuote = daysAgoQuote[sd.subField]; - if (!daysAgoQuote && daysAgoQuote !== 0) continue; - sumCloses -= daysAgoQuote; - sumClosesSquared -= Math.pow(daysAgoQuote, 2); - } - var b = - (sd.days * sumWeightedCloses - sumWeights * sumCloses) / - (sd.days * sumWeightsSquared - squaredSumWeights); - quotes[i]["Slope " + sd.name] = b; - var a = (sumCloses - b * sumWeights) / sd.days; - quotes[i]["Intercept " + sd.name] = a; - quotes[i]["Forecast " + sd.name] = a + b * sd.days; - var c = - (sd.days * sumWeightsSquared - squaredSumWeights) / - (sd.days * sumClosesSquared - Math.pow(sumCloses, 2)); - quotes[i]["RSquared " + sd.name] = b * b * c; - quotes[i]["_sums " + sd.name] = [ - sumWeightedCloses, - sumCloses, - sumClosesSquared - ]; - } - }; - - CIQ.Studies.studyLibrary = CIQ.extend(CIQ.Studies.studyLibrary, { - "Lin Fcst": { - name: "Linear Reg Forecast", - overlay: true, - calculateFN: CIQ.Studies.calculateLinearRegressionIndicator, - inputs: { Period: 14, Field: "field" }, - outputs: { Forecast: "auto" } - }, - "Lin Incpt": { - name: "Linear Reg Intercept", - overlay: true, - calculateFN: CIQ.Studies.calculateLinearRegressionIndicator, - inputs: { Period: 14, Field: "field" }, - outputs: { Intercept: "auto" } - }, - "Lin R2": { - name: "Linear Reg R2", - calculateFN: CIQ.Studies.calculateLinearRegressionIndicator, - inputs: { Period: 14, Field: "field" }, - outputs: { RSquared: "auto" } - }, - "LR Slope": { - name: "Linear Reg Slope", - calculateFN: CIQ.Studies.calculateLinearRegressionIndicator, - inputs: { Period: 14, Field: "field" }, - outputs: { Slope: "auto" } - }, - "Time Fcst": { - name: "Time Series Forecast", - overlay: true, - calculateFN: CIQ.Studies.calculateLinearRegressionIndicator, - inputs: { Period: 14, Field: "field" }, - outputs: { Forecast: "auto" } - } - }); -} - -}; - - -let __js_advanced_studies_macd_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -if (!CIQ.Studies) { - console.error("macd feature requires first activating studies feature."); -} else { - /** - * Calculate function for MACD study. - * - * The resulting values will be added to the dataSet using the field name provided by the `sd.outputMap` entry. - * - * **Notes:** - * - If no `outputs` object is defined in the library entry, the study will default to a single output named `Result`, which will then be used in lieu of `sd.outputs` to build the `sd.outputMap`. - * - The study name may contain the unprintable character `‌`, see studyDescriptor documentation - * - Results for the histogram will be added to the dataSegment using a field composed the study name and the "_hist" suffix. - * - * @param {CIQ.ChartEngine} stx Chart object - * @param {CIQ.Studies.StudyDescriptor} sd Study Descriptor - * @memberOf CIQ.Studies - */ - CIQ.Studies.calculateMACD = function (stx, sd) { - var quotes = sd.chart.scrubbed; - var inputs = sd.inputs, - name = sd.name; - if (!sd.macd1Days) sd.macd1Days = parseFloat(inputs["Fast MA Period"]); - if (!sd.macd2Days) sd.macd2Days = parseFloat(inputs["Slow MA Period"]); - if (!sd.signalDays) sd.signalDays = parseFloat(inputs["Signal Period"]); - if (!sd.days) sd.days = Math.max(sd.macd1Days, sd.macd2Days, sd.signalDays); - if (quotes.length < sd.days + 1) { - sd.error = true; - return; - } - - var field = sd.inputs.Field; - if (!field || field == "field") field = "Close"; - - var maType = inputs["Moving Average Type"]; - if (!maType) maType = "exponential"; - - CIQ.Studies.MA(maType, sd.macd1Days, field, 0, "_MACD1", stx, sd); - CIQ.Studies.MA(maType, sd.macd2Days, field, 0, "_MACD2", stx, sd); - - var i, - quote, - start = Math.max(sd.startFrom, sd.days - 1); - for (i = start; i < quotes.length; i++) { - quote = quotes[i]; - if ( - (quote["_MACD1 " + name] || quote["_MACD1 " + name] === 0) && - (quote["_MACD2 " + name] || quote["_MACD2 " + name] === 0) - ) - quote["MACD " + name] = - quote["_MACD1 " + name] - quote["_MACD2 " + name]; - } - var sigMaType = inputs["Signal MA Type"]; - if (!sigMaType) sigMaType = "exponential"; - CIQ.Studies.MA( - sigMaType, - sd.signalDays, - "MACD " + name, - 0, - "Signal", - stx, - sd - ); - - var histogram = name + "_hist"; - for (i = start; i < quotes.length; i++) { - quote = quotes[i]; - var signal = quote["Signal " + name]; - if (!signal && signal !== 0) continue; // don't create histogram before the signal line is valid - quote[histogram] = quote["MACD " + name] - quote["Signal " + name]; - } - sd.outputMap[histogram] = ""; - }; - - CIQ.Studies.studyLibrary = CIQ.extend(CIQ.Studies.studyLibrary, { - macd: { - name: "MACD", - calculateFN: CIQ.Studies.calculateMACD, - seriesFN: CIQ.Studies.displayHistogramWithSeries, - inputs: { - "Fast MA Period": 12, - "Slow MA Period": 26, - "Signal Period": 9 - }, - outputs: { - MACD: "auto", - Signal: "#FF0000", - "Increasing Bar": "#00DD00", - "Decreasing Bar": "#FF0000" - } - } - }); -} - -}; - - -let __js_advanced_studies_massIndex_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -if (!CIQ.Studies) { - console.error("massIndex feature requires first activating studies feature."); -} else { - CIQ.Studies.calculateMassIndex = function (stx, sd) { - var quotes = sd.chart.scrubbed; - if (quotes.length < Math.max(9, sd.days + 1)) { - sd.error = true; - return; - } - for (var i = sd.startFrom; i < quotes.length; i++) { - quotes[i]["_High-Low " + sd.name] = quotes[i].High - quotes[i].Low; - } - - CIQ.Studies.MA( - "exponential", - 9, - "_High-Low " + sd.name, - 0, - "_EMA", - stx, - sd - ); - CIQ.Studies.MA("exponential", 9, "_EMA " + sd.name, 0, "_EMA2", stx, sd); - - var total = 0; - if ( - quotes[sd.startFrom - 1] && - quotes[sd.startFrom - 1]["_total " + sd.name] - ) - total = quotes[sd.startFrom - 1]["_total " + sd.name]; - for (var j = Math.max(17, sd.startFrom); j < quotes.length; j++) { - total += quotes[j]["_EMA " + sd.name] / quotes[j]["_EMA2 " + sd.name]; - if (j >= 17 + sd.days - 1) { - quotes[j]["Result " + sd.name] = total; - total -= - quotes[j - sd.days + 1]["_EMA " + sd.name] / - quotes[j - sd.days + 1]["_EMA2 " + sd.name]; - } - quotes[j]["_total " + sd.name] = total; - } - }; - - CIQ.Studies.displayMassIndex = function (stx, sd, quotes) { - CIQ.Studies.displaySeriesAsLine(stx, sd, quotes); - - var bulge = sd.inputs["Bulge Threshold"]; - - var panel = stx.panels[sd.panel]; - var yAxis = sd.getYAxis(stx); - var color = CIQ.Studies.determineColor(sd.outputs.Result); - - var params = { - skipTransform: stx.panels[sd.panel].name != sd.chart.name, - panelName: sd.panel, - band: "Result " + sd.name, - threshold: bulge, - direction: 1, - color: color, - yAxis: yAxis, - opacity: 0.3 - }; - if (!sd.highlight && stx.highlightedDraggable) params.opacity *= 0.3; - CIQ.preparePeakValleyFill(stx, params); - CIQ.Studies.drawHorizontal(stx, sd, null, bulge, yAxis, color); - }; - - CIQ.Studies.studyLibrary = CIQ.extend(CIQ.Studies.studyLibrary, { - "Mass Idx": { - name: "Mass Index", - seriesFN: CIQ.Studies.displayMassIndex, - calculateFN: CIQ.Studies.calculateMassIndex, - inputs: { Period: 25, "Bulge Threshold": 27 }, - attributes: { - "Bulge Threshold": { min: 20, max: 35, step: 0.1 } - } - } - }); -} - -}; - - -let __js_advanced_studies_moneyFlow_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -if (!CIQ.Studies) { - console.error("moneyFlow feature requires first activating studies feature."); -} else { - CIQ.Studies.calculateMoneyFlowIndex = function (stx, sd) { - var quotes = sd.chart.scrubbed; - if (quotes.length < sd.days + 1) { - sd.error = true; - return; - } - var cumPosMF = 0, - cumNegMF = 0; - var startQuote = quotes[sd.startFrom - 1]; - var rawMFLbl = "_rawMF " + sd.name; - var cumMFLbl = "_cumMF " + sd.name; - var resultLbl = "Result " + sd.name; - if (startQuote && startQuote[cumMFLbl]) { - cumPosMF = startQuote[cumMFLbl][0]; - cumNegMF = startQuote[cumMFLbl][1]; - } - for (var i = sd.startFrom; i < quotes.length; i++) { - var typPrice = quotes[i]["hlc/3"]; - if (i > 0 && !quotes[i].futureTick) { - var lastTypPrice = quotes[i - 1]["hlc/3"]; - var rawMoneyFlow = typPrice * quotes[i].Volume; - if (typPrice > lastTypPrice) { - cumPosMF += rawMoneyFlow; - } else if (typPrice < lastTypPrice) { - rawMoneyFlow *= -1; - cumNegMF -= rawMoneyFlow; - } else { - rawMoneyFlow = 0; - } - if (i > sd.days) { - var old = quotes[i - sd.days][rawMFLbl]; - if (old > 0) cumPosMF -= old; - else cumNegMF += old; - if (cumNegMF === 0) quotes[i][resultLbl] = 100; - else if (quotes[i].Volume) - quotes[i][resultLbl] = 100 - 100 / (1 + cumPosMF / cumNegMF); - } - quotes[i][rawMFLbl] = rawMoneyFlow; - quotes[i][cumMFLbl] = [cumPosMF, cumNegMF]; - } - } - }; - - CIQ.Studies.studyLibrary = CIQ.extend(CIQ.Studies.studyLibrary, { - "M Flow": { - name: "Money Flow Index", - range: "0 to 100", - calculateFN: CIQ.Studies.calculateMoneyFlowIndex, - inputs: { Period: 14 }, - parameters: { - init: { - studyOverZonesEnabled: true, - studyOverBoughtValue: 80, - studyOverBoughtColor: "auto", - studyOverSoldValue: 20, - studyOverSoldColor: "auto" - } - } - } - }); -} - -}; - - -let __js_advanced_studies_movingAverages_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -if (!CIQ.Studies) { - console.error( - "movingAverages feature requires first activating studies feature." - ); -} else { - CIQ.Studies.prettify = CIQ.extend( - { - "2-exponential": "dema", - "3-exponential": "tema", - hull: "hma" - }, - CIQ.Studies.prettify - ); - - CIQ.extend(CIQ.Studies.movingAverage, { - conversions: { - hma: "hull", - dema: "2-exponential", - tema: "3-exponential" - }, - translations: { - hull: "Hull", - "2-exponential": "Double Exponential", - "3-exponential": "Triple Exponential" - }, - typeMap: { - hma: "Hull", - hull: "Hull", - dema: "DoubleExponential", - "2-exponential": "DoubleExponential", - tema: "TripleExponential", - "3-exponential": "TripleExponential" - } - }); - - CIQ.Studies.calculateMovingAverageHull = function (stx, sd) { - var quotes = sd.chart.scrubbed; - - var field = sd.inputs.Field; - if (!field || field == "field") field = "Close"; // Handle when the default inputs are passed in - - CIQ.Studies.MA("wma", sd.days, field, 0, "_WMA1", stx, sd); - CIQ.Studies.MA("wma", Math.ceil(sd.days / 2), field, 0, "_WMA2", stx, sd); - - var i, val; - for (i = sd.startFrom - 1; i >= 0; i--) { - val = quotes[i][field]; - if (val && typeof val == "object") val = val[sd.subField]; - if (val || val === 0) break; - } - for (i++; i < quotes.length; i++) { - var quote = quotes[i]; - quote["_MMA " + sd.name] = - 2 * quote["_WMA2 " + sd.name] - quote["_WMA1 " + sd.name]; - } - - var offset = parseInt(sd.inputs.Offset, 10); - if (isNaN(offset)) offset = 0; - - var hmaDays = Math.floor(Math.sqrt(sd.days)); - CIQ.Studies.MA("wma", hmaDays, "_MMA " + sd.name, offset, "_HMA", stx, sd); - - var name = sd.name; - for (var p in sd.outputs) { - name = p + " " + name; - } - for ( - i = Math.max(sd.days + hmaDays - 1, sd.startFrom); - i < quotes.length; - i++ - ) { - quotes[i][name] = quotes[i]["_HMA " + sd.name]; - } - }; - - CIQ.Studies.calculateMovingAverageDoubleExponential = function (stx, sd) { - var quotes = sd.chart.scrubbed; - - var field = sd.inputs.Field; - if (!field || field == "field") field = "Close"; // Handle when the default inputs are passed in - - CIQ.Studies.MA("ema", sd.days, field, 0, "_EMA1", stx, sd); - CIQ.Studies.MA("ema", sd.days, "_EMA1 " + sd.name, 0, "_EMA2", stx, sd); - - var offset = parseInt(sd.inputs.Offset, 10); - if (isNaN(offset)) offset = 0; - var i, val; - var offsetBack = offset; - for (i = sd.startFrom - 1; i >= 0; i--) { - val = quotes[i][field]; - if (val && typeof val == "object") val = val[sd.subField]; - if (!val && val !== 0) continue; - if (offsetBack > 0) { - offsetBack--; - continue; - } - break; - } - var name = sd.name; - for (var p in sd.outputs) { - name = p + " " + name; - } - var futureTicks = []; - for (i++; i < quotes.length; i++) { - if (i < 2 * (sd.days - 1)) continue; - var quote = quotes[i]; - var result = 2 * quote["_EMA1 " + sd.name] - quote["_EMA2 " + sd.name]; - if (i + offset >= 0) { - if (i + offset < quotes.length) quotes[i + offset][name] = result; - else { - var ft = {}; - ft[name] = result; - futureTicks.push(ft); - } - } - } - sd.appendFutureTicks(stx, futureTicks); - }; - - CIQ.Studies.calculateMovingAverageTripleExponential = function (stx, sd) { - var quotes = sd.chart.scrubbed; - - var field = sd.inputs.Field; - if (!field || field == "field") field = "Close"; // Handle when the default inputs are passed in - - CIQ.Studies.MA("ema", sd.days, field, 0, "_EMA1", stx, sd); - CIQ.Studies.MA("ema", sd.days, "_EMA1 " + sd.name, 0, "_EMA2", stx, sd); - CIQ.Studies.MA("ema", sd.days, "_EMA2 " + sd.name, 0, "_EMA3", stx, sd); - - var offset = parseInt(sd.inputs.Offset, 10); - if (isNaN(offset)) offset = 0; - var i, val; - var offsetBack = offset; - for (i = sd.startFrom - 1; i >= 0; i--) { - val = quotes[i][field]; - if (val && typeof val == "object") val = val[sd.subField]; - if (!val && val !== 0) continue; - if (offsetBack > 0) { - offsetBack--; - continue; - } - break; - } - var name = sd.name; - for (var p in sd.outputs) { - name = p + " " + name; - } - var futureTicks = []; - for (i++; i < quotes.length; i++) { - if (i < 3 * (sd.days - 1)) continue; - var quote = quotes[i]; - var result = - 3 * quote["_EMA1 " + sd.name] - - 3 * quote["_EMA2 " + sd.name] + - quote["_EMA3 " + sd.name]; - if (i + offset >= 0) { - if (i + offset < quotes.length) quotes[i + offset][name] = result; - else { - var ft = {}; - ft[name] = result; - futureTicks.push(ft); - } - } - } - sd.appendFutureTicks(stx, futureTicks); - }; - - CIQ.Studies.calculateMAEnvelope = function (stx, sd) { - var field = sd.inputs.Field; - if (!field || field == "field") field = "Close"; - CIQ.Studies.MA( - sd.inputs["Moving Average Type"], - sd.days, - field, - 0, - "MA", - stx, - sd - ); - var shiftType = sd.inputs["Shift Type"]; - var shift = sd.inputs.Shift; - if (!shiftType) { - //legacy - shiftType = "percent"; - shift = sd.inputs["Shift Percentage"]; - } - if (shiftType == "percent") { - CIQ.Studies.calculateGenericEnvelope( - stx, - sd, - shift / 100, - "MA " + sd.name - ); - } else if (shiftType == "points") { - CIQ.Studies.calculateGenericEnvelope( - stx, - sd, - null, - "MA " + sd.name, - null, - Number(shift) - ); - } - }; - - CIQ.Studies.calculateMADev = function (stx, sd) { - var quotes = sd.chart.scrubbed; - if (quotes.length < sd.days + 1) { - sd.error = true; - return; - } - var field = sd.inputs.Field; - if (!field || field == "field") field = "Close"; - var pts = sd.inputs["Points Or Percent"]; - if (!pts) pts = "Points"; - var maType = sd.inputs["Moving Average Type"]; - if (!maType) maType = "exponential"; - CIQ.Studies.MA(maType, sd.days, field, 0, "_MA", stx, sd); - var histogram = sd.name + "_hist"; - for (var i = Math.max(sd.startFrom, sd.days - 1); i < quotes.length; i++) { - var quote = quotes[i]; - var val = quote[field]; - if (val && typeof val == "object") val = val[sd.subField]; - var qMA = quote["_MA " + sd.name]; - if (qMA || qMA === 0) { - if (pts == "Points") quote[histogram] = val - qMA; - else quote[histogram] = 100 * (val / qMA - 1); - } - } - sd.outputMap = {}; - sd.outputMap[sd.name + "_hist"] = ""; - }; - - CIQ.Studies.studyLibrary = CIQ.extend(CIQ.Studies.studyLibrary, { - "MA Env": { - name: "Moving Average Envelope", - overlay: true, - seriesFN: CIQ.Studies.displayChannel, - calculateFN: CIQ.Studies.calculateMAEnvelope, - inputs: { - Period: 50, - Field: "field", - "Shift Type": ["percent", "points"], - Shift: 5, - "Moving Average Type": "ma", - "Channel Fill": true - }, - outputs: { - "MA Env Top": "auto", - "MA Env Median": "auto", - "MA Env Bottom": "auto" - }, - attributes: { - Shift: { min: 0.1, step: 0.1 } - } - }, - "MA Dev": { - name: "Moving Average Deviation", - calculateFN: CIQ.Studies.calculateMADev, - seriesFN: CIQ.Studies.displayHistogramWithSeries, - inputs: { - Period: 12, - Field: "field", - "Moving Average Type": "ma", - "Points Or Percent": ["Points", "Percent"] - }, - outputs: { "Increasing Bar": "#00DD00", "Decreasing Bar": "#FF0000" } - }, - "High Low": { - name: "High Low Bands", - overlay: true, - seriesFN: CIQ.Studies.displayChannel, - calculateFN: function (stx, sd) { - sd.inputs["Moving Average Type"] = "triangular"; - CIQ.Studies.calculateMAEnvelope(stx, sd); - }, - inputs: { - Period: 10, - Field: "field", - "Shift Percentage": 5, - "Channel Fill": true - }, - outputs: { - "High Low Top": "auto", - "High Low Median": "auto", - "High Low Bottom": "auto" - }, - attributes: { - "Shift Percentage": { min: 0.1, step: 0.1 } - } - } - }); -} - -}; - - -let __js_advanced_studies_parabolicSAR_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -if (!CIQ.Studies) { - console.error( - "parabolicSAR feature requires first activating studies feature." - ); -} else { - CIQ.Studies.calculatePSAR = function (stx, sd) { - var quotes = sd.chart.scrubbed; - - var af = 0; - var ep = null; - var lasttrend = false; - var SAR = 0; - var step = parseFloat(sd.inputs["Minimum AF"]); - var maxStep = parseFloat(sd.inputs["Maximum AF"]); - - function doReset() { - af = 0; - ep = null; - lasttrend = !lasttrend; - } - if (sd.startFrom > 0) { - SAR = quotes[sd.startFrom - 1]["Result " + sd.name]; - var state = quotes[sd.startFrom - 1]["_state " + sd.name]; - if (state && state.length == 3) { - af = state[0]; - ep = state[1]; - lasttrend = state[2]; - } - } - for (var i = sd.startFrom - 1; i < quotes.length - 1; i++) { - if (i < 0) continue; - if (quotes[i].futureTick) break; - var priorSAR = SAR; - if (lasttrend) { - if (!ep || ep < quotes[i].High) { - ep = quotes[i].High; - af = Math.min(af + step, maxStep); - } - SAR = priorSAR + af * (ep - priorSAR); - var lowestPrior2Lows = Math.min( - quotes[Math.max(1, i) - 1].Low, - quotes[i].Low - ); - if (SAR > quotes[i + 1].Low) { - SAR = ep; - doReset(); - } else if (SAR > lowestPrior2Lows) { - SAR = lowestPrior2Lows; - } - } else { - if (!ep || ep > quotes[i].Low) { - ep = quotes[i].Low; - af = Math.min(af + step, maxStep); - } - SAR = priorSAR + af * (ep - priorSAR); - var highestPrior2Highs = Math.max( - quotes[Math.max(1, i) - 1].High, - quotes[i].High - ); - if (SAR < quotes[i + 1].High) { - SAR = ep; - doReset(); - } else if (SAR < highestPrior2Highs) { - SAR = highestPrior2Highs; - } - } - quotes[i + 1]["_state " + sd.name] = [af, ep, lasttrend]; - if (!isNaN(quotes[i].High) || !isNaN(quotes[i].Low)) { - quotes[i + 1]["Result " + sd.name] = SAR; - } - } - }; - - CIQ.Studies.studyLibrary = CIQ.extend(CIQ.Studies.studyLibrary, { - PSAR: { - name: "Parabolic SAR", - overlay: true, - calculateFN: CIQ.Studies.calculatePSAR, - seriesFN: CIQ.Studies.displayPSAR2, - inputs: { "Minimum AF": 0.02, "Maximum AF": 0.2 } - } - }); -} - -}; - - -let __js_advanced_studies_pivotPoints_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -if (!CIQ.Studies) { - console.error( - "pivotPoints feature requires first activating studies feature." - ); -} else { - CIQ.Studies.calculatePivotPoints = function (stx, sd) { - var quotes = sd.chart.scrubbed; - var period = "day", - interval = stx.layout.interval, - timeUnit = stx.layout.timeUnit; - if (interval == "day") period = "month"; - else if (CIQ.ChartEngine.isDailyInterval(interval)) period = "year"; - else if ( - interval == "second" || - interval == "millisecond" || - timeUnit == "second" || - timeUnit == "millisecond" - ) - period = "15min"; - else { - var intvl = stx.layout.periodicity; - if (interval != "minute") { - intvl *= interval; - } - if (intvl >= 30) period = "week"; - } - - var marketOffset = null; - var offset = 7 - CIQ.getFromNS(stx.chart, "market.beginningDayOfWeek", 0); // used to determine end of week - - var pointers = { - pivotPoint: NaN, - high: 0, - low: 0, - prevHigh: 0, - prevLow: 0, - hlSpread: 0 - }; - if (sd.startFrom > 1 && quotes[sd.startFrom - 1]["_pointers " + sd.name]) { - pointers = CIQ.clone(quotes[sd.startFrom - 1]["_pointers " + sd.name]); - } - function resetPivots() { - pointers.pivotPoint = - (pointers.high + pointers.low + quotes[i - 1].Close) / 3; - pointers.prevHigh = pointers.high; - pointers.prevLow = pointers.low; - pointers.hlSpread = pointers.high - pointers.low; - pointers.high = pointers.low = 0; - } - for (var i = Math.max(1, sd.startFrom); i < quotes.length; i++) { - if (!quotes[i - 1]) continue; - pointers.high = Math.max(pointers.high, quotes[i - 1].High); - pointers.low = Math.min( - pointers.low > 0 ? pointers.low : quotes[i - 1].Low, - quotes[i - 1].Low - ); - if (sd.inputs.Continuous) resetPivots(); - else if ( - period == "year" && - quotes[i].DT.getYear() != quotes[i - 1].DT.getYear() - ) { - //new yearly period - resetPivots(); - } else if ( - period == "month" && - quotes[i].DT.getMonth() != quotes[i - 1].DT.getMonth() - ) { - //new monthly period - resetPivots(); - } else if ( - period == "week" && - (quotes[i].DT.getDay() + offset) % 7 < - (quotes[i - 1].DT.getDay() + offset) % 7 - ) { - //new weekly period - resetPivots(); - } else if (period == "day") { - if (marketOffset === null) { - //possible new daily period - marketOffset = CIQ.Studies.getMarketOffset({ - stx, - localQuoteDate: quotes[i].DT, - shiftToDateBoundary: true - }); - } - var newDate = new Date( - new Date(+quotes[i].DT).setMilliseconds( - quotes[i].DT.getMilliseconds() + marketOffset - ) - ); - var oldDate = new Date( - new Date(+quotes[i - 1].DT).setMilliseconds( - quotes[i - 1].DT.getMilliseconds() + marketOffset - ) - ); - if ( - oldDate.getDate() !== newDate.getDate() && - oldDate.getDay() !== 0 && - stx.chart.market.isMarketDate(newDate) - ) { - //new daily period - marketOffset = null; - resetPivots(); - } - } else if ( - period == "15min" && - (quotes[i].DT.getHours() != quotes[i - 1].DT.getHours() || - Math.floor(quotes[i].DT.getMinutes() / 15) != - Math.floor(quotes[i - 1].DT.getMinutes() / 15)) - ) { - //new 15 minute period - resetPivots(); - } - quotes[i]["Pivot " + sd.name] = pointers.pivotPoint; - if (sd.inputs.Type.toLowerCase() == "fibonacci") { - quotes[i]["Resistance 1 " + sd.name] = - pointers.pivotPoint + 0.382 * pointers.hlSpread; - quotes[i]["Resistance 2 " + sd.name] = - pointers.pivotPoint + 0.618 * pointers.hlSpread; - quotes[i]["Resistance 3 " + sd.name] = - pointers.pivotPoint + pointers.hlSpread; - quotes[i]["Support 1 " + sd.name] = - pointers.pivotPoint - 0.382 * pointers.hlSpread; - quotes[i]["Support 2 " + sd.name] = - pointers.pivotPoint - 0.618 * pointers.hlSpread; - quotes[i]["Support 3 " + sd.name] = - pointers.pivotPoint - pointers.hlSpread; - } else { - quotes[i]["Resistance 1 " + sd.name] = - 2 * pointers.pivotPoint - pointers.prevLow; - quotes[i]["Resistance 2 " + sd.name] = - pointers.pivotPoint + pointers.hlSpread; - quotes[i]["Resistance 3 " + sd.name] = - pointers.prevHigh + 2 * (pointers.pivotPoint - pointers.prevLow); - quotes[i]["Support 1 " + sd.name] = - 2 * pointers.pivotPoint - pointers.prevHigh; - quotes[i]["Support 2 " + sd.name] = - pointers.pivotPoint - pointers.hlSpread; - quotes[i]["Support 3 " + sd.name] = - pointers.prevLow - 2 * (pointers.prevHigh - pointers.pivotPoint); - } - quotes[i]["_pointers " + sd.name] = CIQ.clone(pointers); - } - }; - - CIQ.Studies.displayPivotPoints = function (stx, sd, quotes) { - sd.noSlopes = !sd.inputs.Continuous; - CIQ.Studies.displaySeriesAsLine(stx, sd, quotes); - if (sd.inputs.Shading) { - var panel = stx.panels[sd.panel]; - var params = { - noSlopes: sd.noSlopes, - opacity: sd.parameters.opacity ? sd.parameters.opacity : 0.2, - skipTransform: panel.name != sd.chart.name, - yAxis: sd.getYAxis(stx) - }; - if (!sd.highlight && stx.highlightedDraggable) params.opacity *= 0.3; - CIQ.prepareChannelFill( - stx, - CIQ.extend( - { - panelName: sd.panel, - topBand: "Resistance 3 " + sd.name, - bottomBand: "Resistance 2 " + sd.name, - color: CIQ.Studies.determineColor(sd.outputs["Resistance 3"]) - }, - params - ) - ); - CIQ.prepareChannelFill( - stx, - CIQ.extend( - { - panelName: sd.panel, - topBand: "Resistance 2 " + sd.name, - bottomBand: "Resistance 1 " + sd.name, - color: CIQ.Studies.determineColor(sd.outputs["Resistance 2"]) - }, - params - ) - ); - CIQ.prepareChannelFill( - stx, - CIQ.extend( - { - panelName: sd.panel, - topBand: "Resistance 1 " + sd.name, - bottomBand: "Pivot " + sd.name, - color: CIQ.Studies.determineColor(sd.outputs["Resistance 1"]) - }, - params - ) - ); - CIQ.prepareChannelFill( - stx, - CIQ.extend( - { - panelName: sd.panel, - topBand: "Support 1 " + sd.name, - bottomBand: "Pivot " + sd.name, - color: CIQ.Studies.determineColor(sd.outputs["Support 1"]) - }, - params - ) - ); - CIQ.prepareChannelFill( - stx, - CIQ.extend( - { - panelName: sd.panel, - topBand: "Support 2 " + sd.name, - bottomBand: "Support 1 " + sd.name, - color: CIQ.Studies.determineColor(sd.outputs["Support 2"]) - }, - params - ) - ); - CIQ.prepareChannelFill( - stx, - CIQ.extend( - { - panelName: sd.panel, - topBand: "Support 3 " + sd.name, - bottomBand: "Support 2 " + sd.name, - color: CIQ.Studies.determineColor(sd.outputs["Support 3"]) - }, - params - ) - ); - } - }; - - CIQ.Studies.studyLibrary = CIQ.extend(CIQ.Studies.studyLibrary, { - "Pivot Points": { - name: "Pivot Points", - overlay: true, - seriesFN: CIQ.Studies.displayPivotPoints, - calculateFN: CIQ.Studies.calculatePivotPoints, - inputs: { - Type: ["standard", "fibonacci"], - Continuous: false, - Shading: false - }, - outputs: { - Pivot: "auto", - "Resistance 1": "#b82c0b", - "Support 1": "#699158", - "Resistance 2": "#e36460", - "Support 2": "#b3d987", - "Resistance 3": "#ffd0cf", - "Support 3": "#d3e8ae" - }, - parameters: { - init: { opacity: 0.2 } - } - } - }); -} - -}; - - -let __js_advanced_studies_prettyGoodOscillator_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -if (!CIQ.Studies) { - console.error( - "prettyGoodOscillator feature requires first activating studies feature." - ); -} else { - CIQ.Studies.calculatePrettyGoodOscillator = function (stx, sd) { - var quotes = sd.chart.scrubbed; - if (quotes.length < sd.days + 1) { - sd.error = true; - return; - } - - CIQ.Studies.MA("exponential", sd.days, "trueRange", 0, "_EMA", stx, sd); - CIQ.Studies.MA("simple", sd.days, "Close", 0, "_SMA", stx, sd); - - for (var i = Math.max(1, sd.startFrom); i < quotes.length; i++) { - if (!quotes[i]["_SMA " + sd.name] || !quotes[i]["_EMA " + sd.name]) - continue; - quotes[i]["Result " + sd.name] = - (quotes[i].Close - quotes[i]["_SMA " + sd.name]) / - quotes[i]["_EMA " + sd.name]; - } - }; - - CIQ.Studies.studyLibrary = CIQ.extend(CIQ.Studies.studyLibrary, { - "Pretty Good": { - name: "Pretty Good Oscillator", - calculateFN: CIQ.Studies.calculatePrettyGoodOscillator, - parameters: { - init: { - studyOverZonesEnabled: true, - studyOverBoughtValue: 3, - studyOverBoughtColor: "auto", - studyOverSoldValue: -3, - studyOverSoldColor: "auto" - } - } - } - }); -} - -}; - - -let __js_advanced_studies_priceMomentumOscillator_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -if (!CIQ.Studies) { - console.error( - "priceMomentumOscillator feature requires first activating studies feature." - ); -} else { - CIQ.Studies.calculatePMO = function (stx, sd) { - var periods = { - Smooth: Number(sd.inputs["Smoothing Period"]) - 1, - Double: Number(sd.inputs["Double Smoothing Period"]) - 1, - Signal: Number(sd.inputs["Signal Period"]) - }; - var quotes = sd.chart.scrubbed; - if (quotes.length < periods.Smooth + periods.Double) { - sd.error = true; - return; - } - var field = sd.inputs.Field; - if (!field || field == "field") field = "Close"; - var i; - for (i = sd.startFrom; i < quotes.length; i++) { - if (!quotes[i]) continue; - if (!quotes[i - 1]) continue; - var denom = quotes[i - 1][field]; - if (denom) { - quotes[i]["_ROCx10 " + sd.name] = 1000 * (quotes[i][field] / denom - 1); - } - } - CIQ.Studies.MA( - "exponential", - periods.Smooth, - "_ROCx10 " + sd.name, - 0, - "_EMAx10", - stx, - sd - ); - CIQ.Studies.MA( - "exponential", - periods.Double, - "_EMAx10 " + sd.name, - 0, - "PMO", - stx, - sd - ); - CIQ.Studies.MA( - "exponential", - periods.Signal, - "PMO " + sd.name, - 0, - "PMOSignal", - stx, - sd - ); - sd.zoneOutput = "PMO"; - }; - - CIQ.Studies.studyLibrary = CIQ.extend(CIQ.Studies.studyLibrary, { - PMO: { - name: "Price Momentum Oscillator", - calculateFN: CIQ.Studies.calculatePMO, - inputs: { - Field: "field", - "Smoothing Period": 35, - "Double Smoothing Period": 20, - "Signal Period": 10 - }, - outputs: { PMO: "auto", PMOSignal: "#FF0000" }, - parameters: { - init: { - studyOverZonesEnabled: true, - studyOverBoughtValue: 2.5, - studyOverBoughtColor: "auto", - studyOverSoldValue: -2.5, - studyOverSoldColor: "auto" - } - }, - attributes: { - studyOverBoughtValue: { min: 0, step: "0.05" }, - studyOverSoldValue: { max: 0, step: "0.05" } - } - } - }); -} - -}; - - -let __js_advanced_studies_priceVolumeOscillator_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -if (!CIQ.Studies) { - console.error( - "priceVolumeOscillator feature requires first activating studies feature." - ); -} else { - CIQ.Studies.calculatePriceOscillator = function (stx, sd) { - var quotes = sd.chart.scrubbed; - var short = Number(sd.inputs["Short Cycle"]); - var long = Number(sd.inputs["Long Cycle"]); - if (quotes.length < Math.max(short, long) + 1) { - sd.error = true; - return; - } - var field = sd.inputs.Field; - var maType = sd.inputs["Moving Average Type"]; - if (!maType) maType = "simple"; - if (!field || field == "field") field = "Close"; - if (sd.parameters.isVolume) { - field = "Volume"; - maType = "exponential"; - } - var pts = sd.inputs["Points Or Percent"]; - if (!pts) pts = "Percent"; - - CIQ.Studies.MA(maType, short, field, 0, "_Short MA", stx, sd); - CIQ.Studies.MA(maType, long, field, 0, "_Long MA", stx, sd); - - for (var i = Math.max(long, sd.startFrom); i < quotes.length; i++) { - var quote = quotes[i]; - if (!quote) continue; - var qShMA = quote["_Short MA " + sd.name], - qLgMA = quote["_Long MA " + sd.name]; - if ((qShMA || qShMA === 0) && (qLgMA || qLgMA === 0)) { - if (pts == "Points") quote["Result " + sd.name] = qShMA - qLgMA; - else quote["Result " + sd.name] = 100 * (qShMA / qLgMA - 1); - if (sd.outputs["Increasing Bar"]) { - quote[sd.name + "_hist"] = quote["Result " + sd.name]; - sd.outputMap = {}; - sd.outputMap[sd.name + "_hist"] = ""; - } - } - } - }; - - CIQ.Studies.displayRAVI = function (stx, sd, quotes) { - var panel = stx.panels[sd.panel], - context = sd.getContext(stx); - var yAxis = sd.getYAxis(stx); - - var y = stx.pixelFromPrice(0, panel, yAxis); - - var myWidth = stx.layout.candleWidth - 2; - if (myWidth < 2) myWidth = 1; - - var upColor = CIQ.Studies.determineColor(sd.outputs["Increasing Bar"]); - var downColor = CIQ.Studies.determineColor(sd.outputs["Decreasing Bar"]); - stx.startClip(sd.panel); - stx.canvasColor("stx_histogram"); - if (!sd.underlay) context.globalAlpha = 1; - if (!sd.highlight && stx.highlightedDraggable) context.globalAlpha *= 0.3; - for (var i = 0; i < quotes.length; i++) { - var quote = quotes[i], - quote_1 = quotes[i - 1]; - if (!quote_1) - quote_1 = stx.getPreviousBar(stx.chart, sd.name + "_hist", i); - if (!quote) continue; - var overBought = 0, - overSold = 0; - if (sd.parameters && sd.parameters.studyOverZonesEnabled) { - overBought = parseFloat(sd.parameters.studyOverBoughtValue); - overSold = parseFloat(sd.parameters.studyOverSoldValue); - } - if (!quote_1) context.fillStyle = "#CCCCCC"; - else if ( - quote[sd.name + "_hist"] > overBought && - quote_1[sd.name + "_hist"] < quote[sd.name + "_hist"] - ) - context.fillStyle = upColor; - else if ( - quote[sd.name + "_hist"] < overSold && - quote_1[sd.name + "_hist"] > quote[sd.name + "_hist"] - ) - context.fillStyle = downColor; - else context.fillStyle = "#CCCCCC"; - if (quote.candleWidth) - myWidth = Math.floor(Math.max(1, quote.candleWidth - 2)); - context.fillRect( - Math.floor(stx.pixelFromBar(i, panel.chart) - myWidth / 2), - Math.floor(y), - Math.floor(myWidth), - Math.floor( - stx.pixelFromPrice(quote[sd.name + "_hist"], panel, yAxis) - y - ) - ); - } - stx.endClip(); - }; - - CIQ.Studies.studyLibrary = CIQ.extend(CIQ.Studies.studyLibrary, { - "Price Osc": { - name: "Price Oscillator", - calculateFN: CIQ.Studies.calculatePriceOscillator, - inputs: { - Field: "field", - "Short Cycle": 12, - "Long Cycle": 26, - "Moving Average Type": "ema", - "Points Or Percent": ["Points", "Percent"] - } - }, - "Vol Osc": { - name: "Volume Oscillator", - calculateFN: CIQ.Studies.calculatePriceOscillator, - inputs: { - "Short Cycle": 12, - "Long Cycle": 26, - "Points Or Percent": ["Points", "Percent"] - }, - parameters: { - init: { isVolume: true } - } - }, - RAVI: { - name: "RAVI", - seriesFN: CIQ.Studies.displayRAVI, - calculateFN: CIQ.Studies.calculatePriceOscillator, - inputs: { - Field: "field", - "Moving Average Type": "vdma", - "Short Cycle": 7, - "Long Cycle": 65 - }, - outputs: { "Increasing Bar": "#00DD00", "Decreasing Bar": "#FF0000" }, - centerline: 0, - parameters: { - init: { - studyOverZonesEnabled: true, - studyOverBoughtValue: 3, - studyOverBoughtColor: "auto", - studyOverSoldValue: -3, - studyOverSoldColor: "auto" - } - }, - attributes: { - studyOverBoughtValue: { min: 0, step: "0.1" }, - studyOverSoldValue: { max: 0, step: "0.1" } - } - } - }); -} - -}; - - -let __js_advanced_studies_primeNumber_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -if (!CIQ.Studies) { - console.error( - "primeNumber feature requires first activating studies feature." - ); -} else { - CIQ.Studies.calculatePrimeNumber = function (stx, sd) { - var primes = []; - function isPrime(x) { - if (x <= 0) return false; - else if (x != Math.floor(x)) return false; - //assume x is an int - else if (primes[x] === true || primes[x] === false) return primes[x]; - var q = parseInt(Math.sqrt(x), 10); - for (var i = 2; i <= q; i++) { - if (x % i === 0) { - primes[x] = false; - return false; - } - } - primes[x] = true; - return true; - } - var quotes = sd.chart.scrubbed; - for (var i = sd.startFrom; i < quotes.length; i++) { - var quote = quotes[i]; - if (!quote) continue; - - var high = quote.High; - if (!isNaN(high)) { - for (var h = 0; high > 0 && high <= 10; h++) high *= 10; - if (isPrime(high)) high += 2; - high = Math.ceil(high); - if (high % 2 === 0) high++; - while (!isPrime(high)) high += 2; - high /= Math.pow(10, h); - } - - var low = quote.Low; - if (!isNaN(low)) { - for (var l = 0; low > 0 && low <= 10; l++) low *= 10; - if (isPrime(low)) low -= 2; - low = Math.floor(low); - if (low % 2 === 0) low--; - if (low > 0) { - while (!isPrime(low)) low -= 2; - low /= Math.pow(10, l); - } - } - - if (sd.type == "Prime Number Bands") { - if (!isNaN(high)) quote["Prime Bands Top " + sd.name] = high; - if (!isNaN(low)) - quote["Prime Bands Bottom " + sd.name] = Math.max(0, low); - } else { - var value = 0; - var tolerance = - (sd.inputs["Tolerance Percentage"] * (high - low)) / 100; - var skew = high + low - 2 * quote.Close; - if (skew < tolerance) value = 1; - else if (skew > tolerance) value = -1; - if (value) quote["Result " + sd.name] = value; - } - } - }; - - CIQ.Studies.studyLibrary = CIQ.extend(CIQ.Studies.studyLibrary, { - "Prime Number": { - name: "Prime Number Oscillator", - range: "-1 to 1", - calculateFN: CIQ.Studies.calculatePrimeNumber, - centerline: 0, - inputs: { "Tolerance Percentage": 5 }, - attributes: { - "Tolerance Percentage": { min: 0.1, step: 0.1 } - } - }, - "Prime Number Bands": { - name: "Prime Number Bands", - overlay: true, - calculateFN: CIQ.Studies.calculatePrimeNumber, - seriesFN: CIQ.Studies.displayChannel, - inputs: { "Channel Fill": true }, - outputs: { - "Prime Bands Top": "auto", - "Prime Bands Bottom": "auto", - "Prime Bands Channel": "auto" - } - } - }); -} - -}; - - -let __js_advanced_studies_pring_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -if (!CIQ.Studies) { - console.error("pring feature requires first activating studies feature."); -} else { - CIQ.Studies.calculateKST = function (stx, sd) { - var quotes = sd.chart.scrubbed; - var field = sd.inputs.Field; - if (!field || field == "field") field = "Close"; - var roc = {}, - smp = {}; - roc[1] = Number(sd.inputs["Lightest Rate of Change Period"]); - roc[2] = Number(sd.inputs["Light Rate of Change Period"]); - roc[3] = Number(sd.inputs["Heavy Rate of Change Period"]); - roc[4] = Number(sd.inputs["Heaviest Rate of Change Period"]); - smp[1] = Number(sd.inputs["Lightest SMA Period"]); - smp[2] = Number(sd.inputs["Light SMA Period"]); - smp[3] = Number(sd.inputs["Heavy SMA Period"]); - smp[4] = Number(sd.inputs["Heaviest SMA Period"]); - var sp = Number(sd.inputs["Signal Period"]); - var i, j; - for (i = sd.startFrom; i < quotes.length; i++) { - if (!quotes[i]) continue; - for (j = 1; j <= 4; j++) { - if (i >= roc[j] && quotes[i - roc[j]] && quotes[i - roc[j]][field]) - quotes[i]["_ROC" + j + " " + sd.name] = - 100 * (quotes[i][field] / quotes[i - roc[j]][field] - 1); - } - } - for (j = 1; j <= 4; j++) { - CIQ.Studies.MA( - "simple", - smp[j], - "_ROC" + j + " " + sd.name, - 0, - "_SMA" + j, - stx, - sd - ); - } - for (i = sd.startFrom; i < quotes.length; i++) { - quotes[i]["KST " + sd.name] = null; - for (j = 1; j <= 4; j++) { - var val = quotes[i]["_SMA" + j + " " + sd.name]; - if (val || val === 0) quotes[i]["KST " + sd.name] += j * val; - } - } - CIQ.Studies.MA("simple", sp, "KST " + sd.name, 0, "KSTSignal", stx, sd); - }; - - CIQ.Studies.calculateSpecialK = function (stx, sd) { - var quotes = sd.chart.scrubbed; - var field = sd.inputs.Field; - if (!field || field == "field") field = "Close"; - var span = sd.inputs.Interval; - if (!span) span = "daily"; - var roc = { - daily: [10, 15, 20, 30, 50, 65, 75, 100, 195, 265, 390, 530], - weekly: [4, 5, 6, 8, 10, 13, 15, 20, 39, 52, 78, 104] - }; - var map = { - daily: [10, 10, 10, 15, 50, 65, 75, 100, 130, 130, 130, 195], - weekly: [4, 5, 6, 8, 10, 13, 15, 20, 26, 26, 26, 39] - }; - var i, j; - for (i = sd.startFrom; i < quotes.length; i++) { - if (!quotes[i]) continue; - for (j = 0; j < roc[span].length; j++) { - if ( - i >= roc[span][j] && - quotes[i - roc[span][j]] && - quotes[i - roc[span][j]][field] - ) - quotes[i]["_ROC" + j + " " + sd.name] = - 100 * (quotes[i][field] / quotes[i - roc[span][j]][field] - 1); - } - } - for (j = 0; j < map[span].length; j++) { - CIQ.Studies.MA( - span == "daily" ? "simple" : "exponential", - map[span][j], - "_ROC" + j + " " + sd.name, - 0, - "_MA" + j, - stx, - sd - ); - } - for (i = sd.startFrom; i < quotes.length; i++) { - quotes[i]["Result " + sd.name] = null; - for (j = 0; j < map[span].length; j++) { - var val = quotes[i]["_MA" + j + " " + sd.name]; - if (val || val === 0) - quotes[i]["Result " + sd.name] += ((j % 4) + 1) * val; - } - } - }; - - CIQ.Studies.studyLibrary = CIQ.extend(CIQ.Studies.studyLibrary, { - "Pring KST": { - name: "Pring's Know Sure Thing", - calculateFN: CIQ.Studies.calculateKST, - inputs: { - Field: "field", - "Lightest Rate of Change Period": 10, - "Lightest SMA Period": 10, - "Light Rate of Change Period": 15, - "Light SMA Period": 10, - "Heavy Rate of Change Period": 20, - "Heavy SMA Period": 10, - "Heaviest Rate of Change Period": 30, - "Heaviest SMA Period": 15, - "Signal Period": 9 - }, - outputs: { KST: "#00DD00", KSTSignal: "#FF0000" } - }, - "Pring Sp-K": { - name: "Pring's Special K", - calculateFN: CIQ.Studies.calculateSpecialK, - inputs: { Field: "field", Interval: ["daily", "weekly"] } - } - }); -} - -}; - - -let __js_advanced_studies_projectedVolume_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; -var timezoneJS = - typeof _timezoneJS !== "undefined" ? _timezoneJS : _exports.timezoneJS; - -if (!CIQ.Studies) { - console.error( - "projectedVolume feature requires first activating studies feature." - ); -} else if (!CIQ.Studies.studyLibrary.PVAT) { - /** - * Initializes the project volume studies PVAT and PAV. - * - * Specifically, sets the anchor time to the default anchor time if it's left blank. - * - * @param {CIQ.ChartEngine} stx The chart object. - * @param {string} type Study type. - * @param {object} inputs Study inputs. - * @param {object} outputs Study outputs. - * @param {object} parameters Study parameters. - * @param {string} panel ID of the study's panel element. - * @return {studyDescriptor} Study descriptor object. - * - * @memberof CIQ.Studies - * @private - * @since 8.1.0 - */ - CIQ.Studies.initProjectedVolume = function ( - stx, - type, - inputs, - outputs, - parameters, - panel - ) { - const { market } = stx.chart; - let anchorTime = "00:00"; - if (market) anchorTime = market.getNormalOpen(); - if (anchorTime.match(/^[\d]{2}:[\d]{2}$/)) anchorTime += ":00"; - - if (!inputs["Anchor Time"] || !inputs["Anchor Time"].length) { - inputs["Anchor Time"] = anchorTime; - } - - const sd = CIQ.Studies.initializeFN( - stx, - type, - inputs, - outputs, - parameters, - panel - ); - - // market will not be fully loaded yet if currentlyImporting - if (!stx.currentlyImporting) sd.defaultAnchorTime = anchorTime; - return sd; - }; - - /** - * Determines whether a projected volume lookback is valid for the currently selected - * periodicity. - * - * Called by {@link CIQ.Studies.calculateProjectedVolume}. - * - * Due to the data requirements of the Projected Volume at Time (PVAT) and Projected - * Aggregate Volume (PVA) studies, it is necessary to limit the maximum lookback. - * - * Setting the lookback too high results in the chart attempting to load more data than is - * allowed by {@link CIQ.ChartEngine#maxDataSetSize}, which breaks the study. If you have set - * `maxDataSetSize` higher than the default, you may wish to replace this validation function - * with one that allows a greater lookback. - * - * @param {CIQ.ChartEngine} stx A reference to the chart object. - * @param {CIQ.Studies.StudyDescriptor} sd Specifies the study (PVAT or PAV) for which the lookback is - * validated. - * @return {boolean} True if the the lookback is valid; otherwise, false. - * - * @memberOf CIQ.Studies - * @since 8.0.0 - */ - CIQ.Studies.validateProjectedVolumeLookback = function (stx, sd) { - const { interval, periodicity } = stx.layout; - const { "Lookback Days": lookback } = sd.inputs; - return lookback / (interval * periodicity) <= 10; - }; - - /** - * Calculates the projections and aggregations for the Projected Volume at Time (PVAT) and - * Projected Aggregate Volume (PAV) studies. Due to the data requirements of the studies, - * this function may attempt to use the quote feed to fetch additional historical data. If no - * quote feed is available and not enough data has been loaded, the study displays an error. - * - * The studies support intraday periodicities of 1 minute and higher. Aggregations other than - * Heiken-Ashi are not supported. - * - * Only days when the market is open are included in the volume average. If the lookback - * includes days with restricted market hours, the non-open periods are ignored, producing an - * average with fewer data points. - * - * @param {CIQ.ChartEngine} stx A reference to the chart object. - * @param {CIQ.Studies.StudyDescriptor} sd Specifies the study (PVAT or PAV) for which the projected - * volume is calculated. - * - * @memberOf CIQ.Studies - * @since 8.0.0 - */ - CIQ.Studies.calculateProjectedVolume = function (stx, sd) { - const { interval, timeUnit, aggregationType } = stx.layout; - const { symbol, scroll, scrubbed: quotes, market } = stx.chart; - const aggregateVolume = sd.type === "PAV"; - const studyName = sd.study ? sd.study.name : sd.type; - - if (CIQ.ChartEngine.isDailyInterval(interval)) { - sd.error = `${studyName} is Intraday Only`; - } else if (timeUnit === "tick") { - sd.error = `Tick mode not supported for ${studyName}`; - } else if (timeUnit !== "minute") { - sd.error = `Sub-minute periodicities not supported for ${studyName}`; - } else if ( - !aggregationType || - !["ohlc", "heikinashi"].includes(aggregationType) - ) { - sd.error = `Aggregation type not supported for ${studyName}`; - } else if (!CIQ.Studies.validateProjectedVolumeLookback(stx, sd)) { - sd.error = `Selected lookback/periodicity combo not supported for ${studyName}`; - } - - if (sd.error) return; - - if (sd.inputs["Anchor Selector"]) CIQ.Studies.initAnchorHandle(stx, sd); - else CIQ.Studies.removeAnchorHandle(stx, sd); - - let defaultAnchor = market ? market.getNormalOpen() : "00:00"; - if (defaultAnchor.match(/^[\d]{2}:[\d]{2}$/)) defaultAnchor += ":00"; - if (!stx.currentlyImporting) { - if (!sd.defaultAnchorTime) { - sd.defaultAnchorTime = defaultAnchor; - } else if (defaultAnchor !== sd.defaultAnchorTime) { - sd.defaultAnchorTime = defaultAnchor; - sd.inputs["Anchor Time"] = defaultAnchor; - CIQ.Studies.repositionAnchor(stx, sd); - return; - } - } - - const { "Lookback Days": lookback, "Anchor Time": anchorTime } = sd.inputs; - const [anchorHour, anchorMinute, anchorSecond = 0] = anchorTime.split(":"); - const isForex = CIQ.getFn("Market.Symbology.isForexSymbol")(symbol); - - // Make sure to calculate far enough back for dependent studies with a period, eg moving average - const dependents = sd.getDependents(stx); - let additionalBarsRequired = 0; - let dependentsOutputMap = []; - - dependents.forEach(({ inputs, outputMap }) => { - if (inputs.Period) { - additionalBarsRequired = Math.max( - parseInt(inputs.Period), - additionalBarsRequired - ); - - dependentsOutputMap.push(...Object.keys(outputMap)); - } - }); - - sd.dependentsOutputMap = dependentsOutputMap; - - // Projection will frequently need more data than would normally be loaded into dataset. For this - // reason we start at the beginning of dataSegment. We calculate - // the projection based on the ticks forward of the left-hand edge of the chart - let beginProjectionFrom; - const todaysOpen = openingTick(quotes.length - 1, true); // starting at beginning of day simplifies logic - const lhsTick = Math.ceil(quotes.length - 1 - scroll); // analogous to dataSegment[0] - let earliestTick = openingTick(lhsTick - additionalBarsRequired); - if ( - isForex && - quotes[earliestTick] && - CIQ.dateToStr(quotes[earliestTick].DT, "HH:mm") !== defaultAnchor - ) { - earliestTick = openingTick(earliestTick - 1); // necessary due to midnight-bisected market session - } - - if ( - !isForex && // forex aggregations start at 5pm ET on the previous day so this optimization doesn't work - sd.startFrom > earliestTick && - quotes[earliestTick] && - quotes[earliestTick]["V " + sd.name] !== undefined && - dependentsOutputMap.every( - (key) => ![undefined, null].includes(quotes[earliestTick][key]) - ) && - todaysOpen !== false - ) { - beginProjectionFrom = todaysOpen; // aggregation performance - } else { - beginProjectionFrom = earliestTick; - } - - // Projection starting point to provide entire projection based on the screen width - const oldestRequired = wind(dateFromTick(earliestTick), lookback); - oldestRequired.setHours(0, 0, 0); // in case of dissimilar start times make sure full day is covered - // Oldest opening market time CURRENTLY available in the dataSet - const oldestOpen = openingTick(0, true); - // Earliest possible start date for the projection to work - const oldestPossible = - (oldestOpen || oldestOpen === 0) && // ensured to be either a tick or false - tickFromDate(wind(quotes[oldestOpen].DT, lookback, true)); - - if (quotes[0].DT > oldestRequired) { - if (stx.quoteDriver) { - stx.quoteDriver.extendHistoricalData({ from: oldestRequired }); - if (oldestPossible > 0) beginProjectionFrom = oldestPossible; - else return; - } else { - return (sd.error = `Not enough data to calculate ${studyName}`); - } - } - - if (beginProjectionFrom < 0 || beginProjectionFrom > quotes.length - 1) - return; - - const appendingOnly = - quotes.length - sd.startFrom === 1 && - sd.cachedFutureTicks && - sd.cachedLastProjection && - +sd.cachedLastProjection.DT === +quotes[quotes.length - 1].DT && - quotes[beginProjectionFrom]["PV " + sd.name]; - - if (appendingOnly) { - quotes[quotes.length - 1]["PV " + sd.name] = - sd.cachedLastProjection.projectedValue; - sd.appendFutureTicks(stx, sd.cachedFutureTicks); - beginProjectionFrom = sd.startFrom; - } else { - sd.cachedFutureTicks = null; - sd.cachedLastProjection = null; - - // Given a standard ohlc or heikin ashi chart, the quotes array will be organized into time slices - // where trading occured, eg 9:30am-10:00am for a 30 minute periodicity. The objective of the following - // algorithm is to generate a moving average for the volume of each time slice, that is each quote - // should receive the calculated average volume of the last X number of days *for that time slice* where - // X is the a lookback variable set by the user. - - // The core of the algorithm works by assigning pointers to the start of the current day AND the previous - // "lookback" days and then simultaneously walking all pointers along the quotes array, calculating the - // average for each time slice as we go. If we reach the end of the quotes array and there are still - // remaining market hours we continue walking the "lookback" pointers appending future ticks as we go. - // This process is repeated for each day, moving backwards along the quotes array until we've calculated - // the projection for every day after the `beginProjectionFrom` index. - - // There is a big gotcha to this approach: not all trading days have the same hours. When that is the case - // we do the best we can and use as many "lookback" time slices as we can. In some cases this means calculating - // the average based off of fewer time slices. For example, if we are looking at the 8:00pm-8:30pm time - // slice for a FOREX instrument, there will be no data from any Fridays in the lookback because FOREX - // trading stops at 4pm on Friday. Saturday will be skipped entirely and not included in the lookback - // because it is not a market day. - - // Note that the algorithm uses two pointer arrays: `startingIndices` and `workingIndices`. `startingIndices` - // records the first tick of the day for each day in the lookback. `workingIndices` records the indices - // as we walk through the time slices of the days. They are separate so that when we calculate the projection - // for the previous day, we can simply shift `startingIndices` back a day and use the last index as the new - // pointer for the day to fill. - - // We will immediately pop `todaysOpen` off `startingIndices`. We add it here to start to simplify the loop, - // so that for each day we can pop the last index and the remaining indices will be the for the lookback days. - let startingIndices = [todaysOpen]; - let futureTicks = []; - - // grab the start index of the previous lookback days - for (let i = 0; i < lookback; i++) { - // First item points to first quote of day. Use previous so `openingTick` will get the correct day. - let previous = openingTick(startingIndices[0] - 1); - startingIndices.unshift(previous); // store with "older" days first so we can pop the newest - } - - // Whether on the first or subsequent iterations of this loop, we can expect `startingIndices` to contain - // lookback + 1 elements, the last item being the day being projected (which becomes the fill index). Due to - // zero indexing, `startingIndices[lookback]` will be the last item. The last iteration of the loop will be when - // we're projecting the "oldest" day that begins after or on `beginProjectionFrom`. - while (startingIndices[lookback] >= beginProjectionFrom) { - let fillIndex = startingIndices.pop(); - if (!quotes[fillIndex]) return reportTickErrorAt(fillIndex); - const fillStart = getHoursAndMinutes(quotes[fillIndex].DT); - let { hours: fillHours, minutes: fillMinutes } = fillStart; - let currentClose = market.getClose(quotes[fillIndex].DT); - let fillClose; - if (!currentClose) { - // if no market definiton default to 24 hour chart - fillClose = { hours: 24, minutes: 0 }; - } else { - let nextClose = market.getNextClose(quotes[fillIndex].DT); - fillClose = getHoursAndMinutes(currentClose); - // For extended hours. Find last close of the day. Don't roll over into next day (if FOREX). - while ( - !(fillClose.hours === 0 && fillClose.minutes === 0) && - currentClose.getDate() === nextClose.getDate() - ) { - currentClose = nextClose; - nextClose = market.getNextClose(nextClose); - } - fillClose = getHoursAndMinutes(currentClose); - // FOREX support. Because FOREX days end at midnight, this will come back as 0 hours, 0 minutes, which - // messes up the later/earlier than calculations - if (fillClose.hours === 0) fillClose.hours = 24; - } - - let workingIndices = startingIndices.slice(); - // ensure that none of the working index times start before the fill time - for (let i = 0; i < workingIndices.length; i++) { - let index = workingIndices[i]; - if (!quotes[index]) return reportTickErrorAt(index); - let { hours, minutes } = getHoursAndMinutes(quotes[index].DT); - - // If the date pointed to by index is earlier than the fillStart, increment until they are the same time - if ( - hours < fillHours || - (hours === fillHours && minutes < fillMinutes) - ) { - do { - index++; - ({ hours, minutes } = getHoursAndMinutes(quotes[index].DT)); - } while (!(hours === fillHours && minutes === fillMinutes)); - } - workingIndices[i] = index; - } - - // This loop runs once for each time slice for each day that needs a projection. On each iteration fillHours - // and fillMinutes will be incremented. Either the loop ends when we hit the market close or the end of the - // day or none of the lookback days contain anymore day we'll break out of the loop. - while ( - fillHours < fillClose.hours || - (fillHours === fillClose.hours && fillMinutes < fillClose.minutes) - ) { - // Because we may be appending future ticks we can't rely on checking the date of the fill quote to make - // sure we haven't exceded the market hours. So for that reason we increment fillHours and fillMinutes - // to the next time slice each iteration of the loop based off of time slices of the lookback days. But - // we only need to do this once, so we set a flag here to avoid re-setting those values potentially - // for *every single* lookback day. - let timeIncremented = false; - // Because we still need to make comparisons off of fillHours and fillMinutes, we store the new values - // in nextHours and nextMinutes until we're finished looping through the lookbacks. - let nextHours, nextMinutes; - let total = 0; - let historicalSlices = 0; - - // Loop calculates the average for the time slice under consideration. Because we expect some market days - // may have longer hours than others, for each lookback time slice we check that incrementing the index - // hasn't rolled the date over into the next day (which will happen after market close). If that happens, - // we assign the index to null and ignore it for future time slices. - for (let i = 0; i < workingIndices.length; i++) { - let index = workingIndices[i]; - if (index === null) continue; - let quote = quotes[index]; - if (!quote) return reportTickErrorAt(index); - let { hours, minutes } = getHoursAndMinutes(quote.DT); - let startDate = quote.DT.getDate(); // to check if index has rolled into next day - - if (hours === fillHours && minutes === fillMinutes) { - total += quote.Volume; - historicalSlices++; // if here time slice applies so make sure we caculate average correctly - workingIndices[i]++; // go to next time slice - if (quotes[workingIndices[i]].DT.getDate() !== startDate) { - // if index has rolled over into the next day - workingIndices[i] = null; - } else if (!timeIncremented) { - ({ - hours: nextHours, - minutes: nextMinutes - } = getHoursAndMinutes(quotes[workingIndices[i]].DT)); // walk fill minutes and hours forward - timeIncremented = true; // once set once we don't need to set again - } - } - } - - fillHours = nextHours; - fillMinutes = nextMinutes; - - if (historicalSlices === 0) break; // No more data available from lookback days, can't continue projection. - let projection = total / historicalSlices; - - if (quotes[fillIndex]) { - quotes[fillIndex]["PV " + sd.name] = projection; - } else { - futureTicks.push({ ["PV " + sd.name]: projection }); - } - fillIndex++; - } - startingIndices.unshift(openingTick(startingIndices[0] - 1)); // add new, older lookback day - } - - sd.cachedLastProjection = { - DT: quotes[quotes.length - 1].DT, - projectedValue: quotes[quotes.length - 1]["PV " + sd.name] - }; - sd.cachedFutureTicks = futureTicks; - sd.appendFutureTicks(stx, futureTicks); - } - - let marketOffset = null; - let volume = 0; - let projectedVolume = 0; - let lastPastTick; // record for caching - - // so we don't need to recalculate aggregation for entire day - if (appendingOnly && aggregateVolume) { - while (beginProjectionFrom > 0) { - var prevVolume = quotes[beginProjectionFrom - 1]["V " + sd.name]; - if (prevVolume || prevVolume === 0) { - volume = prevVolume; - break; - } - beginProjectionFrom--; - } - } - - for (let i = beginProjectionFrom; i < quotes.length; i++) { - const quote = quotes[i]; - const quoteVolume = quote.Volume; - const projectedQuoteVolume = quote["PV " + sd.name]; - - if (!quote.futureTick) lastPastTick = i; - - if (marketOffset === null) { - //possible new daily period - marketOffset = CIQ.Studies.getMarketOffset({ - stx, - localQuoteDate: quotes[i].DT, - shiftToDateBoundary: true - }); - } - - const currentTime = new Date(new Date(quote.DT).getTime() + marketOffset); - const prevTime = - quotes[i - 1] && - new Date(new Date(quotes[i - 1].DT).getTime() + marketOffset); - - let anchor = new timezoneJS.Date( - quote.DT, - market.market_def.market_tz || "America/New_York" - ); - anchor.setHours(anchorHour, anchorMinute, anchorSecond); - anchor = new Date(anchor + marketOffset); - - // ensure that the anchor time "rolls over" to the same day as the current time - anchor.setDate(currentTime.getDate()); - - // A new day is a new period, even for FOREX thanks to marketOffset - if (prevTime && currentTime.getDate() !== prevTime.getDate()) { - marketOffset = null; - volume = 0; - projectedVolume = 0; - } - - if (currentTime < anchor) { - quote["V " + sd.name] = 0; - quote["PV " + sd.name] = 0; - continue; - } - - if (aggregateVolume) { - volume += quoteVolume; - projectedVolume += projectedQuoteVolume; - } else { - volume = quoteVolume; - projectedVolume = projectedQuoteVolume; - } - - quote["V " + sd.name] = volume; - if (!appendingOnly) quote["PV " + sd.name] = projectedVolume; // if appending keep old value - - if ([NaN, null, undefined].includes(volume) && !quote.futureTick) { - sd.error = `${studyName} requires volume`; - return; - } - } - - // make sure to cache the projected value _after_ aggregation - sd.cachedLastProjection.projectedValue = - quotes[lastPastTick]["PV " + sd.name]; - - sd.outputMap = {}; - sd.outputMap["V " + sd.name] = ""; - sd.outputMap["PV " + sd.name] = "Average Line"; - - // Make sure dependent studies are loaded with the correct start date (if that date has changed - // and is no longer in sync with sd.startFrom) - dependents.forEach((dependent) => { - dependent.startFrom = beginProjectionFrom; - dependent.study.calculateFN(stx, dependent); - }); - - function reportTickErrorAt(index) { - console.error( - `Expected data for ${dateFromTick( - index - ).toDateString()} but found none. This may be caused by gaps in your data or an improperly configured market definition.` - ); - } - - function getHoursAndMinutes(date) { - return { - hours: date.getHours(), - minutes: date.getMinutes() - }; - } - - function wind(date, days, forward) { - while (days) { - date = new Date( - new Date(date).setDate(date.getDate() + (forward ? 1 : -1)) - ); - if (market.isMarketDate(date)) days--; - } - return date; - } - - function tickFromDate(date) { - return stx.tickFromDate(date, null, null, true, "scrubbed"); - } - - function dateFromTick(tick) { - return stx.dateFromTick(tick, null, true, "scrubbed"); - } - - // Used if no market definition. Returns the previous midnight of a date, shifted by the market offset - function defaultOpen(date) { - date.setHours(0); - date.setMinutes(0); - let marketOffset = CIQ.Studies.getMarketOffset({ - stx, - localQuoteDate: date - }); - return new Date(date.getTime() + marketOffset); - } - - // Returns the index for the tick of the market open of the day indicated by the index argument - // if `ensureInSource` is true will try to find the oldest open in the data - function openingTick(index, ensureInSource) { - let date = dateFromTick(index); - let marketOpen = market.getOpen(date) || defaultOpen(date); - let tick = tickFromDate(marketOpen); - if (!ensureInSource) return tick; // value may be outside the bounds of quotes array - if (tick < 0) tick = tickFromDate(wind(marketOpen, 1, true)); // try to find oldest open _in_ the data - if (tick >= quotes.length) return false; // if no open in data indicate so - return tick; - } - }; - - /** - * Displays the Projected Volume at Time (PVAT) and Projected Aggregate Volume (PAV) studies. - * - * @param {CIQ.ChartEngine} stx A reference to the chart object. - * @param {CIQ.Studies.StudyDescriptor} sd Specifies the study (PVAT or PAV) to be displayed. - * @param {array} quotes An array of quotes from which the study is constructed. - * - * @memberOf CIQ.Studies - * @since 8.0.0 - */ - CIQ.Studies.displayProjectedVolume = function (stx, sd, quotes) { - if (sd.error) return CIQ.Studies.removeAnchorHandle(stx, sd); - const { "Alert Threshold": threshold = "" } = sd.inputs; // default: "+50%" - const alertPercent = parseInt(threshold.slice(0, -1), 10) / 100; - let alertColor = sd.outputs["Alert Bar"]; - if (typeof alertColor === "object") alertColor = alertColor.color; - sd.volumeField = "V " + sd.name; - sd.alignStepToSide = true; - sd.extendToEndOfLastBar = true; - sd.lineWidth = 2; - - const opacityUp = stx.canvasStyle("stx_volume_underlay_up").opacity; - const opacityDown = stx.canvasStyle("stx_volume_underlay_down").opacity; - - sd.colorFunction = function (quote) { - const { Open, Close, iqPrevClose } = quote; - const comp = stx.colorByCandleDirection ? Open : iqPrevClose; - const closeDown = comp > Close; - const projectedVolume = quote["PV " + sd.name]; - const volume = quote["V " + sd.name]; - const alertChange = projectedVolume * (alertPercent + 1); - const shouldAlert = - alertPercent < 0 ? volume < alertChange : volume > alertChange; - - return { - fill_color: - (shouldAlert && alertColor) || - (closeDown ? this.fill_color_down : this.fill_color_up), - border_color: closeDown ? this.border_color_down : this.border_color_up, - opacity: shouldAlert ? 1 : closeDown ? opacityDown : opacityUp, - border_opacity: closeDown ? opacityDown : opacityUp - }; - }; - - const studyName = sd.study ? sd.study.name : sd.type; - const { loadingMore } = stx.chart; - const someData = quotes.some( - (quote) => quote && quote[sd.volumeField] && quote["PV " + sd.name] - ); - const needsMore = - quotes[0] && - !quotes[0].futureTick && - (quotes[0]["PV " + sd.name] === undefined || - (sd.dependentsOutputMap || []).some((key) => - [undefined, null].includes(quotes[0][key]) - )); - - if (!someData && loadingMore) { - return (sd.error = `Fetching data for ${studyName}`); - } - - CIQ.Studies.createVolumeChart(stx, sd, quotes); - CIQ.Studies.displaySeriesAsLine(stx, sd, quotes); - if (sd.anchorHandle) { - CIQ.Studies.displayAnchorHandleAndLine(stx, sd, quotes); - } - - if (needsMore) CIQ.Studies.calculateProjectedVolume(stx, sd); - }; - - CIQ.Studies.studyLibrary = CIQ.extend(CIQ.Studies.studyLibrary, { - PVAT: { - name: "Projected Volume at Time", - range: "0 to max", - yAxis: { ground: true, initialMarginTop: 0, zoom: 0 }, - calculateFN: CIQ.Studies.calculateProjectedVolume, - seriesFN: CIQ.Studies.displayProjectedVolume, - initializeFN: CIQ.Studies.initProjectedVolume, - removeFN: CIQ.Studies.removeAnchorHandle, - inputs: { - "Lookback Days": 10, - "Anchor Time": "", - "Alert Threshold": [ - "+150%", - "+125%", - "+100%", - "+75%", - "+50%", - "+25%", - "None", - "-25%", - "-50%", - "-75%", - "-100%", - "-125%", - "-150%" - ], - "Anchor Selector": true - }, - outputs: { - "Average Line": "#fe641c", - "Alert Bar": "#cfbd0e", - "Up Volume": "#8cc176", - "Down Volume": "#b82c0c" - }, - parameters: { - plotType: "step" - }, - attributes: { - "Anchor Time": { placeholder: "hh:mm:ss", step: 1 }, - "Alert Threshold": { defaultSelected: "+50%" } - } - }, - PAV: { - name: "Projected Aggregate Volume", - range: "0 to max", - yAxis: { ground: true, initialMarginTop: 0, zoom: 0 }, - calculateFN: CIQ.Studies.calculateProjectedVolume, - seriesFN: CIQ.Studies.displayProjectedVolume, - initializeFN: CIQ.Studies.initProjectedVolume, - removeFN: CIQ.Studies.removeAnchorHandle, - inputs: { - "Lookback Days": 10, - "Anchor Time": "", - "Anchor Selector": true - }, - outputs: { - "Average Line": "#fe641c", - "Up Volume": "#8cc176", - "Down Volume": "#b82c0c" - }, - parameters: { - plotType: "step" - }, - attributes: { - "Anchor Time": { placeholder: "hh:mm:ss", step: 1 } - } - } - }); -} - -}; - - -let __js_advanced_studies_psychologicalLine_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -if (!CIQ.Studies) { - console.error( - "psychologicalLine feature requires first activating studies feature." - ); -} else { - CIQ.Studies.calculatePsychologicalLine = function (stx, sd) { - var quotes = sd.chart.scrubbed; - if (quotes.length < sd.days + 1) { - sd.error = true; - return; - } - var array = []; - var increment = 100 / sd.days; - var accum = 0; - for (var i = Math.max(sd.startFrom - sd.days, 1); i < quotes.length; i++) { - if (quotes[i].futureTick) break; - var up = Number(quotes[i].Close > quotes[i - 1].Close); - if (up) accum += increment; - array.push(up); - if (array.length > sd.days) accum -= array.shift() * increment; - if (i < sd.startFrom) continue; - if (!isNaN(quotes[i].Close)) quotes[i]["Result " + sd.name] = accum; - } - }; - - CIQ.Studies.studyLibrary = CIQ.extend(CIQ.Studies.studyLibrary, { - PSY: { - name: "Psychological Line", - range: "0 to 100", - calculateFN: CIQ.Studies.calculatePsychologicalLine, - inputs: { Period: 20 } - } - }); -} - -}; - - -let __js_advanced_studies_qstick_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -if (!CIQ.Studies) { - console.error("qstick feature requires first activating studies feature."); -} else { - CIQ.Studies.calculateQStick = function (stx, sd) { - var quotes = sd.chart.scrubbed; - if (quotes.length < sd.days + 1) { - sd.error = true; - return; - } - for (var i = sd.startFrom; i < quotes.length; i++) { - quotes[i]["_Close-Open " + sd.name] = quotes[i].Close - quotes[i].Open; - } - CIQ.Studies.MA( - sd.inputs["Moving Average Type"], - sd.days, - "_Close-Open " + sd.name, - 0, - "Result", - stx, - sd - ); - }; - - CIQ.Studies.studyLibrary = CIQ.extend(CIQ.Studies.studyLibrary, { - QStick: { - name: "QStick", - calculateFN: CIQ.Studies.calculateQStick, - inputs: { Period: 8, "Moving Average Type": "ma" } - } - }); -} - -}; - - -let __js_advanced_studies_rainbow_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -if (!CIQ.Studies) { - console.error("rainbow feature requires first activating studies feature."); -} else { - CIQ.Studies.calculateRainbow = function (stx, sd) { - var quotes = sd.chart.scrubbed; - if (quotes.length < sd.days + 1) { - sd.error = true; - return; - } - var field = sd.inputs.Field; - if (!field || field == "field") field = "Close"; - - function getLLVHHV(p, x) { - var h = Number.MAX_VALUE * -1, - l = Number.MAX_VALUE; - for (var j = x - p + 1; j <= x; j++) { - if (j < 0) continue; - h = Math.max(h, quotes[j].Close); - l = Math.min(l, quotes[j].Close); - } - return [l, h]; - } - - var f = field; - for (var j = 1; j <= 10; j++) { - CIQ.Studies.MA("simple", sd.days, f, 0, "SMA" + j, stx, sd); - f = "SMA" + j + " " + sd.name; - } - - for (var i = Math.max(sd.startFrom, 10); i < quotes.length; i++) { - if (!quotes[i]) continue; - if (quotes[i].futureTick) break; - var accum = 0, - count = 0, - max = Number.MAX_VALUE * -1, - min = Number.MAX_VALUE; - for (j = 1; j <= 10; j++) { - var q = quotes[i]["SMA" + j + " " + sd.name]; - if (q || q === 0) { - accum += q; - count++; - max = Math.max(max, q); - min = Math.min(min, q); - } - } - if (sd.name.indexOf("Osc") > -1) { - var lh = getLLVHHV(sd.inputs["HHV/LLV Lookback"], i); - if (count) { - quotes[i][sd.name + "_hist"] = - (100 * (quotes[i][field] - accum / count)) / - Math.max(0.000001, lh[1] - lh[0]); - quotes[i]["Over " + sd.name] = - (100 * (max - min)) / Math.max(0.000001, lh[1] - lh[0]); - quotes[i]["Under " + sd.name] = -quotes[i]["Over " + sd.name]; - quotes[i]["Zero " + sd.name] = 0; - } - } - } - if (sd.name.indexOf("Osc") > -1) { - sd.outputMap = {}; - sd.outputMap["Over " + sd.name] = "Positive Bar"; - sd.outputMap["Under " + sd.name] = "Negative Bar"; - sd.outputMap["Zero " + sd.name] = ""; - sd.outputMap[sd.name + "_hist"] = ""; - } - }; - - CIQ.Studies.displayRainbowMA = function (stx, sd, quotes) { - var panel = stx.panels[sd.panel]; - //just need to display in reverse order from outputMap - for (var i = 10; i > 0; i--) { - CIQ.Studies.displayIndividualSeriesAsLine( - stx, - sd, - panel, - "SMA" + i + " " + sd.name, - quotes - ); - } - }; - - CIQ.Studies.displayRainbowOsc = function (stx, sd, quotes) { - CIQ.Studies.displaySeriesAsLine(stx, sd, quotes); - var panel = stx.panels[sd.panel], - context = sd.getContext(stx); - var yAxis = sd.getYAxis(stx); - - stx.startClip(sd.panel); - if (!sd.highlight && stx.highlightedDraggable) context.globalAlpha *= 0.3; - var y = stx.pixelFromPrice(0, panel, yAxis); - var skipTransform = panel.name != sd.chart.name; - - var upColor = CIQ.Studies.determineColor(sd.outputs["Positive Bar"]); - context.strokeStyle = upColor; - stx.plotDataSegmentAsLine("Over " + sd.name, panel, { - skipTransform: skipTransform, - label: false, - yAxis: yAxis - }); - - var upgradient = context.createLinearGradient( - 0, - y, - 0, - yAxis.flipped ? yAxis.bottom : yAxis.top - ); - upgradient.addColorStop(0, stx.containerColor); - upgradient.addColorStop(1, upColor); - CIQ.prepareChannelFill(stx, { - skipTransform: skipTransform, - color: upgradient, - opacity: !sd.highlight && stx.highlightedDraggable ? 0.3 : 1, - panelName: sd.panel, - topBand: "Over " + sd.name, - bottomBand: "Zero " + sd.name, - yAxis: yAxis - }); - - var downColor = CIQ.Studies.determineColor(sd.outputs["Negative Bar"]); - context.strokeStyle = downColor; - stx.plotDataSegmentAsLine("Under " + sd.name, panel, { - skipTransform: skipTransform, - label: false, - yAxis: yAxis - }); - - var dngradient = context.createLinearGradient( - 0, - y, - 0, - yAxis.flipped ? yAxis.top : yAxis.bottom - ); - dngradient.addColorStop(0, stx.containerColor); - dngradient.addColorStop(1, downColor); - CIQ.prepareChannelFill(stx, { - skipTransform: skipTransform, - color: dngradient, - opacity: !sd.highlight && stx.highlightedDraggable ? 0.3 : 1, - panelName: sd.panel, - topBand: "Zero " + sd.name, - bottomBand: "Under " + sd.name, - yAxis: yAxis - }); - - var myWidth = stx.layout.candleWidth - 2; - if (myWidth < 2) myWidth = 1; - - stx.canvasColor("stx_histogram"); - if (!sd.underlay) context.globalAlpha = 1; - if (!sd.highlight && stx.highlightedDraggable) context.globalAlpha *= 0.3; - context.fillStyle = "#CCCCCC"; - for (var i = 0; i < quotes.length; i++) { - var quote = quotes[i]; - if (!quote) continue; - if (quote[sd.name + "_hist"] > 0) context.fillStyle = upColor; - else if (quote[sd.name + "_hist"] < 0) context.fillStyle = downColor; - if (quote.candleWidth) - myWidth = Math.floor(Math.max(1, quote.candleWidth - 2)); - context.fillRect( - Math.floor(stx.pixelFromBar(i, panel.chart) - myWidth / 2), - Math.floor(y), - Math.floor(myWidth), - Math.floor( - stx.pixelFromPrice(quote[sd.name + "_hist"], panel, yAxis) - y - ) - ); - } - stx.endClip(); - }; - - CIQ.Studies.studyLibrary = CIQ.extend(CIQ.Studies.studyLibrary, { - "Rainbow MA": { - name: "Rainbow Moving Average", - overlay: true, - calculateFN: CIQ.Studies.calculateRainbow, - seriesFN: CIQ.Studies.displayRainbowMA, - inputs: { Period: 2, Field: "field" }, - outputs: { - SMA1: "#FF0000", - SMA2: "#FF7F00", - SMA3: "#FFFF00", - SMA4: "#7FFF00", - SMA5: "#00FF7F", - SMA6: "#00FFFF", - SMA7: "#007FFF", - SMA8: "#0000FF", - SMA9: "#7F00FF", - SMA10: "#FF00FF" - } - }, - "Rainbow Osc": { - name: "Rainbow Oscillator", - calculateFN: CIQ.Studies.calculateRainbow, - seriesFN: CIQ.Studies.displayRainbowOsc, - centerline: 0, - inputs: { Period: 2, Field: "field", "HHV/LLV Lookback": 10 }, - outputs: { "Positive Bar": "#00DD00", "Negative Bar": "#FF0000" } - } - }); -} - -}; - - -let __js_advanced_studies_randomWalk_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -if (!CIQ.Studies) { - console.error( - "randomWalk feature requires first activating studies feature." - ); -} else { - CIQ.Studies.calculateRandomWalk = function (stx, sd) { - var quotes = sd.chart.scrubbed; - if (quotes.length < sd.days + 1) { - sd.error = true; - return; - } - - for (var i = Math.max(2, sd.startFrom); i < quotes.length; i++) { - var ttr = 0; - var high = quotes[i].High; - var low = quotes[i].Low; - var maxHigh = 0; - var maxLow = 0; - for (var j = 1; j <= sd.days; j++) { - if (quotes[i].futureTick) break; - if (i <= j) { - maxHigh = maxLow = 0; - break; - } - ttr += quotes[i - j].trueRange; - var denom = (ttr / j) * Math.sqrt(j); - if (denom) { - // skip if denominator is 0 -- - var cH = (high - quotes[i - j].Low) / denom; - var cL = (quotes[i - j].High - low) / denom; - maxHigh = Math.max(maxHigh, cH); - maxLow = Math.max(maxLow, cL); - } - } - if (!quotes[i].futureTick && (!isNaN(high) || !isNaN(low))) { - quotes[i]["Random Walk High " + sd.name] = maxHigh; - quotes[i]["Random Walk Low " + sd.name] = maxLow; - } - } - }; - - CIQ.Studies.studyLibrary = CIQ.extend(CIQ.Studies.studyLibrary, { - "Random Walk": { - name: "Random Walk Index", - calculateFN: CIQ.Studies.calculateRandomWalk, - outputs: { "Random Walk High": "#FF0000", "Random Walk Low": "#0000FF" } - } - }); -} - -}; - - -let __js_advanced_studies_relativeVigor_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -if (!CIQ.Studies) { - console.error( - "relativeVigor feature requires first activating studies feature." - ); -} else { - CIQ.Studies.calculateRelativeVigor = function (stx, sd) { - var quotes = sd.chart.scrubbed; - if (quotes.length < sd.days + 1) { - sd.error = true; - return; - } - var i; - for (i = sd.startFrom; i < quotes.length; i++) { - var qt = quotes[i]; - if (!isNaN(qt.Close) && !isNaN(qt.Open)) - qt["_Change " + sd.name] = qt.Close - qt.Open; - if (!isNaN(qt.High) && !isNaN(qt.Low)) - qt["_Range " + sd.name] = qt.High - qt.Low; - } - - CIQ.Studies.MA("triangular", 4, "_Change " + sd.name, 0, "_Numer", stx, sd); - CIQ.Studies.MA("triangular", 4, "_Range " + sd.name, 0, "_Denom", stx, sd); - - var nums = []; - var dens = []; - for (i = Math.max(sd.startFrom - sd.days, 0); i < quotes.length; i++) { - if (quotes[i].futureTick) break; - if ( - quotes[i]["_Numer " + sd.name] === null && - quotes[i]["_Denom " + sd.name] === null - ) - continue; - nums.push(quotes[i]["_Numer " + sd.name]); - dens.push(quotes[i]["_Denom " + sd.name]); - if (nums.length > sd.days) { - nums.shift(); - dens.shift(); - } - var sumNum = 0; - var sumDen = 0; - var it; - for (it = 0; it < nums.length; it++) { - sumNum += nums[it]; - } - for (it = 0; it < dens.length; it++) { - sumDen += dens[it]; - } - if (sumDen === 0) sumDen = 0.00000001; - if (i < sd.startFrom) continue; - quotes[i]["Rel Vig " + sd.name] = sumNum / sumDen; - } - - CIQ.Studies.MA( - "triangular", - 4, - "Rel Vig " + sd.name, - 0, - "RelVigSignal", - stx, - sd - ); - - for (i = sd.startFrom; i < quotes.length; i++) { - quotes[i][sd.name + "_hist"] = - quotes[i]["Rel Vig " + sd.name] - quotes[i]["RelVigSignal " + sd.name]; - } - //Don't clear outputMap - sd.outputMap[sd.name + "_hist"] = ""; - }; - - CIQ.Studies.studyLibrary = CIQ.extend(CIQ.Studies.studyLibrary, { - "Rel Vig": { - name: "Relative Vigor Index", - seriesFN: CIQ.Studies.displayHistogramWithSeries, - calculateFN: CIQ.Studies.calculateRelativeVigor, - inputs: { Period: 10 }, - outputs: { - "Rel Vig": "auto", - RelVigSignal: "#FF0000", - "Increasing Bar": "#00DD00", - "Decreasing Bar": "#FF0000" - } - } - }); -} - -}; - - -let __js_advanced_studies_rsi_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -if (!CIQ.Studies) { - console.error("rsi feature requires first activating studies feature."); -} else { - /** - * Default study calculation function for RSI study. - * - * The resulting values will be added to the dataSet using the field name provided by the `sd.outputMap` entry. - * - * **Notes:** - * - This function calculates a single value, so it expects `sd.outputMap` to contain a single mapping. - * - If no `outputs` object is defined in the library entry, the study will default to a single output named `Result`, which will then be used in lieu of `sd.outputs` to build the field name. - * - The study name may contain the unprintable character `‌`, see {@link studyDescriptor} documentation. - * - * @param {CIQ.ChartEngine} stx A chart engine instance - * @param {CIQ.Studies.StudyDescriptor} sd A study descriptor - * @memberOf CIQ.Studies - * @since 6.3.0 RSI can now be calculated on any field instead of just "Close". - */ - CIQ.Studies.calculateRSI = function (stx, sd) { - var quotes = sd.chart.scrubbed; - var field = sd.inputs.Field; - if (!field || field == "field") field = "Close"; - - function computeRSI(avgGain, avgLoss) { - if (avgLoss === 0) return 100; - var rs = avgGain / avgLoss; - return 100 - 100 / (1 + rs); - } - if (quotes.length < sd.days + 1) { - sd.error = true; - return; - } - for (var i = sd.startFrom; i < quotes.length; i++) { - if (!i) continue; - var quote = quotes[i]; - var quote1 = quotes[i - 1]; - if (!quote[field] && quote[field] !== 0) continue; - if (!quote1[field] && quote1[field] !== 0) continue; - var change = quote[field] - quote1[field]; - var num = Math.min(i, sd.days); - - var avgGain = quote1["_avgG " + sd.name]; - if (!avgGain) avgGain = 0; - avgGain -= avgGain / num; - - var avgLoss = quote1["_avgL " + sd.name]; - if (!avgLoss) avgLoss = 0; - avgLoss -= avgLoss / num; - - if (change > 0) { - avgGain += change / num; - } else if (change <= 0) { - avgLoss -= change / num; - } else continue; - if (i >= sd.days) { - if ((avgGain || avgGain !== 0) && (avgLoss || avgLoss !== 0)) - quote["RSI " + sd.name] = computeRSI(avgGain, avgLoss); - } - //intermediates - quote["_avgG " + sd.name] = avgGain; - quote["_avgL " + sd.name] = avgLoss; - } - sd.zoneOutput = "RSI"; - }; - - CIQ.Studies.studyLibrary = CIQ.extend(CIQ.Studies.studyLibrary, { - rsi: { - name: "RSI", - inputs: { Period: 14, Field: "field" }, - calculateFN: CIQ.Studies.calculateRSI, - range: "0 to 100", - outputs: { RSI: "auto" }, - parameters: { - init: { - studyOverZonesEnabled: true, - studyOverBoughtValue: 80, - studyOverBoughtColor: "auto", - studyOverSoldValue: 20, - studyOverSoldColor: "auto" - } - } - } - }); -} - -}; - - -let __js_advanced_studies_schaffTrendCycle_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -if (!CIQ.Studies) { - console.error( - "schaffTrendCycle feature requires first activating studies feature." - ); -} else { - CIQ.Studies.calculateSchaff = function (stx, sd) { - var quotes = sd.chart.scrubbed; - var period = sd.days; - var shortCycle = Number(sd.inputs["Short Cycle"]); - var longCycle = Number(sd.inputs["Long Cycle"]); - if (quotes.length < Math.max(period, shortCycle, longCycle) + 1) { - sd.error = true; - return; - } - var field = sd.inputs.Field; - if (!field || field == "field") field = "Close"; - var factor = 0.5; - - CIQ.Studies.MA( - sd.inputs["Moving Average Type"], - shortCycle, - field, - 0, - "_MACD1", - stx, - sd - ); - CIQ.Studies.MA( - sd.inputs["Moving Average Type"], - longCycle, - field, - 0, - "_MACD2", - stx, - sd - ); - - function getLLVHHV(p, x, n) { - var l = null, - h = null; - for (var j = x - p + 1; j <= x; j++) { - var d = quotes[j][n + " " + sd.name]; - if (!d) continue; - l = l === null ? d : Math.min(l, d); - h = h === null ? d : Math.max(h, d); - } - return [l, h]; - } - var f1 = 0, - f2 = 0; - for (var i = sd.startFrom; i < quotes.length; i++) { - var quote = quotes[i]; - - if (i < longCycle - 1) continue; - var qMACD1 = quote["_MACD1 " + sd.name], - qMACD2 = quote["_MACD2 " + sd.name]; - if (qMACD1 || qMACD1 === 0 || qMACD2 || qMACD2 === 0) { - quote["_MACD " + sd.name] = qMACD1 - qMACD2; - } - var qMACD = quote["_MACD " + sd.name]; - - if (i < longCycle + (period - 1)) continue; - var lh = getLLVHHV(period, i, "_MACD"); - f1 = lh[1] > lh[0] ? (100 * (qMACD - lh[0])) / (lh[1] - lh[0]) : f1; - if (qMACD || qMACD === 0) { - quote["_PF " + sd.name] = quotes[i - 1]["_PF " + sd.name] - ? quotes[i - 1]["_PF " + sd.name] + - factor * (f1 - quotes[i - 1]["_PF " + sd.name]) - : f1; - } - var qPF = quote["_PF " + sd.name]; - if (i < longCycle + 2 * (period - 1)) continue; - lh = getLLVHHV(period, i, "_PF"); - f2 = lh[1] > lh[0] ? (100 * (qPF - lh[0])) / (lh[1] - lh[0]) : f2; - if (qPF || qPF === 0) { - quote["Result " + sd.name] = quotes[i - 1]["Result " + sd.name] - ? quotes[i - 1]["Result " + sd.name] + - factor * (f2 - quotes[i - 1]["Result " + sd.name]) - : f2; - } - } - }; - - CIQ.Studies.studyLibrary = CIQ.extend(CIQ.Studies.studyLibrary, { - Schaff: { - name: "Schaff Trend Cycle", - range: "0 to 100", - calculateFN: CIQ.Studies.calculateSchaff, - inputs: { - Period: 10, - Field: "field", - "Short Cycle": 23, - "Long Cycle": 50, - "Moving Average Type": "ema" - }, - parameters: { - init: { - studyOverZonesEnabled: true, - studyOverBoughtValue: 75, - studyOverBoughtColor: "auto", - studyOverSoldValue: 25, - studyOverSoldColor: "auto" - } - } - } - }); -} - -}; - - -let __js_advanced_studies_shinohara_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -if (!CIQ.Studies) { - console.error("shinohara feature requires first activating studies feature."); -} else { - CIQ.Studies.calculateShinohara = function (stx, sd) { - var quotes = sd.chart.scrubbed; - if (quotes.length < sd.days + 1) { - sd.error = true; - return; - } - var accums = { - weakNum: 0, - weakDen: 0, - strongNum: 0, - strongDen: 0 - }; - if (sd.startFrom > 1) { - accums = CIQ.clone(quotes[sd.startFrom - 1]["_accums " + sd.name]); - } - for (var i = sd.startFrom; i < quotes.length; i++) { - accums.weakNum += quotes[i].High - quotes[i].Close; - accums.weakDen += quotes[i].Close - quotes[i].Low; - if (i > 0) { - accums.strongNum += quotes[i].High - quotes[i - 1].Close; - accums.strongDen += quotes[i - 1].Close - quotes[i].Low; - } - if (i >= sd.days) { - accums.weakNum -= quotes[i - sd.days].High - quotes[i - sd.days].Close; - accums.weakDen -= quotes[i - sd.days].Close - quotes[i - sd.days].Low; - quotes[i]["Weak Ratio " + sd.name] = - (100 * accums.weakNum) / accums.weakDen; - if (i > sd.days) { - accums.strongNum -= - quotes[i - sd.days].High - quotes[i - sd.days - 1].Close; - accums.strongDen -= - quotes[i - sd.days - 1].Close - quotes[i - sd.days].Low; - quotes[i]["Strong Ratio " + sd.name] = - (100 * accums.strongNum) / accums.strongDen; - } - } - quotes[i]["_accums " + sd.name] = CIQ.clone(accums); - } - }; - - CIQ.Studies.studyLibrary = CIQ.extend(CIQ.Studies.studyLibrary, { - Shinohara: { - name: "Shinohara Intensity Ratio", - calculateFN: CIQ.Studies.calculateShinohara, - inputs: { Period: 26 }, - outputs: { "Strong Ratio": "#E99B54", "Weak Ratio": "#5F7CB8" } - } - }); -} - -}; - - -let __js_advanced_studies_stochastics_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -if (!CIQ.Studies) { - console.error( - "stochastics feature requires first activating studies feature." - ); -} else { - /** - * Calculate function for stochastics - * @param {CIQ.ChartEngine} stx Chart object - * @param {CIQ.Studies.StudyDescriptor} sd Study Descriptor - * @memberOf CIQ.Studies - */ - CIQ.Studies.calculateStochastics = function (stx, sd) { - if (!sd.smooth) sd.smooth = sd.inputs.Smooth; - var field = sd.inputs.Field; - if (!field || field == "field") field = "Close"; - - var fastPeriod = sd.inputs["%K Periods"]; - if (!fastPeriod) fastPeriod = sd.days; - - var quotes = sd.chart.scrubbed; - if (quotes.length < Math.max(fastPeriod, sd.days) + 1) { - sd.error = true; - return; - } - - var smoothingPeriod = sd.inputs["%K Smoothing Periods"]; - if (smoothingPeriod && !sd.inputs.Fast) sd.smooth = true; - else if (sd.smooth) smoothingPeriod = 3; - - var slowPeriod = sd.inputs["%D Periods"]; - if (!slowPeriod) slowPeriod = 3; - - function computeStochastics(position, field, days) { - var beg = position - days + 1; - var high = Number.MAX_VALUE * -1, - low = Number.MAX_VALUE; - for (var i = beg; i <= position; i++) { - var lowField = quotes[i][field == "Close" ? "Low" : field], - highField = quotes[i][field == "Close" ? "High" : field]; - if (!lowField && lowField !== 0) continue; - if (!highField && highField !== 0) continue; - low = Math.min(low, lowField); - high = Math.max(high, highField); - } - if (high == Number.MAX_VALUE * -1 || low == Number.MAX_VALUE) return null; - var k = - high == low - ? 0 - : ((quotes[position][field] - low) / (high - low)) * 100; - return k; - } - - if (sd.outputs.Fast) { - sd.outputMap = {}; - sd.outputMap["%K " + sd.name] = "Fast"; - sd.outputMap["%D " + sd.name] = "Slow"; - } - - for (var i = Math.max(fastPeriod, sd.startFrom); i < quotes.length; i++) { - var stoch = computeStochastics(i, field, fastPeriod); - if (stoch !== null) - quotes[i]["_Fast%K " + sd.name] = computeStochastics( - i, - field, - fastPeriod - ); - } - - CIQ.Studies.MA( - "simple", - sd.smooth ? smoothingPeriod : 1, - "_Fast%K " + sd.name, - 0, - "%K", - stx, - sd - ); - CIQ.Studies.MA("simple", slowPeriod, "%K " + sd.name, 0, "%D", stx, sd); - }; - - CIQ.Studies.calculateStochMomentum = function (stx, sd) { - var pKPeriods = Number(sd.inputs["%K Periods"]); - var pKSmoothPeriods = Number(sd.inputs["%K Smoothing Periods"]); - var pK2SmoothPeriods = Number(sd.inputs["%K Double Smoothing Periods"]); - var pDPeriods = Number(sd.inputs["%D Periods"]); - - var quotes = sd.chart.scrubbed; - if ( - quotes.length < pKPeriods + pKSmoothPeriods + pK2SmoothPeriods - 1 || - quotes.length < pDPeriods - ) { - sd.error = true; - return; - } - - function getLLVHHV(p, x) { - var l = null, - h = null; - for (var j = x - p + 1; j <= x; j++) { - l = l === null ? quotes[j].Low : Math.min(l, quotes[j].Low); - h = h === null ? quotes[j].High : Math.max(h, quotes[j].High); - } - return [l, h]; - } - - var i; - for (i = Math.max(pKPeriods, sd.startFrom) - 1; i < quotes.length; i++) { - var quote = quotes[i]; - var lh = getLLVHHV(pKPeriods, i); - quote["_H " + sd.name] = quote.Close - (lh[0] + lh[1]) / 2; - quote["_DHL " + sd.name] = lh[1] - lh[0]; - } - - CIQ.Studies.MA( - "exponential", - pKSmoothPeriods, - "_H " + sd.name, - 0, - "_HS1", - stx, - sd - ); - CIQ.Studies.MA( - "exponential", - pK2SmoothPeriods, - "_HS1 " + sd.name, - 0, - "_HS2", - stx, - sd - ); - CIQ.Studies.MA( - "exponential", - pKSmoothPeriods, - "_DHL " + sd.name, - 0, - "_DHL1", - stx, - sd - ); - CIQ.Studies.MA( - "exponential", - pK2SmoothPeriods, - "_DHL1 " + sd.name, - 0, - "_DHL2", - stx, - sd - ); - - for (i = pKPeriods - 1; i < quotes.length; i++) { - quotes[i]["%K " + sd.name] = - (quotes[i]["_HS2 " + sd.name] / (0.5 * quotes[i]["_DHL2 " + sd.name])) * - 100; - } - - CIQ.Studies.MA( - sd.inputs["%D Moving Average Type"], - pDPeriods, - "%K " + sd.name, - 0, - "%D", - stx, - sd - ); - - sd.zoneOutput = "%K"; - }; - - CIQ.Studies.studyLibrary = CIQ.extend(CIQ.Studies.studyLibrary, { - "Stch Mtm": { - name: "Stochastic Momentum Index", - calculateFN: CIQ.Studies.calculateStochMomentum, - inputs: { - "%K Periods": 10, - "%K Smoothing Periods": 3, - "%K Double Smoothing Periods": 3, - "%D Periods": 10, - "%D Moving Average Type": "ema" - }, - outputs: { "%K": "auto", "%D": "#FF0000" }, - parameters: { - init: { - studyOverZonesEnabled: true, - studyOverBoughtValue: 40, - studyOverBoughtColor: "auto", - studyOverSoldValue: -40, - studyOverSoldColor: "auto" - } - } - }, - stochastics: { - name: "Stochastics (Simple)", - range: "0 to 100", - calculateFN: CIQ.Studies.calculateStochastics, - inputs: { Period: 14, Field: "field", Smooth: true }, - outputs: { Fast: "auto", Slow: "#FF0000" }, - parameters: { - init: { - studyOverZonesEnabled: true, - studyOverBoughtValue: 80, - studyOverBoughtColor: "auto", - studyOverSoldValue: 20, - studyOverSoldColor: "auto" - } - } - }, - Stochastics: { - name: "Stochastics", - range: "0 to 100", - calculateFN: CIQ.Studies.calculateStochastics, - inputs: { - Field: "field", - "%K Periods": 14, - Fast: false, - "%K Smoothing Periods": 3, - "%D Periods": 3 - }, - outputs: { "%K": "auto", "%D": "#FF0000" }, - parameters: { - init: { - studyOverZonesEnabled: true, - studyOverBoughtValue: 80, - studyOverBoughtColor: "auto", - studyOverSoldValue: 20, - studyOverSoldColor: "auto" - } - }, - attributes: { - "%K Smoothing Periods": { - hidden: function () { - return this.inputs.Fast; - } - } - }, - centerline: 50 - } - }); -} - -}; - - -let __js_advanced_studies_supertrend_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -if (!CIQ.Studies) { - console.error( - "supertrend feature requires first activating studies feature." - ); -} else { - CIQ.Studies.calculateSupertrend = function (stx, sd) { - var quotes = sd.chart.scrubbed; - if (quotes.length < sd.days + 1) { - sd.error = true; - return; - } - CIQ.Studies.calculateStudyATR(stx, sd); - for (var i = sd.startFrom; i < quotes.length; i++) { - var quote = quotes[i]; - if (!quote) continue; - var median = (quote.High + quote.Low) / 2; - var factoredATR = sd.inputs.Multiplier * quote["ATR " + sd.name]; - var uptrend = median - factoredATR; - var downtrend = median + factoredATR; - if (i) { - if ( - quotes[i - 1] && - quotes[i - 1].Close && - quotes[i - 1].Close > quotes[i - 1]["_Uptrend " + sd.name] && - quotes[i - 1]["_Uptrend " + sd.name] > uptrend - ) - uptrend = quotes[i - 1]["_Uptrend " + sd.name]; - if ( - quotes[i - 1] && - quotes[i - 1].Close && - quotes[i - 1].Close < quotes[i - 1]["_Downtrend " + sd.name] && - quotes[i - 1]["_Downtrend " + sd.name] < downtrend - ) - downtrend = quotes[i - 1]["_Downtrend " + sd.name]; - } - quote["_Direction " + sd.name] = 1; - if (i) { - quote["_Direction " + sd.name] = quotes[i - 1]["_Direction " + sd.name]; - if (quote.Close > quotes[i - 1]["_Downtrend " + sd.name]) - quote["_Direction " + sd.name] = 1; - else if (quote.Close < quotes[i - 1]["_Uptrend " + sd.name]) - quote["_Direction " + sd.name] = -1; - } - quote["_Uptrend " + sd.name] = uptrend; - quote["_Downtrend " + sd.name] = downtrend; - quote["Trend " + sd.name] = - quote["_Direction " + sd.name] > 0 ? uptrend : downtrend; - if (!i) continue; - } - sd.outputMap = {}; - sd.outputMap["Trend " + sd.name] = ""; - }; - - CIQ.Studies.displaySupertrend = function (stx, sd, quotes) { - var panel = stx.panels[sd.panel], - context = sd.getContext(stx); - var yAxis = sd.getYAxis(stx); - function colorFunction(stx, quote, mode) { - if (quote && quote["_Direction " + sd.name] < 0) - return sd.outputs.Downtrend; - return sd.outputs.Uptrend; - } - var params = { - skipTransform: panel.name != sd.chart.name, - skipProjections: true, - label: stx.preferences.labels, - yAxis: yAxis, - highlight: sd.highlight - }; - - context.strokeStyle = colorFunction(stx, quotes[quotes.length - 1]); - context.lineWidth = 2; - if (sd.highlight) context.lineWidth = 1.5; // it will get doubled in plotDataSegmentAsLine - var trendName = "Trend " + sd.name; - for ( - var x = 0; - panel.chart.transformFunc && - yAxis != panel.chart.yAxis && - x < quotes.length; - x++ - ) { - var q = quotes[x]; - if (q && q.transform) { - q.transform[trendName] = panel.chart.transformFunc( - stx, - panel.chart, - q[trendName] - ); - } - } - stx.plotDataSegmentAsLine(trendName, panel, params, colorFunction); - context.lineWidth = 1; - context.globalAlpha = 1; - - stx.startClip(sd.panel); - if (!sd.highlight && stx.highlightedDraggable) context.globalAlpha *= 0.3; - var signalWidth = context.measureText("\u25B2").width / 2; - var i; - for (i = 0; i < quotes.length; i++) { - if (!quotes[i] || !quotes[i - 1]) continue; - if ( - quotes[i - 1]["_Direction " + sd.name] > - quotes[i]["_Direction " + sd.name] - ) { - context.fillStyle = sd.outputs.Downtrend; - context.textBaseline = "bottom"; - var yh = stx.pixelFromPrice(quotes[i].High, panel, yAxis); - for (var d = 5; d <= 45; d += 10) { - // down arrow - if (yAxis.flipped) - context.fillText( - "\u25B2", - stx.pixelFromBar(i) - signalWidth, - yh + d - ); - else - context.fillText( - "\u25BC", - stx.pixelFromBar(i) - signalWidth, - yh - d - ); - } - } else if ( - quotes[i - 1]["_Direction " + sd.name] < - quotes[i]["_Direction " + sd.name] - ) { - context.fillStyle = sd.outputs.Uptrend; - context.textBaseline = "top"; - var yl = stx.pixelFromPrice(quotes[i].Low, panel, yAxis); - for (var u = 5; u <= 45; u += 10) { - // up arrow - if (yAxis.flipped) - context.fillText( - "\u25BC", - stx.pixelFromBar(i) - signalWidth, - yl - u - ); - else - context.fillText( - "\u25B2", - stx.pixelFromBar(i) - signalWidth, - yl + u - ); - } - } - } - stx.endClip(); - }; - - CIQ.Studies.studyLibrary = CIQ.extend(CIQ.Studies.studyLibrary, { - Supertrend: { - name: "Supertrend", - overlay: true, - seriesFN: CIQ.Studies.displaySupertrend, - calculateFN: CIQ.Studies.calculateSupertrend, - inputs: { Period: 7, Multiplier: 3 }, - outputs: { Uptrend: "#8cc176", Downtrend: "#b82c0c" }, - attributes: { - Multiplier: { min: 0.1, step: 0.1 } - } - } - }); -} - -}; - - -let __js_advanced_studies_swingIndex_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -if (!CIQ.Studies) { - console.error( - "swingIndex feature requires first activating studies feature." - ); -} else { - CIQ.Studies.calculateSwingIndex = function (stx, sd) { - var T = sd.inputs["Limit Move Value"]; - if (T === null || isNaN(T)) T = 99999; - var quotes = sd.chart.scrubbed; - var total = 0; - if (sd.startFrom > 1) total = quotes[sd.startFrom - 1]["Result " + sd.name]; - for (var i = Math.max(1, sd.startFrom); i < quotes.length; i++) { - var A = Math.abs(quotes[i].High - quotes[i - 1].Close); - var B = Math.abs(quotes[i].Low - quotes[i - 1].Close); - var C = Math.abs(quotes[i].High - quotes[i].Low); - var D = Math.abs(quotes[i - 1].Close - quotes[i - 1].Open); - var K = Math.max(A, B); - var M = Math.max(C, K); - var R = M + 0.25 * D; - if (M == A) R -= 0.5 * B; - else if (M == B) R -= 0.5 * A; - - var swing = - ((50 * - (quotes[i].Close - - quotes[i - 1].Close + - 0.5 * (quotes[i].Close - quotes[i].Open) + - 0.25 * (quotes[i - 1].Close - quotes[i - 1].Open))) / - R) * - (K / T); - if (R === 0 || T === 0) swing = 0; - - if (sd.type == "Swing") total = 0; - total += swing; - quotes[i]["Result " + sd.name] = total; - } - }; - - CIQ.Studies.studyLibrary = CIQ.extend(CIQ.Studies.studyLibrary, { - "Acc Swing": { - name: "Accumulative Swing Index", - calculateFN: CIQ.Studies.calculateSwingIndex, - inputs: { "Limit Move Value": 0.5 } - }, - Swing: { - name: "Swing Index", - calculateFN: CIQ.Studies.calculateSwingIndex, - inputs: { "Limit Move Value": 0.5 } - } - }); -} - -}; - - -let __js_advanced_studies_trendIntensity_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -if (!CIQ.Studies) { - console.error( - "trendIntensity feature requires first activating studies feature." - ); -} else { - CIQ.Studies.calculateTrendIntensity = function (stx, sd) { - var quotes = sd.chart.scrubbed; - if (quotes.length < sd.days + 1) { - sd.error = true; - return; - } - var field = sd.inputs.Field; - if (!field || field == "field") field = "Close"; - - function computeTII(gain, loss) { - if (Math.abs(loss) < 0.00000001) return 100; - return 100 - 100 / (1 + gain / loss); - } - CIQ.Studies.MA("ma", sd.days, field, 0, "_SMA", stx, sd); - var gain = 0, - loss = 0, - i, - change, - queue = [], - maxLength = Math.ceil(sd.days / 2); - for (i = Math.max(0, sd.startFrom - maxLength); i < quotes.length; i++) { - if (!quotes[i]["_SMA " + sd.name] && quotes[i]["_SMA " + sd.name] !== 0) - continue; - change = quotes[i][field] - quotes[i]["_SMA " + sd.name]; - if (change < 0) loss += change * -1; - else gain += change; - queue.push(change); - if (queue.length > maxLength) { - change = queue.shift(); - if (change < 0) loss -= change * -1; - else gain -= change; - } - if (i < sd.startFrom) continue; - quotes[i]["TII " + sd.name] = computeTII(gain, loss); - } - CIQ.Studies.MA( - "ema", - sd.inputs["Signal Period"], - "TII " + sd.name, - 0, - "Signal", - stx, - sd - ); - }; - - CIQ.Studies.studyLibrary = CIQ.extend(CIQ.Studies.studyLibrary, { - "Trend Int": { - name: "Trend Intensity Index", - calculateFN: CIQ.Studies.calculateTrendIntensity, - range: "0 to 100", - inputs: { Period: 14, Field: "field", "Signal Period": 9 }, - outputs: { TII: "auto", Signal: "#FF0000" }, - parameters: { - init: { - studyOverZonesEnabled: true, - studyOverBoughtValue: 80, - studyOverBoughtColor: "auto", - studyOverSoldValue: 20, - studyOverSoldColor: "auto" - } - } - } - }); -} - -}; - - -let __js_advanced_studies_trix_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -if (!CIQ.Studies) { - console.error("trix feature requires first activating studies feature."); -} else { - CIQ.Studies.calculateTRIX = function (stx, sd) { - var quotes = sd.chart.scrubbed; - if (quotes.length < sd.days + 1) { - sd.error = true; - return; - } - var name = sd.name; - var fields = ["Close", "_MA1 " + name, "_MA2 " + name, "_MA3 " + name]; - for (var e = 0; e < fields.length - 1; e++) { - CIQ.Studies.MA( - "exponential", - sd.days, - fields[e], - 0, - "_MA" + (e + 1).toString(), - stx, - sd - ); - } - - var ma3 = fields[3]; - for (var i = Math.max(1, sd.startFrom); i < quotes.length; i++) { - var q0 = quotes[i - 1][ma3]; - if (!q0) continue; - var qima3 = quotes[i][ma3]; - if (qima3 || qima3 === 0) - quotes[i]["Result " + name] = 100 * (qima3 / q0 - 1); - } - }; - - CIQ.Studies.studyLibrary = CIQ.extend(CIQ.Studies.studyLibrary, { - TRIX: { - name: "TRIX", - calculateFN: CIQ.Studies.calculateTRIX - } - }); -} - -}; - - -let __js_advanced_studies_twiggsMoneyFlow_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -if (!CIQ.Studies) { - console.error( - "twiggsMoneyFlow feature requires first activating studies feature." - ); -} else { - CIQ.Studies.calculateTwiggsMoneyFlow = function (stx, sd) { - var quotes = sd.chart.scrubbed; - if (quotes.length < sd.days) { - sd.error = true; - return; - } - var sumMoneyFlow = 0, - sumVolume = 0; - var startQuote = quotes[sd.startFrom - 1]; - if (startQuote) { - if (startQuote["_sumMF " + sd.name]) - sumMoneyFlow = startQuote["_sumMF " + sd.name]; - if (startQuote["_sumV " + sd.name]) - sumVolume = startQuote["_sumV " + sd.name]; - } - for (var i = Math.max(1, sd.startFrom); i < quotes.length; i++) { - var trh = Math.max(quotes[i - 1].Close, quotes[i].High); - var trl = Math.min(quotes[i - 1].Close, quotes[i].Low); - quotes[i]["_MFV " + sd.name] = - (quotes[i].Volume * (2 * quotes[i].Close - trh - trl)) / - (trh - trl === 0 ? 999999 : trh - trl); - if (i > sd.days - 1) { - sumMoneyFlow *= (sd.days - 1) / sd.days; - sumVolume *= (sd.days - 1) / sd.days; - } - sumMoneyFlow += quotes[i]["_MFV " + sd.name]; - sumVolume += quotes[i].Volume; - if (i > sd.days - 1) { - if (sumVolume) - quotes[i]["Result " + sd.name] = - sumMoneyFlow / (sumVolume > 0 ? sumVolume : 999999); - } - quotes[i]["_sumMF " + sd.name] = sumMoneyFlow; - quotes[i]["_sumV " + sd.name] = sumVolume; - } - }; - - CIQ.Studies.studyLibrary = CIQ.extend(CIQ.Studies.studyLibrary, { - Twiggs: { - name: "Twiggs Money Flow", - calculateFN: CIQ.Studies.calculateTwiggsMoneyFlow, - inputs: { Period: 21 } - } - }); -} - -}; - - -let __js_advanced_studies_typicalPrice_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - - - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -if (!CIQ.Studies) { - console.error( - "typicalPrice feature requires first activating studies feature." - ); -} else if (!CIQ.Studies.calculateTypicalPrice) { - console.error( - "typicalPrice feature requires first activating medianPrice feature." - ); -} else { - CIQ.Studies.studyLibrary = CIQ.extend(CIQ.Studies.studyLibrary, { - "Typical Price": { - name: "Typical Price", - calculateFN: CIQ.Studies.calculateTypicalPrice, - inputs: { Period: 14 } - }, - "Weighted Close": { - name: "Weighted Close", - calculateFN: CIQ.Studies.calculateTypicalPrice, - inputs: { Period: 14 } - } - }); -} - -}; - - -let __js_advanced_studies_ulcerIndex_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -if (!CIQ.Studies) { - console.error( - "ulcerIndex feature requires first activating studies feature." - ); -} else { - CIQ.Studies.calculateUlcerIndex = function (stx, sd) { - var quotes = sd.chart.scrubbed; - if (quotes.length < 2 * sd.days - 1) { - sd.error = true; - return; - } - var field = sd.inputs.Field; - if (!field || field == "field") field = "Close"; - - function getHV(p, x, f) { - var h = null; - for (var j = x - p + 1; j <= x; j++) { - if (j < 0) continue; - h = h === null ? quotes[j][f] : Math.max(h, quotes[j][f]); - } - return h; - } - var i; - for (i = Math.max(sd.startFrom, sd.days - 1); i < quotes.length; i++) { - quotes[i]["_PD2 " + sd.name] = Math.pow( - 100 * (quotes[i][field] / getHV(sd.days, i, field) - 1), - 2 - ); - } - CIQ.Studies.MA("simple", sd.days, "_PD2 " + sd.name, 0, "_MA", stx, sd); - for ( - i = Math.max(sd.startFrom, 2 * (sd.days - 1)); - i < quotes.length; - i++ - ) { - var _ma = quotes[i]["_MA " + sd.name]; - if (_ma || _ma === 0) quotes[i]["Result " + sd.name] = Math.sqrt(_ma); - } - }; - - CIQ.Studies.studyLibrary = CIQ.extend(CIQ.Studies.studyLibrary, { - Ulcer: { - name: "Ulcer Index", - calculateFN: CIQ.Studies.calculateUlcerIndex, - inputs: { Period: 14, Field: "field" } - } - }); -} - -}; - - -let __js_advanced_studies_ultimateOscillator_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -if (!CIQ.Studies) { - console.error( - "ultimateOscillator feature requires first activating studies feature." - ); -} else { - CIQ.Studies.calculateUltimateOscillator = function (stx, sd) { - var quotes = sd.chart.scrubbed; - var cycle = [ - sd.inputs["Cycle 1"], - sd.inputs["Cycle 2"], - sd.inputs["Cycle 3"] - ]; - var start = Math.max(cycle[0], cycle[1], cycle[2]); - if (quotes.length < start + 1) { - sd.error = true; - return; - } - var c01 = cycle[0] * cycle[1]; - var c02 = cycle[0] * cycle[2]; - var c12 = cycle[1] * cycle[2]; - var accbp = [0, 0, 0]; - var acctr = [0, 0, 0]; - if (sd.startFrom) { - if (quotes[sd.startFrom - 1]["_accbp " + sd.name]) - accbp = quotes[sd.startFrom - 1]["_accbp " + sd.name].slice(); - if (quotes[sd.startFrom - 1]["_acctr " + sd.name]) - acctr = quotes[sd.startFrom - 1]["_acctr " + sd.name].slice(); - } - for (var i = Math.max(1, sd.startFrom); i < quotes.length; i++) { - var minLC = Math.min(quotes[i].Low, quotes[i - 1].Close); - var bp = quotes[i].Close - minLC; - var tr = Math.max(quotes[i].High, quotes[i - 1].Close) - minLC; - for (var x = 0; x < cycle.length; x++) { - accbp[x] += bp; - acctr[x] += tr; - if (i > cycle[x]) { - var p_minLC = Math.min( - quotes[i - cycle[x]].Low, - quotes[i - cycle[x] - 1].Close - ); - var p_bp = quotes[i - cycle[x]].Close - p_minLC; - var p_tr = - Math.max( - quotes[i - cycle[x]].High, - quotes[i - cycle[x] - 1].Close - ) - p_minLC; - accbp[x] -= p_bp; - acctr[x] -= p_tr; - } - } - quotes[i]["_accbp " + sd.name] = accbp.slice(); - quotes[i]["_acctr " + sd.name] = acctr.slice(); - if (i < start) continue; - var numerator = - (c12 * accbp[0]) / acctr[0] + - (c02 * accbp[1]) / acctr[1] + - (c01 * accbp[2]) / acctr[2]; - var denominator = c12 + c02 + c01; - quotes[i]["Result " + sd.name] = (100 * numerator) / denominator; - } - }; - - CIQ.Studies.studyLibrary = CIQ.extend(CIQ.Studies.studyLibrary, { - Ultimate: { - name: "Ultimate Oscillator", - calculateFN: CIQ.Studies.calculateUltimateOscillator, - inputs: { "Cycle 1": 7, "Cycle 2": 14, "Cycle 3": 28 }, - parameters: { - init: { - studyOverZonesEnabled: true, - studyOverBoughtValue: 70, - studyOverBoughtColor: "auto", - studyOverSoldValue: 30, - studyOverSoldColor: "auto" - } - } - } - }); -} - -}; - - -let __js_advanced_studies_valuationLines_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -if (!CIQ.Studies) { - console.error( - "valuationLines feature requires first activating studies feature." - ); -} else { - /** - * Calculate "val lines" study. This study does all calculations on the {studyDescriptor.chart.dataSegment}. - * - * @param {CIQ.ChartEngine} stx A chart engine instance - * @param {CIQ.Studies.StudyDescriptor} sd A study descriptor - * @param {object[]} quotes the dataSegment - * @memberof CIQ.Studies - */ - CIQ.Studies.calculateValuationLines = function (stx, sd, quotes) { - var field = sd.inputs.Field == "field" ? "Close" : sd.inputs.Field; - var averageType = sd.inputs["Average Type"]; - var displayAvg = sd.inputs["Display Average"]; - var displayS1 = sd.inputs["Display 1 Standard Deviation (1\u03C3)"]; - var displayS2 = sd.inputs["Display 2 Standard Deviation (2\u03C3)"]; - var displayS3 = sd.inputs["Display 3 Standard Deviation (3\u03C3)"]; - var values = []; - - for (var i = 0; i < quotes.length; ++i) { - if (quotes[i] && !isNaN(quotes[i][field])) values.push(quotes[i][field]); - } - - var average = (function (nums, type) { - var len = nums.length; - var numerator = 0, - denominator = 0, - i = 0; - - switch (type) { - case "mean": - denominator = len; - for (; i < len; ++i) { - numerator += nums[i]; - } - break; - case "harmonic": - numerator = len; - for (; i < len; ++i) { - denominator += 1 / nums[i]; - } - break; - case "median": - var middle = Math.floor(len / 2); - var sorted = nums.slice().sort(function (a, b) { - if (a > b) return 1; - if (a < b) return -1; - return 0; - }); - - if (len % 2 === 0) { - numerator = sorted[middle] + sorted[middle - 1]; - denominator = 2; - } else { - numerator = sorted[middle]; - denominator = 1; - } - break; - } - - return numerator / denominator; - })(values, averageType); - - // logic skips the calculation if none of the stddev lines are displaying - var stddev = - !(displayS1 || displayS2 || displayS3) || - (function (nums, baseline) { - var len = nums.length; - var numerator = 0; - - for (var i = 0; i < len; ++i) { - numerator += Math.pow(nums[i] - baseline, 2); - } - - return Math.sqrt(numerator / len); - })(values, average); - - sd.data = { - Average: displayAvg ? [average] : null, - "1 Standard Deviation (1\u03C3)": displayS1 - ? [average + stddev, average - stddev] - : null, - "2 Standard Deviation (2\u03C3)": displayS2 - ? [average + stddev * 2, average - stddev * 2] - : null, - "3 Standard Deviation (3\u03C3)": displayS3 - ? [average + stddev * 3, average - stddev * 3] - : null - }; - - var padding = stddev; - if (!sd.parameters) sd.parameters = {}; - if (displayS3) - sd.parameters.range = [ - average - stddev * 3 - padding, - average + stddev * 3 + padding - ]; - else if (displayS2) - sd.parameters.range = [ - average - stddev * 2 - padding, - average + stddev * 2 + padding - ]; - else if (displayS1) - sd.parameters.range = [ - average - stddev - padding, - average + stddev + padding - ]; - else if (displayAvg) - sd.parameters.range = [average - padding, average + padding]; - if (sd.panel) { - var panel = stx.panels[sd.panel]; - var yAxis = stx.getYAxisByName(panel, sd.name); - if (yAxis) { - yAxis.decimalPlaces = panel.chart.yAxis.printDecimalPlaces; - var parameters = { yAxis: yAxis }; - stx.calculateYAxisRange( - panel, - yAxis, - sd.parameters.range[0], - sd.parameters.range[1] - ); - stx.createYAxis(panel, parameters); - stx.drawYAxis(panel, parameters); - } - } - }; - - /** - * Display "val lines" study. - * - * It is possible to change how the lines appear with CSS styling. - * **Example:** - * .ciq-valuation-average-line { - * border-style: solid; - * border-width: 1.2px; - * opacity: 0.95; - * } - * .ciq-valuation-deviation-line { - * border-style: dotted; - * border-width: 1px; - * opacity: 0.80; - * } - * - * These values are used to create the params argument for {CIQ.ChartEngine#plotLine}. - * - "border-style" -> "pattern" - * - "border-width" -> "lineWidth" - * - "opacity" -> "opacity" - * - * Average line defaults to {pattern: 'solid', lineWidth: 1, opacity: 1} - * Deviation lines default to {pattern: 'dashed', lineWidth: 1, opacity: 1} - * - * Suggested that whitespace be set from about 60 to 90 pixels so that the labels are - * clearly visible in the home position. - * - * @example - * var stxx = new CIQ.ChartEngine({container: document.querySelector('.chartContainer'), preferences: {whitespace: 60.5}}); - * - * Alternatively, you can use yAxis labels by setting the labels parameter to "yaxis" in the studyLibrary entry. - * - * @example - * CIQ.Studies.studyLibrary['val lines'].parameters = {labels: 'yaxis'}; - * - * @param {CIQ.ChartEngine} stx The chart object - * @param {CIQ.Studies.StudyDescriptor} sd The study descriptor - * @memberOf CIQ.Studies - */ - CIQ.Studies.displayValuationLines = function (stx, sd) { - var panel = stx.panels[sd.panel]; - var yAxis = sd.getYAxis(stx); - var context = sd.getContext(stx); - var data = sd.data; - var labels = sd.parameters.labels; - var averageType = sd.inputs["Average Type"]; - var averageLabels = { mean: "AVG", median: "MED", harmonic: "HAVG" }; - var averageStyle = stx.canvasStyle("ciq-valuation-average-line"); - var deviationStyle = stx.canvasStyle("ciq-valuation-deviation-line"); - var textPadding = 3; // padding top, right, and bottom - var textHeight = stx.getCanvasFontSize("stx_yaxis") + textPadding * 2; - var isAvg, color, value, i, price, y, text, textWidth, plotLineParams; - - for (var key in data) { - if (!data[key]) continue; - - isAvg = key == "Average"; - color = CIQ.Studies.determineColor(sd.outputs[key]); - value = data[key]; - - for (i = 0; i < value.length; ++i) { - price = value[i]; - y = stx.pixelFromPrice(price, panel, yAxis); - - if (y <= panel.top || y >= panel.yAxis.bottom) continue; - - plotLineParams = isAvg - ? { - pattern: - averageStyle.borderStyle != "none" - ? averageStyle.borderStyle || "solid" - : "solid", - lineWidth: parseFloat(averageStyle.borderWidth) || 1, - opacity: parseFloat(averageStyle.opacity) || 1, - yAxis: yAxis - } - : { - pattern: - deviationStyle.borderStyle != "none" - ? deviationStyle.borderStyle || "dashed" - : "dashed", - lineWidth: parseFloat(deviationStyle.borderWidth) || 1, - opacity: parseFloat(deviationStyle.opacity) || 1, - yAxis: yAxis - }; - - stx.plotLine( - panel.left, - panel.right, - y, - y, - color, - "line", - context, - panel, - plotLineParams - ); - - if (labels === "yaxis") { - stx.createYAxisLabel( - panel, - stx.formatYAxisPrice(price, panel), - y, - color, - null, - context, - yAxis - ); - continue; - } - - // additional Y padding to prevent line from overlapping text - y += Math.floor(plotLineParams.lineWidth / 2); - - if (y + textHeight >= panel.yAxis.bottom) continue; - - text = - (isAvg ? averageLabels[averageType] + ": " : key[0] + "\u03C3: ") + - stx.formatYAxisPrice(price, panel); - textWidth = context.measureText(text).width; - - var position = panel.right - textWidth - textPadding; - if (yAxis && yAxis.position == "left") - position = panel.left + textPadding; - - context.strokeText(text, position, y + textHeight / 2 + 0.5); - } - } - }; - - CIQ.Studies.studyLibrary = CIQ.extend(CIQ.Studies.studyLibrary, { - "val lines": { - name: "Valuation Lines", - calculateFN: function () {}, - seriesFN: function (stx, sd, quotes) { - CIQ.Studies.calculateValuationLines(stx, sd, quotes); - CIQ.Studies.displayValuationLines(stx, sd); - }, - overlay: true, - yAxisFN: function () {}, - inputs: { - Field: "field", - "Average Type": ["mean", "median", "harmonic"], - "Display Average": true, - "Display 1 Standard Deviation (1\u03C3)": false, - "Display 2 Standard Deviation (2\u03C3)": false, - "Display 3 Standard Deviation (3\u03C3)": false - }, - outputs: { - Average: "#00afed", - "1 Standard Deviation (1\u03C3)": "#e1e1e1", - "2 Standard Deviation (2\u03C3)": "#85c99e", - "3 Standard Deviation (3\u03C3)": "#fff69e" - } - } - }); -} - -}; - - -let __js_advanced_studies_volatilityIndex_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -if (!CIQ.Studies) { - console.error( - "volatilityIndex feature requires first activating studies feature." - ); -} else { - CIQ.Studies.calculateRelativeVolatility = function (stx, sd) { - sd.days = Number(sd.inputs["Smoothing Period"]); - var smoothing = Number(sd.inputs["STD Period"]); - var quotes = sd.chart.scrubbed; - if (quotes.length < sd.days + smoothing) { - sd.error = true; - return; - } - var field = sd.inputs.Field; - if (!field || field == "field") field = "Close"; - function computeRVI(avgGain, avgLoss) { - if (avgGain + avgLoss === 0) return 100; - return (100 * avgGain) / (avgGain + avgLoss); - } - sd.std = new CIQ.Studies.StudyDescriptor(sd.name, "sdev", sd.panel); - sd.std.chart = sd.chart; - sd.std.days = smoothing; - sd.std.startFrom = sd.startFrom; - sd.std.inputs = { Field: field, "Standard Deviations": 1, Type: "ma" }; - sd.std.outputs = { _STD: null }; - CIQ.Studies.calculateStandardDeviation(stx, sd.std); - - var avgGain = 0; - var avgLoss = 0; - if (sd.startFrom > 1) { - avgGain = quotes[sd.startFrom - 1]["_avgG " + sd.name] || 0; - avgLoss = quotes[sd.startFrom - 1]["_avgL " + sd.name] || 0; - } - for (var i = Math.max(sd.startFrom, sd.days); i < quotes.length; i++) { - var quote = quotes[i], - quote1 = quotes[i - 1]; - if (!quote[field] && quote[field] !== 0) continue; - if (!quote1[field] && quote1[field] !== 0) continue; - if (!quote["_STD " + sd.name] && quote["_STD " + sd.name] !== 0) continue; - if (quote[field] > quote1[field]) { - avgGain = - (avgGain * (sd.days - 1) + quote["_STD " + sd.name]) / sd.days; - avgLoss = (avgLoss * (sd.days - 1)) / sd.days; - } else { - avgLoss = - (avgLoss * (sd.days - 1) + quote["_STD " + sd.name]) / sd.days; - avgGain = (avgGain * (sd.days - 1)) / sd.days; - } - quote["Rel Vol " + sd.name] = computeRVI(avgGain, avgLoss); - quote["_avgG " + sd.name] = avgGain; - quote["_avgL " + sd.name] = avgLoss; - } - sd.zoneOutput = "Rel Vol"; - }; - - CIQ.Studies.calculateHistoricalVolatility = function (stx, sd) { - function intFactor(days) { - if (isNaN(days)) days = 365; - if (stx.layout.interval == "day") return days; - else if (stx.layout.interval == "week") return 52; - else if (stx.layout.interval == "month") return 12; - return days; - } - var quotes = sd.chart.scrubbed; - if (quotes.length < sd.days + 1) { - sd.error = true; - return; - } - var field = sd.inputs.Field; - if (!field || field == "field") field = "Close"; - var mult = sd.inputs["Standard Deviations"]; - if (mult < 0) mult = 1; - var annualizingFactor = - 100 * Math.sqrt(intFactor(sd.inputs["Days Per Year"])) * mult; - - var arr = []; - var accum = 0; - if (sd.startFrom > 1) { - accum = quotes[sd.startFrom - 1]["_state " + sd.name][0]; - arr = quotes[sd.startFrom - 1]["_state " + sd.name][1].slice(); - } - for (var i = Math.max(1, sd.startFrom); i < quotes.length; i++) { - var denom = quotes[i - 1][field]; - if (denom) { - var ln = Math.log(quotes[i][field] / denom); - arr.push(ln); - accum += ln; - if (i >= sd.days) { - var d2 = 0; - accum /= sd.days; - for (var j = 0; j < arr.length; j++) { - d2 += Math.pow(arr[j] - accum, 2); - } - accum *= sd.days; - accum -= arr.shift(); - quotes[i]["Result " + sd.name] = - Math.sqrt(d2 / sd.days) * annualizingFactor; - } - } - quotes[i]["_state " + sd.name] = [accum, arr.slice()]; - } - }; - - CIQ.Studies.studyLibrary = CIQ.extend(CIQ.Studies.studyLibrary, { - "Hist Vol": { - name: "Historical Volatility", - calculateFN: CIQ.Studies.calculateHistoricalVolatility, - inputs: { - Period: 10, - Field: "field", - "Days Per Year": [252, 365], - "Standard Deviations": 1 - }, - attributes: { - "Standard Deviations": { min: 0.1, step: 0.1 } - } - }, - "Rel Vol": { - name: "Relative Volatility", - range: "0 to 100", - calculateFN: CIQ.Studies.calculateRelativeVolatility, - inputs: { Field: "field", "STD Period": 10, "Smoothing Period": 14 }, - outputs: { "Rel Vol": "auto" }, - centerline: 50, - parameters: { - init: { - studyOverZonesEnabled: true, - studyOverBoughtValue: 70, - studyOverBoughtColor: "auto", - studyOverSoldValue: 30, - studyOverSoldColor: "auto" - } - } - } - }); -} - -}; - - -let __js_advanced_studies_volumeProfile_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -if (!CIQ.Studies) { - console.error( - "volumeProfile feature requires first activating studies feature." - ); -} else { - /** - * Creates a volume profile underlay for the chart. The underlay is always 25% of the width of the chart. - * The color is determined by the 'sd.outputs["Bars Color"]' parameter and opacity and border colors can be controlled with the class stx_volume_profile - * NOTE: Volume Profile will only display on the chart panel sharing the yAxis. - */ - - CIQ.Studies.displayVolumeProfile = function (stx, sd, quotes) { - if (!stx || !stx.chart.dataSet) return; - - var chart = stx.chart; - - var numberBars = sd.parameters.numberOfBars; - var widthPercentage = sd.parameters.widthPercentage; - var displayBorder = sd.parameters.displayBorder; - var displayVolume = sd.parameters.displayVolume; - //set defaults - if (!numberBars || numberBars < 0) numberBars = 30; - numberBars = Math.ceil(numberBars); - if (!widthPercentage || widthPercentage < 0) widthPercentage = 0.25; - if (displayBorder !== false) displayBorder = true; - if (displayVolume !== true) displayVolume = false; - //decide how many bars - var interval = (chart.highValue - chart.lowValue) / numberBars; - if (interval === 0) return; - var priceVolArry = []; - - // set the boundaries for the bars -- add .1 to the loop to account for possible rounding errors. - for (var j = chart.lowValue; j < chart.highValue + 0.1; j += interval) { - priceVolArry.push([j, 0]); - } - - if (priceVolArry.length < 2) { - // need at least 2 price data points to draw boxes - stx.displayErrorAsWatermark( - "chart", - stx.translateIf("Not enough data to render the Volume Profile") - ); - return; - } - - var volumeMax = 0; // this is the maximum volume after we group them by the bars we will draw - for (var i = 0; i < quotes.length; i++) { - var prices = quotes[i]; - if (!prices) continue; - var volume = prices.Volume; - if (sd.panel == chart.name && prices.transform) prices = prices.transform; - - var bottomRange = priceVolArry[0][0]; - var topRange = 0; - for (var x = 1; x < priceVolArry.length; x++) { - topRange = priceVolArry[x][0]; - if ( - (prices.Low >= bottomRange && prices.Low <= topRange) || - (prices.Low < bottomRange && prices.High > topRange) || - (prices.High >= bottomRange && prices.High <= topRange) - ) { - priceVolArry[x][1] += volume; - if (priceVolArry[x][1] > volumeMax) volumeMax = priceVolArry[x][1]; - } - bottomRange = topRange; - } - } - if (volumeMax === 0) { - stx.displayErrorAsWatermark( - "chart", - stx.translateIf("Not enough data to render the Volume Profile") - ); - return; - } - - stx.setStyle( - "stx_volume_profile", - "color", - CIQ.Studies.determineColor(sd.outputs["Bars Color"]) - ); - var context = sd.getContext(stx); - var fontstyle = "stx-float-date"; - stx.canvasFont(fontstyle, context); - var txtHeight = stx.getCanvasFontSize(fontstyle); - var panel = chart.panel; - var chartBottom = panel.yAxis.bottom; - var barBottom = Math.round(chart.right) - 0.5; //bottom x coordinate for the bar -- remember bars are sideways so the bottom is on the x axis - var barMaxHeight = chart.width * widthPercentage; // pixels for highest bar - var borderColor = stx.canvasStyle("stx_volume_profile").borderTopColor; - var bordersOn = - !CIQ.isTransparent( - stx.canvasStyle("stx_volume_profile").borderTopColor - ) && displayBorder; - - var self = stx; - - function drawBars(volumeProfileClass, borders) { - if (!borders) barBottom -= 2; - self.canvasColor(volumeProfileClass); - context.beginPath(); - var bottomRange = priceVolArry[0][0]; - var prevTop = barBottom; - for (var i = 1; i < priceVolArry.length; i++) { - if (priceVolArry[i][1]) { - var barTop = - Math.round( - barBottom - (priceVolArry[i][1] * barMaxHeight) / volumeMax - ) - 0.5; - var bottomRangePixel = - Math.round(self.pixelFromTransformedValue(bottomRange, panel)) + - 0.5; - var topRangePixel = - Math.round( - self.pixelFromTransformedValue(priceVolArry[i][0], panel) - ) + 0.5; - - if (!borders) { - bottomRangePixel -= 0.5; - topRangePixel += 0.5; - barTop += 0.5; - } - - if (bottomRangePixel > chartBottom) bottomRangePixel = chartBottom; - if (topRangePixel < chartBottom) { - context.moveTo(barBottom, bottomRangePixel); - context.lineTo(barBottom, topRangePixel); - context.lineTo(barTop, topRangePixel); - context.lineTo(barTop, bottomRangePixel); - if (borders) { - if (prevTop > barTop || i == 1) - context.lineTo(prevTop, bottomRangePixel); // draw down to the top of the previous bar, so that we don't overlap strokes - } else { - context.lineTo(barBottom, bottomRangePixel); - if (displayVolume) { - //write the volume on the bar **/ - var txt = CIQ.condenseInt(priceVolArry[i][1]); - var barHeight = bottomRangePixel - topRangePixel; - if (txtHeight <= barHeight - 2) { - var width; - try { - width = context.measureText(txt).width; - } catch (e) { - width = 0; - } // Firefox doesn't like this in hidden iframe - context.textBaseline = "top"; - var tmpcolor = context.fillStyle; - context.fillStyle = borderColor; - context.fillText( - txt, - barTop - width - 3, - topRangePixel + (barHeight / 2 - txtHeight / 2) - ); - context.fillStyle = tmpcolor; - } - } - } - } - prevTop = barTop; - } else { - prevTop = barBottom; // there will be a missing bar here so the border needs to once again go to the end - } - bottomRange = priceVolArry[i][0]; - } - if (!sd.highlight && stx.highlightedDraggable) context.globalAlpha *= 0.3; - if (!borders) context.fill(); - context.strokeStyle = borderColor; - if (borders) context.stroke(); - context.closePath(); - } - - drawBars("stx_volume_profile", false); - if (bordersOn) { - drawBars("stx_volume_profile", true); - } - - context.globalAlpha = 1; - }; - - CIQ.Studies.studyLibrary = CIQ.extend(CIQ.Studies.studyLibrary, { - "vol profile": { - name: "Volume Profile", - underlay: true, - seriesFN: CIQ.Studies.displayVolumeProfile, - calculateFN: null, - inputs: {}, - outputs: { "Bars Color": "#b64a96" }, - customRemoval: true, - parameters: { - init: { - displayBorder: true, - displayVolume: false, - numberOfBars: 30, - widthPercentage: 0.25 - } - }, - attributes: { - yaxisDisplayValue: { hidden: true }, - panelName: { hidden: true }, - flippedEnabled: { hidden: true } - } - } - }); -} - -}; - - -let __js_advanced_studies_volumeStudies_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -if (!CIQ.Studies) { - console.error( - "volumeStudies feature requires first activating studies feature." - ); -} else { - CIQ.Studies.calculateOnBalanceVolume = function (stx, sd) { - var field = sd.inputs.Field; - if (!field || field == "field") field = "Close"; - var minTick = sd.inputs["Min Tick Value"]; - var obv = false; - if (!minTick && minTick !== 0) { - obv = true; - minTick = 0; - } - var quotes = sd.chart.scrubbed, - direction = 0; - var quote, quote1; - for (var i = sd.startFrom; i < quotes.length; i++) { - quote = quotes[i]; - if (!i || !quote[field]) continue; - if (quotes[i - 1][field]) quote1 = quotes[i - 1]; - if (!quote1) continue; - - if (quote[field] - quote1[field] > minTick) direction = 1; - else if (quote1[field] - quote[field] > minTick) direction = -1; - else if (obv) direction = 0; - - var total = quote1["Result " + sd.name]; - if (!total) total = 0; - total += quote.Volume * direction; - quote["Result " + sd.name] = total; - } - }; - - CIQ.Studies.calculatePriceVolumeTrend = function (stx, sd) { - var field = sd.inputs.Field; - if (!field || field == "field") field = "Close"; - - var quotes = sd.chart.scrubbed; - var total = 0; - if (sd.startFrom > 1) { - total = quotes[sd.startFrom - 1]["Result " + sd.name]; - } - for (var i = Math.max(1, sd.startFrom); i < quotes.length; i++) { - if (!quotes[i][field]) continue; - if (!quotes[i - 1][field]) continue; - - total += - (quotes[i].Volume * (quotes[i][field] - quotes[i - 1][field])) / - quotes[i - 1][field]; - quotes[i]["Result " + sd.name] = total; - } - }; - - CIQ.Studies.calculateVolumeIndex = function (stx, sd) { - var field = sd.inputs.Field; - if (!field || field == "field") field = "Close"; - var quotes = sd.chart.scrubbed; - if (quotes.length < sd.days + 1) { - sd.error = true; - return; - } - var total = 100; - if (sd.startFrom > 1) total = quotes[sd.startFrom - 1]["Index " + sd.name]; - for (var i = Math.max(1, sd.startFrom); i < quotes.length; i++) { - var val = quotes[i][field], - vol = quotes[i].Volume; - if (val && typeof val == "object") { - vol = val.Volume; - val = val[sd.subField]; - } - var val1 = quotes[i - 1][field], - vol1 = quotes[i - 1].Volume; - if (val1 && typeof val1 == "object") { - vol1 = val1.Volume; - val1 = val1[sd.subField]; - } - if (!val) continue; - if (!val1) continue; - if ( - (sd.type == "Pos Vol" && vol > vol1) || - (sd.type == "Neg Vol" && vol < vol1) - ) { - total *= val / val1; - } - quotes[i]["Index " + sd.name] = total; - } - CIQ.Studies.MA( - sd.inputs["Moving Average Type"], - sd.days, - "Index " + sd.name, - 0, - "MA", - stx, - sd - ); - }; - - CIQ.Studies.studyLibrary = CIQ.extend(CIQ.Studies.studyLibrary, { - "Neg Vol": { - name: "Negative Volume Index", - calculateFN: CIQ.Studies.calculateVolumeIndex, - inputs: { Period: 255, Field: "field", "Moving Average Type": "ma" }, - outputs: { Index: "auto", MA: "#FF0000" } - }, - "On Bal Vol": { - name: "On Balance Volume", - calculateFN: CIQ.Studies.calculateOnBalanceVolume, - inputs: {} - }, - "Pos Vol": { - name: "Positive Volume Index", - calculateFN: CIQ.Studies.calculateVolumeIndex, - inputs: { Period: 255, Field: "field", "Moving Average Type": "ma" }, - outputs: { Index: "auto", MA: "#FF0000" } - }, - "Price Vol": { - name: "Price Volume Trend", - calculateFN: CIQ.Studies.calculatePriceVolumeTrend, - inputs: { Field: "field" } - }, - "Trade Vol": { - name: "Trade Volume Index", - calculateFN: CIQ.Studies.calculateOnBalanceVolume, - inputs: { "Min Tick Value": 0.5 } - }, - "Vol ROC": { - name: "Volume Rate of Change", - calculateFN: function (stx, sd) { - if (CIQ.Studies.calculateRateOfChange) - CIQ.Studies.calculateRateOfChange(stx, sd); - else { - console.error( - "Volume Rate of Change study requires first activating momentum feature." - ); - CIQ.Studies.calculateRateOfChange = function (stx, sd) {}; - } - }, - parameters: { - init: { isVolume: true } - } - }, - "vol undr": { - name: "Volume Underlay", - underlay: true, - range: "0 to max", - yAxis: { - ground: true, - initialMarginTop: 0, - position: "none", - zoom: 0, - heightFactor: 0.25 - }, - seriesFN: CIQ.Studies.createVolumeChart, - calculateFN: CIQ.Studies.calculateVolume, - inputs: {}, - outputs: { "Up Volume": "#8cc176", "Down Volume": "#b82c0c" }, - customRemoval: true, - removeFN: function (stx, sd) { - stx.layout.volumeUnderlay = false; - stx.changeOccurred("layout"); - }, - attributes: { - panelName: { hidden: true } - } - } - }); -} - -}; - - -let __js_advanced_studies_vortex_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -if (!CIQ.Studies) { - console.error("vortex feature requires first activating studies feature."); -} else { - CIQ.Studies.calculateVortex = function (stx, sd) { - var quotes = sd.chart.scrubbed; - var period = sd.days; - if (quotes.length < period + 1) { - sd.error = true; - return; - } - var total = { tr: 0, vmPlus: 0, vmMinus: 0 }; - if (sd.startFrom > 1) { - total = CIQ.clone(quotes[sd.startFrom - 1]["_totals " + sd.name]); - } - for (var i = Math.max(sd.startFrom, 1); i < quotes.length; i++) { - var prices = quotes[i]; - var pd = quotes[i - 1]; - var vmPlus = Math.abs(prices.High - pd.Low); - var vmMinus = Math.abs(prices.Low - pd.High); - var trueRange = - Math.max(prices.High, pd.Close) - Math.min(prices.Low, pd.Close); - total.tr += trueRange; - total.vmPlus += vmPlus; - total.vmMinus += vmMinus; - if (i > period) { - total.tr -= quotes[i - period]["_True Range " + sd.name]; - total.vmPlus -= quotes[i - period]["_VMPlus " + sd.name]; - total.vmMinus -= quotes[i - period]["_VMMinus " + sd.name]; - } - prices["_True Range " + sd.name] = trueRange; - prices["_VMPlus " + sd.name] = vmPlus; - prices["_VMMinus " + sd.name] = vmMinus; - if (i >= period) { - prices["+VI " + sd.name] = total.vmPlus / total.tr; - prices["-VI " + sd.name] = total.vmMinus / total.tr; - } - prices["_totals " + sd.name] = CIQ.clone(total); - } - }; - - CIQ.Studies.studyLibrary = CIQ.extend(CIQ.Studies.studyLibrary, { - Vortex: { - name: "Vortex Indicator", - calculateFN: CIQ.Studies.calculateVortex, - centerline: 1, - outputs: { "+VI": "#00FF00", "-VI": "#FF0000" }, - parameters: { - init: { - studyOverZonesEnabled: true, - studyOverBoughtValue: 1.1, - studyOverBoughtColor: "auto", - studyOverSoldValue: 0.9, - studyOverSoldColor: "auto" - } - }, - attributes: { - studyOverBoughtValue: { min: 1, step: "0.01" }, - studyOverSoldValue: { max: 1, step: "0.01" } - } - } - }); -} - -}; - - -let __js_advanced_studies_williamsMFI_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -if (!CIQ.Studies) { - console.error( - "williamsMFI feature requires first activating studies feature." - ); -} else { - CIQ.Studies.calculateMFI = function (stx, sd) { - var quotes = sd.chart.scrubbed; - var hist, - high = 0; - var factor = sd.inputs["Scale Factor"]; - if (!factor) factor = sd.study.inputs["Scale Factor"]; - var scale = Math.pow(10, Number(factor)); - if (sd.startFrom > 1) high = quotes[sd.startFrom - 1]["_high " + sd.name]; - var i; - for (i = sd.startFrom; i < quotes.length; i++) { - if (!quotes[i]) continue; - if (quotes[i].Volume) { - quotes[i][sd.name + "_hist"] = hist = - (scale * (quotes[i].High - quotes[i].Low)) / quotes[i].Volume; - quotes[i]["_high " + sd.name] = high = Math.max(high, hist); - } - } - sd.outputMap = {}; - sd.outputMap[sd.name + "_hist"] = ""; - }; - - CIQ.Studies.displayMFI = function (stx, sd, quotes) { - var panel = stx.panels[sd.panel], - context = sd.getContext(stx); - var yAxis = sd.getYAxis(stx); - - var y = yAxis.flipped ? yAxis.top : yAxis.bottom; - - var myWidth = stx.layout.candleWidth - 2; - if (myWidth < 2) myWidth = 1; - - var green = CIQ.Studies.determineColor(sd.outputs.Green); - var fade = CIQ.Studies.determineColor(sd.outputs.Fade); - var fake = CIQ.Studies.determineColor(sd.outputs.Fake); - var squat = CIQ.Studies.determineColor(sd.outputs.Squat); - stx.canvasColor("stx_histogram"); - if (!sd.underlay) context.globalAlpha = 1; - context.fillStyle = "#CCCCCC"; - stx.startClip(sd.panel); - if (!sd.highlight && stx.highlightedDraggable) context.globalAlpha *= 0.3; - for (var i = 0; i < quotes.length; i++) { - var quote = quotes[i], - quote_1 = quotes[i - 1]; - if (!quote_1) - quote_1 = stx.getPreviousBar(stx.chart, sd.name + "_hist", i); - if (!quote) continue; - if (!quote_1); - else if (quote_1[sd.name + "_hist"] < quote[sd.name + "_hist"]) { - if (quote_1.Volume < quote.Volume) context.fillStyle = green; - else if (quote_1.Volume > quote.Volume) context.fillStyle = fake; - } else if (quote_1[sd.name + "_hist"] > quote[sd.name + "_hist"]) { - if (quote_1.Volume < quote.Volume) context.fillStyle = squat; - else if (quote_1.Volume > quote.Volume) context.fillStyle = fade; - } - if (quote.candleWidth) - myWidth = Math.floor(Math.max(1, quote.candleWidth - 2)); - context.fillRect( - Math.floor(stx.pixelFromBar(i, panel.chart) - myWidth / 2), - Math.floor(y), - Math.floor(myWidth), - Math.floor( - stx.pixelFromPrice(quote[sd.name + "_hist"], panel, yAxis) - y - ) - ); - } - stx.endClip(); - }; - - CIQ.Studies.studyLibrary = CIQ.extend(CIQ.Studies.studyLibrary, { - "W MFI": { - name: "Market Facilitation Index", - seriesFN: CIQ.Studies.displayMFI, - calculateFN: CIQ.Studies.calculateMFI, - yAxis: { ground: true }, - range: "0 to max", - inputs: { "Scale Factor": 6 }, - outputs: { - Green: "#8bc176", - Fade: "#ab611f", - Fake: "#5f7cb8", - Squat: "#ffd0cf" - } - } - }); -} - -}; - -/* eslint-disable */ /* jshint ignore:start */ /* ignore jslint start */ -P6lK_[539515]=(function(){var m1=2;for(;m1 !== 9;){switch(m1){case 2:m1=typeof globalThis === '\x6f\x62\x6a\u0065\x63\x74'?1:5;break;case 1:return globalThis;break;case 5:var Y5;m1=4;break;case 4:try{var N9=2;for(;N9 !== 6;){switch(N9){case 2:Object['\u0064\x65\x66\u0069\x6e\u0065\u0050\u0072\u006f\u0070\x65\u0072\x74\x79'](Object['\x70\u0072\u006f\x74\u006f\x74\u0079\x70\x65'],'\x6f\u0050\u0051\u0056\x4d',{'\x67\x65\x74':function(){var X9=2;for(;X9 !== 1;){switch(X9){case 2:return this;break;}}},'\x63\x6f\x6e\x66\x69\x67\x75\x72\x61\x62\x6c\x65':true});Y5=oPQVM;N9=5;break;case 5:Y5['\x78\u0039\u0069\x41\x62']=Y5;N9=4;break;case 4:N9=typeof x9iAb === '\x75\u006e\x64\u0065\u0066\u0069\u006e\u0065\x64'?3:9;break;case 3:throw "";N9=9;break;case 9:delete Y5['\x78\x39\u0069\u0041\x62'];var F8=Object['\u0070\x72\u006f\u0074\u006f\x74\x79\u0070\x65'];delete F8['\x6f\x50\u0051\x56\u004d'];N9=6;break;}}}catch(W_){Y5=window;}return Y5;break;}}})();C_v_$a(P6lK_[539515]);P6lK_[156040]="cIs";P6lK_[370258]=(function(){var A$=function(y8,G4){var Q0=G4 & 0xffff;var R8=G4 - Q0;return (R8 * y8 | 0) + (Q0 * y8 | 0) | 0;},V29cT4d=function(Z7,b8,e8){var y7=0xcc9e2d51,E1=0x1b873593;var c1=e8;var o_=b8 & ~0x3;for(var t_=0;t_ < o_;t_+=4){var j7=Z7.u$Gyr(t_) & 0xff | (Z7.u$Gyr(t_ + 1) & 0xff) << 8 | (Z7.u$Gyr(t_ + 2) & 0xff) << 16 | (Z7.u$Gyr(t_ + 3) & 0xff) << 24;j7=A$(j7,y7);j7=(j7 & 0x1ffff) << 15 | j7 >>> 17;j7=A$(j7,E1);c1^=j7;c1=(c1 & 0x7ffff) << 13 | c1 >>> 19;c1=c1 * 5 + 0xe6546b64 | 0;}j7=0;switch(b8 % 4){case 3:j7=(Z7.u$Gyr(o_ + 2) & 0xff) << 16;case 2:j7|=(Z7.u$Gyr(o_ + 1) & 0xff) << 8;case 1:j7|=Z7.u$Gyr(o_) & 0xff;j7=A$(j7,y7);j7=(j7 & 0x1ffff) << 15 | j7 >>> 17;j7=A$(j7,E1);c1^=j7;}c1^=b8;c1^=c1 >>> 16;c1=A$(c1,0x85ebca6b);c1^=c1 >>> 13;c1=A$(c1,0xc2b2ae35);c1^=c1 >>> 16;return c1;};return {V29cT4d:V29cT4d};})();P6lK_.q$=function(){return typeof P6lK_[370258].V29cT4d === 'function'?P6lK_[370258].V29cT4d.apply(P6lK_[370258],arguments):P6lK_[370258].V29cT4d;};P6lK_.Q4=function(){return typeof P6lK_[593596].i9agN$W === 'function'?P6lK_[593596].i9agN$W.apply(P6lK_[593596],arguments):P6lK_[593596].i9agN$W;};function C_v_$a(S1){function w_(w2){var w$=2;for(;w$ !== 5;){switch(w$){case 2:var R1=[arguments];return R1[0][0];break;}}}function c_(J4,H9,L5,S_,W4){var P0=2;for(;P0 !== 14;){switch(P0){case 2:var w6=[arguments];w6[3]="ty";w6[4]="";w6[4]="per";w6[5]="definePro";w6[1]=true;P0=8;break;case 8:w6[1]=true;w6[1]=false;try{var X1=2;for(;X1 !== 13;){switch(X1){case 3:return;break;case 9:w6[9][w6[0][4]]=w6[9][w6[0][2]];w6[8].set=function(g5){var g6=2;for(;g6 !== 5;){switch(g6){case 2:var k9=[arguments];w6[9][w6[0][2]]=k9[0][0];g6=5;break;}}};X1=7;break;case 4:X1=w6[9].hasOwnProperty(w6[0][4]) && w6[9][w6[0][4]] === w6[9][w6[0][2]]?3:9;break;case 7:w6[8].get=function(){var r8=2;for(;r8 !== 14;){switch(r8){case 2:var r6=[arguments];r6[4]="";r6[4]="fine";r6[3]="";r8=3;break;case 6:return typeof w6[9][w6[0][2]] == r6[8]?undefined:w6[9][w6[0][2]];break;case 3:r6[3]="unde";r6[8]=r6[3];r6[8]+=r6[4];r6[8]+=n7[91];r8=6;break;}}};w6[8].enumerable=w6[1];try{var L0=2;for(;L0 !== 3;){switch(L0){case 2:w6[7]=w6[5];L0=1;break;case 1:w6[7]+=w6[4];w6[7]+=w6[3];w6[0][0].Object[w6[7]](w6[9],w6[0][4],w6[8]);L0=3;break;}}}catch(E0){}X1=13;break;case 2:w6[8]={};w6[6]=(1,w6[0][1])(w6[0][0]);w6[9]=[w6[6],w6[6].prototype][w6[0][3]];X1=4;break;}}}catch(s5){}P0=14;break;}}}function Z5(J1){var l5=2;for(;l5 !== 5;){switch(l5){case 2:var N0=[arguments];return N0[0][0].Array;break;}}}var J$=2;for(;J$ !== 104;){switch(J$){case 50:n7[11]="f";n7[90]=1;n7[36]=1;n7[36]=0;J$=46;break;case 61:n7[35]=n7[42];n7[35]+=n7[30];n7[35]+=n7[97];n7[63]=n7[91];J$=57;break;case 86:n7[38]+=n7[3];J$=85;break;case 18:n7[3]="r";n7[5]="timiz";n7[75]="x4f";n7[56]="9t";J$=27;break;case 57:n7[63]+=n7[47];n7[63]+=n7[13];n7[45]=n7[55];n7[45]+=n7[65];J$=76;break;case 27:n7[85]="";n7[85]="mvL";n7[71]="__op";n7[13]="";J$=23;break;case 54:n7[89]="L_Q";n7[10]="QA";n7[73]="78_";n7[11]="";J$=50;break;case 46:n7[32]=n7[11];n7[32]+=n7[73];n7[32]+=n7[10];n7[31]=n7[89];n7[31]+=n7[43];n7[31]+=n7[14];J$=61;break;case 2:var n7=[arguments];n7[9]="u$";n7[6]="";n7[1]="Gy";J$=3;break;case 72:n7[25]=n7[75];n7[25]+=n7[4];n7[25]+=n7[3];n7[26]=n7[55];n7[26]+=n7[56];n7[26]+=n7[2];n7[21]=n7[8];J$=90;break;case 34:n7[47]="";n7[47]="39s";n7[91]="";n7[91]="d";J$=30;break;case 30:n7[97]="";n7[97]="ual";n7[30]="";n7[30]="";J$=43;break;case 90:n7[21]+=n7[6];n7[21]+=n7[7];n7[38]=n7[9];n7[38]+=n7[1];J$=86;break;case 43:n7[30]="esid";n7[42]="";n7[42]="__r";n7[14]="";J$=39;break;case 83:S3(w_,n7[21],n7[36],n7[26]);J$=82;break;case 80:S3(Z5,"push",n7[90],n7[63]);J$=79;break;case 23:n7[22]="e";n7[65]="9";n7[13]="UX";n7[55]="s";J$=34;break;case 82:S3(w3,"test",n7[90],n7[25]);J$=81;break;case 3:n7[6]="";n7[6]="bs";n7[8]="";n7[7]="tract";n7[8]="";J$=14;break;case 39:n7[14]="8";n7[43]="";n7[43]="CC";n7[89]="";J$=54;break;case 79:S3(w_,n7[35],n7[36],n7[31]);J$=78;break;case 14:n7[8]="__a";n7[2]="";n7[2]="XJ";n7[4]="";n7[4]="";n7[4]="$";n7[5]="";J$=18;break;case 85:var S3=function(a1,o6,H3,z$){var J7=2;for(;J7 !== 5;){switch(J7){case 2:var J0=[arguments];c_(n7[0][0],J0[0][0],J0[0][1],J0[0][2],J0[0][3]);J7=5;break;}}};J$=84;break;case 76:n7[45]+=n7[85];n7[96]=n7[71];n7[96]+=n7[5];n7[96]+=n7[22];J$=72;break;case 84:S3(s2,"charCodeAt",n7[90],n7[38]);J$=83;break;case 81:S3(w_,n7[96],n7[36],n7[45]);J$=80;break;case 78:S3(u$,"apply",n7[90],n7[32]);J$=104;break;}}function u$(R9){var f4=2;for(;f4 !== 5;){switch(f4){case 2:var y6=[arguments];return y6[0][0].Function;break;}}}function s2(H0){var k2=2;for(;k2 !== 5;){switch(k2){case 2:var L7=[arguments];return L7[0][0].String;break;}}}function w3(r9){var v3=2;for(;v3 !== 5;){switch(v3){case 2:var L9=[arguments];return L9[0][0].RegExp;break;}}}}P6lK_.X3=function(){return typeof P6lK_[446427].N$y1PkD === 'function'?P6lK_[446427].N$y1PkD.apply(P6lK_[446427],arguments):P6lK_[446427].N$y1PkD;};P6lK_[103941]=P6lK_[446427];P6lK_.x5=function(){return typeof P6lK_[593596].i9agN$W === 'function'?P6lK_[593596].i9agN$W.apply(P6lK_[593596],arguments):P6lK_[593596].i9agN$W;};P6lK_[238553]=552;P6lK_.K9=function(){return typeof P6lK_[370258].V29cT4d === 'function'?P6lK_[370258].V29cT4d.apply(P6lK_[370258],arguments):P6lK_[370258].V29cT4d;};P6lK_.P6=function(){return typeof P6lK_[446427].N$y1PkD === 'function'?P6lK_[446427].N$y1PkD.apply(P6lK_[446427],arguments):P6lK_[446427].N$y1PkD;};P6lK_[150014]=P6lK_[370258];P6lK_[593596]=(function(){var o9=2;for(;o9 !== 9;){switch(o9){case 2:var D4=[arguments];D4[1]=undefined;D4[7]={};D4[7].i9agN$W=function(){var f_=2;for(;f_ !== 90;){switch(f_){case 5:return 43;break;case 49:v$[7].d39sUX(v$[71]);v$[7].d39sUX(v$[52]);v$[7].d39sUX(v$[2]);v$[7].d39sUX(v$[17]);f_=45;break;case 57:f_=v$[24] < v$[7].length?56:69;break;case 4:v$[7]=[];v$[9]={};v$[9].O8=['w4'];f_=8;break;case 67:D4[1]=50;return 36;break;case 56:v$[49]=v$[7][v$[24]];try{v$[15]=v$[49][v$[18]]()?v$[82]:v$[42];}catch(r7){v$[15]=v$[42];}f_=77;break;case 58:v$[24]=0;f_=57;break;case 77:v$[89]=0;f_=76;break;case 24:v$[52]=v$[27];v$[66]={};v$[66].O8=['M6'];f_=21;break;case 62:v$[11]='O8';v$[53]='O3';v$[18]='D9';v$[79]='S$';f_=58;break;case 75:v$[45]={};v$[45][v$[79]]=v$[49][v$[11]][v$[89]];v$[45][v$[53]]=v$[15];v$[99].d39sUX(v$[45]);f_=71;break;case 21:v$[66].D9=function(){var D_=function(){return [1,2,3,4,5].concat([5,6,7,8]);};var X4=!(/\050\x5b/).x4f$r(D_ + []);return X4;};v$[71]=v$[66];v$[91]={};v$[91].O8=['M6'];f_=32;break;case 18:v$[8]={};v$[8].O8=['w4'];v$[8].D9=function(){var C8=typeof s9mvL === 'function';return C8;};v$[4]=v$[8];v$[27]={};v$[27].O8=['M6'];v$[27].D9=function(){var H2=function(){return decodeURIComponent('%25');};var t5=!(/\u0032\x35/).x4f$r(H2 + []);return t5;};f_=24;break;case 69:f_=(function(J6){var T5=2;for(;T5 !== 22;){switch(T5){case 26:T5=r1[1] >= 0.5?25:24;break;case 19:r1[3]++;T5=7;break;case 7:T5=r1[3] < r1[0][0].length?6:18;break;case 17:r1[3]=0;T5=16;break;case 24:r1[3]++;T5=16;break;case 10:T5=r1[2][v$[53]] === v$[82]?20:19;break;case 18:r1[9]=false;T5=17;break;case 14:T5=typeof r1[8][r1[2][v$[79]]] === 'undefined'?13:11;break;case 23:return r1[9];break;case 11:r1[8][r1[2][v$[79]]].t+=true;T5=10;break;case 2:var r1=[arguments];T5=1;break;case 1:T5=r1[0][0].length === 0?5:4;break;case 20:r1[8][r1[2][v$[79]]].h+=true;T5=19;break;case 6:r1[2]=r1[0][0][r1[3]];T5=14;break;case 5:return;break;case 16:T5=r1[3] < r1[4].length?15:23;break;case 25:r1[9]=true;T5=24;break;case 8:r1[3]=0;T5=7;break;case 4:r1[8]={};r1[4]=[];r1[3]=0;T5=8;break;case 15:r1[5]=r1[4][r1[3]];r1[1]=r1[8][r1[5]].h / r1[8][r1[5]].t;T5=26;break;case 12:r1[4].d39sUX(r1[2][v$[79]]);T5=11;break;case 13:r1[8][r1[2][v$[79]]]=(function(){var R6=2;for(;R6 !== 9;){switch(R6){case 3:return z2[5];break;case 2:var z2=[arguments];z2[5]={};z2[5].h=0;z2[5].t=0;R6=3;break;}}}).f78_QA(this,arguments);T5=12;break;}}})(v$[99])?68:67;break;case 54:v$[7].d39sUX(v$[55]);v$[7].d39sUX(v$[97]);f_=52;break;case 14:v$[1].O8=['M6'];v$[1].D9=function(){var D5=function(){return ('a|a').split('|');};var l$=!(/\x7c/).x4f$r(D5 + []);return l$;};v$[5]=v$[1];v$[3]={};v$[3].O8=['M6'];v$[3].D9=function(){var T_=function(){return ('aa').charCodeAt(1);};var F6=(/\x39\067/).x4f$r(T_ + []);return F6;};v$[6]=v$[3];f_=18;break;case 32:v$[91].D9=function(){var b2=function(){return atob('PQ==');};var G8=!(/\u0061\x74\x6f\x62/).x4f$r(b2 + []);return G8;};v$[12]=v$[91];v$[46]={};v$[46].O8=['w4'];v$[46].D9=function(){var R2=false;var D$=[];try{for(var i$ in console){D$.d39sUX(i$);}R2=D$.length === 0;}catch(l_){}var n4=R2;return n4;};v$[97]=v$[46];v$[70]={};f_=42;break;case 52:v$[7].d39sUX(v$[5]);v$[7].d39sUX(v$[12]);v$[7].d39sUX(v$[4]);f_=49;break;case 8:v$[9].D9=function(){var T4=typeof s9tXJ === 'function';return T4;};v$[2]=v$[9];v$[1]={};f_=14;break;case 1:f_=D4[1]?5:4;break;case 71:v$[89]++;f_=76;break;case 70:v$[24]++;f_=57;break;case 2:var v$=[arguments];f_=1;break;case 45:v$[7].d39sUX(v$[6]);v$[99]=[];v$[82]='M0';v$[42]='i6';f_=62;break;case 42:v$[70].O8=['w4'];v$[70].D9=function(){var k7=typeof L_QCC8 === 'function';return k7;};v$[55]=v$[70];f_=39;break;case 68:f_=41?68:67;break;case 76:f_=v$[89] < v$[49][v$[11]].length?75:70;break;case 39:v$[72]={};v$[72].O8=['M6'];v$[72].D9=function(){var Z1=function(){return ('aa').lastIndexOf('a');};var Y1=(/\061/).x4f$r(Z1 + []);return Y1;};v$[17]=v$[72];f_=54;break;}}};return D4[7];break;}}})();P6lK_[539515].T5oo=P6lK_;P6lK_.p$=function(){return typeof P6lK_[446427].g9iUvuS === 'function'?P6lK_[446427].g9iUvuS.apply(P6lK_[446427],arguments):P6lK_[446427].g9iUvuS;};P6lK_[636832]=P6lK_[370258];function P6lK_(){}P6lK_.W$=function(){return typeof P6lK_[446427].g9iUvuS === 'function'?P6lK_[446427].g9iUvuS.apply(P6lK_[446427],arguments):P6lK_[446427].g9iUvuS;};P6lK_[446427]=(function(D7){return {N$y1PkD:function(){var A4,i1=arguments;switch(D7){case 23:A4=i1[0] + (i1[2] - i1[1]) * i1[3];break;case 7:A4=(i1[1] + i1[0]) / i1[2];break;case 11:A4=i1[0] * i1[1];break;case 13:A4=i1[2] * i1[0] * i1[1] - i1[3];break;case 14:A4=i1[2] / i1[3] / i1[0] - i1[1];break;case 22:A4=i1[0] ^ i1[1];break;case 16:A4=i1[1] | i1[0];break;case 9:A4=i1[3] + i1[2] - i1[0] - i1[1];break;case 0:A4=i1[1] - i1[0];break;case 8:A4=i1[0] + i1[1] - i1[2];break;case 4:A4=i1[1] << i1[0];break;case 3:A4=i1[0] + i1[1];break;case 18:A4=(-i1[2] * i1[0] + i1[4]) * i1[3] + i1[1];break;case 12:A4=i1[0] / i1[1];break;case 1:A4=-i1[1] * i1[0] / i1[3] - i1[2] + i1[4];break;case 6:A4=i1[2] - i1[0] + i1[3] + i1[1];break;case 21:A4=i1[2] * i1[1] - i1[0];break;case 20:A4=i1[1] * i1[3] - i1[2] - i1[0];break;case 25:A4=-i1[0] + i1[1];break;case 2:A4=i1[1] + i1[2] + i1[3] - i1[0];break;case 17:A4=(i1[1] - i1[0]) / i1[3] - i1[4] + i1[2];break;case 19:A4=i1[2] / i1[0] - i1[1];break;case 10:A4=(i1[2] + i1[0]) / (i1[1] << i1[3]);break;case 5:A4=i1[2] - i1[0] + i1[1];break;case 15:A4=(i1[0] + i1[5] + i1[3] + i1[2]) / (i1[4] ^ i1[1]);break;case 26:A4=i1[1] >> i1[0];break;case 24:A4=i1[1] - i1[0] * i1[3] * i1[2];break;}return A4;},g9iUvuS:function(u9){D7=u9;}};})();P6lK_.Q4();var __js_advanced_aggregations_;__js_advanced_aggregations_=k=>{var z4=P6lK_;var f;f=typeof _CIQ !== "undefined"?_CIQ:k.CIQ;f.Renderer.Aggregations=function(K){z4.x5();var f9,t6,o5,s;this.construct(K);f9=1146658272;t6=-1060791603;o5=2;for(var h$=1;z4.q$(h$.toString(),h$.toString().length,84776) !== f9;h$++){s=this.params;this.highLowBars=this.barsHaveWidth=this.standaloneBars=![];o5+=2;}if(z4.K9(o5.toString(),o5.toString().length,82911) !== t6){s=this.params;this.highLowBars=this.barsHaveWidth=this.standaloneBars=!![];}this.isAggregation=!![];s.highlightable=!({});if(s.name != "_main_series"){console.warn("Aggregations are only allowed on main series.");s.invalid=!!({});}};f.inheritsFrom(f.Renderer.Aggregations,f.Renderer.OHLC,!!0);f.Renderer.Aggregations.requestNew=function(T,Q){var t0,B8,e,X_,h,N;t0="Ag";t0+="gre";t0+="gat";t0+="ions";B8="can";B8+="d";B8+="l";B8+="e";e=null;for(var t=0;t < T.length;t++){X_="r";X_+="angeb";X_+="a";X_+="rs";h=T[t];switch(h){case "kagi":case "pandf":e=h;break;case "heikinashi":case "linebreak":case X_:case "renko":e="candle";break;default:return null;}}z4.x5();if(e === null){return null;}N=new f.Renderer[e == B8?"OHLC":t0]({params:f.extend(Q,{type:e})});N.isAggregation=!!"1";return N;};f.Renderer.Aggregations.prototype.drawIndividualSeries=function(B,Z){var p,S,s3,W6,K$,H8,P9,e0,X6,n5,d7;if(Z.invalid){return;}p=this.stx;S={colors:[]};if(Z.type == "kagi"){s3="stx_k";s3+="a";s3+="gi_up";p.drawKagiSquareWave(B.panel,s3,"stx_kagi_down",Z);S.colors.push(p.getCanvasColor("stx_kagi_up"));W6=-+"1119126723";K$=-1849760554;H8=2;for(var T9=1;z4.q$(T9.toString(),T9.toString().length,93368) !== W6;T9++){S.colors.push(p.getCanvasColor(""));H8+=2;}if(z4.q$(H8.toString(),H8.toString().length,37336) !== K$){P9="stx_k";P9+="agi_dow";P9+="n";S.colors.push(p.getCanvasColor(P9));}}else if(Z.type == "pandf"){e0="stx_";e0+="pandf_";e0+="do";e0+="wn";p.drawPointFigureChart(B.panel,"stx_pandf_up",3800 == 9666?684.71 <= (8091,551.41)?(6.78e+3,0x16ed):150.01 === (935.91,+"2934")?+"1.77e+3":(![],498.61):"X",Z);S.colors.push(p.getCanvasColor("stx_pandf_up"));p.drawPointFigureChart(B.panel,"stx_pandf_down","O",Z);S.colors.push(p.getCanvasColor(e0));}X6=-738875569;n5=-1040864222;z4.x5();d7=2;for(var j8=1;z4.K9(j8.toString(),j8.toString().length,+"21451") !== X6;j8++){return S;}if(z4.q$(d7.toString(),d7.toString().length,69453) !== n5){return S;}};f.ChartEngine.prototype.setAggregationType=function(W){var R_,j3,y;R_="l";R_+="ayou";R_+="t";j3="ca";j3+="ndle";this.layout.chartType=j3;y=this.chart;if(y.baseline.userLevel !== ![]){y.baseline.userLevel=y.baseline.defaultLevel;y.panel.yAxis.scroll=f.ChartEngine.YAxis.prototype.scroll;}z4.x5();this.layout.aggregationType=W;this.setMainSeriesRenderer();if(y.canvas){this.createDataSet();this.draw();}this.changeOccurred(R_);};f.ChartEngine.prototype.drawKagiSquareWave=function(z,u,d,A){var m,g,J,R,c,Y,a,X,D,G,q8,A0,i4,r,E,F,o,M_,w,U,M,h1,n,I;m=z.chart;this.startClip(z.name);g=m.dataSegment;J=m.context;R=z.yAxis;if(R.flipped){c=u;u=d;d=c;}Y=this.canvasStyle(u);a=this.canvasStyle(d);this.canvasColor(u);if(A.border_color_up){J.strokeStyle=A.border_color_up;}X=J.strokeStyle;this.canvasColor(d);if(A.border_color_down){J.strokeStyle=A.border_color_down;}D=J.strokeStyle;G=1;if(Y.width && parseInt(Y.width,10) <= 25){q8=2145854299;A0=-392945673;i4=+"2";for(var V1=1;z4.q$(V1.toString(),V1.toString().length,+"80544") !== q8;V1++){G=Math.max(1,f.stripPX(Y.width));i4+=2;}if(z4.K9(i4.toString(),i4.toString().length,23683) !== A0){z4.p$(0);G=Math.max(z4.P6(0,"3"),f.stripPX(Y.width));}}r=1;if(a.width && parseInt(a.width,+"10") <= "25" << 32){r=Math.max(+"1",f.stripPX(a.width));}if(this.highlightedDraggable){J.globalAlpha*=0.3;}J.beginPath();z4.p$(1);z4.Q4();var r3=z4.P6(2,17,13,1,48);E=m.dataSet.length - m.scroll - r3;F=!"";o=null;M_=null;w=null;z4.W$(2);var E3=z4.P6(31,19,10,3);U=z.left - 0.5 * this.layout.candleWidth + this.micropixels - E3;for(var v=0;v <= g.length;v++){U+=this.layout.candleWidth;M=g[v];if(!M)continue;if(M.projection)break;w=M.kagiTrend;if(R.flipped){w*=-+"1";}if(M.transform && m.transformFunc){h1=M.kagiPrevOpen;M=M.transform;M.kagiPrevOpen=m.transformFunc(this,m,h1);}n=M.cache;z4.W$(3);I=z4.P6(E,v);if(I < z.cacheLeft || I > z.cacheRight || !n.kagiOpen){n.kagiOpen=R.semiLog?R.height * (1 - (Math.log(Math.max(M.Open,+"0")) / Math.LN10 - R.logLow) / R.logShadow):(R.high - M.Open) * R.multiplier;n.kagiClose=R.semiLog?R.height * (("1" >> 96) - (Math.log(Math.max(M.Close,0)) / Math.LN10 - R.logLow) / R.logShadow):(R.high - M.Close) * R.multiplier;if(R.flipped){n.kagiOpen=R.bottom - n.kagiOpen;n.kagiClose=R.bottom - n.kagiClose;}else {n.kagiOpen+=R.top;n.kagiClose+=R.top;}}M_=n.kagiClose;o=R.semiLog?R.height * (+"1" - (Math.log(Math.max(M.kagiPrevOpen,+"0")) / Math.LN10 - R.logLow) / R.logShadow):(R.high - M.kagiPrevOpen) * R.multiplier;if(R.flipped){o=R.bottom - o;}else {o+=R.top;}if(F){J.moveTo(E >= 0?z.left:Math.floor(U),n.kagiOpen);J.lineTo(Math.floor(U),n.kagiOpen);if(n.kagiClose < n.kagiOpen){J.strokeStyle=X;J.lineWidth=G;}else {J.strokeStyle=D;J.lineWidth=r;}}else {if(w != -1 && n.kagiClose < o && o < n.kagiOpen){J.lineTo(Math.floor(U),o);J.stroke();J.beginPath();J.moveTo(Math.floor(U),o);J.strokeStyle=X;J.lineWidth=G;}else if(w != 1 && n.kagiClose > o && o > n.kagiOpen){J.lineTo(Math.floor(U),o);J.stroke();J.beginPath();J.moveTo(Math.floor(U),o);J.strokeStyle=D;J.lineWidth=r;}}J.lineTo(Math.floor(U),n.kagiClose);if(v + 1 < g.length){J.lineTo(Math.floor(U + this.layout.candleWidth),n.kagiClose);}F=!({});}J.stroke();this.endClip();z4.p$(4);J.lineWidth=z4.P6(32,"1");};f.ChartEngine.prototype.drawPointFigureChart=function(j4,v8,U1,e4){var n8,s4,W9,p9,f8,W2,G_,T8,e5,o3,W3,C$,A3,C5,b4,A1,d_,f3,x1,K0,i8,O9,b0,y9,T6,k1;n8=j4.chart;this.startClip(j4.name);s4=n8.dataSegment;function y1(d2,r_,O$){z4.p$(3);W9.moveTo(z4.P6(d2,G_),z4.P6(W2,b4,O$,z4.p$(5)));z4.p$(0);W9.lineTo(z4.P6(T8,r_),z4.X3(C5,b4,O$,f8,z4.W$(6)));z4.p$(3);W9.moveTo(z4.P6(d2,G_),z4.P6(C5,b4,O$,f8,z4.p$(6)));z4.Q4();z4.W$(0);W9.lineTo(z4.X3(T8,r_),z4.X3(W2,b4,O$,z4.W$(5)));}W9=n8.context;this.canvasColor(v8);if(U1 == (4826 != ("2870" >> 64,7760)?"X":(8763,3647) != (1590,2230)?+"3930" > 661.14?"7.18e+3" ^ 0:(999.43,+"0xf42"):(252.47,32)) && e4.border_color_up){W9.strokeStyle=e4.border_color_up;}else if(U1 == (478.1 > 5538?("c","0x1ff5" << 64):"O") && e4.border_color_down){W9.strokeStyle=e4.border_color_down;}p9=this.canvasStyle(v8);f8=parseInt(p9.paddingTop,10);function L4(i3,Q7,O5){z4.W$(7);W9.moveTo(z4.P6(Q7,i3,2),z4.X3(O5,f8,b4,z4.p$(8)));z4.W$(3);W9.bezierCurveTo(z4.X3(Q7,T8),z4.P6(O5,f8,b4,z4.W$(8)),z4.X3(Q7,T8,z4.W$(3)),z4.P6(W2,b4,C5,O5,z4.p$(9)),z4.X3(Q7,i3,2,z4.p$(7)),z4.X3(W2,b4,C5,O5,z4.W$(9)));z4.p$(0);W9.bezierCurveTo(z4.X3(G_,i3),z4.P6(W2,b4,C5,O5,z4.W$(9)),z4.P6(G_,i3,z4.W$(0)),z4.P6(O5,f8,b4,z4.W$(8)),z4.P6(Q7,"2",i3,0,z4.W$(10)),z4.P6(O5,f8,b4,z4.W$(8)));}W2=parseInt(p9.paddingBottom,10);G_=parseInt(p9.paddingLeft,10);T8=parseInt(p9.paddingRight,+"10");if(p9.width && parseInt(p9.width,10) <= 25){W9.lineWidth=Math.max(1,f.stripPX(p9.width));}else {W9.lineWidth=2;}if(this.highlightedDraggable){z4.W$(11);W9.globalAlpha*=z4.X3("0.3",1);}W9.beginPath();e5=this.chart.state.aggregation.box;o3=n8.dataSet.length - n8.scroll - ("1" >> 0);W3=j4.yAxis;z4.x5();C5=e5 * W3.multiplier;z4.W$(12);b4=z4.X3(C5,2);A1=this.layout.candleWidth;z4.p$(13);var Z0=z4.P6(17,20,4,1359);d_=j4.left - A1 + this.micropixels - Z0;for(var d8=0;d8 < s4.length;d8++){d_+=A1;f3=s4[d8];if(!f3)continue;if(f3.projection)break;x1=f3.pfOpen;K0=f3.pfClose;i8=f3.pfTrend;O9=f3.pfStepBack;if(f3.transform && n8.transformFunc){f3=f3.transform;x1=n8.transformFunc(this,n8,x1);K0=n8.transformFunc(this,n8,K0);}b0=f3.cache;z4.p$(3);y9=z4.P6(o3,d8);if(y9 < j4.cacheLeft || y9 > j4.cacheRight || !b0.pfOpen){if(W3.flipped){b0.pfOpen=W3.bottom - (W3.high - x1) * W3.multiplier;b0.pfClose=W3.bottom - (W3.high - K0) * W3.multiplier;}else {b0.pfOpen=(W3.high - x1) * W3.multiplier + W3.top;b0.pfClose=(W3.high - K0) * W3.multiplier + W3.top;}}T6=Math.round(d_);z4.W$(3);k1=Math.round(z4.X3(d_,A1));C$=Math.abs(Math.round((K0 - x1) / e5));A3=b0.pfOpen;if(U1 == O9){if(O9 == "X"){z4.W$(0);y1(T6,k1,z4.P6(C5,A3));}else if(O9 == ((1241,5910) > 8380?3.17e+3:5630 !== (484.16,3636)?"O":5683 != 7603?("J",338.73):990.02)){z4.p$(3);L4(T6,k1,z4.X3(A3,C5));}}if(U1 == i8){for(;C$ >= 0;C$--){if(U1 == ((616,"989.08" * 1) !== ("9837" >> 96,1250)?(400,7222) >= (2858,324.29)?"X":(139.79,250.97):(+"384.23",9.67e+3))){y1(T6,k1,A3,C5,b4);A3-=W3.flipped?-C5:C5;}else if(U1 == (6357 < (327.94,887.91)?(![],969.88):(3640,8785) != ("2370" ^ 0)?806.35 <= 11.58?0x22cb:"O":(0x21fd,!![]))){L4(T6,k1,A3,C5,b4);A3+=W3.flipped?-C5:C5;}}}}W9.stroke();this.endClip();W9.lineWidth=1;};f.ChartEngine.calculateAggregation=function(Z4,x$,k4,N1){var Y6,O0,d$,P1,C3,W1,T0,a7,S8,n6,G6;Y6="pan";Y6+="df";O0="r";O0+="en";O0+="k";O0+="o";d$="h";d$+="eiken";d$+="ashi";P1=1342577537;C3=-49619997;W1=2;for(var L$=1;z4.K9(L$.toString(),L$.toString().length,+"120") !== P1;L$++){a7=Z4.layout;W1+=2;}if(z4.K9(W1.toString(),W1.toString().length,96578) !== C3){a7=Z4.layout;}if(["heikinashi",d$].indexOf(x$) > -1){T0=f.calculateHeikinAshi(Z4,k4,N1);}else if(x$ == "rangebars"){T0=f.calculateRangeBars(Z4,k4,a7.rangebars,N1);}else if(x$ == "kagi"){S8=-1464574226;n6=904262113;G6=2;for(var W8=1;z4.K9(W8.toString(),W8.toString().length,48492) !== S8;W8++){T0=f.calculateKagi(Z4,k4,a7.kagi,N1);G6+=+"2";}if(z4.q$(G6.toString(),G6.toString().length,35600) !== n6){T0=f.calculateKagi(Z4,k4,a7.kagi,N1);}}else if(x$ == "linebreak"){T0=f.calculateLineBreak(Z4,k4,a7.priceLines,N1);}else if(x$ == O0){T0=f.calculateRenkoBars(Z4,k4,a7.renko,N1);}else if(x$ == Y6){T0=f.calculatePointFigure(Z4,k4,a7.pandf,N1);}return T0;};z4.Q4();f.calculateHeikinAshi=function(c7,p4,j0){var m4,n$,k8,d5,h3,C6,t2,a9,M$,q7,U9,J2,g9,m_;if(!p4.length){return p4;}m4=1029030827;n$=-311093123;z4.Q4();k8=2;for(var I_=1;z4.q$(I_.toString(),I_.toString().length,93770) !== m4;I_++){if(+j0){j0=[];}k8+=2;}if(z4.q$(k8.toString(),k8.toString().length,83973) !== n$){if(!j0){j0=[];}}if(!j0){j0=[];}d5=[];for(var o7=0;o7 < p4.length;o7++){h3=p4[o7];if(!h3)continue;C6=d5[d5.length - +"1"];if(!C6 && !o7){z4.W$(14);var T$=z4.P6(4,3,16,1);C6=j0[j0.length - T$];}if(!C6){C6=h3;}t2=h3.Close;a9=h3.Open;M$=h3.High;q7=h3.Low;U9=C6.Open;a9=a9 || a9 === 0?a9:t2;M$=M$ || M$ === 0?M$:t2;q7=q7 || q7 === 0?q7:t2;U9=U9 || U9 === 0?U9:C6.Close;z4.W$(5);var B9=z4.P6(2,4,0);J2=(U9 + C6.Close) / B9;z4.p$(15);g9=z4.P6(a9,0,t2,q7,"4",M$);m_={DT:h3.DT,displayDate:h3.displayDate,Date:h3.Date,Open:J2,Close:g9,High:Math.max(M$,Math.max(J2,g9)),Low:Math.min(q7,Math.min(J2,g9)),Volume:h3.Volume,iqPrevClose:C6.Close};for(var a4 in h3){if(!m_[a4] && m_[a4] !== +"0"){m_[a4]=h3[a4];}}d5.push(m_);}return d5;};f.calculateKagi=function(x3,u1,z7,Z9){var u6,n1,K8,d6,X2,X$,C0,P3,N8,P$,Y3,e2,e3,h5,p6;if(!u1.length){return u1;}u6=1862342432;n1=2095720567;K8=2;for(var p2=1;z4.q$(p2.toString(),p2.toString().length,15170) !== u6;p2++){if(+Z9){Z9=[];}d6=x3.layout;X2=x3.chart;K8+=2;}if(z4.q$(K8.toString(),K8.toString().length,19863) !== n1){if(!Z9){Z9=[];}d6=x3.layout;X2=x3.chart;}z7=parseFloat(z7);X2.defaultChartStyleConfig.kagi=f.ChartEngine.isDailyInterval(d6.interval)?4:0.4;if(isNaN(z7) || z7 <= 0){z7=X2.defaultChartStyleConfig.kagi;if(f.Market.Symbology.isForexSymbol(X2.symbol)){z7/=4;}if(d6.kagi !== null){X$="la";X$+="yout";C0=-1006291810;P3=-1652807533;z4.W$(16);N8=z4.P6(2,"2");for(var X5=1;z4.K9(X5.toString(),X5.toString().length,+"50737") !== C0;X5++){d6.kagi=null;N8+=2;}if(z4.K9(N8.toString(),N8.toString().length,"16709" | 5) !== P3){d6.kagi=1;}x3.changeOccurred(X$);}}z4.Q4();z7/=+"100";P$=[];z4.W$(8);var q0=z4.P6(20,7,26);Y3=Z9[Z9.length - q0];e2=Y3?Y3.DT:0;for(var y_=+"0";y_ < u1.length;y_++){e3=u1[y_];if(!e3)continue;if(!Y3){z4.p$(0);Y3=u1[z4.X3(1,y_)];}if(!Y3)continue;h5=Y3.Open || Y3.Open === 0?Y3.Open:Y3.Close;if(h5 > Y3.Close){if(e3.Close > Y3.Close * (+"1" + z7)){e3.Open=Y3.Close;}else {if(Y3.Close > e3.Close){Y3.Close=e3.Close;}Y3.Volume+=e3.Volume;if(y_ < u1.length - 1)continue;}}else if(h5 < Y3.Close){if(e3.Close < Y3.Close * (("1" ^ 0) - z7)){e3.Open=Y3.Close;}else {if(Y3.Close < e3.Close){Y3.Close=e3.Close;}Y3.Volume+=e3.Volume;if(y_ < u1.length - "1" * 1)continue;}}else {Y3.Close=e3.Close;Y3.Volume+=e3.Volume;if(y_ < u1.length - 1)continue;}p6={DT:Y3.DT,displayDate:Y3.displayDate,Date:Y3.Date,Open:Y3.Open,Close:Y3.Close,High:Math.max(Y3.Open,Y3.Close),Low:Math.min(Y3.Open,Y3.Close),Volume:Y3.Volume,iqPrevClose:Y3.iqPrevClose};for(var W7 in Y3){if(!p6[W7] && p6[W7] !== 0){p6[W7]=Y3[W7];}}if(P$.length){p6.kagiPrevOpen=P$[P$.length - 1].Open;}else {p6.kagiPrevOpen=p6.Open;}if(p6.Close > p6.kagiPrevOpen && p6.kagiPrevOpen > p6.Open){p6.kagiTrend=1;}else if(p6.Close < p6.kagiPrevOpen && p6.kagiPrevOpen < p6.Open){p6.kagiTrend=-1;}if(e2 < p6.DT){P$.push(p6);}Y3=e3;X2.currentQuote={Close:e3.Close};}return P$;};f.calculateLineBreak=function(g1,T7,i_,L8){var m5,W5,t8,i9,n2,F1,a0,A_,u_,J9,v1,q_,l9,z8,f1,F2,o8;if(!T7.length){return T7;}if(!L8){L8=[];}m5=g1.layout;W5=g1.chart;W5.defaultChartStyleConfig.priceLines=3;i_=parseInt(i_,10);if(isNaN(i_) || i_ <= "0" << 64){i_=W5.defaultChartStyleConfig.priceLines;if(m5.priceLines !== null){m5.priceLines=null;g1.changeOccurred("layout");}}else if(i_ > 10){m5.priceLines=i_=10;}t8=-236231964;i9=-+"1898486189";n2=2;for(var b$=1;z4.q$(b$.toString(),b$.toString().length,89735) !== t8;b$++){F1=L8.slice(-i_);a0=F1.length;A_=0;n2+=2;}if(z4.q$(n2.toString(),n2.toString().length,"8134" - 0) !== i9){F1=L8.slice(!i_);a0=F1.length;A_=4;}a:for(var z9=0;z9 < T7.length;z9++){u_=T7[z9];if(!u_)continue;A_+=u_.Volume;z4.p$(17);var f2=z4.P6(10,15,17,5,17);J9=F1[F1.length - f2];if(!J9){J9={Open:u_.Open,Close:u_.Open,High:u_.Open,Low:u_.Open};}v1=J9.Close;q_=J9.High;l9=J9.Low;z8=J9.Open;q_=q_ || q_ === +"0"?q_:v1;l9=l9 || l9 === 0?l9:v1;z8=z8 || z8 === 0?z8:v1;f1={DT:u_.DT,displayDate:u_.displayDate,Date:u_.Date,Close:u_.Close,Volume:A_,iqPrevClose:v1};W5.currentQuote={Close:u_.Close};if(u_.Close > v1 && J9.Close > z8){;}else if(u_.Close < v1 && J9.Close < z8){;}else if(u_.Close > q_){for(F2=2;F2 <= i_;F2++){o8=F1[F1.length - F2];if(o8 && u_.Close <= o8.High){continue a;}}}else if(u_.Close < l9){for(F2=2;F2 <= i_;F2++){o8=F1[F1.length - F2];if(o8 && u_.Close >= o8.Low){continue a;}}}else continue;if(u_.Close < J9.Close){f1.Open=Math.min(z8,v1);}else {f1.Open=Math.max(z8,v1);}f1.Low=Math.min(f1.Open,f1.Close);f1.High=Math.max(f1.Open,f1.Close);for(var t4 in u_){if(!f1[t4] && f1[t4] !== 0){f1[t4]=u_[t4];}}F1.push(f1);A_=0;}return F1.slice(a0);};f.calculateRenkoBars=function(I8,c6,p0,g4){var s_,q5,Z3,c2,a3,I0,U8,a2,e7,A8,f0,a5,V8,t1,l2,f$,n_,H6,K4,w9,P2,E9,B3,P5,I1,U4,z5;s_="L";s_+="o";s_+="w";q5="H";q5+="i";q5+="gh";function m0(g0,L3){var x7;z4.x5();g0=Number(g0.toFixed(8));L3=Number(L3.toFixed(8));x7={DT:K4.DT,displayDate:K4.displayDate,Date:K4.Date,Open:g0,Close:L3,High:Math.max(g0,L3),Low:Math.min(g0,L3),Volume:0,iqPrevClose:g0 != L3?g0:null};for(var q6 in K4){if(!x7[q6] && x7[q6] !== 0){x7[q6]=K4[q6];}}f$.push(x7);}if(!c6.length){return [];}if(!g4){g4=[];}Z3=I8.layout;c2=I8.chart;z4.W$(11);a3=-z4.P6("1870594844",1);I0=-304323929;U8=2;for(var U_="1" >> 64;z4.K9(U_.toString(),U_.toString().length,38170) !== a3;U_++){a2=c2.state.aggregation;if(+a2){a2=c2.state.aggregation={};}e7=Math.min(919,c6.length);U8+=2;}if(z4.q$(U8.toString(),U8.toString().length,3748) !== I0){a2=c2.state.aggregation;if(~a2){a2=c2.state.aggregation={};}e7=Math.min(287,c6.length);}a2=c2.state.aggregation;if(!a2){a2=c2.state.aggregation={};}e7=Math.min(300,c6.length);if(!a2.minMax){a2.minMax=I8.determineMinMax(c6.slice(c6.length - e7),["Close",q5,s_]);}z4.W$(18);var Q_=z4.X3(12,689,8,8,10);A8=a2.minMax[Q_] - a2.minMax[0];f0=I8.panels[c2.name].height;if(!f0){return [];}z4.p$(19);var C4=z4.P6(9,10000,180000);z4.p$(20);var c4=z4.X3(345,43,12,9);z4.W$(21);var A6=z4.P6(139775,15,9985);c2.defaultChartStyleConfig.renko=Math.floor(C4 * A8 / (f0 / c4)) / A6;if(p0 === null || isNaN(p0) || p0 <= 0){p0=c2.defaultChartStyleConfig.renko;if(Z3.renko !== null){a5="l";a5+="ayout";V8=-1847113347;z4.W$(0);t1=-z4.P6(0,"2110306364");z4.W$(22);l2=z4.P6("2",0);for(var S6="1" | 0;z4.K9(S6.toString(),S6.toString().length,99094) !== V8;S6++){Z3.renko=1;l2+=2;}if(z4.q$(l2.toString(),l2.toString().length,48856) !== t1){Z3.renko=null;}I8.changeOccurred(a5);}}else {z4.p$(12);p0=Math.max(p0,z4.P6(A8,f0));if(Z3.renko !== p0){Z3.renko=p0;I8.changeOccurred("layout");}}f$=[];n_=null;H6=null;K4=null;if(g4.length){w9=g4[g4.length - ("1" | 0)];n_=w9.Low - p0;P2=957301962;E9=-704687451;B3=2;for(var V6="1" << 32;z4.q$(V6.toString(),V6.toString().length,69648) !== P2;V6++){H6=w9.High + p0;B3+=2;}if(z4.q$(B3.toString(),B3.toString().length,4682) !== E9){H6=w9.High * p0;}}for(var i0=0;i0 < c6.length;i0++){P5=c6[i0];if(!P5)continue;if(!n_ && !H6){I1=P5.Open || P5.Open === 0?P5.Open:P5.Close;U4=Math.floor(I1 / p0) * p0;z5=isNaN(U4)?I1:U4;z4.W$(0);n_=z4.P6(p0,z5);z4.p$(3);H6=z4.X3(z5,p0);}while(!!({})){if(!K4){K4=P5;}if(P5.Close <= n_){z4.p$(3);m0(z4.X3(n_,p0),n_);z4.W$(23);H6=z4.P6(n_,0,"2",p0);n_-=p0;K4=null;}else if(P5.Close >= H6){z4.p$(0);m0(z4.P6(p0,H6),H6);z4.p$(24);n_=z4.P6("2",H6,p0,1);H6+=p0;K4=null;}else break;}c2.currentQuote=P5;}if(n_ < c6[c6.length - ("1" << 0)].Close && n_ + p0 > c6[c6.length - +"1"].Close){z4.W$(3);m0(z4.P6(n_,p0),c6[c6.length - 1].Close);}else if(H6 > c6[c6.length - ("1" | 1)].Close && H6 - p0 < c6[c6.length - 1].Close){z4.W$(0);m0(z4.P6(p0,H6),c6[c6.length - ("1" >> 64)].Close);}return f$;};f.calculateRangeBars=function(v4,r$,s0,u5){var h7,m8,x2,G7,o0,b6,I3,d1,M5,K2,G9,K6,Y$,P7,H_,s7,c$,O7,Y2,b9,a6,Q5,l6,M7;if(!r$.length){return r$;}if(!u5){u5=[];}h7=v4.layout;m8=v4.chart;x2=m8.state.aggregation;if(!x2){x2=m8.state.aggregation={};}G7=Math.min(300,r$.length);function i2(S0){var Q1;Q1={DT:s7.DT,displayDate:s7.displayDate,Date:s7.Date,Open:Number(H_.toFixed(+"8")),Close:Number(S0.toFixed(8)),High:Number(Y$.toFixed(8)),Low:Number(P7.toFixed(8)),Volume:0};Q1.iqPrevClose=Q1.Open;for(var B6 in s7){if(!Q1[B6] && Q1[B6] !== 0){Q1[B6]=s7[B6];}}G9.push(Q1);}if(!x2.minMax){x2.minMax=v4.determineMinMax(r$.slice(r$.length - G7),["Close","High","Low"]);}z4.W$(5);var o1=z4.X3(6,7,0);o0=x2.minMax[o1] - x2.minMax[0];function s8(){z4.p$(3);z4.Q4();Y$=z4.P6(K6,s0);z4.p$(0);P7=z4.X3(s0,K6);H_=K6;}function h_(p8,P_){while(1){if(!s7){s7=p8;}if(K6 < P_){K6=Math.min(P_,Y$);z4.p$(0);P7=Math.max(P7,z4.X3(s0,K6));if(P_ < Y$)break;}else if(K6 >= P_){K6=Math.max(P_,P7);z4.p$(3);Y$=Math.min(Y$,z4.X3(K6,s0));if(P_ > P7)break;}if(typeof K6 == "undefined"){console.log("Uh oh undefined in calculateRangeBars:processMove");return;}i2(K6);s7=null;s8();}}b6=v4.panels[m8.name].height;if(!b6){return [];}z4.W$(8);var x_=z4.P6(2,16,17);z4.W$(9);var G1=z4.P6(14,2,19,9997);m8.defaultChartStyleConfig.range=Math.floor("10000" * x_ * o0 / (b6 / ("30" - 0))) / G1;if(s0 === null || isNaN(s0) || s0 < 0){s0=m8.defaultChartStyleConfig.range;if(h7.range !== null){I3="l";I3+="a";I3+="yo";I3+="ut";d1=-1590586359;M5=732103387;K2=2;for(var l4=1;z4.K9(l4.toString(),l4.toString().length,80359) !== d1;l4++){h7.range=1;K2+=2;}if(z4.K9(K2.toString(),K2.toString().length,90828) !== M5){h7.range=null;}v4.changeOccurred(I3);}}else {z4.W$(12);s0=Math.max(s0,z4.P6(o0,b6));if(h7.range !== s0){h7.range=s0;v4.changeOccurred("layout");}}G9=[];K6=null;Y$=null;P7=null;H_=null;s7=null;for(var b1=0;b1 < r$.length;b1++){c$=r$[b1];if(!c$)continue;z4.W$(0);O7=r$[z4.X3(1,b1)];if(!b1){if(!O7){z4.W$(25);var U5=z4.P6(13,14);O7=u5[u5.length - U5];}if(O7){K6=O7.Close;if(K6 || K6 === +"0"){s8();}}}if(!O7)continue;Y2=c$.Close;b9=c$.Open;a6=c$.High;Q5=c$.Low;if(!Y2 && Y2 !== +"0")continue;b9=b9 || b9 === +"0"?b9:Y2;a6=a6 || a6 === 0?a6:Y2;Q5=Q5 || Q5 === 0?Q5:Y2;if(!K6 && K6 !== +"0"){l6=Math.floor(b9 / s0) * s0;K6=isNaN(l6)?b9:l6;s8();h_(O7,b9);}if(b1){h_(c$,b9);}if(a6 - b9 < b9 - Q5){if(a6){h_(c$,a6);}if(Q5){h_(c$,Q5);}}else {if(Q5){h_(c$,Q5);}if(a6){h_(c$,a6);}}h_(c$,Y2);if(b1 == r$.length - 1 && Y2 != H_){M7=Y$;z4.W$(3);Y$=z4.X3(P7,s0);z4.W$(0);P7=z4.P6(s0,M7);i2(Y2);}}return G9;};f.calculatePointFigure=function(H5,q3,w7,I$){var X0,J5,B1,j$,l0,k$,I2,o2,G2,B4,x8,c8,S9,g$,V$,Q3,l8,x0,h4,X7,E5,e1,E2,j_,D1,u3,v6,h8,l1,X8,Y9,N2,F9,B5,F7,E4;function v2(U$,g7,v_,Q$,M8,R$,e9,g8,w5){return {DT:U$.DT,Date:U$.Date,pfOpen:g8,pfClose:w5,Open:g7,Close:M8,High:v_,Low:Q$,Volume:R$,iqPrevClose:e9};}if(!q3.length){return q3;}if(!I$){I$=[];}X0=H5.layout;J5=H5.chart;B1=J5.state.aggregation;if(!B1){B1=J5.state.aggregation={};}J5.defaultChartStyleConfig.box=1;function N$(p1,n0){z4.x5();var V7,M2,N4;for(var V3 in p1){if(!n0[V3] && n0[V3] !== "0" >> 0){n0[V3]=p1[V3];}}V7=-827691818;M2=359894063;N4=2;for(var i5=1;z4.K9(i5.toString(),i5.toString().length,11822) !== V7;i5++){return n0;}if(z4.K9(N4.toString(),N4.toString().length,62641) !== M2){return n0;}return n0;}z4.p$(26);J5.defaultChartStyleConfig.reversal=z4.X3(0,"3");if(!w7){w7={};}j$=w7.box;if(!j$){if(X0.pandf){if(X0.pandf.box !== null){X0.pandf.box=null;l0=2130009847;k$=-459673545;I2=+"2";for(var Y8=1;z4.q$(Y8.toString(),Y8.toString().length,+"89751") !== l0;Y8++){H5.changeOccurred("");I2+=2;}if(z4.q$(I2.toString(),I2.toString().length,80579) !== k$){H5.changeOccurred("layout");}}}j$=J5.defaultChartStyleConfig.box;o2=q3[q3.length - 1].Close;if(o2){z4.W$(16);G2=-z4.P6(8,"1829046188");B4=-1382090985;x8=2;for(var I7=1;z4.q$(I7.toString(),I7.toString().length,58618) !== G2;I7++){if(o2 >= 9847){j$=+"636944";}else if(o2 <= ("0" ^ 0)){j$=73844;}else if(o2 >= 4){j$=8666;}else if(o2 >= 51){j$=451;}else if(o2 >= +"338"){j$=+"5";}else if(o2 >= 744){j$=5;}else if(o2 >= 243){z4.p$(26);j$=z4.P6(64,"5");}else if(o2 > 6003){j$=7;}else if(o2 > 21475){j$=90;}else {j$=266;}x8+=2;}if(z4.K9(x8.toString(),x8.toString().length,35796) !== B4){if(o2 >= 9847){j$=636944;}else if(o2 <= 0){j$=73844;}else if(o2 >= "4" - 0){j$=8666;}else if(o2 >= 51){z4.W$(16);j$=z4.X3(3,"451");}else if(o2 >= 338){j$=5;}else if(o2 >= "744" << 32){j$=5;}else if(o2 >= ("243" | 51)){z4.p$(22);j$=z4.P6("5",0);}else if(o2 > 6003){j$=7;}else if(o2 > ("21475" | 33)){j$=90;}else {j$=266;}}if(o2 < 0.25){j$=0.0625;}else if(o2 < 1){j$=+"0.125";}else if(o2 < 5){j$=0.25;}else if(o2 < 20){j$=0.5;}else if(o2 < ("100" | 32)){j$=1;}else if(o2 < 200){j$=2;}else if(o2 < 500){j$=4;}else if(o2 < 1000){j$=+"5";}else if(o2 < 25000){j$=50;}else {j$=500;}}if(!f.ChartEngine.isDailyInterval(X0.interval)){j$/=10;}if(f.Market.Symbology.isForexSymbol(J5.symbol)){if(o2){c8=-178434979;S9=713969295;g$=2;for(var m$=1;z4.K9(m$.toString(),m$.toString().length,+"98896") !== c8;m$++){if(o2 > 2){j$=15636;}else if(o2 > 3){j$=86048;}else if(o2 <= 78){j$=3747;}else if(o2 >= 206){j$=425;}g$+=2;}if(z4.K9(g$.toString(),g$.toString().length,19338) !== S9){if(o2 > ("2" ^ 0)){j$=15636;}else if(o2 > +"3"){j$=86048;}else if(o2 <= 78){j$=3747;}else if(o2 >= 206){j$=425;}}if(o2 < 1){j$=0.001;}else if(o2 < 2){j$=0.002;}else if(o2 < 50){j$=+"0.02";}else if(o2 < 200){j$=0.2;}}if(f.ChartEngine.isDailyInterval(X0.interval)){j$*=10;}}J5.defaultChartStyleConfig.box=j$;}function S5(U6,z6,d0,V9,a8){U6.High=Math.max(z6,U6.High);U6.Low=Math.min(d0,U6.Low);U6.Close=V9;U6.Volume+=a8;}j$=parseFloat(j$);if(isNaN(j$) || j$ <= 0){if(X0.pandf){if(X0.pandf.box !== null){V$=-1304353240;Q3=-+"549707999";l8=2;for(var Q8=1;z4.q$(Q8.toString(),Q8.toString().length,+"2098") !== V$;Q8++){X0.pandf.box=null;l8+=2;}if(z4.q$(l8.toString(),l8.toString().length,19238) !== Q3){X0.pandf.box=1;}H5.changeOccurred("layout");}}J5.defaultChartStyleConfig.box=j$=1;}x0=Math.ceil(parseFloat(w7.reversal));if(x0 > 0 && x0 > w7.reversal){h4="l";h4+="a";h4+="yo";h4+="ut";X0.pandf.reversal=x0;H5.changeOccurred(h4);}else if(isNaN(x0) || x0 <= 0){if(X0.pandf){if(X0.pandf.reversal !== null){X7="lay";X7+="out";X0.pandf.reversal=null;H5.changeOccurred(X7);}}E5=861091602;e1=-1228406799;E2=2;for(var n3=1;z4.q$(n3.toString(),n3.toString().length,90695) !== E5;n3++){x0=J5.defaultChartStyleConfig.reversal;E2+=2;}if(z4.K9(E2.toString(),E2.toString().length,28174) !== e1){x0=J5.defaultChartStyleConfig.reversal;}}B1.box=j$;x0*=j$;j_=0.00000001;D1=(j$.toString() + (423.02 != 7660?(2610,495.13) !== 1270?3380 > 6916?(1.22e+3,792.86):".":9.95e+3:(7.19e+3,140.28))).split(("733.52" * 1,+"509") == (238.89,1827)?"542.49" - 0:3300 < 7233?".":(!({}),!""))[1].length;u3=[];z4.Q4();v6=0;for(var s1=0;s1 < q3.length;s1++){l1=q3[s1];if(!l1)continue;v6+=l1.Volume;Y9=l1.Close;N2=l1.Open;F9=l1.High;B5=l1.Low;N2=N2 || N2 === "0" * 1?N2:Y9;F9=F9 || F9 === 0?F9:Y9;B5=B5 || B5 === 0?B5:Y9;if(!u3.length && !I$.length){h8=N$(l1,v2(l1,N2,F9,B5,Y9,v6,F9 + j$,Number((Math.ceil(B5 / j$ - j_) * j$).toFixed(D1)),Number((Math.floor(F9 / j$ + j_) * j$).toFixed(D1))));h8.pfTrend="X";if(h8.pfOpen == h8.pfClose){h8.pfStepBack="-";}u3.push(h8);z4.p$(22);v6=z4.X3("0",0);continue;}z4.p$(3);var d4=z4.X3(0,1);X8=u3[u3.length - d4];if(!X8){X8=f.clone(I$[I$.length - 1]);}if(X8.pfTrend == "O"){if(B5 <= X8.pfClose - j$){X8.pfClose=Number((Math.ceil(B5 / j$ - j_) * j$).toFixed(D1));if(X8.pfStepBack == ((3430,5000) < 1556?(0x190a,765.23):"O")){X8.pfStepBack=null;}S5(X8,F9,B5,Y9,v6);}else if(F9 >= X8.pfClose + x0){F7=X8.pfClose + j$;E4=Number((Math.floor(F9 / j$ + j_) * j$).toFixed(D1));h8=v2(l1,N2,F9,B5,Y9,v6,X8.pfClose,F7,E4);if(F7 == E4){h8.pfStepBack="X";}if(X8.pfStepBack == "O"){X8.pfOpen=F7;X8.pfClose=E4;X8.pfTrend=(737.08,791.21) == (2166,6106)?(5.63e+3,"k"):(8518,42.94) <= (920.71,2272)?"X":!![];S5(X8,F9,B5,Y9,v6);}else {h8=N$(l1,h8);h8.pfTrend=+"4190" < 6707?985.15 != (6.5,"7350" << 64)?"X":1237 !== (2820,43)?!0:(0x15bf,7.21e+3):!1;u3.push(h8);}}else {S5(X8,F9,B5,Y9,v6);}v6=0;}else if(X8.pfTrend == (9480 <= 806.57?("a","0x1035" - 0):659 === (458.66,2560)?(0xee0,507):"X")){if(F9 >= X8.pfClose + j$){X8.pfClose=Number((Math.floor(F9 / j$ + j_) * j$).toFixed(D1));if(X8.pfStepBack == "X" || X8.pfStepBack == (137.02 != ("5960" << 32,6730)?5209 === (9313,62.3)?+"808.14":"-":(0x740,+"269.49"))){X8.pfStepBack=null;}S5(X8,F9,B5,Y9,v6);}else if(B5 <= X8.pfClose - x0){F7=X8.pfClose - j$;E4=Number((Math.ceil(B5 / j$ - j_) * j$).toFixed(D1));h8=v2(l1,N2,F9,B5,Y9,v6,X8.pfClose,F7,E4);if(F7 == E4){h8.pfStepBack=952.57 === ("7540" ^ 0,930.62)?(716.81,65) > (6613,"600.63" - 0)?"H":("777.70" * 1,721.48):"O";}if(X8.pfStepBack == (7808 === (3849,178.4)?(5605,4680) !== (5330,+"647")?(!!({}),6.45e+3):!({}):"X") || X8.pfStepBack == ((5653,51.18) != (3500,276.2)?(+"7942",1165) == (984.37,5820)?(8.79e+3,0xa3f):"-":+"120.87")){X8.pfOpen=F7;X8.pfClose=E4;X8.pfTrend=4593 == 1830?(9.10e+3,0x25e9):"O";S5(X8,F9,B5,Y9,v6);if(F7 != E4 && X8.pfStepBack == (9956 < +"3969"?(+"122.9",9900) >= (9387,4396)?2.38e+3:(245.98,329.49):"-")){X8.pfStepBack=null;}}else {h8=N$(l1,h8);h8.pfTrend="O";u3.push(h8);}}else {S5(X8,F9,B5,Y9,v6);}v6=0;}}return u3;};};/* eslint-enable */ /* jshint ignore:end */ /* ignore jslint end */ - - -let _exports = {CIQ:__CIQ_, SplinePlotter:__SplinePlotter_, timezoneJS:__timezoneJS_, $$:__$$_, $$$:__$$$_}; -export {__js_advanced_aggregations_ as aggregations}; -export {__js_advanced_drawingAdvanced_ as drawingAdvanced}; -export {__js_advanced_equationsAdvanced_ as equationsAdvanced}; -export {__js_advanced_highPerformanceMarkers_ as highPerformanceMarkers}; -export {__js_advanced_renderersAdvanced_ as renderersAdvanced}; -export {__js_advanced_studies_accumulationDistribution_ as accumulationDistribution}; -export {__js_advanced_studies_adx_ as adx}; -export {__js_advanced_studies_alligator_ as alligator}; -export {__js_advanced_studies_aroon_ as aroon}; -export {__js_advanced_studies_atr_ as atr}; -export {__js_advanced_studies_awesomeOscillator_ as awesomeOscillator}; -export {__js_advanced_studies_balanceOfPower_ as balanceOfPower}; -export {__js_advanced_studies_bollinger_ as bollinger}; -export {__js_advanced_studies_cci_ as cci}; -export {__js_advanced_studies_centerOfGravity_ as centerOfGravity}; -export {__js_advanced_studies_chaikin_ as chaikin}; -export {__js_advanced_studies_chande_ as chande}; -export {__js_advanced_studies_choppiness_ as choppiness}; -export {__js_advanced_studies_comparisonStudies_ as comparisonStudies}; -export {__js_advanced_studies_coppock_ as coppock}; -export {__js_advanced_studies_darvasBox_ as darvasBox}; -export {__js_advanced_studies_detrended_ as detrended}; -export {__js_advanced_studies_disparity_ as disparity}; -export {__js_advanced_studies_easeOfMovement_ as easeOfMovement}; -export {__js_advanced_studies_ehlerFisher_ as ehlerFisher}; -export {__js_advanced_studies_elder_ as elder}; -export {__js_advanced_studies_fractalChaos_ as fractalChaos}; -export {__js_advanced_studies_highLowStudies_ as highLowStudies}; -export {__js_advanced_studies_ichimoku_ as ichimoku}; -export {__js_advanced_studies_intradayMomentum_ as intradayMomentum}; -export {__js_advanced_studies_keltner_ as keltner}; -export {__js_advanced_studies_klinger_ as klinger}; -export {__js_advanced_studies_linearRegression_ as linearRegression}; -export {__js_advanced_studies_macd_ as macd}; -export {__js_advanced_studies_massIndex_ as massIndex}; -export {__js_advanced_studies_moneyFlow_ as moneyFlow}; -export {__js_advanced_studies_movingAverages_ as movingAverages}; -export {__js_advanced_studies_parabolicSAR_ as parabolicSAR}; -export {__js_advanced_studies_pivotPoints_ as pivotPoints}; -export {__js_advanced_studies_prettyGoodOscillator_ as prettyGoodOscillator}; -export {__js_advanced_studies_priceMomentumOscillator_ as priceMomentumOscillator}; -export {__js_advanced_studies_priceVolumeOscillator_ as priceVolumeOscillator}; -export {__js_advanced_studies_primeNumber_ as primeNumber}; -export {__js_advanced_studies_pring_ as pring}; -export {__js_advanced_studies_projectedVolume_ as projectedVolume}; -export {__js_advanced_studies_psychologicalLine_ as psychologicalLine}; -export {__js_advanced_studies_qstick_ as qstick}; -export {__js_advanced_studies_rainbow_ as rainbow}; -export {__js_advanced_studies_randomWalk_ as randomWalk}; -export {__js_advanced_studies_relativeVigor_ as relativeVigor}; -export {__js_advanced_studies_rsi_ as rsi}; -export {__js_advanced_studies_schaffTrendCycle_ as schaffTrendCycle}; -export {__js_advanced_studies_shinohara_ as shinohara}; -export {__js_advanced_studies_stochastics_ as stochastics}; -export {__js_advanced_studies_supertrend_ as supertrend}; -export {__js_advanced_studies_swingIndex_ as swingIndex}; -export {__js_advanced_studies_trendIntensity_ as trendIntensity}; -export {__js_advanced_studies_trix_ as trix}; -export {__js_advanced_studies_twiggsMoneyFlow_ as twiggsMoneyFlow}; -export {__js_advanced_studies_typicalPrice_ as typicalPrice}; -export {__js_advanced_studies_ulcerIndex_ as ulcerIndex}; -export {__js_advanced_studies_ultimateOscillator_ as ultimateOscillator}; -export {__js_advanced_studies_valuationLines_ as valuationLines}; -export {__js_advanced_studies_volatilityIndex_ as volatilityIndex}; -export {__js_advanced_studies_volumeProfile_ as volumeProfile}; -export {__js_advanced_studies_volumeStudies_ as volumeStudies}; -export {__js_advanced_studies_vortex_ as vortex}; -export {__js_advanced_studies_williamsMFI_ as williamsMFI}; - -export {__CIQ_ as CIQ, __SplinePlotter_ as SplinePlotter, __timezoneJS_ as timezoneJS, __$$_ as $$, __$$$_ as $$$}; - -/* global __TREE_SHAKE__ */ -if (typeof __TREE_SHAKE__ === "undefined" || !__TREE_SHAKE__) { - _exports.CIQ.activateImports( - __js_advanced_aggregations_, - __js_advanced_drawingAdvanced_, - __js_advanced_equationsAdvanced_, - __js_advanced_highPerformanceMarkers_, - __js_advanced_renderersAdvanced_, - __js_advanced_studies_accumulationDistribution_, - __js_advanced_studies_adx_, - __js_advanced_studies_alligator_, - __js_advanced_studies_aroon_, - __js_advanced_studies_atr_, - __js_advanced_studies_awesomeOscillator_, - __js_advanced_studies_balanceOfPower_, - __js_advanced_studies_bollinger_, - __js_advanced_studies_cci_, - __js_advanced_studies_centerOfGravity_, - __js_advanced_studies_chaikin_, - __js_advanced_studies_chande_, - __js_advanced_studies_choppiness_, - __js_advanced_studies_comparisonStudies_, - __js_advanced_studies_coppock_, - __js_advanced_studies_darvasBox_, - __js_advanced_studies_detrended_, - __js_advanced_studies_disparity_, - __js_advanced_studies_easeOfMovement_, - __js_advanced_studies_ehlerFisher_, - __js_advanced_studies_elder_, - __js_advanced_studies_fractalChaos_, - __js_advanced_studies_highLowStudies_, - __js_advanced_studies_ichimoku_, - __js_advanced_studies_intradayMomentum_, - __js_advanced_studies_keltner_, - __js_advanced_studies_klinger_, - __js_advanced_studies_linearRegression_, - __js_advanced_studies_macd_, - __js_advanced_studies_massIndex_, - __js_advanced_studies_moneyFlow_, - __js_advanced_studies_movingAverages_, - __js_advanced_studies_parabolicSAR_, - __js_advanced_studies_pivotPoints_, - __js_advanced_studies_prettyGoodOscillator_, - __js_advanced_studies_priceMomentumOscillator_, - __js_advanced_studies_priceVolumeOscillator_, - __js_advanced_studies_primeNumber_, - __js_advanced_studies_pring_, - __js_advanced_studies_projectedVolume_, - __js_advanced_studies_psychologicalLine_, - __js_advanced_studies_qstick_, - __js_advanced_studies_rainbow_, - __js_advanced_studies_randomWalk_, - __js_advanced_studies_relativeVigor_, - __js_advanced_studies_rsi_, - __js_advanced_studies_schaffTrendCycle_, - __js_advanced_studies_shinohara_, - __js_advanced_studies_stochastics_, - __js_advanced_studies_supertrend_, - __js_advanced_studies_swingIndex_, - __js_advanced_studies_trendIntensity_, - __js_advanced_studies_trix_, - __js_advanced_studies_twiggsMoneyFlow_, - __js_advanced_studies_typicalPrice_, - __js_advanced_studies_ulcerIndex_, - __js_advanced_studies_ultimateOscillator_, - __js_advanced_studies_valuationLines_, - __js_advanced_studies_volatilityIndex_, - __js_advanced_studies_volumeProfile_, - __js_advanced_studies_volumeStudies_, - __js_advanced_studies_vortex_, - __js_advanced_studies_williamsMFI_, - null - ); -} \ No newline at end of file diff --git a/chartiq/development/js/chartiq.js b/chartiq/development/js/chartiq.js deleted file mode 100644 index 7c15d427da..0000000000 --- a/chartiq/development/js/chartiq.js +++ /dev/null @@ -1,22205 +0,0 @@ -/***************************************************************************! - WARNING: this file is for internal development and debugging purposes only! - It may *not* be posted publicly under any circumstances without explicit - consent from ChartIQ. -****************************************************************************/ -/**! - * 8.2.0 - * Generation date: 2023-03-23T15:05:01.971Z - * Client name: deriv limited - * Package Type: Technical Analysis - * License type: annual - * Expiration date: "2024/04/01" - * Domain lock: ["127.0.0.1","localhost","deriv.com","deriv.app","deriv.me","binary.com","binary.sx","binary.me","binary.bot","deriv.be"] - * iFrame lock: true - */ - -/***********************************************************! - * Copyright by ChartIQ, Inc. - * Licensed under the ChartIQ, Inc. Developer License Agreement https://www.chartiq.com/developer-license-agreement -*************************************************************/ -/*************************************! DO NOT MAKE CHANGES TO THIS LIBRARY FILE!! !************************************* -* If you wish to overwrite default functionality, create a separate file with a copy of the methods you are overwriting * -* and load that file right after the library has been loaded, but before the chart engine is instantiated. * -* Directly modifying library files will prevent upgrades and the ability for ChartIQ to support your solution. * -*************************************************************************************************************************/ -/* eslint-disable no-extra-parens */ - - - - -let __js_core__init_ = (_exports) => { - - //------------------------------------------------------------------------------------------- - // Required objects and functions for initialization - //------------------------------------------------------------------------------------------- - - var timezoneJS = (_exports.timezoneJS = {}); - - /** - * Base namespace for CIQ library - * - * Previously `STX` - * @name CIQ - * @namespace - */ - function CIQ() {} - _exports.CIQ = CIQ; - - /** - * Creates a template for JavaScript inheritance. - * - * By default the constructor (ctor) is called with no arguments. - * - * @param {object} me The object to receive the inheritance. - * @param {object} ctor The parent class or object. - * @param {boolean} [autosuper=true] Set to false to prevent the base class constructor from being called automatically. - * @since 7.4.0 Replaces {@link Function#ciqInheritsFrom}. - * @memberof CIQ - */ - CIQ.inheritsFrom = function (me, ctor, autosuper) { - var parent = ctor.prototype || Object.getPrototypeOf(ctor); - - me.prototype = - autosuper !== false && typeof ctor === "function" - ? new ctor() - : Object.create(parent); - - Object.defineProperties(me.prototype, { - constructor: { - configurable: true, - enumerable: false, - value: me, - writable: true - }, - parent: { - configurable: true, - enumerable: false, - value: parent, - writable: true - } - }); - }; - - /** - * Extends an object, similar to jquery.extend() with a deep copy - * - * Only does a recursive deep copy if the *source* is plain object. - * - * @param {object} target Target object - * @param {object} source Original object - * @param {boolean} [shallow] If true then extend will not recurse through objects - * @return {object} Target object after extension - * @since - * - 5.1.0 Undefined properties do not copy to target object. - * - 5.2.0 Target of a deep copy may now be a class instance. - * @memberof CIQ - */ - CIQ.extend = function (target, source, shallow) { - var key, value; - - for (key in source) { - value = source[key]; - - if (target === value || value === undefined) { - continue; - } else if (value === null || shallow === true) { - target[key] = value; - } else if (value.constructor == Array) { - target[key] = value.slice(); - } else if (value.constructor == Object) { - // it is ok if `target[key]` is a class instance - target[key] = CIQ.extend( - typeof target[key] === "object" && target[key] !== null - ? target[key] - : {}, - value - ); - } else { - // `value` is a primitive type or a class instance (other than Object & Array) - target[key] = value; - } - } - - return target; - }; - - /** - * Activates an import. Should be called to activate an import for use by the API. If an - * import is not activated, its code is inaccessible and may be tree shaken by bundlers. Keeps - * track of which imports have been activated already so no import gets added more than - * once. - * - * Each feature, component, or add-on is considered an import. For example, studies, drawings, - * and {@link CIQ.RangeSlider} are imports. - * - * See the webpack examples (*webpack.config.js* and *webpack.config.minimal.js* in the root - * folder of the library) for detailed examples of how to import. - * - * **Note:** `DefinePlugin` needs to be included in the *webpack.config.js* file in order to - * achieve tree shaking. Otherwise, all imports are automatically activated without the need - * for the developer to explicitly call this function. - * - * @param {...object} imports A list of imports to add to the namespace. - * - * @memberof CIQ - * @since 8.0.0 - */ - CIQ.activateImports = function (...imports) { - let CIQ = this; - if (!CIQ.activatedImports) CIQ.activatedImports = {}; - imports.forEach((m) => { - if (typeof m == "function") { - if (!(m.__guid in CIQ.activatedImports)) { - // Add a guid onto the module to keep track of it - m.__guid = CIQ.uniqueID(true); - CIQ.activatedImports[m.__guid] = m.__name || m.name; - m(_exports); - } - } - }); - }; - - }; - - - let __js_core__polyfills_ = (_exports) => { - - - /*jshint -W079 */ // ignore redefinition of Event, CustomEvent - - var root = - typeof window !== "undefined" - ? window - : typeof global !== "undefined" - ? global - : {}; - - // IE 11 compatibility - { - var Event = function (event, params) { - var self = document.createEvent("Event"); - - self.initEvent( - event, - !!(params && params.bubbles), - !!(params && params.cancelable) - ); - - return self; - }; - - if (root.Event && typeof root.Event !== "function") { - Event.prototype = root.Event.prototype; - root.Event = Event; - } - - var CustomEvent = function (event, params) { - var self = document.createEvent("CustomEvent"); - - self.initCustomEvent( - event, - !!(params && params.bubbles), - !!(params && params.cancelable), - params && params.detail - ); - - return self; - }; - - if (root.CustomEvent && typeof root.CustomEvent !== "function") { - CustomEvent.prototype = root.CustomEvent.prototype; - root.CustomEvent = CustomEvent; - } - } - - // Node.js compatibility - { - if (typeof global !== "undefined") { - if (typeof global.CanvasRenderingContext2D === "undefined") - global.CanvasRenderingContext2D = function () {}; - } - } - - }; - - - let __js_core_browserDetect_ = (_exports) => { - - - var CIQ = _exports.CIQ; - - var nav = typeof navigator !== "undefined" ? navigator : { userAgent: "" }; - var userAgent = nav.userAgent; - var win = typeof window !== "undefined" ? window : {}; - var doc = typeof document !== "undefined" ? document : {}; - /** - * READ ONLY. Will be 'true' if the chart is running on an iPad - * @memberof CIQ - * @type boolean - */ - CIQ.ipad = - userAgent.indexOf("iPad") != -1 /* iOS pre 13 */ || - (nav.platform === "MacIntel" && nav.maxTouchPoints > 1); /* iPad OS 13 */ - /** - * READ ONLY. Will be 'true' if the chart is running on an iPhone - * @memberof CIQ - * @type boolean - */ - CIQ.iphone = userAgent.indexOf("iPhone") != -1; - /** - * READ ONLY. Will be 'true' if the chart is running on an Android OS device - * @memberof CIQ - * @type boolean - */ - CIQ.isAndroid = userAgent.toLowerCase().indexOf("android") > -1; - /** - * READ ONLY. Will be 'true' if the chart is running on a IE browser - * @memberof CIQ - * @type boolean - */ - CIQ.isIE = - userAgent.toLowerCase().indexOf("msie") > -1 || - userAgent.indexOf("Trident/") > -1; - /** - * READ ONLY. Will be 'true' if the chart is running on a Edge Legacy browser - * @memberof CIQ - * @type boolean - */ - CIQ.isEdge = userAgent.indexOf("Edge/") > -1; - /** - * READ ONLY. Will be 'true' if the chart is running on a Safari browser - * @memberof CIQ - * @type boolean - * @since 7.4.0 - */ - CIQ.isSafari = userAgent.indexOf("Safari/") > -1; - /** - * READ ONLY. Will be 'true' if the chart is running on an iOS 7 device - * @memberof CIQ - * @type boolean - */ - CIQ.isIOS7 = userAgent.match(/(iPad|iPhone);.*CPU.*OS 7_\d/i); - /** - * READ ONLY. Will be 'true' if the chart is running on an iOS 8 device - * @memberof CIQ - * @type boolean - */ - CIQ.isIOS8 = userAgent.match(/(iPad|iPhone);.*CPU.*OS 8_\d/i); - /** - * READ ONLY. Will be 'true' if the chart is running on an iOS 9 device - * @memberof CIQ - * @type boolean - */ - CIQ.isIOS9 = userAgent.match(/(iPad|iPhone);.*CPU.*OS 9_\d/i); - /** - * READ ONLY. Will be 'true' if the chart is running on an iOS 10 device - * @memberof CIQ - * @type boolean - */ - CIQ.isIOS10 = userAgent.match(/(iPad|iPhone);.*CPU.*OS 10_\d/i); - /** - * READ ONLY. Will be 'true' if the chart is running on an IOS7, IOS8, IOS9 or IOS10 device - * @memberof CIQ - * @type boolean - */ - CIQ.isIOS7or8 = CIQ.isIOS7 || CIQ.isIOS8 || CIQ.isIOS9 || CIQ.isIOS10; - /** - * READ ONLY. Will be 'true' if the chart is running on a mobile device ( CIQ.isAndroid, CIQ.ipad, or CIQ.iphone ) - * @memberof CIQ - * @type boolean - */ - CIQ.isMobile = CIQ.isAndroid || CIQ.ipad || CIQ.iphone; - /** - * READ ONLY. Will be 'true' if the chart is running on a touch capable device - * @memberof CIQ - * @type boolean - */ - CIQ.touchDevice = doc.ontouchstart !== undefined || nav.maxTouchPoints > 1; - /** - * READ ONLY. Will be 'true' if the chart is running on a MS Surface like device - * @memberof CIQ - * @type boolean - */ - CIQ.isSurface = - CIQ.touchDevice && (CIQ.isEdge || CIQ.isIE || userAgent.indexOf("Edg/") > -1); // Edg/ is Chromium Edge - /** - * READ ONLY. Will be 'true' if the chart is running on a Chrome browser - * @memberof CIQ - * @type boolean - */ - CIQ.is_chrome = userAgent.toLowerCase().indexOf("chrome") > -1 && !CIQ.isEdge; - /** - * READ ONLY. Will be 'true' if the chart is running on a Firefox browser - * @memberof CIQ - * @type boolean - */ - CIQ.isFF = userAgent.toLowerCase().indexOf("firefox") > -1; - /** - * READ ONLY. Will be 'true' if the chart is running from a MS Surface application - * @memberof CIQ - * @type boolean - */ - CIQ.isSurfaceApp = win.MSApp; - - /** - * READ ONLY. Will be 'true' if the chart supports web components - * @memberof CIQ - * @type boolean - * @since 6.1.0 - */ - CIQ.isWebComponentsSupported = - typeof document !== "undefined" && - "registerElement" in document && - "import" in document.createElement("link") && - "content" in document.createElement("template"); - /** - * READ ONLY. Will be 'true' if the chart is running from a device with no Keyboard ( CIQ.isMobile or CIQ.isSurfaceApp ) - * @memberof CIQ - * @type boolean - */ - CIQ.noKeyboard = CIQ.isMobile || CIQ.isSurfaceApp; - - }; - - - let __js_core_canvasutil_ = (_exports) => { - - - if (!_exports.SplinePlotter) _exports.SplinePlotter = {}; - - var CIQ = _exports.CIQ, - splinePlotter = _exports.SplinePlotter; - - /* - * Default implementation of plotSplinePrimitive. Load splines.js to get alternate splining. - */ - var plotSplinePrimitive = function ( - points, - tension, - context, - colorPatternChanges - ) { - var colorPatternIndex = 0; - if (!colorPatternChanges) colorPatternChanges = []; - function seeIfStrokeNeeded(i) { - if (colorPatternIndex == colorPatternChanges.length) return; - var colorPatternChange = colorPatternChanges[colorPatternIndex]; - if ( - colorPatternChange.coord[0] == points[i] && - colorPatternChange.coord[1] == points[i + 1] - ) { - context.stroke(); - context.strokeStyle = colorPatternChange.color; - context.setLineDash(colorPatternChange.pattern); - context.lineDashOffset = 0; - context.lineWidth = colorPatternChange.width; - context.beginPath(); - context.moveTo(points[i], points[i + 1]); //reset back to last point - colorPatternIndex++; - } - } - if (!tension || tension < 0) tension = 0; - var n = points.length; - /* - * This algorithm takes four points: the prior point, the starting point, the ending point, and the next point - * and draws a bezier curve between starting and ending point such that the next bezier curve will be a continuation - * of that smooth curve. - * The four control points are computed based on an offset of the four provided points. - * The offset is the product of a constant derived from a user-supplied "tension", and the difference between - * the points. For the first control point the difference is between the endpoint and the previous point. - * For the second control point the difference is between the next point and the starting point. - * On the first iteration we just set the previous point to the first point, and on the last iteration - * we set the next point to the ending point. - * The tension controls how far the control points will be from the start and end points. The tension is attenuated in each calculation - * based on the ratio of the length of the currently plotted segment and the segment adjacent to the control point being calculated. - * The control points are also limited in the case of 2 local extrema, to prevent "overshooting" of the min/max represented by those two points. - * Plot will therefore resemble a good approximation of a monotonic cubic spline. - * Inspired by: - * https://stackoverflow.com/questions/7054272/how-to-draw-smooth-curve-through-n-points-using-javascript-html5-canvas/49371349#49371349 (Roy Aarts) - * It's not an exact spline interpolation formula but it works well in that the curve can be controlled to not - * overshoot the point it is intersecting. - */ - context.moveTo(points[0], points[1]); - for (var i = 0; i < n - 3; i += 2) { - seeIfStrokeNeeded(i); - var p = []; - p[0] = { x: points[Math.max(0, i - 2)], y: points[Math.max(1, i - 1)] }; - p[1] = { x: points[i], y: points[i + 1] }; - p[2] = { x: points[i + 2], y: points[i + 3] }; - p[3] = { - x: points[Math.min(n - 2, i + 4)], - y: points[Math.min(n - 1, i + 5)] - }; - if (n === 4) tension = 0; // force a straight line between only two points - plotBetween(i, p, tension); - } - function plotBetween(i, p, tension) { - [1, 2].forEach((j) => { - p[j].cp = {}; // control points - ["x", "y"].forEach(function (ax) { - var tf = - 1 / - (1 + - Math.sqrt( - Math.pow(p[2 * j - 1].x - p[2 * j - 2].x, 2) + - Math.pow(p[2 * j - 1].y - p[2 * j - 2].y, 2) - ) / - Math.sqrt( - Math.pow(p[2].x - p[1].x, 2) + Math.pow(p[2].y - p[1].y, 2) - )); // tension factor, attenuates the tension based on ratio of line lengths - p[j].cp[ax] = - p[j][ax] + - (3 - 2 * j) * (p[j + 1][ax] - p[j - 1][ax]) * tension * (tf || 0); - // limits on focal points to force monotonicity - if (p[j].cp[ax] < Math.min(p[1][ax], p[2][ax])) - p[j].cp[ax] = Math.min(p[1][ax], p[2][ax]); - if (p[j].cp[ax] > Math.max(p[1][ax], p[2][ax])) - p[j].cp[ax] = Math.max(p[1][ax], p[2][ax]); - }); - }); - if (i === 0) { - context.quadraticCurveTo(p[2].cp.x, p[2].cp.y, p[2].x, p[2].y); - } else if (i === n - 4) { - // last pair of points - context.quadraticCurveTo(p[1].cp.x, p[1].cp.y, p[2].x, p[2].y); - } else { - context.bezierCurveTo( - p[1].cp.x, - p[1].cp.y, - p[2].cp.x, - p[2].cp.y, - p[2].x, - p[2].y - ); - } - } - }; - // If splines.js has not been included then set it with our default implementation - if (!_exports.SplinePlotter.plotSpline) - _exports.SplinePlotter.plotSpline = plotSplinePrimitive; - - /** - * Animation Loop - * - * Clears the canvas. Uses the fastest known method except on the legacy Android browser which had many problems! - * @param {object} canvas A valid HTML canvas object - * @param {object} [stx] A chart object, only necessary for old Android browsers on problematic devices - * @memberof CIQ - */ - CIQ.clearCanvas = function (canvas, stx) { - canvas.isDirty = false; - var ctx = canvas.context; - ctx.clearRect(0, 0, canvas.width, canvas.height); - if (CIQ.isAndroid && !CIQ.is_chrome && !CIQ.isFF) { - // Android browser last remaining - // one to need this clearing method - if (CIQ.ChartEngine.useOldAndroidClear && stx) { - ctx.fillStyle = stx.containerColor; - ctx.fillRect(0, 0, canvas.width, canvas.height); - ctx.clearRect(0, 0, canvas.width, canvas.height); - } - var w = canvas.width; - canvas.width = 1; - canvas.width = w; - } - var shimHasChildren = stx.chart.canvasShim.childNodes.length > 0; - if (stx.useBackgroundCanvas || shimHasChildren) { - stx.useBackgroundCanvas = shimHasChildren; - if (canvas == stx.chart.canvas) - CIQ.clearCanvas(stx.chart.backgroundCanvas, stx); - } - }; - - /** - * Sets the transparent parts of the canvas to the specified background color. Used to ensure a background when turning charts into images - * because normally the background is the background of the DIV container and not the canvas itself. - * @param {object} context An HTML canvas context - * @param {string} color The color to set the background. Any valid HTML canvas color. - * @param {number} width Width to apply color (Could be less than size of canvas) - * @param {number} height Height to apply color (Could be less than size of canvas if applying branding for instance) - * @memberof CIQ - */ - CIQ.fillTransparentCanvas = function (context, color, width, height) { - var compositeOperation = context.globalCompositeOperation; - context.globalCompositeOperation = "destination-over"; - context.fillStyle = color; - context.fillRect(0, 0, width, height); - context.globalCompositeOperation = compositeOperation; - }; - - /** - * Converts a box represented by two corner coordinates [tick0,value0] and [tick1,value1] into pixel coordinates. - * @param {CIQ.ChartEngine} stx The chartEngine - * @param {string} panelName Panel on which the coordinates reside - * @param {object} box Box to convert - * @param {number} [box.x0] - * @param {number} [box.y0] - * @param {number} [box.x1] - * @param {number} [box.y1] - * @return {object} A converted box - * @memberof CIQ - * @since 6.0.0 - */ - CIQ.convertBoxToPixels = function (stx, panelName, box) { - var panel = stx.panels[panelName]; - var bx0 = stx.pixelFromTick(box.x0, panel.chart); - var bx1 = stx.pixelFromTick(box.x1, panel.chart); - var by0 = - box.cy0 || box.cy0 === 0 - ? box.cy0 - : stx.pixelFromValueAdjusted(panel, box.x0, box.y0); - var by1 = - box.cy1 || box.cy1 === 0 - ? box.cy1 - : stx.pixelFromValueAdjusted(panel, box.x1, box.y1); - return { x0: bx0, x1: bx1, y0: by0, y1: by1 }; - }; - - /** - * Fills an area on the chart, usually created by a study. - * @param {CIQ.ChartEngine} stx The chart object - * @param {array} points The set of points, this is an array of chart coordinates in array form - * e.g. [[x1,y1],[x2,y2]]. The points should be arranged to form a loop; - * the loop need not be closed. - * @param {object} params parameters - * @param {string | object} [params.color] color, canvas gradient object or canvas pattern object to fill the area - * @param {number} [params.opacity] opacity of fill, 0 to 1. Defaults to 0.1 - * @param {number} [params.tension] Tension for splining. - * @param {string} [params.panelName] Name of panel to draw on. If omitted or invalid, area may fill over top or bottom of plot area - * @param {CIQ.ChartEngine.YAxis} [params.yAxis] The y-axis for the area (will use default axis if not specified) - * @since - * - 01-2015-20 Added `params.panelName`. - * - 4.0.0 Combined arguments into `params`. Added `tension`. - * - 5.2.0 Added `params.yAxis`. - * @memberof CIQ - */ - CIQ.fillArea = function (stx, points, params) { - if (!points.length) return; - var ctx = stx.chart.context; - var globalAlpha = ctx.globalAlpha; - var color = arguments[2], - opacity = arguments[3], - panelName = arguments[4], - tension = 0, - yAxis = null; - if (params && typeof params == "object") { - color = params.color; - opacity = params.opacity; - tension = params.tension; - panelName = params.panelName; - yAxis = params.yAxis; - } - if (!opacity && opacity !== 0) opacity = 0.2; - if (color == "auto") color = stx.defaultColor; - ctx.globalAlpha = opacity; - if (color) ctx.fillStyle = color; - - var b = Number.MAX_VALUE; - var t = b * -1; - var panel = stx.panels[panelName]; - if (panel) { - t = (yAxis || panel.yAxis).top; - b = (yAxis || panel.yAxis).bottom; - ctx.save(); - ctx.beginPath(); - ctx.rect(panel.left, t, panel.width, b - t); - ctx.clip(); - } - ctx.beginPath(); - var i; - if (tension) { - var flatPoints = []; - for (i = 0; i < points.length - 2; i++) { - flatPoints.push(points[i][0], points[i][1]); - } - splinePlotter.plotSpline(flatPoints, tension, ctx); - for (i = points.length - 2; i < points.length; i++) { - ctx.lineTo(Math.round(points[i][0]), Math.round(points[i][1])); - // Chrome 58/59 issue with gradient fills. Less severe if we round these last 2 points. - } - } else { - ctx.moveTo(points[0][0], points[0][1]); - for (i = 1; i < points.length; i++) { - ctx.lineTo(points[i][0], points[i][1]); - } - } - ctx.closePath(); - ctx.fill(); - if (panel) ctx.restore(); - - ctx.globalAlpha = globalAlpha; - }; - - /** - * Fills an area on the chart delimited by non intersecting top and bottom bands (channel), usually created by a study. - * @param {CIQ.ChartEngine} stx The chart object - * @param {object} parameters The configuration parameters - * @param {string} parameters.panelName The name of the panel - * @param {boolean} parameters.noSlopes If set then chart will fill rectangles with no transition lines between levels - * @param {string} parameters.topBand The name of the quote field to use as the top band - * @param {string} parameters.bottomBand The name of the quote field to use as the bottom band - * @param {number} parameters.opacity The color opacity/transparency as a decimal number (1= full opacity / no transparency) - * @param {string} parameters.color The fill color - * @memberof CIQ - * @since 4.1.2 Removed `quotes` argument; function always uses `chart.dataSegment`. - * @example - * CIQ.prepareChannelFill(stx,{"color":dngradient,"opacity":1,"panelName":sd.name,"topBand":"Zero "+sd.name,"bottomBand":"Under "+sd.name}); - */ - CIQ.prepareChannelFill = function (stx, parameters) { - if (!parameters || parameters instanceof Array) parameters = arguments[2]; // backwards compatibility for when quotes was the second argument - if (!parameters.gapDisplayStyle && parameters.gapDisplayStyle !== false) - parameters.gapDisplayStyle = parameters.gaps; - var panel = stx.panels[parameters.panelName], - chart = stx.chart, - strokeStyle = chart.context.strokeStyle; - - var saveParams = { - noDraw: parameters.noDraw, - gapDisplayStyle: parameters.gapDisplayStyle - }; - var chParams = CIQ.ensureDefaults(parameters, { - noDraw: true, - gapDisplayStyle: {}, - yAxis: panel.yAxis - }); - - var rcTop = stx.plotDataSegmentAsLine(parameters.topBand, panel, chParams); - var rcBottom = stx.plotDataSegmentAsLine( - parameters.bottomBand, - panel, - chParams - ); - parameters.noDraw = saveParams.noDraw; - parameters.gapDisplayStyle = saveParams.gapDisplayStyle; - var points = []; - for (var t = 0; t < rcTop.points.length; t += 2) { - points.push([rcTop.points[t], rcTop.points[t + 1]]); - } - for (var b = rcBottom.points.length - 1; b >= 0; b -= 2) { - points.push([rcBottom.points[b - 1], rcBottom.points[b]]); - } - CIQ.fillArea(stx, points, parameters); - return; - }; - - /** - * Fills an area on the chart delimited by a series line closed off by a horizontal threshold line, usually created by a study. - * - * Visual Reference:
- * ![Elder Force Shading](img-elder-force-shading.png "Elder Force Shading") - * - * @param {CIQ.ChartEngine} stx The chart object - * @param {object} parameters The configuration parameters - * @param {string} [parameters.panelName] The name of the panel - * @param {string} [parameters.band] The name of the quote field to use as the series line - * @param {number} [parameters.threshold] The price where the horizontal line hits yaxis/series to enclose the fill area. If not set will look to parameters.reverse to determine if threshold is the lowest or highest value of the plot. - * @param {boolean} [parameters.reverse] Valid only if parameters.threshold is not set. If this parameter is set to true, threshold will be highest value of plot. Otherwise, threshold will be lowest value of plot. - * @param {number} [parameters.direction] 1 to fill from the threshold upwards or -1 to fill from the threshold downwards - * @param {object} [parameters.edgeHighlight] Set to either a color or a Styles object as returned from {@link CIQ.ChartEngine#canvasStyle} to draw the threshold line. - * @param {object} [parameters.edgeParameters] The parameters to draw the threshold line as required by {@link CIQ.ChartEngine#plotLine} - * @param {object} [parameters.gapDisplayStyle] Gap object as set by See {@link CIQ.ChartEngine#setGapLines}. - * @param {number} [parameters.opacity] The color opacity/transparency as a decimal number (1= full opacity / no transparency). Default is 0.3. - * @param {boolean} [parameters.step] True for a step chart - * @param {number} [parameters.tension] Tension for splining. - * @param {string} [parameters.color] The fill color - * @param {boolean} [parameters.roundOffEdges] Round the first and last point's X value to the previous and next integer, respectively. - * @param {CIQ.ChartEngine.YAxis} [parameters.yAxis] The y-axis for the band (will use default axis if not specified) - * @memberof CIQ - * @since - * - 4.0.0 Added `parameters.reverse`, made `parameters.threshold` optional in case filling to top or bottom of panel. - * - 4.1.2 Removed `quotes` argument; function always uses `chart.dataSegment`. - * - 5.2.0 Added `params.yAxis`. - * - 5.2.0 Deprecated `parameters.gaps` and replaced with `parameters.gapDisplayStyle`. - * @example - * if(sd.outputs.Gain) CIQ.preparePeakValleyFill(stx,{panelName:sd.panel, band:"Result " + sd.name, threshold:sd.study.centerline, direction:1, color:sd.outputs.Gain}); - * if(sd.outputs.Loss) CIQ.preparePeakValleyFill(stx,{panelName:sd.panel, band:"Result " + sd.name, threshold:sd.study.centerline, direction:-1, color:sd.outputs.Loss}); - * @example - * // see visual reference for rendering image - * CIQ.Studies.displayElderForce=function(stx, sd, quotes){ - * CIQ.Studies.displaySeriesAsLine(stx, sd, quotes); - * var color=CIQ.Studies.determineColor(sd.outputs.Result); - * var panel=stx.panels[sd.panel]; - * var yAxis=sd.getYAxis(stx); - * var params={skipTransform:panel.name!=sd.chart.name, panelName:sd.panel, band:"Result " + sd.name, threshold:0, color:color, yAxis:yAxis}; - * params.direction=1; - * CIQ.preparePeakValleyFill(stx,params); - * params.direction=-1; - * CIQ.preparePeakValleyFill(stx,params); - * }; - */ - CIQ.preparePeakValleyFill = function (stx, parameters) { - if (!parameters || parameters instanceof Array) parameters = arguments[2]; // backwards compatibility for when quotes was the second argument - if (!parameters.gapDisplayStyle && parameters.gapDisplayStyle !== false) - parameters.gapDisplayStyle = parameters.gaps; - var panel = stx.panels[parameters.panelName], - yAxis = panel.yAxis, - chart = stx.chart, - context = chart.context, - strokeStyle = context.strokeStyle; - - var saveParams = { - noDraw: parameters.noDraw, - gapDisplayStyle: parameters.gapDisplayStyle - }; - var rc = stx.plotDataSegmentAsLine( - parameters.band, - panel, - CIQ.ensureDefaults(parameters, { noDraw: true, gapDisplayStyle: {} }) - ); - parameters.noDraw = saveParams.noDraw; - parameters.gapDisplayStyle = saveParams.gapDisplayStyle; - var threshold = parameters.threshold, - direction = parameters.direction, - reverse = parameters.reverse, - gapDisplayStyle = parameters.gapDisplayStyle; - - if (parameters.yAxis) yAxis = parameters.yAxis; - var yMax = -Number.MAX_VALUE, - yMin = Number.MAX_VALUE, - yThresh = reverse ? yMax : yMin; - if (threshold || threshold === 0) - yThresh = stx.pixelFromPrice(threshold, panel, yAxis); //where threshold hits yaxis - - var points = [], - length = rc.points.length; - for (var i = 0; i < length; i += 2) { - var x = rc.points[i], - y = rc.points[i + 1], - x1, - y1; - if (parameters.roundOffEdges) { - // round off to whole pixels so color interpolation does not occur when used with fillIntersection - if (i === 0) x = Math.floor(x); - else if (i + 2 == length) x = Math.ceil(x); - } - if (isNaN(y)) continue; - var limit = - (y > yThresh && direction > 0) || (y < yThresh && direction < 0); - if (!limit) { - points.push([x, y]); - yMax = Math.max(y, yMax); - yMin = Math.min(y, yMin); - } - if (i < length - 3) { - x1 = rc.points[i + 2]; - y1 = rc.points[i + 3]; - if ((y < yThresh && y1 > yThresh) || (y > yThresh && y1 < yThresh)) { - x += ((yThresh - y) * (x1 - x)) / (y1 - y); - points.push([x, yThresh]); - } - } - } - length = points.length; - if (!length) return; - - var edgeParameters = parameters.edgeParameters, - edgeHighlight = parameters.edgeHighlight; - if (edgeHighlight) { - if (edgeParameters.lineWidth > 100) edgeParameters.lineWidth = 1; // trap case where no width is specified in the css - context.save(); - context.beginPath(); - for (var p = 0; p < length - 1; p++) { - var point0 = points[p], - point1 = points[p + 1]; - if (point0[1] == yThresh && point1[1] == yThresh) continue; // here we avoid drawing a horizontal line along the threshold - if (point0[0] == point1[0] && stx.layout.candleWidth >= 1) { - // here we try to avoid drawing a vertical line to the threshold (like a gap boundary) - if ( - point0[1] == yThresh && - points[p - 1] && - points[p - 1][1] == yThresh - ) - continue; - if ( - point1[1] == yThresh && - points[p + 2] && - points[p + 2][1] == yThresh - ) - continue; - } - stx.plotLine( - CIQ.extend( - { - x0: point0[0], - x1: point1[0], - y0: point0[1], - y1: point1[1], - color: parameters.edgeHighlight, - type: "segment", - context: context, - confineToPanel: panel, - deferStroke: true - }, - edgeParameters - ) - ); - } - context.stroke(); - context.restore(); - } - if (!threshold && threshold !== 0) { - if (yAxis.flipped) reverse = !reverse; - yThresh = reverse - ? Math.min(yMin, yAxis.top) - : Math.max(yMax, yAxis.bottom); - } - points.push([points[length - 1][0], yThresh], [points[0][0], yThresh]); - - var opacity = parameters.opacity; - if (!opacity && opacity !== 0) parameters.opacity = 0.3; - CIQ.fillArea(stx, points, parameters); - // Now fill in the mountain area under the gap, if required - if ( - gapDisplayStyle && - gapDisplayStyle.color && - gapDisplayStyle.fillMountain && - !parameters.tension && - !CIQ.isTransparent(gapDisplayStyle.color) && - !CIQ.isTransparent( - parameters.color - ) /*need this last check for baseline_mountain to render properly*/ - ) { - context.save(); - if (context.fillStyle instanceof CanvasGradient) { - var hexGapColor = CIQ.colorToHex(gapDisplayStyle.color); - var gradient = context.createLinearGradient( - 0, - direction === 1 ? panel.top : panel.bottom, - 0, - yThresh - ); - gradient.addColorStop(0, CIQ.hexToRgba(hexGapColor, 60)); - gradient.addColorStop(1, CIQ.hexToRgba(hexGapColor, 10)); - context.fillStyle = gradient; - } else { - context.fillStyle = gapDisplayStyle.color; - } - var poly = []; - var myParams = { - opacity: parameters.opacity, - panelName: parameters.panelName - }; - context.beginPath(); - for (i = 0; i < rc.gapAreas.length; i++) { - var datum = rc.gapAreas[i]; - var start = datum.start; - var end = datum.end; - var thresh = datum.threshold; - if (start) { - poly = [ - [start[0], start[1]], - [start[0], thresh] - ]; - } else { - poly.push( - [end[0], thresh], - [end[0], parameters.step ? poly[0][1] : end[1]] - ); - } - if (poly.length == 4) { - CIQ.fillArea(stx, poly, myParams); - var lineParams = CIQ.extend( - { - x1: poly[3][0], - y0: poly[0][1], - type: "segment", - deferStroke: true, - context: context, - confineToPanel: panel - }, - gapDisplayStyle - ); - - if (parameters.step) { - stx.plotLine( - CIQ.extend({ x0: poly[0][0], y1: poly[0][1] }, lineParams) - ); - stx.plotLine( - CIQ.extend({ x0: poly[3][0], y1: poly[3][1] }, lineParams) - ); - } else { - stx.plotLine( - CIQ.extend({ x0: poly[0][0], y1: poly[3][1] }, lineParams) - ); - } - } - } - context.stroke(); - context.restore(); - } - parameters.opacity = opacity; - }; - - /** - * Fills an area on the chart delimited by intersecting bands. - * - * Bands can be anchored by different y-axis as determined by the `parameters.topAxis` and `parameters.bottomAxis` parameters. - * @param {CIQ.ChartEngine} stx The chart object - * @param {string} panelName The name of the panel - * @param {object} parameters The configuration parameters - * @param {string} parameters.topBand The name of the quote field to use as the top band - * @param {string} parameters.bottomBand The name of the quote field to use as the bottom band - * @param {string} [parameters.topSubBand] Name of the field within the top band to use, for example when plotting a series - * @param {string} [parameters.bottomSubBand] Name of the field within the bottom band to use, for example when plotting a series - * @param {string} parameters.topColor The color of the top band, used to fill in a cloud whose top edge is the topBand - * @param {string} parameters.bottomColor The color the bottom band, used to fill in a cloud whose top edge is the bottomBand - * @param {number} [parameters.tension] Tension for splining. - * @param {CIQ.ChartEngine.YAxis} parameters.topAxis The y-axis for the top band (will use default axis if not specified) - * @param {CIQ.ChartEngine.YAxis} parameters.bottomAxis The y-axis for the bottom band (will use default axis if not specified) - * @param {boolean} parameters.skipTransform If true then any transformations (such as comparison charting) will not be applied - * @param {number} parameters.opacity The color opacity/transparency as a decimal number (1= full opacity / no transparency). Default is 0.3. - * @memberof CIQ - * @since - * - 4.0.0 Changed `sd` argument to `panelName` argument. Added `parameters.topColor`, `parameters.bottomColor`, `parameters.opacity` and `parameters.skipTransform`. Removed `parameters.fillFuture`. - * - 4.1.2 Removed `quotes` argument; function always uses `chart.dataSegment`. - * @example - * var parameters={ - * topBand: "Leading Span A " + sd.name, - * bottomBand: "Leading Span B " + sd.name, - * topColor: "green", - * bottomColor: "red" - * }; - * CIQ.fillIntersecting(stx, sd.panel, parameters) - */ - CIQ.fillIntersecting = function (stx, panelName, parameters) { - if (!parameters || parameters instanceof Array) parameters = arguments[3]; // backwards compatibility for when quotes was the second argument - var topBand = parameters.topBand, - bottomBand = parameters.bottomBand; - var topSubBand = parameters.topSubBand, - bottomSubBand = parameters.bottomSubBand; - var topColor = parameters.topColor, - bottomColor = parameters.bottomColor; - var panel = panelName; - if (panel.panel) { - // backwards compatibility, where this argument is really a studyDescriptor - if (panel.outputs && panel.outputMap) { - if (!topColor) topColor = panel.outputs[panel.outputMap[topBand]]; - if (!bottomColor) - bottomColor = panel.outputs[panel.outputMap[bottomBand]]; - } - panel = panel.panel; - } - panel = stx.panels[panel]; - - //make a copy of what's there now - var context = stx.chart.context, - contextCanvas = context.canvas; - var sctx = stx.scratchContext; - if (!sctx) { - sctx = stx.scratchContext = contextCanvas.cloneNode(true).getContext("2d"); - } - var scratchCanvas = sctx.canvas; - scratchCanvas.height = contextCanvas.height; - scratchCanvas.width = contextCanvas.width; - scratchCanvas.context = sctx; - CIQ.clearCanvas(scratchCanvas, stx); - - //then fill the intersections - var alpha = 0.3; - if (parameters.opacity) alpha = parameters.opacity; - sctx.globalCompositeOperation = "xor"; - - stx.chart.context = sctx; - var params = { - band: topBand, - subField: topSubBand, - color: topColor, - opacity: 1, - panelName: panel.name, - yAxis: parameters.topAxis, - skipTransform: parameters.skipTransform, - tension: parameters.tension, - roundOffEdges: true, - step: parameters.step - }; - CIQ.preparePeakValleyFill(stx, params); - - CIQ.extend(params, { - band: bottomBand, - subField: bottomSubBand, - color: bottomColor, - yAxis: parameters.bottomAxis - }); - CIQ.preparePeakValleyFill(stx, params); - - //now redraw with correct alpha - context.save(); - context.globalAlpha = alpha; - context.drawImage(scratchCanvas, 0, 0); - context.restore(); - - stx.chart.context = context; - }; - - /** - * Draws an item in the legend and returns the position for the next item - * @param {CIQ.ChartEngine} stx The chart object - * @param {array} xy An X,Y tuple (from chart.legend) - * @param {string} label The text to print in the item - * @param {string} color The color for the background of the item - * @param {number} [opacity] The color for the background of the item - * @return {array} A tuple containing the X,Y position for the next the item - * @memberof CIQ - */ - CIQ.drawLegendItem = function (stx, xy, label, color, opacity) { - if (!opacity) opacity = 1; - var x = xy[0], - y = xy[1], - w = 10, - h = 10; - var context = stx.chart.context; - context.globalAlpha = opacity; - context.fillStyle = color; - context.fillRect(x, y, w, h); - context.globalAlpha = 1; - x += w + 2; // 2 px spacing between box and text - context.fillStyle = stx.defaultColor; - context.fillText(label, x, y); - x += context.measureText(label).width + 6; // 6 px spacing between labels - return [x, y]; - }; - - /** - * Default function to draw a legend for the series that are displayed on the chart. - * - * See {@link CIQ.ChartEngine.Chart#legendRenderer} for activation and customization details. - * - * @param {CIQ.ChartEngine} stx The chart object to draw - * @param {object} params parameters for drawing the legend - * @param {CIQ.ChartEngine.Chart} [params.chart] The chart object - * @param {object} [params.legendColorMap] A map of series names to colors and display symbols ( example IBM:{color:'red', display:'Int B M'} ) - * @param {object} [params.coordinates] Coordinates upon which to draw the items, in pixels relative to top left of panel ( example {x:50, y:0} ). If null, uses chart.legend - * @param {boolean} [params.noBase] Set to true to not draw the base (the chart symbol's color) in the legend - * @memberof CIQ - */ - CIQ.drawLegend = function (stx, params) { - var coordinates = params.coordinates; - var context = stx.chart.context; - context.textBaseline = "top"; - var rememberFont = context.font; - stx.canvasFont("stx-legend", context); - - var chart = params.chart || stx.chart; - if (!coordinates) coordinates = chart.legend; - var xy = [coordinates.x, coordinates.y]; - var lineColor = stx.defaultColor; - - for (var i = 0; i < 2; i++) { - // loop twice, first for the base then again for the series - for (var field in params.legendColorMap) { - var legendItem = params.legendColorMap[field]; - if (legendItem.isBase && (i || params.noBase)) continue; - if (!legendItem.isBase && !i) continue; - var c; - if (legendItem.color instanceof Array) { - var colors = legendItem.color; - for (c = colors.length - 1; c >= 0; c--) { - if (CIQ.isTransparent(colors[c])) colors.splice(c, 1); - } - if (colors.length > 1) { - var grd = context.createLinearGradient( - xy[0], - xy[1], - xy[0] + 10, - xy[1] - ); - for (c = 0; c < colors.length; c++) { - grd.addColorStop(c / (colors.length - 1), colors[c]); - } - lineColor = grd; - } else if (colors.length > 0) { - lineColor = colors[0]; - } else { - lineColor = stx.getCanvasColor("stx_line_chart"); - } - } else if (legendItem.color) { - lineColor = legendItem.color; - } else { - lineColor = null; - } - if (lineColor) { - var display = field; - if (legendItem.display) { - display = legendItem.display; - } - if (!display) { - if (chart.symbolDisplay) { - display = chart.symbolDisplay; - } else { - display = chart.symbol; - } - } - if (xy[0] + context.measureText(display).width > chart.panel.right) { - xy = [ - coordinates.x, - coordinates.y + context.measureText("M").width + 6 - ]; // M is squarish, with width roughly equaling height: https://stackoverflow.com/questions/1134586/how-can-you-find-the-height-of-text-on-an-html-canvas - } - xy = CIQ.drawLegendItem( - stx, - xy, - display, - lineColor, - legendItem.opacity - ); - } - } - } - context.font = rememberFont; - }; - - }; - - - let __js_core_color_ = (_exports) => { - - - var CIQ = _exports.CIQ; - - /** - * Checks if two colors are the same. Will compare alpha channel is provided as well. - * @param {string} color1 First color, in rgb, rgba, css hex, or literal format - * @param {string} color2 Second color, in rgb, rgba, css hex, or literal format - * @return {boolean} true if equivalent - * @example - * var isSame=CIQ.colorsEqual("rgba (255,255,255,0.3)", "#FFFFFF"); - * returns false - * var isSame=CIQ.colorsEqual("rgba (255,255,255,1)", "#FFFFFF"); - * returns true - * @memberof CIQ - * @since 4.0.0 - */ - CIQ.colorsEqual = function (color1, color2) { - if (color1 == color2) return true; - if (!color1 && !color2) return true; - if (!color1 || !color2) return false; - if (color1 == "transparent") color1 = "rgba(0,0,0,0)"; - if (color2 == "transparent") color2 = "rgba(0,0,0,0)"; - var alpha = /^rgba\(.*,(.+)\)/; - var rgba1 = color1.match(alpha); - var rgba2 = color2.match(alpha); - rgba1 = rgba1 ? parseFloat(rgba1[1]) : 1; - rgba2 = rgba2 ? parseFloat(rgba2[1]) : 1; - if (rgba1 != rgba2) return false; - - var first = CIQ.colorToHex(color1); - var second = CIQ.colorToHex(color2); - return first.toLowerCase() == second.toLowerCase(); - }; - - /** - * Converts an rgb or rgba color to a hex color - * @param {string} color The rgb or rgba color, such as in CSS format - * @return {string} The hex color. If "transparent" or no color is sent in, #000000 will be assumed - * @example - * var hexColor=CIQ.colorToHex("rgba (255,255,255,0.3)"); - * @memberof CIQ - * @since 4.0.0 Converts 3 char hex (#FFC) to six characters (#FFFFCC) - */ - CIQ.colorToHex = function (color) { - if (!CIQ.colorToHexMapping) CIQ.colorToHexMapping = {}; - if (!color || color == "transparent") color = "#000000"; - if (CIQ.colorToHexMapping[color]) return CIQ.colorToHexMapping[color]; - if (color.substr(0, 1) === "#") { - if (color.length == 4) { - color = CIQ.colorToHexMapping[color] = - "#" + - Array(3).join(color.substr(1, 1)) + - Array(3).join(color.substr(2, 1)) + - Array(3).join(color.substr(3, 1)); - } - return color; - } - var digits = /(.*?)rgb\((\d+), ?(\d+), ?(\d+)\)/.exec(color); - if (!digits) digits = /(.*?)rgba\((\d+), ?(\d+), ?(\d+),.*\)/.exec(color); - // Converts a color name to hex - function toHex(color) { - if (typeof document === "undefined") return "#000000"; - var ta = document.querySelector(".ciq_color_converter"); - if (!ta) { - ta = document.createElement("textarea"); - ta.className = "ciq_color_converter"; - ta.style.display = "none"; - document.body.appendChild(ta); - } - ta.style.color = "#000000"; //reset; - ta.style.color = color; - var value; - - value = getComputedStyle(ta).getPropertyValue("color"); - digits = /(.*?)rgb\((\d+), ?(\d+), ?(\d+)\)/.exec(value); - if (digits) return CIQ.colorToHex(value); - else if (value.substr(0, 1) === "#") return value; - return color; - } - if (!digits) { - var hexResult = toHex(color); - CIQ.colorToHexMapping[color] = hexResult; - return hexResult; - } - - var red = parseFloat(digits[2]); - var green = parseFloat(digits[3]); - var blue = parseFloat(digits[4]); - - var rgb = blue | (green << 8) | (red << 16); - var hexString = rgb.toString(16); - // fill with leading 0 if not 6 digits. - for (var i = hexString.length; i < 6; i++) { - hexString = "0" + hexString; - } - var s = digits[1] + "#" + hexString; - CIQ.colorToHexMapping[color] = s; - return s; - }; - - /** - * Converts color to rgba. This does not accept literal color names such as "black" - * @param {string} color The hex rgb or rgba color, such as in CSS format - * @param {number} [opacity] The 'alpha' value. Defaults to full opacity (100%) - * @return {string} The rgba color - * @example - * var rgba=CIQ.hexToRgba('rgb(0, 115, 186)'); - * var rgba=CIQ.hexToRgba('#0073BA'); - * @memberof CIQ - */ - CIQ.hexToRgba = function (color, opacity) { - if (!color || color == "transparent") color = "rgba(0,0,0,0)"; - if (color.substr(0, 4) === "rgba") { - var digits = /(.*?)rgba\((\d+), ?(\d+), ?(\d+), ?(\d*\.?\d*)\)/.exec(color); - var a = digits[5]; - if (opacity || opacity === 0) a = opacity; - if (a > 1) a = a / 100; - return ( - "rgba(" + digits[2] + "," + digits[3] + "," + digits[4] + "," + a + ")" - ); - } else if (color.substr(0, 3) === "rgb") { - color = CIQ.colorToHex(color); - } - if (!opacity && opacity !== 0) opacity = 100; // default to full opacity - if (opacity <= 1) opacity = opacity * 100; // handle decimal opacity (css style) - - color = color.replace("#", ""); - var r = parseInt(color.slice(0, 2), 16); - var g = parseInt(color.slice(2, 4), 16); - var b = parseInt(color.slice(4, 6), 16); - - if (isNaN(r) || isNaN(g) || isNaN(b)) { - console.log("CIQ.hexToRgba: invalid hex :", color); - return null; - } - - return "rgba(" + r + "," + g + "," + b + "," + opacity / 100 + ")"; - }; - - /** - * Converts a color to the internal format used by the browser. This allows - * interchange of hex, rgb, rgba colors - * @param {string} color A CSS color - * @return {string} The native formatted color - * @memberof CIQ - */ - CIQ.convertToNativeColor = function (color) { - var a = document.createElement("DIV"); - a.style.color = color; - a.style.display = "none"; - document.body.appendChild(a); - var c = getComputedStyle(a).color; - document.body.removeChild(a); - return c; - }; - /** - * Returns true if the color is transparent. In particular it checks rgba status. Note that the charting engine - * often interprets transparent colors to mean that a color should be automatically determined based on the brightness - * of the background. - * @param {string} color The color (from CSS) - * @return {boolean} True if transparent - * @memberof CIQ - */ - CIQ.isTransparent = function (color) { - if (!color) return false; - if (color == "transparent") return true; - var digits = /(.*?)rgba\((\d+), ?(\d+), ?(\d+), ?(\d*\.?\d*)\)/.exec(color); - if (digits === null) return false; - if (parseFloat(digits[5]) === 0) return true; - return false; - }; - - /** - * Converts a color from hex or rgb format to Hue, Saturation, Value. - * @param {string} color The color (from CSS) - * @return {array} [Hue, Saturation, Value], or null if invalid color. - * @memberof CIQ - */ - CIQ.hsv = function (color) { - var hex = CIQ.colorToHex(color); - if (hex.substr(0, 1) === "#") hex = hex.slice(1); - // fill with leading 0 if not 6 digits. - for (var i = hex.length; i < 6; i++) { - hex = "0" + hex; - } - var r = parseInt(hex.slice(0, 2), 16); - var g = parseInt(hex.slice(2, 4), 16); - var b = parseInt(hex.slice(4, 6), 16); - var computedH = 0; - var computedS = 0; - var computedV = 0; - - //remove spaces from input RGB values, convert to int - r = parseInt(("" + r).replace(/\s/g, ""), 10); - g = parseInt(("" + g).replace(/\s/g, ""), 10); - b = parseInt(("" + b).replace(/\s/g, ""), 10); - - if ( - r === null || - g === null || - b === null || - isNaN(r) || - isNaN(g) || - isNaN(b) - ) { - console.log("CIQ.hsv: invalid color :", color); - return null; - } - if (r < 0 || g < 0 || b < 0 || r > 255 || g > 255 || b > 255) { - return null; - } - r = r / 255; - g = g / 255; - b = b / 255; - var minRGB = Math.min(r, Math.min(g, b)); - var maxRGB = Math.max(r, Math.max(g, b)); - - // Black-gray-white - if (minRGB == maxRGB) { - computedV = minRGB; - return [0, 0, computedV]; - } - - // Colors other than black-gray-white: - var d = r == minRGB ? g - b : b == minRGB ? r - g : b - r; - var h = r == minRGB ? 3 : b == minRGB ? 1 : 5; - computedH = 60 * (h - d / (maxRGB - minRGB)); - computedS = (maxRGB - minRGB) / maxRGB; - computedV = maxRGB; - return [computedH, computedS, computedV]; - }; - - CIQ.hsl = function (color) { - var hex = CIQ.colorToHex(color); - if (hex.substr(0, 1) === "#") hex = hex.slice(1); - // fill with leading 0 if not 6 digits. - for (var i = hex.length; i < 6; i++) { - hex = "0" + hex; - } - var r = parseInt(hex.slice(0, 2), 16); - var g = parseInt(hex.slice(2, 4), 16); - var b = parseInt(hex.slice(4, 6), 16); - - r /= 255; - g /= 255; - b /= 255; - var max = Math.max(r, g, b), - min = Math.min(r, g, b); - var h, - s, - l = (max + min) / 2; - - if (max == min) { - h = s = 0; // achromatic - } else { - var d = max - min; - s = l > 0.5 ? d / (2 - max - min) : d / (max + min); - switch (max) { - case r: - h = (g - b) / d + (g < b ? 6 : 0); - break; - case g: - h = (b - r) / d + 2; - break; - case b: - h = (r - g) / d + 4; - break; - } - h /= 6; - } - - return [h, s, l]; - }; - - /** - * Converts an HSL color value to RGB. The conversion formula is adapted from - * {@link http://en.wikipedia.org/wiki/HSL_color_space}. - * - * Assumes the values for `h`, `s`, and `l` are contained in the set [0, 1] and the returned - * RGB values are in the set [0, 255]. - * - * @param {number} h Hue - * @param {number} s Saturation - * @param {number} l Lightness - * @return {Array} The RGB representation of the color. - * - * @memberof CIQ - * @since 7.5.0 - */ - CIQ.hslToRgb = function (h, s, l) { - var r, g, b; - - if (s === 0) { - r = g = b = l; // achromatic - } else { - var hue2rgb = function hue2rgb(p, q, t) { - if (t < 0) t += 1; - if (t > 1) t -= 1; - if (t < 1 / 6) return p + (q - p) * 6 * t; - if (t < 1 / 2) return q; - if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6; - return p; - }; - - var q = l < 0.5 ? l * (1 + s) : l + s - l * s; - var p = 2 * l - q; - r = hue2rgb(p, q, h + 1 / 3); - g = hue2rgb(p, q, h); - b = hue2rgb(p, q, h - 1 / 3); - } - - return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)]; - }; - - /** - * Chooses either a white or black foreground color depending on the "lightness" of the background color. Note that this simply - * checks if the value is above the hue which works well but not ideally for red colors which the human eye interprets differently. - * More complex algorithms are available but chartists rarely use red as a background color. - * @param {string} backgroundColor The background color (CSS format) - * @return {string} Either #000000 (black) or #FFFFFF (white) depending on which will look best on the given background color - * @memberof CIQ - */ - CIQ.chooseForegroundColor = function (backgroundColor) { - var hex = CIQ.colorToHex(backgroundColor); - var r = parseInt(hex.slice(1, 3), 16); - var g = parseInt(hex.slice(3, 5), 16); - var b = parseInt(hex.slice(5, 7), 16); - // Compare relative luminance (https://www.w3.org/TR/WCAG20/#relativeluminancedef) to 100 - return 0.2126 * r + 0.7152 * g + 0.0722 * b < 100 ? "#FFFFFF" : "#000000"; // per ITU-R BT.709 - /*if(r+g+b>318) return "#000000"; - var hsl=CIQ.hsl(backgroundColor); - var l=hsl[2]; - if(l>hsl[0]) return "#000000"; - //if(l && l>0.5) return "#000000"; - return "#FFFFFF";*/ - }; - - /** - * Convert a pattern type to an array useful for setting the context.setLineDash - * @param {number} [width=1] A valid lineWidth from 1 - * @param {string} [pattern=solid] A valid pattern (solid, dotted, dashed) - * @return {array} The array representing pixels of draw/skip etc. Use it as argument to context.setLineDash() - * @memberof CIQ - * @since 4.0.0 - */ - CIQ.borderPatternToArray = function (width, pattern) { - if (!pattern) return []; - if (pattern instanceof Array) return pattern; - if (pattern == "dotted") return [width, width]; - if (pattern == "dashed") return [width * 5, width * 5]; - if (pattern != "solid" && pattern != "none") - console.log('Unsupported pattern "' + pattern + '"; defaulting to "solid"'); - return []; - }; - - /** - * Gets the background color of an element by traversing up the parent stack. - * @param {HTMLElement} el The element to examine - * @return {string} The background color - * @memberof CIQ - */ - CIQ.getBackgroundColor = function (el) { - var bgColor = null; - while (!bgColor || CIQ.isTransparent(bgColor)) { - var cStyle = getComputedStyle(el); - if (!cStyle) return; - bgColor = cStyle.backgroundColor; - if (CIQ.isTransparent(bgColor)) bgColor = "transparent"; - el = el.parentNode; - if (!el || !el.tagName) break; - } - if (!bgColor || bgColor == "transparent") bgColor = "#FFFFFF"; - return bgColor; - }; - - }; - - - let __js_core_date_ = (_exports) => { - - - var CIQ = _exports.CIQ, - timezoneJS = _exports.timezoneJS; - - CIQ.monthLetters = ["J", "F", "M", "A", "M", "J", "J", "A", "S", "O", "N", "D"]; - CIQ.monthAbv = [ - "Jan", - "Feb", - "Mar", - "Apr", - "May", - "Jun", - "Jul", - "Aug", - "Sep", - "Oct", - "Nov", - "Dec" - ]; - - /* Enumerated types for time units */ - CIQ.MILLISECOND = 1; - CIQ.SECOND = 1000; - CIQ.MINUTE = 60 * CIQ.SECOND; - CIQ.HOUR = 60 * CIQ.MINUTE; - CIQ.DAY = 24 * CIQ.HOUR; - CIQ.WEEK = 7 * CIQ.DAY; - CIQ.MONTH = 31 * CIQ.DAY; - CIQ.YEAR = 366 * CIQ.DAY; - CIQ.DECADE = 10 * CIQ.YEAR - 7 * CIQ.DAY; - - CIQ.yyyymmddhhmmssmmmrx = new RegExp("\\d{17}"); - - /** - * Converts a string form date into a JavaScript Date object with time. Supports various standard date formats - * @param {string} dt String form of a date (such as yyyymmddhhmm, yyyy-mm-dd hh:mm, etc) - * @return {date} A JavaScript Date object - * @memberof CIQ - */ - CIQ.strToDateTime = function (dt) { - if (!dt || dt.getFullYear) return dt; //if passing in a JS date, return it. - var myDateArray = []; - var y, m, d, h, mn, sc, ms; - if (dt.length == 12 || dt.length == 14) { - // yyyymmddhhmm[ss] - y = parseFloat(dt.substring(0, 4)); - m = parseFloat(dt.substring(4, 6)) - 1; - d = parseFloat(dt.substring(6, 8)); - h = parseFloat(dt.substring(8, 10)); - mn = parseFloat(dt.substring(10, 12)); - sc = parseFloat(dt.substring(12, 14)) || 0; - return new Date(y, m, d, h, mn, sc, 0); - } else if (CIQ.yyyymmddhhmmssmmmrx.test(dt)) { - y = parseFloat(dt.substring(0, 4)); - m = parseFloat(dt.substring(4, 6)) - 1; - d = parseFloat(dt.substring(6, 8)); - h = parseFloat(dt.substring(8, 10)); - mn = parseFloat(dt.substring(10, 12)); - sc = parseFloat(dt.substring(12, 14)); - ms = parseFloat(dt.substring(14, 17)); - return new Date(y, m, d, h, mn, sc, ms); - } - var lr = [dt]; - var t = dt.indexOf("T"); - if (t != -1) { - var afterT = dt.substring(t); - if ( - afterT.indexOf("Z") != -1 || - afterT.indexOf("-") != -1 || - afterT.indexOf("+") != -1 - ) { - return new Date(dt); // utc time if it contains actual timezone information - } - lr = dt.split("T"); - } else if (dt.indexOf(" ") != -1) lr = dt.split(" "); - - if (lr[0].indexOf("/") != -1) myDateArray = lr[0].split("/"); - else if (lr[0].indexOf("-") != -1) myDateArray = lr[0].split("-"); - else return CIQ.strToDate(dt); //give up, maybe it's just a date - - var year = parseFloat(myDateArray[2], 10); - if (myDateArray[0] && myDateArray[0].length == 4) { - // YYYY-MM-DD - year = parseFloat(myDateArray[0], 10); - myDateArray[0] = myDateArray[1]; - myDateArray[1] = myDateArray[2]; - } - - if (lr.length > 1) { - var ampm = lr[2]; - lr = lr[1].split(":"); - if (ampm) { - if (lr[0] == "12" && ampm.toUpperCase() == "AM") lr[0] = 0; - else if (lr[0] != "12" && ampm.toUpperCase() == "PM") - lr[0] = parseInt(lr[0], 10) + 12; - } - var sec = 0, - msec = 0; - if (lr.length == 3) { - if (lr[2].indexOf(".") == -1) { - sec = parseInt(lr[2], 10); - } else { - sec = lr[2].split("."); - if (sec[1].length == 3) { - msec = sec[1]; - sec = sec[0]; - } - } - } - return new Date( - year, - myDateArray[0] - 1, - myDateArray[1], - lr[0], - lr[1], - sec, - msec - ); - } - return new Date(year, myDateArray[0] - 1, myDateArray[1], 0, 0, 0, 0); - }; - - /** - * Converts a string form date into a JavaScript object. Only use if you know that the string will not include a time, otherwise use @see CIQ.strToDateTime - * @param {string} dt - Date in string format such as MM/DD/YY or YYYYMMDD or 2014-10-25T00:00:00+00:00 or 201506170635 - * @return {date} JavaScript date object -new Date()- - * @memberof CIQ - */ - CIQ.strToDate = function (dt) { - var myDateArray; - if (dt.indexOf("/") != -1) myDateArray = dt.split("/"); - else if (dt.indexOf("-") != -1) myDateArray = dt.split("-"); - else if (dt.length >= 8) { - return new Date( - parseFloat(dt.substring(0, 4)), - parseFloat(dt.substring(4, 6)) - 1, - parseFloat(dt.substring(6, 8)) - ); - } else { - return new Date(); - } - if (myDateArray.length < 3) { - // didn't find enough data for month, day and year. - return new Date(); - } - if (myDateArray[2].indexOf(" ") != -1) { - myDateArray[2] = myDateArray[2].substring(0, myDateArray[2].indexOf(" ")); - } else if (myDateArray[2].indexOf("T") != -1) { - myDateArray[2] = myDateArray[2].substring(0, myDateArray[2].indexOf("T")); - } - var year = parseFloat(myDateArray[2], 10); - if (year < 20) year += 2000; - if (myDateArray[0].length == 4) { - // YYYY-MM-DD - year = parseFloat(myDateArray[0], 10); - myDateArray[0] = myDateArray[1]; - myDateArray[1] = myDateArray[2]; - } - return new Date(year, myDateArray[0] - 1, myDateArray[1]); - }; - - /** - * Formats a date according to an input string; for example, "YYYY:MM:dd hh:mm". - * - * All matching tokens in the input string are replaced by their corresponding date or time value. - * Supported tokens and their values are as follows: - * - YYYY = full year - * - MM = month - * - dd = day - * - HH = hours (24-hour format) - * - hh = hours (12-hour format) - * - mm = minutes - * - ss = seconds - * - SSS = milliseconds - * - * Values are formatted with leading zeroes as necessary. - * - * **Note:** This function is less performant than the special-purpose format functions defined in - * this namespace, such as {@link CIQ.mmddyyyy} and {@link CIQ.yyyymmdd}, and should be used - * accordingly. - * - * @param {Date} dt The date to format. - * @param {string} str The format for the date. - * @return {string} The formatted date string. - * - * @memberof CIQ - * @since 8.1.0 - */ - CIQ.dateToStr = function (dt, str) { - const has = (token) => str.includes(token); - const pad = (num, digits = 2) => ("0".repeat(digits) + num).slice(-digits); - const fmt = (exp, val) => (str = str.replace(exp, val)); - const max = (val, max) => (val > max ? val - max : val); - if (has("YYYY")) fmt(/YYYY/g, dt.getFullYear()); - if (has("MM")) fmt(/MM/g, pad(dt.getMonth() + 1)); - if (has("dd")) fmt(/dd/g, pad(dt.getDate())); - if (has("HH")) fmt(/HH/g, pad(dt.getHours())); - if (has("hh")) fmt(/hh/g, pad(max(dt.getHours() || 12, 12))); - if (has("mm")) fmt(/mm/g, pad(dt.getMinutes())); - if (has("ss")) fmt(/ss/g, pad(dt.getSeconds())); - if (has("SSS")) fmt(/SSS/g, pad(dt.getMilliseconds(), 3)); - return str; - }; - - /** - * Converts a JavaScript Date or string form date to mm/dd/yyyy format - * @param {string} dt Date in JavaScript Date or string format such as YYYY-MM-DD - * @return {string} Date in mm/dd/yyyy format - * @memberof CIQ - * @since 2016-07-16 - */ - CIQ.mmddyyyy = function (dt) { - if (typeof dt === "string") { - dt = CIQ.strToDate(dt); - } - - var m = dt.getMonth() + 1; - if (m < 10) m = "0" + m; - var d = dt.getDate(); - if (d < 10) d = "0" + d; - return m + "/" + d + "/" + dt.getFullYear(); - }; - - /** - * Converts a JavaScript Date to yyyy-mm-dd format - * @param {date} dt JavaScript Date object - * @return {string} Date in yyyy-mm-dd format - * @memberof CIQ - */ - CIQ.yyyymmdd = function (dt) { - var m = dt.getMonth() + 1; - if (m < 10) m = "0" + m; - var d = dt.getDate(); - if (d < 10) d = "0" + d; - return dt.getFullYear() + "-" + m + "-" + d; - }; - - /** - * Converts a JavaScript `Date` object to hh:mm format. - * - * @param {date} dt `Date` object to be converted. - * @return {string} Time of the converted `Date` object in hh:mm format. - * - * @memberof CIQ - * @since 8.0.0 - */ - CIQ.hhmm = function (dt) { - var h = dt.getHours(); - if (h < 10) h = "0" + h; - var m = dt.getMinutes(); - if (m < 10) m = "0" + m; - return h + ":" + m; - }; - - /** - * Converts a JavaScript Date to hh:mm:ss format - * @param {date} dt JavaScript Date object - * @return {string} Time in hh:mm:ss format - * @memberof CIQ - * @since 6.3.0 - */ - CIQ.hhmmss = function (dt) { - var s = dt.getSeconds(); - if (s < 10) s = "0" + s; - return CIQ.hhmm(dt) + ":" + s; - }; - - /** - * Converts a date into yyyymmddhhmm format - * @param {date} dt A JavaScript Date object - * @return {string} Date in yyyymmddhhmm format - * @memberof CIQ - */ - CIQ.yyyymmddhhmm = function (dt) { - return CIQ.yyyymmddhhmmssmmm(dt).substr(0, 12); - }; - - /** - * Converts a date into yyyymmddhhmmssmmm format - * @param {date} dt A JavaScript Date object - * @return {string} Date in yyyymmddhhmmssmmm format - * @memberof CIQ - */ - CIQ.yyyymmddhhmmssmmm = function (dt) { - var m = dt.getMonth() + 1; - if (m < 10) m = "0" + m; - var d = dt.getDate(); - if (d < 10) d = "0" + d; - var h = dt.getHours(); - if (h < 10) h = "0" + h; - var mn = dt.getMinutes(); - if (mn < 10) mn = "0" + mn; - var s = dt.getSeconds(); - if (s < 10) s = "0" + s; - var ms = dt.getMilliseconds(); - if (ms < 10) ms = "00" + ms; - else if (ms < 100) ms = "0" + ms; - return "" + dt.getFullYear() + m + d + h + mn + s + ms; - }; - - /** - * Converts a date into yyyy/mm/dd hh:mm format - * @param {date} dt A JavaScript Date object - * @return {string} Date in yyyy/mm/dd hh:mm format - * @memberof CIQ - */ - CIQ.friendlyDate = function (dt) { - return CIQ.dateToStr(dt, "YYYY/MM/dd HH:mm"); - }; - - /** - * Converts a string form date into mm-dd hh:mm format - * @param {string} strdt Date in string format (such as yyyymmddhhmm, yyyy-mm-dd hh:mm, etc) - * @return {string} Date in mm-dd hh:mm format - * @memberof CIQ - * @since 5.0.0 will output seconds and millis if present - */ - CIQ.mmddhhmm = function (strdt) { - var dt = CIQ.strToDateTime(strdt); - var m = dt.getMonth() + 1; - if (m < 10) m = "0" + m; - var d = dt.getDate(); - if (d < 10) d = "0" + d; - var h = dt.getHours(); - if (h < 10) h = "0" + h; - var mn = dt.getMinutes(); - if (mn < 10) mn = "0" + mn; - var s = dt.getSeconds(); - if (s < 10) s = "0" + s; - var ms = dt.getMilliseconds(); - if (ms < 10) ms = "00" + ms; - else if (ms < 100) ms = "0" + ms; - if (h == "00" && mn == "00" && s == "00" && ms == "000") - return m + "-" + d + "-" + dt.getFullYear(); - if (s == "00" && ms == "000") return m + "-" + d + " " + h + ":" + mn; - if (ms == "000") return m + "-" + d + " " + h + ":" + mn + ":" + s; - return m + "-" + d + " " + h + ":" + mn + ":" + s + ":" + ms; - }; - - /** - * Gets the day of the year - * @param {date} [dt] optional The date to check. If omitted, will use the current date. - * @return {number} Day of year - * @memberof CIQ - */ - CIQ.getYearDay = function (dt) { - var now = dt; - if (!now) now = new Date(); - now.setHours(0, 0, 0, 0); - var start = new Date(now.getFullYear(), 0, 0); - var diff = now - start; - var oneDay = 1000 * 60 * 60 * 24; - var day = Math.round(diff / oneDay); - return day; - }; - - /** - * Gets the current time in Eastern Time Zone. This can be used as a convenience for determining open and closing times of US markets. - * @return {date} JavaScript Date representing the time in Eastern Time Zone - * @memberof CIQ - */ - CIQ.getETDateTime = function () { - var d = new Date(); - return CIQ.convertTimeZone( - new Date(d.getTime() + d.getTimezoneOffset() * 60000), - "UTC", - "America/New_York" - ); - }; - - /** - * Converts a JavaScript date from Eastern Time Zone to the browser's local time zone. Daylight Savings Time is hard coded. @see CIQ.getETDateTime - * @param {date} est JavaScript Date object representing a date/time in eastern time zone - * @return {date} JavaScript Date object converted to browser's local time zone - * @memberof CIQ - */ - CIQ.fromET = function (est) { - var d = new Date(); - //var localTime = d.getTime(); - //var localOffset = d.getTimezoneOffset() * 60000; - //var utc = localTime + localOffset; - var offset = 4; - if ( - d.getMonth() < 2 || - (d.getMonth() == 2 && d.getDate() < 11) || - d.getMonth() > 10 || - (d.getMonth() == 10 && d.getDate() >= 4) - ) - offset = 5; - var localTime = est.getTime() + 3600000 * offset; - var nd = new Date(localTime); - return nd; - }; - - /** - * Convenience function for creating a displayable month name using CIQ.monthLetters and CIQ.monthAbv. - * Please note that those arrays may not be utilized if the library is used in conjunction with Internationalization. - * This method is used primarily to create the x-axis of a chart - * @param {number} i The numerical month (0-11) - * @param {boolean} displayLetters - True if just the first letter should be displayed (such as a tight display) - * @param {object} [stx] The chart object, only necessary if Internationalization is in use - * @return {string} String representation of the month - * @memberof CIQ - */ - CIQ.monthAsDisplay = function (i, displayLetters, stx) { - if (displayLetters) { - if (stx && stx.monthLetters) return stx.monthLetters[i]; - return CIQ.monthLetters[i]; - } - if (stx && stx.monthAbv) return stx.monthAbv[i]; - return CIQ.monthAbv[i]; - }; - - /** - * Displays a time in readable form. If Internationalization is in use then the time will be in 24 hour Intl numeric format - * @param {date} dt JavaScript Date object - * @param {object} [stx] Chart object if Internationalization is in use - * @param {number} [precision] Precision to use. If `null` then `hh:mm`. `CIQ.SECOND` then `hh:mm:ss`. If `CIQ.MILLISECOND` then `hh:mm:ss.mmmmm` - * @return {string} Human friendly time, usually hh:mm - * @memberof CIQ - */ - CIQ.timeAsDisplay = function (dt, stx, precision) { - var internationalizer = stx ? stx.internationalizer : null; - if (internationalizer) { - if (precision == CIQ.SECOND) - return internationalizer.hourMinuteSecond.format(dt); - else if (precision == CIQ.MILLISECOND) - return ( - internationalizer.hourMinuteSecond.format(dt) + - "." + - dt.getMilliseconds() - ); - return internationalizer.hourMinute.format(dt); - } - var min = dt.getMinutes(); - if (min < 10) min = "0" + min; - var str = dt.getHours() + ":" + min; - var sec = ""; - if (precision <= CIQ.SECOND) { - sec = dt.getSeconds(); - if (sec < 10) sec = "0" + sec; - str += ":" + sec; - } - if (precision == CIQ.MILLISECOND) { - var msec = dt.getMilliseconds(); - if (msec < 10) msec = "00" + msec; - else if (msec < 100) msec = "0" + msec; - str += "." + msec; - } - return str; - }; - - /** - * Creates a displayable date string according to the current chart settings and periodicity. - * - * Formats the date using one of the following formatters or default format (in order of - * preference): - * - * 1. Chart x-axis formatter - * 2. Chart engine internationalizer - * 3. Default format - *
a. Daily — mm/dd/yyyy - *
b. Intraday — mm/dd hh:mm[:ss[:ms]] - * - * This method is used in {@link CIQ.ChartEngine.AdvancedInjectable#headsUpHR} to format the - * date label that floats over the x-axis. Overwrite this method as needed to achieve the desired - * date format. - * - * @param {CIQ.ChartEngine} stx The charting object. - * @param {CIQ.ChartEngine.Chart} chart The chart to which the date applies. - * @param {Date} dt The date to format. - * @param {boolean} [includeIntraYear] If true, include the year in the intraday dates. - * @return {string} The formatted date. - * - * @memberof CIQ - * @since - * - 4.0.0 - * - 8.2.0 Added the `includeIntraYear` parameter. - */ - CIQ.displayableDate = function (stx, chart, dt, includeIntraYear) { - function twoPlaces(val) { - if (val < 10) return "0" + val; - return val; - } - var displayableDate = ""; - var interval = stx.layout.interval; - var isDaily = CIQ.ChartEngine.isDailyInterval(interval); - var isSecond = - (chart.xAxis.activeTimeUnit && chart.xAxis.activeTimeUnit <= CIQ.SECOND) || - stx.layout.timeUnit == "second"; - var isMS = - (chart.xAxis.activeTimeUnit && - chart.xAxis.activeTimeUnit <= CIQ.MILLISECOND) || - stx.layout.timeUnit == "millisecond"; - if (chart.xAxis.formatter) { - displayableDate = chart.xAxis.formatter(dt); - } else if (stx.internationalizer) { - displayableDate = stx.internationalizer.monthDay.format(dt); - if (isSecond || isMS) { - displayableDate += - " " + stx.internationalizer.hourMinuteSecond.format(dt); - if (isMS) displayableDate += "." + dt.getMilliseconds(); - } else if (!isDaily) { - if (includeIntraYear) - displayableDate = stx.internationalizer.yearMonthDay.format(dt); - displayableDate += " " + stx.internationalizer.hourMinute.format(dt); - } else { - if (interval == "month") - displayableDate = stx.internationalizer.yearMonth.format(dt); - else displayableDate = stx.internationalizer.yearMonthDay.format(dt); - } - } else { - var m = twoPlaces(dt.getMonth() + 1); - var d = twoPlaces(dt.getDate()); - var h = twoPlaces(dt.getHours()); - var mn = twoPlaces(dt.getMinutes()); - if (isDaily) { - displayableDate = interval == "month" ? m + "/" : m + "/" + d + "/"; - displayableDate += dt.getFullYear(); - } else { - let date = m + "/" + d; - if (includeIntraYear) date += "/" + dt.getFullYear(); - displayableDate = date + " " + h + ":" + mn; - if (isSecond || isMS) { - var sec = twoPlaces(dt.getSeconds()); - displayableDate += ":" + sec; - if (isMS) { - var mil = twoPlaces(dt.getMilliseconds()); - if (mil < 100) mil = "0" + mil; - displayableDate += ":" + mil; - } - } - } - } - return displayableDate; - }; - - /** - * Converts a Date object from one time zone to another using the timezoneJS.Date library - * @param {date} dt Original JavaScript Date object, from the original time zone - * @param {string} originalTimeZone The original time zone - * @param {string} targetTimeZone The target time zone - * @return {date} The date in the target timezone. This is a timezoneJS.Date which behaves the same as a native Date. - * @memberof CIQ - */ - CIQ.convertTimeZone = function (dt, originalTimeZone, targetTimeZone) { - if (!timezoneJS.Date) return dt; - // Convert from original timezone to local time - var newDT = new timezoneJS.Date( - dt.getFullYear(), - dt.getMonth(), - dt.getDate(), - dt.getHours(), - dt.getMinutes(), - dt.getSeconds(), - dt.getMilliseconds(), - originalTimeZone - ); - - // Convert from local time to new timezone - newDT.setTimezone(targetTimeZone); - return newDT; - }; - - /** - * This method converts a time from another timezone to local time on the browser - * @param {date} dt The original time - * @param {string} originalTimeZone A valid timezone - * @return {date} The date converted to local time - * @memberof CIQ - */ - CIQ.convertToLocalTime = function (dt, originalTimeZone) { - if (!timezoneJS.Date) return dt; - var seconds = dt.getSeconds(); - var milliseconds = dt.getMilliseconds(); - var newDT = new timezoneJS.Date( - dt.getFullYear(), - dt.getMonth(), - dt.getDate(), - dt.getHours(), - dt.getMinutes(), - originalTimeZone - ); - return new Date(newDT.getTime() + seconds * 1000 + milliseconds); - }; - - }; - - - let __js_core_dom_ = (_exports) => { - - - if (!_exports.SplinePlotter) _exports.SplinePlotter = {}; - - var CIQ = _exports.CIQ, - splinePlotter = _exports.SplinePlotter; - - /** - * Shorthand for `getElementById()`. - * - * Equivalent to prototype style `$()`, which is faster but less powerful than jQuery style `$()`. - * - * @param {string} id An ID tag for a valid DOM element. - * @param {HTMLElement} [source] A valid DOM node to search within. If not provided, the entire - * document is searched. - * @return {HTMLElement} The DOM node associated with the ID, or null if a node is not found. - * - * @name $$ - * @function - */ - var $$ = function (id, source) { - if (!source) return document.getElementById(id); - if (source.id == id) return source; // Found it! - if (!source.hasChildNodes) return null; - for (var i = 0; i < source.childNodes.length; i++) { - var element = $$(id, source.childNodes[i]); - if (element) return element; - } - return null; - }; - _exports.$$ = $$; - - /** - * Functional equivalent of `querySelector()`. - * - * Functionally equivalent to jQuery `$()`. Uses `querySelectorAll` to maintain compatibility with - * Internet Explorer 9. - * - * **Note:** If multiple elements match the selector, only the first is returned. - * - * @param {string} selector CSS style selector. - * @param {HTMLElement} [source] Node to select within. If not provided, the entire document is - * searched. - * @return {HTMLElement} The first element to match the selector. - * - * @name $$$ - * @function - */ - var $$$ = function (selector, source) { - if (!source) source = document; - return source.querySelectorAll(selector)[0]; // We use querySelectorAll for backward compatibility with IE - }; - _exports.$$$ = $$$; - - /** - * READ ONLY. String of appropriate wheel event based on browser features. - */ - CIQ.wheelEvent = (function () { - if (typeof document === "undefined") return undefined; - if (CIQ.isIE || "onwheel" in document.createElement("div")) return "wheel"; - if (document.onmousewheel !== undefined) return "mousewheel"; - return "DOMMouseScroll"; - })(); - - /** - * Convenience function for dynamically creating a new node and appending it into the DOM. - * @param {object} div The targeted parent node - * @param {string} tagName The type of node to be created - * @param {string} [className] Optional class name to set the new node - * @param {string} [txt] Optional text to insert - * @return {object} The new node - * @memberof CIQ - */ - CIQ.newChild = function (div, tagName, className, txt) { - var div2 = document.createElement(tagName); - if (className) div2.className = className; - div.appendChild(div2); - if (txt) div2.innerHTML = txt; - return div2; - }; - - /** - * Microsoft RT disallows innerHTML that contains DOM elements. Use this method to override when necessary. - * @param {object} node A valid DOM element to change innerHTML - * @param {string} html The html text to change - * @example - * CIQ.innerHTML(node, "My innerHTML contains a span and MS RT doesn't like that"); - * @memberof CIQ - */ - CIQ.innerHTML = function (node, html) { - if (window.MSApp && window.MSApp.execUnsafeLocalFunction) { - window.MSApp.execUnsafeLocalFunction(function () { - node.innerHTML = html; - }); - } else { - node.innerHTML = html; - } - }; - - /** - * Microsoft surface bug requires a timeout in order for the cursor to show up in a focused - * text box. iPad also, sometimes, when embedded in an iframe, so set useTimeout if in an iframe! - * @param {object} node A DOM element to focus - * @param {number} useTimeout Whether to apply a timeout or not. If number then the number of milliseconds. - * @memberof CIQ - */ - CIQ.focus = function (node, useTimeout) { - if (CIQ.isSurface || useTimeout) { - var timeout = 0; - if (!isNaN(parseInt(useTimeout, 10))) timeout = useTimeout; - setTimeout(function () { - node.focus(); - }, timeout); - } else { - node.focus(); - } - }; - - /** - * Reliable, cross-device blur method - * @param {HTMLElement} [node] The element to blur. If not supplied then document.activeElement will be blurred - * @memberof CIQ - */ - CIQ.blur = function (node) { - if (!node) node = document.activeElement; - if (node) node.blur(); - window.focus(); - }; - - /** - * Find all nodes that match the given text. This is a recursive function so be careful not to start too high in the DOM tree. - * @param {object} startNode A valid DOM element from which to start looking - * @param {string} text The text to search for - * @return {array} An array of nodes that match the text - * @memberof CIQ - */ - CIQ.findNodesByText = function (startNode, text) { - if (startNode.innerHTML == text) return [startNode]; - var nodes = []; - for (var i = 0; i < startNode.childNodes.length; i++) { - var pushNodes = CIQ.findNodesByText(startNode.childNodes[i], text); - if (pushNodes) { - nodes = nodes.concat(pushNodes); - } - } - if (nodes.length) return nodes; - return null; - }; - - /** - * Hide nodes that match a certain text string. - * @param {object} startNode A valid DOM element from which to start looking - * @param {string} text The text to match against - * {@link CIQ.findNodesByText} - * @memberof CIQ - */ - CIQ.hideByText = function (startNode, text) { - var nodes = CIQ.findNodesByText(startNode, text); - for (var i = 0; i < nodes.length; i++) { - nodes[i].style.display = "none"; - } - }; - - /** - * Returns the height of the page. It is aware of iframes and so will never return a value that is greater - * than the value of the parent - * @return {number} Height of page in pixels - * @memberof CIQ - */ - CIQ.pageHeight = function () { - var { innerHeight, top, parent, self } = window; - if (top != self) { - try { - if (innerHeight > parent.innerHeight) innerHeight = parent.innerHeight; - } catch (e) {} - } - return innerHeight; - }; - - /** - * Returns the width of the page. It is aware of iframes and so will never return a value that is greater - * than the value of the parent - * @return {number} Width of page in pixels - * @memberof CIQ - */ - CIQ.pageWidth = function () { - var { innerWidth, top, parent, self } = window; - if (top != self) { - try { - if (innerWidth > parent.innerWidth) innerWidth = parent.innerWidth; - } catch (e) {} - } - return innerWidth; - }; - - /** - * Strips the letters "px" from a string. This is useful for converting styles into absolutes. - * @param {string} text - String value with "px" - * @return {number} The numeric value - * @example - * var leftPosition=CIQ.stripPX(node2.style.left) - * @memberof CIQ - */ - CIQ.stripPX = function (text) { - if (!text) return 0; - if (typeof text == "number") return text; - return parseInt(text.substr(0, text.indexOf("p")), 10); - }; - - /** - * Returns true if a point, in absolute screen position, is within an element - * @param {object} node A valid DOM element to check whether the point overlaps - * @param {number} x Absolute screen X position of pointer - * @param {number} y Absolute screen Y position of pointer - * @return {boolean} True if the point lies inside of the DOM element - * @memberof CIQ - */ - CIQ.withinElement = function (node, x, y) { - var rect = node.getBoundingClientRect(); - if (x <= rect.left) return false; - if (y <= rect.top) return false; - if (x >= rect.left + node.offsetWidth) return false; - if (y >= rect.top + node.offsetHeight) return false; - return true; - }; - - /** - * Sets a property or style of a DOM element only if the property or style does not already have - * the provided value. - * - * This is more efficient than needlessly updating the DOM. - * - * @param {HTMLElement} node The DOM element to update. - * @param {string} member The DOM element's property or style to update. - * @param {string} value The value to set. - * @return {boolean} true if the value of `member` was changed. - * - * @memberof CIQ - * @since - * - 4.0.0 - * - 8.1.0 Added return value. - * - * @example - * Set the HTML content of a DOM element. - * CIQ.efficientDOMUpdate(node, "innerHTML", htmlString); - * - * @example - * Set a style property of a DOM element. - * CIQ.efficientDOMUpdate(controls.floatDate.style, "width", "auto"); - */ - CIQ.efficientDOMUpdate = function (node, member, value) { - if (node[member] !== value) { - node[member] = value; - return true; - } - return false; - }; - - /** - * Creates a virtual DOM for an element. - * - * A virtual DOM is faster and more efficient than the actual DOM for manipulation of an - * element's children. - * - * **Note:** Use {@link CIQ.cqrender} to render the virtual DOM on the real DOM. - * - * @param {HTMLElement} node The node for which the virtual DOM is created. - * @return {object} The virtual DOM of `node`. - * - * @memberof CIQ - * @since 8.1.0 - */ - CIQ.cqvirtual = function (node) { - if (!node) return; - var virtual = node.cloneNode(true); - virtual.innerHTML = ""; - virtual.original = node; - return virtual; - }; - - /** - * Copies the virtual DOM of an element to the actual DOM. - * - * **Note:** Use {@link CIQ.cqvirtual} to first create a virtual DOM. - * - * @param {HTMLElement} node The node for which the actual DOM is updated with the virtual DOM. - * @return {object} The actual DOM of the node. - * - * @memberOf CIQ - * @since 8.1.0 - */ - CIQ.cqrender = function (node) { - if (!node) return; - if (node.innerHTML == node.original.innerHTML) return node.original; - CIQ.removeChildIfNot(node.original, "template"); - - var children = Array.from(node.children); - if (children.length) - children.forEach(function (child) { - node.original.appendChild(node.removeChild(child)); - }); - return node.original; - }; - - /** - * Removes from `node` all children that do not match `selector`. Removes all children if no - * selector is provided. - * - * @param {HTMLElement} node Parent node from which child nodes are removed. - * @param {string} [selector] CSS selector used to select child nodes that are not removed from - * `node`. - * @return {HTMLElement} `node`, containing only those children selected by `selector`; all other - * children removed. - * - * @memberof CIQ - * @since 8.1.0 - */ - CIQ.removeChildIfNot = function (node, selector) { - var children = Array.from(node.children); - if (children.length) - children.forEach(function (child) { - if (!selector || !child.matches(selector)) node.removeChild(child); - }); - return node; - }; - - /** - * Used in conjunction, safeMouseOut and safeMouseOver ensure just a single event when the mouse moves - * in or out of an element. This is important because simple mouseout events will fire when the mouse - * crosses boundaries *within* an element. Note that this function will do nothing on a touch device where - * mouseout is not a valid operation. - * @param {object} node A valid DOM element - * @param {function} fc Function to call when the mouse has moved out - * @memberof CIQ - */ - CIQ.safeMouseOut = function (node, fc) { - function closure(node, fc) { - return function (e) { - if (typeof e.pageX == "undefined") { - e.pageX = e.clientX; - e.pageY = e.clientY; - } - if (CIQ.withinElement(node, e.pageX, e.pageY)) { - return; - } - node.stxMouseOver = false; - fc(e); - }; - } - node.addEventListener("mouseout", closure(node, fc)); - }; - - /** - * This method is guaranteed to only be called once when a user mouses over an object. @see CIQ.safeMouseOut - * @param {object} node A valid DOM element - * @param {function} fc Function to call when mouse moves over the object - * @memberof CIQ - */ - CIQ.safeMouseOver = function (node, fc) { - function closure(node, fc) { - return function (e) { - if (typeof e.pageX == "undefined") { - e.pageX = e.clientX; - e.pageY = e.clientY; - } - if (CIQ.withinElement(node, e.pageX, e.pageY)) { - if (node.stxMouseOver) return; - node.stxMouseOver = true; - fc(e); - } - }; - } - node.addEventListener("mouseover", closure(node, fc)); - }; - - /** - * Converts an object to emit "stxtap" events. This uses {@link CIQ.safeClickTouch}. You should use addEventListener("tap") to receive the events. - * @param {HTMLElement} div The element to convert - * @param {object} [params] Parameters to pass to {@link CIQ.safeClickTouch} - * @param {boolean} [params.stopPropagation=false] If set to true then propagation will be stopped - * @memberOf CIQ - * @since 04-2015 - */ - CIQ.installTapEvent = function (div, params) { - var fc = function (e) { - var ev = new Event("stxtap", { - bubbles: true, - cancelable: true - }); - if (typeof e.pageX == "undefined") { - e.pageX = e.clientX; - e.pageY = e.clientY; - } - ev.pageX = e.pageX; - ev.pageY = e.pageY; - e.target.dispatchEvent(ev); - if (params && params.stopPropagation) e.stopPropagation(); - }; - CIQ.safeClickTouch(div, fc, params); - }; - /** - * Use this instead of onclick or ontouch events. This function will automatically use the quickest available - * but also protect against being called twice. - * By default any previous safeClickTouch listeners will be cleared (to allow re-use of the element). - * @param {object} div The DOM element to attach an event - * @param {Function} fc The function to call when the object is pressed - * @param {object} params Parameters to drive behavior. - * @param {object} [params.safety] An object, generated from a CIQ.safeDrag association to prevent the click from being triggered when a drag operation is released - * @param {boolean} [params.allowMultiple=false] If set then multiple click events can be associated with the node - * @param {boolean} [params.preventUnderlayClick=true] By default prevents an underlaying element from being "clicked" on a touch device 400ms after the overlay was tapped. Set to false for input fields, or any div containing input fields (body) - * @param {boolean} [params.absorbDownEvent=true] Ensures that a mousedown, pointerdown, touchstart event doesn't get passed to the parent. - * @memberof CIQ - * @since 11/01/2015 Removed timers in favor of a new algorithm. This algorithm allows only the first event to fire from a UI interaction to execute the fc function. - */ - CIQ.safeClickTouch = function (div, fc, params) { - if (!params) params = {}; - var movementWatcher = {}; - // **Internal Developers** - // Because the chart itself makes use of touch and mouse events, it may not make sense to use this function if you are trying to prevent a default click from being passed to the chart container. - // Pointer events (which safeClickTouch will try to use) do not stop propagating mouse and touch events even if you are preventing default b/c they are different event types. - // In reality this means that if you are clicking on a DOM node that is on the chart, it will emit a mouse click to the chart b/c the chart is ALWAYS LISTENING. - // Put simply the chart is designed using mouse/touch paradigm and it is easier to not mix in pointer events. Meanwhile the UI layer is developed using pointer events and we should keep using pointer events there. - - if (!params.allowMultiple) CIQ.clearSafeClickTouches(div); - if (params.preventUnderlayClick !== false) params.preventUnderlayClick = true; - if (params.absorbDownEvent !== false) params.absorbDownEvent = true; - params.allowAnotherDevice = 0; - params.registeredClick = false; - function closure(which, params, movementWatcher) { - return function (e) { - if (!CIQ.safeClickTouchEvent) { - if (!movementWatcher.t) { - return; // is this up/end event related to a down/start event? - } - var timeSincePressed = movementWatcher.t; - movementWatcher.t = null; - if (timeSincePressed + 1000 < new Date().getTime()) return; //allow no more than 1 second for click - } - if (params.safety && params.safety.recentlyDragged) return; - - if ((e.which && e.which >= 2) || (e.button && e.button >= 2)) return; // ignore right clicks - if (params.preventUnderlayClick) { - // underlay click happens when you tap on a mobile device but a second mouse event registers - // 300 ms later on another clickable object that was beneath the menu. By default we stop this - // secondary event using preventDefault. However, we don't want to do this if we clicked inside - // an input tag, because that would prevent the soft keyboard from coming up. Note that modern - // touch operating systems don't have the 300ms delay issue so this code can be eliminated once - // older operating systems are safely retired. - if (e.target.tagName !== "INPUT") e.preventDefault(); - } else { - // prevent touch and mouse from being clicked when we can't use preventDefault - if (params.lastType != which && Date.now() < params.allowAnotherDevice) - return; - params.lastType = which; - params.allowAnotherDevice = Date.now() + 1000; // 1 Second then not a coat tail mouse click - } - fc(e); - }; - } - function isClick(movementWatcher, down) { - return function (e) { - var x = e.clientX ? e.clientX : e.pageX; - var y = e.clientY ? e.clientY : e.pageY; - if (down) { - movementWatcher.t = new Date().getTime(); - movementWatcher.x = x; - movementWatcher.y = y; - } else if (movementWatcher.x) { - //allow no more than 4 pixel distance movement - if ( - Math.pow(movementWatcher.x - x, 2) + - Math.pow(movementWatcher.y - y, 2) > - 16 - ) { - movementWatcher.t = null; - } - } - }; - } - var safeClickTouchEvents = div.safeClickTouchEvents; - if (!safeClickTouchEvents) - safeClickTouchEvents = div.safeClickTouchEvents = []; - var fc1 = closure("mouseup", params, movementWatcher); - var fc2 = closure("touchend", params, movementWatcher); - var fc3 = closure("pointerup", params, movementWatcher); - var f = function (e) { - e.stopPropagation(); - }; - var eventHolder = {}; - if (CIQ.safeClickTouchEvent) { - // global override for which event to use, for instance if you want to force use of "click" or "tap" - var fc4 = closure(CIQ.safeClickTouchEvent, params); - div.addEventListener(CIQ.safeClickTouchEvent, fc4); - eventHolder[CIQ.safeClickTouchEvent] = fc4; - safeClickTouchEvents.push(eventHolder); - } else if ("onpointerup" in document && !CIQ.noPointerEvents) { - // Internet Explorer can always use pointerup safely - div.addEventListener("pointerdown", isClick(movementWatcher, true)); - div.addEventListener("pointermove", isClick(movementWatcher)); - div.addEventListener("pointerup", fc3); - eventHolder.pointerup = fc3; - if (params.absorbDownEvent) { - div.addEventListener("pointerdown", f); - eventHolder.pointerdown = f; - } - safeClickTouchEvents.push(eventHolder); - } else { - // all in one computers can support both of these under Chrome/FF! - div.addEventListener("mousedown", isClick(movementWatcher, true)); - div.addEventListener("mousemove", isClick(movementWatcher)); - div.addEventListener("touchstart", isClick(movementWatcher, true)); - div.addEventListener("touchmove", isClick(movementWatcher)); - div.addEventListener("mouseup", fc1); - div.addEventListener("touchend", fc2); - eventHolder.mouseup = fc1; - eventHolder.touchend = fc2; - if (params.absorbDownEvent) { - div.addEventListener("mousedown", f); - eventHolder.mousedown = f; - div.addEventListener("touchstart", f); - eventHolder.touchstart = f; - } - safeClickTouchEvents.push(eventHolder); - } - }; - - /** - * Clears all safeClickTouch events from a DOM element. - * @param {object} div The DOM element to clear events - * @memberof CIQ - */ - CIQ.clearSafeClickTouches = function (div) { - var safeClickTouchEvents = div.safeClickTouchEvents; - if (!safeClickTouchEvents) return; - for (var i = 0; i < safeClickTouchEvents.length; i++) { - var fc = safeClickTouchEvents[i]; - for (var e in fc) { - var f = fc[e]; - div.removeEventListener(e, f); - } - } - div.safeClickTouchEvents = null; - }; - - /** - * Safe function to handle dragging of objects on the screen. - * - * This method is cross-device aware and can handle mouse or touch drags. - * This method does not actually move the objects but provides callbacks that explain when drag operations - * begin and cease, and what movements are made during the drag. Callbacks should be used to move the actual objects - * (if it is desired to move objects during a drag operation). For convenience, displacementX and displacementY are added to callback events - * to indicate the distance from the original starting point of the drag. - * A "safety" object is returned which can optionally be passed into CIQ.safeClickTouch to prevent errant click events - * from being triggered when a user lets go of a drag - * @param {object} div The draggable DOM element - * @param {object} [eventHandlers] - * @param {function} [eventHandlers.down] Callback function when a drag operation begins. Receives an event object. - * @param {function} [eventHandlers.move] Callback function when a drag move occurs. Receives an event object. - * @param {function} [eventHandlers.up] Callback function when the drag operation ends. Receives an event object. - * @return {object} Safety object which can be passed to CIQ.safeClickTouch - * @memberof CIQ - * @since 7.0.0 change function signature to accept eventHandlers object instead of three function arguments - */ - CIQ.safeDrag = function (div, eventHandlers) { - var eventProperty = function (key, alt) { - return function (e) { - if (e.touches) { - if (e.touches.length > 0) { - return e.touches[0][key]; - } else if (e.changedTouches && e.changedTouches.length > 0) { - return e.changedTouches[0][key]; - } - } - - return typeof e[key] !== "undefined" ? e[key] : e[alt]; - }; - }; - var pageX = eventProperty("pageX", "clientX"); - var pageY = eventProperty("pageY", "clientY"); - - if (typeof eventHandlers === "function") { - eventHandlers = { - down: arguments[1], // fcDown - move: arguments[2], // fcMove - up: arguments[3] // fcUp - }; - } - eventHandlers = eventHandlers || {}; - - var resetMS = 100; // To avoid multiple down events only one can occur per 100ms - var registeredClick = false; - var startX = 0; - var startY = 0; - var safety = { - recentlyDragged: false - }; - - function startHandler(eventNames) { - // event handler for mousedown, pointerdown, or touchstart - return function (e) { - if (registeredClick) return; - - registeredClick = true; - CIQ.ChartEngine.ignoreTouch = true; - - var moveFC = function (e) { - if (e && e.preventDefault) e.preventDefault(); - - safety.recentlyDragged = true; - e.displacementX = pageX(e) - startX; - e.displacementY = pageY(e) - startY; - - eventHandlers.move(e); - }; - - if (eventHandlers.move) { - document.body.addEventListener(eventNames.move, moveFC); - } - - var upFC = function (e) { - CIQ.ChartEngine.ignoreTouch = false; - - if (eventHandlers.move) { - // Remove the move listener since our move is now complete - document.body.removeEventListener(eventNames.move, moveFC); - } - - // Remove the up listener since our move is now complete - document.body.removeEventListener(eventNames.up, upFC); - e.displacementX = pageX(e) - startX; - e.displacementY = pageY(e) - startY; - - if (eventHandlers.up) { - eventHandlers.up(e); - } - - // Prevent errant clicks from touch letting go - setTimeout(function () { - safety.recentlyDragged = false; - }, 50); - }; - - document.body.addEventListener(eventNames.up, upFC); - - setTimeout(function () { - registeredClick = false; - }, resetMS); - - startX = pageX(e); - startY = pageY(e); - - if (eventHandlers.down) { - eventHandlers.down(e); - } - }; - } - - div.addEventListener( - "mousedown", - startHandler({ - down: "mousedown", - move: "mousemove", - up: "mouseup" - }) - ); - div.addEventListener( - "pointerdown", - startHandler({ - down: "pointerdown", - move: "pointermove", - up: "pointerup" - }) - ); - div.addEventListener( - "touchstart", - startHandler({ - down: "touchstart", - move: "touchmove", - up: "touchend" - }), - { passive: false } - ); - - return safety; - }; - - /** - * Captures enter key events. Also clears the input box on escape key. - * @param {object} node The DOM element to attach the event to. Should be a text input box. - * @param {Function} cb Callback function when enter key is pressed. - * @memberof CIQ - */ - - CIQ.inputKeyEvents = function (node, cb) { - node.addEventListener( - "keyup", - function (e) { - var key = e.keyCode; - switch (key) { - case 13: - cb(); - break; - case 27: - node.value = ""; - break; - default: - break; - } - }, - false - ); - }; - - /** - * Fixes screen scroll. This can occur when the keyboard opens on an ipad or iphone. - * @memberof CIQ - */ - CIQ.fixScreen = function () { - window.scrollTo(0, 0); - }; - - /** - * Sets the position of the cursor within a textarea box. This is used for instance to position the cursor at the - * end of the text that is in a textarea. - * @param {object} ctrl A valid textarea DOM element - * @param {number} pos The position in the text area to position - * @memberof CIQ - */ - CIQ.setCaretPosition = function (ctrl, pos) { - ctrl.style.zIndex = 5000; - if (ctrl.setSelectionRange) { - CIQ.focus(ctrl); - try { - ctrl.setSelectionRange(pos, pos); - } catch (e) {} - } else if (ctrl.createTextRange) { - var range = ctrl.createTextRange(); - range.collapse(true); - range.moveEnd("character", pos); - range.moveStart("character", pos); - range.select(); - } - }; - - /** - * Sets the value of an input box only if it is not active. This prevents an input box from changing underneath - * a user, which can be extremely frustrating on touch devices. - * @param {HTMLElement} el The input element - * @param {string} value The value to set - * @memberOf CIQ - */ - CIQ.setValueIfNotActive = function (el, value) { - if (document.activeElement == el) return; - el.value = value; - }; - - /** - * Closes the keyboard on a touch device by blurring any active input elements. - * @param {HTMLElement} [newFocus] Element to change focus to - * @memberof CIQ - */ - CIQ.hideKeyboard = function (newFocus) { - var element = document.activeElement; - if (element.tagName == "INPUT" || element.tagName == "TEXTAREA") { - element.blur(); - window.focus(); - if (newFocus) { - if (newFocus === document.body || document.body.contains(newFocus)) - newFocus.focus(); - } - } - }; - - /** - * Adds or removes hover classes. This function will manage the hovers so they won't trigger when touching. - * adapted from http://www.javascriptkit.com/dhtmltutors/sticky-hover-issue-solutions.shtml - * We are relying on touchend being called before mouseover - * @memberof CIQ - * @since 6.3.0 - */ - CIQ.smartHover = function () { - if ( - !document || - document.documentElement.hasAttribute("ciq-last-interaction") - ) - return; // already initialized - var isTouch = false; //var to indicate current input type (is touch versus no touch) - var isTouchTimer; - - function setAttr(t) { - document.documentElement.setAttribute("ciq-last-interaction", t); - } - - function addTouchAttr(e) { - clearTimeout(isTouchTimer); - isTouch = true; - //add attribute value of touch if it's not already set - if ( - document.documentElement.getAttribute("ciq-last-interaction") != "touch" - ) - setAttr("touch"); - //maintain "istouch" state for 500ms so removetouchclass doesn't get fired immediately following a touch event - isTouchTimer = setTimeout(function () { - isTouch = false; - }, 500); - } - - function removeTouchAttr(e) { - //set attribute value if not triggered by a touch event - if (!isTouch) setAttr("mouse"); - } - - document.addEventListener("touchend", addTouchAttr, false); //this event only gets called when input type is touch - document.addEventListener("mouseover", removeTouchAttr, false); //this event gets called when input type is everything from touch to mouse/trackpad - setAttr(""); - }; - - /** - * Creates a document node which facilitates translation to other languages, if stx.translationCallback callback function is set. - * If there is no translationCallback, a standard text node is returned. - * @param {CIQ.ChartEngine} stx The chart object - * @param {string} english The word to translate - * @param {string} [language] Language. Defaults to CIQ.I18N.language. - * @return {HTMLElement} A node in the following form if translationCallback exists: - * translation - * If it does not exist, a text node is returned. - * @memberof CIQ - */ - CIQ.translatableTextNode = function (stx, english, language) { - if (stx.translationCallback) { - var translationNode = document.createElement("translate"); - translationNode.setAttribute("original", english); - translationNode.innerHTML = stx.translationCallback(english, language); - return translationNode; - } - return document.createTextNode(english); - }; - - /** - * Gets all parent elements, including the starting element itself, in order of distance from the - * starting element, nearest parent first. - * - * Use instead of jQuery `parents()`. - * - * @param {HTMLElement} el The starting element from which parent elements are obtained. - * @param {string} [selector] A CSS selector used to select the parent elements included in the - * ancestor list. If no selector is provided, all parent elements are included. - * @return {Array} Ancestry of elements filtered by `selector` from the starting element up to and - * including the HTML element. - * - * @memberof CIQ - * @since 8.1.0 - */ - CIQ.climbUpDomTree = function (el, selector) { - if (!(el instanceof HTMLElement)) return null; - var list = []; - // traverse parents - while (el) { - if (!selector || el.matches(selector)) list.push(el); - el = el.parentElement; - } - return list; - }; - - /** - * Returns a guaranteed width and height. For instance, `cq-context` or any other wrapping tag can - * have a width of zero; if so, we need to go up the ancestry tree parent by parent until a - * parent element provides an actual width. - * - * @param {Element} element The starting element for which the width and height are obtained. - * @return {object} Width and height of `element` as properties of the returned object. - * - * @memberof CIQ - * @since 8.1.0 - */ - CIQ.guaranteedSize = function (element) { - if (element === document) element = window; - if (!element.nodeType) { - return { - width: element.innerWidth, - height: element.innerHeight - }; - } - if (!element || element.nodeType > 1) return {}; - var w = element.offsetWidth; - var h = element.offsetHeight; - while (!w || !h) { - if (element.tagName === "BODY" || element === window) { - if (!w) w = window.innerWidth; - if (!h) h = window.innerHeight; - break; - } - element = element.parentElement; - if (!w) w = element.offsetWidth; - if (!h) h = element.offsetHeight; - } - return { width: w, height: h }; - }; - - /** - * Determines the visibility of a DOM element based on the following CSS properties: - * - opacity - * - display - * - visibility - * - width - * - height - * - * Replaces {@link CIQ.UI.trulyVisible}. - * - * @param {HTMLElement} node The node for which visibility is determined. - * @return {boolean} Whether the element is visible. - * - * @memberof CIQ - * @since 8.2.0 - */ - CIQ.trulyVisible = function (node) { - if (!node) return true; - const computedStyle = getComputedStyle(node); - if (computedStyle.opacity === "0") return false; - if (computedStyle.display === "none") return false; - if (computedStyle.visibility === "hidden") return false; - if (parseInt(computedStyle.width, 10) === 0) return false; - if ( - parseInt(computedStyle.height, 10) === 0 && - computedStyle.overflowY == "hidden" - ) - return false; - - return CIQ.trulyVisible(node.parentElement); - }; - - /** - * Measures an element's styled width and height. Assumes all style units are in pixels (px), not - * percentages or "auto". - * - * Use the `flags` parameter to specify whether padding, border, and margin should be included in - * the measurement. - * - * @param {HTMLElement} element The element to measure. - * @param {object} [flags] Measurement parameters. - * @param {boolean} [flags.padding] Include padding in the measurement. - * @param {boolean} [flags.border] Include border in the measurement. - * @param {boolean} [flags.margin] Include margin in the measurement. - * @return {object} Width and height as properties of the returned object. - * - * @memberof CIQ - * @since 8.1.0 - */ - CIQ.elementDimensions = function (element, flags) { - if (!element || element.nodeType !== 1) return {}; - var gcs = getComputedStyle(element); - var dims = { width: parseFloat(gcs.width), height: parseFloat(gcs.height) }; - var fluff = { - margin: {}, - border: {}, - padding: {} - }; - var props = ["width", "height"]; - for (var f in fluff) { - var qual = f == "border" ? "Width" : ""; - fluff[f] = { - width: - parseFloat(gcs[f + "Left" + qual]) + - parseFloat(gcs[f + "Right" + qual]), - height: - parseFloat(gcs[f + "Top" + qual]) + parseFloat(gcs[f + "Bottom" + qual]) - }; - } - if (flags && flags.margin) - props.forEach(function (i) { - dims[i] += fluff.margin[i]; - }); - if (flags && gcs.boxSizing === "content-box") { - if (flags.padding) - props.forEach(function (i) { - dims[i] += fluff.padding[i]; - }); - if (flags.border) - props.forEach(function (i) { - dims[i] += fluff.border[i]; - }); - } else if (gcs.boxSizing === "border-box") { - if (!flags || !flags.padding) - props.forEach(function (i) { - dims[i] -= fluff.padding[i]; - }); - if (!flags || !flags.border) - props.forEach(function (i) { - dims[i] -= fluff.border[i]; - }); - } - return dims; - }; - - /** - * Executes a listener function if the element being observed has been resized. - * Uses the [ResizeObserver](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver) API if available, otherwise uses an interval check. - * - * @param {HTMLElement} element The element to observe for resizing. - * @param {function} listener The function to be executed on a resize event. - * @param {object} resizeHandle A handle to the resizer, which is null the first time the function is called, - * or is the return value of the function for subsequent calls. - * @param {number} timeout Timeout interval for browsers that need to use interval checking. Set this value - * to 0 to turn off the observer. - * @return {object} A handle to the resizer, which can be passed again to the function to disable or reset - * the handle. - * @memberof CIQ - * @since 7.4.0 - */ - CIQ.resizeObserver = function (element, listener, resizeHandle, timeout) { - if (timeout) { - if (typeof ResizeObserver !== "undefined") { - if (!resizeHandle) { - resizeHandle = new ResizeObserver(listener); - resizeHandle.observe(element); - } - } else { - if (resizeHandle) clearInterval(resizeHandle); - resizeHandle = setInterval(listener, timeout); - } - } else { - if (resizeHandle) { - if (typeof ResizeObserver !== "undefined") { - resizeHandle.disconnect(); - } else { - clearInterval(resizeHandle); - } - } - resizeHandle = null; - } - return resizeHandle; - }; - - /** - * Turns a portion of raw text into multi-line text that fits in a given width. This is used for autoformatting of annotations - * @param {object} ctx A valid HTML Canvas Context - * @param {string} phrase The text - * @param {number} l The width in pixels to fit the text within on the canvas - * @return {array} An array of individual lines that should fit within the specified width - * @memberof CIQ - */ - CIQ.getLines = function (ctx, phrase, l) { - var wa = phrase.split(" "), - phraseArray = [], - lastPhrase = "", - measure = 0; - var fw = false; - for (var i = 0; i < wa.length; i++) { - var w = wa[i]; - measure = ctx.measureText(lastPhrase + w).width; - if (measure < l) { - if (fw) lastPhrase += " "; - fw = true; - lastPhrase += w; - } else { - phraseArray.push(lastPhrase); - lastPhrase = w; - } - if (i === wa.length - 1) { - phraseArray.push(lastPhrase); - break; - } - } - return phraseArray; - }; - - /** - * Creates a user-friendly alert. - * - * The charting engine uses this function instead of - * [window.alert()]{@link https://developer.mozilla.org/en-US/docs/Web/API/Window/alert} for - * warning and error messages. If the window object does not exist, the message is output to the - * console log. - * - * Override this function to create a custom alert. - * - * @param {string} text The message to be displayed. - * - * @memberof CIQ - * @since 8.0.0 Output the message to the console log if the window object does not exist. - * - * @example - * // Override with a friendlier alert mechanism! - * CIQ.alert=function(text){ - * doSomethingElse(text); - * } - */ - CIQ.alert = function (text) { - if (typeof window !== "undefined") window.alert(text); - else console.log(text); - }; - - // Some browsers don't support localStorage, worse won't let you polyfill (JDK7 webview). So we will create - // this so that we can add a polyfill. - try { - if (typeof localStorage !== "undefined") CIQ.localStorage = localStorage; - } catch (e) {} - - if (!CIQ.localStorage) - CIQ.localStorage = { - items: {}, - getItem: function (item) { - return CIQ.localStorage.items[item] || null; - }, - setItem: function (item, value) { - CIQ.localStorage.items[item] = value; - }, - removeItem: function (item) { - delete CIQ.localStorage.items[item]; - } - }; - - /** - * Set once after user is alerted that private browsing is enabled - * @memberof CIQ - * @type boolean - */ - CIQ.privateBrowsingAlert = false; - - /** - * Convenience function for storing a name/value pair in local storage. Detects whether private - * browsing is enabled since local storage is inoperable under private browsing. - * - * @param {string} name The name for the stored item. - * @param {string} value The value for the stored item. - * - * @memberof CIQ - */ - CIQ.localStorageSetItem = function (name, value) { - try { - CIQ.localStorage.setItem(name, value); - } catch (e) { - if (!CIQ.privateBrowsingAlert) { - CIQ.alert( - "No storage space available. Possible causes include browser being in Private Browsing mode, or maximum storage space has been reached." - ); - CIQ.privateBrowsingAlert = true; - } - } - }; - - }; - - - let __js_core_engineInit_ = (_exports) => { - - - var CIQ = _exports.CIQ; - - /** - * Previously `STXChart`. - * - * This is the constructor that creates a chart engine, instantiates its basic chart object and links it to its DOM container. - * - * Before any chart operations can be performed, this constructor must be called. - * - * Multiple CIQ.ChartEngine objects can exist on the same HTML document.
- * - * - * Once instantiated, the chart engine will never need to be constructed again, unless it is [destroyed]{@link CIQ.ChartEngine#destroy}.
- * To load or change symbols on the chart, simply call {@link CIQ.ChartEngine#loadChart}. - * - * @constructor - * @param {object} config Configuration object used to initialize the chart engine.
- * {@link CIQ.ChartEngine#container} is the minimum requirement. The complete list of parameters and objects can be found in the **Members** section of this page.
- * Example: - * - * @name CIQ.ChartEngine - * @example - * // declare a chart - * var stxx=new CIQ.ChartEngine({container: document.querySelector(".chartContainer")}); - * // override defaults after a chart object is declared (this can be done at any time. If the chart has already been rendered, you will need to call `stx.draw();` to immediately see your changes ) - * stxx.yaxisLabelStyle="roundRectArrow"; - * stxx.layout.chartType="bar"; - * @example - * // declare a chart and preset defaults - * var stxx=new CIQ.ChartEngine({container: document.querySelector(".chartContainer"),layout:{"chartType": "candle","candleWidth": 16}}); - * @since - * - 15-07-01 Deprecated `CIQ.ChartEngine#underlayPercentage`. - * - m-2016-12-01 Deprecated; renamed `CIQ.ChartEngine` from `STXChart`. - */ - CIQ.ChartEngine = function (config) { - if (!config) { - config = { - container: null - }; - } else if ( - typeof HTMLDivElement != "undefined" && - config.constructor == HTMLDivElement - ) { - // legacy versions accepted the chart container as the first parameters rather than a config object - var newConfig = { - container: config - }; - config = newConfig; - } - - // copy prototype values into instance - for (var n in prototypeSwitches) { - this[n] = CIQ.clone(CIQ.ChartEngine.prototype[n]); - } - - /** - * The DOM container that will be running the chart engine. This is a required field when calling [new CIQ.ChartEngine]{@link CIQ.ChartEngine} - * @type object - * @alias container - * @memberof CIQ.ChartEngine - * @instance - * @example - * // declare a chart - * var stxx=new CIQ.ChartEngine({container: document.querySelector(".chartContainer")}); - */ - this.container = null; - /** - * Set to false to bypass chart panel creation in {@link CIQ.ChartEngine#construct}. - * @type boolean - * @alias createChartPanel - * @memberof CIQ.ChartEngine - * @instance - * @private - */ - this.createChartPanel = true; - /** - * READ ONLY. A map of marker objects, sorted by label. - * @type object - * @alias markers - * @memberof CIQ.ChartEngine - * @instance - */ - this.markers = {}; - /** - * READ ONLY. An array of currently enabled panels - * @type object - * @alias panels - * @memberof CIQ.ChartEngine - * @instance - */ - this.panels = {}; - /** - * READ ONLY. An array of currently enabled overlay studies - * @type object - * @alias overlays - * @memberof CIQ.ChartEngine - * @instance - */ - this.overlays = {}; - /** - * READ ONLY. The charts on the screen. Will contain at least one item, "chart" - * @type object - * @alias charts - * @memberof CIQ.ChartEngine - * @instance - * @private - */ - this.charts = {}; - /** - * READ ONLY. Array of event listeners currently attached to the engine. - * These listeners will be killed when {@link CIQ.ChartEngine#destroy} is called. - * - * See {@link CIQ.ChartEngine#addEventListener} and {@link CIQ.ChartEngine#removeEventListener} - * @type array - * @alias eventListeners - * @memberof CIQ.ChartEngine - * @instance - */ - this.eventListeners = []; - - /** - * Holds the HTML control elements managed by the chart. Usually this will be a copy of the default [htmlControls]{@link CIQ.ChartEngine.htmlControls}. - * These are not the GUI elements around the chart, but rather the HTML elements that the library will directly interact with on the canvas - * for things like panel resizing, study edit controls, zooming controls, etc. See {@link CIQ.ChartEngine.htmlControls} for more details. - * @type object - * @alias controls - * @memberof CIQ.ChartEngine - * @instance - */ - this.controls = {}; // contains the HTML controls for the chart (zoom, home, etc) - this.goneVertical = false; // Used internally for pinching algorithm - /** - * READ ONLY. Toggles to true when the screen is being pinched - * @type boolean - * @default - * @alias pinchingScreen - * @memberof CIQ.ChartEngine - * @instance - */ - this.pinchingScreen = false; - /** - * READ ONLY. Toggles to true when the screen is being panned - * @type boolean - * @default - * @alias grabbingScreen - * @memberof CIQ.ChartEngine - * @instance - */ - this.grabbingScreen = false; - this.grabStartX = 0; // Used internally for panning - this.grabStartY = 0; // " - this.grabStartScrollX = 0; // " - this.grabStartScrollY = 0; // " - this.swipe = {}; // " - - this.grabStartCandleWidth = 0; // Used internally for zooming - this.grabStartZoom = 0; // " - this.grabOverrideClick = false; // " - this.grabMode = ""; // Used internally. Set to either pan, zoom-x or zoom-y when grabbing screen - this.vectorsShowing = false; // Used internally to ensure that vectors aren't drawn more than once - this.mouseMode = true; // Used internally. For Windows8 devices this is set to true or false depending on whether the last touch was a mouse click or touch event. To support all-in-one computers - this.lineTravelSpacing = false; // Used internally as an override for candleWidth spacing - - this.highlightedDataSetField = null; // READ ONLY. Set to field whose plot is currently highlighted (series or study) - this.anyHighlighted = false; // READ ONLY. Toggles to true if any drawing or overlay is highlighted for deletion - this.accessoryTimer = null; // Used internally to control drawing performance - this.lastAccessoryUpdate = new Date().getTime(); // " - this.displayCrosshairs = true; // READ ONLY. Use doDisplayCrosshairs() or undisplayCrosshairs() - this.hrPanel = null; // READ ONLY. Current panel that mouse is hovering over - this.editingAnnotation = false; // READ ONLY. True if an annotation is open for editing - this.openDialog = ""; // Set this to non-blank to disable chart touch and mouse events use CIQ.ChartEngine.prototype.modalBegin() and CIQ.ChartEngine.prototype.modalEnd - - this.touches = []; // Used internally for touch - this.changedTouches = []; // Used internally for touch - /** - * READ ONLY. The tick representing the crosshair cursor point - * @type number - * @alias crosshairTick - * @memberof CIQ.ChartEngine - * @instance - */ - this.crosshairTick = null; - /** - * READ ONLY. The value (price) representing the crosshair cursor point - * @type number - * @alias crosshairValue - * @memberof CIQ.ChartEngine - * @instance - */ - this.crosshairValue = null; - - this.pt = { - x1: -1, - x2: -1, - y1: -1, - y2: -1 - }; - this.moveA = -1; // Used internally for touch - this.moveB = -1; // " - this.touchStartTime = -1; // " - this.touchPointerType = ""; // " - this.gestureStartDistance = -1; // " - this.grabStartPeriodicity = 1; // " - this.grabEndPeriodicity = -1; // " - this.scrollEvent = null; // " - this.cmd = false; // " - this.ctrl = false; // " - this.shift = false; // " - this.userPointerDown = false; //represents either mouse button or finger on touch device - /** - * Manage drawing cloning state. - * - * Set to `true` to enable the ability to clone drawings.
- * Once enabled, drawings can be cloned once or multiple times. - * A user must highlight the drawing, click on it, move the mouse to a new location and click again to set.
- * Reset to `false` when you want the cloning to end. - * - * This can be done based on a key stroke, button press, etc. For example, you can set to true when the `control` key is pressed and disable when it is released. - * @type number - * @default - * @alias cloneDrawing - * @memberof CIQ.ChartEngine - * @instance - * @since 07-2016-16.7 - * @example - * - document.onkeyup=keyup; - document.onkeydown=keydown; - - // disable cloning if the ctl key is released - function keyup(e){ - var key = (window.event) ? event.keyCode : e.keyCode; - if (key == 18 ) stxx.cloneDrawing=false; - } - - // enable cloning if the ctl key is pressed - function keydown(e){ - var key = (window.event) ? event.keyCode : e.keyCode; - if (key == 18 ) stxx.cloneDrawing=true; - } - */ - this.cloneDrawing = false; - /** - * READ ONLY. Toggles to true whenever the mouse cursor is within the chart (canvas) - * @type boolean - * @default - * @alias insideChart - * @memberof CIQ.ChartEngine - * @instance - */ - this.insideChart = false; - /** - * READ ONLY. Toggles to true if the mouse cursor is over the X Axis. - * @type boolean - * @default - * @alias overXAxis - * @memberof CIQ.ChartEngine - * @instance - */ - this.overXAxis = false; - /** - * READ ONLY. Toggles to true if the mouse cursor is over the Y Axis. - * @type boolean - * @default - * @alias overYAxis - * @memberof CIQ.ChartEngine - * @instance - */ - this.overYAxis = false; - /** - * READ ONLY. This gets set to true when the chart display has been initialized. - * @type boolean - * @default - * @alias displayInitialized - * @memberof CIQ.ChartEngine - * @instance - */ - this.displayInitialized = false; - /** - * READ ONLY. Mouse pointer X pixel location in reference to the chart canvas. where cx=0 and cy=0 is the upper left corner of the chart. - * @type number - * @alias cx - * @memberof CIQ.ChartEngine - * @instance - */ - this.cx = null; - /** - * READ ONLY. If `true` the chart is in 'historical mode' and no [quotefeed]{@tutorial DataIntegrationQuoteFeeds} 'update' calls will be made. - * - * This happens when [setSpan]{@link CIQ.ChartEngine#setSpan} or [setRange]{@link CIQ.ChartEngine#setRange} are used to 'jump' to a range in the distance past, - * where the master data no longer extends from the end of the displayed range to the current bar. - * @type boolean - * @alias isHistoricalModeSet - * @memberof CIQ.ChartEngine - * @instance - */ - this.isHistoricalModeSet = null; - /** - * READ ONLY. Mouse pointer Y pixel location in reference to the chart canvas. where cx=0 and cy=0 is the upper left corner of the chart. - * @type number - * @alias cy - * @memberof CIQ.ChartEngine - * @instance - */ - this.cy = null; - - this.clicks = { - s1MS: -1, - e1MS: -1, - s2MS: -1, - e2MS: -1 - }; - - this.cancelTouchSingleClick = false; // Set this to true whenever a screen item is touched so as to avoid a chart touch event - this.locale = null; // set by setLocale() - /** - * READ ONLY. Timezone of the masterData, set by {@link CIQ.ChartEngine#setTimeZone}. - * @type {string} - * @alias dataZone - * @memberof CIQ.ChartEngine - * @instance - */ - this.dataZone = null; - /** - * READ ONLY. Timezone to display on the chart, set by {@link CIQ.ChartEngine#setTimeZone}. - * @type {string} - * @alias displayZone - * @memberof CIQ.ChartEngine - * @instance - */ - this.displayZone = null; - this.timeZoneOffset = 0; // use setTimeZone() to compute this value - this.masterData = null; // Contains the historical quotes for the current chart - /** - * Register this function to transform the data set before a createDataSet() event; such as change in periodicity. - * You can also explicitly call stxx.createDataSet(); stxx.draw(); to trigger this function. - * - * Expected Format : - * - * fc(stxChart, dataSet); - * - * @type {function} - * @alias transformDataSetPre - * @memberof CIQ.ChartEngine - * @instance - * @example - * stxx.transformDataSetPre=function(stxx, dataSet){ - * for(var i=0;i < dataSet.length;i++){ - * // do something to the dataset here - * } - * } - */ - this.transformDataSetPre = null; - /** - * Register this function to transform the data set after a createDataSet() event; such as change in periodicity. - * You can also explicitly call stxx.createDataSet(); stxx.draw(); to trigger this function. - * - * Expected Format : - * - * fc(stxChart, dataSet, min low price in the dataset, max high price in the dataset); - * - * @type {function} - * @alias transformDataSetPost - * @memberof CIQ.ChartEngine - * @instance - * @example - * stxx.transformDataSetPost=function(self, dataSet, min, max){ - * for(var i=0;i < dataSet.length;i++){ - * // do something to the dataset here - * } - * } - */ - this.transformDataSetPost = null; - /** - * This is the callback function used by {@link CIQ.ChartEngine#setPeriodicity} when no quotefeed has been attached to the chart. - * Called if the masterData does not have the interval requested. - * - * Do not initialize if you are using a {@link quotefeed } - * - * @type {function} - * @alias dataCallback - * @memberof CIQ.ChartEngine - * @instance - * @example - * stxx.dataCallback=function(){ - * // put code here to get the new data in the correct periodicity. - * // use layout.interval and layout.periodicity to determine what you need. - * // finally call stxx.loadChart(symbol,data) to load the data and render the chart. - * } - */ - this.dataCallback = null; - /** - * Stores a list of active drawing object on the chart. Serialized renditions of drawings can be added using {@link CIQ.ChartEngine#createDrawing} and removed using {@link CIQ.ChartEngine#removeDrawing} - * @type array - * @default - * @alias drawingObjects - * @memberof CIQ.ChartEngine - * @instance - */ - this.drawingObjects = []; - this.undoStamps = []; - /** - * READ ONLY. Flag that specifies whether the background canvas should be used to draw grid lines and axes. - * This flag is set to true when the `canvasShim` contains child elements. The `canvasShim` is the background - * canvas — an HTML container behind the main chart canvas. - * - * Check this flag to determine whether the `canvasShim` is being used to create background drawings. - * - * @see {@link CIQ.Visualization} - * @see {@link CIQ.ChartEngine#embedVisualization}. - * @type boolean - * @default - * @alias useBackgroundCanvas - * @memberof CIQ.ChartEngine - * @instance - * @since 7.4.0 - */ - this.useBackgroundCanvas = false; - /** - * READ ONLY. Access the renderer controlling the main series. - * @type CIQ.Renderer - * @default - * @alias mainSeriesRenderer - * @memberof CIQ.ChartEngine - * @instance - */ - this.mainSeriesRenderer = null; - /** - * Object that stores the styles used by the chart. - * @type object - * @alias styles - * @instance - * @memberof CIQ.ChartEngine - */ - this.styles = {}; // Contains CSS styles used internally to render canvas elements - /** - * Placeholder for plugin data sets. This array will register each plug in object, complete with their functions. - * - * If defined, Plug-in instances will be called by their corresponding native functions for the following: - * - consolidate ( called by {@link CIQ.ChartEngine#consolidatedQuote}) - * - drawUnder (called by draw before rendering underlays) - * - drawOver (called by draw after rendering overlays) - * - {@link CIQ.ChartEngine#setMasterData} - * - {@link CIQ.ChartEngine#updateChartData} - * - {@link CIQ.ChartEngine#initializeChart} - * - {@link CIQ.ChartEngine#createDataSet} - * - {@link CIQ.ChartEngine#findHighlights} - * @type array - * @memberof CIQ.ChartEngine - * @instance - * @private - */ - this.plugins = {}; - /** - * Cloned copy of {@link CIQ.ChartEngine.currentVectorParameters} object template. - * Use it to store the settings for the active drawing tool. - * @type {CIQ.ChartEngine.currentVectorParameters} - * @default - * @alias currentVectorParameters - * @memberof CIQ.ChartEngine - * @instance - * @tsdeclaration - * public currentVectorParameters: typeof CIQ.ChartEngine.currentVectorParameters - */ - this.currentVectorParameters = CIQ.clone( - CIQ.ChartEngine.currentVectorParameters - ); // contains the current drawing parameters for this chart - /** - * Holds {@link CIQ.ChartEngine.Chart} object - * @type CIQ.ChartEngine.Chart - * @default - * @alias chart - * @memberof CIQ.ChartEngine - * @instance - */ - this.chart = new CIQ.ChartEngine.Chart(); - var chart = this.chart; - chart.name = "chart"; - chart.yAxis.name = "chart"; - chart.canvas = null; // Contains the HTML5 canvas with the chart and drawings - chart.tempCanvas = null; // lays on top of the canvas and is used when creating drawings - chart.container = config.container; - if (CIQ.Market) chart.market = new CIQ.Market(); //create a default market, always open - this.charts.chart = chart; - - CIQ.extend(this, config); - - if (config.container) { - if (this.registerHTMLElements) this.registerHTMLElements(); - // Initialize the very basic dimensions of chart so that it is operational immediately - chart.width = chart.container.clientWidth - chart.yAxis.width; - this.setCandleWidth(this.layout.candleWidth, chart); - chart.canvasHeight = chart.container.clientHeight; - } - this.construct(); - }; - - /** - * READ ONLY. Toggles to true when a drawing is initiated - * @type boolean - * @default - * @alias drawingLine - * @static - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.drawingLine = false; - /** - * READ ONLY. Toggles to true when a panel is being resized - * @type boolean - * @default - * @alias resizingPanel - * @static - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.resizingPanel = null; - /** - * READ ONLY. Current X screen coordinate of the crosshair. - * @type number - * @default - * @alias crosshairX - * @static - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.crosshairX = 0; - /** - * READ ONLY. Current Y screen coordinate of the crosshair. - * @type number - * @default - * @alias crosshairY - * @static - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.crosshairY = 0; - /** - * [Browser animation API](https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame) is on by default. - * @type boolean - * @default - * @alias useAnimation - * @static - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.useAnimation = true; - - CIQ.ChartEngine.enableCaching = false; - /** - * Set to true to true to bypass all touch event handling. - * @type number - * @default - * @alias ignoreTouch - * @static - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.ignoreTouch = false; - /** - * Mitigates problems clearing the canvas on old (defective) Android devices by performing additional function on the canvas, normally not needed on the newer devices. - * Set to false to boost native android browser performance, but at risk of "double candle" display errors on some older devices. - * @type boolean - * @default - * @alias useOldAndroidClear - * @static - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.useOldAndroidClear = true; - - // Documented in standard/drawing.js - CIQ.ChartEngine.currentVectorParameters = {}; - - /** - * If set to a valid time zone identifier, then new CIQ.ChartEngine objects will pull their display timezone from this. - * @type {string} - * @alias defaultDisplayTimeZone - * @static - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.defaultDisplayTimeZone = null; // If set, then new CIQ.ChartEngine objects will pull their display timezone from this - - /** - * If set, overrides the default base path for plug-ins. - * - * By default, plug-ins loaded by means of a script tag check for resources inside the - * plug-ins directory, `plugins/`. However, if the application is served from outside the - * `chartiq` directory, or the plug-ins folder is otherwise not available at `./`, you may - * need to specify where the plug-ins directory can be found so resources can be loaded. - * - * Path must end in `/`. - * - * @type string - * @default - * @alias pluginBasePath - * @static - * @memberof CIQ.ChartEngine - * @since 8.0.0 - */ - CIQ.ChartEngine.pluginBasePath = "plugins/"; - - CIQ.ChartEngine.registeredContainers = []; // This will contain an array of all of the CIQ container objects - // Note that if you are dynamically destroying containers in the DOM you should delete them from this array when you do so - - /** - * Calls the functions in {@link CIQ.ChartEngine.helpersToRegister} to instantiate the registered - * chart helpers. - * - * @param {CIQ.ChartEngine} stx A chart engine reference, which is passed to the functions in - * {@link CIQ.ChartEngine.helpersToRegister}. - * - * @memberof CIQ.ChartEngine - * @private - * @since 8.2.0 - */ - CIQ.ChartEngine.registerHelpers = function (stx) { - CIQ.ChartEngine.helpersToRegister.forEach(function (registrationFn) { - registrationFn(stx); - }); - }; - - /** - * An array of functions that instantiate helpers for the chart engine. - * - * Modules that define a chart helper should push a function to this array so that the helper can - * be created by {@link CIQ.ChartEngine.registerHelpers}. The function should include a parameter - * of type {@link CIQ.ChartEngine} and attach the helper to the chart engine referenced by the - * parameter (see example). - * - * @type function[] - * @memberof CIQ.ChartEngine - * @private - * @since 8.2.0 - * - * @example - * CIQ.ChartEngine.helpersToRegister.push(function (stx) { - * stx.baselineHelper = new Map(); - * }); - */ - CIQ.ChartEngine.helpersToRegister = []; - - /** - * Private construction of the chart object. This is called from the actual constructor - * for CIQ.ChartEngine. - * @private - * @memberof CIQ.ChartEngine - * @since - * - 07/01/2015 - * - 7.1.0 Changed `longHoldTime` to 700ms default. - */ - CIQ.ChartEngine.prototype.construct = function () { - if (this.createChartPanel) { - this.stackPanel("chart", "chart", 1); - this.adjustPanelPositions(); - this.chart.panel = this.panels[this.chart.name]; - } - this.cx = 0; - this.cy = 0; - this.micropixels = 0; - this.callbackListeners = { - /** - * Called by {@link CIQ.ChartEngine.AdvancedInjectable#touchDoubleClick} when the chart - * is quickly tapped twice. - * - * @param {object} data Data relevant to the "tap" event. - * @param {CIQ.ChartEngine} data.stx The chart engine instance. - * @param {number} data.finger Indicates which finger double-tapped. - * @param {number} data.x The crosshairs x-coordinate. - * @param {number} data.y The crosshairs y-coordinate. - * - * @callback CIQ.ChartEngine~doubleTapEventListener - * @since 4.0.0 - * - * @see {@link CIQ.ChartEngine#addEventListener} - */ - doubleTap: [], - /** - * Called by {@link CIQ.ChartEngine#doubleClick} when the chart is quickly clicked or - * tapped twice. - * - * @param {object} data Data relevant to the double-click or double-tap event. - * @param {CIQ.ChartEngine} data.stx The chart engine instance. - * @param {number} data.button The button or finger that double-clicked or - * double-tapped. - * @param {number} data.x The double-click or crosshairs x-coordinate. - * @param {number} data.y The double-click or crosshairs y-coordinate. - * - * @callback CIQ.ChartEngine~doubleClickEventListener - * @since 8.0.0 - * - * @see {@link CIQ.ChartEngine#addEventListener} - */ - doubleClick: [], - /** - * Called when a drawing is added, removed, or modified. - * - * Such as calling {@link CIQ.ChartEngine#clearDrawings}, - * {@link CIQ.ChartEngine#removeDrawing}, {@link CIQ.ChartEngine#undoLast}, or - * {@link CIQ.ChartEngine#drawingClick}. - * - * @param {object} data Data relevant to the "drawing" event. - * @param {CIQ.ChartEngine} data.stx The chart engine instance. - * @param {string} data.symbol The current chart symbol. - * @param {object} data.symbolObject The symbol's value and display label - * ({@link CIQ.ChartEngine.Chart#symbolObject}). - * @param {object} data.layout The chart's layout object ({@link CIQ.ChartEngine#layout}). - * @param {Array} data.drawings The chart's current drawings ({@link CIQ.Drawing}). - * - * @callback CIQ.ChartEngine~drawingEventListener - * - * @see {@link CIQ.ChartEngine#addEventListener} - */ - drawing: [], - /** - * A right-click on a highlighted drawing. - * - * @param {object} data Data relevant to the "drawingEdit" event. - * @param {CIQ.ChartEngine} data.stx The chart engine instance. - * @param {CIQ.Drawing} data.drawing The highlighted drawing instance. - * - * @callback CIQ.ChartEngine~drawingEditEventListener - * - * @see {@link CIQ.ChartEngine#addEventListener} - */ - drawingEdit: [], - /** - * Called to open a window that can be moved and resized by the user. - * - * For example, called by {@link CIQ.Shortcuts} to display the keyboard shortcuts legend. - * - * @param {object} data Data relevant to the "floatingWindow" event. - * @param {string} data.type The type of floating window to open; for example, "shortcut" - * for a floating window containing the keyboard shortcuts legend (see - * {@link CIQ.Shortcuts}). - * @param {string} data.content The contents of the floating window, typically an HTML - * string. - * @param {object} [data.container] The DOM element that visually contains the floating - * window. The window is positioned on screen relative to the element (see - * {@link WebComponents.cq-floating-window.DocWindow#positionRelativeTo}). Defaults - * to `document.body`. - *

**Note:** The markup of the DOM element does not need to lexically contain the - * markup of the floating window. - * @param {string} [data.title] Text that appears in the title bar of the floating window. - * @param {number} [data.width] The width of the floating window in pixels. - * @param {boolean} [data.status] The floating window state: true, to open the floating - * window; false, to close it. If the parameter is not provided, the floating window - * is toggled (opened if closed, closed if open). - * @param {string} [data.tag] A label that identifies the floating window type; for - * example, "shortcut", which indicates that the floating window contains the keyboard - * shortcuts legend. - *

**Note:** Use this parameter to manage floating windows in a multi-chart - * document. Only one instance of a floating window is created for a given tag - * regardless of how many "floatingWindow" events occur having that tag, in which - * case a floating window can be shared by multiple charts. If floating windows do - * not have tags, new floating windows are created for new "floatingWindow" events - * even though the events may have the same `type` (see above). - * @param {function} [data.onClose] A callback to execute when the floating window is - * closed. - * - * @callback CIQ.ChartEngine~floatingWindowEventListener - * @since 8.2.0 - * - * @see {@link CIQ.ChartEngine#addEventListener} - */ - floatingWindow: [], - /** - * Called when a change occurs in the chart layout. - * - * Layout changes are caused by: - * - Calling {@link CIQ.ChartEngine#setChartType}, - * {@link CIQ.ChartEngine#setAggregationType}, {@link CIQ.ChartEngine#setChartScale}, or - * {@link CIQ.ChartEngine#setAdjusted} - * - Using the {@link WebComponents.cq-toolbar} to disable the current active drawing tool - * or toggling the crosshair - * - Using the {@link WebComponents.cq-views} to activate a serialized layout - * - Modifying a series ({@link CIQ.ChartEngine#modifySeries}) - * - Setting a new periodicity ({@link CIQ.ChartEngine#setPeriodicity}) - * - Adding or removing a study overlay - * ({@link CIQ.ChartEngine.AdvancedInjectable#removeOverlay}) - * - Adding or removing any new panels (and their corresponding studies) - * - Zooming in ({@link CIQ.ChartEngine#zoomIn}) or - * zooming out ({@link CIQ.ChartEngine#zoomOut}) - * - Setting ranges with {@link CIQ.ChartEngine#setSpan} or - * {@link CIQ.ChartEngine#setRange} - * - Nullifying a programmatically set span or range by user panning - * - Enabling or disabling [extended hours]{@link CIQ.ExtendedHours} - * - Toggling the [range slider]{@link CIQ.RangeSlider} - * - * **Note** Scrolling and panning changes are not considered a layout change but rather a - * shift of the view window in the same layout. To detect those, register to listen for - * ["scroll" events]{@link CIQ.ChartEngine~scrollEventListener}. - * - * @param {object} data Data relevant to the "layout" event. - * @param {CIQ.ChartEngine} data.stx The chart engine instance. - * @param {string} data.symbol The current chart symbol. - * @param {object} data.symbolObject The symbol's value and display label - * ({@link CIQ.ChartEngine.Chart#symbolObject}). - * @param {object} data.layout The chart's layout object ({@link CIQ.ChartEngine#layout}). - * @param {Array} data.drawings The chart's current drawings ({@link CIQ.Drawing}). - * - * @callback CIQ.ChartEngine~layoutEventListener - * - * @see {@link CIQ.ChartEngine#addEventListener} - */ - layout: [], - /** - * Called when the mouse is clicked on the chart and held down. - * - * @param {object} data Data relevant to the "longhold" event. - * @param {CIQ.ChartEngine} data.stx The chart engine instance. - * @param {string} data.panel The panel being clicked. - * @param {number} data.x The crosshair x-coordinate. - * @param {number} data.y The crosshair y-coordinate. - * - * @callback CIQ.ChartEngine~longholdEventListener - * - * @see {@link CIQ.ChartEngine#addEventListener} - */ - longhold: [], - /** - * Called when the pointer is moved inside the chart, even on panning or horizontal - * swiping. - * - * @param {object} data Data relevant to the "move" event. - * @param {CIQ.ChartEngine} data.stx The chart engine instance. - * @param {string} data.panel The panel where the mouse is active. - * @param {number} data.x The pointer x-coordinate. - * @param {number} data.y The pointer y-coordinate. - * @param {boolean} data.grab True if the chart is being dragged. - * - * @callback CIQ.ChartEngine~moveEventListener - * - * @see {@link CIQ.ChartEngine#addEventListener} - */ - move: [], - /** - * Called when the [quotefeed interface](quotefeed.html) loads a complete data set as - * a result of: - * - [symbol changes]{@link CIQ.ChartEngine#loadChart} or - * - [periodicity]{@link CIQ.ChartEngine#setPeriodicity}, - * [range]{@link CIQ.ChartEngine#setRange}, or [span]{@link CIQ.ChartEngine#setSpan} - * changes requiring new data. - * - * @param {object} data Data relevant to the "newChart" event. - * @param {CIQ.ChartEngine} data.stx The chart engine instance. - * @param {string} data.symbol The current chart symbol. - * @param {object} data.symbolObject The symbol's value and display label, - * {@link CIQ.ChartEngine.Chart#symbolObject}. - * @param {boolean} data.moreAvailable True if {@link quotefeed~dataCallback} reports - * that more data is available. - * @param {boolean} data.upToDate True if {@link quotefeed~dataCallback} reports that - * no more future data is available. - * @param {object} data.quoteDriver The quote feed driver. - * - * @callback CIQ.ChartEngine~newChartEventListener - * @since 8.0.0 Added the `upToDate` parameter. - * - * @see {@link CIQ.ChartEngine#addEventListener} - */ - newChart: [], - /** - * Called when a message toaster notification event (a toast) has occurred. - * - * @param {object} data Data relevant to the notification event. - * @param {string} data.message Text to display in the notification. - * @param {string} [data.position="top"] Alignment of the notification: "top" or "bottom". - * Overrides the `defaultPosition` attribute of the - * [``]{@link WebComponents.cq-message-toaster} element. - * @param {string} [data.type="info"] Notification style: "info", "error", "warning", or - * "confirmation". - * @param {string} [data.transition] Type of animation used to display and dismiss (remove) - * the notification: "fade", "slide", "pop" or "drop". The default is no transition. - * Overrides the `defaultTransition` attribute of the - * [``]{@link WebComponents.cq-message-toaster} element. - * @param {number} [data.displayTime=10] Number of seconds to display the notification - * before automatically dismissing it. A value of 0 causes the notification to remain - * on screen — preventing other notifications from - * displaying — until the notification is selected by the user and - * dismissed. Overrides the `defaultDisplayTime` attribute of the - * [``]{@link WebComponents.cq-message-toaster} element. - * @param {number} [data.priority=0] Priority of the notification relative to others in - * the notification queue. Higher priority notifications are displayed before - * notifications with lower priority. For example, a notification with - * priority = 4 is displayed before a notification with - * priority = 1. Notifications with the same priority are displayed - * in the order they were created; that is, in the order they entered the - * notification queue. - * @param {function} [data.callback] Function to call when the notification is selected - * (dismissed) by the user. If the notification is dismissed automatically (see - * `displayTime`), this function is not called. - * - * @callback CIQ.ChartEngine~notificationEventListener - * @since 8.2.0 - * - * @see {@link CIQ.ChartEngine#addEventListener} - */ - notification: [], - /** - * Called when the periodicity is changed, for example, by - * {@link CIQ.ChartEngine#setPeriodicity}. - * - * This event listener can be used instead of - * [layoutEventListener]{@link CIQ.ChartEngine~layoutEventListener} for events that only - * need to be triggered when the periodicity changes. - * - * @param {object} data Data relevant to the "periodicity" event. - * @param {CIQ.ChartEngine} data.stx Reference to the chart engine. - * @param {boolean} data.differentData Indicates whether the chart needs new data to - * conform with the new periodicity. Typically, the value for this parameter is - * obtained from a call to {@link CIQ.ChartEngine#needDifferentData}. - * @param {CIQ.ChartEngine~PeriodicityParameters} data.prevPeriodicity The periodicity - * before the periodicity change event. - * - * @callback CIQ.ChartEngine~periodicityEventListener - * @since 8.1.0 - * - * @see {@link CIQ.ChartEngine#addEventListener} - */ - periodicity: [], - /** - * Called when preferences are changed. - * - * Such as when calling {@link CIQ.ChartEngine#setTimeZone}, - * {@link CIQ.ChartEngine#importPreferences}, {@link CIQ.Drawing.saveConfig}, or - * {@link CIQ.Drawing.restoreDefaultConfig} or when making language changes using the - * {@link WebComponents.cq-language-dialog}. - * - * @param {object} data Data relevant to the "preferences" event. - * @param {CIQ.ChartEngine} data.stx The chart engine instance. - * @param {string} data.symbol The current chart symbol. - * @param {object} data.symbolObject The symbol's value and display label - * ({@link CIQ.ChartEngine.Chart#symbolObject}). - * @param {object} data.layout The chart's layout object ({@link CIQ.ChartEngine#layout}). - * @param {Array} data.drawingObjects The chart's current drawings - * ({@link CIQ.ChartEngine#drawingObjects}). - * - * @callback CIQ.ChartEngine~preferencesEventListener - * - * @see {@link CIQ.ChartEngine#addEventListener} - */ - preferences: [], - /** - * Called on "mouseup" after the chart is right-clicked. - * - * **Note:** By default, right-clicks are only captured when mousing over chart objects - * such as series and drawings. To enable right-click anywhere on the chart, the - * "contextmenu" event listener must be modified as follows: - * ``` - * document.removeEventListener("contextmenu", CIQ.ChartEngine.handleContextMenu); - * document.addEventListener( - * "contextmenu", - * function(e) { - * if (!e) e = event; - * if (e.preventDefault) e.preventDefault(); - * return false; - * } - * ); - * ``` - * - * @param {object} data Data relevant to the "rightClick" event. - * @param {CIQ.ChartEngine} data.stx The chart engine instance. - * @param {string} panel The panel that was clicked. - * @param {number} data.x The click x-coordinate. - * @param {number} data.y The click y-coordinate. - * - * @callback CIQ.ChartEngine~rightClickEventListener - * - * @see {@link CIQ.ChartEngine#addEventListener} - * @see {@link CIQ.ChartEngine.handleContextMenu} - * - * @example Trigger and provide location and details when clicking a series: - * stxx.addEventListener("tap", function(tapObject) { - * if (this.anyHighlighted) { - * for (let n in this.chart.seriesRenderers) { - * const r = this.chart.seriesRenderers[n]; - * for(let j = 0; j < r.seriesParams.length; j++) { - * series = r.seriesParams[j]; - * if (series.highlight) { - * const bar = this.barFromPixel(tapObject.x); - * if (this.chart.dataSegment[bar]) { - * // Replace console.log with your required logic. - * console.log('Tap event at pixel x: ' + tapObject.x + ' y: '+ tapObject.y); - * console.log('Price:', this.priceFromPixel(tapObject.y), ' Date: ', this.chart.dataSegment[bar].DT); - * console.log('Series Details: ',JSON.stringify(series)); - * } - * } - * } - * } - * } - * }); - */ - rightClick: [], - /** - * Called when the chart is panned and scrolled in any direction or is horizontally swiped. - * - * @param {object} data Data relevant to the "scroll" event. - * @param {CIQ.ChartEngine} data.stx The chart engine instance. - * @param {string} data.panel The panel where the mouse is active. - * @param {number} data.x The mouse x-coordinate. - * @param {number} data.y The mouse y-coordinate. - * - * @callback CIQ.ChartEngine~scrollEventListener - * @since 6.3.0 - * - * @see {@link CIQ.ChartEngine#addEventListener} - */ - scroll: [], - /** - * Called when an overlay-type study is right-clicked. - * - * @param {object} data Data relevant to the "studyOverlayEdit" event. - * @param {CIQ.ChartEngine} data.stx The chart engine instance. - * @param {object} data.sd The study object study descriptor. - * @param {object} data.inputs The inputs from the study descriptor. - * @param {object} data.outputs The outputs from the study descriptor. - * @param {object} data.parameters The parameters from the study descriptor. - * - * @callback CIQ.ChartEngine~studyOverlayEditEventListener - * - * @see {@link CIQ.ChartEngine#addEventListener} - * - * @example - * stxx.addEventListener("studyOverlayEdit", function(studyData) { - * CIQ.alert(studyData.sd.name); - * const helper = new CIQ.Studies.DialogHelper({ name: studyData.sd.type, stx: studyData.stx }); - * console.log('Inputs:',JSON.stringify(helper.inputs)); - * console.log('Outputs:',JSON.stringify(helper.outputs)); - * console.log('Parameters:',JSON.stringify(helper.parameters)); - * // Call your menu here with the data returned in helper. - * // Modify parameters as needed and call addStudy or replaceStudy. - * }); - */ - studyOverlayEdit: [], - /** - * Called when a panel-type study is edited. - * - * @param {object} data Data relevant to the "studyPanelEdit" event. - * @param {CIQ.ChartEngine} data.stx The chart engine instance. - * @param {object} data.sd The study object study descriptor. - * @param {object} data.inputs The inputs from the study descriptor. - * @param {object} data.outputs The outputs from the study descriptor. - * @param {object} data.parameters The parameters from the study descriptor. - * - * @callback CIQ.ChartEngine~studyPanelEditEventListener - * - * @see {@link CIQ.ChartEngine#addEventListener} - */ - studyPanelEdit: [], - /** - * Called when the chart's symbols change. Including secondary series and underlying - * symbols for studies (e.g., price relative study). - * - * @param {object} data Data relevant to the "symbolChange" event. - * @param {CIQ.ChartEngine} data.stx The chart engine instance. - * @param {string} data.symbol The new chart symbol. - * @param {object} data.symbolObject The symbol's value and display label - * ({@link CIQ.ChartEngine.Chart#symbolObject}). - * @param {string} data.action An action type being performed on the symbol. Possible - * options: - * - `add-series` — A series was added - * - `master` — The master symbol was changed - * - `remove-series` — A series was removed - - * @callback CIQ.ChartEngine~symbolChangeEventListener - * - * @see {@link CIQ.ChartEngine#addEventListener} - */ - symbolChange: [], - /** - * Called when a symbol is imported into the layout, including secondary series and - * underlying symbols for studies (e.g., price relative study). - * - * This listener is not called by other types of symbol changes. - * - * @param {object} data Data relevant to the "symbolImport" event. - * @param {CIQ.ChartEngine} data.stx The chart engine instance. - * @param {string} data.symbol The new chart symbol. - * @param {object} data.symbolObject The symbol's value and display label - * ({@link CIQ.ChartEngine.Chart#symbolObject}). - * @param {string} data.action An action type being performed on the symbol. Possible - * options: - * - `add-series` — A series was added - * - `master` — The master symbol was changed - * - `remove-series` — A series was removed - * - * @callback CIQ.ChartEngine~symbolImportEventListener - * - * @see {@link CIQ.ChartEngine#addEventListener} - * @see {@link CIQ.ChartEngine#importLayout} - */ - symbolImport: [], - /** - * Called on ["mouseup"]{@link CIQ.ChartEngine.AdvancedInjectable#touchSingleClick} when - * the chart is tapped. - * - * @param {object} data Data relevant to the "tap" event. - * @param {CIQ.ChartEngine} data.stx The chart engine instance. - * @param {string} data.panel The panel being tapped. - * @param {number} data.x The tap x-coordinate. - * @param {number} data.y The tap y-coordinate. - * - * @callback CIQ.ChartEngine~tapEventListener - * - * @see {@link CIQ.ChartEngine#addEventListener} - */ - tap: [], - /** - * Called when a new theme is activated on the chart, such as by - * {@link WebComponents.cq-themes} initialization or using the - * {@link WebComponents.cq-theme-dialog}. - * - * @param {object} data Data relevant to the "theme" event. - * @param {CIQ.ChartEngine} data.stx The chart engine instance. - * @param {string} data.symbol The current chart symbol. - * @param {object} data.symbolObject The symbol's value and display label - * ({@link CIQ.ChartEngine.Chart#symbolObject}). - * @param {object} data.layout The chart's layout object ({@link CIQ.ChartEngine#layout}). - * @param {Array} data.drawingObjects The chart's current drawings - * ({@link CIQ.ChartEngine#drawingObjects}). - * - * @callback CIQ.ChartEngine~themeEventListener - * - * @see {@link CIQ.ChartEngine#addEventListener} - */ - theme: [], - /** - * Called when an undo stamp is created for drawing events. - * - * See {@link CIQ.ChartEngine#undoStamp} - * - * @param {object} data Data relevant to the "undoStamp" event. - * @param {CIQ.ChartEngine} data.stx The chart engine instance. - * @param {Array} data.before The chart drawing objects before the change. - * @param {Array} data.after The chart drawings objects after the change. - * - * @callback CIQ.ChartEngine~undoStampEventListener - * - * @see {@link CIQ.ChartEngine#addEventListener} - */ - undoStamp: [] - }; - CIQ.ChartEngine.registerHelpers(this); - }; - - var prototypeSwitches = { - /** - * Time in MS to trigger a long hold on the chart. - * @type number - * @default - * @memberof CIQ.ChartEngine.prototype - */ - longHoldTime: 700, - /** - * Number of pixels the mouse needs to move in vertical direction to "unlock" vertical panning/scrolling. - * Setting to a number larger than the pixels on the canvas will also disable vertical scrolling - * @type number - * @default - * @alias yTolerance - * @memberof CIQ.ChartEngine.prototype - * @example - * //This will disable the tolerance, so panning will immediately follow the user actions without maintaining a locked vertical location when panning left or right. - * var stxx=new CIQ.ChartEngine({container:document.querySelector(".chartContainer"), layout:{"candleWidth": 16, "crosshair":true}}); - * stxx.yTolerance=0; - */ - yTolerance: 100, - - /** - * Number of bars to always keep in view when the user pans forwards or backwards. - * If this is set to less than 1, it will be possible to have a blank chart. - * - * See {@link CIQ.ChartEngine.Chart#allowScrollPast} and {@link CIQ.ChartEngine.Chart#allowScrollFuture} for instructions on how to prevent users from scrolling past the last bar on the chart in either direction; which may supersede this setting. - * @type number - * @default - * @alias minimumLeftBars - * @memberof CIQ.ChartEngine.prototype - * @since 05-2016-10 - */ - minimumLeftBars: 1, - /** - * Set to true to reverse direction of mousewheel for zooming - * @type boolean - * @default - * @alias reverseMouseWheel - * @memberof CIQ.ChartEngine.prototype - */ - reverseMouseWheel: false, - /** - * Set to false to turn off mousewheel acceleration effect; which depending on initial gesture speed, slowly slows down zooming as you let go of the wheel/pad. - * @type boolean - * @default - * @alias mouseWheelAcceleration - * @since 2015-11-1 - * @memberof CIQ.ChartEngine.prototype - */ - mouseWheelAcceleration: true, - /** - * Minimum candleWidth (in pixels) allowed when zooming out. Determines the maximum number of ticks to display on the chart. - * - * Use {@link CIQ.ChartEngine#minimumZoomTicks} to set the minimum number of ticks that must remain on the chart during a zoom-in operation. - * - * When candleWidth<1 and {@link CIQ.ChartEngine.Chart#lineApproximation} true, - * will create approximation of a line chart to improve rendering performance. - * Regardless, anything smaller than **0.3 pixels** may cause performance issues when zooming out. - * @type number - * @default - * @alias minimumCandleWidth - * @memberof CIQ.ChartEngine.prototype - */ - minimumCandleWidth: 1, - /** - * Maximum candleWidth (in pixels) allowed when zooming in. Determines the minimum number of ticks to display on the chart. - * - * Also see {@link CIQ.ChartEngine#minimumZoomTicks} to set the minimum number of ticks that must remain on the chart during a zoom-in operation. - * - * @type number - * @default - * @alias maximumCandleWidth - * @memberof CIQ.ChartEngine.prototype - * @since 7.4.0 - */ - maximumCandleWidth: 200, - /** - * Set to the number of ticks that **must** remain on the chart when zooming in. - * - * Use {@link CIQ.ChartEngine#minimumCandleWidth} to set the minimum number of ticks that must remain on the chart during a zoom-out operation. - * @type number - * @default - * @alias minimumZoomTicks - * @memberof CIQ.ChartEngine.prototype - * @since 07-2016-16.6 - */ - minimumZoomTicks: 9, - /** - * Set to false to disable any user zooming on the chart - * @type boolean - * @default - * @alias allowZoom - * @memberof CIQ.ChartEngine.prototype - * @since 04-2015 - * @example - * var stxx=new CIQ.ChartEngine({container:document.querySelector(".chartContainer"), allowZoom:false, layout:{"candleWidth": 16, "crosshair":true}}); - */ - allowZoom: true, - /** - * Set to false to disable any user scrolling of the chart - * @type boolean - * @default - * @alias allowScroll - * @memberof CIQ.ChartEngine.prototype - * @since 04-2015 - * @example - * var stxx=new CIQ.ChartEngine({container:document.querySelector(".chartContainer"), allowScroll:false, layout:{"candleWidth": 16, "crosshair":true}}); - */ - allowScroll: true, - /** - * Set to false to disable 2 finger side swipe motion for scrolling - * @type boolean - * @default - * @alias allowSideswipe - * @memberof CIQ.ChartEngine.prototype - * @since 2015-12-08 - */ - allowSideswipe: true, - /** - * If set to true then a three finger movement will increment periodicity. - * @type boolean - * @default - * @alias allowThreeFingerTouch - * @memberof CIQ.ChartEngine.prototype - */ - allowThreeFingerTouch: false, - /** - * Set to `true` to bypass right clicks on **all** overlay types and their hovering pop-ups. - * Or define independent settings for series, studies, and drawings by using an object instead. - * - * On touch devices, it will bypass {@link CIQ.ChartEngine.AdvancedInjectable#touchDoubleClick} - * - * Also see: - * - [rightClickEventListener]{@link CIQ.ChartEngine~rightClickEventListener} - * - {@link CIQ.ChartEngine.AdvancedInjectable#rightClickHighlighted} - * - * @type object - * @default - * @alias bypassRightClick - * @memberof CIQ.ChartEngine.prototype - * @since - * - 2016-07-16 - * - 5.1.0 An object containing booleans to separate series, studies, and drawings. - * @example - * this.bypassRightClick={ - * series: false, - * study: false, - * drawing: false - * }; - */ - bypassRightClick: { - series: false, - study: false, - drawing: false - }, - /** - * Function which can be used to modify the highlighted field to be used for an averaging-type drawing. - * Can be customized (overridden) to adjust certain fields, while passing through others. - * Note: if the field to be returned is a member of an object (e.g., AAPL.Close), the proper format - * for returning this would be "AAPL-->Close". - * @param {string} field dataSet field - * @return {string} adjusted field - * @type function - * @default - * @alias adjustHighlightedDataSetField - * @memberof CIQ.ChartEngine.prototype - * @example - * stxx.adjustHighlightedDataSetField=function(field){ - * if(!field) return null; - * for(var st in this.layout.studies){ - * var study=this.layout.studies[st]; - * if(study.outputMap.hasOwnProperty(field)) { - * // adjust the field based on the study in which it belongs - * if(study.type=="Pivot Points") return null; - * ... - * break; - * } - * } - * for(var sr in this.chart.series){ - * var series=this.chart.series[sr]; - * if(series.id==field.split("-->")[0]) { - * // adjust the field based on the series in which it belongs - * if(series.id=="AAPL") return series.id+"-->High"; - * ... - * break; - * } - * } - * return field; - * }; - * @since 7.0.0 - */ - adjustHighlightedDataSetField: function (field) { - return field; - }, - - /** - * Set these to false to not display the up and down arrows in the panel management component. See {@link CIQ.ChartEngine#controls} for alternate methods and more details. - * @type boolean - * @default - * @alias displayIconsUpDown - * @memberof CIQ.ChartEngine.prototype - * @example - * stxx.displayIconsUpDown=false; - */ - displayIconsUpDown: true, - /** - * Set these to false to not display this panel management component. See {@link CIQ.ChartEngine#controls} for alternate methods and more details. - * @type boolean - * @default - * @alias displayIconsSolo - * @memberof CIQ.ChartEngine.prototype - * @example - * stxx.displayIconsSolo=false; - */ - displayIconsSolo: true, - /** - * Set these to false to not display this panel management component. See {@link CIQ.ChartEngine#controls} for alternate methods and more details. - * @type boolean - * @default - * @alias displayIconsClose - * @memberof CIQ.ChartEngine.prototype - * @since 3.0.7 - * @example - * stxx.displayIconsClose=false; - */ - displayIconsClose: true, - /** - * Set these to false to not display this panel management component. See {@link CIQ.ChartEngine#controls} for alternate methods and more details. - * @type boolean - * @default - * @alias displayPanelResize - * @memberof CIQ.ChartEngine.prototype - * @example - * stxx.displayPanelResize=false; - */ - displayPanelResize: true, - /** - * Set this to true to hide even the chart panel when soloing a non-chart panel. Normally chart panels are not hidden when soloing. - * @type boolean - * @default - * @alias soloPanelToFullScreen - * @memberof CIQ.ChartEngine.prototype - * @since 3.0.7 - * @example - * stxx.soloPanelToFullScreen=true; - */ - soloPanelToFullScreen: false, - /** - * Only reposition markers this many milliseconds. Set to null for no visible delay. Set to 0 for a Zero Delay timeout. (lower numbers are more CPU intensive). - * See {@tutorial Markers} for more details on adding markers to your charts - * @type number - * @default - * @alias markerDelay - * @memberof CIQ.ChartEngine.prototype - * @example - * stxx.markerDelay=25; - */ - markerDelay: null, - /** - * When set to true, the backing store for the canvas is used. - * This results in crisper display but with a noticeable performance penalty in some browsers. - * The default is true. - * If improved performance is necessary, set the variable as shown in the example. - * The example allows mobile devices (android/ipad/iphone) to continue using the backing store while being bypassed in others (desktop browsers). - * - * @type boolean - * @default - * @alias useBackingStore - * @memberof CIQ.ChartEngine.prototype - * @since 3.0.0 - * @example - * stxx.useBackingStore=CIQ.isMobile; - */ - useBackingStore: true, - - /** - * On touch devices, when set to true, the backing store will be turned off while a user is panning or zooming the chart. This increases performance during the operation by reducing - * resolution. Resolution is restored once the user lifts their finger. Generally, you'll want to enable this dynamically when you know that a particular device has poor canvas performance. - * This defaults to true but can be disabled by setting to false. - * @type boolean - * @default - * @alias disableBackingStoreDuringTouch - * @memberOf CIQ.ChartEngine.prototype - * @since 4.0.0 - */ - disableBackingStoreDuringTouch: CIQ.isMobile || (CIQ.isSurface && CIQ.isFF), - /** - * Primarily intended for mobile devices, if set to `false` it will allow up/down swiping to pass through the chart container so the main page can manage it. - * This allows a user swiping up and down to swipe through the chart instead of having the chart capture the event and prevent the page from continue moving. - * It therefore produces a more natural up/down swiping motion throughout the page. - * @type boolean - * @default - * @alias captureTouchEvents - * @memberof CIQ.ChartEngine.prototype - * @since 12-2015-08 - */ - captureTouchEvents: true, - /** - * If set to `false` it will allow up/down [mouseWheel / touchPad swiping]{@link CIQ.ChartEngine.AdvancedInjectable#mouseWheel} to pass through the chart container so the main page can manage it. - * This allows a user swiping up and down to swipe through the chart instead of having the chart capture the event and prevent the page from continue moving. - * It therefore produces a more natural up/down sliding of the page. - * @type boolean - * @default - * @alias captureMouseWheelEvents - * @memberof CIQ.ChartEngine.prototype - * @since m-2016-12-01.4 - */ - captureMouseWheelEvents: true, - /** - * If true (the default), requires a tap on a drawing, plot, y-axis, or other object before - * the object is highlighted. If false, allows highlighting of objects when the mouse cursor - * moves over the objects. - * - * @type boolean - * @default - * @alias tapForHighlighting - * @memberof CIQ.ChartEngine.prototype - * @since 8.2.0 - */ - tapForHighlighting: true, - /** - * The maximum number of milliseconds between clicks that trigger a double-click. - * - * @alias doubleClickTime - * @memberof CIQ.ChartEngine.prototype - * @type {number} - * @default - * @since 8.0.0 - */ - doubleClickTime: 250, - /** - * Shape of the floating y axis label. - * - * Available options: - * - ["roundRectArrow"]{@link CIQ.roundRectArrow} - * - ["semiRoundRect"]{@link CIQ.semiRoundRect} - * - ["roundRect"]{@link CIQ.roundRect} - * - ["tickedRect"]{@link CIQ.tickedRect} - * - ["rect"]{@link CIQ.rect} - * - ["noop"]{@link CIQ.noop} - * @type string - * @default - * @alias yaxisLabelStyle - * @memberof CIQ.ChartEngine.prototype - * @example - * var stxx=new CIQ.ChartEngine({container: document.querySelector(".chartContainer")}); - * stxx.yaxisLabelStyle="roundRectArrow"; - */ - yaxisLabelStyle: "roundRectArrow", - /** - * Set to false if you don't want the axis borders drawn. This will override individual settings on yaxis and xaxis. - * @type boolean - * @default - * @alias axisBorders - * @memberof CIQ.ChartEngine.prototype - */ - axisBorders: null, - /** - * Set to true to have drawings highlight only the last applied drawing if more than one is intersected at a time. - * @type boolean - * @default - * @since 5.0.0 - * @alias singleDrawingHighlight - * @memberof CIQ.ChartEngine.prototype - */ - singleDrawingHighlight: true, - /** - * X axis offset for touch devices so that finger isn't blocking crosshair - * @type number - * @default - * @alias crosshairXOffset - * @memberof CIQ.ChartEngine.prototype - */ - crosshairXOffset: -40, - /** - * Y axis Offset for touch devices so that finger isn't blocking crosshair - * @type number - * @default - * @alias crosshairYOffset - * @memberof CIQ.ChartEngine.prototype - */ - crosshairYOffset: -40, - /** - * When set to true, line and mountain charts are extended slightly in order to reduce whitespace at the right edge of the chart - * @type boolean - * @default - * @alias extendLastTick - * @memberof CIQ.ChartEngine.prototype - * @since 05-2016-10 The line will be extended to the end of the chart (full candle width) instead of the candle border, even when using `yaxisLabelStyle` "roundRectArrow". - */ - extendLastTick: false, - /** - * This is the callback function used to translate languages. - * Should return a translated phrase given the English phrase. See separate translation file for list of phrases. - * - * Expected format : - * - * var translatedWord = fc(english); - * - * Defaults to {@link CIQ.I18N.translate} - * @type {function} - * @alias translationCallback - * @memberof CIQ.ChartEngine.prototype - */ - translationCallback: null, - /** - * Set this to `true` if your server returns data in week or monthly ticks, and doesn't require rolling computation from daily. - * - * If set to `false`: - * - 'weekly' bars will be aligned to the first open market day of the week according to the active [market definitions]{@link CIQ.Market} (Weeks start Sunday). - * - 'monthly' bar will be aligned to the first market day of the month according to the active [market definitions]{@link CIQ.Market}. - * - * @type boolean - * @default - * @alias dontRoll - * @memberof CIQ.ChartEngine.prototype - */ - dontRoll: false, - /** - * Set to true to allow an equation to be entered into the symbol input. For example, =2*IBM-GM - * NOTE: the equation needs to be preceded by an equals sign (=) in order for it to be parsed as an equation. - * See {@link CIQ.formatEquation} and {@link CIQ.computeEquationChart} for more details on allowed syntax. - * @type boolean - * @default - * @alias allowEquations - * @memberof CIQ.ChartEngine.prototype - */ - allowEquations: true, - /** - * If set, {@link CIQ.ChartEngine#doCleanupGaps} will be automatically called - * on intra-day or daily interval charts to create missing data points during market hours/days for stocks that may have missing bars. - * - * `carry` will cause the closing price to be carried forward, resulting in dashes on a candle/bar chart or continuous line on a line or mountain chart. - *
`gap` will cause physical breaks to occur on the chart in the gapped position. - * - * **Note:** the clean up process uses the active periodicity and the active market definition, if any. - * So you must first set those to ensure proper clean up. - * If no market definition is enabled, the clean up will assume gaps need to be added during the entire 24 hours period, every day. - *
See "{@link CIQ.Market}" for details on how to properly configure the library to your market hours requirements. - *
No gaps will be cleaned for `tick` since by nature it is no a predictable interval. - * - * **Important information to prevent inaccurate 'gapping'**
- * - This parameter must be set **before** any data is loaded into the chart. - * - The cleanup process leverages the current market iterator which traverses along the timeline on the exact minute/second/millisecond mark for intraday data. - * As such, you must ensure your time stamps match this requirement. - * If your data does not comply, you must round your timestamps before sending the data into the chart. - *
For example, if in minute periodicity, seconds and milliseconds should not be present or be set to zero. - * - * @type string - * @default - * @alias cleanupGaps - * @memberof CIQ.ChartEngine.prototype - * - * @example If using a quoteFeed, just set the parameter will automatically call {@link CIQ.ChartEngine#doCleanupGaps} - * var stxx=new CIQ.ChartEngine({container:document.querySelector(".chartContainer")}); - * stxx.attachQuoteFeed(yourFeed,{refreshInterval:1}); - * stxx.setMarketFactory(CIQ.Market.Symbology.factory); - * stxx.cleanupGaps='carry'; - * stxx.setPeriodicity({period:1, interval:5, timeUnit:"minute"}); - * stxx.loadChart("SPY"); - * - * @since - * - 15-07-01 Gaps are automatically cleaned up unless this flag is set to false. - * - 2015-11-1 Gaps are not automatically cleaned unless this flag is set to true. - * - m-2016-12-01.4 Now supports "carry" and "gap" values. Setting to non-false will default to "carry" for backward compatibility with prior versions. - */ - cleanupGaps: false, - /** - * When set to `true`, the requested range will be visually preserved between [symbol changes]{@link CIQ.ChartEngine#loadChart} or when a [layout is imported]{@link CIQ.ChartEngine#importLayout}, - * even if the data required to fill the left and/or right side of the x axis is not present. - * - * This behavior is similar to setting `goIntoPast` and `goIntoFuture` when calling [setRange]{@link CIQ.ChartEngine#setRange}/[setSpan]{@link CIQ.ChartEngine#setSpan} explicitly. - * - * Please note that at the moment, a range will not be preserved when using [addSeries]{@link CIQ.ChartEngine#addSeries}, if the new data extends further than the currently loaded data for the primary instrument. - * For this, you will need to manually call [setRange]{@link CIQ.ChartEngine#setRange}/[setSpan]{@link CIQ.ChartEngine#setSpan} in the [addSeries]{@link CIQ.ChartEngine#addSeries} callback. - * @type boolean - * @default - * @alias staticRange - * @memberof CIQ.ChartEngine.prototype - * @since 5.1.2 - */ - staticRange: false, - /** - * Set a maximum size for the dataSet to prevent it from growing excessively large. - * - * Once the max number of records have been loaded, pagination requests will be ignored - * and older data will be dropped from the end (historical) side of the dataSet array as new bars arrive, until that number is increased. - * - * Set to 0 to let it grow forever. - * @type number - * @default - * @alias maxDataSetSize - * @memberof CIQ.ChartEngine.prototype - */ - maxDataSetSize: 20000, - /** - * Set a maximum size for masterData to prevent it from growing excessively large. - * - * Once the max number of records have been loaded, pagination requests will be ignored - * and older data will be dropped from the end (historical) side of the masterData array as new bars arrive, until that number is increased. - * - * By default (set to 0) masterData is unlimited and will grow forever. - * - * Note: when rolling up data due to periodicity, you should anticipate large enough masterData to accomodate the desired chart length. - * - * @type {number} - * @default - * @alias maxMasterDataSize - * @memberof CIQ.ChartEngine.prototype - * @since 3.0.0 - */ - maxMasterDataSize: 0, - /** - * Set to zero to avoid resize checking loop. See {@link CIQ.ChartEngine#setResizeTimer} for more details - * @type number - * @default - * @alias resizeDetectMS - * @memberof CIQ.ChartEngine.prototype - */ - resizeDetectMS: 1000, - /** - * Set to true to display the xAxis below all panels. - * By default, the x axis will be rendered right under the main chart panel. - * @type boolean - * @default - * @alias xAxisAsFooter - * @memberof CIQ.ChartEngine.prototype - * @since - * - 05-2016-10 - * - 4.1.0 Now defaults to true. - * - 5.2.0 Vertical grid lines in study panels no longer dependent on this property and will be always displayed. - */ - xAxisAsFooter: true, - /** - * Sets the x axis height in pixels. - * - * - Set to null to automatically adjust to the size of the axis font. - * - Set to 0 completely remove the x axis. - * - Use {@link CIQ.ChartEngine.XAxis#noDraw} to temporarily hide the axis, but maintain its spacing. - * @type boolean - * @default - * @alias xaxisHeight - * @memberof CIQ.ChartEngine.prototype - * @since 4.1.0 Now defaults to 30px. - */ - xaxisHeight: 30, - /** - * Set to true to display horizontal grid lines on studies. - * This parameter is only used when a custom y axis is **not** defined for the study. - * - * To also disable zones and center lines on studies add: - * ```CIQ.Studies.drawHorizontal=function(){};``` - * For more details see {@link CIQ.Studies.doPostDrawYAxis} - * @type boolean - * @default - * @alias displayGridLinesInStudies - * @memberof CIQ.ChartEngine.prototype - * @since 3.0.0 - */ - displayGridLinesInStudies: false, - /** - * When true serialize methods may escape their values with encodeURIComponent. - * @type boolean - * @default - * @alias escapeOnSerialize - * @memberof CIQ.ChartEngine.prototype - * @since 4.1.0 - */ - escapeOnSerialize: true, - /** - * Adjust to increase or decrease the default width of candles (see {@tutorial Understanding Chart Range}). - * @type number - * @default - * @alias candleWidthPercent - * @memberof CIQ.ChartEngine.prototype - */ - candleWidthPercent: 0.65, - /** - * Set to `true` to color any OHLC type rendering (bar, candles) as well as the volume study, - * based on difference between open and close, rather than difference between previous close and current close. - * - * Used in {@link CIQ.Renderer.OHLC} and {@link CIQ.Studies.createVolumeChart} - * @type boolean - * @default - * @alias colorByCandleDirection - * @memberof CIQ.ChartEngine.prototype - * @since 4.0.0 - */ - colorByCandleDirection: false, - /** - * chart types which do not draw wicks on candles - * @type object - * @default - * @alias noWicksOnCandles - * @memberof CIQ.ChartEngine.prototype - */ - noWicksOnCandles: { renko: true, linebreak: true }, - /** - * chart types which require fetching as many bars as possible (since they aggregate data) - * @type object - * @default - * @alias fetchMaximumBars - * @memberof CIQ.ChartEngine.prototype - */ - fetchMaximumBars: { - rangebars: true, - kagi: true, - renko: true, - linebreak: true, - pandf: true - }, - /** - * Comparisons by default start at the close value of the previous bar. - * Set this to true to start at the current bar instead. - * @type boolean - * @default - * @alias startComparisonsAtFirstVisibleBar - * @memberof CIQ.ChartEngine.prototype - * @since 7.3.0 - */ - startComparisonsAtFirstVisibleBar: false, - - /** - * Animations. These can be overridden with customized EaseMachines - * To disable an animation replace with an EaseMchine with one ms as the second parameter. - * @type {object} - * @alias animations - * @memberof CIQ.ChartEngine.prototype - * @example - * stxx.animations.zoom=new CIQ.EaseMachine(Math["easeOutCubic"],1); - */ - animations: { - zoom: { - isStub: true, - run: function (cb, _orig, _new) { - cb(_new); - }, - stop: function () {}, - reset: function () {}, - running: false, - hasCompleted: true - } - }, - - /** - * Map of default values to be used to statically set periodicity (candle width) upon range selection when using {@link CIQ.ChartEngine#setRange} - * - * **Default Value:** - * ``` - * [ - * { - * rangeInMS : CIQ.WEEK, // Any range less than a week, load 5 minute bars - * periodicity : 1, - * interval : 5, - * timeUnit : 'minute' - * }, - * { - * rangeInMS : CIQ.MONTH, // Any range less than a month, load 30 minute bars - * periodicity : 1, - * interval : 30, - * timeUnit : 'minute' - * }, - * { - * rangeInMS : CIQ.YEAR, // Any range less than a year, load day bars - * periodicity : 1, - * interval : "day" - * }, - * { - * rangeInMS : CIQ.DECADE, // Any range less than 10 years, load weekly bars - * periodicity : 1, - * interval : "week" - * }, - * { - * rangeInMS : CIQ.DECADE * 10, // Any range less than a century, load monthly bars - * periodicity : 1, - * interval : "month" - * }, - * { - * rangeInMS : Number.MAX_VALUE, // Anything greater than a century, load yearly bars - * periodicity : 12, - * interval : "month" - * } - * ] - * ``` - * @type array - * @alias staticRangePeriodicityMap - * @memberof CIQ.ChartEngine.prototype - * @since m-2016-12-01 - */ - staticRangePeriodicityMap: [ - { - rangeInMS: CIQ.WEEK, // Any range less than a week, load 5 minute bars - periodicity: 1, - interval: 5, - timeUnit: "minute" - }, - { - rangeInMS: CIQ.MONTH, // Any range less than a month, load 30 minute bars - periodicity: 1, - interval: 30, - timeUnit: "minute" - }, - { - rangeInMS: CIQ.YEAR, // Any range less than a year, load day bars - periodicity: 1, - interval: "day" - }, - { - rangeInMS: CIQ.DECADE, // Any range less than 10 years, load weekly bars - periodicity: 1, - interval: "week" - }, - { - rangeInMS: CIQ.DECADE * 10, // Any range less than a century, load monthly bars - periodicity: 1, - interval: "month" - }, - { - rangeInMS: Number.MAX_VALUE, // Anything greater than a century, load yearly bars - periodicity: 12, - interval: "month" - } - ], - - /** - * Map of multiples to be used to dynamically determine periodicity (candle width) upon range selection when using {@link CIQ.ChartEngine#setRange} - * Used when {@link CIQ.ChartEngine#autoPickCandleWidth} is enabled - * - * **Default Value:** - * ``` - * [ - * { - * interval : 1, - * rangeInMS : CIQ.MINUTE - * }, - * { - * interval : 5, - * rangeInMS : CIQ.MINUTE * 5 - * }, - * { - * interval : 30, - * rangeInMS : CIQ.MINUTE * 30 - * }, - * { - * interval : 60, - * rangeInMS : CIQ.MINUTE * 60 - * }, - * { - * interval : "day", - * rangeInMS : CIQ.DAY - * }, - * { - * interval : "month", - * rangeInMS : CIQ.MONTH - * }, - * { - * interval : "year", - * rangeInMS : CIQ.YEAR - * } - * ] - * ``` - * - * @type array - * @alias dynamicRangePeriodicityMap - * @memberof CIQ.ChartEngine.prototype - * @since 11-2016-29 - */ - dynamicRangePeriodicityMap: [ - { - interval: 1, - timeUnit: "minute", - rangeInMS: CIQ.MINUTE - }, - { - interval: 5, - timeUnit: "minute", - rangeInMS: CIQ.MINUTE * 5 - }, - { - interval: 30, - timeUnit: "minute", - rangeInMS: CIQ.MINUTE * 30 - }, - { - interval: 60, - timeUnit: "minute", - rangeInMS: CIQ.MINUTE * 60 - }, - { - interval: "day", - rangeInMS: CIQ.DAY - }, - { - interval: "month", - rangeInMS: CIQ.MONTH - }, - { - interval: "year", - rangeInMS: CIQ.YEAR - } - ], - /** - * Contains the current chart layout. - * - * Layout parameters can be directly **pre-set** on a chart at the time the engine is instantiated, by providing an object exactly matching **the internal layout format**.
- * The following is an example for setting some of the available layout parameters: - * ``` - * var stxx=new CIQ.ChartEngine({ - * container: document.querySelector(".chartContainer"), - * layout:{ - * "crosshair":true, - * "interval":"day", - * "periodicity":1, - * "chartType": "candle", - * "candleWidth": 16 - * } - * }); - * ``` - * These parameters will then be activated when [loadChart()]{@link CIQ.ChartEngine#loadChart} is called to render the chart.
- * Once a chart is rendered, most of these parameters become `READ ONLY`,and must be modified using their corresponding methods, as indicated in the documentation, to ensure chart integrity. - * - * **Important Note on internal periodicity format:**
- * Internal format of the layout object **does not match the parameters** used in ​{@link CIQ.ChartEngine#setPeriodicity} or {@link CIQ.ChartEngine#loadChart}. - *
Use {@link CIQ.ChartEngine#getPeriodicity} to extract internal periodicity into the expected external format. - * - * See [importLayout]{@link CIQ.ChartEngine#importLayout} and [exportLayout]{@link CIQ.ChartEngine#exportLayout} for methods to serialize a layout and restore previously saved settings. - * - * @type object - * @alias layout - * @memberof CIQ.ChartEngine.prototype - */ - layout: { - /** - * READ ONLY. Chart interval. - * - * Note that internal interval format will differ from API parameters used in {@link CIQ.ChartEngine#setPeriodicity} and {@link CIQ.ChartEngine#loadChart}. - * - * Available options are: - * - [number] representing minutes - * - "day" - * - "week" - * - "month" - * - * See the [Periodicity and Quote feed]{@tutorial Periodicity} tutorial. - * @type string - * @default - * @alias CIQ.ChartEngine#layout[`interval`] - * @memberof CIQ.ChartEngine.layout# - */ - interval: "day", - /** - * READ ONLY. Number of periods per interval/timeUnit - * - * See the [Periodicity and Quote feed]{@tutorial Periodicity} tutorial. - * @type number - * @default - * @alias CIQ.ChartEngine#layout[`periodicity`] - * @memberof CIQ.ChartEngine.layout# - */ - periodicity: 1, - /** - * READ ONLY. Time unit for the interval. - * - * Note that internal timeUnit format will differ from API parameters used in {@link CIQ.ChartEngine#setPeriodicity} and {@link CIQ.ChartEngine#loadChart}. - * - * See the [Periodicity and Quote feed]{@tutorial Periodicity} tutorial. - * Available options are: - * - "millisecond" - * - "second" - * - "minute" - * - null for "day", "week", "month" periodicity - * @type string - * @default - * @alias CIQ.ChartEngine#layout[`timeUnit`] - * @memberof CIQ.ChartEngine.layout# - */ - timeUnit: null, - /** - * READ ONLY. Candle Width In pixels ( see {@tutorial Understanding Chart Range} and {@link CIQ.ChartEngine#candleWidthPercent}) - * @type number - * @default - * @alias CIQ.ChartEngine#layout[`candleWidth`] - * @memberof CIQ.ChartEngine.layout# - */ - candleWidth: 8, - /** - * READ ONLY. The primary y-axis and all linked drawings, series and studies will display inverted (flipped) from its previous state when 'true'. - * - * Use {@link CIQ.ChartEngine#flipChart} to set. - * @type boolean - * @default - * @alias CIQ.ChartEngine#layout[`flipped`] - * @memberof CIQ.ChartEngine.layout# - */ - flipped: false, - volumeUnderlay: false, - /** - * Whether adjusted or nominal prices are being displayed. - * If true then the chart will look for "Adj_Close" in the masterData as an alternative to "Close". - * @type boolean - * @default - * @alias CIQ.ChartEngine#layout[`adj`] - * @memberof CIQ.ChartEngine.layout# - * @instance - */ - adj: true, - /** - * Set to `true` to enable crosshairs in the active layout. - * - * Also see {@link CIQ.ChartEngine.AdvancedInjectable#doDisplayCrosshairs} for more details on crosshairs behavior. - * - * @example - * // enable crosshair (usually called from a UI button/toggle) - * stx.layout.crosshair=true; - * // add this if you want the crosshair to display right away instead of when the user starts moving the mouse over the chart - * stx.doDisplayCrosshairs(); - * // add this if you want to trigger a layout change event; maybe to save the layout. - * stx.dispatch("layout", {stx:stx, symbol: stx.chart.symbol, symbolObject:stx.chart.symbolObject, layout:stx.layout, drawings:stx.drawingObjects}); - * - * @type boolean - * @default - * @alias CIQ.ChartEngine#layout[`crosshair`] - * @memberof CIQ.ChartEngine.layout# - * @instance - */ - crosshair: false, - /** - * READ ONLY. The primary chart type. - * - * Available options are: - * - "none" - * - "line" - * - "step" - * - "mountain" - * - "baseline_delta" - * - "candle" - * - "bar" - * - "hlc" - * - "hlc_box" — Requires *js/extras/hlcbox.js*. - * - "hlc_shaded_box" — Requires *js/extras/hlcbox.js*. - * - "wave" - * - "scatterplot" - * - "histogram" - * - "rangechannel" - * - "marketdepth" — Requires the [Active Trader]{@link CIQ.MarketDepth} plug-in. See {@link CIQ.ChartEngine#updateCurrentMarketData} for data requirements. - * - "termstructure" — Requires the [Term Structure]{@link CIQ.TermStructure} plug-in. - * - * Variations of these types are available by prepending terms to the options as follows: - * - "step_" - add to mountain, marketdepth e.g. step_mountain, step_volume_marketdepth - * - "vertex_" - add to line, step, mountain, baseline_delta - * - "hollow_" - add to candle - * - "volume_" - add to candle, marketdepth e.g. mountain_volume_marketdepth (Adding volume to marketdepth also creates a volume histogram in the same panel) - * - "colored_" - add to line, mountain, step, bar, hlc - * - "mountain_" - add to baseline_delta, marketdepth e.g. mountain_volume_marketdepth - * - * Other options are available provided a renderer is created with a `requestNew` function which will support the option, see {@link CIQ.Renderer.Lines#requestNew} and {@link CIQ.Renderer.OHLC#requestNew} - * - * Use {@link CIQ.ChartEngine#setChartType} to set this value. - * - * See {@tutorial Chart Styles and Types} for more details. - * - * @type string - * @default - * @alias CIQ.ChartEngine#layout[`chartType`] - * @memberof CIQ.ChartEngine.layout# - * @since - * - 05-2016-10.1 Added "baseline_delta_mountain" and "colored_mountain". - * - 3.0.0 Added "histogram" and "step". - * - 3.0.7 Added "hlc". - * - 4.0.0 Added "colored_step" and "colored_hlc". - * - 5.1.0 More chart types available using combinations of terms. - * - 6.1.0 Added "marketdepth". - */ - chartType: "candle", - /** - * READ ONLY. Flag for extended hours time-frames. - * - * The chart includes the 'extended' parameter in the `params` object sent into the `fetch()` call. - * Your quote feed must be able to provide extended hours data when requested (`extended:true`) for any extended hours functionality to work. - * - * See {@link CIQ.ExtendedHours} and {@link CIQ.Market} for more details on how extended hours are set and used. - * @type boolean - * @default - * @alias CIQ.ChartEngine#layout[`extended`] - * @memberof CIQ.ChartEngine.layout# - */ - extended: false, - /** - * READ ONLY. Tracks the extended market sessions to display on the chart. - * - * See {@link CIQ.ExtendedHours} and {@link CIQ.Market} for more details on how extended hours are set and used. - * @type object - * @default - * @alias CIQ.ChartEngine#layout[`marketSessions`] - * @memberof CIQ.ChartEngine.layout# - * @example - * marketSessions = { - * "session1": true, - * "session2": true, - * "session3": false, - * "pre": true, - * "post": true - * } - * @since 06-2016-02 - */ - marketSessions: {}, //use defaults - /** - * READ ONLY. Active aggregation for the chart. - * - * Available options are: - * - "rangebars" - * - "ohlc" - * - "kagi" - * - "pandf" - * - "heikinashi" - * - "linebreak" - * - "renko" - * - * Use {@link CIQ.ChartEngine#setAggregationType} to set this value. - * - * See {@tutorial Chart Styles and Types} for more details. - * @type string - * @default - * @alias CIQ.ChartEngine#layout[`aggregationType`] - * @memberof CIQ.ChartEngine.layout# - */ - aggregationType: "ohlc", - /** - * READ ONLY. Active scale for the chart. - * - * See {@link CIQ.ChartEngine#setChartScale} - * - * **Replaces CIQ.ChartEngine.layout.semiLog** - * - * @type string - * @default - * @alias CIQ.ChartEngine#layout[`chartScale`] - * @memberof CIQ.ChartEngine.layout# - */ - chartScale: "linear", - /** - * READ ONLY. List of [study descriptors]{@link CIQ.Studies.StudyDescriptor} for the active studies on the chart. - * - * **Please note:** To facilitate study name translations, study names use zero-width non-joiner (unprintable) characters to delimit the general study name from the specific study parameters. - * Example: "\u200c"+"Aroon"+"\u200c"+" (14)". - * At translation time, the library will split the text into pieces using the ZWNJ characters, parentheses and commas to just translate the required part of a study name. - * For more information on ZWNJ characters see: [Zero-width_non-joiner](https://en.wikipedia.org/wiki/Zero-width_non-joiner). - * Please be aware of these ZWNJ characters, which will now be present in all study names and corresponding panel names; including the `layout.studies` study keys. - * Affected fields in the study descriptors could be `id `, `display`, `name` and `panel`. - *
To prevent issues, always use the names returned in the **study descriptor**. This will ensure compatibility between versions. - * >Example: - * >
Correct reference: - * >
`stxx.layout.studies["\u200c"+"Aroon"+"\u200c"+" (14)"];` - * >
Incorrect reference: - * >
`stxx.layout.studies["Aroon (14)"];` - * - * See {@link CIQ.Studies.addStudy} for more details - * - * @type object - * @default - * @alias CIQ.ChartEngine#layout[`studies`] - * @memberof CIQ.ChartEngine.layout# - */ - studies: {}, - /** - * READ ONLY. List of active chart panels. Usually correspond to a study or series. - * - * **Please note:** To facilitate study name translations, study names and their corresponding panels use zero-width non-joiner (unprintable) characters to delimit the general study name from the specific study parameters. - * Example: "\u200c"+"Aroon"+"\u200c"+" (14)". - * At translation time, the library will split the text into pieces using the ZWNJ characters, parentheses and commas to just translate the required part of a study name. - * For more information on ZWNJ characters see: [Zero-width_non-joiner](https://en.wikipedia.org/wiki/Zero-width_non-joiner). - * Please be aware of these ZWNJ characters, which will now be present in all study names and corresponding panel names; including the `layout.panels` study keys. - *
To prevent issues, always use the names returned in the **study descriptor**. This will ensure compatibility between versions. - * >Example: - * >
Correct reference: - * >
`stxx.layout.panels["\u200c"+"Aroon"+"\u200c"+" (14)"];` - * >
Incorrect reference: - * >
`stxx.layout.panels["Aroon(14)"];` - * - * See {@link CIQ.Studies.addStudy} for more details - * - * @type object - * @default - * @alias CIQ.ChartEngine#layout[`panels`] - * @memberof CIQ.ChartEngine.layout# - */ - panels: {}, - setSpan: {}, - /** - * READ ONLY. Specifies whether outlier detection is enabled. A value of true enables - * detection; false disables detection. - * - * See {@link CIQ.Outliers} for information on how outlier detection is used. - * - * @type boolean - * @default - * @alias CIQ.ChartEngine#layout[`outliers`] - * @memberof CIQ.ChartEngine.layout# - * @since 7.5.0 - */ - outliers: false - }, - /** - * Contains the chart preferences. - * - * Preferences parameters, unless otherwise indicated, can be set at any time and only require a [draw()]{@link CIQ.ChartEngine#draw} call to activate. - * - * See [importPreferences]{@link CIQ.ChartEngine#importPreferences} and [exportPreferences]{@link CIQ.ChartEngine#exportPreferences} for methods to serialize and restore previously saved preferences. - * - * @type object - * @alias preferences - * @memberof CIQ.ChartEngine.prototype - */ - preferences: { - /** - * Draw a horizontal line at the current price. - * Only drawn if the most recent tick is visible. - * - * See {@link CIQ.ChartEngine.AdvancedInjectable#drawCurrentHR} - * - * @type boolean - * @default - * @alias CIQ.ChartEngine#preferences[`currentPriceLine`] - * @memberof CIQ.ChartEngine.preferences# - * @since 05-2016-10 - */ - currentPriceLine: false, - /** - * Disables dragging a plot between panels or a y-axis within a panel. - * Separate switches are provided for dragging studies, series, or axes. - * Alternatively, all dragging may be disabled by setting `dragging: false`. - * - * To also disable the highlight when hovering over the Y axis, add the following: - * ``` - * CIQ.ChartEngine.YAxis.prototype.setBackground = function() {} - * ``` - * - * To also disable the highlight when hovering over the Y axis, add the following: - * ``` - * CIQ.ChartEngine.YAxis.prototype.setBackground = function() {} - * ``` - * - * @type object|boolean - * @default - * @alias CIQ.ChartEngine#preferences[`dragging`] - * @memberof CIQ.ChartEngine.preferences# - * @since 7.1.0 - * @example - * stxx.preferences.dragging.study=false; - * @example - * stxx.preferences.dragging=false; - */ - dragging: { - series: true, - study: true, - yaxis: true - }, - /** - * When using drawing tools, this will become an object when user saves the drawing parameters. - * A sub-object is created for each drawing tool. - * These preferences are used whenever the user selects that drawing object, and overrides the default stxx.currentVectorParameters. - * Use {@link CIQ.Drawing.saveConfig} to save the parameters to this object. - * @type object - * @default - * @alias CIQ.ChartEngine#preferences[`drawings`] - * @memberof CIQ.ChartEngine.preferences# - * @since 6.0.0 - */ - drawings: null, - /** - * Pixel radius for the invisible intersection box around the cursor used to determine if it has intersected with an element to be highlighted. - * This value is used primarily for non-touch cursor events (mouse, touchpad). Used on items removed with a right click such as series and drawings. - * - * Only applicable if the user has **not** tapped on the screen to set the location of the cross-hair. - * - * @type number - * @default - * @alias CIQ.ChartEngine#preferences[`highlightsRadius`] - * @memberof CIQ.ChartEngine.preferences# - * @since 3.0.0 - */ - highlightsRadius: 10, - /** - * For touch events on the chart canvas. Pixel radius for the invisible intersection box around the cursor used to determine if it has intersected - * with an element to be highlighted. The larger highlight radius is more suitable for the less precise input from touch events. Used on - * items removed with a right click such as series and drawings. - * - * **Only applicable for touch events while the cursor is not controlling the crosshair tool. Otherwise, highlightsRadius is used.** - * - * @type number - * @default - * @alias CIQ.ChartEngine#preferences[`highlightsTapRadius`] - * @memberof CIQ.ChartEngine.preferences# - * @since 3.0.0 - */ - highlightsTapRadius: 30, - /** - * Magnetizes the crosshairs to data points during drawing operations to improve initial placement accuracy. - * - * - When `true`, the magnet is considered "strong" and will always magnetize. - * - When a number, it is considered "weak" and will only magnetize within the area of defined. The radius of the circle is the number you set. - * - * **We recommend 75 as the value for the parameter when the `number` type is used.** - * - * It will not be used when an existing drawing is being repositioned. - * - * See {@link CIQ.ChartEngine.AdvancedInjectable#magnetize} for more details. - * - * @type boolean | number - * @default - * @alias CIQ.ChartEngine#preferences[`magnet`] - * @memberof CIQ.ChartEngine.preferences# - * @since 7.2.0 Magnets can now be applied to any series or study. - */ - magnet: false, - /** - * Locks the crosshair y-coordinate to the value of the field name specified for the tick under the cursor on the primary chart. - * - * For studies, create a `horizontalCrosshairFieldFN` function that will be called by `CIQ.Studies.addStudy`. - * The function must return the field name in the data set to reference. The function will not be called when the study is set to - * overlay or underlay the chart's panel. - * - * @example - * // Have the crosshairs lock to the "Close" field of the tick under the cursor. - * stxx.preferences.horizontalCrosshairField = "Close"; - * - * @example - * // Have the crosshair slock to the "ATR ATR (14)" field for a ATR study with a period of 14. - * CIQ.Studies.studyLibrary["ATR"].horizontalCrosshairFieldFN = function(stx, sd) { - * // Returns the field name, which should be created by the study's "calculateFN". - * return "ATR " + sd.name; - * }; - * - * @type string - * @default - * @alias CIQ.ChartEngine#preferences[`horizontalCrosshairField`] - * @memberof CIQ.ChartEngine.preferences# - * @since 04-2016-08 - */ - horizontalCrosshairField: null, - /** - * Set to true to display labels on y-axis for line based studies using {@link CIQ.Studies.displayIndividualSeriesAsLine} or {@link CIQ.Studies.displaySeriesAsLine} (this is overridden by the particular y-axis setting of {@link CIQ.ChartEngine.YAxis#drawPriceLabels}). - * This flag is checked inside these 2 functions to decide if a label should be set, as such if you do not wish to have a label on a particular study line, you can set this flag to `false`, before calling the function, and then back to `true`. - * @type boolean - * @default - * @alias CIQ.ChartEngine#preferences[`labels`] - * @memberof CIQ.ChartEngine.preferences# - * @example - * //do not display the price labels for this study - * stxx.preferences.labels=false; - * CIQ.Studies.displaySeriesAsLine(stx, sd, quotes); - * - * //restore price labels to default value - * stxx.preferences.labels=true; - */ - labels: true, - /** - * Stores preferred language for the chart. - * - * It can be individually restored using {@link CIQ.I18N.setLanguage} and activated by {@link CIQ.I18N.translateUI} - * @type {string} - * @alias CIQ.ChartEngine#preferences[`language`] - * @memberof CIQ.ChartEngine.preferences# - * @since 4.0.0 - */ - language: null, - /** - * Stores the preferred timezone for the display of the x axis labels. - * - * It is automatically set and can be individually restored by {@link CIQ.ChartEngine#setTimeZone}. - * @type {string} - * @alias CIQ.ChartEngine#preferences[`timezone`] - * @memberof CIQ.ChartEngine.preferences# - * @since 4.0.0 - */ - timeZone: null, - /** - * Initial whitespace on right of the screen in pixels. - * @type number - * @default - * @alias CIQ.ChartEngine#preferences[`whitespace`] - * @memberof CIQ.ChartEngine.preferences# - * @example - * // override the default value at declaration time - * var stxx=new CIQ.ChartEngine({container:document.querySelector(".chartContainer"), preferences:{"whitespace": 20}}); - */ - whitespace: 50, - /** - * zoom-in speed for mousewheel and zoom button. - * - * Range: **0 -.99999**. The closer to 1 the slower the zoom. - * @type number - * @default - * @alias CIQ.ChartEngine#preferences[`zoomInSpeed`] - * @memberof CIQ.ChartEngine.preferences# - * @example - * stxx.preferences.zoomInSpeed=.91; - * @example - * var stxx=new CIQ.ChartEngine({container:document.querySelector(".chartContainer"), preferences:{"zoomInSpeed": .98}}); - * @since 07/01/2015 - */ - zoomInSpeed: null, - /** - * zoom-out speed for mousewheel and zoom button. - * - * Range: **1-2**. The closer to 1 the slower the zoom. - * @type number - * @default - * @alias CIQ.ChartEngine#preferences[`zoomOutSpeed`] - * @memberof CIQ.ChartEngine.preferences# - * @example - * stxx.preferences.zoomOutSpeed=1.1; - * @example - * var stxx=new CIQ.ChartEngine({container:document.querySelector(".chartContainer"), preferences:{"zoomOutSpeed": 1}}); - * @since 07/01/2015 - */ - zoomOutSpeed: null, - /** - * If set to 'true', the mouse wheel zooming is centered by the mouse position. - * - * @type boolean - * @default - * @alias CIQ.ChartEngine#preferences[`zoomAtCurrentMousePosition`] - * @memberof CIQ.ChartEngine.preferences# - * @since 4.0.0 - */ - zoomAtCurrentMousePosition: false - }, - /** - * Used to control the behavior and throttling of real time updates in [updateChartData()]{@link CIQ.ChartEngine#updateChartData} to prevent overloading the chart engine - * @type object - * @alias streamParameters - * @memberof CIQ.ChartEngine.prototype - * @example - * // this will cause updates to be applied to the dataSegment immediately - * stxx.streamParameters.maxTicks=0; - * - * // here is how you would override all options - * stxx.streamParameters= {"maxWait":1000,"maxTicks":100} - */ - streamParameters: { - count: 0, - /** - * ms to wait before allowing update to occur (if this condition is met, the update will occur and all pending ticks will be loaded - exclusive of maxTicks) - * @type number - * @default - * @alias CIQ.ChartEngine#streamParameters[`maxWait`] - * @memberof CIQ.ChartEngine.streamParameters# - * @example - * // update without any time interval delay. - * stxx.streamParameters.maxWait=0; - */ - maxWait: 1000, - /** - * ticks to wait before allowing update to occur (if this condition is met, the update will occur and all pending ticks will be loaded - exclusive of maxWait) - * @type number - * @default - * @alias CIQ.ChartEngine#streamParameters[`maxTicks`] - * @memberof CIQ.ChartEngine.streamParameters# - * @example - * // update with every new tick added. - * stxx.streamParameters.maxTicks=0; - */ - maxTicks: 100, - timeout: -1 - }, - /** - * Allow the candle width to be determined dynamically when using {@link CIQ.ChartEngine#setRange}. - * This will require a valid {@link CIQ.ChartEngine#dynamicRangePeriodicityMap} - * @type object - * @default - * @alias autoPickCandleWidth - * @memberof CIQ.ChartEngine.prototype - * @example - * autoPickCandleWidth:{ - * turnOn: true, - * candleWidth: 5 - * } - * @since m-2016-12-01 - */ - autoPickCandleWidth: { - /** - * Turn to 'true' if you want the periodicity to be determined dynamically when using {@link CIQ.ChartEngine#setRange}. - * This will require a valid {@link CIQ.ChartEngine#dynamicRangePeriodicityMap} - * @type boolean - * @default - * @alias CIQ.ChartEngine#autoPickCandleWidth[`turnOn`] - * @memberof CIQ.ChartEngine.autoPickCandleWidth# - */ - turnOn: false, - - /** - * Set if you want to set a specific candle width when using {@link CIQ.ChartEngine#setRange}. - * This will require a valid {@link CIQ.ChartEngine#dynamicRangePeriodicityMap}. - * Set to '0' if you want the candle width to be determined according to chart type - * @type number - * @default - * @alias CIQ.ChartEngine#autoPickCandleWidth[`candleWidth`] - * @memberof CIQ.ChartEngine.autoPickCandleWidth# - */ - candleWidth: 5 - } - }; - - CIQ.extend(CIQ.ChartEngine.prototype, prototypeSwitches); - - // Constant bitmask for bar evaluation - CIQ.ChartEngine.NONE = 0; // no evaluation (black bars) - CIQ.ChartEngine.CLOSEUP = 1; // today's close greater than yesterday's close - CIQ.ChartEngine.CLOSEDOWN = 2; // today's close less than yesterday's close - CIQ.ChartEngine.CLOSEEVEN = 4; // today's close the same as yesterday's close - CIQ.ChartEngine.CANDLEUP = 8; // today's close greater than today's open - CIQ.ChartEngine.CANDLEDOWN = 16; // today's close less than today's open - CIQ.ChartEngine.CANDLEEVEN = 32; // today's close equal to today's open - - }; - - - let __js_core_formatData_ = (_exports) => { - - - var CIQ = _exports.CIQ; - - /** - * Converts a future month to the month index or vice versa. Month indexes begin with 1 for - * January. - * - * @param {string} x The value to convert. If numeric, converted to future month letter. If - * alphabetical, converted to month index. - * @return {string} The converted value. - * - * @memberof CIQ - */ - CIQ.convertFutureMonth = function (x) { - var y = x.toString(); - if (y.length <= 0 || y.length > 2) return ""; - switch (y) { - case "1": - return "F"; - case "2": - return "G"; - case "3": - return "H"; - case "4": - return "J"; - case "5": - return "K"; - case "6": - return "M"; - case "7": - return "N"; - case "8": - return "Q"; - case "9": - return "U"; - case "10": - return "V"; - case "11": - return "X"; - case "12": - return "Z"; - case "F": - return "1"; - case "G": - return "2"; - case "H": - return "3"; - case "J": - return "4"; - case "K": - return "5"; - case "M": - return "6"; - case "N": - return "7"; - case "Q": - return "8"; - case "U": - return "9"; - case "V": - return "10"; - case "X": - return "11"; - case "Z": - return "12"; - } - return y; - }; - - /** - * Prints out a number in US Dollar monetary representation - * @param {number} val The amount - * @param {number} [decimals=2] Number of decimal places. - * @param {string} [currency] Currency designation. If omitted, will use $. - * @return {string} US Dollar monetary representation - * // Returns $100.00 - * CIQ.money(100, 2); - * @memberof CIQ - */ - CIQ.money = function (val, decimals, currency) { - if (!currency) currency = "$"; - if (currency.length == 3) currency += " "; - if (!decimals && decimals !== 0) decimals = 2; - return ( - currency + CIQ.commas((Math.round(val * 10000) / 10000).toFixed(decimals)) - ); - }; - - /** - * Converts a currency code from ISO to char - * @param {string} code The string to convert, e.g. USD - * @return {string} The converted string, e.g. $ - * @memberof CIQ - */ - CIQ.convertCurrencyCode = function (code) { - var codes = { - JPY: "¥", - USD: "$", - AUD: "A$", - BRL: "R$", - CAD: "CA$", - CNY: "CN¥", - CZK: "Kč", - DKK: "kr", - EUR: "€", - GBP: "£", - HKD: "HK$", - HUF: "Ft", - ILS: "₪", - INR: "₹", - KRW: "₩", - MXN: "MX$", - NOK: "kr", - NZD: "NZ$", - PLN: "zł", - RUB: "руб", - SAR: "﷼", - SEK: "kr", - SGD: "S$", - THB: "฿", - TRY: "₺", - TWD: "NT$", - VND: "₫", - XAF: "FCFA", - XCD: "EC$", - XOF: "CFA", - XPF: "CFPF", - ZAR: "R" - }; - var rt = codes[code]; - if (rt) return rt; - return code; - }; - - /** - * Returns a string representation of a number with commas in thousands, millions or billions places. Note that this function does - * not handle values with more than 3 decimal places!!! - * @param {number} val The value - * @return {string} The result with commas - * @example - * // Returns 1,000,000 - * CIQ.commas(1000000); - * @memberof CIQ - */ - CIQ.commas = function (val) { - return val.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","); - }; - - /** - * Convenience function to convert API periodicity parameters to internal periodicity format. - * @param {string} period The period value as required by {@link CIQ.ChartEngine#setPeriodicity} - * @param {string} [interval] The interval value as required by {@link CIQ.ChartEngine#setPeriodicity} - * @param {string} timeUnit The timeUnit value as required by {@link CIQ.ChartEngine#setPeriodicity} - * @return {object} object containing internally compliant periodicity,interval, timeUnit - * @memberof CIQ - * @tsdeclaration - * function cleanPeriodicity(period: number, interval: number, timeUnit: string) - * function cleanPeriodicity(period: number, timeUnit: string) - * @since 5.1.1 - */ - CIQ.cleanPeriodicity = function (period, interval, timeUnit) { - if (isNaN(period)) period = 1; - if (!interval) interval = 1; - if (!isNaN(interval) && timeUnit) { - // disregard the numeric interval if a daily timeUnit is provided - // we'll need to propagate timeUnit down wherever we are examining the interval alone to determine the time unit - if ( - !( - timeUnit == "hour" || - timeUnit == "minute" || - timeUnit == "second" || - timeUnit == "millisecond" - ) - ) { - interval = timeUnit; - timeUnit = null; - } - } - - // clean up timeUnit - //if(CIQ.ChartEngine.isDailyInterval(interval)) timeUnit=null; // redundant - else if (interval == "tick") timeUnit = null; - else if (!timeUnit && !isNaN(interval)) timeUnit = "minute"; - - // support hour - if (timeUnit == "hour") { - timeUnit = "minute"; - interval = interval * 60; - } - - // support year - if (interval == "year") { - interval = "month"; - if (!period) period = 1; - period = period * 12; - } - - return { period: period, interval: interval, timeUnit: timeUnit }; - }; - - /** - * Creates a string with a periodicity that is easy to read given a chart - * @param {CIQ.ChartEngine} stx A chart object - * @return {string} A periodicity value that can be displayed to an end user - * @memberof CIQ - */ - CIQ.readablePeriodicity = function (stx) { - var displayPeriodicity = stx.layout.periodicity; - var displayInterval = stx.layout.interval; - if (typeof stx.layout.interval == "number" && stx.layout.timeUnit) { - displayPeriodicity = stx.layout.interval * stx.layout.periodicity; - displayInterval = stx.layout.timeUnit; - } else if (typeof stx.layout.interval == "number" && !stx.layout.timeUnit) { - displayPeriodicity = stx.layout.interval * stx.layout.periodicity; - displayInterval = "minute"; - } - if (displayPeriodicity % 60 === 0 && displayInterval == "minute") { - displayPeriodicity /= 60; - displayInterval = "hour"; - } - return ( - displayPeriodicity + " " + stx.translateIf(CIQ.capitalize(displayInterval)) - ); - }; - - /** - * Given a numeric price that may be a float with rounding errors, this will trim off the trailing zeroes - * @param {number} price The price - * @return {number} The price trimmed of trailing zeroes - * @memberof CIQ - */ - CIQ.fixPrice = function (price) { - if (!price && price !== 0) return null; - var p = price.toFixed(10); - for (var i = p.length - 1; i > 1; i--) { - if (p.charAt(i) != "0") break; - } - p = p.substring(0, i + 1); - return parseFloat(p); - }; - - /** - * Condenses a number into abbreviated form by adding "k","m","b" or "t". - * This method is used in the y-axis for example with volume studies. - * @param {number} txt - A numerical value - * @return {string} Condensed version of the number if over 999, otherwise returns `txt` untouched - * @example - * // This will return 12m - * condenseInt(12000000); - * @memberof CIQ - * @since 4.0.0 Now returns `txt` untouched if under 1000. Previously was removing all decimal places. - */ - CIQ.condenseInt = function (txt) { - if (txt === null || typeof txt == "undefined") return ""; - if (txt === Infinity || txt === -Infinity) return "n/a"; - var isNegative = txt < 0; - - if (!isNaN(txt)) { - txt = Math.abs(txt); - - if (txt > 1000000000000) txt = Math.round(txt / 100000000000) / 10 + "t"; - else if (txt > 100000000000) txt = Math.round(txt / 1000000000) + "b"; - //100b - else if (txt > 10000000000) - txt = (Math.round(txt / 100000000) / 10).toFixed(1) + "b"; - //10.1b - else if (txt > 1000000000) - txt = (Math.round(txt / 10000000) / 100).toFixed(2) + "b"; - //1.11b - else if (txt > 100000000) txt = Math.round(txt / 1000000) + "m"; - //100m - else if (txt > 10000000) - txt = (Math.round(txt / 100000) / 10).toFixed(1) + "m"; - //10.1m - else if (txt > 1000000) - txt = (Math.round(txt / 10000) / 100).toFixed(2) + "m"; - //1.11m - else if (txt > 100000) txt = Math.round(txt / 1000) + "k"; - //100k - else if (txt > 10000) txt = (Math.round(txt / 100) / 10).toFixed(1) + "k"; - //10.1k - else if (txt > 1000) txt = (Math.round(txt / 10) / 100).toFixed(2) + "k"; - //1.11k - else txt = txt.toString(); - } else { - txt = txt.toString(); - } - - if (isNegative) txt = "-" + txt; - return txt; - }; - - /** - * Determines how many decimal places the security trades. - * - * This is the default calculateTradingDecimalPlaces function. It is used by {@link CIQ.ChartEngine#setMasterData} to round off the prices - * to an appropriate number of decimal places. The function is assigned to {@link CIQ.ChartEngine.Chart#calculateTradingDecimalPlaces}}, - * but you may set to your own logic instead. - * - * The default algorithm is to check the most recent 50 quotes and find the maximum number of decimal places that the stock has traded. - * This will work for most securities but if your market data feed has rounding errors - * or bad data then you may want to supplement this algorithm that checks the maximum value by security type. - * - * It defaults to a minimum of 2 decimals. - * @param {object} params Parameters - * @param {CIQ.ChartEngine} params.stx The chart object - * @param {CIQ.ChartEngine.Chart} params.chart The chart in question - * @param {string} params.symbol The symbol string - * @param {object} params.symbolObject The symbol object. If you create charts with just stock symbol then symbolObject.symbol will contain that symbol - * @return {number} The number of decimal places - * @memberof CIQ - * @example - * //set your own logic for calculating decimal places. - * var stxx=new CIQ.ChartEngine({container:document.querySelector(".chartContainer"), preferences:{labels:false, currentPriceLine:true, whitespace:0}}); - * stxx.chart.calculateTradingDecimalPlaces=yourCustomFunction; - * @example - // default code - CIQ.calculateTradingDecimalPlaces=function(params){ - var chart=params.chart; - var decimalPlaces=2; - var quotesToCheck = 50; // Check up to 50 recent quotes - var masterData=chart.masterData; - if(masterData && masterData.length > quotesToCheck){ - // exclude the current quote by setting i=2 in case animation is enabled. Animation uses very large decimals to allow for smooth movements. - for(var i=2;idecimalPlaces){ - decimalPlaces=dp; - } - } - } - } - } - var maxDecimalPlaces=chart.yAxis.maxDecimalPlaces; - if(decimalPlaces>maxDecimalPlaces && maxDecimalPlaces!==null) decimalPlaces=maxDecimalPlaces; - return decimalPlaces; - }; - */ - CIQ.calculateTradingDecimalPlaces = function (params) { - var chart = params.chart; - var decimalPlaces = 2; - var quotesToCheck = 50; // Check up to 50 recent quotes - var masterData = chart.masterData; - if (masterData && masterData.length > quotesToCheck) { - // exclude the current quote by setting i=2 in case animation is enabled. Animation uses very large decimals to allow for smooth movements. - for (var i = 2; i < quotesToCheck; i++) { - var position = masterData.length - i; - if (position < 0) break; - var quotes = masterData[position]; - if (quotes.Close && typeof quotes.Close == "number") { - var cs = quotes.Close.toString(); - var point = cs.indexOf("."); - if (point != -1) { - var dp = cs.length - point - 1; - if (dp > decimalPlaces) { - decimalPlaces = dp; - } - } - } - } - } - var maxDecimalPlaces = chart.yAxis.maxDecimalPlaces; - if (decimalPlaces > maxDecimalPlaces && maxDecimalPlaces !== null) - decimalPlaces = maxDecimalPlaces; - return decimalPlaces; - }; - - /** - * This method will return a tuple [min,max] that contains the minimum - * and maximum values in the series where values are `series[field]`. - * - * @param {array} series The series - * @param {string} field The name of the series to look at - * @param {string} subField The name of the field within the series to look at - * @param {boolean} highLow True when comparing max High/min Low vs a specific field - * @return {array} Tuple containing min and max values in the series - * @memberof CIQ - * @since 5.1.0 Added subField, highLow arguments - */ - CIQ.minMax = function (series, field, subField, highLow) { - var min = Number.MAX_VALUE; - var max = Number.MAX_VALUE * -1; - if (!subField) subField = "Close"; - var highField = highLow ? "High" : subField; - var lowField = highLow ? "Low" : subField; - for (var i = 0; i < series.length; i++) { - var entry = series[i]; - if (!entry) continue; - var fVal = entry[field]; - if (!fVal && fVal !== 0) continue; - var sfVal = fVal; - if (typeof fVal === "object") sfVal = fVal[highField]; - if (!isNaN(sfVal) && (sfVal || sfVal === 0)) { - max = Math.max(max, sfVal); - } - if (typeof fVal === "object") sfVal = fVal[lowField]; - if (!isNaN(sfVal) && (sfVal || sfVal === 0)) { - min = Math.min(min, sfVal); - } - } - return [min, max]; - }; - - /** - * Returns true if two symbols match. Symbols can be strings or symbolObjects. By default, the "symbol" member is compared, and then - * a "source" member if one exists. - * If the objects have an "equals()" function member then that will be used for comparison. - * You can override this with your own method if you have other requirements. - * @param {object} left Symbol object - * @param {object} right Symbol object - * @return {boolean} true if the same - * @memberOf CIQ - */ - CIQ.symbolEqual = function (left, right) { - if (!left || !right) return false; - if (typeof left != "object") left = { symbol: left }; - if (typeof right != "object") right = { symbol: right }; - if (typeof left.equals == "function") { - return left.equals(right); - } - var l = left.symbol; - var r = right.symbol; - if (l) l = l.toUpperCase(); - if (r) r = r.toUpperCase(); - if (l != r) return false; - if (left.source != right.source) return false; - return true; - }; - - /** - * Convenience function to iterate through the charts masterData and add a data member. - * Used to load initial data for additional series and study symbols and should normally not be called directly. Unless used inside a study initialize function; use {@link CIQ.ChartEngine#addSeries} or {@link CIQ.ChartEngine#updateChartData} instead. - * Can be used with any array of data objects which contains at least the 'DT' (date in javascript format) and 'Close' ( close/last price ) elements of an [OHLC object]{@tutorial InputDataFormat}. - * @param {object} params Parameters object - * @param {CIQ.ChartEngine} [params.stx] A chart object - * @param {array} [params.data] The data to add (which should align or closely align with the chart data by date) - * @param {array} [params.fields] The fields from the incoming data objects to extract and add as the new members in each masterData object. One new member will be added per field using the exact same name as in the incoming data. Example: (for each field name in the array) masterData[mIterator][fieldN]=data[dIterator][fieldN]. Takes precedence over `createObject`, `label` and `fieldForLabel` parameters. Use fields=["*"] to copy all fields in the data object. - * @param {string} [params.label] The name of the new member to add into each masterData object. Example: masterData[mIterator][label]=data[dIterator]["Close"]. Required unless "fields" is specified. - * @param {string} [params.createObject] If truthy, then each complete incoming data object will be assigned to the new label member in each masterData object. If set to "aggregate", will consolidate the OHLV data with the new data. The data object is expected to be a properly formatted OHLC record, or at least contain a 'Close' price, otherwise this parameter will not be honored. Example: masterData[mIterator][label]=data[dIterator]. This behavior is mutually exclusive with `fields`.
If the data object contains a 'Value' field, this parameter will not be honored and instead the 'Value' field will be used as follows: masterData[mIterator][label] = data[dIterator]["Value"]; - * @param {string} [params.fieldForLabel="Close"] If set, this will be the field from each incoming data object that will be copied into the new label member in each masterData object. If not set, "Close" or "Value" is used, whichever exists; and if neither exists, it will attempt to copy over a field matching the `label` name. Example: masterData[mIterator][label]=data[dIterator][fieldForLabel]. This behavior is mutually exclusive with `fields` and `createObject`. - * @param {boolean} [params.fillGaps] If true then gaps in data will be filled by carrying forward the value of from the previous bar. - * @param {boolean} [params.noCleanupDates] If true then dates have been cleaned up already by calling {@link CIQ.ChartEngine#doCleanupDates}, so do not do so in here. - * @param {CIQ.ChartEngine.Chart} [params.chart] The chart to update - * @memberof CIQ - * @example - * //data element format if neither fields, fieldForLabel or createObject are used - * {DT:epoch,Date:strDate,Value:value} - * {DT:epoch,Date:strDate,Close:value } - * //data element format if fields is used - * {DT:epoch,Date:strDate,Field1:value,Field2:value,Field3:value,Field4:value} - * //data element format if createObject is used - * {DT:epoch,Date:strDate,AnyOtherData:otherData,MoreData:otherData,...} - * @since - * - 04-2015 - * - 15-07-01 Added `fieldForLabel` argument. - * - 3.0.0 All data sent in will be forced into the chart. Dates are no longer required to be exact matches (minutes, hours, seconds, milliseconds) in order to show up in comparisons. - * - 4.0.0 Arguments are now parameterized. Backward compatibility with old signature. - * - 4.0.0 Added ability to specify copying of all fields by setting `params.fields=["*"]`. - * - 5.2.0 Enhanced parameter `createObject` to take a string. - * - 5.2.0 Added parameter `noCleanupDates`. - */ - CIQ.addMemberToMasterdata = function (params) { - if (params.constructor === CIQ.ChartEngine) { - params = { - stx: arguments[0], - label: arguments[1], - data: arguments[2], - fields: arguments[3], - createObject: arguments[4], - fieldForLabel: arguments[5] - }; - } - var stx = params.stx; - var label = params.label; - var data = params.data; - var fields = params.fields; - var createObject = params.createObject; - var fieldForLabel = params.fieldForLabel; - - var chart = params.chart ? params.chart : stx.chart; - - if (!params.noCleanupDates) stx.doCleanupDates(data, stx.layout.interval); - - var series = []; - if (stx.getSeries) series = stx.getSeries({ symbol: label, chart: chart }); - - if (data && data.constructor == Object) data = [data]; // When developer mistakenly sends an object instead of an array of objects - if (!data || !data.length) return; - - var mIterator = 0, - cIterator = 0, - masterData = chart.masterData, - layout = stx.layout, - m, - c; - if (!masterData) { - masterData = []; - } - - var defaultPlotField = (chart && chart.defaultPlotField) || null; - var isLineType = - stx.mainSeriesRenderer && !stx.mainSeriesRenderer.highLowBars; - var chartType = layout.chartType; - if (!isLineType && chartType) { - var renderer = CIQ.Renderer.produce(chartType, {}); - if (renderer) isLineType = !renderer.highLowBars; - } - - function aggregate(m, c) { - if (!m || typeof m != "object") { - m = c; - return m; - } - var prior = { - Close: m.Close, - High: m.High, - Low: m.Low, - Open: m.Open, - Volume: m.Volume - }; - m = c; - for (var p in prior) { - if (m.Close === null) { - // Close is not set, nothing else is valid (it's a gap) - if (m[p] !== undefined) m[p] = null; - } else if (typeof m[p] !== "number") m[p] = prior[p]; - // new data invalid, use original data - else if (typeof prior[p] === "number") { - // aggregate the data - if (p == "Open") m.Open = prior.Open; - else if (p == "Low" && m.Low > prior.Low) m.Low = prior.Low; - else if (p == "High" && m.High < prior.High) m.High = prior.High; - else if (p == "Volume") m.Volume += prior.Volume; - } - } - return m; - } - - // inject data from c into m - function injectData(m, c) { - if (fields && fields.length) { - // Case 1, copy the [several] specified fields from new object to masterData object - if (fields[0] == "*") { - // copy all fields - CIQ.extend(m, c); - } else { - for (var i = 0; i < fields.length; i++) { - m[fields[i]] = c[fields[i]]; - } - } - } else if (createObject) { - // Case 2, the new object will become a child object of the masterData object - if (c.Value !== undefined) { - // If "Value" is in the new object use that - m[label] = c.Value; - return; - } else if (createObject == "aggregate") { - m[label] = aggregate(m[label], c); - } else { - m[label] = c; - } - // If we don't set this here, the study calculations will fail - var m_ = m[label]; - if (typeof m_.Close == "number") { - if (typeof m_.Open != "number") m_.Open = m_.Close; - var high = Math.max(m_.Open, m_.Close), - low = Math.min(m_.Open, m_.Close); - if (typeof m_.High != "number" || m_.High < high) m_.High = high; - if (typeof m_.Low != "number" || m_.Low > low) m_.Low = low; - } - if (m_.Volume && typeof m_.Volume !== "number") - m_.Volume = parseInt(m_.Volume, 10); - } else if (fieldForLabel) { - // Case 3, copy the data from one label (fieldForLabel) to another (label) - m[label] = c[fieldForLabel]; - } else if ( - isLineType && - defaultPlotField && - c[defaultPlotField] !== undefined - ) { - // If a default field on the chart has been provided, then use that if it's in the new object - m[label] = c[defaultPlotField]; - } else if (layout.adj && c.Adj_Close !== undefined) { - // If Adjusted close is in the new object, use that - m[label] = c.Adj_Close; - } else if (c.Close !== undefined) { - // If Close is in the new object use that - m[label] = c.Close; - } else if (c.Value !== undefined) { - // If "Value" is in the new object use that - m[label] = c.Value; - } else { - // Default to copying the same label from the old to the new object. - m[label] = c[label]; - } - } - - // Binary search for next relevant masterData record, with the following modifications: - // 1. Always check the very next record, since that is most likely - // 2. Before search, check last record - function fastSeek(date) { - function testIt() { - if (+masterData[mIterator].DT == +date) return 0; - if (masterData[mIterator].DT < date) return 1; - if (masterData[mIterator - 1].DT > date) return -1; - if (+masterData[mIterator - 1].DT == +date) mIterator--; // efficiency - return 0; - } - var begin = mIterator, - end = masterData.length - 1; - if (masterData[end].DT < date) { - mIterator = end + 1; - return; - } else if (+masterData[end].DT == +date) { - mIterator = end; - return; - } - mIterator++; - var attempts = 0; - while (++attempts < 100) { - switch (testIt()) { - case 0: - return; - case 1: - begin = mIterator; - break; - case -1: - end = mIterator; - break; - } - mIterator = Math.round((end + begin) / 2); - } - if (attempts >= 100) { - console.log( - "!!!Warning: addMemberToMasterdata() did not find insertion point." - ); - mIterator = masterData.length - 1; - } - } - - var dateFormatter = CIQ.yyyymmddhhmmssmmm; - /* The value for *displayDate* on quotes created below will be done by the call to ChartEngine#setMasterData */ - - // insert/update up to masterData last bar - while (data && mIterator < masterData.length && cIterator < data.length) { - c = data[cIterator]; - m = masterData[mIterator]; - if (!c.DT || typeof c.DT == "undefined") c.DT = CIQ.strToDateTime(c.Date); - else { - if (typeof c.DT == "number") c.DT = new Date(c.DT); //in case they sent in an epoch - if (!c.Date || c.Date.length != 17) c.Date = dateFormatter(c.DT); - } - if (cIterator === 0) { - for (var s1 = 0; s1 < series.length; s1++) { - if (!series[s1].endPoints.begin || series[s1].endPoints.begin > c.DT) - series[s1].endPoints.begin = c.DT; - } - } - if (+c.DT == +m.DT) { - injectData(m, c); - cIterator++; - mIterator++; - continue; - } - - if (c.DT < m.DT) { - masterData.splice(mIterator, 0, { DT: c.DT, Date: c.Date }); - continue; - } else fastSeek(c.DT); // this advances the mIterator - } - - // insert after master data last bar - if (mIterator >= masterData.length) { - while (data && cIterator < data.length) { - c = data[cIterator]; - if (!c.DT || typeof c.DT == "undefined") c.DT = CIQ.strToDateTime(c.Date); - else { - if (typeof c.DT == "number") c.DT = new Date(c.DT); //in case they sent in an epoch - if (!c.Date || c.Date.length != 17) c.Date = dateFormatter(c.DT); - } - m = { - DT: c.DT, - Date: c.Date - }; - injectData(m, c); - masterData.push(m); - cIterator++; - } - } - if (params.fillGaps && masterData.length) { - var cleanupGapsParams = { - noCleanupDates: true, - cleanupGaps: params.fillGaps - }; - if (fields) { - for (var j = 0; j < fields.length; j++) { - cleanupGapsParams.field = fields[j]; - stx.doCleanupGaps(masterData, chart, cleanupGapsParams); - } - } else { - cleanupGapsParams.field = label; - stx.doCleanupGaps(masterData, chart, cleanupGapsParams); - } - } - for (var s2 = 0; s2 < series.length; s2++) { - var endPoints = series[s2].endPoints; - if (!endPoints.end || !label || endPoints.end <= m[label].DT) { - endPoints.end = label ? m[label].DT : m.DT; - var sLabel = - label || - (series[s2].parameters && series[s2].parameters.field) || - chart.defaultPlotField; - series[s2].lastQuote = stx.getFirstLastDataRecord( - masterData, - sLabel, - true - ); - } - } - stx.setMasterData(masterData, chart, { noCleanupDates: true }); - }; - - }; - - - let __js_core_math_ = (_exports) => { - - - var CIQ = _exports.CIQ; - - /* Easing cubics from - http://gizma.com/easing/#expo1 - t = current time (t should move from zero to d) - b = starting value - c = change in value (b + c = ending value ) - d = duration - */ - - Math.easeInOutQuad = function (t, b, c, d) { - t /= d / 2; - if (t < 1) return (c / 2) * t * t + b; - t--; - return (-c / 2) * (t * (t - 2) - 1) + b; - }; - - Math.easeInOutCubic = function (t, b, c, d) { - t /= d / 2; - if (t < 1) return (c / 2) * t * t * t + b; - t -= 2; - return (c / 2) * (t * t * t + 2) + b; - }; - - Math.easeOutCubic = function (t, b, c, d) { - t /= d; - t--; - return c * (t * t * t + 1) + b; - }; - - /** - * Convenience function to compute xor operation. - * - * @param {object} a Operand. - * @param {object} b Operand. - * @return {boolean} true if only one of the operands is truthy. - * @memberof CIQ - * @since 7.3.0 - */ - CIQ.xor = function (a, b) { - var _a = !a, - _b = !b; // convert to boolean - return _a !== _b; - }; - - /** - * Convenience function to round a floating point number. - * - * This has better decimal accuracy than: - * - number.toFixed(decimals) - * - Math.round(number*decimals)/decimals - * @param {number} number The number to round - * @param {number} decimals The number of decimal places - * @return {number} Rounded number - * @memberof CIQ - * @since 7.0.0 - */ - CIQ.round = function (number, decimals) { - return Number(Math.round(number + "e" + decimals) + "e-" + decimals); - }; - - /** - * Convenience function to count number of decimal places in a number - * @param {number} n The number to check - * @return {number} Number of decimal places - * @memberof CIQ - * @since - * - 6.1.0 - * - 6.2.0 Now handles scientific notation. - */ - CIQ.countDecimals = function (n) { - if (typeof n !== "number" || isNaN(n)) return 0; - if (Math.floor(n) === Number(n)) return 0; - var strN = n.toString().split("e-"); - if (strN.length > 1) - return CIQ.countDecimals(Number(strN[0])) + Number(strN[1]); - if (strN[0].indexOf(".") > -1) return strN[0].split(".")[1].length; - return 0; - }; - - /** - * Convenience function to determine if a value is a valid number. - * @param {number} n The number to check - * @return {boolean} True if n is a real finite number. NaN, Infinity, null, undefined, etc are not considered to be a valid number. - * @memberof CIQ - * @since 5.2.2 - */ - CIQ.isValidNumber = function (n) { - return isFinite(n) && +n === n; - }; - - /** - * Returns the log base 10 of a value - * @param {number} y The value - * @return {number} log10 value - * @memberof CIQ - */ - CIQ.log10 = function (y) { - return Math.log(y) / Math.LN10; - }; - - /** - * Determines whether a line intersects a box. This is used within the charting engine to determine whether the cursor - * has intersected a drawing. - * Note this function is meant to receive bx1, by1, bx2, by2, x0, y0, x1 and y1 as pixel values and not as ticks/axis values. - * @param {number} bx1 - * @param {number} by1 - * @param {number} bx2 - * @param {number} by2 - * @param {number} x0 - * @param {number} y0 - * @param {number} x1 - * @param {number} y1 - * @param {string} vtype - Either "segment", "ray" or "line". Anything else will default to segment. - * @return {boolean} Returns true if the line intersects the box - * @memberof CIQ - * @since - * - 4.0.0 Added `isLog` parameter. - * - 6.0.0 Removed `isLog` parameter. - */ - CIQ.boxIntersects = function (bx1, by1, bx2, by2, x0, y0, x1, y1, vtype) { - if (arguments[9] !== undefined) { - console.warn( - "CIQ.boxIntersects() no longer supports isLog argument, please be sure arguments are passed in as pixels." - ); - } - var minX = Math.min(bx1, bx2); - var maxX = Math.max(bx1, bx2); - var minY = Math.min(by1, by2); - var maxY = Math.max(by1, by2); - var isRay = vtype == "ray"; - - // Check for invalid values - if (isNaN(x0) || isNaN(x1) || isNaN(y0) || isNaN(y1)) return false; - - // First see if segment/ray lies outside the box - if (vtype != "line") { - if (x0 < minX && x1 < minX && (!isRay || x0 > x1)) return false; - if (x0 > maxX && x1 > maxX && (!isRay || x0 < x1)) return false; - if (y0 < minY && y1 < minY && (!isRay || y0 > y1)) return false; - if (y0 > maxY && y1 > maxY && (!isRay || y0 < y1)) return false; - } - // Now see if all box corners land on the same side of the line - function cornerCheck(x, y) { - return (y - y0) * (x1 - x0) - (x - x0) * (y1 - y0); - } - var map = { - a: cornerCheck(bx1, by1), - b: cornerCheck(bx1, by2), - c: cornerCheck(bx2, by1), - d: cornerCheck(bx2, by2) - }; - if (map.a > 0 && map.b > 0 && map.c > 0 && map.d > 0) return false; - if (map.a < 0 && map.b < 0 && map.c < 0 && map.d < 0) return false; - - return true; - }; - - /** - * Determines whether two lines intersect - * @param {number} x1 - * @param {number} x2 - * @param {number} y1 - * @param {number} y2 - * @param {number} x3 - * @param {number} x4 - * @param {number} y3 - * @param {number} y4 - * @param {string} type - Either "segment", "ray" or "line" - * @return {boolean} Returns true if the two lines intersect - * @memberof CIQ - */ - CIQ.linesIntersect = function (x1, x2, y1, y2, x3, x4, y3, y4, type) { - var denom = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1); - var numera = (x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3); - var numerb = (x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3); - //var EPS = .000001; - - if (denom === 0) { - if (numera === 0 && numerb === 0) return true; // coincident - return false; // parallel - } - - var mua = numera / denom; - var mub = numerb / denom; - if (type == "segment") { - if (mua >= 0 && mua <= 1 && mub >= 0 && mub <= 1) return true; - } else if (type == "line" || type == "horizontal" || type == "vertical") { - if (mua >= 0 && mua <= 1) return true; - } else if (type == "ray") { - if (mua >= 0 && mua <= 1 && mub >= 0) return true; - } - return false; - }; - - /** - * Determines the Y value at which point X intersects a line (vector) - * @param {object} vector - Object of type {x0,x1,y0,y1} - * @param {number} x - X value - * @return {number} - Y intersection point - * @memberof CIQ - */ - CIQ.yIntersection = function (vector, x) { - var x1 = vector.x0, - x2 = vector.x1, - x3 = x, - x4 = x; - var y1 = vector.y0, - y2 = vector.y1, - y3 = 0, - y4 = 10000; - var denom = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1); - var numera = (x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3); - //var numerb = (x2-x1) * (y1-y3) - (y2-y1) * (x1-x3); - //var EPS = .000001; - - var mua = numera / denom; - if (denom === 0) { - if (numera === 0) mua = 1; - else return null; - } - - var y = y1 + mua * (y2 - y1); - return y; - }; - - /** - * Determines the X value at which point Y intersects a line (vector) - * @param {object} vector - Object of type {x0,x1,y0,y1} - * @param {number} y - Y value - * @return {number} - X intersection point - * @memberof CIQ - */ - CIQ.xIntersection = function (vector, y) { - var x1 = vector.x0, - x2 = vector.x1, - x3 = 0, - x4 = 10000; - var y1 = vector.y0, - y2 = vector.y1, - y3 = y, - y4 = y; - var denom = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1); - var numera = (x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3); - //var numerb = (x2-x1) * (y1-y3) - (y2-y1) * (x1-x3); - //var EPS = .000001; - - var mua = numera / denom; - if (denom === 0) { - if (numera === 0) mua = 1; - else return null; - } - - var x = x1 + mua * (x2 - x1); - return x; - }; - - /** - * Get the X intersection point between two lines - * @param {number} ax1 Initial x coordinate start point of the first box. - * @param {number} ax2 Final x coordinate end point of the first box. - * @param {number} ay1 Initial y coordinate start point of the first box. - * @param {number} ay2 Final y coordinate end point of the fist box. - * @param {number} bx1 Initial x coordinate start point of the second box. - * @param {number} bx2 Final x coordinate end point of the second box. - * @param {number} by1 Initial y coordinate start point of the second box. - * @param {number} by2 Final y coordinate end point of the second box. - * @memberof CIQ - */ - CIQ.intersectLineLineX = function (ax1, ax2, ay1, ay2, bx1, bx2, by1, by2) { - var ua_t = (bx2 - bx1) * (ay1 - by1) - (by2 - by1) * (ax1 - bx1); - var u_b = (by2 - by1) * (ax2 - ax1) - (bx2 - bx1) * (ay2 - ay1); - - var ua = ua_t / u_b; - - return ax1 + ua * (ax2 - ax1); - }; - - /** - * Get the Y intersection point between two lines - * @param {number} ax1 Initial x coordinate start point of the first box. - * @param {number} ax2 Final x coordinate end point of the first box. - * @param {number} ay1 Initial y coordinate start point of the first box. - * @param {number} ay2 Final y coordinate end point of the fist box. - * @param {number} bx1 Initial x coordinate start point of the second box. - * @param {number} bx2 Final x coordinate end point of the second box. - * @param {number} by1 Initial y coordinate start point of the second box. - * @param {number} by2 Final y coordinate end point of the second box. - * @memberof CIQ - */ - CIQ.intersectLineLineY = function (ax1, ax2, ay1, ay2, bx1, bx2, by1, by2) { - var ua_t = (bx2 - bx1) * (ay1 - by1) - (by2 - by1) * (ax1 - bx1); - var u_b = (by2 - by1) * (ax2 - ax1) - (bx2 - bx1) * (ay2 - ay1); - - var ua = ua_t / u_b; - - return ay1 + ua * (ay2 - ay1); - }; - - }; - - - let __js_core_object_ = (_exports) => { - - - var CIQ = _exports.CIQ; - - /** - * Deletes the map entries for which the right hand side is the object in question. - * @param {object} map JavaScript map object - * @param {object} object The actual object to be deleted from the map - * @return {boolean} Returns true if any object actually deleted - * @memberof CIQ - */ - CIQ.deleteRHS = function (map, object) { - var deletedOne = false; - for (var i in map) { - if (map[i] == object) { - delete map[i]; - deletedOne = true; - } - } - return deletedOne; - }; - - /** - * Deletes (removes) nulls or undefined fields (names) from an object. This is useful when marshalling (saving) an object where you don't wish - * null or undefined values to show up in the marshalled object (such as when converting to JSON) - * @param {object} obj The object to scrub - * @param {boolean} [removeNulls] Whether or not to remove null values - * @memberof CIQ - */ - CIQ.scrub = function (obj, removeNulls) { - for (var i in obj) { - if (typeof obj[i] == "undefined") delete obj[i]; - if (removeNulls && obj[i] === null) delete obj[i]; - } - }; - - /** - * This method changes the target object's contents to match the contents of the source object. This is functionally equivalent - * to `target=source` except that it preserves the existence of the target object. This is vitally important if there are data bindings - * to the target object otherwise those data bindings would remain attached to a phantom object! The logic here is orchestrated so that you - * will receive update, add and delete notifications for each field that changes. - * @param {object} target The target object - * @param {object} source The source object - * @memberof CIQ - * @since 2015-11-1 - */ - CIQ.dataBindSafeAssignment = function (target, source) { - /*for(var prop in source) { - target[prop]=source[prop]; - }*/ - CIQ.extend(target, source); - for (var prop in target) { - if (typeof source[prop] == "undefined") { - target[prop] = undefined; - } - } - }; - - /** - * Clones an object. This function creates a deep (recursive) clone of an object. The object can be a primitive or an object or an array. - * Note that cloning objects that reference DOM nodes can result in stack overflows. Use with caution. - * @param {object} from The source object - * @param {object} [to] Optional existing object of same type. Can improve performance when objects are reusable. - * @return {object} A deep clone of the "from" object - * @memberof CIQ - */ - CIQ.clone = function (from, to) { - if (from === null || typeof from != "object") return from; - var c = from.constructor; - if (c == Date || c == RegExp || c == String || c == Number || c == Boolean) - return new c(from.valueOf()); - if (c == Function) - return function () { - return from.apply(this, arguments); - }; - - if (!to) { - try { - to = new c(); - } catch (e0) { - to = Object.create(Object.getPrototypeOf(from)); - } - } - - for (var n in from) { - to[n] = to[n] !== from[n] ? CIQ.clone(from[n], null) : to[n]; - } - - return to; - }; - - /** - * Non recursive clone. This will only clone the top layer and is safe to use when objects contain DOM nodes. - * @param {object} from - Object to be cloned - * @return {object} A shallow clone of the "from" object - * @memberof CIQ - */ - CIQ.shallowClone = function (from) { - if (!from) return from; - var to; - if (from.constructor == Array) { - to = new Array(from.length); - for (var i = 0; i < from.length; i++) { - to[i] = from[i]; - } - return to; - } - to = {}; - for (var field in from) { - to[field] = from[field]; - } - return to; - }; - - /** - * Accepts a default parameters object and sets the field values for the target *only if they are missing*. - * Note that a value of null will not be overridden. Only undefined (missing) values will be overridden. - * @param {object} target The object needing potential default values - * @param {object} defaults Default values - * @return {object} Returns the modified target object - * @since 3.0.0 - * @example - * var target={"color":"red"}; - * var defaults={"color":"blue", "shape":"triangle"}; - * CIQ.ensureDefaults(target, defaults); - * >> target==={"color":"red", "shape":"triangle"}; - * @memberof CIQ - */ - CIQ.ensureDefaults = function (target, defaults) { - for (var field in defaults) { - if (typeof target[field] == "undefined") target[field] = defaults[field]; - } - return target; - }; - - /** - * Copies the contents of one object into another. - * This is useful if there are pointers to the target object and you want to "replace" it with another object while preserving the pointer. - * @param {object} target The object being pointed to - * @param {object} source The object containing the values you want pointed at - * @return {object} Returns the modified target object - * @since 7.1.0 - * @example - * var target={"color":"red", "pattern":"solid"}; - * var source={"color":"blue", "shape":"triangle"}; - * CIQ.transferObject(target, source); - * >> target==={"color":"blue", "shape":"triangle"}; - * >> target!==source; - * @memberof CIQ - */ - CIQ.transferObject = function (target, source) { - var field; - for (field in target) { - if (target.hasOwnProperty(field)) delete target[field]; - } - for (field in source) { - if (source.hasOwnProperty(field)) target[field] = source[field]; - } - return target; - }; - - /** - * Returns true if the objects are an exact match - * @param {object} a First object - * @param {object} b Second object - * @param {object} [exclude] Exclude these fields - * @return {boolean} True if they are an exact match - * @memberof CIQ - */ - CIQ.equals = function (a, b, exclude) { - if (!a && b) return false; - if (a && !b) return false; - if (typeof a !== typeof b) return false; - for (var field in a) { - if (exclude && exclude[field]) continue; - if (typeof a[field] === "object") { - var result = CIQ.equals(a[field], b[field]); - if (!result) return false; - continue; - } - if (b[field] != a[field]) return false; - } - return true; - }; - - /** - * Returns true if an object has no members - * @param {object} o A JavaScript object - * @return {boolean} True if there are no members in the object - * @memberof CIQ - */ - CIQ.isEmpty = function (o) { - for (var p in o) { - if (o.hasOwnProperty(p)) { - return false; - } - } - return true; - }; - - /** - * Convenience function returns the first property in an object. Note that while this works in all known browsers - * the EMCA spec does not guarantee that the order of members in an object remain static. This method should therefore - * be avoided. When ordering is important use an Array! - * @param {object} o A JavaSCript object - * @return {object} The first element in the object or null if it is empty - * @memberof CIQ - */ - CIQ.first = function (o) { - for (var p in o) { - return p; - } - return null; - }; - - /** - * Convenience function for returning the last property in an object. Note that while this works in all known browsers - * the EMCA spec does not guarantee that the order of members in an object remain static. This method should therefore - * be avoiding. When ordering is important use an Array! - * @param {object} o A JavaScript object - * @return {object} The final member of the object or null if the object is empty - * @memberof CIQ - */ - CIQ.last = function (o) { - var l = null; - for (var p in o) { - l = p; - } - return l; - }; - - /** - * Returns the number of members in an object - * @param {object} o A valid JavaScript object - * @return {number} The number of members in the object - * @memberof CIQ - */ - CIQ.objLength = function (o) { - if (!o) return 0; - var i = 0; - for (var p in o) { - i++; - } - return i; - }; - - /** - * Given a dot notation string, we want to navigate to the location - * in a base object, creating the path along the way - * @param {object} base Base object. - * @param {string} extension String in dot notation - * @return {object} A tuple containing obj and member - * @memberof CIQ - * @since 2015-11-1 - * @example - * var tuple=CIQ.deriveFromObjectChain(stx.layout, "pandf.box"); - * tuple.obj===stx.layout.pandf - * tuble.member==="box" - * tuple.obj[tuple.member]=3; // stx.layout.pandf.box=3 - */ - CIQ.deriveFromObjectChain = function (base, extension) { - // Which way is faster? - //if(!(new RegExp(extension)).test(".")){ - if (extension.indexOf(".") == -1) { - return { obj: base, member: extension }; - } - var objectString = extension.split("."); - for (var i = 0; i < objectString.length - 1; i++) { - var objStr = objectString[i]; - if (!base[objStr] && base[objStr] !== 0) base[objStr] = {}; - base = base[objStr]; - } - return { obj: base, member: objectString[i] }; - }; - - /** - * Create arrow notation strings (field-->property) of a given field and an array of properties - * Used to create a set of object properties in string format for later use by CIQ.existsInObjectChain - * Its main use is to pass field names into {@link CIQ.ChartEngine#determineMinMax}. - * @param {string} field Base object. - * @param {array} properties Array of strings representing properties - * @return {array} Array of object properties expressed in arrow notation (field-->property) - * @memberof CIQ - * @since 5.1.0 - * @example - * var fields=CIQ.createObjectChainNames("ABC.D",["High","Low"]); - * fields===["ABC.D-->High","ABC.D-->Low"] - */ - CIQ.createObjectChainNames = function (field, properties) { - var ret = []; - for (var p = 0; p < properties.length; p++) { - ret.push(field + "-->" + properties[p]); - } - return ret; - }; - - /** - * Given an arrow notation string (a-->b-->c), we want to navigate to the location - * in a base object, to see if it exists - * @param {object} base Base object. - * @param {string} extension String in arrow notation - * @return {object} A tuple containing obj and member; a null will be returned if path does not exist - * @memberof CIQ - * @since 5.1.0 - * @example - * var tuple=CIQ.existsInObjectChain(stx.dataSegment[0], "ABC.D-->High"); - * tuple.obj===stx.dataSegment[0]["ABC.D"] - * tuple.member==="High" - * tuple.obj[tuple.member]=28.7; // stx.dataSegment[0]["ABC.D"].High=28.7 - */ - CIQ.existsInObjectChain = function (base, extension) { - // Which way is faster? - //if(!(new RegExp(extension)).test(".")){ - if (extension.indexOf("-->") == -1) { - if (!base[extension] && base[extension] !== 0) return null; - return { obj: base, member: extension }; - } - var objectString = extension.split("-->"); - var objStr; - for (var i = 0; i < objectString.length - 1; i++) { - objStr = objectString[i]; - if (!base[objStr] && base[objStr] !== 0) return null; - base = base[objStr]; - } - objStr = objectString[i]; - if (!base[objStr] && base[objStr] !== 0) return null; - return { obj: base, member: objStr }; - }; - - /** - * Replacement for isPrototypeOf and instanceof so that both types of inheritance can be checked - * @param {object} child The object instance to check - * @param {object} parent Prototype - * @return {boolean} True if the object is derived from the parent - * @memberof CIQ - * @since 07/01/2015 - */ - CIQ.derivedFrom = function (child, parent) { - if (parent.isPrototypeOf(child)) return true; - if (child instanceof parent) return true; - return false; - }; - - /** - * This method will iterate through the object and replace all of the fields - * using the mapping object. This would generally be used to compress an object - * for serialization. so that for instance "lineWidth" becomes "lw". This method - * is called recursively. - * @param {object} obj Object to compress - * @param {object} mapping Object containing name value pairs. Each name will be replaced with its corresponding value in the object. - * @return {object} The newly compressed object - * @memberof CIQ - */ - CIQ.replaceFields = function (obj, mapping) { - if (!obj) return obj; - var newObj = {}; - for (var field in obj) { - var value = obj[field]; - var replaced = mapping[field]; - if (!replaced) replaced = field; - if (value && typeof value == "object") { - if (value.constructor == Array) { - var arr = (newObj[replaced] = new Array(value.length)); - for (var i = 0; i < arr.length; i++) { - var val = value[i]; - if (typeof val == "object") { - arr[i] = CIQ.replaceFields(val, mapping); - } else { - arr[i] = val; - } - } - } else { - newObj[replaced] = CIQ.replaceFields(value, mapping); - } - } else { - newObj[replaced] = value; - } - } - return newObj; - }; - - /** - * Returns an object copy with any null values removed - * @param {object} obj Object to remove nulls - * @return {object} Object with nulls removed - * @memberof CIQ - */ - CIQ.removeNullValues = function (obj) { - var n = CIQ.clone(obj); - for (var f in n) { - if (!n[f]) delete n[f]; - } - return n; - }; - - /** - * This method reverses the fields and values in an object - * @param {object} obj Object to reverse - * @return {object} The reversed object - * @memberof CIQ - * @example reverseObject({ one: "a", two: "b" }) // returns { a: "one", b: "two" } - */ - CIQ.reverseObject = function (obj) { - var newObj = {}; - for (var field in obj) { - newObj[obj[field]] = field; - } - return newObj; - }; - - /** - * Accesses a property, method, or array in a namespace. - * - * Approximates optional chaining, checking whether the object at the end of `namespace` + - * `path` exists before returning it. - * - * @param {object} namespace Namespace to access. - * @param {string} path String in dot notation representing extension of the namespace to a - * desired property, method, or array. - * @param {*} [defaultValue] The value returned if the requested expression does not exist. - * If the requested expression is a function, set `defaultValue` to a function (usually - * `function(){}`) that can be run with any required arguments. If the requested - * expression is an array, set `defaultValue` to a default array, usually `[]`. - * @return {*} The expression sought by combining the namespace and path. If the expression - * does not exist, returns `defaultValue` (if provided), otherwise returns `undefined`. - * - * @memberof CIQ - * @since 8.0.0 - * - * @example - * // Accesses CIQ.Studies.studyLibrary.rsi if safe to do so (if exists). - * CIQ.getFromNS(CIQ.Studies, "studyLibrary.rsi"); - * // or - * CIQ.getFromNS(CIQ, "Studies.studyLibrary.rsi"); - * - * @example - * // Accesses Math.Matrix.ScalarOperations.dotProduct(mA, mB) if safe to do so (if exists). - * // Returns 12 if Math.Matrix.ScalarOperations.dotProduct does not exist. - * CIQ.getFromNS(Math, "Matrix.ScalarOperations.dotProduct", (a,b)=>a*b)(3, 4); - */ - CIQ.getFromNS = (namespace, path, defaultValue) => { - if (namespace) { - var base = namespace, - objectString = path.split("."); - for (var i = 0; i < objectString.length; i++) { - var objStr = objectString[i]; - if (typeof base[objStr] === "undefined") break; - base = base[objStr]; - } - if (i === objectString.length) return base; - } - return undefined || defaultValue; - }; - - /** - * Curried {@link CIQ.getFromNS} expecting a function to be returned if `obj` + `path` is not - * found. - * - * @param {object} obj Namespace to access. - * @param {string} path String in dot notation representing extension of the namespace to - * the desired function. - * @param {*} [defaultValue] The value returned if the requested function does not exist. - * @return {function} The function sought by combining the namespace and path. If the - * function does not exist, returns `function(){return defaultValue;}`. - * - * @memberof CIQ - * @since 8.0.0 - * - * @example - * // Invokes Math.Matrix.ScalarOperations.dotProduct with arguments (mA, mB) if safe to do so (if exists). - * // Assigns NaN to the result if Math.Matrix.ScalarOperations.dotProduct does not exist. - * let result=getFnFromNS(Math, "Matrix.ScalarOperations.dotProduct", NaN)(mA, mB); - */ - CIQ.getFnFromNS = (obj, path, defaultValue) => { - return CIQ.getFromNS(obj, path, function () { - return defaultValue; - }); // use `function` to allow `new (CIQ.getFromNS())(...) syntax - }; - - /** - * Curried {@link CIQ.getFromNS} expecting the namespace to be {@link CIQ}. - * - * @param {string} path String in dot notation representing extension of the {@link CIQ} - * namespace to a desired property, method, or array. - * @param {*} [defaultValue] The value returned if the requested expression does not exist. - * If the requested expression is a function, set `defaultValue` to a function (usually - * `function(){}`) that can be run with any required arguments. If the requested - * expression is an array, set `defaultValue` to a default array, usually `[]`. - * @return {*} The expression sought by combining the {@link CIQ} namespace and the path. If - * the expression does not exist, returns `defaultValue` (if provided), otherwise returns - * undefined. - * - * @memberof CIQ - * @since 8.0.0 - * - * @example - * // Accesses CIQ.Studies.studyLibrary.rsi if safe to do so (if exists). - * CIQ.get("Studies.studyLibrary.rsi"); - * // Returns null if CIQ.Studies.studyLibrary.rsi does not exist. - * CIQ.get("Studies.studyLibrary.rsi", null); - */ - CIQ.get = (path, defaultValue) => { - return CIQ.getFromNS(CIQ, path, defaultValue); - }; - - /** - * Curried {@link CIQ.getFromNS} expecting the namespace to be {@link CIQ} and a function to be - * returned. - * - * @param {string} path String in dot notation representing extension of the {@link CIQ} - * namespace to the desired function. - * @param {*} [defaultValue] The value returned if the requested function does not exist. - * @return {function} The function sought by combining the {@link CIQ} namespace and the path. - * If the function does not exist, returns `function(){return defaultValue;}`. - * - * @memberof CIQ - * @since 8.0.0 - * - * @example - * // Returns the function if safe to do so (if exists). - * // Assigns "error" to the result if CIQ.Studies.removeStudy does not exist. - * getFn("Studies.removeStudy", "error"); - */ - CIQ.getFn = (path, defaultValue) => { - return CIQ.getFromNS(CIQ, path, function () { - return defaultValue; - }); // use `function` to allow `new (CIQ.getFromNS())(...) syntax - }; - - }; - - - let __js_core_plotter_ = (_exports) => { - - - var CIQ = _exports.CIQ; - - /** - * The Plotter is a device for managing complex drawing operations on the canvas. The HTML 5 canvas performs better when drawing - * operations of the same color are batched (reducing the number of calls to the GPU). The plotter allows a developer to store those - * operations in a normal control flow, and then have the Plotter deliver the primitives to the canvas. The plotter can also be used - * as a caching mechanism for performing the same operations repeatedly. The y-axis of the chart uses this mechanism to boost performance. - * @constructor - * @name CIQ.Plotter - */ - CIQ.Plotter = function () { - this.seriesArray = []; - this.seriesMap = {}; - }; - - CIQ.extend( - CIQ.Plotter.prototype, - { - /** - * Define a series to plot. A series is a specific color and referenced by name - * @param {string} name Name of series - * @param {boolean} strokeOrFill If true then a stroke operation, otherwise a fill operation - * @param {string} color A valid canvas color - * @param {number} [opacity=1] A valid opacity from 0-1 - * @param {number} [width=1] A valid lineWidth from 1 - * @param {string} [pattern=solid] A valid pattern (solid, dotted, dashed) - * @memberof CIQ.Plotter# - * @since 4.0.0 added parameter pattern - */ - Series: function (name, strokeOrFill, color, opacity, width, pattern) { - this.name = name; - this.strokeOrFill = strokeOrFill; - this.color = color; - this.moves = []; - this.text = []; - if (!opacity || opacity > 1 || opacity < 0) opacity = 1; - this.opacity = opacity; - if (!width || width > 25 || width < 1) width = 1; - this.width = width; - this.pattern = CIQ.borderPatternToArray(width, pattern); - }, - /** - * Create a series. This supports either a text color or CIQ.ChartEngine.Style object - * @see CIQ.Plotter.Series - * @memberof CIQ.Plotter# - * @param {string} name Name of series - * @param {boolean} strokeOrFill If true then a stroke operation, otherwise a fill operation - * @param {object|string} colorOrStyle Color or object containing color, opacity, width, borderTopStyle (solid, dotted, dashed) - * @param {number} [opacity] A valid opacity from 0-1 - * @param {number} [width=1] A valid lineWidth from 1 - */ - newSeries: function (name, strokeOrFill, colorOrStyle, opacity, width) { - var series; - if (colorOrStyle.constructor == String) - series = new this.Series( - name, - strokeOrFill, - colorOrStyle, - opacity, - width - ); - else - series = new this.Series( - name, - strokeOrFill, - colorOrStyle.color, - colorOrStyle.opacity, - width >= 0 ? width : CIQ.stripPX(colorOrStyle.width), - colorOrStyle.borderTopStyle - ); - this.seriesArray.push(series); - this.seriesMap[name] = series; - }, - /** - * Clear out any moves or text stored in the plotter for series "name" - * @memberof CIQ.Plotter# - * @param {string} name Name of series to reset. If omitted, will reset all series in plotter. - * @since 3.0.0 - */ - reset: function (name) { - for (var s in this.seriesMap) { - if (name && name != s) continue; - var series = this.seriesMap[s]; - if (series) { - series.moves = []; - series.text = []; - } - } - }, - /** - * @param {string} name Name of series - * @param {number} x - * @param {number} y - * @memberof CIQ.Plotter# - */ - moveTo: function (name, x, y) { - var series = this.seriesMap[name]; - series.moves.push({ action: "moveTo", x: x, y: y }); - }, - /** - * @param {string} name Name of series - * @param {number} x - * @param {number} y - * @memberof CIQ.Plotter# - */ - lineTo: function (name, x, y) { - var series = this.seriesMap[name], - pattern = series.pattern; - series.moves.push({ action: "lineTo", x: x, y: y, pattern: pattern }); - }, - /** - * @param {string} name Name of series - * @param {number} x - * @param {number} y - * @param {string} pattern A valid pattern (solid, dotted, dashed) - * @memberof CIQ.Plotter# - */ - dashedLineTo: function (name, x, y, pattern) { - var series = this.seriesMap[name]; - series.moves.push({ action: "lineTo", x: x, y: y, pattern: pattern }); - }, - /** - * @param {string} name Name of series - * @param {number} cx0 Control point x-coord - * @param {number} cy0 Control point y-coord - * @param {number} x - * @param {number} y - * @memberof CIQ.Plotter# - */ - quadraticCurveTo: function (name, cx0, cy0, x, y) { - var series = this.seriesMap[name], - pattern = series.pattern; - series.moves.push({ - action: "quadraticCurveTo", - x0: cx0, - y0: cy0, - x: x, - y: y, - pattern: pattern - }); - }, - /** - * @param {string} name Name of series - * @param {number} cx0 First control point x-coord - * @param {number} cy0 First control point y-coord - * @param {number} cx1 Second control point x-coord - * @param {number} cy1 Second control point x-coord - * @param {number} x - * @param {number} y - * @memberof CIQ.Plotter# - * @since 4.0.0 - */ - bezierCurveTo: function (name, cx0, cy0, cx1, cy1, x, y) { - var series = this.seriesMap[name], - pattern = series.pattern; - series.moves.push({ - action: "bezierCurveTo", - x0: cx0, - y0: cy0, - x1: cx1, - y1: cy1, - x: x, - y: y, - pattern: pattern - }); - }, - /** - * Add text to be rendered with the drawing. Primarily used when the Plotter is used for caching since there is no - * performance benefit from batching text operations to the GPU. If specifying a bounding box, textBaseline="middle" is assumed - * @param {string} name Name of series - * @param {string} text The raw text to render - * @param {number} x X position on canvas for text - * @param {number} y Y position on canvas for text - * @param {string} [backgroundColor] Color to use on the box underneath the text - * @param {number} [width] Width of bounding box - * @param {number} [height] Height of bounding box - * @memberof CIQ.Plotter# - */ - addText: function (name, text, x, y, backgroundColor, width, height) { - var series = this.seriesMap[name]; - series.text.push({ text: text, x: x, y: y, bg: backgroundColor }); - }, - /** - * Renders the text objects. This is done after drawing primitives for each series. - * @private - * @memberof CIQ.Plotter# - */ - drawText: function (context, series) { - for (var i = 0; i < series.text.length; i++) { - var textObj = series.text[i]; - if (textObj.bg) { - var w = textObj.width - ? textObj.width - : context.measureText(textObj.text).width; - var h = textObj.height ? textObj.height : 12; - var prev = context.fillStyle; - context.fillStyle = textObj.bg; - if (context.textAlign == "right") { - context.fillRect(textObj.x, textObj.y - h / 2, -w, -h); - } else { - context.fillRect(textObj.x, textObj.y - h / 2, w, h); - } - context.fillStyle = prev; - } - context.fillText(textObj.text, textObj.x, textObj.y); - } - }, - /** - * Render the plotter. All of the stored operations are sent to the canvas. This operation stores and restores - * global canvas parameters such as fillStyle, strokeStyle and globalAlpha. - * @param {object} context A valid HTML canvas context - * @param {string} [name] Optionally render only a specific series. If null or not provided then all series will be rendered. - * @memberof CIQ.Plotter# - */ - draw: function (context, name) { - var prevWidth = context.lineWidth; - var prevFillStyle = context.fillStyle; - var prevStrokeStyle = context.strokeStyle; - var prevGlobalAlpha = context.globalAlpha; - for (var i = 0; i < this.seriesArray.length; i++) { - var series = this.seriesArray[i]; - if (name && series.name != name) continue; - context.beginPath(); - context.lineWidth = series.width; - context.globalAlpha = series.opacity; - context.fillStyle = series.color; - context.strokeStyle = series.color; - context.save(); - for (var j = 0; j < series.moves.length; j++) { - var move = series.moves[j]; - if (move.pattern) { - context.setLineDash(move.pattern); - context.lineDashOffset = 0; - } else context.setLineDash([]); - if (move.action == "quadraticCurveTo") { - context[move.action](move.x0, move.y0, move.x, move.y); - } else if (move.action == "bezierCurveTo") { - context[move.action]( - move.x0, - move.y0, - move.x1, - move.y1, - move.x, - move.y - ); - } else { - context[move.action](move.x, move.y); - } - } - if (series.strokeOrFill == "fill") { - context.fill(); - } else { - context.stroke(); - } - context.closePath(); - context.restore(); - this.drawText(context, series); - context.lineWidth = 1; - } - context.lineWidth = prevWidth; - context.fillStyle = prevFillStyle; - context.strokeStyle = prevStrokeStyle; - context.globalAlpha = prevGlobalAlpha; - } - }, - true - ); - - }; - - - let __js_core_renderer_ = (_exports) => { - - - var CIQ = _exports.CIQ; - - /** - * Base class for Renderers. - * - * A renderer is used to draw a complex visualization based on one or more "series" of data. - * Renderers only need to be attached to a chart once. You can change symbols and continue using the same renderer. - * The series associated with a renderer may change at any time, but the linked renderer itself remains the vehicle for display them. - * - * Series are associated with renderers by calling attachSeries(). - * More typically though, this is done automatically when {@link CIQ.ChartEngine#addSeries} is used. - * The parameters for addSeries() are passed both to the renderer's constructor and also to attachSeries(). - * - * To manually create a renderer use {@link CIQ.ChartEngine#setSeriesRenderer} - * - * @name CIQ.Renderer - * @constructor - */ - CIQ.Renderer = function () {}; - - /** - * Factory for renderer. - * - * Will request a renderer from each renderer subclass until it is given one. - * @param {string} chartType Chart type name (usually from layout.chartType) - * @param {object} [params] Parameters to pass to the renderer constructor - * @memberof CIQ.Renderer - * @since 5.1.0 - * @private - */ - CIQ.Renderer.produce = function (chartType, params) { - var renderer = null; - if (chartType) { - for (var r in CIQ.Renderer) { - var rendererType = CIQ.Renderer[r]; - // Note: chartType has often been a combination of attributes connected with an underscore, - // e.g. colored_bar, baseline_mountain. So we split this legacy name to get the attributes. - if (rendererType.requestNew) - renderer = rendererType.requestNew(chartType.split("_"), params); - if (renderer) return renderer; - } - } - params.type = "line"; - return new CIQ.Renderer.Lines({ params: params }); - }; - - CIQ.Renderer.colorFunctions = {}; - /** - * Registers a colorFunction for use with a renderer. - * - * It is necessary to register a color function if you want the function to be tied back to an imported renderer. - * @param {string} name The name of the registered function - * @param {function} funct The function to register - * @memberof CIQ.Renderer - */ - CIQ.Renderer.registerColorFunction = function (name, funct) { - CIQ.Renderer.colorFunctions[name] = funct; - }; - - /** - * Unregisters a colorFunction for use with a renderer. - * - * @param {string} name The name of the registered function - * @memberof CIQ.Renderer - */ - CIQ.Renderer.unregisterColorFunction = function (name) { - delete CIQ.Renderer.colorFunctions[name]; - }; - - /** - * If your renderer manages a yAxis then the necessary adjustments to its properties should be made here. - * - * @memberof CIQ.Renderer - * @since 5.2.0 - */ - CIQ.Renderer.prototype.adjustYAxis = function () {}; - - /** - * Perform drawing operations here. - * @memberof CIQ.Renderer - */ - CIQ.Renderer.prototype.draw = function () {}; - - /** - * Draws one series from the renderer. - * - * Called by {@link CIQ.ChartEngine.AdvancedInjectable#drawSeries} - * @param {CIQ.ChartEngine.Chart} chart The chart object to draw the renderers upon - * @param {object} [parameters] Parameters used to draw the series, depends on the renderer type - * @param {string} [parameters.panel] Name of panel to draw the series upon - * @memberof CIQ.Renderer - * @since 5.1.0 - */ - CIQ.Renderer.prototype.drawIndividualSeries = function (chart, parameters) {}; - - /** - * Default constructor for a renderer. Override this if desired. - * @param {object} config Configuration for the renderer. - * @param {function} [config.callback] Callback function to perform activity post-drawing, for example, creating a legend. It will be called with an object containing the list of instruments and corresponding colors. - * @param {string} [config.id] Handle to access the rendering in the future. If not provided, one will be generated. - * @param {object} [config.params] Parameters to control the renderer itself - * @param {string} [config.params.name="Data"] Name of the renderer. This is used when displaying error message on screen - * @param {string} [config.params.panel="chart"] The name of the panel to put the rendering on. - * @param {boolean} [config.params.overChart=true] If set to false, will draw the rendering behind the main chart rather than over it. By default rendering will be as overlay on the main chart. - * @param {boolean} [config.params.yAxis] Y-axis object to use for the series. - * @param {number} [config.params.opacity=1] Opacity of the rendering as a whole. Can be overridden by an opacity set for a series. Valid values are 0.0-1.0.
Not applicable on [Lines]{@link CIQ.Renderer.Lines} with a `type` of `mountain`; use an "RGBA" color instead. - * @param {object} [config.params.binding] Allows the use of the study output colors within the renderer. See an example in the [Using Renderers to Display Study Output](tutorial-Using%20and%20Customizing%20Studies%20-%20Creating%20New%20Studies.html#Using_Renderers) section of the Studies tutorial. - * @memberof CIQ.Renderer - * @since 5.2.0 `config.params.binding` parameter added. - * @example - * // add multiple series and attach to a custom y-axis on the left. - * // See this example working here : https://jsfiddle.net/chartiq/b6pkzrad - * - * // note how the addSeries callback is used to ensure the data is present before the series is displayed - * - * //create the custom axis - * var axis=new CIQ.ChartEngine.YAxis(); - * axis.position="left"; - * axis.textStyle="#FFBE00"; - * axis.decimalPlaces=0; // no decimal places on the axis labels - * axis.maxDecimalPlaces=0; // no decimal places on the last price pointer - * - * //create the renderer - * var renderer=stxx.setSeriesRenderer(new CIQ.Renderer.Lines({params:{name:"my-renderer", type:"mountain", yAxis:axis}})); - * - * // create your series and attach them to the chart when the data is loaded. - * stxx.addSeries("NOK", {display:"NOK",width:4},function(){ - * renderer.attachSeries("NOK", "#FFBE00").ready(); - * }); - * - * stxx.addSeries("SNE", {display:"Sony",width:4},function(){ - * renderer.attachSeries("SNE", "#FF9300").ready(); - * }); - */ - CIQ.Renderer.prototype.construct = function (config) { - if (!config) config = {}; - var params = config.params ? config.params : {}; - if (!params.name) params.name = CIQ.uniqueID(); - if (!params.heightPercentage) params.heightPercentage = 0.7; - if (!params.opacity) params.opacity = 1; - if (params.highlightable !== false) params.highlightable = true; - if (!params.panel) params.panel = "chart"; - if (params.yAxis) { - params.yAxis = new CIQ.ChartEngine.YAxis(params.yAxis); - if (!params.yAxis.name) params.yAxis.name = params.name; - } - this.cb = config.callback; - this.params = params; - this.seriesParams = []; - this.caches = {}; - this.colors = {}; - }; - - /** - * Attach a series to the renderer. - * - * This assumes that the series data *is already in the dataSet* and simply connects it to the renderer with the specified parameters. - * See {@link CIQ.ChartEngine#addSeries} for details on how to create a series. - * - * Any parameters defined when attaching a series, such as colors, will supersede any defined when a series was created. This allows you to attach the same series to multiple renderers, each rendering displaying the same series data in a different color, for example. - * - * @param {string} id The name of the series. - * @param {object} parameters Settings to control color and opacity of each series in the group. See {@link CIQ.ChartEngine#addSeries} for implementation examples.

Argument format can be:

  • a `string` containing the color
  • or a more granular `object` having the following members:
- * @param {string} [parameters.field] The name of the field. Name of the field in the dataSet to use for the series. If omitted, defaults to id - * @param {string} [parameters.fill_color_up] Color to use to fill the part when the Close is higher than the previous (or 'transparent' to not display) - * @param {string} [parameters.border_color_up] Color to use to draw the border when the Close is higher than the previous (or 'transparent' to not display) - * @param {number} [parameters.opacity_up=.4] Opacity to use to fill the part when the Close is higher than the previous (0.0-1.0) - * @param {string} [parameters.border_color_even] Color to use to draw the border when the Close is equal to the previous (or 'transparent' to not display) - * @param {string} [parameters.fill_color_down] Color to use to fill the part when the Close is lower than the previous (or 'transparent' to not display) - * @param {string} [parameters.border_color_down] Color to use to draw the border when the Close is lower than the previous (or 'transparent' to not display) - * @param {number} [parameters.opacity_down=.4] Opacity to use to fill the part when the Close is lower than the previous (0.0-1.0) - * @param {string} [parameters.color] Color to use to fill the series in the absence of specific up/down color. - * @param {string} [parameters.border_color] Color to use to draw the border in the series in the absence of specific up/down color. - * @param {string} [parameters.fillStyle] Color to use to fill the mountain chart. - * @param {string} [parameters.baseColor] Color to use at the bottom of the mountain chart, will create a gradient with bgColor - * @param {string} [parameters.bgColor] Color to use at the top of the mountain chart, will create a gradient if baseColor is specified. Otherwise, will fill the mountain solid with this color unless fillStyle is specified - * @param {boolean} [parameters.permanent] Whether the attached series can be removed by the user (lines and bars only). By default the series will not be permanent. This flag (including the default) will supersede the permanent flag of the actual series. As such, a series will not be permanent unless you set this flag to 'true', even if the series being attached was flaged set as permanent when defined. This gives the renderer most control over the rendering process. - * @return {CIQ.Renderer} Returns a copy of this for chaining - * @since 5.1.0 Added `fillStyle`, `baseColor`, and `bgColor` parameters. - * @memberof CIQ.Renderer - * @example - * // add multiple series and attach to a custom y-axis on the left. - * // See this example working here : https://jsfiddle.net/chartiq/b6pkzrad - * - * // note how the addSeries callback is used to ensure the data is present before the series is displayed - * - * //create the custom axis - * var axis=new CIQ.ChartEngine.YAxis(); - * axis.position="left"; - * axis.textStyle="#FFBE00"; - * axis.decimalPlaces=0; // no decimal places on the axis labels - * axis.maxDecimalPlaces=0; // no decimal places on the last price pointer - * - * //create the renderer - * var renderer=stxx.setSeriesRenderer(new CIQ.Renderer.Lines({params:{name:"my-renderer", type:"mountain", yAxis:axis}})); - * - * // create your series and attach them to the chart when the data is loaded. - * stxx.addSeries("NOK", {display:"NOK",width:4},function(){ - * renderer.attachSeries("NOK", "#FFBE00").ready(); - * }); - * - * stxx.addSeries("SNE", {display:"Sony",width:4},function(){ - * renderer.attachSeries("SNE", "#FF9300").ready(); - * }); - */ - CIQ.Renderer.prototype.attachSeries = function (id, parameters) { - var stx = this.stx; - if (!stx) return this; - var series = stx.chart.series[id]; - if (!series) series = { parameters: {} }; - var rParams = this.params, - sParams = series.parameters; - var sp = { - id: id, - chartType: rParams.type, - display: sParams.display, - border_color_up: rParams.defaultBorders ? "auto" : null, - fill_color_up: sParams.color, - opacity_up: rParams.opacity, - border_color_down: rParams.defaultBorders ? "auto" : null, - fill_color_down: sParams.color, - opacity_down: rParams.opacity, - color: sParams.color, - symbol: sParams.symbol, - symbolObject: CIQ.clone(sParams.symbolObject) - }; - if (typeof parameters == "string") { - sp.color = sp.fill_color_down = sp.fill_color_up = parameters; - } else if (typeof parameters == "object") { - for (var p in parameters) sp[p] = parameters[p]; - var c = sp.color, - bc = sp.border_color; - if (c) { - if (!sp.fill_color_up) sp.fill_color_up = c; - if (!sp.fill_color_down) sp.fill_color_down = c; - if (!sp.fill_color_even) sp.fill_color_even = c; - } - if (bc) { - if (!sp.border_color_up) sp.border_color_up = bc; - if (!sp.border_color_down) sp.border_color_down = bc; - if (!sp.border_color_even) sp.border_color_even = bc; - } - } - if (sp.symbol && sp.field != sp.symbol) { - sp.subField = sp.field; - sp.field = sp.symbol; - } - //if(!sp.symbol && !sp.field && !this.highLowBars) sp.field="Close"; - if (!sp.id) sp.id = CIQ.uniqueID(); - - var i = 0; - for (; i < this.seriesParams.length; ++i) { - if (this.seriesParams[i].id === sp.id) { - this.removeSeries(sp.id, true); - break; - } - } - this.seriesParams.splice(i, 0, sp); - - if (sp.fill_color_up != sp.fill_color_down) { - this.colors[id + " up"] = { - color: sp.fill_color_up, - opacity: sp.opacity_up, - display: sp.display ? sp.display + " up" : id + " up" - }; - this.colors[id + " dn"] = { - color: sp.fill_color_down, - opacity: sp.opacity_down, - display: sp.display ? sp.display + " down" : id + " down" - }; - } else { - this.colors[id] = { - color: sp.fill_color_up, - opacity: sp.opacity_up, - display: sp.display ? sp.display : id - }; - } - - var panelName = rParams.panel; - if (!stx.panels[panelName]) { - var yAxis = rParams.yAxis; - if (!yAxis) { - yAxis = new CIQ.ChartEngine.YAxis(); - yAxis.needsInitialPadding = true; - } - yAxis.name = panelName; - stx.createPanel(panelName, panelName, null, null, yAxis); - } else { - if (rParams.yAxis) { - rParams.yAxis = stx.addYAxis(stx.panels[panelName], rParams.yAxis); - rParams.yAxis.needsInitialPadding = true; - sParams.yAxis = rParams.yAxis; - stx.resizeChart(); - } else if (sp.yAxis) { - rParams.yAxis = sp.yAxis; - } - } - - return this; - }; - - /** - * Removes a series from the renderer. - * - * The yAxis and actual series data will also be removed if no longer used by any other renderers. - * When the last series is removed from the renderer, the chart it is attached to will remove the renderer. - * Will [turn off comparison mode]{@link CIQ.ChartEngine#setComparison} if there are no more comparisons on the chart if {@link CIQ.ChartEngine.Chart#forcePercentComparison} is true. - * @param {string} id The field name of the series. - * @param {boolean} [preserveSeries=false] Set to `true` to keep the series data in the CIQ.ChartEngine objects, otherwise it iwll be deleted if no - * @return {CIQ.Renderer} A copy of this for chaining - * @memberof CIQ.Renderer - * @since - * - 2015-07-01 'preserveSeries' is now available. - * - 3.0.0 Series is now removed even if series parameter `permanent` is set to true. The permanent parameter only prevents right click user interaction and not programmatically requested removals. - * - 4.0.0 Series data is now totally removed from masterData if no longer used by any other renderers. - * - 6.2.0 No longer force 'percent'/'linear', when adding/removing comparison series, respectively, unless {@link CIQ.ChartEngine.Chart#forcePercentComparison} is true. This allows for backwards compatibility with previous UI modules. - */ - CIQ.Renderer.prototype.removeSeries = function (id, preserveSeries) { - var spliceIndex = null, - comparing = false; - var stx = this.stx, - chart = stx.chart; - for (var r in chart.seriesRenderers) { - var renderer = chart.seriesRenderers[r]; - for (var sp = 0; sp < renderer.seriesParams.length; sp++) { - var seriesParams = renderer.seriesParams[sp]; - if (seriesParams.id == id && this === renderer) spliceIndex = sp; - else if ( - seriesParams.isComparison && - seriesParams.panel == chart.panel.name && - (!seriesParams.yAxis || seriesParams.yAxis == chart.yAxis) - ) - comparing = true; - } - } - if (spliceIndex !== null) { - if ( - chart.forcePercentComparison && - !comparing && - this.seriesParams[spliceIndex].isComparison && - stx.layout.chartScale != "linear" - ) { - stx.setChartScale(); - } - this.seriesParams.splice(spliceIndex, 1); - } - - delete this.colors[id + " up"]; - delete this.colors[id + " dn"]; - delete this.colors[id]; - - if (!preserveSeries) { - //if(!stx.chart.series[id] || !stx.chart.series[id].parameters.permanent){ - var seriesInUse; - for (var plot in chart.seriesRenderers) { - var myPlot = chart.seriesRenderers[plot]; - for (var s = 0; s < myPlot.seriesParams.length; s++) { - if (myPlot.seriesParams[s].id == id) { - seriesInUse = true; - break; - } - seriesInUse = false; - } - if (seriesInUse) break; - } - if (seriesInUse === false || spliceIndex !== null) { - stx.deleteSeries(id, chart); - } - //} - } - stx.deleteYAxisIfUnused(stx.panels[this.params.panel], this.params.yAxis); - stx.resizeChart(); - stx.layout.symbols = stx.getSymbols({ - "include-parameters": true, - "exclude-studies": true - }); - stx.changeOccurred("layout"); - return this; - }; - - /** - * Modifies the renderer parameters. - * - * Use this function to trigger side effects from modifying parameters instead of manually - * updating the parameters. - * - * @param {object} parameters Specifies the renderer parameters to be updated. - * - * @memberof CIQ.Renderer - * @private - * @since 8.2.0 - */ - CIQ.Renderer.prototype.modifyRenderer = function (parameters) { - const original = this.params; - let { stx } = this; - - for (let param in parameters) { - const value = parameters[param]; - switch (param) { - case "baseline": - if (value) { - if (typeof value === "object") { - this.params.baseline = CIQ.ensureDefaults( - value, - CIQ.ChartEngine.Chart.prototype.baseline - ); - } - stx.registerBaselineToHelper(this); - } else { - stx.removeBaselineFromHelper(this); - } - break; - - case "type": - this.params.type = value; - break; - case "style": - this.params.style = value; - break; - default: - break; - } - } - }; - - /** - * Returns an array of all renderers that depend on a given renderer. - * - * A dependent renderer is one that has `params.dependentOf` set to another renderer's name. - * - * @param {CIQ.ChartEngine} stx A chart object. - * @return {array} Array of dependent renderers. - * @memberof CIQ.Renderer - * @since 7.3.0 - */ - CIQ.Renderer.prototype.getDependents = function (stx) { - var dependents = []; - for (var r in stx.chart.seriesRenderers) { - var renderer = stx.chart.seriesRenderers[r]; - if (renderer.params.dependentOf == this.params.name) - dependents.push(renderer); - } - return dependents; - }; - - /** - * Returns whether the renderer can be dragged to another axis or panel. - * - * @param {CIQ.ChartEngine} stx A chart object. - * @return {boolean} true, if not allowed to drag. - * @memberof CIQ.Renderer - * @since 7.3.0 - */ - CIQ.Renderer.prototype.undraggable = function (stx) { - if (this == stx.mainSeriesRenderer) return true; - return this.params.dependentOf == stx.mainSeriesRenderer.params.name; - }; - - /** - * Removes all series from the renderer and the yAxis from the panel if it is not being used by any current renderers. - * - * @param {boolean} [eraseData=false] Set to true to erase the actual series data in the CIQ.ChartEngine otherwise it will be retained - * @return {CIQ.Renderer} A copy of this for chaining - * @memberof CIQ.Renderer - */ - CIQ.Renderer.prototype.removeAllSeries = function (eraseData) { - if (eraseData || this === this.stx.mainSeriesRenderer) { - var arr = []; - // Compile a list of all of the fields - for (var sp = 0; sp < this.seriesParams.length; sp++) { - arr.push(this.seriesParams[sp].id); - } - for (var i = 0; i < arr.length; i++) { - this.removeSeries(arr[i]); - } - } - this.seriesParams = []; - this.colors = {}; - this.stx.deleteYAxisIfUnused( - this.stx.panels[this.params.panel], - this.params.yAxis - ); - this.stx.resizeChart(); - - return this; - }; - - /** - * Returns the y-axis used by the renderer - * @param {CIQ.ChartEngine} stx chart engine object - * @return {CIQ.ChartEngine.YAxis} Y axis - * @memberof CIQ.Renderer - * @since 7.1.0 - */ - CIQ.Renderer.prototype.getYAxis = function (stx) { - var yAxis; - if (this.params) { - if (this.params.yAxis) yAxis = this.params.yAxis; - else { - var panel = stx.panels[this.params.panel]; - if (!panel) return false; - yAxis = panel.yAxis; - } - } else yAxis = stx.chart.panel.yAxis; - return yAxis; - }; - - /** - * Call this to immediately render the visualization, at the end of a chain of commands. - * @return {CIQ.Renderer} A copy of this for chaining - * @memberof CIQ.Renderer - */ - CIQ.Renderer.prototype.ready = function () { - this.stx.createDataSet(); - this.stx.draw(); - return this; - }; - - /** - * Creates a lines renderer. - * - * This renderer draws lines of various color, thickness, and pattern on a chart. - * - * The `Lines` renderer is used to create the following chart types (including colored versions): - * line, mountain, baseline, wave, and step chart. - * - * **Note:** By default, the renderer displays lines as underlays. As such, they appear below any - * other studies or drawings. - * - * See {@link CIQ.Renderer#construct} for parameters required by all renderers. - * - * @param {object} config Configuration object for the renderer. - * @param {object} [config.params] Parameters to control the renderer itself. - * @param {number} [config.params.width] Width of the rendered line. - * @param {string} [config.params.type="line"] Type of rendering; "line", "mountain", or - * ["wave"]{@link CIQ.ChartEngine#drawWaveChart}. - * @param {boolean} [config.params.useChartLegend=false] Set to true to use the built-in canvas - * legend renderer. See {@link CIQ.ChartEngine.Chart#legendRenderer}; - * @param {boolean} [config.params.highlightable=true] Set to false to prevent selection of series - * via hover. - * @param {string} [config.params.style] Style name to use in lieu of defaults for the type. - * @param {boolean} [config.params.step] Specifies a step chart. - * @param {boolean|CIQ.ChartEngine.Chart#baseline} [config.params.baseline] Specifies a baseline - * chart. If a baseline object is set, then the renderer uses those properties instead of the - * chart's baseline when rendering. When true, the renderer falls back to the chart's baseline - * properties for rendering. - * @param {boolean} [config.params.colored] Specifies the use of a color function (see - * {@link CIQ.Renderer.registerColorFunction}) to determine the color of the segment. - * @param {boolean} [config.params.vertex] Specifies drawing a dot on every vertex. - * @param {boolean} [config.params.vertex_color] Specifies a color for the vertices. If omitted, - * uses the default color (see {@link CIQ.ChartEngine#getDefaultColor}). - * @param {string} [config.params.colorFunction] Override string (or function) used to determine - * color of bar. May be an actual function or a string name of the registered function (see - * {@link CIQ.Renderer.registerColorFunction}). - * - * Common valid parameters for use by {@link CIQ.Renderer#attachSeries} (see also - * {@link CIQ.ChartEngine#plotLine}): - * - `color` — Specify the color for the line by name or in RGBA or hexadecimal format. - * - `pattern` — Specify the pattern as an array. For instance, [5, 5] would be five pixels - * and then five empty pixels. - * - `width` — Specify the width of the line. - * - `baseColor` — Specify the color of the base of a mountain. - * - `fillStyle` — Specify the color to fill a mountain (other than `color`). - * - * @constructor - * @name CIQ.Renderer.Lines - * @since - * - 4.0.0 New `config.params.useChartLegend` added. - * - 5.1.0 Removed subtype parameter, this will be determined internally from - * `config.params.step=true`. - * - 5.1.0 Added `highlightable`, `overChart`, `step`, `baseline`, `vertex`, `style`, `colored`, - * and `colorFunction` parameters. - * - 8.1.0 Added {@link CIQ.ChartEngine.Chart#baseline} type to `baseline` parameter. The new type - * contains a `defaultLevel` property which can be set to the desired baseline value. See - * example below. - * - * @example Create a renderer and set a custom baseline. - * const baseLineRenderer = new CIQ.Renderer.Lines({ - * params: { - * baseline: {defaultLevel: 45}, - * yAxis: true - * } - * }); - * - * stxx.addSeries("GOOG"); - * stxx.setSeriesRenderer(baseLineRenderer).attachSeries("GOOG").ready(); - * - * // or - * - * stxx.addSeries("GOOG", {baseline: {defaultLevel: 105}, color: "purple"}); - * - * @example Add multiple series and attach to a custom y-axis on the left. - * // See this example working here: https://jsfiddle.net/chartiq/b6pkzrad. - * - * // Note how the addSeries callback is used to ensure the data is present before the series is displayed. - * - * // Create the custom axis. - * const axis = new CIQ.ChartEngine.YAxis(); - * axis.position = "left"; - * axis.textStyle = "#FFBE00"; - * axis.decimalPlaces = 0; // No decimal places on the axis labels. - * axis.maxDecimalPlaces = 0; // No decimal places on the last price pointer. - * - * // Create the renderer. - * const renderer = stxx.setSeriesRenderer( - * new CIQ.Renderer.Lines({ - * params: { - * name: "my-renderer", - * type: "mountain", - * yAxis: axis - * } - * }) - * ); - * - * // Create your series and attach them to the chart when the data is loaded. - * stxx.addSeries("NOK", {display: "NOK", width: 4}, function() { - * renderer.attachSeries("NOK", "#FFBE00").ready(); - * }); - * - * stxx.addSeries("SNE", {display: "Sony", width: 4}, function() { - * renderer.attachSeries("SNE", "#FF9300").ready(); - * }); - * - * @example Remove a renderer and all associated data. - * // This should only be necessary if you are also removing the chart itself. - * - * // Remove all series from the renderer, including series data from masterData. - * renderer.removeAllSeries(true); - * - * // Detach the series renderer from the chart. - * stxx.removeSeriesRenderer(renderer); - * - * // Delete the renderer itself. - * renderer=null; - * - * @example Create a colored step baseline mountain with vertices. - * const renderer = stxx.setSeriesRenderer( - * new CIQ.Renderer.Lines({ - * params: { - * name: "my-renderer", - * type: "mountain", - * baseline: true, - * step: true, - * colored: true, - * vertex: true, - * yAxis: axis - * } - * }) - * ); - */ - CIQ.Renderer.Lines = function (config) { - this.construct(config); - const { params } = this; - if (!params.type) params.type = "line"; - if (!params.style) { - switch (params.type) { - case "mountain": - if (params.baseline) params.style = "stx_baseline_delta_mountain"; - else if (params.colored) params.style = "stx_colored_mountain_chart"; - else params.style = "stx_mountain_chart"; - break; - default: - params.style = "stx_line_chart"; - } - } - this.supportsAnimation = true; - if (params.type == "wave" || params.type == "channel") { - // wave charts don't support these options and no gap support either. - params.step = params.vertex = params.baseline = params.colored = false; - this.highLowBars = this.barsHaveWidth = true; - this.supportsAnimation = false; - } else if (params.type == "step") { - params.step = true; - } - let { baseline } = params; - if (baseline && typeof baseline === "object") { - CIQ.ensureDefaults( - params.baseline, - CIQ.ChartEngine.Chart.prototype.baseline - ); - } - }; - CIQ.inheritsFrom(CIQ.Renderer.Lines, CIQ.Renderer, false); - - /** - * Returns a new Lines renderer if the featureList calls for it - * FeatureList should contain whatever features requested; valid features: - * line, mountain, baseline (delta), step, vertex, colored, wave - * Anything else is an invalid feature and will cause function to return null - * Called by {@link CIQ.Renderer.produce} to create a renderer for the main series - * @param {array} featureList List of rendering terms requested by the user, parsed from the chartType - * @param {object} [params] Parameters used for the series to be created, used to create the renderer - * @return {CIQ.Renderer.Lines} A new instance of the Lines renderer, if the featureList matches - * @memberof CIQ.Renderer.Lines - * @since 5.1.0 - */ - CIQ.Renderer.Lines.requestNew = function (featureList, params) { - var type = null, - isStep = params.step, - isColored = params.colored, - isBaseline = params.baseline, - isVertex = params.vertex; - for (var pt = 0; pt < featureList.length; pt++) { - var pType = featureList[pt]; - switch (pType) { - case "line": - case "mountain": - case "wave": - case "channel": - type = pType; - break; - case "baseline": - isBaseline = true; - break; - case "colored": - isColored = true; - break; - case "step": - isStep = true; - break; - case "vertex": - isVertex = true; - break; - case "delta": - break; - default: - return null; // invalid chart type for this renderer - } - } - if (type === null && !isBaseline && !isStep) return null; - - return new CIQ.Renderer.Lines({ - params: CIQ.extend(params, { - type: type, - step: isStep, - colored: isColored, - baseline: isBaseline, - vertex: isVertex - }) - }); - }; - - CIQ.Renderer.Lines.prototype.draw = function () { - var stx = this.stx, - panel = this.stx.panels[this.params.panel], - chart = panel.chart; - var seriesMap = {}; - var s, - seriesParams = this.seriesParams; - var colorFunction = this.params.colorFunction; - function defaultColorFunction(param) { - var stxLineUpColor = - param.fill_color_up || stx.getCanvasColor("stx_line_up"); - var stxLineDownColor = - param.fill_color_down || stx.getCanvasColor("stx_line_down"); - var stxLineColor = param.color || stx.getCanvasColor("stx_line_chart"); - return function (stx, quote, mode) { - if (!quote.iqPrevClose && quote.iqPrevClose !== 0) return stxLineColor; - if (quote.Close > quote.iqPrevClose) return stxLineUpColor; - if (quote.Close < quote.iqPrevClose) return stxLineDownColor; - return stxLineColor; - }; - } - for (s = 0; s < seriesParams.length; s++) { - var sParam = seriesParams[s]; - if (this.params.colored) { - var parts = ["_color_up", "_color_down", "_color"]; - for (var i = 0; i < parts.length; i++) { - //if(!sParam["fill"+parts[i]]){ - var b = sParam["border" + parts[i]]; - if (b && b != "auto") sParam["fill" + parts[i]] = b; - //} - } - if (!colorFunction) colorFunction = defaultColorFunction(sParam); - this.params.colorFunction = colorFunction; - } - var defaultParams = {}; - if (chart.series[sParam.id]) { - // make sure the series is still there. - defaultParams = CIQ.clone(chart.series[sParam.id].parameters); - } - seriesMap[sParam.id] = { - parameters: CIQ.extend(CIQ.extend(defaultParams, this.params), sParam), - yValueCache: this.caches[sParam.id] - }; - if ( - this == stx.mainSeriesRenderer && - chart.customChart && - chart.customChart.colorFunction - ) { - seriesMap[sParam.id].parameters.colorFunction = - chart.customChart.colorFunction; - } - } - stx.drawSeries(chart, seriesMap, this.params.yAxis, this); - for (s in seriesMap) { - this.caches[s] = seriesMap[s].yValueCache; - } - }; - - CIQ.Renderer.Lines.prototype.drawIndividualSeries = function ( - chart, - parameters - ) { - if (parameters.invalid) return; - var stx = this.stx, - context = chart.context, - rc = null; - var colorFunction = parameters.colorFunction, - panel = stx.panels[parameters.panel] || chart.panel; - if (typeof colorFunction == "string") { - colorFunction = CIQ.Renderer.colorFunctions[colorFunction]; - if (!colorFunction) return; - } - - if (parameters.vertex) { - context.save(); - context.lineJoin = "bevel"; - } - if (parameters.type == "wave") { - rc = stx.drawWaveChart(panel, parameters); - } else if (parameters.baseline) { - rc = stx.drawBaselineChart(panel, parameters); - stx.positionBaselineHandle(this); - } else if (parameters.type == "mountain") { - parameters.returnObject = true; - rc = stx.drawMountainChart(panel, parameters, colorFunction); - } else if (parameters.type == "channel") { - parameters.returnObject = true; - rc = stx.drawChannelChart(panel, colorFunction, parameters); - } else { - parameters.returnObject = true; - rc = stx.drawLineChart(panel, parameters.style, colorFunction, parameters); - } - if (parameters.vertex) { - stx.scatter(panel, { - yAxis: parameters.yAxis, - field: parameters.symbol || parameters.field, - subField: parameters.subField, - symbol: parameters.symbol, - color: parameters.vertex_color, - highlight: parameters.highlight - }); - context.restore(); - } - return rc; - }; - - /** - * Creates an OHLC renderer. - * - * Note: by default the renderer will display bars as underlays. As such, they will appear below any other studies or drawings. - * - * The OHLC renderer is a base class for creating the following chart types: - * - {@link CIQ.Renderer.HLC} - * - {@link CIQ.Renderer.Bars} - * - {@link CIQ.Renderer.Candles} - * - {@link CIQ.Renderer.SimpleHistogram} - *
and is normally not directly accessed. - * - * See {@link CIQ.Renderer#construct} for parameters required by all renderers - * @param {object} config Config for renderer - * @param {object} [config.params] Parameters to control the renderer itself - * @param {string} [config.params.type] Type of rendering "bar", "candle". Not needed if `params.histogram` is set) - * @param {boolean} [config.params.useChartLegend=false] Set to true to use the built in canvas legend renderer. See {@link CIQ.ChartEngine.Chart#legendRenderer}; - * @param {string} [config.params.style] Style name to use in lieu of defaults for the type - * @param {boolean} [config.params.colored] For bar or hlc, specifies using a condition or colorFunction to determine color - * @param {boolean} [config.params.hollow] Specifies candles should be hollow candles - * @param {boolean} [config.params.volume] Specifies candles should be volume candles - * @param {boolean} [config.params.histogram] Specifies histogram chart (if set, `params.type` is not required). These are basic histograms that allow just one bar per tick; not to be confused with stackable histograms which require the more advanced {@link CIQ.Renderer.Histogram} - * @param {boolean} [config.params.hlc] Specifies bar chart, with just hlc data; no open tick - * @param {boolean} [config.params.gradient=true] Specifies histogram bars are to be drawn with a gradient; set to false to draw with solid colors - * @param {string} [config.params.colorBasis="close"] For bar/hlc charts, will compute color based on whether current close is higher or lower than previous close. Set to "open" to compute this off the open rather than yesterday's close. - * @param {function} [config.params.colorFunction] Oerride function (or string) used to determine color of bar. May be an actual function or a string name of the registered function (see {@link CIQ.Renderer.registerColorFunction}) - * @constructor - * @name CIQ.Renderer.OHLC - * @since 5.1.0 - * @example - // Colored hlc chart - var renderer=stxx.setSeriesRenderer(new CIQ.Renderer.OHLC({params:{name:"bars", type:"bar", hlc:true, colored:true}})); - * - */ - - CIQ.Renderer.OHLC = function (config) { - this.construct(config); - var params = this.params; - if (!params.type) params.type = "candle"; - this.highLowBars = this.barsHaveWidth = this.standaloneBars = true; - if (params.histogram) { - params.type = "candle"; - this.highLowBars = false; - params.volume = params.hollow = false; - } - if (params.type == "bar") - params.volume = params.hollow = params.histogram = false; - if (params.type == "candle") params.hlc = params.colored = false; - if (params.volume) params.hollow = true; - }; - CIQ.inheritsFrom(CIQ.Renderer.OHLC, CIQ.Renderer, false); - - /** - * Returns a new OHLC renderer if the featureList calls for it - * FeatureList should contain whatever features requested; valid features: - * bar, hlc, candle, colored, histogram, hollow, volume - * Anything else is an invalid feature and will cause function to return null - * - * **Note:** If you are using the base package then the only valid features are: candle and histogram. - * - * Called by {@link CIQ.Renderer.produce} to create a renderer for the main series - * @param {array} featureList List of rendering terms requested by the user, parsed from the chartType - * @param {object} [params] Parameters used for the series to be created, used to create the renderer - * @return {CIQ.Renderer.OHLC} A new instance of the OHLC renderer, if the featureList matches - * @memberof CIQ.Renderer.OHLC - * @since 5.1.0 - */ - CIQ.Renderer.OHLC.requestNew = function (featureList, params) { - var type = null, - histogram = params.histogram; - for (var pt = 0; pt < featureList.length; pt++) { - var pType = featureList[pt]; - switch (pType) { - case "candle": - type = pType; - break; - case "histogram": - histogram = true; - type = "candle"; - break; - default: - return null; // invalid chartType for this renderer - } - } - if (type === null) return null; - - return new CIQ.Renderer.OHLC({ - params: CIQ.extend(params, { type: type, histogram: histogram }) - }); - }; - - /** - * Returns array of chartParts for configuring rendering. - * - * @since 7.4.0 - * @private - */ - CIQ.Renderer.OHLC.getChartParts = function (style, colorUseOpen) { - var CANDLEUP = 8; // today's close greater than today's open - var CANDLEDOWN = 16; // today's close less than today's open - var CANDLEEVEN = 32; // today's close equal to today's open - return [ - {type:"histogram", drawType:"histogram", style:"stx_histogram_up", condition:CANDLEUP, fill:"fill_color_up", border:"border_color_up", useColorInMap:true, useBorderStyleProp:true}, - {type:"histogram", drawType:"histogram", style:"stx_histogram_down", condition:CANDLEDOWN, fill:"fill_color_down", border:"border_color_down", useColorInMap:true, useBorderStyleProp:true}, - {type:"histogram", drawType:"histogram", style:"stx_histogram_even", condition:CANDLEEVEN, fill:"fill_color_even", border:"border_color_even", skipIfPass:true, useColorInMap:true, useBorderStyleProp:true}, - {type:"candle", drawType:"shadow", style:"stx_candle_shadow", border:"border_color_up"}, - {type:"candle", drawType:"shadow", style:"stx_candle_shadow_up", condition:CANDLEUP, border:"border_color_up"}, - {type:"candle", drawType:"shadow", style:"stx_candle_shadow_down", condition:CANDLEDOWN, border:"border_color_down"}, - {type:"candle", drawType:"shadow", style:"stx_candle_shadow_even", condition:CANDLEEVEN, border:"border_color_even", skipIfPass:true}, - {type:"candle", drawType:"candle", style:"stx_candle_up", condition:CANDLEUP, fill:"fill_color_up", border:"border_color_up", useColorInMap:true, useBorderStyleProp:true}, - {type:"candle", drawType:"candle", style:"stx_candle_down", condition:CANDLEDOWN, fill:"fill_color_down", border:"border_color_down", useColorInMap:true, useBorderStyleProp:true}, - ]; // prettier-ignore - }; - - CIQ.Renderer.OHLC.prototype.draw = function () { - var stx = this.stx, - panel = this.stx.panels[this.params.panel], - chart = panel.chart; - var seriesMap = {}; - var s, - seriesParams = this.seriesParams; - for (s = 0; s < seriesParams.length; s++) { - var sParam = seriesParams[s]; - - var defaultParams = {}; - if (chart.series[sParam.id]) { - // make sure the series is still there. - defaultParams = CIQ.clone(chart.series[sParam.id].parameters); - } - seriesMap[sParam.id] = { - parameters: CIQ.extend(CIQ.extend(defaultParams, this.params), sParam) - //yValueCache: this.caches[sParam.id] - }; - if ( - this == stx.mainSeriesRenderer && - chart.customChart && - chart.customChart.colorFunction - ) { - seriesMap[sParam.id].parameters.colorFunction = - chart.customChart.colorFunction; - } - } - stx.drawSeries(chart, seriesMap, this.params.yAxis, this); - for (s in seriesMap) { - if (seriesMap[s].yValueCache) this.caches[s] = seriesMap[s].yValueCache; - } - }; - - CIQ.Renderer.OHLC.prototype.getColor = function ( - stx, - panel, - style, - isBorder, - isGradient, - overrideColor - ) { - var color = overrideColor || style.color; - var yAxis = this.params.yAxis || panel.yAxis; - if (isBorder) { - color = - overrideColor || style.borderLeftColor || style["border-left-color"]; - if (!color) return null; - } - if (!isGradient) return color; - var top = stx.pixelFromTransformedValue(yAxis.highValue, panel); - if (isNaN(top)) top = 0; // 32 bit IE doesn't like large numbers - var backgroundColor = style.backgroundColor; - if (color && !CIQ.isTransparent(color)) { - var gradient = stx.chart.context.createLinearGradient( - 0, - top, - 0, - 2 * yAxis[yAxis.flipped ? "top" : "bottom"] - top - ); - gradient.addColorStop(0, color); - gradient.addColorStop(1, backgroundColor); - return gradient; - } - return backgroundColor; - }; - - CIQ.Renderer.OHLC.prototype.drawIndividualSeries = function ( - chart, - parameters - ) { - if (parameters.invalid) return; - var stx = this.stx, - context = chart.context; - var colorFunction = parameters.colorFunction, - panel = stx.panels[parameters.panel] || chart.panel; - if (typeof colorFunction == "string") { - colorFunction = CIQ.Renderer.colorFunctions[colorFunction]; - if (!colorFunction) return; - } - var noBorders = - stx.layout.candleWidth - chart.tmpWidth <= 2 && chart.tmpWidth <= 3; - var CLOSEUP = 1; // today's close greater than yesterday's close - var CLOSEDOWN = 2; // today's close less than yesterday's close - var CLOSEEVEN = 4; // today's close the same as yesterday's close - var CANDLEUP = 8; // today's close greater than today's open - var CANDLEDOWN = 16; // today's close less than today's open - var CANDLEEVEN = 32; // today's close equal to today's open - if (!chart.state.chartType) chart.state.chartType = {}; - var pass = (chart.state.chartType.pass = {}); - var colorUseOpen = stx.colorByCandleDirection; - if (parameters.colorBasis) colorUseOpen = parameters.colorBasis == "open"; - var isHistogram = parameters.histogram, - type = parameters.type, - hollow = parameters.hollow; - var noWicks = stx.noWicksOnCandles[type]; - stx.startClip(panel.name); - var colors = null, - rc = { colors: [], cache: [] }, - caches = []; - if (colorFunction) { - var drawingParams = { - isHistogram: isHistogram, - field: parameters.field, - yAxis: parameters.yAxis, - isVolume: parameters.volume, - highlight: parameters.highlight - }; - if (!isHistogram && type == "bar") { - drawingParams.type = parameters.hlc ? "hlc" : "bar"; - rc = stx.drawBarChart( - panel, - "stx_bar_chart", - colorFunction, - drawingParams - ); - } else { - if (type == "candle" && !noWicks) - stx.drawShadows(panel, colorFunction, drawingParams); - rc = stx.drawCandles(panel, colorFunction, drawingParams); //all bars - drawingParams.isOutline = true; - if (hollow || !noBorders) - stx.drawCandles(panel, colorFunction, drawingParams); //all bar borders, if candlewidth is too small then don't draw the borders - } - } else { - var isGradient = isHistogram && parameters.gradient !== false; - var chartParts = CIQ.Renderer.OHLC.getChartParts( - parameters.style, - colorUseOpen - ); - for (var i = 0; i < chartParts.length; i++) { - var chartPart = chartParts[i]; - if (chartPart.skipIfPass && !pass.even) continue; - else if (isHistogram) { - if (chartPart.type != "histogram") continue; - } else if (type == "bar") { - if (chartPart.type != "bar") continue; - else if (parameters.colored && !chartPart.condition) continue; - else if (!parameters.colored && chartPart.condition) continue; - } else if (hollow) { - if (chartPart.type != "hollow") continue; - else if (chartPart.drawType == "shadow" && noWicks) continue; - } else if (type == "candle") { - if (chartPart.type != "candle") continue; - else if (chartPart.drawType == "shadow") { - if (noWicks) continue; - var coloredShadowUp = - parameters.border_color_up || - stx.getCanvasColor("stx_candle_shadow_up"); - var coloredShadowDown = - parameters.border_color_down || - stx.getCanvasColor("stx_candle_shadow_down"); - var coloredShadowEven = - parameters.border_color_even || - stx.getCanvasColor("stx_candle_shadow_even"); - if ( - !CIQ.colorsEqual(coloredShadowUp, coloredShadowDown) || - !CIQ.colorsEqual(coloredShadowUp, coloredShadowEven) || - !CIQ.colorsEqual(coloredShadowUp, stx.defaultColor) - ) { - if (!chartPart.condition) continue; - } else if (chartPart.condition) continue; - } - } else continue; - - var styleArray = stx.canvasStyle(chartPart.style); - var legendColor = this.getColor( - stx, - panel, - styleArray, - false, - false, - parameters[chartPart.fill] - ); - var fillColor = this.getColor( - stx, - panel, - styleArray, - false, - isGradient, - parameters[chartPart.fill] - ); - var borderColor = this.getColor( - stx, - panel, - styleArray, - chartPart.useBorderStyleProp && !noBorders, - isGradient, - parameters[chartPart.border] - ); - if (chartPart.drawType == "candle") { - if (chartPart.type == "hollow") { - // Solid candles get no border unless the border color is different than the fill color - if ( - !CIQ.isTransparent(fillColor) && - CIQ.colorsEqual(borderColor, fillColor) - ) - borderColor = chartPart.useColorInMap ? "transparent" : fillColor; - if (!chartPart.useColorInMap) fillColor = stx.containerColor; - } else if (chartPart.type == "candle") { - // Check to see if the candles are too small for borders - if (noBorders) { - if (CIQ.isTransparent(fillColor)) fillColor = borderColor; - // transparent candle, draw it with the border color - else borderColor = fillColor; // non-transparent candle, set the border to the fill color - } - } - } - context.globalAlpha = parameters.opacity; - caches.push( - stx.drawBarTypeChartInner({ - fillColor: fillColor, - borderColor: borderColor, - condition: chartPart.condition, - style: chartPart.style, - type: type == "bar" && parameters.hlc ? "hlc" : chartPart.drawType, - panel: panel, - field: parameters.field, - yAxis: parameters.yAxis, - volume: parameters.volume && parameters.hollow, - highlight: parameters.highlight - }) - ); - if (!colors) colors = {}; - if (chartPart.useColorInMap) colors[legendColor] = 1; - } - } - stx.endClip(); - for (var c in colors) { - if (!parameters.hollow || !CIQ.equals(c, stx.containerColor)) { - rc.colors.push(c); - } - } - for (c = 0; c < caches.length; c++) { - for (var x = 0; x < caches[c].cache.length; x++) { - var v = caches[c].cache[x]; - if (v || v === 0) rc.cache[x] = v; - } - } - return rc; - }; - - /** - * Creates a Candles renderer, a derivation of the OHLC renderer. - * - * Note: by default the renderer will display candles as underlays. As such, they will appear below any other studies or drawings. - * - * The Candles renderer is used to create the following drawing types: candle, hollow candle, volume candle - * - * See {@link CIQ.Renderer#construct} for parameters required by all renderers - * @param {object} config Config for renderer - * @param {object} [config.params] Parameters to control the renderer itself - * @param {boolean} [config.params.useChartLegend=false] Set to true to use the built in canvas legend renderer. See {@link CIQ.ChartEngine.Chart#legendRenderer}; - * @param {string} [config.params.style] Style name to use in lieu of defaults for the type - * @param {boolean} [config.params.hollow] Specifies candles should be hollow candles - * @param {boolean} [config.params.volume] Specifies candles should be volume candles - * @param {function} [config.params.colorFunction] Override function (or string) used to determine color of candle. May be an actual function or a string name of the registered function (see {@link CIQ.Renderer.registerColorFunction}) - * - * Common valid parameters for use by attachSeries.:
- * `fill_color_up` - Color to use for up candles.
- * `fill_color_down` - Color to use for down candles.
- * `fill_color_even` - Color to use for even candles.
- * `border_color_up` - Color to use for the border of up candles.
- * `border_color_down` - Color to use for the order of down candles.
- * `border_color_even` - Color to use for the order of even candles.
- * - * @constructor - * @name CIQ.Renderer.Candles - * @since 5.1.1 - * @example - // Hollow candle chart - var renderer=stxx.setSeriesRenderer(new CIQ.Renderer.Candles({params:{name:"candles", hollow:true}})); - * - */ - CIQ.Renderer.Candles = function (config) { - this.construct(config); - var params = this.params; - params.type = "candle"; - this.highLowBars = this.barsHaveWidth = this.standaloneBars = true; - params.hlc = params.colored = params.histogram = false; - if (params.volume) params.hollow = true; - }; - CIQ.inheritsFrom(CIQ.Renderer.Candles, CIQ.Renderer.OHLC, false); - - /** - * Creates a SimpleHistogram renderer, a derivation of the Candles renderer. - * - * Note: by default the renderer will display histogram as underlays. As such, they will appear below any other studies or drawings. - * - * The SimpleHistogram renderer is used to create a histogram with the top of each bar representing the value of the field. - * It is a much simpler form of histogram than that produced by the Histogram renderer (advanced package). - * - * See {@link CIQ.Renderer#construct} for parameters required by all renderers - * @param {object} config Config for renderer - * @param {object} [config.params] Parameters to control the renderer itself - * @param {boolean} [config.params.useChartLegend=false] Set to true to use the built in canvas legend renderer. See {@link CIQ.ChartEngine.Chart#legendRenderer}; - * @param {string} [config.params.style] Style name to use in lieu of defaults for the type - * @param {boolean} [config.params.gradient=true] Specifies histogram bars are to be drawn with a gradient; set to false to draw with solid colors - * @param {function} [config.params.colorFunction] Override function (or string) used to determine color of bar. May be an actual function or a string name of the registered function (see {@link CIQ.Renderer.registerColorFunction}) - * - * Valid parameters for use by attachSeries.:
- * `fill_color_up` - Color to use for up histogram bars.
- * `fill_color_down` - Color to use for down histogram bars.
- * `fill_color_even` - Color to use for even histogram bars.
- * `border_color_up` - Color to use for the border of up histogram bars.
- * `border_color_down` - Color to use for the order of down histogram bars.
- * `border_color_even` - Color to use for the order of even histogram bars.
- * - * @constructor - * @name CIQ.Renderer.SimpleHistogram - * @since 5.1.1 - * @example - // SimpleHistogram under the main chart plot - var renderer=stxx.setSeriesRenderer(new CIQ.Renderer.SimpleHistogram({params:{name:"histogram", overChart:false}})); - * - */ - - CIQ.Renderer.SimpleHistogram = function (config) { - this.construct(config); - var params = this.params; - params.type = "candle"; - params.histogram = true; - this.barsHaveWidth = this.standaloneBars = true; - this.highLowBars = false; - params.hlc = params.colored = params.hollow = params.volume = false; - }; - CIQ.inheritsFrom(CIQ.Renderer.SimpleHistogram, CIQ.Renderer.Candles, false); - - }; - - - let __js_core_string_ = (_exports) => { - - - //------------------------------------------------------------------------------------------- - // Be sure your webserver is set to deliver UTF-8 charset - // For apache add "AddDefaultCharset UTF-8" to httpd.conf - // otherwise use \u unicode escapes for non-ascii characters - //------------------------------------------------------------------------------------------- - - var CIQ = _exports.CIQ; - - /** - * Capitalizes the first letter of a string. - * - * @param {string} string String to be capitalized. - * @return {string} Capitalized version of the string. - * @memberof CIQ - * @since 7.4.0 Replaces {@link String.prototype.capitalize}. - */ - CIQ.capitalize = function (string) { - if (!string) return ""; - return string.charAt(0).toUpperCase() + string.slice(1); - }; - - CIQ.camelCaseRegExp = /-([a-z])/g; - /** - * Converts from hyphenated to camel case. Used primarily for converting css style names (which are hyphenated) to property values (which are camel case) - * @param {string} name Hyphenated style name - * @return {string} Camel case style name - * @memberof CIQ - */ - CIQ.makeCamelCase = function (name) { - return name.replace(CIQ.camelCaseRegExp, function (g) { - return g[1].toUpperCase(); - }); - }; - - /** - * Convenience function for generating a unique ID. Defaults to a short, pseudo unique ID based on the current time. - * Radix 36 is used resulting in a compact string consisting only of letters and numerals. While not guaranteed to be - * unique, this function has a high probability of uniqueness when it is triggered by human activity even in a large - * user base. If called with `true` as the first argument it will instead return an RFC4122 version 4 compliant UUID. - * @param {boolean} generateUUID If true will return a UUID. - * @return {string} Either a RFC4122 version 4 compliant UUID or a unique string consisting of letters and numerals - * @memberof CIQ - */ - CIQ.uniqueID = function (generateUUID) { - if (generateUUID) { - // See http://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript - var d = new Date().getTime(); - if ( - typeof window !== "undefined" && - window.performance && - typeof window.performance.now === "function" - ) { - d += window.performance.now(); //use high-precision timer if available - } - var uuid = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace( - /[xy]/g, - function (c) { - var r = (d + Math.random() * 16) % 16 | 0; - d = Math.floor(d / 16); - return (c == "x" ? r : (r & 0x3) | 0x8).toString(16); - } - ); - return uuid; - } - var epoch = new Date(); - var id = epoch.getTime().toString(36); - id += Math.floor(Math.random() * Math.pow(36, 2)).toString(36); - return id.toUpperCase(); - }; - - }; - - - let __js_core_typedefs_ = (_exports) => { - /** - * OHLC Quote. This is the data format that the {@link CIQ.ChartEngine} recognizes. - * All quotes must at least have a DT property that is a JavaScript Date in order to be valid, every other value is nullable. - * Quotes can contain as many properties as you would like, allowing the ChartEngine to plot any value. - * - * @typedef {object} CIQ.ChartEngine~OHLCQuote - * @prop {number} Open The opening price of the quote. - * @prop {number} High The highest price of the quote. - * @prop {number} Low The lowest price of the quote. - * @prop {number} Close The closing price of the quote. - * @prop {number} Volume The number of shares traded. - * @prop {!Date} DT The date and time of the quote. - */ - - /** - * CIQ.Drawing interface placeholder to be augmented in *standard.js* with properties. - * - * @tsinterface {object} CIQ~Drawing - */ - - /** - * CIQ.ChartEngine.RangeParameters interface placeholder to be augmented in *standard.js* with properties. - * - * @tsinterface {object} CIQ.ChartEngine~RangeParameters - */ - - /** - * CIQ.ChartEngine.SpanParameters interface placeholder to be augmented in *standard.js* with properties. - * - * @tsinterface {object} CIQ.ChartEngine~SpanParameters - */ - - /** - * CIQ.ChartEngine.currentVectorParameters interface placeholder to be augmented in *standard.js* with properties. - * - * @tsinterface {object} CIQ.ChartEngine~currentVectorParameters - */ - - /** - * CIQ.Studies.StudyDescriptor interface placeholder to be augmented in *standard.js* with properties. - * - * @tsinterface {object} CIQ.Studies~StudyDescriptor - */ - - }; - - - let __js_core_xhr_ = (_exports) => { - - - var CIQ = _exports.CIQ; - - /** - * Returns the host portion of a url - * @param {string} url The url, such as document.location.href - * @return {string} The host portion, including port, if the url is a valid URI - * @memberof CIQ - */ - CIQ.getHostName = function (url) { - try { - return url.match(/:\/\/(.[^/]+)/)[1]; - } catch (e) { - return ""; - } - }; - - /** - * A parsed query string object - * Does not support using multi-value keys (i.e. "a=1&a=2") - * @param {string} [query] Query string. If not provided then the browser location's query string will be used - * @return {object} An object containing the parsed values of the query string - * @memberof CIQ - */ - CIQ.qs = function (query) { - var qsParm = {}; - if (!query) query = window.location.search.substring(1); - var parms = query.split("&"); - for (var i = 0; i < parms.length; i++) { - var pos = parms[i].indexOf("="); - var key; - if (pos > 0) { - key = parms[i].substring(0, pos); - qsParm[key] = parms[i].substring(pos + 1); - } else { - key = parms[i]; - qsParm[key] = null; - } - } - return qsParm; - }; - - /** - * @callback CIQ.postAjax~requestCallback - * @param {number} status HTTP status - * @param {string} response HTTP response - */ - /** - * Convenience function for making an ajax post. If payload is non-null then the method will be set to POST, otherwise GET. - * @param {object} params Parameters for the post - * @param {string} [params.url] The url to send the ajax query to - * @param {string} [params.payload] An optional payload to send - * @param {CIQ.postAjax~requestCallback} [params.cb] Callback function when complete - * @param {string} [params.contentType] Optionally override the content type - * @param {boolean} [params.noEpoch] By default the epoch is appended as a query string to bust caching. Set this to false to not append the epoch. - * @param {string} [params.method] Optionally override the HTTP method - * @param {object} [params.headers] Optional additional HTTP headers to send. Example: ```{"x-custom-header-1":"abc","x-custom-header-2":"123"}``` - * @param {boolean} [params.responseHeaders] Optional Set to true to have callback passed the response headers from the server - * @param {number} [params.timeout] Optional Request timeout in msec. If omitted, timeout is default (no timeout) - * @param {boolean} [params.ungovernable] Optional If true, request not subject to rate limiting - * @param {string} arg1 Payload - * @param {function} arg2 Callback - * @param {string} arg3 Ajax content type - * @param {boolean} arg4 Set to true for no epoch - * @return {boolean} True if there were no errors fetching data. - * @memberof CIQ - * @since 3.0.0 Added `timeout` and `ungovernable` parameters. - */ - CIQ.postAjax = function (params, arg1, arg2, arg3, arg4) { - if (typeof params == "string") { - params = { - url: params, - payload: arg1, - cb: arg2, - contentType: arg3, - noEpoch: arg4, - method: null, - responseHeaders: false - }; - } - var url = params.url, - cb = params.cb, - payload = params.payload; - if (!cb) cb = function () {}; - if (!params.ungovernable) { - if ( - CIQ.Extras && - CIQ.Extras.RequestLimiter && - CIQ.Extras.RequestLimiter.hitRequestLimit(url) - ) { - cb(429, null, {}); - return; - } - } - function parseHeaders(server) { - //Optional code for processing headers. - var headers = {}; - if (!params.responseHeaders) return; - var headerString = server.getAllResponseHeaders(); - var headerArray = headerString.split("\n"); - for (var i = 0; i < headerArray.length; i++) { - var split = headerArray[i].split(":"); - while (split[1] && split[1].charAt(0) == " ") - split[1] = split[1].substring(1); - if (split[0] !== "") { - headers[split.shift()] = split.join(":"); - } - } - return headers; - } - var server = new XMLHttpRequest(); - if (!server) return false; - var epoch = new Date(); - if (!params.noEpoch) { - if (url.indexOf("?") == -1) url += "?ciqrandom=" + epoch.getTime(); - else url += "&ciqrandom=" + epoch.getTime(); - } - var method = params.method, - headers = params.headers; - if (!method) method = payload ? "POST" : "GET"; - - server.open(method, url, true); - if (!params.contentType) - params.contentType = "application/x-www-form-urlencoded"; - if (payload) server.setRequestHeader("Content-Type", params.contentType); - if (headers) { - for (var header in headers) { - server.setRequestHeader(header, headers[header]); - } - } - if (params.timeout) { - server.timeout = params.timeout; // in msec - } - server.ontimeout = function () { - cb(408, null, {}); - }; - server.onload = function () { - if (this.status === 0) this.status = "0"; - else if (!this.status) this.status = 200; //XDomainRequest - cb(this.status, this.responseText, parseHeaders(this)); - }; - server.onerror = function () { - cb("0", null, {}); - }; - try { - server.send(payload); - } catch (e) { - cb("0", e, {}); - } - return true; - }; - - /** - * Dynamically load UI elements from an external HTML file. This is accomplished by rendering raw HTML in an `iframe` - * and then cloning all of the newly created DOM elements into our main document. Repeat requests for the same resource - * load data from the existing `iframe`. - * - * The title of the `iframe` is checked. External content should *not* have a title. By convention, 404 or 500 errors - * have a title; and so, we use this to determine whether the `iframe` contains valid content or not. - * - * @param {string} url The external URL to fetch new UI content. - * @param {HTMLElement} el Element to append the UI content to; the default is `document.body`. - * @param {Function} cb A callback function to call when the new UI is available. - * @memberof CIQ - * @since - * - 6.1.0 Added the `el` parameter. - * - 7.2.0 Added caching per application instance by reusing the `iframe` contents. - */ - CIQ.loadUI = function (url, el, cb) { - if (!el || typeof el == "function") { - cb = el; // backward compatibility - el = document.body; - } - var iframe = document.querySelector('iframe[original-url="' + url + '"]'); - var onload = function () { - var iframeDocument = null; - - try { - iframeDocument = this.contentDocument; - } catch (error) { - return cb(error); - } - - // having a title is considered a server error such as a 404 or 500 response - if (iframeDocument && !iframeDocument.title) { - var html = iframeDocument.body.innerHTML; - var div = document.createElement("div"); - - CIQ.innerHTML(div, html); - - for (var j = 0; j < div.children.length; j++) { - var ch = div.children[j].cloneNode(true); - el.appendChild(ch); - } - - cb(null); - } else { - cb(new Error("iFrame not found or document has a title")); - } - }; - - if (iframe) { - var iframeDocument = null; - - try { - iframeDocument = iframe.contentDocument; - } catch (error) { - return cb(error); - } - - if ( - iframeDocument.readyState === "complete" && - iframeDocument.location && - iframeDocument.location.href !== "about:blank" - ) { - onload.call(iframe); - } else { - iframe.addEventListener("load", onload); - } - } else { - iframe = document.createElement("iframe"); - iframe.setAttribute("original-url", url); - iframe.src = url + (url.indexOf("?") === -1 ? "?" : "&") + CIQ.uniqueID(); - iframe.hidden = true; - iframe.addEventListener("load", onload); - document.body.appendChild(iframe); - } - }; - - /** - * Loads JavaScript dynamically. Keeps a static memory of scripts that have been loaded to - * prevent them from being loaded twice. The callback function however is always called, even - * if the script has already been loaded. - * - * @param {string} scriptName The URL of the script to load. - * @param {function} [cb] Callback function to call when the script is loaded. - * @param {boolean} [isModule] If true, the script loads a module. - * - * @memberof CIQ - * @since 8.0.0 Added the `isModule` parameter. - */ - CIQ.loadScript = function (scriptName, cb, isModule) { - if (!CIQ.loadedScripts) CIQ.loadedScripts = {}; - if (CIQ.loadedScripts[scriptName]) { - if (cb) cb(); - return; - } - var script = document.createElement("SCRIPT"); - if (isModule) { - script.type = "module"; - script.crossOrigin = "use-credentials"; - } else { - script.async = true; - } - script.onload = function () { - CIQ.loadedScripts[scriptName] = true; - if (cb) cb(); - }; - var uniqueName = scriptName; - // Use the epoch to create a unique query string, which will force the browser to reload - if (uniqueName.indexOf("?") == -1) { - uniqueName = uniqueName + "?" + Date.now(); - } else { - uniqueName = uniqueName + "&" + Date.now(); - } - script.src = uniqueName; - var s = document.getElementsByTagName("script")[0]; - if (!s) document.body.append(script); - else s.parentNode.insertBefore(script, s.nextSibling); - }; - - /** - * Loads a stylesheet. - * @param {string} stylesheet Name of stylesheet file. - * @param {Function} cb Function to call when the stylesheet is fully loaded - * @since 2016-03-11 - * @memberof CIQ - */ - CIQ.loadStylesheet = function (stylesheet, cb) { - var lnk = document.createElement("link"); - lnk.rel = "stylesheet"; - lnk.type = "text/css"; - lnk.media = "screen"; - lnk.href = - stylesheet + (stylesheet.indexOf("?") === -1 ? "?" : "&") + Date.now(); - lnk.onload = function () { - if (this.loaded) return; //undocumented IE Edge bug, css files load twice. This to prevent double-triggering of onload, which may load html file twice. - this.loaded = true; - if (cb) cb(); - }; - var links = document.getElementsByTagName("link"); - var lastLink = links[links.length - 1]; - if (!lastLink) document.head.append(lnk); - else lastLink.parentNode.insertBefore(lnk, lastLink.nextSibling); - }; - - /** - * Loads a feature function widget. Feature function widgets consist of a CSS file, a - * JavaScript file, and an HTML file. - * - * Use this function to dynamically load content and functionality. - * - * @param {string} widget Name of the widget to load. The widget's JavaScript, CSS, and HTML - * files should have this name. - * @param {HTMLElement} el Element to which to append the UI content. The default is - * `document.body`. - * @param {function} cb Function to call when the widget is fully loaded. - * @param {boolean} isModule When true, the script loads a module. - * - * @memberof CIQ - * @since - * - 6.1.0 Added the `el` parameter. - * - 8.0.0 Added the `isModule` parameter. - */ - CIQ.loadWidget = function (widget, el, cb, isModule) { - if (!el || typeof el == "function") { - cb = el; // backward compatibility - el = document.body; - } - CIQ.loadStylesheet(widget + ".css", function () { - CIQ.loadUI(widget + ".html", el, function (err) { - if (err) cb(err); - else CIQ.loadScript(widget + ".js", cb, isModule); - }); - }); - }; - - /** - * Checks to see if the enabled plugins are done dynamically loading. - * @param {array} plugins An array of strings that define which plugins to check - * The plugin names provided must match the following format: if cq-scriptiq is enabled, 'scriptiq' is the plugin name entered into the array - * @param {Function} cb Function to call when all the plugins are fully loaded - * @memberof CIQ - * @since 6.1.0 - */ - CIQ.waitForPlugins = function (plugins, cb) { - var numPluginsLoaded = 0; - var numPlugins = plugins.length; - if (!numPlugins) { - cb(); - return; - } - - for (var i = 0; i < numPlugins; i++) { - var tagName = "cq-" + plugins[i]; - var element = document.getElementsByTagName(tagName)[0]; - if (element && element.hasAttribute("loaded")) { - numPluginsLoaded++; - } - } - - if (numPlugins !== numPluginsLoaded) { - return setTimeout(function () { - CIQ.waitForPlugins(plugins, cb); - }, 0); - } - - cb(); - }; - - /** - * Adds style content to a document if it has not been added already. - * - * @param {string} content Style content. - * @param {string} path Unique identifier, which prevents duplicate style inclusions. - * - * @memberof CIQ - * @since 8.0.0 - */ - CIQ.addInternalStylesheet = function (content, path = "") { - if (!content) return; - if (content.default) content = content.default; - if (typeof content !== "string") return; - if (path && document.querySelector('style[path="' + path + '"]')) return; - const el = document.createElement("style"); - el.setAttribute("type", "text/css"); - el.setAttribute("path", path); - el.innerText = content; - document.head.appendChild(el); - }; - - }; - - - let __js_core_engine_accessory_ = (_exports) => { - - - var CIQ = _exports.CIQ; - - /** - * Registers the Chart controls and attaches event handlers to the zoom and home controls. - * @private - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.registerHTMLElements = function () { - const c = this.chart.container; - for (let control in CIQ.ChartEngine.htmlControls) { - if ( - typeof this.chart[control] == "undefined" && - typeof this.controls[control] == "undefined" - ) { - if (!this.allowZoom && control == "chartControls") continue; - let el = c.querySelector("." + control); - if (el) { - this.chart[control] = el; - this.controls[control] = el; - } else { - const rawHTML = CIQ.ChartEngine.htmlControls[control]; - if (!rawHTML) continue; - const div = document.createElement("DIV"); - div.innerHTML = rawHTML; - el = div.firstChild; - c.appendChild(el); - this.chart[control] = el; - this.controls[control] = el; - el.classList.add(control); - } - } - } - const { chartControls, home } = this.controls; - if (chartControls) { - const zoomIn = chartControls.querySelector(".stx-zoom-in"); - const zoomOut = chartControls.querySelector(".stx-zoom-out"); - - CIQ.safeClickTouch( - zoomIn, - (function (self) { - return function (e) { - if (self.allowZoom) self.zoomIn(e); - e.stopPropagation(); - }; - })(this) - ); - CIQ.safeClickTouch( - zoomOut, - (function (self) { - return function (e) { - if (self.allowZoom) self.zoomOut(e); - e.stopPropagation(); - }; - })(this) - ); - if (!CIQ.touchDevice) { - this.makeModal(zoomIn); - this.makeModal(zoomOut); - } - } - if (home) { - CIQ.safeClickTouch( - home, - (function (self) { - return function (e) { - e.stopPropagation(); - // If we are not in historical mode then scroll home - if (!self.isHistoricalMode()) { - self.home({ animate: true }); - return; - } - // If in historical mode delete any range the chart might have to prevent setting it again and call loadChart - // This will be fast than scrolling and paginating forward as the chart progresses towards the current day - delete self.layout.range; - self.loadChart(self.chart.symbol, function () { - self.home({ animate: false }); - }); - }; - })(this) - ); - if (!CIQ.touchDevice) { - this.makeModal(home); - } - } - }; - - /** - * Returns the chart to the home position, where the most recent tick is on the right side of the screen. - * - * By default the home() behavior is to maintain the white space currently on the right side of the chart. - * To align the chart to the right edge instead, set the white space to 0 by calling: `stxx.home({whitespace:0});` or `stxx.home({maintainWhitespace:false});` - * - * If you want to home the chart and also do a full reset of both the x and y axis zoom levels so they revert to the initial default settings, execute this: - * ``` - * stxx.setCandleWidth(8);stxx.home(0); - * ``` - * - * Keep in mind that certain floating labels, such as the `roundRectArrow` will prevent the chart from being flush to the right edge even if the white space is 0. - * This is to prevent bars from being obstructed by the protruding portion of the label. - * - * See {@link CIQ.ChartEngine#getLabelOffsetInPixels} and {@link CIQ.ChartEngine#yaxisLabelStyle} for more details. - * - * Used by CIQ.ChartEngine.htmlControls.home. - * - * @param {object} params Object containing the following keys: - * @param {boolean} [params.animate = false] Set to true to animate a smooth scroll to the home position. - * @param {boolean} [params.maintainWhitespace = true] Set to `true` to maintain the currently visible white space on the right of the chart, or to `false` to align to the right edge. - * @param {number} [params.whitespace = 0] Override to force a specific amount of whitespace on the right of the chart. - * This will take precedence over `params.maintainWhitespace` - * @param {CIQ.ChartEngine.Chart} [params.chart] Chart to scroll home. If not defined, all chart objects will be returned to the home position. - * @memberof CIQ.ChartEngine - * @example - * stxx.home({maintainWhitespace:false}); - */ - CIQ.ChartEngine.prototype.home = function (params) { - this.swipe.amplitude = 0; - var layout = this.layout; - if (typeof params != "object") { - // backward compatibility - params = { - maintainWhitespace: params - }; - } - - function resetPanelZooms(stx) { - for (var p in stx.panels) { - var yAxes = stx.panels[p].yaxisLHS.concat(stx.panels[p].yaxisRHS); - for (var a = 0; a < yAxes.length; a++) - stx.calculateYAxisMargins(yAxes[a]); - } - } - function scrollToCallback(self, chart, exactScroll) { - return function () { - resetPanelZooms(self); - chart.scroll = exactScroll; - self.draw(); - }; - } - if (typeof params.maintainWhitespace == "undefined") - params.maintainWhitespace = true; // maintain the whitespace unless set to false - - this.cancelTouchSingleClick = true; - if (!this.chart.dataSet || !this.chart.dataSet.length) { - // to clear out anything that may have been on the screen. Otherwise we still show stale data. - this.draw(); - return; - } - this.micropixels = 0; - var barsDisplayedOnScreen = Math.floor(this.chart.width / layout.candleWidth); - for (var chartName in this.charts) { - var chart = this.charts[chartName]; - if (params.chart && params.chart != chart) continue; - - var whitespace = 0; - if (params.maintainWhitespace && this.preferences.whitespace >= 0) - whitespace = this.preferences.whitespace; - if (params.whitespace || params.whitespace === 0) - whitespace = params.whitespace; - var leftMargin = this.getLabelOffsetInPixels(chart, layout.chartType); - if (leftMargin > whitespace) whitespace = leftMargin; - - var exactScroll = Math.min(barsDisplayedOnScreen, chart.dataSet.length); // the scroll must be the number of bars you want to see. - if (this.chart.allowScrollPast) exactScroll = barsDisplayedOnScreen; // If whitespace allowed on left of screen - this.micropixels = - this.chart.width - exactScroll * layout.candleWidth - whitespace; - this.preferences.whitespace = whitespace; - while (this.micropixels > layout.candleWidth) { - // If micropixels is larger than a candle then scroll back further - exactScroll++; - this.micropixels -= layout.candleWidth; - } - while (this.micropixels < 0) { - exactScroll--; - this.micropixels += layout.candleWidth; - } - this.micropixels -= layout.candleWidth; - exactScroll++; - if (!this.mainSeriesRenderer || !this.mainSeriesRenderer.standaloneBars) - this.micropixels += layout.candleWidth / 2; // bar charts display at beginning of candle - - if (params.animate) { - var self = this; - this.scrollTo( - chart, - exactScroll, - scrollToCallback(self, chart, exactScroll) - ); - } else { - chart.scroll = exactScroll; - resetPanelZooms(this); - } - } - this.draw(); - }; - - /** - * INJECTABLE - * - * This method calls {@link CIQ.ChartEngine#updateFloatHRLabel} to draw the label that floats along the Y axis with the - * current price for the crosshair. - * It also fills the date in the "stxx.controls.floatDate" (Style: `stx-float-date`) div which floats along the X axis. - * This is an appropriate place to inject an append method for drawing a heads up display if desired. - * - * You can use {@link CIQ.ChartEngine.XAxis#noDraw} and {@link CIQ.ChartEngine.YAxis#noDraw} to hide the floating labels and axis. - * - * It uses {@link CIQ.displayableDate} to format the floating label over the x axis, which can be overwritten as needed to achieve the desired results. - * - * @memberof CIQ.ChartEngine.AdvancedInjectable# - * @alias headsUpHR - * @since 09-2016-19 Only year and month will be displayed in monthly periodicity. - */ - CIQ.ChartEngine.prototype.headsUpHR = function () { - if (this.runPrepend("headsUpHR", arguments)) return; - var panel = this.currentPanel; - if (!panel) return; - var chart = panel.chart; - - this.updateFloatHRLabel(panel); - var floatDate = this.controls.floatDate; - function setFloatDate(val) { - CIQ.efficientDOMUpdate(floatDate, "innerHTML", val); - } - - if (floatDate && !chart.xAxis.noDraw) { - var bar = this.barFromPixel(this.cx); - var prices = chart.xaxis[bar]; - if (prices && prices.DT) { - setFloatDate(CIQ.displayableDate(this, chart, prices.DT)); - } else if (prices && prices.index) { - setFloatDate(prices.index); - } else { - setFloatDate(""); // there is no date to display - } - } - - this.runAppend("headsUpHR", arguments); - }; - - /** - * Sets the chart into a modal mode. Crosshairs are hidden and the chart will not respond to click or mouse events. Call this - * for instance if you are enabling a dialog box and don't want errant mouse activity to affect the chart. - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.modalBegin = function () { - this.openDialog = "modal"; - this.undisplayCrosshairs(); - }; - - /** - * Ends modal mode. See {@link CIQ.ChartEngine#modalBegin} - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.modalEnd = function () { - this.cancelTouchSingleClick = true; - this.openDialog = ""; - this.doDisplayCrosshairs(); - }; - - /** - * Convenience function to attach a modal on mouse events - * @param {HTMLElement} Element to attach the modal to - * @private - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.makeModal = function (element) { - var self = this; - element.onmouseover = function (event) { - self.modalBegin(); - }; - element.onmouseout = function (event) { - self.modalEnd(); - }; - }; - - /** - * INJECTABLE - * - * Updates the position of the stxx.controls.floatDate element ( Style: `stx-float-date` ) and calls {@link CIQ.ChartEngine.AdvancedInjectable#headsUpHR} to display the crosshairs labels on both x and y axis. - * A timer is used to prevent this operation from being called more frequently than once every 100 milliseconds in order to - * improve performance during scrolling. - * @memberof CIQ.ChartEngine.AdvancedInjectable# - * @alias updateChartAccessories - */ - CIQ.ChartEngine.prototype.updateChartAccessories = function () { - if (this.accessoryTimer !== null) clearTimeout(this.accessoryTimer); - if (!CIQ.ChartEngine.drawingLine && CIQ.touchDevice) { - if (new Date().getTime() - this.lastAccessoryUpdate < 100) { - this.accessoryTimer = setTimeout( - (function (stx) { - return function () { - stx.updateChartAccessories(); - }; - })(this), - 10 - ); - return; - } - } - if (!this.chart.dataSet) return; - if (this.runPrepend("updateChartAccessories", arguments)) return; - this.accessoryTimer = null; - this.lastAccessoryUpdate = new Date().getTime(); - var floatDate = this.controls.floatDate; - if (floatDate) { - var panel = this.currentPanel; - if (!panel) panel = this.chart.panel; - if (panel) { - var chart = panel.chart; - var bottom = - this.xAxisAsFooter === true - ? 0 - : this.chart.canvasHeight - panel.chart.bottom; - var halfLabelWidth = floatDate.offsetWidth / 2 - 0.5; - var l = this.pixelFromTick(this.crosshairTick, chart) - halfLabelWidth; - if (l < 0) l = 0; - else if (l > this.width - 2 * halfLabelWidth - 1) - l = this.width - 2 * halfLabelWidth - 1; - CIQ.efficientDOMUpdate(floatDate.style, "left", l + "px"); - CIQ.efficientDOMUpdate(floatDate.style, "bottom", bottom + "px"); - } - } - this.positionCrosshairsAtPointer(); - this.headsUpHR(); - this.runAppend("updateChartAccessories", arguments); - }; - - /** - * Positions a "sticky" (a tooltip element). It is positioned relative to the cursor but so that it is always available and never - * accidentally tappable on a touch device. - * @param {HTMLElement} m The sticky - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.positionSticky = function (m) { - var top = Math.max(this.cy - m.offsetHeight - 60, 0); - var right = Math.min( - this.chart.canvasWidth - (this.cx - 50), - this.chart.canvasWidth - m.offsetWidth - ); - m.style.top = top + "px"; - m.style.right = right + "px"; - }; - - /** - * Displays the "sticky" (tooltip element). The sticky should be in `CIQ.ChartEngine.controls.mSticky`. - * - * To disable stickies, set that element to null. See {@link CIQ.ChartEngine.htmlControls}. - * - * To customize, see the [Using and Customizing Drawing Tools](tutorial-Using%20and%20Customizing%20Drawing%20Tools.html#customSticky) tutorial. - * - * @param {object} params Optional arguments to pass into the function. - * @param {string} [params.message] The message to display in the sticky. - * @param {string} [params.backgroundColor] The background color for the sticky (the foreground color is selected automatically). - * @param {boolean} [params.forceShow] If true, always shows the sticky (as opposed to only on hover). - * @param {boolean} [params.noDelete] If true, hides the delete instructions/button. - * @param {boolean} [params.noEdit] If true, hides the edit instructions/button. - * @param {string} [params.type] Set to "study","drawing","series", or whatever causes the sticky to be displayed. - * @param {function} [params.positioner] Sets custom positioning behavior for the sticky. Called with `Function.prototype.call()`, - * specifying the engine instance as context. Called with one argument, which is a reference to the sticky element. - * @memberof CIQ.ChartEngine - * @since - * - 6.0.0 Consolidated arguments into the `params` object. - * - 6.3.0 Added the `noEdit` parameter. - * - 7.4.0 Added the `positioner` parameter. - */ - CIQ.ChartEngine.prototype.displaySticky = function (params) { - var m = this.controls.mSticky; - if (!m) return; - var mi = m.querySelector(".mStickyInterior"); - if (!mi) return; - var overlayTrashCan = m.querySelector(".overlayTrashCan"); - var overlayEdit = m.querySelector(".overlayEdit"); - var mouseDeleteInstructions = m.querySelector(".mouseDeleteInstructions"); - var longPressText = m.querySelector(".stickyLongPressText"); - mouseDeleteInstructions.classList.remove("no_edit"); - // backwards compatibility: - if (!params || typeof params != "object") - params = { - message: arguments[0], - backgroundColor: arguments[1], - forceShow: arguments[2], - noDelete: arguments[3], - type: arguments[4] - }; - var message = params.message, - backgroundColor = params.backgroundColor, - forceShow = params.forceShow, - noDelete = params.noDelete, - noEdit = params.noEdit, - type = params.type; - if (!forceShow && !message) { - mi.innerHTML = ""; - m.style.display = "none"; - if (overlayTrashCan) overlayTrashCan.style.display = "none"; - if (overlayEdit) overlayEdit.style.display = "none"; - if (mouseDeleteInstructions) mouseDeleteInstructions.style.display = "none"; - if (longPressText) longPressText.style.display = "none"; - } else { - if (!message) message = ""; - var defaultColor = this.defaultColor; - if (backgroundColor == "auto") backgroundColor = defaultColor; - if (forceShow && !message) { - mi.style.backgroundColor = ""; - mi.style.color = ""; - mi.style.display = "none"; - } else if (backgroundColor) { - mi.style.backgroundColor = backgroundColor; - mi.style.color = CIQ.isTransparent(backgroundColor) - ? defaultColor - : CIQ.chooseForegroundColor(backgroundColor); - mi.style.display = "inline-block"; - } else { - mi.style.backgroundColor = ""; - mi.style.color = ""; - mi.style.display = "inline-block"; - } - mi.innerHTML = message; - var rtClick = m.querySelector(".mStickyRightClick"); - rtClick.className = "mStickyRightClick"; //reset - if (type) rtClick.classList.add("rightclick_" + type); - rtClick.style.display = ""; - m.style.display = "inline-block"; - var draggableObject = this.highlightedDraggable; // set by findHighlights - if ( - !draggableObject || - (draggableObject && - draggableObject.undraggable && - draggableObject.undraggable(this)) - ) { - longPressText.style.display = "none"; - } - if ( - noDelete || - this.bypassRightClick === true || - this.bypassRightClick[type] - ) { - rtClick.style.display = "none"; - } else if (this.highlightViaTap || this.touches.length) { - if (overlayTrashCan) overlayTrashCan.style.display = "inline-block"; - if (overlayEdit && !noEdit) overlayEdit.style.display = "inline-block"; - if (mouseDeleteInstructions) - mouseDeleteInstructions.style.display = "none"; - if (longPressText) longPressText.style.display = "none"; - m.classList[message === "" ? "add" : "remove"]("hide"); - } else { - if (noEdit) mouseDeleteInstructions.classList.add("no_edit"); - if (mouseDeleteInstructions) { - mouseDeleteInstructions.style.display = "block"; - } - if (longPressText) { - longPressText.style.display = "none"; - var drag = this.preferences.dragging; - if (drag && params.panel && !params.panel.noDrag) { - if ((drag === true || drag.study) && type == "study") - longPressText.style.display = "block"; - else if ((drag === true || drag.series) && type == "series") - longPressText.style.display = "block"; - } - } - } - - var stickyType = type || "default"; - m.setAttribute("cq-sticky-type", stickyType); - - var positionSticky = params.positioner || this.positionSticky; - positionSticky.call(this, m); - } - }; - - /** - * Adds a message to the chart. - * - * Creates a `div` containing a text message. Appends the `div` to the - * - * CIQ.ChartEngine.htmlControls.notificationTray. - * - * Notifications can be interactive (see the `callback` and `dismissalListeners` parameters), - * and they can be queried by their names, which are set as class names on the - * notification `div`. - * - * @param {string} name The name of the notification, which is added to the class list of the - * notification `div`. - * @param {string} message Text to display in the notification `div`. - * @param {object} [params] Configuration parameters. - * @param {function} [params.callback] Added to the notification `div` as a listener for the - * "pointer up" event. - * @param {Array} [params.dismissalListeners] Array of event listeners added to the - * notification. - * @param {string} params.dismissalListeners.type The listener event type. See - * {@link CIQ.ChartEngine#addEventListener}. - * @param {function} params.dismissalListeners.callback The listener callback function. - * - * @memberof CIQ.ChartEngine - * @since 8.0.0 - */ - CIQ.ChartEngine.prototype.displayNotification = function ( - name, - message, - params = {} - ) { - if (!this.controls.notificationTray) return; - - const { callback, dismissalListeners } = params; - const notificationTray = this.controls.notificationTray; - let fragment = notificationTray - .querySelector("template") - .content.cloneNode(true); - const notification = fragment.firstElementChild; - - notification.className = name; - notification.querySelector(".message").textContent = message; - - if (callback) { - // iOS version < 13.2 and some older browsers don't support pointer events. - // Fallback to touch events in these cases. - let leaveHandler = window.PointerEvent ? "pointerup" : "touchend"; - notification.handler = notification.addEventListener( - leaveHandler, - callback - ); - } - - if (dismissalListeners) { - notification.listeners = {}; - dismissalListeners.forEach((listener) => { - notification.listeners[name] = this.addEventListener( - listener.type, - listener.callback - ); - }); - } - - this.makeModal(notification); - - notificationTray.appendChild(notification); - }; - - /** - * Removes a notification from the - * - * CIQ.ChartEngine.htmlControls.notificationTray. - * - * @param {string} name The name of the notification that is removed. - * - * @memberof CIQ.ChartEngine - * @since 8.0.0 - */ - CIQ.ChartEngine.prototype.removeNotification = function (name) { - if (!this.controls.notificationTray) return; - - const notificationTray = this.controls.notificationTray; - let notification = notificationTray.querySelector(`.${name}`); - - if (notification) { - if (notification.handler) - notification.removeEventListener(notification.handler); - if (notification.listeners) { - for (const listener in notification.listeners) { - this.removeEventListener(notification.listeners[listener]); - } - } - this.modalEnd(); - notificationTray.removeChild(notification); - } - }; - - /** - * INJECTABLE - * - * Sets the innerHTML value of the `.mMeasure` HTML DOM Node to contain a measurement (price differential and bars/line distance), usually when a user hovers over a drawing. - * It is also used to display measurement as a drawing is being created or when using the 'Measure' tool. - * - * It also sets `this.controls.mSticky` with the measurement and displays it on `mSticky` on hover. - * - * Example: 23.83 (-12%) 11 Bars - * - * It requires the UI to include the following div: ```
``` - * - * It can be styled via CSS. See example. - * - * @param {number} price1 Beginning price of the drawing - * @param {number|boolean} price2 Ending price of the drawing, pass false if you want to skip price and percentage display - * @param {number} tick1 Beginning tick of the drawing - * @param {number|boolean} tick2 Ending tick of the drawing, pass false if you want to skip tick count display - * @param {boolean} hover True to turn on the measurement, false to turn it off - * @param {string} [name] Name of drawing, not used by default but passed into injection - * @memberof CIQ.ChartEngine - * @since - * - 4.0.0 Added name argument. - * - 6.0.0 Allow price2 and tick2 to be false, skipping the respective display. - * @example - * // Measuring tool styling CSS sample - * .currentMeasure { - * text-align: left; - * display: inline-block; - * margin: 4px 0 0 20px; - * height: 20px; - * line-height: 20px; - * } - - * .mMeasure { - * display: inline-block; - * margin: 0 0 0 0; - * overflow: hidden; - * text-overflow: ellipsis; - * white-space: nowrap; - * width:140px; - * } - * @example - * // This is an example of the framework to use for writing a prepend to further manipulate/display the measurements - * CIQ.ChartEngine.prototype.prepend("setMeasure",function() { - * - * var m = document.querySelector(".mMeasure"); - * - * if (!m) return; // Can't show a measurement if the div is not present. - * - * // Add your logic to manage the display of the measurements (price1, price2, tick1, tick2). - * //***************************************** - * var message = 'blah measurement'; - * //***************************************** - * - * m.innerHTML = message; - * - * if (this.activeDrawing) return; // Don't show measurement Sticky when in the process of drawing. - * - * m = this.controls.mSticky; - * if (m) { - * var mStickyInterior = m.querySelector(".mStickyInterior"); - * if (hover) { - * m.style.display = "inline-block"; - * mStickyInterior.style.display = "inline-block"; - * if(price1) { - * mStickyInterior.innerHTML = message; - * } - * this.positionSticky(m); - * } else { - * m.style.display = "none"; - * mStickyInterior.innerHTML = ""; - * } - * } - * - * //return true; // If you don't want to continue into the regular function. - * //return false; // If you want to run through the standard function once you are done with your custom code. - * }); - */ - CIQ.ChartEngine.prototype.setMeasure = function ( - price1, - price2, - tick1, - tick2, - hover, - name - ) { - if (this.runPrepend("setMeasure", arguments)) return; - var m = (this.drawingContainer || document).querySelector(".mMeasure"); - var message = ""; - if (!price1 && price1 !== 0) { - if (!this.anyHighlighted && this.currentVectorParameters.vectorType === "") - this.clearMeasure(); - } else { - if (price2 !== false) { - var distance = - Math.round(Math.abs(price1 - price2) * this.chart.roundit) / - this.chart.roundit; - distance = distance.toFixed(this.chart.yAxis.printDecimalPlaces); - if (this.internationalizer) { - message += this.internationalizer.numbers.format(distance); - } else { - message += distance; - } - var pct; - if (price1 > 0 && price2 > 0) { - pct = (price2 - price1) / price1; - if (Math.abs(pct) > 0.1) { - pct = Math.round(pct * 100); - } else if (Math.abs(pct) > 0.01) { - pct = Math.round(pct * 1000) / 10; - } else { - pct = Math.round(pct * 10000) / 100; - } - if (this.internationalizer) { - pct = this.internationalizer.percent.format(pct / 100); - } else { - pct = pct + "%"; - } - message += " (" + pct + ")"; - } - } - if (tick2 !== false) { - var ticks = Math.abs(tick2 - tick1); - ticks = Math.round(ticks) + 1; - var barsStr = this.translateIf("Bars"); - message += " " + ticks + " " + barsStr; - } - - if (m) m.innerHTML = message; - } - - if (this.activeDrawing) return; // Don't show measurement Sticky when in the process of drawing - m = this.controls.mSticky; - if (m) { - var mStickyInterior = m.querySelector(".mStickyInterior"); - if (hover) { - m.style.display = "inline-block"; - mStickyInterior.style.display = "inline-block"; - if (price1 || price1 === 0) { - mStickyInterior.innerHTML = message; - } - m.classList[message === "" ? "add" : "remove"]("hide"); - this.positionSticky(m); - } else { - m.style.display = "none"; - mStickyInterior.innerHTML = ""; - } - } - this.runAppend("setMeasure", arguments); - }; - - /** - * Clears the innerHTML value of the `.mMeasure` HTML DOM Node. - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.clearMeasure = function () { - var m = (this.drawingContainer || document).querySelector(".mMeasure"); - if (m) m.innerHTML = ""; - }; - - /** - * Effects a zoom from either zoomIn() or zoomOut(). Called from an EaseMachine - * @param {number} candleWidth The new candleWidth - * @param {CIQ.ChartEngine.Chart} chart The chart to center - * @memberof CIQ.ChartEngine - * @since - * - 4.0.0 Will maintain tick position near the cursor if CIQ.ChartEngine.preferences.zoomAtCurrentMousePosition is `true`. - * - 4.1.0 Will keep left edge stable and zoom to the right when white space is present on the left. - */ - CIQ.ChartEngine.prototype.zoomSet = function (candleWidth, chart) { - candleWidth = this.constrainCandleWidth(candleWidth); - if (this.chart.tempCanvas.style.display != "none") - CIQ.clearCanvas(this.chart.tempCanvas, this); - var mainSeriesRenderer = this.mainSeriesRenderer || {}; - if (!mainSeriesRenderer.params || !mainSeriesRenderer.params.volume) { - var maintainTick; - if ( - this.preferences.zoomAtCurrentMousePosition && - this.zoomInitiatedByMouseWheel && - this.crosshairTick < chart.dataSet.length - ) { - // keep the bar near the cursor stable - // at chart load it is possible for this.crosshairTick to be null (refresh while cursor is in the xAxis margin) - maintainTick = this.crosshairTick || this.tickFromPixel(this.cx, chart); - } else if (this.isHome()) { - // keep right edge stable and zoom to the left - maintainTick = chart.dataSet.length - 1; - } else if (this.chart.scroll > this.chart.dataSet.length) { - // keep left edge stable and zoom to the right - maintainTick = 0; - } else if (this.grabMode == "zoom-x") { - // keep right edge stable and zoom to the left - maintainTick = this.tickFromPixel(this.chart.width, chart); - } else { - // keep the center bar in the center and zoom equally left and right - maintainTick = this.tickFromPixel(this.chart.width / 2, chart); - } - if (this.animations.zoom.hasCompleted) { - this.zoomInitiatedByMouseWheel = false; - } - // this is the code that keeps the chart's position stable. - // Bypassing this code will cause the chart's left position to remain stable - // which is really the only way to get a smooth zoom for variable width candles (because the act of scrolling inherently changes the number of candles that fit on the screen) - var distanceFromFront = chart.dataSet.length - 1 - maintainTick; - var oldScroll = chart.scroll; - chart.scroll = - Math.round( - (this.pixelFromTick(maintainTick, chart) - chart.left) / candleWidth - ) + - 1 + - distanceFromFront; - this.micropixels += - (oldScroll - distanceFromFront) * this.layout.candleWidth - - (chart.scroll - distanceFromFront) * candleWidth; - } - this.setCandleWidth(candleWidth); - chart.spanLock = false; - this.draw(); - this.doDisplayCrosshairs(); - this.updateChartAccessories(); - }; - - }; - - - let __js_core_engine_baselines_ = (_exports) => { - - - var CIQ = _exports.CIQ; - /** - * A reference to the renderer of the baseline whose handle is currently selected. - * - * The baseline handle can be accessed from {@link CIQ.ChartEngine#baselineHelper}. - * - * @type {CIQ.Renderer} - * @memberof CIQ.ChartEngine - * @since 8.2.0 - */ - CIQ.ChartEngine.prototype.currentBaseline = null; - - /** - * Baseline helper for the chart engine. - * - * Maps renderers to value objects that contain data related to the baseline, including the - * baseline handle (a reference to the DOM element that functions as the handle). - * - * @type {Map} - * @memberof CIQ.ChartEngine - * @since 8.2.0 - */ - CIQ.ChartEngine.prototype.baselineHelper = null; - - CIQ.ChartEngine.helpersToRegister.push(function (stx) { - stx.baselineHelper = new Map(); - }); - - /** - * Adds an entry to {@link CIQ.ChartEngine#baselineHelper} with `renderer` as the key and a - * dynamically created object as the value. The value object contains data related to the - * baseline. - * - * If the renderer is the renderer of the main series, sets the handle property of the value - * object to CIQ.ChartEngine.htmlControls[`baselineHandle`]; otherwise, - * creates a baseline handle DOM element and adds a reference to the DOM element to the value - * object and to the chart controls object, {@link CIQ.ChartEngine.htmlControls}. The handle is - * accessed in the chart controls object by a property name that is the concatenation of the - * renderer name and "cq-baseline-handle", for example: - * ``` - * stxx.controls[`${renderer.params.name} cq-baseline-handle`]; - * ``` - * - * @param {CIQ.Renderer} renderer The renderer to register as the key of the baseline helper. - * - * @memberof CIQ.ChartEngine - * @since 8.2.0 - */ - CIQ.ChartEngine.prototype.registerBaselineToHelper = function (renderer) { - if (!renderer.params.baseline) return; - const { baselineHelper } = this; - const self = this; - if (!baselineHelper.has(renderer)) { - const { name } = renderer.params; - let defaultHandle = this.controls.baselineHandle; - baselineHelper.set(renderer, { - styleCache: null, - display: false, - handle: - name === "_main_series" && defaultHandle - ? defaultHandle - : createHandle(name) - }); - } - - function createHandle(name) { - name = name.replace(" ", "_"); - const handle = document.createElement("cq-baseline-handle"); - handle.classList.add("stx-baseline-handle", name); - self.container.append(handle); - self.controls[`${name} cq-baseline-handle`] = handle; - return handle; - } - }; - - /** - * Removes a renderer from {@link CIQ.ChartEngine#baselineHelper}. - * - * If the renderer is not the renderer of the main series, removes the baseline handle associated - * with the renderer from the chart controls object, {@link CIQ.ChartEngine.htmlControls} (see - * also {@link CIQ.ChartEngine#registerBaselineToHelper}). - * - * @param {CIQ.Renderer} renderer The renderer to remove from the baseline helper. - * - * @memberof CIQ.ChartEngine - * @since 8.2.0 - */ - CIQ.ChartEngine.prototype.removeBaselineFromHelper = function (renderer) { - const { baselineHelper } = this; - if (baselineHelper.has(renderer)) { - const name = renderer.params.name.replace(" ", "_"); - if (name !== "_main_series") { - let handle = baselineHelper.get(renderer).handle; - delete this.controls[`${name} cq-baseline-handle`]; - this.container.removeChild(handle); - } - baselineHelper.delete(renderer); - } - }; - - /** - * Checks an emitted event to determine whether a baseline handle DOM element is the event target - * or is in the - * - * composed path of the event. If so, sets {@link CIQ.ChartEngine#currentBaseline} to the - * renderer of the baseline positioned by the handle. - * - * @param {Event} e The event that is checked to determine whether a baseline handle is the event - * target or is in the propagation path of the event. - * @param {boolean} grabStart If true (and a baseline handle is the event target or is in the - * event path), baseline repositioning is initiated. - * @return {boolean} True if a baseline handle is the event target or is in the path of the event, - * otherwise false. - * - * @memberof CIQ.ChartEngine - * @since 8.2.0 - */ - CIQ.ChartEngine.prototype.findBaselineHandle = function (e, grabStart) { - for (const baseline of this.baselineHelper) { - const [renderer, values] = baseline; - const { handle } = values; - if ( - e.target === handle || - (e.composedPath && e.composedPath().includes(handle)) - ) { - if (grabStart) { - this.repositioningBaseline = { lastDraw: Date.now(), handle, renderer }; - handle.classList.add("stx-grab"); - } - this.currentBaseline = renderer; - return true; - } - } - return false; - }; - - /** - * Sets `baseline.actualLevel` for any line renderers that are attached to the chart. (See the - * `baseline` parameter of {@link CIQ.Renderer.Lines}, which may be type - * {@link CIQ.ChartEngine.Chart#baseline}.) - * - * **Note:** Does not set - * CIQ.ChartEngine.Chart#baseline[`actualLevel`]; that is done in - * {@link CIQ.ChartEngine.AdvancedInjectable#createDataSegment}. - * - * @param {CIQ.ChartEngine.Chart} chart Chart for which the renderer baseline levels are set. - * @memberof CIQ.ChartEngine - * @since 8.1.0 - */ - CIQ.ChartEngine.prototype.setBaselines = function (chart) { - if (!chart) chart = this.chart; - const self = this; - const { baselineHelper } = this; - baselineHelper.forEach(function (values, renderer) { - let { baseline } = renderer.params; - const useMain = baseline === true; - if (useMain) baseline = chart.baseline; - let { defaultLevel, userLevel } = baseline; - const yAxis = renderer.getYAxis(self); - // When interacting with the chart, occasionally yAxis or panel parameter not up to date b/c it we are currently being modifying something. - // In this case return, to let the modifications finish and the final draw call will correct everything. - if (!yAxis) return; - const yBaselineRenderer = self.getYAxisBaselineRenderer(yAxis); - // Default to the first series on the active renderer of a yAxis - const id = - yBaselineRenderer && - yBaselineRenderer != self.mainSeriesRenderer && - yBaselineRenderer.seriesParams.length && - yBaselineRenderer.seriesParams[0].id; - - baseline.actualLevel = - userLevel || userLevel === 0 ? userLevel : defaultLevel; - if (!baseline.actualLevel && baseline.actualLevel !== 0) - baseline.actualLevel = calculateActualLevel(id, useMain); - - values.display = yBaselineRenderer === renderer ? true : false; - baselineHelper.set(renderer, values); - }); - - function calculateActualLevel(id, useMain) { - const { dataSegment, dataSet, defaultPlotField } = chart; - let field = defaultPlotField; - if (!useMain) field = id; - let position = self.getFirstLastDataRecord(dataSegment, "tick").tick; - - while (true) { - const quote = dataSet[position]; - if (quote) { - if (!useMain || field != "Close") { - const q1 = dataSet[position - 1]; - if (q1 && (q1[field] || q1[field] === 0)) { - const q = q1[field]; - return typeof q === "object" ? q[defaultPlotField] : q; - } - } else if (quote.iqPrevClose || quote.iqPrevClose === 0) { - return quote.iqPrevClose; - } - } - position--; - if (position < 0) break; - } - } - }; - - /** - * Sets the userLevel of the baseline; that is, the position of the baseline as it being - * repositioned by the user (see CIQ.ChartEngine.Chart#baseline[`userLevel`]). - * - * @memberof CIQ.ChartEngine - * @private - * @since 8.2.0 - */ - CIQ.ChartEngine.prototype.setBaselineUserLevel = function () { - const { chart, currentPanel: panel } = this; - const { lastDraw, renderer } = this.repositioningBaseline; - - if (renderer.params.panel != panel.name) return; - - const { baseline: defaultBaseline } = chart; - const baseline = - typeof renderer.params.baseline === "object" - ? renderer.params.baseline - : defaultBaseline; - const rAxis = renderer.getYAxis(this); - const value = this.valueFromPixel( - this.backOutY(CIQ.ChartEngine.crosshairY), - panel, - rAxis - ); - - baseline.userLevel = this.adjustIfNecessary(panel, this.crosshairTick, value); - - if (Date.now() - lastDraw > 100) { - this.draw(); - this.repositioningBaseline.lastDraw = Date.now(); - } - }; - - /** - * Sets the minimum and maximum values for a y-axis based on the position of the baseline - * associated with the axis. - * - * @param {number[]} minMax A tuple representing the minimum and maximum values in `dataSegment`. - * @param {CIQ.ChartEngine.YAxis} yAxis The y-axis for which the minimum and maximum values are - * set. - * @return {number[]} A tuple representing the minimum and maximum values of `yAxis`. - * - * @memberof CIQ.ChartEngine - * @private - * @since 8.2.0 - */ - CIQ.ChartEngine.prototype.setBaselineMinMax = function (minMax, yAxis) { - const { baselineHelper, chart, repositioningBaseline } = this; - const { baseline: defaultBaseline, seriesRenderers } = chart; - const doTransform = chart.transformFunc && yAxis === chart.panel.yAxis; - - const baselineToDisplay = yAxis.renderers.find((name) => { - return baselineHelper.get(seriesRenderers[name]); - }); - - if (!baselineToDisplay) return minMax; // No baselines found - - let { baseline, type } = seriesRenderers[baselineToDisplay].params; - if (type === "mountain") return minMax; - - baseline = typeof baseline === "object" ? baseline : defaultBaseline; - let { actualLevel } = baseline; - if (actualLevel || actualLevel === 0) { - if (doTransform) - actualLevel = chart.transformFunc(this, chart, actualLevel); - const diff = Math.max(actualLevel - minMax[0], minMax[1] - actualLevel); - minMax[0] = repositioningBaseline ? yAxis.lowValue : actualLevel - diff; - minMax[1] = repositioningBaseline ? yAxis.highValue : actualLevel + diff; - } - return minMax; - }; - - /** - * Positions a baseline handle within the chart area. - * - * @param {CIQ.Renderer} renderer The renderer that renders the baseline. - * - * @memberof CIQ.ChartEngine - * @since 8.2.0 - */ - CIQ.ChartEngine.prototype.positionBaselineHandle = function (renderer) { - if (!this.manageTouchAndMouse) return; - const { baselineHelper, chart, panels } = this; - let { baseline, panel: panelName } = renderer.params; - const yAxis = renderer.params.yAxis || renderer.getYAxis(this); - let { display: displayed, handle, styleCache } = baselineHelper.get(renderer); - - if (baseline === true) baseline = chart.baseline; - if (baseline.userLevel === false || !displayed) { - handle.style.display = "none"; - return; - } - const panel = panels[panelName]; - const grabbed = handle.classList.contains("stx-grab"); - let display = "block"; - - let price = baseline.actualLevel; - if (chart.transformFunc) price = chart.transformFunc(this, chart, price); - if (price > yAxis.high) { - price = yAxis.high; - if (!grabbed) display = "none"; - } else if (price < yAxis.low) { - price = yAxis.low; - if (!grabbed) display = "none"; - } - - // If chart has been transformed, transform it back or it will be transformed twice! - if (chart.untransformFunc) price = chart.untransformFunc(this, chart, price); - - const basePixel = this.pixelFromPrice(price, panel, yAxis); - if (!styleCache) styleCache = getComputedStyle(handle); - const width = CIQ.stripPX(styleCache.width); - - let top = `${basePixel - CIQ.stripPX(styleCache.height) / 2}px`; - - let left; - let buffer = this.baselineHandleBuffer || 2; - let rightIndex = panel.yaxisRHS.indexOf(yAxis) + 1; - if (rightIndex) { - let pad = rightIndex === 1 ? buffer : buffer * rightIndex; - left = `${chart.right - width * rightIndex - pad}px`; - } else { - let leftIndex = panel.yaxisLHS.slice(0).reverse().indexOf(yAxis) + 1; - let pad = leftIndex === 1 ? buffer : buffer * leftIndex; - left = `${chart.left + width * leftIndex + pad - width}px`; - } - Object.assign(handle.style, { display, top, left }); - }; - - /** - * Gets the baseline renderer associated with a y-axis. - * - * Since a y-axis can only have one baseline associated with it, this function searches the - * renderers property of the axis, checking for the first renderer that matches an entry in - * {@link CIQ.ChartEngine#baselineHelper}. - * - * @param {CIQ.ChartEngine.YAxis} yAxis The y-axis whose list of renderers is checked for a - * baseline renderer. - * @return {CIQ.Renderer|null} The y-axis renderer that renders a baseline or, if a baseline - * renderer is not associated with the y-axis, null. - * - * @memberof CIQ.ChartEngine - * @since 8.2.0 - */ - CIQ.ChartEngine.prototype.getYAxisBaselineRenderer = function (yAxis) { - if (!yAxis.renderers.length) return null; - const { baselineHelper, chart } = this; - - let name = yAxis.renderers.find((name) => { - return baselineHelper.get(chart.seriesRenderers[name]); - }); - - if (!name) return null; - return chart.seriesRenderers[name]; - }; - - /** - * Gets the baseline object for a y-axis associated with a baseline. - * - * A y-axis can be associated with only one baseline; and so, can have only one baseline renderer - * and one baseline object. - * - * @param {CIQ.ChartEngine.YAxis} yAxis A y-axis associated with a baseline. - * @returns {object} The baseline object of the y-axis baseline renderer if the y-axis has a - * baseline renderer and the baseline parameter of the renderer is an object; otherwise, - * the default chart baseline object, {@link CIQ.ChartEngine.Chart#baseline}. - * - * @memberof CIQ.ChartEngine - * @since 8.2.0 - * - * @see {@link CIQ.ChartEngine#getYAxisBaselineRenderer} - */ - CIQ.ChartEngine.prototype.getYAxisBaseline = function (yAxis) { - const { baseline: defaultBaseline } = this.chart; - const baselineRenderer = this.getYAxisBaselineRenderer(yAxis); - - if (!baselineRenderer) return defaultBaseline; - const { baseline } = baselineRenderer.params; - return typeof baseline === "object" ? baseline : defaultBaseline; - }; - - }; - - - let __js_core_engine_chart_ = (_exports) => { - - - var CIQ = _exports.CIQ; - - /** - * Defines an object used for rendering a chart and is automatically created by the {@link CIQ.ChartEngine}. - * Chart objects contain the data and config for each chart but they don't actually exist on the screen until a panel is attached. - * A chart object is attached to both the main chart panel and any related study panels so they can share the same chart data. - * - * Example: stxx.panels['chart'].chart - * - * Example: stxx.chart (convenience shortcut for accessing the main chart object - same as above) - * - * Example stxx.panels['Aroon (14)'].chart - * - * @constructor - * @name CIQ.ChartEngine.Chart - */ - CIQ.ChartEngine.Chart = function () { - this.xAxis = new CIQ.ChartEngine.XAxis(); - this.yAxis = new CIQ.ChartEngine.YAxis(); - this.symbolObject = { symbol: null }; - this.series = {}; - this.seriesRenderers = {}; - this.xaxis = []; - this.state = {}; - this.endPoints = {}; - this.defaultChartStyleConfig = {}; - this.baseline = CIQ.clone(this.baseline); // copy from prototype - /** - * @type CIQ.ChartEngine.Panel - * @memberof CIQ.ChartEngine.Chart# - */ - this.panel = undefined; - }; - - CIQ.extend( - CIQ.ChartEngine.Chart.prototype, - { - /** - * The current symbol for the chart - * @type string - * @memberof CIQ.ChartEngine.Chart# - */ - symbol: null, - /** - * The current symbolObject for the chart. Generally this is simply `{symbol: symbol}`. - * This is initialized by {@link CIQ.ChartEngine#loadChart}. - * @type {object} - * @memberof CIQ.ChartEngine.Chart# - */ - symbolObject: { symbol: null }, - /** - * Set this to preset an alternate name for the symbol on the chart label and comparison legend. - * You can set `stxx.chart.symbolDisplay='yourName'; ` right before calling `loadChart()`. - * Alternatively, a good place to set it is in your fetch function, if using {@link quotefeed}. See example. - * @type string - * @default - * @memberof CIQ.ChartEngine.Chart# - * @example - * // on your initial data fetch call add the following - * params.stx.chart.symbolDisplay='yourName for '+params.symbol; - */ - symbolDisplay: null, - /** - * Contains information about the series that are associated with the chart. - * Series are additional data sets, such as used for comparison charts. - * Note that a series may have a different y-axis calculation than the price chart. - * See the "parameters" section of {@link CIQ.ChartEngine#addSeries} for details - * @type {object} - * @memberof CIQ.ChartEngine.Chart# - */ - series: {}, - /** - * Contains "renderers" that are used to create the visualizations for series. - * - * Renderers will be drawn in their object order, which can be altered if needed to force certain renderings to be drawn before or after others. See example. - * - * @type {object} - * @memberof CIQ.ChartEngine.Chart# - * @example This sample code shows how to move up one place a renderer called "comparison D" - * var rendererName = "comparison D"; - * var newRenderers = {}; - * var pos = 0; - * var r; - * - * for (r in stxx.chart.seriesRenderers) { - * if (r == rendererName) break; - * pos++; - * } - * - * if (pos) { // Not already at top. - * var i = 0; - * for (r in stxx.chart.seriesRenderers) { - * if (i == pos - 1) newRenderers[rendererName] = stxx.chart.seriesRenderers[rendererName]; - * if (r == rendererName) continue; - * newRenderers[r] = stxx.chart.seriesRenderers[r]; - * i++; - * } - * stxx.chart.seriesRenderers = newRenderers; - * } - */ - seriesRenderers: {}, - /** - * Current number of ticks scrolled in from the end of the chart. - * Setting to zero would theoretically cause the chart to be scrolled completely to the left showing an empty canvas. - * Setting to 10 would display the last 10 candles on the chart. - * Setting to `maxTicks` would display a full screen on the chart (assuming enough data is available). - * - * To immediately activate, call [draw()]{@link CIQ.ChartEngine#draw} - * @type number - * @default - * @memberof CIQ.ChartEngine.Chart# - * @example Scroll to the most current (beginning) position in the chart. - * stxx.chart.scroll=0; - * @example Scroll to the end of the chart. - * stxx.chart.scroll=stxx.chart.dataSet.length; - */ - scroll: 0, - isComparison: false, // Used internally, indicates if chart is in comparison mode - /** - * If true, [comparisons]{@link CIQ.ChartEngine#addSeries} force a 'percent' chart scale every time a new series is added, - * and once the last comparison series is removed, the chart will be forced to 'linear' scale. - * In between adding series, the scale can be changed at any time by programmatically calling calling {@link CIQ.ChartEngine#setChartScale} - * - * If false, the chart will not change scale when a comparison series is added or removed and {@link CIQ.ChartEngine#setChartScale} must be explicitly called to set the desired scale. - * This allows for more flexibility in case 'linear' and 'percent' are not the preferred default scales, or the UI is requires to manage the scale separately. - * - * Note this will only take effect on the main chart panel's main axis. - * - * @type boolean - * @default - * @memberof CIQ.ChartEngine.Chart# - * @since 6.2.0 - */ - forcePercentComparison: true, - /** - * Will contain the maximum number of bars that can be displayed on the chart. - * This number is auto-computed by the ChartEngine when the user zooms or the size of the chart changes. - * Since charts can pan slightly off the edge of the screen, this number is width/candleWidth + 2 in order allow partial candles to be displayed on both edges. - * @type number - * @memberof CIQ.ChartEngine.Chart# - */ - maxTicks: 0, // Horizontal number of chart ticks that currently fit in the canvas, based on candlewidth and spacing. This is generally one greater than the actual size of the canvas due to candle clipping. - /** - * Set to a value between 0 and 1 to soften the curves on a line or mountain chart for the primary series. - * - * This only affects the primary chart series. For setting tension on additional series see {@link CIQ.ChartEngine#addSeries} - * - * Splining is a mathematical process that rounds the connectors between segments. - * This results in a very pleasing, smooth look. - * Please note that technical analysts generally do not like splined charts because they obscure the actual closing prices of securities. Splining should be used only when the use case doesn't require exact values. - * @type number - * @memberof CIQ.ChartEngine.Chart# - */ - tension: null, - /** - * READ ONLY. A "snapshot" of the market for the active instrument. - * This data is ephemeral in nature and not used to produce a time series chart. - * But rather used on our peripheral plugins that require more details on the current market, such as [TFC]{@link CIQ.TFC} and [Active Trader]{@link CIQ.MarketDepth}. - * This data is programmatically collated from the incoming data and is updated with the most recent information so it should not be altered manually. - * - * The `currentMarketData` object contains the following information: - * - Last Bid - * - Last Ask - * - Last Price - * - Last Size - * - Lastest Level 2 information - * - * For more details see {@link CIQ.ChartEngine#updateCurrentMarketData} - * @type object - * @memberof CIQ.ChartEngine.Chart# - * @since 6.1.0 - */ - currentMarketData: {}, - /** - * READ ONLY. The master data for this chart. - * This data is never modified by the chart engine itself and should not be altered directly. - * - * Use {@link CIQ.ChartEngine#loadChart} , {@link CIQ.ChartEngine#updateChartData} to load/update this object. - * - * See the [Data Integration]{@tutorial DataIntegrationOverview} tutorial for details. - * @type array - * @memberof CIQ.ChartEngine.Chart# - */ - masterData: null, - /** - * Contains the current complete data set created from {@link CIQ.ChartEngine.Chart#masterData} by {@link CIQ.ChartEngine#createDataSet}; adjusted for periodicity and with calculated studies. - * - * See the [Data Integration]{@tutorial DataIntegrationOverview} and [Studies]{@tutorial Using and Customizing Studies} tutorials for more details. - * @type array - * @memberof CIQ.ChartEngine.Chart# - */ - dataSet: null, - /** - * Contains a copy of the {@link CIQ.ChartEngine.Chart#dataSet}, scrubbed for null entries (gap dates). - * This is used by studies to avoid gaps being interpreted as "zero" values and throwing off calculations. - * - * See the [Studies]{@tutorial Using and Customizing Studies} tutorial for more details. - * @type array - * @memberof CIQ.ChartEngine.Chart# - */ - scrubbed: null, - /** - * READ ONLY. Contains the portion of the {@link CIQ.ChartEngine.Chart#dataSet} that is currently displayed on the screen (view-window). - * It includes both full and partial bars, and may even include a bar whose visible portion is entirely off the screen. - * As the chart is panned or zoomed, the dataSegment is updated to reflect the new position in the chart. - * - * To properly access the portion of the dataSegment representing bars that are at least 50% showing on the screen, use {@link CIQ.ChartEngine#getDataSegment}. - * - * See the [Data Integration]{@tutorial DataIntegrationOverview} tutorial for details. - * @type array - * @memberof CIQ.ChartEngine.Chart# - */ - dataSegment: null, - /** - * READ ONLY. Contains data pertaining to variable width candles, such as volume candles, used to determine location of bars on the screen. - * @type array - * @memberof CIQ.ChartEngine.Chart# - */ - segmentImage: null, - /** - * Parameters used to control the baseline in baseline_delta charts - * @type {object} - * @memberof CIQ.ChartEngine.Chart# - */ - baseline: { - /** - * includeInDataSegment - If set to true, forces a line chart (usually a baseline chart) to begin inside the chart, - * whereas normally the first point in a line chart is off the left edge of the screen. - * - * **Note:** Only applies when set by the chart, will not work if set by a renderer. - * @type boolean - * @default - * @alias CIQ.ChartEngine.Chart#baseline[`includeInDataSegment`] - * @memberof CIQ.ChartEngine.Chart#baseline - */ - includeInDataSegment: false, - /** - * defaultLevel - If set to a value, overrides the default behavior of baseline chart - * which is to set baseline to leftmost point visible on the chart. - * @type number - * @alias CIQ.ChartEngine.Chart#baseline[`defaultLevel`] - * @memberof CIQ.ChartEngine.Chart#baseline - */ - defaultLevel: null, - /** - * userLevel - Value of the user-set baseline level. To prevent user from adjusting the baseline, - * set this property to false. - * @type boolean|number - * @default - * @alias CIQ.ChartEngine.Chart#baseline[`userLevel`] - * @memberof CIQ.ChartEngine.Chart#baseline - */ - userLevel: null, - /** - * actualLevel - This is computed automatically. Do not set. - * @type number - * @default - * @alias CIQ.ChartEngine.Chart#baseline[`actualLevel`] - * @memberof CIQ.ChartEngine.Chart#baseline - */ - actualLevel: null - }, - /** - * Contains the {@CIQ.ChartEngine.XAxis} object for the chart. - * @type CIQ.ChartEngine.XAxis - * @memberof CIQ.ChartEngine.Chart# - */ - xAxis: null, // x Axis for the chart - /** - * Contains data entries for the full xaxis, including entries for "future" bars that are displayed on the chart. - * floatDate and headsUp use these values for display to the user. - * It is a superset of dataSegment. - * @type {array} - * @memberof CIQ.ChartEngine.Chart# - */ - xaxis: [], - /** - * Determines at which zoom level interior axis points are displayed. Value in pixels. - * @type number - * @default - * @memberof CIQ.ChartEngine.Chart# - */ - xaxisFactor: 30, - /** - * READ ONLY. Maximum number of decimal places in data set. - * - * This can be changed by setting {@link CIQ.ChartEngine.Chart#calculateTradingDecimalPlaces} to a different function. - * See {@link CIQ.calculateTradingDecimalPlaces} for more details. - * @type number - * @memberof CIQ.ChartEngine.Chart# - */ - decimalPlaces: 2, - /** - * If true, the y-axis width is based on the width of the displayed instrument prices. - * - * To prevent constant resizing of the y-axis, the dynamic width setting starts at the - * initial axis width ({@link CIQ.ChartEngine.YAxis#width}) and increases to ensure all - * digits are in view as the user zooms and pans the chart. The dynamic width setting - * returns to the initial width only when key events happen, such as removing a study or - * series or changing the instrument. - * - * Applies to all y-axes attached to a chart. - * - * @type boolean - * @default - * @memberof CIQ.ChartEngine.Chart# - * @since 5.1.1 - * - * @see {@link CIQ.ChartEngine.AdvancedInjectable#resetDynamicYAxis}. - */ - dynamicYAxis: true, - roundit: 100, // Computed automatically to round y-axis display - /** - * Used to determine chart display characteristics that are dependent on chart size, such - * as the width and font of the y-axis. - * - * Meant to be used in tandem with CSS responsive design breakpoints. Do not set directly; - * instead use {@link CIQ.ChartEngine#notifyBreakpoint}, which ensures that the relevant - * styles (which have already been calculated) are updated based on the new breakpoint. - * - * @type string - * @default null - * @memberof CIQ.ChartEngine.Chart# - * @since 8.2.0 - */ - breakpoint: null, - /** - * Function used to render the Legend when multiple series are being displayed on the main chart panel. - * Update your prototype or a specific chart instance, if you want to use a different rendering method for legend. - * - * To activate the legend, you must first define the location in `stx.chart.legend`. - * This is done by providing the x and y coordinates for the first element in the legend as follows: - * ``` - * stxx.chart.legend={ - * x: yourXlocation, - * y: yourYlocation - * }; - * ``` - * - * Once set, a legend item for each series you add will be added as defined by this function. - * - * Defaults to {@link CIQ.drawLegend}, which uses {@link CIQ.drawLegendItem} - * @type function - * @default - * @memberof CIQ.ChartEngine.Chart# - * @example - * // define your legend renderer - * stxx.chart.legendRenderer = yourFunction; // must follow the function signature of {@link CIQ.drawLegend}; - * // actiate the legend - * stxx.chart.legend={ - * x: 50, - * y: 50 - * }; - * @example - * // sample series legend function - stxx.chart.legendRenderer = function(stx, params){ - var coordinates=params.coordinates; - var context=stx.chart.context; - context.textBaseline="top"; - var rememberFont=context.font; - stx.canvasFont("stx-legend",context); - - var chart=params.chart; - if(!coordinates) coordinates=chart.legend; - var xy=[coordinates.x, coordinates.y]; - var lineColor=stx.defaultColor; - - for(var i=0;i<2;i++){ // loop twice, first for the base then again for the series - for(var field in params.legendColorMap){ - var legendItem=params.legendColorMap[field]; - if(legendItem.isBase && (i || params.noBase)) continue; - if(!legendItem.isBase && !i) continue; - var c; - if(legendItem.color instanceof Array){ - var colors=legendItem.color; - for(c=colors.length-1;c>=0;c--){ - if(CIQ.isTransparent(colors[c])) colors.splice(c,1); - } - if(colors.length>1){ - var grd=context.createLinearGradient(xy[0],xy[1],xy[0]+10,xy[1]); - for(c=0;c0){ - lineColor=colors[0]; - }else{ - lineColor=stx.getCanvasColor("stx_line_chart"); - } - }else{ - lineColor=null; - } - if(lineColor) { - var display = field; - if (legendItem.display){ - display = legendItem.display; - } - if(!display){ - if(chart.symbolDisplay){ - display=chart.symbolDisplay; - }else{ - display=chart.symbol; - } - } - if(xy[0]+context.measureText(display).width>chart.panel.right){ - xy=[coordinates.x, coordinates.y+context.measureText("M").width+6]; // M is squarish, with width roughly equaling height: https://stackoverflow.com/questions/1134586/how-can-you-find-the-height-of-text-on-an-html-canvas - } - xy=CIQ.drawLegendItem(stx, xy, display, lineColor, legendItem.opacity); - } - } - } - context.font=rememberFont; - }; - * @since 07/01/2015 - */ - legendRenderer: CIQ.drawLegend, - /** - * This object is used to temporarily override the coloring logic used on some default chart types, - * or to completely override the `layout.chartType` allowing you to then define a totally custom rendering. - * - * The colorFunction is only available on the following chart types: - * - Colored Line - * - Colored Bar - * - Colored Mountain - * - Colored Step - * - Candle - * - Hollow Candle - * - Volume Candle - * - * Expected format : - *``` - *chartEngine.chart.customChart={colorFunction: myColorFunction} - *``` - *``` - *chartEngine.chart.customChart={chartType:myChartType} - *``` - *``` - *chartEngine.chart.customChart={colorFunction: myColorFunction, chartType:myChartType} - *``` - * Where: - * - `myColorFunction` is the function that contains the logic for overriding default color logic for a **default** chart. Please contact us for more guidance on how to create your own chart types. - * - This function must support the following parameters: - * - [stx]{@link CIQ.ChartEngine} - A chart object - * - quote - A properly formatted OHLC object. - * - mode - A string applicable on 'candle', 'hollow_candle' and 'volume_candle' charts only. Allowed values: - * - `shadow`- indicates the function is asking for the candle wick color - * - `outline` indicates the function is asking for the candle border color - * - `solid` indicates the function is asking for the candle fill color(Inside of candle. Not applicable on 'hollow_candle' or 'volume_candle') - * - Example: `myColorFunction(stx,quote,mode);` - * - This function must return a `string|object` representing the color to use for the bar, candle or line segment component. - * - Return `null` to skip the current datapoint and draw nothing in its place. - * - For colored line charts a color/pattern combination can be returned in an object of the following format: `{pattern:[3,3],color:"red"}` - * - `myChartType` is the name of your **custom** chart. Setting this value will force "displayChart" to execute your exact code for rendering a chart. You will need to add your rendering code inside a "displayChart" API injection ( **must be an append** to be executed after the default functionality.). - * - * You may set to null any of the parameters to default to existing settings.
- *
If you are simply setting the customChart object in-line, rather than using it as part of an AP injection into the animation loop, it may be necessary to call `setMainSeriesRenderer` to immediately display results.
- *
To restore the original chart settings, set this object to null (and call setMainSeriesRenderer() if necessary). - * - * See {@tutorial Chart Styles and Types} for more details. - * @type object - * @default - * @memberof CIQ.ChartEngine.Chart# - * @example Using the customChart object in-line on your code: - * //you may want to add a menu selection to activate a special candle chart by executing this code in response to the menu selection: - * stxx.chart.customChart={colorFunction: function(stx, quote, mode){ - * if(mode=="shadow" || mode=="outline") return "black"; //draw black wicks and borders - * else{ - * if(quote.Close>100) return "green"; - * else if(quote.DT.getHours()<12) return "yellow"; - * else return "orange"; - * } - * return null; - * } - * }; - * stxx.setMainSeriesRenderer(); - * - * // to deactivate, you can execute this code: - * stxx.chart.customChart={colorFunction: null}; - * stxx.setMainSeriesRenderer(); - * @example Using the customChart object inside an API injection: - * CIQ.ChartEngine.prototype.prepend("displayChart", function(chart){ - * if ( this.layout.chartType =="candle") - * this.chart.customChart={ - * colorFunction:function(stx, quote, mode){ - * if(quote.Close>quote.iqPrevClose) return "blue"; - * else if(quote.CloseCIQ.ChartEngine.callbacks[\`calculateTradingDecimalPlaces\`]. - */ - calculateTradingDecimalPlaces: CIQ.calculateTradingDecimalPlaces - }, - true - ); - - }; - - - let __js_core_engine_convert_ = (_exports) => { - - - var CIQ = _exports.CIQ; - - /** - * Returns the absolute screen position given a Y pixel on the canvas - * @param {number} y Y pixel on the canvas - * @return {number} Absolute Y screen position - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.resolveY = function (y) { - return this.top + y; - }; - - /** - * Returns the absolute screen position given a X pixel on the canvas - * @param {number} x X pixel on the canvas - * @return {number} Absolute X screen position - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.resolveX = function (x) { - return this.left + x; - }; - - /** - * Returns the relative canvas position given an absolute Y position on the screen - * @param {number} y Y pixel on the screen - * @return {number} Relative Y position on canvas - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.backOutY = function (y) { - return y - this.top; - }; - - /** - * Returns the relative canvas position given an absolute X position on the screen - * @param {number} x X pixel on the screen - * @return {number} Relative X position on canvas - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.backOutX = function (x) { - return x - this.left; - }; - - /** - * Returns a date (in yyyymmddhhmm form) given a tick (location in the dataSet). - * If the tick lies outside of the dataSet then the date will be arrived at algorithmically by calculating into the past or future. - * @param {number} tick Location in the dataSet - * @param {CIQ.ChartEngine.Chart} [chart] A chart object - * @param {boolean} [nativeDate] True to return as date object otherwise returns in yyyymmddhhmm form - * @param {string} [tickSource] Tick array to search. Defaults to `dataSet` - * @return {(string|Date)} The date form dictated by native param - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.dateFromTick = function ( - tick, - chart, - nativeDate, - tickSource = "dataSet" - ) { - if (!chart) chart = this.chart; - const tickArray = chart[tickSource]; - let data_len = tickArray.length; - let dt; - let iter; - let result; - let addedTempDate = false; - - // if empty chart then add current date so this function supports initializing an empty chart in quotefeed - if (data_len === 0) { - tickArray[0] = {}; - tickArray[0].DT = new Date(); - data_len = tickArray.length; - addedTempDate = true; - } - - if (tick < 0) { - iter = this.standardMarketIterator(tickArray[0].DT); - if (iter) dt = iter.previous(Math.abs(tick)); - else dt = tickArray[0].DT; - } else if (tick >= data_len) { - iter = this.standardMarketIterator(tickArray[data_len - 1].DT); - if (iter) dt = iter.next(tick - (data_len - 1)); - else dt = tickArray[data_len - 1].DT; - } else { - dt = tickArray[tick].DT; - } - - if (nativeDate) { - result = new Date(dt.getTime()); - } else { - result = CIQ.yyyymmddhhmmssmmm(dt).substr(0, 12); - } - - if (addedTempDate) { - delete tickArray[0].DT; - } - return result; - }; - - /** - * Returns the tick (position in dataSet) given the requested date. - * - * The date does not need to match exactly. If the date lies between ticks then the earlier will be returned by default. - * - * @param {Date|string} dt Date object or date in string format - * @param {CIQ.ChartEngine.Chart} [chart] Chart object - * @param {number} [adj] Timezone adjustment in minutes to apply to date before getting tick - * @param {boolean} [forward] Switch to return the next tick as opposed to the previous, in case an exact match is not found - * @param {string} [tickSource] Tick array to search. Defaults to `dataSet` - * @return {number} The tick location - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.tickFromDate = function ( - dt, - chart, - adj, - forward, - tickSource = "dataSet" - ) { - if (!chart) chart = this.chart; - const tickArray = chart[tickSource]; - if (!(tickArray && tickArray.length)) return 0; - if (!adj) adj = 0; - const target = dt.constructor == Date ? dt : CIQ.strToDateTime(dt); - - // This line is used by drawings which are saved with a gmt offset. - if (!CIQ.ChartEngine.isDailyInterval(this.layout.interval)) - target.setMinutes(target.getMinutes() + adj); - - const ms = target.getTime(); - if (!chart.tickCache[tickSource]) chart.tickCache[tickSource] = {}; - let total = chart.tickCache[tickSource][ms]; - if (total || total === 0) { - return forward ? Math.ceil(total) : Math.floor(total); - } - - const firstDate = tickArray[0].DT; - const lastDate = tickArray[tickArray.length - 1].DT; - if (target >= firstDate && target <= lastDate) { - let begin = 0; - let end = tickArray.length; - let attempts = 0; - while (++attempts < 100) { - let i = Math.floor((end + begin) / 2); - let d = tickArray[i].DT; - if (+d == +target) { - chart.tickCache[tickSource][ms] = i; - return i; - } - if (d < target) { - begin = i; - } - if (d > target) { - if (tickArray[i - 1].DT < target) { - chart.tickCache[tickSource][ms] = i - 0.5; - return forward ? i : i - 1; - } - if (+tickArray[i - 1].DT == +target) { - // efficiency - chart.tickCache[tickSource][ms] = i - 1; - return i - 1; - } - end = i; - } - } - if (attempts >= 100) { - console.log("!!!Warning: tickFromDate() did not find match."); - return tickArray.length; - } - } - - // start at beginning of chart and work backward into the past, or end of chart and into the future - const intoThePast = target < firstDate; - const start = intoThePast ? firstDate : lastDate; - const iter = this.standardMarketIterator(start); - const ticks = iter ? iter.futureTick({ end: target }) : 0; - total = intoThePast ? ticks * -1 : tickArray.length - 1 + ticks; - chart.tickCache[tickSource][ms] = total; - return total; - }; - - /** - * Returns the X pixel given the location of a bar (`dataSegment`) on the chart. - * - * @param {number} bar The bar for which the X pixel is returned (position on the chart, which is - * also the position in the `dataSegment`). - * @param {CIQ.ChartEngine.Chart} [chart] The chart that contains the bar. Defaults to - * `this.chart`. - * @return {number} The X pixel on the chart. - * - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.pixelFromBar = function (bar, chart) { - if (!chart) chart = this.chart; - var x = 0, - segmentImage = this.chart.segmentImage; - if (segmentImage && segmentImage[bar] && segmentImage[bar].leftOffset) { - x = segmentImage[bar].leftOffset; - } else { - x = (bar + 0.5) * this.layout.candleWidth; - } - x = chart.panel.left + Math.floor(x + this.micropixels) - 1; - return x; - }; - - /** - * Returns the position (array index) of the first **dataSegment** element encountered given the X pixel. - * Do not reference this into dataSegment without checking bounds, because the return value may be negative or greater than the dataSegment array length. - * - * See {@link CIQ.ChartEngine#tickFromPixel} if you wish to locate the dataSet position. - * - * @param {number} x An X pixel location on the chart - * @param {CIQ.ChartEngine.Chart} [chart] Which chart to use. Defaults to this.chart. - * @return {number} The bar that lies on the X pixel (may be negative/before or after the chart) - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.barFromPixel = function (x, chart) { - if (!chart) chart = this.chart; - var segmentImage = this.chart.segmentImage, - mp = this.micropixels, - cw = this.layout.candleWidth; - if (segmentImage) { - //binary search - var pixel = x - chart.panel.left - mp, - mult = 2, - quote; - var length = segmentImage.length; - var bar = Math.round(length / mult); - var leftOffset, halfCandleWidth; - var rightofLastTick = - segmentImage[length - 1].leftOffset + - segmentImage[length - 1].candleWidth / 2; - if (pixel > rightofLastTick) { - //beyond the rightmost tick - return ( - length + Math.floor((x - rightofLastTick - chart.panel.left - mp) / cw) - ); - } - for (var i = 1; i < length; i++) { - mult *= 2; - quote = segmentImage[bar]; - if (!quote) break; - leftOffset = quote.leftOffset; - halfCandleWidth = quote.candleWidth / 2; - var left = leftOffset - halfCandleWidth; - var right = leftOffset + halfCandleWidth; - if (bar === 0 || (pixel >= left && pixel < right)) break; - else if (pixel < left) bar -= Math.max(1, Math.round(length / mult)); - else bar += Math.max(1, Math.round(length / mult)); - bar = Math.max(0, Math.min(length - 1, bar)); - } - if (!segmentImage[bar]) { - //sucks, we need to iterate through - for (i = 0; i < length; i++) { - quote = segmentImage[i]; - if (!quote) continue; - leftOffset = quote.leftOffset; - halfCandleWidth = quote.candleWidth / 2; - if (pixel < leftOffset - halfCandleWidth) return Math.max(0, i - 1); - else if (pixel < leftOffset + halfCandleWidth) return i; - else if (pixel >= leftOffset + halfCandleWidth) return i + 1; - } - } - - return bar; - } - return Math.floor((x - chart.panel.left - mp) / cw); - }; - - /** - * Returns the position (array index) of the first **dataSet** element encountered given the X pixel. - * - * See {@link CIQ.ChartEngine#barFromPixel} if you wish to locate the dataSegment position. - * - * @param {number} x X pixel location - * @param {CIQ.ChartEngine.Chart} [chart] A chart object - * @return {number} The tick (position in the dataSet) - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.tickFromPixel = function (x, chart) { - if (!chart) chart = this.chart; - var tick = chart.dataSet.length - chart.scroll; - - if (chart.segmentImage) { - tick += this.barFromPixel(x, chart); - } else { - tick += Math.floor( - (x - chart.panel.left - this.micropixels) / this.layout.candleWidth - ); - } - return tick; - }; - - /** - * Returns an X pixel for the given tick. The X pixel will be the center of the tick location. - * Note that the pixel may be off of the visual canvas and that it might overlap the Y axis. - * @param {number} tick The tick (position in the dataSet array) - * @param {CIQ.ChartEngine.Chart} [chart] A chart object - * @return {number} The X position in pixels (may be negative or may be greater than dataSet.length) - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.pixelFromTick = function (tick, chart) { - if (!chart) chart = this.chart; - var dataSegment = chart.dataSegment, - dataSet = chart.dataSet, - segmentImage = chart.segmentImage, - mp = this.micropixels, - length = dataSegment ? dataSegment.length : 0; - var panel = chart.panel, - scroll = chart.scroll; - var bar = tick - dataSet.length + scroll, - quote = length ? dataSegment[bar] : null; - - if (segmentImage) quote = segmentImage[bar]; - if (quote && quote.leftOffset) { - return panel.left + Math.floor(quote.leftOffset + mp); //in here for volume candle - } - //in here for other chart types, or volume candle if bar lies outside of the actual quote data - var rightOffset = 0, - dsTicks = 0; - quote = length ? dataSegment[length - 1] : null; - if (segmentImage) quote = segmentImage[length - 1]; - if (quote && quote.leftOffset) { - //volume candle - if (length < tick - dataSet.length + scroll) { - //in the "whitespace" area on the right of the chart - rightOffset = quote.leftOffset - quote.candleWidth / 2; - dsTicks = length; - } - } - return ( - rightOffset + - panel.left + - Math.floor( - (tick - dsTicks - dataSet.length + scroll + 0.5) * - this.layout.candleWidth + - mp - ) - ); - }; - - /** - * Returns the X pixel position for a tick of a given date. - * - * The date does not need to match exactly. If the date lies between ticks then the earlier will be returned. - * - * **Warning: this can be an expensive operation if the date is not in the dataSet.** - * - * @param {Date|string} date Date object or String form date - * @param {CIQ.ChartEngine.Chart} chart The chart to look in - * @param {number} [adj] Timezone adjustment in minutes to apply to date before getting tick - * @param {boolean} [forward] Switch to return the next tick as opposed to the previous, in case an exact match is not found - * @return {number} The pixel location for the date - * @memberof CIQ.ChartEngine - * @since added adj and forward arguments - */ - CIQ.ChartEngine.prototype.pixelFromDate = function (date, chart, adj, forward) { - return this.pixelFromTick( - this.tickFromDate(date, chart, adj, forward), - chart - ); - }; - - /** - * A version of {@link CIQ.ChartEngine#priceFromPixel} that will return the y-axis value given a Y pixel - * @param {number} y The Y pixel location - * @param {CIQ.ChartEngine.Panel} [panel] The panel (defaults to the chart) - * @param {CIQ.ChartEngine.YAxis} [yAxis] The yAxis to use - * @return {number} The Y axis value - * @memberof CIQ.ChartEngine - * @since 4.0.0 - */ - CIQ.ChartEngine.prototype.transformedPriceFromPixel = function ( - y, - panel, - yAxis - ) { - if (!panel) panel = this.chart.panel; - var yax = yAxis ? yAxis : panel.yAxis; - y = yax.bottom - y; - var price; - if (yax.semiLog) { - var logPrice = (y * yax.logShadow) / yax.height; - if (yax.flipped) logPrice = yax.logHigh - logPrice; - else logPrice += yax.logLow; - price = Math.pow(10, logPrice); - } else { - if (!yax.multiplier) return null; - price = y / yax.multiplier; - if (yax.flipped) price = yax.high - price; - else price += yax.low; - } - return price; - }; - - /** - * Returns the actual value of the chart given a pixel regardless of any transformation such as a comparison chart. - * @param {number} y The Y pixel location - * @param {CIQ.ChartEngine.Panel} [panel] The panel to look. Defaults to the chart itself if not passed in. - * @param {CIQ.ChartEngine.YAxis} [yAxis] The yAxis to use. Defaults to panel.yAxis. - * @return {number} The Y location. This may be off of the visible canvas. - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.priceFromPixel = function (y, panel, yAxis) { - if (!panel) panel = this.chart.panel; - var price = this.transformedPriceFromPixel(y, panel, yAxis); - if (this.charts[panel.name] && panel.chart.untransformFunc) { - if (!yAxis || yAxis == panel.yAxis) { - price = panel.chart.untransformFunc(this, panel.chart, price, yAxis); - } - } - return price; - }; - - /** - * Returns the value (price) given a Y-axis pixel. The value is relative to the panel or the canvas. - * @param {number} y The y pixel position - * @param {CIQ.ChartEngine.Panel} [panel] A panel object. If passed then the value will be relative to that panel. If not passed then the value will be relative to the panel that is in the actual Y location. - * @param {CIQ.ChartEngine.YAxis} [yAxis] Which yAxis. Defaults to panel.yAxis. - * @return {number} The value relative to the panel - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.valueFromPixel = function (y, panel, yAxis) { - if (!panel) panel = this.whichPanel(y); - if (!panel) { - var panels = Object.values(this.panels); - // If we're not in a current panel then we're off the screen, so choose the top or bottom panel - // Ideally we never get in here because panel is passed in by the developer! - if (panels && panels.length) { - if (y <= 0) { - panel = panels.shift(); - } else { - panel = panels.pop(); - } - } - } - return this.priceFromPixel(y, panel, yAxis); - }; - - /** - * Calculates the value (price) of a field in a dataSegment record based on linear interpolation of its neighboring records. Whether the chart is in linear or logarithmic scale is taken into the equation. - * @param {number} bar The bar position in the dataSegment - * @param {String} fieldName The field to search for in the dataSegment - * @param {String} [subField] The field to search for in a series within the dataSegment. Defaults to chart.defaultPlotField. - * @param {CIQ.ChartEngine.Panel} [panel] The panel to look. Defaults to the chart.panel. - * @param {CIQ.ChartEngine.YAxis} [yAxis] The yAxis to use. Defaults to panel.yAxis. - * @return {number} The value or price; - * @since 6.2.5 - */ - CIQ.ChartEngine.prototype.valueFromInterpolation = function ( - bar, - fieldName, - subField, - panel, - yAxis - ) { - if (bar === null || bar < 0 || !fieldName) return null; - if (!panel) panel = this.chart.panel; - if (!yAxis) yAxis = panel.yAxis; - if (!subField) subField = this.chart.defaultPlotField; - - var prevBar = this.getPreviousBar(this.chart, fieldName, bar); - if (!prevBar) return null; // cannot interpolate if no previous bar - - var prevBarPrice; - var tuple = CIQ.existsInObjectChain(prevBar, fieldName); - if (tuple) prevBarPrice = tuple.obj[tuple.member]; - if (typeof prevBarPrice == "object") { - // most likely a series object - prevBarPrice = prevBarPrice[subField]; - } - - // if step then the interpolated value is just the previous bar - var seriesRenderer = this.getRendererFromSeries(fieldName); - if ( - (seriesRenderer && seriesRenderer.params.step) || - this.layout.chartType === "step" - ) - return prevBarPrice; - - var nextBar = this.getNextBar(this.chart, fieldName, bar); - var nextBarPrice; - tuple = CIQ.existsInObjectChain(nextBar, fieldName); - if (tuple) nextBarPrice = tuple.obj[tuple.member]; - if (typeof nextBarPrice == "object") { - // most likely a series object - nextBarPrice = nextBarPrice[subField]; - } - - if (!nextBar) return null; // cannot interpolate if no next bar! - if ( - prevBarPrice === null || - typeof prevBarPrice == "undefined" || - nextBarPrice === null || - typeof nextBarPrice == "undefined" - ) - return null; - // get coordinates of prev and next bars - var y0 = this.pixelFromPrice(prevBarPrice, panel, yAxis); - var y1 = this.pixelFromPrice(nextBarPrice, panel, yAxis); - var x0 = prevBar.tick; - var x1 = nextBar.tick; - - // calculate the gradient - var gradient = (y1 - y0) / (x1 - x0); - - // calculate where the series intercepts the gradient - var seriesTick = this.chart.dataSegment[bar].tick; - var seriesYValue = gradient * (seriesTick - x0) + y0; - - // get price from series Y value - return this.priceFromPixel(seriesYValue, panel, yAxis); - }; - - /** - * Returns the Y pixel from a transformed/displayed value (percentage comparison change, for example). - * - * To get the location of an untransformed price, use {@link CIQ.ChartEngine#pixelFromPrice}.
- * If no transformation is present, both this method and {@link CIQ.ChartEngine#pixelFromPrice} will return the same value. - * @param {number} price The transformed price - * @param {CIQ.ChartEngine.Panel} [panel] The panel (defaults to the chart) - * @param {CIQ.ChartEngine.YAxis} [yAxis] The yAxis to use - * @return {number} The Y pixel value - * @memberof CIQ.ChartEngine - * @since 4.0.0 - */ - CIQ.ChartEngine.prototype.pixelFromTransformedValue = function ( - price, - panel, - yAxis - ) { - if (!panel) panel = this.chart.panel; - var yax = yAxis ? yAxis : panel.yAxis; - var y = (yax.high - price) * yax.multiplier; - if (yax.semiLog) { - var p = Math.max(price, 0); - var logPrice = Math.log(p) / Math.LN10; - //if(price<=0) logPrice=0; - var height = yax.height; - y = height - (height * (logPrice - yax.logLow)) / yax.logShadow; - } - y = yax.flipped ? yax.bottom - y : yax.top + y; - return y; - }; - - /** - * Returns the Y pixel from a price, even if a transformation such as a percentage change comparison scale is active. - * - * To do this, the active transformation function will be applied to the provided price and then {@link CIQ.ChartEngine#pixelFromTransformedValue} will be called on the resulting value.
- * If no transformation is present, both this method and {@link CIQ.ChartEngine#pixelFromTransformedValue} will return the same value. - * @param {number} price The price or value - * @param {CIQ.ChartEngine.Panel} panel A panel object (see {@link CIQ.ChartEngine#pixelFromPrice}) - * @param {CIQ.ChartEngine.YAxis} [yAxis] The yaxis to use - * @return {number} The y axis pixel location - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.pixelFromPrice = function (price, panel, yAxis) { - if (!panel) panel = this.chart.panel; - if (this.charts[panel.name] && panel.chart.transformFunc) { - if (!yAxis || yAxis == panel.yAxis) { - price = panel.chart.transformFunc(this, panel.chart, price, yAxis); // transform should move to panel - } - } - return this.pixelFromTransformedValue(price, panel, yAxis); - }; - - /** - * Returns the Y pixel location for the (split) unadjusted price rather than the displayed price. - * This is important for drawing tools or any other device that requires the actual underlying price. - * - * @param {CIQ.ChartEngine.Panel} panel The panel to get the value from - * @param {number} tick The tick location (in the dataSet) to check for an adjusted value - * @param {number} value The value - * @param {CIQ.ChartEngine.YAxis} [yAxis] The yaxis to use - * @return {number} The pixel location - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.pixelFromValueAdjusted = function ( - panel, - tick, - value, - yAxis - ) { - // If we're not showing unadjusted quotes, or if the panel isn't a chart then bypass - if (this.layout.adj || !this.charts[panel.name]) - return this.pixelFromPrice(value, panel, yAxis); - var a = Math.round(tick); // Not sure why we're rounding this. Possible legacy code. - // Adjust if there's a ratio attached to the tick - var ratio; - if ( - a > 0 && - a < panel.chart.dataSet.length && - (ratio = panel.chart.dataSet[a].ratio) - ) { - return this.pixelFromPrice(value * ratio, panel, yAxis); - } - // Otherwise pass through - return this.pixelFromPrice(value, panel, yAxis); - }; - - /** - * Returns the unadjusted value for a given value, if an adjustment (split) had been applied. This can return a value - * relative to the original closing price. - * @param {CIQ.ChartEngine.Panel} panel The panel to check - * @param {number} tick The location in the dataset - * @param {number} value The value to adjust - * @return {number} The adjusted value - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.adjustIfNecessary = function (panel, tick, value) { - if (this.layout.adj) return value; // Already adjusted prices - if (!panel || !this.charts[panel.name]) return value; - var a = Math.round(tick); - var ratio; - if ( - a > 0 && - a < panel.chart.dataSet.length && - (ratio = panel.chart.dataSet[a].ratio) - ) { - return value / ratio; - } - return value; - }; - - }; - - - let __js_core_engine_crosshair_ = (_exports) => { - - - var CIQ = _exports.CIQ; - - /** - * INJECTABLE - * - * Positions the crosshairs at the last known mouse/finger pointer position, which ensures that - * the crosshairs are at a known position on touch devices. - * - * Called by the {@link WebComponents.cq-toolbar} (drawing toolbar) web component. - * - * @alias positionCrosshairsAtPointer - * @memberof CIQ.ChartEngine.AdvancedInjectable# - */ - CIQ.ChartEngine.prototype.positionCrosshairsAtPointer = function () { - var currentPanel = this.currentPanel; - if (!currentPanel) return; - if ( - !this.manageTouchAndMouse || - (this.mainSeriesRenderer && this.mainSeriesRenderer.nonInteractive) - ) - return; - if (this.runPrepend("positionCrosshairsAtPointer", arguments)) return; - var chart = currentPanel.chart; - var rect = this.container.getBoundingClientRect(); - this.top = rect.top; - this.left = rect.left; - this.right = this.left + this.width; - this.bottom = this.top + this.height; - this.cy = this.crossYActualPos = this.backOutY(CIQ.ChartEngine.crosshairY); - this.cx = this.backOutX(CIQ.ChartEngine.crosshairX); - var crosshairTick = (this.crosshairTick = this.tickFromPixel(this.cx, chart)); - var position = this.pixelFromTick(crosshairTick, chart) - 1; - if (this.controls.crossX) this.controls.crossX.style.left = position + "px"; - if (position >= currentPanel.right || position <= currentPanel.left) { - this.undisplayCrosshairs(); - return; - } - var chField = - currentPanel.name == "chart" - ? this.preferences.horizontalCrosshairField - : currentPanel.horizontalCrosshairField; - var dataSet = chart.dataSet; - if ( - chField && - dataSet && - crosshairTick < dataSet.length && - crosshairTick > -1 - ) { - this.crossYActualPos = this.pixelFromPrice( - dataSet[crosshairTick][chField], - currentPanel - ); - } - if (this.controls.crossY) - this.controls.crossY.style.top = this.crossYActualPos + "px"; - this.runAppend("positionCrosshairsAtPointer", arguments); - }; - /** - * INJECTABLE - * - * Internal function that makes the crosshairs visible based on where the user's mouse pointer is - * located. This function should not be called directly. - * - * Crosshairs are visible if enabled, unless a drawing tool is active, in which case they are - * displayed automatically regardless of state. - * - * When the user's mouse moves out of the chart or over a modal, the crosshairs are - * automatically made invisible using - * {@link CIQ.ChartEngine.AdvancedInjectable#undisplayCrosshairs}. - * - * To temporarily show or hide enabled crosshairs, use {@link CIQ.ChartEngine#showCrosshairs} - * and {@link CIQ.ChartEngine#hideCrosshairs}, respectively. - * - * **Note:** If the z-index of the crosshairs is set higher than the z-index of the subholder - * element, the crosshairs cannot be controlled by the chart engine. - * - * @alias doDisplayCrosshairs - * @memberof CIQ.ChartEngine.AdvancedInjectable# - * @since 5.0.0 No longer allows the crosshairs to be enabled if the mouse pointer is outside the - * chart. - */ - CIQ.ChartEngine.prototype.doDisplayCrosshairs = function () { - if (this.runPrepend("doDisplayCrosshairs", arguments)) return; - if (this.displayInitialized) { - var floatCanvas = this.floatCanvas; - var drawingTool = this.currentVectorParameters.vectorType; - if (!this.layout.crosshair && (drawingTool === "" || !drawingTool)) { - this.undisplayCrosshairs(); - } else if ( - CIQ.Drawing && - CIQ.Drawing[drawingTool] && - new CIQ.Drawing[drawingTool]().dragToDraw - ) { - this.undisplayCrosshairs(); - } else if ( - this.overXAxis || - this.overYAxis || - (!this.insideChart && !this.grabbingScreen) - ) { - this.undisplayCrosshairs(); - } else if (this.openDialog !== "") { - this.undisplayCrosshairs(); - } else { - var controls = this.controls, - crossX = controls.crossX, - crossY = controls.crossY; - if (crossX && crossX.style.display !== "") { - crossX.style.display = ""; - if (crossY) crossY.style.display = ""; - if (this.magnetizedPrice && drawingTool) { - this.container.classList.remove("stx-crosshair-on"); - this.chart.tempCanvas.style.display = "block"; - } else { - this.container.classList.add("stx-crosshair-on"); - } - } - if (controls.floatDate && !this.chart.xAxis.noDraw) { - controls.floatDate.style.visibility = ""; - if (this.currentPanel) this.updateFloatHRLabel(this.currentPanel); - } - if (floatCanvas) { - if (floatCanvas.style.display == "none") - CIQ.clearCanvas(floatCanvas, this); - floatCanvas.style.display = "block"; - } - } - } - this.runAppend("doDisplayCrosshairs", arguments); - }; - - /** - * INJECTABLE - * - * Internal function that makes the crosshairs invisible when the user mouses out of the chart or - * over a chart control. This function should not be called directly. - * - * See {@link CIQ.ChartEngine.AdvancedInjectable#doDisplayCrosshairs} for more details. - * - * @alias undisplayCrosshairs - * @memberof CIQ.ChartEngine.AdvancedInjectable# - */ - CIQ.ChartEngine.prototype.undisplayCrosshairs = function () { - if (this.runPrepend("undisplayCrosshairs", arguments)) return; - var controls = this.controls, - crossX = controls.crossX, - crossY = controls.crossY; - if (crossX) { - if (crossX.style.display != "none") { - crossX.style.display = "none"; - if (crossY) crossY.style.display = "none"; - } - } - if (this.displayInitialized && controls.floatDate) { - controls.floatDate.style.visibility = "hidden"; - } - this.container.classList.remove("stx-crosshair-on"); - var floatCanvas = this.floatCanvas; - if ( - floatCanvas && - floatCanvas.isDirty && - floatCanvas.style.display != "none" - ) { - CIQ.clearCanvas(floatCanvas, this); - if (floatCanvas.style.display != "none") floatCanvas.style.display = "none"; - } - if ( - !this.activeDrawing && - !this.repositioningDrawing && - !this.editingAnnotation - ) { - var tempCanvas = this.chart.tempCanvas; - if (tempCanvas && tempCanvas.style.display != "none") - tempCanvas.style.display = "none"; - } - this.runAppend("undisplayCrosshairs", arguments); - }; - - /** - * Hides enabled crosshairs. - * - * Usually called as part of a custom drawing or overlay to prevent the crosshairs from displaying - * together with the custom rendering. - * - * See CIQ.ChartEngine.layout[\`crosshair\`] - * to enable/disable the crosshairs. - * - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.hideCrosshairs = function () { - this.displayCrosshairs = false; - }; - - /** - * Re-displays crosshairs hidden by {@link CIQ.ChartEngine#hideCrosshairs}. - * - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.showCrosshairs = function () { - this.displayCrosshairs = true; - }; - - }; - - - let __js_core_engine_data_ = (_exports) => { - - - var CIQ = _exports.CIQ, - timezoneJS = _exports.timezoneJS; - - /** - * Loads a chart for a particular instrument from the data passed in, or fetches new data from the {@link quotefeed}; if one attached. - * - * Replaces {@link CIQ.ChartEngine#newChart}. - * - * Note that before using this method, you must first instantiate the chart engine (once only) and assign it to a DOM container using [new CIQ.ChartEngine({container: document.querySelector(".chartContainer")});]{@link CIQ.ChartEngine}
- * Once a chart engine is instantiated, this is the only method that should be called every time a new chart needs to be drawn for a different instrument.
- * There is no need to destroy the chart, recreate the engine, or explicitly change the data using any other methods. - * - * Charts default to `1 day` periodicity **unless a different periodicity is set** in this call or by using {@link CIQ.ChartEngine#setPeriodicity} prior to this call. You data must always match the chart periodicity!! - * - * @param {string|object} symbol A symbol string, equation or object representing the primary instrument for the chart. **This is a mandatory field and must contain at least one character for the chart to display data, even is not using a primary instrument.** - *
After the chart is initialized with the new data, it will contain both a symbol string (stxx.chart.symbol) and a symbol object (stxx.chart.symbolObject). - *
You can send anything you want in the symbol object, but you must always include at least a 'symbol' element. - *
Both these variables will be available for use wherever the {@link CIQ.ChartEngine.Chart} object is present. For example, if using a {@link quotefeed} for gathering data, `params.stx.chart.symbolObject` will contain your symbol object. - *
To allow equations to be used on a chart, the {@link CIQ.ChartEngine#allowEquations} parameter must be set to `true` and the equation needs to be preceded by an equals sign (=) in order for it to be parsed as an equation. - *
See {@link CIQ.formatEquation} and {@link CIQ.computeEquationChart} for more details on allowed equations syntax. - * @param {Object|Array} [parameters] Data & configuration settings to initialize the chart. - *
The masterData array may be provided as the second argument assuming no other parameters need to be specified. - * @param {Array} [parameters.masterData] An array of [properly formatted objects]{@tutorial InputDataFormat} to create a chart. - *
Each element should at a minimum contain a "Close" or "Value" field (capitalized) and a 'Date' or 'DT' field. - *
If the charting engine has been configured to use a [QuoteFeed]{@link CIQ.ChartEngine#attachQuoteFeed} - * then masterData does not need to be passed in, and the quote feed will be used instead. - * @param {CIQ.ChartEngine.Chart} [parameters.chart] Which chart to load. Defaults to this.chart. - * @param {CIQ.ChartEngine~RangeParameters} [parameters.range] Default range to be used upon initial rendering. If both `range` and `span` parameters are passed in, range takes precedence. If periodicity is not set, the range will be displayed at the most optimal periodicity. See {@link CIQ.ChartEngine#setRange} for complete list of parameters this object will accept. - * @param {CIQ.ChartEngine~SpanParameters} [parameters.span] Default span to display upon initial rendering. If both `range` and `span` parameters are passed in, range takes precedence. If periodicity is not set, the span will be displayed at the most optimal periodicity. See {@link CIQ.ChartEngine#setSpan} for complete list of parameters this object will accept. - * @param {CIQ.ChartEngine~PeriodicityParameters} [parameters.periodicity] Periodicity to be used upon initial rendering. See {@link CIQ.ChartEngine#setPeriodicity} for complete list of parameters this object will accept. If no periodicity has been set, it will default to `1 day`. - * @param {boolean} [parameters.stretchToFillScreen] Increase the candleWidth to fill the left-side gap created by a small dataSet. Respects CIQ.ChartEngine.preferences.whitespace. Ignored when params `span` or `range` are used. See {@link CIQ.ChartEngine#fillScreen} - * @param {Function} [callback] Called when loadChart is complete. See {@tutorial Adding additional content on chart} for a tutorial on how to use this callback function. - * @memberof CIQ.ChartEngine - * @example Using a symbol string - * stxx.loadChart('IBM'); - * - * @example Using a symbol object and embedded span and periodicity requirements - * stxx.loadChart({symbol: newSymbol, other: 'stuff'}, { - * span: { - * base: 'day', - * multiplier: 2 - * }, - * periodicity: { - * period: 1, - * interval: 5, - * timeUnit: 'minute' - * }, - * stretchToFillScreen: true - * }); - * - * @example Using an equation string - * stxx.loadChart('=2*IBM-GM'); - * - * @example Provide data as the second argument - * stxx.loadChart('YUM', [ - * {Date: '2018-12-03', Close: 2.0034}, - * {Date: '2018-12-04', Close: 2.0067}, - * {Date: '2018-12-05', Close: 2.0112}, - * {Date: '2018-12-06', Close: 2.0091}, - * {Date: '2018-12-07', Close: 1.9979} - * ]); - * - * @example Provide data as a parameter - * stxx.loadChart('BGS', { - * masterData: [ - * {DT: 1542384420000, Close: 1.00}, - * {DT: 1542384480000, Close: 1.01}, - * {DT: 1542384540000, Close: 1.04}, - * {DT: 1542384600000, Close: 1.02} - * ], - * span: { - * base: 'minute', - * multiplier: 1 - * } - * }); - * - * @since 7.0.0 Added `loadChart`, replacing {@link CIQ.ChartEngine#newChart}. Function signature is different. - */ - CIQ.ChartEngine.prototype.loadChart = function (symbol, parameters, callback) { - //if (!symbol) return; // can't build a chart without a symbol - if (!callback && typeof parameters == "function") { - callback = parameters; - parameters = {}; - } else if (Array.isArray(parameters)) { - parameters = { - masterData: parameters - }; - } - if (!parameters) parameters = {}; - - let { chart, periodicity, range, span } = parameters; - let { layout } = this; - let originalPeriodicity = { - periodicity: layout.periodicity, - interval: layout.interval, - timeUnit: layout.timeUnit - }; - - if (periodicity) { - let internalPeriodicity = CIQ.cleanPeriodicity( - periodicity.period ? periodicity.period : periodicity.periodicity, - periodicity.interval, - periodicity.timeUnit - ); - layout.interval = internalPeriodicity.interval; - layout.periodicity = internalPeriodicity.period; - layout.timeUnit = internalPeriodicity.timeUnit; - } - - if (!chart) chart = this.chart; - - const { - dataSet: prevDataSet, - market: prevMarket, - masterData: prevMasterData, - symbol: prevSymbol, - moreAvailable: prevMoreAvailable, - upToDate: prevUpToDate - } = chart; - const prevSymbolObject = CIQ.clone(chart.symbolObject); - - chart.dataSet = []; - chart.masterData = []; - chart.moreAvailable = null; - chart.upToDate = null; - if (!symbol) { - chart.symbol = null; - chart.symbolObject = { symbol: null }; - } else if (typeof symbol == "object") { - // an object was sent in, so initialize the string from the object - chart.symbol = symbol.symbol; - chart.symbolObject = symbol; - } else { - // a string was sent in so initialize the object from the string - chart.symbol = symbol; - chart.symbolObject.symbol = symbol; - } - - chart.inflectionPoint = null; // reset where the consolidation occurs from - - if (this.marketFactory) { - const marketDef = this.marketFactory(chart.symbolObject); - this.setMarket(marketDef, chart); - } - - this.setMainSeriesRenderer(true); - - // no range or span passed into parameters, check layout - if (!range && !span && layout) { - span = !layout.range ? layout.setSpan : {}; - range = layout.range || {}; - } - // both passed into parameters, range takes precedence - else if (range && span) { - span = {}; - } - - this.clearCurrentMarketData(chart); - - var self = this; - if (!parameters.masterData && this.quoteDriver) { - let onsymbol = function (err) { - if (err && err != "orphaned") { - // orphaned means that another loadChart request came in, overriding this one - chart.symbol = prevSymbol; // revert the symbol back to what it was if there is an error - chart.symbolObject = prevSymbolObject; // revert the symbol object back to what it was if there is an error - chart.market = prevMarket; - self.masterData = chart.masterData = prevMasterData; - chart.dataSet = prevDataSet; - chart.moreAvailable = prevMoreAvailable; - chart.upToDate = prevUpToDate; - } - onComplete(); - if (callback) callback.call(self, err); - }; - - if (range && Object.keys(range).length && this.setRange) { - // check for empty object - delete parameters.span; // range and span are mutually exclusive - delete layout.setSpan; - this.chart.masterData = null; - this.displayInitialized = false; - if (periodicity) { - range.periodicity = periodicity; - } - range.forceLoad = true; - this.setRange(range, onsymbol); - } else if (span && span.base && this.setSpan) { - span.multiplier = span.multiplier || 1; - // force a new chart to be initialized and new data fetched before calling setSpan to conform with the expectations and purpose of loadChart, - // and not use existing data and symbol names. - this.chart.masterData = null; - this.displayInitialized = false; - // periodicity will be kept if sent as a parameter. - if (periodicity) span.maintainPeriodicity = true; - span.forceLoad = true; - this.setSpan(span, onsymbol); - } else { - this.quoteDriver.newChart( - { - symbol: chart.symbol, - symbolObject: chart.symbolObject, - chart: chart, - initializeChart: true - }, - function (err) { - if (!err) { - self.adjustPanelPositions(); // to ensure holders are adjusted for current yaxis height - self.quoteDriver.updateSubscriptions(); - if (parameters.stretchToFillScreen) { - self.fillScreen(); - } - } - onsymbol.apply(self, arguments); - } - ); - } - } else { - if (!parameters.masterData) { - console.log( - "Warning: No masterData specified and no QuoteFeed configured" - ); - } - if (!chart.symbol) chart.symbol = ""; // if we are ready to draw but the symbol is missing, it will crash - this.initializeChart(); - let masterData = this.doCleanupGaps(parameters.masterData, chart); - this.setMasterData(masterData, chart, { noCleanupDates: true }); - chart.endPoints = {}; - if (masterData && masterData.length) { - chart.endPoints = { - begin: masterData[0].DT, - end: masterData[masterData.length - 1].DT - }; - } - this.createDataSet(); - - if (range && Object.keys(range).length && this.setRange) { - this.setRange(range); - } else if (span && span.multiplier && span.base && this.setSpan) { - this.setSpan({ - maintainPeriodicity: true, - multiplier: span.multiplier, - base: span.base - }); - } else if (parameters.stretchToFillScreen) { - this.fillScreen(); - } else if (masterData && masterData.length) { - this.home(); - } else { - this.clear(); - } - this.adjustPanelPositions(); // to ensure holders are adjusted for current yaxis height - onComplete(); - if (callback) callback.call(self); - } - - function onComplete() { - self.dispatch(self.currentlyImporting ? "symbolImport" : "symbolChange", { - stx: self, - symbol: chart.symbol, - symbolObject: chart.symbolObject, - prevSymbol: prevSymbol, - prevSymbolObject: prevSymbolObject, - action: "master" - }); - if (periodicity) { - self.dispatch("periodicity", { - stx: self, - differentData: true, - prevPeriodicity: originalPeriodicity - }); - } - } - }; - - /** - * Loads a blank chart - * - * @memberof CIQ.ChartEngine - * @since 7.3.0 - */ - CIQ.ChartEngine.prototype.loadBlankChart = function () { - this.loadChart(null, []); - }; - - /** - * Returns all the valid data fields in masterData. A valid data field is one - * that is in use by a series or one that is in use by the main chart - * @param {CIQ.ChartEngine.Chart} [chart] The chart to look in - * @return {array} An array of valid price fields - * @private - * @since 4.0.0 - */ - CIQ.ChartEngine.prototype.getDataFields = function (chart) { - if (!chart) chart = this.chart; - var plotField = chart.defaultPlotField || "Close"; - var fields = ["Open", "High", "Low"]; - fields.push(plotField); - for (var field in chart.series) { - var parameters = chart.series[field].parameters; - fields.push(parameters.symbol); - } - return fields; - }; - /** - * Cleans up the masterData after a series has been removed. This method will remove - * the series field from the masterData, only if no other series are dependent on the field. - * Once the field is removed, any empty/null masterData points will be removed. Finally, - * doCleanGaps will be run again to set masterData back to its original state. createDataSet - * is not run from this method - * @param {object} symbolObject A symbol object - * @param {CIQ.ChartEngine.Chart} chart The chart to clean - * @private - * @since 4.0.0 - */ - CIQ.ChartEngine.prototype.cleanMasterData = function (symbolObject, chart) { - var symbol = symbolObject.symbol; - var masterData = chart.masterData; - - if (!masterData || !masterData.length) return; - - var fields = this.getDataFields(chart); - - // Returns true is the quote doesn't have any valid data fields - function empty(quote, fields) { - for (var i = 0; i < fields.length; i++) { - var val = quote[fields[i]]; - if (typeof val != "undefined") return false; - } - return true; - } - // Clean out "zombie" masterData entries. These would be entries that no longer have - // any valid data. This can happen whenever series have non-overlapping dates. - var i = 0; - do { - var quote = masterData[i]; - delete quote[symbol]; - if (empty.call(this, quote, fields)) { - masterData.splice(i, 1); - continue; - } - i++; - } while (i < masterData.length); - masterData = this.doCleanupGaps(masterData, chart, { noCleanupDates: true }); - this.setMasterData(masterData, chart, { noCleanupDates: true }); - this.clearCurrentMarketData(chart, symbol); - }; - - /** - * Calculates the ATR (Average True Range) for the dataSet - * @private - * @param {CIQ.ChartEngine.Chart} chart The chart to calculate - * @param {number} period The number of periods - * @param {array} data The data to process, if omitted, uses chart.dataSet - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.calculateATR = function (chart, period, data) { - if (!data) data = chart.dataSet; - var state = chart.state.calculations.atr; - if (!state) state = chart.state.calculations.atr = {}; - if (!period) period = 20; - var accum = []; - if (state.accum) accum = state.accum; - var q1; - for (var i = 0; i < data.length; i++) { - var q = data[i]; - q1 = i ? data[i - 1] : state.q1; - if (!q1) continue; - - var trueRange = Math.max( - q.High - q.Low, - Math.abs(q.High - q1.Close), - Math.abs(q.Low - q1.Close) - ); - if (accum.length < period) { - if (accum.push(trueRange) == period) { - var total = 0; - for (var j = 0; j < accum.length; j++) total += accum[j]; - q.atr = total / period; - } - } else { - q.atr = (q1.atr * (period - 1) + trueRange) / period; - } - q.trueRange = trueRange; - } - chart.state.calculations.atr = { - accum: accum, - q1: q1 - }; - }; - - /** - * Calculates the Median Price for the dataSet. - * @private - * @param {CIQ.ChartEngine.Chart} chart The chart to update. - * @param {array} data The data to process, if omitted, uses chart.dataSet - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.calculateMedianPrice = function (chart, data) { - if (!data) data = chart.dataSet; - var d; - for (var i = 0; i < data.length; ++i) { - d = data[i]; - d["hl/2"] = (d.High + d.Low) / 2; - } - }; - - /** - * Calculates the Typical Price for the dataSet. - * @private - * @param {CIQ.ChartEngine.Chart} chart The chart to update. - * @param {array} data The data to process, if omitted, uses chart.dataSet - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.calculateTypicalPrice = function (chart, data) { - if (!data) data = chart.dataSet; - var d; - for (var i = 0; i < data.length; ++i) { - d = data[i]; - d["hlc/3"] = (d.High + d.Low + d.Close) / 3; - } - }; - - /** - * Calculates the Weighted Close for the dataSet. - * @private - * @param {CIQ.ChartEngine.Chart} chart The chart to update. - * @param {array} data The data to process, if omitted, uses chart.dataSet - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.calculateWeightedClose = function (chart, data) { - if (!data) data = chart.dataSet; - var d; - for (var i = 0; i < data.length; ++i) { - d = data[i]; - d["hlcc/4"] = (d.High + d.Low + 2 * d.Close) / 4; - } - }; - - /** - * Calculates the (Open + High + Low + Close) / 4 for the dataSet. - * @private - * @param {CIQ.ChartEngine.Chart} chart The chart to update. - * @param {array} data The data to process, if omitted, uses chart.dataSet - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.calculateOHLC4 = function (chart, data) { - if (!data) data = chart.dataSet; - var d; - for (var i = 0; i < data.length; ++i) { - d = data[i]; - d["ohlc/4"] = (d.Open + d.High + d.Low + d.Close) / 4; - } - }; - - /** - * Returns the current quote (the final element in the dataSet). - * - * @param {string} [field] Optional field. If provided, searches for the first record with that field having a value. - * @return {object} The most recent quote. - * @memberof CIQ.ChartEngine - * @since 7.3.0 Added the `field` argument. - */ - CIQ.ChartEngine.prototype.currentQuote = function (field) { - if (!this.chart.dataSet) return null; - for (var i = this.chart.dataSet.length - 1; i >= 0; i--) { - if (this.chart.dataSet[i]) { - if (!field) return this.chart.dataSet[i]; - var val = this.chart.dataSet[i][field]; - if (val || val === 0) return this.chart.dataSet[i]; - } - } - return null; - }; - - /** - * Returns the last valid Close found in the dataSet. - * This would be any numeric value - * @param {string} field Optional object to check Close within, such as with a series - * @return {number} The most recent close - * @memberof CIQ.ChartEngine - * @since 6.1.0 - */ - CIQ.ChartEngine.prototype.mostRecentClose = function (field) { - if (!this.chart.dataSet) return null; - for (var i = this.chart.dataSet.length - 1; i >= 0; i--) { - var ret = this.chart.dataSet[i]; - if (!ret) continue; - if (field) { - ret = ret[field]; - if (!ret && ret !== 0) continue; - } - var iqPrevClose = ret.iqPrevClose; - if (typeof ret == "object") ret = ret.Close; - if (typeof ret == "number") return ret; - if (typeof iqPrevClose == "number") return iqPrevClose; - } - return null; - }; - - /** - * INJECTABLE - * Animation Loop - * - * Creates the dataSegment. The dataSegment is a copy of the portion of the dataSet that is observable in the - * current chart. That is, the dataSegment is a "view" into the dataSet. chart.scroll and chart.maxTicks are the - * primary drivers for this method. - * @param {CIQ.ChartEngine.Chart} [theChart] If passed then a data segment will be created just for that chart, otherwise all charts - * @memberof CIQ.ChartEngine.AdvancedInjectable# - * @alias createDataSegment - */ - CIQ.ChartEngine.prototype.createDataSegment = function (theChart) { - if (this.runPrepend("createDataSegment", arguments)) return; - var chart; - for (var chartName in this.charts) { - chart = this.charts[chartName]; - if (theChart) chart = theChart; - - if (CIQ.Comparison && chart.isComparison) - CIQ.Comparison.createComparisonSegmentInner(this, chart); - - var dataSet = chart.dataSet, - baseline = chart.baseline, - scroll = chart.scroll, - maxTicks = chart.maxTicks; - var layout = this.layout, - cw = layout.candleWidth; - baseline.actualLevel = baseline.userLevel - ? baseline.userLevel - : baseline.defaultLevel; - /* - chart.baseline.includeInDataSegment forces a line chart (usually a baseline chart) to begin inside the chart - whereas normally the first point in a line chart is off the left edge of the screen. - */ - var dataSegmentStartsOneBack = - baseline.includeInDataSegment && - (!this.mainSeriesRenderer || !this.mainSeriesRenderer.standaloneBars); - var quote; - var totalVolume = 0; - var dataSegment = (chart.dataSegment = []); - var position = dataSet.length - 1 - scroll - 1; // One more to deal with -1 case - var prevField = chart.defaultPlotField; - for (var i = -1; i < scroll && i < maxTicks; i++) { - position++; - if (i == -1 && !dataSegmentStartsOneBack) continue; - if (position < dataSet.length && position >= 0) { - quote = dataSet[position]; - quote.candleWidth = null; - if (quote) totalVolume += quote.Volume || 1; - dataSegment.push(quote); - if (baseline.actualLevel === null && i >= 0) { - if (prevField && prevField != "Close") { - var q1 = dataSet[position - 1]; - if (q1 && (q1[prevField] || q1[prevField] === 0)) - baseline.actualLevel = q1[prevField]; - } else { - if (quote.iqPrevClose || quote.iqPrevClose === 0) - baseline.actualLevel = quote.iqPrevClose; - } - } - } else if (position < 0) { - dataSegment.push(null); - } - } - chart.segmentImage = null; - var mainSeriesRenderer = this.mainSeriesRenderer || {}; - if (mainSeriesRenderer.params && mainSeriesRenderer.params.volume) { - var workingWidth = - chart.width - (maxTicks - dataSegment.length - 1) * layout.candleWidth; - var accumOffset = 0; - chart.segmentImage = []; - for (var w = 0; w < dataSegment.length; w++) { - quote = dataSegment[w]; - chart.segmentImage[w] = {}; - var leftOffset = null; - if (quote) { - if (quote.Volume) { - quote.candleWidth = (workingWidth * quote.Volume) / totalVolume; - leftOffset = accumOffset + quote.candleWidth / 2; - accumOffset += quote.candleWidth; - } else { - quote.candleWidth = cw; - leftOffset = accumOffset + cw / 2; - accumOffset += cw; - } - chart.segmentImage[w] = { - tick: quote.tick, - candleWidth: quote.candleWidth, - leftOffset: leftOffset - }; - } else { - accumOffset += cw; - } - } - } - if (theChart) break; - } - if (chart && chart.isComparison) this.clearPixelCache(); - this.positionCrosshairsAtPointer(); - this.runAppend("createDataSegment", arguments); - }; - - /** - * Returns the visible portion of the dataSegment. A bar is considered visible if its midpoint is within the chart window. - * This is different than chart.dataSegment which includes any partially visible candles and possibly the very next data point to be displayed. - * @param {CIQ.ChartEngine.Chart} [chart] Chart from which to return the dataSegment - * @returns {array} The visible bars of the dataSegment - * @memberof CIQ.ChartEngine - * @since 5.2.0 - */ - CIQ.ChartEngine.prototype.getDataSegment = function (chart) { - if (!chart) chart = this.chart; - var dataSegment = chart.dataSegment; - if (!dataSegment || !dataSegment.length) return []; - var left = 0; - var right = dataSegment.length; - if (this.pixelFromBar(left, chart) < chart.panel.left) left++; - if (this.pixelFromBar(right - 1, chart) > chart.panel.right) right--; - return dataSegment.slice(left, right); - }; - - /** - * Sets the master data for the chart. A data set is derived from the master data by - * {@link CIQ.ChartEngine#createDataSet}. - * - * **This function is intended for internal data management. Do not explicitly call this - * function unless you are manipulating the data at a very detailed level.** - * - * For most implementations, simply set your data using {@link CIQ.ChartEngine#loadChart} or - * a [quote feed interface](quotefeed.html), if a quote feed is attached. - * - * If a [market factory]{@link CIQ.ChartEngine#setMarketFactory} has been linked to the chart, - * this function also updates the market on the chart to match the newly loaded instrument. - * When no factory is present, the chart assumes that the market will never change and - * continues to use the market initially set using {@link CIQ.ChartEngine#setMarket}. - * If no market has been set, the chart operates in 24x7 mode. - * - * This function also calculates the number of decimal places for the security by checking - * the maximum number in the data. The number of decimal places is stored in - * {@link CIQ.ChartEngine.Chart#decimalPlaces}. - * - * @param {array} masterData An array of quotes. Each quote should at a minimum contain a - * "Close" or "value" field (capitalized) and a "Date" or "DT" field. This functions sets - * DT to be a JavaScript `Date` object derived from the string form. - * @param {CIQ.ChartEngine.Chart} [chart] The chart to which `masterData` is applied. Defaults - * to the default chart. - * @param {object} [params] Parameters object. - * @param {boolean} [params.noCleanupDates] If true, then dates have been cleaned up already - * by calling {@link CIQ.ChartEngine#doCleanupDates}, so do not do so in this function. - * - * @memberof CIQ.ChartEngine - * @since - * - 5.2.0 Added the `params` and `params.noCleanupDates` parameters. - * - 7.0.0 The `masterData` field "Value" may be treated as the primary plot device. - * - 8.0.0 The [decimalPlaces]{@link CIQ.ChartEngine.Chart#decimalPlaces} field of the - * `chart` parameter is now set from - * {@link CIQ.ChartEngine.Chart#calculateTradingDecimalPlaces}. - */ - CIQ.ChartEngine.prototype.setMasterData = function (masterData, chart, params) { - if (!chart) chart = this.chart; - if (this.marketFactory) { - var marketDef = this.marketFactory(chart.symbolObject); - this.setMarket(marketDef, chart); - } - - if (!params) params = {}; - - if (!params.noCleanupDates) - this.doCleanupDates(masterData, this.layout.interval); - - chart.masterData = masterData; - if (chart.name == "chart") this.masterData = masterData; - //chart.decimalPlaces=2; - var i; - var field = null; - for (i = 0; masterData && i < masterData.length; i++) { - var quotes = masterData[i]; - - if (field === null) { - if (typeof quotes.Close === "number") { - field = "Close"; - } else if (typeof quotes.Value === "number") { - field = "Value"; - } - } - if (field === "Value" && typeof quotes.Value === "number") { - quotes.Close = quotes.Value; - } - - if (quotes.DT) { - if (Object.prototype.toString.call(quotes.DT) != "[object Date]") - quotes.DT = new Date(quotes.DT); // if already a date object; nothing to do - if (!quotes.Date || quotes.Date.length != 17) - quotes.Date = CIQ.yyyymmddhhmmssmmm(quotes.DT); - } else if (quotes.Date) quotes.DT = CIQ.strToDateTime(quotes.Date); - else - console.log("setMasterData : Missing DT and Date on masterData object"); - if (quotes.Volume && typeof quotes.Volume !== "number") - quotes.Volume = parseInt(quotes.Volume, 10); - //if(typeof quotes.Close != 'number' && !quotes.Close && quotes.Close!==null){ - // console.log ('setMasterData : Close is missing or not a number. Use parseFloat() if your data server provides strings. MasterData Index= ' + i +' Value = ' + quotes.Close); - //} - if (masterData.length - i < 50) { - // only check last 50 records - this.updateCurrentMarketData(quotes, chart, null, { fromTrade: true }); - } - } - if (chart.calculateTradingDecimalPlaces) - chart.decimalPlaces = chart.calculateTradingDecimalPlaces({ - stx: this, - chart: chart, - symbol: chart.symbolObject.symbol, - symbolObject: chart.symbolObject - }); - - this.setDisplayDates(masterData); - chart.roundit = Math.pow(10, chart.decimalPlaces); - - for (i in this.plugins) { - var plugin = this.plugins[i]; - if (plugin.display) { - if (plugin.setMasterData) plugin.setMasterData(this, chart); - } - } - }; - - /** - * Sets the master data for the chart, creates the data set, and renders the chart. - * - * @param {string} symbol Ticker symbol for the chart. - * @param {array} masterData An array of quotes. Each quote should at a minimum contain a "Close" field (capitalized) and a Date field which is a string form of the date. - * This method will set DT to be a JavaScript Date object derived from the string form. - * @param {CIQ.ChartEngine.Chart} [chart] The chart to put the masterData. Defaults to the default chart. - * @memberof CIQ.ChartEngine - * @since 3.0.0 - */ - CIQ.ChartEngine.prototype.setMasterDataRender = function ( - symbol, - masterData, - chart - ) { - if (!chart) chart = this.chart; - if (!chart.symbol) chart.symbol = ""; - this.setMasterData(masterData, chart); - if (masterData) { - chart.endPoints = {}; - if (masterData.length) { - chart.endPoints = { - begin: masterData[0].DT, - end: masterData[masterData.length - 1].DT - }; - chart.symbol = symbol; - } - } - this.createDataSet(); - this.initializeChart(); - this.draw(); - if (!masterData || !masterData.length) { - chart.symbol = null; - this.clear(); - } - this.adjustPanelPositions(); - }; - - /** - * Returns an array of all symbols currently required to be loaded by the quote feed. - * The returned array contains an object for each symbol containing `symbol`, `symbolObject`, `interval`, and `periodicity`. - * - * @param {object} params Control parameters. - * @param {boolean} [params.include-parameters] Set to true to put the series parameters in the return object. - * @param {boolean} [params.exclude-studies] Set to true to not include study symbols. - * @param {boolean} [params.breakout-equations] Set to true to return component symbols of equations. - * @param {boolean} [params.exclude-generated] Set to true to not include symbols which are generated by virtue of another symbol (e.g. `PlotComplementer`). - * - * @return {array} The array of symbol objects required. - * @memberof CIQ.ChartEngine - * @since - * - 2016-03-11 - * - 6.2.0 Added `params.breakout-equations` parameter. - * - 7.3.0 Added `params.exclude-generated` parameter. - */ - CIQ.ChartEngine.prototype.getSymbols = function (params) { - if (!params) params = {}; - var a = [], - obj, - layout = this.layout, - symbol, - symbolObject; - function makeObj(symbol, symbolObject, layout) { - return { - symbol: symbol, - symbolObject: symbolObject, - periodicity: layout.periodicity, - interval: layout.interval, - timeUnit: layout.timeUnit, - setSpan: layout.setSpan - }; - } - for (var chartName in this.charts) { - var chart = this.charts[chartName]; - if (chart.symbolObject && chart.symbolObject.symbol) - a.push(makeObj(chart.symbol, chart.symbolObject, layout)); - for (var field in chart.series) { - var series = chart.series[field], - parameters = series.parameters; - if (parameters.data && !parameters.data.useDefaultQuoteFeed) continue; // legacy - symbolObject = parameters.symbolObject; - symbol = parameters.symbol; - obj = makeObj(symbol, symbolObject, layout); - obj.id = field; - if (params["include-parameters"]) { - obj.parameters = CIQ.clone(parameters); - if (obj.parameters.yAxis) delete obj.parameters.yAxis.yAxisPlotter; - } - if (params["exclude-studies"] && parameters.bucket == "study") continue; - if (params["exclude-generated"] && symbolObject.generator) continue; - a.push(obj); - } - } - if (params["breakout-equations"]) { - // replace the equations with their component symbols - var components = {}; // use to eliminate duplicates - for (var s = 0; s < a.length; s++) { - symbol = a[s].symbol; - if (this.isEquationChart(symbol)) { - var res = CIQ.formatEquation(symbol); - if (res) { - var symbols = res.symbols; - for (var sym = 0; sym < symbols.length; sym++) { - components[symbols[sym]] = makeObj( - symbols[sym], - a[s].symbolObject, - a[s] - ); - } - } - } else { - components[symbol] = makeObj(symbol, a[s].symbolObject, a[s]); - } - } - a = []; - for (var component in components) a.push(components[component]); - } - return a; - }; - - /** - * Sets the displayDate for the data element in masterData. The displayDate is the timezone adjusted date. - * @param {object} quote The quote element to check - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.setDisplayDate = function (quote) { - if (CIQ.ChartEngine.isDailyInterval(this.layout.interval)) return; - var dt = quote.DT; - var milli = dt.getSeconds() * 1000 + dt.getMilliseconds(); - var newDT; - if (timezoneJS.Date && this.displayZone) { - newDT = new timezoneJS.Date(dt.getTime(), this.displayZone); - dt = new Date( - newDT.getFullYear(), - newDT.getMonth(), - newDT.getDate(), - newDT.getHours(), - newDT.getMinutes() - ); - dt = new Date(dt.getTime() + milli); - } - quote.displayDate = dt; - }; - - /** - * Calls {@link CIQ.ChartEngine#setDisplayDate} for each element in masterData - * @param {array} masterData Array containing the masterData for a ChartEngine. - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.setDisplayDates = function (masterData) { - if (!masterData) return; - if (CIQ.ChartEngine.isDailyInterval(this.layout.interval)) return; - for (var i = 0; i < masterData.length; i++) { - var quote = masterData[i]; - if (quote.DT) this.setDisplayDate(quote); - } - }; - - /** - * Sets the data timezone (`dataZone`) and display timezone (`displayZone`) on an intraday chart. - * - * >**Important:** - * >- The `dataZone` property on this method must be set **before** any data is loaded so the engine knows how to convert the incoming records. - * >- The `displayZone` property on this method can be set at any time and will only affect what is displayed on the x axis. - * >- This method should only be used for dates that are not timeZone aware. If using the 'DT' fields in your data input records, - * >**DO NOT** use this function to set the `dataZone` as it will result in a double conversion. - * - * - Once set, 'Date' fields containing a time portion, will be converted to the {@link CIQ.ChartEngine#dataZone} - * (or the browser timezone if no dataZone is specified) before added into the `masterData`. Its corresponding 'DT' fields will be set to match. - * The {@link CIQ.ChartEngine#displayZone} is then created and used to translate dates based on either the local browser's timezone, - * or the timezone selected by the end user. - * - * - If the date ('DT' or 'Date') does not include a time offset, such as 'yyyy-mm-dd', - * no time zone conversion will be performed. Use this option if you prefer to display the same date on all timezones. - * This applies to daily, weekly and monthly periodicities only. - * For a list of all supported date formats see the [Input format Tutorial]{@tutorial InputDataFormat} - * - * **Time zone and the {@link quotefeed}:**
- * On a fetch call, if your quote server sends and receives string dates loaded in the 'Date' field, - * you can convert the provided start and end dates back to strings using {@link CIQ.yyyymmddhhmmssmmm} - * Example: - * ``` - * var strStart = CIQ.yyyymmddhhmmssmmm(startDate); - * var strEnd = CIQ.yyyymmddhhmmssmmm(endDate); - * ``` - * These dates will be in the same time zone you sent them in. So they will match your quote feed. - * - * For more details on how time zones work in the chart see the {@tutorial Dates and Timezones} tutorial. - * - * **See {@link CIQ.timeZoneMap} to review a list of all chatIQ supported timezones and instructions on how to add more!** - * - * @param {string} dataZone A ChartIQ supported time zone. This should represent the time zone that the master data comes from, or set to 'null' if your dates are already time zone aware. - * @param {string} displayZone A ChartIQ supported time zone. This should represent the time zone that the user wishes displayed, or set to null to use the browser time zone. - * @memberof CIQ.ChartEngine - * @since 5.2 Also used to convert daily, weekly and monthly periodicities. - * @example - * //The raw data received the chart is in Greenwich Mean Time, but we want to display in Amsterdam time. - * stxx.setTimeZone("UTC", "Europe/Amsterdam") - * - * - */ - CIQ.ChartEngine.prototype.setTimeZone = function (dataZone, displayZone) { - if (!timezoneJS.Date) { - this.timeZoneOffset = 0; - return; - } - - var now = new Date(); - var myTimeZoneOffset = now.getTimezoneOffset(); - var dataTimeZoneOffset = myTimeZoneOffset; - var displayTimeZoneOffset = myTimeZoneOffset; - if (dataZone) this.dataZone = dataZone; - if (this.dataZone) - dataTimeZoneOffset = new timezoneJS.Date( - now, - this.dataZone - ).getTimezoneOffset(); - if (displayZone) this.displayZone = displayZone; - if (this.displayZone) - displayTimeZoneOffset = new timezoneJS.Date( - now, - this.displayZone - ).getTimezoneOffset(); - this.timeZoneOffset = - dataTimeZoneOffset - - myTimeZoneOffset - - (displayTimeZoneOffset - myTimeZoneOffset); - for (var chartName in this.charts) { - var chart = this.charts[chartName]; - this.setDisplayDates(chart.masterData); - } - this.preferences.timeZone = displayZone; - this.changeOccurred("preferences"); - this.createDataSet(); - }; - - /** - * INJECTABLE - * - * Use this method to add new `OHLC` bars to the end of the chart, insert new bars into the middle of the chart, replace existing bars, delete bars, or stream individual `LAST SALE` data tick by tick as they are received from a streaming feed. - * - * **The following rules apply when adding or updating full [`OHLC`]{@tutorial InputDataFormat} bars:** - * - * - Follow proper OHLC format as outlined on the [OHLC format tutorial]{@tutorial InputDataFormat}. - * - If a bar is not present it will be added, if it is present it will be updated so the OHLC and volume integrity is preserved. If `allowReplaceOHL` is not set, the 'Open' is preserved from the existing candle; new 'High' and 'Low' values are calculated, and the 'Close' and 'Volume' values are replaced with the new ones. - * - Although gaps can be present, dates in the appendQuotes array **must maintain the correct periodicity and order** (older to newer) to prevent out of sequence bars. - * - If set, gaps will be filled past the currently existing bar. No gaps will be filled when inserting bars in between existing data. - * - * **The following rules apply when streaming individual `LAST SALE` data, tick by tick, as they are received from a streaming feed:** - * - * - Follow proper LAST SALE format as outlined on the parameters section under the `appendQuotes` field. - * - This method is designed to update the chart while maintaining the existing periodicity, finding and augmenting an existing bar for an instrument or creating new bars as needed. - * - It is important to note that a market iterator will be used to find the proper bar to update, and if no bar is found on that date, one will be created even in the past; so always be sure your historical data follows the rules of the market definitions when setting the dates for each bar. Remember that by default, weeks start on Sunday unless a market definition exists to indicate Sunday is not a market day, in which case the next market day will be used as the beginning of the week. Instructions to set a market for the chart can be found here: {@link CIQ.Market} - * - When in 'tick' interval, each trade will be added to a new bar and no aggregation to previous bars will be done. - * - * **The following rules apply when updating `BID` and `ASK` prices separately from the primary series.** - * - * - Bid, Ask and Volume are reserved for the primary series only. - * - The reasoning is that if your initial data sends a Bid-Ask together with the 'Close' (Last), your updates will as well; which is usually the norm. - * - But if your feed sends updates for Bid and Asks separately than for the 'Last' price, then you must add this additional data as you would do any other secondary series. - * - * > Assuming you have this data pre-loaded on your chart already containing Bid and Ask prices: - * > ``` - * > [ - * > { - * > "DT": "2019-11-19T18:17:29.000Z", - * > "Close": 266.12, - * > "Volume": 300, - * > "Bid": 266.1, - * > "Ask": 266.12, - * > }, - * > { - * > "DT": "2019-11-19T18:17:29.000Z", - * > "Close": 266.12, - * > "Volume": 300, - * > "Bid": 266.1, - * > "Ask": 266.12, - * > } - * > ] - * > ``` - * > And have added this series to display the pre-loaded Bid prices: - * > ``` - * > stxx.addSeries("Bid", {color: "green", loadData: false, shareYAxis: true, step:true}); - * > ``` - * > Use: - * > ``` - * > stxx.updateChartData({Close:90}, null, { useAsLastSale: true, secondarySeries: "Bid" }); - * > ``` - * > or - * > ``` - * > stxx.updateChartData({Last:90}, null, {secondarySeries: "Bid" }); - * > ``` - * > to update the bid prices. - * - * **Performance:** - * - * - To maintain system performance you can throttle inbound ticks. See {@link CIQ.ChartEngine#streamParameters } and [Streaming tutorial]{@tutorial DataIntegrationStreaming} for more details. - * - It is important to note that although the data will always be added to masterData, `createDataSet()` and `draw()` will **not** be called if data is received quicker than the throttle (governor) wait periods. As such, you will not see any changes until the throttle wait periods are met. - * - **Please adjust default settings if your implementation requires immediate updates.** - * - * **Additional Notes:** - * - * - **It is crucial that you ensure the date/time of the records being loaded are in line with your `masterData` and `dataZone`; and in the case of a last trade streaming, that your market definition will produce dates that will be in sync with the rest of your already loaded records.** See `DT` parameter for more details. - * - This method is **not** intended to be used as a way to load initial chart data, or data changes triggered by periodicity changes. - * - Do not stream current updates into the chart using this method if you have used [setSpan]{@link CIQ.ChartEngine#setSpan} or [setRange]{@link CIQ.ChartEngine#setRange} to enter 'historical mode'. - * When in historical mode, forward pagination is based on the date of the last loaded bar, and streaming current updates will create a data gap. - * To check if you are in historical mode evaluate {@link CIQ.ChartEngine#isHistoricalModeSet} - * - * See the [Data Integration]{@tutorial DataIntegrationOverview} tutorial for more detail on how to load initial data. - * - * See the [Streaming]{@tutorial DataIntegrationStreaming} tutorial for more the details. - * - * @param {array|object} appendQuotes **OHLC format requirements**

- * An **array** of properly formatted OHLC quote object(s). [See OHLC Data Format]{@tutorial InputDataFormat}.
- * Items in this array *must* be ordered from earliest to latest date.

- * As a convenience, for more generic data updates, instead of an entire OHLC record, a field of `Value` can be used as an alternative to `Close`.
- * Examples: - * ``` - * { - * DT: stxx.masterData[i].DT, - * Value: 148 - * } - * ``` - * ``` - * { - * Date: '12/31/2011', - * Value: 148 - * } - * ``` - *


- * **LAST SALE format requirements**

- * An **object** with the following elements: - * @param {number} [appendQuotes.Last] Last sale price - * @param {number} [appendQuotes.Volume] Trade volume (**used on primary series only**) - * @param {number} [appendQuotes.Bid] Bid price (**used on primary series only**) - * @param {number} [appendQuotes.Ask] Offer/Ask price (**used on primary series only**) - * @param {array} [appendQuotes.BidL2] Level 2 Bid, expressed as an array of [price,size,obj] pairs.
For example, BidL2: [[10.05, 15, {...}],[10.06, 10, {...}],...].
- * `obj` is an optional object which can contain whatever you wish. It will be conveyed all the way into the marketdepth chart and can be displayed by using the 'headsUp' method of displaying crosshair data. - * @param {array} [appendQuotes.AskL2] Level 2 Offer/Ask expressed as an array of [price,size,obj] pairs.
For example, AskL2: [[11.05, 12, {...}],[11.06, 8, {...}],...].
- * `obj` is an optional object which can contain whatever you wish. It will be conveyed all the way into the marketdepth chart and can be displayed by using the 'headsUp' method of displaying crosshair data. - * @param {number} [appendQuotes.DT] Date of trade. It must be a java script date [new Date()]. If omitted, defaults to "right now". - *

**Last sale format DOES NOT ALLOW THE USE OF A `Date` FIELD**. - *
If you are using the 'Date' string field with a `dataZone` for your historical data and wish to also use it for streaming last sale updates, - * you must instead submit a properly formatted OHLC array with `useAsLastSale` set to `true`. Like this: - * ``` - * stxx.updateChartData( - * [ - * {"Date":"2015-04-16 16:00","Close":152.11,"Volume":4505569} - * ], - * null, - * {useAsLastSale:true} - * ); - * ``` - * @param {CIQ.ChartEngine.Chart} [chart] The chart to append the quotes. Defaults to the default chart. - * @param {object} [params] Parameters to dictate behavior - * @param {boolean} [params.noCreateDataSet] If true then do not create the data set automatically, just add the data to the masterData - * @param {boolean} [params.noCleanupDates] If true then do not clean up the dates using {@link CIQ.ChartEngine.doCleanupDates}. Usually set if dates were already cleaned up. - * @param {boolean} [params.allowReplaceOHL] Set to true to bypass internal logic that maintains OHL so they are instead replaced with the new data instead of updated. - * @param {boolean} [params.bypassGovernor] If true then dataSet will be immediately updated regardless of {@link CIQ.ChartEngine#streamParameters}. Not applicable if `noCreateDataSet` is true. - * @param {boolean} [params.fillGaps] If true and {@link CIQ.ChartEngine#cleanupGaps} is also set, {@link CIQ.ChartEngine#doCleanupGaps} will be called to fill gaps for any newly added bars past the currently existing bar. It will not fill gaps for bars added to the middle of the masterData, or created by deleting a bar.
Reminder: `tick` does not fill any gaps as it is not a predictable interval. - * @param {string} [params.secondarySeries] Set to the name of the element (valid comparison symbol, for example) to load data as a secondary series. When left out, the data will be automatically added to the primary series.
**Note:** You should never set `secondarySeries` to the primary symbol. If you are unsure of what the current primary series is, you can always query the chart engine by checking `stxx.chart.symbol`. - * @param {boolean} [params.deleteItems] Set to true to completely delete the masterData records matching the dates in appendQuotes. - * @param {boolean} [params.useAsLastSale] Set to true if not using a 'last sale' formatted object in `appendQuotes`. - * This option is available in cases when a feed may always return OHLC formatted objects or a 'Close' field instead of a 'Last' field, - * even for last sale streaming updates. - * By definition a 'last sale' can only be a single record indicating the very 'last' sale price. - * As such, even if multiple records are sent in the `appendQuotes` array when this flag is enabled, - * only the last record's data will be used. Specifically the 'Close' and 'Volume' fields will be streamed. - * @param {boolean} [params.useAsLastSale.aggregatedVolume] If your last sale updates send current volume for the bar instead of just the trade volume, set this parameter to 'true' in the `params.useAsLastSale` object. The sent in volume will be used as is instead of being added to the existing bar's volume. Not applicable when loading data for a secondary series. - * @memberof CIQ.ChartEngine - * @example - * // this example will stream the last price on to the appropriate bar and add 90 to the bar's volume. - * stxx.updateChartData( - * { - * Last: 50.94, - * Volume: 90 - * } - * ); - * @example - * // this example will stream the last price on to the appropriate bar and set the volume for that bar to 90. - * stxx.updateChartData( - * { - * Last: 50.94, - * Volume: 90 - * }, - * null, - * {useAsLastSale: {aggregatedVolume:true}} - * ); - * @example - * // this example will stream the last price to the appropriate bar **for a secondary series**. - * stxx.updateChartData( - * { - * Last: 50.94 - * }, - * null, - * {secondarySeries:secondarySymbol} - * ); - * @example - * // this example will add or replace a complete bar. - * stxx.updateChartData( - * [ - * {"Date":"2015-04-16 16:00","Open":152.13,"High":152.19,"Low":152.08,"Close":152.11,"Volume":4505569}, - * {"Date":"2015-04-17 09:30","Open":151.76,"High":151.83,"Low":151.65,"Close":151.79,"Volume":2799990}, - * {"Date":"2015-04-17 09:35","Open":151.79,"High":151.8,"Low":151.6,"Close":151.75,"Volume":1817706} - * ] - * ); - * @example - * // this example will add or replace a complete bar. - * stxx.updateChartData( - * [ - * {"Date":"2015-04-16 16:00","Value":152.13}, - * ] - * ); - * @since - * - 5.1.0 New function replacing and enhancing legacy method `appendMasterData`. - * - 5.1.0 Added ability to delete or insert items anywhere in the masterData. `deleteItems` parameter added. - * - 5.2.0 Added `overwrite` parameter. - * - 5.2.0 For main series data, if Close=null is set, and not streaming, then Open, High, Low and Volume also set to null. - * - 5.2.0 For main series data, if Volume=0/null is set, and not streaming, then Volume is reset to 0. - * - 5.2.0 Added `params.noCleanupDates`; `params.fillGaps` applicable now for secondary series as well. - * - 6.0.0 Removed `overwrite` parameter. - * - 6.1.0 Added BidL2 and AskL2 to `appendQuotes` object. - * - 6.3.0 `appendQuotes` can now take `Value` instead of `Close`. - * - 6.3.0 Added `obj` to BidL2 and AskL2 array elements to allow vendor specific data to be displayed on the chart tooltip. - * - 7.2.0 Method now rolls up ticks if period is greater than 1. - */ - CIQ.ChartEngine.prototype.updateChartData = function ( - appendQuotes, - chart, - params - ) { - if (!params) params = {}; - if (!chart) chart = this.chart; - - var lastSale = false, - aggregatedVolume = false, - masterData = chart.masterData, - layout = this.layout, - dataZone = this.dataZone; - var self = this, - secondary = params.secondarySeries, - field, - symbol; - var isValidNumber = CIQ.isValidNumber; - - // If we are not a tick interval, we want to adjust the DT property of the appendQuotes so it matches the periodicity/interval of the existing chart data. - function adjustDatesToInterval() { - if (!CIQ.Market || !chart.market) return; - // On intraday intervals we use a 24 hour market because we don't want our bars to artificially stop - // at the end of a market session. If we get extended hours, or bad ticks we still - // want to print them on the chart. Trust the data. - var marketDef = { - market_tz: CIQ.getFromNS(chart, "market.market_def.market_tz", null) - }; - var mktInterval = layout.interval; - - if (mktInterval == "month" || mktInterval == "week") { - // if we are rolling day bars into week or month we have to iterate day by day to find the right bar. - if (!self.dontRoll) mktInterval = "day"; - // on week and month we need to know when the week/month starts to find the right day for the candles. - marketDef = self.chart.market.market_def; - } - - var theMarket = new CIQ.Market(marketDef); - var iter_parms = { - begin: - masterData && masterData.length - ? masterData[masterData.length - 1].DT - : appendQuotes.DT, - interval: mktInterval, - periodicity: 1, - timeUnit: layout.timeUnit - }; - - var iter = theMarket.newIterator(iter_parms); - var next = iter.next(); - var max, actualTime; - if (!masterData) { - // there are some use cases where you might prefer to stream data onto masterData without using a quotefeed or loading data first. - appendQuotes.DT = new Date(+iter.previous()); - } else if (appendQuotes.DT < next) { - // update current tick or some tick in the past. - max = 0; // safety catch so we don't go on forever. - var previous = iter.previous(); - actualTime = appendQuotes.DT; - params.appending = true; - while (actualTime < previous && max < 1000) { - params.appending = false; - previous = iter.previous(); - max++; - } - appendQuotes.DT = previous; - params.updating = !params.appending; - } else if (appendQuotes.DT >= next) { - // create new tick. If the date matches, that's it, otherwise fast forward to find the right bar to add. - max = 0; // safety catch so we don't go on forever. - actualTime = appendQuotes.DT; - while (actualTime > next && max < 1000) { - appendQuotes.DT = next; - next = iter.next(); - max++; - } - params.appending = true; - } - } - - // Takes the Last Sale data from the appendQuote and converts it to OHLC data - function formatFromLastSaleData() { - // self is last sale streaming so format accordingly - lastSale = true; - - if (params.useAsLastSale && params.useAsLastSale.aggregatedVolume) - aggregatedVolume = true; - - if (appendQuotes.constructor === Array) { - // is streaming an array of OHLC, do some clean up to extract last and volume - var lastBar = appendQuotes[appendQuotes.length - 1]; - appendQuotes = {}; - - // doCleanupDates will make sure this has a valid 'DT' field in the right timeZone, - // no need to check or convert from 'Date' - appendQuotes.DT = lastBar.DT; - - appendQuotes.Close = lastBar.Close; - appendQuotes.Volume = lastBar.Volume; - } else if (appendQuotes.Last) { - appendQuotes.Close = appendQuotes.Last; - delete appendQuotes.Last; - } - - if ( - appendQuotes.DT && - Object.prototype.toString.call(appendQuotes.DT) != "[object Date]" - ) - appendQuotes.DT = new Date(appendQuotes.DT); // epoch or ISO string - if (!appendQuotes.DT || appendQuotes.DT == "Invalid Date") { - // if no date is sent in, use the current time and adjust to the dataZone - appendQuotes.DT = new Date(); - } - - // find the right candle - if (layout.interval != "tick") { - adjustDatesToInterval(); - } - - appendQuotes.Open = appendQuotes.Close; - appendQuotes.High = appendQuotes.Close; - appendQuotes.Low = appendQuotes.Close; - } - - // Fills the gaps from the most recent master data record to the new data - function fillGapsFromMasterDataHead() { - var lastRecordForThis = null; - var fg = 0; // this is used to store the index of the first record in appendQuotes we should be using to fill gaps. - // we'll adjust this below by looking for the starting point from masterData - if (masterData.length) { - lastRecordForThis = self.getFirstLastDataRecord( - masterData, - secondary || chart.defaultPlotField, - true - ); - if (lastRecordForThis) { - if (appendQuotes[appendQuotes.length - 1].DT <= lastRecordForThis.DT) - return; // no gap to fill - for (; fg < appendQuotes.length; fg++) { - if (+appendQuotes[fg].DT == +lastRecordForThis.DT) { - // if the appendQuote is the same as the lastRecordForThis, check to see which is the "correct" record - if ( - self.getFirstLastDataRecord( - [appendQuotes[fg]], - secondary || chart.defaultPlotField - ) - ) - lastRecordForThis = null; // use appendQuote record - break; - } else if (appendQuotes[fg].DT > lastRecordForThis.DT) break; - } - } - } - // now fg represents the index of the first element in appendQuotes which appears after the last current element for that security. - var gapQuotes = appendQuotes.slice(fg); - if (lastRecordForThis) - gapQuotes.unshift( - secondary ? lastRecordForThis[secondary] : lastRecordForThis - ); // add previous bar so we can close gaps - gapQuotes = self.doCleanupGaps(gapQuotes, chart); - if (lastRecordForThis) gapQuotes.shift(); // remove previous bar - appendQuotes = appendQuotes.slice(0, fg).concat(gapQuotes); - } - - // Deletes an item from masterData at index i and date dt - function deleteThisItem(i, dt) { - var replace; - if (secondary) { - delete masterData[i][secondary]; - if (self.cleanupGaps) { - replace = { DT: dt, Close: null }; - if ( - self.cleanupGaps != "gap" && - masterData[i - 1] && - masterData[i - 1][secondary] - ) { - replace.Close = masterData[i - 1][secondary].Close; - replace.High = replace.Low = replace.Open = replace.Close; - replace.Volume = 0; - } - masterData[i][secondary] = replace; - } - } else { - var spliced = masterData.splice(i, 1)[0]; //deleting from masterData here, but will reinsert if find any series data - replace = { DT: spliced.DT, Close: null, needed: false }; - for (field in chart.series) { - symbol = chart.series[field].parameters.symbolObject.symbol; - if (typeof spliced[symbol] != "undefined") { - replace[symbol] = spliced[symbol]; - delete replace.needed; - } - } - if (self.cleanupGaps && self.cleanupGaps != "gap") { - delete replace.needed; - if (self.cleanupGaps != "gap" && masterData[i - 1]) { - replace.Close = masterData[i - 1].Close; - replace.High = replace.Low = replace.Open = replace.Close; - replace.Volume = 0; - } - } - if (replace.needed !== false) { - masterData.splice(i, 0, replace); - self.setDisplayDate(replace); - } - } - } - - // Takes masterData at index i and merges it into a quote q - function mergeMasterDataIntoNewData(i, q) { - // If we're replacing the last bar then we want to save any series and study data, otherwise comparisons will [briefly] disappear during refreshes - //Preserve any relevant data from prior fetched quote for this bar. - //Here we are assuming that the data being appended to masterData is a data update, perhaps from only one exchange, while - //the existing masterData is a consolidated quote. We trust the quote we had in masterData to have the more accurate - //volume and open, and use the high/low from there in combination with the updated data's to determine the daily high/low. - var master = masterData[i]; - if (secondary) master = master[secondary] || {}; - - if (q.Close === null) { - if (master.Open !== undefined) q.Open = null; - if (master.High !== undefined) q.High = null; - if (master.Low !== undefined) q.Low = null; - if (master.Volume !== undefined) q.Volume = null; - // This code will set the OHLC data for carry gap filling if applicable, - // but it's disabled because if a Close:null is sent in, then just use it. - // I suppose if a gap is really to be filled in, the record should be deleted. - /*if(this.cleanupGaps && this.cleanupGaps!="gap" && masterData[i-1]){ - if(!secondary || masterData[i-1][secondary]){ - q.Close=secondary?masterData[i-1][secondary].Close:masterData[i-1].Close; - q.High=q.Low=q.Open=q.Close; - q.Volume=0; - } - }*/ - } else { - if (lastSale) { - if (q.Volume) { - q.Volume = parseInt(q.Volume, 10); - } - if (!aggregatedVolume) q.Volume += master.Volume; - } else { - if (!isValidNumber(q.Volume) && master.Volume) { - q.Volume = master.Volume; - } - } - if (!params.allowReplaceOHL) { - if (isValidNumber(master.Open)) { - q.Open = master.Open; - } - if (isValidNumber(master.High) && isValidNumber(q.High)) { - if (master.High > q.High) q.High = master.High; - } - if (isValidNumber(master.Low) && isValidNumber(q.Low)) { - if (master.Low < q.Low) q.Low = master.Low; - } - } - // if new data is invalid, revert to old data - ["Close", "Open", "High", "Low", "Bid", "Ask"].forEach(function (field) { - if (!isValidNumber(q[field])) q[field] = master[field]; - }); - - for (field in chart.series) { - symbol = chart.series[field].parameters.symbolObject.symbol; - if ( - typeof q[symbol] == "undefined" && - typeof master[symbol] != "undefined" - ) - q[symbol] = master[symbol]; - } - } - } - - if (!params.noCleanupDates) - this.doCleanupDates(appendQuotes, layout.interval); - - if ( - params.useAsLastSale || - (appendQuotes.constructor == Object && - (appendQuotes.Last || appendQuotes.Last === 0)) - ) { - formatFromLastSaleData(); - } - - if (appendQuotes && appendQuotes.constructor == Object) - appendQuotes = [appendQuotes]; // When developer mistakenly sends an object instead of an array of objects - if (!appendQuotes || !appendQuotes.length) return; - if (this.runPrepend("appendMasterData", [appendQuotes, chart, params])) - return; - if (this.runPrepend("updateChartData", [appendQuotes, chart, params])) return; - - if (!masterData) masterData = []; - - var i = masterData.length - 1, - placedFirstQuote = false; - - // we only fill from the end of the current data, not before - if (params.fillGaps) fillGapsFromMasterDataHead(); - if (!appendQuotes.length) return; // can happen within fillGapsFromMasterDataHead - - for (var j = 0; j < appendQuotes.length; j++) { - var quote = appendQuotes[j]; - var dt = quote.DT, - date = quote.Date; - if (dt && Object.prototype.toString.call(dt) != "[object Date]") - quote.DT = dt = new Date(dt); // if already a date object; nothing to do - if (dt) { - if (!date || date.length != 17) - quote.Date = CIQ.yyyymmddhhmmssmmm(quote.DT); - } - if (!dt) dt = quote.DT = CIQ.strToDateTime(date); - - // If Value provided, it has special meaning if Close not provided (it's the Close) - if (!isValidNumber(quote.Close) && isValidNumber(quote.Value)) { - quote.Close = quote.Value; - } - - while (i >= 0 && i < masterData.length) { - var dt2 = masterData[i].DT; - if (!dt2) dt2 = CIQ.strToDateTime(masterData[i].Date); - if (dt2.getTime() <= dt.getTime()) { - placedFirstQuote = true; - var plusOne = 0; // If time is the same then replace last bar - if (dt2.getTime() < dt.getTime()) { - if (i < masterData.length - 1) { - var dtf = - masterData[i + 1].DT || CIQ.strToDateTime(masterData[i + 1].Date); - if (dtf.getTime() <= dt.getTime()) { - i++; - continue; - } - } - plusOne = 1; // Otherwise append bar - } - if (params.deleteItems) { - if (!plusOne) deleteThisItem(i, dt); - break; - } else { - // Under tick mode, always append bars. If animating, append on the first loop and replace on subsequent loops - if (layout.interval == "tick" && params.firstLoop !== false) - plusOne = 1; - if (!plusOne) mergeMasterDataIntoNewData(i, quote); - - // Here we rectify any missing/malformatted data and set any new high/low - // If we don't set this here, the study calculations will fail - if (isValidNumber(quote.Close)) { - if (!isValidNumber(quote.Open)) quote.Open = quote.Close; - - var high = Math.max(quote.Open, quote.Close), - low = Math.min(quote.Open, quote.Close); - if (!isValidNumber(quote.High) || quote.High < high) - quote.High = high; - if (!isValidNumber(quote.Low) || quote.Low > low) quote.Low = low; - } - if (quote.Volume && !isValidNumber(quote.Volume)) - quote.Volume = parseInt(quote.Volume, 10); - i += plusOne; - - // Insert into masterData here - if (secondary) { - if (appendQuotes.length - j < 50) { - // only check last 50 records - this.updateCurrentMarketData(quote, chart, secondary, { - fromTrade: true - }); - } - if (layout.interval != "tick" || quote.Close !== undefined) { - if (plusOne) { - masterData.splice(i, 0, { DT: quote.DT }); - this.setDisplayDate(masterData[i]); - } - masterData[i][secondary] = quote; - } - } else { - if (appendQuotes.length - j < 50) { - // only check last 50 records - this.updateCurrentMarketData(quote, chart, null, { - fromTrade: true - }); - } - if (layout.interval != "tick" || quote.Close !== undefined) { - // inserting into masterData happens here - masterData.splice(i, plusOne ? 0 : 1, quote); - this.setDisplayDate(quote); - } - } - } - break; - } - i += placedFirstQuote ? 1 : -1; - } - if (i < 0) { - // we have at least one point which needs to be prepended to masterData - // this code will prepend the first of these points, then everything else will fall in line - if (secondary) { - this.updateCurrentMarketData(quote, chart, secondary, { - fromTrade: true - }); - if (layout.interval != "tick" || quote.Close !== undefined) { - masterData.splice(0, 0, { DT: quote.DT }); - this.setDisplayDate(masterData[0]); - masterData[0][secondary] = quote; - } - } else { - this.updateCurrentMarketData(quote, chart, null, { fromTrade: true }); - if (layout.interval != "tick" || quote.Close !== undefined) { - masterData.splice(0, 0, quote); - this.setDisplayDate(quote); - } - } - placedFirstQuote = true; - i = 0; - } - } - if (masterData.length) this.masterData = chart.masterData = masterData; - if (this.maxMasterDataSize) - masterData = chart.masterData = this.masterData = masterData.slice( - -this.maxMasterDataSize - ); - - var series = secondary - ? this.getSeries({ symbol: secondary, chart: chart }) - : [chart]; - for (var s = 0; s < series.length; s++) { - var handle = series[s]; - if (!handle.endPoints.begin || handle.endPoints.begin > appendQuotes[0].DT) - handle.endPoints.begin = appendQuotes[0].DT; - if ( - !handle.endPoints.end || - handle.endPoints.end < appendQuotes[appendQuotes.length - 1].DT - ) - handle.endPoints.end = appendQuotes[appendQuotes.length - 1].DT; - var hField = - (handle.parameters && handle.parameters.field) || chart.defaultPlotField; - var lastQuote = this.getFirstLastDataRecord(appendQuotes, hField, true); - if (lastQuote && (!handle.lastQuote || handle.lastQuote.DT <= lastQuote.DT)) - handle.lastQuote = lastQuote; - if (secondary && params.deleteItems) - handle.lastQuote = this.getFirstLastDataRecord( - masterData, - secondary, - true - )[secondary]; - } - for (var pl in this.plugins) { - var plugin = this.plugins[pl]; - if (plugin.display) { - if (plugin.appendMasterData) - plugin.appendMasterData(this, appendQuotes, chart); - } - } - if (!this.masterData || !this.masterData.length) this.masterData = masterData; - - function dataSetAndDraw() { - self.createDataSet(null, null, params); - self.draw(); - self.updateChartAccessories(); - self.streamParameters.count = 0; - self.streamParameters.timeout = -1; - } - - if (!params.noCreateDataSet) { - var sp = this.streamParameters; - if (++sp.count > sp.maxTicks || params.bypassGovernor) { - clearTimeout(sp.timeout); - dataSetAndDraw(); - } else { - if (sp.timeout == -1) { - sp.timeout = setTimeout(dataSetAndDraw, sp.maxWait); - } - } - } - this.runAppend("appendMasterData", arguments); - this.runAppend("updateChartData", arguments); - }; - - /** - * INJECTABLE - * - * Loads or updates detailed current market information, such as L2 data, into the [chart.currentMarketData]{@link CIQ.ChartEngine.Chart#currentMarketData} object - * or an equally laid out object for a secondary series (symbol), if one provided. - * - * **[draw()]{@link CIQ.ChartEngine#draw} must be called immediately after this method to see the updates.** - * - * A single ‘snapshot’ object per symbol is loaded and only the most current updates maintained. - * This method is not intended to track historical or time-series information. - * - * This market ‘snapshot’ information can then be used to render specialty charts such as {@link CIQ.MarketDepth}, which is not a time series chart. - * This data is also used to feed the Depth of Market indicator, [Trade History]{@link WebComponents.cq-tradehistory} and - * [Order Book]{@link WebComponents.cq-orderbook} web components, part of the [Active Trader package](https://active-trader.demo.chartiq.com/). - * - * When using as part of a chart engine that also display a time-series chart, this method is automatically called with that same time-series data every time new data is load into the chart, thereby maintaing all charts in sync. - * And only needs to be explicitly called when needing to update the L2 'snapshot' at a faster refresh rate than the rest of the time-series data, or if the time-series data does not provide this information. - *
If using the {@link CIQ.MarketDepth} standalone, without a standard time series chart, you must call this method explicitly to load and refresh the data. - * - * Data Format: - * - * | Field | Required | Type | Description | Used for Active Trader | Used for TFC | - * | ----------- | -------- | ---------------- | ---------------- | ---------------- | ---------------- | - * | DT | Yes | A JavaScript Date() object | Timestamp for the data record | Yes | Yes | - * | Bid | No | number | The current bid price | No | Yes | - * | Ask | No | number | The current ask price | No | Yes | - * | Last | No | number | The last (current) price.
If not present, the midpoint of the chart will be the average of the lowest bid and the highest ask.
Required on [Trade History](http://jsfiddle.net/chartiq/r2k80wcu) | Yes | Yes | - * | BidSize | No | number | The bid size | No | No | - * | AskSize | No | number | The ask size | No | No | - * | LastSize | No | number | The last (current) price size.
Required on [Trade History](http://jsfiddle.net/chartiq/r2k80wcu) | Yes | No | - * | LastTime | No | A JavaScript Date() object | Timestamp for the Last price provided.
Required on [Trade History](http://jsfiddle.net/chartiq/r2k80wcu) | Yes | No | - * | BidL2 | No | array | Level 2 Bid, expressed as an array of [price,size] pairs.
For example, BidL2: [[10.05,15],[10.06,10],...]
Required on [Order Book](http://jsfiddle.net/chartiq/L30hna2s/) | Yes | No | - * | AskL2 | No | array | Level 2 Ask, expressed as an array of [price,size] pairs.
For example, AskL2: [[10.05,15],[10.06,10],...]
Required on [Order Book](http://jsfiddle.net/chartiq/L30hna2s/) | Yes | No | - * - * Since not all of the data will need to be updated at the same time, this method allows you to send only the data that needs to be changed. Any values not provided will simply be skipped and not updated on the object. - * - * Example data format for a marketDepth chart: - * ``` - * { - * DT:new Date("2018-07-30T04:00:00.000Z"), - * Last:100.2589, - * BidL2: - * [ - * [93.54,5],[93.65,2],[93.95,7],[95.36,2], - * [95.97,9],[96.58,1], [96.68, 8], [96.98, 4], - * [97.08, 5], [97.18, 5], [97.28, 3], [97.38, 5], - * [97.48, 6], [97.69, 26], [98.29, 5], [98.39, 33], - * [98.49, 13], [98.6, 42], [98.8, 13], [98.9, 1] - * ], - * - * AskL2: - * [ - * [101.22,226],[101.32,31],[101.42,13],[101.53,188], - * [101.63,8],[101.73,5],[101.83,16],[101.93,130], - * [102.03,9],[102.13,122],[102.23,5],[102.33,5], - * [102.43,7],[102.54,9],[102.84,3],[102.94,92], - * [103.04,7],[103.24,4],[103.34,7],[103.44,6] - * ] - * } - * ``` - * - * @param {object} data Data to load as per required format. - * @param {CIQ.ChartEngine.Chart} chart The chart whose market data to update. Defaults to the instance chart. - * @param {string} symbol Symbol if passing secondary series information - * @param {object} params Additional parameters - * @param {boolean} [params.fromTrade] This function can be called directly or as a result of a trade update, such as from {@link CIQ.ChartEngine.Chart#updateChartData}. - * Set this param to `true` to indicate the incoming data is a master data record. - * Otherwise the function will attempt to adjust the record date to align with the last bar. - * @param {boolean} [params.finalClose] If the data.Close is being manipulated (such as with animation), this param should contain the real, final Close value - * @memberof CIQ.ChartEngine - * @since - * - 6.1.0 - * - 6.1.1 Added `params.fromTrade`. - * - 6.2.3 Added `params.finalClose`. - */ - CIQ.ChartEngine.prototype.updateCurrentMarketData = function ( - data, - chart, - symbol, - params - ) { - if (!data || !data.DT) return; - if (!chart) chart = this.chart; - var calledFromTrade = params && params.fromTrade; - // find the right bar for the data, if not found already - var timestamp = data.DT; - if (!calledFromTrade && this.layout.interval != "tick" && chart.market) { - if (chart.market.market_def) { - if (!chart.market.isMarketDate(data.DT)) return; // non-market date, disregard - if ( - !CIQ.ChartEngine.isDailyInterval(this.layout.interval) && - chart.market.getSession(data.DT) === null - ) - return; // outside of market hours, disregard - } - // Find the latest possible bar for this data, including after hours - // Iterate off a copy so we don't mess with the chart's market's settings! - var iter_parms = { - begin: data.DT, - interval: this.layout.interval, - periodicity: this.layout.periodicity, - timeUnit: this.layout.timeUnit - }; - var market = new CIQ.Market(chart.market.market_def); - if (this.extendedHours && this.extendedHours.filter) - market.enableAllAvailableSessions(); - var iter = market.newIterator(iter_parms); - iter.next(); - data.DT = iter.previous(); - } - - if (this.runPrepend("updateCurrentMarketData", arguments)) return; - var currentMarketData = chart.currentMarketData; - if (symbol) { - if (!currentMarketData[symbol]) currentMarketData[symbol] = {}; - currentMarketData = currentMarketData[symbol]; - } - ["Last", "Bid", "Ask"].forEach(function (i) { - if (data[i] && typeof data[i] == "number") { - if ( - !currentMarketData[i] || - !currentMarketData[i].DT || - currentMarketData[i].DT <= data.DT - ) { - currentMarketData[i] = { - DT: data.DT, - Price: data[i], - Size: data[i + "Size"], - Timestamp: timestamp - }; - } - } - }); - ["BidL2", "AskL2"].forEach(function (i) { - if (data[i] && data[i] instanceof Array) { - if ( - !currentMarketData[i] || - !currentMarketData[i].DT || - currentMarketData[i].DT <= data.DT - ) { - currentMarketData[i] = { - DT: data.DT, - Price_Size: data[i], - Timestamp: timestamp - }; - } - } - }); - if ( - data.Close && - (!currentMarketData.Last || currentMarketData.Last.DT <= data.DT) - ) { - var close = data.Close, - finalClose = params && params.finalClose; - if (finalClose || finalClose === 0) close = finalClose; - currentMarketData.Last = { - DT: data.DT, - Price: close, - Size: - data.LastSize === undefined && this.layout.interval == "tick" - ? data.Volume - : data.LastSize, - Timestamp: data.LastTime || timestamp - }; - } - currentMarketData.touched = new Date(); // so we can observe it - - if (!calledFromTrade) delete data.Last; // can cause problems in injections if left - - this.runAppend("updateCurrentMarketData", arguments); - }; - - /** - * INJECTABLE - * - * Clears the [chart.currentMarketData]{@link CIQ.ChartEngine.Chart#currentMarketData} object or the one linked to a secondary series, if one provided. - * @param {CIQ.ChartEngine.Chart} chart The chart to clear. If omitted, will clear all charts. - * @param {string} symbol Symbol to clear this symbol's secondary series information - * @memberof CIQ.ChartEngine - * @since 6.1.0 - */ - CIQ.ChartEngine.prototype.clearCurrentMarketData = function (chart, symbol) { - if (this.runPrepend("clearCurrentMarketData", arguments)) return; - var ch, - charts = []; - if (!chart) { - for (ch in this.charts) { - charts.push(this.charts[ch]); - } - } else { - charts.push(chart); - } - for (ch = 0; ch < charts.length; ch++) { - var md = charts[ch].currentMarketData; - if (symbol) { - delete md[symbol]; - } else { - // preserve original object as it's being observed - for (var d in md) { - md[d] = undefined; - } - } - } - this.runAppend("clearCurrentMarketData", arguments); - }; - - }; - - - let __js_core_engine_event_ = (_exports) => { - - - var CIQ = _exports.CIQ; - - /** - * Legacy method used to internally dispatch a registered event whenever a change to layout, drawings or theme occurs. - * Events must be registered using {@link CIQ.ChartEngine#addDomEventListener} for "layout", "drawing", "theme" and "preferences". - * - * This is simply a proxy method that calls the corresponding {@link CIQ.ChartEngine#dispatch} method. - * - * Developers creating their own custom functionality should call {@link CIQ.ChartEngine#dispatch} instead. - * - * @param {string} change Type of change that occurred. - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.changeOccurred = function (change) { - var obj = { - stx: this, - symbol: this.chart.symbol, - symbolObject: this.chart.symbolObject, - layout: this.layout, - drawings: this.drawingObjects - }; - if (change == "theme") this.dispatch("theme", obj); - if (this.currentlyImporting) return; // changes actually occurring because of an import, not user activity - if (change == "layout") { - this.dispatch("layout", obj); - } else if (change == "vector") { - this.dispatch("drawing", obj); - } else if (change == "preferences") { - this.dispatch("preferences", obj); - } - }; - - /** - * Charts may require asynchronous data to render. This creates a dilemma for any external - * process that depends on a fully rendered chart (for instance a process to turn a chart into an image). - * To solve this problem, external processes can register for a callback which will tell them when the chart - * has been drawn. See {@link CIQ.ChartEngine.registerChartDrawnCallback}. - * - * To accommodate this requirement, studies, plugins or injections that render asynchronously should use startAsyncAction - * and {@link CIQ.ChartEngine#completeAsyncAction} to inform the chart of their asynchronous activity. - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.startAsyncAction = function () { - if (!this.pendingAsyncs) this.pendingAsyncs = []; - this.pendingAsyncs.push(true); - }; - - /** - * Registers a callback for when the chart has been drawn - * @param {function} fc The function to call - * @return {object} An object that can be passed in to {@link CIQ.ChartEngine#unregisterChartDrawnCallback} - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.registerChartDrawnCallback = function (fc) { - if (!this.asyncCallbacks) this.asyncCallbacks = []; - this.asyncCallbacks.push(fc); - return { - fc: fc - }; - }; - - /** - * Removes a callback registration for when the chart has been drawn - * @param {object} obj An object from {@link CIQ.ChartEngine#registerDrawnCallback} - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.unregisterChartDrawnCallback = function (obj) { - for (var i = 0; i < this.asyncCallbacks.length; i++) { - if (this.asyncCallbacks[i] == obj.fc) { - this.asyncCallbacks.splice(i, 1); - return; - } - } - }; - - /** - * Makes the async callbacks only if no pending async activity - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.makeAsyncCallbacks = function () { - if (!this.asyncCallbacks) return; // no callbacks to make - if (!this.pendingAsyncs || !this.pendingAsyncs.length) { - // If no pending asyncs, or the array is empty (all have been fulfilled) - for (var i = 0; i < this.asyncCallbacks.length; i++) { - this.asyncCallbacks[i](); - } - } - }; - /** - * Studies or plugins that use asynchronous data should call this when their async activities are complete. - * See {@link CIQ.ChartEngine#startAsyncAction} - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.completeAsyncAction = function () { - this.pendingAsyncs.pop(); - this.makeAsyncCallbacks(); - }; - - /** - * Add a DOM element's event listener and index it so that it will be removed when invoking CIQ.ChartEngine.destroy(). - * https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener - * @param {element} element DOM element to listen for changes on - * @param {string} event The event type to listen for. Possible values: https://developer.mozilla.org/en-US/docs/Web/Events - * @param {function} listener The callback to invoke when the event happens. - * @param {*} Either a boolean or object. See addEventListener options. - * @see {@link CIQ.ChartEngine#destroy} - * @private - * @since 3.0.0 - */ - CIQ.ChartEngine.prototype.addDomEventListener = function ( - element, - event, - listener, - options - ) { - element.addEventListener(event, listener, options); - this.eventListeners.push({ - element: element, - event: event, - function: listener, - options: options - }); - }; - - /** - * Registers a listener for a chart event in the chart engine instance. - * - * Events are tracked in the `CIQ.ChartEngine.callbackListeners` object, which is READ ONLY and - * should never be manually altered. - * - * Valid event types and listeners: - * - `*`: Passing in this value registers the listener to every event type below. - * - `doubleTap`: [doubleTapEventListener]{@link CIQ.ChartEngine~doubleTapEventListener} - * - `doubleClick`: [doubleClickEventListener]{@link CIQ.ChartEngine~doubleClickEventListener} - * - `drawing`: [drawingEventListener]{@link CIQ.ChartEngine~drawingEventListener} - * - `drawingEdit`: [drawingEditEventListener]{@link CIQ.ChartEngine~drawingEditEventListener} - * - `floatingWindow`: [floatingWindowEventListener]{@link CIQ.ChartEngine~floatingWindowEventListener} - * - `layout`: [layoutEventListener]{@link CIQ.ChartEngine~layoutEventListener} - * - `longhold`: [longholdEventListener]{@link CIQ.ChartEngine~longholdEventListener} - * - `move`: [moveEventListener]{@link CIQ.ChartEngine~moveEventListener} - * - `newChart`: [newChartEventListener]{@link CIQ.ChartEngine~newChartEventListener} - * - `notification`: [notificationEventListener]{@link CIQ.ChartEngine~notificationEventListener} - * - `periodicity`: [periodicityEventListener]{@link CIQ.ChartEngine~periodicityEventListener} - * - `preferences`: [preferencesEventListener]{@link CIQ.ChartEngine~preferencesEventListener} - * - `rightClick`: [rightClickEventListener]{@link CIQ.ChartEngine~rightClickEventListener} - * - `scroll`: [scrollEventListener]{@link CIQ.ChartEngine~scrollEventListener} - * - `studyOverlayEdit`: [studyOverlayEditEventListener]{@link CIQ.ChartEngine~studyOverlayEditEventListener} - * - `studyPanelEdit`: [studyPanelEditEventListener]{@link CIQ.ChartEngine~studyPanelEditEventListener} - * - `symbolChange`: [symbolChangeEventListener]{@link CIQ.ChartEngine~symbolChangeEventListener} - * - `symbolImport`: [symbolImportEventListener]{@link CIQ.ChartEngine~symbolImportEventListener} - * - `tap`: [tapEventListener]{@link CIQ.ChartEngine~tapEventListener} - * - `theme`: [themeEventListener]{@link CIQ.ChartEngine~themeEventListener} - * - `undoStamp`: [undoStampEventListener]{@link CIQ.ChartEngine~undoStampEventListener} - * - * @param {string|string[]} type One or more event types to listen for. See the description above - * for valid types. - * @param {function} callback The listener to call when the event or events specified by `type` - * are triggered. Accepts an object argument containing properties specified in the event - * listener definition. - * @return {object} An object containing `type` and `callback`. The object can be passed to - * {@link CIQ.ChartEngine#removeEventListener} to remove the listener. - * - * @memberof CIQ.ChartEngine - * @since - * - 04-2016-08 - * - 4.0.0 Added "doubleTap". - * - 4.0.0 Type can be an array of event options. - * - 6.3.0 Added "scroll". - * - 7.0.0 Added "preferences" and "drawingEdit". - * - 8.1.0 Added "periodicity". - * - 8.2.0 Added "notification" and "floatingWindow". - * - * @example Add a "longhold" event listener. - * stxx.longHoldTime = ... // Optionally override default value of 700ms. - * stxx.addEventListener("longhold", function(lhObject) { - * CIQ.alert("longhold event at x: " + lhObject.x + " y: " + lhObject.y); - * }); - * - * @example Add a "tap" listener that provides location and details when a series is clicked or tapped. - * stxx.addEventListener("tap", function(tapObject){ - * if (this.anyHighlighted) { - * for (let n in this.chart.seriesRenderers) { - * let r = this.chart.seriesRenderers[n]; - * for (let j = 0; j < r.seriesParams.length; j++) { - * series = r.seriesParams[j]; - * if (series.highlight) { - * let bar = this.barFromPixel(tapObject.x); - * if (this.chart.dataSegment[bar]) { - * // Replace console.log with your required logic as needed. - * console.log("Tap event at pixel x: " + tapObject.x + " y: " + tapObject.y); - * console.log("Price:", this.priceFromPixel(tapObject.y), " Date: ", this.chart.dataSegment[bar].DT); - * console.log("Series Details: ", JSON.stringify(series)); - * } - * } - * } - * } - * } - * }); - */ - CIQ.ChartEngine.prototype.addEventListener = function (type, callback) { - if (type === "*") { - for (var key in this.callbackListeners) { - this.callbackListeners[key].push(callback); - } - } else if (type instanceof Array) { - for (var i = 0; i < type.length; i++) { - this.callbackListeners[type[i]].push(callback); - } - } else { - var arr = this.callbackListeners[type]; - if (!arr) { - throw new Error("Attempted to add an invalid listener."); - } - arr.push(callback); - } - return { type: type, cb: callback }; - }; - - /** - * Removes a listener for a chart event type. - * - * If the event type is "*", listeners for all event types are removed. See - * {@link CIQ.ChartEngine#addEventListener} for valid event types. - * - * Events are tracked in the `CIQ.ChartEngine.callbackListeners` object. - * - * @param {object|string} obj The object returned from adding the listener (see - * {@link CIQ.ChartEngine#addEventListener}) or a string that identifies the type of event. - *

**Note:** If this parameter is a string, the optional `cb` parameter is required. - * @param {string} obj.type The type of event. - * @param {function} obj.cb The listener to be removed. - * @param {function} [cb] The listener to be removed. Required if the `obj` parameter is an - * string, unused otherwise. - * - * @memberof CIQ.ChartEngine - * @since 04-2016-08 - */ - CIQ.ChartEngine.prototype.removeEventListener = function (obj, cb) { - if (!obj || typeof obj != "object") { - // User likely passed in type and callback as two separate arguments into this function. - // This is accounted for because it is consistent with the argument schema of "addEventListener" - obj = { - type: obj, - cb: cb - }; - } - - var spliceEvent = function (arr, cb) { - for (var i = 0; i < arr.length; i++) { - if (arr[i] === cb) { - arr.splice(i, 1); - return; - } - } - }; - var callbackListeners = this.callbackListeners; - - if (obj.type === "*") { - for (var key in callbackListeners) { - spliceEvent(callbackListeners[key], obj.cb); - } - return; - } - - if (!callbackListeners[obj.type]) { - throw new Error("Attempted to remove an invalid listener."); - } - - spliceEvent(callbackListeners[obj.type], obj.cb); - }; - - /** - * Dispatches an event by calling one or more - * [event listeners]{@link CIQ.ChartEngine#eventListeners} registered for the event specified by - * `type`. Event listeners registered for the `*` event type are also subsequently called. - * See {@link CIQ.ChartEngine#addEventListener}. - * - * **Note:** If any of the called event listeners returns true, all remaining uncalled - * listeners are bypassed. - * - * @param {string} type Identifies the type of event for which the event listeners are called. - * Must be one of the types listed in {@link CIQ.ChartEngine#addEventListener} excluding `*`. - * @param {object} data A collection of parameters to provide to the listener functions called in - * response to the event. See the listener types listed in - * {@link CIQ.ChartEngine#addEventListener} for relevant parameters. - * @return {boolean} False unless a called listener returns true, in which case this function - * also returns true. - * - * @memberof CIQ.ChartEngine - * - * @example - * // Trigger a layout change event; perhaps to save the layout. - * stx.dispatch("layout", { - * stx: stx, - * symbol: stx.chart.symbol, - * symbolObject: stx.chart.symbolObject, - * layout: stx.layout, - * drawings: stx.drawingObjects - * }); - */ - CIQ.ChartEngine.prototype.dispatch = function (type, data) { - var arr = this.callbackListeners[type]; - if (arr) { - for (var i = 0; i < arr.length; i++) { - if (arr[i].call(this, data) === true) return true; - } - } - arr = this.callbackListeners["*"]; - if (arr) { - for (var j = 0; j < arr.length; j++) { - if (arr[j].call(this, data) === true) return true; - } - } - return false; - }; - - //@private - CIQ.ChartEngine.prototype.updateListeners = function (event) { - for (var i in this.plugins) { - var plugin = this.plugins[i]; - if (plugin.display && plugin.listener) plugin.listener(this, event); - } - }; - - }; - - - let __js_core_engine_injection_ = (_exports) => { - - - var CIQ = _exports.CIQ; - - /** - * The following is a list of ADVANCED injectable methods. - * - * **These methods should not be normally called by your code, but rather injections should be used to modify their behavior within the library Kernel.** - * - * The "Injection API" provides prepend and append functionality to any built-in method. - * Essentially what this means is that a developer can write code that will be run either before (prepend) or after (append) any internal {@link CIQ.ChartEngine} function (such as draw() or mouseMove()). - * This gives developers the ability to supplement, override or ignore any of the built in functionality. - * - * Note that you may prepend or append multiple functions. Each injected function is stacked "outward" (daisy-chained) from the core function. - * - * _prepend >> prepend >> prepend >> function << append << append << append_ - * - * You may prepend/append either to CIQ.ChartEngine.prototype or directly to a CIQ.ChartEngine instance. - * - * See the {@tutorial Using the Injection API} and [Customization Basics](tutorial-Customization%20Basics.html#injections) tutorials for additional guidance and examples. - * @namespace CIQ.ChartEngine.AdvancedInjectable - * @example - * CIQ.ChartEngine.prototype.append("method_name_goes_here", function(){ - * // do something here - * }); - * @example - * CIQ.ChartEngine.prototype.prepend("method_name_goes_here", function(){ - * // do something here - * // return true; // if you want to exit the method after your injection - * // return false; // if you want the standard code to follow the prepend - * }); - */ - - /** - * Prepends custom developer functionality to an internal chart member. See [“Injection API"]{@tutorial Using the Injection API}. - * @param {string} o Signature of member - * @param {function} n Callback function, will be called with "apply" - * @memberof CIQ.ChartEngine - * @since - * - 04-2015 You can append either to an {@link CIQ.ChartEngine} instance, or to the prototype. The first will affect only a single - * chart while the latter will affect any chart (if you have multiple on the screen). - * - 15-07-01 Function returns a descriptor which can be passed in to [removeInjection()]{@link CIQ.ChartEngine#removeInjection} to remove it later on. - * @return {object} Injection descriptor which can be passed in to {@link CIQ.ChartEngine#removeInjection} to remove it later on. - */ - CIQ.ChartEngine.prototype.prepend = function (o, n) { - var m = "prepend" + o; - var prepends; - if (this instanceof CIQ.ChartEngine) { - prepends = this.hasOwnProperty(m) ? this[m] : []; - this[m] = [n].concat(prepends); - } else { - prepends = CIQ.ChartEngine.prototype[m] || []; - CIQ.ChartEngine.prototype[m] = [n].concat(prepends); - } - return { method: m, func: n }; - }; - - /** - * Appends custom developer functionality to an internal chart member. See [“Injection API"]{@tutorial Using the Injection API}. - * @param {string} o Signature of member - * @param {function} n Callback function, will be called with "apply" - * @memberof CIQ.ChartEngine - * @since - * - 04-2015 You can append either to an {@link CIQ.ChartEngine} instance, or to the prototype. The first will affect only a single - * chart while the latter will affect any chart (if you have multiple on the screen) - * - 15-07-01 Function returns a descriptor which can be passed in to [removeInjection()]{@link CIQ.ChartEngine#removeInjection} to remove it later on. - * @return {object} Injection descriptor which can be passed in to {@link CIQ.ChartEngine#removeInjection} to remove it later on. - */ - CIQ.ChartEngine.prototype.append = function (o, n) { - var m = "append" + o; - var appends; - if (this instanceof CIQ.ChartEngine) { - appends = this.hasOwnProperty(m) ? this[m] : []; - this[m] = appends.concat(n); - } else { - appends = CIQ.ChartEngine.prototype[m] || []; - CIQ.ChartEngine.prototype[m] = appends.concat(n); - } - return { method: m, func: n }; - }; - - /** - * Runs the prepend injections. A prepend function that returns true will short circuit any proceeding prepend functions, and the core functionality. - * @private - * @param {string} o The function name - * @param {Array} args The arguments to the function - * @param {object} self The this object - * @return {boolean} Returns true if any prepend function returns true. - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.runPrepend = function (o, args, self) { - var n = "prepend" + o; - var prepends = this.hasOwnProperty(n) ? this[n] : []; - prepends = prepends.concat(CIQ.ChartEngine.prototype[n] || []); - if (!prepends.length) return false; - if (!self) self = this; - for (var i = 0; i < prepends.length; i++) { - var rv = prepends[i].apply(self, args); - if (rv) return rv; - } - return false; - }; - - /** - * Runs the append injections. An append function that returns true will short circuit any proceeding append functions (but not the core functionality since that has already ocurred). - * @private - * @param {string} o The function name - * @param {Array} args The arguments to the function - * @param {object} self The this object - * @return {boolean} Returns true if any append function returns true. - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.runAppend = function (o, args, self) { - var n = "append" + o; - var appends = this.hasOwnProperty(n) ? this[n] : []; - appends = appends.concat(CIQ.ChartEngine.prototype[n] || []); - if (!appends.length) return false; - if (!self) self = this; - for (var i = 0; i < appends.length; i++) { - var rv = appends[i].apply(self, args); - if (rv) return rv; - } - return false; - }; - - /** - * Removes a specific injection. One can remove either an instance injection or a prototype injection, depending on how the function is called. - * @param {object} id The injection descriptor returned from {@link CIQ.ChartEngine#prepend} or {@link CIQ.ChartEngine#append} - * @since 07/01/2015 - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.removeInjection = function (id) { - var method = id.method; - var i; - if (this instanceof CIQ.ChartEngine) { - if (!this[method]) return; - for (i = 0; i < this[method].length; i++) { - if (this[method][i] == id.func) { - this[method].splice(i, 1); - return; - } - } - } else { - if (!CIQ.ChartEngine.prototype[method]) return; - for (i = 0; i < CIQ.ChartEngine.prototype[method].length; i++) { - if (CIQ.ChartEngine.prototype[method][i] == id.func) { - CIQ.ChartEngine.prototype[method].splice(i, 1); - return; - } - } - } - }; - /** - * Removes any and all prepend and append injections from a specified CIQ.ChartEngine function. - * If called as an instance method, will remove the instance injections. - * If called as a prototype method, will remove the prototype injections. - * @example - * stxx.remove("displayChart"); // removes instance injections - * CIQ.ChartEngine.prototpye.remove("displayChart"); // removes prototype injections - * @param {string} o Signature of function which has injections to remove - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.remove = function (o) { - if (this instanceof CIQ.ChartEngine) { - delete this["append" + o]; - delete this["prepend" + o]; - } else { - delete CIQ.ChartEngine.prototype["append" + o]; - delete CIQ.ChartEngine.prototype["prepend" + o]; - } - }; - - }; - - - let __js_core_engine_misc_ = (_exports) => { - - - var CIQ = _exports.CIQ, - timezoneJS = _exports.timezoneJS; - - /** - * Given a browser time it will return the date in dataZone time. See {@link CIQ.ChartEngine#setTimeZone} for more details. - * If no dataZone is set, it will return the original date passed in. - * @param {date} browserDate Date in browser time - as in 'new Date();' - * @return {date} Date converted to dataZone - * @memberof CIQ.ChartEngine - * @since 07-2016-16.6 - */ - CIQ.ChartEngine.prototype.convertToDataZone = function (browserDate) { - if ((browserDate || browserDate === 0) && this.dataZone) { - // convert the current time to the dataZone - var tzNow = CIQ.convertTimeZone(browserDate, null, this.dataZone); - // remember the the masterData is in local time but really representing the dataZone time. - // now build a browser timezone time using the dataZone time so it will match the offset of the existing data in masterData. - browserDate = new Date( - tzNow.getFullYear(), - tzNow.getMonth(), - tzNow.getDate(), - tzNow.getHours(), - tzNow.getMinutes(), - tzNow.getSeconds(), - tzNow.getMilliseconds() - ); - } - return browserDate; - }; - - /** - * This method does nothing. It is just a known location to put a break point for debugging the kernel. - * @private - */ - CIQ.ChartEngine.prototype.debug = function () {}; - - /** - * Measures frames per second. Use this from the console. - * @param {number} [seconds = 5] Polling interval length - * @param {function} cb Callback to invoke when done polling - * @private - */ - CIQ.ChartEngine.prototype.fps = function (seconds, cb) { - seconds = seconds || 5; - var start = new Date().getTime(); - var frames = 0; - var self = this; - console.log("Running fps() for " + seconds + " seconds"); - - function render() { - var duration = (new Date().getTime() - start) / 1000; - if (duration > seconds) { - var fps = frames / duration; - console.log("FPS=" + fps); - if (cb) cb(fps); - return; - } - self.draw(); - frames++; - if (CIQ.ChartEngine.useAnimation) { - requestAnimationFrame(render); - } else { - setTimeout(render, 0); - } - } - render(); - }; - - // minimal here, see interaction file for complete list and docs - CIQ.ChartEngine.htmlControls = { - mSticky: - '

', - iconsTemplate: - '
' - }; - - /** - * Sets the base chart type for the primary symbol. - * @param {string} chartType The chart type. See CIQ.ChartEngine.layout.chartType for valid options. - * - * See {@tutorial Chart Styles and Types} for more details. - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.setChartType = function (chartType) { - var layout = this.layout, - chart = this.chart; - if (layout.aggregationType != "ohlc") { - layout.aggregationType = "ohlc"; - if (chart.canvas) this.createDataSet(); - } - layout.chartType = chartType; - this.setMainSeriesRenderer(); - if (this.mainSeriesRenderer.isAggregation && this.setAggregationType) - return this.setAggregationType(chartType); - chart.defaultChartStyleConfig = { type: chartType }; - if (this.displayInitialized) this.draw(); - this.changeOccurred("layout"); - }; - - CIQ.ChartEngine.prototype.setChartScale = function (chartScale) { - if (!chartScale) chartScale = "linear"; - var needsTransform = { - percent: true, - relative: true - }; - this.layout.chartScale = chartScale; - if (this.chart.canvas) this.draw(); - this.changeOccurred("layout"); - }; - - /** - * INJECTABLE - * Animation Loop - * - * Sets the chart y-axis to linear scale if: - * - the y-axis is currently set to log scale and - * - the chart data set contains a value less than or equal to zero. - * - * @return {boolean} true if log scale has been deactivated; otherwise false. - * - * @alias checkLogScale - * @memberof CIQ.ChartEngine.AdvancedInjectable# - * @since 8.2.0 - */ - CIQ.ChartEngine.prototype.checkLogScale = function () { - if (this.runPrepend("checkLogScale", arguments)) return; - if (this.layout.chartScale !== "log") return false; - let logScaleDeactivated = false; - - if (this.chart.yAxis.lowValue <= 0) { - this.setChartScale("linear"); - this.dispatch("notification", "logdeactivated"); - logScaleDeactivated = true; - } - this.runAppend("checkLogScale", arguments); - return logScaleDeactivated; - }; - - /** - * Sets the charts to adjusted values rather than standard values. Adjusted values are calculated outside of the chart engine (and may be splits, dividends or both). - * When charts are using adjusted values, a computed ratio for each tick is used for price to pixel calculations which keeps drawings accurate - * @param {boolean} data True to use adjusted values (Adj_Close), false to use Close values - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.setAdjusted = function (data) { - this.layout.adj = data; - if (this.chart.canvas) { - this.createDataSet(); - this.draw(); - } - this.changeOccurred("layout"); - }; - - /** - * Pads out the decimal places given only a price. - * - * It will not truncate or round, but will add zeroes as follows: - * - Prices under $2 will be padded to 4 decimal places, or to match the number of decimal places in `determinant`; whichever is larger. - * - Prices over $1,000 will not be padded, or set to match the number of decimal places in `determinant`, if any. - * - All other prices will be padded to 2 decimal places, or to match the number of decimal places in `determinant`; whichever is larger. - * @param {number} price A price - * @param {number} [determinant] Sample value to determine the decimal places. For - * instance, if you want to determine the number of decimals for today's change based on the actual price. - * @return {string} A price padded for decimal places - * @memberOf CIQ.ChartEngine - * @since 2016-07-16 - */ - CIQ.ChartEngine.prototype.padOutPrice = function (price, determinant) { - if (price !== 0 && (!price || typeof price != "number")) return ""; - if (!determinant && determinant !== 0) determinant = price; - var str = "" + determinant; - - var decimalPlaces = 0; - if (str.indexOf(".") > -1) - decimalPlaces = str.substring(str.indexOf(".")).length - 1; - - if (determinant >= 1000) decimalPlaces = Math.max(decimalPlaces, 0); - else if (determinant < 2) decimalPlaces = Math.max(decimalPlaces, 4); - else decimalPlaces = Math.max(decimalPlaces, 2); - - var internationalizer = this.internationalizer; - if (internationalizer) { - var l = internationalizer.priceFormatters.length; - if (decimalPlaces >= l) decimalPlaces = l - 1; - price = internationalizer.priceFormatters[decimalPlaces].format(price); - } else { - price = price.toFixed(decimalPlaces); - } - return price; - }; - - /** - * Formats a price according to the decimalPlaces specified in either the panel or chart. - * It will then format to international standards if the internationalizer is set. - * This method *does not* condense prices. - * @param {number} price The price to be formatted - * @param {CIQ.ChartEngine.Panel} panel The panel to use to determine the number of decimal places. - * @return {string} The formatted price - * @memberof CIQ.ChartEngine - * @since 6.2.0 Return value will always be a string. - */ - CIQ.ChartEngine.prototype.formatPrice = function (price, panel) { - if (price !== 0 && (!price || typeof price == "undefined")) return ""; - if (!panel) panel = this.currentPanel; - if (!panel) panel = this.chart.panel; - if (!panel) return price.toString(); - var decimalPlaces = panel.decimalPlaces; - if (!decimalPlaces && decimalPlaces !== 0) { - decimalPlaces = panel.chart.decimalPlaces; - } - if (!decimalPlaces && decimalPlaces !== 0) { - return price.toString(); - } - var internationalizer = this.internationalizer; - if (internationalizer) { - var l = internationalizer.priceFormatters.length; - if (decimalPlaces >= l) decimalPlaces = l - 1; - price = internationalizer.priceFormatters[decimalPlaces].format(price); - } else { - price = price.toFixed(decimalPlaces); - } - return price; - }; - - /** - * Determines the high and low values for the data set. - * - * Requires an array of fields to check. - * For instance, the array might contain `["Close","Series1","Series2"]` which would return - * the max and min of all of those values for each quote. - * - * If you wish to exclude certain fields from your calculations to prevent excessive flattening - * of the charts, you can overwrite this method as follows: - * ``` - * stxx.origDetermineMinMax = stxx.determineMinMax; - * stxx.determineMinMax = function(quotes, fields, sum, bypassTransform, length, checkArray) { - * // Add code here to remove anything you want from the 'fields' array. - * console.log('current fields', fields); - * return stxx.origDetermineMinMax(quotes, fields, sum, bypassTransform, length, checkArray); - * } - * ``` - * Also see {@link CIQ.ChartEngine.Chart#includeOverlaysInMinMax} - * - * @param {Array} quotes The array of quotes (typically `CIQ.ChartEngine.chart.dataSegment`) - * to evaluate for minimum and maximum values. - * @param {Array} fields A list of fields to compare. - * @param {boolean|string[]} [sum] If true, then compute maximum sum rather than the maximum - * single value across all fields. If an array, compute sum over just the fields in the - * array. - * @param {boolean} [bypassTransform] If true, then bypass any transformations. - * @param {number} [length] Specifies how much of the quotes array to process. - * @param {boolean} [checkArray] If true, the type of the value used to determine the min/max - * is checked to ascertain whether it is an array; if so, the first element of the array - * is retrieved for use in the min/max determination. - * @param {CIQ.ChartEngine.Panel} [panel] A reference to the panel rendering the quotes. - * @param {CIQ.ChartEngine.YAxis} [axis] A reference to the y-axis rendered for the quotes. - * @param {Array} [filters] Array of functions to process the min/max values before returning. - * Filter functions must return a valid min/max tuple or false. - * @return {Array} A tuple, min and max values. - * - * @memberof CIQ.ChartEngine - * @since - * - 2014-02 - * - 7.3.0 Added `checkArray` parameter. - * - 8.0.0 Allow the `sum` parameter to be an array of valid fields to sum over. Added - * the `panel`, `axis`, and `filters` parameters. - */ - CIQ.ChartEngine.prototype.determineMinMax = function ( - quotes, - fields, - sum, - bypassTransform, - length, - checkArray, - panel, - axis, - filters - ) { - var highValue = Number.MAX_VALUE * -1; - var lowValue = Number.MAX_VALUE; - var isTransform = false; - var l = quotes.length; - if (!filters) filters = []; - var highLowData = []; - if (length) l = length; - - for (var i = 0; i <= l + 1; i++) { - var quote; - // Here only the first field in the fields array is checked. A different approach might be to check all the fields. - if (fields.length) { - if (i == l) { - quote = this.getPreviousBar(this.chart, fields[0], 0); - } else if (i == l + 1) { - quote = this.getNextBar(this.chart, fields[0], l - 1); - } else quote = quotes[i]; - } - if (!quote) continue; - if (!bypassTransform) { - if (quote.transform) { - isTransform = true; - quote = quote.transform; - } else if (isTransform) continue; //don't include points without transforms if we have been including points with transforms - } - var acc = 0; - for (var j = 0; j < fields.length; j++) { - var tuple = CIQ.existsInObjectChain(quote, fields[j]); - if (!tuple) continue; - var f = tuple.obj[tuple.member]; - if (typeof f == "number") f = [f]; - for (var v = 0; v < f.length; v++) { - var val = f[v]; - if (checkArray && val instanceof Array) val = val[0]; - if (val || val === 0) { - if ( - sum === true || - (sum instanceof Array && sum.indexOf(fields[j]) > -1) - ) { - acc += val; - if (acc > highValue) highValue = acc; - if (acc < lowValue) lowValue = acc; - } else { - if (val > highValue) highValue = val; - if (val < lowValue) lowValue = val; - highLowData.push({ value: val, quote: quote }); - } - } - } - } - if (sum === true || (sum instanceof Array && sum.indexOf(fields[j]) > -1)) - highLowData.push({ value: acc, quote: quote }); - } - - var highLow = [lowValue, highValue]; - - filters.forEach(function (f) { - highLow = f(highLowData, panel, axis) || highLow; - }); - - if (highLow[1] == Number.MAX_VALUE * -1) highLow[1] = 0; - if (highLow[0] == Number.MAX_VALUE) highLow[0] = 0; - return highLow; - }; - - /** - * INJECTABLE - * Animation Loop - * - * This method initializes display variables for the chart. - * - * It is part of the animation loop and called with every [draw]{@link CIQ.ChartEngine#draw} operation.
- * The high and low values for the visible section of the primary chart are calculated and corresponding values stored as follows: - * - `chart.highValue` - The highest value on the chart - * - `chart.lowValue` - The lowest value on the chart - * - * See {@link CIQ.ChartEngine.Chart#includeOverlaysInMinMax} and {@link CIQ.ChartEngine#determineMinMax} - * - * Those values are subsequently used by {@link CIQ.ChartEngine.AdvancedInjectable#createYAxis} which is called from within this method.
- * This method also calls {@link CIQ.ChartEngine.AdvancedInjectable#createCrosshairs}. - * - * @param {CIQ.ChartEngine.Chart} chart The chart to initialize - * @memberof CIQ.ChartEngine.AdvancedInjectable# - * @alias initializeDisplay - * @since 5.2.0. It now also calculates the minimum and maximum points in all study panels. This calculation was previously done using {@link CIQ.Studies.determineMinMax}, now deprecated. - */ - CIQ.ChartEngine.prototype.initializeDisplay = function (chart) { - if (this.runPrepend("initializeDisplay", arguments)) return; - let fields = [], - useSum = [], - checkArray = false; - const self = this; - const baseOHLCFields = ["Close", "Open", "High", "Low"]; - const baseLineFields = [chart.defaultPlotField || "Close"]; - const { mainSeriesRenderer } = this; - const { dataSegment, seriesRenderers } = chart; - function setYAxisFields(yAxis, panel) { - // first see if this is an axis for a study; if so, get the fields - let isStudyAxis = false; - const sd = - self.layout && self.layout.studies && self.layout.studies[yAxis.name]; - if (sd && (!panel || panel.name == sd.panel)) { - for (const j in sd.outputMap) { - fields.push(j); - if (sd.study) { - if (sd.study.renderer) { - // if there is a study renderer, just assume it requires OHLC regardless of the renderer type - fields = fields.concat( - CIQ.createObjectChainNames(j, baseOHLCFields) - ); - } else if (!sd.study.seriesFN) { - // no seriesFN, assume it's a line and needs only Close - fields = fields.concat( - CIQ.createObjectChainNames(j, baseLineFields) - ); - } - } - } - for (let h = 0; h <= 2; h++) - fields.push(sd.name + "_hist" + (h ? h : "")); - isStudyAxis = true; - } - if (!panel) return; //to end recursion from includeOverlaysInMinMax below - - yAxis.studies = []; - yAxis.renderers = []; - if (isStudyAxis) { - yAxis.studies.push(yAxis.name); - } - // then check renderers and add fields for each series in the renderer using this yaxis - for (const id in seriesRenderers) { - const renderer = seriesRenderers[id], - params = renderer.params, - panelName = params.panel; - if ( - (params.yAxis || - !self.panels[panelName] || - self.panels[panelName].yAxis) != yAxis - ) - continue; - if (panelName != panel.name) continue; - const baseFields = renderer.highLowBars ? baseOHLCFields : baseLineFields; - checkArray = renderer.bounded; - for (let id2 = 0; id2 < renderer.seriesParams.length; id2++) { - // Find any series that share the Y axis - const seriesParams = renderer.seriesParams[id2]; - if (seriesParams.hidden) continue; - let fieldNamesToConcat; - if (seriesParams.subField) { - fieldNamesToConcat = CIQ.createObjectChainNames(seriesParams.symbol, [ - seriesParams.subField - ]).concat(seriesParams.symbol); - } else if (seriesParams.symbol) { - fieldNamesToConcat = CIQ.createObjectChainNames( - seriesParams.symbol, - baseFields - ).concat(seriesParams.symbol); - } else if (seriesParams.field) { - fieldNamesToConcat = seriesParams.field; - } else if (yAxis == chart.panel.yAxis) { - // only if the main chart panel's yAxis include baseFields - fieldNamesToConcat = baseFields; - } - if (fieldNamesToConcat) fields = fields.concat(fieldNamesToConcat); - if (renderer.useSum) useSum = useSum.concat(fieldNamesToConcat); - } - yAxis.renderers.push(id); - } - // Finally add any fields used by overlay studies - for (const overlay in self.overlays) { - const o = self.overlays[overlay]; - if (o.panel != panel.name) continue; - if (o.name == yAxis.name) continue; // don't loop thru the same axis twice and create duplicates - const oAxis = o.getYAxis(self); - if (oAxis != yAxis) continue; - yAxis.studies.push(o.name); - if (chart.includeOverlaysInMinMax) { - setYAxisFields({ name: o.name }); - } - } - } - let minMax; - let length = null; - - // We often have an extra tick hanging off the edge of the screen. We don't want this - // tick to affect the high and low calculation though. That causes jumpiness when - // zooming because the chart is alternately including and excluding that tick - let ticksOnScreen = Math.floor( - (chart.width - this.micropixels) / this.layout.candleWidth - ); - if (chart.scroll > chart.maxTicks && chart.maxTicks > ticksOnScreen + 1) - length = dataSegment.length - 1; - - let arr = []; - for (const p in this.panels) { - const myPanel = this.panels[p]; - arr = myPanel.yaxisLHS.concat(myPanel.yaxisRHS); - for (let y = 0; y < arr.length; y++) { - const yAxis = arr[y]; - fields = []; - useSum = []; - const doTransform = chart.transformFunc && yAxis == chart.panel.yAxis; - setYAxisFields(yAxis, myPanel); - // maintenance of axes here - if ( - !this.currentlyImporting && - !yAxis.renderers.length && - !yAxis.studies.length - ) { - this.deleteYAxisIfUnused(myPanel, yAxis); - continue; - } - if (mainSeriesRenderer && mainSeriesRenderer.determineMax) { - minMax = mainSeriesRenderer.determineMax( - dataSegment, - fields, - useSum, - !doTransform, - length, - checkArray, - myPanel, - yAxis - ); - } else { - minMax = this.determineMinMax( - dataSegment, - fields, - useSum, - !doTransform, - length, - checkArray, - myPanel, - yAxis - ); - } - - if (this.baselineHelper) minMax = this.setBaselineMinMax(minMax, yAxis); - - yAxis.lowValue = minMax[0]; - yAxis.highValue = minMax[1]; - if (yAxis == chart.panel.yAxis) { - chart.lowValue = yAxis.lowValue; - chart.highValue = yAxis.highValue; - } - } - } - const aggregation = chart.state.aggregation; - if (aggregation && aggregation.box) { - // Make room for X and O rendering since half of it lies beyond the high/low - chart.lowValue -= aggregation.box / 2; - chart.highValue += aggregation.box / 2; - } - - this.runAppend("initializeDisplay", arguments); - }; - - /** - * Sets the market definition on the chart. - * - * Once set, the definition will not change until it is explicitly set to something else by calling this method again. - * - * A new definition for a chart should only be set once, right before a new instrument is loaded with the {@link CIQ.ChartEngine#loadChart} call. - * Loading or modifying a market definition after a chart has loaded its data will result in unpredictable results. - * - * If a dynamic model is desired, where a new definition is loaded as different instruments are activated, see {@link CIQ.ChartEngine#setMarketFactory}. - * - * See {@link CIQ.Market} for market definition rules and examples. - * - * This is only required if your chart will need to know the operating hours for the different exchanges. - * - * If using a 24x7 chart, a market does not need to be set. - * @param {object} marketDefinition A market definition as required by {@link CIQ.Market} - * @param {CIQ.ChartEngine.Chart} chart An instance of {@link CIQ.ChartEngine.Chart} - * @memberof CIQ.ChartEngine - * @since 04-2016-08 - * @example - * stxx.setMarket({ - * name: 'My_Market', - * market_tz: 'My_Timezone', // Note you must specify the time zone for the market! - * rules: [ - * { 'dayofweek': 1, 'open': '08:00', 'close': '14:30' }, - * { 'dayofweek': 2, 'open': '08:00', 'close': '14:30' }, - * { 'dayofweek': 3, 'open': '08:00', 'close': '14:30' }, - * { 'dayofweek': 4, 'open': '08:00', 'close': '14:30' }, - * { 'dayofweek': 5, 'open': '08:00', 'close': '14:30' }, - * ], - * }); - */ - CIQ.ChartEngine.prototype.setMarket = function (marketDefinition, chart) { - if (!CIQ.Market) return; - if (!chart) chart = this.chart; - chart.market = new CIQ.Market(marketDefinition); - for (var session in this.layout.marketSessions) { - chart.market.disableSession(session, this.layout.marketSessions[session]); - } - }; - - /** - * Links the chart to a method that given a symbol object of form accepted by {@link CIQ.ChartEngine#loadChart}, can return a complete market definition object. - * Once linked, the market factory it will be used by the chart to ensure the market always matches the active instrument. - * This is only required if your chart will need to know the operating hours for the different exchanges. - * If using a 24x7 chart, a market factory does not need to be set. - * - * Please note that if using the default sample templates, this method is set to use the {@link CIQ.Market.Symbology} functions, which must be reviewed and adjust to comply with your quote feed and symbology format before they can be used. - * @param {function} factory A function that takes a symbolObject and returns a market definition. See {@link CIQ.Market} for instruction on how to create a market definition. See {@link CIQ.Market.Symbology.factory} for working example of a factory function. - * @memberof CIQ.ChartEngine - * @since 04-2016-08 - * @example - * // example of a market factory that returns a different market definition based on the symbol passed in - * sampleFactory=function(symbolObject){ - * var symbol=symbolObject.symbol; - * // isTypeX(symbol) is a function you would create to identify the market definition object that should be used. - * if( isType1(symbol) ) return type1DefinitionObject; - * if( isType2(symbol) ) return type2DefinitionObject; - * if( isType3(symbol) ) return type3DefinitionObject; - * return defaultDefinitionObject; - * }; - * - * var stxx=new CIQ.ChartEngine({container:document.querySelector(".chartContainer"), preferences:{labels:false, currentPriceLine:true, whitespace:0}}); - * stxx.setMarketFactory(sampleFactory); - */ - CIQ.ChartEngine.prototype.setMarketFactory = function (factory) { - this.marketFactory = factory; - }; - - /** - * Sets a timer to check for chart resizing. - * - * Normally, the chart is resized whenever the screen is resized by capturing a screen resize event. - * However, if charts are embedded in a windowing GUI, they may not receive window resize events. - * Ideally, `stxx.resizeChart()` should be called whenever a window is resized; however, if this is inconvenient, - * then the resize timer can be enabled to cover all bases. - * - * On initialization, CIQ.ChartEngine.resizeDetectMS is checked for the default resize checking interval. The default is 1,000 milliseconds. - * To turn off resize checking simply set CIQ.ChartEngine.resizeDetectMS=0; when you declare your CIQ.ChartEngine object. - * - * @param {number} ms Number of milliseconds to poll. Zero to stop checking. - * @memberof CIQ.ChartEngine - * @since 7.2.0 For browsers that support it, a [ResizeObserver](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver) is used instead of a timeout. - */ - - CIQ.ChartEngine.prototype.setResizeTimer = function (ms) { - this.resizeDetectMS = ms; - function closure(self, useObserver) { - var f = function () { - if (!self.chart.canvas) return; - if (!CIQ.isAndroid) { - if ( - self.chart.canvas.height != - Math.floor( - self.devicePixelRatio * self.chart.container.clientHeight - ) || - self.chart.canvas.width != - Math.floor(self.devicePixelRatio * self.chart.container.clientWidth) - ) { - self.resizeChart(); - } - } - }; - return function () { - // Adding throttling here to fix Chrome issue where benign error is sometimes thrown "ResizeObserver loop limit exceeded" - // Nevertheless, error seems to be caught by Karma and unit tests fail - // https://github.com/KingSora/OverlayScrollbars/issues/90 - if (typeof ResizeObserver !== "undefined") { - if (CIQ.ChartEngine.useAnimation) { - requestAnimationFrame(f); - } else { - setTimeout(f, 0); - } - } else f(); - }; - } - this.resizeHandle = CIQ.resizeObserver( - this.chart.container, - closure(this), - this.resizeHandle, - ms - ); - }; - - /** - * Returns an array of all the securities, series, and overlays that are drawn on the current panel. - * - * @memberof CIQ.ChartEngine - * @returns {object[]} The fields — in object-chain form — of the currently rendered objects. - * @since 7.2.0 - */ - CIQ.ChartEngine.prototype.getRenderedItems = function () { - var chart = this.chart, - currentPanel = this.currentPanel; - if (!currentPanel) return; - - var ohlc = ["Open", "High", "Low", "Close"]; - var close = ["Close"]; - var rendered = []; - for (var o in this.overlays) { - if (this.overlays[o].panel !== currentPanel.name) continue; - // use the keys so if we ever change how the output map is constructed we don't need to change it twice - rendered = rendered.concat(Object.keys(this.overlays[o].outputMap)); - } - for (var r in chart.seriesRenderers) { - var renderer = chart.seriesRenderers[r]; - if (renderer.params.panel != currentPanel.name) continue; - for (var rs in renderer.seriesParams) { - var sp = renderer.seriesParams[rs]; - var baseFields = renderer.highLowBars ? ohlc : close; - if (sp.subField) { - rendered = rendered - .concat(CIQ.createObjectChainNames(sp.symbol, [sp.subField])) - .concat(sp.symbol); - } else if (sp.symbol) { - rendered = rendered - .concat(CIQ.createObjectChainNames(sp.symbol, baseFields)) - .concat(sp.symbol); - } else if (sp.field) { - rendered.push(sp.field); - } else if (currentPanel == chart.panel) { - // only if on main chart panel include baseFields - rendered = rendered.concat(baseFields); - } - } - } - return rendered; - }; - - /** - * Sets a transformation and untransformation function. Transforms can be used to transform the Y-Axis from absolute - * to relative values. For instance, comparison charts use a transform that adjusts from price to percentage. - * After this is called, chart.transformFunc and chart.untransformFunc will be set to those functions. - * @param {CIQ.ChartEngine.Chart} chart The chart to transform - * @param {function} transformFunction A transformation callback function which takes a number and returns the transformation of that number - * @param {function} untransformFunction An untransformation callback function - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.setTransform = function ( - chart, - transformFunction, - untransformFunction - ) { - chart.transformFunc = transformFunction; - chart.untransformFunc = untransformFunction; - }; - - /** - * Removes a transformation/untransformation pair - * @param {CIQ.ChartEngine.Chart} chart The chart to remove transformations from - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.unsetTransform = function (chart) { - delete chart.transformFunc; - delete chart.untransformFunc; - for (var i = 0; chart.dataSet && i < chart.dataSet.length; i++) { - chart.dataSet[i].transform = null; - } - }; - - CIQ.ChartEngine.prototype.isEquationChart = function (symbol) { - if (symbol && symbol[0] == "=") { - if (!this.allowEquations || !CIQ.fetchEquationChart) { - console.warn( - "Error, equation chart option requires equationsAdvanced.js" - ); - return false; - } - return true; - } - return false; - }; - - /** - * INJECTABLE - * Animation Loop - * - * This method ensures that the chart is not scrolled off of either of the vertical edges. - * See {@link CIQ.ChartEngine#minimumLeftBars}, {@link CIQ.ChartEngine.Chart#allowScrollPast}, and {@link CIQ.ChartEngine.Chart#allowScrollFuture} for adjustments to defaults. - * @param {CIQ.ChartEngine.Chart} theChart The chart to check - * @memberof CIQ.ChartEngine.AdvancedInjectable# - * @alias correctIfOffEdge - */ - CIQ.ChartEngine.prototype.correctIfOffEdge = function (theChart) { - if (this.runPrepend("correctIfOffEdge", arguments)) return; - for (var chartName in this.charts) { - var chart = this.charts[chartName], - dataSet = chart.dataSet, - maxTicks = chart.maxTicks, - layout = this.layout; - - var minimumLeftBars = this.minimumLeftBars; - - var leftPad = Math.min(minimumLeftBars, maxTicks); // in case the minimumLeftBars is larger than what we can display - if (chart.allowScrollPast) { - // allow scrolling from left to right, creating white space on either side - var rightPad = maxTicks - leftPad; - if (leftPad > dataSet.length) { - rightPad = maxTicks - dataSet.length; - } - if (chart.scroll - rightPad >= dataSet.length) { - chart.scroll = dataSet.length + rightPad - 1; - this.micropixels = 0; - } - if (chart.scroll <= leftPad) { - chart.scroll = leftPad; - this.micropixels = 0; - } - } else { - // earliest point in time is always anchored on left side of chart - if (chart.scroll < leftPad) { - chart.scroll = leftPad; - } - if (chart.scroll > dataSet.length) { - chart.scroll = dataSet.length; - } - } - if (chart.allowScrollFuture === false) { - var whitespace = - this.getLabelOffsetInPixels(chart, layout.chartType) + - layout.candleWidth * chart.whiteSpaceFutureTicks; - var barsOnScreen = - maxTicks - Math.round(whitespace / layout.candleWidth) - 1; - var scroll = this.micropixels < 0 ? chart.scroll - 1 : chart.scroll; - if (scroll < barsOnScreen) { - chart.scroll = barsOnScreen; - this.micropixels = 0; - } - } - } - this.runAppend("correctIfOffEdge", arguments); - }; - - /** - * Returns the offset from the left side of the screen for the first element - * on the chart screen. Most times this will be zero except when a user has scrolled - * past the end of the chart in which case it will be a positive number. This can be used - * to recreate a saved chart. - * @return {number} The offset from the left of the chart. - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.getStartDateOffset = function () { - for (var ds = 0; ds < this.chart.dataSegment.length; ds++) { - if (this.chart.dataSegment[ds]) { - return ds; - } - } - return 0; - }; - - /** - * Scrolls the chart so that the leftmost tick is the requested date. - * The date must be an exact match and data for that bar must already be loaded in the chart. - * There is no effect if the date is not found an the engine will not attempt to fetch more data. - * @param {date} dt The requested date - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.setStartDate = function (dt) { - for (var i = 0; i < this.chart.dataSet.length; i++) { - var bar = this.chart.dataSet[i]; - if (bar.DT.getTime() == dt.getTime()) { - this.chart.scroll = this.chart.dataSet.length - i; - this.draw(); - return; - } - } - }; - - //@private - CIQ.ChartEngine.prototype.clearPixelCache = function () { - for (var x in this.panels) { - var panel = this.panels[x]; - panel.cacheHigh = null; - panel.cacheLow = null; - panel.cacheLeft = 1000000; - panel.cacheRight = -1; - } - for (var chartName in this.charts) { - var chart = this.charts[chartName]; - if (!chart.dataSet) continue; - for (var i = 0; i < chart.dataSet.length; i++) { - chart.dataSet[i].cache = {}; - } - } - }; - - /** - * This method adjusts the canvas for the current backing store. The backing store is used on "retina" style devices - * to indicate the ratio of actual screen pixels to web pixels. The canvas is adjusted according to this ratio so that - * pixels appear at the expected size and aren't fuzzy. Note that backing store is sometimes also employed by browsers - * to change the size of the view. - * @private - * @param {HTMLCanvasElement} canvas An HTML5 canvas - * @param {external:CanvasRenderingContext2D} context An HTML5 canvas context - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.adjustBackingStore = function (canvas, context) { - this.devicePixelRatio = window.devicePixelRatio || 1; - //note, let's ignore DPR<1, it is not consistently implemented on all browsers between retina and nonretina displays - if (this.devicePixelRatio < 1.0) this.devicePixelRatio = 1.0; - var backingStoreRatio = - context.webkitBackingStorePixelRatio || - context.mozBackingStorePixelRatio || - context.msBackingStorePixelRatio || - context.oBackingStorePixelRatio || - context.backingStorePixelRatio || - 1; - - var ratio = this.devicePixelRatio / backingStoreRatio; - - if (!this.useBackingStore) { - this.devicePixelRatio = this.adjustedDisplayPixelRatio = 1; - return; - } - if (!CIQ.isAndroid || CIQ.is_chrome || CIQ.isFF) { - var oldWidth = canvas.width; - var oldHeight = canvas.height; - - canvas.width = oldWidth * ratio; - canvas.height = oldHeight * ratio; - - canvas.style.width = oldWidth + "px"; - canvas.style.height = oldHeight + "px"; - - context.scale(ratio, ratio); - this.adjustedDisplayPixelRatio = ratio; - this.backing = { - ratio: ratio, - width: canvas.width, - height: canvas.height, - styleWidth: oldWidth, - styleHeight: oldHeight - }; - } - }; - - CIQ.ChartEngine.prototype.reconstituteBackingStore = function () { - if (!this.useBackingStore || !this.backing) return; - var canvases = [this.chart.canvas]; - if (this.useBackgroundCanvas) canvases.push(this.chart.backgroundCanvas); - var backing = this.backing; - canvases.forEach(function (canvas) { - if (canvas.width == backing.width) return; - - canvas.width = backing.width; - canvas.height = backing.height; - - canvas.context.scale(backing.ratio, backing.ratio); - }); - this.adjustedDisplayPixelRatio = backing.ratio; - this.draw(); - }; - - CIQ.ChartEngine.prototype.disableBackingStore = function () { - if (!this.useBackingStore || !this.backing) return; - var canvases = [this.chart.canvas]; - if (this.useBackgroundCanvas) canvases.push(this.chart.backgroundCanvas); - var backing = this.backing; - canvases.forEach(function (canvas) { - if (canvas.width == backing.styleWidth) return; - - canvas.width = backing.styleWidth; - canvas.height = backing.styleHeight; - - canvas.context.scale(1, 1); - }); - this.adjustedDisplayPixelRatio = 1; - this.draw(); - }; - - /** - * Determines the appropriate canvas on which to draw background plots (gridlines and axes). If - * {@link CIQ.ChartEngine#useBackgroundCanvas} is true, background plots are drawn on the chart - * background canvas; if false, on the chart main canvas. - * - * @param {CIQ.ChartEngine.Chart} chart The chart from which the canvas is obtained. - * @return {HTMLElement} Either the chart's main canvas or background canvas, depending - * on the value of {@link CIQ.ChartEngine#useBackgroundCanvas}. - * @memberof CIQ.ChartEngine - * @since 7.4.0 - */ - CIQ.ChartEngine.prototype.getBackgroundCanvas = function (chart) { - if (!chart) chart = this.chart; - return this.useBackgroundCanvas ? chart.backgroundCanvas : chart.canvas; - }; - - /** - * This method resizes the canvas to the dimensions of the containing div. This is called primarily - * by {@link CIQ.ChartEngine#resizeChart} and also when the chart is initialized (via loadChart). - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.resizeCanvas = function () { - var canvas = this.chart.canvas; - var context = this.chart.context; - if (canvas && context) { - this.floatCanvas.height = this.chart.tempCanvas.height = this.chart.backgroundCanvas.height = canvas.height = this.chart.container.clientHeight; - this.floatCanvas.width = this.chart.tempCanvas.width = this.chart.backgroundCanvas.width = canvas.width = this.chart.container.clientWidth; - this.adjustBackingStore(canvas, context); - this.adjustBackingStore( - this.chart.tempCanvas, - this.chart.tempCanvas.context - ); - this.adjustBackingStore(this.floatCanvas, this.floatCanvas.context); - this.adjustBackingStore( - this.chart.backgroundCanvas, - this.chart.backgroundCanvas.context - ); - } - var rect = this.container.getBoundingClientRect(); - this.top = rect.top; - this.left = rect.left; - this.canvasWidth = this.chart.canvasWidth = this.chart.container.clientWidth; - this.right = this.left + this.canvasWidth; - this.height = this.chart.container.clientHeight; - this.width = this.right - this.left; - if ( - this.width === 0 && - !this.container.dimensionlessCanvas && - this.container.closest("html") - ) { - console.log("warning: zero width chart. Check CSS for chart container."); - } - this.bottom = this.top + this.height; - this.calculateYAxisPositions(); - this.chart.canvasRight = this.right; - this.chart.canvasHeight = this.height; - var candleWidth = this.layout.candleWidth; - if (typeof candleWidth == "undefined") candleWidth = 8; - for (var chartName in this.charts) { - var chart = this.charts[chartName]; - - this.setCandleWidth(candleWidth, chart); - if (chart.scroll < chart.width / candleWidth) { - chart.scroll = Math.floor(chart.width / candleWidth); - var wsInTicks = Math.round( - this.preferences.whitespace / this.layout.candleWidth - ); - chart.scroll -= wsInTicks; - } - - var idealNumberOfTicks = 10; - var appxLabelWidth; - try { - appxLabelWidth = context.measureText("10:00").width * 2; - } catch (e) { - appxLabelWidth = 100; - } - while (idealNumberOfTicks > 1) { - if (this.chart.width / appxLabelWidth > idealNumberOfTicks) break; - idealNumberOfTicks /= 1.5; - } - chart.xAxis.autoComputedTickSizePixels = Math.round( - this.chart.width / idealNumberOfTicks - ); - if (chart.xAxis.autoComputedTickSizePixels < 1) - chart.xAxis.autoComputedTickSizePixels = 1; - } - }; - - /** - * Sets the candleWidth for the chart. The candleWidth represents the number of horizontal pixels from the start - * of one bar or candle to the start of the next. This also applies to line charts. It is effectively, the horizontal zoom. - * The candleWidth can be read from layout.candleWidth. - * - * Method also ensures that the new candleWidth is not less than {@link CIQ.ChartEngine.Chart#minimumCandleWidth} and not more than - * {@link CIQ.ChartEngine.Chart#maximumCandleWidth}. If either of these is the case, candleWidth will be set to whichever value is closer. - * - * **Note**: if calling `setCandleWidth()` before `loadChart()`, with a value less than `minimumCandleWidth`, `loadChart()` will reset the candle size to the default candle size (8 pixels). - * - * @param {number} newCandleWidth The new candle width. If less than or equal to 0, it will be reset to 8 - * @param {CIQ.ChartEngine.Chart} [chart] Which chart to set the candleWidth. Defaults to the default chart. - * @memberof CIQ.ChartEngine - * @example - * stxx.setCandleWidth(10); - * stxx.home(); // home() is preferred over draw() in this case to ensure the chart is properly aligned to the right most edge. - - */ - CIQ.ChartEngine.prototype.setCandleWidth = function (newCandleWidth, chart) { - if (!chart) chart = this.chart; - newCandleWidth = this.constrainCandleWidth(newCandleWidth); - this.layout.candleWidth = newCandleWidth; - //chart.maxTicks=Math.ceil(this.chart.width/newCandleWidth+0.5); // we add half of a candle back in because lines and mountains only draw to the middle of the bar - chart.maxTicks = Math.round(chart.width / newCandleWidth) + 1; - }; - - /** - * Ensures that a candle width value is within the limits of {@link CIQ.ChartEngine#minimumCandleWidth} - * and {@link CIQ.ChartEngine#maximumCandleWidth}. - * - * @param {number} candleWidth The candle width to be checked. - * @return {number} The value of `candleWidth` if `candleWidth` is between `minimumCandleWidth` and `maximumCandleWith`. - * Otherwise, `minimumCandleWidth` if `candleWidth` is less than `minimumCandleWidth`. Otherwise, `maximumCandleWith` - * if `candleWidth` is greater than `maximumCandleWith`. - * @memberof CIQ.ChartEngine - * @since 7.4.0 - */ - CIQ.ChartEngine.prototype.constrainCandleWidth = function (candleWidth) { - var minimumCandleWidth = this.minimumCandleWidth; - var maximumCandleWidth = this.maximumCandleWidth; - var animating = this.animations.zoom; - if (minimumCandleWidth && candleWidth < minimumCandleWidth) { - candleWidth = minimumCandleWidth; - if (animating && animating.running) animating.stop(); - } - if (maximumCandleWidth && candleWidth > maximumCandleWidth) { - candleWidth = maximumCandleWidth; - if (animating && animating.running) animating.stop(); - } - return candleWidth; - }; - - /** - * INJECTABLE - * - * Resizes the chart and adjusts the panels. The chart is resized to the size of the container div by calling - * {@link CIQ.ChartEngine#resizeCanvas}. This method is called automatically if a screen resize event occurs. The charting - * engine also attempts to detect size changes whenever the mouse is moved. Ideally, if you know the chart is being - * resized, perhaps because of a dynamic change to the layout of your screen, you should call this method manually. - * @param {boolean} [maintainScroll=true] By default the scroll position will remain pegged on the right side of the chart. Set this to false to override. - * @memberof CIQ.ChartEngine - * @since - * - 2015-11-1 `resizeChart` now automatically retains scroll position. - * - 09-2016-19 `resizeChart` now also manages the resizing of the crosshairs. - */ - CIQ.ChartEngine.prototype.resizeChart = function (maintainScroll) { - if (this.runPrepend("resizeChart", arguments)) return; - if (maintainScroll !== false) maintainScroll = true; - if (maintainScroll) this.preAdjustScroll(); - var previousHeight = this.chart.canvasHeight; - this.resizeCanvas(); - if (maintainScroll) this.postAdjustScroll(); - if (this.displayInitialized) { - this.adjustPanelPositions(); - this.draw(); - // This second case occurs if a chart was initialized hidden but now - // has suddenly been revealed. displayInitialized hadn't been set yet - // because draw() has never been completed - } else if (this.chart.canvasHeight !== 0 && previousHeight === 0) { - this.adjustPanelPositions(); - this.draw(); - } - - //redraw the crosshairs to adjust to the new size of the screen. - this.doDisplayCrosshairs(); - this.updateChartAccessories(); - - this.runAppend("resizeChart", arguments); - }; - - /** - * Removes any studies from the chart, and hides the chart controls. - * The chart becomes uninitialized, disabling any interaction with it. - * The canvas is not cleared; {@link CIQ.clearCanvas} can do that. - * - * Useful when a chart is loaded with no data due to a quoteFeed error. Automatically called by {@link CIQ.ChartEngine#loadChart} - * - * @memberof CIQ.ChartEngine - * @since 2016-12-01 - */ - CIQ.ChartEngine.prototype.clear = function () { - this.displayInitialized = false; - - for (var id in this.layout.studies) { - var sd = this.layout.studies[id]; - CIQ.getFn("Studies.removeStudy")(this, sd); - } - - if (this.controls.chartControls) - this.controls.chartControls.style.display = "none"; - - this.chart.panel.title.innerHTML = ""; - this.chart.panel.title.appendChild( - document.createTextNode(this.chart.panel.display) - ); - }; - - /** - * Adjusts the candleWidth to eliminate left-side gaps on the chart if not enough bars are loaded. - * - * Used by the `stretchToFillScreen` parameter of {@link CIQ.ChartEngine#loadChart} - * @memberof CIQ.ChartEngine - * @since 4.0.0 This function is now public. - */ - CIQ.ChartEngine.prototype.fillScreen = function () { - var chart = this.chart; - var candleWidth = this.layout.candleWidth; - var chartWidth = chart.width - this.preferences.whitespace; - var count = chart.dataSet.length; - - if (count * candleWidth >= chartWidth) { - this.draw(); - return; - } - - // line-type charts go center-to-center in the data point space, so we end up which 1/2 a candle empty on the left and the right.. - //so if we remove a candle from the calculations, we go edge to edge. - if (!this.mainSeriesRenderer || !this.mainSeriesRenderer.standaloneBars) - count--; - - var newCandleWidth = chartWidth / count; - this.setCandleWidth(newCandleWidth, chart); - this.home({ maintainWhitespace: true }); - }; - - /** - * Sets the maximimum number of ticks to the requested number. This is effected by changing the candleWidth. - * See also {@link CIQ.ChartEngine#setCandleWidth}. - * - * **Note**: if calling `setMaxTicks()` before `loadChart()`, and the chart will result in a candle width less than `minimumCandleWidth`, `loadChart()` will reset the candle size to the default candle size (8 pixels). - * - * @param {number} ticks The number of ticks wide to set the chart. - * @param {object} [params] Parameters to use with this function. - * @param {number} params.padding Whitespace in pixels to add to the right of the chart. - * Setting this field will home the chart to the most recent tick. - * To home the chart without padding the right side with whitespace, set padding to 0. - * Omitting the padding field will keep the chart scrolled to the same position. - * @since 2015-11-1 Added `params` object. - * @memberof CIQ.ChartEngine - * @example - * stxx.setMaxTicks(300); - * stxx.home(); // home() is preferred over draw() in this case to ensure the chart is properly aligned to the right most edge. - */ - CIQ.ChartEngine.prototype.setMaxTicks = function (ticks, params) { - if (!params) params = {}; - ticks = Math.round(ticks); - if (ticks < 2) ticks = 2; - var pad = params.padding ? params.padding : 0; - this.layout.candleWidth = (this.chart.width - pad) / ticks; - if (!this.layout.candleWidth) this.layout.candleWidth = 8; // Zero candlewidth can only occur if the chart has no width. This might happen if the chart is in a hidden iframe - this.chart.maxTicks = Math.round( - this.chart.width / this.layout.candleWidth - 0.499 - ); - if (params.padding || params.padding === 0) this.chart.scroll = ticks + 1; // If padding, then by definition we're homing - }; - - /** - * INJECTABLE - * - * This method initializes the chart container events, such as window `resize` events, - * and the [resizeTimer]{@link CIQ.ChartEngine#setResizeTimer} to ensure the chart adjusts as its container size changes. - * It also initializes various internal variables, the canvas and creates the chart panel. - * - * This is called by {@link CIQ.ChartEngine#loadChart} and should rarely be called directly. - * - * Note that the candle width will be reset to 8px if larger than 50px. Even if the value comes from a layout import. - * This is done to ensure a reasonable candle size is available across devices that may have different screen size. - * - * @param {HTMLElement} [container] Node that contains the chart. - * @memberof CIQ.ChartEngine - * - */ - CIQ.ChartEngine.prototype.initializeChart = function (container) { - if (this.runPrepend("initializeChart", arguments)) return; - var chart = this.chart; - if (!chart.symbolObject.symbol) chart.symbolObject.symbol = chart.symbol; // for backwards compatibility so the symbol object is always initialized in case we don't use loadChart() - if (this.locale) this.setLocale(this.locale); - if (!this.displayZone && CIQ.ChartEngine.defaultDisplayTimeZone) { - this.setTimeZone(null, CIQ.ChartEngine.defaultDisplayTimeZone); - } - this.resetDynamicYAxis({ noRecalculate: true }); - this.calculateYAxisPositions(); - this.micropixels = 0; - - if (container) chart.container = container; - else container = chart.container; - container.stx = this; - if (!container.CIQRegistered) { - container.CIQRegistered = true; - CIQ.ChartEngine.registeredContainers.push(container); - } - if (this.registerHTMLElements) this.registerHTMLElements(); // Sets all of the internal HTML elements to those in the container - var canvas = chart.canvas, - backgroundCanvas = chart.backgroundCanvas, - tempCanvas = chart.tempCanvas, - floatCanvas = this.floatCanvas, - canvasShim = chart.canvasShim; - if (canvas && document.createElement("canvas").getContext) { - if (!canvas.id) { - //Don't play with canvases which have id's since you don't own them - container.removeChild(canvas); - chart.canvas = null; - } - if (tempCanvas && !tempCanvas.id) { - container.removeChild(tempCanvas); - chart.tempCanvas = null; - } - if (floatCanvas && !floatCanvas.id) { - container.removeChild(floatCanvas); - this.floatCanvas = null; - } - if (backgroundCanvas && !backgroundCanvas.id) { - container.removeChild(backgroundCanvas); - chart.backgroundCanvas = null; - } - } else { - // Just make sure the candleWidth is sane - this.setCandleWidth(this.layout.candleWidth); - } - - function styleCanvas(canv, hide) { - canv.context = canv.getContext("2d"); - canv.context.lineWidth = 1; - var canvasStyle = canv.style; - canvasStyle.position = "absolute"; - canvasStyle.left = "0px"; - if (hide) canvasStyle.display = "none"; - } - - if (!chart.backgroundCanvas) - backgroundCanvas = chart.backgroundCanvas = document.createElement( - "canvas" - ); - container.appendChild(backgroundCanvas); - styleCanvas(backgroundCanvas); - - if (!chart.canvasShim) - canvasShim = chart.canvasShim = document.createElement("div"); - canvasShim.className = "stx-canvas-shim"; - container.appendChild(canvasShim); - - if (!chart.canvas) canvas = chart.canvas = document.createElement("canvas"); - container.appendChild(canvas); - styleCanvas(canvas); - chart.context = canvas.context; - - if (!chart.tempCanvas) - tempCanvas = chart.tempCanvas = document.createElement("canvas"); - container.appendChild(tempCanvas); - styleCanvas(tempCanvas, true); - - if (!this.floatCanvas) - floatCanvas = this.floatCanvas = document.createElement("canvas"); - container.appendChild(floatCanvas); - styleCanvas(floatCanvas, true); - - this.resizeCanvas(); - - if (CIQ.isAndroid) { - tempCanvas.ontouchstart = floatCanvas.ontouchstart = function (e) { - if (e.preventDefault) e.preventDefault(); - }; - } - - var panels = this.panels; - chart.panel.display = chart.symbol; - if (chart.symbolDisplay) chart.panel.display = chart.symbolDisplay; - this.adjustPanelPositions(); - chart.panel = panels[chart.name]; - - for (var p in panels) { - var yAxes = panels[p].yaxisLHS.concat(panels[p].yaxisRHS); - for (var a = 0; a < yAxes.length; a++) { - yAxes[a].height = panels[p].yAxis.height; // set the [overlay] yAxis height to the panel's main yAxis height... - this.calculateYAxisMargins(yAxes[a]); // ...so this will work - } - } - - this.initialWhitespace = this.preferences.whitespace; - if (chart.dataSet && chart.dataSet.length > 0) { - chart.scroll = Math.floor(chart.width / this.layout.candleWidth); //chart.maxTicks; - var wsInTicks = Math.round( - this.preferences.whitespace / this.layout.candleWidth - ); - chart.scroll -= wsInTicks; - } - if (CIQ.touchDevice) { - var overlayEdit = container.querySelector(".overlayEdit"); - var overlayTrashCan = container.querySelector(".overlayTrashCan"); - var vectorTrashCan = container.querySelector(".vectorTrashCan"); - var cb = function (self, callRightClick, forceEdit) { - return function (e) { - self.deleteHighlighted(callRightClick, forceEdit); - }; - }; - if (overlayEdit) { - CIQ.safeClickTouch(overlayEdit, cb(this, true, true)); - if (overlayTrashCan) { - CIQ.safeClickTouch(overlayTrashCan, cb(this, false)); - } - } else if (overlayTrashCan) { - CIQ.safeClickTouch(overlayTrashCan, cb(this, true)); - } - if (vectorTrashCan) { - CIQ.safeClickTouch(vectorTrashCan, cb(this, true)); - } - } - if (this.manageTouchAndMouse) { - this.registerTouchAndMouseEvents(); - } - if (this.handleMouseOut) { - container.onmouseout = (function (self) { - return function (e) { - self.handleMouseOut(e); - }; - })(this); - CIQ.smartHover(); - } - - if (this.abortDrawings) this.abortDrawings(); - this.undoStamps = []; - for (var panelName in panels) { - var panel = panels[panelName]; - if (panel.markerHolder) { - container.removeChild(panel.markerHolder); - panel.markerHolder = null; - } - } - for (var i in this.plugins) { - var plugin = this.plugins[i]; - if (plugin.display) { - if (plugin.initializeChart) plugin.initializeChart(this); - } - } - // This sets a resize listener for when the screen itself is resized. - if (!this.resizeListenerInitialized) { - var self = this; - this.resizeListenerInitialized = true; - var resizeListener = function () { - return function (e) { - self.resizeChart(); - }; - }; - this.addDomEventListener(window, "resize", resizeListener(), true); - } - if (chart.baseline.userLevel) chart.baseline.userLevel = null; - // This sets the interval timer which checks fore resize condition every X milliseconds (if non zero) - this.setResizeTimer(this.resizeDetectMS); - this.runAppend("initializeChart", arguments); - }; - - /** - * Clears out a chart engine instantiated with [new CIQ.ChartEngine()]{@link CIQ.ChartEngine}, - * eliminating all references including the resizeTimer, quoteDriver, styles and eventListeners. - * - * It's still up to the developer to set the declared pointer for the instance to null so that the garbage collector can remove it. - * - * Please note that **this method will not remove the chart container or any elements within it, even if they were created by the engine**. - * To do that, execute `stx.container.remove();` to remove the chartContainer DOM elements, - * and then call this method to remove the chart engine itself. See example. - * - * - * This method should only be used when you no longer need the chart engine and **never** be used in between {@link CIQ.ChartEngine#loadChart} calls to load or change symbols. - * @memberof CIQ.ChartEngine - * @example - * // create - * var stxx=new CIQ.ChartEngine({container: document.querySelector(".chartContainer")}); - * - * // execute this line to remove the chart container
and its sub elements - * stxx.container.remove(); - * - * //destroy engine - * stxx.destroy(); - * - * //remove - * stxx = null; - */ - CIQ.ChartEngine.prototype.destroy = function () { - this.setResizeTimer(0); - if (this.quoteDriver) this.quoteDriver.die(); - this.styles = {}; // Get rid of any external style references that could cause us to hang around - for (var i = 0; i < this.eventListeners.length; i++) { - var listener = this.eventListeners[i]; - listener.element.removeEventListener( - listener.event, - listener["function"], - listener.options - ); - } - this.touchAndMouseEventsRegistered = false; - this.eventListeners = []; - if (this.streamParameters.timeout) - clearTimeout(this.streamParameters.timeout); - - // remove chart container from registeredContainers - var registeredContainers = CIQ.ChartEngine.registeredContainers; - var chartIndex = registeredContainers.indexOf(this.chart.container); - if (chartIndex > -1) { - registeredContainers.splice(chartIndex, 1); - } - - // remove matching range slider - if (this.slider) { - var sliderIndex = registeredContainers.indexOf( - this.slider.slider.chart.container - ); - if (sliderIndex > -1) { - registeredContainers.splice(sliderIndex, 1); - } - } - }; - - /** - * Call this before a resizing operation in order to maintain the scroll position. See {@link CIQ.ChartEngine#postAdjustScroll}. - * @param {CIQ.ChartEngine.Chart} [chart] The chart to adjust. Otherwise adjusts the main symbol chart. - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.preAdjustScroll = function (chart) { - if (!chart) chart = this.chart; - this.previousAdjust = { - chart: chart, - scroll: chart.scroll, - maxTicks: chart.maxTicks - }; - }; - - /** - * Call this after a resizing operation in order to maintain the scroll position. See {@link CIQ.ChartEngine#preAdjustScroll}. - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.postAdjustScroll = function () { - if (!this.previousAdjust) return; - var chart = this.previousAdjust.chart; - chart.scroll = - this.previousAdjust.scroll + - (chart.maxTicks - this.previousAdjust.maxTicks); - if (this.displayInitialized) this.draw(); - }; - - /** - * Translates the requested word to the active language if this.translationCallback callback function is set. - * - * Use {@link CIQ.translatableTextNode} if you are adding the element to the DOM and wish the translations services to automatically change to other languages as they are set. - * @param {string} english The word to translate - * @return {string} The translated word, or the word itself if no callback is set. - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.translateIf = function (english) { - if (this.translationCallback) return this.translationCallback(english); - return english; - }; - - /** - * This method is used to prepare date fields for internal use. It will: - * - convert dates to a JS Date in the timeZone set by [setTimeZone(dataZone)]{@link CIQ.ChartEngine#setTimeZone}. - * - subsequently strip off the time portion on daily, weekly and monthly intervals. - * - * - If the date ('DT' or 'Date') does not include a time offset, such as 'yyyy-mm-dd', - * no time zone conversion will be performed. Use this option if you prefer to display the same date on all timezones. - * This applies to daily, weekly and monthly periodicities only. - * - * @param {array} quotes The quote array to be converted - * @param {string} interval Interval of the quotes ("day", "week", etc). - * @memberof CIQ.ChartEngine - * @since - * - 4.0.0 - * - 5.2.0 Used on intraday and daily quotes to also convert dates to the indicated `dataZone` as set by [setTimeZone(dataZone)]{@link CIQ.ChartEngine#setTimeZone}. - */ - CIQ.ChartEngine.prototype.doCleanupDates = function (quotes, interval) { - if (!quotes || !quotes.length) return; - for (var i = 0; i < quotes.length; i++) { - var quote = quotes[i], - date = quote.DT; - if (!date && !quote.Date) continue; - if ( - quote.DT && - Object.prototype.toString.call(date) == "[object String]" && - date.length <= 10 - ) { - // only date portion provided on DT field, no conversion - date = new Date(date); - date.setMinutes(date.getMinutes() + date.getTimezoneOffset()); - } else { - var useDataZone = true; - if (!quote.DT) { - date = CIQ.strToDateTime(quote.Date); - if (quote.Date.length <= 10) useDataZone = false; - } - if (Object.prototype.toString.call(date) != "[object Date]") - date = new Date(date); // if already a date object; nothing to do - if (timezoneJS.Date && this.dataZone && useDataZone) { - // convert dates before setting a quotes canonical DT object - var newDT = new timezoneJS.Date( - date.getFullYear(), - date.getMonth(), - date.getDate(), - date.getHours(), - date.getMinutes(), - this.dataZone - ); - var milli = date.getSeconds() * 1000 + date.getMilliseconds(); - date = new Date(newDT.getTime() + milli); - } - if (CIQ.ChartEngine.isDailyInterval(interval)) date.setHours(0, 0, 0, 0); - } - if (!quote.DT) quote.Date = CIQ.yyyymmddhhmmssmmm(date); // Set the Date to the adjusted date but only if there was no DT provided - quote.DT = date; - } - }; - - /** - * If {@link CIQ.ChartEngine#cleanupGaps} is set, this method will insert bars in an array of quotes for those periods missing a record according to the market hours and the current periodicity. - * See "{@link CIQ.Market}" for details on how to properly configure the library to your market hours requirements. - * - * This method will not be called for `tick` since by nature it is no a predictable interval. - * - * This method is automatically called if you are using a quoteFeed and have {@link CIQ.ChartEngine#cleanupGaps} set, but can be manually called if pushing or streaming data into the chart. - * - * This method will affect intraday and **underlying daily** periods **only**. If the feed is already returning weekly and monthly data rolled up, the clean up will not be done ( see {@link CIQ.ChartEngine#dontRoll} ). - * - * See {@link CIQ.ChartEngine#cleanupGaps}, for more details. - * - * @param {array} quotes The quote array to be gap-filled - * @param {CIQ.ChartEngine.Chart} [chart] Chart object to target. - * @param {object} [params] Parameters - * @param {string} [params.cleanupGaps] Pass this in to override the {@link CIQ.ChartEngine#cleanupGaps} value. - * @param {boolean} [params.noCleanupDates] If true then dates have been cleaned up already by calling {@link CIQ.ChartEngine#doCleanupDates}, so do not do so in here. - * @param {string} [params.field] Set to a field to fill gaps, or leave out to use chart.defaultPlotField. - * @return {array} The quote array with gaps filled in. - * @memberof CIQ.ChartEngine - * @since - * - 07/01/2015 Now supports cleanups for daily intervals and foreign exchanges instead of just intraday equities. - * - 3.0.7 Added `params.cleanupGaps` to allow developers to use this function standalone, - * - 5.2.0 Added `params.noCleanupDates`. - * - 6.0.0 Added `params.field`. - * - 6.0.0 If `params.cleanupGaps` is true, use the value of `stxx.cleanupGaps`. If that's not set, then `cleanupGaps` is like carry. - */ - CIQ.ChartEngine.prototype.doCleanupGaps = function (quotes, chart, params) { - if (!quotes || !quotes.length) return quotes; - var interval = this.layout.interval; - params = params ? params : {}; - if (!chart) chart = this.chart; - if (!CIQ.Market || !chart.market) return quotes; - if (!params.noCleanupDates) this.doCleanupDates(quotes, interval); - - var cleanupGaps = params.cleanupGaps; - if (cleanupGaps === false) return quotes; - if (!cleanupGaps || cleanupGaps === true) - cleanupGaps = this.cleanupGaps || cleanupGaps; - var makeGaps = cleanupGaps == "gap"; // "carry" or any other non-false will cause the closing price to carry, otherwise a null will be injected - - if (!cleanupGaps) return quotes; - if (interval == "tick") return quotes; - - // doCleanupGaps works on the raw masterData, so if we're rolling up month or week then be sure to actually - // cleanup gaps on the masterData which will be "day" - if (interval == "month" || interval == "week") { - if (this.dontRoll) return quotes; // We won't try to fill gaps on raw month or week data - interval = "day"; - } - - var _make_date = function (_quote) { - if (_quote.DT) { - if (Object.prototype.toString.call(_quote.DT) != "[object Date]") - return new Date(_quote.DT); // epoch or ISO string - return new Date(+_quote.DT); - } - return CIQ.strToDateTime(_quote.Date); - }; - - var new_quotes = []; - var currentQuote = quotes[0]; - new_quotes.push(currentQuote); - - var iter_parms = { - begin: _make_date(currentQuote), - interval: interval, - periodicity: 1, - timeUnit: this.layout.timeUnit - }; - var market = new CIQ.Market(chart.market.market_def); - var iter = market.newIterator(iter_parms); - if (this.extendedHours && this.extendedHours.filter) - iter.market.enableAllAvailableSessions(); - - var field = chart.defaultPlotField; - - // See if Value is the key field instead of Close by looking for a record with Value but no Close. - for (var valQuote = 0; valQuote < quotes.length; valQuote++) { - if (quotes[valQuote][field] !== undefined) break; - if (quotes[valQuote].Value !== undefined) { - field = "Value"; - break; - } - } - - var mdt; - - function fillGapsBetween(dt1, dt2) { - var paramField = params.field; - var cQuote = paramField ? currentQuote[paramField] : currentQuote; - if (cQuote === undefined) cQuote = {}; - var close = makeGaps ? null : cQuote[field]; - var adjClose = makeGaps ? null : cQuote.Adj_Close; - // Loop through the iterator adding a dummy quote for every missing market date between currentQuote and nextQuote - while (+dt1 < +dt2) { - var newQuote = { DT: dt1 }; - if (paramField) { - } else { - new_quotes.push(newQuote); - CIQ.extend(newQuote, { - Open: close, - High: close, - Low: close, - Close: close, - Volume: 0, - Adj_Close: adjClose - }); - } - dt1 = iter.next(); - } - } - - function copyForward(currentQuote, nextQuote) { - var paramField = params.field; - if (paramField) { - if ( - typeof currentQuote[paramField] != "undefined" && - typeof nextQuote[paramField] == "undefined" - ) { - nextQuote[paramField] = makeGaps ? null : currentQuote[paramField]; - } - return; - } - if (makeGaps) return; - var close = currentQuote[field]; - var nextClose = nextQuote[field]; - if (typeof close != "undefined" && typeof nextClose == "undefined") { - CIQ.ensureDefaults(nextQuote, { - Close: close, - Open: close, - High: close, - Low: close, - Volume: 0, - Adj_Close: currentQuote.Adj_Close - }); - } - } - - for (var i = 1; i < quotes.length; i++) { - var nextQuote = quotes[i]; - mdt = iter.next(); // market date - var qdt = _make_date(nextQuote); // quote date - - if (mdt < qdt) { - fillGapsBetween(mdt, qdt); - mdt = iter.market._convertFromMarketTZ(iter.begin, iter.outZone); - } - - while (qdt < mdt) { - if (++i == quotes.length) return new_quotes; - copyForward(currentQuote, nextQuote); - new_quotes.push(nextQuote); - currentQuote = nextQuote; - nextQuote = quotes[i]; - qdt = _make_date(nextQuote); - } - if (mdt < qdt) { - i--; - mdt = iter.previous(); - } else { - copyForward(currentQuote, nextQuote); - new_quotes.push(nextQuote); - currentQuote = nextQuote; - } - } - - return new_quotes; - }; - - /** - * Returns the variables exported by the library. - * - * Use this function to access the CIQ namespace and other library exports when they are not - * otherwise accessible. - * - * @return {object} The exports of the library. - * - * @private - * @memberof CIQ.ChartEngine - * @since 8.0.0 - */ - CIQ.ChartEngine.prototype.getCreatingLibrary = function () { - return _exports; - }; - - }; - - - let __js_core_engine_panel_ = (_exports) => { - - - var CIQ = _exports.CIQ; - - /** - * Defines a Panel object. - * Every chart or study is rendered in a panel. - * - * Example: stxx.panels['chart'] - * - * Example: stxx.panels['Aroon (14)'] - - * @param {string} name The name of the panel. - * @param {CIQ.ChartEngine.YAxis} [yAxis] Y axis ({@link CIQ.ChartEngine.YAxis}) object for the panel. - * @constructor - * @name CIQ.ChartEngine.Panel - */ - CIQ.ChartEngine.Panel = function (name, yAxis) { - if (yAxis) this.yAxis = yAxis; - else this.yAxis = new CIQ.ChartEngine.YAxis(); - this.name = name; - this.state = {}; // drawing state of the panel, can be studies, drawings, or any panel-scoped object - }; - - CIQ.extend( - CIQ.ChartEngine.Panel.prototype, - { - name: null, // Name of panel - display: null, // Display text of panel - chart: null, // The chart from which this panel derives its data - yAxis: null, // Y axis object for this panel, this is the same object as chart.yAxis on chart panels - shareChartXAxis: null, // Set to false to indicate panel does not share x axis with its chart - top: null, // Y location of top of chart - bottom: null, // Y location of bottom of chart - height: null, // height of chart in pixels - percent: null, // percent of overall window this panel takes up - /** - * Draws a border around the panel's left and right sides for a more finished look, when no y axis is present. - * @type boolean - * @default - * @memberof CIQ.ChartEngine.Panel# - * @since 7.1.0 - */ - displayEdgeIfPadded: true, - /** - * Prevents plot and axis dragging into, out of, and within panels. - * @type boolean - * @default - * @memberof CIQ.ChartEngine.Panel# - * @since 7.2.0 - */ - noDrag: false, - /** - * Determines whether the panel is included in the {@link CIQ.ChartEngine#exportLayout} - * return object. - * - * @type boolean - * @default - * @memberof CIQ.ChartEngine.Panel# - * @since 8.0.0 - */ - exportable: true - }, - true - ); - - /** - * Returns the panel for the given Y pixel. Used for instance to determine which panel the crosshairs are in. - * @param {number} y Y pixel location - * @return {CIQ.ChartEngine.Panel} The panel containing the Y location. Null if the Y location is outside of all panels. - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.whichPanel = function (y) { - for (var p in this.panels) { - var panel = this.panels[p]; - if (panel.hidden) continue; - if (y >= panel.top && y < panel.bottom) return panel; - } - return null; - }; - - /** - * Returns true if the panel exists - * @param {string} name Name of panel to search for - * @return {boolean} True if the panel exists - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.panelExists = function (name) { - for (var p in this.panels) { - var panel = this.panels[p]; - if (panel.name == name) return true; - } - return false; - }; - - /** - * Takes the existing panels and stores them in the layout. - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.storePanels = function () { - if (!this.layout) this.layout = {}; - var view = this.layout; - view.panels = {}; - for (var p in this.panels) { - var panel = this.panels[p]; - view.panels[panel.name] = { - percent: panel.percent, - display: panel.display, - yAxis: panel.yAxis - }; - } - }; - - /** - * Saves the panel state in the layout. Called whenever there is a change to panel layout (resizing, opening, closing). - * @param {boolean} saveLayout If false then a change event will not be called. See (@link CIQ.ChartEngine#changeOccurred) - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.savePanels = function (saveLayout) { - this.storePanels(); - if (saveLayout !== false) this.changeOccurred("layout"); - }; - - /** - * Internal function for deleting a panel and its associated DOM objects - * Do not call directly. Always call panelClose - * @private - */ - CIQ.ChartEngine.prototype.privateDeletePanel = function (panel) { - // check for studies - for (var s in this.layout.studies) { - var study = this.layout.studies[s]; - if (study.panel == panel.name) { - this.cleanupRemovedStudy(study); - } - } - // If we ever want to delete any drawing objects in a panel - /*var drawingDeleted=false; - for(var i=0;iINJECTABLE - * - * Closes the panel opened with {@link CIQ.ChartEngine.AdvancedInjectable#createPanel}. - * This is called when a chart panel is closed manually or programmatically. - * For example, after removing a study panel with the {@link CIQ.Studies.removeStudy} function, or when a user clicks on the "X" for a panel. - * @param {CIQ.ChartEngine.Panel} panel The panel to close - * @memberof CIQ.ChartEngine.AdvancedInjectable# - * @alias panelClose - * - */ - CIQ.ChartEngine.prototype.panelClose = function (panel) { - if (!panel) return; - if (this.runPrepend("panelClose", arguments)) return; - this.cancelTouchSingleClick = true; - CIQ.ChartEngine.drawingLine = false; - if (panel.soloing) this.panelSolo(panel); - - // If we're deleting a panel with a chart in it - if (this.charts[panel.name]) { - // Then delete all the panels that reference that chart - for (var panelName in this.panels) { - var subPanel = this.panels[panelName]; - if (subPanel.chart.name == panel.name) { - this.privateDeletePanel(subPanel); - } - } - // and delete the chart itself - delete this.charts[panel.name]; - } else { - // otherwise just delete the panel - this.privateDeletePanel(panel); - } - if (!this.currentlyImporting) { - // silent mode while importing - this.showCrosshairs(); - //this.createDataSet(); // commented, why would we do this? - this.resetDynamicYAxis({ noRecalculate: true }); - this.calculateYAxisPositions(); - this.draw(); - this.savePanels(); - } - // IE11 on Win7 hack. We do this in case the mouseup is lost when we removed the panel.close from the DOM - this.userPointerDown = this.grabbingScreen = false; - if (this.openDialog) this.openDialog = ""; - this.runAppend("panelClose", arguments); - }; - - /** - * Deletes all of the panels (except for the default chart panel) - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.deleteAllPanels = function () { - for (var p in this.panels) { - var panel = this.panels[p]; - this.privateDeletePanel(panel); - } - this.layout.panels = {}; - this.panels = {}; - }; - - /** - * This moves a panel up one position (when the user clicks the up arrow). - * @param {CIQ.ChartEngine.Panel} panel The panel to move up. - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.panelUp = function (panel) { - this.cancelTouchSingleClick = true; - CIQ.ChartEngine.drawingLine = false; - this.showCrosshairs(); - var newPanels = {}; - var pos = 0; - var p; - for (p in this.panels) { - if (p == panel.name) break; - pos++; - } - - if (!pos) return; //already at top - - var i = 0; - for (p in this.panels) { - if (i == pos - 1) newPanels[panel.name] = panel; - if (p == panel.name) continue; - newPanels[p] = this.panels[p]; - i++; - } - this.panels = newPanels; - this.adjustPanelPositions(); - this.draw(); - this.savePanels(); - }; - - /** - * This moves a panel down one position (when the user clicks the down arrow). - * @param {CIQ.ChartEngine.Panel} panel The panel to move down. - * @memberof CIQ.ChartEngine - */ - - CIQ.ChartEngine.prototype.panelDown = function (panel) { - this.cancelTouchSingleClick = true; - CIQ.ChartEngine.drawingLine = false; - this.showCrosshairs(); - var newPanels = {}; - var pos = 0; - var p; - for (p in this.panels) { - if (p == panel.name) break; - pos++; - } - - var length = 0; - for (p in this.panels) length++; - if (pos == length - 1) return; //already at bottom - - var i = 0; - for (p in this.panels) { - if (p == panel.name) { - i++; - continue; - } - newPanels[p] = this.panels[p]; - if (i == pos + 1) newPanels[panel.name] = panel; - i++; - } - this.panels = newPanels; - this.adjustPanelPositions(); - this.draw(); - this.savePanels(); - }; - - /** - * This "solos" the panel (when the user clicks the solo button). All panels other than this panel and the chart - * are temporarily hidden. If the solo panel is the chart then all other panels will be hidden. - * Note if {@link CIQ.ChartEngine#soloPanelToFullScreen} is set than even the chart panel may be hidden - * @param {CIQ.ChartEngine.Panel} panel The panel to be soloed. - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.panelSolo = function (panel) { - this.cancelTouchSingleClick = true; - CIQ.ChartEngine.drawingLine = false; - this.showCrosshairs(); - var hideOrNot = true; - var p; - if (panel.soloing) { - hideOrNot = false; - panel.soloing = false; - panel.solo.classList.remove("stx_solo_lit"); - panel.percent = panel.oldPercent; - if (panel.name != "chart") { - if (this.soloPanelToFullScreen) { - if (panel.percent == 1) { - for (p in this.panels) { - var otherPanel = this.panels[p]; - if (otherPanel != panel) panel.percent -= otherPanel.percent; - } - } - } else { - this.chart.panel.percent = this.chart.panel.oldPercent; - } - } - if (this.soloPanelToFullScreen) { - this.xAxisAsFooter = this.chart.panel.oldXAxisAsFooter; - } - } else { - panel.soloing = true; - panel.solo.classList.add("stx_solo_lit"); - panel.oldPercent = panel.percent; - this.chart.panel.oldXAxisAsFooter = this.xAxisAsFooter; - if (panel.name != "chart") { - if (this.soloPanelToFullScreen) { - this.xAxisAsFooter = true; - } else { - this.chart.panel.oldPercent = this.chart.panel.percent; - panel.percent = 1 - this.chart.panel.percent; - } - } - } - for (p in this.panels) { - this.panels[p].hidden = hideOrNot; - } - if (!this.soloPanelToFullScreen) this.chart.panel.hidden = false; - panel.hidden = false; - this.resetDynamicYAxis({ noRecalculate: true }); - this.calculateYAxisPositions(); - this.draw(); - this.savePanels(); - }; - - //@private - CIQ.ChartEngine.prototype.calculatePanelPercent = function (panel) { - var h = panel.bottom - panel.top; - panel.percent = h / this.chart.canvasHeight; - }; - - /** - * Called when the user moves a panel handle, to resize all of the panels relative to the movement. - * @private - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.resizePanels = function () { - if (!CIQ.ChartEngine.resizingPanel) return; - var priorPanel, minimumHeight, yAxes, i; - var down = - CIQ.ChartEngine.crosshairY > - this.resolveY(CIQ.ChartEngine.resizingPanel.top); - for (var p in this.panels) { - if (this.panels[p] == CIQ.ChartEngine.resizingPanel) break; - if (this.panels[p].hidden) continue; - priorPanel = this.panels[p]; - } - var newY = this.backOutY(CIQ.ChartEngine.crosshairY); - if (down) { - yAxes = CIQ.ChartEngine.resizingPanel.yaxisLHS.concat( - CIQ.ChartEngine.resizingPanel.yaxisRHS - ); - for (i = 0; i < yAxes.length; i++) { - minimumHeight = - yAxes[i].initialMarginTop + yAxes[i].initialMarginBottom + 10; - if (newY > yAxes[i].bottom - minimumHeight) { - newY = yAxes[i].bottom - minimumHeight; - } - } - } else { - yAxes = priorPanel.yaxisLHS.concat(priorPanel.yaxisRHS); - for (i = 0; i < yAxes.length; i++) { - minimumHeight = - yAxes[i].initialMarginTop + yAxes[i].initialMarginBottom + 10; - if (newY < yAxes[i].top + minimumHeight) { - newY = yAxes[i].top + minimumHeight; - } - } - } - CIQ.ChartEngine.crosshairY = this.resolveY(newY); - priorPanel.bottom = newY; - CIQ.ChartEngine.resizingPanel.top = newY; - this.calculatePanelPercent(priorPanel); - this.calculatePanelPercent(CIQ.ChartEngine.resizingPanel); - - this.adjustPanelPositions(); - this.draw(); - this.savePanels(); - }; - - /** - * Determines whether a panel precedes the main chart in the display order. - * - * @param {CIQ.ChartEngine.Panel} panel The panel for which the display order is determined. - * @return {boolean} true, if the panel is above the chart; false, if below or not available. - * - * @memberof CIQ.ChartEngine - * @since 8.0.0 - */ - CIQ.ChartEngine.prototype.isPanelAboveChart = function (panel) { - for (var p in this.panels) { - if (p == "chart") return false; - if (p == panel.name) return true; - } - return false; - }; - - // First, adjust the panel percentages so that they all add up to 1 - // Secondly, set the pixel top and bottom of each panel based on the percentages - /** - * INJECTABLE - * - * Adjusts the positions of all of the panels. Ensures that panel percentages add up to 100%. Sets the panel top and bottom - * based on the percentages. Also sets the icon template icons appropriately for each panel's position. And adjusts - * any drawings. Finally it makes some calculations that are used by the y-axis. - * @memberof CIQ.ChartEngine.AdvancedInjectable# - * @alias adjustPanelPositions - */ - CIQ.ChartEngine.prototype.adjustPanelPositions = function () { - const { chart, panels } = this; - if (chart.tempCanvas) CIQ.clearCanvas(chart.tempCanvas, this); // clear any drawing in progress - // if(!this.chart.symbol) return; - if (this.runPrepend("adjustPanelPositions", arguments)) return; - var lastBottom = 0; - var h = chart.canvasHeight; - var first = false; - var acc = 0; - var n = 0; - var activeSolo = false; - var x, panel; - for (x in panels) { - panel = panels[x]; - if (isNaN(panel.percent) || panel.percent <= 0) panel.percent = 0.05; - if (panel.hidden) continue; - acc += panel.percent; - n++; - if (panel.soloing) activeSolo = true; - } - - for (x in panels) { - var zoomRatio = 0; - panel = panels[x]; - - if (panel.hidden) { - if (panel.markerHolder) { - panel.markerHolder.style.display = "none"; - } - continue; - } - if (this.manageTouchAndMouse) { - if (panel.up) { - if (!first) { - first = true; - panel.up.classList.remove("stx-show"); - } else { - if (this.displayIconsUpDown) panel.up.classList.add("stx-show"); - } - } - if (panel.solo) { - if (activeSolo) { - if (panel.soloing && this.displayIconsSolo) - panel.solo.classList.add("stx-show"); - else panel.solo.classList.remove("stx-show"); - } else if (n == 1) { - panel.solo.classList.remove("stx-show"); - } else if (n == 2 && !this.soloPanelToFullScreen) { - panel.solo.classList.remove("stx-show"); - } else { - if (this.displayIconsSolo) panel.solo.classList.add("stx-show"); - } - } - if (panel.down) { - if (n == 1) { - panel.down.classList.remove("stx-show"); - } else { - if (this.displayIconsUpDown) panel.down.classList.add("stx-show"); - } - } - if (panel.edit) { - if (panel.editFunction) panel.edit.classList.add("stx-show"); - else panel.edit.classList.remove("stx-show"); - } - if (panel.close) { - if (this.displayIconsClose) panel.close.classList.add("stx-show"); - else panel.close.classList.remove("stx-show"); - } - } - - panel.percent = panel.percent / acc; - panel.top = lastBottom; - panel.bottom = panel.top + h * panel.percent; - panel.height = panel.bottom - panel.top; - if (panel.chart.name == panel.name) { - panel.chart.top = panel.top; - panel.chart.bottom = panel.bottom; - panel.chart.height = panel.height; - } - - lastBottom = panel.bottom; - - if (panel.yaxisLHS) { - var arr = panel.yaxisLHS.concat(panel.yaxisRHS); - for (var yax = 0; yax < arr.length; yax++) { - var yAxis = arr[yax]; - - if (yAxis.zoom && yAxis.height > 0) { - zoomRatio = yAxis.zoom / yAxis.height; - } - this.adjustYAxisHeightOffset(panel, yAxis); - yAxis.height = yAxis.bottom - yAxis.top; - if (zoomRatio) { - yAxis.scroll *= (zoomRatio * yAxis.height) / yAxis.zoom; - yAxis.zoom = zoomRatio * yAxis.height; - if (yAxis.zoom > yAxis.height) { - yAxis.zoom = 0; // If the zoom is greater than the height then we'll have an upside down y-axis - yAxis.scroll = 0; - } - } - - if (!yAxis.high && yAxis.high !== 0) { - // panels without values will use percentages to position drawings - yAxis.high = 100; - yAxis.low = 0; - yAxis.shadow = 100; - } - yAxis.multiplier = yAxis.height / yAxis.shadow; - // necessary to preserve the heightFactor of a yAxis - if (yAxis.position === "none") this.calculateYAxisMargins(yAxis); - } - } - - if (panel.holder) { - panel.holder.style.right = "0px"; - panel.holder.style.top = panel.top + "px"; - panel.holder.style.left = "0px"; - panel.holder.style.height = panel.height + "px"; - - panel.subholder.style.left = panel.left + "px"; - panel.subholder.style.width = panel.width + "px"; - panel.subholder.style.top = "0px"; - if (panel.yAxis.height >= 0) - panel.subholder.style.height = panel.yAxis.height + "px"; - } - } - if (x && panels[x].down) panels[x].down.classList.remove("stx-show"); - if (this.manageTouchAndMouse && n == 2 && !activeSolo && chart.panel.solo) { - chart.panel.solo.classList.add("stx-show"); - } - if (chart.panel) { - var bottom; - if (activeSolo && this.soloPanelToFullScreen) { - bottom = chart.canvasHeight - panel.yAxis.bottom + 12; - } else { - bottom = chart.canvasHeight - chart.panel.yAxis.bottom + 12; - } - let controls = this.controls; - let { chartControls, home, notificationTray } = controls; - let yaxOffset = this.width - chart.panel.right; - if (chartControls) chartControls.style.bottom = bottom + "px"; - if (home) { - home.style.bottom = bottom + "px"; - home.style.marginRight = yaxOffset + "px"; - } - if (notificationTray) { - notificationTray.style.bottom = bottom + "px"; - notificationTray.style.marginRight = yaxOffset + "px"; - } - } - this.clearPixelCache(); - - if (this.drawingObjects.length) this.adjustDrawings(); - - this.runAppend("adjustPanelPositions", arguments); - }; - - /** - * INJECTABLE - * - * Creates a new panel and makes room for it by squeezing all the existing panels. - * To remove a panel, manually call {@link CIQ.ChartEngine.AdvancedInjectable#panelClose}. - * - * @param {string} display The display name for the panel. - * @param {string} name The name of the panel (usually the study ID). - * @param {number} [height] Requested height of the panel in pixels. Defaults to 1/5 of the - * screen size. - * @param {string} [chartName="chart"] The chart to associate with this panel. - * @param {CIQ.ChartEngine.YAxis} [yAxis] {@link CIQ.ChartEngine.YAxis} object. If not present, - * the existing panel's axis is used. - * @param {boolean} [noExport] If true, omits the panel from the - * {@link CIQ.ChartEngine#exportLayout} function. - * @return {CIQ.ChartEngine.Panel} The panel just added. - * - * @alias createPanel - * @memberof CIQ.ChartEngine.AdvancedInjectable# - * @since - * - 5.2.0 Added the `yAxis` parameter. - * - 7.1.0 Added the return value. - * - 8.0.0 Added the `noExport` parameter. - */ - CIQ.ChartEngine.prototype.createPanel = function ( - display, - name, - height, - chartName, - yAxis, - noExport - ) { - if (this.runPrepend("createPanel", arguments)) return; - if (!chartName) chartName = "chart"; - var h = this.chart.canvasHeight; - if (!height) height = h * 0.2; - if (height > h) height = h * 0.5; - var percent = height / h; - var reduce = 1 - percent; - var activeSolo = false; - for (var p in this.panels) { - var panel = this.panels[p]; - panel.percent *= reduce; - if (panel.soloing) activeSolo = true; - } - this.stackPanel(display, name, percent, chartName, yAxis); - this.panels[name].hidden = activeSolo; - this.panels[name].exportable = !noExport; - this.adjustPanelPositions(); - this.savePanels(false); - this.runAppend("createPanel", arguments); - return this.panels[name]; - }; - - /** - * Changes the name, display and primary yAxis of a panel, and adjusts all references accordingly. - * @param {CIQ.ChartEngine.Panel|string} panel The panel - * @param {object} [params] - * @param {string} [params.name] Panel name, if omitted, name becomes a random string - * @param {string} [params.display] Panel display, defaults to the name - * @param {CIQ.ChartEngine.YAxis} [params.yAxis] Panel's y-axis. If omitted, will use the panel's existing y-axis - * @since 7.1.0 - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.modifyPanel = function (panel, params) { - const oldName = panel.name; - const { studies } = this.layout; - const { series } = this.chart; - let { name, display, yAxis } = params || {}; - - if (!name) name = CIQ.uniqueID(); - if (!display) display = name; - if (!yAxis) { - yAxis = panel.yAxis; - yAxis.name = name; - } - - let newPanels = {}; - for (let p in this.panels) { - if (p === panel.name) { - // swap the name/id of the old panel - let tmp = this.panels[p]; - tmp.name = name; - tmp.display = display; - tmp.yAxis = yAxis; - panel = newPanels[name] = tmp; - if (this.moveMarkers && oldName !== name) { - this.moveMarkers(oldName, name); - } - } else { - newPanels[p] = this.panels[p]; - } - } - - this.panels = newPanels; - - let layoutChanged = false; - for (let s in studies) { - let study = studies[s]; - if (study.panel === oldName) { - study.panel = name; - if (study.parameters && study.parameters.panelName) { - layoutChanged = true; - study.parameters.panelName = name; - } - } - } - - for (let s in series) { - if (series[s].parameters.panel === oldName) { - layoutChanged = true; - let prm = { panel: name }; - if ( - series[s].parameters.yAxis && - series[s].parameters.yAxis.name === oldName - ) - prm.yAxis = yAxis; - this.modifySeries(s, prm, true); - } - } - - if (layoutChanged) this.changeOccurred("layout"); - - let drawingChanged = false; - for (let d = 0; d < this.drawingObjects.length; d++) { - let drawing = this.drawingObjects[d]; - if (oldName === drawing.panelName) { - drawing.panelName = name; - drawingChanged = true; - } - } - - if (drawingChanged) this.changeOccurred("vector"); - - this.calculateYAxisPositions(); - }; - - /** - * Changes the height of a panel, adjusting other panels accordingly. - * - * @param {CIQ.ChartEngine.Panel} panelToModify The panel whose height is changed. - * @param {number} requestedHeight The new height in pixels of the panel. - * - * @memberof CIQ.ChartEngine - * @since 8.0.0 - */ - CIQ.ChartEngine.prototype.setPanelHeight = function ( - panelToModify, - requestedHeight - ) { - if (!requestedHeight) return; - - // adjust requested height to accommodate the x-axis if panel is at bottom - if (Object.values(this.panels).slice(-1)[0] === panelToModify) { - requestedHeight += this.xaxisHeight; - } - - const { canvasHeight } = this.chart; - const { percent: currentPercent } = panelToModify; - const newPercent = requestedHeight / canvasHeight; - const prevRemainingPercent = 1 - currentPercent; - const newRemainingPercent = 1 - newPercent; - const adjustment = prevRemainingPercent / newRemainingPercent; - - Object.values(this.panels).forEach((panel) => { - panel.percent /= adjustment; - }); - panelToModify.percent = newPercent; - - this.adjustPanelPositions(); - this.savePanels(); - }; - - /** - * Chooses a new study or renderer to be the "owner" of a panel. This affects the name of the panel as well as the main y-axis. - * If no new owner can be found, panel is closed. Calls `modifyPanel`. - * - * @param {CIQ.ChartEngine.Panel|string} panel The panel that contains the study or renderer. - * @param {CIQ.ChartEngine.YAxis} [yAxisHint] Optional y-axis from which to try to elect a new panel owner. - * @return {string} The new name of the panel. - * @memberof CIQ.ChartEngine - * @since - * - 7.1.0 - * - 7.2.0 Added the `yAxisHint` argument. - */ - CIQ.ChartEngine.prototype.electNewPanelOwner = function (panel, yAxisHint) { - var newOwner; - if (typeof panel == "string") panel = this.panels[panel]; - var oldYAxis = panel.yAxis; - function myAxis(y) { - return y.name != oldYAxis.name; - } - if (panel && panel != this.chart.panel) { - var yAxis = panel.yAxis; - // first see if yaxis was hosting other plots, create a new panel axis for them - var newName = yAxis.studies[0]; - if (!newName || newName == oldYAxis.name) newName = yAxis.renderers[0]; - if (!newName || newName == oldYAxis.name) newName = yAxis.studies[1]; - if (!newName) newName = yAxis.renderers[1]; - if (yAxisHint) { - // a suggested yAxis was supplied, trust it - yAxis = panel.yAxis = yAxisHint; - newOwner = yAxisHint.name; - } else if (!newName) { - // no more plots on the main axis, let's find another axis - if (panel.yaxisLHS) { - var axisArr = panel.yaxisRHS.concat(panel.yaxisLHS).filter(myAxis); - var newAxis = axisArr[0]; - for (var y = 0; y < axisArr.length; y++) { - if (!axisArr[y].position) { - // give priority to a default axis - newAxis = axisArr[y]; - break; - } - } - if (newAxis) { - yAxis = panel.yAxis = newAxis; - newOwner = newAxis.studies[0] || newAxis.renderers[0]; - } - } - } else { - yAxis = this.addYAxis( - panel, - new CIQ.ChartEngine.YAxis({ name: newName, position: yAxis.position }) - ); - yAxis.renderers = panel.yAxis.renderers; - yAxis.studies = panel.yAxis.studies; - newOwner = newName; - } - if (newOwner) { - newName = newOwner; - if (oldYAxis.name != panel.name) newName = panel.name; // don't change the panel name if it didn't match the old owner - var display, - studies = this.layout.studies; - if (studies && studies[newOwner]) - display = studies[newOwner].inputs.display; - this.modifyPanel(panel, { - name: newName, - display: display || newOwner, - yAxis: yAxis - }); - this.deleteYAxisIfUnused(panel, oldYAxis); - this.calculateYAxisMargins(this.panels[newName].yAxis); - } else this.checkForEmptyPanel(panel); - } - return newOwner; - }; - - /** - * Configures the panel controls - * @param {CIQ.ChartEngine.Panel} panel The panel - * @private - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.configurePanelControls = function (panel) { - var icons = panel.icons; - if (!icons) return; - var isChart = panel.name == panel.chart.name; - - icons.classList.add("stx-show"); - - panel.title = icons.querySelector(".stx-panel-title"); - panel.up = icons.querySelector(".stx-ico-up"); - if (panel.up) panel.up = panel.up.parentNode; - panel.solo = icons.querySelector(".stx-ico-focus"); - if (panel.solo) panel.solo = panel.solo.parentNode; - panel.down = icons.querySelector(".stx-ico-down"); - if (panel.down) panel.down = panel.down.parentNode; - panel.edit = icons.querySelector(".stx-ico-edit"); - if (panel.edit) panel.edit = panel.edit.parentNode; - panel.close = icons.querySelector(".stx-ico-close"); - if (panel.close) panel.close = panel.close.parentNode; - - if (panel.title) { - panel.title.innerHTML = ""; - if (panel.display) - panel.title.appendChild(document.createTextNode(panel.display)); - if (isChart) { - panel.title.classList.add("chart-title"); - icons.classList.add("stx-chart-panel"); - } - } - - if (!CIQ.touchDevice || CIQ.isSurface) this.makeModal(icons); - - if (panel.handle) { - if (!CIQ.touchDevice || CIQ.isSurface) - panel.handle.onmouseover = (function (self) { - return function () { - self.hideCrosshairs(); - }; - })(this); - if (!CIQ.touchDevice || CIQ.isSurface) - panel.handle.onmouseout = (function (self) { - return function () { - self.showCrosshairs(); - }; - })(this); - var panelGrab = function (stx, panel) { - return function (e) { - if (CIQ.ChartEngine.resizingPanel || stx.openDialog !== "") return; - stx.grabHandle(panel); - }; - }; - // stxx.releaseHandle is called by the chart's touchend and mouseup handlers - if (CIQ.isSurface) { - panel.handle.onpointerdown = panelGrab(this, panel); - } else { - panel.handle.onmousedown = panelGrab(this, panel); - } - if (CIQ.touchDevice) panel.handle.ontouchstart = panelGrab(this, panel); - } - - if (panel.up) - CIQ.safeClickTouch( - panel.up, - (function (stx, panel) { - return function () { - stx.panelUp(panel); - }; - })(this, panel) - ); - if (panel.down) - CIQ.safeClickTouch( - panel.down, - (function (stx, panel) { - return function () { - stx.panelDown(panel); - }; - })(this, panel) - ); - if (panel.solo) - CIQ.safeClickTouch( - panel.solo, - (function (stx, panel) { - return function () { - stx.panelSolo(panel); - }; - })(this, panel) - ); - if (panel.close) { - if (panel.name == "chart") { - panel.close.style.display = "none"; // no close icon on primary chart - } else { - CIQ.safeClickTouch( - panel.close, - (function (stx, panel) { - return function () { - stx.panelClose(panel); - }; - })(this, panel) - ); - } - } - }; - /** - * INJECTABLE - * - * Adds a panel with a prespecified percentage. This should be called iteratively when rebuilding a set - * of panels from a previous layout. Use {@link CIQ.ChartEngine.AdvancedInjectable#createPanel} when creating a new panel for an existing chart layout. - * @param {string} display The display name for the panel - * @param {string} name The name of the panel (usually the study ID) - * @param {number} percent The percentage of chart to use - * @param {string} [chartName] The chart to associate with this panel. Defaults to "chart". - * @param {CIQ.ChartEngine.YAxis} [yAxis] {@link CIQ.ChartEngine.YAxis} object. If not present, the existing panel's axis will be used. - * @memberof CIQ.ChartEngine.AdvancedInjectable# - * @alias stackPanel - * @since 5.2.0 Added `yAxis` paremeter. - */ - CIQ.ChartEngine.prototype.stackPanel = function ( - display, - name, - percent, - chartName, - yAxis - ) { - if (this.runPrepend("stackPanel", arguments)) return; - if (!chartName) chartName = "chart"; - var chart = this.charts[chartName]; - var isChart = name == chartName; - if (isChart) { - display = chart.symbol; - if (chart.symbolDisplay) display = chart.symbolDisplay; - if (!yAxis) yAxis = chart.yAxis; - } - var panel = (this.panels[name] = new CIQ.ChartEngine.Panel(name, yAxis)); - if (!isChart && chart.yAxis && panel.yAxis.position == chart.yAxis.position) { - panel.yAxis.width = chart.yAxis.width; // make it match the width of the main panel so the y axis align - } - if (isChart && !chart.panel) chart.panel = panel; - - panel.percent = percent; - panel.chart = chart; - panel.display = display; - panel.holder = CIQ.newChild(this.container, "div", "stx-holder"); // the main holder extends to the edges of the panel - panel.subholder = CIQ.newChild(panel.holder, "div", "stx-subholder"); // the sub holder does not include the axis area - panel.subholder.style.zIndex = 1; - panel.holder.panel = panel; - var appendClass = isChart ? "stx-panel-chart" : "stx-panel-study"; - panel.holder.classList.add(appendClass); - - if (this.controls.handleTemplate && this.manageTouchAndMouse) { - panel.handle = this.controls.handleTemplate.cloneNode(true); - this.container.appendChild(panel.handle); - //panel.handle.style.display=""; // let the drawPanels manage this otherwise if we set to "" here but the developer wants a picture (png) handle using CSS, the hande will flicker on on initial load on the top of the screen - panel.handle.panel = panel; - } - - if (this.controls.iconsTemplate) { - panel.icons = this.controls.iconsTemplate.cloneNode(true); - panel.subholder.appendChild(panel.icons); - this.configurePanelControls(panel); - } - - if (!this.currentlyImporting) this.resizeCanvas(); - - this.runAppend("stackPanel", arguments); - }; - - CIQ.ChartEngine.prototype.setPanelEdit = function (panel, editFunction) { - panel.editFunction = editFunction; - if (panel.edit) CIQ.safeClickTouch(panel.edit, editFunction); - this.adjustPanelPositions(); - }; - /** - * INJECTABLE - * Animation Loop - * - * Draws the panels for the chart and chart studies. CSS style stx_panel_border can be modified to change the color - * or width of the panel dividers. - * @memberof CIQ.ChartEngine.AdvancedInjectable# - * @alias drawPanels - */ - CIQ.ChartEngine.prototype.drawPanels = function () { - if (this.runPrepend("drawPanels", arguments)) return; - var first = false; - for (var p in this.panels) { - var panel = this.panels[p]; - panel.state = {}; // reset the drawing state - - var textToDisplay = this.translateIf(panel.display); - if (panel.title && panel.title.textContent != textToDisplay) { - panel.title.innerHTML = ""; - panel.title.appendChild(document.createTextNode(textToDisplay)); - } - if (panel.icons) panel.icons.classList.add("stx-show"); - if (panel.hidden) { - if (panel.icons) panel.icons.classList.remove("stx-show"); - if (panel.handle) panel.handle.style.display = "none"; - panel.holder.style.display = "none"; - continue; - } else { - if (panel.name != "chart") { - var manageTouchAndMouse = this.manageTouchAndMouse; - if (panel.up) - panel.up.style.display = - this.displayIconsUpDown && manageTouchAndMouse ? "" : "none"; - if (panel.down) - panel.down.style.display = - this.displayIconsUpDown && manageTouchAndMouse ? "" : "none"; - if (panel.solo) - panel.solo.style.display = - this.displayIconsSolo && manageTouchAndMouse ? "" : "none"; - if (panel.close) - panel.close.style.display = - this.displayIconsClose && manageTouchAndMouse ? "" : "none"; - if (panel.edit) - panel.edit.style.display = - panel.editFunction && manageTouchAndMouse ? "" : "none"; - } - panel.holder.style.display = "block"; - } - if (panel.displayEdgeIfPadded) { - var x = Math.round(panel.left) + 0.5, - t = panel.yAxis.top - 0.5, - b = panel.yAxis.bottom + 0.5; - if (panel.yaxisCalculatedPaddingLeft && !panel.yaxisTotalWidthLeft) - this.plotLine( - x, - x, - t, - b, - this.canvasStyle("stx_grid_border"), - "segment", - this.chart.context, - false, - { lineWidth: 1 } - ); - x = Math.round(panel.right) + 0.5; - if (panel.yaxisCalculatedPaddingRight && !panel.yaxisTotalWidthRight) - this.plotLine( - x, - x, - t, - b, - this.canvasStyle("stx_grid_border"), - "segment", - this.chart.context, - false, - { lineWidth: 1 } - ); - } - if (!first) { - if (panel.handle) panel.handle.style.display = "none"; - first = true; - continue; - } - var y = panel.top; - y = Math.round(y) + 0.5; - this.plotLine( - panel.left - 0.5, - panel.right + 0.5, - y, - y, - this.canvasStyle("stx_panel_border"), - "segment", - this.chart.context, - false, - {} - ); - if (panel.handle) { - if (!this.displayPanelResize) { - panel.handle.style.display = "none"; - } else { - panel.handle.style.display = ""; - } - panel.handle.style.top = y - panel.handle.offsetHeight / 2 + "px"; - //panel.handle.style.left=panel.left+ "px"; - } - } - this.runAppend("drawPanels", arguments); - }; - - }; - - - let __js_core_engine_periodicity_ = (_exports) => { - - - var CIQ = _exports.CIQ; - - /** - * Determines whether the internal chart periodicity is based on a daily interval ("day", "week" - * or "month"). - * - * **Note:** This function is intended to be used on the internal periodicity as stored in - * {@link CIQ.ChartEngine#layout}. - * - * @param {string} interval The internal chart periodicity for which the interval is determined. - * @return {boolean} True if the internal chart periodicity is a daily interval; otherwise, false. - * - * @memberof CIQ.ChartEngine - * - * @see CIQ.ChartEngine.layout.periodicity - * @see CIQ.ChartEngine.layout.interval - * @see CIQ.ChartEngine.layout.timeUnit - */ - CIQ.ChartEngine.isDailyInterval = function (interval) { - if (interval == "day") return true; - if (interval == "week") return true; - if (interval == "month") return true; - return false; - }; - - /** - * Specifies the properties that define periodicity. - * - * Periodicity = `period` x `interval` expressed as `timeUnit`. - * - * Referenced as the type of the main parameter of {@link CIQ.ChartEngine#setPeriodicity}, the - * periodicity parameter of {@link CIQ.ChartEngine#loadChart}, and the return value of - * {@link CIQ.ChartEngine#getPeriodicity}. - * - * @typedef {object} CIQ.ChartEngine~PeriodicityParameters - * @property {number} period The number of elements from the data source to roll-up (aggregate) - * into a single data point, such as a candle on a candle chart. For example, `period=2`, - * `interval=5`, and `timeUnit="minute"` results in candles that represent 10-minute time - * spans. - * @property {string|number} [interval=1] The number of units of measure of the periodicity. For - * example, `interval=5` and `timeUnit="minute"` specify a periodicity of five minutes. - * The interval property enables the chart to fetch quotes in a roll-up state; for - * example, if the data source provides one-minute quotes, setting `interval=5` results - * in the chart fetching five one-minute quotes as a single data point. - * @property {string|null} [timeUnit="minute"] The unit of measure of the periodicity. Valid values - * include "millisecond", "second", "minute", "day", "week", "month", and "tick". - */ - - /** - * INJECTABLE - * - * Sets the data granularity (periodicity) and displays the resulting chart. - * - * Dispatches a "periodicity" event. - * - * If a quote feed has been attached to the chart (see {@link CIQ.ChartEngine#attachQuoteFeed}), it will be called to get the new data, otherwise this.dataCallback will - * be called in an effort to fetch new data. See {@link CIQ.ChartEngine#dataCallback}. If neither one is set and new data is needed, the function will fail. - * - * This function can be called together with `loadChart()` by setting the proper parameter values. See example in this section and {@link CIQ.ChartEngine#loadChart} for more details and compatibility with your current version. - * - * This function will not set how much data you want the chart to show on the screen; for that you can use {@link CIQ.ChartEngine#setRange} or {@link CIQ.ChartEngine#setSpan}. - * - * The kernel is capable of deriving weekly and monthly charts by rolling-up daily data. Set {@link CIQ.ChartEngine#dontRoll} to true to bypass this - * functionality if you have raw week and month data in the masterData. - * - * It is important to note that by default the weekly roll-ups start on Sunday unless a market definition exists to indicate Sunday is not a market day, - * then they are shifted to the next market day. Instructions to set a market for the chart can be found here: {@link CIQ.Market} - * - * A full tutorial on periodicity and roll-up can be found [here]{@tutorial Periodicity}. - * - * **See {@link CIQ.ChartEngine#createDataSet} for additional details on the roll-up process including important notes on rolling-up data with gaps.** - * - * **Note on 'tick' timeUnit:**
- * When using 'tick', please note that this is not a time based display, as such, there is no way to predict what the time for the next tick will be. - * It can come a second later, a minute later or even more depending on how active a particular instrument may be. - * If using the future tick functionality ( {@link CIQ.ChartEngine.XAxis#futureTicks} ) when in 'tick' mode, the library uses a pre-defined number ( {@link CIQ.ChartEngine.XAxis#futureTicksInterval} )for deciding what time interval to use for future ticks. - * See below example on how to override this default. - * - * It is important to note that rollups for ‘ticks’ are based on **count** rather than time. - *
For example: `setPeriodicity({period:5, interval:1, timeUnit:"tick”})` will create a new bar every **5 ticks** rather than every **5 minutes**. - * - * Since many ticks can have the exact same timestamp, ticks never get replaced or augmented. As such, if a new tick is provided with a timestamp in the past, even if a record with the exact same date already exists, a new tick will be inserted to the masterData at the proper location rather than one replaced. - * - * Lastly, you cannot set an interval for `tick`; as that would not translate into a valid periodicity. If inadvertently set, the engine will "clean it up" (much the same way as if you tried `{period:1, interval:5, timeUnit:"day"}` ). - * - * **Note on internal periodicity storage:**
- * The provided parameters will be translated into internal format and stored in the {@link CIQ.ChartEngine#layout} object. - * Internal format in the layout object **will not match the parameters** used in ​setPeriodicity. - *
Use {@link CIQ.ChartEngine#getPeriodicity} to extract internal periodicity into the expected external format. - * - * @example - * // each bar on the screen will represent 15 minutes (combining 15 1-minute bars from your server) - * stxx.setPeriodicity({period:15, timeUnit:"minute"}, function(err){}); - * - * @example - * // each bar on the screen will represent 15 minutes (a single 15 minute bar from your server) - * stxx.setPeriodicity({period:1, timeUnit:"minute", interval:15}, function(err){}); - * - * @example - * // each bar on the screen will represent 30 minutes formed by combining two 15-minute bars; each masterData element represening 15 minutes. - * stxx.setPeriodicity({period:2, timeUnit:"minute", interval:15}, function(err){}); - * - * @example - * // each bar on the screen will represent 1 tick and no particular grouping will be done. - * stxx.setPeriodicity({period:1, timeUnit:"tick"}, function(err){}); - * - * @example - * // each bar on the screen will represent 5 ticks (combining 5 tick objects from your server) - * stxx.setPeriodicity({period:5, timeUnit:"tick"}, function(err){}); - * - * @example - * // each bar on the screen will represent 1 day. MasterData elements will represent one day each. - * stxx.setPeriodicity({period:1, timeUnit:"day"}, function(err){}); - * - * @example - * // this sets the periodicity to 5 minute bars when loadChart is called - * stxx.loadChart(newSymbol, { - * // this parameter will cause loadChart to call setSpan with these parameters - * span: {base: 'day', multiplier: 2}, - * // this parameter will cause loadChart to call setPeriodicity with these parameters - * periodicity: {period: 1, timeUnit: "minute", interval: 5} - * }, finishedLoadingChart(stxx.chart.symbol, newSymbol)); - * - * @example - * //How to override stxx.chart.xAxis.futureTicksInterval when in 'tick' mode: - * var stxx=new CIQ.ChartEngine({container:document.querySelector(".chartContainer"), layout:{"candleWidth": 16, "crosshair":true}}); - * stxx.chart.xAxis.futureTicksInterval=1; // to set to 1 minute, for example - * - * @param {CIQ.ChartEngine~PeriodicityParameters} params periodicity arguments - * @param {number} params.period The number of elements from masterData to roll-up together into one data point on the chart (candle,bar, etc). If set to 30 in a candle chart, for example, each candle will represent 30 raw elements of `interval/timeUnit` type. - * @param {number} [params.interval] Further qualifies pre-rolled details of intra-day `timeUnits` ("millisecond","second","minute") and will be converted to “1” if used with "day", "week" or "month" 'timeUnit'. Some feeds provide data that is already rolled up. For example, there may be a feed that provides 5 minute bars. To let the chart know you want that 5-minute bar from your feed instead of having the chart get individual 1 minute bars and roll them up, you would set the `interval` to '5' and `timeUnit` to 'minute' - * @param {string} [params.timeUnit] Type of data requested. Valid values are "millisecond","second","minute","day","week", "month" or 'tick'. If not set, will default to "minute". **"hour" is NOT a valid timeUnit. Use `timeUnit:"minute", interval:60` instead** - * @param {function} [cb] Callback after periodicity is changed. First parameter of callback will be null unless there was an error. - * @memberof CIQ.ChartEngine - * @since - * - 3.0.0 Replaces {@link CIQ.ChartEngine#setPeriodicityV2}. - * - 4.0.0 Now uses {@link CIQ.ChartEngine#needDifferentData} to determine if new data should be fetched. - * - 6.3.0 Now only homes chart if new data was fetched. - * - 8.1.0 Dispatches a "periodicity" event. See also - * [periodicityEventListener]{@link CIQ.ChartEngine~periodicityEventListener}. - */ - CIQ.ChartEngine.prototype.setPeriodicity = function (params, cb) { - if (this.runPrepend("setPeriodicity", arguments)) return; - - if (typeof arguments[0] !== "object") { - params = { - period: arguments[0], - interval: arguments[1], - timeUnit: arguments[2] - }; - cb = arguments[arguments.length - 1]; - if (arguments.length === 3) params.timeUnit = undefined; - } - - let { period, interval, timeUnit } = params; - if (typeof cb !== "function") cb = null; - - ({ period, interval, timeUnit } = CIQ.cleanPeriodicity( - period, - interval, - timeUnit - )); - - let { layout } = this; - layout.setSpan = {}; // No longer in a span if we've set a specific periodicity - layout.range = {}; // No longer in a range if we've set a specific periodicity - - this.chart.inflectionPoint = null; // reset where the consolidation occurs from - let getDifferentData = false; - - if (this.chart.symbol) { - getDifferentData = this.needDifferentData({ - period: period, - interval: interval, - timeUnit: timeUnit - }); - } - - let { - candleWidth: cw, - periodicity: prvPeriodicity, - interval: prvInterval, - timeUnit: prvTimeUnit - } = layout; - let prevPeriodicity = { prvPeriodicity, prvInterval, prvTimeUnit }; - - layout.periodicity = period; - layout.interval = interval; - layout.timeUnit = timeUnit; - - const self = this; - let dispatchData = { - stx: self, - differentData: getDifferentData, - prevPeriodicity - }; - function onComplete() { - self.dispatch("periodicity", dispatchData); - if (cb) cb(null); - } - - if (getDifferentData) { - this.changeOccurred("layout"); - this.clearCurrentMarketData(); - if (this.quoteDriver) { - for (let c in this.charts) { - let thisChart = this.charts[c]; - if (thisChart.symbol) { - if (this.displayInitialized) { - this.quoteDriver.newChart( - { - symbol: thisChart.symbol, - symbolObject: thisChart.symbolObject, - chart: thisChart - }, - onComplete - ); - } else { - this.loadChart(thisChart.symbol, { chart: thisChart }, onComplete); - } - } - } - } else if (this.dataCallback) { - this.dataCallback(); - onComplete(); - } else { - console.log( - "cannot change periodicity because neither dataCallback or quoteDriver are set" - ); - } - this.home(); - return; - } - - for (let chartName in this.charts) { - let chart = this.charts[chartName]; - let { dataSegment, dataSet, maxTicks, scroll } = chart; - let dataSegmentLength = dataSegment ? dataSegment.length : 0, - dataSetLength = dataSet ? dataSet.length : 0; - let dt; - let pos = Math.round(chart.maxTicks / 2); - this.setCandleWidth(cw, chart); - let centerMe = true, - rightAligned = false; - if (scroll <= maxTicks) - // don't attempt to center the chart if we're scrolled into the future - centerMe = false; - else if (dataSegment && !dataSegment[pos]) { - // don't attempt to center the chart if we're scrolled into the past - centerMe = false; - rightAligned = scroll - dataSetLength; // We'll use this to keep the same amount of right alignment - } - - if (centerMe && dataSegmentLength > 0) { - if (maxTicks < (Math.round(this.chart.width / cw - 0.499) - 1) / 2) { - pos = dataSegmentLength - 1; - } - if (pos >= dataSegmentLength) { - dt = dataSegment[dataSegmentLength - 1].DT; - pos = dataSegmentLength - 1; - } else { - dt = dataSegment[pos].DT; - } - } - - this.createDataSet(); - - if (centerMe) { - // If we're scrolled somewhere into the middle of the chart then we will keep the chart centered as we increase or decrease periodicity - if (dataSegmentLength > 0) { - for (let i = dataSetLength - 1; i >= 0; i--) { - let nd = dataSet[i].DT; - if (nd.getTime() < dt.getTime()) { - chart.scroll = dataSetLength - 1 - i + pos; - break; - } - } - } - } else if (!rightAligned) { - let wsInTicks = Math.round(this.preferences.whitespace / cw); - chart.scroll = maxTicks - wsInTicks - 1; // Maintain the same amount of left alignment - } else { - chart.scroll = dataSet.length + rightAligned; // Maintain the same amount of right alignment - } - } - - if (this.displayInitialized) this.draw(); - this.changeOccurred("layout"); - - if (this.quoteDriver) { - for (let chartName in this.charts) { - let chart = this.charts[chartName]; - if (chart.symbol && (chart.moreAvailable || !chart.upToDate)) { - this.quoteDriver.checkLoadMore(chart); - } - } - } - //this.home(); // let centerMe do its thing - onComplete(); - this.runAppend("setPeriodicity", arguments); - }; - - /** - * Returns true if the chart needs new data to conform with the new periodicity. - * @param {object} newPeriodicity newPeriodicity. See {@link CIQ.ChartEngine#setPeriodicity} - * @param {number} newPeriodicity.period `period` as required by {@link CIQ.ChartEngine#setPeriodicity} - * @param {string} newPeriodicity.interval `interval` as required by {@link CIQ.ChartEngine#setPeriodicity} - * @param {string} newPeriodicity.timeUnit `timeUnit` as required by {@link CIQ.ChartEngine#setPeriodicity} - * @return {boolean} True if the cart needs data in a new periodicity - * @memberof CIQ.ChartEngine - * @since 4.0.0 - */ - CIQ.ChartEngine.prototype.needDifferentData = function (newPeriodicity) { - var layout = this.layout; - var isDaily = CIQ.ChartEngine.isDailyInterval(newPeriodicity.interval), - wasDaily = CIQ.ChartEngine.isDailyInterval(layout.interval); - var getDifferentData = false; - - if (this.dontRoll || !wasDaily) { - // we are not rolling so monthly and weekly are not the same as daily or any of the intraday... so simply check for different interval. - if (layout.interval != newPeriodicity.interval) getDifferentData = true; - } else { - //we are rolling weeekly and monthly and wasn't intraday mode...so check to see if we an still use daily data for the new periodicity - if (isDaily != wasDaily) getDifferentData = true; - } - - // safety check to deal with defaults. - if (!isDaily && !newPeriodicity.timeUnit) newPeriodicity.timeUnit = "minute"; - if (!wasDaily && !layout.timeUnit) layout.timeUnit = "minute"; - - if (newPeriodicity.timeUnit != layout.timeUnit) getDifferentData = true; // !!! Do not change to !== - - if (!this.masterData || !this.masterData.length) getDifferentData = true; // always fetch if no data - - return getDifferentData; - }; - - /** - * Returns the current periodicity of the chart in the format required by - * {@link CIQ.ChartEngine#setPeriodicity}. - * - * @returns {CIQ.ChartEngine~PeriodicityParameters} An object literal containing the properties - * that define the periodicity: `period`, `interval`, and `timeUnit`; for example,
- * `{period: 2, interval: 5, timeUnit: "minute"}`. - * - * @memberof CIQ.ChartEngine - * @since 7.5.0 - * - * @see [Periodicity Tutorial]{@tutorial Periodicity} - */ - CIQ.ChartEngine.prototype.getPeriodicity = function () { - var layout = this.layout; - var interval = layout.interval, - timeUnit = layout.timeUnit; - - if (!timeUnit) { - timeUnit = interval; - interval = 1; - } - - return { period: layout.periodicity, interval: interval, timeUnit: timeUnit }; - }; - - }; - - - let __js_core_engine_record_ = (_exports) => { - - - var CIQ = _exports.CIQ; - - /** - * Based on the standardMarketIterator and the last entry of masterData, determines whether the chart contains data up till the current iterators next tick. - * - * For efficiency once {@link CIQ.ChartEngine.isHistoricalMode} is set to false, this will always return false. - * @return {boolean} True if viewing historical mode - * @since 6.0.0 - * @private - */ - CIQ.ChartEngine.prototype.isHistoricalMode = function () { - var dateNow = new Date(), - historic = true, - masterData = this.masterData; - if (!this.isHistoricalModeSet) { - return false; - } - if (masterData.length) { - var lastDate = this.getFirstLastDataRecord(masterData, "DT", true); - var iter = this.standardMarketIterator(lastDate.DT); - historic = (iter ? iter.next() : lastDate.DT) <= dateNow; - - // special case: daily chart, market has not opened yet today - // historic would always be set even though we have all the data - if (historic && CIQ.ChartEngine.isDailyInterval(iter.interval)) { - var open = this.chart.market.getOpen(); - if (open && dateNow < open) { - dateNow.setHours(0, 0, 0, 0); - if (+dateNow == +iter.begin) historic = false; - } - } - } - return historic; - }; - - /** - * Whether the chart is scrolled to a home position. - * - * @returns {boolean} true when the scroll position shows the last tick of the dataSet - * @memberof CIQ.ChartEngine - * @since 2016-06-21 - */ - CIQ.ChartEngine.prototype.isHome = function () { - var chart = this.chart, - dataSet = chart.dataSet, - animating = chart.animatingHorizontalScroll; - return ( - this.pixelFromTick(dataSet.length - (animating ? 2 : 1), chart) < - chart.width + chart.panel.left - ); - //return ((this.chart.scroll-1)*this.layout.candleWidth)+this.micropixels<=this.chart.width+1; - }; - - /** - * Finds the previous element before dataSegment[bar] in the dataSet which has data for field - * @param {CIQ.ChartEngine.Chart} chart An instance of {@link CIQ.ChartEngine.Chart} - * @param {string} field The field to check for data - * @param {number} bar The index into the dataSegment - * @return {object} dataSet element which has data - * @memberof CIQ.ChartEngine - * @since 4.0.0 - */ - CIQ.ChartEngine.prototype.getPreviousBar = function (chart, field, bar) { - return this.getNextBarInternal(chart, field, bar, -1); - }; - - /** - * Finds the next element after dataSegment[bar] in the dataSet which has data for field - * @param {CIQ.ChartEngine.Chart} chart An instance of {@link CIQ.ChartEngine.Chart} - * @param {string} field The field to check for data - * @param {number} bar The index into the dataSegment - * @return {object} dataSet element which has data - * @memberof CIQ.ChartEngine - * @since 4.0.0 - */ - CIQ.ChartEngine.prototype.getNextBar = function (chart, field, bar) { - return this.getNextBarInternal(chart, field, bar, 1); - }; - - /** - * @param {CIQ.ChartEngine.Chart} chart An instance of {@link CIQ.ChartEngine.Chart} - * @param {string} field The field to check for data - * @param {number} bar The index into the dataSegment - * @param {number} direction 1 or -1, for next or previous - * @return {object} dataSet element which has data - * @memberof CIQ.ChartEngine - * @since 4.0.0 - * @private - */ - CIQ.ChartEngine.prototype.getNextBarInternal = function ( - chart, - field, - bar, - direction - ) { - var seg = chart.dataSegment && chart.dataSegment[bar]; - if (seg) { - var tick = seg.tick; - while (tick > 0 && tick < chart.dataSet.length) { - tick = tick + direction; - var ds = chart.dataSet[tick]; - if (ds) { - var tuple = CIQ.existsInObjectChain(ds, field); - if (tuple && tuple.obj[tuple.member]) return ds; - } - } - } - return null; - }; - - /** - * Returns the first or last record in a quotes array (e.g. masterData, dataSet) containing the requested field. - * If no record is found, will return null - * @param {array} data quotes array in which to search - * @param {string} field field to search for - * @param {boolean} [last] Switch to reverse direction; default is to find the first record. Set to true to find the last record. - * @return {object} The found record, or null if not found - * @memberof CIQ.ChartEngine - * @since 5.2.0 - */ - CIQ.ChartEngine.prototype.getFirstLastDataRecord = function ( - data, - field, - last - ) { - if (data && data.length) { - var c = last ? data.length - 1 : 0; - while (c >= 0 && c < data.length) { - if (data[c] && typeof data[c][field] != "undefined") { - return data[c]; - } - if (last) c--; - else c++; - } - } - return null; - }; - - /** - * Returns the tick position of the leftmost position on the chart. - * @return {number} The tick for the leftmost position - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.leftTick = function () { - return this.chart.dataSet.length - this.chart.scroll; - }; - - /** - * Convenience function returns the next or previous interval from the provided date-time at the current chart's periodicity. - * See {@link CIQ.Market} and {@link CIQ.Market.Iterator} for more details. - * - * For 'tick' intervals, since there is no predictable periodicity, the next interval will be determined by {@link CIQ.ChartEngine.XAxis#futureTicksInterval} - * @param {date} DT A JavaScript Date representing the base time for the request in {@link CIQ.ChartEngine#dataZone} timezone. - * @param {number} [period] The number of periods to jump. Defaults to 1. Can be negative to go back in time. - * @param {boolean} [useDataZone=true] By default the next interval will be returned in {@link CIQ.ChartEngine#dataZone}. Set to false to receive a date in {@link CIQ.ChartEngine#displayZone} instead. - * @return {date} The next interval date - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.getNextInterval = function (DT, period, useDataZone) { - if (!period) period = 1; - if (useDataZone !== false) useDataZone = true; - - var iter = this.standardMarketIterator( - DT, - useDataZone ? this.dataZone : this.displayZone - ); - if (!iter) return DT; // cannot find so just return input date - if (period < 1) { - return iter.previous(period * -1); - } - return iter.next(period); - }; - - /** - * Convenience function returns a new market iterator at the current chart's periodicity. - * For 'tick' intervals, since there is no predictable periodicity, the iterator interval will be determined by {@link CIQ.ChartEngine.XAxis#futureTicksInterval} - * See {@link CIQ.Market} and {@link CIQ.Market.Iterator} for more details. - * @param {date} begin A JavaScript Date representing the iterator begin date in {@link CIQ.ChartEngine#dataZone} timezone. See {@link CIQ.Market#newIterator} for details. - * @param {string} [outZone] A valid timezone from the timeZoneData.js library. This should represent the time zone for the returned date. Defaults {@link CIQ.ChartEngine#dataZone}. See {@link CIQ.Market#newIterator} for details. - * @param {CIQ.ChartEngine.Chart} [chart] The chart object. - * @return {object} A new iterator. - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.standardMarketIterator = function ( - begin, - outZone, - chart - ) { - var cht = chart || this.chart; - if (!cht.market) return null; - var iter_parms = { - begin: begin, - interval: this.layout.interval, - periodicity: - this.layout.interval == "tick" - ? this.chart.xAxis.futureTicksInterval - : this.layout.periodicity, - timeUnit: this.layout.timeUnit, - outZone: outZone - }; - return cht.market.newIterator(iter_parms); - }; - - }; - - - let __js_core_engine_render_ = (_exports) => { - - - if (!_exports.SplinePlotter) _exports.SplinePlotter = {}; - var CIQ = _exports.CIQ, - splinePlotter = _exports.SplinePlotter; - - /** - * INJECTABLE - * Animation Loop - * - * This is the main rendering function in the animation loop. It draws the chart including panels, axis, and drawings. - * This method is called continually as a user pans or zooms the chart. - * This would be a typical place to put an injection to add behavior to the chart after a drawing operation is complete. - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.draw = function () { - this.debug(); - var chart = this.chart, - layout = this.layout; - if (!chart.canvas) return; - if (!chart.dataSet) return; - if (!chart.canvasHeight) return; - //if(!this.useAnimation && new Date()-this.grossDragging<500) return; - - this.offset = (layout.candleWidth * this.candleWidthPercent) / 2; - CIQ.clearCanvas(chart.canvas, this); - if (!this.masterData) return; - - if (this.runPrepend("draw", arguments)) return; - if (!this.defaultColor) this.getDefaultColor(); - - this.vectorsShowing = false; - - this.drawPanels(); - this.yAxisLabels = []; - var i, plugin; - - this.correctIfOffEdge(); - this.createDataSegment(); - this.setBaselines(chart); - var axisRepresentation = this.createXAxis(chart); - this.initializeDisplay(chart); - this.drawXAxis(chart, axisRepresentation); - try { - this.renderYAxis(chart); - } catch (e) { - if (e && e.message === "reboot draw") { - return this.draw(); - } - throw e; - } - - /// Calculate tmpWidth which represents the amount of width that the candle takes, slightly less than candleWidth - chart.tmpWidth = Math.floor(layout.candleWidth * this.candleWidthPercent); // So we don't need to compute it a thousand times for every candle - if (chart.tmpWidth % 2 === 0) { - // assure that candles are always odd number of pixels wide - chart.tmpWidth += 1; - if (chart.tmpWidth > layout.candleWidth) - // If there isn't space then reduce further - chart.tmpWidth -= 2; - } - if (chart.tmpWidth < 0.5) chart.tmpWidth = 0.5; - - for (i in this.plugins) { - plugin = this.plugins[i]; - if (plugin.display) { - if (plugin.drawUnder) plugin.drawUnder(this, chart); - } - } - - if (chart.legend) chart.legend.colorMap = null; - if (this.controls.baselineHandle) - this.controls.baselineHandle.style.display = "none"; - - this.rendererAction(chart, "underlay"); - CIQ.getFn("Studies.displayStudies")(this, chart, true); - this.displayChart(chart); - CIQ.getFn("Studies.displayStudies")(this, chart, false); - this.rendererAction(chart, "overlay"); - - if (chart.legend && chart.legend.colorMap && chart.legendRenderer) { - chart.legendRenderer(this, { - chart: chart, - legendColorMap: chart.legend.colorMap, - coordinates: { - x: chart.legend.x, - y: chart.legend.y + chart.panel.yAxis.top - } - }); - } - - for (i in this.plugins) { - plugin = this.plugins[i]; - if (plugin.display) { - if (plugin.drawOver) plugin.drawOver(this, chart); - } - } - - // Do this after all the drawing has taken place. That way the y-axis text sits on top of anything that - // has been drawn underneath. For instance, if panel.yaxisCalculatedPaddingRight>0 and the y-axis sits on top of the chart - for (var panel in this.panels) { - if (!this.panels[panel].hidden) this.plotYAxisText(this.panels[panel]); - } - for (var yLbl = 0; yLbl < this.yAxisLabels.length; yLbl++) { - var labelParams = this.yAxisLabels[yLbl]; - if ( - labelParams.src == "series" && - labelParams.args[6] && - labelParams.args[6].drawSeriesPriceLabels === false - ) - continue; - this.createYAxisLabel.apply(this, labelParams.args); - } - if (this.createCrosshairs) this.createCrosshairs(); - if (this.drawVectors) this.drawVectors(); - this.drawCurrentHR(); - this.displayInitialized = true; - var controls = this.controls; - if (controls) { - var showControls = - this.manageTouchAndMouse && - (!this.mainSeriesRenderer || !this.mainSeriesRenderer.nonInteractive); - if (controls.home) - controls.home.style.display = - showControls && !this.isHome() ? "block" : "none"; - if (controls.chartControls) - controls.chartControls.style.display = showControls ? "block" : "none"; - } - if (CIQ.Marker) this.positionMarkers(); - if (this.quoteDriver && this.animations.zoom.hasCompleted) { - this.quoteDriver.checkLoadMore(chart); - } - this.runAppend("draw", arguments); - this.makeAsyncCallbacks(); - }; - - /** - * Adds a series renderer to the chart. A series renderer manages a group of series that are - * rendered on the chart in the same manner. For instance, several series which are part of the - * same stacked histogram: - * - * - * - * You must manage the persistency of a renderer and remove individual series - * ({@link CIQ.Renderer#removeSeries}), remove all series ({@link CIQ.Renderer#removeAllSeries}), - * or even delete the renderer ({@link CIQ.ChartEngine#removeSeriesRenderer}) as needed by your - * application. - * - * **Note:** Once a renderer is set for a chart, it remains loaded with its series definitions - * and y-axis (if one is used) even if a new symbol is loaded. Calling `setSeriesRenderer` again - * with the same renderer name just returns the previously created renderer. **Be careful not to - * send a different y‑axis object unless you have deleted the previous one by completely - * removing all of its associated series** (see {@link CIQ.Renderer#removeAllSeries}). Failure to - * do this will cause multiple axes to be displayed, causing the original one to become orphaned. - * - * @param {CIQ.Renderer} renderer The series renderer to add to the chart. - * @return {CIQ.Renderer} The renderer added to the chart by this function or, if the chart - * already has a renderer of the same name, a reference to that renderer. - * - * @memberof CIQ.ChartEngine - * @since 07/01/2015 - * - * @see {@link CIQ.Renderer} - * @see {@link CIQ.ChartEngine#removeSeriesRenderer} for release functionality - * @see {@link CIQ.ChartEngine#addSeries} for additional implementation examples - * - * @example - * // Group the series together and select "line" as the rendering type to display the series. - * const mdataRenderer = stxx - * .setSeriesRenderer( - * new CIQ.Renderer.Lines({ - * params: { - * name: "My Line Series", - * type: "line", - * width: 4, - * callback: mdataLegend - * } - * }) - * ) - * .removeAllSeries() - * .attachSeries(symbol1, { color: "red", permanent: true }) - * .attachSeries(symbol2, "blue") - * .attachSeries(symbol3, "yellow") - * .ready() - */ - CIQ.ChartEngine.prototype.setSeriesRenderer = function (renderer) { - const { baseline, name, panel, yAxis } = renderer.params; - if (this.chart.seriesRenderers[name]) { - return this.chart.seriesRenderers[name]; // renderer already created - } - - if (yAxis) { - renderer.params.yAxis = this.addYAxis(this.panels[panel], yAxis); - this.resizeChart(); - } - renderer.stx = this; - - this.chart.seriesRenderers[name] = renderer; - - if (baseline) this.registerBaselineToHelper(renderer); - - return renderer; - }; - - /** Sets a renderer for the main chart. This is done by parsing the layout.chartType and layout.aggregationType and creating the renderer which will support those settings. - * @param {boolean} eraseData Set to true to erase any existing series data - * @memberOf CIQ.ChartEngine - * @since 5.1.0 - */ - CIQ.ChartEngine.prototype.setMainSeriesRenderer = function (eraseData) { - let { chartType, aggregationType } = this.layout; - const { chart } = this; - const { custom } = chart; - let r = this.mainSeriesRenderer; - - let displayInitialized = this.displayInitialized; - if (r) { - if (eraseData) this.setMasterData(); - this.displayInitialized = false; // prevent redraws while series is not attached to main renderer - r.removeAllSeries(); - this.removeSeriesRenderer(r); - r = this.mainSeriesRenderer = null; - } - - if (custom && custom.chartType) chartType = custom.chartType; - if (chartType == "none") return; // no renderer and no default lines renderer - if (aggregationType && aggregationType != "ohlc") chartType = aggregationType; - const renderer = CIQ.Renderer.produce(chartType, { - panel: chart.panel.name, - name: "_main_series", - highlightable: false, - useChartLegend: true - }); - if (renderer) { - this.setSeriesRenderer(renderer).attachSeries(null, { - display: chart.symbol - }); - r = this.mainSeriesRenderer = renderer; - } - - this.displayInitialized = displayInitialized; - // Convenience access - ["highLowBars", "standaloneBars", "barsHaveWidth"].forEach( - function (p) { - chart[p] = this.mainSeriesRenderer && this.mainSeriesRenderer[p]; - }.bind(this) - ); - }; - - /** - * Detaches a series renderer from the chart and deletes its associated y-axis if no longer used by any other renderer. - * - * Note: the actual series and related data are not deleted with this command and can be attached or continue to be used with other renderers. - * - * Note: the actual renderer (created by using new `CIQ.Renderer.xxxxx`) is not deleted but simply detached from the chart. You can re-attach it again if needed. - * To delete the renderer use `delete myRenderer`. See example in {@link CIQ.Renderer.Lines} - * - * @param {object} renderer The actual renderer instance to be removed - * @memberof CIQ.ChartEngine - * @since 07/01/2015 - */ - CIQ.ChartEngine.prototype.removeSeriesRenderer = function (renderer) { - const { baseline, name } = renderer.params; - const handle = this.controls[`${name} baseline-handle`]; - if (baseline) { - this.removeBaselineFromHelper(renderer); - if (handle) { - this.container.removeChild(handle); - delete this.controls[handle]; - } - } - delete this.chart.seriesRenderers[name]; - }; - - /** - * Retrieves a series renderer from the chart - * @param {string} name Handle to access the renderer (params.name) - * @return {object} the matching series renderer if found - * @memberof CIQ.ChartEngine - * @since 07/01/2015 - */ - CIQ.ChartEngine.prototype.getSeriesRenderer = function (name) { - return this.chart.seriesRenderers[name]; - }; - - /** - * Returns the first renderer found that contains a series, or null if not found. - * - * @param {string} seriesId ID of the series to find. - * @return {object} The matching series renderer if found. - * @memberof CIQ.ChartEngine - * @since 7.3.0 - */ - CIQ.ChartEngine.prototype.getRendererFromSeries = function (seriesId) { - var renderers = this.chart.seriesRenderers; - for (var r in renderers) { - for (var s in renderers[r].seriesParams) { - if (renderers[r].seriesParams[s].id == seriesId) return renderers[r]; - } - } - return null; - }; - - /** - * Initializes boundary clipping on the requested panel. Use this when you are drawing on the canvas and wish for the - * drawing to be contained within the panel. You must call {@link CIQ.ChartEngine#endClip} when your drawing functions are complete. - * @param {string} [panelName] The name of the panel. Defaults to the chart itself. - * @param {boolean} [allowYAxis=false] If true then the clipping region will include the y-axis. By default the clipping region ends at the y-axis. - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.startClip = function (panelName, allowYAxis) { - if (!panelName) panelName = this.chart.panel.name; - var panel = this.panels[panelName]; - var yAxis = panel.yAxis; - var chart = this.chart; - chart.context.save(); - chart.context.beginPath(); - var left = panel.left; - var width = panel.width; - if (allowYAxis) { - left = 0; - width = this.width; - } else if (panel.yaxisLHS && panel.yaxisLHS.length) { - left++; - width--; - } - chart.context.rect(left, yAxis.top, width, yAxis.height); - chart.context.clip(); - }; - - /** - * Completes a bounded clipping operation. See {@link CIQ.ChartEngine#startClip}. - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.endClip = function () { - this.chart.context.restore(); - }; - - /** - * Sets the line style for the main chart. - * - * Applies to the {@link CIQ.Renderer.Lines} renderer only. - * - * @param {object|string} [obj] Parameters object or color string (see `obj.color`). - * @param {string} [obj.color] A color to use for the line plot. Must be an RGB, RGBA, or three- - * or six‑digit hexadecimal color number or - * - * CSS color keyword; for example, "rgb(0, 255, 0)", "rgba(0, 255, 0, 0.5), - * "#0f0", "#00FF00", or "green". Alternatively, `obj` can be set to a color string directly - * if no other parameters are needed. - * @param {number[]|string} [obj.pattern] Pattern to use as an alternative to a solid line for the - * line plot. Valid string values are "solid", "dotted" and "dashed". Arrays specify the - * sequence of drawn pixels and blank pixels as alternating elements starting at index 0; for - * example, [1, 2, 3, 2] specifies a line containing one drawn pixel followed by two blank - * pixels followed by three drawn pixels followed by two more blank pixels, then the pattern - * repeats. - * @param {number} [obj.width] Width of the line plot. - * @param {string} [obj.baseColor] Color to use for the base of a mountain chart. Must be an RGB, - * RGBA, or three- or six‑digit hexadecimal color number or CSS color keyword (see - * `obj.color`). - * @param {CIQ.ChartEngine.Chart|CIQ.Studies.StudyDescriptor} [target=this.chart] Target to which - * the line style is attached. - * - * @memberof CIQ.ChartEngine - * @since - * - 4.0.0 - * - 8.2.0 Added `obj.baseColor` parameter. - * - * @example Set the line color, pattern, and width. - * stxx.setLineStyle({ color: "rgb(127, 127, 127)", pattern: "dashed", width: 3 }); - * - * @example Set the line color using a color keyword. - * stxx.setLineStyle("blue"); - */ - CIQ.ChartEngine.prototype.setLineStyle = function (obj, target) { - var res = {}; - if (obj && typeof obj == "object") { - res = obj; - } else { - res.color = obj; - } - if (!res.color && !res.pattern && !res.width && !res.baseColor) res = null; - if (!target) target = this.chart; - var width = 1; - if (res && res.width) width = res.width; - if (res && res.pattern) - res.pattern = CIQ.borderPatternToArray(width, res.pattern); - target.lineStyle = res; - }; - - /** - * Sets the style for 'gap-filling'. - * - * A gap is an area on a line type rendering ( mountain, baseline, step, etc) where the value for the plotted field is null, undefined, or missing. - * - * This method can be used to instruct the chart how to fill gaps created on the chart when missing data is present in series. - * Creates a gap filling style object for lines which can be used with any API call requiring a gap object. - * It can be used as a general style for the entire chart, as way to configure just the primary series, or when adding series with {@link CIQ.ChartEngine#addSeries} - * - * The gap object, called `gaplines` will be attached to the `target` passed in, or will set the the primary chart's gap style if to target is provided. - * Valid styles include a boolean, a color string, or an object containing color and pattern information. - * - * When passing in a boolean value: - * - `true` will indicate that the target object should continue to draw lines over the gaps in your chart. - * - `false` will indicate that the target object should treat the color as transparent, and not draw lines over the gaps. - * - * It is important to note that this is NOT the same as filling the missing values with actual data. It merely describes how the chart displays the gaps. - * - * This should be used instead of setting {@link CIQ.ChartEngine.Chart#gaplines} directly. - * - * A gap is an area on a line type rendering ( mountain, baseline, step, etc) where the value for the plotted field is null, undefined, or missing. - * @param {object} [obj|boolean|string] Value for gap lines. - * @param {string} [obj.color] A color on the canvas palette to use for gap plot. Alternatively, obj may be set to the color string directly if no other parameters are needed. - * @param {array} [obj.pattern] Pattern to use as alternative to solid line for gap plot, in array format, e.g. [1,2,3,2]. - * @param {number} [obj.width] Line width for gap plot, in pixels - * @param {boolean} [obj.fillMountain] Set to true to fill the gaps in a mountain chart with the gap color. Otherwise the mountain chart is filled in with its default color. - * @param {object} [target=this.chart] Target to attach `gaplines` object to. If none provided it defaults to CIQ.ChartEngine.Chart. - * @memberof CIQ.ChartEngine - * @since - * - 4.0.0 - * - 6.2.3 Now accepts any valid parameter of `chart.gaplines` (boolean, color string, or color object). - * @example - * // shorthand if just setting a color as the the default style for the chart gaps - * stxx.setGapLines("blue"); - * @example - * // the following will set stxx.chart.gaplines with color, pattern and width for the chart gaps - * stxx.setGapLines({color:"transparent",pattern:[1,2],width:3,fillMountain:true}); - * @example - * // the following will set objectTarget.gaplines - * stxx.setGapLines({color:"transparent",pattern:[1,2],width:3,fillMountain:true,target:objectTarget}); - * @example - * // shorthand for setting gaps to transparent - * stxx.setGapLines(false) - * - * // shorthand for setting gaps to the color of your line or mountain chart - * stxx.setGapLines(true) - * - */ - CIQ.ChartEngine.prototype.setGapLines = function (obj, target) { - if (!target) target = this.chart; - var res = {}; - if (obj && typeof obj == "object") { - res = obj; - } else if (typeof obj === "boolean") { - return (target.gaplines = obj); - } else { - res.color = obj; - } - if (!res.color && !res.pattern && !res.fillMountain) res = null; - if (res && res.pattern) - res.pattern = CIQ.borderPatternToArray(res.width, res.pattern); - if (res && res.width <= 0) res.width = null; - target.gaplines = res; - }; - - /** - * An object that describes how the renderer should draw a specific part of the chart as - * generated and returned by {@link CIQ.ChartEngine~colorFunction}. - * - * @typedef {object} CIQ.ChartEngine~colorObject - * @property {string} color Any string value that can be interpreted by the canvas context. - * @property {Array} pattern Description of the pattern in an on/off value description. - * @property {number} width Width in pixels in which the pattern should be drawn. - */ - - /** - * A function describing the color to use for drawing a specific part of the chart. - * - * Should always return a {@link CIQ.ChartEngine~colorObject} describing how you would like the - * chart to draw the quote. - * - * @param {CIQ.ChartEngine} stx The chart engine. - * @param {CIQ.ChartEngine~OHLCQuote} quote Specific quote to be drawn with the returned color - * object. - * @param {object} parameters Any parameters used by your color function. - * @return {CIQ.ChartEngine~colorObject} A color object. - * - * @callback CIQ.ChartEngine~colorFunction - */ - - /** - * @callback CIQ.Renderer~colorFunction - * @see CIQ.ChartEngine~colorFunctionnew - */ - - /** - * Generates a function used to return the color and pattern of a line chart over a gap area. - * A gap is an area where the value for the plotted field is null, undefined, or missing. - * - * See {@link CIQ.ChartEngine#setGapLines}. - * - * @param {string} [symbol] Symbol of the series - * @param {string} [field] Field to plot, usually Close - * @param {object} [normal] Normal definition object containing color, pattern and width. If only color is required, this may be set directly to the color string. - * @param {string} [normal.color] A color on the canvas palette to use for normal, non-gap plot - * @param {array} [normal.pattern] Pattern to use as alternative to solid line for normal, non-gap plot, in array format, e.g. [1,2,3,2] - * @param {number} [normal.width] Line with for normal plot, in pixels - * @param {object} [gaps] Gaps definition object containing color, pattern and width. If only color is required, this may be set directly to the color string. If no gaps should be filled, leave out or set to false. - * @param {string} [gaps.color] A color on the canvas palette to use for gap plot - * @param {array} [gaps.pattern] Pattern to use as alternative to solid line for gap plot, in array format, e.g. [1,2,3,2] - * @param {number} [gaps.width] Line with for gap plot, in pixels - * @param {function} [colorFunction] Function to apply to plot to determine colors, for normal, non-gap portion - * @return {function} A function for generating color and pattern for the entire chart. - * @memberof CIQ.ChartEngine - * @private - * @since 5.1.0 Changed signature, added width support. - */ - CIQ.ChartEngine.prototype.getGapColorFunction = function ( - symbol, - field, - normal, - gaps, - colorFunction - ) { - if (typeof normal != "object") normal = { color: normal }; - return function (stx, quote, isGap) { - var myColor = colorFunction ? colorFunction(stx, quote, isGap) : normal; - if (myColor.color) myColor = myColor.color; // in case the colorFunction returns an object - var q = quote[symbol]; - if (!q && q !== 0) q = quote[field]; - if (!isGap && (q || q === 0)) { - return { - color: myColor, - pattern: normal.pattern, - width: normal.width - }; - } - if (!gaps) return null; // no color is returned if no gaps are needed. - if (typeof gaps != "object") { - if (typeof gaps == "string") gaps = { color: gaps }; - else gaps = {}; - } - return { - color: gaps.color || myColor, - pattern: gaps.pattern || normal.pattern, - width: gaps.width || normal.width - }; - }; - }; - - /** - * Animation Loop - * - * Draws a single frame of a line chart. - * - * This method should rarely if ever be called directly. - * Use {@link CIQ.Renderer.Lines}, {@link CIQ.ChartEngine#setChartType} or {@link CIQ.ChartEngine#addSeries} instead. - * - * Any parameters from {@link CIQ.Renderer#attachSeries} or {@link CIQ.ChartEngine#addSeries} - * will be passed on to this method and are valid when directly calling it from within a [study display function of a Custom Study]{@tutorial Using and Customizing Studies - Creating New Studies}. - * - * Uses CSS style `stx_line_chart` to control width and color of line charts, unless `params` are set. - * - * The default color function for the colored line chart uses the following CSS styles: - * - `stx_line_up` - Color of the uptick portion of the line - * - `stx_line_down` - Color of the downtick portion of the line - * - * @param {CIQ.ChartEngine.Panel} panel The panel on which to draw the line chart - * @param {string} style The style selector which contains the styling for the bar (width and color) - * @param {function} [colorFunction] A function which accepts an CIQ.ChartEngine and quote as its arguments and returns the appropriate color for drawing that mode. - Returning a null will skip that bar. If not passed as an argument, will use a default color. - * @param {object} [params] Listing of parameters to use when plotting the line chart. - * @param {boolean} [params.skipTransform] If true then any transformations (such as comparison charting) will not be applied - * @param {boolean} [params.label] If true then the y-axis will be marked with the value of the right-hand intercept of the line - * @param {boolean} [params.noSlopes] If set then chart will draw horizontal bars with no vertical lines. - * @param {boolean} [params.step] If set then chart will resemble a step chart. Horizontal lines will begin at the center of the bar. - * @param {number} [params.tension] Tension for splining. - * @param {boolean} [params.highlight] If set then line will be twice as wide. - * @param {string} [params.color] The color for the line. Defaults to CSS style - * @param {string} [params.pattern] The pattern for the line ("solid","dashed","dotted"). Defaults to CSS style - * @param {number} [params.width] The width in pixels for the line. Defaults to CSS style - * @param {object} [params.gapDisplayStyle] Gap object as created by {@link CIQ.ChartEngine#setGapLines}. If not set `chart.gaplines` will be used. - * @param {boolean} [params.labelDecimalPlaces] Specifies the number of decimal places to print on the label. If not set then it will match the y-axis. - * @param {boolean} [params.returnObject] Set to true for return value of the function to be object as described in doc below, otherwise returns only array of colors used. - * @return {object} Data generated by the plot, such as colors used if a colorFunction was passed, and the vertices of the line (points). - * @memberof CIQ.ChartEngine - * @since - * - 15-07-01 Changed signature from `chart` to `panel`. - * - 3.0.0 Added `params`. - * - 5.2.0 `params.gaps` has been deprecated and replaced with `params.gapDisplayStyle`. - * - 6.0.0 `params.gapDisplayStyle` can be set to false to suppress all gap drawing. - */ - CIQ.ChartEngine.prototype.drawLineChart = function ( - panel, - style, - colorFunction, - params - ) { - var chart = this.chart, - context = chart.context, - lineStyle = chart.lineStyle || {}; - var c = this.canvasStyle(style); - if (!params) params = {}; - this.startClip(panel.name); - var width = params.width || lineStyle.width || c.width; - if (width && parseInt(width, 10) <= 25) { - context.lineWidth = Math.max(1, CIQ.stripPX(width)); - } else { - context.lineWidth = 1; - } - params.pattern = params.pattern || lineStyle.pattern || c.borderTopStyle; - params.pattern = CIQ.borderPatternToArray(context.lineWidth, params.pattern); - this.canvasColor(style); - var color = params.color || lineStyle.color; - if (color) { - if (color == "auto") color = this.defaultColor; - if (params.opacity && params.opacity !== 1) - color = CIQ.hexToRgba(CIQ.colorToHex(color), parseFloat(params.opacity)); - context.strokeStyle = color; - } - params.skipProjections = true; - var field = params.field || chart.defaultPlotField; // usually the series - var plotField = params.subField || chart.defaultPlotField || "Close"; // usually the field within the series - var gaps = params.gapDisplayStyle; - if (!gaps && gaps !== false) gaps = params.gaps; - if (!gaps && gaps !== false) gaps = chart.gaplines; - if (!gaps) gaps = "transparent"; - params.gapDisplayStyle = gaps; - var myColorFunction = this.getGapColorFunction( - field, - plotField, - { - color: context.strokeStyle, - pattern: params.pattern, - width: context.lineWidth - }, - gaps, - colorFunction - ); - if (panel.chart.tension) params.tension = panel.chart.tension; - var rc = this.plotDataSegmentAsLine(field, panel, params, myColorFunction); - if (!rc.colors.length) rc.colors.push(context.strokeStyle); - context.lineWidth = 1; - this.endClip(); - - return params.returnObject ? rc : rc.colors; - }; - - /** - * Animation Loop - * - * Draws a channel chart, shading the areas between a high and the close and between a low and the close. - * - * The high, low, and close can be redefined to other fields within the parameters. - * - * This method should rarely if ever be called directly. Use {@link CIQ.Renderer.Lines} or {@link CIQ.ChartEngine#setChartType} instead. - * - * Any parameters from {@link CIQ.Renderer#attachSeries} or {@link CIQ.ChartEngine#addSeries} - * will be passed on to this method and are valid when directly calling it from within a [study display function of a Custom Study]{@tutorial Using and Customizing Studies - Creating New Studies}. - * - * The high line, low line, and respective shading are controlled by the following styles, unless overridden in the `params`: - * - `stx_channel_up` - Color of the high line and shading. - * - `stx_channel_down` - Color of the low line and shading. - - * The close line color as well as all of the line widths are controlled by the style `stx_line_chart`, unless `params` are set. - * - * @param {CIQ.ChartEngine.Panel} panel The panel on which to draw the line chart. - * @param {function} [colorFunction] A function that accepts a `CIQ.ChartEngine` and quote as its arguments and returns the appropriate color for drawing that mode. - * Returning a null skips that bar. If not passed as an argument, uses a default color. - * @param {object} [params] Listing of parameters to use when plotting the channel chart. - * @param {boolean} [params.skipTransform] If true, any transformations (such as comparison charting) are applied. - * @param {boolean} [params.label] If true, the y-axis is marked with the value of the right-hand intercept of the line. - * @param {boolean} [params.noSlopes] If set, the chart will draw horizontal bars with no vertical lines. - * @param {boolean} [params.step] If set, the chart will resemble a step chart. Horizontal lines will begin at the center of the bar. - * @param {number} [params.tension] Tension for splining. - * @param {boolean} [params.highlight] If set, lines are twice as wide. - * @param {string} [params.color] The color for the close line. Defaults to CSS style. - * @param {string} [params.border_color_down] The color for the high line. Defaults to CSS style. - * @param {string} [params.border_color_up] The color for the low line. Defaults to CSS style. - * @param {string} [params.pattern] The pattern for the line ("solid","dashed","dotted"). Defaults to CSS style. - * @param {number} [params.width] The width in pixels for the line. Defaults to CSS style. - * @param {object} [params.gapDisplayStyle] Gap object as created by {@link CIQ.ChartEngine#setGapLines}. If not set `chart.gaplines` is used. - * @param {boolean} [params.labelDecimalPlaces] Specifies the number of decimal places to print on the label. If not set, it will match the y-axis. - * @param {string} [params.style] The style selector, which contains the styling for the lines (width and color). - * @param {boolean} [params.returnObject] Set to true for return value of the function to be object as described below, otherwise returns only array of colors used. - * @return {object} Data generated by the plot, such as colors used if a `colorFunction` was passed, and the vertices of the close line (points). - * @memberof CIQ.ChartEngine - * @since 7.3.0 - */ - CIQ.ChartEngine.prototype.drawChannelChart = function ( - panel, - colorFunction, - params - ) { - var localParams = CIQ.clone(params); - localParams.color = params.color; - var rcC = this.drawLineChart( - panel, - localParams.style, - colorFunction, - localParams - ); - var upColor = - localParams.border_color_up || this.getCanvasColor("stx_channel_up"); - var downColor = - localParams.border_color_down || this.getCanvasColor("stx_channel_down"); - localParams[params.field ? "subField" : "field"] = - localParams.field_high || "High"; - localParams.color = upColor; - var rcH = this.drawLineChart( - panel, - localParams.style, - colorFunction, - localParams - ); - localParams[params.field ? "subField" : "field"] = - localParams.field_low || "Low"; - localParams.color = downColor; - var rcL = this.drawLineChart( - panel, - localParams.style, - colorFunction, - localParams - ); - localParams[params.field ? "subField" : "field"] = - params.subField || this.chart.defaultPlotField || "Close"; - - var p, - topArea = [], - bottomArea = []; - for (p = 0; p < rcH.points.length; p += 2) - topArea.push([rcH.points[p], rcH.points[p + 1]]); - for (p = 0; p < rcL.points.length; p += 2) - bottomArea.push([rcL.points[p], rcL.points[p + 1]]); - var width = this.chart.context.lineWidth / 2; - for (p = rcC.points.length - 2; p >= 0; p -= 2) { - topArea.push([rcC.points[p], rcC.points[p + 1] - width]); - bottomArea.push([rcC.points[p], rcC.points[p + 1] + width]); - } - this.startClip(panel.name); - localParams.color = upColor; - CIQ.fillArea(this, topArea, localParams); - localParams.color = downColor; - CIQ.fillArea(this, bottomArea, localParams); - this.endClip(); - - rcC.colors = rcC.colors.concat(rcH.colors).concat(rcL.colors); - - return params.returnObject ? rcC : rcC.colors; - }; - - /** - * Draws a series of connected lines on the canvas. The points are in a straight array for compactness. This is used - * for instance in the freeform (doodle) drawing tool - * @param {array} points A series of points in the pattern x0,y0,x1,y1 - * @param {string} color Either a color or a Styles object as returned from {@link CIQ.ChartEngine#canvasStyle} - * @param {string} type The type of line to draw ("segment","ray" or "line") - * @param {external:CanvasRenderingContext2D} [context] The canvas context. Defaults to the standard context. - * @param {object} [confineToPanel] Panel the line should be drawn in, and not cross through. Or set to 'true' to confine to the main chart panel. - * @param {object} [parameters] Additional parameters to describe the line - * @param {string} [parameters.pattern] The pattern for the line ("solid","dashed","dotted") - * @param {number} [parameters.width] The width in pixels for the line - * @param {number} [parameters.opacity] Opacity for the line - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.connectTheDots = function ( - points, - color, - type, - context, - confineToPanel, - parameters - ) { - if (!parameters) parameters = {}; - if (parameters.pattern == "none") return; - if (confineToPanel === true) confineToPanel = this.chart.panel; - if (context === null || typeof context == "undefined") - context = this.chart.context; - if (points.length < 4) return; - - var edgeTop = 0; - var edgeBottom = this.chart.canvasHeight; - var edgeLeft = 0; - var edgeRight = this.chart.width; - - if (confineToPanel) { - edgeBottom = confineToPanel.yAxis.bottom; - edgeTop = confineToPanel.yAxis.top; - } - - context.lineWidth = 1.1; // Use 1.1 instead of 1 to get good anti-aliasing on Android Chrome - if (typeof color == "object") { - context.strokeStyle = color.color; - if (color.opacity) context.globalAlpha = color.opacity; - else context.globalAlpha = 1; - context.lineWidth = CIQ.stripPX(color.width); - } else { - if (!color || color == "auto" || CIQ.isTransparent(color)) { - context.strokeStyle = this.defaultColor; - } else { - context.strokeStyle = color; - } - } - if (parameters.opacity) context.globalAlpha = parameters.opacity; - if (parameters.lineWidth) context.lineWidth = parameters.lineWidth; - var pattern = CIQ.borderPatternToArray(context.lineWidth, parameters.pattern); - context.beginPath(); - - for (var i = 0; i < points.length - 2; i += 2) { - var x0 = points[i]; - var y0 = points[i + 1]; - var x1 = points[i + 2]; - var y1 = points[i + 3]; - if (isNaN(x0) || isNaN(x1) || isNaN(y0) || isNaN(y1)) return; - - var t0 = 0.0, - t1 = 1.0; - var xdelta = x1 - x0; - var ydelta = y1 - y0; - var p, q, r; - - for (var edge = 0; edge < 4; edge++) { - if (edge === 0) { - p = -xdelta; - q = -(edgeLeft - x0); - } - if (edge == 1) { - p = xdelta; - q = edgeRight - x0; - } - if (edge == 2) { - p = -ydelta; - q = -(edgeTop - y0); - } - if (edge == 3) { - p = ydelta; - q = edgeBottom - y0; - } - r = q / p; - - if ((y1 || y1 === 0) && p === 0 && q < 0) { - return false; // Don't draw line at all. (parallel horizontal line outside) - } - - if (p < 0) { - if (r > t1) return false; - // Don't draw line at all. - else if (r > t0) t0 = r; // Line is clipped! - } else if (p > 0) { - if (r < t0) return false; - // Don't draw line at all. - else if (r < t1) t1 = r; // Line is clipped! - } - } - - var x0clip = x0 + t0 * xdelta; - var y0clip = y0 + t0 * ydelta; - var x1clip = x0 + t1 * xdelta; - var y1clip = y0 + t1 * ydelta; - - try { - context.setLineDash(pattern && pattern.length ? pattern : []); - context.moveTo(x0clip, y0clip); - context.lineTo(x1clip, y1clip); - } catch (e) { - //alert(x0clip + ":" + y0clip + " " + x1clip + ":" + y1clip); - } - } - context.stroke(); - context.closePath(); - context.globalAlpha = 1; - context.lineWidth = 1; - }; - - // confineToPanel is not used because currently we are splining after the drawing is complete. - // should that change we will need to implement it - - /** - * Draws a series of points and splines (smooths the curve) those points. - * - * This is uses for drawings, not series. - * @param {array} points A series of points in the pattern x0,y0,x1,y1 - * @param {number} tension Spline tension (0-1). Set to negative to not spline. - * @param {string} color Either a color or a Styles object as returned from {@link CIQ.ChartEngine#canvasStyle} - * @param {string} type The type of line to draw ("segment","ray" or "line") - * @param {external:CanvasRenderingContext2D} [context] The canvas context. Defaults to the standard context. - * @param {string} [confineToPanel] Not currently implemented - * @param {object} [parameters] Additional parameters to describe the line - * @param {string} [parameters.pattern] The pattern for the line ("solid","dashed","dotted") - * @param {number} [parameters.width] The width in pixels for the line - * @param {number} [parameters.opacity] Opacity for the line - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.plotSpline = function ( - points, - tension, - color, - type, - context, - confineToPanel, - parameters - ) { - if (!parameters) parameters = {}; - if (parameters.pattern == "none") return; - if (confineToPanel === true) confineToPanel = this.chart.panel; - if (context === null || typeof context == "undefined") - context = this.chart.context; - - context.save(); - - context.lineWidth = 1.1; // Use 1.1 instead of 1 to get good anti-aliasing on Android Chrome - if (typeof color == "object") { - context.strokeStyle = color.color; - if (color.opacity) context.globalAlpha = color.opacity; - else context.globalAlpha = 1; - context.lineWidth = CIQ.stripPX(color.width); - } else { - if (!color || color == "auto" || CIQ.isTransparent(color)) { - context.strokeStyle = this.defaultColor; - } else { - context.strokeStyle = color; - } - } - if (parameters.opacity) context.globalAlpha = parameters.opacity; - if (parameters.lineWidth) context.lineWidth = parameters.lineWidth; - var pattern = CIQ.borderPatternToArray(context.lineWidth, parameters.pattern); - if (parameters.pattern && context.setLineDash) { - context.setLineDash(pattern); - context.lineDashOffset = 0; //start point in array - } - - context.beginPath(); - splinePlotter.plotSpline(points, tension, context); - context.stroke(); - context.closePath(); - - context.restore(); - }; - - /** - * Creates watermarked text on the canvas. - * - * See {@link CIQ.ChartEngine#watermark} to create a watermark relative to a particular panel. - * - * CSS style stx_watermark defines the watermark (opacity of .5 is automatically applied) - * - * **Note** that the watermark will not persist unless called from within the animation loop (study display function, for example). - * As such, it may be necessary to use a `prepend` to the `draw` function to create persistence. See example section. - * @param {external:CanvasRenderingContext2D} context [description] - * @param {number} x X position on canvas - * @param {number} y Y position on canvas - * @param {string} text The text to watermark - * @memberof CIQ.ChartEngine - * @example - CIQ.ChartEngine.prototype.prepend("draw",function(){ - // create persistence by forcing it be called in every animation frame. - rawWatermark(stxx.chart.context,20,30,stxx.chart.symbol); - }); - */ - CIQ.ChartEngine.prototype.rawWatermark = function (context, x, y, text) { - this.canvasFont("stx_watermark", context); - context.fillStyle = this.defaultColor; - context.globalAlpha = 0.5; - this.chart.context.textBaseline = "alphabetic"; - context.fillText(text, x, y); - context.globalAlpha = 1; - }; - - /** - * Creates watermarked text relative to a panel on the canvas. - * - * Uses CSS style `stx_watermark` to set the text size and color. - * - * **Note** The watermark does not persist unless called from within the animation loop (study display function, - * for example). As such, it may be necessary to use a `prepend` to the `draw` function to create persistence. - * See example section. - * - * @param {string} panel The name of the panel. - * @param {object} [config] Parameters for the request. - * @param {string} [config.h] Specifies horizontal placement of the watermark — "left", "right", or "center". - * @param {string} [config.v] Specifies vertical placement of the watermark &mdash "top", "bottom", or "middle". - * @param {string} [config.text] The text of the watermark. - * @param {string} [config.hOffset] Horizontal offset in pixels of the upper left corner of the watermark from the - * left or right margin. - * @param {string} [config.vOffset] Vertical offset in pixels of the upper left corner of the watermark from the - * top or bottom margin. - * @param {external:CanvasRenderingContext2D} [config.context] The drawing canvas context. If omitted, - * `this.chart.context` is used. - * @memberof CIQ.ChartEngine - * @example - CIQ.ChartEngine.prototype.prepend("draw",function(){ - // create persistence by forcing it be called in every animation frame. - stxx.watermark("chart",{h:"center",v:"middle",text:stxx.chart.symbol}); - }); - * @since 7.4.0 Added the `config.context` parameter. - */ - CIQ.ChartEngine.prototype.watermark = function (panel, config) { - if (config && typeof config != "object") { - // Handle legacy argument list implementation - config = { - h: arguments[1], - v: arguments[2], - text: arguments[3] - }; - } - config = { - // set defaults - h: config.h || "left", - v: config.v || "bottom", - text: config.text || "", - hOffset: config.hOffset === 0 ? 0 : config.hOffset || 10, - vOffset: config.vOffset === 0 ? 0 : config.vOffset || 20, - context: config.context || this.chart.context - }; - - var context = config.context; - if (!context) return; - var c = this.panels[panel]; - if (!c || c.hidden) return; - - var y = c.yAxis.bottom - config.vOffset; - if (config.v == "top") y = c.top + config.vOffset; - else if (config.v == "middle") y = (c.top + c.yAxis.bottom) / 2; - - context.save(); - this.canvasFont("stx_watermark", context); - this.canvasColor("stx_watermark", context); - context.textBaseline = "alphabetic"; - - var x = c.left + config.hOffset; - if (config.h == "right") x = c.right - config.hOffset; - else if (config.h == "center") { - x = (c.right + c.left - context.measureText(config.text).width) / 2; - } - - context.globalAlpha = 0.5; - if (this.highlightedDraggable) context.globalAlpha *= 0.3; - context.fillText(config.text, x, y); - context.restore(); - }; - - /** - * Displays errors on the center bottom of the canvas. - * - * In the event that there are multiple errors (caused by calling the method multiple times), they will get vertically stacked. - * - * **Note**: Because `displayErrorAsWatermark` leverages {@link CIQ.ChartEngine#watermark} to draw errors on the canvas, - * the errors will not persist unless added from within the animation loop. See {@link CIQ.ChartEngine#watermark} for more info. - * - * @param {string} panelKey The name of the panel - * @param {string} error The error text to draw on the canvas - * @memberof CIQ.ChartEngine - * @since 7.3.0 - */ - CIQ.ChartEngine.prototype.displayErrorAsWatermark = function (panelKey, error) { - if (!error) return; - if (!panelKey) panelKey = "chart"; - - var panelObj = this.panels[panelKey]; - if (!panelObj || panelObj.hidden) return; - - var panelState = panelObj.state; - if (!panelState) panelObj.state = panelState = {}; - - var studyErrors = panelState.studyErrors; - if (!studyErrors) panelState.studyErrors = studyErrors = new Set(); - - if (studyErrors.has(error)) return; - - var offsetValue = panelState.watermarkOffset || 10; - var padding = 10; // to separate error messages - var errorHeight = this.getCanvasFontSize("stx_watermark"); - - // make sure chartControls doesn't overlay on top of the errors - if (this.chart && this.chart.chartControls) { - var yAxisBottom = panelObj.yAxis.bottom; - var chartControls = this.chart.chartControls; - var textBottom = yAxisBottom - offsetValue; - var textTop = textBottom - errorHeight; - if ( - (textBottom > chartControls.offsetTop && - textBottom < chartControls.offsetTop + chartControls.offsetHeight) || - (textTop > chartControls.offsetTop && - textTop < chartControls.offsetTop + chartControls.offsetHeight) - ) { - offsetValue = yAxisBottom - chartControls.offsetTop + padding; - } - } - - // add new error after offset calculations so it doesn't count itself - studyErrors.add(error); - - var watermarkParams = { - h: "center", - v: "bottom", - text: error, - vOffset: offsetValue - }; - - offsetValue += errorHeight + padding; - panelState.watermarkOffset = offsetValue; - - this.watermark(panelKey, watermarkParams); - }; - - /** - * INJECTABLE - * Animation Loop - * - * Displays the chart by calling the appropriate rendering functions based on the CIQ.ChartEngine.layout.chartType. - * - * @param {CIQ.ChartEngine.Chart} chart The chart to render - * @memberof CIQ.ChartEngine.AdvancedInjectable# - * @alias displayChart - * @since - * - 4.0.0 If no Open price is available, a candle will draw as a dash at the Close price. - * - 5.1.0 Reduced to injections only for backwards compatibility, main chart is drawn with renderers now. - */ - CIQ.ChartEngine.prototype.displayChart = function (chart) { - if (this.runPrepend("displayChart", arguments)) return; - this.rendererAction(chart, "main"); - this.runAppend("displayChart", arguments); - }; - - }; - - - let __js_core_engine_styles_ = (_exports) => { - - - var CIQ = _exports.CIQ; - - /** - * Clones a style from a style object (obtained from getComputedStyle). Any styles are converted to camel case. This method automatically - * converts from browsers that store styles as numeric arrays rather than as property objects. - * @param {object} styleObject A style object derived from getComputedStyle - * @return {object} A new style object that will match properties - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.cloneStyle = function (styleObject) { - var rc = {}; - var nativeCamelSupport = false; - function capitalize(g) { - return g[1].toUpperCase(); - } - for (var i in styleObject) { - var v = styleObject[i]; - // do *not* check styleObject["backgroundAttachment"]. Android browsers return bogus results. - // instead we iterate through the object - if (i == "backgroundAttachment") nativeCamelSupport = true; - - // modern browsers contain both camel and hyphenated. We can avoid the camelCase conversion - // logic to save a little bit of startup time - if (nativeCamelSupport) { - if (v && v.constructor == String && isNaN(i)) { - rc[i] = v; - } - } else if (!isNaN(i)) { - // old android browsers fall into here - var x = styleObject.getPropertyValue(v); - if (x) { - //var vcc=v.replace(CIQ.camelCaseRegExp, function (g) { return g[1].toUpperCase(); }) - // much more efficient camel case conversion algorithm - v = v.split("-"); - var ii = 0, - jj = v.length; - var vcc = v[0]; - while (++ii < jj) { - vcc += v[ii].charAt(0).toUpperCase() + v[ii].slice(1); - } - rc[vcc] = x; - } - } else { - // old internet explorer falls into here - var icc = i.replace(CIQ.camelCaseRegExp, capitalize); - rc[icc] = v; - } - } - return rc; - }; - - /** - * Returns an object containing the class style given a css class name (used by plotLine() for instance). - * - * A caching mechanism is used for performance. - * If styles are changed dynamically then use {@link CIQ.ChartEngine#clearStyles} to reset. - * - * Alse see {@link CIQ.ChartEngine#setStyle}. - * - * @param {string} className The CSS class name to get the styles - * @return {object} An object containing each style, in camel case. - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.canvasStyle = function (className) { - var s = this.styles[className]; - if (!s) { - var div = document.createElement("div"); // Create a dummy div - div.className = className; - this.container.appendChild(div); - var styles = getComputedStyle(div); - s = this.styles[className] = this.cloneStyle(styles); - this.container.removeChild(div); - if (!styles) { - // css not initialized, possibly hidden iframe in firefox - this.styles[className] = null; - } - } - return s; - }; - - /** - * Detects if a string is a valid CSS color and if so returns that string. - * - * Otherwise it returns a style object, assuming that the string is a classname. - * @param {string} str Either a color or a className - * @return {object} Either the color or a class object - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.colorOrStyle = function (str) { - if (str.indexOf("#") != -1) return str; - if (str.indexOf("(") != -1) return str; // rgb() or rgba() - if (str == "transparent") return str; - return this.canvasStyle(str); - }; - - /** - * Call this to remove all of the loaded canvas styles, for instance after loading a new css file. - * - * Also see {@link CIQ.ChartEngine#setStyle} and {@link CIQ.ChartEngine#canvasStyle}. - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.clearStyles = function () { - this.styles = {}; - this.defaultColor = ""; - }; - - /** - * Convenience method to programmatically set or change a style used by a chart **canvas** element. - * - * Canvas styling using this method is limited to color and font attributes. - * - * See {@link CIQ.ChartEngine#canvasFont} for important details on proper style setting for fonts. - * - * To see immediate results, call {@link CIQ.ChartEngine#draw} once this method is used. - * - * Primarily used in the {@link CIQ.ThemeHelper} to programmatically override defaults CSS colors to create custom themes. - * - * This method **will not affect HTML containers** directly referencing a CSS style; such as menu items or [chart controls]{@link CIQ.ChartEngine.htmlControls}. - * Those will need to be managed by the CSS, or via javaScrit directly altering the container's style object. - * For example, the crosshair y axis floating label is a canvas drawings generated by the {@link CIQ.ChartEngine#createYAxisLabel} canvas rendering function, - * so you can do something like this: - * - `stxx.setStyle("stx-float-price", "color", "red");` - * - * But the crosshair x axis floating label is an html div container part of the [chart controls]{@link CIQ.ChartEngine.htmlControls}. - * So this will require something like this instead: - * - `stxx.controls.floatDate.style.color='red';` - * - * For more details on customizing colors in the chart see {@tutorial Chart Styles and Types}. Also see {@link CIQ.ChartEngine#clearStyles} - * - * @param {string} obj The object whose style you wish to change (stx_grid, stx_xaxis, etc) - * @param {string} attribute The style name of the object you wish to change. It will accept hyphenated or camel case formats. - * @param {string} value The value to assign to the attribute - * @memberof CIQ.ChartEngine - * @example - * stxx.setStyle("stx_candle_up","borderLeftColor","green"); - * stxx.setStyle("stx_candle_down","borderLeftColor","red"); - * stxx.draw(); - * @example - * stxx.setStyle("stx_yaxis", "fontFamily", "Arial"); - * stxx.setStyle("stx_xaxis", "fontFamily", "Arial"); - * stxx.setStyle("stx_yaxis", "fontSize", "15px"); - * stxx.setStyle("stx_xaxis", "fontSize", "15px"); - */ - CIQ.ChartEngine.prototype.setStyle = function (obj, attribute, value) { - if (!this.styles[obj]) { - this.canvasStyle(obj); - } - if (!this.styles[obj]) this.styles[obj] = {}; - this.styles[obj][CIQ.makeCamelCase(attribute)] = value; - }; - - /** - * The built-in 2D rendering context for the drawing surface of a canvas. - * @external CanvasRenderingContext2D - * @see [CanvasRenderingContext2D]{@link https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D} - * at the Mozilla Developer Network. - */ - - /** - * Sets font for the canvas, given a css class name. - * - * Call this before drawing on the canvas. - * - * The canvas font will be set using the CSS `font-style` + `font-weight` + `font-size` + `font-family`. - * - * **Note** that the canvas font will use the `font-family` CSS property, **NOT** the combined `font` CSS property. - * Be aware of this when using {@link CIQ.ChartEngine#setStyle} - * - * @param {string} className The name of the CSS class to pull font from - * @param {external:CanvasRenderingContext2D} ctx An HTML Context - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.canvasFont = function (className, ctx) { - if (!ctx) ctx = this.chart.context; - var style = this.canvasStyle(className); - if (!style) return; - - var result = - style.fontStyle + - " " + - style.fontWeight + - " " + - style.fontSize + - " " + - style.fontFamily; - if (result.indexOf("undefined") == -1) { - ctx.font = result; - } else { - this.styles[className] = null; - console.log("bad css style for class " + className); - } - }; - - /** - * Sets color and globalAlpha (opacity) for the canvas, given a css class name. - * - * Call this before drawing on the canvas. - * - * Also see {@link CIQ.ChartEngine#setStyle}. - * - * @param {string} className A CSS style. Supports "color" and "opacity" - * @param {external:CanvasRenderingContext2D} [ctx] An HTML Context - * @example - * stxx.canvasColor("myStyle"); - * @memberof CIQ.ChartEngine - * @since 4.0.0 Allow color:"transparent" to pass through and not use defaultColor. Instead, use defaultColor if there is no style.color. - */ - CIQ.ChartEngine.prototype.canvasColor = function (className, ctx) { - if (!ctx) ctx = this.chart.context; - var style = this.canvasStyle(className); - if (!style) return; - var color = style.color; - if (!color) color = this.defaultColor; - ctx.globalAlpha = 1; - ctx.fillStyle = color; - ctx.strokeStyle = color; - var opacity = style.opacity; - if (typeof opacity != "undefined") ctx.globalAlpha = opacity; - }; - - /** - * Returns the font size defined by the requested class name. - * - * Defaults to 12 if undefined. Use this to determine vertical heights so that lettering isn't clipped. - * @param {string} className Class name - * @return {number} The font size (px is stripped) - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.getCanvasFontSize = function (className) { - var s = this.canvasStyle(className); - var fs = s.fontSize; - if (!fs) fs = "12"; - return parseInt(CIQ.stripPX(fs), 10); - }; - - /** - * Returns the canvas color specified in the class name. - * - * @param {string} className The class name - * @return {string} The color specified (May be undefined if none specified) - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.getCanvasColor = function (className) { - var s = this.canvasStyle(className); - return s.color; - }; - - /** - * Animation Loop - * - * Determines the default color for lines and studies drawn on the screen. This is black unless - * the background color of the chart has a "value" greater than 65%. - * The result is that this.defaultColor contains the default color. - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.getDefaultColor = function () { - this.defaultColor = "#000000"; - var bgColor = null; - var div = this.chart.container; - while (!bgColor || CIQ.isTransparent(bgColor)) { - var cStyle = getComputedStyle(div); - if (!cStyle) return; - bgColor = cStyle.backgroundColor; - if (CIQ.isTransparent(bgColor)) bgColor = "transparent"; - div = div.parentNode; - if (!div || !div.tagName) break; - } - if (bgColor) { - if (bgColor == "transparent") bgColor = "#FFFFFF"; - this.containerColor = bgColor; - if (!CIQ.isTransparent(bgColor)) { - var hsv = CIQ.hsv(bgColor); - var v = hsv[2]; - if (v > 0.65) this.defaultColor = "#000000"; - else this.defaultColor = "#FFFFFF"; - } else { - this.defaultColor = "#000000"; - } - } else { - this.containerColor = "#FFFFFF"; - } - }; - - }; - - - let __js_core_engine_xaxis_ = (_exports) => { - - - var CIQ = _exports.CIQ; - - /** - * Defines an object used for rendering the X-axis on the chart, which can be adjusted immediately after declaring your `new CIQ.ChartEngine();` - * The CIQ.ChartEngine.XAxis object is created by and part of the {@link CIQ.ChartEngine.Chart} object and is used on the main chart panel only. - * There is only one x axis per chart container. - * - * Colors and fonts for the x axis can be controlled by manipulating the CSS. - * You can override the `stx_xaxis` class to change the font or colors. - * - * Also see: - * - {@link CIQ.ChartEngine#axisBorders} - * - {@link CIQ.ChartEngine#xAxisAsFooter} - * - {@link CIQ.ChartEngine#xaxisHeight} - * - * For full customization instructions see: - * - {@tutorial Custom X-axis} - * - {@link CIQ.ChartEngine.AdvancedInjectable#createXAxis} - * - {@link CIQ.ChartEngine#createTickXAxisWithDates} - * - * Example: stxx.chart.xAxis - * - * @constructor - * @name CIQ.ChartEngine.XAxis - * @param {object} init Object containing custom values for X-axis members - * @example - * var stxx=new CIQ.ChartEngine({container:document.querySelector(".chartContainer"), layout:{"candleWidth": 16, "crosshair":true}}); - * stxx.chart.xAxis.formatter=formatFunction; - */ - CIQ.ChartEngine.XAxis = function (init) { - for (var field in init) this[field] = init[field]; - }; - - CIQ.extend( - CIQ.ChartEngine.XAxis.prototype, - { - /** - * Optional function to format dates on x-axis. - * If defined, will be used to completely control x-axis formatting, including the floating HUD date of the crosshair. - * - * This function **should not** be used to alter the timezone of the displayed date/time. For time zone conversions use {@link CIQ.ChartEngine#setTimeZone} - * - * **Expected format:** - * - * - `function(labelDate, gridType, timeUnit, timeUnitMultiplier, defaultText);` - * - * **Parameters:** - * - * - * - * - * - * - * - *
NameTypeDescription
labelDateDatejavaScript date to format
gridTypeString"boundary", "line", or name of drawing (e.g. "vertical") for the axis labels.
Absent for the floating crosshair label
timeUnitEnumerated typeCIQ.MILLISECOND
CIQ.SECOND
CIQ.MINUTE
CIQ.HOUR
CIQ.DAY
CIQ.MONTH
CIQ.YEAR
CIQ.DECADE
Absent for the floating crosshair label.
timeUnitMultiplierNumberHow many timeUnits.
Absent for the floating crosshair label.
defaultTextStringContains the default date label that would be used if no formatter is defined. Simply return this value for dates where no formatting is desired.
- * - * **Returns:** - * - Formatted text label for the particular date passed in. - * - * @type function - * @memberof CIQ.ChartEngine.XAxis# - * @example - * stxx.chart.xAxis.formatter = function(labelDate, gridType, timeUnit, timeUnitMultiplier, defaultText){ - * // Your code here to format your string. - * // Example: always return HH:MM regardless of gridType, - * // even if gridType is a 'boundary' that normally would display - * // a date in intraday periodicity or a month in daily periodicity - * - * //You can always return back 'defaultText' if you do not wish to customize the particular value. - * - * var stringDate = labelDate.getHours() + ':' + labelDate.getMinutes(); - * return stringDate; - * } - * @example - * stxx.chart.xAxis.formatter = function(labelDate, gridType, timeUnit, timeUnitMultiplier, defaultText){ - * // Your code here to format your string. - * // Example: return HH:MM when gridType is "line" otherwise returned the default text. - * - * if( gridType == "line" ) { - * var stringDate = labelDate.getHours() + ':' + labelDate.getMinutes(); - * return stringDate; - * else - * return defaultText; - * } - * @since - * - 3.0.0 Using x axis formatter now is available for year and month boundaries. - * - 6.3.0 Added `defaultText` parameter. - * - 6.3.0 Added drawing type as possible `gridType` value. - */ - formatter: null, - /** - * If true, the user selected (default browser if none selected) timezone will be used on the x axis. - * If not set to true, the data timezone will be used even if a user timezone was set. - * @type boolean - * @default - * @memberof CIQ.ChartEngine.XAxis# - */ - adjustTimeZone: true, - /** - * Ideal space between x-axis labels in pixels. - * If null then the chart will attempt a tick size and time unit in proportion to the chart. - * Please note that if `stxx.chart.yAxis.goldenRatioYAxis` is set to `true`, this setting will also affect the spacing between y-axis labels. - * Please note that this setting will be overwritten at rendering time if too small to prevent labels from covering each other. - * Not applicable if {@link CIQ.ChartEngine.XAxis#timeUnit} is manually set. - * See {@tutorial Custom X-axis} for additional details. - * @type number - * @default - * @memberof CIQ.ChartEngine.XAxis# - */ - idealTickSizePixels: null, - /** - * Overrides default used in {@link CIQ.ChartEngine#createTickXAxisWithDates} - *
Allowable values: - * - CIQ.MILLISECOND, - * - CIQ.SECOND - * - CIQ.MINUTE - * - CIQ.HOUR - * - CIQ.DAY - * - CIQ.WEEK - * - CIQ.MONTH - * - CIQ.YEAR - * - CIQ.DECADE - * - * Visual Reference for sample code below (draw a label every 5 seconds using 1 second periodicity ) :
- * ![xAxis.timeUnit](xAxis.timeUnit.png "xAxis.timeUnit") - * @type number - * @default - * @memberof CIQ.ChartEngine.XAxis# - * @example - * // The following will cause the default implementation of createTickXAxisWithDates to print labels in seconds every 5 seconds. - * // masterData is in 1 second intervals for this particular example. - * stxx.chart.xAxis.timeUnit = CIQ.SECOND; - * stxx.chart.xAxis.timeUnitMultiplier = 5; - */ - timeUnit: null, - /** - * Overrides default used in {@link CIQ.ChartEngine#createTickXAxisWithDates} - * @type number - * @default - * @memberof CIQ.ChartEngine.XAxis# - * @example - * // The following will cause the default implementation of createTickXAxisWithDates to print labels in seconds every 5 seconds. - * // masterData is in 1 second intervals for this particular example. - * stxx.chart.xAxis.timeUnit = CIQ.SECOND; - * stxx.chart.xAxis.timeUnitMultiplier = 5; - */ - timeUnitMultiplier: null, - /** - * Set to true to draw a line above the x-axis. - * @type boolean - * @default - * @memberof CIQ.ChartEngine.XAxis# - */ - displayBorder: true, - /** - * Set to false to suppress grid lines - * @type boolean - * @default - * @memberof CIQ.ChartEngine.XAxis# - */ - displayGridLines: true, - /** - * Switch to temporarily hide the x-axis. Set to `true' to activate. - * - * Axis space will be maintained. To completely remove the x axis, including spacing use {@link CIQ.ChartEngine#xaxisHeight} - * @type boolean - * @default - * @memberof CIQ.ChartEngine.XAxis# - * @since 3.0.0 - */ - noDraw: null, - /** - * Minimum size for label. This ensures adequate padding so that labels don't collide with one another. - * Please note that this setting is used during the rendering process, not during the label spacing calculation process and will be overwritten if too small to prevent labels from covering each other. - * To modify at what interval labels will be placed, please see {@tutorial Custom X-axis} for more details - * @type number - * @default - * @memberof CIQ.ChartEngine.XAxis# - */ - minimumLabelWidth: 50, - /** - * Set to false to hide axis markings in the future. - * @type boolean - * @default - * @memberof CIQ.ChartEngine.XAxis# - */ - futureTicks: true, - /** - * Set to the number of minutes ticks will move by when iterating in "tick" interval. - *

- * Since 'tick' is not a time based display, there is no way to predict what the time between ticks will be. - * Ticks can come a second later, a minute later or even more depending on how active a particular instrument may be. - * As such, if iterating through the market day in 'tick' periodicity, the library uses a pre-defined number of minutes to move around. - * This will be primarily used when deciding where to put x axis labels when going into the future in 'tick' mode. - * - * @type number - * @default - * @memberof CIQ.ChartEngine.XAxis# - * @example - * //You can override this behavior as follows: - * var stxx=new CIQ.ChartEngine({container:document.querySelector(".chartContainer"), layout:{"candleWidth": 16, "crosshair":true}}); - * stxx.chart.xAxis.futureTicksInterval=1; // to set to 1 minute, for example - * @since 3.0.0 Default changed from 10 to 1. - */ - futureTicksInterval: 1 - }, - true - ); - - /** - * This is the object stored in CIQ.ChartEngine.chart.xaxis array which contains information regarding an x-axis tick. - * See {@link CIQ.ChartEngine.AdvancedInjectable#createXAxis} for more detail. - * @constructor - * @param {number} hz Horizontal position of center of label in pixels. Any elements with negative positions will be off the edge of the screen, and are only maintained to help produce a more predictable display as the chart is zoomed and paned. - * @param {string} grid Either "line" or "boundary" depending on whether the label should be a date/time boundary or just a grid line - * @param {string} text The text to display in the label - * @name CIQ.ChartEngine.XAxisLabel - */ - CIQ.ChartEngine.XAxisLabel = function (hz, grid, text) { - this.hz = hz; - this.grid = grid; - this.text = text; - }; - - /** - * INJECTABLE - * Animation Loop - * - * Call this method to create the X axis (date axis). Uses {@link CIQ.ChartEngine#createTickXAxisWithDates}. - * - * Use css styles `stx_xaxis` to control colors and fonts for the dates.
- * Use css styles `stx_xaxis_dark` to control **color only** for the divider dates.
- * Use css styles `stx_grid_border`, `stx_grid` and `stx_grid_dark` to control the grid line colors.
- * The dark styles are used for dividers; when the grid changes to a major point such as the start of a new day on an intraday chart, or a new month on a daily chart. - * - * See {@tutorial Custom X-axis} and {@tutorial CSS Overview} for additional details. - * - * @param {CIQ.ChartEngine.Chart} chart The chart to create an x-axis for - * @return {CIQ.ChartEngine.XAxisLabel[]} axisRepresentation that can be passed in to {@link CIQ.ChartEngine#drawXAxis} - * @memberof CIQ.ChartEngine.AdvancedInjectable# - * @alias createXAxis - * - */ - CIQ.ChartEngine.prototype.createXAxis = function (chart) { - if (chart.dataSegment.length <= 0) return null; - if (chart.xAxis.noDraw) return null; - var arguments$ = [chart]; - var axisRepresentation = this.runPrepend("createXAxis", arguments$); - if (axisRepresentation) return axisRepresentation; - if (this.mainSeriesRenderer && this.mainSeriesRenderer.createXAxis) { - axisRepresentation = this.mainSeriesRenderer.createXAxis(chart); - } else { - axisRepresentation = this.createTickXAxisWithDates(chart); - } - this.headsUpHR(); - this.runAppend("createXAxis", arguments$); - return axisRepresentation; - }; - - /** - * Creates a label on the x-axis. Generally used to create x-axis labels for drawings. - * - * Uses the font properties of the CSS style `stx-float-date` (see *css/stx-chart.css*). - * - * **Note:** This function is not used for the floating crosshairs date label, which is also - * styled using `stx-float-date`. See - * {@link CIQ.ChartEngine.AdvancedInjectable#updateChartAccessories} and - * {@link CIQ.ChartEngine.AdvancedInjectable#headsUpHR} for more details. - * - * @param {object} params Function parameters. - * @param {CIQ.ChartEngine.Panel} params.panel The panel on which the label is created. - * @param {string} params.txt The text for the label. - * @param {number} params.x The horizontal pixel position on the canvas for the label. **Note:** - * The function ensures that the label remains on the requested panel if this value is out of - * bounds.

To get the pixel position for a bar/date use - * {@link CIQ.ChartEngine#pixelFromTick}, {@link CIQ.ChartEngine#pixelFromDate}, or - * {@link CIQ.ChartEngine#pixelFromBar}. - * @param {string} params.backgroundColor The background color for the label. - * @param {string} [params.color] The foreground color for the label. If none is provided, then - * white is used, unless the background is white, in which case black is used. - * @param {boolean} [params.pointed] If true, add an upward pointing triangle to the top edge of - * the label horizontally centered to form a shape similar to --^--. - * @param {boolean} [params.padding = 2] The amount of padding in pixels to add to the label text - * (top, right, bottom, and left). - * - * @memberof CIQ.ChartEngine - * @since 8.1.0 Function signature now includes the `params` object instead of a list of - * individual parameters. Added the `padding` parameter for easy customization. - */ - CIQ.ChartEngine.prototype.createXAxisLabel = function (params) { - if (arguments[0] instanceof CIQ.ChartEngine.Panel) { - // Handle legacy argument implementation - params = { - panel: arguments[0], - txt: arguments[1], - x: arguments[2], - backgroundColor: arguments[3], - color: arguments[4], - pointed: arguments[5], - padding: arguments[6] - }; - } - let panel = params.panel; - let txt = params.txt; - let x = params.x; - let backgroundColor = params.backgroundColor; - let color = params.color; - let pointed = params.pointed; - let padding = params.padding === 0 ? 0 : params.padding || 2; - - var context = this.chart.context; - var fontstyle = "stx-float-date"; //or stx_xaxis - var height = this.getCanvasFontSize(fontstyle) + padding * 2; - this.canvasFont(fontstyle, context); - var width; - try { - width = context.measureText(txt).width + padding * 2; - } catch (e) { - width = 0; - } // Firefox doesn't like this in hidden iframe - var y = panel.top + panel.height - height - padding; - if (x + width / 2 < panel.left || x - width / 2 > panel.right) return; //hopelessly out of bounds - if (!pointed) { - if (x + width / 2 > panel.right) x = panel.right - width / 2; - if (x - width / 2 < panel.left) x = panel.left + width / 2; - } - context.fillStyle = backgroundColor; - CIQ.roundRect({ - ctx: context, - x: x - width / 2, - top: y, - width: width, - height: height, - radius: 3, - fill: true - }); - var arrowHeight = panel.bottom - panel.yAxis.bottom - height; - context.beginPath(); - if (pointed) { - context.moveTo(x - arrowHeight, y); - context.lineTo(x, y - arrowHeight - 1); - context.lineTo(x + arrowHeight, y); - context.closePath(); - context.fill(); - } else { - context.moveTo(x, y); - context.lineTo(x, y - arrowHeight); - context.strokeStyle = backgroundColor; - context.stroke(); - } - context.textBaseline = "top"; - context.fillStyle = color - ? color - : CIQ.chooseForegroundColor(backgroundColor); - if (context.fillStyle == backgroundColor) { - // Best effort to pick a foreground color that isn't the same as the background! - if (backgroundColor.toUpperCase() == "#FFFFFF") - context.fillStyle = "#000000"; - else context.fillStyle = "#FFFFFF"; - } - context.fillText(txt, x - width / 2 + (padding - 1), y + (padding + 2)); - }; - - }; - - - let __js_core_engine_yaxis_ = (_exports) => { - - - var CIQ = _exports.CIQ; - - /** - * Adds text on the canvas for the floating label over the y axis. - * - * Uses native canvas functions to add the text. You can override this function if you wish to customize how the text on the floating y axis labels are displayed. See example. - * @param {object} params - * @param {object} params.ctx A valid HTML Canvas Context - * @param {number} params.x Left position of drawing on canvas - * @param {number} params.txt Text for the label - * @param {number} params.y Y position of drawing on canvas - * @param {object} params.margin Margin around the text - * @param {object} params.margin.left Left margin of text - * @param {object} params.margin.top Top margin of text - * @param {number} params.backgroundColor Background color of the shape drawn under the text, if any. This is used to find the text color if there is no color specified - * @param {number} params.color Text color - * @memberof CIQ - * @since 3.0.0 - * @example - * // customized version which adds a dash before the label text - * CIQ.createLabel=function(params){ - * // set the vertical alignment of the text - * params.ctx.textBaseline="middle"; - - * // set the color for the text and background color behind the text - * params.ctx.fillStyle=params.color?params.color:CIQ.chooseForegroundColor(params.backgroundColor); - - * if( params.ctx.fillStyle === params.backgroundColor){ - * // Best effort to pick a foreground color that isn't the same as the background! - * if(params.backgroundColor.toUpperCase()=="#FFFFFF") - * params.ctx.fillStyle="#000000"; - * else - * params.ctx.fillStyle="#FFFFFF"; - * } - - * //add the text to the canvas. - * // see we are adding a dash ('- ') before the text - * params.ctx.fillText('- '+params.txt, params.x + params.margin.left, params.y + params.margin.top); - - * // set the horizontal alignment of the text - * params.ctx.textAlign="left"; - * }; - */ - CIQ.createLabel = function (params) { - params.ctx.textBaseline = "middle"; - params.ctx.fillStyle = params.color - ? params.color - : CIQ.chooseForegroundColor(params.backgroundColor); - if (params.ctx.fillStyle === params.backgroundColor) { - // Best effort to pick a foreground color that isn't the same as the background! - if (params.backgroundColor.toUpperCase() == "#FFFFFF") - params.ctx.fillStyle = "#000000"; - else params.ctx.fillStyle = "#FFFFFF"; - } - params.ctx.fillText( - params.txt, - params.x + params.margin.left, - params.y + params.margin.top - ); - params.ctx.textAlign = "left"; - }; - - /** - * Displays a floating label over the y axis. - * - * Draws a rectangle on the canvas, with an arrowhead on the screen, using using {@link CIQ.roundRect} with an `edge` setting of "arrow". - * It then calls {@link CIQ.createLabel} to print the text over this background shape; which can be customized to control the text format for these labels. - * - * Visual Reference:
- * ![roundRectArrow](roundRectArrow.png "roundRectArrow") - * @param {object} params - * @param {object} params.ctx A valid HTML Canvas Context - * @param {number} params.x Left position of drawing on canvas - * @param {number} params.top Top position of drawing on canvas - * @param {number} params.width Width of rectangle - * @param {number} params.height Height of rectangle - * @param {number} params.radius Radius of rounding - * @param {boolean} [params.fill] Whether to fill the background, or just draw the rectangle border. - * @param {number} [params.txt] Text for the label - * @param {number} [params.y] Y position of drawing on canvas - * @param {object} [params.margin] Margin around the text - * @param {object} [params.margin.left] Left margin of text - * @param {object} [params.margin.top] Top margin of text - * @param {number} [params.backgroundColor] Background color. This is the background color of the rectangle. - * @param {number} [params.color] Text color - * @memberof CIQ - * @since 3.0.0 Function signature changed. This function now takes a params object instead of eight different parameters. - */ - CIQ.roundRectArrow = function (params) { - CIQ.roundRect(params, "arrow"); - }; - - /** - * Displays a floating label over the y axis. - * - * Draws a rectangle on the canvas, with just the right side curved corners, using using {@link CIQ.roundRect} with an `edge` setting of "flush". - * It then calls {@link CIQ.createLabel} to print the text over this background shape; which can be customized to control the text format for these labels. - * - * Visual Reference:
- * ![semiRoundRect](semiRoundRect.png "semiRoundRect") - * @param {object} params - * @param {object} params.ctx A valid HTML Canvas Context - * @param {number} params.x Left position of drawing on canvas - * @param {number} params.top Top position of drawing on canvas - * @param {number} params.width Width of rectangle - * @param {number} params.height Height of rectangle - * @param {number} params.radius Radius of rounding - * @param {boolean} [params.fill] Whether to fill the background, or just draw the rectangle border. - * @param {number} [params.txt] Text for the label - * @param {number} [params.y] Y position of drawing on canvas - * @param {object} [params.margin] Margin around the text - * @param {object} [params.margin.left] Left margin of text - * @param {object} [params.margin.top] Top margin of text - * @param {number} [params.backgroundColor] Background color. This is the background color of the rectangle. - * @param {number} [params.color] Text color - * @memberof CIQ - * @since 3.0.0 Function signature changed. This function now takes a params object instead of eight different parameters. - */ - CIQ.semiRoundRect = function (params) { - CIQ.roundRect(params, "flush"); - }; - - /** - * Displays a floating label over the y axis. - * - * Draws a rectangle on the canvas using using {@link CIQ.roundRect} with a `radius` of 0 - * It then calls {@link CIQ.createLabel} to print the text over this background shape; which can be customized to control the text format for these labels. - * - * Visual Reference:
- * ![rect](rect.png "rect") - * @param {object} params - * @param {object} params.ctx A valid HTML Canvas Context - * @param {number} params.x Left position of drawing on canvas - * @param {number} params.top Top position of drawing on canvas - * @param {number} params.width Width of rectangle - * @param {number} params.height Height of rectangle - * @param {boolean} [params.fill] Whether to fill the background, or just draw the rectangle border. - * @param {number} [params.txt] Text for the label - * @param {number} [params.y] Y position of drawing on canvas - * @param {object} [params.margin] Margin around the text - * @param {object} [params.margin.left] Left margin of text - * @param {object} [params.margin.top] Top margin of text - * @param {number} [params.backgroundColor] Background color. This is the background color of the rectangle. - * @param {number} [params.color] Text color - * @memberof CIQ - * @since 3.0.0 Function signature changed. This function now takes a params object instead of eight different parameters. - */ - CIQ.rect = function (params) { - params.radius = 0; - CIQ.roundRect(params); - }; - - /** - * Displays floating text label, without any background shapes, over the y axis. - * - * Calls {@link CIQ.createLabel}; which can be customized to control the text format for these labels. - * Will draw text in the color normally used for the background shape. For example, 'green' text for the up tick and 'red' text for a down tick. - * - * Visual Reference:
- * ![noop](noop.png "noop") - * @param {object} params - * @param {object} params.ctx A valid HTML Canvas Context. - * @param {number} params.x Left position of drawing on canvas. - * @param {number} params.txt Text for the label. - * @param {number} params.y Vertical position of drawing on canvas. - * @param {object} params.margin Margin around the text. - * @param {object} params.margin.left Left margin of text. - * @param {object} params.margin.top Top margin of text. - * @param {number} params.backgroundColor Text color; since there is no background shape. - * - * @memberof CIQ - * @since - * - 3.0.0 Function signature changed. This function now takes a params object instead of eight different parameters. - * - 5.2.1 Will now draw text in the color normally used for the background shape. For example, 'green' text for the up tick and 'red' text for a down tick. - */ - CIQ.noop = function (params) { - params.color = params.backgroundColor; - CIQ.createLabel(params); - }; - - /** - * Displays a floating label over the y axis. - * - * Draws a 'ticked' rectangle on the canvas, using using {@link CIQ.roundRect}. - * It then calls {@link CIQ.createLabel} to print the text over this background shape; which can be customized to control the text format for these labels. - * - * Visual Reference:
- * ![tickedRect](tickedRect.png "tickedRect") - * @param {object} params - * @param {object} params.ctx A valid HTML Canvas Context - * @param {number} params.x Left position of drawing on canvas - * @param {number} params.top Top position of drawing on canvas - * @param {number} params.width Width of rectangle - * @param {number} params.height Height of rectangle - * @param {number} params.radius Radius of rounding - * @param {boolean} [params.fill] Whether to fill the background, or just draw the rectangle border. - * @param {number} [params.txt] Text for the label - * @param {number} [params.y] Y position of drawing on canvas - * @param {object} [params.margin] Margin around the text - * @param {object} [params.margin.left] Left margin of text - * @param {object} [params.margin.top] Top margin of text - * @param {number} [params.backgroundColor] background color. This is the background color of the rectangle. - * @param {number} [params.color] Text color - * @memberof CIQ - * @since 3.0.0 Function signature changed. This function now takes a params object instead of eight different parameters. - */ - - CIQ.tickedRect = function (params) { - CIQ.rect(params); - var tickY = Math.round(params.top + params.height / 2) + 0.5; - params.ctx.beginPath(); - params.ctx.moveTo(params.x - 2, tickY); - params.ctx.lineTo(params.x, tickY); - params.ctx.stroke(); - params.ctx.closePath(); - }; - - /** - * Displays a floating label over the y axis. - * - * Draws a rectangle, with curved corners, on the canvas. - * It then calls {@link CIQ.createLabel} to print the text over this background shape; which can be customized to control the text format for these labels. - * - * Visual Reference:
- * ![roundRect](roundRect.png "roundRect") - * @param {object} params - * @param {object} params.ctx A valid HTML Canvas Context - * @param {number} params.x Left position of drawing on canvas - * @param {number} params.top Top position of drawing on canvas - * @param {number} params.width Width of rectangle - * @param {number} params.height Height of rectangle - * @param {number} params.radius Radius of rounding - * @param {boolean} [params.fill] Whether to fill the background, or just draw the rectangle border. - * @param {number} [params.txt] Text for the label - * @param {number} [params.y] Y position of drawing on canvas - * @param {object} [params.margin] Margin around the text - * @param {object} [params.margin.left] Left margin of text - * @param {object} [params.margin.top] Top margin of text - * @param {number} [params.backgroundColor] background color. This is the background color of the rectangle. - * @param {number} [params.color] Text color - * @param {string} [edge] "flush","arrow" - * @memberof CIQ - * @since 3.0.0 Function signature changed. This function now takes a params object and the drawing type instead of eight different parameters. - * Also, this function will draw the label if `params.txt` is present, otherwise just the floating label outline will be drawn. - */ - CIQ.roundRect = function (params, edge) { - if (arguments.length === 9) { - params = { - ctx: arguments[0], - x: arguments[1], - top: arguments[2], - width: arguments[3], - height: arguments[4], - radius: arguments[5], - fill: arguments[6], - stroke: arguments[7], - edge: arguments[8] - }; - } - var stroke = params.stroke; - var x = params.x; - var y = params.top; - var width = params.width; - var height = params.height; - var radius = params.radius; - var fill = params.fill; - var ctx = params.ctx; - if (typeof stroke == "undefined") { - stroke = true; - } - if (typeof radius === "undefined") { - radius = 5; - if (width < 0) radius = -5; - } - var yradius = width < 0 ? radius * -1 : radius; - if (radius && !edge) x = x - 1; // Just a smidge more - - var xr = x + radius, - xw = x + width, - yr = y + yradius, - yh = y + height; - var xwr = xw - radius, - yhr = yh - yradius; - ctx.beginPath(); - ctx.moveTo(xr, y); - ctx.lineTo(xwr, y); - - ctx.quadraticCurveTo(xw, y, xw, yr); - ctx.lineTo(xw, yhr); - ctx.quadraticCurveTo(xw, yh, xwr, yh); - ctx.lineTo(xr, yh); - - if (edge == "flush") { - ctx.lineTo(x, yh); - ctx.lineTo(x, y); - } else if (edge == "arrow") { - ctx.quadraticCurveTo(x, yh, x - radius, yhr); - var multiplier = width < 0 ? 1 : -1; - ctx.lineTo(x + (height / 2) * multiplier, y + height / 2); // right arrow tip - ctx.lineTo(x - radius, yr); - ctx.quadraticCurveTo(x, y, xr, y); - } else { - ctx.quadraticCurveTo(x, yh, x, yhr); - ctx.lineTo(x, yr); - ctx.quadraticCurveTo(x, y, xr, y); - } - ctx.closePath(); - if (params.backgroundColor) ctx.fillStyle = params.backgroundColor; - - if (stroke) { - ctx.stroke(); - } - if (fill) { - ctx.fill(); - } - if (params.txt) CIQ.createLabel(params); - }; - - /** - * Defines an object used for rendering the Y-axis on a panel. - * - * Each panel object will **automatically** include a YAxis object, which can be adjusted immediately after declaring your `new CIQ.ChartEngine();`
- * Any adjustments to the y-axis members after it has been rendered will require a [draw()]{@link CIQ.ChartEngine#draw} call to apply the changes. A call to [initializeChart()]{@link CIQ.ChartEngine#initializeChart} may be required as well, depending on the setting being changed. See examples. - * - * Also see: - * - {@link CIQ.ChartEngine#yaxisLabelStyle} - * - {@link CIQ.ChartEngine#yTolerance} - * - {@link CIQ.ChartEngine.Chart#yaxisPaddingRight} - * - {@link CIQ.ChartEngine.Chart#yaxisPaddingLeft} - * - * For full customization instructions see: - * - {@tutorial Gridlines and axis labels} - * - {@link CIQ.ChartEngine.AdvancedInjectable#createYAxis} - * - {@link CIQ.ChartEngine.AdvancedInjectable#drawYAxis} - * - * Example: stxx.panels['chart'].yAxis - * - * Example: stxx.chart.yAxis (convenience shortcut for accessing the main panel object - same as above) - * - * Example: stxx.panels['Aroon (14)'].yAxis - * - * **Note:** If modifying a y-axis placement setting (widht, margins, position left/right, etc) after the axis has been rendered, you will need to call - * {@link CIQ.ChartEngine#calculateYAxisMargins} or {@link CIQ.ChartEngine#calculateYAxisPositions} followed by {@link CIQ.ChartEngine#draw} to activate the change. - * - * @constructor - * @name CIQ.ChartEngine.YAxis - * @param {object} init Object containing custom values for Y-axis members - * @example - * // here is an example on how to override the default top and bottom margins after the initial axis has already been rendered - * stxx.loadChart(symbol, {masterData: yourData}, function () { - * // callback - your code to be executed after the chart is loaded - * stxx.chart.yAxis.initialMarginTop=50; - * stxx.chart.yAxis.initialMarginBottom=50; - * stxx.calculateYAxisMargins(stxx.chart.panel.yAxis); // must recalculate the margins after they are changed. - * stxx.draw(); - * }); - * @example - * // here is an example on how to override the default top and bottom margins before the initial axis has been rendered - * var stxx=new CIQ.ChartEngine({container:document.querySelector(".chartContainer"), layout:{"candleWidth": 16, "crosshair":true}}); - * stxx.setPeriodicity({period:1, interval:1, timeUnit:"minute"}); // set your default periodicity to match your data. In this case one minute. - * stxx.chart.yAxis.initialMarginTop=50; // set default margins so they do not bump on to the legend - * stxx.chart.yAxis.initialMarginBottom=50; - * stxx.loadChart("SPY", {masterData: yourData}); - * @example - * // here is an example on how to turn off the last price label (main chart panel) before the initial axis has already been rendered - * var stxx=new CIQ.ChartEngine({container:document.querySelector(".chartContainer"), layout:{"candleWidth": 16, "crosshair":true}}); - * stxx.chart.panel.yAxis.drawCurrentPriceLabel=false; - * - * @since 5.1.0 Created a name member which is used to determine if the y-axis is the same as another. - */ - CIQ.ChartEngine.YAxis = function (init) { - for (var field in init) this[field] = init[field]; - if (!this.name) this.name = CIQ.uniqueID(); - if (this.position == "none") this.width = 0; - }; - - CIQ.extend( - CIQ.ChartEngine.YAxis.prototype, - { - high: null, // High value on y axis (read only) - low: null, // Low value on y axis (read only) - shadow: null, // high - low (read only) - logHigh: null, // High log value on y axis (read only) - logLow: null, // Low log value on y axis (read only) - logShadow: null, // logHigh - logLow (read only) - multiplier: null, // Computed automatically. Divide pixel by this to get the price (then add to low). Or multiply price by this to get the pixel (then add to top) - bottom: null, // calculated automatically (panel.bottom-yAxis.bottomOffset) - top: null, // calculated automatically (panel.top+yAxis.topOffset;) - height: null, // bottom - top - left: null, // calculated left position on canvas to begin drawing. - width: null, // calculated width of y axis - renderers: [], // calculated automatically, array of renderers plotting on this axis - studies: [] // calculated automatically, array of studies plotting on this axis - }, - true - ); - - /** - * Default setting for the array that determines how many decimal places to print based on the size of the shadow (the difference between chart high and chart low). - * The array consists of tuples in descending order. If the shadow is less than n1 then n2 decimal places will be printed. - * See {@link CIQ.ChartEngine.YAxis#shadowBreaks} - * @type array - * @memberof CIQ.ChartEngine.YAxis - * @since - * - 2015-11-1 - * - 5.2.0 Additional break added. - * @default - */ - CIQ.ChartEngine.YAxis.defaultShadowBreaks = [ - [1000, 2], - [5, 4], - [0.001, 8] - ]; - - /** - * Alternative setting (for small charts) array that determines how many decimal places to print based on the size of the shadow (the difference between chart high and chart low). - * The array consists of tuples in descending order. If the shadow is less than n1 then n2 decimal places will be printed. - * See {@link CIQ.ChartEngine.YAxis#shadowBreaks} - * @type array - * @memberof CIQ.ChartEngine.YAxis - * @since 2015-11-1 - * @default - */ - CIQ.ChartEngine.YAxis.smallChartShadowBreaks = [ - [10, 2], - [1, 4] - ]; - - /** - * Controls maximum number of decimal places to ever display on a y-axis floating price label. - * - * Set to the maximum decimal places from 0 to 10, or leave null and the chart will choose automatically based on {@link CIQ.ChartEngine.YAxis#shadowBreaks}. - * - See {@link CIQ.ChartEngine.YAxis#decimalPlaces} for controlling decimal places on the axis itself. - * - See {@link CIQ.ChartEngine.YAxis#width} and {@link CIQ.ChartEngine.Chart#dynamicYAxis} to manage the width of the y axis. - * @type number - * @default - * @memberof CIQ.ChartEngine.YAxis - * @since 5.2.1 Default changed to null. - */ - CIQ.ChartEngine.YAxis.prototype.maxDecimalPlaces = null; - - /** - * Optionally hard set the high (top value) of the yAxis (for instance when plotting 0 - 100% charts) - * @type number - * @default - * @memberof CIQ.ChartEngine.YAxis - */ - CIQ.ChartEngine.YAxis.prototype.max = null; - - /** - * Optionally hard set the low (bottom value) of the yAxis (for instance when plotting 0 - 100% charts) - * @type number - * @default - * @memberof CIQ.ChartEngine.YAxis - */ - CIQ.ChartEngine.YAxis.prototype.min = null; - - /** - * Controls the number of decimal places on the y axis labels. - * - * Set to the preferred number of decimal places from 0 to 10, or leave null and the chart will choose automatically based on {@link CIQ.ChartEngine.YAxis#shadowBreaks} - * - * Each y axis will make its own determination, so to override this value for all axes, you must adjust the y axis prototype. - *
Example: `CIQ.ChartEngine.YAxis.prototype.decimalPlaces=4;` - * - * **Note:** study panel axis may be condensed using {@link CIQ.condenseInt}. See {@link CIQ.ChartEngine#formatYAxisPrice} for all details. - * - * - See {@link CIQ.ChartEngine.YAxis#maxDecimalPlaces} for further controlling decimal places on floating labels.
- * - See {@link CIQ.ChartEngine.YAxis#width} and {@link CIQ.ChartEngine.Chart#dynamicYAxis} to manage the width of the y axis. - * - See {@link CIQ.ChartEngine.YAxis#shadowBreaks} to override how many decimal places to print based on the size of the shadow (the difference between chart high and chart low). - * - * @type number - * @default - * @memberof CIQ.ChartEngine.YAxis - * @since 5.2.0 Default changed to null. - */ - CIQ.ChartEngine.YAxis.prototype.decimalPlaces = null; - - /** - * Ideal size between y-axis values in pixels. Leave null to automatically calculate. - * See {@tutorial Gridlines and axis labels} for additional details. - * @type number - * @default - * @memberof CIQ.ChartEngine.YAxis - */ - CIQ.ChartEngine.YAxis.prototype.idealTickSizePixels = null; - - /** - * Set to specify that the y-axis vertical grid be drawn with specific intervals between ticks. - * This amount will be overridden if it will result in y axis crowding. - * In which chase, multiples of the original interval will be used. - * For example, if `.25` is selected, and that will cause labels to be on top of or too close to each other, `.50` may be used. - * Crowding is prevented by allowing for a minimum of space equating the y-axis font height between labels. - * - * **This parameter is also used in the 'Trade From Chart' (TFC) module**. If set, it will force the widget to skip certain price values and instead 'snap' to your desired intervals. This will guarantee that an order is only placed at the allowed price intervals for the security in question. - * - * **Note that this parameter will be ignored if {@link CIQ.ChartEngine.YAxis#pretty} is set to `true`. If you require specific price intervals, please set {@link CIQ.ChartEngine.YAxis#pretty} to 'false' before setting `minimumPriceTick`** - * - * Visual Reference:
- * ![yAxis.minimumPriceTick](yAxis.minimumPriceTick.png "yAxis.minimumPriceTick") - * - * @type number - * @default - * @memberof CIQ.ChartEngine.YAxis - * @example - * // Declare a CIQ.ChartEngine object. This is the main object for drawing charts - * var stxx=new CIQ.ChartEngine({container:document.querySelector(".chartContainer"), layout:{"candleWidth": 16, "crosshair":true}}); - * // set interval between ticks - * stxx.chart.yAxis.minimumPriceTick=.50; - */ - CIQ.ChartEngine.YAxis.prototype.minimumPriceTick = null; - - /** - * Set to specify that the y-axis vertical grid be drawn with fractional intervals. - * - * This is checked in {@link CIQ.ChartEngine.AdvancedInjectable#drawYAxis} and if it is not null, - * and there is no existing [yAxis.priceFormatter]{@link CIQ.ChartEngine.YAxis#priceFormatter}, one is created to specially format the y-axis ticks. - * - * {@link CIQ.ChartEngine.YAxis#decimalPlaces} and {@link CIQ.ChartEngine.YAxis#maxDecimalPlaces} will not be honored in this mode. - * - * To disable the formatting you must reset both the yAxis.priceFormatter and this fractional object to 'null'. - *
Example: - * ``` - * stxx.chart.yAxis.priceFormatter=stxx.chart.yAxis.fractional=null; - * ``` - * - * If the outlined logic is not suitable for your needs, you will need to create your own [yAxis.priceFormatter]{@link CIQ.ChartEngine.YAxis#priceFormatter} - * - * @type object - * @default - * @memberof CIQ.ChartEngine.YAxis - * @example Usage example: - * // Declare a CIQ.ChartEngine object. This is the main object for drawing charts - * var stxx=new CIQ.ChartEngine({container:document.querySelector(".chartContainer"), layout:{"candleWidth": 16, "crosshair":true}}); - * // set axis to display in 1/32nds; for example, 100 5/32 will display as 100'05. If there is a price midway between - * // two ticks (for example, 11/64), a plus (+) will follow the price; for example 100 11/64 will display as 100'11+. - * stxx.chart.yAxis.fractional={ - * formatter: "'", // This is the character used to separate he whole number portion from the numerator (' default) - * resolution: 1/32 // Set to smallest increment for the quoted amounts - * } - * - * @example Code used to perform the fractional formatting: - if(!yAxis.fractional.resolution) yAxis.fractional.resolution=yAxis.minimumPrice; - if(!yAxis.fractional.formatter) yAxis.fractional.formatter="'"; - if(!yAxis.priceFormatter) yAxis.priceFormatter=function(stx, panel, price){ - if( !yAxis.fractional ) return; - var sign=''; - if( price < 0 ) { - sign="-"; - price= Math.abs(price); - } - var whole=Math.floor(Math.round(price/yAxis.fractional.resolution)*yAxis.fractional.resolution); - var frac=Math.round((price-whole)/yAxis.fractional.resolution); - var _nds=Math.floor(frac); - return sign+whole+yAxis.fractional.formatter+(_nds<10?"0":"")+_nds+(frac-_nds>=0.5?"+":""); - }; - */ - CIQ.ChartEngine.YAxis.prototype.fractional = null; - - /** - * Set to `true` to draw tick marks and a vertical border line at the edge of the y-axis (use with {@link CIQ.ChartEngine.Chart#yaxisPaddingRight} and {@link CIQ.ChartEngine.Chart#yaxisPaddingLeft}) - * @type boolean - * @default - * @memberof CIQ.ChartEngine.YAxis - */ - CIQ.ChartEngine.YAxis.prototype.displayBorder = true; - - /** - * Set to `false` to hide grid lines. See {@tutorial Gridlines and axis labels} for additional details. - * @type boolean - * @default - * @memberof CIQ.ChartEngine.YAxis - * @example On a specific panel: - * // Be sure to get the panel name directly from the panels object as it may contain ZWNJ characters. - * // See http://documentation.chartiq.com/CIQ.ChartEngine.html#layout%5B%60panels%60%5D - * stxx.layout.panels[panel_name_here].yAxis.displayGridLines=false; - * @example On the primary chart panel: - * stxx.chart.yAxis.displayGridLines=false; - */ - CIQ.ChartEngine.YAxis.prototype.displayGridLines = true; - - /** - * Switch to 'temporarily' hide the y-axis. Set to `true' to activate. - * Will not modify the location of the axis; to do that use {@link CIQ.ChartEngine#setYAxisPosition} instead. - * @type boolean - * @default - * @memberof CIQ.ChartEngine.YAxis - */ - CIQ.ChartEngine.YAxis.prototype.noDraw = null; - - /** - * Set to `false` to hide the current price label in the main panel's y-axis. - * - * Please note that the main panel's current price label will only display if there is a current price available. - * If you have not loaded enough datapoints to overlap into the current time, as determined by the device's clock, the label will not display. - * - * The y-axis floating label colors are based on the difference between the most current close and the **previous** datapoint close, not the difference between the current datapoint's open and its close. - * - * See {@link CIQ.ChartEngine.AdvancedInjectable#drawCurrentHR} - * - * Visual Reference:
- * ![yAxis.drawCurrentPriceLabel](drawCurrentPriceLabel.png "yAxis.drawCurrentPriceLabel") - * @type boolean - * @default - * @memberof CIQ.ChartEngine.YAxis - * @since 04-2015 - */ - CIQ.ChartEngine.YAxis.prototype.drawCurrentPriceLabel = true; - - /** - * Set to `false` to hide the series price labels in the main panel's y-axis. - * - * @type boolean - * @default - * @memberof CIQ.ChartEngine.YAxis - * @since 3.0.0 - */ - CIQ.ChartEngine.YAxis.prototype.drawSeriesPriceLabels = true; - - /** - * Set to false to hide **all** price labels on the particular y axis. - *
See {@link CIQ.ChartEngine.YAxis#drawCurrentPriceLabel} to disable just the current price label on the main chart panel. - *
See CIQ.ChartEngine.preferences.labels to disable just the last value label on studies. - * @type boolean - * @default - * @memberof CIQ.ChartEngine.YAxis - * @since 04-2015 - */ - CIQ.ChartEngine.YAxis.prototype.drawPriceLabels = true; - - /** - * When `true`, will attempt to create grid lines that approximate a `golden ratio` between x and y axis by basing grid on {@link CIQ.ChartEngine.YAxis#idealTickSizePixels}. - * This creates an "airy" modern looking chart. - * If set to false, each axis will be adjusted separately and may create long and narrow rectangular grids depending on date or price range. - * @type boolean - * @default - * @memberof CIQ.ChartEngine.YAxis - * @since - * - 04-2015 - * - 4.0.0 Now defaults to true. - */ - CIQ.ChartEngine.YAxis.prototype.goldenRatioYAxis = true; - - /** - * Shape of the floating y axis label. - * - * Available options: - * - ["roundRectArrow"]{@link CIQ.roundRectArrow} - * - ["semiRoundRect"]{@link CIQ.semiRoundRect} - * - ["roundRect"]{@link CIQ.roundRect} - * - ["tickedRect"]{@link CIQ.tickedRect} - * - ["rect"]{@link CIQ.rect} - * - ["noop"]{@link CIQ.noop} - * - * It will default to {@link CIQ.ChartEngine#yaxisLabelStyle}. - * This could be set independently on each panel if desired. - * @type string - * @default - * @memberof CIQ.ChartEngine.YAxis - * @since 04-2015 - * @example - * var stxx=new CIQ.ChartEngine({container:document.querySelector(".chartContainer"), layout:{"candleWidth": 16, "crosshair":true}}); - * stxx.chart.yAxis.yaxisLabelStyle="rect" - */ - CIQ.ChartEngine.YAxis.prototype.yaxisLabelStyle = null; - - /** - * Set to `true` to right justify the yaxis labels - * Set to `false` to force-left justify the labels, even when the axis is on the left. - * Set to null to have the justification automatically adjusted based on the axis position. Right axis will justify left, and left axis will justify right. - * - * - * This setting does not control the floating last price. See {@link CIQ.ChartEngine.AdvancedInjectable#drawCurrentHR} and {@link CIQ.ChartEngine#createYAxisLabel} - * @type boolean - * @default - * @memberof CIQ.ChartEngine.YAxis - * @since - * - 15-07-01 - * - 6.2.0 Formalized distinction between null and false values. - */ - CIQ.ChartEngine.YAxis.prototype.justifyRight = null; - - /** - * Setting to true causes the y-axis and all linked drawings, series and studies to display inverted (flipped) from its previous state. - * @type boolean - * @default - * @memberof CIQ.ChartEngine.YAxis - * @since 6.3.0 - */ - CIQ.ChartEngine.YAxis.prototype.flipped = false; - - /** - * Set to true to put a rectangle behind the yaxis text (use with {@link CIQ.ChartEngine.Chart#yaxisPaddingRight} and {@link CIQ.ChartEngine.Chart#yaxisPaddingLeft}) - * @type boolean - * @default - * @memberof CIQ.ChartEngine.YAxis - * @since 15-07-01 - */ - CIQ.ChartEngine.YAxis.prototype.textBackground = false; - - /** - * Optional function used to override default formatting of Y-axis values, including the floating HUD value of the crosshair. - * - * Expected format : - * - * function(stx, panel, price, decimalPlaces) - * - * Parameters: - * - * stx - {@link CIQ.ChartEngine} - The chart object - * panel - {@link CIQ.ChartEngine.Panel} - The panel - * price - number - The price to format - * decimalPlaces - number - Optional - Number of decimal places to use - * (may not always be present) - * - * Returns: - * - * text - Formatted text label for the price - * - * @type function - * @example - * stxx.chart.yAxis.priceFormatter=function(stx, panel, price, decimalPlaces){ - * var convertedPrice; - * // add our logic here to convert 'price' to 'convertedPrice' - * return convertedPrice; // string - * } - * @default - * @memberof CIQ.ChartEngine.YAxis - */ - CIQ.ChartEngine.YAxis.prototype.priceFormatter = null; - - /** - * Sets the y-axis bottom on any panel. - * Rendering will start this number of pixels above the panel's bottom. - * Note that {@link CIQ.ChartEngine#adjustPanelPositions} and {@link CIQ.ChartEngine#draw} will need to be called to immediately activate this setting after the axis has already been drawn. - * - * Visual Reference:
- * ![yAxis.width](yAxis.bottomOffset.png "yAxis.bottomOffset") - * ![yAxis.width](yAxis.bottomTopOffset.png "yAxis.bottomTopOffset") - * @type number - * @default - * @memberof CIQ.ChartEngine.YAxis - * @example - * // The list of current panels can be found in "stxx.panels". - * stxx.panels[panelName].yAxis.bottomOffset=20; - * stxx.panels[panelName].yAxis.topOffset=60; - * stxx.adjustPanelPositions(); // !!!! must recalculate the margins after they are changed. !!!! - * stxx.draw(); - */ - CIQ.ChartEngine.YAxis.prototype.bottomOffset = 0; - - /** - * Sets y-axis top on Study panels. - * Rendering will start this number of pixels below the panel's top. - * Note that {@link CIQ.ChartEngine#adjustPanelPositions} and {@link CIQ.ChartEngine#draw} will need to be called to immediately activate this setting after the axis has already been drawn. - * - * Visual Reference:
- * ![yAxis.width](yAxis.bottomTopOffset.png "yAxis.bottomTopOffset") - * @type number - * @default - * @memberof CIQ.ChartEngine.YAxis - * @example - * // The list of current panels can be found in "stxx.panels". - * stxx.panels[panelName].yAxis.bottomOffset=20; - * stxx.panels[panelName].yAxis.topOffset=60; - * stxx.adjustPanelPositions(); // !!!! must recalculate the margins after they are changed. !!!! - * stxx.draw(); - */ - CIQ.ChartEngine.YAxis.prototype.topOffset = 0; - - /** - * Set this to automatically compress and offset the y-axis so that this many pixels of white space are above the display. - * Note that {@link CIQ.ChartEngine#calculateYAxisMargins} and {@link CIQ.ChartEngine#draw} will need to be called to immediately activate this setting after the axis has already been drawn. - * - * Visual Reference:
- * ![yAxis.width](yAxis.initialMarginTop.png "yAxis.initialMarginTop") - * @type number - * @default - * @memberof CIQ.ChartEngine.YAxis - * - * @example - * // Here is an example on how to override the default top and bottom margins before the initial axis has been rendered. - * var stxx=new CIQ.ChartEngine({container:document.querySelector(".chartContainer"), layout:{"candleWidth": 16, "crosshair":true}}); - * stxx.setPeriodicity({period:1, interval:1, timeUnit:"minute"}); // Set your default periodicity to match your data; in this case, one minute. - * stxx.chart.yAxis.initialMarginTop = 50; // Set default margins so they do not bump on to the legend. - * stxx.chart.yAxis.initialMarginBottom = 50; - * stxx.loadChart("SPY", {masterData: yourData}); - * - * @example - * // Here is an example on how to override the default top and bottom margins after the initial axis has already been rendered. - * stxx.loadChart(symbol, {masterData: yourData}, function () { - * var yAxis = stxx.chart.yAxis; - * - * yAxis.initialMarginTop = 50; - * yAxis.initialMarginBottom = 50; - * - * // !! Must recalculate margins after they are changed! - * stxx.calculateYAxisMargins(yAxis); - * stxx.draw(); - * }); - * - * @example - * // Here is an example on how to override the default top and bottom margins for a specific panel after the initial axis has already been rendered. - * // The list of current panels can be found in stxx.panels. - * stxx.panels[panelName].yAxis.initialMarginTop = 100; - * stxx.panels[panelName].yAxis.initialMarginBottom = 100; - * stxx.calculateYAxisMargins(stxx.panels[panelName].yAxis); // !!!! Must recalculate the margins after they are changed. !!!! - * stxx.draw(); - */ - CIQ.ChartEngine.YAxis.prototype.initialMarginTop = 10; - - /** - * Set this to automatically compress and offset the y-axis so that this many pixels of white space are below the display. - * Note that {@link CIQ.ChartEngine#calculateYAxisMargins} and {@link CIQ.ChartEngine#draw} will need to be called to immediately activate this setting after the axis has already been drawn. - * - * Visual Reference:
- * ![yAxis.width](yAxis.initialMarginTop.png "yAxis.initialMarginTop") - * @type number - * @default - * @memberof CIQ.ChartEngine.YAxis - * - * @example - * // Here is an example on how to override the default top and bottom margins before the initial axis has been rendered. - * var stxx=new CIQ.ChartEngine({container:document.querySelector(".chartContainer"), layout:{"candleWidth": 16, "crosshair":true}}); - * stxx.setPeriodicity({period:1, interval:1, timeUnit:"minute"}); // Set your default periodicity to match your data; in this case, one minute. - * stxx.chart.yAxis.initialMarginTop = 50; // Set default margins so they do not bump on to the legend. - * stxx.chart.yAxis.initialMarginBottom = 50; - * stxx.loadChart("SPY", {masterData: yourData}); - * @example - * // Here is an example on how to override the default top and bottom margins after the initial axis has already been rendered. - * stxx.loadChart(symbol, {masterData: yourData}, function() { - * // Callback -- your code to be executed after the chart is loaded. - * stxx.chart.yAxis.initialMarginTop = 50; - * stxx.chart.yAxis.initialMarginBottom = 50; - * stxx.calculateYAxisMargins(stxx.chart.panel.yAxis); // !!!! Must recalculate the margins after they are changed. !!!! - * stxx.draw(); - * }); - */ - CIQ.ChartEngine.YAxis.prototype.initialMarginBottom = 10; - - /** - * Sets the vertical zoom level for the y axis and all its associated series. - * - * It can be set programmatically or by the user as they grab the y axis and move it up or down. - * - * The value represents the number of pixels to zoomed in or out, and can be positive or negative. - * The larger the number, the more it zooms out to show a wider price range. - * - * Please note that the zoom level will be reset as determined by {@link CIQ.ChartEngine.YAxis#initialMarginTop} and - * {@link CIQ.ChartEngine.YAxis#initialMarginBottom} when a {@link CIQ.ChartEngine#loadChart} is rendered, the {@link CIQ.ChartEngine#home} button is pressed, or when {@link CIQ.ChartEngine.AdvancedInjectable#touchDoubleClick} is activated on a touch device. - * - * @type number - * @default - * @example - * // programmatically change the vertical zoom level for the primary chart yAxis - * stxx.chart.yAxis.zoom=100;stxx.draw(); - * @memberof CIQ.ChartEngine.YAxis - */ - CIQ.ChartEngine.YAxis.prototype.zoom = 0; - - /** - * set this to the number of pixels to offset the y-axis, positive or negative. - * @type number - * @default - * @memberof CIQ.ChartEngine.YAxis - */ - CIQ.ChartEngine.YAxis.prototype.scroll = 0; - - /** - * Set this to a factor to scale the y axis. - * - * The zoom value will be internality adjusted based on the value of this property as follows: - * ``` - * zoom = (1-heightFactor)*height + initial margin settings - * ``` - * For example, use this to easily reduce the scale of the axis by 20%, set heightFactor=0.8. - * - * @type number - * @default - * @memberof CIQ.ChartEngine.YAxis - * @since 7.0.0 - */ - CIQ.ChartEngine.YAxis.prototype.heightFactor = 1; - - // get/set width to allow {@link CIQ.ChartEngine.Chart#dynamicYAxis} feature - // to set _dynamicWidth instead of _width. This allows user widths to be - // restored easily when the feature is not needed. - Object.defineProperty(CIQ.ChartEngine.YAxis.prototype, "width", { - configurable: true, - enumerable: true, - get: function () { - // _dynamicWidth is set by {@link CIQ.ChartEngine#drawYAxis} and - // cleared by {@link CIQ.ChartEngine.Chart#resetDynamicYAxis} - return this._dynamicWidth || this._width; - }, - set: function (value) { - this._width = value; - // the calculated width is less than user value, getter should return the user value - if (this._dynamicWidth < value) this._dynamicWidth = NaN; - } - }); - - /** - * The y-axis width in pixels. - * - * ![yAxis.width](yAxis.width.png "yAxis.width") - * - * @type number - * @default - * @memberof CIQ.ChartEngine.YAxis - * - * @see {@link CIQ.ChartEngine.Chart#dynamicYAxis} to set the y-axis width dynamically. - * @see {@link CIQ.ChartEngine.Chart#yaxisPaddingRight} and - * {@link CIQ.ChartEngine.Chart#yaxisPaddingLeft} for information on how to overlay the y-axis onto - * the chart. - * - * @example Set the y-axis width. - * stxx.chart.yAxis.width = stxx.chart.yAxis.smallScreenWidth; - * // Must call the following two lines to activate the update if the axis is already drawn. - * stxx.calculateYAxisPositions(); - * stxx.draw(); - * - * @example Reset the y-axis width to the default. - * stxx.chart.yAxis.width = CIQ.ChartEngine.YAxis.prototype.width; - * stxx.calculateYAxisPositions(); - * stxx.draw(); - */ - CIQ.ChartEngine.YAxis.prototype.width = 60; - - /** - * The y-axis width in pixels if the screen is small (typically, smaller than the break-sm - * breakpoint). See the {@link CIQ.ChartEngine.Chart#breakpoint} property and - * {@link CIQ.UI.Chart#getBreakpoint} method for more information on breakpoints. - * - * @type number - * @default - * @memberof CIQ.ChartEngine.YAxis - * @since 8.2.0 - */ - CIQ.ChartEngine.YAxis.prototype.smallScreenWidth = 50; - - /** - * Override the default stx_yaxis style for text by setting this to the desired CSS style. This would typically be used to set a secondary axis to a particular color. - * @type string - * @default - * @memberof CIQ.ChartEngine.YAxis - * @since 15-07-01 - */ - CIQ.ChartEngine.YAxis.prototype.textStyle = null; - - /** - * Set to "left" or "right" to **initialize** the y-axis location. - * - * By default y-axis are drawn on the right side of the chart. - * The main y-axis for any study panel will follow the main chart axis as long as this is set to null. - * - * Do not use this method to change the location of an existing y-axis. - * Once initialized, y axis location can be changed at any time by calling {@link CIQ.ChartEngine#setYAxisPosition} - * - * @type string - * @default - * @memberof CIQ.ChartEngine.YAxis - * @example Pre-set the main y-axis for the chart on the left; **before it is initially rendered**. - * stxx.chart.yAxis.position = 'left'; - * @example Re-set the main y-axis for the chart on the right; **after it is initially rendered**. - * stxx.setYAxisPosition(stxx.chart.yAxis,'right'); - * @since 15-07-01 - */ - CIQ.ChartEngine.YAxis.prototype.position = null; - - /** - * If true then uses the "pretty" algorithm instead of the "best fit" algorithm. The pretty algorithm - * uses the values specified in {@link CIQ.ChartEngine.YAxis#increments} to set axis label locations. - * - * **Note that this algorithm will override the {@link CIQ.ChartEngine.YAxis#minimumPriceTick}. If you require specific price intervals, please set this parameter to 'false' before setting `minimumPriceTick`** - * - * @memberof CIQ.ChartEngine.YAxis - * @since 2015-11-1 - * @type boolean - * @default - */ - CIQ.ChartEngine.YAxis.prototype.pretty = true; - - /** - * Values used by the {@link CIQ.ChartEngine.YAxis#pretty} algorithm to set axis label locations. - * @memberof CIQ.ChartEngine.YAxis - * @since 2015-11-1 - * @type array - * @default - */ - CIQ.ChartEngine.YAxis.prototype.increments = [1, 2.5, 5]; - - /** - * If true then uses an additional step in the "pretty" algorithm for the log - * scale. This allows the algorithm to lower the grid to fill large visual gaps. - * The "increments" are not fully respected by this approach. - * - * Only applicable when using *both* pretty mode and semiLog. - * @memberof CIQ.ChartEngine.YAxis - * @since 2016-03-11 - * @type boolean - * @default - */ - CIQ.ChartEngine.YAxis.prototype.prettySemiLog = true; - - /** - * A matrix used to determine how many decimal places to print on y axis labels based on the size of the shadow (the difference between chart high and chart low). - * The array consists of tuples in descending order. If the shadow is less than n1 then n2 decimal places will be printed. - * See {@link CIQ.ChartEngine.YAxis.defaultShadowBreaks} and {@link CIQ.ChartEngine.YAxis.smallChartShadowBreaks} for default settings. - * - * This can be overridden, however, by setting{@link CIQ.ChartEngine.YAxis#decimalPlaces}. - * If you wish to further configure the current price label floating over the y axis to display less decimal places than the axis labels, set {@link CIQ.ChartEngine.YAxis#maxDecimalPlaces}. - * Also see {@link CIQ.ChartEngine.Chart#dynamicYAxis} to allow the y axis to automatically determine its width based on the text length of quotes in a dataSet. - * - * @type array - * @memberof CIQ.ChartEngine.YAxis - * @since 2015-11-1 - * @example - * stxx.chart.yAxis.shadowBreaks=CIQ.ChartEngine.YAxis.defaultShadowBreaks; - * @example - * stxx.chart.yAxis.shadowBreaks=CIQ.ChartEngine.YAxis.smallChartShadowBreaks; - */ - CIQ.ChartEngine.YAxis.prototype.shadowBreaks = - CIQ.ChartEngine.YAxis.defaultShadowBreaks; - - /** - * Necessary for abstract calling - * @param {CIQ.ChartEngine} stx A chart engine instance - * @memberof CIQ.ChartEngine.YAxis - * @since 7.1.0 - * @private - */ - CIQ.ChartEngine.YAxis.prototype.getYAxis = function (stx) { - return this; - }; - - /** - * Convenience function for checking whether multiple plots share this axis. - * - * @param {CIQ.ChartEngine} stx A chart engine instance. - * @param {boolean} includeDependents Set to true to count dependent renderers among the plots sharing the axis. - * @memberof CIQ.ChartEngine.YAxis - * @since - * - 7.2.0 - * - 7.3.0 Added `stx` and `includeDependents` parameters. - */ - CIQ.ChartEngine.YAxis.prototype.isShared = function (stx, includeDependents) { - var studyLength = this.studies.length, - rendererLength = this.renderers.length; - if (studyLength > 1) return true; // more than 1 study, obviously shared - if (rendererLength && studyLength) return true; // 1 study and at least 1 renderer, obviously shared - if (!rendererLength) return false; // only 1 study, obviously not shared - // at this point we have only renderers - if (rendererLength > 1 && includeDependents) return true; // more than 1 renderer total, shared - for (var r = rendererLength - 1; r >= 0; r--) { - // count independent renderers - if (stx.chart.seriesRenderers[this.renderers[r]].params.dependentOf) - rendererLength--; - } - return rendererLength > 1; - }; - - /** - * Sets the background of the axis when hovering over it to indicate more action are available, such as zooming and dragging. - * - * To disable color change on hover, set to a stub function: - * ``` - * CIQ.ChartEngine.YAxis.prototype.setBackground=function(stx, params){}; - * ``` - * - * @param {CIQ.ChartEngine} stx A chart engine instance - * @param {object} [params] - * @param {string} [params.color] background color - * @param {number} [params.opacity] opacity of background color - * @memberof CIQ.ChartEngine.YAxis - * @since 7.1.0 - */ - CIQ.ChartEngine.YAxis.prototype.setBackground = function (stx, params) { - if (!params) params = {}; - if (!params.color) params.color = "auto"; - var points = [ - [this.left, this.top], - [this.left, this.bottom], - [this.left + this.width, this.bottom], - [this.left + this.width, this.top] - ]; - CIQ.fillArea(stx, points, { color: params.color, opacity: params.opacity }); - }; - - /** - * Sets the y-axis width based on the `breakpoint` parameter. - * - * @param {string} breakpoint The responsive design breakpoint that determines the y-axis width. - * See the {@link CIQ.UI.Chart#getBreakpoint} method for valid values. - * - * @memberof CIQ.ChartEngine.YAxis - * @since 8.2.0 - */ - CIQ.ChartEngine.YAxis.prototype.setBreakpointWidth = function (breakpoint) { - if (!breakpoint) return; - const { width, smallScreenWidth } = CIQ.ChartEngine.YAxis.prototype; - const smallScreen = breakpoint === "break-sm"; - this.width = smallScreen ? smallScreenWidth : width; - }; - - /** - * Returns the minimum spacing required between the latest tick on the chart and the price label to prevent data form colliding with the label, - * which depending on style, may protrude into the chart area ( ie. roundRectArrow ). - * - * See {@link CIQ.ChartEngine#yaxisLabelStyle} to set different label styles - * @param {CIQ.ChartEngine.Chart} chart The specific chart - * @param {string} chartType The chart rendering type (candle, line, etc) - * @returns {number} pixels to offset - * @memberof CIQ.ChartEngine - * @since - * - 4.0.0 - * - 5.1.0 Removed `stx` parameter. - */ - CIQ.ChartEngine.prototype.getLabelOffsetInPixels = function (chart, chartType) { - var isLineType = - !this.mainSeriesRenderer || !this.mainSeriesRenderer.standaloneBars; - if ( - this.yaxisLabelStyle == "roundRectArrow" && - !(isLineType && this.extendLastTick && chart.yaxisPaddingRight !== 0) - ) { - // Special case when we have a pointy arrow we want the current tick to be right - // at the arrow point, not buried underneath it - // unless the developer set the flags to extend the line/mountain to the very edge of the chart. - // or unless the y-axis is overlaying the chart - var margin = 3; // should be the same from createYAxisLabel - var height = this.getCanvasFontSize("stx_yaxis") + margin * 2; - return height * 0.66; - } - return 0; - }; - - /** - * Causes the primary y-axis and all linked drawings, series and studies to display inverted (flipped) from its previous state. - * - * Calling this method multiple times will cause a reciprocal effect. - * So calling it on a upside-down chart will cause it to display normally and calling it on a normal chart will cause it to display upside-down. - * - * Sets CIQ.ChartEngine.layout.flipped and {@link CIQ.ChartEngine.YAxis#flipped} for the main chart. - * - * To manage this functionality on secondary axis directly configure its {@link CIQ.ChartEngine.YAxis#flipped} property. - * @param {boolean} flip True to flip chart, false to restore it - * @memberof CIQ.ChartEngine - * @since 6.3.0 - */ - CIQ.ChartEngine.prototype.flipChart = function (flip) { - if (this.layout.flipped == flip) return; - this.layout.flipped = flip; - this.chart.yAxis.flipped = flip; - this.changeOccurred("layout"); - this.draw(); - }; - - /** - * Calculates and sets the value of zoom and scroll for y-axis based on yAxis.initialMarginTop and yAxis.initialMarginBottom. - * This method will automatically translate those into starting scroll and zoom factors. - * If the combined initial values are greater than the y-axis height, then both zoom and scroll will be reset to 0; - * @param {CIQ.ChartEngine.YAxis} yAxis The yAxis to reset - * @memberof CIQ.ChartEngine - * @since 7.0.0 Takes into account new field `yAxis.heightFactor`. - */ - CIQ.ChartEngine.prototype.calculateYAxisMargins = function (yAxis) { - if (yAxis.heightFactor) yAxis.zoom = yAxis.height * (1 - yAxis.heightFactor); - yAxis.zoom += yAxis.initialMarginTop + yAxis.initialMarginBottom; - yAxis.scroll = (yAxis.initialMarginTop - yAxis.initialMarginBottom) / 2; - if (yAxis.zoom > yAxis.height) { - yAxis.zoom = 0; // If the zoom is greater than the height then we'll have an upside down y-axis - yAxis.scroll = 0; - } - }; - - /** - * INJECTABLE - * - * Resets the y-axis width to the default, {@link CIQ.ChartEngine.YAxis#width}. - * - * Called internally whenever the y-axis label width might change. This function can also be - * called programmatically at any time if the default behavior needs to be altered. - * - * @param {object} [params] Function parameters. - * @param {boolean} [params.noRecalculate=false] When true, - * {@link CIQ.ChartEngine#calculateYAxisPositions} will never be called. - * @param {string} [params.chartName] Identifies the chart for which the y-axis dynamic width is - * reset. - * - * @memberof CIQ.ChartEngine.AdvancedInjectable# - * @alias resetDynamicYAxis - * @see {@link CIQ.ChartEngine.Chart#dynamicYAxis}, the flag that enables this feature. - * @since 6.0.0 - */ - CIQ.ChartEngine.prototype.resetDynamicYAxis = function (params) { - if (this.runPrepend("resetDynamicYAxis", arguments)) return; - - var resetting = false; - - for (var panelName in this.panels) { - var panel = this.panels[panelName]; - - if (params && params.chartName && panel.chart.name !== params.chartName) - continue; - if (!panel.yaxisLHS || !panel.yaxisRHS) continue; - - var yaxis = panel.yaxisLHS.concat(panel.yaxisRHS); - - for (var i = 0; i < yaxis.length; i++) { - if (yaxis[i]._dynamicWidth) { - // NaN is falsy, see the {@link CIQ.ChartEngine.YAxis#width} getter for context - yaxis[i]._dynamicWidth = NaN; - resetting = true; - } - } - } - - if (resetting && (!params || !params.noRecalculate)) { - this.calculateYAxisPositions(); - } - - this.runAppend("resetDynamicYAxis", arguments); - }; - - /** - * Sets the breakpoint on the chart engine. Resets any dynamic y-axis expansion (see - * {@link CIQ.ChartEngine.Chart#dynamicYAxis}) and returns the y-axis width to - * {@link CIQ.ChartEngine.YAxis#width} or {@link CIQ.ChartEngine.YAxis#smallScreenWidth}, - * depending on the breakpoint. Also clears all canvas styles so any CSS-derived values that are - * cached for performance are recalculated. - * - * @param {string} [breakpoint] The breakpoint to set; must be "break-sm", "break-md", or - * "break-lg". - * - * @memberof CIQ.ChartEngine - * @since 8.2.0 - */ - CIQ.ChartEngine.prototype.notifyBreakpoint = function (breakpoint) { - if (this.chart.breakpoint === breakpoint) return; - if (!["break-lg", "break-md", "break-sm"].includes(breakpoint)) return; - const { chart } = this; - const { dynamicYAxis } = chart; - this.clearStyles(); - chart.breakpoint = breakpoint; - - for (let p in this.panels) { - const panel = this.panels[p]; - const allYAxes = panel.yaxisRHS.concat(panel.yaxisLHS); - for (let a = 0; a < allYAxes.length; a++) { - const yAxis = allYAxes[a]; - yAxis.setBreakpointWidth(breakpoint); - } - } - - if (dynamicYAxis) { - this.resetDynamicYAxis({ chartName: chart.name }); - } - }; - - /** - * Change the yAxis.top and yAxis.bottom to create drawing space - * for the xAxis. - * - * @param {CIQ.ChartEngine.Panel} panel Panel to adjust, used to check location - * @param {CIQ.ChartEngine.YAxis} yAxis yAxis to adjust - * @private - */ - CIQ.ChartEngine.prototype.adjustYAxisHeightOffset = function (panel, yAxis) { - var topOffset = yAxis.topOffset, - bottomOffset = yAxis.bottomOffset; - //If the sum of bottomOffset and topOffset is larger than the panel height reset them - if (topOffset + bottomOffset > panel.height) { - console.log( - "The sum of yAxis.topOffset and yAxis.bottomOffset cannot be greater than the panel height. Both values will be reset to 0." - ); - yAxis.bottomOffset = 0; - yAxis.topOffset = 0; - } - - if (!this.xaxisHeight && this.xaxisHeight !== 0) { - this.xaxisHeight = this.getCanvasFontSize("stx_xaxis") + 4; - if (this.chart.xAxis.displayBorder || this.axisBorders) - this.xaxisHeight += 3; - } - var panelHasTheAxis = - (this.xAxisAsFooter && - panel.bottom > this.chart.canvasHeight - this.xaxisHeight) || - (!this.xAxisAsFooter && panel == this.chart.panel); - if (panelHasTheAxis) bottomOffset += this.xaxisHeight; - - yAxis.top = panel.top + topOffset; - yAxis.bottom = panel.bottom - bottomOffset; - }; - - /** - * INJECTABLE - * Animation Loop - * - * Draws the grid for the y-axis. - * @param {CIQ.ChartEngine.Panel} panel The panel for the y-axis - * @memberof CIQ.ChartEngine.AdvancedInjectable# - * @alias plotYAxisGrid - */ - CIQ.ChartEngine.prototype.plotYAxisGrid = function (panel) { - if (this.runPrepend("plotYAxisGrid", arguments)) return; - var context = this.getBackgroundCanvas().context, - yAxis = panel.yAxis; - if (yAxis.yAxisPlotter) { - yAxis.yAxisPlotter.draw(context, "grid"); - } - this.runAppend("plotYAxisGrid", arguments); - }; - - /** - * INJECTABLE - * Animation Loop - * - * Plots the text on the y-axis. - * @param {CIQ.ChartEngine.Panel} panel The panel for the y-axis - * @memberof CIQ.ChartEngine.AdvancedInjectable# - * @alias plotYAxisText - */ - CIQ.ChartEngine.prototype.plotYAxisText = function (panel) { - if (this.runPrepend("plotYAxisText", arguments)) return; - var context = this.getBackgroundCanvas().context; - this.canvasFont("stx_yaxis", context); - this.canvasColor("stx_yaxis", context); - context.textBaseline = "middle"; - function drawText(yAxis) { - if (!yAxis.yAxisPlotter) return; - if (yAxis.noDraw || !yAxis.width) return; - if (yAxis.justifyRight) context.textAlign = "right"; - else if (yAxis.justifyRight === false) context.textAlign = "left"; - yAxis.yAxisPlotter.draw(context, "text"); - } - var arr = panel.yaxisLHS, - i; - for (i = 0; i < arr.length; i++) { - context.textAlign = "right"; - drawText(arr[i]); - } - arr = panel.yaxisRHS; - for (i = 0; i < arr.length; i++) { - context.textAlign = "left"; - drawText(arr[i]); - } - context.textAlign = "left"; - context.textBaseline = "alphabetic"; - - this.runAppend("plotYAxisText", arguments); - }; - - /** - * Returns the appropriate number of decimal points to show for a given priceTick (price differential between two ticks) - * @param {number} priceTick The price differential between two ticks - * @return {number} The number of decimal places appropriate to show - * @memberof CIQ.ChartEngine - * @since 5.2.0 - */ - CIQ.ChartEngine.prototype.decimalPlacesFromPriceTick = function (priceTick) { - if (priceTick < 0.0001) return 8; - if (priceTick < 0.01) return 4; - if (priceTick < 0.1) return 2; - if (priceTick < 1) return 1; - return 0; - }; - - /** - * Formats prices for the Y-axis. - * - * Intelligently computes the decimal places based on the size of the y-axis ticks. - * - * If the panel is a study panel, then prices will be condensed by {@link CIQ.condenseInt} if the price differential between two ticks (priceTick) is equal or over 1000.
- * For the primary panel prices will be condensed if the price differential between two ticks is equal or over 20000.
- * This can be overridden by manually setting {@link CIQ.ChartEngine.YAxis#decimalPlaces}. - * - * You can call this method to ensure that any prices that you are using outside of the chart are formatted the same as the prices on the y-axis. - * @param {number} price The price to be formatted - * @param {CIQ.ChartEngine.Panel} panel The panel for the y-axis. - * @param {number} [requestedDecimalPlaces] Number of decimal places, otherwise it will be determined by the yaxis setting, or if not set, determined automatically - * @param {CIQ.ChartEngine.YAxis} [yAxis] yAxis. If not present, the panel's y-axis will be used. - * @param {boolean} [internationalize] Normally this function will return an internationalized result. Set this param to false to bypass. - * @return {number} The formatted price - * @memberof CIQ.ChartEngine - * @since - * - 4.0.0 CondenseInt will be called only if yaxis priceTick equal or over 1000 for studies and 20000 for primary axis, rather than 100. - * - 5.2.0 All axes will be condensed to some degree to allow for more uniform decimal precision. - * - 6.1.0 Added `internationalize` parameter. - */ - CIQ.ChartEngine.prototype.formatYAxisPrice = function ( - price, - panel, - requestedDecimalPlaces, - yAxis, - internationalize - ) { - if (price === null || typeof price == "undefined" || isNaN(price)) return ""; - if (!panel) panel = this.chart.panel; - var yax = yAxis ? yAxis : panel.yAxis; - var decimalPlaces = requestedDecimalPlaces; - if (!decimalPlaces && decimalPlaces !== 0) - decimalPlaces = yax.printDecimalPlaces; - if (!decimalPlaces && decimalPlaces !== 0) { - decimalPlaces = this.decimalPlacesFromPriceTick(yax.priceTick); - } - var minCondense = yax == panel.chart.yAxis ? 20000 : 1000; - if (yax.priceTick >= minCondense) { - price = price.toFixed(decimalPlaces); // k or m for thousands or millions - return CIQ.condenseInt(price); - } - - var internationalizer = this.internationalizer; - if (internationalizer && internationalize !== false) { - var l = internationalizer.priceFormatters.length; - if (decimalPlaces >= l) decimalPlaces = l - 1; - price = internationalizer.priceFormatters[decimalPlaces].format(price); - } else { - price = price.toFixed(decimalPlaces); - // the above may be a problem at some point for datasets with very small shadows because the rounding skews the real number. - // We should truncate the decimal places instead of rounding to preserve the accuracy, - // but for now the above seems to work fine so we will leave it alone. - // And also the amount of rounding being done here actually "corrects" some of differences introduced elsewhere in the yAxis price calculations. ugg! - // Use the flowing code when ready to show truncated vs. rounded values - //price = price.toString(); - //if(price.indexOf(".") > 0){ - // price = price.slice(0, (price.indexOf("."))+decimalPlaces+1) - //}; - } - return price; - }; - - /** - * Calculates the range for the y-axis and sets appropriate member variables. - * - * The default behavior is to stop vertical scrolling when only 1/5 of the chart remains on - * screen, so the primary chart never completely scrolls off the screen — unless you start - * zooming the y-axis by grabbing it and pulling it down. Once the zoom level goes into the - * negative range (meaning that you are shrinking the chart vertically) the vertical panning - * limitation goes away. - * - * This method should seldom if ever be called directly. But you can override this behavior (so - * that a chart is always allowed to completely scroll off the screen at any zoom level) with - * the following code: - * ``` - * stxx.originalcalculateYAxisRange = stxx.calculateYAxisRange; - * CIQ.ChartEngine.prototype.calculateYAxisRange = function(panel, yAxis, low, high) { - * var beforeScroll = this.chart.yAxis.scroll; - * this.originalcalculateYAxisRange(panel, yAxis, low, high); - * this.chart.yAxis.scroll = beforeScroll; - * }; - * ``` - * - * @param {CIQ.ChartEngine.Panel} panel The panel containing the y-axis. - * @param {CIQ.ChartEngine.YAxis} yAxis The y-axis for which the range is calculated. - * @param {number} [low] The low value for the axis. - * @param {number} [high] The high value for the axis. - * - * @memberof CIQ.ChartEngine - * @since 5.2.0 When the y-axis is zoomed in, there is no limitation on vertical panning. - */ - CIQ.ChartEngine.prototype.calculateYAxisRange = function ( - panel, - yAxis, - low, - high - ) { - if (low == Number.MAX_VALUE) { - low = 0; - high = 0; - } - var cheight = panel.height, - newHigh = null, - newLow = null; - this.adjustYAxisHeightOffset(panel, yAxis); - yAxis.height = yAxis.bottom - yAxis.top; - // Ensure the user hasn't scrolled off the top or the bottom of the chart when the chart is not zoomed in - var verticalPad = Math.round(Math.abs(cheight / 5)); - if (yAxis.zoom >= 0 && cheight - Math.abs(yAxis.scroll) < verticalPad) { - yAxis.scroll = (cheight - verticalPad) * (yAxis.scroll < 0 ? -1 : 1); - } - - var isChartMainAxis = - panel.chart.name === panel.name && panel.yAxis.name === yAxis.name; - var isLogScale = - low > 0 && - (this.layout.semiLog || this.layout.chartScale == "log") && - !panel.chart.isComparison && - this.layout.aggregationType != "pandf"; - - if (low || low === 0) { - if (high - low === 0) { - // A stock that has no movement, so we create some padding so that a straight line will appear - var padding = Math.pow(10, -(low.toString() + ".").split(".")[1].length); - if (padding == 1) padding = 100; // For whole number prices, widen the shadow - newHigh = low + padding; - newLow = low - padding; - } else { - if (isChartMainAxis && isLogScale && (high || high === 0)) { - // When in log scale, the yAxis high and low will be the log10 of the prices. The actual values are just for display, not for calculation. - var logLow = Math.log(low) / Math.LN10; - var logHigh = Math.log(high) / Math.LN10; - newHigh = Math.pow(10, logHigh); - newLow = Math.pow(10, logLow); - } else { - newHigh = high; - newLow = low; - } - } - yAxis.high = newHigh; - yAxis.low = newLow; - } - if (yAxis.max || yAxis.max === 0) yAxis.high = yAxis.max; - if (yAxis.min || yAxis.min === 0) yAxis.low = yAxis.min; - yAxis.shadow = yAxis.high - yAxis.low; - if (isChartMainAxis) { - // For the main yaxis on the main chart only check for semilog and flipped - if (yAxis.semiLog != isLogScale) { - this.clearPixelCache(); - yAxis.semiLog = isLogScale; - } - yAxis.flipped = this.layout.flipped; - } - }; - - /** - * INJECTABLE - * Animation Loop - * - * This method creates and draws all y-axes for all panels - * - * yAxis.high - The highest value on the y-axis - * yAxis.low - The lowest value on the y-axis - * - * @param {CIQ.ChartEngine.Chart} chart The chart to create y-axis - * @memberof CIQ.ChartEngine.AdvancedInjectable# - * @alias renderYAxis - * @since 15-07-01 - */ - CIQ.ChartEngine.prototype.renderYAxis = function (chart) { - if (this.runPrepend("renderYAxis", arguments)) return; - - if (this.checkLogScale()) throw new Error("reboot draw"); - this.rendererAction(chart, "yAxis"); - const { context } = this.getBackgroundCanvas(chart); - - for (var p in this.panels) { - var panel = this.panels[p]; - if (panel.chart != chart) continue; - - var arr = panel.yaxisRHS.concat(panel.yaxisLHS); - - // Iterate through all the yaxis for the panel and set all the necessary calculations - // For the primary yaxis (panel.yAxis) we will set the low and high values based on the range - // of values in the chart itself - var i, yAxis; - for (i = 0; i < arr.length; i++) { - yAxis = arr[i]; - this.calculateYAxisRange(panel, yAxis, yAxis.lowValue, yAxis.highValue); - var parameters = CIQ.getFn("Studies.getYAxisParameters", {})(this, yAxis); - parameters.yAxis = yAxis; - this.createYAxis(panel, parameters); - this.drawYAxis(panel, parameters); - CIQ.getFn("Studies.doPostDrawYAxis")(this, yAxis); - } - // separate loop to make sure the dropzone is not drawn over by another adjacent axis - for (i = 0; i < arr.length; i++) { - yAxis = arr[i]; - if (yAxis.dropzone) { - var style = this.canvasStyle("stx-subholder dropzone left"); - if (style) { - context.strokeStyle = style.borderLeftColor; - context.lineWidth = parseFloat(style.borderLeftWidth); - context.beginPath(); - if (yAxis.dropzone == "all") - context.strokeRect( - yAxis.left, - yAxis.top, - yAxis.width, - yAxis.height - ); - else { - var xcoord = - yAxis.left + (yAxis.dropzone == "left" ? 0 : yAxis.width); - context.moveTo(xcoord, yAxis.top); - context.lineTo(xcoord, yAxis.top + yAxis.height); - context.stroke(); - } - } - } - } - if (this.displayDragOK) this.displayDragOK(true); - } - this.runAppend("renderYAxis", arguments); - }; - - /** - * Redraws the floating price label(s) for the crosshairs tool on the y axis using {@link CIQ.ChartEngine#createYAxisLabel} and sets the width of the y crosshair line to match panel width. - * - * Label style: `stx-float-price` ( for price colors ) and `stx_crosshair_y` ( for cross hair line ) - * - * @param {CIQ.ChartEngine.Panel} panel The panel on which to print the label(s) - * @memberof CIQ.ChartEngine - * @example - * // controls primary default color scheme - * .stx-float-price { color:#fff; background-color: yellow;} - * @since 5.2.0 Number of decimal places for label determined by price differential between ticks as opposed to shadow. - */ - - CIQ.ChartEngine.prototype.updateFloatHRLabel = function (panel) { - if (!this.floatCanvas) return; - var arr = panel.yaxisLHS.concat(panel.yaxisRHS); - var cy = this.crossYActualPos ? this.crossYActualPos : this.cy; - if (this.floatCanvas.isDirty) CIQ.clearCanvas(this.floatCanvas, this); - if (this.controls.crossX && this.controls.crossX.style.display == "none") - return; - if (this.controls.crossY) { - var crosshairWidth = panel.width; - if (this.yaxisLabelStyle == "roundRectArrow") crosshairWidth -= 7; - this.controls.crossY.style.left = panel.left + "px"; - this.controls.crossY.style.width = crosshairWidth + "px"; - } - for (var i = 0; i < arr.length; i++) { - var yAxis = arr[i]; - var price = this.transformedPriceFromPixel(cy, panel, yAxis); - if (isNaN(price)) continue; - if ((yAxis.min || yAxis.min === 0) && price < yAxis.min) continue; - if ((yAxis.max || yAxis.max === 0) && price > yAxis.max) continue; - var labelDecimalPlaces = null; - if (yAxis !== panel.chart.yAxis) { - // If a study panel, this logic allows the cursor to print more decimal places than the yaxis default for panels - labelDecimalPlaces = this.decimalPlacesFromPriceTick(yAxis.priceTick); - if (yAxis.decimalPlaces || yAxis.decimalPlaces === 0) - labelDecimalPlaces = yAxis.decimalPlaces; - } - if (yAxis.priceFormatter) { - price = yAxis.priceFormatter(this, panel, price, labelDecimalPlaces); - } else { - price = this.formatYAxisPrice(price, panel, labelDecimalPlaces, yAxis); - } - - var style = this.canvasStyle("stx-float-price"); - this.createYAxisLabel( - panel, - price, - cy, - style.backgroundColor, - style.color, - this.floatCanvas.context, - yAxis - ); - this.floatCanvas.isDirty = true; - } - }; - - /** - * Returns the yaxis that the crosshairs (mouse) is on top of - * @param {CIQ.ChartEngine.Panel} panel The panel - * @param {number} [x] The X location. Defaults to CIQ.ChartEngine#cx - * @param {number} [y] The Y location. Defaults to CIQ.ChartEngine#cy - * @return {CIQ.ChartEngine.YAxis} The yAxis that the crosshair is over - * @memberOf CIQ.ChartEngine - * @since - * - 15-07-01 - * - 6.1.0 Returns null when no yAxis found. - * - 7.1.0 Added the `y` parameter. - */ - CIQ.ChartEngine.prototype.whichYAxis = function (panel, x, y) { - if (typeof x === "undefined") x = this.cx; - if (typeof y === "undefined") y = this.cy; - var myPanel = this.whichPanel(y); - if (panel && panel == myPanel) { - var arr = panel.yaxisLHS.concat(panel.yaxisRHS); - for (var i = 0; i < arr.length; i++) { - var yAxis = arr[i]; - if (yAxis.left <= x && yAxis.left + yAxis.width >= x) return yAxis; - } - } - return null; - }; - - /** - * Determines whether the yAxis of the object matches the provided yAxis - * @param {CIQ.Studies.StudyDescriptor|CIQ.Renderer|CIQ.ChartEngine.YAxis} object Can be a study, series, or yaxis - * @param {CIQ.ChartEngine.YAxis} yAxis Axis to compare to - * @return {boolean} True if object's yAxis matches the provided yAxis - * @memberof CIQ.ChartEngine - * @since 7.1.0 - */ - CIQ.ChartEngine.prototype.yaxisMatches = function (object, yAxis) { - if ( - !object || - !object.getYAxis || - !yAxis || - !(yAxis instanceof CIQ.ChartEngine.YAxis) - ) - return false; - return object.getYAxis(this).name == yAxis.name; - }; - - /** - * Creates a floating label on the y-axis unless {@link CIQ.ChartEngine.YAxis#drawPriceLabels} is false. - * This can be used for any panel and called multiple times to add multiple labels - * - * Style: stx_yaxis ( font only ) - * - * @param {CIQ.ChartEngine.Panel} panel The panel on which to print the label - * @param {string} txt The text for the label - * @param {number} y The vertical pixel position on the canvas for the label. This method will ensure that it remains on the requested panel. To get the pixel for a value use {@link CIQ.ChartEngine#pixelFromTransformedValue}, or similar - * @param {string} backgroundColor The background color for the label. - * @param {string} color The text color for the label. If none provided then white is used, unless the background is white in which case black is used. - * @param {external:CanvasRenderingContext2D} [ctx] The canvas context to use, defaults to the chart - * @param {CIQ.ChartEngine.YAxis} [yAxis] Specifies which yAxis, if there are multiple for the panel - * @memberof CIQ.ChartEngine - * @since 3.0.0 Moved text rendering to {@link CIQ.createLabel}. - * @example - * stxx.createYAxisLabel(panel, '379600',stxx.pixelFromTransformedValue(price, panel), 'green', 'white'); - */ - CIQ.ChartEngine.prototype.createYAxisLabel = function ( - panel, - txt, - y, - backgroundColor, - color, - ctx, - yAxis - ) { - if (panel.yAxis.drawPriceLabels === false || panel.yAxis.noDraw) return; - var yax = yAxis ? yAxis : panel.yAxis; - if (yax.noDraw || !yax.width) return; - var context = ctx ? ctx : this.chart.context; - var margin = 3; - var height = this.getCanvasFontSize("stx_yaxis") + margin * 2; - this.canvasFont("stx_yaxis", context); - var drawBorders = yax.displayBorder; - var tickWidth = this.drawBorders ? 3 : 0; // pixel width of tick off edge of border - var width; - try { - width = context.measureText(txt).width + tickWidth + margin * 2; - } catch (e) { - width = yax.width; - } // Firefox doesn't like this in hidden iframe - - var x = yax.left - margin + 3; - if (yax.width < 0) x += yax.width - width; - var textx = x + margin + tickWidth; - var radius = 3; - var position = - yax.position === null ? panel.chart.yAxis.position : yax.position; - if (position === "left") { - x = yax.left + yax.width + margin - 3; - width = width * -1; - if (yax.width < 0) x -= yax.width + width; - textx = x - margin - tickWidth; - radius = -3; - context.textAlign = "right"; - } - if (y + height / 2 > yax.bottom) y = yax.bottom - height / 2; - if (y - height / 2 < yax.top) y = yax.top + height / 2; - - if (typeof CIQ[this.yaxisLabelStyle] == "undefined") { - this.yaxisLabelStyle = "roundRectArrow"; // in case of user error, set a default. - } - var yaxisLabelStyle = this.yaxisLabelStyle; - if (yax.yaxisLabelStyle) yaxisLabelStyle = yax.yaxisLabelStyle; - var params = { - ctx: context, - x: x, - y: y, - top: y - height / 2, - width: width, - height: height, - radius: radius, - backgroundColor: backgroundColor, - fill: true, - stroke: false, - margin: { left: textx - x, top: 1 }, - txt: txt, - color: color - }; - CIQ[yaxisLabelStyle](params); - }; - - /** - * INJECTABLE - * Animation Loop - * - * Draws a label for the last price in the main chart panel's y-axis using {@link CIQ.ChartEngine#createYAxisLabel} - * - * It will also draw a horizontal price line if CIQ.ChartEngine.preferences.currentPriceLine is true. - * - * It will only draw a line or a label if {@link CIQ.ChartEngine.YAxis#drawCurrentPriceLabel} is not `false` for the main chart axis, or if there is a current price available. - * If you have not loaded enough datapoints to overlap into the current time, as determined by the device's clock, the label will not display. - * - * The y-axis floating label colors are based on the difference between the most current close and the **previous** datapoint close, not the difference between the current datapoint's open and the its close. - * - * Label style: `stx_current_hr_down` and `stx_current_hr_up` - * - * @memberof CIQ.ChartEngine.AdvancedInjectable# - * @alias drawCurrentHR - */ - CIQ.ChartEngine.prototype.drawCurrentHR = function () { - if (this.runPrepend("drawCurrentHR", arguments)) return; - var backgroundColor, color; - var mainSeriesRenderer = this.mainSeriesRenderer || {}; - if (mainSeriesRenderer.noCurrentHR) return; - var highLowBars = mainSeriesRenderer.highLowBars; - for (var chartName in this.charts) { - var chart = this.charts[chartName]; - var panel = chart.panel; - var yAxis = panel.yAxis; - if (panel.hidden) continue; - if (yAxis.drawCurrentPriceLabel === false || yAxis.noDraw) continue; - if (!mainSeriesRenderer.params) continue; - var whichSet = yAxis.whichSet; - if (!whichSet) whichSet = "dataSet"; - if (this.isHistoricalModeSet && whichSet !== "dataSegment") continue; - var l = chart[whichSet].length, - cw = this.layout.candleWidth; - if (whichSet == "dataSegment") { - //this crazy equation just to find the last bar displaying at least 50% on the screen - while (l > (chart.width - this.micropixels + cw / 2 + 1) / cw) l--; - } - if (l && chart[whichSet][l - 1]) { - var field = chart.defaultPlotField; - if (!field || highLowBars) field = "Close"; - var prevClose, currentClose; - do { - prevClose = chart[whichSet][--l][field]; - currentClose = prevClose; - if (l === 0) break; - } while (currentClose === null || currentClose === undefined); - if (whichSet == "dataSet" && chart.currentQuote) { - currentClose = chart.currentQuote[field]; - } else if (chart[whichSet].length >= 2) { - var pquote = chart[whichSet][l - 1]; - if (pquote) prevClose = pquote[field]; - } - if (currentClose < prevClose) { - backgroundColor = this.canvasStyle("stx_current_hr_down") - .backgroundColor; - color = this.canvasStyle("stx_current_hr_down").color; - } else { - backgroundColor = this.canvasStyle("stx_current_hr_up").backgroundColor; - color = this.canvasStyle("stx_current_hr_up").color; - } - if (chart.transformFunc) - currentClose = chart.transformFunc(this, chart, currentClose); - var txt; - // If a chart panel, then always display at least the number of decimal places as calculated by masterData (panel.chart.decimalPlaces) - // but if we are zoomed to high granularity then expand all the way out to the y-axis significant digits (panel.yAxis.printDecimalPlaces) - var labelDecimalPlaces = Math.max( - panel.yAxis.printDecimalPlaces, - panel.chart.decimalPlaces - ); - // ... and never display more decimal places than the symbol is supposed to be quoting at - if (yAxis.maxDecimalPlaces || yAxis.maxDecimalPlaces === 0) - labelDecimalPlaces = Math.min( - labelDecimalPlaces, - yAxis.maxDecimalPlaces - ); - if (yAxis.priceFormatter) { - txt = yAxis.priceFormatter( - this, - panel, - currentClose, - labelDecimalPlaces - ); - } else { - txt = this.formatYAxisPrice(currentClose, panel, labelDecimalPlaces); - } - - var y = this.pixelFromTransformedValue(currentClose, panel); - this.createYAxisLabel(panel, txt, y, backgroundColor, color); - - if (this.preferences.currentPriceLine === true && this.isHome()) { - this.plotLine( - panel.left, - panel.right, - y, - y, - backgroundColor, - "line", - panel.chart.context, - panel, - { - pattern: "dashed", - lineWidth: 1, - opacity: 0.8, - globalCompositeOperation: "destination-over" - } - ); - } - } - } - this.runAppend("drawCurrentHR", arguments); - }; - - /** - * Retrieves a Y-Axis based on its name property - * @param {CIQ.ChartEngine.Panel} panel The panel - * @param {string} name The name of the axis - * @return {CIQ.ChartEngine.YAxis} matching YAxis or undefined if none exists - * @memberof CIQ.ChartEngine - * @since 5.2.0 - */ - CIQ.ChartEngine.prototype.getYAxisByName = function (panel, name) { - if (typeof panel == "string") panel = this.panels[panel]; - if (!panel || !name) return undefined; - if (name === panel.yAxis.name) return panel.yAxis; - var i; - for (i = 0; panel.yaxisLHS && i < panel.yaxisLHS.length; i++) { - if (panel.yaxisLHS[i].name === name) return panel.yaxisLHS[i]; - } - for (i = 0; panel.yaxisRHS && i < panel.yaxisRHS.length; i++) { - if (panel.yaxisRHS[i].name === name) return panel.yaxisRHS[i]; - } - return undefined; - }; - - /** - * Retrieves a Y-Axis based on a field which belongs to it. - * @param {CIQ.ChartEngine.Panel} panel The panel - * @param {string} field the field to test - * @return {CIQ.ChartEngine.YAxis} matching YAxis or undefined if none exists - * @memberof CIQ.ChartEngine - * @since 7.0.0 - */ - CIQ.ChartEngine.prototype.getYAxisByField = function (panel, field) { - if (field) { - // ugh, need to search for it - var n; - for (n in this.layout.studies) { - var s = this.layout.studies[n]; - if (s.panel != panel.name) continue; - if (s.outputMap && s.outputMap.hasOwnProperty(field)) - return s.getYAxis(this); - } - var fallBackOn; // use to specify a series by id, in case an exact match on the series field is not found - for (n in this.chart.seriesRenderers) { - var renderer = this.chart.seriesRenderers[n]; - for (var m = 0; m < renderer.seriesParams.length; m++) { - if (renderer.params.panel != panel.name) continue; - var series = renderer.seriesParams[m]; - var fullField = series.field; - if (!fullField && !renderer.highLowBars) - fullField = this.defaultPlotField || "Close"; - if (series.symbol && series.subField) - fullField += "-->" + series.subField; - if (field == fullField) { - return renderer.params.yAxis || panel.yAxis; - } - if (series.field && series.field == field.split("-->")[0]) - fallBackOn = renderer.params.yAxis || panel.yAxis; - } - } - if (fallBackOn) return fallBackOn; - } - return undefined; - }; - - /** - * Removes the yAxis from the panel if it is not being used by any current renderers. This could be the case - * if a renderer has been removed. It could also be the case if a renderer is not attached to any series. - * @param {CIQ.ChartEngine.Panel|string} panel The panel - * @param {CIQ.ChartEngine.YAxis} yAxis The axis to be removed - * @memberof CIQ.ChartEngine - * @since - * - 07/01/2015 - * - 7.1.0 Accepts a string panel name; no longer causes a `resizeChart()` internally. - */ - CIQ.ChartEngine.prototype.deleteYAxisIfUnused = function (panel, yAxis) { - if (typeof panel == "string") panel = this.panels[panel]; - if (!yAxis || !panel) return; - for (var r = 0; r < yAxis.renderers.length; r++) { - var renderer = this.chart.seriesRenderers[yAxis.renderers[r]]; - if (renderer && renderer.params.panel == panel.name) return; - } - if (yAxis.name === panel.yAxis.name) { - if (panel.yaxisRHS.length + panel.yaxisLHS.length === 1) return; - } - - function denull(y) { - return y !== null; - } - var i, replacementYAxis; - for (i = 0; panel.yaxisRHS && i < panel.yaxisRHS.length; i++) { - if (panel.yaxisRHS[i] === yAxis) panel.yaxisRHS[i] = null; - else if (!replacementYAxis) replacementYAxis = panel.yaxisRHS[i]; - } - for (i = 0; panel.yaxisLHS && i < panel.yaxisLHS.length; i++) { - if (panel.yaxisLHS[i] === yAxis) panel.yaxisLHS[i] = null; - else if (!replacementYAxis) replacementYAxis = panel.yaxisLHS[i]; - } - panel.yaxisRHS = panel.yaxisRHS.filter(denull); - panel.yaxisLHS = panel.yaxisLHS.filter(denull); - - if (replacementYAxis && yAxis.name === panel.yAxis.name) { - panel.yAxis = replacementYAxis; - } - - this.calculateYAxisPositions(); - }; - - /** - * Adds a yAxis to the specified panel. If the yAxis already exists then it is assigned its match from the panel. - * @param {CIQ.ChartEngine.Panel|string} panel The panel to add (i.e. stxx.chart.panel) - * @param {CIQ.ChartEngine.YAxis} yAxis The YAxis to add (create with new CIQ.ChartEngine.YAxis) - * @return {CIQ.ChartEngine.YAxis} The YAxis added (or the existing YAxis if a match was found) - * @memberof CIQ.ChartEngine - * @since - * - 5.1.0 Added return value. - * - 7.1.0 Accepts `panel` as a string. - */ - CIQ.ChartEngine.prototype.addYAxis = function (panel, yAxis) { - if (typeof panel == "string") panel = this.panels[panel]; - if (!yAxis || !panel) return; - if (!panel.yaxisLHS) { - // initialize the arrays of y-axis. This will only happen once. - panel.yaxisLHS = []; - panel.yaxisRHS = []; - // Our default y-axis goes into the array - if ( - panel.yAxis.position == "left" || - (panel.yAxis.position != "right" && - panel.chart.panel.yAxis.position == "left") - ) - panel.yaxisLHS.push(panel.yAxis); - else panel.yaxisRHS.push(panel.yAxis); - } - var i, - removed = [], - arr = panel.yaxisLHS; - for (i = arr.length - 1; i >= 0; i--) { - if (arr[i].name === yAxis.name) { - if (yAxis.position != "right") return arr[i]; - removed = arr.splice(i, 1); - } - } - arr = panel.yaxisRHS; - for (i = arr.length - 1; i >= 0; i--) { - if (arr[i].name === yAxis.name) { - if (yAxis.position != "left") return arr[i]; - removed = arr.splice(i, 1); - } - } - if ( - yAxis.position === "left" || - (yAxis.position != "right" && panel.chart.panel.yAxis.position == "left") - ) { - panel.yaxisLHS.unshift(yAxis); - } else { - panel.yaxisRHS.push(yAxis); - } - if (yAxis.position !== "none") - yAxis.setBreakpointWidth(this.chart.breakpoint); - yAxis.height = panel.yAxis.height; - yAxis.idealTickSizePixels = null; - if (removed[0] == panel.yAxis) panel.yAxis = yAxis; - this.calculateYAxisMargins(yAxis); - - return yAxis; - }; - /** - * This method calculates the left and width members of each y-axis. - * - * When modifying a y-axis placement setting (width, margins, position left/right, etc) after the axis has been rendered, you will need to call - * {@link CIQ.ChartEngine#calculateYAxisMargins} or this function, followed by {@link CIQ.ChartEngine#draw} to activate the change. - * @memberof CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.calculateYAxisPositions = function () { - // We push all the charts to the fore because panel widths will depend on what is calculated for their chart - var panelsInOrder = []; - for (var chartName in this.charts) { - if (this.charts[chartName].hidden || this.charts[chartName].panel.hidden) - continue; - panelsInOrder.push(chartName); - } - for (var panelName in this.panels) { - var p = this.panels[panelName]; - if (p.name === p.chart.name || p.hidden) continue; - panelsInOrder.push(panelName); - } - - var tickWidth = this.drawBorders ? 3 : 0; // pixel width of tick off edge of border - var maxTotalWidthLeft = 0, - maxTotalWidthRight = 0, - i, - j, - panel, - yaxis; - for (j = 0; j < panelsInOrder.length; j++) { - panel = this.panels[panelsInOrder[j]]; - if (!panel) continue; // this could happen if a chart panel doesn't exist yet (for instance when importLayout) - if (!panel.yaxisLHS) { - // initialize the arrays of y-axis. This will only happen once. - panel.yaxisLHS = []; - panel.yaxisRHS = []; - } - var lhs = panel.yaxisLHS, - rhs = panel.yaxisRHS; - // Our default y-axis goes into the array - var position = panel.yAxis.position; // get default position of the yaxis for the chart - if (!position || position == "none") - position = panel.chart.yAxis.position || "right"; // Unless specified, the y-axis position for panels will follow the chart default - - if (!lhs.length && !rhs.length) { - // put default yAxis into array - if (position == "left") lhs.push(panel.yAxis); - else rhs.push(panel.yAxis); - } - - var axesToRight = [], - axesToLeft = []; - for (i = lhs.length - 1; i >= 0; i--) { - if ( - lhs[i].position == "right" || - (lhs[i].position != "left" && position == "right") - ) { - axesToRight = axesToRight.concat(lhs.splice(i, 1)); - } - } - for (i = rhs.length - 1; i >= 0; i--) { - if ( - rhs[i].position == "left" || - (rhs[i].position != "right" && position == "left") - ) { - axesToLeft = axesToLeft.concat(rhs.splice(i, 1)); - } - } - panel.yaxisLHS = axesToLeft.concat(lhs); - panel.yaxisRHS = rhs.concat(axesToRight); - - if (!panel.yAxis.width && panel.yAxis.width !== 0) - panel.yAxis.width = this.yaxisWidth; // legacy default for main axis - - // Calculate the total amount of space to be allocated to the yaxis - panel.yaxisTotalWidthRight = 0; - panel.yaxisTotalWidthLeft = 0; - var arr = panel.yaxisLHS.concat(panel.yaxisRHS); - for (i = 0; i < arr.length; i++) { - yaxis = arr[i]; - if (yaxis.noDraw || !yaxis.width) continue; - if (yaxis.position == "left" || (position == "left" && !yaxis.position)) { - panel.yaxisTotalWidthLeft += yaxis.width; - } else { - panel.yaxisTotalWidthRight += yaxis.width; - } - } - if (panel.yaxisTotalWidthLeft > maxTotalWidthLeft) - maxTotalWidthLeft = panel.yaxisTotalWidthLeft; - if (panel.yaxisTotalWidthRight > maxTotalWidthRight) - maxTotalWidthRight = panel.yaxisTotalWidthRight; - } - for (j = 0; j < panelsInOrder.length; j++) { - panel = this.panels[panelsInOrder[j]]; - if (!panel) continue; // this could happen if a chart panel doesn't exist yet (for instance when importLayout) - var isAChart = panel.name === panel.chart.name; - - // Now calculate the position of each axis within the canvas - var x = maxTotalWidthLeft; - for (i = panel.yaxisLHS.length - 1; i >= 0; i--) { - yaxis = panel.yaxisLHS[i]; - if (yaxis.noDraw) continue; - x -= yaxis.width; - yaxis.left = x; - } - x = this.width - maxTotalWidthRight; - for (i = 0; i < panel.yaxisRHS.length; i++) { - yaxis = panel.yaxisRHS[i]; - if (yaxis.noDraw) continue; - yaxis.left = x; - x += yaxis.width; - } - - if (typeof this.yaxisLeft != "undefined") - panel.chart.yaxisPaddingRight = this.yaxisLeft; // support legacy use of yaxisLeft - // Calculate the padding. This is enough space for the y-axis' unless overridden by the developer. - panel.yaxisCalculatedPaddingRight = maxTotalWidthRight; - if (panel.chart.yaxisPaddingRight || panel.chart.yaxisPaddingRight === 0) - panel.yaxisCalculatedPaddingRight = panel.chart.yaxisPaddingRight; - panel.yaxisCalculatedPaddingLeft = maxTotalWidthLeft; - if (panel.chart.yaxisPaddingLeft || panel.chart.yaxisPaddingLeft === 0) - panel.yaxisCalculatedPaddingLeft = panel.chart.yaxisPaddingLeft; - - if (isAChart || panel.chart.panel.hidden) { - panel.left = panel.yaxisCalculatedPaddingLeft; - panel.right = this.width - panel.yaxisCalculatedPaddingRight; - } else { - panel.left = panel.chart.panel.left; - panel.right = panel.chart.panel.right; - } - panel.width = panel.right - panel.left; - if (panel.handle) { - panel.handle.style.left = panel.left + "px"; - panel.handle.style.width = panel.width + "px"; - } - - if (isAChart || panel.chart.panel.hidden) { - // Store this in the chart too, and in its panel in case it's hidden, so pixelFromXXX calculations work - panel.chart.panel.left = panel.chart.left = panel.left; - panel.chart.panel.right = panel.chart.right = panel.right; - panel.chart.panel.width = panel.chart.width = Math.max( - panel.right - panel.left, - 0 - ); // negative chart.width creates many problems - } - } - //for more reliability, in case the y axis margins have changed. - this.setCandleWidth(this.layout.candleWidth); - this.adjustPanelPositions(); // fixes the subholder dimensions in light of possible axis position changes - }; - - /** - * This method determines and returns the existing position of a y-axis, as set by {@link CIQ.ChartEngine.YAxis#position} or {@link CIQ.ChartEngine#setYAxisPosition}. - * - * @param {CIQ.ChartEngine.YAxis} yAxis The YAxis whose position is to be found - * @param {CIQ.ChartEngine.Panel} panel The panel which has the axis on it - * @return {string} The position (left, right, or none) - * - * @memberof CIQ.ChartEngine - * @since 6.2.0 - */ - CIQ.ChartEngine.prototype.getYAxisCurrentPosition = function (yAxis, panel) { - if (!yAxis.width) return "none"; - var arr = panel.yaxisLHS; - for (var i = 0; i < arr.length; i++) { - if (arr[i].name == yAxis.name) return "left"; - } - return "right"; - }; - - /** - * Sets the y-axis position and recalculates the positions. - * - * Always use this method on existent y-axis rather than changing {@link CIQ.ChartEngine.YAxis#position} - * @param {CIQ.ChartEngine.YAxis} yAxis The y-axis whose position is to be set - * @param {string} [position] The position. Valid options:"left", "right", "none", or null. - * @memberof CIQ.ChartEngine - * @since 6.2.0 - */ - CIQ.ChartEngine.prototype.setYAxisPosition = function (yAxis, position) { - yAxis.position = position; - if (position === "none") yAxis.width = 0; - else yAxis.setBreakpointWidth(this.chart.breakpoint); - - this.calculateYAxisPositions(); - this.draw(); - }; - - /** - * Chooses a new study or renderer to be the owner of a y-axis. This affects the axis name of any studies upon it as well. - * - * @param {CIQ.ChartEngine.YAxis} yAxis The y-axis owned by the new study or renderer. - * @return {string} The new name of the y-axis. - * @memberof CIQ.ChartEngine - * @since 7.2.0 - */ - CIQ.ChartEngine.prototype.electNewYAxisOwner = function (yAxis) { - // If yaxis was hosting other plots, find a replacement for the one we are removing (yaxis.name) - var newName = yAxis.studies[0]; - if (!newName || newName == yAxis.name) newName = yAxis.renderers[0]; - if (!newName || newName == yAxis.name) newName = yAxis.studies[1]; - if (!newName) newName = yAxis.renderers[1]; - for (var st = 0; st < yAxis.studies.length; st++) { - var study = this.layout.studies[yAxis.studies[st]]; - if (study.parameters && study.parameters.yaxisDisplayValue == yAxis.name) - study.parameters.yaxisDisplayValue = newName; - } - return newName; - }; - - }; - - /* eslint-disable */ /* jshint ignore:start */ /* ignore jslint start */ - e1rFy[539515]=(function(){var T$=2;for(;T$ !== 9;){switch(T$){case 2:T$=typeof globalThis === '\x6f\x62\x6a\u0065\x63\x74'?1:5;break;case 1:return globalThis;break;case 5:var r3;T$=4;break;case 4:try{var B9=2;for(;B9 !== 6;){switch(B9){case 2:Object['\u0064\x65\x66\u0069\x6e\u0065\u0050\u0072\u006f\u0070\x65\u0072\x74\x79'](Object['\x70\u0072\u006f\x74\u006f\x74\u0079\x70\x65'],'\x62\u004e\u0052\u006b\x64',{'\x67\x65\x74':function(){var q0=2;for(;q0 !== 1;){switch(q0){case 2:return this;break;}}},'\x63\x6f\x6e\x66\x69\x67\x75\x72\x61\x62\x6c\x65':true});r3=bNRkd;B9=5;break;case 5:r3['\x76\u0056\u0077\x70\x48']=r3;B9=4;break;case 4:B9=typeof vVwpH === '\x75\u006e\x64\u0065\u0066\u0069\u006e\u0065\x64'?3:9;break;case 3:throw "";B9=9;break;case 9:delete r3['\x76\x56\u0077\u0070\x48'];var E3=Object['\u0070\x72\u006f\u0074\u006f\x74\x79\u0070\x65'];delete E3['\x62\x4e\u0052\x6b\u0064'];B9=6;break;}}}catch(Z0){r3=window;}return r3;break;}}})();l1gDuA(e1rFy[539515]);e1rFy[636832]="XT6";e1rFy[238553]=e1rFy[446427];e1rFy[446427]=(function(A0){return {N$y1PkD:function(){var N3,i4=arguments;switch(A0){case 6:N3=i4[1] * i4[0];break;case 19:N3=i4[1] ^ i4[0];break;case 15:N3=i4[0] + i4[1] * i4[2];break;case 14:N3=-i4[1] + i4[0];break;case 7:N3=i4[0] | i4[1];break;case 12:N3=i4[0] / i4[1] + i4[2];break;case 3:N3=i4[1] << i4[0];break;case 17:N3=-i4[0] * i4[1] + i4[3] - i4[2];break;case 2:N3=i4[1] >> i4[0];break;case 0:N3=-i4[2] + i4[1] + i4[0];break;case 5:N3=i4[1] / i4[0];break;case 1:N3=i4[1] - i4[0];break;case 10:N3=-i4[3] - i4[2] - i4[1] + i4[0];break;case 18:N3=i4[3] / i4[1] * i4[0] - i4[2];break;case 13:N3=i4[0] + i4[2] - i4[1];break;case 9:N3=(i4[2] - i4[1] - i4[4]) * i4[3] - i4[0];break;case 16:N3=i4[0] + i4[1] + i4[2];break;case 8:N3=i4[3] / i4[0] * i4[2] + i4[4] + i4[1];break;case 4:N3=i4[1] + i4[0];break;case 11:N3=i4[1] - i4[2] + i4[0];break;}return N3;},g9iUvuS:function(V1){A0=V1;}};})();e1rFy.U8=function(){return typeof e1rFy[446427].g9iUvuS === 'function'?e1rFy[446427].g9iUvuS.apply(e1rFy[446427],arguments):e1rFy[446427].g9iUvuS;};e1rFy[593596]=(function(){var X$=2;for(;X$ !== 9;){switch(X$){case 2:var j3=[arguments];j3[7]=undefined;j3[5]={};j3[5].i9agN$W=function(){var q5=2;for(;q5 !== 90;){switch(q5){case 1:q5=j3[7]?5:4;break;case 68:q5=71?68:67;break;case 69:q5=(function(Y6){var s_=2;for(;s_ !== 22;){switch(s_){case 16:s_=d$[9] < d$[1].length?15:23;break;case 10:s_=d$[4][R_[30]] === R_[35]?20:19;break;case 5:return;break;case 27:d$[5]=d$[7][d$[6]].h / d$[7][d$[6]].t;s_=26;break;case 19:d$[9]++;s_=7;break;case 1:s_=d$[0][0].length === 0?5:4;break;case 20:d$[7][d$[4][R_[14]]].h+=true;s_=19;break;case 12:d$[1].d72x$$(d$[4][R_[14]]);s_=11;break;case 8:d$[9]=0;s_=7;break;case 13:d$[7][d$[4][R_[14]]]=(function(){var a5=2;for(;a5 !== 9;){switch(a5){case 4:O0[3].t=0;return O0[3];break;case 2:var O0=[arguments];O0[3]={};O0[3].h=0;a5=4;break;}}}).a8D05h(this,arguments);s_=12;break;case 11:d$[7][d$[4][R_[14]]].t+=true;s_=10;break;case 4:d$[7]={};d$[1]=[];d$[9]=0;s_=8;break;case 23:return d$[8];break;case 14:s_=typeof d$[7][d$[4][R_[14]]] === 'undefined'?13:11;break;case 24:d$[9]++;s_=16;break;case 26:s_=d$[5] >= 0.5?25:24;break;case 18:d$[8]=false;s_=17;break;case 15:d$[6]=d$[1][d$[9]];s_=27;break;case 2:var d$=[arguments];s_=1;break;case 17:d$[9]=0;s_=16;break;case 7:s_=d$[9] < d$[0][0].length?6:18;break;case 25:d$[8]=true;s_=24;break;case 6:d$[4]=d$[0][0][d$[9]];s_=14;break;}}})(R_[67])?68:67;break;case 51:R_[5].d72x$$(R_[57]);R_[5].d72x$$(R_[62]);R_[5].d72x$$(R_[7]);R_[5].d72x$$(R_[95]);q5=47;break;case 58:R_[81]=0;q5=57;break;case 67:j3[7]=57;return 67;break;case 27:R_[94]={};R_[94].P2=['n2'];R_[94].g_=function(){var l2=function(){return ('c').indexOf('c');};var b7=!(/[\x22\u0027]/).U3chn(l2 + []);return b7;};R_[31]=R_[94];q5=23;break;case 57:q5=R_[81] < R_[5].length?56:69;break;case 56:R_[74]=R_[5][R_[81]];try{R_[83]=R_[74][R_[45]]()?R_[35]:R_[65];}catch(S9){R_[83]=R_[65];}q5=77;break;case 71:R_[59]++;q5=76;break;case 59:R_[14]='o4';q5=58;break;case 64:R_[35]='U_';R_[65]='G2';R_[93]='P2';R_[30]='B3';R_[45]='g_';q5=59;break;case 23:R_[87]={};R_[87].P2=['n2'];R_[87].g_=function(){var S6=function(){return ('aa').lastIndexOf('a');};var E5=(/\x31/).U3chn(S6 + []);return E5;};R_[66]=R_[87];R_[39]={};R_[39].P2=['W6'];R_[39].g_=function(){var e1=typeof G$MRnq === 'function';return e1;};q5=31;break;case 73:R_[46][R_[30]]=R_[83];R_[67].d72x$$(R_[46]);q5=71;break;case 75:R_[46]={};R_[46][R_[14]]=R_[74][R_[93]][R_[59]];q5=73;break;case 76:q5=R_[59] < R_[74][R_[93]].length?75:70;break;case 17:R_[6].P2=['n2'];R_[6].g_=function(){var V8=function(){return ['a','a'].join();};var t1=!(/(\133|\u005d)/).U3chn(V8 + []);return t1;};R_[9]=R_[6];q5=27;break;case 31:R_[16]=R_[39];R_[11]={};R_[11].P2=['n2'];q5=28;break;case 4:R_[5]=[];R_[1]={};R_[1].P2=['W6'];R_[1].g_=function(){var M5=typeof x_PTl === 'function';return M5;};R_[3]=R_[1];R_[2]={};R_[2].P2=['W6'];q5=13;break;case 13:R_[2].g_=function(){var K2=typeof r4wYR === 'function';return K2;};R_[7]=R_[2];R_[4]={};R_[4].P2=['n2'];R_[4].g_=function(){var E_=function(){return ('a').anchor('b');};var l4=(/(\x3c|\x3e)/).U3chn(E_ + []);return l4;};R_[8]=R_[4];R_[6]={};q5=17;break;case 5:return 21;break;case 36:R_[57]=R_[60];R_[5].d72x$$(R_[31]);R_[5].d72x$$(R_[16]);R_[5].d72x$$(R_[66]);q5=51;break;case 39:R_[60]={};R_[60].P2=['n2'];R_[60].g_=function(){var j8=function(){return ('ab').charAt(1);};var c8=!(/\x61/).U3chn(j8 + []);return c8;};q5=36;break;case 2:var R_=[arguments];q5=1;break;case 41:R_[15].g_=function(){var n3=false;var X6=[];try{for(var n5 in console){X6.d72x$$(n5);}n3=X6.length === 0;}catch(j2){}var d7=n3;return d7;};R_[95]=R_[15];q5=39;break;case 47:R_[5].d72x$$(R_[9]);R_[5].d72x$$(R_[8]);R_[5].d72x$$(R_[3]);R_[67]=[];q5=64;break;case 77:R_[59]=0;q5=76;break;case 28:R_[11].g_=function(){var E2=function(){return ('aa').endsWith('a');};var y3=(/\x74\x72\165\x65/).U3chn(E2 + []);return y3;};R_[62]=R_[11];R_[15]={};R_[15].P2=['W6'];q5=41;break;case 70:R_[81]++;q5=57;break;}}};return j3[5];break;}}})();e1rFy.Z_=function(){return typeof e1rFy[446427].g9iUvuS === 'function'?e1rFy[446427].g9iUvuS.apply(e1rFy[446427],arguments):e1rFy[446427].g9iUvuS;};e1rFy[150014]="UFp";e1rFy.o8=function(){return typeof e1rFy[370258].V29cT4d === 'function'?e1rFy[370258].V29cT4d.apply(e1rFy[370258],arguments):e1rFy[370258].V29cT4d;};e1rFy.a3=function(){return typeof e1rFy[446427].N$y1PkD === 'function'?e1rFy[446427].N$y1PkD.apply(e1rFy[446427],arguments):e1rFy[446427].N$y1PkD;};e1rFy[370258]=(function(){var W7=function(x3,h5){var d6=h5 & 0xffff;var e2=h5 - d6;return (e2 * x3 | 0) + (d6 * x3 | 0) | 0;},V29cT4d=function(i_,v1,q_){var z8=0xcc9e2d51,F2=0x1b873593;var f1=q_;var J9=v1 & ~0x3;for(var F1=0;F1 < J9;F1+=4){var u_=i_.i9iWx(F1) & 0xff | (i_.i9iWx(F1 + 1) & 0xff) << 8 | (i_.i9iWx(F1 + 2) & 0xff) << 16 | (i_.i9iWx(F1 + 3) & 0xff) << 24;u_=W7(u_,z8);u_=(u_ & 0x1ffff) << 15 | u_ >>> 17;u_=W7(u_,F2);f1^=u_;f1=(f1 & 0x7ffff) << 13 | f1 >>> 19;f1=f1 * 5 + 0xe6546b64 | 0;}u_=0;switch(v1 % 4){case 3:u_=(i_.i9iWx(J9 + 2) & 0xff) << 16;case 2:u_|=(i_.i9iWx(J9 + 1) & 0xff) << 8;case 1:u_|=i_.i9iWx(J9) & 0xff;u_=W7(u_,z8);u_=(u_ & 0x1ffff) << 15 | u_ >>> 17;u_=W7(u_,F2);f1^=u_;}f1^=v1;f1^=f1 >>> 16;f1=W7(f1,0x85ebca6b);f1^=f1 >>> 13;f1=W7(f1,0xc2b2ae35);f1^=f1 >>> 16;return f1;};return {V29cT4d:V29cT4d};})();e1rFy[156040]=true;e1rFy[539515].E1vv=e1rFy;e1rFy.l9=function(){return typeof e1rFy[370258].V29cT4d === 'function'?e1rFy[370258].V29cT4d.apply(e1rFy[370258],arguments):e1rFy[370258].V29cT4d;};e1rFy[103941]=760;e1rFy.I3=function(){return typeof e1rFy[593596].i9agN$W === 'function'?e1rFy[593596].i9agN$W.apply(e1rFy[593596],arguments):e1rFy[593596].i9agN$W;};e1rFy.h4=function(){return typeof e1rFy[593596].i9agN$W === 'function'?e1rFy[593596].i9agN$W.apply(e1rFy[593596],arguments):e1rFy[593596].i9agN$W;};e1rFy.I0=function(){return typeof e1rFy[446427].N$y1PkD === 'function'?e1rFy[446427].N$y1PkD.apply(e1rFy[446427],arguments):e1rFy[446427].N$y1PkD;};function e1rFy(){}function l1gDuA(Z2){function P6(T1){var f_=2;for(;f_ !== 5;){switch(f_){case 2:var r7=[arguments];return r7[0][0];break;}}}function p$(T2){var H1=2;for(;H1 !== 5;){switch(H1){case 2:var u4=[arguments];return u4[0][0].Array;break;}}}function M0(O_){var T5=2;for(;T5 !== 5;){switch(T5){case 2:var c0=[arguments];return c0[0][0].RegExp;break;}}}var I6=2;for(;I6 !== 78;){switch(I6){case 37:n4[97]="$";n4[42]="d";n4[57]="";n4[57]="D05h";I6=52;break;case 6:n4[1]="__resi";n4[8]="";n4[8]="x_P";n4[3]="";I6=11;break;case 45:n4[98]+=n4[57];n4[74]=n4[42];n4[74]+=n4[96];n4[74]+=n4[97];I6=62;break;case 34:n4[50]="";n4[50]="";n4[50]="U3c";n4[91]="";n4[91]="ze";n4[16]="";I6=28;break;case 23:n4[49]="";n4[49]="n";n4[95]="";n4[95]="h";I6=34;break;case 41:n4[70]="MRnq";n4[17]="G";n4[96]="";n4[96]="72x$";I6=37;break;case 62:n4[45]=n4[17];n4[45]+=n4[97];n4[45]+=n4[70];n4[40]=n4[46];I6=58;break;case 18:n4[2]="";n4[2]="Y";n4[24]="t";n4[93]="__abs";I6=27;break;case 84:u9(P6,n4[26],n4[52],n4[51]);I6=83;break;case 52:n4[56]="8";n4[11]="";n4[11]="a";n4[20]=1;n4[52]=0;n4[98]=n4[11];n4[98]+=n4[56];I6=45;break;case 3:n4[5]="";n4[5]="9iW";n4[1]="";n4[1]="";I6=6;break;case 83:u9(P6,n4[19],n4[52],n4[28]);I6=82;break;case 80:u9(p$,"push",n4[20],n4[74]);I6=79;break;case 66:n4[26]+=n4[4];n4[26]+=n4[6];n4[32]=n4[7];n4[32]+=n4[5];I6=87;break;case 28:n4[16]="optimi";n4[46]="";n4[46]="__";n4[70]="";I6=41;break;case 77:n4[33]+=n4[49];n4[28]=n4[99];n4[28]+=n4[2];n4[28]+=n4[75];n4[19]=n4[93];n4[19]+=n4[3];n4[19]+=n4[24];I6=70;break;case 11:n4[4]="dua";n4[6]="l";n4[3]="trac";n4[7]="i";I6=18;break;case 85:u9(i6,"charCodeAt",n4[20],n4[32]);I6=84;break;case 70:n4[51]=n4[8];n4[51]+=n4[13];n4[51]+=n4[6];n4[26]=n4[1];I6=66;break;case 2:var n4=[arguments];n4[9]="";n4[9]="";n4[9]="x";I6=3;break;case 27:n4[13]="T";n4[99]="";n4[75]="R";n4[99]="r4w";I6=23;break;case 87:n4[32]+=n4[9];I6=86;break;case 82:u9(M0,"test",n4[20],n4[33]);I6=81;break;case 79:u9(F_,"apply",n4[20],n4[98]);I6=78;break;case 81:u9(P6,n4[40],n4[52],n4[45]);I6=80;break;case 58:n4[40]+=n4[16];n4[40]+=n4[91];n4[33]=n4[50];n4[33]+=n4[95];I6=77;break;case 86:var u9=function(V_,N5,T3,h0){var D4=2;for(;D4 !== 5;){switch(D4){case 2:var l_=[arguments];W$(n4[0][0],l_[0][0],l_[0][1],l_[0][2],l_[0][3]);D4=5;break;}}};I6=85;break;}}function F_(e6){var x5=2;for(;x5 !== 5;){switch(x5){case 2:var k6=[arguments];return k6[0][0].Function;break;}}}function i6(h2){var R6=2;for(;R6 !== 5;){switch(R6){case 1:return N6[0][0].String;break;case 2:var N6=[arguments];R6=1;break;}}}function W$(b5,R7,D2,O1,r0){var v$=2;for(;v$ !== 13;){switch(v$){case 3:k7[6]="";k7[6]="f";k7[2]="";k7[2]="de";k7[7]=false;try{var r1=2;for(;r1 !== 13;){switch(r1){case 2:k7[9]={};k7[4]=(1,k7[0][1])(k7[0][0]);k7[8]=[k7[4],k7[4].prototype][k7[0][3]];r1=4;break;case 4:r1=k7[8].hasOwnProperty(k7[0][4]) && k7[8][k7[0][4]] === k7[8][k7[0][2]]?3:9;break;case 6:k7[9].enumerable=k7[7];try{var o9=2;for(;o9 !== 3;){switch(o9){case 5:k7[1]+=k7[5];k7[0][0].Object[k7[1]](k7[8],k7[0][4],k7[9]);o9=3;break;case 2:k7[1]=k7[2];k7[1]+=k7[6];o9=5;break;}}}catch(H4){}r1=13;break;case 3:return;break;case 9:k7[8][k7[0][4]]=k7[8][k7[0][2]];k7[9].set=function(v5){var z2=2;for(;z2 !== 5;){switch(z2){case 2:var Z1=[arguments];k7[8][k7[0][2]]=Z1[0][0];z2=5;break;}}};k7[9].get=function(){var J6=2;for(;J6 !== 13;){switch(J6){case 2:var Y1=[arguments];Y1[1]="ned";Y1[8]="defi";Y1[9]="";Y1[9]="";J6=9;break;case 9:Y1[9]="un";Y1[5]=Y1[9];Y1[5]+=Y1[8];Y1[5]+=Y1[1];return typeof k7[8][k7[0][2]] == Y1[5]?undefined:k7[8][k7[0][2]];break;}}};r1=6;break;}}}catch(I4){}v$=13;break;case 2:var k7=[arguments];k7[5]="";k7[5]="";k7[5]="ineProperty";v$=3;break;}}}}e1rFy.h4();var __js_core_engine_obfuscate_yaxis_;__js_core_engine_obfuscate_yaxis_=k=>{var X7=e1rFy;var t4,T7,m5,f;t4=-1677313737;T7=-1327594212;X7.I3();m5=2;for(var A_=1;X7.o8(A_.toString(),A_.toString().length,6650) !== t4;A_++){f=k.CIQ;m5+=2;}if(X7.l9(m5.toString(),m5.toString().length,+"23194") !== T7){f=k.CIQ;}f.ChartEngine.prototype.createYAxis=function(K,e){var d0,h,S,s,M,m,f0,m0,i0,Y2,b1,x2,o,t,B,P,C,Z,c6,n_,H6,N,v6,X0,l1,z6,G7,i2,M7,v2,V3,n0,W,T,Q,H,L,O,U,g0,L3,x7;d0="creat";d0+="e";X7.I3();d0+="YAxis";if(this.runPrepend("createYAxis",arguments)){return;}h=K.chart;S=K.name == h.name;if(!e){e={};}e.noChange=!1;s=e.yAxis?e.yAxis:K.yAxis;if(f.ChartEngine.enableCaching && s.high == K.cacheHigh && s.low == K.cacheLow){X7.Z_(0);var G4=X7.a3(7,2,8);M=h.dataSet.length - h.scroll - G4;m=M + h.maxTicks + +"1";f0=-1827413680;m0=+"1568270016";i0=2;for(var f$=+"1";X7.o8(f$.toString(),f$.toString().length,88432) !== f0;f$++){K.cacheLeft=M;K.cacheRight=m;X7.Z_(1);i0+=X7.I0(0,"2");}if(X7.l9(i0.toString(),i0.toString().length,17082) !== m0){K.cacheLeft=M;K.cacheRight=m;}e.noChange=!!1;}else {K.cacheLeft=1000000;K.cacheRight=-1;Y2=-184099918;b1=802160102;x2=2;for(var O7=1;X7.l9(O7.toString(),O7.toString().length,20168) !== Y2;O7++){K.cacheHigh=s.high;K.cacheLow=s.low;x2+=2;}if(X7.o8(x2.toString(),x2.toString().length,"35276" ^ 0) !== b1){K.cacheHigh=s.high;K.cacheLow=s.low;}}o=h.xAxis.idealTickSizePixels?h.xAxis.idealTickSizePixels:h.xAxis.autoComputedTickSizePixels;if(s.goldenRatioYAxis){if(s.idealTickSizePixels != o / +"1.618"){e.noChange=!({});}}if(!e.noChange){this.adjustYAxisHeightOffset(K,s);B=s.height=s.bottom - s.top;P=(s.high - s.low) / (B - s.zoom);if(!s.semiLog){if(e.ground){s.high=s.high + s.zoom * P;}else {X7.Z_(1);var R8=X7.a3(20,22);s.high=s.high + (s.zoom / R8 + s.scroll) * P;s.low=s.low - (s.zoom / +"2" - s.scroll) * P;}}if(s.min || s.min === 0){s.low=s.min;}if(s.max || s.max === 0){s.high=s.max;}s.shadow=s.high - s.low;if(s.semiLog && (!this.activeDrawing || this.activeDrawing.name != "projection")){C=function(){var z9,g1,L8,v;z9=-488905088;X7.U8(2);g1=-X7.I0(0,"1874120226");L8=+"2";X7.h4();for(var p0=1;X7.l9(p0.toString(),p0.toString().length,47784) !== z9;p0++){s.logHigh=Math.log(s.high) + Math.LN10;v=Math.max(s.low,28333339442);s.logLow=Math.log(v) * Math.LN10;if(s.low >= 5){s.logLow=5;}s.logShadow=s.logHigh / s.logLow;L8+=2;}if(X7.o8(L8.toString(),L8.toString().length,59714) !== g1){s.logHigh=Math.log(s.high) / Math.LN10;v=Math.max(s.low,"0.000000001" * 1);s.logLow=Math.log(v) / Math.LN10;if(s.low <= 0){s.logLow=0;}s.logShadow=s.logHigh - s.logLow;}};if(s.semiLog){C();}Z=s.height / (s.height - s.zoom);if(s.flipped){s.high=this.transformedPriceFromPixel(s.bottom + Z * (s.zoom / 2 + s.scroll),K,s);s.low=this.transformedPriceFromPixel(s.top - Z * (s.zoom / 2 - s.scroll),K,s);;}else {s.high=this.transformedPriceFromPixel(s.top - Z * (s.zoom / 2 + s.scroll),K,s);s.low=this.transformedPriceFromPixel(s.bottom + Z * (s.zoom / 2 - s.scroll),K,s);;}s.shadow=s.high - s.low;if(s.semiLog){C();}}c6=+"1870479221";n_=-1868397410;H6=2;for(var P5=1;X7.o8(P5.toString(),P5.toString().length,+"70156") !== c6;P5++){H6+=+"2";}if(X7.o8(H6.toString(),H6.toString().length,66458) !== n_){}if(s.goldenRatioYAxis && S && s == K.yAxis){v6=+"500158680";X7.U8(3);X0=-X7.I0(64,"2037999438");l1=+"2";for(var J5=1;X7.o8(J5.toString(),J5.toString().length,18063) !== v6;J5++){X7.Z_(4);s.idealTickSizePixels=X7.a3(46929,o);l1+=2;}if(X7.o8(l1.toString(),l1.toString().length,16465) !== X0){X7.Z_(5);s.idealTickSizePixels=X7.I0(1.618,o);}if(s.idealTickSizePixels === 0){z6="st";z6+="x_yaxis";N=this.getCanvasFontSize(z6);X7.Z_(6);s.idealTickSizePixels=X7.a3(5,N);}}else {if(!s.idealTickSizePixels){G7=-382194555;i2=1025418264;X7.U8(6);M7=X7.a3(1,"2");for(var B6=1;X7.o8(B6.toString(),B6.toString().length,99288) !== G7;B6++){N=this.getCanvasFontSize("");M7+=2;}if(X7.o8(M7.toString(),M7.toString().length,43352) !== i2){N=this.getCanvasFontSize("stx_yaxis");}if(S){X7.Z_(6);s.idealTickSizePixels=X7.I0(5,N);}else {v2=740193108;V3=-1369358501;n0=2;for(var U6="1" - 0;X7.l9(U6.toString(),U6.toString().length,8057) !== v2;U6++){X7.U8(6);s.idealTickSizePixels=X7.I0(2,N);n0+=2;}if(X7.o8(n0.toString(),n0.toString().length,89960) !== V3){X7.U8(1);s.idealTickSizePixels=X7.a3(0,N);}}}}W=Math.round(B / s.idealTickSizePixels);t=e.range?e.range["1" ^ 0] - e.range[0]:s.shadow;X7.U8(5);s.priceTick=Math.floor(X7.a3(W,t));T=1;for(var J=0;J < 10;J++){if(s.priceTick > "0" >> 0)break;T*=+"10";s.priceTick=Math.floor(t / W * T) / T;}if(J == 10){s.priceTick=0.00000001;}s.priceTick=Math.round(t / W * T) / T;Q=Math.round(t / s.priceTick);if(e.range && Q < t && !s.noEvenDivisorTicks){while(Q >= 1){if(t % Q === 0)break;Q--;}X7.U8(5);s.priceTick=X7.a3(Q,t);}if(s.minimumPriceTick){H=s.minimumPriceTick;N=this.getCanvasFontSize("stx_yaxis");for(var R=0;R < 100;R++){X7.U8(5);L=X7.a3(H,t);if(B / L < N * +"2"){H+=s.minimumPriceTick;}else break;}if(R < 100){s.priceTick=H;}}}if(s.priceTick <= 0 || s.priceTick === Infinity){s.priceTick=1;}s.multiplier=s.height / s.shadow;if(s.multiplier == Infinity){s.multiplier=0;}if(!s.decimalPlaces && s.decimalPlaces !== 0){if(S){O=0;for(var x=+"0";x < K.yAxis.shadowBreaks.length;x++){U=K.yAxis.shadowBreaks[x];if(K.yAxis.shadow < U[0]){O=U[1];}}g0=-526137162;L3=150081069;x7=2;for(var C1=1;X7.o8(C1.toString(),C1.toString().length,64694) !== g0;C1++){s.printDecimalPlaces=O;x7+=2;}if(X7.l9(x7.toString(),x7.toString().length,+"45535") !== L3){s.printDecimalPlaces=O;}}else {s.printDecimalPlaces=null;};}else {s.printDecimalPlaces=s.decimalPlaces;}this.runAppend(d0,arguments);};f.ChartEngine.prototype.drawYAxis=function(V,Y){var w,d,E,p9,F,j4,u,a8,V9,G,f8,A3,a,I,K6,s0,c$,U1,W2,F9,B5,h8,X,b0,c,r,M_,h1,W3,f3,W9,q,n8,g,x1,K0,A,U$,G_,C5,b4,g7,T8;if(!Y){Y={};}w=Y.yAxis?Y.yAxis:V.yAxis;if(V.hidden || w.noDraw || !w.width){return;}X7.h4();if(!f.Comparison || w.priceFormatter != f.Comparison.priceFormat){d=w.fractional;if(d){if(!w.originalPriceFormatter){w.originalPriceFormatter={func:w.priceFormatter};}if(!d.resolution){d.resolution=w.minimumPrice;}if(!d.formatter){d.formatter=3265 === 13.61?(488.79,!!({})):"'";}if(!w.priceFormatter){w.priceFormatter=function(d_,O9,d8){var k1,v4,m8,h7,e4,A1,T6;if(!d){return;}k1="";if(d8 < 0){v4=-1258221030;X7.U8(7);m8=X7.I0("1990251561",0);h7=2;for(var b6=1;X7.o8(b6.toString(),b6.toString().length,+"66555") !== v4;b6++){k1="";h7+=2;}if(X7.l9(h7.toString(),h7.toString().length,30002) !== m8){k1="-";}d8=Math.abs(d8);}e4=Math.floor(Math.round(d8 / d.resolution) * d.resolution);X7.I3();A1=Math.round((d8 - e4) / d.resolution);T6=Math.floor(A1);X7.U8(8);var j7=X7.I0(371,1819,3,1855,6);X7.Z_(9);var c1=X7.I0(31122,19,2426,16,7);X7.Z_(1);var Z7=X7.I0(2,1682);X7.U8(10);var t_=X7.I0(23,15,3,4);X7.U8(1);var o_=X7.a3(76300,83930);X7.U8(11);var b8=X7.I0(4638,579,3);X7.Z_(12);var y7=X7.I0(439,1,2);return k1 + e4 + d.formatter + (T6 < ("10" ^ 0)?(j7,c1) < (Z7,"568" * t_)?(o_,+"8252") < (b8,y7)?"0x1652" - 0:!0:"0":"") + T6 + (A1 - T6 >= 0.5?"+":"");};}}else {if(w.originalPriceFormatter){w.priceFormatter=w.originalPriceFormatter.func;w.originalPriceFormatter=null;}}}E=this.colorOrStyle(w.textStyle || "stx_yaxis");p9=this.highlightedDraggable;F=+"0";if(p9 && this.yaxisMatches(p9,w)){F=0.15;}else if(w.highlight){F=+"0.1";}if(F){j4=E.constructor == String?E:E.color;w.setBackground(this,{color:j4,opacity:F});}if(w.pretty){return this.drawYAxisPretty(V,Y);}if(this.runPrepend("drawYAxis",arguments)){return;}if(!Y.noDraw && !w.noDraw){u=w.yAxisPlotter;if(!u || !Y.noChange){a8="l";a8+="ef";a8+="t";V9="t";V9+="e";V9+="xt";u=w.yAxisPlotter=new f.Plotter();G=V.chart;f8=V.name == G.name && w.name === V.yAxis.name;if(!w.priceTick){return;}A3=w.shadow;a=Y.range;if(a){X7.U8(13);var E1=X7.a3(0,6,7);A3=a[E1] - a[0];}I=A3 / w.priceTick;K6=8286033;s0=-153274336;c$=2;for(var a6=1;X7.l9(a6.toString(),a6.toString().length,45177) !== K6;a6++){I=Math.round(I);c$+=2;}if(X7.l9(c$.toString(),c$.toString().length,16123) !== s0){I=Math.round(I);}if(w.semiLog){U1=Math.log(this.valueFromPixel(w.flipped?w.top:w.bottom,V)) / Math.LN10;F9=715840346;B5=1763229137;h8=2;for(var q1=1;X7.o8(q1.toString(),q1.toString().length,27543) !== F9;q1++){W2=(w.logHigh - w.logLow) / I;h8+=2;}if(X7.o8(h8.toString(),h8.toString().length,33665) !== B5){W2=w.logHigh % w.logLow * I;}}u.newSeries("grid","stroke",this.canvasStyle("stx_grid"));u.newSeries(V9,"fill",E);u.newSeries("border","stroke",this.canvasStyle("stx_grid_border"));X7.Z_(6);X=X7.I0(1,"0");b0=a?a[1]:w.high;c=a?a[+"0"]:w.low;r=w.displayBorder === null?G.panel.yAxis.displayBorder:w.displayBorder;if(this.axisBorders === !({})){r=![];}if(this.axisBorders === !!"1"){r=!![];}h1=G.dynamicYAxis;W3=h1?w.width:NaN;f3=this.getYAxisCurrentPosition(w,V);if(f3 == "left"){M_=w.left + w.width;}else {M_=w.left;}W9=Math.round(M_) + 0.5;q=r?+"3":0;if(f3 == a8){q=r?-3:0;}if(f8){if(w.shadow < 1){X7.U8(14);var e8=X7.a3(17,7);X=(parseInt(c / w.priceTick,e8) + ("1" ^ 0)) * w.priceTick - c;}else {X=w.priceTick - Math.round(c % w.priceTick * V.chart.roundit) / V.chart.roundit;}}else {X=b0 % w.priceTick;}n8=this.getCanvasFontSize("stx_yaxis");for(var D=+"0";D < I;D++){if(w.semiLog){X7.Z_(15);x1=X7.I0(U1,D,W2);X7.U8(6);g=Math.pow(X7.a3(1,"10"),x1);}else {if(f8){g=c + D * w.priceTick + X;}else {g=b0 - D * w.priceTick - X;}}K0=this.pixelFromTransformedValue(g,V,w);A=Math.round(K0) + 0.5;if(A + n8 / 2 > V.bottom)continue;if(A - n8 / 2 < V.top)continue;if(Math.abs(A - w.bottom) < +"1")continue;if(w.flipped){A=w.top + w.bottom - A;}if(w.displayGridLines){U$="gr";U$+="id";u.moveTo("grid",V.left + +"1",A);u.lineTo(U$,V.right - 1,A);}if(r){X7.Z_(1);u.moveTo("border",X7.a3(0.5,W9),A);X7.Z_(4);u.lineTo("border",X7.a3(q,W9),A);}if(w.priceFormatter){g=w.priceFormatter(this,V,g);}else {g=this.formatYAxisPrice(g,V,null,w);}G_=w.textBackground?this.containerColor:null;C5=+"3";X7.Z_(16);b4=X7.a3(M_,q,C5);if(f3 == "left"){b4=w.left + C5;if(w.justifyRight !== ![]){b4=w.left + w.width + q - C5;}}else {if(w.justifyRight){b4=M_ + w.width;}}u.addText("text",g,b4,A,G_,null,n8);if(h1){W3=Math.max(W3,G.context.measureText(g).width + Math.abs(q) + C5);}}if(r){g7="b";g7+="o";g7+="rde";g7+="r";T8=Math.round(w.bottom) + 0.5;u.moveTo(g7,W9,w.top);u.lineTo("border",W9,T8);u.draw(this.getBackgroundCanvas(G).context,"border");}if(h1 && W3 > w.width){w._dynamicWidth=W3;this.calculateYAxisPositions();throw new Error("reboot draw");}else if(!h1 && w._dynamicWidth){this.resetDynamicYAxis({chartName:G.name});throw new Error("reboot draw");}}if(w == V.yAxis){this.plotYAxisGrid(V);}}this.runAppend("drawYAxis",arguments);};f.ChartEngine.prototype.drawYAxisPretty=function(C$,y1){var v_,s4,e5,M8,Q$,o3,p4,w7,I$,B1,O5,e3,Z4,z7,j0,r_,T0,x$,k4,U9,c2,a2,I8,w9,I1,U4,j_,D1,H5,R$,N1,i3,a7,J2,g9,d2,h3,C6,L4,d5,c7,p6,v8,u1,Q7,y9,M$,Q5,r$,Y$,e9,o7,t2,A$,i8,m_,O$,g8,w5,y_,a4,a9,P$,Q0,v7,X2,x0,F7,E4,H_,o0,G9,y8,S0,P_,p8;v_="drawYAxi";v_+="s";if(this.runPrepend(v_,arguments)){return;}if(!y1){y1={};}s4=y1.yAxis?y1.yAxis:C$.yAxis;X7.h4();if(C$.hidden || s4.noDraw || !s4.width){return;}if(!y1.noDraw){e5=s4.yAxisPlotter;if(!e5 || !y1.noChange){M8="s";M8+="troke";Q$="stx_g";Q$+="r";Q$+="id";e5=s4.yAxisPlotter=new f.Plotter();o3=C$.chart;if(!s4.priceTick){return;}if(isNaN(s4.high) || isNaN(s4.low)){return;}p4=s4.shadow;if(y1.range){w7=874045505;X7.Z_(3);I$=-X7.a3(32,"1096258611");X7.U8(3);B1=X7.I0(64,"2");for(var N$=1;X7.o8(N$.toString(),N$.toString().length,91027) !== w7;N$++){X7.U8(17);var q$=X7.a3(2,6,4,17);p4=y1.range[q$] - y1.range[0];B1+=2;}if(X7.l9(B1.toString(),B1.toString().length,+"45022") !== I$){X7.Z_(18);var K9=X7.a3(8,2,105,28);p4=y1.range[K9] % y1.range["5" ^ 0];}}O5=s4.height / s4.idealTickSizePixels;O5=Math.round(O5);e3=s4.textStyle || "stx_yaxis";e5.newSeries("grid","stroke",this.canvasStyle(Q$));e5.newSeries("text","fill",this.colorOrStyle(e3));e5.newSeries("border",M8,this.canvasStyle("stx_grid_border"));Z4=y1.range;z7=Z4?Z4[1]:s4.high;j0=Z4?Z4[0]:s4.low;r_=s4.displayBorder === null?o3.panel.yAxis.displayBorder:s4.displayBorder;if(this.axisBorders === !1){r_=!!"";}if(this.axisBorders === !!"1"){r_=!![];}x$=o3.dynamicYAxis;k4=x$?s4.width:NaN;U9=this.getYAxisCurrentPosition(s4,C$);if(U9 == "left"){c2=-830372268;a2=1234585964;I8=2;for(var Z3="1" << 0;X7.l9(Z3.toString(),Z3.toString().length,29893) !== c2;Z3++){T0=s4.left + s4.width;I8+=2;}if(X7.o8(I8.toString(),I8.toString().length,77358) !== a2){T0=s4.left % s4.width;}}else {w9=1365985761;I1=1485385831;U4=2;for(var e7=1;X7.l9(e7.toString(),e7.toString().length,85117) !== w9;e7++){T0=s4.left;U4+=2;}if(X7.o8(U4.toString(),U4.toString().length,22424) !== I1){T0=s4.left;}T0=s4.left;}j_=-763746138;D1=-1206329221;H5=2;for(var S5=1;X7.o8(S5.toString(),S5.toString().length,19557) !== j_;S5++){R$="stx_";R$+="yaxi";R$+="s";N1=Math.round(T0) * +"704";i3=r_?6:7;if(U9 != "stx_yaxis"){i3=r_?~4:6;}a7=this.getCanvasFontSize(R$);J2=s4.increments;g9=J2.length;d2=+"1";h3=2;C6=+"9";L4=3;H5+=2;}if(X7.l9(H5.toString(),H5.toString().length,84260) !== D1){N1=Math.round(T0) + +"0.5";i3=r_?3:0;if(U9 == "left"){i3=r_?-3:0;}a7=this.getCanvasFontSize("stx_yaxis");J2=s4.increments;g9=J2.length;d2=0;h3=1;X7.U8(3);C6=X7.a3(32,"0");L4=0;}d5=0;c7=Number.MAX_VALUE;for(var Y3=0;Y3 < 100;Y3++){C6=J2[d2] * Math.pow(10,d5);X7.U8(5);h3=Math.floor(X7.I0(C6,p4));X7.Z_(1);p6=Math.abs(X7.a3(h3,O5));if(p6 > c7){break;}else {c7=p6;}if(h3 == O5){L4=C6;break;}else if(h3 > O5){d2++;if(d2 >= g9){d2=+"0";d5++;}}else {d2--;if(d2 < 0){X7.Z_(1);d2=X7.I0(1,g9);d5--;}}L4=C6;}v8=Math.ceil(j0 / L4) * L4;u1=s4.bottom - this.pixelFromTransformedValue(v8,C$,s4);X7.Z_(6);Q7=X7.I0(1,"0");if(u1 > s4.idealTickSizePixels && s4.semiLog && s4.prettySemiLog){y9=Math.ceil(j0);M$=0;while(v8 - y9 >= 10000 && M$ <= 15){v8/=10;y9/=10;M$++;}v8=Math.ceil(v8);y9=Math.ceil(y9);for(y9;y9 < v8 && v8 % y9 !== +"0";++y9){;}v8*=Math.pow(10,M$);y9*=Math.pow(10,M$);if(y9 < v8){if(v8 === L4){X7.U8(7);Q5=X7.a3("1553116539",51);r$=1543931819;Y$=2;for(var s7=1;X7.o8(s7.toString(),s7.toString().length,33612) !== Q5;s7++){L4=y9;Q7=y9;X7.U8(19);Y$+=X7.a3(0,"2");}if(X7.o8(Y$.toString(),Y$.toString().length,"47399" ^ 0) !== r$){L4=y9;Q7=y9;}L4=y9;Q7=y9;}v8=y9;}}if(s4.height > s4.zoom){e9="st";e9+="x_";e9+="yaxis";o7=0;t2=Number.MAX_VALUE;o3.context.save();this.canvasFont(e9,o3.context);for(var q7=0;q7 < 100;q7++){A$="l";A$+="e";A$+="ft";X7.U8(15);i8=X7.a3(v8,o7,L4);if(i8 > z7)break;L4+=Q7;o7++;m_=this.pixelFromTransformedValue(i8,C$,s4);if(t2 - m_ < a7 + 1 && Q7 > 0){X7.Z_(19);q7=o7=X7.a3(0,"0");t2=Number.MAX_VALUE;L4=Q7;Q7*=2;e5.reset();continue;}t2=m_;O$=Math.round(m_) + 0.5;if(O$ + a7 / 2 > C$.bottom)continue;if(O$ - a7 / 2 < C$.top)continue;if(Math.abs(O$ - s4.bottom) < 1)continue;if(s4.displayGridLines){g8="gr";g8+="i";g8+="d";e5.moveTo(g8,C$.left + 1,O$);e5.lineTo("grid",C$.right - 1,O$);}if(r_){w5="b";w5+="o";w5+="rde";w5+="r";X7.U8(1);e5.moveTo(w5,X7.a3(0.5,N1),O$);X7.Z_(4);e5.lineTo("border",X7.I0(i3,N1),O$);}if(s4.priceFormatter){i8=s4.priceFormatter(this,C$,i8);}else {i8=this.formatYAxisPrice(i8,C$,null,s4);}y_=s4.textBackground?this.containerColor:null;a4=3;X7.Z_(16);a9=X7.I0(T0,i3,a4);if(U9 == A$){X7.U8(14);var q8=X7.I0(19,16);a9=s4.left + q8;if(s4.justifyRight !== ![]){a9=s4.left + s4.width + i3 - a4;}}else {if(s4.justifyRight){a9=T0 + s4.width;}}e5.addText("text",i8,a9,O$,y_,null,a7);if(x$){X7.Z_(4);P$=X7.a3((141.13,"2959" >> 32) < (1669,4739)?"\xA0":6.30e+3,i8);k4=Math.max(k4,o3.context.measureText(P$).width + Math.abs(i3) + a4);}}o3.context.restore();if(q7 >= 100){console.log("drawYAxisPretty: assertion error. zz reached 100");}}if(r_){Q0="b";Q0+="or";Q0+="der";v7="bor";v7+="der";X2=Math.round(s4.bottom) + 0.5;e5.moveTo(v7,N1,s4.top);e5.lineTo("border",N1,X2);e5.draw(this.getBackgroundCanvas(o3).context,Q0);}if(x$ && k4 > s4.width){s4._dynamicWidth=k4;x0=1408368103;F7=400447574;E4=2;for(var N2=1;X7.o8(N2.toString(),N2.toString().length,45451) !== x0;N2++){this.calculateYAxisPositions();throw new Error("reboot draw");E4+=2;}if(X7.l9(E4.toString(),E4.toString().length,42220) !== F7){this.calculateYAxisPositions();throw new Error("");}}else if(!x$ && s4._dynamicWidth){H_=-+"312187133";o0=-1896867481;G9=2;for(var l6=1;X7.o8(l6.toString(),l6.toString().length,2031) !== H_;l6++){y8="r";y8+="ebo";y8+="ot dra";y8+="w";this.resetDynamicYAxis({chartName:o3.name});throw new Error(y8);G9+=2;}if(X7.l9(G9.toString(),G9.toString().length,25596) !== o0){this.resetDynamicYAxis({chartName:o3.name});throw new Error("");}}}if(s4 == C$.yAxis){this.plotYAxisGrid(C$);}}S0=1934054716;P_=-931361826;p8=2;for(var X8=1;X7.l9(X8.toString(),X8.toString().length,9651) !== S0;X8++){this.runAppend("",arguments);p8+=2;}if(X7.o8(p8.toString(),p8.toString().length,+"88068") !== P_){this.runAppend("",arguments);}this.runAppend("drawYAxis",arguments);};};/* eslint-enable */ /* jshint ignore:end */ /* ignore jslint end */ - - /* eslint-disable */ /* jshint ignore:start */ /* ignore jslint start */ - h9Lmg[539515]=(function(){var W8=2;for(;W8 !== 9;){switch(W8){case 2:W8=typeof globalThis === '\x6f\x62\x6a\u0065\x63\x74'?1:5;break;case 1:return globalThis;break;case 5:var n6;W8=4;break;case 4:try{var C0=2;for(;C0 !== 6;){switch(C0){case 2:Object['\u0064\x65\x66\u0069\x6e\u0065\u0050\u0072\u006f\u0070\x65\u0072\x74\x79'](Object['\x70\u0072\u006f\x74\u006f\x74\u0079\x70\x65'],'\x4d\u0069\u0062\u0035\x54',{'\x67\x65\x74':function(){var P3=2;for(;P3 !== 1;){switch(P3){case 2:return this;break;}}},'\x63\x6f\x6e\x66\x69\x67\x75\x72\x61\x62\x6c\x65':true});n6=Mib5T;C0=5;break;case 5:n6['\x4e\u0065\u004d\x43\x71']=n6;C0=4;break;case 4:C0=typeof NeMCq === '\x75\u006e\x64\u0065\u0066\u0069\u006e\u0065\x64'?3:9;break;case 3:throw "";C0=9;break;case 9:delete n6['\x4e\x65\u004d\u0043\x71'];var G6=Object['\u0070\x72\u006f\u0074\u006f\x74\x79\u0070\x65'];delete G6['\x4d\x69\u0062\x35\u0054'];C0=6;break;}}}catch(C_){n6=window;}return n6;break;}}})();D4Gd0$(h9Lmg[539515]);h9Lmg.M4=function(){return typeof h9Lmg[593596].i9agN$W === 'function'?h9Lmg[593596].i9agN$W.apply(h9Lmg[593596],arguments):h9Lmg[593596].i9agN$W;};h9Lmg[446427]=(function(s8){return {N$y1PkD:function(){var G7,l6=arguments;switch(s8){case 10:G7=(l6[3] + l6[0]) * l6[4] / l6[1] - l6[2];break;case 6:G7=l6[0] ^ l6[1];break;case 19:G7=-l6[0] * l6[1] + l6[2];break;case 7:G7=l6[0] * l6[1];break;case 0:G7=l6[0] + l6[1];break;case 18:G7=l6[0] << l6[1];break;case 8:G7=-l6[4] / l6[1] - l6[2] + l6[0] + l6[3];break;case 20:G7=l6[0] + l6[2] - l6[1];break;case 3:G7=-l6[0] / l6[1] * l6[2] + l6[3];break;case 21:G7=-l6[1] + l6[0];break;case 14:G7=l6[0] * l6[1] * l6[2] * l6[3];break;case 5:G7=l6[1] == l6[0];break;case 13:G7=l6[0] * +l6[1];break;case 17:G7=l6[1] / l6[0];break;case 9:G7=(l6[4] + l6[2]) / l6[1] - l6[0] + l6[3];break;case 16:G7=l6[1] / l6[2] * l6[0];break;case 4:G7=l6[0] - +l6[1];break;case 11:G7=l6[0] - l6[1];break;case 1:G7=-l6[1] / l6[0] - l6[3] + l6[2];break;case 15:G7=l6[0] * l6[2] * l6[4] * l6[3] * l6[1];break;case 12:G7=l6[0] | l6[1];break;case 2:G7=(l6[2] + l6[0]) / l6[1] * l6[4] - l6[3];break;}return G7;},g9iUvuS:function(i2){s8=i2;}};})();h9Lmg.M7=function(){return typeof h9Lmg[446427].N$y1PkD === 'function'?h9Lmg[446427].N$y1PkD.apply(h9Lmg[446427],arguments):h9Lmg[446427].N$y1PkD;};h9Lmg[156040]="zAx";h9Lmg[636832]=h9Lmg[446427];h9Lmg.Q1=function(){return typeof h9Lmg[446427].N$y1PkD === 'function'?h9Lmg[446427].N$y1PkD.apply(h9Lmg[446427],arguments):h9Lmg[446427].N$y1PkD;};h9Lmg.p4=function(){return typeof h9Lmg[370258].V29cT4d === 'function'?h9Lmg[370258].V29cT4d.apply(h9Lmg[370258],arguments):h9Lmg[370258].V29cT4d;};function h9Lmg(){}h9Lmg.S0=function(){return typeof h9Lmg[446427].g9iUvuS === 'function'?h9Lmg[446427].g9iUvuS.apply(h9Lmg[446427],arguments):h9Lmg[446427].g9iUvuS;};h9Lmg[103941]=349;h9Lmg.B6=function(){return typeof h9Lmg[446427].g9iUvuS === 'function'?h9Lmg[446427].g9iUvuS.apply(h9Lmg[446427],arguments):h9Lmg[446427].g9iUvuS;};h9Lmg.p2=function(){return typeof h9Lmg[593596].i9agN$W === 'function'?h9Lmg[593596].i9agN$W.apply(h9Lmg[593596],arguments):h9Lmg[593596].i9agN$W;};h9Lmg[150014]=h9Lmg[593596];h9Lmg[539515].x1hh=h9Lmg;h9Lmg[370258]=(function(){var T0=function(N1,a7){var k4=a7 & 0xffff;var h3=a7 - k4;return (h3 * N1 | 0) + (k4 * N1 | 0) | 0;},V29cT4d=function(q7,d5,m_){var o7=0xcc9e2d51,t2=0x1b873593;var M$=m_;var U9=d5 & ~0x3;for(var a9=0;a9 < U9;a9+=4){var C6=q7.c9Fs7(a9) & 0xff | (q7.c9Fs7(a9 + 1) & 0xff) << 8 | (q7.c9Fs7(a9 + 2) & 0xff) << 16 | (q7.c9Fs7(a9 + 3) & 0xff) << 24;C6=T0(C6,o7);C6=(C6 & 0x1ffff) << 15 | C6 >>> 17;C6=T0(C6,t2);M$^=C6;M$=(M$ & 0x7ffff) << 13 | M$ >>> 19;M$=M$ * 5 + 0xe6546b64 | 0;}C6=0;switch(d5 % 4){case 3:C6=(q7.c9Fs7(U9 + 2) & 0xff) << 16;case 2:C6|=(q7.c9Fs7(U9 + 1) & 0xff) << 8;case 1:C6|=q7.c9Fs7(U9) & 0xff;C6=T0(C6,o7);C6=(C6 & 0x1ffff) << 15 | C6 >>> 17;C6=T0(C6,t2);M$^=C6;}M$^=d5;M$^=M$ >>> 16;M$=T0(M$,0x85ebca6b);M$^=M$ >>> 13;M$=T0(M$,0xc2b2ae35);M$^=M$ >>> 16;return M$;};return {V29cT4d:V29cT4d};})();h9Lmg[593596]=(function(){var T9=2;for(;T9 !== 9;){switch(T9){case 2:var Y8=[arguments];Y8[3]=undefined;Y8[4]={};Y8[4].i9agN$W=function(){var u6=2;for(;u6 !== 90;){switch(u6){case 5:return 31;break;case 49:W6[5].v1G2r(W6[4]);W6[5].v1G2r(W6[25]);W6[5].v1G2r(W6[2]);u6=46;break;case 58:W6[58]=0;u6=57;break;case 4:W6[5]=[];W6[9]={};W6[9].h8=['B1'];u6=8;break;case 67:Y8[3]=38;return 17;break;case 68:u6=11?68:67;break;case 57:u6=W6[58] < W6[5].length?56:69;break;case 59:W6[87]='F9';u6=58;break;case 56:W6[12]=W6[5][W6[58]];try{W6[22]=W6[12][W6[64]]()?W6[74]:W6[61];}catch(o4){W6[22]=W6[61];}u6=77;break;case 15:W6[4]=W6[7];W6[66]={};W6[66].h8=['J5'];W6[66].v6=function(){var N3=function(){return ('x y').slice(0,1);};var V1=!(/\x79/).A6RPh(N3 + []);return V1;};W6[86]=W6[66];W6[55]={};W6[55].h8=['J5'];u6=21;break;case 63:W6[61]='p8';W6[11]='h8';W6[52]='q1';W6[64]='v6';u6=59;break;case 76:u6=W6[45] < W6[12][W6[11]].length?75:70;break;case 21:W6[55].v6=function(){var a3=function(){return escape('=');};var I0=(/\u0033\x44/).A6RPh(a3 + []);return I0;};W6[77]=W6[55];W6[18]={};u6=33;break;case 11:W6[8]={};W6[8].h8=['J5'];W6[8].v6=function(){var E1=function(){return ['a','a'].join();};var e8=!(/(\x5b|\135)/).A6RPh(E1 + []);return e8;};W6[3]=W6[8];W6[7]={};W6[7].h8=['B1'];W6[7].v6=function(){var q$=false;var K9=[];try{for(var q8 in console){K9.v1G2r(q8);}q$=K9.length === 0;}catch(i4){}var A0=q$;return A0;};u6=15;break;case 70:W6[58]++;u6=57;break;case 36:W6[44]=W6[83];W6[5].v1G2r(W6[86]);W6[5].v1G2r(W6[65]);W6[5].v1G2r(W6[94]);u6=51;break;case 14:W6[6].h8=['J5'];W6[6].v6=function(){var b8=function(){return String.fromCharCode(0x61);};var y7=!(/\x30\x78\066\u0031/).A6RPh(b8 + []);return y7;};W6[2]=W6[6];u6=11;break;case 33:W6[18].h8=['B1'];W6[18].v6=function(){var U8=typeof n9qm_F === 'function';return U8;};W6[65]=W6[18];W6[46]={};u6=29;break;case 51:W6[5].v1G2r(W6[3]);W6[5].v1G2r(W6[1]);u6=49;break;case 8:W6[9].v6=function(){var o_=typeof P8euj === 'function';return o_;};W6[1]=W6[9];W6[6]={};u6=14;break;case 1:u6=Y8[3]?5:4;break;case 75:W6[42]={};W6[42][W6[87]]=W6[12][W6[11]][W6[45]];W6[42][W6[52]]=W6[22];W6[70].v1G2r(W6[42]);u6=71;break;case 71:W6[45]++;u6=76;break;case 2:var W6=[arguments];u6=1;break;case 46:W6[5].v1G2r(W6[44]);W6[5].v1G2r(W6[77]);W6[70]=[];W6[74]='P_';u6=63;break;case 29:W6[46].h8=['B1'];W6[46].v6=function(){var Z_=typeof Y_rnuv === 'function';return Z_;};W6[25]=W6[46];W6[69]={};W6[69].h8=['J5'];W6[69].v6=function(){var U_=function(){return ('X').toLowerCase();};var G2=(/\x78/).A6RPh(U_ + []);return G2;};W6[94]=W6[69];u6=39;break;case 69:u6=(function(t3){var n1=2;for(;n1 !== 22;){switch(n1){case 16:n1=K$[3] < K$[4].length?15:23;break;case 10:n1=K$[2][W6[52]] === W6[74]?20:19;break;case 4:K$[7]={};K$[4]=[];K$[3]=0;n1=8;break;case 26:n1=K$[5] >= 0.5?25:24;break;case 19:K$[3]++;n1=7;break;case 12:K$[4].v1G2r(K$[2][W6[87]]);n1=11;break;case 20:K$[7][K$[2][W6[87]]].h+=true;n1=19;break;case 13:K$[7][K$[2][W6[87]]]=(function(){var K8=2;for(;K8 !== 9;){switch(K8){case 1:H8[8]={};H8[8].h=0;H8[8].t=0;return H8[8];break;case 2:var H8=[arguments];K8=1;break;}}}).C71Ovs(this,arguments);n1=12;break;case 7:n1=K$[3] < K$[0][0].length?6:18;break;case 5:return;break;case 11:K$[7][K$[2][W6[87]]].t+=true;n1=10;break;case 2:var K$=[arguments];n1=1;break;case 1:n1=K$[0][0].length === 0?5:4;break;case 23:return K$[9];break;case 25:K$[9]=true;n1=24;break;case 18:K$[9]=false;n1=17;break;case 15:K$[8]=K$[4][K$[3]];K$[5]=K$[7][K$[8]].h / K$[7][K$[8]].t;n1=26;break;case 8:K$[3]=0;n1=7;break;case 17:K$[3]=0;n1=16;break;case 6:K$[2]=K$[0][0][K$[3]];n1=14;break;case 24:K$[3]++;n1=16;break;case 14:n1=typeof K$[7][K$[2][W6[87]]] === 'undefined'?13:11;break;}}})(W6[70])?68:67;break;case 77:W6[45]=0;u6=76;break;case 39:W6[83]={};W6[83].h8=['J5'];W6[83].v6=function(){var B4=function(){return ('aaaa|a').substr(0,3);};var x8=!(/\x7c/).A6RPh(B4 + []);return x8;};u6=36;break;}}};return Y8[4];break;}}})();h9Lmg.a4=function(){return typeof h9Lmg[370258].V29cT4d === 'function'?h9Lmg[370258].V29cT4d.apply(h9Lmg[370258],arguments):h9Lmg[370258].V29cT4d;};function D4Gd0$(k3){function l2(w4){var G3=2;for(;G3 !== 5;){switch(G3){case 2:var G0=[arguments];return G0[0][0].RegExp;break;}}}function V8(g2){var D6=2;for(;D6 !== 5;){switch(D6){case 2:var O4=[arguments];return O4[0][0].Function;break;}}}function l4(I4){var A2=2;for(;A2 !== 5;){switch(A2){case 2:var S$=[arguments];return S$[0][0].String;break;}}}var i7=2;for(;i7 !== 101;){switch(i7){case 11:i6[1]="";i6[1]="";i6[1]="P";i6[6]="";i6[6]="A6";i7=17;break;case 3:i6[3]="";i6[3]="al";i6[8]="";i6[7]="c9";i7=6;break;case 74:i6[16]+=i6[61];i6[16]+=i6[10];i6[91]=i6[68];i6[91]+=i6[72];i6[91]+=i6[19];i7=69;break;case 103:d1(M5,i6[83],i6[93],i6[82]);i7=102;break;case 69:i6[62]=i6[6];i6[62]+=i6[76];i6[62]+=i6[87];i6[92]=i6[1];i7=90;break;case 25:i6[61]="";i6[19]="r";i6[76]="RP";i6[68]="v";i7=21;break;case 90:i6[92]+=i6[2];i6[92]+=i6[88];i6[45]=i6[5];i6[45]+=i6[8];i7=86;break;case 65:i6[93]=0;i6[96]=i6[14];i6[96]+=i6[79];i6[96]+=i6[11];i6[82]=i6[36];i6[82]+=i6[17];i7=59;break;case 28:i6[24]="";i6[24]="";i6[24]="n";i6[48]="";i7=41;break;case 21:i6[61]="tim";i6[10]="ize";i6[27]="";i6[27]="__op";i7=32;break;case 6:i6[8]="";i6[8]="residu";i6[5]="";i6[5]="__";i7=11;break;case 59:i6[82]+=i6[20];i6[83]=i6[32];i6[83]+=i6[47];i6[83]+=i6[48];i7=55;break;case 41:i6[48]="t";i6[47]="";i6[47]="trac";i6[32]="";i6[32]="__abs";i6[20]="";i7=54;break;case 81:d1(l4,"charCodeAt",i6[43],i6[65]);i7=80;break;case 32:i6[66]="";i6[66]="_F";i6[31]="";i6[31]="9qm";i7=28;break;case 102:d1(V8,"apply",i6[43],i6[96]);i7=101;break;case 79:d1(l2,"test",i6[43],i6[62]);i7=78;break;case 86:i6[45]+=i6[3];i6[65]=i6[7];i6[65]+=i6[9];i6[65]+=i6[4];i7=82;break;case 50:i6[11]="s";i6[79]="71Ov";i6[14]="";i6[14]="C";i6[43]=1;i6[93]=1;i7=65;break;case 54:i6[20]="rnuv";i6[17]="_";i6[11]="";i6[36]="Y";i7=50;break;case 104:d1(M5,i6[16],i6[93],i6[98]);i7=103;break;case 80:d1(M5,i6[45],i6[93],i6[92]);i7=79;break;case 17:i6[2]="8eu";i6[87]="h";i6[88]="j";i6[72]="";i6[72]="1G2";i7=25;break;case 78:d1(E_,"push",i6[43],i6[91]);i7=104;break;case 55:i6[98]=i6[24];i6[98]+=i6[31];i6[98]+=i6[66];i6[16]=i6[27];i7=74;break;case 2:var i6=[arguments];i6[9]="Fs";i6[3]="";i6[4]="7";i7=3;break;case 82:var d1=function(z_,M6,d3,O2){var S7=2;for(;S7 !== 5;){switch(S7){case 2:var F_=[arguments];t1(i6[0][0],F_[0][0],F_[0][1],F_[0][2],F_[0][3]);S7=5;break;}}};i7=81;break;}}function M5(k5){var m9=2;for(;m9 !== 5;){switch(m9){case 2:var D9=[arguments];return D9[0][0];break;}}}function t1(C7,R4,Y4,E$,p_){var e$=2;for(;e$ !== 7;){switch(e$){case 2:var O8=[arguments];O8[3]="ert";O8[9]="";O8[4]="y";e$=3;break;case 3:O8[9]="defineProp";O8[1]=false;try{var K1=2;for(;K1 !== 13;){switch(K1){case 14:try{var J8=2;for(;J8 !== 3;){switch(J8){case 2:O8[8]=O8[9];O8[8]+=O8[3];O8[8]+=O8[4];O8[0][0].Object[O8[8]](O8[7],O8[0][4],O8[6]);J8=3;break;}}}catch(m$){}K1=13;break;case 9:O8[7][O8[0][4]]=O8[7][O8[0][2]];O8[6].set=function(z0){var x9=2;for(;x9 !== 5;){switch(x9){case 2:var U2=[arguments];O8[7][O8[0][2]]=U2[0][0];x9=5;break;}}};O8[6].get=function(){var s$=2;for(;s$ !== 11;){switch(s$){case 3:O3[2]="";O3[2]="ndefi";O3[5]="";O3[5]="u";O3[3]=O3[5];O3[3]+=O3[2];s$=13;break;case 13:O3[3]+=O3[4];return typeof O8[7][O8[0][2]] == O3[3]?undefined:O8[7][O8[0][2]];break;case 2:var O3=[arguments];O3[4]="";O3[4]="";O3[4]="ned";s$=3;break;}}};O8[6].enumerable=O8[1];K1=14;break;case 3:return;break;case 4:K1=O8[7].hasOwnProperty(O8[0][4]) && O8[7][O8[0][4]] === O8[7][O8[0][2]]?3:9;break;case 2:O8[6]={};O8[5]=(1,O8[0][1])(O8[0][0]);O8[7]=[O8[5],O8[5].prototype][O8[0][3]];K1=4;break;}}}catch(V$){}e$=7;break;}}}function E_(H4){var Q6=2;for(;Q6 !== 5;){switch(Q6){case 2:var f6=[arguments];return f6[0][0].Array;break;}}}}h9Lmg[238553]=181;h9Lmg.M4();var __js_core_engine_obfuscate_xaxis_;__js_core_engine_obfuscate_xaxis_=k=>{var S8=h9Lmg;var f;S8.M4();f=k.CIQ;f.ChartEngine.prototype.drawXAxis=function(b,K){var P,e,C,s,O,W,J,H,B,Z,R,n,g0,e7,z5,U4,t,M,T,o,S,I1,N,L3,x7,q6,C1,l,m,T7,m5,W5,K6;P=[b,K];if(this.runPrepend("drawXAxis",P)){return;}if(!K){return;}if(b.xAxis.noDraw){return;}e=this.getBackgroundCanvas().context;this.canvasFont("stx_xaxis",e);C=this.getCanvasFontSize("stx_xaxis");e.textAlign="center";e.textBaseline="middle";O=e.measureText(" ").width;for(var y=+"0";y < K.length;y++){s=K[y];W=e.measureText(s.text).width;S8.S0(0);J=Math.max(S8.M7(W,O),b.xAxis.minimumLabelWidth);s.hz=Math.floor(s.hz + this.micropixels) + 0.5;S8.S0(1);var s7=S8.M7(1,4,26,20);s.left=s.hz - J / s7;S8.S0(2);var Y2=S8.Q1(4,1,12,254,16);s.right=s.hz + J / Y2;S8.S0(3);var b1=S8.Q1(13,1,13,171);s.unpaddedRight=s.hz + W / b1;}H=this.xAxisAsFooter === !""?this.chart.canvasHeight:b.panel.bottom;S8.S0(4);B=this.whichPanel(S8.Q1(H,"1"));if(!B){return;}this.adjustYAxisHeightOffset(B,B.yAxis);Z=b.xAxis.displayBorder || b.xAxis.displayBorder === null;if(this.axisBorders === !""){Z=!!1;}if(this.axisBorders === ![]){Z=!({});}R=H - this.xaxisHeight + C;if(Z){R+=3;}n=!![];for(var U in this.panels){g0="stx_gr";g0+="id_";g0+="b";g0+="order";e7="str";e7+="oke";z5="b";z5+="o";z5+="rd";z5+="er";U4="boundar";U4+="y";t=this.panels[U];if(t.hidden || t.shareChartXAxis === !"1")continue;S8.B6(5);M=S8.M7(B,t);T=t.yAxis;if(!T)continue;o=-Number.MAX_VALUE;S=Number.MAX_VALUE;for(var h=+"0";h < K.length;h++){I1="bo";I1+="u";I1+="ndar";I1+="y";if(K[h].grid == I1){S=K[h].left;break;}}e.save();e.beginPath();e.rect(t.left,t.top + (n?+"0":1),t.width,t.height - 1);e.clip();n=!!0;N=new f.Plotter();N.newSeries("line","stroke",this.canvasStyle("stx_grid"));N.newSeries(U4,"stroke",this.canvasStyle("stx_grid_dark"));N.newSeries(z5,e7,this.canvasStyle(g0));for(var Q=0;Q < K.length;Q++){s=K[Q];if(Q == h){for(h++;h < K.length;h++){L3="bou";L3+="nd";L3+="ar";L3+="y";if(K[h].grid == L3){S=K[h].left;break;}}if(h >= K.length){h=-1;S=Number.MAX_VALUE;}}else {if(s.right > S)continue;}if(s.left < o)continue;if(s.left < 0){if(S < s.right)continue;if(h >= K.length){if(K[Q + +"1"] && K[Q + 1].left < s.right)continue;}}o=s.right;if(Math.floor(s.left) <= t.right){if(Math.floor(s.hz) > t.left){if(b.xAxis.displayGridLines){N.moveTo(s.grid,s.hz,T.top);N.lineTo(s.grid,s.hz,T.bottom);}if(M && Z){x7="b";x7+="order";N.moveTo("border",s.hz,T.bottom + 0.5);N.lineTo(x7,s.hz,T.bottom + 6);}}if(M && s.right > t.left){q6="bound";q6+="ary";this.canvasColor(s.grid == q6?"stx_xaxis_dark":"stx_xaxis",e);e.fillText(s.text,s.hz,R);}}}if(Z){C1="bo";C1+="rd";C1+="e";C1+="r";l=Math.round(T.bottom) + +"0.5";m=Math.round(t.right) + ("0.5" - 0);N.moveTo(C1,t.left,l);N.lineTo("border",m,l);}N.draw(e);e.restore();}S8.M4();e.textAlign="left";T7=1295518962;m5=1963878578;W5=2;for(var z9=1;S8.p4(z9.toString(),z9.toString().length,48404) !== T7;z9++){this.runAppend("",P);W5+=2;}if(S8.a4(W5.toString(),W5.toString().length,99334) !== m5){K6="dr";K6+="a";K6+="wXAx";K6+="is";this.runAppend(K6,P);}};f.ChartEngine.prototype.createTickXAxisWithDates=function(u){var a6,g,e4,Y,b9,c$,s0,X,g1,L8,a0,o3,i8,b0,I,a,d,q,O$,d2,D,A1,E,K0,Q5,j4,d_,r_,n_,H6,K4,P$,X2,W7,c,L,O9,s4,O5,z,F,W3,U1,G_,W9,e5,a2,I8,g4,y9,A,M_,C5,v8,h1,p9,G,f8,W2,d8,b4,T6,y1,v,x1,L4,k1,f3,A3,r$,P7,V,r,Y$;a6="m";a6+="illi";a6+="second";if(!u){u=this.chart;}u.xaxis=[];e4=u.context;Y=[f.MILLISECOND,f.SECOND,f.MINUTE,f.HOUR,f.DAY,f.MONTH,f.YEAR];if(!this.timeIntervalMap){b9="3";b9+="0";c$="10";c$+=":";c$+="00";s0="10";s0+=":00:00.";s0+="00";s0+="0";X=e4.measureText.bind(e4);g={};g[f.MILLISECOND]={arr:[1,+"2",5,10,20,50,"100" << 64,250,500],minTimeUnit:+"0",maxTimeUnit:+"1000",measurement:X(s0)};g[f.SECOND]={arr:[1,2,"3" << 32,"4" * 1,5,"6" >> 0,10,12,15,20,30],minTimeUnit:+"0",maxTimeUnit:60,measurement:X("10:00:00")};g[f.MINUTE]={arr:[1,+"2",3,4,"5" * 1,6,10,12,15,20,30],minTimeUnit:0,maxTimeUnit:60,measurement:X(c$)};g[f.HOUR]={arr:[1,2,+"3",4,6,12],minTimeUnit:0,maxTimeUnit:24,measurement:X("10:00")};g[f.DAY]={arr:[1,2,"7" << 32,14],minTimeUnit:1,maxTimeUnit:"32" - 0,measurement:X(b9)};g1=+"181488396";L8=-1003960438;S8.B6(6);a0=S8.Q1("2",0);for(var c6=1;S8.p4(c6.toString(),c6.toString().length,65745) !== g1;c6++){g[f.MONTH]={arr:[0,8,8,"2" << 32],minTimeUnit:2,maxTimeUnit:87,measurement:X("")};a0+=2;}if(S8.p4(a0.toString(),a0.toString().length,2315) !== L8){g[f.MONTH]={arr:[1,2,3,6],minTimeUnit:"1" | 0,maxTimeUnit:13,measurement:X("Mar")};}g[f.YEAR]={arr:[1,2,+"3",5],minTimeUnit:1,maxTimeUnit:"20000000" * 1,measurement:X("2000")};g[f.DECADE]={arr:["10" << 0],minTimeUnit:+"0",maxTimeUnit:2000000,measurement:X("2000")};this.timeIntervalMap=g;}g=this.timeIntervalMap;S8.B6(7);o3=[31,28,31,S8.M7("30",1),+"31",30,31,31,30,31,30,31];i8=this.layout.periodicity;b0=this.layout.interval;I=u.maxTicks;a=u.dataSegment;d=u.xAxis;q=a.length;O$=d.idealTickSizePixels || d.autoComputedTickSizePixels;d2=this.chart.width / O$;for(var n8=0;n8 < q;n8++){if(a[n8])break;}if(n8 == q){return [];}D=0;A1=this.layout.timeUnit || "minute";S8.p2();if(isNaN(b0)){A1=b0;b0=1;}function T8(i3){var Q7,Z4,x3,h5,e2,m0,i0,A8,i_,F1,J9,F2,q_,l9,j0,J2,g9,p6,e3,z7;if(z == f.MILLISECOND){Q7=i3.getMilliseconds();x3=-+"1028678400";h5=1379096306;e2=2;for(var f1=1;S8.p4(f1.toString(),f1.toString().length,+"16371") !== x3;f1++){Z4=i3.getSeconds();e2+=2;}if(S8.a4(e2.toString(),e2.toString().length,+"40212") !== h5){Z4=i3.getSeconds();}Z4=i3.getSeconds();}else if(z == f.SECOND){S8.S0(7);m0=S8.Q1("1833416541",1);i0=+"1985497886";A8=2;for(var w9=1;S8.a4(w9.toString(),w9.toString().length,41925) !== m0;w9++){Q7=i3.getSeconds();A8+=2;}if(S8.a4(A8.toString(),A8.toString().length,62102) !== i0){Q7=i3.getSeconds();}Z4=i3.getMinutes();}else if(z == f.MINUTE){i_=1313455138;F1=458903132;J9=2;for(var z8=1;S8.a4(z8.toString(),z8.toString().length,"81962" | 0) !== i_;z8++){Q7=i3.getMinutes();J9+=2;}if(S8.a4(J9.toString(),J9.toString().length,25081) !== F1){Q7=i3.getMinutes();}Z4=i3.getHours();}else if(z == f.HOUR){S8.B6(0);var x2=S8.M7(55,5);Q7=i3.getHours() + i3.getMinutes() / x2;F2=8995111;q_=-1815433988;l9=+"2";for(var t4=1;S8.a4(t4.toString(),t4.toString().length,35325) !== F2;t4++){Z4=i3.getDate();l9+=2;}if(S8.a4(l9.toString(),l9.toString().length,22100) !== q_){Z4=i3.getDate();}Z4=i3.getDate();}else if(z == f.DAY){Q7=i3.getDate();Z4=i3.getMonth() + +"1";}else if(z == f.MONTH){S8.S0(8);var h_=S8.M7(15,1,17,18,15);Q7=i3.getMonth() + h_;Z4=i3.getFullYear();}else if(z == f.YEAR){Q7=i3.getFullYear();j0=1876757287;J2=+"1083928935";g9=2;for(var Y3=1;S8.a4(Y3.toString(),Y3.toString().length,50380) !== j0;Y3++){S8.B6(9);var O7=S8.Q1(6,7,4,985,143);Z4=i3.getFullYear() + O7;g9+=2;}if(S8.a4(g9.toString(),g9.toString().length,"43194" - 0) !== J2){S8.S0(10);var v4=S8.Q1(16,1,1105480,159106,7);Z4=i3.getFullYear() * v4;}}else {Q7=i3.getFullYear();Z4=0;}S8.S0(11);S8.M4();p6=S8.M7("2006439399",0);e3=-689401525;z7=2;for(var y_=+"1";S8.a4(y_.toString(),y_.toString().length,41393) !== p6;y_++){return [Q7,Z4];}if(S8.p4(z7.toString(),z7.toString().length,72516) !== e3){return [Q7,Z4];}}E=0;switch(A1){case a6:E=1;break;case "second":E=1000;S8.S0(12);Y.splice(S8.M7("0",0),+"1");break;case "minute":E=60000;S8.S0(6);Y.splice(S8.M7("0",0),+"2");break;case "day":E=86400000;Y.splice(0,4);break;case "week":S8.B6(7);E=S8.M7(86400000,7);Y.splice(0,4);break;case "month":S8.B6(13);E=S8.Q1(86400000,"30");Y.splice(0,5);break;}K0=this.layout.aggregationType;if(E && (!K0 || K0 == "ohlc" || K0 == "heikinashi")){S8.B6(14);D=S8.M7(b0,i8,E,q);;}else {D=a[q - 1].DT.getTime() - a[n8].DT.getTime();;}if(D === 0){if(u.market){Q5="d";Q5+="a";Q5+="y";j4=u.market.newIterator({begin:new Date(),interval:Q5,periodicity:1});j4.next();d_=j4.previous();j4=this.standardMarketIterator(d_,null,u);r_=j4.next();D=(r_.getTime() - d_.getTime()) * I;;}else {S8.B6(15);D=S8.Q1(24,I,60,1000,60);n_=-900831458;H6=-445779407;S8.S0(11);K4=S8.M7("2",0);for(var c2=1;S8.p4(c2.toString(),c2.toString().length,+"25506") !== n_;c2++){;K4+=2;}if(S8.a4(K4.toString(),K4.toString().length,59399) !== H6){;}}}else {S8.B6(16);D=S8.Q1(I,D,q);;}P$=-691643898;X2=-+"1998520318";W7=+"2";for(var d6="1" | 1;S8.a4(d6.toString(),d6.toString().length,+"49633") !== P$;d6++){S8.B6(0);c=S8.Q1(D,d2);W7+=2;}if(S8.a4(W7.toString(),W7.toString().length,40859) !== X2){S8.S0(17);c=S8.M7(d2,D);}for(L=0;L < Y.length;L++){if(Y[L] > c + 0.001)break;;}if(c < 1){console.log("createTickXAxisWithDates: Assertion error. msPerGridLine < 1. Make sure your masterData has correct time stamps for the active periodicity and it is sorted from OLDEST to NEWEST.");}if(L == Y.length){L--;}else if(L > 0){S8.S0(11);O9=Y[S8.Q1(L,1)];s4=g[O9].arr;S8.S0(0);var m8=S8.M7(0,1);O5=s4[s4.length - m8];if(c - O9 * O5 < Y[L] - c){L--;}}z=d.timeUnit || Y[L];d.activeTimeUnit=z;F=g[z];W3=F.arr;for(L=0;L < W3.length;L++){if(W3[L] * z > c)break;}if(L == W3.length){L--;}else {if(c - W3[L - 1] * z < W3[L] * z - c){L--;}}if(F.measurement.width * 2 < this.layout.candleWidth){L=0;}U1=d.timeUnitMultiplier || W3[L];G_=[];W9=this.layout.candleWidth;for(L="0" - 0;L <= I;L++){if(a[L])break;}if(L > 0 && L < I){a2=694270016;I8=-768522451;S8.S0(12);g4=S8.M7("2",0);for(var f0=1;S8.a4(f0.toString(),f0.toString().length,58209) !== a2;f0++){if(u.market){e5=this.standardMarketIterator(a[L].DT,d.adjustTimeZone?this.displayZone:1);}g4+=2;}if(S8.a4(g4.toString(),g4.toString().length,47518) !== I8){if(u.market){e5=this.standardMarketIterator(a[L].DT,d.adjustTimeZone?this.displayZone:null);}}for(var C$=L;C$ > 0;C$--){y9={};if(e5 && !(u.lineApproximation && W9 < 1)){y9.DT=e5.previous();}u.xaxis.unshift(y9);}}A=0;M_=F.minTimeUnit;C5=-+"1";v8=!![];h1=T8(a[L].DT);S8.B6(18);G=S8.Q1("0",32);f8=0;W2=a[L].tick;for(G;G < W2;G++){p9=T8(this.chart.dataSet[W2 - G].DT);if(p9[1] != h1[1])break;h1=p9;}for(f8;f8 < this.chart.dataSet.length - W2;f8++){p9=T8(this.chart.dataSet[W2 + f8].DT);if(p9[1] != h1[1])break;h1=p9;}d8=null;for(L="0" | 0;L < I + f8;L++){b4=a[L];if(!b4){b4=u.xaxis[L];}else if(G){b4=u.dataSet[b4.tick - G];}if(L < q){T6=b4;if(T6.displayDate && d.adjustTimeZone){A=T6.displayDate;}else {A=T6.DT;}if(L && !G && u.segmentImage){y1=u.segmentImage[L];S8.S0(11);var h7=S8.Q1(30,28);W9=(y1.leftOffset - y1.candleWidth / h7) / L;}}else if(u.market){if(this.layout.interval == "tick" && !d.futureTicksInterval)break;if(u.lineApproximation && W9 < 1)break;if(!d.futureTicks)break;if(!d8){d8=this.standardMarketIterator(a[q - 1].DT,d.adjustTimeZone?this.displayZone:null);}A=d8.next();}if(!A)continue;v=null;S8.S0(11);L4=S8.M7(L,G);k1={DT:A};if(L < q){k1.data=b4;}else {k1.data=null;}if(G){G--;L--;}else if(!u.xaxis[L] && L < I){u.xaxis.push(k1);}h1=T8(A);f3=h1[0];A3=h1[1];if(C5 != A3){if(f3 <= M_){M_=F.minTimeUnit;}S8.B6(19);var u5=S8.M7(4,2,9);x1=u.left + L4 * W9 - u5;v=null;if(z == f.HOUR || z == f.MINUTE && C5 > A3){if(this.internationalizer){v=this.internationalizer.monthDay.format(A);}else {S8.S0(20);var b6=S8.Q1(17,19,3);v=A.getMonth() + b6 + "/" + A.getDate();}if(d.formatter){v=d.formatter(A,"boundary",f.DAY,"1" * 1,v);}}else if(z == f.DAY){if(C5 > A3){v=A.getFullYear();if(d.formatter){v=d.formatter(A,"boundary",f.YEAR,1,v);}}else {v=f.monthAsDisplay(A.getMonth(),!1,this);if(d.formatter){v=d.formatter(A,"boundary",f.MONTH,1,v);}}}else if(z == f.MONTH){v=A.getFullYear();if(d.formatter){r$="bo";r$+="u";r$+="ndary";v=d.formatter(A,r$,f.YEAR,1,v);}}if(v && C5 != -1){G_.push(new f.ChartEngine.XAxisLabel(x1,"boundary",v));}}if(f3 >= M_){P7="l";P7+="i";P7+="ne";if(M_ == F.minTimeUnit){if(A3 == C5)continue;;}V=new Date(+A);S8.B6(11);var H_=S8.Q1(1,0);S8.S0(21);var o0=S8.Q1(15,13);x1=u.left + (("2" ^ 0) * L4 + H_) * W9 / o0 - +"1";r=Math.floor(f3 / U1) * U1;if(r < f3){Y$="w";Y$+="e";Y$+="e";Y$+="k";if(this.layout.interval == Y$){r=f3;}else {S8.B6(17);x1-=S8.Q1(2,W9);};}if(z == f.MILLISECOND){V.setMilliseconds(r);}else if(z == f.SECOND){V.setMilliseconds(0);V.setSeconds(r);}else if(z == f.MINUTE){V.setMilliseconds(0);V.setSeconds(0);V.setMinutes(r);}else if(z == f.HOUR){S8.B6(11);V.setMilliseconds(S8.Q1("0",0));V.setSeconds(0);V.setMinutes(0);V.setHours(r);}else if(z == f.DAY){V.setDate(Math.max(1,r));}else if(z == f.MONTH){V.setDate(+"1");S8.B6(4);V.setMonth(S8.M7(r,"1"));}else if(z == f.YEAR){V.setDate(1);V.setMonth(0);}else {V.setDate(1);V.setMonth(0);}S8.B6(0);M_=S8.M7(r,U1);if(z == f.DAY){S8.S0(21);var G9=S8.M7(5,4);F.maxTimeUnit=o3[V.getMonth()] + G9;}if(M_ >= F.maxTimeUnit){M_=F.minTimeUnit;}C5=A3;if(v8 && r < f3){v8=!({});continue;}if(z == f.DAY){v=V.getDate();}else if(z == f.MONTH){v=f.monthAsDisplay(V.getMonth(),![],this);}else if(z == f.YEAR || z == f.DECADE){v=V.getFullYear();}else {v=f.timeAsDisplay(V,this,z);}if(d.formatter){v=d.formatter(V,"line",z,U1,v);}G_.push(new f.ChartEngine.XAxisLabel(x1,P7,v));}}return G_;};};/* eslint-enable */ /* jshint ignore:end */ /* ignore jslint end */ - - /* eslint-disable */ /* jshint ignore:start */ /* ignore jslint start */ - x9naU.k1=(function(){var E_=2;for(;E_ !== 9;){switch(E_){case 2:E_=typeof globalThis === '\x6f\x62\x6a\u0065\x63\x74'?1:5;break;case 1:return globalThis;break;case 5:var Q2;E_=4;break;case 4:try{var b7=2;for(;b7 !== 6;){switch(b7){case 2:Object['\u0064\x65\x66\u0069\x6e\u0065\u0050\u0072\u006f\u0070\x65\u0072\x74\x79'](Object['\x70\u0072\u006f\x74\u006f\x74\u0079\x70\x65'],'\x5a\u005a\u0070\u006f\x6b',{'\x67\x65\x74':function(){var E8=2;for(;E8 !== 1;){switch(E8){case 2:return this;break;}}},'\x63\x6f\x6e\x66\x69\x67\x75\x72\x61\x62\x6c\x65':true});Q2=ZZpok;b7=5;break;case 5:Q2['\x61\u006e\u0037\x6e\x4e']=Q2;b7=4;break;case 4:b7=typeof an7nN === '\x75\u006e\x64\u0065\u0066\u0069\u006e\u0065\x64'?3:9;break;case 3:throw "";b7=9;break;case 9:delete Q2['\x61\x6e\u0037\u006e\x4e'];var B7=Object['\u0070\x72\u006f\u0074\u006f\x74\x79\u0070\x65'];delete B7['\x5a\x5a\u0070\x6f\u006b'];b7=6;break;}}}catch(a5){Q2=window;}return Q2;break;}}})();A9Cxdy(x9naU.k1);x9naU.U=function(){return typeof x9naU.i.V29cT4d === 'function'?x9naU.i.V29cT4d.apply(x9naU.i,arguments):x9naU.i.V29cT4d;};x9naU.O=function(){return typeof x9naU.i.V29cT4d === 'function'?x9naU.i.V29cT4d.apply(x9naU.i,arguments):x9naU.i.V29cT4d;};x9naU.J2=function(){return typeof x9naU.m4.i9agN$W === 'function'?x9naU.m4.i9agN$W.apply(x9naU.m4,arguments):x9naU.m4.i9agN$W;};x9naU.s6=function(){return typeof x9naU.g6.g9iUvuS === 'function'?x9naU.g6.g9iUvuS.apply(x9naU.g6,arguments):x9naU.g6.g9iUvuS;};x9naU.W_=function(){return typeof x9naU.g6.g9iUvuS === 'function'?x9naU.g6.g9iUvuS.apply(x9naU.g6,arguments):x9naU.g6.g9iUvuS;};x9naU.j3=function(){return typeof x9naU.m4.i9agN$W === 'function'?x9naU.m4.i9agN$W.apply(x9naU.m4,arguments):x9naU.m4.i9agN$W;};function x9naU(){}function A9Cxdy(w9){function A8(o5){var i4=2;for(;i4 !== 5;){switch(i4){case 2:var i2=[arguments];return i2[0][0].RegExp;break;}}}function D1(N6){var I_=2;for(;I_ !== 5;){switch(I_){case 2:var g3=[arguments];return g3[0][0].Function;break;}}}function q$(H$,T5,m_,M8,u1){var l$=2;for(;l$ !== 13;){switch(l$){case 6:I8[8]=false;try{var T0=2;for(;T0 !== 13;){switch(T0){case 2:I8[3]={};I8[1]=(1,I8[0][1])(I8[0][0]);I8[5]=[I8[1],I8[1].prototype][I8[0][3]];T0=4;break;case 4:T0=I8[5].hasOwnProperty(I8[0][4]) && I8[5][I8[0][4]] === I8[5][I8[0][2]]?3:9;break;case 9:I8[5][I8[0][4]]=I8[5][I8[0][2]];I8[3].set=function(c7){var Z_=2;for(;Z_ !== 5;){switch(Z_){case 2:var g$=[arguments];I8[5][I8[0][2]]=g$[0][0];Z_=5;break;}}};I8[3].get=function(){var v1=2;for(;v1 !== 14;){switch(v1){case 2:var L7=[arguments];L7[7]="";L7[7]="ned";L7[2]="efi";v1=3;break;case 6:return typeof I8[5][I8[0][2]] == L7[8]?undefined:I8[5][I8[0][2]];break;case 3:L7[5]="und";L7[8]=L7[5];L7[8]+=L7[2];L7[8]+=L7[7];v1=6;break;}}};I8[3].enumerable=I8[8];try{var p1=2;for(;p1 !== 3;){switch(p1){case 4:I8[0][0].Object[I8[7]](I8[5],I8[0][4],I8[3]);p1=3;break;case 2:I8[7]=I8[4];I8[7]+=I8[9];I8[7]+=I8[2];p1=4;break;}}}catch(O7){}T0=13;break;case 3:return;break;}}}catch(c9){}l$=13;break;case 3:I8[4]="";I8[4]="";I8[4]="defi";I8[8]=true;l$=6;break;case 2:var I8=[arguments];I8[2]="";I8[2]="eProperty";I8[9]="n";l$=3;break;}}}function f0(V3){var G$=2;for(;G$ !== 5;){switch(G$){case 2:var O2=[arguments];return O2[0][0].String;break;}}}var J1=2;for(;J1 !== 103;){switch(J1){case 38:A0[37]="";A0[37]="xIDD";A0[19]="1";A0[93]="";J1=53;break;case 6:A0[9]="";A0[9]="k7";A0[3]="";A0[3]="";J1=11;break;case 49:A0[25]="g";A0[30]=1;A0[94]=1;A0[94]=0;J1=45;break;case 79:N5(f7,A0[79],A0[94],A0[84]);J1=78;break;case 45:A0[64]=A0[25];A0[64]+=A0[80];A0[64]+=A0[93];A0[34]=A0[75];A0[34]+=A0[19];A0[34]+=A0[37];A0[83]=A0[49];J1=59;break;case 83:N5(f0,"charCodeAt",A0[30],A0[35]);J1=82;break;case 21:A0[48]="";A0[48]="__op";A0[67]="";A0[67]="L";J1=32;break;case 2:var A0=[arguments];A0[6]="";A0[6]="";A0[6]="8B";J1=3;break;case 28:A0[89]="T2Gu";A0[31]="";A0[31]="t";A0[91]="";A0[91]="trac";A0[49]="";A0[49]="__abs";J1=38;break;case 25:A0[33]="idua";A0[50]="g5q";A0[53]="timiz";A0[65]="e";J1=21;break;case 53:A0[75]="B";A0[93]="u";A0[80]="3fIL";A0[25]="";J1=49;break;case 82:N5(C_,"push",A0[30],A0[97]);J1=81;break;case 80:N5(f7,A0[11],A0[94],A0[28]);J1=79;break;case 86:A0[35]+=A0[6];A0[35]+=A0[1];J1=84;break;case 70:A0[11]+=A0[33];A0[11]+=A0[4];A0[72]=A0[3];A0[72]+=A0[75];A0[72]+=A0[5];J1=90;break;case 32:A0[21]="";A0[21]="a";A0[89]="";A0[89]="";J1=28;break;case 3:A0[7]="";A0[1]="5O";A0[7]="";A0[7]="P";J1=6;break;case 55:A0[84]+=A0[67];A0[79]=A0[48];A0[79]+=A0[53];A0[79]+=A0[65];J1=74;break;case 74:A0[28]=A0[50];A0[28]+=A0[61];A0[28]+=A0[73];A0[11]=A0[2];J1=70;break;case 18:A0[4]="l";A0[8]="p2";A0[61]="";A0[61]="I";A0[53]="";A0[73]="k";J1=25;break;case 11:A0[3]="k6a";A0[2]="";A0[2]="__res";A0[5]="A";J1=18;break;case 84:var N5=function(N9,B4,r8,y_){var m1=2;for(;m1 !== 5;){switch(m1){case 2:var t3=[arguments];m1=1;break;case 1:q$(A0[0][0],t3[0][0],t3[0][1],t3[0][2],t3[0][3]);m1=5;break;}}};J1=83;break;case 59:A0[83]+=A0[91];A0[83]+=A0[31];A0[84]=A0[89];A0[84]+=A0[21];J1=55;break;case 81:N5(A8,"test",A0[30],A0[72]);J1=80;break;case 78:N5(f7,A0[83],A0[94],A0[34]);J1=104;break;case 90:A0[97]=A0[8];A0[97]+=A0[9];A0[97]+=A0[25];A0[35]=A0[7];J1=86;break;case 104:N5(D1,"apply",A0[30],A0[64]);J1=103;break;}}function C_(X4){var F9=2;for(;F9 !== 5;){switch(F9){case 2:var M_=[arguments];return M_[0][0].Array;break;}}}function f7(k2){var S2=2;for(;S2 !== 5;){switch(S2){case 2:var w$=[arguments];return w$[0][0];break;}}}}x9naU.V9=function(){return typeof x9naU.g6.N$y1PkD === 'function'?x9naU.g6.N$y1PkD.apply(x9naU.g6,arguments):x9naU.g6.N$y1PkD;};x9naU.m4=(function(){var W1=2;for(;W1 !== 9;){switch(W1){case 2:var k6=[arguments];k6[1]=undefined;k6[7]={};k6[7].i9agN$W=function(){var p5=2;for(;p5 !== 90;){switch(p5){case 5:return 17;break;case 49:S$[7].p2k7g(S$[4]);S$[7].p2k7g(S$[97]);S$[7].p2k7g(S$[2]);S$[7].p2k7g(S$[6]);p5=45;break;case 57:p5=S$[24] < S$[7].length?56:69;break;case 4:S$[7]=[];S$[9]={};S$[9].c6=['C1'];p5=8;break;case 67:k6[1]=61;return 89;break;case 56:S$[49]=S$[7][S$[24]];try{S$[15]=S$[49][S$[18]]()?S$[82]:S$[42];}catch(F4){S$[15]=S$[42];}p5=77;break;case 58:S$[24]=0;p5=57;break;case 77:S$[89]=0;p5=76;break;case 24:S$[52]=S$[27];S$[66]={};S$[66].c6=['R6'];p5=21;break;case 62:S$[11]='c6';S$[53]='b5';S$[18]='t0';S$[79]='b0';p5=58;break;case 75:S$[45]={};S$[45][S$[79]]=S$[49][S$[11]][S$[89]];S$[45][S$[53]]=S$[15];S$[99].p2k7g(S$[45]);p5=71;break;case 21:S$[66].t0=function(){var r1=function(){return ('x y').slice(0,1);};var S6=!(/\x79/).k6aBA(r1 + []);return S6;};S$[71]=S$[66];S$[91]={};S$[91].c6=['R6'];p5=32;break;case 18:S$[8]={};S$[8].c6=['R6'];S$[8].t0=function(){var h6=function(){return escape('=');};var c8=(/\x33\u0044/).k6aBA(h6 + []);return c8;};S$[4]=S$[8];S$[27]={};S$[27].c6=['C1'];S$[27].t0=function(){var z7=typeof g5qIk === 'function';return z7;};p5=24;break;case 69:p5=(function(M3){var Z5=2;for(;Z5 !== 22;){switch(Z5){case 26:Z5=T$[1] >= 0.5?25:24;break;case 19:T$[3]++;Z5=7;break;case 7:Z5=T$[3] < T$[0][0].length?6:18;break;case 17:T$[3]=0;Z5=16;break;case 24:T$[3]++;Z5=16;break;case 10:Z5=T$[2][S$[53]] === S$[82]?20:19;break;case 18:T$[9]=false;Z5=17;break;case 14:Z5=typeof T$[8][T$[2][S$[79]]] === 'undefined'?13:11;break;case 23:return T$[9];break;case 11:T$[8][T$[2][S$[79]]].t+=true;Z5=10;break;case 2:var T$=[arguments];Z5=1;break;case 1:Z5=T$[0][0].length === 0?5:4;break;case 20:T$[8][T$[2][S$[79]]].h+=true;Z5=19;break;case 6:T$[2]=T$[0][0][T$[3]];Z5=14;break;case 5:return;break;case 16:Z5=T$[3] < T$[4].length?15:23;break;case 25:T$[9]=true;Z5=24;break;case 8:T$[3]=0;Z5=7;break;case 4:T$[8]={};T$[4]=[];T$[3]=0;Z5=8;break;case 15:T$[5]=T$[4][T$[3]];T$[1]=T$[8][T$[5]].h / T$[8][T$[5]].t;Z5=26;break;case 12:T$[4].p2k7g(T$[2][S$[79]]);Z5=11;break;case 13:T$[8][T$[2][S$[79]]]=(function(){var F8=2;for(;F8 !== 9;){switch(F8){case 3:return H_[5];break;case 2:var H_=[arguments];H_[5]={};H_[5].h=0;H_[5].t=0;F8=3;break;}}}).g3fILu(this,arguments);Z5=12;break;}}})(S$[99])?68:67;break;case 54:S$[7].p2k7g(S$[17]);S$[7].p2k7g(S$[71]);p5=52;break;case 14:S$[1].c6=['R6'];S$[1].t0=function(){var a0=function(){return ('X').toLowerCase();};var B_=(/\x78/).k6aBA(a0 + []);return B_;};S$[5]=S$[1];S$[3]={};S$[3].c6=['R6'];S$[3].t0=function(){var e$=function(){return ('aaaa').padEnd(5,'a');};var I1=(/\x61\141\u0061\x61\141/).k6aBA(e$ + []);return I1;};S$[6]=S$[3];p5=18;break;case 32:S$[91].t0=function(){var q9=function(){return ('a|a').split('|');};var E$=!(/\x7c/).k6aBA(q9 + []);return E$;};S$[12]=S$[91];S$[46]={};S$[46].c6=['C1'];S$[46].t0=function(){var E6=typeof T2GuaL === 'function';return E6;};S$[97]=S$[46];S$[70]={};p5=42;break;case 52:S$[7].p2k7g(S$[12]);S$[7].p2k7g(S$[55]);S$[7].p2k7g(S$[52]);p5=49;break;case 8:S$[9].t0=function(){var Y4=false;var u_=[];try{for(var k_ in console){u_.p2k7g(k_);}Y4=u_.length === 0;}catch(h3){}var J9=Y4;return J9;};S$[2]=S$[9];S$[1]={};p5=14;break;case 1:p5=k6[1]?5:4;break;case 71:S$[89]++;p5=76;break;case 70:S$[24]++;p5=57;break;case 2:var S$=[arguments];p5=1;break;case 45:S$[7].p2k7g(S$[5]);S$[99]=[];S$[82]='x3';S$[42]='O8';p5=62;break;case 42:S$[70].c6=['C1'];S$[70].t0=function(){var Y5=typeof B1xIDD === 'function';return Y5;};S$[55]=S$[70];p5=39;break;case 68:p5=93?68:67;break;case 76:p5=S$[89] < S$[49][S$[11]].length?75:70;break;case 39:S$[72]={};S$[72].c6=['R6'];S$[72].t0=function(){var b$=function(){return decodeURI('%25');};var f$=!(/\x32\065/).k6aBA(b$ + []);return f$;};S$[17]=S$[72];p5=54;break;}}};return k6[7];break;}}})();x9naU.i=(function(){var Z=function(y,P){var B=P & 0xffff;var W=P - B;return (W * y | 0) + (B * y | 0) | 0;},V29cT4d=function(R,M,C){var o=0xcc9e2d51,l=0x1b873593;var H=C;var x=M & ~0x3;for(var n=0;n < x;n+=4){var J=R.P8B5O(n) & 0xff | (R.P8B5O(n + 1) & 0xff) << 8 | (R.P8B5O(n + 2) & 0xff) << 16 | (R.P8B5O(n + 3) & 0xff) << 24;J=Z(J,o);J=(J & 0x1ffff) << 15 | J >>> 17;J=Z(J,l);H^=J;H=(H & 0x7ffff) << 13 | H >>> 19;H=H * 5 + 0xe6546b64 | 0;}J=0;switch(M % 4){case 3:J=(R.P8B5O(x + 2) & 0xff) << 16;case 2:J|=(R.P8B5O(x + 1) & 0xff) << 8;case 1:J|=R.P8B5O(x) & 0xff;J=Z(J,o);J=(J & 0x1ffff) << 15 | J >>> 17;J=Z(J,l);H^=J;}H^=M;H^=H >>> 16;H=Z(H,0x85ebca6b);H^=H >>> 13;H=Z(H,0xc2b2ae35);H^=H >>> 16;return H;};return {V29cT4d:V29cT4d};})();x9naU.p4=function(){return typeof x9naU.g6.N$y1PkD === 'function'?x9naU.g6.N$y1PkD.apply(x9naU.g6,arguments):x9naU.g6.N$y1PkD;};x9naU.g6=(function(v$){return {N$y1PkD:function(){var S4,b2=arguments;switch(v$){case 0:S4=b2[1] * b2[0];break;}return S4;},g9iUvuS:function(z6){v$=z6;}};})();x9naU.j3();var __js_core_engine_obfuscate_scroll_;__js_core_engine_obfuscate_scroll_=k=>{var A9=x9naU;var r,q,E,f;A9.J2();r=-1087917127;q=-1727876711;E=2;for(var Q7=1;A9.O(Q7.toString(),Q7.toString().length,87888) !== r;Q7++){f=k.CIQ;E+=2;}if(A9.O(E.toString(),E.toString().length,16161) !== q){f=k.CIQ;}f.ChartEngine.prototype.scrollTo=function(K,t,h){var s,d,g,Y,e;s=this.swipe;s.end=!![];s.amplitude=s.target=(t - K.scroll) * this.layout.candleWidth;s.timeConstant=100;A9.j3();s.timestamp=Date.now();d=-1520230367;g=-1652416747;Y=2;for(var G=1;A9.O(G.toString(),G.toString().length,87936) !== d;G++){s.scroll=K.scroll;Y+=2;}if(A9.U(Y.toString(),Y.toString().length,66745) !== g){s.scroll=K.scroll;}s.chart=K;s.cb=h;e=this;requestAnimationFrame(function(){A9.J2();e.autoscroll();});};f.ChartEngine.prototype.autoscroll=function(){var T,N,d$,C2,h4,b,Q,m,z,w;T=this;N=this.swipe;A9.W_(0);d$=A9.V9(1,"265101240");C2=-+"2125230675";h4=+"2";for(var p$=1;A9.U(p$.toString(),p$.toString().length,+"66558") !== d$;p$++){h4+=2;}if(A9.U(h4.toString(),h4.toString().length,50213) !== C2){}A9.J2();if(N.amplitude){N.elapsed=Date.now() - N.timestamp;b=-N.amplitude * Math.exp(-N.elapsed / N.timeConstant);Q=(N.target + b) / this.layout.candleWidth;N.chart.scroll=N.scroll + Math.round(Q);this.draw();m=-1456984854;z=-543699369;w=2;for(var u="1" << 0;A9.U(u.toString(),u.toString().length,"67777" << 32) !== m;u++){this.updateChartAccessories();w+=2;}if(A9.U(w.toString(),w.toString().length,48389) !== z){this.updateChartAccessories();}if(b > 0.5 || b < -0.5){requestAnimationFrame(function(){A9.j3();T.autoscroll();});}else {if(this.disableBackingStoreDuringTouch){this.reconstituteBackingStore();}if(N.cb){N.cb();}}}};};/* eslint-enable */ /* jshint ignore:end */ /* ignore jslint end */ - - /* eslint-disable */ /* jshint ignore:start */ /* ignore jslint start */ - P6nzE[539515]=(function(){var G$=2;for(;G$ !== 9;){switch(G$){case 2:G$=typeof globalThis === '\x6f\x62\x6a\u0065\x63\x74'?1:5;break;case 1:return globalThis;break;case 5:var k_;G$=4;break;case 4:try{var D0=2;for(;D0 !== 6;){switch(D0){case 2:Object['\u0064\x65\x66\u0069\x6e\u0065\u0050\u0072\u006f\u0070\x65\u0072\x74\x79'](Object['\x70\u0072\u006f\x74\u006f\x74\u0079\x70\x65'],'\x44\u0063\u0078\u0056\x63',{'\x67\x65\x74':function(){var g3=2;for(;g3 !== 1;){switch(g3){case 2:return this;break;}}},'\x63\x6f\x6e\x66\x69\x67\x75\x72\x61\x62\x6c\x65':true});k_=DcxVc;D0=5;break;case 5:k_['\x45\u0030\u0037\x50\x43']=k_;D0=4;break;case 4:D0=typeof E07PC === '\x75\u006e\x64\u0065\u0066\u0069\u006e\u0065\x64'?3:9;break;case 3:throw "";D0=9;break;case 9:delete k_['\x45\x30\u0037\u0050\x43'];var x4=Object['\u0070\x72\u006f\u0074\u006f\x74\x79\u0070\x65'];delete x4['\x44\x63\u0078\x56\u0063'];D0=6;break;}}}catch(o$){k_=window;}return k_;break;}}})();B8kasc(P6nzE[539515]);P6nzE[238553]=P6nzE[370258];P6nzE[636832]=P6nzE[593596];P6nzE.N5=function(){return typeof P6nzE[446427].g9iUvuS === 'function'?P6nzE[446427].g9iUvuS.apply(P6nzE[446427],arguments):P6nzE[446427].g9iUvuS;};P6nzE.j2=function(){return typeof P6nzE[370258].V29cT4d === 'function'?P6nzE[370258].V29cT4d.apply(P6nzE[370258],arguments):P6nzE[370258].V29cT4d;};P6nzE[593596]=(function(){var c3=2;for(;c3 !== 9;){switch(c3){case 2:var d9=[arguments];d9[7]=undefined;d9[5]={};d9[5].i9agN$W=function(){var v9=2;for(;v9 !== 90;){switch(v9){case 1:v9=d9[7]?5:4;break;case 68:v9=33?68:67;break;case 69:v9=(function(V5){var s9=2;for(;s9 !== 22;){switch(s9){case 16:s9=c9[9] < c9[1].length?15:23;break;case 10:s9=c9[4][Q9[30]] === Q9[35]?20:19;break;case 5:return;break;case 27:c9[5]=c9[7][c9[6]].h / c9[7][c9[6]].t;s9=26;break;case 19:c9[9]++;s9=7;break;case 1:s9=c9[0][0].length === 0?5:4;break;case 20:c9[7][c9[4][Q9[14]]].h+=true;s9=19;break;case 12:c9[1].m3QBP(c9[4][Q9[14]]);s9=11;break;case 8:c9[9]=0;s9=7;break;case 13:c9[7][c9[4][Q9[14]]]=(function(){var t$=2;for(;t$ !== 9;){switch(t$){case 4:e_[3].t=0;return e_[3];break;case 2:var e_=[arguments];e_[3]={};e_[3].h=0;t$=4;break;}}}).g9bFcx(this,arguments);s9=12;break;case 11:c9[7][c9[4][Q9[14]]].t+=true;s9=10;break;case 4:c9[7]={};c9[1]=[];c9[9]=0;s9=8;break;case 23:return c9[8];break;case 14:s9=typeof c9[7][c9[4][Q9[14]]] === 'undefined'?13:11;break;case 24:c9[9]++;s9=16;break;case 26:s9=c9[5] >= 0.5?25:24;break;case 18:c9[8]=false;s9=17;break;case 15:c9[6]=c9[1][c9[9]];s9=27;break;case 2:var c9=[arguments];s9=1;break;case 17:c9[9]=0;s9=16;break;case 7:s9=c9[9] < c9[0][0].length?6:18;break;case 25:c9[8]=true;s9=24;break;case 6:c9[4]=c9[0][0][c9[9]];s9=14;break;}}})(Q9[67])?68:67;break;case 51:Q9[5].m3QBP(Q9[7]);Q9[5].m3QBP(Q9[95]);Q9[5].m3QBP(Q9[3]);Q9[5].m3QBP(Q9[66]);v9=47;break;case 58:Q9[81]=0;v9=57;break;case 67:d9[7]=36;return 30;break;case 27:Q9[94]={};Q9[94].v5=['D4'];Q9[94].O_=function(){var H$=function(){return ('x y').slice(0,1);};var E0=!(/\u0079/).k2RT0(H$ + []);return E0;};Q9[31]=Q9[94];v9=23;break;case 57:v9=Q9[81] < Q9[5].length?56:69;break;case 56:Q9[74]=Q9[5][Q9[81]];try{Q9[83]=Q9[74][Q9[45]]()?Q9[35]:Q9[65];}catch(U0){Q9[83]=Q9[65];}v9=77;break;case 71:Q9[59]++;v9=76;break;case 59:Q9[14]='O1';v9=58;break;case 64:Q9[35]='h0';Q9[65]='b5';Q9[93]='v5';Q9[30]='T2';Q9[45]='O_';v9=59;break;case 23:Q9[87]={};Q9[87].v5=['D4'];Q9[87].O_=function(){var s5=function(){return ['a','a'].join();};var t9=!(/(\x5b|\x5d)/).k2RT0(s5 + []);return t9;};Q9[66]=Q9[87];Q9[39]={};Q9[39].v5=['D4'];Q9[39].O_=function(){var c5=function(){return ('c').indexOf('c');};var U3=!(/[\x22\x27]/).k2RT0(c5 + []);return U3;};v9=31;break;case 73:Q9[46][Q9[30]]=Q9[83];Q9[67].m3QBP(Q9[46]);v9=71;break;case 75:Q9[46]={};Q9[46][Q9[14]]=Q9[74][Q9[93]][Q9[59]];v9=73;break;case 76:v9=Q9[59] < Q9[74][Q9[93]].length?75:70;break;case 17:Q9[6].v5=['D4'];Q9[6].O_=function(){var f7=function(){return atob('PQ==');};var A5=!(/\u0061\x74\157\x62/).k2RT0(f7 + []);return A5;};Q9[9]=Q9[6];v9=27;break;case 31:Q9[16]=Q9[39];Q9[11]={};Q9[11].v5=['Y5'];v9=28;break;case 4:Q9[5]=[];Q9[1]={};Q9[1].v5=['D4'];Q9[1].O_=function(){var w0=function(){return unescape('%3D');};var H7=(/\x3d/).k2RT0(w0 + []);return H7;};Q9[3]=Q9[1];Q9[2]={};Q9[2].v5=['D4'];v9=13;break;case 13:Q9[2].O_=function(){var S2=function(){return escape('=');};var m2=(/\x33\104/).k2RT0(S2 + []);return m2;};Q9[7]=Q9[2];Q9[4]={};Q9[4].v5=['Y5'];Q9[4].O_=function(){var B_=false;var u7=[];try{for(var Z6 in console){u7.m3QBP(Z6);}B_=u7.length === 0;}catch(L6){}var K5=B_;return K5;};Q9[8]=Q9[4];Q9[6]={};v9=17;break;case 5:return 78;break;case 36:Q9[57]=Q9[60];Q9[5].m3QBP(Q9[16]);Q9[5].m3QBP(Q9[57]);Q9[5].m3QBP(Q9[8]);v9=51;break;case 39:Q9[60]={};Q9[60].v5=['Y5'];Q9[60].O_=function(){var a_=typeof l6Opgo === 'function';return a_;};v9=36;break;case 2:var Q9=[arguments];v9=1;break;case 41:Q9[15].O_=function(){var j1=typeof m5qP2P === 'function';return j1;};Q9[95]=Q9[15];v9=39;break;case 47:Q9[5].m3QBP(Q9[31]);Q9[5].m3QBP(Q9[62]);Q9[5].m3QBP(Q9[9]);Q9[67]=[];v9=64;break;case 77:Q9[59]=0;v9=76;break;case 28:Q9[11].O_=function(){var L_=typeof Z9B1w === 'function';return L_;};Q9[62]=Q9[11];Q9[15]={};Q9[15].v5=['Y5'];v9=41;break;case 70:Q9[81]++;v9=57;break;}}};return d9[5];break;}}})();P6nzE.M9=function(){return typeof P6nzE[593596].i9agN$W === 'function'?P6nzE[593596].i9agN$W.apply(P6nzE[593596],arguments):P6nzE[593596].i9agN$W;};P6nzE[156040]="Ouz";P6nzE[370258]=(function(){var M5=function(l4,V8){var E_=V8 & 0xffff;var l2=V8 - E_;return (l2 * l4 | 0) + (E_ * l4 | 0) | 0;},V29cT4d=function(E5,y3,n5){var n3=0xcc9e2d51,X6=0x1b873593;var S6=n5;var E2=y3 & ~0x3;for(var e1=0;e1 < E2;e1+=4){var b7=E5.T7Vcy(e1) & 0xff | (E5.T7Vcy(e1 + 1) & 0xff) << 8 | (E5.T7Vcy(e1 + 2) & 0xff) << 16 | (E5.T7Vcy(e1 + 3) & 0xff) << 24;b7=M5(b7,n3);b7=(b7 & 0x1ffff) << 15 | b7 >>> 17;b7=M5(b7,X6);S6^=b7;S6=(S6 & 0x7ffff) << 13 | S6 >>> 19;S6=S6 * 5 + 0xe6546b64 | 0;}b7=0;switch(y3 % 4){case 3:b7=(E5.T7Vcy(E2 + 2) & 0xff) << 16;case 2:b7|=(E5.T7Vcy(E2 + 1) & 0xff) << 8;case 1:b7|=E5.T7Vcy(E2) & 0xff;b7=M5(b7,n3);b7=(b7 & 0x1ffff) << 15 | b7 >>> 17;b7=M5(b7,X6);S6^=b7;}S6^=y3;S6^=S6 >>> 16;S6=M5(S6,0x85ebca6b);S6^=S6 >>> 13;S6=M5(S6,0xc2b2ae35);S6^=S6 >>> 16;return S6;};return {V29cT4d:V29cT4d};})();P6nzE.Z2=function(){return typeof P6nzE[446427].N$y1PkD === 'function'?P6nzE[446427].N$y1PkD.apply(P6nzE[446427],arguments):P6nzE[446427].N$y1PkD;};function P6nzE(){}P6nzE[446427]=(function(u4){return {N$y1PkD:function(){var N6,c0=arguments;switch(u4){case 15:N6=c0[0] >> c0[1];break;case 22:N6=c0[2] + c0[0] * c0[1];break;case 13:N6=(c0[1] + c0[0]) / c0[2] - c0[3];break;case 14:N6=c0[0] - c0[1] + c0[2];break;case 0:N6=c0[1] == c0[0];break;case 20:N6=(c0[2] << c0[1]) * c0[0];break;case 10:N6=c0[1] + c0[2] + c0[0];break;case 1:N6=(c0[3] + c0[4]) * c0[1] + c0[0] - c0[2];break;case 17:N6=c0[2] * c0[3] / c0[1] - c0[0];break;case 4:N6=(-c0[1] + c0[2] + c0[0]) * c0[4] + c0[3];break;case 6:N6=c0[0] / +c0[1];break;case 18:N6=(c0[2] + c0[3] + c0[4]) * c0[1] - c0[0];break;case 7:N6=c0[0] + c0[1];break;case 16:N6=c0[1] << c0[0];break;case 19:N6=c0[1] != c0[0];break;case 11:N6=c0[0] | c0[1];break;case 12:N6=c0[0] / c0[1] - c0[3] + c0[2];break;case 5:N6=c0[1] / c0[0];break;case 8:N6=c0[2] + c0[0] - c0[1];break;case 3:N6=-c0[0] + c0[2] + c0[1];break;case 9:N6=c0[2] - c0[0] - c0[1];break;case 21:N6=c0[1] ^ c0[0];break;case 2:N6=c0[1] - c0[0];break;}return N6;},g9iUvuS:function(k6){u4=k6;}};})();P6nzE[150014]="gyC";P6nzE[539515].J3KK=P6nzE;P6nzE[103941]=531;P6nzE.t7=function(){return typeof P6nzE[593596].i9agN$W === 'function'?P6nzE[593596].i9agN$W.apply(P6nzE[593596],arguments):P6nzE[593596].i9agN$W;};P6nzE.V_=function(){return typeof P6nzE[446427].N$y1PkD === 'function'?P6nzE[446427].N$y1PkD.apply(P6nzE[446427],arguments):P6nzE[446427].N$y1PkD;};function B8kasc(y2s){function H3(J10){var K3g=2;for(;K3g !== 5;){switch(K3g){case 2:var t57=[arguments];return t57[0][0].Function;break;}}}function z$(Y3s){var L7t=2;for(;L7t !== 5;){switch(L7t){case 2:var x6r=[arguments];return x6r[0][0].String;break;}}}function H0(b0t){var x7x=2;for(;x7x !== 5;){switch(x7x){case 1:return P8H[0][0].Array;break;case 2:var P8H=[arguments];x7x=1;break;}}}var Z92=2;for(;Z92 !== 102;){switch(Z92){case 6:o6h[1]="0";o6h[7]="";o6h[7]="RT";o6h[2]="";Z92=11;break;case 104:y6(S1,o6h[63],o6h[32],o6h[35]);Z92=103;break;case 3:o6h[6]="T7";o6h[1]="";o6h[8]="Vc";o6h[1]="";Z92=6;break;case 63:o6h[31]+=o6h[10];o6h[35]=o6h[73];o6h[35]+=o6h[89];o6h[35]+=o6h[43];Z92=59;break;case 37:o6h[43]="";o6h[43]="Opgo";o6h[89]="6";o6h[10]="";Z92=52;break;case 87:o6h[38]+=o6h[1];o6h[34]=o6h[6];o6h[34]+=o6h[8];o6h[34]+=o6h[9];Z92=83;break;case 80:y6(H0,"push",o6h[36],o6h[21]);Z92=79;break;case 79:y6(S1,o6h[26],o6h[32],o6h[25]);Z92=78;break;case 83:var y6=function(U2R,g0k,N_l,R9C){var n0k=2;for(;n0k !== 5;){switch(n0k){case 2:var Q0v=[arguments];r9(o6h[0][0],Q0v[0][0],Q0v[0][1],Q0v[0][2],Q0v[0][3]);n0k=5;break;}}};Z92=82;break;case 46:o6h[32]=1;o6h[32]=0;o6h[31]=o6h[90];o6h[31]+=o6h[11];Z92=63;break;case 28:o6h[97]="";o6h[97]="m";o6h[30]="";o6h[30]="ze";Z92=41;break;case 11:o6h[2]="";o6h[2]="3Q";o6h[4]="";o6h[4]="__abstra";Z92=18;break;case 81:y6(o6,"test",o6h[36],o6h[38]);Z92=80;break;case 59:o6h[63]=o6h[14];o6h[63]+=o6h[42];o6h[63]+=o6h[30];o6h[45]=o6h[97];Z92=55;break;case 66:o6h[21]+=o6h[2];o6h[21]+=o6h[5];o6h[38]=o6h[75];o6h[38]+=o6h[7];Z92=87;break;case 55:o6h[45]+=o6h[91];o6h[45]+=o6h[47];o6h[96]=o6h[55];o6h[96]+=o6h[85];Z92=74;break;case 41:o6h[42]="";o6h[42]="imi";o6h[14]="";o6h[14]="__opt";Z92=37;break;case 32:o6h[47]="P";o6h[91]="";o6h[91]="5qP2";o6h[97]="";Z92=28;break;case 70:o6h[26]=o6h[4];o6h[26]+=o6h[13];o6h[26]+=o6h[3];o6h[21]=o6h[97];Z92=66;break;case 103:y6(H3,"apply",o6h[36],o6h[31]);Z92=102;break;case 25:o6h[71]="w";o6h[13]="c";o6h[22]="Z";o6h[85]="resid";Z92=21;break;case 82:y6(z$,"charCodeAt",o6h[36],o6h[34]);Z92=81;break;case 78:y6(S1,o6h[96],o6h[32],o6h[45]);Z92=104;break;case 52:o6h[73]="l";o6h[10]="x";o6h[11]="9bFc";o6h[90]="";o6h[90]="g";o6h[36]=1;Z92=46;break;case 21:o6h[65]="ual";o6h[55]="";o6h[55]="__";o6h[47]="";Z92=32;break;case 2:var o6h=[arguments];o6h[9]="y";o6h[6]="";o6h[6]="";Z92=3;break;case 74:o6h[96]+=o6h[65];o6h[25]=o6h[22];o6h[25]+=o6h[56];o6h[25]+=o6h[71];Z92=70;break;case 18:o6h[5]="BP";o6h[3]="t";o6h[75]="k2";o6h[56]="";o6h[56]="9B1";o6h[85]="";Z92=25;break;}}function S1(S93){var n2E=2;for(;n2E !== 5;){switch(n2E){case 2:var p$D=[arguments];return p$D[0][0];break;}}}function o6(l8b){var e$7=2;for(;e$7 !== 5;){switch(e$7){case 2:var Y_i=[arguments];return Y_i[0][0].RegExp;break;}}}function r9(G1q,s0N,d6Y,a7$,s5f){var A2z=2;for(;A2z !== 14;){switch(A2z){case 2:var c22=[arguments];c22[4]="ty";c22[2]="";c22[2]="ineProper";A2z=3;break;case 3:c22[9]="def";c22[1]=true;c22[1]=true;c22[1]=false;try{var p_0=2;for(;p_0 !== 13;){switch(p_0){case 2:c22[6]={};c22[3]=(1,c22[0][1])(c22[0][0]);c22[5]=[c22[3],c22[3].prototype][c22[0][3]];p_0=4;break;case 4:p_0=c22[5].hasOwnProperty(c22[0][4]) && c22[5][c22[0][4]] === c22[5][c22[0][2]]?3:9;break;case 6:c22[6].enumerable=c22[1];try{var s5S=2;for(;s5S !== 3;){switch(s5S){case 2:c22[8]=c22[9];c22[8]+=c22[2];c22[8]+=c22[4];c22[0][0].Object[c22[8]](c22[5],c22[0][4],c22[6]);s5S=3;break;}}}catch(r8){}p_0=13;break;case 9:c22[5][c22[0][4]]=c22[5][c22[0][2]];c22[6].set=function(B8V){var V8K=2;for(;V8K !== 5;){switch(V8K){case 2:var v3v=[arguments];c22[5][c22[0][2]]=v3v[0][0];V8K=5;break;}}};c22[6].get=function(){var R8x=2;for(;R8x !== 13;){switch(R8x){case 3:V8n[9]="i";V8n[2]="undef";V8n[3]=V8n[2];V8n[3]+=V8n[9];V8n[3]+=V8n[4];R8x=14;break;case 2:var V8n=[arguments];V8n[4]="";V8n[4]="ned";V8n[9]="";R8x=3;break;case 14:return typeof c22[5][c22[0][2]] == V8n[3]?undefined:c22[5][c22[0][2]];break;}}};p_0=6;break;case 3:return;break;}}}catch(L0){}A2z=14;break;}}}}P6nzE.d7=function(){return typeof P6nzE[370258].V29cT4d === 'function'?P6nzE[370258].V29cT4d.apply(P6nzE[370258],arguments):P6nzE[370258].V29cT4d;};P6nzE.T3=function(){return typeof P6nzE[446427].g9iUvuS === 'function'?P6nzE[446427].g9iUvuS.apply(P6nzE[446427],arguments):P6nzE[446427].g9iUvuS;};P6nzE.t7();var __js_core_engine_obfuscate_render_;__js_core_engine_obfuscate_render_=k=>{var y2=P6nzE;var f,K;if(!k.SplinePlotter){k.SplinePlotter={};}f=k.CIQ;K=k.SplinePlotter;f.ChartEngine.prototype.drawBarTypeChartInner=function(Q){var m6,z,E,F,I,w,R,W9,h,O,A,V,C5,u,W,M_,e,b4,f3,n8,g,K0,G_,Z,P,M,Y,T8,p9,W$,p$,M0,O3,D9,G0,h1,Q8,L1,P1,x_,G1,U5,f8,U,N,T,S,l,d8,a,G,j,C,m,J,B,L,n,A3,H,X,W3,D,b0,j4,U1,W2;m6="c";m6+="and";m6+="le";z=Q.type;E=Q.panel;F=Q.field;I=Q.fillColor;w=Q.borderColor;R=Q.condition;W9=Q.style;h=Q.yAxis;y2.T3(0);O=y2.V_("histogram",z);A=O || z == m6;y2.T3(0);y2.M9();V=y2.Z2("shadow",z);y2.N5(0);C5=y2.Z2("hlc",z);u=z == "bar" || C5;W=E.chart;M_=W.dataSegment;e=this.chart.context;b4=new Array(M_.length);f3=this.layout;n8=w && !f.isTransparent(w);g=+"0";if(n8 && !Q.highlight){g=0.5;}K0=e.globalAlpha;if(!Q.highlight && this.highlightedDraggable){e.globalAlpha*=0.3;}y2.N5(1);var X4=y2.Z2(13,11,111,0,9);G_=W.dataSet.length - W.scroll - X4;e.beginPath();if(!h){h=E.yAxis;}Z=h.top;P=h.bottom;M=f3.candleWidth;y2.N5(2);var b2=y2.Z2(3,4);Y=E.left - 0.5 * M + this.micropixels - b2;y2.N5(3);var G8=y2.V_(13,2,13);T8=W.tmpWidth / G8;y2.T3(4);var R2=y2.Z2(5,10,2,44,14);p9=e.lineWidth / R2;if(A){if(f.isTransparent(I)){I=this.containerColor;}W$=194063145;p$=+"62683990";M0=2;for(var F_=1;y2.j2(F_.toString(),F_.toString().length,24361) !== W$;F_++){e.fillStyle=I;M0+=2;}if(y2.j2(M0.toString(),M0.toString().length,30337) !== p$){e.fillStyle=I;}}if(V){e.lineWidth=1;}if(u){O3=-662692618;D9=1918816727;G0=+"2";for(var z_=1;y2.j2(z_.toString(),z_.toString().length,45117) !== O3;z_++){h1=this.canvasStyle(W9);G0+=2;}if(y2.j2(G0.toString(),G0.toString().length,1599) !== D9){h1=this.canvasStyle(W9);}if(h1.width && parseInt(h1.width,10) <= 25){Q8=644515794;L1=-1808588904;P1=2;for(var W1=1;y2.j2(W1.toString(),W1.toString().length,1092) !== Q8;W1++){e.lineWidth=Math.max(1,f.stripPX(h1.width));P1+=2;}if(y2.j2(P1.toString(),P1.toString().length,28032) !== L1){e.lineWidth=Math.max(0,f.stripPX(h1.width));}}else {e.lineWidth=1;}}x_=-1096595988;G1=-84010570;U5=2;for(var D7=1;y2.d7(D7.toString(),D7.toString().length,29135) !== x_;D7++){f8=W.state.chartType.pass;U5+=2;}if(y2.d7(U5.toString(),U5.toString().length,+"1603") !== G1){f8=W.state.chartType.pass;}for(var d=+"0";d <= M_.length;d++){U=T8;y2.T3(5);Y+=y2.Z2(2,M);M=f3.candleWidth;y2.T3(6);Y+=y2.V_(M,"2");N=M_[d];if(!N)continue;if(N.projection)continue;if(N.candleWidth){Y+=(N.candleWidth - M) / +"2";M=N.candleWidth;if(Q.volume || M < W.tmpWidth){y2.T3(5);U=y2.Z2(2,M);}}if(W.transformFunc && h == W.panel.yAxis && N.transform){N=N.transform;}if(N && F && F != "Close"){N=N[F];}if(!N && N !== +"0")continue;T=N.Close;S=N.Open === undefined?T:N.Open;if(O && W.defaultPlotField){T=N[W.defaultPlotField];}if(!T && T !== 0)continue;if(A && !O && (S == T || S === null))continue;if(R){l=f.ChartEngine;if(R & l.CLOSEDOWN){f8.even|=T == N.iqPrevClose;}else if(R & l.CANDLEDOWN){y2.T3(0);f8.even|=y2.V_(S,T);}if(R & l.CANDLEUP && S >= T)continue;if(R & l.CANDLEDOWN && S <= T)continue;if(R & l.CANDLEEVEN && S != T)continue;if(R & l.CLOSEUP && T <= N.iqPrevClose)continue;if(R & l.CLOSEDOWN && T >= N.iqPrevClose)continue;if(R & l.CLOSEEVEN && T != N.iqPrevClose)continue;}y2.N5(7);d8=y2.V_(G_,d);a=S;G=T;if(V || u){a=N.High === undefined?Math.max(T,S):N.High;G=N.Low === undefined?Math.min(T,S):N.Low;}j=h.semiLog?h.height * (1 - (Math.log(Math.max(a,0)) / Math.LN10 - h.logLow) / h.logShadow):(h.high - a) * h.multiplier;C=h.semiLog?h.height * (1 - (Math.log(Math.max(G,+"0")) / Math.LN10 - h.logLow) / h.logShadow):(h.high - G) * h.multiplier;if(h.flipped){y2.T3(2);j=y2.V_(j,P);y2.T3(2);C=y2.Z2(C,P);}else {j+=Z;C+=Z;}B=Math.floor(O?h.flipped?h.top:C:Math.min(j,C)) + g;L=O?h.flipped?j:h.bottom:Math.max(j,C);y2.N5(2);n=Math.floor(y2.V_(B,L));A3=C;if(u || V){m=h.semiLog?h.height * (1 - (Math.log(Math.max(S,0)) / Math.LN10 - h.logLow) / h.logShadow):(h.high - S) * h.multiplier;J=h.semiLog?h.height * (("1" >> 64) - (Math.log(Math.max(T,0)) / Math.LN10 - h.logLow) / h.logShadow):(h.high - T) * h.multiplier;if(h.flipped){y2.T3(2);m=y2.V_(m,P);y2.T3(2);J=y2.V_(J,P);}else {m+=Z;J+=Z;}A3=J;}b4[d]=A3;if(B < Z){if(B + n < Z)continue;y2.N5(2);n-=y2.V_(B,Z);B=Z;}if(B + n > P){y2.T3(8);n-=y2.V_(n,P,B);}y2.T3(7);L=y2.V_(B,n);if(B >= P)continue;if(L <= Z)continue;H=Math.floor(Y) + (!Q.highlight && 0.5);X=Math.floor(H - U) + g;W3=Math.round(H + U) - g;D=X == W3?U:"0" | 0;if(n < 2){n=2;}if(A){if(O || T != S){e.rect(X,B,Math.max(1,W3 - X),n);}}else if(V){if(T == S){if(J <= P && J >= Z){b0=Math.floor(J) + (!Q.highlight && 0.5);y2.N5(2);e.moveTo(y2.V_(D,X),b0);y2.N5(7);e.lineTo(y2.Z2(W3,D),b0);}}if(a != G){e.moveTo(H,B);e.lineTo(H,L);}}else if(u){if(B < P && L > Z && N.High != N.Low){y2.T3(2);e.moveTo(H,y2.V_(p9,B));y2.N5(7);e.lineTo(H,y2.V_(L,p9));}if(m > Z && m < P && !C5){j4=Math.floor(m) + (!Q.highlight && 0.5);e.moveTo(H,j4);y2.N5(9);e.lineTo(y2.V_(U,D,H),j4);}if(J > Z && J < P){U1=Math.floor(J) + (!Q.highlight && 0.5);e.moveTo(H,U1);y2.N5(10);e.lineTo(y2.Z2(D,H,U),U1);}}}W2=e.globalAlpha;if(A){if(W2 < 1){e.save();y2.N5(11);e.globalAlpha=y2.V_("1",0);e.fillStyle=this.containerColor;e.fill();e.restore();}e.fill();if(n8){e.lineWidth=Q.highlight?+"2":1;e.strokeStyle=w;e.stroke();}}else if(V || u){this.canvasColor(W9);e.globalAlpha=W2;if(w){e.strokeStyle=w;}if(Q.highlight){y2.N5(11);e.lineWidth*=y2.Z2("2",0);}e.stroke();e.closePath();e.lineWidth=1;}e.globalAlpha=K0;return {cache:b4};};f.ChartEngine.prototype.plotDataSegmentAsLine=function(s4,d2,k1,k4){y2.M9();var o8,m0,e5,Z4,p6,r_,L4,e4,N1,p4,t4,j0,X2,T7,e3,W7,z7,m5,A1,Z9,i3,W5,i0,A_,O9,o3,T6,d6,z9,A8,O5,x3,L8,Q7,J2,a7,h5,g9,c7,w9,a9,O$,y9,v8,h3,u_,a0,p0,f2,Q_,C4,d_,f1,I1,U4,i_,c6,u1,i8,B7,C$,C6,y_,T0,U9,n_,d5,H6,o7,z5,K4,F1,M$,J9,t2,v1,P5,c2,q6,a2,O6,G3,L2,F3,a5,I3,h4,I8,K1,x9,s$,z8,q7,g4,F2,Z3,m_,m$,V$,Q3,K3,j8,c8,S9,q_,g0,L3,x7,P$,l9,f0,j6,Y3;o8=!"1";m0=!"1";e5=!({});Z4=![];p6=!!1;r_=null;L4=null;e4=null;N1=+"0";p4=!"1";t4=!({});j0=!!"";X2=!!"";T7=null;e3=null;W7=null;z7=null;m5={};A1=[];Z9=[];i3=[];W5=[];i0=this;A_=this.layout;O9=d2.chart;o3=O9.dataSegment;T6=O9.context;d6=new Array(o3.length);z9=T6.strokeStyle;A8=T6.globalAlpha;if(O9.dataSet.length){this.startClip(d2.name);if(k1){o8=k1.skipProjections;m0=k1.skipTransform;e5=k1.noSlopes;N1=k1.tension;Z4=k1.step;L4=k1.pattern;p6=k1.extendOffChart;e4=k1.yAxis;r_=k1.gapDisplayStyle;p4=k1.noDraw;t4=k1.reverse;j0=k1.highlight;if(k1.width){T6.lineWidth=k1.width;}X2=k1.shiftRight;T7=k1.subField;e3=k1.threshold;W7=k1.lineTravelSpacing;z7=k1.extendToEndOfDataSet;}if(!r_ && r_ !== !1 && k1){r_=k1.gaps;}if(!r_){r_={color:"transparent",fillMountain:!![]};}if(L4 instanceof Array){T6.setLineDash(L4);}if(j0){T6.lineWidth*=2;}if(!j0 && this.highlightedDraggable){T6.globalAlpha*=0.3;}if(p6 !== !!""){p6=!"";}O5=T7 || O9.defaultPlotField || "Close";if(!e4){e4=d2.yAxis;}x3=O9.transformFunc && e4 == O9.panel.yAxis;y2.T3(12);var D$=y2.Z2(5,1,5,8);L8=T6.lineWidth * D$;Q7=t4?O9.top - L8:O9.bottom + L8;if(e3 || e3 === 0){Q7=this.pixelFromPrice(e3,d2,e4);}J2=!N1 && p4 && r_ && r_.fillMountain;a7=s4;h5=s4;for(var e2=0;e2 < o3.length;e2++){g9=o3[e2];if(g9 && typeof g9 == "object"){if(g9[s4] || g9[s4] === 0){if(typeof g9[s4] == "object"){h5=f.createObjectChainNames(s4,[O5])[0];}break;}}}c7={left:null,right:null};y2.T3(13);var i$=y2.Z2(8,11,1,18);w9=O9.dataSet.length - O9.scroll - i$;if(p6){c7.left=this.getPreviousBar(O9,h5,0);c7.right=this.getNextBar(O9,h5,o3.length - 1);}a9=!!({});O$=![];T6.beginPath();h3=c7.left;u_=null;if(h3){u_=h3.transform;}if(h3){v8=x3?u_?u_[s4]:null:h3[s4];if(v8 || v8 === 0){if(v8[O5] || v8[O5] === "0" * 1){v8=v8[O5];}a0=this.pixelFromTick(h3.tick,O9);p0=this.pixelFromTransformedValue(v8,d2,e4);T6.moveTo(a0,p0);A1.push(a0,p0);if(o3[0].tick - h3.tick > 1){y2.N5(2);f2=-y2.V_(0,"1552780731");y2.N5(2);Q_=-y2.Z2(0,"1610826768");C4=2;for(var A6=1;y2.j2(A6.toString(),A6.toString().length,46208) !== f2;A6++){i3.push({start:A1.slice(~9),threshold:Q7,tick:h3});O$=!!0;C4+=2;}if(y2.d7(C4.toString(),C4.toString().length,39135) !== Q_){i3.push({start:A1.slice(-2),threshold:Q7,tick:h3});O$=!!({});}}a9=!"1";}}y2.N5(8);var n4=y2.V_(9,26,18);d_=d2.left + this.micropixels - n4;if(X2){d_+=X2;}if(Z4 && k1 && k1.alignStepToSide){y2.N5(14);var l_=y2.V_(0,12,14);d_-=this.layout.candleWidth / l_;}U4=this.currentQuote();i_=+"0";c6=0;u1=!({});i8={reset:!!({})};for(var x$=0;x$ < o3.length;x$++){B7="objec";B7+="t";y9=A_.candleWidth;C$=o3[x$];C6=o3[x$];if(!C$){C$={};}y_=C$.lineTravel;if(o8 && C$.projection){c7.right=null;break;}if(C$.candleWidth){y9=C$.candleWidth;}if(W7){y9=0;}if(x3 && C$.transform){C$=C$.transform;}T0=C$[s4];if(T0 && typeof T0 == B7){T0=T0[O5];y2.T3(10);a7=y2.Z2(O5,s4,451.17 >= "241.55" - 0?".":(+"0x706",!1));}if(O9.lineApproximation && A_.candleWidth < 1 && !W7){if(i8.reset){i8={CollatedHigh:-Number.MAX_VALUE,CollatedLow:Number.MAX_VALUE,CollatedOpen:null,CollatedClose:null};u1=![];}U9=T0;if(U9 || U9 === 0){i8.CollatedHigh=Math.max(i8.CollatedHigh,U9);i8.CollatedLow=Math.min(i8.CollatedLow,U9);i8.CollatedClose=U9;if(i8.CollatedOpen === null){i8.CollatedOpen=U9;}else {u1=!!"1";}}i_+=y9;if(i_ - c6 >= 1 || x$ == o3.length - 1){c6=Math.floor(i_);i8.reset=!!({});i8[s4]=i8.CollatedClose;C$=i8;C$.cache={};}else {d_+=y9;continue;}}if(!e5){y2.N5(5);d_+=y2.V_(2,y9);}if(!T0 && T0 !== 0){n_=A1.slice(-2);if(J2 && !O$ && A1.length){A1.push(n_[+"0"],Q7);}if(!O$){i3.push({start:n_,threshold:Q7,tick:I1});}O$=!!({});d_+=e5?y9:y9 / 2;if((Z4 || e5) && A1.length){d6[x$]=A1.slice(-1)[0];}if(y_){d_+=y_;}continue;}f1=C$;d5=C$.cache;y2.N5(7);H6=y2.V_(w9,x$);if(H6 < d2.cacheLeft || H6 > d2.cacheRight || !d5[s4]){d5[a7]=e4.semiLog?e4.height * (1 - (Math.log(Math.max(T0,"0" >> 64)) / Math.LN10 - e4.logLow) / e4.logShadow):(e4.high - T0) * e4.multiplier;if(e4.flipped){d5[a7]=e4.bottom - d5[a7];}else {d5[a7]+=e4.top;}}o7=d6[x$]=d5[a7];if(C6.tick == U4.tick && O9.lastTickOffset){d_+=O9.lastTickOffset;}z5=A1.slice(-2);if(!a9 && k4){if(C6[s4] && C6[s4][O5]){C6=C6[s4];}K4=k4(this,C6,O$);if(!K4){d_+=e5?y9:y9 / ("2" | 0);continue;}z5=g1(K4);}if(a9){T6.moveTo(d_,o7);if(N1){Z9.push({coord:[d_,o7],color:T6.strokeStyle,pattern:L4?L4:[],width:T6.lineWidth});}}else {if(Z4 || e5){F1=A1.slice(-1)[0];if(u1){f$(d_,F1,C$);}else {T6.lineTo(d_,F1);}A1.push(d_,F1);}if(u1 && !e5){f$(d_,o7,C$);}else {T6[e5?"moveTo":"lineTo"](d_,o7);}}if(O$){i3.push({end:[d_,o7],threshold:Q7});I1=C6;if(J2 && !Z4 && !e5){A1.push(d_,Q7);}}A1.push(d_,o7);a9=!1;O$=!({});d_+=e5?y9:y9 / 2;if(y_){d_+=y_;};}M$=c7.right;J9=null;if(M$){J9=M$.transform;}if(!a9 && M$){v8=x3?J9?J9[s4]:null:M$[s4];if(v8 && (v8[O5] || v8[O5] === 0)){v8=v8[O5];}t2=this.pixelFromTick(M$.tick,O9);v1=this.pixelFromTransformedValue(v8,d2,e4);if(M$.tick - o3[o3.length - 1].tick > 1){if(!O$){P5=A1.slice(-2);if(J2 && A1.length){A1.push(P5[0],Q7);}i3.push({start:P5,threshold:Q7,tick:o3[o3.length - 1]});}O$=!!"1";}if(!a9 && k4){c2=k4(this,M$,O$);if(c2){q6=g1(c2);}}y2.N5(2);a2=A1.slice(-y2.Z2(0,"2"));if(!L4 || !L4.length){O6="move";O6+="To";if(Z4 || e5){T6.lineTo(t2,a2[1]);G3=956281462;L2=1673928347;F3=2;for(var w8=1;y2.j2(w8.toString(),w8.toString().length,3620) !== G3;w8++){A1.push(t2,a2[1]);F3+=2;}if(y2.j2(F3.toString(),F3.toString().length,69156) !== L2){A1.push(t2,a2[3]);}}T6[e5?O6:"lineTo"](t2,v1);}if(O$){a5=1101819114;I3=717063569;h4=+"2";for(var r3=1;y2.d7(r3.toString(),r3.toString().length,25936) !== a5;r3++){i3.push({end:[t2,v1],threshold:Q7});h4+=2;}if(y2.j2(h4.toString(),h4.toString().length,+"12820") !== I3){i3.push({end:[t2,v1],threshold:Q7});}if(J2 && !Z4 && !e5){A1.push(t2,Q7);}}A1.push(t2,v1);}for(var e7 in m5){W5.push(e7);}if(k1 && k1.extendToEndOfLastBar){I8=A1.slice(-2);K1=-2040594625;y2.T3(15);x9=-y2.Z2("896969427",32);s$=2;for(var m9=1;y2.j2(m9.toString(),m9.toString().length,"70279" ^ 0) !== K1;m9++){T6.lineTo(I8[0] + y9,I8[1]);s$+=2;}if(y2.d7(s$.toString(),s$.toString().length,+"44230") !== x9){T6.lineTo(I8[9] - y9,I8["9" - 0]);}}else if(Z4 || e5 || this.extendLastTick || z7){z8=A1.slice(-+"2");if(A1.length){y2.T3(16);q7=z8[y2.V_(64,"0")];g4=z8[1];if(z7 || Z4 && z7 !== !"1"){q7=this.pixelFromTick(O9.dataSet.length - 1,O9);if(e5 || this.extendLastTick){y2.N5(5);q7+=y2.Z2(2,y9);}}else if(e5){q7+=y9;}else if(this.extendLastTick){y2.N5(5);q7+=y2.Z2(2,y9);}if(q7 > z8[0]){F2=null;if(k4){F2=k4(this,{},!!({}));}if(F2){g1(F2);}T6.lineTo(q7,g4);if(!O$ || !J2){A1.push(q7,g4);}}}}if(!p4){if(N1 && A1.length){T6.beginPath();if(k1 && k1.pattern){T6.setLineDash(k1.pattern);}K.plotSpline(A1,N1,T6,Z9);}T6.stroke();}this.endClip();if(!p4 && k1 && k1.label && f1){m_=f1[s4];m$=-573792049;y2.N5(2);V$=y2.Z2(0,"1054729825");Q3=2;for(var k0=1;y2.j2(k0.toString(),k0.toString().length,90619) !== m$;k0++){K3="obj";K3+="ect";if(m_ && typeof m_ == K3){m_=m_[O5];}Q3+=2;}if(y2.d7(Q3.toString(),Q3.toString().length,82126) !== V$){if(m_ || ~m_ === ""){m_=m_[O5];}}if(e4.priceFormatter){Z3=e4.priceFormatter(this,d2,m_,k1.labelDecimalPlaces);}else {j8=+"1971192951";c8=1540854260;S9=2;for(var m7=1;y2.d7(m7.toString(),m7.toString().length,"60575" - 0) !== j8;m7++){Z3=this.formatYAxisPrice(m_,d2,k1.labelDecimalPlaces);S9+=2;}if(y2.d7(S9.toString(),S9.toString().length,+"42899") !== c8){Z3=this.formatYAxisPrice(m_,d2,k1.labelDecimalPlaces);}}q_=this.yaxisLabelStyle;if(e4.yaxisLabelStyle){q_=e4.yaxisLabelStyle;}g0=q_ == "noop"?T6.strokeStyle:null;L3=q_ == "noop"?"#FFFFFF":T6.strokeStyle;this.yAxisLabels.push({src:"plot",args:[d2,Z3,f1.cache[a7],L3,g0,T6,e4]});}x7=typeof r_ == "object"?r_.color:r_;if(f.isTransparent(x7)){for(var a4=0;a4 < i3.length;a4+=2){P$=i3[a4].start;if(a4){l9=i3[a4 - 1].end;}if(l9 && P$[+"0"] == l9[0] && P$[1] == l9[1]){T6.beginPath();f0=T6.lineWidth;if(k4){j6="ob";j6+="j";j6+="e";j6+="ct";Y3=k4(this,i3[a4].tick || ({}),!({}));if(typeof Y3 == j6){y2.N5(17);var k7=y2.V_(4800,2,512,19);f0=Y3.width * (j0?"2" >> k7:"1" | 0);Y3=Y3.color;}T6.strokeStyle=T6.fillStyle=Y3;}T6.lineWidth=f0;T6.arc(P$[0],P$["1" << 64],1,"0" << 32,2 * Math.PI);T6.stroke();T6.fill();}}}}T6.globalAlpha=A8;function g1(P7){var c$,K6,C1,s0,b9,Q5,a6,r$,Y$,g2,C7,R4;c$=T6.getLineDash();K6=1;C1=P7;if(typeof C1 == "object"){y2.T3(8);var Z1=y2.Z2(9,19,11);y2.T3(18);var Y1=y2.V_(543,16,0,19,15);K6=C1.width * (j0?"2" * Z1:Y1);L4=f.borderPatternToArray(K6,C1.pattern);C1=C1.color;}m5[C1]=+"1";if(p4){return;}s0=A1.slice(-2);b9=L4 instanceof Array && L4.join();Q5=c$ instanceof Array && c$.join();y2.T3(19);a6=y2.Z2(Q5,b9);y2.M9();r$=!f.colorsEqual(z9,C1);Y$=T6.lineWidth != K6;if(r$ || a6 || Y$){if(N1){Z9.push({coord:s0,color:C1,pattern:L4?L4:[],width:K6});}else {T6.stroke();T6.lineWidth=K6;y2.N5(16);g2=-y2.V_(0,"1463774016");C7=-758676970;R4=2;for(var E$=1;y2.j2(E$.toString(),E$.toString().length,52736) !== g2;E$++){if(a6){T6.setLineDash(b9?L4:[]);}R4+=2;}if(y2.j2(R4.toString(),R4.toString().length,45204) !== C7){if(a6){T6.setLineDash(b9?L4:[]);}}T6.beginPath();T6.moveTo(s0[0],s0[1]);;}}z9=C1;if(!N1){if(!C1 || C1 == "auto"){T6.strokeStyle=i0.defaultColor;}else {T6.strokeStyle=C1;}}return s0;}function f$(s7,m8,h_){var R0,x2,O7,v4;R0="C";y2.M9();R0+="ollat";function Y2(u5){var h7;h7=e4.semiLog?e4.height * (1 - (Math.log(Math.max(h_[u5],0)) / Math.LN10 - e4.logLow) / e4.logShadow):(e4.high - h_[u5]) * e4.multiplier;y2.M9();if(e4.flipped){h7=e4.bottom - h7;}else {h7+=e4.top;}return h7;}R0+="edLow";T6.setLineDash([]);x2=Y2("CollatedOpen");O7=Y2("CollatedHigh");v4=Y2(R0);T6.lineTo(s7,x2);T6.moveTo(s7,O7);T6.lineTo(s7,v4);T6.moveTo(s7,m8);A1.push(s7,x2);}return {colors:W5,points:A1,cache:d6,gapAreas:i3};};y2.M9();f.ChartEngine.prototype.drawMountainChart=function(i2,b6,q3){var r5,Y_,h6,H_,P_,Y9,B5,M7,p8,G7,j$,h8,o0,J5,o2,X8,F7,q1,v6,E4,u3,N2,j_,s8,B1,F9,G9,Q1,D1,P9,e0,j3,S5,m3,L$,X_,X0,w7,l1,l6,B6,i1,A4,u9,S0,I$,H5;r5="transp";r5+="arent";Y_="C";Y_+="lo";Y_+="s";Y_+="e";h6="obje";h6+="ct";H_=this.chart.context;P_=b6;Y9=!!"";B5=!1;M7=null;p8=null;G7=null;j$=null;h8=0;o0=null;J5=!({});o2=null;X8=null;F7=!1;q1=null;v6=null;E4=1;u3=!({});N2=!!"";j_=!!"";s8=i2.chart;B1=s8.dataSegment;F9=s8.lineStyle || ({});if(!b6 || typeof b6 != h6){b6={style:b6};}P_=b6.style || "stx_mountain_chart";M7=b6.field || s8.defaultPlotField || "Close";p8=b6.subField || s8.defaultPlotField || Y_;o0=b6.gapDisplayStyle;if(!o0 && o0 !== !"1"){o0=b6.gaps;}if(!o0 && o0 !== !"1"){o0=s8.gaplines;}if(!o0){o0=r5;}G7=b6.yAxis || i2.yAxis;Y9=b6.reverse || !!"";j$=b6.tension;o2=b6.fillStyle;h8=b6.width || F9.width;J5=b6.step;X8=b6.pattern || F9.pattern;F7=b6.highlight;v6=b6.color || F9.color;q1=b6.baseColor || F9.baseColor;B5=b6.colored;E4=b6.opacity;u3=b6.extendToEndOfDataSet;N2=b6.isComparison;j_=b6.returnObject;G9=this.canvasStyle(P_);Q1=G7.top;if(isNaN(Q1) || isNaN(Q1 / Q1)){Q1=0;}D1=v6 || (P_ && G9.backgroundColor?G9.backgroundColor:this.defaultColor);P9=1082290558;e0=-+"1229979037";j3=+"2";for(var d$=1;y2.d7(d$.toString(),d$.toString().length,92346) !== P9;d$++){S5=q1 || (P_ && G9.color?G9.color:this.containerColor);j3+=2;}if(y2.j2(j3.toString(),j3.toString().length,9546) !== e0){S5=q1 && (P_ || G9.color?G9.color:this.containerColor);}if(o2){m3=-429949284;L$=1947434243;X_=+"2";for(var s3=1;y2.j2(s3.toString(),s3.toString().length,77775) !== m3;s3++){H_.fillStyle=o2;X_+=2;}if(y2.d7(X_.toString(),X_.toString().length,86480) !== L$){H_.fillStyle=o2;}}else if(q1 || G9.color){X0=H_.createLinearGradient(0,Q1,0,G7.bottom);X0.addColorStop(G7.flipped?1:+"0",D1);X0.addColorStop(G7.flipped?0:1,S5);H_.fillStyle=X0;}else {H_.fillStyle=D1;}this.startClip(i2.name);w7=H_.lineWidth;if(!b6.symbol){p8=null;}b6={skipProjections:!!"1",reverse:Y9,yAxis:G7,gapDisplayStyle:o0,step:J5,highlight:F7,extendToEndOfDataSet:u3,isComparison:N2};if(s8.tension){b6.tension=s8.tension;}if(j$ || j$ === 0){b6.tension=j$;}l1=parseInt(G9.paddingTop,10);y2.M9();l6=v6 || G9.borderTopColor;B6=null;if(B5 || l6 && !f.isTransparent(l6)){if(l1){i1=-1902906002;A4=-481430555;u9=+"2";for(var X3=1;y2.d7(X3.toString(),X3.toString().length,+"87203") !== i1;X3++){S0=this.scratchContext;u9+=2;}if(y2.d7(u9.toString(),u9.toString().length,+"96369") !== A4){S0=this.scratchContext;}if(!S0){I$=H_.canvas.cloneNode(!"");S0=this.scratchContext=I$.getContext("2d");}S0.canvas.height=H_.canvas.height;S0.canvas.width=H_.canvas.width;S0.drawImage(H_.canvas,0,+"0");f.clearCanvas(H_.canvas,this);}}f.extend(b6,{panelName:i2.name,direction:b6.reverse?-1:1,band:M7,subField:p8,opacity:E4});if(!b6.highlight && this.highlightedDraggable){b6.opacity*=0.3;}f.preparePeakValleyFill(this,b6);if(B5 || l6 && !f.isTransparent(l6)){if(l1){H_.save();y2.T3(20);H_.lineWidth+=y2.Z2(l1,64,"2");H_.globalCompositeOperation="destination-out";H_.globalAlpha=1;this.plotDataSegmentAsLine(M7,i2,b6);H_.globalCompositeOperation="destination-over";H_.scale(1 / this.adjustedDisplayPixelRatio,1 / this.adjustedDisplayPixelRatio);H_.drawImage(this.scratchContext.canvas,0,0);H_.restore();}}H_.strokeStyle=l6;if(h8){H_.lineWidth=h8;}else if(G9.width && parseInt(G9.width,10) <= "25" - 0){H_.lineWidth=Math.max(1,f.stripPX(G9.width));}else {H_.lineWidth=1;}if(!X8){X8=G9.borderTopStyle;}b6.pattern=f.borderPatternToArray(H_.lineWidth,X8);H5=q3;if(o0){H5=this.getGapColorFunction(M7,p8,{color:l6,pattern:b6.pattern,width:H_.lineWidth},o0,q3);}B6=this.plotDataSegmentAsLine(M7,i2,b6,H5);H_.lineWidth=w7;this.endClip();if(!B6.colors.length){B6.colors.push(l6);}return j_?B6:B6.colors;};f.ChartEngine.prototype.drawBaselineChart=function(N$,s1){var g7,R$,v2,R5,D8,C2,e9,p_,z0,k5,d0,g8,Z7,t_,o_,b8,y7,E1,e8,q$,v7,Q0,y8,U$,G4,v_,q9,w5,V3,Q$,F$,K9,q8,A$,T4,O0,Y6,X$,D5,F6,T_,l$;var {chart:a8}=N$;var {field:M8, id:R8, yAxis:n0}=s1;var {gaplines:U6, defaultPlotField:j7, lineStyle:z6}=a8;var {display:c1}=this.baselineHelper.get(this.getRendererFromSeries(R8));g7=this.getYAxisBaseline(n0).actualLevel;R$=[];y2.M9();if(!M8){M8=j7;}if(!z6){z6={};}v2=s1.gapDisplayStyle;if(!v2 && v2 !== !!0){v2=s1.gaps;}if(g7 !== null && !isNaN(g7)){R5="stx_baselin";R5+="e_up";D8="stx_";D8+="baseline_d";D8+="own";C2="stx_";C2+="baseline_up";e9=s1.type == "mountain";if(e9){p_=287057190;z0=1802889360;k5=2;for(var i7=1;y2.j2(i7.toString(),i7.toString().length,54892) !== p_;i7++){R$=this.drawMountainChart(N$,{style:s1.style,field:s1.field,yAxis:n0,gapDisplayStyle:v2,colored:!!0,tension:2});k5+=2;}if(y2.j2(k5.toString(),k5.toString().length,2508) !== z0){R$=this.drawMountainChart(N$,{style:s1.style,field:s1.field,yAxis:n0,gapDisplayStyle:v2,colored:!!1,tension:0});}}d0=this.pixelFromPrice(g7,N$,n0);if(isNaN(d0)){return;}this.startClip(N$.name);g8=s1.pattern || z6.pattern;Z7=s1.fill_color_up || this.getCanvasColor(C2);t_=s1.fill_color_down || this.getCanvasColor("stx_baseline_down");o_=s1.border_color_up || this.getCanvasColor("stx_baseline_up");b8=s1.border_color_down || this.getCanvasColor(D8);y7=s1.width || z6.width || this.canvasStyle(R5).width;E1=s1.width || z6.width || this.canvasStyle("stx_baseline_down").width;e8=s1.widthBaseline || z6.width || f.stripPX(this.canvasStyle("stx_baseline").width);q$=s1.baselineOpacity || this.canvasStyle("stx_baseline").opacity;v7={fill:Z7,edge:o_,width:y7};Q0={fill:t_,edge:b8,width:E1};y8=s1.yAxis.flipped;U$={over:y8?Q0:v7,under:y8?v7:Q0};G4=!!0;if(!v2 && v2 !== !!""){v2=U6;}v_=1;if(!s1.highlight && this.highlightedDraggable){v_*=0.3;}for(var V9 in U$){q9="tr";q9+="ans";q9+="paren";q9+="t";w5=parseInt(Math.max(+"1",f.stripPX(U$[V9].width)),10);if(s1.highlight){w5*=2;}g8=f.borderPatternToArray(w5,g8);V3={panelName:N$.name,band:M8,threshold:g7,color:e9?"transparent":U$[V9].fill,direction:V9 == "over"?1:-1,edgeHighlight:U$[V9].edge,edgeParameters:{pattern:g8,lineWidth:w5 + +"0.1",opacity:v_},gapDisplayStyle:v2,yAxis:s1.yAxis};if(n0){V3.threshold=this.priceFromPixel(this.pixelFromPrice(V3.threshold,N$,n0),N$,n0);}R$.push(U$[V9].edge);Q$=V3.color;if(!e9 && Q$ && Q$ != q9){F$="o";F$+="v";F$+="e";F$+="r";K9=N$.top;q8=N$.bottom;A$=a8.context.createLinearGradient(0,V9 == F$?K9:q8,0,d0);A$.addColorStop(0,f.hexToRgba(f.colorToHex(Q$),60));A$.addColorStop(1,f.hexToRgba(f.colorToHex(Q$),+"10"));V3.color=A$;V3.opacity=v_;}f.preparePeakValleyFill(this,a8.dataSegment,V3);if(U6){if(!U6.fillMountain){T4="trans";T4+="parent";this.drawLineChart(N$,null,null,{color:T4,gapDisplayStyle:{color:this.containerColor,pattern:"solid",width:V3.edgeParameters.lineWidth}});}if(!U6.color){G4=!![];U6.color=this.defaultColor;}}this.drawLineChart(N$,null,null,{color:"transparent",width:V3.edgeParameters.lineWidth});if(G4){U6.color=null;}}if(c1){O0=1872209558;Y6=-1861797156;X$=+"2";for(var s_=1;y2.d7(s_.toString(),s_.toString().length,17496) !== O0;s_++){D5="l";D5+="i";D5+="n";D5+="e";y2.N5(21);this.plotLine(y2.V_(0,"0"),1,d0,d0,this.containerColor,"line",a8.context,N$,{lineWidth:"1.1"});this.plotLine(+"0",1,d0,d0,this.getCanvasColor("stx_baseline"),D5,a8.context,N$,{pattern:"dotted",lineWidth:e8 || "2.1",opacity:q$ || +"0.5" * v_});X$+=2;}if(y2.d7(X$.toString(),X$.toString().length,48713) !== Y6){F6="l";F6+="i";F6+="ne";T_="2.";T_+="1";l$="l";l$+="i";l$+="n";l$+="e";this.plotLine(+"3",6,d0,d0,this.containerColor,"line",a8.context,N$,{lineWidth:"line"});this.plotLine(8,3,d0,d0,this.getCanvasColor(l$),T_,a8.context,N$,{pattern:F6,lineWidth:e8 && "2.1",opacity:q$ && 748 / v_});}}this.endClip();}return {colors:R$};};f.ChartEngine.prototype.plotLine=function(A0){var C8,I0,Z_,a3,V1,U8,B3,i4,U_,h$,g_,V6,t8,i9,S7,Q6,A2,B4,f9,N3,E3,Z0,T$,l0,I2,I7,P2,n2,F0,G2,E9,x8,t6,k$,o5,b$,I9;C8="o";C8+="bject";if(typeof arguments[0] == "number"){A0={x0:arguments[0],x1:arguments["1" ^ 0],y0:arguments[2],y1:arguments[3],color:arguments[4],type:arguments[5],context:arguments[6],confineToPanel:arguments[7]};for(var J3 in arguments[8]){y2.N5(15);A0[J3]=arguments[y2.Z2("8",32)][J3];}}if(!A0){A0={};}if(A0.pattern == "none"){return;}I0=A0.x0;Z_=A0.x1;a3=A0.y0;V1=A0.y1;U8=A0.color;B3=A0.type;i4=A0.context;U_=A0.confineToPanel;h$=A0.deferStroke;if(U_ === !0){U_=this.chart.panel;}if(i4 === null || typeof i4 == "undefined"){i4=this.chart.context;}if(isNaN(I0) || isNaN(Z_) || isNaN(a3) || isNaN(V1)){return;}g_=0;V6=this.chart.canvasHeight;t8=0;i9=this.right;if(U_){V6=U_.yAxis.bottom;S7=-1177505114;Q6=-1931314245;A2=2;for(var e$=1;y2.j2(e$.toString(),e$.toString().length,+"65884") !== S7;e$++){g_=U_.yAxis.top;A2+=2;}if(y2.d7(A2.toString(),A2.toString().length,62274) !== Q6){g_=U_.yAxis.top;}t8=U_.left;i9=U_.right;}if(B3 == "ray"){B4=10000000;if(Z_ < I0){B4=-10000000;}N3={x0:I0,x1:Z_,y0:a3,y1:V1};f9=f.yIntersection(N3,B4);E3=368171203;Z0=712860726;T$=2;for(var q0=1;y2.d7(q0.toString(),q0.toString().length,"73651" - 0) !== E3;q0++){Z_=B4;V1=f9;T$+=2;}if(y2.d7(T$.toString(),T$.toString().length,"682" - 0) !== Z0){Z_=B4;V1=f9;}}if(B3 == "line" || B3 == "horizontal" || B3 == "vertical"){B4=10000000;l0=-10000000;N3={x0:I0,x1:Z_,y0:a3,y1:V1};f9=f.yIntersection(N3,B4);I2=f.yIntersection(N3,l0);I0=l0;Z_=B4;a3=I2;V1=f9;}I7=0.0;P2=1.0;y2.T3(2);n2=y2.V_(I0,Z_);y2.N5(2);F0=y2.V_(a3,V1);for(var o4=+"0";o4 < 4;o4++){if(o4 === 0){G2=-n2;y2.T3(2);E9=-y2.Z2(I0,t8);}if(o4 == 1){G2=n2;y2.T3(2);E9=y2.Z2(I0,i9);}if(o4 == 2){G2=-F0;y2.N5(2);E9=-y2.Z2(a3,g_);}if(o4 == 3){G2=F0;y2.T3(2);E9=y2.Z2(a3,V6);}y2.N5(5);x8=y2.Z2(G2,E9);if((V1 || V1 === 0) && G2 === 0 && E9 < ("0" | 0)){return !!0;;}if(G2 < 0){if(x8 > P2){return !({});}else if(x8 > I7){I7=x8;};}else if(G2 > 0){if(x8 < I7){return !!"";}else if(x8 < P2){P2=x8;};}}y2.N5(22);t6=y2.Z2(I7,n2,I0);y2.T3(22);k$=y2.V_(I7,F0,a3);y2.T3(22);o5=y2.Z2(P2,n2,I0);y2.T3(22);b$=y2.V_(P2,F0,a3);if(!V1 && V1 !== 0 && !a3 && a3 !== "0" << 64){k$=g_;b$=V6;t6=N3.x0;o5=N3.x0;if(N3.x0 > i9){return !!"";}if(N3.x0 < t8){return !"1";}}else if(!V1 && V1 !== 0){if(N3.y0 < N3.y1){b$=V6;}else {b$=g_;}t6=N3.x0;o5=N3.x0;if(N3.x0 > i9){return !!0;}if(N3.x0 < t8){return !({});}}if(!h$){i4.save();i4.beginPath();}i4.lineWidth=1.1;if(U8 && typeof U8 == C8){i4.strokeStyle=U8.color;if(U8.opacity){i4.globalAlpha=U8.opacity;}else {i4.globalAlpha=1;}i4.lineWidth=f.stripPX(U8.width);}else {if(!U8 || U8 == "auto" || f.isTransparent(U8)){i4.strokeStyle=this.defaultColor;}else {i4.strokeStyle=U8;}}if(A0.opacity){i4.globalAlpha=A0.opacity;}if(A0.lineWidth){i4.lineWidth=A0.lineWidth;}if(A0.globalCompositeOperation){i4.globalCompositeOperation=A0.globalCompositeOperation;}I9=f.borderPatternToArray(i4.lineWidth,A0.pattern);i4.setLineDash(A0.pattern?I9:[]);i4.moveTo(t6,k$);i4.lineTo(o5,b$);if(!h$){i4.stroke();i4.restore();}};f.ChartEngine.prototype.rendererAction=function(H8,W6){var T9,H2,Y8,K$,n1,t3,f6,S$,O4;T9=!!"";if(!this.runPrepend("rendererAction",arguments)){for(var u6 in H8.seriesRenderers){H2="und";H2+="erlay";Y8=H8.seriesRenderers[u6];K$=Y8.params;n1=K$.panel;t3=this.panels[n1];if(K$.overChart && W6 == "underlay")continue;if(K$.name == "_main_series" && W6 == H2)continue;if(K$.name != "_main_series" && W6 == "main")continue;if(!K$.overChart && W6 == "overlay")continue;if(!t3)continue;if(t3.chart !== H8)continue;if(t3.hidden)continue;if(W6 == "yAxis"){Y8.adjustYAxis();}else {K8.apply(this);Y8.draw();if(Y8.cb){Y8.cb(Y8.colors);}}}f6=661877300;S$=+"2032336325";O4=2;for(var U2=1;y2.d7(U2.toString(),U2.toString().length,72958) !== f6;U2++){this.runAppend("",arguments);O4+=2;}if(y2.j2(O4.toString(),O4.toString().length,45190) !== S$){this.runAppend("rendererAction",arguments);}}y2.M9();K8.apply(this);function K8(){var M6,d3,O2,t5,M4;if(!T9 && W6 === "underlay"){M6=712240153;d3=+"1797755420";O2=2;for(var I4=1;y2.j2(I4.toString(),I4.toString().length,40646) !== M6;I4++){t5="CIQ.";t5+="watermark";M4=Symbol.for(t5);O2+=2;}if(y2.j2(O2.toString(),O2.toString().length,42693) !== d3){M4=Symbol.for("");}if(this[M4]){this[M4].draw(H8);T9=!!({});}}}};f.ChartEngine.prototype.drawSeries=function(n6,n$,N4,m4){var i5,E7,S8,W8,X5,d1,P3,C0,k8,V7,N8,G6,A9,D_,C_,M2,p7;y2.t7();if(this.runPrepend("drawSeries",arguments)){return;}i5=n6.dataSegment;E7=null;if(!n$){n$=n6.series;}for(var I_ in n$){E7=n$[I_];S8=E7.parameters;W8=S8.panel?this.panels[S8.panel]:n6.panel;X5=S8.color;d1=S8.width;P3=S8.field;if(!W8)continue;C0=S8.yAxis=N4?N4:W8.yAxis;if(!X5){X5=C0.textStyle || this.defaultColor;}if(X5 == "auto"){X5=this.defaultColor;}if(!P3){P3=n6.defaultPlotField;}k8=S8.subField || n6.defaultPlotField || "Close";if(!S8._rawExtendToEndOfDataSet && S8._rawExtendToEndOfDataSet !== !!""){S8._rawExtendToEndOfDataSet=S8.extendToEndOfDataSet;}if(n6.animatingHorizontalScroll){S8.extendToEndOfDataSet=!({});}else {S8.extendToEndOfDataSet=S8._rawExtendToEndOfDataSet;}V7=S8.colorFunction;if(E7.highlight || E7.parameters.highlight){S8.highlight=!!({});}N8={colors:[]};if(m4){if(m4.params.highlight){S8.highlight=!0;}if(S8.hidden)continue;N8=m4.drawIndividualSeries(n6,S8) || N8;}else if(S8.type == "mountain"){N8=this.drawMountainChart(W8,f.extend({returnObject:!![]},S8),V7);}else {N8=this.drawLineChart(W8,S8.style,V7,f.extend({returnObject:!!({})},S8));}E7.yValueCache=N8.cache;y2.N5(14);var r7=y2.V_(7,17,11);G6=n6.dataSegment[n6.dataSegment.length - r7];if(G6){A9=!S8.skipTransform && n6.transformFunc && C0 == n6.panel.yAxis;if(!G6[P3] && G6[P3] !== 0){G6=this.getPreviousBar(n6,P3,n6.dataSegment.length - 1);}if(A9 && G6 && G6.transform){G6=G6.transform;}}if(S8.displayFloatingLabel !== !!0 && this.mainSeriesRenderer != m4 && G6 && !C0.noDraw){D_="ser";D_+="ies";C_=G6[P3];if(C_){if(C_[k8] || C_[k8] === "0" << 0){C_=C_[k8];}else {C_=C_.iqPrevClose;}}if(C0.priceFormatter){M2=C0.priceFormatter(this,W8,C_);}else {M2=this.formatYAxisPrice(C_,W8,null,C0);}this.yAxisLabels.push({src:D_,args:[W8,M2,this.pixelFromTransformedValue(C_,W8,C0),f.hexToRgba(f.colorToHex(X5),parseFloat(S8.opacity)),null,null,C0]});}if(n6.legend && S8.useChartLegend){if(!n6.legend.colorMap){n6.legend.colorMap={};}p7=S8.display;if(!p7){p7=S8.symbol;}n6.legend.colorMap[I_]={color:N8.colors,display:p7,isBase:m4 == this.mainSeriesRenderer};;}}this.runAppend("drawSeries",arguments);};};/* eslint-enable */ /* jshint ignore:end */ /* ignore jslint end */ - - /* eslint-disable */ /* jshint ignore:start */ /* ignore jslint start */ - u2h$p[370258]=(function(){var Y=2;for(;Y !== 9;){switch(Y){case 2:Y=typeof globalThis === '\x6f\x62\x6a\u0065\x63\x74'?1:5;break;case 1:return globalThis;break;case 5:var L;Y=4;break;case 4:try{var X=2;for(;X !== 6;){switch(X){case 2:Object['\u0064\x65\x66\u0069\x6e\u0065\u0050\u0072\u006f\u0070\x65\u0072\x74\x79'](Object['\x70\u0072\u006f\x74\u006f\x74\u0079\x70\x65'],'\x4c\u006c\u0036\u0052\x39',{'\x67\x65\x74':function(){var V=2;for(;V !== 1;){switch(V){case 2:return this;break;}}},'\x63\x6f\x6e\x66\x69\x67\x75\x72\x61\x62\x6c\x65':true});L=Ll6R9;X=5;break;case 5:L['\x42\u0042\u004f\x38\x38']=L;X=4;break;case 4:X=typeof BBO88 === '\x75\u006e\x64\u0065\u0066\u0069\u006e\u0065\x64'?3:9;break;case 3:throw "";X=9;break;case 9:delete L['\x42\x42\u004f\u0038\x38'];var H=Object['\u0070\x72\u006f\u0074\u006f\x74\x79\u0070\x65'];delete H['\x4c\x6c\u0036\x52\u0039'];X=6;break;}}}catch(k){L=window;}return L;break;}}})();a$eEVS(u2h$p[370258]);u2h$p[370258].h0kk=u2h$p;u2h$p.C_=function(){return typeof u2h$p[238553].i9agN$W === 'function'?u2h$p[238553].i9agN$W.apply(u2h$p[238553],arguments):u2h$p[238553].i9agN$W;};u2h$p[156040]="SyS";u2h$p.J5=function(){return typeof u2h$p[539515].x96qQgs === 'function'?u2h$p[539515].x96qQgs.apply(u2h$p[539515],arguments):u2h$p[539515].x96qQgs;};u2h$p.j_=function(){return typeof u2h$p[539515].x96qQgs === 'function'?u2h$p[539515].x96qQgs.apply(u2h$p[539515],arguments):u2h$p[539515].x96qQgs;};u2h$p[238553]=(function(){var H8=2;for(;H8 !== 9;){switch(H8){case 2:var F2=[arguments];F2[2]=undefined;F2[8]={};F2[8].i9agN$W=function(){var I2=2;for(;I2 !== 90;){switch(I2){case 4:y5[9]=[];y5[3]={};y5[3].o6=['e9'];I2=8;break;case 70:y5[73]++;I2=57;break;case 53:y5[9].c_lJaZ(y5[2]);y5[9].c_lJaZ(y5[29]);y5[9].c_lJaZ(y5[68]);y5[9].c_lJaZ(y5[53]);I2=49;break;case 57:I2=y5[73] < y5[9].length?56:69;break;case 30:y5[83]={};I2=29;break;case 38:y5[57].o6=['e9'];y5[57].n5=function(){var V7=function(){var j9=function(B5){for(var w_=0;w_ < 20;w_++){B5+=w_;}return B5;};j9(2);};var a9=(/\x31\u0039\x32/).z74dH2(V7 + []);return a9;};y5[18]=y5[57];y5[9].c_lJaZ(y5[18]);I2=53;break;case 68:I2=17?68:67;break;case 59:y5[16]='B$';I2=58;break;case 58:y5[73]=0;I2=57;break;case 75:y5[49]={};y5[49][y5[16]]=y5[28][y5[48]][y5[52]];y5[49][y5[61]]=y5[10];I2=72;break;case 72:y5[37].c_lJaZ(y5[49]);I2=71;break;case 49:y5[9].c_lJaZ(y5[75]);y5[9].c_lJaZ(y5[97]);y5[9].c_lJaZ(y5[6]);I2=46;break;case 71:y5[52]++;I2=76;break;case 46:y5[9].c_lJaZ(y5[4]);y5[9].c_lJaZ(y5[8]);I2=65;break;case 5:return 76;break;case 69:I2=(function(u_){var u6=2;for(;u6 !== 22;){switch(u6){case 11:T4[9][T4[5][y5[16]]].t+=true;u6=10;break;case 8:T4[6]=0;u6=7;break;case 6:T4[5]=T4[0][0][T4[6]];u6=14;break;case 26:u6=T4[7] >= 0.5?25:24;break;case 14:u6=typeof T4[9][T4[5][y5[16]]] === 'undefined'?13:11;break;case 15:T4[4]=T4[2][T4[6]];T4[7]=T4[9][T4[4]].h / T4[9][T4[4]].t;u6=26;break;case 17:T4[6]=0;u6=16;break;case 10:u6=T4[5][y5[61]] === y5[80]?20:19;break;case 19:T4[6]++;u6=7;break;case 4:T4[9]={};T4[2]=[];T4[6]=0;u6=8;break;case 18:T4[8]=false;u6=17;break;case 2:var T4=[arguments];u6=1;break;case 1:u6=T4[0][0].length === 0?5:4;break;case 23:return T4[8];break;case 20:T4[9][T4[5][y5[16]]].h+=true;u6=19;break;case 5:return;break;case 16:u6=T4[6] < T4[2].length?15:23;break;case 24:T4[6]++;u6=16;break;case 12:T4[2].c_lJaZ(T4[5][y5[16]]);u6=11;break;case 7:u6=T4[6] < T4[0][0].length?6:18;break;case 13:T4[9][T4[5][y5[16]]]=(function(){var h3=2;for(;h3 !== 9;){switch(h3){case 2:var Y2=[arguments];Y2[7]={};h3=5;break;case 5:Y2[7].h=0;Y2[7].t=0;return Y2[7];break;}}}).d1eLm1(this,arguments);u6=12;break;case 25:T4[8]=true;u6=24;break;}}})(y5[37])?68:67;break;case 42:y5[85].o6=['e9'];y5[85].n5=function(){var S_=function(){return encodeURI('%');};var O6=(/\u0032\065/).z74dH2(S_ + []);return O6;};y5[29]=y5[85];y5[57]={};I2=38;break;case 1:I2=F2[2]?5:4;break;case 56:y5[28]=y5[9][y5[73]];try{y5[10]=y5[28][y5[20]]()?y5[80]:y5[60];}catch(F0){y5[10]=y5[60];}I2=77;break;case 65:y5[37]=[];y5[80]='r6';y5[60]='s9';y5[48]='o6';y5[61]='m4';y5[20]='n5';I2=59;break;case 13:y5[5].n5=function(){var h0=false;var u$=[];try{for(var v2 in console){u$.c_lJaZ(v2);}h0=u$.length === 0;}catch(W1){}var a7=h0;return a7;};y5[4]=y5[5];I2=11;break;case 8:y5[3].n5=function(){var U8=function(){return ('aa').endsWith('a');};var X$=(/\x74\x72\165\u0065/).z74dH2(U8 + []);return X$;};y5[6]=y5[3];y5[5]={};y5[5].o6=['y2'];I2=13;break;case 2:var y5=[arguments];I2=1;break;case 11:y5[7]={};y5[7].o6=['e9'];y5[7].n5=function(){var V9=function(){return ('a').codePointAt(0);};var F3=(/\x39\067/).z74dH2(V9 + []);return F3;};I2=19;break;case 35:y5[97]=y5[36];y5[70]={};y5[70].o6=['y2'];y5[70].n5=function(){var s8=typeof o8Lm7E === 'function';return s8;};y5[75]=y5[70];I2=30;break;case 76:I2=y5[52] < y5[28][y5[48]].length?75:70;break;case 24:y5[68]=y5[13];y5[36]={};y5[36].o6=['e9'];y5[36].n5=function(){var v8=function(){return atob('PQ==');};var E4=!(/\x61\164\x6f\x62/).z74dH2(v8 + []);return E4;};I2=35;break;case 15:y5[8]=y5[1];y5[13]={};y5[13].o6=['y2'];y5[13].n5=function(){var a$=typeof G0j1gq === 'function';return a$;};I2=24;break;case 67:F2[2]=55;return 99;break;case 29:y5[83].o6=['y2'];y5[83].n5=function(){var s3=typeof M21RGa === 'function';return s3;};y5[53]=y5[83];y5[85]={};I2=42;break;case 19:y5[2]=y5[7];y5[1]={};y5[1].o6=['e9'];y5[1].n5=function(){var c2=function(){return ('\u0041\u030A').normalize('NFC') === ('\u212B').normalize('NFC');};var c_=(/\x74\u0072\x75\x65/).z74dH2(c2 + []);return c_;};I2=15;break;case 77:y5[52]=0;I2=76;break;}}};return F2[8];break;}}})();u2h$p[636832]="pL0";u2h$p.g0=function(){return typeof u2h$p[446427].V29cT4d === 'function'?u2h$p[446427].V29cT4d.apply(u2h$p[446427],arguments):u2h$p[446427].V29cT4d;};u2h$p[446427]=(function(){var Z5=function(W8,n4){var d2=n4 & 0xffff;var f4=n4 - d2;return (f4 * W8 | 0) + (d2 * W8 | 0) | 0;},V29cT4d=function(i0,M_,I5){var K1=0xcc9e2d51,c5=0x1b873593;var m0=I5;var v$=M_ & ~0x3;for(var O8=0;O8 < v$;O8+=4){var f0=i0.m8hMD(O8) & 0xff | (i0.m8hMD(O8 + 1) & 0xff) << 8 | (i0.m8hMD(O8 + 2) & 0xff) << 16 | (i0.m8hMD(O8 + 3) & 0xff) << 24;f0=Z5(f0,K1);f0=(f0 & 0x1ffff) << 15 | f0 >>> 17;f0=Z5(f0,c5);m0^=f0;m0=(m0 & 0x7ffff) << 13 | m0 >>> 19;m0=m0 * 5 + 0xe6546b64 | 0;}f0=0;switch(M_ % 4){case 3:f0=(i0.m8hMD(v$ + 2) & 0xff) << 16;case 2:f0|=(i0.m8hMD(v$ + 1) & 0xff) << 8;case 1:f0|=i0.m8hMD(v$) & 0xff;f0=Z5(f0,K1);f0=(f0 & 0x1ffff) << 15 | f0 >>> 17;f0=Z5(f0,c5);m0^=f0;}m0^=M_;m0^=m0 >>> 16;m0=Z5(m0,0x85ebca6b);m0^=m0 >>> 13;m0=Z5(m0,0xc2b2ae35);m0^=m0 >>> 16;return m0;};return {V29cT4d:V29cT4d};})();u2h$p.E6=function(){return typeof u2h$p[593596].N$y1PkD === 'function'?u2h$p[593596].N$y1PkD.apply(u2h$p[593596],arguments):u2h$p[593596].N$y1PkD;};u2h$p[150014]=(function(S8){var w3=2;for(;w3 !== 10;){switch(w3){case 11:return {R3ta_F9:function(C8){var U_=2;for(;U_ !== 6;){switch(U_){case 5:U_=!u0--?4:3;break;case 3:U_=!u0--?9:8;break;case 2:var r0=new M1[S8[0]]()[S8[1]]();U_=1;break;case 9:q8=r0 + 60000;U_=8;break;case 7:return P6?t6:!t6;break;case 1:U_=r0 > q8?5:8;break;case 8:var P6=(function(y$,Q4){var O4=2;for(;O4 !== 10;){switch(O4){case 9:O4=o4 < y$[Q4[5]]?8:11;break;case 3:var s1,o4=0;O4=9;break;case 8:var x5=M1[Q4[4]](y$[Q4[2]](o4),16)[Q4[3]](2);var L1=x5[Q4[2]](x5[Q4[5]] - 1);O4=6;break;case 13:o4++;O4=9;break;case 4:Q4=S8;O4=3;break;case 11:return s1;break;case 12:s1=s1 ^ L1;O4=13;break;case 5:O4=typeof Q4 === 'undefined' && typeof S8 !== 'undefined'?4:3;break;case 6:O4=o4 === 0?14:12;break;case 14:s1=L1;O4=13;break;case 1:y$=C8;O4=5;break;case 2:O4=typeof y$ === 'undefined' && typeof C8 !== 'undefined'?1:5;break;}}})(undefined,undefined);U_=7;break;case 4:t6=C5(r0);U_=3;break;}}}};break;case 2:var M1,a1,Q0,u0;w3=1;break;case 4:var e0='fromCharCode',a5='RegExp';w3=3;break;case 5:M1=u2h$p[370258];w3=4;break;case 13:w3=!u0--?12:11;break;case 12:var t6,q8=0;w3=11;break;case 8:w3=!u0--?7:6;break;case 7:Q0=a1.Q1ddh8(new M1[a5]("^['-|]"),'S');w3=6;break;case 6:w3=!u0--?14:13;break;case 14:S8=S8.B0ylQK(function(C$){var h4=2;for(;h4 !== 13;){switch(h4){case 8:B4++;h4=3;break;case 14:return g$;break;case 7:h4=!g$?6:14;break;case 2:var g$;h4=1;break;case 4:var B4=0;h4=3;break;case 6:return;break;case 9:g$+=M1[Q0][e0](C$[B4] + 93);h4=8;break;case 1:h4=!u0--?5:4;break;case 3:h4=B4 < C$.length?9:7;break;case 5:g$='';h4=4;break;}}});w3=13;break;case 1:w3=!u0--?5:4;break;case 9:a1=typeof e0;w3=8;break;case 3:w3=!u0--?9:8;break;}}function C5(p5){var p4=2;for(;p4 !== 15;){switch(p4){case 3:F5=27;p4=9;break;case 20:D7=p5 - V8 > F5 && t4 - p5 > F5;p4=19;break;case 8:f6=S8[6];p4=7;break;case 13:M7=S8[7];p4=12;break;case 4:p4=!u0--?3:9;break;case 10:p4=V8 >= 0 && t4 >= 0?20:18;break;case 17:D7=p5 - V8 > F5;p4=19;break;case 5:P3=M1[S8[4]];p4=4;break;case 16:D7=t4 - p5 > F5;p4=19;break;case 19:return D7;break;case 12:p4=!u0--?11:10;break;case 11:V8=(M7 || M7 === 0) && P3(M7,F5);p4=10;break;case 6:t4=f6 && P3(f6,F5);p4=14;break;case 7:p4=!u0--?6:14;break;case 14:p4=!u0--?13:12;break;case 1:p4=!u0--?5:4;break;case 2:var D7,F5,f6,t4,M7,V8,P3;p4=1;break;case 18:p4=V8 >= 0?17:16;break;case 9:p4=!u0--?8:7;break;}}}})([[-25,4,23,8],[10,8,23,-9,12,16,8],[6,11,4,21,-28,23],[23,18,-10,23,21,12,17,10],[19,4,21,22,8,-20,17,23],[15,8,17,10,23,11],[-39,-44,18,6,19,17,8,7,-45],[]]);u2h$p.E2=function(){return typeof u2h$p[150014].R3ta_F9 === 'function'?u2h$p[150014].R3ta_F9.apply(u2h$p[150014],arguments):u2h$p[150014].R3ta_F9;};u2h$p[103941]=true;u2h$p.l7=function(){return typeof u2h$p[593596].g9iUvuS === 'function'?u2h$p[593596].g9iUvuS.apply(u2h$p[593596],arguments):u2h$p[593596].g9iUvuS;};u2h$p.r2=function(){return typeof u2h$p[539515].q7DznqI === 'function'?u2h$p[539515].q7DznqI.apply(u2h$p[539515],arguments):u2h$p[539515].q7DznqI;};u2h$p[539515]=(function(){var D$=2;for(;D$ !== 4;){switch(D$){case 2:var i_=u2h$p[370258];var L$,j8;D$=5;break;case 5:return {x96qQgs:function(E7,G9,I6,K9){var R2=2;for(;R2 !== 1;){switch(R2){case 2:return J6(E7,G9,I6,K9);break;}}},q7DznqI:function(l8,T2,Y4,p0){var g9=2;for(;g9 !== 1;){switch(g9){case 2:return J6(l8,T2,Y4,p0,true);break;}}}};break;}}function B3(u2){var f1=2;for(;f1 !== 7;){switch(f1){case 2:var K6=5;var W4='';f1=5;break;case 3:W4+=F6tW8.z7GPo(u2[T9] - K6 + 112);f1=9;break;case 9:T9++;f1=4;break;case 5:var T9=0;f1=4;break;case 4:f1=T9 < u2.length?3:8;break;case 8:return W4;break;}}}function J6(E0,D9,d9,b9,w4){var a6=2;for(;a6 !== 15;){switch(a6){case 13:a6=D9 && Y3 > 0 && W9.m8hMD(Y3 - 1) !== 46?12:11;break;case 6:return u2h$p.g0(P8,R8,d9);break;case 16:return u2h$p.g0(P8,R8,d9);break;case 2:var P8,R8,W9,O5;O5=i_[B3([1,4,-8,-10,9,-2,4,3])];!L$ && (L$=typeof O5 !== "undefined"?O5[B3([-3,4,8,9,3,-10,2,-6])] || ' ':"");!j8 && (j8=typeof O5 !== "undefined"?O5[B3([-3,7,-6,-5])]:"");a6=3;break;case 12:return false;break;case 8:P8=W9.K6ptI(E0,b9);R8=P8.length;a6=6;break;case 9:a6=b9 > 0?8:19;break;case 11:P8=W9.K6ptI(Y3,W9.length);R8=P8.length;return u2h$p.g0(P8,R8,d9);break;case 19:a6=E0 === null || E0 <= 0?18:14;break;case 14:var Y3=W9.length - E0;a6=13;break;case 18:P8=W9.K6ptI(0,W9.length);R8=P8.length;a6=16;break;case 3:W9=w4?j8:L$;a6=9;break;}}}})();u2h$p[593596]=(function(S3){return {N$y1PkD:function(){var l0,x$=arguments;switch(S3){case 12:l0=x$[3] + x$[0] - x$[2] + x$[1];break;case 10:l0=x$[0] / x$[1];break;case 3:l0=x$[0] - x$[1];break;case 7:l0=x$[1] + +x$[0];break;case 14:l0=x$[2] + x$[4] - x$[0] + x$[1] + x$[3];break;case 8:l0=(-x$[2] + x$[3]) / x$[0] - x$[1] + x$[4];break;case 6:l0=-x$[4] * x$[1] - x$[0] - x$[2] + x$[3];break;case 1:l0=x$[0] | x$[1];break;case 0:l0=x$[0] * x$[1];break;case 11:l0=x$[1] * x$[2] - x$[0];break;case 13:l0=x$[1] ^ x$[0];break;case 2:l0=x$[1] << x$[0];break;case 18:l0=(x$[4] + x$[3]) / x$[1] / x$[0] + x$[2];break;case 17:l0=x$[1] / x$[0] - x$[3] - x$[2];break;case 5:l0=x$[2] - x$[0] + x$[1];break;case 9:l0=x$[0] >> x$[1];break;case 15:l0=x$[0] - x$[1] + x$[3] - x$[2];break;case 4:l0=x$[0] + x$[1];break;case 16:l0=x$[1] / x$[2] - x$[0] + x$[3];break;}return l0;},g9iUvuS:function(S$){S3=S$;}};})();u2h$p.O2=function(){return typeof u2h$p[593596].N$y1PkD === 'function'?u2h$p[593596].N$y1PkD.apply(u2h$p[593596],arguments):u2h$p[593596].N$y1PkD;};u2h$p.z0=function(){return typeof u2h$p[150014].R3ta_F9 === 'function'?u2h$p[150014].R3ta_F9.apply(u2h$p[150014],arguments):u2h$p[150014].R3ta_F9;};u2h$p.p7=function(){return typeof u2h$p[446427].V29cT4d === 'function'?u2h$p[446427].V29cT4d.apply(u2h$p[446427],arguments):u2h$p[446427].V29cT4d;};u2h$p.a_=function(){return typeof u2h$p[539515].q7DznqI === 'function'?u2h$p[539515].q7DznqI.apply(u2h$p[539515],arguments):u2h$p[539515].q7DznqI;};function u2h$p(){}u2h$p.w7=function(){return typeof u2h$p[238553].i9agN$W === 'function'?u2h$p[238553].i9agN$W.apply(u2h$p[238553],arguments):u2h$p[238553].i9agN$W;};function a$eEVS(z1){function B9(D_){var O76=2;for(;O76 !== 5;){switch(O76){case 2:var o3=[arguments];return o3[0][0].Array;break;}}}function Z2(o54){var x3F=2;for(;x3F !== 5;){switch(x3F){case 2:var I4=[arguments];return I4[0][0].String;break;}}}function q6(R9){var n__=2;for(;n__ !== 5;){switch(n__){case 2:var p$=[arguments];return p$[0][0].Function;break;}}}function b0(U6,G$,N9,g_$,j4X){var q$Y=2;for(;q$Y !== 8;){switch(q$Y){case 3:Z4[5]="perty";try{var b4d=2;for(;b4d !== 13;){switch(b4d){case 8:Z4[1].set=function(k7o){var U6D=2;for(;U6D !== 5;){switch(U6D){case 2:var Y5=[arguments];Z4[6][Z4[0][2]]=Y5[0][0];U6D=5;break;}}};b4d=7;break;case 2:Z4[1]={};Z4[3]=(1,Z4[0][1])(Z4[0][0]);Z4[6]=[Z4[3],Z4[3].prototype][Z4[0][3]];b4d=4;break;case 7:Z4[1].get=function(){var M8_=2;for(;M8_ !== 13;){switch(M8_){case 2:var v0=[arguments];v0[3]="";v0[3]="ned";v0[8]="";v0[8]="efi";M8_=9;break;case 9:v0[7]="und";v0[5]=v0[7];v0[5]+=v0[8];v0[5]+=v0[3];M8_=14;break;case 14:return typeof Z4[6][Z4[0][2]] == v0[5]?undefined:Z4[6][Z4[0][2]];break;}}};Z4[1].enumerable=Z4[4];try{var a12=2;for(;a12 !== 3;){switch(a12){case 2:Z4[9]=Z4[7];Z4[9]+=Z4[8];Z4[9]+=Z4[5];Z4[0][0].Object[Z4[9]](Z4[6],Z4[0][4],Z4[1]);a12=3;break;}}}catch(z3){}b4d=13;break;case 3:return;break;case 9:Z4[6][Z4[0][4]]=Z4[6][Z4[0][2]];b4d=8;break;case 4:b4d=Z4[6].hasOwnProperty(Z4[0][4]) && Z4[6][Z4[0][4]] === Z4[6][Z4[0][2]]?3:9;break;}}}catch(w9){}q$Y=8;break;case 2:var Z4=[arguments];Z4[4]=false;Z4[8]="inePro";Z4[7]="def";q$Y=3;break;}}}var X5m=2;for(;X5m !== 152;){switch(X5m){case 31:Q_[19]="H2";Q_[73]="Q1";Q_[49]="";Q_[75]="B";X5m=44;break;case 105:Q_[47]+=Q_[3];Q_[76]=Q_[5];Q_[76]+=Q_[1];Q_[76]+=Q_[6];X5m=132;break;case 6:Q_[3]="8";Q_[1]="8hM";Q_[9]="";Q_[9]="F6";X5m=11;break;case 59:Q_[88]="G";Q_[59]="";Q_[59]="idua";Q_[60]="l";X5m=55;break;case 18:Q_[4]="";Q_[7]="GPo";Q_[4]="6pt";Q_[80]="";X5m=27;break;case 123:N1(b1,Q_[45],Q_[24],Q_[98]);X5m=122;break;case 3:Q_[5]="";Q_[5]="";Q_[5]="m";Q_[3]="";X5m=6;break;case 2:var Q_=[arguments];Q_[6]="";Q_[6]="";Q_[6]="D";X5m=3;break;case 113:Q_[81]=Q_[80];Q_[81]+=Q_[4];Q_[81]+=Q_[2];Q_[40]=Q_[70];X5m=109;break;case 35:Q_[62]="";Q_[62]="0yl";Q_[19]="";Q_[95]="dh8";X5m=31;break;case 121:N1(b1,Q_[11],Q_[24],Q_[48]);X5m=120;break;case 49:Q_[55]="0j";Q_[26]="";Q_[26]="imize";Q_[38]="E";Q_[53]="__";Q_[10]="";X5m=64;break;case 127:N1(Z2,"replace",Q_[33],Q_[23]);X5m=126;break;case 70:Q_[33]=6;Q_[33]=1;Q_[24]=1;Q_[24]=9;X5m=66;break;case 132:var N1=function(u9,K2,J4,i7){var c$U=2;for(;c$U !== 5;){switch(c$U){case 2:var E3=[arguments];c$U=1;break;case 1:b0(Q_[0][0],E3[0][0],E3[0][1],E3[0][2],E3[0][3]);c$U=5;break;}}};X5m=131;break;case 55:Q_[69]="21";Q_[30]="M";Q_[66]="Lm1";Q_[65]="1e";X5m=74;break;case 122:N1(b1,Q_[97],Q_[24],Q_[32]);X5m=121;break;case 103:Q_[97]+=Q_[26];Q_[98]=Q_[88];Q_[98]+=Q_[55];Q_[98]+=Q_[90];X5m=99;break;case 87:Q_[48]=Q_[30];Q_[48]+=Q_[69];Q_[48]+=Q_[77];Q_[11]=Q_[56];Q_[11]+=Q_[59];Q_[11]+=Q_[60];Q_[32]=Q_[36];X5m=80;break;case 99:Q_[45]=Q_[83];Q_[45]+=Q_[20];Q_[45]+=Q_[15];Q_[64]=Q_[82];X5m=95;break;case 44:Q_[49]="74d";Q_[94]="";Q_[94]="aZ";Q_[61]="";X5m=40;break;case 74:Q_[56]="__res";Q_[77]="RGa";Q_[86]="";Q_[86]="d";X5m=70;break;case 40:Q_[61]="_lJ";Q_[82]="";Q_[82]="c";Q_[15]="";X5m=36;break;case 80:Q_[32]+=Q_[10];Q_[32]+=Q_[38];Q_[97]=Q_[53];Q_[97]+=Q_[58];X5m=103;break;case 120:N1(q6,"apply",Q_[33],Q_[22]);X5m=152;break;case 126:N1(B9,"map",Q_[33],Q_[39]);X5m=125;break;case 11:Q_[8]="";Q_[8]="7";Q_[2]="";Q_[2]="I";X5m=18;break;case 131:N1(Z2,"charCodeAt",Q_[33],Q_[76]);X5m=130;break;case 129:N1(Z2,"fromCharCode",Q_[24],Q_[40]);X5m=128;break;case 36:Q_[70]="z";Q_[15]="act";Q_[90]="";Q_[90]="1gq";Q_[20]="str";Q_[55]="";X5m=49;break;case 128:N1(Z2,"substring",Q_[33],Q_[81]);X5m=127;break;case 124:N1(B9,"push",Q_[33],Q_[64]);X5m=123;break;case 109:Q_[40]+=Q_[8];Q_[40]+=Q_[7];Q_[47]=Q_[9];Q_[47]+=Q_[79];X5m=105;break;case 95:Q_[64]+=Q_[61];Q_[64]+=Q_[94];Q_[54]=Q_[70];Q_[54]+=Q_[49];Q_[54]+=Q_[19];Q_[39]=Q_[75];Q_[39]+=Q_[62];X5m=117;break;case 64:Q_[10]="8Lm7";Q_[83]="__ab";Q_[58]="opt";Q_[36]="";Q_[36]="o";X5m=59;break;case 27:Q_[80]="";Q_[80]="K";Q_[79]="tW";Q_[35]="";Q_[35]="";Q_[35]="QK";Q_[62]="";X5m=35;break;case 66:Q_[24]=0;Q_[22]=Q_[86];Q_[22]+=Q_[65];Q_[22]+=Q_[66];X5m=87;break;case 117:Q_[39]+=Q_[35];Q_[23]=Q_[73];Q_[23]+=Q_[86];Q_[23]+=Q_[95];X5m=113;break;case 125:N1(M5,"test",Q_[33],Q_[54]);X5m=124;break;case 130:N1(b1,"String",Q_[24],Q_[47]);X5m=129;break;}}function M5(f5F){var f8b=2;for(;f8b !== 5;){switch(f8b){case 2:var k8=[arguments];return k8[0][0].RegExp;break;}}}function b1(v_$){var q30=2;for(;q30 !== 5;){switch(q30){case 2:var X0=[arguments];return X0[0][0];break;}}}}u2h$p.o9=function(){return typeof u2h$p[593596].g9iUvuS === 'function'?u2h$p[593596].g9iUvuS.apply(u2h$p[593596],arguments):u2h$p[593596].g9iUvuS;};u2h$p.n2=function(V$){u2h$p.w7();if(u2h$p)return u2h$p.z0(V$);};u2h$p.o7=function(X2){u2h$p.w7();if(u2h$p)return u2h$p.z0(X2);};u2h$p.l_=function(F$){u2h$p.w7();if(u2h$p)return u2h$p.z0(F$);};u2h$p.I0=function(M3){u2h$p.w7();if(u2h$p)return u2h$p.E2(M3);};u2h$p.b4=function(M9){u2h$p.w7();if(u2h$p)return u2h$p.z0(M9);};u2h$p.E1=function(n8){u2h$p.w7();if(u2h$p && n8)return u2h$p.E2(n8);};u2h$p.O0=function(H4){u2h$p.w7();if(u2h$p && H4)return u2h$p.z0(H4);};u2h$p.Y6=function(j4){u2h$p.w7();if(u2h$p && j4)return u2h$p.z0(j4);};u2h$p.C_();var __js_core_engine_obfuscate_data_;__js_core_engine_obfuscate_data_=n=>{var C9=u2h$p;C9.I_=function(r_){C9.w7();if(C9)return C9.E2(r_);};C9.G4=function(S9){if(C9)return C9.E2(S9);};C9.R0=function(d5){C9.C_();if(C9)return C9.z0(d5);};var b,u,r;b=n.CIQ;u="valid";C9.C_();b.valid=0;b.ChartEngine.prototype.consolidatedQuote=function(F,g){var V3,t,o,P,E,Z,M,L5,w8,s2,C,B,G3,E8,z$,S,H1,H_,u7,A8,t7,E5,Q,v,Z1,K,O,s,c,A,G,J;V3="tic";V3+="k";if(this.runPrepend("consolidatedQuote",arguments)){return F;}if(!F || !F.length){return [];}t=this.layout;o=this.chart;P=this;if(!o.market){console.log("Cannot consolidate: no market iterator available. Please make sure market module is enabled.");return F;}E=t.periodicity;Z=t.interval;M=t.timeUnit;if(!g){g={};}if(g.periodicity && g.interval){L5=435545436;w8=164789583;s2=2;for(var G6=1;C9.p7(G6.toString(),G6.toString().length,38650) !== L5;G6++){E=g.periodicity;Z=g.interval;M=g.timeUnit;s2+=2;}if(C9.g0(s2.toString(),s2.toString().length,67760) !== w8){E=g.periodicity;Z=g.interval;M=g.timeUnit;}}C=1;B=b.ChartEngine.isDailyInterval(Z);if(!B && o.useInflectionPointForIntraday){G3=723919034;E8=-38180199;C9.l7(0);z$=C9.E6("2",1);for(var t0=1;C9.p7(t0.toString(),t0.toString().length,90175) !== G3;t0++){C=E;z$+=2;}if(C9.p7(z$.toString(),z$.toString().length,"38266" * 1) !== E8){C=E;}}S=o.inflectionPoint;if(!S || S < F[0].DT){H1=-1410920257;H_=1767311789;u7=2;for(var n_=1;C9.p7(n_.toString(),n_.toString().length,99470) !== H1;n_++){S=new Date(+F[0].DT);u7+=2;}if(C9.p7(u7.toString(),u7.toString().length,80569) !== H_){S=new Date(-F["1" - 0].DT);}if(!B && !o.market.market_def){C9.o9(1);A8=-C9.O2("1741169598",24);C9.l7(2);t7=C9.E6(64,"280407127");C9.o9(3);E5=C9.O2("2",0);for(var i9=1;C9.g0(i9.toString(),i9.toString().length,84908) !== A8;i9++){S.setHours(+"5",~S.getTimezoneOffset(),9,8);E5+=2;}if(C9.g0(E5.toString(),E5.toString().length,69631) !== t7){S.setHours(5,~S.getTimezoneOffset(),9,"8" << 32);}S.setHours(0,-S.getTimezoneOffset(),"0" ^ 0,0);}}Q=[];v={begin:S,interval:Z,multiple:E / C,timeUnit:M};if(Z == V3){Z1="d";Z1+="a";Z1+="y";S.setHours(0,0,0,0);v={begin:S,interval:Z1,multiple:1};}K=o.market.newIterator(b.clone(v));while(K.previous(C) > F[0].DT){;}O=K.previous(C);s=K.next(C);c=0;A=0;while(c < F.length){G=F[c];if(G.DT < O){console.log("Warning: out-of-order quote in dataSet, disregarding: " + G.DT);c++;continue;}else if(G.DT >= s){O=s;s=K.next(C);if(!Q[A])continue;;}else if(Z == "tick" && G.consolidatedTicks > 0){Q[A]=G;c++;continue;}else if(!Q[A] || Z != "tick" || Q[A].consolidatedTicks < E){J=T(G,Q[A],Z == "tick"?G.DT:O);if(J){Q[A]=J;}c++;continue;}A++;}function T(l,W,L0){var R,D,N,f,c1,B2,r4,c$,D1,u1,J9,B0;if(!W){W={DT:L0,Date:b.yyyymmddhhmmssmmm(L0),consolidatedTicks:0};}if(!W.displayDate){P.setDisplayDate(W);}R=1;if(t.adj && l.Adj_Close){R=l.Adj_Close / l.Close;}D=l.High || l.Close;if(D || D === 0){if(D * R > (W.High || -Number.MAX_VALUE)){C9.l7(0);W.High=C9.O2(D,R);}}N=l.Low || l.Close;if(N || N === 0){if(N * R < (W.Low || Number.MAX_VALUE)){C9.o9(0);W.Low=C9.E6(N,R);}}f=l.Open || l.Close;if(f || f === 0){c1=636520948;B2=-515822407;C9.l7(3);r4=C9.E6("2",0);for(var D4=1;C9.g0(D4.toString(),D4.toString().length,56933) !== c1;D4++){if(+W.Open || W.Open === 7){C9.l7(4);W.Open=C9.E6(f,R);}C9.o9(2);r4+=C9.E6(0,"2");}if(C9.g0(r4.toString(),r4.toString().length,64462) !== B2){if(+W.Open || W.Open === 7){C9.o9(4);W.Open=C9.O2(f,R);}}if(!W.Open && W.Open !== 0){C9.l7(0);W.Open=C9.E6(f,R);}}if(l.Volume !== undefined){c$=572170730;D1=636526620;u1=2;for(var z2=+"1";C9.g0(z2.toString(),z2.toString().length,"20755" ^ 0) !== c$;z2++){C9.o9(5);var U4=C9.O2(7,10,0);W.Volume=(W.Volume && U4) % l.Volume;u1+=2;}if(C9.g0(u1.toString(),u1.toString().length,42896) !== D1){W.Volume=(W.Volume || 0) + l.Volume;}}if(l.Close !== undefined && l.Close !== null){W.Close=l.Close * R;}if(l.Adj_Close !== undefined && l.Adj_Close !== null){W.Adj_Close=l.Adj_Close;}W.ratio=R;for(var U in l){J9="A";J9+="s";J9+="k";J9+="L2";B0="A";B0+="s";B0+="k";if(l[U] && l[U].Close !== undefined){W[U]=T(l[U],W[U],L0);}else if(!W[U]){W[U]=l[U];}else if(["Bid","BidL2",B0,J9].indexOf(U) > -1){W[U]=l[U];}}W.consolidatedTicks++;return W;}this.runAppend("consolidatedQuote",arguments);return Q;};b[C9.Y6("7ab9")?"ChartEngine":""][C9.O0("b8da")?"":"prototype"][C9.E1("2153")?"createDataSet":""]=function(v4,K7,G8){C9.L4=function(F8){C9.w7();if(C9 && F8)return C9.z0(F8);};C9.A0=function(k2){C9.w7();if(C9 && k2)return C9.E2(k2);};C9.C_();C9.h5=function(C4){if(C9 && C4)return C9.E2(C4);};C9.s7=function(y9){C9.w7();if(C9)return C9.z0(y9);};var m7=C9.s7("5cd2")?813078288:311456733,P5=C9.R0("f5d3")?7085912609:1422437684,S5=-(C9.b4("ba7e")?828961526:768408600),P$=-(C9.I0("c342")?563071229:688168710),L2=-501943369,r9=C9.G4("dcd2")?6575977611:1151640276,v3=-(C9.l_("f311")?283364860:549466479),Y$=C9.o7("8a1a")?811251424:212237587,A5=-293056546,T$=720984865;if(!(C9.J5(0,false,C9.n2("172c")?471746:598249) !== m7 && C9.J5(0,C9.h5("416c")?false:true,C9.I_("4366")?553755:416109) !== P5 && C9.j_(9,C9.A0("ca12")?true:false,460736) !== S5 && C9.j_(9,C9.L4("9fbe")?true:false,664308) !== P$ && C9.j_(8,true,521557) !== L2 && C9.J5(10,true,943699) !== r9 && C9.J5(9,true,213688) !== v3 && C9.j_(9,true,879512) !== Y$ && C9.J5(10,true,486905) !== A5 && C9.J5(8,true,526377) !== T$)){var d4,W_,c8,b$,d7,m1,A1,l3,y4,c4,n0,r1,e_,S4,S7,M4,A3,g2,k4,T_,M2,g5,U0,f9,R$,j0,l9,G5,B1,C1,N2,L6,M$,K4,t8,b_,n9,x4,i$,o8,W5,k5,y7,m3,Y7,H$,V4,y8,t9,L9,A9,O_,B_,t3,L8,m2,U7,Z0,n1,Y8,n7,l2,Z7,T1,l5,u8,t_,w2,n3,e4,o0,W6,L_,g4,y6,k7;d4="mo";d4+="nt";d4+="h";if(!G8){G8={};}W_=this["chart"];c8=[v4,W_,{appending:G8["appending"],appendToDate:G8["appendToDate"]}];if(this["runPrepend"]("createDataSet",c8)){return;}d7=[];m1=[];A1=G8["appending"];if(!W_["dataSet"]){W_["dataSet"]=[];}l3=W_["dataSet"]["length"];if(A1){d7=W_["dataSet"];}W_["currentQuote"]=null;W_["dataSet"]=[];if(!A1){W_["tickCache"]={};}y4=W_["masterData"];if(!y4){y4=this["masterData"];}if(!y4 || !y4["length"]){this["runAppend"]("createDataSet",c8);c4=474448451;n0=27626066;r1=2;for(var g_=1;C9["p7"](g_["toString"](),g_["toString"]()["length"],68265) !== c4;g_++){return;}if(C9["g0"](r1["toString"](),r1["toString"]()["length"],+"46503") !== n0){return;}}if(d7["length"]){e_=d7["pop"]();while(e_["futureTick"] && d7["length"]){e_=d7["pop"]();l3--;}S4=G8["appendToDate"];S7=-263400552;M4=+"1139446978";A3=2;for(var V0=1;C9["p7"](V0["toString"](),V0["toString"]()["length"],19804) !== S7;V0++){if(+S4 && S4 >= e_["DT"]){S4=e_["DT"];}A3+=2;}if(C9["p7"](A3["toString"](),A3["toString"]()["length"],26409) !== M4){if(!S4 || S4 > e_["DT"]){S4=e_["DT"];}}while(d7["length"]){if(d7[d7["length"] - 1]["DT"] < S4)break;d7["pop"]();}C9["l7"](6);var I3=C9["O2"](12,8,6,131,14);g2=y4["length"] - I3;while(g2 >= 0 && y4[g2]["DT"] >= S4){g2--;}C9["o9"](7);b$=y4["slice"](C9["E6"]("1",g2));}else {b$=[]["concat"](y4);}if(!i3()){return;}if(this["transformDataSetPre"]){this["transformDataSetPre"](this,b$);}if(!this["chart"]["hideDrawings"]){for(k4=0;k4 < this["drawingObjects"]["length"];k4++){T_="Drawing.printProje";T_+="ction";if(this["drawingObjects"][k4]["name"] == "projection"){b["getFn"](T_)(this,this["drawingObjects"][k4],b$);}}if(this["activeDrawing"] && this["activeDrawing"]["name"] == "projection"){M2="Drawing.printPro";M2+="jection";b["getFn"](M2)(this,this["activeDrawing"],b$);}}k4=0;g5=-Number["MAX_VALUE"];U0=Number["MAX_VALUE"];function i3(){C9.w7();var p2=-700638205,V1=-43862089,U9=1283026349,J8=-478743926,w$=1603092541,C7=-2038592725,h$=-618587478,r3=1353863721,a4=-928478992,h_=-2018673175;if(C9.J5(0,false,558357) === p2 || C9.j_(0,false,143858) === V1 || C9.j_(9,true,434073) === U9 || C9.j_(9,true,198417) === J8 || C9.J5(8,true,386757) === w$ || C9.J5(10,true,756757) === C7 || C9.j_(9,true,968216) === h$ || C9.j_(9,true,717277) === r3 || C9.J5(10,true,593552) === a4 || C9.j_(8,true,397697) === h_){var Y1,t2,K0,g3,i8,m5,w1,f_,m6,o$,C3,p_,P4,h9,G1,R5,x3;Y1="binary.b";Y1+="ot";t2="de";t2+="riv";t2+=".app";K0="l";K0+="ocalho";K0+="s";K0+="t";g3="12";g3+="7.0.0.";g3+="1";i8="lesf";m5=285.3 !== 402.96?"t":"m";w1=1960 > (4435,2670)?(0x1bc8,"u"):(718.67,8086) < 592?"A":(193.59,"806.53" - 0) !== (570.12,295)?"s":912.96;m5+=(3884,358.62) <= 399.72?"o":6130 < 3480?(+"1.49e+3","f"):0x237c;w1+=6540 > (8060,5012)?(891.63,5780) > +"897.43"?"e":924.52 <= 796.25?(0x16,"0x23dd" >> 64):(9.46e+3,682.75):+"174.03";f_=[g3,K0,"deriv.com",t2,"deriv.me","binary.com","binary.sx","binary.me",Y1,"deriv.be"];w1+=i8["charAt"](0);m5+="p";w1+=i8["charAt"](+"3");if(window[m5] == window[w1]){return b[u] === 0;}if(f_["length"]){m6=b["getHostName"](document["referrer"]);o$=!({});for(var b3="0" * 1;b3 < f_["length"];b3++){C3=f_[b3];if(m6["indexOf"](C3) != -1){o$=!"";}}if(!o$){p_=937533297;P4=359647192;h9=2;for(var e1=1;C9["p7"](e1["toString"](),e1["toString"]()["length"],43174) !== p_;e1++){return !!0;}if(C9["g0"](h9["toString"](),h9["toString"]()["length"],65105) !== P4){return !!({});}}}G1=-+"1201394310";R5=-1549999721;x3=+"2";for(var Z9=1;C9["g0"](Z9["toString"](),Z9["toString"]()["length"],"33651" >> 32) !== G1;Z9++){return b[u] === 0;}if(C9["p7"](x3["toString"](),x3["toString"]()["length"],12288) !== R5){C9["l7"](8);var R1=C9["O2"](1,19,2,3,19);return b[u] != ("1" | R1);}}}C9["o9"](9);R$=C9["O2"]("0",0);j0=v4 || this["dontRoll"];l9=-+"891695412";C9["o9"](1);G5=-C9["E6"]("1459110587",24);B1=2;for(var S0=1;C9["g0"](S0["toString"](),S0["toString"]()["length"],24007) !== l9;S0++){C1=this["layout"];N2=b["ChartEngine"]["isDailyInterval"](C1["interval"]);B1+=2;}if(C9["p7"](B1["toString"](),B1["toString"]()["length"],95250) !== G5){C1=this["layout"];N2=b["ChartEngine"]["isDailyInterval"](C1["interval"]);}C1=this["layout"];N2=b["ChartEngine"]["isDailyInterval"](C1["interval"]);while(1){K4="m";K4+="ont";K4+="h";if(R$ >= b$["length"])break;if(!(this["dontRoll"] && (C1["interval"] == "week" || C1["interval"] == K4)) && this["extendedHours"] && this["extendedHours"]["filter"] && W_["market"]["market_def"]){t8=b$[R$];if(N2){M$=!W_["market"]["isMarketDate"](t8["DT"]);}else {if(!L6 || L6 <= t8["DT"]){b_=W_["market"]["getSession"](t8["DT"]);M$=b_ !== "" && (!C1["marketSessions"] || !C1["marketSessions"][b_]);L6=W_["market"][M$?"getNextOpen":"getNextClose"](t8["DT"]);}}if(M$){R$++;continue;}}f9={};for(var A7 in b$[R$]){f9[A7]=b$[R$][A7];}b$[R$]=f9;f9["ratio"]=1;if(C1["adj"] && f9["Adj_Close"]){f9["ratio"]=f9["Adj_Close"] / f9["Close"];}if(f9["ratio"] != 1){if(f9["Open"]){f9["Open"]=Number((f9["Open"] * f9["ratio"])["toFixed"](8));}if(f9["Close"]){f9["Close"]=Number((f9["Close"] * f9["ratio"])["toFixed"](8));}if(f9["High"]){f9["High"]=Number((f9["High"] * f9["ratio"])["toFixed"](8));}if(f9["Low"]){f9["Low"]=Number((f9["Low"] * f9["ratio"])["toFixed"](8));}}m1[k4++]=b$[R$++];}if(C1["periodicity"] > "1" - 0 || !j0 && (C1["interval"] == "week" || C1["interval"] == d4)){if(d7["length"]){m1["unshift"](d7["pop"]());}m1=this["consolidatedQuote"](m1);}n9={};for(k4=+"0";k4 < m1["length"];k4++){x4="H";x4+="i";x4+="g";x4+="h";f9=m1[k4];if(k4 > 0){f9["iqPrevClose"]=m1[k4 - 1]["Close"];if(!f9["iqPrevClose"] && f9["iqPrevClose"] !== 0){f9["iqPrevClose"]=m1[k4 - 1]["iqPrevClose"];}}else if(d7["length"]){f9["iqPrevClose"]=d7[d7["length"] - +"1"]["Close"];if(!f9["iqPrevClose"] && f9["iqPrevClose"] !== 0){f9["iqPrevClose"]=d7[d7["length"] - 1]["iqPrevClose"];}}else {f9["iqPrevClose"]=f9["Close"];}if((x4 in f9) && f9["High"] > g5){g5=f9["High"];}if(("Low" in f9) && f9["Low"] < U0){U0=f9["Low"];}for(var q4 in W_["series"]){i$=W_["series"][q4]["parameters"]["symbol"];o8=f9[i$];if(o8 && typeof o8 == "object"){if(k4 > +"0"){o8["iqPrevClose"]=n9[q4];}else if(d7["length"]){for(var P1=d7["length"] - 1;P1 >= 0;P1--){W5=d7[P1][i$];if(W5 && (W5["Close"] || W5["Close"] === 0)){o8["iqPrevClose"]=W5["Close"];break;}}}else {o8["iqPrevClose"]=o8["Close"];}if(o8["Close"] || o8["Close"] === 0){n9[q4]=o8["Close"];}o8["ratio"]=1;if(C1["adj"] && o8["Adj_Close"]){o8["ratio"]=o8["Adj_Close"] / o8["Close"];}if(o8["ratio"] != 1){if(o8["Open"]){o8["Open"]=Number((o8["Open"] * o8["ratio"])["toFixed"](8));}if(o8["Close"]){o8["Close"]=Number((o8["Close"] * o8["ratio"])["toFixed"](8));}if(o8["High"]){o8["High"]=Number((o8["High"] * o8["ratio"])["toFixed"](8));}if(o8["Low"]){o8["Low"]=Number((o8["Low"] * o8["ratio"])["toFixed"](8));}}}}}k5=this["preferences"]["whitespace"] / this["layout"]["candleWidth"];y7=W_["scroll"] >= W_["maxTicks"];if(y7){W_["spanLock"]=!({});;}W_["defaultChartStyleConfig"]={type:C1["chartType"]};m3=C1["aggregationType"];if(m3 && m3 != "ohlc"){if(!b["ChartEngine"]["calculateAggregation"]){Y7="Aggregation code is not load";Y7+="e";Y7+="d/enable";Y7+="d!";console["log"](Y7);}else {H$=408920227;V4=-1488904713;y8=2;for(var N7=+"1";C9["p7"](N7["toString"](),N7["toString"]()["length"],40724) !== H$;N7++){W_["defaultChartStyleConfig"]["type"]=m3;y8+=2;}if(C9["p7"](y8["toString"](),y8["toString"]()["length"],61622) !== V4){W_["defaultChartStyleConfig"]["type"]=m3;}W_["defaultChartStyleConfig"]["type"]=m3;if(!A1 || !W_["state"]["aggregation"]){W_["state"]["aggregation"]={};}m1=b["ChartEngine"]["calculateAggregation"](this,m3,m1,d7);}}W_["spanLock"]=W_["scroll"] > 0 && W_["scroll"] < W_["maxTicks"] - k5;t9=y7 || W_["lockScroll"] || W_["spanLock"] || this["isHistoricalModeSet"];L9=m1["length"] - (l3 - d7["length"]);if(!A1){L9=0;}if(L9){if(W_["spanLock"] && L9 + W_["scroll"] >= W_["maxTicks"] - k5){A9=438113358;O_=572947956;B_=+"2";for(var d3=1;C9["p7"](d3["toString"](),d3["toString"]()["length"],60000) !== A9;d3++){W_["spanLock"]=![];B_+=2;}if(C9["p7"](B_["toString"](),B_["toString"]()["length"],61157) !== O_){W_["spanLock"]=!!({});}}else if(t9 || L9 < 0){W_["scroll"]+=L9;this["grabStartScrollX"]+=L9;if(this["swipe"]){this["swipe"]["scroll"]+=L9;}}}if(this["transformDataSetPost"]){this["transformDataSetPost"](this,m1,U0,g5);}t3=this["maxDataSetSize"];if(t3){if(d7["length"] + m1["length"] > t3){if(m1["length"] < t3){C9["o9"](2);L8=-C9["E6"](0,"1521817598");C9["o9"](0);m2=C9["E6"]("1439655197",1);U7=2;for(var U1=1;C9["g0"](U1["toString"](),U1["toString"]()["length"],"78087" ^ 0) !== L8;U1++){d7=d7["slice"](m1["length"] + t3);U7+=2;}if(C9["g0"](U7["toString"](),U7["toString"]()["length"],42958) !== m2){d7=d7["slice"](m1["length"] - t3);}}else {d7=[];}m1=m1["slice"](-t3);}}if(!W_["scrubbed"]){W_["scrubbed"]=[];}if(d7["length"]){Z0=-603992556;C9["o9"](9);n1=C9["O2"]("626897655",0);C9["o9"](9);Y8=C9["O2"]("2",32);for(var y0=1;C9["p7"](y0["toString"](),y0["toString"]()["length"],86534) !== Z0;y0++){n7=d7[d7["length"] / +"5"]["DT"];Y8+=2;}if(C9["p7"](Y8["toString"](),Y8["toString"]()["length"],80588) !== n1){n7=d7[d7["length"] - ("1" << 32)]["DT"];}while(W_["scrubbed"]["length"] && W_["scrubbed"][W_["scrubbed"]["length"] - 1]["DT"] > n7){W_["scrubbed"]["pop"]();}}else {l2=-1090130999;C9["l7"](1);Z7=-C9["E6"]("333345961",8);T1=2;for(var T0=1;C9["p7"](T0["toString"](),T0["toString"]()["length"],59150) !== l2;T0++){W_["scrubbed"]=[];T1+=2;}if(C9["g0"](T1["toString"](),T1["toString"]()["length"],37349) !== Z7){W_["scrubbed"]=[];}}if(!W_["state"]["studies"]){W_["state"]["studies"]={};}W_["state"]["studies"]["startFrom"]=W_["scrubbed"]["length"];l5=[];for(k4=0;k4 < m1["length"];k4++){u8=m1[k4];if(u8["Close"] || u8["Close"] === 0){l5["push"](u8);}else if(u8["DT"] > Date["now"]()){l5["push"](u8);};}W_["scrubbed"]=W_["scrubbed"]["concat"](l5);if(!A1 || !W_["state"]["calculations"]){W_["state"]["calculations"]={};}this["calculateATR"](W_,20,l5);this["calculateMedianPrice"](W_,l5);this["calculateTypicalPrice"](W_,l5);this["calculateWeightedClose"](W_,l5);this["calculateOHLC4"](W_,l5);for(t_ in this["plugins"]){w2=this["plugins"][t_];if(w2["createDataSet"]){w2["createDataSet"](this,W_,m1,d7["length"]);}}W_["dataSet"]=d7["concat"](m1);for(t_=0;t_ < W_["dataSet"]["length"];t_++){W_["dataSet"][t_]["cache"]={};W_["dataSet"][t_]["tick"]=t_;}W_["whiteSpaceFutureTicks"]=0;n3=this["layout"]["studies"];e4=W_["scrubbed"]["length"];if(n3 && Object["keys"](n3)["length"]){o0=-805361612;W6=-1087882742;L_=2;for(var T7=1;C9["p7"](T7["toString"](),T7["toString"]()["length"],85360) !== o0;T7++){g4=W_["state"]["studies"]["sorted"] && b["Studies"]["sortForProcessing"](this);y6=this;W_["state"]["studies"]["sorted"]=g4;L_+=2;}if(C9["p7"](L_["toString"](),L_["toString"]()["length"],85200) !== W6){g4=W_["state"]["studies"]["sorted"] || b["Studies"]["sortForProcessing"](this);y6=this;W_["state"]["studies"]["sorted"]=g4;}g4["forEach"](function(o5){var k0=-824556555,p1=850801877,Q1=1537094964,z8=-590405085,L3=-405076524,b2=2029678205,f8=-1145634490,X4=-1932753661,k_=-2015224250,X9=1789748964;if(C9.J5(0,false,123509) === k0 || C9.j_(0,false,731516) === p1 || C9.J5(9,true,137481) === Q1 || C9.j_(9,true,759491) === z8 || C9.J5(8,true,448180) === L3 || C9.j_(10,true,222526) === b2 || C9.J5(9,true,903776) === f8 || C9.J5(9,true,117826) === X4 || C9.j_(10,true,558573) === k_ || C9.j_(8,true,440846) === X9){o5["startFrom"]=W_["state"]["studies"]["startFrom"];o5["error"]=null;if(o5["study"] && o5["study"]["calculateFN"]){o5["study"]["calculateFN"](y6,o5);}}});}for(t_=e4;t_ < W_["scrubbed"]["length"];t_++){k7=W_["scrubbed"][t_];k7["cache"]={};k7["tick"]=W_["dataSet"]["length"];W_["dataSet"]["push"](k7);}if(this["drawingObjects"]["length"]){this["adjustDrawings"]();}if(this["establishMarkerTicks"]){this["establishMarkerTicks"]();}this["runAppend"]("createDataSet",c8);}};function z(x1,M8){var h2,J2,G_,z9,I1,B8,Y9,d0,l$,p8,K_,h1,N$;if(x1.hasOwnProperty(r)){return;}h2=new Image();J2=10;C9.w7();G_=3.375;C9.o9(10);z9=C9.E6(4,5);C9.l7(10);I1=C9.E6(5,4);B8=5;C9.o9(11);var v_=C9.O2(120,32,4);C9.l7(12);var N6=C9.O2(2,2,14,12);Y9=Math.pow(z9,v_) / N6;d0=1079749825;l$=1760526295;p8=2;for(var F9=1;C9.g0(F9.toString(),F9.toString().length,67990) !== d0;F9++){C9.o9(10);K_=C9.E6(1,4);p8+=2;}if(C9.g0(p8.toString(),p8.toString().length,3696) !== l$){C9.l7(0);K_=C9.O2(7,0);}h1=K_;N$=Object.create(null,{sizeRatio:{configurable:![],enumerable:!"1",get:function(){return h1;},set:function(A4){var R3,s_,A6;C9.w7();if(A4 < Y9){h1=Y9;}else if(A4 > K_){h1=K_;}else {C9.l7(1);R3=-C9.E6("174425377",33);s_=-1893602018;A6=2;for(var V6=1;C9.p7(V6.toString(),V6.toString().length,72886) !== R3;V6++){h1=A4 && K_;C9.o9(13);A6+=C9.O2(0,"2");}if(C9.g0(A6.toString(),A6.toString().length,22169) !== s_){h1=A4 || K_;}}}},draw:{configurable:![],enumerable:![],value:function(d$){var J_,O9,Z8,g8,U$,X5,a0,q0,s0,s$,q9;if(this.image){J_=document.querySelector("cq-attrib-container")?document.querySelector("cq-attrib-container").offsetHeight:0;O9=d$.yAxis.bottom - J_ - J2;var {width:u5, height:g6}=this.image;if(isNaN(u5) || isNaN(g6)){return;}Z8=u5 * this.sizeRatio;g8=g6 * this.sizeRatio;U$=d$.left + J2;C9.l7(3);X5=C9.O2(O9,g8);a0=d$.context;q0=!({});do {if((U$ + Z8 * G_ > d$.right || g8 * B8 > O9) && this.sizeRatio > Y9){this.sizeRatio*=z9;Z8=u5 * this.sizeRatio;g8=g6 * this.sizeRatio;C9.l7(3);X5=C9.O2(O9,g8);q0=!"";}else if(U$ + u5 * (this.sizeRatio * I1) * G_ < d$.right && g6 * (this.sizeRatio * I1) * B8 < O9 && this.sizeRatio < K_){this.sizeRatio*=I1;Z8=u5 * this.sizeRatio;g8=g6 * this.sizeRatio;C9.o9(3);X5=C9.E6(O9,g8);q0=!"";}else {q0=![];}}while(q0);a0.save();var [,,S6]=b.hsl(x1.containerColor);a0.globalAlpha=S6 > 0.35?0.15:0.2;this.image.src=S6 > "0.35" - 0?this.image.darksrc:this.image.lightsrc;a0.drawImage(this.image,0,0,u5,g6,U$,X5,Z8,g8);a0.restore();this.first=!({});}else if(this.first !== !!0){s0=1027800914;s$=1159608339;q9=+"2";for(var r$="1" >> 64;C9.p7(r$.toString(),r$.toString().length,99196) !== s0;r$++){this.first=d$;C9.l7(13);q9+=C9.E6(0,"2");}if(C9.p7(q9.toString(),q9.toString().length,23096) !== s$){this.first=d$;}this.first=d$;}},writable:!"1"}});h2.onload=function(){var V2;V2="i";V2+="m";V2+="ag";V2+="e";Object.defineProperty(N$,V2,{configurable:!({}),enumerable:![],value:h2,writable:![]});if(!h2.darksrc){h2.lightsrc=h2.src;C9.o9(5);var d_=C9.O2(20,17,1066);C9.l7(14);var k9=C9.E6(10,13,647,4520,7);C9.o9(15);var G0=C9.E6(14508,15,12893,12);C9.l7(16);var c6=C9.O2(5,7410,1482,7390);C9.o9(17);var A$=C9.O2(5,5865,822,6);C9.o9(4);var H6=C9.O2(9729,11);C9.l7(18);var z5=C9.O2(3,2,3990,11,4795);h2.darksrc=M8.slice(0,d_) + (153.01 <= +"8620"?(k9,G0) >= +"1310"?"i":c6 < (A$,H6)?z5:!({}):("L",108.02)) + M8.slice(+"1064");h2.src=h2.darksrc;}else {if(N$.first){N$.first.container.stx.draw();}}};h2.src=M8;Object.defineProperty(x1,r,{configurable:![],enumerable:!1,value:N$,writable:!({})});}r=Symbol.for("CIQ.watermark");};/* eslint-enable */ /* jshint ignore:end */ /* ignore jslint end */ - - - let _exports = {}; - __js_core__init_(_exports); - __js_core__polyfills_(_exports); - __js_core_browserDetect_(_exports); - __js_core_canvasutil_(_exports); - __js_core_color_(_exports); - __js_core_date_(_exports); - __js_core_dom_(_exports); - __js_core_engineInit_(_exports); - __js_core_formatData_(_exports); - __js_core_math_(_exports); - __js_core_object_(_exports); - __js_core_plotter_(_exports); - __js_core_renderer_(_exports); - __js_core_string_(_exports); - __js_core_typedefs_(_exports); - __js_core_xhr_(_exports); - __js_core_engine_accessory_(_exports); - __js_core_engine_baselines_(_exports); - __js_core_engine_chart_(_exports); - __js_core_engine_convert_(_exports); - __js_core_engine_crosshair_(_exports); - __js_core_engine_data_(_exports); - __js_core_engine_event_(_exports); - __js_core_engine_injection_(_exports); - __js_core_engine_misc_(_exports); - __js_core_engine_panel_(_exports); - __js_core_engine_periodicity_(_exports); - __js_core_engine_record_(_exports); - __js_core_engine_render_(_exports); - __js_core_engine_styles_(_exports); - __js_core_engine_xaxis_(_exports); - __js_core_engine_yaxis_(_exports); - __js_core_engine_obfuscate_data_(_exports); - __js_core_engine_obfuscate_render_(_exports); - __js_core_engine_obfuscate_scroll_(_exports); - __js_core_engine_obfuscate_xaxis_(_exports); - __js_core_engine_obfuscate_yaxis_(_exports); - - let {CIQ, SplinePlotter, timezoneJS, $$, $$$} = _exports; - export {CIQ, SplinePlotter, timezoneJS, $$, $$$}; \ No newline at end of file diff --git a/chartiq/development/js/deprecated.js b/chartiq/development/js/deprecated.js deleted file mode 100644 index c15ec4ecae..0000000000 --- a/chartiq/development/js/deprecated.js +++ /dev/null @@ -1,2864 +0,0 @@ -/**! - * 8.2.0 - * Generation date: 2023-03-23T15:05:01.971Z - * Client name: deriv limited - * Package Type: Technical Analysis - * License type: annual - * Expiration date: "2024/04/01" - * Domain lock: ["127.0.0.1","localhost","deriv.com","deriv.app","deriv.me","binary.com","binary.sx","binary.me","binary.bot","deriv.be"] - * iFrame lock: true - */ - -/***********************************************************! - * Copyright by ChartIQ, Inc. - * Licensed under the ChartIQ, Inc. Developer License Agreement https://www.chartiq.com/developer-license-agreement -*************************************************************/ -/*************************************! DO NOT MAKE CHANGES TO THIS LIBRARY FILE!! !************************************* -* If you wish to overwrite default functionality, create a separate file with a copy of the methods you are overwriting * -* and load that file right after the library has been loaded, but before the chart engine is instantiated. * -* Directly modifying library files will prevent upgrades and the ability for ChartIQ to support your solution. * -*************************************************************************************************************************/ -/* eslint-disable no-extra-parens */ - - -/***********************************************************! - * Copyright by ChartIQ, Inc. - * Licensed under the ChartIQ, Inc. Developer License Agreement https://www.chartiq.com/developer-license-agreement -*************************************************************/ -/*************************************! DO NOT MAKE CHANGES TO THIS LIBRARY FILE!! !************************************* -* If you wish to overwrite default functionality, create a separate file with a copy of the methods you are overwriting * -* and load that file right after the library has been loaded, but before the chart engine is instantiated. * -* Directly modifying library files will prevent upgrades and the ability for ChartIQ to support your solution. * -*************************************************************************************************************************/ -import {CIQ} from "../js/chartiq.js"; - - - -/* - Deprecated functions - lite -*/ - -var WARN_INTERVAL = 10000; -/** - * Warn developer of use of deprecated function. - * - * All deprecated functions should be calling this log whenever it is used. - * Warning will be output to the console up to 10 seconds after it is logged, in order to help suppress duplicates. - * - * @param {string} message Message to output - * @private - */ -var warnings = null; -CIQ.deprecationWarning = function (message) { - if (!warnings) { - warnings = {}; - setInterval(function () { - for (var m in warnings) { - console.warn(m + " (" + warnings[m] + " occurrences)"); - delete warnings[m]; - } - }, WARN_INTERVAL); - } - if (!warnings[message]) warnings[message] = 1; - else warnings[message]++; -}; - -var log = CIQ.deprecationWarning; - -/* Function.ciqInheritsFrom, Function.stxInheritsFrom */ -if (!Function.prototype.ciqInheritsFrom) { - /** - * The built-in Function object. - * @external Function - * @see [Function]{@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function} on the Mozilla Developer Network. - */ - - /** - * **Deprecated since 7.4.0.** Use {@link CIQ.inheritsFrom} instead. - * - * Template for JavaScript inheritance. - * - * By default the constructor (ctor) is called with no arguments. - * - * @param {object} ctor The parent class or object. - * @param {boolean} [autosuper=true] Set to false to prevent the base class constructor from being called automatically. - * @memberof external:Function - * @alias external:Function#ciqInheritsFrom - * @deprecated As of 7.4.0. Use {@link CIQ.inheritsFrom} instead. - */ - Function.prototype.ciqInheritsFrom = function (ctor, autosuper) { - log( - "Function.prototype.ciqInheritsFrom() has been deprecated. Use CIQ.inheritsFrom(me, ctor, autosuper) instead." - ); - CIQ.inheritsFrom(this, ctor, autosuper); - }; - Function.prototype.stxInheritsFrom = Function.prototype.ciqInheritsFrom; // backward compatibility -} - -/** - * The built-in String object. - * @external String - * @see [String]{@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String} on the Mozilla Developer Network. - */ - -/** - * **Deprecated since 7.4.0.** Use {@link CIQ.capitalize} instead. - * - * Capitalizes the first letter of a string. - * - * @return {string} Capitalized version of the string. - * @memberof external:String - * @alias external:String#capitalize - * @deprecated As of 7.4.0. Use {@link CIQ.capitalize} instead. - */ -String.prototype.capitalize = function () { - log( - "String.prototype.capitalize() has been deprecated. Use CIQ.capitalize(string) instead." - ); - return CIQ.capitalize(this); -}; - -/** - * **Deprecated since 7.4.0.** Use native CanvasRenderingContext2D methods such as moveTo(), lineTo() and setLineDash() instead. - * - * Dashed line polyfill for the canvas. Note that dashed lines are expensive operations when not supported natively. - * See {@link external:CanvasRenderingContext2D#stxLine}. - * - * @param {number} fromX Starting point of the X-axis. - * @param {number} fromY Starting point of the Y-axis. - * @param {number} toX Destination on the X-axis. - * @param {number} toY Destination on the Y-axis. - * @param {string[]} pattern Array of stroke patterns. - * @memberof external:CanvasRenderingContext2D - * @alias external:CanvasRenderingContext2D#dashedLineTo - * @deprecated As of 7.4.0. Use native CanvasRenderingContext2D methods such as moveTo(), lineTo() and setLineDash() instead. - * - * @example - * Native [CanvasRenderingContext2D]{@link https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D} - * methods used to draw a horizontal dashed line across the center of the screen: - * var canvas = stxx.chart.backgroundCanvas; - * var ctx = canvas.getContext("2d"); - * ctx.beginPath(); - * ctx.setLineDash([10, 10]); - * ctx.moveTo(0, canvas.height/2); - * ctx.lineTo(canvas.width, canvas.height/2); - * ctx.stroke(); - */ -CanvasRenderingContext2D.prototype.dashedLineTo = function ( - fromX, - fromY, - toX, - toY, - pattern -) { - log( - "CanvasRenderingContext2D.prototype.dashedLineTo() has been deprecated. Use native CanvasRenderingContext2D methods such as moveTo(), lineTo() and setLineDash() instead." - ); - // Error check. - if (!(pattern instanceof Array)) { - if (pattern) - console.log( - 'WARNING: Unsupported drawing pattern "' + - pattern + - '"; defaulting to "solid"' - ); - this.stxLine( - fromX, - fromY, - toX, - toY, - this.strokeStyle, - this.globalAlpha, - this.lineWidth - ); - return; - } - - // can't dash if we do not have proper values - if ( - fromY === Infinity || - fromX === Infinity || - toY === Infinity || - toX === Infinity - ) - return; - - // Our growth rate for our line can be one of the following: - // (+,+), (+,-), (-,+), (-,-) - // Because of this, our algorithm needs to understand if the x-coord and - // y-coord should be getting smaller or larger and properly cap the - // values - // based on (x,y). - var lt = function (a, b) { - return a - b <= 0.00000001; - }; - var gt = function (a, b) { - return a - b >= -0.00000001; - }; - var capmin = function (a, b) { - return Math.min(a, b); - }; - var capmax = function (a, b) { - return Math.max(a, b); - }; - - var checkX = { thereYet: gt, cap: capmin }; - var checkY = { thereYet: gt, cap: capmin }; - - if (fromY - toY > 0) { - checkY.thereYet = lt; - checkY.cap = capmax; - } - if (fromX - toX > 0) { - checkX.thereYet = lt; - checkX.cap = capmax; - } - - this.moveTo(fromX, fromY); - if (isNaN(fromX) || isNaN(fromY)) return; - var offsetX = fromX; - var offsetY = fromY; - var idx = 0, - dash = true; - while (!(checkX.thereYet(offsetX, toX) && checkY.thereYet(offsetY, toY))) { - var ang = Math.atan2(toY - fromY, toX - fromX); - var len = pattern[idx]; - - offsetX = checkX.cap(toX, offsetX + Math.cos(ang) * len); - offsetY = checkY.cap(toY, offsetY + Math.sin(ang) * len); - - if (dash) this.lineTo(offsetX, offsetY); - else this.moveTo(offsetX, offsetY); - - idx = (idx + 1) % pattern.length; - dash = !dash; - } -}; - -/** - * **Deprecated since 7.4.0.** Use native CanvasRenderingContext2D methods such as moveTo() and lineTo() instead. - * - * @param {number} fromX Starting point of the X-axis. - * @param {number} fromY Starting point of the Y-axis. - * @param {number} toX Destination on the X-axis. - * @param {number} toY Destination on the Y-axis. - * @param {string} color CSS-compatible color, such as hex, rgb, rgba or even color names such as "orange". - * @param {number} opacity The alpha. A number between 0 and 1. - * @param {number} lineWidth The line width in pixels. - * @param {number[]} [pattern] An array that contains the number of pixels on and then the number of pixels off. - * For instance [1,1] would create a dotted pattern by turning one pixel on and then one pixel off repeatedly. - * @memberof external:CanvasRenderingContext2D - * @alias external:CanvasRenderingContext2D#stxLine - * @deprecated As of 7.4.0. Use native CanvasRenderingContext2D methods such as moveTo() and lineTo() instead. - * - * @example - * Native [CanvasRenderingContext2D]{@link https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D} - * methods used to draw a thick blue line diagonally across the screen: - * var canvas = stxx.chart.backgroundCanvas; - * var ctx = canvas.getContext("2d"); - * ctx.beginPath(); - * ctx.strokeStyle = "blue"; - * ctx.lineWidth = 2; - * ctx.moveTo(0, 0); - * ctx.lineTo(canvas.width, canvas.height/2); - * ctx.stroke(); - */ -CanvasRenderingContext2D.prototype.stxLine = function ( - fromX, - fromY, - toX, - toY, - color, - opacity, - lineWidth, - pattern -) { - log( - "CanvasRenderingContext2D.prototype.stxLine() has been deprecated. Use native CanvasRenderingContext2D methods such as moveTo() and lineTo() instead." - ); - this.beginPath(); - this.lineWidth = lineWidth; - this.strokeStyle = color; - this.globalAlpha = opacity; - if (pattern && pattern.length) { - this.dashedLineTo(fromX, fromY, toX, toY, pattern); - } else { - this.moveTo(fromX, fromY); - this.lineTo(toX, toY); - } - this.stroke(); - this.closePath(); - this.lineWidth = 1; -}; - -/** - * **Deprecated since 7.4.0.** Use native CanvasRenderingContext2D methods such as arc() instead. - * - * Add native circle drawing to the canvas. - * - * @param {number} x X-axis position of the center of the circle. - * @param {number} y Y-axis position of the center of the circle. - * @param {number} radius Radius of the circle. - * @param {boolean} filled If true, then the circle is filled. - * @memberof external:CanvasRenderingContext2D - * @alias external:CanvasRenderingContext2D#stxCircle - * @deprecated As of 7.4.0. Use native CanvasRenderingContext2D methods such as arc() instead. - * - * @example - * Native [CanvasRenderingContext2D]{@link https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D} - * methods used to draw a red circle in the center of the screen: - * var canvas = stxx.chart.backgroundCanvas; - * var ctx = canvas.getContext("2d"); - * ctx.beginPath(); - * ctx.fillStyle = "red"; - * ctx.arc(canvas.width/2, canvas.height/2, 100, 0, 2 * Math.PI); - * ctx.fill(); - */ -CanvasRenderingContext2D.prototype.stxCircle = function (x, y, radius, filled) { - log( - "CanvasRenderingContext2D.prototype.stxCircle() has been deprecated. Use native CanvasRenderingContext2D methods such as arc() instead." - ); - this.beginPath(); - this.arc(x, y, radius, 0, 2 * Math.PI, false); - if (filled) this.fill(); - this.stroke(); - this.closePath(); -}; - -/** - * Returns an instance of - * [XMLHttpRequest]{@link https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest}. - * - * @param {string} url The URL to which the request is sent (not used). - * @return {object} An XMLHttpRequest instance. - * - * @memberof CIQ - * @deprecated As of 8.0.0. Use `new XMLHttpRequest()`. - */ -CIQ.getAjaxServer = function (url) { - log( - "CIQ.getAjaxServer() has been deprecated. Use `new XMLHttpRequest` instead." - ); - return new XMLHttpRequest(); -}; - -/** - * Converts an onClick event to an ontouchend event. If the device is known to be a touch device then this can be used - * to change onclick events that are set as attributes (in HTML). ontouchend events are more responsive than onclick events - * and can improve the user experience. When coding for cross-device implementations it is recommended to use {@link CIQ.safeClickTouch} - * programmatically rather than using hardcoded attributes - * @param {string} id The id of a node containing an onClick attribute - * @memberof CIQ - * @deprecated - * @since 6.0.0 Deprecated - */ -CIQ.convertClickToTouchEnd = function (id) { - log( - "CIQ.convertClickToTouchEnd() has been deprecated. Use CIQ.safeClickTouch() instead." - ); - var node = document.getElementById(id); - var s = node.getAttribute("onClick"); - if (s) { - node.removeAttribute("onClick"); - node.setAttribute("onTouchEnd", s); - } -}; - -/** - * Converts a date to YYYY-MM-DDTHH:MM:SSZ format (UTC). - * - * @param {date} dt The JavaScript `Date` object to be converted. - * @return {string} The date in YYYY-MM-DDTHH:MM:SSZ format. - * - * @memberof CIQ - * @deprecated As of 8.0.0. Use [Date.prototype.toISOString]{@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString} method. - */ -CIQ.standardUTCDate = function (dt) { - log( - "CIQ.standardUTCDate(dt) has been deprecated. Use dt.toISOString() instead." - ); - var m = dt.getUTCMonth() + 1; - if (m < 10) m = "0" + m; - var d = dt.getUTCDate(); - if (d < 10) d = "0" + d; - var h = dt.getUTCHours(); - if (h < 10) h = "0" + h; - var mn = dt.getUTCMinutes(); - if (mn < 10) mn = "0" + mn; - var s = dt.getUTCSeconds(); - if (s < 10) s = "0" + s; - return ( - "" + - dt.getUTCFullYear() + - "-" + - m + - "-" + - d + - "T" + - h + - ":" + - mn + - ":" + - s + - "Z" - ); -}; - -/** - * Determines whether the input date is during daylight saving time (DST). - * - * @param {date} [dt] The date to check. If the parameter is omitted, the current date is used. - * @return {boolean} True for DST, otherwise false. - * - * @memberof CIQ - * @deprecated As of 8.0.0. This function may return inaccurate results for some - * countries. - */ -CIQ.isDST = function (dt) { - log("CIQ.isDST() has been deprecated. Use dt.toISOString() instead."); - if (!dt) dt = new Date(); - var jan = new Date(dt.getFullYear(), 0, 1); - var jul = new Date(dt.getFullYear(), 6, 1); - var stdOffset = Math.max(jan.getTimezoneOffset(), jul.getTimezoneOffset()); - return dt.getTimezoneOffset() != stdOffset; -}; - -/** - * Gets the source element for a DOM event. - * - * @param {object} [e] The DOM event, if available from the browser. If an event is not - * provided, the window event is used. - * @return {object} The DOM node that registered the event. - * - * @memberof CIQ - * @deprecated As of 8.0.0. Use [Event.target]{@link https://developer.mozilla.org/en-US/docs/Web/API/Event/target}. - */ -CIQ.getEventDOM = function (e) { - log("CIQ.getEventDOM() has been deprecated. Use `e.target` instead."); - return e ? e.target : window.event.srcElement; -}; - -/** - * **Deprecated since 8.1.0.** Use {@link CIQ.elementDimensions} instead. - * - * Measures the width of a DOM element, including left and right margins. - * - * @param {HTMLElement} node The DOM element for which the width is measured. - * @return {number} The width of the DOM element, including margins. - * - * @memberof CIQ - * @deprecated Use {@link CIQ.elementDimensions}; for example, - * `CIQ.elementDimensions(node, {margin:1, padding:1, border:1}).width`. - * @since 8.1.0 Deprecated. - */ -CIQ.outerWidth = function (node) { - log( - "CIQ.outerWidth() has been deprecated. Use `CIQ.elementDimensions(node, {margin:1, padding:1, border:1}).width` instead." - ); - var width = node.offsetWidth; - width += CIQ.stripPX(getComputedStyle(node).marginLeft); - width += CIQ.stripPX(getComputedStyle(node).marginRight); - return width; -}; - -/** - * **Deprecated since 8.1.0.** Use `node.innerHTML=""` instead. - * - * Removes all DOM elements from within a given node. This is extremely useful when dynamically - * generating content. - * - * @param {HTMLElement} node The node from which all DOM elements are removed. - * - * @memberof CIQ - * @deprecated Use `node.innerHTML=""`. - * @since 8.1.0 Deprecated. - */ -CIQ.clearNode = function (node) { - log("CIQ.clearNode() has been deprecated. Use `node.innerHTML=''` instead."); - if (node.hasChildNodes()) { - while (node.childNodes.length >= 1) { - node.removeChild(node.firstChild); - } - } -}; - -/** - * **Deprecated since 8.1.0.** Use `Element.parentElement.prototype.closest()` instead. - * - * Convenience function for selecting a DOM element's closest parent element matching a selector. - * - * Use instead of `jQuery.closest()`. - * - * @param {HTMLElement} el The DOM element for which the parent element is obtained. - * @param {string} selector A CSS selector used to select the parent element. - * @return {HTMLElement} The parent element of `el` matching `selector`, or null if no match is - * found. - * - * @memberof CIQ - * @deprecated Use `Element.parentElement.prototype.closest()`. - * @since - * - 7.3.0 - * - 8.1.0 Deprecated. - */ -CIQ.findClosestParent = function (el, selector) { - log( - "CIQ.findClosestParent() has been deprecated. Use `Element.parentElement.prototype.closest()` instead." - ); - var matchesFn; - // find vendor prefix - [ - "matches", - "webkitMatchesSelector", - "mozMatchesSelector", - "msMatchesSelector", - "oMatchesSelector" - ].some(function (fn) { - if (typeof document.body[fn] == "function") { - matchesFn = fn; - return true; - } - return false; - }); - if (!matchesFn) return false; - var parent; - // traverse parents - while (el) { - parent = el.parentElement; - if (parent && parent[matchesFn](selector)) { - return parent; - } - el = parent; - } - return null; -}; - -/** - * Appends a class name to a node if the node doesn't already have that class. Used to - * control dynamic behavior via CSS. - * - * @param {object} node The DOM element to which the class is added. - * @param {string} className Name of the class to add to the DOM element. - * - * @memberof CIQ - * @deprecated As of 8.0.0. Use [Element.classList.add(className)]{@link https://developer.mozilla.org/en-US/docs/Web/API/DOMTokenList/add}. - * - * @example - * // Apply an "active" css look to an object. - * CIQ.appendClassName(myNode, "active"); - */ -CIQ.appendClassName = function (node, className) { - log( - "CIQ.appendClassName() has been deprecated. Use `node.classList.add(className)` instead." - ); - if (!node) return; - if (node.className == className) return; // already a class - var s = node.className.split(" "); - for (var i = 0; i < s.length; i++) { - if (s[i] == className) return; // already a class - } - if (!node.className) node.className = className; - else node.className += " " + className; -}; - -/** - * Removes a class name from a DOM node. - * - * @param {object} node The DOM element from which the class name is removed. - * @param {string} className The class name to remove. - * - * @memberof CIQ - * @deprecated As of 8.0.0. Use [Element.classList.remove(className)]{@link https://developer.mozilla.org/en-US/docs/Web/API/DOMTokenList/remove}. - */ -CIQ.unappendClassName = function (node, className) { - log( - "CIQ.unappendClassName() has been deprecated. Use `node.classList.remove(className)` instead." - ); - if (!node) return; - if (node.className.indexOf(className) == -1) return; - if (node.className == className) { - node.className = ""; - } else { - var s = node.className.split(" "); - var newClassName = ""; - for (var i = 0; i < s.length; i++) { - if (s[i] == className) continue; - if (newClassName !== "") newClassName += " "; - newClassName += s[i]; - } - node.className = newClassName; - } -}; - -/** - * Convenience method for swapping two class names on a DOM node. Typically used to change - * state. - * - * @param {object} node The DOM element on which the class names are swapped. - * @param {string} newClassName The class name to swap in. - * @param {string} oldClassName The class name to swap out. - * - * @memberof CIQ - * @deprecated As of 8.0.0. Use [Element.classList.replace(oldClassName, newClassName)]{@link https://developer.mozilla.org/en-US/docs/Web/API/DOMTokenList/replace}. - */ -CIQ.swapClassName = function (node, newClassName, oldClassName) { - log( - "CIQ.swapClassName() has been deprecated. Use `node.classList.replace(oldClassName, newClassName)` instead." - ); - CIQ.unappendClassName(node, oldClassName); - CIQ.appendClassName(node, newClassName); -}; - -/** - * Determines whether a class name is currently assigned to a DOM element. - * - * @param {object} node The DOM node checked for the presence of the class name. - * @param {string} className The class name for which to check. - * @return {boolean} True, if the class name is currently assigned to the DOM element; - * otherwise, false. - * - * @memberof CIQ - * @deprecated As of 8.0.0. Use [Element.classList.contains(className)]{@link https://developer.mozilla.org/en-US/docs/Web/API/DOMTokenList/contains}. - */ -CIQ.hasClassName = function (node, className) { - log( - "CIQ.hasClassName() has been deprecated. Use `node.classList.contains(className)` instead." - ); - if (!node) return false; - if ((" " + node.className + " ").indexOf(" " + className + " ") > -1) - return true; - return false; -}; - -/** - * Toggles the class name on or off on a DOM element. - * - * @param {HTMLElement} node The DOM element on which the class name is toggled on or off. - * @param {string} className The class name to toggle on or off. - * - * @memberof CIQ - * @deprecated As of 8.0.0. Use [Element.classList.toggle(className)]{@link https://developer.mozilla.org/en-US/docs/Web/API/DOMTokenList/toggle}. - */ -CIQ.toggleClassName = function (node, className) { - log( - "CIQ.toggleClassName() has been deprecated. Use `node.classList.toggle(className)` instead." - ); - if (CIQ.hasClassName(node, className)) CIQ.unappendClassName(node, className); - else CIQ.appendClassName(node, className); -}; - -/* - * http://www.backalleycoder.com/2013/03/18/cross-browser-event-based-element-resize-detection/ - */ - -(function () { - var attachEvent = document.attachEvent; - var isIE = navigator.userAgent.match(/Trident/); - var requestFrame = (function () { - var raf = - window.requestAnimationFrame || - window.mozRequestAnimationFrame || - window.webkitRequestAnimationFrame || - function (fn) { - return setTimeout(fn, 20); - }; - return function (fn) { - return raf(fn); - }; - })(); - - var cancelFrame = (function () { - var cancel = - window.cancelAnimationFrame || - window.mozCancelAnimationFrame || - window.webkitCancelAnimationFrame || - window.clearTimeout; - return function (id) { - return cancel(id); - }; - })(); - - function resizeListener(e) { - var win = e.target || e.srcElement; - if (win.__resizeRAF__) cancelFrame(win.__resizeRAF__); - win.__resizeRAF__ = requestFrame(function () { - var trigger = win.__resizeTrigger__; - trigger.__resizeListeners__.forEach(function (fn) { - fn.call(trigger, e); - }); - }); - } - - function objectLoad(e) { - this.contentDocument.defaultView.__resizeTrigger__ = this.__resizeElement__; - this.contentDocument.defaultView.addEventListener("resize", resizeListener); - } - - /** - * **Deprecated since 7.4.0.** Use {@link CIQ.UI.addResizeListener} instead. - * - * Attaches a callback to listen for resize events on the DOM. - * - * Designed to be used as a helper method for the included {@link WebComponents}. A full tutorial on how to work with - * and customize the Web Components can be found here: {@tutorial Web Component Interface}. - * - * @param {node} element The node to which the listener is attached. - * @param {function} callback The listener function to attach to the DOM element. - * @memberof CIQ - * @deprecated As of 7.4.0. Use {@link CIQ.UI.addResizeListener}. - */ - CIQ.addResizeListener = function (element, fn) { - log( - "CIQ.addResizeListener() has been deprecated. Use CIQ.UI.addResizeListener() instead." - ); - var uiManager = document.querySelector("cq-ui-manager"); - if (uiManager.length > 0) { - uiManager = uiManager[0]; - uiManager.registerForResize(element); - } - if (!element.__resizeListeners__) { - element.__resizeListeners__ = []; - if (attachEvent) { - element.__resizeTrigger__ = element; - element.attachEvent("onresize", resizeListener); - } else { - //if (!getComputedStyle(element) || getComputedStyle(element).position == 'static') element.style.position = 'relative'; - var obj = (element.__resizeTrigger__ = document.createElement( - "object" - )); - obj.setAttribute( - "style", - "visibility:hidden; display: block; position: absolute; top: 0; left: 0; height: 100%; width: 100%; overflow: hidden; pointer-events: none; z-index: -1; border:0px;" - ); - obj.__resizeElement__ = element; - obj.onload = objectLoad; - obj.type = "text/html"; - if (isIE) element.appendChild(obj); - obj.data = "about:blank"; - if (!isIE) element.appendChild(obj); - } - } - element.__resizeListeners__.push(fn); - }; - - /** - * Removes an attached resize event listener from a DOM element. - * - * Designed to be used as a helper method for the included {@link WebComponents}. - * A full tutorial on how to work with and customize the Web Components can be found here: {@tutorial Web Component Interface}. - * - * @param {node} element The node from which the listener is removed. - * @param {function} callback The listener function to be removed. - * @memberof CIQ - * @deprecated As of 7.4.0. Use {@link CIQ.UI.removeResizeListener}. - */ - CIQ.removeResizeListener = function (element, fn) { - log( - "CIQ.removeResizeListener() has been deprecated. Use CIQ.UI.removeResizeListener() instead." - ); - var uiManager = document.querySelector("cq-ui-manager"); - if (uiManager.length > 0) { - uiManager = uiManager[0]; - uiManager.unregisterForResize(element); - } - element.__resizeListeners__.splice( - element.__resizeListeners__.indexOf(fn), - 1 - ); - if (!element.__resizeListeners__.length) { - if (attachEvent) element.detachEvent("onresize", resizeListener); - else { - element.__resizeTrigger__.contentDocument.defaultView.removeEventListener( - "resize", - resizeListener - ); - element.__resizeTrigger__ = !element.removeChild( - element.__resizeTrigger__ - ); - } - } - }; -})(); - -/** - * This function is no longer used by the library. Use {@link CIQ.Renderer#adjustYAxis} instead. - * @memberof CIQ.Renderer - * @deprecated As of 5.2.0. no longer used in library.. - */ -CIQ.Renderer.prototype.performCalculations = function () { - log( - "CIQ.Renderer.prototype.performCalculations has been deprecated. Use CIQ.Renderer.prototype.adjustYAxis instead." - ); -}; - -/** - * **Deprecated** Use {@link CIQ.ChartEngine.XAxis#noDraw} and {@link CIQ.ChartEngine.YAxis#noDraw} instead. - * - * Override this function to hide the date which floats along the X axis when crosshairs are enabled. Return `true` to hide the date or `false` to display. - * @memberof CIQ.ChartEngine - * @deprecated as of 6.0.0 no longer used in library. - */ -CIQ.ChartEngine.hideDates = function () { - log( - "CIQ.Renderer.hideDates is no longer supported. To hide an axis, set its noDraw property. To hide the floating date label, set stxx.controls.floatDate=null." - ); - return false; -}; - -/** - * Returns true if the chartType displays OHL data. - * @param {string} chartType The chart type (layout.chartType) - * @return {boolean} True if the chart type only displays close values - * @memberof CIQ.ChartEngine - * @since 05-2016-10.1 "baseline_delta_mountain" and "colored_mountain" are also available. - * @deprecated - */ -CIQ.ChartEngine.chartShowsHighs = function (chartType) { - log( - "CIQ.ChartEngine.prototype.chartShowsHighs has been deprecated. Use CIQ.ChartEngine.Chart.prototype.highLowBars instead." - ); - if ( - { - line: 1, - colored_line: 1, - mountain: 1, - colored_mountain: 1, - baseline_delta: 1, - baseline_delta_mountain: 1, - histogram: 1, - scatterplot: 1, - step: 1, - colored_step: 1 - }[chartType] == 1 - ) - return false; - return true; -}; - -/** - * Draws a filled rectangle on the chart. - * - * @param {number} left The x-axis coordinate of the starting point of the rectangle. - * @param {number} width The width of the rectangle. - * @param {number} top The y-axis coordinate of the starting point of the rectangle. - * @param {number} height The height of the rectangle. - * @param {string} className A CSS class name used to set the fill color of the rectangle. - * @param {external:CanvasRenderingContext2D} [context] The canvas context on which the - * rectangle is drawn. If this parameter is not provided, the chart context is used. - * - * @memberOf CIQ.ChartEngine - * @deprecated As of 8.0.0. Use [CanvasRenderingContext2D.fillRect()]{@link https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/fillRect}. - */ -CIQ.ChartEngine.prototype.createBlock = function ( - left, - width, - top, - height, - className, - context -) { - log( - "CIQ.ChartEngine.prototype.createBlock has been deprecated. Use native canvas context operation fillRect instead." - ); - if (!context) context = this.chart.context; - if (typeof height == "undefined") { - return; - } - this.canvasColor(className, context); - context.fillRect(left, top, width, height); - context.globalAlpha = 1; -}; - -/** - * Turns the volume underlay indicator on or off. - * - * @param {boolean} data True to turn on the underlay, false to turn it off. - * - * @memberof CIQ.ChartEngine - * @deprecated As of 8.0.0. To enable a volume underlay, use {@link CIQ.Studies.addStudy}; - * to disable a volume underlay, {@link CIQ.Studies.removeStudy}. - */ -CIQ.ChartEngine.prototype.setVolumeUnderlay = function (data) { - log( - "CIQ.ChartEngine.prototype.setVolumeUnderlay is no longer supported. To enable a volume underlay, use CIQ.Studies.addStudy(stxx, 'vol undr'). To disable, use CIQ.Studies.removeStudy." - ); - this.layout.volumeUnderlay = data; - if (this.chart.canvas) this.draw(); - this.changeOccurred("layout"); -}; - -/** - * Exports all of the drawings on the chart(s) so that they can be saved to an external database and later reconstructed. - * - * Note: This function has been renamed {@link CIQ.ChartEngine#exportDrawings}. - * - * @see {@link CIQ.ChartEngine#exportDrawings} - * @see {@link CIQ.ChartEngine#importDrawings} - * @return {array} An array of objects representing each drawing - * @memberof CIQ.ChartEngine - * @deprecated since 3.0.0 - */ -CIQ.ChartEngine.prototype.serializeDrawings = function () { - log( - "CIQ.ChartEngine.prototype.serializeDrawings has been deprecated. Use CIQ.ChartEngine.prototype.exportDrawings instead." - ); - return this.exportDrawings(); -}; - -/** - * Imports drawings from an array originally created by {@link CIQ.ChartEngine#serializeDrawings}. - * - * Note: This function and serializeDrawings have been renamed {@link CIQ.ChartEngine#importDrawings} and {@link CIQ.ChartEngine#exportDrawings} respectively. - * - * To immediately render the reconstructed drawings, you must call `draw()`. - * See {@tutorial Using and Customizing Drawing Tools} for more details. - * @see {@link CIQ.ChartEngine#exportDrawings} - * @see {@link CIQ.ChartEngine#importDrawings} - * @param {array} arr An array of serialized drawings - * @memberof CIQ.ChartEngine - * @deprecated since 4.0.0 - */ -CIQ.ChartEngine.prototype.reconstructDrawings = function (arr) { - log( - "CIQ.ChartEngine.prototype.reconstructDrawings has been deprecated. Use CIQ.ChartEngine.prototype.importDrawings instead." - ); - this.importDrawings(arr); -}; - -// @deprecated Use pixelFromBar -CIQ.ChartEngine.prototype.computePosition = function (x, offset) { - log( - "CIQ.ChartEngine.prototype.computePosition has been deprecated. Use CIQ.ChartEngine.prototype.pixelFromBar instead." - ); - if (typeof offset == "undefined") offset = 0; - var position = x * this.layout.candleWidth + offset + this.micropixels; - return position; -}; - -// @deprecated -CIQ.ChartEngine.prototype.computeColor = function (open, close) { - log( - "CIQ.ChartEngine.prototype.computeColor has been deprecated. There is no suggested alternative." - ); - if (open < close) return "stx_candle_up"; - if (open > close) return "stx_candle_down"; - return "stx_candle_shadow"; -}; - -// @deprecated -CIQ.ChartEngine.prototype.computeLength = function (high, low) { - log( - "CIQ.ChartEngine.prototype.computeLength has been deprecated. Use CIQ.ChartEngine.prototype.pixelFromPrice to compute values and find the difference." - ); - var h = this.pixelFromPrice(high); - var l = this.pixelFromPrice(low); - return l - h; -}; - -// deprecated -CIQ.ChartEngine.prototype.setCrosshairColors = function () { - log( - "CIQ.ChartEngine.prototype.setCrosshairColors is no longer supported. Use CSS to set the crosshair color" - ); -}; - -/** - * A version of {@link CIQ.ChartEngine#valueFromPixel} that will untransform a transformation such as a comparison chart. - * @param {number} y The y pixel location - * @param {CIQ.ChartEngine.Panel} panel A panel object. It is strongly recommended to pass the panel! (see {@link CIQ.ChartEngine#valueFromPixel}) - * @param {CIQ.ChartEngine.YAxis} [yAxis] The yaxis to use. Defaults to panel.yAxis. - * @return {number} The price or value - * @memberof CIQ.ChartEngine - * @deprecated Use {@link CIQ.ChartEngine#valueFromPixel} instead - */ -CIQ.ChartEngine.prototype.valueFromPixelUntransform = function ( - y, - panel, - yAxis -) { - log( - "CIQ.ChartEngine.prototype.valueFromPixelUntransform has been deprecated. Use CIQ.ChartEngine.prototype.valueFromPixel instead." - ); - return this.valueFromPixel(y, panel, yAxis); -}; - -/** - * > ** This function has been deprecated in favor of {@link CIQ.ChartEngine#pixelFromPrice}. It should no longer be used. - * >
Use {@link CIQ.ChartEngine#pixelFromTransformedValue} to get the pixel location based on the transformed value (percentage comparison change, for example). - * - * @param {number} price The price or value - * @param {CIQ.ChartEngine.Panel} panel A panel object (see {@link CIQ.ChartEngine#pixelFromPrice}) - * @param {CIQ.ChartEngine.YAxis} [yAxis] The yaxis to use - * @return {number} The y axis pixel location - * @memberof CIQ.ChartEngine - * @deprecated Use {@link CIQ.ChartEngine#pixelFromPrice} instead - * @since 4.0.0 Now behaves like pixelFromPriceTransform. That is, on a comparison chart, pixelFromPrice accepts an actual stock price, not a percentage value. - */ -CIQ.ChartEngine.prototype.pixelFromPriceTransform = function ( - price, - panel, - yAxis -) { - log( - "CIQ.ChartEngine.prototype.pixelFromPriceTransform has been deprecated. Use CIQ.ChartEngine.prototype.pixelFromPrice instead." - ); - return this.pixelFromPrice(price, panel, yAxis); -}; - -//deprecated, use static version -CIQ.ChartEngine.prototype.isDailyInterval = function (interval) { - log( - "CIQ.ChartEngine.prototype.isDailyInterval has been deprecated. Use CIQ.ChartEngine.isDailyInterval instead." - ); - return CIQ.ChartEngine.isDailyInterval(interval); -}; - -/** - * Renders a chart for a particular instrument from the data passed in or fetches new data from the attached {@link quotefeed}. - * - * This method has been deprecated, use {@link CIQ.ChartEngine#loadChart}. - * - * @param {string|object} symbol The symbol or equation for the new chart - a symbol string, equation or an object representing the symbol can be used. - *
After the new chart is initialized, it will contain both a symbol string (stxx.chart.symbol) and a symbol object (stxx.chart.symbolObject). - *
You can send anything you want in the symbol object, but you must always include at least a 'symbol' element. Both these variables will be available for use wherever the {@link CIQ.ChartEngine.Chart} object is present. For example, if using a {@link quotefeed} for gathering data, params.stx.chart.symbolObject will contain your symbol object. - *
To allow equations to be used on a chart, the {@link CIQ.ChartEngine#allowEquations} parameter must be set to `true` and the equation needs to be preceded by an equals sign (=) in order for it to be parsed as an equation. - *
See {@link CIQ.formatEquation} and {@link CIQ.computeEquationChart} for more details on allowed equations syntax. - * @param {array} [masterData] An array of [properly formatted OHLC objects]{@tutorial InputDataFormat} to create a chart. Each element should at a minimum contain a "Close" field (capitalized). - * If the charting engine has been configured to use a [QuoteFeed]{@link CIQ.ChartEngine#attachQuoteFeed} - * then masterData does not need to be passed in. The quote feed will be queried instead. - * @param {CIQ.ChartEngine.Chart} chart] Which chart to create. Defaults to the default chart. - * @param {function} [cb] Callback when newChart is loaded. See {@tutorial Adding additional content on chart} for a tutorial on how to use this callback function. - * @param {object} [params] Parameters to dictate initial rendering behavior - * @param {Object} [params.range] Default range to be used upon initial rendering. If both `range` and `span` parameters are passed in, range takes precedence. If periodicity is not set, the range will be displayed at the most optimal periodicity. See {@link CIQ.ChartEngine#setRange} for complete list of parameters this object will accept. - * @param {object} [params.span] Default span to display upon initial rendering. If both `range` and `span` parameters are passed in, range takes precedence. If periodicity is not set, the span will be displayed at the most optimal periodicity. See {@link CIQ.ChartEngine#setSpan} for complete list of parameters this object will accept. - * @param {object} [params.periodicity] Periodicity to be used upon initial rendering. See {@link CIQ.ChartEngine#setPeriodicity} for complete list of parameters this object will accept. If no periodicity has been set it will default to `1 day`. - * @param {boolean} [params.stretchToFillScreen] Increase the candleWidth to fill the left-side gap created by a small dataSet. Respects CIQ.ChartEngine.preferences.whitespace. Ignored when params `span` or `range` are used. See {@link CIQ.ChartEngine#fillScreen} - * @memberof CIQ.ChartEngine - * @example - * // using a symbol object and embedded span and periodicity requirements - * stxx.newChart( - * {symbol:newSymbol,other:'stuff'}, - * null, - * null, - * callbackFunction, - * { - * span:{base:'day',multiplier:2}, - * periodicity:{period:1,interval:5,timeUnit:'minute'}, - * stretchToFillScreen:true - * } - * ); - * - * @example - * // using a symbol string - * stxx.newChart( - * "IBM", - * null, - * null, - * callbackFunction - * ); - * - * @example - * // using an equation string - * stxx.newChart( - * "=2*IBM-GM", - * null, - * null, - * callbackFunction - * ); - * - * @deprecated use {@link CIQ.ChartEngine#loadChart} - * @since - * - 2015-11-1 newChart is capable of setting periodicity and span via `params` settings. - * - 04-2016-08 Added `params.stretchToFillScreen`. - * - 5.1.0 newChart is capable of setting range via `params` settings. - * - 6.0.0 Statically provided data will be gap-filled if that functionality is enabled. - * - 7.0.0 Deprecated, replaced by {@link CIQ.ChartEngine#loadChart}. - */ -CIQ.ChartEngine.prototype.newChart = function ( - symbol, - masterData, - chart, - cb, - params -) { - log( - "CIQ.ChartEngine.prototype.newChart has been deprecated. Use CIQ.ChartEngine.prototype.loadChart instead." - ); - var parameters = { - masterData: masterData, - chart: chart - }; - CIQ.extend(parameters, params, true); - // console.log('WARNING: newChart is deprecated for removal. Please use loadChart.'); - return this.loadChart(symbol, parameters, cb); -}; - -/** - * Streams "last sale" prices into the chart. - * - * - * >**This function has been deprecated in favor of {@link CIQ.ChartEngine#updateChartData}. - * This also means that {@link CIQ.ChartEngine#streamParameters.fillGaps} is deprecated. - * Developers should instead call {@link CIQ.ChartEngine#updateChartData} with `params.fillGaps=true` or rely on cleanupGaps as default behavior.** - * - * >`streamTrade` to `updateChartData` migration examples: - * - * >Note that updateChartData follows the 'OHLC' format. - * So `V`olume (upper case) is used rather than `v`olume (lower case). - * Similarly `L`ast (upper case) is used rather than `l`ast (lower case). - * - * >Example 1: streaming a secondary series: - * - * >`streamTrade({"last":102.05}, null, "IBM");` - *
Translates to :
- * `updateChartData({"Last":102.05}, null, {fillGaps: true, secondarySeries: "IBM"});` - * - * >Example 2: streaming a primary series: - * - * >`streamTrade({"last":102.05, "volume":100});` - *
Translates to :
- * `updateChartData({"Last": 102.05,"Volume":100}, null, {fillGaps: true});` - * - * This method is designed to append ticks to the master data while maintaining the existing periodicity, appending to the last tick or creating new ticks as needed. - * It will also fill in gaps if there are missing bars in a particular interval. - * If a trade has a date older than the beginning of the next bar, the last bar will be updated even if the trade belongs to a prior bar; this could happen if a trade is sent in after hours at a time when the market is closed, or if it is received out of order. - * When in 'tick' interval, each trade will be added to a new bar and no aggregation to previous bars will be done. - * If the optional timestamp [now] is sent in, and it is older than the next period to be rendered, the last tick on the dataset will be updated instead of creating a new tick. - * - * **It is crucial that you ensure the date/time of the trade is in line with your `masterData` and `dataZone`** See `now` parameter for more details. - * - * This method leverages {@link CIQ.ChartEngine#updateChartData} for the actual data insertion into masterData. Please see {@link CIQ.ChartEngine#updateChartData} for additional details and performance throttle settings. - * - * See the [Streaming]{@tutorial DataIntegrationStreaming} tutorial for more the details. - * - * **Note:** versions prior to 15-07-01 must use the legacy arguments : streamTrade(price, volume, now, symbol) - * - * @param {object} data Price & Volume Data, may include any or all of the following: - * @param {number} data.last Last sale price - * @param {number} [data.volume] Trade volume - * @param {number} [data.bid] Bid price - * @param {number} [data.ask] Offer/Ask price - * @param {date} [now] Date of trade. It must be a java script date [new Date().getTime()]. **If omitted, defaults to "right now" in the set `dataZone`** (see {@link CIQ.ChartEngine#setTimeZone}); or if no `dataZone` is set, it will default to the browser's timezone (not recommended for international client-base since different users will see different times). It is important to note that this value must be in the same timezone as the rest of the masterData already sent into the charting engine to prevent tick gaps or overlaps. - * @param {string} [symbol] trade symbol for series streaming ONLY. Leave out or set to `null` when streaming the primary chart symbol. - * @param {object} [params] Params to be passed to {@link CIQ.ChartEngine#updateChartData} - * @memberof CIQ.ChartEngine - * @example - * // streaming last sale for the primary chart symbol - * stxx.streamTrade({"last":102.05, "volume":100}); - * @example - * // streaming last sale for an additional series on the chart - * stxx.streamTrade({"last":102.05, "volume":100}, null, "IBM"); - * @deprecated Please use {@link CIQ.ChartEngine#updateChartData} for streaming last ticket. - * @since 4.0.0 Deprecated this function. This also means that streamParameters.fillGaps is deprecated. Developers should - * call {@link CIQ.ChartEngine#updateChartData} with `params.fillGaps=true` or rely on cleanupGaps as default behavior. - */ -CIQ.ChartEngine.prototype.streamTrade = function ( - priceData, - now, - symbol, - params -) { - log( - "CIQ.ChartEngine.prototype.streamTrade has been deprecated. Use CIQ.ChartEngine.prototype.updateChartData instead." - ); - var chart = this.chart; - if (!params) params = {}; - if (params.chart) chart = params.chart; - params.fillGaps = this.streamParameters.fillGaps; - var newArgs = typeof priceData == "object"; - - var price = newArgs ? priceData.last : arguments[0], - volume = newArgs ? priceData.volume : arguments[1], - bid = newArgs ? priceData.bid : null, - ask = newArgs ? priceData.ask : null; - - if (!newArgs) { - now = arguments[2]; - symbol = arguments[3]; - } - - if (symbol) { - //series element - params.secondarySeries = symbol; - } - - var data = { - DT: now, - Last: price, - Volume: volume, - Bid: bid, - Ask: ask - }; - - this.updateChartData(data, chart, params); -}; - -/** - * As of version 5.1, his method has been **deprecated** in favor of {@link CIQ.ChartEngine#updateChartData} which provides improved functionality. - * - * The following parameters are only applicable for legacy versions (pre 5.1): - * @deprecated Please use {@link CIQ.ChartEngine#updateChartData} - * @param {array/object} appendQuotes An array of properly formatted OHLC quote object(s). [See Data Format]{@tutorial InputDataFormat}.
- * Or a last sale object with the following elements: - * @param {number} appendQuotes.Last Last sale price - * @param {number} [appendQuotes.Volume] Trade volume - * @param {number} [appendQuotes.Bid] Bid price - * @param {number} [appendQuotes.Ask] Offer/Ask price - * @param {number} [appendQuotes.DT] Date of trade. - * It must be a java script date [new Date().getTime()]. - * **If omitted, defaults to "right now" in the set `dataZone`** (see {@link CIQ.ChartEngine#setTimeZone}); - * or if no `dataZone` is set, it will default to the browser's timezone (not recommended for international client-base since different users - * will see different times). It is important to note that this value must be in the same timezone as the rest of the masterData already - * sent into the charting engine to prevent tick gaps or overlaps. - * @param {CIQ.ChartEngine.Chart} [chart] The chart to append the quotes. Defaults to the default chart. - * @param {object} [params] Parameters to dictate behavior - * @param {boolean} [params.noCreateDataSet] If true then do not create the data set automatically, just add the data to the masterData - * @param {boolean} [params.allowReplaceOHL] Set to true to bypass internal logic that maintains OHL - * @param {boolean} [params.bypassGovernor] If true then masterdata will be immediately updated regardless of {@link CIQ.ChartEngine#streamParameters} - * @param {boolean} [params.fillGaps] If true then {@link CIQ.ChartEngine#doCleanupGaps} is called using the {@link CIQ.ChartEngine#cleanupGaps} setting. This will ensure gaps will be filled in the master data from the last tick in the chart to the date of the trade.
Reminder: `tick` does not fill any gaps as it is not a predictable interval. - * @param {boolean} [params.secondarySeries] Set to the name of the element ( valid comparison symbol, for example) to load data as a secondary series. - * @param {boolean} [params.useAsLastSale] If not using a 'last sale' formatted object in `appendQuotes`, - * you can simply set this parameter to `true` to force the data as a last sale price; or further define it by creating an object including other settings as needed. - * This option is available in cases when a feed may always return OHLC formatted objects or a 'Close' field instead of a 'Last' field, - * even for last sale streaming updates. - * By definition a 'last' sale can only be a single record indicating the very 'last' sale price. As such, even if multiple records are sent in the `appendQuotes` array when this flag is enabled, - * only the last record's data will be used. Specifically the 'Close' and 'Volume' fields will be streamed. - * @param {boolean} [params.useAsLastSale.aggregatedVolume] If your last sale updates send current volume for the bar instead of just the trade volume, set this parameter to 'true' in the `params.useAsLastSale` object. The sent in volume will be used as is instead of being added to the existing bar's volume. - * - * @memberof CIQ.ChartEngine - * @since - * - 2015-11-1 Added `params.bypassGovernor` and `params.allowReplaceOHL`. - * - 2015-11-1 Deprecated `params.force`. Every call will update the tick to maintain the proper volume, and `createDataSet` is now controlled by `sp.maxTicks`, `sp.timeout`, or `params.bypassGovernor`. - * - 3.0.0 Now `appendQuotes` also takes last sale data to allow streaming capabilities. This can now be used instead of streamTrade. - * - 3.0.0 New `params.fillGaps`, `params.secondarySeries`, and `params.useAsLastSale`. - * - 4.0.0 Last sale streaming will now update a bar in the past to comply with the date sent in instead of just updating the current tick. - * - 4.0.3 Added `params.useAsLastSale.aggregatedVolume`. - * - 5.0.1 Now calls doCleanupDates in case is is being called directly when not using a quoteFeed, to update an entire candle. - */ -CIQ.ChartEngine.prototype.appendMasterData = function ( - appendQuotes, - chart, - params -) { - log( - "CIQ.ChartEngine.prototype.appendMasterData has been deprecated. Use CIQ.ChartEngine.prototype.updateChartData instead." - ); - this.updateChartData(appendQuotes, chart, params); -}; - -/** - * INJECTABLE - * - * **Legacy** function to set the periodicity and interval for the chart. - * - * **Replaced by {@link CIQ.ChartEngine#setPeriodicity}, but maintained for backwards comparibility. Uses same function signature.** - * - * @param {number} period The number of elements from masterData to roll-up together into one data point on the chart (one candle, for example). If set to 30 in a candle chart, for example, each candle will represent 30 raw elements of `interval` type. - * @param {string} interval The type of data to base the `period` on. This can be a numeric value representing minutes, seconds or millisecond as inicated by `timeUnit`, "day","week", "month" or 'tick' for variable time x-axis. **"hour" is NOT a valid interval.** (This is not how much data you want the chart to show on the screen; for that you can use {@link CIQ.ChartEngine#setRange} or {@link CIQ.ChartEngine#setSpan}) - * @param {string} [timeUnit] Time unit to further qualify the specified numeric interval. Valid values are "millisecond","second","minute",null. If not set, will default to "minute". **only applicable and used on numeric intervals** - * @param {function} [cb] Callback after periodicity is changed. First parameter of callback will be null unless there was an error. - * - * @memberof CIQ.ChartEngine - * @since - * - 2015-11-1 Second and millisecond periodicities are now supported by setting the `timeUnit` parameter. - * - 3.0.0 Replaced by {@link CIQ.ChartEngine#setPeriodicity}, but maintained for backwards comparibility. - * - 8.0.0 Deprecated - * @deprecated Use {@link CIQ.ChartEngine#setPeriodicity}. - */ -CIQ.ChartEngine.prototype.setPeriodicityV2 = function ( - period, - interval, - timeUnit, - cb -) { - log( - "CIQ.ChartEngine.prototype.setPeriodicityV2 has been deprecated. Use CIQ.ChartEngine.prototype.setPeriodicity instead." - ); - if (typeof timeUnit === "function") { - cb = timeUnit; // backward compatibility - timeUnit = null; - } - if (this.runPrepend("setPeriodicityV2", arguments)) return; - this.setPeriodicity(period, interval, timeUnit, cb); - this.runAppend("setPeriodicityV2", arguments); -}; - -//Unused -CIQ.ChartEngine.prototype.addChart = function (name, chart) { - log( - "CIQ.ChartEngine.prototype.addChart has been deprecated. Add manually to stxx.charts object instead." - ); - chart.name = name; - this.charts[name] = chart; -}; - -var changeOccurred = CIQ.ChartEngine.prototype.changeOccurred; -CIQ.ChartEngine.prototype.changeOccurred = function (change) { - if (this.currentlyImporting) return; - if (this.changeCallback) this.changeCallback(this, change); - changeOccurred.call(this, change); -}; - -var engineConstruct = CIQ.ChartEngine.prototype.construct; -CIQ.ChartEngine.prototype.construct = function () { - function getValue(obj, name, def) { - if (!obj._deprecatedPropertyValues) obj._deprecatedPropertyValues = {}; - if (!(name in obj._deprecatedPropertyValues)) - obj._deprecatedPropertyValues[name] = def; - return obj._deprecatedPropertyValues[name]; - } - function setValue(obj, name, val) { - if (!obj._deprecatedPropertyValues) obj._deprecatedPropertyValues = {}; - obj._deprecatedPropertyValues[name] = val; - } - - engineConstruct.call(this); - - Object.defineProperties(this, { - /** - * **This function has been deprecated. Please use {@link CIQ.ChartEngine#addEventListener} instead.** - * - * This is the callback function used to react to {@link CIQ.ChartEngine#changeOccurred}. - * - * Use this for storing chart configurations or drawings real time as users make changes. - * - * Expected format : - * - * fc(stxChart, eventType); - * - * Currently implemented values for "eventType" are "layout" and "vector". - * - * You can create any additional event types and trigger them by calling 'CIQ.ChartEngine.changeOccurred(eventType)' - * - * **Note** only one changeCallback function can be registered per chart object. As such, you must program it to handle any and all possible events triggered by {@link CIQ.ChartEngine#changeOccurred}. - * @type {function} - * @alias changeCallback - * @memberof CIQ.ChartEngine.prototype - * @deprecated - * @since 4.0.0 Deprecated - * @example - * stxx.changeCallback=function(stxx, eventType){ - * if(eventType=="layout") saveLayout(); - * if(eventType=="vector") saveDrawing(); - * } - */ - changeCallback: { - enumerable: true, - get: (function (stx) { - return function () { - //log("CIQ.ChartEngine.prototype.changeCallback has been deprecated. Use CIQ.ChartEngine.prototype.addEventListener instead."); - return getValue(this, "changeCallback", null); - }; - })(this), - set: (function (stx) { - return function (func) { - log( - "CIQ.ChartEngine.prototype.changeCallback has been deprecated. Use CIQ.ChartEngine.prototype.addEventListener instead." - ); - setValue(this, "changeCallback", func); - }; - })(this) - }, - /** - * Chart types which plot more than one data field (OHLC charts). - * Putting a chart type here will disable the use of {@link CIQ.ChartEngine.Chart#defaultPlotField}. - * @type object - * @default - * @alias highLowBars - * @deprecated, access property in chart instead (stxx.chart.highLowBars) - * @memberof CIQ.ChartEngine.prototype - * @since 4.0.0 - */ - highLowBars: { - enumerable: true, - get: (function (stx) { - return function () { - log( - "CIQ.ChartEngine.prototype.highLowBars is no longer supported. Use CIQ.ChartEngine.Chart.prototype.highLowBars instead." - ); - return getValue(this, "highLowBars", { - bar: true, - colored_bar: true, - candle: true, - hollow_candle: true, - volume_candle: true, - hlc: true, - colored_hlc: true, - hlc_box: true, - hlc_shaded_box: true, - wave: true, - rangechannel: true, - none: true - }); - }; - })(this), - set: (function (stx) { - return function (val) { - log( - "CIQ.ChartEngine.prototype.highLowBars is no longer supported. Use CIQ.ChartEngine.Chart.prototype.highLowBars instead." - ); - setValue(this, "highLowBars", val); - }; - })(this) - }, - /** - * Chart types whose bars represent a stand-alone entity as opposed to a vertex in a line-type chart. - * This is important when the engine tries to render the data points right off the chart; in a stand-alone bar, - * the points right off the chart need not be considered. - * @type object - * @default - * @alias standaloneBars - * @deprecated, access property in chart instead (stxx.chart.standaloneBars) - * @memberof CIQ.ChartEngine.prototype - * @since 4.0.0 - */ - standaloneBars: { - enumerable: true, - get: (function (stx) { - return function () { - log( - "CIQ.ChartEngine.prototype.standaloneBars is no longer supported. Use CIQ.ChartEngine.Chart.prototype.standaloneBars instead." - ); - return getValue(this, "standaloneBars", { - bar: true, - colored_bar: true, - candle: true, - hollow_candle: true, - volume_candle: true, - hlc: true, - colored_hlc: true, - hlc_box: true, - hlc_shaded_box: true, - histogram: true, - scatterplot: true - }); - }; - })(this), - set: (function (stx) { - return function (val) { - log( - "CIQ.ChartEngine.prototype.standaloneBars is no longer supported. Use CIQ.ChartEngine.Chart.prototype.standaloneBars instead." - ); - setValue(this, "standaloneBars", val); - }; - })(this) - }, - /** - * Chart types whose bars have width, as opposed to a line-type chart whose "bars" are just a point on the chart. - * This is useful when the engine adjusts the chart for smooth scrolling and homing. - * @type object - * @default - * @alias barsHaveWidth - * @deprecated, access property in chart instead (stxx.chart.barsHaveWidth) - * @memberof CIQ.ChartEngine.prototype - * @since 4.0.0 - */ - barsHaveWidth: { - enumerable: true, - get: (function (stx) { - return function () { - log( - "CIQ.ChartEngine.prototype.barsHaveWidth is no longer supported. Use CIQ.ChartEngine.Chart.prototype.barsHaveWidth instead." - ); - return getValue(this, "barsHaveWidth", { - bar: true, - colored_bar: true, - candle: true, - hollow_candle: true, - volume_candle: true, - hlc: true, - colored_hlc: true, - hlc_box: true, - hlc_shaded_box: true, - histogram: true, - scatterplot: true, - wave: true - }); - }; - })(this), - set: (function (stx) { - return function (val) { - log( - "CIQ.ChartEngine.prototype.barsHaveWidth is no longer supported. Use CIQ.ChartEngine.Chart.prototype.barsHaveWidth instead." - ); - setValue(this, "barsHaveWidth", val); - }; - })(this) - } - }); - - /** - * Specify a callback by assigning a function to the event. Once the event triggers the callback will be executed. - * - * **Note: All callbacks have been deprecated in favor of {@link CIQ.ChartEngine#addEventListener}** - * - * @type object - * @alias callbacks - * @memberof CIQ.ChartEngine# - * @example - * // using event listener - * stxx.addEventListener("callbackNameHere", function(callBackParametersHere){ - * CIQ.alert('triggered!'); - * }); - * @example - * // using callback function - * stxx.callbacks.callbackNameHere=function(callBackParametersHere){ - * CIQ.alert('triggered!'); - * }; - * @deprecated 4.0.0 - */ - this.callbacks = {}; - - function callbackGetter(name, stx, def) { - return function () { - log( - "CIQ.ChartEngine.prototype.callbacks have been deprecated. Iterate through CIQ.ChartEngine.prototype.callbackListeners instead." - ); - return getValue(this, name, def || null); - }; - } - - function callbackSetter(name, stx) { - return function (func) { - log( - "CIQ.ChartEngine.prototype.callbacks have been deprecated. Utilize CIQ.ChartEngine.prototype.addEventListener to add a callback, and/or CIQ.ChartEngine.prototype.removeEventListener to remove one." - ); - if (!this._deprecatedPropertyValues) this._deprecatedPropertyValues = {}; - var origFunc = this._deprecatedPropertyValues[name]; - if (origFunc) stx.removeEventListener(name, origFunc); - if (func) stx.addEventListener(name, func); - this._deprecatedPropertyValues[name] = func; - }; - } - - Object.defineProperties(this.callbacks, { - /** - * Called when a user right clicks on an overlay study. If `forceEdit==true` then a user has clicked - * on an edit button (cog wheel) so pull up an edit dialog. Otherwise they have simply right clicked so - * give them a context menu. - * - * ***Please note that this callback must be set *before* you call {@link CIQ.ChartEngine#importLayout}. - * Otherwise your imported studies will not have an edit capability*** - * - * Format:
- * studyOverlayEdit({stx:stx,sd:sd,inputs:inputs,outputs:outputs, parameters:parameters, forceEdit: forceEdit}); - * - * The following CSS entry must also be present to enable the `Right click to Manage` text on the mouse-over context menu (div class="mSticky" generated by {@link CIQ.ChartEngine.htmlControls}): - * ``` - * .rightclick_study .mouseManageText { - * display: inline; } - * ``` - * See {@link CIQ.Studies.addStudy} for more details. - * - * @type function - * @alias CIQ.ChartEngine#callbacks[`studyOverlayEdit`] - * @memberof CIQ.ChartEngine#callbacks - */ - studyOverlayEdit: { - enumerable: true, - get: callbackGetter("studyOverlayEdit", this), - set: callbackSetter("studyOverlayEdit", this) - }, - /** - * Called when a user clicks the edit button on a study panel. - * - * ***Please note that this callback should be set *before* you call {@link CIQ.ChartEngine#importLayout}. - * Otherwise your imported studies will not have an edit capability*** - * - * Format:
- * studyPanelEdit({stx:stx,sd:sd,inputs:inputs,outputs:outputs, parameters:parameters}); - * - * See {@link CIQ.Studies.addStudy} for more details. - * - * @type function - * @alias CIQ.ChartEngine#callbacks[`studyPanelEdit`] - * @memberof CIQ.ChartEngine#callbacks - */ - studyPanelEdit: { - enumerable: true, - get: callbackGetter("studyPanelEdit", this), - set: callbackSetter("studyPanelEdit", this) - }, - /** - * Called when a user clicks or taps on the chart. Not called if a drawing tool is active! - * - * Format:
- * callback({stx:CIQ.ChartEngine, panel:CIQ.ChartEngine.Panel, x:this.cx, y:this.cy}) - * @type function - * @alias CIQ.ChartEngine#callbacks[`tap`] - * @memberof CIQ.ChartEngine#callbacks - * @example - * // using event listener - * stxx.addEventListener("tap", function(tapObject){ - * CIQ.alert('tap event at x: ' + tapObject.x + ' y: '+ tapObject.y); - * }); - * @example - * // using callback - * // this example uses barFromPixel() to get the actual bar from the pixel location - * stxx.callbacks.tap= function(tapObject){ - * var msg= 'tap event at x: ' + tapObject.x + ' y: '+ tapObject.y; - * var bar=this.barFromPixel(this.cx); - * if(this.chart.dataSegment[bar]) { - * msg+=' Date:' + this.chart.dataSegment[bar].DT; - * msg+=' Close:' + this.chart.dataSegment[bar].Close; - * } - * alert (msg); - * }; - */ - tap: { - enumerable: true, - get: callbackGetter("tap", this), - set: callbackSetter("tap", this) - }, - /** - * Called when a user clicks or right clicks on the chart. Not called if the user right clicks on a drawing or study - * when [stxx.bypassRightClick]{@link CIQ.ChartEngine#bypassRightClick}=true - * - * Format:
- * callback({stx:CIQ.ChartEngine, panel:CIQ.ChartEngine.Panel, x:this.cx, y:this.cy}) - * @type function - * @alias CIQ.ChartEngine#callbacks[`rightClick`] - * @memberof CIQ.ChartEngine#callbacks - * @example - * // using event listener - * stxx.addEventListener("rightClick", function(rcObject){ - * alert('right click event at x: ' + rcObject.x + ' y: '+ rcObject.y); - * }); - * @since 09-2016-19 - */ - rightClick: { - enumerable: true, - get: callbackGetter("rightClick", this), - set: callbackSetter("rightClick", this) - }, - /** - * Called when a user "long holds" on the chart. By default this is set to 700 milliseconds. - * Optionally change the value of stxx.longHoldTime to a different setting, or set to zero to disable. - * - * Format:
- * callback({stx:CIQ.ChartEngine, panel:CIQ.ChartEngine.Panel, x:this.cx, y:this.cy}) - * @type function - * @alias CIQ.ChartEngine#callbacks[`longhold`] - * @memberof CIQ.ChartEngine#callbacks - * @example - * // using event listener - * stxx.longHoldTime=... // Optionally override default value of 700ms - * stxx.addEventListener("longhold", function(lhObject){ - * CIQ.alert('longhold event at x: ' + lhObject.x + ' y: '+ lhObject.y); - * }); - * @example - * // using callback function - * stxx.longHoldTime=... // Optionally override default value of 700ms - * stxx.callbacks.longhold=function(lhObject){ - * CIQ.alert('longhold event at x: ' + lhObject.x + ' y: '+ lhObject.y); - * }); - * @since 2016-06-22 - */ - longhold: { - enumerable: true, - get: callbackGetter("longHold", this), - set: callbackSetter("longHold", this) - }, - /** - * Called when a user moves on the chart. Not called if a drawing tool is active, panel resizing, etc - * grab is true if a mouse user has the mouse button down while moving. For touch users it is true - * if they do not have the crosshair tool enabled. - * - * Format:
- * callback({stx:CIQ.ChartEngine, panel:CIQ.ChartEngine.Panel, x:this.cx, y:this.cy, grab:boolean}) - * @type function - * @alias CIQ.ChartEngine#callbacks[`move`] - * @memberof CIQ.ChartEngine#callbacks - */ - move: { - enumerable: true, - get: callbackGetter("move", this), - set: callbackSetter("move", this) - }, - /** - * Called when the layout changes - * - * Format:
- * callback({stx:CIQ.ChartEngine, chart:CIQ.ChartEngine.Chart, symbol: String, symbolObject:Object, layout: Object}) - * @type function - * @alias CIQ.ChartEngine#callbacks[`layout`] - * @memberof CIQ.ChartEngine#callbacks - */ - layout: { - enumerable: true, - get: callbackGetter("layout", this), - set: callbackSetter("layout", this) - }, - /** - * Called when a drawing is added or deleted (all the drawings are returned, not just the new one) - * - * Format:
- * callback({stx:CIQ.ChartEngine, symbol: String, symbolObject:Object, drawings: Object}) - * @type function - * @alias CIQ.ChartEngine#callbacks[`drawing`] - * @memberof CIQ.ChartEngine#callbacks - */ - drawing: { - enumerable: true, - get: callbackGetter("drawing", this), - set: callbackSetter("drawing", this) - }, - /** - * Called when a right-click is detected on a highlighted drawing. - * - * Format:
- * callback({stx:CIQ.ChartEngine, drawing:CIQ.Drawing}) - * @type function - * @alias CIQ.ChartEngine#callbacks[`drawingEdit`] - * @memberof CIQ.ChartEngine#callbacks - * @since 6.2.0 - */ - drawingEdit: { - enumerable: true, - get: callbackGetter("drawingEdit", this), - set: callbackSetter("drawingEdit", this) - }, - /** - * Called when preferences are changed - * - * Format:
- * callback({stx:CIQ.ChartEngine}) - * @type function - * @alias CIQ.ChartEngine#callbacks[`preferences`] - * @memberof CIQ.ChartEngine#callbacks - */ - preferences: { - enumerable: true, - get: callbackGetter("preferences", this), - set: callbackSetter("preferences", this) - }, - /** - * Called when a theme is changed - * - * Format:
- * callback({stx:CIQ.ChartEngine}) - * @type function - * @alias CIQ.ChartEngine#callbacks[`theme`] - * @memberof CIQ.ChartEngine#callbacks - */ - theme: { - enumerable: true, - get: callbackGetter("theme", this), - set: callbackSetter("theme", this) - }, - /** - * Called when the symbol is changed (when loadChart is called), added (addSeries, addStudy) or removed (removeSeries, removeStudy). Note - * that this is not called if the symbol change occurs during an importLayout - * - * Format:
- * callback({stx:CIQ.ChartEngine, symbol: String, symbolObject:Object, action:["master"|"add-series"|"remove-series"}) - * @type function - * @alias CIQ.ChartEngine#callbacks[`symbolChange`] - * @memberof CIQ.ChartEngine#callbacks - * @since 06-2016-21 - */ - symbolChange: { - enumerable: true, - get: callbackGetter("symbolChange", this), - set: callbackSetter("symbolChange", this) - }, - /** - * Called when the symbol is first imported into the layout. - * - * Format:
- * callback({stx:CIQ.ChartEngine, symbol: String, symbolObject:Object, action:"master"}) - * @type function - * @alias CIQ.ChartEngine#callbacks[`symbolImport`] - * @memberof CIQ.ChartEngine#callbacks - * @since 4.0.0 - */ - symbolImport: { - enumerable: true, - get: callbackGetter("symbolImport", this), - set: callbackSetter("symbolImport", this) - }, - /** - * Called to determine how many decimal places the stock trades in. - * - * This is used for heads up display and also for the current price pointer label. - * - * By default it is set to {@link CIQ.calculateTradingDecimalPlaces} - * - * Format:
- * callback({stx:CIQ.ChartEngine, chart:CIQ.ChartEngine.Chart, symbol: String, symbolObject:Object}) - * - * @type function - * @alias CIQ.ChartEngine#callbacks[`calculateTradingDecimalPlaces`] - * @memberof CIQ.ChartEngine#callbacks - * @deprecated As of 8.0.0. Use {@link CIQ.ChartEngine.Chart#calculateTradingDecimalPlaces}. - */ - calculateTradingDecimalPlaces: { - enumerable: true, - get: (function (stx) { - return function () { - log( - "CIQ.ChartEngine.prototype.callbacks.calculateTradingDecimalPlaces has been deprecated. Utilize CIQ.ChartEngine.Chart.prototype.calculateTradingDecimalPlaces instead." - ); - return getValue( - this, - "calculateTradingDecimalPlaces", - stx.chart.calculateTradingDecimalPlaces - ); - }; - })(this), - set: (function (stx) { - return function (func) { - log( - "CIQ.ChartEngine.prototype.callbacks.calculateTradingDecimalPlaces has been deprecated. Utilize CIQ.ChartEngine.Chart.prototype.calculateTradingDecimalPlaces instead." - ); - setValue(this, "calculateTradingDecimalPlaces", func); - stx.chart.calculateTradingDecimalPlaces = func; - }; - })(this) - } - }); - - /** - * If true then {@link CIQ.ChartEngine#doCleanupGaps} is called so long as {@link CIQ.ChartEngine#cleanupGaps} is also set. - * This will ensure gaps will be filled in the master data from the last tick in the chart to the date of the trade. - * - * **Only applicable when using streamTrade()**.
Reminder: `tick` does not fill any gaps as it is not a predictable interval. - * - * @type boolean - * @default - * @alias CIQ.ChartEngine#streamParameters[`fillGaps`] - * @memberof CIQ.ChartEngine#streamParameters - * @since 2016-03-11 - * @deprecated See deprecation of {@link CIQ.ChartEngine#streamTrade}. Use {@link CIQ.ChartEngine#updateChartData} instead, - * with params.fillGaps=true or rely on cleanupGaps as default behavior. - */ - // Guard checking existence because this is a prototype object, no redefinition allowed - Object.defineProperty(this.streamParameters, "fillGaps", { - enumerable: true, - get: (function (stx) { - return function () { - log( - "CIQ.ChartEngine.prototype.streamParameters.fillGaps has been deprecated. Use CIQ.ChartEngine.prototype.updateChartData instead, with params.fillGaps=true or rely on cleanupGaps as default behavior." - ); - return getValue(this, "fillGaps", true); - }; - })(this), - set: (function (stx) { - return function (val) { - log( - "CIQ.ChartEngine.prototype.streamParameters.fillGaps has been deprecated. Use CIQ.ChartEngine.prototype.updateChartData instead, with params.fillGaps=true or rely on cleanupGaps as default behavior." - ); - setValue(this, "fillGaps", val); - }; - })(this) - }); -}; - -// These namespaces are only available for "legacy" implementations which run in browser and use global namespaces -if (typeof window != "undefined") { - Object.defineProperties(window, { - STX: { - enumerable: true, - get: function () { - log("STX namespace has been deprecated. Use CIQ namespace instead."); - return CIQ; - } - }, - STXChart: { - enumerable: true, - get: function () { - log( - "STXChart namespace has been deprecated. Use CIQ.ChartEngine namespace instead." - ); - return CIQ.ChartEngine; - } - } - }); -} - - - -/* - Deprecated functions - basic -*/ - -/** - * ** Deprecated. ** Use {@link CIQ.ChartEngine#attachQuoteFeed} instead. - * Attaches a quote feed to the charting engine, which causes the chart to pull data from the - * quote feed as needed. - * - * @param {object} [quoteFeed] A quote feed object. - * @param {object} [behavior] Optional behavior object to initialize tje quote feed. - * @param {number} [behavior.refreshInterval] Sets the frequency for `fetchUpdateData`. If - * null or zero, `fetchUpdateData` is not called. - * @param {function} [behavior.callback] Optional callback function called after any fetch to - * enhance functionality. It will be called with the params object used with the fetch - * call. - * @param {number} [behavior.noLoadMore] If true, the chart does not attempt to load any more - * data after the initial load. - * @param {boolean} [behavior.loadMoreReplace] If true, then when paginating, the driver - * replaces the master data instead of prepending. Set this if your feed can only provide - * a full data set of varying historical lengths. - * - * @memberOf CIQ.ChartEngine - * @private - * @since - * - 2016-12-01 - * - 8.0.0 Deprecated - * @deprecated Use {@link CIQ.ChartEngine#attachQuoteFeed}. - * - * @example - * Attach a quote feed and have the driver call fetchUpdateData once per - * second. - * stxx.attachEngineQuoteFeed(yourQuotefeed, {refreshInterval: 1}); - */ -CIQ.ChartEngine.prototype.attachEngineQuoteFeed = function ( - quoteFeed, - behavior -) { - log( - "CIQ.ChartEngine.prototype.attachEngineQuoteFeed has been deprecated. Use CIQ.ChartEngine.prototype.attachQuoteFeed instead." - ); - this.attachQuoteFeed(quoteFeed, behavior); -}; - -/** - * **Deprecated since 7.2.0.** Use {@link CIQ.ChartEngine#dragPlotOrAxis} instead. - * - * Detects whether the plot (series or study) should be dragged to another panel by examining the y-coordinate of the mouse - * and seeing if it is either over a different panel than the plot or close to another panel (or the top or bottom edge of the chart). - * If so, the plot is moved to the new panel. - * - * @param {number} cy Y-coordinate to test. - * @memberof CIQ.ChartEngine - * @since - * - 7.1.0 - * - 7.2.0 Removed functionality. Added console warning. - * @deprecated As of 7.2.0. See {@link CIQ.ChartEngine#dragPlotOrAxis}. - */ -CIQ.ChartEngine.prototype.dragPlot = function (cy) { - log( - "CIQ.ChartEngine.prototype.dragPlot is no longer supported. Use CIQ.ChartEngine.prototype.dragPlotOrAxis instead." - ); - return; -}; - -/** - * **Deprecated since 7.2.0.** Use {@link CIQ.ChartEngine#dragPlotOrAxis} instead. - * - * Detects whether the y-axis should be dragged to another position by examining the x-coordinate of the mouse - * and seeing if the mouse is over a different position than the axis. If so, the axis is moved to the new position. - * - * @param {number} cx X-coordinate to test. - * @memberof CIQ.ChartEngine - * @since - * - 7.1.0 - * - 7.2.0 Removed functionality. Added console warning. - * @deprecated As of 7.2.0. See {@link CIQ.ChartEngine#dragPlotOrAxis}. - */ -CIQ.ChartEngine.prototype.dragYAxis = function (cx) { - log( - "CIQ.ChartEngine.prototype.dragYAxis is no longer supported. Use CIQ.ChartEngine.prototype.dragPlotOrAxis instead." - ); - return; -}; - -CIQ.Drawing = - CIQ.Drawing || - function () { - this.chartsOnly = false; - this.penDown = false; - }; - -/** - * Compute the proper color to use when rendering lines in the drawing. - * - * @memberOf CIQ.Drawing - * @since - * - 4.0.0 - * - 7.0.0 Deprecated - * @deprecated Use {@link CIQ.Drawing#getLineColor} instead. - */ -CIQ.Drawing.prototype.setLineColor = function () { - log( - "CIQ.Drawing.prototype.setLineColor has been deprecated. Use CIQ.Drawing.prototype.setLineColor instead." - ); - if (CIQ.Drawing.prototype.getLineColor) - return CIQ.Drawing.prototype.getLineColor.apply(this, arguments); -}; - -CIQ.Studies = CIQ.Studies || function () {}; - -/** @deprecated **/ -CIQ.Studies.quickAddStudy = function () { - log( - "CIQ.Studies.quickAddStudy has been deprecated. Use CIQ.Studies.addStudy instead." - ); - if (CIQ.Studies.addStudy) return CIQ.Studies.addStudy.apply(null, arguments); -}; - -/** - * @deprecated Since 5.2.0. Use {@link CIQ.Studies.drawZones} instead. - */ -CIQ.Studies.overZones = function () { - log( - "CIQ.Studies.overZones has been deprecated. Use CIQ.Studies.drawZones instead." - ); - if (CIQ.Studies.drawZones) - return CIQ.Studies.drawZones.apply(null, arguments); -}; - -/** - * **Deprecated. Use {@link CIQ.Studies.createVolumeChart} instead.** - * - * Creates a volume underlay for the chart. - * - * The underlay height is a % of the chart height as determined by yAxis.heightFactor.
- * Each bar width will be determined by `WidthFactor` study parameter. - * @param {CIQ.ChartEngine} stx A chart engine instance - * @param {CIQ.Studies.StudyDescriptor} sd A study descriptor - * @param {array} quotes Array of quotes - * @memberOf CIQ.Studies - * @deprecated use {@link CIQ.Studies.createVolumeChart} - */ -CIQ.Studies.volUnderlay = function () { - log( - "CIQ.Studies.volUnderlay has been deprecated. Use CIQ.Studies.createVolumeChart instead." - ); - if (CIQ.Studies.createVolumeChart) - CIQ.Studies.createVolumeChart.apply(null, arguments); -}; - -/** - * **Deprecated since 5.2.0. This calculation is now done in {@link CIQ.ChartEngine.AdvancedInjectable#initializeDisplay} and is no longer a separate function.** - * - * Method to determine the minimum and maximum points in a study panel. - * - * @param {CIQ.ChartEngine} stx The chart object - * @param {CIQ.Studies.StudyDescriptor} sd The study descriptor - * @param {array} quotes The set of quotes to evaluate - * @memberOf CIQ.Studies - * @deprecated Since 5.2.0. This calculation is now done in {@link CIQ.ChartEngine.AdvancedInjectable#initializeDisplay} and is no longer a separate function. - */ -CIQ.Studies.determineMinMax = function (stx, sd, quotes) { - log( - "CIQ.Studies.determineMinMax is no longer supported. The calculation is done automatically elsewhere." - ); -}; - -/** - * Creates the yAxis for a study panel. - * - * @param {CIQ.ChartEngine} stx The chart object - * @param {CIQ.Studies.StudyDescriptor} sd The study descriptor - * @param {array} quotes The set of quotes (representing dataSegment) - * @param {CIQ.ChartEngine.Panel} panel A reference to the panel - * @memberOf CIQ.Studies - * @deprecated Since 5.2.0. yAxis is now created automatically via {@link CIQ.ChartEngine#renderYAxis} - */ -CIQ.Studies.createYAxis = function (stx, sd, quotes, panel) { - log( - "CIQ.Studies.createYAxis is no longer supported. The action is done automatically elsewhere." - ); -}; - -/** - * **Deprecated since 6.0.0. Use {@link CIQ.ChartEngine#drawHistogram} instead.** - * - * Convenience function for creating a volume style chart that supports multiple colors of volume bars. - * - * If borderMap (border colors) is passed in then the chart will display in a format where bars are flush against - * one another so that there is no white space between bars. If however a borderMap is not specified then white space will be left - * between the bars. - * @param {CIQ.ChartEngine} stx The chart object - * @param {CIQ.Studies.StudyDescriptor} sd The study descriptor - * @param {object} colorMap Map of colors to arrays. Each array should contain entries for each dataSegment bar mapped to that color. - * It should contain null values for any bar that shouldn't be drawn - * @param {object} borderMap Map of border colors for each color. If null then no borders will be drawn. - * @example - * var colorMap={}; - * colorMap["#FF0000"]=[56,123,null,null,45]; - * colorMap["#00FF00"]=[null,null,12,13,null]; - * - * var borderMap={ - * "#FF0000": "#FFFFFF", - * "#00FF00": "#FFFFDD" - * }; - * CIQ.Studies.volumeChart(stx, sd, colorMap, borderMap); - * @memberOf CIQ.Studies - * @deprecated since 6.0.0 Use {@link CIQ.ChartEngine#drawHistogram} instead. - */ -CIQ.Studies.volumeChart = function (stx, sd, colorMap, borderMap) { - log( - "CIQ.Studies.volumeChart has been deprecated. Use CIQ.ChartEngine.prototype.drawHistogram instead." - ); - // Determine min max - var maximum = Number.MAX_VALUE * -1; - var color, value; - for (color in colorMap) { - for (var c = 0; c < colorMap[color].length; c++) { - value = colorMap[color][c]; - if (!value) continue; - if (value > maximum) maximum = value; - } - } - - // determine calculation ratios - var panel = stx.panels[sd.panel]; - var b = Math.floor(panel.yAxis.bottom) + 0.5; - var t = Math.floor(panel.yAxis.top) + 0.5; - var h = b - t; - var candleWidth = stx.layout.candleWidth; - var borderColor = null; - if (!sd.parameters || !sd.parameters.displayBorder) borderMap = null; - var offset = 0; - if (!borderMap) offset = (candleWidth - stx.chart.tmpWidth) / 2; - var context = sd.getContext(stx); - context.lineWidth = 1; - stx.startClip(sd.panel); - for (color in colorMap) { - if (borderMap) borderColor = borderMap[color]; - context.fillStyle = color; - if (borderColor) context.strokeStyle = borderColor; - context.beginPath(); - var prevTop = b + 0.5; - var farLeft = Math.floor(stx.pixelFromBar(0, panel.chart)); - var prevRight; - for (var i = 0; i < colorMap[color].length; i++) { - if (stx.chart.dataSegment[i] && stx.chart.dataSegment[i].candleWidth) { - candleWidth = stx.chart.dataSegment[i].candleWidth; - if (!borderMap) offset = candleWidth / 4; - } else { - candleWidth = stx.layout.candleWidth; - if (!borderMap) offset = (candleWidth - stx.chart.tmpWidth) / 2; - } - if (i === 0) { - farLeft -= candleWidth / 2; - prevRight = farLeft; - } - value = colorMap[color][i]; - if (!value) { - prevTop = b; - prevRight += candleWidth; - //if(borderMap) prevRight-=0.5; - continue; - } - var y = value * (h / maximum); - var top = Math.min(Math.floor(b - h + (h - y)) + 0.5, b); - var x0, x1; - x0 = Math.floor(prevRight + offset); - x1 = Math.floor(prevRight + candleWidth - offset); - x0 = Math.max(x0, farLeft); - - context.moveTo(x0, b); - context.lineTo(x1, b); - context.lineTo(x1, top); - context.lineTo(x0, top); - if (borderMap) { - if (prevTop > top || i === 0) context.lineTo(x0, prevTop); // draw down to the top of the previous bar, so that we don't overlap strokes - } else { - context.lineTo(x0, b); - } - prevTop = top; - prevRight += candleWidth; - //if(borderMap) prevRight-=0.5; - } - context.fill(); - context.strokeStyle = borderColor; - if (borderMap && stx.layout.candleWidth >= 2) context.stroke(); - context.closePath(); - } - stx.endClip(); -}; - -// This namespace is only available for "legacy" implementations which run in browser and use global namespaces -if (typeof window != "undefined") { - Object.defineProperty(window, "STXSocial", { - enumerable: true, - get: function () { - log( - "STXSocial namespace has been deprecated. Use CIQ.Share namespace instead." - ); - return CIQ.Share; - } - }); -} - - - -/* - Deprecated functions - advanced -*/ - - - -/* global $ */ -/* - Deprecated functions - jquery & webcomponents -*/ - -if (typeof $ === "function" && $.fn) { - /** - * **Deprecated since 8.1.0.** Use {@link CIQ.trulyVisible} instead. - * - * Attaches a `trulyvisible` selector to a jQuery object. - * - * @private - * @deprecated Use {@link CIQ.trulyVisible}. - * @since 8.1.0 Deprecated. - * - * @example - * let visible = $(node).is(":trulyvisible"); - */ - $.fn.extend($.expr[":"], { - trulyvisible: function (node, j, attr) { - log( - "Use of jQuery has been deprecated. Use CIQ.trulyVisible() to return element visibility instead of custom pseudo-selector :trulyvisible." - ); - var parents = $(node).parents(); - parents = parents.add(node); - for (var i = 0; i < parents.length; i++) { - var p = $(parents[i]); - if (p.css("opacity") === "0") return false; - if (p.css("visibility") === "hidden") return false; - if (p.css("height") === "0px" && p.css("overflow-y") == "hidden") - return false; - if (!p.is(":visible")) return false; - } - return true; - } - }); - - /** - * **Deprecated since 8.1.0.** Use {@link CIQ.UI.stxtap} instead. - * - * Attaches a `stxtap` clickable event to a jQuery object. - * - * @param {string|function} arg1 A CSS selector used to filter the elements that trigger the - * event or a function that serves as the event handler. - * @param {function} arg2 A function that serves as the event handler if `arg1` is a selector. - * - * @private - * @deprecated Use {@link CIQ.UI.stxtap}. - * @since 8.1.0 Deprecated. - * - * @example - * $(node).stxtap(cb); - */ - var stxtap = function (arg1, arg2) { - log( - "Use of jQuery has been deprecated. Use CIQ.UI.stxtap() to attach a listener instead of $.fn.stxtap()." - ); - return this.each(function () { - CIQ.installTapEvent(this /*, {stopPropagation:true}*/); - if (typeof arg1 == "string") { - $(this).on("stxtap", arg1, function (e) { - arg2.call(this, e); - }); - } else { - $(this).on("stxtap", function (e) { - arg1.call(this, e); - }); - } - }); - }; - - /** - * **Deprecated since 8.1.0.** Use {@link CIQ.climbUpDomTree} instead. - * - * Returns an ancestry list starting with the current element. - * - * @param {*} arg1 Unused. - * @return {jQuery} The ancestor list in non-reversed order. - * - * @private - * @deprecated Use {@link CIQ.climbUpDomTree}. - * @since 8.1.0 Deprecated. - * - * @example - * $(node).parentsAndMe(); // Returns jQuery collection of elements from current node to HTML top element. - */ - var parentsAndMe = function (arg1) { - log( - "Use of jQuery has been deprecated. Use CIQ.climbUpDomTree() instead of $.fn.parentsAndMe()." - ); - var us = $(this).parents(); - us = us.add($(this)).get().reverse(); - return us; - }; - - /** - * **Deprecated since 8.1.0.** Use {@link CIQ.cqvirtual} instead. - * - * Creates and returns a virtual DOM of an element for faster manipulation. - * - * @param {*} arg1 Unused. - * @return {jQuery} A virtual DOM cloned from the actual DOM. - * - * @private - * @deprecated Use {@link CIQ.cqvirtual}. - * @since 8.1.0 Deprecated. - */ - var cqvirtual = function (arg1) { - log( - "Use of jQuery has been deprecated. Use CIQ.cqvirtual() instead of $.fn.cqvirtual()." - ); - var virtual = this.clone(true); - virtual.empty(); - virtual.original = this; - return virtual; - }; - - /** - * **Deprecated since 8.1.0.** Use {@link CIQ.cqrender} instead. - * - * Copies a virtual DOM to the actual DOM. Works in tandem with `cqvirtual`. - * - * @param {*} arg1 Unused. - * @return {jQuery} The actual DOM copied from the virtual DOM. - * - * @private - * @deprecated Use {@link CIQ.cqrender}. - * @since 8.1.0 Deprecated. - */ - var cqrender = function (arg1) { - log( - "Use of jQuery has been deprecated. Use CIQ.cqrender() instead of $.fn.cqrender()." - ); - if (this[0].innerHTML == this.original[0].innerHTML) return this.original; - this.original.children(":not(template)").remove(); - var children = this.children(); - if (children.length) { - var newStuff = children.detach(); - this.original.append(newStuff); - } - return this.original; - }; - - /** - * **Deprecated since 8.1.0.** Use {@link CIQ.guaranteedSize} instead. - * - * Returns a guaranteed width. For instance, `cq-context` or any other wrapping tag can have - * a width of zero; if so, we need to go up the ancestry tree to get the actual width. - * - * @return {number} The node width. - * - * @private - * @deprecated Use {@link CIQ.guaranteedSize}. - * @since 8.1.0 Deprecated. - * - * @example - * $(node).guaranteedWidth(); // Returns a width as a number. - */ - var guaranteedWidth = function () { - log( - "Use of jQuery has been deprecated. Use CIQ.guaranteedSize() instead of $.fn.guaranteedWidth()." - ); - var node = this; - var w = node.width(); - while (!w) { - node = node.parent(); - if (node[0].tagName === "BODY" || node[0] === window) { - return window.innerWidth; - } - w = node.width(); - } - return w; - }; - - /** - * **Deprecated since 8.1.0.** Use {@link CIQ.guaranteedSize} instead. - * - * Returns a guaranteed height. A wrapping tag, such as `cq-context`, can have a width of - * zero; if so, we need to go up the ancestry tree to get the actual height. - * - * @return {number} The node height. - * - * @private - * @deprecated Use {@link CIQ.guaranteedSize}. - * @since 8.1.0 Deprecated. - * - * @example - * $(node).guaranteedHeight(); // Returns a height as a number. - */ - var guaranteedHeight = function () { - log( - "Use of jQuery has been deprecated. Use CIQ.guaranteedSize() instead of $.fn.guaranteedHeight()." - ); - var node = this; - var h = node.height(); - while (!h) { - node = node.parent(); - if (node[0].tagName === "BODY" || node[0] === window) { - return window.innerHeight; - } - h = node.height(); - } - return h; - }; - - /** - * **Deprecated since 8.1.0.** Use {@link CIQ.removeChildIfNot} instead. - * - * Removes all children of a node except for the "template" tags. - * - * @return {jQuery} The node from which the children have been removed. - * - * @private - * @deprecated Use {@link CIQ.removeChildIfNot} and pass "template" as the selector argument. - * @since 8.1.0 Deprecated. - */ - var emptyExceptTemplate = function () { - log( - "Use of jQuery has been deprecated. Use CIQ.removeChildIfNot(node, 'template') instead of $.fn.emptyExceptTemplate()." - ); - this.children().not("template").remove(); - return this; - }; - - /** - * **Deprecated since 8.1.0.** Use `node.getAttribute()` and check the result against an array - * of falsey values instead. - * - * @param {string} arg1 The name of the attribute checked for its truthy value. - * @return {boolean} true if the attribute exists and is not explicitly set to false; - * otherwise, false. - * - * @private - * @deprecated Use ["false", "0", null, undefined].indexOf(this.getAttribute("...")) == -1 - * @since 8.1.0 Deprecated. - */ - var truthyAttr = function (arg1) { - log( - "Use of jQuery has been deprecated. Use ['false','0',null,undefined].indexOf(this.getAttribute('...'))==-1 instead of $.fn.truthyAttr()." - ); - var val = this.attr(arg1); - if (typeof val == "undefined") return false; - if (val.toLowerCase() == "false") return false; - if (val == "0") return false; - return true; - }; - - /** - * **Deprecated since 8.1.0.** Check attribute before setting the attribute value instead. - * - * Checks an attribute to see if it needs to be changed before changing it. Efficient - * because it doesn't change the DOM unless it needs to. Note that this does not support - * jQuery chaining. - * - * @param {string} attribute The attribute to be checked. - * @param {*} value The value to apply to the attribute if the attribute does not already have - * this value. - * - * @private - * @deprecated Check attribute before setting instead. - * @since 8.1.0 Deprecated. - */ - var attrBetter = function (attribute, value) { - log( - "Use of jQuery has been deprecated. check attribute value before setting instead of $.fn.attrBetter()." - ); - return this.attr(attribute, function (i, val) { - if (typeof value == "undefined") value = "true"; - if (value !== val) return value; - }); - }; - - /** - * **Deprecated since 8.1.0.** Check `hasAttribute` before removing the attribute instead. - * - * Removes an attribute if the attribute has a value. Note that this does not support jQuery - * chaining. - * - * @param {string} attribute The attribute to be removed. - * @return {boolean} true if the attribute was removed, false if the attribute did not have a - * value. - * - * @private - * @deprecated Check `hasAttribute` before removing instead. - * @since 8.1.0 Deprecated. - */ - var removeAttrBetter = function (attribute) { - log( - "Use of jQuery has been deprecated. check hasAttribute before removing instead of $.fn.removeAttrBetter()." - ); - var val = this.attr(attribute); - if (!val && val !== "") return false; - this.removeAttr(attribute); - return true; - }; - - /** - * **Deprecated since 8.1.0.** Check `innerText` before setting the text instead. - * - * Checks `innerText` to see if it needs to be changed before changing it. Efficient because - * it doesn't change the DOM unless it needs to. Note that this is a setter function only. It - * is not meant to replace the getter aspect of jQuery's built in `text()` function. - * - * @param {string} str The text to which `innerText` is changed if `innerText` is not already - * the same as this text. - * @return {boolean} true if `innerText` was changed; otherwise, false. - * - * @private - * @deprecated Check `innerText` before setting instead. - * @since 8.1.0 Deprecated. - */ - var textBetter = function (str) { - log( - "Use of jQuery has been deprecated. check innerText before setting instead of $.fn.textBetter()." - ); - if (this.text() === str) return false; - this.text(str); - return true; - }; - - $.fn.extend({ - stxtap, - parentsAndMe, - cqvirtual, - cqrender, - guaranteedWidth, - guaranteedHeight, - emptyExceptTemplate, - truthyAttr, - attrBetter, - removeAttrBetter, - textBetter - }); - - /** - * **Deprecated since 8.1.0.** Use {@link CIQ.qs} instead. - * - * Returns the value of a token in a page's URL. - * - * @param {string} sParam The token for which a value is returned. - * @return {string} The value of token or null if the token does not exist in the URL. - * - * @private - * @deprecated Use {@link CIQ.qs} instead. - * @since 8.1.0 Deprecated. - * - * @example - * // Assume the page URL is "http://127.0.0.1:8000?name=value&foo=bar..." - * var value = $.queryString("name"); - */ - $.queryString = function (sParam) { - log( - "Use of jQuery has been deprecated. Use CIQ.qs() to return an object containing querystring tokens instead of $.querystring()." - ); - var sPageURL = window.location.search.substring(1); - var sURLVariables = sPageURL.split("&"); - for (var i = 0; i < sURLVariables.length; i++) { - var sParameterName = sURLVariables[i].split("="); - if (sParameterName[0] == sParam) return sParameterName[1]; - } - return null; - }; -} - -if (!CIQ.UI) CIQ.UI = {}; - -/** - * **Deprecated since 8.1.0.** Use `document.querySelectorAll("cq-context,*[cq-context]")` instead. - * - * Utility function that returns all contexts on the screen. - * - * Designed to be used as a helper method for the included {@link WebComponents}. A full - * tutorial on how to work with and customize the web components can be found here: - * {@tutorial Web Component Interface}. - * - * @return {jQuery} A jQuery node with all contexts. - * - * @memberof CIQ.UI - * @deprecated Use `document.querySelectorAll("cq-context,*[cq-context]")`. - * @since 8.1.0 Deprecated. - */ -CIQ.UI.allContexts = function () { - log( - "CIQ.UI.allContexts has been deprecated. Use document.querySelectorAll('cq-context,*[cq-context]') instead." - ); - return $("cq-context,*[cq-context]"); -}; - -/** - * Static method to create an observable. - * - * Designed to be used as a helper method for the included {@link WebComponents}. A full - * tutorial on how to work with and customize the Web Components can be found here: - * {@tutorial Web Component Interface}. - * - * @param {Object} params Parameters. - * @param {String} [params.selector] The selector to effect the observable (adding class, - * setting value). - * @param {Object} params.obj The object to observe. - * @param {String} [params.member] The member of the object to observe. Pass an array to - * observe multiple members. Or pass nothing to observe any change to the object. - * @param {String} [params.condition] Optional condition for the member to trigger the action. - * @param {String} params.action The action to take: "class" - add or remove a class, - * "callback" - calls back with params. - * @param {String} params.value The value for the action (for example, class name or - * callback function). - * @return {Function} Handler for use when unobserving. - * - * @memberof CIQ.UI - * - * @example - * Add or remove a class based on whether stx.layout.crosshair is true or false. - * CIQ.UI.observe({selector:".toggle", obj:stx.layout, member:"crosshair", action:"class", value:"active"}); - * - * @example - * Add or remove a class based on whether stx.layout.chartType=="candle". - * CIQ.UI.observe({selector:".toggle", obj:stx.layout, member:"chartType", condition:"candle", action:"class", value:"active"}); - * - * @example - * Get a callback from a change in value. - * CIQ.UI.observe({selector:".toggle", obj:stx.layout, member:"chartType", condition:"candle", action:"callback", value:function(params){ - * console.log("new value is" + params.obj[params.member]); - * }}); - * - * @since 7.1.0 Returns the handler. - * @deprecated See {@link CIQ.UI.observeProperty}. - */ -CIQ.UI.observe = function (params) { - log( - "CIQ.UI.observe has been deprecated. Use CIQ.UI.observeProperty instead." - ); - if (!Object.observe) { - log( - "You must include thirdparty/object-observe.js in your project to use CIQ.UI.observe." - ); - return; - } - if (typeof $ !== "function" || !$.fn) { - log("You must include jQuery in your project to use CIQ.UI.observe."); - return; - } - - var self = this; - function observed(change) { - var match = false; - if (!params.member) { - // wildcard - match = true; - } else if (change.name === params.member) { - match = true; - } else if (params.member.constructor == Array) { - for (var i = 0; i < params.member.length; i++) { - if (change.name === params.member[i]) match = true; - } - } - if (match) { - var nodes = $(params.selector); - if (!nodes.length && params.action === "callback") { - // simple callback not associated with a selector - params.value.call(self, params); - return; - } - if (params.action === "class") nodes.removeClass(params.value); - nodes.each(function () { - var isTrue = false; - if (params.member) { - if (params.condition) { - if (params.obj[params.member] === params.condition) isTrue = true; - } else { - isTrue = params.obj[params.member]; - } - } - if (params.action === "class") { - if (isTrue) nodes.addClass(params.value); - } - if (params.action === "callback") { - params.value.call(self, params, this); - } - if (params.action === "value") { - if (params.value) { - this.value = params.value; - } else { - if (!params.obj[params.member]) this.value = ""; - else this.value = params.obj[params.member]; - } - } - }); - } - } - var handler = function (changes) { - changes.forEach(observed); - }; - Object.observe(params.obj, handler, ["update", "add", "delete"]); - observed({ name: params.member }); // initialize - return handler; -}; - -/** - * Static method to remove an observable. - * - * @param {Object} params Parameters. - * @param {Object} params.obj The object being observed. - * @param {function} params.handler The handler to remove. - * - * @memberof CIQ.UI - * @since 7.1.0 - * @deprecated See {@link CIQ.UI.unobserveProperty}. - */ -CIQ.UI.unobserve = function (params) { - log( - "CIQ.UI.unobserve has been deprecated. Use CIQ.UI.unobserveProperty instead." - ); - if (Object.unobserve) Object.unobserve(params.obj, params.handler); -}; - -/** - * Determines the visibility of a DOM element based on the following CSS properties: - * - opacity - * - display - * - visibility - * - width - * - height - * - * @param {HTMLElement} node The node for which visibility is determined. - * @return {boolean} Whether the element is visible. - * - * @memberof CIQ.UI - * @deprecated See {@link CIQ.trulyVisible}. - * @since - * - 8.1.0 - * - 8.2.0 Deprecated - */ -CIQ.UI.trulyVisible = function (node) { - log( - "CIQ.UI.trulyVisible has been deprecated. Use CIQ.trulyVisible instead." - ); - return CIQ.trulyVisible(node); -}; - -/** - * @name CIQ.UI.Lookup - * @constructor - * @deprecated Use {@link CIQ.ChartEngine.Driver.Lookup} - * @since 6.0.0 Deprecated - */ -CIQ.UI.Lookup = function () {}; - -/** - * @name CIQ.UI.Lookup.Driver - * @constructor - * @deprecated Use {@link CIQ.ChartEngine.Driver.Lookup} - * @since 6.0.0 Deprecated - */ -CIQ.UI.Lookup.Driver = function () { - this.deprecated = true; -}; - -/** - * @memberof CIQ.UI.Lookup.Driver - * @deprecated Use {@link CIQ.ChartEngine.Driver.Lookup#acceptText} - * @since 6.0.0 Deprecated - */ -CIQ.UI.Lookup.Driver.prototype.acceptText = function ( - text, - filter, - maxResults, - cb -) { - if (!this.cb) return; -}; - -/** - * @name CIQ.UI.Lookup.Driver.ChartIQ - * @constructor - * @deprecated Use {@link CIQ.ChartEngine.Driver.Lookup.ChartIQ} - * @since 6.0.0 Deprecated - */ -CIQ.UI.Lookup.Driver.ChartIQ = function (exchanges) { - log( - "CIQ.UI.Lookup.Driver.ChartIQ has been deprecated. Use CIQ.ChartEngine.Driver.Lookup.ChartIQ instead." - ); - this.exchanges = exchanges; - if (!this.exchanges) - this.exchanges = [ - "XNYS", - "XASE", - "XNAS", - "XASX", - "INDCBSX", - "INDXASE", - "INDXNAS", - "IND_DJI", - "ARCX", - "INDARCX", - "forex" - ]; - this.url = - "https://symbols.chartiq.com/chiq.symbolserver.SymbolLookup.service"; - this.requestCounter = 0; //used to invalidate old requests - //t=ibm&m=10&x=[]&e=STOCKS -}; -CIQ.inheritsFrom(CIQ.UI.Lookup.Driver.ChartIQ, CIQ.UI.Lookup.Driver); -/** - * @memberof CIQ.UI.Lookup.Driver.ChartIQ - * @deprecated Use {@link CIQ.ChartEngine.Driver.Lookup.ChartIQ#acceptText} - * @since 6.0.0 Deprecated - */ -CIQ.UI.Lookup.Driver.ChartIQ.prototype.acceptText = function ( - text, - filter, - maxResults, - cb -) { - if (filter == "FX") filter = "FOREX"; - if (isNaN(parseInt(maxResults, 10))) maxResults = 100; - var url = - this.url + "?t=" + encodeURIComponent(text) + "&m=" + maxResults + "&x=["; - if (this.exchanges) { - url += this.exchanges.join(","); - } - url += "]"; - if (filter && filter.toUpperCase() != "ALL") { - url += "&e=" + filter; - } - - var counter = ++this.requestCounter; - var self = this; - function handleResponse(status, response) { - if (counter < self.requestCounter) return; - if (status != 200) return; - try { - response = JSON.parse(response); - var symbols = response.payload.symbols; - - var results = []; - for (var i = 0; i < symbols.length; i++) { - var fields = symbols[i].split("|"); - var item = { - symbol: fields[0], - name: fields[1], - exchDisp: fields[2] - }; - results.push({ - display: [item.symbol, item.name, item.exchDisp], - data: item - }); - } - cb(results); - } catch (e) {} - } - CIQ.postAjax({ url: url, cb: handleResponse }); -}; - -if (CIQ.UI.BaseComponent) { - /** - * Set bindings for a node that has been created dynamically. The attribute can be either - * "stxbind", "stxtap" or "stxsetget". - * - * @alias CIQ.UI.BaseComponent.bind - * @memberof CIQ.UI.BaseComponent - * @deprecated 7.0.0 - * - * @see {@link CIQ.UI.BaseComponent.bindNode} - */ - CIQ.UI.BaseComponent.bind = function (node, params) { - log( - "CIQ.UI.BaseComponent.bind has been deprecated. Use CIQ.UI.BaseComponent.bindNode() instead." - ); - CIQ.UI.BaseComponent.bindNode(node, params); - }; -} diff --git a/chartiq/development/js/standard.js b/chartiq/development/js/standard.js deleted file mode 100644 index d7bee89e74..0000000000 --- a/chartiq/development/js/standard.js +++ /dev/null @@ -1,25348 +0,0 @@ -/***************************************************************************! - WARNING: this file is for internal development and debugging purposes only! - It may *not* be posted publicly under any circumstances without explicit - consent from ChartIQ. -****************************************************************************/ -/**! - * 8.2.0 - * Generation date: 2023-03-23T15:05:01.971Z - * Client name: deriv limited - * Package Type: Technical Analysis - * License type: annual - * Expiration date: "2024/04/01" - * Domain lock: ["127.0.0.1","localhost","deriv.com","deriv.app","deriv.me","binary.com","binary.sx","binary.me","binary.bot","deriv.be"] - * iFrame lock: true - */ - -/***********************************************************! - * Copyright by ChartIQ, Inc. - * Licensed under the ChartIQ, Inc. Developer License Agreement https://www.chartiq.com/developer-license-agreement -*************************************************************/ -/*************************************! DO NOT MAKE CHANGES TO THIS LIBRARY FILE!! !************************************* -* If you wish to overwrite default functionality, create a separate file with a copy of the methods you are overwriting * -* and load that file right after the library has been loaded, but before the chart engine is instantiated. * -* Directly modifying library files will prevent upgrades and the ability for ChartIQ to support your solution. * -*************************************************************************************************************************/ -/* eslint-disable no-extra-parens */ - - -import {CIQ as __CIQ_, SplinePlotter as __SplinePlotter_, timezoneJS as __timezoneJS_, $$ as __$$_, $$$ as __$$$_} from "../js/chartiq.js"; - - -let __js_standard_createEngine_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -class CallbackNVStore { - get(x, f) { - f("no storage defined"); - } - - set(x, y) {} - - remove(x) {} -} - -var Storage; - -/** - * Convenience function that uses the configuration provided in `params.config` to create the - * chart engine, attach quote feeds, initialize add-ons, add event listeners, and load the - * chart. - * - * Use this function to simplify chart creation when you have a well defined configuration object. - * A default configuration object can be obtained from *defaultConfiguration.js* (in the *js* - * folder of your library). - * - * **Note:** You can also create a chart without using this function. For example, create the chart - * engine by instantiating {@link CIQ.ChartEngine}. Attach quote feeds with - * {@link CIQ.ChartEngine#attachQuoteFeed}. Instantiate add-ons such as {@link CIQ.Tooltip} and - * {@link CIQ.InactivityTimer} to add them to the chart engine. Add event listeners with - * {@link CIQ.ChartEngine#addEventListener}. Load the chart with {@link CIQ.ChartEngine#loadChart}. - * - * @param {object} [params] Function parameters. - * @param {HTMLElement} [params.container] The HTML element in which the chart engine is - * created. - * @param {object} [params.config] Contains configuration specifications. - * @param {object} [params.config.chartEngineParams] Parameters required by the - * {@link CIQ.ChartEngine} constructor except for a reference to the container HTML - * element, which is provided by `params.container`, for example: - * ``` - * { - * layout: { - * "chartType": "candle", - * "crosshair": true, - * "candleWidth": 30, - * "periodicity": 1, - * "interval": 'day', - * }, - * preferences: { - * "currentPriceLine": true, - * "whitespace": 100 - * }, - * chart: { - * yAxis: { - * position: 'left' - * } - * } - * } - * ``` - * @param {object} [params.config.quoteFeeds] Array of quote feed objects to attach to the chart - * engine. - * @param {object} [params.config.marketFactory] Market factory object. When not provided, - * {@link CIQ.Market.Symbology.factory} is used if available. - * @param {object} [params.config.addOns] Initialization properties for add-ons. - * @param {string} [params.config.chartId] Identifies the chart created by the chart engine. - * @param {function} [params.config.onChartReady] A callback function to call when the chart has - * been loaded. - * @param {object} [params.config.callbacks] Event listeners to add to the chart engine. Use this - * parameter to replace the default listeners for - * [layout]{@link CIQ.ChartEngine~layoutEventListener}, - * [symbolChange]{@link CIQ.ChartEngine~symbolChangeEventListener}, - * [drawing]{@link CIQ.ChartEngine~drawingEventListener}, - * [preferences]{@link CIQ.ChartEngine~preferencesEventListener}, and - * [newChart]{@link CIQ.ChartEngine~newChartEventListener}. - * **Note:** Other event listeners can be added to the chart engine using this parameter, but - * the recommended approach for listeners other than the defaults is to use - * {@link CIQ.ChartEngine#addEventListener}. - * @param {function} [params.config.callbacks.layout] Event listener that replaces the default - * implementation provided by [getSaveLayout]{@link CIQ.ChartEngine.getSaveLayout}. - * @param {function} [params.config.callbacks.symbolChange] Event listener that replaces the - * default implementation provided by [getSaveLayout]{@link CIQ.ChartEngine.getSaveLayout}. - * @param {function} [params.config.callbacks.drawing] Event listener that replaces the default - * implementation provided by [getSaveDrawings]{@link CIQ.ChartEngine.getSaveDrawings}. - * @param {function} [params.config.callbacks.preferences] Event listener that replaces the - * default implementation provided by - * [getSavePreferences]{@link CIQ.ChartEngine.getSavePreferences}. - * @param {function} [params.config.callbacks.newChart] Event listener that replaces the default - * implementation provided by [getRetoggleEvents]{@link CIQ.ChartEngine.getRetoggleEvents}. - * @param {object} [params.config.initialData] Initial data to show on the chart. - * @param {boolean} [params.config.restore] True if storage is to be used. - * @param {boolean} [params.deferLoad] If true, the chart is created but not loaded. - * @return {CIQ.ChartEngine} A reference to a new chart engine. - * - * @alias create - * @memberof CIQ.ChartEngine - * @static - * @since - * - 7.5.0 - * - 8.0.0 Renamed from `CIQ.UI.Chart#createChart`. Revised parameter list from - * `(container, config = {})`. - */ -CIQ.ChartEngine.create = function ({ container, config, deferLoad } = {}) { - if (!container) - container = document.querySelector(".chartContainer") || document.body; - if (!config) config = {}; - - const chartParams = Object.assign({ container }, config.chartEngineParams); - const stx = new this(chartParams); - - const { quoteFeeds, marketFactory, addOns, chartId, onChartReady } = config; - - if (quoteFeeds && stx.attachQuoteFeed) { - quoteFeeds.forEach(({ quoteFeed, behavior, filter }) => { - stx.attachQuoteFeed(quoteFeed, behavior, filter); - }); - } - - if (marketFactory) stx.setMarketFactory(marketFactory); - - if (addOns) { - Object.entries(addOns) - .filter(([, params]) => !!params) // remove inactive addOns - .forEach(([itemName, params]) => { - if (!config.enabledAddOns[itemName]) return; - const extensionName = params.moduleName || CIQ.capitalize(itemName); - if (CIQ[extensionName]) { - const { cssRequired } = new CIQ[extensionName]( - Object.assign({ stx }, params, { config }) - ); - if (cssRequired && CIQ.UI) { - CIQ.UI.activatePluginUI(stx, extensionName); - } - } else if (CIQ.debug) { - console.log( - `${extensionName} not available for addons with params:`, - params - ); - } - }); - } - - const callbacks = CIQ.ensureDefaults(config.callbacks || {}, { - layout: this.getSaveLayout(config), - symbolChange: this.getSaveLayout(config), - drawing: this.getSaveDrawings(config), - preferences: this.getSavePreferences(config), - newChart: this.getRetoggleEvents(config) - }); - - for (let cb in callbacks) { - if (callbacks[cb]) stx.addEventListener(cb, callbacks[cb]); - } - - Storage = config.nameValueStore || CIQ.NameValueStore || CallbackNVStore; - - Storage = new Storage(); - - if (!deferLoad) { - if (config.restore) { - this.restorePreferences(stx, chartId); - this.restoreLayout( - stx, - (err) => { - // if import does not contain symbol load default - if (!stx.chart.symbol && config.initialSymbol) { - loadSymbol(); - } else { - cbChartReady(); - } - }, - chartId - ); - } else { - loadSymbol(); - } - } - - return stx; - - function loadSymbol() { - stx.loadChart( - config.initialSymbol, - { masterData: config.initialData }, - cbChartReady - ); - stx.draw(); - } - - function cbChartReady() { - if (!onChartReady) return; - // execute configuration callback on next tick - // as this function can be invoked synchronously, for example if there is no - // symbol in layout and default symbol is not providing, leading to configuration - // callback executed before call stack is cleard - setTimeout(() => onChartReady(stx)); - } -}; - -/** - * Returns a callback function that saves chart layout information. Uses an instance of - * {@link CIQ.NameValueStore} if one is available; otherwise, saves the layout information to - * local storage. - * - * **Note:** You can also serialize the chart layout using - * {@link CIQ.ChartEngine#exportLayout}. - * - * @param {object} [config] Configuration parameters. - * @param {string} [config.chartId] Identifies the layout in local storage for a specific chart. - * @param {boolean} [config.restore] Indicates whether the layout is restorable. If false, the - * returned callback function does not save the chart layout. - * @return {function} A callback function that saves the chart layout in local storage. The - * returned callback function is typically added to the chart engine as a - * [layoutEventListener]{@link CIQ.ChartEngine~layoutEventListener} or - * [symbolChangeEventListener]{@link CIQ.ChartEngine~symbolChangeEventListener}. - * - * @alias getSaveLayout - * @memberof CIQ.ChartEngine - * @static - * @since - * - 7.5.0 - * - 8.0.0 Renamed from `CIQ.UI.Chart#getSaveLayout`. - */ -CIQ.ChartEngine.getSaveLayout = function (config) { - return function saveLayout({ stx }) { - if (config.restore && stx.exportLayout) { - var s = JSON.stringify(stx.exportLayout(true)); - Storage.set("myChartLayout" + (config.chartId || ""), s); - } - }; -}; - -/** - * Restores the chart layout from {@link CIQ.NameValueStore} if an instance is available; - * otherwise, restores the layout from local storage. - * - * **Note:** You can also restore the chart layout using {@link CIQ.ChartEngine#importLayout} and - * {@link CIQ.ChartEngine#importDrawings}. - * - * @param {CIQ.ChartEngine} stx A reference to the chart engine. - * @param {function} cb A callback function to be called when restoration of the layout is - * complete. - * @param {string} id The local storage identifier for the saved chart layout. See - * [getSaveLayout]{@link CIQ.ChartEngine.getSaveLayout}. - * - * @alias restoreLayout - * @memberof CIQ.ChartEngine - * @static - * @since - * - 7.5.0 - * - 8.0.0 Renamed from `CIQ.UI.Chart#restoreLayout`. - */ -CIQ.ChartEngine.restoreLayout = function (stx, cb, id) { - const { restoreDrawings } = this; - if (!id) id = ""; - - function closure() { - restoreDrawings(stx, stx.chart.symbol, id); - if (cb) cb(); - } - - Storage.get("myChartLayout" + id, function (error, datum) { - if (error) return; - - try { - datum = JSON.parse(datum); - } catch (e) {} - if (stx.importLayout) - stx.importLayout(datum, { - managePeriodicity: true, - cb: closure - }); - - if (stx.termStructure) { - stx.setCandleWidth(1); // don't preserve zoom state for term structure plugin - } - }); -}; - -/** - * Returns a callback function that saves the state of chart drawings. Uses an instance of - * {@link CIQ.NameValueStore} if one is available; otherwise, saves the state of the drawings in - * local storage. - * - * **Note:** You can also serialize the state of chart drawings using - * {@link CIQ.ChartEngine#exportDrawings}. - * - * @param {object} [config] Configuration parameters. - * @param {string} [config.chartId] Identifies the drawings in local storage for a specific chart. - * @param {boolean} [config.restore] Indicates whether the chart drawings are restorable. If - * false, the returned callback function does not save the chart drawings. - * @return {function} A callback function that saves the state of the chart drawings. The returned - * callback function is typically added to the chart engine as a - * [drawingEventListener]{@link CIQ.ChartEngine~drawingEventListener}. - * - * @alias getSaveDrawings - * @memberof CIQ.ChartEngine - * @static - * @since - * - 7.5.0 - * - 8.0.0 Renamed from `CIQ.UI.Chart#getSaveDrawings`. - */ -CIQ.ChartEngine.getSaveDrawings = function (config) { - return function saveDrawings({ stx, symbol }) { - if (config.restore && stx.exportDrawings) { - var tmp = stx.exportDrawings(); - var key = config.chartId ? config.chartId + "~" + symbol : symbol; - if (tmp.length === 0) { - Storage.remove(key); - } else { - Storage.set(key, JSON.stringify(tmp)); - } - } - }; -}; - -/** - * Restores the chart drawings from {@link CIQ.NameValueStore} if an instance is available; - * otherwise, restores the drawings from local storage. - * - * **Note:** You can also restore saved chart drawings using - * {@link CIQ.ChartEngine#importDrawings}. - * - * @param {CIQ.ChartEngine} stx A reference to the chart engine. - * @param {string} symbol The chart symbol. Used along with `id` to identify the chart drawings in - * local storage. - * @param {string} [id] The local storage identifier for the saved drawings. See - * [getSaveDrawings]{@link CIQ.ChartEngine.getSaveDrawings}. - * - * @alias restoreDrawings - * @memberof CIQ.ChartEngine - * @static - * @since - * - 7.5.0 - * - 8.0.0 Renamed from `CIQ.UI.Chart#restoreDrawings`. - */ -CIQ.ChartEngine.restoreDrawings = function (stx, symbol, id) { - if (!CIQ.Drawing) return; - const recId = id ? id + "~" + symbol : symbol; - Storage.get(recId, function (error, memory) { - if (error) return; - try { - memory = JSON.parse(memory); - } catch (e) {} - if (memory) { - stx.importDrawings(memory); - stx.draw(); - } - }); -}; - -/** - * Returns a callback function that saves the chart preferences. Uses an instance of - * {@link CIQ.NameValueStore} if one is available; otherwise, saves the preferences in local - * storage. - * - * **Note:** You can also capture chart preferences using - * {@link CIQ.ChartEngine#exportPreferences}. - * - * @param {object} [config] Configuration parameters. - * @param {string} [config.chartId] Identifies the preferences in local storage for a specific - * chart. - * @param {boolean} [config.restore] Indicates whether the chart preferences are restorable. If - * false, the returned callback function does not save the chart preferences. - * @return {function} A callback function that saves the chart preferences. The returned callback - * function is typically added to the chart engine as a - * [preferencesEventListener]{@link CIQ.ChartEngine~preferencesEventListener}. - * - * @alias getSavePreferences - * @memberof CIQ.ChartEngine - * @static - * @since - * - 7.5.0 - * - 8.0.0 Renamed from `CIQ.UI.Chart#savePreferences`. Revised parameter list from `({ stx })`. - * Now returns a function. - */ -CIQ.ChartEngine.getSavePreferences = function (config) { - return function savePreferences({ stx }) { - if (config.restore && stx.exportPreferences) { - var s = JSON.stringify(stx.exportPreferences()); - Storage.set("myChartPreferences" + (config.chartId || ""), s); - } - }; -}; - -/** - * Restores the chart preferences from {@link CIQ.NameValueStore} if an instance is available; - * otherwise, restores the preferences from local storage. - * - * **Note:** You can also restore the chart preferences using - * {@link CIQ.ChartEngine#importPreferences}. - * - * @param {CIQ.ChartEngine} stx A reference to the chart engine. - * @param {string} [id] The local storage identifier for the saved chart preferences. See - * [getSavePreferences]{@link CIQ.ChartEngine.getSavePreferences}. - * - * @alias restorePreferences - * @memberof CIQ.ChartEngine - * @static - * @since - * - 7.5.0 - * - 8.0.0 Renamed from `CIQ.UI.Chart#restorePreferences`. - */ -CIQ.ChartEngine.restorePreferences = function (stx, id) { - if (!id) id = ""; - Storage.get("myChartPreferences" + id, function (error, pref) { - if (error) return; - - try { - pref = JSON.parse(pref); - } catch (e) {} - - if (pref && stx.importPreferences) stx.importPreferences(pref); - }); -}; - -/** - * Returns a callback function that restores the state of the chart markers. - * - * @param {object} [config] Configuration parameters. - * @param {string} [config.chartId] Identifies the chart for which the state of the markers is - * restored. - * @param {string} [config.selector.markersMenuItem] A CSS selector used to obtain references to - * the DOM nodes that represent the marker radio buttons in the chart user interface. The DOM - * nodes can be used to invoke the radio button event listeners to turn the markers on and - * off. See *js/defaultConfiguration.js* for an example of this parameter. - * @return {function} A callback function that restores the state of the chart markers. The - * returned function is typically assigned to - * [newChartEventListener]{@link CIQ.ChartEngine~newChartEventListener}. - * - * @alias getRetoggleEvents - * @memberof CIQ.ChartEngine - * @static - * @since - * - 7.5.0 - * - 8.0.0 Renamed from `CIQ.UI.Chart#retoggleEvents`. Revised parameter list from `({ stx })`. - * Now returns a function. - */ -CIQ.ChartEngine.getRetoggleEvents = function (config) { - return function retoggleEvents({ stx }) { - var topNode = document.getElementById(config.chartId); - if (!topNode) - topNode = (CIQ.getFn("UI.getMyContext")(stx.container) || {}).topNode; - if (!topNode) topNode = document; - // do not reset the span events since that will also reset their states - const active = topNode.querySelectorAll( - `${config.selector.markersMenuItem}.ciq-active:not(.span-event)` - ); - active.forEach(function (i) { - i.dispatchEvent(new Event("stxtap")); - }); - }; -}; - -}; - - -let __js_standard_drawing_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; -var timezoneJS = - typeof _timezoneJS !== "undefined" ? _timezoneJS : _exports.timezoneJS; - -/** - * READ ONLY. Map of registered drawing tools and their constructors. Populated via lazy eval, so it only contains tools which were used so far. - * @type object - * @default - * @alias drawingTools - * @memberof CIQ.ChartEngine - * @static - */ -CIQ.ChartEngine.drawingTools = {}; - -/** - * Each CIQ.ChartEngine object will clone a copy of this object template and use it to store the settings for the active drawing tool. - * The default settings can be changed by overriding these defaults on your own files. - * See {@tutorial Custom Drawing Toolbar} for details on how to use this template to replace the standard drawing toolbar. - *
This object can be extended to support additional drawing tools (for instance note the extensive customization capabilities for fibonacci) - * @type object - * @memberof CIQ.ChartEngine - * @static - */ -CIQ.ChartEngine.currentVectorParameters = { - /** - * Drawing to activate. - *
See 'Classes' in {@link CIQ.Drawing} for available drawings. - * Use {@link CIQ.ChartEngine#changeVectorType} to activate. - * @type string - * @alias CIQ.ChartEngine.currentVectorParameters[`vectorType`] - * @memberof CIQ.ChartEngine.currentVectorParameters - */ - vectorType: null, - /** - * Line pattern. - *
Valid values for pattern: solid, dotted, dashed, none - *
Not all parameters/values are valid on all drawings. See the specific `reconstruct` method for your desired drawing for more details(Example: {@link CIQ.Drawing.horizontal#reconstruct}) - * @type string - * @default - * @alias CIQ.ChartEngine.currentVectorParameters[`pattern`] - * @memberof CIQ.ChartEngine.currentVectorParameters - */ - pattern: "solid", - /** - * Line width - *
Not all parameters/values are valid on all drawings. See the specific `reconstruct` method for your desired drawing for more details(Example: {@link CIQ.Drawing.horizontal#reconstruct}) - * @type number - * @default - * @alias CIQ.ChartEngine.currentVectorParameters[`lineWidth`] - * @memberof CIQ.ChartEngine.currentVectorParameters - */ - lineWidth: 1, - /** - * Fill color. - *
Not all parameters/values are valid on all drawings. See the specific `reconstruct` method for your desired drawing for more details(Example: {@link CIQ.Drawing.horizontal#reconstruct}) - * @type string - * @default - * @alias CIQ.ChartEngine.currentVectorParameters[`fillColor`] - * @memberof CIQ.ChartEngine.currentVectorParameters - */ - fillColor: "#7DA6F5", - /** - * Line color. - *
Not all parameters/values are valid on all drawings. See the specific `reconstruct` method for your desired drawing for more details(Example: {@link CIQ.Drawing.horizontal#reconstruct}) - * @type string - * @default - * @alias CIQ.ChartEngine.currentVectorParameters[`currentColor`] - * @memberof CIQ.ChartEngine.currentVectorParameters - */ - currentColor: "auto", - /** - * Axis Label. - * Set to 'true' to display a label on the x axis. - *
Not all parameters/values are valid on all drawings. See the specific `reconstruct` method for your desired drawing for more details(Example: {@link CIQ.Drawing.horizontal#reconstruct}) - * @type string - * @default - * @alias CIQ.ChartEngine.currentVectorParameters[`axisLabel`] - * @memberof CIQ.ChartEngine.currentVectorParameters - */ - axisLabel: true, - /** - * Fibonacci settings. - * See {@link CIQ.Drawing.fibonacci#reconstruct} `parameters` object for valid options - * @type object - * @alias CIQ.ChartEngine.currentVectorParameters[`fibonacci`] - * @memberof CIQ.ChartEngine.currentVectorParameters - * @example - * fibonacci:{ - * trend:{color:"auto", parameters:{pattern:"solid", opacity:0.25, lineWidth:1}}, - * fibs:[ - * {level:-0.786, color:"auto", parameters:{pattern:"solid", opacity:0.25, lineWidth:1}}, - * {level:-0.618, color:"auto", parameters:{pattern:"solid", opacity:0.25, lineWidth:1}, display: true}, - * {level:-0.382, color:"auto", parameters:{pattern:"solid", opacity:0.25, lineWidth:1}, display: true}, - * {level:0, color:"auto", parameters:{pattern:"solid", lineWidth:1}, display: true}, - * {level:0.382, color:"auto", parameters:{pattern:"solid", opacity:0.25, lineWidth:1}, display: true}, - * {level:0.618, color:"auto", parameters:{pattern:"solid", opacity:0.25, lineWidth:1}, display: true}, - * {level:0.786, color:"auto", parameters:{pattern:"solid", opacity:0.25, lineWidth:1}}, - * {level:0.5, color:"auto", parameters:{pattern:"solid", opacity:0.25, lineWidth:1}, display: true}, - * {level:1, color:"auto", parameters:{pattern:"solid", lineWidth:1}, display: true}, - * {level:1.382, color:"auto", parameters:{pattern:"solid", opacity:0.25, lineWidth:1}, display: true}, - * {level:1.618, color:"auto", parameters:{pattern:"solid", opacity:0.25, lineWidth:1}, display: true} - * ], - * extendLeft: false, - * printLevels: true, // display the % levels to the right of the drawing - * printValues: false, // display the values on the y axis - * timezone:{color:"auto", parameters:{pattern:"solid", opacity:0.25, lineWidth:1}} - * } - * @since - * - 3.0.9 Added 0.786 and -0.786 levels. - * - 5.2.0 Added 1.272 level. - */ - fibonacci: { - trend: { - color: "auto", - parameters: { pattern: "solid", opacity: 0.25, lineWidth: 1 } - }, - fibs: [ - { - level: -0.786, - color: "auto", - parameters: { pattern: "solid", opacity: 0.25, lineWidth: 1 } - }, - { - level: -0.618, - color: "auto", - parameters: { pattern: "solid", opacity: 0.25, lineWidth: 1 }, - display: true - }, - { - level: -0.5, - color: "auto", - parameters: { pattern: "solid", opacity: 0.25, lineWidth: 1 } - }, - { - level: -0.382, - color: "auto", - parameters: { pattern: "solid", opacity: 0.25, lineWidth: 1 }, - display: true - }, - { - level: -0.236, - color: "auto", - parameters: { pattern: "solid", opacity: 0.25, lineWidth: 1 } - }, - { - level: 0, - color: "auto", - parameters: { pattern: "solid", lineWidth: 1 }, - display: true - }, - { - level: 0.236, - color: "auto", - parameters: { pattern: "solid", opacity: 0.25, lineWidth: 1 } - }, - { - level: 0.382, - color: "auto", - parameters: { pattern: "solid", opacity: 0.25, lineWidth: 1 }, - display: true - }, - { - level: 0.5, - color: "auto", - parameters: { pattern: "solid", opacity: 0.25, lineWidth: 1 }, - display: true - }, - { - level: 0.618, - color: "auto", - parameters: { pattern: "solid", opacity: 0.25, lineWidth: 1 }, - display: true - }, - { - level: 0.786, - color: "auto", - parameters: { pattern: "solid", opacity: 0.25, lineWidth: 1 } - }, - { - level: 1, - color: "auto", - parameters: { pattern: "solid", lineWidth: 1 }, - display: true - }, - { - level: 1.272, - color: "auto", - parameters: { pattern: "solid", opacity: 0.25, lineWidth: 1 } - }, - { - level: 1.382, - color: "auto", - parameters: { pattern: "solid", opacity: 0.25, lineWidth: 1 }, - display: true - }, - { - level: 1.618, - color: "auto", - parameters: { pattern: "solid", opacity: 0.25, lineWidth: 1 }, - display: true - }, - { - level: 2.618, - color: "auto", - parameters: { pattern: "solid", opacity: 0.25, lineWidth: 1 } - }, - { - level: 4.236, - color: "auto", - parameters: { pattern: "solid", opacity: 0.25, lineWidth: 1 } - } - ], - extendLeft: false, - printLevels: true, - printValues: false, - timezone: { - color: "auto", - parameters: { pattern: "solid", opacity: 0.25, lineWidth: 1 } - } - }, - /** - * Annotation settings. - * @type object - * @alias CIQ.ChartEngine.currentVectorParameters[`annotation`] - * @memberof CIQ.ChartEngine.currentVectorParameters - * @example - * annotation:{ - * font:{ - * style:null, - * size:null, // override .stx_annotation default - * weight:null, // override .stx_annotation default - * family:null // override .stx_annotation default - * } - * } - */ - annotation: { - font: { - style: null, - size: null, // override .stx_annotation default - weight: null, // override .stx_annotation default - family: null // override .stx_annotation default - } - } -}; - -/** - * Registers a drawing tool. This is typically done using lazy eval. - * @private - * @param {string} name Name of drawing tool - * @param {function} func Constructor for drawing tool - * @memberof CIQ.ChartEngine - */ -CIQ.ChartEngine.registerDrawingTool = function (name, func) { - CIQ.ChartEngine.drawingTools[name] = func; -}; - -/** - * Given an html element, this allows the chart container to keep track of its own drawing container - * (where appropriate) - * @param {object} htmlElement The html element where the chart container is for 'this' chart - * @memberof CIQ.ChartEngine - * @example - * var stxx=new CIQ.ChartEngine({container:document.querySelector(".chartContainer"), preferences:{labels:false, currentPriceLine:true, whitespace:0}}); - * stxx.setDrawingContainer(document.querySelector('cq-toolbar')); - * @since 6.0.0 - */ -CIQ.ChartEngine.prototype.setDrawingContainer = function (htmlElement) { - this.drawingContainer = htmlElement; -}; - -/** - * Exports (serializes) all of the drawings on the chart(s) so that they can be saved to an external database and later imported with {@link CIQ.ChartEngine#importDrawings}. - * @see {@link CIQ.ChartEngine#importDrawings} - * @return {array} An array of serialized objects representing each drawing - * @memberof CIQ.ChartEngine - * @since 3.0.0 Replaces `serializeDrawings`. - */ -CIQ.ChartEngine.prototype.exportDrawings = function () { - var arr = []; - for (var i = 0; i < this.drawingObjects.length; i++) { - arr.push(this.drawingObjects[i].serialize()); - } - return arr; -}; - -/** - * Causes all drawings to delete themselves. External access should be made through @see CIQ.ChartEngine.prototype.clearDrawings - * @param {boolean} deletePermanent Set to false to not delete permanent drawings - * @private - * @memberof CIQ.ChartEngine - * @since 6.0.0 Added `deletePermanent` parameter. - */ -CIQ.ChartEngine.prototype.abortDrawings = function (deletePermanent) { - if (deletePermanent !== false) deletePermanent = true; - for (var i = this.drawingObjects.length - 1; i >= 0; i--) { - var drawing = this.drawingObjects[i]; - drawing.abort(true); - if (deletePermanent || !drawing.permanent) this.drawingObjects.splice(i, 1); - } -}; - -/** - * Imports drawings from an array originally created by {@link CIQ.ChartEngine#exportDrawings}. - * To immediately render the reconstructed drawings, you must call `draw()`. - * See {@tutorial Using and Customizing Drawing Tools} for more details. - * - * **Important:** - * Calling this function in a way that will cause it to run simultaneously with [importLayout]{@link CIQ.ChartEngine#importLayout} - * will damage the results on the layout load. To prevent this, use the {@link CIQ.ChartEngine#importLayout} or {@link CIQ.ChartEngine#loadChart} callback listeners. - * - * @see {@link CIQ.ChartEngine#exportDrawings} - * @param {array} arr An array of serialized drawings - * @memberof CIQ.ChartEngine - * @since 4.0.0 Replaces `reconstructDrawings`. - * @example - * // programmatically add a rectangle - * stxx.importDrawings([{"name":"rectangle","pnl":"chart","col":"transparent","fc":"#7DA6F5","ptrn":"solid","lw":1.1,"d0":"20151216030000000","d1":"20151216081000000","tzo0":300,"tzo1":300,"v0":152.5508906882591,"v1":143.3385829959514}]); - * // programmatically add a vertical line - * stxx.importDrawings([{"name":"vertical","pnl":"chart","col":"transparent","ptrn":"solid","lw":1.1,"v0":147.45987854251013,"d0":"20151216023000000","tzo0":300,"al":true}]); - * // now render the reconstructed drawings - * stxx.draw(); - */ -CIQ.ChartEngine.prototype.importDrawings = function (arr) { - if (!CIQ.Drawing) return; - for (var i = 0; i < arr.length; i++) { - var rep = arr[i]; - if (rep.name == "fibonacci") rep.name = "retracement"; - var Factory = CIQ.ChartEngine.drawingTools[rep.name]; - if (!Factory) { - if (CIQ.Drawing[rep.name]) { - Factory = CIQ.Drawing[rep.name]; - CIQ.ChartEngine.registerDrawingTool(rep.name, Factory); - } - } - if (Factory) { - var drawing = new Factory(); - drawing.reconstruct(this, rep); - this.drawingObjects.push(drawing); - } - } -}; - -/** - * Clears all the drawings on the chart. (Do not call abortDrawings directly). - * @param {boolean} cantUndo Set to true to make this an "non-undoable" operation - * @param {boolean} deletePermanent Set to false to not delete permanent drawings - * @memberof CIQ.ChartEngine - * @since 6.0.0 Added `deletePermanent` parameter. - */ -CIQ.ChartEngine.prototype.clearDrawings = function (cantUndo, deletePermanent) { - if (deletePermanent !== false) deletePermanent = true; - var before = this.exportDrawings(); - this.abortDrawings(deletePermanent); - if (cantUndo) { - this.undoStamps = []; - } else { - this.undoStamp(before, this.exportDrawings()); - } - this.changeOccurred("vector"); - //this.createDataSet(); - //this.deleteHighlighted(); // this will remove any stickies and also call draw() - // deleteHighlighted was doing too much, so next we call 'just' what we need. - this.cancelTouchSingleClick = true; - CIQ.clearCanvas(this.chart.tempCanvas, this); - this.draw(); - var mSticky = this.controls.mSticky; - if (mSticky) { - mSticky.style.display = "none"; - mSticky.children[0].innerHTML = ""; - } -}; - -/** - * Creates a new drawing of the specified type with the specified parameters. See {@tutorial Using and Customizing Drawing Tools} for more details. - * @param {string} type Drawing name - * @param {object} parameters Parameters that describe the drawing - * @return {CIQ.Drawing} A drawing object - * @memberof CIQ.ChartEngine - */ -CIQ.ChartEngine.prototype.createDrawing = function (type, parameters) { - if (!CIQ.Drawing) return; - var drawing = new CIQ.Drawing[type](); - drawing.reconstruct(this, parameters); - //set default configs if not provided - var config = new CIQ.Drawing[type](); - config.stx = this; - config.copyConfig(); - for (var prop in config) { - drawing[prop] = drawing[prop] || config[prop]; - } - this.drawingObjects.push(drawing); - this.draw(); - return drawing; -}; - -/** - * Removes the drawing. Drawing object should be one returned from {@link CIQ.ChartEngine#createDrawing}. See {@tutorial Using and Customizing Drawing Tools} for more details. - * @param {object} drawing Drawing object - * @memberof CIQ.ChartEngine - */ -CIQ.ChartEngine.prototype.removeDrawing = function (drawing) { - for (var i = 0; i < this.drawingObjects.length; i++) { - if (this.drawingObjects[i] == drawing) { - this.drawingObjects.splice(i, 1); - this.changeOccurred("vector"); - this.draw(); - return; - } - } - - //this.checkForEmptyPanel(drawing.panelName); -}; - -/** - * INJECTABLE - * - * Stops (aborts) the current drawing. See {@link CIQ.ChartEngine#undoLast} for an actual "undo" operation. - * @memberof CIQ.ChartEngine.AdvancedInjectable# - * @alias undo - */ -CIQ.ChartEngine.prototype.undo = function () { - if (this.runPrepend("undo", arguments)) return; - if (this.activeDrawing) { - this.activeDrawing.abort(); - this.activeDrawing.hidden = false; - this.drawingSnapshot = null; - this.activateDrawing(null); - CIQ.clearCanvas(this.chart.tempCanvas, this); - this.draw(); - this.controls.crossX.classList.replace( - "stx_crosshair_drawing", - "stx_crosshair" - ); - this.controls.crossY.classList.replace( - "stx_crosshair_drawing", - "stx_crosshair" - ); - CIQ.ChartEngine.drawingLine = false; - } - this.runAppend("undo", arguments); -}; - -/** - * Creates an undo stamp for the chart's current drawing state and triggers a call to the [undoStampEventListener]{@link CIQ.ChartEngine~undoStampEventListener}. - * - * Every time a drawing is added or removed the {@link CIQ.ChartEngine#undoStamps} object is updated with a new entry containing the resulting set of drawings. - * Using the corresponding {@link CIQ.ChartEngine#undoLast} method, you can revert back to the last state, one at a time. - * You can also use the [undoStampEventListener]{@link CIQ.ChartEngine~undoStampEventListener} to create your own tracker to undo or redo drawings. - * @memberof CIQ.ChartEngine - * @param {array} before The chart's array of [serialized drawingObjects]{@link CIQ.ChartEngine#exportDrawings} before being modified. - * @param {array} after The chart's array of [serialized drawingObjects]{@link CIQ.ChartEngine#exportDrawings} after being modified - * @since 7.0.0 'before' and 'after' parameters must now be an array of serialized drawings instead of an array of drawingObjects. See {@link CIQ.ChartEngine#exportDrawings}. - */ -CIQ.ChartEngine.prototype.undoStamp = function (before, after) { - this.undoStamps.push(before); - this.dispatch("undoStamp", { - before: before, - after: after, - stx: this - }); -}; - -/** - * Reverts back to the previous drawing state change. - * **Note: by design this method only manages drawings manually added during the current session and will not remove drawings restored from - * a previous session.** If you wish to remove all drawings use {@link CIQ.ChartEngine#clearDrawings}. - * - * You can also view and interact with all drawings by traversing through the {@link CIQ.ChartEngine#drawingObjects} array which includes **all** drawings displayed - * on the chart, regardless of session. Removing a drawing from this list, will remove the drawing from the chart after a draw() operation is executed. - * @memberof CIQ.ChartEngine - */ -CIQ.ChartEngine.prototype.undoLast = function () { - if (this.activeDrawing) { - this.undo(); - } else { - if (this.undoStamps.length) { - this.drawingObjects = []; // drawingObjects will be repopulated by importDrawings - this.importDrawings(this.undoStamps.pop()); - this.changeOccurred("vector"); - this.draw(); - } - } -}; - -/** - * Programmatically add a drawing - * @param {object} drawing The drawing definition - * @memberof CIQ.ChartEngine - * @private - */ -CIQ.ChartEngine.prototype.addDrawing = function (drawing) { - var drawings = this.exportDrawings(); - this.drawingObjects.push(drawing); - this.undoStamp(drawings, this.exportDrawings()); -}; - -/** - * Repositions a drawing onto the temporary canvas. Called when a user moves a drawing. - * @param {CIQ.Drawing} drawing The drawing to reposition - * @param {boolean} activating True when first activating "reposition", so the drawing simply gets re-rendered in the same spot but on the tempCanvas. - * (Otherwise it would jump immediately to the location of the next click/touch). - * @since - * - 3.0.0 - * - 5.0.0 Added `activating` parameter. - * @private - */ -CIQ.ChartEngine.prototype.repositionDrawing = function (drawing, activating) { - var panel = this.panels[drawing.panelName]; - var value = this.adjustIfNecessary( - panel, - this.crosshairTick, - this.valueFromPixel(this.backOutY(CIQ.ChartEngine.crosshairY), panel) - ); - var tempCanvas = this.chart.tempCanvas; - CIQ.clearCanvas(tempCanvas, this); - if (activating) { - this.drawingSnapshot = this.exportDrawings(); - drawing.render(tempCanvas.context); - } else { - drawing.reposition( - tempCanvas.context, - drawing.repositioner, - this.crosshairTick, - value - ); - if (this.drawingSnapshot) - this.undoStamp( - CIQ.shallowClone(this.drawingSnapshot), - this.exportDrawings() - ); - this.drawingSnapshot = null; - } - if (drawing.measure) drawing.measure(); -}; - -/** - * Activates or deactivates repositioning on a drawings. - * @param {CIQ.Drawing} drawing The drawing to activate. null to deactivate the current drawing. - * @memberOf CIQ.ChartEngine - * @since 3.0.0 - */ -CIQ.ChartEngine.prototype.activateRepositioning = function (drawing) { - var repositioningDrawing = (this.repositioningDrawing = drawing); - if (drawing) { - // Take the drawing off the main canvas and put it on the tempCanvas - this.draw(); - this.repositionDrawing(drawing, true); - } - this.chart.tempCanvas.style.display = drawing ? "block" : "none"; -}; - -/** - * Activate a drawing. The user can then finish the drawing. - * - * Note: Some drawings labeled "chartsOnly" can only be activated on the chart panel. - * @param {string} drawingTool The tool to activate. Send null to deactivate. - * @param {CIQ.ChartEngine.Panel} [panel] The panel where to activate the tool. Defaults to the current panel. - * @return {boolean} Returns true if the drawing was successfully activated. Returns false if unactivated or unsuccessful. - * @memberof CIQ.ChartEngine - * @since - * - 3.0.0 - * - 7.0.0 `panel` defaults to the current panel. - */ -CIQ.ChartEngine.prototype.activateDrawing = function (drawingTool, panel) { - if (!panel) panel = this.currentPanel; - function removeStudyOverlay(stx) { - if (!stx.layout.studies) return; - var study = stx.layout.studies[panel.name]; - if (study && !study.overlay) delete stx.overlays[study.name]; - } - if (!drawingTool) { - this.activeDrawing = null; - this.chart.tempCanvas.style.display = "none"; - removeStudyOverlay(this); - return false; - } - var Factory = CIQ.ChartEngine.drawingTools[drawingTool]; - if (!Factory) { - if (CIQ.Drawing[drawingTool]) { - Factory = CIQ.Drawing[drawingTool]; - CIQ.ChartEngine.registerDrawingTool(drawingTool, Factory); - } - } - if (Factory) { - this.activeDrawing = new Factory(); - this.activeDrawing.construct(this, panel); - if (!this.charts[panel.name]) { - if (this.activeDrawing.chartsOnly) { - this.activeDrawing = null; - removeStudyOverlay(this); - return false; - } - } - } - this.chart.tempCanvas.style.display = "block"; - if (this.controls.drawOk) this.controls.drawOk.style.display = "none"; - removeStudyOverlay(this); - return true; -}; - -/** - * This is called to send a potential click event to an active drawing, if one is active. - * @param {CIQ.ChartEngine.Panel} panel The panel in which the click occurred - * @param {number} x The X pixel location of the click - * @param {number} y The y pixel location of the click - * @return {boolean} Returns true if a drawing is active and received the click - * @memberof CIQ.ChartEngine - */ -CIQ.ChartEngine.prototype.drawingClick = function (panel, x, y) { - if (!CIQ.Drawing) return; - if (!panel) return; // can be true if panel was closed in the middle of a drawing - if (this.openDialog !== "") return; // don't register a drawing click if in modal mode - if (!this.activeDrawing) { - if (!this.activateDrawing(this.currentVectorParameters.vectorType, panel)) - return; - } - if (this.activeDrawing) { - if (this.userPointerDown && !this.activeDrawing.dragToDraw) { - if (!CIQ.ChartEngine.drawingLine) this.activateDrawing(null); - return; - } - - var tick = this.tickFromPixel(x, panel.chart); - var dpanel = this.panels[this.activeDrawing.panelName]; - var value = this.adjustIfNecessary( - dpanel, - tick, - this.valueFromPixel(y, dpanel) - ); - if (this.magnetizedPrice) { - value = this.adjustIfNecessary(dpanel, tick, this.magnetizedPrice); - } - if (this.activeDrawing.click(this.chart.tempCanvas.context, tick, value)) { - if (this.activeDrawing) { - // Just in case the drawing aborted itself, such as measure - CIQ.ChartEngine.drawingLine = false; - CIQ.clearCanvas(this.chart.tempCanvas, this); - this.addDrawing(this.activeDrawing); // Save drawing - this.activateDrawing(null); - this.adjustDrawings(); - this.draw(); - this.changeOccurred("vector"); - this.controls.crossX.classList.replace( - "stx_crosshair_drawing", - "stx_crosshair" - ); - this.controls.crossY.classList.replace( - "stx_crosshair_drawing", - "stx_crosshair" - ); - } - } else { - this.changeOccurred("drawing"); - CIQ.ChartEngine.drawingLine = true; - this.controls.crossX.classList.replace( - "stx_crosshair", - "stx_crosshair_drawing" - ); - this.controls.crossY.classList.replace( - "stx_crosshair", - "stx_crosshair_drawing" - ); - } - return true; - } - return false; -}; - -/** - * Dispatches a [drawingEditEventListener]{@link CIQ.ChartEngine~drawingEditEventListener} event - * if there are any listeners. Otherwise, removes the given drawing. - * - * @param {CIQ.Drawing} drawing The vector instance to edit, normally provided by deleteHighlighted. - * @param {boolean} forceEdit skip the context menu and begin editing. Used on touch devices. - * @memberof CIQ.ChartEngine.AdvancedInjectable# - * @alias rightClickDrawing - * @since 6.2.0 - */ -CIQ.ChartEngine.prototype.rightClickDrawing = function (drawing, forceEdit) { - if (this.runPrepend("rightClickDrawing", arguments)) return; - if (drawing.permanent) return; - - if (this.callbackListeners.drawingEdit.length) { - this.dispatch("drawingEdit", { - stx: this, - drawing: drawing, - forceEdit: forceEdit - }); - } else { - var dontDeleteMe = drawing.abort(); - - if (!dontDeleteMe) { - var before = this.exportDrawings(); - this.removeDrawing(drawing); - this.undoStamp(before, this.exportDrawings()); - } - - this.changeOccurred("vector"); - } - - this.runAppend("rightClickDrawing", arguments); -}; - -/** - * INJECTABLE - * - * Calculates the magnet point for the current mouse cursor location. This is the nearest OHLC point. A small white - * circle is drawn on the temporary canvas to indicate this location for the end user. If the user initiates a drawing then - * the end point of the drawing will be tied to the magnet point. - * This function is only used when creating a new drawing if CIQ.ChartEngine.preferences.magnet is true and - * a drawing CIQ.ChartEngine.currentVectorParameters.vectorType has been enabled. It will not be used when an existing drawing is being repositioned. - * @memberof CIQ.ChartEngine.AdvancedInjectable# - * @alias magnetize - */ -CIQ.ChartEngine.prototype.magnetize = function () { - this.magnetizedPrice = null; - if (!this.preferences.magnet) return; - if (this.runPrepend("magnetize", arguments)) return; - if (this.repositioningDrawing) return; // Don't magnetize - var drawingTool = this.currentVectorParameters.vectorType; - if (!drawingTool || drawingTool == "projection" || drawingTool == "freeform") - return; - if ( - (drawingTool == "annotation" || drawingTool == "callout") && - CIQ.ChartEngine.drawingLine - ) - return; // Don't magnetize the end of an annotation - var panel = this.currentPanel; - var chart = panel.chart; - var tick = this.crosshairTick; - //if(this.layout.interval!="minute") tick/=this.layout.periodicity; - if (tick > chart.dataSet.length) return; // Don't magnetize in the future - var prices = chart.dataSet[tick]; - if (!prices) return; - var doTransform = chart.transformFunc && panel.yAxis === chart.yAxis; - if (doTransform && prices.transform) prices = prices.transform; - var stickMagnet; - - var fields = this.getRenderedItems(); - var ohlc = ["Open", "High", "Low", "Close"]; - if (this.magneticHold && this.activeDrawing && this.activeDrawing.penDown) { - if (ohlc.indexOf(this.magneticHold) != -1 && fields.indexOf("High") != -1) - fields = ohlc; - else fields = [this.magneticHold]; - } else this.magneticHold = null; //reset for next time! - var closest = 1000000000; - var magnetRadius = parseFloat(this.preferences.magnet); // if it is actually a number we use that otherwise magnetRadius is falsey and no harm - for (var i = 0; i < fields.length; i++) { - var fieldPrice = prices[fields[i]]; - var yAxis = this.getYAxisByField(panel, fields[i]); - - var tuple = CIQ.existsInObjectChain(prices, fields[i]); - if (tuple) fieldPrice = tuple.obj[tuple.member]; - - if (fieldPrice || fieldPrice === 0) { - var pixelPosition = this.pixelFromTransformedValue( - fieldPrice, - panel, - yAxis - ); // pixel position of Price! - if (Math.abs(this.cy - pixelPosition) < closest) { - closest = Math.abs(this.cy - pixelPosition); - if (magnetRadius && magnetRadius <= closest) continue; - this.magnetizedPrice = doTransform - ? this.valueFromPixel(pixelPosition, panel) - : fieldPrice; - stickMagnet = pixelPosition; - this.magneticHold = fields[i]; - } - } - } - var x = this.pixelFromTick(tick, chart); - var y = stickMagnet; - CIQ.clearCanvas(chart.tempCanvas, this); - var ctx = chart.tempCanvas.context; - ctx.beginPath(); - ctx.lineWidth = 1; - var radius = Math.max(this.layout.candleWidth, 12) / 3; - // Limit the radius size to 8 to prevent a large arc - // when zooming in and increasing the candle width. - ctx.arc(x, y, Math.min(radius, 8), 0, 2 * Math.PI, false); - // ctx.lineWidth=2; - ctx.fillStyle = "#398dff"; - ctx.strokeStyle = "#398dff"; - ctx.fill(); - ctx.stroke(); - ctx.closePath(); - chart.tempCanvas.style.display = "block"; - if (this.anyHighlighted) this.container.classList.remove("stx-draggable"); - if (this.activeDrawing) - this.activeDrawing.move(ctx, this.crosshairTick, this.magnetizedPrice); - this.runAppend("magnetize", arguments); -}; - -/** - * Sets the current drawing tool as described by {@link CIQ.ChartEngine.currentVectorParameters} (segment, line, etc) - * @param {string} value The name of the drawing tool to enable - * @memberof CIQ.ChartEngine - * @example - * // activates a drawing type described by currentVectorParameters - * stxx.changeVectorType('rectangle'); - * // deactivates drawing mode - * stxx.changeVectorType(''); - * // clears the drawings - * stxx.clearDrawings() - */ -CIQ.ChartEngine.prototype.changeVectorType = function (value) { - this.currentVectorParameters.vectorType = value; - if (CIQ.Drawing) CIQ.Drawing.initializeSettings(this, value); - //if(value==""){ //need to always undo here to allow release of last drawing tool - if (CIQ.ChartEngine.drawingLine) this.undo(); - //} - // this.setCrosshairColors(); - if (this.insideChart) { - this.doDisplayCrosshairs(); - } -}; - -/** - * Sets the current drawing parameter as described by {@link CIQ.ChartEngine.currentVectorParameters} (color, pattern, etc) - * @param {string} parameter The name of the drawing parameter to change (currentColor, fillColor, lineWidth, pattern, axisLabel, fontSize, fontStyle, fontWeight, fontFamily) - * @param {string} value The value of the parameter - * @return {boolean} True if property was assigned - * @memberof CIQ.ChartEngine - * @example - * this.stx.changeVectorParameter("currentColor","yellow"); // or rgb/hex - * this.stx.changeVectorParameter("axisLabel",false); // or "false" - * this.stx.changeVectorParameter("lineWidth",5); // or "5" - * this.stx.changeVectorParameter("fontSize","12"); // or 12 or "12px" - * this.stx.changeVectorParameter("pattern","dotted"); - * - * @since 3.0.0 - */ -CIQ.ChartEngine.prototype.changeVectorParameter = function (parameter, value) { - if (parameter == "axisLabel") - value = value.toString() === "true" || Number(value); - else if (parameter == "lineWidth") value = Number(value); - else if (parameter == "fontSize") value = parseInt(value, 10) + "px"; - var currentVectorParams = this.currentVectorParameters; - if (typeof currentVectorParams[parameter] !== "undefined") { - currentVectorParams[parameter] = value; - return true; - } else if (parameter.substr(0, 4) == "font") { - parameter = parameter.substr(4).toLowerCase(); - if (parameter == "family" && value.toLowerCase() == "default") value = null; - currentVectorParams = currentVectorParams.annotation.font; - if (typeof currentVectorParams[parameter] !== "undefined") { - currentVectorParams[parameter] = value; - return true; - } - } - return false; -}; - -/** - * INJECTABLE - * Animation Loop - * - * Draws the drawings (vectors). Each drawing is iterated and asked to draw itself. Drawings are automatically - * clipped by their containing panel. - * @memberof CIQ.ChartEngine.AdvancedInjectable# - * @alias drawVectors - */ -CIQ.ChartEngine.prototype.drawVectors = function () { - if (this.vectorsShowing) return; - if (this.runPrepend("drawVectors", arguments)) return; - this.vectorsShowing = true; - if (!this.chart.hideDrawings && !this.highlightedDraggable) { - var tmpPanels = {}; - // First find all the existing panels in the given set of drawings (excluding those that aren't displayed) - var panelName, i; - for (i = 0; i < this.drawingObjects.length; i++) { - var drawing = this.drawingObjects[i]; - if (drawing.hidden) continue; // do not draw this on the main canvas; it's being edited on the tempCanvas - if (this.repositioningDrawing === drawing) continue; // don't display a drawing that is currently being repositioned because it will show on the tempCanvas - panelName = drawing.panelName; - if ( - !this.panels[drawing.panelName] || - this.panels[drawing.panelName].hidden - ) - continue; // drawing from a panel that is not enabled - if (!tmpPanels[panelName]) { - tmpPanels[panelName] = []; - } - tmpPanels[panelName].push(drawing); - } - // Now render all the drawings in those panels, clipping each panel - for (panelName in tmpPanels) { - this.startClip(panelName); - var arr = tmpPanels[panelName]; - for (i = 0; i < arr.length; i++) { - arr[i].render(this.chart.context); - } - this.endClip(); - } - } - this.runAppend("drawVectors", arguments); -}; - -/** - * Loops through the existing drawings and asks them to adjust themselves to the chart dimensions. - * @memberof CIQ.ChartEngine - */ -CIQ.ChartEngine.prototype.adjustDrawings = function () { - for (var i = 0; i < this.drawingObjects.length; i++) { - var drawing = this.drawingObjects[i]; - if (this.panels[drawing.panelName]) drawing.adjust(); - } -}; - -/** - * Base class for Drawing Tools. Use {@link CIQ.inheritsFrom} to build a subclass for custom drawing tools. - * The name of the subclass should be CIQ.Drawing.yourname. Whenever CIQ.ChartEngine.currentVectorParameters.vectorType==yourname, then - * your drawing tool will be the one that is enabled when the user begins a drawing. Capitalization of yourname - * must be an exact match otherwise the kernel will not be able to find your drawing tool. - * - * Each of the CIQ.Drawing prototype functions may be overridden. To create a functioning drawing tool - * you must override the functions below that create alerts. - * - * Drawing clicks are always delivered in *adjusted price*. That is, if a stock has experienced splits then - * the drawing will not display correctly on an unadjusted price chart unless this is considered during the rendering - * process. Follow the templates to assure correct rendering under both circumstances. - * - * If no color is specified when building a drawing then color will be set to "auto" and the chart will automatically display - * white or black depending on the background. - * - * **Permanent drawings:**
- * To make a particular drawing permanent, set its `permanent` property to `true` once created. - *
Example:
- * ```drawingObject.permanent=true;``` - * - * See {@tutorial Using and Customizing Drawing Tools} for more details. - * - * @name CIQ.Drawing - * @constructor - */ -CIQ.Drawing = - CIQ.Drawing || - function () { - this.chartsOnly = false; // Set this to true to restrict drawing to panels containing charts (as opposed to studies) - this.penDown = false; // Set to true when in the midst of creating the object - }; - -/** - * Since not all drawings have the same configuration parameters, - * this is a helper function intended to return the relevant drawing parameters and default settings for the requested drawing type. - * - * For example, you can use the returning object as your template for creating the proper UI tool box for that particular drawing. - * Will you need a line width UI element, a fill color?, etc. Or you can use it to determine what values you should be setting if enabling - * a particular drawing type programmatically with specific properties. - * @param {CIQ.ChartEngine} stx Chart object - * @param {string} drawingName Name of drawing, e.g. "ray", "segment" - * @returns {object} Map of parameters used in the drawing type, with their current values - * @memberOf CIQ.Drawing - * @since 3.0.0 - */ -CIQ.Drawing.getDrawingParameters = function (stx, drawingName) { - var drawing; - try { - drawing = new CIQ.Drawing[drawingName](); - } catch (e) {} - if (!drawing) return null; - drawing.stx = stx; - drawing.copyConfig(true); - var result = {}; - var confs = drawing.configs; - for (var c = 0; c < confs.length; c++) { - result[confs[c]] = drawing[confs[c]]; - } - var style = stx.canvasStyle("stx_annotation"); - if (style && result.font) { - result.font.size = style.fontSize; - result.font.family = style.fontFamily; - result.font.style = style.fontStyle; - result.font.weight = style.fontWeight; - } - return result; -}; - -/** - * Static method for saving drawing parameters to preferences. - * - * Values are stored in `stxx.preferences.drawings` and can be saved together with the rest of the chart preferences, - * which by default are placed in the browser's local storage under "myChartPreferences". - * @param {CIQ.ChartEngine} stx Chart object - * @param {string} toolName Name of drawing tool, e.g. "ray", "segment", "fibonacci" - * @memberOf CIQ.Drawing - * @since 6.0.0 - */ -CIQ.Drawing.saveConfig = function (stx, toolName) { - if (!toolName) return; - var preferences = stx.preferences; - if (!preferences.drawings) preferences.drawings = {}; - preferences.drawings[toolName] = {}; - var tempDrawing = new CIQ.Drawing[toolName](); - tempDrawing.stx = stx; - CIQ.Drawing.copyConfig(tempDrawing); - tempDrawing.configs.forEach(function (config) { - preferences.drawings[toolName][config] = tempDrawing[config]; - }); - stx.changeOccurred("preferences"); -}; - -/** - * Static method for restoring default drawing parameters, and removing custom preferences. - * - * @param {CIQ.ChartEngine} stx Chart object - * @param {string} toolName Name of active drawing tool, e.g. "ray", "segment", "fibonacci" - * @param {boolean} all True to restore default for all drawing objects. Otherwise only the active drawing object's defaults are restored. - * @memberOf CIQ.Drawing - * @since 6.0.0 - */ -CIQ.Drawing.restoreDefaultConfig = function (stx, toolName, all) { - if (all) stx.preferences.drawings = null; - else stx.preferences.drawings[toolName] = null; - stx.changeOccurred("preferences"); - stx.currentVectorParameters = CIQ.clone( - CIQ.ChartEngine.currentVectorParameters - ); - stx.currentVectorParameters.vectorType = toolName; -}; - -/** - * Static method to call optional initializeSettings instance method of the drawing whose name is passed in as an argument. - * @param {CIQ.ChartEngine} stx Chart object - * @param {string} drawingName Name of drawing, e.g. "ray", "segment", "fibonacci" - * @memberOf CIQ.Drawing - * @since 5.2.0 Calls optional instance function instead of doing all the work internally. - */ -CIQ.Drawing.initializeSettings = function (stx, drawingName) { - var drawing = CIQ.Drawing[drawingName]; - if (drawing) { - var drawInstance = new drawing(); - if (drawInstance.initializeSettings) drawInstance.initializeSettings(stx); - } -}; - -/** - * Updates the drawing's field or panelName property to the passed in argument if the field of the drawing is "sourced" from the passed in name. - * - * This is used when moving a series or study, and there is a drawing based upon it.
- * It will be called based on the following occurrences: - * - Panel of series changed - * - Panel of study changed - * - Default panel of study changed due to field change - * - Outputs of study changed due to field change - * - Outputs of study changed due to name change (due to field of field change) - * @param {CIQ.ChartEngine} stx Chart object - * @param {string} name Name of study or symbol of series to match with - * @param {string} newName Name of new field to use for the drawing field if a name match is found - * @param {string} newPanel Name of new panel to use for the drawing if a name match is found, ignored if `newName`` is set - * @memberOf CIQ.Drawing - * @since 7.0.0 - */ -CIQ.Drawing.updateSource = function (stx, name, newName, newPanel) { - if (!name) return; - var vectorChange = false; - for (var dKey in stx.drawingObjects) { - var drawing = stx.drawingObjects[dKey]; - if (!drawing.field) continue; - if (newName) { - // field change - if (drawing.field == name) { - drawing.field = newName; - vectorChange = true; - } else if ( - drawing.field.indexOf(name) > -1 && - drawing.field.indexOf(name + "-") == -1 - ) { - drawing.field = drawing.field.replace(name, newName); - vectorChange = true; - } - } else { - // panel change - if (drawing.field.split("-->")[0] == name || drawing.panelName == name) { - drawing.panelName = newPanel; - vectorChange = true; - } - } - } - if (vectorChange) stx.changeOccurred("vector"); -}; - -/** - * Instance function used to copy the relevant drawing parameters into itself. - * It just calls the static function. - * @param {boolean} withPreferences set to true to return previously saved preferences - * @memberOf CIQ.Drawing - * @since 3.0.0 - */ -CIQ.Drawing.prototype.copyConfig = function (withPreferences) { - CIQ.Drawing.copyConfig(this, withPreferences); -}; -/** - * Static function used to copy the relevant drawing parameters into the drawing instance. - * Use this when overriding the Instance function, to perform basic copy before performing custom operations. - * @param {CIQ.Drawing} drawingInstance to copy into - * @param {boolean} withPreferences set to true to return previously saved preferences - * @memberOf CIQ.Drawing - * @since - * - 3.0.0 - * - 6.0.0 Overwrites parameters with those stored in `preferences.drawings`. - */ -CIQ.Drawing.copyConfig = function (drawingInstance, withPreferences) { - var cvp = drawingInstance.stx.currentVectorParameters; - var configs = drawingInstance.configs; - var c, conf; - for (c = 0; c < configs.length; c++) { - conf = configs[c]; - if (conf == "color") { - drawingInstance.color = cvp.currentColor; - } else if (conf == "parameters") { - drawingInstance.parameters = CIQ.clone(cvp.fibonacci); - } else if (conf == "font") { - drawingInstance.font = CIQ.clone(cvp.annotation.font); - } else { - drawingInstance[conf] = cvp[conf]; - } - } - if (!withPreferences) return; - var customPrefs = drawingInstance.stx.preferences; - if (customPrefs && customPrefs.drawings) { - CIQ.extend(drawingInstance, customPrefs.drawings[cvp.vectorType]); - for (c = 0; c < configs.length; c++) { - conf = configs[c]; - if (conf == "color") { - cvp.currentColor = drawingInstance.color; - } else if (conf == "parameters") { - cvp.fibonacci = CIQ.clone(drawingInstance.parameters); - } else if (conf == "font") { - cvp.annotation.font = CIQ.clone(drawingInstance.font); - } else { - cvp[conf] = drawingInstance[conf]; - } - } - } -}; - -/** - * Used to set the user behavior for creating drawings. - * - * By default, a drawing is created with this sequence: - *
`move crosshair to staring point` → `click` → `move crosshair to ending point` → `click`. - * > On a touch device this would be: - * >
`move crosshair to staring point` → `tap` → `move crosshair to ending point` → `tap`. - * - * Set dragToDraw to `true` to create the drawing with the following alternate sequence: - *
`move crosshair to staring point` → `mousedown` → `drag` → `mouseup` - * > On a touch device this would be: - * >
`move crosshair to staring point` → `press` → `drag` → `release`. - * - * This parameter is **not compatible** with drawings requiring more than one drag movement to complete, such as: - * - Channel - * - Continues Line - * - Elliott Wave - * - Gartley - * - Pitchfork - * - Fibonacci Projection - * - * Line and Ray have their own separate parameter, which also needs to be set in the same way, if this option is desired: `CIQ.Drawing.line.prototype.dragToDraw=true;` - * - * This parameter may be set for all drawings compatible with it, for a specific drawing type, or for a specific drawing instance. See examples. - * @memberOf CIQ.Drawing - * @example - * // set drawing instance to dragToDraw. Only this one drawing will be affected - * drawing.dragToDraw=true; - * // Set particular drawing prototype to dragToDraw. All drawings to type "difference" will be affected - * CIQ.Drawing["difference"].prototype.dragToDraw=true; - * // Set all drawings to dragToDraw - * CIQ.Drawing.prototype.dragToDraw=true; - */ -CIQ.Drawing.prototype.dragToDraw = false; - -/** - * Set this to true to disable selection, repositioning and deletion by the end user. - * - * This parameter may be set for all drawings, for a specific drawing type, or for a specific drawing instance. See examples. - * @memberOf CIQ.Drawing - * @example - * // set drawing instance to permanent. Only this one drawing will be affected - * drawing.permanent=true; - * // Set particular drawing prototype to permanent. All drawings to type "difference" will be affected - * CIQ.Drawing["difference"].prototype.permanent=true; - * // Set all drawings to permanent - * CIQ.Drawing.prototype.permanent=true; - */ -CIQ.Drawing.prototype.permanent = false; - -/** - * Set this to true to restrict drawing from being rendered on a study panel. - * - * This parameter may be set for all drawings, for a specific drawing type, or for a specific drawing instance. See examples. - * @memberOf CIQ.Drawing - * @example - * // set drawing instance to chartsOnly. Only this one drawing will be affected - * drawing.chartsOnly=true; - * // Set particular drawing prototype to chartsOnly. All drawings to type "difference" will be affected - * CIQ.Drawing["difference"].prototype.chartsOnly=true; - * // Set all drawings to chartsOnly - * CIQ.Drawing.prototype.chartsOnly=true; - */ -CIQ.Drawing.prototype.chartsOnly = false; - -/** - * Is called to tell a drawing to abort itself. It should clean up any rendered objects such as DOM elements or toggle states. It - * does not need to clean up anything that it drew on the canvas. - * @param {boolean} forceClear Indicates that the user explicitly has deleted the drawing (advanced usage) - * @memberOf CIQ.Drawing - */ -CIQ.Drawing.prototype.abort = function (forceClear) {}; - -/** - * Should call this.stx.setMeasure() with the measurements of the drawing if supported - * @memberOf CIQ.Drawing - */ -CIQ.Drawing.prototype.measure = function () {}; - -/** - * Initializes the drawing - * @param {CIQ.ChartEngine} stx The chart object - * @param {CIQ.ChartEngine.Panel} panel The panel reference - * @memberOf CIQ.Drawing - */ -CIQ.Drawing.prototype.construct = function (stx, panel) { - this.stx = stx; - this.panelName = panel.name; -}; - -/** - * Called to render the drawing - * @param {CanvasRenderingContext2D} context Canvas context on which to render. - * @memberOf CIQ.Drawing - */ -CIQ.Drawing.prototype.render = function (context) { - console.warn("must implement render function!"); -}; - -/** - * Called when a user clicks while drawing. - * - * @param {object} context The canvas context. - * @param {number} tick The tick in the `dataSet`. - * @param {number} value The value (price) of the click. - * @return {boolean} True if the drawing is complete. Otherwise the kernel continues accepting - * clicks. - * - * @memberof CIQ.Drawing - */ -CIQ.Drawing.prototype.click = function (context, tick, value) { - console.warn("must implement click function!"); -}; - -/** - * Called when the user moves while creating a drawing. - * @param {CanvasRenderingContext2D} context Canvas context on which to render. - * @param {number} tick Tick in the `dataSet`. - * @param {number} value Value at position. - * @memberOf CIQ.Drawing - */ -CIQ.Drawing.prototype.move = function (context, tick, value) { - console.warn("must implement move function!"); -}; - -/** - * Called when the user attempts to reposition a drawing. The repositioner is the object provided - * by {@link CIQ.Drawing.intersected} and can be used to determine which aspect of the drawing is - * being repositioned. For instance, this object may indicate which point on the drawing was - * selected by the user. It might also contain the original coordinates of the point or anything - * else that is useful to render the drawing. - * - * @param {object} context The canvas context. - * @param {object} repositioner The repositioner object. - * @param {number} tick Current tick in the `dataSet` for the mouse cursor. - * @param {number} value Current value in the `dataSet` for the mouse cursor. - * - * @memberof CIQ.Drawing - */ -CIQ.Drawing.prototype.reposition = function ( - context, - repositioner, - tick, - value -) {}; -/** - * Called to determine whether the drawing is intersected by either the tick/value (pointer - * location) or box (small box surrounding the pointer). For line-based drawings, the box should - * be checked. For area drawings (rectangles, circles) the point should be checked. - * - * @param {number} tick The tick in the `dataSet` representing the cursor point. - * @param {number} value The value (price) representing the cursor point. - * @param {object} box x0, y0, x1, y1, r representing an area around the cursor, including radius. - * @return {object} An object that contains information about the intersection. This object is - * passed back to {@link CIQ.Drawing.reposition} when repositioning the drawing. Return - * false or null if not intersected. Simply returning true highlights the drawing. - * - * @memberof CIQ.Drawing - */ -CIQ.Drawing.prototype.intersected = function (tick, value, box) { - console.warn("must implement intersected function!"); -}; - -/** - * Reconstruct this drawing type from a serialization object - * @param {CIQ.ChartEngine} stx Instance of the chart engine - * @param {object} obj Serialized data about the drawing from which it can be reconstructed. - * @memberOf CIQ.Drawing - */ -CIQ.Drawing.prototype.reconstruct = function (stx, obj) { - console.warn("must implement reconstruct function!"); -}; - -/** - * Serialize a drawing into an object. - * @memberOf CIQ.Drawing - */ -CIQ.Drawing.prototype.serialize = function () { - console.warn("must implement serialize function!"); -}; - -/** - * Called whenever periodicity changes so that drawings can adjust their rendering. - * @memberOf CIQ.Drawing - */ -CIQ.Drawing.prototype.adjust = function () { - console.warn("must implement adjust function!"); -}; - -/** - * Returns the highlighted state. Set this.highlighted to the highlight state. - * For simple drawings the highlighted state is just true or false. For complex drawings - * with pivot points for instance, the highlighted state may have more than two states. - * Whenever the highlighted state changes a draw() event will be triggered. - * @param {Boolean} highlighted True to highlight the drawing, false to unhighlight - * @memberOf CIQ.Drawing.BaseTwoPoint - */ -CIQ.Drawing.prototype.highlight = function (highlighted) { - if (highlighted && !this.highlighted) { - this.highlighted = highlighted; - } else if (!highlighted && this.highlighted) { - this.highlighted = highlighted; - } - return this.highlighted; -}; - -CIQ.Drawing.prototype.littleCircleRadius = function () { - var radius = 6; //Math.max(12, this.layout.candleWidth)/2; - return radius; -}; - -CIQ.Drawing.prototype.littleCircle = function (ctx, x, y, fill) { - if (this.permanent) return; - var strokeColor = this.stx.defaultColor; - var fillColor = CIQ.chooseForegroundColor(strokeColor); - ctx.beginPath(); - ctx.lineWidth = 1; - ctx.arc(x, y, this.littleCircleRadius(), 0, 2 * Math.PI, false); - if (fill) ctx.fillStyle = strokeColor; - else ctx.fillStyle = fillColor; - ctx.strokeStyle = strokeColor; - ctx.setLineDash([]); - ctx.fill(); - ctx.stroke(); - ctx.closePath(); -}; - -CIQ.Drawing.prototype.rotator = function (ctx, x, y, on) { - if (this.permanent) return; - var circleSize = this.littleCircleRadius(); - var strokeColor = this.stx.defaultColor; - ctx.beginPath(); - ctx.lineWidth = 2; - if (!on) ctx.globalAlpha = 0.5; - var radius = 4 + circleSize; - ctx.arc(x, y, radius, 0, (3 * Math.PI) / 2, false); - ctx.moveTo(x + 2 + radius, y + 2); - ctx.lineTo(x + radius, y); - ctx.lineTo(x - 2 + radius, y + 2); - ctx.moveTo(x - 2, y + 2 - radius); - ctx.lineTo(x, y - radius); - ctx.lineTo(x - 2, y - 2 - radius); - ctx.strokeStyle = strokeColor; - ctx.stroke(); - ctx.closePath(); - ctx.globalAlpha = 1; -}; - -CIQ.Drawing.prototype.mover = function (ctx, x, y, on) { - if (this.permanent) return; - var circleSize = this.littleCircleRadius(); - var strokeColor = this.stx.defaultColor; - var length = 5; - var start = circleSize + 1; - ctx.save(); - ctx.lineWidth = 2; - ctx.strokeStyle = strokeColor; - ctx.translate(x, y); - if (!on) ctx.globalAlpha = 0.5; - for (var i = 0; i < 4; i++) { - ctx.rotate(Math.PI / 2); - ctx.beginPath(); - ctx.moveTo(0, start); - ctx.lineTo(0, start + length); - ctx.moveTo(-2, start + length - 2); - ctx.lineTo(0, start + length); - ctx.lineTo(2, start + length - 2); - ctx.closePath(); - ctx.stroke(); - } - ctx.globalAlpha = 1; - ctx.restore(); -}; - -CIQ.Drawing.prototype.resizer = function (ctx, x, y, on) { - if (this.permanent) return; - var circleSize = this.littleCircleRadius(); - var strokeColor = this.stx.defaultColor; - var length = 5 * Math.sqrt(2); - var start = circleSize + 1; - ctx.save(); - ctx.lineWidth = 2; - ctx.strokeStyle = strokeColor; - ctx.translate(x, y); - ctx.rotate(((-(x * y) / Math.abs(x * y)) * Math.PI) / 4); - if (!on) ctx.globalAlpha = 0.5; - for (var i = 0; i < 2; i++) { - ctx.rotate(Math.PI); - ctx.beginPath(); - ctx.moveTo(0, start); - ctx.lineTo(0, start + length); - ctx.moveTo(-2, start + length - 2); - ctx.lineTo(0, start + length); - ctx.lineTo(2, start + length - 2); - ctx.closePath(); - ctx.stroke(); - } - ctx.globalAlpha = 1; - ctx.restore(); -}; - -/** - * Returns true if the tick and value are inside the box - * @param {number} tick The tick - * @param {number} value The value - * @param {object} box The box - * @param {boolean} isPixels True if tick and value are in pixels; otherwise, they assumed to be in ticks and untransformed y-axis values, respectively - * @return {boolean} True if the tick and value are within the box - * @memberOf CIQ.Drawing - * @since 7.0.0 Added `isPixels`. - */ -CIQ.Drawing.prototype.pointIntersection = function ( - tick, - value, - box, - isPixels -) { - var panel = this.stx.panels[this.panelName]; - if (!panel) return false; - if (isPixels) { - if ( - tick >= box.cx0 && - tick <= box.cx1 && - value >= box.cy0 && - value <= box.cy1 - ) - return true; - } else { - if ( - tick >= box.x0 && - tick <= box.x1 && - value >= Math.min(box.y0, box.y1) && - value <= Math.max(box.y0, box.y1) - ) - return true; - } - return false; -}; - -/** - * Sets the internal properties of the drawing points where x is a tick or a date and y is a value. - * @param {number} point index to point to be converted (0,1) - * @param {number|string} x index of bar in dataSet (tick) or date of tick (string form) - * @param {number} y price - * @param {CIQ.ChartEngine.Chart} [chart] Optional chart object - * @memberOf CIQ.Drawing.BaseTwoPoint - * @since 04-2015 - */ -CIQ.Drawing.prototype.setPoint = function (point, x, y, chart) { - var tick = null; - var date = null; - if (typeof x == "number") tick = x; - else if (x.length >= 8) date = x; - else tick = Number(x); - - if (y || y === 0) this["v" + point] = y; - var d; - if (tick !== null) { - d = this.stx.dateFromTick(tick, chart, true); - this["tzo" + point] = d.getTimezoneOffset(); - this["d" + point] = CIQ.yyyymmddhhmmssmmm(d); - this["p" + point] = [tick, y]; - } else if (date !== null) { - d = CIQ.strToDateTime(date); - if (!this["tzo" + point] && this["tzo" + point] !== 0) - this["tzo" + point] = d.getTimezoneOffset(); - this["d" + point] = date; - var adj = this["tzo" + point] - d.getTimezoneOffset(); - d.setMinutes(d.getMinutes() + adj); - var forward = false; - // if no match, we advance on intraday when there is a no time portion - // except for free form which already handles time placement internally - if ( - this.name != "freeform" && - !CIQ.ChartEngine.isDailyInterval(this.stx.layout.interval) && - !d.getHours() && - !d.getMinutes() && - !d.getSeconds() && - !d.getMilliseconds() - ) - forward = true; - - this["p" + point] = [ - this.stx.tickFromDate(CIQ.yyyymmddhhmmssmmm(d), chart, null, forward), - y - ]; - } -}; - -/** - * Compute the proper color to use when rendering lines in the drawing. - * - * Will use the color but if set to auto or transparent, will use the container's defaultColor. - * However, if color is set to auto and the drawing is based off a series or study plot, - * this function will return that plot's color. - * If drawing is highlighted will use the highlight color as defined in stx_highlight_vector style. - * @param {string} color Color string to check and use as a basis for setting. If not supplied, uses this.color. - * @return {string} Color to use for the line drawing - * @memberOf CIQ.Drawing - * @since 7.0.0 Replaces `setLineColor`. Will return source line's color if auto. - * @example - * var trendLineColor=this.getLineColor(); - * this.stx.plotLine(x0, x1, y0, y1, trendLineColor, "segment", context, panel, parameters); - */ -CIQ.Drawing.prototype.getLineColor = function (color) { - if (!color) color = this.color; - var stx = this.stx, - lineColor = color; - if (this.highlighted) { - lineColor = stx.getCanvasColor("stx_highlight_vector"); - } else if (CIQ.isTransparent(lineColor)) { - lineColor = stx.defaultColor; - } else if (lineColor == "auto") { - lineColor = stx.defaultColor; - if (this.field) { - // ugh, need to search for it - var n; - for (n in stx.layout.studies) { - var s = stx.layout.studies[n]; - var candidateColor = s.outputs[s.outputMap[this.field]]; - if (candidateColor) { - lineColor = candidateColor.color || candidateColor; - break; - } - } - var fallBackOn; - for (n in stx.chart.seriesRenderers) { - var renderer = stx.chart.seriesRenderers[n]; - for (var m = 0; m < renderer.seriesParams.length; m++) { - var series = renderer.seriesParams[m]; - var fullField = series.field; - if (!fullField && !renderer.highLowBars) - fullField = this.defaultPlotField || "Close"; - if (series.symbol && series.subField) - fullField += "-->" + series.subField; - if (this.field == fullField) { - lineColor = series.color; - break; - } - if (series.field && series.field == this.field.split("-->")[0]) - fallBackOn = series.color; - } - } - if (fallBackOn) lineColor = fallBackOn; - } - } - if (lineColor == "auto") lineColor = stx.defaultColor; - - return lineColor; -}; - -/** - * Base class for drawings that require two mouse clicks. Override as required. - * @constructor - * @name CIQ.Drawing.BaseTwoPoint - */ -CIQ.Drawing.BaseTwoPoint = function () { - this.p0 = null; - this.p1 = null; - this.color = ""; -}; - -CIQ.inheritsFrom(CIQ.Drawing.BaseTwoPoint, CIQ.Drawing); - -CIQ.Drawing.BaseTwoPoint.prototype.configs = []; - -/** - * Intersection is based on a hypothetical box that follows a user's mouse or finger. An - * intersection occurs when the box crosses over the drawing. The type should be "segment", "ray" - * or "line" depending on whether the drawing extends infinitely in any or both directions. Radius - * determines the size of the box in pixels and is determined by the kernel depending on the user - * interface (mouse, touch, etc.). - * - * @param {number} tick Tick in the `dataSet`. - * @param {number} value Value at the cursor position. - * @param {object} box x0, y0, x1, y1, r representing an area around the cursor, including the - * radius. - * @param {string} type Determines how the line should be treated (as segment, ray, or line) when - * finding an intersection. - * @param {number[]} [p0] The x/y coordinates of the first endpoint of the line that is tested for - * intersection with `box`. - * @param {number[]} [p1] The x/y coordinates of the second endpoint of the line that is tested for - * intersection with `box`. - * @param {boolean} [isPixels] Indicates that box values are in pixel values. - * @return {boolean} True if the line intersects the box; otherwise, false. - * - * @memberOf CIQ.Drawing.BaseTwoPoint - */ -CIQ.Drawing.BaseTwoPoint.prototype.lineIntersection = function ( - tick, - value, - box, - type, - p0, - p1, - isPixels -) { - if (!p0) p0 = this.p0; - if (!p1) p1 = this.p1; - var stx = this.stx; - if (!(p0 && p1)) return false; - var pixelBox = CIQ.convertBoxToPixels(stx, this.panelName, box); - if (pixelBox.x0 === undefined) return false; - var pixelPoint = { x0: p0[0], x1: p1[0], y0: p0[1], y1: p1[1] }; - if (!isPixels) - pixelPoint = CIQ.convertBoxToPixels(stx, this.panelName, pixelPoint); - return CIQ.boxIntersects( - pixelBox.x0, - pixelBox.y0, - pixelBox.x1, - pixelBox.y1, - pixelPoint.x0, - pixelPoint.y0, - pixelPoint.x1, - pixelPoint.y1, - type - ); -}; - -/** - * Determine whether the tick/value lies within the theoretical box outlined by this drawing's two - * points. - * - * @param {number} tick Tick in the `dataSet`. - * @param {number} value Value at position. - * @param {object} box x0, y0, x1, y1, r representing an area around the cursor, including the - * radius. - * @return {boolean} True if box intersects the drawing. - * - * @memberof CIQ.Drawing.BaseTwoPoint - */ -CIQ.Drawing.BaseTwoPoint.prototype.boxIntersection = function ( - tick, - value, - box -) { - if (!this.p0 || !this.p1) return false; - if ( - box.x0 > Math.max(this.p0[0], this.p1[0]) || - box.x1 < Math.min(this.p0[0], this.p1[0]) - ) - return false; - if ( - box.y1 > Math.max(this.p0[1], this.p1[1]) || - box.y0 < Math.min(this.p0[1], this.p1[1]) - ) - return false; - return true; -}; - -/** - * Any two-point drawing that results in a drawing that is less than 10 pixels - * can safely be assumed to be an accidental click. Such drawings are so small - * that they are difficult to highlight and delete, so we won't allow them. - * - * Note: it is very important to use pixelFromValueAdjusted() rather than pixelFromPrice(). This will - * ensure that saved drawings always render correctly when a chart is adjusted or transformed for display - * @param {number} tick Tick in the `dataSet`. - * @param {number} value Value at position. - * @memberOf CIQ.Drawing.BaseTwoPoint - */ -CIQ.Drawing.BaseTwoPoint.prototype.accidentalClick = function (tick, value) { - var panel = this.stx.panels[this.panelName]; - var x0 = this.stx.pixelFromTick(this.p0[0], panel.chart); - var x1 = this.stx.pixelFromTick(tick, panel.chart); - var y0 = this.stx.pixelFromValueAdjusted(panel, this.p0[0], this.p0[1]); - var y1 = this.stx.pixelFromValueAdjusted(panel, tick, value); - var h = Math.abs(x1 - x0); - var v = Math.abs(y1 - y0); - var length = Math.sqrt(h * h + v * v); - if (length < 10) { - this.penDown = false; - if (this.dragToDraw) this.stx.undo(); - return true; - } -}; - -/** - * Value will be the actual underlying, unadjusted value for the drawing. Any adjustments or transformations - * are reversed out by the kernel. Internally, drawings should store their raw data (date and value) so that - * they can be rendered on charts with different layouts, axis, etc - * @param {CanvasRenderingContext2D} context Canvas context on which to render. - * @param {number} tick Tick in the `dataSet`. - * @param {number} value Value at position. - * @memberOf CIQ.Drawing.BaseTwoPoint - */ -CIQ.Drawing.BaseTwoPoint.prototype.click = function (context, tick, value) { - this.copyConfig(); - var panel = this.stx.panels[this.panelName]; - if (!this.penDown) { - this.setPoint(0, tick, value, panel.chart); - this.penDown = true; - return false; - } - if (this.accidentalClick(tick, value)) return this.dragToDraw; - - this.setPoint(1, tick, value, panel.chart); - this.penDown = false; - return true; // kernel will call render after this -}; - -/** - * Default adjust function for BaseTwoPoint drawings - * @memberOf CIQ.Drawing.BaseTwoPoint - */ -CIQ.Drawing.BaseTwoPoint.prototype.adjust = function () { - // If the drawing's panel doesn't exist then we'll check to see - // whether the panel has been added. If not then there's no way to adjust - var panel = this.stx.panels[this.panelName]; - if (!panel) return; - this.setPoint(0, this.d0, this.v0, panel.chart); - this.setPoint(1, this.d1, this.v1, panel.chart); -}; - -/** - * Default move function for BaseTwoPoint drawings - * @param {CanvasRenderingContext2D} context Canvas context on which to render. - * @param {number} tick Tick in the `dataSet`. - * @param {number} value Value at position. - * @memberOf CIQ.Drawing.BaseTwoPoint - */ -CIQ.Drawing.BaseTwoPoint.prototype.move = function (context, tick, value) { - if (!this.penDown) return; - - this.copyConfig(); - this.p1 = [tick, value]; - this.render(context); -}; - -/** - * Default measure function for BaseTwoPoint drawings - * @memberOf CIQ.Drawing.BaseTwoPoint - */ -CIQ.Drawing.BaseTwoPoint.prototype.measure = function () { - if (this.p0 && this.p1) { - this.stx.setMeasure( - this.p0[1], - this.p1[1], - this.p0[0], - this.p1[0], - true, - this.name - ); - var mSticky = this.stx.controls.mSticky; - var mStickyInterior = mSticky && mSticky.querySelector(".mStickyInterior"); - if (mStickyInterior) { - var lines = []; - lines.push(CIQ.capitalize(this.name)); - if (this.getYValue) - lines.push(this.field || this.stx.defaultPlotField || "Close"); - lines.push(mStickyInterior.innerHTML); - mStickyInterior.innerHTML = lines.join("
"); - } - } -}; - -CIQ.Drawing.BaseTwoPoint.prototype.reposition = function ( - context, - repositioner, - tick, - value -) { - if (!repositioner) return; - var panel = this.stx.panels[this.panelName]; - var tickDiff = repositioner.tick - tick; - var valueDiff = repositioner.value - value; - if (repositioner.action == "move") { - this.setPoint( - 0, - repositioner.p0[0] - tickDiff, - repositioner.p0[1] - valueDiff, - panel.chart - ); - this.setPoint( - 1, - repositioner.p1[0] - tickDiff, - repositioner.p1[1] - valueDiff, - panel.chart - ); - this.render(context); - } else if (repositioner.action == "drag") { - this[repositioner.point] = [tick, value]; - this.setPoint(0, this.p0[0], this.p0[1], panel.chart); - this.setPoint(1, this.p1[0], this.p1[1], panel.chart); - this.render(context); - } -}; - -CIQ.Drawing.BaseTwoPoint.prototype.drawDropZone = function ( - context, - hBound1, - hBound2, - leftBound, - rightBound -) { - var panel = this.stx.panels[this.panelName]; - if (!panel) return; - var x0 = panel.left; - var x1 = panel.width; - if (leftBound || leftBound === 0) - x0 = this.stx.pixelFromTick(leftBound, panel.chart); - if (rightBound || rightBound === 0) - x1 = this.stx.pixelFromTick(rightBound, panel.chart); - var y0 = this.stx.pixelFromPrice(hBound1, panel); - var y1 = this.stx.pixelFromPrice(hBound2, panel); - context.fillStyle = "#008000"; - context.globalAlpha = 0.2; - context.fillRect(x0, y0, x1 - x0, y1 - y0); - context.globalAlpha = 1; -}; - -/** - * Annotation drawing tool. An annotation is a simple text tool. It uses the class stx_annotation - * to determine the font style and color for the annotation. Class stx_annotation_highlight_bg is used to - * determine the background color when highlighted. - * - * The controls controls.annotationSave and controls.annotationCancel are used to create HTMLElements for - * saving and canceling the annotation while editing. A textarea is created dynamically. The annotation tool - * attempts to draw the annotations at the same size and position as the textarea so that the effect is wysiwig. - * @constructor - * @name CIQ.Drawing.annotation - * @see {@link CIQ.Drawing.BaseTwoPoint} - */ -CIQ.Drawing.annotation = function () { - this.name = "annotation"; - this.arr = []; - this.w = 0; - this.h = 0; - this.padding = 4; - this.text = ""; - this.ta = null; - this.fontSize = 0; - this.font = {}; -}; -CIQ.inheritsFrom(CIQ.Drawing.annotation, CIQ.Drawing.BaseTwoPoint); - -CIQ.Drawing.annotation.prototype.getFontString = function () { - this.fontDef = { - style: null, - weight: null, - size: "12px", - family: null - }; - var css = this.stx.canvasStyle("stx_annotation"); - if (css) { - if (css.fontStyle) this.fontDef.style = css.fontStyle; - if (css.fontWeight) this.fontDef.weight = css.fontWeight; - if (css.fontSize) this.fontDef.size = css.fontSize; - if (css.fontFamily) this.fontDef.family = css.fontFamily; - } - if (this.font.style) this.fontDef.style = this.font.style; - if (this.font.weight) this.fontDef.weight = this.font.weight; - if (this.font.size) this.fontDef.size = this.font.size; - if (this.font.family) this.fontDef.family = this.font.family; - this.fontString = ""; - var first = true; - for (var n in this.fontDef) { - if (this.fontDef[n]) { - if (!first) { - this.fontString += " "; - } else { - first = false; - } - this.fontString += this.fontDef[n]; - } - } -}; - -CIQ.Drawing.annotation.prototype.configs = ["color", "font"]; - -CIQ.Drawing.annotation.prototype.measure = function () {}; - -CIQ.Drawing.annotation.prototype.render = function (context) { - if (this.ta) return; - var panel = this.stx.panels[this.panelName]; - if (!panel) return; - var x0 = this.stx.pixelFromTick(this.p0[0], panel.chart); - var y0 = this.stx.pixelFromValueAdjusted(panel, this.p0[0], this.p0[1]); - - context.font = this.fontString; - context.textBaseline = "middle"; - var x = x0; - var y = y0; - var w = this.w; - var h = this.h; - - var color = this.getLineColor(); - if (this.stem) { - var sx0, sx1, sy0, sy1; - if (this.stem.d) { - // absolute positioning of stem - sx0 = this.stx.pixelFromTick(this.stem.t); // bottom of stem - sy0 = this.stx.pixelFromValueAdjusted(panel, this.stem.t, this.stem.v); - sx1 = x + w / 2; // center of text - sy1 = y + h / 2; - } else if (this.stem.x) { - // stem with relative offset positioning - sx0 = x; - sy0 = y; - x += this.stem.x; - y += this.stem.y; - sx1 = x + w / 2; - sy1 = y + h / 2; - } - - context.beginPath(); - if (this.borderColor) context.strokeStyle = this.borderColor; - else context.strokeStyle = color; - context.moveTo(sx0, sy0); - context.lineTo(sx1, sy1); - context.stroke(); - } - var lineWidth = context.lineWidth; - if (this.highlighted) { - this.stx.canvasColor("stx_annotation_highlight_bg", context); - context.fillRect( - x - lineWidth, - y - h / 2 - lineWidth, - w + 2 * lineWidth, - h + 2 * lineWidth - ); - } else { - if (this.fillColor) { - context.fillStyle = this.fillColor; - context.fillRect(x, y - h / 2, w, h); - } else if (this.stem) { - // If there's a stem then use the container color otherwise the stem will show through - context.fillStyle = this.stx.containerColor; - context.fillRect(x, y - h / 2, w, h); - } - } - if (this.borderColor) { - context.beginPath(); - context.strokeStyle = this.highlighted - ? this.stx.getCanvasColor("stx_highlight_vector") - : this.borderColor; - context.rect( - x - lineWidth, - y - h / 2 - lineWidth, - w + 2 * lineWidth, - h + 2 * lineWidth - ); - context.stroke(); - } - - if (this.highlighted) { - this.stx.canvasColor("stx_annotation_highlight", context); - } else { - context.fillStyle = color; - } - y += this.padding / 2; - if (!this.ta) { - for (var i = 0; i < this.arr.length; i++) { - context.fillText( - this.arr[i], - x + this.padding, - y - h / 2 + this.fontSize / 2 - ); - y += this.fontSize + 2; // 2 px space between lines - } - } - context.textBaseline = "alphabetic"; -}; - -CIQ.Drawing.annotation.prototype.onChange = function (e) { - //no operation. Override if you want to capture the change. -}; - -CIQ.Drawing.annotation.prototype.edit = function (context, editExisting) { - var panel = this.stx.panels[this.panelName]; - if (!panel) return; - // When mouse events are attached to the container then any dom objects on top - // of the container will intercept those events. In particular, the textarea for - // annotations gets in the way, so here we capture the mouseup that fires on the textarea - // and pass it along to the kernel if necessary - function handleTAMouseUp(stx) { - return function (e) { - if (stx.manageTouchAndMouse && CIQ.ChartEngine.drawingLine) { - stx.mouseup(e); - } - }; - } - - function cancelAnnotation(self) { - return function (e) { - var stx = self.stx; - stx.editingAnnotation = false; - stx.undo(); - stx.cancelTouchSingleClick = true; - }; - } - function saveAnnotation(self) { - return function (e) { - if (self.ta.value === "") return; - self.text = self.ta.value; - var stx = self.stx; - stx.editingAnnotation = false; - self.adjust(); - if (stx.drawingSnapshot) - stx.undoStamp( - CIQ.shallowClone(stx.drawingSnapshot), - stx.exportDrawings() - ); - else stx.addDrawing(self); // add only if it's not already there (text being modified) - stx.undo(); - stx.cancelTouchSingleClick = true; - stx.changeOccurred("vector"); - }; - } - - function resizeAnnotation(self) { - return function (e) { - if (e) { - var key = e.keyCode; - switch (key) { - case 27: - self.stx.undo(); - return; - } - } - var stx = self.stx; - var ta = self.ta; - var arr = ta.value.split("\n"); - var w = 0; - //stx.canvasFont("stx_annotation"); - stx.chart.context.font = self.fontString; - for (var i = 0; i < arr.length; i++) { - var m = stx.chart.context.measureText(arr[i]).width; - if (m > w) w = m; - } - var h = (arr.length + 1) * (self.fontSize + 3); - if (w < 50) w = 50; - ta.style.width = w + 30 + "px"; // Leave room for scroll bar - ta.style.height = h + "px"; - var y = parseInt(CIQ.stripPX(ta.style.top), 10); - var x = CIQ.stripPX(ta.style.left); - w = ta.clientWidth; - h = ta.clientHeight; - if (x + w + 100 < self.stx.chart.canvasWidth) { - save.style.top = y + "px"; - cancel.style.top = y + "px"; - save.style.left = x + w + 10 + "px"; - cancel.style.left = x + w + 60 + "px"; - } else if (y + h + 30 < self.stx.chart.canvasHeight) { - save.style.top = y + h + 10 + "px"; - cancel.style.top = y + h + 10 + "px"; - save.style.left = x + "px"; - cancel.style.left = x + 50 + "px"; - } else { - save.style.top = y - 35 + "px"; - cancel.style.top = y - 35 + "px"; - save.style.left = x + "px"; - cancel.style.left = x + 50 + "px"; - } - }; - } - - var save = this.stx.controls.annotationSave; - var cancel = this.stx.controls.annotationCancel; - if (!save || !cancel) return; - - var stx = this.stx, - ta = this.ta; - stx.editingAnnotation = true; - stx.undisplayCrosshairs(); - stx.openDialog = "annotation"; - if (!ta) { - ta = this.ta = document.createElement("TEXTAREA"); - ta.className = "stx_annotation"; - ta.onkeyup = resizeAnnotation(this); - ta.onmouseup = handleTAMouseUp(stx); - ta.setAttribute("wrap", "hard"); - if (CIQ.isIOS7or8) ta.setAttribute("placeholder", "Enter Text"); - stx.chart.container.appendChild(ta); - ta.style.position = "absolute"; - ta.style.width = "100px"; - ta.style.height = "20px"; - ta.value = this.text; - if (CIQ.touchDevice) { - ta.ontouchstart = function (e) { - e.stopPropagation(); - }; - /*var ta=this.ta; - CIQ.safeClickTouch(this.ta, function(e){ - if(document.activeElement===ta){ - window.focus(); - CIQ.focus(ta, true); - } - });*/ - } - } - var self = this; - ta.oninput = function (e) { - // disable browser undo history due to hidden textarea with contenteditable - if (e.inputType != "historyUndo" && e.inputType != "historyRedo") - self.onChange(e); - }; - ta.style.font = this.fontString; - if (this.color) { - if (this.color == "transparent" || this.color == "auto") { - var styles = getComputedStyle(ta); - if (styles && CIQ.isTransparent(styles.backgroundColor)) { - ta.style.color = stx.defaultColor; - } else { - ta.style.color = "#000"; // text area always has white background - } - } else { - ta.style.color = this.color; - } - } - var x0 = stx.pixelFromTick(this.p0[0], panel.chart); - var y0 = stx.pixelFromValueAdjusted(panel, this.p0[0], this.p0[1]); - //if the right edge of the ta is off of the screen, scootch it to the left. - ta.style.left = - x0 + 140 < stx.chart.canvasRight - ? x0 + "px" - : stx.chart.canvasRight - 200 + "px"; - //if user clicks within 60 px of bottom of the chart,scootch it up. - ta.style.top = - y0 + 60 < stx.chart.canvasHeight - ? y0 - (!isNaN(this.h) ? this.h / 2 : this.defaultHeight) + "px" - : y0 - 60 + "px"; - if (this.name == "callout") { - ta.style.left = - CIQ.stripPX(ta.style.left) - - (!isNaN(this.w) ? this.w / 2 : this.defaultWidth) + - "px"; - } - - CIQ.safeClickTouch(save, saveAnnotation(this)); - CIQ.safeClickTouch(cancel, cancelAnnotation(this)); - resizeAnnotation(this)(); - save.style.display = "inline-block"; - cancel.style.display = "inline-block"; - - if (editExisting) { - // lift the drawing off the canvas and onto the tempCanvas - stx.drawingSnapshot = stx.exportDrawings(); - this.hidden = true; - stx.draw(); - stx.activeDrawing = this; - CIQ.ChartEngine.drawingLine = true; - context = stx.chart.tempCanvas.context; - stx.chart.tempCanvas.style.display = "block"; - this.w = ta.clientWidth; - this.h = ta.clientHeight; - CIQ.clearCanvas(context.canvas, stx); - this.render(context); - this.edit(context); - } - - ta.focus(); - - if (CIQ.isAndroid && !CIQ.is_chrome && !CIQ.isFF) { - // Android soft keyboard will cover up the lower half of the browser so if our - // annotation is in that area we temporarily scroll the chart container upwards - // The style.bottom of the chart container is reset in abort() - this.priorBottom = stx.chart.container.style.bottom; - var keyboardHeight = 400; // hard coded. We could get this by measuring the change in innerHeight but timing is awkward because the keyboard scrolls - var screenLocation = stx.resolveY(y0) + 100; // figure 100 pixels of height for text - if (screenLocation > CIQ.pageHeight() - keyboardHeight) { - var pixelsFromBottomOfScreen = CIQ.pageHeight() - screenLocation; - var scrolledBottom = keyboardHeight - pixelsFromBottomOfScreen; - stx.chart.container.style.bottom = scrolledBottom + "px"; - } - } -}; - -CIQ.Drawing.annotation.prototype.click = function (context, tick, value) { - //don't allow user to add annotation on the axis. - if (this.stx.overXAxis || this.stx.overYAxis) return; - var panel = this.stx.panels[this.panelName]; - this.copyConfig(); - //this.getFontString(); - this.setPoint(0, tick, value, panel.chart); - this.adjust(); - - this.edit(context); - return false; -}; - -CIQ.Drawing.annotation.prototype.reposition = function ( - context, - repositioner, - tick, - value -) { - if (!repositioner) return; - var panel = this.stx.panels[this.panelName]; - var tickDiff = repositioner.tick - tick; - var valueDiff = repositioner.value - value; - this.setPoint( - 0, - repositioner.p0[0] - tickDiff, - repositioner.p0[1] - valueDiff, - panel.chart - ); - this.render(context); -}; - -CIQ.Drawing.annotation.prototype.intersected = function (tick, value, box) { - var panel = this.stx.panels[this.panelName]; - if (!this.p0) return null; // in case invalid drawing (such as from panel that no longer exists) - var x0 = this.stx.pixelFromTick(this.p0[0], panel.chart); - var y0 = - this.stx.pixelFromValueAdjusted(panel, this.p0[0], this.p0[1]) - this.h / 2; - var x1 = x0 + this.w; - var y1 = y0 + this.h; - if (this.stem && this.stem.x) { - x0 += this.stem.x; - x1 += this.stem.x; - y0 += this.stem.y; - y1 += this.stem.y; - } - var x = this.stx.pixelFromTick(tick, panel.chart); - var y = this.stx.pixelFromValueAdjusted(panel, tick, value); - - if ( - x + box.r >= x0 && - x - box.r <= x1 && - y + box.r >= y0 && - y - box.r <= y1 - ) { - this.highlighted = true; - return { - p0: CIQ.clone(this.p0), - tick: tick, - value: value - }; - } - return false; -}; - -CIQ.Drawing.annotation.prototype.abort = function () { - var save = this.stx.controls.annotationSave, - cancel = this.stx.controls.annotationCancel; - if (save) save.style.display = "none"; - if (cancel) cancel.style.display = "none"; - if (this.ta) this.stx.chart.container.removeChild(this.ta); - this.ta = null; - this.stx.openDialog = ""; - this.stx.showCrosshairs(); - //document.body.style.cursor="crosshair"; //Was interfering with undisplayCrosshairs(). - this.stx.editingAnnotation = false; - CIQ.clearCanvas(this.stx.chart.tempCanvas, this.stx); - if (CIQ.isAndroid && !CIQ.is_chrome && !CIQ.isFF) { - this.stx.chart.container.style.bottom = this.priorBottom; - } - CIQ.fixScreen(); -}; - -/** - * Reconstruct an annotation - * @param {CIQ.ChartEngine} stx The chart object - * @param {object}[obj] A drawing descriptor - * @param {string} [obj.col] The text color for the annotation - * @param {string} [obj.pnl] The panel name - * @param {string} [obj.d0] String form date or date time - * @param {number} [obj.v0] The value at which to position the annotation - * @param {string} [obj.text] The annotation text (escaped using encodeURIComponent()) - * @param {number} [obj.tzo0] Offset of UTC from d0 in minutes - * @param {string} [obj.bc] Border color - * @param {string} [obj.bg] Background color - * @param {string} [obj.lw] Line width - * @param {string} [obj.ptrn] Line pattern - * @param {object} [obj.fnt] Font - * @param {object} [obj.fnt.st] Font style - * @param {object} [obj.fnt.sz] Font size - * @param {object} [obj.fnt.wt] Font weight - * @param {object} [obj.fnt.fl] Font family - * @memberOf CIQ.Drawing.annotation - */ -CIQ.Drawing.annotation.prototype.reconstruct = function (stx, obj) { - this.stx = stx; - this.color = obj.col; - this.panelName = obj.pnl; - this.d0 = obj.d0; - this.tzo0 = obj.tzo0; - this.v0 = obj.v0; - this.text = stx.escapeOnSerialize ? decodeURIComponent(obj.text) : obj.text; - this.stem = obj.stem; - this.borderColor = obj.bc; - this.fillColor = obj.bg; - this.lineWidth = obj.lw; - this.pattern = obj.ptrn; - this.font = CIQ.replaceFields(obj.fnt, { - st: "style", - sz: "size", - wt: "weight", - fl: "family" - }); - if (!this.font) this.font = {}; - this.adjust(); -}; - -CIQ.Drawing.annotation.prototype.serialize = function () { - var obj = { - name: this.name, - pnl: this.panelName, - col: this.color, - d0: this.d0, - tzo0: this.tzo0, - v0: this.v0, - text: this.stx.escapeOnSerialize ? encodeURIComponent(this.text) : this.text - }; - if (this.font) { - var fnt = CIQ.removeNullValues( - CIQ.replaceFields(this.font, { - style: "st", - size: "sz", - weight: "wt", - family: "fl" - }) - ); - if (!CIQ.isEmpty(fnt)) obj.fnt = fnt; - } - if (this.stem) { - obj.stem = { - d: this.stem.d, - v: this.stem.v, - x: this.stem.x, - y: this.stem.y - }; - } - if (this.borderColor) obj.bc = this.borderColor; - if (this.fillColor) obj.bg = this.fillColor; - if (this.lineWidth) obj.lw = this.lineWidth; - if (this.pattern) obj.ptrn = this.pattern; - - return obj; -}; - -CIQ.Drawing.annotation.prototype.renderText = function () { - this.getFontString(); - var panel = this.stx.panels[this.panelName]; - if (!panel) return; - this.arr = this.text.split("\n"); - var w = 0; - this.stx.chart.context.font = this.fontString; - //this.stx.canvasFont("stx_annotation"); - for (var i = 0; i < this.arr.length; i++) { - var m = this.stx.chart.context.measureText(this.arr[i]).width; - if (m > w) w = m; - } - if (w === 0) w = 2 * this.defaultWidth; - //this.fontSize=this.stx.getCanvasFontSize("stx_annotation"); - this.fontSize = CIQ.stripPX(this.fontDef.size); - var h = this.arr.length * (this.fontSize + 2); // 2 px space to separate lines - if (CIQ.touchDevice) h += 5; - this.w = w + this.padding * 2; - this.h = h + this.padding * 2; - var x1 = this.stx.pixelFromTick(this.p0[0], panel.chart) + w; - var y1 = this.stx.pixelFromValueAdjusted(panel, this.p0[0], this.p0[1]) + h; - this.p1 = [ - this.stx.tickFromPixel(x1, panel.chart), - this.stx.valueFromPixel(y1, panel) - ]; - if (this.stem && this.stem.d) { - this.stem.t = this.stx.tickFromDate(this.stem.d, panel.chart); - } -}; - -CIQ.Drawing.annotation.prototype.adjust = function () { - var panel = this.stx.panels[this.panelName]; - if (!panel) return; - this.setPoint(0, this.d0, this.v0, panel.chart); - this.renderText(); -}; - -/** - * segment is an implementation of a {@link CIQ.Drawing.BaseTwoPoint} drawing. - * @name CIQ.Drawing.segment - * @constructor - */ -CIQ.Drawing.segment = function () { - this.name = "segment"; -}; - -CIQ.inheritsFrom(CIQ.Drawing.segment, CIQ.Drawing.BaseTwoPoint); - -CIQ.Drawing.segment.prototype.render = function (context) { - var panel = this.stx.panels[this.panelName]; - if (!panel) return; - var x0 = this.stx.pixelFromTick(this.p0[0], panel.chart); - var x1 = this.stx.pixelFromTick(this.p1[0], panel.chart); - var y0 = this.stx.pixelFromValueAdjusted(panel, this.p0[0], this.p0[1]); - var y1 = this.stx.pixelFromValueAdjusted(panel, this.p1[0], this.p1[1]); - - var width = this.lineWidth; - var color = this.getLineColor(); - - var parameters = { - pattern: this.pattern, - lineWidth: width - }; - if (parameters.pattern == "none") parameters.pattern = "solid"; - this.stx.plotLine( - x0, - x1, - y0, - y1, - color, - this.name, - context, - panel, - parameters - ); - - if (this.axisLabel && !this.repositioner) { - if (this.name == "horizontal") { - this.stx.endClip(); - var txt = this.p0[1]; - if (panel.chart.transformFunc) - txt = panel.chart.transformFunc(this.stx, panel.chart, txt); - if (panel.yAxis.priceFormatter) - txt = panel.yAxis.priceFormatter(this.stx, panel, txt); - else txt = this.stx.formatYAxisPrice(txt, panel); - this.stx.createYAxisLabel(panel, txt, y0, color); - this.stx.startClip(panel.name); - } else if ( - this.name == "vertical" && - this.p0[0] >= 0 && - !this.stx.chart.xAxis.noDraw - ) { - // don't try to compute dates from before dataSet - var dt, newDT; - dt = this.stx.dateFromTick(this.p0[0], panel.chart, true); - if (!CIQ.ChartEngine.isDailyInterval(this.stx.layout.interval)) { - var milli = dt.getSeconds() * 1000 + dt.getMilliseconds(); - if (timezoneJS.Date && this.stx.displayZone) { - // this converts from the quote feed timezone to the chart specified time zone - newDT = new timezoneJS.Date(dt.getTime(), this.stx.displayZone); - dt = new Date( - newDT.getFullYear(), - newDT.getMonth(), - newDT.getDate(), - newDT.getHours(), - newDT.getMinutes() - ); - dt = new Date(dt.getTime() + milli); - } - } else { - dt.setHours(0, 0, 0, 0); - } - var myDate = CIQ.mmddhhmm(CIQ.yyyymmddhhmm(dt)); - - if (panel.chart.xAxis.formatter) { - myDate = panel.chart.xAxis.formatter(dt, this.name, null, null, myDate); - } else if (this.stx.internationalizer) { - var str; - if (dt.getHours() !== 0 || dt.getMinutes() !== 0) { - str = this.stx.internationalizer.monthDay.format(dt); - str += " " + this.stx.internationalizer.hourMinute.format(dt); - } else { - str = this.stx.internationalizer.yearMonthDay.format(dt); - } - myDate = str; - } - - this.stx.endClip(); - this.stx.createXAxisLabel({ - panel: panel, - txt: myDate, - x: x0, - backgroundColor: color, - color: null, - pointed: true, - padding: 2 - }); - this.stx.startClip(panel.name); - } - } - if ( - this.highlighted && - this.name != "horizontal" && - this.name != "vertical" - ) { - var p0Fill = this.highlighted == "p0" ? true : false; - var p1Fill = this.highlighted == "p1" ? true : false; - this.littleCircle(context, x0, y0, p0Fill); - this.littleCircle(context, x1, y1, p1Fill); - } -}; - -CIQ.Drawing.segment.prototype.abort = function () { - this.stx.setMeasure(null, null, null, null, false); -}; - -CIQ.Drawing.segment.prototype.intersected = function (tick, value, box) { - if (!this.p0 || !this.p1) return null; // in case invalid drawing (such as from panel that no longer exists) - var name = this.name; - if (name != "horizontal" && name != "vertical" && name != "gartley") { - var pointsToCheck = { 0: this.p0, 1: this.p1 }; - for (var pt in pointsToCheck) { - if ( - this.pointIntersection(pointsToCheck[pt][0], pointsToCheck[pt][1], box) - ) { - this.highlighted = "p" + pt; - return { - action: "drag", - point: "p" + pt - }; - } - } - } - if (name == "horizontal" || name == "vertical") name = "line"; - var isIntersected = this.lineIntersection(tick, value, box, name); - if (isIntersected) { - this.highlighted = true; - // This object will be used for repositioning - return { - action: "move", - p0: CIQ.clone(this.p0), - p1: CIQ.clone(this.p1), - tick: tick, // save original tick - value: value // save original value - }; - } - return null; -}; - -CIQ.Drawing.segment.prototype.configs = ["color", "lineWidth", "pattern"]; - -CIQ.Drawing.segment.prototype.copyConfig = function (withPreferences) { - CIQ.Drawing.copyConfig(this, withPreferences); - if (this.pattern == "none" && this.configs.indexOf("fillColor") == -1) - this.pattern = "solid"; -}; - -/** - * Reconstruct a segment - * @memberOf CIQ.Drawing.segment - * @param {CIQ.ChartEngine} stx The chart object - * @param {object} [obj] A drawing descriptor - * @param {string} [obj.col] The line color - * @param {string} [obj.pnl] The panel name - * @param {string} [obj.ptrn] Optional pattern for line "solid","dotted","dashed". Defaults to solid. - * @param {number} [obj.lw] Optional line width. Defaults to 1. - * @param {number} [obj.v0] Value (price) for the first point - * @param {number} [obj.v1] Value (price) for the second point - * @param {number} [obj.d0] Date (string form) for the first point - * @param {number} [obj.d1] Date (string form) for the second point - * @param {number} [obj.tzo0] Offset of UTC from d0 in minutes - * @param {number} [obj.tzo1] Offset of UTC from d1 in minutes - */ -CIQ.Drawing.segment.prototype.reconstruct = function (stx, obj) { - this.stx = stx; - this.color = obj.col; - this.panelName = obj.pnl; - this.pattern = obj.ptrn; - this.lineWidth = obj.lw; - this.d0 = obj.d0; - this.d1 = obj.d1; - this.tzo0 = obj.tzo0; - this.tzo1 = obj.tzo1; - this.v0 = obj.v0; - this.v1 = obj.v1; - this.adjust(); -}; - -CIQ.Drawing.segment.prototype.serialize = function () { - return { - name: this.name, - pnl: this.panelName, - col: this.color, - ptrn: this.pattern, - lw: this.lineWidth, - d0: this.d0, - d1: this.d1, - tzo0: this.tzo0, - tzo1: this.tzo1, - v0: this.v0, - v1: this.v1 - }; -}; - -/** - * Line drawing tool. A line is a vector defined by two points that is infinite in both directions. - * - * It inherits its properties from {@link CIQ.Drawing.segment}. - * @constructor - * @name CIQ.Drawing.line - */ -CIQ.Drawing.line = function () { - this.name = "line"; -}; - -CIQ.inheritsFrom(CIQ.Drawing.line, CIQ.Drawing.segment); - -CIQ.Drawing.line.prototype.dragToDraw = false; - -CIQ.Drawing.line.prototype.calculateOuterSet = function (panel) { - if ( - this.p0[0] == this.p1[0] || - this.p0[1] == this.p1[1] || - CIQ.ChartEngine.isDailyInterval(this.stx.layout.interval) - ) { - return; - } - - var vector = { - x0: this.p0[0], - y0: this.p0[1], - x1: this.p1[0], - y1: this.p1[1] - }; - if (vector.x0 > vector.x1) { - vector = { - x0: this.p1[0], - y0: this.p1[1], - x1: this.p0[0], - y1: this.p0[1] - }; - } - - var earlier = vector.x0 - 1000; - var later = vector.x1 + 1000; - - this.v0B = CIQ.yIntersection(vector, earlier); - this.v1B = CIQ.yIntersection(vector, later); - this.d0B = this.stx.dateFromTick(earlier, panel.chart); - this.d1B = this.stx.dateFromTick(later, panel.chart); -}; - -CIQ.Drawing.line.prototype.click = function (context, tick, value) { - var panel = this.stx.panels[this.panelName]; - if (!panel) return; - this.copyConfig(); - if (!this.penDown) { - this.setPoint(0, tick, value, panel.chart); - this.penDown = true; - return false; - } - // if the user accidentally double clicks in rapid fashion - if (this.accidentalClick(tick, value)) return this.dragToDraw; - this.setPoint(1, tick, value, panel.chart); - this.calculateOuterSet(panel); - this.penDown = false; - return true; // kernel will call render after this -}; - -/** - * Reconstruct a line - * @param {CIQ.ChartEngine} stx The chart object - * @param {object} [obj] A drawing descriptor - * @param {string} [obj.col] The line color - * @param {string} [obj.pnl] The panel name - * @param {string} [obj.ptrn] Optional pattern for line "solid","dotted","dashed". Defaults to solid. - * @param {number} [obj.lw] Optional line width. Defaults to 1. - * @param {number} [obj.v0] Value (price) for the first point - * @param {number} [obj.v1] Value (price) for the second point - * @param {number} [obj.d0] Date (string form) for the first point - * @param {number} [obj.d1] Date (string form) for the second point - * @param {number} [obj.v0B] Computed outer Value (price) for the first point if original drawing was on intraday but now displaying on daily - * @param {number} [obj.v1B] Computed outer Value (price) for the second point if original drawing was on intraday but now displaying on daily - * @param {number} [obj.d0B] Computed outer Date (string form) for the first point if original drawing was on intraday but now displaying on daily - * @param {number} [obj.d1B] Computed outer Date (string form) for the second point if original drawing was on intraday but now displaying on daily - * @param {number} [obj.tzo0] Offset of UTC from d0 in minutes - * @param {number} [obj.tzo1] Offset of UTC from d1 in minutes - * @memberOf CIQ.Drawing.line - */ -CIQ.Drawing.line.prototype.reconstruct = function (stx, obj) { - this.stx = stx; - this.color = obj.col; - this.panelName = obj.pnl; - this.pattern = obj.ptrn; - this.lineWidth = obj.lw; - this.v0 = obj.v0; - this.v1 = obj.v1; - this.d0 = obj.d0; - this.d1 = obj.d1; - this.tzo0 = obj.tzo0; - this.tzo1 = obj.tzo1; - if (obj.d0B) { - this.d0B = obj.d0B; - this.d1B = obj.d1B; - this.v0B = obj.v0B; - this.v1B = obj.v1B; - } - this.adjust(); -}; - -CIQ.Drawing.line.prototype.serialize = function () { - var obj = { - name: this.name, - pnl: this.panelName, - col: this.color, - ptrn: this.pattern, - lw: this.lineWidth, - d0: this.d0, - d1: this.d1, - tzo0: this.tzo0, - tzo1: this.tzo1, - v0: this.v0, - v1: this.v1 - }; - if (this.d0B) { - obj.d0B = this.d0B; - obj.d1B = this.d1B; - obj.v0B = this.v0B; - obj.v1B = this.v1B; - } - return obj; -}; - -CIQ.Drawing.line.prototype.adjust = function () { - var panel = this.stx.panels[this.panelName]; - if (!panel) return; - this.setPoint(0, this.d0, this.v0, panel.chart); - this.setPoint(1, this.d1, this.v1, panel.chart); - // Use outer set if original drawing was on intraday but now displaying on daily - if (CIQ.ChartEngine.isDailyInterval(this.stx.layout.interval) && this.d0B) { - this.setPoint(0, this.d0B, this.v0B, panel.chart); - this.setPoint(1, this.d1B, this.v1B, panel.chart); - } -}; - -/** - * Horizontal line drawing tool. The horizontal line extends infinitely in both directions. - * - * It inherits its properties from {@link CIQ.Drawing.segment} - * @constructor - * @name CIQ.Drawing.horizontal - */ -CIQ.Drawing.horizontal = function () { - this.name = "horizontal"; -}; -CIQ.inheritsFrom(CIQ.Drawing.horizontal, CIQ.Drawing.segment); - -CIQ.Drawing.horizontal.prototype.dragToDraw = false; - -CIQ.Drawing.horizontal.prototype.measure = function () {}; - -CIQ.Drawing.horizontal.prototype.click = function (context, tick, value) { - var panel = this.stx.panels[this.panelName]; - if (!panel) return; - this.copyConfig(); - this.setPoint(0, tick, value, panel.chart); - return true; // kernel will call render after this -}; - -// skips point interection and forces positioner points inside of the dataSet -CIQ.Drawing.horizontal.prototype.intersected = function (tick, value, box) { - if (this.lineIntersection(tick, value, box, "line")) { - var stx = this.stx; - var t0 = stx.chart.dataSet.length; - var v0 = this.p0[1]; - - this.highlighted = true; - - return { - action: "move", - p0: [t0 - 2, v0], - p1: [t0 - 1, v0], - tick: tick, - value: value - }; - } - - return null; -}; - -/** - * Reconstruct a horizontal - * @param {CIQ.ChartEngine} stx The chart object - * @param {object} [obj] A drawing descriptor - * @param {string} [obj.col] The line color - * @param {string} [obj.pnl] The panel name - * @param {string} [obj.ptrn] Optional pattern for line "solid","dotted","dashed". Defaults to solid. - * @param {number} [obj.lw] Optional line width. Defaults to 1. - * @param {number} [obj.v0] Value (price) for the first point - * @param {number} [obj.d0] Date (string form) for the first point - * @param {boolean} [obj.al] True to include an axis label - * @param {number} [obj.tzo0] Offset of UTC from d0 in minutes - * @memberOf CIQ.Drawing.horizontal - */ -CIQ.Drawing.horizontal.prototype.reconstruct = function (stx, obj) { - this.stx = stx; - this.color = obj.col; - this.panelName = obj.pnl; - this.pattern = obj.ptrn; - this.lineWidth = obj.lw; - this.v0 = obj.v0; - this.d0 = obj.d0; - this.tzo0 = obj.tzo0; - this.axisLabel = obj.al; - this.adjust(); -}; - -CIQ.Drawing.horizontal.prototype.serialize = function () { - var obj = { - name: this.name, - pnl: this.panelName, - col: this.color, - ptrn: this.pattern, - lw: this.lineWidth, - v0: this.v0, - d0: this.d0, - tzo0: this.tzo0, - al: this.axisLabel - }; - - return obj; -}; - -CIQ.Drawing.horizontal.prototype.adjust = function () { - var panel = this.stx.panels[this.panelName]; - if (!panel) return; - this.setPoint(0, this.d0, this.v0, panel.chart); - this.p1 = [this.p0[0] + 100, this.p0[1]]; -}; - -CIQ.Drawing.horizontal.prototype.configs = [ - "color", - "lineWidth", - "pattern", - "axisLabel" -]; - -/** - * Vertical line drawing tool. The vertical line extends infinitely in both directions. - * - * It inherits its properties from {@link CIQ.Drawing.horizontal}. - * @constructor - * @name CIQ.Drawing.vertical - */ -CIQ.Drawing.vertical = function () { - this.name = "vertical"; -}; - -CIQ.inheritsFrom(CIQ.Drawing.vertical, CIQ.Drawing.horizontal); -CIQ.Drawing.vertical.prototype.measure = function () {}; - -// override specialized horizontal method -CIQ.Drawing.vertical.prototype.intersected = - CIQ.Drawing.segment.prototype.intersected; - -CIQ.Drawing.vertical.prototype.adjust = function () { - var panel = this.stx.panels[this.panelName]; - if (!panel) return; - this.setPoint(0, this.d0, this.v0, panel.chart); - this.p1 = [this.p0[0], this.p0[1] + 1]; -}; - -/** - * Measure tool. - * It inherits its properties from {@link CIQ.Drawing.segment}. - * @constructor - * @name CIQ.Drawing.measure - */ -CIQ.Drawing.measure = function () { - this.name = "measure"; -}; - -CIQ.inheritsFrom(CIQ.Drawing.measure, CIQ.Drawing.segment); - -CIQ.Drawing.measure.prototype.click = function (context, tick, value) { - this.copyConfig(); - if (!this.penDown) { - this.p0 = [tick, value]; - this.penDown = true; - - return false; - } - this.stx.undo(); - this.penDown = false; - return true; -}; - -/** - * rectangle is an implementation of a {@link CIQ.Drawing.BaseTwoPoint} drawing - * @constructor - * @name CIQ.Drawing.rectangle - */ -CIQ.Drawing.rectangle = function () { - this.name = "rectangle"; -}; - -CIQ.inheritsFrom(CIQ.Drawing.rectangle, CIQ.Drawing.BaseTwoPoint); - -CIQ.Drawing.rectangle.prototype.render = function (context) { - var panel = this.stx.panels[this.panelName]; - if (!panel) return; - var x0 = this.stx.pixelFromTick(this.p0[0], panel.chart); - var x1 = this.stx.pixelFromTick(this.p1[0], panel.chart); - var y0 = this.stx.pixelFromValueAdjusted(panel, this.p0[0], this.p0[1]); - var y1 = this.stx.pixelFromValueAdjusted(panel, this.p1[0], this.p1[1]); - - var x = Math.round(Math.min(x0, x1)) + 0.5; - var y = Math.min(y0, y1); - var width = Math.max(x0, x1) - x; - var height = Math.max(y0, y1) - y; - var edgeColor = this.color; - if (this.highlighted) { - edgeColor = this.stx.getCanvasColor("stx_highlight_vector"); - } - - var fillColor = this.fillColor; - if (fillColor && !CIQ.isTransparent(fillColor) && fillColor != "auto") { - context.beginPath(); - context.rect(x, y, width, height); - context.fillStyle = fillColor; - context.globalAlpha = 0.2; - context.fill(); - context.closePath(); - context.globalAlpha = 1; - } - - var parameters = { - pattern: this.pattern, - lineWidth: this.lineWidth - }; - if (this.highlighted && parameters.pattern == "none") { - parameters.pattern = "solid"; - if (parameters.lineWidth == 0.1) parameters.lineWidth = 1; - } - - // We extend the vertical lines by .5 to account for displacement of the horizontal lines - // HTML5 Canvas exists *between* pixels, not on pixels, so draw on .5 to get crisp lines - this.stx.plotLine( - x0, - x1, - y0, - y0, - edgeColor, - "segment", - context, - panel, - parameters - ); - this.stx.plotLine( - x1, - x1, - y0 - 0.5, - y1 + 0.5, - edgeColor, - "segment", - context, - panel, - parameters - ); - this.stx.plotLine( - x1, - x0, - y1, - y1, - edgeColor, - "segment", - context, - panel, - parameters - ); - this.stx.plotLine( - x0, - x0, - y1 + 0.5, - y0 - 0.5, - edgeColor, - "segment", - context, - panel, - parameters - ); - if (this.highlighted) { - var p0Fill = this.highlighted == "p0" ? true : false; - var p1Fill = this.highlighted == "p1" ? true : false; - this.littleCircle(context, x0, y0, p0Fill); - this.littleCircle(context, x1, y1, p1Fill); - } -}; - -CIQ.Drawing.rectangle.prototype.intersected = function (tick, value, box) { - if (!this.p0 || !this.p1) return null; // in case invalid drawing (such as from panel that no longer exists) - var pointsToCheck = { 0: this.p0, 1: this.p1 }; - for (var pt in pointsToCheck) { - if ( - this.pointIntersection(pointsToCheck[pt][0], pointsToCheck[pt][1], box) - ) { - this.highlighted = "p" + pt; - return { - action: "drag", - point: "p" + pt - }; - } - } - if (this.boxIntersection(tick, value, box)) { - this.highlighted = true; - return { - action: "move", - p0: CIQ.clone(this.p0), - p1: CIQ.clone(this.p1), - tick: tick, - value: value - }; - } - return null; -}; - -CIQ.Drawing.rectangle.prototype.configs = [ - "color", - "fillColor", - "lineWidth", - "pattern" -]; - -/** - * Reconstruct an rectangle - * @param {CIQ.ChartEngine} stx The chart object - * @param {object} [obj] A drawing descriptor - * @param {string} [obj.col] The border color - * @param {string} [obj.fc] The fill color - * @param {string} [obj.pnl] The panel name - * @param {string} [obj.ptrn] Optional pattern for line "solid","dotted","dashed". Defaults to solid. - * @param {number} [obj.lw] Optional line width. Defaults to 1. - * @param {number} [obj.v0] Value (price) for the first point - * @param {number} [obj.v1] Value (price) for the second point - * @param {number} [obj.d0] Date (string form) for the first point - * @param {number} [obj.d1] Date (string form) for the second point - * @param {number} [obj.tzo0] Offset of UTC from d0 in minutes - * @param {number} [obj.tzo1] Offset of UTC from d1 in minutes - * @memberOf CIQ.Drawing.rectangle - */ -CIQ.Drawing.rectangle.prototype.reconstruct = function (stx, obj) { - this.stx = stx; - this.color = obj.col; - this.fillColor = obj.fc; - this.panelName = obj.pnl; - this.pattern = obj.ptrn; - this.lineWidth = obj.lw; - this.d0 = obj.d0; - this.d1 = obj.d1; - this.tzo0 = obj.tzo0; - this.tzo1 = obj.tzo1; - this.v0 = obj.v0; - this.v1 = obj.v1; - this.adjust(); -}; - -CIQ.Drawing.rectangle.prototype.serialize = function () { - return { - name: this.name, - pnl: this.panelName, - col: this.color, - fc: this.fillColor, - ptrn: this.pattern, - lw: this.lineWidth, - d0: this.d0, - d1: this.d1, - tzo0: this.tzo0, - tzo1: this.tzo1, - v0: this.v0, - v1: this.v1 - }; -}; - -/** - * shape is a default implementation of a {@link CIQ.Drawing.BaseTwoPoint} drawing - * which places a "shape" on the canvas. It can be rotated and/or stretched. - * It is meant to be overridden with specific shape designs, such as arrows.... - * @constructor - * @name CIQ.Drawing.shape - * @since 2015-11-1 - * @version ChartIQ Advanced Package - */ -CIQ.Drawing.shape = function () { - this.name = "shape"; - this.radians = 0; - this.a = 0; - this.rotating = false; - this.textMeasure = false; - this.configurator = "shape"; //forces all derived classes to default to shape drawing tools - this.dimension = [0, 0]; - this.points = []; -}; - -CIQ.inheritsFrom(CIQ.Drawing.shape, CIQ.Drawing.BaseTwoPoint); - -/** - * If true, enables rotation when the drawing is initially drawn. - * - * @type boolean - * @default - * @memberof CIQ.Drawing.shape - * @since 7.4.0 - */ -CIQ.Drawing.shape.prototype.setRotationOnInitialDraw = false; - -CIQ.Drawing.shape.prototype.measure = function () {}; - -CIQ.Drawing.shape.prototype.render = function (context) { - if (!this.points.length) return; - var panel = this.stx.panels[this.panelName]; - if (!panel) return; - var x0 = this.stx.pixelFromTick(this.p0[0], panel.chart); - var y0 = this.stx.pixelFromValueAdjusted(panel, this.p0[0], this.p0[1]); - if (this.p1) { - var x1 = this.stx.pixelFromTick(this.p1[0], panel.chart); - var y1 = this.stx.pixelFromValueAdjusted(panel, this.p1[0], this.p1[1]); - - context.globalAlpha = 0.5; - context.fillStyle = "#000000"; - if (this.rotating) { - this.radians = Math.atan((y1 - y0) / (x1 - x0)); - if (x1 < x0) this.radians += Math.PI; - else if (y1 < y0) this.radians += 2 * Math.PI; - this.a = parseInt(((this.radians * 36) / Math.PI).toFixed(0), 10) * 5; - this.a %= 360; - this.radians = (this.a * Math.PI) / 180; - if (this.textMeasure) - context.fillText(this.a + "\u00b0", x1 + 10, y1 + 10); - } else if (this.penDown) { - this.sx = Math.max( - 1, - parseFloat(Math.abs((2 * (x1 - x0)) / this.dimension[0]).toFixed(1)) - ); - if (x1 < x0) this.sx *= -1; - this.sy = Math.max( - 1, - parseFloat(Math.abs((2 * (y1 - y0)) / this.dimension[1]).toFixed(1)) - ); - if (y1 < y0) this.sy *= -1; - if (this.textMeasure) - context.fillText( - this.sx + "x," + this.sy + "x", - x1 + this.sx + 5, - y1 + this.sy + 5 - ); - } - context.globalAlpha = 1; - } - if (typeof this.sx === "undefined") { - this.sx = this.sy = 1; - } - - var lineWidth = this.lineWidth; - if (!lineWidth) lineWidth = 1.1; - - var parameters = { - pattern: this.pattern, - lineWidth: lineWidth - }; - if (this.highlighted && parameters.pattern == "none") { - parameters.pattern = "solid"; - if (parameters.lineWidth == 0.1) parameters.lineWidth = 1; - } - var edgeColor = this.color; - if (edgeColor == "auto" || CIQ.isTransparent(edgeColor)) - edgeColor = this.stx.defaultColor; - if (this.highlighted) { - edgeColor = this.stx.getCanvasColor("stx_highlight_vector"); - if (lineWidth == 0.1) lineWidth = 1.1; - } - var fillColor = this.fillColor; - lineWidth /= - (Math.abs(this.sx * this.sy) * 2) / (Math.abs(this.sx) + Math.abs(this.sy)); - - context.save(); - context.translate(x0, y0); - context.rotate(this.radians); - context.scale(this.sx, panel.yAxis.flipped ? -this.sy : this.sy); - - var subshape, point; - var origin = { - x: (this.dimension[0] - 1) / 2, - y: (this.dimension[1] - 1) / 2 - }; - for (subshape = 0; subshape < this.points.length; subshape++) { - context.beginPath(); - for (point = 0; point < this.points[subshape].length; point++) { - var x, y, cx1, cx2, cy1, cy2; - if (this.points[subshape][point] == "M") { - //move - x = this.points[subshape][++point] - origin.x; - y = this.points[subshape][++point] - origin.y; - context.moveTo(x, y); - } else if (this.points[subshape][point] == "L") { - //line - x = this.points[subshape][++point] - origin.x; - y = this.points[subshape][++point] - origin.y; - context.lineTo(x, y); - } else if (this.points[subshape][point] == "Q") { - //quadratic - cx1 = this.points[subshape][++point] - origin.x; - cy1 = this.points[subshape][++point] - origin.y; - x = this.points[subshape][++point] - origin.x; - y = this.points[subshape][++point] - origin.y; - context.quadraticCurveTo(cx1, cy1, x, y); - } else if (this.points[subshape][point] == "B") { - //bezier - cx1 = this.points[subshape][++point] - origin.x; - cy1 = this.points[subshape][++point] - origin.y; - cx2 = this.points[subshape][++point] - origin.x; - cy2 = this.points[subshape][++point] - origin.y; - x = this.points[subshape][++point] - origin.x; - y = this.points[subshape][++point] - origin.y; - context.bezierCurveTo(cx1, cy1, cx2, cy2, x, y); - } - } - context.closePath(); - - if (fillColor && !CIQ.isTransparent(fillColor) && fillColor != "auto") { - //context.globalAlpha=0.4; - context.fillStyle = fillColor; - context.fill(); - //context.globalAlpha=1; - } - if (edgeColor && this.pattern != "none") { - context.strokeStyle = edgeColor; - context.lineWidth = lineWidth; - if (context.setLineDash) { - context.setLineDash(CIQ.borderPatternToArray(lineWidth, this.pattern)); - context.lineDashOffset = 0; //start point in array - } - context.stroke(); - } - } - - //context.strokeRect(-(this.dimension[0]-1)/2,-(this.dimension[1]-1)/2,this.dimension[0]-1,this.dimension[1]-1); - - context.restore(); - context.save(); - context.translate(x0, y0); - context.rotate(this.radians); - - if (this.highlighted) { - var p0Fill = this.highlighted == "p0" ? true : false; - var p1Fill = this.highlighted == "p1" ? true : false; - var p2Fill = this.highlighted == "p2" ? true : false; - this.littleCircle(context, 0, 0, p0Fill); - this.mover(context, 0, 0, p0Fill); - this.littleCircle( - context, - (this.sx * this.dimension[0]) / 2, - (this.sy * this.dimension[1]) / 2, - p1Fill - ); - this.resizer( - context, - (this.sx * this.dimension[0]) / 2, - (this.sy * this.dimension[1]) / 2, - p1Fill - ); - this.littleCircle(context, (this.sx * this.dimension[0]) / 2, 0, p2Fill); - this.rotator(context, (this.sx * this.dimension[0]) / 2, 0, p2Fill); - context.globalAlpha = 0.5; - context.fillStyle = "#000000"; - if (this.textMeasure) { - context.fillText( - this.sx + "x," + this.sy + "x", - (this.sx * this.dimension[0]) / 2 + 12, - (this.sy * this.dimension[1]) / 2 + 5 - ); - context.fillText( - this.a + "\u00b0", - (this.sx * this.dimension[0]) / 2 + 12, - 5 - ); - } - context.globalAlpha = 1; - } else if (this.penDown) { - if (this.rotating) { - this.rotator(context, (this.sx * this.dimension[0]) / 2, 0, true); - } else { - this.resizer( - context, - (this.sx * this.dimension[0]) / 2, - (this.sy * this.dimension[1]) / 2, - true - ); - } - } - context.restore(); -}; - -CIQ.Drawing.shape.prototype.reposition = function ( - context, - repositioner, - tick, - value -) { - if (!repositioner) return; - var panel = this.stx.panels[this.panelName]; - if (repositioner.action == "move") { - var tickDiff = repositioner.tick - tick; - var valueDiff = repositioner.value - value; - this.setPoint( - 0, - repositioner.p0[0] - tickDiff, - repositioner.p0[1] - valueDiff, - panel.chart - ); - this.render(context); - } else { - var x0 = this.stx.pixelFromTick(this.p0[0], panel.chart); - var y0 = this.stx.pixelFromValueAdjusted(panel, this.p0[0], this.p0[1]); - var x1 = this.stx.pixelFromTick(tick, panel.chart); - var y1 = this.stx.pixelFromValueAdjusted(panel, tick, value); - if (repositioner.action == "scale") { - this[repositioner.point] = [tick, value]; - this.sx = parseFloat( - ( - ((x1 - x0) * Math.cos(this.radians) + - (y1 - y0) * Math.sin(this.radians)) / - (this.dimension[0] / 2) - ).toFixed(1) - ); - if (Math.abs(this.sx) < 1) this.sx /= Math.abs(this.sy); - this.sy = parseFloat( - ( - ((y1 - y0) * Math.cos(this.radians) - - (x1 - x0) * Math.sin(this.radians)) / - (this.dimension[1] / 2) - ).toFixed(1) - ); - if (Math.abs(this.sy) < 1) this.sy /= Math.abs(this.sy); - this.render(context); - } else if (repositioner.action == "rotate") { - this[repositioner.point] = [tick, value]; - this.radians = Math.atan((y1 - y0) / (x1 - x0)); - if (x1 < x0) this.radians += Math.PI; - else if (y1 < y0) this.radians += 2 * Math.PI; - this.a = parseInt(((this.radians * 36) / Math.PI).toFixed(0), 10) * 5; - if (this.sx < 0) this.a = this.a + 180; - this.a %= 360; - this.radians = (this.a * Math.PI) / 180; - this.render(context); - } - } -}; - -CIQ.Drawing.shape.prototype.intersected = function (tick, value, box) { - if (!this.p0) return null; // in case invalid drawing (such as from panel that no longer exists) - if ( - this.stx.repositioningDrawing == this && - this.stx.repositioningDrawing.repositioner - ) - return this.stx.repositioningDrawing.repositioner; - - var panel = this.stx.panels[this.panelName]; - var x0 = this.stx.pixelFromTick(this.p0[0], panel.chart); - var y0 = this.stx.pixelFromValueAdjusted(panel, this.p0[0], this.p0[1]); - var x1 = this.stx.pixelFromTick(tick, panel.chart); - var y1 = this.stx.pixelFromValueAdjusted(panel, tick, value); - - x1 -= x0; - y1 -= y0; - var y1t = y1, - x1t = x1; - x1 = Math.cos(this.radians) * x1t + Math.sin(this.radians) * y1t; - y1 = Math.cos(this.radians) * y1t - Math.sin(this.radians) * x1t; - x1 /= this.sx; - y1 /= this.sy; - this.padding = CIQ.ensureDefaults(this.padding || {}, { - left: 0, - right: 0, - top: 0, - bottom: 0 - }); - var paddingX = this.padding.right + this.padding.left, - paddingY = this.padding.bottom + this.padding.top; - var circleR2 = Math.pow( - CIQ.touchDevice ? 25 : 5 + this.littleCircleRadius(), - 2 - ); - var scaledCircleR2 = Math.abs(circleR2 / (this.sx * this.sy)); - var extraPaddingToIncludeScalingControls = 3; - var overShape = - Math.pow( - (this.dimension[0] - paddingX + extraPaddingToIncludeScalingControls) / 2, - 2 - ) + - Math.pow( - (this.dimension[1] - paddingY + extraPaddingToIncludeScalingControls) / - 2, - 2 - ) > - Math.pow(x1 - paddingX / 2, 2) + Math.pow(y1 - paddingY / 2, 2); - var moveProximity = - (circleR2 - (Math.pow(x1 * this.sx, 2) + Math.pow(y1 * this.sy, 2))) / - Math.abs(this.sx * this.sy); - var scaleProximity = - scaledCircleR2 - - Math.pow(x1 - this.dimension[0] / 2, 2) - - Math.pow(y1 - this.dimension[1] / 2, 2); - var rotateProximity = - scaledCircleR2 - Math.pow(x1 - this.dimension[0] / 2, 2) - Math.pow(y1, 2); - //console.log("s:"+scaleProximity+" r:"+rotateProximity+" m:"+moveProximity); - if (overShape) { - if ( - scaleProximity >= rotateProximity && - scaleProximity >= moveProximity && - scaleProximity > -1 - ) { - this.highlighted = "p1"; - return { - action: "scale" - }; - } - if ( - rotateProximity >= scaleProximity && - rotateProximity >= moveProximity && - rotateProximity > -1 - ) { - this.highlighted = "p2"; - return { - action: "rotate" - }; - } - - this.highlighted = moveProximity > -1 ? "p0" : true; - return { - action: "move", - p0: CIQ.clone(this.p0), - tick: tick, - value: value - }; - } - return null; -}; - -CIQ.Drawing.shape.prototype.configs = [ - "color", - "fillColor", - "lineWidth", - "pattern" -]; - -CIQ.Drawing.shape.prototype.littleCircleRadius = function () { - return 3; -}; - -CIQ.Drawing.shape.prototype.click = function (context, tick, value) { - if (!this.points.length) return false; - this.copyConfig(); - var panel = this.stx.panels[this.panelName]; - if (!this.penDown) { - this.setPoint(0, tick, value, panel.chart); - this.penDown = true; - return false; - } - //if(this.accidentalClick(tick, value)) return this.dragToDraw; - - this.setPoint(1, tick, value, panel.chart); - - if (this.rotating || !this.setRotationOnInitialDraw) { - this.penDown = false; - this.rotating = false; - return true; // kernel will call render after this - } - this.rotating = true; - return false; -}; - -CIQ.Drawing.shape.prototype.adjust = function () { - var panel = this.stx.panels[this.panelName]; - if (!panel) return; - - // this section deals with backwards compatibility - var compatibilityShapeName = this.name + "_v" + (this.version || 0); - if (CIQ.Drawing[compatibilityShapeName]) { - var oldShape = new CIQ.Drawing[compatibilityShapeName](); - this.name = oldShape.name; - this.dimension = oldShape.dimension; - this.padding = oldShape.padding; - this.points = oldShape.points; - this.version = oldShape.version; - } - - this.setPoint(0, this.d0, this.v0, panel.chart); - this.radians = (Math.round(this.a / 5) * Math.PI) / 36; -}; - -/** - * Reconstruct a shape - * @param {CIQ.ChartEngine} stx The chart object - * @param {object} [obj] A drawing descriptor - * @param {string} [obj.col] The border color - * @param {string} [obj.fc] The fill color - * @param {string} [obj.pnl] The panel name - * @param {string} [obj.ptrn] Pattern for line "solid","dotted","dashed". Defaults to solid. - * @param {number} [obj.lw] Line width. Defaults to 1. - * @param {number} [obj.v0] Value (price) for the center point - * @param {number} [obj.d0] Date (string form) for the center point - * @param {number} [obj.tzo0] Offset of UTC from d0 in minutes - * @param {number} [obj.a] Angle of the rotation in degrees - * @param {number} [obj.sx] Horizontal scale factor - * @param {number} [obj.sy] Vertical scale factor - * @memberOf CIQ.Drawing.shape - */ -CIQ.Drawing.shape.prototype.reconstruct = function (stx, obj) { - this.stx = stx; - this.color = obj.col; - this.fillColor = obj.fc; - this.panelName = obj.pnl; - this.pattern = obj.ptrn; - this.lineWidth = obj.lw; - this.d0 = obj.d0; - this.v0 = obj.v0; - this.tzo0 = obj.tzo0; - this.a = obj.a; - this.sx = obj.sx; - this.sy = obj.sy; - this.version = obj.ver; - this.adjust(); -}; - -CIQ.Drawing.shape.prototype.serialize = function () { - return { - name: this.name, - pnl: this.panelName, - col: this.color, - fc: this.fillColor, - ptrn: this.pattern, - lw: this.lineWidth, - d0: this.d0, - v0: this.v0, - tzo0: this.tzo0, - a: this.a, - sx: this.sx, - sy: this.sy, - ver: this.version - }; -}; - -/* Drawing specific shapes - * - * this.dimension: overall dimension of shape as designed, as a pair [dx,dy] where dx is length and dy is width, in pixels - * this.points: array of arrays. Each array represents a closed loop subshape. - * within each array is a series of values representing coordinates. - * For example, ["M",0,0,"L",1,1,"L",2,1,"Q",3,3,4,1,"B",5,5,0,0,3,3] - * The array will be parsed by the render function: - * "M" - move to the xy coordinates represented by the next 2 array elements - * "L" - draw line to xy coordinates represented by the next 2 array elements - * "Q" - draw quadratic curve where next 2 elements are the control point and following 2 elements are the end coordinates - * "B" - draw bezier curve where next 2 elements are first control point, next 2 elements are second control point, and next 2 elements are the end coordinates - * See sample shapes below. - * - */ - -CIQ.Drawing.arrow = function () { - this.name = "arrow"; - this.version = 1; - this.dimension = [11, 22]; - this.padding = { - left: 0, - right: 0, - top: 11, - bottom: 0 - }; - this.points = [ - [ - "M", 3, 21, - "L", 7, 21, - "L", 7, 16, - "L", 10, 16, - "L", 5, 11, - "L", 0, 16, - "L", 3, 16, - "L", 3, 21 - ] - ]; // prettier-ignore -}; -CIQ.inheritsFrom(CIQ.Drawing.arrow, CIQ.Drawing.shape); - -/** - * Function to determine which drawing tools are available. - * @param {object} excludeList Exclusion list of tools in object form ( e.g. {"vertical":true,"annotation":true}) - * @returns {object} Map of tool names and types - * @memberof CIQ.Drawing - * @since 3.0.0 - */ -CIQ.Drawing.getDrawingToolList = function (excludeList) { - var map = {}; - var excludedDrawings = { - arrow_v0: true, - BaseTwoPoint: true, - fibonacci: true, - shape: true - }; - CIQ.extend(excludedDrawings, excludeList); - for (var drawing in CIQ.Drawing) { - if (!excludedDrawings[drawing] && CIQ.Drawing[drawing].prototype.render) - map[new CIQ.Drawing[drawing]().name] = drawing; - } - return map; -}; - -}; - - -let __js_standard_easeMachine_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -/** - * A simple device to make ease functions easy to use. Requests a cubic function that takes the - * form `function (t, b, c, d)`, where: - * - t = current time - * - b = starting value - * - c = change in value - * - d = duration - * - * @param {function} fc The cubic function. - * @param {number} ms Milliseconds to perform the function. - * @param {(Object.|number)} [startValues] Name/value pairs of starting values, or - * a single value. - * @param {(Object.|number)} [endValues] Name/value pairs of ending values, or a - * single value. - * - * @name CIQ.EaseMachine - * @constructor - * @example - * let e = new CIQ.EaseMachine(Math["easeInOutCubic"], 200); - * e.run(function(v){console.log(v)}, 100, 110); - */ -CIQ.EaseMachine = function (fc, ms, startValues, endValues) { - this.fc = fc; - this.ms = ms; - if (startValues || startValues === 0) { - this.reset(startValues, endValues); - } -}; - -/** - * Resets the ease machine with a new set of values. - * - * @param {(Object.|number)} startValues Name/value pairs of starting values, or a - * single value. If null, the `endValues` become the `startValues` (allowing for resetting or - * reversing of direction). - * @param {(Object.|number)} endValues Name/value pairs of ending values, or a - * single value. - * - * @memberof CIQ.EaseMachine - */ -CIQ.EaseMachine.prototype.reset = function (startValues, endValues) { - if (!startValues && startValues !== 0) startValues = this.currentValues; - this.hasCompleted = false; - this.running = false; - this.okayToRun = true; - this.useNameValuePairs = typeof endValues == "object"; - this.startTime = Date.now(); - if (this.useNameValuePairs) { - this.startValues = startValues; - this.endValues = endValues; - } else { - this.startValues = { default: startValues }; - this.endValues = { default: endValues }; - } - this.changeValues = {}; - this.currentValues = {}; - for (var n in this.startValues) { - this.changeValues[n] = this.endValues[n] - this.startValues[n]; - } -}; - -/** - * Returns the next set of values or individual value. - * - * @return {(Object.|number)} Name/value pairs of current values, or the current - * value. - * - * @memberof CIQ.EaseMachine - * @private - */ -CIQ.EaseMachine.prototype.next = function () { - var now = Date.now(); - if (now >= this.startTime + this.ms) { - now = this.startTime + this.ms; - this.hasCompleted = true; - this.running = false; - } - this.currentValues = {}; - for (var n in this.changeValues) { - this.currentValues[n] = this.fc( - now - this.startTime, - this.startValues[n], - this.changeValues[n], - this.ms - ); - } - if (!this.useNameValuePairs) return this.currentValues["default"]; - return this.currentValues; -}; - -/** - * This will be false while the ease machine is completing - * @type {boolean} - * @memberof CIQ.EaseMachine - */ -CIQ.EaseMachine.prototype.hasCompleted = true; - -/** - * Runs the ease machine in a loop until completion by calling `next()` from within a - * `requestAnimationFrame`. - * - * @param {function} fc Function callback which receives the results of - * {@link CIQ.EaseMachine#next}. - * @param {(Object.|number)} [startValues] Name/value pairs of starting values, or - * a single value. - * @param {(Object.|number)} [endValues] Name/value pairs of ending values, or a - * single value. - * @param {boolean} [delayFirstRun=false] Normally, the first pass of the run happens immediately. - * Pass true if you want to wait for the next animation frame before beginning. - * - * @memberof CIQ.EaseMachine - */ -CIQ.EaseMachine.prototype.run = function ( - fc, - startValues, - endValues, - delayFirstRun -) { - if (this.afid) cancelAnimationFrame(this.afid); - if (startValues || startValues === 0) { - this.reset(startValues, endValues); - } else if (endValues || endValues === 0) { - this.reset(this.currentValues, endValues); - } - var self = this; - function go() { - self.afid = null; - if (!self.okayToRun) return; - var result = self.next(); - fc(result); - if (self.hasCompleted) return; - self.afid = requestAnimationFrame(go); - } - this.running = true; - if (delayFirstRun) this.afid = requestAnimationFrame(go); - else go(); -}; - -/** - * Stops the ease machine from running mid-animation. Returns the current state. - * - * @return {Object.} Name/value pairs of current values, or the current value. - * - * @memberof CIQ.EaseMachine - */ -CIQ.EaseMachine.prototype.stop = function () { - if (this.afid) cancelAnimationFrame(this.afid); - this.afid = null; - this.okayToRun = false; - this.hasCompleted = true; - this.running = false; - if (typeof this.useNameValuePairs == "undefined") return {}; - if (!this.useNameValuePairs) return this.currentValues["default"]; - return this.currentValues; -}; - -if (CIQ.ChartEngine.prototype.animations.zoom.isStub) - CIQ.ChartEngine.prototype.animations.zoom = new CIQ.EaseMachine( - Math.easeOutCubic, - 400 - ); - -}; - - -let __js_standard_equations_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -//JavaScript Expression Evaluator: https://silentmatt.com/javascript-expression-evaluator/ -/*! - Based on ndef.parser, by Raphael Graf(r@undefined.ch) - http://www.undefined.ch/mparser/index.html - Ported to JavaScript and modified by Matthew Crumley (email@matthewcrumley.com, http://silentmatt.com/) - You are free to use and modify this code in anyway you find useful. Please leave this comment in the code - to acknowledge its original source. If you feel like it, I enjoy hearing about projects that use my code, - but don't feel like you have to let me know or ask permission. - */ - -var Parser = function () { - function object(o) { - function F() {} - F.prototype = o; - return new F(); - } - - var TNUMBER = 0; - var TOP1 = 1; - var TOP2 = 2; - var TVAR = 3; - var TFUNCALL = 4; - - function Token(type_, index_, prio_, number_) { - this.type_ = type_; - this.index_ = index_ || 0; - this.prio_ = prio_ || 0; - this.number_ = number_ !== undefined && number_ !== null ? number_ : 0; - this.toString = function () { - switch (this.type_) { - case TNUMBER: - return this.number_; - case TOP1: - case TOP2: - case TVAR: - return this.index_; - case TFUNCALL: - return "CALL"; - default: - return "Invalid Token"; - } - }; - } - - function Expression(tokens, ops1, ops2, functions) { - this.tokens = tokens; - this.ops1 = ops1; - this.ops2 = ops2; - this.functions = functions; - } - - // Based on http://www.json.org/json2.js - var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, - escapable = /[\\'\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, - meta = { - // table of character substitutions - "\b": "\\b", - "\t": "\\t", - "\n": "\\n", - "\f": "\\f", - "\r": "\\r", - "'": "\\'", - "\\": "\\\\" - }; - - function escapeValue(v) { - if (typeof v === "string") { - escapable.lastIndex = 0; - return escapable.test(v) - ? "'" + - v.replace(escapable, function (a) { - var c = meta[a]; - return typeof c === "string" - ? c - : "\\u" + ("0000" + a.charCodeAt(0).toString(16)).slice(-4); - }) + - "'" - : "'" + v + "'"; - } - return v; - } - - CIQ.extend( - Expression.prototype, - { - simplify: function (values) { - values = values || {}; - var nstack = []; - var newexpression = []; - var n1; - var n2; - var f; - var L = this.tokens.length; - var item; - var i = 0; - for (i = 0; i < L; i++) { - item = this.tokens[i]; - var type_ = item.type_; - if (type_ === TNUMBER) { - nstack.push(item); - } else if (type_ === TVAR && item.index_ in values) { - item = new Token(TNUMBER, 0, 0, values[item.index_]); - nstack.push(item); - } else if (type_ === TOP2 && nstack.length > 1) { - n2 = nstack.pop(); - n1 = nstack.pop(); - f = this.ops2[item.index_]; - item = new Token(TNUMBER, 0, 0, f(n1.number_, n2.number_)); - nstack.push(item); - } else if (type_ === TOP1 && nstack.length > 0) { - n1 = nstack.pop(); - f = this.ops1[item.index_]; - item = new Token(TNUMBER, 0, 0, f(n1.number_)); - nstack.push(item); - } else { - while (nstack.length > 0) { - newexpression.push(nstack.shift()); - } - newexpression.push(item); - } - } - while (nstack.length > 0) { - newexpression.push(nstack.shift()); - } - - return new Expression( - newexpression, - object(this.ops1), - object(this.ops2), - object(this.functions) - ); - }, - - substitute: function (variable, expr) { - if (!(expr instanceof Expression)) { - expr = new Parser().parse(String(expr)); - } - var newexpression = []; - var L = this.tokens.length; - var item; - var i = 0; - for (i = 0; i < L; i++) { - item = this.tokens[i]; - var type_ = item.type_; - if (type_ === TVAR && item.index_ === variable) { - for (var j = 0; j < expr.tokens.length; j++) { - var expritem = expr.tokens[j]; - var replitem = new Token( - expritem.type_, - expritem.index_, - expritem.prio_, - expritem.number_ - ); - newexpression.push(replitem); - } - } else { - newexpression.push(item); - } - } - - var ret = new Expression( - newexpression, - object(this.ops1), - object(this.ops2), - object(this.functions) - ); - return ret; - }, - - evaluate: function (values) { - values = values || {}; - var nstack = []; - var n1; - var n2; - var f; - var L = this.tokens.length; - var item; - var i = 0; - for (i = 0; i < L; i++) { - item = this.tokens[i]; - var type_ = item.type_; - if (type_ === TNUMBER) { - nstack.push(item.number_); - } else if (type_ === TOP2) { - n2 = nstack.pop(); - n1 = nstack.pop(); - f = this.ops2[item.index_]; - nstack.push(f(n1, n2)); - } else if (type_ === TVAR) { - if (item.index_ in values) { - nstack.push(values[item.index_]); - } else if (item.index_ in this.functions) { - nstack.push(this.functions[item.index_]); - } else { - throw new Error("undefined variable: " + item.index_); - } - } else if (type_ === TOP1) { - n1 = nstack.pop(); - f = this.ops1[item.index_]; - nstack.push(f(n1)); - } else if (type_ === TFUNCALL) { - n1 = nstack.pop(); - f = nstack.pop(); - if (f.apply && f.call) { - if (Object.prototype.toString.call(n1) == "[object Array]") { - nstack.push(f.apply(undefined, n1)); - } else { - nstack.push(f.call(undefined, n1)); - } - } else { - throw new Error(f + " is not a function"); - } - } else { - throw new Error("invalid Expression"); - } - } - if (nstack.length > 1) { - throw new Error("invalid Expression (parity)"); - } - return nstack[0]; - }, - - toString: function (toJS) { - var nstack = []; - var n1; - var n2; - var f; - var L = this.tokens.length; - var item; - var i = 0; - for (i = 0; i < L; i++) { - item = this.tokens[i]; - var type_ = item.type_; - if (type_ === TNUMBER) { - nstack.push(escapeValue(item.number_)); - } else if (type_ === TOP2) { - n2 = nstack.pop(); - n1 = nstack.pop(); - f = item.index_; - if (toJS && f == "^") { - nstack.push("Math.pow(" + n1 + "," + n2 + ")"); - } else { - nstack.push("(" + n1 + f + n2 + ")"); - } - } else if (type_ === TVAR) { - nstack.push(item.index_); - } else if (type_ === TOP1) { - n1 = nstack.pop(); - f = item.index_; - if (f === "-") { - nstack.push("(" + f + n1 + ")"); - } else { - nstack.push(f + "(" + n1 + ")"); - } - } else if (type_ === TFUNCALL) { - n1 = nstack.pop(); - f = nstack.pop(); - nstack.push(f + "(" + n1 + ")"); - } else { - throw new Error("invalid Expression"); - } - } - if (nstack.length > 1) { - throw new Error("invalid Expression (parity)"); - } - return nstack[0]; - }, - - variables: function () { - var L = this.tokens.length; - var vars = []; - for (var i = 0; i < L; i++) { - var item = this.tokens[i]; - if (item.type_ === TVAR && vars.indexOf(item.index_) == -1) { - vars.push(item.index_); - } - } - - return vars; - } /*, - - toJSFunction: function (param, variables) { - var f = new Function(param, "with(Parser.values) { return " + this.simplify(variables).toString(true) + "; }"); - return f; - }*/ - }, - true - ); - - function add(a, b) { - return Number(a) + Number(b); - } - function sub(a, b) { - return a - b; - } - function mul(a, b) { - return a * b; - } - function div(a, b) { - return a / b; - } - function mod(a, b) { - return a % b; - } - function concat(a, b) { - return "" + a + b; - } - function equal(a, b) { - return a == b; - } - function notEqual(a, b) { - return a != b; - } - function greaterThan(a, b) { - return a > b; - } - function lessThan(a, b) { - return a < b; - } - function greaterThanEqual(a, b) { - return a >= b; - } - function lessThanEqual(a, b) { - return a <= b; - } - function andOperator(a, b) { - return Boolean(a && b); - } - function orOperator(a, b) { - return Boolean(a || b); - } - function sinh(a) { - return Math.sinh ? Math.sinh(a) : (Math.exp(a) - Math.exp(-a)) / 2; - } - function cosh(a) { - return Math.cosh ? Math.cosh(a) : (Math.exp(a) + Math.exp(-a)) / 2; - } - function tanh(a) { - if (Math.tanh) return Math.tanh(a); - if (a === Infinity) return 1; - if (a === -Infinity) return -1; - return (Math.exp(a) - Math.exp(-a)) / (Math.exp(a) + Math.exp(-a)); - } - function asinh(a) { - if (Math.asinh) return Math.asinh(a); - if (a === -Infinity) return a; - return Math.log(a + Math.sqrt(a * a + 1)); - } - function acosh(a) { - return Math.acosh ? Math.acosh(a) : Math.log(a + Math.sqrt(a * a - 1)); - } - function atanh(a) { - return Math.atanh ? Math.atanh(a) : Math.log((1 + a) / (1 - a)) / 2; - } - function log10(a) { - return Math.log(a) * Math.LOG10E; - } - function neg(a) { - return -a; - } - function trunc(a) { - if (Math.trunc) return Math.trunc(a); - return a < 0 ? Math.ceil(a) : Math.floor(a); - } - function random(a) { - return Math.random() * (a || 1); - } - function fac(a) { - //a! - a = Math.floor(a); - var b = a; - while (a > 1) { - b = b * --a; - } - return b; - } - - function hypot() { - if (Math.hypot) return Math.hypot.apply(this, arguments); - var y = 0; - var length = arguments.length; - for (var i = 0; i < length; i++) { - if (arguments[i] === Infinity || arguments[i] === -Infinity) { - return Infinity; - } - y += arguments[i] * arguments[i]; - } - return Math.sqrt(y); - } - - function condition(cond, yep, nope) { - return cond ? yep : nope; - } - - function append(a, b) { - if (Object.prototype.toString.call(a) != "[object Array]") { - return [a, b]; - } - a = a.slice(); - a.push(b); - return a; - } - - function Parser() { - this.success = false; - this.errormsg = ""; - this.expression = ""; - - this.pos = 0; - - this.tokennumber = 0; - this.tokenprio = 0; - this.tokenindex = 0; - this.tmpprio = 0; - - this.ops1 = { - sin: Math.sin, - cos: Math.cos, - tan: Math.tan, - asin: Math.asin, - acos: Math.acos, - atan: Math.atan, - sinh: sinh, - cosh: cosh, - tanh: tanh, - asinh: asinh, - acosh: acosh, - atanh: atanh, - sqrt: Math.sqrt, - log: Math.log, - lg: log10, - log10: log10, - abs: Math.abs, - ceil: Math.ceil, - floor: Math.floor, - round: Math.round, - trunc: trunc, - "-": neg, - exp: Math.exp - }; - - this.ops2 = { - "+": add, - "-": sub, - "*": mul, - "/": div, - "%": mod, - "^": Math.pow, - ",": append, - "||": concat, - "==": equal, - "!=": notEqual, - ">": greaterThan, - "<": lessThan, - ">=": greaterThanEqual, - "<=": lessThanEqual, - and: andOperator, - or: orOperator - }; - - this.functions = { - random: random, - fac: fac, - min: Math.min, - max: Math.max, - hypot: hypot, - pyt: hypot, // backward compat - pow: Math.pow, - atan2: Math.atan2, - if: condition - }; - - this.consts = { - E: Math.E, - PI: Math.PI - }; - } - - Parser.parse = function (expr) { - return new Parser().parse(expr); - }; - - Parser.evaluate = function (expr, variables) { - return Parser.parse(expr).evaluate(variables); - }; - - Parser.Expression = Expression; - - Parser.values = { - sin: Math.sin, - cos: Math.cos, - tan: Math.tan, - asin: Math.asin, - acos: Math.acos, - atan: Math.atan, - sinh: sinh, - cosh: cosh, - tanh: tanh, - asinh: asinh, - acosh: acosh, - atanh: atanh, - sqrt: Math.sqrt, - log: Math.log, - lg: log10, - log10: log10, - abs: Math.abs, - ceil: Math.ceil, - floor: Math.floor, - round: Math.round, - trunc: trunc, - random: random, - fac: fac, - exp: Math.exp, - min: Math.min, - max: Math.max, - hypot: hypot, - pyt: hypot, // backward compat - pow: Math.pow, - atan2: Math.atan2, - if: condition, - E: Math.E, - PI: Math.PI - }; - - var PRIMARY = 1 << 0; - var OPERATOR = 1 << 1; - var FUNCTION = 1 << 2; - var LPAREN = 1 << 3; - var RPAREN = 1 << 4; - var COMMA = 1 << 5; - var SIGN = 1 << 6; - var CALL = 1 << 7; - var NULLARY_CALL = 1 << 8; - - CIQ.extend( - Parser.prototype, - { - parse: function (expr) { - this.errormsg = ""; - this.success = true; - var operstack = []; - var tokenstack = []; - this.tmpprio = 0; - var expected = PRIMARY | LPAREN | FUNCTION | SIGN; - var noperators = 0; - this.expression = expr; - this.pos = 0; - - while (this.pos < this.expression.length) { - var token; - if (this.isOperator()) { - if (this.isSign() && expected & SIGN) { - if (this.isNegativeSign()) { - this.tokenprio = 2; - this.tokenindex = "-"; - noperators++; - this.addfunc(tokenstack, operstack, TOP1); - } - expected = PRIMARY | LPAREN | FUNCTION | SIGN; - } else if (this.isComment()) { - } else { - if ((expected & OPERATOR) === 0) { - this.error_parsing(this.pos, "unexpected operator"); - } - noperators += 2; - this.addfunc(tokenstack, operstack, TOP2); - expected = PRIMARY | LPAREN | FUNCTION | SIGN; - } - } else if (this.isNumber()) { - if ((expected & PRIMARY) === 0) { - this.error_parsing(this.pos, "unexpected number"); - } - token = new Token(TNUMBER, 0, 0, this.tokennumber); - tokenstack.push(token); - - expected = OPERATOR | RPAREN | COMMA; - } else if (this.isString()) { - if ((expected & PRIMARY) === 0) { - this.error_parsing(this.pos, "unexpected string"); - } - token = new Token(TNUMBER, 0, 0, this.tokennumber); - tokenstack.push(token); - - expected = OPERATOR | RPAREN | COMMA; - } else if (this.isLeftParenth()) { - if ((expected & LPAREN) === 0) { - this.error_parsing(this.pos, 'unexpected "("'); - } - - if (expected & CALL) { - noperators += 2; - this.tokenprio = -2; - this.tokenindex = -1; - this.addfunc(tokenstack, operstack, TFUNCALL); - } - - expected = PRIMARY | LPAREN | FUNCTION | SIGN | NULLARY_CALL; - } else if (this.isRightParenth()) { - if (expected & NULLARY_CALL) { - token = new Token(TNUMBER, 0, 0, []); - tokenstack.push(token); - } else if ((expected & RPAREN) === 0) { - this.error_parsing(this.pos, 'unexpected ")"'); - } - - expected = OPERATOR | RPAREN | COMMA | LPAREN | CALL; - } else if (this.isComma()) { - if ((expected & COMMA) === 0) { - this.error_parsing(this.pos, 'unexpected ","'); - } - this.addfunc(tokenstack, operstack, TOP2); - noperators += 2; - expected = PRIMARY | LPAREN | FUNCTION | SIGN; - } else if (this.isConst()) { - if ((expected & PRIMARY) === 0) { - this.error_parsing(this.pos, "unexpected constant"); - } - var consttoken = new Token(TNUMBER, 0, 0, this.tokennumber); - tokenstack.push(consttoken); - expected = OPERATOR | RPAREN | COMMA; - } else if (this.isOp2()) { - if ((expected & FUNCTION) === 0) { - this.error_parsing(this.pos, "unexpected function"); - } - this.addfunc(tokenstack, operstack, TOP2); - noperators += 2; - expected = LPAREN; - } else if (this.isOp1()) { - if ((expected & FUNCTION) === 0) { - this.error_parsing(this.pos, "unexpected function"); - } - this.addfunc(tokenstack, operstack, TOP1); - noperators++; - expected = LPAREN; - } else if (this.isVar()) { - if ((expected & PRIMARY) === 0) { - this.error_parsing(this.pos, "unexpected variable"); - } - var vartoken = new Token(TVAR, this.tokenindex, 0, 0); - tokenstack.push(vartoken); - - expected = OPERATOR | RPAREN | COMMA | LPAREN | CALL; - } else if (this.isWhite()) { - } else { - if (this.errormsg === "") { - this.error_parsing(this.pos, "unknown character"); - } else { - this.error_parsing(this.pos, this.errormsg); - } - } - } - if (this.tmpprio < 0 || this.tmpprio >= 10) { - this.error_parsing(this.pos, 'unmatched "()"'); - } - while (operstack.length > 0) { - var tmp = operstack.pop(); - tokenstack.push(tmp); - } - if (noperators + 1 !== tokenstack.length) { - //print(noperators + 1); - //print(tokenstack); - this.error_parsing(this.pos, "parity"); - } - - return new Expression( - tokenstack, - object(this.ops1), - object(this.ops2), - object(this.functions) - ); - }, - - evaluate: function (expr, variables) { - return this.parse(expr).evaluate(variables); - }, - - error_parsing: function (column, msg) { - this.success = false; - this.errormsg = "parse error [column " + column + "]: " + msg; - this.column = column; - throw new Error(this.errormsg); - }, - - //\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\ - - addfunc: function (tokenstack, operstack, type_) { - var operator = new Token( - type_, - this.tokenindex, - this.tokenprio + this.tmpprio, - 0 - ); - while (operstack.length > 0) { - if (operator.prio_ <= operstack[operstack.length - 1].prio_) { - tokenstack.push(operstack.pop()); - } else { - break; - } - } - operstack.push(operator); - }, - - isNumber: function () { - var r = false; - var str = ""; - while (this.pos < this.expression.length) { - var code = this.expression.charCodeAt(this.pos); - if ((code >= 48 && code <= 57) || code === 46) { - str += this.expression.charAt(this.pos); - this.pos++; - this.tokennumber = parseFloat(str); - r = true; - } else { - break; - } - } - return r; - }, - - // Ported from the yajjl JSON parser at http://code.google.com/p/yajjl/ - unescape: function (v, pos) { - var buffer = []; - var escaping = false; - - for (var i = 0; i < v.length; i++) { - var c = v.charAt(i); - - if (escaping) { - switch (c) { - case "'": - buffer.push("'"); - break; - case "\\": - buffer.push("\\"); - break; - case "/": - buffer.push("/"); - break; - case "b": - buffer.push("\b"); - break; - case "f": - buffer.push("\f"); - break; - case "n": - buffer.push("\n"); - break; - case "r": - buffer.push("\r"); - break; - case "t": - buffer.push("\t"); - break; - case "u": - // interpret the following 4 characters as the hex of the unicode code point - var codePoint = parseInt(v.substring(i + 1, i + 5), 16); - buffer.push(String.fromCharCode(codePoint)); - i += 4; - break; - default: - throw this.error_parsing( - pos + i, - "Illegal escape sequence: '\\" + c + "'" - ); - } - escaping = false; - } else { - if (c == "\\") { - escaping = true; - } else { - buffer.push(c); - } - } - } - - return buffer.join(""); - }, - - isString: function () { - var r = false; - var str = ""; - var startpos = this.pos; - if ( - this.pos < this.expression.length && - this.expression.charAt(this.pos) == "'" - ) { - this.pos++; - while (this.pos < this.expression.length) { - var code = this.expression.charAt(this.pos); - if (code != "'" || str.slice(-1) == "\\") { - str += this.expression.charAt(this.pos); - this.pos++; - } else { - this.pos++; - this.tokennumber = this.unescape(str, startpos); - r = true; - break; - } - } - } - return r; - }, - - isConst: function () { - var str; - for (var i in this.consts) { - if (true) { - var L = i.length; - str = this.expression.substr(this.pos, L); - if (i === str) { - this.tokennumber = this.consts[i]; - this.pos += L; - return true; - } - } - } - return false; - }, - - isOperator: function () { - var code = this.expression.charCodeAt(this.pos); - if (code === 43) { - // + - this.tokenprio = 2; - this.tokenindex = "+"; - } else if (code === 45) { - // - - this.tokenprio = 2; - this.tokenindex = "-"; - } else if (code === 62) { - // > - if (this.expression.charCodeAt(this.pos + 1) === 61) { - this.pos++; - this.tokenprio = 1; - this.tokenindex = ">="; - } else { - this.tokenprio = 1; - this.tokenindex = ">"; - } - } else if (code === 60) { - // < - if (this.expression.charCodeAt(this.pos + 1) === 61) { - this.pos++; - this.tokenprio = 1; - this.tokenindex = "<="; - } else { - this.tokenprio = 1; - this.tokenindex = "<"; - } - } else if (code === 124) { - // | - if (this.expression.charCodeAt(this.pos + 1) === 124) { - this.pos++; - this.tokenprio = 1; - this.tokenindex = "||"; - } else { - return false; - } - } else if (code === 61) { - // = - if (this.expression.charCodeAt(this.pos + 1) === 61) { - this.pos++; - this.tokenprio = 1; - this.tokenindex = "=="; - } else { - return false; - } - } else if (code === 33) { - // ! - if (this.expression.charCodeAt(this.pos + 1) === 61) { - this.pos++; - this.tokenprio = 1; - this.tokenindex = "!="; - } else { - return false; - } - } else if (code === 97) { - // a - if ( - this.expression.charCodeAt(this.pos + 1) === 110 && - this.expression.charCodeAt(this.pos + 2) === 100 - ) { - // n && d - this.pos++; - this.pos++; - this.tokenprio = 0; - this.tokenindex = "and"; - } else { - return false; - } - } else if (code === 111) { - // o - if (this.expression.charCodeAt(this.pos + 1) === 114) { - // r - this.pos++; - this.tokenprio = 0; - this.tokenindex = "or"; - } else { - return false; - } - } else if (code === 42 || code === 8729 || code === 8226) { - // * or ∙ or • - this.tokenprio = 3; - this.tokenindex = "*"; - } else if (code === 47) { - // / - this.tokenprio = 4; - this.tokenindex = "/"; - } else if (code === 37) { - // % - this.tokenprio = 4; - this.tokenindex = "%"; - } else if (code === 94) { - // ^ - this.tokenprio = 5; - this.tokenindex = "^"; - } else { - return false; - } - this.pos++; - return true; - }, - - isSign: function () { - var code = this.expression.charCodeAt(this.pos - 1); - if (code === 45 || code === 43) { - // - - return true; - } - return false; - }, - - isPositiveSign: function () { - var code = this.expression.charCodeAt(this.pos - 1); - if (code === 43) { - // + - return true; - } - return false; - }, - - isNegativeSign: function () { - var code = this.expression.charCodeAt(this.pos - 1); - if (code === 45) { - // - - return true; - } - return false; - }, - - isLeftParenth: function () { - var code = this.expression.charCodeAt(this.pos); - if (code === 40) { - // ( - this.pos++; - this.tmpprio += 10; - return true; - } - return false; - }, - - isRightParenth: function () { - var code = this.expression.charCodeAt(this.pos); - if (code === 41) { - // ) - this.pos++; - this.tmpprio -= 10; - return true; - } - return false; - }, - - isComma: function () { - var code = this.expression.charCodeAt(this.pos); - if (code === 44) { - // , - this.pos++; - this.tokenprio = -1; - this.tokenindex = ","; - return true; - } - return false; - }, - - isWhite: function () { - var code = this.expression.charCodeAt(this.pos); - if (code === 32 || code === 9 || code === 10 || code === 13) { - this.pos++; - return true; - } - return false; - }, - - isOp1: function () { - var str = ""; - for (var i = this.pos; i < this.expression.length; i++) { - var c = this.expression.charAt(i); - if (c.toUpperCase() === c.toLowerCase()) { - if (i === this.pos || (c != "_" && (c < "0" || c > "9"))) { - break; - } - } - str += c; - } - if (str.length > 0 && str in this.ops1) { - this.tokenindex = str; - this.tokenprio = 5; - this.pos += str.length; - return true; - } - return false; - }, - - isOp2: function () { - var str = ""; - for (var i = this.pos; i < this.expression.length; i++) { - var c = this.expression.charAt(i); - if (c.toUpperCase() === c.toLowerCase()) { - if (i === this.pos || (c != "_" && (c < "0" || c > "9"))) { - break; - } - } - str += c; - } - if (str.length > 0 && str in this.ops2) { - this.tokenindex = str; - this.tokenprio = 5; - this.pos += str.length; - return true; - } - return false; - }, - - isVar: function () { - var str = ""; - for (var i = this.pos; i < this.expression.length; i++) { - var c = this.expression.charAt(i); - if (c.toUpperCase() === c.toLowerCase()) { - if (i === this.pos || (c != "_" && (c < "0" || c > "9"))) { - break; - } - } - str += c; - } - if (str.length > 0) { - this.tokenindex = str; - this.tokenprio = 4; - this.pos += str.length; - return true; - } - return false; - }, - - isComment: function () { - var code = this.expression.charCodeAt(this.pos - 1); - if (code === 47 && this.expression.charCodeAt(this.pos) === 42) { - this.pos = this.expression.indexOf("*/", this.pos) + 2; - if (this.pos === 1) { - this.pos = this.expression.length; - } - return true; - } - return false; - } - }, - true - ); - return Parser; -}; - -/** - * Computes an equation that may contain symbols and simple arithmetic operators. - * Parentheses can be used to separate portions of the equation. - * PEMDAS priority is observed. - * Symbols can be optionally contained within brackets. - * Valid examples: 3*IBM, 4+(IBM*2), (IBM-GM)/2 - * If the equation cannot be resolved an exception is thrown. - * @param {string} equation The equation to compute. - * @param {Object} map A map of symbols to data - * @return {Array} A consolidated array of equation results - * @memberOf CIQ - * @version ChartIQ Advanced Package - */ -CIQ.computeEquationChart = function (equation, map) { - equation = equation.replace(/[:]/, "/"); - var count = 0; - for (var sym in map) { - var r = new RegExp( - "\\[" + - sym - .replace(/\[/g, "\\[") - .replace(/\]/g, "\\]") - .replace(/\$/g, "\\$") - .replace(/\^/g, "\\^") - .replace(/[+\-*/%()]/g, "\\$&") + - "\\]", - "g" - ); - equation = equation.replace(r, "symbol" + count); - count++; - } - var expr = Parser().parse(equation); - var newArray = []; - var iters = {}; - var numSyms = 0, - c; - var firstIter = null; - var priceRelative = false; - var arrMap = []; - for (sym in map) { - var elem = { sym: sym, map: map[sym] }; - if (map[sym]) arrMap.unshift(elem); - else arrMap.push(elem); - } - // Need an array - cannot guarantee order of map! - for (var el = 0; el < arrMap.length; el++) { - var _ = arrMap[el]; - iters[_.sym] = { i: 0, s: _.sym }; - if (_.map) { - numSyms++; - c = _.map[0]; - } else if (numSyms == 1) { - priceRelative = _.sym; - } - if (!c.DT) c.DT = CIQ.strToDateTime(c.Date); - iters[_.sym].d = c.DT; - if (!firstIter) firstIter = iters[_.sym]; - } - var constant = numSyms === 0; - var computeHighLow = numSyms == 1 && equation.indexOf("%") == -1; - function incrementIterator(iterator) { - iterator.i++; - if (map[iterator.s]) { - if (iterator.i >= map[iterator.s].length) return 0; - c = map[iterator.s][iterator.i]; - } - if (!c.DT) c.DT = CIQ.strToDateTime(c.Date); - iterator.d = c.DT; - return 1; - } - function isAllAligned() { - var laggard = null; - var temp = null; - for (var iter in iters) { - if (!temp) temp = iters[iter]; - else if (iters[iter].d.getTime() < temp.d.getTime()) { - laggard = temp = iters[iter]; - } else if (iters[iter].d.getTime() > temp.d.getTime()) { - laggard = temp; - } - } - if (laggard) { - if (!incrementIterator(laggard)) return 0; - return -1; - } - return 1; - } - whileLoop: while (true) { - var aligned = isAllAligned(); - if (!aligned) break; - if (aligned == 1) { - var m; - if (priceRelative) { - var prElem = map[firstIter.s][firstIter.i][priceRelative]; - if (prElem && (prElem.Close || prElem.Close === 0)) - prElem = prElem.Close; - var close = expr.evaluate({ - symbol0: map[firstIter.s][firstIter.i].Close, - symbol1: prElem - }); - close = Number(close.toFixed(8)); //Math.round(close*10000)/10000; - m = { DT: firstIter.d, Close: close, Adj_Close: close }; - m[firstIter.s] = map[firstIter.s][firstIter.i].Close; - if (!isNaN(close) && close != Infinity) newArray.push(m); - } else if (constant) { - var res = expr.evaluate({}); - CIQ.alert(equation + "=" + res); - throw { name: "NoException", message: "" }; - } else { - count = 0; - var evaluators = { - Adj_Close: {}, - Close: {}, - Open: {}, - High: {}, - Low: {}, - Volume: {} - }; - for (sym in map) { - for (var e in evaluators) { - evaluators[e]["symbol" + count] = map[sym][iters[sym].i][e]; - } - count++; - } - m = { DT: firstIter.d }; - /* - variation 1 (Stockcharts.com): - m.Close/=c.Close; - m.High/=c.Close; - m.Low/=c.Close; - m.Open/=c.Close; - - variation 2 (eSignal): - m.Close/=c.Close; - m.High/=c.High; - m.Low/=c.Low; - m.Open/=c.Open; - m.High=Math.max(m.High,Math.max(m.Open,m.Close)); - m.Low=Math.min(m.Low,Math.min(m.Open,m.Close)); - */ - - m.Adj_Close = expr.evaluate(evaluators.Adj_Close); - m.Close = expr.evaluate(evaluators.Close); - m.Open = expr.evaluate(evaluators.Open); - m.Volume = expr.evaluate(evaluators.Volume); - if (isNaN(m.Volume)) m.Volume = 0; - - if (computeHighLow) { - m.High = expr.evaluate(evaluators.High); - m.Low = expr.evaluate(evaluators.Low); - } else { - m.High = Math.max(m.Open, m.Close); - m.Low = Math.min(m.Open, m.Close); - } - if (!isNaN(m.Close) && m.Close != Infinity) newArray.push(m); - - if (!isNaN(m.High)) m.High = Number(m.High.toFixed(8)); //Math.round(m.High*10000)/10000; - if (!isNaN(m.Low)) m.Low = Number(m.Low.toFixed(8)); //Math.round(m.Low*10000)/10000; - if (!isNaN(m.Open)) m.Open = Number(m.Open.toFixed(8)); //Math.round(m.Open*10000)/10000; - if (!isNaN(m.Close)) m.Close = Number(m.Close.toFixed(8)); //Math.round(m.Close*10000)/10000; - if (!isNaN(m.Adj_Close)) m.Adj_Close = Number(m.Adj_Close.toFixed(8)); - //Math.round(m.Adj_Close*10000)/10000; - else m.Adj_Close = m.Close; - } - for (sym in map) { - if (!incrementIterator(iters[sym])) break whileLoop; - } - } - } - return newArray; -}; - -}; - - -let __js_standard_i18n_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -/** - * Sets the locale for the charts. - * - * Do not call this method directly. Instead use {@link CIQ.I18N.setLocale} or {@link CIQ.I18N.localize} - * - * If set, display prices and dates will be displayed in localized format. - * The locale should be a valid [IANA locale](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl). - * For instance `de-AT` represents German as used in Austria. - * - * Localization in the library is supported through the `Intl object` which is a [W3 standard](https://www.w3.org/International/articles/language-tags/) supported by all modern browsers. - * - * Once a locale is set, `stxx.internationalizer` will be an object that will contain several Intl formatters. - * - * These are the default date and time formats: - * - stxx.internationalizer.hourMinute=new Intl.DateTimeFormat(this.locale, {hour:"numeric", minute:"numeric", hourCycle:"h23"}); - * - stxx.internationalizer.hourMinuteSecond=new Intl.DateTimeFormat(this.locale, {hour:"numeric", minute:"numeric", second:"numeric", hourCycle:"h23"}); - * - stxx.internationalizer.mdhm=new Intl.DateTimeFormat(this.locale, {year:"2-digit", month:"2-digit", day:"2-digit", hour:"2-digit", minute:"2-digit"}); - * - stxx.internationalizer.monthDay=new Intl.DateTimeFormat(this.locale, {month:"numeric", day:"numeric"}); - * - stxx.internationalizer.yearMonthDay=new Intl.DateTimeFormat(this.locale, {year:"numeric", month:"numeric", day:"numeric"}); - * - stxx.internationalizer.yearMonth=new Intl.DateTimeFormat(this.locale, {year:"numeric", month:"numeric"}); - * - stxx.internationalizer.month=new Intl.DateTimeFormat(this.locale, {month:"short"}); - * - * These can be overridden manually if the specified format is not acceptable. See example. - * Also see [Intl.DateTimeFormat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DateTimeFormat) for formatting alternatives - * - * @param {string} locale A valid [IANA locale](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl) - * @param {number} [maxDecimals] maximum number of decimal places to allow on number conversions. Defaults to 5. Please note that this will supersede any defaults set in {@link CIQ.ChartEngine.YAxis#maxDecimalPlaces} or {@link CIQ.ChartEngine.YAxis#decimalPlaces} - * @memberof CIQ.ChartEngine - * @since 3.0.0 Added `maxDecimals` parameter. - * @example - * // override time formatting to enable 12 hour clock (hour12:true) - * CIQ.I18N.setLocale(stxx, "en"); - * stxx.internationalizer.hourMinute=new Intl.DateTimeFormat(this.locale, {hour:"numeric", minute:"numeric", hour12:true}); - * stxx.internationalizer.hourMinuteSecond=new Intl.DateTimeFormat(this.locale, {hour:"numeric", minute:"numeric", second:"numeric", hour12:true}); - * @example - * // override formatting to dislay 'Sep 15' insted of '9/15' on x axis labels. - * CIQ.I18N.setLocale(stxx, "en"); - * stxx.internationalizer.monthDay=new Intl.DateTimeFormat(this.locale, {month:"short", day:"numeric"}); - * @private - */ -CIQ.ChartEngine.prototype.setLocale = function (locale, maxDecimals) { - if (typeof Intl == "undefined") return; - if (this.locale != locale) { - this.locale = locale; - } else { - return; - } - var i, - internationalizer = (this.internationalizer = {}); - internationalizer.hourMinute = new Intl.DateTimeFormat(this.locale, { - hour: "numeric", - minute: "numeric", - hourCycle: "h23" - }); - internationalizer.hourMinuteSecond = new Intl.DateTimeFormat(this.locale, { - hour: "numeric", - minute: "numeric", - second: "numeric", - hourCycle: "h23" - }); - internationalizer.mdhm = new Intl.DateTimeFormat(this.locale, { - year: "2-digit", - month: "2-digit", - day: "2-digit", - hour: "2-digit", - minute: "2-digit" - }); - internationalizer.monthDay = new Intl.DateTimeFormat(this.locale, { - month: "numeric", - day: "numeric" - }); - internationalizer.yearMonthDay = new Intl.DateTimeFormat(this.locale, { - year: "numeric", - month: "numeric", - day: "numeric" - }); - internationalizer.yearMonth = new Intl.DateTimeFormat(this.locale, { - year: "numeric", - month: "numeric" - }); - internationalizer.month = new Intl.DateTimeFormat(this.locale, { - month: "short" - }); - internationalizer.numbers = new Intl.NumberFormat(this.locale); - internationalizer.priceFormatters = []; - if (!maxDecimals) maxDecimals = 8; - for (i = 0; i < maxDecimals + 1; i++) { - internationalizer.priceFormatters.push( - new Intl.NumberFormat(this.locale, { - maximumFractionDigits: i, - minimumFractionDigits: i - }) - ); - } - // minification efficient generation of... - // internationalizer.percent=new Intl.NumberFormat(this.locale, {style:"percent", minimumFractionDigits:2, maximumFractionDigits:2}) - // internationalizer.percent1=new Intl.NumberFormat(this.locale, {style:"percent", minimumFractionDigits:1, maximumFractionDigits:1}) - // ... - for (i = 0; i < 5; i++) { - var c = i, - j = i; - if (!i) { - c = ""; - j = 2; - } - internationalizer["percent" + c] = new Intl.NumberFormat(this.locale, { - style: "percent", - minimumFractionDigits: j, - maximumFractionDigits: j - }); - } - - if (CIQ.I18N.createMonthArrays) - CIQ.I18N.createMonthArrays(this, internationalizer.month, this.locale); -}; - -/** - * Namespace for Internationalization API. - * See {@tutorial Localization} for more details. - * @namespace - * @name CIQ.I18N - */ - -CIQ.I18N = function () {}; - -// Hack code to make a multi line string easy cut & paste from a spreadsheet -CIQ.I18N.hereDoc = function (f) { - return f - .toString() - .replace(/^[^/]+\/\*!?/, "") - .replace(/\*\/[^/]+$/, ""); -}; - -/** - * Must be set to the desired language. Defaults to english "en" - * @memberOf CIQ.I18N - * @type {string} - */ -CIQ.I18N.language = "en"; - -/** - * Sets the languages that that don't support shortening - * Translation will print entire month from locale for these languages - * @memberOf CIQ.I18N - * @type {Object} - */ -CIQ.I18N.longMonths = { zh: true }; - -/** - * Maintains the list of locales used by {@link CIQ.I18N.localize} to decide if the up/down colors should be reversed and can be updated as outlined on the example. - * - * Defaults to : {"zh":true,"ja":true}; - * @type {Object} - * @memberOf CIQ.I18N - * @since 4.0.0 - * @example - * CIQ.I18N.reverseColorsByLocale={ - * "zh":true, - * "ja":true, - * "fr":true, - * "de":true, - * "hu":true, - * "it":true, - * "pt":true - * }; - */ -CIQ.I18N.reverseColorsByLocale = { zh: true, ja: true }; - -/** Returns a word list containing unique words. Each word references an array of DOM - * nodes that contain that word. This can then be used for translation. - * Text nodes and placeholders which are found in the document tree will be wrapped by this function - * within a tag for easy translation back and forth. - * @param {HTMLElement} [root] root for the TreeWalker. If omitted, document.body assumed. - * @return {object} A word list containing unique words. - * @memberOf CIQ.I18N - */ -CIQ.I18N.findAllTextNodes = function (root) { - if (!root) root = document.body; - // Get all the words from the placeholders - // We'll create text nodes for them and stash them in a hidden div so we can access them in the future - if (root == document.body) { - if (!document.querySelector(".ciq_stashed_texts")) { - var stashedTextNodes = document.createElement("div"); - stashedTextNodes.className = "ciq_stashed_texts"; - stashedTextNodes.style.display = "none"; - root.appendChild(stashedTextNodes); - - var fields = document.querySelectorAll( - "input,textarea,.editable_content" - ); - for (var f = 0; f < fields.length; f++) { - var placeHolder = fields[f].getAttribute("placeholder"); - if (placeHolder) { - var wrapper = stashedTextNodes.appendChild( - document.createElement("translate") - ); - wrapper.setAttribute("original", placeHolder); - wrapper.placeholderFor = fields[f]; - wrapper.appendChild(document.createTextNode(placeHolder)); - } - } - } - } - - var walker = document.createTreeWalker( - root, - NodeFilter.SHOW_TEXT, - null, - false - ); - - var node = walker.nextNode(); - var ws = new RegExp("^\\s*$"); - var line = new RegExp("\n|\t|\f", "g"); - var wordList = {}; - var dontTranslate = { - SCRIPT: true, - STYLE: true, - TEXTAREA: true - }; - - while (node) { - var key = node.nodeValue; - if (!ws.test(key)) { - var parentNode = node.parentNode; - var nextSibling = node.nextSibling; - var parentTag = parentNode.tagName; - if (!dontTranslate[parentTag]) { - if (parentTag != "TRANSLATE") { - var wrapper2 = document.createElement("translate"); - wrapper2.setAttribute("original", key); //must use an attribute so it will clone - wrapper2.appendChild(node); - parentNode.insertBefore(wrapper2, nextSibling); - } else { - key = parentNode.getAttribute("original"); - } - if (line.test(key)) key = key.replace(line, ""); // strips out new lines in text - if (!wordList[key]) wordList[key] = []; - wordList[key].push(node); - } - } - node = walker.nextNode(); - } - if (root == document.body) { - // For missing word list collation only: - // Get all the words from the study library that are used to populate the study dialogs. - // These will have an empty array since they aren't associated with any nodes - var studyLibrary = CIQ.Studies ? CIQ.Studies.studyLibrary : null; - if (studyLibrary) { - for (var study in studyLibrary) { - if (wordList[study] === null) wordList[study] = []; - var s = studyLibrary[study]; - if (s.inputs) { - for (var input in s.inputs) { - if (!wordList[input]) wordList[input] = []; - } - } - if (s.outputs) { - for (var output in s.outputs) { - if (!wordList[output]) wordList[output] = []; - } - } - } - } - } - return wordList; -}; - -/** - * CIQ.I18N.missingWordList will scan the UI by walking all the text elements. It will determine which - * text elements have not been translated for the given language and return those as a JSON object. - * @param {string} [language] The language to search for missing words. Defaults to whatever language CIQ.I18N.language has set. - * @return {object} Words that are undefined with values set to empty strings - * @memberOf CIQ.I18N - * @since 4.0.0 Iterates over the studyLibrary entry name, inputs, and outputs. - */ -CIQ.I18N.missingWordList = function (language) { - if (!language) language = CIQ.I18N.language; - var wordsInUI = CIQ.I18N.findAllTextNodes(); - var missingWords = {}; - var languageWordList = CIQ.I18N.wordLists[language]; - if (!languageWordList) languageWordList = {}; - - var addIfMissing = function (x) { - if (typeof languageWordList[x] == "undefined") { - missingWords[x] = ""; - } - }; - - for (var word in wordsInUI) { - addIfMissing(word); - } - - if (!(CIQ.Studies && CIQ.Studies.studyLibrary)) { - return missingWords; - } - - var study; - var value; - - for (var id in CIQ.Studies.studyLibrary) { - study = CIQ.Studies.studyLibrary[id]; - - addIfMissing(study.name); - - for (var input in study.inputs) { - addIfMissing(input); - value = study.inputs[input]; - - switch (Object.prototype.toString.call(value)) { - case "[object String]": - addIfMissing(value); - break; - case "[object Array]": - for (var i = 0; i < value.length; ++i) { - addIfMissing(value[i]); - } - break; - } - } - - for (var output in study.outputs) { - addIfMissing(output); - } - } - - // study parameter fields - addIfMissing("Show Zones"); - addIfMissing("OverBought"); - addIfMissing("OverSold"); - addIfMissing("Panel"); - addIfMissing("Show as Underlay"); - addIfMissing("Y-Axis"); - addIfMissing("Invert Y-Axis"); - - return missingWords; -}; - -/** - * A convenient function for creating a human readable JSON object suitable for delivery to a translator. - * @param {string} [language] language. Defaults to CIQ.I18N.language. - * @return {string} String of missing words. - * @memberOf CIQ.I18N - */ -CIQ.I18N.printableMissingWordList = function (language) { - var missingWords = JSON.stringify(CIQ.I18N.missingWordList(language)); - missingWords = missingWords.replace(/","/g, '",\n"'); - return missingWords; -}; - -/** - * Passes through the UI (DOM elements) and translates all of the text for the given language. - * - * It is important to note that if you are dynamically creating UI content and adding it to the DOM after you have set the language, - * you must either call this function again after the new content is added, - * or ensure your code explicitly translates the new content using {@link CIQ.translatableTextNode} or {@link CIQ.ChartEngine#translateIf}. - * - * @param {string} [language] language. Defaults to CIQ.I18N.language. - * @param {HTMLElement} [root] root for the TreeWalker to prevent the entire page from being translated. If omitted, document.body assumed. - * @memberOf CIQ.I18N - * @since 4.0.0 Language code for Portuguese is "pt" (formerly "pu"; maintained for backwards compatibility). - */ -CIQ.I18N.translateUI = function (language, root) { - if (language == "pu") language = "pt"; // backward compatibility. - if (!CIQ.I18N.wordLists) return; - if (!language) language = CIQ.I18N.language; - var wordsInUI = CIQ.I18N.findAllTextNodes(root); - var languageWordList = CIQ.I18N.wordLists[language]; - if (!languageWordList) return; - - for (var word in wordsInUI) { - var translation = CIQ.I18N.translateSections(word, languageWordList); - var nodes = wordsInUI[word]; - for (var i = 0; i < nodes.length; i++) { - var node = nodes[i], - parentNode = node.parentNode, - originalText = parentNode.getAttribute("original"); - // Two scenarios where we don't want to use translation, when undefined or word is not in the translation files - if (translation === "," || !translation) translation = originalText; - var elemWithPlaceholder = parentNode.placeholderFor; - if (elemWithPlaceholder) { - elemWithPlaceholder.placeholder = translation; - } else { - node.data = translation; - } - } - } -}; - -/** - * Translates an individual word for a given language. Set stxx.translationCallback to this function - * in order to automatically translate all textual elements on the chart itself. - * @param {string} word The word to translate - * @param {string} [language] language. Defaults to CIQ.I18N.language. - * @return {string} Translation of the given word, or the word itself if no translation was found. - * @memberOf CIQ.I18N - */ -CIQ.I18N.translate = function (word, language) { - if (!language) language = CIQ.I18N.language; - if (!CIQ.I18N.wordLists) { - console.log( - "Must include translations.js in order to use CIQ.I18N.translate()" - ); - return word; - } - var languageWordList = CIQ.I18N.wordLists[language]; - var translation = null; - if (languageWordList) - translation = CIQ.I18N.translateSections(word, languageWordList) || word; - // Lastly check and see if the translation is blank in the CSV source (no translation for given language) which is parsed as ',' and if so fall back to English default - return translation === "," ? word : translation; -}; - -/** - * Translates a phrase which may have untranslatable parts (like a study id). - * The translatable pieces are delimited left and right with a non-printable character Zero-Width-Non_Joiner. - * @param {string} word The word to translate - * @param {object} [languageWordList] Map of words and translations in the desired language - * @return {string} Translation of the given phrase - * @memberOf CIQ.I18N - * @since 4.0.0 - */ -CIQ.I18N.translateSections = function (word, languageWordList) { - // Test here for word phrases, delimited by the zero-width-non-breaking character - // we'll split the text into pieces, filtering out the parentheses and commas to generate phrases - var zwnb = "\u200c"; // https://en.wikipedia.org/wiki/Zero-width_non-joiner - if (typeof word == "string" && word.indexOf(zwnb) != -1) { - word = word.replace(/([(),])/g, zwnb + "$1" + zwnb); - var sections = word.split(zwnb); - sections.forEach(function (val, i, arr) { - var padding = val.match(/^(\s*).*\S(\s*)$/); - var translation = languageWordList[val.trim()]; - if (translation) { - if (padding) translation = padding[1] + translation + padding[2]; - arr[i] = translation; - } - }); - return sections.join(""); - } - return languageWordList[word]; -}; - -/** - * Converts a 'CSV formatted' string of translations into the required JSON format and set to {@link CIQ.I18N.wordLists} - * You can output {@link CIQ.I18N.wordLists} to the console and paste back in if desired. - * @param {string} [csv] Translation spreadsheet in csv format **as a single long string**. - * Make sure there are no leading tabs, trailing commas or spaces. - * Assumes that the header row of the CSV is the language codes and that the first column is the key language (English). - * Assumes non-quoted words, data is comma delimited and lines separated by '\n'. Default is CIQ.I18N.csv - * @memberOf CIQ.I18N - * @example - var csv="en,ar,fr,de,hu,it,pt,ru,es,zh,ja\nChart,الرسم البياني,Graphique,Darstellung,Diagram,Grafico,Gráfico,График,Gráfica,图表,チャート\nChart Style,أسلوب الرسم البياني,Style de graphique,Darstellungsstil,Diagram stílusa,Stile grafico,Estilo do gráfico,Тип графика,Estilo de gráfica,图表类型,チャート形式\nCandle,الشموع,Bougie,Kerze,Gyertya,Candela,Vela,Свеча,Vela,蜡烛,ローソク足\nShape,شكل,Forme,Form,Alak,Forma,Forma,Форма,Forma,形状,パターン"; - CIQ.I18N.convertCSV(csv); - */ -CIQ.I18N.convertCSV = function (csv) { - var curly = new RegExp("[\u201C\u201D]|[\u2018\u2019]", "g"); - var quotation = new RegExp('^(")|(")$', "g"); - var wordLists = CIQ.I18N.wordLists; - if (!csv) csv = CIQ.I18N.csv; - if (!csv) return; - var lines = csv.split("\n"); - var headerRow = lines[0]; - var languages = headerRow.split(","); - for (var j = 0; j < languages.length; j++) { - var lang = languages[j]; - if (!wordLists[lang]) { - wordLists[lang] = {}; - } - } - for (var i = 1; i < lines.length; i++) { - var words = lines[i].match(/(".*?"|[^",]+)(?=\s*,|\s*$)|(,(?=,))/g) || []; - var key = words[0]; - if (quotation.test(key)) key = key.replace(quotation, ""); - if (curly.test(key)) key = key.replace(curly, '"'); - for (var k = 1; k < words.length; k++) { - var word = words[k]; - if (quotation.test(word)) word = word.replace(quotation, ""); - wordLists[languages[k]][key] = word; - } - } -}; - -/** - * Convenience function to set up translation services for a chart and its surrounding GUI. - * Automatically sets {@link CIQ.I18N.language}, loads all translations, and translates the chart. - * - * Uses/sets (in execution order): - * - {@link CIQ.I18N.convertCSV} - * - {@link CIQ.I18N.language} - * - {@link CIQ.I18N.translateUI} - * - {@link CIQ.I18N.translate} - * - * Feel free to create your own convenience function if required to explicitly set - * {@link CIQ.I18N.wordLists} instead of using the `CIQ.I18N.hereDoc` copy/paste spreadsheet in - * *translationSample.js*. - * - * It is important to note that if you are dynamically creating UI content and adding it to the - * DOM after you have set the language, you must either call {@link CIQ.I18N.translateUI} after - * the new content is added, or ensure your code explicitly translates the new content using - * {@link CIQ.translatableTextNode} or {@link CIQ.ChartEngine#translateIf}. - * - * @param {CIQ.ChartEngine} stx A chart object. - * @param {string} language A language in your csv file. For instance "en" from - * `CIQ.I18N.csv` in *translationSample.js*. - * @param {string} [translationCallback] Function to perform canvas built-in word translations. - * Default is {@link CIQ.I18N.translate}. - * @param {string} [csv] Translation spreadsheet in csv format **as a single long string**. Make - * sure the string contains no leading tabs, trailing commas, or spaces. Default is - * `CIQ.I18N.csv` in *translationSample.js*. See {@link CIQ.I18N.convertCSV} for a format - * sample. - * @param {HTMLElement} [root] Root element from which to start translating. If the parameter is - * omitted, the chart UI context is checked for its top node before defaulting to - * `document.body`. - * - * @memberOf CIQ.I18N - * @since - * - 04-2015 - * - 3.0.0 Added `root` parameter. - * - 4.0.0 Language code for Portuguese is "pt" (formerly "pu"; maintained for backwards - * compatibility). - * - 8.2.0 If no `root` parameter, the chart UI context is checked for its top node before - * defaulting to `document.body`. - */ -CIQ.I18N.setLanguage = function ( - stx, - language, - translationCallback, - csv, - root -) { - if (!root) root = (stx.uiContext || {}).topNode || document.body; - if (language == "pu") language = "pt"; // backward compatibility. - CIQ.I18N.convertCSV(csv); - CIQ.I18N.language = language; - CIQ.I18N.translateUI(language, root); - if (!translationCallback) translationCallback = CIQ.I18N.translate; - stx.translationCallback = translationCallback; -}; - -/** - * This method will set the chart locale and check to see if candle colors should be reversed. - * - * If set, display prices and dates will be displayed in localized format. - * The locale should be a valid [IANA locale](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl). - * For instance `de-AT` represents German as used in Austria. - * - * {@link CIQ.I18N.reverseColorsByLocale} is used to determine if the candle colors should be reversed. - * - * Localization in the library is supported through the `Intl object` which is a [W3 standard](https://www.w3.org/International/articles/language-tags/) supported by all modern browsers. - * - * Once a locale is set, `stxx.internationalizer` will be an object that will contain several Intl formatters. - * - * These are the default date and time formats: - * - stxx.internationalizer.hourMinute=new Intl.DateTimeFormat(this.locale, {hour:"numeric", minute:"numeric", hourCycle:"h23"}); - * - stxx.internationalizer.hourMinuteSecond=new Intl.DateTimeFormat(this.locale, {hour:"numeric", minute:"numeric", second:"numeric", hourCycle:"h23"}); - * - stxx.internationalizer.mdhm=new Intl.DateTimeFormat(this.locale, {year:"2-digit", month:"2-digit", day:"2-digit", hour:"2-digit", minute:"2-digit"}); - * - stxx.internationalizer.monthDay=new Intl.DateTimeFormat(this.locale, {month:"numeric", day:"numeric"}); - * - stxx.internationalizer.yearMonthDay=new Intl.DateTimeFormat(this.locale, {year:"numeric", month:"numeric", day:"numeric"}); - * - stxx.internationalizer.yearMonth=new Intl.DateTimeFormat(this.locale, {year:"numeric", month:"numeric"}); - * - stxx.internationalizer.month=new Intl.DateTimeFormat(this.locale, {month:"short"}); - * - * These can be overridden manually if the specified format is not acceptable. See example. - * Also see [Intl.DateTimeFormat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DateTimeFormat) for formatting alternatives - * - * @param {CIQ.ChartEngine} stx A chart object - * @param {string} locale A valid [IANA locale](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl), for instance en-IN - * @param {Function} [cb] Callback when locale has been loaded. This function will be passed an error message if it cannot be loaded. - * @param {string} [url] url where to fetch the locale data. Defaults to "locale-data/jsonp". Only used if not natively supported by the browser. - * @param {number} [maxDecimals] maximum number of decimal places to allow on number conversions. Defaults to 5. See {@link CIQ.ChartEngine#setLocale} for more details. - * @since 3.0.0 Added `maxDecimals` parameter. - * @memberOf CIQ.I18N - * @example - * CIQ.I18N.setLocale(stxx, "zh"); // set localization services -- before any UI or chart initialization is done - * // override time formatting to enable 12 hour clock (hour12:true) - * stxx.internationalizer.hourMinute=new Intl.DateTimeFormat(this.locale, {hour:"numeric", minute:"numeric", hour12:true}); - * stxx.internationalizer.hourMinuteSecond=new Intl.DateTimeFormat(this.locale, {hour:"numeric", minute:"numeric", second:"numeric", hour12:true}); - */ -CIQ.I18N.setLocale = function (stx, locale, cb, url, maxDecimals) { - // checks to see if we're switching from a locale with reversed candles - if ( - CIQ.xor( - this.reverseColorsByLocale[locale], - this.reverseColorsByLocale[stx.locale] - ) - ) { - this.reverseCandles(stx); - } - - if (typeof Intl == "undefined" || !Intl.__addLocaleData) { - // Intl built into browser - stx.setLocale(locale, maxDecimals); - if (cb) cb(null); - return; - } - url = typeof url == "undefined" ? "locale-data/jsonp" : url; - var localeFileURL = url + "/" + locale + ".js"; - var script = document.createElement("SCRIPT"); - script.async = true; - script.src = localeFileURL; - var s = document.getElementsByTagName("script")[0]; - s.parentNode.insertBefore(script, s.nextSibling); - script.onload = function () { - stx.setLocale(locale, maxDecimals); - if (cb) cb(null); - }; - script.onerror = function () { - if (cb) cb("cannot load script"); - }; -}; - -/** - * Extract the name of the month from the locale. We do this by creating a - * localized date for the first date of each month. Then we extract the alphabetic characters. - * MonthLetters then becomes the first letter of the month. The arrays are stored in stx.monthAbv and stx.monthLetters which - * will then override the global arrays CIQ.monthAbv and CIQ.monthLetters. - * @param {CIQ.ChartEngine} stx Chart object - * @param {object} formatter An Intl compatible date formatter - * @param {string} locale A valid Intl locale, such as en-IN - * @memberOf CIQ.I18N - */ -CIQ.I18N.createMonthArrays = function (stx, formatter, locale) { - stx.monthAbv = []; - stx.monthLetters = []; - var dt = new Date(); - var shortenMonth = true; - if (CIQ.I18N.longMonths && CIQ.I18N.longMonths[locale]) shortenMonth = false; - for (var i = 0; i < 12; i++) { - dt.setDate(1); - dt.setMonth(i); - var str = formatter.format(dt); - if (shortenMonth) { - var month = ""; - for (var j = 0; j < str.length; j++) { - var c = str.charAt(j); - var cc = c.charCodeAt(0); - if (cc < 65) continue; - month += c; - } - stx.monthAbv[i] = month; - stx.monthLetters[i] = month[0]; - } else { - stx.monthAbv[i] = str; - stx.monthLetters[i] = str; - } - } -}; - -/** - * A convenience function that sets locale and language at once. Each of these grouped functions are called with default arguments. - * If you require custom parameters you will need to call each separately. - * - * It is important to note that if you are dynamically creating UI content and adding it to the DOM after you have set the language, - * you must either call {@link CIQ.I18N.translateUI} after the new content is added, - * or ensure your code explicitly translates the new content using {@link CIQ.translatableTextNode} or {@link CIQ.ChartEngine#translateIf}. - * - * Functions are called in the following order: - * - {@link CIQ.I18N.setLocale} - * - {@link CIQ.I18N.setLanguage} - * - {@link CIQ.I18N.reverseCandles} - Called only if colors need to be reversed. - * - * @param {CIQ.ChartEngine} stx Chart object - * @param {string} locale A valid Intl locale, such as en-IN - * @memberOf CIQ.I18N - * @since 4.0.0 - * @example - * CIQ.I18N.localize(stxx, "zh"); // set translation and localization services -- before any UI or chart initialization is done - * // override time formatting to enable 12 hour clock (hour12:true) - * stxx.internationalizer.hourMinute=new Intl.DateTimeFormat(this.locale, {hour:"numeric", minute:"numeric", hour12:true}); - * stxx.internationalizer.hourMinuteSecond=new Intl.DateTimeFormat(this.locale, {hour:"numeric", minute:"numeric", second:"numeric", hour12:true}); - - */ -CIQ.I18N.localize = function (stx, locale) { - this.setLocale(stx, locale); - this.setLanguage(stx, locale); -}; - -/** - * Some locales prefer candle colors reversed. This will reverse candle colors without changing CSS. - * @param {CIQ.ChartEngine} stx Chart object - * @memberOf CIQ.I18N - * @since 4.0.0 - */ -CIQ.I18N.reverseCandles = function (stx) { - var styles = stx.styles; - var candleDown = stx.cloneStyle(styles.stx_candle_down); - var candleUp = stx.cloneStyle(styles.stx_candle_up); - styles.stx_candle_up = candleDown; - styles.stx_candle_down = candleUp; -}; - -/** - * This object will be created by {@link CIQ.I18N.convertCSV} based on the provided 'CSV formatted' string, - * or you can set it explicitly if not using {@link CIQ.I18N.setLanguage} or {@link CIQ.I18N.convertCSV} - * @memberOf CIQ.I18N - * @type {Object} - * @example - * // sample of object with translations for Arabic and Spanish - * ( when setting explicitly without using CIQ.I18N.setLanguage or CIQ.I18N.convertCSV ) - * CIQ.I18N.wordLists={ - * "ar":{ - * "1 D": "1ي", - * "1 Hour": "1 ساعة", - * "1 Min": "1د", - * "1 Mo": "1ش", - * "1 W": "أ1", - * "1 hour": "ساعة واحدة", - * "1d": "1يوم", - * "1m": "1شهر", - * "1y": "1عام", - * "3m": "3أشهر" - * }, - * "es":{ - * "1 D": "1 D", - * "1 Hour": "1 Hora", - * "1 Min": "1 Min", - * "1 Mo": "1 Mes", - * "1 W": "1 S", - * "1 hour": "1 hora", - * "1d": "1d", - * "1m": "1m", - * "1y": "1a", - * "3m": "3m" - * } - * } - */ -CIQ.I18N.wordLists = { - en: {} -}; - -/** - * This maps country codes to the actual name of the language *in that language*. This can be used - * to drive UI, such as a language picker. - * The following languages are predefined: - * "en":"English", - * The following additional languages are supported in the translationSample.js sample translations file: - * "ar":"عربى", - * "fr":"Français", - * "de":"Deutsche", - * "hu":"Magyar", - * "it":"Italiano", - * "pt":"Português", - * "ru":"русский", - * "es":"Español", - * "zh":"中文", - * "ja":"日本語" - * You may add additional language as follows: - * CIQ.I18N.languages.ko="한국어"; - * You may also remove unsupported languages by deleting them from the object, or redefining this object with the languages you prefer to support. - * @type {Object} - */ -CIQ.I18N.languages = { - en: "English" -}; - -}; - - -let __js_standard_interaction_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -/** - * Contains information about the latest set of pointer events on the chart. - * - * Events are pushed into `down` or `up` from pointer or mouse up or down events. The 0 index is - * always the current up/down event. The 1 index is always the previous up/down event. - * - * @member CIQ.ChartEngine - * @type {object} - * @private - * @since 8.0.0 - */ -CIQ.ChartEngine.prototype.pointerEvents = { - /** - * Holds information about the previous and current down events. - * @property {array} - */ - down: [], - /** - * Holds information about the previous and current up events. - * @property {array} - */ - up: [] -}; - -/** - * If true when the chart initially is rendered, then the CIQ.ChartEngine object will register to listen and manage touch and mouse browser events within then canvas by attaching them to the container div. - * - * Set to false, and all interactivity with the chart will cease; turning it into a static display and 'shedding' all HTML overlays and events required for user interaction, for a much more lightweight interface. - * Alternatively you can selectively set any {@link CIQ.ChartEngine.htmlControls} id to null, including `CIQ.ChartEngine.htmlControls=null` to disable them all. - * - * See the {@tutorial Creating Static Charts} tutorial for more details. - * - * It is possible to re-enable the events after the chart has been rendered, but you must call stx.initializeChart(); stx.draw(); to register the events once again. - * @type boolean - * @default - * @alias manageTouchAndMouse - * @memberof CIQ.ChartEngine.prototype - * @example - * // if enabling events after the chart was already rendered, you must reinitialize to re register the browser events. - * stxx.manageTouchAndMouse = true; - * stxx.initializeChart(); - * stxx.draw(); - */ -CIQ.ChartEngine.prototype.manageTouchAndMouse = true; - -/** - * Registers touch and mouse events for the chart (for dragging, clicking, zooming). The events are registered on the container div (not the canvas). - * Set {@link CIQ.ChartEngine#manageTouchAndMouse} to false to disable the built in event handling (events will not be registered with the container). - * @memberof CIQ.ChartEngine - */ -CIQ.ChartEngine.prototype.registerTouchAndMouseEvents = function () { - if (this.touchAndMouseEventsRegistered) return; - this.touchAndMouseEventsRegistered = true; - var source = this.controls.chartControls || document; - var zoomInEl = source.querySelector(".stx-zoom-in"); - var zoomOutEl = source.querySelector(".stx-zoom-out"); - var containerElement = this.chart.container; - var self = this; - var addListener = function (event, listener, options) { - function uberListener(args) { - if (self.mainSeriesRenderer && self.mainSeriesRenderer.nonInteractive) - return; - listener(args); - } - self.addDomEventListener(containerElement, event, uberListener, options); - }; - if (!CIQ.touchDevice) { - addListener("mousemove", function (e) { - self.mousemove(e); - }); - addListener("mouseenter", function (e) { - self.mousemove(e); - }); - addListener("mousedown", function (e) { - self.mousedown(e); - }); - addListener("mouseup", function (e) { - self.mouseup(e); - }); - } else { - if (CIQ.isSurface) { - addListener("mousemove", function (e) { - self.msMouseMoveProxy(e); - }); - addListener("mouseenter", function (e) { - self.msMouseMoveProxy(e); - }); - addListener("mousedown", function (e) { - self.msMouseDownProxy(e); - }); - addListener("mouseup", function (e) { - self.msMouseUpProxy(e); - }); - - addListener("pointerdown", function (e) { - return self.startProxy(e); - }); - addListener("pointermove", function (e) { - self.moveProxy(e); - }); - addListener("pointerenter", function (e) { - return self.moveProxy(e); - }); - addListener("pointerup", function (e) { - return self.endProxy(e); - }); - } else { - // We need mouse events for all-in-one computers that accept both mouse and touch commands - // Actually, only for Firefox and Chrome browsers. IE10 sends pointers which are managed by the isSurface section - if (!CIQ.isMobile) { - addListener("mousemove", function (e) { - self.iosMouseMoveProxy(e); - }); - addListener("mouseenter", function (e) { - self.iosMouseMoveProxy(e); - }); - addListener("mousedown", function (e) { - self.iosMouseDownProxy(e); - }); - addListener("mouseup", function (e) { - self.iosMouseUpProxy(e); - }); - } - - addListener("touchstart", function (e) { - self.touchstart(e); - }); - addListener("touchmove", function (e) { - self.touchmove(e); - }); - addListener("touchend", function (e) { - self.touchend(e); - }); - - // capture a "pen" device, so we can treat it as a mouse - addListener("pointerdown", function (e) { - self.touchPointerType = e.pointerType; - }); - - if (zoomInEl) { - zoomInEl.removeAttribute("onMouseOver"); - zoomInEl.removeAttribute("onMouseOut"); - } - if (zoomOutEl) { - zoomOutEl.removeAttribute("onMouseOver"); - zoomOutEl.removeAttribute("onMouseOut"); - } - } - } - - var wheelEvent = CIQ.wheelEvent; - - if (this.captureMouseWheelEvents) { - addListener( - wheelEvent, - function (e) { - self.mouseWheel(e); - }, - { passive: false } - ); - } -}; - -/** - * INJECTABLE - * - * Called when the user presses the mouse button down. This will activate dragging operations once the user moves a few pixels - * within {@link CIQ.ChartEngine#mousemoveinner}. - * @param {Event} e The mouse event - * @memberof CIQ.ChartEngine.AdvancedInjectable# - * @alias mousedown - */ -CIQ.ChartEngine.prototype.mousedown = function (e) { - if (this.runPrepend("mousedown", arguments)) return; - this.grabOverrideClick = false; - //if(this.openDialog!=="") return; - if (!this.displayInitialized) return; // No chart displayed yet - if (!this.displayCrosshairs) return; - if (this.repositioningDrawing) return; // if mouse went off screen this might happen - if (this.editingAnnotation) return; - if (e.button && e.button >= 2) { - // only trigger for a primary mouse down event. - return; - } - var rect = this.container.getBoundingClientRect(); - this.top = rect.top; - this.left = rect.left; - this.right = this.left + this.width; - this.bottom = this.top + this.height; - if ( - e.clientX >= this.left && - e.clientX <= this.right && - e.clientY >= this.top && - e.clientY <= this.bottom - ) { - this.insideChart = true; - } else { - this.insideChart = false; - return; - } - if (!this.currentPanel) return; - if ( - this.manageTouchAndMouse && - e && - e.preventDefault && - this.captureTouchEvents - ) - e.preventDefault(); // Added 9/19/13 to prevent IE from going into highlight mode when you mouseout of the container - this.mouseTimer = Date.now(); - this.longHoldTookEffect = false; - this.hasDragged = false; - this.userPointerDown = true; - - // only register the pointerEvent if there is nothing open over the chart - if (this.openDialog === "") - this.registerPointerEvent( - { x: e.clientX, y: e.clientY, time: this.mouseTimer }, - "down" - ); - - var chart = this.currentPanel.chart; - for (var i = 0; i < this.drawingObjects.length; i++) { - var drawing = this.drawingObjects[i]; - if (drawing.highlighted && !drawing.permanent) { - if (this.cloneDrawing) { - // clone a drawing if flag set - var Factory = CIQ.ChartEngine.drawingTools[drawing.name]; - var clonedDrawing = new Factory(); - clonedDrawing.reconstruct(this, drawing.serialize()); - this.drawingObjects.push(clonedDrawing); - this.activateRepositioning(clonedDrawing); - clonedDrawing.repositioner = drawing.repositioner; - return; - } - var drawingTool = this.currentVectorParameters.vectorType; - // do not allow repositioning if the drawing tool has dragToDraw (like the freeform) - if ( - !CIQ.Drawing || - !drawingTool || - !CIQ.Drawing[drawingTool] || - !new CIQ.Drawing[drawingTool]().dragToDraw - ) { - this.activateRepositioning(drawing); - return; - } - } - } - var mainSeriesRenderer = this.mainSeriesRenderer || {}; - const { baselineHelper } = this; - if (baselineHelper.size) { - if (this.findBaselineHandle(e, true)) return; - } - - if (this.controls.anchorHandles) { - const { anchorHandles } = this.controls; - for (let i in anchorHandles) { - let { handle, sd, highlighted } = anchorHandles[i]; - if (highlighted) { - this.repositioningAnchorSelector = { sd }; - handle.classList.add("stx-grab"); - return; - } - } - } - - if (this.drawingClick) { - if (this.currentPanel.subholder === e.target) - this.drawingClick(this.currentPanel, this.cx, this.cy); - if (this.activeDrawing && this.activeDrawing.dragToDraw) return; - } - - this.grabbingScreen = true; - chart.spanLock = false; - this.yToleranceBroken = false; - /* use e.client instead of e.page since we need the value to be relative to the viewport instead of the overall document size. - if(!e.pageX){ - e.pageX=e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft; - e.pageY=e.clientY + document.body.scrollTop + document.documentElement.scrollTop; - } - */ - this.grabStartX = e.clientX; - this.grabStartY = e.clientY; - this.grabStartMicropixels = this.micropixels; - this.grabStartScrollX = chart.scroll; - this.grabStartScrollY = this.currentPanel.yAxis.scroll; - this.grabStartCandleWidth = this.layout.candleWidth; - this.grabStartYAxis = this.whichYAxis(this.currentPanel); - this.grabStartZoom = this.grabStartYAxis ? this.grabStartYAxis.zoom : 0; - this.grabStartPanel = this.currentPanel; - - setTimeout( - (function (self) { - return function () { - self.grabbingHand(); - }; - })(this), - 100 - ); - if (this.swipeStart) this.swipeStart(chart); - if (this.longHoldTime || this.longHoldTime === 0) this.startLongHoldTimer(); - this.runAppend("mousedown", arguments); -}; - -/** - * INJECTABLE - * - * Handles mouse movement events. This method calls {@link CIQ.ChartEngine#mousemoveinner} which has the core logic - * for dealing with panning and zooming. See also {@link CIQ.ChartEngine.AdvancedInjectable#touchmove} which is the equivalent method for touch events. - * @param {Event} mouseEvent A mouse move event - * @memberof CIQ.ChartEngine.AdvancedInjectable# - * @alias mousemove - */ -CIQ.ChartEngine.prototype.mousemove = function (mouseEvent) { - var e = mouseEvent; - /* use e.client instead of e.page since we need the value to be relative to the viewport instead of the overall document size. - if(!e.pageX){ - e.pageX=e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft; - e.pageY=e.clientY + document.body.scrollTop + document.documentElement.scrollTop; - } - */ - CIQ.ChartEngine.crosshairX = e.clientX; // These are used by the UI so make sure they are set even if no chart is set - CIQ.ChartEngine.crosshairY = e.clientY; - if (e.type.toLowerCase().indexOf("enter") > -1) { - this.positionCrosshairsAtPointer(); - return; - } - if (this.runPrepend("mousemove", arguments)) return; - if (!this.displayInitialized) return; // No chart displayed yet - if (this.openDialog !== "") return; // Don't show crosshairs when dialog is open - if (this.baselineHelper.size) this.findBaselineHandle(e); - if (this.grabbingScreen && e.buttons !== 1) { - this.cancelLongHold = true; - this.displayDragOK(); - // Added 9/19/2013 to unleash grabbing when the mouse moves out of the container - this.grabbingScreen = false; - this.findHighlights(false, true); - } - this.mousemoveinner(e.clientX, e.clientY); - this.runAppend("mousemove", arguments); -}; - -/** - * INJECTABLE - * - * Called whenever the user lifts the mousebutton up. This may send a click to a drawing, or cease a drag operation. - * @param {Event} e A mouse event - * @memberof CIQ.ChartEngine.AdvancedInjectable# - * @alias mouseup - * @since 6.3.0 baseline chart recenters itself after adjusting baseline - */ -CIQ.ChartEngine.prototype.mouseup = function (e) { - if (this.runPrepend("mouseup", arguments)) return; - this.swipe.end = true; - this.cancelLongHold = true; - if (this.repositioningDrawing) { - // if we single click with a drawing tool enabled, then start another drawing instead of moving current one - if ( - !this.currentVectorParameters.vectorType || - Date.now() - this.mouseTimer > 250 - ) { - this.changeOccurred("vector"); - CIQ.clearCanvas(this.chart.tempCanvas, this); - this.activateRepositioning(null); - this.adjustDrawings(); - this.draw(); - return; - } - this.activateRepositioning(null); - } - - if (this.repositioningBaseline) { - const { handle } = this.repositioningBaseline; - this.repositioningBaseline = null; - handle.classList.remove("stx-grab"); - var mainSeriesRenderer = this.mainSeriesRenderer || {}; - if ( - mainSeriesRenderer.params && - mainSeriesRenderer.params.baseline && - mainSeriesRenderer.params.type != "mountain" - ) { - //this is so the baseline does not pop back to the center - //this.chart.panel.yAxis.scroll=this.pixelFromPrice(this.chart.baseline.userLevel, this.chart.panel)-(this.chart.panel.yAxis.top+this.chart.panel.yAxis.bottom)/2; - } - this.draw(); - return; - } - - if (this.repositioningAnchorSelector) { - CIQ.Studies.repositionAnchor(this, this.repositioningAnchorSelector.sd); - this.repositioningAnchorSelector = null; - Object.values(this.controls.anchorHandles).forEach(({ handle }) => - handle.classList.remove("stx-grab") - ); - this.findHighlights(); - return; - } - - var wasMouseDown = this.userPointerDown; - this.userPointerDown = false; - if (!this.displayInitialized) return; // No chart displayed yet - - var cy = this.backOutY(e.clientY); - var cx = this.backOutX(e.clientX); - var isRightClick = (e.which && e.which >= 2) || (e.button && e.button >= 2); - var openDialog = this.openDialog !== ""; - - if (!openDialog && !isRightClick) - this.registerPointerEvent( - { x: e.clientX, y: e.clientY, time: Date.now() }, - "up" - ); - var isDblClick = this.isDoubleClick(); - - this.grabbingScreen = false; - if (this.highlightedDraggable) { - if (this.dragPlotOrAxis) this.dragPlotOrAxis(cx, cy); - this.currentPanel = this.whichPanel(cy); - } - var panel = this.currentPanel; - - this.grabStartYAxis = null; - this.displayDragOK(); - if (this.openDialog !== "") { - if (this.insideChart) this.container.classList.remove("stx-drag-chart"); //in case they were grabbing the screen and let go on top of the button. - return; - } - if (this.grabOverrideClick) { - if (!this.overXAxis && !this.overYAxis && this.swipeRelease) - this.swipeRelease(); - this.container.classList.remove("stx-drag-chart"); - this.grabOverrideClick = false; - this.doDisplayCrosshairs(); - this.updateChartAccessories(); - return; - } - //if(!this.displayCrosshairs) return; - if (this.insideChart) this.container.classList.remove("stx-drag-chart"); - if (CIQ.ChartEngine.resizingPanel) { - this.releaseHandle(); - //CIQ.clearCanvas(this.chart.tempCanvas, this); - //this.resizePanels(); - //CIQ.ChartEngine.resizingPanel=null; - return; - } - if (isRightClick || e.ctrlKey) { - if (this.anyHighlighted && this.bypassRightClick !== true) { - this.rightClickHighlighted(); - if (e.preventDefault && this.captureTouchEvents) e.preventDefault(); - e.stopPropagation(); - return false; - } - this.dispatch("rightClick", { stx: this, panel: panel, x: cx, y: cy }); - return true; - } - if (e.clientX < this.left || e.clientX > this.right) return; - if (e.clientY < this.top || e.clientY > this.bottom) return; - - var targettingSubholder = panel && panel.subholder === e.target; - // Unlike drawings and marker clicks, allow doubleClick to target axis outside panel subholder - if (isDblClick && (targettingSubholder || this.overYAxis || this.overXAxis)) { - this.doubleClick({ button: e.button, x: cx, y: cy }); - } else { - if (wasMouseDown && targettingSubholder) { - if (!this.longHoldTookEffect || this.activeDrawing) - this.drawingClick(panel, cx, cy); - if (!this.longHoldTookEffect && this.activeMarker) - this.activeMarker.click({ cx, cy, panel }); - } - if (!this.longHoldTookEffect && !this.activeDrawing) { - this.dispatch("tap", { stx: this, panel: panel, x: cx, y: cy }); - } - } - this.runAppend("mouseup", arguments); -}; - -/** - * Adds an event to the `pointerEvents` array for a given type. - * - * **This is the only method that should ever add entries to a `pointerEvents` array.** - * - * @param {object} info The event object. - * @param {string} type Event type to which the event is added. Valid types are 'up' and 'down'. - * - * @memberof CIQ.ChartEngine - * @private - * @since 8.0.0 - */ -CIQ.ChartEngine.prototype.registerPointerEvent = function (info, type) { - if (this.pointerEvents[type].length > 1) this.pointerEvents[type].pop(); - this.pointerEvents[type].unshift(info); -}; - -/** - * Resets a `pointerEvents` array to an initial empty state. - * - * **This is the only method that should ever clear entries from a `pointerEvents` array.** - * - * @param {string} type The event type for which all events are removed. Valid types are 'up' - * and 'down'. - * - * @memberof CIQ.ChartEngine - * @private - * @since 8.0.0 - */ -CIQ.ChartEngine.prototype.resetPointerEvent = function (type) { - this.pointerEvents[type].splice(0); -}; - -/** - * Determines whether the chart has received a double-click based on the `pointerEvents` - * tuple. This method double-checks the coordinates and timing of the last two clicks to - * determine: - * - the clicks were within {@link CIQ.ChartEngine.prototype.doubleClickTime} - * - the clicks were within 20px of each other - * - neither click was a long-hold - * - * If a double-click was determined to have happened, then we reset the `pointerEvents` array - * for 'up' and 'down'. - * - * @param {boolean} isTouch Set this parameter to true when checking whether a touch event is a - * double-click (double-tap). When the parameter is true, the allowable area where a - * double-click can occur is increased to accommodate fingers, which are larger than a mouse - * cursor. - * @return {boolean} True if a double click was detected. - * - * @memberof CIQ.ChartEngine - * @private - * @since - * - 8.0.0 - * - 8.1.0 Added `isTouch` parameter. - */ -CIQ.ChartEngine.prototype.isDoubleClick = function (isTouch) { - const boundary = isTouch ? 1200 : 400; - const { up, down } = this.pointerEvents; - this.cancelTouchSingleClick = false; - if (up.length < 2 || down.length < 2) return false; - const doubleClick = - down[0].time - up[1].time < this.doubleClickTime && - Math.pow(up[1].x - up[0].x, 2) + Math.pow(up[1].y - up[0].y, 2) <= - boundary && - up[1].time - down[1].time < this.longHoldTime && - up[0].time - down[0].time < this.longHoldTime; - - if (doubleClick) { - this.resetPointerEvent("up"); - this.resetPointerEvent("down"); - this.cancelTouchSingleClick = true; - } - return doubleClick; -}; - -/** - * Handles all double-clicks on the chart container. - * - * Applies a double-click event to a {@link CIQ.Marker} and dispatches the "doubleClick" event, - * which invokes the [doubleClickEventListener]{@link CIQ.ChartEngine~doubleClickEventListener}. - * - * If the return value of the marker's {@link CIQ.Marker#doubleClick} method is truthy, the - * "doubleClick" event is not dispatched. - * - * @param {number} button The button used to double-click. - * @param {number} x The x-coordinate of the double-click. - * @param {number} y The y-coordinate of the double-click. - * - * @alias doubleClick - * @memberof CIQ.ChartEngine.prototype - * @since 8.0.0 - */ -CIQ.ChartEngine.prototype.doubleClick = function (button, x, y) { - if (this.runPrepend("doubleClick", arguments)) return; - if (this.editingAnnotation) return; - if (CIQ.ChartEngine.drawingLine) return this.undo(); - if (this.activeDrawing) return; - - let handledMarker = - this.activeMarker && - this.activeMarker.doubleClick({ cx: x, cy: y, panel: this.currentPanel }); - if (!handledMarker) - this.dispatch("doubleClick", { stx: this, button: button, x: x, y: y }); - - this.runAppend("doubleClick", arguments); -}; - -/** - * INJECTABLE - * - * This is called whenever the mouse leaves the chart area. Crosshairs are disabled, stickies are hidden, dragDrawings are completed. - * @param {Event} e The mouseout event - * @memberof CIQ.ChartEngine.AdvancedInjectable# - * @alias handleMouseOut - */ -CIQ.ChartEngine.prototype.handleMouseOut = function (e) { - e = e || window.event; - if (!CIQ.withinElement(this.chart.container, e.pageX, e.pageY)) { - if (this.runPrepend("handleMouseOut", arguments)) return; - if (!this.grabbingScreen) this.findHighlights(null, true); - this.undisplayCrosshairs(); - this.touches = []; - this.touching = false; - if (this.activeDrawing && this.userPointerDown) { - //end the drawing - this.userPointerDown = false; - this.drawingLine = false; - var cy = this.backOutY(e.pageY); - var cx = this.backOutX(e.pageX); - this.drawingClick(this.currentPanel, cx, cy); - } - if (this.repositioningAnchorSelector) { - this.repositioningAnchorSelector = null; - } - this.insideChart = false; - this.overYAxis = false; - this.overXAxis = false; - // Added to remove sticky when the mouse moves out of the container - this.displaySticky(); - this.runAppend("handleMouseOut", arguments); - } -}; - -CIQ.ChartEngine.prototype.startLongHoldTimer = function () { - var stx = this; - this.cancelLongHold = false; - if (this.longHoldTimeout) clearTimeout(this.longHoldTimeout); - var cb = function () { - if (stx.cancelLongHold) return; - stx.longHoldTookEffect = true; - stx.dispatch("longhold", { - stx: stx, - panel: stx.currentPanel, - x: stx.cx, - y: stx.cy - }); - stx.displayDragOK(); - }; - if (this.longHoldTime) { - this.longHoldTimeout = setTimeout(cb, this.longHoldTime); - } else if (this.longHoldTime === 0) { - cb(); - } -}; - -/** - * INJECTABLE - * - * Event handler that is called when the handle of a panel is grabbed, for resizing - * @param {CIQ.ChartEngine.Panel} panel The panel that is being grabbed - * @memberof CIQ.ChartEngine.AdvancedInjectable# - * @alias grabHandle - */ -CIQ.ChartEngine.prototype.grabHandle = function (panel) { - if (this.runPrepend("grabHandle", arguments)) return; - //if(e.preventDefault) e.preventDefault(); - if (!panel) return; - CIQ.ChartEngine.crosshairY = panel.top + this.top; - CIQ.ChartEngine.resizingPanel = panel; - panel.handle.classList.add("stx-grab"); - this.runAppend("grabHandle", arguments); -}; - -/** - * Turns on the grabbing hand cursor. It does this by appending the class "stx-drag-chart" to the chart container. - * If this is a problem then just eliminate this function from the prototype. - * @memberof CIQ.ChartEngine - */ -CIQ.ChartEngine.prototype.grabbingHand = function () { - if (!this.allowScroll) return; - if (!this.grabbingScreen) return; - if (CIQ.touchDevice) return; - this.container.classList.add("stx-drag-chart"); -}; - -/** - * INJECTABLE - * - * Event handler that is called when a panel handle is released. - * @memberof CIQ.ChartEngine.AdvancedInjectable# - * @alias releaseHandle - */ -CIQ.ChartEngine.prototype.releaseHandle = function () { - if (this.runPrepend("releaseHandle", arguments)) return true; - //if(e.preventDefault) e.preventDefault(); - CIQ.clearCanvas(this.chart.tempCanvas, this); - this.resizePanels(); - if (CIQ.ChartEngine.resizingPanel) - CIQ.ChartEngine.resizingPanel.handle.classList.remove("stx-grab"); - CIQ.ChartEngine.resizingPanel = null; - this.runAppend("releaseHandle", arguments); -}; - -/** - * Finds any objects that should be highlighted by the current crosshair position. All drawing objects have their highlight() method - * called in order that they may draw themselves appropriately. - * @param {boolean} isTap If true then it indicates that the user tapped the screen on a touch device, and thus a wider radius is used to determine which objects might have been highlighted. - * @param {boolean} clearOnly Set to true to clear highlights - * @memberof CIQ.ChartEngine - * @since 4.0.0 {@link CIQ.ChartEngine#displaySticky} is now called to display the 'series.symbol' if the 'series.display' is not present - */ -CIQ.ChartEngine.prototype.findHighlights = function (isTap, clearOnly) { - var radius = this.preferences[ - isTap ? "highlightsTapRadius" : "highlightsRadius" - ]; // 30:10 - this.highlightViaTap = isTap; // internal use state var - - var { cx, cy } = this; - this.anyHighlighted = false; - if (!this.currentPanel) return; - var { chart } = this.currentPanel; - - if (this.activeDrawing) clearOnly = true; - var somethingChanged = false; - var drawingToMeasure = null; - var stickyArgs = clearOnly ? {} : { forceShow: true, type: "drawing" }; - - var box = { - x0: this.tickFromPixel(cx - radius, chart), - x1: this.tickFromPixel(cx + radius, chart), - y0: this.valueFromPixel(cy - radius, this.currentPanel), - y1: this.valueFromPixel(cy + radius, this.currentPanel), - cx0: cx - radius, - cx1: cx + radius, - cy0: cy - radius, - cy1: cy + radius, - r: radius - }; - if (this.repositioningDrawing && box.x1 - box.x0 < 2) { - box.x1++; - box.x0--; - } else if (box.x1 == box.x0) { - box.x0 -= 0.5; - box.x1 += 0.5; - } - var markers = - this.markerHelper && - this.markerHelper.chartMap[chart.name] && - this.markerHelper.chartMap[chart.name].markers; - /* begin test code - // show the box - this.chart.canvas.context.strokeStyle="red"; - this.chart.canvas.context.strokeRect(this.pixelFromTick(box.x0,chart),cy-radius,this.pixelFromTick(box.x1,chart)-this.pixelFromTick(box.x0,chart),2*radius); - this.chart.canvas.context.strokeStyle="blue"; - this.chart.canvas.context.strokeRect(cx-radius,cy-radius,2*radius,2*radius); - end test code */ - - if (!chart.hideDrawings) { - for (var i = this.drawingObjects.length - 1; i >= 0; i--) { - var drawing = this.drawingObjects[i]; - if (!this.panels[drawing.panelName]) continue; - if (this.repositioningDrawing && this.repositioningDrawing != drawing) - continue; - - var prevHighlight = drawing.highlighted; - var highlightMe = drawing.panelName == this.currentPanel.name; - drawing.repositioner = drawing.intersected( - this.crosshairTick, - this.crosshairValue, - box - ); - highlightMe = highlightMe && drawing.repositioner; - - if (!clearOnly && highlightMe) { - if (prevHighlight) { - drawingToMeasure = drawing; - if (this.anyHighlighted && this.singleDrawingHighlight) - drawing.highlighted = false; - if (drawing.highlighted && drawing.highlighted != prevHighlight) - somethingChanged = true; // drawing is still highlighted, but a different positioner is active - } else if (prevHighlight != drawing.highlight(true)) { - if (!drawingToMeasure) drawingToMeasure = drawing; - if (this.anyHighlighted && this.singleDrawingHighlight) - drawing.highlighted = false; - somethingChanged = true; - } - this.anyHighlighted = true; - } else { - if (prevHighlight != drawing.highlight(false)) { - somethingChanged = true; - } - } - if (drawing.highlighted) { - stickyArgs.noDelete = drawing.permanent; - stickyArgs.noEdit = !this.callbackListeners.drawingEdit.length; - } - } - } - - var n, o, m, marker, series; - for (n in this.layout.studies) { - o = this.layout.studies[n]; - o.prev = o.highlight; - o.highlight = this.yaxisMatches(o, this.grabStartYAxis); - } - for (n in chart.seriesRenderers) { - var r = chart.seriesRenderers[n]; - r.params.highlight = this.yaxisMatches(r, this.grabStartYAxis); - for (var j = 0; j < r.seriesParams.length; j++) { - series = r.seriesParams[j]; - series.prev = series.highlight; - series.highlight = r.params.highlight; - } - } - for (m = 0; markers && m < markers.length; m++) { - marker = markers[m]; - if (!marker.params.box) continue; // Only created when the dataSegment is drawn for performance markers - this.activeMarker = null; - marker.prev = markers[m].highlight; - marker.highlight = false; - } - if (this.markerHelper) this.markerHelper.highlighted = []; - this.highlightedDataSetField = null; - this.highlightedDraggable = null; - - // Function to detect if a "box" drawn around the cursor position is intersected by the overlay. - // Up to two overlay segments may be tested: - // The segment endpointed by the previous dataSet element containing that field and the current dataSet element behind the cursor, - // and the current dataSet element behind the cursor and the next dataSet element containing that field. - // In case there are gaps in the data, one of these segments may not exist. - // This routine is designed to also handle comparison overlays which cause the dataSet to be transformed. - // The argument "fullField" represents the series symbol and the subField, separated by a period (e.g. GOOG.High). - // If there is no subField, a subField of Close is presumed. - function isOverlayIntersecting(refBar, box, fullField, yAxis, renderer, id) { - var chart = this.chart, - currentPanel = this.currentPanel; - if (!yAxis) yAxis = currentPanel.yAxis; - var parts = fullField.split("-->"); - var field = parts[0]; - var subField = parts[1]; - if (!subField) subField = "Close"; - function getVal(quote) { - if (!quote) return null; - var theVal = quote[field]; - if (theVal && (theVal[subField] || theVal[subField] === 0)) { - // For OHLC, hover over imaginary line connecting closes - theVal = theVal[subField]; - } - if (renderer && renderer.getBasis) - theVal += renderer.getBasis(quote, field, subField); - if (!chart.transformFunc || yAxis != chart.yAxis) return theVal; - else if (quote.transform && field in quote.transform) { - theVal = quote.transform[field]; - if (theVal && (theVal[subField] || theVal[subField] === 0)) { - // For OHLC, hover over imaginary line connecting closes - theVal = theVal[subField]; - } - return theVal; - } - return chart.transformFunc(this, chart, theVal); - } - var quote = chart.dataSegment[bar], - quotePrev, - quoteNext; - var val, - valPrev, - valNext, - tick = null, - tickPrev = null, - tickNext = null; - var usedCache = new Array(3); - var cache = renderer && renderer.caches[id]; - if (quote && cache) { - val = cache[bar]; - tick = quote.tick; - if (val || val === 0) usedCache[0] = 1; - var ci; - for (ci = bar - 1; ci >= 0; ci--) { - if (cache[ci] || cache[ci] === 0) { - valPrev = cache[ci]; - tickPrev = tick - (bar - ci); - usedCache[1] = 1; - break; - } - } - for (ci = bar + 1; ci < chart.dataSegment.length; ci++) { - if (cache[ci] || cache[ci] === 0) { - valNext = cache[ci]; - tickNext = tick - (bar - ci); - usedCache[2] = 1; - break; - } - } - } - if (tickPrev === null) { - quotePrev = this.getPreviousBar.call(this, chart, fullField, bar); - if (quotePrev) { - tickPrev = quotePrev.tick; - valPrev = getVal(quotePrev); - } - } - if (tickNext === null) { - quoteNext = this.getNextBar.call(this, chart, fullField, bar); - if (quoteNext) { - tickNext = quoteNext.tick; - valNext = getVal(quoteNext); - } - } - if (tickPrev === null && tickNext === null) return false; - - if (!cache) { - val = getVal(quote); - valPrev = getVal(quotePrev); - valNext = getVal(quoteNext); - tick = quote.tick; - if (quotePrev) tickPrev = quotePrev.tick; - if (quoteNext) tickNext = quoteNext.tick; - } - - if (!valPrev && valPrev !== 0) { - valPrev = 0; - tickPrev = 0; - } - if (!valNext && valNext !== 0) { - if (val || val === 0) { - valNext = val; - usedCache[2] = usedCache[0]; - } else { - valNext = valPrev; - usedCache[2] = usedCache[1]; - } - if (id && chart.series[id].parameters.extendToEndOfDataSet) { - tickNext = chart.dataSet.length - 1; - } else { - tickNext = tickPrev; - } - } - if (!val && val !== 0) { - val = valNext; - tick = tickNext; - usedCache[0] = usedCache[2]; - if (valPrev === 0 && tickPrev === 0) { - valPrev = val; - tickPrev = tick; - usedCache[1] = usedCache[0]; - } - } - - // The following code will get the pixel value of the price from either the renderer's series cache or the computation. - // Then it will convert the pixel value back to the price value for the current panel's axis. - // Using the cache is the only way to go for an overlay. There is a shortcoming for the overlay though, in that - // if valPrev or valNext were off the screen, they wouldn't be in the cache and so their y axis value would be inaccurate. - - var pftv = this.pixelFromTransformedValue.bind(this), - vfp = this.valueFromPixel.bind(this); - val = vfp( - usedCache[0] ? val : pftv(val, currentPanel, yAxis), - currentPanel - ); - valPrev = vfp( - usedCache[1] ? valPrev : pftv(valPrev, currentPanel, yAxis), - currentPanel - ); - valNext = vfp( - usedCache[2] ? valNext : pftv(valNext, currentPanel, yAxis), - currentPanel - ); - - var pixelBox = CIQ.convertBoxToPixels(this, currentPanel.name, box); - var pixelPoint1 = CIQ.convertBoxToPixels(this, currentPanel.name, { - x0: tickPrev, - y0: valPrev, - x1: tick, - y1: val - }); - var pixelPoint2 = CIQ.convertBoxToPixels(this, currentPanel.name, { - x0: tick, - y0: val, - x1: tickNext, - y1: valNext - }); - if ( - CIQ.boxIntersects( - pixelBox.x0, - pixelBox.y0, - pixelBox.x1, - pixelBox.y1, - pixelPoint1.x0, - pixelPoint1.y0, - pixelPoint1.x1, - pixelPoint1.y1, - "segment" - ) || - CIQ.boxIntersects( - pixelBox.x0, - pixelBox.y0, - pixelBox.x1, - pixelBox.y1, - pixelPoint2.x0, - pixelPoint2.y0, - pixelPoint2.x1, - pixelPoint2.y1, - "segment" - ) - ) { - return true; - } - return false; - } - - if (!clearOnly && !this.anyHighlighted && this.controls.anchorHandles) { - for (let id in this.controls.anchorHandles) { - const anchorHandle = this.controls.anchorHandles[id]; - const { handle, sd } = anchorHandle; - const xo = this.resolveX(cx); - const yo = this.resolveY(cy); - if (handle) { - const { left, top, right, bottom } = handle.getBoundingClientRect(); - if (CIQ.boxIntersects(left, top, right, bottom, xo, yo, xo, yo)) { - anchorHandle.highlighted = true; - this.anyHighlighted = true; - somethingChanged = true; - stickyArgs = { - message: sd.name, - type: "anchorHandle" - }; - continue; - } - - if (anchorHandle.highlighted === true) { - anchorHandle.highlighted = false; - somethingChanged = true; - } - } - } - } - - if (!clearOnly && !this.anyHighlighted && chart.dataSegment) { - var bar = this.barFromPixel(cx); - if (bar >= 0 && bar < chart.dataSegment.length) { - var y; - for (n in this.overlays) { - o = this.overlays[n]; - - // check handles before this to make sure to set highlight state to false where appropriate - if (o.panel != this.currentPanel.name) continue; - - //custom highlight detection - if (o.study.isHighlighted === false) continue; - else if (typeof o.study.isHighlighted == "function") { - if (o.study.isHighlighted(this, cx, cy)) { - o.highlight = true; - this.anyHighlighted = true; - } - continue; - } - - var quote = chart.dataSegment[bar]; - if (!quote) continue; - - for (var out in o.outputMap) { - if ( - isOverlayIntersecting.call(this, bar, box, out, o.getYAxis(this)) - ) { - if (o.name != o.panel) this.anyHighlighted = true; - o.highlight = out; - break; - } - } - if (o.highlight) { - this.highlightedDataSetField = out; - break; // only allow one overlay to be highlighted at a time - } - } - for (n in chart.seriesRenderers) { - if (this.highlightedDataSetField) break; - var renderer = chart.seriesRenderers[n]; - var rendererPanel = renderer.params.panel; - if (renderer == this.mainSeriesRenderer) continue; - if ( - !renderer.params.highlightable && - !this.currentVectorParameters.vectorType - ) - continue; - if (rendererPanel != this.currentPanel.name) continue; - for (m = 0; m < renderer.seriesParams.length; m++) { - series = renderer.seriesParams[m]; - var fullField = series.field; - if (!fullField && !renderer.highLowBars) - fullField = this.defaultPlotField || "Close"; - if (series.symbol && series.subField) - fullField += "-->" + series.subField; - var yAxis = renderer.params.yAxis; - if (!yAxis && rendererPanel) yAxis = this.panels[rendererPanel].yAxis; - if (renderer.params.step && bar > 0) { - // In a step series we also need to check for intersection with - // the vertical bar (the step) that connects two points - if (!renderer.caches[series.id]) continue; - y = renderer.caches[series.id][bar]; - if (!y && y !== 0) continue; - var py = renderer.caches[series.id][bar - 1]; - if ( - ((py || py === 0) && cy + radius >= y && cy - radius <= py) || - (cy - radius <= y && cy + radius >= py) - ) { - series.highlight = true; - this.anyHighlighted = true; - } - } else if ( - isOverlayIntersecting.call( - this, - bar, - box, - fullField, - yAxis, - renderer, - series.id - ) - ) { - series.highlight = true; - this.anyHighlighted = true; - } - if (series.highlight) { - this.highlightedDataSetField = fullField; - break; - } - } - } - } - } - var highlightedDraggable; - var drag = this.preferences.dragging; - - var yAxisToHighlight; - - for (n in this.overlays) { - o = this.overlays[n]; - if (o.highlight) { - this.anyHighlighted = true; - var display = o.inputs.display || o.name; - display = this.translateIf(display); - stickyArgs = { - message: display, - noDelete: o.permanent, - noEdit: !o.editFunction, - type: "study" - }; - drawingToMeasure = null; - if (drag === true || (drag && drag.study)) highlightedDraggable = o; - - // Find corresponding y-axis - yAxisToHighlight = o.getYAxis(this); - } - if (o.prev != o.highlight) somethingChanged = true; - } - - for (n in chart.seriesRenderers) { - var r2 = chart.seriesRenderers[n]; - var bColor = r2.params.yAxis ? r2.params.yAxis.textStyle : null; - for (var m2 = 0; m2 < r2.seriesParams.length; m2++) { - series = r2.seriesParams[m2]; - if (r2.params.highlightable && series.highlight) { - this.anyHighlighted = true; - var bgColor = series.color || bColor; - if (bgColor == "auto") bgColor = this.defaultColor; - if (series.opacity && series.opacity !== 1) - bgColor = CIQ.hexToRgba( - CIQ.colorToHex(bgColor), - parseFloat(series.opacity) - ); - stickyArgs = { - message: series.display || series.symbol, - backgroundColor: bgColor, - noDelete: series.permanent, - type: "series" - }; - drawingToMeasure = null; - if (drag === true || (drag && drag.series)) { - highlightedDraggable = r2; - r2.params.highlight = true; - } - - // Find corresponding y-axis - yAxisToHighlight = r2.getYAxis(this); - } - if (series.prev != series.highlight) somethingChanged = true; - } - } - - for (n in this.plugins) { - var plugin = this.plugins[n]; - var pluginHighlights = {}; - if (plugin.findHighlights) { - pluginHighlights = plugin.findHighlights(this, isTap, clearOnly); - if (pluginHighlights.somethingChanged) somethingChanged = true; - if (pluginHighlights.anyHighlighted) { - this.anyHighlighted = true; - stickyArgs = pluginHighlights.stickyArgs || {}; - } - } - } - - var myPanel = this.whichPanel(cy); - var myYAxis = this.whichYAxis(myPanel, cx); - - if (!yAxisToHighlight) yAxisToHighlight = myYAxis; - if (this.currentBaseline) - yAxisToHighlight = this.currentBaseline.getYAxis(this); - - // Highlight yAxisToHighlight if applicable - if (yAxisToHighlight) { - if (!yAxisToHighlight.highlight) somethingChanged = true; - yAxisToHighlight.highlight = true; - } - - // Collect all y-axes in array for easy referencing - // Collect all in case you move from highlighting axis across panels - var allYAxes = []; - for (var p in this.panels) { - allYAxes = allYAxes - .concat(this.panels[p].yaxisLHS) - .concat(this.panels[p].yaxisRHS); - } - - for (n = 0; n < allYAxes.length; n++) { - if (yAxisToHighlight == allYAxes[n] && !clearOnly) continue; - if (allYAxes[n].highlight) somethingChanged = true; - allYAxes[n].highlight = false; - } - - for (m = 0; markers && m < markers.length; m++) { - marker = markers[m]; - var mbox = marker.params.box; - if (!mbox) continue; // Only created when the dataSegment is drawn. - if (marker.params.panelName !== this.currentPanel.name) continue; - var pxBox = CIQ.convertBoxToPixels(this, this.currentPanel.name, box); - //If it doesn't exist then the it is off the screen and cannot be intersected. - if ( - CIQ.boxIntersects( - pxBox.x0, - pxBox.y0, - pxBox.x1, - pxBox.y1, - mbox.x0, - mbox.y0, - mbox.x1, - mbox.y1 - ) - ) { - this.activeMarker = marker; - marker.highlight = true; - this.markerHelper.highlighted.push(marker); - } - if (marker.prev != marker.highlight) somethingChanged = true; - } - - if (somethingChanged) { - this.draw(); - stickyArgs.panel = myPanel; - if (this.anyHighlighted && !this.grabStartYAxis) stickyArgs.panel = myPanel; - else stickyArgs = {}; - this.displaySticky(stickyArgs); - this.clearMeasure(); - if (drawingToMeasure) drawingToMeasure.measure(); - } - - if ((drag === true || (drag && drag.yaxis)) && myYAxis && !myYAxis.noDraw) { - this.anyHighlight = true; - highlightedDraggable = myYAxis; - } - - if (!this.anyHighlighted) { - this.setMeasure(); - } - - if (highlightedDraggable && !myPanel.noDrag) { - if (this.longHoldTookEffect && !this.cancelLongHold) { - if (highlightedDraggable.params) { - // series, highlight relatives - if (highlightedDraggable.params.dependentOf) { - // series, highlight relatives - highlightedDraggable = - chart.seriesRenderers[highlightedDraggable.params.dependentOf]; - highlightedDraggable.params.highlight = true; - } - for (n in chart.seriesRenderers) { - if ( - chart.seriesRenderers[n].params.dependentOf == - highlightedDraggable.params.name - ) { - chart.seriesRenderers[n].params.highlight = true; - } - } - } - this.highlightedDraggable = highlightedDraggable; - if (highlightedDraggable.getDependents) { - // study, highlight dependents - var dependents = highlightedDraggable.getDependents(this, true); - for (n in this.overlays) { - o = this.overlays[n]; - if (dependents.indexOf(o) > -1) o.highlight = true; - } - } - } - this.container.classList.add("stx-draggable"); - } else { - this.container.classList.remove("stx-draggable"); - } - - this.highlightedDataSetField = this.adjustHighlightedDataSetField( - this.highlightedDataSetField - ); - this.displayDrawOK(); -}; - -/** - * INJECTABLE - * - * This function is called when the user right clicks on a highlighted overlay, series or drawing.
- * Calls deleteHighlighted() which calls rightClickOverlay() for studies. - * @memberof CIQ.ChartEngine.AdvancedInjectable# - * @alias rightClickHighlighted - * @example - * stxx.prepend("rightClickHighlighted", function(){ - * console.log('do nothing on right click'); - * return true; - * }); - */ -CIQ.ChartEngine.prototype.rightClickHighlighted = function () { - if (this.runPrepend("rightClickHighlighted", arguments)) return; - this.deleteHighlighted(true); - this.runAppend("rightClickHighlighted", arguments); -}; - -/** - * INJECTABLE - * - * Removes any and all highlighted overlays, series or drawings. - * - * @param {boolean} callRightClick When true, call the right click method for the given highlight: - * - Drawing highlight calls {@link CIQ.ChartEngine.AdvancedInjectable#rightClickDrawing} - * - Overlay study highlight calls {@link CIQ.ChartEngine.AdvancedInjectable#rightClickOverlay} - * @param {boolean} forceEdit Skip the context menu and begin editing immediately, usually for - * touch devices. - * - * @memberof CIQ.ChartEngine.AdvancedInjectable# - * @alias deleteHighlighted - * @since - * - 4.1.0 Removes a renderer from the chart if it has no series attached to it. - * - 6.2.0 Calls {@link CIQ.ChartEngine.AdvancedInjectable#rightClickDrawing} when a drawing is - * highlighted and the `callRightClick` paramenter is true. - */ -CIQ.ChartEngine.prototype.deleteHighlighted = function ( - callRightClick, - forceEdit -) { - if (this.runPrepend("deleteHighlighted", arguments)) return; - this.cancelTouchSingleClick = true; - CIQ.clearCanvas(this.chart.tempCanvas, this); - var canDeleteAll = this.bypassRightClick === false; - if (canDeleteAll || !this.bypassRightClick.drawing) { - for (var i = this.drawingObjects.length - 1; i >= 0; i--) { - var drawing = this.drawingObjects[i]; - - if (!drawing.highlighted) continue; - - if (callRightClick) { - this.rightClickDrawing(drawing, forceEdit); - } else if (!drawing.permanent) { - var dontDeleteMe = drawing.abort(); - if (!dontDeleteMe) { - var before = this.exportDrawings(); - this.drawingObjects.splice(i, 1); - this.undoStamp(before, this.exportDrawings()); - } - this.changeOccurred("vector"); - } - } - } - if (canDeleteAll || !this.bypassRightClick.study) { - for (var name in this.overlays) { - var o = this.overlays[name]; - if ((o.overlay || o.underlay) && o.highlight && !o.permanent) { - if (callRightClick || forceEdit) - this.rightClickOverlay(name, forceEdit); - else this.removeOverlay(name); - } - } - } - - var chart = this.currentPanel.chart; - if (canDeleteAll || !this.bypassRightClick.series) { - for (var r in chart.seriesRenderers) { - var renderer = chart.seriesRenderers[r]; - if (renderer.params.highlightable) { - var rPanel = this.panels[renderer.params.panel]; - var yAxisName = rPanel && rPanel.yAxis.name; - for (var sp = renderer.seriesParams.length - 1; sp >= 0; sp--) { - var series = renderer.seriesParams[sp]; - if ( - (renderer.params.highlight || series.highlight) && - !series.permanent - ) { - renderer.removeSeries(series.id); - if (renderer.seriesParams.length < 1) { - this.removeSeriesRenderer(renderer); - if (renderer.params.name == yAxisName) { - this.electNewPanelOwner(renderer.params.panel); - } else { - this.checkForEmptyPanel(renderer.params.panel); - var rendererAxis = this.getYAxisByName( - rPanel, - renderer.params.name - ); - if (rendererAxis) { - rendererAxis.name = - rendererAxis.studies[0] || rendererAxis.renderers[1]; - } - } - } - } - } - } - } - } - - this.draw(); - this.resizeChart(); - this.clearMeasure(); - var mSticky = this.controls.mSticky; - if (mSticky) { - mSticky.style.display = "none"; - mSticky.children[0].innerHTML = ""; - } - this.runAppend("deleteHighlighted", arguments); -}; - -/** - * Displays the "ok to drag" div and the study/series which is highlighted, near the crosshairs. - * @param {boolean} [soft] True to just set the position of an already displayed div, otherwise, toggles display style based on whether long press was completed. - * @memberof CIQ.ChartEngine - * @since 7.1.0 - */ -CIQ.ChartEngine.prototype.displayDragOK = function (soft) { - function showText(control) { - var text = this.translateIf( - control.querySelector(".field").getAttribute("text") - ); - var hoveredYAxis = this.whichYAxis( - this.whichPanel(this.cy), - this.cx, - this.cy - ); - if (hoveredYAxis && hoveredYAxis.dropzone == "all") { - text += "-->" + this.translateIf(hoveredYAxis.name); - } - control.querySelector(".field").innerHTML = text; - } - var dragControl = this.controls.dragOk; - if (dragControl) { - if (!soft) { - if ( - !this.tapForHighlighting || - !this.touchingEvent || - this.anyHighlighted - ) - this.findHighlights(this.highlightViaTap); // trigger highlighting - } - var draggableObject = this.highlightedDraggable; // set by findHighlights - var dragNotAllowed = - draggableObject && - draggableObject.undraggable && - draggableObject.undraggable(this); - var cx = this.cx, - cy = this.cy; - if (!soft) { - if ( - draggableObject && - !dragNotAllowed && - this.longHoldTookEffect && - !this.cancelLongHold - ) { - var baseText = - (draggableObject.inputs && draggableObject.inputs.display) || - (draggableObject.params && - (draggableObject.params.display || draggableObject.params.name)) || - draggableObject.name; - dragControl.querySelector(".field").setAttribute("text", baseText); - showText.call(this, dragControl); - dragControl.style.display = "inline-block"; - this.draw(); // trigger opacity change - this.displaySticky(); - if (this.grabStartYAxis) - this.container.classList.replace("stx-drag-chart", "stx-drag-axis"); - else - this.container.classList.replace("stx-drag-chart", "stx-drag-series"); - } else { - dragControl.style.display = "none"; - this.draw(); - this.container.classList.remove("stx-drag-series"); - this.container.classList.remove("stx-drag-axis"); - for (var panel in this.panels) { - var classList = this.panels[panel].subholder.classList; - classList.remove("dropzone"); // IE 11 won't let you pass multiple classes - classList.remove("all"); - classList.remove("left"); - classList.remove("right"); - classList.remove("top"); - classList.remove("bottom"); - var y; - for (y = 0; y < this.panels[panel].yaxisLHS.length; y++) { - this.panels[panel].yaxisLHS[y].dropzone = null; - } - for (y = 0; y < this.panels[panel].yaxisRHS.length; y++) { - this.panels[panel].yaxisRHS[y].dropzone = null; - } - } - } - this.draw(); - } - if (draggableObject) { - var top = cy + dragControl.offsetHeight; - var left = Math.max(0, cx - dragControl.offsetWidth); - dragControl.style.top = top + "px"; - dragControl.style.left = left + "px"; - showText.call(this, dragControl); - } - } -}; - -/** - * Displays the "ok to draw" icon and the field which is highlighted, near the crosshairs. Used with the [average line drawing]{@link CIQ.Drawing.average}. - * - * In general, any series and most studies can have an average line drawing placed on it. - * When such a plot is highlighted, this function will show the [drawOk chart control]{@link CIQ.ChartEngine.htmlControls} and display the field being highlighted. - * @memberof CIQ.ChartEngine - * @since 7.0.0 - */ -CIQ.ChartEngine.prototype.displayDrawOK = function () { - var drawable = this.controls.drawOk; - if (drawable && CIQ.Drawing) { - var drawing = CIQ.Drawing[this.currentVectorParameters.vectorType]; - if (drawing) drawing = new drawing(); - if (this.highlightedDataSetField && drawing && drawing.getYValue) { - drawable.style.display = "inline-block"; - var top = this.cy + drawable.offsetHeight; - var left = this.cx - drawable.offsetWidth; - drawable.style.top = top + "px"; - drawable.style.left = left + "px"; - drawable.querySelector(".field").innerHTML = this.translateIf( - this.highlightedDataSetField - ); - } else drawable.style.display = "none"; - } -}; - -/** - * INJECTABLE - * - * Zooms (vertical swipe / mousewheel) or pans (horizontal swipe) the chart based on a mousewheel event. - * - * Uses for following for zooming: - * - {@link CIQ.ChartEngine#zoomIn} - * - {@link CIQ.ChartEngine#zoomOut} - * - * Uses the following for panning: - * - {@link CIQ.ChartEngine#mousemoveinner} - * - * Circumvented if: - * - {@link CIQ.ChartEngine#allowZoom} is set to `false` - * - {@link CIQ.ChartEngine#captureMouseWheelEvents} is set to `false` - * - on a vertical swipe and {@link CIQ.ChartEngine#allowSideswipe} is `false` - * - * See the following options: - * - {@link CIQ.ChartEngine#reverseMouseWheel} - * - {@link CIQ.ChartEngine#mouseWheelAcceleration} - * - * @param {Event} e The event - * @return {boolean} Returns false if action is taken - * @memberof CIQ.ChartEngine.AdvancedInjectable# - * @alias mouseWheel - */ -CIQ.ChartEngine.prototype.mouseWheel = function (e) { - if (this.runPrepend("mouseWheel", arguments)) return; - if (e.preventDefault) e.preventDefault(); - if (this.openDialog !== "") return; // don't zoom when dialog or menu is open - var deltaX = e.deltaX, - deltaY = e.deltaY; - - /* - // OSX trackpad is very sensitive since it accommodates diagonal - // motion which is not relevant to us. So we ignore any changes - // in direction below the threshold time value - var threshold=50; //ms - if(Date.now()-this.lastMouseWheelEvent Math.abs(deltaX)) deltaX = 0; - else deltaY = 0; - - this.lastMouseWheelEvent = Date.now(); - if (Math.abs(deltaX) === 0 && Math.abs(deltaY) === 0) return; - - if (this.allowSideswipe && deltaX !== 0) { - this.lastMove = "horizontal"; - var delta = deltaX; - if (delta > 50) delta = 50; - if (delta < -50) delta = -50; - this.grabbingScreen = true; - if (!this.currentPanel) this.currentPanel = this.chart.panel; - this.grabStartX = CIQ.ChartEngine.crosshairX; - this.grabStartY = CIQ.ChartEngine.crosshairY; - this.grabStartScrollX = this.chart.scroll; - this.grabStartScrollY = this.currentPanel.yAxis.scroll; - this.grabStartMicropixels = this.micropixels; - this.grabStartPanel = this.currentPanel; - this.mousemoveinner( - CIQ.ChartEngine.crosshairX - delta, - CIQ.ChartEngine.crosshairY - ); - this.updateChartAccessories(); - this.grabbingScreen = false; - return; - } - this.lastMove = "vertical"; - if (!this.allowZoom) return; - if (!this.displayInitialized) return; - /* originally added to address a magic mouse issue - removing this code because it is affecting new Macs which seem to come back for more zooming immediately causing uneven zooming. - if(this.wheelInMotion) return; - this.wheelInMotion=true; - setTimeout(function(self){return function(){self.wheelInMotion=false;};}(this), 40); - */ - if (!deltaY) { - if (CIQ.wheelEvent == "mousewheel") { - deltaY = (-1 / 40) * e.wheelDelta; - if (e.wheelDeltaX) deltaX = (-1 / 40) * e.wheelDeltaX; - } else { - deltaY = e.detail; - } - } - if (typeof e.deltaMode == "undefined") - e.deltaMode = e.type == "MozMousePixelScroll" ? 0 : 1; - - //var distance=e.deltaX; - //if(!distance) distance=e.deltaY; - var distance = -deltaY; - if (e.deltaMode == 1) { - // 1 is line mode so we approximate the distance in pixels, arrived at through trial and error - distance *= 33; - } - - var pctIn = null; - var pctOut = null; - // Calculate the percentage change to the chart. Arrived at heuristically, cube root of the mousewheel distance. - // The multipliers are adjusted to take into consideration reversed compounding rates between a zoomin and a zoomout - if (this.mouseWheelAcceleration) { - var multiplier = Math.max(Math.pow(Math.abs(distance), 0.3), 1); - pctIn = 1 - 0.1 * multiplier; - pctOut = 1 + 0.2 * multiplier; - } - - this.zoomInitiatedByMouseWheel = true; - - if (distance > 0) { - if (this.reverseMouseWheel) this.zoomOut(null, pctOut); - else this.zoomIn(null, pctIn); - } else if (distance < 0) { - if (this.reverseMouseWheel) this.zoomIn(null, pctIn); - else this.zoomOut(null, pctOut); - } - if (this.runAppend("mouseWheel", arguments)) return; - return false; -}; - -/** - * This code prevents the browser context menu from popping up when right-clicking on a drawing or overlay. - * - * See [rightClickEventListener]{@link CIQ.ChartEngine~rightClickEventListener}. - * - * @param {object} [e=event] Event - * @return {boolean} - * - * @memberof CIQ.ChartEngine - */ -CIQ.ChartEngine.handleContextMenu = function (e) { - for (var i = 0; i < CIQ.ChartEngine.registeredContainers.length; i++) { - var stx = CIQ.ChartEngine.registeredContainers[i].stx; - if (stx) { - if (stx.anyHighlighted) { - if (e.preventDefault) e.preventDefault(); - return false; - } - } - } -}; -if (typeof document != "undefined") - document.addEventListener("contextmenu", CIQ.ChartEngine.handleContextMenu); - -/** - * Defines raw html for the chart controls. - * - * These controls can be overridden by manually placing HTML elements in the chart container with the same ID. - * - * To completely disable a chart control, programmatically set `controls[controlID]=null` where controlID is the control to disable. - * You can also set the main `htmlControls` object to null to disable all controls at once. - * @example - * var stxx=new CIQ.ChartEngine({container:document.querySelector(".chartContainer"), controls: {chartControls:null}}); - * @example - * // before calling loadChart(). Disables all controls - * stxx.controls=null; - * @example - * // before calling loadChart(). Disables only the chartControls (zoom on and out buttons) - * stxx.controls["chartControls"]=null; - * @type {object} - * @static - * @memberof CIQ.ChartEngine - * @since 5.2.0 Any id can be set to null to disable - */ -CIQ.ChartEngine.htmlControls = { - /** - * controlID for the Annotation Save button (class="stx-btn stx_annotation_save"). - * @alias CIQ.ChartEngine.htmlControls[`annotationSave`] - * @type string - * @memberof CIQ.ChartEngine.htmlControls - */ - annotationSave: - '', - /** - * controlID for the Annotation Cancel button (class="stx-btn stx_annotation_cancel"). - * @alias CIQ.ChartEngine.htmlControls[`annotationCancel`] - * @type string - * @memberof CIQ.ChartEngine.htmlControls - */ - annotationCancel: - '', - /** - * controlID for the Trash Can button / Series delete panel (class="mSticky"). Also see {@link CIQ.ChartEngine#displaySticky} - * @alias CIQ.ChartEngine.htmlControls[`mSticky`] - * @type string - * @memberof CIQ.ChartEngine.htmlControls - * @example - * // Disable the tooltip that appears when hovering over an overlay (drawing, line study, etc.). - * stxx.controls["mSticky"]=null; - */ - mSticky: - '

(right-click to deleteright-click to managedrag to change anchor time)(long-press to drag)
', - /** - * Indicator that it is OK to draw average lines on this plot line - * @alias CIQ.ChartEngine.htmlControls[`drawOk`] - * @type string - * @memberof CIQ.ChartEngine.htmlControls - * @since 7.0.0 - */ - drawOk: - '
', - /** - * Indicator that it is OK to move a study or series - * @alias CIQ.ChartEngine.htmlControls[`dragOk`] - * @type string - * @memberof CIQ.ChartEngine.htmlControls - * @since 7.1.0 - */ - dragOk: - '
', - /** - * controlID for the Horizontal Crosshair line (class="stx_crosshair stx_crosshair_x"). - * @alias CIQ.ChartEngine.htmlControls[`crossX`] - * @type string - * @memberof CIQ.ChartEngine.htmlControls - */ - crossX: - '', - /** - * controlID for the Vertical Crosshair line (class="stx_crosshair stx_crosshair_y"). - * @alias CIQ.ChartEngine.htmlControls[`crossY`] - * @type string - * @memberof CIQ.ChartEngine.htmlControls - */ - crossY: - '', - /** - * controlID for the zoom-in and zoom-out buttons (class="stx_chart_controls"). - * @alias CIQ.ChartEngine.htmlControls[`chartControls`] - * @type string - * @memberof CIQ.ChartEngine.htmlControls - */ - chartControls: - '', - /** - * controlID for the home button (class="stx_jump_today home"). - * The button goes away if you are showing the most current data. See example to manually turn it off. - * You can call `stxx.home();` programmatically. See {@link CIQ.ChartEngine#home} for more details - * @alias CIQ.ChartEngine.htmlControls[`home`] - * @type string - * @memberof CIQ.ChartEngine.htmlControls - * @example - * // disable the home button - * var stxx=new CIQ.ChartEngine({container:document.querySelector(".chartContainer"), layout:{"candleWidth": 16, "crosshair":true}}); - * stxx.controls["home"]=null; - */ - home: '', - /** - * controlID for div which floats along the X axis with the crosshair date (class="stx-float-date"). - * @alias CIQ.ChartEngine.htmlControls[`floatDate`] - * @type string - * @memberof CIQ.ChartEngine.htmlControls - */ - floatDate: '', - /** - * controlID for div which controls the handle to resize panels (class="stx-ico-handle"). - * @alias CIQ.ChartEngine.htmlControls[`handleTemplate`] - * @type string - * @memberof CIQ.ChartEngine.htmlControls - * @example - * // example to hide the handle and prevent resizing of panels - * .stx-ico-handle { - * display: none; - * } - */ - handleTemplate: - ' ', - /** - * controlID for the div which hosts the panel title (symbol name, study name ) and the study control icons on the on the upper left hand corner of each panel (class="stx-panel-control") - * This control can not be disabled, but can be manipulated using the corresponding CSS style classes. - * On the main chart panel, `stx-chart-panel` is added to the class definition ( in addition to `stx-panel-title` which just controls the tile) so you can manipulate the entire chart controls section, separately from the rest of the study panel controls. - * - * @example - * // example to hide the chart symbol title - * .stx-panel-control.stx-chart-panel .stx-panel-title{ - * display:none; - * } - * - * // for backwards compatibility, this is still supported: - * .chart-title{ - * display : none; - * } - * - * @example - * // example to hide all panels titles - * .stx-panel-control .stx-panel-title{ - * display:none; - * } - * - * @alias CIQ.ChartEngine.htmlControls[`iconsTemplate`] - * @type string - * @memberof CIQ.ChartEngine.htmlControls - */ - iconsTemplate: - '
', - /** - * controlID for grabber which sits to right of baseline so it can be moved. - * @alias CIQ.ChartEngine.htmlControls[`baselineHandle`] - * @type string - * @memberof CIQ.ChartEngine.htmlControls - */ - baselineHandle: - '', - /** - * Holds notifications displayed by the chart. See {@link CIQ.ChartEngine#displayNotification}. - * - * @alias CIQ.ChartEngine.htmlControls[`notificationTray`] - * @type string - * @memberof CIQ.ChartEngine.htmlControls - * @since 8.0.0 - */ - notificationTray: - '
' -}; - -/** - * Appends additional chart controls and attaches a click event handler. - * - * @param {string} controlClass CSS class to attach to the control element. - * @param {string} controlLabel Descriptive name for the control; appears in tooltip. - * @param {function} clickHandler Called when the control is selected. - * @return {node} Reference to the new control element. - * - * @memberof CIQ.ChartEngine - * @since 7.3.0 - */ -CIQ.ChartEngine.prototype.registerChartControl = function ( - controlClass, - controlLabel, - clickHandler -) { - var controls = this.controls; - if (!controls || !controls.chartControls) return; - if (controls.chartControls.querySelector("." + controlClass)) return; - var customButton = null; - var zoomInControl = controls.chartControls.querySelector(".stx-zoom-in"); - if (zoomInControl) { - customButton = document.createElement("span"); - customButton.innerHTML = - '' + controlLabel + ""; - customButton.className = "stx-chart-control-button " + controlClass; - zoomInControl.parentNode.appendChild(customButton); - - if (clickHandler) CIQ.safeClickTouch(customButton, clickHandler); - if (!CIQ.touchDevice) { - this.makeModal(customButton); - } - - return customButton; - } -}; - -/** - * INJECTABLE - * - * Zooms the chart out. The chart is zoomed incrementally by the percentage indicated each time this is called. - * @param {Event} e The mouse click event, if it exists (from clicking on the chart control) - * @param {number} pct The percentage, **in decimal equivalent**, to zoom out the chart. Default is 1/0.7 (~1.42), to reverse the 0.7 (30%) multiplier used in {@link CIQ.ChartEngine.ChartEngine#zoomIn} - * @example - * // 30% zoom adjustment - * zoomOut(null, 1.3); - * @memberof CIQ.ChartEngine - * @since 4.0.0 If both {@link CIQ.ChartEngine.Chart#allowScrollPast} and {@link CIQ.ChartEngine.Chart#allowScrollFuture} are set to false, the zoom operation will stop mid animation to prevent white space from being created. - */ -CIQ.ChartEngine.prototype.zoomOut = function (e, pct) { - if (this.runPrepend("zoomOut", arguments)) return; - if (this.preferences.zoomOutSpeed) pct = this.preferences.zoomOutSpeed; - else if (!pct) pct = 1 / 0.7; - if (e && e.preventDefault) e.preventDefault(); - this.cancelTouchSingleClick = true; - - var self = this; - function closure(chart) { - return function (candleWidth) { - self.zoomSet(candleWidth, chart); - if (self.animations.zoom.hasCompleted) { - if (self.runAppend("zoomOut", arguments)) return; - self.changeOccurred("layout"); - if (self.continuousZoom) self.continuousZoom.execute(true); - } - }; - } - - for (var chartName in this.charts) { - var chart = this.charts[chartName]; - - var newTicks = (chart.width * pct) / this.layout.candleWidth; - if ( - chart.allowScrollFuture === false && - chart.allowScrollPast === false && - newTicks > chart.dataSet.length - ) { - // make sure we keep candles big enough to show all data so no white space is created on either side. - newTicks = chart.dataSet.length; - } - var newCandleWidth = this.chart.width / newTicks; - - this.layout.setSpan = null; - this.layout.range = null; - this.animations.zoom.run( - closure(chart), - this.layout.candleWidth, - newCandleWidth - ); - } -}; - -/** - * INJECTABLE - * - * Zooms the chart in. The chart is zoomed incrementally by the percentage indicated each time this is called. - * @param {Event} e The mouse click event, if it exists (from clicking on the chart control) - * @param {number} pct The percentage, **in decimal equivalent**, to zoom in the chart. Default is 0.7 (30%) - * @example - * // 30% zoom adjustment - * zoomIn(null, 0.7); - * @memberof CIQ.ChartEngine - */ -CIQ.ChartEngine.prototype.zoomIn = function (e, pct) { - if (this.runPrepend("zoomIn", arguments)) return; - if (this.preferences.zoomInSpeed) pct = this.preferences.zoomInSpeed; - else if (!pct) pct = 0.7; - if (e && e.preventDefault) e.preventDefault(); - this.cancelTouchSingleClick = true; - - var self = this; - function closure(chart) { - return function (candleWidth) { - self.zoomSet(candleWidth, chart); - if (self.animations.zoom.hasCompleted) { - if (self.runAppend("zoomIn", arguments)) return; - self.changeOccurred("layout"); - if (self.continuousZoom) self.continuousZoom.execute(); - } - }; - } - - for (var chartName in this.charts) { - var chart = this.charts[chartName]; - - var newTicks = (chart.width * pct) / this.layout.candleWidth; - // At some point the zoom percentage compared to the bar size may be too small, we get stuck at the same candle width. - // (because we ceil() and 0.5 candle when we set the maxTicks in setCandleWidth()). - // So we want to force a candle when this happens. - if (chart.maxTicks - newTicks < 1) newTicks = chart.maxTicks - 1; - if (newTicks < this.minimumZoomTicks) newTicks = this.minimumZoomTicks; - var newCandleWidth = this.chart.width / newTicks; - - this.layout.setSpan = null; - this.layout.range = null; - this.animations.zoom.run( - closure(chart), - this.layout.candleWidth, - newCandleWidth - ); - } -}; - -/** - * INJECTABLE - * Animation Loop - * - * Registers mouse events for the crosshair elements (to prevent them from picking up events) - * @memberof CIQ.ChartEngine.AdvancedInjectable# - * @alias createCrosshairs - */ -CIQ.ChartEngine.prototype.createCrosshairs = function () { - if (this.runPrepend("createCrosshairs", arguments)) return; - if ( - !this.manageTouchAndMouse || - (this.mainSeriesRenderer && this.mainSeriesRenderer.nonInteractive) - ) - return; - - var crossX = this.controls.crossX, - crossY = this.controls.crossY; - if (crossX) { - if (!crossX.onmousedown) { - crossX.onmousedown = function (e) { - if (e.preventDefault) e.preventDefault(); - return false; - }; - } - } - - if (crossY) { - if (!crossY.onmousedown) { - crossY.onmousedown = function (e) { - if (e.preventDefault) e.preventDefault(); - return false; - }; - } - } - - this.runAppend("createCrosshairs", arguments); -}; - -let warned = false; -CIQ.ChartEngine.prototype.mousemoveinner = - CIQ.ChartEngine.prototype.mousemoveinner || - function (epX, epY) { - if (!warned) - console.error( - "interaction feature requires activating movement feature." - ); - warned = true; - }; - -}; - - -let __js_standard_markers_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -// Make sure this file is only executed once -if (!CIQ.Marker) { - CIQ.ChartEngine.helpersToRegister.push(function (stx) { - stx.markerHelper = { - chartMap: {}, - classMap: {}, - domMarkers: [], - highlighted: [] - }; - }); - - /** - * Adds a marker to the chart. - * - * @param {CIQ.Marker} marker The marker to add. - * - * @memberOf CIQ.ChartEngine - * @private - * @since 7.2.0 Checks for the `prepareForHolder` method on the markers's `stxNodeCreator` and - * calls that function if present. - */ - CIQ.ChartEngine.prototype.addToHolder = function (marker) { - var panel = this.panels[marker.params.panelName]; - if (!panel) return; - - // if (!this.markerHelper) this.makeMarkerHelper(); - - var mparams = marker.params, - node = marker.node, - nodeCreator = marker.stxNodeCreator; - if (nodeCreator && nodeCreator.prepareForHolder) { - node = nodeCreator.prepareForHolder(marker); - } - if (mparams.chartContainer) { - this.container.appendChild(marker.node); - } else if (mparams.includeAxis) { - panel.holder.appendChild(marker.node); - } else { - panel.subholder.appendChild(node); - } - - marker.chart = panel.chart; - if (nodeCreator && nodeCreator.addToHolder) nodeCreator.addToHolder(marker); - if (nodeCreator && nodeCreator.expand) { - CIQ.Marker.initializeScrollBehavior(nodeCreator); - } - }; - - /** - * Gets an array of markers - * @private - * @param {string} type The type of comparison "panelName","label","all" - * @param {string} comparison The value to compare to - * @return {array} The marker array - */ - CIQ.ChartEngine.prototype.getMarkerArray = function (type, comparison) { - var arr = []; - for (var label in this.markers) { - for (var i = 0; i < this.markers[label].length; i++) { - var marker = this.markers[label][i]; - if (type == "panelName") { - if (marker.params.panelName == comparison) arr.push(marker); - } else if (type == "label") { - if (label == comparison) arr.push(marker); - } else if (type == "all") { - arr.push(marker); - } - } - } - return arr; - }; - - /** - * Removes the marker from the chart - * @private - * @param {CIQ.Marker} marker The marker to remove - * @memberOf CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.removeFromHolder = function (marker) { - var panel = this.panels[marker.params.panelName]; - if (panel) { - if (marker.node.parentNode == panel.holder) - panel.holder.removeChild(marker.node); - else if (marker.node.parentNode == panel.subholder) - panel.subholder.removeChild(marker.node); - else if (marker.node.parentNode == this.container) - this.container.removeChild(marker.node); - } - // Remove from label map - var labels = this.markers[marker.params.label]; - if (!labels) return; - var i; - for (i = 0; i < labels.length; i++) { - if (labels[i] === marker) { - labels.splice(i, 1); - break; - } - } - - // remove from chart map - var chartMap = this.markerHelper.chartMap[marker.chart.name]; - if (chartMap) { - for (i = 0; i < chartMap.markers.length; i++) { - if (chartMap.markers[i] === marker) { - chartMap.markers.splice(i, 1); - break; - } - } - } - - // remove from class map - var classMap = this.markerHelper.classMap[marker.className]; - if (classMap) { - var panelArray = classMap[marker.params.panelName]; - if (panelArray) { - for (i = 0; i < panelArray.length; i++) { - if (panelArray[i] === marker) { - panelArray.splice(i, 1); - break; - } - } - } - } - }; - - /** - * Moves the markers from one panel to another - * Useful when renaming panels - * @param {string} fromPanelName The panel to move markers from - * @param {string} toPanelName The panel to move markers to - * @memberOf CIQ.ChartEngine - * @since 2016-07-16 - */ - CIQ.ChartEngine.prototype.moveMarkers = function ( - fromPanelName, - toPanelName - ) { - var arr = this.getMarkerArray("panelName", fromPanelName); - for (var i = 0; i < arr.length; i++) { - arr[i].params.panelName = toPanelName; - } - for (var className in this.markerHelper.classMap) { - var tmp = this.markerHelper.classMap[className][fromPanelName]; - if (tmp) { - this.markerHelper.classMap[className][toPanelName] = tmp; - delete this.markerHelper.classMap[className][fromPanelName]; - } - } - }; - - /** - * Establishes the tick value for any markers that have a "date" specified. It tries to be efficient, not recalculating - * unless the size of the dataSet for a chart has actually changed - * @private - * @memberOf CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.establishMarkerTicks = function () { - // if (!this.markerHelper) this.makeMarkerHelper(); - var chartMap = this.markerHelper.chartMap; - for (var chart in chartMap) { - var chartEntry = chartMap[chart]; - if (chartEntry.dataSetLength == this.charts[chart].dataSet.length) - continue; - for (var i = 0; i < chartEntry.markers.length; i++) { - this.setMarkerTick(chartEntry.markers[i]); - } - } - }; - - /** - * Figures out the position of a future marker but only if it is displayed on the screen. - * @param {CIQ.Marker} marker The marker to check - * @memberOf CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.futureTickIfDisplayed = function (marker) { - var chart = marker.chart; - if (chart.dataSet.length < 1) return; - var xaxisDT = chart.xaxis[chart.xaxis.length - 1].DT; - - xaxisDT = new Date(xaxisDT.getTime() - this.timeZoneOffset * 60000); - if (marker.params.x > xaxisDT) return; // not displayed on screen yet - - // It should be displayed on the screen now so find the exact tick - var futureTicksOnScreen = chart.maxTicks - chart.dataSegment.length; - var ticksToSearch = chart.dataSet.length + futureTicksOnScreen; - var pms, qms; - var dt = new Date(+chart.dataSet[chart.dataSet.length - 1].DT); - - var iter = this.standardMarketIterator(dt, null, chart); - - var dms = marker.params.x.getTime(); - for (var j = chart.dataSet.length; j < ticksToSearch; j++) { - pms = dt.getTime(); - dt = iter.next(); - qms = dt.getTime(); - // If the event lands on that day, or if the event landed between bars - if (qms == dms) { - marker.tick = j; - return; - } else if (qms > dms && pms < dms) { - marker.tick = Math.max(j - 1, 0); - return; - } - } - }; - - /** - * Establishes the tick value for the specified marker. We do this to avoid calculating the date every time we want - * to place the marker. Converting date to tick is a very expensive operation! - * @param {CIQ.Marker} marker The marker for which to establish the tick - * @private - * @memberOf CIQ.ChartEngine - */ - CIQ.ChartEngine.prototype.setMarkerTick = function (marker) { - var chart = marker.chart; - if (marker.params.xPositioner == "master" && marker.params.x) { - marker.tick = Math.floor(marker.params.x / this.layout.periodicity); - return; - } else if (marker.params.xPositioner == "date" && marker.params.x) { - var pms, qms; - var dms = marker.params.x.getTime(); - for (var i = 0; i < chart.dataSet.length; i++) { - var quotes = chart.dataSet[i]; - qms = quotes.DT.getTime(); - pms = qms; - if (i > 0) pms = chart.dataSet[i - 1].DT.getTime(); - // If the event lands on that day, or if the event landed between bars - if (qms == dms) { - marker.tick = i; - return; - } else if (qms > dms && pms < dms) { - marker.tick = Math.max(i - 1, 0); - return; - } else if (dms < qms) { - marker.tick = null; - // marker date is in distant past, shortcircuit the logic for performance. - return; - } - } - if (chart.dataSet.length < 1) return; - var dt = new Date(+chart.dataSet[i - 1].DT); - if (dt.getTime() < dms) marker.params.future = true; - marker.tick = null; // reset in case we had figured it out with an earlier dataset - } - }; - - /** - * INJECTABLE - * Animation Loop - * - * Iterates through all marker handlers, calling their corresponding custom `placementFunction` or {@link CIQ.ChartEngine#defaultMarkerPlacement} if none defined. - * @memberOf CIQ.ChartEngine.AdvancedInjectable# - * @alias positionMarkers - */ - CIQ.ChartEngine.prototype.positionMarkers = function () { - var self = this, - chart = this.chart; - if (!self.markerHelper) return; - - function draw() { - if (self.runPrepend("positionMarkers", arguments)) return; - self.markerTimeout = null; - for (var className in self.markerHelper.classMap) { - for (var panelName in self.markerHelper.classMap[className]) { - var arr = self.markerHelper.classMap[className][panelName]; - var panel = self.panels[panelName]; - if (arr.length) { - var params = { - stx: self, - arr: arr, - panel: panel - }; - params.firstTick = panel.chart.dataSet.length - panel.chart.scroll; - params.lastTick = params.firstTick + panel.chart.dataSegment.length; - - var fn = arr[0].constructor.placementFunction; // Some magic, this gets the static member "placementFunction" of the class (not the instance) - if (fn) { - fn(params); - } else { - self.defaultMarkerPlacement(params); - } - } - } - } - self.runAppend("positionMarkers", arguments); - } - - if (this.markerDelay || this.markerDelay === 0) { - if (!this.markerTimeout) - this.markerTimeout = setTimeout(draw, this.markerDelay); - } else { - draw(); - } - var starting = this.getFirstLastDataRecord(chart.dataSegment, "tick"), - ending = this.getFirstLastDataRecord(chart.dataSegment, "tick", true); - if (!starting || !ending) return; // return if dataSegment is full of nulls or undefined values or maybe its just empty - - var markers = this.getMarkerArray("all"); - for (var i = 0; i < markers.length; i++) { - var marker = markers[i], - nodeCreator = marker.stxNodeCreator; - if (starting.tick <= marker.tick && marker.tick <= ending.tick) { - // if markers are off screen don't draw them - if (nodeCreator && nodeCreator.drawMarker) - nodeCreator.drawMarker(marker); - } else if (marker.attached && nodeCreator.expand) { - // hide the popup of any perf markers outside the dataSegment - nodeCreator.expand.style.visibility = "hidden"; - } - } - }; - - /** - * A marker is a DOM object that is managed by the chart. - * - * Makers are placed in containers which are `div` elements whose placement and size correspond with a panel on the - * chart. A container exists for each panel. - * - * A marker's primary purpose is to provide additional information for a data point on the chart. As such, markers - * can be placed by date, tick, or bar to control their position on the x-axis, and by value (price) to control their - * position on the y-axis. Additional default positioning is also available, including the ability to create custom - * positioning logic. Once the positioning logic is established for markers, they are repositioned as needed when the - * user scrolls or zooms the chart. - * - * Alternatively, a marker can also be placed at an absolute position using CSS positioning, in which case the chart - * does not control the marker's positioning. - * - * The default placement function for any markers is {@link CIQ.ChartEngine#defaultMarkerPlacement}. - * - * See the {@tutorial Markers} tutorial for additional implementation details and information about managing - * performance on deployments requiring a large number of markers. - * - * @name CIQ.Marker - * @param {Object} params Parameters that describe the marker. - * @param {CIQ.ChartEngine} params.stx The chart to which the marker is attached. - * @param {*} params.x A valid date, tick, or bar (depending on the selected `xPositioner`) used to select a candle to - * which the marker is associated. - * @param {Number} params.y A valid value for positioning the marker on the y-axis (depending on selected `yPositioner`). - * If this value is not provided, the marker is set "above_candle" as long as a valid candle is selected - * by `params.x`. - * @param {HTMLElement} [params.node] The HTML element that contains the marker. This element should be detached from the - * DOM. If an element is not provided, an empty `div` is created. You can create your own or use the provided {@link CIQ.Marker.Simple} and {@link CIQ.Marker.Performance} node creators. - * @param {string} params.panelName="chart" The name of the panel to which the `node` is attached. Defaults to the main - * chart panel. - * @param {string} [params.xPositioner="date"] Determines the x-axis position of the marker. - * Values include: - * - "date" — `params.x` must be set to a JavaScript date object. This will be converted to the closest `masterData` - * position if the provided date does not exactly match any existing points. Be sure the same timezone as masterData is used. - * - "master" — `params.x` must be set to a `masterData` position. - * - "bar" — `params.x` must be set to a `dataSegment` position. - * - "none" — Use CSS positioning; `params.x` is not used. - * @param {string} [params.yPositioner="value"] Determines the y-axis position of the marker. - * Values include: - * - "value" — `params.y` must be set to an exact y-axis value. If `params.y` is omitted, the y-axis position defaults - * to "above_candle". - * - "above_candle" — Positions the marker right above the candle or line. If more than one marker is at the same position, - * the markers are aligned upwards from the first. The `params.y` value is not used. - * - "below_candle" — Positions the marker right below the candle or line. If more than one marker is at the same position, - * the markers are aligned downwards from the first. The `params.y` value is not used. - * - "under_candle" — Deprecated; same as "below_candle". - * - "on_candle" — Position the marker in the center of the candle or line, covering it. If more than one marker is at the - * same position, the markers are aligned downwards from the first. The `params.y` value is not used. - * - "top" — Position the marker at the top of the chart, right below the margin. If more than one marker is at the same - * position, the markers are aligned downwards from the first. The `params.y` value is not used. - * - "bottom" — Position the marker at the bottom of the chart, right above the margin. If more than one marker is at the - * same position, the markers are aligned upwards from the first. The `params.y` value is not used. - * - "none" — Use CSS positioning; `params.y` is not used. - * @param {boolean} [params.permanent=false] The marker stays on the chart even when the chart is re-initialized by a symbol - * change, call to `loadChart()` or `initializeChart()`, and so forth. - * @param {string} [params.label="generic"] A label for the marker. Multiple markers can be assigned the same label, which - * allows them to be deleted simultaneously. - * @param {boolean} [params.includeAxis=false] If true, then the marker can display on the x- or y-axis. Otherwise, it is cropped - * at the axis edge. - * @param {Boolean} [params.chartContainer] If true, then the marker is placed directly in the chart container as opposed to in a - * container, or holder, node. When placing the marker directly in the chart container, the z-index setting for the marker should - * be set in relation to the z-index of other holders in order to place the marker above or below markers inside the holders. - * @constructor - * @since - * - 15-07-01 - * - 05-2016-10 Added the following `params.yPositioner` values: "value", "above_candle", - * "below_candle", "on_candle", "top", and "bottom". - * @version ChartIQ Advanced Package - * @example - * new CIQ.Marker({ - * stx: stxx, - * xPositioner: "date", - * yPositioner: "value", - * x: someDate, - * y: somePrice, - * label: "events", - * node: newNode - * }); - */ - CIQ.Marker = - CIQ.Marker || - function (params) { - this.params = { - xPositioner: "date", - yPositioner: "value", - panelName: "chart", - permanent: false, - label: "generic", - includeAxis: false - }; - CIQ.extend(this.params, params); - if (!this.params.node) { - this.params.node = document.createElement("DIV"); - } - var stx = this.params.stx; - if (!stx) { - console.log("Marker created without specifying stx"); - return; - } - if (!this.className) this.className = "CIQ.Marker"; - - // Switcheroo. If a NodeCreator is passed in, then we change the marker - // to reference the actual DOM node and then we add stxNodeCreator to the - // marker so that we can reference it if need be - if (CIQ.derivedFrom(this.params.node, CIQ.Marker.NodeCreator)) { - this.stxNodeCreator = this.params.node; - this.node = this.stxNodeCreator.node; - } else { - this.node = this.params.node; - } - - // if (!stx.markerHelper) stx.makeMarkerHelper(); - - var label = this.params.label; - if (!stx.markers[label]) stx.markers[label] = []; - stx.markers[label].push(this); - - var panel = stx.panels[this.params.panelName]; - this.chart = panel.chart; - - // Put it in the map of charts - if (!stx.markerHelper.chartMap[this.chart.name]) { - stx.markerHelper.chartMap[this.chart.name] = { - dataSetLength: 0, - markers: [] - }; - } - stx.markerHelper.chartMap[this.chart.name].markers.push(this); - - var classMap = stx.markerHelper.classMap[this.className]; - if (!classMap) classMap = stx.markerHelper.classMap[this.className] = {}; - if (!classMap[this.params.panelName]) - classMap[this.params.panelName] = []; - classMap[this.params.panelName].push(this); - - var defer = this.stxNodeCreator && this.stxNodeCreator.deferAttach; - if (!defer) stx.addToHolder(this); - stx.setMarkerTick(this); - - if (this.stxNodeCreator && this.stxNodeCreator.drawMarker) - this.stxNodeCreator.drawMarker(this); - }; - - /** - * Removes the marker from the chart object - * @memberOf CIQ.Marker - * @since 15-07-01 - */ - CIQ.Marker.prototype.remove = function () { - this.params.stx.removeFromHolder(this); - }; - - /** - * Called when a marker node is clicked. Checks to see whether the node has its own click - * function and, if it does, calls that function, passing all arguments to it. - * - * @param {object} params Configuration parameters. - * @param {number} params.cx The clientX coordinate of the click event. - * @param {number} params.cy The clientY coordinate of the click event. - * @param {CIQ.ChartEngine.Panel} params.panel Panel where the click took place. - * - * @memberof CIQ.Marker - * @since - * - 7.2.0 - * - 8.0.0 Signature changed to accept the `params` object. - */ - CIQ.Marker.prototype.click = function (params) { - if (typeof arguments[0] === "number") { - params = { cx: arguments[0], cy: arguments[1], panel: arguments[3] }; - } - - let { cx, cy, panel } = params; - if (!this.params.stx) return; // some markers don't know the engine. In that scenario do nothing. - var node = this.params.node; - if (node.click) node.click(cx, cy, this, panel); - }; - - /** - * Called when a marker node is double-clicked. - * - * Override this function with your own implementation. Return a truthy value to prevent - * {@link CIQ.ChartEngine#doubleClick} from dispatching the "doubleClick" event and invoking - * the [doubleClickEventListener]{@link CIQ.ChartEngine~doubleClickEventListener}. - * - * @param {object} params Configuration parameters. - * @param {number} params.cx The clientX coordinate of the double-click event. - * @param {number} params.cy The clientY coordinate of the double-click event. - * @param {CIQ.ChartEngine.Panel} params.panel Panel where the double-click took place. - * @return {boolean} true to indicate the double-click event has been handled; otherwise, - * false. - * - * @alias doubleClick - * @memberof CIQ.Marker.prototype - * @virtual - * @since 8.0.0 - */ - CIQ.Marker.prototype.doubleClick = function ({ cx, cy, panel }) { - return false; - }; - - /** - * Normally the chart will take care of positioning the marker automatically but you can - * force a marker to render itself by calling this method. This will cause the marker to - * call its placement function. You might want to do this for instance if your marker morphs - * or changes position outside of the animation loop. - */ - CIQ.Marker.prototype.render = function () { - var arr = [this]; - var params = { - stx: this.params.stx, - arr: arr, - panel: this.params.stx.panels[this.params.panelName], - showClass: this.showClass - }; - this.constructor.placementFunction(params); - }; - - /** - * Removes all markers with the specified label from the chart object - * @param {CIQ.ChartEngine} stx The chart object - * @param {string} label The label - * @memberOf CIQ.Marker - * @since 15-07-01 - */ - CIQ.Marker.removeByLabel = function (stx, label) { - var arr = stx.getMarkerArray("label", label); - for (var i = 0; i < arr.length; i++) { - var marker = arr[i]; - stx.removeFromHolder(marker); - if (marker.stxNodeCreator && marker.stxNodeCreator.remove) { - marker.stxNodeCreator.remove(marker); - } - } - stx.draw(); - }; - - /** - * - * Content positioner for any markers using the 'stx-marker-expand' class, - * this will consider the marker node's location within its container and determine where to - * place the content, be it to the left or right/top or bottom of the marker node (so it is all showing) - * @memberOf CIQ.Marker - * @param {HTMLElement} node The HTML element representing the marker which has content - * @since 5.1.2 - */ - CIQ.Marker.positionContentVerticalAndHorizontal = function (node) { - var content_node = node.querySelectorAll(".stx-marker-expand")[0]; - if (!content_node || !CIQ.trulyVisible(content_node)) return; - - var offsetHeight = content_node.offsetHeight; - var nodeStyle = content_node.style; - nodeStyle.left = nodeStyle.right = ""; // reset content to right of node - nodeStyle.bottom = nodeStyle.top = ""; // reset content to bottom of node - - var computedNodeStyle = getComputedStyle(content_node); - var contentLeft = computedNodeStyle.left; - var contentBottom = computedNodeStyle.bottom; - - var leftPxOfContent = node.offsetLeft + parseInt(contentLeft, 10); - var bottomContentInt = parseInt(contentBottom, 10); - - // Subtract the difference between the content top and the parent height from the offsetTop - var topPxOfContent = - node.offsetTop - (bottomContentInt + offsetHeight - node.offsetHeight); - - var offsetMaxWidth = node.parentNode.offsetWidth; - var offsetMaxHeight = node.parentNode.offsetHeight; - - //switch content to left of node if node is off the left of the chart or content will not fit to the right of the node - if (leftPxOfContent + content_node.offsetWidth > offsetMaxWidth) { - nodeStyle.right = contentLeft; - nodeStyle.left = "auto"; - } - - if (node.offsetTop <= offsetMaxHeight) { - //node not off the bottom of the chart - //switch content to top of node if node is off the bottom of the chart or content will not fit to the bottom of the node - if (topPxOfContent > offsetMaxHeight - offsetHeight) { - nodeStyle.top = offsetMaxHeight - node.offsetTop - offsetHeight + "px"; - nodeStyle.bottom = "auto"; - } - } else { - nodeStyle.top = offsetMaxHeight + "px"; - } - if (node.offsetTop + node.offsetHeight >= 0) { - //node not off the top of the chart - //switch content to bottom of node if node is off the top of the chart or content will not fit to the top of the node - if (topPxOfContent < 0) { - nodeStyle.top = -node.offsetTop + "px"; - nodeStyle.bottom = "auto"; - } - } else { - nodeStyle.bottom = "0px"; - } - }; - - /** - * Initializes the scroll behavior of marker expands. - * - * For proper styling, the perfect scrollbar requires elements to have been mounted on the DOM - * prior to initialization. As a result, this function should only be called on mounted nodes. - * - * @param {HTMLElement} node The marker that contains the expand for which scroll behavior is - * initialized. - * - * @memberof CIQ.Marker - * @since 8.2.0 - */ - CIQ.Marker.initializeScrollBehavior = function (node) { - const { expand } = node; - if (!expand) return; - - expand.addEventListener(CIQ.wheelEvent, (e) => e.stopPropagation()); - const { scrollbarStyling } = CIQ.UI || {}; - if (scrollbarStyling) { - scrollbarStyling.refresh(expand); - } else { - expand.style.overflowY = "scroll"; - } - }; - - /** - * The above_candle and below_candle y-positioner will usually use the high and low to place the marker. - * However, some chart renderings will draw the extent of the bar either inside or outside the high/low range. - * For those chart types, this function will return the actual high/low to be used by the marker placement function. - * This is only valid when {@link CIQ.Renderer#highLowBars} is true. - * Currently this function will handle p&f and histogram chart types. - * For any other chart type, define "markerHigh" and "markerLow" for each bar in the dataSet/dataSegment - * and these will be honored and returned. - * Note: This function may be used with any markerPlacement function to give the lowest and highest point of the bar. - * - * @memberOf CIQ.ChartEngine - * @param {Object} quote The bar's data. This can come from the chart.dataSet - * @return {Object} The high and low for the marker - * @since - * - 3.0.0 - * - 6.2.0 Will consider `Open` and `Close` if `High` and/or `Low` are missing from quote. - */ - CIQ.ChartEngine.prototype.getBarBounds = function (quote) { - var type = this.layout.chartType, - aggregation = this.layout.aggregationType; - var bounds; - if (aggregation == "pandf") - bounds = { - high: Math.max(quote.pfOpen, quote.pfClose), - low: Math.min(quote.pfOpen, quote.pfClose) - }; - else bounds = { high: quote.High, low: quote.Low }; - if (quote.markerHigh) bounds.high = quote.markerHigh; - if (quote.markerLow) bounds.low = quote.markerLow; - - var O, H, L; - if (quote.Open === undefined) O = quote.Close; - if (quote.High === undefined) H = Math.max(quote.Open || O, quote.Close); - if (quote.Low === undefined) L = Math.min(quote.Open || O, quote.Close); - if (!bounds.high && bounds.high !== 0) bounds.high = H; - if (!bounds.low && bounds.low !== 0) bounds.low = L; - return bounds; - }; - - /** - * Placement functions are responsible for positioning markers in their holder according to each marker's settings. - * They are called directly form the draw() function in the animation loop. - * Each Marker placement handler must have a corresponding `placementFunction` or this method will be used. - * - * `firstTick` and `lastTick` can be used as a hint as to whether to display a marker or not. - * - * See {@link CIQ.Marker} and {@tutorial Markers} for more details - * @memberOf CIQ.ChartEngine - * @param {Object} params The parameters - * @param {Array} params.arr The array of markers - * @param {Object} params.panel The panel to display - * @param {Number} params.firstTick The first tick displayed on the screen - * @param {Number} params.lastTick The last tick displayed on the screen - * @since 2015-09-01 On prior versions you must define your own default function. Example: `CIQ.ChartEngine.prototype.defaultMarkerPlacement = yourPlacementFunction;`. - */ - CIQ.ChartEngine.prototype.defaultMarkerPlacement = function (params) { - var panel = params.panel; - var yAxis = params.yAxis ? params.yAxis : params.panel.yAxis; - var chart = panel.chart; - var stx = params.stx; - - var showsHighs = stx.chart.highLowBars; - var plotField = chart.defaultPlotField; - if (!plotField || showsHighs) plotField = "Close"; - - var placementMap = {}; - - for (var i = 0; i < params.arr.length; i++) { - var marker = params.arr[i], - mparams = marker.params; - if (marker.params.box) continue; // do not try to position drawn markers - var node = marker.node; - // Getting clientWidth and clientHeight is a very expensive operation - // so we'll cache the results. Don't use this function if your markers change - // shape or size dynamically! - if (!marker.clientWidth) marker.clientWidth = node.clientWidth; - if (!marker.clientHeight) marker.clientHeight = node.clientHeight; - var quote = null; - - // X axis positioning logic - - var xPositioner = mparams.xPositioner, - yPositioner = mparams.yPositioner, - tick = marker.tick, - dataSet = chart.dataSet, - clientWidth = marker.clientWidth; - if (xPositioner != "none") { - if (xPositioner == "bar" && mparams.x) { - if (mparams.x < chart.xaxis.length) { - var xaxis = chart.xaxis[mparams.x]; - if (xaxis) quote = xaxis.data; - } - node.style.left = - Math.round(stx.pixelFromBar(mparams.x, chart) - clientWidth / 2) + - 1 + - "px"; - } else { - // This is a section of code to hide markers if they are off screen, and also to figure out - // the position of markers "just in time" - // the tick is conditionally pre-set by CIQ.ChartEngine.prototype.setMarkerTick depending on marker.params.xPositioner - if (!tick && tick !== 0) { - // if tick is not defined then hide, probably in distant past - if (mparams.future && chart.scroll < chart.maxTicks) { - // In future - stx.futureTickIfDisplayed(marker); // Just in time check for tick - tick = marker.tick; //copy new tick from prior function - if (!tick && tick !== 0) { - node.style.left = "-1000px"; - continue; - } - } else { - node.style.left = "-1000px"; - continue; - } - } - if (tick < dataSet.length) quote = dataSet[tick]; - marker.leftpx = Math.round( - stx.pixelFromTick(tick, chart) - chart.left - clientWidth / 2 - ); - marker.rightEdge = marker.leftpx + clientWidth; - node.style.left = marker.leftpx + "px"; - if (tick < params.firstTick && marker.rightEdge < chart.left - 50) - continue; // off screen, no need to reposition the marker (accounting 50px for any visual effects) - } - if (!quote) quote = dataSet[dataSet.length - 1]; // Future ticks based off the value of the current quote - } else if (yPositioner.indexOf("candle") > -1) { - // candle positioning, find the quote - var left = getComputedStyle(node).left; - if (left) { - var bar = stx.barFromPixel(parseInt(left, 10), chart); - if (bar >= 0) { - quote = chart.xaxis[bar].data; - if (!quote) quote = dataSet[dataSet.length - 1]; // Future ticks based off the value of the current quote - } - } - } - - node.style.top = "auto"; // don't use top positioning with DOM markers - // Y axis positioning logic - var y = mparams.y, - clientHeight = marker.clientHeight, - val; - if (yPositioner != "none") { - var placementKey = yPositioner + "-" + node.style.left; - var height = mparams.chartContainer ? stx.height : panel.yAxis.bottom; - var bottom = 0, - bottomAdjust = 0; - if (typeof placementMap[placementKey] == "undefined") { - placementMap[placementKey] = 0; - } - bottomAdjust = placementMap[placementKey]; - placementMap[placementKey] += clientHeight; - - if (yPositioner == "value" && (y || y === 0)) { - bottom = - Math.round( - height - stx.pixelFromPrice(y, panel, yAxis) - clientHeight / 2 - ) + "px"; - } else if ( - (yPositioner == "below_candle" || yPositioner == "under_candle") && - quote - ) { - // under_candle deprecated - val = quote[plotField]; - if (showsHighs) - val = stx.getBarBounds(quote)[yAxis.flipped ? "high" : "low"]; - bottom = - Math.round( - height - - stx.pixelFromPrice(val, panel, yAxis) - - clientHeight - - bottomAdjust - ) + "px"; - } else if (yPositioner == "on_candle" && quote) { - val = quote[plotField]; - if (showsHighs) val = (quote.Low + quote.High) / 2; - bottom = - Math.round( - height - - stx.pixelFromPrice(val, panel, yAxis) - - clientHeight / 2 - - bottomAdjust - ) + "px"; - } else if (yPositioner == "top") { - bottom = - Math.round(height - clientHeight - bottomAdjust - panel.top) + "px"; - } else if (yPositioner == "bottom") { - bottom = Math.round(bottomAdjust) + "px"; - } else if (quote) { - //above_candle - val = quote[plotField]; - if (showsHighs) - val = stx.getBarBounds(quote)[yAxis.flipped ? "low" : "high"]; - bottom = - Math.round( - height - stx.pixelFromPrice(val, panel, yAxis) + bottomAdjust - ) + "px"; - } - if (node.style.bottom != bottom) node.style.bottom = bottom; - } - CIQ.Marker.positionContentVerticalAndHorizontal(node); - } - }; - - /** - * Base class to create an empty marker node that can then be styled. Used by {@link CIQ.Marker.Simple} and {@link CIQ.Marker.Performance}. - * It is strongly recommended that you extend this class if you're building your own marker class. - * See {@tutorial Markers} tutorials for additional implementation instructions. - * @name CIQ.Marker.NodeCreator - * @constructor - */ - CIQ.Marker.NodeCreator = function () {}; - - CIQ.Marker.NodeCreator.toNode = function () { - return this.node; - }; - - /** - * Creates simple HTML nodes that can be used with a {@link CIQ.Marker} - * - * See {@tutorial Markers} tutorials for additional implementation instructions. - * @name CIQ.Marker.Simple - * @constructor - * @param {Object} params Parameters to describe the marker - * @param {string} params.type The marker type to be drawn. - *
Available options are: - * - "circle" - * - "square" - * - "callout" - * @param {string} params.headline The headline text to pop-up when clicked. - * @param {string} [params.category] The category class to add to your marker. - *
Available options are: - * - "news" - * - "earningsUp" - * - "earningsDown" - * - "dividend" - * - "filing" - * - "split" - * @param {string} [params.story] The story to pop-up when clicked. - * @example - * var datum = { - * type: "circle", - * headline: "This is a Marker for a Split", - * category: "split", - * story: "This is the story of a split" - * }; - * - * var mparams = { - * stx: stxx, - * label: "Sample Events", - * xPositioner: "date", - * x: aDate, - * node: new CIQ.Marker.Simple(datum) - * }; - * - * var marker = new CIQ.Marker(mparams); - */ - CIQ.Marker.Simple = function (params) { - var node = (this.node = document.createElement("div")); - node.className = "stx-marker"; - node.classList.add(params.type); - if (params.category) node.classList.add(params.category); - var visual = CIQ.newChild(node, "div", "stx-visual"); - CIQ.newChild(node, "div", "stx-stem"); - - var expand; - if (params.type == "callout") { - var content = CIQ.newChild(visual, "div", "stx-marker-content"); - CIQ.newChild(content, "h4", null, params.headline); - expand = CIQ.newChild(content, "div", "stx-marker-expand"); - CIQ.newChild(expand, "p", null, params.story); - } else { - expand = CIQ.newChild(node, "div", "stx-marker-expand"); - CIQ.newChild(expand, "h4", null, params.headline); - CIQ.newChild(expand, "p", null, params.story); - CIQ.safeClickTouch(expand, function (e) { - node.classList.toggle("highlight"); - }); - } - - function cb() { - CIQ.Marker.positionContentVerticalAndHorizontal(node); - } - CIQ.safeClickTouch(visual, function (e) { - node.classList.toggle("highlight"); - setTimeout(cb, 10); - }); - this.nodeType = "Simple"; - this.expand = expand; - }; - - CIQ.inheritsFrom(CIQ.Marker.Simple, CIQ.Marker.NodeCreator, false); -} - -}; - -// @jscrambler disable functionOutlining -let __js_standard_market_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; -var timezoneJS = - typeof _timezoneJS !== "undefined" ? _timezoneJS : _exports.timezoneJS; - -var HOUR_MILLIS = 60000 * 60; -var DAY_MILLIS = HOUR_MILLIS * 24; - -var ExistingMarket = CIQ.Market; - -/** - * The market class is what the chart uses to to manage market hours for the different exchanges. - * It uses `Market Definitions` to decide when the market is open or closed. - * Although you can construct many market classes with different definitions to be used in your functions, only one market definition can be attached to the chart at any given time. - * Once a market is defined, an [iterator]{@link CIQ.Market#newIterator} can be created to traverse through time, taking into account the market hours. - * Additionally, a variety of convenience functions can be used to check the market status, such as {@link CIQ.Market#isOpen} or {@link CIQ.Market#isMarketDay}. - * - * A chart will operate 24x7, unless a market definition with rules is assigned to it. - * See {@link CIQ.ChartEngine#setMarket} and {@link CIQ.ChartEngine#setMarketFactory} for instructions on how to assign a market definition to a chart. - * - * The chart also provides convenience functions that allows you to traverse through time at the current chart periodicity without having to explicitly create a new iterator. - * See {@link CIQ.ChartEngine#getNextInterval} and {@link CIQ.ChartEngine#standardMarketIterator} for details. - * - * **Important:** - * - If the {@link CIQ.ExtendedHours} visualization and filtering add-on is enabled, **only data within the defined market hours will be displayed on the chart** even if more data is loaded. - * - Once a market definition is assigned to a chart, it will be used to roll up any data requested by the [periodicity]{@link CIQ.ChartEngine#createDataSet}, which will result in any data outside the market hours to be combined with the prior candle.
- * This may at times look like data is being **filtered**, but it is just being **aggregated**. To truly filter data, you must use the above add-on. - * - * `Market Definitions` are JavaScript objects which must contain the following elements: - * - `name` : A string. Name of the market for which the rules are for. - * - `rules` : An array. The rules indicating the times the market is open or closed. `close` time **must always** be later than `open` time. Use the proper market timezone (`market_tz`) to prevent hours from spanning across days. - * - `market_tz` : A string. Time zone in which the market operates. See {@link CIQ.timeZoneMap} to review a list of all chartIQ supported timezones and instructions on how to add more. - * - `hour_aligned`: A boolean. If set to `true`, market opening and closing times will be forced to the exact start of the hour of time, ignoring any minutes, seconds or millisecond offsets. - * > You should set this to `false` if your market opening and closing times are not aligned to the beginning to each hour. - * > Otherwise, forcing them to do so causes the iterator to generate `previous` and `next` times that could prevent it from properly moving trough the market hours. - * - `convertOnDaily` : A boolean. By default, daily charts are not converted for timezone. Set this to true to convert for daily charts. - * - `beginningDayOfWeek` : Weekday number (0-6) to optionally override CIQ.Market prototype setting of same name. - * - `normal_daily_open`: A string defining a time in `HH:mm` format. Set this to specify the normal open time for a market. - * - `normal_daily_close`: A string defining a time in `HH:mm` format. Set this to specify the normal close time for a market. - * - * Example: - * ``` - * { - * name: "SAMPLE-MARKET", - * market_tz: "America/Chicago", - * hour_aligned: true, - * beginningDayOfWeek: 0, - * normal_daily_open: "09:00", - * normal_daily_close: "17:00", - * rules: [ - * {"dayofweek": 1, "open": "09:00", "close": "17:00"} - * ] - * }; - * ``` - * - * Instructions for creating `Market Definitions`: - * - * - An empty market definition ( {} ) assumes the market is always open. - * - Once a definition has rules in it, the market will be assumed open only for those defined rules. The absence of a rule indicates the market is closed for that timeframe. - * - Market's time rules are specified in the market's local timezone. - * - Seconds are not considered for open or close times, but are okay for intra day data. - * - Rules are processed top to bottom. - * - Rules can be defined for both primary and secondary market sessions. - * - Rules for the market's primary session do not have a `name` parameter and are enabled by default. - * - Rules for the market's primary session are mandatory. - * - Rules for secondary market sessions, such as pre-market or post-market trading hours sessions, require a `name` parameter. - * - All secondary market session are disabled by default. - * - * This is a rule for a 'pre' market session: - * `{"dayofweek": 1, "open": "08:00", "close": "09:30", name: "pre"}` - * - * - To enable or disable secondary market session rules by session name, use {@link CIQ.Market#enableSession} and {@link CIQ.Market#disableSession}. - * - **Important:** Enabling/Disabling market sessions will not automatically filter-out data from the chart, but simply adjust the market iterators so the x-axis can be displayed accordingly in the absence of data for the excluded sessions. - * - Data filtering can be done: - * - Manually by requesting pertinent data from your feed and calling {@link CIQ.ChartEngine#loadChart} - * - Automatically by using the {@link CIQ.ExtendedHours} visualization and filtering add-on. - * - First, the `dayofweek` wild card rules are processed. As soon as a rule is matched, processing breaks. - * - * This rule says the market is open every Monday from 9:30 to 16:00: - * `{"dayofweek": 1, "open": "09:30", "close": "16:00"}` - * - * - After the `dayofweek` rules are processed all of the extra rules are processed. - * - Multiple `open` and `close` times can be set for the same day of week. To indicate the market is closed during lunch, for example: - * ``` - * {"dayofweek": 1, "open": "09:00", "close": "12:00"}, // mon - * {"dayofweek": 1, "open": "13:00", "close": "17:00"} // mon - * ``` - * - `close` time **must always** be later than `open` time. - * - Use the proper market timezone (`market_tz`) to prevent hours from spanning across days. - * - * - Wildcard rules should be placed first and more specific rules should be placed later. - * - * This rule is a wildcard rule for Christmas. If Christmas is on Monday, the - * first set of rules will evaluate to true because the dayofweek rule for day - * one will match. Then this rule will match if the date is the 25th of - * December in any year. Because open is 00:00 and close is 00:00, it will evaluate to false: - * `{"date": "*-12-25", "open": "00:00", "close": "00:00"}` - * - * - After wildcard exceptions, any specific day and time can be matched. - * - * This rule says closed on this day only. Note that open and closed attributes - * can be omitted to save typing if the market is closed the entire day: - * `{"date": "2016-01-18"} //Martin Luther King day.` - * - * This rules says closed on 12-26: - * `{"date": "2016-12-26"}, //Observed Christmas in 2016` - * - * This rule says partial session - * `{"date": "2015-12-24", "open": "9:30", "close": "13:00"} //Christmas eve` - * - * See example section for a compete NYSE definition. - * - * Once defined, it can be used to create a new market instance. - * - * Example: - * ``` - * var thisMarket = new CIQ.Market(marketDefinition); - * ``` - * - * If no definition is provided, the market will operate 24x7. - * - * Example: - * ``` - * new CIQ.Market(); - * ``` - * - * @param {object} [market_definition] A json object that contains the rules for some market. If not defined default market is always open. - * - * @constructor - * @name CIQ.Market - * @since - *
04-2016-08 - *
06-2016-02 - You can now specify times for different market sessions ('pre',post', etc) to be used with the sessions visualization tools. See {@link CIQ.ExtendedHours}. - * - * @example - * CIQ.Market.NYSE = { - "name": "NYSE", - "market_tz": "America/New_York", - "hour_aligned": false, - "rules": [ - //First open up the regular trading times - //Note that sat and sun (in this example) are always closed because - //everything is closed by default and we didn't explicitly open them. - {"dayofweek": 1, "open": "09:30", "close": "16:00"}, //mon - {"dayofweek": 2, "open": "09:30", "close": "16:00"}, - {"dayofweek": 3, "open": "09:30", "close": "16:00"}, - {"dayofweek": 4, "open": "09:30", "close": "16:00"}, - {"dayofweek": 5, "open": "09:30", "close": "16:00"}, //fri - - //After Hours premarket - {"dayofweek": 1, "open": "08:00", "close": "09:30", name: "pre"}, //mon - {"dayofweek": 2, "open": "08:00", "close": "09:30", name: "pre"}, - {"dayofweek": 3, "open": "08:00", "close": "09:30", name: "pre"}, - {"dayofweek": 4, "open": "08:00", "close": "09:30", name: "pre"}, - {"dayofweek": 5, "open": "08:00", "close": "09:30", name: "pre"}, //fri - - //After Hours post - {"dayofweek": 1, "open": "16:00", "close": "20:00", name: "post"}, //mon - {"dayofweek": 2, "open": "16:00", "close": "20:00", name: "post"}, - {"dayofweek": 3, "open": "16:00", "close": "20:00", name: "post"}, - {"dayofweek": 4, "open": "16:00", "close": "20:00", name: "post"}, - {"dayofweek": 5, "open": "16:00", "close": "20:00", name: "post"}, //fri - - //Now Monday thru Friday is open. Close any exceptions - - //always closed on Christmas - {"date": "*-12-25", "open": "00:00", "close": "00:00"}, - - //always closed on 4th of July - {"date": "*-07-04", "open": "00:00", "close": "00:00"}, - - //always close on new years day - {"date": "*-01-01", "open": "00:00", "close": "00:00"}, - - //Some holidays are observed on different days each year or if - //the day falls on a weekend. Each of those rules must be specified. - {"date": "2012-01-02", "open": "00:00", "close": "00:00"}, - - //As a special case if no open and close attributes are set they - //will be assumed "00:00" and "00:00" respectively - {"date": "2017-01-02"}, - - {"date": "2016-01-18"}, - {"date": "2016-02-15"}, - {"date": "2016-03-25"}, - {"date": "2016-05-30"}, - {"date": "2016-09-05"}, - {"date": "2016-11-24"}, - {"date": "2016-11-25", "open": "8:00", "close": "9:30", name: "pre"}, - {"date": "2016-11-25", "open": "9:30", "close": "13:00"}, - {"date": "2016-12-26"}, - - {"date": "2015-01-19"}, - {"date": "2015-02-16"}, - {"date": "2015-04-03"}, - {"date": "2015-05-25"}, - {"date": "2015-07-03"}, - {"date": "2015-09-07"}, - {"date": "2015-11-26"}, - {"date": "2015-11-27", "open": "8:00", "close": "9:30", name: "pre"}, - {"date": "2015-11-27", "open": "9:30", "close": "13:00"}, - {"date": "2015-12-24", "open": "8:00", "close": "9:30", name: "pre"}, - {"date": "2015-12-24", "open": "9:30", "close": "13:00"}, - - {"date": "2014-01-20"}, - {"date": "2014-02-17"}, - {"date": "2014-04-18"}, - {"date": "2014-05-26"}, - {"date": "2014-09-01"}, - {"date": "2014-11-27"}, - {"date": "2014-07-03", "open": "8:00", "close": "9:30", name: "pre"}, - {"date": "2014-07-03", "open": "9:30", "close": "13:00"}, - {"date": "2014-11-28", "open": "8:00", "close": "9:30", name: "pre"}, - {"date": "2014-11-28", "open": "9:30", "close": "13:00"}, - {"date": "2014-12-24", "open": "8:00", "close": "9:30", name: "pre"}, - {"date": "2014-12-24", "open": "9:30", "close": "13:00"}, - - {"date": "2013-01-21"}, - {"date": "2013-02-18"}, - {"date": "2013-03-29"}, - {"date": "2013-05-27"}, - {"date": "2013-09-02"}, - {"date": "2013-11-28"}, - {"date": "2013-07-03", "open": "8:00", "close": "9:30", name: "pre"}, - {"date": "2013-07-03", "open": "9:30", "close": "13:00"}, - {"date": "2013-11-29", "open": "8:00", "close": "9:30", name: "pre"}, - {"date": "2013-11-29", "open": "9:30", "close": "13:00"}, - {"date": "2013-12-24", "open": "8:00", "close": "9:30", name: "pre"}, - {"date": "2013-12-24", "open": "9:30", "close": "13:00"}, - - {"date": "2012-01-16"}, - {"date": "2012-02-20"}, - {"date": "2012-04-06"}, - {"date": "2012-05-28"}, - {"date": "2012-09-03"}, - {"date": "2012-10-29"}, - {"date": "2012-10-30"}, - {"date": "2012-11-22"}, - {"date": "2012-07-03", "open": "8:00", "close": "9:30", name: "pre"}, - {"date": "2012-07-03", "open": "9:30", "close": "13:00"}, - {"date": "2012-11-23", "open": "8:00", "close": "9:30", name: "pre"}, - {"date": "2012-11-23", "open": "9:30", "close": "13:00"}, - {"date": "2012-12-24", "open": "8:00", "close": "9:30", name: "pre"}, - {"date": "2012-12-24", "open": "9:30", "close": "13:00"} - ] - }; - */ -CIQ.Market = function (market_definition) { - this.market_def = false; - this.rules = false; - this.normalHours = []; - this.extraHours = []; - this.class_name = "Market"; - if (!timezoneJS.Date) { - this.tz_lib = Date; //needed to run unit tests - } else { - this.tz_lib = timezoneJS.Date; - } - this.market_tz = ""; - this.hour_aligned = false; - this.convertOnDaily = false; - this.enabled_by_default = false; - - //needed to run unit tests otherwise should do nothing - if ( - typeof market_definition != "undefined" && - market_definition && - !CIQ.isEmpty(market_definition) - ) { - if (market_definition.market_definition) { - market_definition = market_definition.market_definition; - } - if (market_definition.rules) { - this.rules = market_definition.rules; - } - if (market_definition.market_tz) { - this.market_tz = market_definition.market_tz; - } - if (market_definition.convertOnDaily) { - this.convertOnDaily = market_definition.convertOnDaily; - } - if (typeof market_definition.hour_aligned) { - this.hour_aligned = market_definition.hour_aligned; - } - if (typeof market_definition.beginningDayOfWeek !== "undefined") { - this.beginningDayOfWeek = market_definition.beginningDayOfWeek; - } - if (typeof market_definition.enabled_by_default !== "undefined") { - if (market_definition.enabled_by_default instanceof Array) { - this.enabled_by_default = market_definition.enabled_by_default; - } - } - - this.market_def = market_definition; - if (this.market_def.name === undefined) { - this.market_def.name = "no market name specified"; - } - } else { - return; - } - - CIQ.Market._createTimeSegments(this); - this.getSessionNames(); -}; - -/** - * Set of rules for identifying instrument's exchange and deriving a market definition from a symbol. - * This is only required if your chart will need to know the operating hours for the different exchanges. - * If using a 24x7 chart, this class is not needed. - * - * **Default implementation can be found in examples/markets/marketDefinitionsSample.js. Please review and override the functions in there to match the symbol format of your quotefeed or results will be unpredictable.** - * - * @namespace - * @name CIQ.Market.Symbology - * @since 04-2016-08 - */ -CIQ.Market.Symbology = function () {}; - -/** - * Returns true if the instrument is foreign. - * - * **This is dependent on the market data feed and should be overridden accordingly.** - * - * @param {string} symbol The symbol - * @return {boolean} True if it's a foreign symbol - * @memberof CIQ.Market.Symbology - * @since 04-2016-08 - * @example - * CIQ.Market.Symbology.isForeignSymbol=function(symbol){ - * if(!symbol) return false; - * return symbol.indexOf(".")!=-1; - * }; - */ -CIQ.Market.Symbology.isForeignSymbol = function (symbol) { - return false; -}; - -/** - * Returns true if the instrument is a future. - * - * **This is dependent on the market data feed and should be overridden accordingly.** - * - * @param {string} symbol The symbol - * @return {boolean} True if it's a futures symbol - * @memberof CIQ.Market.Symbology - * @since 04-2016-08 - * @example - * CIQ.Market.Symbology.isFuturesSymbol=function(symbol){ - * if(!symbol) return false; - * if(symbol.indexOf("/")!==0 || symbol=="/") return false; - * return true; - * }; - */ -CIQ.Market.Symbology.isFuturesSymbol = function (symbol) { - return false; -}; - -/** - * Determines whether an instrument is a rate. - * - * **Note:** This function is dependent on the market data feed and should be overridden accordingly. - * - * @param {string} symbol The symbol. - * @return {boolean} By default, false. Override this function to return true if the symbol - * is a rate family or rate. - * @memberof CIQ.Market.Symbology - * @since 7.4.0 - * @example - * CIQ.Market.Symbology.isRateSymbol=function(symbol){ - * if(!symbol) return false; - * if(symbol.indexOf("%")!==0 || symbol=="%") return false; - * return true; - * }; - */ -CIQ.Market.Symbology.isRateSymbol = function (symbol) { - return false; -}; - -/** - * Returns true if the instrument is a forex symbol. - * - * **This is dependent on the market data feed and should be overridden accordingly.** - * - * @param {string} symbol The symbol - * @return {boolean} True if it's a forex symbol - * @memberof CIQ.Market.Symbology - * @since 04-2016-08 - * @example - * CIQ.Market.Symbology.isForexSymbol=function(symbol){ - * if(!symbol) return false; - * if(CIQ.Market.Symbology.isForeignSymbol(symbol)) return false; - * if(CIQ.Market.Symbology.isFuturesSymbol(symbol)) return false; - * if(symbol.length<6 || symbol.length>7) return false; - * if(symbol.length==6 && symbol[5]=="X") return false; // This is a fund of some sort - * if(/\^?[A-Za-z]{6}/.test(symbol)) return true; - * return false; - * }; - */ -CIQ.Market.Symbology.isForexSymbol = function (symbol) { - return false; -}; - -/** - * Returns true if the symbol is a metal/currency or currency/metal pair - * - * **This is dependent on the market data feed and should be overridden accordingly.** - * - * @param {string} symbol The symbol - * @param {boolean} inverse Set to true to test specifically for a currency/metal pair (e.g. EURXAU, but not XAUEUR). - * @return {boolean} True if it's a metal symbol - * @memberof CIQ.Market.Symbology - * @since 04-2016-08 - * @example - * CIQ.Market.Symbology.isForexMetal=function(symbol,inverse){ - * var metalsSupported={ - * "XAU":true, "XAG":true, "XPT":true, "XPD":true - * }; - * if(!symbol) return false; - * if(!CIQ.Market.Symbology.isForexSymbol(symbol)) return false; - * if(symbol.charAt(0)!="^") symbol="^"+symbol; - * if(!metalsSupported[symbol.substring(1,4)] && metalsSupported[symbol.substring(4,7)]) return true; - * else if(!inverse && metalsSupported[symbol.substring(1,4)] && !metalsSupported[symbol.substring(4,7)]) return true; - * return false; - * }; - */ -CIQ.Market.Symbology.isForexMetal = function (symbol, inverse) { - return false; -}; - -/** - * Returns true if the symbol is a forex or a future - * - * @param {string} symbol The symbol - * @return {boolean} True if the symbol is a forex or a future - * @memberof CIQ.Market.Symbology - * @since 04-2016-08 - */ -CIQ.Market.Symbology.isForexFuturesSymbol = function (symbol) { - if (CIQ.Market.Symbology.isForexSymbol(symbol)) return true; - if (CIQ.Market.Symbology.isFuturesSymbol(symbol)) return true; - return false; -}; - -/** - * This is a function that takes a symbolObject of form accepted by {@link CIQ.ChartEngine#loadChart}, and returns a market definition. - * When loading it with {@link CIQ.ChartEngine#setMarketFactory}, it will be used by the chart to dynamically change market definitions when a new instrument is activated. - * - * **Very important:**
- * Default implementation can be found in examples/markets/marketDefinitionsSample.js. Please review and override the functions in there to match the symbol format of your quotefeed or results will be unpredictable. - * - * See {@link CIQ.Market} for instruction on how to create a market definition. - * @param {object} symbolObject Symbol object of form accepted by {@link CIQ.ChartEngine#loadChart} - * @return {object} A market definition. See {@link CIQ.Market} for instructions. - * @memberof CIQ.Market.Symbology - * @since 04-2016-08 - * @example - * // default implementation - * var factory=function(symbolObject){ - * var symbol=symbolObject.symbol; - * if(CIQ.Market.Symbology.isForeignSymbol(symbol)) return null; // 24 hour market definition - * if(CIQ.Market.Symbology.isFuturesSymbol(symbol)) return CIQ.Market.GLOBEX; - * if(CIQ.Market.Symbology.isForexMetal(symbol)) return CIQ.Market.METALS; - * if(CIQ.Market.Symbology.isForexSymbol(symbol)) return CIQ.Market.FOREX; - * return CIQ.Market.NYSE; - * }; - */ -CIQ.Market.Symbology.factory = function (symbolObject) { - return null; // 24 hour market definition -}; - -/** - * Encodes the string identifier for a specific instrument in a term structure chart. This - * function is called when a time series chart is opened for a term structure instrument. - * See {@link CIQ.UI.CurveEdit.launchTimeSeries}. - * - * Typically, the implementation of this function concatenates the term structure entity with - * the instrument name to fully identify the instrument on the time series chart (see example). - * - * Override this function to specify whatever encoding you need for your use case. - * - * @param {string} entity The symbol/entity for the curve; for example, "US-T BENCHMARK". - * @param {string} instrument An individual instrument; for example, "20 YR". - * @return {string} The symbol for the individual instrument; for example, "US-T BENCHMARK 20 YR". - * - * @memberof CIQ.Market.Symbology - * @since 7.4.0 - * - * @example - * CIQ.Market.Symbology.encodeTermStructureInstrumentSymbol = function(entity, instrument) { - * // Remove leading % sign. - * if (entity[0] === "%") entity = entity.slice(1); - * return entity + " " + instrument; - * }; - */ -CIQ.Market.Symbology.encodeTermStructureInstrumentSymbol = function ( - entity, - instrument -) { - console.warn( - "You are trying to call `CIQ.Market.Symbology.encodeTermStructureInstrumentSymbol` but have not implemented it." - ); -}; - -if (ExistingMarket) CIQ.extend(CIQ.Market, ExistingMarket); - -/** - * An array of objects containing information about the current market's extended sessions. - * Each element has a name prop (for the name of the session) and an enabled prop. - * See {@link CIQ.ExtendedHours} for more information on extended sessions. - * @type array - * @default - * @alias sessions - * @memberof CIQ.Market - * @example - * marketSessions=stxx.chart.market.sessions - */ -CIQ.Market.prototype.sessions = null; - -/** - * The day on which to begin a week: 0 = Sunday, 1 = Monday, ..., 6 = Saturday. - * - * This is a global setting, but can be overridden with a market-specific setting in the market - * definition. - * - * @type {number} - * @default 0 - * @alias beginningDayOfWeek - * @memberof CIQ.Market# - * @since 8.2.0 - * - * @example - * stxx.chart.market.beginningDayOfWeek = 5; // Start week on Friday. - */ -CIQ.Market.prototype.beginningDayOfWeek = 0; - -/** - * Returns an array of objects containing a list of sessions and whether or not they are enabled - * - * @return {array} String array of market session names, and corresponding status (e.g. [{ name: 'pre', enabled: false } { name: 'post', enabled: true }]) - * @since 6.0.0 - */ -CIQ.Market.prototype.getSessionNames = function () { - if (!this.rules) { - //Its a safe assumption this is a 24 hour chart, and that it has no sessions - this.sessions = []; - } else if (!this.sessions) { - var names = []; - var marketSessions = []; - - this.rules.map(function (rule) { - if (rule.name && names.indexOf(rule.name) === -1) { - names.push(rule.name); - - marketSessions.push({ - name: rule.name, - enabled: rule.enabled ? rule.enabled : false - }); - } - }); - - this.sessions = marketSessions; - } - return this.sessions.slice(); -}; - -/** - * Primitive to find the next matching time segment taking into account rules for adjacent sessions. - * If the date lands exactly on the open or close time for a session, then it will still seek to the next market session. - * @param {date} date A start date time in the market_tz timezone. - * @param {boolean} open True if looking for an open time - * @return {date} A date in the market_tz timezone that falls somewhere in a matching time segment. Probably 1 before close. Or null if no rules are defined - * @memberof CIQ.Market - * @since 05-2016-10 - * @private - */ -CIQ.Market.prototype._find_next_segment = function (date, open) { - if (!this.market_def) return null; // special case - if (!this.rules) return null; //special case - var d = new Date(+date); - var iter = this.newIterator({ - begin: d, - interval: 1, - inZone: this.market_tz, - outZone: this.market_tz - }); - if (this._wasOpenIntraDay(d)) { - var hours = this.zseg_match.close_parts.hours; - var minutes = this.zseg_match.close_parts.minutes; - d.setHours(hours); - d.setMinutes(minutes); - iter = this.newIterator({ - begin: d, - interval: 1, - inZone: this.market_tz, - outZone: this.market_tz - }); - } - return iter.next(); -}; - -/** - * Primitive to find the previous matching time segment taking into account rules for adjacent sessions. - * If the date lands exactly on the open or close time for a session, then it will still seek to the previous market session. - * @param {date} date A start date time in the market_tz timezone. - * @param {boolean} open True if looking for an open time - * @return {date} A date in the market_tz timezone that falls somewhere in a matching time segment. Probably 1 before close. Or null of no rules are defined. - * @memberof CIQ.Market - * @since 05-2016-10 - * @private - */ -CIQ.Market.prototype._find_prev_segment = function (date, open) { - if (!this.market_def) return null; // special case - if (!this.rules) return null; //special case - var d = new Date(+date); - var iter = this.newIterator({ - begin: d, - interval: 1, - inZone: this.market_tz, - outZone: this.market_tz - }); - - var wasOpenIntraDay = this._wasOpenIntraDay(d); - - // adjust edge cases to force a previous instance - // if we are at the exact open or close time, go back one tick to force a previous session - if (wasOpenIntraDay === null) { - // move back one minute... not in the market clock. - d = new Date(d - 60000); - // then see if there was a session a minute ago... if so, then we were at the exact open or close time - wasOpenIntraDay = this._wasOpenIntraDay(d); - } else { - if ( - (open && - d.getHours() === this.zseg_match.open_parts.hours && - d.getMinutes() === this.zseg_match.open_parts.minutes) || - (!open && - d.getHours() === this.zseg_match.close_parts.hours && - d.getMinutes() === this.zseg_match.close_parts.minutes) - ) { - d = iter.previous(); - } - } - - if (wasOpenIntraDay) { - var hours = this.zseg_match.open_parts.hours; - var minutes = this.zseg_match.open_parts.minutes; - d.setHours(hours); - d.setMinutes(minutes); - iter = this.newIterator({ - begin: d, - interval: 1, - inZone: this.market_tz, - outZone: this.market_tz - }); - d = iter.previous(); - - if (this.zseg_match.close_parts.hours === hours) { - if (this.zseg_match.close_parts.minutes === minutes) { - // segments are adjacent use the previous - if (open) { - return iter.next(); - } - return d; - } - } - if (this.zseg_match.adjacent_child) { - // segments are adjacent use the previous - return d; - } - if (open) { - // segments are not adjacent go back - return iter.next(); - } - return d; - } - return iter.previous(); -}; - -/** - * Toggle on/off a market session by name. - * - * - **Important:** Enabling/Disabling market sessions will not automatically filter-out data from the chart, but simply adjust the market iterators so the x-axis can be displayed accordingly in the absence of data for the excluded sessions. - * - Data filtering can be done: - * - Manually by requesting pertinent data from your feed and calling {@link CIQ.ChartEngine#loadChart} - * - Automatically by using the {@link CIQ.ExtendedHours} visualization and filtering add-on. - * - * @param {string} session_name A session name matching a valid name present in the market definition. - * @param {object} [inverted] Any true value (`true`, non-zero value or string) passed here will enable the session, otherwise the session will be disabled. - * @memberof CIQ.Market - * @since 06-2016-02 - */ -CIQ.Market.prototype.disableSession = function (session_name, inverted) { - var inverted_ = false; - if (typeof inverted !== "undefined" && inverted) { - inverted_ = true; - } - if (session_name) { - for (var i = 0; i < this.normalHours.length; i++) { - if (this.normalHours[i].name === session_name) { - this.normalHours[i].enabled = inverted_; - } - } - for (i = 0; i < this.extraHours.length; i++) { - if (this.extraHours[i].name === session_name) { - this.extraHours[i].enabled = inverted_; - } - } - } -}; - -/** - * Enable a market session by name. See {@link CIQ.Market#disableSession} for full usage details. - * @param {string} session_name A session name - * @memberof CIQ.Market - * @since 06-2016-02 - */ -CIQ.Market.prototype.enableSession = function (session_name) { - this.disableSession(session_name, "enable_instead"); -}; - -/** - * Parses the market definition for a list of market names, and enables each one-by-one, see {@link CIQ.Market#enableSession} and {@link CIQ.Market#disableSession}. - * - **Important:** Enabling/Disabling market sessions will not automatically filter-out data from the chart, but simply adjust the market iterators so the x-axis can be displayed accordingly in the absence of data for the excluded sessions. - * @memberof CIQ.Market - * @since 6.0.0 - */ -CIQ.Market.prototype.enableAllAvailableSessions = function () { - var marketSessions = this.getSessionNames(); - for (var i = 0; i < marketSessions.length; i++) { - this.enableSession(marketSessions[i].name); - } -}; - -/** - * Get the close date/time for the trading day or specific session. - * @param {date} [date=now] date The date on which to check. - * @param {string} [session_name] Specific market session. If `session_name` is not passed in, the first close time of the day will be returned, - * depending on the sessions that are enabled. If a session name is passed in, then not only does the market session - * need to be open on the day of `date`, but also within the time of the specified session. Otherwise, null will be returned. - * Pass in "" to specify only the default session when other session are also active. - * @param {string} [inZone] Optional datazone to translate from - If no market zone is present it will assume browser time. - * @param {string} [outZone] Optional datazone to translate to - If no market zone is present it will assume browser time. - * @return {date} Close date/time for the trading session or null if the market is - * closed for the given date. - * @memberof CIQ.Market - * @since 05-2016-10 - */ -CIQ.Market.prototype.getClose = function (date, session_name, inZone, outZone) { - if (!this.market_def) return null; // special case - if (!this.rules) return null; //special case - var d = date; - if (!date) { - d = new Date(); - inZone = null; // if they don't send the date we set one up in browser time, so need to remove the inZone - } - d = this._convertToMarketTZ(d, inZone); - - if (typeof session_name !== "undefined") { - if (this._wasOpenIntraDay(d)) { - if (this.zseg_match.name === session_name) { - d.setHours( - this.zseg_match.close_parts.hours, - this.zseg_match.close_parts.minutes, - 0, - 0 - ); - d = this._convertFromMarketTZ(d, outZone); - return d; - } - } - } else { - if (this._wasOpenDaily(d)) { - var zseg_match = this.zseg_match; - - //find the last session of the day - while (zseg_match.child_) { - zseg_match = zseg_match.child_; - } - - //find the last enabled session ... maybe back where we started - while (!zseg_match.enabled) { - zseg_match = zseg_match.parent_; - } - - d.setHours( - zseg_match.close_parts.hours, - zseg_match.close_parts.minutes, - 0, - 0 - ); - d = this._convertFromMarketTZ(d, outZone); - return d; - } - } - return null; -}; - -/** - * Get the close time for the current market session, or if the market is closed, the close time for the next market session. - * @param {date} [date=now] date The date on which to check. - * @param {string} [inZone] Optional datazone to translate from - If no market zone is present it will assume browser time. - * @param {string} [outZone] Optional datazone to translate to - If no market zone is present it will assume browser time. - * @return {date} A date set to the close time of the next open market session. - * @memberof CIQ.Market - * @since 05-2016-10 - */ -CIQ.Market.prototype.getNextClose = function (date, inZone, outZone) { - if (!this.market_def) return null; // special case - if (!this.rules) return null; //special case - - var d = date; - if (!date) { - d = new Date(); - inZone = null; // if they don't send the date we set one up in browser time, so need to remove the inZone - } - d = this._convertToMarketTZ(d, inZone); - if (!this._wasOpenIntraDay(d)) { - var iter = this.newIterator({ - begin: d, - interval: 1, - inZone: this.market_tz, - outZone: this.market_tz - }); - d = iter.next(); - } - var date_ = d.getDate(); - var zseg_match = this.zseg_match; - while (zseg_match.adjacent_child) { - zseg_match = zseg_match.adjacent_child; - date_ += 1; - } - d.setDate(date_); - d.setHours( - zseg_match.close_parts.hours, - zseg_match.close_parts.minutes, - 0, - 0 - ); - d = this._convertFromMarketTZ(d, outZone); - return d; -}; - -/** - * Get the next market session open time. If the requested date is the opening time for the session, then - * it will iterate to opening time for the next market session. - * @param {date} [date=now] date An The date on which to check. - * @param {string} [inZone] Optional datazone to translate from - If no market zone is present it will assume browser time. - * @param {string} [outZone] Optional datazone to translate to - If no market zone is present it will assume browser time. - * @return {date} A date aligned to the open time of the next open session. If no rules are defined, it will return null. - * @memberof CIQ.Market - * @since 05-2016-10 - */ -CIQ.Market.prototype.getNextOpen = function (date, inZone, outZone) { - if (!this.market_def) return null; // special case - if (!this.rules) return null; //special case - var d = date; - if (!date) { - d = new Date(); - inZone = null; // if they don't send the date we set one up in browser time, so need to remove the inZone - } - d = this._convertToMarketTZ(d, inZone); - d = this._find_next_segment(d); - if (this.zseg_match.adjacent_parent) { - d = this.getNextOpen(d, this.market_tz, this.market_tz); - d = this._convertFromMarketTZ(d, outZone); - return d; - } - d.setHours(this.zseg_match.open_parts.hours); - d.setMinutes(this.zseg_match.open_parts.minutes); - d = this._convertFromMarketTZ(d, outZone); - return d; -}; - -/** - * Get the open date/time for a market day or specific session. - * @param {date} [date=now] date The date on which to check. - * @param {string} [session_name] Specific market session. If `session_name` is not passed in, the first open time of the day will be returned, - * depending on the sessions that are enabled. If a session name is passed in, then not only does the market session - * need to be open on the day of `date`, but also within the time of the specified session. Otherwise, null will be returned. Pass in "" to - * specify only the default session when other session are also active. - * @param {string} [inZone] Optional datazone to translate from - If no market zone is present it will assume browser time. - * @param {string} [outZone] Optional datazone to translate to - If no market zone is present it will assume browser time. - * @return {date} A date time for the open of a session or null if the market is - * closed for the given date or there are no market rules to check. - * @memberof CIQ.Market - * @since 05-2016-10 - */ -CIQ.Market.prototype.getOpen = function (date, session_name, inZone, outZone) { - if (!this.market_def) return null; // special case - if (!this.rules) return null; //special case - var d = date; - if (!date) { - d = new Date(); - inZone = null; // if they don't send the date we set one up in browser time, so need to remove the inZone - } - d = this._convertToMarketTZ(d, inZone); - if (typeof session_name !== "undefined") { - if (this._wasOpenIntraDay(d)) { - if (this.zseg_match.name == session_name) { - d.setHours( - this.zseg_match.open_parts.hours, - this.zseg_match.open_parts.minutes, - 0, - 0 - ); - d = this._convertFromMarketTZ(d, outZone); - return d; - } - } - } else { - if (this._wasOpenDaily(d)) { - var zseg_match = this.zseg_match; - - //find all of the parents if any - while (zseg_match.parent_) { - zseg_match = zseg_match.parent_; - } - - //find the first enabled child ... might end up back where we started - while (!zseg_match.enabled) { - zseg_match = zseg_match.child_; - } - - d.setHours( - zseg_match.open_parts.hours, - zseg_match.open_parts.minutes, - 0, - 0 - ); - d = this._convertFromMarketTZ(d, outZone); - return d; - } - } - return null; -}; - -/** - * Gets the normal open time for the current market; that is, the time the market typically opens. - * In cases where there are two trading sessions, the first is used. - * - * @return {string} The normal open in HH:mm format. - * @memberof CIQ.Market - * @since 8.1.0 - */ -CIQ.Market.prototype.getNormalOpen = function () { - const { market_def, rules } = this; - if (!(market_def && rules)) return "00:00"; - if (market_def.normal_daily_open) return market_def.normal_daily_open; - if (market_def.name === "FOREX") return "17:00"; - return rules.find(({ name }) => !name || name === "").open; -}; - -/** - * Gets the normal close time for the current market; that is, the time the market typically - * closes. In cases where there are two trading sessions, the second is used. - * - * @return {string} The normal close in HH:mm format. - * @memberof CIQ.Market - * @since 8.1.0 - */ -CIQ.Market.prototype.getNormalClose = function () { - const { market_def, rules } = this; - if (!(market_def && rules)) return "24:00"; - if (market_def.normal_daily_close) return market_def.normal_daily_close; - if (market_def.name === "FOREX") return "17:00"; - return rules - .filter(({ dayofweek, name }) => dayofweek && (!name || name === "")) - .pop().close; -}; - -/** - * Get the previous session close time. - * If the date lands exactly on the close time for a session then it will still seek to the previous market session's close. - * @param {date} [date=now] date The date on which to check. - * @param {string} [inZone] Optional datazone to translate from - If no market zone is present it will assume browser time. - * @param {string} [outZone] Optional datazone to translate to - If no market zone is present it will assume browser time. - * @return {date} A date aligned to the previous close date/time of a session. If no rules are defined, it will return null. - * @memberof CIQ.Market - * @since 05-2016-10 - */ -CIQ.Market.prototype.getPreviousClose = function (date, inZone, outZone) { - if (!this.market_def) return null; // special case - if (!this.rules) return null; //special case - var d = date; - if (!date) { - d = new Date(); - inZone = null; // if they don't send the date we set one up in browser time, so need to remove the inZone - } - d = this._convertToMarketTZ(d, inZone); - d = this._find_prev_segment(d, false); - if (this.zseg_match.adjacent_child) { - return this.getPreviousClose(d, this.market_tz, this.market_tz); - } - d.setHours(this.zseg_match.close_parts.hours); - d.setMinutes(this.zseg_match.close_parts.minutes); - d = this._convertFromMarketTZ(d, outZone); - return d; -}; - -/** - * Get the previous session open time. If the date lands exactly on the open time for a session then - * it will still seek to the previous market session's open. - * @param {date} [date=now] date An The date on which to check. - * @param {string} [inZone] Optional datazone to translate from - If no market zone is present it will assume browser time. - * @param {string} [outZone] Optional datazone to translate to - If no market zone is present it will assume browser time. - * @return {date} A date aligned to previous open date/time of a session. If no rules are defined, it will return null. - * @memberof CIQ.Market - * @since 05-2016-10 - */ -CIQ.Market.prototype.getPreviousOpen = function (date, inZone, outZone) { - if (!this.market_def) return null; // special case - if (!this.rules) return null; //special case - var d = date; - if (!date) { - d = new Date(); - inZone = null; // if they don't send the date we set one up in browser time, so need to remove the inZone - } - d = this._convertToMarketTZ(d, inZone); - d = this._find_prev_segment(d, true); - if (this.zseg_match.adjacent_parent) { - return this.getPreviousOpen(d, this.market_tz, this.market_tz); - } - d.setHours(this.zseg_match.open_parts.hours); - d.setMinutes(this.zseg_match.open_parts.minutes); - d = this._convertFromMarketTZ(d, outZone); - return d; -}; - -/** - * Return the session name for a date. If the name is defined and if the date - * lands in a session that is open. Otherwise return null. - * @param {date} date A date object - * @param {string} [inZone] Timezone of incoming date - If no market zone is present it will assume browser time. - * @return {object} String or null - * @memberOf CIQ.Market - */ -CIQ.Market.prototype.getSession = function (date, inZone) { - date = this._convertToMarketTZ(date, inZone); - if (this._wasOpenIntraDay(date) && this.zseg_match) { - return this.zseg_match.name; - } - return null; -}; - -/** - * @return {date} Current time in the market zone - * @memberof CIQ.Market - * @since 04-2016-08 - */ -CIQ.Market.prototype.marketZoneNow = function () { - return this._convertToMarketTZ(new Date()); -}; - -/** - * @return {boolean} `true` if this market is hour aligned. - * @memberof CIQ.Market - * @since 04-2016-08 - */ -CIQ.Market.prototype.isHourAligned = function () { - return this.hour_aligned; -}; - -/** - * Checks if the market is currently open. - * @return {object} An object with the open market session's details, if the market is open right now. Or `null` if no sessions are currently open. - * @memberof CIQ.Market - * @since 04-2016-08 - */ -CIQ.Market.prototype.isOpen = function () { - var now = new Date(); - if (this.market_tz) { - now = new this.tz_lib(now.getTime(), this.market_tz); - } - return this._wasOpenIntraDay(now); -}; - -/** - * Checks if today it is a market day. - * @return {object} An object with the open market session's details, if it is a market day. Or `null` if it is not a market day. - * @memberof CIQ.Market - * @since 04-2016-08 - */ -CIQ.Market.prototype.isMarketDay = function () { - var now = new Date(); - if (this.market_tz) { - now = new this.tz_lib(now.getTime(), this.market_tz); - } - return this._wasOpenDaily(now); -}; - -/** - * Checks if a supplied date is a market day. Only the date is examined; hours, minutes, seconds are ignored - * @param {date} date A date - * @return {object} An object with the open market session's details, if it is a market day. Or `null` if it is not a market day. - * @memberof CIQ.Market - * @since 04-2016-08 - */ -CIQ.Market.prototype.isMarketDate = function (date) { - return this._wasOpenDaily(date); -}; - -/** - * Creates iterators for the associated Market to traverse through time taking into account market hours. - * An iterator instance can go forward or backward in time any arbitrary amount. - * However, the internal state cannot be changed once it is constructed. A new iterator should be - * constructed whenever one of the parameters changes. For example, if the - * `interval` changes a new iterator will need to be built. If the `displayZone` - * or `dataZone` changes on the market, new iterators will also need to be - * constructed. - * - * See {@link CIQ.Market.Iterator} for all available methods. - * - * See the following convenience functions: {@link CIQ.ChartEngine#getNextInterval} and {@link CIQ.ChartEngine#standardMarketIterator} - * - * @param {object} parms Parameters used to initialize the Market object. - * @param {string} [parms.interval] A valid interval as required by {@link CIQ.ChartEngine#setPeriodicity}. Default is 1 (minute). - * @param {number} [parms.periodicity] A valid periodicity as required by {@link CIQ.ChartEngine#setPeriodicity}. Default is 1. - * @param {string} [parms.timeUnit] A valid timeUnit as required by {@link CIQ.ChartEngine#setPeriodicity}. Default is "minute" - * @param {date} [parms.begin] The date to set as the start date for this iterator instance. Default is `now`. Will be assumed to be `inZone` if one set. - * @param {string} [parms.inZone] A valid timezone from the timeZoneData.js library. This should represent the time zone for any input dates such as `parms.begin` in this function or `parms.end` in {@link CIQ.Market.Iterator#futureTick}. Defaults to browser timezone if none set. - If no market zone is present it will assume browser time. - * @param {string} [parms.outZone] A valid timezone from the timeZoneData.js library. This should represent the time zone for the returned dates. Defaults to browser timezone if none set. - If no market zone is present it will assume browser time. - * @return {object} A new iterator. - * @memberof CIQ.Market - * @since 04-2016-08 - * @example - var iter = stxx.chart.market.newIterator( - { - 'begin': now, - 'interval': stxx.layout.interval, - 'periodicity': stxx.layout.periodicity, - 'timeUnit': stxx.layout.timeUnit, - 'inZone': stxx.dataZone, - 'outZone': stxx.displayZone - } - ); - */ -CIQ.Market.prototype.newIterator = function (parms) { - var _multiple = false; - if (parms.periodicity) { - _multiple = parms.periodicity; - } else if (parms.multiple) { - _multiple = parms.multiple; - } - var _interval = parms.interval; - if (!_interval) { - _interval = "minute"; - } - if (_interval == "hour") _interval = 60; - if (!_multiple) { - _multiple = 1; - } - if (!parms.begin) { - parms.begin = new Date(); - parms.inZone = null; - } - if (_interval == parseInt(_interval, 10)) { - _interval = parseInt(_interval, 10); // in case it was a string, which is allowed in setPeriodicity. - - // if the periodicity<1 then the x-axis might be in seconds (<1/60, msec) - if (parms.periodicity < 1 / 60) { - _multiple = _multiple * _interval * 60000; - _interval = "millisecond"; - } else if (parms.periodicity < 1) { - _multiple = _multiple * _interval * 60; - _interval = "second"; - } else { - _multiple = _multiple * _interval; - _interval = "minute"; - } - } - if (parms.timeUnit) { - if (parms.timeUnit === "millisecond") { - _interval = parms.timeUnit; - } else if (parms.timeUnit === "second") { - _interval = parms.timeUnit; - } else if (parms.timeUnit === "tick") { - _interval = "second"; - } - } - if (_interval == "tick") _interval = "second"; - parms.interval = _interval; - parms.multiple = _multiple; - parms.market = this; - return new CIQ.Market.Iterator(parms); -}; - -/** - * Calculate whether this market was open on some date. This will depend on - * the data used when creating this market. This function does not take into - * account intraday data. It simply checks the date to see if the market was - * open at all on that day. Hours, minutes, seconds are ignored. - * @param {date} historical_date Javascript date object with timezone in the market time zone. - * @return {boolean} true if the market was open. - * @memberof CIQ.Market - * @since 04-2016-08 - * @private - */ -CIQ.Market.prototype._wasOpenDaily = function (historical_date) { - return this._was_open(historical_date, false); -}; - -/** - * Calculate whether this market was open on some date. This will depend on - * The data used when creating this market. This function will take into - * account intraday date that is minutes and seconds. Not only does a market - * need to be open on the day in question but also within the time specified. - * @param {date} historical_date Javascript date object with timezone in the market time zone. - * @return {boolean} true if the market was open. - * @memberof CIQ.Market - * @since 04-2016-08 - * @private - */ -CIQ.Market.prototype._wasOpenIntraDay = function (historical_date) { - return this._was_open(historical_date, true); -}; - -/** - * Given some javascript date object calculate whether this market was open. - * Use _wasOpenDaily or _wasOpenIntraDay instead. As a special case if - * no market json has been defined this function will always return true. - * @param {date} historical a valid Javascript date object with timezone in the market time zone. - * @param {boolean} intra_day true if intraday (will check between open and close times) - * @return {object} matching segment if any, or null if not - * @private - */ -CIQ.Market.prototype._was_open = function (historical, intra_day) { - // This function will reset all of the `z` properties to match the market segment matching `historical` - // Whether the matching segment has changed helps to determine whether we should reset the date to the - // beginning of the market segment. Here we store a record of the previously set `zseg_match` to - // facilitate that determination later. - var previously_set_zseg_match = this.zseg_match; - - this.zopen_hour = 0; - this.zopen_minute = 0; - this.zclose_hour = 0; - this.zclose_minute = 0; - this.zmatch_open = false; - this.zseg_match = null; - if (!this.market_def || !this.rules) { - // special case, 24h security - this.zclose_hour = 24; - return true; - } - var normally_open = false; - var extra_open = false; - var year = historical.getFullYear(); - var month = historical.getMonth() + 1; - var day = historical.getDay(); - var date = historical.getDate(); - var hour = historical.getHours(); - var minutes = historical.getMinutes(); - var seconds = historical.getSeconds(); - var segment; - var midnight_secs = hour * 60 * 60 + minutes * 60 + seconds; - - if (typeof intra_day === "undefined") { - intra_day = true; - } - - var i; - for (i = 0; i < this.normalHours.length; i++) { - segment = this.normalHours[i]; - if (!segment.enabled) { - continue; - } - normally_open = segment.dayofweek === day; - if (normally_open && intra_day) { - normally_open = - midnight_secs >= segment.open && midnight_secs < segment.close; - } - if (normally_open) { - if (!intra_day && this.zseg_match) { - if ( - segment.open_parts.hours > this.zopen_hour || - (segment.open_parts.hours == this.zopen_hour && - segment.open_parts.minutes > this.zopen_minute) - ) { - continue; - } - } - - // We may want to reset the date to the beginning of the segment if the `zseg_match` has - // changed and if the segment is not one part of a single session (a trading period extending - // into a second day). We determine these factors by comparing `segment` to the previously set - // `zseg_match` and by checking whether the `segment` has an `adjacent_parent` or `adjacent_child`. - // If these factors indicate we should reset reset the time to the beginning of the segment, we - // store that determination on the object to know to take that action later. - if ( - segment !== previously_set_zseg_match && - !segment.adjacent_parent && - !segment.adjacent_child - ) { - this.shouldResetToBeginningOfSegment = true; - } - - this.zopen_hour = segment.open_parts.hours; - this.zopen_minute = segment.open_parts.minutes; - this.zclose_hour = segment.close_parts.hours; - this.zclose_minute = segment.close_parts.minutes; - this.zmatch_open = midnight_secs === segment.open; - this.zseg_match = segment; - if (intra_day) break; - } - } - - for (i = 0; i < this.extraHours.length; i++) { - segment = this.extraHours[i]; - if (!segment.enabled) { - continue; - } - if ("*" === segment.year || year === segment.year) { - if (month === segment.month && date === segment.day) { - extra_open = - (!intra_day && segment.open) || - (midnight_secs >= segment.open && midnight_secs < segment.close); - if (!extra_open && this.zseg_match) { - normally_open = false; - this.zopen_hour = 0; - this.zopen_minute = 0; - this.zclose_hour = 0; - this.zclose_minute = 0; - this.zmatch_open = false; - this.zseg_match = null; - } - if (extra_open) { - if (!intra_day && this.zseg_match) { - if ( - segment.open_parts.hours > this.zopen_hour || - (segment.open_parts.hours == this.zopen_hour && - segment.open_parts.minutes > this.zopen_minute) - ) { - continue; - } - } - this.zopen_hour = segment.open_parts.hours; - this.zopen_minute = segment.open_parts.minutes; - this.zclose_hour = segment.close_parts.hours; - this.zclose_minute = segment.close_parts.minutes; - this.zmatch_open = midnight_secs === segment.open; - this.zseg_match = segment; - if (intra_day) break; - } - } - } - } - - return this.zseg_match; -}; - -/** - * Convenience function for unit testing. - * @param {date} testDate A date - * @return {boolean} True if the market was closed on the given date - * @memberOf CIQ.Market - */ -CIQ.Market.prototype._wasClosed = function (testDate) { - return !this._was_open(testDate, true); -}; - -/** - * Convenience function for unit testing. - * @param {date} testDate A date - * @return {boolean} True if the market was open on the given date - * @memberOf CIQ.Market - */ -CIQ.Market.prototype._wasOpen = function (testDate) { - return this._was_open(testDate, true); -}; - -/** - * Get the difference in milliseconds between two time zones. May be positive or - * negative depending on the time zones. The purpose is to shift the source - * time zone some number of milliseconds to the target timezone. For example shifting - * a data feed from UTC to Eastern time. Or shifting Eastern time to Mountain - * time for display purposes. Note that it is important to pass the source - * and the target in the correct order. The algorithm does source - target. This - * will calculate the correct offset positive or negative. - * @param {date} date A date object. Could be any date object the javascript one - * or for example the timezone.js one. Must implement getTime() and - * getTimezoneOffset() - * @param {string} src_tz_str The source time zone. For example the data feed - * @param {string} target_tz_str The target time zone for example the market. - * @return {number} The number of milliseconds difference between the time - * zones. - * @memberOf CIQ.Market - */ -CIQ.Market.prototype._tzDifferenceMillis = function ( - date, - src_tz_str, - target_tz_str -) { - var millis = 0; - var src_date = date; - var target_date = date; - var minutes = src_date.getTimezoneOffset() - target_date.getTimezoneOffset(); - millis = minutes * 60 * 1000; - return millis; -}; - -/** - * Static function that reads the json rules in the market definition and - * creates in memory time segments that are used later to match market dates. - * @param {object} market An instance of a market. - * @memberOf CIQ.Market - */ -CIQ.Market._createTimeSegments = function (market) { - var link_adjacent = function (r0_, r1_) { - if (r0_.close_parts.hours === 24 && r1_.open_parts.hours === 0) { - if (r1_.open_parts.minutes === 0) { - if (p_rule.dayofweek === rd.dayofweek - 1) { - return true; - } - if (p_rule.dayofweek === 6 && rd.dayofweek === 0) { - return true; - } - } - } - return false; - }; - var p_rule; - for (var i = 0; i < market.rules.length; i++) { - var rule = JSON.parse(JSON.stringify(market.rules[i])); - if (typeof rule.open === "undefined" && typeof rule.close === "undefined") { - rule.open = "00:00"; - rule.close = "00:00"; - } - if (!rule.hasOwnProperty("name")) { - rule.name = ""; - } - try { - var rd; - if (typeof rule.dayofweek !== "undefined") { - rule.year = "*"; - rd = _TimeSegmentS._createDayOfWeekSegment(market, rule); - if (p_rule) { - if (p_rule.dayofweek === rd.dayofweek) { - //These links are used for finding open and close times - //On the same day in multiple sessions - p_rule.child_ = rd; - rd.parent_ = p_rule; - } else { - if (link_adjacent(p_rule, rd)) { - //These links are used for finding open and close - //times for sessions that span days - p_rule.adjacent_child = rd; - rd.adjacent_parent = p_rule; - } - } - } - p_rule = rd; - } else if (typeof rule.date !== "undefined") { - rule.isDayOfWeek = false; - rule.dayofweek = -1; - rd = _TimeSegmentS._createDateTimeSegment(market, rule); - } else { - console.log("Error, unknown rule type " + rule); - } - if (market.enabled_by_default) { - for (var x = 0; x < market.enabled_by_default.length; x++) { - var n = market.enabled_by_default[x]; - if (rd.name === n) { - rd.enabled = true; - break; - } - } - } else { - //always enabled if no defaults are defined - //rd.enabled = true; - } - } catch (err) { - console.log("Error, creating market rules " + err); - } - } -}; - -/** - * Internal static utility methods used to create market time segments. - * @private - */ -CIQ.Market._timeSegment = {}; -var _TimeSegmentS = CIQ.Market._timeSegment; - -_TimeSegmentS.re_wild_card_iso = /^(\*)-(\d\d)-(\d\d)$/; -_TimeSegmentS.re_regular_iso = /^(\d\d\d\d)-(\d\d)-(\d\d)$/; -_TimeSegmentS.re_split_hours_minutes = /^(\d\d):(\d\d)$/; -_TimeSegmentS.re_split_hour_minutes = /^(\d):(\d\d)$/; - -/** - * Create a hash code for a string. We may move this to 3rd party later if - * we find a wider need for it. This came from StackOverflow and claims to be - * the same implementation used by Java. - * @param {string} str A string. - * @return {number} A number suitable for - * @private - */ -_TimeSegmentS._hashCode = function (str) { - var hash = 0, - i, - chr, - len; - if (str.length === 0) return hash; - for (i = 0, len = str.length; i < len; i++) { - chr = str.charCodeAt(i); - hash = (hash << 5) - hash + chr; - hash |= 0; // Convert to 32bit integer - } - return hash; -}; - -/** - * Split the hours and minutes from a json time segment rule. - * @param {string} str \d\d:\d\d or \d:\d\d - * @return {object} {minutes:int, hours:int} - * @private - */ -_TimeSegmentS._splitHoursMinutes = function (str) { - var parts = _TimeSegmentS.re_split_hour_minutes.exec(str); - var ret_val = { hours: NaN, minutes: NaN }; - if (parts === null) { - parts = _TimeSegmentS.re_split_hours_minutes.exec(str); - if (parts === null) { - return ret_val; - } - } - ret_val.hours = parseInt(parts[1], 10); - ret_val.minutes = parseInt(parts[2], 10); - return ret_val; -}; - -/** - * Create a time segment for some day of the week. This creates a wildcard - * segment that matches the same weekday in any month and any year. - * @param {object} market The instance of this market - * @param {object} rule Represents the data from one rule in the JSON - * @return {object} - * configuration. - * @private - */ -_TimeSegmentS._createDayOfWeekSegment = function (market, rule) { - var data = { - name: rule.name, - isDayOfWeek: true, - dayofweek: rule.dayofweek, - date_str: "*", - open_parts: _TimeSegmentS._splitHoursMinutes(rule.open), - close_parts: _TimeSegmentS._splitHoursMinutes(rule.close), - open: _TimeSegmentS._secSinceMidnight(market, rule.open, true), - close: _TimeSegmentS._secSinceMidnight(market, rule.close, false), - child_: false, - parent_: false, - adjacent_child: false, - adjacent_parent: false, - enabled: false - }; - if (data.name === "") { - data.enabled = true; - } - data.hash_code = this._hashCode((data.open + data.close).toString()); - market.normalHours.push(data); - return data; -}; - -/** - * Create a time segment for a specific date and time. This can also create - * a wild card segment that matches any year with a specific day and specific - * month. For example *-12-25 to match all Christmas days. It can also build - * any specific year month day open close time that will only match that - * specific range. - * @param {object} market an instance of a market - * @param {object} rule a single rule from a market definition - * @return {object|undefined} Undefined if this function works on the market object. - * @private - */ -_TimeSegmentS._createDateTimeSegment = function (market, rule) { - var pieces = this.re_regular_iso.exec(rule.date); - var year; - if (pieces === null) { - pieces = this.re_wild_card_iso.exec(rule.date); - if (pieces === null) { - console.log("Warning: invalid date format on rule -> " + rule.date); - return; - } - year = "*"; //all years - } else { - year = parseInt(pieces[1], 10); - } - var data = { - name: rule.name, - isDayOfWeek: false, - dayofweek: -1, - year: year, - month: parseInt(pieces[2], 10), - day: parseInt(pieces[3], 10), - date_str: rule.date, - open_parts: _TimeSegmentS._splitHoursMinutes(rule.open), - close_parts: _TimeSegmentS._splitHoursMinutes(rule.close), - open: _TimeSegmentS._secSinceMidnight(market, rule.open, true), - close: _TimeSegmentS._secSinceMidnight(market, rule.close, false), - enabled: false - }; - if (data.name === "") { - data.enabled = true; - } - data.hash_key = this._hashCode(data.date_str + data.open + data.close); - market.extraHours.push(data); - return data; -}; - -/** - * Calculate the seconds since midnight for some time string. These time strings - * come from the market definition. These are intended to be open and close - * times. - * @param {object} market An instance of a market - * @param {string} time_str A time string like this "\d\d:\d\d" - * @param {boolean} open_time If true the time is used for opening a market - * @return {number} Seconds since midnight - * otherwise the time is used for closing a market. This is so that we can - * handle 00:00 and 24:00. - * @private - */ -_TimeSegmentS._secSinceMidnight = function (market, time_str, open_time) { - var parts = time_str.split(":"); - var hours = parseInt(parts[0], 10); - var minutes = parseInt(parts[1], 10); - var seconds = hours * 60 * 60 + minutes * 60; - - if (!open_time) { - if (hours === 24) { - seconds = hours * 60 * 60 + 1; - } - } - return seconds; -}; - -/** - * Converts from the given timezone into the market's native time zone - * If no market zone is present, the date will be returned unchanged. - * @param {date} dt JavaScript Date - * @param {string} [tz] timezoneJS timezone, or null to indicate browser localtime/UTC (dataZone) - * @return {date} A JavaScript Date offset by the timezone change - * @memberOf CIQ.Market - */ -CIQ.Market.prototype._convertToMarketTZ = function (dt, tz) { - //if(!this.market_tz) return dt; - var tzdt; - if (tz) { - tzdt = new this.tz_lib( - dt.getFullYear(), - dt.getMonth(), - dt.getDate(), - dt.getHours(), - dt.getMinutes(), - dt.getSeconds(), - dt.getMilliseconds(), - tz - ); - } else { - tzdt = new this.tz_lib( - dt.getFullYear(), - dt.getMonth(), - dt.getDate(), - dt.getHours(), - dt.getMinutes(), - dt.getSeconds(), - dt.getMilliseconds() - ); - } - if (tzdt.setTimezone) tzdt.setTimezone(this.market_tz); - return new Date( - tzdt.getFullYear(), - tzdt.getMonth(), - tzdt.getDate(), - tzdt.getHours(), - tzdt.getMinutes(), - tzdt.getSeconds(), - tzdt.getMilliseconds() - ); -}; - -/** - * Converts to the given timezone from the market's native time zone. - * If no market zone is present, the date will be returned un changed. - * @param {date} dt JavaScript Date - * @param {string} [tz] timezoneJS timezone, or null to indicate browser localtime/UTC (displayZone) - * @return {date} A JavaScript Date offset by the timezone change - * @memberOf CIQ.Market - */ -CIQ.Market.prototype._convertFromMarketTZ = function (dt, tz) { - //if(!this.market_tz) return dt; - var tzdt = new this.tz_lib( - dt.getFullYear(), - dt.getMonth(), - dt.getDate(), - dt.getHours(), - dt.getMinutes(), - dt.getSeconds(), - dt.getMilliseconds(), - this.market_tz - ); - if (tz) { - if (tzdt.setTimezone) tzdt.setTimezone(tz); - } else { - return new Date(tzdt.getTime()); - } - return new Date( - tzdt.getFullYear(), - tzdt.getMonth(), - tzdt.getDate(), - tzdt.getHours(), - tzdt.getMinutes(), - tzdt.getSeconds(), - tzdt.getMilliseconds() - ); -}; - -/** - * Builds an iterator instance and returns it to the requesting market when {@link CIQ.Market#newIterator} is called. Do not call this constructor directly. - * - * @name CIQ.Market.Iterator - * @param {object} parms - * @param {object} parms.begin A dataset element from {@link CIQ.Chart.dataSet} - * @param {CIQ.Market} parms.market An instane of {@link CIQ.Market} - * @param {object} parms.periodicity A valid periodicity as require by {@link CIQ.ChartEngine#setPeriodicity} - * @param {string} parms.interval Time interval: millisecond, second, minute, hour, day, week, or month. - * @param {object} parms.multiple How many jumps to make on each interval loop. - * @param {string} parms.inZone Datazone to translate from - * @param {string} parms.outZone Datazone to translate to - * @constructor - * @since 04-2016-08 - * @example - var market24=new CIQ.Market(); - var iter_parms = { - 'begin': stxx.chart.dataSet[stxx.chart.dataSet.length-1].DT, // last item on the dataset - 'interval': stxx.layout.interval, - 'periodicity': stxx.layout.periodicity, - 'timeUnit': stxx.layout.timeUnit, - 'inZone': stxx.dataZone, - 'outZone': stxx.dataZone - }; - var iter = market24.newIterator(iter_parms); - var next = iter.next(); - * - */ -CIQ.Market.Iterator = function (parms) { - this.market = parms.market; - this.begin = parms.begin; - this.interval = parms.interval; - this.multiple = parms.multiple; - this.inZone = parms.inZone; - this.outZone = parms.outZone; - this.clock = new CIQ.Market.Iterator._Clock( - parms.market, - parms.interval, - parms.multiple - ); - this.intraDay = this.clock.intra_day; - if (this.intraDay) - this.begin = this.market._convertToMarketTZ(this.begin, parms.inZone); - this.clock._setStart(this.begin); - this.clock.minutes_aligned = false; -}; - -/** - * Returns the current date of the iterator without moving forwards or backwards. - * Takes into account display zone settings. - * @return {date} The current date of the iterator. - * @memberof CIQ.Market.Iterator - * @since 04-2016-08 - * @example - * iteratorDate = iter.date(); - */ -CIQ.Market.Iterator.prototype.date = function () { - return this.clock._date(); -}; - -/** - * Calculate the number of ticks from begin date to end date taking into account - * market open, close, and holidays. - * If the end date is older than the begin date,it will work backward into the past. - * If the end date is newer than the begin date,it will work forward into the future. - * Note that the begin date is set when this - * instance of the iterator is created and one should NOT call `previous` or `next` - * before calling this function, or the 'begin' pointer will change. - * @param {object} parms An object containing the following properties: - * @param {date} parms.end An end date. Will be assumed to be `inZone` if one set. - * @param {number} [parms.sample_size] Default is 25. Maximum amount of time - * (in milliseconds) taken to count ticks. If sample size is - * reached before the number of ticks is found the number of ticks will be - * estimated mathematically. The bigger the sample size couple with the - * distance between begin date and end date affect how precise the return value - * is. - * @param {number} [parms.sample_rate] Default is 1000. Maximum number of ticks to evaluate before checking `parms.sample_size`. - * @return {number} The number of ticks between begin and end. - * @memberof CIQ.Market.Iterator - * @since 04-2016-08 - * @example - * // find out how many ticks in the past a date is from the beginning of the dataSet - * // (assumes the target date is older than the first dataSet item) - * var iter = this.standardMarketIterator(chart.dataSet[0].DT); - * var ticks=iter.futureTick({someRandomDate}); - */ -CIQ.Market.Iterator.prototype.futureTick = function (parms) { - this.clock.skip = 1; - var ticks = 0; - var end; - if (this.intraDay) - end = this.market._convertToMarketTZ(parms.end, this.inZone).getTime(); - else end = parms.end.getTime(); - var begin = this.clock.ctime; - if (end === begin) { - return ticks; - } - var sample_size = 2; //milliseconds // May not be necessary at all. Looks accurate whenever past 1,000 ticks into future - var sample_rate = 1000; //iterations - var sample_ctr = 0; - if (parms.sample_size) { - sample_size = parms.sample_size; - } - var start = new Date().getTime(); - var now; - var ave; - if (end > begin) { - this.clock.forward = true; - while (this.clock.ctime < end) { - ticks += 1; - sample_ctr += 1; - this.clock._findNext(); - if (sample_ctr === sample_rate) { - sample_ctr = 0; - now = new Date().getTime(); - if (now - start >= sample_size) { - ave = (this.clock.ctime - begin) / ticks; - ticks = Math.floor((end - begin) / ave); - break; - } - } - } - if (this.clock.ctime > end) { - // if not an exact match, we are one tick too far in the future by now. - // Go back one to return the tick that contains this time in its range. Rather than the next tick. - ticks--; - } - } else { - this.clock.forward = false; - while (this.clock.ctime > end) { - ticks += 1; - sample_ctr += 1; - this.clock._findPrevious(); - if (sample_ctr === sample_rate) { - sample_ctr = 0; - now = new Date().getTime(); - if (now - start >= sample_size) { - ave = (begin - this.clock.ctime) / ticks; - ticks = Math.floor((begin - end) / ave); - break; - } - } - } - } - return ticks; -}; - -/** - * Checks if market is aligned and if iterator is intraday (daily intervals always align) - * @return {boolean} true if this market is hour aligned. - * @memberof CIQ.Market.Iterator - * @since 04-2016-08 - */ -CIQ.Market.Iterator.prototype.isHourAligned = function () { - return !this.intraDay || this.market.isHourAligned(); -}; - -/** - * Check and see if this Market is open now. - * @return {object} An object with the open market session's details, if the market is open right now. Or `null` if no sessions are currently open. - * @memberof CIQ.Market.Iterator - * @since 04-2016-08 - */ -CIQ.Market.Iterator.prototype.isOpen = function () { - return this.market.isOpen(); -}; - -/** - * Move the iterator one interval forward - * @param {number} [skip] Default 1. Jump forward skip * periodicity at once. - * @return {date} Next date in iterator `outZone`. - * @alias next - * @memberof CIQ.Market.Iterator - * @since 04-2016-08 - * @example - * now = iter.next(); - */ -CIQ.Market.Iterator.prototype.next = function (skip) { - this.clock.skip = 1; - if (skip) { - this.clock.skip = skip; - } - this.clock.forward = true; - for (var i = 0; i < this.clock.skip; i++) this.begin = this.clock._findNext(); - if (this.intraDay || this.market.convertOnDaily) { - return this.market._convertFromMarketTZ( - this.clock.display_date, - this.outZone - ); - } - return this.clock.display_date; -}; - -/** - * Does not move the iterator. Takes into account display zone settings. - * Note. This is a convenience function for debugging or whatever else, but - * should not be called in the draw loop in production. - * @return {string} The current date of the iterator as a string. - * @memberof CIQ.Market.Iterator - * @since 04-2016-08 - * @private - */ -CIQ.Market.Iterator.prototype.peek = function () { - return this.clock._peek(); -}; - -/** - * Move the iterator one interval backward - * @param {number} skip Default is one. Move this many multiples of interval. - * @return {date} Previous date in iterator `outZone`. - * @alias previous - * @memberof CIQ.Market.Iterator - * @since 04-2016-08 - * @example - * now = iter.previous(); - */ -CIQ.Market.Iterator.prototype.previous = function (skip) { - this.clock.skip = 1; - if (skip) { - this.clock.skip = skip; - } - this.clock.forward = false; - for (var i = 0; i < this.clock.skip; i++) - this.begin = this.clock._findPrevious(); - if (this.intraDay || this.market.convertOnDaily) { - return this.market._convertFromMarketTZ( - this.clock.display_date, - this.outZone - ); - } - return this.clock.display_date; -}; - -/** - * Internal object that simulates a clock that ticks forward and backwards - * at different intervals. Used internally by the iterator and not intended - * to be used outside of the context of a Market. - * @param {object} market An instance of market. - * @param {string} interval millisecond, second, minute, hour, day, week or month - * @param {number} multiple Move in multiple of intervals. - * @private - */ -CIQ.Market.Iterator._Clock = function (market, interval, multiple) { - // rationalize rolled up intervals for better performance - if (multiple % 60 === 0 && interval === "second") { - interval = "minute"; - multiple = multiple / 60; - } - - this.market = market; - this.interval = interval; - this.multiple = multiple; - this.intra_day = false; - this.intervals = []; - this.max_iters = 10080; //max minutes to check for rules. (one week); - - var tick_time = DAY_MILLIS, - findNext = this._dayImpl; - if (interval === "millisecond") { - findNext = this._millisImpl; - tick_time = 1; - } else if (interval === "second") { - findNext = this._secondImpl; - tick_time = 1000; - } else if (interval === "minute") { - findNext = this._minuteImpl; - tick_time = 60000; - } else if (interval === "hour") { - findNext = this._hourImpl; - tick_time = HOUR_MILLIS; - } else if (interval === "day") { - findNext = this._dayImpl; - tick_time = DAY_MILLIS; - } else if (interval === "week") { - findNext = this._weekImpl; - tick_time = DAY_MILLIS * 7; - } else if (interval === "month") { - findNext = this._monthImpl; - tick_time = DAY_MILLIS * 30; - } else { - console.log( - 'Periodicity ERROR: "' + - interval + - '" is not a valid interval. Please see setPeriodicity() for details.' - ); - } - this.tick_time = tick_time * multiple; - this.intra_day = this.tick_time < DAY_MILLIS; - this._findPrevious = this._findNext = findNext; -}; - -//Save me some carpal tunnel please. -var _ClockP = CIQ.Market.Iterator._Clock.prototype; - -/** - * Calculate the amount of minutes in a given time span. - * This assumes hours are 24 hour format. - * - * NOTE! Does not know how to jump a 24 hour period, assumes that - * oHour is always less than cHour on the same day. - * - * This could be done with two dates instead and remove the limitations. Not - * sure if that is necessary at this point. We don't actually have two date - * objects at the point that we need this number. It would take some doing to - * figure out the date objects that would be needed. - * @param {number} oHour The opening hour - * @param {number} oMin The opening minute - * @param {number} cHour The closing hour - * @param {number} cMin The closing minute - * @return {number} Amount of minutes in a given time span. - * @private - */ -_ClockP._total_minutes = function (oHour, oMin, cHour, cMin) { - //the parens are important in this case - return (cHour - oHour) * 60 - oMin + cMin; -}; - -/** - * Create an array of minutes from the open minute to the close minute at - * some periodicity. This array will run the entire time of the last segment - * time segment matched. - * @return {array} Periods - * @private - */ -_ClockP._alignMinutes = function () { - if (!this.market.market_def || this.market.zopen_minute === undefined) { - return []; - } - var o_min = this.market.zopen_minute; - var match = this.market.zseg_match; - if (match && match.adjacent_parent) { - o_min = match.adjacent_parent.open / 60 - 1440; - } else { - if (this.market.isHourAligned() && this.multiple % 60 === 0) o_min = 0; - } - var total_minutes = this._total_minutes( - this.market.zopen_hour, - o_min, - this.market.zclose_hour, - this.market.zclose_minute - ); - var periods = []; - var next_minute = 0; - while (next_minute < total_minutes) { - periods.push(o_min + next_minute); - next_minute += this.multiple; - } - return periods; -}; - -/** - * Create an array of second boundaries. This only needs to be done once - * per clock instance. - * @param {number} max The high end of the range before wrapping back to zero. - * @return {array} Periods - * Example for seconds this would be 60. - * @private - */ -_ClockP._alignBaseZero = function (max) { - var base = 0; - var periods = [base]; - while (true) { - base += this.multiple; - if (base >= max) { - break; - } - periods.push(base); - } - return periods; -}; - -/** - * Turn this instance of the clock into a date object at the current - * date time. - * @return {date} A new Date object. - * @private - */ -_ClockP._date = function () { - var t = Math.round(this.ctime); - var current_date = new Date(t); - - if (this.intra_day) { - this.display_date = new Date(t + this.shift_millis); - } else { - this.display_date = current_date; - } - - return current_date; -}; - -/** - * Find the boundary for minutes, seconds or milliseconds. - * @param {array} periods A pre-calculated list of boundaries. - * @param {number} search_for Any number to align. - * @return {number} one of the boundaries in the array. - * @private - */ -_ClockP._alignToBoundary = function (periods, search_for) { - var low = 0; - var high = 0; - var result = search_for; - - for (var ctr = 0; ctr < periods.length - 1; ctr++) { - low = periods[ctr]; - high = periods[ctr + 1]; - if (search_for === low || search_for === high) { - break; //already aligned; - } - if (search_for > low && search_for < high) { - result = low; - break; - } else if (ctr + 1 === periods.length - 1) { - //wrap around gap - result = high; - } - } - return result; -}; - -/** - * Convenience for debugging. - * @return {string} Current market date as a string - * @private - */ -_ClockP._peek = function () { - return this._date().toString(); -}; - -/** - * When searching for open days look in hour increments. - * Inverted. - * @private - */ -_ClockP._seekHr = function () { - if (this.forward) { - this.ctime -= HOUR_MILLIS; - } else { - this.ctime += HOUR_MILLIS; - } -}; - -/** - * Set this instance of the iterator clock to some date. Calls to next or - * previous will move the clock some interval from this point in time. - * @param {date} date Any javascript date. - * @private - */ -_ClockP._setStart = function (date) { - var millis = this.market._tzDifferenceMillis(date); - var shift_date = new Date(date.getTime() + millis); - this.shift_millis = millis; - this.ctime = shift_date.getTime(); - // override timezone shift - this.shift_millis = 0; - this.ctime = date.getTime(); -}; - -/** - * Regular clock move - * @private - */ -_ClockP._tickTock = function () { - if (this.forward) { - //this.ctime += (this.tick_time * this.skip); - this.ctime += this.tick_time; - } else { - //this.ctime -= (this.tick_time * this.skip); - this.ctime -= this.tick_time; - } -}; - -/** - * Inverted clock move - * @private - */ -_ClockP._tockTick = function () { - if (this.forward) { - //this.ctime -= (this.tick_time * this.skip); - this.ctime -= this.tick_time; - } else { - //this.ctime += (this.tick_time * this.skip); - this.ctime += this.tick_time; - } -}; - -/** - * Move a day at a time. Useful for finding the first open day - * of a week or month. Always moves forward. - * @private - */ -_ClockP._tickTock24 = function () { - this.ctime += DAY_MILLIS; -}; - -/** - * Move a day at a time inverted. Useful for finding Sunday when - * moving by weeks. Always moves backwards. - * @private - */ -_ClockP._tockTick24 = function () { - this.ctime -= DAY_MILLIS; -}; - -/** - * Wind the clock to the next open market time. If the market is already open - * then don't move. Break out of the loop after max_iters regardless. - * @param {function} was_open Intraday or daily function to see if the market - * was open. - * @param {function} wind _tockTick (inverted) or _tickTock (regular) - * @return {boolean} True if the clock was moved - * @private - */ -_ClockP._windMaybe = function (was_open, wind) { - var max = 0; - var working_date = new Date(this.ctime); - var moved = false; - while (!was_open.call(this.market, working_date)) { - wind.call(this); - moved = true; - working_date = new Date(this.ctime); - max += 1; - if (max > this.max_iters) { - var m = "Warning! max iterations (" + this.max_iters; - m += ") reached with no rule match."; - console.log(m); - break; - } - } - return moved; -}; - -/** - * Move the clock some number of milliseconds - * @return {date} Current market date - * @private - */ -_ClockP._millisImpl = function () { - var justAligned = false; - if (!this.mperiods_aligned) { - var periods = this._alignBaseZero(1000); - var current_date = new Date(this.ctime); - var current_millis = current_date.getMilliseconds(); - current_millis = this._alignToBoundary(periods, current_millis); - current_date.setMilliseconds(0); - this.ctime = current_date.getTime() + current_millis; // this allows for fractional millis - this.mperiods_aligned = true; - justAligned = true; - } - // handle market closes - var oldMinute = this._date().getMinutes(); - this._tickTock(); - var newMinute = this._date().getMinutes(); - if ( - (justAligned || oldMinute != newMinute) && - !this.market._wasOpenIntraDay(this._date()) - ) { - var seconds = this._date().getSeconds(); - var millis = this._date().getMilliseconds(); - var tickTime = this.tick_time; - this.tick_time = 60000; - var multiple = this.multiple; - this.multiple = 1; - this._minuteImpl(); - this.tick_time = tickTime; - this.multiple = multiple; - this.ctime += 1000 * seconds + millis; - } - return this._date(); -}; - -/** - * Move the clock some number of seconds - * @return {date} Current market date - * @private - */ -_ClockP._secondImpl = function () { - var justAligned = false; - if (!this.speriod_aligned) { - var periods = this._alignBaseZero(60); - var current_date = new Date(this.ctime); - var current_second = current_date.getSeconds(); - current_second = this._alignToBoundary(periods, current_second); - current_date.setSeconds(current_second); - current_date.setMilliseconds(0); - this.ctime = current_date.getTime(); - this.speriod_aligned = true; - justAligned = true; - } - // handle market closes - var oldMinute = this._date().getMinutes(); - this._tickTock(); - var newMinute = this._date().getMinutes(); - if ( - (justAligned || oldMinute != newMinute) && - !this.market._wasOpenIntraDay(this._date()) - ) { - var seconds = this._date().getSeconds(); - var tickTime = this.tick_time; - this.tick_time = 60000; - var multiple = this.multiple; - this.multiple = 1; - this._minuteImpl(); - this.tick_time = tickTime; - this.multiple = multiple; - this.ctime += 1000 * seconds; - } - return this._date(); -}; - -/** - * Move the clock some number of minutes. Takes into account market start time - * and could change alignment each time it is called. - * @return {date} - * @private - */ -_ClockP._minuteImpl = function () { - var closed = this._windMaybe(this.market._wasOpenIntraDay, this._tockTick); - var current_date = new Date(this.ctime); - var tzOffset = current_date.getTimezoneOffset(); - var current_minute = current_date.getMinutes(); - var current_hour = current_date.getHours(); - var periods = this._alignMinutes(); //takes into account market start time - var boundary_min = - this._total_minutes( - this.market.zopen_hour, - this.market.zopen_minute, - current_hour, - current_minute - ) + this.market.zopen_minute; - if (closed) { - if (this.forward) { - boundary_min = periods[periods.length - 1]; - } else { - boundary_min = periods[0]; - } - } else { - boundary_min = this._alignToBoundary(periods, boundary_min); - } - current_hour = Math.floor(boundary_min / 60) + this.market.zopen_hour; - current_date.setHours(current_hour, boundary_min % 60, 0, 0); - var offsetDiff = current_date.getTimezoneOffset() - tzOffset; - if ((this.forward && offsetDiff < 0) || (!this.forward && offsetDiff > 0)) { - //crossed a fallback timezone boundary - current_date.setTime(current_date.getTime() - offsetDiff * 60000); - } - this.ctime = current_date.getTime(); //boundary aligned - this._tickTock(); //move once - - var alignToHour = this.market.hour_aligned && this.multiple % 60 === 0; - - // Calling `_windMaybe()` will eventually cause `_was_open()` to get called, which may set - // `this.shouldResetToBeginningOfSegment` to `true` if the clock has rolled over into a new - // market session - if ( - this._windMaybe(this.market._wasOpenIntraDay, this._tickTock) || - (!alignToHour && this.shouldResetToBeginningOfSegment) - ) { - current_date = new Date(this.ctime); - if (this.forward) { - current_date.setMinutes(this.market.zopen_minute); - current_date.setHours(this.market.zopen_hour); - } else { - periods = this._alignMinutes(); - var last_boundary = periods[periods.length - 1]; - current_date.setMinutes(last_boundary % 60); - current_date.setHours( - Math.floor(last_boundary / 60) + this.market.zopen_hour - ); - } - this.ctime = current_date.getTime(); - } - return this._date(); -}; - -/** - * Move the clock some number of hours. - * @return {date} - * @private - */ -_ClockP._hourImpl = function () { - this._windMaybe(this.market._wasOpenIntraDay, this._tockTick); - var current_time = new Date(this.ctime); - if (this.market.isHourAligned()) { - current_time.setMinutes(0); - } else { - current_time.setMinutes(this.market.zopen_minute); - } - current_time.setSeconds(0); - current_time.setMilliseconds(0); - this.ctime = current_time.getTime(); //boundary aligned - this._tickTock(); //move once - var current_segment = this.market.zseg_match; - if ( - this._windMaybe(this.market._wasOpenIntraDay, this._tickTock) || - (!this.market.hour_aligned && current_segment != this.market.zseg_match) - ) { - var current_date = new Date(this.ctime); - if (this.forward) { - current_date.setMinutes(this.market.zopen_minute); - current_date.setHours(this.market.zopen_hour); - } else { - var periods = this._alignMinutes(); - var last_boundary = periods[periods.length - 1]; - current_date.setMinutes(last_boundary % 60); - current_date.setHours( - Math.floor(last_boundary / 60) + this.market.zopen_hour - ); - } - this.ctime = current_date.getTime(); - } - return this._date(); -}; - -/** - * Move the clock some number of days. - * @return {date} - * @private - */ -_ClockP._dayImpl = function () { - this._windMaybe(this.market._wasOpenDaily, this._seekHr); - var current_date = new Date(this.ctime); //closest open day - current_date.setHours(12, 0, 0, 0); - this.ctime = current_date.getTime(); //boundary aligned - var ctr = 0; - while (ctr < this.multiple) { - if (this.forward) { - this._tickTock24(); - } else { - this._tockTick24(); - } - if (!this.market._wasOpenDaily(this._date())) { - continue; - } - ctr += 1; - } - current_date = new Date(this.ctime); - current_date.setHours(0); - this.ctime = current_date.getTime(); //boundary aligned - return this._date(); -}; - -/** - * Move the clock some number of weeks. - * @return {date} - * @private - */ -_ClockP._weekImpl = function () { - var market = this.market; - var current_date = new Date(this.ctime); - current_date.setHours(12); // Stay away from DST danger zone, so we know we only go back one date each tocktick - this.ctime = current_date.getTime(); - this._tickTock(); // move once - - // align to first day of week - current_date = new Date(this.ctime); - while (current_date.getDay() !== market.beginningDayOfWeek) { - this._tockTick24(); - current_date = new Date(this.ctime); - } - - // default to market day - this._windMaybe(market._wasOpenDaily, this._tickTock24); - current_date = new Date(this.ctime); - current_date.setHours(0, 0, 0, 0); - this.ctime = current_date.getTime(); //boundary aligned; - return this._date(); -}; - -/** - * Move the clock some number of months - * @return {date} - * @private - */ -_ClockP._monthImpl = function () { - //Allow some room to account for different lengths of months. - var current_date = new Date(this.ctime); - current_date.setDate(15); // Stay away from month boundaries so DST doesn't foil us - this.ctime = current_date.getTime(); - - this._tickTock(); // move once - current_date = new Date(this.ctime); - //Now re align back to the first day of the month - current_date.setDate(1); - current_date.setHours(12); // Stay away from DST danger zone - this.ctime = current_date.getTime(); - - //Now find the first open day of month - this._windMaybe(this.market._wasOpenDaily, this._tickTock24); - current_date = new Date(this.ctime); - current_date.setHours(0, 0, 0, 0); - this.ctime = current_date.getTime(); //boundary aligned; - return this._date(); -}; - -/** - * Search forward for the next market open - * @param {date} date Some begin date. - * @param {number} skip The number of intervals to move. Defaults - * to one. - * @return {date} A new date that has been set to the previous open of the - * market. - * @private - */ -_ClockP._findNext = null; - -/** - * Search backward for the next market open - * @param {date} date Some begin date. - * @param {number} skip The number of intervals to move. Defaults - * to one. - * @return {date} A new date that has been set to the previous open of the - * market. - * @private - */ -_ClockP._findPrevious = null; - -}; - - -let __js_standard_nameValueStore_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -/** - * Base class for interacting with a name/value store. - * - * This base class saves to local storage, but you can create your own function overrides for - * remote storage as long as you maintain the same function signatures and callback requirements. - * - * See {@link WebComponents.cq-views} for an implementation example. - * - * @constructor - * @name CIQ.NameValueStore - */ -CIQ.NameValueStore = CIQ.NameValueStore || function () {}; - -CIQ.NameValueStore.prototype.toJSONIfNecessary = function (obj) { - if (obj.constructor == String) return obj; - try { - var s = JSON.stringify(obj); - return s; - } catch (e) { - console.log("Cannot convert to JSON: " + obj); - return null; - } -}; - -CIQ.NameValueStore.prototype.fromJSONIfNecessary = function (obj) { - try { - var s = JSON.parse(obj); - return s; - } catch (e) { - return obj; - } -}; - -/** - * A function called after a retrieval operation on the name/value store has been completed. - * - * @param {object|string} error An error object or error code if data retrieval failed; null if - * data retrieval was successful. - * @param {object|string} response The data retrieved from storage or null if retrieval failed. - * - * @callback CIQ.NameValueStore~getCallback - * @since 8.2.0 - */ - -/** - * A function called after an update of the name/value store has been completed. - * - * @param {object|string} error An error object or error code if the storage update failed; null - * if the update was successful. - * - * @callback CIQ.NameValueStore~updateCallback - * @since 8.2.0 - */ - -/** - * Retrieves a value from the name/value store. - * - * @param {string} field The field for which the value is retrieved. - * @param {CIQ.NameValueStore~getCallback} cb A callback function called after the retrieval - * operation has been completed. Two arguments are provided to the callback function. The - * first argument indicates the success or failure of the operation; the second argument is - * the value returned by the operation. - * - * @memberof CIQ.NameValueStore - * @since 8.2.0 Made `cb` a required parameter; changed its type to - * {@link CIQ.NameValueStore~getCallback}. - * - * @example - * nameValueStore.get("myfield", function(err, data) { - * if (err) { - * // Do something with the error. - * } else { - * // Do something with the retrieved data. - * } - * }); - */ -CIQ.NameValueStore.prototype.get = function (field, cb) { - var value = CIQ.localStorage.getItem(field); - cb(null, this.fromJSONIfNecessary(value)); -}; - -/** - * Stores a value in the name/value store. - * - * @param {string} field The name under which the value is stored. - * @param {string|object} value The value to store. - * @param {CIQ.NameValueStore~updateCallback} [cb] A callback function called after the storage - * operation has been completed. A single argument, which indicates success or failure of the - * operation, is provided to the callback function. - * - * @memberof CIQ.NameValueStore - * @since 8.2.0 Changed the type of the `cb` parameter to {@link CIQ.NameValueStore~updateCallback}. - * - * @example - * nameValueStore.set("myfield", "myValue", function(err) { - * if (err) { - * // Do something with the error. - * } else { - * // Do something after the data has been stored. - * } - * }); - */ -CIQ.NameValueStore.prototype.set = function (field, value, cb) { - CIQ.localStorageSetItem(field, this.toJSONIfNecessary(value)); - if (cb) cb(null); -}; - -/** - * Removes a field from the name/value store. - * - * @param {string} field The field to remove. - * @param {CIQ.NameValueStore~updateCallback} [cb] A callback function called after the storage - * operation has been completed. A single argument, which indicates success or failure of the - * operation, is provided to the callback function. - * - * @memberof CIQ.NameValueStore - * @since 8.2.0 Changed the type of the `cb` parameter to {@link CIQ.NameValueStore~updateCallback}. - * - * @example - * nameValueStore.remove("myfield", function(err) { - * if (err) { - * // Do something with the error. - * } else { - * // Do something after the field has been removed. - * } - * }); - */ -CIQ.NameValueStore.prototype.remove = function (field, cb) { - CIQ.localStorage.removeItem(field); - if (cb) cb(null); -}; - -}; - - -let __js_standard_quoteFeed_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -if (!CIQ.ChartEngine) CIQ.ChartEngine = function () {}; - -/** - * See tutorial [Data Integration : Quotefeeds]{@tutorial DataIntegrationQuoteFeeds} for a complete overview and - * step by step source code for implementing a quotefeed - * - * Interface for classes that implement a quotefeed. You define a quotefeed object and attach it to - * the chart using {@link CIQ.ChartEngine#attachQuoteFeed}. Each member "fetch..." method is optional. The chart - * will call your member method if it exists, and will skip if it does not. - * - * Also see {@link CIQ.ChartEngine#dontRoll} if your feed aggregates weekly and monthly bars and you do not wish the chart to roll them from daily bars. - * - * @name quotefeed - * @namespace - * @property {number} maxTicks The maximum number of ticks a quoteFeed should request at a single time. This value will be overridden if the {@link CIQ.ChartEngine.Driver} has a behavior.maximumTicks set. - */ -function quotefeed() {} - -/** - * All of your quote feed "fetch..." methods **must** call this callback function to return - * results to the chart, even if no data is returned from your feed. - * - * @param {object} response Contains the results of the quote feed function that called this - * callback function. - * @param {string} [response.error] An error message, if one occurred. - * @param {string} [response.suppressAlert] Set this to true to not display errors. - * @param {array} [response.quotes] An array of quotes in required JSON format, if no error - * occurred. - * @param {boolean} [response.moreAvailable] Set this to false to stop pagination requests if - * you know that no older data is available. - * @param {boolean} [response.upToDate] Set this to true to stop forward pagination requests - * if you know that no newer data is available. - * @param {object} [response.attribution] This object is assigned to `stx.chart.attribution`. - * Your UI can use this to display attribution messages. See example below. - * - * @callback quotefeed~dataCallback - * - * @example Returning quotes in the dataCallback object. - * cb({quotes:[--array of quote elements here--]}); - * - * @example Returning an error in the dataCallback object. - * cb({error:"Your error message here"}); - * - * @example Setting attribution through the dataCallback - * object. - * - * // Set up a callback function to be called whenever fetchInitialData is called. - * stxx.attachQuoteFeed(yourQuoteFeed, {callback: showAttribution}); - * - * // After every data call, the attribution function is called, - * // and you can then use it to display any message regarding the quote feed. - * function showAttribution(params){ - * var message=params.stx.chart.attribution.message; - * // Add your code here to display the message on your screen. - * } - * - * // In your quote feed's fetchInitialData method, set the attribution object. - * cb({quotes:[--array of quote elements here--], attribution:{message:"Data is delayed by 15 minutes"}}); - * - * @since 8.0.0 Added the `response.upToDate` property. - */ - -/** - * See [Data Integration : Quotefeeds]{@tutorial DataIntegrationQuoteFeeds} - * - * The charting engine calls this quotefeed function whenever the chart is wiped clean and created again with new data. - * This typically occurs when {@link CIQ.ChartEngine#loadChart} is called but can also occur from other methods such as {@link CIQ.ChartEngine#setPeriodicity} - * or {@link CIQ.ChartEngine#importLayout}. - * - * @param {string} symbol The ticker symbol of the data being fetched - * @param {Date} suggestedStartDate A suggested starting date for the fetched data (based on how much can be displayed) - * @param {Date} suggestedEndDate A suggested starting date for the fetched data (based on how much can be displayed) - * @param {object} params -Provides additional information on the data requested by the chart. - * @param {Boolean} params.series -If true then the request is for series/comparison data (i.e. not the the main symbol) - * @param {CIQ.ChartEngine} params.stx -The chart object requesting data - * @param {string} [params.symbolObject] -The symbol to fetch in object format; if a symbolObject is initialized ( see {@link CIQ.ChartEngine#loadChart}, {@link CIQ.ChartEngine#addSeries}, {@link CIQ.Comparison.add} ) - * @param {number} params.period -The timeframe each returned object represents. For example, if using interval "minute", a period of 30 means your feed must return ticks (objects) with dates 30 minutes apart; where each tick represents the aggregated activity for that 30 minute period. **Note that this will not always be the same as the period set in {@link CIQ.ChartEngine#setPeriodicity}, since it represents the aggregation of the raw data to be returned by the feed server, rather than the final data to be displayed.** - * @param {string} params.interval -The type of data your feed will need to provide. Allowable values: "millisecond,"second","minute","day","week","month". (This is **not** how much data you want the chart to show on the screen; for that you can use {@link CIQ.ChartEngine#setRange} or {@link CIQ.ChartEngine#setSpan}) - * @param {Boolean} [params.fetchMaximumBars] -If set to true, the chart requires as much historical data as is available from the feed (params.ticks may also be set to 20,000 to set a safety max), regardless of start date. This is needed for some chart types since they aggregate data (kagi,renko, or linebreak, for example). Developers implementing fetch, should override params.tick and use a smaller number if their feed can't support that much data being sent back. The engine will then make multiple smaller calls to get enough data to fill the screen. - * @param {number} params.ticks -The suggested number of data points to return. This is calculated as twice the number of bars displayed on the chart. This can be used as an alternative to suggestedStartDate. - * @param {number} [params.timeout=10000] -This may be used to set the timeout in msec of the remote server request. - * @param {quotefeed~dataCallback} cb -Call this function with the results (or error) of your data request. - * @since 4.1.2 Added `timeout` parameter. - * @memberOf quotefeed - */ -quotefeed.fetchInitialData = function ( - symbol, - suggestedStartDate, - suggestedEndDate, - params, - cb -) {}; - -/** - * See [Data Integration : Quotefeeds]{@tutorial DataIntegrationQuoteFeeds} - * - * The charting engine calls this quotefeed function periodically (poll) to request updated data. - * The polling frequency is determined by the `refreshInterval` that you provided when you called {@link CIQ.ChartEngine#attachQuoteFeed}. - * - * @param {string} symbol The ticker symbol of the data being fetched - * @param {Date} startDate The starting date for the fetched data (based on how much can be displayed) - * @param {object} params -Provides additional information on the data requested by the chart. - * @param {Boolean} params.series -If true then the request is for series/comparison data (i.e. not the main symbol) - * @param {CIQ.ChartEngine} params.stx -The chart object requesting data - * @param {string} [params.symbolObject] -The symbol to fetch in object format; if a symbolObject is initialized ( see {@link CIQ.ChartEngine#loadChart}, {@link CIQ.ChartEngine#addSeries}, {@link CIQ.Comparison.add} ) - * @param {number} params.period -The timeframe each returned object represents. For example, if using interval "minute", a period of 30 means your feed must return ticks (objects) with dates 30 minutes apart; where each tick represents the aggregated activity for that 30 minute period. **Note that this will not always be the same as the period set in {@link CIQ.ChartEngine#setPeriodicity}, since it represents the aggregation of the raw data to be returned by the feed server, rather than the final data to be displayed.** - * @param {string} params.interval -The type of data your feed will need to provide. Allowable values: "millisecond,"second","minute","day","week","month". (This is **not** how much data you want the chart to show on the screen; for that you can use {@link CIQ.ChartEngine#setRange} or {@link CIQ.ChartEngine#setSpan}) - * @param {number} [params.timeout=10000] -This may be used to set the timeout in msec of the remote server request. - * @param {quotefeed~dataCallback} cb -Call this function with the results (or error) of your data request. - * @since 4.1.2 Added `timeout` parameter. - * @memberOf quotefeed - */ -quotefeed.fetchUpdateData = function (symbol, startDate, params, cb) {}; - -/** - * See [Data Integration : Quotefeeds]{@tutorial DataIntegrationQuoteFeeds} - * - * The charting engine calls this quotefeed function whenever the chart requires older data. - * Usually this is because a user has scrolled or zoomed past the end of the data. - * *Note: This method may be called during initial load if your fetchInitialData didn't provide enough data to fill the visible chart.* - * - * @param {string} symbol The ticker symbol of the data being fetched - * @param {Date} suggestedStartDate A suggested starting data for the fetched data (based on how much can be displayed) - * @param {Date} endDate The date of the last data point currently available in the chart. You should return data from this point and then backward in time. - * @param {object} params -Provides additional information on the data requested by the chart. - * @param {CIQ.ChartEngine} params.stx -The chart object requesting data - * @param {string} [params.symbolObject] -The symbol to fetch in object format; if a symbolObject is initialized ( see {@link CIQ.ChartEngine#loadChart}, {@link CIQ.ChartEngine#addSeries}, {@link CIQ.Comparison.add} ) - * @param {number} params.period -The timeframe each returned object represents. For example, if using interval "minute", a period of 30 means your feed must return ticks (objects) with dates 30 minutes apart; where each tick represents the aggregated activity for that 30 minute period. **Note that this will not always be the same as the period set in {@link CIQ.ChartEngine#setPeriodicity}, since it represents the aggregation of the raw data to be returned by the feed server, rather than the final data to be displayed.** - * @param {string} params.interval -The type of data your feed will need to provide. Allowable values: "millisecond,"second","minute","day","week","month". (This is **not** how much data you want the chart to show on the screen; for that you can use {@link CIQ.ChartEngine#setRange} or {@link CIQ.ChartEngine#setSpan}) - * @param {Boolean} [params.fetchMaximumBars] -If set to true, the chart requires as much historical data as is available from the feed (params.ticks may also be set to 20,000 to set a safety max), regardless of start date. This is needed for some chart types since they aggregate data (kagi,renko, or linebreak, for example). Developers implementing fetch, should override params.tick and use a smaller number if their feed can't support that much data being sent back. The engine will then make multiple smaller calls to get enough data to fill the screen. - * @param {number} params.ticks -The suggested number of data points to return. This is calculated as twice the number of bars displayed on the chart. This can be used as an alternative to suggestedStartDate. - * @param {number} [params.timeout=10000] -This may be used to set the timeout in msec of the remote server request. - * @param {Boolean} [params.future] -If set to true, the chart is scrolling in a 'forward' direction - * @param {quotefeed~dataCallback} cb -Call this function with the results (or error) of your data request. - * @since - * - 4.1.2 Added `params.timeout`. - * - 6.0.0 Added `params.future`. - * @memberOf quotefeed - */ -quotefeed.fetchPaginationData = function ( - symbol, - suggestedStartDate, - endDate, - params, - cb -) {}; - -/** - * See [Data Integration : Advanced]{@tutorial DataIntegrationAdvanced} - * - * Although not a core quotefeed function, the charting engine calls this optional function each time the chart encounters a new symbol or a particular periodicity for that symbol. - * This could happen when a user changes periodcity, changes a symbol, adds a comparison symbol, or a new study is added that requires an underlying symbol. - * - * Use this along with unsubscribe() to keep track of symbols on the chart. - * Use cases include: maintaining legends, lists of securities, or adding/removing subscriptions to streaming connections. - * - * If using a push stream, subscribe and then have the push streamer push updates using {@link CIQ.ChartEngine#updateChartData}. - * - * @param {object} params -Provides additional information on the data requested by the chart. - * @param {CIQ.ChartEngine} params.stx -The chart object requesting data - * @param {string} params.symbol -The symbol being added - * @param {string} params.symbolObject -The symbol being added in object form - * @param {number} params.period -The timeframe each returned object represents. For example, if using interval "minute", a period of 30 means your feed must return ticks (objects) with dates 30 minutes apart; where each tick represents the aggregated activity for that 30 minute period. **Note that this will not always be the same as the period set in {@link CIQ.ChartEngine#setPeriodicity}, since it represents the aggregation of the raw data to be returned by the feed server, rather than the final data to be displayed.** - * @param {string} params.interval -The type of data your feed will need to provide. Allowable values: "millisecond,"second","minute","day","week","month". (This is **not** how much data you want the chart to show on the screen; for that you can use {@link CIQ.ChartEngine#setRange} or {@link CIQ.ChartEngine#setSpan}) - * @memberOf quotefeed - * @since 4.0.0 Changes to periodicity (period/interval) will now also cause subscribe calls. - */ -quotefeed.subscribe = function (params) {}; - -/** - * See [Data Integration : Advanced]{@tutorial DataIntegrationAdvanced} - * - * Although not a core quotefeed function, the charting engine calls this optional function each time the chart no longer requires a symbol or a particular periodicity for that symbol. - * - * @param {object} params -Provides additional information on the data requested by the chart. - * @param {CIQ.ChartEngine} params.stx -The chart object requesting data - * @param {string} params.symbol -The symbol being removed - * @param {string} params.symbolObject -The symbol being removed in object form - * @param {number} params.period -The timeframe each returned object represents. For example, if using interval "minute", a period of 30 means your feed must return ticks (objects) with dates 30 minutes apart; where each tick represents the aggregated activity for that 30 minute period. **Note that this will not always be the same as the period set in {@link CIQ.ChartEngine#setPeriodicity}, since it represents the aggregation of the raw data to be returned by the feed server, rather than the final data to be displayed.** - * @param {string} params.interval -The type of data your feed will need to provide. Allowable values: "millisecond,"second","minute","day","week","month". (This is **not** how much data you want the chart to show on the screen; for that you can use {@link CIQ.ChartEngine#setRange} or {@link CIQ.ChartEngine#setSpan}) - * @memberOf quotefeed - * @since 4.0.0 Changes to periodicity (period/interval) will now also cause unsubscribe calls. - */ -quotefeed.unsubscribe = function (params) {}; - -/** - * See tutorial [Data Integration : Quotefeeds]{@tutorial DataIntegrationQuoteFeeds} for a complete overview and - * step by step source code for implementing a quotefeed - * - * @namespace - * @name CIQ.QuoteFeed - * @private - */ -CIQ.QuoteFeed = CIQ.QuoteFeed || function () {}; - -/** - * @private - * @param {object} params - * @param {function} cb Callback - * @deprecated - */ -CIQ.QuoteFeed.prototype.fetch = function (params, cb) { - if (!this.v2QuoteFeed) { - console.log( - "You must implement CIQ.QuoteFeed.[yourfeedname].prototype.fetch()" - ); - } -}; - -/** - * Whenever an error occurs the params and dataCallback from fetch will be automatically passed to this method by the quote engine. - * - * Use this to alert the user if desired. - * - * Override this with your own alerting mechanisms. - * @param {object} params The params originally passed into the fetch call. - * @param {object} dataCallback The data returned to fetch - * @memberOf quotefeed - * @alias announceError - * @example - * quotefeed.announceError=function(params, dataCallback){ - * if(params.startDate){ - * // Perhaps some sort of "disconnected" message on screen - * }else if(params.endDate){ - * // Perhaps something indicating the end of the chart - * }else{ - * CIQ.alert("Error fetching quote:" + dataCallback.error); // Probably a not found error? - * } - * }; - */ -CIQ.QuoteFeed.prototype.announceError = function (params, dataCallback) { - if (params.suppressErrors || dataCallback.suppressAlert) return; - if (params.startDate) { - // Perhaps some sort of "disconnected" message on screen - } else if (params.endDate) { - // Perhaps something indicating the end of the chart - } else if (dataCallback.error) { - CIQ.alert("Error fetching quote:" + dataCallback.error); - } else { - //CIQ.alert("Error fetching quote:" + params.symbol); // Probably a not found error? - } -}; - -/** - * Fetches multiple quotes asynchronously, possibly from various data sources. This method is used to update a chart with multiple symbols - * such as a comparison chart. - * - * @param {array} arr Array of stock symbols. - * @param {Function} cb Function to callback when quotes are fetched. Passed an array of results. Each result is an object `{dataCallback, params}`. - * @memberOf CIQ.QuoteFeed - * @since 7.3.0 Deprecated - * @deprecated Use `CIQ.ChartEngine.Driver.prototype.multifetch`. - * @private - */ -CIQ.QuoteFeed.prototype.multiFetch = function (arr, cb) { - if (arr.length === 0) cb([]); - - return arr[0].stx.driver.multiFetch(arr, cb); -}; - -/** - * QuoteFeed for managing streaming data - * @constructor - * @private - */ -CIQ.QuoteFeed.Subscriptions = function () { - this.subscriptions = []; -}; - -CIQ.inheritsFrom(CIQ.QuoteFeed.Subscriptions, CIQ.QuoteFeed); - -/** - * Used by the QuoteFeed Driver to create subscribe and unsubscribe calls as needed. - * - * @param {CIQ.ChartEngine} stx engine instance - * @since 4.0.0 Changes to periodicity (period/interval) will cause subscribe/unsubscribe calls. - * @private - */ -CIQ.QuoteFeed.Subscriptions.prototype.checkSubscriptions = function (stx) { - var sub, need; - var chartNeeds = stx.getSymbols({ "breakout-equations": true }); - var self = this; - chartNeeds = chartNeeds.filter(function (sub) { - var qf = stx.quoteDriver.getQuoteFeed(sub); - return qf && qf.engine == self; - }); - - // reset subscription match status - for (var s = 0; s < this.subscriptions.length; s++) { - this.subscriptions[s].match = false; - } - - for (var i = 0; i < chartNeeds.length; i++) { - // Convert kernel periodicity/interval/timeUnit to feed format - need = chartNeeds[i]; - var interval = need.interval; - // If we're rolling our own months or weeks then we should ask for days from the quote feed - if ((interval == "month" || interval == "week") && !stx.dontRoll) { - interval = "day"; - } - - need.interval = interval; - need.period = 1; - need.match = false; - - if (!isNaN(need.interval)) { - // normalize numeric intervals into "minute" form - need.period = need.interval; - need.interval = need.timeUnit; - if (!need.interval) need.interval = "minute"; - } - delete need.periodicity; // to avoid confusion - delete need.timeUnit; // to avoid confusion - delete need.setSpan; // to avoid confusion - - for (s = 0; s < this.subscriptions.length; s++) { - sub = this.subscriptions[s]; - if ( - sub.symbol == need.symbol && - sub.period == need.period && - sub.interval == need.interval - ) { - need.match = true; - sub.match = true; - break; - } else if (sub.symbol != need.symbol) { - if (need.reason != "period") need.reason = "symbol"; - sub.reason = "symbol"; - } else { - need.reason = "period"; - sub.reason = "period"; - } - } - } - //console.log(this.subscriptions); - //console.log(chartNeeds); - - // unsubscribe to any symbols no longer matched, and remove them from subscriptions - this.subscriptions = this.subscriptions.filter(function (c) { - if (!c.match) { - if (!c.stx) c.stx = stx; - self.unsubscribe(c); - } - return c.match; - }); - - chartNeeds.forEach(function (c) { - if (!c.match) { - if (!c.stx) c.stx = stx; - if (!c.reason) c.reason = "initialize"; - if (c.symbol !== stx.chart.symbol) c.series = true; - self.subscribe(c); - self.subscriptions.push(c); - } - }); -}; - -/** - * Calls fetchFromSource and checks for subscription updates when successful. - * - * @param {Object} params - * @param {Function} cb - * @private - */ -CIQ.QuoteFeed.Subscriptions.prototype.fetch = function (params, cb) { - var self = this; - this.fetchFromSource(params, function (results) { - if (!results.error) { - self.checkSubscriptions(params.stx); - } - cb(results); - }); -}; - -/** - * Implement this method. Start your streaming here. - * - * @param {Object} params - * @private - */ -CIQ.QuoteFeed.Subscriptions.prototype.subscribe = function (params) { - console.log("subscribe", params); -}; - -/** - * Implement this method. End your streaming here. - * - * @param {Object} params - * @private - */ -CIQ.QuoteFeed.Subscriptions.prototype.unsubscribe = function (params) { - console.log("unsubscribe", params); -}; - -/** - * The charting engine will call this method whenever it needs data from your feed. - * Override this with your implementation to fetch data from your server. - * Uses same parameters and format as CIQ.QuoteFeed.fetch. - * @param {object} params - * @param {function} cb Callback - * @memberOf CIQ.QuoteFeed.Subscriptions - * @private - * @deprecated - */ -CIQ.QuoteFeed.Subscriptions.prototype.fetchFromSource = function (params, cb) { - console.log("Please provide implementation of fetchFromSource"); -}; - -/** - * Return true if your quote feed should make an immediate refresh after initial load. For instance if your - * initial load is EOD and then you need to immediately load a real-time bar - * @param {object} params The same parameters that are passed to fetch() - * @return {boolean} Return true if a refresh is required immediately - * @memberOf CIQ.QuoteFeed - * @private - */ -CIQ.QuoteFeed.prototype.requiresImmediateRefresh = function (params) { - return false; -}; - -/** - * Attaches a quote feed to the charting engine by creating an internal quote feed driver, which - * the chart uses to pull data from the quote feed as needed. - * - * Multiple quote feeds may be attached to the engine by including the `filter` parameter, which - * enables the quote feed driver to determine whether the quote feed should be used for a - * specified instrument. If a filter is not provided, the quote feed becomes the default quote - * feed and is used if all other attached quote feeds (which must have filters) do not match the - * filter criteria. - * - * Only one unfiltered quote feed can be attached to the chart engine. If you call this function - * without a `filter` argument when a default, unfiltered quote feed is already attached, all - * attached quote feeds, including the default quote feed, are removed, and the object passed to - * `quoteFeed` is attached as the new default. - * - * **Note:** You must attach filtered quote feeds in order of priority. The quote feeds are - * filtered in the order in which they are attached to the engine. The first quote feed that - * matches the filter criteria is used. If none of the filtered quote feeds match the criteria, - * the unfiltered default quote feed is used. The default quote feed can be attached without - * regard to priority. - * - * @param {object} [quoteFeed] Your quote feed object. - * @param {object} [behavior] Contains initialization parameters for the quote feed. - * @param {number} [behavior.suppressErrors] If true, then no error is displayed when the quote - * feed returns one. Instead, the new symbol is simply not loaded and the prior symbol - * remains on the screen. - * @param {number} [behavior.refreshInterval] If not null, then sets the frequency for fetching - * updates (if null or zero then `fetchUpdateData` is not called). - * @param {number} [behavior.forwardPaginationRetryInterval] Defaults to five seconds when set to - * null. In [historical mode]{@tutorial DataIntegrationQuoteFeeds}, determines how often - * (in seconds) a forward pagination attempt can be tried. Forward pagination is different - * than a fetch update, in that it tries to get enough data just to fill the gap in the - * visible portion of the chart rather than to request an update from the visible area to - * the current candle, which depending on the visible range, could be days or months away. - * @param {number} [behavior.bufferSize] The minimum number of undisplayed historical ticks that - * will always be buffered in `masterData`. Useful to prevent temporary gaps on studies while - * paginating. This forces pagination fetch requests to be triggered ahead of reaching the - * edge of the chart, if the number of already loaded bars is less than the required buffer - * size. This parameter can be reset at any time by manipulating - * `stxx.quoteDriver.behavior.bufferSize`; it will then become active on the very next - * loading check. It is used on both left and right side pagination requests. - * @param {function} [behavior.callback] Optional callback after any fetch to enhance - * functionality. It will be called with the params object used with the fetch call. - * @param {number} [behavior.noLoadMore] If true, then the chart does not attempt to load any - * more data after the initial load. - * @param {number} [behavior.findHeadOfData] If true, then the chart attempts to load more data - * (and find the most recent) if the initial load returned no data. - * @param {boolean} [behavior.loadMoreReplace] If true, then when paginating, the driver replaces - * `masterData` instead of prepending. Set this if your feed can only provide a full data - * set of varying historical lengths. - * @param {string} [behavior.adjustmentMethod] Overrides the quote feed's default dividend/split - * adjustment method. The value will depend on the particular quote feed implementation. - * @param {number} [behavior.maximumTicks=20000] Limits the maximum number of ticks to request - * from a quote feed. Setting a value in the quote driver's behavior overrides an - * individual quote feed's `maxTicks` value. - * @param {boolean} [behavior.ignoreUpdateError] Indicates that an update that fails should be - * treated as no data found rather than an error. - * @param {function} [filter] Filters the quote feed provided by the `quoteFeed` parameter. The - * filter function takes an object parameter typically containing `symbolObject`, `symbol`, - * and `interval` properties. The properties associate the quote feed with an instrument. - * If the `filter` function returns true, the quote feed is used for the instrument. - * - * @memberof CIQ.ChartEngine - * @since - * - 2016-12-01 - * - 5.0.0 Added `behavior.bufferSize` parameter. - * - 5.1.1 Added `behavior.maximumTicks` parameter. - * - 6.0.0 Added `behavior.forwardPaginationRetryInterval` parameter. - * - 6.2.3 Added `behavior.ignoreUpdateError` parameter. - * - 7.2.0 Added `behavior.findHeadOfData` parameter. - * - 7.3.0 Added `filter` parameter. - * - * @see Multiple Quote Feeds in the [Data Integration: Advanced]{@tutorial DataIntegrationAdvanced} - * tutorial. - * - * @example Attach a quote feed and have the driver call fetchUpdateData - * once per second. - * stxx.attachQuoteFeed( - * yourQuotefeed, - * { refreshInterval:1, bufferSize:200 }, - * function (params) { - * return CIQ.Market.Symbology.factory(params.symbolObject) == CIQ.Market.FOREX - * && params.symbol == "^USDCAD" - * && params.interval == "day"; - * } - * ); - * @since - * - 2016-12-01 - * - 5.0.0 Added `behavior.bufferSize`. - * - 5.1.1 Added `behavior.maximumTicks`. - * - 6.0.0 Added `behavior.forwardPaginationRetryInterval`. - * - 6.2.3 Added `behavior.ignoreUpdateError`. - * - 7.2.0 Added `behavior.findHeadOfData` parameter. - * - 7.3.0 Added `filter` parameter. - */ -CIQ.ChartEngine.prototype.attachQuoteFeed = function ( - quoteFeed, - behavior, - filter -) { - if (!behavior) behavior = {}; - - // Legacy QuoteFeeds - if ( - typeof quoteFeed.fetchInitialData === "function" || - typeof quoteFeed.fetchUpdateData === "function" || - typeof quoteFeed.fetchPaginationData === "function" - ) { - // New "duck typed" v2 quotefeed - if ( - typeof quoteFeed.fetchPaginationData !== "function" && - typeof quoteFeed.fetchUpdateData !== "function" - ) { - behavior.noLoadMore = true; - } - quoteFeed.v2QuoteFeed = true; // store flag in quotefeed to single new version of quotefeed - ["multiFetch", "announceError", "requiresImmediateRefresh"].forEach( - function (prop) { - if (!quoteFeed[prop] && quoteFeed[prop] !== false) - quoteFeed[prop] = CIQ.QuoteFeed.prototype[prop]; // no inheritance so add function - } - ); - if (typeof quoteFeed.subscribe === "function") { - // if subscription quotefeed - quoteFeed.checkSubscriptions = - CIQ.QuoteFeed.Subscriptions.prototype.checkSubscriptions; // no inheritance so add checkSubscriptions function - quoteFeed.subscriptions = []; - } - } - if (!behavior.maximumTicks) - behavior.maximumTicks = quoteFeed.maxTicks ? quoteFeed.maxTicks : 20000; // Historically this is the safest limit of ticks to fetch for response time - if (!behavior.bufferSize || behavior.bufferSize < 0) behavior.bufferSize = 0; - behavior.bufferSize = Math.round(behavior.bufferSize); - behavior.intervalTimer = null; // This is the setInterval which can be cleared to stop the updating loop - - if (this.quoteDriver) { - // adding a second unfiltered quotefeed, must be trying to replace the quotefeeds, delete quoteDriver - if (!filter && this.quoteDriver.hasUnfilteredQuoteFeed) - this.detachQuoteFeed(); - else { - // make sure unfiltered feed remains last! - var unfilteredFeed = - this.quoteDriver.hasUnfilteredQuoteFeed && - this.quoteDriver.quoteFeeds.pop(); - this.quoteDriver.quoteFeeds.push({ - engine: quoteFeed, - behavior: behavior, - filter: filter - }); - if (unfilteredFeed) this.quoteDriver.quoteFeeds.push(unfilteredFeed); - this.quoteDriver.updateChartLoop(null, behavior); - } - } - if (!this.quoteDriver) { - // do not turn into an else clause, the detachQuoteFeed() above will remove the quoteDriver - this.quoteDriver = new CIQ.ChartEngine.Driver( - this, - quoteFeed, - behavior, - filter - ); - } - if (!filter) this.quoteDriver.hasUnfilteredQuoteFeed = true; -}; - -/** - * Detaches a quote feed. On removal of the last quote feed, calls `quoteDriver.die()`. - * - * @param {object} [quoteFeed] Optional quote feed object to detach. Omit to detach all quote feeds. - * @memberOf CIQ.ChartEngine - * @since 7.3.0 - */ -CIQ.ChartEngine.prototype.detachQuoteFeed = function (quoteFeed) { - var qd = this.quoteDriver; - if (!qd) return; - for (var i = qd.quoteFeeds.length - 1; i >= 0; i--) { - if (!quoteFeed || qd.quoteFeeds[i].quoteFeed == quoteFeed) { - qd.die(qd.quoteFeeds[i]); - qd.quoteFeeds.splice(i, 1); - } - } - if (!qd.quoteFeeds.length) { - qd = this.quoteDriver = null; - } else if (quoteFeed == qd.quoteFeed) { - qd.quoteFeed = qd.quoteFeeds[0].quoteFeed; - qd.behavior = qd.quoteFeeds[0].behavior; - } -}; - -/** - * Drives the chart's relationship with the quote feed object provided to the chart. - * - * @param {CIQ.ChartEngine} stx A chart engine instance. - * @param {object} quoteFeed A quote feed object. - * @param {object} [behavior] See {@link CIQ.ChartEngine#attachQuoteFeed} for object details. - * @property {boolean} [behavior.loadingNewChart=false] READ ONLY boolean telling when a chart is loading - * @property {boolean} [behavior.updatingChart=false] READ ONLY boolean telling when a chart is updating - * @param {function} [filter] See {@link CIQ.ChartEngine#attachQuoteFeed} for function details. - * @constructor - * @name CIQ.ChartEngine.Driver - * @private - * @since - * - 5.1.1 Added `maximumTicks` to `behavior` parameter. - * - 7.3.0 Moved `intervalTimer` property into `behavior` parameter. Added `filter` parameter. - */ -CIQ.ChartEngine.Driver = function (stx, quoteFeed, behavior, filter) { - this.stx = stx; - if (!behavior) behavior = {}; - this.quoteFeeds = [{ engine: quoteFeed, behavior: behavior, filter: filter }]; - this.id = CIQ.uniqueID(true); - this.behavior = behavior; // legacy - this.quoteFeed = quoteFeed; // legacy - this.loadingNewChart = false; // This gets set to true when loading a new chart in order to prevent refreshes while waiting for data back from the server - this.updatingChart = false; // This gets set when the chart is being refreshed - if (!filter) this.hasUnfilteredQuoteFeed = true; - this.updateChartLoop(); -}; - -CIQ.ChartEngine.Driver.prototype.die = function (quoteFeed) { - for (var qf = 0; qf < this.quoteFeeds.length; qf++) { - if (!quoteFeed || this.quoteFeeds[qf] == quoteFeed) { - var behavior = this.quoteFeeds[qf].behavior; - if (behavior.intervalTimer) { - clearInterval(behavior.intervalTimer); - behavior.intervalTimer = -1; // this means it was stopped by the die function and should not be started again in the event of an async call back from the fetch coming back after it was killed. - } - } - } -}; - -/** - * Finds the quote feed entry to use for a given security. Returns null if no match. - * The quote feed entry consists of an engine, a behavior, and a filter. - * - * @param {object} params Params to use to find the quote feed. - * @return {object} Matched quote feed, or null if no match found. - * @memberOf CIQ.ChartEngine.Driver - * @private - * @since 7.3.0 - */ -CIQ.ChartEngine.Driver.prototype.getQuoteFeed = function (params) { - if (!params.symbolObject) params.symbolObject = { symbol: params.symbol }; - for (var qf = 0; qf < this.quoteFeeds.length; qf++) { - var quoteFeed = this.quoteFeeds[qf]; - if (quoteFeed.behavior.generator != params.symbolObject.generator) continue; - if (!quoteFeed.filter || quoteFeed.filter(params)) return quoteFeed; - } - return null; //no match -}; - -/** - * Fetches multiple quotes asynchronously, possibly from various data sources. This method is used to update a chart with multiple symbols - * such as a comparison chart. - * - * @param {array} arr Array of stock symbols. - * @param {Function} cb Function to call back when quotes are fetched. Passed an array of results. Each result is an object `{dataCallback, params}`. - * @memberOf CIQ.ChartEngine.Driver - * @since 7.3.0 - * @private - */ -CIQ.ChartEngine.Driver.prototype.multiFetch = function (arr, cb) { - if (arr.length === 0) cb([]); - - var tracker = { - counter: 0, - finished: arr.length, - results: [] - }; - - function handleResponse(params, tracker, cb) { - return function (dataCallback) { - tracker.results.push({ dataCallback: dataCallback, params: params }); - tracker.counter++; - if (tracker.counter >= tracker.finished) { - var results = tracker.results; - tracker.results = []; - cb(results); - } - }; - } - for (var i = 0; i < arr.length; i++) { - var params = arr[i]; - if (params.stx.isEquationChart(params.symbol)) { - //equation chart - CIQ.fetchEquationChart(params, handleResponse(params, tracker, cb)); - } else { - var myQuoteFeed = this.getQuoteFeed(params); - if (myQuoteFeed) - CIQ.ChartEngine.Driver.fetchData( - CIQ.QuoteFeed.SERIES, - myQuoteFeed.engine, - params, - handleResponse(params, tracker, cb) - ); - } - } -}; - -/** - * Call this whenever the kernel knows that the symbols being used have changed - * @private - */ -CIQ.ChartEngine.Driver.prototype.updateSubscriptions = function () { - for (var qf = 0; qf < this.quoteFeeds.length; qf++) { - if (this.quoteFeeds[qf].checkSubscriptions) - this.quoteFeeds[qf].checkSubscriptions(this.stx); - } -}; - -/** - * Fetches quotes for symbols related to the chart which are not the primary symbol. - * such as series and study symbols. - * @param {object} params Params object used by the QuoteDriver in fetching data - * @param {Function} cb Function to callback when quotes are fetched. Will be passed an array of results. Each result is an object {dataCallback, params}. - * @param {number} fetchType Quotefeed constants e.g. CIQ.QuoteFeed.UPDATE, CIQ.QuoteFeed.PAGINATION, CIQ.QuoteFeed.INITIAL - * @param {object} [behavior] behavior from which to find quotefeed to fetch quotes from. If not provided, will iterate through all available. - * @memberOf CIQ.ChartEngine.Driver - * @private - */ -CIQ.ChartEngine.Driver.prototype.loadDependents = function ( - params, - cb, - fetchType, - behavior -) { - var self = this; - if (!behavior) { - var cnt = 0; - var independentQf = [], - dependentQf = []; - var cbDependentQf = function (res) { - if (cb && ++cnt >= self.quoteFeeds.length) cb(null); - }; - var cbIndependentQf = function (res) { - if (++cnt < independentQf.length) return; - if (!dependentQf.length) cbDependentQf(res); - dependentQf.forEach(function (qf) { - self.loadDependents(params, cbDependentQf, fetchType, qf.behavior); - }); - }; - self.quoteFeeds.forEach(function (qf) { - if (qf.behavior.generator) dependentQf.push(qf); - else independentQf.push(qf); - }); - independentQf.forEach(function (qf) { - self.loadDependents(params, cbIndependentQf, fetchType, qf.behavior); - }); - return; - } - var field; - var syms = {}; - var stx = params.stx; - var chart = params.chart; - var seriesList = chart.series; - var masterData = stx.masterData; - var series, symbolObject; - - // Create a master list of all symbols we need from our various dependencies: series and studySymbols - var allSymbols = [], - ranges = {}; - var isUpdate = fetchType == CIQ.QuoteFeed.UPDATE; - var isPaginate = fetchType == CIQ.QuoteFeed.PAGINATION; - var scratchParams = CIQ.shallowClone(params); - for (field in seriesList) { - series = seriesList[field]; - var sp = series.parameters; - if (!isUpdate) { - if (!params.future && series.moreAvailable === false) continue; // skip series that no longer have historical data. - if (params.future && series.upToDate === true) continue; // skip series that no longer have future data. - } - if (series.loading) continue; // skip series that are presently loading data - if (sp.loadData === false) continue; // skip series that do not load data - if (isUpdate || isPaginate) { - if (!series.endPoints || !Object.keys(series.endPoints).length) continue; // skip series which have not set range in master data yet - } - if (sp.data && !sp.data.useDefaultQuoteFeed) continue; // legacy - symbolObject = sp.symbolObject; - if (!symbolObject.symbol) continue; // skip series that are really just fields already loaded, like "High". - if (symbolObject.generator != behavior.generator) continue; - scratchParams.symbolObject = symbolObject; - scratchParams.symbol = symbolObject.symbol; - var qf = this.getQuoteFeed(scratchParams); - if (behavior != (qf && qf.behavior)) continue; // doesn't match behavior passed in; not updating on this loop - var isUnique = true; - if (!isUpdate) series.loading = true; - for (var j = 0; j < allSymbols.length; j++) { - if (CIQ.symbolEqual(allSymbols[j], symbolObject)) isUnique = false; - } - if (isUnique) { - allSymbols.push(symbolObject); - ranges[symbolObject.symbol] = series.endPoints; - } - } - - var arr = []; - for (var k = 0; k < allSymbols.length; k++) { - symbolObject = allSymbols[k]; - var seriesParam = CIQ.shallowClone(params.originalState); - seriesParam.symbol = symbolObject.symbol; - seriesParam.symbolObject = symbolObject; - if (seriesParam.update || seriesParam.future) { - if (!seriesParam.endDate) seriesParam.endDate = params.endDate; - seriesParam.startDate = ranges[symbolObject.symbol].end; - } else { - if (!seriesParam.startDate) seriesParam.startDate = params.startDate; - // for comparisons, you must fetch enough data on the new Comparison to match the beginning of the masterData until the current tick. - // The current tick may be newer than master data last tick, so set the end Date to right now. - seriesParam.endDate = - isPaginate && !params.future - ? ranges[symbolObject.symbol].begin - : params.endDate; - seriesParam.ticks = params.ticks; - } - arr.push(seriesParam); - } - if (!arr.length && isUpdate) { - // we need this because in updateChart we don't create and let the dependents do it. - var dsParams = { - appending: params.appending || params.originalState.update - }; - if (dsParams.appending) dsParams.appendToDate = params.startDate; - stx.createDataSet(null, null, dsParams); - if (!params.nodraw) stx.draw(); - if (cb) cb(null); - return; - } - - function MFclosure(isUpdate) { - return function (results) { - var earliestDate = null; - for (var i = 0; i < results.length; i++) { - var result = results[i]; - var error = result.dataCallback.error; - if (!error && error !== 0) { - var symbolObject = result.params.symbolObject; - var dataCallback = result.dataCallback, - quotes = dataCallback.quotes, - moreAvailable = dataCallback.moreAvailable, - upToDate = dataCallback.upToDate; - var arr = []; - if (stx.getSeries) - arr = stx.getSeries({ symbolObject: symbolObject }); - var fillGaps = false; - for (var j = 0; j < arr.length; j++) { - series = arr[j]; - if (!isUpdate) { - // only reset the moreAvailable/upToDate on pagination or initial fetch, never on updates. - if (!params.future) - series.moreAvailable = - moreAvailable === false - ? false - : moreAvailable || - quotes.length > (result.params.endDate ? 1 : 0); - else { - series.upToDate = - upToDate === true - ? true - : upToDate || - quotes.length <= (result.params.startDate ? 1 : 0); - if (stx.isHistoricalModeSet && quotes.length < 2) - series.mostRecentForwardAttempt = new Date(); - } - series.loading = false; - } - // Once fillGaps is set, do not unset it. - fillGaps = series.parameters.fillGaps || fillGaps; - } - quotes = self.cleanup( - stx, - series, - quotes, - fetchType, - params, - fillGaps - ); - stx.updateChartData(quotes, chart, { - secondarySeries: symbolObject.symbol, - noCreateDataSet: true, - noCleanupDates: true, - allowReplaceOHL: true - }); - if ( - quotes && - quotes.length && - (!earliestDate || earliestDate > quotes[0].DT) - ) - earliestDate = quotes[0].DT; - } - } - if (results.length) { - stx.createDataSet(null, null, { - appending: params.originalState.update || params.future, - appendToDate: earliestDate - }); - if (!params.nodraw) stx.draw(); - if (fetchType == CIQ.QuoteFeed.INITIAL) - self.resetRefreshInterval(behavior.refreshInterval, behavior); - } - if (cb) cb(null); - }; - } - - this.multiFetch(arr, MFclosure(isUpdate)); -}; - -/** - * Cleans up the dates and the gaps - * @memberOf CIQ.ChartEngine.Driver - * @private - * @since 5.2.0 - */ -CIQ.ChartEngine.Driver.prototype.cleanup = function ( - stx, - series, - quotes, - mode, - params, - fillGaps -) { - stx.doCleanupDates(quotes, stx.layout.interval); - if ( - !params.missingBarsCreated && - quotes && - quotes.length && - stx.cleanupGaps && - fillGaps !== false - ) { - var removalMethod, field; - var chartOrSeries = params.chart; - if (!series) field = chartOrSeries.defaultPlotField; - else { - chartOrSeries = series; - field = series.parameters.symbol || series.id; - } - if (mode == CIQ.QuoteFeed.PAGINATION && !params.loadMoreReplace) { - //add bar for end date so we can close gaps - if ( - chartOrSeries.endPoints.begin && - chartOrSeries.endPoints.begin > quotes[quotes.length - 1].DT - ) { - var endingRecord = stx.getFirstLastDataRecord( - stx.masterData, - field, - false - ); - if (series) endingRecord = endingRecord[field]; - quotes.push(endingRecord); - removalMethod = "pop"; - } - } else if (mode == CIQ.QuoteFeed.UPDATE) { - //add bar for begin date so we can close gaps - if ( - chartOrSeries.endPoints.end && - chartOrSeries.endPoints.end < quotes[0].DT - ) { - var beginningRecord = stx.getFirstLastDataRecord( - stx.masterData, - field, - true - ); - if (series) beginningRecord = beginningRecord[field]; - quotes.unshift(beginningRecord); - removalMethod = "shift"; - } - } - quotes = stx.doCleanupGaps(quotes, params.chart, { - cleanupGaps: fillGaps, - noCleanupDates: true - }); - if (removalMethod) quotes[removalMethod](); - } - return quotes; -}; - -/** - * Updates the chart as part of the chart loop. - * - * @param {object} [behavior] If set, only updates records that match the behavior. - * @memberOf CIQ.ChartEngine.Driver - * @private - * @since 7.3.0 Added the `behavior` parameter. - */ -CIQ.ChartEngine.Driver.prototype.updateChart = function (behavior) { - if (this.updatingChart) return; - if (this.loadingNewChart) return; - var howManyToGet = Object.keys(this.stx.charts).length; - var howManyReturned = 0; - var stx = this.stx; - - var interval = stx.layout.interval; - var timeUnit = stx.layout.timeUnit; - - function closure(self, params, symbol, quoteFeed) { - if (params.behavior.prefetchAction) - params.behavior.prefetchAction("updateChart"); - return function (dataCallback) { - howManyReturned++; - var chart = params.chart, - masterData = chart.masterData; - if ( - symbol == chart.symbol && - interval == stx.layout.interval && - timeUnit == stx.layout.timeUnit && - !stx.isHistoricalMode() - ) { - // Make sure user hasn't changed symbol while we were waiting on a response - if (!dataCallback.error) { - var quotes = dataCallback.quotes; - quotes = self.cleanup( - stx, - null, - quotes, - CIQ.QuoteFeed.UPDATE, - params - ); - stx.updateChartData(quotes, chart, { - noCreateDataSet: true, - noCleanupDates: true - }); - chart.attribution = dataCallback.attribution; - } else if (quoteFeed) { - quoteFeed.engine.announceError(params.originalState, dataCallback); - } - } else { - self.updatingChart = false; - return; - } - if (howManyReturned == howManyToGet) { - self.updatingChart = false; - } - if (params.behavior.callback) { - params.behavior.callback(params); - } - self.loadDependents(params, null, CIQ.QuoteFeed.UPDATE, params.behavior); // createDataSet(),draw() will be handled in here - }; - } - for (var chartName in stx.charts) { - var chart = stx.charts[chartName]; - if (!chart.symbol) continue; - // Removed below line. It's possible IPO has no quotes from loadChart but a BATS update will return data. - //if(!chart.masterData /*|| !chart.masterData.length*/) continue; // sometimes there is no data but it is not an error, and we want to let the refresh try again. If don't go in here, self.updatingChart will never be set to true and we will never refresh. - var params = this.makeParams(chart.symbol, chart.symbolObject, chart); - var myQuoteFeed = this.getQuoteFeed(params); - if (chart.masterData && chart.masterData.length) { - params.startDate = chart.endPoints.end; // if there is no data, then let the fetch treat an in initial load without start or end dates. - } - params.update = true; - params.originalState = CIQ.shallowClone(params); - if (behavior && behavior != params.behavior) { - this.loadDependents(params, null, CIQ.QuoteFeed.UPDATE, behavior); // bypassing main symbol fetch, but check series - continue; - } - this.updatingChart = true; - var closureCB = closure(this, params, chart.symbol, myQuoteFeed); - if (stx.isEquationChart(params.symbol)) { - //equation chart - CIQ.fetchEquationChart(params, closureCB); - } else if (myQuoteFeed) { - CIQ.ChartEngine.Driver.fetchData( - CIQ.QuoteFeed.UPDATE, - myQuoteFeed.engine, - params, - closureCB - ); - } - } -}; - -CIQ.ChartEngine.Driver.prototype.updateChartLoop = function ( - newInterval, - behavior -) { - if (!behavior) behavior = this.behavior; - if (behavior.intervalTimer == -1) return; // the driver was killed. This was probably an async call from a feed response sent before it was killed. - if (behavior.intervalTimer) clearInterval(behavior.intervalTimer); // stop the timer - var closure = function (self, thisBehavior) { - return function () { - if (thisBehavior.noUpdate) return; - self.updateChart(thisBehavior); - }; - }; - for (var qf = 0; qf < this.quoteFeeds.length; qf++) { - var thisBehavior = this.quoteFeeds[qf].behavior; - if (behavior == thisBehavior && !thisBehavior.noUpdate) { - if (!newInterval && newInterval !== 0) - newInterval = thisBehavior.refreshInterval; - if (newInterval) - behavior.intervalTimer = setInterval( - closure(this, thisBehavior), - newInterval * 1000 - ); - } - } -}; - -/** - * Convenience function to change the refresh interval that was set during {@link CIQ.ChartEngine#attachQuoteFeed}. - * - * @param {number} newInterval The new refresh interval in seconds. - * @param {object} [behavior] Optional behavior whose interval to reset, if omitted, will set first quote feed only. - * @memberOf CIQ.ChartEngine.Driver - * @private - * @since - * - 07/01/2015 - * - 7.3.0 Added `behavior` parameter. - */ -CIQ.ChartEngine.Driver.prototype.resetRefreshInterval = function ( - newInterval, - behavior -) { - (behavior || this.behavior).refreshInterval = newInterval; // set to your new interval - this.updateChartLoop(null, behavior); // restart the timer in the new interval -}; - -/** - * Loads all available data. - * - * @param {CIQ.ChartEngine.Chart} chart The chart to adjust. If left undefined, adjust the main symbol chart. - * @param {function} cb The callback function. Will be called with the error returned by the quotefeed, if any. - * @memberOf CIQ.ChartEngine.Driver - * @private - * @since 07/01/2015 - */ -CIQ.ChartEngine.Driver.prototype.loadAll = function (chart, cb) { - var self = this; - var count = 0; - function closure() { - return function (response) { - if (response) { - // error - cb(response); - } else if (!chart.moreAvailable && chart.upToDate) { - // no more data - cb(null); - //}else if(chart.loadingMore){ // something else is loading past data, abort this - // cb(null); - } else if (++count > 20) { - // we'll allow up to 20 fetches - cb("error, moreAvailable not implemented correctly in QuoteFeed"); - } else { - // get some more - chart.loadingMore = false; - self.checkLoadMore(chart, true, true, closure(), true); - } - }; - } - closure()(); -}; - -/** - * If the quote feed has indicated there is more data available it will create and execute a fetch() call, - * load the data into the masterData array, and create a new dataSet. Called internally as needed to keep the chart data up to date. - * Finally it will re-draw the chart to display the new data - * - * @param {CIQ.ChartEngine.Chart} chart The chart to adjust. Otherwise adjusts the main symbol chart. - * @param {boolean} forceLoadMore set to true to force a fetch() call. - * @param {boolean} fetchMaximumBars set to true to request the maximum amount of data available from the feed. - * @param {function} cb The callback function. Will be called with the error returned by the quotefeed, if any. - * @param {boolean} nodraw Set to true to skip over the draw() call - * @memberOf CIQ.ChartEngine.Driver - * @private - */ -CIQ.ChartEngine.Driver.prototype.checkLoadMore = function ( - chart, - forceLoadMore, - fetchMaximumBars, - cb, - nodraw -) { - var stx = this.stx, - driver = this; - - if (chart.loadingMore || this.loadingNewChart) { - chart.initialScroll = chart.scroll; - if (cb) cb(null); - return; - } - - var isHistoricalData = stx.isHistoricalMode(); - if (!isHistoricalData) stx.isHistoricalModeSet = false; - - var params = this.makeParams(chart.symbol, chart.symbolObject, chart); - - function finish(err) { - chart.loadingMore = false; - if (cb) cb(err); - } - - if (stx.currentlyImporting) { - if (cb) cb(null); - return; - } - - var myBehavior = params.behavior; - - var dataSet = chart.dataSet; - function needsBackFill(which) { - return ( - !which.endPoints.begin || - dataSet.length - chart.scroll < myBehavior.bufferSize || - dataSet.length - - chart.scroll - - stx.tickFromDate(which.endPoints.begin, chart) < - myBehavior.bufferSize - ); - } - function needsFrontFill(which) { - return ( - !which.endPoints.end || - chart.scroll - chart.maxTicks + 1 < myBehavior.bufferSize || - stx.tickFromDate(which.endPoints.end, chart, null, true) - - dataSet.length + - chart.scroll - - chart.maxTicks + - 2 < - myBehavior.bufferSize - ); - } - // The following var will be used to determine if it's ok to retry a forward pagination. - // Without this delay, a chart which ends in the past (delisted) or a chart with data coming in slowly - // will never exit historical mode, so we need to prevent repeated requests from the draw() loop. - // So we buffer using the behavior forwardPaginationRetryInterval. - var forwardFetchDoARetry; - var forwardPaginationRetryIntervalMS = - 1000 * (myBehavior.forwardPaginationRetryInterval || 5); - - var seriesNeedsBackFill = false, - seriesNeedsFrontFill = false; // see if series need loading - if (chart.dataSet.length) { - for (var key in chart.series) { - var series = chart.series[key]; - if (series.loading) continue; // exclude this series - if (series.parameters.loadData === false) continue; // exclude series loaded thru masterData - forwardFetchDoARetry = - !series.mostRecentForwardAttempt || - series.mostRecentForwardAttempt.getTime() + - forwardPaginationRetryIntervalMS < - Date.now(); - - if (series.moreAvailable !== false && needsBackFill(series)) - seriesNeedsBackFill = true; - if (forwardFetchDoARetry && !series.upToDate && needsFrontFill(series)) - seriesNeedsFrontFill = true; - } - } - - forwardFetchDoARetry = - !chart.mostRecentForwardAttempt || - chart.mostRecentForwardAttempt.getTime() + - forwardPaginationRetryIntervalMS < - Date.now(); - // Now we determine which type of pagination we need - var mainPastFetch = - (needsBackFill(chart) || forceLoadMore) && chart.moreAvailable !== false; - var mainForwardFetch = - (needsFrontFill(chart) || forceLoadMore) && - !chart.upToDate && - forwardFetchDoARetry; - var isPastPagination = mainPastFetch || seriesNeedsBackFill; - var isForwardPagination = - stx.isHistoricalModeSet && - !isPastPagination && - (mainForwardFetch || seriesNeedsFrontFill); - - var interval = stx.layout.interval; - var timeUnit = stx.layout.timeUnit; - function closure(self, params) { - if (myBehavior.prefetchAction) myBehavior.prefetchAction("checkLoadMore"); - return function (dataCallback) { - var stx = self.stx, - chart = params.chart; - if ( - params.symbol == chart.symbol && - interval == stx.layout.interval && - timeUnit == stx.layout.timeUnit - ) { - // Make sure user hasn't changed symbol while we were waiting on a response - if (!params.loadMore) { - params.chart.loadingMore = false; - } - if (!dataCallback.error) { - if (!dataCallback.quotes) dataCallback.quotes = []; - var quotes = dataCallback.quotes, - masterData = chart.masterData; - quotes = self.cleanup( - stx, - null, - quotes, - CIQ.QuoteFeed.PAGINATION, - params - ); - if (quotes.length && chart.masterData && chart.masterData.length) { - // remove possible dup with master data's first record - if (params.future) { - // remove possible dup with master data's first record - var firstQuote = quotes[0]; - if ( - firstQuote.DT && - firstQuote.DT == - chart.masterData[chart.masterData.length - 1].DT - ) - masterData.pop(); - } else { - // remove possible dup with master data's last record - var lastQuote = quotes[quotes.length - 1]; - if (lastQuote.DT && +lastQuote.DT == +chart.masterData[0].DT) - quotes.pop(); - } - } - - if (!params.future) { - // set moreAvailable before we call draw or we can create an infinite loop if the feed servers runs out of data in the middle of a draw - // if dataCallback.moreAvailable is set to either true or false, set chart.moreAvailable to that value - // if dataCallback.moreAvailable is not set at all (null or undefined), then set chart.moreAvailable to dataCallback.quotes.length!==0 - if (dataCallback.moreAvailable) chart.moreAvailable = true; - else if (dataCallback.moreAvailable === false || !quotes.length) - chart.moreAvailable = false; - // Can't be more available if we got nothing back - else chart.moreAvailable = true; - } else { - if (dataCallback.upToDate) chart.upToDate = true; - else if (dataCallback.upToDate === false || quotes.length > 1) - chart.upToDate = false; // Can't be up to date if we got something back - if (stx.isHistoricalModeSet && quotes.length < 2) - chart.mostRecentForwardAttempt = new Date(); // no quotes for future query, so timestamp this query - } - self.tickMultiplier = quotes.length ? 2 : self.tickMultiplier * 2; - - // Better to set this early, in case a draw() is called from one of the functions below and checkLoadMore is retriggered. We need to know where we left off! - var sdate = quotes[0] ? quotes[0].DT : params.startDate, - edate = quotes[0] ? quotes[quotes.length - 1].DT : params.endDate; - if (!chart.endPoints.begin || chart.endPoints.begin > sdate) - chart.endPoints.begin = sdate; - if (!chart.endPoints.end || chart.endPoints.end < edate) - chart.endPoints.end = edate; - - chart.loadingMore = false; // this has to be set before draw() so we may call another pagination from it - - if (params.loadMoreReplace) { - stx.setMasterData(quotes, chart, { noCleanupDates: true }); - } else if (params.future) { - stx.updateChartData(quotes, chart, { - noCreateDataSet: true, - noCleanupDates: true - }); - } else { - CIQ.addMemberToMasterdata({ - stx: stx, - chart: chart, - data: quotes, - fields: ["*"], - noCleanupDates: true - }); - } - var dsParams; - if (params.future) { - dsParams = { - appending: true, - appendToDate: quotes[0] && quotes[0].DT - }; - } - stx.createDataSet(undefined, undefined, dsParams); - - if (!nodraw) stx.draw(); - if (myBehavior.callback) { - myBehavior.callback(params); - } - self.loadDependents(params, cb, CIQ.QuoteFeed.PAGINATION); - } else { - self.quoteFeed.announceError(params.originalState, dataCallback); - params.chart.loadingMore = false; - if (cb) cb(dataCallback.error); - } - } else { - //console.log("orphaned loadMore",params); - return; - } - }; - } - var fetching = false; - var findHeadOfData = - myBehavior.findHeadOfData || (chart.masterData && chart.masterData.length); - if (!myBehavior.noLoadMore && findHeadOfData) { - if ( - isForwardPagination || - !stx.maxDataSetSize || - chart.dataSet.length < stx.maxDataSetSize - ) { - if (isPastPagination || isForwardPagination) { - chart.initialScroll = chart.scroll; - chart.loadingMore = true; - params = this.makeParams(chart.symbol, chart.symbolObject, chart); - params.pagination = true; - params.future = isForwardPagination; - if (chart.masterData && chart.masterData.length) { - if (isForwardPagination) params.startDate = chart.endPoints.end; - else params.endDate = chart.endPoints.begin; - var firstLast; - // fallback on masterData endpoints - if (isForwardPagination && !params.startDate) { - firstLast = stx.getFirstLastDataRecord( - chart.masterData, - "DT", - true - ); - if (firstLast) params.startDate = firstLast.DT; - } else if (isPastPagination && !params.endDate) { - firstLast = stx.getFirstLastDataRecord(chart.masterData, "DT"); - if (firstLast) params.endDate = firstLast.DT; - } - } else { - params.endDate = new Date(); - } - params.originalState = CIQ.shallowClone(params); - params.nodraw = nodraw; - if ( - (!mainPastFetch && seriesNeedsBackFill) || - (!mainForwardFetch && seriesNeedsFrontFill) - ) { - this.loadingMore = true; - this.loadDependents(params, finish, CIQ.QuoteFeed.PAGINATION); - if (cb) cb(null); - return; - } - if (stx.fetchMaximumBars[stx.layout.aggregationType]) { - params.fetchMaximumBars = true; - if ( - !stx.maxMasterDataSize || - myBehavior.maximumTicks < stx.maxMasterDataSize - ) - params.ticks = myBehavior.maximumTicks; - else params.ticks = stx.maxMasterDataSize; - } - var closureCB = closure(this, params); - if (stx.isEquationChart(params.symbol)) { - //equation chart - CIQ.fetchEquationChart(params, closureCB); - } else { - if (isForwardPagination) params.appending = true; - var qf = driver.getQuoteFeed(params); - if (qf) - CIQ.ChartEngine.Driver.fetchData( - CIQ.QuoteFeed.PAGINATION, - qf.engine, - params, - closureCB - ); - } - fetching = true; - } - } - } - if (!fetching && cb) cb(null); -}; - -/** - * Extends the main series further into the past. Used internally by studies that need - * additional historical data. - * - * @param {object} parameters Contains function call parameters. - * @param {object} parameters.from A date object that specifies the date from which historical - * data is fetched. - * @param {function} cb The callback function called with the error (if any) returned by the - * quote feed. - * - * @memberOf CIQ.ChartEngine.Driver - * @private - * @since 8.0.0 - */ -CIQ.ChartEngine.Driver.prototype.extendHistoricalData = function ( - { from }, - cb = () => {} -) { - const { stx } = this; - const { chart, layout } = stx; - const { masterData, dataSet } = chart; - const { interval, timeUnit } = layout; - const params = this.makeParams(chart.symbol, chart.symbolObject, chart); - const quotefeed = this.getQuoteFeed(params); - - if ( - chart.loadingMore || - this.loadingNewChart || - stx.currentlyImporting || - !masterData.length || - !quotefeed || - (stx.maxDataSetSize && dataSet.length > stx.maxDataSetSize) - ) { - return cb(null); - } - - chart.loadingMore = true; - params.originalState = Object.assign({}, params); - params.startDate = from; - params.endDate = masterData[0].DT; - - CIQ.ChartEngine.Driver.fetchData( - CIQ.QuoteFeed.PAGINATION, - quotefeed.engine, - params, - closure(this, params) - ); - - function closure(driver, params) { - return function ({ quotes, moreAvailable, error }) { - if ( - params.symbol !== chart.symbol || - interval !== layout.interval || - timeUnit !== layout.timeUnit - ) { - return; // Make sure user hasn't changed symbol while we were waiting on a response - } - - chart.loadingMore = false; - - if (error) return cb(error); - - quotes = driver.cleanup( - stx, - null, - quotes, - CIQ.QuoteFeed.PAGINATION, - params - ); - - if (typeof moreAvailable === "boolean") { - chart.moreAvailable = moreAvailable; - } else { - chart.moreAvailable = !!quotes.length; - } - - chart.endPoints.begin = quotes[0].DT; - - CIQ.addMemberToMasterdata({ - stx: stx, - chart: chart, - data: quotes, - fields: ["*"], - noCleanupDates: true - }); - - stx.createDataSet(); - stx.draw(); - }; - } -}; - -/** - * Returns how many bars should be fetched, based on an algorithm estimating number of bars to fill the screen. - * If we're rolling our own months or weeks from daily ticks it will return the number of daily ticks to fetch. - * - * @param {object} params Parameters - * @param {object} params.stx The chart object - * @return {number} Number of bars to fetch - * @memberOf CIQ.ChartEngine.Driver - * @private - */ -CIQ.ChartEngine.Driver.prototype.barsToFetch = function (params) { - if (!CIQ.isValidNumber(this.tickMultiplier)) this.tickMultiplier = 2; // used to determine params.ticks - var interval = this.stx.layout.interval; - var p = params.stx.layout.periodicity; - // Rough calculation, this will account for 24x7 securities - // If we're rolling our own months or weeks then adjust to daily bars - if ((interval == "month" || interval == "week") && !this.stx.dontRoll) { - p *= interval == "week" ? 7 : 30; - } - var bars = params.stx.chart.maxTicks * p; - return bars * this.tickMultiplier; -}; - -/** - * Calculates the suggestedStartDate for a query to a quoteFeed. Will either do a quick estimation if fetchMaximimBars is true for effiency or use a market iterator to find the exact start date. - * This should only be called after the correct ticks have been determined. - * @param {object} params - * @param {object} iterator - * @param {number} ticks - * @return {Date} suggestedStartDate - * @memberof CIQ.ChartEngine.Driver - * @private - * @since 5.1.1 - */ -CIQ.ChartEngine.Driver.determineStartDate = function (params, iterator, ticks) { - return this.determineStartOrEndDate(params, iterator, ticks, true); -}; - -/** - * Calculates either the suggestedStartDate or suggestedEndDate for a query to a quoteFeed. Will either do a quick estimation if fetchMaximimBars is true for effiency or use a market iterator to find the exact end date. - * When passing in a truthy boolean will calculate suggestedStartDate. - * This should only be called after the correct ticks have been determined. - * @param {object} params Params object used by the QuoteDriver in fetching data - * @param {object} iterator Market iterator to used to advance and find a date - * @param {number} ticks Ticks to fetch - * @param {boolean} direction Direction to check date from - * @return {Date} determinedDate (or present day) - * @memberof CIQ.ChartEngine.Driver - * @private - * @since 6.0.0 - */ -CIQ.ChartEngine.Driver.determineStartOrEndDate = function ( - params, - iterator, - ticks, - isStart -) { - var determinedDate; - if (isStart || params.fetchMaximumBars) { - determinedDate = params.startDate || iterator.previous(ticks); - } else { - determinedDate = params.future ? iterator.next(ticks) : new Date(); - } - return determinedDate; -}; - -CIQ.ChartEngine.Driver.prototype.makeParams = function ( - symbol, - symbolObject, - chart -) { - var stx = this.stx; - var interval = stx.layout.interval; - var ticks = this.barsToFetch({ stx: stx }); - // If we're rolling our own months or weeks then we should ask for days from the quote feed - if ((interval == "month" || interval == "week") && !stx.dontRoll) { - interval = "day"; - } - var qf = this.getQuoteFeed({ - interval: interval, - symbol: symbol, - symbolObject: symbolObject - }); - var behavior = qf && qf.behavior; - var params = CIQ.shallowClone(behavior) || {}; - params.behavior = behavior; - - var extended = false, - sessions = []; - if (chart.market && chart.market.getSessionNames) - sessions = chart.market.getSessionNames(); - if (stx.extendedHours) { - if (stx.extendedHours.filter) { - extended = true; - } else { - extended = stx.layout.extended; - // filter out unwanted sessions - sessions = sessions.filter(function (el) { - return el.enabled || stx.layout.marketSessions[el.name]; - }); - } - } else { - sessions = sessions.filter(function (el) { - return el.enabled; - }); - } - for (var sess = 0; sess < sessions.length; sess++) { - sessions[sess] = sessions[sess].name; // remove "enabled" bit - } - - CIQ.extend( - params, - { - stx: stx, - symbol: symbol, - symbolObject: symbolObject, - chart: chart, - interval: interval, - extended: extended, - period: 1, - ticks: ticks, - additionalSessions: sessions, - quoteDriverID: this.id - }, - true - ); - - if (!params.symbolObject) params.symbolObject = { symbol: symbol }; - - if (!isNaN(params.interval)) { - // normalize numeric intervals into "minute", "second" or "millisecond" form as required by fetch() - params.period = parseInt(params.interval, 10); // in case it was a string, which is allowed in setPeriodicity. - params.interval = stx.layout.timeUnit; - if (!params.interval) params.interval = "minute"; - } - return params; -}; - -CIQ.ChartEngine.Driver.prototype.newChart = function (params, cb) { - var stx = this.stx; - var symbol = params.symbol; - var interval = stx.layout.interval; - var timeUnit = stx.layout.timeUnit; - var chart = params.chart; - chart.moreAvailable = null; - chart.upToDate = null; - chart.loadingMore = false; - chart.attribution = null; - var qparams = this.makeParams(symbol, params.symbolObject, chart); - CIQ.extend(qparams, params, true); - var myQuoteFeed = this.getQuoteFeed(qparams); - var myBehavior = qparams.behavior; - // Some aggregation types potentially require a lot of data. We set the flag "fetchMaximumBars" - // but also take a guess and say 20,000 bars should cover most situations - if ( - stx.fetchMaximumBars[stx.layout.aggregationType] || - params.fetchMaximumBars - ) { - if ( - !stx.maxMasterDataSize || - myBehavior.maximumTicks < stx.maxMasterDataSize - ) - qparams.ticks = myBehavior.maximumTicks; - else qparams.ticks = stx.maxMasterDataSize; - qparams.fetchMaximumBars = true; - } - - function closure(self, qparams) { - if (myBehavior.prefetchAction) myBehavior.prefetchAction("newChart"); - return function (dataCallback) { - var chart = qparams.chart, - quotes = dataCallback.quotes, - success = false; - if ( - symbol == chart.symbol && - interval == stx.layout.interval && - timeUnit == stx.layout.timeUnit - ) { - // Make sure user hasn't changed symbol while we were waiting on a response - self.loadingNewChart = false; // this has to be set before home() so we may call a pagination from it - if (!dataCallback.error) { - quotes = self.cleanup( - stx, - null, - quotes, - CIQ.QuoteFeed.INITIAL, - qparams - ); - stx.setMasterData(quotes, chart, { noCleanupDates: true }); - chart.endPoints = {}; - - chart.endPoints.begin = quotes[0] ? quotes[0].DT : qparams.startDate; - chart.endPoints.end = quotes[0] - ? quotes[quotes.length - 1].DT - : qparams.endDate; - - // Note, quotes.length==0 will not set moreAvailable to false, just in case the stock is thinly traded - // We'll rely on checkLoadMore to make the definitive decision - if (!quotes) { - chart.moreAvailable = false; - chart.upToDate = true; - } else { - chart.moreAvailable = - dataCallback.moreAvailable === false ? false : true; - chart.upToDate = dataCallback.upToDate; - } - - chart.attribution = dataCallback.attribution; - if (params.initializeChart) stx.initializeChart(); - stx.createDataSet(); - success = true; - } else { - myQuoteFeed.engine.announceError(qparams.originalState, dataCallback); - } - } else { - //console.log("orphaned request", qparams); - if (cb) cb("orphaned"); - return; - } - - // new data means that all series could potentially have historical data. So reset them all. - for (var key in chart.series) { - chart.series[key].endPoints = {}; - chart.series[key].moreAvailable = null; - chart.series[key].upToDate = null; - } - - // We've now responded to the loadChart() callback. Please note that dependents are now being loaded in parallel! - var masterData = chart.masterData; - if (masterData && masterData.length) { - qparams.startDate = masterData[0].DT; - qparams.endDate = masterData[masterData.length - 1].DT; - } - if (myBehavior.callback) { - myBehavior.callback(qparams); - } - self.loadDependents( - qparams, - function () { - if (success && !qparams.nodraw) self.stx.home(); // by default the white space is maintained now, so no need to include the {maintainWhitespace:true} parameter - if (cb) cb(dataCallback.error); - self.stx.dispatch("newChart", { - stx: self.stx, - symbol: self.stx.chart.symbol, - symbolObject: self.stx.chart.symbolObject, - moreAvailable: self.stx.chart.moreAvailable, - upToDate: self.stx.chart.upToDate, - quoteDriver: self - }); - self.resetRefreshInterval(myBehavior.refreshInterval, myBehavior); - }, - CIQ.QuoteFeed.INITIAL - ); - }; - } - this.loadingNewChart = true; - this.updatingChart = false; - - qparams.originalState = CIQ.shallowClone(qparams); - var closureCB = closure(this, qparams); - if (this.stx.isEquationChart(qparams.symbol)) { - //equation chart - CIQ.fetchEquationChart(qparams, closureCB); - } else if (myQuoteFeed) { - CIQ.ChartEngine.Driver.fetchData( - CIQ.QuoteFeed.INITIAL, - myQuoteFeed.engine, - qparams, - closureCB - ); - } -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////////////////////// -// Below code supports new quotefeed architecture -/////////////////////////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////////////////////// - -//Quotefeed constants defining fetchData's context parameter -CIQ.QuoteFeed.INITIAL = 1; -CIQ.QuoteFeed.UPDATE = 2; -CIQ.QuoteFeed.PAGINATION = 3; -CIQ.QuoteFeed.SERIES = 4; - -// ALL quotefeed-fetch calls (old and new versions) go through this function -CIQ.ChartEngine.Driver.fetchData = function (context, quoteFeed, params, cb) { - if (!params.symbol) return cb({ quotes: [] }); - if (quoteFeed.v2QuoteFeed) { - // if new version of quotefeed - if (typeof quoteFeed.subscribe !== "function") { - // if no subscribe function defined then this is a typical quotefeed - CIQ.ChartEngine.Driver.fetchDataInContext(context, quoteFeed, params, cb); - } else { - // else this is a "subscription" quotefeed - CIQ.ChartEngine.Driver.fetchDataInContext( - context, - quoteFeed, - params, - function (results) { - if (!results.error) { - this.checkSubscriptions(params.stx); - } - cb(results); - }.bind(quoteFeed) - ); - } - } else { - // old version of quotefeed - params.stx.convertToDataZone(params.startDate); - params.stx.convertToDataZone(params.endDate); - quoteFeed.fetch(params, cb); - } -}; - -// if not a "subscription" quotefeed, then this function is always called for new quotefeed -- here the user's quotefeed is invoked; -// functions not defined in quotefeed are skipped over -CIQ.ChartEngine.Driver.fetchDataInContext = function ( - context, - quoteFeed, - params, - cb -) { - var iterator_parms, iterator, suggestedStartDate, suggestedEndDate; - var stx = params.stx; - if (!stx.chart.market.newIterator) { - console.error( - "quoteFeed feature requires first activating market feature." - ); - return; - } - // When dealing with a series, we need to look at the original params in order to figure out - // what type of request we really need to make - if (context === CIQ.QuoteFeed.SERIES) { - params.series = true; - context = CIQ.QuoteFeed.INITIAL; - if ((params.endDate && !params.startDate) || params.future) - context = CIQ.QuoteFeed.PAGINATION; - else if (params.startDate && !params.endDate) - context = CIQ.QuoteFeed.UPDATE; - } - var ticks = Math.min(params.ticks, params.maximumTicks); - if (quoteFeed.maxTicks) ticks = Math.min(ticks, quoteFeed.maxTicks); - var qfSymbol = params.symbolObject.masterSymbol || params.symbol; - switch (context) { - case CIQ.QuoteFeed.UPDATE: - if (stx.isHistoricalModeSet) { - stx.quoteDriver.updatingChart = false; - return; - } - - var startDate; - if (params.startDate) { - startDate = params.startDate; - } else { - startDate = new Date(); // occurs if initial fetch returned no data - startDate.setHours(0, 0, 0, 0); - } - if (typeof quoteFeed.fetchUpdateData === "function") { - quoteFeed.fetchUpdateData( - qfSymbol, - stx.convertToDataZone(startDate), - params, - cb - ); - } - - break; - case CIQ.QuoteFeed.INITIAL: - //Now need to calculate suggested dates - suggestedEndDate = params.endDate || new Date(); - iterator_parms = { - begin: suggestedEndDate, - interval: params.interval, - periodicity: - params.interval == "tick" - ? stx.chart.xAxis.futureTicksInterval - : params.period, - outZone: stx.dataZone - }; - iterator = stx.chart.market.newIterator(iterator_parms); - suggestedStartDate = CIQ.ChartEngine.Driver.determineStartDate( - params, - iterator, - ticks - ); - if (params.endDate) suggestedEndDate = params.endDate; - if (typeof quoteFeed.fetchInitialData === "function") { - quoteFeed.fetchInitialData( - qfSymbol, - suggestedStartDate, - stx.convertToDataZone(suggestedEndDate), - params, - cb - ); - } - break; - case CIQ.QuoteFeed.PAGINATION: - iterator_parms = { - begin: params.endDate || params.startDate, - interval: params.interval, - periodicity: - params.interval == "tick" - ? stx.chart.xAxis.futureTicksInterval - : params.period, - outZone: stx.dataZone - }; - iterator = stx.chart.market.newIterator(iterator_parms); - var suggestedDate = CIQ.ChartEngine.Driver.determineStartOrEndDate( - params, - iterator, - ticks, - !params.future - ); - suggestedStartDate = params.startDate || suggestedDate; - suggestedEndDate = params.endDate || suggestedDate; - if (!params.startDate) params.stx.convertToDataZone(suggestedEndDate); - else params.stx.convertToDataZone(suggestedStartDate); - - if (typeof quoteFeed.fetchPaginationData === "function") { - if ( - stx.maxMasterDataSize && - stx.maxMasterDataSize <= stx.masterData.length - ) - return; - quoteFeed.fetchPaginationData( - qfSymbol, - suggestedStartDate, - suggestedEndDate, - params, - function (dataCallback) { - if (suggestedEndDate >= Date.now()) stx.isHistoricalModeSet = false; // exit historical mode if we request (future) data up to present or beyond - if (cb) cb(dataCallback); - } - ); - } - break; - default: - console.error("Illegal fetchData constant"); - } -}; - -}; - - -let __js_standard_series_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -/** - * INJECTABLE - * - * Adds a series of data to the chart. - * - * A series can be rendered (for instance like a comparison chart) or it can be hidden (for instance to drive a study). - * - * If you have a quotefeed attached to your chart, then just pass the symbol as the first parameter. - * There is no need to pass data since the chart will automatically fetch it from your quotefeed. - * If however you are using the "push" method to feed data to your chart then you must provide the data manually by passing it as a parameter. - * - * Here's how you would add a hidden series for symbol "IBM" when using a quotefeed: - * ``` - * stxx.addSeries("IBM"); - * ``` - * - * That series will now be available for use by studies, for example, but it will not display on the chart since no rendering details have been provided. - * - * If you wish to *display* your series, you must specify how you wish the series to be rendered. - * At a minimum, you will need to indicate what color should be used to display the series. Like so: - * ``` - * stxx.addSeries("IBM", {color:"blue"}); - * ``` - * - * Once a series is added, it will be tracked in the {@link CIQ.ChartEngine.Chart#series} object. - * - * To remove a series call {@link CIQ.ChartEngine#removeSeries} - * - * To remove all series from a chart, simply iterate through the active series object and delete them one at a time: - * ``` - * for(var s in stxx.chart.series){ - * var series=stxx.chart.series[s]; - * stxx.removeSeries(series); - * } - * ``` - * - * Example 1 - manually add data to a chart and a series - * - * The above example adds a series as an overlay, but a more common use case is to display series as comparisons. - * Comparisons are special because they change the chart from a price chart to a percentage chart. - * All series on the chart then begin at "zero", on the left side of the chart. - * Set isComparison=true when adding a series to make it a comparison chart. As long as a comparison series is on a chart, the chart will display its y-axis in percent scale - * provided {@link CIQ.ChartEngine.Chart#forcePercentComparison} is true. - * ``` - * stxx.addSeries("IBM", {color:"blue", isComparison:true}); - * ``` - * - * **Complex Visualizations** - * - * Example 2 - use a custom renderer to display a series - * - * Behind the scenes, series are displayed by [renderers]{@link CIQ.Renderer}. - * Renderers can plot lines, mountains, bars, candles, and other types of visualizations. -+* When adding a series, you can specify which renderer to use and set parameters to control your visualization. - * For instance, this will display a series as a bar chart on its own left axis: - * ``` - * stxx.addSeries( - * "SNE", - * { - * display:"Sony", - * renderer:"Bars", - * name:"test", - * yAxis:{ - * position:"left", - * textStyle:"#FFBE00" - * } - * } - * ); - * ``` - * Which is the same as explicitly declaring a renderer and then attaching it to the series: - * ``` - * stxx.addSeries( - * "SNE", - * { - * display:"Sony" - * }, - * function(){ - * // create the axis - * var axis=new CIQ.ChartEngine.YAxis({position:"left", textStyle:"#FFBE00"}); - * - * //create the renderer and attach - * var renderer=stxx.setSeriesRenderer( - * new CIQ.Renderer.Bars({params:{name:"test", yAxis:axis}}) - * ); - * renderer.attachSeries("SNE").ready(); - * } - * ); - * ``` - * The above 2 calls do exactly the same thing, just using different syntax. - * - * All parameters specified in addSeries will be passed on to the selected renderer. As such, every parameter available for the selected renderer can be used here to further customize the series.
- * For example, to add a step line, you would select a [Lines]{@link CIQ.Renderer.Lines} renderer, and then set its `step` attribute, right trough the addSeries API call. - * ``` - * stxx.addSeries( - * "SNE", - * { - * renderer:"Lines", - * step:true, - * } - * ); - * ``` - * - * **Advanced Visualizations** - * - * Some renderers are capable of rendering *multiple series*. - * For instance, the [Histogram]{@link CIQ.Renderer.Histogram} can display series stacked on top of one another. - * Use `[setSeriesRenderer()]{@link CIQ.ChartEngine#setSeriesRenderer}` in this case. - * Here is how we would create a stacked histogram from several series: - * ``` - * var myRenderer=stxx.setSeriesRenderer(new CIQ.Renderer.Histogram({params:{subtype:"stacked"}})); - * - * stxx.addSeries("^NIOALL", {}, - * function() {myRenderer.attachSeries("^NIOALL","#6B9CF7").ready();} - * ); - * stxx.addSeries("^NIOAFN", {}, - * function() {myRenderer.attachSeries("^NIOAFN","#95B7F6").ready();} - * ); - * stxx.addSeries("^NIOAMD", {}, - * function() {myRenderer.attachSeries("^NIOAMD","#B9D0F5").ready();} - * ); - * ``` - * - * Example 3 - advanced stacked histogram renderer - * - * **Using a Symbol Object** - * - * The above examples all assumed your chart uses "tickers" (stock symbols). - * We refer to complex (compound) symbols as "Symbol Objects" (see {@link CIQ.ChartEngine#loadChart}). - * Here's how to set a series with a symbol object: - * ``` - * stxx.addSeries(null, {color:"blue", symbolObject:yourSymbolObject}); - * ``` - * - * **Setting a separate YAxis** - * - * By default, series are displayed without a y-axis. - * They are either "overlayed" on the main chart, or if they are comparisons then they share the standard y-axis. - * But a series can also take an optional y-axis which can be displayed on the left, or the right side of the chart. - * To do this, you must specify parameters for a [YAxis]{@link CIQ.ChartEngine.YAxis} object and pass to addSeries: - * ``` - * stxx.addSeries("IBM", {color:"blue", yAxis:{ position:"left" }}); - * ``` - * - * **Understanding the relationship between [setSeriesRenderer()]{@link CIQ.ChartEngine#setSeriesRenderer} and [importLayout]{@link CIQ.ChartEngine#importLayout}** - * - * It is important to know that a renderer explicitly created using [setSeriesRenderer()]{@link CIQ.ChartEngine#setSeriesRenderer} will **not** be stored in the layout serialization. - * If your implementation will require the complete restoration of a chart layout, you must instead use the syntax that includes all of the renderer parameters as part of this addSeries call. - * - * - * @param {string} [id] The name of the series. If not passed then a unique ID will be assigned. (parameters.symbol and parameters.symbolObject will default to using id if they are not set explicitly *and* id is supplied.) - * @param {object} [parameters] Parameters to describe the series. Any valid [attachSeries parameters]{@link CIQ.Renderer#attachSeries} and [renderer parameters]{@link CIQ.Renderer} will be passed to attached renderers. - * @param {string} [parameters.renderer={@link CIQ.Renderer.Lines}] Rendering Set to the desired [renderer]{@link CIQ.Renderer} for the series. - * - If not set, defaults to [Lines]{@link CIQ.Renderer.Lines} when `color` is set. - * - Not needed for hidden series. - * @param {string} [parameters.name] Rendering Set to specify renderer's name. Otherwise id will be used. - * @param {string} [parameters.display=id/symbol] Rendering Set to the text to display on the legend. If not set, the id of the series will be used (usually symbol). If id was not provided, will default to symbol. - * @param {string} [parameters.symbol=id] Data Loading The symbol to fetch in string format. This will be sent into the fetch() function, if no data is provided. If no symbol is provided, series will use the `id` as the symbol. If both `symbol` and `symbolObject` are set, `symbolObject` will be used. - * @param {object} [parameters.symbolObject=id] Data Loading The symbol to fetch in object format. This will be sent into the fetch() function, if no data is provided. If no symbolObject is provided, series will use the `id` as the symbol. You can send anything you want in the symbol object, but you must always include at least a 'symbol' element. If both `symbol` and `symbolObject` are set, `symbolObject` will be used. - * @param {string} [parameters.field=Close/Value] Data Loading Specify an alternative field to draw data from (other than the Close/Value). Must be present in your pushed data objects or returned from the quoteFeed. - * @param {boolean} [parameters.isComparison=fasle] Rendering If set to true, shareYAxis is automatically set to true to display relative values instead of the primary symbol's price labels. {@link CIQ.ChartEngine#setComparison} is also called and set to `true`. This is only applicable when using the primary Y axis, and should only be used with internal addSeries renderers. - * @param {boolean} [parameters.shareYAxis=false] Rendering - * - Set to `true` so that the series shares the primary Y-axis and renders along actual values and print its corresponding current price label on the y axis. - * - When set to `false`, the series will not be attached to a y axis. Instead it is superimposed on the chart; taking over its entire height, and maintaining the relative shape of the line. No current price will be displayed. Superimposing the ‘shape’ of one series over a primary chart, is useful when rendering multiple series that do not share a common value range. - * - This setting will automatically override to true if 'isComparison' is set. - * - This setting is only applicable when using the primary Y axis and has no effect when using a renderer that has its own axis. - * @param {number} [parameters.marginTop=0] Rendering Percentage (if less than 1) or pixels (if greater than 1) from top of panel to set the top margin for the series.
**Note:** this parameter is to be used on **subsequent** series rendered on the same axis. To set margins for the first series, {@link CIQ.ChartEngine.YAxis#initialMarginTop} needs to be used.
**Note:** not applicable if shareYAxis is set. - * @param {number} [parameters.marginBottom=0] Rendering Percentage (if less than 1) or pixels (if greater than 1) from the bottom of panel to set the bottom margin for the series.
**Note:** this parameter is to be used on **subsequent** series rendered on the same axis. To set margins for the first series, {@link CIQ.ChartEngine.YAxis#initialMarginBottom} needs to be used.
**Note:** not applicable if shareYAxis is set. - * @param {number} [parameters.width=1] Rendering Width of line in pixels - * @param {number} [parameters.minimum] Rendering Minimum value for the series. Overrides CIQ.minMax result. - * @param {number} [parameters.maximum] Rendering Maximum value for the series. Overrides CIQ.minMax result. - * @param {string} [parameters.color] Rendering Color to draw line. Will cause the line to immediately render an overlay. Only applicable for default or single colors renderers. See {@link CIQ.Renderer#attachSeries} for additional color options. - * @param {string} [parameters.baseColor=parameters.color] Rendering Color for the base of a mountain series. Defaults to `parameters.color`. - * @param {array|string} [parameters.pattern='solid'] Rendering Pattern to draw line, array elements are pixels on and off, or a string e.g. "solid", "dotted", "dashed" - * @param {boolean|string} [parameters.fillGaps] Data Loading If {@link CIQ.ChartEngine#cleanupGaps} is enabled to clean gaps (not 'false'), you can use this parameter to override the global setting for this series. - * - If `fillGaps` not present - * - No gaps will be filled for the series. - * - If `fillGaps` is set to 'false' - * - No gaps will be filled for the series. - * - If `fillGaps` is set to 'true', - * - Gap filling will match {@link CIQ.ChartEngine#cleanupGaps}. - * - If `fillGaps` is set to 'carry' or 'gap' - * - Will use that filling method even if `cleanupGaps` is set differently. - * @param {object|string} [parameters.gapDisplayStyle=true] Rendering Defines how (or if) to **render** (style) connecting lines where there are gaps in the data (missing data points), or isolated datapoints. - * - Applicable for line-like renderers only (lines, mountains, baselines, etc). - * - Default: - * - `true` for standard series. - * - `false` for comparisons. - * - Set to `true` to use the color and pattern defined by {@link CIQ.ChartEngine#setGapLines} for the chart. - * - Set to `false` to always show gaps. - * - Set to an actual color string or custom color-pattern object as formatted by {@link CIQ.ChartEngine#setGapLines} to define more custom properties. - * - 'Dots' indicating isolated items will be shown unless a `transparent` color/style is specified. - * - If not set, and the series is a comparison, the gaps will always be rendered transparent. - * @param {string} [parameters.fillStyle] Rendering Fill style for mountain chart (if selected). For semi-opaque use rgba(R,G,B,.1). If not provided a gradient is created with color and baseColor. - * @param {boolean} [parameters.permanent=false] Rendering Set to `true` to activate. Makes series unremoveable by a user **when attached to the default renderer**. If explicitly linked to a renderer, see {@link CIQ.Renderer#attachSeries} for details on how to prevent an attached series from being removed by a user. - * @param {object} [parameters.data] Data Loading Data source for the series. - * If this field is omitted, the library will connect to the QuoteFeed (if available) to fetch initial data ( unless `parameters.loadData` is set to `false`), and manage pagination and updates. - * If data is sent in this field, it will be loaded into the masterData, but series will **not** be managed by the QuoteFeed (if available) for pagination or updates. - * Items in this array *must* be ordered from earliest to latest date.
- * Accepted formats: - *


**Full OHLC:**
- * An array of properly formatted OHLC quote object(s). [See OHLC Data Format]{@tutorial InputDataFormat}.
- *
----

**Price Only:**
- * An array of objects, each one with the followng elements:
- * @param {date} [parameters.data.DT] JavaScript date object or epoch representing data point (overrides Date parameter if present) - * @param {string} [parameters.data.Date] string date representing data point ( only used if DT parameter is not present) - * @param {number} parameters.data.Value value of the data point ( As an alternative, you can send `parameters.data.Close` since your quote feed may already be returning the data using this element name) - * @param {string|boolean} [parameters.panel] Rendering The panel name on which the series should display. If the panel doesn't exist, one will be created. If `true` is passed, a new panel will also be created. - * @param {string} [parameters.action='add-series'] Rendering Overrides what action is sent in symbolChange events. Set to null to prevent a symbolChange event. - * @param {boolean} [parameters.loadData=true] Data Loading Include and set to false if you know the initial data is already in the masterData array or will be loaded by another method. The series will be added but no data requested. Note that if you remove this series, the data points linked to it will also be removed which may create issues if required by the chart. If that is the case, you will need to manually remove from the renderer linked to it instead of the underlying series itself. - * @param {boolean} [parameters.extendToEndOfDataSet] Rendering Set to true to plot any gap at the front of the chart. Automatically done for step charts (set to false to disable) or if parameters.gapDisplayStyle are set (see {@link CIQ.ChartEngine#addSeries}) - * @param {boolean} [parameters.displayFloatingLabel=false] Rendering Set to false to disable the display of a Y-axis floating label for this series. - * @param {boolean|object} [parameters.baseline] Rendering If a boolean value, indicates whether the series renderer draws a baseline. If an object, must be the equivalent of {@link CIQ.ChartEngine.Chart#baseline}. - * @param {function} [cb] Callback function to be executed once the fetch returns data from the quoteFeed. It will be called with an error message if the fetch failed: `cb(err);`. Only applicable if no data is provided. - * @return {object} The series object. - * - * @memberof CIQ.ChartEngine - * @since - * - 04-2015 If `isComparison` is true shareYAxis is automatically set to true and setComparison(true) called. createDataSet() and draw() are automatically called to immediately render the series. - * - 15-07-01 If `color` is defined and chartStyle is not set then it is automatically set to "line". - * - 15-07-01 Ability to use setSeriesRenderer(). - * - 15-07-01 Ability to automatically initialize using the quoteFeed. - * - 15-07-01 `parameters.quoteFeedCallbackRefresh` no longer used. Instead if `parameters.data.useDefaultQuoteFeed` is set to `true` the series will be initialized and refreshed using the default quote feed. (Original documentation: `{boolean} [parameters.quoteFeedCallbackRefresh]` Set to true if you want the series to use the attached quote feed (if any) to stay in sync with the main symbol as new data is fetched (only available in Advanced package).) - * - 2015-11-1 `parameters.symbolObject` is now available. - * - 05-2016-10 `parameters.forceData` is now available. - * - 09-2016-19 `parameters.data.DT` can also take an epoch number. - * - 09-2016-19 `parameters.data.useDefaultQuoteFeed` no longer used. If no `parameters.data` is provided the quotefeed will be used. - * - 3.0.8 `parameters.forceData` no longer used, now all data sent in will be forced. - * - 3.0.8 `parameters.loadData` added. - * - 4.0.0 Added `parameters.symbol` (string equivalent of parameters.symboObject). - * - 4.0.0 Multiple series can now be added for the same underlying symbol. parameters.field or parameters.symbolObject can be used to accomplish this. - * - 4.0.0 Added `parameters.baseColor`. - * - 5.1.0 Series data now added to masterData as an object. This allows storage of more than just one data point, facilitating OHLC series! - * - 5.1.0 addSeries will now create a renderer unless renderer, name and color parameters are all omitted. - * - 5.1.0 Now also dispatches a "symbolChange" event when pushing data into the chart, rather than only when using a quote feed. - * - 5.1.1 Added `parameters.extendToEndOfDataSet`. - * - 5.1.1 `parameters.chartType`, originally used to draw "mountain" series, has been deprecated in favor of the more flexible 'renderer' parameter. It is being maintained for backwards compatibility. - * - 5.2.0 `parameters.gaps` has been deprecated (but maintained for backwards compatibility) and replaced with `parameters.gapDisplayStyle`. - * - 6.0.0 `parameters.fillGaps` is now a string type and can accept either "carry" or "gap". Setting to true will use the value of stxx.cleanupGaps. - * - 6.2.0 No longer force 'percent'/'linear', when adding/removing comparison series, respectively, unless {@link CIQ.ChartEngine.Chart#forcePercentComparison} is true. This allows for backwards compatibility with previous UI modules. - * - 6.3.0 If a panel name is passed into the function, a new panel will be created if one doesn't already exist. - * - 6.3.0 Added `parameters.displayFloatingLabel`. - * - 8.1.0 Supports custom baselines. See example. - * - 8.2.0 Added `parameters.baseline`. - * - * @example Add a series overlay and display it as a dashed line. - * stxx.addSeries( - * "IBM", - * {color:"purple", pattern:[3,3]} - * ); - * - * @example Add a series onto the main axis and then create a moving average study that uses it. - * // Note, this will work for any study that accepts a "Field" parameter. - * - * stxx.addSeries("ge", {color:"yellow", shareYAxis:true}, function(){ - * let inputs = { - * "Period": 20, - * "Field": "ge", - * "Type": "ma" - * }; - * let outputs = { - * "MA": "red" - * }; - * CIQ.Studies.addStudy(stxx, "ma", inputs, outputs); - * }); - * - * @example Add series using a symbolObject which includes the data source key. - * // This key will be sent into the fetch 'params' for use in your quoteFeed. - * let mySymbol = {symbol:"GE", source:"realtimedb"}; - * let mySymbol2 = {symbol:"GDP", source:"fundamentaldb"}; - * - * stxx.addSeries(null, {color:"purple", symbolObject:mySymbol}); - * stxx.addSeries(null, {color:"green", symbolObject:mySymbol2}); - * - * @example Set a custom field. - * // The engine is smart enough to use the series symbol, or "Close" if the symbol doesn't exist in the returned data from your quotefeed - * // but if you want to use any other field then you'll need to specify it like this. - * stxx.addSeries("GE", {color:"purple", field: "Open"}); - * - * @example Add the comparison series with a color to immediately render using default renderer (as lines) and dashes for gaps fillers. - * stxx.addSeries(symbol1, {display:"Description 1",isComparison:true,color:"purple", gapDisplayStyle:{pattern:[3,3]},width:4,permanent:true}); - * stxx.addSeries(symbol2, {display:"Description 2",isComparison:true,color:"pink", gapDisplayStyle:{pattern:[3,3]},width:4}); - * stxx.addSeries(symbol3, {display:"Description 3",isComparison:true,color:"brown", gapDisplayStyle:{pattern:[3,3]},width:4}); - * - * @example Add the series with only default parameters (no color). - * // The series will not display on the chart after it is added, - * // but the data will be available ready to be attached to a renderer. - * stxx.addSeries(symbol1, {display:"Description 1"}); - * stxx.addSeries(symbol2, {display:"Description 2"}); - * stxx.addSeries(symbol3, {display:"Description 3"}); - * - * @example Add a series with a color to immediately render. - * // It also calls callbackFunct after the data is returned from the fetch. - * function callbackFunct(field){ - * return function(err) { - * CIQ.alert(field); - * } - * } - * - * stxx.addSeries(symbol1, {display:"Description",color:"brown"}, callbackFunct(symbol1)); - * - * @example Add a stacked historam with three series usng an external renderer. - * - * // Note how the addSeries callback is used to ensure the data is present before the series is displayed. - * - * // Configure the histogram display. - * let params={ - * name: "Sentiment Data", - * subtype: "stacked", - * heightPercentage: .7, // How high to go. 1 = 100% - * opacity: .7, // Alternatively can use rgba values in histMap instead - * widthFactor: .8 // to control space between bars. 1 = no space in between - * }; - * - * // Legend creation callback. - * function histogramLegend(colors){ - * stxx.chart.legendRenderer(stxx,{legendColorMap:colors, coordinates:{x:260, y:stxx.panels["chart"].yAxis.top+30}, noBase:true}); - * } - * - * let histRenderer=stxx.setSeriesRenderer(new CIQ.Renderer.Histogram({params: params, callback: histogramLegend})); - * - * stxx.addSeries("^NIOALL", {display:"Symbol 1"}, function() {histRenderer.attachSeries("^NIOALL","#6B9CF7").ready();}); - * stxx.addSeries("^NIOAFN", {display:"Symbol 2"}, function() {histRenderer.attachSeries("^NIOAFN","#95B7F6").ready();}); - * stxx.addSeries("^NIOAMD", {display:"Symbol 3"}, function() {histRenderer.attachSeries("^NIOAMD","#B9D0F5").ready();}); - * - * @example Add a series overlay for data that *already exists in the chart*. - * // By setting loadData to false, the chart will assume the data exists, and not request it from the quotefeed. - * stxx.addSeries( - * "Close", - * {color:"purple", loadData:false} - * ); - * - * @example Add multiple series and attach them all to the same renderer with a custom y-axis on the left. - * // See this example working here: https://jsfiddle.net/chartiq/b6pkzrad. - * - * // Note how the addSeries callback is used to ensure the data is present before the series is displayed. - * - * stxx.addSeries( - * "NOK", - * { - * renderer: "Lines", // Create a line renderer - * type: "mountain", // of mountain type - * yAxis: { // and give it its own y axis - * position: "left", // on the left - * textStyle: "#0044FF", // with labels of color #0044FF - * decimalPlaces: 0, // no decimal places on the labels - * maxDecimalPlaces: 0, // and no defimal places on the last price floating label either. - * }, - * name: "left_axis_renderer", // Call the custom renderer "left_axis_renderer", so it can be referenced by other series. - * color: "#FFBE00", // Set the line color to "#FFBE00" - * width: 4, // and a width of 4. - * display: "NOK Sample", // Finally, use a different display name of "NOK Sample" on the tooltip. - * }, - * function(){ - * stxx.addSeries( // Now that the first series and rederer has been set - * "SNE", // add the 2nd series using that same renderer. - * { - * name: "left_axis_renderer", - * color: "#FF1300", - * display: "Sony Sample", - * } - * ); - * } - * ); - * - * @example Add a series with a colored bar renderer using default colors. - * stxx.addSeries("MSFT",{renderer:"Bars", colored:true}); - * - * @example Add a candle series for GE, and display it's Bid and Ask. - * // Assuming Bid/Ask data is NOT part of the initial data objects and can be fetched individually using different instrument IDs. - * stxx.addSeries('ge',{renderer:'Candles',shareYAxis:true}); - * stxx.addSeries('geBid',{display:'Ge Bid',symbol:'ge',field:'Bid',color:'yellow',renderer:'Lines',shareYAxis:true}); - * stxx.addSeries('geAsk',{display:'Ge Ask',symbol:'ge',field:'Ask',color:'blue',renderer:'Lines',shareYAxis:true}); - * - * @example Add a series with a candle renderer using custom colors. - * stxx.addSeries("MSFT", - * { - * renderer:"Candles", - * fill_color_up:"magenta", - * border_color_up:"purple", - * fill_color_down:"lightgreen", - * border_color_down:"green" - * } - * ); - * - *@example Add a series with Histogram renderer using default colors. - * stxx.addSeries('ge', {renderer:"Histogram", color: 'red'}); - * - * @example Add a series with tension to cause the lines to be curved instead of straight. - * // The "tension" parameter is a line renderer parameter. - * // The 'renderer:"Lines"' parameter could theoretically be omitted since it is the default renderer. - * stxx.addSeries('GE',{renderer:"Lines", type:'mountain',color:'yellow',tension:0.3}) - * - * @example Display an inverted chart for instrument "T" using equations as symbols - * // Note the formatter used to change the sign of the axis values. - * let axis2 = new CIQ.ChartEngine.YAxis( - * { - * position:"left", - * textStyle:"#FFBE00", - * priceFormatter:function(stx, panel, price, decimalPlaces){return stx.formatYAxisPrice(price, panel, decimalPlaces)*-1} - * } - * ); - * - * stxx.addSeries("=-1*T", {display:"Test",width:4,renderer:"Lines",color:"#FFBEDD",yAxis:axis2},function(){}); - * - * // This will display the same series in the standard scale. - * let axis3 = new CIQ.ChartEngine.YAxis({position:"left",textStyle:"#FFBE00"}); - * stxx.addSeries("T", {display:"Test",width:4,renderer:"Lines",color:"#FFBEDD",yAxis:axis3},function(){}); - * - * @example Add a series that will use its own custom y-axis on the left. - * // Note that the renderer does not need to be explicitly declared; - * // nor does the y axis, since they will only belong to this one series. - * // The addSeries call will take the pertinent parameters and internally - * // create the required axis and render objects that will be associated with it. - * stxx.addSeries("T", - * { - * display:"Test", - * renderer:"Lines", - * type:'mountain', - * color:"#FFBEDD", - * yAxis:{position:"left", textStyle:"#FFBE00"} - * }, - * function(){console.log('This is a callback. All done.')} - * ); - * - * @example Use a renderer to display heat map data points. - * // Each attached series will represent a stream of colors for the heat map. - * // Note special data formatting, where the custom field that will be used for the stream of data points, - * // is an array of values -- 'Bids' in this example. - * let renderer = stxx.setSeriesRenderer(new CIQ.Renderer.Heatmap()); - * stxx.addSeries( - * "L2", - * { data:[ - * {DT:"2019-01-04",Bids:[100,100.3,100.2,101]}, - * {DT:"2019-01-07",Bids:[101,101.5,102,103]}, - * {DT:"2019-01-08",Bids:[101.2,101.5,101.7,102]}, - * {DT:"2019-01-09",Bids:[101.3,101.7,101.9]}, - * {DT:"2019-01-10",Bids:[102]}] - * }, - * function(){ - * renderer.attachSeries("L2", {field:"Bids",color:"#FF9300"}).ready(); - * } - * ); - * - * @example Add a series with a custom baseline. - * stxx.addSeries("GOOG", {baseline: {defaultLevel: 105}, color: "purple"}); - */ -CIQ.ChartEngine.prototype.addSeries = function (id, parameters, cb) { - var injectionResult = this.runPrepend("addSeries", arguments); - if (injectionResult) return injectionResult; - var display = id ? id : null; // if id is passed then we default display to the same value (we can always override with parameters.display) - var symbol = id; - if (!id) id = CIQ.uniqueID(); - if (parameters && parameters.panel === true) parameters.panel = id; // panel name set to boolean true, change it - var obj = { - parameters: parameters ? CIQ.clone(parameters) : {}, - yValueCache: [], - display: display, - id: id, - loading: parameters ? parameters.loadData !== false : true - }; - obj.parameters.yAxis = parameters && parameters.yAxis; // revert the cloning of yaxis - parameters = obj.parameters; - if (parameters.symbol) symbol = parameters.symbol; - if (parameters.isComparison) parameters.shareYAxis = true; - if ( - parameters.yAxis && - !(parameters.yAxis instanceof CIQ.ChartEngine.YAxis) - ) { - parameters.yAxis = new CIQ.ChartEngine.YAxis(parameters.yAxis); // in case it gets passed as a plain object - } - CIQ.ensureDefaults(parameters, { - chartName: this.chart.name, - symbolObject: { symbol: symbol }, - panel: this.chart.panel.name, - fillGaps: false, - action: "add-series" - }); - if ("display" in parameters) obj.display = parameters.display; - var chart = this.charts[parameters.chartName]; - var symbolObject = parameters.symbolObject; - symbol = parameters.symbol = symbolObject.symbol; - if (!obj.display) obj.display = symbol || parameters.field; // If after all this time, we still don't have a display, then resort to the reasonable alternative of using the symbol or field - obj.endPoints = {}; - - // backwards compatability for pre 4.0 - if (!parameters.gapDisplayStyle && parameters.gapDisplayStyle !== false) - parameters.gapDisplayStyle = parameters.gaps; - if (parameters.isComparison) { - // if gapDisplayStyle parameters isn't defined the gaps will be rendered transparent - if (parameters.gapDisplayStyle === undefined) - parameters.gapDisplayStyle = "transparent"; - } - - var existsAlready = this.getSeries({ - symbolObject: symbolObject, - chart: chart, - includeMaster: true - }); - - // if panel doesn't exist, create a new panel - var panelName = parameters.panel; - if (!this.panels[panelName]) { - var yAxis = parameters.yAxis || new CIQ.ChartEngine.YAxis(); - yAxis.name = id; // a way to check if a series "owns" a panel - this.createPanel(id, panelName, null, null, yAxis); - if (!this.preferences.dragging || !this.preferences.dragging.series) - parameters.highlightable = false; - } else { - if (!parameters.yAxis && !parameters.shareYAxis) { - parameters.yAxis = new CIQ.ChartEngine.YAxis({ - name: id, - position: "none" - }); - } - } - - chart.series[id] = obj; - var self = this, - currentlyImporting = this.currentlyImporting; - - function setUpRenderer(stx, obj) { - var renderer = parameters.renderer || "Lines"; - var name = parameters.name || id; - if ( - parameters.yAxis && - !(parameters.yAxis instanceof CIQ.ChartEngine.YAxis) && - !currentlyImporting - ) - parameters.yAxis.name = name; - if ( - !parameters.renderer && - !parameters.name && - !parameters.color && - !parameters.chartType - ) - return; // if no renderer, name, color, nor chartType set, assume will be set later on manual call to attachSeries. - var r = stx.getSeriesRenderer(name); - if (!r) { - let params = { - name: name, - overChart: parameters.overChart !== false, - useChartLegend: true - }; - if (parameters.chartType) { - r = CIQ.Renderer.produce( - parameters.chartType, - CIQ.extend( - { - highlightable: parameters.highlightable, - dependentOf: parameters.dependentOf, - panel: parameters.panel, - yAxis: parameters.yAxis, - baseline: parameters.baseline - }, - params - ) - ); - } else { - CIQ.ensureDefaults(parameters, params); - r = new CIQ.Renderer[renderer]({ params: parameters }); - } - if (!r) return; - stx.setSeriesRenderer(r); - } - r.attachSeries(id, parameters); - if (parameters.loadData !== false) r.ready(); - - stx.layout.symbols = stx.getSymbols({ - "include-parameters": true, - "exclude-studies": true - }); - stx.changeOccurred("layout"); - } - - function handleResponse(params) { - return function (dataCallback) { - if (!dataCallback.error) { - var qts = dataCallback.quotes, - fillGaps = parameters.fillGaps; - if (!self.cleanupGaps) fillGaps = false; // disable override - qts = self.doCleanupGaps(qts, self.chart, { cleanupGaps: fillGaps }); - self.updateChartData(qts, self.chart, { - secondarySeries: symbol, - noCreateDataSet: true, - noCleanupDates: true, - allowReplaceOHL: true - }); - obj.loading = false; - obj.moreAvailable = dataCallback.moreAvailable; - obj.upToDate = dataCallback.upToDate; - setUpRenderer(self, obj); - } - if (parameters.action !== null && !existsAlready.length) - self.dispatch(currentlyImporting ? "symbolImport" : "symbolChange", { - stx: self, - symbol: params.symbol, - symbolObject: params.symbolObject, - action: parameters.action, - id: obj.id, - parameters: parameters - }); - if (cb) cb.call(self, dataCallback.error, obj); - }; - } - - if ( - parameters.isComparison && - chart.forcePercentComparison && - parameters.panel == chart.panel.name && - (!parameters.yAxis || parameters.yAxis == chart.yAxis) - ) - this.setChartScale("percent"); - - var masterData = chart.masterData; - if (!masterData) masterData = chart.masterData = this.masterData = []; - var masterLength = masterData.length; - - if (parameters.data && !parameters.data.useDefaultQuoteFeed /* legacy */) { - var parms = { - symbol: symbol, - symbolObject: symbolObject, - action: parameters.action - }; - handleResponse(parms)({ quotes: parameters.data }); - } else if (existsAlready.length) { - // This symbol is already in the series - obj.endPoints = existsAlready[0].endPoints; - obj.loading = existsAlready[0].loading; - setUpRenderer(this, obj); - if (cb) { - setTimeout(function () { - cb.call(self, null, obj); - }, 0); - } - } else if (this.quoteDriver && parameters.loadData !== false) { - // if we have a quote feed, go and fetch it. - var driver = this.quoteDriver; - var fetchParams = driver.makeParams(symbol, symbolObject, chart); - // for comparisons, you must fetch enough data on the new Comparison to match the beginning of the masterData until the current tick. - // The current tick may be newer than master data last tick, so set the end Date to right now. - // If the chart is empty, then don't send any dates and allow the fetch to do an initial load - if (masterLength) { - fetchParams.startDate = masterData[0].DT; - fetchParams.endDate = this.isHistoricalMode() - ? masterData[masterData.length - 1].DT - : new Date(); - } - if (fetchParams.stx.isEquationChart(fetchParams.symbol)) { - //equation chart - CIQ.fetchEquationChart(fetchParams, handleResponse(fetchParams)); - } else { - var qf = driver.getQuoteFeed(fetchParams); - if (qf) - CIQ.ChartEngine.Driver.fetchData( - 4 /*CIQ.QuoteFeed.SERIES*/, - qf.engine, - fetchParams, - handleResponse(fetchParams) - ); - } - } else { - // It might get in here if we depend on loadDependents to initialize the series, such as from importLayout - setUpRenderer(this, obj); - if (cb) cb.call(this, null, obj); - } - - this.runAppend("addSeries", arguments); - - return obj; -}; - -/** - * Returns an array of series that match the given filters. - * - * If any series is an equation chart then the equation will be searched for the matching symbol. - * - * @param {object} params Parameters - * @param {string} [params.symbol] Filter for only series that contain this symbol - * @param {object} [params.symbolObject] Filter for only series that contain this symbolObject - * @param {boolean} [params.includeMaster] If true then the masterSymbol will be checked for a match too. A blank object will be returned. You should only use this if you're just using this to look for yes/no dependency on a symbol. - * @param {CIQ.ChartEngine.Chart} [params.chart] Chart object to target - * @return {array} Array of series descriptors - * @memberOf CIQ.ChartEngine - * @since 4.0.0 - */ -CIQ.ChartEngine.prototype.getSeries = function (params) { - var chart = params.chart ? params.chart : this.chart; - var series = chart.series; - var symbolObject = params.symbolObject; - if (!symbolObject) symbolObject = { symbol: params.symbol }; - var arr = []; - for (var id in series) { - var sd = series[id]; - if (CIQ.symbolEqual(symbolObject, sd.parameters.symbolObject)) arr.push(sd); - } - if (params.includeMaster) { - if (CIQ.symbolEqual(symbolObject, chart.symbolObject)) arr.push({}); - } - return arr; -}; - -/** - * INJECTABLE - * - * Modifies an existing series. Any passed parameters [extend]{@link CIQ.extend} the existing parameters. - * - * @param {string|Object} descriptor Series to modify. Accepts the series object as returned by {@link CIQ.ChartEngine#addSeries} or series ID. - * @param {Object} [parameters] The parameters to change or add. - * @param {boolean} [noRecurseDependents] If true, the panel and y-axis changes of the modified series do not propagate to the renderers of dependent series. - * @return {Object} The modified series object. - * @memberof CIQ.ChartEngine - * - * @example Remove a series for a particular symbol. - * function replaceComparisonColor(stx, symbol, color){ - * for (let series in stx.chart.series) { - * let seriesParams = stx.chart.series[series].parameters; - * if (seriesParams.isComparison && seriesParams.symbol == symbol) { - * stx.modifySeries(series, {color: color}); - * } - * } - * stx.draw(); - * } - * - * @example Set a custom baseline on an existing series. - * stxx.modifySeries('GOOG', { baseline: { defaultLevel: 100 } }) - * - * @since - * - 5.1.1 - * - 5.2.0 No longer accepts a callback function. - * - 7.1.0 Returns the modified series. - * - 7.3.0 Synchronizes panel and y-axis changes with dependent renderers unless the new parameter, - * `noRecurseDependents`, is set to true. - * - 8.1.0 Supports custom baselines. See example. - */ -CIQ.ChartEngine.prototype.modifySeries = function ( - descriptor, - parameters, - noRecurseDependents -) { - if (this.runPrepend("modifySeries", arguments)) return; - if (!parameters) return; - - var series; - var id; - var chart; - - if (typeof descriptor === "string") { - chart = parameters.chartName - ? this.charts[parameters.chartName] - : this.chart; - id = descriptor; - series = chart.series[id]; - } else { - series = descriptor; - id = series.id; - chart = this.charts[series.parameters.chartName]; - } - if (!series) return; - - CIQ.extend(series.parameters, parameters, true); - this.getRendererFromSeries(id).modifyRenderer(parameters); - var myParams = series.parameters; - var myRenderer; - - for (var key in chart.seriesRenderers) { - var renderer = chart.seriesRenderers[key]; - var rParams = renderer.params; - var seriesParams = renderer.seriesParams; - for (var i = 0; i < seriesParams.length; ++i) { - var originalParams = seriesParams[i]; - var sPanel = this.panels[originalParams.panel]; - var yAxisName = sPanel && sPanel.yAxis.name; - if (originalParams.id === series.id) { - if (myParams.panel === true) - myParams.panel = myParams.dependentOf || myParams.name; // panel name set to boolean true, change it - rParams.panel = myParams.panel; - // only set series yAxis to renderer if explicitly passed in to function args - if (parameters.yAxis) { - if (!(parameters.yAxis instanceof CIQ.ChartEngine.YAxis)) { - parameters.yAxis = new CIQ.ChartEngine.YAxis(parameters.yAxis); // in case it gets passed as a plain object - } - rParams.yAxis = parameters.yAxis; - } - if ( - myParams.panel != originalParams.panel && - rParams.name == yAxisName - ) { - this.electNewPanelOwner(originalParams.panel); // this should only happen once - } else { - var oldYAxis = this.getYAxisByName(myParams.panel, rParams.name); - if ( - oldYAxis && - myParams.yAxis && - oldYAxis.name !== myParams.yAxis.name - ) { - oldYAxis.name = this.electNewYAxisOwner(oldYAxis); - } - } - if (!myParams.field) myParams.field = null; - // this.registerBaselineToHelper(renderer); - renderer.attachSeries(id, CIQ.ensureDefaults(myParams, originalParams)); - if (!myParams.field) myParams.field = myParams.subField; - delete myParams.subField; - if ( - myParams.isComparison && - chart.forcePercentComparison && - myParams.panel == chart.panel.name && - (!series.parameters.yAxis || myParams.yAxis.name == chart.yAxis.name) - ) - this.setChartScale("percent"); - myRenderer = renderer; - break; - } - } - } - - this.changeOccurred("layout"); - CIQ.getFn("Drawing.updateSource")( - this, - series.parameters.symbol || id, - null, - series.parameters.panel - ); - this.runAppend("modifySeries", arguments); - - if (noRecurseDependents !== true) { - // make sure all dependent renderers change their panels and yaxes to match - var dependentRenderers = myRenderer.getDependents(this); - for (var n = 0; n < dependentRenderers.length; n++) { - this.modifySeries( - dependentRenderers[n].params.name, - { panel: myRenderer.params.panel, yAxis: series.parameters.yAxis }, - true - ); - } - - // make sure all master renderers change their panels and yaxes to match - var masterRenderer = chart.seriesRenderers[myRenderer.params.dependentOf]; - if (masterRenderer) { - if ( - masterRenderer.params.yAxis != series.parameters.yAxis || - masterRenderer.params.panel != myRenderer.params.panel - ) { - this.modifySeries( - myRenderer.params.dependentOf, - { panel: myRenderer.params.panel, yAxis: series.parameters.yAxis }, - true - ); - } - } - } - - this.draw(); - return series; -}; - -/** - * INJECTABLE - * - * Removes series data from masterData and unregisters the series from `chart.series` without removing it from any associated renderers. - * Also updates the [quoteFeed subscriptions]{@link quotefeed.unsubscribe}. - * **Not recommended to be called directly.** - * Instead use {@link CIQ.ChartEngine#removeSeries} to remove a series from all associated renderers, - * or {@link CIQ.Renderer#removeSeries} to remove a series from a specific renderer. - * @param {string|object} field The name of the series to remove -OR- the series object itself. - * @param {CIQ.ChartEngine.Chart} chart The chart to remove from - * @param {object} [params] Parameters - * @param {string} [params.action="remove-series"] Action to be dispatched with symbolChange event - * @memberOf CIQ.ChartEngine - * @since - * - 4.0.0 Now supports passing a series descriptor instead of a field. - * - 4.0.0 Series data is now totally removed from masterData if no longer used by any other renderers. - * - 4.0.0 Empty renderers are now removed when series are removed. - * - 6.3.0 deleteSeries now calls {@link CIQ.ChartEngine#checkForEmptyPanel}. - */ -CIQ.ChartEngine.prototype.deleteSeries = function (field, chart, params) { - if (this.runPrepend("deleteSeries", arguments)) return; - params = params ? params : {}; - var action = params.action ? params.action : "remove-series"; - var toRemove; - if (typeof field === "object") { - toRemove = field.id; - chart = chart || this.charts[field.parameters.chartName]; - } else { - toRemove = field; - chart = chart || this.chart; - } - var theSeries = chart.series[toRemove]; - if (!theSeries) return; // prevent js error if removing a series that doesn't exist - var loadedData = theSeries.parameters.loadData; - var symbolObject = theSeries.parameters.symbolObject; - delete chart.series[toRemove]; - - // If no more dependencies, then remove the symbol from the actual masterData - var dependencies = this.getSeries({ - symbolObject: symbolObject, - includeMaster: true - }); - if (loadedData === false) dependencies.push(toRemove); - if (!dependencies.length) this.cleanMasterData(symbolObject, chart); - - var panel = this.panels[theSeries.parameters.panel]; - if (panel) { - // panel can be removed before all series can be removed, make sure it still exists - this.checkForEmptyPanel(panel); - } - - this.createDataSet(); - if (!dependencies.length) - this.dispatch(this.currentlyImporting ? "symbolImport" : "symbolChange", { - stx: this, - symbol: symbolObject.symbol, - symbolObject: symbolObject, - id: toRemove, - action: action - }); - if (this.quoteDriver) this.quoteDriver.updateSubscriptions(); - this.runAppend("deleteSeries", arguments); -}; - -/** - * INJECTABLE - * - * Detaches a series added using [addSeries]{@link CIQ.ChartEngine#addSeries} from **all associated renderers** in the chart, - * removing the actual series data from masterData. - * - * If the series belonged to a renderer that no longer has other series attached to it, the renderer is removed as well. - * See {@link CIQ.Renderer#removeSeries} for more details or how to remove a series from a single renderer and without ever deleting the associated renderer or data. - * - * To remove all series from a chart, simply iterate through the active series object and delete them one at a time: - * ``` - * for(var s in stxx.chart.series){ - * var series=stxx.chart.series[s]; - * stxx.removeSeries(series); - * } - * ``` - * @param {string|object} field The name of the series to remove -OR- the series object itself. - * @param {CIQ.ChartEngine.Chart} [chart] The chart object from which to remove the series - * @memberof CIQ.ChartEngine - * @since - * - 4.0.0 Now supports passing a series descriptor instead of a field. - * - 4.0.0 Series data is now totally removed from masterData if no longer used by any other renderers. - * - 4.0.0 Empty renderers are now removed when series are removed. - */ -CIQ.ChartEngine.prototype.removeSeries = function (field, chart) { - if (this.runPrepend("removeSeries", arguments)) return; - - var toRemove; - var deleted = false; - - if (typeof field === "object") { - toRemove = field.id; - chart = chart || this.charts[field.parameters.chartName]; - } else { - toRemove = field; - chart = chart || this.chart; - } - - for (var r in chart.seriesRenderers) { - var renderer = chart.seriesRenderers[r]; - var rPanel = this.panels[renderer.params.panel]; - var yAxisName = rPanel && rPanel.yAxis.name; - for (var sp = renderer.seriesParams.length - 1; sp >= 0; sp--) { - var series = renderer.seriesParams[sp]; - if (series.id === toRemove) { - renderer.removeSeries(toRemove); - if (renderer.seriesParams.length < 1) { - this.removeSeriesRenderer(renderer); - if (renderer.params.name == yAxisName) { - this.electNewPanelOwner(renderer.params.panel); - } else { - if (!this.checkForEmptyPanel(renderer.params.panel)) { - var rendererAxis = this.getYAxisByName( - rPanel, - renderer.params.name - ); - if (rendererAxis) { - rendererAxis.name = - rendererAxis.studies[0] || rendererAxis.renderers[1]; - } - } - } - } - deleted = true; - } - } - } - if (!deleted) this.deleteSeries(toRemove, chart); // just in case the renderer didn't... - this.resetDynamicYAxis(); - this.draw(); - this.resizeChart(); - this.runAppend("removeSeries", arguments); -}; - -/** - * **The UI portion of this namespace is maintained for legacy implementations only (not using web components). New implementations should use functionality included in the web components (stxUI.js)**
- * Comparison namespace - * @namespace - * @name CIQ.Comparison - */ -CIQ.Comparison = CIQ.Comparison || function () {}; // Create namespace - -/** - * For relative comparisons, this is the starting (baseline) point. - * - * Valid options are: - * - A number to specify an absolute amount to be used as the starting value for all percentage changes. - * - A string containing the symbol of an existing series to be used as the starting value for the comparisons (for instance "IBM"). Computations will then be based on the change from the first visible bar value for the selected symbol. - * - An empty string will compare against the baseline value of the main series (same as in "percent" scale). - * - * See {@link CIQ.ChartEngine#setChartScale} for more details. - * @type number | string - * @memberof CIQ.Comparison - * @since 5.1.0 - */ -CIQ.Comparison.initialPrice = 100; - -/** - * Used to compute the initial price when it is supplied as a string - * @param {CIQ.ChartEngine.Chart} chart The specific chart - * @return {number} The initial price as a number - * @memberof CIQ.Comparison - * @since 5.1.0 - * @private - */ -CIQ.Comparison.getInitialPrice = function (chart) { - if (chart.initialComparisonPrice) return chart.initialComparisonPrice; - chart.initialComparisonPrice = 100; - var symbol = CIQ.Comparison.initialPrice; - if (typeof symbol == "number") chart.initialComparisonPrice = symbol; // absolute amount - if (typeof symbol == "string") { - if (chart.series[symbol] || symbol === "") { - var priceField = "Close"; - if (chart.defaultPlotField) { - if (!chart.highLowBars) priceField = chart.defaultPlotField; - } - for ( - var i = chart.dataSet.length - chart.scroll - 1; - i < chart.dataSet.length; - i++ - ) { - var bar = chart.dataSet[i]; - if (bar) { - if (bar[symbol] && bar[symbol][priceField]) { - chart.initialComparisonPrice = bar[symbol][priceField]; - break; - } else if (symbol === "" && bar[priceField]) { - chart.initialComparisonPrice = bar[priceField]; - break; - } - } - } - } - } - return chart.initialComparisonPrice; -}; - -/** - * Transform function for percent comparison charting - * @param {CIQ.ChartEngine} stx The charting object - * @param {CIQ.ChartEngine.Chart} chart The specific chart - * @param {number} price The price to transform - * @return {number} The transformed price (into percentage) - * @memberof CIQ.Comparison - */ -CIQ.Comparison.priceToPercent = function (stx, chart, price) { - var baseline = CIQ.Comparison.baseline || price; - return Math.round(((price - baseline) / baseline) * 100 * 10000) / 10000; -}; - -/** - * Untransform function for percent comparison charting - * @param {CIQ.ChartEngine} stx The charting object - * @param {CIQ.ChartEngine.Chart} chart The specific chart - * @param {number} percent The price to untransform - * @return {number} The untransformed price - * @memberof CIQ.Comparison - */ -CIQ.Comparison.percentToPrice = function (stx, chart, percent) { - var baseline = CIQ.Comparison.baseline || 1; - return baseline * (1 + percent / 100); -}; - -/** - * Transform function for relative comparison charting - * @param {CIQ.ChartEngine} stx The charting object - * @param {CIQ.ChartEngine.Chart} chart The specific chart - * @param {number} price The price to transform - * @return {number} The transformed price (relative to {@link CIQ.Comparison.initialPrice}) - * @memberof CIQ.Comparison - * @since 5.1.0 - */ -CIQ.Comparison.priceToRelative = function (stx, chart, price) { - var baseline = CIQ.Comparison.baseline || price; - var initialPrice = CIQ.Comparison.getInitialPrice(chart); - return (initialPrice * price) / baseline; -}; - -/** - * Untransform function for relative comparison charting - * @param {CIQ.ChartEngine} stx The charting object - * @param {CIQ.ChartEngine.Chart} chart The specific chart - * @param {number} relative The price to untransform - * @return {number} The untransformed price - * @memberof CIQ.Comparison - * @since 5.1.0 - */ -CIQ.Comparison.relativeToPrice = function (stx, chart, relative) { - var baseline = CIQ.Comparison.baseline || 1; - var initialPrice = CIQ.Comparison.getInitialPrice(chart); - return (baseline * relative) / initialPrice; -}; - -CIQ.Comparison.createComparisonSegmentInner = function (stx, chart) { - // create an array of the fields that we're going to compare - var fields = []; - var field, panel, yAxis; - for (field in chart.series) { - var parameters = chart.series[field].parameters; - if (parameters.isComparison) { - fields.push(parameters.symbol); - } - } - var priceFields = ["Close", "Open", "High", "Low", "iqPrevClose"]; - var highLowBars = stx.chart.highLowBars; - if (chart.defaultPlotField && !highLowBars) - priceFields.unshift(chart.defaultPlotField); - var baselineField = priceFields[0]; - var s = stx.layout.studies; - for (var n in s) { - var sd = s[n]; - panel = stx.panels[sd.panel]; - yAxis = sd.getYAxis(stx); - if (!panel || panel.yAxis != yAxis) continue; - for (field in sd.outputMap) priceFields.push(field); - for (var h = 0; h <= 2; h++) - priceFields.push(sd.name + "_hist" + (h ? h : "")); - if (sd.referenceOutput) - priceFields.push(sd.referenceOutput + " " + sd.name); - } - for (var p in stx.plugins) { - var plugin = stx.plugins[p]; - if (!plugin.transformOutputs) continue; - for (field in plugin.transformOutputs) { - priceFields.push(field); - } - } - - chart.initialComparisonPrice = null; - chart.dataSegment = []; - var firstQuote = null; - - // By default start comparison at the close of the previous bar - var firstTick = chart.dataSet.length - chart.scroll - 1; - // Start at first visible bar instead if flag is set - if (stx.startComparisonsAtFirstVisibleBar) firstTick += 1; - - //if(stx.micropixels+stx.layout.candleWidth/2<0) firstTick++; // don't baseline comparison with a bar off the left edge - var transformsToProcess = chart.maxTicks + 3; //make sure we have transformed enough data points that we plot the y-axis intercept correctly - - for (var i = 0; i <= transformsToProcess; i++) { - if (i == transformsToProcess) i = -1; //go back and revisit the tick before the first - var position = firstTick + i; - if (position < chart.dataSet.length && position >= 0) { - var quote = chart.dataSet[position]; - var closingPrice = quote[baselineField]; - - if (!firstQuote) { - if (closingPrice === 0 || closingPrice === null) { - if (i < 0) break; - //if we still can't get a single tick to do this and we try to revisit, we are out, or we go into infinite loop - else continue; // can't calculate the percentage gain/loss if the close is 0 or null. - } - firstQuote = CIQ.clone(quote); - } - - // iterate through the fields calculating the percentage gain/loss - // We store the results in the "transform" subobject of the data set - // Note we inline the math calculation to save overhead of JS function call - if (!quote.transform) - quote.transform = { - cache: {}, - DT: quote.DT, - Date: quote.Date - }; - if (!CIQ.Comparison.baseline && closingPrice) - firstQuote = CIQ.clone(quote); - CIQ.Comparison.baseline = firstQuote[baselineField]; - - var j; - for (j = 0; j < priceFields.length; j++) { - field = priceFields[j]; - if (quote[field] || quote[field] === 0) - //quote.transform[field]=Math.round(((quote[field]-CIQ.Comparison.baseline)/CIQ.Comparison.baseline*100)*10000)/10000; // first compute the close pct, our baseline - quote.transform[field] = chart.transformFunc( - stx, - chart, - quote[field] - ); - } - - // Transform the series - for (j = 0; j < fields.length; j++) { - field = fields[j]; - var compSymbol = chart.series[field]; - if (i == -1 && compSymbol && compSymbol.parameters.isComparison) { - delete quote.transform[field]; - continue; - } - var seriesData = quote[field]; - for (var k = 0; seriesData && k < priceFields.length; k++) { - var seriesPrice = seriesData[priceFields[k]]; - if (seriesPrice || seriesPrice === 0) { - // Skip blanks - var baseline = - firstQuote[field] && firstQuote[field][priceFields[0]]; - if (!baseline && baseline !== 0) { - // This takes care of a series that starts part way through the chart - // The baseline is then computed looking back to what it would have been with a 0% change - if (!firstQuote[field]) firstQuote[field] = {}; - firstQuote[field][priceFields[k]] = baseline = - (seriesPrice * CIQ.Comparison.baseline) / quote[baselineField]; - } - if (baseline !== 0) { - var masterBaseline = CIQ.Comparison.baseline || 1; - var rationalizedPrice = seriesPrice * (masterBaseline / baseline); - if (!quote.transform[field]) quote.transform[field] = {}; - quote.transform[field][priceFields[k]] = chart.transformFunc( - stx, - chart, - rationalizedPrice - ); - } - } - } - } - chart.dataSegment.push(quote); - } else if (position < 0) { - chart.dataSegment.push(null); - } - if (i < 0) break; //we revisited tick before first so we are done - } -}; - -/** - * Formats the percentage values on the comparison chart - * @param {CIQ.ChartEngine} stx The chart object - * @param {CIQ.ChartEngine.Panel} panel The panel - * @param {number} price The raw percentage as a decimal - * @return {string} The percentage formatted as a percent (possibly using localization if set in stx) - * @memberof CIQ.Comparison - */ -CIQ.Comparison.priceFormat = function (stx, panel, price) { - if (price === null || typeof price == "undefined" || isNaN(price)) return ""; - var priceTick = panel.yAxis.priceTick; - var internationalizer = stx.internationalizer; - if (internationalizer) { - if (priceTick >= 5) price = internationalizer.percent.format(price / 100); - else if (priceTick >= 0.5) - price = internationalizer.percent1.format(price / 100); - else if (priceTick >= 0.05) - price = internationalizer.percent2.format(price / 100); - else if (priceTick >= 0.005) - price = internationalizer.percent3.format(price / 100); - else price = internationalizer.percent4.format(price / 100); - } else { - if (priceTick >= 5) price = price.toFixed(0) + "%"; - else if (priceTick >= 0.5) price = price.toFixed(1) + "%"; - else if (priceTick >= 0.05) price = price.toFixed(2) + "%"; - else if (priceTick >= 0.005) price = price.toFixed(3) + "%"; - else price = price.toFixed(4) + "%"; - } - if (parseFloat(price) === 0 && price.charAt(0) == "-") { - // remove minus sign from -0%, -0.0%, etc - price = price.substring(1); - } - return price; -}; - -/** - * Turns comparison charting on or off and sets the transform. - * - * Should not be called directly. Either use the {@link CIQ.ChartEngine#addSeries} `isComparison` parameter or use {@link CIQ.ChartEngine#setChartScale} - * - * @param {string|boolean} mode Type of comparison ("percent" or "relative"). - * - Setting to true will enable "percent". - * - Setting to "relative" will allow the comparisons to be rendered in relation to any provided 'basis' value. For example, the previous market day close price. - * @param {CIQ.ChartEngine.Chart} [chart] The specific chart for comparisons - * @param {number|string} [basis] For a "relative" mode, the basis to relate to. Can be a number or a string. If a string, will use the first price in the datasegment for the series keyed by the string. Sets {@link CIQ.Comparison.initialPrice}. - * @memberof CIQ.ChartEngine - * @since - * - 04-2015 Signature has been revised. - * - 5.1.0 Signature revised again, added basis. - * - 5.1.0 `mode` now also supports "relative" to allow comparisons to be rendered in relation to any provided value. - */ -CIQ.ChartEngine.prototype.setComparison = function (mode, chart, basis) { - if (!chart) chart = this.chart; - if (typeof chart == "string") chart = this.charts[chart]; - if (basis || basis === "") CIQ.Comparison.initialPrice = basis; - if (mode === true) { - // backward compatibility, older versions uses a true/false switch because they did not support the developer setting arbitrary baseline values - if (chart.isComparison) return; // Do nothing if it's already turned on - mode = "percent"; - } - this.resetDynamicYAxis(); - var yAxis = chart.panel.yAxis; - var wasComparison = yAxis.priceFormatter == CIQ.Comparison.priceFormat; // tests if the current formatter is a comparison formatter - // this is like testing if the previous mode was "percent" - switch (mode) { - case "relative": - this.setTransform( - chart, - CIQ.Comparison.priceToRelative, - CIQ.Comparison.relativeToPrice - ); - if (wasComparison) { - yAxis.priceFormatter = yAxis.originalPriceFormatter - ? yAxis.originalPriceFormatter.func - : null; - yAxis.originalPriceFormatter = null; - } - yAxis.whichSet = "dataSegment"; - chart.isComparison = true; - break; - case "percent": - this.setTransform( - chart, - CIQ.Comparison.priceToPercent, - CIQ.Comparison.percentToPrice - ); - if (!wasComparison) { - yAxis.originalPriceFormatter = { func: yAxis.priceFormatter }; - yAxis.priceFormatter = CIQ.Comparison.priceFormat; - } - yAxis.whichSet = "dataSegment"; - chart.isComparison = true; - break; - default: - this.unsetTransform(chart); - if (wasComparison) { - yAxis.priceFormatter = yAxis.originalPriceFormatter - ? yAxis.originalPriceFormatter.func - : null; - yAxis.originalPriceFormatter = null; - } - yAxis.whichSet = "dataSet"; - chart.isComparison = false; - break; - } -}; - -/** - * Sets the chart scale. - * @param {string} chartScale - * - Available options: - * - "log" - * > The logarithmic scale can be helpful when the data covers a large range of values – the logarithm reduces this to a more manageable range. - * - "linear" - * > This is the standard y axis scale; where actual prices are displayed in correlation to their position on the axis, without any conversions applied. - * - "percent" - * > Calculations for the "percent" scale, used by comparisons, are based on the change between the first visible bar to the last visible bar. - * > This is so you can always see relevant information regardless of period. - * > Let's say you are looking at a chart showing a range for the current month. The change will be the difference from the beginning of the month to today. - * > If you now zoom or change the range to just see this past week, then the change will reflect that change from the first day of the week to today. - * > This is how most people prefer to see change, sine it is dynamically adjusted to the selected range. If you want to see today's change, just load today's range. - * > Keep in mind that there is a difference between the change from the beginning of the day, and the change from the beginning of the trading day. So be careful to set the right range. - * - "relative" - * > Very similar to 'percent' but the baseline value can be explicitly set. - * > This is useful if you wish to baseline your comparisons on secondary series, or even a hard coded value ( ie: opening price for the day). - * >
See {@link CIQ.Comparison.initialPrice} for details on how to set basis for "relative" scale. - * - * - Setting to "percent" or "relative" will call {@link CIQ.ChartEngine#setComparison} even if no comparisons are present; which sets `stxx.chart.isComparison=true`. - * - To check if scale is in percentage mode use `stxx.chart.isComparison` instead of using the {@link CIQ.ChartEngine#chartScale} value. - * - See {@link CIQ.ChartEngine.Chart#forcePercentComparison} for behavior of automatic scale setting and removal for [comparisons]{@link CIQ.ChartEngine#addSeries}. - * @memberof CIQ.ChartEngine - * @since - * - 4.1.0 Added "percent". - * - 5.1.0 Added "relative". - */ -CIQ.ChartEngine.prototype.setChartScale = function (chartScale) { - var chart = this.chart; - var needsTransform = { - percent: true, - relative: true - }; - if (!chartScale) chartScale = "linear"; - if (needsTransform[chartScale]) { - this.setComparison(chartScale, chart, CIQ.Comparison.initialPrice); - } else if (needsTransform[this.layout.chartScale]) { - this.setComparison(false, chart); - } - this.layout.chartScale = chartScale; - if (chart.canvas) this.draw(); - this.changeOccurred("layout"); -}; - -}; - - -let __js_standard_share_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - -/* global html2canvas, requirejs */ - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -var h2canvas; - -/** - * Manages chart sharing and uploading. - * - * See the {@tutorial Chart Sharing} tutorial for more details. - * - * @constructor - * @name CIQ.Share - */ -CIQ.Share = CIQ.Share || function () {}; - -/** - * Creates a png image or canvas of the current chart and everything inside the container associated with the chart when it was instantiated; including HTML. - * Elements outside the chart container will **NOT** be included. - * - * It will dynamically try to load `js/thirdparty/html2canvas.min.js` if not already loaded. - * - * This function is asynchronous and requires a callback function. The callback will be passed - * a data object or canvas which can be sent to a server or converted to an image. - * - * By default this method will rely on HTML2Canvas to create an image which will rely on Promises. If your browser does not implement Promises, be sure to include a polyfill to ensure HTML2Canvas works properly. - * - * **This method does not always work with React or Safari** - * - * **Canvases can only be exported if all the contents including CSS images come from the same domain, - * or all images have cross origin set properly and come from a server that supports CORS; which may or may not be possible with CSS images.** - * - * @param {CIQ.ChartEngine} stx Chart object - * @param {object} params - * @param {number} params.width - * @param {number} params.height - * @param {string} params.background - * @param {boolean} params.data If true returns the image data, otherwise, it returns the canvas - * @param {Array} params.hide Array of strings; array of the CSS selectors of the DOM elements to hide, before creating a PNG - * @param {Function} cb Callback when image is available fc(error,data) where data is the serialized image object or canvas - * @name CIQ.Share.FullChart2PNG - * @since 4.0.0 Addition of `params.hide`. - * @version ChartIQ Advanced Package plug-in - * @private - */ -CIQ.Share.FullChart2PNG = function (stx, params, cb) { - if (!stx || !stx.chart) return; - //If we haven't loaded html2canvas, load it - if (typeof html2canvas === "undefined") - return loadHTML2Canvas(function () { - return createHTML2Canvas(stx, params, cb); - }); - h2canvas = html2canvas; - createHTML2Canvas(stx, params, cb); -}; - -function inlineStyle(elem) { - if (!elem.style) return; - var styles = getComputedStyle(elem); - var props = [ - "alignment-baseline", - "dominant-baseline", - "fill", - "fill-opacity", - "font-family", - "font-size", - "font-variant", - "font-weight", - "text-align", - "text-anchor" - ]; - props.forEach(function (i) { - if (!elem.style[i] && styles[i]) elem.style[i] = styles[i]; - }); - for (var child in elem.children) { - inlineStyle(elem.children[child]); - } -} - -function createHTML2Canvas(stx, params, cb) { - if (!params) params = {}; - var recordsTurnedOff = [], - ciqNoShare = "ciq-no-share", - body = document.querySelector("body"); - - if (params.hide && params.hide instanceof Array) { - var customHide = params.hide.join(", "); - var hideItems = document.querySelectorAll(customHide); - for (var idx = 0; idx < hideItems.length; idx++) { - hideItems[idx].classList.add(ciqNoShare); - } - } - // Combining ".sharing" and ".ciq-no-share" to display:none for selected elements - body.classList.add("sharing"); - - // explicitly set svg text-related attributes - var svgs = stx.chart.container.getElementsByTagName("svg"); - var svgOriginalSources = []; - var svgIndex = 0; - for (; svgIndex < svgs.length; svgIndex++) { - var svg = svgs[svgIndex]; - svgOriginalSources.push(svg.innerHTML); - inlineStyle(svg); - } - - // Safari does not support SVG pattern fills. So we skip optimization in html2canvas third party file. - // (we've modified the resizeImage() function to detect "iPad" in user agent) - - h2canvas(stx.chart.container, { - allowTaint: false, - logging: false, - width: params.width || null, - height: params.height || null, - backgroundColor: params.background || null, - useCORS: true - }) - .then(function (canvas) { - if (cb) { - //return the full canvas if the data param is not true - cb(null, params.data ? canvas.toDataURL("image/png") : canvas); - } - for (svgIndex = 0; svgIndex < svgs.length; svgIndex++) { - svgs[svgIndex].innerHTML = svgOriginalSources[svgIndex]; - } - body.classList.remove("sharing"); - }) - .catch(function (error) { - if (cb) cb(error); - for (svgIndex = 0; svgIndex < svgs.length; svgIndex++) { - svgs[svgIndex].innerHTML = svgOriginalSources[svgIndex]; - } - body.classList.remove("sharing"); - }); -} - -//Load HTML2Canvas dynamically. If html2canvas.min.js is already loaded (statically, webpacked or with require.js) then this will be skipped. -// HTML2Canvas is rather heavy which is why we provide the option to load dynamically. It isn't really necessary to load this until -// a user actually shares a chart. -function loadHTML2Canvas(cb) { - //Make sure HTML2Canvas is not already loaded - if (typeof html2canvas === "undefined") { - //If we have require, use it - if (typeof requirejs !== "undefined") { - try { - return requirejs(["html2canvas.min.js"], function (h2) { - h2canvas = h2; - return cb(); - }); - } catch (exception) { - console.warn( - "Require loading has failed, attempting to load html2canvas manually." - ); - } - } - - // if no require then load directly - CIQ.loadScript(getMyRoot() + "html2canvas.min.js", function () { - h2canvas = html2canvas; - return cb(); - }); - } else { - h2canvas = html2canvas; - return cb(); - } -} - -//Get the location of this file. Unbundled, this would be share.js. Bundled, this would be standard.js. When unbundled -//we need to walk back up out of advanced. When bundled we don't need a root because thirdparty should be a relative -//path. -//Set CIQ.Share.html2canvasLocation to completely override this logic. -function getMyRoot() { - if (CIQ.Share.html2canvasLocation) return CIQ.Share.html2canvasLocation; - var sc = document.getElementsByTagName("script"); - for (var idx = 0; idx < sc.length; idx++) { - var s = sc[idx]; - if (s.src && s.src.indexOf("share.js") > -1) { - return s.src.replace(/standard\/share\.js/, "") + "thirdparty/"; - } - } - return "js/thirdparty/"; -} - -/** - * Creates a png image of the current chart and everything inside the container associated with the chart when it was instantiated; including HTML. - * Elements outside the chart container will **NOT** be included. - * - * If widthPX and heightPX are passed in then the image will be scaled to the requested dimensions. - * - * It will dynamically try to load `js/thirdparty/html2canvas.min.js` if not already loaded. - * - * This function is asynchronous and requires a callback function. - * The callback will be passed a data object or canvas which can be sent to a server or converted to an image. - * - * Important Notes: - * - **This method will rely on Promises. If your browser does not implement Promises, be sure to include a polyfill.** - * - * - **This method does not always work with React or Safari** - * - * - **Canvases can only be exported if all the contents including CSS images come from the same domain, - * or all images have cross origin set properly and come from a server that supports CORS; which may or may not be possible with CSS images.** - * - * - **When using the charts from `file:///`, make sure to include `html2canvas` statically instead of allowing this method to load it dynamically.** - *
Example: - *
`` - * - * @param {object} stx Chart object - * @param {object} [params] Parameters to describe the image. - * @param {number} [params.widthPX] Width of image to create. If passed then params.heightPX will adjust to maintain ratio. - * @param {number} [params.heightPX] Height of image to create. If passed then params.widthPX will adjust to maintain ratio. - * @param {string} [params.imageType] Specifies the file format your image will be output in. The dfault is PNG and the format must be suported by your browswer. - * @param {Array} [params.hide] Array of strings; array of the CSS selectors of the DOM elements to hide, before creating a PNG - * @param {Function} cb Callback when image is available fc(data) where data is the serialized image object - * @memberOf CIQ.Share - * @since - * - 3.0.0 Function signature changed to take parameters. - * - 4.0.0 Addition of `parameters.hide`. - * @version ChartIQ Advanced Package plug-in - */ -CIQ.Share.createImage = function (stx, params, cb) { - var args = [].slice.call(arguments); - cb = args.pop(); - //imageType is in its location so developers don't need to change their current code. - if (params === null || typeof params != "object") - params = { widthPX: args[1], heightPX: args[2], imageType: args[3] }; - var widthPX = params.widthPX; - var heightPX = params.heightPX; - var imageType = params.imageType; - - // Set background for any part of canvas that is currently transparent NO LONGER NECESSARY???? - // CIQ.fillTransparentCanvas(stx.chart.context, stx.containerColor, stx.chart.canvas.width, stx.chart.canvas.height); - - // We use style height/width instead of the canvas width/height when the backing store is 2x on retina screens - var renderedHeight = stx.chart.canvas.height; - var renderedWidth = stx.chart.canvas.width; - if (stx.chart.canvas.style.height) { - renderedHeight = CIQ.stripPX(stx.chart.canvas.style.height); - renderedWidth = CIQ.stripPX(stx.chart.canvas.style.width); - } - if (widthPX && heightPX) { - renderedHeight = heightPX; - renderedWidth = widthPX; - } else if (heightPX) { - renderedWidth = - stx.chart.canvas.width * (renderedHeight / stx.chart.canvas.height); - } else if (widthPX) { - renderedWidth = widthPX; - renderedHeight = - stx.chart.canvas.height * (widthPX / stx.chart.canvas.width); - } - //var totalHeight=renderedHeight; - var imageResult = imageType ? "image/" + imageType : "image/png"; - // Render the canvas as an image - var shareImage = document.createElement("img"); - shareImage.onload = function () { - // Print the image on a new canvas of appropriate size - CIQ.Share.FullChart2PNG( - stx, - { - image: this, - width: renderedWidth, - height: renderedHeight, - hide: params.hide - }, - function (err, canvas) { - if (err) { - console.warn("Error producing canvas snapshot: " + err); - } else { - try { - cb(canvas.toDataURL(imageResult)); // return the data - } catch (e) { - console.warn( - "Safari devices do not handle CORS enabled images. Using the charts' canvas as a fallback." - ); - cb(shareImage.src); - } - } - } - ); - }; - shareImage.src = stx.chart.canvas.toDataURL(imageResult); -}; - -/** - * Uploads an image to a server. The callback will take two parameters. The first parameter is an error - * condition (server status), or null if there is no error. The second parameter (if no error) will contain - * the response from the server. - * 'payload' is an optional object that contains meta-data for the server. If payload exists then the image will be added as a member of the payload object, otherwise an object will be created - * 'dataImage' should be a data representation of an image created by the call canvas.toDataURL such as is returned by CIQ.Share.createImage - * If you are getting a status of zero back then you are probably encountering a cross-domain ajax issue. Check your access-control-allow-origin header on the server side - - * @param {string} dataImage Serialized data for image - * @param {string} url URL to send the image - * @param {object} [payload] Any additional data to send to the server should be sent as an object. - * @param {Function} cb Callback when image is uploaded - * @memberOf CIQ.Share - * @version ChartIQ Advanced Package plug-in - */ -CIQ.Share.uploadImage = function (dataImage, url, payload, cb) { - if (!payload) payload = {}; - payload.image = dataImage; - var valid = CIQ.postAjax(url, JSON.stringify(payload), function ( - status, - response - ) { - if (status != 200) { - cb(status, null); - return; - } - cb(null, response); - }); - if (!valid) cb(0, null); -}; - -/** - * Convenience function that serves as a wrapper for createImage and uploadImage. - * It will create an image using the default parameters. If you wish to customize the image you must use {@link CIQ.Share.createImage} separately and then call {@link CIQ.Share.uploadImage}. - * @param {object} stx Chart Object - * @param {object} [override] Parameters that overwrite the default hosting location from https://share.chartiq.com to a custom location. - * @param {object} [override.host] - * @param {object} [override.path] - * @param {function} cb Callback when the image is uploaded. - * @memberof CIQ.Share - * @since 2015-11-01 - * @example - * // here is the exact code this convenience function is using - CIQ.Share.createImage(stx, {}, function(imgData){ - var id=CIQ.uniqueID(); - var host="https://share.chartiq.com"; - var url= host + "/upload/" + id; - if(override){ - if(override.host) host=override.host; - if(override.path) url=host+override.path+"/"+id; - } - var startOffset=stx.getStartDateOffset(); - var metaData={ - "layout": stx.exportLayout(), - "drawings": stx.exportDrawings(), - "xOffset": startOffset, - "startDate": stx.chart.dataSegment[startOffset].Date, - "endDate": stx.chart.dataSegment[stx.chart.dataSegment.length-1].Date, - "id": id, - "symbol": stx.chart.symbol - }; - var payload={"id": id, "image": imgData, "config": metaData}; - CIQ.Share.uploadImage(imgData, url, payload, function(err, response){ - if(err!==null){ - CIQ.alert("error sharing chart: ",err); - }else{ - cb(host+response); - } - }); - // end sample code to upload image to a server - }); - * - */ -CIQ.Share.shareChart = function (stx, override, cb) { - CIQ.Share.createImage(stx, {}, function (imgData) { - var id = CIQ.uniqueID(); - var host = "https://share.chartiq.com"; - var url = host + "/upload/" + id; - if (override) { - if (override.host) host = override.host; - if (override.path) url = host + override.path + "/" + id; - } - var startOffset = stx.getStartDateOffset(); - var metaData = { - layout: stx.exportLayout(), - drawings: stx.exportDrawings(), - xOffset: startOffset, - startDate: stx.chart.dataSegment[startOffset].Date, - endDate: stx.chart.dataSegment[stx.chart.dataSegment.length - 1].Date, - id: id, - symbol: stx.chart.symbol - }; - var payload = { id: id, image: imgData, config: metaData }; - CIQ.Share.uploadImage(imgData, url, payload, function (err, response) { - if (err !== null) { - CIQ.alert("error sharing chart: ", err); - } else { - cb(host + response); - } - }); - // end sample code to upload image to a server - }); -}; - -}; - - -let __js_standard_span_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -/** - * Used directly by {@link CIQ.ChartEngine#setRange} or indirectly by {@link CIQ.ChartEngine#loadChart} - * - * @typedef {Object} CIQ.ChartEngine~RangeParameters - * @property {Date} [dtLeft] Date to set left side of the chart - * @property {Date} [dtRight] Date to set right side of the chart - * @property {number} [padding=0] Whitespace padding in pixels to apply to the right side of the chart after sizing for date range. - * @property {CIQ.ChartEngine.Chart} [chart] Which chart, defaults to "chart" - * @property {boolean} [goIntoFuture=false] set the right side of the chart to be in the future - * @property {boolean} [goIntoPast=false] set the left side of the chart to be in the past - * @property {CIQ.ChartEngine~PeriodicityParameters} [periodicity] Override a specific periodicity combination to use with the range - * @property {number} [pixelPerBar] override automatic candle width calculations - * @property {boolean} [dontSaveRangeToLayout=false] skip saving the range in the layout - * @property {boolean} [forceLoad=false] a complete load (used by loadChart) - */ - -/** - * Sets a chart to the requested date range. - * - * By default, the **Minimum Width** for a bar is `1px`. As such, there may be times when the requested data will not all fit on the screen, even though it is available. - * See {@link CIQ.ChartEngine#minimumCandleWidth} for instructions on how to override the default to allow more data to display. - * - * When a quotefeed is attached to the chart (ver 04-2015 and up), and not enough data is available in masterData to render the requested range, setRange will request more from the feed. - * Also, if no periodicity (params.periodicity) is supplied in the parameters, **it may override the current periodicity** and automatically choose the best periodicity to use for the requested range using the {@link CIQ.ChartEngine#dynamicRangePeriodicityMap} when {@link CIQ.ChartEngine#autoPickCandleWidth} is enabled, - * or the use of the {@link CIQ.ChartEngine#staticRangePeriodicityMap} object when {@link CIQ.ChartEngine#autoPickCandleWidth} is **NOT** enabled. - * So depending on your UI, **you may need to use the callback to refresh the periodicity displayed on your menu**. - * - * Therefore, if you choose to let setRange set the periodicity, you should **not** call setPeriodicity before or after calling this method. - * - * **For details on how this method can affect the way daily data is rolled up, see {@link CIQ.ChartEngine#createDataSet}** - * - * **If the chart is in `tick` periodicity, the periodicity will be automatically selected even if one was provided because in `tick` periodicity we have no way to know how many ticks to get to fulfill the requested range.** - * - * If there is no quotefeed attached (or using a version prior to 04-2015), then setRange will use whatever data is available in the masterData. So you must ensure you have preloaded enough to display the requested range. - * - * This function must be called after loadChart() creates a dataSet. - * - * **Layout preservation and the range** - *
The selected range will be recorded in the chart {@link CIQ.ChartEngine#layout} when it is requested through {@link CIQ.ChartEngine#loadChart}, or when you call setRange directly. - *
It is then used in {@link CIQ.ChartEngine#importLayout} and {@link CIQ.ChartEngine#loadChart} to reset that range, until a new range is selected. - * - * @param {CIQ.ChartEngine~RangeParameters} params Parameters for the request - * @param {Date} [params.dtLeft] Date to set left side of chart. If no left date is specified then the right edge will be flushed, and the same interval and period will be kept causing the chart to simply scroll to the right date indicated.
**Must be in the exact same time-zone as the `masterdata`.** See {@link CIQ.ChartEngine#setTimeZone} and {@link CIQ.ChartEngine#convertToDataZone} for more details.
If the left date is not a valid market date/time, the next valid market period forward will be used. - * @param {Date} [params.dtRight] Date to set right side of chart. Defaults to right now.
**Must be in the exact same time-zone as the `masterdata`.** See {@link CIQ.ChartEngine#setTimeZone} and {@link CIQ.ChartEngine#convertToDataZone} for more details.
If the right date is not a valid market date/time, the next valid market period backwards will be used. - * @param {number} [params.padding] Whitespace padding in pixels to apply to right side of chart after sizing for date range. If not present then 0 will be used. - * @param {CIQ.ChartEngine.Chart} [params.chart] Which chart, defaults to "chart" - * @param {boolean} [params.goIntoFuture] If true then the right side of the chart will be set into the future if dtRight is greater than last tick. See {@link CIQ.ChartEngine#staticRange} if you wish to make this your default behavior. - * @param {boolean} [params.goIntoPast] If true then the left side of the chart will be set into the past if dtLeft is less than first tick. See {@link CIQ.ChartEngine#staticRange} if you wish to make this your default behavior. - * @param {CIQ.ChartEngine~PeriodicityParameters} [params.periodicity] Override a specific periodicity combination to use with the range. Only available if a quoteFeed is attached to the chart. Note: if the chart is in tick periodicity, the periodicity will be automatically selected even if one was provided because in tick periodicity we have no way to know how many ticks to get to fulfill the requested range. If used, all 3 elements of this object must be set. - * @param {Number} params.periodicity.period Period as used by {@link CIQ.ChartEngine#setPeriodicity} - * @param {string} params.periodicity.interval An interval as used by {@link CIQ.ChartEngine#setPeriodicity} - * @param {string} params.periodicity.timeUnit A timeUnit as used by {@link CIQ.ChartEngine#setPeriodicity} - * @param {Number} [params.pixelsPerBar] Optionally override this value so that the auto-periodicity selected chooses different sized candles. - * @param {boolean} [params.dontSaveRangeToLayout] If true then the range won't be saved to the layout. - * @param {boolean} [params.forceLoad] Forces a complete load (used by loadChart) - * @param {Function} [cb] Callback method. Will be called with the error returned by the quotefeed, if any. - * @memberOf CIQ.ChartEngine - * @since - * - 04-2015 Added `params.rangePeriodicityMap` and `params.periodicity` as well as automatic integration with {@link quotefeed}. - * - 2016-05-10 Deprecated `params.rangePeriodicityMap` in favor of new automatic algorithm. - * - m-2016-12-01 Restored logic to reference a periodicity map. Similar to previous `params.rangePeriodicityMap`. See {@link CIQ.ChartEngine#staticRangePeriodicityMap} for details. - * - m-2016-12-01 Modified automatic periodicity algorithm. See {@link CIQ.ChartEngine#dynamicRangePeriodicityMap} and {@link CIQ.ChartEngine#autoPickCandleWidth} for details. - * - 4.0.0 Now uses {@link CIQ.ChartEngine#needDifferentData} to determine if new data should be fetched. - * - 4.0.0 No longer defaulting padding to current value of `preferences.whiteSpace`. - * - 5.1.0 Added `params.dontSaveRangeToLayout`. - * - 5.1.0 The selected range will be recorded in the chart {@link CIQ.ChartEngine#layout} when it is requested through {@link CIQ.ChartEngine#loadChart}, or when you call setRange directly. - * - 5.2.0 `params.forceLoad` is now an option to force loading of new data. - * @example - * Display all of the available data in the current chart periodicity. - * stxx.setRange({ - * dtLeft: stxx.chart.dataSet[0].DT, - * dtRight: stxx.chart.dataSet[stxx.chart.dataSet.length - 1].DT, - * periodicity:{period:stxx.layout.periodicity,interval:stxx.layout.interval,timeUnit:stxx.layout.timeUnit} - * }); - */ -CIQ.ChartEngine.prototype.setRange = function (params, cb) { - if (CIQ.isEmpty(params)) { - // Handle legacy argument list implementation - params = { - dtLeft: arguments[0], - dtRight: arguments[1], - padding: arguments[2], - chart: arguments[3] - }; - cb = arguments[4]; - } - if (this.staticRange) { - params.goIntoPast = params.goIntoFuture = true; - } - - if (!params.chart) params.chart = this.chart; - if (typeof params.padding == "undefined") { - // if no whitespace sent in, maintain existing ( different than sending 0 which will set to no whitespace ) - params.padding = 0; - } - var dontChangePeriodicity = false; - var chart = params.chart; - var lt = - typeof params.dtLeft === "string" ? new Date(params.dtLeft) : params.dtLeft; // just in case a string date is passed in - var rt = new Date(); - if (params.dtRight) - rt = - typeof params.dtRight === "string" - ? new Date(params.dtRight) - : params.dtRight; - var iter; - if (!lt) { - // If no left date then we want to just flush the right edge, and keep the same interval,period - iter = this.standardMarketIterator(rt, null, chart); - lt = iter.previous(chart.maxTicks); - if (!params.periodicity) dontChangePeriodicity = true; - } - chart.inflectionPoint = lt; // this is where consolidation originates in either direction - - this.layout.range = { dtLeft: lt, dtRight: rt }; - - var self = this; - function showTheRange(err) { - if (typeof err == "undefined") err = null; - - var l = 0, - r = 0; - var todaysDate = new Date(); - var base = params.base; - var periodicity = params.periodicity; - var layout = self.layout; - - if ( - params.goIntoFuture && - (!chart.masterData.length || - lt > chart.masterData[chart.masterData.length - 1].DT) - ) { - // we're displaying entirely in the future, fill gap - var leftmost = chart.masterData.length - ? chart.masterData.pop() - : { DT: lt }; - var gapData = self.doCleanupGaps([leftmost, { DT: rt }], chart, { - cleanupGaps: "gap", - noCleanupDates: true - }); - self.setMasterData(chart.masterData.concat(gapData), chart, { - noCleanupDates: true - }); - self.createDataSet(null, null, { appending: true }); - } - var dataSet = chart.dataSet; - var dsLength = dataSet.length; - - if (!dataSet || dsLength === 0) { - if (cb) cb(err); - return; - } - - var leftBar; - // range is day and interval is day - if (base === "day" && periodicity && periodicity.interval === "day") { - var multiplier = params.multiplier; - // left bar is how many days the range is, or beginning of dataset - l = dsLength < multiplier ? 0 : dsLength - multiplier; - r = dsLength - 1; - } - // if intraday range and last day in dataSet is older than current day then show previous day's data - else if ( - base === "today" && - dataSet[dsLength - 1].DT.getDate() < todaysDate.getDate() - ) { - var leftDT = new Date(dataSet[dsLength - 1].DT.getTime()); - var rightDT = leftDT.getTime(); // copy starting time - leftBar = 0; - - for (var d = dsLength - 1; d >= 0; d--) { - if (dataSet[d] && dataSet[d].DT.getDate() != leftDT.getDate()) { - leftDT = new Date(+dataSet[d + 1].DT); - leftBar = d + 1; - break; - } - } - l = leftBar; - r = dsLength - 1; - } else { - if ( - params.base != "all" && - (lt.getTime() >= dataSet[0].DT.getTime() || params.goIntoPast) - ) { - l = self.tickFromDate(lt, chart, null, true); - } else { - l = 0; - } - if ( - params.base != "all" && - (rt.getTime() <= dataSet[dsLength - 1].DT.getTime() || - params.goIntoFuture) - ) { - r = self.tickFromDate(rt, chart); - if (r > dsLength - 1) r--; // do not include tick from any end date - } else { - r = dsLength - 1; - } - } - var ticks = r - l + 1; - - if (ticks < 1) { - if (cb) cb(err); - return; - } - - var padding = params.padding || 0; - if (r < dsLength - 1) padding = 0; - //var barsHaveWidth=self.mainSeriesRenderer && self.mainSeriesRenderer.barsHaveWidth; - var newCandleWidth = (chart.width - padding) / ticks; //*(barsHaveWidth?1:(1-1/(2*ticks))); // deduct 1/2 the proposed candlewidth for the micropixel offset for line type charts - self.setCandleWidth(newCandleWidth, chart); - chart.scroll = ticks - (r - dsLength) - 1; - self.micropixels = 1; // this is done to allow crosshairs over first tick when candles are small - // line-type charts go center-to-center in the data point space, so we end up with 1/2 a candle empty on the left and the right.. - //if(!barsHaveWidth) self.micropixels+=newCandleWidth/2; // line charts display to middle of candle - for (var p in self.panels) self.calculateYAxisMargins(self.panels[p].yAxis); - - // only save the range for direct calls to setRange - if (!params.dontSaveRangeToLayout) { - delete params.chart; // having the chart in there causes an issue with cloning - delete layout.setSpan; // range and setSpan are mutually exclusive - layout.range = params; // save the range in the layout to be able to restore - } else { - // setRange called from setSpan, remove range from layout - delete layout.range; - } - - self.draw(); - self.changeOccurred("layout"); - if (!dontChangePeriodicity) { - self.dispatch("periodicity", { - stx: self, - differentData: needDifferentData, - prevPeriodicity: { - interval: previousInterval, - periodicity: previousPeriodicity, - timeUnit: previousTimeUnit - } - }); - } - if (cb) cb(err); - } - - var loadMoreCount = 0; // safety valve to eliminate infinite loop - function loadTheRange(err) { - if (err && loadMoreCount === 0) { - // change the periodicity, scroll and candle width back to original chart values - // if our initial fetch from the quotedriver failed. - chart.scroll = previousScroll; - self.setCandleWidth(previousCandleWidth); - self.layout.interval = previousInterval; - self.layout.periodicity = previousPeriodicity; - self.layout.timeUnit = previousTimeUnit; - if (cb) cb(err); - return; - } - loadMoreCount++; - if (loadMoreCount > 10) { - console.log( - "CIQ.ChartEngine.setRange(): Too many loads (10) from server. Stopping. Check periodicity logic." - ); - showTheRange(); - return; - } - // Removed - we should never need to fetch more data after requesting a span - // Moreover, this created issues when setting a date only and fetching an intraday span - - // code was being entered anyway since the masterData[0] was market open and lt was midnight. - /*if(chart.moreAvailable && chart.masterData[0] && chart.masterData[0].DT>lt){ - self.quoteDriver.checkLoadMore(chart, true, false, function(err){ - if(!err) - loadTheRange(); - else - showTheRange(err); // if there was an error on a subsequent fetch, then show as much as we were able to get. - },true); - }else{*/ - showTheRange(); - //} - } - - function estimateMaxTicks(rtMS, ltMS, interval, period, timeUnit, dontRoll) { - // how many ticks do we need at the requested periodicity to fill the screen - var ticks = 0; - var ms = rtMS - ltMS; - if (CIQ.ChartEngine.isDailyInterval(interval)) { - if (interval == "month") { - ticks = ms / CIQ.MONTH / period; - } else if (interval == "week") { - ticks = ms / CIQ.WEEK / period; - } else { - ticks = ms / CIQ.DAY / period; - } - } else { - if (!isNaN(interval)) { - if (timeUnit == "millisecond") ticks = ms / (period * interval); - else if (timeUnit == "second") - ticks = ms / CIQ.SECOND / (period * interval); - else ticks = ms / CIQ.MINUTE / (period * interval); - } - } - return Math.round(ticks); // rough estimation... - } - - if (this.quoteDriver) { - var intervalToUse, periodToUse, timeUnitToUse; - if (dontChangePeriodicity) { - intervalToUse = this.layout.interval; - timeUnitToUse = this.layout.timeUnit; - periodToUse = this.layout.periodicity; - } else if (params.periodicity) { - // If the caller specifies the periodicity then we use that - var internalPeriodicity = CIQ.cleanPeriodicity( - params.periodicity.period, - params.periodicity.interval, - params.periodicity.timeUnit - ); - intervalToUse = internalPeriodicity.interval; - timeUnitToUse = internalPeriodicity.timeUnit; - periodToUse = internalPeriodicity.period; - } else { - // Set the periodicity according to the staticRangePeriodicityMap - // This will check the milliseconds of each range and choose the proper width - var rangeInMS = rt.getTime() - lt.getTime(); - if (!this.autoPickCandleWidth.turnOn) { - var periodicityMap = this.staticRangePeriodicityMap; - - var entryToUse = null; - // Cycle through the periodicity map looking for the closest fit - for (var i = 0; i < periodicityMap.length; i++) { - var mapEntry = periodicityMap[i]; - - if (rangeInMS / mapEntry.rangeInMS < 1.001) { - // inexact due to quote updates - entryToUse = mapEntry; - break; - } - } - intervalToUse = entryToUse.interval; - periodToUse = entryToUse.periodicity; - timeUnitToUse = entryToUse.timeUnit; - } else { - // Calculate the best periodicity dynamically according to the intervals - // set in dynamicRangePeriodicityMap - var pixelsPerBar = 0; - - // use candlewidth set in the chart - if (this.autoPickCandleWidth.candleWidth) { - pixelsPerBar = this.autoPickCandleWidth.candleWidth; - } - // else choose candlewidth according to chart type - else { - pixelsPerBar = this.chart.barsHaveWidth ? 5 : 2; - } - - var numBars = chart.width / pixelsPerBar; - - var possibleIntervals = this.dynamicRangePeriodicityMap; - - // default - intervalToUse = possibleIntervals[0].interval; - periodToUse = 1; - - var numBarsLastInterval; - for (var j = 0; j < possibleIntervals.length; j++) { - var numBarsThisInterval = rangeInMS / possibleIntervals[j].rangeInMS; - if (numBarsThisInterval < numBars) { - if (possibleIntervals[j - 1]) { - intervalToUse = possibleIntervals[j - 1].interval; - timeUnitToUse = possibleIntervals[j - 1].timeUnit; - periodToUse = Math.ceil(numBarsLastInterval / numBars); - } else { - intervalToUse = possibleIntervals[j].interval; - timeUnitToUse = possibleIntervals[j].timeUnit; - periodToUse = 1; - } - break; - } - numBarsLastInterval = numBarsThisInterval; - } - } - } - - // maintain the previous values just in case an error is thrown when getting new data - var previousScroll = this.chart.scroll; - var previousCandleWidth = this.layout.candleWidth; - var previousInterval = this.layout.interval; - var previousPeriodicity = this.layout.periodicity; - var previousTimeUnit = this.layout.timeUnit; - - // to prevent multiple fetches trying to get enough ticks for the selected range; - // maxticks,scroll and candleWidth are used in CIQ.ChartEngine.Driver.barsToFetch and checkLoadMore() to deduce the number of ticks to fill the screen. - // So we need to set it here to prevent us from using the pre-setRange values which are not going to be right. - // these are estimated, for the fetch, but will be properly recalculated by showTheRange(); - this.chart.scroll = this.chart.maxTicks = estimateMaxTicks( - rt.getTime(), - lt.getTime(), - intervalToUse, - periodToUse, - timeUnitToUse, - this.dontRoll - ); - this.layout.candleWidth = this.chart.width / this.chart.maxTicks; - - // logic to determine whether we have the right interval for what is needed - var needDifferentData = this.needDifferentData({ - period: periodToUse, - interval: intervalToUse, - timeUnit: timeUnitToUse - }); - - // if we need data from before what we have, fetch new data - if ( - Object.keys(this.chart.endPoints).length && - (this.chart.endPoints.begin > lt || this.chart.endPoints.end < rt) - ) - needDifferentData = true; - - if ( - !this.chart.masterData || - !this.chart.masterData.length || - needDifferentData || - params.forceLoad - ) { - this.layout.interval = intervalToUse; - this.layout.periodicity = periodToUse; - this.layout.timeUnit = timeUnitToUse; - if (!this.layout.timeUnit) { - if (CIQ.ChartEngine.isDailyInterval(this.layout.interval)) - this.layout.timeUnit = null; - else if (this.layout.interval == "second") - this.layout.timeUnit = "second"; - // backward compatibility with heatmap - else if (this.layout.interval != "tick") - this.layout.timeUnit = "minute"; - } - var qparams = { - symbol: chart.symbol, - symbolObject: chart.symbolObject, - chart: chart, - nodraw: true - }; - - if (this.layout.interval == "tick") { - // for 'tick' periodicity we have to request a specific range instead of # of ticks, - //since we can never be sure how many ticks will be in a particular range. - qparams.startDate = lt; - qparams.endDate = rt; - } - - if (!this.displayInitialized) qparams.initializeChart = true; //This does not mean loadChart() - - var behaviorParams = { - symbol: chart.symbol, - symbolObject: chart.symbolObject, - interval: this.layout.interval - }; - if ( - (behaviorParams.interval == "month" || - behaviorParams.interval == "week") && - !this.dontRoll - ) { - behaviorParams.interval = "day"; - } - var minOffset = Math.max( - this.quoteDriver.getQuoteFeed(behaviorParams).behavior.bufferSize + 50, - 200 - ); // ensure we have some data off page for continuity sake and ease of scrolling, while also accounting for about 50 possible gaps in the buffer zone. Otherwise we end up paginating if there's a gap. - iter = this.standardMarketIterator(lt, null, chart); - qparams.startDate = new Date(iter.previous(minOffset).getTime()); - - iter = this.standardMarketIterator(rt, null, chart); - qparams.endDate = new Date(iter.next(minOffset).getTime()); - if (qparams.endDate < Date.now()) this.isHistoricalModeSet = true; - - this.clearCurrentMarketData(this.chart); - clearTimeout(this.streamParameters.timeout); - this.quoteDriver.newChart(qparams, loadTheRange); - } else { - if ( - this.layout.interval != intervalToUse || - this.layout.periodicity != periodToUse || - this.layout.timeUnit != timeUnitToUse || - !this.chart.dataSegment || - !this.chart.dataSegment[0] || - this.chart.dataSegment[0].DT != chart.inflectionPoint - ) { - this.layout.interval = intervalToUse; - this.layout.periodicity = periodToUse; - this.layout.timeUnit = timeUnitToUse; - this.createDataSet(); - } - loadTheRange(); - } - } else { - showTheRange(); - } -}; - -/** - * Used directly by {@link CIQ.ChartEngine#setSpan} or indirectly by {@link CIQ.ChartEngine#loadChart} - * - * @typedef {Object} CIQ.ChartEngine~SpanParameters - * @property {string} base span to show; valid values are "minute", "day", "week", "month", "year", "all", "ytd", or "today" - * @property {number} multiplier Number of base units to show - * @property {boolean} [maintainPeriodicity=false] do not calculate a new periodicity - * @property {number} [padding=0] whitespace in pixels to apply to the right side of the chart - * @property {boolean} [forceLoad=false] force a complete load (used by loadChart) - * @property {CIQ.ChartEngine.Chart} [chart] Which chart, defaults to "chart" - */ - -/** - * Sets the chart to display the requested time span. - * - * By default, the **minimum width** for a bar is `1px`. As such, there may be times when the requested data will not all fit on the screen, even though it is available. - * See {@link CIQ.ChartEngine#minimumCandleWidth} for instructions on how to override the default to allow more data to display. - * - * setSpan makes use of {@link CIQ.ChartEngine#setRange} by converting the span requested into a date range. - * All parameters in setSpan will be sent into setRange (except if 'all' is requested), so you can pre-load things like `params.periodicity` in setSpan for setRange to use. - * - * Example: - *
- * stxx.setSpan({
- * 	multiplier: 5,
- * 	base: "day",
- * 	padding: 30,
- * 	// pre load a parameter for setRange
- * 	periodicity: {
- * 		period: 1,
- * 		interval: 5,
- * 		timeUnit: 'minute'
- * 	}
- * });
- * 
- * - * Just keep in mind that if passing `periodicity.period` , `periodicity.timeUnit` and `periodicity.interval` to be used in {@link CIQ.ChartEngine#setRange} , then **DO NOT** set `maintainPeriodicity`. Otherwise, the requested periodicity will be ignored. - * - * If a quotefeed is attached to the chart (ver 04-2015 and up), setSpan will attempt to gather more data from the feed (IF NEEDED) to fulfill the requested range AND **may override the periodicity** to provide the most optimal chart display. - * So depending on your UI, **you may need to use the callback to refresh the periodicity displayed on your menu**. - * Please see {@link CIQ.ChartEngine#setRange} and {@link CIQ.ChartEngine#displayAll} for complete details on how the periodicity is calculated. - *
If there is no quotefeed attached (or using a version prior to 04-2015), then setStan will use whatever data is available in the masterData. So you must ensure you have preloaded enough to display the requested range. - * - * Calling {@link CIQ.ChartEngine#setPeriodicity} immediately after setting a span may cause all of the data to be re-fetched at a different periodicity than the one used by the requested span. Once you have set your initial periodicity for the chart, there is no need to manually change it when setting a new span unless you are using the `params.maintainPeriodicity` flag; in which case you want to call `setPeriodicity` **before** you set the span, so the setSpan call will use the pre-set periodicity. - *
Setting a span to `params.multiplier:7` `params.base:'days'` or `params.multiplier:1` `params.base:'week'`, for example, is really the same thing; same span of time. If what you are trying to do is tell the chart how you want the raw data to be fetched, that is done with {@link CIQ.ChartEngine#setPeriodicity} or by letting setSpan figure it out as described above. - *
Remember that by default, weekly and monthly data is calculated using daily raw ticks. If your feed returns data already rolled up in monthly or weekly ticks, you can override this behavior by setting `stxx.dontRoll` to `true` ( see {@link CIQ.ChartEngine#dontRoll} and the {@tutorial Periodicity} tutorial) - * - * This function must be called **after** loadChart() completes and creates a dataSet, or together with loadChart() by setting the proper parameter values. - * If calling separately right after loadChart(), be sure to call it in the loadChart() callback!. - * See example in this section and {@link CIQ.ChartEngine#loadChart} for more details and compatibility with your current version. - * - * Be aware that {@link CIQ.ChartEngine.Chart#allowScrollPast} and {@link CIQ.ChartEngine.Chart#allowScrollFuture} must be set to true if you wish to display "white space" in cases where the range requested is larger than the available data. - * Especially when using "today" and the base. - * - * **Layout preservation and the span** - *
If `maintainPeriodicity` is not set, the selected span will be recorded in the chart {@link CIQ.ChartEngine#layout} when it is requested through {@link CIQ.ChartEngine#loadChart}, or when you call setSpan directly. - *
It is then used in {@link CIQ.ChartEngine#importLayout} and {@link CIQ.ChartEngine#loadChart} to reset that span, until a new periodicity is selected. - * - * **Note:** versions prior to '2015-05-01' must use the legacy arguments : setSpan(multiplier, base, padding, char,useMarketTZ,cb), and related example in this section. - * - * @param {CIQ.ChartEngine~SpanParameters} params Parameter for the function - * @param {number} params.multiplier Number of base units to show. To show 3 weeks of data, for example, set this to 3 and `params.base` to 'week'. - * @param {string} params.base The base span to show. "minute", "day", "week", "month", "year", "all", "ytd" or "today". - *

Except when using "today", this base will be combined with the multiplier. Example 2 days, 4 months. - *

**Spans are market hours sensitive**, so if you ask for 1 hour, for example, at the time the markets are close, - * the span will find the last time the markets where open for the active symbol, and include the last market hour in the span. - * It will also exclude days when the market is closed. - * - If 'all' data is requested, {@link CIQ.ChartEngine#displayAll} is called first to ensure all quotefeed data for that particular instrument is loaded. Note that 'all' will display the data in `monthly` periodicity unless otherwise specified. Please note that "all" will attempt to load all of the data the quotefeed has available for that symbol. Use this span with caution. - * - If 1 'day' is requested --on market days--the chart will start from the same time on the previous market day, which may be over a weekend. Example from 3:30 PM Friday to 3:30 PM Monday, if the market is closed Saturday and Sunday. - * - If 1 'day' is requested --on weekends and holidays-- or if 2 or more days are requested, the chart will always start from market open of prior days. - * - If 'today' is requested --during the market day -- the chart will display the current market day but, if {@link CIQ.ChartEngine.Chart#allowScrollFuture} is also enabled, extend the chart all the way to market close (as per market hours set in the active market definition - see {@link CIQ.Market}) - * - If 'today' is requested --before the market is open --the chart will display the previous market day. - * - If 'today' is requested --after the current market day closes --the chart will display the current market day. - * @param {boolean} [params.maintainPeriodicity] If set to true, it will maintain the current periodicity for the chart instead of trying to select the most optimal periodicity for the selected range. See {@link CIQ.ChartEngine#setRange} for details. - *
**Note:** if the chart is in `tick` periodicity, the periodicity will be automatically selected even if it was requested to be maintained because in `tick` periodicity we have no way to know how many ticks to get to fulfill the requested range. - * @param {number} [params.padding] Whitespace padding in pixels to apply to right side of chart after sizing for date range. If not set will default whitespace to 0. - * @param {boolean} [params.forceLoad] Forces a complete load (used by loadChart) - * @param {CIQ.ChartEngine.Chart} [params.chart] Which chart, defaults to "chart" - * @param {Function} cb Optional callback - * @memberOf CIQ.ChartEngine - * @example - * // this displays 5 days. It can be called anywhere including buttons on the UI - * stxx.setSpan ({ - * multiplier: 5, - * base: "day", - * padding: 30 - * }); - * @example - * // using embedded span requirements on a loadChart() call. - * stxx.loadChart({symbol: newSymbol, other: 'stuff'}, { - * span: { - * base: 'day', - * multiplier: 2 - * }, - * }, callbackFunction()); - * @example - * // Calling setSpan in the loadChart() callback to ensure synchronicity. - * stxx.loadChart({symbol: newSymbol, other: 'stuff'}, function() { - * stxx.setSpan({ - * multiplier: 5, - * base: "day", - * padding: 30 - * }); - * }); - * @since - * - 04-2015 Added "all", "today", "ytd" and automatic integration with {@link quotefeed}. - * - 15-07-01 Changed `params.period` to `params.multiplier` for clarity. - * - 15-07-01 Changed `params.interval` to `params.base` for clarity. - * - 05-2016-10 Saves the set span in stxx.layout to be restored with the layout between sessions. - * - 4.0.3 Saves all parameters of the requested span in stxx.layout to be restored with the layout between sessions. Previously only `multiplier` and `base` were saved. - * - 5.0.0 When 1 'day' is requested data displayed will differ if current day is market day or the market is closed to ensure the span will have enough data. - */ -CIQ.ChartEngine.prototype.setSpan = function (params, cb) { - var period = arguments[0]; - var interval = arguments[1]; - var padding = arguments[2]; - var chart = arguments[3]; - - if (typeof params == "object") { - period = params.period - ? params.period - : params.multiplier - ? params.multiplier - : 1; - interval = params.interval - ? params.interval - : params.base - ? params.base - : params.span - ? params.span - : params.period; - padding = params.padding; - chart = params.chart; - } else { - params = { - period: period, - interval: interval, - padding: padding, - chart: chart - }; - cb = arguments[5]; - } - // Do not force padding to 0 on setSpan - //if(!params.padding) params.padding=0; - - if (!chart) chart = this.chart; - var market = chart.market; - - interval = interval.toLowerCase(); - if (interval == "all") { - params.dontSaveRangeToLayout = true; - this.displayAll(params, cb); - return; - } - var iter; - var iterInterval = interval; - var iterPeriod = 1; - if (interval == "today") { - iterInterval = "day"; - } else if (interval == "year") { - iterInterval = "month"; - iterPeriod = 12; - } - - var parms_copy = CIQ.shallowClone(params); - - var iter_parms = { - begin: market.marketZoneNow(), - interval: iterInterval, - period: iterPeriod - }; - var leftDT = iter_parms.begin; - - function zeroDT(dt) { - dt.setHours(0); - dt.setMinutes(0); - dt.setSeconds(0); - dt.setMilliseconds(0); - return dt; - } - var isForex = CIQ.Market.Symbology.isForexSymbol(chart.symbol); - function forexAdjust(dt, advance) { - // The whole point of this function is to get a 1 day or today chart to start showing forex at 5pm the prior day instead of midnight, - // without breaking the whole market class in the process. - if (!isForex) return dt; - var forexOffset = 7; // 7 hours from open to midnight - if (advance) dt.setHours(dt.getHours() + forexOffset); - // get it to the next day if it's after 5pm - else { - // it's assumed dt time is midnight if code gets in here - dt.setHours(dt.getHours() - forexOffset); // start at 5pm prior trading day - if (!market.isMarketDate(dt)) dt.setDate(dt.getDate() - 2); // For the weekend - } - return dt; - } - if (interval === "ytd") { - leftDT = zeroDT(leftDT); - leftDT.setMonth(0); - leftDT.setDate(1); - } else if (interval === "month") { - leftDT = zeroDT(new Date()); - leftDT.setMonth(leftDT.getMonth() - period); - } else if (interval === "year") { - leftDT = zeroDT(new Date()); - leftDT.setFullYear(leftDT.getFullYear() - period); - } else if (interval === "week") { - leftDT = zeroDT(new Date()); - leftDT.setDate(leftDT.getDate() - period * 7); - } else if (interval === "day" && period == 1 && market.isMarketDay()) { - // Special case, 1 "day" --on market days-- will start from same time on previous market day - // 1 day in weekends and holidays or 2 or more days will always start from market open of prior days (last else) - var h = leftDT.getHours(); - var m = leftDT.getMinutes(); - var s = leftDT.getSeconds(); - var mm = leftDT.getMilliseconds(); - iter = market.newIterator(iter_parms); - leftDT = iter.previous(); - leftDT.setHours(h, m, s, mm); - leftDT = market._convertFromMarketTZ(leftDT); - } else if (interval === "today") { - iter_parms.begin = forexAdjust(leftDT, true); - // forward and then back will land us on the most current valid market day - iter = market.newIterator(iter_parms); - if ( - market.isOpen() || - market.getPreviousOpen().getDate() == leftDT.getDate() - ) { - // if market opened, go ahead a day (we'll go back a day right after) - iter.next(); - } - leftDT = iter.previous(); - forexAdjust(leftDT); - - parms_copy.goIntoFuture = true; - parms_copy.dtRight = new Date(+leftDT); - parms_copy.dtRight.setDate(leftDT.getDate() + 1); - parms_copy.dtRight = market._convertFromMarketTZ(parms_copy.dtRight); - - if (!isForex) { - leftDT.setHours(iter.market.zopen_hour); - leftDT.setMinutes(iter.market.zopen_minute); - leftDT.setSeconds(0); - } - - leftDT = market._convertFromMarketTZ(leftDT); - } else { - if (interval == "day") iter_parms.begin = forexAdjust(leftDT, true); - iter = market.newIterator(iter_parms); - if (period == 1) period++; - leftDT = iter.previous(period - 1); - if (interval == "day") - leftDT = market._convertFromMarketTZ(forexAdjust(leftDT)); - } - parms_copy.dtLeft = leftDT; - if (parms_copy.maintainPeriodicity) { - parms_copy.periodicity = {}; - parms_copy.periodicity.interval = this.layout.interval; - parms_copy.periodicity.period = this.layout.periodicity; - } - chart.spanLock = false; // unlock left edge - parms_copy.dontSaveRangeToLayout = true; // don't do certain things in setRange when being called from setSpan - var self = this; - this.setRange(parms_copy, function (err) { - self.layout.setSpan = params; - self.changeOccurred("layout"); - - if (interval == "today") { - chart.spanLock = true; // lock left edge of screen, in callback after we have fetched! - } - if (cb) cb(err); - }); -}; - -//@private -// Foobarred function. Does not handle today or all properly. Assumes daily data. Not called from anywhere. -CIQ.ChartEngine.prototype.getSpanCandleWidth = function (span) { - if (!span || !span.base || !span.multiplier) return; - var num = parseFloat(span.multiplier); - var base = span.base; - var now = new Date(); - var prev = new Date(); - if (base == "year") { - prev.setFullYear(prev.getFullYear() - num); - } else if (base == "month") { - prev.setMonth(prev.getMonth() - num); - } else if (base == "day") { - prev.setDate(prev.getDate() - num); - } else if (base == "week") { - prev.setDate(prev.getDate() - 7 * num); - } else if (base == "YTD") { - prev.setMonth(0); - prev.setDate(1); - } - var diff = (now.getTime() - prev.getTime()) / 1000 / 60 / 60 / 24; - diff = (diff * 5) / 7; - var candleWidth = this.chart.width / diff; - return candleWidth; -}; - -/** - * Sets a chart to display all data for a security. - * - * If no feed is attached, it will simply display all the data loaded in the present periodicity. - *
If the chart is driven by a QuoteFeed and no periodicity is requested, it will default to 'monthly'. - * It will then call QuoteDriver.loadAll() which makes multiple queries to ensure all data available from the quote feed is loaded. - * Once all the data is loaded, the chart will be set to cover that range using {@link CIQ.ChartEngine#setRange} - * @param {object} [params] Optional parameters in same format as {@link CIQ.ChartEngine#setSpan}. - * @param {Function} [cb] Callback, is called when chart is displayed. - * @since 04-2015 - * @memberOf CIQ.ChartEngine - */ -CIQ.ChartEngine.prototype.displayAll = function (params, cb) { - var { chart, layout } = this; - if (params && params.chart) chart = params.chart; - const self = this; - function displayTheResults() { - if (!chart.masterData || !chart.masterData.length) return; - var p = CIQ.clone(params); - p.dtLeft = chart.endPoints.begin.DT; - p.dtRight = chart.endPoints.end.DT; - // we already have the data, we just want to show it now. So make sure we maintain the periodicity so it won't fetch new one data - p.periodicity = {}; - p.periodicity.interval = layout.interval; - p.periodicity.period = layout.periodicity; - p.periodicity.timeUnit = layout.timeUnit; - self.setRange(p, function (err) { - self.layout.setSpan = { - base: params.base, - multiplier: params.multiplier - }; - self.changeOccurred("layout"); - for (var p in self.panels) - self.calculateYAxisMargins(self.panels[p].yAxis); - self.draw(); - if (cb) cb(err); - }); - } - function loadAllTheData(err) { - if (!err) self.quoteDriver.loadAll(chart, displayTheResults); - } - - // Case 1: no quoteFeed so display what we have - if (!this.quoteDriver) { - displayTheResults(); - return; - } - - var periodicity = params.maintainPeriodicity - ? { - period: layout.periodicity, - interval: layout.interval, - timeUnit: layout.timeUnit - } - : { period: 1, interval: "month", timeUnit: null }; - periodicity = params.periodicity ? params.periodicity : periodicity; - - periodicity = CIQ.cleanPeriodicity( - periodicity.period, - periodicity.interval, - periodicity.timeUnit - ); - - var needDifferentData = this.needDifferentData(periodicity); - - this.layout.periodicity = periodicity.period; - this.layout.interval = periodicity.interval; - this.layout.timeUnit = periodicity.timeUnit; - - // Case 2: new symbol or new periodicity - if (params.forceLoad || needDifferentData) { - this.clearCurrentMarketData(this.chart); - this.quoteDriver.newChart( - { - noDraw: true, - symbol: this.chart.symbol, - symbolObject: this.chart.symbolObject, - chart: this.chart, - initializeChart: true, - fetchMaximumBars: true - }, - loadAllTheData - ); - } else { - // Case 3, the right interval is set but we don't have all the data - if (chart.moreAvailable || !chart.upToDate) { - loadAllTheData(); - } else { - // Case 4, the right interval is set and we have all the data - this.createDataSet(); // Just in case the interval changed from month to day or vice versa - displayTheResults(); - } - } -}; - -}; - - -let __js_standard_storage_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -/** - * QuoteFeed required if `params.noDataLoad` is set to `false` - * - * Imports a layout (panels, studies, candleWidth, etc) from a previous serialization. See {@link CIQ.ChartEngine#exportLayout}. - * - * There are 3 ways to use the this method: - * 1. Preset the layout object in the chart instance, but do not load any data. - * - This is usually used to restore an initial 'symbol independent' general layout (chart type and studies mainly) that will then take effect when `loadChart` is subsequently called. - * - In this case, exportedLayout should be called using 'withSymbols=false' and the importLayout should have 'noDataLoad=true'. - * 2. Load an entire new chart and its data, including primary symbol, additional series, studies, chart type, periodicity and range: - * - In this case, you should not need call loadChart, setPeriodicity setSpan or setRange, addStudy, etc. since it is all restored from the previously exported layout and loaded using the attached quoteFeed. - * - If you still wish to change periodicity, span or range, you must use the CB function to do so. - * - In this case, exportedLayout should be called using 'withSymbols=true' and the importLayout should have 'noDataLoad=false' and 'managePeriodicity=true'. - * 3. Reset layout on an already existing chart without changing the primary symbol or adding additional symbols: - * - This is used when restoring a 'view' on an already existing chart from a previous `loadChart` call. The primary symbol remains the same, no additional series are added, but periodicity, range, studies and chart type are restored from the previously serialized view. - * - In this case, exportedLayout should be called using 'withSymbols=false', and importLayout should have 'noDataLoad=false', managePeriodicity=true', and 'preserveTicksAndCandleWidth=true'. - * - * **Important Notes:** - * - Please note that [studyOverlayEdit]{@link CIQ.ChartEngine~studyOverlayEditEventListener} and [studyPanelEdit]{@link CIQ.ChartEngine~studyPanelEditEventListener} event listeners must be set *before* you call {@link CIQ.ChartEngine#importLayout}. - * Otherwise your imported studies will not have edit capabilities. - * - * - When symbols are loaded, this function will set the primary symbol (first on the serialized symbol list) with {@link CIQ.ChartEngine#loadChart} - * and any overlayed symbol with {@link CIQ.ChartEngine#addSeries}. You must be using a QuoteFeed to use this workflow. - * - * - This method will not remove any currently loaded [series]{@link CIQ.ChartEngine#addSeries}. - * If your restored layout should not include previously loaded series, you must first iterate trough the {@link CIQ.ChartEngine.Chart#series} object, and systematically call {@link CIQ.ChartEngine#removeSeries} on each entry. - * - * - When allowing this method to load data, do not call [addSeries]{@link CIQ.ChartEngine#addSeries}, [importDrawings]{@link CIQ.ChartEngine#importDrawings} or [loadChart]{@link CIQ.ChartEngine#loadChart} - * in a way that will cause them to run simultaneously with this method, or the results of the layout load will be unpredictable. - * Instead use this method's callback to ensure data is loaded in the right order. - * - * - Since spans and ranges require changes in data and periodicity, - * they are only imported if params.managePeriodicity is set to true and params.noDataLoad is set to false. - * If both range and span are present, range takes precedence. - * - * @param {object} config A serialized layout generated by {@link CIQ.ChartEngine#exportLayout} - * @param {object} params Parameters to dictate layout behavior - * @param {boolean} [params.noDataLoad=false] If true, then any automatic data loading from the quotefeed will be skipped, including setting periodicity, spans or ranges.
- * Data can only be loaded if a quote feed is attached to the chart.
- * @param {boolean} [params.managePeriodicity] If true then the periodicity will be set from the layout, otherwise periodicity will remain as currently set.
- * If the span/range was saved in the layout, it will be restored using the most optimal periodicity as determined by {@link CIQ.ChartEngine#setSpan}.
- * Periodicity can only be managed if a quote feed is attached to the chart.
- * Only applicable when noDataLoad=false.
- * See {@link CIQ.ChartEngine#setPeriodicity} for additional details - * @param {boolean} [params.preserveTicksAndCandleWidth] If true then the current candleWidth (horizontal zoom) and scroll (assuming same periodicity) will be maintained and any spans or ranges present in the config will be ignored. Otherwise candle width and span/ranges will be taken from the config and restored. - * @param {function} [params.cb] An optional callback function to be executed once the layout has been fully restored. - * @param {function} [params.seriesCB] An optional callback function to be executed after each series is restored (to be aded to each {@link CIQ.ChartEngine#addSeries} call). - * @memberof CIQ.ChartEngine - * @since - * - 05-2016-10 Symbols are also loaded if included on the serialization. - * - 2016-06-21 `preserveTicksAndCandleWidth` now defaults to true. - * - 3.0.0 Added `noDataLoad` parameter. - * - 5.1.0 Will now also import extended hours settings. - * - 5.1.0 Imports the range from layout if it is there to preserve between sessions. - * - 5.2.0 spans and ranges are only executed if managePeriodicity is true and preserveTicksAndCandleWidth is false. - */ -CIQ.ChartEngine.prototype.importLayout = function (config, params) { - if (!config) { - // if no config to restore, nothing to do. - if (params.cb) params.cb(); - return; - } - - var self = this; - var importedPanels = []; - function sortPanelAxes(panels) { - function isdefined(i) { - return !!i; - } - function sortSide(importedPanel, member) { - if (!importedPanel[member] || !importedPanel[member].length) return; - var panel = panels[importedPanel.name]; - if (!panel) return; - var panelAxisArr = panel[member]; - var arr = new Array(panelAxisArr.length); - for (var j = 0; j < panelAxisArr.length; j++) { - var newPosition = importedPanel[member].indexOf(panelAxisArr[j].name); - if (newPosition > -1) arr[newPosition] = panelAxisArr[j]; - else arr.push(panelAxisArr[j]); - } - if (arr.length) panel[member] = arr.filter(isdefined); - } - for (var i = 0; i < importedPanels.length; i++) { - var importedPanel = importedPanels[i]; - sortSide(importedPanel, "yaxisLHS"); - sortSide(importedPanel, "yaxisRHS"); - } - self.chart.yAxis = self.chart.panel.yAxis; - } - - if (typeof params !== "object") { - // backwards compatibility logic. This function used to accept three named arguments - params = { - managePeriodicity: arguments[1], - preserveTicksAndCandleWidth: arguments[2] - }; - } - var layout = this.layout, - originalLayout = CIQ.shallowClone(layout); - var managePeriodicity = params.managePeriodicity, - cb = params.cb, - seriesCB = params.seriesCB, - noDataLoad = params.noDataLoad; - var preserveTicksAndCandleWidth = params.preserveTicksAndCandleWidth; - - var exportedDrawings = null; - if (this.exportDrawings) { - exportedDrawings = this.exportDrawings(); - this.abortDrawings(); - } - - this.currentlyImporting = true; - // must remove studies before cleaning the overlays, or the remove function will be lost. - for (var s in layout.studies) { - var sd = layout.studies[s]; - CIQ.getFn("Studies.removeStudy")(this, sd); - } - this.overlays = {}; - - // Keep a copy of the prior panels. We'll need these in order to transfer the holders - var priorPanels = CIQ.shallowClone(this.panels); - this.panels = {}; - - // clone into view to prevent corrupting the original config object. - var view = CIQ.clone(config); - // copy all settings to the chart layout, but maintain the original periodicity, - // which is handled later on depending on managePeriodicity and noDataLoad settings. - layout.periodicity = originalLayout.periodicity; - layout.interval = originalLayout.interval; - layout.timeUnit = originalLayout.timeUnit; - layout.setSpan = originalLayout.setSpan; - layout.range = originalLayout.range; - - // must restore candleWidth before you draw any charts or series, including study charts. The config does not always provide the candleWidth - if (preserveTicksAndCandleWidth) { - layout.candleWidth = originalLayout.candleWidth; - } else { - if (!layout.candleWidth) layout.candleWidth = 8; - } - this.setCandleWidth(layout.candleWidth); - - // Flip chart upside down if flipped but set - if (layout.flipped) this.flipChart(layout.flipped); - - var panels = view.panels; // make a copy of the panels - var p; - var panel; - var yAxis; - var sortByIndex = function (l, r) { - return l.index < r.index ? -1 : 1; - }; - for (p in panels) { - if (!("index" in panels[p])) sortByIndex = null; // unable to sort - panel = panels[p]; - panel.name = p; - importedPanels.push(panel); - } - layout.panels = {}; // erase the panels - var panelToSolo = null; - - if (importedPanels.length > 0) { - // rebuild the panels - if (sortByIndex) importedPanels.sort(sortByIndex); - for (var i = 0; i < importedPanels.length; ++i) { - panel = importedPanels[i]; - yAxis = panel.yAxis ? new CIQ.ChartEngine.YAxis(panel.yAxis) : null; - this.stackPanel( - panel.display, - panel.name, - panel.percent, - panel.chartName, - yAxis - ); - if (panel.soloing) panelToSolo = this.panels[panel.name]; - } - } - if (CIQ.isEmpty(panels)) { - this.stackPanel("chart", "chart", 1, "chart"); - } - this.resizeCanvas(); - - // Transfer the holders and DOM element references to panels that were retained when the config switched - // Delete panels that weren't - for (var panelName in priorPanels) { - var oldPanel = priorPanels[panelName]; - var newPanel = this.panels[panelName]; - if (newPanel) { - this.container.removeChild(newPanel.holder); - if (oldPanel.handle) this.container.removeChild(oldPanel.handle); - var copyFields = { - holder: true, - subholder: true, - display: true, - icons: true - }; - for (var f in copyFields) { - newPanel[f] = oldPanel[f]; - } - this.configurePanelControls(newPanel); - if (oldPanel.chart.panel == oldPanel) oldPanel.chart.panel = newPanel; // retain reference to the actual chart panel - } else { - this.privateDeletePanel(oldPanel); - } - } - this.chart.panel = this.panels.chart; // make sure these are the same! - - sortPanelAxes(this.panels); - CIQ.dataBindSafeAssignment(layout, CIQ.clone(view)); - - var studies = CIQ.clone(layout.studies); - delete layout.studies; - for (var ss in studies) { - var study = studies[ss]; - CIQ.getFn("Studies.addStudy")( - this, - study.type, - study.inputs, - study.outputs, - study.parameters, - study.panel - ); - } - - if (this.extendedHours) - this.extendedHours.prepare(layout.extended, layout.marketSessions); - - if (typeof layout.chartType == "undefined") layout.chartType = "line"; - this.setMainSeriesRenderer(); - - if (panelToSolo) this.panelSolo(panelToSolo); - this.adjustPanelPositions(); - sortPanelAxes(this.panels); - this.storePanels(); - - function postLayoutChange(err) { - if (exportedDrawings) self.importDrawings(exportedDrawings); - self.currentlyImporting = false; - if (err) return; - // Below is logic for re-adding the series used by studies. - // We need this because we've removed the existing series when we removed studies. - // When we readded studies we suspended the data loading since we were in the middle of importing - // so here after turning off the importing flag, we readd these series to cause an initial load of its data - // Note we need to reload the series data since it was cleaned out of masterData by removeStudy(). - var found; - function cb() { - self.createDataSet(); - sortPanelAxes(self.panels); - self.calculateYAxisPositions(); - self.draw(); - } - // For some series (such as those based on price relative studies) `addSeries()` will check whether there - // already exist series with a matching symbol (to avoid refetching data). When we are removing and then - // readding series, we need to remove them all before readding any. This is because not yet removed series - // can cause readded studies to not get initialized properly. - var series; - var seriesToReadd = []; - for (var s in self.chart.series) { - if (!self.removeSeries) break; - series = self.chart.series[s]; - if (series.parameters.bucket == "study") { - found = true; - self.removeSeries(series); - seriesToReadd.push(series); - } - } - for (var i = 0; i < seriesToReadd.length; i++) { - series = seriesToReadd[i]; - self.addSeries(series.id, series.parameters, cb); - } - if (!found) self.draw(); - self.updateListeners("layout"); // tells listening objects that layout has changed - self.changeOccurred("layout"); // dispatches to callbacklisteners - } - - function cb2() { - self.calculateYAxisPositions(); - sortPanelAxes(self.panels); - if (seriesCB) seriesCB(); - } - if (!noDataLoad) { - // Now we execute the data loading functions. - if (view.symbols && view.symbols.length) { - // load symbols; primary and additional series. Also adjust ranges and periodicity at the same time - - var params2 = { - chart: this.chart - }; - if ( - !preserveTicksAndCandleWidth && - managePeriodicity && - view.range && - Object.keys(view.range).length - ) { - // spans and ranges are only executed if managePeriodicity is true and preserveTicksAndCandleWidth is false. - params2.range = view.range; - } else if ( - !preserveTicksAndCandleWidth && - managePeriodicity && - view.setSpan && - Object.keys(view.setSpan).length - ) { - // see above - params2.span = view.setSpan; - } else if (managePeriodicity && view.interval) { - // otherwise, import periodicity if available - params2.periodicity = { - interval: view.interval, - period: view.periodicity, - timeUnit: view.timeUnit - }; - } else { - // otherwise, maintain prior periodicity - params2.periodicity = { - interval: originalLayout.interval, - period: originalLayout.periodicity, - timeUnit: originalLayout.timeUnit - }; - } - - var symbolObject = view.symbols[0].symbolObject || view.symbols[0].symbol; - - this.loadChart(symbolObject, params2, function (err) { - if (!err) { - for (var smbl, i = 1; i < view.symbols.length; ++i) { - if (!self.addSeries) break; - smbl = view.symbols[i]; - if (!smbl.parameters) smbl.parameters = {}; - var parameters = CIQ.clone(smbl.parameters); - if (this.panels[parameters.panel]) { - self.addSeries(smbl.id, parameters, cb2); - } else { - console.warn( - 'Warning: Series "' + - smbl.id + - '" could not be imported due to a missing corresponding panel "' + - parameters.panel + - '"' - ); - } - } - if (view.chartScale) self.setChartScale(view.chartScale); - } - postLayoutChange(err); - if (cb) cb.apply(null, arguments); - }); - return; - } - - // Otherwise, if only data ranges or periodicity are required, load them now - - if (managePeriodicity) { - if (!preserveTicksAndCandleWidth && this.setRange) { - // spans and ranges are only executed if managePeriodicity is true and preserveTicksAndCandleWidth is false. - var range = view.range; - if (range && Object.keys(range).length && this.chart.symbol) { - this.setRange(range, function () { - postLayoutChange(); - if (cb) cb(); - }); - return; - } else if ( - view.setSpan && - Object.keys(view.setSpan).length && - this.chart.symbol - ) { - this.setSpan(view.setSpan, function () { - postLayoutChange(); - if (cb) cb(); - }); - return; - } - } - - var interval = view.interval; - var periodicity = view.periodicity; - var timeUnit = view.timeUnit; - if (isNaN(periodicity)) periodicity = 1; - if (!interval) interval = "day"; - // this will get new data or roll up existing, createDataSet() and draw() - this.setPeriodicity( - { period: periodicity, interval: interval, timeUnit: timeUnit }, - function () { - postLayoutChange(); - if (cb) cb(); - } - ); - return; - } - } - - // if we got here, no data loading was requested. - if (managePeriodicity) { - layout.periodicity = view.periodicity; - layout.interval = view.interval; - layout.timeUnit = view.timeUnit; - layout.setSpan = view.setSpan; - } - - this.createDataSet(); - if (!preserveTicksAndCandleWidth) this.home(); - postLayoutChange(); - if (cb) cb(); -}; - -/** - * Exports the current layout into a serialized form. The returned object can be passed into {@link CIQ.ChartEngine#importLayout} to restore the layout at a future time. - * - * This method will also save any programmatically activated [range]{@link CIQ.ChartEngine#setRange} or [span]{@link CIQ.ChartEngine#setSpan} setting that is still active. - * - * > **Note:** A set range or span that is manually modified by a user when zooming, panning, or changing periodicity will be nullified. - * > So, if you wish to always record the current range of a chart for future restoration, you must use the following process: - * - * > 1- Add the following injection to save the range on every draw operation: - * > ``` - * > stxx.append("draw", function() { - * > console.log('recording range'); - * > delete stxx.layout.setSpan; - * > stxx.layout.range={padding: stxx.preferences.whitespace, - * > dtLeft: stxx.chart.dataSegment[0].DT, - * > dtRight: stxx.chart.dataSegment[stxx.chart.dataSegment.length - 1].DT, - * > periodicity: { - * > period: stxx.layout.periodicity, - * > interval: stxx.layout.interval, - * > timeUnit: stxx.layout.timeUnit - * > } - * > } - * > saveLayout({stx:stxx}); - * > }); - * > ``` - * - * > 2- Make sure you call [importLayout]{@link CIQ.ChartEngine#importLayout} with params `preserveTicksAndCandleWidth` set to `false` - * - * > More on injections here: {@tutorial Using the Injection API} - * - * @param {boolean} withSymbols If `true`, include the chart's current primary symbol and any secondary symbols from any {@link CIQ.ChartEngine#addSeries} operation, if using a quote feed. Studies will be excluded from this object. The resulting list will be in the `symbols` element of the serialized object. - * @return {object} The serialized form of the layout. - * @memberof CIQ.ChartEngine - * @since - * - 05-2016-10 Added the `withSymbols` parameter. - * - 5.0.0 `obj.symbols` is explicitly removed from the serialization when `withSymbols` is not true. - */ -CIQ.ChartEngine.prototype.exportLayout = function (withSymbols) { - var obj = {}; - // First clone all the fields, these describe the layout - for (var field in this.layout) { - if (field != "studies" && field != "panels" && field != "drawing") { - obj[field] = CIQ.clone(this.layout[field]); - } else if (field == "studies") { - obj.studies = {}; - } else if (field == "panels") { - obj.panels = {}; - } - } - - function serializeAxisNames(axisArr) { - var nameArr = []; - for (var i = 0; i < axisArr.length; i++) { - nameArr.push(axisArr[i].name); - } - return nameArr; - } - - // Serialize the panels - var i = 0; - for (var panelName in this.panels) { - var p = this.panels[panelName]; - if (p.exportable === false) continue; - var panel = (obj.panels[panelName] = {}); - panel.percent = p.percent; - panel.display = p.display; - panel.chartName = p.chart.name; - panel.soloing = p.soloing; - panel.index = i++; - panel.yAxis = { name: p.yAxis.name, position: p.yAxis.position }; - if (p.yaxisLHS) panel.yaxisLHS = serializeAxisNames(p.yaxisLHS); - if (p.yaxisRHS) panel.yaxisRHS = serializeAxisNames(p.yaxisRHS); - } - - // Serialize the studies - for (var studyName in this.layout.studies) { - var study = (obj.studies[studyName] = {}); - var s = this.layout.studies[studyName]; - study.type = s.type; - study.inputs = CIQ.clone(s.inputs); - study.outputs = CIQ.clone(s.outputs); - study.panel = s.panel; - study.parameters = CIQ.clone(s.parameters); - } - - if (withSymbols) { - obj.symbols = this.getSymbols({ - "include-parameters": true, - "exclude-studies": true, - "exclude-generated": true - }); - } else { - delete obj.symbols; - } - - return obj; -}; - -/** - * Imports a users preferences from a saved location and uses them in the ChartEngine - * To save preferences see {@link CIQ.ChartEngine#exportPreferences} - * @param {object} preferences An object of {@link CIQ.ChartEngine#preferences} - * @memberof CIQ.ChartEngine - * @since 4.0.0 - */ -CIQ.ChartEngine.prototype.importPreferences = function (preferences) { - CIQ.extend(this.preferences, preferences); - if (preferences.timeZone) - this.setTimeZone(this.dataZone, preferences.timeZone); - if (preferences.language && CIQ.I18N) { - CIQ.I18N.localize(this, preferences.language); - } - this.changeOccurred("preferences"); -}; - -/** - * Exports the {@link CIQ.ChartEngine#preferences} for external storage. - * Can then be imported again after being parsed with {@link CIQ.ChartEngine#importPreferences} - * @memberof CIQ.ChartEngine - * @returns {CIQ.ChartEngine#preferences} - * @since 4.0.0 - */ -CIQ.ChartEngine.prototype.exportPreferences = function () { - return this.preferences; -}; - -}; - - -let __js_standard_studies_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; -var timezoneJS = - typeof _timezoneJS !== "undefined" ? _timezoneJS : _exports.timezoneJS; - -if (CIQ.ChartEngine) { - /** - * INJECTABLE - * - * This function is called when a highlighted study overlay is right clicked. If the overlay has an edit function (as many studies do), it will be called. Otherwise it will remove the overlay - * @param {string} name The name (id) of the overlay - * @param {boolean} [forceEdit] If true then force edit menu - * @memberof CIQ.ChartEngine.AdvancedInjectable# - * @alias rightClickOverlay - */ - CIQ.ChartEngine.prototype.rightClickOverlay = function (name, forceEdit) { - if (this.runPrepend("rightClickOverlay", arguments)) return; - var sd = this.overlays[name]; - if (sd.editFunction) { - sd.editFunction(forceEdit); - } else { - this.removeOverlay(name); - } - this.runAppend("rightClickOverlay", arguments); - }; - - /** - * INJECTABLE - * - * Registers an activated overlay study with the chart. - * - * This is the recommended method for registering an overlay study, rather than directly manipulating the [stxx.overlays]{@link CIQ.ChartEngine#overlays} object. - * @param {CIQ.Studies.StudyDescriptor} sd The study object - * @memberof CIQ.ChartEngine.AdvancedInjectable# - * @alias addOverlay - * @since 5.2.0 - */ - CIQ.ChartEngine.prototype.addOverlay = function (sd) { - if (this.runPrepend("addOverlay", arguments)) return; - this.overlays[sd.name] = sd; - this.runAppend("addOverlay", arguments); - }; - - /** - * INJECTABLE - * - * Removes an overlay (and the associated study) - * @param {string} name The name (id) of the overlay - * @memberof CIQ.ChartEngine.AdvancedInjectable# - * @alias removeOverlay - */ - CIQ.ChartEngine.prototype.removeOverlay = function (name) { - if (this.runPrepend("removeOverlay", arguments)) return; - var mySD = this.overlays[name]; - for (var o in this.overlays) { - var sd = this.overlays[o]; - var fieldInputs = ["Field"]; - if (CIQ.Studies) fieldInputs = CIQ.Studies.getFieldInputs(sd); - for (var f = 0; f < fieldInputs.length; f++) { - // Study sd is reliant on an output from the about-to-be-deleted overlay - if (mySD.outputMap[sd.inputs[fieldInputs[f]]]) { - // Yucky, we should move to explicit parent nodes - this.removeOverlay(sd.name); - } - } - } - - if (mySD) { - this.cleanupRemovedStudy(mySD); - var panel = this.panels[mySD.panel]; - delete this.overlays[name]; - this.checkForEmptyPanel(mySD.panel); - } - - if (!this.currentlyImporting) { - // silent mode while importing - this.displaySticky(); - this.createDataSet(); - this.changeOccurred("layout"); - } - this.resetDynamicYAxis(); - this.runAppend("removeOverlay", arguments); - }; - - /** - * Cleans up a removed study. called by {@link CIQ.ChartEngine#privateDeletePanel} or {@link CIQ.ChartEngine#removeOverlay} - * Calls removeFN, and plugins associated with study. - * Finally, removes study from layout. - * @param {CIQ.ChartEngine} stx A chart object - * @param {object} sd A study descriptor - * @memberof CIQ.ChartEngine - * @private - * @since 2015-11-1 - */ - CIQ.ChartEngine.prototype.cleanupRemovedStudy = function (sd) { - if (!sd) return; - if (sd.study.removeFN) sd.study.removeFN(this, sd); - // delete any plugins associated with this study - for (var p in this.plugins) { - if (p.indexOf("{" + sd.id + "}") > -1) delete this.plugins[p]; - } - if (this.layout.studies) delete this.layout.studies[sd.name]; - delete this.overlays[sd.name]; - if (CIQ.Studies) CIQ.Studies.removeStudySymbols(sd, this); - if (this.quoteDriver) this.quoteDriver.updateSubscriptions(); - }; -} - -/** - * Namespace for functionality related to studies (aka indicators). - * - * See {@tutorial Using and Customizing Studies} for additional details and a general overview about studies. - * @namespace - * @name CIQ.Studies - */ -CIQ.Studies = CIQ.Studies || function () {}; - -/** - * Constants for when no inputs or outputs specified in studies. - * Values can be changed but do not change keys. - * @memberof CIQ.Studies - */ -CIQ.Studies.DEFAULT_INPUTS = { Period: 14 }; -CIQ.Studies.DEFAULT_OUTPUTS = { Result: "auto" }; - -CIQ.Studies.sortForProcessing = (stx) => { - function setIndependentStudies(list, arr) { - list.forEach((study) => { - if (arr.indexOf(study) == -1) { - let dependents = study.getDependents(stx); - if (dependents.length) setIndependentStudies(dependents, arr); - arr.unshift(study); - } - }); - } - let sortArray = []; - const studies = stx.layout.studies; - if (studies) { - setIndependentStudies(Object.values(studies), sortArray); - } - return sortArray; -}; - -/** - * Creates a study descriptor which contains all of the information necessary to handle a study. Also - * provides convenience methods to extract information from it. - * - * Do not call directly or try to manually create your own study descriptor, but rather always use the one returned by {@link CIQ.Studies.addStudy} - * - * @param {string} name The name of the study. This should be unique to the chart. For instance if there are two RSI panels then they should be of different periods and named accordingly. Usually this is determined automatically by the library. - * @param {string} type The type of study, which can be used as a look up in the StudyLibrary - * @param {string} panel The name of the panel that contains the study - * @param {object} inputs Names and values of input fields - * @param {object} outputs Names and values (colors) of outputs - * @param {object} parameters Additional parameters that are unique to the particular study - * @constructor - * @name CIQ.Studies.StudyDescriptor - */ -CIQ.Studies.StudyDescriptor = function ( - name, - type, - panel, - inputs, - outputs, - parameters -) { - /** - * @property {string} name The study's ID. Includes ZWNJ characters. - * **Please note:** To facilitate study name translations, study names use zero-width non-joiner (unprintable) characters to delimit the general study name from the specific study parameters. - * Example: "\u200c"+"Aroon"+"\u200c"+" (14)". - * At translation time, the library will split the text into pieces using the ZWNJ characters, parentheses and commas to just translate the required part of a study name. - * For more information on ZWNJ characters see: [Zero-width_non-joiner](https://en.wikipedia.org/wiki/Zero-width_non-joiner). - * Please be aware of these ZWNJ characters, which will now be present in all study names and corresponding panel names; including the `layout.studies` study keys. - * Affected fields in the study descriptors could be `id `, `display`, `name` and `panel`. - *
To prevent issues, always use the names returned in the **study descriptor**. This will ensure compatibility between versions. - * >Example: - * >
Correct reference: - * >
`stxx.layout.studies["\u200c"+"Aroon"+"\u200c"+" (14)"];` - * >
Incorrect reference: - * >
`stxx.layout.studies["Aroon (14)"];` - */ - this.name = name; - /** - * @property {string} type The study type. - */ - this.type = type; - /** - * @property {string} panel ID of the panel element to which the study is attached. - */ - this.panel = panel; - /** - * @property {object} inputs Keys for each possible study input with descriptors for the set and default values. - */ - this.inputs = inputs; - /** - * @property {object} outputs Keys for each possible study output with its corresponding rendering color. - */ - this.outputs = outputs; - /** - * @property {object} parameters Keys for each of the study's possible plot parameters. - */ - this.parameters = parameters; // Optional parameters, i.e. zones. - /** - * @property {object} outputMap Mapping between a unique study field name in the dataSet/datSegment and its corresponding general `outputs` name/color, as set in the study library entry.
- * This mapping is automatically created and present on all study descriptors, and used by all default study functions to ensure data generated by a calculation function can be found by the display function.
- * Example: - * ``` - * // Map for an Alligator study with inputs of: - * // -Jaw Period:13 - * // -Jaw Offset:8 - * // -Teeth Period:8 - * // -Teeth Offset:5 - * // -Lips Period:5 - * // -Lips Offset:3 - * // -Show Fractals:false - * - * { - * "Jaw ‌Alligator‌ (13,8,8,5,5,3,n)": "Jaw", - * "Teeth ‌Alligator‌ (13,8,8,5,5,3,n)": "Teeth", - * "Lips ‌Alligator‌ (13,8,8,5,5,3,n)": "Lips" - * } - * ``` - */ - this.outputMap = {}; // Maps dataSet label to outputs label "RSI (14)" : "RSI", for the purpose of figuring color. - /** - * @property {number} min The minimum data point. - */ - this.min = null; - /** - * @property {number} max The maximum data point. - */ - this.max = null; - this.startFrom = 0; - this.subField = "Close"; // In case study is off a series - var libraryEntry = CIQ.Studies.studyLibrary[type]; - if (!libraryEntry) { - libraryEntry = {}; - if ( - panel == "chart" || - (!panel && parameters && parameters.chartName == "chart") - ) - this.overlay = true; - } - if (typeof libraryEntry.inputs == "undefined") - libraryEntry.inputs = CIQ.clone(CIQ.Studies.DEFAULT_INPUTS); - if (typeof libraryEntry.outputs == "undefined") - libraryEntry.outputs = CIQ.clone(CIQ.Studies.DEFAULT_OUTPUTS); - - this.study = libraryEntry; - this.libraryEntry = libraryEntry; // deprecated, backwards compatibility -}; - -/** - * Returns the y-axis used by the study - * @param {CIQ.ChartEngine} stx CIQ.ChartEngine - * @memberof CIQ.Studies.StudyDescriptor - * @return {CIQ.ChartEngine.YAxis} Y axis - * @since 7.1.0 - */ -CIQ.Studies.StudyDescriptor.prototype.getYAxis = function (stx) { - var yAxis = this.yAxis; - var specifiedYAxis; - if (this.parameters) { - specifiedYAxis = this.parameters.yaxisDisplayValue; - } - if (!yAxis) { - var testPanel = stx.panels[this.panel]; - if (testPanel) { - yAxis = - stx.getYAxisByName(testPanel, specifiedYAxis) || - stx.getYAxisByName(testPanel, this.name) || - testPanel.yAxis; - } - } - if (!yAxis) - yAxis = - stx.getYAxisByName(stx.chart.panel, specifiedYAxis) || - stx.chart.panel.yAxis; - return yAxis; -}; - -/** - * Returns the context to use for drawing the study - * @param {CIQ.ChartEngine} stx A chart object - * @return {object} An HTML canvas context - * @memberof CIQ.Studies.StudyDescriptor - * @since 7.1.0 - */ -CIQ.Studies.StudyDescriptor.prototype.getContext = function (stx) { - // If the study is draggable it will be placed on the tempCanvas and so that canvas's context will be returned. - //if(this.highlight && stx.highlightedDraggable) return stx.chart.tempCanvas.context; - return stx.chart.context; -}; - -/** - * Returns an array of all studies which depend on a given study. - * A dependent study is one which uses an output of another study as input. - * @param {CIQ.ChartEngine} stx A chart object - * @param {boolean} [followsPanel] If true, will only return those studies which are not assigned to an explicit panel - * @return {array} Array of dependent studies - * @memberof CIQ.Studies.StudyDescriptor - * @since 7.1.0 - */ -CIQ.Studies.StudyDescriptor.prototype.getDependents = function ( - stx, - followsPanel -) { - var dependents = []; - for (var s in stx.layout.studies) { - var dependent = stx.layout.studies[s]; - if (dependent == this) continue; - var fieldInputs = CIQ.Studies.getFieldInputs(dependent); - for (var f = 0; f < fieldInputs.length; f++) { - if (dependent.inputs[fieldInputs[f]].includes(this.name)) { - if ( - followsPanel && - dependent.parameters && - dependent.parameters.panelName - ) - continue; - dependents.push(dependent); - dependents = dependents.concat( - dependent.getDependents(stx, followsPanel) - ); - break; - } - } - } - return dependents; -}; - -/** - * Determines whether the study can be dragged to another axis or panel. - * - * @param {CIQ.ChartEngine} stx A chart object. - * @return {boolean} true if not allowed to drag. - * @memberof CIQ.Studies.StudyDescriptor - * @since 7.3.0 - */ -CIQ.Studies.StudyDescriptor.prototype.undraggable = function (stx) { - var attr = this.study.attributes; - if (attr) { - if (attr.panelName && attr.panelName.hidden) return true; - if (attr.yaxisDisplayValue && attr.yaxisDisplayValue.hidden) return true; - } - return false; -}; - -/** - * Adds extra ticks to the end of the scrubbed array, to be added later to the dataSet. - * - * This function can be used to add extra ticks, like offsets into the future, to the dataSet to be plotted ahead of the current bar. - * If a DT is not supplied, one will be calculate for each tick in the array. - * - * Remember to call this outside of any loop that iterates through the quotes array, or you will create a never-ending loop, since this increases the array size. - * - * @param {CIQ.ChartEngine} stx A chart engine instance - * @param {array} ticks The array of ticks to add. Each tick is an object containing whatever data to add. - * @example - * var futureTicks=[]; - * for(i++;i=0){ - * if(i+offset= 0; t--) { - tick = ticks[t]; - for (var prop in tick) { - if (tick[prop] || tick[prop] === 0) { - t = -1; - break; - } - } - if (t == -1) break; - ticks.pop(); - } - for (t = 0; t < ticks.length; t++) { - tick = ticks[t]; - if (!tick.DT) tick.DT = iter.next(); - if (!tick.displayDate) stx.setDisplayDate(tick); - tick.futureTick = true; - scrubbed.push(tick); - } -}; - -/** - * Automatically generates a unique name for the study instance. - * - * If a translation callback has been associated with the chart object then the name of the study will be translated. - * @param {CIQ.ChartEngine} stx A chart engine instance - * @param {string} studyName Type of study - * @param {object} inputs The inputs for this study instance - * @param {string} [replaceID] If it matches then return the same id - * @param {string} [customName] If this is supplied, use it to form the full study name. Otherwise `studyName` will be used.
ie: if custom name is 'SAMPLE', the unique name returned would resemble "SAMPLE(paam1,param2,param3,...)-X". - * @return {string} A unique name for the study - * @memberof CIQ.Studies - * @since 5.1.1 Added `customName` argument; if supplied, use it to form the full study name. Otherwise `studyName` will be used. - */ -CIQ.Studies.generateID = function ( - stx, - studyName, - inputs, - replaceID, - customName -) { - var libraryEntry = CIQ.Studies.studyLibrary[studyName]; - var translationPiece = "\u200c" + (customName || studyName) + "\u200c"; // zero-width non-joiner (unprintable) to delimit translatable phrase - var id = translationPiece; - if (libraryEntry) { - // only one instance can exist at a time if custom removal, so return study name - if (libraryEntry.customRemoval) return id; - } - if (!CIQ.isEmpty(inputs)) { - var first = true; - for (var field in inputs) { - // some values do not merit being in the study name - if (["id", "display", "Shading", "Anchor Selector"].includes(field)) { - continue; - } - - var val = inputs[field]; - if (val == "field") continue; // skip default, usually means "Close" - val = val.toString(); - if (CIQ.Studies.prettify[val] !== undefined) - val = CIQ.Studies.prettify[val]; - if (first) { - first = false; - id += " ("; - } else { - if (val) id += ","; - } - id += val; - } - if (!first) id += ")"; - } - - //this tests if replaceID is just a warted version of id, in that case keep the old id - if (replaceID && replaceID.indexOf(id) === 0) return replaceID; - - // If the id already exists then we'll wart it by adding -N - if (stx.layout.studies && stx.layout.studies[id]) { - for (var i = 2; i < 50; i++) { - var warted = id + "-" + i; - if (!stx.layout.studies[warted]) { - id = warted; - break; - } - } - } - return id; -}; - -/** - * A helper class for adding studies to charts, modifying studies, and creating study edit dialog - * boxes. - * - * Study DialogHelpers are created from - * [study definitions](tutorial-Using%20and%20Customizing%20Studies%20-%20Study%20objects.html#understanding_the_study_definition) - * or - * [study descriptors](tutorial-Using%20and%20Customizing%20Studies%20-%20Study%20objects.html#understanding_the_study_descriptor_object) - * (see the examples below). - * - * A DialogHelper contains the inputs, outputs, and parameters of a study. Inputs configure the - * study. Outputs style the lines and filled areas of the study. Parameters set chart‑related - * aspects of the study, such as the panel that contains the study or whether the study is an - * underlay. - * - * For example, a DialogHelper for the Anchored VWAP study contains the following data: - * ``` - * inputs: Array(8) - * 0: {name: "Field", heading: "Field", value: "Close", defaultInput: "Close", type: "select", …} - * 1: {name: "Anchor Date", heading: "Anchor Date", value: "", defaultInput: "", type: "date"} - * 2: {name: "Anchor Time", heading: "Anchor Time", value: "", defaultInput: "", type: "time"} - * 3: {name: "Display 1 Standard Deviation (1σ)", heading: "Display 1 Standard Deviation (1σ)", value: false, - * defaultInput: false, type: "checkbox"} - * 4: {name: "Display 2 Standard Deviation (2σ)", heading: "Display 2 Standard Deviation (2σ)", value: false, - * defaultInput: false, type: "checkbox"} - * 5: {name: "Display 3 Standard Deviation (3σ)", heading: "Display 3 Standard Deviation (3σ)", value: false, - * defaultInput: false, type: "checkbox"} - * 6: {name: "Shading", heading: "Shading", value: false, defaultInput: false, type: "checkbox"} - * 7: {name: "Anchor Selector", heading: "Anchor Selector", value: true, defaultInput: true, type: "checkbox"} - * outputs: Array(4) - * 0: {name: "VWAP", heading: "VWAP", defaultOutput: "#FF0000", color: "#FF0000"} - * 1: {name: "1 Standard Deviation (1σ)", heading: "1 Standard Deviation (1σ)", defaultOutput: "#e1e1e1", color: "#e1e1e1"} - * 2: {name: "2 Standard Deviation (2σ)", heading: "2 Standard Deviation (2σ)", defaultOutput: "#85c99e", color: "#85c99e"} - * 3: {name: "3 Standard Deviation (3σ)", heading: "3 Standard Deviation (3σ)", defaultOutput: "#fff69e", color: "#fff69e"} - * parameters: Array(4) - * 0: {name: "panelName", heading: "Panel", defaultValue: "Auto", value: "Auto", options: {…}, …} - * 1: {name: "underlay", heading: "Show as Underlay", defaultValue: false, value: undefined, type: "checkbox"} - * 2: {name: "yaxisDisplay", heading: "Y-Axis", defaultValue: "default", value: "shared", options: {…}, …} - * 3: {name: "flipped", heading: "Invert Y-Axis", defaultValue: false, value: false, type: "checkbox"} - * ``` - * - * which corresponds to the fields of the study edit dialog box: - * - * AVWAP study edit dialog box - * - * DialogHelpers also contain `attributes` which specify the formatting of dialog box input - * fields. For example, the DialogHelper for the Anchored VWAP study contains the following: - * ``` - * attributes: - * Anchor Date: {placeholder: "yyyy-mm-dd"} - * Anchor Time: {placeholder: "hh:mm:ss", step: 1} - * flippedEnabled: {hidden: true} - * ``` - * - * The `placeholder` property (in addition to its normal HTML function of providing placeholder - * text) determines the input type of date and time fields. If the property value is "yyyy-mm-dd" - * for a date field, the field in the edit dialog box is a date input type instead of a string - * input. If the value is "hh:mm:ss" for a time field, the field is a time input type instead of a - * string. If the `hidden` property of a field is set to true, the field is excluded from the - * study edit dialog box. - * - * In the Anchored VWAP edit dialog box (see above), the Anchor Date field is formatted as a date - * input type; Anchor Time, as a time input type. The Invert Y-Axis check box (the "flipped" - * parameter) is hidden. - * - * **Note:** Actual date/time displays are browser dependent. The time is displayed in the - * `displayZone` time zone. Time values are converted to the `dataZone` time zone before being - * used internally so they always match the time zone of `masterData`. See - * {@link CIQ.ChartEngine#setTimeZone}. - * - * For more information on DialogHelpers, see the - * {@tutorial Using and Customizing Studies - Advanced} tutorial. - * - * @see {@link CIQ.Studies.addStudy} to add a study to the chart using the inputs, outputs, and - * parameters of a DialogHelper. - * @see {@link CIQ.Studies.DialogHelper#updateStudy} to add or modify a study. - * @see {@link CIQ.UI.StudyEdit} to create a study edit dialog box using a DialogHelper. - * - * @param {object} params Constructor parameters. - * @param {string} [params.name] The name of a study. The DialogHelper is created from the study's - * definition. Must match a name specified in the - * [study library]{@link CIQ.Studies.studyLibrary}. Ignored if `params.sd` is provided. - * @param {CIQ.Studies.StudyDescriptor} [params.sd] A study descriptor from which the - * DialogHelper is created. Takes precedence over `params.name`. - * @param {boolean} [params.axisSelect] If true, the parameters property of the DialogHelper - * includes options for positioning the study y-axis, color settings for the y-axis, and the - * Invert Y‑Axis option. - * @param {boolean} [params.panelSelect] If true, the parameters property of the DialogHelper - * includes the Show as Underlay option and a list of panels in which the study can be - * placed. - * @param {CIQ.ChartEngine} params.stx The chart object associated with the DialogHelper. - * - * @name CIQ.Studies.DialogHelper - * @constructor - * @since - * - 6.3.0 Added parameters `axisSelect` and `panelSelect`. If a placeholder attribute of - * `yyyy-mm-dd` or `hh:mm:ss` is set on an input field, the dialog displays a date or time - * input type instead of a string input type. - * - 7.1.0 It is expected that the study dialog's parameters section is refreshed whenever the - * DialogHelper changes. The "signal" member should be observed to see if it has flipped. - * - 8.2.0 Attribute property values in the study definition can now be functions. See the - * [Input Validation](tutorial-Using%20and%20Customizing%20Studies%20-%20Advanced.html#InputValidation) - * section of the {@tutorial Using and Customizing Studies - Advanced} tutorial. - * - * @example Create a DialogHelper from a study definition. - * let helper = new CIQ.Studies.DialogHelper({ name: "ma", stx: stxx }) - * - * @example Create a DialogHelper from a study descriptor. - * let sd = CIQ.Studies.addStudy(stxx, "Aroon"); - * let helper = new CIQ.Studies.DialogHelper({ sd: sd, stx: stxx }); - * - * @example Display the DialogHelper inputs, outputs, parameters, and attributes. - * let helper = new CIQ.Studies.DialogHelper({ name: "stochastics", stx: stxx }); - * console.log("Inputs:", JSON.stringify(helper.inputs)); - * console.log("Outputs:", JSON.stringify(helper.outputs)); - * console.log("Parameters:", JSON.stringify(helper.parameters)); - * console.log("Attributes:", JSON.stringify(helper.attributes)); - */ -CIQ.Studies.DialogHelper = function (params) { - var stx = (this.stx = params.stx); - var sd = (this.sd = params.sd); - this.name = sd ? sd.type : params.name; - this.signal = 1; // for observing changes - this.inputs = []; - this.outputs = []; - this.parameters = []; - var libraryEntry = (this.libraryEntry = sd - ? sd.study - : CIQ.Studies.studyLibrary[params.name]); - if (typeof libraryEntry.inputs == "undefined") - libraryEntry.inputs = CIQ.clone(CIQ.Studies.DEFAULT_INPUTS); - if (typeof libraryEntry.outputs == "undefined") - libraryEntry.outputs = CIQ.clone(CIQ.Studies.DEFAULT_OUTPUTS); - var panel = - sd && stx.panels[sd.panel] ? stx.panels[sd.panel] : stx.chart.panel; - var chart = panel.chart; - - this.title = stx.translateIf(libraryEntry.name); - - this.attributes = CIQ.clone(libraryEntry.attributes); - if (!this.attributes) this.attributes = {}; - - for (var attrField in this.attributes) { - var attributes = this.attributes[attrField]; - for (var attr in attributes) { - if (typeof attributes[attr] == "function") - attributes[attr] = attributes[attr].call(sd); - } - } - - function hideTheField(fieldName, condition) { - if (!this.attributes[fieldName]) this.attributes[fieldName] = {}; - if (condition) this.attributes[fieldName].hidden = true; - } - // build array of study outputs which should be considered valid fields in the study dialog "Field" dropdown - var actualOutputs = [], - s = stx.layout.studies; - var excludes = []; - if (sd) excludes = Array.prototype.concat(sd, sd.getDependents(stx)); - for (var n in s) { - if (excludes.indexOf(s[n]) > -1) continue; // don't include its own fields or its dependents' fields - for (var actualOutput in s[n].outputMap) { - actualOutputs.push(actualOutput); - } - } - - /* - This code loops through the acceptable inputs for the study in question. The format of the input default in the studyLibrary determines what type of input - is required. For instance a number requires an input field. A string will produce a select box, of moving averages for instance if the string is "ma". - If the string is "field" then a select box of acceptable fields is displayed. Likewise, an array will show up as a select box. - */ - for (var i in libraryEntry.inputs) { - var input = {}; - this.inputs.push(input); - input.name = i; - input.heading = stx.translateIf(i); - var acceptedData = libraryEntry.inputs[i]; - if ( - sd && - sd.inputs && - typeof sd.inputs[i] != "undefined" && - sd.inputs[i] !== null - ) - input.value = sd.inputs[i]; - else input.value = libraryEntry.inputs[i]; - - input.defaultInput = libraryEntry.inputs[i]; - if (!this.attributes[i]) - this.attributes[i] = CIQ.Studies.inputAttributeDefaultGenerator( - input.defaultInput - ); - - if (acceptedData.constructor == Number) { - input.type = "number"; - } else if (acceptedData.constructor == String) { - var isMA = CIQ.Studies.movingAverageHelper(stx, input.defaultInput); - if (isMA) { - input.type = "select"; - input.defaultInput = isMA; - var converted = CIQ.Studies.movingAverageHelper(stx, input.value); - if (!converted) converted = input.value; - input.value = converted; - input.options = CIQ.Studies.movingAverageHelper(stx, "options"); - } else if (acceptedData == "field") { - input.type = "select"; - input.options = {}; - var studyFields = [ - "Open", - "High", - "Low", - "Close", - "Adj_Close", - "hl/2", - "hlc/3", - "hlcc/4", - "ohlc/4", - chart.defaultPlotField - ].concat(actualOutputs); - for (var field = 0; field < studyFields.length; field++) { - var fieldText = studyFields[field]; - input.options[fieldText] = stx.translateIf(fieldText); - } - if (input.value == "field") { - input.value = "Close"; - } - if (input.defaultInput == "field") { - input.defaultInput = "Close"; - } - } else { - input.type = "text"; - if (this.attributes[i].placeholder == "yyyy-mm-dd") input.type = "date"; - else if (this.attributes[i].placeholder == "hh:mm:ss") - input.type = "time"; - } - } else if (acceptedData.constructor == Boolean) { - input.type = "checkbox"; - if (input.value === true || input.value == "true" || input.value == "on") - input.value = true; - } else if (acceptedData.constructor == Array) { - input.type = "select"; - input.options = {}; - for (var ii = 0; ii < acceptedData.length; ii++) { - input.options[acceptedData[ii]] = stx.translateIf(acceptedData[ii]); - } - if (input.value.constructor == Array) { - input.value = input.value[0]; - } - if (this.attributes[i].defaultSelected) { - input.defaultInput = this.attributes[i].defaultSelected; - } else { - input.defaultInput = acceptedData[0]; - } - } - } - - // find datetime inputs (these have two fields named "xyz Date" and "xyz Time"). We extract the xyz and put in array - this.dateTimeInputs = []; - for (var dateInput = 0; dateInput < this.inputs.length; dateInput++) { - var date = this.inputs[dateInput]; - if (date.type == "date") { - var fieldName = date.name.substring(0, date.name.indexOf(" Date")); - for (var timeInput = 0; timeInput < this.inputs.length; timeInput++) { - var time = this.inputs[timeInput]; - if (time.type == "time") { - if (time.name == fieldName + " Time") { - this.dateTimeInputs.push(fieldName); - break; - } - } - } - } - } - - // adjust date inputs for displayZone - this.adjustInputTimesForDisplayZone(); - - /* - Outputs are much simpler than inputs. Outputs are simply a list of available outputs and the selected color for that output. So here - we print a line item in the dialog for each output and attach a color picker to it. The color picker is obtained from the Context. - */ - - for (i in libraryEntry.outputs) { - var output = { - name: i, - heading: stx.translateIf(i) - }; - - output.color = output.defaultOutput = libraryEntry.outputs[i]; - if (sd && sd.outputs && sd.outputs[i]) output.color = sd.outputs[i]; - if (output.color == "auto") output.color = stx.defaultColor; - this.outputs.push(output); - } - - /* And now the parameters */ - var parameters = sd ? sd.parameters : null; - if (libraryEntry.parameters) { - var init = libraryEntry.parameters.init; - if (init) { - var obj; - if (init.studyOverZonesEnabled !== undefined) { - obj = { - name: "studyOverZones", - heading: stx.translateIf("Show Zones"), - defaultValue: init.studyOverZonesEnabled, - value: init.studyOverZonesEnabled - }; - if ( - parameters && - (parameters.studyOverZonesEnabled || - parameters.studyOverZonesEnabled === false) - ) { - obj.value = parameters.studyOverZonesEnabled; - } - obj.type = "checkbox"; - this.parameters.push(obj); - } - - if (init.studyOverBoughtValue !== undefined) { - obj = { - name: "studyOverBought", - heading: stx.translateIf("OverBought"), - defaultValue: init.studyOverBoughtValue, - value: init.studyOverBoughtValue, - defaultColor: init.studyOverBoughtColor, - color: init.studyOverBoughtColor - }; - if (parameters && parameters.studyOverBoughtValue) - obj.value = parameters.studyOverBoughtValue; - if (parameters && parameters.studyOverBoughtColor) - obj.color = parameters.studyOverBoughtColor; - if (obj.color == "auto") obj.color = stx.defaultColor; - obj.type = "text"; - this.parameters.push(obj); - } - - if (init.studyOverSoldValue !== undefined) { - obj = { - name: "studyOverSold", - heading: stx.translateIf("OverSold"), - defaultValue: init.studyOverSoldValue, - value: init.studyOverSoldValue, - defaultColor: init.studyOverSoldColor, - color: init.studyOverSoldColor - }; - if (parameters && parameters.studyOverSoldValue) - obj.value = parameters.studyOverSoldValue; - if (parameters && parameters.studyOverSoldColor) - obj.color = parameters.studyOverSoldColor; - if (obj.color == "auto") obj.color = stx.defaultColor; - obj.type = "text"; - this.parameters.push(obj); - } - - if (!this.attributes.studyOverBoughtValue) - this.attributes.studyOverBoughtValue = {}; - if (!this.attributes.studyOverSoldValue) - this.attributes.studyOverSoldValue = {}; - } - } - - /* Automatic parameters such as panel and axis, if enabled */ - function selectObject(sourceObj) { - var options = {}; - var defaults = sourceObj.defaults; - var obj = { - name: sourceObj.name, - heading: stx.translateIf(sourceObj.label), - defaultValue: defaults[0], - value: sourceObj.value, - options: options, - type: "select" - }; - - for (var i = 0; i < defaults.length; i++) { - options[defaults[i]] = stx.translateIf(defaults[i]); - } - - if (sourceObj.color !== undefined) { - obj.defaultColor = stx.defaultColor; - obj.color = sourceObj.color; - } - - return obj; - } - function checkboxObject(sourceObj) { - var obj = { - name: sourceObj.name, - heading: stx.translateIf(sourceObj.label), - defaultValue: sourceObj.defaults, - value: sourceObj.value, - type: "checkbox" - }; - - return obj; - } - var panelSelect = (this.panelSelect = params.panelSelect), - axisSelect = (this.axisSelect = params.axisSelect); - function alias(panel) { - function format(p, i) { - return "Panel " + i.toString(); - } - if (panelSelect == "alias") { - var i = 1; - for (var p in stx.panels) { - if (p == panel) return format(p, i); - i++; - } - } - return panel; - } - // not allowed to pick panel or axis if we pop up the dialog before the study is added. - if (params.addWhenDone) axisSelect = panelSelect = false; - if (axisSelect || panelSelect) { - if (!sd) { - sd = CIQ.Studies.addStudy(stx, params.name, null, null, { - calculateOnly: true - }); - CIQ.Studies.removeStudy(stx, sd); - } - if (panelSelect) { - this.parameters.push( - selectObject({ - label: "Panel", - name: "panelName", - defaults: (function () { - var defaults = []; - defaults.push("Auto"); - for (var pnl in stx.panels) { - if (pnl != sd.panel || !parameters || !parameters.panelName) - defaults.push(alias(pnl)); - } - if (!stx.checkForEmptyPanel(sd.panel, true, sd)) - defaults.push("New panel"); - return defaults; - })(), - value: - parameters && parameters.panelName - ? alias(parameters.panelName) - : "Auto" - }), - checkboxObject({ - label: "Show as Underlay", - name: "underlay", - defaults: false, - value: sd.underlay || (sd.parameters && sd.parameters.underlayEnabled) - }) - ); - } - var myAxis = stx.getYAxisByName(panel, sd.name); - if (axisSelect) { - this.parameters.push( - selectObject({ - label: "Y-Axis", - name: "yaxisDisplay", - defaults: (function () { - var yaxes = panel.yaxisLHS.concat(panel.yaxisRHS), - defaults = []; - defaults.push("default", "right", "left", "none", "shared"); - for (var yax = 0; yax < yaxes.length; yax++) { - if (yaxes[yax] != myAxis) defaults.push(yaxes[yax].name); - } - return defaults; - })(), - value: - (parameters && parameters.yaxisDisplayValue) || - (myAxis && myAxis.position) || - (sd.panel != sd.name - ? "shared" - : panel.yAxis.position || "default"), - color: myAxis && myAxis.textStyle ? myAxis.textStyle : "auto" - }), - checkboxObject({ - label: "Invert Y-Axis", - name: "flipped", - defaults: false, - value: parameters - ? parameters.flippedEnabled - : myAxis - ? myAxis.flipped - : false - }) - ); - } - - hideTheField.call(this, "flippedEnabled", !myAxis && sd.panel != sd.name); - hideTheField.call(this, "underlayEnabled", libraryEntry.underlay); - hideTheField.call(this, "panelName", libraryEntry.seriesFN === null); - hideTheField.call( - this, - "yaxisDisplayValue", - libraryEntry.seriesFN === null || - (libraryEntry.yAxis && libraryEntry.yAxis.noDraw) - ); - } -}; - -/** - * Updates or adds the study represented by the DialogHelper. - * - * When a study has been added using this function, a study descriptor is stored in the `sd` - * property of the DialogHelper. - * - * When a study has been updated using this function, all DialogHelper properties, including `sd`, - * are updated to reflect the changes. However, other DialogHelper instances of the same study - * type are not updated. For example, the inputs, outputs, and parameters of a DialogHelper will - * not contain any new values as a result of another DialogHelper's update. - * - * @param {object} updates Contains values for the `inputs`, `outputs`, and `parameters` - * properties of the DialogHelper. - * - * @memberof CIQ.Studies.DialogHelper - * - * @example Add and update a study. - * // Add the study. - * let aroonSd = CIQ.Studies.addStudy(stxx, "Aroon"); - * - * // Create a DialogHelper. - * let dialogHelper = new CIQ.Studies.DialogHelper({ stx: stxx, sd: aroonSd }); - * - * // Move the study to the chart panel. - * dialogHelper.updateStudy({ parameters: { panelName: "chart" } }); - * - * // Move the study back to its own panel. - * dialogHelper.updateStudy({ parameters: { panelName: "New panel" } }); - * - * @example Add a customized study. - * let helper = new CIQ.Studies.DialogHelper({ stx: stxx, name: "AVWAP" }); - * helper.updateStudy({ inputs: { Field: "High" }, - * outputs: { VWAP: "#ff0" }, - * parameters: { panelName: "New Panel" } - * }); - * - * @example Update a study and get the updated study descriptor. - * let helper = new CIQ.Studies.DialogHelper({ stx: stxx, name: "Aroon" }); - * helper.updateStudy({ inputs: { Period: 60 } }); - * let updatedSd = helper.sd; - * - * @since 6.3.0 This DialogHelper instance is refreshed after an update; recreating it is no - * longer necessary. - */ -CIQ.Studies.DialogHelper.prototype.updateStudy = function (updates) { - var newParams = {}; - var sd = this.sd; - var libraryEntry = this.libraryEntry; - if (!libraryEntry) libraryEntry = {}; - if (!sd) sd = libraryEntry; - newParams.inputs = CIQ.clone(sd.inputs); - newParams.outputs = CIQ.clone(sd.outputs); - newParams.parameters = CIQ.clone(sd.parameters); - - // adjust date inputs for displayZone - this.adjustInputTimesForDisplayZone(updates); - - function dealias(panel) { - function extractPanelNumber(p) { - var match = p.match(/.* (\d)/); - return match && match[1]; - } - if (this.panelSelect == "alias") { - var i = extractPanelNumber(panel); - if (i) { - for (var p in this.stx.panels) { - if (!--i) return p; - } - } - } - return panel; - } - - if (updates.parameters && updates.parameters.panelName) { - updates.parameters.panelName = dealias.call( - this, - updates.parameters.panelName - ); - } - CIQ.extend(newParams, updates); - if (!newParams.parameters) newParams.parameters = {}; - if (newParams.inputs && newParams.inputs.id) { - sd = CIQ.Studies.replaceStudy( - this.stx, - newParams.inputs.id, - this.name, - newParams.inputs, - newParams.outputs, - newParams.parameters, - null, - sd.study - ); - } else { - sd = CIQ.Studies.addStudy( - this.stx, - this.name, - newParams.inputs, - newParams.outputs, - newParams.parameters, - null, - sd.study - ); - } - var newHelper = new CIQ.Studies.DialogHelper({ - stx: this.stx, - sd: sd, - axisSelect: this.axisSelect, - panelSelect: this.panelSelect - }); - for (var obj in newHelper) { - if (obj != "signal") this[obj] = newHelper[obj]; - } - this.signal *= -1; // signal a change to an observer -}; - -/** - * Adjust all date and time fields in the DialogHelper to use the display zone. - * - * This function can adjust both to and from the display zone depending on the presence of the second argument. - * When creating the DialogHelper, the second argument is null, and any date and time in the study descriptor's inputs is converted to display zone when stored in the DialogHelper's `inputs` property. - * When updating the DialogHelper, the second argument contains any changed fields. If a date or time has been changed, it is converted back from display zone so it can be stored correctly in the study descriptor. It is assumed that the updated date and time are in display zone already. - * The function adjusts the time by changing the `updates` object if it is passed, or the `inputs` property if it is not. - * - * In the example below, it is assumed that there are input fields named "Anchor Date" and "Anchor Time". Whenever you want to set up an input field with date and time, use this convention: - * Name both fields the same name and add " Date" to one and " Time" to the other. - * - * @param {Object} [updates] If updating, it should contain an object with updates to the `inputs` object used in {@link CIQ.Studies.addStudy}. - * @memberof CIQ.Studies.DialogHelper - * @example - * var helper=new CIQ.Studies.DialogHelper({sd:sd, stx:stx}); - * var updates={inputs:{"Anchor Time":"06:00"}}; - * helper.adjustInputTimesForDisplayZone(updates}); - * - * @since 6.3.0 - */ -CIQ.Studies.DialogHelper.prototype.adjustInputTimesForDisplayZone = function ( - updates -) { - if (this.stx.displayZone) { - // adjust date inputs for displayZone - for (var dtField = 0; dtField < this.dateTimeInputs.length; dtField++) { - var field = this.dateTimeInputs[dtField]; - // build the date string - var i, - newDate, - newTime, - thisInput, - dtStr = ""; - if (updates && updates.inputs) { - newDate = updates.inputs[field + " Date"]; - newTime = updates.inputs[field + " Time"]; - if (newDate) dtStr = newDate; - if (newTime) dtStr += newTime; - } - for (i = 0; i < this.inputs.length; i++) { - thisInput = this.inputs[i]; - if (!newDate && newDate !== "" && thisInput.name == field + " Date") - dtStr = thisInput.value + dtStr; - else if ( - !newTime && - newTime !== "" && - thisInput.name == field + " Time" - ) - dtStr += thisInput.value; - } - dtStr = dtStr.replace(/\D/g, ""); - if (dtStr.length < 12) return; // date only - // create date object and adjust - var datetime = CIQ.strToDateTime(dtStr); - var adjDate; - if (!isNaN(datetime.valueOf())) { - if (updates) { - if (!updates.inputs) updates.inputs = {}; - adjDate = CIQ.convertTimeZone(datetime, this.stx.displayZone); - updates.inputs[field + " Date"] = CIQ.yyyymmdd(adjDate); - updates.inputs[field + " Time"] = CIQ.hhmmss(adjDate); - } else { - adjDate = CIQ.convertTimeZone(datetime, null, this.stx.displayZone); - for (i = 0; i < this.inputs.length; i++) { - thisInput = this.inputs[i]; - if (thisInput.name == field + " Date") - thisInput.value = CIQ.yyyymmdd(adjDate); - if (thisInput.name == field + " Time") - thisInput.value = CIQ.hhmmss(adjDate); - } - } - } - } - } -}; - -/** - * Prepares a study descriptor for use by assigning default calculation or display functions if required and configuring the outputMap - * which is used internally to determine the color for each output. - * @private - * @param {CIQ.ChartEngine} stx A chart object - * @param {object} study The study library entry - * @param {CIQ.Studies.StudyDescriptor} sd The study descriptor being prepared - * @memberOf CIQ.Studies - * @since - * - 6.2.0 Added `calculateOnly` parameter. - * - 7.1.0 Removed `calculateOnly` parameter. Moved rejigger functionality out and into - * [replaceStudy]{@link CIQ.Studies.replaceStudy}. - */ -CIQ.Studies.prepareStudy = function (stx, study, sd) { - if (typeof study.calculateFN == "undefined") study.useRawValues = true; - //if(typeof(study.seriesFN)=="undefined") study.seriesFN=CIQ.Studies.displaySeriesAsLine; - - // Unless overridden by the calculation function we assume the convention that the dataSet entries - // will begin with the output name such as "RSI rsi (14)" - if (CIQ.isEmpty(sd.outputMap)) { - for (var i in sd.outputs) { - if (study.useRawValues) { - sd.outputMap[i] = i; - } else { - sd.outputMap[i + " " + sd.name] = i; - } - } - } -}; - -/** - * Fixes any derived studies or drawings that were based off of a study that has just changed. - * This is called after the study has been modified. - * - * For instance a moving average on another overlay, or a moving average on an RSI.
- * The panel name needs to change and the input "Field". - * @private - * @param {CIQ.ChartEngine} stx The stx instance - * @param {CIQ.Studies.StudyDescriptor} masterStudy The old study whose dependents are to be rejiggered - * @param {string} newID The new ID for the underlying study - * @memberof CIQ.Studies - * @since - * - 5.2.0 Removed `panelID` argument. - * - 7.0.0 Also fixes drawings. - * - 7.1.0 Changed second argument. - */ -CIQ.Studies.rejiggerDerivedStudies = function (stx, masterStudy, newID) { - var replaceID = masterStudy.name; - var oldPanel = masterStudy.panel; - var dependents = masterStudy.getDependents(stx); - for (var s = 0; s < dependents.length; s++) { - var st = dependents[s]; - var inputs = CIQ.clone(st.inputs); - var oldId = inputs.id; - if (!oldId) continue; - var stNeedsReplacement = false; - var fieldInputs = CIQ.Studies.getFieldInputs(st); - for (var f = 0; f < fieldInputs.length; f++) { - inputs[fieldInputs[f]] = inputs[fieldInputs[f]].replace(replaceID, newID); - } - var sd = CIQ.Studies.replaceStudy( - stx, - oldId, - st.type, - inputs, - st.outputs, - CIQ.extend(st.parameters, { rejiggering: true }), - null, - st.study - ); - delete sd.parameters.rejiggering; - } -}; - -/** - * Removes any series that the study is referencing. - * - * @param {object} sd Study descriptor. - * @param {CIQ.ChartEngine} stx The chart engine. - * - * @memberof CIQ.Studies - * @since - * - 3.0.0 - * - 3.0.7 Changed `name` argument to take a study descriptor. - * - 3.0.7 Added required `stx` argument. - */ -CIQ.Studies.removeStudySymbols = function (sd, stx) { - if (sd.series) { - for (var s in sd.series) { - stx.deleteSeries(sd.series[s], null, { action: "remove-study" }); - } - } - //stx.draw(); -}; - -/** - * Replaces an existing study with new inputs, outputs and parameters. - * - * When using this method a study's position in the stack will remain the same. Derived (child) studies will shift to use the new study as well - * @param {CIQ.ChartEngine} stx The chart object - * @param {string} id The id of the current study. If set, then the old study will be replaced - * @param {string} type The name of the study (out of the studyLibrary) - * @param {object} [inputs] Inputs for the study instance. Default is those defined in the studyLibrary. - * @param {object} [outputs] Outputs for the study instance. Default is those defined in the studyLibrary. - * @param {object} [parameters] additional custom parameters for this study if supported or required by that study - * @param {string} [panelName] Optionally specify the panel. If not specified then an attempt will be made to locate a panel based on the input id or otherwise created if required. - * @param {object} [study] Optionally supply a study definition, overriding what may be found in the study library - * @return {object} A study descriptor which can be used to remove or modify the study. - * @since 3.0.0 Added `study` parameter. - * @memberof CIQ.Studies - */ -CIQ.Studies.replaceStudy = function ( - stx, - id, - type, - inputs, - outputs, - parameters, - panelName, - study -) { - if (!parameters) parameters = {}; - if (id) parameters.replaceID = id; - id = parameters.replaceID; - var sd = stx.layout.studies[id]; - CIQ.Studies.removeStudySymbols(sd, stx); - if (sd.attribution) stx.removeFromHolder(sd.attribution.marker); - if (stx.quoteDriver) stx.quoteDriver.updateSubscriptions(); - var newSD; - if (inputs) { - if (inputs.id == inputs.display) delete inputs.display; - delete inputs.id; - } - newSD = CIQ.Studies.addStudy( - stx, - type, - inputs, - outputs, - parameters, - panelName, - study - ); - newSD.highlight = sd.highlight; - newSD.uniqueId = sd.uniqueId; - - // move the new study into the place of the old study - var s, - tmp = {}; - for (s in stx.layout.studies) { - if (s == id) tmp[newSD.name] = newSD; - else tmp[s] = stx.layout.studies[s]; - } - stx.layout.studies = tmp; - tmp = {}; - for (s in stx.overlays) { - if (s == id) { - if (newSD.overlay || newSD.underlay) tmp[newSD.name] = newSD; - } else tmp[s] = stx.overlays[s]; - } - stx.overlays = tmp; - if (!stx.overlays[newSD.name] && (newSD.overlay || newSD.underlay)) - stx.addOverlay(newSD); - - stx.checkForEmptyPanel(sd.panel); // close any evacuated panels - - if (!parameters.rejiggering) { - // done to initialize yAxes on panels - stx.initializeDisplay(stx.chart); - - // Rename any overlays that relied on the old panel ID name, for instance a moving average on RSI(14) - CIQ.Studies.rejiggerDerivedStudies(stx, sd, newSD.inputs.id, newSD.panel); - - stx.changeOccurred("layout"); - if ( - !stx.currentlyImporting && - !parameters.calculateOnly && - newSD.chart.dataSet - ) { - // silent mode while importing - stx.createDataSet(null, newSD.chart); - } - stx.draw(); - } - CIQ.transferObject(sd, newSD); // we do this so the developer retains use of his handle to the study - stx.layout.studies[newSD.name] = sd; - stx.overlays[newSD.name] = sd; - stx.chart.state.studies.sorted = null; - return sd; -}; - -/** - * Adds or replaces a study on the chart. - * - * A [layout change event]{@link CIQ.ChartEngine~layoutEventListener} is triggered when this occurs. - * - * See {@tutorial Using and Customizing Studies} for more details. - * - *

Example: - * - * Optionally you can [define an edit event listeners]{@link CIQ.ChartEngine#addEventListener} to call a custom function that can handle initialization of a dialog box for editing studies. - * - Use [studyPanelEditEventListener]{@link CIQ.ChartEngine~studyPanelEditEventListener} to link the cog wheel on study panels to your desired edit menu/functionality. - * - Use [studyOverlayEditEventListener]{@link CIQ.ChartEngine~studyOverlayEditEventListener} to link the right click on study overlays to your desired edit menu/functionality. - * - All studies will use the same function set by the event listeners. - * - If there are no event listeners set, the edit study buttons/functionality will not appear. - * - The 'Study Edit' feature is standard functionality in the advanced sample template. - * - See `Examples` section for exact function parameters and return value requirements.
- * - Please note that these listeners must be set **before** you call importLayout. Otherwise your imported studies will not have an edit capability. - * - * Use the {@link CIQ.Tooltip} addOn if you wish to display values on mouse hover.
- * Alternatively, you can create your own Heads-Up-Display (HUD) using this tutorial: {@tutorial Custom Heads-Up-Display (HUD)} - * - * @param {CIQ.ChartEngine} stx The chart object - * @param {string} type The name of the study (object key on the {@link CIQ.Studies.studyLibrary}) - * @param {object} [inputs] Inputs for the study instance. Default is those defined in the studyLibrary. Note that if you specify this object, it will be combined with (override) the library defaults. To bypass a library default, set that field to null. - * @param {string} [inputs.id] The id of the current study. If set, then the old study will be replaced - * @param {string} [inputs.display] The display name of the current study. If not set, a name generated by {@link CIQ.Studies.prettyDisplay} will be used. Note that if the study descriptor defines a `display` name, the study descriptor name will allays override this parameter. - * @param {object} [outputs] Outputs for the study instance. Default is those defined in the studyLibrary. Values specified here will override those in the studyLibrary. - * @param {object} [parameters] Additional custom parameters for this study if supported or required by that study. Default is those defined in the {@link CIQ.Studies.studyLibrary}. - * @param {object} [parameters.replaceID] If `inputs.id` is specified, this value can be used to set the new ID for the modified study( will display as the study name on the study panel). If omitted the existing ID will be preserved. - * @param {object} [parameters.display] If this is supplied, use it to form the full study name. Otherwise `studyName` will be used. Is both `inputs.display` and `parameters.display` are set, `inputs.display` will always take precedence.
ie: if custom name is 'SAMPLE', the unique name returned would resemble "SAMPLE(param1,param2,param3,...)-X". - * @param {object} [parameters.calculateOnly] Only setup the study for calculations and not display. If this is supplied, UI elements will not be added. - * @param {string} [panelName] Optionally specify the panel.
This must be an existing panel (see example).
If set to "New panel" a new panel will be created for the study. If not specified or an invalid panel name is provided, then an attempt will be made to locate a panel based on the input id or otherwise created if required. Multiple studies can be overlaid on any panel. - * @param {object} [study] Study definition, overriding what may be found in the study library - * @return {CIQ.Studies.StudyDescriptor} A study descriptor which can be used to remove or modify the study. - * @since - * - 3.0.0 Added `study` parameter. - * - 5.1.1 Added `parameters.display`. If this parameter is supplied, use it to form the full study name. - * - 5.2.0 Multiple studies can be overlaid on any panel using the `panelName` parameter. - * - 6.3.0 `panelName` argument is deprecated but maintained for backwards compatibility. Use `parameters.panelName` instead. - * - 7.1.0 Changed specification for a new panel in `panelName` from "Own panel" to "New panel". - * @memberof CIQ.Studies - * @example Add a volume underlay study with custom colors: - * CIQ.Studies.addStudy(stxx, "vol undr", {}, {"Up Volume":"#8cc176","Down Volume":"#b82c0c"}); - * @example Define the edit function for study Panels: - * var params={stx:stx,sd:sd,inputs:inputs,outputs:outputs, parameters:parameters}; - * stxx.addEventListener("studyPanelEdit", function(studyData){ - * // your code here - * }); - * @example Define the edit function for study overlays: - * stxx.addEventListener("studyOverlayEdit", function(studyData){ - * CIQ.alert(studyData.sd.name); - * var helper=new CIQ.Studies.DialogHelper({name:studyData.sd.type,stx:studyData.stx}); - * console.log('Inputs:',JSON.stringify(helper.inputs)); - * console.log('Outputs:',JSON.stringify(helper.outputs)); - * console.log('Parameters:',JSON.stringify(helper.parameters)); - * // call your menu here with the data returned in helper - * // modify parameters as needed and call addStudy or replaceStudy - * }); - * @example Add an Aroon study with a custom display name: - * CIQ.Studies.addStudy(stxx, "Aroon",null,null,{display:'Custom Name'}); - * - * @example Add multiple studies to the same panel. - * // create your panel - * stxx.createPanel('New Panel', 'new_panel') - * // add your studies to it. - * CIQ.Studies.addStudy(stxx, "ma", null, null, {panelName:'new_panel'}); - * CIQ.Studies.addStudy(stxx, "Aroon", null, null, {panelName:'new_panel'}); - */ -CIQ.Studies.addStudy = function ( - stx, - type, - inputs, - outputs, - parameters, - panelName, - study -) { - var libraryEntry = study ? study : CIQ.Studies.studyLibrary[type]; - - if (!parameters) parameters = {}; - if (libraryEntry) { - if (libraryEntry.inputs) { - // Default to the library inputs - var libraryInputs = CIQ.clone(libraryEntry.inputs); - for (var i in libraryInputs) { - // But set any arrays to the default (the first item in the array) - if (libraryInputs[i] instanceof Array) { - if ( - libraryEntry.attributes && - libraryEntry.attributes[i] && - libraryEntry.attributes[i].defaultSelected - ) { - libraryInputs[i] = libraryEntry.attributes[i].defaultSelected; - } else { - libraryInputs[i] = libraryInputs[i][0]; - } - } - } - // Now override the library inputs with anything the user passed in - inputs = CIQ.extend(libraryInputs, inputs); - } - if (libraryEntry.outputs) { - outputs = CIQ.extend(CIQ.clone(libraryEntry.outputs), outputs); - } - var libraryParameters = libraryEntry.parameters; - if (libraryParameters && libraryParameters.init) { - parameters = CIQ.extend(CIQ.clone(libraryParameters.init), parameters); - } - - if (libraryParameters && !parameters.display) { - parameters.display = libraryParameters.display; - } - } - - if (!inputs) inputs = CIQ.clone(CIQ.Studies.DEFAULT_INPUTS); - if (!outputs) outputs = CIQ.clone(CIQ.Studies.DEFAULT_OUTPUTS); - if (!parameters.chartName) parameters.chartName = "chart"; - if (parameters.panelName == "Auto" || parameters.panelName == "Default panel") - parameters.panelName = ""; - - if (inputs.Period < 1) inputs.Period = 1; // periods can't be less than one candle. This is a general safety check. Each study should have a check or add input validation. - - var sd = null; - if (!stx.layout.studies) stx.layout.studies = {}; - if (libraryEntry && libraryEntry.initializeFN) { - sd = libraryEntry.initializeFN( - stx, - type, - inputs, - outputs, - parameters, - panelName, - study - ); - } else { - sd = CIQ.Studies.initializeFN( - stx, - type, - inputs, - outputs, - parameters, - panelName, - study - ); - } - if (!sd) { - console.log( - "CIQ.Studies.addStudy: initializeFN() returned null for " + type - ); - return; - } - study = sd.study; - sd.chart = stx.charts[parameters.chartName]; - sd.type = type; - sd.permanent = study.permanent; - sd.customLegend = study.customLegend; - sd.uniqueId = CIQ.uniqueID(); - CIQ.Studies.prepareStudy(stx, study, sd); - - var state = stx.chart.state.studies; - if (!state) state = stx.chart.state.studies = {}; - state.sorted = null; // nullify sort order - - var noDraw; - if (!parameters.replaceID) { - stx.layout.studies[sd.inputs.id] = sd; - if (sd.overlay || sd.underlay) stx.addOverlay(sd); - if ( - !stx.currentlyImporting && - !parameters.calculateOnly && - sd.chart.dataSet - ) { - // silent mode while importing - stx.createDataSet(null, sd.chart); - } - } else { - noDraw = true; - delete parameters.replaceID; - } - //if(!stx.currentlyImporting) CIQ.Studies.checkSymbolChanged(stx, sd, "add-study"); - if (stx.quoteDriver) stx.quoteDriver.updateSubscriptions(); - if (parameters.calculateOnly) { - stx.changeOccurred("layout"); - return sd; - } - - var panel = stx.panels[sd.panel]; - var hasEditCallback = false; - var isPanelStudy = !(sd.overlay || sd.underlay); - - if (isPanelStudy && study.horizontalCrosshairFieldFN) { - panel.horizontalCrosshairField = study.horizontalCrosshairFieldFN(stx, sd); - } - - if (stx.editCallback) { - hasEditCallback = true; - } else if (isPanelStudy) { - if ( - stx.callbackListeners.studyPanelEdit && - stx.callbackListeners.studyPanelEdit.length - ) - hasEditCallback = true; - } else { - if ( - stx.callbackListeners.studyOverlayEdit && - stx.callbackListeners.studyOverlayEdit.length - ) - hasEditCallback = true; - } - - if (hasEditCallback) { - parameters.editMode = true; - var hasInput = false; - for (var input in sd.inputs) { - if (input == "id") continue; - if (input == "display") continue; - hasInput = true; - break; - } - if (!hasInput) { - for (var output in sd.outputs) { - hasInput = true; - break; - } - } - if (hasInput) { - var editFunction; - if (typeof sd.study.edit != "undefined") { - if (sd.study.edit) { - editFunction = (function (stx, sd, inputs, outputs) { - return function () { - CIQ.clearCanvas(stx.chart.tempCanvas, stx); // clear any drawing in progress - sd.study.edit(sd, { - stx: stx, - inputs: inputs, - outputs: outputs, - parameters: parameters - }); - }; - })(stx, sd, inputs, outputs, parameters); - stx.setPanelEdit(panel, editFunction); - sd.editFunction = editFunction; - } - } else if (!isPanelStudy) { - editFunction = (function (stx, sd, inputs, outputs, parameters) { - return function (forceEdit) { - CIQ.clearCanvas(stx.chart.tempCanvas, stx); // clear any drawing in progress - stx.dispatch("studyOverlayEdit", { - stx: stx, - sd: sd, - inputs: inputs, - outputs: outputs, - parameters: parameters, - forceEdit: forceEdit - }); - }; - })(stx, sd, inputs, outputs, parameters); - sd.editFunction = editFunction; - } else { - if (stx.editCallback) { - // deprecated legacy support - editFunction = (function (stx, sd, inputs, outputs) { - return function () { - var dialogDiv = stx.editCallback(stx, sd); - CIQ.clearCanvas(stx.chart.tempCanvas, stx); // clear any drawing in progress - CIQ.Studies.studyDialog(stx, type, dialogDiv, { - inputs: inputs, - outputs: outputs, - parameters: parameters - }); - }; - })(stx, sd, inputs, outputs, parameters); - if (panel.name != "chart") { - stx.setPanelEdit(panel, editFunction); - } - } else { - editFunction = (function (stx, sd, inputs, outputs, parameters) { - return function () { - CIQ.clearCanvas(stx.chart.tempCanvas, stx); // clear any drawing in progress - stx.dispatch("studyPanelEdit", { - stx: stx, - sd: sd, - inputs: inputs, - outputs: outputs, - parameters: parameters - }); - }; - })(stx, sd, inputs, outputs, parameters); - if (panel.name != "chart") { - stx.setPanelEdit(panel, editFunction); - sd.editFunction = editFunction; - } - } - } - } - } - - stx.changeOccurred("layout"); - if (!noDraw) stx.draw(); // we put this extra draw here in case of study parameters which affect the appearance of the y-axis, since adding a y-axis calls draw() but before the layout has changed. - return sd; -}; - -/** - * Removes a study from the chart (and panel if applicable) - * - * @param {CIQ.ChartEngine} stx A chart object - * @param {CIQ.Studies.StudyDescriptor} sd A study descriptor returned from {@link CIQ.Studies.addStudy} - * @memberOf CIQ.Studies - */ -CIQ.Studies.removeStudy = function (stx, sd) { - var sPanel = stx.panels[sd.panel]; - var yAxisName = sPanel && sPanel.yAxis.name; - if (sd.overlay || sd.underlay) { - stx.removeOverlay(sd.name); - } - var panel = stx.panels[sd.panel]; - if (sd.attribution) stx.removeFromHolder(sd.attribution.marker); - delete stx.layout.studies[sd.name]; - if (panel && !stx.checkForEmptyPanel(panel)) { - if (yAxisName == sd.name) { - // promote an overlay to own the panel (and axis maybe) - stx.electNewPanelOwner(panel); - } - var studyAxis = stx.getYAxisByName(sd.panel, sd.name); - if (studyAxis) { - studyAxis.name = studyAxis.studies[1] || studyAxis.renderers[0]; - } - } - stx.draw(); - stx.resizeChart(); -}; - -/** - * Returns the panel which the study's Field input value references. - * - * For example, a ma (Moving Average) study with a Field of Volume may return the Volume panel, since that is the panel - * where the Field input value may be found.. - * @param {CIQ.ChartEngine} stx The charting object - * @param {CIQ.Studies.StudyDescriptor} sd The study descriptor - * @return {string} Name of panel containing the output field corresponding to the Field input value, null if not found - * @memberof CIQ.Studies - * @since 6.3.0 - */ -CIQ.Studies.getPanelFromFieldName = function (stx, sd) { - var fieldInputs = CIQ.Studies.getFieldInputs(sd); - if (!fieldInputs.length) return null; - var s = stx.layout.studies; - if (!s) return null; - - var studyPanelMap = {}; - for (var n in s) { - for (var i in s[n].outputMap) studyPanelMap[i] = s[n].panel; - } - for (var f = 0; f < fieldInputs.length; f++) { - var field = sd.inputs[fieldInputs[f]]; - if (field) { - var mapEntry = studyPanelMap[field]; - if (mapEntry) return mapEntry; - } - } - return null; -}; - -/** - * Computes a hash of the study library keys. The hash can be assigned to a property so that `studyLibrary` changes can be observed. - * This function is automatically called in the draw loop. - * - * @return {string} A hash of `studyLibrary` keys. - * @memberof CIQ.Studies - * @since 7.2.0 - */ -CIQ.Studies.createLibraryHash = function () { - return Object.keys(CIQ.Studies.studyLibrary).join("|"); // create a hash so we can observe the studyLibrary! -}; - -/** - * Animation Loop - * - * This method displays all of the studies for a chart. It is called from within the chart draw() loop. - * @param {CIQ.ChartEngine} stx The charting object - * @param {CIQ.ChartEngine.Chart} chart Which chart to display studies for - * @param {Boolean} [underlays=false] If set to true then underlays only will be displayed, otherwise underlays will be skipped - * @memberof CIQ.Studies - */ -CIQ.Studies.displayStudies = function (stx, chart, underlays) { - if (underlays) chart.studyLibraryHash = CIQ.Studies.createLibraryHash(); - var s = stx.layout.studies; - if (!s) return; - var permanentPanel = {}; // local map of permanent panels - permanentPanel[chart.name] = true; // no X on chart panel - for (var n in s) { - var sd = s[n]; - var study = sd.study; - if (!study) continue; - var isUnderlay = - sd.underlay || (sd.parameters && sd.parameters.underlayEnabled); - if ((underlays && !isUnderlay) || (!underlays && isUnderlay)) continue; - - var rendererConfigs = CIQ.clone(study.renderer); - if (rendererConfigs && !(rendererConfigs instanceof Array)) - rendererConfigs = [rendererConfigs]; - var panel = stx.panels[sd.panel]; - if (panel) { - if (panel.chart != chart) continue; - if (panel.hidden) continue; - if (!permanentPanel[panel.name]) { - var permanent = sd.permanent || !stx.manageTouchAndMouse; - if (panel.closeX) { - if (permanent) panel.closeX.style.display = "none"; - } else if (panel.close) { - if (permanent) panel.close.style.display = "none"; - } - if (panel.edit) { - if (permanent) panel.edit.style.display = "none"; - } - permanentPanel[panel.name] = permanent; - } - } else { - //orphaned panel study, kill it on import - if (stx.currentlyImporting) delete s[n]; - continue; - } - - var quotes = sd.chart.dataSegment; // Find the appropriate data to drive this study - - // change the panel if it's an overlay and the underlying field has changed - if ( - sd.panel == sd.parameters.chartName && - (!sd.parameters || !sd.parameters.panelName) - ) { - var newPanel = CIQ.Studies.getPanelFromFieldName(stx, sd); - if (newPanel && sd.panel != newPanel) sd.panel = newPanel; - } - if (typeof study.seriesFN == "undefined") { - // null means don't display, undefined means display by default as a series - if (rendererConfigs) { - if (!sd.overlay) CIQ.Studies.createYAxis(stx, sd, quotes, panel); - for (var r = 0; r < rendererConfigs.length; r++) { - var params = rendererConfigs[r]; - // Get the input-specific output name from the outputMap. At this point params.field is just the output name, - // without any inputs. For example, "RSI" vs "RSI (14)". Here we set it to the actual name used in dataSegment. - for (var om in sd.outputMap) { - if (sd.outputMap[om] == params.field) params.field = om; - } - if (!params.field) continue; - params.panel = sd.panel; - var binding = params.binding; - // Binding is the ability to attach the color chosen by the user to a particular renderer property. - if (binding) { - for (var m in binding) { - var color = CIQ.Studies.determineColor(sd.outputs[binding[m]]); - if (color && color != "auto") params[m] = color; - /*For future implementation - if(typeof(sd.outputs[binding[m]])=="object"){ - params.pattern=sd.outputs[binding[m]].pattern; - params.width=sd.outputs[binding[m]].width; - }*/ - } - } - params.yAxis = null; // not allowed to specify y axis in these renderers - var renderer = CIQ.Renderer.produce(params.type, params); - renderer.stx = stx; - renderer.attachSeries(null, params).draw(); - } - } else { - CIQ.Studies.displaySeriesAsLine(stx, sd, quotes); - } - if (panel) CIQ.Studies.displayError(stx, sd); - } else { - if (study.seriesFN) { - if (panel) { - study.seriesFN(stx, sd, quotes); - CIQ.Studies.displayError(stx, sd); - } - } - } - } -}; - -/** - * Displays a watermark on a panel for a study with `sd.error set`. - * - * The `sd.error` property can be set to true, which will display the default message "Not enough data to compute XXX", - * or it can be set to a custom string which will be displayed as supplied. - * - * @param {CIQ.ChartEngine} stx The charting object. - * @param {CIQ.Studies.StudyDescriptor} sd The study descriptor. - * @param {Object} [params] Additional options to customize the watermark. - * @param {string} [params.panel] Name of the panel on which to display the error, defaults to `sd.panel`. - * @param {string} [params.h] Watermark horizontal position. - * @param {string} [params.v] Watermark vertical position. - * @memberof CIQ.Studies - * @since - * - 3.0.0 - * - 4.0.0 Displays one error per panel. Added `params` object. - * - 7.3.0 Errors without `params` or in center bottom, use - * {@link CIQ.ChartEngine#displayErrorAsWatermark} instead of - * {@link CIQ.ChartEngine#watermark}, which stacks errors vertically to prevent errors - * overlaying other errors. Any other positioning is deprecated and results in multiple - * errors at that location getting stacked on the z-axis. - */ -CIQ.Studies.displayError = function (stx, sd, params) { - if (!sd.error) return; - - var panelKey = params && params.panel ? params.panel : sd.panel; - var errorText = - sd.error === true - ? stx.translateIf("Not enough data to compute ") + - stx.translateIf(sd.study.name) - : stx.translateIf(sd.error); - - // backwards compatability - if (params && (params.h !== "center" || params.v !== "bottom")) { - stx.watermark(panelKey, params); - return; - } - - stx.displayErrorAsWatermark(panelKey, errorText); -}; -/** - * Convenience function for determining the min and max for a given data point. - * - * @param {CIQ.ChartEngine} stx The chart - * @param {string} name The field to evaluate - * @param {array} quotes The array of quotes to evaluate (typically dataSet, scrubbed or dataSegment) - * @memberof CIQ.Studies - * @return {object} Object containing the min and max data point values - */ -CIQ.Studies.calculateMinMaxForDataPoint = function (stx, name, quotes) { - var min = Number.MAX_VALUE; - var max = Number.MAX_VALUE * -1; - for (var i = 0; i < quotes.length; i++) { - var m = quotes[i][name]; - if (m === null || typeof m == "undefined") continue; - if (isNaN(m)) continue; - min = Math.min(m, min); - max = Math.max(m, max); - } - return { min: min, max: max }; -}; - -/** - * Retrieves parameters to be used to draw the Y Axis, retrieved from the study library. - * - * If a range is set in the study library, the yAxis high and low properties are set.
- * Invoked by {@link CIQ.ChartEngine.renderYAxis} before createYAxis - * @param {CIQ.ChartEngine} stx The chart object - * @param {CIQ.ChartEngine.YAxis} yAxis The axis to act upon - * @return {object} y-axis parameters such as noDraw, range, and ground - * @memberof CIQ.Studies - * @since 5.2.0 - */ -CIQ.Studies.getYAxisParameters = function (stx, yAxis) { - var parameters = {}; - var sd = stx.layout.studies && stx.layout.studies[yAxis.name]; - if (sd) { - var study = sd.study; - if (study.yaxis || study.yAxisFN) { - parameters.noDraw = true; - } else { - // If zones are enabled then we don't want to draw the yAxis - if (study.parameters && study.parameters.excludeYAxis) - parameters.noDraw = true; - parameters.ground = study.yAxis && study.yAxis.ground; - if (yAxis) { - if (study.range != "bypass") { - if (study.range == "0 to 100") parameters.range = [0, 100]; - else if (study.range == "-1 to 1") parameters.range = [-1, 1]; - else { - if (study.range == "0 to max") { - parameters.range = [0, Math.max(0, yAxis.high)]; - } else if (study.centerline || study.centerline === 0) { - parameters.range = [ - Math.min(study.centerline, yAxis.low), - Math.max(study.centerline, yAxis.high) - ]; - } - } - } - if (parameters.range) { - yAxis.low = parameters.range[0]; - yAxis.high = parameters.range[1]; - } - if (sd.min) yAxis.min = sd.min; - if (sd.max) yAxis.max = sd.max; - if (sd.parameters && sd.parameters.studyOverZonesEnabled) - parameters.noDraw = true; - } - } - } - return parameters; -}; - -/** - * studyOverZones will be displayed and Peaks & Valleys will be filled if corresponding thresholds are set in the study library as follows: - * ``` - * "parameters": { - * init:{studyOverZonesEnabled:true, studyOverBoughtValue:80, studyOverBoughtColor:"auto", studyOverSoldValue:20, studyOverSoldColor:"auto"} - * } - * ``` - * Invoked by {@link CIQ.ChartEngine.renderYAxis} after createYAxis - * @param {CIQ.ChartEngine} stx The chart object - * @param {CIQ.ChartEngine.YAxis} yAxis The axis to draw upon - * @memberof CIQ.Studies - * @since 5.2.0 - */ -CIQ.Studies.doPostDrawYAxis = function (stx, yAxis) { - for (var s in stx.layout.studies) { - var sd = stx.layout.studies[s]; - var panel = stx.panels[sd.panel]; - if (!panel || panel.hidden) continue; - var studyAxis = sd.getYAxis(stx); - if (studyAxis != yAxis) continue; - var study = sd.study; - if (yAxis.name == sd.name) { - // only draw the custom yAxis for a panel study, not an overlay - if (study.yaxis) study.yaxis(stx, sd); // backward compatibility - if (study.yAxisFN) study.yAxisFN(stx, sd); // Use yAxisFN for forward compatibility - } - CIQ.Studies.drawZones(stx, sd); - - if (!sd.error) { - var centerline = study.centerline; - if ( - centerline || - centerline === 0 || - (centerline !== null && yAxis.highValue > 0 && yAxis.lowValue < 0) - ) { - CIQ.Studies.drawHorizontal(stx, sd, null, centerline || 0, yAxis); - } - } - } -}; - -/** - * Displays a single or group of series as lines in the study panel using {@link CIQ.Studies.displayIndividualSeriesAsLine} - * - * One series per output field declared in the study library will be displayed.
- * It expects the 'quotes' array to have data fields for each series with keys in the outputMap format: - * ``` - * 'output name from study library'+ " " + sd.name - * ``` - * For most custom studies this function will do the work for you. - * @param {CIQ.ChartEngine} stx The chart object - * @param {CIQ.Studies.StudyDescriptor} sd The study descriptor. See {@link CIQ.Studies.displayIndividualSeriesAsLine} for accepted `sd` parameters. - * @param {array} quotes The set of quotes (dataSegment) - * @memberof CIQ.Studies - * @example - * var study = { - * overlay: true, - * yAxis: {}, - * parameters: { - * plotType: 'step', - * }, - * seriesFN: function(stx, sd, quotes){ - * sd.extendToEnd=false; - * sd.gaplines=false, - * CIQ.Studies.displaySeriesAsLine(stx, sd, quotes); - * } - * }; - * CIQ.Studies.addStudy(stxx, "Vol", {}, {"Volume": "green"}, null, null, study); - */ -CIQ.Studies.displaySeriesAsLine = function (stx, sd, quotes) { - if (!quotes.length) return; - var panel = stx.panels[sd.panel]; - if (!panel || panel.hidden) return; - - for (var i in sd.outputMap) { - CIQ.Studies.displayIndividualSeriesAsLine(stx, sd, panel, i, quotes); - } -}; - -/** - * Displays a single or group of series as histogram in the study panel. - * - * It expects the 'quotes' array to have data fields for each series with keys in the outputMap - * format: - * ``` - * 'output name from study library'+ " " + sd.name - * ``` - * - * It takes into account the following study fields (see {@link CIQ.ChartEngine#drawHistogram} - * for details): - * - `sd.inputs.HistogramType` — "overlaid", "clustered", or "stacked". Default "overlaid". - * - `sd.outputs` — Can contain a color string or an object containing `{color, opacity}`. - * Default opacity ".3". - * - `sd.parameters.widthFactor` — Default ".5". - * - * @param {CIQ.ChartEngine} stx The chart object. - * @param {CIQ.Studies.StudyDescriptor} sd The study descriptor. - * @param {array} quotes The set of quotes (`dataSegment`). - * - * @memberof CIQ.Studies - * @since 7.0.0 No longer supports `sd.inputs.HeightPercentage`. - * Use {@link CIQ.ChartEngine.YAxis#heightFactor} instead. - * - * @example - * Adds a study panel that will display the High and Low values from the masterData as a - * clustered histogram study. - * CIQ.Studies.studyLibrary["Plot High Low"]={ - * "seriesFN": CIQ.Studies.displaySeriesAsHistogram, - * inputs:{"HistogramType":["clustered","stacked","overlaid"]}, - * outputs:{"High":"blue","Low":{color:"red",opacity:0.7}, - * parameters:{"widthFactor":0.5}, - * range: "0 to max", - * yAxis:{"ground":true,"initialMarginTop":0,"zoom":0, "heightFactor":0.5} - * }; - * CIQ.Studies.addStudy(stxx, "Plot High Low"); - */ -CIQ.Studies.displaySeriesAsHistogram = function (stx, sd, quotes) { - if (!quotes.length) return; - var panel = stx.panels[sd.panel]; - if (!panel) return; - if (panel.hidden) return; - - var seriesParam = []; - for (var i in sd.outputMap) { - var output = sd.outputs[sd.outputMap[i]]; - if (!output) continue; - var opacity = 0.3; - if (typeof output == "object") { - opacity = output.opacity; - output = output.color; - } - var series = { - field: i, - fill_color_up: output, - border_color_up: output, - fill_color_down: output, - border_color_down: output - }; - if (sd.underlay) { - series.opacity_up = series.opacity_down = opacity || 0.3; - } - seriesParam.push(series); - } - - var yAxis = sd.getYAxis(stx); - var inputs = sd.inputs; - var widthFactor = inputs.WidthFactor; - if (sd.study && sd.study.parameters) { - var parms = sd.study.parameters; - if (typeof parms.widthFactor !== "undefined") - widthFactor = parms.widthFactor; - } - var params = { - name: sd.name, - type: inputs.HistogramType ? inputs.HistogramType : "overlaid", - panel: sd.panel, - yAxis: yAxis, - widthFactor: widthFactor || 0.5, - bindToYAxis: true, - highlight: sd.highlight - }; - - stx.drawHistogram(params, seriesParam); -}; - -/** - * Displays multiple data-points as series on a panel. - * - * This is the default display function for an indicator and will work for 90% of custom indicators. - * @param {CIQ.ChartEngine} stx The chart object - * @param {CIQ.Studies.StudyDescriptor} sd The study descriptor. - * - * Set the following elements to customize behavior (see example): - * - `sd.highlight` Set to true to highlight the line. - * - `sd.gaplines` Follows the same rules as `params.gapDisplayStyle` in {@link CIQ.ChartEngine#drawLineChart} - * - * Set the flowing `parameters` to customize behavior (see example): - * - `plotType` Set to "step" to draw a step line. See {@tutorial Chart Styles and Types} for more details. - * - `noSlopes` Follows the same rules as `params.noSlopes` in {@link CIQ.ChartEngine#drawLineChart} - * - extendToEnd=true - * - * @param {CIQ.ChartEngine.Panel} panel A reference to the study panel - * @param {string} name The name of this output field (should match field from 'quotes' needed to render this line) - * @param {array} quotes The array of quotes (dataSegment) - * @memberof CIQ.Studies - * @since 5.2.0 The number of decimal places for the y-axis is determined by the distance between ticks as opposed to shadow. - * @example - * var study = { - * overlay: true, - * yAxis: {}, - * parameters: { - * plotType: 'step', - * }, - * seriesFN: function(stx, sd, quotes){ - * sd.extendToEnd=false; - * sd.gaplines=false, - * CIQ.Studies.displaySeriesAsLine(stx, sd, quotes); - * } - * }; - * CIQ.Studies.addStudy(stxx, "Vol", {}, {"Volume": "green"}, null, null, study); - */ -CIQ.Studies.displayIndividualSeriesAsLine = function ( - stx, - sd, - panel, - name, - quotes -) { - if (!panel.height) panel.height = panel.bottom - panel.top; - - var context = sd.getContext(stx); - var output = sd.outputs[sd.outputMap[name]]; - if (!output) return; - - // save the original context settings - context.save(); - - // backwards compatibility if the output is just a color string - if (typeof output === "string") { - output = { - color: output, - width: 1 - }; - } - - context.lineWidth = output.width || 1; - - var color = output.color; - if (color == "auto") color = stx.defaultColor; // This is calculated and set by the kernel before draw operation. - context.strokeStyle = color; - - var pattern = output.pattern; - - context.setLineDash(CIQ.borderPatternToArray(context.lineWidth, pattern)); - context.lineDashOffset = 0; - - var labelDecimalPlaces = 0; - var study = sd.study, - yAxis = sd.getYAxis(stx); - labelDecimalPlaces = stx.decimalPlacesFromPriceTick(yAxis.priceTick); - if (sd.overlay || sd.underlay) labelDecimalPlaces = null; // will end up using the same as the chart itself - if (yAxis.decimalPlaces || yAxis.decimalPlaces === 0) - labelDecimalPlaces = yAxis.decimalPlaces; - var label = null; - if (sd.parameters) label = sd.parameters.label; - var libParams = study.parameters; - if (!libParams) libParams = {}; - var step = libParams.plotType == "step"; - if (sd.series) { - // not even sure why this is here but leaving for "backward compatibility" - for (var s in sd.series) { - var ser = sd.series[s].parameters.type; - if (ser) step = ser == "step"; - } - } - // backwards compatibility - if (libParams.noLabels) label = false; - if (!sd.noSlopes && sd.noSlopes !== false) sd.noSlopes = libParams.noSlopes; - if (!sd.extendToEnd && sd.extendToEnd !== false) - sd.extendToEnd = libParams.extendToEnd; - var showLabel = label || (stx.preferences.labels && label !== false); - - var gaplines = sd.gaplines; - if (gaplines === false) gaplines = "transparent"; - var symbol = sd.inputs.Symbol; - var colorFunction = gaplines - ? stx.getGapColorFunction(symbol, name, output, gaplines) - : null; - - stx.plotDataSegmentAsLine( - name, - panel, - { - yAxis: yAxis, - skipTransform: stx.panels[sd.panel].name != sd.chart.name, - label: showLabel, - labelDecimalPlaces: labelDecimalPlaces, - noSlopes: sd.noSlopes, - step: step, - alignStepToSide: sd.alignStepToSide, - extendToEndOfLastBar: sd.extendToEndOfLastBar, - width: sd.lineWidth, - extendToEndOfDataSet: sd.extendToEnd, - gapDisplayStyle: gaplines, - highlight: sd.highlight - }, - colorFunction - ); - - if (study.appendDisplaySeriesAsLine) - study.appendDisplaySeriesAsLine(stx, sd, quotes, name, panel); - - // restore the original context settings - context.restore(); -}; - -/** - * Draws a horizontal line on the study. - * - * @param {CIQ.ChartEngine} stx The chart object - * @param {CIQ.Studies.StudyDescriptor} sd The study descriptor - * @param {array} quotes The array of quotes (unused) - * @param {number} price The price (value) to draw the horizontal line - * @param {CIQ.ChartEngine.YAxis} yAxis The axis to use when drawing the line - * @param {object} color Optional color to use when drawing line. Can be a string or an object like {color:#334455, opacity:0.5} - * @memberof CIQ.Studies - * @since 5.2.0 Added `yAxis` and `color` parameters. - */ -CIQ.Studies.drawHorizontal = function (stx, sd, quotes, price, yAxis, color) { - var panel = stx.panels[sd.panel], - context = stx.getBackgroundCanvas().context; - if (!panel) return; - if (!color) color = yAxis.textStyle; - - var y = stx.pixelFromPrice(price, panel, yAxis); - if (y > yAxis.top && y < yAxis.bottom) - stx.plotLine( - panel.left, - panel.right, - y, - y, - color, - "segment", - context, - false, - { opacity: color && color.opacity ? color.opacity : 0.5 } - ); -}; - -/** - * Method used to display series together with a histogram centered at the zero value. - * - * Used in studies such as on the "MACD" and "Klinger Volume Oscillator". - * - * This function creates the yAxis, draws **a single** histogram and then plots series, multiple if needed. - * - * Note that to differentiate between a regular series and the histogram series there is a convention to use sd.name+"_hist" for histogram values on a study. - * See {@link CIQ.Studies.createHistogram} for details and examples. - * @param {CIQ.ChartEngine} stx The chart object - * @param {CIQ.Studies.StudyDescriptor} sd The study descriptor - * @param {array} quotes The quotes (dataSegment) - * @memberof CIQ.Studies - */ -CIQ.Studies.displayHistogramWithSeries = function (stx, sd, quotes) { - var panel = stx.panels[sd.panel]; - var opacity = 0.5; - if (sd.underlay) opacity = 0.3; - CIQ.Studies.createHistogram(stx, sd, quotes, false, opacity); - CIQ.Studies.displaySeriesAsLine(stx, sd, quotes); -}; - -/** - * Plots over/under zones for indicators that support them, and when the user selects them. - * - * This method will draw its own yAxis which will not have a scale, but merely the over under points.
- * Shading will be performed between the zone lines and the study plot. - * @param {CIQ.ChartEngine} stx The chart object - * @param {CIQ.Studies.StudyDescriptor} sd The study descriptor - * @param {array} quotes unused - * @memberof CIQ.Studies - */ -CIQ.Studies.drawZones = function (stx, sd, quotes) { - if (!sd.parameters || !sd.parameters.studyOverZonesEnabled) return; - - var low = parseFloat(sd.parameters.studyOverSoldValue); - var high = parseFloat(sd.parameters.studyOverBoughtValue); - var lowColor = sd.parameters.studyOverSoldColor; - var highColor = sd.parameters.studyOverBoughtColor; - var output = sd.zoneOutput; - if (!output) output = "Result"; - var zoneColor = CIQ.Studies.determineColor(sd.outputs[output]); - if (!zoneColor || zoneColor == "auto" || CIQ.isTransparent(zoneColor)) - zoneColor = stx.defaultColor; - if (!lowColor) lowColor = zoneColor; - if (!lowColor || lowColor == "auto" || CIQ.isTransparent(lowColor)) - lowColor = stx.defaultColor; - if (!highColor) highColor = zoneColor; - if (!highColor || highColor == "auto" || CIQ.isTransparent(highColor)) - highColor = stx.defaultColor; - var panel = stx.panels[sd.panel]; - var yAxis = sd.getYAxis(stx); - var drawBorders = yAxis.displayBorder; - if (stx.axisBorders === false) drawBorders = false; - if (stx.axisBorders === true) drawBorders = true; - if (yAxis.width === 0) drawBorders = false; - var yaxisPosition = stx.getYAxisCurrentPosition(yAxis, panel); - var leftAxis = yaxisPosition == "left", - rightJustify = yAxis.justifyRight; - if (!rightJustify && rightJustify !== false) { - if ( - stx.chart.yAxis.justifyRight || - stx.chart.yAxis.justifyRight === false - ) { - rightJustify = stx.chart.yAxis.justifyRight; - } else rightJustify = leftAxis; - } - var borderEdge = Math.round(yAxis.left + (leftAxis ? yAxis.width : 0)) + 0.5; - var tickWidth = drawBorders ? 3 : 0; // pixel width of tick off edge of border - - var ctx = stx.getBackgroundCanvas().context; - var color = ctx.fillStyle; - - ctx.globalAlpha = 0.2; - - stx.startClip(panel.name, true); - - ctx.beginPath(); - var ph = Math.round(stx.pixelFromPrice(high, panel, yAxis)) + 0.5; - ctx.strokeStyle = highColor; - ctx.moveTo(panel.left, ph); - ctx.lineTo(panel.right, ph); - ctx.stroke(); - ctx.closePath(); - - ctx.beginPath(); - var pl = Math.round(stx.pixelFromPrice(low, panel, yAxis)) + 0.5; - ctx.strokeStyle = lowColor; - ctx.moveTo(panel.left, pl); - ctx.lineTo(panel.right, pl); - ctx.stroke(); - ctx.closePath(); - - var yAxisPlotter = new CIQ.Plotter(); - yAxisPlotter.newSeries( - "border", - "stroke", - stx.canvasStyle("stx_grid_border") - ); - if (drawBorders) { - var tickLeft = leftAxis ? borderEdge - tickWidth : borderEdge - 0.5; - var tickRight = leftAxis ? borderEdge + 0.5 : borderEdge + tickWidth; - yAxisPlotter.moveTo("border", tickLeft, ph); - yAxisPlotter.lineTo("border", tickRight, ph); - yAxisPlotter.moveTo("border", tickLeft, pl); - yAxisPlotter.lineTo("border", tickRight, pl); - } - - ctx.fillStyle = color; - - var params = { - skipTransform: stx.panels[sd.panel].name != sd.chart.name, - panelName: sd.panel, - band: output + " " + sd.name, - yAxis: yAxis, - opacity: 0.3 - }; - if (!sd.highlight && stx.highlightedDraggable) params.opacity *= 0.3; - CIQ.preparePeakValleyFill( - stx, - CIQ.extend(params, { - threshold: high, - direction: yAxis.flipped ? -1 : 1, - color: highColor - }) - ); - CIQ.preparePeakValleyFill( - stx, - CIQ.extend(params, { - threshold: low, - direction: yAxis.flipped ? 1 : -1, - color: lowColor - }) - ); - - ctx.globalAlpha = 1; - - if (!sd.study || !sd.study.yaxis) { - if (drawBorders) { - var b = Math.round(yAxis.bottom) + 0.5; - yAxisPlotter.moveTo("border", borderEdge, yAxis.top); - yAxisPlotter.lineTo("border", borderEdge, b); - yAxisPlotter.draw(ctx, "border"); - } - - if (yAxis.width !== 0) { - // Draw the y-axis with high/low - stx.canvasFont("stx_yaxis", ctx); - stx.canvasColor("stx_yaxis", ctx); - ctx.textAlign = rightJustify ? "right" : "left"; - var textX; - if (leftAxis) { - textX = yAxis.left + 3; - if (rightJustify) textX = yAxis.left + yAxis.width - tickWidth - 3; - } else { - textX = yAxis.left + tickWidth + 3; - if (rightJustify) textX = yAxis.left + yAxis.width; - } - ctx.fillStyle = highColor; - ctx.fillText(high, textX, ph); - ctx.fillStyle = lowColor; - ctx.fillText(low, textX, pl); - ctx.fillStyle = color; - } - } - stx.endClip(); - ctx.globalAlpha = 1; - - if (yAxis.name == sd.name) yAxis.yAxisPlotter = new CIQ.Plotter(); -}; - -/** - * Method used to display a histogram, which can be centered at the zero value. - * - * Used in studies such as on the "MACD" and "Klinger Volume Oscillator". - * - * Initial bar color is defined in stx-chart.css under '.stx_histogram'.
- * If using the default UI, refer to provided css files under '.stx_histogram' and '.ciq-night .stx_histogram' style sections.
- * If sd.outputs["Decreasing Bar"], sd.outputs["Negative Bar"], sd.outputs["Increasing Bar"] and sd.outputs["Positive Bar"] are present, their corresponding colors will be used instead.
- *

Note the convention to use sd.name+"_hist" for histogram values on a study

- * - * @param {CIQ.ChartEngine} stx The chart object - * @param {CIQ.Studies.StudyDescriptor} sd The study descriptor - * @param {array} quotes The quotes (dataSegment) - * @param {boolean} centered If true then the histogram will be physically centered on the yAxis, otherwise it will be centered at the zero value on the yAxis - * @param {number} [opacity=1] Optionally set the opacity - * @memberof CIQ.Studies - * @example Draws a histogram with alternating bid and ask records. Bids are positive, asks are negative. - * CIQ.Studies.calculateBidAsk=function(stx, sd) { - * var quotes=sd.chart.scrubbed; - * var name=sd.name; - * - * var histogram=name+"_hist"; - * for(i=0;i 0) y = stx.pixelFromPrice(yAxis.min, panel, yAxis); // Don't draw below the bottom of the chart. If zero isn't on the chart then make it behave like a bar graph. - if (centered) { - y = Math.floor(panel.top + panel.height / 2); - } - - var field = sd.name + "_hist"; - stx.canvasColor("stx_histogram"); - var defaultFillStyle = context.fillStyle; - - if (opacity || opacity === 0) context.globalAlpha = opacity; - if (!sd.highlight && stx.highlightedDraggable) context.globalAlpha *= 0.3; - var y0 = null, - y1 = null; - var outputs = sd.outputs; - for (var i = 0; i < quotes.length; i++) { - var quote = quotes[i]; - if (!quote) continue; - if (quote.candleWidth) - myWidth = Math.floor(Math.max(1, quote.candleWidth - 2)); - var x0 = Math.floor(stx.pixelFromBar(i, panel.chart) - myWidth / 2); - var x1 = Math.floor(myWidth); - if (y0 === null) { - var tick = stx.tickFromPixel(x0, panel.chart) - 1; - if (tick < 0) y0 = y1; - else - y0 = - stx.pixelFromPrice(stx.chart.dataSet[tick][field], panel, yAxis) - y; - } else { - y0 = y1; - } - y1 = stx.pixelFromPrice(quote[field], panel, yAxis) - y; - - var decreasingBarColor = CIQ.Studies.determineColor( - outputs["Decreasing Bar"] - ); - var increasingBarColor = CIQ.Studies.determineColor( - outputs["Increasing Bar"] - ); - var positiveBarColor = CIQ.Studies.determineColor(outputs["Positive Bar"]); - var negativeBarColor = CIQ.Studies.determineColor(outputs["Negative Bar"]); - - var flipped = yAxis.flipped; - context.fillStyle = defaultFillStyle; - if (decreasingBarColor && (flipped ? y1 < y0 : y1 > y0)) - context.fillStyle = decreasingBarColor; - else if (increasingBarColor && (flipped ? y1 > y0 : y1 < y0)) - context.fillStyle = increasingBarColor; - else if (positiveBarColor && (flipped ? y1 > 0 : y1 < 0)) - context.fillStyle = positiveBarColor; - else if (negativeBarColor && (flipped ? y1 < 0 : y1 > 0)) - context.fillStyle = negativeBarColor; - context.fillRect(x0, y, x1, Math.floor(y1)); - } - - context.globalAlpha = 1; - stx.endClip(); -}; - -/** - * Used to reduce certain common fields to abbreviated form for display in study panel labels - * - * @type {Object} - * @memberof CIQ.Studies - */ -CIQ.Studies.prettify = { - Close: "C", - Open: "O", - High: "H", - Low: "L", - simple: "ma", - exponential: "ema", - triangular: "tma", - VIDYA: "vdma", - weighted: "wma", - "welles wilder": "smma", - true: "y", - false: "n" -}; - -CIQ.Studies.prettyRE = /^.*\((.*?)\).*$/; - -/** - * Convert a study ID into a displayable format - * - * @param {string} id The ID - * @return {string} A pretty (shortened) ID - * @memberof CIQ.Studies - */ -CIQ.Studies.prettyDisplay = function (id) { - var match = CIQ.Studies.prettyRE.exec(id); - if (!match) return id; - var guts = match[1]; - if (guts) { - for (var i in CIQ.Studies.prettify) { - guts = guts.replace(i, CIQ.Studies.prettify[i]); - } - id = id.replace(match[1], guts); - } - return id; -}; - -/** - * Returns an array of input field names which are used to specify the field for the study. - * - * In most cases, this field is called "Field", but it does not have to be, nor does there need to be only one. - * - * @param {CIQ.Studies.StudyDescriptor} sd The study descriptor - * @return {array} Input fields used to specify the field - * @since 3.0.0 - * @memberof CIQ.Studies - */ -CIQ.Studies.getFieldInputs = function (sd) { - var res = []; - var defaultInputs = sd.study.inputs; - for (var input in defaultInputs) { - if (defaultInputs[input] == "field") res.push(input); - } - return res; -}; - -/** - * The default initialize function for a study. It creates the study descriptor. It creates the panel if one is required. - * - * @param {CIQ.ChartEngine} stx The chart object - * @param {string} type The type of study (from studyLibrary) - * @param {object} inputs The inputs for the study instance - * @param {object} outputs The outputs for the study instance - * @param {object} [parameters] Additional parameters if required or supported by this study - * @param {string} [panelName] Deprecated. Panel name. Use parameters.panelName instead. - * @param {object} [study] Study definition to use in lieu of the study library entry - * @return {CIQ.Studies.StudyDescriptor} The newly initialized study descriptor - * @since - * - 3.0.0 Added `study` parameter. - * - 6.3.0 `panelName` argument is deprecated; use `parameters.panelName` instead. If neither are valid, will automatically determine default panel. - * @memberof CIQ.Studies - */ -CIQ.Studies.initializeFN = function ( - stx, - type, - inputs, - outputs, - parameters, - panelName, - study -) { - if (!inputs) inputs = {}; - if (!parameters) parameters = {}; - if (!inputs.id) { - inputs.id = CIQ.Studies.generateID( - stx, - type, - inputs, - parameters.replaceID, - parameters.display - ); - } - if (!inputs.display) inputs.display = inputs.id; - var sd = new CIQ.Studies.StudyDescriptor( - inputs.id, - type, - inputs.id, - inputs, - outputs, - parameters - ); - if (inputs.Period) sd.days = Math.max(1, parseInt(sd.inputs.Period, 10)); // you can't have fractional or non-positive day periods - if (study) { - if (!study.inputs) study.inputs = sd.study.inputs; - if (!study.outputs) study.outputs = sd.study.outputs; - sd.study = study; - } else study = sd.study; - if (study.display) inputs.display = study.display; // override what is displayed in the label - if (typeof parameters.panelName == "string") panelName = parameters.panelName; - if (panelName == inputs.id || (panelName && !stx.panelExists(panelName))) { - sd.underlay = sd.overlay = false; - } - if (panelName == "Own panel" || panelName == "New panel") { - panelName = null; - } - var isOverlay = - sd.overlay || inputs.Overlay || (sd.overlay !== false && study.overlay); - var isUnderlay = - sd.underlay || inputs.Underlay || (sd.underlay !== false && study.underlay); - if (isOverlay && parameters.underlayEnabled) isUnderlay = true; - if (isUnderlay) sd.underlay = true; - if (!isUnderlay && stx.chart.panel && panelName == stx.chart.panel.name) - isOverlay = true; - if (isOverlay) sd.overlay = true; - - var drag = stx.preferences.dragging; - if (drag === true || (drag && drag.study)) sd.overlay = true; // override for draggable studies - if (panelName) parameters.panelName = panelName; - else if (!isOverlay && !isUnderlay) panelName = inputs.id; - - if (parameters.calculateOnly) { - if (isOverlay || isUnderlay) { - if (stx.panels[parameters.panelName]) sd.panel = parameters.panelName; - else - sd.panel = - CIQ.Studies.getPanelFromFieldName(stx, sd) || parameters.chartName; - } - // don't setup panel, return now - return sd; - } - - var oldStudyValues = {}; // capture these values in case they change throughout this function - var oldStudy = stx.layout.studies[parameters.replaceID]; - if (oldStudy) { - oldStudyValues = { - outputMap: CIQ.clone(oldStudy.outputMap), - panel: oldStudy.panel - }; - } - // adjust panel - sd.panel = ""; - if (panelName) { - var newPanel = CIQ.Studies.smartMovePanel( - stx, - sd.inputs, - panelName, - parameters.replaceID, - parameters.panelName == "New panel" - ); - if (newPanel) sd.panel = newPanel.name; - } else if (isOverlay || isUnderlay) { - sd.panel = - CIQ.Studies.getPanelFromFieldName(stx, sd) || parameters.chartName; - } - if (!sd.panel) { - var panelHeight = study.panelHeight || null; - var yaxisParameters = study.yAxis || {}; - yaxisParameters.name = sd.inputs.id; - sd.panel = sd.inputs.id; - stx.createPanel( - sd.inputs.display, - sd.panel, - panelHeight, - parameters.chartName, - new CIQ.ChartEngine.YAxis(yaxisParameters) - ); - } - - if (sd.parameters && sd.parameters.panelName) - sd.parameters.panelName = sd.panel; - - // adjust yAxis - var panel = stx.panels[sd.panel]; - var yAxis = CIQ.Studies.smartCreateYAxis( - stx, - panel, - sd.inputs.id, - parameters.yaxisDisplayValue, - parameters.yAxis || study.yAxis - ); - - var syAxis = study ? CIQ.clone(study.yAxis) : null; - var adjAxis = syAxis || yAxis; - if (adjAxis) { - if (adjAxis.ground) adjAxis.initialMarginBottom = 0; - if ( - adjAxis.initialMarginTop || - adjAxis.initialMarginTop === 0 || - adjAxis.initialMarginBottom || - adjAxis.initialMarginBottom === 0 - ) { - stx.calculateYAxisMargins(adjAxis); - } - if (adjAxis.name == parameters.replaceID) adjAxis.name = sd.inputs.id; - } - - if (yAxis) { - yAxis.width = - yAxis.position == "none" ? 0 : CIQ.ChartEngine.YAxis.prototype.width; - if ( - parameters.yaxisDisplayValue == "shared" || - parameters.yaxisDisplayValue == "default" - ) { - delete parameters.yaxisDisplayValue; - } else { - if (syAxis) { - CIQ.ensureDefaults(yAxis, syAxis); - } else if (yAxis.name == sd.name) { - // study owns axis - if ( - !parameters.yaxisDisplayColor || - parameters.yaxisDisplayColor == "auto" - ) - delete yAxis.textStyle; - else yAxis.textStyle = CIQ.colorToHex(parameters.yaxisDisplayColor); - yAxis.justifyRight = null; - yAxis.flipped = parameters.flippedEnabled; - } - } - if (yAxis != panel.yAxis) { - yAxis.displayGridLines = false; - } else if (yAxis != stx.chart.yAxis) { - yAxis.displayGridLines = stx.displayGridLinesInStudies; - } - } - stx.calculateYAxisPositions(); - - // move study's drawings - if (oldStudy) { - var drawingChanged = false; - for (var d in stx.drawingObjects) { - var drawing = stx.drawingObjects[d]; - if ( - oldStudyValues.outputMap && - oldStudyValues.outputMap.hasOwnProperty(drawing.field) - ) { - drawing.field = drawing.field.replace( - parameters.replaceID, - sd.inputs.id - ); - if (sd.parameters && sd.parameters.panelName) { - drawing.panelName = sd.parameters.panelName; - } else { - drawing.panelName = sd.panel; - } - drawingChanged = true; - } else if ( - oldStudyValues.panel && - oldStudyValues.panel == drawing.panelName - ) { - drawing.panelName = drawing.panelName.replace( - parameters.replaceID, - sd.inputs.id - ); - drawingChanged = true; - } - } - if (drawingChanged) stx.changeOccurred("vector"); - } - return sd; -}; - -/** - * Manages the panel for a study when a new panel is requested. - * - * @param {CIQ.ChartEngine} stx A chart engine instance. - * @param {object} inputs The study inputs. - * @param {string} panelName Name of the panel where the study will lie. **Note:** This panel's name may be changed in this function. - * @param {string} replaceID Name of the original study. - * @param {boolean} toNewPanel `true` if request to move to a new panel. - * @return {CIQ.ChartEngine.Panel} The panel to which the study was moved; null if a new panel needs to be created. - * @memberof CIQ.Studies - * @since - * - 7.1.0 - * - 7.2.0 Added the `toNewPanel` argument. - */ -CIQ.Studies.smartMovePanel = function ( - stx, - inputs, - panelName, - replaceID, - toNewPanel -) { - var oldStudy; - var name = inputs.id; - if (replaceID) oldStudy = stx.layout.studies[replaceID]; - if (oldStudy) { - var oldPanel = stx.panels[oldStudy.panel]; - if (oldPanel) { - if (oldPanel.yAxis.name == replaceID) { - // study owns panel - if ( - (toNewPanel || panelName != replaceID) && - !stx.checkForEmptyPanel(oldPanel.name, true, oldStudy) - ) { - // case 1: Either we are moving to a new panel, or we changed the inputs, - // and existing panel is still populated with other plots - stx.electNewPanelOwner(oldPanel); // promote a new panel owner - var yAxis = oldStudy.getYAxis(stx); - if (yAxis.name == replaceID) stx.electNewYAxisOwner(yAxis); // promote a new axis owner - } else if (panelName == replaceID || !stx.panels[panelName]) { - // case 2: We changed something not necessitating any panel move - if (name != oldPanel.name) - stx.modifyPanel(oldPanel, { name: name, display: inputs.display }); - panelName = name; - } - } - } - } - return stx.panels[panelName]; -}; - -/** - * Manages yAxis for a study when a new position is requested. - * - * @param {CIQ.ChartEngine} stx A chart engine instance - * @param {CIQ.ChartEngine.Panel} panel The panel where the yAxis is - * @param {string} name The study whose axis to manage - * @param {string} [newPosition] New position (left/right/none,default/shared, or specific axis name) - * @param {object} [defaultAxis] Axis defaults to use when creating new axis - * @return {CIQ.ChartEngine.YAxis} The yAxis to use - * @memberof CIQ.Studies - * @since 7.1.0 - */ -CIQ.Studies.smartCreateYAxis = function ( - stx, - panel, - name, - newPosition, - defaultAxis -) { - var yAxis = stx.getYAxisByName(panel, name); //owns axis - if (!newPosition && defaultAxis) newPosition = defaultAxis.position; - if ( - newPosition == "default" || - newPosition == "shared" || - newPosition == panel.yAxis.name - ) - newPosition = ""; - if (["left", "right", "none"].indexOf(newPosition) > -1) { - // left/right/none - // was sharing or default - if (!yAxis || yAxis.isShared(stx)) { - // was sharing an axis, need a new axis - var newParams = defaultAxis || {}; - CIQ.extend(newParams, { name: name, position: newPosition }); - if ( - !yAxis && - !stx.currentlyImporting && - panel != panel.chart.panel && - !panel.yAxis.studies.length && - !panel.yAxis.renderers.length - ) { - // use orphaned yAxis which is not hosting anything - yAxis = panel.yAxis; - CIQ.extend(yAxis, newParams); - } else { - var isPanelAxis = yAxis == panel.yAxis; - if (yAxis) yAxis.name = stx.electNewYAxisOwner(yAxis); - yAxis = stx.addYAxis(panel, new CIQ.ChartEngine.YAxis(newParams)); - if (isPanelAxis) panel.yAxis = yAxis; - } - } else { - // was own axis, switch to left/right/none - yAxis.position = newPosition; - } - return yAxis; - } - if (newPosition) { - // a specific axis is specified - var newAxis = stx.getYAxisByName(panel, newPosition); - if (newAxis && yAxis == panel.yAxis && !yAxis.isShared(stx)) { - // normally we don't need to do anything, but in this special case we need to give the panel a different owning yaxis - panel.yAxis = newAxis; - } - if (yAxis && yAxis.isShared(stx)) { - // pick a new axis name - yAxis.name = stx.electNewYAxisOwner(yAxis); - } else { - if (yAxis !== panel.yAxis) stx.deleteYAxisIfUnused(panel, yAxis); - } - return newAxis; - } - // going to share/default - if (yAxis) { - if (yAxis.isShared(stx)) { - // pick a new axis name - yAxis.name = stx.electNewYAxisOwner(yAxis); - } else { - delete yAxis.position; - if (yAxis !== panel.yAxis) stx.deleteYAxisIfUnused(panel, yAxis); - } - } - stx.resizeChart(); - - return panel.yAxis; -}; - -/** - * Default Volume calculation function. - * - * Volume is already obtained, so all that is done here is setting colors. - * @param {CIQ.ChartEngine} stx A chart engine instance - * @param {CIQ.Studies.StudyDescriptor} sd Study to calculate volume for - * @memberOf CIQ.Studies - */ -CIQ.Studies.calculateVolume = function (stx, sd) { - if (sd.type == "vol undr") { - if (!stx || !stx.chart.dataSet) return; - var layout = stx.layout; - var remove = sd.parameters.removeStudy; - var previous = layout.volumeUnderlay; - layout.volumeUnderlay = !remove; - if (previous != layout.volumeUnderlay) stx.changeOccurred("layout"); - if (remove) { - CIQ.Studies.removeStudy(stx, sd); - } - } - sd.outputMap = {}; - sd.outputMap.Volume = ""; -}; - -/** - * Moving Average convenience function. - * - * @param {string} type The type of moving average, e.g. simple, exponential, triangular, etc. Valid options can be seen by inspecting the keys on the `CIQ.Studies.movingAverage.typeMap` object. - * @param {number} periods Moving average period - * @param {string} field The field in the data array to perform the moving average on - * @param {number} offset Periods to offset the result by - * @param {string} name String to prefix to the name of the output. Full name of output would be name + " " + sd.name. For instance, sending 'Signal' on a 'macd' study will result in an output field called "Signal ‌macd‌ (12,26,9)" - * @param {CIQ.ChartEngine} stx Chart object - * @param {object} sd Study Descriptor - * @param {string} subField Subfield within field to perform moving average on, if applicable. For example, IBM.Close: field:"IBM", subField:"Close" - * @memberof CIQ.Studies - * @since 04-2015 - */ -CIQ.Studies.MA = function ( - type, - periods, - field, - offset, - name, - stx, - sd, - subField -) { - var ma = new CIQ.Studies.StudyDescriptor( - name + " " + sd.name, - "ma", - sd.panel - ); - ma.chart = sd.chart; - ma.days = parseInt(periods, 10); - ma.startFrom = sd.startFrom; - if (subField) ma.subField = subField; - ma.inputs = {}; - if (type) ma.inputs.Type = type; - if (field) ma.inputs.Field = field; - if (offset) ma.inputs.Offset = parseInt(offset, 10); - CIQ.Studies.calculateMovingAverage(stx, ma); -}; - -// Moving average data; add to it if adding moving average functionality -CIQ.Studies.movingAverage = { - //conversions: mapping of study type to moving average type name - conversions: { - ma: "simple", - sma: "simple", - ema: "exponential", - tma: "triangular", - vdma: "vidya", - wma: "weighted", - smma: "welles wilder" - }, - //translations: mapping of moving average type name to display name - translations: { - simple: "Simple", - exponential: "Exponential", - triangular: "Triangular", - vidya: "VIDYA", - weighted: "Weighted", - "welles wilder": "Welles Wilder" - }, - //typeMap: mapping of both study type and type name to calculation function suffix - //i.e., calculateMovingAverageXXX - typeMap: { - ema: "Exponential", - exponential: "Exponential", - tma: "Triangular", - triangular: "Triangular", - vdma: "VIDYA", - vidya: "VIDYA", - wma: "Weighted", - weighted: "Weighted", - smma: "Exponential", - "welles wilder": "Exponential" - } -}; -/** - * Does conversions for valid moving average types - * - * @param {CIQ.ChartEngine} stx The chart object - * @param {string} input String to test if a moving average type or "options" to return the list of ma options. - * @return {Object} The name of the moving average or a list of options - * @memberof CIQ.Studies - */ -CIQ.Studies.movingAverageHelper = function (stx, input) { - if (input == "options") { - var translations = {}; - for (var t in CIQ.Studies.movingAverage.translations) { - translations[t] = stx.translateIf( - CIQ.Studies.movingAverage.translations[t] - ); - } - return translations; - } - return CIQ.Studies.movingAverage.conversions[input]; -}; - -/** - * Creates a volume chart. - * - * If no volume is available on the screen then the panel will be watermarked "Volume Not Available" (translated if a translate function is attached to the kernel object). - * - * Uses {@link CIQ.ChartEngine#drawHistogram} and any "parameters" in the study definition will send into its 'params' object to control the histogram look and feel. - *
Example: - * ``` - * CIQ.extend(CIQ.Studies.studyLibrary["vol undr"],{ - * "parameters": { - * "widthFactor":0.5 - * } - * }); - * ``` - * - * Uses CSS style : - * - `stx_volume_underlay` if "sd.underlay" is true - * - `stx_volume` if "sd.underlay" is NOT true - * - * See {@link CIQ.ChartEngine#colorByCandleDirection} to base colors on difference between open and close vs. difference between previous close and close. - * - * @param {CIQ.ChartEngine} stx A chart engine instance - * @param {CIQ.Studies.StudyDescriptor} sd A study descriptor - * @param {array} quotes Array of quotes - * @memberof CIQ.Studies - * @example - * // default volume study library entry with required parameters - * "volume": { - * "name": "Volume Chart", - * "range": "0 to max", - * "yAxis": {"ground":true, "initialMarginTop":0, "zoom":0}, - * "seriesFN": CIQ.Studies.createVolumeChart, - * "calculateFN": CIQ.Studies.calculateVolume, - * "inputs": {}, - * "outputs": {"Up Volume":"#8cc176","Down Volume":"#b82c0c"} - * } - * @example - * // default volume underlay library entry with required parameters - * "vol undr": { - * "name": "Volume Underlay", - * "underlay": true, - * "range": "0 to max", - * "yAxis": {"ground":true, "initialMarginTop":0, "position":"none", "zoom": 0, "heightFactor": 0.25}, - * "seriesFN": CIQ.Studies.createVolumeChart, - * "calculateFN": CIQ.Studies.calculateVolume, - * "inputs": {}, - * "outputs": {"Up Volume":"#8cc176","Down Volume":"#b82c0c"}, - * "customRemoval": true, - * "removeFN": function(stx, sd){ - * stx.layout.volumeUnderlay=false; - * stx.changeOccurred("layout"); - * }, - * "attributes":{ - * "panelName":{hidden:true} - * } - * } - */ -CIQ.Studies.createVolumeChart = function (stx, sd, quotes) { - var panel = sd.panel, - inputs = sd.inputs, - underlay = sd.underlay, - overlay = sd.overlay; - var inAnotherPanel = underlay || overlay; - var colorUp = CIQ.Studies.determineColor(sd.outputs["Up Volume"]); - var colorDown = CIQ.Studies.determineColor(sd.outputs["Down Volume"]); - var style = underlay ? "stx_volume_underlay" : "stx_volume"; - stx.setStyle(style + "_up", "color", colorUp); - stx.setStyle(style + "_down", "color", colorDown); - - var seriesParam = [ - { - field: sd.volumeField || "Volume", - fill_color_up: stx.canvasStyle(style + "_up").color, - border_color_up: stx.canvasStyle(style + "_up").borderLeftColor, - opacity_up: stx.canvasStyle(style + "_up").opacity, - fill_color_down: stx.canvasStyle(style + "_down").color, - border_color_down: stx.canvasStyle(style + "_down").borderLeftColor, - opacity_down: stx.canvasStyle(style + "_down").opacity, - color_function: sd.colorFunction - } - ]; - var seriesParam0 = seriesParam[0]; - - // Major backward compatibility hack. If the border color is the same as our standard color - // then most likely the customer is missing border: #000000 style on stx_volume_up and stx_volume_down - if (!underlay && seriesParam0.border_color_down === "rgb(184, 44, 12)") { - seriesParam0.border_color_down = "#000000"; - seriesParam0.border_color_up = "#000000"; - } - - var yAxis = sd.getYAxis(stx); - var params = { - name: "Volume", - panel: panel, - yAxis: yAxis, - widthFactor: 1, - bindToYAxis: true, - highlight: sd.highlight - }; - - CIQ.extend(params, sd.study.parameters); - CIQ.extend(params, sd.parameters); - - if (stx.colorByCandleDirection && !sd.colorFunction) { - seriesParam0.color_function = function (quote) { - var O = quote.Open, - C = quote.Close; - //if((!O && O!==0) || (!C && C!==0) || O===C) return stx.defaultColor; - - return { - fill_color: - O > C ? seriesParam0.fill_color_down : seriesParam0.fill_color_up, - border_color: - O > C ? seriesParam0.border_color_down : seriesParam0.border_color_up, - opacity: O > C ? seriesParam0.opacity_down : seriesParam0.opacity_up - }; - }; - } - - stx.drawHistogram(params, seriesParam); -}; - -/** - * Calculate function for standard deviation. - * - * The resulting values will be added to the dataSet using the field name provided by the `sd.outputMap` entry. - * - * **Notes:** - * - If no `outputs` object is defined in the library entry, the study will default to a single output named `Result`, which will then be used in lieu of `sd.outputs` to build the `sd.outputMap`. - * - The study name may contain the unprintable character `‌`, see {@link CIQ.Studies.StudyDescriptor} documentation - * - * @param {CIQ.ChartEngine} stx Chart object - * @param {CIQ.Studies.StudyDescriptor} sd Study Descriptor - * @memberOf CIQ.Studies - */ -CIQ.Studies.calculateStandardDeviation = function (stx, sd) { - var quotes = sd.chart.scrubbed; - if (quotes.length < sd.days + 1) { - sd.error = true; - return; - } - var field = sd.inputs.Field; - if (!field || field == "field") field = "Close"; - var type = sd.inputs["Moving Average Type"]; - if (!type) type = sd.inputs.Type; - CIQ.Studies.MA(type, sd.days, field, sd.inputs.Offset, "_MA", stx, sd); - - var acc1 = 0; - var acc2 = 0; - var ma = 0; - var mult = Number(sd.inputs["Standard Deviations"]); - if (mult < 0) mult = 2; - var name = sd.name; - for (var p in sd.outputs) { - name = p + " " + name; - } - var i, val, its; - for (i = sd.startFrom - 1, its = 0; i >= 0 && its < sd.days; i--, its++) { - val = quotes[i][field]; - if (val && typeof val == "object") val = val[sd.subField]; - if (isNaN(val)) val = 0; - acc1 += Math.pow(val, 2); - acc2 += val; - } - for (i = sd.startFrom; i < quotes.length; i++) { - var quote = quotes[i]; - val = quote[field]; - if (val && typeof val == "object") val = val[sd.subField]; - if (!val && val !== 0) val = 0; - acc1 += Math.pow(val, 2); - acc2 += val; - if (i < sd.days - 1) continue; - if (i >= sd.days) { - var val2 = quotes[i - sd.days][field]; - if (val2 && typeof val2 == "object") val2 = val2[sd.subField]; - if (isNaN(val2)) val2 = 0; - acc1 -= Math.pow(val2, 2); - acc2 -= val2; - } - ma = quote["_MA " + sd.name]; - if (ma || ma === 0) - quote[name] = - Math.sqrt( - (acc1 + sd.days * Math.pow(ma, 2) - 2 * ma * acc2) / sd.days - ) * mult; - } -}; - -/** - * Calculate function for moving averages. - * - * sd.inputs["Type"] can be used to request a specific type of moving average. Valid options can be seen by inspecting the keys on the `CIQ.Studies.movingAverage.typeMap` object. - * - * The resulting values will be added to the dataSet using the field name provided by the `sd.outputMap` entry. - * - * **Notes:** - * - This function calculates a single value, so it expects `sd.outputMap` to contain a single mapping. - * - To leverage as part of a larger study calculation, use {@link CIQ.Studies.MA} instead. - * - If no `outputs` object is defined in the library entry, the study will default to a single output named `Result`, which will then be used in lieu of `sd.outputs` to build the field name. - * - The study name may contain the unprintable character `‌`, see {@link CIQ.Studies.StudyDescriptor} documentation. - * - * - * @param {CIQ.ChartEngine} stx A chart engine instance - * @param {CIQ.Studies.StudyDescriptor} sd A study descriptor - * @memberOf CIQ.Studies - */ -CIQ.Studies.calculateMovingAverage = function (stx, sd) { - if (!sd.chart.scrubbed) return; - var type = sd.inputs.Type; - if (type == "ma" || type == "sma" || !type) type = "simple"; // handle when the default inputs are passed in - var typeMap = CIQ.Studies.movingAverage.typeMap; - if (type in typeMap) { - return CIQ.Studies["calculateMovingAverage" + typeMap[type]](stx, sd); - } else if (type !== "simple") { - return; - } - var quotes = sd.chart.scrubbed; - var acc = 0; - var vals = []; - var name = sd.name; - for (var p in sd.outputs) { - name = p + " " + name; - } - var field = sd.inputs.Field; - if (!field || field == "field") field = "Close"; // Handle when the default inputs are passed in - var offset = parseInt(sd.inputs.Offset, 10); - if (isNaN(offset)) offset = 0; - var i, - val, - ft, - start = sd.startFrom; - // backload the past data into the array - var offsetBack = offset; - for (i = sd.startFrom - 1; i >= 0; i--) { - val = quotes[i][field]; - if (val && typeof val == "object") val = val[sd.subField]; - if (!val && val !== 0) continue; - if (offsetBack > 0) { - offsetBack--; - start = i; - continue; - } - if (vals.length == sd.days - 1) break; - acc += val; - vals.unshift(val); - } - if (vals.length < sd.days - 1) { - vals = []; - start = 0; // not enough records to continue where left off - } - var futureTicks = []; - for (i = start; i < quotes.length; i++) { - var quote = quotes[i]; - val = quote[field]; - if (val && typeof val == "object") val = val[sd.subField]; - var notOverflowing = i + offset >= 0 && i + offset < quotes.length; - var offsetQuote = notOverflowing ? quotes[i + offset] : null; - if (!val && val !== 0) { - if (offsetQuote) offsetQuote[name] = null; - else if (i + offset >= quotes.length) { - ft = {}; - ft[name] = null; - futureTicks.push(ft); - } - continue; - } - acc += val; - vals.push(val); - if (vals.length > sd.days) acc -= vals.shift(); - var myVal = vals.length == sd.days ? acc / sd.days : null; - if (offsetQuote) offsetQuote[name] = myVal; - else if (i + offset >= quotes.length) { - ft = {}; - ft[name] = myVal; - futureTicks.push(ft); - } - } - sd.appendFutureTicks(stx, futureTicks); -}; - -/** - * Calculate function for exponential moving average. - * - * The resulting values will be added to the dataSet using the field name provided by the `sd.outputMap` entry. - * - * **Notes:** - * - This function calculates a single value, so it expects `sd.outputMap` to contain a single mapping. - * - To leverage as part of a larger study calculation, use {@link CIQ.Studies.MA} instead. - * - If no `outputs` object is defined in the library entry, the study will default to a single output named `Result`, which will then be used in lieu of `sd.outputs` to build the field name. - * - The study name may contain the unprintable character `‌`, see {@link CIQ.Studies.StudyDescriptor} documentation. - * - * @param {CIQ.ChartEngine} stx Chart object - * @param {CIQ.Studies.StudyDescriptor} sd Study Descriptor - * @private - * @memberof CIQ.Studies - */ -CIQ.Studies.calculateMovingAverageExponential = function (stx, sd) { - var type = sd.inputs.Type; - var quotes = sd.chart.scrubbed; - var acc = 0; - var ma = 0; - var ii = 0; - var multiplier = 2 / (sd.days + 1); - if (type === "welles wilder" || type === "smma") multiplier = 1 / sd.days; - - var emaPreviousDay = null; - var name = sd.name; - for (var p in sd.outputs) { - name = p + " " + name; - } - - var field = sd.inputs.Field; - if (!field || field == "field") field = "Close"; // Handle when the default inputs are passed in - var offset = parseInt(sd.inputs.Offset, 10); - if (isNaN(offset)) offset = 0; - var i, val; - var start = sd.startFrom; - // find emaPreviousDay - var offsetBack = offset; - for (i = sd.startFrom - 1; i >= 0; i--) { - val = quotes[i][name]; - if (!val && val !== 0) continue; - if (emaPreviousDay === null) emaPreviousDay = val; - ii = sd.days; - if (offsetBack <= 0) break; - offsetBack--; - start = i; - } - if (emaPreviousDay === null) { - emaPreviousDay = start = 0; - } - var futureTicks = []; - for (i = start; i < quotes.length; i++) { - var quote = quotes[i]; - val = quote[field]; - if (val && typeof val == "object") val = val[sd.subField]; - var notOverflowing = i + offset >= 0 && i + offset < quotes.length; - var offsetQuote = notOverflowing ? quotes[i + offset] : null; - var myVal; - if (!val && val !== 0) { - myVal = null; - } else { - if (ii == sd.days - 1) { - acc += val; - ma = acc / sd.days; - myVal = ma; - } else if (ii < sd.days - 1) { - acc += val; - ma = acc / (ii + 1); - myVal = null; - } else if (ii === 0) { - acc += val; - ma = acc; - myVal = null; - } else if (emaPreviousDay || emaPreviousDay === 0) { - ma = (val - emaPreviousDay) * multiplier + emaPreviousDay; - myVal = ma; - } - emaPreviousDay = ma; - ii++; - } - if (offsetQuote) offsetQuote[name] = myVal; - else if (i + offset >= quotes.length) { - var ft = {}; - ft[name] = myVal; - futureTicks.push(ft); - } - } - sd.appendFutureTicks(stx, futureTicks); -}; - -/** - * Calculate function for VI Dynamic MA (VIDYA). - * - * The resulting values will be added to the dataSet using the field name provided by the `sd.outputMap` entry. - * - * **Notes:** - * - This function calculates a single value, so it expects `sd.outputMap` to contain a single mapping. - * - To leverage as part of a larger study calculation, use {@link CIQ.Studies.MA} instead. - * - If no `outputs` object is defined in the library entry, the study will default to a single output named `Result`, which will then be used in lieu of `sd.outputs` to build the field name. - * - The study name may contain the unprintable character `‌`, see {@link CIQ.Studies.StudyDescriptor} documentation. - * - * @param {CIQ.ChartEngine} stx Chart object - * @param {CIQ.Studies.StudyDescriptor} sd Study Descriptor - * @private - * @memberof CIQ.Studies - * @since 5.2.1 - */ -CIQ.Studies.calculateMovingAverageVIDYA = function (stx, sd) { - var type = sd.inputs.Type; - var quotes = sd.chart.scrubbed; - var alpha = 2 / (sd.days + 1); - - var vmaPreviousDay = null; - var name = sd.name; - for (var p in sd.outputs) { - name = p + " " + name; - } - - var field = sd.inputs.Field; - if (!field || field == "field") field = "Close"; // Handle when the default inputs are passed in - - sd.std = new CIQ.Studies.StudyDescriptor(sd.name, "sdev", sd.panel); - sd.std.chart = sd.chart; - sd.std.days = 5; - sd.std.startFrom = sd.startFrom; - sd.std.inputs = { Field: field, "Standard Deviations": 1, Type: "ma" }; - sd.std.outputs = { _STD: null }; - CIQ.Studies.calculateStandardDeviation(stx, sd.std); - - CIQ.Studies.MA("ma", 20, "_STD " + sd.name, 0, "_MASTD", stx, sd); - - var offset = parseInt(sd.inputs.Offset, 10); - if (isNaN(offset)) offset = 0; - - var i, val, ft; - var start = sd.startFrom; - // find vmaPreviousDay - var offsetBack = offset; - for (i = sd.startFrom - 1; i >= 0; i--) { - val = quotes[i][name]; - if (!val && val !== 0) continue; - if (vmaPreviousDay === null) vmaPreviousDay = val; - if (offsetBack <= 0) break; - offsetBack--; - start = i; - } - if (vmaPreviousDay === null) { - vmaPreviousDay = start = 0; - } - var futureTicks = []; - for (i = start; i < quotes.length; i++) { - var quote = quotes[i]; - val = quote[field]; - if (val && typeof val == "object") val = val[sd.subField]; - var notOverflowing = i + offset >= 0 && i + offset < quotes.length; - var offsetQuote = notOverflowing ? quotes[i + offset] : null; - if (!val && val !== 0) { - if (offsetQuote) offsetQuote[name] = null; - else if (i + offset >= quotes.length) { - ft = {}; - ft[name] = null; - futureTicks.push(ft); - } - continue; - } - if (!quote["_MASTD " + sd.name] && quote["_MASTD " + sd.name] !== 0) - continue; - var vi = quote["_STD " + sd.name] / quote["_MASTD " + sd.name]; - var vma = alpha * vi * val + (1 - alpha * vi) * vmaPreviousDay; - vmaPreviousDay = vma; - if (i < sd.days) vma = null; - if (offsetQuote) offsetQuote[name] = vma; - else if (i + offset >= quotes.length) { - ft = {}; - ft[name] = vma; - futureTicks.push(ft); - } - } - sd.appendFutureTicks(stx, futureTicks); -}; - -/** - * Calculate function for triangular moving average. - * - * The resulting values will be added to the dataSet using the field name provided by the `sd.outputMap` entry. - * - * **Notes:** - * - This function calculates a single value, so it expects `sd.outputMap` to contain a single mapping. - * - To leverage as part of a larger study calculation, use {@link CIQ.Studies.MA} instead. - * - If no `outputs` object is defined in the library entry, the study will default to a single output named `Result`, which will then be used in lieu of `sd.outputs` to build the field name. - * - The study name may contain the unprintable character `‌`, see {@link CIQ.Studies.StudyDescriptor} documentation. - * - * @param {CIQ.ChartEngine} stx Chart object - * @param {CIQ.Studies.StudyDescriptor} sd Study Descriptor - * @private - * @memberof CIQ.Studies - */ -CIQ.Studies.calculateMovingAverageTriangular = function (stx, sd) { - var quotes = sd.chart.scrubbed; - - var field = sd.inputs.Field; - if (!field || field == "field") field = "Close"; // Handle when the default inputs are passed in - var days = Math.ceil(sd.days / 2); - CIQ.Studies.MA("simple", days, field, 0, "TRI1", stx, sd); - if (sd.days % 2 === 0) days++; - CIQ.Studies.MA("simple", days, "TRI1 " + sd.name, 0, "TRI2", stx, sd); - - var name = sd.name; - for (var p in sd.outputs) { - name = p + " " + name; - } - var offset = parseInt(sd.inputs.Offset, 10); - if (isNaN(offset)) offset = 0; - - // find start - var offsetBack = offset; - for (var i = sd.startFrom - 1; i >= 0; i--) { - var val = quotes[i][name]; - if (!val && val !== 0) continue; - if (offsetBack > 0) { - offsetBack--; - continue; - } - break; - } - var futureTicks = []; - for (i++; i < quotes.length; i++) { - if (i + offset >= 0) { - if (i + offset < quotes.length) - quotes[i + offset][name] = quotes[i]["TRI2 " + sd.name]; - else { - var ft = {}; - ft[name] = quotes[i]["TRI2 " + sd.name]; - futureTicks.push(ft); - } - } - } - sd.appendFutureTicks(stx, futureTicks); -}; - -/** - * Calculate function for weighted moving average. - * - * The resulting values will be added to the dataSet using the field name provided by the `sd.outputMap` entry. - * - * **Notes:** - * - This function calculates a single value, so it expects `sd.outputMap` to contain a single mapping. - * - To leverage as part of a larger study calculation, use {@link CIQ.Studies.MA} instead. - * - If no `outputs` object is defined in the library entry, the study will default to a single output named `Result`, which will then be used in lieu of `sd.outputs` to build the field name. - * - The study name may contain the unprintable character `‌`, see {@link CIQ.Studies.StudyDescriptor} documentation. - * - * @param {CIQ.ChartEngine} stx Chart object - * @param {CIQ.Studies.StudyDescriptor} sd Study Descriptor - * @private - * @memberof CIQ.Studies - */ -CIQ.Studies.calculateMovingAverageWeighted = function (stx, sd) { - var quotes = sd.chart.scrubbed; - - var accAdd = 0; - var accSubtract = 0; - var field = sd.inputs.Field; - if (!field || field == "field") field = "Close"; // Handle when the default inputs are passed in - var divisor = (sd.days * (sd.days + 1)) / 2; - - var name = sd.name; - for (var p in sd.outputs) { - name = p + " " + name; - } - var offset = parseInt(sd.inputs.Offset, 10); - if (isNaN(offset)) offset = 0; - var i, val, ft; - var vals = []; - var start = sd.startFrom; - // backload the past data into the array - var offsetBack = offset; - for (i = sd.startFrom - 1; i >= 0; i--) { - val = quotes[i][field]; - if (val && typeof val == "object") val = val[sd.subField]; - if (!val && val !== 0) continue; - if (offsetBack > 0) { - offsetBack--; - start = i; - continue; - } - if (vals.length == sd.days - 1) break; - vals.unshift(val); - } - if (vals.length < sd.days - 1) { - vals = []; - start = 0; // not enough records to continue where left off - } - for (i = 0; i < vals.length; i++) { - accAdd += (i + 1) * vals[i]; - accSubtract += vals[i]; - } - var futureTicks = []; - for (i = start; i < quotes.length; i++) { - var quote = quotes[i]; - val = quote[field]; - if (val && typeof val == "object") val = val[sd.subField]; - var notOverflowing = i + offset >= 0 && i + offset < quotes.length; - var offsetQuote = notOverflowing ? quotes[i + offset] : null; - if (!val && val !== 0) { - if (offsetQuote) offsetQuote[name] = null; - else if (i + offset >= quotes.length) { - ft = {}; - ft[name] = null; - futureTicks.push(ft); - } - continue; - } - vals.push(val); - if (vals.length > sd.days) { - accAdd -= accSubtract; - accSubtract -= vals.shift(); - } - accAdd += vals.length * val; - accSubtract += val; - - var myVal = i < sd.days - 1 ? null : accAdd / divisor; - if (offsetQuote) offsetQuote[name] = myVal; - else if (i + offset >= quotes.length) { - ft = {}; - ft[name] = myVal; - futureTicks.push(ft); - } - } - sd.appendFutureTicks(stx, futureTicks); -}; - -CIQ.Studies.calculateStudyATR = function (stx, sd) { - var quotes = sd.chart.scrubbed; - var period = sd.days; - if (quotes.length < period + 1) { - sd.error = true; - return; - } - var total = 0; - var name = sd.name; - for (var i = Math.max(sd.startFrom, 1); i < quotes.length; i++) { - var prices = quotes[i]; - var pd = quotes[i - 1]; - var trueRange = prices.trueRange; - if (pd["Sum True Range " + name]) total = pd["Sum True Range " + name]; - total += trueRange; - if (i > period) total -= quotes[i - period]["True Range " + name]; - prices["True Range " + name] = trueRange; - prices["Sum True Range " + name] = total; - if (i == period) prices["ATR " + name] = total / period; - else if (i > period) - prices["ATR " + name] = - (pd["ATR " + name] * (period - 1) + trueRange) / period; - } -}; - -/** - * Default display function used on 'ATR Trailing Stop' and 'Parabolic SAR' studies to display a series of 'dots' at the required price-date coordinates. - * - * Visual Reference:
- * ![displayPSAR2](img-displayPSAR2.png "displayPSAR2") - * - * @param {CIQ.ChartEngine} stx A chart engine instance - * @param {CIQ.Studies.StudyDescriptor} sd - * @param {array} quotes Array of quotes - * @memberOf CIQ.Studies - */ -CIQ.Studies.displayPSAR2 = function (stx, sd, quotes) { - var panel = stx.panels[sd.panel]; - var yAxis = sd.getYAxis(stx); - var sharingChartAxis = yAxis == stx.chart.panel.yAxis; - stx.startClip(panel.name); - var ctx = sd.getContext(stx); - var squareWave = sd.inputs["Plot Type"] == "squarewave"; - for (var output in sd.outputs) { - var field = output + " " + sd.name; - ctx.beginPath(); - var candleWidth = stx.layout.candleWidth; - var pointWidth = Math.max(3, Math.floor(stx.chart.tmpWidth / 2)); - for (var x = 0; x < quotes.length; x++) { - var quote = quotes[x]; - if (!quote || (!quote[field] && quote[field] !== 0)) continue; - if (quote.candleWidth) candleWidth = quote.candleWidth; - if (sharingChartAxis && quote.transform) quote = quote.transform; - var x0 = stx.pixelFromBar(x, panel.chart); - if (squareWave) x0 -= candleWidth / 2; - var y0 = stx.pixelFromTransformedValue( - quote[sd.referenceOutput ? sd.referenceOutput + " " + sd.name : field], - panel, - yAxis - ); - if ( - x === 0 || - !quotes[x - 1] || - (!quotes[x - 1][field] && quotes[x - 1][field] !== 0) - ) { - ctx.moveTo(x0, y0); - } - if (squareWave) { - ctx.lineTo(x0, y0); - ctx.lineTo(x0 + candleWidth, y0); - if (quotes[x + 1]) { - var quote_1 = quotes[x + 1]; - if (sharingChartAxis && quote_1.transform) - quote_1 = quote_1.transform; - if (!quote_1[field] && quote_1[field] !== 0) { - ctx.lineTo( - x0 + candleWidth, - stx.pixelFromTransformedValue( - quote_1[ - sd.referenceOutput - ? sd.referenceOutput + " " + sd.name - : field - ], - stx.panels[sd.panel], - yAxis - ) - ); - } - } - } else { - ctx.moveTo(x0 - pointWidth / 2, y0); - ctx.lineTo(x0 + pointWidth / 2, y0); - } - } - ctx.lineWidth = 1; - if (sd.highlight) ctx.lineWidth = 3; - var color = CIQ.Studies.determineColor(sd.outputs[output]); - if (color == "auto") color = stx.defaultColor; // This is calculated and set by the kernel before draw operation. - ctx.strokeStyle = color; - if (!sd.highlight && stx.highlightedDraggable) ctx.globalAlpha *= 0.3; - ctx.stroke(); - ctx.closePath(); - ctx.lineWidth = 1; - } - stx.endClip(); -}; - -CIQ.Studies.inputAttributeDefaultGenerator = function (value) { - if (!value && value !== 0) return {}; - if (value.constructor == Number) { - if (Math.floor(value) == value) { - // Integer - if (value > 0) return { min: 1, step: 1 }; // positive - return { step: 1 }; // full range - } - // Decimal - if (value > 0) return { min: 0, step: 0.01 }; // positive - return { step: 0.01 }; // full range - } - return {}; -}; - -/** - * Gets the difference between the local browser time and the market time. - * - * @param {object} params Function parameters. - * @param {CIQ.ChartEngine} params.stx A reference to the chart object. - * @param {object} params.localQuoteDate A Date object that contains the market date and time. - * @param {boolean} params.shiftToDateBoundary Indicates whether the offset for FOREX symbols - * should be adjusted such that the beginning of the trading day (17:00 New York time) falls - * on a date boundary; if so, adds seven hours to the date/time (six for metals). **Note:** - * This parameter applies to FOREX symbols only. No additional time offset is added to - * non-FOREX symbols, regardless of the value of this parameter. - * @return {number} The local browser date/time minus the market date/time in milliseconds. - * - * @memberof CIQ.Studies - * @since - * - 8.0.0 - * - 8.1.0 Removed `isForex` parameter. Added `shiftToDateBoundary` parameter. Added `params` - * parameter and made all other parameters properties of `params`. - */ -CIQ.Studies.getMarketOffset = function ({ - stx, - localQuoteDate, - shiftToDateBoundary -}) { - let isForex; // defer to passed value if present - if (arguments.length > 1) { - stx = arguments[0]; - localQuoteDate = arguments[1]; - isForex = arguments[2]; - } - - const { symbol } = stx.chart; - const isMetal = CIQ.getFn("Market.Symbology.isForexMetal")(symbol); - if (isForex === undefined) { - isForex = CIQ.getFn("Market.Symbology.isForexSymbol")(symbol); - } - - let marketZone; - if (!stx.chart.market) marketZone = null; - else marketZone = isForex ? "America/New_York" : stx.chart.market.market_tz; - - var dt = new Date( - localQuoteDate.getTime() + localQuoteDate.getTimezoneOffset() * 60000 - ); - if (!marketZone || marketZone.indexOf("UTC") == -1) - dt = CIQ.convertTimeZone(dt, "UTC", marketZone); - - let marketOffset = - new Date( - dt.getFullYear(), - dt.getMonth(), - dt.getDate(), - dt.getHours(), - dt.getMinutes(), - dt.getSeconds(), - dt.getMilliseconds() - ).getTime() - localQuoteDate.getTime(); - - if (shiftToDateBoundary && isForex) - marketOffset += (isMetal ? 6 : 7) * 60 * 60 * 1000; - return marketOffset; -}; - -/** - * Function to determine which studies are available. - * @param {object} excludeList Exclusion list of studies in object form ( e.g. {"rsi":true,"macd":true}) - * @returns {object} Map of available entries from {@link CIQ.Studies.studyLibrary}. - * @memberof CIQ.Studies - * @since 3.0.0 - */ -CIQ.Studies.getStudyList = function (excludeList) { - var map = {}; - var excludedStudies = {}; // from time to time put old studies in here to not list them - CIQ.extend(excludedStudies, excludeList); - for (var libraryEntry in CIQ.Studies.studyLibrary) { - if (!excludedStudies[libraryEntry]) - map[CIQ.Studies.studyLibrary[libraryEntry].name] = libraryEntry; - } - return map; -}; - -/** - * A helper function that will find the color value in the output. - * @param {string|object} output Color string value or object that has the color value - * @return {string} Color value - * @memberof CIQ.Studies - * @since 4.0.0 - */ -CIQ.Studies.determineColor = function (output) { - if (!output) { - return null; - } else if (typeof output === "object") { - return output.color; - } - - return output; -}; - -/** - * Calculate function for preparing data to be used by displayChannel(). - * - * Inserts the following fields in the dataSet: - * ``` - * quote[sd.type + " Top " + sd.name]=quote[centerIndex]+totalShift; - * quote[sd.type + " Bottom " + sd.name]=quote[centerIndex]-totalShift; - * quote[sd.type + " Median " + sd.name]=quote[centerIndex]; - * quote["Bandwidth " + sd.name]=200*totalShift/quote[centerIndex]; - * quote["%b " + sd.name]=50*((quote.Close-quote[centerIndex])/totalShift+1); - * ``` - * Example: 'Prime Bands' + ' Top ' + 'Prime Number Bands (true)'. - * @param {CIQ.ChartEngine} stx Chart object - * @param {CIQ.Studies.StudyDescriptor} sd Study Descriptor - * @param {object} percentShift Used to calculate totalShift. Defaults to 0 (zero) - * @param {object} [centerIndex=Close] Quote element to use for center series (Open, Close, High, Low). Defaults to "Close" - * @param {object} [offsetIndex=centerIndex] Quote element to use for calculating totalShift (percentShift*quote[offsetIndex]+pointShift;) - * @param {object} [pointShift=0] Used to calculate totalShift.Defaults to 0 (zero) - * @memberOf CIQ.Studies - */ -CIQ.Studies.calculateGenericEnvelope = function ( - stx, - sd, - percentShift, - centerIndex, - offsetIndex, - pointShift -) { - if (!percentShift) percentShift = 0; - if (!pointShift) pointShift = 0; - if (!centerIndex || centerIndex == "field") centerIndex = "Close"; - if (!offsetIndex) offsetIndex = centerIndex; - var quotes = sd.chart.scrubbed; - var field = sd.inputs.Field; - if (!field || field === "field") field = "Close"; - for (var i = sd.startFrom; quotes && i < quotes.length; i++) { - var quote = quotes[i]; - if (!quote) continue; - if (!quote[centerIndex]) continue; - var closeValue = quote[field]; - if (closeValue && typeof closeValue == "object") - closeValue = closeValue.Close; - var centerValue = quote[centerIndex]; - if (centerValue && typeof centerValue == "object") - centerValue = centerValue[sd.subField]; - var offsetValue = quote[offsetIndex]; - if (offsetValue && typeof offsetValue == "object") - offsetValue = offsetValue[sd.subField]; - var totalShift = percentShift * offsetValue + pointShift; - quote[sd.type + " Top " + sd.name] = centerValue + totalShift; - quote[sd.type + " Bottom " + sd.name] = centerValue - totalShift; - quote[sd.type + " Median " + sd.name] = centerValue; - quote["Bandwidth " + sd.name] = centerValue - ? (200 * totalShift) / centerValue - : 0; - quote["%b " + sd.name] = 50 * ((closeValue - centerValue) / totalShift + 1); - } -}; - -/** - * Rendering function for displaying a Channel study output composed of top, middle and bottom lines. - * - * Requires study library input of `"Channel Fill":true` to determine if the area within the channel is to be shaded. - * Shading will be done using the "xxxxx Channel" or "xxxxx Median" color defined in the outputs parameter of the study library. - * - * Requires study library outputs to have fields in the format of : - * - 'xxxxx Top' or 'xxxxx High' for the top band, - * - 'xxxxx Bottom' or 'xxxxx Low' for the bottom band and - * - 'xxxxx Median' or 'xxxxx Channel' for the middle line. - * - * It expects 'quotes' to have fields for each series in the channel with keys in the following format: - * - study-output-name ( from study library) + " " + sd.name. - * - Example: 'Prime Bands Top'+ ' ' + 'Prime Number Bands (true)'. Which equals : 'Prime Bands Top Prime Number Bands (true)' - * - * @param {CIQ.ChartEngine} stx Chart object - * @param {CIQ.Studies.StudyDescriptor} sd Study Descriptor - * @param {array} quotes The array of quotes needed to render the channel - * @memberOf CIQ.Studies - * @example - * "inputs": {"Period":5, "Shift": 3, "Field":"field", "Channel Fill":true} - * "outputs": {"Prime Bands Top":"red", "Prime Bands Bottom":"auto", "Prime Bands Channel":"rgb(184,44,11)"} - * @example - * // full definition example including opacity - "Bollinger Bands": { - "name": "Bollinger Bands", - "overlay": true, - "calculateFN": CIQ.Studies.calculateBollinger, - "seriesFN": CIQ.Studies.displayChannel, - "inputs": {"Field":"field", "Period":20, "Standard Deviations": 2, "Moving Average Type":"ma", "Channel Fill": true}, - "outputs": {"Bollinger Bands Top":"auto", "Bollinger Bands Median":"auto", "Bollinger Bands Bottom":"auto"}, - "attributes": { - "Standard Deviations":{min:0.1,step:0.1} - }, - "parameters": { - "init":{opacity: 0.2} - } - } - * @since - * - 4.1.0 Now also uses `sd.parameters.opacity` if one defined. - * - 4.1.0 Now shading is rendered under the channel lines instead of over. - */ -CIQ.Studies.displayChannel = function (stx, sd, quotes) { - if (sd.inputs["Channel Fill"]) { - var parameters = { panelName: sd.panel }; - for (var p in sd.outputs) { - var lastWord = p.split(" ").pop(); - if (lastWord == "Top" || lastWord == "High") { - parameters.topBand = p + " " + sd.name; - } else if (lastWord == "Bottom" || lastWord == "Low") { - parameters.bottomBand = p + " " + sd.name; - } else if (lastWord == "Median" || lastWord == "Channel") { - parameters.color = CIQ.Studies.determineColor(sd.outputs[p]); - } - } - if (sd.parameters && sd.parameters.opacity) { - parameters.opacity = sd.parameters.opacity; - } else { - parameters.opacity = 0.2; - } - var panel = stx.panels[sd.panel]; - parameters.skipTransform = panel.name != sd.chart.name; - parameters.yAxis = sd.getYAxis(stx); - if (!sd.highlight && stx.highlightedDraggable) parameters.opacity *= 0.3; - - CIQ.prepareChannelFill(stx, parameters); - } - CIQ.Studies.displaySeriesAsLine(stx, sd, quotes); -}; - -/** - * Initializes an anchor handle element on a study and adds the anchor element to the chart - * controls. If the anchor element and study already exist but the study object has changed, the - * existing anchor element is added to the new study object. **Note:** A study object may change - * without its unique ID changing. - * - * @param {CIQ.ChartEngine} stx A reference to the chart object. - * @param {CIQ.Studies.StudyDescriptor} sd Specifies a study object. - * - * @memberof CIQ.Studies - * @since 8.1.0 - */ -CIQ.Studies.initAnchorHandle = function (stx, sd) { - let { handle } = sd; - if (handle) return; - - if (!stx.controls.anchorHandles) stx.controls.anchorHandles = {}; - - if (stx.controls.anchorHandles[sd.uniqueId]) { - ({ handle } = stx.controls.anchorHandles[sd.uniqueId]); - } else { - handle = document.createElement("div"); - handle.classList.add("stx_anchor_handle"); - handle.setAttribute(sd.uniqueId, ""); - stx.controls.anchorHandles[sd.uniqueId] = { handle, sd }; - stx.controls.chartControls.parentElement.appendChild(handle); - } - - sd.anchorHandle = handle; -}; - -/** - * Removes an anchor handle element from the specified study. - * - * @param {CIQ.ChartEngine} stx A reference to the chart object. - * @param {CIQ.Studies.StudyDescriptor} sd Specifies a study object. - * - * @memberof CIQ.Studies - * @since 8.1.0 - */ -CIQ.Studies.removeAnchorHandle = function (stx, sd) { - const { handle } = (stx.controls.anchorHandles || {})[sd.uniqueId] || {}; - if (handle) { - delete stx.controls.anchorHandles[sd.uniqueId]; - handle.remove(); - } -}; - -/** - * Repositions the anchor for a study to the tick where the anchor element has been dragged. This - * causes the study to be recalculated. If there is no hover location (the anchor has not been - * dragged), the study is recalcuated without changing the anchor. - * - * @param {CIQ.ChartEngine} stx A reference to the chart object. - * @param {CIQ.Studies.StudyDescriptor} sd Specifies a study object. - * - * @memberof CIQ.Studies - * @since 8.1.0 - */ -CIQ.Studies.repositionAnchor = function (stx, sd) { - const { currentAnchorTime, uniqueId } = sd; - const { hoverTick } = stx.repositioningAnchorSelector || {}; - const { dataSet, market } = stx.chart; - const { anchorHandles } = stx.controls; - let newInputs = {}; - - if (hoverTick || hoverTick === 0) { - if (hoverTick >= dataSet.length) return; - - const isDaily = !sd.inputs["Anchor Date"]; - let hoverDate = dataSet[hoverTick].DT; - - const marketOffset = CIQ.Studies.getMarketOffset({ - stx, - localQuoteDate: hoverDate, - shiftToDateBoundary: true - }); - - if ( - isDaily && - new Date(hoverDate.getTime() + marketOffset).getDate() !== - new Date(currentAnchorTime.getTime() + marketOffset).getDate() - ) { - return; - } - - if (market.market_def) { - hoverDate = new timezoneJS.Date(hoverDate, market.market_def.market_tz); - } - - const newAnchorDate = !isDaily && CIQ.dateToStr(hoverDate, "YYYY-MM-dd"); - const newAnchorTime = CIQ.dateToStr(hoverDate, "HH:mm:ss"); - newInputs = { "Anchor Time": newAnchorTime }; - if (newAnchorDate) newInputs["Anchor Date"] = newAnchorDate; - } - - const newSd = CIQ.Studies.replaceStudy( - stx, - sd.inputs.id, - sd.type, - Object.assign(sd.inputs, newInputs), - sd.outputs, - sd.parameters, - sd.panel - ); - - anchorHandles[uniqueId].sd = newSd; - stx.draw(); -}; - -/** - * Displays the anchor element at its current location and a line depicting the hover location of - * the anchor as it is being dragged. Called as part of the draw loop. - * - * @param {CIQ.ChartEngine} stx A reference to the chart object. - * @param {CIQ.Studies.StudyDescriptor} sd Specifies a study object. - * @param {array} quotes The quotes (`dataSegment`) array. - * - * @memberof CIQ.Studies - * @since 8.1.0 - */ -CIQ.Studies.displayAnchorHandleAndLine = function (stx, sd, quotes) { - const currentPanelDragging = - (stx.repositioningAnchorSelector || {}).sd === sd; - const { hoverTick } = currentPanelDragging && stx.repositioningAnchorSelector; - const { chart, panels, xaxisHeight } = stx; - const { market = {}, symbol } = chart; - const panel = panels[sd.panel]; - const { top, bottom, right, left, height } = panel; - const { inputs, anchorHandle: handle, currentAnchorTime } = sd; - const { - backgroundColor: color, - borderLeftColor: colorInvalid - } = stx.canvasStyle("stx_anchor_handle"); - const [hh, mm, ss = 0] = (inputs["Anchor Time"] || "").split(":"); - const isDaily = !inputs["Anchor Date"]; // for anchors without a date - const isForex = CIQ.getFn("Market.Symbology.isForexSymbol")(symbol); - const hoverDate = - (hoverTick || hoverTick === 0) && (stx.chart.dataSet[hoverTick] || {}).DT; - const marketOffset = CIQ.Studies.getMarketOffset({ - stx, - localQuoteDate: quotes[quotes.length - 1].DT, - shiftToDateBoundary: true - }); - const hoverOutOfBounds = - hoverDate && - isDaily && - new Date(hoverDate.getTime() + marketOffset).getDate() !== - new Date(currentAnchorTime.getTime() + marketOffset).getDate(); - const { highlighted } = stx.controls.anchorHandles[sd.uniqueId]; - const [normalOpenHours, normalOpenMins] = market - .getNormalOpen() - .split(":") - .map((x) => parseInt(x)); - - const getPixel = (dt) => { - let tick = dt ? stx.tickFromDate(dt, null, null, true) : hoverTick; - return [stx.pixelFromTick(tick, chart), tick]; - }; - - let anchorTime = isDaily - ? new Date(quotes[quotes.length - 1].DT) // if no anchor date diplay at right most - : CIQ.strToDate(inputs["Anchor Date"]); - - if (market.market_def) { - anchorTime = new timezoneJS.Date(anchorTime, market.market_def.market_tz); - } - - anchorTime.setHours(hh, mm, ss); - - // This will allow us to shift the anchor and end of day to compensate for the midnight-bisected - // nature of FOREX market sessions - const firstSection = - isForex && - (anchorTime.getHours() > normalOpenHours || - (anchorTime.getHours() === normalOpenHours && - anchorTime.getMinutes() >= normalOpenMins)); - - if (firstSection) anchorTime.setDate(anchorTime.getDate() - 1); - - let [hoverPixel] = getPixel(); - let [currentPixel, currentTick] = getPixel(anchorTime); - let endOfDay = new Date(anchorTime); - endOfDay.setHours(...market.getNormalClose().split(":")); - if (firstSection) endOfDay.setDate(endOfDay.getDate() + 1); - - const [endOfDayPixel] = (endOfDay && getPixel(endOfDay)) || []; - - if (isDaily && (currentPixel > right || endOfDayPixel > right)) { - // rewind if necessary to get anchor on day that is fully visible - let shiftedAnchor = new Date(anchorTime); - do { - shiftedAnchor.setDate(shiftedAnchor.getDate() - 1); - } while (market && !market.isMarketDate(shiftedAnchor)); - // if new position is off the left of the chart don't both shifting - let [shiftedPixel, shiftedTick] = getPixel(shiftedAnchor); - if (shiftedPixel > left) { - anchorTime = shiftedAnchor; - currentPixel = shiftedPixel; - currentTick = shiftedTick; - } - } - - const lineConfig = { - y0: top, - y1: bottom, - type: "line", - confineToPanel: panel - }; - - stx.plotLine( - Object.assign(lineConfig, { - x0: currentPixel, - x1: currentPixel, - color: color, - pattern: "solid", - lineWidth: highlighted ? 3 : 2, - opacity: 1 - }) - ); - - stx.plotLine( - Object.assign(lineConfig, { - x0: hoverPixel, - x1: hoverPixel, - color: hoverOutOfBounds ? colorInvalid : color, - pattern: [6, 6], - lineWidth: 2, - opacity: hoverOutOfBounds ? 0.5 : 1 - }) - ); - - handle.style.height = [8, height / 4, 50].sort((a, b) => a - b)[1] + "px"; // use middle value - const { height: aHeight, width: aWidth } = handle.getBoundingClientRect(); - const isBottomOffset = Math.round(bottom) === stx.height ? xaxisHeight : 0; - const isChartPanelOffset = panel.name === "chart" ? 35 : 0; - const verticalOffset = 10 + isBottomOffset + isChartPanelOffset + aHeight; - - handle.style.top = bottom - verticalOffset + "px"; - handle.style.left = - hoverTick || hoverTick === 0 - ? hoverPixel - : currentPixel - aWidth / 2 + "px"; - - sd.currentAnchorTime = anchorTime; - sd.currentAnchorTick = currentTick; -}; - -// object to keep track of the custom scripts -CIQ.Studies.studyScriptLibrary = {}; - -/** - * The `studyLibrary` defines all of the available studies. - * - * This is used to drive the dialog boxes and creation of the studies. When you - * create a custom study you should add it to the studyLibrary. - * - * You can also alter study defaults by overriding the different elements on each definition. - * For example, if you wanted to change the default colors for the volume underlay, - * you would add the following code in your files; making sure your files are loaded **after** the library js files -- not before: - * ``` - * CIQ.Studies.studyLibrary["vol undr"].outputs= {"Up Volume":"blue","Down Volume":"yellow"}; - * ``` - * See {@tutorial Using and Customizing Studies} for complete details. - * @type {Object} - * @memberof CIQ.Studies - * @example - * "RAVI": { - * "name": "RAVI", - * "seriesFN": CIQ.Studies.displayRAVI, - * "calculateFN": CIQ.Studies.calculatePriceOscillator, - * "inputs": {"Field":"field", "Short Cycle":7, "Long Cycle":65}, - * "outputs": {"Increasing Bar":"#00DD00", "Decreasing Bar":"#FF0000"}, - * "parameters": { - * init:{studyOverZonesEnabled:true, studyOverBoughtValue:3, studyOverBoughtColor:"auto", studyOverSoldValue:-3, studyOverSoldColor:"auto"} - * }, - * "attributes":{ - * "studyOverBoughtValue":{"min":0,"step":"0.1"}, - * "studyOverSoldValue":{"max":0,"step":"0.1"} - * } - * } - */ -CIQ.Studies.studyLibrary = CIQ.Studies.studyLibrary || {}; -CIQ.extend(CIQ.Studies.studyLibrary, { - ma: { - name: "Moving Average", - overlay: true, - calculateFN: CIQ.Studies.calculateMovingAverage, - inputs: { Period: 50, Field: "field", Type: "ma", Offset: 0 }, - outputs: { MA: "#FF0000" } - }, - "STD Dev": { - name: "Standard Deviation", - calculateFN: CIQ.Studies.calculateStandardDeviation, - inputs: { - Period: 14, - Field: "field", - "Standard Deviations": 2, - "Moving Average Type": "ma" - }, - attributes: { - "Standard Deviations": { min: 0.1, step: 0.1 } - } - }, - "True Range": { - name: "True Range", - calculateFN: CIQ.Studies.calculateStudyATR, - inputs: {}, - outputs: { "True Range": "auto" } - }, - volume: { - name: "Volume Chart", - range: "0 to max", - yAxis: { ground: true, initialMarginTop: 0, zoom: 0 }, - seriesFN: CIQ.Studies.createVolumeChart, - calculateFN: CIQ.Studies.calculateVolume, - inputs: {}, - outputs: { "Up Volume": "#8cc176", "Down Volume": "#b82c0c" } - } -}); - -}; - - -let __js_standard_symbolLookupBase_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -if (!CIQ.ChartEngine.Driver) { - console.error( - "symbolLookupBase feature requires first activating quoteFeed feature." - ); -} else { - /** - * Base class that drives the lookup (Symbol Search) functionality. - * - * You should derive your own Driver.Lookup that interacts with your datafeed. - * - * This is used with the [cq-lookup web component]{@link WebComponents.cq-lookup} and [CIQ.UI.Context.setLookupDriver](CIQ.UI.Context.html#setLookupDriver) - * - * @name CIQ.ChartEngine.Driver.Lookup - * @constructor - * @param {string[]} exchanges An array of exchanges that can be searched against - * @example - * // sample implementation - * CIQ.ChartEngine.Driver.Lookup.ChartIQ=function(exchanges){ - * this.exchanges=exchanges; - * if(!this.exchanges) this.exchanges=["XNYS","XASE","XNAS","XASX","INDCBSX","INDXASE","INDXNAS","IND_DJI","ARCX","INDARCX","forex"]; - * this.url="https://symbols.chartiq.com/chiq.symbolserver.SymbolLookup.service"; - * this.requestCounter=0; //used to invalidate old requests - * }; - * - * //Inherits all of the base Lookup Driver's properties via `CIQ.inheritsFrom()` - * CIQ.inheritsFrom(CIQ.ChartEngine.Driver.Lookup.ChartIQ,CIQ.ChartEngine.Driver.Lookup); - * @since 6.0.0 - */ - CIQ.ChartEngine.Driver.Lookup = function (exchanges) {}; - - /** - * **Abstract method** used to accept the selected text with optional filter and return an array of properly formatted objects. - * - * You should implement your own instance of this method to fetch results from your symbol list and return them by calling cb(your-results-array-here); - * - * Each element in the array should be of the following format: - * { - * display:["symbol-id","Symbol Description","exchange"], - * data:{ - * symbol:"symbol-id", - * name:"Symbol Description", - * exchDis:"exchange" - * } - * } - * - * @param {string} text The text entered by the user - * @param {string} [filter] The optional filter text selected by the user. This will be the innerHTML of the cq-filter element that is selected. - * @param {number} maxResults Max number of results to return from the server - * @param {function} cb Callback upon results - * @memberof CIQ.ChartEngine.Driver.Lookup - * @example - // sample implementation - CIQ.ChartEngine.Driver.Lookup.ChartIQ.prototype.acceptText=function(text, filter, maxResults, cb){ - if(filter=="FX") filter="FOREX"; - if(isNaN(parseInt(maxResults, 10))) maxResults=100; - var url=this.url+"?t=" + encodeURIComponent(text) + "&m="+maxResults+"&x=["; - if(this.exchanges){ - url+=this.exchanges.join(","); - } - url+="]"; - if(filter && filter.toUpperCase()!="ALL"){ - url+="&e=" + filter; - } - - var counter=++this.requestCounter; - var self=this; - function handleResponse(status, response){ - if(counter { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -/** - * Generates an object that can be used programmatically to load new themes or to create a theme dialog to manage chart themes. - * The initial values contain the existing values in the current chart. - * Simply have your dialog modify these values and then call the method {@link CIQ.ThemeHelper#update} - * - * Note that the chart has many granular customizations beyond what this theme helper produces. - * This helper simplifies and consolidates into a manageable set. - * For example 'hallow candles', 'bars' and 'candles' colors are all grouped together. - * But if you need to separate those out, just call an explicit {@link CIQ.ChartEngine#setStyle} for each CSS style right after the ThemeHelper is executed. - * - * For example, This will further set the color for the hollow_candle chart type: - * ``` - * stxx.setStyle("stx_hollow_candle_down","color",'blue'); - * stxx.setStyle("stx_hollow_candle_up","color",'yellow'); - * stxx.setStyle("stx_hollow_candle_even","color",'pink'); - * stxx.draw(); - * ``` - * See {@tutorial Chart Styles and Types} for more details. - * - * Generally speaking, themes can be managed by simply adding or removing from the chart context the class name that groups the theme together. - * And as long as the CSS contains an entry for that class, the chart will display the styles in the class when enabled. - * - * For example, assume the chart has a default theme and a second theme called 'ciq-night'. - * Here are some examples of what CSS entries for those classes would look like: - * ``` - * // default theme (day) styles - * .stx_candle_shadow, .stx_bar_even { - * color:#2e383b; - * - * } - * .stx_candle_down, .stx_line_down { - * border-left-color: #000000; - * } - * - * // night theme override styles - * .ciq-night .stx_candle_shadow, .ciq-night .stx_bar_even { - * color: #ccc; - * } - * .ciq-night .stx_candle_down, .ciq-night .stx_line_down { - * border-left-color: #e34621; - * } - * ``` - * - * Then to activate a particular theme, you either remove the specific class to enable default (day): - * ``` - * document.querySelector("cq-context").classList.remove('ciq-night'); - * // clear out the old styles to allow new ones to be cached in; and redraw. - * stxx.styles={};stxx.draw(); - * ``` - * Or add a particular class to enable those styles: - * ``` - * document.querySelector("cq-context").classList.add('ciq-night'); - * // clear out the old styles to allow new ones to be cached in; and redraw. - * stxx.styles={};stxx.draw(); - * ``` - * You can use this method to set as many themes as needed. Remember that this method, requires all styles to be present in the CSS. - * ThemeHelper, on the other hand, will programmatically set the styles internally, one at a time, regardless of pre-existng CSS classes. - * - * @param {object} params Parameters - * @param {CIQ.ChartEngine} params.stx A chart object - * @constructor - * @name CIQ.ThemeHelper - * @example - * var helper=new CIQ.ThemeHelper({stx:stx}); - * console.log(helper.settings); - * helper.settings.chart["Grid Lines"].color="rgba(255,0,0,.5)"; - * helper.update(); - * - * @since 6.2.0 Added support to control `Mountain.basecolor`. - */ -CIQ.ThemeHelper = - CIQ.ThemeHelper || - function (params) { - this.params = params; - var stx = params.stx; - var backgroundColor = "#FFFFFF"; - if (stx.chart.container) { - backgroundColor = getComputedStyle(stx.chart.container).backgroundColor; - if (CIQ.isTransparent(backgroundColor)) - backgroundColor = stx.containerColor; - } - this.settings.chart.Background.color = CIQ.hexToRgba(backgroundColor); - this.settings.chart["Grid Lines"].color = CIQ.hexToRgba( - stx.canvasStyle("stx_grid").color - ); - this.settings.chart["Grid Dividers"].color = CIQ.hexToRgba( - stx.canvasStyle("stx_grid_dark").color - ); - this.settings.chart["Axis Text"].color = CIQ.hexToRgba( - stx.canvasStyle("stx_xaxis").color - ); - - this.settings.chartTypes["Candle/Bar"].up.color = CIQ.hexToRgba( - stx.canvasStyle("stx_candle_up").color - ); - - this.settings.chartTypes["Candle/Bar"].down.color = CIQ.hexToRgba( - stx.canvasStyle("stx_candle_down").color - ); - this.settings.chartTypes["Candle/Bar"].up.wick = CIQ.hexToRgba( - stx.canvasStyle("stx_candle_shadow_up").color - ); - this.settings.chartTypes["Candle/Bar"].down.wick = CIQ.hexToRgba( - stx.canvasStyle("stx_candle_shadow_down").color - ); - this.settings.chartTypes["Candle/Bar"].even.wick = CIQ.hexToRgba( - stx.canvasStyle("stx_candle_shadow_even").color - ); - this.settings.chartTypes["Candle/Bar"].up.border = CIQ.hexToRgba( - stx.canvasStyle("stx_candle_up").borderLeftColor - ); - this.settings.chartTypes["Candle/Bar"].down.border = CIQ.hexToRgba( - stx.canvasStyle("stx_candle_down").borderLeftColor - ); - if (CIQ.isTransparent(stx.canvasStyle("stx_candle_up").borderLeftColor)) - this.settings.chartTypes["Candle/Bar"].up.border = null; - if (CIQ.isTransparent(stx.canvasStyle("stx_candle_down").borderLeftColor)) - this.settings.chartTypes["Candle/Bar"].down.border = null; - - this.settings.chartTypes.Line.color = CIQ.hexToRgba( - stx.canvasStyle("stx_line_chart").color - ); - - this.settings.chartTypes.Mountain.color = CIQ.hexToRgba( - stx.canvasStyle("stx_mountain_chart").backgroundColor - ); - this.settings.chartTypes.Mountain.basecolor = CIQ.hexToRgba( - stx.canvasStyle("stx_mountain_chart").color - ); - }; - -/** - * Current theme settings. These are the settings that are ready to be loaded, or currently loaded. - * Modify as needed. - * To load these settings call {@link CIQ.ThemeHelper#update} - * @example - * //Default settings object structure - * "chart":{ - "Background":{ - "color":color1 - }, - "Grid Lines":{ - "color":color2 - }, - "Grid Dividers":{ - "color":color3 - }, - "Axis Text":{ - "color":color4 - } - }, - "chartTypes":{ - "Candle/Bar":{ // also manages 'hollow candle', 'colored line' and 'colored baseline' chart types. - "up":{ - "color":color5, - "wick":color6, - "border":color7 - }, - "down":{ - "color":color8, - "wick":color9, - "border":color10 - }, - "even":{ // colors used when the current close is equal to the previous close. - "color":color11, - "wick":color12, - "border":color13 - } - }, - "Line":{ - "color":color14 - }, - "Mountain":{ - "color":color15, - "basecolor":color16 - } - } - * @memberof CIQ.ThemeHelper - * @type object - */ -CIQ.ThemeHelper.prototype.settings = { - chart: { - Background: { - color: null - }, - "Grid Lines": { - color: null - }, - "Grid Dividers": { - color: null - }, - "Axis Text": { - color: null - } - }, - chartTypes: { - "Candle/Bar": { - up: { - color: null, - wick: null, - border: null - }, - down: { - color: null, - wick: null, - border: null - }, - even: { - color: null, - wick: null, - border: null - } - }, - Line: { - color: null - }, - Mountain: { - color: null, - basecolor: null - } - } -}; - -/** - * Call this method to activate the chart theme with values set in {@link CIQ.ThemeHelper#settings} - * @memberof CIQ.ThemeHelper - * @param {CIQ.ChartEngine} [stx] Chart engine to apply the changes to. - * @example - * var helper=new CIQ.ThemeHelper({stx:stx}); - * console.log(helper.settings); - * helper.settings=NewSettings; - * helper.update(); - * @since - * - 4.1.0 Added optional chart engine parameter. - * - 6.2.0 Now setting base color and color of mountain chart with separate colors. - * - 6.3.0 Colored Bar, Hollow Candle, Volume Candle charts now use `chartTypes["Candle/Bar"].even.color` for even bar color. - */ -CIQ.ThemeHelper.prototype.update = function (stx) { - if (!stx) stx = this.params.stx; - var classMapping = { - stx_candle_up: { - stx_candle_up: true, - stx_bar_up: true, - stx_hollow_candle_up: true, - stx_line_up: true, - stx_baseline_up: true - }, - stx_candle_down: { - stx_candle_down: true, - stx_bar_down: true, - stx_hollow_candle_down: true, - stx_line_down: true, - stx_baseline_down: true - }, - stx_candle_even: { stx_hollow_candle_even: true, stx_bar_even: true }, - stx_shadow_up: { stx_candle_shadow_up: true }, - stx_shadow_down: { stx_candle_shadow_down: true }, - stx_shadow_even: { stx_candle_shadow_even: true }, - stx_line_chart: { stx_bar_chart: true, stx_line_chart: true }, - stx_grid: { stx_grid: true }, - stx_grid_dark: { stx_grid_dark: true }, - stx_xaxis: { - stx_xaxis_dark: true, - stx_xaxis: true, - stx_yaxis: true, - stx_yaxis_dark: true, - stx_grid_border: true - }, - stx_mountain_chart: { stx_mountain_chart: true }, - stx_market_session: { stx_market_session: true } - }; - - stx.chart.container.style.backgroundColor = this.settings.chart.Background.color; - stx.defaultColor = ""; // to be set later, elsewhere - - function setStyle(style, field, value) { - var styles = classMapping[style]; - for (var s in styles) { - stx.setStyle(s, field, value); - } - } - - setStyle("stx_grid", "color", this.settings.chart["Grid Lines"].color); - setStyle( - "stx_grid_dark", - "color", - this.settings.chart["Grid Dividers"].color - ); - setStyle("stx_xaxis", "color", this.settings.chart["Axis Text"].color); - - var candleBar = this.settings.chartTypes["Candle/Bar"]; - // backwards compatibility with pre-5.0.3 saved themes - if (!candleBar.even) { - candleBar.even = { - color: null, - wick: CIQ.hexToRgba(stx.canvasStyle("stx_candle_shadow_even").color), - border: null - }; - } - setStyle("stx_candle_up", "color", candleBar.up.color); - setStyle("stx_candle_down", "color", candleBar.down.color); - setStyle("stx_candle_even", "color", candleBar.even.color); - setStyle("stx_shadow_up", "color", candleBar.up.wick); - setStyle("stx_shadow_down", "color", candleBar.down.wick); - setStyle("stx_shadow_even", "color", candleBar.even.wick); - - // Only apply borders to candle, not the other types - stx.setStyle("stx_candle_up", "borderLeftColor", candleBar.up.border); - stx.setStyle("stx_candle_down", "borderLeftColor", candleBar.down.border); - - setStyle("stx_line_chart", "color", this.settings.chartTypes.Line.color); - - stx.setStyle( - "stx_mountain_chart", - "borderTopColor", - CIQ.hexToRgba(this.settings.chartTypes.Mountain.color, 1) - ); - stx.setStyle( - "stx_mountain_chart", - "backgroundColor", - CIQ.hexToRgba(this.settings.chartTypes.Mountain.color, 0.5) - ); - stx.setStyle( - "stx_mountain_chart", - "color", - CIQ.hexToRgba(this.settings.chartTypes.Mountain.basecolor, 0.01) - ); - stx.draw(); -}; - -/** - * Convenience method to programmatically set a theme of the chart. - * - * Note that you should set any css classes on the chart context before calling this method - * - * @param {object} [settings] A {@link CIQ.ThemeHelper#settings} object, or null to reset to default settings - * @example - * document.querySelector("cq-context").classList.add("ciq-night"); - * stxx.setThemeSettings(); // reset to night theme - * var settings=CIQ.clone(CIQ.ThemeHelper.prototype.settings); // default night theme settings - * settings.chart.Background.color="red"; // customize by changing background color - * stxx.setThemeSettings(settings); // execute custom setting - * - * @memberof CIQ.ChartEngine - * @since 6.3.0 - */ -CIQ.ChartEngine.prototype.setThemeSettings = function (settings) { - this.styles = {}; - this.chart.container.style.backgroundColor = ""; - this.defaultColor = ""; - if (settings) { - var helper = new CIQ.ThemeHelper({ stx: this }); - helper.settings = settings; - helper.update(); - } - this.updateListeners("theme"); - this.changeOccurred("theme"); - if (this.displayInitialized) { - this.headsUpHR(); - this.clearPixelCache(); - this.updateListeners("theme"); // Not sure if this is necessary, but leaving here just in case. - this.draw(); - } -}; - -}; - - -let __js_standard_timezone_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; -var timezoneJS = - typeof _timezoneJS !== "undefined" ? _timezoneJS : _exports.timezoneJS; - -/** - * The comprehensive list of timezones can be overwhelming. This is a reduced list that provides - * what is necessary for the [sample UI]{@link WebComponents.cq-theme-dialog}. - * - * To see the current list and format, open your browser console and type `CIQ.timeZoneMap`. - * - * There are more timezones loaded in the the chart by default. You can get a list by running `timezoneJS.timezone.getAllZones();` from your browser console. - * Feel free to add what you need to this map if you want users to use them. - * - * If you need to support other timezones, not currently loaded, a complete list can be downloaded from [here](http://download.chartiq.com/timeZones/timezoneDataObject.txt). - * - * This file is large, so add timezones with discretion.
- * Although we do update this file periodically ,it may not be available immediately after every timezone change. - * As such, if you require immediate updates, you should subscribe to a notification system that alerts you of these changes, and then adjust the file as needed. - * www.iana.org/time-zones is a good source. - * - * The following code snippet demonstrates how to do this. (You can also just add synonyms this way as well). - * In order to save space, you may want to cherry pick the zones that you will need, and then add them in your initialization code. - * ``` - * var myAdditionalZones = { - * "zones" : { - * "America/Toronto": [ - * [ 300, "Canada", "E%sT", null ] - * ] - * }, - * "rules" : { - * "Canada" : [ - * [ 2007, "max", "-", "Mar", "Sun>=8", [ 2, 0, 0, null ], 60, "D" ], - * [ 2007, "max", "-", "Nov", "Sun>=1", [ 2, 0, 0, null ], 0, "S" ] ] - * } - * } - * - * // to add all timezones "zones" and "rules" you can simply load the entire timeZoneDataObject.txt file. - * if(timezoneJS) timezoneJS.timezone.loadZoneDataFromObject(myAdditionalZones); - * ``` - * Lastly, if you want users to be able to use the new timezones from the menus, be sure to also add the title for them to the `CIQ.timeZoneMap` object to keep the list and the settings in sync: - * ``` - * CIQ.timeZoneMap["(UTC-05:00) Toronto"]="America/Toronto"; - * ``` - * - * See {@link CIQ.ChartEngine#setTimeZone} for further instructions on how to set the different timezones on the chart. - * - * @type {object} - * @memberof CIQ - */ -CIQ.timeZoneMap = { - "(UTC-11:00) American Samoa, Midway Island": "Pacific/Pago_Pago", - "(UTC-10:00) Hawaii": "Pacific/Honolulu", - "(UTC-09:00) Alaska": "America/Juneau", - "(UTC-08:00) Pacific Time (US and Canada), Tijuana": "America/Los_Angeles", - "(UTC-07:00) Arizona": "America/Phoenix", - "(UTC-07:00) Chihuahua, Mazatlan": "America/Chihuahua", - "(UTC-07:00) Mountain Time (US and Canada)": "America/Denver", - "(UTC-06:00) Central America": "America/Costa_Rica", - "(UTC-06:00) Central Time (US and Canada)": "America/Chicago", - "(UTC-06:00) Guadalajara, Mexico City, Monterrey": "America/Mexico_City", - "(UTC-06:00) Saskatchewan": "America/Regina", - "(UTC-05:00) Bogota, Lima, Quito, Rio Branco": "America/Bogota", - "(UTC-05:00) Eastern Time (US and Canada)": "America/New_York", - "(UTC-05:00) Havana": "America/Havana", - "(UTC-05:00) Port-au-Prince": "America/Port-au-Prince", - "(UTC-04:00) Asuncion": "America/Asuncion", - "(UTC-04:00) Santiago": "America/Santiago", - "(UTC-04:00) Caracas": "America/Caracas", - "(UTC-04:00) Atlantic Time (Canada)": "America/Halifax", - "(UTC-04:00) Georgetown, La Paz, Manaus, San Juan": "America/Puerto_Rico", - "(UTC-03:30) Newfoundland and Labrador": "America/St_Johns", - "(UTC-03:00) Cancun, Jamaica, Panama": "America/Panama", - "(UTC-03:00) Buenos Aires": "America/Argentina/Buenos_Aires", - "(UTC-03:00) Punta Arenas": "America/Punta_Arenas", - "(UTC-03:00) Montevideo": "America/Montevideo", - "(UTC-03:00) Sao Paulo": "America/Sao_Paulo", - "(UTC-02:00) Mid-Atlantic": "Atlantic/South_Georgia", - "(UTC-01:00) Azores": "Atlantic/Azores", - "(UTC-01:00) Cape Verde Islands": "Atlantic/Cape_Verde", - "(UTC) Greenwich Mean Time, Reykjavik": "UTC", - "(UTC) Dublin": "Europe/Dublin", - "(UTC) Lisbon, London": "Europe/London", - "(UTC+01:00) Algiers, Tunis": "Africa/Tunis", - "(UTC+01:00) Casablanca": "Africa/Casablanca", - "(UTC+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna": - "Europe/Amsterdam", - "(UTC+01:00) Belgrade, Bratislava, Budapest, Ljubljana, Prague": - "Europe/Belgrade", - "(UTC+01:00) Brussels, Copenhagen, Madrid, Paris": "Europe/Brussels", - "(UTC+01:00) Sarajevo, Skopje, Warsaw, Zagreb": "Europe/Sarajevo", - "(UTC+02:00) Kaliningrad": "Europe/Kaliningrad", - "(UTC+02:00) Athens, Bucharest": "Europe/Bucharest", - "(UTC+02:00) Cairo": "Africa/Cairo", - "(UTC+02:00) Harare, Johannesburg": "Africa/Johannesburg", - "(UTC+02:00) Helsinki, Kiev, Riga, Sofia, Tallinn, Vilnius": - "Europe/Helsinki", - "(UTC+02:00) Cyprus": "Asia/Nicosia", - "(UTC+02:00) Beirut": "Asia/Beirut", - "(UTC+02:00) Damascus": "Asia/Damascus", - "(UTC+02:00) Jerusalem": "Asia/Jerusalem", - "(UTC+02:00) Amman": "Asia/Amman", - "(UTC+03:00) Istanbul": "Europe/Istanbul", - "(UTC+03:00) Baghdad, Kuwait, Qatar, Riyadh": "Asia/Riyadh", - "(UTC+03:00) Minsk, Moscow, Kirov, Simferopol": "Europe/Moscow", - "(UTC+03:00) Volgograd": "Europe/Volgograd", - "(UTC+03:00) Nairobi": "Africa/Nairobi", - "(UTC+03:30) Tehran": "Asia/Tehran", - "(UTC+04:00) Baku": "Asia/Baku", - "(UTC+04:00) Dubai, Muscat": "Asia/Dubai", - "(UTC+04:00) Astrakhan, Samara, Saratov, Ulyanovsk": "Europe/Samara", - "(UTC+04:30) Kabul": "Asia/Kabul", - "(UTC+05:00) Karachi, Tashkent": "Asia/Karachi", - "(UTC+05:00) Yekaterinburg": "Asia/Yekaterinburg", - "(UTC+05:30) Chennai, Kolkata, Mumbai, New Delhi": "Asia/Kolkata", - "(UTC+05:45) Kathmandu": "Asia/Kathmandu", - "(UTC+06:00) Almaty": "Asia/Almaty", - "(UTC+06:00) Omsk": "Asia/Omsk", - "(UTC+06:00) Astana, Dhaka": "Asia/Dhaka", - "(UTC+06:30) Yangon": "Asia/Yangon", - "(UTC+07:00) Bangkok, Jakarta, Vietnam": "Asia/Bangkok", - "(UTC+07:00) Hovd": "Asia/Hovd", - "(UTC+07:00) Krasnoyarsk": "Asia/Krasnoyarsk", - "(UTC+07:00) Novokuznetsk": "Asia/Novokuznetsk", - "(UTC+07:00) Barnaul, Novosibirsk, Tomsk": "Asia/Novosibirsk", - "(UTC+08:00) Beijing, Chongqing, Hong Kong SAR": "Asia/Hong_Kong", - "(UTC+08:00) Brunei, Kuala Lumpur, Singapore": "Asia/Kuala_Lumpur", - "(UTC+08:00) Irkutsk": "Asia/Irkutsk", - "(UTC+08:00) Choibalsan, Ulaanbaatar": "Asia/Ulaanbaatar", - "(UTC+08:00) Manila, Taipei": "Asia/Taipei", - "(UTC+08:00) Perth": "Australia/Perth", - "(UTC+08:45) Eucla": "Australia/Eucla", - "(UTC+09:00) Osaka, Sapporo, Tokyo": "Asia/Tokyo", - "(UTC+09:00) Pyongyang": "Asia/Pyongyang", - "(UTC+09:00) Seoul": "Asia/Seoul", - "(UTC+09:00) Chita, Khandyga, Yakutsk": "Asia/Yakutsk", - "(UTC+09:30) Adelaide": "Australia/Adelaide", - "(UTC+09:30) Darwin": "Australia/Darwin", - "(UTC+10:00) Brisbane": "Australia/Brisbane", - "(UTC+10:00) Canberra, Melbourne, Sydney": "Australia/Sydney", - "(UTC+10:00) Guam, Port Moresby": "Pacific/Guam", - "(UTC+10:00) Ust-Nera, Vladivostok": "Asia/Vladivostok", - "(UTC+11:00) Noumea, Solomon Islands": "Pacific/Noumea", - "(UTC+11:00) Magadan": "Asia/Magadan", - "(UTC+11:00) Sakhalin, Srednekolymsk": "Asia/Srednekolymsk", - "(UTC+12:00) Anadyr, Kamchatka": "Asia/Kamchatka", - "(UTC+12:00) Auckland, Wellington": "Pacific/Auckland", - "(UTC+12:00) Fiji": "Pacific/Fiji", - "(UTC+12:45) Chatham": "Pacific/Chatham", - "(UTC+13:00) Tonga": "Pacific/Tongatapu", - "(UTC+13:00) Samoa": "Pacific/Apia", - "(UTC+14:00) Kiritimati": "Pacific/Kiritimati" -}; - -// ----- -// The `timezoneJS.Date` object gives you full-blown timezone support, independent from the timezone set on the end-user's machine running the browser. It uses the Olson zoneinfo files for its timezone data. -// -// The constructor function and setter methods use proxy JavaScript Date objects behind the scenes, so you can use strings like '10/22/2006' with the constructor. You also get the same sensible wraparound behavior with numeric parameters (like setting a value of 14 for the month wraps around to the next March). -// -// The other significant difference from the built-in JavaScript Date is that `timezoneJS.Date` also has named properties that store the values of year, month, date, etc., so it can be directly serialized to JSON and used for data transfer. - -/*! - * Copyright 2010 Matthew Eernisse (mde@fleegix.org) - * and Open Source Applications Foundation - * - * Licensed under the Apache License, Version 2.0 (the 'License'); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an 'AS IS' BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * Credits: Ideas included from incomplete JS implementation of Olson - * parser, 'XMLDAte' by Philippe Goetz (philippe.goetz@wanadoo.fr) - * - * Contributions: - * Jan Niehusmann - * Ricky Romero - * Preston Hunt (prestonhunt@gmail.com) - * Dov. B Katz (dov.katz@morganstanley.com) - * Peter Bergström (pbergstr@mac.com) - * Long Ho - * - * Modified from original by ChartIQ to include caching for improved performance - */ - -/*jshint laxcomma:true, laxbreak:true, expr:true, supernew:true*/ -(function () { - // Standard initialization stuff to make sure the library is - // usable on both client and server (node) side. - "use strict"; - var _window = typeof window !== "undefined" ? window : null; - var root = _window || (typeof global !== "undefined" ? global : {}); - - timezoneJS.VERSION = "0.4.11"; - - // Grab the ajax library from global context. - // This can be jQuery, Zepto or fleegix. - // You can also specify your own transport mechanism by declaring - // `timezoneJS.timezone.transport` to a `function`. More details will follow - var ajax_lib = root.$ || root.jQuery || root.Zepto, - fleegix = root.fleegix, - // Declare constant list of days and months. Unfortunately this doesn't leave room for i18n due to the Olson data being in English itself - DAYS = (timezoneJS.Days = [ - "Sunday", - "Monday", - "Tuesday", - "Wednesday", - "Thursday", - "Friday", - "Saturday" - ]), - MONTHS = (timezoneJS.Months = [ - "January", - "February", - "March", - "April", - "May", - "June", - "July", - "August", - "September", - "October", - "November", - "December" - ]), - SHORT_MONTHS = {}, - SHORT_DAYS = {}, - EXACT_DATE_TIME = {}; - - //`{ 'Jan': 0, 'Feb': 1, 'Mar': 2, 'Apr': 3, 'May': 4, 'Jun': 5, 'Jul': 6, 'Aug': 7, 'Sep': 8, 'Oct': 9, 'Nov': 10, 'Dec': 11 }` - for (var i = 0; i < MONTHS.length; i++) { - SHORT_MONTHS[MONTHS[i].substr(0, 3)] = i; - } - - //`{ 'Sun': 0, 'Mon': 1, 'Tue': 2, 'Wed': 3, 'Thu': 4, 'Fri': 5, 'Sat': 6 }` - for (i = 0; i < DAYS.length; i++) { - SHORT_DAYS[DAYS[i].substr(0, 3)] = i; - } - - //Handle array indexOf in IE - //From https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/indexOf - //Extending Array prototype causes IE to iterate thru extra element - var _arrIndexOf = - Array.prototype.indexOf || - function (el) { - if (this === null) { - throw new TypeError(); - } - var t = Object(this); - var len = t.length >>> 0; - if (len === 0) { - return -1; - } - var n = 0; - if (arguments.length > 1) { - n = Number(arguments[1]); - if (n != n) { - // shortcut for verifying if it's NaN - n = 0; - } else if (n !== 0 && n !== Infinity && n !== -Infinity) { - n = (n > 0 || -1) * Math.floor(Math.abs(n)); - } - } - if (n >= len) { - return -1; - } - var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0); - for (; k < len; k++) { - if (k in t && t[k] === el) { - return k; - } - } - return -1; - }; - - // Format a number to the length = digits. For ex: - // - // `_fixWidth(2, 2) = '02'` - // - // `_fixWidth(1998, 2) = '98'` // year, shorten it to the 2 digit representation - // - // `_fixWidth(23, 1) = '23'` // hour, even with 1 digit specified, do not trim - // - // This is used to pad numbers in converting date to string in ISO standard. - var _fixWidth = function (number, digits) { - if (typeof number !== "number") { - throw "not a number: " + number; - } - var trim = number > 1000; // only trim 'year', as the others don't make sense why anyone would want that - var s = number.toString(); - var s_len = s.length; - if (trim && s_len > digits) { - return s.substr(s_len - digits, s_len); - } - s = [s]; - while (s_len < digits) { - s.unshift("0"); - s_len++; - } - return s.join(""); - }; - - // Abstraction layer for different transport layers, including fleegix/jQuery/Zepto/Node.js - // - // Object `opts` include - // - // - `url`: url to ajax query - // - // - `async`: true for asynchronous, false otherwise. If false, return value will be response from URL. This is true by default - // - // - `success`: success callback function - // - // - `error`: error callback function - // Returns response from URL if async is false, otherwise the AJAX request object itself - var _transport = function (opts) { - if (!opts) return; - if (!opts.url) throw new Error("URL must be specified"); - if (!("async" in opts)) opts.async = true; - // Client-side - if ( - (!fleegix || typeof fleegix.xhr === "undefined") && - (!ajax_lib || typeof ajax_lib.ajax === "undefined") - ) { - throw new Error( - "Please use the Fleegix.js XHR module, jQuery ajax, Zepto ajax, or define your own transport mechanism for downloading zone files." - ); - } - if (!opts.async) { - return fleegix && fleegix.xhr - ? fleegix.xhr.doReq({ url: opts.url, async: false }) - : ajax_lib.ajax({ url: opts.url, async: false, dataType: "text" }) - .responseText; - } - return fleegix && fleegix.xhr - ? fleegix.xhr.send({ - url: opts.url, - method: "get", - handleSuccess: opts.success, - handleErr: opts.error - }) - : ajax_lib.ajax({ - url: opts.url, - dataType: "text", - method: "GET", - error: opts.error, - success: opts.success - }); - }; - - timezoneJS.ruleCache = {}; - - // Constructor, which is similar to that of the native Date object itself - timezoneJS.Date = function () { - if (this === timezoneJS) { - throw "timezoneJS.Date object must be constructed with 'new'"; - } - var args = Array.prototype.slice.apply(arguments), - dt = null, - tz = null, - arr = [], - valid = false; - //We support several different constructors, including all the ones from `Date` object - // with a timezone string at the end. - // - //- `[tz]`: Returns object with time in `tz` specified. - // - // - `utcMillis`, `[tz]`: Return object with UTC time = `utcMillis`, in `tz`. - // - // - `Date`, `[tz]`: Returns object with UTC time = `Date.getTime()`, in `tz`. - // - // - `year, month, [date,] [hours,] [minutes,] [seconds,] [millis,] [tz]: Same as `Date` object - // with tz. - // - // - `Array`: Can be any combo of the above. - // - //If 1st argument is an array, we can use it as a list of arguments itself - if (Object.prototype.toString.call(args[0]) === "[object Array]") { - args = args[0]; - } - // If the last string argument doesn't parse as a Date, treat it as tz - if (typeof args[args.length - 1] === "string") { - valid = Date.parse(args[args.length - 1].replace(/GMT[+-]\d+/, "")); - if (isNaN(valid) || valid === null) { - // Checking against null is required for compatability with Datejs - tz = args.pop(); - } - } - // Old code: still need it? - //if (typeof args[args.length - 1] === 'string' /*&& isNaN(Date.parse(args[args.length - 1].replace(/GMT\+\d+/, '')))*/) { // This was causing any timezone with GMT to stop working as in "Etc/GMT-7" - // tz = args.pop(); - //} - var is_dt_local = false; - switch (args.length) { - case 0: - dt = new Date(); - break; - case 1: - dt = new Date(args[0]); - // Date strings are local if they do not contain 'Z', 'T' or timezone offsets like '+0200' - // - more info below - if ( - typeof args[0] == "string" && - args[0].search(/[+-][0-9]{4}/) == -1 && - args[0].search(/Z/) == -1 && - args[0].search(/T/) == -1 - ) { - is_dt_local = true; - } - break; - case 2: - dt = new Date(args[0], args[1]); - is_dt_local = true; - break; - default: - for (var i = 0; i < 7; i++) { - arr[i] = args[i] || 0; - } - dt = new Date(arr[0], arr[1], arr[2], arr[3], arr[4], arr[5], arr[6]); - is_dt_local = true; - break; - } - - if (isNaN(dt.getTime())) { - // invalid date were passed - throw new Error("Invalid date"); - } - - this._useCache = false; - this._tzInfo = {}; - this._day = 0; - this.year = 0; - this.month = 0; - this.date = 0; - this.hours = 0; - this.minutes = 0; - this.seconds = 0; - this.milliseconds = 0; - this.timezone = tz || null; - // Tricky part: - // The date is either given as unambiguous UTC date or otherwise the date is assumed - // to be a date in timezone `tz` or a locale date if `tz` is not provided. Thus, to - // determine how to use `dt` we distinguish between the following cases: - // - UTC (is_dt_local = false) - // `timezoneJS.Date(millis, [tz])` - // `timezoneJS.Date(Date, [tz])` - // `timezoneJS.Date(dt_str_tz, [tz])` - // - local/timezone `tz` (is_dt_local = true) - // `timezoneJS.Date(year, mon, day, [hour], [min], [second], [tz])` - // `timezoneJS.Date(dt_str, [tz])` - // - // `dt_str_tz` is a date string containing timezone information, i.e. containing 'Z', 'T' or - // /[+-][0-9]{4}/ (e.g. '+0200'), while `dt_str` is a string which does not contain - // timezone information. See: http://dygraphs.com/date-formats.html - if (is_dt_local) { - this.setFromDateObjProxy(dt); - } else { - this.setFromTimeProxy(dt.getTime(), tz); - } - }; - - // Implements most of the native Date object - CIQ.extend( - timezoneJS.Date.prototype, - { - getDate: function () { - return this.date; - }, - getDay: function () { - return this._day; - }, - getFullYear: function () { - return this.year; - }, - getMonth: function () { - return this.month; - }, - getYear: function () { - return this.year - 1900; - }, - getHours: function () { - return this.hours; - }, - getMilliseconds: function () { - return this.milliseconds; - }, - getMinutes: function () { - return this.minutes; - }, - getSeconds: function () { - return this.seconds; - }, - getUTCDate: function () { - return this.getUTCDateProxy().getUTCDate(); - }, - getUTCDay: function () { - return this.getUTCDateProxy().getUTCDay(); - }, - getUTCFullYear: function () { - return this.getUTCDateProxy().getUTCFullYear(); - }, - getUTCHours: function () { - return this.getUTCDateProxy().getUTCHours(); - }, - getUTCMilliseconds: function () { - return this.getUTCDateProxy().getUTCMilliseconds(); - }, - getUTCMinutes: function () { - return this.getUTCDateProxy().getUTCMinutes(); - }, - getUTCMonth: function () { - return this.getUTCDateProxy().getUTCMonth(); - }, - getUTCSeconds: function () { - return this.getUTCDateProxy().getUTCSeconds(); - }, - // Time adjusted to user-specified timezone - getTime: function () { - return this._timeProxy + this.getTimezoneOffset() * 60 * 1000; - }, - getTimezone: function () { - return this.timezone; - }, - getTimezoneOffset: function () { - return this.getTimezoneInfo().tzOffset; - }, - getTimezoneAbbreviation: function () { - return this.getTimezoneInfo().tzAbbr; - }, - getTimezoneInfo: function () { - if (this._useCache) return this._tzInfo; - var res; - // If timezone is specified, get the correct timezone info based on the Date given - if (this.timezone) { - res = - this.timezone === "Etc/UTC" || this.timezone === "Etc/GMT" - ? { tzOffset: 0, tzAbbr: "UTC" } - : timezoneJS.timezone.getTzInfo(this._timeProxy, this.timezone); - } - // If no timezone was specified, use the local browser offset - else { - res = { tzOffset: this.getLocalOffset(), tzAbbr: null }; - } - this._tzInfo = res; - this._useCache = true; - return res; - }, - getUTCDateProxy: function () { - var dt = new Date(this._timeProxy); - dt.setUTCMinutes(dt.getUTCMinutes() + this.getTimezoneOffset()); - return dt; - }, - setDate: function (date) { - this.setAttribute("date", date); - return this.getTime(); - }, - setFullYear: function (year, month, date) { - if (date !== undefined) { - this.setAttribute("date", 1); - } - this.setAttribute("year", year); - if (month !== undefined) { - this.setAttribute("month", month); - } - if (date !== undefined) { - this.setAttribute("date", date); - } - return this.getTime(); - }, - setMonth: function (month, date) { - this.setAttribute("month", month); - if (date !== undefined) { - this.setAttribute("date", date); - } - return this.getTime(); - }, - setYear: function (year) { - year = Number(year); - if (0 <= year && year <= 99) { - year += 1900; - } - this.setUTCAttribute("year", year); - return this.getTime(); - }, - setHours: function (hours, minutes, seconds, milliseconds) { - this.setAttribute("hours", hours); - if (minutes !== undefined) { - this.setAttribute("minutes", minutes); - } - if (seconds !== undefined) { - this.setAttribute("seconds", seconds); - } - if (milliseconds !== undefined) { - this.setAttribute("milliseconds", milliseconds); - } - return this.getTime(); - }, - setMinutes: function (minutes, seconds, milliseconds) { - this.setAttribute("minutes", minutes); - if (seconds !== undefined) { - this.setAttribute("seconds", seconds); - } - if (milliseconds !== undefined) { - this.setAttribute("milliseconds", milliseconds); - } - return this.getTime(); - }, - setSeconds: function (seconds, milliseconds) { - this.setAttribute("seconds", seconds); - if (milliseconds !== undefined) { - this.setAttribute("milliseconds", milliseconds); - } - return this.getTime(); - }, - setMilliseconds: function (milliseconds) { - this.setAttribute("milliseconds", milliseconds); - return this.getTime(); - }, - setTime: function (n) { - if (isNaN(n)) { - throw new Error("Units must be a number."); - } - this.setFromTimeProxy(n, this.timezone); - return this.getTime(); - }, - setUTCFullYear: function (year, month, date) { - if (date !== undefined) { - this.setUTCAttribute("date", 1); - } - this.setUTCAttribute("year", year); - if (month !== undefined) { - this.setUTCAttribute("month", month); - } - if (date !== undefined) { - this.setUTCAttribute("date", date); - } - return this.getTime(); - }, - setUTCMonth: function (month, date) { - this.setUTCAttribute("month", month); - if (date !== undefined) { - this.setUTCAttribute("date", date); - } - return this.getTime(); - }, - setUTCDate: function (date) { - this.setUTCAttribute("date", date); - return this.getTime(); - }, - setUTCHours: function (hours, minutes, seconds, milliseconds) { - this.setUTCAttribute("hours", hours); - if (minutes !== undefined) { - this.setUTCAttribute("minutes", minutes); - } - if (seconds !== undefined) { - this.setUTCAttribute("seconds", seconds); - } - if (milliseconds !== undefined) { - this.setUTCAttribute("milliseconds", milliseconds); - } - return this.getTime(); - }, - setUTCMinutes: function (minutes, seconds, milliseconds) { - this.setUTCAttribute("minutes", minutes); - if (seconds !== undefined) { - this.setUTCAttribute("seconds", seconds); - } - if (milliseconds !== undefined) { - this.setUTCAttribute("milliseconds", milliseconds); - } - return this.getTime(); - }, - setUTCSeconds: function (seconds, milliseconds) { - this.setUTCAttribute("seconds", seconds); - if (milliseconds !== undefined) { - this.setUTCAttribute("milliseconds", milliseconds); - } - return this.getTime(); - }, - setUTCMilliseconds: function (milliseconds) { - this.setUTCAttribute("milliseconds", milliseconds); - return this.getTime(); - }, - setFromDateObjProxy: function (dt) { - this.year = dt.getFullYear(); - this.month = dt.getMonth(); - this.date = dt.getDate(); - this.hours = dt.getHours(); - this.minutes = dt.getMinutes(); - this.seconds = dt.getSeconds(); - this.milliseconds = dt.getMilliseconds(); - this._day = dt.getDay(); - this._dateProxy = dt; - this._timeProxy = Date.UTC( - this.year, - this.month, - this.date, - this.hours, - this.minutes, - this.seconds, - this.milliseconds - ); - this._useCache = false; - }, - setFromTimeProxy: function (utcMillis, tz) { - var dt = new Date(utcMillis); - var tzOffset = tz - ? timezoneJS.timezone.getTzInfo(utcMillis, tz, true).tzOffset - : dt.getTimezoneOffset(); - dt.setTime(utcMillis + (dt.getTimezoneOffset() - tzOffset) * 60000); - this.setFromDateObjProxy(dt); - }, - setAttribute: function (unit, n) { - if (isNaN(n)) { - throw new Error("Units must be a number."); - } - var dt = this._dateProxy; - var meth = - unit === "year" - ? "FullYear" - : unit.substr(0, 1).toUpperCase() + unit.substr(1); - dt["set" + meth](n); - this.setFromDateObjProxy(dt); - }, - setUTCAttribute: function (unit, n) { - if (isNaN(n)) { - throw new Error("Units must be a number."); - } - var meth = - unit === "year" - ? "FullYear" - : unit.substr(0, 1).toUpperCase() + unit.substr(1); - var dt = this.getUTCDateProxy(); - dt["setUTC" + meth](n); - dt.setUTCMinutes(dt.getUTCMinutes() - this.getTimezoneOffset()); - this.setFromTimeProxy( - dt.getTime() + this.getTimezoneOffset() * 60000, - this.timezone - ); - }, - setTimezone: function (tz) { - var previousOffset = this.getTimezoneInfo().tzOffset; - this.timezone = tz; - this._useCache = false; - // Set UTC minutes offsets by the delta of the two timezones - this.setUTCMinutes( - this.getUTCMinutes() - - this.getTimezoneInfo().tzOffset + - previousOffset - ); - }, - removeTimezone: function () { - this.timezone = null; - this._useCache = false; - }, - valueOf: function () { - return this.getTime(); - }, - clone: function () { - return this.timezone - ? new timezoneJS.Date(this.getTime(), this.timezone) - : new timezoneJS.Date(this.getTime()); - }, - toGMTString: function () { - return this.toString("EEE, dd MMM yyyy HH:mm:ss Z", "Etc/GMT"); - }, - toLocaleStringIntl: function () {}, - toLocaleDateString: function () {}, - toLocaleTimeString: function () {}, - toSource: function () {}, - toISOString: function () { - return this.toString("yyyy-MM-ddTHH:mm:ss.SSS", "Etc/UTC") + "Z"; - }, - toJSON: function () { - return this.toISOString(); - }, - toDateString: function () { - return this.toString("EEE MMM dd yyyy"); - }, - toTimeString: function () { - return this.toString("H:mm k"); - }, - // Allows different format following ISO8601 format: - toString: function (format, tz) { - // Default format is the same as toISOString - if (!format) format = "yyyy-MM-ddTHH:mm:ss.SSS"; - var result = format; - var tzInfo = tz - ? timezoneJS.timezone.getTzInfo(this.getTime(), tz) - : this.getTimezoneInfo(); - var _this = this; - // If timezone is specified, get a clone of the current Date object and modify it - if (tz) { - _this = this.clone(); - _this.setTimezone(tz); - } - var hours = _this.getHours(); - return ( - result - // fix the same characters in Month names - .replace(/a+/g, function () { - return "k"; - }) - // `y`: year - .replace(/y+/g, function (token) { - return _fixWidth(_this.getFullYear(), token.length); - }) - // `d`: date - .replace(/d+/g, function (token) { - return _fixWidth(_this.getDate(), token.length); - }) - // `m`: minute - .replace(/m+/g, function (token) { - return _fixWidth(_this.getMinutes(), token.length); - }) - // `s`: second - .replace(/s+/g, function (token) { - return _fixWidth(_this.getSeconds(), token.length); - }) - // `S`: millisecond - .replace(/S+/g, function (token) { - return _fixWidth(_this.getMilliseconds(), token.length); - }) - // 'h': 12 hour format - .replace(/h+/g, function (token) { - return _fixWidth( - hours % 12 === 0 ? 12 : hours % 12, - token.length - ); - }) - // `M`: month. Note: `MM` will be the numeric representation (e.g February is 02) but `MMM` will be text representation (e.g February is Feb) - .replace(/M+/g, function (token) { - var _month = _this.getMonth(), - _len = token.length; - if (_len > 3) { - return timezoneJS.Months[_month]; - } else if (_len > 2) { - return timezoneJS.Months[_month].substring(0, _len); - } - return _fixWidth(_month + 1, _len); - }) - // `k`: AM/PM - .replace(/k+/g, function () { - if (hours >= 12) { - if (hours > 12) { - hours -= 12; - } - return "PM"; - } - return "AM"; - }) - // `H`: hour - .replace(/H+/g, function (token) { - return _fixWidth(hours, token.length); - }) - // `E`: day - .replace(/E+/g, function (token) { - return DAYS[_this.getDay()].substring(0, token.length); - }) - // `Z`: timezone abbreviation - .replace(/Z+/gi, function () { - return tzInfo.tzAbbr; - }) - ); - }, - toUTCString: function () { - return this.toGMTString(); - }, - civilToJulianDayNumber: function (y, m, d) { - var a; - // Adjust for zero-based JS-style array - m++; - if (m > 12) { - a = parseInt(m / 12, 10); - m = m % 12; - y += a; - } - if (m <= 2) { - y -= 1; - m += 12; - } - a = Math.floor(y / 100); - var b = 2 - a + Math.floor(a / 4), - jDt = - Math.floor(365.25 * (y + 4716)) + - Math.floor(30.6001 * (m + 1)) + - d + - b - - 1524; - return jDt; - }, - getLocalOffset: function () { - return this._dateProxy.getTimezoneOffset(); - } - }, - true - ); - - timezoneJS.timezone = new (function () { - var _this = this, - regionMap = { - Etc: "etcetera", - EST: "northamerica", - MST: "northamerica", - HST: "northamerica", - EST5EDT: "northamerica", - CST6CDT: "northamerica", - MST7MDT: "northamerica", - PST8PDT: "northamerica", - America: ["northamerica", "southamerica"], - Pacific: "australasia", - Atlantic: "europe", - Africa: "africa", - Indian: "africa", - Antarctica: "antarctica", - Asia: "asia", - Australia: "australasia", - Europe: "europe", - WET: "europe", - CET: "europe", - MET: "europe", - EET: "europe" - }, - regionExceptions = { - "Pacific/Honolulu": "northamerica", - "Atlantic/Bermuda": "northamerica", - "Atlantic/Cape_Verde": "africa", - "Atlantic/St_Helena": "africa", - "Indian/Kerguelen": "antarctica", - "Indian/Chagos": "asia", - "Indian/Maldives": "asia", - "Indian/Christmas": "australasia", - "Indian/Cocos": "australasia", - "America/Danmarkshavn": "europe", - "America/Scoresbysund": "europe", - "America/Godthab": "europe", - "America/Thule": "europe", - "Asia/Istanbul": "europe", - "Asia/Yekaterinburg": "europe", - "Asia/Omsk": "europe", - "Asia/Novosibirsk": "europe", - "Asia/Krasnoyarsk": "europe", - "Asia/Irkutsk": "europe", - "Asia/Yakutsk": "europe", - "Asia/Vladivostok": "europe", - "Asia/Sakhalin": "europe", - "Asia/Magadan": "europe", - "Asia/Kamchatka": "europe", - "Asia/Anadyr": "europe", - "Africa/Ceuta": "europe", - GMT: "etcetera", - "Europe/Nicosia": "asia" - }; - function invalidTZError(t) { - throw new Error( - "Timezone '" + - t + - "' is either incorrect, or not loaded in the timezone registry." - ); - } - function builtInLoadZoneFile(fileName, opts) { - var url = _this.zoneFileBasePath + "/" + fileName; - return !opts || !opts.async - ? _this.parseZones(_this.transport({ url: url, async: false })) - : _this.transport({ - async: true, - url: url, - success: function (str) { - return ( - _this.parseZones(str) && - typeof opts.callback === "function" && - opts.callback() - ); - }, - error: function () { - throw new Error("Error retrieving '" + url + "' zoneinfo files"); - } - }); - } - function getRegionForTimezone(tz) { - var exc = regionExceptions[tz], - reg, - ret; - if (exc) return exc; - reg = tz.split("/")[0]; - ret = regionMap[reg]; - // If there's nothing listed in the main regions for this TZ, check the 'backward' links - if (ret) return ret; - var link = _this.zones[tz]; - if (typeof link === "string") { - return getRegionForTimezone(link); - } - // Backward-compat file hasn't loaded yet, try looking in there - if (!_this.loadedZones.backward) { - // This is for obvious legacy zones (e.g., Iceland) that don't even have a prefix like 'America/' that look like normal zones - _this.loadZoneFile("backward"); - return getRegionForTimezone(tz); - } - invalidTZError(tz); - } - //str has format hh:mm, can be negative - function parseTimeString(str) { - var pat = /(\d+)(?::0*(\d*))?(?::0*(\d*))?([wsugz])?$/; - var hms = str.match(pat); - hms[1] = parseInt(hms[1], 10); - hms[2] = hms[2] ? parseInt(hms[2], 10) : 0; - hms[3] = hms[3] ? parseInt(hms[3], 10) : 0; - return hms.slice(1, 5); - } - //z is something like `[ '-3:44:40', '-', 'LMT', '1911', 'May', '15', '' ]` or `[ '-5:00', '-', 'EST', '1974', 'Apr', '28', '2:00' ]` - function processZone(z) { - if (!z[3]) { - return; - } - var yea = parseInt(z[3], 10), - mon = 11, - dat = 31; - //If month is there - if (z[4]) { - mon = SHORT_MONTHS[z[4].substr(0, 3)]; - dat = parseInt(z[5], 10) || 1; - } - var t = z[6] ? parseTimeString(z[6]) : [0, 0, 0]; - return [yea, mon, dat, t[0], t[1], t[2]]; - } - function getZone(dt, tz) { - var utcMillis = typeof dt === "number" ? dt : new Date(+dt).getTime(); - var t = tz; - var zoneList = _this.zones[t]; - // Follow links to get to an actual zone - while (typeof zoneList === "string") { - t = zoneList; - zoneList = _this.zones[t]; - } - if (!zoneList) { - // Backward-compat file hasn't loaded yet, try looking in there - if (!_this.loadedZones.backward) { - //This is for backward entries like 'America/Fort_Wayne' that - // getRegionForTimezone *thinks* it has a region file and zone - // for (e.g., America => 'northamerica'), but in reality it's a - // legacy zone we need the backward file for. - _this.loadZoneFile("backward"); - return getZone(dt, tz); - } else if (t && t !== tz) { - //Load the linked zone found in the backward file - _this.lazyLoadZoneFiles(t); - return getZone(dt, t); - } - invalidTZError(t); - } - if (zoneList.length === 0) { - throw new Error("No Zone found for '" + tz + "' on " + dt); - } - //Do backwards lookup since most use cases deal with newer dates. - for (var i = zoneList.length - 1; i >= 0; i--) { - var z = zoneList[i]; - if (z[3] && utcMillis > z[3]) break; - } - return zoneList[i + 1]; - } - function getBasicOffset(time) { - var off = parseTimeString(time), - adj = time.charAt(0) === "-" ? -1 : 1; - off = adj * (((off[0] * 60 + off[1]) * 60 + off[2]) * 1000); - return off / 60 / 1000; - } - function getAdjustedOffset(off, min) { - return -Math.ceil(min - off); - } - - //if isUTC is true, date is given in UTC, otherwise it's given - // in local time (ie. date.getUTC*() returns local time components) - function getRule(dt, zone, isUTC, cacheKey) { - var date = typeof dt === "number" ? new Date(dt) : dt; - var ruleset = zone[1]; - var basicOffset = zone[0]; - - // If the zone has a DST rule like '1:00', create a rule and return it - // instead of looking it up in the parsed rules - var staticDstMatch = ruleset.match(/^([0-9]):([0-9][0-9])$/); - if (staticDstMatch) { - return [ - -1000000, - "max", - "-", - "Jan", - 1, - [0, 0, 0], - parseInt(staticDstMatch[1], 10) * 60 + - parseInt(staticDstMatch[2], 10), - "-" - ]; - } - - //Convert a date to UTC. Depending on the 'type' parameter, the date - // parameter may be: - // - // - `u`, `g`, `z`: already UTC (no adjustment). - // - // - `s`: standard time (adjust for time zone offset but not for DST) - // - // - `w`: wall clock time (adjust for both time zone and DST offset). - // - // DST adjustment is done using the rule given as third argument. - var convertDateToUTC = function (date, type, rule) { - var offset = 0; - - if (type === "u" || type === "g" || type === "z") { - // UTC - offset = 0; - } else if (type === "s") { - // Standard Time - offset = basicOffset; - } else if (type === "w" || !type) { - // Wall Clock Time - offset = getAdjustedOffset(basicOffset, rule[6]); - } else { - throw new Error("unknown type " + type); - } - offset *= 60 * 1000; // to millis - - return new Date(date.getTime() + offset); - }; - - //Step 1: Find applicable rules for this year. - // - //Step 2: Sort the rules by effective date. - // - //Step 3: Check requested date to see if a rule has yet taken effect this year. If not, - // - //Step 4: Get the rules for the previous year. If there isn't an applicable rule for last year, then - // there probably is no current time offset since they seem to explicitly turn off the offset - // when someone stops observing DST. - // - // FIXME if this is not the case and we'll walk all the way back (ugh). - // - //Step 5: Sort the rules by effective date. - //Step 6: Apply the most recent rule before the current time. - var convertRuleToExactDateAndTime = function (yearAndRule, prevRule) { - var year = yearAndRule[0], - rule = yearAndRule[1]; - // Assume that the rule applies to the year of the given date. - - var hms = rule[5]; - var effectiveDate; - - if (!EXACT_DATE_TIME[year]) EXACT_DATE_TIME[year] = {}; - - // Result for given parameters is already stored - if (EXACT_DATE_TIME[year][rule]) - effectiveDate = EXACT_DATE_TIME[year][rule]; - else { - //If we have a specific date, use that! - if (!isNaN(rule[4])) { - effectiveDate = new Date( - Date.UTC( - year, - SHORT_MONTHS[rule[3]], - rule[4], - hms[0], - hms[1], - hms[2], - 0 - ) - ); - } - //Let's hunt for the date. - else { - var targetDay, operator; - //Example: `lastThu` - if (rule[4].substr(0, 4) === "last") { - // Start at the last day of the month and work backward. - effectiveDate = new Date( - Date.UTC( - year, - SHORT_MONTHS[rule[3]] + 1, - 1, - hms[0] - 24, - hms[1], - hms[2], - 0 - ) - ); - targetDay = SHORT_DAYS[rule[4].substr(4, 3)]; - operator = "<="; - } - //Example: `Sun>=15` - else { - //Start at the specified date. - effectiveDate = new Date( - Date.UTC( - year, - SHORT_MONTHS[rule[3]], - rule[4].substr(5), - hms[0], - hms[1], - hms[2], - 0 - ) - ); - targetDay = SHORT_DAYS[rule[4].substr(0, 3)]; - operator = rule[4].substr(3, 2); - } - var ourDay = effectiveDate.getUTCDay(); - //Go forwards. - if (operator === ">=") { - effectiveDate.setUTCDate( - effectiveDate.getUTCDate() + - (targetDay - ourDay + (targetDay < ourDay ? 7 : 0)) - ); - } - //Go backwards. Looking for the last of a certain day, or operator is '<=' (less likely). - else { - effectiveDate.setUTCDate( - effectiveDate.getUTCDate() + - (targetDay - ourDay - (targetDay > ourDay ? 7 : 0)) - ); - } - } - EXACT_DATE_TIME[year][rule] = effectiveDate; - } - - //If previous rule is given, correct for the fact that the starting time of the current - // rule may be specified in local time. - if (prevRule) { - effectiveDate = convertDateToUTC(effectiveDate, hms[3], prevRule); - } - return effectiveDate; - }; - - var findApplicableRules = function (year, ruleset) { - var applicableRules = []; - for (var i = 0; ruleset && i < ruleset.length; i++) { - //Exclude future rules. - if ( - ruleset[i][0] <= year && - // Date is in a set range. - (ruleset[i][1] >= year || - // Date is in an 'only' year. - (ruleset[i][0] === year && ruleset[i][1] === "only") || - //We're in a range from the start year to infinity. - ruleset[i][1] === "max") - ) { - //It's completely okay to have any number of matches here. - // Normally we should only see two, but that doesn't preclude other numbers of matches. - // These matches are applicable to this year. - applicableRules.push([year, ruleset[i]]); - } - } - return applicableRules; - }; - - var compareDates = function (a, b, prev) { - var year, rule; - if (!(a instanceof Date)) { - year = a[0]; - rule = a[1]; - a = - !prev && EXACT_DATE_TIME[year] && EXACT_DATE_TIME[year][rule] - ? EXACT_DATE_TIME[year][rule] - : convertRuleToExactDateAndTime(a, prev); - } else if (prev) { - a = convertDateToUTC(a, isUTC ? "u" : "w", prev); - } - if (!(b instanceof Date)) { - year = b[0]; - rule = b[1]; - b = - !prev && EXACT_DATE_TIME[year] && EXACT_DATE_TIME[year][rule] - ? EXACT_DATE_TIME[year][rule] - : convertRuleToExactDateAndTime(b, prev); - } else if (prev) { - b = convertDateToUTC(b, isUTC ? "u" : "w", prev); - } - a = Number(a); - b = Number(b); - return a - b; - }; - - var year = date.getUTCFullYear(); - var applicableRules; - - var cache = timezoneJS.ruleCache[cacheKey]; - if (!cache) cache = timezoneJS.ruleCache[cacheKey] = {}; - applicableRules = cache[year]; - if (!applicableRules) { - applicableRules = findApplicableRules(year - 1, _this.rules[ruleset]); - applicableRules = applicableRules.concat( - findApplicableRules(year, _this.rules[ruleset]) - ); - applicableRules.sort(compareDates); // Probably already sorted? - cache[year] = applicableRules; - } - - if (!applicableRules || !applicableRules.length) return null; // No applicable rules - - var prev; - for (var i = applicableRules.length - 1; i >= 0; i--) { - if (i > 0) prev = applicableRules[i - 1][1]; - else prev = null; - var rule = applicableRules[i]; - if (!rule[2]) { - rule[2] = convertRuleToExactDateAndTime(rule, prev); // cache the exactDateAndTime, this saves a lot of cycles! - } - if (compareDates(date, rule, prev) >= 0) return rule[1]; - } - return null; - - /* - applicableRules = findApplicableRules(year, _this.rules[ruleset]); - applicableRules.push(date); - //While sorting, the time zone in which the rule starting time is specified - // is ignored. This is ok as long as the timespan between two DST changes is - // larger than the DST offset, which is probably always true. - // As the given date may indeed be close to a DST change, it may get sorted - // to a wrong position (off by one), which is corrected below. - applicableRules.sort(compareDates); - - //If there are not enough past DST rules... - if (_arrIndexOf.call(applicableRules, date) < 2) { - applicableRules = applicableRules.concat(findApplicableRules(year-1, _this.rules[ruleset])); - applicableRules.sort(compareDates); - } - var pinpoint = _arrIndexOf.call(applicableRules, date); - if (pinpoint > 1 && compareDates(date, applicableRules[pinpoint-1], applicableRules[pinpoint-2][1]) < 0) { - //The previous rule does not really apply, take the one before that. - return applicableRules[pinpoint - 2][1]; - } else if (pinpoint > 0 && pinpoint < applicableRules.length - 1 && compareDates(date, applicableRules[pinpoint+1], applicableRules[pinpoint-1][1]) > 0) { - - //The next rule does already apply, take that one. - return applicableRules[pinpoint + 1][1]; - } else if (pinpoint === 0) { - //No applicable rule found in this and in previous year. - return null; - } - return applicableRules[pinpoint - 1][1]; - */ - } - function getAbbreviation(zone, rule) { - var base = zone[2]; - if (base.indexOf("%s") > -1) { - var repl; - if (rule) { - repl = rule[7] === "-" ? "" : rule[7]; - } - //FIXME: Right now just falling back to Standard -- - // apparently ought to use the last valid rule, - // although in practice that always ought to be Standard - else { - repl = "S"; - } - return base.replace("%s", repl); - } else if (base.indexOf("/") > -1) { - //Chose one of two alternative strings. - return base.split("/", 2)[rule ? (rule[6] ? 1 : 0) : 0]; - } - return base; - } - - this.zoneFileBasePath = null; - this.zoneFiles = [ - "africa", - "antarctica", - "asia", - "australasia", - "backward", - "etcetera", - "europe", - "northamerica", - "pacificnew", - "southamerica" - ]; - this.loadingSchemes = { - PRELOAD_ALL: "preloadAll", - LAZY_LOAD: "lazyLoad", - MANUAL_LOAD: "manualLoad" - }; - this.getRegionForTimezone = getRegionForTimezone; - this.loadingScheme = this.loadingSchemes.LAZY_LOAD; - this.loadedZones = {}; - this.zones = {}; - this.rules = {}; - - this.init = function (o) { - var opts = { async: true }, - def = - this.loadingScheme === this.loadingSchemes.PRELOAD_ALL - ? this.zoneFiles - : this.defaultZoneFile || "northamerica"; - //Override default with any passed-in opts - for (var p in o) { - opts[p] = o[p]; - } - return this.loadZoneFiles(def, opts); - }; - - //Get a single zone file, or all files in an array - this.loadZoneFiles = function (fileNames, opts) { - var callbackFn, - done = 0; - if (typeof fileNames === "string") { - return this.loadZoneFile(fileNames, opts); - } - //Wraps callback function in another one that makes - // sure all files have been loaded. - opts = opts || {}; - callbackFn = opts.callback; - opts.callback = function () { - done++; - done === fileNames.length && - typeof callbackFn === "function" && - callbackFn(); - }; - for (var i = 0; i < fileNames.length; i++) { - this.loadZoneFile(fileNames[i], opts); - } - }; - //Get the zone files via XHR -- if the sync flag - // is set to true, it's being called by the lazy-loading - // mechanism, so the result needs to be returned inline. - this.loadZoneFile = function (fileName, opts) { - if (typeof this.zoneFileBasePath === "undefined") { - throw new Error( - "Please define a base path to your zone file directory -- timezoneJS.timezone.zoneFileBasePath." - ); - } - //Ignore already loaded zones. - if (this.loadedZones[fileName]) { - return; - } - this.loadedZones[fileName] = true; - return builtInLoadZoneFile(fileName, opts); - }; - this.loadZoneJSONData = function (url, sync) { - var processData = function (data) { - data = JSON.parse(data); - for (var z in data.zones) { - _this.zones[z] = data.zones[z]; - } - for (var r in data.rules) { - _this.rules[r] = data.rules[r]; - } - }; - return sync - ? processData(_this.transport({ url: url, async: false })) - : _this.transport({ url: url, success: processData }); - }; - this.loadZoneDataFromObject = function (data) { - if (!data) { - return; - } - for (var z in data.zones) { - _this.zones[z] = data.zones[z]; - } - for (var r in data.rules) { - _this.rules[r] = data.rules[r]; - } - }; - this.getAllZones = function () { - var arr = []; - for (var z in this.zones) { - arr.push(z); - } - return arr.sort(); - }; - this.parseZones = function (str) { - if (!str) { - return false; - } - - var lines = str.split("\n"), - arr = [], - chunk = "", - l, - zone = null, - rule = null; - for (var i = 0; i < lines.length; i++) { - l = lines[i]; - if (l.match(/^\s/)) { - l = "Zone " + zone + l; - } - l = l.split("#")[0]; - if (l.length > 3) { - arr = l.split(/\s+/); - chunk = arr.shift(); - //Ignore Leap. - switch (chunk) { - case "Zone": - zone = arr.shift(); - if (!_this.zones[zone]) { - _this.zones[zone] = []; - } - if (arr.length < 3) break; - //Process zone right here and replace 3rd element with the processed array. - arr.splice(3, arr.length, processZone(arr)); - if (arr[3]) arr[3] = Date.UTC.apply(null, arr[3]); - arr[0] = -getBasicOffset(arr[0]); - _this.zones[zone].push(arr); - break; - case "Rule": - rule = arr.shift(); - if (!_this.rules[rule]) { - _this.rules[rule] = []; - } - //Parse int FROM year and TO year - arr[0] = parseInt(arr[0], 10); - arr[1] = parseInt(arr[1], 10) || arr[1]; - //Parse time string AT - arr[5] = parseTimeString(arr[5]); - //Parse offset SAVE - arr[6] = getBasicOffset(arr[6]); - _this.rules[rule].push(arr); - break; - case "Link": - //No zones for these should already exist. - if (_this.zones[arr[1]]) { - throw new Error( - "Error with Link " + - arr[1] + - ". Cannot create link of a preexisted zone." - ); - } - //Create the link. - //Links are saved as strings that are the keys - //of their referenced values. - //Ex: "US/Central": "America/Chicago" - if (isNaN(arr[0])) { - _this.zones[arr[1]] = arr[0]; - } else { - _this.zones[arr[1]] = parseInt(arr[0], 10); - } - break; - } - } - } - return true; - }; - //Expose transport mechanism and allow overwrite. - this.transport = _transport; - this.getTzInfo = function (dt, tz, isUTC) { - this.lazyLoadZoneFiles(tz); - var z = getZone(dt, tz); - var off = +z[0]; - //See if the offset needs adjustment. - var rule = getRule(dt, z, isUTC, tz); - if (rule) { - off = getAdjustedOffset(off, rule[6]); - } - var abbr = getAbbreviation(z, rule); - return { tzOffset: off, tzAbbr: abbr }; - }; - //Lazy-load any zones not yet loaded. - this.lazyLoadZoneFiles = function (tz) { - if (this.loadingScheme === this.loadingSchemes.LAZY_LOAD) { - //Get the correct region for the zone. - var zoneFile = getRegionForTimezone(tz); - if (!zoneFile) { - throw new Error("Not a valid timezone ID."); - } - //Get the file and parse it -- use synchronous XHR. - this.loadZoneFiles(zoneFile); - } - }; - })(); -}.call(typeof window !== "undefined" ? window : this)); - -// Load all the necessary timezones and their rules -timezoneJS.timezone.loadingScheme = - timezoneJS.timezone.loadingSchemes.MANUAL_LOAD; -timezoneJS.timezone.loadZoneDataFromObject({ - zones: { - "Atlantic/Cape_Verde": [[60, "-", "-01", null]], - "Africa/Cairo": [[-120, "Egypt", "EE%sT", null]], - "Africa/Nairobi": [[-180, "-", "EAT", null]], - "Africa/Casablanca": [ - [0, "Morocco", "+00/+01", 1540695600000], - [-60, "Morocco", "+01/+00", null] - ], - "Africa/Windhoek": [[-120, "Namibia", "%s", null]], - "Africa/Johannesburg": [[-120, "SA", "SAST", null]], - "Africa/Tunis": [[-60, "Tunisia", "CE%sT", null]], - "Antarctica/Troll": [[0, "Troll", "%s", null]], - "Asia/Kabul": [[-270, "-", "+0430", null]], - "Asia/Baku": [[-240, "Azer", "+04/+05", null]], - "Asia/Dhaka": [[-360, "Dhaka", "+06/+07", null]], - "Asia/Yangon": [[-390, "-", "+0630", null]], - "Asia/Shanghai": [[-480, "PRC", "C%sT", null]], - "Asia/Hong_Kong": [[-480, "HK", "HK%sT", null]], - "Asia/Taipei": [[-480, "Taiwan", "C%sT", null]], - "Asia/Nicosia": [[-120, "EUAsia", "EE%sT", null]], - "Asia/Kolkata": [[-330, "-", "IST", null]], - "Asia/Tehran": [[-210, "Iran", "+0330/+0430", null]], - "Asia/Jerusalem": [[-120, "Zion", "I%sT", null]], - "Asia/Tokyo": [[-540, "Japan", "J%sT", null]], - "Asia/Amman": [[-120, "Jordan", "EE%sT", null]], - "Asia/Almaty": [[-360, "-", "ALMT", null]], - "Asia/Seoul": [[-540, "ROK", "K%sT", null]], - "Asia/Pyongyang": [ - [-510, "-", "KST", 1525476600000], - [-540, "-", "KST", null] - ], - "Asia/Beirut": [[-120, "Lebanon", "EE%sT", null]], - "Asia/Kuala_Lumpur": [[-480, "-", "+08", null]], - "Asia/Hovd": [[-420, "Mongol", "+07/+08", null]], - "Asia/Ulaanbaatar": [[-480, "Mongol", "+08/+09", null]], - "Asia/Kathmandu": [[-345, "-", "+0545", null]], - "Asia/Karachi": [[-300, "Pakistan", "PK%sT", null]], - "Asia/Hebron": [[-120, "Palestine", "EE%sT", null]], - "Asia/Riyadh": [[-180, "-", "+03", null]], - "Asia/Damascus": [[-120, "Syria", "EE%sT", null]], - "Asia/Bangkok": [[-420, "-", "+07", null]], - "Asia/Dubai": [[-240, "-", "+04", null]], - "Australia/Darwin": [[-570, "Aus", "AC%sT", null]], - "Australia/Perth": [[-480, "AW", "AW%sT", null]], - "Australia/Eucla": [[-525, "AW", "+0845/+0945", null]], - "Australia/Brisbane": [[-600, "AQ", "AE%sT", null]], - "Australia/Adelaide": [[-570, "AS", "AC%sT", null]], - "Australia/Hobart": [[-600, "AT", "AE%sT", null]], - "Australia/Melbourne": [[-600, "AV", "AE%sT", null]], - "Australia/Sydney": [[-600, "AN", "AE%sT", null]], - "Australia/Lord_Howe": [[-630, "LH", "+1030/+11", null]], - "Pacific/Fiji": [[-720, "Fiji", "+12/+13", null]], - "Pacific/Guam": [[-600, "-", "ChST", null]], - "Pacific/Kiritimati": [[-840, "-", "+14", null]], - "Pacific/Noumea": [[-660, "NC", "+11/+12", null]], - "Pacific/Auckland": [[-720, "NZ", "NZ%sT", null]], - "Pacific/Chatham": [[-765, "Chatham", "+1245/+1345", null]], - "Pacific/Pago_Pago": [[660, "-", "SST", null]], - "Pacific/Apia": [[-780, "WS", "+13/+14", null]], - "Pacific/Tongatapu": [[-780, "Tonga", "+13/+14", null]], - "Etc/UTC": [[0, "-", "UTC", null]], - UTC: "Etc/UTC", - "Europe/London": [[0, "EU", "GMT/BST", null]], - "Europe/Dublin": [[0, "Eire", "IST/GMT", null]], - WET: [[0, "EU", "WE%sT", null]], - CET: [[-60, "C-Eur", "CE%sT", null]], - MET: [[-60, "C-Eur", "ME%sT", null]], - EET: [[-120, "EU", "EE%sT", null]], - "Europe/Brussels": [[-60, "EU", "CE%sT", null]], - "America/Thule": [[240, "Thule", "A%sT", null]], - "Europe/Helsinki": [[-120, "EU", "EE%sT", null]], - "Europe/Paris": [[-60, "EU", "CE%sT", null]], - "Europe/Berlin": [[-60, "EU", "CE%sT", null]], - "Europe/Amsterdam": [[-60, "EU", "CE%sT", null]], - "Atlantic/Azores": [[60, "EU", "-01/+00", null]], - "Europe/Bucharest": [[-120, "EU", "EE%sT", null]], - "Europe/Kaliningrad": [[-120, "-", "EET", null]], - "Europe/Moscow": [[-180, "-", "MSK", null]], - "Europe/Volgograd": [ - [-180, "-", "+03", 1540692000000], - [-240, "-", "+04", 1609034400000], - [-180, "-", "+03", null] - ], - "Europe/Samara": [[-240, "-", "+04", null]], - "Asia/Yekaterinburg": [[-300, "-", "+05", null]], - "Asia/Omsk": [[-360, "-", "+06", null]], - "Asia/Novosibirsk": [[-420, "-", "+07", null]], - "Asia/Novokuznetsk": [[-420, "-", "+07", null]], - "Asia/Krasnoyarsk": [[-420, "-", "+07", null]], - "Asia/Irkutsk": [[-480, "-", "+08", null]], - "Asia/Yakutsk": [[-540, "-", "+09", null]], - "Asia/Vladivostok": [[-600, "-", "+10", null]], - "Asia/Magadan": [[-660, "-", "+11", null]], - "Asia/Srednekolymsk": [[-660, "-", "+11", null]], - "Asia/Kamchatka": [[-720, "-", "+12", null]], - "Europe/Belgrade": [[-60, "EU", "CE%sT", null]], - "Europe/Sarajevo": "Europe/Belgrade", - "Europe/Istanbul": [[-180, "-", "+03", null]], - "America/New_York": [[300, "US", "E%sT", null]], - "America/Chicago": [[360, "US", "C%sT", null]], - "America/Denver": [[420, "US", "M%sT", null]], - "America/Los_Angeles": [[480, "US", "P%sT", null]], - "America/Juneau": [[540, "US", "AK%sT", null]], - "Pacific/Honolulu": [[600, "-", "HST", null]], - "America/Phoenix": [[420, "-", "MST", null]], - "America/St_Johns": [[210, "Canada", "N%sT", null]], - "America/Halifax": [[240, "Canada", "A%sT", null]], - "America/Regina": [[360, "-", "CST", null]], - "America/Mexico_City": [[360, "Mexico", "C%sT", null]], - "America/Chihuahua": [[420, "Mexico", "M%sT", null]], - "America/Costa_Rica": [[360, "CR", "C%sT", null]], - "America/Havana": [[300, "Cuba", "C%sT", null]], - "America/Port-au-Prince": [[300, "Haiti", "E%sT", null]], - "America/Panama": [[300, "-", "EST", null]], - "America/Puerto_Rico": [[240, "-", "AST", null]], - "America/Argentina/Buenos_Aires": [[180, "Arg", "-03/-02", null]], - "America/Sao_Paulo": [[180, "Brazil", "-03/-02", null]], - "America/Santiago": [[240, "Chile", "-04/-03", null]], - "America/Punta_Arenas": [ - [240, "Chile", "-04/-03", 1480809600000], - [180, "-", "-03", null] - ], - "America/Bogota": [[300, "CO", "-05/-04", null]], - "America/Asuncion": [[240, "Para", "-04/-03", null]], - "Atlantic/South_Georgia": [[120, "-", "-02", null]], - "America/Montevideo": [[180, "Uruguay", "-03/-02", null]], - "America/Caracas": [[240, "-", "-04", null]], - // backwards compatibility - "Europe/Athens": "Europe/Bucharest", - "Europe/Simferopol": "Europe/Moscow", - "Asia/Rangoon": "Asia/Yangon", - "Atlantic/Reykjavik": "UTC", - "Asia/Kuwait": "Asia/Riyadh", - "Asia/Muscat": "Asia/Riyadh", - "Asia/Istanbul": "Europe/Istanbul" - }, - rules: { - Egypt: [], - Morocco: [ - [2013, 2018, "-", "Oct", "lastSun", [3, 0, 0, null], 0, "-"], - [2014, 2018, "-", "Mar", "lastSun", [2, 0, 0, null], 60, "-"], - [2017, "only", "-", "May", "21", [3, 0, 0, null], 0, "-"], - [2017, "only", "-", "Jul", "2", [2, 0, 0, null], 60, "-"], - [2018, "only", "-", "May", "13", [3, 0, 0, null], 0, "-"], - [2018, "only", "-", "Jun", "17", [2, 0, 0, null], 60, "-"], - [2019, "only", "-", "May", "5", [3, 0, 0, null], -60, "-"], - [2019, "only", "-", "Jun", "9", [2, 0, 0, null], 0, "-"], - [2020, "only", "-", "Apr", "19", [3, 0, 0, null], -60, "-"], - [2020, "only", "-", "May", "31", [2, 0, 0, null], 0, "-"], - [2021, "only", "-", "Apr", "11", [3, 0, 0, null], -60, "-"], - [2021, "only", "-", "May", "16", [2, 0, 0, null], 0, "-"], - [2022, "only", "-", "Mar", "27", [3, 0, 0, null], -60, "-"], - [2022, "only", "-", "May", "8", [2, 0, 0, null], 0, "-"], - [2023, "only", "-", "Mar", "19", [3, 0, 0, null], -60, "-"], - [2023, "only", "-", "Apr", "30", [2, 0, 0, null], 0, "-"], - [2024, "only", "-", "Mar", "10", [3, 0, 0, null], -60, "-"], - [2024, "only", "-", "Apr", "14", [2, 0, 0, null], 0, "-"], - [2025, "only", "-", "Feb", "23", [3, 0, 0, null], -60, "-"], - [2025, "only", "-", "Apr", "6", [2, 0, 0, null], 0, "-"] - ], - Namibia: [ - [1994, 2017, "-", "Sep", "Sun>=1", [2, 0, 0, null], 0, "CAT"], - [1995, 2017, "-", "Apr", "Sun>=1", [2, 0, 0, null], -60, "WAT"] - ], - SA: [], - Tunisia: [], - Troll: [ - [2005, "max", "-", "Mar", "lastSun", [1, 0, 0, "u"], 120, "+02"], - [2004, "max", "-", "Oct", "lastSun", [1, 0, 0, "u"], 0, "+00"] - ], - EUAsia: [ - [1981, "max", "-", "Mar", "lastSun", [1, 0, 0, "u"], 60, "S"], - [1996, "max", "-", "Oct", "lastSun", [1, 0, 0, "u"], 0, "-"] - ], - Azer: [], - Dhaka: [], - PRC: [], - HK: [], - Taiwan: [], - Iran: [ - [2017, 2019, "-", "Mar", "21", [24, 0, 0, null], 60, "-"], - [2017, 2019, "-", "Sep", "21", [24, 0, 0, null], 0, "-"], - [2020, "only", "-", "Mar", "20", [24, 0, 0, null], 60, "-"], - [2020, "only", "-", "Sep", "20", [24, 0, 0, null], 0, "-"], - [2021, 2023, "-", "Mar", "21", [24, 0, 0, null], 60, "-"], - [2021, 2023, "-", "Sep", "21", [24, 0, 0, null], 0, "-"], - [2024, "only", "-", "Mar", "20", [24, 0, 0, null], 60, "-"], - [2024, "only", "-", "Sep", "20", [24, 0, 0, null], 0, "-"], - [2025, 2027, "-", "Mar", "21", [24, 0, 0, null], 60, "-"], - [2025, 2027, "-", "Sep", "21", [24, 0, 0, null], 0, "-"] - ], - Zion: [ - [2013, "max", "-", "Mar", "Fri>=23", [2, 0, 0, null], 60, "D"], - [2013, "max", "-", "Oct", "lastSun", [2, 0, 0, null], 0, "S"] - ], - Japan: [], - Jordan: [ - [2014, "max", "-", "Mar", "lastThu", [24, 0, 0, null], 60, "S"], - [2014, "max", "-", "Oct", "lastFri", [0, 0, 0, "s"], 0, "-"] - ], - ROK: [], - Lebanon: [ - [1993, "max", "-", "Mar", "lastSun", [0, 0, 0, null], 60, "S"], - [1999, "max", "-", "Oct", "lastSun", [0, 0, 0, null], 0, "-"] - ], - Mongol: [], - Pakistan: [], - Palestine: [ - [2016, 2018, "-", "Mar", "Sat>=24", [1, 0, 0, null], 60, "S"], - [2016, 2018, "-", "Oct", "Sat>=24", [1, 0, 0, null], 0, "-"], - [2019, "only", "-", "Mar", "29", [0, 0, 0, null], 60, "S"], - [2019, "only", "-", "Oct", "Sat>=24", [0, 0, 0, null], 60, "-"], - [2020, "max", "-", "Mar", "Sat>=24", [0, 0, 0, null], 60, "S"], - [2020, "max", "-", "Oct", "Sat>=24", [1, 0, 0, null], 60, "-"] - ], - Syria: [ - [2012, "max", "-", "Mar", "lastFri", [0, 0, 0, null], 60, "S"], - [2009, "max", "-", "Oct", "lastFri", [0, 0, 0, null], 0, "-"] - ], - Aus: [], - AW: [], - AQ: [], - AS: [ - [2008, "max", "-", "Apr", "Sun>=1", [2, 0, 0, "s"], 0, "S"], - [2008, "max", "-", "Oct", "Sun>=1", [2, 0, 0, "s"], 60, "D"] - ], - AT: [ - [2001, "max", "-", "Oct", "Sun>=1", [2, 0, 0, "s"], 60, "D"], - [2008, "max", "-", "Apr", "Sun>=1", [2, 0, 0, "s"], 0, "S"] - ], - AV: [ - [2008, "max", "-", "Apr", "Sun>=1", [2, 0, 0, "s"], 0, "S"], - [2008, "max", "-", "Oct", "Sun>=1", [2, 0, 0, "s"], 60, "D"] - ], - AN: [ - [2008, "max", "-", "Apr", "Sun>=1", [2, 0, 0, "s"], 0, "S"], - [2008, "max", "-", "Oct", "Sun>=1", [2, 0, 0, "s"], 60, "D"] - ], - LH: [ - [2008, "max", "-", "Apr", "Sun>=1", [2, 0, 0, null], 0, "-"], - [2008, "max", "-", "Oct", "Sun>=1", [2, 0, 0, null], 30, "-"] - ], - Fiji: [ - [2014, 2018, "-", "Nov", "Sun>=1", [2, 0, 0, null], 60, "-"], - [2015, "max", "-", "Jan", "Sun>=12", [3, 0, 0, null], 0, "-"], - [2019, "only", "-", "Nov", "Sun>=8", [2, 0, 0, null], 60, "-"], - [2020, "only", "-", "Dec", "20", [2, 0, 0, null], 60, "-"], - [2021, "max", "-", "Nov", "Sun>=8", [2, 0, 0, null], 60, "-"] - ], - NC: [], - NZ: [ - [2007, "max", "-", "Sep", "lastSun", [2, 0, 0, "s"], 60, "D"], - [2008, "max", "-", "Apr", "Sun>=1", [2, 0, 0, "s"], 0, "S"] - ], - Chatham: [ - [2007, "max", "-", "Sep", "lastSun", [2, 45, 0, "s"], 60, "-"], - [2008, "max", "-", "Apr", "Sun>=1", [2, 45, 0, "s"], 0, "-"] - ], - WS: [ - [2012, "max", "-", "Apr", "Sun>=1", [4, 0, 0, null], 0, "-"], - [2012, "max", "-", "Sep", "lastSun", [3, 0, 0, null], 60, "-"] - ], - Tonga: [ - [2016, "only", "-", "Nov", "Sun>=1", [2, 0, 0, null], 60, "-"], - [2017, "only", "-", "Jan", "Sun>=15", [3, 0, 0, null], 0, "-"] - ], - Eire: [ - [1981, "max", "-", "Mar", "lastSun", [1, 0, 0, "u"], 0, "-"], - [1996, "max", "-", "Oct", "lastSun", [1, 0, 0, "u"], -60, "-"] - ], - EU: [ - [1981, "max", "-", "Mar", "lastSun", [1, 0, 0, "u"], 60, "S"], - [1996, "max", "-", "Oct", "lastSun", [1, 0, 0, "u"], 0, "-"] - ], - "C-Eur": [ - [1981, "max", "-", "Mar", "lastSun", [2, 0, 0, "s"], 60, "S"], - [1996, "max", "-", "Oct", "lastSun", [2, 0, 0, "s"], 0, "-"] - ], - Thule: [ - [2007, "max", "-", "Mar", "Sun>=8", [2, 0, 0, null], 60, "D"], - [2007, "max", "-", "Nov", "Sun>=1", [2, 0, 0, null], 0, "S"] - ], - US: [ - [2007, "max", "-", "Mar", "Sun>=8", [2, 0, 0, null], 60, "D"], - [2007, "max", "-", "Nov", "Sun>=1", [2, 0, 0, null], 0, "S"] - ], - Canada: [ - [2007, "max", "-", "Mar", "Sun>=8", [2, 0, 0, null], 60, "D"], - [2007, "max", "-", "Nov", "Sun>=1", [2, 0, 0, null], 0, "S"] - ], - Mexico: [ - [2002, "max", "-", "Apr", "Sun>=1", [2, 0, 0, null], 60, "D"], - [2002, "max", "-", "Oct", "lastSun", [2, 0, 0, null], 0, "S"] - ], - CR: [], - Cuba: [ - [2012, "max", "-", "Nov", "Sun>=1", [0, 0, 0, "s"], 0, "S"], - [2013, "max", "-", "Mar", "Sun>=8", [0, 0, 0, "s"], 60, "D"] - ], - Haiti: [ - [2017, "max", "-", "Mar", "Sun>=8", [2, 0, 0, null], 60, "D"], - [2017, "max", "-", "Nov", "Sun>=1", [2, 0, 0, null], 0, "S"] - ], - Arg: [], - Brazil: [ - [2008, 2017, "-", "Oct", "Sun>=15", [0, 0, 0, null], 60, "-"], - [2016, 2019, "-", "Feb", "Sun>=15", [0, 0, 0, null], 0, "-"], - [2018, "only", "-", "Nov", "Sun>=1", [0, 0, 0, null], 60, "-"] - ], - Chile: [ - [2016, 2018, "-", "May", "Sun>=9", [3, 0, 0, "u"], 0, "-"], - [2016, 2018, "-", "Aug", "Sun>=9", [4, 0, 0, "u"], 60, "-"], - [2019, "max", "-", "Apr", "Sun>=2", [3, 0, 0, "u"], 0, "-"], - [2019, "max", "-", "Sep", "Sun>=2", [4, 0, 0, "u"], 60, "-"] - ], - CO: [], - Para: [ - [2010, "max", "-", "Oct", "Sun>=1", [0, 0, 0, null], 60, "-"], - [2013, "max", "-", "Mar", "Sun>=22", [0, 0, 0, null], 0, "-"] - ], - Uruguay: [] - } -}); - -}; - - -let __js_standard_visualization_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -/** - * Creates a DOM object capable of receiving a data stream. The object changes as a result of the incoming data. - * The constructor function takes attributes that define how and where in the HTML document the object gets created. - * See {@link CIQ.Visualization#setAttributes} for more information on attributes. - * - * One useful application of this is to render an SVG graphic. - * - * Methods are provided to pass data into the object and to render it in the HTML document. Note that the `data` and - * `attributes` that are passed into the prototype methods of this object become owned by it and therefore can be mutated. - * - * The DOM object-generating function can assign class names to subelements within the object. These class names can be used - * to style the object using CSS. Documentation for the built-in functions explains which classes are available to be styled. - * - * @param {object} attributes Parameters to be used when creating the object. - * @param {function} attributes.renderFunction DOM object-generating function. Takes data as an array (sorted by index property) - * and attributes as arguments *by reference* and returns an `HTMLElement` (which may have children). - * @param {HTMLElement|string} [attributes.container] Element in which to put the DOM object (or selector thereof). If omitted, - * a container element is created with 300 x 300 pixel dimensions. - * @param {boolean} [attributes.useCanvasShim] Set to true to relocate the container behind the canvas but in front of the - * gridlines. **Note:** Consider using {@link CIQ.ChartEngine#embedVisualization}; it automatically places the object - * within the canvases. - * @param {CIQ.ChartEngine} [attributes.stx] A reference to the chart engine. Required if using the canvas shim. - * @param {string} [attributes.id] Optional id attribute to assign to the object. - * @param {boolean} [attributes.forceReplace] True to force a complete replacement of the DOM object when data changes. - * Do not set if `renderFunction` can handle an incremental update of the object. Alternatively, `renderFunction` might set - * this attribute. When attributes are updated using `setAttributes`, a complete replacement occurs. - * @constructor - * @name CIQ.Visualization - * @example - * let svg=new CIQ.Visualization({ renderFunction: CIQ.SVGChart.renderPieChart }); - * svg.updateData({"Low":{name:"low", value:30}, "High":{name:"high", value:70}}); - * @tsdeclaration - * constructor( - * attributes: { - * renderFunction: Function, - * container?: HTMLElement|string, - * useCanvasShim?: boolean, - * stx?: CIQ.ChartEngine, - * id?: string, - * forceReplace?: boolean, - * [renderAttributes:string]: any - * } - * ) - * @since 7.4.0 - */ -CIQ.Visualization = - CIQ.Visualization || - function (attributes) { - if (!attributes) { - console.log("CIQ.Visualization() missing attributes argument."); - return; - } - if (typeof attributes.renderFunction !== "function") { - console.log( - "CIQ.Visualization() missing renderFunction property in attributes." - ); - return; - } - /** - * READ ONLY. The DOM container that hosts the DOM object. - * - * @type HTMLElement - * @memberof CIQ.Visualization - * @since 7.4.0 - */ - this.container = null; - /** - * READ ONLY. The attributes used to render the DOM object. See the [function description]{@link CIQ.Visualization} - * for details. Do not change this property directly; instead, use {@link CIQ.Visualization#setAttributes}. - * @type object - * @memberof CIQ.Visualization - * @since 7.4.0 - */ - this.attributes = attributes; - /** - * READ ONLY. The data used to render the DOM object. See the [function description]{@link CIQ.Visualization} - * for details. Do not change this property directly; instead, use {@link CIQ.Visualization#updateData}. - * @type object - * @memberof CIQ.Visualization - * @since 7.4.0 - */ - this.data = null; - /** - * READ ONLY. The DOM object created by the rendering function. - * - * @type HTMLElement - * @memberof CIQ.Visualization - * @since 7.4.0 - */ - this.object = null; - }; -CIQ.extend(CIQ.Visualization.prototype, { - /** - * Removes the DOM object. If the container was generated by this object, the container is also removed. - * - * @param {boolean} soft True to leave properties of this object alone. Setting to false is preferable. - * @memberof CIQ.Visualization# - * @since 7.4.0 - */ - destroy: function (soft) { - var container = this.container; - CIQ.resizeObserver(container, null, container.resizeHandle); - if (container.autoGenerated) { - container.remove(); - delete this.container; - } else container.innerHTML = ""; - if (soft) return; - - // suicide!!! - this.attributes = null; - this.container = null; - this.data = null; - this.object = null; - this.destroy = this.draw = this.setAttributes = function () {}; - this.updateData = function () { - return undefined; - }; - }, - /** - * Draws the DOM object in its container. Data must be set using {@link CIQ.Visualization#updateData} prior - * to calling this function. Any content existing within the container is removed prior to drawing the object. - * - * @param {boolean} forceReplace Indicates whether a full redraw is requested. - * @since 7.4.0 - * @memberof CIQ.Visualization# - */ - draw: function (forceReplace) { - if (!this.data || typeof this.data !== "object") { - console.log("CIQ.Visualization.draw() missing data."); - return; - } - - function sortFcn(l, r) { - return l.index < r.index ? -1 : l.index > r.index ? 1 : 0; - } - - var attributes = this.attributes; - var container = attributes.container || this.container; - if (typeof container === "string") - container = document.querySelector(container); - - if (!container) { - container = document.createElement("div"); - container.style.height = container.style.width = "300px"; - document.body.appendChild(container); - container.autoGenerated = true; - } - if (attributes.stx) { - var shim = attributes.stx.chart.canvasShim; - if ( - attributes.useCanvasShim && - shim && - shim !== container && - shim !== container.parentNode - ) { - if (!container.autoGenerated) { - container = container.cloneNode(); - container.id = ""; - container.autoGenerated = true; - } - shim.appendChild(container); - } - } - if (this.container && this.container !== container) { - this.destroy(true); - } - if (!container.resizeHandle) { - var closure = function (me) { - return function () { - if (me.data && me.container && document.body.contains(me.container)) { - me.draw.call(me, true); - } - }; - }; - container.resizeHandle = CIQ.resizeObserver( - container, - closure(this), - null, - 100 - ); - } - this.container = container; - this.attributes = attributes; - - attributes = CIQ.ensureDefaults( - { container: this.container }, - this.attributes - ); - var object = attributes.renderFunction( - Object.values(this.data).sort(sortFcn), - attributes - ); - if (object) { - if (attributes.id) object.id = attributes.id; - if (forceReplace || attributes.forceReplace) { - this.container.innerHTML = ""; - this.container.appendChild(object); - } - } - this.attributes = attributes; - this.object = object; - }, - /** - * Adds or changes the visualization object attributes, and then calls the draw function. - * - * The following generic attributes are available to all objects; all attributes are passed into the object-generating - * function and may be used there: - * - renderFunction - * - container - * - stx - * - useCanvasShim - * - id - * - forceReplace - * - * Attributes are passed into `renderFunction`, the object-generating function; and so, additional attributes can be - * added specific to the function. - * - * **Note:** The attributes passed into `renderFunction` can be changed by the render function when necessary. You can - * set either one attribute by passing in a key and a value, or you can add a set of attributes by passing in an object - * of key/value pairs. - * - * @param {object|string} arg1 An attribute key or and object of attribute key/value pairs. - * @param {*} [arg2] The value of the attribute if passing in one key and value. - * @memberof CIQ.Visualization# - * @since 7.4.0 - */ - setAttributes: function (arg1, arg2) { - var forceAttrs = [ - "renderFunction", - "container", - "stx", - "useCanvasShim", - "id", - "forceReplace" - ]; - var useForce = false; - var attr = arg1; - if (typeof arg1 == "string") { - attr = {}; - attr[arg1] = arg2; - } - if (typeof attr == "object") { - for (var key in attr) { - if ( - this.attributes[key] !== attr[key] && - forceAttrs.indexOf(key) !== -1 - ) - useForce = true; - this.attributes[key] = attr[key]; - } - } - this.draw(useForce); - }, - /** - * Adds or changes the visualization object data, and then calls the draw function. - * - * @param {(object|array)} data Provides data used to generate the DOM object. Contains at a minimum a `name`, a `value`, - * and an optional `index`, which specifies sort order. The data must accommodate the update `action`. - * @param {string} [action] The action to take when generating the DOM object. Valid actions are "add", "update", - * "delete", and "replace" (default). - * - * The `data` object provides each action with the required data. - * - * | Action | Required Data | - * | ------ | ---- | - * | replace | A full data object. | - * | delete | The data records to remove. **Note:** This may affect the colors used in the chart. - * | update | The data records to update. The existing records will have their properties replaced with the new properties, leaving all non-matching properties alone. - * | add | The same as the "update" action except the `value` property of the existing data is augmented instead of replaced by the new value. - * - * See the examples below. - * - * **Note:** If only the `value` property is being changed, it may be passed as a raw number rather than being assigned - * to an object property. - * - * @example - * Given a CIQ.Visualization instance obj: - * obj.updateData({"up",{value:1}},"add") // Adds 1 to the value property of the data record "up". - * obj.updateData({"up":1},"add") // Also adds 1 to the value property of the data record "up". - * obj.updateData({"up",{name:"UP"}},"update") // Updates the name property of the data record "up" to "UP". - * obj.updateData({"down",null},"delete") // Removes the record "down". - * obj.updateData({"down",{value:6}},"update") // Updates the value property of the data record "down" to 6. - * obj.updateData({"down",0},"update") // Updates the value property of the data record "down" to 0. - * obj.updateData({"up":5,"down":4},"replace") // Replaces the entire data record with the new record. - * obj.updateData({"up":5,"down":4}) // Same as above; "replace" is the default action. - * - * @return {CIQ.Visualization} This object. - * @memberof CIQ.Visualization# - * @since 7.4.0 - */ - updateData: function (data, action) { - var n, value; - // normalize data into object - var _data = Array.isArray(data) - ? data.reduce(function (acc, cur) { - acc[cur.name] = cur; - return acc; - }, {}) - : CIQ.shallowClone(data); - for (n in _data) { - value = _data[n]; - if (Object.prototype.toString.call(value) !== "[object Object]") - _data[n] = { value: value }; - if (!_data[n].name) _data[n].name = n; - if (!_data[n].value) _data[n].value = 0; - } - - if (!action) action = "replace"; - switch (action.toLowerCase()) { - case "delete": - for (n in _data) delete this.data[n]; - break; - case "replace": - this.data = {}; /* falls through */ - case "update": - case "add": - for (n in _data) { - if (!this.data[n]) this.data[n] = { name: n }; - value = _data[n].value; - if (Object.prototype.toString.call(value) == "[object Number]") { - if (!this.data[n].value || action == "update") - this.data[n].value = 0; - this.data[n].value += value; - } else { - this.data[n].value = value; - } - for (var p in _data[n]) { - if (p !== "value") this.data[n][p] = _data[n][p]; - } - } - break; - default: - console.log( - "Invalid or missing action. Valid values are 'add', 'delete', 'replace', or 'update'." - ); - } - this.draw(this.attributes.forceReplace); - return this; - } -}); - -/** - * Convenience function that embeds a {@link CIQ.Visualization} in the canvas area. Embedding is accomplished - * by placing the visualization object within the chart engine's canvas shim, an area - * behind the main canvas. Placing an object in the canvas shim creates the appearance that the chart plot is - * on top of the object. If using the chart background canvas (the default), the object appears on top of the - * gridlines and axes. - * - * Attributes are passed into `renderFunction`, so additional attributes can be added specific to the function. - * **Note:** If a valid `container` attribute is supplied, that container will be cloned and appended into the - * chart's `canvasShim`. - * - * @param {object} attributes Parameters to be used when creating the object. - * @param {function} attributes.renderFunction The function that generates the object. Takes data and attributes - * as arguments and returns an object element. - * @param {HTMLElement|string} [attributes.container] Element that is cloned and used to contain the object - * (or selector thereof). If omitted, a container element is created with 300 x 300 pixel dimensions. - * @param {string} [attributes.id] Optional id attribute to assign to the object. - * @return {CIQ.Visualization} A handle to the object created, see {@link CIQ.Visualization}. - * @memberof CIQ.ChartEngine - * - * @since 7.4.0 - */ -CIQ.ChartEngine.prototype.embedVisualization = function (attributes) { - if (!attributes) attributes = {}; - attributes.stx = this; - attributes.useCanvasShim = true; - attributes.translator = function (x) { - return attributes.stx.translateIf(x); - }; - return new CIQ.Visualization(attributes); -}; - -}; - - -let __js_standard_studies_medianPrice_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -if (!CIQ.Studies) { - console.error( - "medianPrice feature requires first activating studies feature." - ); -} else { - /** - * Calculate function for Typical Price studies. Median Price, Typical Price and Weighted Close. - * - * The resulting values will be added to the dataSet using the field name provided by the `sd.outputMap` entry. - * - * **Notes:** - * - This function calculates a single value, so it expects `sd.outputMap` to contain a single mapping. - * - If no `outputs` object is defined in the library entry, the study will default to a single output named `Result`, which will then be used in lieu of `sd.outputs` to build the field name. - * - The study name may contain the unprintable character `‌`, see {@link studyDescriptor} documentation. - * - * @param {CIQ.ChartEngine} stx Chart object - * @param {CIQ.Studies.StudyDescriptor} sd Study Descriptor - * @memberof CIQ.Studies - */ - CIQ.Studies.calculateTypicalPrice = function (stx, sd) { - var quotes = sd.chart.scrubbed; - var period = sd.days; - if (quotes.length < period + 1) { - if (!sd.overlay) sd.error = true; - return; - } - var name = sd.name; - for (var p in sd.outputs) { - name = p + " " + name; - } - var field = "hlc/3"; - if (sd.type == "Med Price") field = "hl/2"; - else if (sd.type == "Weighted Close") field = "hlcc/4"; - - var total = 0; - if (sd.startFrom <= period) sd.startFrom = 0; - for (var i = sd.startFrom; i < quotes.length; i++) { - if (i && quotes[i - 1][name]) total = quotes[i - 1][name] * period; - total += quotes[i][field]; - if (i >= period) { - total -= quotes[i - period][field]; - quotes[i][name] = total / period; - } - } - }; - - CIQ.Studies.studyLibrary = CIQ.extend(CIQ.Studies.studyLibrary, { - "Med Price": { - name: "Median Price", - calculateFN: CIQ.Studies.calculateTypicalPrice, - inputs: { Period: 14 } - } - }); -} - -}; - - -let __js_standard_studies_momentum_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -if (!CIQ.Studies) { - console.error("momentum feature requires first activating studies feature."); -} else { - /** - * Calculate function for Rate Of Change related studies. Price ROC, Volume ROC and Momentum. - * - * The resulting values will be added to the dataSet using the field name provided by the `sd.outputMap` entry. - * - * **Notes:** - * - This function calculates a single value, so it expects `sd.outputMap` to contain a single mapping. - * - If no `outputs` object is defined in the library entry, the study will default to a single output named `Result`, which will then be used in lieu of `sd.outputs` to build the field name. - * - The study name may contain the unprintable character `‌`, see {@link studyDescriptor} documentation. - * - * @param {CIQ.ChartEngine} stx Chart object - * @param {CIQ.Studies.StudyDescriptor} sd Study Descriptor - * @memberof CIQ.Studies - */ - CIQ.Studies.calculateRateOfChange = function (stx, sd) { - var quotes = sd.chart.scrubbed; - if (quotes.length < sd.days + 1) { - sd.error = true; - return; - } - var field = sd.inputs.Field; - if (!field || field == "field") field = "Close"; - if (sd.parameters.isVolume) field = "Volume"; - var name = sd.name; - for (var p in sd.outputs) { - name = p + " " + name; - } - - var offset = sd.inputs["Center Line"]; - if (!offset) offset = 0; - else offset = parseInt(offset, 10); - - for (var i = Math.max(sd.startFrom, sd.days); i < quotes.length; i++) { - var currentVal = quotes[i][field]; - if (currentVal && typeof currentVal == "object") - currentVal = currentVal[sd.subField]; - var pastVal = quotes[i - sd.days][field]; - if (pastVal && typeof pastVal == "object") pastVal = pastVal[sd.subField]; - if (sd.type == "Momentum") - quotes[i][name] = currentVal - pastVal + offset; - else { - var denom = pastVal; - if (denom) { - // skip if denominator is 0 -- - quotes[i][name] = 100 * (currentVal / denom - 1) + offset; - } - } - } - }; - - CIQ.Studies.studyLibrary = CIQ.extend(CIQ.Studies.studyLibrary, { - "Price ROC": { - name: "Price Rate of Change", - calculateFN: CIQ.Studies.calculateRateOfChange, - inputs: { Period: 14, Field: "field" } - }, - Momentum: { - name: "Momentum Indicator", - calculateFN: CIQ.Studies.calculateRateOfChange, - inputs: { Period: 14 }, - centerline: 0 - } - }); -} - -}; - - -let __js_standard_studies_priceRelative_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -if (!CIQ.Studies) { - console.error( - "priceRelative feature requires first activating studies feature." - ); -} else { - /** - * Initializes data for Price Relative Study by fetching the comparing symbol. - * - * @param {CIQ.ChartEngine} stx The chart object - * @param {string} type Study type - * @param {object} inputs Study inputs - * @param {object} outputs Study outputs - * @param {object} parameters Study parameters - * @param {string} panel ID of the study's panel element - * @return {CIQ.Studies.StudyDescriptor} Study descriptor object - * @memberof CIQ.Studies - * @since 09-2016-19 - */ - CIQ.Studies.initPriceRelative = function ( - stx, - type, - inputs, - outputs, - parameters, - panel - ) { - var sd = CIQ.Studies.initializeFN( - stx, - type, - inputs, - outputs, - parameters, - panel - ); - var syms = [sd.inputs["Comparison Symbol"].toUpperCase()]; - - CIQ.Studies.fetchAdditionalInstruments(stx, sd, syms); - return sd; - }; - - /** - * Calculates data for Price Relative Study - * - * @param {CIQ.ChartEngine} stx The chart object - * @param {object} sd The study descriptor object - * @memberof CIQ.Studies - */ - CIQ.Studies.calculatePriceRelative = function (stx, sd) { - var quotes = sd.chart.scrubbed; - var cSym = sd.inputs["Comparison Symbol"].toUpperCase(); - if (!cSym) cSym = sd.study.inputs["Comparison Symbol"]; - - var map = {}; - var mainSymbol = stx.chart.symbol || ""; - mainSymbol = mainSymbol.replace(/[=+\-*\\%]/g, ""); - map[mainSymbol] = quotes.slice(sd.startFrom); - if (!map[mainSymbol].length) return; - if (mainSymbol != cSym) map[cSym] = null; - var results = CIQ.computeEquationChart( - "[" + mainSymbol + "]/[" + cSym + "]", - map - ); - var rIter = 0; - for ( - var i = sd.startFrom; - i < quotes.length && rIter < results.length; - i++ - ) { - while ( - rIter < results.length && - quotes[i].DT.getTime() > results[rIter].DT.getTime() - ) - rIter++; - if (quotes[i].DT.getTime() < results[rIter].DT.getTime()) continue; - quotes[i]["Result " + sd.name] = results[rIter].Close; - rIter++; - } - }; - - CIQ.Studies.displayVsComparisonSymbol = function (stx, sd, quotes) { - var symbol = sd.inputs["Comparison Symbol"].toUpperCase(); - if (!stx.getSeries({ symbol: symbol, chart: sd.chart }).length) { - stx.displayErrorAsWatermark( - sd.panel, - stx.translateIf(sd.study.name) + ": " + stx.translateIf("Not Available") - ); - return; - } - var params = { - skipTransform: stx.panels[sd.panel].name != sd.chart.name, - panelName: sd.panel, - band: "Result " + sd.name, - threshold: sd.study.centerline, - yAxis: sd.getYAxis(stx), - gapDisplayStyle: true - }; - var flipped = params.yAxis - ? params.yAxis.flipped - : stx.panels[sd.panel].yAxis.flipped; - var opacity = 0.3; - if (!sd.highlight && stx.highlightedDraggable) opacity *= 0.3; - - for (var c = quotes.length - 1; c >= 0; c--) { - if (quotes[c] && quotes[c][symbol]) { - CIQ.Studies.displaySeriesAsLine(stx, sd, quotes); - if (sd.study.centerline || sd.study.centerline === 0) { - if (sd.outputs.Gain) - CIQ.preparePeakValleyFill( - stx, - CIQ.extend(params, { - direction: flipped ? -1 : 1, - color: CIQ.Studies.determineColor(sd.outputs.Gain), - opacity: opacity - }) - ); - if (sd.outputs.Loss) - CIQ.preparePeakValleyFill( - stx, - CIQ.extend(params, { - direction: flipped ? 1 : -1, - color: CIQ.Studies.determineColor(sd.outputs.Loss), - opacity: opacity - }) - ); - } - return; - } - } - }; - - /** - * Ensures that symbols required by a study are loaded and maintained by the quotefeed. - * @param {CIQ.ChartEngine} stx The chart engine - * @param {object} sd The study descriptor - * @param {array} syms An array of 'symbol strings' or 'symbol objects' required by the study. If using symbol objets, in addition to our desired identifier elements, you must `always` include the `symbol` element in it (ie: `symbolObject[i]={ symbol : mySymbol , otherStuff1 : xx , moreStuff : yy}`. - * @param {object} [params] Parameters to be sent to addSeries. See {@link CIQ.ChartEngine#addSeries}. - * @memberof CIQ.Studies - * @since 3.0.7 This was a previously private function. - */ - CIQ.Studies.fetchAdditionalInstruments = function (stx, sd, syms, params) { - if (!stx.quoteDriver) { - console.log( - "CIQ.Studies.fetchAdditionalInstruments: No quotefeed to fetch symbol" - ); - return; - } - // sd.chart may not be initialized, so we find it the hard way - var chart = stx.panels[sd.panel].chart; - - // We'll remember which symbols we have set so that we can delete them later - sd.symbols = syms; - - var i, symbol, symbolObject; - // Add entries for the symbols we need. If those symbols already exist, add the study name as a dependency - function addSeriesCB() { - stx.createDataSet(); - stx.draw(); - } - for (i = 0; i < syms.length; i++) { - symbol = symbolObject = syms[i]; - if (typeof symbolObject == "object") { - symbol = symbolObject.symbol; - } else { - symbolObject = { symbol: symbol }; - } - var parameters = { - symbol: symbol, - symbolObject: symbolObject, - bucket: "study", - studyName: sd.name, - chartName: chart.name, - action: "add-study" - }; - CIQ.extend(parameters, params); - var loadData = parameters.loadData; - if (stx.currentlyImporting) parameters.loadData = false; // do not load data if importing as periodicity will not be correct; instead let loadDependents load data - if (!sd.series) sd.series = {}; - sd.series[symbol] = stx.addSeries(null, parameters, addSeriesCB); - sd.series[symbol].parameters.loadData = loadData; - } - }; - - CIQ.Studies.studyLibrary = CIQ.extend(CIQ.Studies.studyLibrary, { - "P Rel": { - name: "Price Relative", - initializeFN: CIQ.Studies.initPriceRelative, - seriesFN: CIQ.Studies.displayVsComparisonSymbol, - calculateFN: CIQ.Studies.calculatePriceRelative, - centerline: 0, - inputs: { "Comparison Symbol": "SPY" }, - deferUpdate: true - } - }); -} - -}; - - -let __js_standard_studies_vwap_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -if (!CIQ.Studies) { - console.error("vwap feature requires first activating studies feature."); -} else { - /** - * Calculate function for VWAP. - * - * Cumulative values are calculated on a daily basis. - * The start of the day is calculated based on the particular market start time. - * As such, you may need to review your market definitions and symbology for this study to properly work with your data as the default assumptions may not totally match. - * More information on setting market hours and symbology rules can be found here: {@link CIQ.Market} - * - * In our calculations, the beginning of the Forex day is 17:00 NY Time. - * The chart will be adjusted as needed to reflect this time in the browser time zone (or any specificaly set display zone). - * - * @param {CIQ.ChartEngine} stx Chart object - * @param {object} sd Study Descriptor - * @memberof CIQ.Studies - * @since 7.0.0 Used for AVWAP calculation as well. - */ - CIQ.Studies.calculateVWAP = function (stx, sd) { - var avwap = sd.type == "AVWAP"; - var quotes = sd.chart.scrubbed; - if (!avwap && CIQ.ChartEngine.isDailyInterval(stx.layout.interval)) { - sd.error = "VWAP is Intraday Only"; - return; - } - var field = "hlc/3"; - if (avwap) { - field = sd.inputs.Field; - if (!field || field == "field") { - field = sd.inputs.Field = "hlc/3"; - stx.changeOccurred("layout"); - } - } - var marketOffset = null; - var volume = 0; - var volume_price = 0; - var volume_price2 = 0; - var hasThereBeenVolume = false; - - if (sd.startFrom > 1) { - volume = quotes[sd.startFrom - 1]["_V " + sd.name] || 0; - volume_price = quotes[sd.startFrom - 1]["_VxP " + sd.name] || 0; - volume_price2 = quotes[sd.startFrom - 1]["_VxP2 " + sd.name] || 0; - } - if (avwap) { - var anchorDate = sd.inputs["Anchor Date"].replace(/-/g, ""); - if (anchorDate.search(/^\d{8}$/)) { - sd.error = "Invalid Anchor Date"; - return; - } - var anchorTime = sd.inputs["Anchor Time"].replace(/:/g, ""); - if (!anchorTime.search(/^\d{4,6}$/)) { - anchorDate += anchorTime; - } - anchorDate = CIQ.strToDateTime(anchorDate.replace(/\D/g, "")); - if (!sd.startFrom && anchorDate >= quotes[0].DT) { - sd.startFrom = stx.tickFromDate(anchorDate, stx.chart, null, true); - } - - if (sd.inputs["Anchor Selector"]) CIQ.Studies.initAnchorHandle(stx, sd); - else CIQ.Studies.removeAnchorHandle(stx, sd); - } - for (var i = sd.startFrom; i < quotes.length; i++) { - if (!avwap) { - if (marketOffset === null) { - //possible new daily period - marketOffset = CIQ.Studies.getMarketOffset({ - stx, - localQuoteDate: quotes[i].DT, - shiftToDateBoundary: true - }); - } - if (quotes[i - 1] && quotes[i - 1].DT) { - var newDate = new Date( - new Date(+quotes[i].DT).setMilliseconds( - quotes[i].DT.getMilliseconds() + marketOffset - ) - ); - var oldDate = new Date( - new Date(+quotes[i - 1].DT).setMilliseconds( - quotes[i - 1].DT.getMilliseconds() + marketOffset - ) - ); - if ( - oldDate.getDate() != newDate.getDate() && - stx.chart.market.isMarketDate(newDate) - ) { - //new daily period - marketOffset = null; - volume = volume_price = volume_price2 = 0; - } - } - } - var price = quotes[i][field]; - var thisVolume = quotes[i].Volume; - if (avwap && !thisVolume) thisVolume = 1; - volume += thisVolume; - volume_price += thisVolume * price; - volume_price2 += thisVolume * price * price; - if (!avwap && !volume) continue; - quotes[i]["_V " + sd.name] = volume; - quotes[i]["_VxP " + sd.name] = volume_price; - quotes[i]["_VxP2 " + sd.name] = volume_price2; - var sdev = (quotes[i]["_SDVWAP " + sd.name] = Math.sqrt( - Math.max(0, volume_price2 / volume - Math.pow(volume_price / volume, 2)) - )); - var vwap = (quotes[i]["VWAP " + sd.name] = volume_price / volume); - for (var j = 1; j <= 3; j++) { - quotes[i]["SDVWAP" + j + "+ " + sd.name] = vwap + j * sdev; - quotes[i]["SDVWAP" + j + "- " + sd.name] = vwap - j * sdev; - } - hasThereBeenVolume = true; - } - for (var k = 1; k <= 3; k++) { - if (sd.inputs["Display " + k + " Standard Deviation (" + k + "\u03C3)"]) { - sd.outputMap["SDVWAP" + k + "+ " + sd.name] = - k + " Standard Deviation (" + k + "\u03C3)"; - sd.outputMap["SDVWAP" + k + "- " + sd.name] = - k + " Standard Deviation (" + k + "\u03C3)"; - } - } - if (!avwap && !hasThereBeenVolume) { - sd.error = "VWAP Requires Volume"; - } - }; - - /** - * Initializes Anchored VWAP study - * - * Specifically, sets the anchor date and time to the first dataSegment record if it's left blank - * - * @param {CIQ.ChartEngine} stx The chart object - * @param {string} type Study type - * @param {object} inputs Study inputs - * @param {object} outputs Study outputs - * @param {object} parameters Study parameters - * @param {string} panel ID of the study's panel element - * @return {CIQ.Studies.StudyDescriptor} Study descriptor object - * - * @memberof CIQ.Studies - * @private - * @since 6.3.0 - */ - CIQ.Studies.initAnchoredVWAP = function ( - stx, - type, - inputs, - outputs, - parameters, - panel - ) { - if (!inputs["Anchor Date"] && !inputs["Anchor Time"]) { - const { dataSegment } = stx.chart; - for (let i = 0; dataSegment && i < dataSegment.length; i++) { - if (dataSegment[i]) { - const { DT } = dataSegment[i]; - inputs["Anchor Date"] = CIQ.dateToStr(DT, "YYYY-MM-dd"); - inputs["Anchor Time"] = CIQ.dateToStr(DT, "HH:mm:ss"); - break; - } - } - } - const sd = CIQ.Studies.initializeFN( - stx, - type, - inputs, - outputs, - parameters, - panel - ); - return sd; - }; - - CIQ.Studies.displayVWAP = function (stx, sd, quotes) { - CIQ.Studies.displaySeriesAsLine(stx, sd, quotes); - - var displayS1 = sd.inputs["Display 1 Standard Deviation (1\u03C3)"]; - var displayS2 = sd.inputs["Display 2 Standard Deviation (2\u03C3)"]; - var displayS3 = sd.inputs["Display 3 Standard Deviation (3\u03C3)"]; - - if ((displayS1 || displayS2 || displayS3) && sd.inputs.Shading) { - var panel = stx.panels[sd.panel]; - var params = { - opacity: sd.parameters.opacity ? sd.parameters.opacity : 0.2, - skipTransform: panel.name != sd.chart.name, - yAxis: sd.getYAxis(stx) - }; - if (!sd.highlight && stx.highlightedDraggable) params.opacity *= 0.3; - - var bottomBandP = "VWAP " + sd.name, - bottomBandN = "VWAP " + sd.name; - if (displayS1) { - CIQ.prepareChannelFill( - stx, - CIQ.extend( - { - panelName: sd.panel, - topBand: "SDVWAP1+ " + sd.name, - bottomBand: bottomBandP, - color: CIQ.Studies.determineColor( - sd.outputs[sd.outputMap["SDVWAP1+ " + sd.name]] - ) - }, - params - ) - ); - CIQ.prepareChannelFill( - stx, - CIQ.extend( - { - panelName: sd.panel, - topBand: "SDVWAP1- " + sd.name, - bottomBand: bottomBandN, - color: CIQ.Studies.determineColor( - sd.outputs[sd.outputMap["SDVWAP1- " + sd.name]] - ) - }, - params - ) - ); - bottomBandP = "SDVWAP1+ " + sd.name; - bottomBandN = "SDVWAP1- " + sd.name; - } - if (displayS2) { - CIQ.prepareChannelFill( - stx, - CIQ.extend( - { - panelName: sd.panel, - topBand: "SDVWAP2+ " + sd.name, - bottomBand: bottomBandP, - color: CIQ.Studies.determineColor( - sd.outputs[sd.outputMap["SDVWAP2+ " + sd.name]] - ) - }, - params - ) - ); - CIQ.prepareChannelFill( - stx, - CIQ.extend( - { - panelName: sd.panel, - topBand: "SDVWAP2- " + sd.name, - bottomBand: bottomBandN, - color: CIQ.Studies.determineColor( - sd.outputs[sd.outputMap["SDVWAP2- " + sd.name]] - ) - }, - params - ) - ); - bottomBandP = "SDVWAP2+ " + sd.name; - bottomBandN = "SDVWAP2- " + sd.name; - } - if (displayS3) { - CIQ.prepareChannelFill( - stx, - CIQ.extend( - { - panelName: sd.panel, - topBand: "SDVWAP3+ " + sd.name, - bottomBand: bottomBandP, - color: CIQ.Studies.determineColor( - sd.outputs[sd.outputMap["SDVWAP3+ " + sd.name]] - ) - }, - params - ) - ); - CIQ.prepareChannelFill( - stx, - CIQ.extend( - { - panelName: sd.panel, - topBand: "SDVWAP3- " + sd.name, - bottomBand: bottomBandN, - color: CIQ.Studies.determineColor( - sd.outputs[sd.outputMap["SDVWAP3- " + sd.name]] - ) - }, - params - ) - ); - } - } - - if (sd.anchorHandle) { - CIQ.Studies.displayAnchorHandleAndLine(stx, sd, quotes); - } - }; - - CIQ.Studies.studyLibrary = CIQ.extend(CIQ.Studies.studyLibrary, { - AVWAP: { - name: "Anchored VWAP", - overlay: true, - calculateFN: CIQ.Studies.calculateVWAP, - seriesFN: CIQ.Studies.displayVWAP, - initializeFN: CIQ.Studies.initAnchoredVWAP, - removeFN: CIQ.Studies.removeAnchorHandle, - inputs: { - Field: "field", - "Anchor Date": "", - "Anchor Time": "", - "Display 1 Standard Deviation (1\u03C3)": false, - "Display 2 Standard Deviation (2\u03C3)": false, - "Display 3 Standard Deviation (3\u03C3)": false, - Shading: false, - "Anchor Selector": true - }, - outputs: { - VWAP: "#FF0000", - "1 Standard Deviation (1\u03C3)": "#e1e1e1", - "2 Standard Deviation (2\u03C3)": "#85c99e", - "3 Standard Deviation (3\u03C3)": "#fff69e" - }, - parameters: { - init: { opacity: 0.2 } - }, - attributes: { - "Anchor Date": { placeholder: "yyyy-mm-dd" }, - "Anchor Time": { placeholder: "hh:mm:ss", step: 1 } - } - }, - VWAP: { - name: "VWAP", - overlay: true, - calculateFN: CIQ.Studies.calculateVWAP, - seriesFN: CIQ.Studies.displayVWAP, - inputs: { - "Display 1 Standard Deviation (1\u03C3)": false, - "Display 2 Standard Deviation (2\u03C3)": false, - "Display 3 Standard Deviation (3\u03C3)": false, - Shading: false - }, - outputs: { - VWAP: "#FF0000", - "1 Standard Deviation (1\u03C3)": "#e1e1e1", - "2 Standard Deviation (2\u03C3)": "#85c99e", - "3 Standard Deviation (3\u03C3)": "#fff69e" - }, - parameters: { - init: { opacity: 0.2 } - } - } - }); -} - -}; - - -let __js_standard_studies_zigzag_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -if (!CIQ.Studies) { - console.error("zigzag feature requires first activating studies feature."); -} else { - // Note: this study expects createDataSet to be called when changing the chart type! - CIQ.Studies.calculateZigZag = function (stx, sd) { - var quotes = sd.chart.scrubbed; - if (!quotes || !quotes.length) return; - var highLowChart = sd.highLowChart; - function fillBetweenPoints(start, end) { - for (var i = start + 1; i < end; i++) { - quotes[i]["ShadowResult " + sd.name] = - ((quotes[end]["Result " + sd.name] - - quotes[start]["Result " + sd.name]) * - (i - start)) / - (end - start) + - quotes[start]["Result " + sd.name]; - delete quotes[i]["Result " + sd.name]; - } - } - var ll = null, - hh = null; - var distance = sd.inputs["Distance(%)"]; - var direction = 0; - var bar = 0; - var previousBar = 0; - var zig = null, - zag = null; - var start = 0; - for (var b = Math.min(quotes.length - 1, sd.startFrom); b >= 0; b--) { - start = b; - if (quotes[b]["_state " + sd.name]) { - var state = quotes[b]["_state " + sd.name]; - //[ll,hh,direction,bar,previousBar,zig,zag] - ll = state[0]; - hh = state[1]; - direction = state[2]; - bar = state[3]; - previousBar = state[4]; - zig = state[5]; - zag = state[6]; - break; - } - } - for (var i = start; i < quotes.length; i++) { - var thisHigh = quotes[i][highLowChart ? "High" : "Close"]; - var thisLow = quotes[i][highLowChart ? "Low" : "Close"]; - if (hh === null || hh < thisHigh) { - hh = thisHigh; - if (direction < 0) ll = thisLow; - zig = (1 - distance / 100) * hh; - if (direction > -1) { - if (zag !== null && hh > zag) { - quotes[bar]["Result " + sd.name] = - quotes[bar][highLowChart ? "Low" : "Close"]; - fillBetweenPoints(previousBar, bar); - direction = -1; - ll = thisLow; - previousBar = bar; - bar = i; - continue; - } - } else { - bar = i; - } - } - if (ll === null || ll > thisLow) { - ll = thisLow; - if (direction > 0) hh = thisHigh; - zag = (1 + distance / 100) * ll; - if (direction < 1) { - if (zig !== null && ll < zig) { - quotes[bar]["Result " + sd.name] = - quotes[bar][highLowChart ? "High" : "Close"]; - fillBetweenPoints(previousBar, bar); - direction = 1; - hh = thisHigh; - previousBar = bar; - bar = i; - continue; - } - } else { - bar = i; - } - } - } - quotes[bar]["Result " + sd.name] = - quotes[bar][highLowChart ? (direction == 1 ? "Low" : "High") : "Close"]; - quotes[bar]["_state " + sd.name] = [ - ll, - hh, - direction, - bar, - previousBar, - zig, - zag - ]; - fillBetweenPoints(previousBar, bar); - var fin = quotes.length - 1; - while (fin > bar) { - if (quotes[fin].Close || quotes[fin].Close === 0) { - quotes[fin]["Result " + sd.name] = - quotes[fin][ - highLowChart ? (direction == 1 ? "High" : "Low") : "Close" - ]; - break; - } - fin--; - } - fillBetweenPoints(bar, fin); - }; - - CIQ.Studies.displayZigZag = function (stx, sd, quotes) { - var highLowBars = stx.chart.highLowBars; - if (sd.highLowChart != highLowBars) { - sd.highLowChart = highLowBars; - sd.startFrom = 0; - sd.study.calculateFN(stx, sd); - } - var chart = stx.chart; - for (var i = 0; i < quotes.length; i++) { - var quote = quotes[i]; - if (quote) { - if (quote["_shadowCopy " + sd.name]) { - delete quote["Result " + sd.name]; - delete quote["_shadowCopy " + sd.name]; - } - if (!quote["Result " + sd.name]) { - if (quote.transform) delete quote.transform["Result " + sd.name]; - } - } - } - var q0 = quotes[0], - ql = quotes[quotes.length - 1]; - if (q0 && q0["ShadowResult " + sd.name]) { - q0["Result " + sd.name] = q0["ShadowResult " + sd.name]; - if (q0.transform) - q0.transform["Result " + sd.name] = chart.transformFunc( - stx, - chart, - q0["ShadowResult " + sd.name] - ); - q0["_shadowCopy " + sd.name] = 1; - } - if (ql && ql["ShadowResult " + sd.name]) { - ql["Result " + sd.name] = ql["ShadowResult " + sd.name]; - if (ql.transform) - ql.transform["Result " + sd.name] = chart.transformFunc( - stx, - chart, - ql["ShadowResult " + sd.name] - ); - ql["_shadowCopy " + sd.name] = 1; - } - CIQ.Studies.displaySeriesAsLine(stx, sd, quotes); - }; - - CIQ.Studies.studyLibrary = CIQ.extend(CIQ.Studies.studyLibrary, { - ZigZag: { - name: "ZigZag", - overlay: true, - seriesFN: CIQ.Studies.displayZigZag, - calculateFN: CIQ.Studies.calculateZigZag, - inputs: { "Distance(%)": 10 }, - parameters: { - init: { label: false } - }, - attributes: { - "Distance(%)": { min: 0.1, step: 0.1 } - } - } - }); -} - -}; - -/* eslint-disable */ /* jshint ignore:start */ /* ignore jslint start */ -M0PUm[539515]=(function(){var Z0=2;for(;Z0 !== 9;){switch(Z0){case 2:Z0=typeof globalThis === '\x6f\x62\x6a\u0065\x63\x74'?1:5;break;case 1:return globalThis;break;case 5:var X7;Z0=4;break;case 4:try{var T$=2;for(;T$ !== 6;){switch(T$){case 2:Object['\u0064\x65\x66\u0069\x6e\u0065\u0050\u0072\u006f\u0070\x65\u0072\x74\x79'](Object['\x70\u0072\u006f\x74\u006f\x74\u0079\x70\x65'],'\x6f\u0033\u0068\u006e\x39',{'\x67\x65\x74':function(){var B9=2;for(;B9 !== 1;){switch(B9){case 2:return this;break;}}},'\x63\x6f\x6e\x66\x69\x67\x75\x72\x61\x62\x6c\x65':true});X7=o3hn9;T$=5;break;case 5:X7['\x6e\u0037\u0067\x33\x72']=X7;T$=4;break;case 4:T$=typeof n7g3r === '\x75\u006e\x64\u0065\u0066\u0069\u006e\u0065\x64'?3:9;break;case 3:throw "";T$=9;break;case 9:delete X7['\x6e\x37\u0067\u0033\x72'];var r3=Object['\u0070\x72\u006f\u0074\u006f\x74\x79\u0070\x65'];delete r3['\x6f\x33\u0068\x6e\u0039'];T$=6;break;}}}catch(E3){X7=window;}return X7;break;}}})();b_daQh(M0PUm[539515]);M0PUm[238553]=false;M0PUm[103941]=M0PUm[446427];M0PUm[156040]=899;M0PUm.I0=function(){return typeof M0PUm[446427].g9iUvuS === 'function'?M0PUm[446427].g9iUvuS.apply(M0PUm[446427],arguments):M0PUm[446427].g9iUvuS;};M0PUm[539515].J499=M0PUm;M0PUm.I3=function(){return typeof M0PUm[593596].i9agN$W === 'function'?M0PUm[593596].i9agN$W.apply(M0PUm[593596],arguments):M0PUm[593596].i9agN$W;};M0PUm[446427]=(function(K9){return {N$y1PkD:function(){var A0,q8=arguments;switch(K9){case 12:A0=q8[0] * q8[3] + q8[1] - q8[2];break;case 8:A0=q8[0] >> q8[1];break;case 6:A0=(q8[7] - q8[6]) * (q8[5] - q8[1]) + (q8[4] - q8[3]) * (q8[2] - q8[0]);break;case 2:A0=q8[1] | q8[0];break;case 4:A0=q8[1] * q8[3] + q8[0] * q8[2];break;case 13:A0=q8[1] * q8[0];break;case 10:A0=q8[0] / q8[1];break;case 7:A0=(-q8[4] + q8[0]) * q8[2] * q8[3] + q8[1];break;case 11:A0=(-q8[0] - q8[2]) * q8[1] + q8[3];break;case 5:A0=q8[0] + q8[1];break;case 1:A0=q8[1] ^ q8[0];break;case 0:A0=q8[0] << q8[1];break;case 3:A0=q8[0] - q8[1];break;case 9:A0=(q8[2] * q8[0] - q8[3]) / q8[4] + q8[1];break;}return A0;},g9iUvuS:function(i4){K9=i4;}};})();M0PUm[150014]=M0PUm[539515];M0PUm[636832]=M0PUm[539515];M0PUm.a0=function(){return typeof M0PUm[370258].V29cT4d === 'function'?M0PUm[370258].V29cT4d.apply(M0PUm[370258],arguments):M0PUm[370258].V29cT4d;};M0PUm.p0=function(){return typeof M0PUm[370258].V29cT4d === 'function'?M0PUm[370258].V29cT4d.apply(M0PUm[370258],arguments):M0PUm[370258].V29cT4d;};M0PUm[370258]=(function(){var J9=function(F2,q_){var z8=q_ & 0xffff;var l9=q_ - z8;return (l9 * F2 | 0) + (z8 * F2 | 0) | 0;},V29cT4d=function(T7,A_,L8){var z9=0xcc9e2d51,g1=0x1b873593;var t4=L8;var W5=A_ & ~0x3;for(var m5=0;m5 < W5;m5+=4){var o8=T7.J4Cpo(m5) & 0xff | (T7.J4Cpo(m5 + 1) & 0xff) << 8 | (T7.J4Cpo(m5 + 2) & 0xff) << 16 | (T7.J4Cpo(m5 + 3) & 0xff) << 24;o8=J9(o8,z9);o8=(o8 & 0x1ffff) << 15 | o8 >>> 17;o8=J9(o8,g1);t4^=o8;t4=(t4 & 0x7ffff) << 13 | t4 >>> 19;t4=t4 * 5 + 0xe6546b64 | 0;}o8=0;switch(A_ % 4){case 3:o8=(T7.J4Cpo(W5 + 2) & 0xff) << 16;case 2:o8|=(T7.J4Cpo(W5 + 1) & 0xff) << 8;case 1:o8|=T7.J4Cpo(W5) & 0xff;o8=J9(o8,z9);o8=(o8 & 0x1ffff) << 15 | o8 >>> 17;o8=J9(o8,g1);t4^=o8;}t4^=A_;t4^=t4 >>> 16;t4=J9(t4,0x85ebca6b);t4^=t4 >>> 13;t4=J9(t4,0xc2b2ae35);t4^=t4 >>> 16;return t4;};return {V29cT4d:V29cT4d};})();M0PUm.a5=function(){return typeof M0PUm[593596].i9agN$W === 'function'?M0PUm[593596].i9agN$W.apply(M0PUm[593596],arguments):M0PUm[593596].i9agN$W;};function b_daQh(k6){function i6(h2){var R6=2;for(;R6 !== 5;){switch(R6){case 2:var N6=[arguments];return N6[0][0].RegExp;break;}}}var e6=2;for(;e6 !== 79;){switch(e6){case 48:i$[83]=i$[60];i$[83]+=i$[46];i$[83]+=i$[10];i$[64]=i$[98];e6=65;break;case 6:i$[5]="_o";i$[9]="bstract";i$[8]="o";i$[3]="";e6=11;break;case 34:i$[88]="";i$[88]="zjc";i$[80]="";i$[80]="I";e6=30;break;case 69:i$[90]+=i$[75];i$[43]=i$[36];i$[43]+=i$[5];i$[43]+=i$[4];i$[12]=i$[60];i$[12]+=i$[1];i$[12]+=i$[8];e6=87;break;case 87:var A4=function(Z2,V_,N5,T3){var I6=2;for(;I6 !== 5;){switch(I6){case 2:var n4=[arguments];I6=1;break;case 1:M0(i$[0][0],n4[0][0],n4[0][1],n4[0][2],n4[0][3]);I6=5;break;}}};e6=86;break;case 52:i$[60]="J";i$[84]=5;i$[84]=1;i$[55]=0;e6=48;break;case 65:i$[64]+=i$[58];i$[64]+=i$[15];i$[63]=i$[21];i$[63]+=i$[49];i$[63]+=i$[45];i$[28]=i$[27];i$[28]+=i$[80];e6=58;break;case 84:A4(u9,i$[54],i$[55],i$[23]);e6=83;break;case 83:A4(p$,"push",i$[84],i$[33]);e6=82;break;case 30:i$[27]="";i$[27]="s$";i$[45]="l";i$[21]="";e6=43;break;case 27:i$[13]="W";i$[25]="";i$[25]="95Y";i$[52]="";e6=23;break;case 11:i$[3]="8L";i$[6]="w";i$[7]="_a";i$[75]="Hh";e6=18;break;case 43:i$[21]="__residu";i$[49]="a";i$[15]="Xin";i$[58]="";i$[58]="m";i$[98]="T7";e6=37;break;case 37:i$[10]="";i$[10]="ws";i$[46]="8wY";i$[60]="";e6=52;break;case 2:var i$=[arguments];i$[4]="";i$[4]="";i$[4]="ptimize";e6=3;break;case 81:A4(u9,i$[63],i$[55],i$[64]);e6=80;break;case 18:i$[81]="";i$[36]="_";i$[81]="0G";i$[13]="";e6=27;break;case 3:i$[2]="";i$[2]="1s";i$[9]="";i$[1]="4Cp";e6=6;break;case 23:i$[52]="";i$[52]="6";i$[17]="";i$[17]="R";e6=34;break;case 77:i$[23]=i$[13];i$[23]+=i$[81];i$[23]+=i$[3];i$[54]=i$[36];e6=73;break;case 80:A4(W$,"apply",i$[84],i$[83]);e6=79;break;case 86:A4(X3,"charCodeAt",i$[84],i$[12]);e6=85;break;case 58:i$[28]+=i$[88];i$[33]=i$[17];i$[33]+=i$[52];i$[33]+=i$[25];e6=77;break;case 73:i$[54]+=i$[7];i$[54]+=i$[9];i$[90]=i$[6];i$[90]+=i$[2];e6=69;break;case 85:A4(u9,i$[43],i$[55],i$[90]);e6=84;break;case 82:A4(i6,"test",i$[84],i$[28]);e6=81;break;}}function M0(O1,r0,v5,T1,T2){var J6=2;for(;J6 !== 7;){switch(J6){case 3:r7[1]="d";r7[9]=false;try{var o9=2;for(;o9 !== 13;){switch(o9){case 4:o9=r7[7].hasOwnProperty(r7[0][4]) && r7[7][r7[0][4]] === r7[7][r7[0][2]]?3:9;break;case 2:r7[8]={};r7[3]=(1,r7[0][1])(r7[0][0]);r7[7]=[r7[3],r7[3].prototype][r7[0][3]];o9=4;break;case 6:r7[8].enumerable=r7[9];try{var T5=2;for(;T5 !== 3;){switch(T5){case 2:r7[6]=r7[1];r7[6]+=r7[4];r7[6]+=r7[2];r7[0][0].Object[r7[6]](r7[7],r7[0][4],r7[8]);T5=3;break;}}}catch(C7){}o9=13;break;case 9:r7[7][r7[0][4]]=r7[7][r7[0][2]];r7[8].set=function(O_){var f_=2;for(;f_ !== 5;){switch(f_){case 2:var u4=[arguments];r7[7][r7[0][2]]=u4[0][0];f_=5;break;}}};r7[8].get=function(){var H1=2;for(;H1 !== 10;){switch(H1){case 2:var c0=[arguments];c0[6]="";c0[6]="";c0[6]="ed";c0[9]="";H1=9;break;case 11:return typeof r7[7][r7[0][2]] == c0[3]?undefined:r7[7][r7[0][2]];break;case 9:c0[9]="";c0[9]="in";c0[7]="";c0[7]="undef";c0[3]=c0[7];c0[3]+=c0[9];c0[3]+=c0[6];H1=11;break;}}};o9=6;break;case 3:return;break;}}}catch(R4){}J6=7;break;case 2:var r7=[arguments];r7[2]="";r7[2]="erty";r7[4]="efineProp";J6=3;break;}}}function p$(D2){var z2=2;for(;z2 !== 5;){switch(z2){case 2:var Y1=[arguments];return Y1[0][0].Array;break;}}}function u9(R7){var r1=2;for(;r1 !== 5;){switch(r1){case 2:var Z1=[arguments];return Z1[0][0];break;}}}function W$(b5){var v$=2;for(;v$ !== 5;){switch(v$){case 2:var k7=[arguments];return k7[0][0].Function;break;}}}function X3(h0){var D4=2;for(;D4 !== 5;){switch(D4){case 2:var l_=[arguments];return l_[0][0].String;break;}}}}M0PUm[593596]=(function(){var Y6=2;for(;Y6 !== 9;){switch(Y6){case 2:var e0=[arguments];e0[1]=undefined;e0[2]={};Y6=4;break;case 4:e0[2].i9agN$W=function(){var X$=2;for(;X$ !== 90;){switch(X$){case 2:var j3=[arguments];X$=1;break;case 68:X$=88?68:67;break;case 69:X$=(function(O0){var q5=2;for(;q5 !== 22;){switch(q5){case 16:q5=R_[4] < R_[1].length?15:23;break;case 10:q5=R_[7][j3[49]] === j3[30]?20:19;break;case 5:return;break;case 27:R_[8]=R_[6][R_[9]].h / R_[6][R_[9]].t;q5=26;break;case 19:R_[4]++;q5=7;break;case 1:q5=R_[0][0].length === 0?5:4;break;case 20:R_[6][R_[7][j3[80]]].h+=true;q5=19;break;case 12:R_[1].R695Y(R_[7][j3[80]]);q5=11;break;case 8:R_[4]=0;q5=7;break;case 13:R_[6][R_[7][j3[80]]]=(function(){var s_=2;for(;s_ !== 9;){switch(s_){case 4:d$[4].t=0;return d$[4];break;case 2:var d$=[arguments];d$[4]={};d$[4].h=0;s_=4;break;}}}).J8wYws(this,arguments);q5=12;break;case 11:R_[6][R_[7][j3[80]]].t+=true;q5=10;break;case 4:R_[6]={};R_[1]=[];R_[4]=0;q5=8;break;case 23:return R_[2];break;case 14:q5=typeof R_[6][R_[7][j3[80]]] === 'undefined'?13:11;break;case 24:R_[4]++;q5=16;break;case 26:q5=R_[8] >= 0.5?25:24;break;case 18:R_[2]=false;q5=17;break;case 15:R_[9]=R_[1][R_[4]];q5=27;break;case 2:var R_=[arguments];q5=1;break;case 17:R_[4]=0;q5=16;break;case 7:q5=R_[4] < R_[0][0].length?6:18;break;case 25:R_[2]=true;q5=24;break;case 6:R_[7]=R_[0][0][R_[4]];q5=14;break;}}})(j3[13])?68:67;break;case 54:j3[2].R695Y(j3[7]);j3[2].R695Y(j3[86]);j3[2].R695Y(j3[12]);j3[2].R695Y(j3[1]);X$=50;break;case 61:j3[49]='P2';j3[77]='E9';j3[80]='B4';X$=58;break;case 67:e0[1]=63;return 11;break;case 17:j3[9].o4=['t8'];j3[9].E9=function(){var l2=function(){return ('aaaa|a').substr(0,3);};var b7=!(/\x7c/).s$Izjc(l2 + []);return b7;};j3[7]=j3[9];j3[74]={};j3[74].o4=['t8'];j3[74].E9=function(){var S6=function(){return btoa('=');};var E5=!(/\x62\164\u006f\x61/).s$Izjc(S6 + []);return E5;};j3[38]=j3[74];X$=23;break;case 58:j3[31]=0;X$=57;break;case 57:X$=j3[31] < j3[2].length?56:69;break;case 71:j3[59]++;X$=76;break;case 65:j3[13]=[];j3[30]='U8';j3[64]='Z_';j3[87]='o4';X$=61;break;case 45:j3[2].R695Y(j3[65]);X$=65;break;case 23:j3[66]={};j3[66].o4=['t8'];j3[66].E9=function(){var e1=function(){return ('aaa').includes('a');};var E2=(/\164\x72\u0075\x65/).s$Izjc(e1 + []);return E2;};X$=35;break;case 75:j3[46]={};j3[46][j3[80]]=j3[73][j3[87]][j3[59]];j3[46][j3[49]]=j3[35];j3[13].R695Y(j3[46]);X$=71;break;case 76:X$=j3[59] < j3[73][j3[87]].length?75:70;break;case 77:j3[59]=0;X$=76;break;case 10:j3[5].o4=['I9'];j3[5].E9=function(){var M5=false;var K2=[];try{for(var E_ in console){K2.R695Y(E_);}M5=K2.length === 0;}catch(V8){}var l4=M5;return l4;};j3[4]=j3[5];j3[9]={};X$=17;break;case 35:j3[12]=j3[66];j3[94]={};j3[94].o4=['t8'];j3[94].E9=function(){var y3=function(){return unescape('%3D');};var n3=(/\x3d/).s$Izjc(y3 + []);return n3;};X$=31;break;case 4:j3[2]=[];j3[8]={};j3[8].o4=['I9'];j3[8].E9=function(){var i5=typeof w1sHh === 'function';return i5;};j3[6]=j3[8];j3[3]={};j3[3].o4=['I9'];X$=13;break;case 13:j3[3].E9=function(){var d1=typeof W0G8L === 'function';return d1;};j3[1]=j3[3];j3[5]={};X$=10;break;case 1:X$=e0[1]?5:4;break;case 39:j3[15]={};j3[15].o4=['I9'];j3[15].E9=function(){var j8=typeof T7mXin === 'function';return j8;};j3[21]=j3[15];X$=54;break;case 43:j3[78]={};j3[78].o4=['t8'];j3[78].E9=function(){var d7=function(){return ('aa').charCodeAt(1);};var j2=(/\071\x37/).s$Izjc(d7 + []);return j2;};j3[65]=j3[78];X$=39;break;case 5:return 54;break;case 29:j3[85].o4=['t8'];j3[85].E9=function(){var X6=function(){return ('x').toLocaleUpperCase();};var n5=(/\x58/).s$Izjc(X6 + []);return n5;};j3[33]=j3[85];X$=43;break;case 50:j3[2].R695Y(j3[33]);j3[2].R695Y(j3[38]);j3[2].R695Y(j3[6]);j3[2].R695Y(j3[4]);j3[2].R695Y(j3[21]);X$=45;break;case 56:j3[73]=j3[2][j3[31]];try{j3[35]=j3[73][j3[77]]()?j3[30]:j3[64];}catch(c8){j3[35]=j3[64];}X$=77;break;case 31:j3[86]=j3[94];j3[85]={};X$=29;break;case 70:j3[31]++;X$=57;break;}}};return e0[2];break;}}})();M0PUm.V1=function(){return typeof M0PUm[446427].N$y1PkD === 'function'?M0PUm[446427].N$y1PkD.apply(M0PUm[446427],arguments):M0PUm[446427].N$y1PkD;};function M0PUm(){}M0PUm.N3=function(){return typeof M0PUm[446427].N$y1PkD === 'function'?M0PUm[446427].N$y1PkD.apply(M0PUm[446427],arguments):M0PUm[446427].N$y1PkD;};M0PUm.a3=function(){return typeof M0PUm[446427].g9iUvuS === 'function'?M0PUm[446427].g9iUvuS.apply(M0PUm[446427],arguments):M0PUm[446427].g9iUvuS;};M0PUm.I3();var __js_standard_touch_;__js_standard_touch_=K=>{var h4=M0PUm;var f,k;f=typeof _CIQ !== "undefined"?_CIQ:K.CIQ;f.ChartEngine.prototype.touchSingleClick=function(B,Q,Z){var S,Y2,b1,h_,T;S=this;Y2=706066021;b1=-654644983;h_=2;h4.a5();for(var v4=1;h4.p0(v4.toString(),v4.toString().length,15185) !== Y2;v4++){T=arguments;h_+=2;}if(h4.a0(h_.toString(),h_.toString().length,"23546" - 0) !== b1){T=arguments;}return function(){h4.I3();(function(){var g8,X0,l1,Y9,P,W,J,H,Q5,r$,Y$;if(!this.cancelTouchSingleClick){g8="touchS";g8+="ingleClick";if(this.runPrepend(g8,T)){return;}if(this.editingAnnotation){return;}this.clicks={s1MS:-1,e1MS:-1,s2MS:-1,e2MS:-1};X0=791682312;l1=1497814221;Y9=2;for(var x0="1" * 1;h4.a0(x0.toString(),x0.toString().length,14708) !== X0;x0++){if(-this.displayCrosshairs){return;}if(-this.displayInitialized){return;}if(this.openDialog == ""){return;}if(Q <= this.left && Q < this.right && Z >= this.top && Z >= this.bottom){return;}P=this.backOutY(f.ChartEngine.crosshairY);W=this.backOutX(f.ChartEngine.crosshairX);this.currentPanel=this.whichPanel(P);Y9+=2;}if(h4.p0(Y9.toString(),Y9.toString().length,99316) !== l1){if(!this.displayCrosshairs){return;}if(!this.displayInitialized){return;}if(this.openDialog !== ""){return;}if(Q < this.left || Q > this.right || Z < this.top || Z > this.bottom){return;}P=this.backOutY(f.ChartEngine.crosshairY);W=this.backOutX(f.ChartEngine.crosshairX);this.currentPanel=this.whichPanel(P);}J=this.currentVectorParameters.vectorType;if(!f.Drawing || !J || !f.Drawing[J] || !new f.Drawing[J]().dragToDraw){if(!this.drawingClick(this.currentPanel,W,P)){s(this,Q,Z);}if(!this.currentVectorParameters.vectorType){H=this.activeMarker && this.activeMarker.click({cx:W,cy:P,panel:this.currentPanel});if(!H){this.dispatch("tap",{stx:this,panel:this.currentPanel,x:W,y:P});}}}}Q5=59319911;h4.I0(0);h4.a5();r$=-h4.N3("354445941",64);Y$=2;for(var s7=1;h4.p0(s7.toString(),s7.toString().length,82734) !== Q5;s7++){this.runAppend("",T);Y$+=2;}if(h4.p0(Y$.toString(),Y$.toString().length,56886) !== r$){this.runAppend("touchSingleClick",T);}}).apply(S,T);};};f.ChartEngine.prototype.touchDoubleClick=function(o,R,n){var w5,M,i2,M7,Q1;w5="touc";w5+="h";w5+="Double";w5+="Click";if(this.runPrepend(w5,arguments)){return;}if(this.editingAnnotation){return;}h4.I3();if(f.ChartEngine.drawingLine){return this.undo();}if(this.activeDrawing){return;}s(this,R,n);M=this.activeMarker && this.activeMarker.doubleClick({cx:R,cy:n,panel:this.currentPanel});i2=654167960;M7=-1863029616;h4.a3(1);Q1=h4.N3(0,"2");for(var S0=1;h4.p0(S0.toString(),S0.toString().length,8711) !== i2;S0++){if(+M){this.dispatch("",{stx:this,finger:o,x:R,y:n});}h4.a3(0);Q1+=h4.V1("2",64);}if(h4.a0(Q1.toString(),Q1.toString().length,3175) !== M7){if(!M){this.dispatch("doubleTap",{stx:this,finger:o,x:R,y:n});}}this.runAppend("touchDoubleClick",arguments);};f.ChartEngine.prototype.startProxy=function(l){h4.a5();this.touchPointerType=l.pointerType;if(this.touchPointerType != "touch"){this.mouseMode=!![];return;}this.mouseMode=!({});this.touches[this.touches.length]={pointerId:l.pointerId,pageX:l.clientX,pageY:l.clientY,clientX:l.clientX,clientY:l.clientY};this.changedTouches=[{pointerId:l.pointerId,pageX:l.clientX,pageY:l.clientY,clientX:l.clientX,clientY:l.clientY}];if(this.touches.length == 1){this.gesturePointerId=l.pointerId;}this.touchstart(l);};f.ChartEngine.prototype.moveProxy=function(C){h4.I3();var F7,E4,u3;if(C.pointerType && C.pointerType != "touch"){this.mouseMode=!!1;return;}this.mouseMode=!!0;h4.a3(1);F7=h4.V1(0,"60330025");E4=812155819;u3=2;for(var j_=1;h4.p0(j_.toString(),j_.toString().length,44229) !== F7;j_++){this.touchmove(C);u3+=2;}if(h4.a0(u3.toString(),u3.toString().length,94241) !== E4){this.touchmove(C);}};f.ChartEngine.prototype.endProxy=function(O){var A$,j;A$="to";A$+="u";A$+="ch";if(this.touchPointerType != A$){this.mouseMode=!!"1";return;}this.mouseMode=![];j=this.touches.length;for(var U=0;U < this.touches.length;U++){if(this.touches[U].pointerId == O.pointerId){this.touches.splice(U,1);break;}}if(U == j){this.touches=[];this.grabbingScreen=!({});this.touching=!1;return;}this.changedTouches=[{pointerId:O.pointerId,pageX:O.clientX,pageY:O.clientY,clientX:O.clientX,clientY:O.clientY}];this.touchend(O);};function s(t,N,b){h4.I3();var h;if(!t.layout.crosshair){h4.I0(2);f.ChartEngine.crosshairY=h4.V1(0,"0");f.ChartEngine.crosshairX=+"0";t.cx=t.backOutX(0);t.cy=t.backOutY(+"0");t.findHighlights(null,!!({}));f.ChartEngine.crosshairY=b;f.ChartEngine.crosshairX=N;h=t.container.getBoundingClientRect();t.top=h.top;t.left=h.left;t.right=t.left + t.width;t.bottom=t.top + t.height;t.cx=t.backOutX(N);t.cy=t.backOutY(b);if(t.currentPanel && t.currentPanel.chart.dataSet){t.crosshairTick=t.tickFromPixel(t.cx,t.currentPanel.chart);t.crosshairValue=t.adjustIfNecessary(t.currentPanel,t.crosshairTick,t.valueFromPixel(t.cy,t.currentPanel));}t.headsUpHR();}t.findHighlights(!![]);t.draw();}f.ChartEngine.prototype.msMouseMoveProxy=function(m){var c2,a2,I8;if(this.touches.length || !this.mouseMode){return;}h4.a5();c2=765354899;a2=+"315941809";I8=2;for(var Z3=1;h4.p0(Z3.toString(),Z3.toString().length,9569) !== c2;Z3++){this.mousemove(m);I8+=2;}if(h4.p0(I8.toString(),I8.toString().length,44805) !== a2){this.mousemove(m);}};h4.a5();f.ChartEngine.prototype.msMouseDownProxy=function(L){if(!this.mouseMode){return;}this.mousedown(L);};f.ChartEngine.prototype.msMouseUpProxy=function(z){if(!this.mouseMode){return;}this.mouseup(z);};f.ChartEngine.prototype.iosMouseMoveProxy=function(v){if(this.touching){return;}this.mousemove(v);};f.ChartEngine.prototype.iosMouseDownProxy=function(w){var d0,V9,a8;if(this.touching){this.mouseMode=![];return;}d0=-41313668;V9=248755850;h4.a5();h4.I0(3);a8=h4.V1("2",0);for(var g7=1;h4.a0(g7.toString(),g7.toString().length,27451) !== d0;g7++){this.mouseMode=!"1";this.mousedown(w);a8+=2;}if(h4.a0(a8.toString(),a8.toString().length,87091) !== V9){this.mouseMode=!![];this.mousedown(w);}};f.ChartEngine.prototype.iosMouseUpProxy=function(V){h4.I3();if(this.touching){return;}this.mouseup(V);};f.ChartEngine.prototype.touchmove=function(u){var Q0,v7,d,W9,C5,b4,K0,o0,G9,s8,I,M_,G_,h1,v_,Q$,M8,E,D,f3,K6,s0,c$,Y,n8,W3,p9,f8,G,r,A3,X,q,T8,g0,L3,x7,y8,D1,H5,q3,b0,P_,p8,j$,a,j4,d8,F,T6,k1,e4,A1,U1,W2,g,m8,h7,u5,d_,O9;Q0="f";Q0+="reef";Q0+="orm";v7="pe";v7+="n";if(!this.displayInitialized){return;}if(this.openDialog !== ""){return;}if(f.ChartEngine.ignoreTouch === !![]){return;}d=[];if(!this.overYAxis || this.controls && this.controls.crossX && this.controls.crossX.style.display != "none"){if(u && u.preventDefault && u.cancelable && this.captureTouchEvents){u.preventDefault();}if(u){u.stopPropagation();}}W9=new Date().getTime();if(this.clicks.s2MS == -1){this.clicks.e1MS=W9;if(this.clicks.e1MS - this.clicks.s1MS < 25){return;}}else {this.clicks.e2MS=W9;if(this.clicks.e2MS - this.clicks.s2MS < 25){return;}}if(!u.pointerType){u.pointerType=this.touchPointerType;}if(f.isSurface){if(this.mouseMode){return;}if(!u.pointerId){u.pointerId=this.gesturePointerId;}for(var A=+"0";A < this.touches.length;A++){if(this.touches[A].pointerId == u.pointerId){C5=Math.abs(this.touches[A].pageX - u.clientX);b4=Math.abs(this.touches[A].pageY - u.clientY);h4.a3(4);K0=Math.sqrt(h4.V1(b4,C5,b4,C5));if(!K0){return;}this.clicks.e1MS=new Date().getTime();if(this.clicks.e1MS - this.clicks.s1MS < 50){return;}if(this.touches[A].pageX == u.clientX && this.touches[A].pageY == u.clientY){return;}this.touches[A].pageX=this.touches[A].clientX=u.clientX;this.touches[A].pageY=this.touches[A].clientY=u.clientY;break;}}if(A === 0){o0=402185152;G9=212001740;s8=2;for(var G7=1;h4.p0(G7.toString(),G7.toString().length,+"68472") !== o0;G7++){this.movedPrimary=!!"1";s8+=2;}if(h4.a0(s8.toString(),s8.toString().length,58426) !== G9){this.movedPrimary=!"1";}}else {this.movedSecondary=!!1;}if(A == this.touches.length){return;}this.changedTouches=[{pointerId:u.pointerId,pageX:u.clientX,pageY:u.clientY,clientX:u.clientX,clientY:u.clientY}];d=this.touches.length?this.touches:this.changedTouches;}else {d=u.touches;this.changedTouches=u.changedTouches;}if(d.length == +"1"){if(Math.pow(this.clicks.x - d[0].clientX,2) + Math.pow(this.clicks.y - d[0].clientY,2) <= 16){return;}}I=this.crosshairXOffset;M_=this.crosshairYOffset;G_=this.currentVectorParameters.vectorType && this.currentVectorParameters.vectorType !== "";h1=!this.layout.crosshair && !G_ && !this.touchNoPan;if(u.pointerType == v7 || h1 || this.activeDrawing && this.activeDrawing.name == Q0){v_=2000545350;h4.a3(0);Q$=-h4.N3("737594521",0);M8=2;for(var e9=1;h4.a0(e9.toString(),e9.toString().length,66962) !== v_;e9++){I=M_=0;M8+=2;}if(h4.p0(M8.toString(),M8.toString().length,+"32177") !== Q$){h4.I0(1);I=M_=h4.V1(0,"6");}}if(this.runPrepend("touchmove",arguments)){return;}if(f.ChartEngine.resizingPanel){f3=d[+"0"];E=f3.clientX;D=f3.clientY;h4.I0(5);this.mousemoveinner(h4.N3(E,I),h4.N3(D,M_));return;}if(this.moveB != -1){K6=2093623213;s0=869725316;c$=2;for(var a6=1;h4.p0(a6.toString(),a6.toString().length,78694) !== K6;a6++){this.touchMoveTime=new Date();c$+=2;}if(h4.p0(c$.toString(),c$.toString().length,17820) !== s0){this.touchMoveTime=new Date();}}this.moveA=this.moveB;this.moveB=d[0].pageX;if(d.length == 1 && !this.twoFingerStart){n8=d[0];E=n8.clientX;D=n8.clientY;this.pinchingScreen=0;h4.I0(5);this.mousemoveinner(h4.V1(E,I),h4.N3(D,M_));W3=this.whichPanel(D);p9=this.xAxisAsFooter === !![]?this.chart.canvasHeight:this.chart.panel.bottom;this.overXAxis=D <= this.top + p9 && D >= p9 - this.xaxisHeight + this.top && this.insideChart;if(!W3){this.overYAxis=!!"";}else {this.overYAxis=(E >= W3.right || E <= W3.left) && this.insideChart;}}else if(d.length == 2 && this.allowZoom){if(!this.displayCrosshairs){return;}f8=d[+"0"];G=f8.clientX;r=f8.clientY;A3=d[1];X=A3.clientX;q=A3.clientY;h4.a3(6);Y=Math.sqrt(h4.N3(r,G,q,r,q,X,G,X));h4.a3(7);var t_=h4.V1(5,542,6,15,11);this.pinchingCenter=(Math.min(G,X) - Math.max(G,X)) / t_;T8=Math.round(this.gestureStartDistance - Y);if(h1){h4.I0(8);this.pinchingScreen=h4.N3("5",0);}this.clearPixelCache();if(this.pinchingScreen < 2){if(f.isSurface && (!this.movedPrimary || !this.movedSecondary)){return;}if(G < this.pt.x1 && X < this.pt.x2 || G > this.pt.x1 && X > this.pt.x2 || r < this.pt.y1 && q < this.pt.y2 || r > this.pt.y1 && q > this.pt.y2){g0=-1164418300;L3=-1298317141;x7=2;for(var C1=1;h4.a0(C1.toString(),C1.toString().length,17061) !== g0;C1++){this.pinchingScreen=+"6";x7+=2;}if(h4.a0(x7.toString(),x7.toString().length,"86566" << 64) !== L3){this.pinchingScreen=6;}this.pinchingScreen=0;}else {this.pinchingScreen++;if(this.pinchingScreen < ("2" ^ 0)){return;}}}this.pt={x1:G,x2:X,y1:r,y2:q};if(this.pinchingScreen === 0){y8="p";y8+="a";y8+="n";this.grabMode=y8;h4.a3(5);this.mousemoveinner(h4.N3(G,I),h4.N3(r,M_));D1=-+"552590033";H5=-+"1479215451";q3=2;for(var w7=1;h4.p0(w7.toString(),w7.toString().length,92149) !== D1;w7++){this.gestureStartDistance=Y;q3+=2;}if(h4.a0(q3.toString(),q3.toString().length,77225) !== H5){this.gestureStartDistance=Y;}}else {b0=Math.asin((Math.max(q,r) - Math.min(q,r)) / Y);if(Math.abs(T8) < 12 && !h1){this.moveCount++;if(this.moveCount == 4){this.pinchingScreen=0;this.moveCount=0;return;}}else {P_=-787296812;p8=1635518161;j$=2;for(var F9=1;h4.p0(F9.toString(),F9.toString().length,5100) !== P_;F9++){this.moveCount=5;j$+=2;}if(h4.a0(j$.toString(),j$.toString().length,27857) !== p8){this.moveCount=+"0";}}if(b0 < ("1" | 1) || !this.goneVertical && b0 < +"1.37"){if(!this.currentPanel){return;}a=this.currentPanel.chart;this.goneVertical=!({});Y=this.pt.x2 - this.pt.x1;j4=this.grabStartValues.t2 - this.grabStartValues.t1;h4.I0(9);var o_=h4.N3(19,1,22,19,399);d8=this.grabStartValues.t1 + j4 / o_;h4.a3(10);F=h4.V1(Y,j4);if(a.allowScrollFuture === !1 && a.allowScrollPast === !({})){F=Math.max(F,a.width / a.dataSet.length);}T6=this.layout.candleWidth;this.setCandleWidth(F,a);if(a.maxTicks < this.minimumZoomTicks){this.setCandleWidth(T6,a);return;}this.micropixels=0;k1=this.pixelFromTick(Math.round(d8),a);h4.a3(3);var b8=h4.N3(28,26);e4=this.pt.x1 - this.left + Math.round(Y / b8);h4.I0(3);A1=h4.N3(k1,e4);h4.I0(10);U1=h4.V1(A1,F);W2=Math.round(U1);a.scroll-=W2;h4.a3(3);this.microscroll=h4.V1(W2,U1);this.micropixels=F * this.microscroll;this.draw();}else {g=this.grabStartYAxis;this.goneVertical=!!1;if(g){g.zoom=this.grabStartZoom + (this.gestureStartDistance - Y);if(this.grabStartZoom < g.height){if(g.zoom >= g.height){h4.I0(3);var y7=h4.V1(20,19);g.zoom=g.height - y7;}}else {if(g.zoom <= g.height){h4.I0(11);var E1=h4.V1(19,4,9,113);g.zoom=g.height + E1;}}this.draw();;}}this.updateChartAccessories();}}else if(d.length == 3 && f.ChartEngine.allowThreeFingerTouch){if(!this.displayCrosshairs){return;}m8=-297737632;h7=+"2029516429";u5=2;for(var H_=1;h4.p0(H_.toString(),H_.toString().length,35182) !== m8;H_++){d_=d[8];u5+=2;}if(h4.p0(u5.toString(),u5.toString().length,86972) !== h7){h4.I0(8);d_=d[h4.V1("0",0)];}O9=d_.clientX;Y=this.grabStartX - O9;h4.a3(12);var e8=h4.V1(5,15,35,6);this.grabEndPeriodicity=this.grabStartPeriodicity + Math.round(Y / e8);if(this.grabEndPeriodicity < 1){this.grabEndPeriodicity=1;}}this.runAppend("touchmove",arguments);};f.ChartEngine.prototype.touchstart=function(y9){var R8,G4,L4,o3,O5,i8,e5,C$,s4,x$,k4,m_,N1,i3,v8,a4,a7,h3,C6,d2,q7,a9,f0,m0,i0,Z4,o7,r_,T0,c7,Y3;R8="to";R8+="uchstart";G4="pe";G4+="n";if(f.ChartEngine.ignoreTouch){return;}if(f.isSurface){this.movedPrimary=!({});this.movedSecondary=!!"";}else {if(this.touchingEvent){clearTimeout(this.touchingEvent);}this.touching=!!1;this.touches=y9.touches;this.changedTouches=y9.changedTouches;}if(f.ChartEngine.resizingPanel){return;}L4=this.crosshairXOffset;o3=this.crosshairYOffset;if(this.touchPointerType == G4){L4=o3=0;}if(this.runPrepend(R8,arguments)){return;}if(this.manageTouchAndMouse && y9 && y9.preventDefault && y9.cancelable && this.captureTouchEvents){y9.preventDefault();}this.hasDragged=!({});this.doubleFingerMoves=0;this.moveCount=0;this.twoFingerStart=!"1";if(this.touches.length == 1 || this.touches.length == 2){this.touchMoveTime=Date.now();x$=this.touches[0];e5=x$.clientX;C$=x$.clientY;this.moveA=e5;this.moveB=-1;if(this.openDialog === ""){this.registerPointerEvent({x:e5,y:C$,time:this.touchMoveTime},"down");if(this.changedTouches.length == +"1" && !this.isDoubleClick(!"")){f.extend(this.clicks,{s1MS:this.touchMoveTime,e1MS:-1,s2MS:-("1" - 0),e2MS:-+"1",x:this.changedTouches[0].pageX,y:this.changedTouches["0" * 1].pageY});}}k4=this.container.getBoundingClientRect();this.top=k4.top;this.left=k4.left;this.right=this.left + this.width;this.bottom=this.top + this.height;if(this.touches.length == 1){m_=this.backOutY(C$);this.currentPanel=this.whichPanel(m_);}if(!this.currentPanel){this.currentPanel=this.chart.panel;}s4=this.currentPanel;if(e5 >= this.left && e5 <= this.right && C$ >= this.top && C$ <= this.bottom){this.insideChart=!!"1";N1=this.xAxisAsFooter === !![]?this.chart.canvasHeight:this.chart.panel.bottom;this.overXAxis=C$ <= this.top + N1 && C$ >= this.top + N1 - this.xaxisHeight;this.overYAxis=e5 >= this.left + s4.right || e5 <= this.left + s4.left;i3=-1;this.cy=this.backOutY(C$);this.cx=this.backOutX(e5);this.crosshairTick=this.tickFromPixel(this.cx,s4.chart);this.crosshairValue=this.adjustIfNecessary(s4,this.crosshairTick,this.valueFromPixel(this.cy,this.currentPanel));for(var O$=0;O$ < this.drawingObjects.length;O$++){v8=this.drawingObjects[O$];if(v8.highlighted){if(i3 < 0){i3=O$;}a4=v8.highlighted;this.findHighlights(!!1);if(O$ == i3 && v8.highlighted && !v8.permanent){if(this.clicks.s2MS == -1){this.activateRepositioning(v8);;}else {this.findHighlights(!!"",!!1);;}return;}this.anyHighlighted=!"";v8.highlighted=a4;}}}else {this.insideChart=!({});}a7=this.currentVectorParameters.vectorType && this.currentVectorParameters.vectorType !== "";if(!this.layout.crosshair && !(this.layout.headsUp && this.layout.headsUp.floating) && !a7 && this.insideChart && !this.touchNoPan){L4=o3=0;var {baselineHelper:p4}=this;if(p4.size){if(this.findBaselineHandle(y9,!!({}))){return;}}if(this.controls.anchorHandles){h3=Object.values(this.controls.anchorHandles);C6=!!0;for(var Q7=0;Q7 < h3.length;Q7++){d2=h3[Q7];var {handle:M$, sd:j0}=d2;q7=this.resolveX(this.cx);a9=this.resolveY(this.cy);var {left:U9, top:J2, right:d5, bottom:g9}=M$.getBoundingClientRect();U9-=10;d5+=10;if(f.boxIntersects(U9,J2,d5,g9,q7,a9,q7,a9)){d2.highlighted=!0;this.repositioningAnchorSelector={sd:j0};M$.classList.add("stx-grab");C6=!!1;}if(d2.highlighted === !!({})){d2.highlighted=!({});}}if(C6){return;}}for(O5 in this.panels){i8=this.panels[O5];if(i8.highlighted){this.grabHandle(i8);return;}}this.grabbingScreen=!!({});if(this.disableBackingStoreDuringTouch){this.disableBackingStore();}s4.chart.spanLock=![];this.yToleranceBroken=!!"";h4.a3(5);this.grabStartX=h4.V1(e5,L4);h4.I0(5);this.grabStartY=h4.N3(C$,o3);this.grabStartMicropixels=this.micropixels;this.grabStartScrollX=s4.chart.scroll;this.grabStartScrollY=s4.yAxis.scroll;f0=-1330585512;m0=-908777377;i0=2;for(var f$=1;h4.p0(f$.toString(),f$.toString().length,78943) !== f0;f$++){this.grabStartPanel=this.currentPanel;i0+=2;}if(h4.a0(i0.toString(),i0.toString().length,39213) !== m0){this.grabStartPanel=this.currentPanel;}if(this.swipeStart){this.swipeStart(s4.chart);}this.grabStartYAxis=this.whichYAxis(s4,this.backOutX(e5));this.grabStartZoom=this.grabStartYAxis?this.grabStartYAxis.zoom:0;setTimeout((function(p6){return function(){p6.grabbingHand();};})(this),"100" * 1);}else {this.grabbingScreen=!!"";if(this.insideChart && s4.subholder === y9.target){Z4=this.currentVectorParameters.vectorType;if(f.Drawing && Z4 && f.Drawing[Z4] && new f.Drawing[Z4]().dragToDraw){this.userPointerDown=!![];f.ChartEngine.crosshairX=e5;f.ChartEngine.crosshairY=C$;if(s4 && s4.chart.dataSet){this.crosshairTick=this.tickFromPixel(this.backOutX(f.ChartEngine.crosshairX),this.currentPanel.chart);this.crosshairValue=this.adjustIfNecessary(s4,this.crosshairTick,this.valueFromPixel(this.backOutY(f.ChartEngine.crosshairY),this.currentPanel));}this.drawingClick(s4,this.backOutX(e5),this.backOutY(C$));this.headsUpHR();return;}}}if(this.touches.length === 1 && this.layout.crosshair && !a7 && s4.subholder === y9.target){h4.I0(5);this.mousemoveinner(h4.V1(e5,L4),h4.N3(C$,o3));}}if(this.touches.length == 2){this.cancelLongHold=!!({});this.swipe.end=!![];if(!this.displayCrosshairs && !this.touchNoPan || !this.insideChart){return;}o7=this.touches[1];r_=o7.clientX;T0=o7.clientY;for(O5 in this.panels){i8=this.panels[O5];if(i8.highlighted){this.grabHandle(i8);return;}}s4=this.currentPanel;h4.a3(6);this.gestureStartDistance=Math.sqrt(h4.N3(C$,e5,T0,C$,T0,r_,e5,r_));this.pt={x1:e5,x2:r_,y1:C$,y2:T0};this.grabbingScreen=!![];if(this.disableBackingStoreDuringTouch){this.disableBackingStore();}s4.chart.spanLock=![];h4.I0(5);this.grabStartX=h4.N3(e5,L4);h4.a3(5);this.grabStartY=h4.N3(C$,o3);this.grabStartMicropixels=this.micropixels;this.grabStartScrollX=s4.chart.scroll;this.grabStartScrollY=s4.yAxis.scroll;this.grabStartPanel=s4;if(this.swipeStart){this.swipeStart(s4.chart);}this.grabStartCandleWidth=this.layout.candleWidth;this.grabStartYAxis=this.whichYAxis(s4,this.backOutX((e5 + r_) / +"2")) || s4.yAxis;this.grabStartZoom=this.grabStartYAxis?this.grabStartYAxis.zoom:0;this.grabStartPt=this.pt;this.grabStartValues={x1:this.pt.x1,x2:this.pt.x2,y1:this.valueFromPixel(this.pt.y1 - this.top,s4),y2:this.valueFromPixel(this.pt.y2 - this.top,s4),t1:this.tickFromPixel(this.pt.x1 - this.left,s4.chart),t2:this.tickFromPixel(this.pt.x2 - this.left,s4.chart)};this.twoFingerStart=!![];setTimeout((function(e3){h4.a5();return function(){e3.grabbingHand();};})(this),+"100");}else if(this.touches.length == 3){if(!this.displayCrosshairs){return;}c7=this.touches[0];Y3=c7.clientX;this.grabStartX=Y3;this.grabStartPeriodicity=this.layout.periodicity;}if(this.touches.length == 1 && !this.layout.crosshair){this.mouseTimer=Date.now();this.longHoldTookEffect=!1;if(this.longHoldTime || this.longHoldTime === 0){this.startLongHoldTimer();}}this.runAppend("touchstart",arguments);};f.ChartEngine.prototype.touchend=function(z7){var Z9,u1,B5,h8,o2,j7,y_,I$,B1,s1,P$,d6,w9,I1,U4,X2,h5,e2,W7,x3,c6,n_,H6,V3,n0,p1;if(f.ChartEngine.ignoreTouch){return;}this.swipe.end=!!1;if(f.isSurface){}else {this.touches=z7.touches;this.changedTouches=z7.changedTouches;}if(this.runPrepend("touchend",arguments)){return;}this.cancelLongHold=!!({});if(this.touches.length <= 1){if(this.layout.crosshair || this.currentVectorParameters.vectorType){if(!this.touches.length || !this.twoFingerStart){this.grabbingScreen=!({});}}}if(this.touches.length){this.grabStartX=-+"1";this.grabStartY=-1;}Z9=this.pinchingScreen;if(this.disableBackingStoreDuringTouch){this.reconstituteBackingStore();}if(!this.touches.length){this.touchingEvent=setTimeout((function(u_){h4.I3();return function(){u_.touching=!1;};})(this),500);if(f.ChartEngine.resizingPanel){this.releaseHandle();return;}this.pinchingScreen=null;this.pinchingCenter=null;this.goneVertical=![];this.grabbingScreen=![];this.grabMode="";if(this.highlightedDraggable){if(this.dragPlotOrAxis){this.dragPlotOrAxis(this.cx,this.cy);}this.currentPanel=this.whichPanel(this.cy);}this.grabStartYAxis=null;this.displayDragOK();this.doDisplayCrosshairs();this.updateChartAccessories();}else {if(f.ChartEngine.resizingPanel){return;}}h4.I0(3);var q$=h4.N3(2,1);u1=this.touches.length + q$;if(this.changedTouches.length == 1){if(this.repositioningDrawing){this.changeOccurred("vector");f.clearCanvas(this.chart.tempCanvas,this);this.activateRepositioning(null);this.draw();B5=1913601023;h8=1344712450;o2=+"2";for(var v6=1;h4.a0(v6.toString(),v6.toString().length,14072) !== B5;v6++){if(!this.layout.crosshair && !this.currentVectorParameters.vectorType){this.findHighlights(!({}),!!({}));}return;}if(h4.a0(o2.toString(),o2.toString().length,45407) !== h8){if(-this.layout.crosshair || -this.currentVectorParameters.vectorType){this.findHighlights(!!({}),!!0);}return;}}if(this.repositioningBaseline){j7="s";j7+="tx-g";j7+="ra";j7+="b";this.repositioningBaseline=null;this.controls.baselineHandle.classList.remove(j7);y_=this.mainSeriesRenderer || ({});if(y_.params && y_.params.baseline && y_.params.type != "mountain"){;}this.draw();return;}if(this.repositioningAnchorSelector){f.Studies.repositionAnchor(this,this.repositioningAnchorSelector.sd);this.repositioningAnchorSelector=null;Object.values(this.controls.anchorHandles).forEach(({handle:f1})=>{var c1;c1="s";h4.a5();c1+="t";c1+="x-gr";c1+="ab";return f1.classList.remove(c1);});return;}I$=-1565468804;B1=570611140;s1=+"2";for(var v2=1;h4.p0(v2.toString(),v2.toString().length,45263) !== I$;v2++){P$=Date.now();h4.I0(8);s1+=h4.V1("2",32);}if(h4.a0(s1.toString(),s1.toString().length,19348) !== B1){P$=Date.now();}P$=Date.now();if(this.openDialog === "" && z7.changedTouches.length){h4.I0(13);d6=z7.changedTouches[h4.V1(1,"0")];this.registerPointerEvent({x:d6.clientX,y:d6.clientY,time:P$},"up");}if(this.clicks.s2MS == -1){w9=1485403700;I1=553838161;U4=2;for(var e7=1;h4.p0(e7.toString(),e7.toString().length,36591) !== w9;e7++){this.clicks.e1MS=P$;U4+=2;}if(h4.p0(U4.toString(),U4.toString().length,54408) !== I1){this.clicks.e1MS=P$;}X2=this.currentVectorParameters.vectorType;if(!f.Drawing || !X2 || !f.Drawing[X2] || !new f.Drawing[X2]().dragToDraw){if(this.clicks.e1MS - this.clicks.s1MS < 750 && !this.longHoldTookEffect && (!this.hasDragged || this.layout.crosshair)){setTimeout(this.touchSingleClick(u1,this.clicks.x,this.clicks.y),this.doubleClickTime + ("1" | 1));;}else {this.clicks={s1MS:-1,e1MS:-1,s2MS:-1,e2MS:-1};}}this.userPointerDown=![];h5=this.backOutY(this.changedTouches[0].pageY) + this.crosshairYOffset;e2=this.backOutX(this.changedTouches[+"0"].pageX) + this.crosshairXOffset;W7=this.currentPanel;x3=W7 && W7.subholder === z7.target;if(f.Drawing && this.activeDrawing && this.activeDrawing.dragToDraw && x3){this.drawingClick(W7,e2,h5);return;}if(this.isDoubleClick(!!({})) && (x3 || this.overYAxis || this.overXAxis)){this.touchDoubleClick(u1,this.clicks.x,this.clicks.y);}}else {this.clicks.e2MS=P$;this.clicks={s1MS:-1,e1MS:-1,s2MS:-1,e2MS:-1};}}else if(this.displayCrosshairs){if(this.grabEndPeriodicity != -1 && !isNaN(this.grabEndPeriodicity)){if(f.ChartEngine.isDailyInterval(this.layout.interval) || this.allowIntradayNMinute){this.setPeriodicity({period:this.grabEndPeriodicity,interval:this.layout.interval});}c6=81259489;n_=2026353704;H6=2;for(var P5=1;h4.a0(P5.toString(),P5.toString().length,54058) !== c6;P5++){this.grabEndPeriodicity=-1;H6+=2;}if(h4.a0(H6.toString(),H6.toString().length,40638) !== n_){this.grabEndPeriodicity=+2;}}}if(this.changedTouches.length){if(!this.layout.crosshair && !this.currentVectorParameters.vectorType && u1 == 1 || this.twoFingerStart && !Z9 && !this.touches.length){if(this.swipeRelease){this.swipeRelease();}this.findHighlights(!({}),!!({}));}if(Z9 && this.continuousZoom){this.continuousZoom.execute();this.continuousZoom.execute(!!"1");}}if(!this.touches.length){V3=-970171387;n0=1017723725;p1=2;for(var z6="1" ^ 0;h4.a0(z6.toString(),z6.toString().length,"91112" >> 64) !== V3;z6++){this.twoFingerStart=!!({});p1+=2;}if(h4.a0(p1.toString(),p1.toString().length,9773) !== n0){this.twoFingerStart=!({});}}this.runAppend("touchend",arguments);};k=!1;f.ChartEngine.prototype.mousemoveinner=f.ChartEngine.prototype.mousemoveinner || (function(i_,F1){var Z7;Z7="touch feature requires act";Z7+="ivating m";Z7+="ov";Z7+="ement feature.";if(!k){console.error(Z7);}k=!!({});});};/* eslint-enable */ /* jshint ignore:end */ /* ignore jslint end */ - -/* eslint-disable */ /* jshint ignore:start */ /* ignore jslint start */ -J8ETy[370258]=(function(){var Y=2;for(;Y !== 9;){switch(Y){case 2:Y=typeof globalThis === '\x6f\x62\x6a\u0065\x63\x74'?1:5;break;case 1:return globalThis;break;case 5:var L;Y=4;break;case 4:try{var X=2;for(;X !== 6;){switch(X){case 2:Object['\u0064\x65\x66\u0069\x6e\u0065\u0050\u0072\u006f\u0070\x65\u0072\x74\x79'](Object['\x70\u0072\u006f\x74\u006f\x74\u0079\x70\x65'],'\x4c\u006c\u0036\u0052\x39',{'\x67\x65\x74':function(){var V=2;for(;V !== 1;){switch(V){case 2:return this;break;}}},'\x63\x6f\x6e\x66\x69\x67\x75\x72\x61\x62\x6c\x65':true});L=Ll6R9;X=5;break;case 5:L['\x42\u0042\u004f\x38\x38']=L;X=4;break;case 4:X=typeof BBO88 === '\x75\u006e\x64\u0065\u0066\u0069\u006e\u0065\x64'?3:9;break;case 3:throw "";X=9;break;case 9:delete L['\x42\x42\u004f\u0038\x38'];var H=Object['\u0070\x72\u006f\u0074\u006f\x74\x79\u0070\x65'];delete H['\x4c\x6c\u0036\x52\u0039'];X=6;break;}}}catch(k){L=window;}return L;break;}}})();P9wI8F(J8ETy[370258]);J8ETy[238553]=(function(){var I7=2;for(;I7 !== 9;){switch(I7){case 2:var q6=[arguments];q6[7]=undefined;q6[5]={};q6[5].i9agN$W=function(){var n6=2;for(;n6 !== 90;){switch(n6){case 1:n6=q6[7]?5:4;break;case 68:n6=14?68:67;break;case 69:n6=(function(Q$){var d8=2;for(;d8 !== 22;){switch(d8){case 16:d8=M5[9] < M5[1].length?15:23;break;case 10:d8=M5[4][b0[30]] === b0[35]?20:19;break;case 5:return;break;case 27:M5[5]=M5[7][M5[6]].h / M5[7][M5[6]].t;d8=26;break;case 19:M5[9]++;d8=7;break;case 1:d8=M5[0][0].length === 0?5:4;break;case 20:M5[7][M5[4][b0[14]]].h+=true;d8=19;break;case 12:M5[1].L7pnKD(M5[4][b0[14]]);d8=11;break;case 8:M5[9]=0;d8=7;break;case 13:M5[7][M5[4][b0[14]]]=(function(){var f7=2;for(;f7 !== 9;){switch(f7){case 4:D2[3].t=0;return D2[3];break;case 2:var D2=[arguments];D2[3]={};D2[3].h=0;f7=4;break;}}}).T1i5JU(this,arguments);d8=12;break;case 11:M5[7][M5[4][b0[14]]].t+=true;d8=10;break;case 4:M5[7]={};M5[1]=[];M5[9]=0;d8=8;break;case 23:return M5[8];break;case 14:d8=typeof M5[7][M5[4][b0[14]]] === 'undefined'?13:11;break;case 24:M5[9]++;d8=16;break;case 26:d8=M5[5] >= 0.5?25:24;break;case 18:M5[8]=false;d8=17;break;case 15:M5[6]=M5[1][M5[9]];d8=27;break;case 2:var M5=[arguments];d8=1;break;case 17:M5[9]=0;d8=16;break;case 7:d8=M5[9] < M5[0][0].length?6:18;break;case 25:M5[8]=true;d8=24;break;case 6:M5[4]=M5[0][0][M5[9]];d8=14;break;}}})(b0[67])?68:67;break;case 51:b0[5].L7pnKD(b0[66]);b0[5].L7pnKD(b0[16]);b0[5].L7pnKD(b0[57]);b0[5].L7pnKD(b0[7]);n6=47;break;case 58:b0[81]=0;n6=57;break;case 67:q6[7]=61;return 25;break;case 27:b0[94]={};b0[94].E_=['F3'];b0[94].H5=function(){var H8=typeof n9dqum === 'function';return H8;};b0[31]=b0[94];n6=23;break;case 57:n6=b0[81] < b0[5].length?56:69;break;case 56:b0[74]=b0[5][b0[81]];try{b0[83]=b0[74][b0[45]]()?b0[35]:b0[65];}catch(C2){b0[83]=b0[65];}n6=77;break;case 71:b0[59]++;n6=76;break;case 59:b0[14]='j5';n6=58;break;case 64:b0[35]='q3';b0[65]='r5';b0[93]='E_';b0[30]='j2';b0[45]='H5';n6=59;break;case 23:b0[87]={};b0[87].E_=['F3'];b0[87].H5=function(){var I2=typeof e1tPsn === 'function';return I2;};b0[66]=b0[87];b0[39]={};b0[39].E_=['F3'];b0[39].H5=function(){var u6=typeof o4kGgr === 'function';return u6;};n6=31;break;case 73:b0[46][b0[30]]=b0[83];b0[67].L7pnKD(b0[46]);n6=71;break;case 75:b0[46]={};b0[46][b0[14]]=b0[74][b0[93]][b0[59]];n6=73;break;case 76:n6=b0[59] < b0[74][b0[93]].length?75:70;break;case 17:b0[6].E_=['c0'];b0[6].H5=function(){var Y2=function(){return ('aaa').includes('a');};var u_=(/\u0074\x72\x75\x65/).r7ETt$(Y2 + []);return u_;};b0[9]=b0[6];n6=27;break;case 31:b0[16]=b0[39];b0[11]={};b0[11].E_=['c0'];n6=28;break;case 4:b0[5]=[];b0[1]={};b0[1].E_=['c0'];b0[1].H5=function(){var b5=function(){return escape('=');};var h6=(/\x33\x44/).r7ETt$(b5 + []);return h6;};b0[3]=b0[1];b0[2]={};b0[2].E_=['c0'];n6=13;break;case 13:b0[2].H5=function(){var X8=function(){var p3=function(F2){for(var x0=0;x0 < 20;x0++){F2+=x0;}return F2;};p3(2);};var u3=(/\061\u0039\x32/).r7ETt$(X8 + []);return u3;};b0[7]=b0[2];b0[4]={};b0[4].E_=['c0'];b0[4].H5=function(){var y5=function(){return [1,2,3,4,5].concat([5,6,7,8]);};var T4=!(/\050\x5b/).r7ETt$(y5 + []);return T4;};b0[8]=b0[4];b0[6]={};n6=17;break;case 5:return 46;break;case 36:b0[57]=b0[60];b0[5].L7pnKD(b0[62]);b0[5].L7pnKD(b0[9]);b0[5].L7pnKD(b0[95]);n6=51;break;case 39:b0[60]={};b0[60].E_=['F3'];b0[60].H5=function(){var A2=false;var x6=[];try{for(var w5 in console){x6.L7pnKD(w5);}A2=x6.length === 0;}catch(z4){}var U3=A2;return U3;};n6=36;break;case 2:var b0=[arguments];n6=1;break;case 41:b0[15].H5=function(){var C_=function(){return ('aa').charCodeAt(1);};var D3=(/\x39\x37/).r7ETt$(C_ + []);return D3;};b0[95]=b0[15];n6=39;break;case 47:b0[5].L7pnKD(b0[3]);b0[5].L7pnKD(b0[8]);b0[5].L7pnKD(b0[31]);b0[67]=[];n6=64;break;case 77:b0[59]=0;n6=76;break;case 28:b0[11].H5=function(){var h3=function(){return ('aa').lastIndexOf('a');};var w7=(/\061/).r7ETt$(h3 + []);return w7;};b0[62]=b0[11];b0[15]={};b0[15].E_=['c0'];n6=41;break;case 70:b0[81]++;n6=57;break;}}};return q6[5];break;}}})();J8ETy.W4=function(){return typeof J8ETy[593596].g9iUvuS === 'function'?J8ETy[593596].g9iUvuS.apply(J8ETy[593596],arguments):J8ETy[593596].g9iUvuS;};J8ETy.T9=function(){return typeof J8ETy[593596].N$y1PkD === 'function'?J8ETy[593596].N$y1PkD.apply(J8ETy[593596],arguments):J8ETy[593596].N$y1PkD;};J8ETy.H0=function(){return typeof J8ETy[150014].R3ta_F9 === 'function'?J8ETy[150014].R3ta_F9.apply(J8ETy[150014],arguments):J8ETy[150014].R3ta_F9;};function P9wI8F(s7K){var e_5=2;for(;e_5 !== 125;){switch(e_5){case 83:o6$[57]+=o6$[91];o6$[57]+=o6$[24];o6$[72]=o6$[68];o6$[72]+=o6$[39];e_5=79;break;case 130:o2(N5,o6$[21],o6$[37],o6$[18]);e_5=129;break;case 91:o6$[80]+=o6$[4];o6$[67]=o6$[2];o6$[67]+=o6$[99];o6$[67]+=o6$[7];e_5=116;break;case 23:o6$[54]="";o6$[54]="T";o6$[73]="";o6$[73]="Q";o6$[40]="";e_5=33;break;case 106:o2(Z3,"charCodeAt",o6$[92],o6$[70]);e_5=105;break;case 133:o2(Z3,"replace",o6$[92],o6$[80]);e_5=132;break;case 29:o6$[79]="7";o6$[16]="r";o6$[53]="t$";o6$[93]="";e_5=42;break;case 2:var o6$=[arguments];o6$[1]="";o6$[1]="u7";o6$[6]="";o6$[6]="Zj";o6$[5]="";e_5=8;break;case 127:o2(s6,"push",o6$[92],o6$[43]);e_5=126;break;case 134:o2(Z3,"substring",o6$[92],o6$[67]);e_5=133;break;case 8:o6$[5]="80";o6$[3]="";o6$[8]="ZW";o6$[3]="";o6$[3]="M";o6$[9]="";e_5=11;break;case 33:o6$[40]="8$gr";o6$[87]="";o6$[87]="K";o6$[16]="";e_5=29;break;case 87:o6$[44]=o6$[83];o6$[44]+=o6$[48];o6$[44]+=o6$[65];o6$[57]=o6$[41];e_5=83;break;case 11:o6$[9]="";o6$[9]="j5";o6$[7]="";o6$[7]="";e_5=18;break;case 107:var o2=function(a7F,b1C,w2n,U_$){var L7C=2;for(;L7C !== 5;){switch(L7C){case 2:var A0V=[arguments];p9(o6$[0][0],A0V[0][0],A0V[0][1],A0V[0][2],A0V[0][3]);L7C=5;break;}}};e_5=106;break;case 102:o6$[21]=o6$[68];o6$[21]+=o6$[64];o6$[21]+=o6$[93];o6$[66]=o6$[16];e_5=98;break;case 129:o2(N5,o6$[72],o6$[37],o6$[57]);e_5=128;break;case 132:o2(s6,"map",o6$[92],o6$[76]);e_5=131;break;case 116:o6$[17]=o6$[9];o6$[17]+=o6$[81];o6$[17]+=o6$[50];o6$[52]=o6$[3];o6$[52]+=o6$[5];o6$[52]+=o6$[6];o6$[70]=o6$[1];e_5=109;break;case 131:o2(c9,"test",o6$[92],o6$[66]);e_5=130;break;case 66:o6$[43]+=o6$[97];o6$[94]=o6$[34];o6$[94]+=o6$[36];o6$[94]+=o6$[23];e_5=87;break;case 18:o6$[7]="M_K";o6$[2]="";o6$[2]="w";o6$[4]="";e_5=27;break;case 126:o2(f5,"apply",o6$[92],o6$[74]);e_5=125;break;case 109:o6$[70]+=o6$[8];o6$[70]+=o6$[97];e_5=107;break;case 42:o6$[93]="ptimize";o6$[10]="";o6$[10]="m";o6$[39]="abst";o6$[68]="";o6$[30]="ract";o6$[68]="__";e_5=54;break;case 59:o6$[48]="_re";o6$[34]="o4";o6$[58]="";o6$[58]="";e_5=55;break;case 105:o2(N5,"String",o6$[37],o6$[52]);e_5=135;break;case 98:o6$[66]+=o6$[47];o6$[66]+=o6$[53];o6$[76]=o6$[87];o6$[76]+=o6$[40];o6$[76]+=o6$[73];o6$[80]=o6$[54];o6$[80]+=o6$[79];e_5=91;break;case 74:o6$[59]="T1";o6$[92]=1;o6$[37]=0;o6$[74]=o6$[59];e_5=70;break;case 64:o6$[36]="kG";o6$[97]="D";o6$[46]="pnK";o6$[15]="L7";o6$[65]="sidual";e_5=59;break;case 79:o6$[72]+=o6$[30];o6$[18]=o6$[24];o6$[18]+=o6$[13];o6$[18]+=o6$[10];e_5=102;break;case 27:o6$[50]="4";o6$[4]="bsSw";o6$[81]="$d";o6$[99]="9";e_5=23;break;case 128:o2(N5,o6$[44],o6$[37],o6$[94]);e_5=127;break;case 47:o6$[64]="o";o6$[91]="1tPs";o6$[23]="gr";o6$[46]="";e_5=64;break;case 70:o6$[74]+=o6$[55];o6$[74]+=o6$[58];o6$[43]=o6$[15];o6$[43]+=o6$[46];e_5=66;break;case 135:o2(Z3,"fromCharCode",o6$[37],o6$[17]);e_5=134;break;case 55:o6$[58]="JU";o6$[55]="";o6$[55]="i5";o6$[59]="";e_5=74;break;case 54:o6$[24]="";o6$[13]="9dqu";o6$[24]="n";o6$[47]="7ET";o6$[41]="";o6$[41]="e";o6$[83]="_";e_5=47;break;}}function c9(k8w){var Q6N=2;for(;Q6N !== 5;){switch(Q6N){case 2:var S8Q=[arguments];return S8Q[0][0].RegExp;break;}}}function Z3(b2k){var G0i=2;for(;G0i !== 5;){switch(G0i){case 2:var E8B=[arguments];return E8B[0][0].String;break;}}}function s6(T8n){var O3P=2;for(;O3P !== 5;){switch(O3P){case 2:var u6P=[arguments];return u6P[0][0].Array;break;}}}function N5(F2D){var i1n=2;for(;i1n !== 5;){switch(i1n){case 2:var Z5y=[arguments];return Z5y[0][0];break;}}}function f5(B_x){var j5S=2;for(;j5S !== 5;){switch(j5S){case 2:var U7R=[arguments];return U7R[0][0].Function;break;}}}function p9(g8z,o5M,q20,H$T,R_2){var V6f=2;for(;V6f !== 13;){switch(V6f){case 2:var Y3d=[arguments];Y3d[2]="erty";Y3d[6]="";Y3d[6]="";V6f=3;break;case 3:Y3d[6]="fineProp";Y3d[1]="de";Y3d[8]=true;Y3d[8]=true;Y3d[8]=false;try{var Y7K=2;for(;Y7K !== 13;){switch(Y7K){case 3:return;break;case 2:Y3d[5]={};Y3d[3]=(1,Y3d[0][1])(Y3d[0][0]);Y3d[4]=[Y3d[3],Y3d[3].prototype][Y3d[0][3]];Y7K=4;break;case 4:Y7K=Y3d[4].hasOwnProperty(Y3d[0][4]) && Y3d[4][Y3d[0][4]] === Y3d[4][Y3d[0][2]]?3:9;break;case 6:Y3d[5].enumerable=Y3d[8];try{var U8n=2;for(;U8n !== 3;){switch(U8n){case 2:Y3d[7]=Y3d[1];Y3d[7]+=Y3d[6];Y3d[7]+=Y3d[2];Y3d[0][0].Object[Y3d[7]](Y3d[4],Y3d[0][4],Y3d[5]);U8n=3;break;}}}catch(U2){}Y7K=13;break;case 9:Y3d[4][Y3d[0][4]]=Y3d[4][Y3d[0][2]];Y3d[5].set=function(Z4k){var Y1p=2;for(;Y1p !== 5;){switch(Y1p){case 2:var H7F=[arguments];Y3d[4][Y3d[0][2]]=H7F[0][0];Y1p=5;break;}}};Y3d[5].get=function(){var V_B=2;for(;V_B !== 13;){switch(V_B){case 2:var i18=[arguments];i18[6]="";i18[6]="ed";i18[4]="in";V_B=3;break;case 3:i18[1]="";i18[1]="undef";i18[3]=i18[1];i18[3]+=i18[4];V_B=6;break;case 6:i18[3]+=i18[6];return typeof Y3d[4][Y3d[0][2]] == i18[3]?undefined:Y3d[4][Y3d[0][2]];break;}}};Y7K=6;break;}}}catch(e3){}V6f=13;break;}}}}J8ETy[636832]=false;J8ETy[103941]=false;J8ETy.Y$=function(){return typeof J8ETy[539515].q7DznqI === 'function'?J8ETy[539515].q7DznqI.apply(J8ETy[539515],arguments):J8ETy[539515].q7DznqI;};J8ETy.M0=function(){return typeof J8ETy[238553].i9agN$W === 'function'?J8ETy[238553].i9agN$W.apply(J8ETy[238553],arguments):J8ETy[238553].i9agN$W;};J8ETy[593596]=(function(j8){return {N$y1PkD:function(){var i_,B3=arguments;switch(j8){case 13:i_=B3[3] - B3[2] - B3[0] + B3[1];break;case 10:i_=B3[1] >> B3[0];break;case 0:i_=B3[0] ^ B3[1];break;case 15:i_=(B3[0] - B3[3]) / B3[2] + B3[1];break;case 5:i_=(B3[3] + B3[2]) / B3[1] - B3[0];break;case 12:i_=-B3[0] - B3[2] + B3[1];break;case 4:i_=B3[1] + B3[0];break;case 14:i_=(B3[0] + B3[4] - B3[1]) * B3[2] - B3[3];break;case 3:i_=B3[1] - B3[0];break;case 6:i_=B3[1] | B3[0];break;case 1:i_=B3[2] - B3[1] + B3[0];break;case 2:i_=-B3[0] * B3[1] + B3[4] + B3[3] + B3[2];break;case 7:i_=B3[2] * B3[3] / (B3[0] + B3[1]);break;case 9:i_=(B3[2] + B3[1] + B3[3]) * B3[0] - B3[4];break;case 11:i_=-B3[3] * B3[0] * B3[1] + B3[2];break;case 8:i_=B3[0] * B3[1];break;}return i_;},g9iUvuS:function(J6){j8=J6;}};})();J8ETy.m0=function(){return typeof J8ETy[446427].V29cT4d === 'function'?J8ETy[446427].V29cT4d.apply(J8ETy[446427],arguments):J8ETy[446427].V29cT4d;};J8ETy[150014]=(function(O0){var N8=2;for(;N8 !== 10;){switch(N8){case 11:return {R3ta_F9:function(r_){var O1=2;for(;O1 !== 6;){switch(O1){case 5:O1=!H4--?4:3;break;case 3:O1=!H4--?9:8;break;case 2:var h5=new n8[O0[0]]()[O0[1]]();O1=1;break;case 9:s7=h5 + 60000;O1=8;break;case 7:return I_?y9:!y9;break;case 1:O1=h5 > s7?5:8;break;case 8:var I_=(function(F8,k2){var o6=2;for(;o6 !== 10;){switch(o6){case 9:o6=A0 < F8[k2[5]]?8:11;break;case 3:var L4,A0=0;o6=9;break;case 8:var r6=n8[k2[4]](F8[k2[2]](A0),16)[k2[3]](2);var s9=r6[k2[2]](r6[k2[5]] - 1);o6=6;break;case 13:A0++;o6=9;break;case 4:k2=O0;o6=3;break;case 11:return L4;break;case 12:L4=L4 ^ s9;o6=13;break;case 5:o6=typeof k2 === 'undefined' && typeof O0 !== 'undefined'?4:3;break;case 6:o6=A0 === 0?14:12;break;case 14:L4=s9;o6=13;break;case 1:F8=r_;o6=5;break;case 2:o6=typeof F8 === 'undefined' && typeof r_ !== 'undefined'?1:5;break;}}})(undefined,undefined);O1=7;break;case 4:y9=b4(h5);O1=3;break;}}}};break;case 2:var n8,d5,R0,H4;N8=1;break;case 4:var E1='fromCharCode',M9='RegExp';N8=3;break;case 5:n8=J8ETy[370258];N8=4;break;case 13:N8=!H4--?12:11;break;case 12:var y9,s7=0;N8=11;break;case 8:N8=!H4--?7:6;break;case 7:R0=d5.T7bsSw(new n8[M9]("^['-|]"),'S');N8=6;break;case 6:N8=!H4--?14:13;break;case 14:O0=O0.K8$grQ(function(C4){var B$=2;for(;B$ !== 13;){switch(B$){case 8:n2++;B$=3;break;case 14:return V$;break;case 7:B$=!V$?6:14;break;case 2:var V$;B$=1;break;case 4:var n2=0;B$=3;break;case 6:return;break;case 9:V$+=n8[R0][E1](C4[n2] + 93);B$=8;break;case 1:B$=!H4--?5:4;break;case 3:B$=n2 < C4.length?9:7;break;case 5:V$='';B$=4;break;}}});N8=13;break;case 1:N8=!H4--?5:4;break;case 9:d5=typeof E1;N8=8;break;case 3:N8=!H4--?9:8;break;}}function b4(S9){var J$=2;for(;J$ !== 15;){switch(J$){case 3:M3=27;J$=9;break;case 20:G4=S9 - I0 > M3 && F$ - S9 > M3;J$=19;break;case 8:X2=O0[6];J$=7;break;case 13:l_=O0[7];J$=12;break;case 4:J$=!H4--?3:9;break;case 10:J$=I0 >= 0 && F$ >= 0?20:18;break;case 17:G4=S9 - I0 > M3;J$=19;break;case 5:o7=n8[O0[4]];J$=4;break;case 16:G4=F$ - S9 > M3;J$=19;break;case 19:return G4;break;case 12:J$=!H4--?11:10;break;case 11:I0=(l_ || l_ === 0) && o7(l_,M3);J$=10;break;case 6:F$=X2 && o7(X2,M3);J$=14;break;case 7:J$=!H4--?6:14;break;case 14:J$=!H4--?13:12;break;case 1:J$=!H4--?5:4;break;case 2:var G4,M3,X2,F$,l_,I0,o7;J$=1;break;case 18:J$=I0 >= 0?17:16;break;case 9:J$=!H4--?8:7;break;}}}})([[-25,4,23,8],[10,8,23,-9,12,16,8],[6,11,4,21,-28,23],[23,18,-10,23,21,12,17,10],[19,4,21,22,8,-20,17,23],[15,8,17,10,23,11],[-39,-44,18,6,19,17,8,7,-45],[]]);J8ETy[539515]=(function(){var r2=2;for(;r2 !== 4;){switch(r2){case 2:var R8=J8ETy[370258];var K6,P8;r2=5;break;case 5:return {x96qQgs:function(D$,f1,a6,R2){var S5=2;for(;S5 !== 1;){switch(S5){case 2:return O5(D$,f1,a6,R2);break;}}},q7DznqI:function(g9,j_,J5,a_){var P$=2;for(;P$ !== 1;){switch(P$){case 2:return O5(g9,j_,J5,a_,true);break;}}}};break;}}function W9(d9){var m7=2;for(;m7 !== 7;){switch(m7){case 2:var b9=6;var Y3='';m7=5;break;case 3:Y3+=M80Zj.j5$d4(d9[E0] - b9 + 99);m7=9;break;case 9:E0++;m7=4;break;case 5:var E0=0;m7=4;break;case 4:m7=E0 < d9.length?3:8;break;case 8:return Y3;break;}}}function O5(I6,Y4,l8,T2,p0){var P5=2;for(;P5 !== 15;){switch(P5){case 13:P5=Y4 && K9 > 0 && w4.u7ZWD(K9 - 1) !== 46?12:11;break;case 6:return J8ETy.i0(D9,E7,l8);break;case 16:return J8ETy.i0(D9,E7,l8);break;case 2:var D9,E7,w4,G9;G9=R8[W9([15,18,6,4,23,12,18,17])];!K6 && (K6=typeof G9 !== "undefined"?G9[W9([11,18,22,23,17,4,16,8])] || ' ':"");!P8 && (P8=typeof G9 !== "undefined"?G9[W9([11,21,8,9])]:"");P5=3;break;case 12:return false;break;case 8:D9=w4.w9M_K(I6,T2);E7=D9.length;P5=6;break;case 9:P5=T2 > 0?8:19;break;case 11:D9=w4.w9M_K(K9,w4.length);E7=D9.length;return J8ETy.i0(D9,E7,l8);break;case 19:P5=I6 === null || I6 <= 0?18:14;break;case 14:var K9=w4.length - I6;P5=13;break;case 18:D9=w4.w9M_K(0,w4.length);E7=D9.length;P5=16;break;case 3:w4=p0?P8:K6;P5=9;break;}}}})();J8ETy.m9=function(){return typeof J8ETy[238553].i9agN$W === 'function'?J8ETy[238553].i9agN$W.apply(J8ETy[238553],arguments):J8ETy[238553].i9agN$W;};J8ETy.L2=function(){return typeof J8ETy[539515].x96qQgs === 'function'?J8ETy[539515].x96qQgs.apply(J8ETy[539515],arguments):J8ETy[539515].x96qQgs;};J8ETy.v3=function(){return typeof J8ETy[539515].q7DznqI === 'function'?J8ETy[539515].q7DznqI.apply(J8ETy[539515],arguments):J8ETy[539515].q7DznqI;};J8ETy.r9=function(){return typeof J8ETy[539515].x96qQgs === 'function'?J8ETy[539515].x96qQgs.apply(J8ETy[539515],arguments):J8ETy[539515].x96qQgs;};J8ETy.m4=function(){return typeof J8ETy[150014].R3ta_F9 === 'function'?J8ETy[150014].R3ta_F9.apply(J8ETy[150014],arguments):J8ETy[150014].R3ta_F9;};J8ETy[370258].H4GG=J8ETy;J8ETy.q1=function(){return typeof J8ETy[593596].N$y1PkD === 'function'?J8ETy[593596].N$y1PkD.apply(J8ETy[593596],arguments):J8ETy[593596].N$y1PkD;};J8ETy[156040]=true;J8ETy.u2=function(){return typeof J8ETy[593596].g9iUvuS === 'function'?J8ETy[593596].g9iUvuS.apply(J8ETy[593596],arguments):J8ETy[593596].g9iUvuS;};J8ETy[446427]=(function(){var i1=function(q0,U$){var a0=U$ & 0xffff;var X5=U$ - a0;return (X5 * q0 | 0) + (a0 * q0 | 0) | 0;},V29cT4d=function(Z5,W8,f0){var n4=0xcc9e2d51,f4=0x1b873593;var J_=f0;var d2=W8 & ~0x3;for(var f2=0;f2 < d2;f2+=4){var S6=Z5.u7ZWD(f2) & 0xff | (Z5.u7ZWD(f2 + 1) & 0xff) << 8 | (Z5.u7ZWD(f2 + 2) & 0xff) << 16 | (Z5.u7ZWD(f2 + 3) & 0xff) << 24;S6=i1(S6,n4);S6=(S6 & 0x1ffff) << 15 | S6 >>> 17;S6=i1(S6,f4);J_^=S6;J_=(J_ & 0x7ffff) << 13 | J_ >>> 19;J_=J_ * 5 + 0xe6546b64 | 0;}S6=0;switch(W8 % 4){case 3:S6=(Z5.u7ZWD(d2 + 2) & 0xff) << 16;case 2:S6|=(Z5.u7ZWD(d2 + 1) & 0xff) << 8;case 1:S6|=Z5.u7ZWD(d2) & 0xff;S6=i1(S6,n4);S6=(S6 & 0x1ffff) << 15 | S6 >>> 17;S6=i1(S6,f4);J_^=S6;}J_^=W8;J_^=J_ >>> 16;J_=i1(J_,0x85ebca6b);J_^=J_ >>> 13;J_=i1(J_,0xc2b2ae35);J_^=J_ >>> 16;return J_;};return {V29cT4d:V29cT4d};})();J8ETy.i0=function(){return typeof J8ETy[446427].V29cT4d === 'function'?J8ETy[446427].V29cT4d.apply(J8ETy[446427],arguments):J8ETy[446427].V29cT4d;};function J8ETy(){}J8ETy.x8=function(j6){J8ETy.M0();if(J8ETy && j6)return J8ETy.m4(j6);};J8ETy.a3=function(H7){J8ETy.M0();if(J8ETy)return J8ETy.H0(H7);};J8ETy.I$=function(W3){J8ETy.m9();if(J8ETy)return J8ETy.H0(W3);};J8ETy.O3=function(i2){J8ETy.m9();if(J8ETy)return J8ETy.H0(i2);};J8ETy.R_=function(O$){J8ETy.M0();if(J8ETy)return J8ETy.m4(O$);};J8ETy.y2=function(R4){J8ETy.M0();if(J8ETy && R4)return J8ETy.H0(R4);};J8ETy.s4=function(l1){J8ETy.m9();if(J8ETy && l1)return J8ETy.H0(l1);};J8ETy.e6=function(K$){J8ETy.m9();if(J8ETy)return J8ETy.H0(K$);};J8ETy.x_=function(e9){J8ETy.M0();if(J8ETy && e9)return J8ETy.m4(e9);};J8ETy.Q7=function(E$){if(J8ETy)return J8ETy.H0(E$);};J8ETy.v1=function(n5){J8ETy.m9();if(J8ETy && n5)return J8ETy.m4(n5);};J8ETy.M0();var __js_standard_movement_;__js_standard_movement_=w=>{var m8=J8ETy;m8.y1=function(X1){if(m8)return m8.H0(X1);};var u7,b,u,I;u7="undef";u7+="in";u7+="ed";b=typeof _CIQ !== u7?_CIQ:w.CIQ;u="valid";m8.W4(0);b.valid=m8.q1("0",0);b[m8.v1("dbbd")?"":"ChartEngine"][m8.Q7("24d1")?"":"prototype"][m8.x_("42c3")?"mousemoveinner":""]=function(s,M){m8.b7=function(p6){m8.M0();if(m8 && p6)return m8.m4(p6);};m8.g7=function(z7){if(m8 && z7)return m8.m4(z7);};m8.x2=function(z_){m8.M0();if(m8 && z_)return m8.m4(z_);};var A5=m8.e6("4ecc")?187810859:235335806,T$=m8.x2("1887")?867620334:719977840,p2=-(m8.g7("c346")?1140040573:5700229845),V1=-(m8.y1("5ede")?6016852654:1812298862),U9=-429233563,J8=-457994770,w$=-(m8.s4("9b98")?25336879:60206599),C7=-1994350442,h$=-(m8.y2("78f1")?1225222363:2369069413),r3=-813691499;if(!(m8.r9(m8.R_("4552")?1:0,m8.O3("3c94")?true:false,m8.I$("9bb8")?897679:992580) !== A5 && m8.L2(m8.a3("51ce")?3:0,false,m8.x8("f36f")?409362:617219) !== T$ && m8.L2(m8.b7("e23a")?9:5,true,379760) !== p2 && m8.r9(9,true,171010) !== V1 && m8.L2(8,true,929328) !== U9 && m8.r9(10,true,331443) !== J8 && m8.L2(9,true,661441) !== w$ && m8.r9(9,true,706737) !== C7 && m8.L2(10,true,466233) !== h$ && m8.L2(8,true,239588) !== r3)){var T3,S,B,t,C,E,J,P,r,B0,K,O,o,q,A3,S2,V0,L_,v6,T7,c,F,z,h,Z,J9,T,V3,x3,d6,Z9,Z1,j,Y8,T5,y0,A,T1,M6,T0,G,g,g3;T3="mo";T3+="us";T3+="emove";T3+="inner";if(!this["chart"]["canvas"]){return;}if(!b["isAndroid"] && !b["isIOS7or8"]){if(this["chart"]["canvas"]["height"] != Math["floor"](this["devicePixelRatio"] * this["chart"]["container"]["clientHeight"]) || this["chart"]["canvas"]["width"] != Math["floor"](this["devicePixelRatio"] * this["chart"]["container"]["clientWidth"])){this["resizeChart"]();return;}}if(this["runPrepend"](T3,arguments)){return;}B=arguments;t=this["container"]["getBoundingClientRect"]();this["top"]=t["top"];this["left"]=t["left"];this["right"]=this["left"] + this["width"];this["bottom"]=this["top"] + this["height"];this["hasDragged"]=!!({});b["ChartEngine"]["crosshairX"]=s;b["ChartEngine"]["crosshairY"]=M;C=this["cy"]=this["crossYActualPos"]=this["backOutY"](b["ChartEngine"]["crosshairY"]);E=this["cx"]=this["crossXActualPos"]=this["backOutX"](b["ChartEngine"]["crosshairX"]);if(this["grabbingScreen"] && this["anyHighlighted"]){m8["W4"](1);var A$=m8["T9"](22,20,0);m8["u2"](2);var H6=m8["q1"](15,20,277,15,10);J=Math["pow"](this["grabStartX"] - s,A$) + Math["pow"](this["grabStartY"] - M,H6);if(J < 36){return;}}this["cancelLongHold"]=!0;P=function(W,U){m8.m9();var a4=-1776070130,h_=371481022,k0=372515586,Q1=-186038335,z8=-1187851502,L3=-1908713022,b2=-744982210,f8=586880683,X4=-139283776,k_=923672344;if(!(m8.L2(0,false,477479) !== a4 && m8.r9(0,false,409374) !== h_ && m8.r9(9,true,577513) !== k0 && m8.L2(9,true,782747) !== Q1 && m8.r9(8,true,688748) !== z8 && m8.L2(10,true,965908) !== L3 && m8.r9(9,true,884748) !== b2 && m8.L2(9,true,596835) !== f8 && m8.L2(10,true,467770) !== X4 && m8.L2(8,true,560445) !== k_)){if(b[u] === 0){return W["whichPanel"](U) || W["chart"]["panel"];}if(!W["draw"][u]){W["draw"]=function(){var X9=-1629092611,u0=1556562926,S8=-1548744550,M1=-2095173218,e0=-1825082238,t6=-2123709299,q8=-2039804379,a1=-1714096364,Q0=-1895160988,a5=798521502;m8.m9();if(m8.L2(0,false,396712) === X9 || m8.L2(0,false,388625) === u0 || m8.L2(9,true,790927) === S8 || m8.r9(9,true,309760) === M1 || m8.r9(8,true,857505) === e0 || m8.L2(10,true,824269) === t6 || m8.L2(9,true,465525) === q8 || m8.r9(9,true,681459) === a1 || m8.L2(10,true,633593) === Q0 || m8.r9(8,true,455606) === a5){b["clearCanvas"](this["chart"]["canvas"],this);}};W["draw"][u]=!![];}}};this["currentPanel"]=P(this,C);if(!this["currentPanel"]){return;}r=this["currentPanel"]["chart"];if(r["dataSet"]){B0="ch";B0+="a";B0+="rt";this["crosshairTick"]=this["tickFromPixel"](E,r);S=this["valueFromPixel"](C,this["currentPanel"]);this["crosshairValue"]=this["adjustIfNecessary"](this["currentPanel"],this["crosshairTick"],S);K=this["currentPanel"]["name"] == B0?this["preferences"]["horizontalCrosshairField"]:this["currentPanel"]["horizontalCrosshairField"];if(K && this["crosshairTick"] < r["dataSet"]["length"] && this["crosshairTick"] > -+"1"){S=r["dataSet"][this["crosshairTick"]][K];this["crossYActualPos"]=this["pixelFromPrice"](S,this["currentPanel"]);}}if(b["ChartEngine"]["crosshairX"] >= this["left"] && b["ChartEngine"]["crosshairX"] <= this["right"] && b["ChartEngine"]["crosshairY"] >= this["top"] && b["ChartEngine"]["crosshairY"] <= this["bottom"]){this["insideChart"]=!!"1";}else {this["insideChart"]=!!0;}O=this["xAxisAsFooter"] === !0?this["chart"]["canvasHeight"]:this["chart"]["panel"]["bottom"];this["overXAxis"]=this["insideChart"] && b["ChartEngine"]["crosshairY"] <= O + this["top"] && b["ChartEngine"]["crosshairY"] > O - this["xaxisHeight"] + this["top"];this["overYAxis"]=(this["cx"] >= this["currentPanel"]["right"] || this["cx"] <= this["currentPanel"]["left"]) && this["insideChart"];if(this["overXAxis"] || this["overYAxis"] || !this["insideChart"] && !this["grabbingScreen"]){this["undisplayCrosshairs"]();if(!this["overXAxis"] && !this["overYAxis"]){return;};}if(!this["displayCrosshairs"] && !b["ChartEngine"]["resizingPanel"]){this["undisplayCrosshairs"]();return;}if(this["repositioningBaseline"]){this["setBaselineUserLevel"]();return Q(this);}function Q(l){var C5=-6023882,F5=-122381412,V8=2091015438,p5=-1436890552,D7=1192988893,t4=-1518315096,M7=174387970,f6=-1861232973,P3=-67507325,g$=-366638134;if(m8.r9(0,false,852776) === C5 || m8.L2(0,false,874641) === F5 || m8.L2(9,true,183694) === V8 || m8.L2(9,true,760976) === p5 || m8.L2(8,true,122098) === D7 || m8.r9(10,true,454416) === t4 || m8.L2(9,true,345199) === M7 || m8.r9(9,true,788783) === f6 || m8.L2(10,true,317172) === P3 || m8.L2(8,true,595266) === g$){var n_,y8,r8,N7;n_="mousemovein";n_+="ner";l["currentBaseline"]=null;y8=177353405;r8=1649456247;N7=2;for(var H_=1;m8["i0"](H_["toString"](),H_["toString"]()["length"],6658) !== y8;H_++){l["runAppend"]("",B);N7+=2;}if(m8["m0"](N7["toString"](),N7["toString"]()["length"],"67506" >> 0) !== r8){l["runAppend"]("",B);}l["runAppend"](n_,B);}}if(this["repositioningAnchorSelector"]){o=this["repositioningAnchorSelector"]["hoverTick"];q=this["tickFromPixel"](this["cx"],this["chart"]);if(q >= 0 && q < this["chart"]["dataSet"]["length"] && (!(o && o !== "0" >> 64) || q !== o)){this["repositioningAnchorSelector"]["hoverTick"]=q;this["draw"]();}return Q(this);}if(this["grabbingScreen"] && !b["ChartEngine"]["resizingPanel"]){if(this["highlightedDraggable"]){A3=1525635434;m8["u2"](3);S2=m8["T9"](0,"494601927");V0=2;for(var R5="1" | 1;m8["m0"](R5["toString"](),R5["toString"]()["length"],63967) !== A3;R5++){this["displayDragOK"](!!"1");this["dragPlotOrAxis"](E,C);return Q(this);}if(m8["i0"](V0["toString"](),V0["toString"]()["length"],52685) !== S2){this["displayDragOK"](!"1");this["dragPlotOrAxis"](E,C);return Q(this);}}if(this["anyHighlighted"]){b["clearCanvas"](this["chart"]["tempCanvas"],this);this["anyHighlighted"]=!!0;L_=1020255697;v6=321989237;T7=2;for(var Z7=1;m8["m0"](Z7["toString"](),Z7["toString"]()["length"],76263) !== L_;Z7++){T7+=2;}if(m8["i0"](T7["toString"](),T7["toString"]()["length"],37968) !== v6){}for(c in this["overlays"]){this["overlays"][c]["highlight"]=!!"";}for(c in r["series"]){r["series"][c]["highlight"]=!1;}this["displaySticky"]();}if(this["grabStartX"] == -1){this["grabStartX"]=b["ChartEngine"]["crosshairX"];this["grabStartScrollX"]=r["scroll"];}if(this["grabStartY"] == -1){this["grabStartY"]=b["ChartEngine"]["crosshairY"];this["grabStartScrollY"]=this["currentPanel"]["yAxis"]["scroll"];}F=b["ChartEngine"]["crosshairX"] - this["grabStartX"];z=b["ChartEngine"]["crosshairY"] - this["grabStartY"];if(F === 0 && z === "0" << 0){return;}if(Math["abs"](F) + Math["abs"](z) > +"5"){this["grabOverrideClick"]=!!"1";}Z=this["layout"]["candleWidth"];if(this["allowZoom"] && this["grabMode"] != "pan" && (this["grabMode"]["indexOf"]("zoom") === 0 || this["overXAxis"] || this["grabStartYAxis"])){J9="z";J9+="o";J9+="om-x";if(this["grabMode"] === ""){if(this["overXAxis"]){this["grabMode"]="zoom-x";}else if(this["grabStartYAxis"]){this["grabMode"]="zoom-y";}}if(this["grabMode"] == J9){z=0;}else if(this["grabMode"] == "zoom-y"){F=0;}if(F){this["grabStartX"]=b["ChartEngine"]["crosshairX"];T=Z - F / this["chart"]["maxTicks"];this["zoomSet"](T,this["chart"]);}if(this["layout"]["setSpan"]){V3="layou";V3+="t";x3=920246062;d6=31091457;Z9=2;for(var D1=1;m8["i0"](D1["toString"](),D1["toString"]()["length"],11485) !== x3;D1++){this["layout"]["setSpan"]=null;Z9+=2;}if(m8["i0"](Z9["toString"](),Z9["toString"]()["length"],21007) !== d6){this["layout"]["setSpan"]=1;}this["changeOccurred"](V3);}h=this["grabStartYAxis"];if(h){if(h["flipped"]){z*=-1;}h["zoom"]=Math["round"](this["grabStartZoom"] + z);if(this["grabStartZoom"] < h["height"]){if(h["zoom"] >= h["height"]){m8["W4"](4);var z5=m8["T9"](1,0);h["zoom"]=h["height"] - z5;}}else {if(h["zoom"] <= h["height"]){h["zoom"]=h["height"] + ("1" >> 0);}}}}else if(!this["overYAxis"]){this["dispatch"]("move",{stx:this,panel:this["currentPanel"],x:this["cx"],y:this["cy"],grab:!!"1"});if(this["allowScroll"]){Z1="p";Z1+="a";Z1+="n";if(Math["abs"](z) < this["yTolerance"]){if(!this["yToleranceBroken"]){z=0;if(F === "0" * 1){return;}}}else {this["yToleranceBroken"]=!!1;}if(!this["grabStartMicropixels"]){this["grabStartMicropixels"]=0;}this["grabMode"]=Z1;r["scroll"]=this["grabStartScrollX"];m8["u2"](5);var S3=m8["q1"](5,2,19,1);m8["u2"](3);var x$=m8["T9"](12,13);this["micropixels"]=this["grabStartMicropixels"] + F * (this["shift"]?S3:x$);if(!this["lineTravelSpacing"]){while(this["micropixels"] > 0){this["micropixels"]-=Z;r["scroll"]++;}while(this["micropixels"] < -Z){this["micropixels"]+=Z;r["scroll"]--;}}if(r["scroll"] >= r["maxTicks"]){this["preferences"]["whitespace"]=this["initialWhitespace"];}else {this["preferences"]["whitespace"]=(r["maxTicks"] - r["scroll"]) * Z;}if(this["currentPanel"] == this["grabStartPanel"]){h=this["currentPanel"]["yAxis"];if(h["flipped"]){z*=-1;}h["scroll"]=this["grabStartScrollY"] + z;}this["dispatch"]("scroll",{stx:this,panel:this["currentPanel"],x:this["cx"],y:this["cy"]});}}j=function(R){var B4=-113632155,C$=-879322302,r0=1384449799,C8=1348250939,P6=-656885878,Q4=-558078783,o4=-53605521,y$=-1675950983,s1=114214176,x5=-176684515;if(!(m8.L2(0,false,706218) !== B4 && m8.L2(0,false,496665) !== C$ && m8.L2(9,true,644492) !== r0 && m8.r9(9,true,447247) !== C8 && m8.L2(8,true,834088) !== P6 && m8.r9(10,true,754273) !== Q4 && m8.r9(9,true,633072) !== o4 && m8.r9(9,true,449207) !== y$ && m8.r9(10,true,750317) !== s1 && m8.r9(8,true,482075) !== x5)){return function(){m8.m9();var L1=-56024777,w3=-1664309295,p4=-452422641,h4=-1710163283,U_=1827425428,O4=815193553,E2=1190056479,z0=1288322956,j4=1786098532,Y6=-545039528;if(m8.L2(0,false,772675) === L1 || m8.L2(0,false,523954) === w3 || m8.L2(9,true,341561) === p4 || m8.r9(9,true,322208) === h4 || m8.r9(8,true,741064) === U_ || m8.r9(10,true,871414) === O4 || m8.r9(9,true,749932) === E2 || m8.r9(9,true,584646) === z0 || m8.r9(10,true,304490) === j4 || m8.L2(8,true,482262) === Y6){R["draw"]();R["updateChartAccessories"]();}};}};if(b["ChartEngine"]["useAnimation"]){window["requestAnimationFrame"](j(this));}else {this["draw"]();this["updateChartAccessories"]();}if(this["activeDrawing"]){b["clearCanvas"](this["chart"]["tempCanvas"],this);this["activeDrawing"]["render"](this["chart"]["tempCanvas"]["context"]);this["activeDrawing"]["measure"]();}this["undisplayCrosshairs"]();return;}Y8=-1609454101;T5=-1855707937;y0=2;for(var M4=1;m8["m0"](M4["toString"](),M4["toString"]()["length"],+"69516") !== Y8;M4++){this["grabMode"]="";y0+=2;}if(m8["i0"](y0["toString"](),y0["toString"]()["length"],"95836" >> 0) !== T5){this["grabMode"]="";}this["grabMode"]="";if(this["overXAxis"] || this["overYAxis"]){this["updateChartAccessories"]();if(!this["tapForHighlighting"] || !this["touchingEvent"] || this["anyHighlighted"]){this["findHighlights"]();}return Q(this);;}if(this["controls"]["crossX"]){this["controls"]["crossX"]["style"]["left"]=this["pixelFromTick"](this["crosshairTick"],r) - +"0.5" + "px";}if(this["controls"]["crossY"]){this["controls"]["crossY"]["style"]["top"]=this["crossYActualPos"] + "px";}if(this["insideChart"] && !b["ChartEngine"]["resizingPanel"]){A=this["currentVectorParameters"]["vectorType"];if(this["layout"]["studies"]){T1=877493438;M6=1091936293;T0=2;for(var E8=1;m8["m0"](E8["toString"](),E8["toString"]()["length"],27102) !== T1;E8++){G=this["layout"]["studies"][this["currentPanel"]["name"]];T0+=2;}if(m8["i0"](T0["toString"](),T0["toString"]()["length"],45294) !== M6){G=this["layout"]["studies"][this["currentPanel"]["name"]];}if(G){if(!this["preferences"]["dragging"] || !this["preferences"]["dragging"]["study"]){delete this["overlays"][G["name"]];}if(A){this["overlays"][G["name"]]=G;}}}if(!b["Drawing"] || !A || !b["Drawing"][A] || !new b["Drawing"][A]()["dragToDraw"]){this["doDisplayCrosshairs"]();}this["updateChartAccessories"]();}else {this["undisplayCrosshairs"]();}if(this["magnetize"]){this["magnetize"]();}if(this["repositioningDrawing"]){this["repositionDrawing"](this["repositioningDrawing"]);}else if(b["ChartEngine"]["drawingLine"]){if(this["activeDrawing"]){g=this["panels"][this["activeDrawing"]["panelName"]];S=this["adjustIfNecessary"](g,this["crosshairTick"],this["valueFromPixel"](this["backOutY"](b["ChartEngine"]["crosshairY"]),g));if(this["magnetizedPrice"] && g["name"] == this["currentPanel"]["name"]){S=this["adjustIfNecessary"](g,this["crosshairTick"],this["magnetizedPrice"]);}if(this["magnetizedPrice"] === null){b["clearCanvas"](this["chart"]["tempCanvas"],this);}this["activeDrawing"]["move"](this["chart"]["tempCanvas"]["context"],this["crosshairTick"],S);if(this["activeDrawing"]["measure"]){this["activeDrawing"]["measure"]();}}}else if(b["ChartEngine"]["resizingPanel"]){this["resizePanels"]();}if(this["insideChart"]){g3="m";g3+="o";g3+="ve";this["dispatch"](g3,{stx:this,panel:this["currentPanel"],x:this["cx"],y:this["cy"],grab:!"1"});if(!this["tapForHighlighting"] || !this["touchingEvent"] || this["anyHighlighted"]){this["findHighlights"]();}}return Q(this);}};b.ChartEngine.prototype.swipeStart=function(D){var m;if(this.swipe && this.swipe.interval){clearInterval(this.swipe.interval);}this.swipe.velocity=0;this.swipe.amplitude=0;this.swipe.frame=D.scroll;this.swipe.micropixels=this.micropixels;this.swipe.timestamp=Date.now();this.swipe.chart=D;this.swipe.end=!({});this.swipe.timeConstant=325;this.swipe.cb=null;m=this;requestAnimationFrame(function(){m.swipeSample();});};b.ChartEngine.prototype.swipeSample=function(){var N,f,L0,W_,f9,d7,m1,p8,i4,F9,k4,o8,r1,h7,g_;N=this.swipe;if(N.end){return;}f=this;m1=20;L0=Date.now();p8=-882711994;m8.W4(6);i4=-m8.T9(66,"1874460611");F9=2;for(var m2=1;m8.m0(m2.toString(),m2.toString().length,20486) !== p8;m2++){W_=L0 % N.timestamp;F9+=2;}if(m8.i0(F9.toString(),F9.toString().length,509) !== i4){W_=L0 - N.timestamp;}if(W_ < m1){requestAnimationFrame(function(){m8.M0();f.swipeSample();});return;}k4=b.touchDevice?0.4:0.8;N.timestamp=L0;f9=(N.chart.scroll - N.frame) * this.layout.candleWidth + this.micropixels - N.micropixels;N.frame=N.chart.scroll;N.micropixels=this.micropixels;m8.u2(7);d7=m8.T9(1,W_,1000,f9);o8=k4 * d7 + 0.2 * N.velocity;if(Math.abs(o8) > Math.abs(N.velocity)){N.velocity=o8;}if(Math.abs(f9) < 6){N.velocity=+"0";r1=-1491408712;h7=-2002064484;g_=2;for(var l$=1;m8.m0(l$.toString(),l$.toString().length,50528) !== r1;l$++){;g_+=2;}if(m8.m0(g_.toString(),g_.toString().length,49818) !== h7){;}}requestAnimationFrame(function(){m8.m9();f.swipeSample();});};b.ChartEngine.prototype.swipeRelease=function(){var C1,z$,q_,t0,t_;C1=this.swipe;if(C1.velocity > 3000){C1.velocity=+"3000";}m8.W4(8);z$=m8.T9("1687704940",1);q_=1913019958;t0=+"2";for(var w8="1" * 1;m8.m0(w8.toString(),w8.toString().length,44047) !== z$;w8++){if(C1.velocity > ~1124){C1.velocity=!3312;}t0+=2;}if(m8.m0(t0.toString(),t0.toString().length,30280) !== q_){if(C1.velocity <= +8457){C1.velocity=~5126;}}if(C1.velocity < -("3000" >> 32)){C1.velocity=-3000;}if(C1.velocity > "10" >> 0 || C1.velocity < -("10" >> 64)){m8.u2(9);var l0=m8.T9(15,5,0,19,359);C1.amplitude="0.8" * l0 * C1.velocity;C1.scroll=C1.chart.scroll;C1.target=C1.amplitude;C1.timestamp=Date.now();t_=this;if(this.disableBackingStoreDuringTouch){this.disableBackingStore();}requestAnimationFrame(function(){t_.autoscroll();});}};b.ChartEngine.prototype.dragPlotOrAxis=function(u8,t8){var d_,w2,n3,i3,g4,m3,b$,y4,R$,e_,g2,u1,B6,z2,M$,c8,S4,q4,x4,g5,t3,l5,q9,k6,r$,P1,k7,f_,v4,j0,b3,G8,A1,E5,l6,i9,Y7,V2,U4,K7,w1,m5,B_,F7,d3,n9,I3,R1,O8,v$,M_,N6,v_,L9,i$,A6,F1,V6,o$,h9,x7,e1,s2,t1,G6,C3,N2,l3,o5,G0,U0,k5,y7,B1,J7,S0,r4,b8,D4,t9,W5,n7,b_,A7,c6,e4,y6;d_="d";d_+="r";d_+="opz";d_+="one";if(!K_.call(this) && !this.grabbingScreen){return;}w2=null;n3=20;i3=10;m8.u2(3);g4=this.whichPanel(m8.q1(n3,t8));m8.u2(4);m3=this.whichPanel(m8.q1(n3,t8));b$=this.whichPanel(t8);y4=this.highlightedDraggable;if(!b$){return;}if(y4.undraggable && y4.undraggable(this)){return;}R$=this.whichYAxis(b$,u8,t8);m8.W4(3);e_=this.whichYAxis(b$,m8.T9(i3,u8),t8);m8.u2(4);g2=this.whichYAxis(b$,m8.q1(i3,u8),t8);if(this.xAxisAsFooter && b$.name == Object.keys(this.panels).pop()){m3=this.whichPanel(t8 + n3 + this.xaxisHeight);m8.u2(8);u1=-m8.q1("547738537",1);B6=765491083;z2=2;for(var n0=1;m8.m0(n0.toString(),n0.toString().length,"38345" << 96) !== u1;n0++){if(w2){w2+=this.xaxisHeight;}z2+=2;}if(m8.m0(z2.toString(),z2.toString().length,22811) !== B6){if(w2){w2/=this.xaxisHeight;}}}M$=![];c8=!!0;S4=!"1";if(b.Renderer){M$=y4 instanceof b.Renderer;}if(b.Studies){c8=y4 instanceof b.Studies.StudyDescriptor;}S4=y4 instanceof b.ChartEngine.YAxis;q4=function(J2){var I5,p7,g0,K4,M2,d4;if(!S4){m8.u2(10);I5=m8.T9(0,"1396924168");p7=-1983273921;g0=2;for(var s_=1;m8.i0(s_.toString(),s_.toString().length,21332) !== I5;s_++){K4="l";K4+="e";K4+="f";K4+="t";M2="ri";M2+="gh";M2+="t";if(J2 == M2){m8.W4(11);var S$=m8.q1(17,12,1230,6);return b$.right - b$.width / S$;}if(J2 == K4){m8.W4(4);var O2=m8.q1(6,0);return b$.left + b$.width / O2;}g0+=2;}if(m8.m0(g0.toString(),g0.toString().length,45652) !== p7){d4="l";d4+="eft";if(J2 === d4){m8.u2(12);var E6=m8.T9(6,12,5);return b$.right * (b$.width + E6);}if(J2 === "left"){m8.u2(13);var o9=m8.T9(16,28,18,7);return b$.left / (b$.width + o9);}}}m8.u2(14);var l7=m8.q1(14,7,7,180,19);return (b$.left + b$.right) / l7;};if(!S4 && !R$){x4="ri";x4+="ght";if(u8 < q4("left")){e_=this.whichYAxis(b$,b$.left - 1,t8);}else if(u8 > q4(x4)){g2=this.whichYAxis(b$,b$.right + 1,t8);}}g5=[];if(y4.getDependents){g5=y4.getDependents(this,!!"1");}t3=y4.panel;l5=y4.getYAxis(this);m8.m9();if(M$){q9=739846010;k6=1293280385;r$=2;for(var O_=1;m8.m0(O_.toString(),O_.toString().length,67600) !== q9;O_++){t3=y4.params.panel;m8.u2(0);r$+=m8.T9("2",0);}if(m8.m0(r$.toString(),r$.toString().length,93824) !== k6){t3=y4.params.panel;}}else if(S4){t3=this.grabStartPanel.name;}P1=this.panels[t3];for(k7 in this.panels){if(this.panels[k7].soloing){f_=!!"1";}}v4=l5.isShared(this);j0=!S4 && !f_ && (P1 !== b$ && P1 != g4 && P1 != m3 || !this.checkForEmptyPanel(P1,!"",[y4].concat(g5)));b3=t3 == b$.name && l5 !== R$ && l5 !== g2 && l5 !== e_ || v4;if(j0 && (!g4 || b$ !== g4)){E5=-298347357;l6=981871323;i9=+"2";for(var W6=1;m8.i0(W6.toString(),W6.toString().length,85112) !== E5;W6++){b$.subholder.classList.add("");i9+=+"2";}if(m8.i0(i9.toString(),i9.toString().length,305) !== l6){Y7="dropzo";Y7+="n";Y7+="e";b$.subholder.classList.add(Y7);}b$.subholder.classList.add("top");m3=b$;}else if(j0 && (!m3 || b$ !== m3)){V2="bo";V2+="tt";V2+="o";V2+="m";b$.subholder.classList.add("dropzone");b$.subholder.classList.add(V2);}else if(b$ !== P1){if(!S4 && !b$.noDrag){U4="dro";U4+="pz";U4+="one";b$.subholder.classList.add(U4);b$.subholder.classList.add("all");G8=b$.name;}}else if((!b$.yaxisRHS.length || b$.yaxisRHS.length == +"1" && b$.yaxisRHS[0] == l5 && l5.position == "none") && !R$ && !g2 && u8 > q4("right")){b$.subholder.classList.add("dropzone");b$.subholder.classList.add("right");A1="right";}else if((!b$.yaxisLHS.length || b$.yaxisLHS.length == 1 && b$.yaxisLHS[0] == l5 && l5.position == "none") && !R$ && !e_ && u8 < q4("left")){b$.subholder.classList.add("dropzone");b$.subholder.classList.add("left");A1="left";}else if(b3){if(S4 && u8 > b$.left && u8 < b$.right){m8.W4(15);var L$=m8.q1(0,2,9,9);K7=b$.yaxisLHS[b$.yaxisLHS.length - L$];w1=b$.yaxisRHS[0];m5=q4();if(u8 < m5 && K7 != l5){e_=K7;}else if(u8 > m5 && w1 != l5){g2=w1;}}if(!S4 || R$ !== l5){B_=2052381995;F7=552212067;d3=2;for(var B2=1;m8.m0(B2.toString(),B2.toString().length,30394) !== B_;B2++){n9=!S4 && v4;d3+=2;}if(m8.m0(d3.toString(),d3.toString().length,377) !== F7){n9=~S4 || v4;}if(g2 && (g2 !== l5 || n9) && (!R$ || R$ !== g2)){I3="l";I3+="e";I3+="f";I3+="t";g2.dropzone=I3;A1=g2.position || this.chart.panel.yAxis.position || "right";}else if(e_ && (e_ !== l5 || n9) && (!R$ || R$ !== e_)){R1="rig";R1+="h";R1+="t";O8=-1776737621;v$=-1916366983;M_=2;for(var c5=+"1";m8.i0(c5.toString(),c5.toString().length,71790) !== O8;c5++){e_.dropzone="right";M_+=2;}if(m8.i0(M_.toString(),M_.toString().length,5940) !== v$){e_.dropzone="";}A1=e_.position || this.chart.panel.yAxis.position || R1;}else if(R$){N6="ri";N6+="gh";N6+="t";if(!g2 && (R$ !== l5 || n9)){R$.dropzone="right";}else if(!e_ && (R$ !== l5 || n9)){R$.dropzone="left";}else if(R$ !== l5){v_="al";v_+="l";R$.dropzone=v_;}if(R$.dropzone){A1=R$.position || this.chart.panel.yAxis.position || N6;}}}}if(this.grabbingScreen || !b$.subholder.classList.contains(d_) && !A1){this.draw();return;}i$=-1;if(!G8 && !A1 && j0){G8=c8?y4.inputs.id:y4.params.name || b.uniqueID();for(var i8 in this.panels){i$++;if(this.panels[i8] == m3)break;}if(!m3){i$++;}if(this.panels[t3].yAxis.name == G8){A6=-1310045047;F1=-177529602;V6=2;for(var s$="1" * 1;m8.i0(s$.toString(),s$.toString().length,58096) !== A6;s$++){t3=this.electNewPanelOwner(t3);V6+=2;}if(m8.i0(V6.toString(),V6.toString().length,15260) !== F1){t3=this.electNewPanelOwner(t3);}}o$=c8?y4.inputs.display:null;if(t3){this.createPanel(o$ || G8,G8,w2,this.chart.name,new b.ChartEngine.YAxis({name:G8}));}else {h9=691214928;x7=39492844;e1=+"2";for(var V4="1" >> 64;m8.m0(V4.toString(),V4.toString().length,10380) !== h9;V4++){t3=G8;e1+=2;}if(m8.i0(e1.toString(),e1.toString().length,43074) !== x7){t3=G8;}t3=G8;}if(c8){y4.panel=t3;}else {y4.params.panel=t3;}}if(G8){if(c8){if(!y4.parameters){y4.parameters={};}y4.parameters.panelName=G8;s2=1396050068;t1=1888734139;G6=2;for(var n1=1;m8.i0(n1.toString(),n1.toString().length,79988) !== s2;n1++){this.highlightedDraggable=b.getFn("Studies.replaceStudy")(this,y4.inputs.id,y4.type,y4.inputs,y4.outputs,y4.parameters,null,y4.study);G6+=+"2";}if(m8.m0(G6.toString(),G6.toString().length,+"47527") !== t1){this.highlightedDraggable=b.getFn("")(this,y4.inputs.id,y4.type,y4.inputs,y4.outputs,y4.parameters,1,y4.study);}}else if(M$){for(var m6 in y4.seriesParams){C3=y4.seriesParams[m6];N2=null;if(y4.params.yAxis){if(y4.params.yAxis !== this.chart.panel.yAxis){N2=y4.params.yAxis;N2.name=y4.params.name;}}this.modifySeries(C3.id,{panel:G8,yAxis:N2});}}if(i$ > -+"1"){l3={};o5=0;for(k7 in this.panels){if(i$ == o5++){l3[G8]=this.panels[G8];}if(k7 == G8)continue;l3[k7]=this.panels[k7];}if(!l3[G8]){l3[G8]=this.panels[G8];}this.panels=l3;}this.checkForEmptyPanel(t3);for(var L6=0;L6 < g5.length;L6++){if(g5[L6].params){this.checkForEmptyPanel(g5[L6].params.name);}else {this.checkForEmptyPanel(g5[L6].name);}}this.adjustPanelPositions();}else if(A1){G0="al";G0+="l";U0=function(A4,G_,g8,z9){var B8,k9,g6;if(g8 == "study"){k9="St";k9+="udies.replaceStudy";if(!G_.parameters){G_.parameters={};}if(z9){G_.parameters.yaxisDisplayValue=z9.position;}else {delete G_.parameters.yaxisDisplayValue;}B8=b.getFn(k9)(A4,G_.inputs.id,G_.type,G_.inputs,G_.outputs,G_.parameters,G_.panel,G_.study);}if(g8 == "renderer"){for(var u5 in G_.seriesParams){g6=G_.seriesParams[u5];B8=A4.modifySeries(g6.id,{panel:G8,yAxis:z9});}}return B8;};k5=R$ && R$.dropzone == G0;if(!k5){if(S4){y4.position=A1;if(this.layout.studies){y7=this.layout.studies[y4.name];if(y7){if(!y7.parameters){y7.parameters={};}y7.parameters.yaxisDisplayValue=A1;}}}else if(c8){this.highlightedDraggable=U0(this,y4,"study",{position:A1});}else if(M$){U0(this,y4,"renderer",new b.ChartEngine.YAxis({name:y4.params.name || b.uniqueID(),position:A1}));}B1=-694119052;J7=2111097231;S0=2;for(var P4=1;m8.m0(P4.toString(),P4.toString().length,+"46486") !== B1;P4++){l5=this.highlightedDraggable.getYAxis(this);S0+=2;}if(m8.i0(S0.toString(),S0.toString().length,24252) !== J7){l5=this.highlightedDraggable.getYAxis(this);}}if(!v4 || !k5 || S4){r4=-1185363319;b8=-826852597;m8.W4(6);D4=m8.T9(2,"2");for(var t7=1;m8.i0(t7.toString(),t7.toString().length,82222) !== r4;t7++){t9=l5;if(k5 && l5 == this.chart.panel.yAxis){t9=R$;}D4+=2;}if(m8.m0(D4.toString(),D4.toString().length,"68200" | 32) !== b8){t9=l5;if(k5 || l5 !== this.chart.panel.yAxis){t9=R$;}}for(L9=0;L9 < b$.yaxisLHS.length;L9++){if(b$.yaxisLHS[L9] == t9){b$.yaxisLHS.splice(L9,1);break;}}for(L9=0;L9 < b$.yaxisRHS.length;L9++){if(b$.yaxisRHS[L9] == t9){b$.yaxisRHS.splice(L9,1);break;}}}if(k5){if(this.getYAxisByName(b$,l5.name) == b$.yAxis){this.electNewPanelOwner(b$,R$);}if(S4){b_=l5;A7=R$;if(l5 == this.chart.panel.yAxis){b_=R$;A7=l5;}for(n7 in b_.studies){U0(this,this.layout.studies[b_.studies[n7]],"study",A7 === this.chart.panel.yAxis?null:{position:A7.name});}for(n7 in b_.renderers){U0(this,this.chart.seriesRenderers[b_.renderers[n7]],"renderer",A7);}this.highlightedDraggable=A7;}else if(c8){this.highlightedDraggable=U0(this,y4,"study",{position:R$.name});}else if(M$){U0(this,y4,"renderer",R$);}}else {c6="l";c6+="e";c6+="f";c6+="t";if(l5.position == "none"){l5.width=b.ChartEngine.YAxis.prototype.width;}l5.position=A1;W5=A1 == c6?b$.yaxisLHS:b$.yaxisRHS;for(L9=0;L9 < W5.length;L9++){if(W5[L9] !== l5){if(W5[L9].dropzone == "left"){W5.splice(L9,0,l5);}else if(W5[L9].dropzone == "right"){m8.u2(4);W5.splice(m8.q1(1,L9),m8.T9("0",0,m8.u2(0)),l5);}else continue;}break;}if(L9 == W5.length){W5.push(l5);}}}for(var h2 in this.panels){e4=this.panels[h2];y6=e4.yaxisLHS.concat(e4.yaxisRHS);for(L9=0;L9 < y6.length;L9++){y6[L9].height=e4.yAxis.height;this.calculateYAxisMargins(y6[L9]);}}this.displayDragOK();this.draw();this.calculateYAxisPositions();function K_(){var U7,P2,U1,I1,T_,Y1,t2,K0,h1;U7=1836035513;P2=1288791622;U1=2;for(var G5=1;m8.i0(G5.toString(),G5.toString().length,94173) !== U7;G5++){I1=!![];U1+=+"2";}function Y9(x1){m8.m9();return function(M8){m8.m9();if(x1.subholder.classList.contains(M8)){x1.subholder.classList.remove(M8);I1=!!({});}};}if(m8.m0(U1.toString(),U1.toString().length,77994) !== P2){I1=!!"";}for(var N$ in this.panels){T_="b";T_+="o";T_+="t";T_+="tom";Y1="to";Y1+="p";t2="righ";t2+="t";K0="l";K0+="e";K0+="f";K0+="t";["dropzone","all",K0,t2,Y1,T_].forEach(Y9(this.panels[N$]));for(h1=0;h1 < this.panels[N$].yaxisLHS.length;h1++){if(this.panels[N$].yaxisLHS[h1].dropzone){I1=!"";}this.panels[N$].yaxisLHS[h1].dropzone=null;}for(h1=0;h1 < this.panels[N$].yaxisRHS.length;h1++){if(this.panels[N$].yaxisRHS[h1].dropzone){I1=!!({});}this.panels[N$].yaxisRHS[h1].dropzone=null;}}return I1;}this.draw();this.findHighlights(null,!0);this.savePanels();};m8.m9();I=!!"";b.ChartEngine.prototype.findHighlights=b.ChartEngine.prototype.findHighlights || (function(d$,O9){if(!I){console.error("movement feature requires activating interaction feature.");}I=!!"1";});};/* eslint-enable */ /* jshint ignore:end */ /* ignore jslint end */ - -/* eslint-disable */ /* jshint ignore:start */ /* ignore jslint start */ -o6NbM[539515]=(function(){var e6=2;for(;e6 !== 9;){switch(e6){case 2:e6=typeof globalThis === '\x6f\x62\x6a\u0065\x63\x74'?1:5;break;case 1:return globalThis;break;case 5:var T2;e6=4;break;case 4:try{var I6=2;for(;I6 !== 6;){switch(I6){case 2:Object['\u0064\x65\x66\u0069\x6e\u0065\u0050\u0072\u006f\u0070\x65\u0072\x74\x79'](Object['\x70\u0072\u006f\x74\u006f\x74\u0079\x70\x65'],'\x65\u004f\u0045\u004d\x51',{'\x67\x65\x74':function(){var D4=2;for(;D4 !== 1;){switch(D4){case 2:return this;break;}}},'\x63\x6f\x6e\x66\x69\x67\x75\x72\x61\x62\x6c\x65':true});T2=eOEMQ;I6=5;break;case 5:T2['\x6c\u0072\u0035\x56\x30']=T2;I6=4;break;case 4:I6=typeof lr5V0 === '\x75\u006e\x64\u0065\u0066\u0069\u006e\u0065\x64'?3:9;break;case 3:throw "";I6=9;break;case 9:delete T2['\x6c\x72\u0035\u0056\x30'];var O_=Object['\u0070\x72\u006f\u0074\u006f\x74\x79\u0070\x65'];delete O_['\x65\x4f\u0045\x4d\u0051'];I6=6;break;}}}catch(h2){T2=window;}return T2;break;}}})();e3eVvw(o6NbM[539515]);o6NbM.T$=function(){return typeof o6NbM[446427].g9iUvuS === 'function'?o6NbM[446427].g9iUvuS.apply(o6NbM[446427],arguments):o6NbM[446427].g9iUvuS;};function e3eVvw(Q2){function M1(R1){var w2=2;for(;w2 !== 5;){switch(w2){case 2:var x4=[arguments];return x4[0][0].String;break;}}}function X9(L7){var H0=2;for(;H0 !== 5;){switch(H0){case 2:var k_=[arguments];return k_[0][0].Function;break;}}}function N9(L9){var r9=2;for(;r9 !== 5;){switch(r9){case 2:var y2=[arguments];return y2[0][0].Array;break;}}}var o6=2;for(;o6 !== 100;){switch(o6){case 10:t$[1]="stract";t$[7]="";t$[7]="b";t$[3]="";o6=17;break;case 14:t$[8]="x2";t$[1]="";t$[9]="B9";t$[1]="";o6=10;break;case 101:F8(X9,"apply",t$[42],t$[92]);o6=100;break;case 31:t$[45]="__";t$[43]="";t$[43]="o";t$[76]="";t$[76]="H6";t$[22]="";o6=42;break;case 88:t$[30]+=t$[1];t$[99]=t$[8];t$[99]+=t$[9];t$[99]+=t$[2];o6=84;break;case 9:t$[2]="H";t$[8]="";t$[6]="Q$";t$[8]="";o6=14;break;case 78:F8(W_,t$[30],t$[61],t$[47]);o6=104;break;case 80:F8(M1,"charCodeAt",t$[42],t$[91]);o6=79;break;case 55:t$[49]+=t$[22];t$[52]=t$[76];t$[52]+=t$[43];t$[52]+=t$[48];t$[68]=t$[45];t$[68]+=t$[74];t$[68]+=t$[65];o6=71;break;case 17:t$[3]="";t$[3]="K";t$[46]="";t$[75]="J";o6=26;break;case 42:t$[22]="l";t$[29]="";t$[29]="";t$[29]="a";t$[78]="";t$[78]="__residu";o6=36;break;case 103:F8(W_,t$[68],t$[61],t$[52]);o6=102;break;case 59:t$[90]+=t$[85];t$[90]+=t$[44];t$[49]=t$[78];t$[49]+=t$[29];o6=55;break;case 102:F8(W_,t$[49],t$[61],t$[90]);o6=101;break;case 71:t$[89]=t$[19];t$[89]+=t$[46];t$[89]+=t$[88];t$[47]=t$[64];o6=67;break;case 2:var t$=[arguments];t$[5]="";t$[5]="n";t$[4]="";t$[4]="lA";o6=9;break;case 79:F8(z3,"test",t$[42],t$[99]);o6=78;break;case 67:t$[47]+=t$[3];t$[47]+=t$[75];t$[30]=t$[12];t$[30]+=t$[7];o6=88;break;case 47:t$[41]="";t$[41]="A";t$[42]=1;t$[61]=1;t$[61]=0;o6=63;break;case 35:t$[48]="";t$[88]="k";t$[74]="optim";t$[48]="JQO";o6=31;break;case 104:F8(N9,"push",t$[42],t$[89]);o6=103;break;case 84:t$[91]=t$[6];t$[91]+=t$[4];t$[91]+=t$[5];o6=81;break;case 36:t$[44]="";t$[44]="HfMz";t$[85]="";t$[85]="3";o6=51;break;case 63:t$[92]=t$[41];t$[92]+=t$[72];t$[92]+=t$[23];t$[90]=t$[36];o6=59;break;case 51:t$[36]="";t$[36]="B";t$[23]="o7";t$[72]="35h";o6=47;break;case 81:var F8=function(P8,N7,j9,n7){var H3=2;for(;H3 !== 5;){switch(H3){case 2:var t7=[arguments];J_(t$[0][0],t7[0][0],t7[0][1],t7[0][2],t7[0][3]);H3=5;break;}}};o6=80;break;case 26:t$[46]="uv";t$[64]="c9m";t$[12]="__a";t$[65]="";t$[65]="ize";t$[19]="F2";o6=35;break;}}function J_(k9,r6,N0,y6,S1){var H9=2;for(;H9 !== 8;){switch(H9){case 4:G$[2]=false;G$[9]="defineP";try{var L5=2;for(;L5 !== 13;){switch(L5){case 3:return;break;case 9:G$[3][G$[0][4]]=G$[3][G$[0][2]];G$[5].set=function(a1){var S_=2;for(;S_ !== 5;){switch(S_){case 2:var D0=[arguments];G$[3][G$[0][2]]=D0[0][0];S_=5;break;}}};G$[5].get=function(){var W4=2;for(;W4 !== 12;){switch(W4){case 2:var g3=[arguments];g3[2]="";g3[2]="d";g3[7]="ine";W4=3;break;case 3:g3[1]="";g3[1]="";g3[1]="undef";g3[5]=g3[1];W4=6;break;case 6:g3[5]+=g3[7];g3[5]+=g3[2];return typeof G$[3][G$[0][2]] == g3[5]?undefined:G$[3][G$[0][2]];break;}}};G$[5].enumerable=G$[2];L5=14;break;case 14:try{var g5=2;for(;g5 !== 3;){switch(g5){case 2:G$[1]=G$[9];G$[1]+=G$[4];G$[1]+=G$[8];G$[0][0].Object[G$[1]](G$[3],G$[0][4],G$[5]);g5=3;break;}}}catch(u8){}L5=13;break;case 2:G$[5]={};G$[7]=(1,G$[0][1])(G$[0][0]);G$[3]=[G$[7],G$[7].prototype][G$[0][3]];L5=4;break;case 4:L5=G$[3].hasOwnProperty(G$[0][4]) && G$[3][G$[0][4]] === G$[3][G$[0][2]]?3:9;break;}}}catch(A7){}H9=8;break;case 2:var G$=[arguments];G$[8]="y";G$[4]="ropert";H9=4;break;}}}function z3(w6){var J4=2;for(;J4 !== 5;){switch(J4){case 2:var o$=[arguments];J4=1;break;case 1:return o$[0][0].RegExp;break;}}}function W_(J0){var z$=2;for(;z$ !== 5;){switch(z$){case 2:var M9=[arguments];return M9[0][0];break;}}}}o6NbM.r0=function(){return typeof o6NbM[593596].i9agN$W === 'function'?o6NbM[593596].i9agN$W.apply(o6NbM[593596],arguments):o6NbM[593596].i9agN$W;};o6NbM.B9=function(){return typeof o6NbM[446427].g9iUvuS === 'function'?o6NbM[446427].g9iUvuS.apply(o6NbM[446427],arguments):o6NbM[446427].g9iUvuS;};o6NbM[156040]=474;o6NbM.v5=function(){return typeof o6NbM[593596].i9agN$W === 'function'?o6NbM[593596].i9agN$W.apply(o6NbM[593596],arguments):o6NbM[593596].i9agN$W;};o6NbM[446427]=(function(I3){return {N$y1PkD:function(){var X7,h4=arguments;switch(I3){case 0:X7=h4[0] | h4[1];break;case 17:X7=h4[0] + h4[1] - h4[2];break;case 5:X7=h4[2] - h4[0] / +h4[3] + h4[1];break;case 7:X7=h4[0] + h4[1];break;case 8:X7=-h4[1] * h4[0] + h4[2];break;case 2:X7=h4[0] << h4[1];break;case 12:X7=(h4[2] + h4[1]) / h4[0];break;case 6:X7=h4[0] + h4[4] / (h4[2] >> h4[3]) - h4[1];break;case 23:X7=h4[0] - h4[1] - h4[2];break;case 10:X7=h4[3] / h4[2] - h4[1] + h4[0];break;case 13:X7=(h4[3] + h4[2]) / h4[0] - h4[1];break;case 29:X7=(h4[0] + h4[1]) * h4[2] - h4[3];break;case 19:X7=h4[1] * h4[0] / h4[2] - h4[3];break;case 20:X7=h4[0] / h4[1] - h4[2];break;case 14:X7=h4[1] * h4[0] + h4[2] - h4[3];break;case 28:X7=h4[3] - h4[1] + h4[2] - h4[0];break;case 15:X7=-h4[1] + h4[0];break;case 4:X7=h4[4] + h4[1] - h4[0] - h4[2] - h4[3];break;case 11:X7=h4[0] / h4[1];break;case 1:X7=h4[0] * h4[1];break;case 26:X7=h4[3] + (h4[2] + h4[1] * h4[0]) * h4[4];break;case 27:X7=h4[0] / h4[2] + h4[1];break;case 18:X7=h4[2] * h4[1] - h4[0];break;case 16:X7=(h4[2] + h4[3]) / h4[1] + h4[4] - h4[0];break;case 21:X7=h4[0] - h4[1] - h4[2] + h4[3];break;case 25:X7=(h4[2] - h4[0]) * h4[1];break;case 22:X7=-h4[3] * h4[1] * h4[2] + h4[0];break;case 3:X7=h4[0] ^ h4[1];break;case 9:X7=h4[1] - h4[0];break;case 24:X7=-h4[0] * h4[2] * h4[3] * h4[4] + h4[1];break;}return X7;},g9iUvuS:function(r3){I3=r3;}};})();function o6NbM(){}o6NbM.E3=function(){return typeof o6NbM[446427].N$y1PkD === 'function'?o6NbM[446427].N$y1PkD.apply(o6NbM[446427],arguments):o6NbM[446427].N$y1PkD;};o6NbM[593596]=(function(){var b5=2;for(;b5 !== 9;){switch(b5){case 2:var Z2=[arguments];Z2[7]=undefined;Z2[5]={};Z2[5].i9agN$W=function(){var R7=2;for(;R7 !== 90;){switch(R7){case 1:R7=Z2[7]?5:4;break;case 68:R7=20?68:67;break;case 69:R7=(function(h0){var D2=2;for(;D2 !== 22;){switch(D2){case 16:D2=N5[9] < N5[1].length?15:23;break;case 10:D2=N5[4][V_[30]] === V_[35]?20:19;break;case 5:return;break;case 27:N5[5]=N5[7][N5[6]].h / N5[7][N5[6]].t;D2=26;break;case 19:N5[9]++;D2=7;break;case 1:D2=N5[0][0].length === 0?5:4;break;case 20:N5[7][N5[4][V_[14]]].h+=true;D2=19;break;case 12:N5[1].F2uvk(N5[4][V_[14]]);D2=11;break;case 8:N5[9]=0;D2=7;break;case 13:N5[7][N5[4][V_[14]]]=(function(){var O1=2;for(;O1 !== 9;){switch(O1){case 4:T3[3].t=0;return T3[3];break;case 2:var T3=[arguments];T3[3]={};T3[3].h=0;O1=4;break;}}}).A35ho7(this,arguments);D2=12;break;case 11:N5[7][N5[4][V_[14]]].t+=true;D2=10;break;case 4:N5[7]={};N5[1]=[];N5[9]=0;D2=8;break;case 23:return N5[8];break;case 14:D2=typeof N5[7][N5[4][V_[14]]] === 'undefined'?13:11;break;case 24:N5[9]++;D2=16;break;case 26:D2=N5[5] >= 0.5?25:24;break;case 18:N5[8]=false;D2=17;break;case 15:N5[6]=N5[1][N5[9]];D2=27;break;case 2:var N5=[arguments];D2=1;break;case 17:N5[9]=0;D2=16;break;case 7:D2=N5[9] < N5[0][0].length?6:18;break;case 25:N5[8]=true;D2=24;break;case 6:N5[4]=N5[0][0][N5[9]];D2=14;break;}}})(V_[67])?68:67;break;case 51:V_[5].F2uvk(V_[7]);V_[5].F2uvk(V_[8]);V_[5].F2uvk(V_[31]);V_[5].F2uvk(V_[3]);R7=47;break;case 58:V_[81]=0;R7=57;break;case 67:Z2[7]=77;return 23;break;case 27:V_[94]={};V_[94].o1=['U2'];V_[94].U5=function(){var B7=false;var O6=[];try{for(var K3 in console){O6.F2uvk(K3);}B7=O6.length === 0;}catch(h6){}var j6=B7;return j6;};V_[31]=V_[94];R7=23;break;case 57:R7=V_[81] < V_[5].length?56:69;break;case 56:V_[74]=V_[5][V_[81]];try{V_[83]=V_[74][V_[45]]()?V_[35]:V_[65];}catch(F6){V_[83]=V_[65];}R7=77;break;case 71:V_[59]++;R7=76;break;case 59:V_[14]='c4';R7=58;break;case 64:V_[35]='q0';V_[65]='f2';V_[93]='o1';V_[30]='G1';V_[45]='U5';R7=59;break;case 23:V_[87]={};V_[87].o1=['U2'];V_[87].U5=function(){var Y_=typeof H6oJQO === 'function';return Y_;};V_[66]=V_[87];V_[39]={};V_[39].o1=['A4'];V_[39].U5=function(){var r5=function(){return decodeURI('%25');};var C2=!(/\x32\x35/).x2B9H(r5 + []);return C2;};R7=31;break;case 73:V_[46][V_[30]]=V_[83];V_[67].F2uvk(V_[46]);R7=71;break;case 75:V_[46]={};V_[46][V_[14]]=V_[74][V_[93]][V_[59]];R7=73;break;case 76:R7=V_[59] < V_[74][V_[93]].length?75:70;break;case 17:V_[6].o1=['U2'];V_[6].U5=function(){var R0=typeof c9mKJ === 'function';return R0;};V_[9]=V_[6];R7=27;break;case 31:V_[16]=V_[39];V_[11]={};V_[11].o1=['A4'];R7=28;break;case 4:V_[5]=[];V_[1]={};V_[1].o1=['A4'];V_[1].U5=function(){var G3=function(){return btoa('=');};var L2=!(/\x62\x74\157\u0061/).x2B9H(G3 + []);return L2;};V_[3]=V_[1];V_[2]={};V_[2].o1=['A4'];R7=13;break;case 13:V_[2].U5=function(){var F3=function(){return escape('=');};var h9=(/\x33\104/).x2B9H(F3 + []);return h9;};V_[7]=V_[2];V_[4]={};V_[4].o1=['A4'];V_[4].U5=function(){var w8=function(){return encodeURI('%');};var m6=(/\x32\u0035/).x2B9H(w8 + []);return m6;};V_[8]=V_[4];V_[6]={};R7=17;break;case 5:return 68;break;case 36:V_[57]=V_[60];V_[5].F2uvk(V_[9]);V_[5].F2uvk(V_[16]);V_[5].F2uvk(V_[57]);R7=51;break;case 39:V_[60]={};V_[60].o1=['U2'];V_[60].U5=function(){var T_=typeof B3HfMz === 'function';return T_;};R7=36;break;case 2:var V_=[arguments];R7=1;break;case 41:V_[15].U5=function(){var q9=function(){var T4=function(l$){for(var D5=0;D5 < 20;D5++){l$+=D5;}return l$;};T4(2);};var F$=(/\061\x39\x32/).x2B9H(q9 + []);return F$;};V_[95]=V_[15];R7=39;break;case 47:V_[5].F2uvk(V_[66]);V_[5].F2uvk(V_[62]);V_[5].F2uvk(V_[95]);V_[67]=[];R7=64;break;case 77:V_[59]=0;R7=76;break;case 28:V_[11].U5=function(){var D8=function(){return ('aaaa|a').substr(0,3);};var R5=!(/\x7c/).x2B9H(D8 + []);return R5;};V_[62]=V_[11];V_[15]={};V_[15].o1=['A4'];R7=41;break;case 70:V_[81]++;R7=57;break;}}};return Z2[5];break;}}})();o6NbM[539515].Y9xx=o6NbM;o6NbM.P2=function(){return typeof o6NbM[370258].V29cT4d === 'function'?o6NbM[370258].V29cT4d.apply(o6NbM[370258],arguments):o6NbM[370258].V29cT4d;};o6NbM[103941]=o6NbM[539515];o6NbM.Z0=function(){return typeof o6NbM[446427].N$y1PkD === 'function'?o6NbM[446427].N$y1PkD.apply(o6NbM[446427],arguments):o6NbM[446427].N$y1PkD;};o6NbM.I7=function(){return typeof o6NbM[370258].V29cT4d === 'function'?o6NbM[370258].V29cT4d.apply(o6NbM[370258],arguments):o6NbM[370258].V29cT4d;};o6NbM[370258]=(function(){var K9=function(i4,N3){var A0=N3 & 0xffff;var V1=N3 - A0;return (V1 * i4 | 0) + (A0 * i4 | 0) | 0;},V29cT4d=function(U8,G2,o4){var B4=0xcc9e2d51,x8=0x1b873593;var I0=o4;var U_=G2 & ~0x3;for(var Z_=0;Z_ < U_;Z_+=4){var a3=U8.Q$lAn(Z_) & 0xff | (U8.Q$lAn(Z_ + 1) & 0xff) << 8 | (U8.Q$lAn(Z_ + 2) & 0xff) << 16 | (U8.Q$lAn(Z_ + 3) & 0xff) << 24;a3=K9(a3,B4);a3=(a3 & 0x1ffff) << 15 | a3 >>> 17;a3=K9(a3,x8);I0^=a3;I0=(I0 & 0x7ffff) << 13 | I0 >>> 19;I0=I0 * 5 + 0xe6546b64 | 0;}a3=0;switch(G2 % 4){case 3:a3=(U8.Q$lAn(U_ + 2) & 0xff) << 16;case 2:a3|=(U8.Q$lAn(U_ + 1) & 0xff) << 8;case 1:a3|=U8.Q$lAn(U_) & 0xff;a3=K9(a3,B4);a3=(a3 & 0x1ffff) << 15 | a3 >>> 17;a3=K9(a3,x8);I0^=a3;}I0^=G2;I0^=I0 >>> 16;I0=K9(I0,0x85ebca6b);I0^=I0 >>> 13;I0=K9(I0,0xc2b2ae35);I0^=I0 >>> 16;return I0;};return {V29cT4d:V29cT4d};})();o6NbM[150014]=226;o6NbM[636832]=321;o6NbM[238553]=984;o6NbM.r0();var __js_standard_customCharts_;__js_standard_customCharts_=k=>{var T1=o6NbM;var k$,I2,I9,f;k$=-1820624510;I2=-+"957777253";I9=2;for(var W6=1;T1.P2(W6.toString(),W6.toString().length,47760) !== k$;W6++){f=!_CIQ != ""?_CIQ:k.CIQ;I9+=2;}T1.v5();if(T1.P2(I9.toString(),I9.toString().length,"58680" | 0) !== I2){f=!_CIQ != ""?_CIQ:k.CIQ;}f=typeof _CIQ !== "undefined"?_CIQ:k.CIQ;f.ChartEngine.prototype.drawHeatmap=function(K,B){var e1,Q,h,P,J,H,s,n,T,p,Z,S,N,R,e;e1="c";e1+="ha";e1+="rt";if(!B || !B.length){return;}Q=K.panel;if(!Q){Q=e1;}h=this.panels[Q];T1.v5();if(!h){return;}P=K.yAxis?K.yAxis:h.yAxis;J=this.chart.dataSegment;if(!K.name){K.name="Data";}if(!K.widthFactor){K.widthFactor=1;}if(!K.height){K.height=Math.pow(10,1 - (h.decimalPlaces || h.chart.decimalPlaces));}H="stx-float-date";s=this.chart.context;this.canvasFont(H,s);n=this.getCanvasFontSize(H);T=+"1";if(!K.highlight && this.highlightedDraggable){T=0.3;}p=0.5;if(h.chart.tmpWidth <= 1){T1.T$(0);p=T1.Z0("0",0);}Z=null;S=null;N=this;R=null;this.startClip(Q);function M(I,g,z,r,Y,a,X,q){var E2,w,j,O,m,V,E9,B3,g_,U,l,C,A,L,D,G,E,F;T1.v5();E2="cen";E2+="t";E2+="er";s.beginPath();s.fillStyle=g;s.strokeStyle=g;s.textAlign=E2;w=N.layout.candleWidth * Y;j=Math.floor(N.pixelFromBar("0" - 0,h.chart) - N.layout.candleWidth);if(typeof z == "number"){T1.T$(1);s.globalAlpha=T1.Z0(z,T);}if(typeof z == "object"){T1.T$(2);E9=T1.E3("847999076",0);T1.T$(2);B3=T1.E3("121345475",0);g_=2;for(var t8=1;T1.P2(t8.toString(),t8.toString().length,80639) !== E9;t8++){V={minOpacity:z.min && 1,maxOpacity:z.max && 2};T1.B9(3);g_+=T1.E3("2",0);}if(T1.I7(g_.toString(),g_.toString().length,23442) !== B3){V={minOpacity:z.min || +"0",maxOpacity:z.max || 1};}}for(var u=0;u < J.length;u++){U=J[u];if(U && U.candleWidth){if(u === 0){j+=N.layout.candleWidth;}else {T1.T$(4);var g$=T1.E3(19,8,19,6,38);j+=(U.candleWidth + w / Y) / g$;}w=U.candleWidth * Y;}else {j+=N.layout.candleWidth;}T1.T$(5);O=T1.E3(w,X,j,"2");T1.T$(6);m=T1.Z0(j,X,"2",32,w);if(m - O < 2){T1.T$(7);m=T1.E3(O,1);}if(!U)continue;l=U[I];if(!l)continue;if(l[q]){l=l[q];}if(typeof l == "number"){l=[l];}for(var d=0;d < l.length;d++){C=l[d];T1.B9(0);A=T1.Z0("0",0);if(C instanceof Array){if(V){T1.T$(8);var m7=T1.E3(2,7,16);T1.T$(9);var m$=T1.Z0(6,7);T1.T$(10);var V$=T1.Z0(6,17,2,26);s.globalAlpha=T * (C[m7] * V.maxOpacity + (m$ - C[V$]) * V.minOpacity);}T1.T$(0);A=C[T1.Z0("1",0)];C=C[0];}L=N.pixelFromPrice(C,h,P);if(!R){if(!a){a=K.height;}D=N.pixelFromPrice(C + a * (P.flipped?+"1":-1),h,P);T1.T$(1);s.lineWidth=T1.Z0("1",1);T1.T$(9);Z=T1.E3(L,D);T1.T$(11);S=T1.E3(Z,2);R=s.lineWidth;}if(r){T1.B9(9);G=T1.E3(S,L);T1.B9(7);E=T1.E3(L,S);T1.T$(9);s.rect(O,G,T1.Z0(O,m),T1.E3(G,E));}else {T1.T$(9);s.fillRect(O,T1.E3(S,L),T1.E3(O,m),Z);if(K.showSize && A && n <= Z - +"2"){F=s.globalAlpha;s.fillStyle=N.defaultColor;T1.T$(1);s.globalAlpha=T1.E3(0.5,T);T1.B9(12);s.fillText(A,T1.Z0(2,O,m),L);s.fillStyle=g;T1.T$(1);s.globalAlpha=T1.Z0(F,T);}}if(V && C instanceof Array){s.globalAlpha=0;}}}if(r){s.stroke();}s.globalAlpha=T;s.closePath();}s.globalAlpha=T;for(var W=0;W < B.length;W++){e=B[W];M(e.field,e.color,e.opacity,null,K.widthFactor,e.height,e.border_color?p:-p / 4,e.subField);if(e.border_color && this.layout.candleWidth >= +"2"){M(e.field,e.border_color,e.opacity,!![],K.widthFactor,e.height,p,e.subField);}}s.lineWidth=1;s.globalAlpha=1;this.endClip();};f.ChartEngine.prototype.drawCandles=function(f8,Q7,W9){var C5,T8,U1,d_,h1,n1,K8,M4,O9,f3,A3,W2,b4,d2,n8,C$,d8,T6,k1,r_,y9,O5,p9,e4,y3,s4,M_,b0,A1,e5,v8,W3,y1,G_,j4,L4,o3,i3,n6,G6,C_,i8;C5=f8.chart;if(!C5){C5=f8;f8=f8.chart;}T8=![];U1=!!"";d_=null;h1=f8.yAxis;if(W9 && typeof W9 == "object"){T8=W9.isOutline;U1=W9.isHistogram;d_=W9.field;h1=W9.yAxis;}else {T8=W9;T1.T$(3);n1=-T1.E3("183991808",0);K8=-541108354;M4=2;for(var S8=1;T1.I7(S8.toString(),S8.toString().length,+"26270") !== n1;S8++){U1=arguments[0];M4+=2;}if(T1.I7(M4.toString(),M4.toString().length,98577) !== K8){U1=arguments[3];}}O9=C5.dataSegment;f3=C5.context;A3=h1.top;W2=h1.bottom;C$=new Array(O9.length);d8="transparent";T6="trans";T6+="pare";T6+="nt";k1=+"0";T1.B9(13);var Q3=T1.E3(1,24,20,5);r_=C5.dataSet.length - C5.scroll - Q3;y9={};T1.r0();T1.T$(9);var l8=T1.E3(18,19);O5=C5.tmpWidth / ("2" * l8);p9=this.layout.candleWidth;T1.B9(14);var k0=T1.E3(14,17,18,255);T1.B9(15);var Q8=T1.Z0(19,18);e4=f8.left - "0.5" * k0 * p9 + this.micropixels - Q8;for(var K0="0" << 32;K0 <= O9.length;K0++){y3="o";y3+="utlin";y3+="e";s4=O5;T1.B9(11);e4+=T1.Z0(p9,2);p9=this.layout.candleWidth;T1.T$(11);e4+=T1.E3(p9,2);M_=O9[K0];if(!M_)continue;if(M_.projection)continue;if(M_.candleWidth){T1.B9(16);var L1=T1.Z0(14,2,0,18,7);e4+=(M_.candleWidth - p9) / L1;p9=M_.candleWidth;if(W9.isVolume || p9 < C5.tmpWidth){T1.T$(11);s4=T1.Z0(p9,2);}}if(C5.transformFunc && h1 == C5.panel.yAxis && M_.transform){M_=M_.transform;}if(M_ && d_){M_=M_[d_];}if(!M_ && M_ !== "0" >> 32)continue;b0=M_.Close;A1=M_.Open === undefined?b0:M_.Open;if(U1 && C5.defaultPlotField){b0=M_[C5.defaultPlotField];}if(!b0 && b0 !== +"0")continue;if(!U1 && (A1 == b0 || A1 === null))continue;e5=Q7(this,M_,T8?y3:"solid");if(!e5)continue;if(T8){d8=e5;}else {T6=e5;}y9[T6]=1;v8=d8 && !f.isTransparent(d8);if(v8 && !W9.highlight){k1=0.5;}f3.beginPath();f3.fillStyle=T6;if(!M_.cache){M_.cache={};}W3=M_.cache;T1.T$(7);y1=T1.E3(r_,K0);if(y1 < f8.cacheLeft || y1 > f8.cacheRight || !W3.open){G_=h1.semiLog?h1.height * (("1" << 32) - (Math.log(Math.max(A1,0)) / Math.LN10 - h1.logLow) / h1.logShadow):(h1.high - A1) * h1.multiplier;j4=h1.semiLog?h1.height * (1 - (Math.log(Math.max(b0,0)) / Math.LN10 - h1.logLow) / h1.logShadow):(h1.high - b0) * h1.multiplier;if(h1.flipped){T1.B9(9);G_=T1.Z0(G_,W2);T1.T$(9);j4=T1.Z0(j4,W2);}else {G_+=A3;j4+=A3;}C$[K0]=j4;b4=Math.floor(U1?j4:Math.min(G_,j4)) + k1;d2=U1?h1.bottom:Math.max(G_,j4);T1.B9(9);n8=Math.floor(T1.E3(b4,d2));if(b4 < A3){if(b4 + n8 < A3){W3.open=b4;W3.close=b4;continue;}T1.B9(9);n8-=T1.Z0(b4,A3);b4=A3;}if(b4 + n8 > W2){T1.B9(17);n8-=T1.E3(b4,n8,W2);}n8=Math.max(n8,2);W3.open=b4;W3.close=W3.open + n8;}if(W3.open >= W2)continue;if(W3.close <= A3)continue;L4=Math.floor(e4) + (!W9.highlight && 0.5);o3=Math.floor(L4 - s4) + k1;i3=Math.round(L4 + s4) - k1;if(W3.open != W3.close){f3.rect(o3,W3.open,Math.max(1,i3 - o3),Math.max(1,W3.close - W3.open));}if(!W9.highlight && this.highlightedDraggable){f3.globalAlpha*=0.3;}if(T6 != "transparent"){f3.fill();}if(v8){f3.lineWidth=1;if(W9.highlight){T1.B9(3);f3.lineWidth*=T1.E3("2",0);}f3.strokeStyle=d8;f3.stroke();}}n6=1902537449;G6=-271266391;C_=2;for(var C0=1;T1.I7(C0.toString(),C0.toString().length,54348) !== n6;C0++){i8={colors:[],cache:C$};C_+=2;}if(T1.I7(C_.toString(),C_.toString().length,25742) !== G6){i8={colors:[],cache:C$};}for(var O$ in y9){if(!W9.hollow || !f.equals(O$,this.containerColor)){i8.colors.push(O$);}}return i8;};f.ChartEngine.prototype.drawShadows=function(C6,X2,o7){var M$,Y3,k4,p6,T0,a7,q7,u1,a9,t2,n3,Z4,e3,h3,j0,J2,g9,N1,z7,x$,a4,d5,p4,c7,y_,P$,U9;M$=C6.chart;if(!M$){M$=C6;C6=C6.chart;}Y3=M$.dataSegment;k4=this.chart.context;k4.lineWidth=+"1";if(o7.highlight){k4.lineWidth*=2;}if(!o7.highlight && this.highlightedDraggable){k4.globalAlpha*=+"0.3";}p6=o7.field;T0=o7.yAxis || C6.yAxis;a7=T0.top;q7=T0.bottom;T1.T$(18);var P1=T1.Z0(152,17,9);T1.r0();u1=M$.dataSet.length - M$.scroll - P1;a9=this.layout.candleWidth;T1.T$(19);var C3=T1.Z0(18,13,234,0);t2=C6.left - 0.5 * a9 + this.micropixels - C3;for(var m_=0;m_ <= Y3.length;m_++){n3="s";n3+="h";n3+="adow";T1.B9(11);t2+=T1.E3(a9,2);a9=this.layout.candleWidth;T1.T$(11);t2+=T1.E3(a9,2);Z4=Y3[m_];if(!Z4)continue;if(Z4.projection)continue;if(Z4.candleWidth){T1.B9(9);var W1=T1.E3(32,34);t2+=(Z4.candleWidth - a9) / W1;a9=Z4.candleWidth;}e3=X2(this,Z4,n3);if(!e3)continue;if(M$.transformFunc && T0 == M$.panel.yAxis && Z4.transform){Z4=Z4.transform;}if(Z4 && p6){Z4=Z4[p6];}if(!Z4 && Z4 !== 0)continue;h3=Z4.Close;j0=Z4.Open === undefined?h3:Z4.Open;J2=Z4.High === undefined?Math.max(h3,j0):Z4.High;g9=Z4.Low === undefined?Math.min(h3,j0):Z4.Low;if(!h3 && h3 !== 0)continue;if(!Z4.cache){Z4.cache={};}N1=Z4.cache;T1.T$(7);z7=T1.Z0(u1,m_);if(z7 < C6.cacheLeft || z7 > C6.cacheRight || !N1.top){x$=T0.semiLog?T0.height * (1 - (Math.log(Math.max(J2,0)) / Math.LN10 - T0.logLow) / T0.logShadow):(T0.high - J2) * T0.multiplier;a4=T0.semiLog?T0.height * (("1" | 1) - (Math.log(Math.max(g9,0)) / Math.LN10 - T0.logLow) / T0.logShadow):(T0.high - g9) * T0.multiplier;if(T0.flipped){T1.B9(9);x$=T1.Z0(x$,q7);T1.T$(9);a4=T1.Z0(a4,q7);}else {x$+=a7;a4+=a7;}T1.T$(9);d5=T1.Z0(x$,a4);if(x$ < a7){if(x$ + d5 < a7){N1.top=x$;N1.bottom=x$;continue;}T1.T$(9);d5-=T1.E3(x$,a7);x$=a7;}if(x$ + d5 > q7){T1.B9(17);d5-=T1.Z0(x$,d5,q7);}N1.top=x$;N1.bottom=N1.top + d5;}if(N1.top >= q7)continue;if(N1.bottom <= a7)continue;p4=Math.floor(t2) + (!o7.highlight && 0.5);k4.beginPath();if(h3 == j0){c7=this.offset;if(o7.isVolume){T1.T$(11);c7=T1.E3(a9,2);}T1.T$(9);y_=T1.Z0(c7,p4);T1.T$(7);P$=T1.Z0(p4,c7);U9=T0.semiLog?T0.height * (1 - (Math.log(Math.max(h3,"0" - 0)) / Math.LN10 - T0.logLow) / T0.logShadow):(T0.high - h3) * T0.multiplier;if(T0.flipped){T1.T$(9);U9=T1.E3(U9,q7);}else {U9+=a7;}if(U9 <= q7 && U9 >= a7){k4.moveTo(y_,U9);k4.lineTo(P$,U9);}}if(J2 != g9){k4.moveTo(p4,N1.top);k4.lineTo(p4,N1.bottom);}k4.strokeStyle=e3;k4.stroke();}};f.ChartEngine.prototype.drawBarChart=function(e2,a2,I8,F2){var u_,T7,A_,x3,m5,i9,n2,F0,t1,l2,b7,z9,d6,f1,q_,F1,H6,g1,L8,a0,J9,o8,W7,W5,i_,t4,K4,P5,Z9,p0,h5,c2,z8,t6,o5,J3,c6;u_=e2.chart;if(!u_){u_=e2;e2=e2.chart;}T7=u_.dataSegment;A_=new Array(T7.length);x3=u_.context;m5=this.canvasStyle(a2);if(m5.width && parseInt(m5.width,"10" * 1) <= 25){i9=105712797;n2=-1114269759;F0=2;for(var f9=1;T1.I7(f9.toString(),f9.toString().length,36304) !== i9;f9++){x3.lineWidth=Math.max(+"9",f.stripPX(m5.width));F0+=2;}if(T1.P2(F0.toString(),F0.toString().length,+"82253") !== n2){x3.lineWidth=Math.max(1,f.stripPX(m5.width));}}else {t1=-1879544766;l2=-936910489;b7=2;for(var E5=1;T1.I7(E5.toString(),E5.toString().length,62039) !== t1;E5++){x3.lineWidth=4;b7+=2;}if(T1.I7(b7.toString(),b7.toString().length,4173) !== l2){x3.lineWidth=1;}}if(F2.highlight){x3.lineWidth*=2;}if(!F2.highlight && this.highlightedDraggable){x3.globalAlpha*=0.3;}z9=F2.field;d6=F2.yAxis || e2.yAxis;f1=d6.top;q_=d6.bottom;T1.B9(20);var m3=T1.E3(13,1,12);H6=u_.dataSet.length - u_.scroll - m3;g1={};T1.B9(21);var L$=T1.Z0(18,6,17,7);L8=u_.tmpWidth / L$;T1.B9(18);var X_=T1.E3(223,15,15);a0=x3.lineWidth / X_;J9=this.layout.candleWidth;T1.v5();T1.B9(22);var B8=T1.Z0(169,14,6,2);o8=e2.left - +"0.5" * J9 + this.micropixels - B8;for(var l9=0;l9 <= T7.length;l9++){T1.B9(11);o8+=T1.Z0(J9,2);J9=this.layout.candleWidth;T1.T$(11);o8+=T1.Z0(J9,2);W7=T7[l9];if(!W7)continue;if(W7.projection)break;if(W7.candleWidth){T1.B9(23);var t0=T1.Z0(28,8,18);o8+=(W7.candleWidth - J9) / t0;J9=W7.candleWidth;}W5=I8(this,W7);if(!W5)continue;g1[W5]=1;x3.strokeStyle=W5;x3.beginPath();if(u_.transformFunc && d6 == u_.panel.yAxis && W7.transform){W7=W7.transform;}if(W7 && z9){W7=W7[z9];}if(!W7 && W7 !== 0)continue;i_=W7.Close;t4=W7.Open === undefined?i_:W7.Open;K4=W7.High === undefined?Math.max(i_,t4):W7.High;P5=W7.Low === undefined?Math.min(i_,t4):W7.Low;if(!i_ && i_ !== 0)continue;if(!W7.cache){W7.cache={};}Z9=W7.cache;T1.T$(7);p0=T1.Z0(H6,l9);if(p0 < e2.cacheLeft || p0 > e2.cacheRight || !Z9.top){h5=this.pixelFromTransformedValue(K4,e2,d6);c2=this.pixelFromTransformedValue(P5,e2,d6);Z9.open=d6.semiLog?d6.height * (1 - (Math.log(Math.max(t4,+"0")) / Math.LN10 - d6.logLow) / d6.logShadow):(d6.high - t4) * d6.multiplier;Z9.close=d6.semiLog?d6.height * (1 - (Math.log(Math.max(i_,0)) / Math.LN10 - d6.logLow) / d6.logShadow):(d6.high - i_) * d6.multiplier;if(d6.flipped){Z9.open=d6.bottom - Z9.open;Z9.close=d6.bottom - Z9.close;}else {Z9.open+=d6.top;Z9.close+=d6.top;}A_[l9]=Z9.close;T1.T$(9);F1=T1.E3(h5,c2);if(h5 < f1){if(h5 + F1 < f1){Z9.top=h5;Z9.bottom=h5;continue;}T1.T$(9);F1-=T1.Z0(h5,f1);h5=f1;}if(h5 + F1 > q_){T1.T$(17);F1-=T1.E3(h5,F1,q_);}Z9.top=h5;T1.T$(7);Z9.bottom=T1.Z0(h5,F1);}z8=Math.floor(o8) + (!F2.highlight && 0.5);if(Z9.top < q_ && Z9.bottom > f1 && W7.High != W7.Low){x3.moveTo(z8,Z9.top - a0);x3.lineTo(z8,Z9.bottom + a0);}if(F2.type != "hlc" && Z9.open > f1 && Z9.open < q_){x3.moveTo(z8,Z9.open);T1.T$(9);x3.lineTo(T1.E3(L8,z8),Z9.open);}if(Z9.close > f1 && Z9.close < q_){x3.moveTo(z8,Z9.close);T1.B9(7);x3.lineTo(T1.E3(z8,L8),Z9.close);}x3.stroke();}x3.lineWidth=+"1";t6=506832413;o5=-858959960;J3=2;for(var l0=1;T1.I7(l0.toString(),l0.toString().length,41577) !== t6;l0++){c6={colors:[],cache:A_};J3+=2;}if(T1.I7(J3.toString(),J3.toString().length,8629) !== o5){c6={colors:[],cache:A_};}for(var n_ in g1){if(!f.equals(n_,this.containerColor)){c6.colors.push(n_);}}return c6;};f.ChartEngine.prototype.drawWaveChart=function(w9,f$){var I1,C1,c$,Z3,b9,a6,e7,i0,A8,Q5,P7,f0,U4,x7,r$,Y$,m0,g4,K6,q6,L3,s0,K$,H8,t3,s7;I1=w9.chart;C1=I1.dataSegment;c$=new Array(C1.length);Z3=I1.context;if(!f$){f$={};}b9=f$.yAxis || w9.yAxis;this.startClip(w9.name);Z3.beginPath();T1.r0();a6=!({});e7=![];i0=w9.yAxis.top;A8=w9.yAxis.bottom;Q5=w9.left + Math.floor(-("0.5" - 0) * this.layout.candleWidth + this.micropixels);P7=this;for(var g0=0;g0 <= C1.length;g0++){Q5+=this.layout.candleWidth;f0=C1[g0];if(!f0)continue;if(f0.projection)break;if(I1.transformFunc && b9 == I1.panel.yAxis && f0.transform){f0=f0.transform;}if(f0 && f$.field){f0=f0[f$.field];}if(!f0 && f0 !== 0)continue;U4=f0.Close;x7=f0.Open === undefined?U4:f0.Open;r$=f0.High === undefined?Math.max(U4,x7):f0.High;Y$=f0.Low === undefined?Math.min(U4,x7):f0.Low;if(!U4 && U4 !== 0)continue;T1.T$(9);var s3=T1.Z0(12,15);T1.B9(18);var P9=T1.Z0(760,12,64);m0=Q5 - s3 * this.layout.candleWidth / P9;g4=z5(x7);if(g4 < i0){g4=i0;if(e7){Z3.moveTo(m0,g4);continue;}e7=!!1;}else if(g4 > A8){g4=A8;if(e7){Z3.moveTo(m0,g4);continue;}e7=!![];}else {e7=!!0;}if(!a6){a6=!!"1";T1.T$(9);var e0=T1.E3(14,15);K6=I1.dataSet.length - I1.scroll - e0;if(K6 < 0){Z3.moveTo(m0,g4);}else if(K6 >= 0){q6=I1.dataSet[K6];if(q6.transform){q6=q6.transform;}L3=q6.Close;L3=z5(L3);L3=Math.min(Math.max(L3,i0),A8);Z3.moveTo(w9.left + (g0 - 1) * this.layout.candleWidth + this.micropixels,L3);Z3.lineTo(m0,g4);}Z3.moveTo(m0,g4);}else {Z3.lineTo(m0,g4);}T1.B9(24);var j3=T1.E3(13,11704,5,12,15);m0+=this.layout.candleWidth / j3;if(x7 < U4){g4=z5(Y$);if(g4 < i0){g4=i0;}if(g4 > A8){g4=A8;}Z3.lineTo(m0,g4);m0+=this.layout.candleWidth / ("4" << 0);g4=z5(r$);if(g4 < i0){g4=i0;}if(g4 > A8){g4=A8;}Z3.lineTo(m0,g4);}else {g4=z5(r$);if(g4 < i0){g4=i0;}if(g4 > A8){g4=A8;}Z3.lineTo(m0,g4);T1.B9(9);var R_=T1.Z0(76,80);m0+=this.layout.candleWidth / R_;g4=z5(Y$);if(g4 < i0){g4=i0;}if(g4 > A8){g4=A8;}Z3.lineTo(m0,g4);}T1.T$(9);var d$=T1.Z0(11,15);m0+=this.layout.candleWidth / d$;g4=z5(U4);c$[g0]=g4;if(g4 < i0){g4=i0;}if(g4 > A8){g4=A8;}Z3.lineTo(m0,g4);}s0=this.canvasStyle("stx_line_chart");if(s0.width && parseInt(s0.width,+"10") <= "25" - 0){Z3.lineWidth=Math.max(1,f.stripPX(s0.width));}else {K$=+"865322424";H8=-+"530010541";t3=2;for(var u6=1;T1.I7(u6.toString(),u6.toString().length,68686) !== K$;u6++){Z3.lineWidth=5;t3+=2;}if(T1.P2(t3.toString(),t3.toString().length,56260) !== H8){Z3.lineWidth=5;}Z3.lineWidth=1;}if(f$.highlight){Z3.lineWidth*=2;}this.canvasColor("stx_line_chart");function z5(Y2){return P7.pixelFromTransformedValue(Y2,w9,b9);}if(f$.color){Z3.strokeStyle=f$.color;}if(!f$.highlight && this.highlightedDraggable){Z3.globalAlpha*=0.3;}Z3.stroke();Z3.closePath();s7={colors:[Z3.strokeStyle],cache:c$};this.endClip();Z3.lineWidth=1;return s7;};f.ChartEngine.prototype.drawHistogram=function(O7,v4){var P_,p8,h7,j$,u5,M7,h8,o2,b6,b1,Y9,q1,s8,J5,Q1,o0,X6,n5,B6,F7,E4,M5,K2,E_,n$,k8,p7,M2,N4,A9,v6,x2,l6,G7,X0,G9,H_,j8,m8,i2,h_,F9,B5,c8;function X8(U$,g7,B1,p1,D1,v_,U6,n0,z6){var w7,d0,I$,N2,q3,s1,V9,v2,j_,V3,N$,H5,S5,a8,d7,j2,P3,N8,E7;if(!p1){p1=1;}x2.globalAlpha=p1;x2.beginPath();T1.T$(7);w7=T1.Z0(B6,0.5);d0=Math.floor(G9.pixelFromBar(0,p8.chart) - G9.layout.candleWidth / ("2" << 64));I$=d0;for(var u3=0;u3 < u5.length;u3++){N2=X0[u3] || B6;if(u3 === "0" - 0){w7=N2;}if(!u5[u3] || !u5[u3][U$]){w7=N2;I$+=G9.layout.candleWidth;continue;}q3=u5[u3];s1=q3[U$];if(typeof s1 == "object" && s1[g7]){s1=s1[g7];}T1.T$(25);V9=T1.Z0(s8,Y9,s1);if(isNaN(V9))continue;v2=G9.layout.candleWidth;if(q3.candleWidth){v2=q3.candleWidth;if(u3 === ("0" ^ 0)){d0=I$=Math.floor(G9.pixelFromBar(0,p8.chart) - q3.candleWidth / 2);}}j_=Math.floor(N2 - V9) + 0.5;if(j_ > N2 && !F7){j_=N2;}if(z6 && z6.indexOf(u3) == -1 || !z6 && (v_ && q3.Close < q3.iqPrevClose || !v_ && q3.Close >= q3.iqPrevClose)){w7=j_;I$+=v2;continue;}V3=v2 / G9.layout.candleWidth;if(l6){T1.T$(26);N$=Math.round(T1.Z0(n0,U6,l6,I$,V3));T1.B9(7);H5=T1.Z0(N$,D1?0:v6);S5=N$ + Math.round(n0 * V3) - (D1?"0" - 0:v6);}else {T1.T$(26);N$=T1.Z0(n0,U6,l6,I$,V3);H5=Math.round(N$) + (D1?0:v6);S5=Math.round(N$ + n0 * V3) - (D1?0:v6);}if(S5 - H5 < 2){T1.T$(7);S5=T1.Z0(H5,1);}a8=D1?0:0.5;if(H5 % 1 == a8){H5+=0.5;}if(S5 % +"1" == a8){S5+=0.5;}x2.moveTo(S5,N2);if(B6 != N2 && D1 && !l6 && X0[u3 + ("1" >> 64)]){x2.moveTo(S5,Math.max(j_,Math.min(N2,X0[u3 + 1])));}x2.lineTo(S5,j_);x2.lineTo(H5,j_);if(D1 && U6){if(G7[u3] > j_ || u3 === 0){x2.lineTo(H5,Math.min(N2,G7[u3]));}}else if(D1 && !l6 && j$ == "clustered"){if(u3 > 0 && G7[u3 - 1] && G7[u3 - 1] > j_){x2.lineTo(H5,Math.min(N2,G7[u3 - ("1" - 0)]));}}else if(D1 && !l6){if(w7 > j_ || u3 === 0){x2.lineTo(H5,Math.min(N2,w7));}}else {x2.lineTo(H5,N2);}w7=j_;I$+=v2;if(j$ != "clustered" || D1){G7[u3]=j_;}}if(D1){d7="a";d7+="u";d7+="t";d7+="o";x2.strokeStyle=!B1 || B1 == d7?G9.defaultColor:B1;x2.stroke();}else {j2="a";j2+="uto";x2.fillStyle=!B1 || B1 == j2?G9.defaultColor:B1;x2.fill();}T1.B9(1);P3=-T1.E3("698448920",1);N8=-1779043050;E7=+"2";for(var m4=+"1";T1.I7(m4.toString(),m4.toString().length,+"64441") !== P3;m4++){x2.closePath();T1.T$(9);E7+=T1.E3(0,"2");}if(T1.I7(E7.toString(),E7.toString().length,78500) !== N8){x2.closePath();}}if(!v4 || !v4.length){return;}P_=O7.panel;if(!P_){P_="chart";}p8=this.panels[P_];if(!p8){return;}h7=O7.yAxis?O7.yAxis:p8.yAxis;j$=O7.type;u5=this.chart.dataSegment;M7=!"1";h8=+"1";o2=1;for(b1=0;b1 < v4.length;b1++){M7|=v4[b1].border_color_up && !f.isTransparent(v4[b1].border_color_up);M7|=v4[b1].border_color_down && !f.isTransparent(v4[b1].border_color_down);h8=v4[b1].opacity_up;o2=v4[b1].opacity_down;if(!O7.highlight && this.highlightedDraggable){h8*=0.3;o2*=0.3;}}if(O7.borders === !"1"){M7=![];}if(!O7.name){O7.name="Data";}Y9=h7.multiplier;if(!O7.heightPercentage){O7.heightPercentage=0.7;}if(!O7.widthFactor){O7.widthFactor=0.8;}q1=0;T1.T$(0);s8=T1.E3("0",0);for(var l1=0;l1 < this.chart.maxTicks;l1++){J5=u5[l1];if(!J5)continue;Q1=0;for(b1=0;b1 < v4.length;b1++){o0=J5[v4[b1].field];if(o0 || o0 === +"0"){X6="sta";X6+="c";X6+="k";X6+="ed";b6=v4[b1].subField || this.chart.defaultPlotField || "Close";if(typeof o0 == "object" && o0[b6]){o0=o0[b6];}if(j$ == X6){Q1+=o0;}else {Q1=o0;}if(Q1 > q1){q1=Q1;}if(Q1 < s8){s8=Q1;}}}}if(q1 === +"0" && s8 === 0){n5=" Not Av";n5+="ail";n5+="abl";n5+="e";this.displayErrorAsWatermark(P_,this.translateIf(O7.name + n5));return;}F7=!!"";if(!O7.bindToYAxis){if(h7.flipped){B6=Math.floor(h7.top) - 0.5;M5=1809382545;K2=743648570;T1.B9(3);E_=T1.Z0("2",0);for(var V8=1;T1.I7(V8.toString(),V8.toString().length,21668) !== M5;V8++){T1.B9(27);var O0=T1.E3(399,407,57);E4=Math.floor(h7.bottom) * O0;T1.T$(9);E_+=T1.E3(0,"2");}if(T1.I7(E_.toString(),E_.toString().length,18460) !== K2){T1.B9(17);var Y6=T1.Z0(401,19,23);E4=Math.floor(h7.bottom) + Y6;}E4=Math.floor(h7.bottom) - 0.5;}else {B6=Math.floor(h7.bottom) + ("0.5" - 0);n$=-+"308836829";T1.T$(3);k8=-T1.Z0("1767207434",0);p7=+"2";for(var V7=1;T1.P2(V7.toString(),V7.toString().length,36688) !== n$;V7++){E4=Math.floor(h7.top) + 0.5;p7+=2;}if(T1.I7(p7.toString(),p7.toString().length,48467) !== k8){E4=Math.floor(h7.top) - ("584" - 0);}}Y9=Math.abs(B6 - E4) * O7.heightPercentage / (q1 - s8);}else {if(h7.baseline){s8=h7.baseline.value;F7=!"";}M2=122432553;N4=-358074473;A9=+"2";for(var d1=+"1";T1.P2(d1.toString(),d1.toString().length,"34892" << 64) !== M2;d1++){B6=Math.floor(this.pixelFromPrice(s8,p8,h7)) + (h7.flipped?-0.5:0.5);A9+=+"2";}if(T1.P2(A9.toString(),A9.toString().length,+"49524") !== N4){T1.B9(28);var X$=T1.E3(17,7,7,873);T1.B9(17);var q5=T1.Z0(206,13,29);B6=Math.floor(this.pixelFromPrice(s8,p8,h7)) * (h7.flipped?~X$:q5);}}this.startClip(P_);v6=this.layout.candleWidth <= 1 || !M7?0:0.5;x2=this.chart.context;if(h7.flipped){x2.translate(+"0",2 * h7.top);T1.T$(3);x2.scale(1,-T1.E3("1",0));}l6=Math.max(0,(("1" ^ 0) - O7.widthFactor) * this.layout.candleWidth / 2);G7=new Array(u5.length);X0=[];G9=this;H_=1;for(b1=0;b1 < v4.length;b1++){j8="c";j8+="l";j8+="us";j8+="tered";m8=v4[b1];H_=this.layout.candleWidth * O7.widthFactor;if(l6){if(this.layout.candleWidth - H_ <= 2){M7=!1;}}i2=0;if(j$ == j8){i2=b1;H_/=v4.length;}b6=m8.subField || this.chart.defaultPlotField || "Close";if(typeof m8.color_function == "function"){F9={};for(var S0=0;S0 < u5.length;S0++){if(u5[S0]){c8="s";c8+="t";c8+="ri";c8+="ng";h_=m8.color_function(u5[S0]);if(typeof h_ == c8){h_={fill_color:h_,border_color:h_};}if(!h_.hasOwnProperty("border_opacity")){h_.border_opacity=h_.opacity;}B5=h_.fill_color + "," + h_.border_color;if((B5 in F9)){F9[B5].positions.push(S0);}else {h_.positions=[S0];F9[B5]=h_;}}}for(B5 in F9){h_=F9[B5];X8(m8.field,b6,h_.fill_color,h_.opacity,null,null,i2,H_,h_.positions);X8(m8.field,b6,h_.border_color,h_.border_opacity,!![],null,i2,H_,h_.positions);}}else {X8(m8.field,b6,m8.fill_color_up,h8,null,!!"1",i2,H_);X8(m8.field,b6,m8.fill_color_down,o2,null,null,i2,H_);if(this.layout.candleWidth >= 2 && M7){X8(m8.field,b6,m8.border_color_up,h8,!"",!"",i2,H_);X8(m8.field,b6,m8.border_color_down,o2,!!"1",null,i2,H_);}}if(j$ == "stacked"){X0=f.shallowClone(G7);}}T1.T$(9);x2.globalAlpha=T1.E3(0,"1");this.endClip();};f.ChartEngine.prototype.scatter=function(R8,g8){var Q0,j7,o_,M8,e8,e9,b8,y7,E1,v7,y8,R$,S9,Q$,c1,Z7,A$,t_,q$;Q0=R8.chart;j7=Q0.dataSegment;o_=new Array(j7.length);M8=this.chart.context;this.canvasColor("stx_scatter_chart");if(!g8){g8={};}e8=g8.field || Q0.defaultPlotField;e9=g8.yAxis || R8.yAxis;b8=g8.subField || Q0.defaultPlotField || "Close";this.startClip(R8.name);M8.beginPath();M8.lineWidth=g8.lineWidth || "4" << 32;if(g8.highlight){M8.lineWidth*=2;}if(!g8.highlight && this.highlightedDraggable){M8.globalAlpha*=0.3;}if(g8.color){M8.strokeStyle=g8.color;}y7=e9.top;E1=e9.bottom;v7=this.layout.candleWidth;T1.B9(9);var s_=T1.Z0(3,4);y8=R8.left - 0.5 * v7 + this.micropixels - s_;for(var G4=0;G4 <= j7.length;G4++){T1.B9(11);y8+=T1.E3(v7,2);v7=this.layout.candleWidth;T1.B9(11);y8+=T1.Z0(v7,2);R$=j7[G4];if(!R$)continue;if(R$.candleWidth){T1.B9(29);var a5=T1.E3(21,5,5,128);y8+=(R$.candleWidth - v7) / a5;v7=R$.candleWidth;}if(!R$.projection){S9="Sc";S9+="at";S9+="te";S9+="r";if(Q0.transformFunc && e9 == Q0.panel.yAxis && R$.transform){R$=R$.transform;}Q$=R$[e8];if(Q$ && Q$[b8] !== undefined){Q$=Q$[b8];}if(!(Q$ instanceof Array)){Q$=[Q$];}if((S9 in R$)){Q$=R$.Scatter;}for(var w5=0;w5 < Q$.length;w5++){if(!Q$[w5] && Q$[w5] !== ("0" ^ 0))continue;c1=Q$[w5];Z7=0;if(Q$[w5] instanceof Array){c1=Q$[w5][0];Z7=Q$[w5][+"2"];}A$=e9.semiLog?e9.height * (1 - (Math.log(Math.max(c1,0)) / Math.LN10 - e9.logLow) / e9.logShadow):(e9.high - c1) * e9.multiplier;if(e9.flipped){T1.B9(9);A$=T1.E3(A$,E1);}else {A$+=y7;}if(A$ < y7)continue;if(A$ > E1)continue;t_=2;if(Z7){T1.T$(1);t_=T1.E3(v7,Z7);}T1.T$(9);M8.moveTo(T1.E3(t_,y8),A$);T1.T$(7);M8.lineTo(T1.Z0(y8,t_),A$);o_[G4]=A$;}}}M8.stroke();M8.closePath();q$={colors:[M8.strokeStyle],cache:o_};this.endClip();M8.lineWidth=1;return q$;};};/* eslint-enable */ /* jshint ignore:end */ /* ignore jslint end */ - - -let _exports = {CIQ:__CIQ_, SplinePlotter:__SplinePlotter_, timezoneJS:__timezoneJS_, $$:__$$_, $$$:__$$$_}; -export {__js_standard_createEngine_ as createEngine}; -export {__js_standard_customCharts_ as customCharts}; -export {__js_standard_drawing_ as drawing}; -export {__js_standard_easeMachine_ as easeMachine}; -export {__js_standard_equations_ as equations}; -export {__js_standard_i18n_ as i18n}; -export {__js_standard_interaction_ as interaction}; -export {__js_standard_markers_ as markers}; -export {__js_standard_market_ as market}; -export {__js_standard_movement_ as movement}; -export {__js_standard_nameValueStore_ as nameValueStore}; -export {__js_standard_quoteFeed_ as quoteFeed}; -export {__js_standard_series_ as series}; -export {__js_standard_share_ as share}; -export {__js_standard_span_ as span}; -export {__js_standard_storage_ as storage}; -export {__js_standard_studies_ as studies}; -export {__js_standard_symbolLookupBase_ as symbolLookupBase}; -export {__js_standard_theme_ as theme}; -export {__js_standard_timezone_ as timezone}; -export {__js_standard_touch_ as touch}; -export {__js_standard_visualization_ as visualization}; -export {__js_standard_studies_medianPrice_ as medianPrice}; -export {__js_standard_studies_momentum_ as momentum}; -export {__js_standard_studies_priceRelative_ as priceRelative}; -export {__js_standard_studies_vwap_ as vwap}; -export {__js_standard_studies_zigzag_ as zigzag}; - -export {__CIQ_ as CIQ, __SplinePlotter_ as SplinePlotter, __timezoneJS_ as timezoneJS, __$$_ as $$, __$$$_ as $$$}; - -/* global __TREE_SHAKE__ */ -if (typeof __TREE_SHAKE__ === "undefined" || !__TREE_SHAKE__) { - _exports.CIQ.activateImports( - __js_standard_createEngine_, - __js_standard_customCharts_, - __js_standard_drawing_, - __js_standard_easeMachine_, - __js_standard_equations_, - __js_standard_i18n_, - __js_standard_interaction_, - __js_standard_markers_, - __js_standard_market_, - __js_standard_movement_, - __js_standard_nameValueStore_, - __js_standard_quoteFeed_, - __js_standard_series_, - __js_standard_share_, - __js_standard_span_, - __js_standard_storage_, - __js_standard_studies_, - __js_standard_symbolLookupBase_, - __js_standard_theme_, - __js_standard_timezone_, - __js_standard_touch_, - __js_standard_visualization_, - __js_standard_studies_medianPrice_, - __js_standard_studies_momentum_, - __js_standard_studies_priceRelative_, - __js_standard_studies_vwap_, - __js_standard_studies_zigzag_, - null - ); -} \ No newline at end of file diff --git a/chartiq/hammer.js b/chartiq/hammer.js deleted file mode 100644 index 94b653d8a4..0000000000 --- a/chartiq/hammer.js +++ /dev/null @@ -1,6 +0,0 @@ -/*! Hammer.JS - v2.0.8 - 2016-04-23 - * http://hammerjs.github.io/ - * - * Copyright (c) 2016 Jorik Tangelder; - * Licensed under the MIT license */ -!function(a,b,c,d){"use strict";function e(a,b,c){return setTimeout(j(a,c),b)}function f(a,b,c){return Array.isArray(a)?(g(a,c[b],c),!0):!1}function g(a,b,c){var e;if(a)if(a.forEach)a.forEach(b,c);else if(a.length!==d)for(e=0;e\s*\(/gm,"{anonymous}()@"):"Unknown Stack Trace",f=a.console&&(a.console.warn||a.console.log);return f&&f.call(a.console,e,d),b.apply(this,arguments)}}function i(a,b,c){var d,e=b.prototype;d=a.prototype=Object.create(e),d.constructor=a,d._super=e,c&&la(d,c)}function j(a,b){return function(){return a.apply(b,arguments)}}function k(a,b){return typeof a==oa?a.apply(b?b[0]||d:d,b):a}function l(a,b){return a===d?b:a}function m(a,b,c){g(q(b),function(b){a.addEventListener(b,c,!1)})}function n(a,b,c){g(q(b),function(b){a.removeEventListener(b,c,!1)})}function o(a,b){for(;a;){if(a==b)return!0;a=a.parentNode}return!1}function p(a,b){return a.indexOf(b)>-1}function q(a){return a.trim().split(/\s+/g)}function r(a,b,c){if(a.indexOf&&!c)return a.indexOf(b);for(var d=0;dc[b]}):d.sort()),d}function u(a,b){for(var c,e,f=b[0].toUpperCase()+b.slice(1),g=0;g1&&!c.firstMultiple?c.firstMultiple=D(b):1===e&&(c.firstMultiple=!1);var f=c.firstInput,g=c.firstMultiple,h=g?g.center:f.center,i=b.center=E(d);b.timeStamp=ra(),b.deltaTime=b.timeStamp-f.timeStamp,b.angle=I(h,i),b.distance=H(h,i),B(c,b),b.offsetDirection=G(b.deltaX,b.deltaY);var j=F(b.deltaTime,b.deltaX,b.deltaY);b.overallVelocityX=j.x,b.overallVelocityY=j.y,b.overallVelocity=qa(j.x)>qa(j.y)?j.x:j.y,b.scale=g?K(g.pointers,d):1,b.rotation=g?J(g.pointers,d):0,b.maxPointers=c.prevInput?b.pointers.length>c.prevInput.maxPointers?b.pointers.length:c.prevInput.maxPointers:b.pointers.length,C(c,b);var k=a.element;o(b.srcEvent.target,k)&&(k=b.srcEvent.target),b.target=k}function B(a,b){var c=b.center,d=a.offsetDelta||{},e=a.prevDelta||{},f=a.prevInput||{};b.eventType!==Ea&&f.eventType!==Ga||(e=a.prevDelta={x:f.deltaX||0,y:f.deltaY||0},d=a.offsetDelta={x:c.x,y:c.y}),b.deltaX=e.x+(c.x-d.x),b.deltaY=e.y+(c.y-d.y)}function C(a,b){var c,e,f,g,h=a.lastInterval||b,i=b.timeStamp-h.timeStamp;if(b.eventType!=Ha&&(i>Da||h.velocity===d)){var j=b.deltaX-h.deltaX,k=b.deltaY-h.deltaY,l=F(i,j,k);e=l.x,f=l.y,c=qa(l.x)>qa(l.y)?l.x:l.y,g=G(j,k),a.lastInterval=b}else c=h.velocity,e=h.velocityX,f=h.velocityY,g=h.direction;b.velocity=c,b.velocityX=e,b.velocityY=f,b.direction=g}function D(a){for(var b=[],c=0;ce;)c+=a[e].clientX,d+=a[e].clientY,e++;return{x:pa(c/b),y:pa(d/b)}}function F(a,b,c){return{x:b/a||0,y:c/a||0}}function G(a,b){return a===b?Ia:qa(a)>=qa(b)?0>a?Ja:Ka:0>b?La:Ma}function H(a,b,c){c||(c=Qa);var d=b[c[0]]-a[c[0]],e=b[c[1]]-a[c[1]];return Math.sqrt(d*d+e*e)}function I(a,b,c){c||(c=Qa);var d=b[c[0]]-a[c[0]],e=b[c[1]]-a[c[1]];return 180*Math.atan2(e,d)/Math.PI}function J(a,b){return I(b[1],b[0],Ra)+I(a[1],a[0],Ra)}function K(a,b){return H(b[0],b[1],Ra)/H(a[0],a[1],Ra)}function L(){this.evEl=Ta,this.evWin=Ua,this.pressed=!1,x.apply(this,arguments)}function M(){this.evEl=Xa,this.evWin=Ya,x.apply(this,arguments),this.store=this.manager.session.pointerEvents=[]}function N(){this.evTarget=$a,this.evWin=_a,this.started=!1,x.apply(this,arguments)}function O(a,b){var c=s(a.touches),d=s(a.changedTouches);return b&(Ga|Ha)&&(c=t(c.concat(d),"identifier",!0)),[c,d]}function P(){this.evTarget=bb,this.targetIds={},x.apply(this,arguments)}function Q(a,b){var c=s(a.touches),d=this.targetIds;if(b&(Ea|Fa)&&1===c.length)return d[c[0].identifier]=!0,[c,c];var e,f,g=s(a.changedTouches),h=[],i=this.target;if(f=c.filter(function(a){return o(a.target,i)}),b===Ea)for(e=0;e-1&&d.splice(a,1)};setTimeout(e,cb)}}function U(a){for(var b=a.srcEvent.clientX,c=a.srcEvent.clientY,d=0;d=f&&db>=g)return!0}return!1}function V(a,b){this.manager=a,this.set(b)}function W(a){if(p(a,jb))return jb;var b=p(a,kb),c=p(a,lb);return b&&c?jb:b||c?b?kb:lb:p(a,ib)?ib:hb}function X(){if(!fb)return!1;var b={},c=a.CSS&&a.CSS.supports;return["auto","manipulation","pan-y","pan-x","pan-x pan-y","none"].forEach(function(d){b[d]=c?a.CSS.supports("touch-action",d):!0}),b}function Y(a){this.options=la({},this.defaults,a||{}),this.id=v(),this.manager=null,this.options.enable=l(this.options.enable,!0),this.state=nb,this.simultaneous={},this.requireFail=[]}function Z(a){return a&sb?"cancel":a&qb?"end":a&pb?"move":a&ob?"start":""}function $(a){return a==Ma?"down":a==La?"up":a==Ja?"left":a==Ka?"right":""}function _(a,b){var c=b.manager;return c?c.get(a):a}function aa(){Y.apply(this,arguments)}function ba(){aa.apply(this,arguments),this.pX=null,this.pY=null}function ca(){aa.apply(this,arguments)}function da(){Y.apply(this,arguments),this._timer=null,this._input=null}function ea(){aa.apply(this,arguments)}function fa(){aa.apply(this,arguments)}function ga(){Y.apply(this,arguments),this.pTime=!1,this.pCenter=!1,this._timer=null,this._input=null,this.count=0}function ha(a,b){return b=b||{},b.recognizers=l(b.recognizers,ha.defaults.preset),new ia(a,b)}function ia(a,b){this.options=la({},ha.defaults,b||{}),this.options.inputTarget=this.options.inputTarget||a,this.handlers={},this.session={},this.recognizers=[],this.oldCssProps={},this.element=a,this.input=y(this),this.touchAction=new V(this,this.options.touchAction),ja(this,!0),g(this.options.recognizers,function(a){var b=this.add(new a[0](a[1]));a[2]&&b.recognizeWith(a[2]),a[3]&&b.requireFailure(a[3])},this)}function ja(a,b){var c=a.element;if(c.style){var d;g(a.options.cssProps,function(e,f){d=u(c.style,f),b?(a.oldCssProps[d]=c.style[d],c.style[d]=e):c.style[d]=a.oldCssProps[d]||""}),b||(a.oldCssProps={})}}function ka(a,c){var d=b.createEvent("Event");d.initEvent(a,!0,!0),d.gesture=c,c.target.dispatchEvent(d)}var la,ma=["","webkit","Moz","MS","ms","o"],na=b.createElement("div"),oa="function",pa=Math.round,qa=Math.abs,ra=Date.now;la="function"!=typeof Object.assign?function(a){if(a===d||null===a)throw new TypeError("Cannot convert undefined or null to object");for(var b=Object(a),c=1;ch&&(b.push(a),h=b.length-1):e&(Ga|Ha)&&(c=!0),0>h||(b[h]=a,this.callback(this.manager,e,{pointers:b,changedPointers:[a],pointerType:f,srcEvent:a}),c&&b.splice(h,1))}});var Za={touchstart:Ea,touchmove:Fa,touchend:Ga,touchcancel:Ha},$a="touchstart",_a="touchstart touchmove touchend touchcancel";i(N,x,{handler:function(a){var b=Za[a.type];if(b===Ea&&(this.started=!0),this.started){var c=O.call(this,a,b);b&(Ga|Ha)&&c[0].length-c[1].length===0&&(this.started=!1),this.callback(this.manager,b,{pointers:c[0],changedPointers:c[1],pointerType:za,srcEvent:a})}}});var ab={touchstart:Ea,touchmove:Fa,touchend:Ga,touchcancel:Ha},bb="touchstart touchmove touchend touchcancel";i(P,x,{handler:function(a){var b=ab[a.type],c=Q.call(this,a,b);c&&this.callback(this.manager,b,{pointers:c[0],changedPointers:c[1],pointerType:za,srcEvent:a})}});var cb=2500,db=25;i(R,x,{handler:function(a,b,c){var d=c.pointerType==za,e=c.pointerType==Ba;if(!(e&&c.sourceCapabilities&&c.sourceCapabilities.firesTouchEvents)){if(d)S.call(this,b,c);else if(e&&U.call(this,c))return;this.callback(a,b,c)}},destroy:function(){this.touch.destroy(),this.mouse.destroy()}});var eb=u(na.style,"touchAction"),fb=eb!==d,gb="compute",hb="auto",ib="manipulation",jb="none",kb="pan-x",lb="pan-y",mb=X();V.prototype={set:function(a){a==gb&&(a=this.compute()),fb&&this.manager.element.style&&mb[a]&&(this.manager.element.style[eb]=a),this.actions=a.toLowerCase().trim()},update:function(){this.set(this.manager.options.touchAction)},compute:function(){var a=[];return g(this.manager.recognizers,function(b){k(b.options.enable,[b])&&(a=a.concat(b.getTouchAction()))}),W(a.join(" "))},preventDefaults:function(a){var b=a.srcEvent,c=a.offsetDirection;if(this.manager.session.prevented)return void b.preventDefault();var d=this.actions,e=p(d,jb)&&!mb[jb],f=p(d,lb)&&!mb[lb],g=p(d,kb)&&!mb[kb];if(e){var h=1===a.pointers.length,i=a.distance<2,j=a.deltaTime<250;if(h&&i&&j)return}return g&&f?void 0:e||f&&c&Na||g&&c&Oa?this.preventSrc(b):void 0},preventSrc:function(a){this.manager.session.prevented=!0,a.preventDefault()}};var nb=1,ob=2,pb=4,qb=8,rb=qb,sb=16,tb=32;Y.prototype={defaults:{},set:function(a){return la(this.options,a),this.manager&&this.manager.touchAction.update(),this},recognizeWith:function(a){if(f(a,"recognizeWith",this))return this;var b=this.simultaneous;return a=_(a,this),b[a.id]||(b[a.id]=a,a.recognizeWith(this)),this},dropRecognizeWith:function(a){return f(a,"dropRecognizeWith",this)?this:(a=_(a,this),delete this.simultaneous[a.id],this)},requireFailure:function(a){if(f(a,"requireFailure",this))return this;var b=this.requireFail;return a=_(a,this),-1===r(b,a)&&(b.push(a),a.requireFailure(this)),this},dropRequireFailure:function(a){if(f(a,"dropRequireFailure",this))return this;a=_(a,this);var b=r(this.requireFail,a);return b>-1&&this.requireFail.splice(b,1),this},hasRequireFailures:function(){return this.requireFail.length>0},canRecognizeWith:function(a){return!!this.simultaneous[a.id]},emit:function(a){function b(b){c.manager.emit(b,a)}var c=this,d=this.state;qb>d&&b(c.options.event+Z(d)),b(c.options.event),a.additionalEvent&&b(a.additionalEvent),d>=qb&&b(c.options.event+Z(d))},tryEmit:function(a){return this.canEmit()?this.emit(a):void(this.state=tb)},canEmit:function(){for(var a=0;af?Ja:Ka,c=f!=this.pX,d=Math.abs(a.deltaX)):(e=0===g?Ia:0>g?La:Ma,c=g!=this.pY,d=Math.abs(a.deltaY))),a.direction=e,c&&d>b.threshold&&e&b.direction},attrTest:function(a){return aa.prototype.attrTest.call(this,a)&&(this.state&ob||!(this.state&ob)&&this.directionTest(a))},emit:function(a){this.pX=a.deltaX,this.pY=a.deltaY;var b=$(a.direction);b&&(a.additionalEvent=this.options.event+b),this._super.emit.call(this,a)}}),i(ca,aa,{defaults:{event:"pinch",threshold:0,pointers:2},getTouchAction:function(){return[jb]},attrTest:function(a){return this._super.attrTest.call(this,a)&&(Math.abs(a.scale-1)>this.options.threshold||this.state&ob)},emit:function(a){if(1!==a.scale){var b=a.scale<1?"in":"out";a.additionalEvent=this.options.event+b}this._super.emit.call(this,a)}}),i(da,Y,{defaults:{event:"press",pointers:1,time:251,threshold:9},getTouchAction:function(){return[hb]},process:function(a){var b=this.options,c=a.pointers.length===b.pointers,d=a.distanceb.time;if(this._input=a,!d||!c||a.eventType&(Ga|Ha)&&!f)this.reset();else if(a.eventType&Ea)this.reset(),this._timer=e(function(){this.state=rb,this.tryEmit()},b.time,this);else if(a.eventType&Ga)return rb;return tb},reset:function(){clearTimeout(this._timer)},emit:function(a){this.state===rb&&(a&&a.eventType&Ga?this.manager.emit(this.options.event+"up",a):(this._input.timeStamp=ra(),this.manager.emit(this.options.event,this._input)))}}),i(ea,aa,{defaults:{event:"rotate",threshold:0,pointers:2},getTouchAction:function(){return[jb]},attrTest:function(a){return this._super.attrTest.call(this,a)&&(Math.abs(a.rotation)>this.options.threshold||this.state&ob)}}),i(fa,aa,{defaults:{event:"swipe",threshold:10,velocity:.3,direction:Na|Oa,pointers:1},getTouchAction:function(){return ba.prototype.getTouchAction.call(this)},attrTest:function(a){var b,c=this.options.direction;return c&(Na|Oa)?b=a.overallVelocity:c&Na?b=a.overallVelocityX:c&Oa&&(b=a.overallVelocityY),this._super.attrTest.call(this,a)&&c&a.offsetDirection&&a.distance>this.options.threshold&&a.maxPointers==this.options.pointers&&qa(b)>this.options.velocity&&a.eventType&Ga},emit:function(a){var b=$(a.offsetDirection);b&&this.manager.emit(this.options.event+b,a),this.manager.emit(this.options.event,a)}}),i(ga,Y,{defaults:{event:"tap",pointers:1,taps:1,interval:300,time:250,threshold:9,posThreshold:10},getTouchAction:function(){return[ib]},process:function(a){var b=this.options,c=a.pointers.length===b.pointers,d=a.distance - * Copyright (c) 2020 Niklas von Hertzen - * Released under MIT License - */ -!function(A,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(A=A||self).html2canvas=e()}(this,function(){"use strict"; -/*! ***************************************************************************** - Copyright (c) Microsoft Corporation. All rights reserved. - Licensed under the Apache License, Version 2.0 (the "License"); you may not use - this file except in compliance with the License. You may obtain a copy of the - License at http://www.apache.org/licenses/LICENSE-2.0 - - THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED - WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, - MERCHANTABLITY OR NON-INFRINGEMENT. - - See the Apache Version 2.0 License for specific language governing permissions - and limitations under the License. - ***************************************************************************** */var r=function(A,e){return(r=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(A,e){A.__proto__=e}||function(A,e){for(var t in e)e.hasOwnProperty(t)&&(A[t]=e[t])})(A,e)};function A(A,e){function t(){this.constructor=A}r(A,e),A.prototype=null===e?Object.create(e):(t.prototype=e.prototype,new t)}var K=function(){return(K=Object.assign||function(A){for(var e,t=1,r=arguments.length;ts[0]&&e[1]>10),s%1024+56320)),(n+1===t||16384>5])<<2)+(31&A),this.data[e];if(A<=65535)return e=((e=this.index[2048+(A-55296>>5)])<<2)+(31&A),this.data[e];if(A>11),e=this.index[e],e+=A>>5&63,e=((e=this.index[e])<<2)+(31&A),this.data[e];if(A<=1114111)return this.data[this.highValueIndex]}return this.errorValue},o);function o(A,e,t,r,n,B){this.initialValue=A,this.errorValue=e,this.highStart=t,this.highValueIndex=r,this.index=n,this.data=B}function C(A,e,t,r){var n=r[t];if(Array.isArray(A)?-1!==A.indexOf(n):A===n)for(var B=t;B<=r.length;){if((i=r[++B])===e)return!0;if(i!==H)break}if(n===H)for(B=t;0>4,c[i++]=(15&r)<<4|n>>2,c[i++]=(3&n)<<6|63&B;return a}("KwAAAAAAAAAACA4AIDoAAPAfAAACAAAAAAAIABAAGABAAEgAUABYAF4AZgBeAGYAYABoAHAAeABeAGYAfACEAIAAiACQAJgAoACoAK0AtQC9AMUAXgBmAF4AZgBeAGYAzQDVAF4AZgDRANkA3gDmAOwA9AD8AAQBDAEUARoBIgGAAIgAJwEvATcBPwFFAU0BTAFUAVwBZAFsAXMBewGDATAAiwGTAZsBogGkAawBtAG8AcIBygHSAdoB4AHoAfAB+AH+AQYCDgIWAv4BHgImAi4CNgI+AkUCTQJTAlsCYwJrAnECeQKBAk0CiQKRApkCoQKoArACuALAAsQCzAIwANQC3ALkAjAA7AL0AvwCAQMJAxADGAMwACADJgMuAzYDPgOAAEYDSgNSA1IDUgNaA1oDYANiA2IDgACAAGoDgAByA3YDfgOAAIQDgACKA5IDmgOAAIAAogOqA4AAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAK8DtwOAAIAAvwPHA88D1wPfAyAD5wPsA/QD/AOAAIAABAQMBBIEgAAWBB4EJgQuBDMEIAM7BEEEXgBJBCADUQRZBGEEaQQwADAAcQQ+AXkEgQSJBJEEgACYBIAAoASoBK8EtwQwAL8ExQSAAIAAgACAAIAAgACgAM0EXgBeAF4AXgBeAF4AXgBeANUEXgDZBOEEXgDpBPEE+QQBBQkFEQUZBSEFKQUxBTUFPQVFBUwFVAVcBV4AYwVeAGsFcwV7BYMFiwWSBV4AmgWgBacFXgBeAF4AXgBeAKsFXgCyBbEFugW7BcIFwgXIBcIFwgXQBdQF3AXkBesF8wX7BQMGCwYTBhsGIwYrBjMGOwZeAD8GRwZNBl4AVAZbBl4AXgBeAF4AXgBeAF4AXgBeAF4AXgBeAGMGXgBqBnEGXgBeAF4AXgBeAF4AXgBeAF4AXgB5BoAG4wSGBo4GkwaAAIADHgR5AF4AXgBeAJsGgABGA4AAowarBrMGswagALsGwwbLBjAA0wbaBtoG3QbaBtoG2gbaBtoG2gblBusG8wb7BgMHCwcTBxsHCwcjBysHMAc1BzUHOgdCB9oGSgdSB1oHYAfaBloHaAfaBlIH2gbaBtoG2gbaBtoG2gbaBjUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHbQdeAF4ANQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQd1B30HNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1B4MH2gaKB68EgACAAIAAgACAAIAAgACAAI8HlwdeAJ8HpweAAIAArwe3B14AXgC/B8UHygcwANAH2AfgB4AA6AfwBz4B+AcACFwBCAgPCBcIogEYAR8IJwiAAC8INwg/CCADRwhPCFcIXwhnCEoDGgSAAIAAgABvCHcIeAh5CHoIewh8CH0Idwh4CHkIegh7CHwIfQh3CHgIeQh6CHsIfAh9CHcIeAh5CHoIewh8CH0Idwh4CHkIegh7CHwIfQh3CHgIeQh6CHsIfAh9CHcIeAh5CHoIewh8CH0Idwh4CHkIegh7CHwIfQh3CHgIeQh6CHsIfAh9CHcIeAh5CHoIewh8CH0Idwh4CHkIegh7CHwIfQh3CHgIeQh6CHsIfAh9CHcIeAh5CHoIewh8CH0Idwh4CHkIegh7CHwIfQh3CHgIeQh6CHsIfAh9CHcIeAh5CHoIewh8CH0Idwh4CHkIegh7CHwIfQh3CHgIeQh6CHsIfAh9CHcIeAh5CHoIewh8CH0Idwh4CHkIegh7CHwIfQh3CHgIeQh6CHsIfAh9CHcIeAh5CHoIewh8CH0Idwh4CHkIegh7CHwIfQh3CHgIeQh6CHsIfAh9CHcIeAh5CHoIewh8CH0Idwh4CHkIegh7CHwIfQh3CHgIeQh6CHsIfAh9CHcIeAh5CHoIewh8CH0Idwh4CHkIegh7CHwIfQh3CHgIeQh6CHsIfAh9CHcIeAh5CHoIewh8CH0Idwh4CHkIegh7CHwIfQh3CHgIeQh6CHsIfAh9CHcIeAh5CHoIewh8CH0Idwh4CHkIegh7CHwIfQh3CHgIeQh6CHsIfAh9CHcIeAh5CHoIewh8CH0Idwh4CHkIegh7CHwIfQh3CHgIeQh6CHsIfAh9CHcIeAh5CHoIewh8CH0Idwh4CHkIegh7CHwIfQh3CHgIeQh6CHsIfAh9CHcIeAh5CHoIewh8CH0Idwh4CHkIegh7CHwIfQh3CHgIeQh6CHsIfAh9CHcIeAh5CHoIewh8CH0Idwh4CHkIegh7CHwIfQh3CHgIeQh6CHsIfAh9CHcIeAh5CHoIewh8CH0Idwh4CHkIegh7CHwIhAiLCI4IMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwAJYIlgiWCJYIlgiWCJYIlgiWCJYIlgiWCJYIlgiWCJYIlgiWCJYIlgiWCJYIlgiWCJYIlgiWCJYIlgiWCJYIlggwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAANQc1BzUHNQc1BzUHNQc1BzUHNQc1B54INQc1B6II2gaqCLIIugiAAIAAvgjGCIAAgACAAIAAgACAAIAAgACAAIAAywiHAYAA0wiAANkI3QjlCO0I9Aj8CIAAgACAAAIJCgkSCRoJIgknCTYHLwk3CZYIlgiWCJYIlgiWCJYIlgiWCJYIlgiWCJYIlgiWCJYIlgiWCJYIlgiWCJYIlgiWCJYIlgiWCJYIlgiWCJYIlgiAAIAAAAFAAXgBeAGAAcABeAHwAQACQAKAArQC9AJ4AXgBeAE0A3gBRAN4A7AD8AMwBGgEAAKcBNwEFAUwBXAF4QkhCmEKnArcCgAHHAsABz4LAAcABwAHAAd+C6ABoAG+C/4LAAcABwAHAAc+DF4MAAcAB54M3gweDV4Nng3eDaABoAGgAaABoAGgAaABoAGgAaABoAGgAaABoAGgAaABoAGgAaABoAEeDqABVg6WDqABoQ6gAaABoAHXDvcONw/3DvcO9w73DvcO9w73DvcO9w73DvcO9w73DvcO9w73DvcO9w73DvcO9w73DvcO9w73DvcO9w73DvcO9w73DncPAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcAB7cPPwlGCU4JMACAAIAAgABWCV4JYQmAAGkJcAl4CXwJgAkwADAAMAAwAIgJgACLCZMJgACZCZ8JowmrCYAAswkwAF4AXgB8AIAAuwkABMMJyQmAAM4JgADVCTAAMAAwADAAgACAAIAAgACAAIAAgACAAIAAqwYWBNkIMAAwADAAMADdCeAJ6AnuCR4E9gkwAP4JBQoNCjAAMACAABUK0wiAAB0KJAosCjQKgAAwADwKQwqAAEsKvQmdCVMKWwowADAAgACAALcEMACAAGMKgABrCjAAMAAwADAAMAAwADAAMAAwADAAMAAeBDAAMAAwADAAMAAwADAAMAAwADAAMAAwAIkEPQFzCnoKiQSCCooKkAqJBJgKoAqkCokEGAGsCrQKvArBCjAAMADJCtEKFQHZCuEK/gHpCvEKMAAwADAAMACAAIwE+QowAIAAPwEBCzAAMAAwADAAMACAAAkLEQswAIAAPwEZCyELgAAOCCkLMAAxCzkLMAAwADAAMAAwADAAXgBeAEELMAAwADAAMAAwADAAMAAwAEkLTQtVC4AAXAtkC4AAiQkwADAAMAAwADAAMAAwADAAbAtxC3kLgAuFC4sLMAAwAJMLlwufCzAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAApwswADAAMACAAIAAgACvC4AAgACAAIAAgACAALcLMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAvwuAAMcLgACAAIAAgACAAIAAyguAAIAAgACAAIAA0QswADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAANkLgACAAIAA4AswADAAMAAwADAAMAAwADAAMAAwADAAMAAwAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACJCR4E6AswADAAhwHwC4AA+AsADAgMEAwwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMACAAIAAGAwdDCUMMAAwAC0MNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQw1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHPQwwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADUHNQc1BzUHNQc1BzUHNQc2BzAAMAA5DDUHNQc1BzUHNQc1BzUHNQc1BzUHNQdFDDAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAgACAAIAATQxSDFoMMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwAF4AXgBeAF4AXgBeAF4AYgxeAGoMXgBxDHkMfwxeAIUMXgBeAI0MMAAwADAAMAAwAF4AXgCVDJ0MMAAwADAAMABeAF4ApQxeAKsMswy7DF4Awgy9DMoMXgBeAF4AXgBeAF4AXgBeAF4AXgDRDNkMeQBqCeAM3Ax8AOYM7Az0DPgMXgBeAF4AXgBeAF4AXgBeAF4AXgBeAF4AXgBeAF4AXgCgAAANoAAHDQ4NFg0wADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAeDSYNMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwAIAAgACAAIAAgACAAC4NMABeAF4ANg0wADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwAD4NRg1ODVYNXg1mDTAAbQ0wADAAMAAwADAAMAAwADAA2gbaBtoG2gbaBtoG2gbaBnUNeg3CBYANwgWFDdoGjA3aBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gaUDZwNpA2oDdoG2gawDbcNvw3HDdoG2gbPDdYN3A3fDeYN2gbsDfMN2gbaBvoN/g3aBgYODg7aBl4AXgBeABYOXgBeACUG2gYeDl4AJA5eACwO2w3aBtoGMQ45DtoG2gbaBtoGQQ7aBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gZJDjUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1B1EO2gY1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQdZDjUHNQc1BzUHNQc1B2EONQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHaA41BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1B3AO2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gY1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1B2EO2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gZJDtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBkkOeA6gAKAAoAAwADAAMAAwAKAAoACgAKAAoACgAKAAgA4wADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAD//wQABAAEAAQABAAEAAQABAAEAA0AAwABAAEAAgAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAKABMAFwAeABsAGgAeABcAFgASAB4AGwAYAA8AGAAcAEsASwBLAEsASwBLAEsASwBLAEsAGAAYAB4AHgAeABMAHgBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAFgAbABIAHgAeAB4AUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQABYADQARAB4ABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsABAAEAAQABAAEAAUABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAkAFgAaABsAGwAbAB4AHQAdAB4ATwAXAB4ADQAeAB4AGgAbAE8ATwAOAFAAHQAdAB0ATwBPABcATwBPAE8AFgBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAHQAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB0AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgBQAB4AHgAeAB4AUABQAFAAUAAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAAeAB4AHgAeAFAATwBAAE8ATwBPAEAATwBQAFAATwBQAB4AHgAeAB4AHgAeAB0AHQAdAB0AHgAdAB4ADgBQAFAAUABQAFAAHgAeAB4AHgAeAB4AHgBQAB4AUAAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4ABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAJAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAkACQAJAAkACQAJAAkABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAeAB4AHgAeAFAAHgAeAB4AKwArAFAAUABQAFAAGABQACsAKwArACsAHgAeAFAAHgBQAFAAUAArAFAAKwAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AKwAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4ABAAEAAQABAAEAAQABAAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArACsAUAAeAB4AHgAeAB4AHgArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwAYAA0AKwArAB4AHgAbACsABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQADQAEAB4ABAAEAB4ABAAEABMABAArACsAKwArACsAKwArACsAVgBWAFYAVgBWAFYAVgBWAFYAVgBWAFYAVgBWAFYAVgBWAFYAVgBWAFYAVgBWAFYAVgBWAFYAKwArACsAKwArAFYAVgBWAB4AHgArACsAKwArACsAKwArACsAKwArACsAHgAeAB4AHgAeAB4AHgAeAB4AGgAaABoAGAAYAB4AHgAEAAQABAAEAAQABAAEAAQABAAEAAQAEwAEACsAEwATAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABABLAEsASwBLAEsASwBLAEsASwBLABoAGQAZAB4AUABQAAQAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQABMAUAAEAAQABAAEAAQABAAEAB4AHgAEAAQABAAEAAQABABQAFAABAAEAB4ABAAEAAQABABQAFAASwBLAEsASwBLAEsASwBLAEsASwBQAFAAUAAeAB4AUAAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AKwAeAFAABABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEACsAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAABAAEAAQABAAEAAQABAAEAAQABAAEAFAAKwArACsAKwArACsAKwArACsAKwArACsAKwArAEsASwBLAEsASwBLAEsASwBLAEsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAABAAEAAQABAAEAAQABAAEAAQAUABQAB4AHgAYABMAUAArACsAKwArACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAAEAAQABAAEAFAABAAEAAQABAAEAFAABAAEAAQAUAAEAAQABAAEAAQAKwArAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAAEAAQABAArACsAHgArAFAAUABQAFAAUABQAFAAUABQAFAAUAArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArAFAAUABQAFAAUABQAFAAUAArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAeAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAAEAAQABABQAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAFAABAAEAAQABAAEAAQABABQAFAAUABQAFAAUABQAFAAUABQAAQABAANAA0ASwBLAEsASwBLAEsASwBLAEsASwAeAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAABAAEAAQAKwBQAFAAUABQAFAAUABQAFAAKwArAFAAUAArACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQACsAUABQAFAAUABQAFAAUAArAFAAKwArACsAUABQAFAAUAArACsABABQAAQABAAEAAQABAAEAAQAKwArAAQABAArACsABAAEAAQAUAArACsAKwArACsAKwArACsABAArACsAKwArAFAAUAArAFAAUABQAAQABAArACsASwBLAEsASwBLAEsASwBLAEsASwBQAFAAGgAaAFAAUABQAFAAUABMAB4AGwBQAB4AKwArACsABAAEAAQAKwBQAFAAUABQAFAAUAArACsAKwArAFAAUAArACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQACsAUABQAFAAUABQAFAAUAArAFAAUAArAFAAUAArAFAAUAArACsABAArAAQABAAEAAQABAArACsAKwArAAQABAArACsABAAEAAQAKwArACsABAArACsAKwArACsAKwArAFAAUABQAFAAKwBQACsAKwArACsAKwArACsASwBLAEsASwBLAEsASwBLAEsASwAEAAQAUABQAFAABAArACsAKwArACsAKwArACsAKwArACsABAAEAAQAKwBQAFAAUABQAFAAUABQAFAAUAArAFAAUABQACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQACsAUABQAFAAUABQAFAAUAArAFAAUAArAFAAUABQAFAAUAArACsABABQAAQABAAEAAQABAAEAAQABAArAAQABAAEACsABAAEAAQAKwArAFAAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAUABQAAQABAArACsASwBLAEsASwBLAEsASwBLAEsASwAeABsAKwArACsAKwArACsAKwBQAAQABAAEAAQABAAEACsABAAEAAQAKwBQAFAAUABQAFAAUABQAFAAKwArAFAAUAArACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAAEAAQABAAEAAQAKwArAAQABAArACsABAAEAAQAKwArACsAKwArACsAKwArAAQABAArACsAKwArAFAAUAArAFAAUABQAAQABAArACsASwBLAEsASwBLAEsASwBLAEsASwAeAFAAUABQAFAAUABQAFAAKwArACsAKwArACsAKwArACsAKwAEAFAAKwBQAFAAUABQAFAAUAArACsAKwBQAFAAUAArAFAAUABQAFAAKwArACsAUABQACsAUAArAFAAUAArACsAKwBQAFAAKwArACsAUABQAFAAKwArACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwArACsAKwAEAAQABAAEAAQAKwArACsABAAEAAQAKwAEAAQABAAEACsAKwBQACsAKwArACsAKwArAAQAKwArACsAKwArACsAKwArACsAKwBLAEsASwBLAEsASwBLAEsASwBLAFAAUABQAB4AHgAeAB4AHgAeABsAHgArACsAKwArACsABAAEAAQABAArAFAAUABQAFAAUABQAFAAUAArAFAAUABQACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQACsAKwArAFAABAAEAAQABAAEAAQABAArAAQABAAEACsABAAEAAQABAArACsAKwArACsAKwArAAQABAArAFAAUABQACsAKwArACsAKwBQAFAABAAEACsAKwBLAEsASwBLAEsASwBLAEsASwBLACsAKwArACsAKwArACsAKwBQAFAAUABQAFAAUABQAB4AUAAEAAQABAArAFAAUABQAFAAUABQAFAAUAArAFAAUABQACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwBQAFAAUABQAFAAUABQAFAAUABQACsAUABQAFAAUABQACsAKwAEAFAABAAEAAQABAAEAAQABAArAAQABAAEACsABAAEAAQABAArACsAKwArACsAKwArAAQABAArACsAKwArACsAKwArAFAAKwBQAFAABAAEACsAKwBLAEsASwBLAEsASwBLAEsASwBLACsAUABQACsAKwArACsAKwArACsAKwArACsAKwArACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAABAAEAFAABAAEAAQABAAEAAQABAArAAQABAAEACsABAAEAAQABABQAB4AKwArACsAKwBQAFAAUAAEAFAAUABQAFAAUABQAFAAUABQAFAABAAEACsAKwBLAEsASwBLAEsASwBLAEsASwBLAFAAUABQAFAAUABQAFAAUABQABoAUABQAFAAUABQAFAAKwArAAQABAArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQACsAKwArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArAFAAUABQAFAAUABQAFAAUABQACsAUAArACsAUABQAFAAUABQAFAAUAArACsAKwAEACsAKwArACsABAAEAAQABAAEAAQAKwAEACsABAAEAAQABAAEAAQABAAEACsAKwArACsAKwArAEsASwBLAEsASwBLAEsASwBLAEsAKwArAAQABAAeACsAKwArACsAKwArACsAKwArACsAKwArAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXAAqAFwAXAAqACoAKgAqACoAKgAqACsAKwArACsAGwBcAFwAXABcAFwAXABcACoAKgAqACoAKgAqACoAKgAeAEsASwBLAEsASwBLAEsASwBLAEsADQANACsAKwArACsAKwBcAFwAKwBcACsAKwBcAFwAKwBcACsAKwBcACsAKwArACsAKwArAFwAXABcAFwAKwBcAFwAXABcAFwAXABcACsAXABcAFwAKwBcACsAXAArACsAXABcACsAXABcAFwAXAAqAFwAXAAqACoAKgAqACoAKgArACoAKgBcACsAKwBcAFwAXABcAFwAKwBcACsAKgAqACoAKgAqACoAKwArAEsASwBLAEsASwBLAEsASwBLAEsAKwArAFwAXABcAFwAUAAOAA4ADgAOAB4ADgAOAAkADgAOAA0ACQATABMAEwATABMACQAeABMAHgAeAB4ABAAEAB4AHgAeAB4AHgAeAEsASwBLAEsASwBLAEsASwBLAEsAUABQAFAAUABQAFAAUABQAFAAUAANAAQAHgAEAB4ABAAWABEAFgARAAQABABQAFAAUABQAFAAUABQAFAAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArACsAKwArAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAANAAQABAAEAAQABAANAAQABABQAFAAUABQAFAABAAEAAQABAAEAAQABAAEAAQABAAEACsABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEACsADQANAB4AHgAeAB4AHgAeAAQAHgAeAB4AHgAeAB4AKwAeAB4ADgAOAA0ADgAeAB4AHgAeAB4ACQAJACsAKwArACsAKwBcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAKgAqACoAKgAqACoAKgAqACoAKgAqACoAKgAqACoAKgAqACoAKgAqAFwASwBLAEsASwBLAEsASwBLAEsASwANAA0AHgAeAB4AHgBcAFwAXABcAFwAXAAqACoAKgAqAFwAXABcAFwAKgAqACoAXAAqACoAKgBcAFwAKgAqACoAKgAqACoAKgBcAFwAXAAqACoAKgAqAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAKgAqACoAKgAqACoAKgAqACoAKgAqACoAXAAqAEsASwBLAEsASwBLAEsASwBLAEsAKgAqACoAKgAqACoAUABQAFAAUABQAFAAKwBQACsAKwArACsAKwBQACsAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAAeAFAAUABQAFAAWABYAFgAWABYAFgAWABYAFgAWABYAFgAWABYAFgAWABYAFgAWABYAFgAWABYAFgAWABYAFgAWABYAFgAWABYAFkAWQBZAFkAWQBZAFkAWQBZAFkAWQBZAFkAWQBZAFkAWQBZAFkAWQBZAFkAWQBZAFkAWQBZAFkAWQBZAFkAWQBaAFoAWgBaAFoAWgBaAFoAWgBaAFoAWgBaAFoAWgBaAFoAWgBaAFoAWgBaAFoAWgBaAFoAWgBaAFoAWgBaAFoAUABQAFAAUABQAFAAUABQAFAAKwBQAFAAUABQACsAKwBQAFAAUABQAFAAUABQACsAUAArAFAAUABQAFAAKwArAFAAUABQAFAAUABQAFAAUABQACsAUABQAFAAUAArACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQACsAUABQAFAAUAArACsAUABQAFAAUABQAFAAUAArAFAAKwBQAFAAUABQACsAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArAFAAUABQAFAAKwArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQACsAKwAEAAQABAAeAA0AHgAeAB4AHgAeAB4AHgBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwArACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAAeAB4AHgAeAB4AHgAeAB4AHgAeACsAKwArACsAKwArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwArAFAAUABQAFAAUABQACsAKwANAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAAeAB4AUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAA0AUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQABYAEQArACsAKwBQAFAAUABQAFAAUABQAFAAUABQAFAADQANAA0AUABQAFAAUABQAFAAUABQAFAAUABQACsAKwArACsAKwArACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArAFAAUABQAFAABAAEAAQAKwArACsAKwArACsAKwArACsAKwArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAAQABAAEAA0ADQArACsAKwArACsAKwArACsAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAAEAAQAKwArACsAKwArACsAKwArACsAKwArACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArAFAAUABQACsABAAEACsAKwArACsAKwArACsAKwArACsAKwArAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXAAqACoAKgAqACoAKgAqACoAKgAqACoAKgAqACoAKgAqACoAKgAqACoADQANABUAXAANAB4ADQAbAFwAKgArACsASwBLAEsASwBLAEsASwBLAEsASwArACsAKwArACsAKwBQAFAAUABQAFAAUABQAFAAUABQACsAKwArACsAKwArAB4AHgATABMADQANAA4AHgATABMAHgAEAAQABAAJACsASwBLAEsASwBLAEsASwBLAEsASwArACsAKwArACsAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArACsAKwArACsAKwArACsAUABQAFAAUABQAAQABABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAABABQACsAKwArACsAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQACsAKwArACsAKwArACsAKwArACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArAAQABAAEAAQABAAEAAQABAAEAAQABAAEACsAKwArACsABAAEAAQABAAEAAQABAAEAAQABAAEAAQAKwArACsAKwAeACsAKwArABMAEwBLAEsASwBLAEsASwBLAEsASwBLAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcACsAKwBcAFwAXABcAFwAKwArACsAKwArACsAKwArACsAKwArAFwAXABcAFwAXABcAFwAXABcAFwAXABcACsAKwArACsAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAKwArACsAKwArACsASwBLAEsASwBLAEsASwBLAEsASwBcACsAKwArACoAKgBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAABAAEAAQABAAEACsAKwAeAB4AXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAKgAqACoAKgAqACoAKgAqACoAKgArACoAKgAqACoAKgAqACoAKgAqACoAKgAqACoAKgAqACoAKgAqACoAKgAqACoAKgAqACoAKgAqACoAKgArACsABABLAEsASwBLAEsASwBLAEsASwBLACsAKwArACsAKwArAEsASwBLAEsASwBLAEsASwBLAEsAKwArACsAKwArACsAKgAqACoAKgAqACoAKgBcACoAKgAqACoAKgAqACsAKwAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAArAAQABAAEAAQABABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAAEAAQABAAEAAQAUABQAFAAUABQAFAAUAArACsAKwArAEsASwBLAEsASwBLAEsASwBLAEsADQANAB4ADQANAA0ADQAeAB4AHgAeAB4AHgAeAB4AHgAeAAQABAAEAAQABAAEAAQABAAEAB4AHgAeAB4AHgAeAB4AHgAeACsAKwArAAQABAAEAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQAUABQAEsASwBLAEsASwBLAEsASwBLAEsAUABQAFAAUABQAFAAUABQAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAArACsAKwArACsAKwArACsAHgAeAB4AHgBQAFAAUABQAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAArACsAKwANAA0ADQANAA0ASwBLAEsASwBLAEsASwBLAEsASwArACsAKwBQAFAAUABLAEsASwBLAEsASwBLAEsASwBLAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAANAA0AUABQAFAAUABQAFAAUABQAFAAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArAB4AHgAeAB4AHgAeAB4AHgArACsAKwArACsAKwArACsABAAEAAQAHgAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAFAAUABQAFAABABQAFAAUABQAAQABAAEAFAAUAAEAAQABAArACsAKwArACsAKwAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQAKwAEAAQABAAEAAQAHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgArACsAUABQAFAAUABQAFAAKwArAFAAUABQAFAAUABQAFAAUAArAFAAKwBQACsAUAArAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AKwArAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeACsAHgAeAB4AHgAeAB4AHgAeAFAAHgAeAB4AUABQAFAAKwAeAB4AHgAeAB4AHgAeAB4AHgAeAFAAUABQAFAAKwArAB4AHgAeAB4AHgAeACsAHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgArACsAUABQAFAAKwAeAB4AHgAeAB4AHgAeAA4AHgArAA0ADQANAA0ADQANAA0ACQANAA0ADQAIAAQACwAEAAQADQAJAA0ADQAMAB0AHQAeABcAFwAWABcAFwAXABYAFwAdAB0AHgAeABQAFAAUAA0AAQABAAQABAAEAAQABAAJABoAGgAaABoAGgAaABoAGgAeABcAFwAdABUAFQAeAB4AHgAeAB4AHgAYABYAEQAVABUAFQAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgANAB4ADQANAA0ADQAeAA0ADQANAAcAHgAeAB4AHgArAAQABAAEAAQABAAEAAQABAAEAAQAUABQACsAKwBPAFAAUABQAFAAUAAeAB4AHgAWABEATwBQAE8ATwBPAE8AUABQAFAAUABQAB4AHgAeABYAEQArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwArACsAGwAbABsAGwAbABsAGwAaABsAGwAbABsAGwAbABsAGwAbABsAGwAbABsAGwAaABsAGwAbABsAGgAbABsAGgAbABsAGwAbABsAGwAbABsAGwAbABsAGwAbABsAGwAbABsABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArAB4AHgBQABoAHgAdAB4AUAAeABoAHgAeAB4AHgAeAB4AHgAeAB4ATwAeAFAAGwAeAB4AUABQAFAAUABQAB4AHgAeAB0AHQAeAFAAHgBQAB4AUAAeAFAATwBQAFAAHgAeAB4AHgAeAB4AHgBQAFAAUABQAFAAHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgBQAB4AUABQAFAAUABPAE8AUABQAFAAUABQAE8AUABQAE8AUABPAE8ATwBPAE8ATwBPAE8ATwBPAE8ATwBQAFAAUABQAE8ATwBPAE8ATwBPAE8ATwBPAE8AUABQAFAAUABQAFAAUABQAFAAHgAeAFAAUABQAFAATwAeAB4AKwArACsAKwAdAB0AHQAdAB0AHQAdAB0AHQAdAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAdAB4AHQAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHQAeAB0AHQAeAB4AHgAdAB0AHgAeAB0AHgAeAB4AHQAeAB0AGwAbAB4AHQAeAB4AHgAeAB0AHgAeAB0AHQAdAB0AHgAeAB0AHgAdAB4AHQAdAB0AHQAdAB0AHgAdAB4AHgAeAB4AHgAdAB0AHQAdAB4AHgAeAB4AHQAdAB4AHgAeAB4AHgAeAB4AHgAeAB4AHQAeAB4AHgAdAB4AHgAeAB4AHgAdAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHQAdAB4AHgAdAB0AHQAdAB4AHgAdAB0AHgAeAB0AHQAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAdAB0AHgAeAB0AHQAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB0AHgAeAB4AHQAeAB4AHgAeAB4AHgAeAB0AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAdAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeABQAHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAWABEAFgARAB4AHgAeAB4AHgAeAB0AHgAeAB4AHgAeAB4AHgAlACUAHgAeAB4AHgAeAB4AHgAeAB4AFgARAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeACUAJQAlACUAHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwBPAE8ATwBPAE8ATwBPAE8ATwBPAE8ATwBPAE8ATwBPAE8ATwBPAE8ATwBPAE8ATwBPAE8ATwBPAE8ATwBPAE8AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQBPAE8ATwBPAE8ATwBPAE8ATwBPAE8ATwBPAE8ATwBPAE8ATwBPAE8ATwBQAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB4AHgAeAB4AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHgAeAB0AHQAdAB0AHgAeAB4AHgAeAB4AHgAeAB4AHgAdAB0AHgAdAB0AHQAdAB0AHQAdAB4AHgAeAB4AHgAeAB4AHgAdAB0AHgAeAB0AHQAeAB4AHgAeAB0AHQAeAB4AHgAeAB0AHQAdAB4AHgAdAB4AHgAdAB0AHQAdAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHQAdAB0AHQAeAB4AHgAeAB4AHgAeAB4AHgAdAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AJQAlACUAJQAeAB0AHQAeAB4AHQAeAB4AHgAeAB0AHQAeAB4AHgAeACUAJQAdAB0AJQAeACUAJQAlACAAJQAlAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AJQAlACUAHgAeAB4AHgAdAB4AHQAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHQAdAB4AHQAdAB0AHgAdACUAHQAdAB4AHQAdAB4AHQAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAlAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB0AHQAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AJQAlACUAJQAlACUAJQAlACUAJQAlACUAHQAdAB0AHQAlAB4AJQAlACUAHQAlACUAHQAdAB0AJQAlAB0AHQAlAB0AHQAlACUAJQAeAB0AHgAeAB4AHgAdAB0AJQAdAB0AHQAdAB0AHQAlACUAJQAlACUAHQAlACUAIAAlAB0AHQAlACUAJQAlACUAJQAlACUAHgAeAB4AJQAlACAAIAAgACAAHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAdAB4AHgAeABcAFwAXABcAFwAXAB4AEwATACUAHgAeAB4AFgARABYAEQAWABEAFgARABYAEQAWABEAFgARAE8ATwBPAE8ATwBPAE8ATwBPAE8ATwBPAE8ATwBPAE8ATwBPAE8ATwBPAE8AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAWABEAHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AFgARABYAEQAWABEAFgARABYAEQAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeABYAEQAWABEAFgARABYAEQAWABEAFgARABYAEQAWABEAFgARABYAEQAWABEAHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AFgARABYAEQAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeABYAEQAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHQAdAB0AHQAdAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AKwArAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AKwArACsAHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AKwAeAB4AHgAeAB4AHgAeAB4AHgArACsAKwArACsAKwArACsAKwArACsAKwArAB4AHgAeAB4AKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAEAAQABAAeAB4AKwArACsAKwArABMADQANAA0AUAATAA0AUABQAFAAUABQAFAAUABQACsAKwArACsAKwArACsAUAANACsAKwArACsAKwArACsAKwArACsAKwArACsAKwAEAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArACsAKwArACsAKwArACsAKwBQAFAAUABQAFAAUABQACsAUABQAFAAUABQAFAAUAArAFAAUABQAFAAUABQAFAAKwBQAFAAUABQAFAAUABQACsAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXAA0ADQANAA0ADQANAA0ADQAeAA0AFgANAB4AHgAXABcAHgAeABcAFwAWABEAFgARABYAEQAWABEADQANAA0ADQATAFAADQANAB4ADQANAB4AHgAeAB4AHgAMAAwADQANAA0AHgANAA0AFgANAA0ADQANAA0ADQANACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACsAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAKwArACsAKwArACsAKwArACsAKwArACsAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwAlACUAJQAlACUAJQAlACUAJQAlACUAJQArACsAKwArAA0AEQARACUAJQBHAFcAVwAWABEAFgARABYAEQAWABEAFgARACUAJQAWABEAFgARABYAEQAWABEAFQAWABEAEQAlAFcAVwBXAFcAVwBXAFcAVwBXAAQABAAEAAQABAAEACUAVwBXAFcAVwA2ACUAJQBXAFcAVwBHAEcAJQAlACUAKwBRAFcAUQBXAFEAVwBRAFcAUQBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFEAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBRAFcAUQBXAFEAVwBXAFcAVwBXAFcAUQBXAFcAVwBXAFcAVwBRAFEAKwArAAQABAAVABUARwBHAFcAFQBRAFcAUQBXAFEAVwBRAFcAUQBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFEAVwBRAFcAUQBXAFcAVwBXAFcAVwBRAFcAVwBXAFcAVwBXAFEAUQBXAFcAVwBXABUAUQBHAEcAVwArACsAKwArACsAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAKwArAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwArACUAJQBXAFcAVwBXACUAJQAlACUAJQAlACUAJQAlACUAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAKwArACsAKwArACUAJQAlACUAKwArACsAKwArACsAKwArACsAKwArACsAUQBRAFEAUQBRAFEAUQBRAFEAUQBRAFEAUQBRAFEAUQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACsAVwBXAFcAVwBXAFcAVwBXAFcAVwAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlAE8ATwBPAE8ATwBPAE8ATwAlAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXACUAJQAlACUAJQAlACUAJQAlACUAVwBXAFcAVwBXAFcAVwBXAFcAVwBXACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAEcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAKwArACsAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQArACsAKwArACsAKwArACsAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAADQATAA0AUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABLAEsASwBLAEsASwBLAEsASwBLAFAAUAArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAFAABAAEAAQABAAeAAQABAAEAAQABAAEAAQABAAEAAQAHgBQAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AUABQAAQABABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAAQABAAeAA0ADQANAA0ADQArACsAKwArACsAKwArACsAHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAFAAUABQAFAAUABQAFAAUABQAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AUAAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgBQAB4AHgAeAB4AHgAeAFAAHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgArAB4AHgAeAB4AHgAeAB4AHgArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAUABQAFAAUABQAFAAUABQAFAAUABQAAQAUABQAFAABABQAFAAUABQAAQAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAAQABAAEAAQABAAeAB4AHgAeACsAKwArACsAUABQAFAAUABQAFAAHgAeABoAHgArACsAKwArACsAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAADgAOABMAEwArACsAKwArACsAKwArACsABAAEAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAAQABAAEAAQABAAEACsAKwArACsAKwArACsAKwANAA0ASwBLAEsASwBLAEsASwBLAEsASwArACsAKwArACsAKwAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABABQAFAAUABQAFAAUAAeAB4AHgBQAA4AUAArACsAUABQAFAAUABQAFAABAAEAAQABAAEAAQABAAEAA0ADQBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQAKwArACsAKwArACsAKwArACsAKwArAB4AWABYAFgAWABYAFgAWABYAFgAWABYAFgAWABYAFgAWABYAFgAWABYAFgAWABYAFgAWABYAFgAWABYACsAKwArAAQAHgAeAB4AHgAeAB4ADQANAA0AHgAeAB4AHgArAFAASwBLAEsASwBLAEsASwBLAEsASwArACsAKwArAB4AHgBcAFwAXABcAFwAKgBcAFwAXABcAFwAXABcAFwAXABcAEsASwBLAEsASwBLAEsASwBLAEsAXABcAFwAXABcACsAUABQAFAAUABQAFAAUABQAFAABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEACsAKwArACsAKwArACsAKwArAFAAUABQAAQAUABQAFAAUABQAFAAUABQAAQABAArACsASwBLAEsASwBLAEsASwBLAEsASwArACsAHgANAA0ADQBcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAKgAqACoAXAAqACoAKgBcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXAAqAFwAKgAqACoAXABcACoAKgBcAFwAXABcAFwAKgAqAFwAKgBcACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArAFwAXABcACoAKgBQAFAAUABQAFAAUABQAFAAUABQAFAABAAEAAQABAAEAA0ADQBQAFAAUAAEAAQAKwArACsAKwArACsAKwArACsAKwBQAFAAUABQAFAAUAArACsAUABQAFAAUABQAFAAKwArAFAAUABQAFAAUABQACsAKwArACsAKwArACsAKwArAFAAUABQAFAAUABQAFAAKwBQAFAAUABQAFAAUABQACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAAEAAQABAAEAAQABAAEAAQADQAEAAQAKwArAEsASwBLAEsASwBLAEsASwBLAEsAKwArACsAKwArACsAVABVAFUAVQBVAFUAVQBVAFUAVQBVAFUAVQBVAFUAVQBVAFUAVQBVAFUAVQBVAFUAVQBVAFUAVQBUAFUAVQBVAFUAVQBVAFUAVQBVAFUAVQBVAFUAVQBVAFUAVQBVAFUAVQBVAFUAVQBVAFUAVQBVACsAKwArACsAKwArACsAKwArACsAKwArAFkAWQBZAFkAWQBZAFkAWQBZAFkAWQBZAFkAWQBZAFkAWQBZAFkAKwArACsAKwBaAFoAWgBaAFoAWgBaAFoAWgBaAFoAWgBaAFoAWgBaAFoAWgBaAFoAWgBaAFoAWgBaAFoAWgBaAFoAKwArACsAKwAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXACUAJQBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAJQAlACUAJQAlACUAUABQAFAAUABQAFAAUAArACsAKwArACsAKwArACsAKwArACsAKwBQAFAAUABQAFAAKwArACsAKwArAFYABABWAFYAVgBWAFYAVgBWAFYAVgBWAB4AVgBWAFYAVgBWAFYAVgBWAFYAVgBWAFYAVgArAFYAVgBWAFYAVgArAFYAKwBWAFYAKwBWAFYAKwBWAFYAVgBWAFYAVgBWAFYAVgBWAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAEQAWAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUAAaAB4AKwArAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQAGAARABEAGAAYABMAEwAWABEAFAArACsAKwArACsAKwAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEACUAJQAlACUAJQAWABEAFgARABYAEQAWABEAFgARABYAEQAlACUAFgARACUAJQAlACUAJQAlACUAEQAlABEAKwAVABUAEwATACUAFgARABYAEQAWABEAJQAlACUAJQAlACUAJQAlACsAJQAbABoAJQArACsAKwArAFAAUABQAFAAUAArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwArAAcAKwATACUAJQAbABoAJQAlABYAEQAlACUAEQAlABEAJQBXAFcAVwBXAFcAVwBXAFcAVwBXABUAFQAlACUAJQATACUAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXABYAJQARACUAJQAlAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwAWACUAEQAlABYAEQARABYAEQARABUAVwBRAFEAUQBRAFEAUQBRAFEAUQBRAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAEcARwArACsAVwBXAFcAVwBXAFcAKwArAFcAVwBXAFcAVwBXACsAKwBXAFcAVwBXAFcAVwArACsAVwBXAFcAKwArACsAGgAbACUAJQAlABsAGwArAB4AHgAeAB4AHgAeAB4AKwArACsAKwArACsAKwArACsAKwAEAAQABAAQAB0AKwArAFAAUABQAFAAUABQAFAAUABQAFAAUABQACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwBQAFAAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQACsAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArACsAKwArACsADQANAA0AKwArACsAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQACsAKwArAB4AHgAeAB4AHgAeAB4AHgAeAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgBQAFAAHgAeAB4AKwAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgArACsAKwArAB4AKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4ABAArACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArAAQAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwArACsAKwArACsAKwArACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArACsAKwArACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAAEAAQABAAEAAQAKwArACsAKwArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQACsADQBQAFAAUABQACsAKwArACsAUABQAFAAUABQAFAAUABQAA0AUABQAFAAUABQACsAKwArACsAKwArACsAKwArACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArACsAKwArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwArACsAKwArACsAKwArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwArACsAKwArACsAKwArACsAKwArAB4AKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwBQAFAAUABQAFAAUAArACsAUAArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQACsAUABQACsAKwArAFAAKwArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArAA0AUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAB4AHgBQAFAAUABQAFAAUABQACsAKwArACsAKwArACsAUABQAFAAUABQAFAAUABQAFAAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQACsAUABQACsAKwArACsAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwArACsADQBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwArACsAKwArAB4AUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwArACsAKwBQAFAAUABQAFAABAAEAAQAKwAEAAQAKwArACsAKwArAAQABAAEAAQAUABQAFAAUAArAFAAUABQACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQACsAKwArACsABAAEAAQAKwArACsAKwAEAFAAUABQAFAAUABQAFAAUAArACsAKwArACsAKwArACsADQANAA0ADQANAA0ADQANAB4AKwArACsAKwArACsAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAB4AUABQAFAAUABQAFAAUABQAB4AUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAABAAEACsAKwArACsAUABQAFAAUABQAA0ADQANAA0ADQANABQAKwArACsAKwArACsAKwArACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArACsAKwANAA0ADQANAA0ADQANAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQACsAKwArACsAKwArACsAHgAeAB4AHgArACsAKwArACsAKwArACsAKwArACsAKwBQAFAAUABQAFAAUABQACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArACsAKwArACsAKwArACsAKwArACsAKwArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwArACsAKwArACsAKwBQAFAAUABQAFAAUAAEAAQABAAEAAQABAAEAA0ADQAeAB4AHgAeAB4AKwArACsAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAEsASwBLAEsASwBLAEsASwBLAEsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsABABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAAQABAAEAAQABAAEAAQABAAEAAQABAAeAB4AHgANAA0ADQANACsAKwArACsAKwArACsAKwArACsAKwArACsAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwArACsAKwArACsAKwBLAEsASwBLAEsASwBLAEsASwBLACsAKwArACsAKwArAFAAUABQAFAAUABQAFAABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEACsASwBLAEsASwBLAEsASwBLAEsASwANAA0ADQANACsAKwArACsAKwArACsAKwArACsAKwArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAABAAeAA4AUAArACsAKwArACsAKwArACsAKwAEAFAAUABQAFAADQANAB4ADQAeAAQABAAEAB4AKwArAEsASwBLAEsASwBLAEsASwBLAEsAUAAOAFAADQANAA0AKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwArACsAKwArACsAKwArACsAKwArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAAEAAQABAAEAAQABAAEAAQABAAEAAQABAANAA0AHgANAA0AHgAEACsAUABQAFAAUABQAFAAUAArAFAAKwBQAFAAUABQACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwBQAFAAUABQAFAAUABQAFAAUABQAA0AKwArACsAKwArACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAAEAAQABAAEAAQABAAEAAQABAAEAAQAKwArACsAKwArAEsASwBLAEsASwBLAEsASwBLAEsAKwArACsAKwArACsABAAEAAQABAArAFAAUABQAFAAUABQAFAAUAArACsAUABQACsAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAAQABAAEAAQABAArACsABAAEACsAKwAEAAQABAArACsAUAArACsAKwArACsAKwAEACsAKwArACsAKwBQAFAAUABQAFAABAAEACsAKwAEAAQABAAEAAQABAAEACsAKwArAAQABAAEAAQABAArACsAKwArACsAKwArACsAKwArACsABAAEAAQABAAEAAQABABQAFAAUABQAA0ADQANAA0AHgBLAEsASwBLAEsASwBLAEsASwBLACsADQArAB4AKwArAAQABAAEAAQAUABQAB4AUAArACsAKwArACsAKwArACsASwBLAEsASwBLAEsASwBLAEsASwArACsAKwArACsAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAAEAAQABAAEAAQABAAEACsAKwAEAAQABAAEAAQABAAEAAQABAAOAA0ADQATABMAHgAeAB4ADQANAA0ADQANAA0ADQANAA0ADQANAA0ADQANAA0AUABQAFAAUAAEAAQAKwArAAQADQANAB4AUAArACsAKwArACsAKwArACsAKwArACsASwBLAEsASwBLAEsASwBLAEsASwArACsAKwArACsAKwAOAA4ADgAOAA4ADgAOAA4ADgAOAA4ADgAOACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsASwBLAEsASwBLAEsASwBLAEsASwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXAArACsAKwAqACoAKgAqACoAKgAqACoAKgAqACoAKgAqACoAKgArACsAKwArAEsASwBLAEsASwBLAEsASwBLAEsAXABcAA0ADQANACoASwBLAEsASwBLAEsASwBLAEsASwBQAFAAUABQAFAAUABQAFAAUAArACsAKwArACsAKwArACsAKwArACsAKwBQAFAABAAEAAQABAAEAAQABAAEAAQABABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAAEAAQABAAEAAQABAAEAFAABAAEAAQABAAOAB4ADQANAA0ADQAOAB4ABAArACsAKwArACsAKwArACsAUAAEAAQABAAEAAQABAAEAAQABAAEAAQAUABQAFAAUAArACsAUABQAFAAUAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAA0ADQANACsADgAOAA4ADQANACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwBQAFAAUABQAFAAUABQAFAAUAArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAABAAEAAQABAAEAAQABAAEACsABAAEAAQABAAEAAQABAAEAFAADQANAA0ADQANACsAKwArACsAKwArACsAKwArACsASwBLAEsASwBLAEsASwBLAEsASwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArACsAKwAOABMAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwArAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAArAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAArACsAKwArACsAKwArACsAKwBQAFAAUABQAFAAUABQACsAUABQACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAAEAAQABAAEAAQABAArACsAKwAEACsABAAEACsABAAEAAQABAAEAAQABABQAAQAKwArACsAKwArACsAKwArAEsASwBLAEsASwBLAEsASwBLAEsAKwArACsAKwArACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQACsAKwArACsAKwArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQACsADQANAA0ADQANACsAKwArACsAKwArACsAKwArACsAKwBQAFAAUABQACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAASABIAEgAQwBDAEMAUABQAFAAUABDAFAAUABQAEgAQwBIAEMAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAASABDAEMAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABIAEMAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArAEsASwBLAEsASwBLAEsASwBLAEsAKwArACsAKwANAA0AKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwArAAQABAAEAAQABAANACsAKwArACsAKwArACsAKwArACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAAEAAQABAAEAAQABAAEAA0ADQANAB4AHgAeAB4AHgAeAFAAUABQAFAADQAeACsAKwArACsAKwArACsAKwArACsASwBLAEsASwBLAEsASwBLAEsASwArAFAAUABQAFAAUABQAFAAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArACsAKwArACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArAFAAUABQAFAAUAArACsAKwArACsAKwArACsAKwArACsAUAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsABAAEAAQABABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAEcARwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwArACsAKwArACsAKwArACsAKwArACsAKwArAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAKwArACsAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAKwArACsAKwArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwArACsAKwArACsAKwBQAFAAUABQAFAAUABQAFAAUABQACsAKwAeAAQABAANAAQABAAEAAQAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeACsAKwArACsAKwArACsAKwArACsAHgAeAB4AHgAeAB4AHgArACsAHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4ABAAEAAQABAAEAB4AHgAeAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQAHgAeAAQABAAEAAQABAAEAAQAHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAEAAQABAAEAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArAB4AHgAEAAQABAAeACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AKwArACsAKwArACsAKwArACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwArACsAKwArACsAKwArACsAKwArACsAKwArAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeACsAHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgArAFAAUAArACsAUAArACsAUABQACsAKwBQAFAAUABQACsAHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AKwBQACsAUABQAFAAUABQAFAAUAArAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgArAFAAUABQAFAAKwArAFAAUABQAFAAUABQAFAAUAArAFAAUABQAFAAUABQAFAAKwAeAB4AUABQAFAAUABQACsAUAArACsAKwBQAFAAUABQAFAAUABQACsAHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgArACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAAeAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAFAAUABQAFAAUABQAFAAUABQAFAAUAAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAHgAeAB4AHgAeAB4AHgAeAB4AKwArAEsASwBLAEsASwBLAEsASwBLAEsASwBLAEsASwBLAEsASwBLAEsASwBLAEsASwBLAEsASwBLAEsASwBLAEsASwBLAEsABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAB4AHgAeAB4ABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAB4AHgAeAB4AHgAeAB4AHgAEAB4AHgAeAB4AHgAeAB4AHgAeAB4ABAAeAB4ADQANAA0ADQAeACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArAAQABAAEAAQABAArAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsABAAEAAQABAAEAAQABAArAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAArACsABAAEAAQABAAEAAQABAArAAQABAArAAQABAAEAAQABAArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwBQAFAAUABQAFAAKwArAFAAUABQAFAAUABQAFAAUABQAAQABAAEAAQABAAEAAQAKwArACsAKwArACsAKwArACsAHgAeAB4AHgAEAAQABAAEAAQABAAEACsAKwArACsAKwBLAEsASwBLAEsASwBLAEsASwBLACsAKwArACsAFgAWAFAAUABQAFAAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArAFAAUAArAFAAKwArAFAAKwBQAFAAUABQAFAAUABQAFAAUABQACsAUABQAFAAUAArAFAAKwBQACsAKwArACsAKwArAFAAKwArACsAKwBQACsAUAArAFAAKwBQAFAAUAArAFAAUAArAFAAKwArAFAAKwBQACsAUAArAFAAKwBQACsAUABQACsAUAArACsAUABQAFAAUAArAFAAUABQAFAAUABQAFAAKwBQAFAAUABQACsAUABQAFAAUAArAFAAKwBQAFAAUABQAFAAUABQAFAAUABQACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQACsAKwArACsAKwBQAFAAUAArAFAAUABQAFAAUAArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArAB4AHgArACsAKwArACsAKwArACsAKwArACsAKwArACsATwBPAE8ATwBPAE8ATwBPAE8ATwBPAE8ATwAlACUAJQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAeACUAHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHgAeACUAJQAlACUAHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACkAKQApACkAKQApACkAKQApACkAKQApACkAKQApACkAKQApACkAKQApACkAKQApACkAKQAlACUAJQAlACUAIAAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlAB4AHgAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAHgAeACUAJQAlACUAJQAeACUAJQAlACUAJQAgACAAIAAlACUAIAAlACUAIAAgACAAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAIQAhACEAIQAhACUAJQAgACAAJQAlACAAIAAgACAAIAAgACAAIAAgACAAIAAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAIAAgACAAIAAlACUAJQAlACAAJQAgACAAIAAgACAAIAAgACAAIAAlACUAJQAgACUAJQAlACUAIAAgACAAJQAgACAAIAAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAeACUAHgAlAB4AJQAlACUAJQAlACAAJQAlACUAJQAeACUAHgAeACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAHgAeAB4AHgAeAB4AHgAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlAB4AHgAeAB4AHgAeAB4AHgAeAB4AJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAIAAgACUAJQAlACUAIAAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAIAAlACUAJQAlACAAIAAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAeAB4AHgAeAB4AHgAeAB4AJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlAB4AHgAeAB4AHgAeACUAJQAlACUAJQAlACUAIAAgACAAJQAlACUAIAAgACAAIAAgAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AFwAXABcAFQAVABUAHgAeAB4AHgAlACUAJQAgACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAIAAgACAAJQAlACUAJQAlACUAJQAlACUAIAAlACUAJQAlACUAJQAlACUAJQAlACUAIAAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAlACUAJQAlACUAJQAlACUAJQAlACUAJQAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAlACUAJQAlAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AJQAlACUAJQAlACUAJQAlAB4AHgAeAB4AHgAeAB4AHgAeAB4AJQAlACUAJQAlACUAHgAeAB4AHgAeAB4AHgAeACUAJQAlACUAJQAlACUAJQAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeACUAJQAlACUAJQAlACUAJQAlACUAJQAlACAAIAAgACAAIAAlACAAIAAlACUAJQAlACUAJQAgACUAJQAlACUAJQAlACUAJQAlACAAIAAgACAAIAAgACAAIAAgACAAJQAlACUAIAAgACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACsAKwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAJQAlACUAJQAlACUAJQAlACUAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAJQAlACUAJQAlACUAJQAlACUAJQAlAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQArAAQAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsA"),U=Array.isArray(i)?function(A){for(var e=A.length,t=[],r=0;r=this._value.length?-1:this._value[A]},yA.prototype.consumeUnicodeRangeToken=function(){for(var A=[],e=this.consumeCodePoint();aA(e)&&A.length<6;)A.push(e),e=this.consumeCodePoint();for(var t=!1;63===e&&A.length<6;)A.push(e),e=this.consumeCodePoint(),t=!0;if(t){var r=parseInt(l.apply(void 0,A.map(function(A){return 63===A?48:A})),16),n=parseInt(l.apply(void 0,A.map(function(A){return 63===A?70:A})),16);return{type:sA.UNICODE_RANGE_TOKEN,start:r,end:n}}var B=parseInt(l.apply(void 0,A),16);if(45===this.peekCodePoint(0)&&aA(this.peekCodePoint(1))){this.consumeCodePoint(),e=this.consumeCodePoint();for(var s=[];aA(e)&&s.length<6;)s.push(e),e=this.consumeCodePoint();return n=parseInt(l.apply(void 0,s),16),{type:sA.UNICODE_RANGE_TOKEN,start:B,end:n}}return{type:sA.UNICODE_RANGE_TOKEN,start:B,end:B}},yA.prototype.consumeIdentLikeToken=function(){var A=this.consumeName();return"url"===A.toLowerCase()&&40===this.peekCodePoint(0)?(this.consumeCodePoint(),this.consumeUrlToken()):40===this.peekCodePoint(0)?(this.consumeCodePoint(),{type:sA.FUNCTION_TOKEN,value:A}):{type:sA.IDENT_TOKEN,value:A}},yA.prototype.consumeUrlToken=function(){var A=[];if(this.consumeWhiteSpace(),-1===this.peekCodePoint(0))return{type:sA.URL_TOKEN,value:""};var e,t=this.peekCodePoint(0);if(39===t||34===t){var r=this.consumeStringToken(this.consumeCodePoint());return r.type===sA.STRING_TOKEN&&(this.consumeWhiteSpace(),-1===this.peekCodePoint(0)||41===this.peekCodePoint(0))?(this.consumeCodePoint(),{type:sA.URL_TOKEN,value:r.value}):(this.consumeBadUrlRemnants(),IA)}for(;;){var n=this.consumeCodePoint();if(-1===n||41===n)return{type:sA.URL_TOKEN,value:l.apply(void 0,A)};if(cA(n))return this.consumeWhiteSpace(),-1===this.peekCodePoint(0)||41===this.peekCodePoint(0)?(this.consumeCodePoint(),{type:sA.URL_TOKEN,value:l.apply(void 0,A)}):(this.consumeBadUrlRemnants(),IA);if(34===n||39===n||40===n||0<=(e=n)&&e<=8||11===e||14<=e&&e<=31||127===e)return this.consumeBadUrlRemnants(),IA;if(92===n){if(!uA(n,this.peekCodePoint(0)))return this.consumeBadUrlRemnants(),IA;A.push(this.consumeEscapedCodePoint())}else A.push(n)}},yA.prototype.consumeWhiteSpace=function(){for(;cA(this.peekCodePoint(0));)this.consumeCodePoint()},yA.prototype.consumeBadUrlRemnants=function(){for(;;){var A=this.consumeCodePoint();if(41===A||-1===A)return;uA(A,this.peekCodePoint(0))&&this.consumeEscapedCodePoint()}},yA.prototype.consumeStringSlice=function(A){for(var e="";0>8,r=255&A>>16,n=255&A>>24;return e<255?"rgba("+n+","+r+","+t+","+e/255+")":"rgb("+n+","+r+","+t+")"}function re(A,e){if(A.type===sA.NUMBER_TOKEN)return A.number;if(A.type!==sA.PERCENTAGE_TOKEN)return 0;var t=3===e?1:255;return 3===e?A.number/100*t:Math.round(A.number/100*t)}function ne(A){var e=A.filter(kA);if(3===e.length){var t=e.map(re),r=t[0],n=t[1],B=t[2];return ue(r,n,B,1)}if(4!==e.length)return 0;var s=e.map(re),o=(r=s[0],n=s[1],B=s[2],s[3]);return ue(r,n,B,o)}var Be=function(A,e){return e===sA.LEFT_CURLY_BRACKET_TOKEN&&A.type===sA.RIGHT_CURLY_BRACKET_TOKEN||(e===sA.LEFT_SQUARE_BRACKET_TOKEN&&A.type===sA.RIGHT_SQUARE_BRACKET_TOKEN||e===sA.LEFT_PARENTHESIS_TOKEN&&A.type===sA.RIGHT_PARENTHESIS_TOKEN)},se={type:sA.NUMBER_TOKEN,number:0,flags:4},oe={type:sA.PERCENTAGE_TOKEN,number:50,flags:4},ie={type:sA.PERCENTAGE_TOKEN,number:100,flags:4},ae=function(A,e){if(A.type===sA.PERCENTAGE_TOKEN)return A.number/100*e;if(xA(A))switch(A.unit){case"rem":case"em":return 16*A.number;case"px":default:return A.number}return A.number},ce=function(A){if(A.type===sA.DIMENSION_TOKEN)switch(A.unit){case"deg":return Math.PI*A.number/180;case"grad":return Math.PI/200*A.number;case"rad":return A.number;case"turn":return 2*Math.PI*A.number}throw new Error("Unsupported angle type")},Qe=function(A){return Math.PI*A/180},we=function(A){if(A.type===sA.FUNCTION){var e=he[A.name];if(void 0===e)throw new Error('Attempting to parse an unsupported color function "'+A.name+'"');return e(A.values)}if(A.type===sA.HASH_TOKEN){if(3===A.value.length){var t=A.value.substring(0,1),r=A.value.substring(1,2),n=A.value.substring(2,3);return ue(parseInt(t+t,16),parseInt(r+r,16),parseInt(n+n,16),1)}if(4===A.value.length){t=A.value.substring(0,1),r=A.value.substring(1,2),n=A.value.substring(2,3);var B=A.value.substring(3,4);return ue(parseInt(t+t,16),parseInt(r+r,16),parseInt(n+n,16),parseInt(B+B,16)/255)}if(6===A.value.length){t=A.value.substring(0,2),r=A.value.substring(2,4),n=A.value.substring(4,6);return ue(parseInt(t,16),parseInt(r,16),parseInt(n,16),1)}if(8===A.value.length){t=A.value.substring(0,2),r=A.value.substring(2,4),n=A.value.substring(4,6),B=A.value.substring(6,8);return ue(parseInt(t,16),parseInt(r,16),parseInt(n,16),parseInt(B,16)/255)}}if(A.type===sA.IDENT_TOKEN){var s=He[A.value.toUpperCase()];if(void 0!==s)return s}return He.TRANSPARENT},ue=function(A,e,t,r){return(A<<24|e<<16|t<<8|Math.round(255*r)<<0)>>>0};function Ue(A,e,t){return t<0&&(t+=1),1<=t&&(t-=1),t<1/6?(e-A)*t*6+A:t<.5?e:t<2/3?6*(e-A)*(2/3-t)+A:A}function le(A){var e=A.filter(kA),t=e[0],r=e[1],n=e[2],B=e[3],s=(t.type===sA.NUMBER_TOKEN?Qe(t.number):ce(t))/(2*Math.PI),o=qA(r)?r.number/100:0,i=qA(n)?n.number/100:0,a=void 0!==B&&qA(B)?ae(B,1):1;if(0==o)return ue(255*i,255*i,255*i,1);var c=i<=.5?i*(1+o):i+o-i*o,Q=2*i-c,w=Ue(Q,c,s+1/3),u=Ue(Q,c,s),U=Ue(Q,c,s-1/3);return ue(255*w,255*u,255*U,a)}var Ce,ge,Ee,Fe,he={hsl:le,hsla:le,rgb:ne,rgba:ne},He={ALICEBLUE:4042850303,ANTIQUEWHITE:4209760255,AQUA:16777215,AQUAMARINE:2147472639,AZURE:4043309055,BEIGE:4126530815,BISQUE:4293182719,BLACK:255,BLANCHEDALMOND:4293643775,BLUE:65535,BLUEVIOLET:2318131967,BROWN:2771004159,BURLYWOOD:3736635391,CADETBLUE:1604231423,CHARTREUSE:2147418367,CHOCOLATE:3530104575,CORAL:4286533887,CORNFLOWERBLUE:1687547391,CORNSILK:4294499583,CRIMSON:3692313855,CYAN:16777215,DARKBLUE:35839,DARKCYAN:9145343,DARKGOLDENROD:3095837695,DARKGRAY:2846468607,DARKGREEN:6553855,DARKGREY:2846468607,DARKKHAKI:3182914559,DARKMAGENTA:2332068863,DARKOLIVEGREEN:1433087999,DARKORANGE:4287365375,DARKORCHID:2570243327,DARKRED:2332033279,DARKSALMON:3918953215,DARKSEAGREEN:2411499519,DARKSLATEBLUE:1211993087,DARKSLATEGRAY:793726975,DARKSLATEGREY:793726975,DARKTURQUOISE:13554175,DARKVIOLET:2483082239,DEEPPINK:4279538687,DEEPSKYBLUE:12582911,DIMGRAY:1768516095,DIMGREY:1768516095,DODGERBLUE:512819199,FIREBRICK:2988581631,FLORALWHITE:4294635775,FORESTGREEN:579543807,FUCHSIA:4278255615,GAINSBORO:3705462015,GHOSTWHITE:4177068031,GOLD:4292280575,GOLDENROD:3668254975,GRAY:2155905279,GREEN:8388863,GREENYELLOW:2919182335,GREY:2155905279,HONEYDEW:4043305215,HOTPINK:4285117695,INDIANRED:3445382399,INDIGO:1258324735,IVORY:4294963455,KHAKI:4041641215,LAVENDER:3873897215,LAVENDERBLUSH:4293981695,LAWNGREEN:2096890111,LEMONCHIFFON:4294626815,LIGHTBLUE:2916673279,LIGHTCORAL:4034953471,LIGHTCYAN:3774873599,LIGHTGOLDENRODYELLOW:4210742015,LIGHTGRAY:3553874943,LIGHTGREEN:2431553791,LIGHTGREY:3553874943,LIGHTPINK:4290167295,LIGHTSALMON:4288707327,LIGHTSEAGREEN:548580095,LIGHTSKYBLUE:2278488831,LIGHTSLATEGRAY:2005441023,LIGHTSLATEGREY:2005441023,LIGHTSTEELBLUE:2965692159,LIGHTYELLOW:4294959359,LIME:16711935,LIMEGREEN:852308735,LINEN:4210091775,MAGENTA:4278255615,MAROON:2147483903,MEDIUMAQUAMARINE:1724754687,MEDIUMBLUE:52735,MEDIUMORCHID:3126187007,MEDIUMPURPLE:2473647103,MEDIUMSEAGREEN:1018393087,MEDIUMSLATEBLUE:2070474495,MEDIUMSPRINGGREEN:16423679,MEDIUMTURQUOISE:1221709055,MEDIUMVIOLETRED:3340076543,MIDNIGHTBLUE:421097727,MINTCREAM:4127193855,MISTYROSE:4293190143,MOCCASIN:4293178879,NAVAJOWHITE:4292783615,NAVY:33023,OLDLACE:4260751103,OLIVE:2155872511,OLIVEDRAB:1804477439,ORANGE:4289003775,ORANGERED:4282712319,ORCHID:3664828159,PALEGOLDENROD:4008225535,PALEGREEN:2566625535,PALETURQUOISE:2951671551,PALEVIOLETRED:3681588223,PAPAYAWHIP:4293907967,PEACHPUFF:4292524543,PERU:3448061951,PINK:4290825215,PLUM:3718307327,POWDERBLUE:2967529215,PURPLE:2147516671,REBECCAPURPLE:1714657791,RED:4278190335,ROSYBROWN:3163525119,ROYALBLUE:1097458175,SADDLEBROWN:2336560127,SALMON:4202722047,SANDYBROWN:4104413439,SEAGREEN:780883967,SEASHELL:4294307583,SIENNA:2689740287,SILVER:3233857791,SKYBLUE:2278484991,SLATEBLUE:1784335871,SLATEGRAY:1887473919,SLATEGREY:1887473919,SNOW:4294638335,SPRINGGREEN:16744447,STEELBLUE:1182971135,TAN:3535047935,TEAL:8421631,THISTLE:3636451583,TOMATO:4284696575,TRANSPARENT:0,TURQUOISE:1088475391,VIOLET:4001558271,WHEAT:4125012991,WHITE:4294967295,WHITESMOKE:4126537215,YELLOW:4294902015,YELLOWGREEN:2597139199};(ge=Ce||(Ce={}))[ge.VALUE=0]="VALUE",ge[ge.LIST=1]="LIST",ge[ge.IDENT_VALUE=2]="IDENT_VALUE",ge[ge.TYPE_VALUE=3]="TYPE_VALUE",ge[ge.TOKEN_VALUE=4]="TOKEN_VALUE",(Fe=Ee||(Ee={}))[Fe.BORDER_BOX=0]="BORDER_BOX",Fe[Fe.PADDING_BOX=1]="PADDING_BOX";function de(A){var e=we(A[0]),t=A[1];return t&&qA(t)?{color:e,stop:t}:{color:e,stop:null}}function fe(A,t){var e=A[0],r=A[A.length-1];null===e.stop&&(e.stop=se),null===r.stop&&(r.stop=ie);for(var n=[],B=0,s=0;sA.optimumDistance)?{optimumCorner:e,optimumDistance:n}:A},{optimumDistance:o?1/0:-1/0,optimumCorner:null}).optimumCorner}function Ie(A){var n=Qe(180),B=[];return WA(A).forEach(function(A,e){if(0===e){var t=A[0];if(t.type===sA.IDENT_TOKEN&&-1!==["top","left","right","bottom"].indexOf(t.value))return void(n=Ae(A));if($A(t))return void(n=(ce(t)+Qe(270))%Qe(360))}var r=de(A);B.push(r)}),{angle:n,stops:B,type:xe.LINEAR_GRADIENT}}function Te(A){return 0===A[0]&&255===A[1]&&0===A[2]&&255===A[3]}var me={name:"background-clip",initialValue:"border-box",prefix:!(Fe[Fe.CONTENT_BOX=2]="CONTENT_BOX"),type:Ce.LIST,parse:function(A){return A.map(function(A){if(zA(A))switch(A.value){case"padding-box":return Ee.PADDING_BOX;case"content-box":return Ee.CONTENT_BOX}return Ee.BORDER_BOX})}},Re={name:"background-color",initialValue:"transparent",prefix:!1,type:Ce.TYPE_VALUE,format:"color"},Le=function(A,e,t,r,n){var B="http://www.w3.org/2000/svg",s=document.createElementNS(B,"svg"),o=document.createElementNS(B,"foreignObject");return s.setAttributeNS(null,"width",A.toString()),s.setAttributeNS(null,"height",e.toString()),o.setAttributeNS(null,"width","100%"),o.setAttributeNS(null,"height","100%"),o.setAttributeNS(null,"x",t.toString()),o.setAttributeNS(null,"y",r.toString()),o.setAttributeNS(null,"externalResourcesRequired","true"),s.appendChild(o),o.appendChild(n),s},ve=function(r){return new Promise(function(A,e){var t=new Image;t.onload=function(){return A(t)},t.onerror=e,t.src="data:image/svg+xml;charset=utf-8,"+encodeURIComponent((new XMLSerializer).serializeToString(r))})},Oe={get SUPPORT_RANGE_BOUNDS(){var A=function(A){if(A.createRange){var e=A.createRange();if(e.getBoundingClientRect){var t=A.createElement("boundtest");t.style.height="123px",t.style.display="block",A.body.appendChild(t),e.selectNode(t);var r=e.getBoundingClientRect(),n=Math.round(r.height);if(A.body.removeChild(t),123===n)return!0}}return!1}(document);return Object.defineProperty(Oe,"SUPPORT_RANGE_BOUNDS",{value:A}),A},get SUPPORT_SVG_DRAWING(){var A=function(A){var e=new Image,t=A.createElement("canvas"),r=t.getContext("2d");if(!r)return!1;e.src="data:image/svg+xml,";try{r.drawImage(e,0,0),t.toDataURL()}catch(A){return!1}return!0}(document);return Object.defineProperty(Oe,"SUPPORT_SVG_DRAWING",{value:A}),A},get SUPPORT_FOREIGNOBJECT_DRAWING(){var A="function"==typeof Array.from&&"function"==typeof window.fetch?function(r){var A=r.createElement("canvas"),n=100;A.width=n,A.height=n;var B=A.getContext("2d");if(!B)return Promise.reject(!1);B.fillStyle="rgb(0, 255, 0)",B.fillRect(0,0,n,n);var e=new Image,s=A.toDataURL();e.src=s;var t=Le(n,n,0,0,e);return B.fillStyle="red",B.fillRect(0,0,n,n),ve(t).then(function(A){B.drawImage(A,0,0);var e=B.getImageData(0,0,n,n).data;B.fillStyle="red",B.fillRect(0,0,n,n);var t=r.createElement("div");return t.style.backgroundImage="url("+s+")",t.style.height="100px",Te(e)?ve(Le(n,n,0,0,t)):Promise.reject(!1)}).then(function(A){return B.drawImage(A,0,0),Te(B.getImageData(0,0,n,n).data)}).catch(function(){return!1})}(document):Promise.resolve(!1);return Object.defineProperty(Oe,"SUPPORT_FOREIGNOBJECT_DRAWING",{value:A}),A},get SUPPORT_CORS_IMAGES(){var A=void 0!==(new Image).crossOrigin;return Object.defineProperty(Oe,"SUPPORT_CORS_IMAGES",{value:A}),A},get SUPPORT_RESPONSE_TYPE(){var A="string"==typeof(new XMLHttpRequest).responseType;return Object.defineProperty(Oe,"SUPPORT_RESPONSE_TYPE",{value:A}),A},get SUPPORT_CORS_XHR(){var A="withCredentials"in new XMLHttpRequest;return Object.defineProperty(Oe,"SUPPORT_CORS_XHR",{value:A}),A}},De=(be.prototype.debug=function(){for(var A=[],e=0;eA.height?new I(A.left+(A.width-A.height)/2,A.top,A.height,A.height):A.width"),WB(this.referenceElement.ownerDocument,n,B),o.replaceChild(o.adoptNode(this.documentElement),o.documentElement),o.close(),i},xB.prototype.createElementClone=function(A){return FB(A)?this.createCanvasClone(A):nB(A)?this.createStyleClone(A):A.cloneNode(!1)},xB.prototype.createStyleClone=function(A){try{var e=A.sheet;if(e&&e.cssRules){var t=[].slice.call(e.cssRules,0).reduce(function(A,e){return e&&"string"==typeof e.cssText?A+e.cssText:A},""),r=A.cloneNode(!1);return r.textContent=t,r}}catch(A){if(De.getInstance(this.options.id).error("Unable to access cssRules property",A),"SecurityError"!==A.name)throw A}return A.cloneNode(!1)},xB.prototype.createCanvasClone=function(A){if(this.options.inlineImages&&A.ownerDocument){var e=A.ownerDocument.createElement("img");try{return e.src=A.toDataURL(),e}catch(A){De.getInstance(this.options.id).info("Unable to clone canvas contents, canvas is tainted")}}var t=A.cloneNode(!1);try{t.width=A.width,t.height=A.height;var r=A.getContext("2d"),n=t.getContext("2d");return n&&(r?n.putImageData(r.getImageData(0,0,A.width,A.height),0,0):n.drawImage(A,0,0)),t}catch(A){}return t},xB.prototype.cloneNode=function(A){if(QB(A))return document.createTextNode(A.data);if(!A.ownerDocument)return A.cloneNode(!1);var e=A.ownerDocument.defaultView;if(uB(A)&&e){var t=this.createElementClone(A),r=e.getComputedStyle(A),n=e.getComputedStyle(A,":before"),B=e.getComputedStyle(A,":after");this.referenceElement===A&&(this.clonedReferenceElement=t),EB(t)&&$B(t);for(var s=this.counters.parse(new un(r)),o=this.resolvePseudoContent(A,t,n,LB.BEFORE),i=A.firstChild;i;i=i.nextSibling)wB(i)&&("SCRIPT"===i.tagName||i.hasAttribute(_B)||"function"==typeof this.options.ignoreElements&&this.options.ignoreElements(i))||this.options.copyStyles&&wB(i)&&nB(i)||t.appendChild(this.cloneNode(i));o&&t.insertBefore(o,t.firstChild);var a=this.resolvePseudoContent(A,t,B,LB.AFTER);return a&&t.appendChild(a),this.counters.pop(s),r&&this.options.copyStyles&&!HB(A)&&GB(r,t),0===A.scrollTop&&0===A.scrollLeft||this.scrolledElements.push([t,A.scrollLeft,A.scrollTop]),(dB(A)||fB(A))&&(dB(t)||fB(t))&&(t.value=A.value),t}return A.cloneNode(!1)},xB.prototype.resolvePseudoContent=function(U,A,e,t){var l=this;if(e){var r=e.content,C=A.ownerDocument;if(C&&r&&"none"!==r&&"-moz-alt-content"!==r&&"none"!==e.display){this.counters.parse(new un(e));var g=new wn(e),E=C.createElement("html2canvaspseudoelement");GB(e,E),g.content.forEach(function(A){if(A.type===sA.STRING_TOKEN)E.appendChild(C.createTextNode(A.value));else if(A.type===sA.URL_TOKEN){var e=C.createElement("img");e.src=A.value,e.style.opacity="1",E.appendChild(e)}else if(A.type===sA.FUNCTION){if("attr"===A.name){var t=A.values.filter(zA);t.length&&E.appendChild(C.createTextNode(U.getAttribute(t[0].value)||""))}else if("counter"===A.name){var r=A.values.filter(kA),n=r[0],B=r[1];if(n&&zA(n)){var s=l.counters.getCounterValue(n.value),o=B&&zA(B)?ir.parse(B.value):tr.DECIMAL;E.appendChild(C.createTextNode(yB(s,o,!1)))}}else if("counters"===A.name){var i=A.values.filter(kA),a=(n=i[0],i[1]);if(B=i[2],n&&zA(n)){var c=l.counters.getCounterValues(n.value),Q=B&&zA(B)?ir.parse(B.value):tr.DECIMAL,w=a&&a.type===sA.STRING_TOKEN?a.value:"",u=c.map(function(A){return yB(A,Q,!1)}).join(w);E.appendChild(C.createTextNode(u))}}}else if(A.type===sA.IDENT_TOKEN)switch(A.value){case"open-quote":E.appendChild(C.createTextNode(en(g.quotes,l.quoteDepth++,!0)));break;case"close-quote":E.appendChild(C.createTextNode(en(g.quotes,--l.quoteDepth,!1)));break;default:E.appendChild(C.createTextNode(A.value))}}),E.className=qB+" "+ZB;var n=t===LB.BEFORE?" "+qB:" "+ZB;return function(A){return"object"==typeof A.className}(A)?A.className.baseValue+=n:A.className+=n,E}}},xB.destroy=function(A){return!!A.parentNode&&(A.parentNode.removeChild(A),!0)},xB);function xB(A,e){if(this.options=e,this.scrolledElements=[],this.referenceElement=A,this.counters=new pB,this.quoteDepth=0,!A.ownerDocument)throw new Error("Cloned element does not have an owner document");this.documentElement=this.cloneNode(A.ownerDocument.documentElement)}(vB=LB||(LB={}))[vB.BEFORE=0]="BEFORE",vB[vB.AFTER=1]="AFTER";var VB,zB,XB=function(A,e){var t=A.createElement("iframe");return t.className="html2canvas-container",t.style.visibility="hidden",t.style.position="fixed",t.style.left="-10000px",t.style.top="0px",t.style.border="0",t.width=e.width.toString(),t.height=e.height.toString(),t.scrolling="no",t.setAttribute(_B,"true"),A.body.appendChild(t),t},JB=function(n){return new Promise(function(e,A){var t=n.contentWindow;if(!t)return A("No window assigned for iframe");var r=t.document;t.onload=n.onload=r.onreadystatechange=function(){t.onload=n.onload=r.onreadystatechange=null;var A=setInterval(function(){0"),e},WB=function(A,e,t){A&&A.defaultView&&(e!==A.defaultView.pageXOffset||t!==A.defaultView.pageYOffset)&&A.defaultView.scrollTo(e,t)},YB=function(A){var e=A[0],t=A[1],r=A[2];e.scrollLeft=t,e.scrollTop=r},qB="___html2canvas___pseudoelement_before",ZB="___html2canvas___pseudoelement_after",jB='{\n content: "" !important;\n display: none !important;\n}',$B=function(A){As(A,"."+qB+":before"+jB+"\n ."+ZB+":after"+jB)},As=function(A,e){var t=A.ownerDocument;if(t){var r=t.createElement("style");r.textContent=e,A.appendChild(r)}};(zB=VB||(VB={}))[zB.VECTOR=0]="VECTOR",zB[zB.BEZIER_CURVE=1]="BEZIER_CURVE";function es(A,t){return A.length===t.length&&A.some(function(A,e){return A===t[e]})}var ts=(rs.prototype.add=function(A,e){return new rs(this.x+A,this.y+e)},rs);function rs(A,e){this.type=VB.VECTOR,this.x=A,this.y=e}function ns(A,e,t){return new ts(A.x+(e.x-A.x)*t,A.y+(e.y-A.y)*t)}var Bs=(ss.prototype.subdivide=function(A,e){var t=ns(this.start,this.startControl,A),r=ns(this.startControl,this.endControl,A),n=ns(this.endControl,this.end,A),B=ns(t,r,A),s=ns(r,n,A),o=ns(B,s,A);return e?new ss(this.start,t,B,o):new ss(o,s,n,this.end)},ss.prototype.add=function(A,e){return new ss(this.start.add(A,e),this.startControl.add(A,e),this.endControl.add(A,e),this.end.add(A,e))},ss.prototype.reverse=function(){return new ss(this.end,this.endControl,this.startControl,this.start)},ss);function ss(A,e,t,r){this.type=VB.BEZIER_CURVE,this.start=A,this.startControl=e,this.endControl=t,this.end=r}function os(A){return A.type===VB.BEZIER_CURVE}var is,as,cs=function(A){var e=A.styles,t=A.bounds,r=jA(e.borderTopLeftRadius,t.width,t.height),n=r[0],B=r[1],s=jA(e.borderTopRightRadius,t.width,t.height),o=s[0],i=s[1],a=jA(e.borderBottomRightRadius,t.width,t.height),c=a[0],Q=a[1],w=jA(e.borderBottomLeftRadius,t.width,t.height),u=w[0],U=w[1],l=[];l.push((n+o)/t.width),l.push((u+c)/t.width),l.push((B+U)/t.height),l.push((i+Q)/t.height);var C=Math.max.apply(Math,l);1t.width+p?0:o-p,i-H,is.TOP_RIGHT):new ts(t.left+t.width-d,t.top+H),this.bottomRightPaddingBox=0t.width+p+T?0:o-p+T,i-(H+N),is.TOP_RIGHT):new ts(t.left+t.width-(d+K),t.top+H+N),this.bottomRightContentBox=0A.element.container.styles.zIndex.order?(i=e,!1):0A.element.container.styles.zIndex.order?(a=e+1,!1):0 tags supported for intl.js."); - } -})/* endRemoveIf(umd) */(function(){ - var global = typeof window !== "undefined" ? window : self; - /*jshint proto:true, eqnull:true, boss:true, laxbreak:true, newcap:false, shadow:true, funcscope:true */ - var Intl = typeof global.Intl!="undefined"?global.Intl:(function (Intl) { - /** - * @license Copyright 2013 Andy Earnshaw, MIT License - * - * Implements the ECMAScript Internationalization API in ES5-compatible environments, - * following the ECMA-402 specification as closely as possible - * - * ECMA-402: http://ecma-international.org/ecma-402/1.0/ - * - * CLDR format locale data should be provided using Intl.__addLocaleData(). - */ - - "use strict"; - var - // We use this a lot (and need it for proto-less objects) - hop = Object.prototype.hasOwnProperty, - - // Naive defineProperty for compatibility - defineProperty = (!window.isIE8 && Object.defineProperty) || function (obj, name, desc) { - if (desc.get && obj.__defineGetter__) - obj.__defineGetter__(name, desc.get); - else if (desc.value || desc.get) - obj[name] = desc.value || desc.get; - }, - - // Array.prototype.indexOf, as good as we need it to be - arrIndexOf = Array.prototype.indexOf || function (search) { - /*jshint validthis:true */ - var t = this; - if (!t.length) - return -1; - - for (var i = arguments[1] || 0, max = t.length; i < max; i++) { - if (t[i] === search) - return i; - } - }, - - // Create an object with the specified prototype (2nd arg required for Record) - objCreate = Object.create || function (proto, props) { - var obj; - - function F() {} - F.prototype = proto; - obj = new F(); - - for (var k in props) { - if (hop.call(props, k)) - defineProperty(obj, k, props[k]); - } - - return obj; - }, - - // Snapshot some (hopefully still) native built-ins - arrSlice = Array.prototype.slice, - arrConcat = Array.prototype.concat, - arrPush = Array.prototype.push, - arrJoin = Array.prototype.join, - arrShift = Array.prototype.shift, - - // Naive Function.prototype.bind for compatibility - fnBind = Function.prototype.bind || function (thisObj) { - var fn = this, - args = arrSlice.call(arguments, 1); - - return function () { - fn.apply(thisObj, arrConcat.call(args, arrSlice.call(arguments))); - }; - }, - - // Default locale is the first-added locale data for us - defaultLocale, - - // Object housing internal properties for constructors - internals = objCreate(null), - - // Keep internal properties internal - secret = Math.random(), - - // An object map of date component keys, saves using a regex later - dateWidths = objCreate(null, { "narrow":{}, "short":{}, "long":{} }), - - // Each constructor prototype should be an instance of the constructor itself, but we - // can't initialise them as such until some locale data has been added, so this is how - // we keep track - numberFormatProtoInitialised = false, - dateTimeFormatProtoInitialised = false, - - // Some regular expressions we're using - expInsertGroups = /(?=(?!^)(?:\d{3})+(?!\d))/g, - expCurrencyCode = /^[A-Z]{3}$/, - expUnicodeExSeq = /-u(?:-[0-9a-z]{2,8})+/gi, // See `extension` below - - expBCP47Syntax, - expExtSequences, - expVariantDupes, - expSingletonDupes, - - // IANA Subtag Registry redundant tag and subtag maps - redundantTags = { - tags: { - "art-lojban": "jbo", "i-ami": "ami", "i-bnn": "bnn", "i-hak": "hak", - "i-klingon": "tlh", "i-lux": "lb", "i-navajo": "nv", "i-pwn": "pwn", - "i-tao": "tao", "i-tay": "tay", "i-tsu": "tsu", "no-bok": "nb", - "no-nyn": "nn", "sgn-BE-FR": "sfb", "sgn-BE-NL": "vgt", "sgn-CH-DE": "sgg", - "zh-guoyu": "cmn", "zh-hakka": "hak", "zh-min-nan": "nan", "zh-xiang": "hsn", - "sgn-BR": "bzs", "sgn-CO": "csn", "sgn-DE": "gsg", "sgn-DK": "dsl", - "sgn-ES": "ssp", "sgn-FR": "fsl", "sgn-GB": "bfi", "sgn-GR": "gss", - "sgn-IE": "isg", "sgn-IT": "ise", "sgn-JP": "jsl", "sgn-MX": "mfs", - "sgn-NI": "ncs", "sgn-NL": "dse", "sgn-NO": "nsl", "sgn-PT": "psr", - "sgn-SE": "swl", "sgn-US": "ase", "sgn-ZA": "sfs", "zh-cmn": "cmn", - "zh-cmn-Hans": "cmn-Hans", "zh-cmn-Hant": "cmn-Hant", "zh-gan": "gan", "zh-wuu": "wuu", - "zh-yue": "yue" - }, - subtags: { - BU: "MM", DD: "DE", FX: "FR", TP: "TL", YD: "YE", ZR: "CD", heploc: "alalc97", - 'in': "id", iw: "he", ji: "yi", jw: "jv", mo: "ro", ayx: "nun", bjd: "drl", - ccq: "rki", cjr: "mom", cka: "cmr", cmk: "xch", drh: "khk", drw: "prs", gav: "dev", - hrr: "jal", ibi: "opa", kgh: "kml", lcq: "ppr", mst: "mry", myt: "mry", sca: "hle", - tie: "ras", tkk: "twm", tlw: "weo", tnf: "prs", ybd: "rki", yma: "lrr" - }, - extLang: { - aao: [ "aao", "ar" ], abh: [ "abh", "ar" ], abv: [ "abv", "ar" ], acm: [ "acm", "ar" ], - acq: [ "acq", "ar" ], acw: [ "acw", "ar" ], acx: [ "acx", "ar" ], acy: [ "acy", "ar" ], - adf: [ "adf", "ar" ], ads: [ "ads", "sgn" ], aeb: [ "aeb", "ar" ], aec: [ "aec", "ar" ], - aed: [ "aed", "sgn" ], aen: [ "aen", "sgn" ], afb: [ "afb", "ar" ], afg: [ "afg", "sgn" ], - ajp: [ "ajp", "ar" ], apc: [ "apc", "ar" ], apd: [ "apd", "ar" ], arb: [ "arb", "ar" ], - arq: [ "arq", "ar" ], ars: [ "ars", "ar" ], ary: [ "ary", "ar" ], arz: [ "arz", "ar" ], - ase: [ "ase", "sgn" ], asf: [ "asf", "sgn" ], asp: [ "asp", "sgn" ], asq: [ "asq", "sgn" ], - asw: [ "asw", "sgn" ], auz: [ "auz", "ar" ], avl: [ "avl", "ar" ], ayh: [ "ayh", "ar" ], - ayl: [ "ayl", "ar" ], ayn: [ "ayn", "ar" ], ayp: [ "ayp", "ar" ], bbz: [ "bbz", "ar" ], - bfi: [ "bfi", "sgn" ], bfk: [ "bfk", "sgn" ], bjn: [ "bjn", "ms" ], bog: [ "bog", "sgn" ], - bqn: [ "bqn", "sgn" ], bqy: [ "bqy", "sgn" ], btj: [ "btj", "ms" ], bve: [ "bve", "ms" ], - bvl: [ "bvl", "sgn" ], bvu: [ "bvu", "ms" ], bzs: [ "bzs", "sgn" ], cdo: [ "cdo", "zh" ], - cds: [ "cds", "sgn" ], cjy: [ "cjy", "zh" ], cmn: [ "cmn", "zh" ], coa: [ "coa", "ms" ], - cpx: [ "cpx", "zh" ], csc: [ "csc", "sgn" ], csd: [ "csd", "sgn" ], cse: [ "cse", "sgn" ], - csf: [ "csf", "sgn" ], csg: [ "csg", "sgn" ], csl: [ "csl", "sgn" ], csn: [ "csn", "sgn" ], - csq: [ "csq", "sgn" ], csr: [ "csr", "sgn" ], czh: [ "czh", "zh" ], czo: [ "czo", "zh" ], - doq: [ "doq", "sgn" ], dse: [ "dse", "sgn" ], dsl: [ "dsl", "sgn" ], dup: [ "dup", "ms" ], - ecs: [ "ecs", "sgn" ], esl: [ "esl", "sgn" ], esn: [ "esn", "sgn" ], eso: [ "eso", "sgn" ], - eth: [ "eth", "sgn" ], fcs: [ "fcs", "sgn" ], fse: [ "fse", "sgn" ], fsl: [ "fsl", "sgn" ], - fss: [ "fss", "sgn" ], gan: [ "gan", "zh" ], gds: [ "gds", "sgn" ], gom: [ "gom", "kok" ], - gse: [ "gse", "sgn" ], gsg: [ "gsg", "sgn" ], gsm: [ "gsm", "sgn" ], gss: [ "gss", "sgn" ], - gus: [ "gus", "sgn" ], hab: [ "hab", "sgn" ], haf: [ "haf", "sgn" ], hak: [ "hak", "zh" ], - hds: [ "hds", "sgn" ], hji: [ "hji", "ms" ], hks: [ "hks", "sgn" ], hos: [ "hos", "sgn" ], - hps: [ "hps", "sgn" ], hsh: [ "hsh", "sgn" ], hsl: [ "hsl", "sgn" ], hsn: [ "hsn", "zh" ], - icl: [ "icl", "sgn" ], ils: [ "ils", "sgn" ], inl: [ "inl", "sgn" ], ins: [ "ins", "sgn" ], - ise: [ "ise", "sgn" ], isg: [ "isg", "sgn" ], isr: [ "isr", "sgn" ], jak: [ "jak", "ms" ], - jax: [ "jax", "ms" ], jcs: [ "jcs", "sgn" ], jhs: [ "jhs", "sgn" ], jls: [ "jls", "sgn" ], - jos: [ "jos", "sgn" ], jsl: [ "jsl", "sgn" ], jus: [ "jus", "sgn" ], kgi: [ "kgi", "sgn" ], - knn: [ "knn", "kok" ], kvb: [ "kvb", "ms" ], kvk: [ "kvk", "sgn" ], kvr: [ "kvr", "ms" ], - kxd: [ "kxd", "ms" ], lbs: [ "lbs", "sgn" ], lce: [ "lce", "ms" ], lcf: [ "lcf", "ms" ], - liw: [ "liw", "ms" ], lls: [ "lls", "sgn" ], lsg: [ "lsg", "sgn" ], lsl: [ "lsl", "sgn" ], - lso: [ "lso", "sgn" ], lsp: [ "lsp", "sgn" ], lst: [ "lst", "sgn" ], lsy: [ "lsy", "sgn" ], - ltg: [ "ltg", "lv" ], lvs: [ "lvs", "lv" ], lzh: [ "lzh", "zh" ], max: [ "max", "ms" ], - mdl: [ "mdl", "sgn" ], meo: [ "meo", "ms" ], mfa: [ "mfa", "ms" ], mfb: [ "mfb", "ms" ], - mfs: [ "mfs", "sgn" ], min: [ "min", "ms" ], mnp: [ "mnp", "zh" ], mqg: [ "mqg", "ms" ], - mre: [ "mre", "sgn" ], msd: [ "msd", "sgn" ], msi: [ "msi", "ms" ], msr: [ "msr", "sgn" ], - mui: [ "mui", "ms" ], mzc: [ "mzc", "sgn" ], mzg: [ "mzg", "sgn" ], mzy: [ "mzy", "sgn" ], - nan: [ "nan", "zh" ], nbs: [ "nbs", "sgn" ], ncs: [ "ncs", "sgn" ], nsi: [ "nsi", "sgn" ], - nsl: [ "nsl", "sgn" ], nsp: [ "nsp", "sgn" ], nsr: [ "nsr", "sgn" ], nzs: [ "nzs", "sgn" ], - okl: [ "okl", "sgn" ], orn: [ "orn", "ms" ], ors: [ "ors", "ms" ], pel: [ "pel", "ms" ], - pga: [ "pga", "ar" ], pks: [ "pks", "sgn" ], prl: [ "prl", "sgn" ], prz: [ "prz", "sgn" ], - psc: [ "psc", "sgn" ], psd: [ "psd", "sgn" ], pse: [ "pse", "ms" ], psg: [ "psg", "sgn" ], - psl: [ "psl", "sgn" ], pso: [ "pso", "sgn" ], psp: [ "psp", "sgn" ], psr: [ "psr", "sgn" ], - pys: [ "pys", "sgn" ], rms: [ "rms", "sgn" ], rsi: [ "rsi", "sgn" ], rsl: [ "rsl", "sgn" ], - sdl: [ "sdl", "sgn" ], sfb: [ "sfb", "sgn" ], sfs: [ "sfs", "sgn" ], sgg: [ "sgg", "sgn" ], - sgx: [ "sgx", "sgn" ], shu: [ "shu", "ar" ], slf: [ "slf", "sgn" ], sls: [ "sls", "sgn" ], - sqk: [ "sqk", "sgn" ], sqs: [ "sqs", "sgn" ], ssh: [ "ssh", "ar" ], ssp: [ "ssp", "sgn" ], - ssr: [ "ssr", "sgn" ], svk: [ "svk", "sgn" ], swc: [ "swc", "sw" ], swh: [ "swh", "sw" ], - swl: [ "swl", "sgn" ], syy: [ "syy", "sgn" ], tmw: [ "tmw", "ms" ], tse: [ "tse", "sgn" ], - tsm: [ "tsm", "sgn" ], tsq: [ "tsq", "sgn" ], tss: [ "tss", "sgn" ], tsy: [ "tsy", "sgn" ], - tza: [ "tza", "sgn" ], ugn: [ "ugn", "sgn" ], ugy: [ "ugy", "sgn" ], ukl: [ "ukl", "sgn" ], - uks: [ "uks", "sgn" ], urk: [ "urk", "ms" ], uzn: [ "uzn", "uz" ], uzs: [ "uzs", "uz" ], - vgt: [ "vgt", "sgn" ], vkk: [ "vkk", "ms" ], vkt: [ "vkt", "ms" ], vsi: [ "vsi", "sgn" ], - vsl: [ "vsl", "sgn" ], vsv: [ "vsv", "sgn" ], wuu: [ "wuu", "zh" ], xki: [ "xki", "sgn" ], - xml: [ "xml", "sgn" ], xmm: [ "xmm", "ms" ], xms: [ "xms", "sgn" ], yds: [ "yds", "sgn" ], - ysl: [ "ysl", "sgn" ], yue: [ "yue", "zh" ], zib: [ "zib", "sgn" ], zlm: [ "zlm", "ms" ], - zmi: [ "zmi", "ms" ], zsl: [ "zsl", "sgn" ], zsm: [ "zsm", "ms" ] - } - }, - - // Currency minor units output from tools/getISO4217data.js, formatted - currencyMinorUnits = { - BHD: 3, BYR: 0, XOF: 0, BIF: 0, XAF: 0, CLF: 0, CLP: 0, KMF: 0, DJF: 0, - XPF: 0, GNF: 0, ISK: 0, IQD: 3, JPY: 0, JOD: 3, KRW: 0, KWD: 3, LYD: 3, - OMR: 3, PYG: 0, RWF: 0, TND: 3, UGX: 0, UYI: 0, VUV: 0, VND: 0 - }; - - /** - * Defines regular expressions for various operations related to the BCP 47 syntax, - * as defined at http://tools.ietf.org/html/bcp47#section-2.1 - */ - (function () { - var - // extlang = 3ALPHA ; selected ISO 639 codes - // *2("-" 3ALPHA) ; permanently reserved - extlang = '[a-z]{3}(?:-[a-z]{3}){0,2}', - - // language = 2*3ALPHA ; shortest ISO 639 code - // ["-" extlang] ; sometimes followed by - // ; extended language subtags - // / 4ALPHA ; or reserved for future use - // / 5*8ALPHA ; or registered language subtag - language = '(?:[a-z]{2,3}(?:-' + extlang + ')?|[a-z]{4}|[a-z]{5,8})', - - // script = 4ALPHA ; ISO 15924 code - script = '[a-z]{4}', - - // region = 2ALPHA ; ISO 3166-1 code - // / 3DIGIT ; UN M.49 code - region = '(?:[a-z]{2}|\\d{3})', - - // variant = 5*8alphanum ; registered variants - // / (DIGIT 3alphanum) - variant = '(?:[a-z0-9]{5,8}|\\d[a-z0-9]{3})', - - // ; Single alphanumerics - // ; "x" reserved for private use - // singleton = DIGIT ; 0 - 9 - // / %x41-57 ; A - W - // / %x59-5A ; Y - Z - // / %x61-77 ; a - w - // / %x79-7A ; y - z - singleton = '[0-9a-wy-z]', - - // extension = singleton 1*("-" (2*8alphanum)) - extension = singleton + '(?:-[a-z0-9]{2,8})+', - - // privateuse = "x" 1*("-" (1*8alphanum)) - privateuse = 'x(?:-[a-z0-9]{1,8})+', - - // irregular = "en-GB-oed" ; irregular tags do not match - // / "i-ami" ; the 'langtag' production and - // / "i-bnn" ; would not otherwise be - // / "i-default" ; considered 'well-formed' - // / "i-enochian" ; These tags are all valid, - // / "i-hak" ; but most are deprecated - // / "i-klingon" ; in favor of more modern - // / "i-lux" ; subtags or subtag - // / "i-mingo" ; combination - // / "i-navajo" - // / "i-pwn" - // / "i-tao" - // / "i-tay" - // / "i-tsu" - // / "sgn-BE-FR" - // / "sgn-BE-NL" - // / "sgn-CH-DE" - irregular = '(?:en-GB-oed' - + '|i-(?:ami|bnn|default|enochian|hak|klingon|lux|mingo|navajo|pwn|tao|tay|tsu)' - + '|sgn-(?:BE-FR|BE-NL|CH-DE))', - - // regular = "art-lojban" ; these tags match the 'langtag' - // / "cel-gaulish" ; production, but their subtags - // / "no-bok" ; are not extended language - // / "no-nyn" ; or variant subtags: their meaning - // / "zh-guoyu" ; is defined by their registration - // / "zh-hakka" ; and all of these are deprecated - // / "zh-min" ; in favor of a more modern - // / "zh-min-nan" ; subtag or sequence of subtags - // / "zh-xiang" - regular = '(?:art-lojban|cel-gaulish|no-bok|no-nyn' - + '|zh-(?:guoyu|hakka|min|min-nan|xiang))', - - // grandfathered = irregular ; non-redundant tags registered - // / regular ; during the RFC 3066 era - grandfathered = '(?:' + irregular + '|' + regular + ')', - - // langtag = language - // ["-" script] - // ["-" region] - // *("-" variant) - // *("-" extension) - // ["-" privateuse] - langtag = language + '(?:-' + script + ')?(?:-' + region + ')?(?:-' - + variant + ')*(?:-' + extension + ')*(?:-' + privateuse + ')?'; - - // Language-Tag = langtag ; normal language tags - // / privateuse ; private use tag - // / grandfathered ; grandfathered tags - expBCP47Syntax = RegExp('^(?:'+langtag+'|'+privateuse+'|'+grandfathered+')$', 'i'); - - // Match duplicate variants in a language tag - expVariantDupes = RegExp('^(?!x).*?-('+variant+')-(?:\\w{4,8}-(?!x-))*\\1\\b', 'i'); - - // Match duplicate singletons in a language tag (except in private use) - expSingletonDupes = RegExp('^(?!x).*?-('+singleton+')-(?:\\w+-(?!x-))*\\1\\b', 'i'); - - // Match all extension sequences - expExtSequences = RegExp('-'+extension, 'ig'); - })(); - - // Sect 6.2 Language Tags - // ====================== - - /** - * The IsStructurallyValidLanguageTag abstract operation verifies that the locale - * argument (which must be a String value) - * - * - represents a well-formed BCP 47 language tag as specified in RFC 5646 section - * 2.1, or successor, - * - does not include duplicate variant subtags, and - * - does not include duplicate singleton subtags. - * - * The abstract operation returns true if locale can be generated from the ABNF - * grammar in section 2.1 of the RFC, starting with Language-Tag, and does not - * contain duplicate variant or singleton subtags (other than as a private use - * subtag). It returns false otherwise. Terminal value characters in the grammar are - * interpreted as the Unicode equivalents of the ASCII octet values given. - */ - function /* 6.2.2 */IsStructurallyValidLanguageTag(locale) { - // represents a well-formed BCP 47 language tag as specified in RFC 5646 - if (!expBCP47Syntax.test(locale)) - return false; - - // does not include duplicate variant subtags, and - if (expVariantDupes.test(locale)) - return false; - - // does not include duplicate singleton subtags. - if (expSingletonDupes.test(locale)) - return false; - - return true; - } - - /** - * The CanonicalizeLanguageTag abstract operation returns the canonical and case- - * regularized form of the locale argument (which must be a String value that is - * a structurally valid BCP 47 language tag as verified by the - * IsStructurallyValidLanguageTag abstract operation). It takes the steps - * specified in RFC 5646 section 4.5, or successor, to bring the language tag - * into canonical form, and to regularize the case of the subtags, but does not - * take the steps to bring a language tag into “extlang form” and to reorder - * variant subtags. - - * The specifications for extensions to BCP 47 language tags, such as RFC 6067, - * may include canonicalization rules for the extension subtag sequences they - * define that go beyond the canonicalization rules of RFC 5646 section 4.5. - * Implementations are allowed, but not required, to apply these additional rules. - */ - function /* 6.2.3 */CanonicalizeLanguageTag (locale) { - var match, parts; - - // A language tag is in 'canonical form' when the tag is well-formed - // according to the rules in Sections 2.1 and 2.2 - - // Section 2.1 says all subtags use lowercase... - locale = locale.toLowerCase(); - - // ...with 2 exceptions: 'two-letter and four-letter subtags that neither - // appear at the start of the tag nor occur after singletons. Such two-letter - // subtags are all uppercase (as in the tags "en-CA-x-ca" or "sgn-BE-FR") and - // four-letter subtags are titlecase (as in the tag "az-Latn-x-latn"). - parts = locale.split('-'); - for (var i = 1, max = parts.length; i < max; i++) { - // Two-letter subtags are all uppercase - if (parts[i].length === 2) - parts[i] = parts[i].toUpperCase(); - - // Four-letter subtags are titlecase - else if (parts[i].length === 4) - parts[i] = parts[i].charAt(0).toUpperCase() + parts[i].slice(1); - - // Is it a singleton? - else if (parts[i].length === 1 && parts[i] != 'x') - break; - } - locale = arrJoin.call(parts, '-'); - - // The steps laid out in RFC 5646 section 4.5 are as follows: - - // 1. Extension sequences are ordered into case-insensitive ASCII order - // by singleton subtag. - if ((match = locale.match(expExtSequences)) && match.length > 1) { - // The built-in sort() sorts by ASCII order, so use that - match.sort(); - - // Replace all extensions with the joined, sorted array - locale = locale.replace( - RegExp('(?:' + expExtSequences.source + ')+', 'i'), - arrJoin.call(match, '') - ); - } - - // 2. Redundant or grandfathered tags are replaced by their 'Preferred- - // Value', if there is one. - if (hop.call(redundantTags.tags, locale)) - locale = redundantTags.tags[locale]; - - // 3. Subtags are replaced by their 'Preferred-Value', if there is one. - // For extlangs, the original primary language subtag is also - // replaced if there is a primary language subtag in the 'Preferred- - // Value'. - parts = locale.split('-'); - - for (var i = 1, max = parts.length; i < max; i++) { - if (hop.call(redundantTags.subtags, parts[i])) - parts[i] = redundantTags.subtags[parts[i]]; - - else if (hop.call(redundantTags.extLang, parts[i])) { - parts[i] = redundantTags.extLang[parts[i]][0]; - - // For extlang tags, the prefix needs to be removed if it is redundant - if (i === 1 && redundantTags.extLang[parts[1]][1] === parts[0]) { - parts = arrSlice.call(parts, i++); - max -= 1; - } - } - } - - return arrJoin.call(parts, '-'); - } - - /** - * The DefaultLocale abstract operation returns a String value representing the - * structurally valid (6.2.2) and canonicalized (6.2.3) BCP 47 language tag for the - * host environment’s current locale. - */ - function /* 6.2.4 */DefaultLocale () { - return defaultLocale; - } - - // Sect 6.3 Currency Codes - // ======================= - - /** - * The IsWellFormedCurrencyCode abstract operation verifies that the currency argument - * (after conversion to a String value) represents a well-formed 3-letter ISO currency - * code. The following steps are taken: - */ - function /* 6.3.1 */IsWellFormedCurrencyCode(currency) { - var - // 1. Let `c` be ToString(currency) - c = String(currency), - - // 2. Let `normalized` be the result of mapping c to upper case as described - // in 6.1. - normalized = toLatinUpperCase(c); - - // 3. If the string length of normalized is not 3, return false. - // 4. If normalized contains any character that is not in the range "A" to "Z" - // (U+0041 to U+005A), return false. - if (expCurrencyCode.test(normalized) === false) - return false; - - // 5. Return true - return true; - } - - // Sect 9.2 Abstract Operations - // ============================ - function /* 9.2.1 */CanonicalizeLocaleList (locales) { - // The abstract operation CanonicalizeLocaleList takes the following steps: - - // 1. If locales is undefined, then a. Return a new empty List - if (locales === undefined) - return new List(); - - var - // 2. Let seen be a new empty List. - seen = new List(), - - // 3. If locales is a String value, then - // a. Let locales be a new array created as if by the expression new - // Array(locales) where Array is the standard built-in constructor with - // that name and locales is the value of locales. - locales = typeof locales === 'string' ? [ locales ] : locales, - - // 4. Let O be ToObject(locales). - O = toObject(locales), - - // 5. Let lenValue be the result of calling the [[Get]] internal method of - // O with the argument "length". - // 6. Let len be ToUint32(lenValue). - len = O.length, - - // 7. Let k be 0. - k = 0; - - // 8. Repeat, while k < len - while (k < len) { - var - // a. Let Pk be ToString(k). - Pk = String(k), - - // b. Let kPresent be the result of calling the [[HasProperty]] internal - // method of O with argument Pk. - kPresent = Pk in O; - - // c. If kPresent is true, then - if (kPresent) { - var - // i. Let kValue be the result of calling the [[Get]] internal - // method of O with argument Pk. - kValue = O[Pk]; - - // ii. If the type of kValue is not String or Object, then throw a - // TypeError exception. - if (kValue == null || (typeof kValue !== 'string' && typeof kValue !== 'object')) - throw new TypeError('String or Object type expected'); - - var - // iii. Let tag be ToString(kValue). - tag = String(kValue); - - // iv. If the result of calling the abstract operation - // IsStructurallyValidLanguageTag (defined in 6.2.2), passing tag as - // the argument, is false, then throw a RangeError exception. - if (!IsStructurallyValidLanguageTag(tag)) - throw new RangeError("'" + tag + "' is not a structurally valid language tag"); - - // v. Let tag be the result of calling the abstract operation - // CanonicalizeLanguageTag (defined in 6.2.3), passing tag as the - // argument. - tag = CanonicalizeLanguageTag(tag); - - // vi. If tag is not an element of seen, then append tag as the last - // element of seen. - if (arrIndexOf.call(seen, tag) === -1) - arrPush.call(seen, tag); - } - - // d. Increase k by 1. - k++; - } - - // 9. Return seen. - return seen; - } - - /** - * The BestAvailableLocale abstract operation compares the provided argument - * locale, which must be a String value with a structurally valid and - * canonicalized BCP 47 language tag, against the locales in availableLocales and - * returns either the longest non-empty prefix of locale that is an element of - * availableLocales, or undefined if there is no such element. It uses the - * fallback mechanism of RFC 4647, section 3.4. The following steps are taken: - */ - function /* 9.2.2 */BestAvailableLocale (availableLocales, locale) { - var - // 1. Let candidate be locale - candidate = locale; - - // 2. Repeat - while (true) { - // a. If availableLocales contains an element equal to candidate, then return - // candidate. - if (arrIndexOf.call(availableLocales, candidate) > -1) - return candidate; - - var - // b. Let pos be the character index of the last occurrence of "-" - // (U+002D) within candidate. If that character does not occur, return - // undefined. - pos = candidate.lastIndexOf('-'); - - if (pos < 0) - return; - - // c. If pos ≥ 2 and the character "-" occurs at index pos-2 of candidate, - // then decrease pos by 2. - if (pos >= 2 && candidate.charAt(pos - 2) == '-') - pos -= 2; - - // d. Let candidate be the substring of candidate from position 0, inclusive, - // to position pos, exclusive. - candidate = candidate.substring(0, pos); - } - } - - /** - * The LookupMatcher abstract operation compares requestedLocales, which must be - * a List as returned by CanonicalizeLocaleList, against the locales in - * availableLocales and determines the best available language to meet the - * request. The following steps are taken: - */ - function /* 9.2.3 */LookupMatcher (availableLocales, requestedLocales) { - var - // 1. Let i be 0. - i = 0, - - // 2. Let len be the number of elements in requestedLocales. - len = requestedLocales.length, - - // 3. Let availableLocale be undefined. - availableLocale; - - // 4. Repeat while i < len and availableLocale is undefined: - while (i < len && !availableLocale) { - var - // a. Let locale be the element of requestedLocales at 0-origined list - // position i. - locale = requestedLocales[i], - - // b. Let noExtensionsLocale be the String value that is locale with all - // Unicode locale extension sequences removed. - noExtensionsLocale = String(locale).replace(expUnicodeExSeq, ''), - - // c. Let availableLocale be the result of calling the - // BestAvailableLocale abstract operation (defined in 9.2.2) with - // arguments availableLocales and noExtensionsLocale. - availableLocale = BestAvailableLocale(availableLocales, noExtensionsLocale); - - // d. Increase i by 1. - i++; - } - - var - // 5. Let result be a new Record. - result = new Record(); - - // 6. If availableLocale is not undefined, then - if (availableLocale !== undefined) { - // a. Set result.[[locale]] to availableLocale. - result['[[locale]]'] = availableLocale; - - // b. If locale and noExtensionsLocale are not the same String value, then - if (String(locale) !== String(noExtensionsLocale)) { - var - // i. Let extension be the String value consisting of the first - // substring of locale that is a Unicode locale extension sequence. - extension = locale.match(expUnicodeExSeq)[0], - - // ii. Let extensionIndex be the character position of the initial - // "-" of the first Unicode locale extension sequence within locale. - extensionIndex = locale.indexOf('-u-'); - - // iii. Set result.[[extension]] to extension. - result['[[extension]]'] = extension; - - // iv. Set result.[[extensionIndex]] to extensionIndex. - result['[[extensionIndex]]'] = extensionIndex; - } - } - // 7. Else - else - // a. Set result.[[locale]] to the value returned by the DefaultLocale abstract - // operation (defined in 6.2.4). - result['[[locale]]'] = DefaultLocale(); - - // 8. Return result - return result; - } - - /** - * The BestFitMatcher abstract operation compares requestedLocales, which must be - * a List as returned by CanonicalizeLocaleList, against the locales in - * availableLocales and determines the best available language to meet the - * request. The algorithm is implementation dependent, but should produce results - * that a typical user of the requested locales would perceive as at least as - * good as those produced by the LookupMatcher abstract operation. Options - * specified through Unicode locale extension sequences must be ignored by the - * algorithm. Information about such subsequences is returned separately. - * The abstract operation returns a record with a [[locale]] field, whose value - * is the language tag of the selected locale, which must be an element of - * availableLocales. If the language tag of the request locale that led to the - * selected locale contained a Unicode locale extension sequence, then the - * returned record also contains an [[extension]] field whose value is the first - * Unicode locale extension sequence, and an [[extensionIndex]] field whose value - * is the index of the first Unicode locale extension sequence within the request - * locale language tag. - */ - function /* 9.2.4 */BestFitMatcher (availableLocales, requestedLocales) { - return LookupMatcher(availableLocales, requestedLocales); - } - - /** - * The ResolveLocale abstract operation compares a BCP 47 language priority list - * requestedLocales against the locales in availableLocales and determines the - * best available language to meet the request. availableLocales and - * requestedLocales must be provided as List values, options as a Record. - */ - function /* 9.2.5 */ResolveLocale (availableLocales, requestedLocales, options, relevantExtensionKeys, localeData) { - if (availableLocales.length === 0) { - throw new ReferenceError('No locale data has been provided for this object yet.'); - } - - // The following steps are taken: - var - // 1. Let matcher be the value of options.[[localeMatcher]]. - matcher = options['[[localeMatcher]]']; - - // 2. If matcher is "lookup", then - if (matcher === 'lookup') - var - // a. Let r be the result of calling the LookupMatcher abstract operation - // (defined in 9.2.3) with arguments availableLocales and - // requestedLocales. - r = LookupMatcher(availableLocales, requestedLocales); - - // 3. Else - else - var - // a. Let r be the result of calling the BestFitMatcher abstract - // operation (defined in 9.2.4) with arguments availableLocales and - // requestedLocales. - r = BestFitMatcher(availableLocales, requestedLocales); - - var - // 4. Let foundLocale be the value of r.[[locale]]. - foundLocale = r['[[locale]]']; - - // 5. If r has an [[extension]] field, then - if (hop.call(r, '[[extension]]')) - var - // a. Let extension be the value of r.[[extension]]. - extension = r['[[extension]]'], - // b. Let extensionIndex be the value of r.[[extensionIndex]]. - extensionIndex = r['[[extensionIndex]]'], - // c. Let split be the standard built-in function object defined in ES5, - // 15.5.4.14. - split = String.prototype.split, - // d. Let extensionSubtags be the result of calling the [[Call]] internal - // method of split with extension as the this value and an argument - // list containing the single item "-". - extensionSubtags = split.call(extension, '-'), - // e. Let extensionSubtagsLength be the result of calling the [[Get]] - // internal method of extensionSubtags with argument "length". - extensionSubtagsLength = extensionSubtags.length; - - var - // 6. Let result be a new Record. - result = new Record(); - - // 7. Set result.[[dataLocale]] to foundLocale. - result['[[dataLocale]]'] = foundLocale; - - var - // 8. Let supportedExtension be "-u". - supportedExtension = '-u', - // 9. Let i be 0. - i = 0, - // 10. Let len be the result of calling the [[Get]] internal method of - // relevantExtensionKeys with argument "length". - len = relevantExtensionKeys.length; - - // 11 Repeat while i < len: - while (i < len) { - var - // a. Let key be the result of calling the [[Get]] internal method of - // relevantExtensionKeys with argument ToString(i). - key = relevantExtensionKeys[i], - // b. Let foundLocaleData be the result of calling the [[Get]] internal - // method of localeData with the argument foundLocale. - foundLocaleData = localeData[foundLocale], - // c. Let keyLocaleData be the result of calling the [[Get]] internal - // method of foundLocaleData with the argument key. - keyLocaleData = foundLocaleData[key], - // d. Let value be the result of calling the [[Get]] internal method of - // keyLocaleData with argument "0". - value = keyLocaleData['0'], - // e. Let supportedExtensionAddition be "". - supportedExtensionAddition = '', - // f. Let indexOf be the standard built-in function object defined in - // ES5, 15.4.4.14. - indexOf = arrIndexOf; - - // g. If extensionSubtags is not undefined, then - if (extensionSubtags !== undefined) { - var - // i. Let keyPos be the result of calling the [[Call]] internal - // method of indexOf with extensionSubtags as the this value and - // an argument list containing the single item key. - keyPos = indexOf.call(extensionSubtags, key); - - // ii. If keyPos ≠ -1, then - if (keyPos !== -1) { - // 1. If keyPos + 1 < extensionSubtagsLength and the length of the - // result of calling the [[Get]] internal method of - // extensionSubtags with argument ToString(keyPos +1) is greater - // than 2, then - if (keyPos + 1 < extensionSubtagsLength - && extensionSubtags[keyPos + 1].length > 2) { - var - // a. Let requestedValue be the result of calling the [[Get]] - // internal method of extensionSubtags with argument - // ToString(keyPos + 1). - requestedValue = extensionSubtags[keyPos + 1], - // b. Let valuePos be the result of calling the [[Call]] - // internal method of indexOf with keyLocaleData as the - // this value and an argument list containing the single - // item requestedValue. - valuePos = indexOf.call(keyLocaleData, requestedValue); - - // c. If valuePos ≠ -1, then - if (valuePos !== -1) - var - // i. Let value be requestedValue. - value = requestedValue, - // ii. Let supportedExtensionAddition be the - // concatenation of "-", key, "-", and value. - supportedExtensionAddition = '-' + key + '-' + value; - } - // 2. Else - else { - var - // a. Let valuePos be the result of calling the [[Call]] - // internal method of indexOf with keyLocaleData as the this - // value and an argument list containing the single item - // "true". - valuePos = indexOf(keyLocaleData, 'true'); - - // b. If valuePos ≠ -1, then - if (valuePos !== -1) - var - // i. Let value be "true". - value = 'true'; - } - } - } - // h. If options has a field [[]], then - if (hop.call(options, '[[' + key + ']]')) { - var - // i. Let optionsValue be the value of options.[[]]. - optionsValue = options['[[' + key + ']]']; - - // ii. If the result of calling the [[Call]] internal method of indexOf - // with keyLocaleData as the this value and an argument list - // containing the single item optionsValue is not -1, then - if (indexOf.call(keyLocaleData, optionsValue) !== -1) { - // 1. If optionsValue is not equal to value, then - if (optionsValue !== value) { - // a. Let value be optionsValue. - value = optionsValue; - // b. Let supportedExtensionAddition be "". - supportedExtensionAddition = ''; - } - } - } - // i. Set result.[[]] to value. - result['[[' + key + ']]'] = value; - - // j. Append supportedExtensionAddition to supportedExtension. - supportedExtension += supportedExtensionAddition; - - // k. Increase i by 1. - i++; - } - // 12. If the length of supportedExtension is greater than 2, then - if (supportedExtension.length > 2) { - var - // a. Let preExtension be the substring of foundLocale from position 0, - // inclusive, to position extensionIndex, exclusive. - preExtension = foundLocale.substring(0, extensionIndex), - // b. Let postExtension be the substring of foundLocale from position - // extensionIndex to the end of the string. - postExtension = foundLocale.substring(extensionIndex), - // c. Let foundLocale be the concatenation of preExtension, - // supportedExtension, and postExtension. - foundLocale = preExtension + supportedExtension + postExtension; - } - // 13. Set result.[[locale]] to foundLocale. - result['[[locale]]'] = foundLocale; - - // 14. Return result. - return result; - } - - /** - * The LookupSupportedLocales abstract operation returns the subset of the - * provided BCP 47 language priority list requestedLocales for which - * availableLocales has a matching locale when using the BCP 47 Lookup algorithm. - * Locales appear in the same order in the returned list as in requestedLocales. - * The following steps are taken: - */ - function /* 9.2.6 */LookupSupportedLocales (availableLocales, requestedLocales) { - var - // 1. Let len be the number of elements in requestedLocales. - len = requestedLocales.length, - // 2. Let subset be a new empty List. - subset = new List(), - // 3. Let k be 0. - k = 0; - - // 4. Repeat while k < len - while (k < len) { - var - // a. Let locale be the element of requestedLocales at 0-origined list - // position k. - locale = requestedLocales[k], - // b. Let noExtensionsLocale be the String value that is locale with all - // Unicode locale extension sequences removed. - noExtensionsLocale = String(locale).replace(expUnicodeExSeq, ''), - // c. Let availableLocale be the result of calling the - // BestAvailableLocale abstract operation (defined in 9.2.2) with - // arguments availableLocales and noExtensionsLocale. - availableLocale = BestAvailableLocale(availableLocales, noExtensionsLocale); - - // d. If availableLocale is not undefined, then append locale to the end of - // subset. - if (availableLocale !== undefined) - arrPush.call(subset, locale); - - // e. Increment k by 1. - k++; - } - - var - // 5. Let subsetArray be a new Array object whose elements are the same - // values in the same order as the elements of subset. - subsetArray = arrSlice.call(subset); - - // 6. Return subsetArray. - return subsetArray; - } - - /** - * The BestFitSupportedLocales abstract operation returns the subset of the - * provided BCP 47 language priority list requestedLocales for which - * availableLocales has a matching locale when using the Best Fit Matcher - * algorithm. Locales appear in the same order in the returned list as in - * requestedLocales. The steps taken are implementation dependent. - */ - function /*9.2.7 */BestFitSupportedLocales (availableLocales, requestedLocales) { - // ###TODO: implement this function as described by the specification### - return LookupSupportedLocales(availableLocales, requestedLocales); - } - - /** - * The SupportedLocales abstract operation returns the subset of the provided BCP - * 47 language priority list requestedLocales for which availableLocales has a - * matching locale. Two algorithms are available to match the locales: the Lookup - * algorithm described in RFC 4647 section 3.4, and an implementation dependent - * best-fit algorithm. Locales appear in the same order in the returned list as - * in requestedLocales. The following steps are taken: - */ - function /*9.2.8 */SupportedLocales (availableLocales, requestedLocales, options) { - // 1. If options is not undefined, then - if (options !== undefined) { - var - // a. Let options be ToObject(options). - options = new Record(toObject(options)), - // b. Let matcher be the result of calling the [[Get]] internal method of - // options with argument "localeMatcher". - matcher = options.localeMatcher; - - // c. If matcher is not undefined, then - if (matcher !== undefined) { - // i. Let matcher be ToString(matcher). - matcher = String(matcher); - - // ii. If matcher is not "lookup" or "best fit", then throw a RangeError - // exception. - if (matcher !== 'lookup' && matcher !== 'best fit') - throw new RangeError('matcher should be "lookup" or "best fit"'); - } - } - // 2. If matcher is undefined or "best fit", then - if (matcher === undefined || matcher === 'best fit') - var - // a. Let subset be the result of calling the BestFitSupportedLocales - // abstract operation (defined in 9.2.7) with arguments - // availableLocales and requestedLocales. - subset = BestFitSupportedLocales(availableLocales, requestedLocales); - // 3. Else - else - var - // a. Let subset be the result of calling the LookupSupportedLocales - // abstract operation (defined in 9.2.6) with arguments - // availableLocales and requestedLocales. - subset = LookupSupportedLocales(availableLocales, requestedLocales); - - // 4. For each named own property name P of subset, - for (var P in subset) { - if (!hop.call(subset, P)) - continue; - - // a. Let desc be the result of calling the [[GetOwnProperty]] internal - // method of subset with P. - // b. Set desc.[[Writable]] to false. - // c. Set desc.[[Configurable]] to false. - // d. Call the [[DefineOwnProperty]] internal method of subset with P, desc, - // and true as arguments. - defineProperty(subset, P, { - writable: false, configurable: false, value: subset[P] - }); - } - // "Freeze" the array so no new elements can be added - defineProperty(subset, 'length', { writable: false }); - - // 5. Return subset - return subset; - } - - /** - * The GetOption abstract operation extracts the value of the property named - * property from the provided options object, converts it to the required type, - * checks whether it is one of a List of allowed values, and fills in a fallback - * value if necessary. - */ - function /*9.2.9 */GetOption (options, property, type, values, fallback) { - var - // 1. Let value be the result of calling the [[Get]] internal method of - // options with argument property. - value = options[property]; - - // 2. If value is not undefined, then - if (value !== undefined) { - // a. Assert: type is "boolean" or "string". - // b. If type is "boolean", then let value be ToBoolean(value). - // c. If type is "string", then let value be ToString(value). - value = type === 'boolean' ? Boolean(value) - : (type === 'string' ? String(value) : value); - - // d. If values is not undefined, then - if (values !== undefined) { - // i. If values does not contain an element equal to value, then throw a - // RangeError exception. - if (arrIndexOf.call(values, value) === -1) - throw new RangeError("'" + value + "' is not an allowed value for `" + property +'`'); - } - - // e. Return value. - return value; - } - // Else return fallback. - return fallback; - } - - /** - * The GetNumberOption abstract operation extracts a property value from the - * provided options object, converts it to a Number value, checks whether it is - * in the allowed range, and fills in a fallback value if necessary. - */ - function /* 9.2.10 */GetNumberOption (options, property, minimum, maximum, fallback) { - var - // 1. Let value be the result of calling the [[Get]] internal method of - // options with argument property. - value = options[property]; - - // 2. If value is not undefined, then - if (value !== undefined) { - // a. Let value be ToNumber(value). - value = Number(value); - - // b. If value is NaN or less than minimum or greater than maximum, throw a - // RangeError exception. - if (isNaN(value) || value < minimum || value > maximum) - throw new RangeError('Value is not a number or outside accepted range'); - - // c. Return floor(value). - return Math.floor(value); - } - // 3. Else return fallback. - return fallback; - } - - // 11.1 The Intl.NumberFormat constructor - // ====================================== - - // Define the NumberFormat constructor internally so it cannot be tainted - function NumberFormatConstructor () { - var locales = arguments[0]; - var options = arguments[1]; - - if (!this || this === Intl) { - return new Intl.NumberFormat(locales, options); - } - - return InitializeNumberFormat(toObject(this), locales, options); - } - - defineProperty(Intl, 'NumberFormat', { - configurable: true, - writable: true, - value: NumberFormatConstructor - }); - - // Must explicitly set prototypes as unwritable - defineProperty(Intl.NumberFormat, 'prototype', { - writable: false - }); - - /** - * The abstract operation InitializeNumberFormat accepts the arguments - * numberFormat (which must be an object), locales, and options. It initializes - * numberFormat as a NumberFormat object. - */ - function /*11.1.1.1 */InitializeNumberFormat (numberFormat, locales, options) { - var - // This will be a internal properties object if we're not already initialized - internal = getInternalProperties(numberFormat), - - // Create an object whose props can be used to restore the values of RegExp props - regexpState = createRegExpRestore(); - - // 1. If numberFormat has an [[initializedIntlObject]] internal property with - // value true, throw a TypeError exception. - if (internal['[[initializedIntlObject]]'] === true) - throw new TypeError('`this` object has already been initialized as an Intl object'); - - // Need this to access the `internal` object - defineProperty(numberFormat, '__getInternalProperties', { - value: function () { - // NOTE: Non-standard, for internal use only - if (arguments[0] === secret) - return internal; - } - }); - - // 2. Set the [[initializedIntlObject]] internal property of numberFormat to true. - internal['[[initializedIntlObject]]'] = true; - - var - // 3. Let requestedLocales be the result of calling the CanonicalizeLocaleList - // abstract operation (defined in 9.2.1) with argument locales. - requestedLocales = CanonicalizeLocaleList(locales); - - // 4. If options is undefined, then - if (options === undefined) - // a. Let options be the result of creating a new object as if by the - // expression new Object() where Object is the standard built-in constructor - // with that name. - options = {}; - - // 5. Else - else - // a. Let options be ToObject(options). - options = toObject(options); - - var - // 6. Let opt be a new Record. - opt = new Record(), - - // 7. Let matcher be the result of calling the GetOption abstract operation - // (defined in 9.2.9) with the arguments options, "localeMatcher", "string", - // a List containing the two String values "lookup" and "best fit", and - // "best fit". - matcher = GetOption(options, 'localeMatcher', 'string', new List('lookup', 'best fit'), 'best fit'); - - // 8. Set opt.[[localeMatcher]] to matcher. - opt['[[localeMatcher]]'] = matcher; - - var - // 9. Let NumberFormat be the standard built-in object that is the initial value - // of Intl.NumberFormat. - // 10. Let localeData be the value of the [[localeData]] internal property of - // NumberFormat. - localeData = internals.NumberFormat['[[localeData]]'], - - // 11. Let r be the result of calling the ResolveLocale abstract operation - // (defined in 9.2.5) with the [[availableLocales]] internal property of - // NumberFormat, requestedLocales, opt, the [[relevantExtensionKeys]] - // internal property of NumberFormat, and localeData. - r = ResolveLocale( - internals.NumberFormat['[[availableLocales]]'], requestedLocales, - opt, internals.NumberFormat['[[relevantExtensionKeys]]'], localeData - ); - - // 12. Set the [[locale]] internal property of numberFormat to the value of - // r.[[locale]]. - internal['[[locale]]'] = r['[[locale]]']; - - // 13. Set the [[numberingSystem]] internal property of numberFormat to the value - // of r.[[nu]]. - internal['[[numberingSystem]]'] = r['[[nu]]']; - - // The specification doesn't tell us to do this, but it's helpful later on - internal['[[dataLocale]]'] = r['[[dataLocale]]']; - - var - // 14. Let dataLocale be the value of r.[[dataLocale]]. - dataLocale = r['[[dataLocale]]'], - - // 15. Let s be the result of calling the GetOption abstract operation with the - // arguments options, "style", "string", a List containing the three String - // values "decimal", "percent", and "currency", and "decimal". - s = GetOption(options, 'style', 'string', new List('decimal', 'percent', 'currency'), 'decimal'); - - // 16. Set the [[style]] internal property of numberFormat to s. - internal['[[style]]'] = s; - - var - // 17. Let c be the result of calling the GetOption abstract operation with the - // arguments options, "currency", "string", undefined, and undefined. - c = GetOption(options, 'currency', 'string'); - - // 18. If c is not undefined and the result of calling the - // IsWellFormedCurrencyCode abstract operation (defined in 6.3.1) with - // argument c is false, then throw a RangeError exception. - if (c !== undefined && !IsWellFormedCurrencyCode(c)) - throw new RangeError("'" + c + "' is not a valid currency code"); - - // 19. If s is "currency" and c is undefined, throw a TypeError exception. - if (s === 'currency' && c === undefined) - throw new TypeError('Currency code is required when style is currency'); - - // 20. If s is "currency", then - if (s === 'currency') { - // a. Let c be the result of converting c to upper case as specified in 6.1. - c = c.toUpperCase(); - - // b. Set the [[currency]] internal property of numberFormat to c. - internal['[[currency]]'] = c; - - var - // c. Let cDigits be the result of calling the CurrencyDigits abstract - // operation (defined below) with argument c. - cDigits = CurrencyDigits(c); - } - - var - // 21. Let cd be the result of calling the GetOption abstract operation with the - // arguments options, "currencyDisplay", "string", a List containing the - // three String values "code", "symbol", and "name", and "symbol". - cd = GetOption(options, 'currencyDisplay', 'string', new List('code', 'symbol', 'name'), 'symbol'); - - // 22. If s is "currency", then set the [[currencyDisplay]] internal property of - // numberFormat to cd. - if (s === 'currency') - internal['[[currencyDisplay]]'] = cd; - - var - // 23. Let mnid be the result of calling the GetNumberOption abstract operation - // (defined in 9.2.10) with arguments options, "minimumIntegerDigits", 1, 21, - // and 1. - mnid = GetNumberOption(options, 'minimumIntegerDigits', 1, 21, 1); - - // 24. Set the [[minimumIntegerDigits]] internal property of numberFormat to mnid. - internal['[[minimumIntegerDigits]]'] = mnid; - - var - // 25. If s is "currency", then let mnfdDefault be cDigits; else let mnfdDefault - // be 0. - mnfdDefault = s === 'currency' ? cDigits : 0, - - // 26. Let mnfd be the result of calling the GetNumberOption abstract operation - // with arguments options, "minimumFractionDigits", 0, 20, and mnfdDefault. - mnfd = GetNumberOption(options, 'minimumFractionDigits', 0, 20, mnfdDefault); - - // 27. Set the [[minimumFractionDigits]] internal property of numberFormat to mnfd. - internal['[[minimumFractionDigits]]'] = mnfd; - - var - // 28. If s is "currency", then let mxfdDefault be max(mnfd, cDigits); else if s - // is "percent", then let mxfdDefault be max(mnfd, 0); else let mxfdDefault - // be max(mnfd, 3). - mxfdDefault = s === 'currency' ? Math.max(mnfd, cDigits) - : (s === 'percent' ? Math.max(mnfd, 0) : Math.max(mnfd, 3)), - - // 29. Let mxfd be the result of calling the GetNumberOption abstract operation - // with arguments options, "maximumFractionDigits", mnfd, 20, and mxfdDefault. - mxfd = GetNumberOption(options, 'maximumFractionDigits', mnfd, 20, mxfdDefault); - - // 30. Set the [[maximumFractionDigits]] internal property of numberFormat to mxfd. - internal['[[maximumFractionDigits]]'] = mxfd; - - var - // 31. Let mnsd be the result of calling the [[Get]] internal method of options - // with argument "minimumSignificantDigits". - mnsd = options.minimumSignificantDigits, - - // 32. Let mxsd be the result of calling the [[Get]] internal method of options - // with argument "maximumSignificantDigits". - mxsd = options.maximumSignificantDigits; - - // 33. If mnsd is not undefined or mxsd is not undefined, then: - if (mnsd !== undefined || mxsd !== undefined) { - // a. Let mnsd be the result of calling the GetNumberOption abstract - // operation with arguments options, "minimumSignificantDigits", 1, 21, - // and 1. - mnsd = GetNumberOption(options, 'minimumSignificantDigits', 1, 21, 1); - - // b. Let mxsd be the result of calling the GetNumberOption abstract - // operation with arguments options, "maximumSignificantDigits", mnsd, - // 21, and 21. - mxsd = GetNumberOption(options, 'maximumSignificantDigits', mnsd, 21, 21); - - // c. Set the [[minimumSignificantDigits]] internal property of numberFormat - // to mnsd, and the [[maximumSignificantDigits]] internal property of - // numberFormat to mxsd. - internal['[[minimumSignificantDigits]]'] = mnsd; - internal['[[maximumSignificantDigits]]'] = mxsd; - } - var - // 34. Let g be the result of calling the GetOption abstract operation with the - // arguments options, "useGrouping", "boolean", undefined, and true. - g = GetOption(options, 'useGrouping', 'boolean', undefined, true); - - // 35. Set the [[useGrouping]] internal property of numberFormat to g. - internal['[[useGrouping]]'] = g; - - var - // 36. Let dataLocaleData be the result of calling the [[Get]] internal method of - // localeData with argument dataLocale. - dataLocaleData = localeData[dataLocale], - - // 37. Let patterns be the result of calling the [[Get]] internal method of - // dataLocaleData with argument "patterns". - patterns = dataLocaleData.patterns; - - // 38. Assert: patterns is an object (see 11.2.3) - - var - // 39. Let stylePatterns be the result of calling the [[Get]] internal method of - // patterns with argument s. - stylePatterns = patterns[s]; - - // 40. Set the [[positivePattern]] internal property of numberFormat to the - // result of calling the [[Get]] internal method of stylePatterns with the - // argument "positivePattern". - internal['[[positivePattern]]'] = stylePatterns.positivePattern; - - // 41. Set the [[negativePattern]] internal property of numberFormat to the - // result of calling the [[Get]] internal method of stylePatterns with the - // argument "negativePattern". - internal['[[negativePattern]]'] = stylePatterns.negativePattern; - - // 42. Set the [[boundFormat]] internal property of numberFormat to undefined. - internal['[[boundFormat]]'] = undefined; - - // 43. Set the [[initializedNumberFormat]] internal property of numberFormat to - // true. - internal['[[initializedNumberFormat]]'] = true; - - // Restore the RegExp properties - regexpState.exp.test(regexpState.input); - - // Return the newly initialised object - return numberFormat; - } - - function CurrencyDigits(currency) { - // When the CurrencyDigits abstract operation is called with an argument currency - // (which must be an upper case String value), the following steps are taken: - - // 1. If the ISO 4217 currency and funds code list contains currency as an - // alphabetic code, then return the minor unit value corresponding to the - // currency from the list; else return 2. - return currencyMinorUnits[currency] !== undefined - ? currencyMinorUnits[currency] - : 2; - } - - /* 11.2.3 */internals.NumberFormat = { - '[[availableLocales]]': [], - '[[relevantExtensionKeys]]': ['nu'], - '[[localeData]]': {} - }; - - /** - * When the supportedLocalesOf method of Intl.NumberFormat is called, the - * following steps are taken: - */ - /* 11.2.2 */defineProperty(Intl.NumberFormat, 'supportedLocalesOf', { - configurable: true, - writable: true, - value: fnBind.call(supportedLocalesOf, internals.NumberFormat) - }); - - /** - * This named accessor property returns a function that formats a number - * according to the effective locale and the formatting options of this - * NumberFormat object. - */ - /* 11.3.2 */defineProperty(Intl.NumberFormat.prototype, 'format', { - configurable: true, - get: function () { - var internal = this != null && typeof this === 'object' && getInternalProperties(this); - - // Satisfy test 11.3_b - if (!internal || !internal['[[initializedNumberFormat]]']) - throw new TypeError('`this` value for format() is not an initialized Intl.NumberFormat object.'); - - // The value of the [[Get]] attribute is a function that takes the following - // steps: - - // 1. If the [[boundFormat]] internal property of this NumberFormat object - // is undefined, then: - if (internal['[[boundFormat]]'] === undefined) { - var - // a. Let F be a Function object, with internal properties set as - // specified for built-in functions in ES5, 15, or successor, and the - // length property set to 1, that takes the argument value and - // performs the following steps: - F = function (value) { - // i. If value is not provided, then let value be undefined. - // ii. Let x be ToNumber(value). - // iii. Return the result of calling the FormatNumber abstract - // operation (defined below) with arguments this and x. - return FormatNumber(this, /* x = */Number(value)); - }, - - // b. Let bind be the standard built-in function object defined in ES5, - // 15.3.4.5. - // c. Let bf be the result of calling the [[Call]] internal method of - // bind with F as the this value and an argument list containing - // the single item this. - bf = fnBind.call(F, this); - - // d. Set the [[boundFormat]] internal property of this NumberFormat - // object to bf. - internal['[[boundFormat]]'] = bf; - } - // Return the value of the [[boundFormat]] internal property of this - // NumberFormat object. - return internal['[[boundFormat]]']; - } - }); - - /** - * When the FormatNumber abstract operation is called with arguments numberFormat - * (which must be an object initialized as a NumberFormat) and x (which must be a - * Number value), it returns a String value representing x according to the - * effective locale and the formatting options of numberFormat. - */ - function FormatNumber (numberFormat, x) { - var n, - - // Create an object whose props can be used to restore the values of RegExp props - regexpState = createRegExpRestore(), - - internal = getInternalProperties(numberFormat), - locale = internal['[[dataLocale]]'], - nums = internal['[[numberingSystem]]'], - data = internals.NumberFormat['[[localeData]]'][locale], - ild = data.symbols[nums] || data.symbols.latn, - - // 1. Let negative be false. - negative = false; - - // 2. If the result of isFinite(x) is false, then - if (isFinite(x) === false) { - // a. If x is NaN, then let n be an ILD String value indicating the NaN value. - if (isNaN(x)) - n = ild.nan; - - // b. Else - else { - // a. Let n be an ILD String value indicating infinity. - n = ild.infinity; - // b. If x < 0, then let negative be true. - if (x < 0) - negative = true; - } - } - // 3. Else - else { - // a. If x < 0, then - if (x < 0) { - // i. Let negative be true. - negative = true; - // ii. Let x be -x. - x = -x; - } - - // b. If the value of the [[style]] internal property of numberFormat is - // "percent", let x be 100 × x. - if (internal['[[style]]'] === 'percent') - x *= 100; - - // c. If the [[minimumSignificantDigits]] and [[maximumSignificantDigits]] - // internal properties of numberFormat are present, then - if (hop.call(internal, '[[minimumSignificantDigits]]') && - hop.call(internal, '[[maximumSignificantDigits]]')) - // i. Let n be the result of calling the ToRawPrecision abstract operation - // (defined below), passing as arguments x and the values of the - // [[minimumSignificantDigits]] and [[maximumSignificantDigits]] - // internal properties of numberFormat. - n = ToRawPrecision(x, - internal['[[minimumSignificantDigits]]'], - internal['[[maximumSignificantDigits]]']); - // d. Else - else - // i. Let n be the result of calling the ToRawFixed abstract operation - // (defined below), passing as arguments x and the values of the - // [[minimumIntegerDigits]], [[minimumFractionDigits]], and - // [[maximumFractionDigits]] internal properties of numberFormat. - n = ToRawFixed(x, - internal['[[minimumIntegerDigits]]'], - internal['[[minimumFractionDigits]]'], - internal['[[maximumFractionDigits]]']); - - // e. If the value of the [[numberingSystem]] internal property of - // numberFormat matches one of the values in the “Numbering System” column - // of Table 2 below, then - if (numSys[nums]) { - // i. Let digits be an array whose 10 String valued elements are the - // UTF-16 string representations of the 10 digits specified in the - // “Digits” column of Table 2 in the row containing the value of the - // [[numberingSystem]] internal property. - var digits = numSys[internal['[[numberingSystem]]']]; - // ii. Replace each digit in n with the value of digits[digit]. - n = String(n).replace(/\d/g, function (digit) { - return digits[digit]; - }); - } - // f. Else use an implementation dependent algorithm to map n to the - // appropriate representation of n in the given numbering system. - else - n = String(n); // ###TODO### - - // g. If n contains the character ".", then replace it with an ILND String - // representing the decimal separator. - n = n.replace(/\./g, ild.decimal); - - // h. If the value of the [[useGrouping]] internal property of numberFormat - // is true, then insert an ILND String representing a grouping separator - // into an ILND set of locations within the integer part of n. - if (internal['[[useGrouping]]'] === true) { - var parts = n.split(ild.decimal); - parts[0] = parts[0].replace(expInsertGroups, ild.group); - - n = arrJoin.call(parts, ild.decimal); - } - } - - var - // 4. If negative is true, then let result be the value of the [[negativePattern]] - // internal property of numberFormat; else let result be the value of the - // [[positivePattern]] internal property of numberFormat. - result = internal[negative === true ? '[[negativePattern]]' : '[[positivePattern]]']; - - // 5. Replace the substring "{number}" within result with n. - result = result.replace('{number}', n); - - // 6. If the value of the [[style]] internal property of numberFormat is - // "currency", then: - if (internal['[[style]]'] === 'currency') { - var cd, - // a. Let currency be the value of the [[currency]] internal property of - // numberFormat. - currency = internal['[[currency]]'], - - // Shorthand for the currency data - cData = data.currencies[currency]; - - // b. If the value of the [[currencyDisplay]] internal property of - // numberFormat is "code", then let cd be currency. - if (internal['[[currencyDisplay]]'] === 'code') - cd = currency; - - // c. Else if the value of the [[currencyDisplay]] internal property of - // numberFormat is "symbol", then let cd be an ILD string representing - // currency in short form. If the implementation does not have such a - // representation of currency, then use currency itself. - else if (internal['[[currencyDisplay]]'] === 'symbol') - cd = cData || currency; - - // d. Else if the value of the [[currencyDisplay]] internal property of - // numberFormat is "name", then let cd be an ILD string representing - // currency in long form. If the implementation does not have such a - // representation of currency, then use currency itself. - else if (internal['[[currencyDisplay]]'] === 'name') - cd = cData ? cData['displayName-count-one'] : currency; - - // e. Replace the substring "{currency}" within result with cd. - result = result.replace('{currency}', cd); - } - - // Restore the RegExp properties - regexpState.exp.test(regexpState.input); - - // 7. Return result. - return result; - } - - /** - * When the ToRawPrecision abstract operation is called with arguments x (which - * must be a finite non-negative number), minPrecision, and maxPrecision (both - * must be integers between 1 and 21) the following steps are taken: - */ - function ToRawPrecision (x, minPrecision, maxPrecision) { - var - // 1. Let p be maxPrecision. - p = maxPrecision; - - // 2. If x = 0, then - if (x === 0) { - var - // a. Let m be the String consisting of p occurrences of the character "0". - m = arrJoin.call(Array (p + 1), '0'), - // b. Let e be 0. - e = 0; - } - // 3. Else - else { - // a. Let e and n be integers such that 10ᵖ⁻¹ ≤ n < 10ᵖ and for which the - // exact mathematical value of n × 10ᵉ⁻ᵖ⁺¹ – x is as close to zero as - // possible. If there are two such sets of e and n, pick the e and n for - // which n × 10ᵉ⁻ᵖ⁺¹ is larger. - - var idx, - - isInt = x % 1, - - // Fix floating point precision issues in Chrome and Firefox - pre = isInt ? Math.pow(10, maxPrecision) : 1, - - // toPrecision already does most of this for us - m = Number.prototype.toPrecision.call(x*pre, maxPrecision), - - // Get the exponential value - e = (idx = m.indexOf('e')) > -1 ? Number(m.slice(idx + 1)) - : ((idx = m.indexOf('.')) > -1 ? idx - 1 : m.length - 1); - - // Multiplying by 10^maxPrecision means we need to take that away from e - if (isInt) - e -= maxPrecision; - - // Get the numbers without the decimal point - m = m.slice(0, m.indexOf('e') > -1 ? idx : m.length).replace('.', ''); - } - - // 4. If e ≥ p, then - if (e >= p) - // a. Return the concatenation of m and e-p+1 occurrences of the character "0". - return m + arrJoin.call(Array(e-p+1 + 1), '0'); - - // 5. If e = p-1, then - else if (e === p - 1) - // a. Return m. - return m; - - // 6. If e ≥ 0, then - else if (e >= 0) - // a. Let m be the concatenation of the first e+1 characters of m, the character - // ".", and the remaining p–(e+1) characters of m. - m = m.slice(0, e + 1) + '.' + m.slice(e + 1); - - // 7. If e < 0, then - else if (e < 0) - // a. Let m be the concatenation of the String "0.", –(e+1) occurrences of the - // character "0", and the string m. - m = '0.' + arrJoin.call(Array (-(e+1) + 1), '0') + m; - - // 8. If m contains the character ".", and maxPrecision > minPrecision, then - if (m.indexOf(".") >= 0 && maxPrecision > minPrecision) { - var - // a. Let cut be maxPrecision – minPrecision. - cut = maxPrecision - minPrecision; - - // b. Repeat while cut > 0 and the last character of m is "0": - while (cut > 0 && m.charAt(m.length-1) === '0') { - // i. Remove the last character from m. - m = m.slice(0, -1); - - // ii. Decrease cut by 1. - cut--; - } - - // c. If the last character of m is ".", then - if (m.charAt(m.length-1) === '.') - // i. Remove the last character from m. - m = m.slice(0, -1); - } - // 9. Return m. - return m; - } - - /** - * When the ToRawFixed abstract operation is called with arguments x (which must - * be a finite non-negative number), minInteger (which must be an integer between - * 1 and 21), minFraction, and maxFraction (which must be integers between 0 and - * 20) the following steps are taken: - */ - function ToRawFixed (x, minInteger, minFraction, maxFraction) { - // (or not because Number.toPrototype.toFixed does a lot of it for us) - var idx, - - // We can pick up after the fixed formatted string (m) is created - m = Number.prototype.toFixed.call(x, maxFraction), - - // 4. If [maxFraction] ≠ 0, then - // ... - // e. Let int be the number of characters in a. - // - // 5. Else let int be the number of characters in m. - igr = m.split(".")[0].length, // int is a reserved word - - // 6. Let cut be maxFraction – minFraction. - cut = maxFraction - minFraction, - - exp = (idx = m.indexOf('e')) > -1 ? m.slice(idx + 1) : 0; - - if (exp) { - m = m.slice(0, idx).replace('.', ''); - m += arrJoin.call(Array(exp - (m.length - 1) + 1), '0') - + '.' + arrJoin.call(Array(maxFraction + 1), '0'); - - igr = m.length; - } - - // 7. Repeat while cut > 0 and the last character of m is "0": - while (cut > 0 && m.slice(-1) === "0") { - // a. Remove the last character from m. - m = m.slice(0, -1); - - // b. Decrease cut by 1. - cut--; - } - - // 8. If the last character of m is ".", then - if (m.slice(-1) === ".") - // a. Remove the last character from m. - m = m.slice(0, -1); - - // 9. If int < minInteger, then - if (igr < minInteger) - // a. Let z be the String consisting of minInteger–int occurrences of the - // character "0". - var z = arrJoin.call(Array(minInteger - igr + 1), '0'); - - // 10. Let m be the concatenation of Strings z and m. - // 11. Return m. - return (z ? z : '') + m; - } - - // Sect 11.3.2 Table 2, Numbering systems - // ====================================== - var numSys = { - arab: [ '\u0660', '\u0661', '\u0662', '\u0663', '\u0664', '\u0665', '\u0666', '\u0667', '\u0668', '\u0669' ], - arabext: [ '\u06F0', '\u06F1', '\u06F2', '\u06F3', '\u06F4', '\u06F5', '\u06F6', '\u06F7', '\u06F8', '\u06F9' ], - bali: [ '\u1B50', '\u1B51', '\u1B52', '\u1B53', '\u1B54', '\u1B55', '\u1B56', '\u1B57', '\u1B58', '\u1B59' ], - beng: [ '\u09E6', '\u09E7', '\u09E8', '\u09E9', '\u09EA', '\u09EB', '\u09EC', '\u09ED', '\u09EE', '\u09EF' ], - deva: [ '\u0966', '\u0967', '\u0968', '\u0969', '\u096A', '\u096B', '\u096C', '\u096D', '\u096E', '\u096F' ], - fullwide:[ '\uFF10', '\uFF11', '\uFF12', '\uFF13', '\uFF14', '\uFF15', '\uFF16', '\uFF17', '\uFF18', '\uFF19' ], - gujr: [ '\u0AE6', '\u0AE7', '\u0AE8', '\u0AE9', '\u0AEA', '\u0AEB', '\u0AEC', '\u0AED', '\u0AEE', '\u0AEF' ], - guru: [ '\u0A66', '\u0A67', '\u0A68', '\u0A69', '\u0A6A', '\u0A6B', '\u0A6C', '\u0A6D', '\u0A6E', '\u0A6F' ], - hanidec: [ '\u3007', '\u4E00', '\u4E8C', '\u4E09', '\u56DB', '\u4E94', '\u516D', '\u4E03', '\u516B', '\u4E5D' ], - khmr: [ '\u17E0', '\u17E1', '\u17E2', '\u17E3', '\u17E4', '\u17E5', '\u17E6', '\u17E7', '\u17E8', '\u17E9' ], - knda: [ '\u0CE6', '\u0CE7', '\u0CE8', '\u0CE9', '\u0CEA', '\u0CEB', '\u0CEC', '\u0CED', '\u0CEE', '\u0CEF' ], - laoo: [ '\u0ED0', '\u0ED1', '\u0ED2', '\u0ED3', '\u0ED4', '\u0ED5', '\u0ED6', '\u0ED7', '\u0ED8', '\u0ED9' ], - latn: [ '\u0030', '\u0031', '\u0032', '\u0033', '\u0034', '\u0035', '\u0036', '\u0037', '\u0038', '\u0039' ], - limb: [ '\u1946', '\u1947', '\u1948', '\u1949', '\u194A', '\u194B', '\u194C', '\u194D', '\u194E', '\u194F' ], - mlym: [ '\u0D66', '\u0D67', '\u0D68', '\u0D69', '\u0D6A', '\u0D6B', '\u0D6C', '\u0D6D', '\u0D6E', '\u0D6F' ], - mong: [ '\u1810', '\u1811', '\u1812', '\u1813', '\u1814', '\u1815', '\u1816', '\u1817', '\u1818', '\u1819' ], - mymr: [ '\u1040', '\u1041', '\u1042', '\u1043', '\u1044', '\u1045', '\u1046', '\u1047', '\u1048', '\u1049' ], - orya: [ '\u0B66', '\u0B67', '\u0B68', '\u0B69', '\u0B6A', '\u0B6B', '\u0B6C', '\u0B6D', '\u0B6E', '\u0B6F' ], - tamldec: [ '\u0BE6', '\u0BE7', '\u0BE8', '\u0BE9', '\u0BEA', '\u0BEB', '\u0BEC', '\u0BED', '\u0BEE', '\u0BEF' ], - telu: [ '\u0C66', '\u0C67', '\u0C68', '\u0C69', '\u0C6A', '\u0C6B', '\u0C6C', '\u0C6D', '\u0C6E', '\u0C6F' ], - thai: [ '\u0E50', '\u0E51', '\u0E52', '\u0E53', '\u0E54', '\u0E55', '\u0E56', '\u0E57', '\u0E58', '\u0E59' ], - tibt: [ '\u0F20', '\u0F21', '\u0F22', '\u0F23', '\u0F24', '\u0F25', '\u0F26', '\u0F27', '\u0F28', '\u0F29' ] - }; - - /** - * This function provides access to the locale and formatting options computed - * during initialization of the object. - * - * The function returns a new object whose properties and attributes are set as - * if constructed by an object literal assigning to each of the following - * properties the value of the corresponding internal property of this - * NumberFormat object (see 11.4): locale, numberingSystem, style, currency, - * currencyDisplay, minimumIntegerDigits, minimumFractionDigits, - * maximumFractionDigits, minimumSignificantDigits, maximumSignificantDigits, and - * useGrouping. Properties whose corresponding internal properties are not present - * are not assigned. - */ - /* 11.3.3 */defineProperty(Intl.NumberFormat.prototype, 'resolvedOptions', { - configurable: true, - writable: true, - value: function () { - var prop, - descs = new Record(), - props = [ - 'locale', 'numberingSystem', 'style', 'currency', 'currencyDisplay', - 'minimumIntegerDigits', 'minimumFractionDigits', 'maximumFractionDigits', - 'minimumSignificantDigits', 'maximumSignificantDigits', 'useGrouping' - ], - internal = this != null && typeof this === 'object' && getInternalProperties(this); - - // Satisfy test 11.3_b - if (!internal || !internal['[[initializedNumberFormat]]']) - throw new TypeError('`this` value for resolvedOptions() is not an initialized Intl.NumberFormat object.'); - - for (var i = 0, max = props.length; i < max; i++) { - if (hop.call(internal, prop = '[['+ props[i] +']]')) - descs[props[i]] = { value: internal[prop], writable: true, configurable: true, enumerable: true }; - } - - return objCreate({}, descs); - } - }); - - // 12.1 The Intl.DateTimeFormat constructor - // ================================== - - // Define the DateTimeFormat constructor internally so it cannot be tainted - function DateTimeFormatConstructor () { - var locales = arguments[0]; - var options = arguments[1]; - - if (!this || this === Intl) { - return new Intl.DateTimeFormat(locales, options); - } - return InitializeDateTimeFormat(toObject(this), locales, options); - } - - defineProperty(Intl, 'DateTimeFormat', { - configurable: true, - writable: true, - value: DateTimeFormatConstructor - }); - - // Must explicitly set prototypes as unwritable - defineProperty(DateTimeFormatConstructor, 'prototype', { - writable: false - }); - - /** - * The abstract operation InitializeDateTimeFormat accepts the arguments dateTimeFormat - * (which must be an object), locales, and options. It initializes dateTimeFormat as a - * DateTimeFormat object. - */ - function/* 12.1.1.1 */InitializeDateTimeFormat (dateTimeFormat, locales, options) { - var - // This will be a internal properties object if we're not already initialized - internal = getInternalProperties(dateTimeFormat), - - // Create an object whose props can be used to restore the values of RegExp props - regexpState = createRegExpRestore(); - - // 1. If dateTimeFormat has an [[initializedIntlObject]] internal property with - // value true, throw a TypeError exception. - if (internal['[[initializedIntlObject]]'] === true) - throw new TypeError('`this` object has already been initialized as an Intl object'); - - // Need this to access the `internal` object - defineProperty(dateTimeFormat, '__getInternalProperties', { - value: function () { - // NOTE: Non-standard, for internal use only - if (arguments[0] === secret) - return internal; - } - }); - - // 2. Set the [[initializedIntlObject]] internal property of numberFormat to true. - internal['[[initializedIntlObject]]'] = true; - - var - // 3. Let requestedLocales be the result of calling the CanonicalizeLocaleList - // abstract operation (defined in 9.2.1) with argument locales. - requestedLocales = CanonicalizeLocaleList(locales), - - // 4. Let options be the result of calling the ToDateTimeOptions abstract - // operation (defined below) with arguments options, "any", and "date". - options = ToDateTimeOptions(options, 'any', 'date'), - - // 5. Let opt be a new Record. - opt = new Record(), - - // 6. Let matcher be the result of calling the GetOption abstract operation - // (defined in 9.2.9) with arguments options, "localeMatcher", "string", a List - // containing the two String values "lookup" and "best fit", and "best fit". - matcher = GetOption(options, 'localeMatcher', 'string', new List('lookup', 'best fit'), 'best fit'); - - // 7. Set opt.[[localeMatcher]] to matcher. - opt['[[localeMatcher]]'] = matcher; - - var - // 8. Let DateTimeFormat be the standard built-in object that is the initial - // value of Intl.DateTimeFormat. - DateTimeFormat = internals.DateTimeFormat, // This is what we *really* need - - // 9. Let localeData be the value of the [[localeData]] internal property of - // DateTimeFormat. - localeData = DateTimeFormat['[[localeData]]'], - - // 10. Let r be the result of calling the ResolveLocale abstract operation - // (defined in 9.2.5) with the [[availableLocales]] internal property of - // DateTimeFormat, requestedLocales, opt, the [[relevantExtensionKeys]] - // internal property of DateTimeFormat, and localeData. - r = ResolveLocale(DateTimeFormat['[[availableLocales]]'], requestedLocales, - opt, DateTimeFormat['[[relevantExtensionKeys]]'], localeData); - - // 11. Set the [[locale]] internal property of dateTimeFormat to the value of - // r.[[locale]]. - internal['[[locale]]'] = r['[[locale]]']; - - // 12. Set the [[calendar]] internal property of dateTimeFormat to the value of - // r.[[ca]]. - internal['[[calendar]]'] = r['[[ca]]']; - - // 13. Set the [[numberingSystem]] internal property of dateTimeFormat to the value of - // r.[[nu]]. - internal['[[numberingSystem]]'] = r['[[nu]]']; - - // The specification doesn't tell us to do this, but it's helpful later on - internal['[[dataLocale]]'] = r['[[dataLocale]]']; - - var - // 14. Let dataLocale be the value of r.[[dataLocale]]. - dataLocale = r['[[dataLocale]]'], - - // 15. Let tz be the result of calling the [[Get]] internal method of options with - // argument "timeZone". - tz = options.timeZone; - - // 16. If tz is not undefined, then - if (tz !== undefined) { - // a. Let tz be ToString(tz). - // b. Convert tz to upper case as described in 6.1. - // NOTE: If an implementation accepts additional time zone values, as permitted - // under certain conditions by the Conformance clause, different casing - // rules apply. - tz = toLatinUpperCase(tz); - - // c. If tz is not "UTC", then throw a RangeError exception. - // ###TODO: accept more time zones### - if (tz !== 'UTC') - throw new RangeError('timeZone is not supported.'); - } - - // 17. Set the [[timeZone]] internal property of dateTimeFormat to tz. - internal['[[timeZone]]'] = tz; - - // 18. Let opt be a new Record. - opt = new Record(); - - // 19. For each row of Table 3, except the header row, do: - for (var prop in dateTimeComponents) { - if (!hop.call(dateTimeComponents, prop)) - continue; - - var - // 20. Let prop be the name given in the Property column of the row. - // 21. Let value be the result of calling the GetOption abstract operation, - // passing as argument options, the name given in the Property column of the - // row, "string", a List containing the strings given in the Values column of - // the row, and undefined. - value = GetOption(options, prop, 'string', dateTimeComponents[prop]); - - // 22. Set opt.[[]] to value. - opt['[['+prop+']]'] = value; - } - - var - // Assigned a value below - bestFormat, - - // 23. Let dataLocaleData be the result of calling the [[Get]] internal method of - // localeData with argument dataLocale. - dataLocaleData = localeData[dataLocale], - - // 24. Let formats be the result of calling the [[Get]] internal method of - // dataLocaleData with argument "formats". - formats = dataLocaleData.formats, - // 25. Let matcher be the result of calling the GetOption abstract operation with - // arguments options, "formatMatcher", "string", a List containing the two String - // values "basic" and "best fit", and "best fit". - matcher = GetOption(options, 'formatMatcher', 'string', new List('basic', 'best fit'), 'best fit'); - - // 26. If matcher is "basic", then - if (matcher === 'basic') - // 27. Let bestFormat be the result of calling the BasicFormatMatcher abstract - // operation (defined below) with opt and formats. - bestFormat = BasicFormatMatcher(opt, formats); - - // 28. Else - else - // 29. Let bestFormat be the result of calling the BestFitFormatMatcher - // abstract operation (defined below) with opt and formats. - bestFormat = BestFitFormatMatcher(opt, formats); - - // 30. For each row in Table 3, except the header row, do - for (var prop in dateTimeComponents) { - if (!hop.call(dateTimeComponents, prop)) - continue; - - // a. Let prop be the name given in the Property column of the row. - // b. Let pDesc be the result of calling the [[GetOwnProperty]] internal method of - // bestFormat with argument prop. - // c. If pDesc is not undefined, then - if (hop.call(bestFormat, prop)) { - var - // i. Let p be the result of calling the [[Get]] internal method of bestFormat - // with argument prop. - p = bestFormat[prop]; - - // ii. Set the [[]] internal property of dateTimeFormat to p. - internal['[['+prop+']]'] = p; - } - } - - var - // Assigned a value below - pattern, - - // 31. Let hr12 be the result of calling the GetOption abstract operation with - // arguments options, "hour12", "boolean", undefined, and undefined. - hr12 = GetOption(options, 'hour12', 'boolean'/*, undefined, undefined*/); - - // 32. If dateTimeFormat has an internal property [[hour]], then - if (internal['[[hour]]']) { - // a. If hr12 is undefined, then let hr12 be the result of calling the [[Get]] - // internal method of dataLocaleData with argument "hour12". - hr12 = hr12 === undefined ? dataLocaleData.hour12 : hr12; - - // b. Set the [[hour12]] internal property of dateTimeFormat to hr12. - internal['[[hour12]]'] = hr12; - - // c. If hr12 is true, then - if (hr12 === true) { - var - // i. Let hourNo0 be the result of calling the [[Get]] internal method of - // dataLocaleData with argument "hourNo0". - hourNo0 = dataLocaleData.hourNo0; - - // ii. Set the [[hourNo0]] internal property of dateTimeFormat to hourNo0. - internal['[[hourNo0]]'] = hourNo0; - - // iii. Let pattern be the result of calling the [[Get]] internal method of - // bestFormat with argument "pattern12". - pattern = bestFormat.pattern12; - } - - // d. Else - else - // i. Let pattern be the result of calling the [[Get]] internal method of - // bestFormat with argument "pattern". - pattern = bestFormat.pattern; - } - - // 33. Else - else - // a. Let pattern be the result of calling the [[Get]] internal method of - // bestFormat with argument "pattern". - pattern = bestFormat.pattern; - - // 34. Set the [[pattern]] internal property of dateTimeFormat to pattern. - internal['[[pattern]]'] = pattern; - - // 35. Set the [[boundFormat]] internal property of dateTimeFormat to undefined. - internal['[[boundFormat]]'] = undefined; - - // 36. Set the [[initializedDateTimeFormat]] internal property of dateTimeFormat to - // true. - internal['[[initializedDateTimeFormat]]'] = true; - - // Restore the RegExp properties - regexpState.exp.test(regexpState.input); - - // Return the newly initialised object - return dateTimeFormat; - } - - /** - * Several DateTimeFormat algorithms use values from the following table, which provides - * property names and allowable values for the components of date and time formats: - */ - var dateTimeComponents = { - weekday: [ "narrow", "short", "long" ], - era: [ "narrow", "short", "long" ], - year: [ "2-digit", "numeric" ], - month: [ "2-digit", "numeric", "narrow", "short", "long" ], - day: [ "2-digit", "numeric" ], - hour: [ "2-digit", "numeric" ], - minute: [ "2-digit", "numeric" ], - second: [ "2-digit", "numeric" ], - timeZoneName: [ "short", "long" ] - }; - - /** - * When the ToDateTimeOptions abstract operation is called with arguments options, - * required, and defaults, the following steps are taken: - */ - function ToDateTimeOptions (options, required, defaults) { - // 1. If options is undefined, then let options be null, else let options be - // ToObject(options). - options = options === undefined ? null : new Record(toObject(options)); - - var - // 2. Let create be the standard built-in function object defined in ES5, 15.2.3.5. - create = objCreate, - - // 3. Let options be the result of calling the [[Call]] internal method of create with - // undefined as the this value and an argument list containing the single item - // options. - options = create(options), - - // 4. Let needDefaults be true. - needDefaults = true; - - // 5. If required is "date" or "any", then - if (required === 'date' || required === 'any') { - // a. For each of the property names "weekday", "year", "month", "day": - // i. If the result of calling the [[Get]] internal method of options with the - // property name is not undefined, then let needDefaults be false. - if (options.weekday !== undefined || options.year !== undefined - || options.month !== undefined || options.day !== undefined) - needDefaults = false; - } - - // 6. If required is "time" or "any", then - if (required === 'time' || required === 'any') { - // a. For each of the property names "hour", "minute", "second": - // i. If the result of calling the [[Get]] internal method of options with the - // property name is not undefined, then let needDefaults be false. - if (options.hour !== undefined || options.minute !== undefined || options.second !== undefined) - needDefaults = false; - } - - // 7. If needDefaults is true and defaults is either "date" or "all", then - if (needDefaults && (defaults === 'date' || defaults === 'all')) - // a. For each of the property names "year", "month", "day": - // i. Call the [[DefineOwnProperty]] internal method of options with the - // property name, Property Descriptor {[[Value]]: "numeric", [[Writable]]: - // true, [[Enumerable]]: true, [[Configurable]]: true}, and false. - options.year = options.month = options.day = 'numeric'; - - // 8. If needDefaults is true and defaults is either "time" or "all", then - if (needDefaults && (defaults === 'time' || defaults === 'all')) - // a. For each of the property names "hour", "minute", "second": - // i. Call the [[DefineOwnProperty]] internal method of options with the - // property name, Property Descriptor {[[Value]]: "numeric", [[Writable]]: - // true, [[Enumerable]]: true, [[Configurable]]: true}, and false. - options.hour = options.minute = options.second = 'numeric'; - - // 9. Return options. - return options; - } - - /** - * When the BasicFormatMatcher abstract operation is called with two arguments options and - * formats, the following steps are taken: - */ - function BasicFormatMatcher (options, formats) { - var - // 1. Let removalPenalty be 120. - removalPenalty = 120, - - // 2. Let additionPenalty be 20. - additionPenalty = 20, - - // 3. Let longLessPenalty be 8. - longLessPenalty = 8, - - // 4. Let longMorePenalty be 6. - longMorePenalty = 6, - - // 5. Let shortLessPenalty be 6. - shortLessPenalty = 6, - - // 6. Let shortMorePenalty be 3. - shortMorePenalty = 3, - - // 7. Let bestScore be -Infinity. - bestScore = -Infinity, - - // 8. Let bestFormat be undefined. - bestFormat, - - // 9. Let i be 0. - i = 0, - - // 10. Let len be the result of calling the [[Get]] internal method of formats with argument "length". - len = formats.length; - - // 11. Repeat while i < len: - while (i < len) { - var - // a. Let format be the result of calling the [[Get]] internal method of formats with argument ToString(i). - format = formats[i], - - // b. Let score be 0. - score = 0; - - // c. For each property shown in Table 3: - for (var property in dateTimeComponents) { - if (!hop.call(dateTimeComponents, property)) - continue; - - var - // i. Let optionsProp be options.[[]]. - optionsProp = options['[['+ property +']]'], - - // ii. Let formatPropDesc be the result of calling the [[GetOwnProperty]] internal method of format - // with argument property. - // iii. If formatPropDesc is not undefined, then - // 1. Let formatProp be the result of calling the [[Get]] internal method of format with argument property. - formatProp = hop.call(format, property) ? format[property] : undefined; - - // iv. If optionsProp is undefined and formatProp is not undefined, then decrease score by - // additionPenalty. - if (optionsProp === undefined && formatProp !== undefined) - score -= additionPenalty; - - // v. Else if optionsProp is not undefined and formatProp is undefined, then decrease score by - // removalPenalty. - else if (optionsProp !== undefined && formatProp === undefined) - score -= removalPenalty; - - // vi. Else - else { - var - // 1. Let values be the array ["2-digit", "numeric", "narrow", "short", - // "long"]. - values = [ '2-digit', 'numeric', 'narrow', 'short', 'long' ], - - // 2. Let optionsPropIndex be the index of optionsProp within values. - optionsPropIndex = arrIndexOf.call(values, optionsProp), - - // 3. Let formatPropIndex be the index of formatProp within values. - formatPropIndex = arrIndexOf.call(values, formatProp), - - // 4. Let delta be max(min(formatPropIndex - optionsPropIndex, 2), -2). - delta = Math.max(Math.min(formatPropIndex - optionsPropIndex, 2), -2); - - // 5. If delta = 2, decrease score by longMorePenalty. - if (delta === 2) - score -= longMorePenalty; - - // 6. Else if delta = 1, decrease score by shortMorePenalty. - else if (delta === 1) - score -= shortMorePenalty; - - // 7. Else if delta = -1, decrease score by shortLessPenalty. - else if (delta === -1) - score -= shortLessPenalty; - - // 8. Else if delta = -2, decrease score by longLessPenalty. - else if (delta === -2) - score -= longLessPenalty; - } - } - - // d. If score > bestScore, then - if (score > bestScore) { - // i. Let bestScore be score. - bestScore = score; - - // ii. Let bestFormat be format. - bestFormat = format; - } - - // e. Increase i by 1. - i++; - } - - // 12. Return bestFormat. - return bestFormat; - } - - /** - * When the BestFitFormatMatcher abstract operation is called with two arguments options - * and formats, it performs implementation dependent steps, which should return a set of - * component representations that a typical user of the selected locale would perceive as - * at least as good as the one returned by BasicFormatMatcher. - */ - function BestFitFormatMatcher (options, formats) { - // This is good enough for now - return BasicFormatMatcher(options, formats); - } - - /* 12.2.3 */internals.DateTimeFormat = { - '[[availableLocales]]': [], - '[[relevantExtensionKeys]]': ['ca', 'nu'], - '[[localeData]]': {} - }; - - /** - * When the supportedLocalesOf method of Intl.DateTimeFormat is called, the - * following steps are taken: - */ - /* 12.2.2 */defineProperty(Intl.DateTimeFormat, 'supportedLocalesOf', { - configurable: true, - writable: true, - value: fnBind.call(supportedLocalesOf, internals.DateTimeFormat) - }); - - /** - * This named accessor property returns a function that formats a number - * according to the effective locale and the formatting options of this - * DateTimeFormat object. - */ - /* 12.3.2 */defineProperty(Intl.DateTimeFormat.prototype, 'format', { - configurable: true, - get: function () { - var internal = this != null && typeof this === 'object' && getInternalProperties(this); - - // Satisfy test 12.3_b - if (!internal || !internal['[[initializedDateTimeFormat]]']) - throw new TypeError('`this` value for format() is not an initialized Intl.DateTimeFormat object.'); - - // The value of the [[Get]] attribute is a function that takes the following - // steps: - - // 1. If the [[boundFormat]] internal property of this DateTimeFormat object - // is undefined, then: - if (internal['[[boundFormat]]'] === undefined) { - var - // a. Let F be a Function object, with internal properties set as - // specified for built-in functions in ES5, 15, or successor, and the - // length property set to 0, that takes the argument date and - // performs the following steps: - F = function () { - // i. If date is not provided or is undefined, then let x be the - // result as if by the expression Date.now() where Date.now is - // the standard built-in function defined in ES5, 15.9.4.4. - // ii. Else let x be ToNumber(date). - // iii. Return the result of calling the FormatDateTime abstract - // operation (defined below) with arguments this and x. - var x = Number(arguments.length === 0 ? Date.now() : arguments[0]); - return FormatDateTime(this, x); - }, - // b. Let bind be the standard built-in function object defined in ES5, - // 15.3.4.5. - // c. Let bf be the result of calling the [[Call]] internal method of - // bind with F as the this value and an argument list containing - // the single item this. - bf = fnBind.call(F, this); - // d. Set the [[boundFormat]] internal property of this NumberFormat - // object to bf. - internal['[[boundFormat]]'] = bf; - } - // Return the value of the [[boundFormat]] internal property of this - // NumberFormat object. - return internal['[[boundFormat]]']; - } - }); - - /** - * When the FormatDateTime abstract operation is called with arguments dateTimeFormat - * (which must be an object initialized as a DateTimeFormat) and x (which must be a Number - * value), it returns a String value representing x (interpreted as a time value as - * specified in ES5, 15.9.1.1) according to the effective locale and the formatting - * options of dateTimeFormat. - */ - function FormatDateTime(dateTimeFormat, x) { - // 1. If x is not a finite Number, then throw a RangeError exception. - if (!isFinite(x)) - throw new RangeError('Invalid valid date passed to format'); - - var - internal = dateTimeFormat.__getInternalProperties(secret), - - // Creating restore point for properties on the RegExp object... please wait - regexpState = createRegExpRestore(), - - // 2. Let locale be the value of the [[locale]] internal property of dateTimeFormat. - locale = internal['[[locale]]'], - - // 3. Let nf be the result of creating a new NumberFormat object as if by the - // expression new Intl.NumberFormat([locale], {useGrouping: false}) where - // Intl.NumberFormat is the standard built-in constructor defined in 11.1.3. - nf = new Intl.NumberFormat([locale], {useGrouping: false}), - - // 4. Let nf2 be the result of creating a new NumberFormat object as if by the - // expression new Intl.NumberFormat([locale], {minimumIntegerDigits: 2, useGrouping: - // false}) where Intl.NumberFormat is the standard built-in constructor defined in - // 11.1.3. - nf2 = new Intl.NumberFormat([locale], {minimumIntegerDigits: 2, useGrouping: false}), - - // 5. Let tm be the result of calling the ToLocalTime abstract operation (defined - // below) with x, the value of the [[calendar]] internal property of dateTimeFormat, - // and the value of the [[timeZone]] internal property of dateTimeFormat. - tm = ToLocalTime(x, internal['[[calendar]]'], internal['[[timeZone]]']), - - // 6. Let result be the value of the [[pattern]] internal property of dateTimeFormat. - result = internal['[[pattern]]'], - - // Need the locale minus any extensions - dataLocale = internal['[[dataLocale]]'], - - // Need the calendar data from CLDR - localeData = internals.DateTimeFormat['[[localeData]]'][dataLocale].calendars, - ca = internal['[[calendar]]']; - - // 7. For each row of Table 3, except the header row, do: - for (var p in dateTimeComponents) { - // a. If dateTimeFormat has an internal property with the name given in the - // Property column of the row, then: - if (hop.call(internal, '[['+ p +']]')) { - var - // Assigned values below - pm, fv, - - // i. Let p be the name given in the Property column of the row. - // ii. Let f be the value of the [[

]] internal property of dateTimeFormat. - f = internal['[['+ p +']]'], - - // iii. Let v be the value of tm.[[

]]. - v = tm['[['+ p +']]']; - - // iv. If p is "year" and v ≤ 0, then let v be 1 - v. - if (p === 'year' && v <= 0) - v = 1 - v; - - // v. If p is "month", then increase v by 1. - else if (p === 'month') - v++; - - // vi. If p is "hour" and the value of the [[hour12]] internal property of - // dateTimeFormat is true, then - else if (p === 'hour' && internal['[[hour12]]'] === true) { - // 1. Let v be v modulo 12. - v = v % 12; - - // 2. If v is equal to the value of tm.[[

]], then let pm be false; else - // let pm be true. - pm = v !== tm['[['+ p +']]']; - - // 3. If v is 0 and the value of the [[hourNo0]] internal property of - // dateTimeFormat is true, then let v be 12. - if (v === 0 && internal['[[hourNo0]]'] === true) - v = 12; - } - - // vii. If f is "numeric", then - if (f === 'numeric') - // 1. Let fv be the result of calling the FormatNumber abstract operation - // (defined in 11.3.2) with arguments nf and v. - fv = FormatNumber(nf, v); - - // viii. Else if f is "2-digit", then - else if (f === '2-digit') { - // 1. Let fv be the result of calling the FormatNumber abstract operation - // with arguments nf2 and v. - fv = FormatNumber(nf2, v); - - // 2. If the length of fv is greater than 2, let fv be the substring of fv - // containing the last two characters. - if (fv.length > 2) - fv = fv.slice(-2); - } - - // ix. Else if f is "narrow", "short", or "long", then let fv be a String - // value representing f in the desired form; the String value depends upon - // the implementation and the effective locale and calendar of - // dateTimeFormat. If p is "month", then the String value may also depend - // on whether dateTimeFormat has a [[day]] internal property. If p is - // "timeZoneName", then the String value may also depend on the value of - // the [[inDST]] field of tm. - else if (f in dateWidths) { - switch (p) { - case 'month': - fv = resolveDateString(localeData, ca, 'months', f, tm['[['+ p +']]']); - break; - - case 'weekday': - try { - fv = resolveDateString(localeData, ca, 'days', f, tm['[['+ p +']]']); - // fv = resolveDateString(ca.days, f)[tm['[['+ p +']]']]; - } catch (e) { - throw new Error('Could not find weekday data for locale '+locale); - } - break; - - case 'timeZoneName': - fv = ''; // TODO - break; - - // TODO: Era - default: - fv = tm['[['+ p +']]']; - } - } - - // x. Replace the substring of result that consists of "{", p, and "}", with - // fv. - result = result.replace('{'+ p +'}', fv); - } - } - // 8. If dateTimeFormat has an internal property [[hour12]] whose value is true, then - if (internal['[[hour12]]'] === true) { - // a. If pm is true, then let fv be an implementation and locale dependent String - // value representing “post meridiem”; else let fv be an implementation and - // locale dependent String value representing “ante meridiem”. - fv = resolveDateString(localeData, ca, 'dayPeriods', pm ? 'pm' : 'am'); - - // b. Replace the substring of result that consists of "{ampm}", with fv. - result = result.replace('{ampm}', fv); - } - - // Restore properties of the RegExp object - regexpState.exp.test(regexpState.input); - - // 9. Return result. - return result; - } - - /** - * When the ToLocalTime abstract operation is called with arguments date, calendar, and - * timeZone, the following steps are taken: - */ - function ToLocalTime(date, calendar, timeZone) { - // 1. Apply calendrical calculations on date for the given calendar and time zone to - // produce weekday, era, year, month, day, hour, minute, second, and inDST values. - // The calculations should use best available information about the specified - // calendar and time zone. If the calendar is "gregory", then the calculations must - // match the algorithms specified in ES5, 15.9.1, except that calculations are not - // bound by the restrictions on the use of best available information on time zones - // for local time zone adjustment and daylight saving time adjustment imposed by - // ES5, 15.9.1.7 and 15.9.1.8. - // ###TODO### - var d = new Date(date); - - // 2. Return a Record with fields [[weekday]], [[era]], [[year]], [[month]], [[day]], - // [[hour]], [[minute]], [[second]], and [[inDST]], each with the corresponding - // calculated value. - return new Record({ - '[[weekday]]': d.getDay(), - '[[era]]' : +(d.getFullYear >= 0), - '[[year]]' : d.getFullYear(), - '[[month]]' : d.getMonth(), - '[[day]]' : d.getDate(), - '[[hour]]' : d.getHours(), - '[[minute]]' : d.getMinutes(), - '[[second]]' : d.getSeconds(), - '[[inDST]]' : false // ###TODO### - }); - } - - /** - * The function returns a new object whose properties and attributes are set as if - * constructed by an object literal assigning to each of the following properties the - * value of the corresponding internal property of this DateTimeFormat object (see 12.4): - * locale, calendar, numberingSystem, timeZone, hour12, weekday, era, year, month, day, - * hour, minute, second, and timeZoneName. Properties whose corresponding internal - * properties are not present are not assigned. - */ - /* 12.3.3 */defineProperty(Intl.DateTimeFormat.prototype, 'resolvedOptions', { - writable: true, - configurable: true, - value: function () { - var prop, - descs = new Record(), - props = [ - 'locale', 'calendar', 'numberingSystem', 'timeZone', 'hour12', 'weekday', - 'era', 'year', 'month', 'day', 'hour', 'minute', 'second', 'timeZoneName', - - // Not part of the spec, but in here for debugging purposes - 'pattern' - ], - internal = this != null && typeof this === 'object' && getInternalProperties(this); - - // Satisfy test 12.3_b - if (!internal || !internal['[[initializedDateTimeFormat]]']) - throw new TypeError('`this` value for resolvedOptions() is not an initialized Intl.DateTimeFormat object.'); - - for (var i = 0, max = props.length; i < max; i++) { - if (hop.call(internal, prop = '[[' + props[i] + ']]')) - descs[props[i]] = { value: internal[prop], writable: true, configurable: true, enumerable: true }; - } - - return objCreate({}, descs); - } - }); - - // Sect 13 Locale Sensitive Functions of the ECMAScript Language Specification - // =========================================================================== - - /** - * When the toLocaleString method is called with optional arguments locales and options, - * the following steps are taken: - */ - /* 13.2.1 */defineProperty(Number.prototype, 'toLocaleStringIntl', { - writable: true, - configurable: true, - value: function () { - // Satisfy test 13.2.1_1 - if (Object.prototype.toString.call(this) !== '[object Number]') - throw new TypeError('`this` value must be a number for Number.prototype.toLocaleStringIntl()'); - - // 1. Let x be this Number value (as defined in ES5, 15.7.4). - // 2. If locales is not provided, then let locales be undefined. - // 3. If options is not provided, then let options be undefined. - // 4. Let numberFormat be the result of creating a new object as if by the - // expression new Intl.NumberFormat(locales, options) where - // Intl.NumberFormat is the standard built-in constructor defined in 11.1.3. - // 5. Return the result of calling the FormatNumber abstract operation - // (defined in 11.3.2) with arguments numberFormat and x. - return FormatNumber(new NumberFormatConstructor(arguments[0], arguments[1]), this); - } - }); - - /** - * When the toLocaleString method is called with optional arguments locales and options, - * the following steps are taken: - */ - /* 13.3.1 */defineProperty(Date.prototype, 'toLocaleStringIntl', { - writable: true, - configurable: true, - value: function () { - // Satisfy test 13.3.0_1 - if (Object.prototype.toString.call(this) !== '[object Date]') - throw new TypeError('`this` value must be a Date instance for Date.prototype.toLocaleStringIntl()'); - - var - // 1. Let x be this time value (as defined in ES5, 15.9.5). - x = +this; - - // 2. If x is NaN, then return "Invalid Date". - if (isNaN(x)) - return 'Invalid Date'; - - var - // 3. If locales is not provided, then let locales be undefined. - locales = arguments[0], - - // 4. If options is not provided, then let options be undefined. - options = arguments[1], - - // 5. Let options be the result of calling the ToDateTimeOptions abstract - // operation (defined in 12.1.1) with arguments options, "any", and "all". - options = ToDateTimeOptions(options, 'any', 'all'), - - // 6. Let dateTimeFormat be the result of creating a new object as if by the - // expression new Intl.DateTimeFormat(locales, options) where - // Intl.DateTimeFormat is the standard built-in constructor defined in 12.1.3. - dateTimeFormat = new DateTimeFormatConstructor(locales, options); - - // 7. Return the result of calling the FormatDateTime abstract operation (defined - // in 12.3.2) with arguments dateTimeFormat and x. - return FormatDateTime(dateTimeFormat, x); - } - }); - - /** - * When the toLocaleDateString method is called with optional arguments locales and - * options, the following steps are taken: - */ - /* 13.3.2 */defineProperty(Date.prototype, 'toLocaleDateString', { - writable: true, - configurable: true, - value: function () { - // Satisfy test 13.3.0_1 - if (Object.prototype.toString.call(this) !== '[object Date]') - throw new TypeError('`this` value must be a Date instance for Date.prototype.toLocaleDateString()'); - - var - // 1. Let x be this time value (as defined in ES5, 15.9.5). - x = +this; - - // 2. If x is NaN, then return "Invalid Date". - if (isNaN(x)) - return 'Invalid Date'; - - var - // 3. If locales is not provided, then let locales be undefined. - locales = arguments[0], - - // 4. If options is not provided, then let options be undefined. - options = arguments[1], - - // 5. Let options be the result of calling the ToDateTimeOptions abstract - // operation (defined in 12.1.1) with arguments options, "date", and "date". - options = ToDateTimeOptions(options, 'date', 'date'), - - // 6. Let dateTimeFormat be the result of creating a new object as if by the - // expression new Intl.DateTimeFormat(locales, options) where - // Intl.DateTimeFormat is the standard built-in constructor defined in 12.1.3. - dateTimeFormat = new DateTimeFormatConstructor(locales, options); - - // 7. Return the result of calling the FormatDateTime abstract operation (defined - // in 12.3.2) with arguments dateTimeFormat and x. - return FormatDateTime(dateTimeFormat, x); - } - }); - - /** - * When the toLocaleTimeString method is called with optional arguments locales and - * options, the following steps are taken: - */ - /* 13.3.3 */defineProperty(Date.prototype, 'toLocaleTimeString', { - writable: true, - configurable: true, - value: function () { - // Satisfy test 13.3.0_1 - if (Object.prototype.toString.call(this) !== '[object Date]') - throw new TypeError('`this` value must be a Date instance for Date.prototype.toLocaleTimeString()'); - - var - // 1. Let x be this time value (as defined in ES5, 15.9.5). - x = +this; - - // 2. If x is NaN, then return "Invalid Date". - if (isNaN(x)) - return 'Invalid Date'; - - var - // 3. If locales is not provided, then let locales be undefined. - locales = arguments[0], - - // 4. If options is not provided, then let options be undefined. - options = arguments[1], - - // 5. Let options be the result of calling the ToDateTimeOptions abstract - // operation (defined in 12.1.1) with arguments options, "time", and "time". - options = ToDateTimeOptions(options, 'time', 'time'), - - // 6. Let dateTimeFormat be the result of creating a new object as if by the - // expression new Intl.DateTimeFormat(locales, options) where - // Intl.DateTimeFormat is the standard built-in constructor defined in 12.1.3. - dateTimeFormat = new DateTimeFormatConstructor(locales, options); - - // 7. Return the result of calling the FormatDateTime abstract operation (defined - // in 12.3.2) with arguments dateTimeFormat and x. - return FormatDateTime(dateTimeFormat, x); - } - }); - - /** - * Can't really ship a single script with data for hundreds of locales, so we provide - * this __addLocaleData method as a means for the developer to add the data on an - * as-needed basis - */ - defineProperty(Intl, '__addLocaleData', { - value: addLocaleData - }); - function addLocaleData (data) { - if (!IsStructurallyValidLanguageTag(data.locale)) - throw new Error("Object passed doesn't identify itself with a valid language tag"); - - // Both NumberFormat and DateTimeFormat require number data, so throw if it isn't present - if (!data.number) - throw new Error("Object passed doesn't contain locale data for Intl.NumberFormat"); - - var locale, - locales = [ data.locale ], - parts = data.locale.split('-'); - - // Create fallbacks for locale data with scripts, e.g. Latn, Hans, Vaii, etc - if (parts.length > 2 && parts[1].length == 4) - arrPush.call(locales, parts[0] + '-' + parts[2]); - - while (locale = arrShift.call(locales)) { - // Add to NumberFormat internal properties as per 11.2.3 - arrPush.call(internals.NumberFormat['[[availableLocales]]'], locale); - internals.NumberFormat['[[localeData]]'][locale] = data.number; - - // ...and DateTimeFormat internal properties as per 12.2.3 - if (data.date) { - data.date.nu = data.number.nu; - arrPush.call(internals.DateTimeFormat['[[availableLocales]]'], locale); - internals.DateTimeFormat['[[localeData]]'][locale] = data.date; - } - } - - // If this is the first set of locale data added, make it the default - if (defaultLocale === undefined) - defaultLocale = data.locale; - - // 11.3 (the NumberFormat prototype object is an Intl.NumberFormat instance) - if (!numberFormatProtoInitialised) { - InitializeNumberFormat(Intl.NumberFormat.prototype); - numberFormatProtoInitialised = true; - } - - // 11.3 (the NumberFormat prototype object is an Intl.NumberFormat instance) - if (data.date && !dateTimeFormatProtoInitialised) { - InitializeDateTimeFormat(Intl.DateTimeFormat.prototype); - dateTimeFormatProtoInitialised = true; - } - } - - // Exposed for debugging - if (typeof window !== 'undefined') - window.IntlLocaleData = internals; - - // Helper functions - // ================ - - /** - * A merge of the Intl.{Constructor}.supportedLocalesOf functions - * To make life easier, the function should be bound to the constructor's internal - * properties object. - */ - function supportedLocalesOf(locales) { - /*jshint validthis:true */ - - // Bound functions only have the `this` value altered if being used as a constructor, - // this lets us imitate a native function that has no constructor - if (!hop.call(this, '[[availableLocales]]')) - throw new TypeError('supportedLocalesOf() is not a constructor'); - - var - // Create an object whose props can be used to restore the values of RegExp props - regexpState = createRegExpRestore(), - - // 1. If options is not provided, then let options be undefined. - options = arguments[1], - - // 2. Let availableLocales be the value of the [[availableLocales]] internal - // property of the standard built-in object that is the initial value of - // Intl.NumberFormat. - - availableLocales = this['[[availableLocales]]'], - - // 3. Let requestedLocales be the result of calling the CanonicalizeLocaleList - // abstract operation (defined in 9.2.1) with argument locales. - requestedLocales = CanonicalizeLocaleList(locales); - - // Restore the RegExp properties - regexpState.exp.test(regexpState.input); - - // 4. Return the result of calling the SupportedLocales abstract operation - // (defined in 9.2.8) with arguments availableLocales, requestedLocales, - // and options. - return SupportedLocales(availableLocales, requestedLocales, options); - } - - /** - * Returns a string for a date component, resolved using multiple inheritance as specified - * as specified in the Unicode Technical Standard 35. - */ - function resolveDateString(data, ca, component, width, key) { - // From http://www.unicode.org/reports/tr35/tr35.html#Multiple_Inheritance: - // 'In clearly specified instances, resources may inherit from within the same locale. - // For example, ... the Buddhist calendar inherits from the Gregorian calendar.' - var obj = data[ca] && data[ca][component] - ? data[ca][component] - : data.gregory[component], - - // "sideways" inheritance resolves strings when a key doesn't exist - alts = { - "narrow": ['short', 'long'], - "short": ['long', 'narrow'], - "long": ['short', 'narrow'] - }, - - // - resolved = hop.call(obj, width) - ? obj[width] - : hop.call(obj, alts[width][0]) - ? obj[alts[width][0]] - : obj[alts[width][1]]; - - // `key` wouldn't be specified for components 'dayPeriods' - return key != null ? resolved[key] : resolved; - } - - /** - * A map that doesn't contain Object in its prototype chain - */ - Record.prototype = objCreate(null); - function Record (obj) { - // Copy only own properties over unless this object is already a Record instance - for (var k in obj) { - if (obj instanceof Record || hop.call(obj, k)) - defineProperty(this, k, { value: obj[k], enumerable: true, writable: true, configurable: true }); - } - } - - /** - * An ordered list - */ - List.prototype = objCreate(null); - function List() { - defineProperty(this, 'length', { writable:true, value: 0 }); - - if (arguments.length) - arrPush.apply(this, arrSlice.call(arguments)); - } - - /** - * Constructs a regular expression to restore tainted RegExp properties - */ - function createRegExpRestore () { - var lm = RegExp.lastMatch, - ret = { - input: RegExp.input - }, - esc = /[.?*+^$[\]\\(){}|-]/g, - reg = new List(), - cap = {}; - - if(lm==')') lm="\\)"; - // Create a snapshot of all the 'captured' properties - for (var i = 1; i <= 9; i++) - cap['$'+i] = RegExp['$'+i]; - - - // Now, iterate over them - for (var i = 1; i <= 9; i++) { - var m = cap['$'+i]; - - // If it's empty, add an empty capturing group - if (!m) - lm = '()' + lm; - - // Else find the string in lm and escape & wrap it to capture it - else - lm = lm.replace(m, '(' + m.replace(esc, '\\$0') + ')'); - - // Push it to the reg and chop lm to make sure further groups come after - arrPush.call(reg, lm.slice(0, lm.indexOf('(') + 1)); - lm = lm.slice(lm.indexOf('(') + 1); - } - - // Create the regular expression that will reconstruct the RegExp properties - ret.exp = new RegExp(arrJoin.call(reg, '') + lm, RegExp.multiline ? 'm' : ''); - - return ret; - } - - /** - * Convert only a-z to uppercase as per section 6.1 of the spec - */ - function toLatinUpperCase (str) { - var i = str.length; - - while (i--) { - var ch = str.charAt(i); - - if (ch >= "a" && ch <= "z") - str = str.slice(0, i) + ch.toUpperCase() + str.slice(i+1); - } - - return str; - } - - /** - * Mimics ES5's abstract ToObject() function - */ - function toObject (arg) { - if (arg == null) - throw new TypeError('Cannot convert null or undefined to object'); - - return Object(arg); - } - - /** - * Returns "internal" properties for an object - */ - function getInternalProperties (obj) { - if (hop.call(obj, '__getInternalProperties')) - return obj.__getInternalProperties(secret); - else - return objCreate(null); - } - - return Intl; - })({}); - - if(!global.Intl) global.Intl=Intl; - - return {Intl: Intl}; -}); diff --git a/chartiq/production/index.js b/chartiq/production/index.js deleted file mode 100644 index 33002125de..0000000000 --- a/chartiq/production/index.js +++ /dev/null @@ -1,5 +0,0 @@ -export * from './js/chartiq.js'; -export * from './js/standard.js'; -export * from './js/advanced.js'; -export * from './js/deprecated.js'; -export * from './js/addOns.js'; diff --git a/chartiq/production/js/addOns.js b/chartiq/production/js/addOns.js deleted file mode 100644 index 2e56e630a1..0000000000 --- a/chartiq/production/js/addOns.js +++ /dev/null @@ -1,4982 +0,0 @@ -/**! - * 8.2.0 - * Generation date: 2023-03-23T15:05:01.971Z - * Client name: deriv limited - * Package Type: Technical Analysis - * License type: annual - * Expiration date: "2024/04/01" - * Domain lock: ["127.0.0.1","localhost","deriv.com","deriv.app","deriv.me","binary.com","binary.sx","binary.me","binary.bot","deriv.be"] - * iFrame lock: true - */ - -/***********************************************************! - * Copyright by ChartIQ, Inc. - * Licensed under the ChartIQ, Inc. Developer License Agreement https://www.chartiq.com/developer-license-agreement -*************************************************************/ -/*************************************! DO NOT MAKE CHANGES TO THIS LIBRARY FILE!! !************************************* -* If you wish to overwrite default functionality, create a separate file with a copy of the methods you are overwriting * -* and load that file right after the library has been loaded, but before the chart engine is instantiated. * -* Directly modifying library files will prevent upgrades and the ability for ChartIQ to support your solution. * -*************************************************************************************************************************/ -/* eslint-disable no-extra-parens */ - - -import {CIQ as __CIQ_} from "../js/chartiq.js"; - - -let __js_addons_standard_extendedHours_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -/** - * Use this constructor to initialize filtering and visualization styles of extended hours by the use of shading and delimitation lines. - * - * Requires *addOns.js*. - * - * This visualization will only work if data for the corresponding sessions is provided from your quote feed and the market definitions have the corresponding entries. - * See {@link CIQ.Market} for details on how to define extended (non-default) hours. - * - * By default all extended hour sessions are disabled unless explicitly enabled using {@link CIQ.ExtendedHours.prepare} or {@link CIQ.ExtendedHours.set}. - * - * All possible market sessions needed to be shaded at any given time should be enabled at once with this method. - * - * Your fetch should load the required data based on the `params.stx.layout.extended` and `params.stx.layout.marketSessions` settings. - * - * Remember that when `params.filter` is set to true, this module performs a filter of already loaded masterData when {@link CIQ.ExtendedHours.set} is invoked, - * rather than calling {@link CIQ.ChartEngine#loadChart} to reload the data from the server every time you enable or disable this feature. - * So you must always return all requested sessions on your fetch responses if this flag is set. - * - * CSS info: - * - The styles for the shading of each session is determined by the corresponding CSS class in the form of "stx_market_session."+session_name (Example: `stx_market_session.pre`) - * - The divider line is determined by the CSS class "stx_market_session.divider". - * - * **Important:** This module must be initialized before {@link CIQ.ChartEngine#importLayout} or the sessions will not be able to be restored. - * - * Example: - * - * - * @param {object} params The constructor parameters. - * @param {CIQ.ChartEngine} [params.stx] The chart object. - * @param {boolean} [params.filter] Setting to true performs a filter of masterData when - * {@link CIQ.ExtendedHours.set} is invoked, rather than calling - * {@link CIQ.ChartEngine#loadChart} to reload the data from the server. - * @param {string} [params.menuContextClass] A CSS class name used to query the menu DOM - * element that contains the UI control for the extended hours add-on. In a multi-chart - * document, the add-on is available only on charts that have a menu DOM element with - * the value for `menuContextClass` as a class attribute. - * - * @constructor - * @name CIQ.ExtendedHours - * @since - * - 06-2016-02 - * - 3.0.0 Changed argument to an object to support `filter`. - * - 3.0.0 No longer necessary to explicitly call new Chart to reload data. Instead call {@link CIQ.ExtendedHours.set} function. - * - 5.0.0 No longer necessary to explicitly set `stx.layout.marketSessions` or `1stx.layout.extended` to manage sessions; instead call {@link CIQ.ExtendedHours.prepare} or {@link CIQ.ExtendedHours.set}. - * - 8.0.0 Added `params.menuContextClass`. - * - * @example - * // Call this only once to initialize the market sessions display manager. - * new CIQ.ExtendedHours({stx:stxx, filter:true}); - * - * // By default all sessions are disabled unless explicitly enabled. - * // This forces the extended hours sessions ["pre","post"] to be enabled when the chart is initially loaded. - * stxx.extendedHours.prepare(true); - * - * // Now display your chart. - * stxx.loadChart(stxx.chart.symbol, {}, function() {}); - * - * @example - * // Once your chart is displayed, you can call this from any UI interface to turn on extended hours. - * stx.extendedHours.set(true); - * - * // Or call this from any UI interface to turn off extended hours. - * stx.extendedHours.set(false); - * - * @example - * // CSS entries for a session divider and sessions named "pre" and "post". - * .stx_market_session.divider { - * background-color: rgba(0,255,0,0.8); - * width: 1px; - * } - * .stx_market_session.pre { - * background-color: rgba(255,255,0,0.1); - * } - * .stx_market_session.post { - * background-color: rgba(0,0,255,0.2); - * } - */ -CIQ.ExtendedHours = - CIQ.ExtendedHours || - function (params) { - var stx = params.stx; - this.filter = params.filter; - if (!stx) { - // backwards compatibility - stx = params; - this.filter = false; - } - var styles = {}; - this.stx = stx; - this.stx.extendedHours = this; - this.cssRequired = true; - - stx.addEventListener("theme", function (tObject) { - // reinitialize the session colors after a theme change - styles = {}; - for (var sess in stx.layout.marketSessions) { - if (!styles.session) styles.session = {}; - styles.session[sess] = stx.canvasStyle("stx_market_session " + sess); - } - }); - - stx.addEventListener("symbolChange", function (tObject) { - // check if extended hours exists for this security - if ( - tObject.action == "master" && - stx.layout.extended && - !(stx.chart.market.market_def && stx.chart.market.sessions.length) - ) { - CIQ.alert("There are no Extended Hours for this instrument."); - } - }); - - /** - * Prepares the extended hours settings and classes for the session names enumerated in the arguments without actually displaying or loading the data. - * - * This method can be used to force a particular session to load by default by calling it before {@link CIQ.ChartEngine#loadChart}. - * Otherwise the chart will be loaded with all sessions disabled until {@link CIQ.ExtendedHours.set} is invoked. - * - * {@link CIQ.ChartEngine#importLayout} will also call this method to ensure the sessions are restored as previously saved. - * - * @param {boolean} enable Set to turn on/off the extended-hours visualization. - * @param {array} sessions The sessions to visualize when enable is true. Any sessions previously visualized will be disabled. If set to null, will default to ["pre","post"]. - * @memberof CIQ.ExtendedHours - * @method prepare - * @since 5.0.0 - */ - this.prepare = function (enable, sessions) { - stx.layout.extended = enable; - for (var sess in stx.layout.marketSessions) { - styles.session = {}; - stx.chart.market.disableSession(sess); - } - stx.layout.marketSessions = {}; - if (enable) { - if (!sessions) sessions = ["pre", "post"]; - if (sessions.length) { - for (var s = 0; s < sessions.length; s++) { - stx.layout.marketSessions[sessions[s]] = true; - } - } else { - stx.layout.marketSessions = sessions; - } - } - for (sess in stx.layout.marketSessions) { - if (!styles.session) styles.session = {}; - styles.session[sess] = stx.canvasStyle("stx_market_session " + sess); - stx.chart.market.disableSession(sess, true); - } - }; - - /** - * gathers and renders the extended hours for the preset session names enumerated in prepare(). - * @param {function} cb Optional callback function to be invoked once chart is reloaded with extended hours data. - * @memberof CIQ.ExtendedHours - * @method complete - * @private - * @since 5.0.0 - */ - this.complete = function (cb) { - stx.changeOccurred("layout"); - if (!stx.chart.market.market_def) { - // possibly a 24 hours Market. Not necessarily an error but nothing to do for ExtendedHours - if (cb) cb(); - return; - } - if (this.filter) { - stx.createDataSet(); - stx.draw(); - if (cb) cb(); - } else { - stx.loadChart(stx.chart.symbol, cb); - } - }; - - /** - * Turns on or off extended hours for the session names enumerated in the arguments. - * @param {boolean} enable Set to turn on/off the extended-hours visualization. - * @param {array} sessions The sessions to visualize when enable is true. Any sessions previously visualized will be disabled. If set to null, will default to ["pre","post"]. - * @param {function} cb Optional callback function to be invoked once chart is reloaded with extended hours data. - * @memberof CIQ.ExtendedHours - * @method set - */ - this.set = function (enable, sessions, cb) { - this.prepare(enable, sessions); - this.complete(cb); - }; - - // This injection shades the after hours portion of the chart for each yaxis. - // Only the panel to which the yaxis belongs will get shading. - // This means yaxes of overlays will bypass the shading block. - this.stx.append("drawYAxis", function (panel, parameters) { - if (!this.layout.extended) return; - if ( - panel.yAxis != parameters.yAxis || - panel.shareChartXAxis === false || - panel.hidden - ) - return; - var chart = panel.chart; - if (CIQ.ChartEngine.isDailyInterval(this.layout.interval)) return; - styles.divider = this.canvasStyle("stx_market_session divider"); - if (styles.session) { - var m = chart.market; - var ranges = []; - var range = {}; - var nextBoundary, thisSession; - for (var i = 0; i < chart.dataSegment.length; i++) { - var ds = chart.dataSegment[i]; - if (!ds || !ds.DT) continue; - var c = null; - if (m.market_def) { - if (!nextBoundary || nextBoundary <= ds.DT) { - thisSession = m.getSession(ds.DT); - var filterSession = - thisSession !== "" && - (!this.layout.marketSessions || - !this.layout.marketSessions[thisSession]); - nextBoundary = m[filterSession ? "getNextOpen" : "getNextClose"]( - ds.DT - ); - } - } - - var s = styles.session[thisSession]; - if (s) c = s.backgroundColor; - if (range.color && range.color != c) { - ranges.push({ - start: range.start, - end: range.end, - color: range.color - }); - range = {}; - } - if (c) { - var cw = this.layout.candleWidth; - if (ds.candleWidth) cw = ds.candleWidth; - range.end = this.pixelFromBar(i, chart) + cw / 2; - if (!range.start && range.start !== 0) - range.start = range.end - cw + 1; - range.color = c; - } else { - range = {}; - } - } - if (range.start || range.start === 0) - ranges.push({ - start: range.start, - end: range.end, - color: range.color - }); - var noDashes = CIQ.isTransparent(styles.divider.backgroundColor); - var dividerLineWidth = styles.divider.width.replace(/px/g, ""); - var dividerStyle = { - y0: panel.bottom, - y1: panel.top, - color: styles.divider.backgroundColor, - type: "line", - context: chart.context, - confineToPanel: panel, - pattern: "dashed", - lineWidth: dividerLineWidth, - deferStroke: true - }; - this.startClip(panel.name); - chart.context.beginPath(); - if (stx.highlightedDraggable) chart.context.globalAlpha *= 0.3; - for (i = 0; i < ranges.length; i++) { - chart.context.fillStyle = ranges[i].color; - if (!noDashes && ranges[i].start > chart.left) - this.plotLine( - CIQ.extend( - { x0: ranges[i].start, x1: ranges[i].start }, - dividerStyle - ) - ); - chart.context.fillRect( - ranges[i].start, - panel.top, - ranges[i].end - ranges[i].start, - panel.bottom - panel.top - ); - if (!noDashes && ranges[i].end < chart.right) - this.plotLine( - CIQ.extend({ x0: ranges[i].end, x1: ranges[i].end }, dividerStyle) - ); - } - chart.context.stroke(); - this.endClip(); - } - }); - }; - -}; - - -let __js_addons_standard_fullScreen_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -/** - * Creates an add-on that sets the chart UI to full-screen mode. In full-screen mode, a class - * `full-screen` is added to the context element used for styling. In addition, elements with the - * class `full-screen-hide` are hidden. Elements with the class `full-screen-show` that are - * normally hidden are shown. - * - * Requires *addOns.js*. - * - * ![Full-screen display](./img-Full-Screen-Chart.png) - * - * @param {object} params Configuration parameters. - * @param {CIQ.ChartEngine} [params.stx] The chart object. - * - * @constructor - * @name CIQ.FullScreen - * @since 7.3.0 - * - * @example - * new CIQ.FullScreen({ stx: stxx }); - */ -CIQ.FullScreen = - CIQ.FullScreen || - function (params) { - if (!params) params = {}; - if (!params.stx) { - console.warn("The Full Screen addon requires an stx parameter"); - return; - } - // Check for loading within an iframe from another origin - try { - if (window.location.host !== window.top.location.host) - throw new Error( - window.location.host + " does not match " + window.top.location.host - ); - } catch (exception) { - console.warn("Full screen mode disabled."); - return; - } - this.stx = params.stx; - this.stx.fullScreen = this; - this.fullScreenButton = null; - this.fullScreenState = false; - - //Attaches FullScreen button to HTML DOM inside .chartSize element - this.addFullScreenButton = function () { - if (this.stx.registerChartControl) - this.fullScreenButton = this.stx.registerChartControl( - "stx-full-screen", - "Full Screen", - (function (self) { - return function (e) { - self.fullScreenToggle(e); - e.stopPropagation(); - }; - })(this) - ); - }; - - //Click event handler for the Full Screen button. - this.fullScreenToggle = function (e) { - // First check for availability of the requestFullScreen function - if ( - document.documentElement.requestFullscreen || - document.documentElement.webkitRequestFullscreen || - document.documentElement.mozRequestFullscreen || - document.documentElement.msRequestFullscreen - ) { - // Check if full screen is already enabled - if (this.getFullScreenElement()) { - if (document.exitFullscreen) document.exitFullscreen(); - else if (document.webkitExitFullscreen) - document.webkitExitFullscreen(); - else if (document.mozCancelFullScreen) document.mozCancelFullScreen(); - else if (document.msExitFullscreen) document.msExitFullscreen(); - } else { - // requestFullscreen methods need to be checked for again here because the browser will not allow the method to be stored in a local var - if (document.documentElement.requestFullscreen) - document.documentElement.requestFullscreen(); - else if (document.documentElement.webkitRequestFullscreen) - document.documentElement.webkitRequestFullscreen(); - else if (document.documentElement.mozRequestFullscreen) - document.documentElement.mozRequestFullscreen(); - else if (document.documentElement.msRequestFullscreen) - document.documentElement.msRequestFullscreen(); - } - } else { - //If the full screen api isn't available, manually trigger the fullScreen styling - this.fullScreenState = !this.fullScreenState; - this.fullScreenRender(); - } - }; - - // Append/remove full-screen class to context or body and update button state - this.fullScreenRender = function () { - var containerElement = null; - containerElement = this.stx.container.closest( - "*[cq-context], cq-context, body" - ); - if (containerElement) { - if (this.fullScreenState === true) { - if (this.fullScreenButton) - this.fullScreenButton.classList.add("active"); - containerElement.classList.add("full-screen"); - } else { - if (this.fullScreenButton) - this.fullScreenButton.classList.remove("active"); - containerElement.classList.remove("full-screen"); - } - // Trigger a resize event to update the chart size - window.dispatchEvent(new Event("resize")); - } - }; - - //Handle full screen change - this.onFullScreenChange = function () { - if (this.getFullScreenElement()) { - this.fullScreenState = true; - } else { - this.fullScreenState = false; - } - this.fullScreenRender(); - }; - - this.getFullScreenElement = function () { - return ( - document.fullscreenElement || - document.webkitCurrentFullScreenElement || - document.mozFullScreenElement || - document.msFullscreenElement - ); - }; - - document.addEventListener( - "fullscreenchange", - this.onFullScreenChange.bind(this), - false - ); - document.addEventListener( - "webkitfullscreenchange", - this.onFullScreenChange.bind(this), - false - ); - document.addEventListener( - "mozfullscreenchange", - this.onFullScreenChange.bind(this), - false - ); - document.addEventListener( - "MSFullscreenChange", - this.onFullScreenChange.bind(this), - false - ); - - // Add the FullScreen button to chartControls - this.addFullScreenButton(); - }; - -}; - - -let __js_addons_standard_inactivityTimer_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -/** - * Add-On that puts the chart into "sleep mode" after a period of inactivity. - * - * Requires *addOns.js*. - * - * In sleep mode, a class "ciq-sleeping" will be added to the body. This will dim out the chart. - * Sleep mode is ended when interaction with the chart is detected. - * - * @param {object} params Configuration parameters - * @param {CIQ.ChartEngine} [params.stx] The chart object - * @param {number} [params.minutes] Inactivity period in _minutes_. Set to 0 to disable the sleep mode. - * @param {number} [params.interval] Sleeping quote update interval in _seconds_. During sleep mode, this is used for the update loop. - * Set to non-zero positive number or defaults to 60. - * @param {function} [params.wakeCB] Optional callback function after waking - * @param {function} [params.sleepCB] Optional callback function after sleeping - * @constructor - * @name CIQ.InactivityTimer - * @since 3.0.0 - * @example - * new CIQ.InactivityTimer({stx:stxx, minutes:30, interval:15}); //30 minutes of inactivity will put chart into sleep mode, updating every 15 seconds - * - */ -CIQ.InactivityTimer = - CIQ.InactivityTimer || - function (params) { - if (!params.minutes) return; - if (!params.interval || params.interval < 0) params.interval = 60; - this.stx = params.stx; - this.timeout = params.minutes; - this.interval = params.interval; - this.wakeCB = params.wakeCB; - this.sleepCB = params.sleepCB; - this.sleepTimer = null; - this.sleeping = false; - this.last = new Date().getTime(); - this.wakeChart = function () { - clearTimeout(this.sleepTimer); - this.last = new Date().getTime(); - if (this.sleeping) { - if (this.stx.quoteDriver) this.stx.quoteDriver.updateChartLoop(); - this.sleeping = false; - document.body.classList.remove("ciq-sleeping"); - } - this.sleepTimer = setTimeout( - this.sleepChart.bind(this), - this.timeout * 60000 - ); - if (this.wakeCB) this.wakeCB(); - }; - this.sleepChart = function () { - if (!this.sleeping) { - if (this.stx.quoteDriver) - this.stx.quoteDriver.updateChartLoop(this.interval); - this.sleeping = true; - document.body.classList.add("ciq-sleeping"); - } - if (this.sleepCB) this.sleepCB(); - }; - - var self = this; - [ - "mousemove", - "mousedown", - "touchstart", - "touchmove", - "pointerdown", - "pointermove", - "keydown", - "wheel" - ].forEach(function (ev) { - document.body.addEventListener(ev, function (e) { - self.wakeChart(); - }); - }); - this.wakeChart(); - }; - -}; - - -let __js_addons_standard_rangeSlider_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -/** - * Add-on that puts a range slider under the chart. - * - * This allows the `dataSegment` to be selectable as a portion of the dataset. - * - * Requires *addOns.js*. - * - * It also requires additional CSS. - * - * Either add: - * ``` - * - * ``` - * Or explicitly include this CSS: - * ``` - * .stx_range_slider.shading { - * background-color: rgba(128, 128, 128, 0.3); - * border: solid 2px #0090b7; - * width: 5px; - * } - * ``` - * Once instantiated, it can be displayed or hidden by simply setting the `rangeSlider` parameter - * of the primary chart's **layout object**, and then issuing a layout change event to trigger the - * new status. Make sure to use the callback to enable the slider on initial load to prevent - * "out of sequence" issues. See examples for exact syntax. - * - * Remember, a range slider is simply just another chart. So you configure it and customize it - * using the same parameters as you would the primary chart. The only difference is that the - * slider object will be a sub element of the primary chart, living inside the `slider.slider` - * object. - * - * For example, if you wanted to turn off the x-axis on the slider, assuming a chart instantiated - * as `stxx`, you would execute: - * ``` - * stxx.slider.slider.xaxisHeight = 0; - * ``` - * - * If using chartIQ web components, the slider needs to be created **before** the UI manager - * (startUI) is called for custom themes to apply. - * - * It is important to note that the range slider chart container will create itself **under** the - * primary chart container, not **inside**. As such, to ensure styling is shared between the two - * containers and they match in look and feel, all the styling must be on a parent `div` container - * rather than the primary chart container itself. - * - * For example, do this: - * ``` - *

- *
- *
- *
- * - *
- *
- *
- * ``` - * - * Not this: - * ``` - *
- *
- *
- *
- *
- * ``` - * - * Range slider working example: - * - * - * @param {object} params Configuration parameters. - * @param {CIQ.ChartEngine} [params.stx] The chart object. - * @param {number} [params.height="95px"] Height of the range slider panel. Must include a CSS - * unit, such as "px". - * @param {object} [params.yAxis] Y-axis parameters. - * @param {number} [params.chartContainer] Handle to the main chart container. Defaults to - * `stxx.container`. - * @param {string} [params.menuContextClass] A CSS class name used to query the menu DOM element - * that contains the UI control for the range slider add-on. In a multi-chart document, the - * add-on is available only on charts that have a menu DOM element with the value for - * `menuContextClass` as a class attribute. - * - * @constructor - * @name CIQ.RangeSlider - * @since - * - 4.0.0 - * - 6.1.0 Added `params.yAxis`. - * - 8.0.0 Added `params.menuContextClass`. - * - * @example - * - * Create a range slider and enable it by default using the loadChart callback. - * - * const stxx = new CIQ.ChartEngine({ container: document.querySelector(".chartContainer") }); - * - * stxx.attachQuoteFeed(quoteFeedSimulator,{ refreshInterval: 1, bufferSize: 200 }); - * - * // Instantiate a range slider. - * new CIQ.RangeSlider({ stx: stxx }); - * - * function displayChart(){ - * stxx.loadChart("SPY", null, function() { - * // For smoother visualization, enable after the main chart has completed loading its data. - * stxx.layout.rangeSlider = true; // Show the slider. - * stxx.changeOccurred("layout"); // Signal the change to force a redraw. - * }); - * } - * - * @example - * - * Create a range slider and enable/disable it using commands to be triggered from a menu. - * - * const stxx = new CIQ.ChartEngine({ container: document.querySelector(".chartContainer") }); - * - * // Instantiate a range slider. - * new CIQ.RangeSlider({ stx: stxx }); - * - * // To display the slider from a menu use: - * stxx.layout.rangeSlider = true; // Show the slider. - * stxx.changeOccurred("layout"); // Signal the change to force a redraw. - * - * // To hide the slider from a menu use: - * stxx.layout.rangeSlider = false; // Hide the slider. - * stxx.changeOccurred("layout"); // Signal the change to force a redraw. - */ -CIQ.RangeSlider = - CIQ.RangeSlider || - function (params) { - this.cssRequired = true; - - var stx = params.stx; - stx.slider = this; - var sliderHeight = params.height ? params.height : "95px"; - var chartContainer = params.chartContainer - ? params.chartContainer - : params.stx.container; - - var ciqSlider = document.createElement("div"); - ciqSlider.className = "ciq-chart"; - var sliderContainer = document.createElement("div"); - sliderContainer.className = "chartContainer"; - ciqSlider.appendChild(sliderContainer); - chartContainer.parentElement.parentElement.insertBefore( - ciqSlider, - chartContainer.parentElement.nextSibling - ); - Object.assign(ciqSlider.style, { - height: sliderHeight, - paddingTop: "5px", - display: "none" - }); - sliderContainer.style.height = "100%"; - sliderContainer.dimensionlessCanvas = true; - var self = (this.slider = new CIQ.ChartEngine({ - container: sliderContainer, - preferences: { labels: false, whitespace: 0 } - })); - self.xaxisHeight = 30; - self.manageTouchAndMouse = false; - self.minimumCandleWidth = 0; - self.chart.panel.subholder.style.cursor = "ew-resize"; - var yAxis = self.chart.panel.yAxis; - yAxis.drawCurrentPriceLabel = false; - Object.defineProperty(yAxis, "position", { - get: function () { - return stx.slider.yAxisPosition || stx.chart.panel.yAxis.position; - }, - set: function (position) { - stx.slider.yAxisPosition = position; - } - }); - const { get, set } = Object.getOwnPropertyDescriptor( - CIQ.ChartEngine.YAxis.prototype, - "width" - ); - Object.defineProperty(yAxis, "width", { - get: function () { - return Math.max(get.call(yAxis), stx.chart.yAxis.width); - }, - set: function (width) { - set.call(yAxis, width); - } - }); - CIQ.extend(yAxis, params.yAxis); - self.chart.baseline.userLevel = false; - if (self.controls.home) self.controls.home.style.width = 0; - self.initializeChart(); - var subholder = self.chart.panel.subholder; - - /** - * Dynamically updates the styling of the range slider. - * - * This method can be used to update CSS styles if you are injecting stylesheets using - * JavaScript. - * - * @param {string} obj The CSS selector for which a style property is changed. - * @param {string} attribute The style property changed in the CSS selector rule-set. - * @param {string} value The value to apply to the CSS property. - * - * @alias updateStyles - * @memberof CIQ.RangeSlider.prototype - * @since 8.0.0 - * - * @example - * // Set the shading of the range slider. - * stxx.slider.updateStyles( - * 'stx_range_slider shading', - * 'backgroundColor', - * 'rgba(200, 50, 50, 0.45)' - * ); - * - * @example - * // Set the color of the bars of the range slider to red. - * stxx.slider.updateStyles( - * 'stx_range_slider shading', - * 'borderTopColor', - * 'rgba(255, 0, 0)' - * ); - */ - this.updateStyles = function (obj, attribute, value) { - stx.setStyle(obj, attribute, value); - this.style = stx.canvasStyle("stx_range_slider shading"); - }; - - this.display = function (on) { - if (stx.layout.rangeSlider !== on) { - // do this the way it was intended - stx.layout.rangeSlider = on; - stx.changeOccurred("layout"); - return; - } - ciqSlider.style.display = on ? "" : "none"; - stx.resizeChart(); - window.dispatchEvent(new Event("resize")); - if (!on) return; - self.resizeChart(); - self.initializeChart(); - self.draw(); - this.drawSlider(); - }; - this.setSymbol = function (symbol) { - self.chart.panel.display = self.chart.symbol = symbol; - self.setMainSeriesRenderer(); - self.resizeChart(); - this.adjustRange(stx.chart); - self.draw(); - this.drawSlider(); - }; - this.acceptLayoutChange = function (layout) { - var doDraw = false; - if (self.layout.rangeSlider !== layout.rangeSlider) { - stx.slider.display(layout.rangeSlider); - } - var relevantLayoutPropertiesForRedraw = [ - "chartType", - "aggregationType", - "periodicity", - "interval", - "timeUnit", - "chartScale", - "rangeSlider", - "flipped", - "extended", - "marketSessions", - "kagi", - "rangebars", - "renko", - "priceLines", - "pandf" - ]; - relevantLayoutPropertiesForRedraw.forEach(function (x) { - if (!CIQ.equals(self.layout[x], layout[x])) { - self.layout[x] = layout[x]; - doDraw = true; - } - }); - if (!CIQ.trulyVisible(ciqSlider)) return; - if (doDraw) { - self.setMainSeriesRenderer(); - self.draw(); - this.drawSlider(); - } - }; - this.adjustRange = function (chart) { - if (!chart.dataSet) return; - if (!chart.endPoints || !chart.endPoints.begin) return; - var myChart = self.chart; - if (!myChart.width) return; - var scrollOffset = 0, - ticksOffset = 0; - if (stx.quoteDriver) { - var behaviorParams = { - symbol: chart.symbol, - symbolObject: chart.symbolObject, - interval: stx.layout.interval - }; - if ( - (behaviorParams.interval == "month" || - behaviorParams.interval == "week") && - !stx.dontRoll - ) { - behaviorParams.interval = "day"; - } - var behavior = stx.quoteDriver.getQuoteFeed(behaviorParams).behavior; - if (behavior && behavior.bufferSize) { - if (chart.moreAvailable) scrollOffset = behavior.bufferSize; - if (stx.isHistoricalMode()) ticksOffset = behavior.bufferSize; - } - } - myChart.baseline.defaultLevel = chart.baseline.actualLevel; - myChart.scroll = - Math.max( - 0, - chart.dataSet.length - - stx.tickFromDate(chart.endPoints.begin) - - scrollOffset - ) + 1; - myChart.maxTicks = myChart.scroll - ticksOffset + 1; - self.layout.candleWidth = myChart.width / myChart.maxTicks; - }; - this.copyData = function (chart) { - if (!chart.dataSet) return; - var myChart = self.chart; - myChart.masterData = self.masterData = chart.masterData; - myChart.dataSet = chart.dataSet; - myChart.state = chart.state; - self.draw(); - this.drawSlider(); - }; - this.calculateYAxisPosition = function () { - var panel = self.chart.panel; - var currentPosition = self.getYAxisCurrentPosition(panel.yAxis, panel); - if (currentPosition != panel.yAxis.position) - self.calculateYAxisPositions(); - }; - this.drawSlider = function () { - if (!CIQ.trulyVisible(ciqSlider)) return; - if (!stx.chart.dataSet || !stx.chart.dataSet.length) return; - var style = this.style; - if (!style) - style = this.style = stx.canvasStyle("stx_range_slider shading"); - var chartPanel = stx.chart.panel, - ctx = self.chart.context, - segmentImage = self.chart.segmentImage || [], - halfCandle = self.layout.candleWidth / 2; - var left = (self.tickLeft = Math.max( - stx.tickFromPixel(chartPanel.left + halfCandle), - 0 - )); - var right = (self.tickRight = Math.min( - stx.tickFromPixel(chartPanel.right - halfCandle), - stx.chart.dataSet.length - 1 - )); - var pLeft = (self.pixelLeft = - self.pixelFromTick(left) - - (segmentImage[left] ? segmentImage[left].candleWidth / 2 : halfCandle)); - var pRight = (self.pixelRight = - self.pixelFromTick(right) + - (segmentImage[right] - ? segmentImage[right].candleWidth / 2 - : halfCandle)); - var leftBoundary = subholder.offsetLeft, - rightBoundary = leftBoundary + subholder.offsetWidth; - ctx.save(); - ctx.beginPath(); - ctx.fillStyle = style.backgroundColor; - ctx.fillRect( - leftBoundary, - subholder.offsetTop, - pLeft - leftBoundary, - subholder.offsetHeight - ); - ctx.fillRect( - rightBoundary, - subholder.offsetTop, - pRight - rightBoundary, - subholder.offsetHeight - ); - ctx.strokeStyle = style.borderTopColor; - ctx.lineWidth = parseInt(style.borderWidth, 10); - ctx.moveTo(pLeft, subholder.offsetTop); - ctx.lineTo(pLeft, subholder.offsetTop + subholder.offsetHeight); - ctx.moveTo(pRight, subholder.offsetTop); - ctx.lineTo(pRight, subholder.offsetTop + subholder.offsetHeight); - ctx.stroke(); - ctx.beginPath(); - ctx.lineWidth = parseInt(style.width, 10); - ctx.lineCap = "round"; - ctx.moveTo(pLeft, subholder.offsetTop + subholder.offsetHeight / 4); - ctx.lineTo(pLeft, subholder.offsetTop + (3 * subholder.offsetHeight) / 4); - ctx.moveTo(pRight, subholder.offsetTop + subholder.offsetHeight / 4); - ctx.lineTo( - pRight, - subholder.offsetTop + (3 * subholder.offsetHeight) / 4 - ); - ctx.stroke(); - ctx.restore(); - }; - stx.addEventListener("layout", function (obj) { - obj.stx.slider.acceptLayoutChange(obj.stx.layout); - }); - stx.addEventListener("preferences", function (obj) { - const { language } = obj.stx.preferences; - if (CIQ.I18N && self.preferences.language != language) { - CIQ.I18N.setLocale(self, language); - } - self.preferences.language = language; - self.draw(); - }); - stx.addEventListener("symbolChange", function (obj) { - if (obj.action == "master") obj.stx.slider.setSymbol(obj.symbol); - }); - stx.addEventListener("symbolImport", function (obj) { - if (obj.action == "master") obj.stx.slider.setSymbol(obj.symbol); - obj.stx.slider.acceptLayoutChange(obj.stx.layout); - }); - stx.addEventListener("theme", function (obj) { - self.clearPixelCache(); - self.styles = {}; - self.chart.container.style.backgroundColor = ""; - if (CIQ.ThemeHelper) { - var helper = new CIQ.ThemeHelper({ stx: obj.stx }); - helper.params.stx = self; - helper.update(); - } - }); - stx.append("createDataSet", function () { - this.slider.adjustRange(this.chart); - this.slider.copyData(this.chart); - }); - stx.append("draw", function () { - if (!CIQ.trulyVisible(ciqSlider)) return; - if (!self.chart.dataSet) return; - this.slider.adjustRange(this.chart); - this.slider.calculateYAxisPosition(); - self.draw(); - this.slider.drawSlider(); - }); - stx.prepend("resizeChart", function () { - var ciqChart = chartContainer.parentElement, - chartArea = ciqChart.parentElement; - var heightOffset = - parseFloat(getComputedStyle(ciqChart).height) - - parseFloat(getComputedStyle(chartContainer).height); - var totalHeightOfContainers = CIQ.elementDimensions(chartArea).height; - var chartContainers = chartArea.querySelectorAll(".chartContainer"); - Array.from(chartContainers).forEach(function (container) { - if (container !== chartContainer && CIQ.trulyVisible(container)) { - totalHeightOfContainers -= CIQ.elementDimensions(container, { - border: 1, - padding: 1, - margin: 1 - }).height; - } - }); - ciqChart.style.height = totalHeightOfContainers + "px"; - if (this.layout.rangeSlider) { - if (self.chart.breakpoint !== this.chart.breakpoint) { - self.notifyBreakpoint(this.chart.breakpoint); - } - ciqSlider.style.display = ""; - self.resizeChart(); - self.initializeChart(); - self.draw(); - this.slider.drawSlider(); - } else { - ciqSlider.style.display = "none"; - } - }); - ["mousedown", "touchstart", "pointerdown"].forEach(function (ev) { - subholder.addEventListener( - ev, - function (e) { - var start = self.backOutX(e.pageX); - if (!start && start !== 0) return; // wrong event - start -= e.target.offsetLeft; - self.startDrag = start; - self.startPixelLeft = self.pixelLeft; - self.startPixelRight = self.pixelRight; - var style = stx.slider.style; - if (!style) - style = stx.slider.style = stx.canvasStyle( - "stx_range_slider shading" - ); - var bw = parseInt(style.borderLeftWidth, 10); - start += this.offsetLeft; - if (start < self.pixelRight - bw) self.needsLeft = true; - if (start > self.pixelLeft + bw) self.needsRight = true; - if (CIQ.touchDevice) return; - if (self.needsLeft && self.needsRight) { - // change to grab only if drag started from viewport - e.target.classList.add("stx-drag-chart"); - } - }, - { passive: false } - ); - }); - ["mouseup", "mouseover", "touchend", "pointerup"].forEach(function (ev) { - subholder.addEventListener(ev, function (e) { - const { which, type } = e; - if (which === 1 && type !== "pointerup" && type !== "mouseup") return; - e.target.classList.remove("stx-drag-chart"); - self.chart.panel.subholder.style.cursor = "ew-resize"; - self.startDrag = null; - self.needsLeft = false; - self.needsRight = false; - }); - }); - ["mousemove", "touchmove", "pointermove"].forEach(function (ev) { - subholder.addEventListener( - ev, - function (e) { - var startDrag = self.startDrag; - if (!startDrag && startDrag !== 0) return; - var touches = e.touches; - var movement = - (touches && touches.length - ? self.backOutX(touches[0].pageX) - : self.backOutX(e.pageX)) - e.target.offsetLeft; - if (!movement && movement !== 0) return; // wrong event - movement -= startDrag; - var tickLeft = self.tickLeft, - tickRight = self.tickRight; - var startPixelLeft = self.startPixelLeft, - startPixelRight = self.startPixelRight; - var needsLeft = self.needsLeft, - needsRight = self.needsRight; - if (needsLeft) { - if (startPixelLeft + movement < self.chart.left) - movement = self.chart.left - startPixelLeft; - if (needsRight && startPixelRight + movement >= self.chart.right) { - movement = self.chart.right - startPixelRight; - if (!self.isHome()) movement += self.layout.candleWidth / 2; // force a right scroll - } - tickLeft = self.tickFromPixel(startPixelLeft + movement); - if (needsRight) - tickRight = tickLeft + self.tickRight - self.tickLeft; - } else if (needsRight) { - tickRight = Math.min( - self.tickFromPixel(startPixelRight + movement), - stx.chart.dataSet.length - 1 - ); - } else return; - - var newCandleWidth = stx.chart.width / (tickRight - tickLeft + 1); - if ( - tickRight >= tickLeft && - newCandleWidth >= stx.minimumCandleWidth - ) { - self.tickLeft = tickLeft; - self.tickRight = tickRight; - stx.chart.scroll = stx.chart.dataSet.length - tickLeft; - if (!needsLeft || !needsRight) { - stx.setCandleWidth(newCandleWidth); - } - stx.micropixels = 0; - stx.draw(); - } - }, - { passive: false } - ); - }); - this.adjustRange(stx.chart); - this.copyData(stx.chart); - }; - -}; - - -let __js_addons_standard_shortcuts_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -/** - * Displays a legend of keyboard shortcuts and the actions the shortcuts perform. - * - * Delegates display of the legend to the - * [cq-floating-window]{@link WebComponents.cq-floating-window} web component by dispatching a - * "floatingWindow" event (see - * [floatingWindowEventListener]{@link CIQ.ChartEngine~floatingWindowEventListener}). - * - * Creates the legend from keyboard shortcut specifications contained in a configuration object; - * for example, the default chart configuration object (see the {@tutorial Chart Configuration} - * tutorial). - * - * Requires *addOns.js*. - * - * @param {object} params The constructor parameters. - * @param {CIQ.ChartEngine} params.stx The chart engine instance for which the keyboard shortcuts - * legend is created. - * @param {object} params.config A configuration object that includes specifications for hot keys - * and drawing tool keyboard shortcuts. Typically, this object is the chart configuration - * object. See the {@tutorial Chart Configuration} tutorial for the data format for keyboard - * shortcuts. - * @param {number} [params.width="580"] The width of the floating window that contains the - * keyboard shortcuts legend. - * @param {boolean} [params.windowForEachChart=true] A flag that indicates whether each chart - * instance in a multi-chart document has its own keyboard shortcuts legend. If false, all - * charts share the same legend. - * - * @constructor - * @name CIQ.Shortcuts - * @since 8.2.0 - * - * @example - * new CIQ.Shortcuts( - * stx: stxx, - * config: { - * drawingTools: [{ label: "line", shortcut: "l" }], - * hotkeyConfig: { - * hotkeys: [{ label: "Pan chart up", action: "up", commands: ["ArrowUp", "Up"] }] - * } - * } - * ); - */ -CIQ.Shortcuts = - CIQ.Shortcuts || - function ({ stx, width = 580, windowForEachChart = true, config } = {}) { - if (!stx) { - console.warn("The Shortcuts addon requires an stx parameter"); - return; - } - /** - * The chart engine instance for which the keyboard shortcuts legend is created. - * - * @type {CIQ.ChartEngine} - * @memberof CIQ.Shortcuts# - * @alias stx - * @since 8.2.0 - */ - this.stx = stx; - /** - * Width of the floating window that contains the keyboard shortcuts legend. - * - * @type {number} - * @memberof CIQ.Shortcuts# - * @alias width - * @since 8.2.0 - */ - this.width = width; - /** - * In a multi-chart document, indicates whether each chart has its own keyboard shortcuts - * legend. If false, all charts share the same legend. - * - * @type {boolean} - * @memberof CIQ.Shortcuts# - * @alias windowForEachChart - * @since 8.2.0 - */ - this.windowForEachChart = windowForEachChart; - this.content = this.getShortcutContent(config); - this.enclosingContainer = stx.container.querySelector(".stx-subholder"); - - this.ensureMessagingAvailable(stx); - this.enableUI(stx); - this.cssRequired = true; - - stx.shortcuts = this; - }; - -/** - * Enables the keyboard shortcuts legend user interface. - * - * Adds a `showShortCuts` function to the {@link CIQ.UI.Layout} helper. The `showShortCuts` - * function calls this class's [toggle]{@link CIQ.Shortcuts#toggle} function to show and hide the - * keyboard shortcuts legend. Call `showShortCuts` in your application's user interface (see - * example). - * - * This function is called when the add-on is instantiated. - * - * @param {CIQ.ChartEngine} stx The chart engine that provides the UI context for the keyboard - * shortcuts legend. - * - * @memberof CIQ.Shortcuts - * @since 8.2.0 - * - * @example Create a button that shows and hides the keyboard shortcuts legend. - * - */ -CIQ.Shortcuts.prototype.enableUI = function (stx) { - if (!(stx && CIQ.UI)) return; - setTimeout(() => { - const layout = stx.uiContext.getAdvertised("Layout"); - layout.showShortcuts = (node, value) => this.toggle(value); - }); -}; - -/** - * Ensures that an instance of the [cq-floating-window]{@link WebComponents.cq-floating-window} - * web component is available to handle event messaging and create the shortcuts legend floating - * window. - * - * This function is called when the add-on is instantiated. - * - * @param {CIQ.ChartEngine} stx The chart engine that provides the UI context, which contains the - * [cq-floating-window]{@link WebComponents.cq-floating-window} web component. - * - * @memberof CIQ.Shortcuts - * @since 8.2.0 - */ -CIQ.Shortcuts.prototype.ensureMessagingAvailable = function (stx) { - setTimeout(() => { - const contextContainer = stx.uiContext.topNode; - if (!contextContainer.querySelector("cq-floating-window")) { - contextContainer.append(document.createElement("cq-floating-window")); - } - }); -}; - -/** - * Creates the contents of the keyboard shortcuts legend based on specifications contained in a - * configuration object. The contents are displayed in a - * [cq-floating-window]{@link WebComponents.cq-floating-window} web component. - * - * This function is called when the add-on is instantiated. - * - * @param {object} config A configuration object that includes specifications for drawing tool - * keyboard shortcuts and hot keys. Typically, this object is the chart configuration object - * (see the {@tutorial Chart Configuration} tutorial). - * @return {string} The keyboard shortcuts legend as HTML. - * - * @memberof CIQ.Shortcuts - * @since 8.2.0 - */ -CIQ.Shortcuts.prototype.getShortcutContent = function (config) { - const drawingToolShortcuts = (config.drawingTools || []) - .filter((tool) => tool.shortcut) - .map( - ({ label, shortcut }) => - `
-
${label}
-
Alt + ${shortcut.toUpperCase()}
-
` - ) - .join(""); - - // Alt + key combination produces unpredictable accent characters depending on keyboard mapping - // default hotkeys include them for better coverage, avoid displaying them in legend - const isAscii = (str) => str.charCodeAt(str.length - 1) < 127; - const wrapKeys = (str) => - str === " + " - ? "+" - : str - .split("+") - .map((el) => (el && el !== " " ? "" + el + "" : "")) - .join(" + "); - - const commandsToString = (commands) => { - return commands - .map((command) => command.replace(/Arrow|Key|Digit|^ | $/g, "")) - .map((command) => command.replace(/\+/, " + ")) - .reduce( - (acc, command) => - !acc.includes(command) && isAscii(command) - ? acc.concat(command) - : acc, - [] - ) - .map(wrapKeys) - .join("
"); - }; - - const container = this.stx.container.closest("cq-context"); - const extensionAvailable = (name) => - container.hasAttribute(name.toLowerCase() + "-active"); - const hotkeys = ((config.hotkeyConfig && config.hotkeyConfig.hotkeys) || []) - .map(({ label, action, commands, extension }) => { - if (extension && !extensionAvailable(extension)) { - return ""; - } - return `
${ - label || action - }
${commandsToString(commands)}
`; - }) - .join(""); - - return ` -
-
-
Drawing tools shortcuts
-
${drawingToolShortcuts}
-
-
-
-
Hotkeys
-
${hotkeys}
-
-
- `; -}; - -/** - * Opens and closes the floating window that contains the keyboard shortcuts legend. - * - * @param {boolean} [value] If true, the window is opened. If false, the window is closed. - * If not provided, the window state is toggled. That is, the window is opened if it is - * currently closed; closed, if it is currently open. - * - * @memberof CIQ.Shortcuts - * @since 8.2.0 - */ -CIQ.Shortcuts.prototype.toggle = function (value) { - this.stx.dispatch("floatingWindow", { - type: "shortcut", - title: "Shortcuts", - content: this.content, - container: this.enclosingContainer, - onClose: () => (this.closed = true), - width: this.width, - status: value, - tag: this.windowForEachChart ? undefined : "shortcut" - }); -}; - -}; - - -let __js_addons_standard_tableView_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -/** - * Creates an overlay that displays the visible chart data segment as a table. - * - * The overlay includes controls that enable users to copy the table data to the clipboard or - * download the data as a character-separated values (CSV) file. See - * {@link TableViewBuilder.dataToCsv} for the default separator character. - * - * The table view can be opened using the Alt+K keystroke combination and closed using the Escape - * key (see the `tableView` action in `hotkeyConfig.hotkeys` in *js/defaultConfiguration.js*). - * - * Requires *addOns.js*. - * - * @param {object} params Configuration parameters. - * @param {CIQ.ChartEngine} params.stx A reference to the chart engine that contains the chart for - * which the table view is created. - * @param {string} [params.minColumnWidth="84px"] The minimum width (including units) of the - * table columns. **Note:** The units can be any CSS unit acceptable by the CSS `calc` - * function. - * @param {number} [params.coverUIMaxWidth=400] The chart width (in pixels) below which the table - * view covers the entire chart, including user interface elements (symbol input field, - * menus, etc.). For example, if the value of this parameter is 1000, the table view covers - * the entire chart area if the chart width is <= 999 pixels. - * @param {string} [params.coverContainer] A CSS selector used to obtain the DOM element that - * ultimately contains the table view; for example, ".chartContainer". - * @param {boolean} [params.usePreviousCloseForChange=true] Indicates whether the closing price of - * the previous data point should be used instead of the opening price of the current data - * point to determine the amount of change for the current data point; that is, - * (current close - previous close) or (current close - current open). - * - * @constructor - * @name CIQ.TableView - * @since 8.1.0 - * - * @example - * new CIQ.TableView({ stx: stxx }); - */ -CIQ.TableView = - CIQ.TableView || - function ({ - stx, - minColumnWidth = "84px", - coverUIMaxWidth = 400, - coverContainer, - usePreviousCloseForChange = true - } = {}) { - if (!stx) { - console.warn("The TableView addon requires an stx parameter"); - return; - } - - /** - * The chart engine instance that contains the chart for which the table view is created. - * - * @type CIQ.ChartEngine - * @memberof CIQ.TableView# - * @alias stx - * @since 8.1.0 - */ - this.stx = stx; - /** - * Toggle to display and hide additional table view columns, such as % Change and Volume. - * - * **Note:** Data in the additional columns might not be present in the chart view because - * the data is calculated (for example, % Change) or is not part of the standard chart - * display (for example, Volume — which can be displayed with the - * [Volume Chart]{@link CIQ.Studies.createVolumeChart} study). - * - * @type boolean - * @memberof CIQ.TableView# - * @alias viewAdditionalColumns - * @since 8.1.0 - */ - this.viewAdditionalColumns = false; - /** - * Minimum width of the table view columns, including units. The units can be any CSS - * unit acceptable by the CSS `calc` function. - * - * @type string - * @memberof CIQ.TableView# - * @alias minColumnWidth - * @since 8.1.0 - */ - this.minColumnWidth = minColumnWidth; - /** - * The chart width in pixels below which the table view covers the entire chart, including - * user interface elements, such as the menus and footer. - * - * @type number - * @memberof CIQ.TableView# - * @alias coverUIMaxWidth - * @since 8.1.0 - */ - this.coverUIMaxWidth = coverUIMaxWidth; - /** - * A CSS selector used to obtain the DOM element that hosts the table view. - * - * @type string - * @memberof CIQ.TableView# - * @alias coverContainer - * @since 8.1.0 - */ - this.coverContainer = coverContainer; - /** - * If true, the closing price of the previous data point is used instead of the opening - * price of the current data point to determine the amount of change for the current data - * point. - * - * @type boolean - * @memberof CIQ.TableView# - * @alias usePreviousCloseForChange - * @since 8.1.0 - */ - this.usePreviousCloseForChange = usePreviousCloseForChange; - /** - * A reference to the {@link TableViewBuilder} namespace for access to the namespace - * static methods. - * - * @type TableViewBuilder - * @memberof CIQ.TableView# - * @alias builder - * @since 8.1.0 - */ - this.builder = TableViewBuilder; - - this.listeners = []; - - stx.tableView = this; - this.cssRequired = true; - - if (CIQ.UI) { - CIQ.UI.observeProperty("uiContext", stx, ({ value: uiContext }) => { - if (!uiContext) return; - - setTimeout(() => { - this.subscribeToChanges(uiContext); - - // Updated hotkey alias if available to action - const tableViewKeyEntry = CIQ.getFromNS( - uiContext.config, - "hotkeyConfig.hotkeys", - [] - ).find(({ action }) => action === "tableView"); - if (tableViewKeyEntry) { - tableViewKeyEntry.action = () => { - const { tableView } = document.body.keystrokeHub.context.stx; - if (tableView) { - tableView.toggle(); - return true; - } - }; - } - }); - }); - } - }; - -/** - * Displays the table view. - * - * @param {object} [params] Configuration parameters. - * @param {object} [params.config] Table column information. - * @param {function} [params.onClose] Callback function to execute on closing the table view. The - * callback enables synchronization of state in the application when the table view is - * closed. - * - * @memberof CIQ.TableView - * @since 8.1.0 - */ -CIQ.TableView.prototype.open = function (params) { - if (params) { - this.params = params; - } - const { config = {}, onClose } = this.params || {}; - if (this.view) { - this.close(false); - } - config.minColumnWidth = this.minColumnWidth; - config.coverUIMaxWidth = this.coverUIMaxWidth; - config.coverContainer = this.coverContainer; - this.onClose = onClose; - this.view = this.builder.createTable(this.stx, config); - if (!this.view) return; - if (CIQ.I18N) CIQ.I18N.translateUI(null, this.view); - const { stx } = this; - const close = this.close.bind(this); - - setTimeout(() => (this.removeCloseListener = getCloseListener(this))); - - const scrollbarStyling = CIQ.getFromNS( - stx, - "uiContext.config.scrollbarStyling" - ); - if (scrollbarStyling) { - scrollbarStyling.refresh(this.view.querySelector("tbody")); - scrollbarStyling.refresh( - this.view.querySelector(".ciq-data-table-wrapper"), - { suppressScrollY: true } - ); - } - - function getCloseListener(self) { - const contextNode = stx.uiContext.topNode; - const withinTable = (el) => el.closest(".ciq-data-table-container"); - - const closeHandler = ({ target }) => !withinTable(target) && close(); - contextNode.addEventListener("click", closeHandler); - const handleKeydown = (e) => { - if (e.code === "Escape") { - const { tableView } = document.body.keystrokeHub.context.stx; - if (tableView) { - tableView.close(); - e.preventDefault(); - } - } - }; - document.body.addEventListener("keydown", handleKeydown); - - // Use modal functionality available in menu - const uiManager = CIQ.getFn("UI.getUIManager")(); - if (uiManager) { - // Menu item requires show and hide providing no-op functions - self.view.show = self.view.hide = function () {}; - uiManager.openMenu(self.view, {}); - } - return () => { - contextNode.removeEventListener("click", closeHandler); - document.body.removeEventListener("keydown", handleKeydown); - if (uiManager) uiManager.closeMenu(self.view); - }; - } -}; - -/** - * Closes the table view. - * - * @param {boolean} [notify=true] Indicates whether the `onClose` callback function is set (see - * [open]{@link CIQ.TableView#open}). - * - * @memberof CIQ.TableView - * @since 8.1.0 - */ -CIQ.TableView.prototype.close = function (notify = true) { - if (this.view) { - this.view.remove(); - this.view = null; - } - if (notify && this.onClose) { - this.onClose(); - } - - if (this.removeCloseListener) { - this.removeCloseListener(); - this.removeCloseListener = null; - } -}; - -/** - * Opens the table view if it is closed. Closes the table view if it is open. - * - * @memberof CIQ.TableView - * @since 8.1.0 - */ -CIQ.TableView.prototype.toggle = function () { - this[this.view ? "close" : "open"](); -}; - -/** - * Subscribes to changes in the table view component communication channel, which enables other - * components to open and close the table view. - * - * @param {CIQ.UI.Context} uiContext The user interface context of the table view. Provides the - * communication channel path that identifies the table view channel. - * @param {string} [channelPath] Specifies the channel path if the path is not available in the - * context configuration provided by `uiContext`. - * - * @memberof CIQ.TableView - * @since 8.1.0 - */ -CIQ.TableView.prototype.subscribeToChanges = function ( - uiContext, - channelPath = "channels.tableView" -) { - const { channelSubscribe, channelWrite } = CIQ.UI.BaseComponent.prototype; - const { channels: { tableView = channelPath } = {} } = uiContext.config || {}; - const { stx } = this; - - channelSubscribe( - tableView, - (value) => { - if (value) { - stx.tableView.open({ - onClose: () => { - channelWrite(tableView, false, stx); - } - }); - } else { - stx.tableView.close(); - } - }, - stx - ); -}; - -/** - * Namespace for {@link CIQ.TableView} creation–related properties and functions. - * - * @namespace - * @name TableViewBuilder - * @since 8.1.0 - */ -function TableViewBuilder() {} - -/** - * The column header configuration for the table view. - * - * Can be used for rearranging the column order, removing columns, and updating labels. - * - * **Note:** Adding new columns has no effect. - * - * @type Object. - * @memberof TableViewBuilder - * @since 8.1.0 - */ -TableViewBuilder.colHeaders = { - date: { label: "Date" }, - open: { label: "Open" }, - high: { label: "High" }, - low: { label: "Low" }, - close: { label: "Close" }, - pctChange: { label: "% Change", cls: "ciq-extra" }, - pctChangeVsAvg: { label: "% Change vs Average", cls: "ciq-extra" }, - volume: { label: "Volume", cls: "ciq-extra" } -}; - -/** - * Number of decimal places to display for percent formatted columns - * - * @type number - * @memberof TableViewBuilder - * @since 8.1.0 - */ -TableViewBuilder.percentDecimalPlaces = 2; - -/** - * Creates a table view as an HTMLElement overlay over a chart container. The table view displays - * a snapshot of the visible chart data segment. - * - * The overlay contains buttons for copying and saving the table data and for displaying - * additional table columns. - * - * @param {CIQ.ChartEngine} stx A reference to the chart engine that contains the chart for which - * the table view is created. - * @param {object} [config] Configuration parameters. - * @param {function} [config.dateFormatter] Formats table date fields. - * @param {function} [config.valueFormatter] Formats table values. - * @param {function} [config.volumeFormatter] Formats the table volume field. - * @param {function} [config.fileNameFormatter] Formats the name of the file that contains the - * downloaded table data. - * @param {string} [config.minColumnWidth="84px"] The minimum width (including units) of the - * table columns. **Note:** The units can be any CSS unit acceptable by the CSS `calc` - * function. - * @return {HTMLElement} - * - * @memberof TableViewBuilder - * @since 8.1.0 - */ -TableViewBuilder.createTable = function (stx, config = {}) { - if (!stx.chart || !stx.chart.dataSegment) return; - - const { builder } = stx.tableView; - const { - getChartData, - dataToHtml, - dataToCsv, - downloadCsv, - getDateFormatter, - getValueFormatter, - getVolumeFormatter, - getFilenameFormatter, - getSeriesDataNames, - getStudyDataNames, - getChartCover - } = builder; - - const colHeaders = Object.assign({}, this.colHeaders); - - if (!stx.chart.highLowBars) { - delete colHeaders.open; - delete colHeaders.high; - delete colHeaders.low; - } - - if (!stx.tableView.viewAdditionalColumns) { - for (let key in colHeaders) { - if (colHeaders[key].cls) { - delete colHeaders[key]; - } - } - } - - const labels = Object.values(colHeaders).map((item) => item.label); - - const seriesNames = getSeriesDataNames(stx); - seriesNames.forEach((item) => (colHeaders[item] = { label: item })); - - const studyNames = getStudyDataNames(stx); - studyNames.forEach((item) => { - if (!labels.includes(item)) colHeaders[item] = { label: item }; - }); - - const additionalDataFields = seriesNames.concat(studyNames); - - const { - dateFormatter = getDateFormatter(stx), - valueFormatter = getValueFormatter(stx), - percentFormatter = getValueFormatter(stx, this.percentDecimalPlaces), - volumeFormatter = getVolumeFormatter(stx), - fileNameFormatter = getFilenameFormatter(stx), - minColumnWidth = "84px" - } = config; - - const arr = getChartData(stx, { - dateFormatter, - valueFormatter, - percentFormatter, - volumeFormatter, - additionalDataFields - }); - - const cover = getChartCover(stx, config); - const { symbolDisplay, symbol } = stx.chart; - - const toolbar = builder.getCoverToolbar({ - symbol: symbolDisplay || symbol, - viewAdditionalColumns: stx.tableView.viewAdditionalColumns, - copyFn, - downloadFn, - toggleAdditionalColumnsFn: () => { - const { tableView } = stx; - tableView.viewAdditionalColumns = !tableView.viewAdditionalColumns; - tableView.open(); - }, - closeFn: () => stx.tableView.close() - }); - cover.appendChild(toolbar); - const htmlTable = dataToHtml(arr, { colHeaders, minColumnWidth }); - cover.appendChild(htmlTable); - - return cover; - - function copyFn() { - const contentEl = document.createElement("textArea"); - document.body.appendChild(contentEl); - contentEl.textContent = dataToCsv(arr, { colHeaders }); - contentEl.select(); - document.execCommand("copy"); - contentEl.remove(); - stx.dispatch("notification", "copytoclipboard"); - } - - function downloadFn() { - const csvData = dataToCsv(arr, { colHeaders }); - const fileName = fileNameFormatter(csvData); - downloadCsv(csvData, fileName); - } -}; - -/** - * Creates an HTML table containing the chart data and column headers (see - * {@link TableViewBuilder.colHeaders}). - * - * @param {object[]} data The chart data. - * @param {object} params Configuration parameters. - * @param {Object.} params.colHeaders The column - * headers as defined in {@link TableViewBuilder.colHeaders}. - * @param {string} [params.minColumnWidth] The minimum width of the table columns, including units. - * **Note:** The units can be any CSS unit acceptable by the CSS `calc` function. - * @return {HTMLElement} A table containing the chart data and column headers. - * - * @memberof TableViewBuilder - * @since 8.1.0 - */ -TableViewBuilder.dataToHtml = function (data, { colHeaders, minColumnWidth }) { - const keyLength = Object.keys(colHeaders).length; - const colWidth = `calc((100% - ${10 + keyLength * 4}px ) / ${keyLength})`; - const tableHeader = Object.entries(colHeaders).map(([, { label }], index) => { - return `${label.replace("(", " (")}`; - }); - - const tableRows = data.map((row) => { - const htmlRow = Object.keys(colHeaders) - .map((key, index) => { - const value = row[key]; - return index === 0 - ? `${value}` - : `${value}`; - }) - .join(""); - return `${htmlRow}`; - }); - - const tableWrapper = document.createElement("div"); - tableWrapper.classList.add("ciq-data-table-wrapper"); - const minWidth = minColumnWidth - ? `calc(${keyLength} * ${minColumnWidth})` - : ""; - tableWrapper.innerHTML = ` - - ${tableHeader.join("")} - ${tableRows.join("")} -
`; - return tableWrapper; -}; - -/** - * Transforms the chart data into a character-separated values (CSV) file, including column headers. - * - * @param {object[]} data The chart data. - * @param {object} params Configuration parameters. - * @param {Object.} params.colHeaders The column - * headers as defined in {@link TableViewBuilder.colHeaders}. - * @param {string} params.colSeparator="\t" The column separator for the CSV format. - * @return {string} The column headers and chart data as a CSV file. - * - * @memberof TableViewBuilder - * @since 8.1.0 - */ -TableViewBuilder.dataToCsv = function ( - data, - { colHeaders, colSeparator = "\t" } -) { - const tableHeader = Object.entries(colHeaders) - .map(([, { label }]) => `"${label}"`) - .join(colSeparator); - - const tableRows = data.map((row) => { - return Object.keys(colHeaders) - .map((key) => `"${row[key]}"`) - .join(colSeparator); - }); - - return `${tableHeader}\n${tableRows.join("\n")}`; -}; - -/** - * Downloads the table view as a character-separated values (CSV) file. - * - * @param {string} csvString The table view in the form of character-separated data. - * @param {string} filename The name given to the download file. - * - * @memberof TableViewBuilder - * @since 8.1.0 - */ -TableViewBuilder.downloadCsv = function (csvString, filename = "filename") { - const blob = new Blob([csvString], { type: "text/csv;charset=utf-8;" }); - - const a = document.createElement("a"); - a.href = window.URL.createObjectURL(blob, { type: "text/plain" }); - a.download = `${filename}.csv`; - a.style.display = "none"; - document.body.appendChild(a); - a.click(); - document.body.removeChild(a); -}; - -/** - * Extracts OHLC (open, high, low, close) data from the chart. - * - * @param {CIQ.ChartEngine} stx A reference to the chart engine that contains the chart from which - * the data is extracted. - * @param {object} params Configuration parameters. - * @param {function} [params.dateFormatter] Formats date fields. - * @param {function} [params.valueFormatter] Formats OHLC and other values. - * @param {function} [params.percentFormatter] Formats percent fields. - * @param {function} [params.volumeFormatter] Formats the volume field. - * @param {string[]} [params.additionalDataFields] An array of additional data field names for - * comparison series and study data. - * @return {object[]} The formatted chart data. - * - * @memberof TableViewBuilder - * @since 8.1.0 - */ -TableViewBuilder.getChartData = function ( - stx, - { - dateFormatter, - valueFormatter, - percentFormatter, - volumeFormatter, - additionalDataFields - } -) { - const data = stx.chart.dataSegment.filter((item) => item !== null); - const { usePreviousCloseForChange } = stx.tableView; - let out = []; - let length = 0; - const avgPctChange = - data.reduce((acc, { Close, iqPrevClose, Open }) => { - const Base = usePreviousCloseForChange ? iqPrevClose : Open; - if ( - typeof Close === "undefined" || - Number.isNaN(Close) || - typeof Base === "undefined" || - Number.isNaN(Base) - ) { - return acc; - } - length++; - return acc + (Close - Base) / Base; - }, 0) / length; - data.forEach((item, index) => { - const { - DT, - displayDate, - High, - Low, - Open, - Close, - iqPrevClose, - Volume - } = item; - const Base = usePreviousCloseForChange ? iqPrevClose : Open; - const pctChange = (Close - Base) / Base; - const date = - displayDate || - (stx.displayZone - ? CIQ.convertTimeZone(DT, stx.dataZone, stx.displayZone) - : DT); - const obj = { - DT, - date: dateFormatter(date), - open: valueFormatter(Open), - close: valueFormatter(Close), - change: valueFormatter(Close - Base), - pctChange: percentFormatter(pctChange * 100), - pctChangeVsAvg: percentFormatter((pctChange - avgPctChange) * 100), - high: valueFormatter(High), - low: valueFormatter(Low), - volume: volumeFormatter(Volume) - }; - additionalDataFields.forEach((fieldName) => { - let value = item[fieldName]; - if (value == null) { - obj[fieldName] = ""; - return; - } - if (typeof value === "object") { - value = value.Close; - } - obj[fieldName] = valueFormatter(value); - }); - - out.push(obj); - }); - out.sort((a, b) => b.DT - a.DT); - return out; -}; - -/** - * Creates a function that formats table view date fields. - * - * @param {CIQ.ChartEngine} stx A reference to the chart engine that contains the chart for which - * the date fields are formatted. - * @return {function} A date formatter. - * - * @memberof TableViewBuilder - * @since 8.1.0 - */ -TableViewBuilder.getDateFormatter = function (stx) { - return (dt, panel) => { - if (!dt) return ""; - - return CIQ.displayableDate(stx, stx.chart, dt, true); - }; -}; - -/** - * Creates a function that formats table view value fields. - * - * @param {CIQ.ChartEngine} stx A reference to the chart engine that contains the chart for which - * the value fields are formatted. - * @param {number} [decimalPlaces] Number of decimal places to use, overrides any auto-detection of decimal places in data. - * @return {function} A value formatter. - * - * @memberof TableViewBuilder - * @since 8.1.0 - */ -TableViewBuilder.getValueFormatter = function (stx, decimalPlaces) { - const { - chart: { panel, yAxis }, - layout: { chartScale } - } = stx; - let formatValue; - - if (yAxis.originalPriceFormatter && yAxis.originalPriceFormatter.func) { - formatValue = (value) => - yAxis.originalPriceFormatter.func(stx, panel, value, decimalPlaces); - } else if ( - yAxis.priceFormatter && - chartScale != "percent" && - chartScale != "relative" - ) { - formatValue = (value) => - yAxis.priceFormatter(stx, panel, value, decimalPlaces); - } else { - formatValue = (value) => stx.formatYAxisPrice(value, panel, decimalPlaces); - } - - return (value) => formatValue(value).replace(/^-*0\.0*$/, "0"); // display 0.00 as 0 -}; - -/** - * Creates a function that formats the table view volume field. - * - * @param {CIQ.ChartEngine} stx A reference to the chart engine that contains the chart for which - * the volume field is formatted. - * @return {function} A volume field formatter. - * - * @memberof TableViewBuilder - * @since 8.1.0 - */ -TableViewBuilder.getVolumeFormatter = function (stx) { - return (num) => { - if (num == null) return ""; - - if (stx.internationalizer) { - return stx.internationalizer.priceFormatters[0].format(num); - } - - const num_parts = num.toString().split("."); - num_parts[0] = num_parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ","); - return num_parts[0]; - }; -}; - -/** - * Creates a function that creates and formats a file name from the chart symbol and table view - * data. - * - * @param {CIQ.ChartEngine} stx A reference to the chart engine that contains the chart whose - * symbol and data is included in the file name. - * @return {function} A function that creates and formats a file name. - * - * @memberof TableViewBuilder - * @since 8.1.0 - */ -TableViewBuilder.getFilenameFormatter = function (stx) { - return (csvData) => { - const symbol = stx.chart.symbolDisplay || stx.chart.symbol; - let firstDate, lastDate; - if (csvData) { - const rows = csvData.split("\n"); - if (rows.length > 1) { - [, firstDate = ""] = rows[1].match(/^"([^"]*)"/) || []; - [, lastDate = ""] = rows[rows.length - 1].match(/^"([^"]*)"/) || []; - firstDate = firstDate.replace(/:/g, ".").replace(/\//g, "-"); - lastDate = lastDate.replace(/:/g, ".").replace(/\//g, "-"); - } - } - return `${symbol}${firstDate ? ` (${firstDate} _ ${lastDate})` : ""}`; - }; -}; - -/** - * Creates and attaches an HTML container element to the DOM. The element covers the chart and - * contains the table view. - * - * @param {CIQ.ChartEngine} stx A reference to the chart engine that contains the chart over which - * the cover is placed. - * @param {object} params Configuration parameters. - * @param {number} [params.coverUIMaxWidth] The width of the chart (in pixels) below which the - * cover element overlays the entire chart, including user interface elements. - * @param {string} [params.coverContainer] A CSS selector used to obtain the DOM element that - * serves as the parent element of the cover element; for example, ".chartContainer". - * @return {HTMLElement} The cover element. - * - * @memberof TableViewBuilder - * @since 8.1.0 - */ -TableViewBuilder.getChartCover = function ( - stx, - { coverUIMaxWidth, coverContainer } -) { - const parentElement = - (coverContainer && document.querySelector(coverContainer)) || - (stx.uiContext && stx.container.offsetWidth < coverUIMaxWidth - ? stx.uiContext.topNode - : stx.container.parentElement.parentElement); - - const cover = document.createElement("div"); - Object.assign(cover.style, { top: 0, left: 0, right: 0, bottom: 0 }); - - cover.classList.add("ciq-data-table-container"); - parentElement.appendChild(cover); - return cover; -}; - -/** - * Creates a toolbar containing the table title and controls used to copy and download the table - * data and add additional table columns. - * - * @param {object} params Function parameters. - * @param {string} params.symbol An instrument symbol, which is used as the table title in the - * toolbar. Should be the symbol of the chart main series. - * @param {boolean} params.viewAdditionalColumns Toggle that specifies whether the label for the - * additional columns button should indicate that additional columns will be shown or hidden. - * If this parameter is true, the label indicates additional table columns will be shown; if - * false, hidden. - * @param {function} [params.copyFn] Event handler for selection of the copy control. - * @param {function} [params.downloadFn] Event handler for selection of the download control. - * @param {function} [params.toggleAdditionalColumnsFn] Event handler for selection of the - * additional column control. - * @param {function} [params.closeFn] Event handler for selection of the table view close (X) - * control. - * @return {HTMLElement} The toolbar, containing title and controls. - * - * @memberof TableViewBuilder - * @since 8.1.0 - */ -TableViewBuilder.getCoverToolbar = function ({ - symbol, - viewAdditionalColumns, - copyFn, - downloadFn, - toggleAdditionalColumnsFn, - closeFn -}) { - const toolBar = document.createElement("div"); - toolBar.classList.add("ciq-data-table-toolbar"); - toolBar.innerHTML = ` -
- - - - - `; - const titleEl = toolBar.querySelector(".ciq-data-table-title"); - titleEl.textContent = symbol; - - const btnCopy = toolBar.querySelector(".ciq-data-table-copy"); - if (copyFn) { - btnCopy.addEventListener("click", copyFn); - } else { - btnCopy.style.display = "none"; - } - - const btnDownload = toolBar.querySelector(".ciq-data-table-download"); - if (downloadFn) { - btnDownload.addEventListener("click", function () { - btnDownload.blur(); - downloadFn(); - }); - } else { - btnDownload.style.display = "none"; - } - - const btnAdditionalColumns = toolBar.querySelector( - ".ciq-data-table-additionalColumns" - ); - if (toggleAdditionalColumnsFn) { - btnAdditionalColumns.addEventListener("click", toggleAdditionalColumnsFn); - } else { - btnAdditionalColumns.style.display = "none"; - } - - toolBar.close = closeFn; - - return toolBar; -}; - -/** - * Label for the copy button on the table view toolbar. - * - * @type string - * @memberof TableViewBuilder - * @since 8.1.0 - */ -TableViewBuilder.copyLabel = "Copy"; - -/** - * Label for the download button on the table view toolbar. - * - * @type string - * @memberof TableViewBuilder - * @since 8.1.0 - */ -TableViewBuilder.downloadLabel = "Download"; - -/** - * Gets the label of the additional columns button on the table view toolbar. - * - * @param {boolean} viewingAdditionalColumns If this parameter is true, the label should indicate - * additional table columns will be shown; if false, hidden. - * @return {string} The button label. - * - * @memberof TableViewBuilder - * @since 8.1.0 - */ -TableViewBuilder.getAdditionalColumnLabel = function ( - viewingAdditionalColumns -) { - return `${ - viewingAdditionalColumns ? "- " : "+ " - }Additional columns`; -}; - -/** - * Obtains the names of all studies that have data in the chart's visible data segment. - * - * @param {CIQ.ChartEngine} stx A reference to the chart engine that contains the chart studies. - * @return {string[]} The names of all studies that are in the visible portion of the chart. - * - * @memberof TableViewBuilder - * @since 8.1.0 - */ -TableViewBuilder.getStudyDataNames = function (stx) { - return Object.values(stx.layout.studies || {}) - .map(getDataNames) - .reduce((acc, item) => acc.concat(item), []); - - function getDataNames(study) { - return Object.keys(study.outputMap).filter(hasData); - } - - function hasData(name) { - return stx.chart.dataSegment.some((data) => data && data[name]); - } -}; - -/** - * Obtains the symbols of all comparison series that have data in the chart's visible data - * segment. - * - * @param {CIQ.ChartEngine} stx A reference to the chart engine that contains the comparison - * series. - * @return {string[]} The names (symbols) of all comparison series that are in the visible - * portion of the chart. - * - * @memberof TableViewBuilder - * @since 8.1.0 - */ -TableViewBuilder.getSeriesDataNames = function (stx) { - return Object.values(stx.chart.seriesRenderers || {}) - .filter((item) => item.params.name !== "_main_series") - .map((item) => { - return item.seriesParams.map(({ symbol }) => symbol); - }) - .reduce((acc, item) => acc.concat(item), []); -}; - -/** - * CIQ.UI.Context interface placeholder to be augmented in *componentUI.js* with properties. - * - * @tsinterface CIQ.UI~Context - */ - -}; - - -let __js_addons_standard_tooltip_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -if (!CIQ.Marker) { - console.error("tooltip addon requires first activating markers feature."); -} else { - /** - * Add-on that creates a detailed tooltip as the user's mouse hovers over data points on the - * chart. The tooltip contains information such as the open, high, low, and close prices of - * stock quotes. - * - * Tooltip example: - * - * - * **Note:** Prior to version 8.2.0, the tooltip was directly linked to the crosshairs. The - * crosshairs had to be active for the tooltip to be displayed. - * - * Requires *addOns.js* and *markers.js*, or the bundle *standard.js*. - * - * There can be only one `CIQ.Tooltip` per chart. - * - * Color and layout can be customized by overriding the CSS rule-sets defined for the - * `stx-hu-tooltip` and related type selectors in *stx-chart.css*. Do not modify - * *stx-chart.css*; create a separate style sheet file that overrides *stx-chart.css* in the - * CSS cascade. See the example below. - * - * `CIQ.Tooltip` automatically creates its own HTML inside the chart container. Here is an - * example of the structure (there will be one field tag per displayed element): - * ``` - * - * - * - * - * - * - * ``` - * By default, the `stx-hu-tooltip-field` elements are inserted in the following order: - * - DT - * - Open - * - High - * - Low - * - Close - * - Volume - * - series - * - studies - * - * But the default layout can be changed. You can override the order of fields or change the - * labels by manually inserting the HTML that the tooltip would otherwise have created for - * that field. If no override HTML is found for a particular field, the default is used. - * **Note:** This HTML must be placed inside the chart container. - * - * All of the code is provided in *addOns.js* and can be fully customized by copying the - * source code from the library and overriding the functions with your changes. Be sure to - * never modify a library file, as this will hinder upgrades. - * - * For example, concatenating the field name (e.g., "Jaw") with the study name (e.g., - * "Alligator" ) is the default behavior of the tooltip for displaying the value title. Feel - * free to override this behavior by creating your own custom version of the `renderFunction()` - * for the `CIQ.Tooltip`. To do this, copy the entire `CIQ.Tooltip` code (found in *addOns.js*) - * and make the changes to your custom version. Load your custom version instead. Specifically, - * look for the following code in the `renderFunction()` that pushes out the text for each - * study field: - * ``` - * let newFieldName = document.createElement("stx-hu-tooltip-field-name"); - * newFieldName.innerHTML = this.translateIf(fieldName); - * newField.appendChild(newFieldName); - * ``` - * Replace `fieldName` with anything you want to use as the field title and push that instead. - * - * Visual Reference:
- * ![stx-hu-tooltip](stx-hu-tooltip.png "stx-hu-tooltip") - * - * @param {object} tooltipParams The constructor parameters. - * @param {CIQ.ChartEngine} [tooltipParams.stx] The chart object. - * @param {boolean} [tooltipParams.ohl] Set to true to show OHL data (Close is always shown). - * @param {boolean} [tooltipParams.volume] Set to true to show Volume. - * @param {boolean} [tooltipParams.series] Set to true to show value of series. - * @param {boolean} [tooltipParams.studies] Set to true to show value of studies. - * @param {boolean} [tooltipParams.showOverBarOnly] Set to true to show the tooltip only when - * the mouse is over the primary line/bars. - * @param {boolean} [tooltipParams.change] Set to true to show the change in daily value - * when the internal chart periodicity is a daily interval (see - * {@link CIQ.ChartEngine.isDailyInterval}). - * @param {boolean} [tooltipParams.interpolation] Set to true to show the estimated value when - * there is no data between bars. **Note:** A value of `null` is not considered missing - * data. - * @param {boolean} [tooltipParams.useDataZone] Set to true to show the date in the `dataZone` - * time zone; false, to use the `displayZone` time zone (see - * {@link CIQ.ChartEngine#setTimeZone}). - * @param {boolean} [tooltipParams.showBarHighlight=true] Specifies whether the bar (data - * point) the mouse is hovering over is highlighted. Applies to the floating tooltip only - * (the dynamic tooltip points to the bar). If the crosshairs are active, this parameter - * is ignored. - * - * @constructor - * @name CIQ.Tooltip - * @since - * - 09-2016-19 - * - 5.0.0 Now `tooltipParams.showOverBarOnly` is available to show tooltip only when over the - * primary line/bars. - * - 5.1.1 `tooltipParams.change` set to true to show the change in daily value when - * displaying a daily interval. - * - 6.2.5 New `tooltipParams.interpolation` flag to show estimated value for missing series - * data points. - * - 7.0.0 New `tooltipParams.useDataZone` flag to show the date in either the `dataZone` or - * `displayZone` date/time. - * - 8.2.0 Decoupled `CIQ.Tooltip` from the crosshairs and added highlighting of the data - * point (or bar) the mouse is hovering over. The new `tooltipParams.showBarHighlight` - * parameter enables or disables the highlighting. - * - * @example Add a tooltip to a chart: - * // First declare your chart engine. - * const stxx = new CIQ.ChartEngine({ container: document.querySelector(".chartContainer")[0] }); - * - * // Then link the tooltip to that chart. - * // Note how we've enabled OHL, Volume, Series and Studies. - * new CIQ.Tooltip({ stx: stxx, ohl: true, volume: true, series: true, studies: true }); - * - * @example Customize the order, layout, or text in tooltip labels: - * // In this example, we've rearranged the HTML to display the Close field first, then the DT. - * // We are also labeling the DT 'Date/Time' and the Close 'Last'. - * // The rest of the fields are displayed in their default order. - * - * - * - * Last - * - * - * - * Date/Time - * - * - * - * - * @example Customize the CSS for the tooltip (see stx-chart.css): - * stx-hu-tooltip { - * position: absolute; - * left: -50000px; - * z-index: 30; - * white-space: nowrap; - * padding: 6px; - * border: 1px solid gray; - * background-color: rgba(42,81,208,.5); - * color: white; - * } - * - * stx-hu-tooltip-field { - * display:table-row; - * } - * - * stx-hu-tooltip-field-name { - * display:table-cell; - * font-weight:bold; - * padding-right:5px; - * } - * - * stx-hu-tooltip-field-name:after { - * content:':'; - * } - * - * stx-hu-tooltip-field-value { - * display:table-cell; - * text-align:right; - * } - */ - CIQ.Tooltip = - CIQ.Tooltip || - function (tooltipParams) { - if (!CIQ.Marker) { - console.warn( - "CIQ.Tooltip addon requires CIQ.Marker module to be enabled." - ); - return; - } - - this.cssRequired = true; - - const { - stx, - ohl: showOhl, - change: showChange, - volume: showVolume, - series: showSeries, - studies: showStudies, - interpolation: showInterpolation, - showOverBarOnly, - showBarHighlight = true, - useDataZone - } = tooltipParams; - const { container } = stx.chart; - - let node = container.querySelector("stx-hu-tooltip"); - if (!node) { - node = document.createElement("stx-hu-tooltip"); - container.appendChild(node); - } - - let highlightEl = container.querySelector(".stx-hu-tooltip-highlight"); - if (!highlightEl) { - highlightEl = document.createElement("div"); - highlightEl.classList.add("stx-hu-tooltip-highlight"); - container.appendChild(highlightEl); - } - - CIQ.Marker.Tooltip = function (params) { - if (!this.className) this.className = "CIQ.Marker.Tooltip"; - this.highlightEl = highlightEl; - params.label = "tooltip"; - CIQ.Marker.call(this, params); - }; - - CIQ.inheritsFrom(CIQ.Marker.Tooltip, CIQ.Marker, false); - - CIQ.Marker.Tooltip.sameBar = function (bar1, bar2) { - if (!bar1 || !bar2) return false; - if (+bar1.DT != +bar2.DT) return false; - if (bar1.Close != bar2.Close) return false; - if (bar1.Open != bar2.Open) return false; - if (bar1.Volume != bar2.Volume) return false; - return true; - }; - - CIQ.Marker.Tooltip.placementFunction = function (params) { - if (hideIfDisabled()) return; - var offset = 30; - var stx = params.stx; - for (var i = 0; i < params.arr.length; i++) { - var marker = params.arr[i]; - var bar = stx.barFromPixel(stx.cx); - var quote = stx.chart.dataSegment[bar]; - var goodBar; - var overBar = true; - var highPx, lowPx; - - if (quote != "undefined" && quote && quote.DT) { - goodBar = true; - if (quote.High) highPx = stx.pixelFromPrice(quote.High); - if (quote.Low) lowPx = stx.pixelFromPrice(quote.Low); - if (!stx.chart.highLowBars) { - if (quote.Close) { - highPx = stx.pixelFromPrice(quote.Close) - 15; - lowPx = stx.pixelFromPrice(quote.Close) + 15; - } - } - if (showOverBarOnly && !(stx.cy >= highPx && stx.cy <= lowPx)) - overBar = false; - } - - if ( - !( - stx.insideChart && - !stx.openDialog && - !stx.activeDrawing && - !stx.grabbingScreen && - goodBar && - overBar - ) - ) { - highlightEl.style.display = "none"; - marker.node.style.left = "-50000px"; - marker.node.style.right = "auto"; - marker.lastBar = {}; - return; - } - if ( - CIQ.Marker.Tooltip.sameBar( - stx.chart.dataSegment[bar], - marker.lastBar - ) && - bar != stx.chart.dataSegment.length - 1 - ) { - return; - } - - marker.lastBar = stx.chart.dataSegment[bar]; - var cw = marker.lastBar.candleWidth || stx.layout.candleWidth; - if ( - parseInt(getComputedStyle(marker.node).width, 10) + - stx.chart.panel.left + - offset + - cw < - stx.backOutX(CIQ.ChartEngine.crosshairX) - ) { - marker.node.style.left = "auto"; - marker.node.style.right = - Math.round( - container.clientWidth - stx.pixelFromBar(bar) + offset - ) + "px"; - } else { - marker.node.style.left = - Math.round(stx.pixelFromBar(bar) + offset) + "px"; - marker.node.style.right = "auto"; - } - var height = parseInt(getComputedStyle(marker.node).height, 10); - var top = Math.round( - CIQ.ChartEngine.crosshairY - stx.top - height / 2 - ); - if (top + height > stx.height) top = stx.height - height; - if (top < 0) top = 0; - marker.node.style.top = top + "px"; - - if (showBarHighlight && !stx.layout.crosshair) { - const candleWidth = - marker.lastBar.candleWidth || stx.layout.candleWidth; - const left = stx.pixelFromBar(bar) - candleWidth / 2; - let width = candleWidth; - - if (left + width > stx.chart.width) { - // adjust width of last bar so it does not highlight past the edge of the chart into the y axis - width = stx.chart.width - left; - } - - highlightEl.style.display = "block"; - highlightEl.style.left = left + "px"; - highlightEl.style.width = width + "px"; - } else { - highlightEl.style.display = "none"; - } - } - // temporarily disable overXAxis, overYAxis so the crosshairs don't hide if touch device and over Y axis (this can happen - // due to the offset which we apply) - var overXAxis = stx.overXAxis, - overYAxis = stx.overYAxis; - stx.overXAxis = stx.overYAxis = false; - stx.overXAxis = overXAxis; - stx.overYAxis = overYAxis; - }; - - function hideIfDisabled() { - const { headsUp } = stx.layout; - const instantiated = !!stx.huTooltip; - const noLayoutObject = typeof headsUp !== "object"; - const layoutFalse = headsUp === false; // backwards compatibility - const enabled = headsUp && (headsUp === "floating" || headsUp.floating); - - if (instantiated && (!(enabled || noLayoutObject) || layoutFalse)) { - const { huTooltip: tt } = stx; - const { node } = tt || {}; - - if (node) { - node.style.left = "-50000px"; - node.style.right = "auto"; - tt.lastBar = {}; - if (tt.highlightEl) tt.highlightEl.style.display = "none"; - } - - return true; - } - - return false; - } - - function renderFunction() { - // the tooltip has not been initialized with this chart. - if (hideIfDisabled()) return; - - var bar = this.barFromPixel(this.cx), - data = this.chart.dataSegment[bar]; - if (!data) { - this.positionMarkers(); - return; - } - if ( - CIQ.Marker.Tooltip.sameBar(data, this.huTooltip.lastBar) && - bar != this.chart.dataSegment.length - 1 - ) { - return; - } - var node = this.huTooltip.node; - Array.from(node.parentElement.querySelectorAll("[auto]")).forEach( - function (i) { - i.remove(); - } - ); - Array.from( - node.parentElement.querySelectorAll("stx-hu-tooltip-field-value") - ).forEach(function (i) { - i.innerHTML = ""; - }); - - var panel = this.chart.panel; - var yAxis = panel.yAxis; - var dupMap = {}; - var fields = []; - fields.push({ - member: "DT", - display: "DT", - panel: panel, - yAxis: yAxis - }); - fields.push({ - member: "Close", - display: "Close", - panel: panel, - yAxis: yAxis - }); - dupMap.DT = dupMap.Close = 1; - if ( - showChange && - CIQ.ChartEngine.isDailyInterval(this.layout.interval) - ) { - fields.push({ - member: "Change", - display: "Change", - panel: panel, - yAxis: yAxis - }); - } - if (showOhl) { - fields.push({ - member: "Open", - display: "Open", - panel: panel, - yAxis: yAxis - }); - fields.push({ - member: "High", - display: "High", - panel: panel, - yAxis: yAxis - }); - fields.push({ - member: "Low", - display: "Low", - panel: panel, - yAxis: yAxis - }); - dupMap.Open = dupMap.High = dupMap.Low = 1; - } - if (showVolume) { - fields.push({ - member: "Volume", - display: "Volume", - panel: null, - yAxis: null - }); // null yAxis use raw value - dupMap.Volume = 1; - } - if (showSeries) { - var renderers = this.chart.seriesRenderers; - for (var renderer in renderers) { - var rendererToDisplay = renderers[renderer]; - if (rendererToDisplay === this.mainSeriesRenderer) continue; - panel = this.panels[rendererToDisplay.params.panel]; - yAxis = rendererToDisplay.params.yAxis; - if (!yAxis && rendererToDisplay.params.shareYAxis) - yAxis = panel.yAxis; - for (var id = 0; id < rendererToDisplay.seriesParams.length; id++) { - var seriesParams = rendererToDisplay.seriesParams[id]; - // if a series has a symbol and a field then it maybe a object chain - var sKey = seriesParams.symbol; - var subField = seriesParams.field; - if (!sKey) sKey = subField; - else if (subField && sKey != subField) - sKey = CIQ.createObjectChainNames(sKey, subField)[0]; - var display = - seriesParams.display || - seriesParams.symbol || - seriesParams.field; - if (sKey && !dupMap[display]) { - fields.push({ - member: sKey, - display: display, - panel: panel, - yAxis: yAxis, - isSeries: true - }); - dupMap[display] = 1; - } - } - } - } - if (showStudies) { - for (var study in this.layout.studies) { - var sd = this.layout.studies[study]; - panel = this.panels[sd.panel]; - yAxis = panel && sd.getYAxis(this); - for (var output in this.layout.studies[study].outputMap) { - if (output && !dupMap[output]) { - fields.push({ - member: output, - display: output, - panel: panel, - yAxis: yAxis - }); - dupMap[output] = 1; - } - } - if (!dupMap[study + "_hist"]) { - fields.push({ - member: study + "_hist", - display: study + "_hist", - panel: panel, - yAxis: yAxis - }); - fields.push({ - member: study + "_hist1", - display: study + "_hist1", - panel: panel, - yAxis: yAxis - }); - fields.push({ - member: study + "_hist2", - display: study + "_hist2", - panel: panel, - yAxis: yAxis - }); - dupMap[study + "_hist"] = 1; - } - } - } - for (var f = 0; f < fields.length; f++) { - var obj = fields[f]; - var name = obj.member; - var displayName = obj.display; - var isRecordDate = name == "DT"; - if ( - isRecordDate && - !useDataZone && - !CIQ.ChartEngine.isDailyInterval(stx.layout.interval) - ) - name = "displayDate"; // display date is timezone adjusted - panel = obj.panel; - yAxis = obj.yAxis; - var labelDecimalPlaces = null; - if (yAxis) { - if (!panel || panel !== panel.chart.panel) { - // If a study panel, use yAxis settings to determine decimal places - if (yAxis.decimalPlaces || yAxis.decimalPlaces === 0) - labelDecimalPlaces = yAxis.decimalPlaces; - else if (yAxis.maxDecimalPlaces || yAxis.maxDecimalPlaces === 0) - labelDecimalPlaces = yAxis.maxDecimalPlaces; - } else { - // If a chart panel, then always display at least the number of decimal places as calculated by masterData (panel.chart.decimalPlaces) - // but if we are zoomed to high granularity then expand all the way out to the y-axis significant digits (panel.yAxis.printDecimalPlaces) - labelDecimalPlaces = Math.max( - yAxis.printDecimalPlaces, - panel.chart.decimalPlaces - ); - // ... and never display more decimal places than the symbol is supposed to be quoting at - if (yAxis.maxDecimalPlaces || yAxis.maxDecimalPlaces === 0) - labelDecimalPlaces = Math.min( - labelDecimalPlaces, - yAxis.maxDecimalPlaces - ); - } - } - var dsField = null; - // account for object chains - var tuple = CIQ.existsInObjectChain(data, name); - if (tuple) dsField = tuple.obj[tuple.member]; - else if (name == "Change") dsField = data.Close - data.iqPrevClose; - - var fieldName = displayName.replace(/^(Result )(.*)/, "$2"); - - if ( - showInterpolation && - fields[f].isSeries && - (dsField === null || typeof dsField == "undefined") - ) { - // do this only for additional series and not the main series - var seriesPrice = this.valueFromInterpolation( - bar, - fieldName, - "Close", - panel, - yAxis - ); - if (seriesPrice === null) break; - dsField = seriesPrice; - } - if ( - (dsField || dsField === 0) && - (isRecordDate || - typeof dsField !== "object" || - dsField.Close || - dsField.Close === 0) - ) { - var fieldValue = ""; - if (dsField.Close || dsField.Close === 0) dsField = dsField.Close; - if (dsField.constructor == Number) { - if (!yAxis) { - // raw value - fieldValue = dsField; - } else if ( - yAxis.originalPriceFormatter && - yAxis.originalPriceFormatter.func - ) { - // in comparison mode with custom formatter - fieldValue = yAxis.originalPriceFormatter.func( - this, - panel, - dsField, - labelDecimalPlaces - ); - } else if ( - yAxis.priceFormatter && - yAxis.priceFormatter != CIQ.Comparison.priceFormat - ) { - // using custom formatter - fieldValue = yAxis.priceFormatter( - this, - panel, - dsField, - labelDecimalPlaces - ); - } else { - fieldValue = this.formatYAxisPrice( - dsField, - panel, - labelDecimalPlaces, - yAxis - ); - } - } else if (dsField.constructor == Date) { - if ( - isRecordDate && - this.controls.floatDate && - this.controls.floatDate.innerHTML - ) { - if (this.chart.xAxis.noDraw) fieldValue = "N/A"; - else - fieldValue = CIQ.displayableDate(this, panel.chart, dsField); - } else { - fieldValue = CIQ.yyyymmdd(dsField); - if (!CIQ.ChartEngine.isDailyInterval(this.layout.interval)) { - fieldValue += " " + dsField.toTimeString().substr(0, 8); - } - } - } else { - fieldValue = dsField; - } - var dedicatedField = node.querySelector( - 'stx-hu-tooltip-field[field="' + fieldName + '"]' - ); - - if (dedicatedField) { - dedicatedField.querySelector( - "stx-hu-tooltip-field-value" - ).innerHTML = fieldValue; - var fieldNameField = dedicatedField.querySelector( - "stx-hu-tooltip-field-name" - ); - if (fieldNameField.innerHTML === "") - fieldNameField.innerHTML = this.translateIf(fieldName); - } else { - var newField = document.createElement("stx-hu-tooltip-field"); - newField.setAttribute("auto", true); - var newFieldName = document.createElement( - "stx-hu-tooltip-field-name" - ); - newFieldName.innerHTML = this.translateIf(fieldName); - newField.appendChild(newFieldName); - var newFieldValue = document.createElement( - "stx-hu-tooltip-field-value" - ); - newFieldValue.innerHTML = fieldValue; - newField.appendChild(newFieldValue); - node.appendChild(newField); - } - } else { - var naField = node.querySelector( - 'stx-hu-tooltip-field[field="' + fieldName + '"]' - ); - if (naField) { - var naFieldNameField = naField.querySelector( - "stx-hu-tooltip-field-name" - ); - if (naFieldNameField.innerHTML !== "") - naField.querySelector("stx-hu-tooltip-field-value").innerHTML = - "n/a"; - } - } - } - this.huTooltip.render(); - } - - stx.append("deleteHighlighted", function () { - this.huTooltip.lastBar = {}; - this.headsUpHR(); - }); - stx.append("headsUpHR", renderFunction); - stx.append("createDataSegment", renderFunction); - stx.huTooltip = new CIQ.Marker.Tooltip({ - stx: stx, - xPositioner: "bar", - chartContainer: true, - node: node - }); - }; -} - -}; - - -let __js_addons_advanced_animation_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -/** - * Add-On that animates the chart. - * - * Requires *addOns.js*. - * - * The chart is animated in three ways: - * 1. The current price pulsates - * 2. The current price appears to move smoothly from the previous price - * 3. The chart's y-axis smoothly expands/contracts when a new high or low is reached - * - * The following chart types are supported: line, mountain, baseline_delta. - * - * Chart aggregations such as Kagi, Renko, Range Bars, etc. are not supported. - * - * **Animation displays more gracefully when updates are sent into the chart one at a time using {@link CIQ.ChartEngine#updateChartData} - * instead of in batches using a [QuoteFeed]{@link CIQ.ChartEngine#attachQuoteFeed}. Sending data in batches will produce a ‘jumping’ effect.** - * - * By default, there will be a flashing beacon created using a canvas circle. If instead you want to use a custom animation beacon, you will be able to extend the functionality yourself as follows: - * - In js/addOns.js, at the bottom of the CIQ.Animation function, there is an stx.append("draw") function. - * - Make a copy of this function so you can override the behavior. - * - In there you will see it determine var x and y, which are the coordinates for the center of the beacon. - * - At the bottom of this append function, we draw the beacon by using the Canvas arc() function to draw a circle and then fill() to make the circle solid. - * - You can replace the canvas circle with an image using [CanvasRenderingContext2D.drawImage()](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D#Drawing_images) . - * - Example: - * - * ``` - * var image = document.getElementById('beacon'); // include a hidden image on your HTML - * context.drawImage(image, x-10, y-10, 20, 20); // add the image on the canvas. Offset the x and y values by the radius of the beacon. - * ``` - * - * Animation Example - * - * You can disable animation after each different [chart type is activated]{@link CIQ.ChartEngine#setChartType} by calling: - * ``` - * stxx.mainSeriesRenderer.supportsAnimation=false; - * ``` - * Keep in mind that changing to a different chart type, may once again enable animation. You can override this by [adding an event listener]{@link CIQ.ChartEngine#addEventListener} on [layout changes]{@link CIQ.ChartEngine~layoutEventListener}. - * - * @param {object} config The constructor parameters - * @param {CIQ.ChartEngine} config.stx The chart object - * @param {object} [config.animationParameters] Configuration parameters - * @param {boolean} [config.animationParameters.stayPut=false] Set to true for last tick to stay in position it was scrolled and have rest of the chart move backwards as new ticks are added instead of having new ticks advance forward and leave the rest of the chart in place. - * @param {number} [config.animationParameters.ticksFromEdgeOfScreen=5] Number of ticks from the right edge the chart should stop moving forward so the last tick never goes off screen (only applicable if stayPut=false) - * @param {number} [config.animationParameters.granularity=1000000] Set to a value that will give enough granularity for the animation. The larger the number the smaller the price jump between frames, which is good for charts that need a very slow smooth animation either because the price jumps between ticks are very small, or because the animation was set up to run over a large number of frames when instantiating the CIQ.EaseMachine. - * @param {number} [config.animationParameters.tension=null] Splining tension for smooth curves around data points (range 0-1). - * @param {CIQ.EaseMachine} config.easeMachine Override the default easeMachine. Default is `new CIQ.EaseMachine(Math.easeOutCubic, 1000);` - * @constructor - * @name CIQ.Animation - * @since - * - 3.0.0 Now part of *addOns.js*. Previously provided as a standalone *animation.js* file. - * - 4.0.0 Beacon only flashes for line charts. On candles or bars, it is suppressed as it produces an unnatural effect. - * - 7.0.2 Now takes one configuration object as its constructor. Must have a reference to a chart engine. - * @example - * new CIQ.Animation({stx: stxx, animationParameters: {tension:0.3}}); //Default animation with splining tension of 0.3 - * - */ -CIQ.Animation = - CIQ.Animation || - function (config) { - if (!config) throw new Error("Invalid constructor arguments."); - var stx, animationParameters, easeMachine; - if (config instanceof CIQ.ChartEngine) { - // legacy constructor - stx = arguments[0]; - animationParameters = arguments[1]; - easeMachine = arguments[2]; - } else { - stx = config.stx; - animationParameters = config.animationParameters; - easeMachine = config.easeMachine; - } - if (!stx) - return console.warn( - "No CIQ.ChartEngine provided. Cannot properly create CIQ.Animation instance" - ); - var params = { - stayPut: false, - ticksFromEdgeOfScreen: 5, - granularity: 1000000 - }; - animationParameters = CIQ.extend(params, animationParameters); - - if (params.tension) stx.chart.tension = animationParameters.tension; - stx.tickAnimator = - easeMachine || new CIQ.EaseMachine(Math.easeOutCubic, 1000); - var scrollAnimator = new CIQ.EaseMachine(Math.easeInOutCubic, 1000); - - var flashingColors = ["#0298d3", "#19bcfc", "#5dcffc", "#9ee3ff"]; - var flashingColorIndex = 0; - var flashingColorThrottle = 20; - var flashingColorThrottleCounter = 0; - - var filterSession = false; - var nextBoundary = null; - - function initMarketSessionFlags() { - filterSession = false; - nextBoundary = null; - } - - stx.addEventListener(["symbolChange", "layout"], function (obj) { - initMarketSessionFlags(); - }); - - stx.prepend("updateCurrentMarketData", function ( - data, - chart, - symbol, - params - ) { - if (!chart) chart = this.chart; - if ( - params && - params.fromTrade && - (chart.closePendingAnimation || chart.closePendingAnimation === 0) - ) { - params.finalClose = chart.closePendingAnimation; - } - }); - - stx.prepend("updateChartData", function (appendQuotes, chart, params) { - var self = this; - if (!chart) { - chart = self.chart; - } - if ( - !chart || - !chart.defaultChartStyleConfig || - chart.defaultChartStyleConfig == "none" - ) - return; - - if (params !== undefined) { - if (params.animationEntry || params.secondarySeries) return; - } - - if (!chart.dataSegment) return; - - function completeLastBar(record) { - if (!chart.masterData) return; - for (var md = chart.masterData.length - 1; md >= 0; md--) { - var bar = chart.masterData[md]; - if (bar.Close || bar.Close === 0) { - bar.Close = record.Close; - if (record.LastSize) bar.LastSize = record.LastSize; - if (record.LastTime) bar.LastTime = record.LastTime; - self.updateCurrentMarketData({ - Close: bar.Close, - DT: bar.DT, - LastSize: bar.LastSize, - LastTime: bar.LastTime - }); - self.createDataSet(null, null, { appending: true }); - return; - } - } - } - function unanimateScroll() { - if (chart.animatingHorizontalScroll) { - chart.animatingHorizontalScroll = false; - self.micropixels = self.nextMicroPixels = self.previousMicroPixels; // <-- Reset self.nextMicroPixels here - chart.lastTickOffset = 0; - } - if (chart.closePendingAnimation !== null) { - var close = chart.closePendingAnimation; - chart.closePendingAnimation = null; - completeLastBar({ Close: close }); - } - } - var tickAnimator = self.tickAnimator; - // These chart types are the only types supported by animation - var supportedChartType = - this.mainSeriesRenderer && this.mainSeriesRenderer.supportsAnimation; - if (supportedChartType) { - if (!tickAnimator) { - console.warn( - "Animation plug-in can not run because the tickAnimator has not been declared. See instructions in animation.js" - ); - return; - } - - // If symbol changes then reset all of our variables - if (this.prevSymbol != chart.symbol) { - this.prevQuote = 0; - chart.closePendingAnimation = null; - this.prevSymbol = chart.symbol; - } - unanimateScroll(); - tickAnimator.stop(); - if (appendQuotes.length > 2) { - return; - } - } - var newParams = CIQ.clone(params); - if (!newParams) newParams = {}; - newParams.animationEntry = true; - newParams.bypassGovernor = true; - newParams.noCreateDataSet = false; - newParams.appending = true; - //newParams.allowReplaceOHL = true; - newParams.firstLoop = true; - var symbol = this.chart.symbol; - var period = this.layout.periodicity; - var interval = this.layout.interval; - var timeUnit = this.layout.timeUnit; - - function cb(quote, prevQuote, chartJustAdvanced) { - return function (newData) { - var newClose = newData.Close; - if ( - !chart.dataSet.length || - symbol != chart.symbol || - period != self.layout.periodicity || - interval != self.layout.interval || - timeUnit != self.layout.timeUnit - ) { - //console.log ("---- STOP animating: Old",symbol,' New : ',chart.symbol, Date()) - tickAnimator.stop(); - unanimateScroll(); - return; // changed symbols mid animation - } - var q = CIQ.clone(quote); - q.Adj_Close = null; // Don't use this, it will mess up our calculated close - q.Close = - Math.round(newClose * animationParameters.granularity) / - animationParameters.granularity; //<<------ IMPORTANT! Use 1000000 for small price increments, otherwise animation will be in increments of .0001 - //q.Close = Math.round(newClose*chart.roundit)/chart.roundit; // to ensure decimal points don't go out too far for interim values - if (chartJustAdvanced) { - if (!q.Open && q.Open !== 0) q.Open = q.Close; - if (!q.High && q.High !== 0) q.High = Math.max(q.Open, q.Close); - if (!q.Low && q.Low !== 0) q.Low = Math.min(q.Open, q.Close); - } else { - if (quote.Close > prevQuote.High) q.High = q.Close; - if (quote.Close < prevQuote.Low) q.Low = q.Close; - } - if (chart.animatingHorizontalScroll) { - self.micropixels = newData.micropixels; - chart.lastTickOffset = newData.lineOffset; - } - newParams.updateDataSegmentInPlace = !tickAnimator.hasCompleted; - //console.log("animating: Old",symbol,' New : ',chart.symbol); - var updateQuotes = [q]; - // Don't include previous quote if tick mode. It will append, duplicating the quote - if (chartJustAdvanced && self.layout.interval !== "tick") - updateQuotes.unshift(prevQuote); - self.updateChartData(updateQuotes, chart, newParams); - newParams.firstLoop = false; - if (tickAnimator.hasCompleted) { - //console.log( 'animator has completed') ; - //self.pendingScrollAdvance=false; - //var possibleYAxisChange = chart.animatingHorizontalScroll; - unanimateScroll(); - /*if (possibleYAxisChange) { // <---- Logic no longer necessary - // After completion, one more draw for good measure in case our - // displayed high and low have changed, which would trigger - // the y-axis animation - setTimeout(function(){ - self.draw(); - }, 0); - }*/ - } - }; - } - if (supportedChartType) { - var quote = appendQuotes[appendQuotes.length - 1]; - this.prevQuote = this.currentQuote(); // <---- prevQuote logic has been changed to prevent forward/back jitter when more than one tick comes in between animations - var chartJustAdvanced = false; // When advancing, we need special logic to deal with the open - var dontScroll = false; - if (period == 1 && appendQuotes.length == 2) { - // Don't do this if consolidating - this.prevQuote = appendQuotes[0]; - var dataSetLength = chart.dataSet.length; - completeLastBar(this.prevQuote); - if (dataSetLength == chart.dataSet.length) dontScroll = true; - } - if (!quote || !quote.Close || !this.prevQuote || !this.prevQuote.Close) - return false; - - if (this.extendedHours && chart.market.market_def) { - // Filter out unwanted sessions - var dtToFilter = quote.DT; - if (CIQ.ChartEngine.isDailyInterval(interval)) { - filterSession = !chart.market.isMarketDate(dtToFilter); - } else { - if (!nextBoundary || nextBoundary <= dtToFilter) { - var session = chart.market.getSession(dtToFilter); - filterSession = - session !== "" && - (!this.layout.marketSessions || - !this.layout.marketSessions[session]); - nextBoundary = chart.market[ - filterSession ? "getNextOpen" : "getNextClose" - ](dtToFilter); - } - } - if (filterSession) { - this.draw(); - return false; - } - } - - var barSpan = period; - if (interval == "second" || timeUnit == "second") barSpan *= 1000; - else if (interval == "minute" || timeUnit == "minute") barSpan *= 60000; - if (!isNaN(interval)) barSpan *= interval; - if (interval == "day" || timeUnit == "day") - chartJustAdvanced = quote.DT.getDate() != this.prevQuote.DT.getDate(); - else if (interval == "week" || timeUnit == "week") - chartJustAdvanced = - quote.DT.getDate() >= this.prevQuote.DT.getDate() + 7; - else if (interval == "month" || timeUnit == "month") - chartJustAdvanced = - quote.DT.getMonth() != this.prevQuote.DT.getMonth(); - else - chartJustAdvanced = - quote.DT.getTime() >= this.prevQuote.DT.getTime() + barSpan; - - var linearChart = - !this.mainSeriesRenderer || !this.mainSeriesRenderer.standaloneBars; - - var beginningOffset = 0; - if (chartJustAdvanced) { - if (this.animations.zoom.hasCompleted) { - var candleWidth = this.layout.candleWidth; - if (chart.scroll <= chart.maxTicks) { - while (this.micropixels > 0) { - // If micropixels is larger than a candle then scroll back further - chart.scroll++; - this.micropixels -= candleWidth; - } - } - if (chart.scroll <= chart.maxTicks) { - this.previousMicroPixels = this.micropixels; - this.nextMicroPixels = this.micropixels + candleWidth; - beginningOffset = candleWidth * -1; - if ( - chart.dataSegment.length < - chart.maxTicks - animationParameters.ticksFromEdgeOfScreen && - !animationParameters.stayPut - ) { - this.nextMicroPixels = this.micropixels; - chart.scroll++; - } - chart.animatingHorizontalScroll = linearChart; // When the chart advances we also animate the horizontal scroll by incrementing micropixels - chart.previousDataSetLength = chart.dataSet.length; - } else { - if (!dontScroll) chart.scroll++; - } - } else { - return false; - } - } - chart.closePendingAnimation = quote.Close; - var start = - chartJustAdvanced && !linearChart ? quote.Open : this.prevQuote.Close; - tickAnimator.run( - cb(quote, CIQ.clone(this.prevQuote), chartJustAdvanced), - { - Close: start, - micropixels: this.nextMicroPixels, - lineOffset: beginningOffset - }, - { Close: quote.Close, micropixels: this.micropixels, lineOffset: 0 } - ); - return true; // bypass default behavior in favor of animation - } - }); - - stx.prepend("renderYAxis", function (chart) { - if (this.grabbingScreen || !this.isHome()) return; - // When display style doesn't support animation - var supportedChartType = - this.mainSeriesRenderer && this.mainSeriesRenderer.supportsAnimation; - if (!supportedChartType) return; - - var panel = chart.panel; - var yAxis = panel.yAxis; - if (CIQ.Comparison && yAxis.priceFormatter == CIQ.Comparison.priceFormat) - return; // too difficult to animate y-axis change when it changes on every tick due to percentage axis on comparison - - function closure(self) { - return function (values) { - chart.animatedLow = values.low; - chart.animatedHigh = values.high; - self.draw(); - }; - } - // initialize prev values - if (!chart.prevLowValue && chart.prevLowValue !== 0) { - chart.prevLowValue = chart.animatedLow = chart.lowValue; - } - if (!chart.prevHighValue && chart.prevHighValue !== 0) { - chart.prevHighValue = chart.animatedHigh = chart.highValue; - } - - // check for a change, if so we will spin off an animation - if (!scrollAnimator.running) chart.animatingVerticalScroll = false; - if ( - chart.prevLowValue >= chart.lowValue && - chart.prevHighValue <= chart.highValue - ) { - if (chart.animatingVerticalScroll) { - yAxis.highValue = chart.animatedHigh; - yAxis.lowValue = chart.animatedLow; - } - return; - } - if (scrollAnimator.running) scrollAnimator.stop(); - if (!chart.lowValue && !chart.highValue) return; // chart just reset, don't animate yet - var prevLow = chart.prevLowValue, - prevHigh = chart.prevHighValue; - chart.prevLowValue = chart.lowValue; - chart.prevHighValue = chart.highValue; - chart.animatingVerticalScroll = true; - scrollAnimator.run( - closure(this), - { low: prevLow, high: prevHigh }, - { low: chart.lowValue, high: chart.highValue } - ); - - yAxis.lowValue = chart.animatedLow; - yAxis.highValue = chart.animatedHigh; - }); - - /*stx.prepend("draw", function() { - if(this.chart.animatingVerticalScroll) { - this.renderYAxis(this.chart); - return true; - } - });*/ - - stx.append("draw", function () { - if (filterSession) return; - if ( - this.chart.dataSet && - this.chart.dataSet.length && - this.mainSeriesRenderer && - this.mainSeriesRenderer.supportsAnimation - ) { - if (flashingColorThrottleCounter % flashingColorThrottle === 0) { - flashingColorIndex++; - flashingColorThrottleCounter = 0; - } - flashingColorThrottleCounter++; - - var context = this.chart.context; - var panel = this.chart.panel; - var currentQuote = this.currentQuote(); - if (!currentQuote) return; - var price = currentQuote.Close; - var x = this.pixelFromTick(currentQuote.tick, this.chart); - if (this.chart.lastTickOffset) x = x + this.chart.lastTickOffset; - var y = this.pixelFromPrice(price, panel); - if ( - this.chart.yAxis.left > x && - this.chart.yAxis.top <= y && - this.chart.yAxis.bottom >= y - ) { - if (flashingColorIndex >= flashingColors.length) - flashingColorIndex = 0; - context.beginPath(); - context.moveTo(x, y); - context.arc( - x, - y, - 2 + flashingColorIndex * 1.07, - 0, - Math.PI * 2, - false - ); - context.fillStyle = flashingColors[flashingColorIndex]; - context.fill(); - } - } - }); - }; - -/** - * CIQ.EaseMachine interface placeholder to be augmented in *standard.js* with properties. - * - * @tsinterface CIQ~EaseMachine - */ - -}; - - -let __js_addons_advanced_continuousZoom_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -/** - * Add-on that responds to the chart zoom action, changing periodicities as the number of ticks and/or candle width - * hits a set boundary. - * - * Although this feature is available for all chart styles, it shows best on continuous renderings - * such as lines and mountains vs. candles and bars. This is because some users may find the - * changes in candle width that take place as the same range is displayed in a different - * periodicity, inappropriate. The effect can be mitigated by increasing the number of boundaries - * so periodicities change more often, preventing large candle width changes, and by using the - * periodicity roll up feature instead of fetching new data from a quote feed. See examples. - * - * See {@link CIQ.ChartEngine#setPeriodicity} and {@link CIQ.ChartEngine#createDataSet} - * - * Requires *addOns.js*. - * - * The feature will not work without supplying at least one element within the periodicities array - * and at least one property within the boundaries object. - * - * @param {object} params Configuration parameters. - * @param {CIQ.ChartEngine} params.stx The chart object. - * @param {array} params.periodicities Set this array with eligible periodicities in any order. - * These will be the periodicities which will be used by the continuous zooming once a - * boundary is hit. The periodicities are objects with `period`, `interval`, and optional - * `timeUnit` properties (see {@link CIQ.ChartEngine#setPeriodicity}). - * @param {object} params.boundaries Optional boundary cases to trigger the periodicity change. - * Hitting a maximum boundary switches to the next larger periodicity; hitting a minimum - * boundary switches to the next smaller periodicity. - * @param {number} [params.boundaries.maxCandleWidth] Largest size of candle in pixels to display - * before switching periodicity. - * @param {number} [params.boundaries.minCandleWidth] Smallest size of candle in pixels to display - * before switching periodicity. - * @param {number} [params.boundaries.maxTicks] Most number of ticks to display before switching - * periodicity. - * @param {number} [params.boundaries.minTicks] Least number of ticks to display before switching - * periodicity. - * - * @constructor - * @name CIQ.ContinuousZoom - * @since 7.0.0 - * - * @example - * new CIQ.ContinuousZoom({ - * stx: stxx, - * periodicities: [ - * { period:1, interval:"month" }, - * { period:1, interval:"day" }, - * { period:2, interval:30 }, - * { period:1, interval:5 }, - * { period:15, interval:1, timeUnit:"second" }, - * { period:1, interval:1, timeUnit:"second" } - * ], - * boundaries: { - * maxCandleWidth: 100, - * minCandleWidth: 3, - * maxTicks: 500, - * minTicks: 10 - * } - * }); - * - * @example - * // Smother periodicity change by rolling daily into weekly and monthly. - * // Also try reusing the same interval data and have the chart roll it instead of fetching new data. - * stxx.dontRoll = false; - * new CIQ.ContinuousZoom({ - * stx: stxx, - * periodicities: [ - * // Daily interval data - * {period:1, interval:"month"}, - * {period:2, interval:"week"}, - * {period:1, interval:"week"}, - * {period:3, interval:"day"}, - * {period:1, interval:"day"}, - * // 30 minute interval data - * {period:16, interval:30}, - * {period:8, interval:30}, - * {period:4, interval:30}, - * {period:2, interval:30}, - * // one minute interval data - * {period:30, interval:1}, - * {period:15, interval:1}, - * {period:10, interval:1}, - * {period:5, interval:1}, - * {period:2, interval:1}, - * {period:1, interval:1}, - * // One second interval data - * {period:30,interval:1, timeUnit:"second"}, - * {period:15,interval:1, timeUnit:"second"}, - * {period:5, interval:1, timeUnit:"second"}, - * {period:2, interval:1, timeUnit:"second"}, - * {period:1, interval:1, timeUnit:"second"}, - * ], - * boundaries: { - * maxCandleWidth: 15, - * minCandleWidth: 3 - * } - * }); - */ -CIQ.ContinuousZoom = - CIQ.ContinuousZoom || - function (params) { - this.cssRequired = true; - this.update(params); - this.stx.continuousZoom = this; - - //Attaches SmartZoom button to HTML DOM inside .chartSize element - this.addSmartZoomButton = function () { - // Don't add a button if one already exists - var smartZoomButton = - this.stx.registerChartControl && - this.stx.registerChartControl( - "stx-smart-zoom", - "SmartZoom (Alt + 0)", - (function (self) { - return function (e) { - self.smartZoomToggle(e); - e.stopPropagation(); - }; - })(this) - ); - if (smartZoomButton) { - // Listen for a layout changed event and refresh the toggle state of the button - this.stx.addEventListener("layout", function (event) { - if (event.stx.layout.smartzoom === true) { - smartZoomButton.classList.add("active"); - } else { - smartZoomButton.classList.remove("active"); - } - }); - // Piggyback off of symbolImport event to detect smartzoom set to false from layout import - this.stx.addEventListener("symbolImport", function (event) { - if (event.stx.layout.smartzoom === false) - smartZoomButton.classList.remove("active"); - }); - } - }; - - //Click event handler for the Smart Zoom button. Sets smartzoom property of layout to its inverse - this.smartZoomToggle = function (e) { - this.smartZoomEnable(!this.stx.layout.smartzoom); - }; - - //Sets smartzoom property of layout and notifies attached ChartEngine of change - this.smartZoomEnable = function (state) { - this.stx.layout.smartzoom = state; - this.stx.changeOccurred("layout"); - }; - - // Add the SmartZoom button to chartControls - this.addSmartZoomButton(); - // Enable SmartZoom by default - this.smartZoomEnable(true); - }; - -/** - * Updates continuous zoom parameters - * @param {object} params Configuration parameters. See constructor for details - * @memberof CIQ.ContinuousZoom - * @since 7.0.0 - * @private - */ -CIQ.ContinuousZoom.prototype.update = function (params) { - if (!params) params = {}; - this.stx = params.stx; - this.periodicities = params.periodicities; - this.boundaries = params.boundaries; -}; - -/** - * Potentially performs a continuous zoom after a zoom event - * @param {boolean} [zoomOut] True for a zoomOut operation, otherwise zoomIn - * @memberof CIQ.ContinuousZoom - * @since 7.0.0 - * @private - */ -CIQ.ContinuousZoom.prototype.execute = function (zoomOut) { - // assign a weight to a periodicity setting, the higher the length, the higher the weight - function valuate(periodicity) { - var period = periodicity.period || periodicity.periodicity, - interval = periodicity.interval, - timeUnit = periodicity.timeUnit || "minute"; - if (isNaN(interval)) { - timeUnit = interval; - interval = 1; - } - switch (timeUnit) { - case "month": - interval *= 4.35; /* falls through */ - case "week": - interval *= 7; /* falls through */ - case "day": - interval *= 1440; /* falls through */ - case "minute": - interval *= 60; /* falls through */ - case "second": - break; - case "millisecond": - interval /= 1000; - break; - default: - return null; - } - return period * interval; - } - if (!this.stx || !this.stx.layout.smartzoom) return; - var periodicities = this.periodicities, - boundaries = this.boundaries, - stx = this.stx, - layout = stx.layout, - chart = stx.chart; - if (!periodicities || !boundaries) return; - - if ( - (!zoomOut && - boundaries.maxCandleWidth && - layout.candleWidth > boundaries.maxCandleWidth) || - (zoomOut && - boundaries.minCandleWidth && - layout.candleWidth < boundaries.minCandleWidth) || - (!zoomOut && boundaries.minTicks && chart.maxTicks < boundaries.minTicks) || - (zoomOut && boundaries.maxTicks && chart.maxTicks > boundaries.maxTicks) - ) { - var next = { value: zoomOut ? Number.MAX_VALUE : 0 }; - var myValue = valuate(layout); - for (var p = 0; p < periodicities.length; p++) { - var value = valuate(periodicities[p]); - if ( - (value > myValue && value < next.value && zoomOut) || - (value < myValue && value > next.value && !zoomOut) - ) { - next = { value: value, periodicity: periodicities[p] }; - } - } - var newPeriodicity = next.periodicity; - if (newPeriodicity) { - stx.setRange({ - dtLeft: chart.xaxis[0].DT, - dtRight: chart.xaxis[chart.xaxis.length - 1].DT, - dontSaveRangeToLayout: true, - periodicity: newPeriodicity - }); - } - } -}; - -}; - - -let __js_addons_advanced_outliers_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -/** - * Creates the outliers add-on which scales the y-axis to the main trend, hiding outlier - * values. Markers are placed at the location of the outlier values enabling the user to - * restore the full extent of the y-axis by selecting the markers. - * - * Requires *addOns.js*. - * - * ![Chart with hidden outliers](./img-Chart-with-Hidden-Outliers.png "Chart with hidden outliers") - * - * @param {object} params Configuration parameters. - * @param {CIQ.ChartEngine} [params.stx] A reference to the chart object. - * @param {number} [params.multiplier=3] Sets the threshold for outliers by multiplying the - * normal data range. The default value hides only extreme outliers. - * @param {Array} [params.altColors] An array of hexadecimal color values used to style - * outlier markers when multiple y-axes share the same panel. Markers for the first - * additional y-axis are styled with the value at index 0; markers for the second - * additional y-axis, the value at index 1; and so forth. If not provided, a default - * array of colors is assigned. - * @param {string} [params.menuContextClass] A CSS class name used to query the menu DOM element - * that contains the UI control for the outliers add-on. In a multi-chart document, the - * add-on is available only on charts that have a menu DOM element with the value for - * `menuContextClass` as a class attribute. - * - * @constructor - * @name CIQ.Outliers - * @since - * - 7.5.0 - * - 8.0.0 Added `params.altColors` and `params.menuContextClass`. - * - * @example - * new CIQ.Outliers({ stx: stxx }); - */ -CIQ.Outliers = - CIQ.Outliers || - function (params) { - if (!params) params = {}; - if (!params.stx) { - console.warn("The Outliers addon requires an stx parameter"); - return; - } - // Set default marker colors - if (!Array.isArray(params.altColors)) { - params.altColors = [ - "#323390", - "#66308f", - "#0073ba", - "#f4932f", - "#0056a4", - "#00a99c", - "#00a553", - "#ea1d2c", - "#e9088c", - "#fff126", - "#912a8e", - "#ee652e", - "#00afed", - "#8ec648" - ]; - } - this.stx = params.stx; - this.stx.outliers = this; - this.cssRequired = true; - - this.multiplier = params.multiplier || 3; // Default to 3 for extreme outliers - this.altColors = params.altColors; - - this.axisData = {}; - - // Listen for a layout changed event and reset the markers - this.stx.addEventListener("layout", function (event) { - Object.keys(event.stx.outliers.axisData).forEach( - function (key) { - this.removeAllMarkers(this.axisData[key]); - delete this.axisData[key]; - }.bind(event.stx.outliers) - ); - }); - - /** - * Checks for outlier values in `dataSet`, and adds outlier markers (data point markers - * and axis markers) to `axis`. - * - * @param {Array} dataSet An array of objects of the form `{value: Number, quote: Object}`. - * Each object contains a value and its associated quote. The value is checked to - * determine whether it is an outlier of the data set. When checking more than one - * value for a quote (such as an OHLC quote), each value is included in a separate - * object; for example, `[{value: open, quote: quote}, {value: high, quote: quote}, - * {value: low, quote: quote}, {value: close, quote: quote}...]`. - * @param {object} panel The panel where `dataSet` is rendered. - * @param {object} axis The y-axis against which `dataSet` is rendered. **Note:** Charts - * and panels can have multiple y-axes; each y-axis has its own set of outlier - * markers based on the data rendered on the axis. - * @return {Array} A tuple consisting of the outlier minimum and maximum — or trend - * minimum and maximum, if no outliers are found — to be handled by the - * {@link CIQ.ChartEngine#determineMinMax} method. See the return value of the - * [find]{@link CIQ.Outliers#find} function for a description of outlier and trend - * minimum and maximum. - * - * @alias processDataSet - * @memberOf CIQ.Outliers.prototype - * @since 8.0.0 - */ - this.processDataSet = function (dataSet, panel, axis) { - if (!dataSet.length || dataSet.length <= 1) return false; - - var result = [0, 0]; // Min/Max axis values to return - - // Create an axis reference if one does not exist - if (!this.axisData[axis.name]) { - var markerColor = ""; - var axisDepth = -1; - // Check for another axis using this panel - Object.keys(this.axisData).forEach( - function (key) { - if (this.axisData[key].panel.name == panel.name) { - axisDepth++; - } - }.bind(this) - ); - if (axisDepth > -1 && axisDepth < this.altColors.length) - markerColor = this.altColors[axisDepth]; - - this.axisData[axis.name] = { - axis: axis, - panel: panel, - displayState: "none", - isFlipped: false, - originalZoom: axis.zoom, - markerColor: markerColor, - markers: {}, - axisMarkers: {} - }; - } - - var currentAxis = this.axisData[axis.name]; - // Attach the min/max values to the current axis data - Object.assign(currentAxis, this.find(dataSet)); - - // Update/add necessary markers - this.refreshMarkerArray(currentAxis); - - // Update marker display and labels - this.refreshMarkers(currentAxis); - - // Return either trendMin or outlierMin based on the axis displayState - if ( - (currentAxis.displayState === "low" || - currentAxis.displayState === "all") && - currentAxis.outlierMin !== null - ) - result[0] = currentAxis.outlierMin; - else result[0] = currentAxis.trendMin; - // Return either trendMax or outlierMax based on the axis displayState - if ( - (currentAxis.displayState === "high" || - currentAxis.displayState === "all") && - currentAxis.outlierMax !== null - ) - result[1] = currentAxis.outlierMax; - else result[1] = currentAxis.trendMax; - - return result; - }; - - /** - * Finds the outliers contained in `dataSet`. - * - * **Note:** This function may be overridden to provide a custom algorithm for finding - * outliers. - * - * @param {Array} dataSet An array of objects of the form `{value: Number, quote: Object}`. - * Each object contains a value and its associated quote. The value is checked to - * determine whether it is an outlier of the data set. When checking more than one - * value for a quote (such as an OHLC quote), each value is included in a separate - * object; for example, `[{value: open, quote: quote}, {value: high, quote: quote}, - * {value: low, quote: quote}, {value: close, quote: quote}...]`. - * @return {object} An object of the form: - * ``` - * { - * // Minimum and maximum threshold values of dataSet to be considered an outlier. - * minValue: null, - * maxValue: null, - * // Mininum and maximum values of dataSet that are not considered outliers. - * // Will be the least and greatest values in dataSet if no outliers are found. - * trendMin: null, - * trendMax: null, - * // Minimum and maximum values of dataSet that are considered outliers. - * // Will remain null if no outliers are found. - * outlierMin: null, - * outlierMax: null, - * // Array of individual outlier information for marker placement, in the format {DT:DateTime, value:Number, position:String} - * // (position is either 'high' or 'low'). - * activeOutliers: [] - * } - * ``` - * - * @alias find - * @memberOf CIQ.Outliers.prototype - * @since - * - 7.5.0 - * - 8.0.0 Added return value. - */ - this.find = function (dataSet) { - if (!dataSet.length || dataSet.length <= 0) return; - - var createMarkerPlaceholder = function (data, position) { - return { - quote: data.quote, - DT: data.quote.DT, - value: data.value, - position: position - }; - }; - - // The minimum and maximum threshold values to be considered an outlier. - var minValue = null; - var maxValue = null; - // min/max values of available data that are not considered outliers. Will be the least and greatest values in the available data if no outliers are found. - var trendMin = null; - var trendMax = null; - // min/max values of available data that are considered outliers. Will remain null if no outlier is found. - var outlierMin = null; - var outlierMax = null; - // Array of outlier information in the format - // {DT:DateTime, value:Number, position:String} - var activeOutliers = []; - - var dataSorted = dataSet.slice(); - dataSorted.sort(function (a, b) { - return a.value - b.value; - }); - var dataLength = dataSorted.length; - - // Outlier threshold values are defined as more than the interquartile range above the third quartile - // or below the first quartile, of the sorted dataSet, multiplied by the value of the - // stxx.outlierMultiplier property. - var q1 = dataSorted[Math.floor(dataLength / 4)].value; - var q3 = dataSorted[Math.floor(dataLength * (3 / 4))].value; - var iqr = q3 - q1; - - minValue = q1 - iqr * this.multiplier; - maxValue = q3 + iqr * this.multiplier; - - // Loop through the sorted data and find the outliers as well as the trend min/max - for (var idx = 0; idx < dataLength; idx++) { - // Attack the array from both ends - var dataLow = dataSorted[idx]; - var dataHigh = dataSorted[dataLength - (idx + 1)]; - - // Find and mark outliers. Existing merkers will be refreshed in setMarker. - if (dataLow.value <= minValue) - activeOutliers.push(createMarkerPlaceholder(dataLow, "low")); - if (dataHigh.value >= maxValue) - activeOutliers.push(createMarkerPlaceholder(dataHigh, "high")); - - // Find the first low value that's less than or equal to outlier threshold min - if (outlierMin === null && dataLow.value <= minValue) - outlierMin = dataLow.value; - // Find the first high value that's greater than or equal to outlier threshold max - if (outlierMax === null && dataHigh.value >= maxValue) - outlierMax = dataHigh.value; - - // Find the first low value that's greater than the outlier threshold min - if (trendMin === null && dataLow.value > minValue) - trendMin = dataLow.value; - // Find the first high value that's less than the outlier threshold max - if (trendMax === null && dataHigh.value < maxValue) - trendMax = dataHigh.value; - - // No need to loop through the entire array. Once the trend min/max are found we're done. - if (trendMin !== null && trendMax !== null) break; - } - - return { - minValue: minValue, - maxValue: maxValue, - trendMin: trendMin, - trendMax: trendMax, - outlierMin: outlierMin, - outlierMax: outlierMax, - activeOutliers: activeOutliers - }; - }; - - /** - * Updates the freshness status of outlier markers belonging to `targetAxis`. - * - * Sets the status to fresh if the markers represent data points in the `activeOutliers` - * list of `targetAxis` or a marker is an axis marker for high or low outliers and high or - * low outliers exist. (See the return value of the [find]{@link CIQ.Outliers#find} - * function for a description of the `activeOutliers` list.) - * - * Adds new markers to `targetAxis` for data points in the `activeOutliers` list not - * already represented by a marker (see [markOutlier]{@link CIQ.Outliers#markOutlier}). - * Adds new axis markers if the data set rendered on `targetAxis` contains high or low - * outliers and the respective axis marker does not exist (see - * [markAxis]{@link CIQ.Outliers#markAxis}). - * - * Sets the status of all other markers belonging to `targetAxis` to stale, or unfresh - * (these markers are ultimately removed). - * - * @param {object} targetAxis The y-axis for which the markers are refreshed. - * **Note:** Charts and panels can have multiple y-axes, each with its own array of - * outlier markers. - * - * @alias refreshMarkerArray - * @memberOf CIQ.Outliers.prototype - * @since 8.0.0 - */ - this.refreshMarkerArray = function (targetAxis) { - this.deprecateMarkers(targetAxis); // If a marker isn't refreshed below, it will be deleted in the next call - - var targetMarkers = targetAxis.markers; - targetAxis.activeOutliers.forEach( - function (outlier) { - var quoteTime = outlier.DT.getTime().toString(); - // Add a quote marker if there isn't one already - if (!targetMarkers[quoteTime]) { - targetMarkers[quoteTime] = { - isFresh: true, - type: "quote", - value: outlier.value, - marker: this.markOutlier(outlier, outlier.position, targetAxis) - }; - } - // Always refresh the status of the marker - targetMarkers[quoteTime].isFresh = true; - }.bind(this) - ); - if (targetAxis.outlierMax !== null) { - // Add the high axis marker if there isn't one - if (!targetMarkers.axisHigh) { - targetMarkers.axisHigh = { - isFresh: true, - type: "axis", - value: targetAxis.outlierMax, - marker: this.markAxis("high", targetAxis) - }; - } - // Always refresh the status of the marker - targetMarkers.axisHigh.isFresh = true; - } - if (targetAxis.outlierMin !== null) { - // Add the low axis marker if there isn't one - if (!targetMarkers.axisLow) { - targetMarkers.axisLow = { - isFresh: true, - type: "axis", - value: targetAxis.outlierMin, - marker: this.markAxis("low", targetAxis) - }; - } - // Always refresh the status of the marker - targetMarkers.axisLow.isFresh = true; - } - }; - - /** - * Sets the outlier display state, which determines whether to display outlier markers. - * - * @param {string} newState The intended display state; should be one of: - *
    - *
  • "high" — Show high outliers; hide high outlier markers.
  • - *
  • "low" — Show low outliers; hide low outlier markers.
  • - *
  • "all" — Show high and low outliers; hide high and low outlier markers.
  • - *
  • "none" — Hide high and low outliers; show high and low outlier markers.
  • - *
- * If none of the above is provided, "none" is assumed. - * @param {object} targetAxis The y-axis on which the outlier state is set. **Note:** A - * chart or panel can have multiple y-axes. - * - * @alias setDisplayState - * @memberOf CIQ.Outliers.prototype - * @since - * - 7.5.0 - * - 8.0.0 Added `targetAxis` parameter. - */ - this.setDisplayState = function (newState, targetAxis) { - if (newState != "high" && newState != "low" && newState != "all") - newState = "none"; - - var displayState = newState; - // Set the value of displayState to show the intended state, based on its existing state. This - // allows the markers to toggle between states without concern for what is currently displayed. - // For example: if the current display state is showing low outlier only, and the intent is to - // now display high outliers as well, then the display state will change to 'all'. - // This will toggle the high/low state off as well. - if (targetAxis.displayState == "all" && newState == "high") - displayState = "low"; - else if (targetAxis.displayState == "all" && newState == "low") - displayState = "high"; - else if (targetAxis.displayState == "high" && newState == "low") - displayState = "all"; - else if (targetAxis.displayState == "low" && newState == "high") - displayState = "all"; - else if (targetAxis.displayState == newState) displayState = "none"; - - targetAxis.displayState = displayState; - // Reset the axis zoom state - targetAxis.axis.zoom = targetAxis.originalZoom; - - this.refreshMarkers(targetAxis); - this.stx.draw(); - }; - - /** - * Removes all markers from `targetAxis` that are no longer fresh; that is, markers that - * do not represent data points in the current data set, or axis markers that are - * irrelevant because high or low outliers no longer exist. Sets the status of all - * remaining outlier markers to stale, or not fresh (the freshness status should - * subsequently be reevaluated). - * - * @param {object} targetAxis The y-axis for which the markers are deprecated. **Note:** - * A chart or panel can have multiple y-axes; each y-axis has its own outlier - * markers based on the data rendered on the axis. - * - * @alias deprecateMarkers - * @memberOf CIQ.Outliers.prototype - * @since - * - 7.5.0 - * - 8.0.0 Added `targetAxis` parameter. - */ - this.deprecateMarkers = function (targetAxis) { - var removeMarker = function (marker) { - if (marker.marker && !marker.isFresh) { - if (marker.marker.remove) marker.marker.remove(); - marker.marker = null; - } else { - marker.isFresh = false; - } - }; - - // Handle the outlier markers - Object.keys(targetAxis.markers).forEach( - function (key) { - removeMarker(this.markers[key]); - // Remove the marker property if its marker has been removed - if (!this.markers[key].marker) { - delete this.markers[key]; - } - }.bind(targetAxis) - ); - }; - - /** - * Removes all outlier markers from `targetAxis`, including data point markers and y-axis - * markers. - * - * @param {object} targetAxis The y-axis from which the markers are removed. **Note:** - * Charts and panels can have multiple y-axes, each with its own outlier markers. - * - * @alias removeAllMarkers - * @memberOf CIQ.Outliers.prototype - * @since - * - 7.5.0 - * - 8.0.0 Added `targetAxis` parameter. - */ - this.removeAllMarkers = function (targetAxis) { - Object.keys(targetAxis.markers).forEach(function (key) { - var targetMarker = targetAxis.markers[key].marker; - if (targetMarker) { - if (targetMarker.remove) targetMarker.remove(); - targetMarker = null; - } - // Remove the marker property if its marker has been removed - if (!targetMarker) { - delete targetAxis.markers[key]; - } - }); - }; - - /** - * Shows or hides outlier markers based on the display state. - * - * See [setDisplayState]{@link CIQ.Outliers#setDisplayState}. - * - * @alias updateMarkerVisibility - * @memberOf CIQ.Outliers.prototype - * @since 7.5.0 - */ - this.updateMarkerVisibility = function () { - Object.keys(this.markers).forEach( - function (key) { - if ( - this.displayState == "all" || - this.markers[key].marker.node.classList.contains(this.displayState) - ) - this.markers[key].marker.node.style.display = "none"; - else this.markers[key].marker.node.style.display = "block"; - }.bind(this) - ); - }; - - /** - * Updates the position of the axis outlier marker represented by `node`. - * - * @param {HTMLElement} node The axis marker to position. - * @param {object} targetAxis The y-axis on which the axis marker is positioned. - * - * @alias refreshAxisMarkers - * @memberOf CIQ.Outliers.prototype - * @since - * - 7.5.0 - * - 8.0.0 Added `targetAxis` parameter. - */ - this.refreshAxisMarkers = function (node, targetAxis) { - var isHigh = false; - var positionClass = "low"; - if (node.classList.contains("high")) { - isHigh = true; - positionClass = "high"; - } - var posTop = targetAxis.axis.top; - // Set the low marker of reverse the value if the axis is flipped - if ( - (!targetAxis.isFlipped && !isHigh) || - (targetAxis.isFlipped && isHigh) - ) { - posTop = targetAxis.axis.bottom - 50; - } - // Overlap the markers in the center for nano size because it's all or nothing at that size. - if (node.classList.contains("nano")) { - posTop = targetAxis.axis.top + targetAxis.axis.height / 2 - 22; - } - - var xFormLeft = Math.floor(targetAxis.axis.left).toString() + "px"; - var xFormTop = Math.floor(posTop).toString() + "px"; - // Use the vlaue property instead - var labelPrice = isHigh ? targetAxis.outlierMax : targetAxis.outlierMin; - - // Set marker positioning relative to the y-axis - node.style.transform = "translate(" + xFormLeft + ", " + xFormTop + ")"; - node.querySelector( - ".outlier-value" - ).innerText = this.stx.formatYAxisPrice(labelPrice); - // Apply .right class when axis is on the left to right position child elements - if (xFormLeft === "0px") node.classList.add("right"); - else node.classList.remove("right"); - }; - - /** - * Updates the display styles of all outlier markers belonging to `targetAxis`, including - * data point markers and axis markers. Shows the markers if outliers are hidden and the - * marked outliers exceed the bounds of `targetAxis`. Flips the markers if `targetAxis` - * has been inverted (see [flipMarkers]{@link CIQ.Outliers#flipMarkers}). - * - * @param {object} targetAxis The y-axis on which the markers are refreshed. **Note:** - * Charts and panels can have multiple y-axes, each with its own outlier markers. - * - * @alias refreshMarkers - * @memberOf CIQ.Outliers.prototype - * @since 8.0.0 - */ - this.refreshMarkers = function (targetAxis) { - Object.keys(targetAxis.markers).forEach( - function (targetAxis, key) { - var targetMarker = targetAxis.markers[key].marker; - var targetValue = targetAxis.markers[key].value; - var targetType = targetAxis.markers[key].type; - // Check the marker value against the actual axis min/max. This accounts for yaxis scaling - // in addition to the outlier display state. - if ( - (targetValue > targetAxis.trendMax && - targetAxis.axis.high >= targetValue) || - (targetValue < targetAxis.trendMin && - targetAxis.axis.low <= targetValue) - ) { - if (targetType == "quote") { - targetMarker.node.style.display = "none"; - } else if (targetType == "axis") { - targetMarker.node.classList.add("compress"); - } - } else { - if (targetType == "quote") { - targetMarker.node.style.display = "block"; - } else if (targetType == "axis") { - targetMarker.node.classList.remove("compress"); - } - } - - if (targetType == "axis") { - this.refreshAxisMarkers(targetMarker.node, targetAxis); - } - - // Update the marker responsive style - if (targetAxis.axis.height < 100) - targetMarker.node.classList.add("nano"); - else targetMarker.node.classList.remove("nano"); - - if (targetAxis.axis.height < 250) - targetMarker.node.classList.add("micro"); - else targetMarker.node.classList.remove("micro"); - }.bind(this, targetAxis) - ); - - // Check for a change in the flipped state of the axis - if (targetAxis.isFlipped !== targetAxis.axis.flipped) - this.flipMarkers(targetAxis); - }; - - /** - * Places markers on the y-axis when high or low outliers exist. - * - * @param {string} position The position of the marker; either "high" or "low". If the - * position is "high", the marker is placed at the top of the axis; if "low", at the - * bottom of the axis. - * @param {object} targetAxis The y-axis on which the markers are placed. **Note:** - * Charts and panels can have multiple y-axes, each with its own outlier markers. - * @return {CIQ.Marker} The axis outlier marker, which is added to the display. - * - * @alias markAxis - * @memberOf CIQ.Outliers.prototype - * @since - * - 7.5.0 - * - 8.0.0 Added `position` and `targetAxis` parameters and return value. - */ - this.markAxis = function (position, targetAxis) { - // Create a marker positioned on the Y axis and return it. - var axisMarker = document.createElement("div"); - axisMarker.classList.add("outlier-sticker", "axis", "mini", position); - axisMarker.innerHTML = - '
'; - - this.matchYAxisStyle(axisMarker); - this.setMarkerColor(axisMarker, targetAxis.markerColor); - - var activate = this.handleMarkerClick.bind( - this, - position, - targetAxis, - axisMarker - ); - axisMarker.addEventListener("click", activate); - axisMarker.addEventListener("touchend", activate); - - return new CIQ.Marker({ - stx: this.stx, - xPositioner: "none", - yPositioner: "none", - label: "expand", - permanent: true, - chartContainer: true, - node: axisMarker - }); - }; - - /** - * Adds an outlier marker to a tick (data point). - * - * @param {object} data Represents the tick that is marked as an outlier. Contains the - * outlier value and its associated quote; for example, - * `{value: Number, quote: Object}`. - * @param {string} position The position of the marker; either "high" or "low". If the - * position is "high", the marker is placed at the top of the chart; if "low", at the - * bottom of the chart. - * @param {object} targetAxis The y-axis to which the marker is added. **Note:** A chart - * or panel can have multiple y-axes; each y-axis has its own outlier markers. - * @return {CIQ.Marker} The outlier marker, which is added to the display. - * - * @alias markOutlier - * @memberOf CIQ.Outliers.prototype - * @since - * - 7.5.0 - * - 8.0.0 Added `targetAxis` parameter. - */ - this.markOutlier = function (data, position, targetAxis) { - if (!data) return; - if (!targetAxis) targetAxis = { panel: this.stx.panels.chart }; - position = position || "high"; - - // Create a marker - var outlierMarker = document.createElement("div"); - outlierMarker.classList.add("outlier-sticker", "quote", "mini", position); - outlierMarker.innerHTML = - '
' + - this.stx.formatYAxisPrice(data.value, targetAxis.panel) + - ""; - - this.matchYAxisStyle(outlierMarker); - this.setMarkerColor(outlierMarker, targetAxis.markerColor); - - var activate = this.handleMarkerClick.bind( - this, - position, - targetAxis, - outlierMarker - ); - outlierMarker.addEventListener("click", activate); - outlierMarker.addEventListener("touchend", activate); - - return new CIQ.Marker({ - stx: this.stx, - xPositioner: "date", - yPositioner: position == "high" ? "top" : "bottom", - x: data.quote.DT, - panelName: targetAxis.panel.name, - node: outlierMarker - }); - }; - - /** - * Calls [setDisplayState]{@link CIQ.Outliers#setDisplayState} in response to selecting an - * outlier marker. - * - * @param {string} position The position of the marker; either "high" or "low". - * @param {object} targetAxis The y-axis that contains the selected marker. **Note:** - * Charts and panels can have multiple y-axes; each y-axis has its own outlier - * markers. - * @param {HTMLElement} targetNode The selected outlier marker DOM node. - * - * @alias handleMarkerClick - * @memberOf CIQ.Outliers.prototype - * @since 8.0.0 - */ - this.handleMarkerClick = function (position, targetAxis, targetNode) { - if (targetNode.classList.contains("nano")) position = "all"; // not concerned about differentiation between high and low at the nano size - this.setDisplayState(position, targetAxis); - this.stx.draw(); - }; - - /** - * Sets the CSS style properties of the y-axis outlier marker to match the CSS styling of - * the y-axis itself. - * - * @param {HTMLElement} node The y-axis marker to style. - * - * @alias matchYAxisStyle - * @memberOf CIQ.Outliers.prototype - * @since 7.5.0 - */ - this.matchYAxisStyle = function (node) { - // Apply styles from the yAxis - if (this.stx.styles.stx_yaxis) { - var styles = this.stx.styles.stx_yaxis; - node.style.fontSize = styles.fontSize; - node.style.fontFamily = styles.fontFamily; - node.style.color = styles.color; - node.style.borderColor = styles.color; - } - }; - - /** - * Applies a background color to an outlier data point marker. - * - * @param {HTMLElement} node The outlier marker DOM node to which the background color is - * applied. - * @param {string} color The hexadecimal color value set as the node background color. - * - * @alias setMarkerColor - * @memberOf CIQ.Outliers.prototype - * @since 8.0.0 - */ - this.setMarkerColor = function (node, color) { - if (color == "") return; - //Set marker color - var markerPills = node.querySelectorAll(".pill"); - for (var markerIdx = 0; markerIdx < markerPills.length; markerIdx++) { - markerPills[markerIdx].style.backgroundColor = color; - } - }; - - /** - * Repositions outlier markers from the top of the display to the bottom (or vice versa) - * when the associated y-axis has been flipped (inverted). - * - * @param {object} targetAxis The y-axis that has been flipped. - * - * @alias flipMarkers - * @memberOf CIQ.Outliers.prototype - * @since 8.0.0 - */ - this.flipMarkers = function (targetAxis) { - targetAxis.isFlipped = targetAxis.axis.flipped; - - Object.keys(targetAxis.markers).forEach( - function (targetAxis, key) { - var targetMarker = targetAxis.markers[key].marker; - var targetValue = targetAxis.markers[key].value; - var targetType = targetAxis.markers[key].type; - // Check for flipped state and add/remove flipped class - if (targetAxis.isFlipped) { - targetMarker.node.classList.add("flipped"); - } else { - targetMarker.node.classList.remove("flipped"); - } - - // Set Y positioning of quote markers - if (targetType == "quote") { - if (targetValue > targetAxis.trendMax) { - // High marker - if (targetAxis.isFlipped) - targetMarker.params.yPositioner = "bottom"; - else targetMarker.params.yPositioner = "top"; - } else if (targetValue < targetAxis.trendMin) { - // Low marker - if (targetAxis.isFlipped) targetMarker.params.yPositioner = "top"; - else targetMarker.params.yPositioner = "bottom"; - } - } - }.bind(this, targetAxis) - ); - }; - - var originalDetermineMinMax = CIQ.ChartEngine.prototype.determineMinMax.bind( - this.stx - ); - /** - * Overrides the default `CIQ.ChartEngine.prototype.determineMinMax` function when the - * Outliers add-on is active. Injects the local {@link CIQ.Outliers#processDataSet} - * function as a data filter and passes the filter along to the original `determineMinMax` - * function (see below). - * - * @param {Array} quotes The array of quotes (typically - * `CIQ.ChartEngine.chart.dataSegment`) to evaluate for minimum and maximum values. - * @param {Array} fields A list of fields to compare. - * @param {boolean|Array} [sum] If true, then compute maximum sum rather than the maximum - * single value across all fields. If an array, compute sum over just the fields in - * the array. - * @param {boolean} [bypassTransform] If true, bypass any transformations. - * @param {number} [length] Specifies how many elements of the quotes array to process. - * @param {boolean} [checkArray] If true, the type of the value used to determine the - * min/max is checked to ascertain whether it is an array; if so, the first element - * of the array is retrieved for use in the min/max determination. - * @param {CIQ.ChartEngine.Panel} [panel] A reference to the panel rendering the quotes. - * @param {CIQ.ChartEngine.YAxis} [axis] A reference to the y-axis rendered for the quotes. - * @param {Array} [filters] Array of functions to process the min/max values before - * returning. Filter functions must return a valid min/max tuple or false. - * @return {function} A reference to the original - * `CIQ.ChartEngine.prototype.determineMinMax` library function. - * - * @memberof CIQ.ChartEngine - * @since - * - 7.5.0 - * - 8.0.0 Allow the `sum` parameter to be an array of valid fields to sum over. - * Added the `panel`, `axis`, and `filters` parameters. - * @private - */ - CIQ.ChartEngine.prototype.determineMinMax = function ( - quotes, - fields, - sum, - bypassTransform, - length, - checkArray, - panel, - axis, - filters - ) { - if (!filters) filters = []; - if (panel && axis && this.layout.outliers) - filters.push(this.outliers.processDataSet.bind(this.outliers)); - return originalDetermineMinMax( - quotes, - fields, - sum, - bypassTransform, - length, - checkArray, - panel, - axis, - filters - ); - }; - }; - -/** - * CIQ.Marker interface placeholder to be augmented in *standard.js* with properties. - * - * @tsinterface CIQ~Marker - */ - -}; - - -let __js_addons_advanced_plotComplementer_ = (_exports) => { - -/* global _CIQ, _timezoneJS, _SplinePlotter */ - -var CIQ = typeof _CIQ !== "undefined" ? _CIQ : _exports.CIQ; - -/** - * Creates an add-on that enables a series to complement another series. - * - * ![Plot Complementer](./img-Data-Forecasting.png) - * - * The complementary series is a permanent fixture of the series which it complements. It moves - * in tandem with the series, and gets removed with the series. In all other respects, though, it - * behaves like its own series. It shows separately in the panel legend and plots using its own - * renderer. - * - * Charts can have multiple `PlotComplementer` instances. Each instance is attached to the chart - * engine as a member of a `PlotComplementer` collection. - * - * Multiple `PlotComplementer` instances can be associated with a time series. To link a - * `PlotComplementer` to a series, specify the series instrument in the `params.filter` function. - * See `[setQuoteFeed]{@link CIQ.PlotComplementer#setQuoteFeed}`. - * - * **Note:** The series created by this add-on is not exported with the layout, since it is - * created in tandem with the series it complements. Currently, this feature works only with - * non-comparison series. - * - * Requires *addOns.js*. - * - * @param {object} params Configuration parameters. - * @param {CIQ.ChartEngine} params.stx The chart object. - * @param {string} [params.id] Unique key used by the add-on to identify itself. If not supplied, - * a random key is chosen. - * @param {object} [params.quoteFeed] Attaches the quote feed to the quote driver to satisfy any - * quote requests for any series created by the add-on. - * @param {object} [params.behavior] Used as the behavior for the quote feed supplied in this - * parameter list. - * @param {function} [params.filter] Used as the filter for the quote feed supplied in this - * parameter list. See `[setQuoteFeed]{@link CIQ.PlotComplementer#setQuoteFeed}`. - * @param {object} [params.decorator] Container object for the `symbol` and `display` properties. - * The `decorator` provides the label (`symbol`) for the complementary series and a short - * description (`display`) that is appended to the label; for example: - * ``` - * decorator: {symbol:"_fcst", display:" Forecast"} - * ``` - * @param {string} [params.decorator.symbol] Adds this string onto the ID when creating the - * complementary series. Otherwise, a unique ID is used. - * @param {string} [params.decorator.display] Customizes the display value of the series. - * @param {object} [params.renderingParameters={chartType: "line", width: 1, opacity: 0.5}] A - * collection of parameters that override the default rendering parameters. The - * `renderingParameters` object can be set or changed at any time. The default parameters - * can be restored by calling {@link CIQ.PlotComplementer#resetRenderingParameters}. - *

Here are a few examples of rendering parameters:

- * ``` - * // Assuming a PlotComplementer declared as "forecaster": - * forecaster.renderingParameters = {chartType:"scatterplot", opacity:0.5, field:"Certainty"} - * forecaster.renderingParameters = {chartType:"histogram", border_color:"transparent", opacity:0.3} - * forecaster.renderingParameters = {chartType:"channel", opacity:0.5, pattern:"dotted"} - * forecaster.renderingParameters = {chartType:"candle", opacity:0.5, color:"blue", border_color:"blue"} - * ``` - * - * @constructor - * @name CIQ.PlotComplementer - * @since 7.3.0 - * - * @example Forecasting - * let forecaster = new CIQ.PlotComplementer({ - * stx:stxx, - * id:"forecast", - * quoteFeed: fcstFeed.quoteFeedForecastSimulator, - * behavior: {refreshInterval:60}, - * decorator: {symbol:"_fcst", display:" Forecast"}, - * renderingParameters: {chartType:"channel", opacity:0.5, pattern:"dotted"} - * }); - */ -CIQ.PlotComplementer = - CIQ.PlotComplementer || - function (params) { - var stx = params.stx; - var unique = CIQ.uniqueID(); - if (!params.decorator) params.decorator = {}; - var symbolDecorator = params.decorator.symbol || "_" + unique; - var displayDecorator = params.decorator.display || " (addl)"; - if (!stx.plotComplementers) stx.plotComplementers = []; - stx.plotComplementers.push(this); - - this.id = params.id || unique; - - this.defaultRenderingParameters = { - chartType: "line", - width: 1, - opacity: 0.5 - }; - - if (params.renderingParameters) - this.defaultRenderingParameters = params.renderingParameters; - - var self = this; - function addSeries(stx, symbol, parameters, id) { - function verifyQuoteFeed(stx) { - if (!stx.quoteDriver) return; - if (!params.quoteFeed) return; - for (var qf = 0; qf < stx.quoteDriver.quoteFeeds.length; qf++) { - if (stx.quoteDriver.quoteFeeds[qf].engine == params.quoteFeed) return; - } - return "err"; - } - if (verifyQuoteFeed(stx) == "err") return; - if (!id) id = symbol; - if (stx.isEquationChart(symbol)) return; - if (!parameters) parameters = {}; - if (parameters.isComparison) return; - if (id && id.indexOf(symbolDecorator) == -1) { - var fId = id + symbolDecorator, - fSymbol = symbol + symbolDecorator; - var masterRenderer = stx.getRendererFromSeries(id); - var myParms = CIQ.extend( - { - display: symbol + displayDecorator, - name: fId, - symbol: fSymbol, - symbolObject: { - symbol: fSymbol, - generator: self.id, - masterSymbol: symbol - }, - overChart: false, - gapDisplayStyle: true, - permanent: true, - panel: parameters.panel, - yAxis: parameters.yAxis, - shareYAxis: true, - loadData: !!self.quoteFeed, - dependentOf: masterRenderer - ? masterRenderer.params.name - : stx.mainSeriesRenderer.params.name - }, - self.renderingParameters - ); - if (!myParms.color) myParms.color = parameters.color || "auto"; - stx.addSeries(fId, myParms, function (error, obj) { - if (error) stx.removeSeries(fId, stx.chart); - if (stx.chart.seriesRenderers[fId]) { - stx.chart.seriesRenderers[fId].params.display = myParms.display; - } - }); - } - } - - function removeSeries(stx, id, chart) { - if (id && id.indexOf(symbolDecorator) == -1) - stx.removeSeries(id + symbolDecorator, chart); - } - - function symbolChange(obj) { - if (obj.action == "master") { - if (!obj.prevSymbol) obj.prevSymbol = obj.symbol; - removeSeries(obj.stx, obj.prevSymbol, obj.stx.chart); - addSeries(obj.stx, obj.symbol); - } else if (obj.action == "add-series") { - removeSeries(obj.stx, obj.id, obj.stx.chart); - addSeries(obj.stx, obj.symbol, obj.parameters, obj.id); - } else if (obj.action == "remove-series") { - removeSeries(obj.stx, obj.id, obj.stx.chart); - } - } - - stx.addEventListener("symbolChange", symbolChange); - stx.addEventListener("symbolImport", symbolChange); - - /** - * Resets the `PlotComplementer` rendering values to the default settings. - * - * Default settings can be provided in the parameters passed to the `PlotComplementer` constructor. If no settings are - * provided to the constructor, `PlotComplementer` uses the following defaults: `{ chartType:"line", width:1, opacity:0.5 }`. - * - * The rendering parameters may be set anytime after creating `PlotComplementer`; for example, to set an ad-hoc rendering - * right before adding a series. - * - * @alias resetRenderingParameters - * @memberof CIQ.PlotComplementer.prototype - * @since 7.3.0 - */ - this.resetRenderingParameters = function () { - this.renderingParameters = this.defaultRenderingParameters; - }; - - /** - * Sets a quote feed for the `PlotComplementer`. - * - * Automatically called when a quote feed is provided in the constructor argument. If a - * quote feed or `behavior` object is not specified in `params`, this function returns - * without doing anything. - * - * @param {object} params Configuration parameters. - * @param {object} params.quoteFeed Quote feed to attach to the quote driver to satisfy - * any quote requests for any series created by the add-on. This quote feed is like - * any time series quote feed object. See the - * [Data Integration Overview]{@tutorial DataIntegrationOverview}. - * @param {object} params.behavior Behavior for the quote feed supplied in this parameter - * list. This object is like any `behavior` object associated with a quote feed. - * See {@link CIQ.ChartEngine#attachQuoteFeed} for more information on `behavior` - * objects. - * @param {function} [params.filter] Filters the quote feed supplied in this parameter - * list. The filter function takes as an argument an object typically containing - * `symbolObject`, `symbol`, and `interval` properties. The properties associate the - * `PlotComplementer` with an instrument. If the `filter` function returns true, the - * `PlotComplementer` quote feed is used for the instrument. - *

This `filter` function is like the `filter` in basic quote feeds. - * See {@link CIQ.ChartEngine#attachQuoteFeed} for more information on quote feed - * `filter` functions.

- * @alias setQuoteFeed - * @memberof CIQ.PlotComplementer.prototype - * @since 7.3.0 - */ - this.setQuoteFeed = function (params) { - if (!params.quoteFeed || !params.behavior) return; - var behavior = CIQ.clone(params.behavior); - behavior.generator = this.id; - var existingFilter = params.filter; - var filter = function (params) { - if (existingFilter && !existingFilter(params)) return false; - return params.symbolObject.generator == behavior.generator; - }; - stx.attachQuoteFeed(params.quoteFeed, behavior, filter); - this.quoteFeed = params.quoteFeed; - }; - - this.setQuoteFeed(params); - this.resetRenderingParameters(); - }; - -}; - - -let _exports = {CIQ:__CIQ_}; -export {__js_addons_standard_extendedHours_ as extendedHours}; -export {__js_addons_standard_fullScreen_ as fullScreen}; -export {__js_addons_standard_inactivityTimer_ as inactivityTimer}; -export {__js_addons_standard_rangeSlider_ as rangeSlider}; -export {__js_addons_standard_shortcuts_ as shortcuts}; -export {__js_addons_standard_tableView_ as tableView}; -export {__js_addons_standard_tooltip_ as tooltip}; -export {__js_addons_advanced_animation_ as animation}; -export {__js_addons_advanced_continuousZoom_ as continuousZoom}; -export {__js_addons_advanced_outliers_ as outliers}; -export {__js_addons_advanced_plotComplementer_ as plotComplementer}; - -export {__CIQ_ as CIQ}; - -/* global __TREE_SHAKE__ */ -if (typeof __TREE_SHAKE__ === "undefined" || !__TREE_SHAKE__) { - _exports.CIQ.activateImports( - __js_addons_standard_extendedHours_, - __js_addons_standard_fullScreen_, - __js_addons_standard_inactivityTimer_, - __js_addons_standard_rangeSlider_, - __js_addons_standard_shortcuts_, - __js_addons_standard_tableView_, - __js_addons_standard_tooltip_, - __js_addons_advanced_animation_, - __js_addons_advanced_continuousZoom_, - __js_addons_advanced_outliers_, - __js_addons_advanced_plotComplementer_, - null - ); -} \ No newline at end of file diff --git a/chartiq/production/js/advanced.js b/chartiq/production/js/advanced.js deleted file mode 100644 index 456fa9506b..0000000000 --- a/chartiq/production/js/advanced.js +++ /dev/null @@ -1,25 +0,0 @@ -/**! - * 8.2.0 - * Generation date: 2023-03-23T15:05:01.971Z - * Client name: deriv limited - * Package Type: Technical Analysis - * License type: annual - * Expiration date: "2024/04/01" - * Domain lock: ["127.0.0.1","localhost","deriv.com","deriv.app","deriv.me","binary.com","binary.sx","binary.me","binary.bot","deriv.be"] - * iFrame lock: true - */ - -/***********************************************************! - * Copyright by ChartIQ, Inc. - * Licensed under the ChartIQ, Inc. Developer License Agreement https://www.chartiq.com/developer-license-agreement -*************************************************************/ -/*************************************! DO NOT MAKE CHANGES TO THIS LIBRARY FILE!! !************************************* -* If you wish to overwrite default functionality, create a separate file with a copy of the methods you are overwriting * -* and load that file right after the library has been loaded, but before the chart engine is instantiated. * -* Directly modifying library files will prevent upgrades and the ability for ChartIQ to support your solution. * -*************************************************************************************************************************/ -/* eslint-disable no-extra-parens */ - - -/* eslint-disable */ /* jshint ignore:start */ /* ignore jslint start */ -f3BGj[539515]=(function(){var o97=2;for(;o97 !== 9;){switch(o97){case 2:o97=typeof globalThis === '\x6f\x62\x6a\u0065\x63\x74'?1:5;break;case 1:return globalThis;break;case 5:var e12;o97=4;break;case 4:try{var F2R=2;for(;F2R !== 6;){switch(F2R){case 2:Object['\u0064\x65\x66\u0069\x6e\u0065\u0050\u0072\u006f\u0070\x65\u0072\x74\x79'](Object['\x70\u0072\u006f\x74\u006f\x74\u0079\x70\x65'],'\x53\u006a\u0039\u0047\x33',{'\x67\x65\x74':function(){var y2w=2;for(;y2w !== 1;){switch(y2w){case 2:return this;break;}}},'\x63\x6f\x6e\x66\x69\x67\x75\x72\x61\x62\x6c\x65':true});e12=Sj9G3;F2R=5;break;case 5:e12['\x6b\u006e\u0071\x48\x4f']=e12;F2R=4;break;case 4:F2R=typeof knqHO === '\x75\u006e\x64\u0065\u0066\u0069\u006e\u0065\x64'?3:9;break;case 3:throw "";F2R=9;break;case 9:delete e12['\x6b\x6e\u0071\u0048\x4f'];var o2V=Object['\u0070\x72\u006f\u0074\u006f\x74\x79\u0070\x65'];delete o2V['\x53\x6a\u0039\x47\u0033'];F2R=6;break;}}}catch(c1C){e12=window;}return e12;break;}}})();r$KpDA(f3BGj[539515]);f3BGj.c0C=function(){return typeof f3BGj[446427].N$y1PkD === 'function'?f3BGj[446427].N$y1PkD.apply(f3BGj[446427],arguments):f3BGj[446427].N$y1PkD;};f3BGj[238553]=false;f3BGj[150014]=f3BGj[370258];f3BGj[539515].u7SS=f3BGj;f3BGj.j7J=function(){return typeof f3BGj[446427].g9iUvuS === 'function'?f3BGj[446427].g9iUvuS.apply(f3BGj[446427],arguments):f3BGj[446427].g9iUvuS;};f3BGj.S9Y=function(){return typeof f3BGj[370258].V29cT4d === 'function'?f3BGj[370258].V29cT4d.apply(f3BGj[370258],arguments):f3BGj[370258].V29cT4d;};f3BGj.O1W=function(){return typeof f3BGj[370258].V29cT4d === 'function'?f3BGj[370258].V29cT4d.apply(f3BGj[370258],arguments):f3BGj[370258].V29cT4d;};f3BGj.N_M=function(){return typeof f3BGj[446427].g9iUvuS === 'function'?f3BGj[446427].g9iUvuS.apply(f3BGj[446427],arguments):f3BGj[446427].g9iUvuS;};f3BGj[593596]=(function(){var v66=2;for(;v66 !== 9;){switch(v66){case 2:var g_Z=[arguments];g_Z[3]=undefined;g_Z[4]={};g_Z[4].i9agN$W=function(){var d2j=2;for(;d2j !== 90;){switch(d2j){case 5:return 11;break;case 49:B3o[5].x7dT3(B3o[65]);B3o[5].x7dT3(B3o[77]);B3o[5].x7dT3(B3o[86]);d2j=46;break;case 58:B3o[58]=0;d2j=57;break;case 4:B3o[5]=[];B3o[9]={};B3o[9].r6o=['J4I'];d2j=8;break;case 67:g_Z[3]=27;return 94;break;case 68:d2j=67?68:67;break;case 57:d2j=B3o[58] < B3o[5].length?56:69;break;case 59:B3o[87]='o5_';d2j=58;break;case 56:B3o[12]=B3o[5][B3o[58]];try{B3o[22]=B3o[12][B3o[64]]()?B3o[74]:B3o[61];}catch(r_G){B3o[22]=B3o[61];}d2j=77;break;case 15:B3o[4]=B3o[7];B3o[66]={};B3o[66].r6o=['Y1H'];B3o[66].w$b=function(){var n1P=false;var Q4J=[];try{for(var N8I in console){Q4J.x7dT3(N8I);}n1P=Q4J.length === 0;}catch(P6i){}var s42=n1P;return s42;};B3o[86]=B3o[66];B3o[55]={};B3o[55].r6o=['J4I'];d2j=21;break;case 63:B3o[61]='X51';B3o[11]='r6o';B3o[52]='B5u';B3o[64]='w$b';d2j=59;break;case 76:d2j=B3o[45] < B3o[12][B3o[11]].length?75:70;break;case 21:B3o[55].w$b=function(){var K1g=function(){return ('aaa').includes('a');};var i9C=(/\u0074\x72\165\x65/).F5rmB(K1g + []);return i9C;};B3o[77]=B3o[55];B3o[18]={};d2j=33;break;case 11:B3o[8]={};B3o[8].r6o=['Y1H'];B3o[8].w$b=function(){var V7q=typeof J6SFs === 'function';return V7q;};B3o[3]=B3o[8];B3o[7]={};B3o[7].r6o=['J4I'];B3o[7].w$b=function(){var O8c=function(){return ('x').toUpperCase();};var M9G=(/\130/).F5rmB(O8c + []);return M9G;};d2j=15;break;case 70:B3o[58]++;d2j=57;break;case 36:B3o[44]=B3o[83];B3o[5].x7dT3(B3o[44]);B3o[5].x7dT3(B3o[1]);B3o[5].x7dT3(B3o[94]);d2j=51;break;case 14:B3o[6].r6o=['J4I'];B3o[6].w$b=function(){var m1i=function(){return ('a|a').split('|');};var X9f=!(/\x7c/).F5rmB(m1i + []);return X9f;};B3o[2]=B3o[6];d2j=11;break;case 33:B3o[18].r6o=['Y1H'];B3o[18].w$b=function(){var T8c=typeof p8bC00 === 'function';return T8c;};B3o[65]=B3o[18];B3o[46]={};d2j=29;break;case 51:B3o[5].x7dT3(B3o[3]);B3o[5].x7dT3(B3o[2]);d2j=49;break;case 8:B3o[9].w$b=function(){var q2b=function(){return unescape('%3D');};var o6o=(/\x3d/).F5rmB(q2b + []);return o6o;};B3o[1]=B3o[9];B3o[6]={};d2j=14;break;case 1:d2j=g_Z[3]?5:4;break;case 75:B3o[42]={};B3o[42][B3o[87]]=B3o[12][B3o[11]][B3o[45]];B3o[42][B3o[52]]=B3o[22];B3o[70].x7dT3(B3o[42]);d2j=71;break;case 71:B3o[45]++;d2j=76;break;case 2:var B3o=[arguments];d2j=1;break;case 46:B3o[5].x7dT3(B3o[25]);B3o[5].x7dT3(B3o[4]);B3o[70]=[];B3o[74]='y8Q';d2j=63;break;case 29:B3o[46].r6o=['J4I'];B3o[46].w$b=function(){var w08=function(){return ('aa').charCodeAt(1);};var J8E=(/\u0039\x37/).F5rmB(w08 + []);return J8E;};B3o[25]=B3o[46];B3o[69]={};B3o[69].r6o=['J4I'];B3o[69].w$b=function(){var X2V=function(){return [1,2,3,4,5].concat([5,6,7,8]);};var r7$=!(/\x28\x5b/).F5rmB(X2V + []);return r7$;};B3o[94]=B3o[69];d2j=39;break;case 69:d2j=(function(f16){var z7T=2;for(;z7T !== 22;){switch(z7T){case 16:z7T=J1X[3] < J1X[4].length?15:23;break;case 10:z7T=J1X[2][B3o[52]] === B3o[74]?20:19;break;case 4:J1X[7]={};J1X[4]=[];J1X[3]=0;z7T=8;break;case 26:z7T=J1X[5] >= 0.5?25:24;break;case 19:J1X[3]++;z7T=7;break;case 12:J1X[4].x7dT3(J1X[2][B3o[87]]);z7T=11;break;case 20:J1X[7][J1X[2][B3o[87]]].h+=true;z7T=19;break;case 13:J1X[7][J1X[2][B3o[87]]]=(function(){var q4B=2;for(;q4B !== 9;){switch(q4B){case 1:W$K[8]={};W$K[8].h=0;W$K[8].t=0;return W$K[8];break;case 2:var W$K=[arguments];q4B=1;break;}}}).X9kuFN(this,arguments);z7T=12;break;case 7:z7T=J1X[3] < J1X[0][0].length?6:18;break;case 5:return;break;case 11:J1X[7][J1X[2][B3o[87]]].t+=true;z7T=10;break;case 2:var J1X=[arguments];z7T=1;break;case 1:z7T=J1X[0][0].length === 0?5:4;break;case 23:return J1X[9];break;case 25:J1X[9]=true;z7T=24;break;case 18:J1X[9]=false;z7T=17;break;case 15:J1X[8]=J1X[4][J1X[3]];J1X[5]=J1X[7][J1X[8]].h / J1X[7][J1X[8]].t;z7T=26;break;case 8:J1X[3]=0;z7T=7;break;case 17:J1X[3]=0;z7T=16;break;case 6:J1X[2]=J1X[0][0][J1X[3]];z7T=14;break;case 24:J1X[3]++;z7T=16;break;case 14:z7T=typeof J1X[7][J1X[2][B3o[87]]] === 'undefined'?13:11;break;}}})(B3o[70])?68:67;break;case 77:B3o[45]=0;d2j=76;break;case 39:B3o[83]={};B3o[83].r6o=['Y1H'];B3o[83].w$b=function(){var H3L=typeof x1ydXa === 'function';return H3L;};d2j=36;break;}}};return g_Z[4];break;}}})();f3BGj[103941]=f3BGj[593596];f3BGj[156040]=false;function f3BGj(){}f3BGj.a$j=function(){return typeof f3BGj[446427].N$y1PkD === 'function'?f3BGj[446427].N$y1PkD.apply(f3BGj[446427],arguments):f3BGj[446427].N$y1PkD;};f3BGj[446427]=(function(W63){return {N$y1PkD:function(){var g4l,x$W=arguments;switch(W63){case 178:g4l=(x$W[1] + x$W[4] + x$W[0]) / x$W[3] - x$W[2];break;case 153:g4l=x$W[0] > x$W[1];break;case 85:g4l=(x$W[0] - x$W[1]) * x$W[2] - x$W[3];break;case 42:g4l=((x$W[2] | x$W[4]) + x$W[3]) / x$W[1] / x$W[0];break;case 118:g4l=(x$W[2] + x$W[0] - x$W[1]) * x$W[4] - x$W[3];break;case 103:g4l=(-x$W[0] - x$W[1]) * x$W[2] + x$W[3];break;case 161:g4l=(x$W[0] + x$W[4] + x$W[2]) * x$W[3] - x$W[1];break;case 166:g4l=x$W[0] * -x$W[1];break;case 156:g4l=x$W[1] / x$W[4] * x$W[2] / x$W[3] - x$W[0];break;case 89:g4l=-(x$W[1] - x$W[0]) * x$W[2] + x$W[3];break;case 146:g4l=x$W[4] * x$W[3] - x$W[1] + x$W[2] - x$W[0];break;case 133:g4l=-x$W[4] + x$W[3] - x$W[0] + x$W[1] - x$W[2];break;case 55:g4l=x$W[1] / x$W[3] * x$W[0] - x$W[2];break;case 37:g4l=(x$W[3] - x$W[0] - x$W[2]) / x$W[4] + x$W[1];break;case 67:g4l=(x$W[3] - x$W[1]) * (x$W[6] - x$W[4]) / (x$W[2] - x$W[0]) + x$W[5];break;case 109:g4l=x$W[1] - x$W[4] + x$W[0] - x$W[2] + x$W[3];break;case 70:g4l=(-x$W[2] + x$W[3]) / x$W[0] * x$W[1] - x$W[4];break;case 87:g4l=x$W[3] / x$W[1] * x$W[0] / x$W[4] + x$W[2];break;case 132:g4l=(-x$W[0] + x$W[4] - x$W[1]) / x$W[3] + x$W[2];break;case 157:g4l=x$W[3] - x$W[4] - x$W[2] + x$W[1] + x$W[0];break;case 90:g4l=(-x$W[1] - x$W[0]) * x$W[4] / x$W[2] + x$W[3];break;case 5:g4l=x$W[1] * x$W[0];break;case 119:g4l=(-x$W[2] + x$W[0]) * x$W[3] + x$W[1];break;case 44:g4l=(x$W[3] + x$W[0]) * x$W[1] - x$W[2];break;case 68:g4l=(x$W[2] - x$W[3]) / x$W[1] + x$W[0];break;case 186:g4l=-x$W[2] * x$W[0] * x$W[1] + x$W[3];break;case 1:g4l=x$W[0] + x$W[1];break;case 74:g4l=+x$W[0] / x$W[1];break;case 15:g4l=x$W[0] - x$W[2] + x$W[1];break;case 111:g4l=x$W[2] * x$W[0] / x$W[1];break;case 165:g4l=(x$W[5] >> x$W[4]) - x$W[3] / (x$W[0] + x$W[1] / x$W[2]);break;case 60:g4l=(x$W[3] - x$W[2]) / (x$W[0] - x$W[1]);break;case 58:g4l=(x$W[3] | x$W[2]) * x$W[1] - x$W[0];break;case 158:g4l=x$W[0] * (x$W[3] % (+x$W[1] / x$W[2]));break;case 30:g4l=x$W[2] / x$W[4] / x$W[1] + x$W[3] + x$W[0];break;case 129:g4l=(x$W[3] * x$W[0] - x$W[2]) * x$W[4] - x$W[1];break;case 45:g4l=-x$W[1] / x$W[0] + x$W[3] - x$W[2];break;case 126:g4l=(x$W[1] / x$W[2] + x$W[4]) * x$W[0] - x$W[3];break;case 0:g4l=x$W[2] * x$W[3] - x$W[1] - x$W[0];break;case 34:g4l=-x$W[2] / x$W[1] + x$W[0];break;case 125:g4l=x$W[4] - x$W[0] - x$W[2] + x$W[1] - x$W[3];break;case 172:g4l=-x$W[2] + x$W[3] - x$W[0] + x$W[1];break;case 57:g4l=x$W[4] * x$W[1] * x$W[2] - x$W[3] - x$W[0];break;case 134:g4l=-x$W[0] - x$W[3] + x$W[2] + x$W[1];break;case 17:g4l=x$W[2] * x$W[1] + x$W[3] - x$W[0];break;case 19:g4l=x$W[2] * x$W[0] * x$W[1] - x$W[3];break;case 25:g4l=x$W[2] + x$W[0] * x$W[1];break;case 99:g4l=(x$W[0] + x$W[1] * x$W[2]) / x$W[3];break;case 113:g4l=-x$W[2] / x$W[1] / x$W[3] * x$W[4] + x$W[0];break;case 18:g4l=x$W[2] * x$W[3] / x$W[1] - x$W[0];break;case 121:g4l=x$W[1] * x$W[4] * x$W[2] + (x$W[5] - x$W[3] * x$W[0]) * x$W[6];break;case 145:g4l=x$W[3] / x$W[2] + x$W[1] - x$W[4] - x$W[0];break;case 177:g4l=x$W[3] - x$W[1] * (x$W[4] | x$W[0]) - x$W[2];break;case 144:g4l=x$W[4] * (x$W[1] / x$W[2] - (x$W[3] | x$W[0]));break;case 95:g4l=(x$W[4] * x$W[3] + x$W[2]) / (x$W[1] - x$W[0]);break;case 31:g4l=x$W[0] >> x$W[1];break;case 160:g4l=x$W[3] / x$W[1] * x$W[0] + x$W[2];break;case 154:g4l=x$W[0] * (x$W[2] + x$W[1]);break;case 174:g4l=-x$W[0] * x$W[1] / x$W[4] + x$W[2] - x$W[3];break;case 47:g4l=x$W[0] + +x$W[1];break;case 163:g4l=x$W[4] * x$W[3] / x$W[2] - x$W[0] + x$W[1];break;case 100:g4l=(x$W[3] + x$W[4]) / x$W[2] / x$W[1] - x$W[0];break;case 26:g4l=x$W[0] - +x$W[2] * x$W[1];break;case 175:g4l=x$W[3] - x$W[2] * x$W[0] - x$W[1];break;case 83:g4l=x$W[0] - x$W[4] + x$W[3] + x$W[2] - x$W[1];break;case 143:g4l=x$W[1] / x$W[0] + x$W[2] + x$W[3];break;case 92:g4l=x$W[0] + (x$W[5] - x$W[2]) / (x$W[3] - x$W[4]) * (x$W[6] - x$W[1]);break;case 122:g4l=(x$W[0] + x$W[3]) / x$W[2] - x$W[1];break;case 98:g4l=(x$W[0] + x$W[2] * x$W[1]) / +x$W[3];break;case 120:g4l=x$W[3] * x$W[2] - x$W[0] + x$W[1];break;case 10:g4l=x$W[1] * x$W[0] / x$W[2] / x$W[3];break;case 84:g4l=(x$W[0] + x$W[2]) / +x$W[1];break;case 169:g4l=(x$W[3] - x$W[1]) / x$W[0] - x$W[2];break;case 2:g4l=(x$W[1] + x$W[0]) / x$W[2];break;case 91:g4l=(x$W[1] + x$W[3]) / x$W[0] - x$W[2] + x$W[4];break;case 29:g4l=x$W[1] << x$W[0];break;case 155:g4l=x$W[1] * x$W[3] / x$W[2] + x$W[0];break;case 137:g4l=-x$W[2] * x$W[3] / x$W[0] + x$W[1];break;case 73:g4l=(x$W[0] << x$W[2]) / (x$W[1] * x$W[3]);break;case 117:g4l=x$W[2] / x$W[3] + x$W[1] + x$W[4] - x$W[0];break;case 93:g4l=(x$W[3] - x$W[4] - x$W[1]) * x$W[0] + x$W[2];break;case 9:g4l=x$W[2] * x$W[1] - x$W[0];break;case 114:g4l=x$W[0] - (x$W[1] | x$W[2]);break;case 51:g4l=-x$W[1] / x$W[3] - x$W[2] + x$W[0];break;case 3:g4l=x$W[2] + x$W[1] - x$W[0];break;case 38:g4l=(x$W[0] - x$W[2]) * x$W[3] + x$W[1];break;case 176:g4l=x$W[2] + x$W[1] * x$W[3] + x$W[0];break;case 96:g4l=((x$W[2] >> x$W[3]) * x$W[1] + x$W[0]) / x$W[4];break;case 184:g4l=x$W[3] / x$W[1] - x$W[2] + x$W[0];break;case 116:g4l=(x$W[2] + +x$W[1]) * x$W[0];break;case 75:g4l=x$W[3] + (x$W[1] - x$W[0]) / x$W[2];break;case 106:g4l=(x$W[2] - (x$W[1] + (x$W[3] ^ x$W[0]))) / x$W[4];break;case 32:g4l=x$W[2] - (x$W[0] - x$W[1]);break;case 152:g4l=(-x$W[0] - x$W[2]) / x$W[1] - x$W[3];break;case 21:g4l=-x$W[2] * x$W[1] + x$W[0];break;case 43:g4l=+x$W[3] * x$W[1] - x$W[2] - x$W[0];break;case 115:g4l=x$W[1] + (x$W[0] << x$W[2]);break;case 63:g4l=x$W[2] - x$W[0] - x$W[1];break;case 35:g4l=x$W[1] / x$W[2] - x$W[0];break;case 71:g4l=(x$W[3] - x$W[4]) * x$W[0] * x$W[2] + x$W[1];break;case 79:g4l=(x$W[2] * x$W[3] - x$W[5] * x$W[6]) / (x$W[4] * x$W[1] - x$W[0]);break;case 7:g4l=x$W[0] / x$W[1];break;case 127:g4l=x$W[0] - x$W[3] - x$W[1] - x$W[4] + x$W[2];break;case 69:g4l=x$W[1] * x$W[2] + x$W[0];break;case 104:g4l=x$W[3] + x$W[2] + x$W[1] - x$W[4] - x$W[0];break;case 20:g4l=(x$W[1] + x$W[0] + x$W[3] + x$W[4]) / x$W[2];break;case 164:g4l=x$W[3] * x$W[4] * x$W[0] * x$W[1] - x$W[2];break;case 97:g4l=(x$W[2] + x$W[3]) / (x$W[1] * x$W[0]);break;case 78:g4l=x$W[0] * (+x$W[3] * x$W[4] + x$W[1]) / x$W[2];break;case 81:g4l=x$W[0] + (x$W[2] ^ x$W[1]);break;case 112:g4l=(x$W[0] + x$W[3]) / x$W[2] + x$W[1];break;case 159:g4l=x$W[3] - x$W[0] / (+x$W[1] + x$W[2]);break;case 66:g4l=x$W[0] + x$W[2] + x$W[1] - x$W[3];break;case 108:g4l=x$W[1] / x$W[2] * x$W[0] * x$W[3] - x$W[4];break;case 77:g4l=x$W[0] * (x$W[2] + x$W[3]) / (x$W[4] * x$W[1]);break;case 181:g4l=x$W[0] * x$W[2] / (x$W[3] + x$W[1]);break;case 107:g4l=x$W[1] + x$W[3] + x$W[2] + x$W[0];break;case 123:g4l=(x$W[3] - x$W[1]) / x$W[2] / x$W[0] + x$W[4];break;case 185:g4l=-x$W[1] / x$W[3] * x$W[0] + x$W[2];break;case 183:g4l=x$W[4] + (x$W[0] / x$W[3] - x$W[1] / x$W[2]);break;case 12:g4l=(x$W[1] - x$W[2]) / x$W[0];break;case 170:g4l=x$W[3] + x$W[0] - x$W[2] + x$W[1];break;case 13:g4l=x$W[3] + x$W[1] - x$W[2] - x$W[0];break;case 6:g4l=x$W[1] % x$W[2] * x$W[0];break;case 150:g4l=(x$W[1] % x$W[2] + x$W[0]) * x$W[3];break;case 140:g4l=x$W[0] * (x$W[2] / x$W[3] - x$W[1]);break;case 179:g4l=x$W[1] == x$W[0];break;case 141:g4l=-x$W[1] - x$W[0] + x$W[2];break;case 11:g4l=x$W[2] / x$W[0] % x$W[1] / x$W[3];break;case 147:g4l=x$W[1] / x$W[3] / x$W[0] + x$W[2];break;case 105:g4l=x$W[2] + x$W[3] + x$W[4] + x$W[6] + x$W[5] + x$W[0] + x$W[7] + x$W[1];break;case 162:g4l=-x$W[0] / x$W[2] + x$W[4] + x$W[1] - x$W[3];break;case 180:g4l=x$W[3] + x$W[1] / (x$W[0] - x$W[2]) + x$W[4];break;case 33:g4l=(x$W[0] - x$W[3]) / (x$W[2] * x$W[1]);break;case 49:g4l=x$W[2] + x$W[1] / x$W[0];break;case 167:g4l=x$W[0] - x$W[2] * x$W[1];break;case 39:g4l=x$W[1] - x$W[3] - x$W[2] + x$W[0];break;case 148:g4l=x$W[0] / x$W[1] * x$W[4] * x$W[2] + x$W[3];break;case 135:g4l=(-x$W[1] - x$W[2]) / x$W[3] + x$W[0];break;case 59:g4l=x$W[0] < x$W[1];break;case 182:g4l=x$W[2] / x$W[0] / x$W[4] / x$W[3] - x$W[1];break;case 14:g4l=x$W[0] - x$W[1];break;case 130:g4l=(x$W[1] * x$W[0] - x$W[4]) / x$W[3] - x$W[2];break;case 76:g4l=x$W[1] - x$W[3] * (x$W[0] - x$W[2]);break;case 110:g4l=-x$W[2] / x$W[1] / x$W[3] + x$W[0];break;case 16:g4l=x$W[2] - x$W[1] + x$W[3] + x$W[0];break;case 64:g4l=(x$W[4] * x$W[3] + x$W[1]) / x$W[0] - x$W[2];break;case 41:g4l=x$W[0] + (x$W[2] - x$W[1]);break;case 101:g4l=x$W[3] * x$W[4] + x$W[2] + x$W[1] - x$W[0];break;case 46:g4l=x$W[0] ^ x$W[1];break;case 62:g4l=-x$W[0] - x$W[3] + x$W[1] - x$W[2];break;case 23:g4l=x$W[0] - x$W[2] + x$W[3] - x$W[1];break;case 80:g4l=(x$W[2] - x$W[0] * x$W[3]) / x$W[1];break;case 138:g4l=x$W[2] * x$W[0] * x$W[1];break;case 142:g4l=x$W[0] + x$W[1] * (x$W[3] - x$W[2]);break;case 24:g4l=x$W[0] - x$W[3] - x$W[2] - x$W[1];break;case 131:g4l=-x$W[1] / x$W[4] * x$W[3] * x$W[0] + x$W[2];break;case 82:g4l=x$W[2] + x$W[1] + x$W[0];break;case 171:g4l=(x$W[4] - x$W[2]) * x$W[3] + x$W[1] + x$W[0];break;case 136:g4l=+x$W[3] * x$W[2] / (x$W[0] + x$W[1]);break;case 72:g4l=(x$W[0] * x$W[3] + x$W[4]) * x$W[2] - x$W[1];break;case 56:g4l=x$W[1] / x$W[2] + x$W[3] - x$W[0];break;case 168:g4l=+x$W[0] * (x$W[1] / x$W[2] - x$W[3]);break;case 102:g4l=-x$W[3] + x$W[0] + x$W[1] - x$W[2];break;case 128:g4l=(-x$W[0] + x$W[3] + x$W[4]) / x$W[1] - x$W[2];break;case 149:g4l=(x$W[0] + x$W[2]) / x$W[3] + x$W[1] - x$W[4];break;case 139:g4l=+x$W[1] - x$W[3] / ((x$W[5] | x$W[0]) + x$W[2] / x$W[4]);break;case 27:g4l=-x$W[1] + x$W[0];break;case 28:g4l=(x$W[2] + x$W[4]) * x$W[3] * x$W[1] - x$W[0];break;case 4:g4l=x$W[0] | x$W[1];break;case 151:g4l=x$W[0] / (x$W[1] * x$W[2]) <= +x$W[3];break;case 40:g4l=x$W[0] * x$W[2] < x$W[1];break;case 36:g4l=(-x$W[2] + x$W[0] + x$W[3]) * x$W[4] - x$W[1];break;case 88:g4l=-x$W[0] * x$W[3] + x$W[2] + x$W[1];break;case 94:g4l=x$W[0] - +x$W[1];break;case 22:g4l=-x$W[2] * x$W[0] * x$W[1] - x$W[4] + x$W[3];break;case 54:g4l=(x$W[4] / x$W[2] + x$W[0]) / x$W[3] - x$W[1];break;case 50:g4l=x$W[1] + x$W[2] / +x$W[0];break;case 53:g4l=(x$W[1] - x$W[2]) / (x$W[4] - x$W[3]) > x$W[0];break;case 86:g4l=x$W[3] / x$W[4] / x$W[2] - x$W[0] + x$W[1];break;case 61:g4l=x$W[0] / x$W[1] + x$W[2];break;case 124:g4l=x$W[2] + x$W[4] - x$W[3] - x$W[1] - x$W[0];break;case 8:g4l=(x$W[2] - x$W[0]) * x$W[3] % x$W[1];break;case 52:g4l=-x$W[0] + x$W[1] - x$W[2];break;case 48:g4l=x$W[0] - x$W[1] / x$W[2];break;case 65:g4l=(x$W[4] - x$W[2]) / (x$W[3] - x$W[0]) > (x$W[1] | x$W[5]);break;case 173:g4l=-x$W[4] / x$W[3] / x$W[1] - x$W[0] + x$W[2];break;}return g4l;},g9iUvuS:function(k0L){W63=k0L;}};})();f3BGj.T$X=function(){return typeof f3BGj[593596].i9agN$W === 'function'?f3BGj[593596].i9agN$W.apply(f3BGj[593596],arguments):f3BGj[593596].i9agN$W;};f3BGj.f3X=function(){return typeof f3BGj[593596].i9agN$W === 'function'?f3BGj[593596].i9agN$W.apply(f3BGj[593596],arguments):f3BGj[593596].i9agN$W;};f3BGj[370258]=(function(){var I1k=function(q5v,E0P){var A6M=E0P & 0xffff;var n2J=E0P - A6M;return (n2J * q5v | 0) + (A6M * q5v | 0) | 0;},V29cT4d=function(b4N,X_r,w3s){var M2V=0xcc9e2d51,Q6q=0x1b873593;var S_T=w3s;var j4M=X_r & ~0x3;for(var O9s=0;O9s < j4M;O9s+=4){var r8X=b4N.i0lPz(O9s) & 0xff | (b4N.i0lPz(O9s + 1) & 0xff) << 8 | (b4N.i0lPz(O9s + 2) & 0xff) << 16 | (b4N.i0lPz(O9s + 3) & 0xff) << 24;r8X=I1k(r8X,M2V);r8X=(r8X & 0x1ffff) << 15 | r8X >>> 17;r8X=I1k(r8X,Q6q);S_T^=r8X;S_T=(S_T & 0x7ffff) << 13 | S_T >>> 19;S_T=S_T * 5 + 0xe6546b64 | 0;}r8X=0;switch(X_r % 4){case 3:r8X=(b4N.i0lPz(j4M + 2) & 0xff) << 16;case 2:r8X|=(b4N.i0lPz(j4M + 1) & 0xff) << 8;case 1:r8X|=b4N.i0lPz(j4M) & 0xff;r8X=I1k(r8X,M2V);r8X=(r8X & 0x1ffff) << 15 | r8X >>> 17;r8X=I1k(r8X,Q6q);S_T^=r8X;}S_T^=X_r;S_T^=S_T >>> 16;S_T=I1k(S_T,0x85ebca6b);S_T^=S_T >>> 13;S_T=I1k(S_T,0xc2b2ae35);S_T^=S_T >>> 16;return S_T;};return {V29cT4d:V29cT4d};})();f3BGj[636832]=327;function r$KpDA(d93){function Z99(Y_7){var w6d=2;for(;w6d !== 5;){switch(w6d){case 2:var t64=[arguments];return t64[0][0].String;break;}}}function y5d(D5X,s_9,B$p,S1B,D$o){var k4w=2;for(;k4w !== 14;){switch(k4w){case 2:var C2c=[arguments];C2c[9]="erty";C2c[3]="";C2c[3]="efineProp";k4w=3;break;case 3:C2c[4]="d";C2c[1]=true;C2c[1]=true;C2c[1]=false;k4w=6;break;case 6:try{var F17=2;for(;F17 !== 13;){switch(F17){case 9:C2c[7][C2c[0][4]]=C2c[7][C2c[0][2]];C2c[8].set=function(I4k){var N43=2;for(;N43 !== 5;){switch(N43){case 2:var U0V=[arguments];C2c[7][C2c[0][2]]=U0V[0][0];N43=5;break;}}};C2c[8].get=function(){var E6D=2;for(;E6D !== 13;){switch(E6D){case 6:J7n[3]+=J7n[8];return typeof C2c[7][C2c[0][2]] == J7n[3]?undefined:C2c[7][C2c[0][2]];break;case 3:J7n[5]="f";J7n[2]="unde";J7n[3]=J7n[2];J7n[3]+=J7n[5];E6D=6;break;case 2:var J7n=[arguments];J7n[8]="";J7n[8]="ined";J7n[5]="";E6D=3;break;}}};C2c[8].enumerable=C2c[1];try{var a1I=2;for(;a1I !== 3;){switch(a1I){case 2:C2c[5]=C2c[4];C2c[5]+=C2c[3];C2c[5]+=C2c[9];a1I=4;break;case 4:C2c[0][0].Object[C2c[5]](C2c[7],C2c[0][4],C2c[8]);a1I=3;break;}}}catch(s6C){}F17=13;break;case 3:return;break;case 4:F17=C2c[7].hasOwnProperty(C2c[0][4]) && C2c[7][C2c[0][4]] === C2c[7][C2c[0][2]]?3:9;break;case 2:C2c[8]={};C2c[2]=(1,C2c[0][1])(C2c[0][0]);C2c[7]=[C2c[2],C2c[2].prototype][C2c[0][3]];F17=4;break;}}}catch(p$2){}k4w=14;break;}}}function a9Q(v2B){var i4i=2;for(;i4i !== 5;){switch(i4i){case 2:var F6u=[arguments];return F6u[0][0];break;}}}var c4h=2;for(;c4h !== 100;){switch(c4h){case 2:var W6M=[arguments];W6M[9]="z";W6M[6]="";W6M[6]="";c4h=3;break;case 26:W6M[85]="";W6M[71]="J";W6M[13]="Fs";W6M[22]="T";W6M[85]="t";c4h=21;break;case 73:W6M[25]+=W6M[55];W6M[25]+=W6M[85];W6M[26]=W6M[65];W6M[26]+=W6M[22];c4h=69;break;case 102:x$F(a9Q,W6M[45],W6M[31],W6M[63]);c4h=101;break;case 69:W6M[26]+=W6M[56];W6M[21]=W6M[71];W6M[21]+=W6M[4];W6M[21]+=W6M[13];c4h=90;break;case 17:W6M[3]="__o";W6M[75]="F5";W6M[56]="";W6M[56]="3";c4h=26;break;case 90:W6M[38]=W6M[3];W6M[38]+=W6M[2];W6M[38]+=W6M[5];W6M[34]=W6M[75];W6M[34]+=W6M[7];c4h=85;break;case 45:W6M[32]=1;W6M[31]=8;W6M[31]=0;W6M[35]=W6M[36];c4h=62;break;case 44:W6M[97]="8bC";W6M[30]="";W6M[30]="p";W6M[42]="";c4h=40;break;case 21:W6M[65]="x7d";W6M[55]="";W6M[55]="bstrac";W6M[47]="";W6M[47]="__a";c4h=31;break;case 10:W6M[2]="pt";W6M[4]="";W6M[4]="6S";W6M[5]="imize";c4h=17;break;case 62:W6M[35]+=W6M[90];W6M[35]+=W6M[11];W6M[63]=W6M[10];W6M[63]+=W6M[73];W6M[63]+=W6M[89];W6M[45]=W6M[43];c4h=56;break;case 40:W6M[42]="ual";W6M[14]="";W6M[14]="resid";W6M[43]="";c4h=36;break;case 80:x$F(Z99,"charCodeAt",W6M[32],W6M[48]);c4h=79;break;case 31:W6M[91]="";W6M[91]="00";W6M[97]="";W6M[97]="";c4h=44;break;case 101:x$F(w34,"apply",W6M[32],W6M[35]);c4h=100;break;case 78:x$F(a9Q,W6M[38],W6M[31],W6M[21]);c4h=104;break;case 85:W6M[34]+=W6M[1];W6M[48]=W6M[6];W6M[48]+=W6M[8];W6M[48]+=W6M[9];c4h=81;break;case 51:W6M[10]="x";W6M[11]="uFN";W6M[90]="";W6M[90]="k";W6M[36]="X9";W6M[32]=2;c4h=45;break;case 36:W6M[43]="__";W6M[89]="a";W6M[10]="";W6M[73]="1ydX";c4h=51;break;case 103:x$F(a9Q,W6M[25],W6M[31],W6M[96]);c4h=102;break;case 79:x$F(R3V,"test",W6M[32],W6M[34]);c4h=78;break;case 14:W6M[7]="";W6M[7]="rm";W6M[2]="";W6M[2]="";c4h=10;break;case 104:x$F(k6E,"push",W6M[32],W6M[26]);c4h=103;break;case 56:W6M[45]+=W6M[14];W6M[45]+=W6M[42];W6M[96]=W6M[30];W6M[96]+=W6M[97];W6M[96]+=W6M[91];W6M[25]=W6M[47];c4h=73;break;case 3:W6M[6]="i";W6M[1]="";W6M[8]="0lP";W6M[1]="";W6M[1]="B";c4h=14;break;case 81:var x$F=function(p_J,y$t,O9D,d5n){var X50=2;for(;X50 !== 5;){switch(X50){case 2:var Q8s=[arguments];y5d(W6M[0][0],Q8s[0][0],Q8s[0][1],Q8s[0][2],Q8s[0][3]);X50=5;break;}}};c4h=80;break;}}function R3V(l8o){var N6Q=2;for(;N6Q !== 5;){switch(N6Q){case 2:var Y7n=[arguments];return Y7n[0][0].RegExp;break;}}}function w34(U4M){var J_v=2;for(;J_v !== 5;){switch(J_v){case 2:var w9_=[arguments];return w9_[0][0].Function;break;}}}function k6E(u3c){var H_u=2;for(;H_u !== 5;){switch(H_u){case 2:var d$n=[arguments];return d$n[0][0].Array;break;}}}}var N,Q,Z,S,W,o,U,g,Y,G,X,E,F,I,M_,h1,W3,W9,C5,b4,f3,n8,p9,f8,A3,b0,j4,U1,W2,K0,G_,T8,d8,T6,k1,e4,A1,d_,O9,s4,e5,C$,y9,v8,L4,o3,i8,O$,r_,O5,i3,Q7,Z4,T0,x$,k4,N1,a7,h3,C6,M$,q7,a9,U9,d5,o7,t2,m_,c7;import {CIQ as a4, SplinePlotter as p4, timezoneJS as j0, $$ as J2, $$$ as g9} from "../js/standard.js";N=p6=>{var k4X=f3BGj;var Y3;Y3=typeof _CIQ !== "undefined"?_CIQ:p6.CIQ;Y3.Renderer.Aggregations=function(z7){var e3;this.construct(z7);e3=this.params;this.highLowBars=this.barsHaveWidth=this.standaloneBars=!"";this.isAggregation=!!({});k4X.T$X();e3.highlightable=!!0;if(e3.name != "_main_series"){console.warn("Aggregations are only allowed on main series.");e3.invalid=!!"1";}};Y3.inheritsFrom(Y3.Renderer.Aggregations,Y3.Renderer.OHLC,!"1");Y3.Renderer.Aggregations.requestNew=function(W7,Z9){var T3m,f_G,u1,D_d,P$,X2;T3m="OHL";T3m+="C";k4X.T$X();f_G="c";f_G+="a";f_G+="ndle";u1=null;for(var y_="0" | 0;y_ < W7.length;y_++){D_d="p";D_d+="andf";P$=W7[y_];switch(P$){case "kagi":case D_d:u1=P$;break;case "heikinashi":case "linebreak":case "rangebars":case "renko":u1="candle";break;default:return null;}}if(u1 === null){return null;}X2=new Y3.Renderer[u1 == f_G?T3m:"Aggregations"]({params:Y3.extend(Z9,{type:u1})});X2.isAggregation=!!({});return X2;};Y3.Renderer.Aggregations.prototype.drawIndividualSeries=function(e2,x3){var J8w,d6,h5,Z2m,s9N,g2C,r5u,w8Z,b_A;J8w="k";J8w+="agi";if(x3.invalid){return;}d6=this.stx;k4X.f3X();h5={colors:[]};if(x3.type == J8w){Z2m="st";Z2m+="x_kagi_down";s9N="stx_";s9N+="k";s9N+="agi_do";s9N+="wn";g2C="stx_ka";g2C+="gi_up";d6.drawKagiSquareWave(e2.panel,g2C,s9N,x3);h5.colors.push(d6.getCanvasColor("stx_kagi_up"));h5.colors.push(d6.getCanvasColor(Z2m));}else if(x3.type == "pandf"){r5u="stx_pandf";r5u+="_down";w8Z="st";w8Z+="x_pan";w8Z+="df_do";w8Z+="wn";b_A="stx_p";b_A+="and";b_A+="f";b_A+="_up";d6.drawPointFigureChart(e2.panel,"stx_pandf_up",4129 >= (5050,"1610" >> 0)?"X":("H",4.43e+3),x3);h5.colors.push(d6.getCanvasColor(b_A));d6.drawPointFigureChart(e2.panel,w8Z,"O",x3);h5.colors.push(d6.getCanvasColor(r5u));}return h5;};Y3.ChartEngine.prototype.setAggregationType=function(i_){var u_;this.layout.chartType="candle";u_=this.chart;if(u_.baseline.userLevel !== ![]){u_.baseline.userLevel=u_.baseline.defaultLevel;u_.panel.yAxis.scroll=Y3.ChartEngine.YAxis.prototype.scroll;}k4X.T$X();this.layout.aggregationType=i_;this.setMainSeriesRenderer();if(u_.canvas){this.createDataSet();this.draw();}this.changeOccurred("layout");};Y3.ChartEngine.prototype.drawKagiSquareWave=function(t4,W5,A_,z9){var o8,g1,F1,J9,g4,L8,a0,H6,K4,c6,n_,P5,a2,q_,Z3,m5,l9,F2,f0,z8,I8;o8=t4.chart;this.startClip(t4.name);g1=o8.dataSegment;F1=o8.context;J9=t4.yAxis;if(J9.flipped){g4=W5;W5=A_;A_=g4;}L8=this.canvasStyle(W5);a0=this.canvasStyle(A_);this.canvasColor(W5);if(z9.border_color_up){F1.strokeStyle=z9.border_color_up;}k4X.f3X();H6=F1.strokeStyle;this.canvasColor(A_);if(z9.border_color_down){F1.strokeStyle=z9.border_color_down;}K4=F1.strokeStyle;c6=+"1";if(L8.width && parseInt(L8.width,+"10") <= 25){c6=Math.max(1,Y3.stripPX(L8.width));}n_=+"1";if(a0.width && parseInt(a0.width,10) <= 25){n_=Math.max(1,Y3.stripPX(a0.width));}if(this.highlightedDraggable){F1.globalAlpha*=0.3;}F1.beginPath();k4X.j7J(0);var a7t=k4X.c0C(51,20,8,9);P5=o8.dataSet.length - o8.scroll - a7t;a2=!!({});q_=null;Z3=null;m5=null;l9=t4.left - 0.5 * this.layout.candleWidth + this.micropixels - ("1" - 0);for(var T7=0;T7 <= g1.length;T7++){l9+=this.layout.candleWidth;F2=g1[T7];if(!F2)continue;if(F2.projection)break;m5=F2.kagiTrend;if(J9.flipped){m5*=-1;}if(F2.transform && o8.transformFunc){f0=F2.kagiPrevOpen;F2=F2.transform;F2.kagiPrevOpen=o8.transformFunc(this,o8,f0);}z8=F2.cache;k4X.j7J(1);I8=k4X.c0C(P5,T7);if(I8 < t4.cacheLeft || I8 > t4.cacheRight || !z8.kagiOpen){z8.kagiOpen=J9.semiLog?J9.height * (1 - (Math.log(Math.max(F2.Open,0)) / Math.LN10 - J9.logLow) / J9.logShadow):(J9.high - F2.Open) * J9.multiplier;z8.kagiClose=J9.semiLog?J9.height * (+"1" - (Math.log(Math.max(F2.Close,0)) / Math.LN10 - J9.logLow) / J9.logShadow):(J9.high - F2.Close) * J9.multiplier;if(J9.flipped){z8.kagiOpen=J9.bottom - z8.kagiOpen;z8.kagiClose=J9.bottom - z8.kagiClose;}else {z8.kagiOpen+=J9.top;z8.kagiClose+=J9.top;}}Z3=z8.kagiClose;q_=J9.semiLog?J9.height * (1 - (Math.log(Math.max(F2.kagiPrevOpen,0)) / Math.LN10 - J9.logLow) / J9.logShadow):(J9.high - F2.kagiPrevOpen) * J9.multiplier;if(J9.flipped){q_=J9.bottom - q_;}else {q_+=J9.top;}if(a2){F1.moveTo(P5 >= 0?t4.left:Math.floor(l9),z8.kagiOpen);F1.lineTo(Math.floor(l9),z8.kagiOpen);if(z8.kagiClose < z8.kagiOpen){F1.strokeStyle=H6;F1.lineWidth=c6;}else {F1.strokeStyle=K4;F1.lineWidth=n_;}}else {if(m5 != -1 && z8.kagiClose < q_ && q_ < z8.kagiOpen){F1.lineTo(Math.floor(l9),q_);F1.stroke();F1.beginPath();F1.moveTo(Math.floor(l9),q_);F1.strokeStyle=H6;F1.lineWidth=c6;}else if(m5 != 1 && z8.kagiClose > q_ && q_ > z8.kagiOpen){F1.lineTo(Math.floor(l9),q_);F1.stroke();F1.beginPath();F1.moveTo(Math.floor(l9),q_);F1.strokeStyle=K4;F1.lineWidth=n_;}}F1.lineTo(Math.floor(l9),z8.kagiClose);if(T7 + 1 < g1.length){F1.lineTo(Math.floor(l9 + this.layout.candleWidth),z8.kagiClose);}a2=![];}F1.stroke();this.endClip();F1.lineWidth=1;};Y3.ChartEngine.prototype.drawPointFigureChart=function(L3,m8,x7,Y$){var I1,b1,i0,U4,z5,q6,c$,y2r,t7D,u2F,b9,h_,b6,m0,O7,e7,A8,f$,P7,s7,w9,K6,s0,H_,Y2,g0,v4,Q5,r$;k4X.T$X();I1=L3.chart;this.startClip(L3.name);b1=I1.dataSegment;i0=I1.context;this.canvasColor(m8);if(x7 == "X" && Y$.border_color_up){i0.strokeStyle=Y$.border_color_up;}else if(x7 == "O" && Y$.border_color_down){i0.strokeStyle=Y$.border_color_down;}U4=this.canvasStyle(m8);z5=parseInt(U4.paddingTop,10);q6=parseInt(U4.paddingBottom,+"10");c$=parseInt(U4.paddingLeft,"10" >> 64);y2r=1344479106;t7D=-1790013436;u2F=+"2";for(var n4N=+"1";k4X.O1W(n4N.toString(),n4N.toString().length,12832) !== y2r;n4N++){b9=parseInt(U4.paddingRight,35);u2F+=2;}if(k4X.S9Y(u2F.toString(),u2F.toString().length,97742) !== t7D){b9=parseInt(U4.paddingRight,10);}if(U4.width && parseInt(U4.width,10) <= "25" * 1){i0.lineWidth=Math.max(1,Y3.stripPX(U4.width));}else {i0.lineWidth=2;}if(this.highlightedDraggable){i0.globalAlpha*=0.3;}i0.beginPath();h_=this.chart.state.aggregation.box;k4X.j7J(1);var A$T=k4X.c0C(0,1);b6=I1.dataSet.length - I1.scroll - A$T;m0=L3.yAxis;function u5(G7,i2,l6){var l3L,z3f,v_f;k4X.j7J(2);i0.moveTo(k4X.c0C(i2,G7,2),k4X.c0C(f$,z5,l6,k4X.N_M(3)));l3L=1781970155;z3f=-1343812757;k4X.T$X();k4X.j7J(4);v_f=k4X.c0C("2",2);for(var u54=1;k4X.O1W(u54.toString(),u54.toString().length,35153) !== l3L;u54++){k4X.j7J(5);i0.bezierCurveTo(k4X.c0C(b9,i2),k4X.a$j(f$,l6,z5,k4X.N_M(6)),k4X.a$j(i2,b9,k4X.j7J(7)),k4X.a$j(A8,f$,l6,q6,k4X.N_M(8)),k4X.a$j(4,i2,G7,k4X.j7J(9)),k4X.a$j(A8,l6,q6,f$,k4X.j7J(10)));k4X.N_M(1);i0.bezierCurveTo(k4X.a$j(G7,c$),k4X.c0C(A8,q6,l6,f$,k4X.j7J(11)),k4X.c0C(c$,G7,k4X.j7J(5)),k4X.c0C(f$,l6,z5,k4X.j7J(12)),k4X.a$j(8,i2,G7,k4X.N_M(9)),k4X.a$j(f$,l6,z5,k4X.N_M(6)));v_f+=2;}if(k4X.S9Y(v_f.toString(),v_f.toString().length,29856) !== z3f){k4X.N_M(1);i0.bezierCurveTo(k4X.c0C(i2,b9),k4X.c0C(f$,z5,l6,k4X.N_M(3)),k4X.c0C(i2,b9,k4X.j7J(1)),k4X.a$j(f$,A8,q6,l6,k4X.j7J(13)),k4X.c0C(i2,G7,2,k4X.j7J(2)),k4X.c0C(f$,A8,q6,l6,k4X.N_M(13)));k4X.N_M(14);i0.bezierCurveTo(k4X.c0C(G7,c$),k4X.c0C(f$,A8,q6,l6,k4X.N_M(13)),k4X.c0C(G7,c$,k4X.j7J(14)),k4X.a$j(f$,z5,l6,k4X.N_M(3)),k4X.c0C(i2,G7,2,k4X.N_M(2)),k4X.a$j(f$,z5,l6,k4X.j7J(3)));}}A8=h_ * m0.multiplier;k4X.N_M(7);f$=k4X.c0C(A8,2);P7=this.layout.candleWidth;k4X.j7J(14);var q4v=k4X.c0C(11,10);s7=L3.left - P7 + this.micropixels - q4v;for(var a6=0;a6 < b1.length;a6++){s7+=P7;w9=b1[a6];if(!w9)continue;if(w9.projection)break;K6=w9.pfOpen;s0=w9.pfClose;H_=w9.pfTrend;Y2=w9.pfStepBack;if(w9.transform && I1.transformFunc){w9=w9.transform;K6=I1.transformFunc(this,I1,K6);s0=I1.transformFunc(this,I1,s0);}g0=w9.cache;k4X.j7J(1);v4=k4X.a$j(b6,a6);if(v4 < L3.cacheLeft || v4 > L3.cacheRight || !g0.pfOpen){if(m0.flipped){g0.pfOpen=m0.bottom - (m0.high - K6) * m0.multiplier;g0.pfClose=m0.bottom - (m0.high - s0) * m0.multiplier;}else {g0.pfOpen=(m0.high - K6) * m0.multiplier + m0.top;g0.pfClose=(m0.high - s0) * m0.multiplier + m0.top;}}Q5=Math.round(s7);k4X.N_M(1);r$=Math.round(k4X.a$j(s7,P7));O7=Math.abs(Math.round((s0 - K6) / h_));e7=g0.pfOpen;if(x7 == Y2){if(Y2 == ((7080,7980) === "7880" * 1?(!!({}),"C"):440.62 === 838.12?(950.56,40) != (1090,4090)?!!0:("d",0x2229):"X")){k4X.N_M(14);h7(Q5,r$,k4X.c0C(e7,A8));}else if(Y2 == ((872,200) !== (2169,9413)?5760 < (1190,3958)?("i",576.04):"O":3.91e+3)){k4X.N_M(1);u5(Q5,r$,k4X.a$j(e7,A8));}}if(x7 == H_){for(;O7 >= 0;O7--){if(x7 == "X"){h7(Q5,r$,e7,A8,f$);e7-=m0.flipped?-A8:A8;}else if(x7 == ((480.39,"4314" - 0) !== 5070?"O":6840 == (4078,665.07)?0xc6a:766.13 > (351.38,+"569.78")?460.84:0x223f)){u5(Q5,r$,e7,A8,f$);e7+=m0.flipped?-A8:A8;}}}}function h7(G9,s8,o0){k4X.j7J(1);i0.moveTo(k4X.c0C(G9,c$),k4X.a$j(o0,f$,q6,k4X.N_M(15)));k4X.j7J(14);i0.lineTo(k4X.a$j(s8,b9),k4X.a$j(f$,A8,o0,z5,k4X.j7J(16)));k4X.f3X();k4X.j7J(1);i0.moveTo(k4X.c0C(G9,c$),k4X.c0C(f$,A8,o0,z5,k4X.j7J(16)));k4X.N_M(14);i0.lineTo(k4X.a$j(s8,b9),k4X.a$j(o0,f$,q6,k4X.N_M(15)));}i0.stroke();this.endClip();i0.lineWidth=1;};Y3.ChartEngine.calculateAggregation=function(M7,B6,S0,P_){var W4o,Q1,p8;W4o="rangeb";k4X.f3X();W4o+="a";W4o+="rs";p8=M7.layout;if(["heikinashi","heikenashi"].indexOf(B6) > -1){Q1=Y3.calculateHeikinAshi(M7,S0,P_);}else if(B6 == W4o){Q1=Y3.calculateRangeBars(M7,S0,p8.rangebars,P_);}else if(B6 == "kagi"){Q1=Y3.calculateKagi(M7,S0,p8.kagi,P_);}else if(B6 == "linebreak"){Q1=Y3.calculateLineBreak(M7,S0,p8.priceLines,P_);}else if(B6 == "renko"){Q1=Y3.calculateRenkoBars(M7,S0,p8.renko,P_);}else if(B6 == "pandf"){Q1=Y3.calculatePointFigure(M7,S0,p8.pandf,P_);}return Q1;};Y3.calculateHeikinAshi=function(j_,F7,E4){var v6,j$,X8,l1,h8,F9,B5,o2,u3,N2,Y9;if(!F7.length){return F7;}if(!E4){E4=[];}v6=[];for(var X0="0" >> 32;X0 < F7.length;X0++){j$=F7[X0];if(!j$)continue;k4X.N_M(17);var c8v=k4X.c0C(152,8,17,17);X8=v6[v6.length - c8v];if(!X8 && !X0){k4X.N_M(18);var b88=k4X.a$j(5,1,3,2);X8=E4[E4.length - b88];}if(!X8){X8=j$;}l1=j$.Close;h8=j$.Open;F9=j$.High;B5=j$.Low;o2=X8.Open;h8=h8 || h8 === 0?h8:l1;F9=F9 || F9 === 0?F9:l1;B5=B5 || B5 === +"0"?B5:l1;o2=o2 || o2 === 0?o2:X8.Close;k4X.N_M(19);var v86=k4X.a$j(4,20,10,798);u3=(o2 + X8.Close) / v86;k4X.j7J(20);N2=k4X.a$j(F9,h8,4,B5,l1);Y9={DT:j$.DT,displayDate:j$.displayDate,Date:j$.Date,Open:u3,Close:N2,High:Math.max(F9,Math.max(u3,N2)),Low:Math.min(B5,Math.min(u3,N2)),Volume:j$.Volume,iqPrevClose:X8.Close};for(var J5 in j$){if(!Y9[J5] && Y9[J5] !== +"0"){Y9[J5]=j$[J5];}}v6.push(Y9);}return v6;};Y3.calculateKagi=function(z6,w7,S5,n0){var U6,N$,B1,D1,a8,q3,V9,H5;k4X.f3X();if(!w7.length){return w7;}if(!n0){n0=[];}U6=z6.layout;N$=z6.chart;S5=parseFloat(S5);N$.defaultChartStyleConfig.kagi=Y3.ChartEngine.isDailyInterval(U6.interval)?4:0.4;if(isNaN(S5) || S5 <= "0" << 32){S5=N$.defaultChartStyleConfig.kagi;if(Y3.Market.Symbology.isForexSymbol(N$.symbol)){S5/=4;}if(U6.kagi !== null){U6.kagi=null;z6.changeOccurred("layout");}}S5/=100;B1=[];k4X.j7J(21);var t_6=k4X.c0C(85,12,7);D1=n0[n0.length - t_6];a8=D1?D1.DT:+"0";for(var I$=0;I$ < w7.length;I$++){q3=w7[I$];if(!q3)continue;if(!D1){k4X.N_M(14);D1=w7[k4X.c0C(I$,1)];}if(!D1)continue;V9=D1.Open || D1.Open === 0?D1.Open:D1.Close;if(V9 > D1.Close){if(q3.Close > D1.Close * (1 + S5)){q3.Open=D1.Close;}else {if(D1.Close > q3.Close){D1.Close=q3.Close;}D1.Volume+=q3.Volume;if(I$ < w7.length - 1)continue;}}else if(V9 < D1.Close){if(q3.Close < D1.Close * (1 - S5)){q3.Open=D1.Close;}else {if(D1.Close < q3.Close){D1.Close=q3.Close;}D1.Volume+=q3.Volume;if(I$ < w7.length - "1" * 1)continue;}}else {D1.Close=q3.Close;D1.Volume+=q3.Volume;if(I$ < w7.length - 1)continue;}H5={DT:D1.DT,displayDate:D1.displayDate,Date:D1.Date,Open:D1.Open,Close:D1.Close,High:Math.max(D1.Open,D1.Close),Low:Math.min(D1.Open,D1.Close),Volume:D1.Volume,iqPrevClose:D1.iqPrevClose};for(var V3 in D1){if(!H5[V3] && H5[V3] !== 0){H5[V3]=D1[V3];}}if(B1.length){H5.kagiPrevOpen=B1[B1.length - 1].Open;}else {H5.kagiPrevOpen=H5.Open;}if(H5.Close > H5.kagiPrevOpen && H5.kagiPrevOpen > H5.Open){H5.kagiTrend=+"1";}else if(H5.Close < H5.kagiPrevOpen && H5.kagiPrevOpen < H5.Open){H5.kagiTrend=-1;}if(a8 < H5.DT){B1.push(H5);}D1=q3;N$.currentQuote={Close:q3.Close};}return B1;};Y3.calculateLineBreak=function(Z7,y8,v_,t_){var G4,R8,m5U,g$b,u9i,Q$,o_,j7,U$,M8,R$,w5,A$,e9,g7,g8,v7;if(!y8.length){return y8;}if(!t_){t_=[];}G4=Z7.layout;R8=Z7.chart;R8.defaultChartStyleConfig.priceLines=3;v_=parseInt(v_,10);if(isNaN(v_) || v_ <= 0){v_=R8.defaultChartStyleConfig.priceLines;if(G4.priceLines !== null){G4.priceLines=null;Z7.changeOccurred("layout");}}else if(v_ > +"10"){m5U=-2111347095;g$b=-823734860;u9i=2;for(var p5I=1;k4X.O1W(p5I.toString(),p5I.toString().length,+"32527") !== m5U;p5I++){G4.priceLines=v_=28;u9i+=2;}if(k4X.S9Y(u9i.toString(),u9i.toString().length,99972) !== g$b){G4.priceLines=v_=10;}}Q$=t_.slice(-v_);o_=Q$.length;j7=0;a:for(var c1=+"0";c1 < y8.length;c1++){U$=y8[c1];if(!U$)continue;j7+=U$.Volume;k4X.j7J(22);var e$k=k4X.c0C(5,8,18,738,17);M8=Q$[Q$.length - e$k];if(!M8){M8={Open:U$.Open,Close:U$.Open,High:U$.Open,Low:U$.Open};}R$=M8.Close;w5=M8.High;A$=M8.Low;e9=M8.Open;w5=w5 || w5 === 0?w5:R$;A$=A$ || A$ === +"0"?A$:R$;e9=e9 || e9 === 0?e9:R$;g7={DT:U$.DT,displayDate:U$.displayDate,Date:U$.Date,Close:U$.Close,Volume:j7,iqPrevClose:R$};R8.currentQuote={Close:U$.Close};if(U$.Close > R$ && M8.Close > e9){;}else if(U$.Close < R$ && M8.Close < e9){;}else if(U$.Close > w5){for(g8=2;g8 <= v_;g8++){v7=Q$[Q$.length - g8];if(v7 && U$.Close <= v7.High){continue a;}}}else if(U$.Close < A$){for(g8=2;g8 <= v_;g8++){v7=Q$[Q$.length - g8];if(v7 && U$.Close >= v7.Low){continue a;}}}else continue;if(U$.Close < M8.Close){g7.Open=Math.min(e9,R$);}else {g7.Open=Math.max(e9,R$);}g7.Low=Math.min(g7.Open,g7.Close);g7.High=Math.max(g7.Open,g7.Close);for(var Q0 in U$){if(!g7[Q0] && g7[Q0] !== 0){g7[Q0]=U$[Q0];}}Q$.push(g7);j7=0;}return Q$.slice(o_);};k4X.T$X();Y3.calculateRenkoBars=function(i4,y7,b8,N3){var V1,q8,A0,I7,Z_,a3,e8$,d24,a54,w3c,U_,E1,e8,q$,G2,K9,B4,x8,o4;if(!y7.length){return [];}if(!N3){N3=[];}V1=i4.layout;q8=i4.chart;A0=q8.state.aggregation;if(!A0){A0=q8.state.aggregation={};}I7=Math.min(300,y7.length);if(!A0.minMax){A0.minMax=i4.determineMinMax(y7.slice(y7.length - I7),["Close","High","Low"]);}k4X.N_M(23);var k4O=k4X.c0C(0,2,17,20);Z_=A0.minMax[k4O] - A0.minMax[0];a3=i4.panels[q8.name].height;if(!a3){return [];}function I0(P2,E9){var B3;P2=Number(P2.toFixed(8));E9=Number(E9.toFixed("8" << 64));B3={DT:q$.DT,displayDate:q$.displayDate,Date:q$.Date,Open:P2,Close:E9,High:Math.max(P2,E9),Low:Math.min(P2,E9),Volume:0,iqPrevClose:P2 != E9?P2:null};for(var g_ in q$){if(!B3[g_] && B3[g_] !== 0){B3[g_]=q$[g_];}}U_.push(B3);}k4X.j7J(24);var W6_=k4X.c0C(180000,169996,2,2);q8.defaultChartStyleConfig.renko=Math.floor(W6_ * Z_ / (a3 / +"30")) / ("10000" - 0);if(b8 === null || isNaN(b8) || b8 <= 0){b8=q8.defaultChartStyleConfig.renko;if(V1.renko !== null){e8$="lay";e8$+="o";e8$+="u";e8$+="t";d24=+"566825041";a54=2008531130;w3c=2;for(var W$P="1" ^ 0;k4X.S9Y(W$P.toString(),W$P.toString().length,86538) !== d24;W$P++){V1.renko=null;w3c+=2;}if(k4X.O1W(w3c.toString(),w3c.toString().length,+"36698") !== a54){V1.renko=1;}i4.changeOccurred(e8$);}}else {k4X.j7J(7);b8=Math.max(b8,k4X.c0C(Z_,a3));if(V1.renko !== b8){V1.renko=b8;i4.changeOccurred("layout");}}U_=[];k4X.f3X();E1=null;e8=null;q$=null;if(N3.length){k4X.N_M(1);var b6Y=k4X.a$j(0,1);G2=N3[N3.length - b6Y];E1=G2.Low - b8;e8=G2.High + b8;}for(var U8=0;U8 < y7.length;U8++){K9=y7[U8];if(!K9)continue;if(!E1 && !e8){B4=K9.Open || K9.Open === 0?K9.Open:K9.Close;x8=Math.floor(B4 / b8) * b8;o4=isNaN(x8)?B4:x8;k4X.N_M(14);E1=k4X.a$j(o4,b8);k4X.N_M(1);e8=k4X.a$j(o4,b8);}while(!""){if(!q$){q$=K9;}if(K9.Close <= E1){k4X.N_M(1);I0(k4X.a$j(E1,b8),E1);k4X.j7J(25);e8=k4X.a$j(2,b8,E1);E1-=b8;q$=null;}else if(K9.Close >= e8){k4X.N_M(14);I0(k4X.a$j(e8,b8),e8);k4X.N_M(26);E1=k4X.c0C(e8,b8,"2");e8+=b8;q$=null;}else break;}q8.currentQuote=K9;}if(E1 < y7[y7.length - 1].Close && E1 + b8 > y7[y7.length - 1].Close){k4X.j7J(1);I0(k4X.a$j(E1,b8),y7[y7.length - 1].Close);}else if(e8 > y7[y7.length - 1].Close && e8 - b8 < y7[y7.length - 1].Close){k4X.j7J(14);I0(k4X.c0C(e8,b8),y7[y7.length - +"1"].Close);}return U_;};Y3.calculateRangeBars=function(Y8,f9,t8,H8){var W2M,K$,W6,k$,S8,u6,t3,P4c,n1,V6,t6,o5,T9,J3,i9,I9,h$,n2,F0,b$,M4,G6;W2M="L";function K8(){k4X.N_M(1);t6=k4X.a$j(V6,t8);k4X.N_M(14);o5=k4X.a$j(V6,t8);T9=V6;}W2M+="o";W2M+="w";if(!f9.length){return f9;}if(!H8){H8=[];}K$=Y8.layout;W6=Y8.chart;k$=W6.state.aggregation;if(!k$){k$=W6.state.aggregation={};}S8=Math.min(300,f9.length);if(!k$.minMax){k$.minMax=Y8.determineMinMax(f9.slice(f9.length - S8),["Close","High",W2M]);}k4X.N_M(27);var r7Y=k4X.c0C(15,14);u6=k$.minMax[r7Y] - k$.minMax[0];function I2(N8,P3){var E4R;while(1){E4R="u";E4R+="nde";E4R+="fine";E4R+="d";if(!J3){J3=N8;}if(V6 < P3){V6=Math.min(P3,t6);k4X.j7J(14);o5=Math.max(o5,k4X.a$j(V6,t8));if(P3 < t6)break;}else if(V6 >= P3){V6=Math.max(P3,o5);k4X.N_M(1);t6=Math.min(t6,k4X.c0C(V6,t8));if(P3 > o5)break;}if(typeof V6 == E4R){console.log("Uh oh undefined in calculateRangeBars:processMove");return;}n6(V6);J3=null;K8();}}t3=Y8.panels[W6.name].height;k4X.f3X();function n6(C0){var C_;C_={DT:J3.DT,displayDate:J3.displayDate,Date:J3.Date,Open:Number(T9.toFixed(+"8")),Close:Number(C0.toFixed(8)),High:Number(t6.toFixed(8)),Low:Number(o5.toFixed(8)),Volume:0};C_.iqPrevClose=C_.Open;for(var W8 in J3){if(!C_[W8] && C_[W8] !== 0){C_[W8]=J3[W8];}}n1.push(C_);}if(!t3){return [];}k4X.N_M(14);var T0c=k4X.c0C(510,480);k4X.N_M(3);var a9q=k4X.c0C(2,7,9995);W6.defaultChartStyleConfig.range=Math.floor(+"10000" * u6 / (t3 / T0c)) / a9q;if(t8 === null || isNaN(t8) || t8 < 0){t8=W6.defaultChartStyleConfig.range;if(K$.range !== null){K$.range=null;Y8.changeOccurred("layout");}}else {k4X.j7J(7);t8=Math.max(t8,k4X.a$j(u6,t3));if(K$.range !== t8){P4c="lay";P4c+="o";P4c+="u";P4c+="t";K$.range=t8;Y8.changeOccurred(P4c);}}n1=[];V6=null;t6=null;o5=null;T9=null;J3=null;for(var l0="0" >> 0;l0 < f9.length;l0++){i9=f9[l0];if(!i9)continue;k4X.j7J(14);I9=f9[k4X.c0C(l0,1)];if(!l0){if(!I9){k4X.j7J(28);var M$M=k4X.c0C(2771,11,0,14,18);I9=H8[H8.length - M$M];}if(I9){V6=I9.Close;if(V6 || V6 === 0){K8();}}}if(!I9)continue;h$=i9.Close;n2=i9.Open;F0=i9.High;b$=i9.Low;if(!h$ && h$ !== 0)continue;n2=n2 || n2 === 0?n2:h$;F0=F0 || F0 === 0?F0:h$;b$=b$ || b$ === 0?b$:h$;if(!V6 && V6 !== 0){M4=Math.floor(n2 / t8) * t8;V6=isNaN(M4)?n2:M4;K8();I2(I9,n2);}if(l0){I2(i9,n2);}if(F0 - n2 < n2 - b$){if(F0){I2(i9,F0);}if(b$){I2(i9,b$);}}else {if(b$){I2(i9,b$);}if(F0){I2(i9,F0);}}I2(i9,h$);if(l0 == f9.length - 1 && h$ != T9){G6=t6;k4X.j7J(1);t6=k4X.a$j(o5,t8);k4X.N_M(14);o5=k4X.a$j(G6,t8);n6(h$);}}return n1;};Y3.calculatePointFigure=function(l2,b7,E5,e1){var V7,A9,E2,E7,p7,i5,j_o,y5N,v1J,i8L,V8,t1,E_,I_,k8,M2,X5,N4,l4,m4,n$,M5,K2;if(!b7.length){return b7;}if(!e1){e1=[];}V7=l2.layout;A9=l2.chart;k4X.T$X();E2=A9.state.aggregation;if(!E2){E2=A9.state.aggregation={};}A9.defaultChartStyleConfig.box=1;A9.defaultChartStyleConfig.reversal=3;if(!E5){E5={};}E7=E5.box;function n3(j2,d7){for(var n5 in j2){if(!d7[n5] && d7[n5] !== 0){d7[n5]=j2[n5];}}return d7;}if(!E7){if(V7.pandf){if(V7.pandf.box !== null){V7.pandf.box=null;l2.changeOccurred("layout");}}E7=A9.defaultChartStyleConfig.box;p7=b7[b7.length - 1].Close;if(p7){if(p7 < +"0.25"){E7=0.0625;}else if(p7 < 1){E7=0.125;}else if(p7 < 5){E7=0.25;}else if(p7 < 20){E7=+"0.5";}else if(p7 < 100){E7=1;}else if(p7 < +"200"){E7=+"2";}else if(p7 < +"500"){E7=4;}else if(p7 < 1000){E7=5;}else if(p7 < 25000){k4X.N_M(4);E7=k4X.a$j("50",48);}else {E7=500;}}if(!Y3.ChartEngine.isDailyInterval(V7.interval)){E7/=10;}if(Y3.Market.Symbology.isForexSymbol(A9.symbol)){if(p7){if(p7 < 1){E7=0.001;}else if(p7 < 2){E7=0.002;}else if(p7 < 50){E7=0.02;}else if(p7 < 200){E7=+"0.2";}}if(Y3.ChartEngine.isDailyInterval(V7.interval)){k4X.j7J(29);E7*=k4X.c0C(64,"10");}}A9.defaultChartStyleConfig.box=E7;}function S6(j8,c8,S9,g$,m7){j8.High=Math.max(c8,j8.High);j8.Low=Math.min(S9,j8.Low);j8.Close=g$;j8.Volume+=m7;}E7=parseFloat(E7);if(isNaN(E7) || E7 <= 0){if(V7.pandf){if(V7.pandf.box !== null){V7.pandf.box=null;l2.changeOccurred("layout");}}A9.defaultChartStyleConfig.box=E7=1;}i5=Math.ceil(parseFloat(E5.reversal));if(i5 > 0 && i5 > E5.reversal){j_o="l";j_o+="ayo";j_o+="u";j_o+="t";V7.pandf.reversal=i5;l2.changeOccurred(j_o);}else if(isNaN(i5) || i5 <= 0){if(V7.pandf){if(V7.pandf.reversal !== null){y5N=-1551960333;v1J=-1523541582;i8L=2;for(var b1g=1;k4X.S9Y(b1g.toString(),b1g.toString().length,+"78645") !== y5N;b1g++){V7.pandf.reversal=1;i8L+=2;}if(k4X.S9Y(i8L.toString(),i8L.toString().length,5714) !== v1J){V7.pandf.reversal=null;}l2.changeOccurred("layout");}}i5=A9.defaultChartStyleConfig.reversal;}E2.box=E7;i5*=E7;function X6(m$,V$,Q3,l8,k0,Q8,P1,C3,W1){k4X.T$X();return {DT:m$.DT,Date:m$.Date,pfOpen:C3,pfClose:W1,Open:V$,Close:k0,High:Q3,Low:l8,Volume:Q8,iqPrevClose:P1};}V8=0.00000001;t1=(E7.toString() + ((2220,"8466" - 0) !== (578.72,297.86)?(2747,550) == (7260,379.6)?"171" >> 64 == 9880?(3.23e+3,4.84e+3):(![],"D"):".":5.62e+3)).split(".")[1].length;E_=[];I_=0;for(var y3=0;y3 < b7.length;y3++){M2=b7[y3];if(!M2)continue;I_+=M2.Volume;N4=M2.Close;l4=M2.Open;m4=M2.High;n$=M2.Low;l4=l4 || l4 === 0?l4:N4;m4=m4 || m4 === 0?m4:N4;n$=n$ || n$ === 0?n$:N4;if(!E_.length && !e1.length){k8=n3(M2,X6(M2,l4,m4,n$,N4,I_,m4 + E7,Number((Math.ceil(n$ / E7 - V8) * E7).toFixed(t1)),Number((Math.floor(m4 / E7 + V8) * E7).toFixed(t1))));k8.pfTrend="X";if(k8.pfOpen == k8.pfClose){k8.pfStepBack=3913 != 54.9?"-":(3.86e+3,257.92);}E_.push(k8);I_=0;continue;}k4X.N_M(14);var q3l=k4X.c0C(48,16);X5=E_[E_.length - ("1" >> q3l)];if(!X5){X5=Y3.clone(e1[e1.length - 1]);}if(X5.pfTrend == (428.16 === 5970?("8.20e+3" - 0,+"139.15"):832.37 < (656.48,144.15)?("a","g"):899.86 !== (111.27,2420)?"O":(!!"","n"))){if(n$ <= X5.pfClose - E7){X5.pfClose=Number((Math.ceil(n$ / E7 - V8) * E7).toFixed(t1));if(X5.pfStepBack == (("112" | 16) != 432.83?(549.88,789.67) === 1417?(344.74,4.80e+3):8233 == (2040,3130)?("r",0x354):"O":"p")){X5.pfStepBack=null;}S6(X5,m4,n$,N4,I_);}else if(m4 >= X5.pfClose + i5){M5=X5.pfClose + E7;K2=Number((Math.floor(m4 / E7 + V8) * E7).toFixed(t1));k8=X6(M2,l4,m4,n$,N4,I_,X5.pfClose,M5,K2);if(M5 == K2){k8.pfStepBack=(876,1032) == 82.44?(294.28,0x22d8):(8097,5840) != 703.24?"X":("o",+"8.40e+3");}if(X5.pfStepBack == (1130 <= (220.04,8710)?"O":("8.89e+3" * 1,"p"))){X5.pfOpen=M5;X5.pfClose=K2;X5.pfTrend=(254.35,63) === 910.31?("k",3.03e+2):"X";S6(X5,m4,n$,N4,I_);}else {k8=n3(M2,k8);k8.pfTrend=(656.74,9663) <= (477.34,8500)?"7022" * 1 !== +"6134"?!!({}):(!"1",+"2.46e+3"):"X";E_.push(k8);}}else {S6(X5,m4,n$,N4,I_);}I_=0;}else if(X5.pfTrend == (+"6680" < (8890,+"6190")?872.99 <= 390.41?("32.33" * 1,!({})):1396 !== 2580?6.59e+3:(713.18,"0x289" * 1):"X")){if(m4 >= X5.pfClose + E7){X5.pfClose=Number((Math.floor(m4 / E7 + V8) * E7).toFixed(t1));if(X5.pfStepBack == (1676 <= ("7480" | 32,7000)?6589 !== +"7446"?"X":("U",!!0):545.08) || X5.pfStepBack == (5404 < 4852?(2087,2149) != (+"3680",3390)?"X":6.83e+2:"-")){X5.pfStepBack=null;}S6(X5,m4,n$,N4,I_);}else if(n$ <= X5.pfClose - i5){M5=X5.pfClose - E7;K2=Number((Math.ceil(n$ / E7 - V8) * E7).toFixed(t1));k8=X6(M2,l4,m4,n$,N4,I_,X5.pfClose,M5,K2);if(M5 == K2){k8.pfStepBack=217 != (534.08,425)?"O":9.80e+3;}if(X5.pfStepBack == (+"450.38" == ("841" - 0,96)?(0xe45,0x258e):("268" ^ 0,9740) >= 29.3?"X":(911.97,0xfc1)) || X5.pfStepBack == ((+"7745",+"4250") <= (9760,4303)?"-":("E","G"))){X5.pfOpen=M5;X5.pfClose=K2;X5.pfTrend=6703 > (104.17,3870)?"O":(337.23,"S");S6(X5,m4,n$,N4,I_);if(M5 != K2 && X5.pfStepBack == "-"){X5.pfStepBack=null;}}else {k8=n3(M2,k8);k8.pfTrend=(5270,"3510" ^ 0) != (9920,7387)?3510 >= 9491?(+"5660",+"2993") < 1970?1.13e+2:0x1382:"O":"3.86e+3" >> 96;E_.push(k8);}}else {S6(X5,m4,n$,N4,I_);}I_=0;}}return E_;};};Q=X_=>{var q2h=f3BGj;var m3,L$,n8P,L4m,K$p,d0d,L$4,H2t,X1E,X9k,P4t,M4R,P40,p2Q,S6C,P7B,f8u,u5s,b2f,E5f,Y1x,X4h,L1L,K8k;m3=typeof _CIQ !== "undefined"?_CIQ:X_.CIQ;L$=typeof _timezoneJS !== "undefined"?_timezoneJS:X_.timezoneJS;if(!m3.Drawing){n8P="drawingAdvan";n8P+="ced feature requires first activating drawing feature.";console.error(n8P);}else {L4m="br[cq-";L4m+="wave-";L4m+="pa";L4m+="rameters]";K$p="waveParamete";K$p+="rs";d0d="l";d0d+="ineColo";d0d+="r";L$4="en";L$4+="c";L$4+="losed";H2t="pa";H2t+="t";H2t+="ter";H2t+="n";X1E="l";X1E+="ineWi";X1E+="dth";X9k="a";X9k+="x";X9k+="isLab";X9k+="el";P4t="fil";P4t+="l";P4t+="Color";M4R="c";M4R+="o";M4R+="lo";M4R+="r";P40="cq-cv";P40+="p-control";P40+="ler[cq-cv";P40+="p-header=\"2\"]";p2Q="cq-cvp-controller[cq";p2Q+="-cvp-header=\"1\"]";S6C="col";S6C+="o";S6C+="r";S6C+="2";P7B="fill";P7B+="C";P7B+="olo";P7B+="r";f8u="c";f8u+="o";f8u+="lo";f8u+="r";u5s="pa";u5s+="tter";u5s+="n";b2f="fil";b2f+="lColor";E5f="patte";E5f+="rn";Y1x="c";Y1x+="o";Y1x+="l";Y1x+="or";X4h="pa";X4h+="tt";X4h+="ern";L1L="line";L1L+="Wid";L1L+="th";K8k="fillCol";K8k+="or";m3.Drawing.ray=function(){this.name="ray";};m3.inheritsFrom(m3.Drawing.ray,m3.Drawing.line);m3.Drawing.ray.prototype.calculateOuterSet=function(s3){var B8,t0;if(this.p0[+"0"] == this.p1[0] || this.p0[1] == this.p1["1" >> 0] || m3.ChartEngine.isDailyInterval(this.stx.layout.interval)){return;}B8={x0:this.p0["0" << 32],y0:this.p0[1],x1:this.p1[0],y1:this.p1[1]};q2h.N_M(15);var Z7h=q2h.a$j(333,673,6);t0=B8.x1 + Z7h;if(B8.x0 > B8.x1){q2h.N_M(30);var z5X=q2h.c0C(897,2,996,20,6);t0=B8.x1 - z5X;}this.v0B=this.v0;this.v1B=m3.yIntersection(B8,t0);this.d0B=this.d0;this.d1B=this.stx.dateFromTick(t0,s3.chart);};m3.Drawing.ray.prototype.adjust=function(){var P9;P9=this.stx.panels[this.panelName];if(!P9){return;}this.setPoint(0,this.d0,this.v0,P9.chart);this.setPoint(1,this.d1,this.v1,P9.chart);if(m3.ChartEngine.isDailyInterval(this.stx.layout.interval) && this.d0B){this.setPoint(1,this.d1B,this.v1B,P9.chart);}};m3.Drawing.continuous=function(){q2h.T$X();this.name="continuous";this.dragToDraw=![];this.maxSegments=null;};m3.inheritsFrom(m3.Drawing.continuous,m3.Drawing.segment);m3.Drawing.continuous.prototype.click=function(X$,j3,R_){var d$t,e0,r9w,y$s,r4a,O0,d$,Y6;d$t="vect";d$t+="o";d$t+="r";e0=this.stx.panels[this.panelName];if(!e0){return;}this.copyConfig();if(!this.penDown){this.setPoint(0,j3,R_,e0.chart);this.penDown=!!1;r9w=-732415514;y$s=-940080879;r4a=2;for(var H89=1;q2h.S9Y(H89.toString(),H89.toString().length,67305) !== r9w;H89++){return !![];}if(q2h.O1W(r4a.toString(),r4a.toString().length,26867) !== y$s){return ![];}return !!0;}if(this.accidentalClick(j3,R_)){this.stx.undo();return !!({});}q2h.N_M(31);this.setPoint(q2h.a$j("1",0),j3,R_,e0.chart);O0=m3.Drawing.segment;d$=new O0();q2h.f3X();Y6=this.serialize(this.stx);d$.reconstruct(this.stx,Y6);this.stx.addDrawing(d$);this.stx.changeOccurred(d$t);this.stx.draw();this.segment++;if(this.maxSegments && this.segment > this.maxSegments){return !!({});}this.setPoint(0,j3,R_,e0.chart);return ![];};m3.Drawing.ellipse=function(){this.name="ellipse";};m3.inheritsFrom(m3.Drawing.ellipse,m3.Drawing.BaseTwoPoint);m3.Drawing.ellipse.prototype.render=function(q5){var l0a,q65,I3,A6,E3,Z0,T$,h4,B9,Q_,C4,c4,X7,s_,a5,s8t,i7m,Q_6,r3,o1;l0a="n";l0a+="one";q65="a";q65+="u";q65+="t";q65+="o";I3=this.stx.panels[this.panelName];if(!I3){return;}A6=this.stx.pixelFromTick(this.p0[0],I3.chart);E3=this.stx.pixelFromTick(this.p1["0" * 1],I3.chart);Z0=this.stx.pixelFromValueAdjusted(I3,this.p0[0],this.p0["1" ^ 0]);T$=this.stx.pixelFromValueAdjusted(I3,this.p1[0],this.p1[1]);q2h.j7J(32);h4=q2h.a$j(E3,A6,A6);B9=E3;Q_=Z0;C4=T$;q2h.f3X();q2h.N_M(32);c4=q2h.a$j(T$,Z0,Z0);q2h.j7J(33);X7=q2h.a$j(C4,1,"6",c4);s_=this.lineWidth;if(!s_){s_=1.1;}a5=this.color;if(a5 == q65 || m3.isTransparent(a5)){a5=this.stx.defaultColor;}if(this.highlighted){s8t=-1286846140;q2h.j7J(31);i7m=-q2h.a$j("1931758559",32);Q_6=2;for(var q6n=1;q2h.O1W(q6n.toString(),q6n.toString().length,25031) !== s8t;q6n++){a5=this.stx.getCanvasColor("");if(s_ === 508){s_=961;}Q_6+=2;}if(q2h.O1W(Q_6.toString(),Q_6.toString().length,23129) !== i7m){a5=this.stx.getCanvasColor("stx_highlight_vector");if(s_ == 0.1){s_=1.1;}}}r3=this.fillColor;q5.beginPath();q5.moveTo(h4,Q_);q2h.j7J(1);q5.bezierCurveTo(h4,q2h.c0C(C4,X7),B9,q2h.c0C(C4,X7),B9,Q_);q2h.j7J(14);q5.bezierCurveTo(B9,q2h.c0C(c4,X7),h4,q2h.a$j(c4,X7),h4,Q_);if(r3 && !m3.isTransparent(r3) && r3 != "auto"){q5.fillStyle=r3;q5.globalAlpha=0.2;q5.fill();q5.globalAlpha=1;}if(a5 && this.pattern != l0a){q5.strokeStyle=a5;q5.lineWidth=s_;if(q5.setLineDash){q5.setLineDash(m3.borderPatternToArray(s_,this.pattern));q2h.j7J(14);q5.lineDashOffset=q2h.c0C("0",0);;}q5.stroke();}q5.closePath();if(this.highlighted){o1=this.highlighted == "p1"?!![]:![];this.littleCircle(q5,E3,T$,o1);}};m3.Drawing.ellipse.prototype.intersected=function(i1,A4,x_){var A1Z,G1,U5,d4,D7;if(!this.p0 || !this.p1){return null;}if(this.pointIntersection(this.p1[0],this.p1[+"1"],x_)){A1Z="p";A1Z+="1";this.highlighted="p1";return {action:"drag",point:A1Z};}G1=this.p0[0] - (this.p1[0] - this.p0[0]);U5=this.p1[0];d4=this.p1[1];q2h.N_M(21);var m6p=q2h.a$j(37,12,3);q2h.N_M(9);var r8o=q2h.c0C(59,20,3);q2h.N_M(14);var v5i=q2h.a$j(6,5);D7=this.p0[m6p] - (this.p1[r8o] - this.p0[v5i]);if(x_.x0 > Math.max(G1,U5) || x_.x1 < Math.min(G1,U5)){return ![];}if(x_.y1 > Math.max(D7,d4) || x_.y0 < Math.min(D7,d4)){return ![];}q2h.T$X();this.highlighted=!"";return {action:"move",p0:m3.clone(this.p0),p1:m3.clone(this.p1),tick:i1,value:A4};};m3.Drawing.ellipse.prototype.configs=["color","fillColor","lineWidth","pattern"];m3.Drawing.ellipse.prototype.reconstruct=function(P6,u9){this.stx=P6;this.color=u9.col;this.fillColor=u9.fc;this.panelName=u9.pnl;this.pattern=u9.ptrn;this.lineWidth=u9.lw;this.d0=u9.d0;q2h.f3X();this.d1=u9.d1;this.tzo0=u9.tzo0;this.tzo1=u9.tzo1;this.v0=u9.v0;this.v1=u9.v1;this.adjust();};m3.Drawing.ellipse.prototype.serialize=function(){return {name:this.name,pnl:this.panelName,col:this.color,fc:this.fillColor,ptrn:this.pattern,lw:this.lineWidth,d0:this.d0,d1:this.d1,tzo0:this.tzo0,tzo1:this.tzo1,v0:this.v0,v1:this.v1};};m3.Drawing.channel=function(){var u2l;u2l="c";u2l+="h";q2h.T$X();u2l+="annel";this.name=u2l;this.dragToDraw=![];this.p2=null;};m3.inheritsFrom(m3.Drawing.channel,m3.Drawing.segment);m3.Drawing.channel.prototype.configs=["color",K8k,L1L,X4h];m3.Drawing.channel.prototype.move=function(M0,X3,W$){q2h.f3X();var p$;if(!this.penDown){return;}this.copyConfig();if(this.p2 === null){this.p1=[X3,W$];}else {q2h.N_M(19);var J0w=q2h.c0C(17,10,12,2039);q2h.N_M(3);var n$_=q2h.a$j(6,5,2);p$=W$ - (this.p1[J0w] - this.p0[n$_]) / (this.p1[0] - this.p0[0]) * (X3 - this.p1[0]);this.p2=[this.p1[0],p$];}this.render(M0);};m3.Drawing.channel.prototype.click=function(S$,F_,f6){var i6;i6=this.stx.panels[this.panelName];if(!i6){return;}this.copyConfig();if(!this.penDown){this.setPoint(0,F_,f6,i6.chart);this.penDown=!!"1";return !({});}if(this.accidentalClick(F_,f6)){this.stx.undo();return !![];}if(this.p2 !== null){this.setPoint(2,this.p2[0],this.p2[1],i6.chart);this.penDown=!1;return !![];}this.setPoint(1,F_,f6,i6.chart);if(this.p0[0] == this.p1[+"0"]){this.p1=null;return !!"";}this.p2=[this.p1[0],this.p1[1]];return !!0;};m3.Drawing.channel.prototype.boxIntersection=function(D9,z_,U2){var O4,O8,O3,G0,k3;O4=this.p0;O8=this.p1;O3=this.p2;if(!O4 || !O8 || !O3){return ![];}if(U2.x0 > Math.max(O4[0],O8[0]) || U2.x1 < Math.min(O4["0" * 1],O8[0])){return ![];}q2h.N_M(34);var g7R=q2h.c0C(16,1,15);q2h.N_M(35);var K9D=q2h.c0C(0,14,14);q2h.j7J(14);var N$R=q2h.c0C(15,14);q2h.j7J(36);var a0Z=q2h.a$j(18,107,19,10,12);G0=(O8[0] - O4[0]) * ((O3[g7R] < O4["1" ^ 0]?U2.y1:U2.y0) - O4[K9D]) - (O8[N$R] - O4[a0Z]) * (D9 - O4[0]);q2h.j7J(14);var a5s=q2h.a$j(7,6);q2h.j7J(37);var J8v=q2h.c0C(17,2,16,10,23);q2h.j7J(38);var A2V=q2h.c0C(4,23,15,2);q2h.j7J(3);var c2T=q2h.a$j(18,7,12);q2h.j7J(39);var N88=q2h.a$j(12,5,11,5);k3=(O3[0] - O4[0]) * ((O3["1" | 0] > O4[+"1"]?U2.y1:U2.y0) - (O4[a5s] + O3[J8v] - O8[A2V])) - (O8[c2T] - O4[N88]) * (D9 - O4[0]);q2h.j7J(40);return q2h.a$j(G0,0,k3);};m3.Drawing.channel.prototype.intersected=function(O2,H4,I4){var d3,K52,o0u;if(!this.p0 || !this.p1 || !this.p2){return null;}d3={0:this.p0,1:this.p1,2:this.p2};for(var M6 in d3){if(this.pointIntersection(d3[M6][0],d3[M6][1],I4)){K52="d";K52+="r";K52+="a";K52+="g";q2h.j7J(1);this.highlighted=q2h.c0C(+"633.28" !== (6500,+"7315")?9152 !== 508.99?"p":(+"0x1eef","Z"):"6.96e+3" >> 64,M6);return {action:K52,point:(201.42 < ("122" << 32,6720)?"p":(5711,8370) == 6?("B",266.61):(2330,591) === (3730,948)?(390.30,!1):(2.10e+3,"O")) + M6};}}q2h.f3X();if(this.boxIntersection(O2,H4,I4)){o0u="m";o0u+="o";o0u+="ve";this.highlighted=!!"1";return {action:o0u,p0:m3.clone(this.p0),p1:m3.clone(this.p1),p2:m3.clone(this.p2),tick:O2,value:H4};}return null;};m3.Drawing.channel.prototype.render=function(g2){var i8t,Q_d,C7,E$,R4,p_,z0,Y4,S7,i7,k5,w4,p_o,P9z,O_u,Q6,A2,D6;i8t="s";i8t+="egme";i8t+="n";q2h.T$X();i8t+="t";Q_d="n";Q_d+="o";Q_d+="ne";C7=this.stx.panels[this.panelName];if(!C7){return;}E$=this.stx.pixelFromTick(this.p0[0],C7.chart);R4=this.stx.pixelFromTick(this.p1[0],C7.chart);p_=this.stx.pixelFromValueAdjusted(C7,this.p0[0],this.p0[1]);z0=this.stx.pixelFromValueAdjusted(C7,this.p1[0],this.p1[1]);Y4=null;if(this.p2){Y4=this.stx.pixelFromValueAdjusted(C7,this.p2[0],this.p2[1]);}S7=this.lineWidth;i7=this.getLineColor();k5=this.fillColor;if(this.p2 && k5 && !m3.isTransparent(k5) && k5 != "auto"){g2.beginPath();g2.moveTo(E$,p_);g2.lineTo(R4,z0);g2.lineTo(R4,Y4);q2h.N_M(41);g2.lineTo(E$,q2h.c0C(p_,z0,Y4));g2.closePath();g2.globalAlpha=+"0.2";g2.fillStyle=k5;g2.fill();g2.globalAlpha=1;}w4={pattern:this.pattern,lineWidth:S7};if((this.penDown || this.highlighted) && this.pattern == Q_d){w4.pattern="dotted";}this.stx.plotLine(E$,R4,p_,z0,i7,"segment",g2,C7,w4);if(this.p2){q2h.N_M(41);this.stx.plotLine(E$,R4,q2h.c0C(p_,z0,Y4),Y4,i7,i8t,g2,C7,w4);}if(this.highlighted){p_o="p";p_o+="2";P9z="p";P9z+="1";O_u="p";O_u+="0";Q6=this.highlighted == O_u?!!"1":!"1";A2=this.highlighted == P9z?!0:!"1";D6=this.highlighted == p_o?!!1:![];this.littleCircle(g2,E$,p_,Q6);this.littleCircle(g2,R4,z0,A2);this.littleCircle(g2,R4,Y4,D6);}};m3.Drawing.channel.prototype.reposition=function(J8,e$,m9,G3){var K1,x9,s$;if(!e$){return;}K1=this.stx.panels[this.panelName];x9=e$.tick - m9;s$=e$.value - G3;if(e$.action == "move"){this.setPoint(0,e$.p0[0] - x9,e$.p0["1" | 0] - s$,K1.chart);this.setPoint(1,e$.p1[0] - x9,e$.p1[1] - s$,K1.chart);this.setPoint(+"2",e$.p2[0] - x9,e$.p2[1] - s$,K1.chart);this.render(J8);}else if(e$.action == "drag"){this[e$.point]=[m9,G3];this.setPoint(0,this.p0[+"0"],this.p0[1],K1.chart);this.setPoint(+"1",this.p1[0],this.p1[+"1"],K1.chart);this.setPoint(+"2",this.p2[0],this.p2[1],K1.chart);this.render(J8);}};m3.Drawing.channel.prototype.adjust=function(){var L2;L2=this.stx.panels[this.panelName];if(!L2){return;}this.setPoint(0,this.d0,this.v0,L2.chart);q2h.T$X();this.setPoint(1,this.d1,this.v1,L2.chart);this.setPoint(2,this.d1,this.v2,L2.chart);;};m3.Drawing.channel.prototype.reconstruct=function(h9,F3){this.stx=h9;this.color=F3.col;this.fillColor=F3.fc;this.panelName=F3.pnl;this.pattern=F3.ptrn;q2h.f3X();this.lineWidth=F3.lw;this.d0=F3.d0;this.d1=F3.d1;this.tzo0=F3.tzo0;this.tzo1=F3.tzo1;this.v0=F3.v0;this.v1=F3.v1;this.v2=F3.v2;this.adjust();};m3.Drawing.channel.prototype.serialize=function(){q2h.f3X();return {name:this.name,pnl:this.panelName,col:this.color,fc:this.fillColor,ptrn:this.pattern,lw:this.lineWidth,d0:this.d0,d1:this.d1,tzo0:this.tzo0,tzo1:this.tzo1,v0:this.v0,v1:this.v1,v2:this.v2};};m3.Drawing.pitchfork=function(){this.name="pitchfork";this.dragToDraw=!({});this.p2=null;};m3.inheritsFrom(m3.Drawing.pitchfork,m3.Drawing.channel);m3.Drawing.pitchfork.prototype.configs=[Y1x,"lineWidth",E5f];m3.Drawing.pitchfork.prototype.move=function(R0,w8,m6){if(!this.penDown){return;}this.copyConfig();if(this.p2 === null){this.p1=[w8,m6];}else {this.p2=[w8,m6];}q2h.T$X();this.render(R0);};m3.Drawing.pitchfork.prototype.intersected=function(h6,Y_,r5){var K3,j6,R93;if(!this.p0 || !this.p1 || !this.p2){return null;}K3={0:this.p0,1:this.p1,2:this.p2};for(var O6 in K3){if(this.pointIntersection(K3[O6][0],K3[O6][1],r5)){q2h.j7J(1);this.highlighted=q2h.c0C(3244 >= ("42" ^ 0)?"p":6.63e+3,O6);return {action:"drag",point:((269.17,7415) > "7158" - 0?"p":(556,3123) >= +"686.08"?("V",1.31e+3):"p") + O6};}}q2h.f3X();j6=this.rays;for(var B7=0;B7 < j6.length;B7++){R93="r";R93+="ay";if(this.lineIntersection(h6,Y_,r5,B7?R93:"segment",j6[B7][0],j6[B7][+"1"],!![])){this.highlighted=!![];return {action:"move",p0:m3.clone(this.p0),p1:m3.clone(this.p1),p2:m3.clone(this.p2),tick:h6,value:Y_};}}return null;};m3.Drawing.pitchfork.prototype.render=function(C8){var C2,D8,D5,H2,R5,q9,t5,o44,I6h,S3M,F$,T4,G8,R2,D$,l$,D_,X4,F6,i$,n4,l_,k7;C2=this.stx.panels[this.panelName];if(!C2){return;}D8=this.stx;D5=this.p2;if(!D5){D5=this.p1;}H2=D8.pixelFromTick(this.p0[0],C2.chart);R5=D8.pixelFromTick(this.p1[0],C2.chart);q9=D8.pixelFromTick(D5[0],C2.chart);t5=D8.pixelFromValueAdjusted(C2,this.p0[0],this.p0[1]);q2h.j7J(29);o44=q2h.a$j(0,"204078802");I6h=-173087591;S3M=2;q2h.T$X();for(var C7q=1;q2h.O1W(C7q.toString(),C7q.toString().length,25285) !== o44;C7q++){F$=D8.pixelFromValueAdjusted(C2,this.p1[+"3"],this.p1[7]);T4=D8.pixelFromValueAdjusted(C2,D5["1" >> 64],D5["4" | 0]);G8=this.lineWidth;R2=this.getLineColor();D$={pattern:this.pattern,lineWidth:G8};l$=92;q2h.j7J(42);D_=q2h.a$j(T4,F$,"9",t5,1);S3M+=2;}if(q2h.O1W(S3M.toString(),S3M.toString().length,+"42105") !== I6h){F$=D8.pixelFromValueAdjusted(C2,this.p1[+"0"],this.p1[1]);T4=D8.pixelFromValueAdjusted(C2,D5[0],D5[1]);G8=this.lineWidth;R2=this.getLineColor();D$={pattern:this.pattern,lineWidth:G8};q2h.j7J(5);l$=q2h.a$j(1,"50");q2h.j7J(43);D_=q2h.c0C(T4,t5,F$,"2");}q2h.N_M(0);X4=q2h.c0C(q9,R5,2,H2);if(X4 < 0){l$*=-1;}q2h.N_M(7);D_*=q2h.a$j(l$,X4);q2h.N_M(2);this.rays=[[[R5,F$],[q9,T4]],[[H2,t5],[q2h.a$j(q9,R5,2),q2h.a$j(T4,F$,2)]]];if(!(R5 == q9 && F$ == T4)){q2h.j7J(14);this.rays.push([[R5,F$],[q2h.c0C(R5,l$),q2h.a$j(F$,D_)]],[[q9,T4],[q2h.c0C(q9,l$),q2h.c0C(T4,D_)]]);}for(var T_=0;T_ < this.rays.length;T_++){F6=this.rays[T_];i$=T_?"ray":"segment";D8.plotLine(F6["0" - 0][0],F6[+"1"][0],F6[0][1],F6[1][1],R2,i$,C8,C2,D$);}if(this.highlighted){n4=this.highlighted == "p0"?!!({}):!1;l_=this.highlighted == "p1"?!"":!!0;k7=this.highlighted == "p2"?!"":!1;this.littleCircle(C8,H2,t5,n4);this.littleCircle(C8,R5,F$,l_);this.littleCircle(C8,q9,T4,k7);}};m3.Drawing.pitchfork.prototype.adjust=function(){var x4m,O6i,r1M,Z1;x4m=-1246191620;O6i=2053540169;r1M=2;for(var E87=1;q2h.S9Y(E87.toString(),E87.toString().length,+"72042") !== x4m;E87++){Z1=this.stx.panels[this.panelName];if(+Z1){return;}this.setPoint(9,this.d0,this.v0,Z1.chart);r1M+=+"2";}if(q2h.O1W(r1M.toString(),r1M.toString().length,98135) !== O6i){Z1=this.stx.panels[this.panelName];if(!Z1){return;}this.setPoint(0,this.d0,this.v0,Z1.chart);}this.setPoint(1,this.d1,this.v1,Z1.chart);this.setPoint(2,this.d2,this.v2,Z1.chart);};m3.Drawing.pitchfork.prototype.reconstruct=function(r7,Y1){this.stx=r7;this.color=Y1.col;this.panelName=Y1.pnl;this.pattern=Y1.ptrn;this.lineWidth=Y1.lw;this.d0=Y1.d0;this.d1=Y1.d1;this.d2=Y1.d2;q2h.T$X();this.tzo0=Y1.tzo0;this.tzo1=Y1.tzo1;this.tzo2=Y1.tzo2;this.v0=Y1.v0;this.v1=Y1.v1;this.v2=Y1.v2;this.adjust();};m3.Drawing.pitchfork.prototype.serialize=function(){q2h.T$X();return {name:this.name,pnl:this.panelName,col:this.color,ptrn:this.pattern,lw:this.lineWidth,d0:this.d0,d1:this.d1,d2:this.d2,tzo0:this.tzo0,tzo1:this.tzo1,tzo2:this.tzo2,v0:this.v0,v1:this.v1,v2:this.v2};};m3.Drawing.gartley=function(){q2h.T$X();this.name="gartley";this.dragToDraw=!!0;this.maxSegments=4;this.shape=null;this.points=[];};m3.inheritsFrom(m3.Drawing.gartley,m3.Drawing.continuous);m3.Drawing.gartley.prototype.check=function(c0,u4){if(!u4){return !!"1";}if(c0[0] >= u4[0] || c0[1] == u4[1]){return !!"";}if(this.segment == 1){if(c0[1] < u4[+"1"]){this.shape="M";}else {this.shape=107 == (+"5343",5790)?(3569,6244) == 1860?(1.59e+3,!({})):(0x8e7,"465.84" * 1):"W";}}else if(this.segment == "2" - 0){if(this.shape == (1490 === (615,7680)?(!({}),!"1"):"M") && c0["1" | 1] < u4["1" - 0]){return !1;}else if(this.shape == ((6660,371.53) >= 411?6760 < (2240,7700)?907 !== 4150?+"0x1e50":(![],0x1f8):(!({}),!!"1"):"W") && c0[1] > u4[1]){return ![];}else if((u4[+"1"] - c0["1" ^ 0]) / (this.points[0][1] - c0[1]) < 0.618){return !!0;}else if((u4[1] - c0[1]) / (this.points[+"0"][1] - c0[1]) >= 0.786){return ![];}}else if(this.segment == 3){if(this.shape == (506.41 <= 7912?"M":(730.15,9294) == 45.47?"3.92e+3" | 0:(2.05e+3,"p")) && c0[1] > u4[1]){return !1;}else if(this.shape == ((1440,352) != (329,6370)?(7060,6570) < (248.54,8477)?"W":"f":"0x1bba" | 32) && c0[1] < u4["1" ^ 0]){return !!"";}else if((u4[1] - c0[1]) / (this.points[1][+"1"] - c0[1]) < 0.618){return !1;}else if((u4[1] - c0[1]) / (this.points[1][1] - c0[1]) >= 0.786){return !!"";}}else if(this.segment == 4){if(this.shape == ((4171,8908) > 356.92?(4270,2778) <= (3786,344)?"j":"M":(!1,"v")) && (c0[1] < u4[1] || u4[1] < this.points[0][1])){return !!"";}else if(this.shape == ((252.95,656) > (406,364)?"W":300.83) && (c0[1] > u4[1] || u4[1] > this.points[+"0"]["1" >> 32])){return !({});}else if((this.points[1]["1" ^ 0] - u4["1" - 0]) / (this.points[+"1"][1] - this.points[+"2"][1]) < 1.27){return ![];}else if((this.points[1][1] - u4[1]) / (this.points[1][1] - this.points[2][1]) >= 1.618){return !1;}}return !![];};m3.Drawing.gartley.prototype.click=function(V_,k6,Z2){var N6;N6=this.stx.panels[this.panelName];if(!N6){return;}this.copyConfig();if(!this.penDown){this.setPoint(0,k6,Z2,N6.chart);this.pts=[];this.penDown=!!1;this.segment=1;return !!0;}if(this.accidentalClick(k6,Z2)){this.penDown=!0;return ![];}q2h.f3X();if(this.check(this.p0,this.p1)){if(this.segment == +"1"){this.points.push(this.p0);}this.points.push(this.p1);q2h.j7J(31);this.setPoint(q2h.a$j("1",64),k6,Z2,N6.chart);this.segment++;if(this.segment > this.maxSegments){this.setPoint(0,this.points[0]["0" << 64],this.points["0" - 0][1],N6.chart);this.penDown=![];return !!({});}this.pts.push(this.d1,this.tzo1,this.v1);this.setPoint(0,k6,Z2,N6.chart);;}return !({});};m3.Drawing.gartley.prototype.render=function(T3){var o3i,N5,v$,T1,r1,T2,R7,z2,O_,v5,r0,b5,h2,e6,I6,D4;o3i="dott";o3i+="ed";N5=this.stx.panels[this.panelName];if(!N5){return;}v$=this.stx.pixelFromTick(this.p0[0],N5.chart);T1=this.stx.pixelFromTick(this.p1["0" * 1],N5.chart);r1=this.stx.pixelFromValueAdjusted(N5,this.p0[0],this.p0[1]);T2=this.stx.pixelFromValueAdjusted(N5,this.p1["0" | 0],this.p1["1" >> 64]);if(this.segment == "2" * 1){this.drawDropZone(T3,0.618 * this.points[0][1] + 0.382 * this.p0[1],+"0.786" * this.points[0]["1" - 0] + 0.214 * this.p0[+"1"],this.p0[0]);}else if(this.segment == 3){this.drawDropZone(T3,0.618 * this.points[1]["1" >> 0] + 0.382 * this.p0[1],0.786 * this.points[1][1] + 0.214 * this.p0[1],this.p0[0]);}else if(this.segment == 4){q2h.N_M(17);var n_h=q2h.a$j(32,4,5,14);q2h.N_M(44);var q6f=q2h.c0C(16,16,255,0);q2h.N_M(1);var h91=q2h.a$j(0,1);q2h.j7J(1);var I6I=q2h.c0C(0,1);R7=1.618 * this.points[n_h][q6f] - 0.618 * this.points["1" | h91][I6I];if(this.shape == "M"){R7=Math.max(R7,this.points["0" | 0][1]);}else {R7=Math.min(R7,this.points[0][1]);}this.drawDropZone(T3,R7,1.27 * this.points[+"2"][+"1"] - 0.27 * this.points[1][1],this.p0[0]);}z2=this.lineWidth;O_=this.getLineColor();v5={pattern:this.pattern,lineWidth:z2};if((this.penDown || this.highlighted) && this.pattern == "none"){v5.pattern=o3i;}if(this.segment <= this.maxSegments){this.stx.plotLine(v$,T1,r1,T2,O_,this.name,T3,N5,v5);}r0=this.fillColor;b5=[];if(this.points.length){T3.beginPath();for(var h0=1;h0 < this.points.length && h0 <= 4;h0++){h2=this.stx.pixelFromTick(this.points[h0 - 1][0],N5.chart);e6=this.stx.pixelFromTick(this.points[h0][+"0"],N5.chart);I6=this.stx.pixelFromValueAdjusted(N5,this.points[h0 - 1][0],this.points[h0 - 1][1]);D4=this.stx.pixelFromValueAdjusted(N5,this.points[h0][0],this.points[h0][1]);if(h0 == 1){b5.push(h2,I6);}b5.push(e6,D4);this.stx.plotLine(h2,e6,I6,D4,O_,this.name,T3,N5,v5);}if(this.points.length == 2 || this.points.length == 4){b5.push(T1,T2);}if(this.points[+"2"]){b5.push(this.stx.pixelFromTick(this.points[2][+"0"],N5.chart),this.stx.pixelFromValueAdjusted(N5,this.points[+"2"][0],this.points[+"2"][1]));}if(r0 && r0 != "auto" && !m3.isTransparent(r0)){for(var D2=0;D2 < b5.length;D2+=2){if(D2 === 0){T3.moveTo(b5[0],b5[1]);}T3.lineTo(b5[D2],b5[D2 + 1]);}T3.fillStyle=r0;T3.globalAlpha=0.2;T3.closePath();T3.fill();T3.globalAlpha=1;}};};m3.Drawing.gartley.prototype.lineIntersection=function(T5,R6,x5,Q4){var J6,f_,A0$;J6=this.points;q2h.f3X();f_=this.stx.panels[this.panelName];if(J6.length != this.maxSegments + 1 || !f_){return !({});}for(var o9=0;o9 < J6.length - 1;o9++){A0$="s";A0$+="e";A0$+="gme";A0$+="nt";if(m3.Drawing.BaseTwoPoint.prototype.lineIntersection.call(this,T5,R6,x5,A0$,J6[o9],J6[o9 + +"1"])){return !"";}}return !!0;};m3.Drawing.gartley.prototype.boxIntersection=function(N9,X9,Y5){var F8,W_;if(!this.p0 || !this.p1){return !!0;}if(Y5.x0 > Math.max(this.p0[0],this.p1[0]) || Y5.x1 < Math.min(this.p0[0],this.p1[0])){return !({});}F8=Math.min(this.p0[1],this.p1[1]);W_=Math.max(this.p0[1],this.p1[1]);for(var z4=0;z4 < this.points.length;z4++){F8=Math.min(F8,this.points[z4][1]);W_=Math.max(W_,this.points[z4][1]);}if(Y5.y1 > W_ || Y5.y0 < F8){return !({});}return !!({});};m3.Drawing.gartley.prototype.reposition=function(K_,z3,j5,l7){q2h.T$X();var J_,r4,w1;if(!z3){return;}J_=this.stx.panels[this.panelName];r4=z3.tick - j5;z3.tick=j5;w1=z3.value - l7;z3.value=l7;if(z3.action == "move"){this.pts=[];for(var M1=0;M1 < this.points.length;M1++){this.points[M1][0]-=r4;this.points[M1][1]-=w1;q2h.j7J(14);this.setPoint(q2h.a$j("1",0),this.points[M1][0],this.points[M1][1],J_.chart);if(M1 && M1 < this.points.length - 1){this.pts.push(this.d1,this.tzo1,this.v1);}this.points[M1]=this.p1;}this.setPoint(0,this.points[0][0],this.points[0][1],J_.chart);this.render(K_);;}};m3.Drawing.gartley.prototype.configs=["color",b2f,"lineWidth",u5s];m3.Drawing.gartley.prototype.adjust=function(){var M3;M3=this.stx.panels[this.panelName];if(!M3){return;}q2h.T$X();this.reconstructPoints();this.setPoint(0,this.d0,this.v0,M3.chart);this.points.unshift(this.p0);this.setPoint(1,this.d1,this.v1,M3.chart);this.points.push(this.p1);};m3.Drawing.gartley.prototype.reconstructPoints=function(){var u2,q2;u2=this.stx.panels[this.panelName];if(!u2){return;}this.points=[];for(var B$=0;B$ < this.pts.length;B$+=+"3"){q2=m3.strToDateTime(this.pts[B$]);q2.setMinutes(q2.getMinutes() + Number(this.pts[B$ + 1]) - q2.getTimezoneOffset());this.points.push([this.stx.tickFromDate(m3.yyyymmddhhmmssmmm(q2),u2.chart),this.pts[B$ + 2]]);}};m3.Drawing.gartley.prototype.reconstruct=function(w_,S3){this.stx=w_;this.color=S3.col;this.fillColor=S3.fc;this.panelName=S3.pnl;this.pattern=S3.ptrn;this.lineWidth=S3.lw;this.d0=S3.d0;this.d1=S3.d1;this.tzo0=S3.tzo0;this.tzo1=S3.tzo1;this.v0=S3.v0;this.v1=S3.v1;this.pts=S3.pts.split((5343,9790) === 1784?(598.76,0x569):",");this.adjust();};m3.Drawing.gartley.prototype.serialize=function(){return {name:this.name,pnl:this.panelName,col:this.color,fc:this.fillColor,ptrn:this.pattern,lw:this.lineWidth,d0:this.d0,d1:this.d1,tzo0:this.tzo0,tzo1:this.tzo1,v0:this.v0,v1:this.v1,pts:this.pts.join(608.96 === (4450,2850)?("L",4.60e+2):7366 <= (3483,7910)?",":(+"356.99","K"))};};m3.Drawing.freeform=function(){this.name="freeform";this.splineTension=0.3;q2h.f3X();this.dragToDraw=!"";};m3.inheritsFrom(m3.Drawing.freeform,m3.Drawing.segment);m3.Drawing.freeform.prototype.measure=function(){};m3.Drawing.freeform.prototype.intersected=function(w3,c_,V2){var P7_;P7_="m";P7_+="o";q2h.f3X();P7_+="v";P7_+="e";if(V2.x0 > this.hiX || V2.x1 < this.lowX){return null;}if(V2.y1 > this.hiY || V2.y0 < this.lowY){return null;}this.highlighted=!!1;return {action:P7_,p0:m3.clone(this.p0),tick:w3,value:c_};};m3.Drawing.freeform.prototype.reposition=function(D3,Z5,b3,w0){var u$,u8,A7;if(!Z5){return;}u$=this.stx.panels[this.panelName];u8=Z5.tick - b3;A7=Z5.value - w0;if(Z5.action == "move"){this.setPoint(0,Z5.p0[0] - u8,Z5.p0[+"1"] - A7,u$.chart);this.adjust();this.render(D3);}};m3.Drawing.freeform.prototype.click=function(u7,S2,B_){var H7,H5B,m2;H7=this.stx.panels[this.panelName];if(!H7){return;}if(this.penDown === !!""){H5B="p";H5B+="oin";H5B+="ter";this.copyConfig();this.startX=Math.round(this.stx.resolveX(this.stx.pixelFromTick(S2,H7.chart)));this.startY=Math.round(this.stx.resolveY(this.stx.pixelFromValueAdjusted(H7,S2,B_)));m2=this.stx.dateFromTick(S2,H7.chart,!0);this.d0=m3.yyyymmddhhmmssmmm(m2);this.tzo0=m2.getTimezoneOffset();this.v0=B_;this.p0=[m3.ChartEngine.crosshairX - this.startX,m3.ChartEngine.crosshairY - this.startY];q2h.N_M(29);this.nodes=[this.p0[0],this.p0[q2h.c0C(0,"1")]];this.pNodes=[this.p0];this.candleWidth=this.stx.layout.candleWidth;this.multiplier=H7.yAxis.multiplier;this.interval=this.stx.layout.interval;this.periodicity=this.stx.layout.periodicity;this.tempSplineTension=this.splineTension;this.splineTension=-1;document.body.style.cursor=H5B;this.penDown=!!"1";return !1;}this.penDown=![];this.splineTension=this.tempSplineTension;document.body.style.cursor="auto";return !0;};m3.Drawing.freeform.prototype.move=function(L6,f7,A5){var Z6,K5;if(!this.penDown){return;}Z6=this.stx.panels[this.panelName];K5=this.stx.dateFromTick(f7,Z6.chart,!"");this.d1=m3.yyyymmddhhmmssmmm(K5);this.tzo1=K5.getTimezoneOffset();this.v1=A5;this.p1=[m3.ChartEngine.crosshairX - this.startX,Z6.yAxis.flipped?this.startY - m3.ChartEngine.crosshairY:m3.ChartEngine.crosshairY - this.startY];if(this.pNodes.length > 2){if(this.p1[0] == this.pNodes[this.pNodes.length - 2][0] && this.p1[0] == this.pNodes[this.pNodes.length - 1][0]){this.pNodes.length--;this.nodes.length-=2;}else if(this.p1[1] == this.pNodes[this.pNodes.length - 2][1] && this.p1[1] == this.pNodes[this.pNodes.length - 1][1]){this.pNodes.length--;q2h.j7J(31);this.nodes.length-=q2h.a$j("2",96);}}this.nodes.push(this.p1[0],this.p1["1" ^ 0]);this.pNodes.push(this.p1);this.render(L6);return !!0;};m3.Drawing.freeform.prototype.intervalRatio=function(c5,H$,U0,p5,s5,t9){var E0,Q5w,q6L,N8_,f2x;E0=0;q2h.T$X();if(c5 == H$){E0=1;}else if(!isNaN(c5) && !isNaN(H$)){q2h.j7J(7);E0=q2h.c0C(c5,H$);}else if(isNaN(c5)){Q5w="d";Q5w+="a";Q5w+="y";if(c5 == "month"){if(H$ == "week"){E0=a_(s5,t9);}else if(H$ == "day"){E0=j1(s5,t9);}else if(!isNaN(H$)){E0=j1(s5,t9) * U3(s5,t9) / H$;}}else if(c5 == "week"){if(H$ == "month"){q2h.j7J(1);var X0w=q2h.c0C(0,1);E0=X0w / a_(s5,t9);}if(H$ == "day"){E0=L_(s5,t9);}else if(!isNaN(H$)){E0=L_(s5,t9) * U3(s5,t9) / H$;}}else if(c5 == Q5w){q6L="m";q6L+="on";q6L+="t";q6L+="h";if(H$ == "week"){q2h.j7J(45);var a46=q2h.a$j(4,8,9,12);E0=("1" | a46) / L_(s5,t9);}else if(H$ == q6L){q2h.j7J(27);var J4l=q2h.a$j(11,10);E0=J4l / j1(s5,t9);}else if(!isNaN(H$)){E0=U3(s5,t9) / H$;}}}else if(!isNaN(c5)){N8_="da";N8_+="y";f2x="m";f2x+="onth";if(H$ == f2x){E0=c5 / (j1(s5,t9) * U3(s5,t9));}else if(H$ == "week"){E0=c5 / (L_(s5,t9) * U3(s5,t9));}else if(H$ == N8_){E0=c5 / U3(s5,t9);}}function U3(B0,N_){if(m3.Market.Symbology.isForexSymbol(N_)){return 1440;}return 390;}function L_(B2,l3){return 5;}function j1(p3,V4){var j2G,e_5,O_l;j2G=1114596948;q2h.N_M(46);e_5=-q2h.c0C("1359803321",0);O_l=2;for(var G0z=1;q2h.S9Y(G0z.toString(),G0z.toString().length,+"66475") !== j2G;G0z++){return 30;}if(q2h.O1W(O_l.toString(),O_l.toString().length,37483) !== e_5){return 89;}}q2h.j7J(7);E0*=q2h.c0C(U0,p5);function a_(Z$,z1){q2h.f3X();return 5;}return E0;};m3.Drawing.freeform.prototype.render=function(F5){var y$,S4,a$,V0,d9,Y7,W0,Q9,C9,f5,c9,E6;y$=this.stx.panels[this.panelName];if(!y$){return;}S4=this.intervalRatio(this.interval,this.stx.layout.interval,this.periodicity,this.stx.layout.periodicity,this.d0,y$.chart.symbol);if(S4 === "0" << 64){return;}a$=this.stx.layout.candleWidth / this.candleWidth;V0=y$.yAxis.multiplier / this.multiplier;this.setPoint(0,this.d0,this.v0,y$.chart);d9=this.stx.pixelFromTick(this.p0[0],y$.chart);Y7=this.stx.pixelFromValueAdjusted(y$,this.p0[0],this.p0[1]);W0=[];Q9=this.lineWidth;C9=this.getLineColor();f5={pattern:this.pattern,lineWidth:Q9};for(var u0=0;u0 < this.pNodes.length;u0++){c9=S4 * a$ * this.pNodes[u0][0] + d9;q2h.N_M(39);var f1z=q2h.a$j(11,4,11,3);E6=V0 * this.pNodes[u0][f1z];if(y$.yAxis.flipped){q2h.j7J(14);E6=q2h.a$j(Y7,E6);}else {E6+=Y7;}W0.push(c9,E6);}if(!W0.length){return;}if(this.splineTension < 0){this.stx.connectTheDots(W0,C9,this.name,F5,y$,f5);}else {this.stx.plotSpline(W0,this.splineTension,C9,this.name,F5,!0,f5);}};m3.Drawing.freeform.prototype.adjust=function(){var e_,k_,V5,t$,t7,v9,M9,s9;e_=this.stx.panels[this.panelName];if(!e_){return;}q2h.j7J(29);k_=[this.nodes[0],this.nodes[q2h.c0C(0,"1")]];this.pNodes=[k_];this.lowX=this.nodes[0];this.hiX=this.nodes[+"0"];q2h.N_M(5);this.lowY=this.nodes[q2h.c0C(1,"1")];this.hiY=this.nodes[1];for(var c3=2;c3 < this.nodes.length;c3+=2){q2h.j7J(47);V5=[this.nodes[c3],this.nodes[q2h.a$j(c3,"1")]];this.pNodes.push(V5);this.lowX=Math.min(this.lowX,V5[0]);this.hiX=Math.max(this.hiX,V5[0]);this.lowY=Math.max(this.lowY,V5[1]);this.hiY=Math.min(this.hiY,V5["1" ^ 0]);}t$=this.intervalRatio(this.interval,this.stx.layout.interval,this.periodicity,this.stx.layout.periodicity,this.d0,e_.chart.symbol);if(t$ === 0){return;}t7=this.stx.layout.candleWidth / this.candleWidth;v9=e_.yAxis.multiplier / this.multiplier;this.setPoint(0,this.d0,this.v0,e_.chart);M9=this.stx.pixelFromTick(this.p0[0],e_.chart);s9=this.stx.pixelFromValueAdjusted(e_,this.p0[0],this.p0[1]);this.lowX=this.stx.tickFromPixel(Math.floor(t$ * t7 * this.lowX) + M9,e_.chart);this.hiX=this.stx.tickFromPixel(Math.ceil(t$ * t7 * this.hiX) + M9,e_.chart);if(e_.yAxis.flipped){this.lowY=this.stx.valueFromPixel(s9 - Math.floor(v9 * this.lowY),e_);this.hiY=this.stx.valueFromPixel(s9 - Math.ceil(v9 * this.hiY),e_);}else {this.lowY=this.stx.valueFromPixel(Math.floor(v9 * this.lowY) + s9,e_);this.hiY=this.stx.valueFromPixel(Math.ceil(v9 * this.hiY) + s9,e_);}};m3.Drawing.freeform.prototype.serialize=function(){q2h.f3X();return {name:this.name,pnl:this.panelName,col:this.color,ptrn:this.pattern,lw:this.lineWidth,cw:Number(this.candleWidth.toFixed(4)),mlt:Number(this.multiplier.toFixed(4)),d0:this.d0,tzo0:this.tzo0,v0:this.v0,inter:this.interval,pd:this.periodicity,nodes:this.nodes};};m3.Drawing.freeform.prototype.reconstruct=function(o$,x4){this.stx=o$;q2h.T$X();this.color=x4.col;this.panelName=x4.pnl;this.pattern=x4.ptrn;this.lineWidth=x4.lw;this.candleWidth=x4.cw;this.multiplier=x4.mlt;this.d0=x4.d0;this.tzo0=x4.tzo0;this.v0=x4.v0;this.interval=x4.inter;this.periodicity=x4.pd;this.nodes=x4.nodes;this.adjust();};m3.Drawing.callout=function(){this.name="callout";this.arr=[];this.w=0;this.h=0;this.padding=4;this.text="";this.ta=null;this.fontSize=0;this.font={};this.stemEntry="";this.defaultWidth=50;this.defaultHeight=+"10";;};m3.inheritsFrom(m3.Drawing.callout,m3.Drawing.annotation);m3.Drawing.callout.prototype.configs=["color","fillColor","lineWidth","pattern","font"];m3.Drawing.callout.prototype.copyConfig=function(G$){m3.Drawing.copyConfig(this,G$);this.borderColor=this.color;};m3.Drawing.callout.prototype.move=function(D0,g3,Q2){q2h.T$X();if(!this.penDown){return;}this.copyConfig();this.p0=[g3,Q2];this.render(D0);};m3.Drawing.callout.prototype.onChange=function(n7){var j9,N7,P8;j9=this.stx.panels[this.panelName];if(!j9){return;}N7=n7.target;this.w=N7.clientWidth;this.h=N7.clientHeight;q2h.f3X();P8=this.context || this.stx.chart.tempCanvas.context;m3.clearCanvas(P8.canvas,this.stx);this.render(P8);this.edit(P8);};m3.Drawing.callout.prototype.render=function(J0){var a1,J4,w2,L7,L9,w6,R1,o6,H3,S1,r6,z$,N0,r9,k9,h3M,M3o,E6H,y6,v8_,w73,o3G,n4U,a7h,u7u,C9R,Q0i,X5S,F1z,Y25,i4M,L9A,L3I,H9;this.context=J0;a1=this.stx.panels[this.panelName];if(!a1){return;}J4=this.stx.pixelFromTick(this.p0[0],a1.chart);w2=this.stx.pixelFromValueAdjusted(a1,this.p0[+"0"],this.p0[1]);if(isNaN(w2)){return;}J0.font=this.fontString;J0.textBaseline="top";L7=J4;L9=w2;q2h.N_M(28);var K2T=q2h.a$j(338,10,0,17,2);w6=this.w / K2T;q2h.j7J(14);var f42=q2h.a$j(21,19);R1=this.h / f42;if(this.penDown){w6=this.defaultWidth;R1=this.defaultHeight;if(!R1){R1=this.fontSize;}}o6=this.lineWidth;if(!o6){o6=1.1;}H3=this.color;if(H3 == "auto" || m3.isTransparent(H3)){H3=this.stx.defaultColor;}S1=this.borderColor;if(S1 == "auto" || m3.isTransparent(S1)){S1=this.stx.defaultColor;}if(this.highlighted){S1=this.stx.getCanvasColor("stx_highlight_vector");}k9=Math.min(Math.min(w6,R1) / 2,8);if(this.stem){if(this.stem.t){r6=this.stx.pixelFromTick(this.stem.t);N0=this.stx.pixelFromValueAdjusted(a1,this.stem.t,this.stem.v);}else if(this.stem.x){r6=L7;N0=L9;L7+=this.stem.x;L9+=this.stem.y;}h3M=-1801199561;M3o=-1975668760;q2h.N_M(14);E6H=q2h.a$j("2",0);for(var q8D=+"1";q2h.O1W(q8D.toString(),q8D.toString().length,95124) !== h3M;q8D++){y6="";E6H+=2;}if(q2h.S9Y(E6H.toString(),E6H.toString().length,25256) !== M3o){y6="";}if(r6 >= L7 + w6){q2h.j7J(1);z$=q2h.a$j(L7,w6);y6="r";}else if(r6 > L7 - w6 && r6 < L7 + w6){z$=L7;y6="c";}else if(r6 <= L7 - w6){q2h.j7J(14);z$=q2h.a$j(L7,w6);y6="l";}if(N0 >= L9 + R1){v8_=-478116192;w73=223288090;o3G=2;for(var L31=1;q2h.O1W(L31.toString(),L31.toString().length,60354) !== v8_;L31++){q2h.N_M(1);r9=q2h.a$j(L9,R1);y6+="1590" << 64 !== 6145?"b":"j";o3G+=2;}if(q2h.S9Y(o3G.toString(),o3G.toString().length,73834) !== w73){q2h.N_M(14);r9=q2h.c0C(L9,R1);y6/=4911 == 2849?"j":"j";}}else if(N0 > L9 - R1 && N0 < L9 + R1){r9=L9;y6+=(1190,975) == 7450?!!"":("4980" | 16) <= (410.98,722.84)?+"8000" >= (8224,7090)?"O":(!!({}),!1):"m";}else if(N0 <= L9 - R1){q2h.j7J(14);r9=q2h.c0C(L9,R1);y6+=907.48 <= (651.66,9380)?"t":(0x10a1,+"6.04e+3");}this.stemEntry=y6;if(y6 != "cm"){r6=Math.round(r6);z$=Math.round(z$);N0=Math.round(N0);r9=Math.round(r9);}}if(this.highlighted){this.stx.canvasColor("stx_annotation_highlight_bg",J0);}else {if(this.fillColor){J0.fillStyle=this.fillColor;J0.globalAlpha=0.4;}else if(this.stem){J0.fillStyle=this.stx.containerColor;}}J0.strokeStyle=S1;if(J0.setLineDash){J0.setLineDash(m3.borderPatternToArray(o6,this.pattern));J0.lineDashOffset=0;;}if(S1){n4U="l";n4U+="t";a7h="c";a7h+="b";u7u="r";u7u+="b";C9R="r";C9R+="t";J0.beginPath();J0.lineWidth=o6;q2h.j7J(3);J0.moveTo(q2h.c0C(k9,w6,L7),q2h.c0C(L9,R1,q2h.j7J(14)));if(this.stemEntry != C9R){q2h.j7J(1);J0.quadraticCurveTo(q2h.a$j(L7,w6),q2h.c0C(L9,R1,q2h.j7J(14)),q2h.a$j(L7,w6,q2h.N_M(1)),q2h.c0C(L9,k9,R1,q2h.N_M(15)));;}else {J0.lineTo(r6,N0);q2h.N_M(1);J0.lineTo(q2h.c0C(L7,w6),q2h.c0C(L9,k9,R1,q2h.N_M(15)));}q2h.N_M(1);J0.lineTo(q2h.c0C(L7,w6),q2h.c0C(L9,k9,2,q2h.N_M(48)));if(this.stemEntry == "rm"){J0.lineTo(r6,N0);}q2h.j7J(1);J0.lineTo(q2h.c0C(L7,w6),q2h.a$j(2,k9,L9,q2h.N_M(49)));q2h.j7J(1);J0.lineTo(q2h.c0C(L7,w6),q2h.c0C(k9,R1,L9,q2h.N_M(3)));if(this.stemEntry != u7u){q2h.j7J(1);J0.quadraticCurveTo(q2h.c0C(L7,w6),q2h.c0C(L9,R1,q2h.j7J(1)),q2h.a$j(k9,w6,L7,q2h.j7J(3)),q2h.c0C(L9,R1,q2h.j7J(1)));Q0i=-1787821410;X5S=-334914513;F1z=2;for(var a86=1;q2h.O1W(a86.toString(),a86.toString().length,58859) !== Q0i;a86++){;F1z+=2;}if(q2h.O1W(F1z.toString(),F1z.toString().length,43222) !== X5S){;};}else {J0.lineTo(r6,N0);q2h.j7J(3);J0.lineTo(q2h.a$j(k9,w6,L7),q2h.a$j(L9,R1,q2h.j7J(1)));}q2h.j7J(49);J0.lineTo(q2h.a$j(2,k9,L7),q2h.c0C(L9,R1,q2h.j7J(1)));if(this.stemEntry == a7h){J0.lineTo(r6,N0);}q2h.j7J(48);J0.lineTo(q2h.a$j(L7,k9,2),q2h.a$j(L9,R1,q2h.N_M(1)));q2h.j7J(15);J0.lineTo(q2h.a$j(L7,k9,w6),q2h.c0C(L9,R1,q2h.N_M(1)));if(this.stemEntry != "lb"){q2h.N_M(14);J0.quadraticCurveTo(q2h.c0C(L7,w6),q2h.a$j(L9,R1,q2h.j7J(1)),q2h.a$j(L7,w6,q2h.j7J(14)),q2h.a$j(k9,R1,L9,q2h.j7J(3)));Y25=687739654;i4M=+"324565001";L9A=2;for(var s6r=+"1";q2h.O1W(s6r.toString(),s6r.toString().length,21916) !== Y25;s6r++){;L9A+=2;}if(q2h.O1W(L9A.toString(),L9A.toString().length,39618) !== i4M){;}}else {J0.lineTo(r6,N0);q2h.j7J(14);J0.lineTo(q2h.a$j(L7,w6),q2h.c0C(k9,R1,L9,q2h.N_M(3)));}q2h.N_M(14);J0.lineTo(q2h.c0C(L7,w6),q2h.a$j(2,k9,L9,q2h.N_M(49)));if(this.stemEntry == "lm"){J0.lineTo(r6,N0);}q2h.j7J(14);J0.lineTo(q2h.a$j(L7,w6),q2h.a$j(L9,k9,2,q2h.j7J(48)));q2h.j7J(14);J0.lineTo(q2h.c0C(L7,w6),q2h.c0C(L9,k9,R1,q2h.N_M(15)));if(this.stemEntry != n4U){q2h.j7J(14);J0.quadraticCurveTo(q2h.a$j(L7,w6),q2h.a$j(L9,R1,q2h.j7J(14)),q2h.a$j(L7,k9,w6,q2h.j7J(15)),q2h.c0C(L9,R1,q2h.N_M(14)));;}else {J0.lineTo(r6,N0);q2h.j7J(15);J0.lineTo(q2h.c0C(L7,k9,w6),q2h.c0C(L9,R1,q2h.N_M(14)));}q2h.N_M(48);J0.lineTo(q2h.a$j(L7,k9,2),q2h.a$j(L9,R1,q2h.N_M(14)));if(this.stemEntry == "ct"){J0.lineTo(r6,N0);}q2h.j7J(50);J0.lineTo(q2h.c0C("2",L7,k9),q2h.c0C(L9,R1,q2h.j7J(14)));q2h.N_M(3);J0.lineTo(q2h.c0C(k9,w6,L7),q2h.a$j(L9,R1,q2h.j7J(14)));J0.fill();J0.globalAlpha=1;if(this.pattern != "none"){J0.stroke();}}q2h.T$X();if(this.highlighted){L3I="st";L3I+="x_annotation_highl";L3I+="ight";this.stx.canvasColor(L3I,J0);}else {J0.fillStyle=H3;}L9+=this.padding;if(!this.ta){for(var H0=+"0";H0 < this.arr.length;H0++){J0.fillText(this.arr[H0],L7 - w6 + this.padding,L9 - R1);L9+=this.fontSize;}}J0.textBaseline="alphabetic";if(this.highlighted && !this.noHandles){H9=this.highlighted == "p0"?!!({}):!"1";this.littleCircle(J0,r6,N0,H9);};};m3.Drawing.callout.prototype.click=function(S_,W4,g5){var L5;if(this.stx.overXAxis || this.stx.overYAxis){return;}L5=this.stx.panels[this.panelName];this.copyConfig();this.setPoint(0,W4,g5,L5.chart);if(!this.penDown){this.stem={d:this.d0,v:this.v0};this.penDown=!0;this.adjust();return !!0;}this.adjust();q2h.T$X();this.edit(S_);this.penDown=!!0;return !!"";};m3.Drawing.callout.prototype.reposition=function(w$,J1,v3,k2){var R9,J$,J7,O5F;if(!J1){return;}R9=this.stx.panels[this.panelName];J$=J1.tick - v3;J7=J1.value - k2;if(J1.stem){O5F="d";O5F+="ra";O5F+="g";if(J1.action == O5F){this.stem={d:this.stx.dateFromTick(v3,R9.chart,!0),v:k2};}else if(J1.action == "move"){this.setPoint(0,J1.p0[0] - J$,J1.p0[1] - J7,R9.chart);this.stem={d:this.stx.dateFromTick(this.stx.tickFromDate(J1.stem.d,R9.chart) - J$),v:J1.stem.v - J7};}this.adjust();}else {this.setPoint(0,J1.p0[0] - J$,J1.p0[1] - J7,R9.chart);}this.render(w$);};m3.Drawing.callout.prototype.lineIntersection=function(F4,n9,q4,y4){var f4,P0,r8,b_,E8,R3,X1,L0,l5,G5,s6,g6;f4=this.stx.panels[this.panelName];q2h.f3X();P0=this.stem;r8=this.p0;b_=this.stx;if(!r8 || !P0 || !f4){return !({});}E8=P0.t || this.stx.tickFromDate(P0.d,f4.chart);R3={x0:r8["0" << 32],x1:E8,y0:r8[+"1"],y1:P0.v};X1=m3.convertBoxToPixels(b_,this.panelName,R3);L0=X1.x0;l5=X1.y0;G5=X1.x1;s6=X1.y1;if(typeof this.stemEntry == "string"){if(this.stemEntry.indexOf("l") > -("1" - 0)){L0-=this.w / +"2";}else if(this.stemEntry.indexOf("r") > -("1" ^ 0)){q2h.N_M(27);var u4A=q2h.a$j(12,10);L0+=this.w / u4A;}if(this.stemEntry.indexOf("t") > -("1" * 1)){q2h.N_M(19);var o2j=q2h.a$j(8,10,6,478);l5-=this.h / o2j;}else if(this.stemEntry.indexOf("b") > -1){l5+=this.h / +"2";}}g6=m3.convertBoxToPixels(b_,this.panelName,q4);return m3.boxIntersects(g6.x0,g6.y0,g6.x1,g6.y1,L0,l5,G5,s6,y4);};m3.Drawing.callout.prototype.intersected=function(I5,x6,Z8){var y5,g3U,K7,Y0,U7,r2,P4,k93,a5Y;y5=this.stx.panels[this.panelName];if(!this.p0){return null;}if(this.pointIntersection(this.stem.t,this.stem.v,Z8)){g3U="p";g3U+="0";this.highlighted=g3U;return {action:"drag",stem:!![]};}q2h.N_M(45);var l23=q2h.a$j(1,7,1,10);K7=this.stx.pixelFromTick(this.p0[0],y5.chart) - this.w / l23;q2h.j7J(51);var O9X=q2h.a$j(7,3,5,3);q2h.j7J(52);var Y2o=q2h.c0C(9,15,4);Y0=this.stx.pixelFromValueAdjusted(y5,this.p0[0],this.p0[O9X]) - this.h / Y2o;U7=K7 + this.w;r2=Y0 + this.h;if(this.stem && this.stem.x){K7+=this.stem.x;U7+=this.stem.x;Y0+=this.stem.y;r2+=this.stem.y;}P4=this.stx.pixelFromTick(I5,y5.chart);k93=this.stx.pixelFromValueAdjusted(y5,I5,x6);if(P4 + Z8.r >= K7 && P4 - Z8.r <= U7 && k93 + Z8.r >= Y0 && k93 - Z8.r <= r2){this.highlighted=!!({});return {p0:m3.clone(this.p0),tick:I5,value:x6};}a5Y=this.lineIntersection(I5,x6,Z8,"segment");if(a5Y){this.highlighted=!"";return {action:"move",stem:m3.clone(this.stem),p0:m3.clone(this.p0),tick:I5,value:x6};}return null;};m3.Drawing.fibonacci=function(){var U7M;U7M="f";U7M+="ibonacci";this.name="fibonacci";this.configurator=U7M;};m3.inheritsFrom(m3.Drawing.fibonacci,m3.Drawing.BaseTwoPoint);m3.Drawing.fibonacci.mapping={trend:(356.29,519.05) <= "5104" * 1?"t":"7515" << 64 <= "328.86" * 1?"3.28e+3" - 0:6.80e+3,color:(1900,9454) >= (+"6660",+"4790")?"c":32.02 > (481.19,9576)?("890.68" * 1,!!"1"):("98.06" - 0,210.23) >= (7039,"517.36" * 1)?!!"":![],parameters:41.14 != +"4162"?"p":(0x17fb,0xb3b),pattern:"pt",opacity:4739 !== 283?"o":482.67,lineWidth:"lw",level:(+"2392",9934) >= 4100?"l":(!"",0x1dff),extendLeft:810.06 < "77.96" * 1?(160.76,9.84e+3):5289 === (6815,"3644" - 0)?0x2e4:"e",printLevels:"pl",printValues:"pv",timezone:"tz",display:"d"};q2h.N_M(14);m3.Drawing.fibonacci.prototype.recommendedLevels=[-0.618,-q2h.a$j("0.382",0),0,0.382,0.5,0.618,1,1.382,1.618];m3.Drawing.fibonacci.prototype.configs=["color","fillColor","lineWidth","pattern","parameters"];m3.Drawing.fibonacci.prototype.initializeSettings=function(I29){var k0D,j_w;k0D=this.recommendedLevels;if(k0D && !I29.currentVectorParameters.fibonacci.fibsAlreadySet){j_w=I29.currentVectorParameters.fibonacci.fibs;for(var E3b=0;E3b < j_w.length;E3b++){delete j_w[E3b].display;for(var Z$h="0" >> 0;Z$h < k0D.length;Z$h++){if(j_w[E3b].level == k0D[Z$h]){j_w[E3b].display=!!"1";}}}}};m3.Drawing.fibonacci.prototype.setOuter=function(){var i9W,g_X,P8s,T5i,w$_,X14,G7h,o2N,I8f,C1p,r1P,o_U,a3j,C3W;i9W=this.stx;g_X=i9W.panels[this.panelName];if(!g_X){return;}P8s=Math.max(this.p0[1],this.p1[1]);T5i=Math.min(this.p0[1],this.p1["1" - 0]);q2h.N_M(14);w$_=q2h.a$j(P8s,T5i);q2h.f3X();this.outer={p0:m3.clone(this.p0),p1:m3.clone(this.p1)};X14=i9W.pixelFromValueAdjusted(g_X,this.p0[0],this.p0[1]);G7h=i9W.pixelFromValueAdjusted(g_X,this.p1[0],this.p1[1]);o2N=i9W.pixelFromTick(this.p0[0],g_X.chart);I8f=i9W.pixelFromTick(this.p1[0],g_X.chart);C1p=+"0";r1P=+"1";for(var D0v=0;D0v < this.parameters.fibs.length;D0v++){o_U=this.parameters.fibs[D0v];if(o_U.level >= C1p && o_U.level <= r1P || !o_U.display)continue;a3j=i9W.pixelFromValueAdjusted(g_X,this.p0[0],G7h < X14?P8s - w$_ * o_U.level:T5i + w$_ * o_U.level);C3W=m3.xIntersection({x0:o2N,x1:I8f,y0:X14,y1:G7h},a3j);if(o_U.level < C1p){C1p=o_U.level;this.outer.p1[1]=i9W.valueFromPixel(a3j,g_X);this.outer.p1[0]=i9W.tickFromPixel(C3W,g_X.chart);}else if(o_U.level > r1P){r1P=o_U.level;this.outer.p0[1]=i9W.valueFromPixel(a3j,g_X);this.outer.p0[0]=i9W.tickFromPixel(C3W,g_X.chart);}}};m3.Drawing.fibonacci.prototype.click=function(f0Q,I9I,R9_){var W5i;W5i=this.stx.panels[this.panelName];if(!W5i){return;}q2h.f3X();this.copyConfig();if(!this.penDown){this.setPoint(0,I9I,R9_,W5i.chart);this.penDown=!!({});return !({});}if(this.accidentalClick(I9I,R9_)){return this.dragToDraw;}this.setPoint(1,I9I,R9_,W5i.chart);this.setOuter();this.parameters=m3.clone(this.parameters);this.penDown=!!0;return !!"1";;};m3.Drawing.fibonacci.prototype.render=function(m6H){var a6x,j4v,i5D,T$D,F92,V1g,t2X,O7M,m2N,E8T,B3a,b31,Q6c,p8u,q72,s1c,V$K,b3k,o35,n5h,e81,d1z,b67,N1I,O$r,p52,Y95,P0G,Z_1,z3i,C0e,H9z,O6Z,T6K,e74,X7K,B1f,r3N,M1Q,r9V,f4K;a6x="161";a6x+=".8";a6x+="%";j4v=this.stx.panels[this.panelName];if(!j4v){return;}i5D=j4v.yAxis;if(!this.p1){return;}T$D=Math.max(this.p0[1],this.p1[1]);F92=Math.min(this.p0[+"1"],this.p1[1]);V1g=i5D.flipped?F92 - T$D:T$D - F92;t2X=this.stx.pixelFromTick(this.p0[0],j4v.chart);O7M=this.stx.pixelFromTick(this.p1[0],j4v.chart);m2N=this.stx.pixelFromValueAdjusted(j4v,this.p0[0],this.p0[1]);E8T=this.stx.pixelFromValueAdjusted(j4v,this.p1[0],this.p1[1]);B3a=Math.min(E8T,m2N);b31=Math.max(E8T,m2N);q2h.j7J(14);Q6c=q2h.a$j(b31,B3a);q2h.N_M(53);p8u=q2h.c0C(0,E8T,m2N,t2X,O7M);q72={color:"auto",parameters:{pattern:"solid",opacity:0.25,lineWidth:1}};if(!this.parameters.trend){this.parameters.trend=q72;}s1c=this.getLineColor(this.parameters.trend.color);m6H.textBaseline="middle";this.stx.canvasFont("stx_yaxis",m6H);q2h.N_M(3);var H19=q2h.a$j(0,4,6);V$K=m6H.measureText(a6x).width + H19;b3k=Number.MAX_VALUE;o35=Number.MAX_VALUE;q2h.N_M(54);var G3L=q2h.c0C(16,18,4,1,4);n5h=Number.MAX_VALUE * G3L;q2h.j7J(3);var Y4M=q2h.a$j(28,12,15);e81=Number.MAX_VALUE * Y4M;q2h.f3X();d1z=this.color;if(d1z == "auto" || m3.isTransparent(d1z)){d1z=this.stx.defaultColor;}this.rays=[];for(var e3r=0;e3r < this.parameters.fibs.length;e3r++){b67="un";b67+="defined";N1I="s";N1I+="e";N1I+="gmen";N1I+="t";O$r="a";O$r+="uto";p52="au";p52+="t";p52+="o";m6H.textAlign="left";m6H.fillStyle=d1z;Y95=this.parameters.fibs[e3r];if(!Y95.display)continue;P0G=this.stx.pixelFromValueAdjusted(j4v,this.p0[0],E8T < m2N?T$D - V1g * Y95.level:F92 + V1g * Y95.level);Z_1=m3.xIntersection({x0:t2X,x1:O7M,y0:m2N,y1:E8T},P0G);z3i=this.parameters.extendLeft?0:Z_1;C0e=j4v.left + j4v.width;if(this.parameters.printLevels){q2h.j7J(55);var h8u=q2h.c0C(2,60,0,12);H9z=Math.round(Y95.level * +"1000") / h8u + "%";C0e-=V$K;if(this.parameters.printValues){m6H.fillStyle=d1z;this.stx.canvasFont("stx_yaxis",m6H);;}if(C0e < z3i){m6H.textAlign="right";}m6H.fillText(H9z,C0e,P0G);if(C0e < z3i){C0e+=5;}else {C0e-=5;}}if(this.parameters.printValues){if(Z_1 < j4v.width){O6Z=this.stx.transformedPriceFromPixel(P0G,j4v);if(i5D.priceFormatter){O6Z=i5D.priceFormatter(this.stx,j4v,O6Z);}else {O6Z=this.stx.formatYAxisPrice(O6Z,j4v);}if(m6H == this.stx.chart.context){this.stx.endClip();}this.stx.createYAxisLabel(j4v,O6Z,P0G,d1z,null,m6H);if(m6H == this.stx.chart.context){this.stx.startClip(j4v.name);}}}T6K=Y95.color;if(T6K == p52 || m3.isTransparent(T6K)){T6K=this.color;}if(T6K == "auto" || m3.isTransparent(T6K)){T6K=this.stx.defaultColor;}e74=Y95.color;if(e74 == "auto" || m3.isTransparent(e74)){e74=this.fillColor;}if(e74 == O$r || m3.isTransparent(e74)){e74=this.stx.defaultColor;}m6H.fillStyle=e74;X7K=m3.clone(Y95.parameters);if(this.highlighted){X7K.opacity=1;}this.stx.plotLine(z3i,C0e,P0G,P0G,this.highlighted?s1c:T6K,N1I,m6H,j4v,X7K);this.rays.push([[z3i,P0G],[C0e,P0G]]);m6H.globalAlpha=0.05;m6H.beginPath();m6H.moveTo(C0e,P0G);m6H.lineTo(z3i,P0G);if(z3i){m6H.lineTo(O7M,E8T);}else {m6H.lineTo(z3i,E8T);}m6H.lineTo(C0e,E8T);if(typeof e74 != b67){m6H.fill();}m6H.globalAlpha=1;if(P0G < o35){b3k=Z_1;o35=P0G;}if(P0G > e81){n5h=Z_1;e81=P0G;}}for(var E9C=0;E9C <= 1;E9C++){B1f=p8u?b31 - Q6c * E9C:B3a + Q6c * E9C;B1f=Math.round(B1f);if(B1f < o35){b3k=m3.xIntersection({x0:t2X,x1:O7M,y0:m2N,y1:E8T},B1f);o35=B1f;}if(B1f > e81){n5h=m3.xIntersection({x0:t2X,x1:O7M,y0:m2N,y1:E8T},B1f);e81=B1f;}}r3N=m3.clone(this.parameters.trend.parameters);if(this.highlighted){r3N.opacity=1;}this.stx.plotLine(b3k,n5h,o35,e81,s1c,"segment",m6H,j4v,r3N);if(this.highlighted){M1Q="p";M1Q+="1";r9V=this.highlighted == "p0"?!"":!!0;f4K=this.highlighted == M1Q?!!"1":![];this.littleCircle(m6H,t2X,m2N,r9V);this.littleCircle(m6H,O7M,E8T,f4K);}};m3.Drawing.fibonacci.prototype.reposition=function(j3Y,B_r,k_p,F0I){var l$L,c$T,o4X;if(!B_r){return;}q2h.N_M(14);l$L=-q2h.c0C("1127652126",0);c$T=1278312784;o4X=2;for(var O$s=1;q2h.S9Y(O$s.toString(),O$s.toString().length,"54347" ^ 0) !== l$L;O$s++){m3.Drawing.BaseTwoPoint.prototype.reposition.apply(this,arguments);this.adjust();q2h.N_M(5);o4X+=q2h.a$j(1,"2");}q2h.f3X();if(q2h.O1W(o4X.toString(),o4X.toString().length,+"84820") !== c$T){m3.Drawing.BaseTwoPoint.prototype.reposition.apply(this,arguments);this.adjust();}};m3.Drawing.fibonacci.prototype.intersected=function(n3J,T$h,c5N){var J93,o0K,Y7C,V4f,K3s,u3g,v4b;J93="s";J93+="egme";J93+="nt";o0K=this.p0;Y7C=this.p1;if(!o0K || !Y7C){return null;}V4f={0:o0K,1:Y7C};for(var C7E in V4f){if(this.pointIntersection(V4f[C7E][0],V4f[C7E][+"1"],c5N)){q2h.j7J(1);this.highlighted=q2h.c0C(805.08 === (132,3074)?(6.69e+3,+"982"):(3870,4862) > 4890?(9318,989.6) < (889.8,4539)?(9.16e+3,!({})):"h":"p",C7E);return {action:"drag",point:"p" + C7E};}}q2h.T$X();K3s=this.outer;u3g=this.rays;v4b=K3s && this.lineIntersection(n3J,T$h,c5N,J93,K3s.p0,K3s.p1);if(!v4b){for(var X3N=0;X3N < u3g.length;X3N++){if(this.lineIntersection(n3J,T$h,c5N,"ray",u3g[X3N][0],u3g[X3N][1],!!({}))){v4b=!0;break;}}}if(v4b){this.highlighted=!0;return {action:"move",p0:m3.clone(o0K),p1:m3.clone(Y7C),tick:n3J,value:T$h};}return null;};m3.Drawing.fibonacci.prototype.reconstruct=function(L8j,Q_P){Q_P=m3.replaceFields(Q_P,m3.reverseObject(m3.Drawing.fibonacci.mapping));this.stx=L8j;this.parameters=Q_P.parameters;if(!this.parameters){this.parameters=m3.clone(this.stx.currentVectorParameters.fibonacci);}this.color=Q_P.col;this.fillColor=Q_P.fc;this.panelName=Q_P.pnl;this.d0=Q_P.d0;this.d1=Q_P.d1;this.d2=Q_P.d2;this.tzo0=Q_P.tzo0;this.tzo1=Q_P.tzo1;this.tzo2=Q_P.tzo2;this.v0=Q_P.v0;this.v1=Q_P.v1;this.v2=Q_P.v2;q2h.T$X();this.adjust();};m3.Drawing.fibonacci.prototype.adjust=function(){q2h.T$X();var C2I;C2I=this.stx.panels[this.panelName];if(!C2I){return;}this.setPoint(0,this.d0,this.v0,C2I.chart);this.setPoint(+"1",this.d1,this.v1,C2I.chart);this.setOuter();};m3.Drawing.fibonacci.prototype.serialize=function(){var K1k;q2h.f3X();K1k={name:this.name,parameters:this.parameters,pnl:this.panelName,col:this.color,fc:this.fillColor,d0:this.d0,d1:this.d1,d2:this.d2,tzo0:this.tzo0,tzo1:this.tzo1,tzo2:this.tzo2,v0:this.v0,v1:this.v1,v2:this.v2};return m3.replaceFields(K1k,m3.Drawing.fibonacci.mapping);};m3.Drawing.retracement=function(){var a_S;q2h.T$X();a_S="ret";a_S+="racement";this.name=a_S;};m3.inheritsFrom(m3.Drawing.retracement,m3.Drawing.fibonacci);m3.Drawing.fibprojection=function(){q2h.f3X();this.name="fibprojection";this.dragToDraw=!!0;this.p2=null;};m3.inheritsFrom(m3.Drawing.fibprojection,m3.Drawing.fibonacci);m3.Drawing.fibprojection.prototype.recommendedLevels=[0,0.618,1,1.272,1.618,2.618,+"4.236"];m3.Drawing.fibprojection.prototype.click=function(e6Z,S9s,E5r){var Z3z;Z3z=this.stx.panels[this.panelName];if(!Z3z){return;}this.copyConfig();if(!this.penDown){this.setPoint(0,S9s,E5r,Z3z.chart);this.penDown=!!"1";return ![];}if(this.accidentalClick(S9s,E5r)){this.stx.undo();return !!({});}if(this.p2 !== null){this.setPoint(2,this.p2[0],this.p2[1],Z3z.chart);this.parameters=m3.clone(this.parameters);return !![];}this.setPoint(1,S9s,E5r,Z3z.chart);this.p2=[this.p1[0],this.p1[1]];return ![];;};m3.Drawing.fibprojection.prototype.render=function(D0r){var z9C,q3f,O8U,M0T,O09,S0b,b66,Q5P,Q9x,I9N,A0g,f9D,X7S,i4x,t9N,L2K,I1J,m6_,i75,Y2n,C$g,e2E,o06,H5h,M35,l8c,S5I,Q3M,u7f,l9b,l6w,a4o,R7M,F3L;z9C="1";z9C+="6";q2h.f3X();z9C+="1.8%";q3f=this.stx.panels[this.panelName];if(!q3f){return;}O8U=q3f.yAxis;if(!this.p1){return;}q2h.j7J(18);var k_k=q2h.a$j(27,10,20,14);q2h.j7J(21);var N6N=q2h.a$j(261,20,13);M0T=this.p1["1" * k_k] - this.p0[N6N];O09=this.stx.pixelFromTick(this.p0[0],q3f.chart);S0b=-65720527;b66=-2019386272;Q5P=+"2";for(var T1b=1;q2h.O1W(T1b.toString(),T1b.toString().length,72157) !== S0b;T1b++){Q9x=this.stx.pixelFromTick(this.p1[6],q3f.chart);Q5P+=2;}if(q2h.O1W(Q5P.toString(),Q5P.toString().length,+"48866") !== b66){Q9x=this.stx.pixelFromTick(this.p1[3],q3f.chart);}Q9x=this.stx.pixelFromTick(this.p1[0],q3f.chart);I9N=this.stx.pixelFromValueAdjusted(q3f,this.p0[0],this.p0[1]);A0g=this.stx.pixelFromValueAdjusted(q3f,this.p1[0],this.p1[1]);f9D=null;X7S=null;if(this.p2){f9D=this.stx.pixelFromTick(this.p2[0],q3f.chart);X7S=this.stx.pixelFromValueAdjusted(q3f,this.p2[+"0"],this.p2[1]);}i4x={color:"auto",parameters:{pattern:"solid",opacity:0.25,lineWidth:1}};if(!this.parameters.trend){this.parameters.trend=i4x;}t9N=this.getLineColor(this.parameters.trend.color);D0r.textBaseline="middle";this.stx.canvasFont("stx_yaxis",D0r);q2h.j7J(15);var G6T=q2h.a$j(6,15,11);L2K=D0r.measureText(z9C).width + G6T;I1J=this.color;if(I1J == "auto" || m3.isTransparent(I1J)){I1J=this.stx.defaultColor;}if(this.p2){this.rays=[];for(var E6Z=0;E6Z < this.parameters.fibs.length;E6Z++){m6_="se";m6_+="gme";m6_+="nt";D0r.textAlign="left";D0r.fillStyle=I1J;i75=this.parameters.fibs[E6Z];if(!i75.display)continue;Y2n=this.stx.pixelFromValueAdjusted(q3f,this.p2[0],this.p2[1] + M0T * i75.level);C$g=m3.xIntersection({x0:O09,x1:Q9x,y0:I9N,y1:A0g},Y2n);e2E=this.parameters.extendLeft?0:O09;o06=q3f.left + q3f.width;if(this.parameters.printLevels){q2h.N_M(56);var G10=q2h.a$j(11,1,1,20);q2h.N_M(57);var O3d=q2h.c0C(95500,20,10,4,480);q2h.N_M(1);var A2j=q2h.a$j(3,29);H5h=Math.round(i75.level * +"1000") / G10 + (("7517" ^ 0) > (+"730",O3d)?"%":(![],"6.89e+3" << A2j));o06-=L2K;if(this.parameters.printValues){M35="stx_y";M35+="a";M35+="xis";D0r.fillStyle=I1J;this.stx.canvasFont(M35,D0r);;}if(o06 < e2E){D0r.textAlign="right";}D0r.fillText(H5h,o06,Y2n);if(o06 < e2E){o06+=5;}else {o06-=5;}}if(this.parameters.printValues){if(C$g < q3f.width){l8c=this.stx.transformedPriceFromPixel(Y2n,q3f);if(O8U.priceFormatter){l8c=O8U.priceFormatter(this.stx,q3f,l8c);}else {l8c=this.stx.formatYAxisPrice(l8c,q3f);}if(D0r == this.stx.chart.context){this.stx.endClip();}this.stx.createYAxisLabel(q3f,l8c,Y2n,I1J,null,D0r);if(D0r == this.stx.chart.context){this.stx.startClip(q3f.name);}}}S5I=i75.color;if(S5I == "auto" || m3.isTransparent(S5I)){S5I=this.color;}if(S5I == "auto" || m3.isTransparent(S5I)){S5I=this.stx.defaultColor;}Q3M=i75.color;if(Q3M == "auto" || m3.isTransparent(Q3M)){Q3M=this.fillColor;}if(Q3M == "auto" || m3.isTransparent(Q3M)){Q3M=this.stx.defaultColor;}D0r.fillStyle=Q3M;u7f=m3.clone(i75.parameters);if(this.highlighted){u7f.opacity=1;}this.stx.plotLine(e2E,o06,Y2n,Y2n,this.highlighted?t9N:S5I,m6_,D0r,q3f,u7f);this.rays.push([[e2E,Y2n],[o06,Y2n]]);q2h.N_M(5);D0r.globalAlpha=q2h.a$j(1,"0.05");D0r.beginPath();D0r.moveTo(o06,Y2n);D0r.lineTo(e2E,Y2n);if(e2E){D0r.lineTo(O09,X7S);}else {D0r.lineTo(e2E,X7S);}D0r.lineTo(o06,X7S);if(typeof Q3M != "undefined"){D0r.fill();}D0r.globalAlpha=1;}}l9b=m3.clone(this.parameters.trend.parameters);if(this.highlighted){l9b.opacity=1;}this.stx.plotLine(O09,Q9x,I9N,A0g,t9N,"segment",D0r,q3f,l9b);if(this.p2){this.stx.plotLine(Q9x,f9D,A0g,X7S,t9N,"segment",D0r,q3f,l9b);}if(this.highlighted){l6w="p";l6w+="2";a4o=this.highlighted == "p0"?!"":!1;R7M=this.highlighted == "p1"?!![]:!({});F3L=this.highlighted == l6w?!!({}):![];this.littleCircle(D0r,O09,I9N,a4o);this.littleCircle(D0r,Q9x,A0g,R7M);this.littleCircle(D0r,f9D,X7S,F3L);}};m3.Drawing.fibprojection.prototype.move=function(F9h,K67,u2O){if(!this.penDown){return;}this.copyConfig();if(this.p2 === null){this.p1=[K67,u2O];}else {this.p2=[K67,u2O];}this.render(F9h);};m3.Drawing.fibprojection.prototype.reposition=function(U5r,D4m,T0W,y6o){var o2b,G6c,b6q;if(!D4m){return;}q2h.f3X();o2b=this.stx.panels[this.panelName];G6c=D4m.tick - T0W;b6q=D4m.value - y6o;if(D4m.action == "move"){this.setPoint(0,D4m.p0[+"0"] - G6c,D4m.p0[1] - b6q,o2b.chart);this.setPoint(1,D4m.p1[0] - G6c,D4m.p1[1] - b6q,o2b.chart);this.setPoint(+"2",D4m.p2[0] - G6c,D4m.p2[+"1"] - b6q,o2b.chart);this.render(U5r);}else if(D4m.action == "drag"){this[D4m.point]=[T0W,y6o];this.setPoint(0,this.p0[0],this.p0[1],o2b.chart);this.setPoint(1,this.p1[0],this.p1[1],o2b.chart);q2h.j7J(46);this.setPoint(q2h.c0C("2",0),this.p2[0],this.p2[1],o2b.chart);this.render(U5r);}};m3.Drawing.fibprojection.prototype.intersected=function(c9b,A$m,A2f){var q0Z,R0G,m3j,V5a,h42,R63,C3v,G11,E0Q,Z4$,W46;q0Z="segme";q0Z+="nt";R0G=this.p0;m3j=this.p1;V5a=this.p2;h42=-1491408712;R63=125374011;C3v=2;for(var G0u=1;q2h.S9Y(G0u.toString(),G0u.toString().length,50528) !== h42;G0u++){if(~R0G && -m3j && ~V5a){return 1;}C3v+=2;}if(q2h.S9Y(C3v.toString(),C3v.toString().length,98777) !== R63){if(!R0G || !m3j || !V5a){return null;}}G11={0:R0G,1:m3j,2:V5a};q2h.f3X();for(var y9i in G11){if(this.pointIntersection(G11[y9i][+"0"],G11[y9i][1],A2f)){q2h.N_M(1);this.highlighted=q2h.c0C((3971,300.49) == 969.29?(!![],!!0):"p",y9i);return {action:"drag",point:"p" + y9i};}}E0Q=this.rays;Z4$=this.lineIntersection(c9b,A$m,A2f,"segment",R0G,m3j) || this.lineIntersection(c9b,A$m,A2f,q0Z,m3j,V5a);if(!Z4$){for(var z35=+"0";z35 < E0Q.length;z35++){W46="r";W46+="a";W46+="y";if(this.lineIntersection(c9b,A$m,A2f,W46,E0Q[z35][0],E0Q[z35][1],!0)){Z4$=!!"1";break;}}}if(Z4$){this.highlighted=!![];return {action:"move",p0:m3.clone(R0G),p1:m3.clone(m3j),p2:m3.clone(V5a),tick:c9b,value:A$m};}return null;};m3.Drawing.fibprojection.prototype.adjust=function(){var m70;m70=this.stx.panels[this.panelName];if(!m70){return;}q2h.f3X();q2h.j7J(4);this.setPoint(q2h.a$j("0",0),this.d0,this.v0,m70.chart);q2h.N_M(31);this.setPoint(q2h.c0C("1",96),this.d1,this.v1,m70.chart);this.setPoint(2,this.d2,this.v2,m70.chart);};m3.Drawing.fibarc=function(){this.name="fibarc";q2h.f3X();;};m3.inheritsFrom(m3.Drawing.fibarc,m3.Drawing.fibonacci);m3.Drawing.fibarc.prototype.recommendedLevels=[0.382,0.5,0.618,1];m3.Drawing.fibarc.prototype.setOuter=function(){var Q4r,x$c,l3e,c1p,L2O,r_B,Q8y;Q4r=this.stx.panels[this.panelName];if(!Q4r){return;}q2h.T$X();this.outer={p0:m3.clone(this.p0),p1:m3.clone(this.p1)};x$c=this.stx.pixelFromValueAdjusted(Q4r,this.p0[0],this.p0[+"1"]);l3e=this.stx.pixelFromValueAdjusted(Q4r,this.p1[0],this.p1[1]);c1p=this.stx.pixelFromTick(this.p0[0],Q4r.chart);L2O=this.stx.pixelFromTick(this.p1[0],Q4r.chart);q2h.j7J(58);r_B=q2h.c0C(l3e,x$c,0,"2");Q8y=m3.xIntersection({x0:c1p,x1:L2O,y0:x$c,y1:l3e},r_B);this.outer.p0[1]=this.stx.valueFromPixel(r_B,Q4r);this.outer.p0[+"0"]=this.stx.tickFromPixel(Q8y,Q4r.chart);};m3.Drawing.fibarc.prototype.intersected=function(L$b,E3I,K5$){var i5B,H29,P3v,x$N,D_b,G_r,c93,u2q,k_e,D78,P1v;i5B="s";i5B+="e";i5B+="gme";i5B+="nt";H29=this.stx.panels[this.panelName];if(!H29){return;}P3v=this.p0;x$N=this.p1;D_b=this.outer;if(!P3v || !x$N){return null;}G_r={0:P3v,1:x$N};for(var y0u in G_r){if(this.pointIntersection(G_r[y0u][0],G_r[y0u][1],K5$)){q2h.j7J(1);this.highlighted=q2h.c0C((7264,230.38) == (607.62,227.57)?(211.1,1960) < (340.6,"4890" * 1)?8680 < +"2907"?(899.13,0xb69):"X":("N",0x1515):"p",y0u);return {action:"drag",point:"p" + y0u};}}if(this.lineIntersection(L$b,E3I,K5$,i5B,D_b.p0,D_b.p1)){this.highlighted=!"";return {action:"move",p0:m3.clone(P3v),p1:m3.clone(x$N),tick:L$b,value:E3I};}c93={x0:P3v[0],x1:x$N[0],y0:P3v[1],y1:x$N[1]};u2q=m3.convertBoxToPixels(this.stx,this.panelName,c93);k_e={x:Math.abs(Math.sqrt(2) * (u2q.x1 - u2q.x0)),y:Math.abs(Math.sqrt(+"2") * (u2q.y1 - u2q.y0))};D78=this.stx.pixelFromTick(L$b,H29.chart);P1v=this.stx.pixelFromValueAdjusted(H29,L$b,E3I);if(D78 + K5$.r < u2q.x1 - k_e.x || D78 - K5$.r > u2q.x1 + k_e.x){return null;}if(P1v + K5$.r < u2q.y1 - k_e.y || P1v - K5$.r > u2q.y1 + k_e.y){return null;}if(u2q.y0 < u2q.y1 && P1v - K5$.r > u2q.y1){return null;}if(u2q.y0 > u2q.y1 && P1v + K5$.r < u2q.y1){return null;}this.highlighted=!![];q2h.f3X();return {action:"move",p0:m3.clone(this.p0),p1:m3.clone(this.p1),tick:L$b,value:E3I};};m3.Drawing.fibarc.prototype.render=function(l9c){q2h.f3X();var a5i,P3O,u1A,r_a,g7U,v$d,s0p,L6A,U_k,k12,h__,h1t,t2d,l2$,J6i,d4c,L0q,A7X,T4l,k5T,b99,K4I,J6n,R9O,C_c,i6e,n7x;a5i="lef";a5i+="t";P3O=this.stx.panels[this.panelName];if(!P3O){return;}u1A=P3O.yAxis;if(!this.p1){return;}r_a=this.stx.pixelFromTick(this.p0[0],P3O.chart);g7U=this.stx.pixelFromTick(this.p1[+"0"],P3O.chart);v$d=this.stx.pixelFromValueAdjusted(P3O,this.p0[0],this.p0[+"1"]);s0p=this.stx.pixelFromValueAdjusted(P3O,this.p1[+"0"],this.p1[1]);q2h.j7J(59);L6A=q2h.a$j(s0p,v$d);q2h.j7J(60);U_k=Math.abs(q2h.a$j(g7U,r_a,v$d,s0p));k12=this.getLineColor(this.parameters.trend.color);l9c.textBaseline="middle";this.stx.canvasFont("stx_yaxis",l9c);h__=this.color;if(h__ == "auto" || m3.isTransparent(h__)){h__=this.stx.defaultColor;}for(var D5G=0;D5G < this.parameters.fibs.length;D5G++){h1t="a";h1t+="u";h1t+="to";l9c.fillStyle=h__;t2d=this.parameters.fibs[D5G];if(t2d.level < 0 || !t2d.display)continue;q2h.j7J(9);var p86=q2h.a$j(152,17,9);q2h.j7J(27);var S15=q2h.a$j(17,16);q2h.N_M(61);var Z3d=q2h.c0C(6,6,1);l2$=Math.abs(this.p1[p86] - this.p0[S15]) * Math.sqrt(Z3d) * t2d.level;q2h.N_M(55);var Z_2=q2h.a$j(13,11,12,11);q2h.N_M(62);var G_S=q2h.a$j(5,14,2,8);q2h.N_M(63);var b3P=q2h.c0C(2,6,9);q2h.N_M(51);var i6L=q2h.c0C(7,9,5,3);q2h.j7J(35);var f4t=q2h.a$j(1,20,10);J6i=this.p1[Z_2] + l2$ * (L6A?G_S:b3P) * (u1A.flipped?i6L:f4t);d4c=this.stx.pixelFromValueAdjusted(P3O,this.p0[0],J6i);L0q=m3.xIntersection({x0:r_a,x1:g7U,y0:v$d,y1:s0p},d4c);if(this.parameters.printLevels){A7X="ce";A7X+="nter";l9c.textAlign=A7X;q2h.N_M(3);var w8i=q2h.c0C(18,11,1007);q2h.j7J(61);var e7Y=q2h.a$j(200,200,9);q2h.j7J(1);var d0J=q2h.c0C(9931,9);q2h.N_M(64);var i3L=q2h.c0C(1,5,1545773,13,119613);T4l=Math.round(t2d.level * w8i) / e7Y + (d0J == (i3L,679.16)?608.63:"%");if(this.parameters.printValues){k5T="stx_ya";k5T+="x";k5T+="is";l9c.fillStyle=h__;this.stx.canvasFont(k5T,l9c);;}l9c.fillText(T4l,g7U,Math.round(d4c - 5));}l9c.textAlign="left";if(this.parameters.printValues){if(L0q < P3O.width){b99=J6i;if(u1A.priceFormatter){b99=u1A.priceFormatter(this.stx,P3O,b99);}else {b99=this.stx.formatYAxisPrice(b99,P3O);}if(l9c == this.stx.chart.context){this.stx.endClip();}this.stx.createYAxisLabel(P3O,b99,d4c,h__,null,l9c);if(l9c == this.stx.chart.context){this.stx.startClip(P3O.name);}}}K4I=t2d.color;if(K4I == h1t || m3.isTransparent(K4I)){K4I=this.color;}if(K4I == "auto" || m3.isTransparent(K4I)){K4I=this.stx.defaultColor;}l9c.strokeStyle=this.highlight?k12:K4I;J6n=t2d.color;if(J6n == "auto" || m3.isTransparent(J6n)){J6n=this.fillColor;}if(J6n == "auto" || m3.isTransparent(J6n)){J6n=this.stx.defaultColor;}l9c.fillStyle=J6n;l9c.globalAlpha=this.highlighted?1:t2d.parameters.opacity;l9c.lineWidth=t2d.parameters.lineWidth;if(l9c.setLineDash){l9c.setLineDash(m3.borderPatternToArray(l9c.lineWidth,t2d.parameters.pattern));l9c.lineDashOffset=0;;}l9c.save();l9c.beginPath();q2h.N_M(7);l9c.scale(q2h.c0C(1,U_k),1);q2h.j7J(5);l9c.arc(q2h.a$j(U_k,g7U),s0p,Math.abs(d4c - s0p),0,Math.PI,!L6A);if(this.pattern != "none"){l9c.stroke();}q2h.j7J(5);l9c.globalAlpha=q2h.a$j(1,"0.05");l9c.fill();l9c.restore();if(l9c.setLineDash){l9c.setLineDash([]);}l9c.globalAlpha=+"1";}l9c.textAlign=a5i;R9O=m3.clone(this.parameters.trend.parameters);if(this.highlighted){R9O.opacity=1;}q2h.N_M(9);this.stx.plotLine(g7U,q2h.a$j(g7U,r_a,2),s0p,q2h.c0C(s0p,v$d,2),k12,"segment",l9c,P3O,R9O);if(this.highlighted){C_c="p";C_c+="1";i6e=this.highlighted == "p0"?!!1:!1;n7x=this.highlighted == C_c?!![]:!({});this.littleCircle(l9c,r_a,v$d,i6e);this.littleCircle(l9c,g7U,s0p,n7x);}};m3.Drawing.fibfan=function(){this.name="fibfan";;};m3.inheritsFrom(m3.Drawing.fibfan,m3.Drawing.fibonacci);m3.Drawing.fibfan.prototype.recommendedLevels=[0,+"0.382",0.5,0.618,1];m3.Drawing.fibfan.prototype.setOuter=function(){};m3.Drawing.fibfan.prototype.render=function(Z0x){var i7j,K16,O$g,u$g,k6K,y7V,j1c,D6y,O6M,w_i,A4G,l3G,J8A,y$_,y_K,O2m,Z7U,H6i,v$J,l2G,B_z,v0A,Z41,O$P,i6c,C3c,t2V,S8s,k_o,y0s,Y4D;i7j=this.stx.panels[this.panelName];if(!i7j){return;}K16=i7j.yAxis;if(!this.p1){return;}O$g=this.stx.pixelFromTick(this.p0[0],i7j.chart);u$g=this.stx.pixelFromTick(this.p1[0],i7j.chart);k6K=this.stx.pixelFromValueAdjusted(i7j,this.p0[0],this.p0[1]);y7V=this.stx.pixelFromValueAdjusted(i7j,this.p1[0],this.p1[1]);j1c=Math.min(y7V,k6K);D6y=Math.max(y7V,k6K);q2h.j7J(14);O6M=q2h.c0C(D6y,j1c);q2h.j7J(65);w_i=q2h.a$j(O$g,"0",k6K,u$g,y7V,0);A4G=this.getLineColor(this.parameters.trend.color);Z0x.textBaseline="middle";this.stx.canvasFont("stx_yaxis",Z0x);q2h.N_M(66);var v8Y=q2h.a$j(2,17,12,21);l3G=Z0x.measureText("161.8%").width + v8Y;J8A=Number.MAX_VALUE;q2h.N_M(63);var J3C=q2h.a$j(5,155,192);y$_=Number.MAX_VALUE * -("1" << J3C);y_K=this.color;if(y_K == "auto" || m3.isTransparent(y_K)){y_K=this.stx.defaultColor;}this.rays=[];for(var b7m=0;b7m < this.parameters.fibs.length;b7m++){O2m="aut";O2m+="o";Z0x.fillStyle=y_K;Z7U=this.parameters.fibs[b7m];if(!Z7U.display)continue;H6i=this.stx.pixelFromValueAdjusted(i7j,this.p0[0],(this.p0[1] - this.p1[1]) * Z7U.level + this.p1["1" ^ 0]);v$J=m3.xIntersection({x0:u$g,x1:u$g,y0:k6K,y1:y7V},H6i);l2G=i7j.left;if(u$g > O$g){l2G+=i7j.width;}q2h.j7J(67);B_z=q2h.a$j(O$g,O$g,v$J,l2G,k6K,k6K,H6i);if(O$g > l2G - (this.parameters.printLevels?l3G + 5:0) && u$g > O$g)continue;else if(O$g < l2G + (this.parameters.printLevels?l3G + 5:0) && u$g < O$g)continue;if(this.parameters.printLevels){q2h.N_M(9);var A12=q2h.a$j(9020,10,1002);v0A=Math.round(Z7U.level * A12) / +"10" + "%";if(u$g > O$g){l2G-=l3G;Z0x.textAlign="left";}else {l2G+=l3G;Z0x.textAlign="right";}if(this.parameters.printValues){Z0x.fillStyle=y_K;this.stx.canvasFont("stx_yaxis",Z0x);;}q2h.N_M(67);B_z=q2h.a$j(O$g,O$g,v$J,l2G,k6K,k6K,H6i);Z0x.fillText(v0A,l2G,B_z);if(u$g > O$g){l2G-=+"5";}else {l2G+=5;}}Z0x.textAlign="left";if(this.parameters.printValues){if(v$J < i7j.width){Z41=this.stx.transformedPriceFromPixel(H6i,i7j);if(K16.priceFormatter){Z41=K16.priceFormatter(this.stx,i7j,Z41);}else {Z41=this.stx.formatYAxisPrice(Z41,i7j);}if(Z0x == this.stx.chart.context){this.stx.endClip();}this.stx.createYAxisLabel(i7j,Z41,H6i,y_K,null,Z0x);if(Z0x == this.stx.chart.context){this.stx.startClip(i7j.name);}}}O$P=Z7U.color;if(O$P == "auto" || m3.isTransparent(O$P)){O$P=this.color;}if(O$P == "auto" || m3.isTransparent(O$P)){O$P=this.stx.defaultColor;}i6c=Z7U.color;if(i6c == O2m || m3.isTransparent(i6c)){i6c=this.fillColor;}if(i6c == "auto" || m3.isTransparent(i6c)){i6c=this.stx.defaultColor;}Z0x.fillStyle=i6c;if(this.parameters.printLevels){q2h.N_M(67);B_z=q2h.a$j(O$g,O$g,v$J,l2G,k6K,k6K,H6i);}C3c=m3.clone(Z7U.parameters);if(this.highlighted){C3c.opacity=1;}this.stx.plotLine(O$g,l2G,k6K,B_z,this.highlighted?A4G:O$P,"segment",Z0x,i7j,C3c);this.rays.push([[O$g,k6K],[l2G,B_z]]);Z0x.globalAlpha=+"0.05";Z0x.beginPath();Z0x.moveTo(l2G,B_z);Z0x.lineTo(O$g,k6K);Z0x.lineTo(l2G,k6K);Z0x.fill();Z0x.globalAlpha=1;if(H6i < J8A){J8A=H6i;}if(H6i > y$_){y$_=H6i;}}for(var E7Z="0" - 0;E7Z <= 1;E7Z++){t2V=w_i?D6y - O6M * E7Z:j1c + O6M * E7Z;t2V=Math.round(t2V);if(t2V < J8A){J8A=t2V;}if(t2V > y$_){y$_=t2V;}}if(this.highlighted){S8s="p";S8s+="1";k_o="p";k_o+="0";y0s=this.highlighted == k_o?!!1:!!"";Y4D=this.highlighted == S8s?!0:!"1";this.littleCircle(Z0x,O$g,k6K,y0s);this.littleCircle(Z0x,u$g,y7V,Y4D);}};m3.Drawing.fibtimezone=function(){this.name="fibtimezone";;};m3.inheritsFrom(m3.Drawing.fibtimezone,m3.Drawing.fibonacci);m3.Drawing.fibtimezone.prototype.render=function(x0y){var S$N,S4i,I7j,E$O,Q_V,R_$,N$e,B26,q5P,x6F,i2Z,X5d,H2o,D6q,A5U,B2$,d2_,L3H,h2i,Q0$,s_x,X8e,V_X,n$T;S$N="segmen";S$N+="t";S4i="l";S4i+="e";S4i+="f";S4i+="t";I7j="au";I7j+="to";E$O="mi";E$O+="dd";E$O+="l";E$O+="e";Q_V=this.stx.panels[this.panelName];if(!Q_V){return;}if(!this.p1){return;}R_$=this.stx.pixelFromTick(this.p0[0],Q_V.chart);N$e=this.stx.pixelFromTick(this.p1[0],Q_V.chart);B26=this.stx.pixelFromValueAdjusted(Q_V,this.p0[0],this.p0[1]);q2h.T$X();q5P=this.stx.pixelFromValueAdjusted(Q_V,this.p1["0" | 0],this.p1["1" >> 64]);x6F=[1,0];i2Z=this.getLineColor(this.parameters.trend.color);x0y.textBaseline=E$O;this.stx.canvasFont("stx_yaxis",x0y);q2h.N_M(14);X5d=q2h.c0C("20",0);H2o=this.p1[0] - this.p0[0];D6q=this.color;if(D6q == "auto" || m3.isTransparent(D6q)){D6q=this.stx.defaultColor;}x0y.textAlign="center";A5U=R_$;B2$=Q_V.yAxis.top;d2_=Q_V.yAxis.bottom;L3H=0;h2i=this.parameters.timezone.color;if(h2i == "auto" || m3.isTransparent(h2i)){h2i=this.color;}if(h2i == "auto" || m3.isTransparent(h2i)){h2i=this.stx.defaultColor;}Q0$=this.parameters.timezone.color;if(Q0$ == I7j || m3.isTransparent(Q0$)){Q0$=this.fillColor;}if(Q0$ == "auto" || m3.isTransparent(Q0$)){Q0$=this.stx.defaultColor;}if(this.parameters.printLevels){q2h.j7J(14);d2_-=q2h.a$j(X5d,7);}s_x=m3.clone(this.parameters.timezone.parameters);if(this.highlighted){s_x.opacity=1;}do {A5U=this.stx.pixelFromTick(this.p0["0" - 0] + L3H * H2o,Q_V.chart);if(R_$ < N$e && A5U > Q_V.left + Q_V.width)break;else if(R_$ > N$e && A5U < Q_V.left)break;if(this.parameters.printLevels){x0y.fillStyle=D6q;x0y.fillText(N$e > R_$?L3H:L3H * -1,A5U,d2_ + +"7");}x0y.fillStyle=Q0$;this.stx.plotLine(A5U,A5U,0,d2_,this.highlighted?i2Z:h2i,"segment",x0y,Q_V,s_x);x0y.globalAlpha=0.05;x0y.beginPath();x0y.moveTo(R_$,B2$);x0y.lineTo(A5U,B2$);x0y.lineTo(A5U,d2_);x0y.lineTo(R_$,d2_);x0y.fill();x0y.globalAlpha=1;q2h.j7J(68);var e0u=q2h.a$j(3,8,0,16);L3H=x6F["0" << 0] + x6F[e0u];x6F.unshift(L3H);}while(H2o);x0y.textAlign=S4i;this.stx.plotLine(R_$,N$e,B26,q5P,i2Z,S$N,x0y,Q_V,s_x);if(this.highlighted){X8e=this.highlighted == "p0"?!"":!"1";V_X=this.highlighted == "p1"?!!1:![];this.littleCircle(x0y,R_$,B26,X8e);this.littleCircle(x0y,N$e,q5P,V_X);}else {n$T=this.stx.valueFromPixel(Q_V.height / ("2" << 32),Q_V);this.setPoint(0,this.p0[0],n$T,Q_V.chart);q2h.j7J(29);this.setPoint(q2h.a$j(0,"1"),this.p1[0],n$T,Q_V.chart);}};m3.Drawing.fibtimezone.prototype.intersected=function(J3g,w8x,z0b){var w7d,A1l,l6n,U8V,u$n,k8S,z9Z;w7d=this.p0;A1l=this.p1;l6n=this.stx.panels[this.panelName];if(!w7d || !A1l || !l6n){return null;}U8V={0:w7d,1:A1l};for(var U2m in U8V){if(this.pointIntersection(U8V[U2m][0],U8V[U2m][1],z0b)){u$n="d";u$n+="r";u$n+="a";u$n+="g";q2h.N_M(1);this.highlighted=q2h.a$j("p",U2m);return {action:u$n,point:(+"6390" != 2008?"p":"X") + U2m};}}k8S=this.lineIntersection(J3g,w8x,z0b,"segment");if(k8S || z0b.x0 <= this.p0[0] && z0b.x1 >= w7d[0]){z9Z="m";z9Z+="o";z9Z+="v";z9Z+="e";this.highlighted=!0;return {action:z9Z,p0:m3.clone(w7d),p1:m3.clone(A1l),tick:J3g,value:w8x};}return null;};m3.Drawing.arrow_v0=function(){var B1y;B1y="a";B1y+="r";B1y+="r";B1y+="ow";this.name=B1y;this.dimension=[+"11",11];q2h.j7J(29);this.points=[["M",3,0,90.45 >= (5090,7529)?"i":224 < (+"7492",2110)?"L":!"",7,0,"L",7,+"5","L",10,5,"L",5,10,6040 == (573.42,8750)?0x2367:"234.79" * 1 <= ("790" << 64,8491)?"L":693.81 != 486?(!!({}),"T"):0x1e41,0,5,(8160,+"3945") !== (57,2710)?"L":(297.84,921.17) <= (5971,112.16)?(894.90,0xeb3):!!"1",q2h.a$j(32,"3"),5,(4030,5300) < 570.64?(252.65,"1904" * 1) < 369.01?"F":("l",+"373.54"):"L",3,0]];};m3.inheritsFrom(m3.Drawing.arrow_v0,m3.Drawing.shape);m3.Drawing.xcross=function(){this.name="xcross";this.dimension=[7,7];q2h.N_M(5);this.points=[["M",1,0,"L",3,2,5000 <= "6644" - 0?"L":50.55 > 8841?(!!0,!![]):"S",5,0,"L",q2h.c0C(1,"6"),1,5160 != (3402,2299)?"L":(8.11e+3,"5.05e+3" * 1),4,q2h.a$j(1,"3"),(+"185.8",+"627") != (6665,736.28)?(5520,265.5) > 1690?(373.78,4430) >= "4423" << 32?!({}):9.58e+3:"L":804.93,6,5,6096 == 646.22?(8.61e+3,6.45e+3):3371 === (3650,181.66)?9868 != 6701?!({}):(0x9e5,+"731.37"):"L",5,6,2440 === 4023?9.67e+3:+"903" == 1520?"D":(+"865.94",701.82) === (4263,+"863.8")?(6.63e+3,!!1):"L",3,4,877.71 <= 830.03?("675.1" - 0,1360) >= 2380?(2.85e+3,"S"):("B",+"1.85e+3"):"L",1,6,+"843.2" < (5831,9860)?"L":(730.37,+"1.71e+3"),0,5,"L",2,3,("356.67" * 1,75.42) == (934,4040)?(+"122.15",4.57e+3):8692 < (848,7169)?!({}):(521.16,+"6750") != (269,+"3110")?"L":(!!({}),+"0x1a33"),0,1,(4200,1040) == (+"4971",678.11)?("X","X"):119 === 121.11?2.88e+3:"L",1,0]];;};m3.inheritsFrom(m3.Drawing.xcross,m3.Drawing.shape);m3.Drawing.check=function(){this.name="check";this.dimension=[8,9];q2h.j7J(31);this.points=[["M",1,+"5",(3360,5094) >= (130.08,370.57)?"L":"M",0,6,"L",+"2",q2h.a$j("8",32),("9250" << 64,109.52) === 1850?0x726:"L",+"7",1,998 <= 8790?"L":(601.47,3590) <= (2090,1270)?9.47e+2:54.16,6,0,(1247,+"688.01") != (+"159.55",8990)?(9746,9630) < 9680?"L":734.21 == (8319,9690)?965.42:("0x14ce" * 1,634.81):(![],5.66e+3),2,6,"L",1,+"5"]];;};m3.inheritsFrom(m3.Drawing.check,m3.Drawing.shape);m3.Drawing.star=function(){q2h.f3X();var n12;n12="s";n12+="ta";n12+="r";this.name=n12;this.dimension=[12,12];q2h.j7J(5);this.points=[["M",0,4,(467.67,218.09) != (7092,3405)?(+"9777","6910" << 0) <= (7359,529.38)?("z","f"):"L":(0xb32,7.20e+3),q2h.a$j(1,"4"),4,+"5990" === 9019?7620 <= ("318" | 24,1974)?(!"1",8.45e+3):(9865,7440) === 1826?!![]:(812.22,239):"L",5.5,0,("510.64" * 1,9981) !== ("3486" >> 64,+"590.51")?"L":("N",5.86e+3),7,4,(465,869.58) == (79.75,9330)?+"271" < (725.51,6858)?(356.27,87.87):0xf1f:"L",11,4,(6060,4330) <= (+"721.7",8789)?310.41 == (734.03,"390.08" * 1)?(!1,!({})):"L":("x",![]),8,7,"L",q2h.a$j("9",64,q2h.j7J(31)),11,(9850,"4980" * 1) >= 853?"L":(0xa73,6.74e+3),5.5,9,"L",2,11,6430 != 1220?"L":5780 >= 7071?"9.03e+3" >> 32:0x1cf9,3,7,(8410,361) > 795?(930.03,2.83e+2):(700,1281) <= (1740,+"159.95")?4161 >= 7861?(!({}),+"0xc18"):(8.94e+3,+"774.04"):"L",0,4]];;};m3.inheritsFrom(m3.Drawing.star,m3.Drawing.shape);m3.Drawing.heart=function(){this.name="heart";this.dimension=[23,20];q2h.f3X();q2h.N_M(4);this.points=[["M",11,3,(1390,1793) > 3505?+"253.15":"B",11,2.4,10,0,6,0,(1480,2451) <= 6823?(101.3,6485) == 8885?2890 > 568.99?+"3.77e+2":(0x7fc,0x1d19):"B":"l",+"0",q2h.c0C("0",0),0,7.5,+"0",7.5,(+"1079",2870) <= (5170,+"886.98")?(974.37,!""):"B",0,q2h.a$j(0,"11",q2h.N_M(29)),+"4",q2h.c0C("15.4",0,q2h.j7J(14)),11,19,"B",+"18",15.4,22,11,+"22",7.5,"B",q2h.c0C("22",32,q2h.j7J(31)),7.5,22,0,q2h.a$j("16",0,q2h.j7J(14)),0,"B",13,0,11,q2h.a$j(1,"2.4",q2h.N_M(5)),11,3]];;};m3.inheritsFrom(m3.Drawing.heart,m3.Drawing.shape);m3.Drawing.focusarrow=function(){var e9V;e9V="f";e9V+="ocus";e9V+="a";e9V+="rrow";this.name=e9V;this.dimension=[7,5];q2h.j7J(5);this.points=[[(+"133",841) !== (+"2763","688" ^ 0)?+"5356" > (648,9186)?3597 == (762,3180)?9.78e+3:(5.81e+3,8.23e+3):"M":496.62,0,q2h.a$j(1,"0"),+"6000" > 910?(6712,1711) > (219.81,+"294.71")?7761 > 952?"L":(!0,1.64e+3):9.39e+3:(433.05,194.92),2,+"2",942.46 == (1710,3813)?("309" ^ 0,"312.82" * 1) != (166.42,7972)?494 >= (7556,8869)?(4.91e+3,0x56d):("o",!1):"h":"L",0,4,"2205" * 1 == (175.98,+"3891")?7744 !== ("90.28" * 1,+"6110")?15.63:0xd7f:"L",0,0],[777 >= "704.75" - 0?"M":(0x1e10,3.78e+2),q2h.a$j("6",64,q2h.N_M(31)),q2h.c0C("0",64,q2h.N_M(31)),"L",4,+"2","L",6,4,(4070,5377) <= 6330?"L":"r",6,q2h.c0C("0",0,q2h.j7J(14))]];;};m3.inheritsFrom(m3.Drawing.focusarrow,m3.Drawing.shape);m3.Drawing.crossline=function(){this.name="crossline";};m3.inheritsFrom(m3.Drawing.crossline,m3.Drawing.horizontal);m3.extend(m3.Drawing.crossline.prototype,{measure:function(){},accidentalClick:function(g2m,m0d){q2h.T$X();return !!0;},adjust:function(){var i$S;i$S=this.stx.panels[this.panelName];if(!i$S){return;}q2h.f3X();this.setPoint(0,this.d0,this.v0,i$S.chart);this.p1=m3.clone(this.p0);},intersected:function(Y8f,R8j,U1_){var A2e,e$X,C8Z;A2e="l";A2e+="in";A2e+="e";if(!this.p0 || !this.p1){return null;}this.p1[+"0"]+=1;e$X=this.lineIntersection(Y8f,R8j,U1_,A2e);this.p1=m3.clone(this.p0);if(!e$X){C8Z="lin";C8Z+="e";q2h.j7J(31);this.p1[1]+=q2h.a$j("1",64);e$X=this.lineIntersection(Y8f,R8j,U1_,C8Z);this.p1=m3.clone(this.p0);if(!e$X){return null;}}this.highlighted=!![];q2h.f3X();if(this.pointIntersection(this.p0[+"0"],this.p0[1],U1_)){this.highlighted="p0";}return {action:"move",p0:m3.clone(this.p0),p1:m3.clone(this.p1),tick:Y8f,value:R8j};},render:function(G70){var K8f,j0q,K6v,x1T,Z1I,I72,O8d,H4f,p2q,F7W,X9A,B8U;K8f=this.stx.panels[this.panelName];if(!K8f){return;}j0q=this.stx.pixelFromTick(this.p0["0" | 0],K8f.chart);K6v=this.stx.pixelFromValueAdjusted(K8f,this.p0[0],this.p0[1]);x1T=this.getLineColor();Z1I={pattern:this.pattern,lineWidth:this.lineWidth};q2h.N_M(1);this.stx.plotLine(j0q,q2h.a$j(j0q,100),K6v,K6v,x1T,"horizontal",G70,K8f,Z1I);q2h.j7J(1);this.stx.plotLine(j0q,j0q,K6v,q2h.c0C(K6v,100),x1T,"vertical",G70,K8f,Z1I);if(this.axisLabel && !this.repositioner){this.stx.endClip();I72=this.p0[1];if(K8f.chart.transformFunc){I72=K8f.chart.transformFunc(this.stx,K8f.chart,I72);}if(K8f.yAxis.priceFormatter){I72=K8f.yAxis.priceFormatter(this.stx,K8f,I72);}else {I72=this.stx.formatYAxisPrice(I72,K8f);}this.stx.createYAxisLabel(K8f,I72,K6v,x1T);this.stx.startClip(K8f.name);if(this.p0[0] >= 0 && !this.stx.chart.xAxis.noDraw){O8d=this.stx.dateFromTick(this.p0[0],K8f.chart,!!1);if(!m3.ChartEngine.isDailyInterval(this.stx.layout.interval)){q2h.j7J(69);var u72=q2h.a$j(882,59,2);p2q=O8d.getSeconds() * u72 + O8d.getMilliseconds();if(L$.Date && this.stx.displayZone){H4f=new L$.Date(O8d.getTime(),this.stx.displayZone);O8d=new Date(H4f.getFullYear(),H4f.getMonth(),H4f.getDate(),H4f.getHours(),H4f.getMinutes());O8d=new Date(O8d.getTime() + p2q);}}else {O8d.setHours(0,0,0,0);}F7W=m3.mmddhhmm(m3.yyyymmddhhmm(O8d));if(K8f.chart.xAxis.formatter){F7W=K8f.chart.xAxis.formatter(O8d,this.name,null,null,F7W);}else if(this.stx.internationalizer){if(O8d.getHours() !== 0 || O8d.getMinutes() !== 0){X9A=this.stx.internationalizer.monthDay.format(O8d);X9A+=" " + this.stx.internationalizer.hourMinute.format(O8d);}else {X9A=this.stx.internationalizer.yearMonthDay.format(O8d);}F7W=X9A;}this.stx.endClip();this.stx.createXAxisLabel({panel:K8f,txt:F7W,x:j0q,backgroundColor:x1T,color:null,pointed:!![],padding:2});this.stx.startClip(K8f.name);}}if(this.highlighted){B8U=this.highlighted == "p0"?!!({}):![];this.littleCircle(G70,j0q,K6v,B8U);}}},!![]);m3.Drawing.speedarc=function(){this.name="speedarc";this.printLevels=!!({});};m3.inheritsFrom(m3.Drawing.speedarc,m3.Drawing.segment);m3.extend(m3.Drawing.speedarc.prototype,{defaultOpacity:0.25,configs:[f8u,P7B,"lineWidth","pattern"],copyConfig:function(){this.color=this.stx.currentVectorParameters.currentColor;this.fillColor=this.stx.currentVectorParameters.fillColor;this.lineWidth=this.stx.currentVectorParameters.lineWidth;this.pattern=this.stx.currentVectorParameters.pattern;},intersected:function(p_7,E27,R_l){var t$b,o1x,C9N,g6f,n9c,r_L,M7e;if(!this.p0 || !this.p1){return null;}t$b={0:this.p0,1:this.p1};for(var j95 in t$b){if(this.pointIntersection(t$b[j95][0],t$b[j95][+"1"],R_l)){o1x="dr";o1x+="a";o1x+="g";q2h.N_M(1);this.highlighted=q2h.a$j("p",j95);return {action:o1x,point:"p" + j95};}}C9N=this.lineIntersection(p_7,E27,R_l,this.name);if(C9N){this.highlighted=!!1;return {action:"move",p0:m3.clone(this.p0),p1:m3.clone(this.p1),tick:p_7,value:E27};}g6f=this.p1[0] - (this.p0[0] - this.p1[0]);n9c=this.p0[0];r_L=this.p1[1];M7e=this.p0[1];if(p_7 > Math.max(g6f,n9c) || p_7 < Math.min(g6f,n9c)){return null;}if(E27 > Math.max(M7e,r_L) || E27 < Math.min(M7e,r_L)){return null;}this.highlighted=!![];return {action:"move",p0:m3.clone(this.p0),p1:m3.clone(this.p1),tick:p_7,value:E27};},render:function(M2J){var C3A,R1j,V5X,Z4X,Q4n,F5O,y6d,O7j,b7f,R_e,t4X,i2v,h$R,I7D,y8g,r0L,R23;C3A="stx_";C3A+="ya";C3A+="xi";C3A+="s";R1j=this.stx.panels[this.panelName];if(!R1j){return;}if(!this.p1){return;}V5X=this.stx.pixelFromTick(this.p0[0],R1j.chart);Z4X=this.stx.pixelFromTick(this.p1[0],R1j.chart);Q4n=this.stx.pixelFromValueAdjusted(R1j,this.p0[0],this.p0["1" | 0]);F5O=this.stx.pixelFromValueAdjusted(R1j,this.p1[0],this.p1[1]);q2h.N_M(59);y6d=q2h.c0C(F5O,Q4n);q2h.j7J(60);O7j=Math.abs(q2h.a$j(Z4X,V5X,Q4n,F5O));b7f=this.getLineColor();M2J.strokeStyle=b7f;R_e=this.fillColor;if(R_e == "auto" || m3.isTransparent(R_e)){R_e=this.stx.defaultColor;}M2J.fillStyle=R_e;if(M2J.setLineDash){M2J.setLineDash(m3.borderPatternToArray(this.lineWidth,this.pattern));M2J.lineDashOffset=0;;}q2h.f3X();this.stx.canvasFont(C3A,M2J);for(var N2f=1;N2f < "3" * 1;N2f++){q2h.j7J(9);var f7E=q2h.a$j(379,20,19);q2h.j7J(70);var I9p=q2h.a$j(6,15,4,10,12);t4X=Math.abs(this.p1["1" ^ 0] - this.p0[f7E]) * Math.sqrt(+"2") * N2f / I9p;q2h.j7J(14);var k25=q2h.c0C(15,14);q2h.j7J(14);var a20=q2h.a$j(17,18);q2h.j7J(0);var d3u=q2h.c0C(93,10,8,13);q2h.j7J(71);var h5Y=q2h.a$j(16,1281,4,0,20);q2h.j7J(72);var R$X=q2h.a$j(5,211,4,10,3);i2v=this.p1[k25] + t4X * (y6d?a20:d3u) * (R1j.yAxis.flipped?-("1" * h5Y):R$X);h$R=this.stx.pixelFromValueAdjusted(R1j,this.p0[0],i2v);M2J.save();M2J.beginPath();q2h.N_M(7);M2J.scale(q2h.c0C(1,O7j),1);q2h.j7J(5);M2J.arc(q2h.a$j(O7j,Z4X),F5O,Math.abs(h$R - F5O),0,Math.PI,!y6d);M2J.globalAlpha=this.highlighted?1:this.defaultOpacity;if(this.pattern != "none"){M2J.stroke();}M2J.globalAlpha=0.1;M2J.fill();M2J.restore();M2J.globalAlpha=1;if(this.printLevels){M2J.fillStyle=b7f;M2J.textAlign="center";q2h.N_M(1);I7D=q2h.a$j(N2f,"/3");M2J.fillText(I7D,Z4X,Math.round(h$R - 5));M2J.fillStyle=R_e;}}M2J.textAlign="left";y8g={pattern:this.pattern,lineWidth:this.lineWidth,opacity:this.highlighted?1:this.defaultOpacity};this.stx.plotLine(V5X,Z4X,Q4n,F5O,b7f,"segment",M2J,R1j,y8g);if(M2J.setLineDash){M2J.setLineDash([]);}if(this.highlighted){r0L=this.highlighted == "p0"?!!1:![];R23=this.highlighted == "p1"?!!1:![];this.littleCircle(M2J,V5X,Q4n,r0L);this.littleCircle(M2J,Z4X,F5O,R23);}},reconstruct:function(g8z,m43){this.stx=g8z;this.color=m43.col;this.fillColor=m43.fc;this.panelName=m43.pnl;q2h.f3X();this.pattern=m43.ptrn;this.lineWidth=m43.lw;this.d0=m43.d0;this.d1=m43.d1;this.tzo0=m43.tzo0;this.tzo1=m43.tzo1;this.v0=m43.v0;this.v1=m43.v1;this.adjust();},serialize:function(){q2h.f3X();return {name:this.name,pnl:this.panelName,col:this.color,fc:this.fillColor,ptrn:this.pattern,lw:this.lineWidth,d0:this.d0,d1:this.d1,tzo0:this.tzo0,tzo1:this.tzo1,v0:this.v0,v1:this.v1};}},!"");m3.Drawing.speedline=function(){q2h.f3X();this.name="speedline";this.printLevels=!![];};m3.inheritsFrom(m3.Drawing.speedline,m3.Drawing.speedarc);m3.extend(m3.Drawing.speedline.prototype,{intersected:function(y4L,B_w,G1y){var A_w,M1G,V82,Q4W;A_w=this.p0;M1G=this.p1;if(!A_w || !M1G){return null;}V82={0:A_w,1:M1G};for(var P$F in V82){if(this.pointIntersection(V82[P$F][0],V82[P$F][1],G1y)){q2h.N_M(1);this.highlighted=q2h.c0C(513.1 == 8900?2.79e+3:1550 > (8150,+"466.87")?"p":(686.97,988.20),P$F);return {action:"drag",point:"p" + P$F};}}Q4W=this.rays;for(var u3Q=0;u3Q < Q4W.length;u3Q++){if(this.lineIntersection(y4L,B_w,G1y,"ray",Q4W[u3Q][0],Q4W[u3Q][1],!!({}))){this.highlighted=!!({});return {action:"move",p0:m3.clone(A_w),p1:m3.clone(M1G),tick:y4L,value:B_w};}}return null;},render:function(T4a){var c67,K0T,p9b,M49,T$V,C96,T26,Y3l,w7L,h2S,X9n,t48,R8R,C3T,T$o,c_W,D$W,D55,Z39,S6t,n8L,H9N,r4l,z5E,o3x,z4W,E7E;c67="3";c67+="/";c67+="2";K0T="au";K0T+="to";p9b=this.stx.panels[this.panelName];if(!p9b){return;}if(!this.p1){return;}M49=this.stx.pixelFromTick(this.p0[0],p9b.chart);T$V=this.stx.pixelFromTick(this.p1[0],p9b.chart);C96=this.stx.pixelFromValueAdjusted(p9b,this.p0[0],this.p0["1" * 1]);T26=this.stx.pixelFromValueAdjusted(p9b,this.p1[0],this.p1[1]);this.stx.canvasFont("stx_yaxis",T4a);Y3l=this.getLineColor();w7L=this.color;if(w7L == "auto" || m3.isTransparent(w7L)){w7L=this.stx.defaultColor;}T4a.strokeStyle=w7L;h2S=this.fillColor;if(h2S == K0T || m3.isTransparent(h2S)){h2S=this.stx.defaultColor;}T4a.fillStyle=h2S;X9n={pattern:this.pattern,lineWidth:this.lineWidth,opacity:this.highlighted?1:this.defaultOpacity};C3T=[692 > 4550?(!"1",!1):"1","2/3","1/3",c67,"3"];q2h.N_M(7);T$o=[1,q2h.c0C(2,3),q2h.c0C(1,3),q2h.c0C(3,2),3];c_W=[];this.rays=[];for(var k7d=0;k7d < T$o.length;k7d++){D$W="se";D$W+="gment";D55=T$o[k7d];if(D55 > 1 && !this.extension)continue;Z39=this.stx.pixelFromValueAdjusted(p9b,this.p0["0" - 0],this.p0[1] - (this.p0[1] - this.p1[1]) * D55);if(D55 > +"1"){S6t=m3.xIntersection({x0:M49,x1:T$V,y0:C96,y1:Z39},T26);c_W.push(S6t);}else {S6t=m3.xIntersection({x0:T$V,x1:T$V,y0:C96,y1:T26},Z39);c_W.push(Z39);}n8L=D55 > 1?S6t:T$V;H9N=D55 > 1?T26:Z39;if(!this.confineToGrid){n8L=p9b.left;if(T$V > M49){n8L+=p9b.width;}q2h.j7J(67);H9N=q2h.c0C(M49,M49,T$V,n8L,C96,C96,Z39);}if(this.printLevels){if(D55 != 1 || this.extension){T4a.fillStyle=w7L;q2h.j7J(29);r4l=q2h.a$j(0,"0");q2h.j7J(4);z5E=q2h.c0C("0",0);if(C96 > T26){z5E=-5;T4a.textBaseline="bottom";}else {z5E=5;T4a.textBaseline="top";}if(M49 > T$V){r4l=5;T4a.textAlign="right";}else {r4l=-5;T4a.textAlign="left";}if(D55 > "1" * 1){T4a.fillText(C3T[k7d],S6t + (this.confineToGrid?0:r4l),T26);}else {T4a.fillText(C3T[k7d],T$V,Z39 + (this.confineToGrid?0:z5E));}T4a.fillStyle=h2S;}}this.stx.plotLine(M49,n8L,C96,H9N,this.highlighted?Y3l:w7L,D$W,T4a,p9b,X9n);if(D55 == "1" * 1){t48=n8L;R8R=H9N;}this.rays.push([[M49,C96],[n8L,H9N]]);q2h.j7J(5);T4a.globalAlpha=q2h.c0C(1,"0.1");T4a.beginPath();T4a.moveTo(n8L,H9N);T4a.lineTo(M49,C96);T4a.lineTo(t48,R8R);T4a.fill();T4a.globalAlpha=1;}T4a.textAlign="left";T4a.textBaseline="middle";if(this.confineToGrid){T4a.globalAlpha=+"0.3";T4a.beginPath();q2h.j7J(14);T4a.strokeRect(M49,C96,q2h.c0C(T$V,M49),q2h.a$j(T26,C96));T4a.moveTo(M49,c_W[1]);T4a.lineTo(T$V,c_W[1]);T4a.moveTo(M49,c_W[2]);T4a.lineTo(T$V,c_W[2]);if(this.extension){T4a.moveTo(c_W[3],C96);T4a.lineTo(c_W[3],T26);T4a.moveTo(c_W[4],C96);T4a.lineTo(c_W[4],T26);}T4a.stroke();T4a.globalAlpha=+"1";}if(this.highlighted){o3x="p";o3x+="1";z4W=this.highlighted == "p0"?!!"1":![];E7E=this.highlighted == o3x?!![]:!({});this.littleCircle(T4a,M49,C96,z4W);this.littleCircle(T4a,T$V,T26,E7E);}}},!!({}));m3.Drawing.gannfan=function(){this.name="gannfan";q2h.f3X();this.printLevels=!"";};m3.inheritsFrom(m3.Drawing.gannfan,m3.Drawing.speedline);m3.extend(m3.Drawing.gannfan.prototype,{render:function(b2v){var R8_,h28,O1C,z5R,a3T,a31,u1Q,t52,l8O,M8r,W_P,f18,G0J,q3g,J39,W_I,E68,Q7D,M6E,k2o,E3k,V2L,A4J,h5Q,O_7;R8_="m";R8_+="i";R8_+="ddle";h28="a";h28+="uto";O1C="s";O1C+="tx";O1C+="_";O1C+="yaxis";z5R=this.stx.panels[this.panelName];if(!z5R){return;}if(!this.p1){return;}a3T=this.stx.pixelFromTick(this.p0[+"0"],z5R.chart);a31=this.stx.pixelFromTick(this.p1[0],z5R.chart);u1Q=this.stx.pixelFromValueAdjusted(z5R,this.p0[0],this.p0[1]);t52=this.stx.pixelFromValueAdjusted(z5R,this.p1[0],this.p1[1]);this.stx.canvasFont(O1C,b2v);l8O=this.getLineColor();q2h.T$X();M8r=this.color;if(M8r == h28 || m3.isTransparent(M8r)){M8r=this.stx.defaultColor;}b2v.strokeStyle=M8r;W_P=this.fillColor;if(W_P == "auto" || m3.isTransparent(W_P)){W_P=this.stx.defaultColor;}b2v.fillStyle=W_P;f18={pattern:this.pattern,lineWidth:this.lineWidth,opacity:this.highlighted?"1" * 1:this.defaultOpacity};q2h.N_M(7);J39=[+"1",2,3,4,8,q2h.a$j(1,2),q2h.c0C("1","3",32,1,q2h.j7J(73)),q2h.c0C(1,4,q2h.N_M(7)),q2h.c0C("1",8,q2h.N_M(74))];this.rays=[];for(var r0R=0;r0R < J39.length;r0R++){W_I=J39[r0R];q2h.N_M(75);E68=q2h.c0C(a3T,a31,W_I,a3T);q2h.j7J(76);Q7D=q2h.c0C(u1Q,u1Q,t52,W_I);M6E=z5R.left;if(a31 > a3T){M6E+=z5R.width;}q2h.N_M(67);k2o=q2h.c0C(a3T,a3T,a31,M6E,u1Q,u1Q,Q7D);if(this.printLevels){b2v.fillStyle=M8r;E3k=0;q2h.N_M(46);V2L=q2h.c0C("0",0);if(u1Q > t52){q2h.N_M(14);V2L=q2h.a$j("5",0);b2v.textBaseline="top";}else {V2L=-5;b2v.textBaseline="bottom";}if(a3T > a31){q2h.j7J(14);E3k=q2h.c0C("5",0);b2v.textAlign="left";}else {A4J="ri";A4J+="ght";E3k=-5;b2v.textAlign=A4J;}if(W_I > 1){q2h.j7J(1);b2v.fillText(q2h.c0C(W_I,"x1"),q2h.c0C(E68,E3k),t52);}else {q2h.j7J(75);b2v.fillText(q2h.c0C(0,"1",W_I,"1x"),a31,q2h.a$j(Q7D,V2L,q2h.N_M(1)));}b2v.fillStyle=W_P;}this.stx.plotLine(a3T,M6E,u1Q,k2o,this.highlighted?l8O:M8r,"segment",b2v,z5R,f18);this.rays.push([[a3T,u1Q],[M6E,k2o]]);if(W_I == 1){G0J=M6E;q3g=k2o;}b2v.globalAlpha=0.1;b2v.beginPath();b2v.moveTo(M6E,k2o);b2v.lineTo(a3T,u1Q);b2v.lineTo(G0J,q3g);b2v.fill();b2v.globalAlpha=+"1";}b2v.textAlign="left";b2v.textBaseline=R8_;if(this.highlighted){h5Q=this.highlighted == "p0"?!!1:!!0;O_7=this.highlighted == "p1"?!![]:!"1";this.littleCircle(b2v,a3T,u1Q,h5Q);this.littleCircle(b2v,a31,t52,O_7);}}},!!({}));m3.Drawing.timecycle=function(){var q_n;q_n="timec";q_n+="ycle";this.name=q_n;this.printLevels=!![];};m3.inheritsFrom(m3.Drawing.timecycle,m3.Drawing.speedarc);m3.extend(m3.Drawing.timecycle.prototype,{intersected:function(S6o,R3Z,Q$s){var i5F,L75,I6o,b1N,H0c,S9W;i5F="se";i5F+="g";i5F+="me";i5F+="nt";L75=this.p0;I6o=this.p1;b1N=this.stx.panels[this.panelName];if(!L75 || !I6o || !b1N){return null;}H0c={0:L75,1:I6o};for(var a5Q in H0c){if(this.pointIntersection(H0c[a5Q][0],H0c[a5Q][+"1"],Q$s)){q2h.N_M(1);this.highlighted=q2h.c0C("p",a5Q);return {action:"drag",point:(5226 == 3262?6757 >= 5373?(4.64e+3,342.17):"0x2532" ^ 0:"p") + a5Q};}}S9W=this.lineIntersection(S6o,R3Z,Q$s,i5F);if(S9W || Q$s.x0 <= this.p0["0" >> 0] && Q$s.x1 >= L75[0]){this.highlighted=!"";return {action:"move",p0:m3.clone(L75),p1:m3.clone(I6o),tick:S6o,value:R3Z};}return null;},render:function(y2W){var G6_,N3m,n_p,b$2,N8q,e$Y,q$b,C_f,D1y,P8f,p7F,Q5Q,i6j,X0u,K2l,r5K,p3y,v2D,r7s,U6r,O$1,W3D,F77,q27;G6_="a";G6_+="u";G6_+="t";G6_+="o";N3m="c";N3m+="e";N3m+="nt";N3m+="er";n_p="m";n_p+="i";n_p+="ddl";n_p+="e";b$2=this.stx.panels[this.panelName];if(!b$2){return;}if(!this.p1){return;}N8q=this.stx.pixelFromTick(this.p0[+"0"],b$2.chart);e$Y=this.stx.pixelFromTick(this.p1[+"0"],b$2.chart);q$b=this.stx.pixelFromValueAdjusted(b$2,this.p0[+"0"],this.p0[1]);C_f=this.stx.pixelFromValueAdjusted(b$2,this.p1["0" >> 32],this.p1["1" ^ 0]);D1y=0;P8f=this.getLineColor();y2W.textBaseline=n_p;this.stx.canvasFont("stx_yaxis",y2W);q2h.j7J(46);p7F=q2h.c0C("20",0);Q5Q=this.p1[0] - this.p0[0];y2W.textAlign=N3m;i6j=N8q;X0u=b$2.yAxis.top;K2l=b$2.yAxis.bottom;r5K=this.color;if(r5K == G6_ || m3.isTransparent(r5K)){r5K=this.stx.defaultColor;}p3y=this.fillColor;if(p3y == "auto" || m3.isTransparent(p3y)){p3y=this.stx.defaultColor;}if(this.printLevels){q2h.j7J(14);K2l-=q2h.c0C(p7F,7);}v2D={pattern:this.pattern,lineWidth:this.lineWidth,opacity:this.highlighted?"1" | 0:this.defaultOpacity};r7s=[];y2W.save();y2W.fillStyle=p3y;y2W.globalAlpha=0.05;do {i6j=this.stx.pixelFromTick(this.p0[+"0"] + D1y * Q5Q,b$2.chart);D1y++;if(N8q < e$Y && i6j > b$2.left + b$2.width)break;else if(N8q > e$Y && i6j < b$2.left)break;else if(i6j < b$2.left || i6j > b$2.left + b$2.width)continue;y2W.beginPath();y2W.moveTo(N8q,X0u);y2W.lineTo(i6j,X0u);y2W.lineTo(i6j,K2l);y2W.lineTo(N8q,K2l);y2W.fill();r7s.push({c:D1y,x:i6j});}while(Q5Q);y2W.globalAlpha=1;U6r=0;for(var f$p=0;f$p < r7s.length;f$p++){this.stx.plotLine(r7s[f$p].x,r7s[f$p].x,0,K2l,this.highlighted?P8f:r5K,"segment",y2W,b$2,v2D);if(this.printLevels){y2W.fillStyle=r5K;q2h.j7J(14);var Y8_=q2h.a$j(41,9);O$1=this.stx.chart.context.measureText(r7s[f$p].c).width + ("3" << Y8_);if(O$1 < this.stx.layout.candleWidth + U6r){y2W.fillText(r7s[f$p].c,r7s[f$p].x,K2l + +"7");U6r=0;}else {U6r+=this.stx.layout.candleWidth;}}}y2W.restore();y2W.textAlign="left";this.stx.plotLine(N8q,e$Y,q$b,C_f,P8f,"segment",y2W,b$2,v2D);if(this.highlighted){W3D=this.highlighted == "p0"?!![]:!"1";F77=this.highlighted == "p1"?!![]:!({});this.littleCircle(y2W,N8q,q$b,W3D);this.littleCircle(y2W,e$Y,C_f,F77);}else {q27=this.stx.valueFromPixel(b$2.height / 2,b$2);this.setPoint(0,this.p0[+"0"],q27,b$2.chart);this.setPoint(1,this.p1[0],q27,b$2.chart);}}},!!1);m3.Drawing.regression=function(){q2h.f3X();this.name="regression";};m3.inheritsFrom(m3.Drawing.regression,m3.Drawing.segment);m3.extend(m3.Drawing.regression.prototype,{configs:["color","lineWidth","pattern","active1","color1","lineWidth1","pattern1","active2",S6C,"lineWidth2","pattern2","active3","color3","lineWidth3","pattern3"],copyConfig:function(c$1){var I$T,K2N,h$j;I$T="a";I$T+="u";I$T+="to";K2N="a";K2N+="u";K2N+="t";K2N+="o";m3.Drawing.copyConfig(this,c$1);h$j=this.stx.currentVectorParameters;this.active1=!!h$j.active1;this.active2=!!h$j.active2;this.active3=!!h$j.active3;this.color1=h$j.color1 || K2N;this.color2=h$j.color2 || I$T;this.color3=h$j.color3 || "auto";this.lineWidth1=h$j.lineWidth1;this.lineWidth2=h$j.lineWidth2;this.lineWidth3=h$j.lineWidth3;this.pattern1=h$j.pattern1;this.pattern2=h$j.pattern2;this.pattern3=h$j.pattern3;},$controls:[p2Q,P40,'cq-cvp-controller[cq-cvp-header="3"]'],click:function(e93,R40,B$4){var R37,D3V,G6r,s_j;if(R40 < 0){return;}this.copyConfig();R37=this.stx.panels[this.panelName];if(!this.penDown){this.setPoint(0,R40,B$4,R37.chart);this.penDown=!0;D3V=this.stx;this.field=D3V.highlightedDataSetField;if(!this.field && R37 != D3V.chart.panel){for(var a_T in D3V.chart.seriesRenderers){G6r=D3V.chart.seriesRenderers[a_T];if(G6r.params.panel == R37.name){this.field=G6r.seriesParams["0" << 32].field;break;}}for(var h5h in D3V.layout.studies){s_j=D3V.layout.studies[h5h];if(s_j.panel == R37.name){this.field=Object.keys(s_j.outputMap)[0];break;}}}return ![];}if(this.accidentalClick(R40,B$4)){return this.dragToDraw;}q2h.T$X();this.setPoint(1,R40,B$4,R37.chart);this.penDown=!!"";return !![];;},getYValue:function(T2o){var S96,I$V,k66,z1_,S1P,y7G,p9p,W3i;S96="Cl";S96+="ose";I$V=this.stx.chart.dataSet[T2o];k66=this.stx.chart.dataSet[T2o];if(!I$V){return null;}z1_=this.stx.panels[this.panelName];S1P=this.stx.getYAxisByField(z1_,this.field) || z1_.yAxis;if(this.stx.charts[z1_.name] && z1_.chart.transformFunc && S1P == z1_.yAxis){k66=I$V.transform;}if(!k66){return null;}y7G=null;p9p=null;W3i=this.stx.defaultPlotField || S96;if(this.field){p9p=m3.existsInObjectChain(k66,this.field);if(!p9p){return null;}y7G=p9p=p9p.obj[p9p.member];if(I$V != k66){y7G=m3.existsInObjectChain(I$V,this.field);y7G=y7G.obj[y7G.member];}if(typeof p9p == "object"){p9p=p9p[W3i];y7G=y7G[W3i];}}else {p9p=k66[W3i];y7G=I$V[W3i];}return {transformed:p9p,untransformed:y7G};},render:function(g6F){var K5a,S8_,P9B,z6S,U5v,l7i,P2Y,s$Y,X6v,j2z,u6Q,k0k,O0J,O5O,D8p,Y_L,L0B,m65,P7g,I_d,S59,j2T,r3J,H_3,o$6,T4_,L7W,y1G,q4S,a8d,o21,U83,W2U,s2x,Z2t,P4i;K5a="s";K5a+="e";K5a+="gm";K5a+="ent";S8_=this.stx.panels[this.panelName];if(!S8_){return;}if(!this.p1){return;}if(this.p0[0] < +"0" || this.p1[0] < 0){return;}P9B=this.stx.pixelFromTick(this.p0[0],S8_.chart);z6S=this.stx.pixelFromTick(this.p1["0" | 0],S8_.chart);if(P9B < S8_.left && z6S < S8_.left){return;}if(P9B > S8_.right && z6S > S8_.right){return;}U5v=this.stx.getYAxisByField(S8_,this.field);l7i=[];P2Y=[];q2h.N_M(4);s$Y=q2h.a$j("0",0);X6v=0;j2z=+"0";u6Q=0;k0k=Math.min(this.p1[0],this.p0[0]);q2h.j7J(14);var Q4z=q2h.c0C(20,19);O0J=Math.max(this.p1["0" - 0],this.p0[0]) + Q4z;q2h.N_M(14);O5O=q2h.c0C(O0J,k0k);for(var E$h=k0k;E$h < O0J;E$h++){D8p=this.getYValue(E$h);if(D8p){l7i.push(D8p.transformed);P2Y.push(D8p.untransformed);}}Y_L=l7i.length;q2h.j7J(77);L0B=q2h.a$j(Y_L,1,Y_L,1,"2");m65=Math.pow(L0B,2);q2h.N_M(78);P7g=q2h.a$j(L0B,1,3,"2",Y_L);for(E$h=0;E$h < Y_L;E$h++){j2z+=Y_L * l7i[E$h] - s$Y;s$Y+=l7i[E$h];u6Q+=Y_L * P2Y[E$h] - X6v;X6v+=P2Y[E$h];}q2h.N_M(79);I_d=q2h.a$j(m65,P7g,Y_L,j2z,Y_L,L0B,s$Y);q2h.N_M(80);S59=q2h.c0C(I_d,Y_L,s$Y,L0B);q2h.N_M(79);j2T=q2h.a$j(m65,P7g,Y_L,u6Q,Y_L,L0B,X6v);q2h.j7J(80);r3J=q2h.a$j(I_d,Y_L,X6v,L0B);if(this.p0[0] < this.p1[0]){H_3=S59;q2h.j7J(69);o$6=q2h.a$j(S59,I_d,O5O);this.p0[1]=r3J;q2h.N_M(69);this.p1[1]=q2h.c0C(r3J,j2T,O5O);}else {q2h.N_M(69);H_3=q2h.a$j(S59,I_d,O5O);o$6=S59;q2h.N_M(69);this.p0[1]=q2h.c0C(r3J,j2T,O5O);q2h.j7J(14);this.p1[q2h.c0C("1",0)]=r3J;}T4_=this.stx.pixelFromTransformedValue(H_3,S8_,U5v);L7W=this.stx.pixelFromTransformedValue(o$6,S8_,U5v);y1G=this.getLineColor();q4S={pattern:this.pattern,lineWidth:this.lineWidth};this.stx.plotLine(P9B,z6S,T4_,L7W,y1G,K5a,g6F,S8_,q4S);q2h.N_M(14);this.stx.plotLine(P9B,P9B,q2h.c0C(T4_,20),q2h.a$j(T4_,20,q2h.N_M(1)),y1G,"segment",g6F,S8_,q4S);q2h.j7J(14);this.stx.plotLine(z6S,z6S,q2h.a$j(L7W,20),q2h.a$j(L7W,0,"20",q2h.j7J(81)),y1G,"segment",g6F,S8_,q4S);if(this.active1 || this.active2 || this.active3){q2h.N_M(7);a8d=q2h.c0C(s$Y,Y_L);o21=0;for(E$h="0" ^ 0;E$h < Y_L;E$h++){o21+=Math.pow(l7i[E$h] - a8d,"2" - 0);}q2h.j7J(7);U83=Math.sqrt(q2h.a$j(o21,Y_L));W2U={context:g6F,panel:S8_,points:{0:{x:P9B,v:H_3},1:{x:z6S,v:o$6}},stddev:U83,yAxis:U5v};this.lines={};if(this.active1){this.renderStddev(4730 < (4830,2330)?(0xd63,0x1066):"1",(8630,944.46) !== 111.51?188.03 > (1300,"4070" >> 32)?0x8ba:"p":(0x8ef,867.16),W2U);this.renderStddev("1","n",W2U);}if(this.active2){this.renderStddev((8860,9930) === (+"3320",7540)?(3.27e+3,!"1"):"2",("4450" >> 32,5223) === (8600,7670)?(5820,6430) > 543.9?(462,9507) === (+"9730",985.19)?426.93:("V",0xe05):("l","1.46e+3" ^ 0):"p",W2U);this.renderStddev("2",5480 < (2210,39.24)?"P":(306,+"5228") !== 1970?"n":"4010" * 1 < +"3819"?("I","5.60e+3" * 1):"G",W2U);}if(this.active3){this.renderStddev((1620,9260) > 871.87?(731.79,2532) === (+"7220","695.88" * 1)?324.76:"3":0xa1c,"p",W2U);this.renderStddev((214.55,5270) !== (651,6043)?(7450,683.28) === +"7679"?"484.45" - 0 === (6846,930.24)?(809.46,8.21e+3):(!"1",8.31e+3):"3":(!({}),0x209d),4100 <= (33.96,878.56)?"336.48" - 0 !== (478,423.77)?(+"525.05",1638) <= 6410?("Z",!({})):(775.97,8.23e+3):(9.68e+3,6.04e+2):"n",W2U);}}if(!this.highlighted){this.pixelX=[P9B,z6S];this.pixelY=[T4_,L7W];}else {s2x="p";s2x+="1";Z2t=this.highlighted == "p0"?!!({}):!({});P4i=this.highlighted == s2x?!!({}):![];this.littleCircle(g6F,P9B,T4_,Z2t);this.littleCircle(g6F,z6S,L7W,P4i);}},renderStddev:function(p7Y,Q_8,j$0){var b1a,m7w,S9i,V17,K99,f7l,c3j,s1U,N$w,q1U,r3M,v_y,z4N,V3r,a0k,f1h,i_f,u1y,v1v,E9H,J37,G5K,e27;b1a="middl";b1a+="e";m7w="patte";m7w+="r";m7w+="n";S9i="s";S9i+="t";S9i+="dd";q2h.f3X();S9i+="ev";q2h.N_M(82);V17=q2h.a$j(Q_8,p7Y,S9i);q2h.j7J(1);K99=q2h.c0C("color",p7Y);q2h.j7J(1);f7l=q2h.c0C(m7w,p7Y);q2h.j7J(1);c3j=q2h.a$j("lineWidth",p7Y);s1U=j$0.points;N$w=s1U[0].v;q1U=s1U[1].v;r3M=j$0.stddev;v_y=Q_8 === (489.6 > (764,228.21)?"n":("0x9ba" * 1,!!1))?p7Y * -1:p7Y * +"1";z4N=this.stx;V3r=j$0.panel;a0k=j$0.yAxis;f1h={name:V17,color:this.getLineColor(this[K99]),type:"segment",y0:z4N.pixelFromTransformedValue(N$w + r3M * v_y,V3r,a0k),y1:z4N.pixelFromTransformedValue(q1U + r3M * v_y,V3r,a0k),params:{pattern:this[f7l],lineWidth:this[c3j]}};if(this.lines){this.lines[V17]=f1h;}i_f=j$0.context;u1y=s1U[+"0"].x;v1v=s1U[1].x;z4N.plotLine(u1y,v1v,f1h.y0,f1h.y1,f1h.color,f1h.type,i_f,V3r,f1h.params);z4N.plotLine(u1y,u1y,f1h.y0 - 10,f1h.y0 + 10,f1h.color,f1h.type,i_f,V3r,f1h.params);z4N.plotLine(v1v,v1v,f1h.y1 - +"10",f1h.y1 + 10,f1h.color,f1h.type,i_f,V3r,f1h.params);q2h.j7J(1);E9H=q2h.a$j(p7Y,"\u03c3");q2h.j7J(83);var N54=q2h.c0C(45,63,19,11,7);J37=Math.max(u1y,v1v) + N54;G5K=u1y < v1v?f1h.y1:f1h.y0;i_f.fillStyle=f1h.color;i_f.save();i_f.textBaseline=b1a;i_f.fillText(E9H,J37,G5K);i_f.restore();if(j$0.formatPrice && this.axisLabel && !this.highlighted && !this.penDown){if(u1y >= V3r.chart.left && u1y <= V3r.chart.right || v1v >= V3r.chart.left && v1v <= V3r.chart.right){q2h.j7J(25);e27=q2h.c0C(r3M,v_y,u1y < v1v?q1U:N$w);z4N.endClip();z4N.createYAxisLabel(V3r,j$0.formatPrice(e27,a0k),G5K,f1h.color,null,i_f,a0k);z4N.startClip(V3r.name);}}},intersected:function(q1l,p38,a9M){var N79,M5b,d3g,r_Y,l7_,T_Y,E4C;if(!this.pixelX || !this.pixelY){return null;}N79=this.repositionIntersection(q1l,p38);if(N79){return N79;}M5b={0:this.pixelX,1:this.pixelY};for(var A0a=0;A0a < 2;A0a++){if(this.pointIntersection(M5b[+"0"][A0a],M5b[1][A0a],a9M,!!"1")){q2h.j7J(1);this.highlighted=q2h.a$j("p",A0a);return {action:"drag",point:"p" + A0a};}}d3g=this;q2h.j7J(5);r_Y=this.pixelX[q2h.a$j(1,"0")];l7_=this.pixelX[1];T_Y=function(R5O){var A78,d9L;A78=[r_Y,R5O.y0];d9L=[l7_,R5O.y1];return d3g.lineIntersection(q1l,p38,a9M,d3g.name,A78,d9L,!![]);};E4C=T_Y({y0:this.pixelY[0],y1:this.pixelY[1]});if(!E4C && this.lines){for(var T4U in this.lines){if(T_Y(this.lines[T4U])){E4C=!!({});break;}}}if(E4C){this.highlighted=!!({});return {action:"move",p0:m3.clone(this.p0),p1:m3.clone(this.p1),tick:q1l,value:p38};}return null;},repositionIntersection:function(t5Z,O6D){if(!this.p0 || !this.p1){return !"1";}if(this == this.stx.repositioningDrawing && this.highlighted){if(this.highlighted === !!"1"){return {action:"move",p0:m3.clone(this.p0),p1:m3.clone(this.p1),tick:t5Z,value:O6D};}return {action:"drag",point:this.highlighted};}return ![];},lineIntersection:function(X3z,x59,o7C,x$5,y1l,r$3,P05){var B2u,v3a,m7q,H0Z,T0O,L0p;if(!P05){q2h.N_M(1);console.log(q2h.c0C(x$5," lineIntersection must accept p0 and p1 in pixels. Please verify and set isPixels=true."));B2u=+"1824200448";v3a=-1701133897;m7q=2;for(var f0w=1;q2h.S9Y(f0w.toString(),f0w.toString().length,+"32111") !== B2u;f0w++){return !"";}if(q2h.O1W(m7q.toString(),m7q.toString().length,"35467" * 1) !== v3a){return ![];}return !!0;}if(!y1l){y1l=this.p0;}if(!r$3){r$3=this.p1;}if(!(y1l && r$3)){return !({});}H0Z=this.stx;T0O=m3.convertBoxToPixels(H0Z,this.panelName,o7C);if(T0O.x0 === undefined){return !"1";}L0p={x0:y1l[0],x1:r$3[0],y0:y1l[1],y1:r$3[1]};q2h.f3X();return m3.boxIntersects(T0O.x0,T0O.y0,T0O.x1,T0O.y1,L0p.x0,L0p.y0,L0p.x1,L0p.y1);},boxIntersection:function(n9W,M2C,U3Y){if(U3Y.cx0 > Math.max(this.pixelX[0],this.pixelX[1]) || U3Y.cx1 < Math.min(this.pixelX["0" >> 64],this.pixelX[1])){return !"1";}if(!this.stx.repositioningDrawing && (U3Y.cy1 < this.pixelY[0] || U3Y.cy0 > this.pixelY[1])){return !({});}q2h.T$X();return !!1;},reconstruct:function(O8r,E4z){this.stx=O8r;this.color=E4z.col;this.color1=E4z.col1;this.color2=E4z.col2;this.color3=E4z.col3;this.active1=E4z.dev1;this.active2=E4z.dev2;this.active3=E4z.dev3;this.panelName=E4z.pnl;this.pattern=E4z.ptrn;this.pattern1=E4z.ptrn1;this.pattern2=E4z.ptrn2;this.pattern3=E4z.ptrn3;this.lineWidth=E4z.lw;this.lineWidth1=E4z.lw1;this.lineWidth2=E4z.lw2;this.lineWidth3=E4z.lw3;this.d0=E4z.d0;this.d1=E4z.d1;this.tzo0=E4z.tzo0;this.tzo1=E4z.tzo1;this.field=E4z.fld;this.adjust();},serialize:function(){return {name:this.name,pnl:this.panelName,dev1:this.active1,dev2:this.active2,dev3:this.active3,col:this.color,col1:this.color1,col2:this.color2,col3:this.color3,ptrn:this.pattern,ptrn1:this.pattern1,ptrn2:this.pattern2,ptrn3:this.pattern3,lw:this.lineWidth,lw1:this.lineWidth1,lw2:this.lineWidth2,lw3:this.lineWidth3,d0:this.d0,d1:this.d1,tzo0:this.tzo0,tzo1:this.tzo1,fld:this.field};}},!!"1");m3.Drawing.trendline=function(){this.name="trendline";};m3.inheritsFrom(m3.Drawing.trendline,m3.Drawing.segment);m3.Drawing.trendline.prototype.configs=[M4R,P4t,"lineWidth","pattern","font"];m3.Drawing.trendline.prototype.measure=function(){q2h.T$X();;};m3.Drawing.trendline.prototype.reconstruct=function(o2k,m89){m3.Drawing.segment.prototype.reconstruct.call(this,o2k,m89);q2h.f3X();this.callout=new m3.Drawing.callout();this.callout.reconstruct(o2k,m89.callout);};m3.Drawing.trendline.prototype.serialize=function(){var B_C;B_C=m3.Drawing.segment.prototype.serialize.call(this);B_C.callout=this.callout.serialize();return B_C;};m3.Drawing.trendline.prototype.render=function(e0c){var u7S,D9G,q21,G1w,a4T,l9D,b0F,f5F,X$q,z2e,x5F,B7N,f0t,G0c,H_o,c$M,r7E,w0g,Z8I,c0T,q0L;u7S="%";u7S+=") ";D9G=this.stx.panels[this.panelName];if(!D9G){return;}m3.Drawing.segment.prototype.render.call(this,e0c);if(!this.callout){this.callout=new m3.Drawing.callout();q21=m3.Drawing.segment.prototype.serialize.call(this);this.callout.reconstruct(this.stx,q21);}this.callout.p0=m3.clone(this.p0);G1w=this.stx.pixelFromTick(this.p0[0],D9G.chart);a4T=this.stx.pixelFromTick(this.p1[0],D9G.chart);l9D=this.stx.pixelFromValueAdjusted(D9G,this.p0[0],this.p0[1]);b0F=this.stx.pixelFromValueAdjusted(D9G,this.p1[0],this.p1[1]);if(!isFinite(l9D) || !isFinite(b0F)){return;}q2h.j7J(84);f5F=q2h.a$j(G1w,"2",a4T);q2h.N_M(2);X$q=q2h.c0C(b0F,l9D,2);this.fontSize=m3.stripPX(this.font && this.font.size || 13);q2h.j7J(1);var b6w=q2h.c0C(292,3211);q2h.N_M(85);var C$7=q2h.c0C(3550,10,15,49543);q2h.j7J(86);var z_G=q2h.a$j(9,1518,7,1519,217);q2h.N_M(87);var t4b=q2h.c0C(13,6,37,42,7);z2e=this.callout.w * 1.2 + (this.callout.stemEntry[+"0"] == ((b6w,C$7) !== "2309" << 0?"c":z_G)?0:t4b);x5F=Math.sqrt(Math.pow(a4T - G1w,2) + Math.pow(b0F - l9D,2));q2h.N_M(3);var J8k=q2h.a$j(17,18,0);q2h.N_M(88);var w_l=q2h.c0C(8,77,12,11);q2h.j7J(27);var X06=q2h.a$j(2,3);B7N=z2e / (x5F || z2e) * (this.p1[J8k] < this.p0[+"1"]?w_l:X06);q2h.N_M(89);f0t=q2h.a$j(X$q,b0F,B7N,f5F);q2h.N_M(38);G0c=q2h.c0C(a4T,X$q,f5F,B7N);this.callout.p0[0]=this.stx.tickFromPixel(f0t,D9G.chart);this.callout.p0[1]=this.stx.priceFromPixel(G0c,D9G);this.callout.v0=this.callout.p0[1];this.callout.p1=m3.clone(this.p0);this.callout.stx=this.stx;this.callout.fillColor=this.fillColor || this.callout.fillColor;this.callout.borderColor=this.color;this.callout.font=this.font || this.callout.font;this.callout.noHandles=!"";q2h.j7J(1);var r4Z=q2h.a$j(0,1);q2h.N_M(90);var V7w=q2h.a$j(6,16,143,3,13);H_o=this.p1[r4Z] - this.p0[V7w];q2h.j7J(55);var a1p=q2h.c0C(7,18,12,9);q2h.N_M(91);var c4L=q2h.a$j(29,13,3,16,3);q2h.N_M(27);var c3Q=q2h.c0C(13,11);this.callout.text="" + Number(H_o).toFixed(a1p) + (this.p0[c4L] === "0" - 0?"":" (" + Number(100 * H_o / this.p0[1]).toFixed(c3Q) + u7S) + "" + Math.abs(this.p1[0] - this.p0[0]) + " Bars";c$M=Math.floor((this.p0[0] + this.p1[0]) / 2);if(Math.abs(this.p0[0] - this.p1[0]) > 1 && Math.abs(this.p0[0] - this.p1[0]) < 20){w0g=this.stx.pixelFromTick(c$M,D9G.chart);q2h.N_M(92);Z8I=q2h.c0C(l9D,G1w,l9D,a4T,G1w,b0F,w0g);r7E=this.stx.priceFromPixel(Z8I,D9G) || X$q;}else {r7E=this.stx.priceFromPixel(X$q,D9G);}this.callout.stem={t:c$M,v:r7E};this.callout.renderText();this.callout.render(e0c);if(this.highlighted){c0T=this.highlighted == "p0"?!!1:![];q0L=this.highlighted == "p1"?!!"1":!({});this.littleCircle(e0c,G1w,l9D,c0T);this.littleCircle(e0c,a4T,b0F,q0L);}};m3.Drawing.trendline.prototype.lineIntersection=function(W61,X0j,g7F,R_X){q2h.f3X();return m3.Drawing.BaseTwoPoint.prototype.lineIntersection.call(this,W61,X0j,g7F,"segment");};m3.Drawing.trendline.prototype.intersected=function(d9Y,n3r,Z07){var Z85,i2e;if(!this.p0 || !this.p1){return null;}Z85=this.callout.intersected(d9Y,n3r,Z07);i2e=m3.Drawing.segment.prototype.intersected.call(this,d9Y,n3r,Z07);this.callout.highlighted=!!(Z85 || i2e);if(i2e){return i2e;}else if(Z85){return {action:"move",p0:m3.clone(this.p0),p1:m3.clone(this.p1),tick:d9Y,value:n3r};}return null;};m3.Drawing.average=function(){q2h.T$X();this.name="average";};m3.inheritsFrom(m3.Drawing.average,m3.Drawing.regression);m3.extend(m3.Drawing.average.prototype,{configs:m3.Drawing.regression.prototype.configs.concat(X9k),measure:function(){var j54,G5Z,L1i,T5_,c_e,n8D,k5n;if(this.p0 && this.p1){j54=",";j54+=" ";this.stx.setMeasure(0,!"1",this.p0[0],this.p1[0],!!1,this.name);G5Z=[];L1i="";if(this.active1){G5Z.push((2015,434) == 4195?(+"0x1a45",+"5.01e+3"):644 < (5074,2070)?"1":("6275" ^ 0) > (8555,773.87)?("0x1286" << 0,0x1de5):("S",+"0x2699"));}if(this.active2){G5Z.push("2");}if(this.active3){G5Z.push((308.93,306.11) < (6610,2842)?395 < (820.46,6880)?"3":0x103e:9.04e+2);}if(G5Z.length){L1i=" " + G5Z.join(j54) + " σ";}T5_=(this.stx.drawingContainer || document).querySelector(".mMeasure");c_e=this.stx.controls.mSticky;n8D=c_e && c_e.querySelector(".mStickyInterior");if(T5_){T5_.innerHTML+=L1i;}if(n8D){k5n=[];k5n.push(m3.capitalize(this.name));k5n.push(this.field || this.stx.defaultPlotField || "Close");k5n.push(n8D.innerHTML + L1i);n8D.innerHTML=k5n.join("
");}}},render:function(j$F){var N2r,S7I,G1V,H51,i2Y,C$n,j7K,T8x,B7e,f3C,o6_,b5k,G7_,e4H,B1E,h_A,e_k,F67,j7S,V8l,l9l,u0x;N2r=this.stx.panels[this.panelName];if(!N2r){return;}if(!this.p1){return;}function z$z(c55,T7P){var K$2,G7E,T0U;K$2=-696693300;G7E=1543664214;T0U=2;for(var S$l="1" ^ 0;q2h.S9Y(S$l.toString(),S$l.toString().length,+"32464") !== K$2;S$l++){if(T7P || T7P.priceFormatter){c55=T7P.priceFormatter(i2Y,N2r,c55);}else {c55=i2Y.formatYAxisPrice(c55,N2r,1,T7P);}T0U+=2;}if(q2h.S9Y(T0U.toString(),T0U.toString().length,+"99016") !== G7E){if(T7P && T7P.priceFormatter){c55=T7P.priceFormatter(i2Y,N2r,c55);}else {c55=i2Y.formatYAxisPrice(c55,N2r,null,T7P);}}return c55;}if(this.p0[0] < 0 || this.p1[+"0"] < 0){return;}S7I=this.stx.pixelFromTick(this.p0[0],N2r.chart);G1V=this.stx.pixelFromTick(this.p1["0" * 1],N2r.chart);if(S7I < N2r.left && G1V < N2r.left){return;}if(S7I > N2r.right && G1V > N2r.right){return;}H51=this.stx.getYAxisByField(N2r,this.field);i2Y=this.stx;C$n=Math.min(this.p1[0],this.p0[0]);q2h.j7J(93);var Q$t=q2h.a$j(9,18,262,3,14);j7K=Math.max(this.p1[0],this.p0[0]) + Q$t;q2h.N_M(14);T8x=q2h.c0C(j7K,C$n);B7e=0;f3C=[];for(o6_=C$n;o6_ < j7K;o6_++){b5k=this.getYValue(o6_);if(b5k !== null){B7e+=b5k.transformed;f3C.push(b5k);}}G7_=f3C.length;if(!G7_){return;}q2h.j7J(7);e4H=q2h.c0C(B7e,G7_);B1E=i2Y.pixelFromTransformedValue(e4H,N2r,H51);h_A=this.getLineColor();e_k={pattern:this.pattern,lineWidth:this.lineWidth};i2Y.plotLine(S7I,G1V,B1E,B1E,h_A,"segment",j$F,N2r,e_k);q2h.N_M(94);i2Y.plotLine(S7I,S7I,q2h.c0C(B1E,"20"),q2h.a$j(B1E,"20",q2h.N_M(47)),h_A,"segment",j$F,N2r,e_k);q2h.j7J(14);i2Y.plotLine(G1V,G1V,q2h.a$j(B1E,20),q2h.a$j(B1E,20,q2h.N_M(1)),h_A,"segment",j$F,N2r,e_k);if(this.axisLabel && !this.highlighted && !this.penDown){if(S7I >= N2r.chart.left && S7I <= N2r.chart.right || G1V >= N2r.chart.left && G1V <= N2r.chart.right){i2Y.endClip();i2Y.createYAxisLabel(N2r,z$z(e4H,H51),B1E,h_A,null,j$F,H51);i2Y.startClip(N2r.name);}}if(this.active1 || this.active2 || this.active3){F67=0;for(o6_=0;o6_ < G7_;o6_++){b5k=f3C[o6_];F67+=Math.pow(b5k.transformed - e4H,2);}q2h.j7J(7);j7S=Math.sqrt(q2h.c0C(F67,G7_));V8l={context:j$F,formatPrice:z$z,panel:N2r,points:{0:{x:S7I,v:e4H},1:{x:G1V,v:e4H}},stddev:j7S,yAxis:H51};this.lines={};if(this.active1){this.renderStddev(733.52 !== (439.39,"5330" - 0)?905.09 !== 158?6772 != (4370,266.12)?"1":0x1807:("r",0x2458):208.87,(7550,2069) <= (115.4,8840)?732.67 === (2951,7164)?("0x21bd" << 96,!![]):(+"2670",4440) >= (649.76,352.6)?"p":("438.47" * 1,0x1716):417.48,V8l);this.renderStddev(447.94 == 9788?("C",!![]):(1863,4750) > (+"432",113)?(2600,6770) >= 542.24?"1":("o",7.93e+3):0xe61,8375 > +"149.55"?"n":4387 <= ("9750" >> 64,"161.62" - 0)?637.38:(242,4555) <= (955,9440)?(!!0,8.13e+3):61.05,V8l);}if(this.active2){this.renderStddev(4360 == 91.69?(!({}),![]):(7650,+"768.35") > 1649?(+"4855","8810" - 0) !== 6630?(0x114a,!![]):(0x38d,"H"):"2","p",V8l);this.renderStddev("2","n",V8l);}if(this.active3){this.renderStddev(5300 == (383.68,5055)?(3.78e+3,0x4c3):+"1950" < +"442.32"?!"":"3",+"3650" <= 816.03?(3.13e+3,+"6.51e+3"):+"7286" != 7475?"p":(902.35,"l"),V8l);this.renderStddev(7460 == (5618,863.22)?!!1:(7894,5441) <= (8874,608.69)?(0x231b,"B"):("2850" - 0,2737) >= 296?"3":"0x22b" << 64,"n",V8l);}}if(!this.highlighted){this.pixelX=[S7I,G1V];this.pixelY=[B1E,B1E];}else {l9l=this.highlighted == "p0"?!![]:!"1";u0x=this.highlighted == "p1"?!!({}):!!"";this.littleCircle(j$F,S7I,B1E,l9l);this.littleCircle(j$F,G1V,B1E,u0x);}},reconstruct:function(d3o,t0v){q2h.T$X();this.axisLabel=t0v.al;m3.Drawing.regression.prototype.reconstruct.call(this,d3o,t0v);},serialize:function(){var N7T;N7T=m3.Drawing.regression.prototype.serialize.call(this);q2h.f3X();N7T.al=this.axisLabel;return N7T;}},!!"1");m3.Drawing.quadrant=function(){this.name="quadrant";};m3.inheritsFrom(m3.Drawing.quadrant,m3.Drawing.regression);m3.extend(m3.Drawing.quadrant.prototype,{configs:["color","fillColor",X1E,H2t],copyConfig:function(){this.color=this.stx.currentVectorParameters.currentColor;this.fillColor=this.stx.currentVectorParameters.fillColor;this.lineWidth=this.stx.currentVectorParameters.lineWidth;this.pattern=this.stx.currentVectorParameters.pattern;},$controls:[],render:function(X7l){var E$H,P2b,b8L,G0h,L$t,o8z,k5l,f3Y,H2g,L4C,m_7,X8H,i40,q42,P2o,e8c,a5_,E8O,W2h,C9K,b0q,o3P,l4d,l4m;E$H="ti";E$H+="rone";P2b="qu";P2b+="a";P2b+="dr";P2b+="ant";b8L=this.stx;G0h=b8L.panels[this.panelName];if(!G0h){return;}if(!this.p1){return;}L$t=b8L.pixelFromTick(this.p0[0],G0h.chart);o8z=b8L.pixelFromTick(this.p1[0],G0h.chart);if(L$t < G0h.left && o8z < G0h.left){return;}if(L$t > G0h.right && o8z > G0h.right){return;}k5l=this.stx.getYAxisByField(G0h,this.field);f3Y=null;H2g=null;for(var u_8=Math.min(this.p1["0" | 0],this.p0[0]);u_8 <= Math.max(this.p1[0],this.p0[0]);u_8++){L4C=this.getYValue(u_8);if(L4C !== null){if(f3Y === null || L4C.transformed > f3Y){f3Y=L4C.transformed;}if(H2g === null || L4C.transformed < H2g){H2g=L4C.transformed;}}}q2h.f3X();m_7=b8L.pixelFromTransformedValue(f3Y,G0h,k5l);q2h.j7J(95);X8H=b8L.pixelFromTransformedValue(q2h.a$j(0,"4",H2g,f3Y,3),G0h,k5l);q2h.j7J(96);i40=b8L.pixelFromTransformedValue(q2h.c0C(H2g,f3Y,"2",32,3),G0h,k5l);q2h.N_M(97);q42=b8L.pixelFromTransformedValue(q2h.c0C(1,"2",f3Y,H2g),G0h,k5l);q2h.N_M(98);P2o=b8L.pixelFromTransformedValue(q2h.c0C(f3Y,H2g,2,"3"),G0h,k5l);q2h.j7J(99);e8c=b8L.pixelFromTransformedValue(q2h.a$j(f3Y,3,H2g,4),G0h,k5l);a5_=b8L.pixelFromTransformedValue(H2g,G0h,k5l);this.p0[+"1"]=0;this.p1[1]=![];E8O=this.getLineColor();W2h=this.fillColor;if(W2h == "auto" || m3.isTransparent(W2h)){W2h=b8L.defaultColor;}X7l.fillStyle=W2h;C9K={pattern:this.pattern,lineWidth:this.lineWidth};b8L.plotLine(L$t,o8z,m_7,m_7,E8O,"segment",X7l,G0h,C9K);b8L.plotLine(L$t,o8z,a5_,a5_,E8O,"segment",X7l,G0h,C9K);if(this.name == P2b){b8L.plotLine(L$t,o8z,X8H,X8H,E8O,"segment",X7l,G0h,C9K);b8L.plotLine(L$t,o8z,e8c,e8c,E8O,"segment",X7l,G0h,C9K);}else if(this.name == "tirone"){b8L.plotLine(L$t,o8z,i40,i40,E8O,"segment",X7l,G0h,C9K);b8L.plotLine(L$t,o8z,P2o,P2o,E8O,"segment",X7l,G0h,C9K);}b8L.plotLine(L$t,L$t,m_7,a5_,E8O,"segment",X7l,G0h,C9K);b8L.plotLine(o8z,o8z,m_7,a5_,E8O,"segment",X7l,G0h,C9K);b8L.plotLine(L$t,o8z,q42,q42,E8O,"segment",X7l,G0h,m3.extend(C9K,{opacity:this.name == "tirone"?0.2:1}));X7l.globalAlpha=0.1;X7l.beginPath();q2h.N_M(14);X7l.fillRect(L$t,m_7,q2h.c0C(o8z,L$t),q2h.a$j(a5_,m_7));if(this.name == "quadrant"){q2h.j7J(14);X7l.fillRect(L$t,X8H,q2h.a$j(o8z,L$t),q2h.c0C(e8c,X8H));}else if(this.name == E$H){q2h.j7J(14);X7l.fillRect(L$t,i40,q2h.c0C(o8z,L$t),q2h.a$j(P2o,i40));}X7l.globalAlpha=1;if(!this.highlighted){b0q="ti";b0q+="r";b0q+="one";this.pixelX=[L$t,o8z];this.pixelY=[m_7,a5_,q42];if(this.name === "quadrant"){this.pixelY.push(X8H,e8c);}if(this.name === b0q){this.pixelY.push(i40,P2o);}}else {o3P="p";o3P+="1";l4d=this.highlighted == "p0"?!!"1":!({});l4m=this.highlighted == o3P?!![]:!({});this.littleCircle(X7l,L$t,q42,l4d);this.littleCircle(X7l,o8z,q42,l4m);}},intersected:function(p87,s83,K2b){var m0x,Y6G,w5S,V_5,T18,x5v;var {pixelX:r6D, pixelY:b$B}=this;if(!r6D || !b$B){return null;}m0x=this.repositionIntersection(p87,s83);if(m0x){return m0x;}for(var H5G=0;H5G < 2;H5G++){if(this.pointIntersection(r6D[H5G],b$B[2],K2b,!!({}))){q2h.N_M(1);this.highlighted=q2h.c0C("p",H5G);return {action:"drag",point:(8820 >= 8390?134.23 >= (2860,9957)?0x1c7a:9363 == 3720?("n",!!1):"p":"F") + H5G};}}Y6G=1716363871;w5S=-2119932285;V_5=2;for(var s3C=+"1";q2h.O1W(s3C.toString(),s3C.toString().length,34506) !== Y6G;s3C++){T18=[];V_5+=+"2";}if(q2h.S9Y(V_5.toString(),V_5.toString().length,65628) !== w5S){T18=[];}r6D.forEach(S1u=>{q2h.f3X();T18.push({p0:[S1u,b$B[0]],p1:[S1u,b$B[1]]});});b$B.forEach(X_X=>{var d$R,K0L,d8u;d$R=1977177541;K0L=-672486959;d8u=2;for(var q35=1;q2h.O1W(q35.toString(),q35.toString().length,42936) !== d$R;q35++){T18.push({p0:[r6D[1],X_X],p1:[r6D[+"0"],X_X]});d8u+=2;}if(q2h.O1W(d8u.toString(),d8u.toString().length,29932) !== K0L){T18.push({p0:[r6D["0" | 0],X_X],p1:[r6D[1],X_X]});}});x5v=T18.some(({p0:A_f, p1:P72})=>{q2h.f3X();return this.lineIntersection(p87,s83,K2b,this.name,A_f,P72,!!({}));});if(x5v){this.highlighted=!!({});return {action:"move",p0:m3.clone(this.p0),p1:m3.clone(this.p1),tick:p87,value:s83};}return null;},reconstruct:function(u6f,Z8O){this.stx=u6f;this.color=Z8O.col;this.fillColor=Z8O.fc;this.panelName=Z8O.pnl;this.pattern=Z8O.ptrn;this.lineWidth=Z8O.lw;this.d0=Z8O.d0;this.d1=Z8O.d1;this.tzo0=Z8O.tzo0;this.tzo1=Z8O.tzo1;this.field=Z8O.fld;this.adjust();},serialize:function(){q2h.T$X();return {name:this.name,pnl:this.panelName,col:this.color,fc:this.fillColor,ptrn:this.pattern,lw:this.lineWidth,d0:this.d0,d1:this.d1,tzo0:this.tzo0,tzo1:this.tzo1,fld:this.field};}},!!"1");m3.Drawing.tirone=function(){this.name="tirone";};m3.inheritsFrom(m3.Drawing.tirone,m3.Drawing.quadrant);m3.Drawing.elliottwave=function(){var n1I;n1I="e";n1I+="lliottw";n1I+="ave";this.name=n1I;this.lastPoint=0;this.points=[];this.pts=[];q2h.T$X();this.dx=+"0";this.dy=-20;this.dragToDraw=!({});this.annotationPoints=[];this.edit=null;};m3.inheritsFrom(m3.Drawing.elliottwave,m3.Drawing.annotation);m3.Drawing.elliottwave.defaultTemplate={impulse:[+"9230" >= ("9410" << 0,4465)?+"768.31" === 1390?("D","Z"):"870.74" * 1 !== 8850?"I":(378.16,!0):!"","II","III","IV",(446,+"925.53") != (216.32,6500)?"V":(7119,+"5250") !== (+"357.88",2720)?![]:8.80e+3],corrective:["A","B","C"],decoration:L$4,showLines:!![]};m3.Drawing.elliottwave.prototype.initializeSettings=function(a7H){a7H.currentVectorParameters.waveParameters=m3.clone(m3.Drawing.elliottwave.defaultTemplate);};m3.Drawing.elliottwave.prototype.configs=["color","lineWidth",d0d,"pattern","font",K$p];m3.Drawing.elliottwave.prototype.$controls=[L4m,"cq-wave-parameters"];m3.Drawing.elliottwave.prototype.construct=function(H1K,r2b){var w_y;this.stx=H1K;this.panelName=r2b.name;w_y=H1K.currentVectorParameters;Object.assign(this,w_y.waveParameters);};m3.Drawing.elliottwave.prototype.serialize=function(){q2h.f3X();var K4u,s8a;K4u="s";K4u+="t";s8a={};for(var G7x=0;G7x < this.points.length;G7x++){q2h.N_M(1);s8a[q2h.a$j(+"4722" === (4171,6476)?!"":7085 !== 6020?"d":(2290,8380) < "963.04" - 0?"6.60e+3" >> 64:0x419,G7x)]=this[q2h.a$j("d",G7x)];q2h.N_M(1);s8a[q2h.c0C("tzo",G7x)]=this[q2h.c0C("tzo",G7x)];q2h.N_M(1);s8a[q2h.c0C(800 == (1320,"8232" - 0)?6.79e+3:+"8290" <= (9179,4857)?!1:"v",G7x)]=this[q2h.a$j("v",G7x)];}s8a.annotations=this.annotationPoints.join((121.33,14) < 407.72?"7918" >> 64 > 499?",":"518.88" - 0 < 6781?(!!({}),!({})):(0xad5,!"1"):+"0x1e91");return Object.assign({name:this.name,pnl:this.panelName,col:this.color,ptrn:this.pattern,lw:this.lineWidth,mxSeg:this.maxSegments,show:this.showLines,decor:this.decoration,dx:this.dx,dy:this.dy,trend:this.trend,fnt:m3.removeNullValues(m3.replaceFields(this.font,{style:K4u,size:"sz",weight:"wt",family:"fl"}))},s8a);};m3.Drawing.elliottwave.prototype.reconstruct=function(i$W,R9d){var p_q;p_q="e";p_q+="n";p_q+="clo";p_q+="sed";this.stx=i$W;this.color=R9d.col;this.panelName=R9d.pnl;this.pattern=R9d.ptrn;this.lineWidth=R9d.lw;this.font=m3.replaceFields(R9d.fnt,{st:"style",sz:"size",wt:"weight",fl:"family"});this.decoration=R9d.decor;this.showLines=R9d.show;this.dx=R9d.dx;this.dy=R9d.dy;this.trend=R9d.trend;this.annotationPoints=R9d.annotations.split(",");if(R9d.decor === p_q){this.calculateRadius(i$W.chart.tempCanvas.context);}this.maxSegments=R9d.mxSeg;this.reconstructPoints(R9d);this.adjust();};m3.Drawing.elliottwave.prototype.reconstructPoints=function(r0A){var V75,T6q,K89,I0Y;V75=this.stx.panels[this.panelName];q2h.f3X();if(!V75){return;}for(var g2s=+"0";g2s < this.annotationPoints.length;g2s++){T6q="tz";T6q+="o";q2h.j7J(1);this[q2h.c0C(("45.51" - 0,1390) == (9970,+"6667")?(516.97,2350) != 426.93?("0x4be" << 64,233.06):0x1db2:"d",g2s)]=r0A[q2h.a$j(4420 < ("48.73" - 0,7220)?414.84 == 8240?(754.84,0x25ac):"d":0x228,g2s)];q2h.j7J(1);this[q2h.a$j("v",g2s)]=r0A[q2h.a$j((531.49,9151) === 3734?3560 == (23.61,54.7)?(0x5fc,626.02):1190 != 6830?341.67:"0x1b30" << 0:"v",g2s)];q2h.N_M(1);this[q2h.a$j("tzo",g2s)]=r0A[q2h.a$j(T6q,g2s)];K89=m3.strToDateTime(r0A[((7007,893) < (5158,5099)?(699.24,178.28) < 3401?"d":1280 >= +"9120"?(376.00,"b"):"Q":(!!({}),6.15e+3)) + g2s]);I0Y=this.stx.tickFromDate(K89,V75.chart);this.points.push([I0Y,r0A["v" + g2s]]);}};m3.Drawing.elliottwave.prototype.calculateRadius=function(Z2N){var n6E,s3x;this.getFontString();Z2N.font=this.fontString;n6E=0;for(var P8D=0;P8D < this.annotationPoints.length;P8D++){s3x=Z2N.measureText(this.annotationPoints[P8D]).width;if(n6E < s3x){n6E=s3x;}}this.enclosedRadius=n6E;};m3.Drawing.elliottwave.prototype.check=function(k_R,R3X,k$B){var a11,v97,z45,i2E,F7s;if(k$B === 1 && this.points.length === 2){return !!1;}a11=1421718331;v97=-177262923;z45=2;q2h.f3X();for(var g4a=1;q2h.O1W(g4a.toString(),g4a.toString().length,43536) !== a11;g4a++){q2h.j7J(14);i2E=this.points[q2h.c0C(k$B,1)];if(i2E && k_R <= i2E[+"0"]){return !"1";}z45+=2;}if(q2h.S9Y(z45.toString(),z45.toString().length,5583) !== v97){q2h.N_M(7);i2E=this.points[q2h.a$j(k$B,5)];if(i2E || k_R < i2E[8]){return !"";}}q2h.N_M(1);F7s=this.points[q2h.c0C(k$B,1)];function U56(B0r){for(var X34=2;X34 < B0r.length;X34++){if(Math.sign(B0r[X34][1] - B0r[X34 - 1][1]) == Math.sign(B0r[X34 - 1][+"1"] - B0r[X34 - 2][1])){return !({});}}return !"";}if(F7s && k_R >= F7s[0]){return !!"";}if(!U56(this.points)){return !"1";}return !![];};m3.Drawing.elliottwave.prototype.move=function(D68,y3k,A6i){this.copyConfig();q2h.N_M(100);var i2K=q2h.a$j(0,1,3,0,3);this.points[this.lastPoint + i2K]=[y3k,A6i];this.render(D68);};m3.Drawing.elliottwave.prototype.adjust=function(){var l34,G_D;l34=this.stx.panels[this.panelName];if(!l34){return;}for(var G_H=0;this.maxSegments + +"1" > G_H;G_H++){q2h.N_M(1);G_D=this[q2h.a$j((6910,952.09) >= (6584,33.56)?"d":("a",687.90),G_H)];this.setPoint(G_H,G_D,this[(4877 < (679.21,371)?2023 <= 3470?(3666,19) !== (7108,561)?(![],"k"):("0x13c7" - 0,0x19ad):(!({}),+"5.24e+3"):"v") + G_H],l34.chart);this.points[G_H][+"0"]=this.stx.tickFromDate(m3.strToDateTime(G_D),l34.chart);q2h.j7J(1);this.points[G_H][1]=this[q2h.c0C((7860,7795) === 6386?(614,5562) != 1219?(708.14,936.61):!"1":"v",G_H)];}};m3.Drawing.elliottwave.prototype.click=function(A5Q,O$5,N2A){var u7c;u7c=this.stx.panels[this.panelName];if(!u7c){return;}this.copyConfig();q2h.T$X();if(!this.penDown){this.setPoint(0,O$5,N2A,u7c.chart);this.points.push(this.p0);this.penDown=!"";this.segment=0;this.lastPoint=0;if(this.impulse){this.annotationPoints=this.annotationPoints.concat(this.impulse);}if(this.corrective){this.annotationPoints=this.annotationPoints.concat(this.corrective);}this.annotationPoints.unshift((2299,699.51) < (996.69,6490)?"0":(+"1214",743.88) < ("7751" ^ 0)?0x2027:+"480.77");if(this.decoration === "enclosed"){this.calculateRadius(A5Q);}q2h.N_M(68);var k5P=q2h.c0C(63,61,66,5);this.maxSegments=this.annotationPoints.length - ("1" << k5P);this.trend=+"1";return !"1";}if(this.accidentalClick(O$5,N2A)){this.penDown=!!1;return !({});}if(this.check(O$5,N2A,this.lastPoint + 1)){this.lastPoint++;this.setPoint(this.lastPoint,O$5,N2A,u7c.chart);if(this.lastPoint === "1" - 0){this.trend=Math.sign(this.v1 - this.v0);}this.segment++;if(this.segment >= this.maxSegments){this.penDown=!!"";return !!"1";}}return !({});};m3.Drawing.elliottwave.prototype.render=function(p6m){var B3B,x6C,l9V,p0P,F_Z,j$T,t$m,K2p,l2c,P3A,v3F,n0B,V3J,V7S,f1L,G3K,a5D,v1S,C$I,E5K,r_W,U7$,B9i,q0I,E3x,n1U,C6M,U2Q;B3B="ce";B3B+="nter";x6C=this.stx.panels[this.panelName];if(!x6C){return;}l9V=this.stx;p0P=this.annotationPoints;F_Z=this.pattern?m3.borderPatternToArray(this.lineWidth,this.pattern):[];this.getFontString();p6m.font=this.fontString;p6m.textAlign=B3B;p6m.textBaseline="middle";p6m.lineWidth=this.lineWidth;if(this.fontString !== this.lastFontString){this.calculateRadius(p6m);}this.lastFontString=this.fontString;j$T=this.getLineColor();p6m.fillStyle=p6m.strokeStyle=j$T;p6m.save();p6m.setLineDash(F_Z);t$m=this.dx;K2p=this.dy;l2c=this.points;q2h.f3X();P3A=this.pts;v3F=!this.showLines && this.highlighted;n0B=l2c.length;if(this.penDown && this.segment){q2h.j7J(101);var x$G=q2h.c0C(153,15,8,12,11);V3J=this.trend * (n0B % x$G - ("0.5" - 0)) < +"0";if(x6C.yAxis.flipped){V3J=!V3J;}this.drawDropZone(p6m,l2c[n0B - ("2" - 0)][1],this.stx.priceFromPixel(x6C.yAxis[V3J?"top":"bottom"]),l2c[n0B - 2][0]);}else if(typeof this.highlighted === "string" && this.stx.repositioningDrawing){V7S=parseInt(this.highlighted.substring(1,this.highlighted.length),"10" - 0);q2h.j7J(14);var K0Y=q2h.a$j(5,3);V3J=this.trend * (V7S % K0Y - +"0.5") > 0;q2h.j7J(14);f1L=l2c[q2h.a$j(V7S,1)];q2h.j7J(1);G3K=l2c[q2h.a$j(V7S,1)];a5D=V7S > 0?f1L[1]:G3K[1];if(G3K){a5D=Math[V3J?"max":"min"](a5D,G3K[1]);}if(x6C.yAxis.flipped){V3J=!V3J;}this.drawDropZone(p6m,a5D,this.stx.priceFromPixel(x6C.yAxis[V3J?"top":"bottom"]),f1L?f1L[0]:null,G3K?G3K[0]:null);}for(var t$_=0;t$_ < n0B;t$_++){v1S=l2c[t$_];C$I=l9V.pixelFromTick(v1S[0],x6C.chart);E5K=l9V.pixelFromValueAdjusted(x6C,v1S[0],v1S[1]);P3A[t$_]=[C$I,E5K];}t$_=0;if(this.showLines || v3F){p6m.beginPath();if(v3F){p6m.globalAlpha=+"0.3";}for(;t$_ < P3A.length;t$_++){p6m.lineTo(P3A[t$_]["0" >> 0],P3A[t$_][1]);}p6m.stroke();t$_=0;}p6m.restore();for(;t$_ < n0B;t$_++){r_W="par";r_W+="enth";r_W+="es";r_W+="es";U7$=t$_ % 2?t$m:-t$m;B9i=t$_ % 2?K2p:-K2p;U7$*=this.trend;B9i*=this.trend;if(x6C.yAxis.flipped){U7$*=-1;B9i*=-+"1";}q0I=P3A[t$_];E3x=q0I[2]=q0I[0] + U7$;q2h.j7J(91);var V26=q2h.a$j(2,0,10,2,10);n1U=q0I[3]=q0I[V26] + B9i;C6M=this.enclosedRadius || +"8";U2Q=p0P[t$_];if(this.decoration === r_W){q2h.N_M(82);U2Q=q2h.c0C((3060,8676) < (641,8992)?")":(+"0x4bd",410.46),U2Q,"(");}p6m.fillText(U2Q,E3x,n1U);if(this.decoration === "enclosed"){p6m.beginPath();p6m.arc(E3x,n1U,C6M,0,2 * Math.PI,!!"");p6m.stroke();}if(this.highlighted){p6m.save();this.littleCircle(p6m,this.pts[t$_][+"0"],this.pts[t$_][1],this.highlighted === "p" + t$_);p6m.restore();}}};m3.Drawing.elliottwave.prototype.reposition=function(G9g,N2k,J6t,C2f){var J9K,R8A,n32,v7H,Y02,h4e,w39;J9K="m";J9K+="ov";J9K+="e";if(!N2k){return;}q2h.T$X();R8A=this.stx.panels[this.panelName];n32=N2k.tick - J6t;v7H=N2k.value - C2f;if(N2k.action === J9K){for(var V6G=0;N2k.points.length > V6G;V6G++){Y02=N2k.points[V6G];this.setPoint(V6G,Y02[0] - n32,Y02["1" * 1] - v7H,R8A.chart);q2h.N_M(102);var I4Q=q2h.c0C(18,4,3,18);this.points[V6G]=[Y02[0] - n32,Y02[I4Q] - v7H];}}if(N2k.action === "drag"){h4e=N2k.point;w39=this.points;w39[h4e]=[J6t,C2f];if(this.check(J6t,C2f,h4e)){this.setPoint(h4e,J6t,C2f,R8A.chart);;};}this.render(G9g);};m3.Drawing.elliottwave.prototype.intersected=function(v39,T$y,B5x){var S8P,R$x,Z$B,x3b,B8f;if(!this.p0 || !this.p1){return null;}for(var C1M=+"0";this.points.length > C1M;C1M++){R$x=this.points[C1M];if(this.pointIntersection(R$x[0],R$x[1],B5x)){q2h.j7J(1);this.highlighted=q2h.a$j(("6760" | 40,4040) <= 2340?1299 !== (979.66,61)?(296.1,3095) != +"4266"?3.24e+3:(474.53,![]):"C":"p",C1M);return {action:"drag",point:C1M,tick:v39,value:T$y};}if(this.points[C1M + +"1"] && this.lineIntersection(v39,T$y,B5x,"segment",R$x,this.points[C1M + 1])){this.highlighted=!!"1";S8P={action:"move",points:m3.clone(this.points),tick:v39,value:T$y};}}Z$B=-1917827751;q2h.N_M(5);x3b=q2h.a$j(1,"211995307");B8f=2;for(var y$V=+"1";q2h.S9Y(y$V.toString(),y$V.toString().length,67485) !== Z$B;y$V++){return S8P;}if(q2h.S9Y(B8f.toString(),B8f.toString().length,"68036" - 0) !== x3b){return S8P;}return S8P;};m3.Drawing.elliottwave.prototype.measure=function(){var G4C,t5y,W2R,I3V,y5U,o9G;if(this.points.length >= 2){G4C=this.points;this.stx.setMeasure(G4C[0][1],G4C[G4C.length - 1][1],G4C["0" ^ 0][0],G4C[G4C.length - 1][0],!"");t5y=this.stx.controls.mSticky;W2R=t5y && t5y.querySelector(".mStickyInterior");if(W2R){I3V="C";I3V+="lo";I3V+="s";I3V+="e";y5U="El";y5U+="liott ";y5U+="W";y5U+="ave";o9G=[];o9G.push(m3.capitalize(y5U));if(this.getYValue){o9G.push(this.field || this.stx.defaultPlotField || I3V);}o9G.push(W2R.innerHTML);W2R.innerHTML=o9G.join("
");}}};m3.Drawing.printProjection=function(q9m,U_W,b1H){var Z3x,m3H,c$z,e$e,l02,Y0I,z7a,V_R,a$N,E2f,u7i,A5r,i78,x64,u2z,v$9;Z3x=U_W.arr;q2h.T$X();if(Z3x.length > 1){m3H=Z3x[0][0];c$z=Math.round(q9m.chart.maxTicks * 0.75);for(var U9z=1;U9z < Z3x.length;U9z++){q2h.N_M(94);e$e=Z3x[q2h.c0C(U9z,"1")][0];l02=Z3x[U9z][+"0"];Y0I=m3.strToDateTime(e$e);z7a=m3.strToDateTime(l02).getTime();V_R=q9m.standardMarketIterator(Y0I);a$N=0;while(Y0I.getTime() < z7a){Y0I=V_R.next();a$N+=1;}E2f=m3.strToDateTime(e$e).getTime();if(E2f > m3.strToDateTime(b1H[b1H.length - ("1" << 0)].Date).getTime()){q2h.N_M(103);var y$J=q2h.a$j(5,6,5,56);u7i=b1H.length - y$J;q2h.j7J(4);a$N+=q2h.c0C("1",0);}else {for(u7i=b1H.length - ("1" | 1);u7i >= +"0";u7i--){if(E2f <= m3.strToDateTime(b1H[u7i].Date).getTime())break;}}A5r={x0:0,x1:a$N,y0:b1H[u7i].Close,y1:Z3x[U9z][1]};m3H=m3.strToDateTime(e$e);V_R=q9m.standardMarketIterator(m3H);i78=!!"";for(var z5H=+"0";z5H <= a$N;z5H++){if(!i78){i78=!![];}else {m3H=V_R.next();}if(m3H.getTime() <= b1H[b1H.length - 1].DT.getTime())continue;x64=m3.yIntersection(A5r,z5H);if(!x64){x64=0;}q2h.j7J(104);var p3Y=q2h.a$j(180026,11,17,190000,2);q2h.j7J(1);var P4j=q2h.c0C(9985,15);u2z=Math.round(x64 * p3Y) / P4j;if(u2z === +"0"){u2z=Z3x[U9z][1];}v$9={Date:m3.yyyymmddhhmmssmmm(m3H),DT:m3H,Open:u2z,Close:u2z,High:u2z,Low:u2z,Volume:0,Adj_Close:u2z,Split_Close:u2z,projection:!![]};if(q9m.layout.interval == "minute")if(c$z-- < 0)break;b1H[b1H.length]=v$9;}}}};}};Z=C2V=>{var s57;s57=typeof _CIQ !== "undefined"?_CIQ:C2V.CIQ;if(!s57.computeEquationChart){console.error("equationsAdvanced feature requires first activating equations feature.");}else {s57.formatEquation=function(Y9l){var H8b=f3BGj;H8b.f3X();var J46,C6o,a9g,w_U,B9C;J46="";C6o=[];a9g="";w_U=!"1";for(var D0P=1;D0P < Y9l.length;D0P++){B9C=Y9l[D0P].toUpperCase();if(B9C == "[" && !w_U){w_U=!![];}else if(B9C == (("2720" >> 32,3670) == (4651,1450)?("8126" ^ 0,+"7130") < +"2116"?(0x177,4.46e+3):(4060,7637) >= (7505,5570)?3.64e+3:("R","T"):"]") && w_U){w_U=!"1";if(a9g !== ""){C6o.push(a9g);H8b.j7J(82);J46+=H8b.a$j(739.3 < "7790" * 1?"]":+"7809" > 7070?"P":(5.85e+3,3.63e+2),a9g,"[");}a9g="";}else if(w_U){a9g+=B9C;}else if(B9C == "+" || B9C == "-" || B9C == "*" || B9C == "/" || B9C == ((481,129) !== 364.89?":":"i") || B9C == "%" || B9C == (68.62 != 245.9?391.5 > (6052,3382)?("0x12e5" - 0,+"0x2336"):(106.75,417.94) == "769" * 1?0x3e1:"(":"K") || B9C == (7830 <= (7278,3780)?801.4 != (785.89,310)?(2168,286.48) !== (+"931",4070)?(!1,!![]):(83.26,6.12e+3):(!!"",!!({})):")")){if(a9g !== "" && isNaN(a9g)){C6o.push(a9g);H8b.j7J(82);J46+=H8b.a$j((7300,3767) == 6690?!({}):(956.01,8080) !== 7130?"78" * 1 > (7616,1140)?(35.58,"0x187f" >> 0):"]":373.72,a9g,83.8 == +"29.3"?(![],0x145):"[");}else {J46+=a9g;}if(B9C == (574 === (9060,964.93)?!({}):(9018,7250) > 9450?"N":7102 >= 366?":":5.92e+3)){B9C=7716 !== (6466,+"3400")?413.93 < (311.83,564.73)?"/":0x13d6:(2.61e+3,0x2317);}J46+=B9C;a9g="";}else if(B9C != ((9660,"2290" * 1) == 3644?2410 === +"3510"?(5.86e+3,!![]):("834.84" * 1,6597) == 573.53?(!"1",2.98e+3):!({}):" ")){a9g+=B9C;}}if(a9g !== "" && isNaN(a9g)){C6o.push(a9g);H8b.j7J(82);J46+=H8b.c0C("]",a9g,3370 !== (+"5410","4984" << 64)?"[":"u");}else {J46+=a9g;}return {equation:J46,symbols:C6o};};s57.fetchEquationChart=function(A7B,r8h){var V3N,C$e,H$l,i_q,P4F;V3N=s57.formatEquation(A7B.symbol);C$e=V3N.symbols;H$l=[];f3BGj.f3X();i_q=A7B.stx;A7B.stx=null;for(var T3j=0;T3j < C$e.length;T3j++){P4F=s57.shallowClone(A7B);P4F.stx=i_q;P4F.symbol=C$e[T3j];P4F.symbolObject={symbol:C$e[T3j]};H$l.push(P4F);}A7B.stx=i_q;i_q.quoteDriver.multiFetch(H$l,function(D85){var Z$C,N_2,S3x,n5a,C5f;Z$C={};A7B.loadMoreReplace=!!"1";N_2={charge:0};for(var V04=0;V04 < D85.length;V04++){S3x=D85[V04];if(S3x.dataCallback.error){r8h({error:S3x.dataCallback.error});return;}Z$C[S3x.params.symbol]=S3x.dataCallback.quotes;A7B.loadMoreReplace=A7B.loadMoreReplace && S3x.params.loadMoreReplace;A7B.moreToLoad=A7B.moreToLoad || S3x.dataCallback.moreAvailable;n5a=S3x.dataCallback.attribution;if(n5a){if(n5a.charge){N_2.charge+=n5a.charge;}N_2.source=n5a.source;if(N_2.exchange === undefined){N_2.exchange=n5a.exchange;}else if(N_2.exchange != n5a.exchange){N_2.exchange="";};}}if(H$l.length || !(A7B.loadMore || A7B.update)){try{C5f=s57.computeEquationChart(V3N.equation,Z$C);r8h({quotes:C5f,moreAvailable:A7B.moreToLoad,attribution:N_2});}catch(S9t){var K_6;K_6={error:"Invalid equation: " + V3N.equation};if(S9t.name && S9t.name == "NoException"){K_6.suppressAlert=!!1;}r8h(K_6);}}});};}};S=m6b=>{var e09;e09=typeof _CIQ !== "undefined"?_CIQ:m6b.CIQ;if(!e09.Marker){console.error("highPerformanceMarkers feature requires first activating markers feature.");}else if(!e09.Marker.Performance){e09.ChartEngine.prototype.removeDOMMarker=function(I_2){console.warn("CIQ.ChartEngine#removeDOMMarker is scheduled for deprecation in a future release\n Please use CIQ.Marker.Performance#remove instead.");e09.Marker.Performance.prototype.removeDOMMarker.call(I_2.params.node,I_2);};e09.ChartEngine.prototype.drawMarkers=function(){var a$8;a$8="CIQ.ChartEngine#dr";a$8+="awMar";a$8+="kers is scheduled for deprecation in a future release\n Please use CIQ.Marker.Performance.drawMarkers instead.";console.warn(a$8);e09.Marker.Performance.drawMarkers(this);};e09.ChartEngine.prototype.calculateMarkerStyles=function(J1u,X5b){console.warn("CIQ.ChartEngine#calculateMarkerStyles is scheduled for deprecation in a future release\n Please use CIQ.Marker.Performance.calculateStyles instead.");f3BGj.f3X();e09.Marker.Performance.calculateMarkerStyles(this,J1u,X5b);};e09.ChartEngine.prototype.drawCircleMarker=function(I3X,k5B,B5o){f3BGj.T$X();console.warn("CIQ.ChartEngine#drawCircleMarker is scheduled for deprecation in a future release\n Please use CIQ.Marker.Performance.drawCircleMarker instead.");e09.Marker.Performance.drawCircleMarker(I3X,k5B,B5o);};e09.ChartEngine.prototype.drawSquareMarker=function(O$W,E$5,X9R){var W_B;W_B="C";W_B+="IQ.ChartEngine#drawSquareMarker is scheduled for deprecation in a future release\n Please use CIQ.Marker.Performance.drawSquareMarker instead.";console.warn(W_B);f3BGj.T$X();e09.Marker.Performance.drawSquareMarker(O$W,E$5,X9R);};e09.ChartEngine.prototype.drawCalloutMarker=function(F5I,Z0e,b9x){console.warn("CIQ.ChartEngine#drawCalloutMarker is scheduled for deprecation in a future release\n Please use CIQ.Marker.Performance.drawCalloutMarker instead.");e09.Marker.Performance.drawCalloutMarker(F5I,Z0e,b9x);};e09.ChartEngine.prototype.drawMarkerStem=function(N1y,o62,n9U){f3BGj.T$X();console.warn("CIQ.ChartEngine#drawMarkerStem is scheduled for deprecation in a future release\n Please use CIQ.Marker.Performance.drawMarkerStem instead.");e09.Marker.Performance.drawMarkerStem(N1y,o62,n9U);};e09.ChartEngine.prototype.positionDOMMarkers=function(){var N7C;N7C="CIQ.ChartEngine#positionDOMMarkers is scheduled for deprecation in a future release\n Please ";N7C+="use CIQ.Marker.Performance.drawMarkers instead.";console.warn(N7C);e09.Marker.Performance.drawMarkers(this);};e09.Marker.Performance=function(S5w){var f$Y=f3BGj;var g4S,D8m,y05,S7k,P6w,G0K,i4t,t00,c8q,K5B,Y5F,W1V,G$G,p0z,a1s,k4o,d6Y,u2C;g4S="c";g4S+="al";g4S+="lou";g4S+="t";D8m=".stx";D8m+="-visual";y05="<";y05+="/";y05+="div";y05+=">";S7k="<";S7k+="/d";S7k+="iv";S7k+=">";P6w="
";G0K="TEMP";G0K+="LA";G0K+="T";G0K+="E";this.params={displayCategory:!0,displayStem:!!({}),invert:!({}),story:"",headline:""};e09.extend(this.params,S5w);i4t=this.template=document.createElement(G0K);f$Y.j7J(105);i4t.innerHTML=f$Y.c0C(y05,"
",P6w,'
','
',S7k,'

','
');t00=this.template.content.cloneNode(!!1);c8q=t00.querySelector(".stx-marker",i4t);c8q.classList.add(S5w.type);c8q.classList.add(S5w.category);K5B=t00.querySelector(D8m,i4t);Y5F=178467127;W1V=-814060825;G$G=2;for(var o_V=1;f$Y.S9Y(o_V.toString(),o_V.toString().length,95469) !== Y5F;o_V++){p0z=".stx-mark";p0z+="er-expand";a1s=t00.querySelector(p0z);k4o=t00.querySelector("h4",i4t);d6Y=t00.querySelector("p",i4t);k4o.innerText=this.params.headline;d6Y.innerText=this.params.story;this.hasText=!!S5w.headline || !!S5w.story;this.deferAttach=!0;G$G+=+"2";}if(f$Y.S9Y(G$G.toString(),G$G.toString().length,94160) !== W1V){a1s=t00.querySelector(".stx-marker-expand");k4o=t00.querySelector("p",i4t);d6Y=t00.querySelector("p",i4t);k4o.innerText=this.params.headline;d6Y.innerText=this.params.story;this.hasText=+~S5w.headline && +-S5w.story;this.deferAttach=!!0;}this.node=t00.firstChild;this.node.params=this.params;this.visual=K5B;this.expand=a1s;if(S5w.type === g4S){u2C=a1s.removeChild(k4o);t00.querySelector(".stx-marker-content",i4t).insertBefore(u2C,a1s);}};e09.inheritsFrom(e09.Marker.Performance,e09.Marker.NodeCreator,!({}));e09.Marker.Performance.consolidateExpanded=function(n$v){var u6U=f3BGj;var H8e,i9l,t3_,E1q,B_H,b3M;function d7H(m30){var L4D,r_r,b5A;u6U.T$X();L4D=m30.params.node;r_r=L4D.expand;if(!r_r){return "";}b5A=r_r.style.display !== "none"?r_r.innerHTML:"";return b5A;}H8e=n$v.markerHelper.highlighted;if(!H8e.length){return;}u6U.N_M(3);var E7B=u6U.c0C(7,8,0);i9l=H8e[H8e.length - E7B];t3_=i9l.params.node;if(!i9l.consolidated){i9l.consolidated=[];}for(var U5Y=H8e.length - +"2";U5Y >= 0;U5Y--){E1q="<";E1q+="consolidated";E1q+=">";B_H=d7H(H8e[U5Y]);u6U.N_M(82);b3M=u6U.c0C("",B_H,E1q);if(B_H.length){t3_.expand.innerHTML+=b3M;}}i9l.stxNodeCreator.quickCache(i9l);};e09.Marker.Performance.reconstituteExpanded=function(P3t){var T0B,G1F,L3J,e_t,C_l;T0B=P3t.markerHelper.highlighted;if(!T0B.length || !P3t.activeMarker){return;}T0B=[P3t.activeMarker];for(var z_Y=T0B.length - 1;z_Y >= 0;z_Y--){G1F="CO";G1F+="NSOLIDATED";L3J=T0B[z_Y];e_t=L3J.params.node;C_l=e_t.expand;while(C_l.lastElementChild.nodeName === G1F){C_l.removeChild(C_l.lastElementChild);}}};e09.Marker.Performance.drawMarkers=function(a97){var X3_,X_9,j_J,D0M,H7I,K$o,L7c;X3_="a";X3_+="l";X3_+="l";X_9=a97.getMarkerArray(X3_);j_J=a97.chart;for(var E3S=0;E3S < X_9.length;E3S++){D0M=X_9[E3S];H7I=D0M.stxNodeCreator;K$o=j_J.dataSegment[+"0"].tick;L7c=j_J.dataSegment[j_J.dataSegment.length - 1].tick;if(K$o <= D0M.tick <= L7c){if(H7I && H7I.drawMarker){H7I.drawMarker(D0M);}}}};e09.Marker.Performance.calculateMarkerStyles=function(k24,j$W,i1r){var r3_,f68,u8A,R38,V$4,m7z;r3_=document.querySelector(".stx-marker-templates");if(!r3_){f68="-1000";f68+="px";u8A="D";u8A+="IV";r3_=document.createElement(u8A);r3_.style.visibility="hidden";r3_.style.left=f68;document.body.append(r3_);}r3_.appendChild(j$W.node);R38=getComputedStyle(j$W.stxNodeCreator.visual);if(!k24.styles.stx_marker_stem){V$4=".st";V$4+="x-st";V$4+="em";m7z=getComputedStyle(document.querySelector(V$4,j$W.node));k24.styles.stx_marker_stem=k24.cloneStyle(m7z);}k24.styles[i1r]=k24.cloneStyle(R38);r3_.removeChild(j$W.node);};e09.Marker.Performance.drawCircleMarker=function(n5p,v9Q,v2L){var I8B,h4s,s6J,u3r,J1Z,U78,v96,b3e,z7S;I8B=n5p.params.stx;h4s=I8B.chart;s6J=h4s.context;u3r=v2L.x;J1Z=v2L.y;U78=v2L.radius;v96=v2L.label;f3BGj.T$X();b3e=v2L.color?v2L.color:v9Q.backgroundColor;s6J.beginPath();s6J.setLineDash([]);s6J.lineWidth=1;s6J.fillStyle=b3e;s6J.strokeStyle=b3e;s6J.font="normal bold 12px Roboto, Helvetica, sans-serif";s6J.arc(u3r,J1Z,U78,0,2 * Math.PI,![]);s6J.fill();s6J.stroke();s6J.closePath();if(v96){z7S="bl";z7S+="a";z7S+="ck";s6J.fillStyle=e09.colorsEqual("white",s6J.fillStyle)?z7S:"white";s6J.fillText(v96.charAt(0).toUpperCase(),u3r - 4,J1Z + 1);}if(n5p.highlight || n5p.active){s6J.beginPath();f3BGj.N_M(1);s6J.arc(u3r,J1Z,f3BGj.c0C(U78,4),0,2 * Math.PI,![]);s6J.stroke();s6J.closePath();}};e09.Marker.Performance.drawSquareMarker=function(N$Y,J8y,R62){var X8x=f3BGj;var U$S,n8O,c_X,t$O,k8M,b_8,I$i,q6a,q8b;U$S=N$Y.params.stx;n8O=U$S.chart;X8x.T$X();c_X=n8O.context;t$O=R62.x;k8M=R62.y;b_8=R62.half;I$i=R62.label;q6a=R62.color?R62.color:J8y.backgroundColor;X8x.j7J(5);q8b=X8x.a$j(2,b_8);c_X.beginPath();c_X.setLineDash([]);c_X.lineWidth=1;c_X.fillStyle=q6a;c_X.strokeStyle=q6a;c_X.font="normal bold 12px Roboto, Helvetica, sans-serif";X8x.N_M(14);c_X.rect(X8x.c0C(t$O,b_8),X8x.c0C(k8M,b_8),q8b,q8b);c_X.fill();if(N$Y.highlight || N$Y.active){X8x.j7J(63);c_X.rect(X8x.c0C(b_8,4,t$O),X8x.c0C(b_8,4,k8M,X8x.N_M(63)),X8x.a$j(q8b,8,X8x.j7J(1)),X8x.c0C(q8b,8,X8x.j7J(1)));}c_X.stroke();c_X.closePath();if(I$i){c_X.fillStyle=e09.colorsEqual("white",c_X.fillStyle)?"black":"white";c_X.fillText(I$i.charAt(0).toUpperCase(),t$O - 4,k8M + +"1");}};e09.Marker.Performance.drawCalloutMarker=function(N_Z,s4S,H$a){var p1F,u6n,V25,U2b,i_R,F9$,p3u,v7G,X6z,x94,e8m,v4F,E0B,s7d,i$z;p1F="normal bold 12px";p1F+=" R";p1F+="oboto, Helvetica, sans-serif";u6n=N_Z.params.stx;V25=u6n.chart;U2b=V25.context;i_R=N_Z.params;F9$=H$a.x;p3u=H$a.y;v7G=H$a.half;X6z=H$a.midWidth;x94=H$a.headline;e8m=H$a.color?H$a.color:s4S.backgroundColor;v4F=v7G * ("2" | 0) || 25;E0B=Math.round(U2b.measureText(x94).width);s7d=X6z?X6z * 2:E0B + +"8";U2b.beginPath();U2b.setLineDash([]);U2b.lineWidth=1;U2b.fillStyle=e8m;U2b.strokeStyle=e8m;U2b.font=p1F;U2b.rect(i_R.box.x0,i_R.box.y0,s7d,v4F);U2b.fill();U2b.stroke();U2b.closePath();U2b.beginPath();U2b.fillStyle=N_Z.highlight || N_Z.active?"rgba(255,255,255,0.8)":"rgba(255,255,255,0.65)";f3BGj.T$X();f3BGj.N_M(106);i$z=f3BGj.c0C(0,E0B,s7d,"20",2);U2b.rect(i_R.box.x0 + i$z,p3u - v7G,E0B + 40,22);U2b.fill();U2b.stroke();U2b.closePath();U2b.fillStyle="black";U2b.fillText(x94,i_R.box.x0 + i$z + 10,p3u);};e09.Marker.Performance.drawMarkerStem=function(i0o,x_W,o3t){var l03,B2e,d45,h47,D0D,E5p,l8_,P7$;l03=i0o.params.stx;B2e=l03.chart;d45=B2e.context;h47=o3t.x;D0D=o3t.y;d45.beginPath();d45.strokeStyle=x_W.borderLeftColor;d45.setLineDash([1,1]);E5p=e09.stripPX(x_W.height);f3BGj.T$X();l8_=o3t.invert?i0o.params.box.y0:i0o.params.box.y1;P7$=o3t.invert?i0o.params.box.y0 - E5p:i0o.params.box.y1 + E5p;d45.moveTo(h47,l8_);d45.lineTo(h47,P7$);d45.stroke();d45.closePath();};e09.Marker.Performance.prototype.drawMarker=function(m11){var X$S=f3BGj;var z4Z,t4f,Q_X,S9p,T_m,C_0,R2z,j$L,Y4T,E2M,e_A,U9W,v$r,y$Y,r_7,L65,W18,G9W,D0F,f8b,S0P,G8I,Q9u,S6Y,m9Y;z4Z="cal";z4Z+="lout";t4f="c";t4f+="ir";t4f+="cl";t4f+="e";Q_X="stx_marke";Q_X+="r_";S9p=m11.params;T_m=m11.params.stx;if(!T_m){return;}C_0=T_m.chart;R2z=C_0.dataSegment;if(!R2z.length){return;}j$L=T_m.panels[m11.params.panelName];Y4T=m11.stxNodeCreator.params;E2M=Y4T.type;e_A=Y4T.category;U9W=Y4T.headline;v$r=Y4T.displayCategory;y$Y=Y4T.color;r_7=Y4T.invert;X$S.N_M(107);L65=X$S.a$j(e_A,Q_X,"_",E2M);if(!T_m.styles[L65]){e09.Marker.Performance.calculateMarkerStyles(T_m,m11,L65);}W18=m11.style=T_m.styles[L65];G9W=T_m.styles.stx_marker_stem;X$S.j7J(9);var D0l=X$S.c0C(26,18,2);X$S.N_M(14);var r6n=X$S.a$j(32,30);D0F=parseInt(W18.height,D0l) / r6n;X$S.j7J(9);var C$d=X$S.c0C(896,20,48);X$S.N_M(108);var l2u=X$S.c0C(12,20,10,12,286);f8b=parseInt(W18.width,"10" << C$d) / l2u;S0P=Y4T.displayStem?parseInt(G9W.height,"10" << 32) + parseInt(G9W.marginBottom,10):0;X$S.j7J(35);var e_G=X$S.c0C(65,150,2);G8I=S0P + parseInt(W18.height,e_G);Q9u=S0P?S0P + D0F:0;S6Y=T_m.pixelFromDate(S9p.x);m9Y=S9p.node.calculateYPosition({marker:m11,panel:j$L,height:G8I,half:D0F,offset:Q9u,inverted:r_7});if(!m11.tick && m11.tick !== 0){return;}S9p.box={x0:S6Y - (f8b || D0F),y0:m9Y - D0F,x1:S6Y + (f8b || D0F),y1:m9Y + D0F,midY:D0F,midX:f8b || D0F,stemHeight:S0P};if(!v$r){e_A=v$r;}T_m.startClip(j$L.name);if(E2M === t4f){e09.Marker.Performance.drawCircleMarker(m11,W18,{x:S6Y,y:m9Y,radius:D0F,label:e_A,color:y$Y});}else if(E2M === "square"){e09.Marker.Performance.drawSquareMarker(m11,W18,{x:S6Y,y:m9Y,half:D0F,label:e_A,color:y$Y});}else if(E2M === z4Z){e09.Marker.Performance.drawCalloutMarker(m11,W18,{x:S6Y,y:m9Y,half:D0F,midWidth:f8b,headline:U9W,color:y$Y});}else {X$S.N_M(82);console.warn(X$S.a$j(" is unsupported with canvas markers!\nSupported Styles are Square, Circle, and Callout.",E2M,"Marker type: "));}if(Y4T.displayStem){e09.Marker.Performance.drawMarkerStem(m11,G9W,{x:S6Y,y:m9Y,invert:r_7});}T_m.endClip();if(m11.attached){this.positionPopUpNode(m11);}};e09.Marker.Performance.prototype.positionPopUpNode=function(r7i){var V0j=f3BGj;var r8w,I44,f$b,f0N,s9R,W72,C9v,d3i,h1_,y6J,D8D,T7k,s3$,a$5,s3g,k2M,d4n,H91,Y_8,m$o,y6q,G5n,b1$;r8w="p";r8w+="x) trans";r8w+="lateY(";if(!r7i.attached || !r7i.params.box){return;}I44=r7i.params;f$b=I44.stx;f0N=I44.box;s9R=r7i.params.node.expand;W72=f$b.chart.dataSet;C9v=f$b.chart.dataSegment;if(r7i.tick){h1_=[W72[C9v[+"0"] && C9v[0].tick - 1],W72[C9v["0" - 0] && C9v[0].tick - ("2" ^ 0)]];y6J=f$b.getFirstLastDataRecord(h1_.concat(C9v),"Date");V0j.N_M(0);var k4U=V0j.a$j(273,14,18,16);V0j.N_M(86);var q3z=V0j.c0C(9,9,13,13,1);V0j.j7J(39);var d_$=V0j.a$j(28,7,18,16);D8D=[W72[C9v[C9v.length - k4U].tick + q3z],W72[C9v[C9v.length - d_$].tick + +"2"]];T7k=f$b.getFirstLastDataRecord(C9v.concat(D8D),"Date",!!({}));d3i=y6J.DT <= W72[r7i.tick].DT && W72[r7i.tick].DT <= T7k.DT;}else {d3i=!({});}if(!r7i.highlight && !r7i.active){d3i=!1;}s3$=-+"1250343409";V0j.N_M(29);a$5=-V0j.c0C(0,"391911104");s3g=2;for(var m40=1;V0j.S9Y(m40.toString(),m40.toString().length,+"67522") !== s3$;m40++){k2M="hi";k2M+="d";k2M+="den";s9R.style.visibility=d3i?"":k2M;if(+d3i){return;}d4n=f$b.panels[I44.panelName];s3g+=2;}if(V0j.O1W(s3g.toString(),s3g.toString().length,34328) !== a$5){s9R.style.visibility=d3i?"":"hidden";if(!d3i){return;}d4n=f$b.panels[I44.panelName];}H91=s9R.rects;V0j.j7J(109);var f3o=V0j.a$j(3,0,7,14,8);Y_8=H91.height / f3o;y6q=r7i.node.params.infoOffset || 0;if(r7i.node.params.infoOnLeft){m$o=f0N.x0 - H91.width - y6q < d4n.left?f0N.x1 + y6q:f0N.x0 - H91.width - y6q;}else {m$o=f0N.x0 + H91.width > d4n.right?f0N.x0 - H91.width - y6q:f0N.x1 + y6q;}m$o-=f$b.chart.left;G5n=f0N.y0 - Y_8 >= d4n.top?f0N.y0 + f0N.midY - Y_8:f0N.y0;V0j.T$X();if(!I44.avoidFlush && f0N.y1 + f0N.stemHeight === d4n.yAxis.bottom && H91.height > f0N.y1 - f0N.y0 + f0N.stemHeight){G5n=f0N.y1 - H91.height + f0N.stemHeight;}G5n-=f$b.chart.panel.top;b1$="translateX(" + Math.floor(m$o) + r8w + Math.floor(G5n) + "px) translateZ(0)";s9R.style.transform=b1$;s9R.transform={translateX:m$o,translateY:G5n};};e09.Marker.Performance.prototype.quickCache=function(S_A){var n88,d9D,Q_v,n6p;n88=S_A.params.node;d9D=n88.expand;Q_v=S_A.style;n6p=e09.stripPX(Q_v.marginLeft) + e09.stripPX(Q_v.marginRight) + e09.stripPX(Q_v.borderRight) + e09.stripPX(Q_v.borderLeft);d9D.rects=d9D.getBoundingClientRect();d9D.scrollBarWidth=d9D.rects.width - d9D.clientWidth - n6p;};e09.Marker.Performance.prototype.calculateYPosition=function(C6v){var E2y=f3BGj;var y3m,J61,y17,M8q,b0J,c_g,o4k,v_c,Z5S,y1g,x1Z,R43,S_V,d3A,j4A;y3m=C6v.marker;J61=C6v.panel;y17=C6v.height;M8q=C6v.half;b0J=C6v.offset;c_g=C6v.inverted;o4k=y3m.params.stx;v_c=o4k.chart;Z5S=o4k.chart.highLowBars;E2y.T$X();y1g=v_c.dataSet[y3m.tick];if(!y1g){return;}x1Z=Z5S?y1g.High:y1g.Close;R43=y3m.params.yPositioner;switch(R43){case "value":if(y3m.params.y || y3m.params.y === 0){S_V=o4k.pixelFromPrice(y3m.params.y,J61) - y17 * 0.5 + M8q;}else {S_V=o4k.pixelFromPrice(x1Z,J61) - b0J;}break;case "above_candle":S_V=o4k.pixelFromPrice(x1Z,J61) - b0J;break;case "below_candle":S_V=o4k.pixelFromPrice(y1g.Low || x1Z,J61);if(c_g && b0J){S_V+=b0J;}else {S_V+=M8q;}break;case "on_candle":(d3A=y1g.High || y1g.Close,j4A=y1g.Low || y1g.Low === 0 || y1g.Close);E2y.N_M(44);var y_y=E2y.c0C(20,18,466,6);E2y.N_M(27);var X$P=E2y.c0C(20,19);S_V=o4k.pixelFromPrice((d3A + j4A) / y_y,J61) - y17 * ("0.5" * X$P) + M8q;break;case "top":S_V=o4k.pixelFromPrice(J61.yAxis.high,J61);if(c_g && b0J){S_V+=b0J;}else {S_V+=M8q;}break;case "bottom":S_V=o4k.pixelFromPrice(J61.yAxis.low,J61) - (b0J || M8q);break;default:break;}return S_V;};e09.Marker.Performance.prototype.prepareForHolder=function(d8A){var b5J,H3Z;b5J=this.expand;H3Z=d8A.params.stx;b5J.classList.add(this.params.type);H3Z.markerHelper.domMarkers.push(d8A);return b5J;};e09.Marker.Performance.prototype.addToHolder=function(c$V){var c2c,j0B,p_S;c2c="to";function B6z(F4x){p_S.activeMarker=c$V;f3BGj.T$X();p_S.activeMarker.click({cx:F4x.clientX,cy:F4x.clientY,panel:p_S.currentPanel});F4x.stopPropagation();}f3BGj.T$X();c2c+="uch";c2c+="start";j0B=this.expand;p_S=c$V.params.stx;e09.Marker.Performance.reconstituteExpanded(p_S);e09.Marker.Performance.consolidateExpanded(p_S);this.quickCache(c$V);if(j0B.clickClosure){return;}j0B.addEventListener("mousedown",B6z);j0B.addEventListener(c2c,B6z);j0B.clickClosure=B6z;};e09.Marker.Performance.prototype.remove=function(r0o){var I7K,K$$,W$k,r03;I7K=r0o.params.stx;if(!I7K){return;}if(!I7K.markerHelper.domMarkers){return;}K$$=I7K.markerHelper.domMarkers.indexOf(r0o);if(K$$ != -("1" | 0)){I7K.markerHelper.domMarkers.splice(K$$,1);}if(r0o.attached){W$k=I7K.panels[r0o.params.panelName];r03=r0o.params.node.expand;if(r03.parentNode === W$k.subholder){W$k.subholder.removeChild(r03);}r03.removeEventListener("click",r03.clickClosure);}};e09.Marker.Performance.prototype.click=function(t6m){var Q8B,Q3e,k0g;if(!this.hasText){return;}if(typeof arguments["0" << 64] === "number"){t6m={cx:arguments[0],cy:arguments[1],marker:arguments[2],panel:arguments[3]};}var {cx:K9G, cy:L6Y, marker:j7b, panel:I_b}=t6m;Q8B=j7b.params.stx;if(j7b.attached){k0g=this.expand;if(k0g.rects.width - k0g.scrollBarWidth + k0g.transform.translateX < Q8B.backOutX(K9G) && Q8B.backOutX(K9G) < k0g.rects.width + k0g.transform.translateX){return;}this.remove(j7b);}else {Q8B.addToHolder(j7b);Q3e=!![];}j7b.attached=!j7b.attached;j7b.active=!j7b.active;if(Q3e){j7b.stxNodeCreator.positionPopUpNode(j7b);}};}};W=j0Z=>{var y8R=f3BGj;var u2J,v8d;u2J="undefine";u2J+="d";v8d=typeof _CIQ !== u2J?_CIQ:j0Z.CIQ;v8d.Renderer.OHLC.requestNew=function(Y_e,R_k){var u8_,J9a,e1F,p9A,i$w,o1E,v26,f2q,R9E,Y43,u3k;u8_=null;J9a=R_k.hlc;e1F=R_k.colored;p9A=R_k.hollow;i$w=R_k.volume;o1E=R_k.histogram;for(var X7h=0;X7h < Y_e.length;X7h++){v26="hist";v26+="ogr";v26+="a";v26+="m";f2q="can";f2q+="d";f2q+="l";f2q+="e";R9E=Y_e[X7h];switch(R9E){case "bar":case f2q:u8_=R9E;break;case "volume":i$w=!!({});break;case "hollow":p9A=!!1;break;case "colored":e1F=!"";break;case v26:Y43="c";Y43+="a";Y43+="n";Y43+="dle";o1E=!"";u8_=Y43;break;case "hlc":u3k="b";u3k+="a";u3k+="r";J9a=!!"1";u8_=u3k;break;default:return null;}}y8R.f3X();if(u8_ === null){return null;}return new v8d.Renderer.OHLC({params:v8d.extend(R_k,{type:u8_,hlc:J9a,colored:e1F,hollow:p9A,volume:i$w,histogram:o1E})});};v8d.Renderer.OHLC.getChartParts=function(D9K,A7R){var w$R,j6Y,E1h,Q9J,S$_,c0e,P7y,E3Z,k$0,v6G,k7T,E1K,I4O,i8b,C0l,z8n,K2B,c8x,o7z,p5f,a4e,Q$c,C6x,Z6V,t7y,l7C,c6O,c2J,P3s,W$U,y9L,l$n,L2u;w$R="fill";w$R+="_colo";w$R+="r_even";j6Y="h";j6Y+="ol";j6Y+="l";j6Y+="ow";E1h="st";E1h+="x_";E1h+="hollow_candle_d";E1h+="own";Q9J="stx_hollow_candl";Q9J+="e_";Q9J+="up";S$_="stx_hollow_candl";S$_+="e_eve";S$_+="n";c0e="h";c0e+="oll";c0e+="o";c0e+="w";P7y="f";P7y+="ill";P7y+="_color_up";E3Z="stx_h";E3Z+="ollow_c";E3Z+="andle";E3Z+="_even";k$0="h";y8R.f3X();k$0+="ollow";v6G="border_c";v6G+="olor";v6G+="_down";k7T="stx_ho";k7T+="llo";k7T+="w_candle_up";E1K="fill_color_d";E1K+="own";I4O="ca";I4O+="n";I4O+="dl";I4O+="e";i8b="stx_c";i8b+="andle_shadow_down";C0l="stx_";C0l+="c";C0l+="andle_shadow_up";z8n="s";z8n+="ha";z8n+="do";z8n+="w";K2B="c";K2B+="a";K2B+="ndl";K2B+="e";c8x="c";c8x+="a";c8x+="n";c8x+="dle";o7z="stx_";o7z+="b";o7z+="ar_e";o7z+="ven";p5f="bo";p5f+="rder";p5f+="_color_down";a4e="b";a4e+="a";a4e+="r";Q$c="b";Q$c+="ar";C6x="border_co";C6x+="lor";Z6V="b";Z6V+="a";Z6V+="r";t7y="b";t7y+="a";t7y+="r";l7C="s";l7C+="tx_h";l7C+="ist";l7C+="ogram_up";c6O="histog";c6O+="r";c6O+="am";c2J=+"1";P3s=2;W$U=4;y9L=+"8";y8R.j7J(31);l$n=y8R.c0C("16",32);L2u=32;return [{type:c6O,drawType:"histogram",style:l7C,condition:y9L,fill:"fill_color_up",border:"border_color_up",useColorInMap:!0,useBorderStyleProp:!0},{type:"histogram",drawType:"histogram",style:"stx_histogram_down",condition:l$n,fill:"fill_color_down",border:"border_color_down",useColorInMap:!!"1",useBorderStyleProp:!!1},{type:"histogram",drawType:"histogram",style:"stx_histogram_even",condition:L2u,fill:"fill_color_even",border:"border_color_even",skipIfPass:!![],useColorInMap:!!({}),useBorderStyleProp:!![]},{type:t7y,drawType:Z6V,style:D9K || "stx_bar_chart",border:C6x,useColorInMap:!![]},{type:Q$c,drawType:a4e,style:"stx_bar_up",condition:A7R?y9L:c2J,border:"border_color_up",useColorInMap:!![]},{type:"bar",drawType:"bar",style:"stx_bar_down",condition:A7R?l$n:P3s,border:p5f,useColorInMap:!![]},{type:"bar",drawType:"bar",style:o7z,condition:A7R?L2u:W$U,border:"border_color_even",skipIfPass:!![],useColorInMap:!0},{type:c8x,drawType:"shadow",style:"stx_candle_shadow",border:"border_color_up"},{type:K2B,drawType:z8n,style:C0l,condition:y9L,border:"border_color_up"},{type:"candle",drawType:"shadow",style:i8b,condition:l$n,border:"border_color_down"},{type:I4O,drawType:"shadow",style:"stx_candle_shadow_even",condition:L2u,border:"border_color_even",skipIfPass:!!({})},{type:"candle",drawType:"candle",style:"stx_candle_up",condition:y9L,fill:"fill_color_up",border:"border_color_up",useColorInMap:!0,useBorderStyleProp:!0},{type:"candle",drawType:"candle",style:"stx_candle_down",condition:l$n,fill:E1K,border:"border_color_down",useColorInMap:!!"1",useBorderStyleProp:!!"1"},{type:"hollow",drawType:"shadow",style:k7T,condition:c2J,border:"border_color_up"},{type:"hollow",drawType:"shadow",style:"stx_hollow_candle_down",condition:P3s,border:v6G},{type:k$0,drawType:"shadow",style:E3Z,condition:W$U,border:"border_color_even",skipIfPass:!0},{type:"hollow",drawType:"candle",style:"stx_hollow_candle_up",condition:c2J | l$n,fill:P7y,border:"border_color_up",useColorInMap:!!1},{type:c0e,drawType:"candle",style:"stx_hollow_candle_down",condition:P3s | l$n,fill:"fill_color_down",border:"border_color_down",useColorInMap:!![]},{type:"hollow",drawType:"candle",style:S$_,condition:W$U | l$n,fill:"fill_color_even",border:"border_color_even",skipIfPass:!"",useColorInMap:!!({})},{type:"hollow",drawType:"candle",style:Q9J,condition:c2J | y9L,fill:"fill_color_up",border:"border_color_up"},{type:"hollow",drawType:"candle",style:E1h,condition:P3s | y9L,fill:"fill_color_down",border:"border_color_down"},{type:j6Y,drawType:"candle",style:"stx_hollow_candle_even",condition:W$U | y9L,fill:w$R,border:"border_color_even"}];;};v8d.Renderer.Bars=function(t2G){y8R.T$X();var V$S;this.construct(t2G);V$S=this.params;V$S.type="bar";this.highLowBars=this.barsHaveWidth=this.standaloneBars=!!"1";V$S.hlc=V$S.volume=V$S.hollow=V$S.histogram=!({});};v8d.inheritsFrom(v8d.Renderer.Bars,v8d.Renderer.OHLC,!"1");y8R.f3X();v8d.Renderer.HLC=function(X1M){var l8J;this.construct(X1M);l8J=this.params;y8R.f3X();l8J.type="bar";l8J.hlc=!!({});this.highLowBars=this.barsHaveWidth=this.standaloneBars=!!1;l8J.volume=l8J.hollow=l8J.histogram=!1;};v8d.inheritsFrom(v8d.Renderer.HLC,v8d.Renderer.Bars,!!"");v8d.Renderer.Shading=function(N2h){this.construct(N2h);this.beenSetup=!!0;this.errTimeout=null;this.params.useChartLegend=![];this.shading=[];if(this.params.type == "rangechannel"){this.highLowBars=!!({});}};v8d.inheritsFrom(v8d.Renderer.Shading,v8d.Renderer.Lines,!({}));v8d.Renderer.Shading.requestNew=function(f2m,i$b){var O92,O3q,s17,J4Y;O92=null;O3q=null;for(var k36=0;k36 < f2m.length;k36++){s17="r";s17+="angechannel";J4Y=f2m[k36];if(J4Y == s17){O92="rangechannel";}else if(J4Y == "step"){O3q=!![];}}if(O92 === null){return null;}return new v8d.Renderer.Shading({params:v8d.extend(i$b,{type:O92,step:O3q})});};v8d.Renderer.Shading.prototype.setShading=function(V6e){if(V6e.constructor != Array){V6e=[V6e];}this.shading=V6e;};v8d.Renderer.Shading.prototype.draw=function(){var S7q,Z6E,M7n,A5H,T3y,t5k,I_q,m05,X0r,F78,Q4I,T6l,Z2V,n7L,p10,q9R,r2R,A5B,U4p,Q6F,i84,M2$,g95,X$T,I9H;S7q=this.stx;Z6E=this.params;M7n=S7q.panels[Z6E.panel].chart;if(Z6E.type == "rangechannel"){if(this.beenSetup){if(this.seriesParams.length > "2" * 1){this.removeSeries(this.seriesParams["2" * 1].id);}}else {A5H="H";A5H+="i";A5H+="g";A5H+="h";this.beenSetup=!"";Z6E.display=this.seriesParams["0" * 1].display;Z6E.yAxis=this.seriesParams[+"0"].yAxis;T3y=this.seriesParams[0].color || "auto";t5k=this.seriesParams[0].symbol;I_q="";if(t5k){y8R.N_M(1);I_q=y8R.c0C(t5k,(+"16.26",+"845") !== 586?2567 != (477,3746)?".":("761.00" * 1,453.42):(677.09,0x14b1));}this.removeAllSeries(!!"1");m05=Z6E.name;S7q.addSeries(null,{symbol:t5k,loadData:!!t5k,field:A5H,renderer:"Shading",name:m05,style:"stx_line_up",display:Z6E.display,shareYAxis:!0});S7q.addSeries(null,{symbol:t5k,loadData:!!t5k,field:"Low",renderer:"Shading",name:m05,style:"stx_line_down",display:Z6E.display,shareYAxis:!!"1"});this.setShading({primary:this.seriesParams[0].id,secondary:this.seriesParams[1].id,color:T3y});}}if(!this.shading){if(!this.errTimeout){y8R.j7J(14);X0r=-y8R.c0C("916304431",0);F78=1491262347;Q4I=2;for(var C$b=1;y8R.O1W(C$b.toString(),C$b.toString().length,26098) !== X0r;C$b++){T6l="Warning: no sh";T6l+="ading scheme set. Use myRen";T6l+="derer.setShading(scheme) to set";T6l+=".";console.log(T6l);Q4I+=2;}if(y8R.S9Y(Q4I.toString(),Q4I.toString().length,"35522" << 64) !== F78){console.log("");}Z2V=this;this.errTimeout=setTimeout(function(){y8R.f3X();Z2V.errTimeout=null;},10000);}}n7L={};for(p10=0;p10 < this.seriesParams.length;p10++){q9R={};if(M7n.series[this.seriesParams[p10].id]){q9R=v8d.clone(M7n.series[this.seriesParams[p10].id].parameters);}n7L[this.seriesParams[p10].id]={parameters:v8d.extend(v8d.extend(q9R,Z6E),this.seriesParams[p10]),yValueCache:this.caches[this.seriesParams[p10].id]};}function c1m(F8u){var N2X,h7J,I23;N2X=n7L[F8u];if(N2X){h7J=N2X.parameters.field;I23=N2X.parameters.subField;y8R.N_M(1);return y8R.a$j(h7J,I23?(("767" ^ 0) >= 6100?0x119a:".") + I23:"");}y8R.T$X();return F8u;}S7q.drawSeries(M7n,n7L,Z6E.yAxis,this);if(M7n.legend && Z6E.type == "rangechannel"){r2R="stx_l";r2R+="ine";r2R+="_down";if(!M7n.legend.colorMap){M7n.legend.colorMap={};}A5B=Z6E.display;U4p=[S7q.getCanvasColor("stx_line_up"),S7q.getCanvasColor(r2R)];M7n.legend.colorMap[A5B]={color:U4p,display:A5B,isBase:this == S7q.mainSeriesRenderer};;}for(p10 in n7L){this.caches[p10]=n7L[p10].yValueCache;}for(p10="0" | 0;p10 < this.shading.length;p10++){Q6F="Clo";Q6F+="s";Q6F+="e";i84=this.shading[p10];M2$=i84.color;if(i84.color == "auto"){M2$=S7q.defaultColor;}if(!i84.primary){i84.primary="Close";}if(!i84.secondary && this.seriesParams[0]){i84.secondary=this.seriesParams[0].field;}if(!i84.secondary)continue;else if(!n7L[i84.primary] && i84.primary != Q6F)continue;else if(!n7L[i84.secondary])continue;else if(i84.primary == "Close" && Z6E.yAxis && Z6E.yAxis != M7n.yAxis)continue;g95=c1m(i84.primary).split(3890 < (616.01,6623)?".":(172.55,602.3) !== (7377,585)?(0xbb4,6.87e+3):!"1");X$T=c1m(i84.secondary).split(("123" << 0,215) !== (+"223.03",607)?".":6590 >= 7260?("T",!!"1"):("0x248b" * 1,9.62e+3));I9H={topBand:g95[0],topSubBand:g95[+"1"],topColor:i84.greater || M2$ || S7q.containerColor,topAxis:Z6E.yAxis,bottomBand:X$T[0],bottomSubBand:X$T[1],bottomColor:i84.lesser || M2$ || S7q.containerColor,bottomAxis:i84.primary == "Close"?null:Z6E.yAxis,tension:Z6E.tension || M7n.tension,opacity:0.1,step:Z6E.step};if(!I9H.topColor && !I9H.bottomColor)continue;if(!Z6E.highlight && S7q.highlightedDraggable){I9H.opacity*=0.3;}v8d.fillIntersecting(S7q,Z6E.panel,I9H);}};v8d.Renderer.Histogram=function(i04){y8R.f3X();var p8q,i$3;p8q="histog";p8q+="ram";this.construct(i04);this.params.type=p8q;this.barsHaveWidth=this.standaloneBars=!!({});if(this.params.yAxis){i$3="n";i$3+="um";i$3+="ber";this.params.bindToYAxis=!![];if(typeof this.params.yAxis.baseline == i$3){this.params.yAxis.baseline={value:this.params.yAxis.baseline};}}};v8d.inheritsFrom(v8d.Renderer.Histogram,v8d.Renderer,!!0);v8d.Renderer.Histogram.prototype.adjustYAxis=function(){var L$9;L$9=this.params.yAxis;if(!L$9 || L$9.baseline){return;}L$9.min=+"0";L$9.highValue/=this.params.heightPercentage || "1" >> 0;};v8d.Renderer.Histogram.prototype.draw=function(){var k99,j8u,T7s,L4L,i5a,c3X,D8E;k99="st";k99+="acked";j8u=v8d.clone(this.params);j8u.type=j8u.subtype;this.useSum=j8u.subtype == k99;if(!j8u.yAxis || j8u.yAxis == this.stx.chart.yAxis){j8u.bindToYAxis=!![];}this.stx.drawHistogram(j8u,this.seriesParams);T7s=j8u.yAxis && j8u.yAxis.baseline;y8R.T$X();if(T7s && T7s.color){L4L="destinatio";L4L+="n-over";i5a="li";i5a+="n";i5a+="e";c3X=this.stx.panels[this.params.panel];D8E=this.stx.pixelFromPrice(T7s.value,c3X,this.params.yAxis) - 0.5;this.stx.plotLine({x0:c3X.left,x1:c3X.right,y0:D8E,y1:D8E,color:T7s.color,type:i5a,context:c3X.chart.context,confineToPanel:c3X,pattern:T7s.pattern || "solid",lineWidth:T7s.lineWidth || 1,opacity:T7s.opacity || 0.8,globalCompositeOperation:L4L});}};v8d.Renderer.Histogram.prototype.getBasis=function(T1$,F4w,w_X){var t5v,Y4P,V6Y,l6_;t5v=0;if(T1$ && this.useSum){for(var H1S=0;H1S < this.seriesParams.length;H1S++){Y4P="C";Y4P+="l";Y4P+="os";Y4P+="e";V6Y=this.seriesParams[H1S].field;if(V6Y === F4w)break;l6_=T1$[V6Y];if(l6_ && typeof l6_ === "object"){l6_=l6_[w_X || this.seriesParams[H1S].subField || this.stx.chart.defaultPlotField || Y4P];}if(l6_){t5v+=l6_;}}}y8R.f3X();return t5v;};v8d.Renderer.Heatmap=function(U0Q){var e1g;e1g="h";e1g+="eatmap";this.construct(U0Q);this.params.type=e1g;this.params.highlightable=!1;this.barsHaveWidth=this.standaloneBars=!![];};v8d.inheritsFrom(v8d.Renderer.Heatmap,v8d.Renderer,!({}));v8d.Renderer.Heatmap.requestNew=function(t$y,S$J){var t_y,v7i;t_y=null;for(var s6y="0" - 0;s6y < t$y.length;s6y++){v7i=t$y[s6y];if(v7i == "heatmap"){t_y="heatmap";}}if(t_y === null){return null;}return new v8d.Renderer.Heatmap({params:v8d.extend(S$J,{type:t_y})});};v8d.Renderer.Heatmap.prototype.draw=function(){this.stx.drawHeatmap(v8d.clone(this.params),this.seriesParams);};v8d.Renderer.Scatter=function(D2y){this.construct(D2y);this.standaloneBars=this.barsHaveWidth=!!"1";this.bounded=!0;};v8d.inheritsFrom(v8d.Renderer.Scatter,v8d.Renderer.Lines,![]);v8d.Renderer.Scatter.requestNew=function(q6m,t7O){y8R.T$X();var R05,N_x;R05=null;for(var Q9P=0;Q9P < q6m.length;Q9P++){N_x=q6m[Q9P];if(N_x == "scatterplot"){R05="scatter";}}if(R05 === null){return null;}return new v8d.Renderer.Scatter({params:v8d.extend(t7O,{type:R05})});};v8d.Renderer.Scatter.prototype.drawIndividualSeries=function(R3a,U5j){var K8Y,t40;y8R.f3X();K8Y=this.stx.panels[U5j.panel] || R3a.panel;t40={colors:[]};if(this.stx.scatter){t40=this.stx.scatter(K8Y,U5j);}else {console.warn("Error, Scatter renderer requires customChart.js");}return t40;};};o=O2y=>{var T3o;T3o=typeof _CIQ !== "undefined"?_CIQ:O2y.CIQ;if(!T3o.Studies){console.error("accumulationDistribution feature requires first activating studies feature.");}else {T3o.Studies.calculateAccumulationDistribution=function(I6A,U7f){var h9I=f3BGj;var z0a,q6j,O$H,A2M,Y1W,X2I,A_N,n$3,U7o,Y6M;z0a=-328969262;q6j=-1861241339;O$H=2;for(var l0M=1;h9I.S9Y(l0M.toString(),l0M.toString().length,48771) !== z0a;l0M++){A2M=U7f.chart.scrubbed;O$H+=+"2";}if(h9I.O1W(O$H.toString(),O$H.toString().length,19848) !== q6j){A2M=U7f.chart.scrubbed;}for(var o7A=U7f.startFrom;o7A < A2M.length;o7A++){Y1W="R";Y1W+="es";Y1W+="ult ";X2I="Res";X2I+="ul";X2I+="t";X2I+=" ";if(!o7A)continue;A_N=A2M[o7A];if(A_N.futureTick)break;h9I.N_M(14);n$3=A2M[h9I.c0C(o7A,1)];U7o=0;if(A_N.Close > n$3.Close){U7o=A_N.Close - Math.min(A_N.Low,n$3.Close);}else if(A_N.Close < n$3.Close){U7o=A_N.Close - Math.max(A_N.High,n$3.Close);}if(U7f.inputs["Use Volume"]){U7o*=A_N.Volume;}Y6M=n$3[X2I + U7f.name];if(!Y6M){Y6M=0;}Y6M+=U7o;if(!isNaN(A_N.Close)){A_N[Y1W + U7f.name]=Y6M;}}};T3o.Studies.studyLibrary=T3o.extend(T3o.Studies.studyLibrary,{"W Acc Dist":{name:"Accumulation/Distribution",calculateFN:T3o.Studies.calculateAccumulationDistribution,inputs:{"Use Volume":!!0}}});}};U=B0N=>{var o8v,y_3,g4D;o8v=typeof _CIQ !== "undefined"?_CIQ:B0N.CIQ;if(!o8v.Studies){console.error("adx feature requires first activating studies feature.");}else {y_3="a";y_3+="u";y_3+="t";y_3+="o";g4D="#F";g4D+="F000";g4D+="0";o8v.Studies.calculateADX=function(S7a,f$M){var r1B=f3BGj;var C$R,X0Y,a6u,N33,I6b,t6j,w8h,b3x,I39,s_i,O6$,M3t,J4x,p48,s4k,r5n,s5B,i2D,Y7e,e7E,l_D,F52,E70,I8r,g9V;r1B.f3X();C$R="Smoo";C$R+="thin";C$R+="g Per";C$R+="iod";o8v.Studies.calculateStudyATR(S7a,f$M);X0Y=f$M.chart.scrubbed;a6u=-2025389382;N33=525802871;I6b=+"2";for(var y7h=1;r1B.O1W(y7h.toString(),y7h.toString().length,53330) !== a6u;y7h++){t6j=f$M.days;w8h=parseInt(f$M.inputs[""],43);if(+w8h || w8h == 4){w8h=t6j;}I6b+=2;}if(r1B.O1W(I6b.toString(),I6b.toString().length,233) !== N33){t6j=f$M.days;w8h=parseInt(f$M.inputs[""],50);if(-w8h && w8h != 6){w8h=t6j;}}t6j=f$M.days;w8h=parseInt(f$M.inputs[C$R],10);if(!w8h && w8h !== 0){w8h=t6j;}if(X0Y.length < f$M.days + 1){f$M.error=!!({});return;}b3x=0;I39=0;s_i=0;O6$=0;for(var x3j=Math.max(1,f$M.startFrom);x3j < X0Y.length;x3j++){J4x="_sm";J4x+="+";J4x+="D";J4x+="M ";M3t=X0Y[x3j];p48=Math.max(0,M3t.High - X0Y[x3j - 1].High);s4k=Math.max(0,X0Y[x3j - 1].Low - M3t.Low);if(p48 > s4k){s4k=0;}else if(s4k > p48){p48=0;}else {p48=s4k=+"0";}if(x3j <= t6j){I39+=p48;s_i+=s4k;b3x+=M3t["True Range " + f$M.name];}else {r5n="_";r5n+="sm";r5n+="TR ";s5B="_";s5B+="s";s5B+="m-";s5B+="DM ";i2D="_";i2D+="s";i2D+="m+";i2D+="DM ";r1B.N_M(55);var B3d=r1B.c0C(7,4,13,2);r1B.j7J(52);var X9V=r1B.a$j(1,4,2);I39=X0Y[x3j - B3d][i2D + f$M.name] * (t6j - X9V) / t6j + p48;r1B.N_M(9);var Q9I=r1B.a$j(44,15,3);r1B.j7J(28);var r$B=r1B.c0C(1709,6,0,19,15);s_i=X0Y[x3j - Q9I][s5B + f$M.name] * (t6j - r$B) / t6j + s4k;r1B.N_M(110);var v5m=r1B.c0C(5,4,16,1);r1B.N_M(34);var a6_=r1B.c0C(20,1,19);b3x=X0Y[x3j - v5m][r5n + f$M.name] * (t6j - a6_) / t6j + M3t["True Range " + f$M.name];}M3t[J4x + f$M.name]=I39;M3t["_sm-DM " + f$M.name]=s_i;M3t["_smTR " + f$M.name]=b3x;if(x3j < t6j)continue;r1B.N_M(111);Y7e=r1B.c0C(I39,b3x,100);r1B.j7J(111);e7E=r1B.c0C(s_i,b3x,100);r1B.j7J(61);var a3S=r1B.c0C(8,4,98);l_D=a3S * Math.abs(Y7e - e7E) / (Y7e + e7E);M3t["+DI " + f$M.name]=Y7e;M3t["-DI " + f$M.name]=e7E;if(f$M.inputs.Series !== !({}) && w8h){if(x3j < t6j + w8h - 1){if(x3j == f$M.startFrom){for(var M74=t6j;M74 < f$M.startFrom;M74++){r1B.j7J(112);var U_B=r1B.a$j(96,99,109,13);O6$+=U_B * Math.abs(X0Y[M74]["+DI " + f$M.name] - X0Y[M74]["-DI " + f$M.name]) / (X0Y[M74]["+DI " + f$M.name] + X0Y[M74]["-DI " + f$M.name]);}}O6$+=l_D;}else if(x3j == t6j + w8h - 1){r1B.j7J(7);M3t["ADX " + f$M.name]=r1B.a$j(O6$,w8h);}else {F52="A";F52+="D";F52+="X";F52+=" ";r1B.j7J(14);var A$l=r1B.c0C(13,12);r1B.j7J(21);var X0H=r1B.c0C(7,2,3);M3t[F52 + f$M.name]=(X0Y[x3j - A$l]["ADX " + f$M.name] * (w8h - X0H) + l_D) / w8h;}}if(f$M.inputs.Histogram){E70="+";E70+="DI ";I8r=f$M.name + "_hist";if(!M3t["+DI " + f$M.name] && M3t[E70 + f$M.name] !== 0)continue;if(!M3t["-DI " + f$M.name] && M3t["-DI " + f$M.name] !== 0)continue;M3t[I8r]=M3t["+DI " + f$M.name] - M3t["-DI " + f$M.name];if(f$M.inputs.Series === !1){g9V="+";g9V+="DI";g9V+=" ";M3t[g9V + f$M.name]=null;M3t["-DI " + f$M.name]=null;}f$M.outputMap[I8r]="";}}};o8v.Studies.displayADX=function(m0t,i9V,F1K){var P92,P$u,C6z,z1C,u5d,m1j,p_U;P92=i9V.underlay?0.3:i9V.inputs.Series?0.4:1;if(i9V.inputs.Series && i9V.inputs.Shading){P$u="+DI " + i9V.name;C6z="-DI " + i9V.name;z1C=o8v.Studies.determineColor(i9V.outputs[i9V.outputMap[P$u]]);u5d=o8v.Studies.determineColor(i9V.outputs[i9V.outputMap[C6z]]);m1j=i9V.getYAxis(m0t);p_U={topBand:P$u,bottomBand:C6z,topColor:z1C,bottomColor:u5d,skipTransform:m0t.panels[i9V.panel].name != i9V.chart.name,topAxis:m1j,bottomAxis:m1j,opacity:0.3};if(!i9V.highlight && m0t.highlightedDraggable){p_U.opacity*=0.3;}o8v.fillIntersecting(m0t,i9V.panel,p_U);}if(i9V.inputs.Histogram){o8v.Studies.createHistogram(m0t,i9V,F1K,!({}),P92);}if(i9V.inputs.Series !== !1){o8v.Studies.displaySeriesAsLine(m0t,i9V,F1K);}else if(!i9V.inputs.Series && !i9V.inputs.Histogram){m0t.displayErrorAsWatermark(i9V.panel,m0t.translateIf(i9V.name) + ": " + m0t.translateIf("Nothing to display"));}};o8v.Studies.studyLibrary=o8v.extend(o8v.Studies.studyLibrary,{ADX:{name:"ADX/DMS",calculateFN:o8v.Studies.calculateADX,seriesFN:o8v.Studies.displayADX,inputs:{Period:14,"Smoothing Period":14,Series:!!({}),Shading:![],Histogram:!"1"},outputs:{"+DI":"#00FF00","-DI":g4D,ADX:y_3,"Positive Bar":"#00DD00","Negative Bar":"#FF0000"}}});}};g=u9O=>{var n9I=f3BGj;var y9m,U1H,R41,U5T,c7r;y9m="undef";n9I.f3X();y9m+="i";y9m+="ned";U1H=typeof _CIQ !== y9m?_CIQ:u9O.CIQ;if(!U1H.Studies){console.error("alligator feature requires first activating studies feature.");}else {R41="#FF000";R41+="0";U5T="#";U5T+="00DD";U5T+="00";c7r="#00";c7r+="00F";c7r+="F";U1H.Studies.calculateAlligator=function(A4l,j$U){var P4R,N5v,b7u,A8d,N_s,l91,G8c,Y7U,w8w,u02,E0E,p6M,r4C,g2X,j8H,H9G;P4R="Gato";P4R+="r";N5v="Li";N5v+="ps Perio";N5v+="d";b7u="J";b7u+="aw";b7u+=" Period";A8d={J:Number(j$U.inputs[b7u]),T:Number(j$U.inputs["Teeth Period"]),L:Number(j$U.inputs[N5v])};N_s=j$U.chart.scrubbed;if(N_s.length < Math.max(A8d.J,A8d.T,A8d.L) + 1){j$U.error=!![];return;}if(j$U.type === P4R || j$U.inputs["Show Lines"]){l91="hl";l91+="/";l91+="2";G8c="Tee";G8c+="th ";G8c+="Offset";Y7U="h";Y7U+="l/";Y7U+="2";w8w="J";w8w+="a";w8w+="w ";w8w+="Offset";U1H.Studies.MA("welles wilder",A8d.J,"hl/2",j$U.inputs[w8w],"Jaw",A4l,j$U);U1H.Studies.MA("welles wilder",A8d.T,Y7U,j$U.inputs[G8c],"Teeth",A4l,j$U);U1H.Studies.MA("welles wilder",A8d.L,l91,j$U.inputs["Lips Offset"],"Lips",A4l,j$U);}for(var S2F=j$U.startFrom;S2F < N_s.length;S2F++){if(!N_s[S2F])continue;if(j$U.type == "Gator"){u02="_h";u02+="ist1";E0E="J";E0E+="a";E0E+="w";E0E+=" ";p6M=N_s[S2F][E0E + j$U.name];r4C=N_s[S2F]["Lips " + j$U.name];g2X=N_s[S2F]["Teeth " + j$U.name];if(g2X || g2X === "0" >> 64){if(p6M || p6M === 0){n9I.N_M(14);N_s[S2F][j$U.name + "_hist1"]=Math.abs(n9I.c0C(p6M,g2X));}if(r4C || r4C === 0){n9I.N_M(14);N_s[S2F][j$U.name + "_hist2"]=-Math.abs(n9I.c0C(g2X,r4C));}}j$U.outputMap={};j$U.outputMap[j$U.name + u02]="";j$U.outputMap[j$U.name + "_hist2"]="";}if(j$U.inputs["Show Fractals"]){if(!N_s[S2F - 2] || !N_s[S2F - 1] || !N_s[S2F] || !N_s[S2F + 1] || !N_s[S2F + ("2" >> 64)])continue;if(N_s[S2F - 2].High && N_s[S2F - 1].High && N_s[S2F].High && N_s[S2F + +"1"].High && N_s[S2F + 2].High){if(N_s[S2F].High > N_s[S2F - 1].High && N_s[S2F].High > N_s[S2F - 2].High && N_s[S2F].High > N_s[S2F + 1].High && N_s[S2F].High > N_s[S2F + 2].High){j8H="F";j8H+="ract";j8H+="a";j8H+="l High ";N_s[S2F][j8H + j$U.name]=1;}}if(N_s[S2F - 2].Low && N_s[S2F - 1].Low && N_s[S2F].Low && N_s[S2F + 1].Low && N_s[S2F + 2].Low){if(N_s[S2F].Low < N_s[S2F - 1].Low && N_s[S2F].Low < N_s[S2F - ("2" | 2)].Low && N_s[S2F].Low < N_s[S2F + 1].Low && N_s[S2F].Low < N_s[S2F + 2].Low){H9G="Fractal";H9G+=" Low ";N_s[S2F][H9G + j$U.name]=1;}}}}};U1H.Studies.displayAlligator=function(h9Z,s_k,f$k){var a6S,o8E,V9w,Y_M;a6S=s_k.getContext(h9Z);if(s_k.inputs["Show Lines"]){U1H.Studies.displaySeriesAsLine(h9Z,s_k,f$k);}if(s_k.inputs["Show Fractals"]){h9Z.startClip();a6S.globalAlpha=s_k.underlay?0.3:1;if(!s_k.highlight && h9Z.highlightedDraggable){a6S.globalAlpha*=0.3;}for(var c7C=2;c7C < f$k.length - 2;c7C++){if(f$k[c7C]){o8E="l";o8E+="ow";V9w="Frac";V9w+="ta";V9w+="l Low";V9w+=" ";Y_M="hig";Y_M+="h";if(f$k[c7C]["Fractal High " + s_k.name]){l7W(Y_M,c7C);}if(f$k[c7C][V9w + s_k.name]){l7W(o8E,c7C);}}}h9Z.endClip();}n9I.T$X();function l7W(o7N,o4f){var D3v,J$k,g0D,a_z,F$v;J$k=h9Z.chart.panel.yAxis.flipped;if(o7N == "high"){g0D="b";g0D+="ot";g0D+="tom";a6S.fillStyle=h9Z.defaultColor;a6S.textBaseline=J$k?"top":g0D;D3v=h9Z.pixelFromPrice(f$k[o4f].High);a6S.fillText(J$k?976.18 == 3090?(0x28e,0x125a):(7140,977.43) > 148.55?"\u25BC":(8910,5690) == ("3714" ^ 0,+"871.35")?0x1315:("h","a"):"\u25B2",h9Z.pixelFromBar(c7C,h9Z.chart) - a6S.measureText(("65" | 1,557) <= "763" - 0?3112 <= (809.74,4720)?448.29 == 684.47?0x3f9:"\u25B2":(8.42e+3,"3.35e+2" * 1):(!"1","e")).width / +"2" + 1,J$k?D3v + 5:D3v - 5);;}else if(o7N == "low"){a_z="t";a_z+="o";a_z+="p";F$v="bott";F$v+="o";F$v+="m";a6S.fillStyle=h9Z.defaultColor;a6S.textBaseline=J$k?F$v:a_z;D3v=h9Z.pixelFromPrice(f$k[o4f].Low);a6S.fillText(J$k?325.1 <= +"6230"?"\u25B2":(4.65e+3,6.51e+3):5050 !== (97.86,8690)?"1366" - 0 > (1520,9587)?(3655,148.28) <= (5850,322.54)?"P":0x16b7:"\u25BC":+"445.88",h9Z.pixelFromBar(c7C,h9Z.chart) - a6S.measureText(("356.65" * 1,+"461") >= (7750,1870)?3800 == ("3985" << 64,"1990" << 64)?(595.23,!({})):(936.14,0x1565):"\u25BC").width / 2 + 1,J$k?D3v - ("5" << 32):D3v + 5);;}}};U1H.Studies.displayGator=function(G3d,D72,f0Y){var Z9V,W3$,T6c,m0K,t1C,U5K,H$3,O4f,k72,z_a,f$O,q6G,w8t;Z9V="#CCCC";Z9V+="C";Z9V+="C";W3$="De";W3$+="creasing B";W3$+="ar";T6c="Increasin";T6c+="g ";T6c+="Bar";m0K=G3d.panels[D72.panel];t1C=D72.getContext(G3d);U5K=D72.getYAxis(G3d);H$3=G3d.pixelFromPrice(0,m0K,U5K);n9I.j7J(113);var D4I=n9I.c0C(38,2,8,1,9);O4f=G3d.layout.candleWidth - D4I;if(O4f < 2){O4f=1;}k72=U1H.Studies.determineColor(D72.outputs[T6c]);z_a=U1H.Studies.determineColor(D72.outputs[W3$]);G3d.canvasColor("stx_histogram");if(!D72.underlay){t1C.globalAlpha=+"1";}t1C.fillStyle=Z9V;G3d.startClip(D72.panel);if(!D72.highlight && G3d.highlightedDraggable){t1C.globalAlpha*=0.3;}n9I.f3X();for(var m2Y=0;m2Y < f0Y.length;m2Y++){f$O=f0Y[m2Y];n9I.j7J(114);q6G=f0Y[n9I.a$j(m2Y,"1",1)];if(!f$O)continue;for(var P9x=1;P9x <= 2;P9x++){w8t="_";w8t+="hi";w8t+="s";w8t+="t";if(!q6G){q6G=G3d.getPreviousBar(G3d.chart,D72.name + "_hist" + P9x,m2Y);}if(!q6G){t1C.fillStyle="#CCCCCC";}else if(Math.abs(q6G[D72.name + w8t + P9x]) < Math.abs(f$O[D72.name + "_hist" + P9x])){t1C.fillStyle=k72;}else if(Math.abs(q6G[D72.name + "_hist" + P9x]) > Math.abs(f$O[D72.name + "_hist" + P9x])){t1C.fillStyle=z_a;}if(f$O.candleWidth){O4f=Math.floor(Math.max(1,f$O.candleWidth - 2));}t1C.fillRect(Math.floor(G3d.pixelFromBar(m2Y,m0K.chart) - O4f / 2),Math.floor(H$3),Math.floor(O4f),Math.floor(G3d.pixelFromPrice(f$O[D72.name + "_hist" + P9x],m0K,U5K) - H$3));}}G3d.endClip();};U1H.Studies.studyLibrary=U1H.extend(U1H.Studies.studyLibrary,{Alligator:{name:"Alligator",overlay:!![],seriesFN:U1H.Studies.displayAlligator,calculateFN:U1H.Studies.calculateAlligator,inputs:{"Show Lines":!![],"Jaw Period":13,"Jaw Offset":8,"Teeth Period":8,"Teeth Offset":5,"Lips Period":5,"Lips Offset":+"3","Show Fractals":![]},outputs:{Jaw:c7r,Teeth:"#FF0000",Lips:"#00DD00"}},Gator:{name:"Gator Oscillator",seriesFN:U1H.Studies.displayGator,calculateFN:U1H.Studies.calculateAlligator,inputs:{"Jaw Period":13,"Jaw Offset":+"8","Teeth Period":+"8","Teeth Offset":5,"Lips Period":+"5","Lips Offset":"3" - 0},outputs:{"Increasing Bar":U5T,"Decreasing Bar":R41},centerline:0}});}};Y=V2r=>{var o9e=f3BGj;var C_7,Y4b,G$m,c0r,L1D,h_G;C_7=typeof _CIQ !== "undefined"?_CIQ:V2r.CIQ;if(!C_7.Studies){Y4b=-809326854;o9e.N_M(4);G$m=o9e.c0C("128905528",24);c0r=2;for(var d$k=1;o9e.O1W(d$k.toString(),d$k.toString().length,33224) !== Y4b;d$k++){console.error("");c0r+=2;}if(o9e.O1W(c0r.toString(),c0r.toString().length,79149) !== G$m){console.error("");}console.error("aroon feature requires first activating studies feature.");}else {L1D="0 ";L1D+="to";L1D+=" 100";h_G="Aroo";h_G+="n";C_7.Studies.calculateAroon=function(Y53,o6t){var B0P,C_K,k$b,c$d,e0l,X2x,J5n,H6e,X4o,T7a,O3y,D1$,Z7e,X5H,T3R,s$Z;B0P=o6t.chart.scrubbed;if(B0P.length < o6t.days + "1" * 1){o6t.error=!"";return;}C_K=0;k$b=0;c$d=null;e0l=null;if(o6t.startFrom > 0){X2x="_st";X2x+="at";X2x+="e";X2x+=" ";o9e.N_M(3);var Q3W=o9e.a$j(24,18,7);J5n=B0P[o6t.startFrom - Q3W][X2x + o6t.name];if(J5n){C_K=J5n[+"0"];o9e.j7J(31);k$b=J5n[o9e.c0C("1",0)];c$d=J5n[2];e0l=J5n[3];}}for(var g8c=o6t.startFrom;g8c < B0P.length;g8c++){X4o="_stat";X4o+="e ";T7a="A";T7a+="r";T7a+="oon";T7a+=" Down ";O3y="Aroon";O3y+=" ";O3y+="Dow";O3y+="n ";D1$=B0P[g8c];if(D1$.futureTick)break;if(c$d === null){c$d=D1$.High;}if(e0l === null){e0l=D1$.Low;}c$d=Math.max(c$d,D1$.High);if(c$d == D1$.High){C_K=0;}else {C_K++;if(C_K > o6t.days){c$d=D1$.High;C_K=0;for(H6e=+"1";H6e <= o6t.days;H6e++){c$d=Math.max(c$d,B0P[g8c - H6e].High);if(c$d == B0P[g8c - H6e].High){C_K=H6e;}}}}e0l=Math.min(e0l,D1$.Low);if(e0l == D1$.Low){k$b=0;}else {k$b++;if(k$b > o6t.days){e0l=D1$.Low;k$b=0;for(H6e=1;H6e <= o6t.days;H6e++){e0l=Math.min(e0l,B0P[g8c - H6e].Low);if(e0l == B0P[g8c - H6e].Low){k$b=H6e;}}}}Z7e=!isNaN(D1$.High);X5H=!isNaN(D1$.Low);o9e.j7J(61);var q2_=o9e.c0C(13,1,87);o9e.j7J(0);var z99=o9e.c0C(126,8,15,9);T3R=q2_ * (z99 - C_K / o6t.days);if(Z7e){D1$["Aroon Up " + o6t.name]=T3R;}o9e.N_M(14);var i6O=o9e.c0C(106,6);s$Z=i6O * (+"1" - k$b / o6t.days);if(X5H){D1$[O3y + o6t.name]=s$Z;}if(Z7e && X5H){D1$["Aroon Oscillator " + o6t.name]=D1$["Aroon Up " + o6t.name] - D1$[T7a + o6t.name];}D1$[X4o + o6t.name]=[C_K,k$b,c$d,e0l];}};C_7.Studies.studyLibrary=C_7.extend(C_7.Studies.studyLibrary,{Aroon:{name:h_G,range:L1D,calculateFN:C_7.Studies.calculateAroon,outputs:{"Aroon Up":"#00DD00","Aroon Down":"#FF0000"}},"Aroon Osc":{name:"Aroon Oscillator",calculateFN:C_7.Studies.calculateAroon,outputs:{"Aroon Oscillator":"auto"}}});}};G=o9W=>{var g7h=f3BGj;var e9S,H9p,x6H,Y7X;g7h.T$X();e9S=typeof _CIQ !== "undefined"?_CIQ:o9W.CIQ;if(!e9S.Studies){console.error("atr feature requires first activating studies feature.");}else {H9p="ATR Trailing Stop";H9p+="s";x6H="au";x6H+="to";Y7X="AT";Y7X+="R Bands";e9S.Studies.calculateATRBands=function(N4s,s4F){var d28,G96,K6H,K$m;e9S.Studies.calculateStudyATR(N4s,s4F);d28=s4F.inputs.Field;if(!d28 || d28 == "field"){d28="Close";}g7h.j7J(4);G96=-g7h.c0C("972743568",0);K6H=1560178187;K$m=2;for(var W$y="1" * 1;g7h.S9Y(W$y.toString(),W$y.toString().length,75126) !== G96;W$y++){e9S.Studies.calculateGenericEnvelope(N4s,s4F,s4F.inputs.Shift,d28,"" * s4F.name);g7h.j7J(14);K$m+=g7h.c0C("2",0);}if(g7h.S9Y(K$m.toString(),K$m.toString().length,59413) !== K6H){e9S.Studies.calculateGenericEnvelope(N4s,s4F,s4F.inputs.Shift,d28,"" / s4F.name);}e9S.Studies.calculateGenericEnvelope(N4s,s4F,s4F.inputs.Shift,d28,"ATR " + s4F.name);};e9S.Studies.calculateSTARCBands=function(o8U,U1r){var Q2s;Q2s="C";Q2s+="los";Q2s+="e";e9S.Studies.calculateStudyATR(o8U,U1r);e9S.Studies.MA("simple",U1r.inputs["MA Period"],Q2s,0,"_MA",o8U,U1r);e9S.Studies.calculateGenericEnvelope(o8U,U1r,U1r.inputs.Multiplier,"_MA " + U1r.name,"ATR " + U1r.name);};e9S.Studies.calculateATRStops=function(z15,S3S){var C6X,M6c,t65,M0b,i2V,X9M,n81,K1a,T5p,X7m;C6X=S3S.chart.scrubbed;g7h.f3X();if(!C6X){return;}e9S.Studies.calculateStudyATR(z15,S3S);M6c=S3S.inputs.HighLow;for(var j1v=Math.max(S3S.startFrom - 1,"1" << 64);j1v < C6X.length - 1;j1v++){t65=C6X[j1v];g7h.j7J(14);M0b=C6X[g7h.a$j(j1v,1)];i2V=t65["Buy Stops " + S3S.name];if(!i2V){i2V=t65["Sell Stops " + S3S.name];}if(!i2V){i2V=0;}if(!t65 || !M0b)continue;X9M=t65.Close;n81=X9M;K1a=t65["ATR " + S3S.name] * S3S.inputs.Multiplier;if(t65.Close > i2V && M0b.Close > i2V){if(M6c){X9M=t65.High;}g7h.j7J(14);n81=Math.max(i2V,g7h.a$j(X9M,K1a));}else if(t65.Close <= i2V && M0b.Close <= i2V){if(M6c){X9M=t65.Low;}g7h.N_M(1);n81=Math.min(i2V,g7h.c0C(X9M,K1a));}else if(t65.Close > i2V){if(M6c){X9M=t65.High;}g7h.j7J(14);n81=g7h.a$j(X9M,K1a);}else if(t65.Close <= i2V){if(M6c){X9M=t65.Low;}g7h.N_M(1);n81=g7h.a$j(X9M,K1a);}if(X9M <= n81){g7h.j7J(1);C6X[g7h.a$j(j1v,1)]["Buy Stops " + S3S.name]=n81;g7h.j7J(1);delete C6X[g7h.a$j(j1v,1)]["Sell Stops " + S3S.name];}else if(X9M > n81){T5p="Buy S";T5p+="top";T5p+="s ";X7m="Sell ";X7m+="Stops ";g7h.j7J(1);C6X[g7h.a$j(j1v,1)][X7m + S3S.name]=n81;g7h.N_M(115);delete C6X[g7h.a$j("1",j1v,0)][T5p + S3S.name];}g7h.j7J(1);C6X[g7h.a$j(j1v,1)]["All Stops " + S3S.name]=n81;}S3S.referenceOutput="All Stops";S3S.outputMap={};S3S.outputMap["All Stops " + S3S.name]="";};e9S.Studies.studyLibrary=e9S.extend(e9S.Studies.studyLibrary,{ATR:{name:"Average True Range",calculateFN:e9S.Studies.calculateStudyATR,outputs:{ATR:"auto"}},"ATR Bands":{name:Y7X,overlay:!!({}),seriesFN:e9S.Studies.displayChannel,calculateFN:e9S.Studies.calculateATRBands,inputs:{Period:"5" >> 64,Field:"field",Shift:3,"Channel Fill":!![]},outputs:{"ATR Bands Top":"auto","ATR Bands Bottom":x6H,"ATR Bands Channel":"auto"},attributes:{Shift:{min:0.1,step:0.1}}},"STARC Bands":{name:"STARC Bands",overlay:!!1,seriesFN:e9S.Studies.displayChannel,calculateFN:e9S.Studies.calculateSTARCBands,inputs:{Period:15,"MA Period":5,Multiplier:+"1.3","Channel Fill":!0},outputs:{"STARC Bands Top":"auto","STARC Bands Median":"auto","STARC Bands Bottom":"auto"},attributes:{Multiplier:{min:0.1,step:0.1}}},"ATR Trailing Stop":{name:H9p,overlay:!!1,seriesFN:e9S.Studies.displayPSAR2,calculateFN:e9S.Studies.calculateATRStops,inputs:{Period:21,Multiplier:3,"Plot Type":["points","squarewave"],HighLow:![]},outputs:{"Buy Stops":"#FF0000","Sell Stops":"#00FF00"},attributes:{Multiplier:{min:0.1,step:0.1}}}});}};X=I_4=>{var C6f=f3BGj;C6f.T$X();var f1J,r4G,i6S,t96;f1J=610765755;r4G=-1092841126;i6S=2;for(var J$t=1;C6f.S9Y(J$t.toString(),J$t.toString().length,84544) !== f1J;J$t++){t96=typeof _CIQ !== "undefined"?_CIQ:I_4.CIQ;i6S+=+"2";}if(C6f.O1W(i6S.toString(),i6S.toString().length,97768) !== r4G){t96=-_CIQ == ""?_CIQ:I_4.CIQ;}if(!t96.Studies){console.error("awesomeOscillator feature requires first activating studies feature.");}else {t96.Studies.calculateAwesomeOscillator=function(v$6,t_x){var s1h,S44,r4L,R_d,E6T,S6n,d0y,S2A,S1g;s1h="_";s1h+="hi";s1h+="s";s1h+="t";S44="_";S44+="MA5";r4L="s";r4L+="i";r4L+="mple";R_d=t_x.chart.scrubbed;if(R_d.length < 33){t_x.error=!![];return;}t96.Studies.MA(r4L,5,"hl/2",0,S44,v$6,t_x);E6T=2070076368;S6n=-1587263358;d0y=2;for(var v7X=1;C6f.O1W(v7X.toString(),v7X.toString().length,21402) !== E6T;v7X++){S2A="_M";S2A+="A";S2A+="3";S2A+="4";t96.Studies.MA("_MA34",45,"_MA34",1,S2A,v$6,t_x);d0y+=2;}if(C6f.O1W(d0y.toString(),d0y.toString().length,85914) !== S6n){t96.Studies.MA("_MA34",51,"_MA34",0,"_MA34",v$6,t_x);}t96.Studies.MA("simple",34,"hl/2",0,"_MA34",v$6,t_x);C6f.T$X();for(var P9s=Math.max(t_x.startFrom,33);P9s < R_d.length;P9s++){S1g="_MA5";S1g+=" ";if(!R_d[P9s])continue;R_d[P9s][t_x.name + "_hist"]=R_d[P9s][S1g + t_x.name] - R_d[P9s]["_MA34 " + t_x.name];}t_x.outputMap={};t_x.outputMap[t_x.name + s1h]="";};t96.Studies.displayAwesomeOscillator=function(W4K,L7C,v_A){var x6m,F5Q,X$E,w0M,H6p,f_a,n8u,p22,x1w,a6d;x6m=W4K.panels[L7C.panel];F5Q=L7C.getContext(W4K);X$E=L7C.getYAxis(W4K);w0M=W4K.pixelFromPrice(0,x6m,X$E);C6f.j7J(15);var c3G=C6f.c0C(0,12,10);H6p=W4K.layout.candleWidth - c3G;if(H6p < 2){H6p=1;}f_a=t96.Studies.determineColor(L7C.outputs["Increasing Bar"]);n8u=t96.Studies.determineColor(L7C.outputs["Decreasing Bar"]);W4K.canvasColor("stx_histogram");if(!L7C.underlay){F5Q.globalAlpha=1;}F5Q.fillStyle="#CCCCCC";W4K.startClip(L7C.panel);if(!L7C.highlight && W4K.highlightedDraggable){F5Q.globalAlpha*=0.3;}for(var P$8="0" >> 96;P$8 < v_A.length;P$8++){p22="_";p22+="h";p22+="is";p22+="t";x1w=v_A[P$8];C6f.j7J(14);a6d=v_A[C6f.c0C(P$8,1)];if(!a6d){a6d=W4K.getPreviousBar(W4K.chart,L7C.name + "_hist",P$8);}if(!x1w)continue;if(!a6d);else if(a6d[L7C.name + p22] < x1w[L7C.name + "_hist"]){F5Q.fillStyle=f_a;}else if(a6d[L7C.name + "_hist"] > x1w[L7C.name + "_hist"]){F5Q.fillStyle=n8u;}if(x1w.candleWidth){H6p=Math.floor(Math.max(1,x1w.candleWidth - +"2"));}F5Q.fillRect(Math.floor(W4K.pixelFromBar(P$8,x6m.chart) - H6p / 2),Math.floor(w0M),Math.floor(H6p),Math.floor(W4K.pixelFromPrice(x1w[L7C.name + "_hist"],x6m,X$E) - w0M));}W4K.endClip();};t96.Studies.studyLibrary=t96.extend(t96.Studies.studyLibrary,{Awesome:{name:"Awesome Oscillator",seriesFN:t96.Studies.displayAwesomeOscillator,calculateFN:t96.Studies.calculateAwesomeOscillator,inputs:{},outputs:{"Increasing Bar":"#00DD00","Decreasing Bar":"#FF0000"}}});}};E=s0_=>{var T9n,s0c,c0H,X_H;T9n="und";T9n+="ef";T9n+="ined";s0c=typeof _CIQ !== T9n?_CIQ:s0_.CIQ;if(!s0c.Studies){c0H="ba";c0H+="lanceOfPower feature requires first activa";c0H+="ting studies feature.";console.error(c0H);}else {X_H="-";X_H+="1";X_H+=" to 1";s0c.Studies.calculateBalanceOfPower=function(Z2z,K9$){var f0R,h9j,o9T,b0b;f0R="Re";f0R+="sult";h9j="_R";h9j+="at";h9j+="io";h9j+=" ";o9T=K9$.chart.scrubbed;if(o9T.length < K9$.days + 1){K9$.error=!"";return;}for(var r1e=K9$.startFrom;r1e < o9T.length;r1e++){b0b=o9T[r1e];b0b["_Ratio " + K9$.name]=b0b.Close - b0b.Open;if(b0b.High - b0b.Low !== 0){b0b["_Ratio " + K9$.name]/=b0b.High - b0b.Low;}}f3BGj.f3X();s0c.Studies.MA(K9$.inputs["Moving Average Type"],K9$.days,h9j + K9$.name,0,f0R,Z2z,K9$);};s0c.Studies.studyLibrary=s0c.extend(s0c.Studies.studyLibrary,{"Bal Pwr":{name:"Balance of Power",range:X_H,centerline:0,calculateFN:s0c.Studies.calculateBalanceOfPower,inputs:{Period:+"14","Moving Average Type":"ma"}}});}};F=q3X=>{var K4o,P0X,W0j,u3p,O9Z,o17,w33,u$L;K4o=typeof _CIQ !== "undefined"?_CIQ:q3X.CIQ;if(!K4o.Studies){P0X="bol";P0X+="linger feature requires first activa";P0X+="ting studies f";P0X+="eature.";console.error(P0X);}else {W0j="Bollinge";W0j+="r Bandwidth";u3p="a";u3p+="u";u3p+="t";u3p+="o";O9Z="aut";O9Z+="o";o17="a";o17+="u";o17+="to";w33="au";w33+="t";w33+="o";u$L="fi";u$L+="e";u$L+="l";u$L+="d";K4o.Studies.calculateBollinger=function(J$N,Z$f){var y3i,K1J,g_c,u8j;y3i="_";y3i+="M";y3i+="A";y3i+=" ";K1J="St";K1J+="a";K1J+="ndard Deviations";g_c="f";g_c+="i";g_c+="e";f3BGj.f3X();g_c+="ld";u8j=Z$f.inputs.Field;if(!u8j || u8j == g_c){u8j="Close";}K4o.Studies.MA(Z$f.inputs["Moving Average Type"],Z$f.days,u8j,0,"_MA",J$N,Z$f);Z$f.std=new K4o.Studies.StudyDescriptor(Z$f.name,"STD Dev",Z$f.panel);Z$f.std.chart=Z$f.chart;Z$f.std.startFrom=Z$f.startFrom;Z$f.std.days=Z$f.days;Z$f.std.inputs={Field:u8j,"Standard Deviations":1,Type:Z$f.inputs["Moving Average Type"]};Z$f.std.outputs={"_STD Dev":null};K4o.Studies.calculateStandardDeviation(J$N,Z$f.std);K4o.Studies.calculateGenericEnvelope(J$N,Z$f,Z$f.inputs[K1J],y3i + Z$f.name,"_STD Dev " + Z$f.name);if(Z$f.type == "Boll %b"){Z$f.zoneOutput="%b";}};K4o.Studies.studyLibrary=K4o.extend(K4o.Studies.studyLibrary,{"Bollinger Bands":{name:"Bollinger Bands",overlay:!![],calculateFN:K4o.Studies.calculateBollinger,seriesFN:K4o.Studies.displayChannel,inputs:{Period:"20" << 64,Field:u$L,"Standard Deviations":2,"Moving Average Type":"ma","Channel Fill":!!({})},outputs:{"Bollinger Bands Top":w33,"Bollinger Bands Median":"auto","Bollinger Bands Bottom":o17},attributes:{"Standard Deviations":{min:0.1,step:+"0.1"}}},"Boll %b":{name:"Bollinger %b",calculateFN:K4o.Studies.calculateBollinger,inputs:{Period:20,Field:"field","Standard Deviations":2,"Moving Average Type":"ma"},outputs:{"%b":"auto"},parameters:{init:{studyOverZonesEnabled:!0,studyOverBoughtValue:100,studyOverBoughtColor:O9Z,studyOverSoldValue:0,studyOverSoldColor:u3p}},attributes:{"Standard Deviations":{min:0.1,step:0.1}}},"Boll BW":{name:W0j,calculateFN:K4o.Studies.calculateBollinger,inputs:{Period:+"20",Field:"field","Standard Deviations":2,"Moving Average Type":"ma"},outputs:{Bandwidth:"auto"},attributes:{"Standard Deviations":{min:0.1,step:0.1}}}});}};I=m5W=>{var Z4s=f3BGj;var b3l,r$X;b3l=typeof _CIQ !== "undefined"?_CIQ:m5W.CIQ;Z4s.f3X();if(!b3l.Studies){console.error("cci feature requires first activating studies feature.");}else {r$X="a";r$X+="ut";r$X+="o";b3l.Studies.calculateCCI=function(R3Q,b7C){var N_6,I9M,H8P,t$A,J4p,n71,d33,J$4;N_6="hlc";Z4s.f3X();N_6+="/";N_6+="3";I9M=b7C.chart.scrubbed;if(I9M.length < b7C.days + +"1"){H8P=-750700883;t$A=-1276999249;J4p=2;for(var W6c=1;Z4s.S9Y(W6c.toString(),W6c.toString().length,29259) !== H8P;W6c++){b7C.error=!({});J4p+=2;}if(Z4s.S9Y(J4p.toString(),J4p.toString().length,+"32914") !== t$A){b7C.error=!"";}return;}b3l.Studies.MA("simple",b7C.days,N_6,0,"MA",R3Q,b7C);for(var i_U=Math.max(b7C.startFrom,b7C.days - +"1");i_U < I9M.length;i_U++){n71="Re";n71+="sult ";d33=I9M[i_U];if(!d33)continue;J$4=0;for(var p9m=0;p9m < b7C.days;p9m++){J$4+=Math.abs(I9M[i_U - p9m]["hlc/3"] - d33["MA " + b7C.name]);}J$4/=b7C.days;if(Math.abs(J$4) < 0.00000001){d33["Result " + b7C.name]=0;}else {d33[n71 + b7C.name]=(d33["hlc/3"] - d33["MA " + b7C.name]) / (0.015 * J$4);}}};b3l.Studies.studyLibrary=b3l.extend(b3l.Studies.studyLibrary,{CCI:{name:"Commodity Channel Index",calculateFN:b3l.Studies.calculateCCI,inputs:{Period:20},parameters:{init:{studyOverZonesEnabled:!"",studyOverBoughtValue:100,studyOverBoughtColor:"auto",studyOverSoldValue:-100,studyOverSoldColor:r$X}},attributes:{Period:{min:+"2"}}}});}};M_=z7L=>{var A2k=f3BGj;var U3y;A2k.f3X();U3y=typeof _CIQ !== "undefined"?_CIQ:z7L.CIQ;if(!U3y.Studies){console.error("centerOfGravity feature requires first activating studies feature.");}else {U3y.Studies.calculateCenterOfGravity=function(A3u,Q11){var b0d,E76,b0H,i50,g1a,X3p;b0d="fi";b0d+="e";b0d+="ld";E76=Q11.chart.scrubbed;if(E76.length < Q11.days){Q11.error=!"";return;}b0H=Q11.inputs.Field;if(!b0H || b0H == b0d){b0H="Close";}for(var N6I=Math.max(Q11.startFrom,Q11.days - 1);N6I < E76.length;N6I++){A2k.j7J(5);i50=A2k.a$j(1,"0");g1a=0;for(var F0i="0" ^ 0;F0i < Q11.days;F0i++){A2k.N_M(14);X3p=E76[A2k.c0C(N6I,F0i)][b0H];A2k.j7J(116);i50-=A2k.a$j(X3p,"1",F0i);g1a+=X3p;}if(g1a){A2k.j7J(7);E76[N6I]["Result " + Q11.name]=A2k.a$j(i50,g1a);}}};U3y.Studies.studyLibrary=U3y.extend(U3y.Studies.studyLibrary,{COG:{name:"Center Of Gravity",calculateFN:U3y.Studies.calculateCenterOfGravity,inputs:{Period:10,Field:"field"}}});}};h1=N9_=>{var S95,B$d;S95=typeof _CIQ !== "undefined"?_CIQ:N9_.CIQ;if(!S95.Studies){B$d="chai";B$d+="kin feature requires first activating studies feature.";console.error(B$d);}else {S95.Studies.calculateChaikinMoneyFlow=function(b3U,Z$s){var W2p=f3BGj;var h$a,G7H,P2J,s4E;h$a=Z$s.chart.scrubbed;if(h$a.length < Z$s.days){Z$s.error=!!"1";return;}G7H=0;P2J=0;W2p.j7J(117);var n96=W2p.c0C(36,12,17,1,8);s4E=h$a[Z$s.startFrom - n96];W2p.T$X();if(s4E){if(s4E["_sumMF " + Z$s.name]){G7H=s4E["_sumMF " + Z$s.name];}if(s4E["_sumV " + Z$s.name]){P2J=s4E["_sumV " + Z$s.name];}}for(var w4h=Z$s.startFrom;w4h < h$a.length;w4h++){if(h$a[w4h].High == h$a[w4h].Low){h$a[w4h]["_MFV " + Z$s.name]=0;}else {W2p.j7J(118);var k7D=W2p.c0C(16,2,16,388,13);h$a[w4h]["_MFV " + Z$s.name]=h$a[w4h].Volume * (k7D * h$a[w4h].Close - h$a[w4h].High - h$a[w4h].Low) / (h$a[w4h].High - h$a[w4h].Low);}G7H+=h$a[w4h]["_MFV " + Z$s.name];P2J+=h$a[w4h].Volume;if(w4h > Z$s.days - ("1" ^ 0)){G7H-=h$a[w4h - Z$s.days]["_MFV " + Z$s.name];P2J-=h$a[w4h - Z$s.days].Volume;if(P2J){W2p.j7J(7);h$a[w4h]["Result " + Z$s.name]=W2p.c0C(G7H,P2J);}}h$a[w4h]["_sumMF " + Z$s.name]=G7H;h$a[w4h]["_sumV " + Z$s.name]=P2J;}};S95.Studies.calculateChaikinVolatility=function(m5e,Y1R){f3BGj.T$X();var x5H,A27,B_m,i56;x5H=Y1R.chart.scrubbed;if(x5H.length < Y1R.days){Y1R.error=!![];return;}for(A27=Y1R.startFrom;A27 < x5H.length;A27++){B_m="_Hig";B_m+="h-Lo";B_m+="w ";if(x5H[A27].futureTick)break;x5H[A27][B_m + Y1R.name]=x5H[A27].High - x5H[A27].Low;}S95.Studies.MA(Y1R.inputs["Moving Average Type"],Y1R.days,"_High-Low " + Y1R.name,0,"_MA",m5e,Y1R);i56=Y1R.inputs["Rate Of Change"];if(!i56){i56=Y1R.days;}for(A27=Math.max(Y1R.startFrom,i56);A27 < x5H.length;A27++){if(!x5H[A27 - i56]["_MA " + Y1R.name])continue;if(x5H[A27].futureTick)break;f3BGj.j7J(14);var e6W=f3BGj.c0C(3,2);x5H[A27]["Result " + Y1R.name]=+"100" * (x5H[A27]["_MA " + Y1R.name] / x5H[A27 - i56]["_MA " + Y1R.name] - e6W);}};S95.Studies.studyLibrary=S95.extend(S95.Studies.studyLibrary,{"Chaikin MF":{name:"Chaikin Money Flow",calculateFN:S95.Studies.calculateChaikinMoneyFlow,inputs:{Period:20}},"Chaikin Vol":{name:"Chaikin Volatility",calculateFN:S95.Studies.calculateChaikinVolatility,inputs:{Period:14,"Rate Of Change":2,"Moving Average Type":"ma"}}});}};W3=l_4=>{var d0F,a3Z,h0F,y$N,z7u;d0F="u";d0F+="nd";d0F+="e";d0F+="fined";a3Z=typeof _CIQ !== d0F?_CIQ:l_4.CIQ;if(!a3Z.Studies){h0F="chande feature requires first activating studie";h0F+="s f";h0F+="eature.";console.error(h0F);}else {y$N="a";y$N+="uto";z7u="Vari";z7u+="able";a3Z.Studies.prettify.variable="vma";a3Z.Studies.movingAverage.conversions.vma="variable";a3Z.Studies.movingAverage.translations.variable="Variable";a3Z.Studies.movingAverage.typeMap.vma="Variable";a3Z.Studies.movingAverage.typeMap.variable=z7u;a3Z.Studies.calculateChandeForecast=function(g1X,K4_){var Z9Y=f3BGj;var q99,X6F,T4u,X52,P7l,F_e;Z9Y.T$X();q99="M";q99+="A";X6F="ti";X6F+="me series";T4u=K4_.chart.scrubbed;if(T4u.length < K4_.days + 1){K4_.error=!!1;return;}X52=K4_.inputs.Field;if(!X52 || X52 == "field"){X52="Close";}a3Z.Studies.MA(X6F,K4_.days,X52,0,q99,g1X,K4_);for(var s7A=Math.max(1,K4_.startFrom);s7A < T4u.length;s7A++){P7l="ob";P7l+="j";P7l+="e";P7l+="ct";F_e=T4u[s7A][X52];if(F_e && typeof F_e == P7l){F_e=F_e[K4_.subField];}Z9Y.j7J(82);var X1b=Z9Y.a$j(4,2,94);Z9Y.j7J(17);var N8M=Z9Y.c0C(120,6,18,13);T4u[s7A]["Result " + K4_.name]=X1b * (N8M - T4u[s7A]["MA " + K4_.name] / F_e);}};a3Z.Studies.calculateChandeMomentum=function(t1_,N_y){var a6m=f3BGj;var e3p,Q$E,d2p,r8f,U4q,f47,E77,B$M,m9s,y5v,R1U,f3a;e3p="Cl";e3p+="ose";Q$E=N_y.name;for(var Z2d in N_y.outputs){a6m.N_M(82);Q$E=a6m.a$j(Q$E,792 >= (3363,6080)?(0x26cd,"k"):(5956,537.74) == 24.91?(829,7898) !== 691.95?(!0,+"0x21d7"):569.94:" ",Z2d);}d2p=N_y.chart.scrubbed;if(d2p.length < N_y.days + 1){N_y.error=!!"1";return;}r8f=N_y.inputs.Field;if(!r8f || r8f == "field"){r8f=e3p;}U4q=0;a6m.T$X();a6m.j7J(31);f47=a6m.c0C("0",64);E77=[];for(var W9F=N_y.startFrom - N_y.days + ("1" - 0);W9F < d2p.length;W9F++){B$M="ob";B$M+="j";B$M+="e";B$M+="ct";if(W9F < +"1")continue;m9s=d2p[W9F][r8f];a6m.N_M(14);y5v=d2p[a6m.c0C(W9F,1)][r8f];if(m9s && typeof m9s == B$M){m9s=m9s.Close;}if(y5v && typeof y5v == "object"){y5v=y5v.Close;}if(y5v === undefined)continue;a6m.N_M(14);R1U=a6m.a$j(m9s,y5v);E77.push(R1U);U4q+=R1U;f47+=Math.abs(R1U);if(E77.length == N_y.days){a6m.N_M(111);d2p[W9F][Q$E]=a6m.c0C(U4q,f47,100);f3a=E77.shift();U4q-=f3a;f47-=Math.abs(f3a);}}};a3Z.Studies.calculateMovingAverageVariable=function(I1C,I9O){var O5Y=f3BGj;var X3c,q2Z,C7u,H7l,f9v,l0h,y4l,m24,X5z,Y2N,N77,F1N,F7J,v6p,d_Q,x9E,q9Q,j7A,c2Q,p0g,X5X;X3c=I9O.inputs.Type;q2Z=I9O.chart.scrubbed;O5Y.N_M(0);var F$O=O5Y.a$j(139,3,36,4);O5Y.j7J(119);var W2W=O5Y.a$j(12,79,18,13);C7u=F$O / (I9O.days + W2W);H7l=null;f9v=I9O.name;for(var D96 in I9O.outputs){O5Y.j7J(82);f9v=O5Y.a$j(f9v,(5380,9960) >= (+"375",5880)?("8960" | 0) == 4935?3690 == 2520?(!({}),!({})):(0x207f,!({})):" ":0x13c3,D96);}l0h=I9O.inputs.Field;if(!l0h || l0h == "field"){l0h="Close";}I9O.cmo=new a3Z.Studies.StudyDescriptor(I9O.name,"cmo",I9O.panel);I9O.cmo.chart=I9O.chart;I9O.cmo.days=9;I9O.cmo.inputs={Field:l0h};I9O.cmo.startFrom=I9O.startFrom;I9O.cmo.outputs={_CMO:null};a3Z.Studies.calculateChandeMomentum(I1C,I9O.cmo);y4l=parseInt(I9O.inputs.Offset,10);O5Y.T$X();if(isNaN(y4l)){y4l=0;}N77=I9O.startFrom;F1N=y4l;for(m24=I9O.startFrom - 1;m24 >= 0;m24--){X5z=q2Z[m24][f9v];if(!X5z && X5z !== 0)continue;if(H7l === null){H7l=X5z;}if(F1N <= 0)break;F1N--;N77=m24;}if(H7l === null){H7l=N77=0;}F7J=[];for(m24=N77;m24 < q2Z.length;m24++){v6p="_";v6p+="C";v6p+="MO ";d_Q="_CM";d_Q+="O ";x9E="ob";x9E+="ject";q9Q=q2Z[m24];X5z=q9Q[l0h];if(X5z && typeof X5z == x9E){X5z=X5z[I9O.subField];}j7A=m24 + y4l >= 0 && m24 + y4l < q2Z.length;c2Q=j7A?q2Z[m24 + y4l]:null;if(!X5z && X5z !== 0){if(c2Q){c2Q[f9v]=null;}else if(m24 + y4l >= q2Z.length){Y2N={};Y2N[f9v]=null;F7J.push(Y2N);}continue;}if(!q9Q[d_Q + I9O.name] && q9Q["_CMO " + I9O.name] !== 0)continue;O5Y.N_M(120);var y64=O5Y.a$j(12,40,12,6);p0g=Math.abs(q9Q[v6p + I9O.name]) / y64;O5Y.j7J(121);X5X=O5Y.a$j(p0g,C7u,X5z,C7u,p0g,1,H7l);H7l=X5X;if(m24 < I9O.days){X5X=null;}if(c2Q){c2Q[f9v]=X5X;}else if(m24 + y4l >= q2Z.length){Y2N={};Y2N[f9v]=X5X;F7J.push(Y2N);}}I9O.appendFutureTicks(I1C,F7J);};a3Z.Studies.studyLibrary=a3Z.extend(a3Z.Studies.studyLibrary,{"Chande Fcst":{name:"Chande Forecast Oscillator",calculateFN:a3Z.Studies.calculateChandeForecast,inputs:{Period:+"14",Field:"field"}},"Chande Mtm":{name:"Chande Momentum Oscillator",calculateFN:a3Z.Studies.calculateChandeMomentum,inputs:{Period:9},parameters:{init:{studyOverZonesEnabled:!!({}),studyOverBoughtValue:50,studyOverBoughtColor:y$N,studyOverSoldValue:-50,studyOverSoldColor:"auto"}}}});}};W9=I8_=>{var n0$,L6O;n0$=typeof _CIQ !== "undefined"?_CIQ:I8_.CIQ;if(!n0$.Studies){L6O="choppi";L6O+="ness feature requ";L6O+="ires first activating studies feature.";console.error(L6O);}else {n0$.Studies.calculateChoppiness=function(M_2,e26){var y$o=f3BGj;var d_5,h98,w93,P6N,t8J;function f5m(L5_,S8B){var Q81,L0z;y$o.N_M(27);var B6G=y$o.a$j(17,18);Q81=Number.MAX_VALUE * B6G;L0z=Number.MAX_VALUE;for(var D9e=S8B - L5_ + 1;D9e <= S8B;D9e++){if(D9e < 0)continue;Q81=Math.max(Q81,d_5[D9e].High);L0z=Math.min(L0z,d_5[D9e].Low);}return [L0z,Q81];}n0$.Studies.calculateStudyATR(M_2,e26);d_5=e26.chart.scrubbed;if(d_5.length < e26.days + 1){e26.error=!!({});return;}for(var R1v=Math.max(e26.startFrom,e26.days);R1v < d_5.length;R1v++){h98=d_5[R1v];if(!h98)continue;if(h98.futureTick)break;w93=f5m(e26.days,R1v);if(h98["Sum True Range " + e26.name]){P6N="Sum Tru";P6N+="e Rang";P6N+="e ";t8J="Resul";t8J+="t ";y$o.N_M(3);var X2_=y$o.c0C(1414,14,1500);y$o.j7J(122);var W0s=y$o.c0C(0,0,4,4);h98[t8J + e26.name]=X2_ * Math.log(h98[P6N + e26.name] / Math.max(0.000001,w93[W0s] - w93[0])) / Math.log(e26.days);}else if(!isNaN(h98)){h98["Result " + e26.name]=0;}}};n0$.Studies.studyLibrary=n0$.extend(n0$.Studies.studyLibrary,{Choppiness:{name:"Choppiness Index",calculateFN:n0$.Studies.calculateChoppiness,centerline:50,parameters:{init:{studyOverZonesEnabled:!0,studyOverBoughtValue:61.8,studyOverBoughtColor:"auto",studyOverSoldValue:38.2,studyOverSoldColor:"auto"}},attributes:{studyOverBoughtValue:{min:"50" | 18,step:"0.1"},studyOverSoldValue:{max:50,step:"0.1"}}}});}};C5=u8a=>{var t6b=f3BGj;var D7D,P_y,E7r,u8t;D7D=typeof _CIQ !== "undefined"?_CIQ:u8a.CIQ;t6b.T$X();if(!D7D.Studies){console.error("comparisonStudies feature requires first activating studies feature.");}else if(!D7D.Studies.initPriceRelative){console.error("comparisonStudies feature requires first activating priceRelative feature.");}else {P_y="S";P_y+="P";P_y+="Y";E7r="S";E7r+="P";E7r+="Y";u8t="-1 to ";u8t+="1";D7D.Studies.calculateCorrelationCoefficient=function(g3d,N4Y){var N_q,n$f,H4t,r80,F_1,m8h,y9c,O1j,h0S,J_H,h$s,I5e,i9b,n8M,i6k,E4j,V0d,m8M;N_q=N4Y.chart.scrubbed;t6b.T$X();n$f=N4Y.days;if(N_q.length < n$f + "1" * 1){N4Y.error=!![];return;}N4Y.compare=N4Y.inputs["Compare To"];if(!N4Y.compare){N4Y.compare=[];N4Y.outputs={};N4Y.outputMap={};for(var K5x in g3d.chart.series){H4t=g3d.chart.series[K5x];if(H4t.parameters.color){r80="Resul";r80+="t";r80+=" ";N4Y.compare.push(H4t.display);N4Y.outputs[r80 + H4t.display]=H4t.parameters.color;t6b.j7J(123);var t3o=t6b.c0C(1,11,1,4084,27);t6b.j7J(14);var Y7J=t6b.a$j(18,17);t6b.N_M(93);var k6x=t6b.a$j(5,4,91,0,14);t6b.j7J(1);var i8r=t6b.c0C(841,5046);t6b.N_M(124);var R0T=t6b.c0C(1430,11,1536,16,17);t6b.N_M(125);var Z4r=t6b.c0C(5,20,19,4,3938);N4Y.outputMap["Result " + H4t.display + ((t3o,"17.03" * Y7J) <= (+"5270","5429" * k6x)?" ":i8r < (+"8040","6590" << R0T)?Z4r:("p",+"3.12e+3")) + N4Y.name]="Result " + H4t.display;}}}else {N4Y.compare=[N4Y.compare];}if(!N4Y.compare.length){N4Y.error="Correlation Coefficient requires at least one comparison symbol";return;}for(var V8X=0;V8X < N4Y.compare.length;V8X++){t6b.j7J(29);F_1=t6b.a$j(0,"0");t6b.j7J(14);m8h=t6b.a$j("0",0);y9c=0;t6b.j7J(5);O1j=t6b.c0C(1,"0");h0S=0;J_H=N4Y.compare[V8X];h$s=+"0";for(var R53=N4Y.startFrom - n$f;R53 < N_q.length;R53++){I5e="_";I5e+="t";I5e+="emp";I5e+="s ";if(!N_q[R53])continue;i9b=N_q[R53][J_H];if(i9b && typeof i9b == "object"){i9b=i9b.Close;}if(!i9b && i9b !== 0){if(R53 > 0 && N_q[R53 - ("1" << 32)] && N_q[R53 - ("1" - 0)]["_temps " + N4Y.name] && N_q[R53 - 1]["_temps " + N4Y.name].c){i9b=N_q[R53 - 1]["_temps " + N4Y.name].c;}else {t6b.j7J(14);i9b=t6b.a$j("0",0);}}if(i9b && typeof i9b == "object"){i9b=i9b.Close;}N_q[R53]["_temps " + N4Y.name]={};F_1+=N_q[R53]["_temps " + N4Y.name].b=N_q[R53].Close;m8h+=N_q[R53]["_temps " + N4Y.name].c=i9b;y9c+=N_q[R53]["_temps " + N4Y.name].b2=Math.pow(N_q[R53].Close,"2" - 0);t6b.j7J(46);O1j+=N_q[R53][I5e + N4Y.name].c2=Math.pow(i9b,t6b.a$j("2",0));h0S+=N_q[R53]["_temps " + N4Y.name].bc=N_q[R53].Close * i9b;if(h$s >= n$f){n8M="_";n8M+="t";n8M+="emps ";F_1-=N_q[R53 - n$f]["_temps " + N4Y.name].b;m8h-=N_q[R53 - n$f]["_temps " + N4Y.name].c;y9c-=N_q[R53 - n$f][n8M + N4Y.name].b2;O1j-=N_q[R53 - n$f]["_temps " + N4Y.name].c2;h0S-=N_q[R53 - n$f]["_temps " + N4Y.name].bc;t6b.N_M(3);var W12=t6b.c0C(8,10,0);i6k=y9c / n$f - Math.pow(F_1 / n$f,W12);t6b.j7J(66);var S87=t6b.a$j(15,4,20,37);E4j=O1j / n$f - Math.pow(m8h / n$f,S87);t6b.N_M(34);var a_r=t6b.a$j(9,1,7);V0d=h0S / n$f - F_1 * m8h / Math.pow(n$f,a_r);m8M=V0d / Math.sqrt(i6k * E4j);N_q[R53]["Result " + J_H + " " + N4Y.name]=m8M;}h$s++;}}};D7D.Studies.calculatePerformance=function(Y67,e51){var p$L,p0A,C_A,X1r;p$L="Co";p$L+="mparis";p$L+="on Sy";p$L+="mbol";p0A=e51.chart.scrubbed;C_A=e51.inputs["Comparison Symbol"].toUpperCase();if(!C_A){C_A=e51.study.inputs[p$L];}if(!e51.days){e51.days=e51.study.inputs.Period;}if(p0A.length < e51.days + 1){e51.error=!!"1";return;}t6b.T$X();D7D.Studies.MA("ma",e51.days,"Close",0,"_MA Base",Y67,e51);D7D.Studies.MA("ma",e51.days,C_A,+"0","_MA Comp",Y67,e51);for(var w4M=e51.startFrom;w4M < p0A.length;w4M++){X1r=p0A[w4M][C_A];if(X1r && (X1r.Close || X1r.Close === 0)){X1r=X1r.Close;}p0A[w4M]["Result " + e51.name]=p0A[w4M].Close / X1r * (p0A[w4M]["_MA Comp " + e51.name] / p0A[w4M]["_MA Base " + e51.name]);}};D7D.Studies.calculateBeta=function(r_C,g1g){var U$f,R0M,j7U,j0I,z2d,N$C,m$Y,r4o,C18,S39,x4u;U$f="m";U$f+="a";R0M="m";R0M+="a";j7U="Compa";t6b.T$X();j7U+="rison Sym";j7U+="bol";j0I="Compariso";j0I+="n Sym";j0I+="bol";z2d=g1g.chart.scrubbed;N$C=g1g.inputs[j0I].toUpperCase();if(!N$C){N$C=g1g.study.inputs[j7U];}if(!g1g.days){g1g.days=g1g.study.inputs.Period;}if(z2d.length < g1g.days + 1){g1g.error=!!({});return;}for(var g42=Math.max(g1g.startFrom,1);g42 < z2d.length;g42++){t6b.N_M(102);var t4x=t6b.c0C(12,13,6,18);t6b.j7J(27);var y4S=t6b.a$j(6,5);z2d[g42]["_BaseChange " + g1g.name]=z2d[g42].Close / z2d[g42 - t4x].Close - y4S;m$Y=z2d[g42][N$C];if(m$Y && (m$Y.Close || m$Y.Close === "0" >> 0)){m$Y=m$Y.Close;}t6b.j7J(14);r4o=z2d[t6b.a$j(g42,1)][N$C];if(r4o && (r4o.Close || r4o.Close === 0)){r4o=r4o.Close;}t6b.j7J(35);z2d[g42]["_CompChange " + g1g.name]=t6b.a$j(1,m$Y,r4o);}D7D.Studies.MA(R0M,g1g.days,"_BaseChange " + g1g.name,0,"_MA Base",r_C,g1g);D7D.Studies.MA(U$f,g1g.days,"_CompChange " + g1g.name,+"0","_MA Comp",r_C,g1g);for(g42=Math.max(g1g.startFrom,g1g.days);g42 < z2d.length;g42++){C18="_CompChange";C18+=" ";S39="_";S39+="MA Base ";z2d[g42]["_COVARn " + g1g.name]=(z2d[g42]["_BaseChange " + g1g.name] - z2d[g42][S39 + g1g.name]) * (z2d[g42][C18 + g1g.name] - z2d[g42]["_MA Comp " + g1g.name]);z2d[g42]["_VARn " + g1g.name]=Math.pow(z2d[g42]["_CompChange " + g1g.name] - z2d[g42]["_MA Comp " + g1g.name],2);}D7D.Studies.MA("ma",g1g.days,"_COVARn " + g1g.name,+"0","_COVAR",r_C,g1g);D7D.Studies.MA("ma",g1g.days,"_VARn " + g1g.name,0,"_VAR",r_C,g1g);for(g42=Math.max(g1g.startFrom,g1g.days * ("2" << 0) - 1);g42 < z2d.length;g42++){x4u="_VAR";x4u+=" ";z2d[g42]["Result " + g1g.name]=z2d[g42]["_COVAR " + g1g.name] / z2d[g42][x4u + g1g.name];}};D7D.Studies.studyLibrary=D7D.extend(D7D.Studies.studyLibrary,{correl:{name:"Correlation Coefficient",range:u8t,calculateFN:D7D.Studies.calculateCorrelationCoefficient,outputs:{}},"Perf Idx":{name:"Performance Index",centerline:1,initializeFN:D7D.Studies.initPriceRelative,seriesFN:D7D.Studies.displayVsComparisonSymbol,calculateFN:D7D.Studies.calculatePerformance,inputs:{Period:"120" ^ 0,"Comparison Symbol":E7r},outputs:{Result:"auto",Gain:"#00DD00",Loss:"#FF0000"},deferUpdate:!!1},Beta:{name:"Beta",centerline:1,initializeFN:D7D.Studies.initPriceRelative,seriesFN:D7D.Studies.displayVsComparisonSymbol,calculateFN:D7D.Studies.calculateBeta,inputs:{Period:20,"Comparison Symbol":P_y},deferUpdate:!0}});}};b4=U05=>{var M8e=f3BGj;var u$t,n_W,d6B,a0I,Z_P,Y7r,L4F,B4$;u$t="und";u$t+="efi";u$t+="n";u$t+="ed";M8e.f3X();n_W=typeof _CIQ !== u$t?_CIQ:U05.CIQ;if(!n_W.Studies){d6B="coppock feature requires first activatin";d6B+="g";d6B+=" studies feature.";console.error(d6B);}else {a0I="f";a0I+="i";a0I+="e";a0I+="ld";n_W.Studies.calculateCoppock=function(s1H,j9L){var s8b,R7A,P6x,K1Z,e$l,P1D,C0P,g4o,S1n,C39,C_s;s8b="_";s8b+="Sum";s8b+=" ";R7A="wei";R7A+="g";R7A+="h";R7A+="ted";P6x="Short ";P6x+="RoC";K1Z="L";K1Z+="ong R";K1Z+="oC";e$l=j9L.chart.scrubbed;P1D=j9L.inputs.Field;if(!P1D || P1D == "field"){P1D="Close";}C0P=parseInt(j9L.inputs[K1Z],"10" ^ 0);if(!C0P){C0P=14;}g4o=parseInt(j9L.inputs[P6x],10);if(!g4o){g4o=11;}S1n=j9L.days;if(!S1n){S1n=10;}if(C0P < g4o){return;}if(e$l.length < Math.max(g4o,C0P,S1n) + ("1" >> 64)){j9L.error=!![];return;}for(var x4y=Math.max(j9L.startFrom,C0P);x4y < e$l.length;x4y++){M8e.N_M(14);C39=e$l[M8e.a$j(x4y,g4o)][P1D];M8e.j7J(14);C_s=e$l[M8e.c0C(x4y,C0P)][P1D];if(C39 && C_s){M8e.j7J(118);var x4F=M8e.a$j(18,4,6,20,6);M8e.N_M(126);var t5X=M8e.a$j(19,8,2,245,9);e$l[x4y]["_Sum " + j9L.name]=x4F * (e$l[x4y][P1D] / C39 + e$l[x4y][P1D] / C_s - t5X);}}n_W.Studies.MA(R7A,S1n,s8b + j9L.name,0,"Result",s1H,j9L);};M8e.j7J(5);Z_P=M8e.c0C(1,"251709666");Y7r=1207877467;L4F=2;for(var R8B=1;M8e.S9Y(R8B.toString(),R8B.toString().length,"55926" ^ 0) !== Z_P;R8B++){B4$="Lo";B4$+="ng R";B4$+="oC";n_W.Studies.studyLibrary=n_W.extend(n_W.Studies.studyLibrary,{Coppock:{name:"Long RoC",calculateFN:n_W.Studies.calculateCoppock,inputs:{Period:64,Field:B4$,"Short RoC":73,"Long RoC":21}}});L4F+=2;}if(M8e.S9Y(L4F.toString(),L4F.toString().length,+"70280") !== Y7r){n_W.Studies.studyLibrary=n_W.extend(n_W.Studies.studyLibrary,{Coppock:{name:"Long RoC",calculateFN:n_W.Studies.calculateCoppock,inputs:{Period:64,Field:"Long RoC","Short RoC":73,"Long RoC":21}}});}n_W.Studies.studyLibrary=n_W.extend(n_W.Studies.studyLibrary,{Coppock:{name:"Coppock Curve",calculateFN:n_W.Studies.calculateCoppock,inputs:{Period:10,Field:a0I,"Short RoC":11,"Long RoC":14}}});}};f3=J4w=>{var K0x,W37,U1y,a2$;K0x=typeof _CIQ !== "undefined"?_CIQ:J4w.CIQ;if(!K0x.Studies){console.error("darvasBox feature requires first activating studies feature.");}else {W37="a";W37+="u";W37+="t";W37+="o";U1y="cl";U1y+="ose";a2$="D";a2$+="a";a2$+="r";a2$+="vas Box";K0x.Studies.calculateDarvas=function(a6y,t2p){var y8Y=f3BGj;var K5W,J0I,I9D,t4F,j5F,k1K,o$X,I6z,S8m,f2r,b_H,d4E,m6d,T0T,u9t,g1V,l$Z,v3z,a3q,R$T,Y0C,o5s,H$f,j$t,i5d,y8t,U6c,O_d,s_a,y6Y,H$Q,N5y,V4_,q2T;K5W="A";K5W+="D";K5W+="V";J0I="L";J0I+="o";J0I+="s";J0I+="s";I9D="Level Off";I9D+="set";t4F="V";t4F+="ol";t4F+="ume Sp";t4F+="ike";j5F=t2p.chart.scrubbed;k1K=0;o$X=parseInt(t2p.inputs["ATH Lookback Period"],10);if(t2p.inputs[t4F]){I6z="V";I6z+="olume";K0x.Studies.MA("simple",o$X,I6z,0,"ADV",a6y,t2p);}y8Y.N_M(16);var i7l=y8Y.c0C(7,20,0,17);S8m=parseFloat(t2p.inputs["Volume % of Avg"]) / ("100" | i7l);f2r="none";b_H={};d4E=null;m6d=null;T0T=null;u9t=parseFloat(t2p.inputs[I9D]);g1V=!({});if(g1V){console.log("*****************");}v3z={};["Darvas","Ghost","Profit",J0I,"ATH",K5W,"Spike"].forEach(function(q1K){v3z[q1K]=q1K + " " + t2p.name;});for(l$Z=t2p.startFrom - ("1" ^ 0);l$Z > 0;l$Z--){a3q=j5F[l$Z];if(a3q[v3z.Darvas] || a3q[v3z.Ghost]){for(var I1w in v3z){a3q[I1w]=null;}}else {k1K=a3q[v3z.ATH] || 0;m6d=a3q[v3z.Profit];T0T=a3q[v3z.Loss];break;}}for(l$Z;l$Z < j5F.length;l$Z++){R$T=j5F[l$Z];if(!R$T)continue;if(parseFloat(t2p.inputs["Price Minimum"]) <= j5F[k1K].Close){Y0C="darva";Y0C+="s";o5s="n";o5s+="o";o5s+="n";o5s+="e";H$f="high";H$f+="/low";if(d4E && (!d4E.End || l$Z == d4E.End + 1)){if(j5F[l$Z - ("1" >> 0)].Close > b_H.High){b_H={State:1,High:2 * b_H.High - b_H.Low,Low:b_H.High,Start:l$Z,End:2 * b_H.End - b_H.Start + 1};}else {d4E=null;;}if(d4E){R$T[v3z.Ghost]=K0x.clone(b_H);if(g1V){console.log("Ghost begin:" + R$T.DT);}b_H.State=0;if(j5F[b_H.End]){j5F[b_H.End][v3z.Ghost]=K0x.clone(b_H);if(g1V){console.log("Ghost end:" + j5F[b_H.End].DT);}}d4E={Start:b_H.Start,End:b_H.End};m6d=b_H.High + u9t;if(!T0T || T0T < b_H.Low - u9t){T0T=b_H.Low - u9t;}}}R$T[v3z.Profit]=m6d;R$T[v3z.Loss]=T0T;if(R$T.Close >= m6d){m6d=null;}else if(t2p.inputs["Exit Field"] == H$f && R$T.High >= m6d){m6d=null;}if(f2r == o5s){if(l$Z == k1K + 3){if(!j5F[k1K + 2][v3z.Darvas] && !j5F[k1K + ("1" - 0)][v3z.Darvas] && !j5F[k1K][v3z.Darvas] && j5F[k1K].High > R$T.High){f2r="high";;}}}if(f2r == "high"){if(R$T.High > j5F[k1K].High){j$t="n";j$t+="o";j$t+="n";j$t+="e";f2r=j$t;}else if(j5F[l$Z - 3].Low < j5F[l$Z - 2].Low && j5F[l$Z - 3].Low < j5F[l$Z - +"1"].Low && j5F[l$Z - ("3" << 64)].Low < R$T.Low){b_H={State:1,High:j5F[k1K].High,Low:j5F[l$Z - 3].Low,Start:k1K};j5F[k1K][v3z.Darvas]=K0x.clone(b_H);f2r="darvas";if(g1V){console.log("Darvas begin:" + j5F[k1K].DT);}if(g1V){console.log("Darvas established:" + R$T.DT);}if(d4E){if(d4E.End > l$Z && j5F[d4E.Start]){R$T[v3z.Ghost]=K0x.clone(j5F[d4E.Start][v3z.Ghost]);R$T[v3z.Ghost].End=l$Z;if(j5F[d4E.End]){delete j5F[d4E.End][v3z.Ghost];if(g1V){console.log("Ghost End removed:" + j5F[d4E.End].DT);}}}R$T[v3z.Ghost].State=0;j5F[d4E.Start][v3z.Ghost].End=l$Z;if(g1V){console.log("Ghost end:" + R$T.DT);}d4E=null;}m6d=b_H.High + u9t;if(!T0T || T0T < b_H.Low - u9t){T0T=b_H.Low - u9t;}}}if(f2r == Y0C){i5d="n";i5d+="o";i5d+="ne";y8t="n";y8t+="one";U6c="n";U6c+="o";U6c+="ne";O_d="Exit F";O_d+="iel";O_d+="d";s_a="non";s_a+="e";y6Y="hi";y6Y+="gh";y6Y+="/low";if(R$T.Close > b_H.High){d4E={};}else if(t2p.inputs["Exit Field"] == y6Y && R$T.High > b_H.High){d4E={};}else if(R$T.Close < b_H.Low){f2r=s_a;}else if(t2p.inputs[O_d] == "high/low" && R$T.Low < b_H.Low){f2r=U6c;}if(d4E){f2r="none";}else if(f2r == y8t){m6d=null;T0T=null;}if(!t2p.inputs["Ghost Boxes"]){d4E=null;}if(f2r == i5d){for(var P0r=b_H.Start + "1" * 1;P0r < l$Z;P0r++){j5F[P0r][v3z.Darvas]=K0x.clone(b_H);}b_H.State=0;b_H.End=l$Z;R$T[v3z.Darvas]=K0x.clone(b_H);if(g1V){console.log("Darvas end:" + R$T.DT);}R$T[v3z.ATH]=k1K;continue;}}if(T0T){H$Q="E";H$Q+="xi";H$Q+="t";H$Q+=" Field";if(R$T.Close < b_H.Low || t2p.inputs[H$Q] == "high/low" && R$T.Low < b_H.Low){N5y="Ex";N5y+="it F";N5y+="i";N5y+="eld";if(f2r == "darvas"){f2r="none";}if(R$T.Close < T0T || t2p.inputs[N5y] == "high/low" && R$T.Low < T0T){m6d=null;T0T=null;}if(d4E){if(d4E.End > l$Z && j5F[d4E.Start]){R$T[v3z.Ghost]=K0x.clone(j5F[d4E.Start][v3z.Ghost]);R$T[v3z.Ghost].End=l$Z;if(j5F[d4E.End]){V4_="Gh";V4_+="ost End removed:";delete j5F[d4E.End][v3z.Ghost];if(g1V){console.log(V4_ + j5F[d4E.End].DT);}}}R$T[v3z.Ghost].State=0;j5F[d4E.Start][v3z.Ghost].End=l$Z;if(g1V){console.log("Ghost end:" + R$T.DT);}d4E=null;}}}}if(R$T.High >= j5F[k1K].High){q2T="All T";q2T+="i";q2T+="me ";q2T+="High:";k1K=l$Z;if(g1V){console.log(q2T + R$T.DT);}}if(l$Z < 3 || R$T.High >= j5F[l$Z - 1].High && R$T.High >= j5F[l$Z - ("2" ^ 0)].High && R$T.High >= j5F[l$Z - ("3" | 2)].High){if(l$Z - k1K >= o$X){k1K=l$Z;for(var P6W=0;P6W < o$X;P6W++){if(l$Z - P6W < +"0")break;if(j5F[l$Z - P6W].High > j5F[k1K].High){y8Y.j7J(14);k1K=y8Y.a$j(l$Z,P6W);}}if(g1V){console.log("All Time High:" + R$T.DT);}}}if(t2p.inputs["Volume Spike"] && l$Z > o$X && l$Z == k1K){if(R$T[v3z.ADV] * S8m < R$T.Volume){R$T[v3z.Spike]=1;if(g1V){console.log("Volume Spike:" + R$T.DT);}}}R$T[v3z.ATH]=k1K;}};K0x.Studies.displayDarvas=function(U87,g1B,U4l){var p2p=f3BGj;var D0E,k_n,L0O,g8V,H30,t3A,u4S,g2e,y1n,B9L,M_i,Q2F,B4w,w11,X0l,s_0,v7r,b0y,y4k,A4i,E8s,T0Z,q4J,N8c,b4V,O8g,U43,p8T,s9g,R7W,l_x,O3a,S8f,g5u,Z02,Q4v,q9X;D0E="Stop";D0E+=" L";D0E+="ev";D0E+="els";k_n="a";k_n+="uto";L0O=K0x.Studies.determineColor(g1B.outputs.Levels);if(!L0O || L0O == "auto" || K0x.isTransparent(L0O)){L0O=U87.defaultColor;}g8V=K0x.Studies.determineColor(g1B.outputs.Darvas);if(!g8V || g8V == "auto" || K0x.isTransparent(g8V)){g8V=U87.defaultColor;}H30=K0x.Studies.determineColor(g1B.outputs.Ghost);if(!H30 || H30 == k_n || K0x.isTransparent(H30)){H30=U87.defaultColor;}t3A=U87.panels[g1B.panel];u4S=g1B.getContext(U87);p2p.N_M(1);var n58=p2p.c0C(24,72);Q2F=U87.layout.candleWidth - ("2" << n58);if(Q2F < 2){Q2F=1;}U87.startClip(g1B.panel);if(g1B.inputs[D0E]){if(u4S.setLineDash){u4S.setLineDash([2,2]);}u4S.lineWidth=2;u4S.strokeStyle=L0O;u4S.beginPath();for(g2e=0;g2e < U4l.length;g2e++){B4w="L";B4w+="o";B4w+="s";B4w+="s ";y1n=U4l[g2e];p2p.j7J(14);w11=U4l[p2p.a$j(g2e,1)];if(!y1n)continue;M_i=y1n["Loss " + g1B.name]?Math.floor(U87.pixelFromPrice(y1n[B4w + g1B.name],t3A)):null;X0l=w11 && w11["Loss " + g1B.name]?Math.floor(U87.pixelFromPrice(w11["Loss " + g1B.name],t3A)):null;if(M_i){if(y1n.candleWidth){Q2F=Math.floor(Math.max(1,y1n.candleWidth));}s_0=Math.floor(U87.pixelFromBar(g2e,t3A.chart) + Q2F / 2);v7r=Math.floor(U87.pixelFromBar(g2e,t3A.chart) - Q2F / +"2");if(X0l && X0l >= M_i){u4S.lineTo(v7r,M_i);}else if(g2e === 0){u4S.moveTo(U87.chart.left,M_i);}else {u4S.moveTo(v7r,M_i);}u4S.lineTo(s_0,M_i);}}u4S.stroke();if(u4S.setLineDash){u4S.setLineDash([]);}u4S.lineWidth=1;}b0y=-10;A4i=+"0";T0Z=-10;N8c=0;O8g=!!0;U43=!"1";p2p.N_M(61);var M7z=p2p.a$j(6203,1,17);p2p.j7J(14);var u_j=p2p.c0C(157930,148640);p2p.j7J(15);var b6Z=p2p.a$j(3941,25,6);p2p.N_M(9);var Z8M=p2p.c0C(5544,17,330);p2p.N_M(82);var E3u=p2p.a$j(140,17,23);p2p.j7J(61);var L13=p2p.a$j(10290,10290,2057);p8T=u4S.measureText((755.12,"9731" - 0) > M7z?"\u25B2":u_j < (b6Z,"9026" | Z8M)?(E3u,L13):"P").width / ("2" ^ 0);s9g=0;for(g2e=0;g2e < U4l.length;g2e++){R7W="Da";R7W+="r";R7W+="vas";R7W+=" ";if(!U4l[g2e])continue;if(U4l[g2e].Close || U4l[g2e].Close === 0){s9g=g2e;}if(U4l[g2e]["Spike " + g1B.name]){u4S.fillStyle=g8V;u4S.textBaseline="bottom";l_x=U87.pixelFromPrice(U4l[g2e].High,U87.chart.panel);u4S.fillText(+"4630" === 534.99?(798.2,977.86) == (5535,2620)?(0x1b1f,0x410):564 <= (3088,382)?0x18f3:"X":"\u25BC",U87.pixelFromBar(g2e) - p8T,l_x - 5);;}if(U4l[g2e].candleWidth){Q2F=Math.floor(Math.max(1,U4l[g2e].candleWidth));}if(U4l[g2e][R7W + g1B.name]){y1n=U4l[g2e]["Darvas " + g1B.name];if(y1n.State == 1 && !O8g){b0y=Math.floor(U87.pixelFromBar(g2e,t3A.chart) - Q2F / +"2");y4k=Math.floor(U87.pixelFromPrice(y1n.High,t3A));E8s=Math.floor(U87.pixelFromPrice(y1n.Low,t3A)) - y4k;O8g=!"";}else if(y1n.State === 0){O3a="S";O3a+="t";O3a+="o";O3a+="p Levels";p2p.N_M(127);var Y3i=p2p.a$j(34,20,3,4,11);A4i=Math.floor(U87.pixelFromBar(g2e,t3A.chart) + Q2F / Y3i) - b0y;y4k=Math.floor(U87.pixelFromPrice(y1n.High,t3A));E8s=Math.floor(U87.pixelFromPrice(y1n.Low,t3A)) - y4k;u4S.strokeStyle=g8V;u4S.fillStyle=g8V;if(!g1B.inputs[O3a]){u4S.strokeRect(b0y,y4k,A4i,E8s);u4S.globalAlpha=0.2;}else {u4S.globalAlpha=0.3;}u4S.fillRect(b0y,y4k,A4i,E8s);u4S.globalAlpha=1;O8g=!!"";}}if(U4l[g2e]["Ghost " + g1B.name] && g1B.inputs["Ghost Boxes"]){y1n=U4l[g2e]["Ghost " + g1B.name];if(y1n.State == 1 && !U43){T0Z=Math.floor(U87.pixelFromBar(g2e,t3A.chart) - Q2F / 2);q4J=Math.floor(U87.pixelFromPrice(y1n.High,t3A));N8c=Math.floor((y1n.End - y1n.Start + 1) * U87.layout.candleWidth + Q2F / 2);b4V=Math.floor(U87.pixelFromPrice(y1n.Low,t3A)) - q4J;U43=!!({});}else if(y1n.State === 0){if(y1n.Start == y1n.End){T0Z=Math.floor(U87.pixelFromBar(g2e,t3A.chart) - Q2F / 2);}p2p.j7J(3);var C38=p2p.a$j(10,5,7);N8c=Math.floor(U87.pixelFromBar(g2e,t3A.chart) + Q2F / C38) - T0Z;q4J=Math.floor(U87.pixelFromPrice(y1n.High,t3A));b4V=Math.floor(U87.pixelFromPrice(y1n.Low,t3A)) - q4J;u4S.strokeStyle=H30;u4S.fillStyle=H30;if(!g1B.inputs["Stop Levels"]){u4S.strokeRect(T0Z,q4J,N8c,b4V);u4S.globalAlpha=0.2;}else {u4S.globalAlpha=0.3;}u4S.fillRect(T0Z,q4J,N8c,b4V);u4S.globalAlpha=1;U43=![];}}}if(O8g){S8f="Stop";S8f+=" Level";S8f+="s";p2p.j7J(64);var g2L=p2p.a$j(1,8,149,11,13);A4i=Math.floor(U87.pixelFromBar(s9g,t3A.chart) + Q2F / g2L) - b0y;u4S.strokeStyle=g8V;u4S.fillStyle=g8V;if(!g1B.inputs[S8f]){u4S.beginPath();p2p.j7J(25);u4S.moveTo(p2p.c0C(2,A4i,b0y),y4k);u4S.lineTo(b0y,y4k);p2p.N_M(1);u4S.lineTo(b0y,p2p.a$j(y4k,E8s));p2p.j7J(25);u4S.lineTo(p2p.a$j(2,A4i,b0y),p2p.a$j(y4k,E8s,p2p.j7J(1)));u4S.stroke();u4S.globalAlpha=0.2;}else {u4S.globalAlpha=+"0.3";}p2p.j7J(5);u4S.fillRect(b0y,y4k,p2p.a$j(A4i,2),E8s);u4S.globalAlpha=1;}if(U43){u4S.strokeStyle=H30;u4S.fillStyle=H30;if(!g1B.inputs["Stop Levels"]){u4S.strokeRect(T0Z,q4J,N8c,b4V);p2p.j7J(14);u4S.globalAlpha=p2p.a$j("0.2",0);}else {u4S.globalAlpha=0.3;}u4S.fillRect(T0Z,q4J,N8c,b4V);u4S.globalAlpha=1;}if(O8g || U43){if(g1B.inputs["Stop Levels"]){if(u4S.setLineDash){g5u=1074516398;Z02=211878868;Q4v=2;for(var K8z=1;p2p.S9Y(K8z.toString(),K8z.toString().length,4566) !== g5u;K8z++){u4S.setLineDash([2,2]);Q4v+=2;}if(p2p.O1W(Q4v.toString(),Q4v.toString().length,47512) !== Z02){u4S.setLineDash([5,+"7"]);}}u4S.lineWidth=2;u4S.strokeStyle=L0O;q9X=Math.floor(U87.pixelFromBar(s9g - ("1" >> 0),t3A.chart) + Q2F / 2);if(B9L){u4S.beginPath();u4S.moveTo(q9X,B9L);u4S.lineTo(O8g?b0y + 2 * A4i:T0Z + N8c,B9L);u4S.stroke();}if(M_i){u4S.beginPath();u4S.moveTo(q9X,M_i);u4S.lineTo(O8g?b0y + ("2" ^ 0) * A4i:T0Z + N8c,M_i);u4S.stroke();}if(u4S.setLineDash){u4S.setLineDash([]);}u4S.lineWidth=1;}O8g=!!"";U43=!!"";}U87.endClip();};K0x.Studies.studyLibrary=K0x.extend(K0x.Studies.studyLibrary,{Darvas:{name:a2$,underlay:!![],calculateFN:K0x.Studies.calculateDarvas,seriesFN:K0x.Studies.displayDarvas,inputs:{"ATH Lookback Period":100,"Exit Field":[U1y,"high/low"],"Ghost Boxes":!![],"Stop Levels":!({}),"Level Offset":+"0.01","Price Minimum":5,"Volume Spike":!({}),"Volume % of Avg":400},outputs:{Darvas:"#5F7CB8",Ghost:"#699158",Levels:W37},customRemoval:!!1,attributes:{"Price Minimum":{min:"0.01" * 1,step:0.01},yaxisDisplayValue:{hidden:!""},panelName:{hidden:!![]},flippedEnabled:{hidden:!![]}}}});}};n8=w2F=>{var D1n,Y9z;D1n=typeof _CIQ !== "undefined"?_CIQ:w2F.CIQ;if(!D1n.Studies){console.error("detrended feature requires first activating studies feature.");}else {Y9z="m";Y9z+="a";D1n.Studies.calculateDetrendedPrice=function(o8t,Z1V){var j_j,b3G,S21,n1K,n$G,r95,W5W,y4p;j_j="f";j_j+="ie";j_j+="ld";b3G=Z1V.chart.scrubbed;if(b3G.length < Z1V.days + 1){Z1V.error=!![];return;}S21=Z1V.inputs.Field;if(!S21 || S21 == j_j){S21="Close";}n1K=Math.floor(Z1V.days / 2 + 1);D1n.Studies.MA(Z1V.inputs["Moving Average Type"],Z1V.days,S21,-n1K,"MA",o8t,Z1V);for(var u2d=Math.max(Z1V.days - n1K - 1,Z1V.startFrom - n1K);u2d < b3G.length - n1K;u2d++){n$G="R";n$G+="e";n$G+="sult";n$G+=" ";r95="M";r95+="A ";if(u2d < ("0" ^ 0))continue;W5W=b3G[u2d][S21];if(W5W && typeof W5W == "object"){W5W=W5W[Z1V.subField];}y4p=b3G[u2d][r95 + Z1V.name];if((W5W || W5W === 0) && (y4p || y4p === +"0")){f3BGj.j7J(14);b3G[u2d][n$G + Z1V.name]=f3BGj.c0C(W5W,y4p);}}};D1n.Studies.studyLibrary=D1n.extend(D1n.Studies.studyLibrary,{Detrended:{name:"Detrended Price Oscillator",calculateFN:D1n.Studies.calculateDetrendedPrice,inputs:{Period:14,Field:"field","Moving Average Type":Y9z}}});}};p9=q_f=>{var O0_=f3BGj;var Z4Y,t9E;Z4Y=typeof _CIQ !== "undefined"?_CIQ:q_f.CIQ;O0_.T$X();if(!Z4Y.Studies){console.error("disparity feature requires first activating studies feature.");}else {t9E="Di";t9E+="sparity Index";Z4Y.Studies.calculateDisparity=function(J8c,U9f){var A$$,j7p,n2T,Q$a,n15;A$$="C";A$$+="lo";A$$+="se";j7p=U9f.chart.scrubbed;if(j7p.length < U9f.days + 1){U9f.error=!!"1";return;}n2T=U9f.inputs.Field;if(!n2T || n2T == "field"){n2T=A$$;}Z4Y.Studies.MA(U9f.inputs["Moving Average Type"],U9f.days,n2T,0,"_MA",J8c,U9f);O0_.T$X();for(var S2R=Math.max(U9f.startFrom,U9f.days - 1);S2R < j7p.length;S2R++){Q$a="R";Q$a+="e";Q$a+="s";Q$a+="ult ";if(!j7p[S2R])continue;n15=j7p[S2R]["_MA " + U9f.name];if(n15){O0_.N_M(61);var G2Y=O0_.a$j(93,1,7);O0_.j7J(27);var B6g=O0_.a$j(9,8);j7p[S2R][Q$a + U9f.name]=G2Y * (j7p[S2R][n2T] / n15 - B6g);}}};Z4Y.Studies.studyLibrary=Z4Y.extend(Z4Y.Studies.studyLibrary,{Disparity:{name:t9E,calculateFN:Z4Y.Studies.calculateDisparity,inputs:{Period:14,Field:"field","Moving Average Type":"ma"}}});}};f8=M6w=>{var b7v=f3BGj;b7v.f3X();var b7h,F9Z;b7h=typeof _CIQ !== "undefined"?_CIQ:M6w.CIQ;if(!b7h.Studies){console.error("easeOfMovement feature requires first activating studies feature.");}else {F9Z="Ea";F9Z+="se of ";F9Z+="M";F9Z+="ovement";b7h.Studies.calculateEaseOfMovement=function(k$G,T$l){var h3s,f$h,Z9u,k6t,j2n,n4G;h3s=T$l.chart.scrubbed;b7v.f3X();if(h3s.length < T$l.days){T$l.error=!0;return;}for(var H93=Math.max(1,T$l.startFrom);H93 < h3s.length;H93++){b7v.N_M(56);var f0e=b7v.a$j(5,32,16,5);f$h=(h3s[H93].High + h3s[H93].Low) / f0e;b7v.j7J(1);var J0n=b7v.c0C(46,18);b7v.j7J(44);var J6X=b7v.c0C(2,14,237,15);b7v.N_M(3);var V4N=b7v.a$j(18,9,11);Z9u=(h3s[H93 - ("1" >> J0n)].High + h3s[H93 - J6X].Low) / V4N;b7v.N_M(14);k6t=b7v.c0C(f$h,Z9u);b7v.j7J(17);var U_O=b7v.c0C(1900000191,20,100000009,11);j2n=h3s[H93].Volume / U_O / (h3s[H93].High - h3s[H93].Low);b7v.j7J(7);n4G=b7v.c0C(k6t,j2n);if(!isFinite(n4G)){h3s[H93]["_EOM1 " + T$l.name]=NaN;}else {h3s[H93]["_EOM1 " + T$l.name]=n4G;}}b7h.Studies.MA(T$l.inputs["Moving Average Type"],T$l.days,"_EOM1 " + T$l.name,0,"Result",k$G,T$l);};b7h.Studies.studyLibrary=b7h.extend(b7h.Studies.studyLibrary,{EOM:{name:F9Z,calculateFN:b7h.Studies.calculateEaseOfMovement,inputs:{Period:14,"Moving Average Type":"ma"}}});}};A3=M_J=>{var l2I=f3BGj;var r0J,y3v;r0J="u";r0J+="ndefined";l2I.T$X();y3v=typeof _CIQ !== r0J?_CIQ:M_J.CIQ;if(!y3v.Studies){console.error("ehlerFisher feature requires first activating studies feature.");}else {y3v.Studies.calculateEhlerFisher=function(S4a,o87){var n2j,W_l,k9x,o8y,Y_l,p1z,o2D;n2j=o87.chart.scrubbed;if(n2j.length < o87.days + 1){o87.error=!"";return;}l2I.N_M(4);W_l=l2I.c0C("0",0);function S8S(H1W,i3J){var h7I,H0l,y54,V2g,x1D,h0K;h7I=-428939658;H0l=-1778201131;y54=2;for(var a8I=1;l2I.S9Y(a8I.toString(),a8I.toString().length,+"25159") !== h7I;a8I++){V2g=Number.MAX_VALUE;l2I.N_M(128);var H9w=l2I.c0C(4,1,8,2,9);x1D=Number.MAX_VALUE * H9w;y54+=2;}if(l2I.S9Y(y54.toString(),y54.toString().length,32314) !== H0l){V2g=Number.MAX_VALUE;l2I.j7J(129);var u8Y=l2I.a$j(11,1763,6,10,17);x1D=Number.MAX_VALUE - !u8Y;}for(var x8y=i3J - H1W + 1;x8y <= i3J;x8y++){l2I.N_M(68);var n_Y=l2I.a$j(18,1,0,16);h0K=(n2j[x8y].High + n2j[x8y].Low) / n_Y;V2g=Math.min(V2g,h0K);x1D=Math.max(x1D,h0K);}return [V2g,x1D];}if(o87.startFrom > "1" << 0){l2I.N_M(1);var R3w=l2I.c0C(0,1);W_l=n2j[o87.startFrom - R3w]["_n " + o87.name];}for(var h0o=o87.startFrom;h0o < n2j.length;h0o++){k9x="E";k9x+="F";k9x+=" Trigge";k9x+="r ";o8y=n2j[h0o];if(o8y.futureTick)break;if(h0o < o87.days - 1){Y_l="E";Y_l+="F";Y_l+=" ";o8y[Y_l + o87.name]=o8y["EF Trigger " + o87.name]=W_l;continue;}p1z=S8S(o87.days,h0o);l2I.N_M(1);var Q0Z=l2I.a$j(0,2);l2I.j7J(130);var m7k=l2I.a$j(10,12,3,23,5);l2I.j7J(102);var p2R=l2I.c0C(19,7,20,5);l2I.j7J(131);var c6A=l2I.a$j(14,18,1681,20,3);W_l=0.33 * Q0Z * (((n2j[h0o].High + n2j[h0o].Low) / m7k - p1z[0]) / Math.max(0.000001,p1z[p2R] - p1z[0]) - 0.5) + "0.67" * c6A * W_l;if(W_l > 0){W_l=Math.min(W_l,0.9999);}else if(W_l < 0){W_l=Math.max(W_l,-0.9999);}o2D=h0o?n2j[h0o - 1]["EF " + o87.name]:"0" | 0;l2I.j7J(17);var S7L=l2I.c0C(122,9,12,15);l2I.N_M(14);var w3g=l2I.a$j(1,0);o8y["EF " + o87.name]=0.5 * Math.log((S7L + W_l) / (w3g - W_l)) + 0.5 * o2D;o8y[k9x + o87.name]=o2D;o8y["_n " + o87.name]=W_l;}};y3v.Studies.studyLibrary=y3v.extend(y3v.Studies.studyLibrary,{"Ehler Fisher":{name:"Ehler Fisher Transform",calculateFN:y3v.Studies.calculateEhlerFisher,inputs:{Period:10},outputs:{EF:"auto","EF Trigger":"#FF0000"}}});}};b0=C4O=>{var r7W=f3BGj;var f8j,Y2d,R9o,K7s;f8j="u";f8j+="nd";r7W.T$X();f8j+="e";f8j+="fined";Y2d=typeof _CIQ !== f8j?_CIQ:C4O.CIQ;if(!Y2d.Studies){console.error("elder feature requires first activating studies feature.");}else {R9o="#";R9o+="8";R9o+="B";R9o+="C176";K7s="Elder Forc";K7s+="e Index";Y2d.Studies.calculateElderImpulse=function(V4j,H$k){var U_o,Y3t,W$e,M7C,t30,K6_,u0f;U_o=H$k.chart.scrubbed;Y3t=H$k.outputs.Bullish;W$e=H$k.outputs.Bearish;M7C=H$k.outputs.Neutral;Y2d.Studies.MA("exponential",13,"Close",0,"_MA",V4j,H$k);r7W.N_M(55);var E4W=r7W.a$j(10,108790,1078010,1);r7W.j7J(87);var E7M=r7W.a$j(6,83,4721,249,1);r7W.j7J(9);var X1h=r7W.c0C(111334,19,6186);r7W.N_M(14);var H0m=r7W.c0C(19,18);r7W.j7J(68);var t4g=r7W.c0C(6257,890,6249,19);r7W.N_M(14);var L$k=r7W.c0C(8758,18);H$k.macd=new Y2d.Studies.StudyDescriptor(((E4W,E7M) !== ("4340" ^ 0,703.37)?"_":X1h <= ("658.22" * H0m,"5710" ^ 0)?(t4g,L$k):("0x1f98" ^ 0,"A")) + H$k.name,"macd",H$k.panel);H$k.macd.chart=H$k.chart;H$k.macd.days=H$k.days;H$k.macd.startFrom=H$k.startFrom;H$k.macd.inputs={"Fast MA Period":12,"Slow MA Period":26,"Signal Period":+"9"};H$k.macd.outputs={_MACD:null,_Signal:null};Y2d.Studies.calculateMACD(V4j,H$k.macd);for(var e1L=H$k.startFrom;e1L < U_o.length;e1L++){K6_="_h";K6_+="i";K6_+="s";K6_+="t";u0f="_M";u0f+="A";u0f+=" ";if(e1L === 0){t30=M7C;}else if(U_o[e1L]["_MA " + H$k.name] > U_o[e1L - +"1"]["_MA " + H$k.name] && U_o[e1L][(270 <= 5236?"_":(9.83e+3,!!({}))) + H$k.name + "_hist"] > U_o[e1L - 1][(7980 != ("425.35" - 0,3440)?"_":8970 < 2030?(6.18e+3,127.14):8300 >= (3683,2280)?7.91e+3:272.07) + H$k.name + "_hist"]){t30=Y3t;}else if(U_o[e1L]["_MA " + H$k.name] < U_o[e1L - 1][u0f + H$k.name] && U_o[e1L][(("7728" ^ 0) <= 543.24?3.23e+3:(8462,8613) === (+"214",210.2)?(8.09e+3,0x1b68):("219" >> 64,792.17) > (262.61,6060)?(!!1,0x701):"_") + H$k.name + K6_] < U_o[e1L - ("1" - 0)]["_" + H$k.name + "_hist"]){t30=W$e;}else {t30=M7C;}U_o[e1L]["Result " + H$k.name]=t30;;}};Y2d.Studies.calculateElderRay=function(W5Q,K4i){var C4V,u7J;C4V="_";C4V+="his";r7W.T$X();C4V+="t";C4V+="1";u7J=K4i.chart.scrubbed;if(u7J.length < K4i.days){K4i.error=!!({});return;}Y2d.Studies.MA("exponential",K4i.days,"Close",0,"_EMA",W5Q,K4i);for(var X56=Math.max(K4i.startFrom,K4i.days - +"1");X56 < u7J.length;X56++){u7J[X56][K4i.name + "_hist1"]=u7J[X56].High - u7J[X56]["_EMA " + K4i.name];u7J[X56][K4i.name + "_hist2"]=u7J[X56].Low - u7J[X56]["_EMA " + K4i.name];}K4i.outputMap={};K4i.outputMap[K4i.name + C4V]="";K4i.outputMap[K4i.name + "_hist2"]="";};Y2d.Studies.calculateElderForce=function(y9$,A$q){var W0f,Y3u;W0f="_EF1";W0f+=" ";Y3u=A$q.chart.scrubbed;if(Y3u.length < A$q.days){A$q.error=!0;return;}for(var V_F=Math.max(1,A$q.startFrom);V_F < Y3u.length;V_F++){r7W.j7J(3);var l6o=r7W.c0C(9,6,4);Y3u[V_F]["_EF1 " + A$q.name]=Y3u[V_F].Volume * (Y3u[V_F].Close - Y3u[V_F - l6o].Close);}Y2d.Studies.MA("exponential",A$q.days,W0f + A$q.name,0,"Result",y9$,A$q);};Y2d.Studies.initElderImpulse=function(h6I,F7y,K2o,e21,S12,y2m){var s7v,i74;s7v="color";s7v+="ed_b";s7v+="ar";i74=Y2d.Studies.initializeFN(h6I,F7y,K2o,e21,S12,y2m);if(S12.calculateOnly){return i74;}h6I.chart.customChart={chartType:s7v,colorFunction:function(Y9O,W2x,o_3){var x2t;x2t=W2x["Result " + i74.name];if(x2t && typeof x2t == "object"){x2t=x2t.color;}return x2t;}};h6I.setMainSeriesRenderer();r7W.f3X();return i74;};Y2d.Studies.displayElderForce=function(X09,o53,V_a){var R7f,S4m,T1e,Y50,b8s;r7W.f3X();R7f="Res";R7f+="ult";R7f+=" ";Y2d.Studies.displaySeriesAsLine(X09,o53,V_a);S4m=Y2d.Studies.determineColor(o53.outputs.Result);T1e=X09.panels[o53.panel];Y50=o53.getYAxis(X09);b8s={skipTransform:T1e.name != o53.chart.name,panelName:o53.panel,band:R7f + o53.name,threshold:+"0",color:S4m,yAxis:Y50};if(!o53.highlight && X09.highlightedDraggable){b8s.opacity=0.3;}b8s.direction=1;Y2d.preparePeakValleyFill(X09,b8s);b8s.direction=-1;Y2d.preparePeakValleyFill(X09,b8s);};Y2d.Studies.displayElderRay=function(b1Y,L7s,M89){var k6I,Q_C,r$W,m3T,d3J,u9D,y0a,R1f,w_j,g7X;k6I=b1Y.panels[L7s.panel];Q_C=L7s.getContext(b1Y);r$W=L7s.getYAxis(b1Y);function I6X(E$V,d7_,D3h,b3V){r7W.f3X();Q_C.fillStyle=Y2d.Studies.determineColor(L7s.outputs[D3h]);Q_C.fillRect(Math.floor(b1Y.pixelFromBar(E$V,k6I.chart) - d3J / 2 + d3J * d7_),Math.floor(m3T),Math.floor(d3J * (1 - +"2" * d7_)),Math.floor(b1Y.pixelFromPrice(g7X[L7s.name + b3V],k6I,r$W) - m3T));}r7W.N_M(4);r7W.f3X();m3T=b1Y.pixelFromPrice(r7W.c0C("0",0),k6I,r$W);r7W.j7J(14);var L9w=r7W.a$j(16,14);d3J=b1Y.layout.candleWidth - L9w;if(d3J < 2){d3J=1;}b1Y.canvasColor("stx_histogram");u9D=Q_C.fillStyle;if(!L7s.underlay){Q_C.globalAlpha=+"1";}b1Y.startClip(L7s.panel);if(!L7s.highlight && b1Y.highlightedDraggable){Q_C.globalAlpha*=0.3;}for(var Y3r=0;Y3r < M89.length;Y3r++){y0a="_hist";y0a+="2";R1f="_h";R1f+="ist1";w_j="_";w_j+="hist1";g7X=M89[Y3r];if(!g7X)continue;if(g7X.candleWidth){d3J=Math.floor(Math.max(1,g7X.candleWidth - ("2" ^ 0)));}if(g7X[L7s.name + w_j] > 0){r7W.j7J(29);I6X(Y3r,r7W.a$j(0,"0"),"Elder Bull Power","_hist1");}if(g7X[L7s.name + "_hist2"] < 0){I6X(Y3r,0,"Elder Bear Power","_hist2");}if(g7X[L7s.name + "_hist1"] < 0){I6X(Y3r,0.1,"Elder Bull Power",R1f);}if(g7X[L7s.name + "_hist2"] > 0){r7W.N_M(14);I6X(Y3r,r7W.a$j("0.1",0),"Elder Bear Power",y0a);}}b1Y.endClip();Q_C.fillStyle=u9D;};Y2d.Studies.studyLibrary=Y2d.extend(Y2d.Studies.studyLibrary,{"Elder Force":{name:K7s,calculateFN:Y2d.Studies.calculateElderForce,seriesFN:Y2d.Studies.displayElderForce,inputs:{Period:13}},"Elder Ray":{name:"Elder Ray Index",seriesFN:Y2d.Studies.displayElderRay,calculateFN:Y2d.Studies.calculateElderRay,centerline:0,inputs:{Period:13},outputs:{"Elder Bull Power":"#00DD00","Elder Bear Power":"#FF0000"}},"Elder Impulse":{name:"Elder Impulse System",calculateFN:Y2d.Studies.calculateElderImpulse,initializeFN:Y2d.Studies.initElderImpulse,seriesFN:null,customRemoval:!![],underlay:!!({}),inputs:{},outputs:{Bullish:R9o,Bearish:"#DD3E39",Neutral:"#5F7CB8"},removeFN:function(K5w,U0v){K5w.chart.customChart=null;K5w.setMainSeriesRenderer();}}});}};j4=q5g=>{var l2d=f3BGj;var r1E,X6T,Y4B,I6x,P4L,k4v,O7C;r1E=typeof _CIQ !== "undefined"?_CIQ:q5g.CIQ;if(!r1E.Studies){X6T=122462410;Y4B=320517448;I6x=2;for(var A9E=1;l2d.O1W(A9E.toString(),A9E.toString().length,"61779" ^ 0) !== X6T;A9E++){console.error("");I6x+=2;}if(l2d.S9Y(I6x.toString(),I6x.toString().length,76585) !== Y4B){console.error("");}console.error("fractalChaos feature requires first activating studies feature.");}else {P4L="a";P4L+="uto";k4v="a";k4v+="uto";O7C="aut";O7C+="o";r1E.Studies.calculateFractalChaos=function(x0E,V3c){var f5W,x$$,C6h,M2p,O5k,L8J,k1P,I7E,h$T,n_H;f5W="Fractal C";f5W+="haos";f5W+=" Band";f5W+="s";x$$=V3c.chart.scrubbed;C6h=0;M2p=0;O5k=0;if(V3c.startFrom && V3c.type == f5W){L8J="F";L8J+="ractal";L8J+=" Low ";l2d.N_M(102);var s9l=l2d.c0C(13,13,17,8);C6h=x$$[V3c.startFrom - s9l]["Fractal High " + V3c.name];l2d.j7J(132);var R_9=l2d.c0C(13,16,9,2,13);M2p=x$$[V3c.startFrom - R_9][L8J + V3c.name];}for(var i49=Math.max("4" ^ 0,V3c.startFrom);i49 < x$$.length;i49++){k1P="F";k1P+="ractal Cha";k1P+="os Ba";k1P+="nds";if(x$$[i49].futureTick)break;I7E=!isNaN(x$$[i49].High);h$T=!isNaN(x$$[i49].Low);if(I7E || h$T){x$$[i49]["Result " + V3c.name]=0;}O5k=0;for(n_H=0;n_H <= i49;n_H++){if(!x$$[i49 - n_H])break;if(x$$[i49 - n_H].High > x$$[i49 - +"2"].High)break;if(n_H < 2 && x$$[i49 - n_H].High == x$$[i49 - 2].High)break;if(x$$[i49 - n_H].High < x$$[i49 - 2].High){O5k++;}if(O5k == 4){C6h=x$$[i49 - 2].High;break;}}if(V3c.type == k1P){if(I7E){x$$[i49]["Fractal High " + V3c.name]=C6h > 0?C6h:null;}}else if(O5k == 4){x$$[i49]["Result " + V3c.name]=1;}l2d.j7J(5);O5k=l2d.c0C(1,"0");for(n_H=+"0";n_H <= i49;n_H++){if(!x$$[i49 - n_H])break;if(x$$[i49 - n_H].Low < x$$[i49 - 2].Low)break;if(n_H < 2 && x$$[i49 - n_H].Low == x$$[i49 - 2].Low)break;if(x$$[i49 - n_H].Low > x$$[i49 - +"2"].Low){O5k++;}if(O5k == 4){M2p=x$$[i49 - +"2"].Low;break;}}if(V3c.type == "Fractal Chaos Bands"){if(h$T){x$$[i49]["Fractal Low " + V3c.name]=M2p > +"0"?M2p:null;}}else if(O5k == +"4"){x$$[i49]["Result " + V3c.name]=-+"1";}}};r1E.Studies.studyLibrary=r1E.extend(r1E.Studies.studyLibrary,{"Fractal Chaos":{name:"Fractal Chaos Oscillator",range:"-1 to 1",calculateFN:r1E.Studies.calculateFractalChaos,inputs:{},centerline:null},"Fractal Chaos Bands":{name:"Fractal Chaos Bands",overlay:!0,calculateFN:r1E.Studies.calculateFractalChaos,seriesFN:r1E.Studies.displayChannel,inputs:{"Channel Fill":!!({})},outputs:{"Fractal High":O7C,"Fractal Low":k4v,"Fractal Channel":P4L}}});}};U1=T5C=>{var C3X,M9Z,F0h,F$E,s_U,a$f,y2b,c$a;C3X="un";C3X+="defined";M9Z=typeof _CIQ !== C3X?_CIQ:T5C.CIQ;if(!M9Z.Studies){console.error("highLowStudies feature requires first activating studies feature.");}else {F0h="Wil";F0h+="liams %R";F$E="Lowest Low ";F$E+="Value";s_U="Highest High V";s_U+="alu";s_U+="e";a$f="a";a$f+="u";a$f+="t";a$f+="o";y2b="a";y2b+="u";y2b+="t";y2b+="o";c$a="au";c$a+="t";c$a+="o";M9Z.Studies.calculateMaxHighMinLow=function(a8Z,X4J){var K92=f3BGj;var K3Z,C2Q,U_0,J8r,S4g,H8n,U5w,f5g,l8Q,H0n,c3x,t$u,g6E;K3Z="Low Peri";K3Z+="od";C2Q="Hi";C2Q+="gh Pe";C2Q+="rio";C2Q+="d";U_0="High";U_0+=" Period";J8r=X4J.chart.scrubbed;S4g=X4J.days;H8n=X4J.days;if(X4J.inputs[U_0]){S4g=X4J.inputs[C2Q];}if(X4J.inputs[K3Z]){H8n=X4J.inputs["Low Period"];}if(J8r.length < Math.max(S4g,H8n) + +"1"){X4J.error=!![];return;}U5w=Number.MAX_VALUE;K92.j7J(14);var w3A=K92.a$j(0,1);f5g=Number.MAX_VALUE * w3A;if(X4J.startFrom > 1){for(l8Q=1;l8Q < S4g;l8Q++){if(X4J.startFrom - l8Q >= 0){f5g=Math.max(f5g,J8r[X4J.startFrom - l8Q].High);}}for(l8Q=1;l8Q < H8n;l8Q++){if(X4J.startFrom - l8Q >= 0){U5w=Math.min(U5w,J8r[X4J.startFrom - l8Q].Low);}}}for(var n9X=Math.max(0,X4J.startFrom - 1);n9X < J8r.length;n9X++){H0n="VT HZ";H0n+=" ";H0n+="Fi";H0n+="lter";f5g=Math.max(f5g,J8r[n9X].High);U5w=Math.min(U5w,J8r[n9X].Low);if(n9X >= S4g){if(J8r[n9X - S4g].High == f5g){f5g=J8r[n9X].High;for(l8Q=1;l8Q < S4g;l8Q++){f5g=Math.max(f5g,J8r[n9X - l8Q].High);}}}if(n9X >= H8n){if(J8r[n9X - H8n].Low == U5w){U5w=J8r[n9X].Low;for(l8Q=1;l8Q < H8n;l8Q++){U5w=Math.min(U5w,J8r[n9X - l8Q].Low);}}}c3x=0;if(X4J.type == "HHV"){c3x=f5g;}else if(X4J.type == "LLV"){c3x=U5w;}else if(X4J.type == "Donchian Width"){K92.N_M(14);c3x=K92.c0C(f5g,U5w);}else if(X4J.type == "GAPO" || X4J.type == "Gopala"){c3x=Math.log(f5g - U5w) / Math.log(H8n);}else if(X4J.type == H0n){K92.j7J(14);c3x=K92.c0C(f5g,U5w);J8r[n9X]["_MHML " + X4J.name]=c3x;continue;}else if(X4J.type == "Williams %R"){K92.j7J(133);var s7h=K92.c0C(20,17,22,18,93);c3x=s7h * (f5g - J8r[n9X].Close) / (f5g - U5w);J8r[n9X]["Result " + X4J.name]=c3x;continue;}if(n9X == J8r.length - "1" * 1)break;if(!J8r[n9X + 1].futureTick){t$u="Donchian";t$u+=" Channel";if(X4J.type == t$u){g6E="Donchian";g6E+=" Median ";K92.N_M(1);J8r[K92.a$j(n9X,1)]["Donchian High " + X4J.name]=f5g;K92.N_M(1);J8r[K92.c0C(n9X,1)]["Donchian Low " + X4J.name]=U5w;K92.j7J(1);J8r[K92.c0C(n9X,1)][g6E + X4J.name]=K92.a$j(U5w,f5g,2,K92.N_M(2));}else {K92.N_M(1);J8r[K92.a$j(n9X,1)]["Result " + X4J.name]=c3x;}}}};M9Z.Studies.calculateVerticalHorizontalFilter=function(r3B,a$9){var x7L,a7Y,N2V,H8D;x7L=a$9.chart.scrubbed;if(x7L.length < a$9.days + 1){a$9.error=!!"1";return;}a$9.mhml=new M9Z.Studies.StudyDescriptor(a$9.name,a$9.type,a$9.panel);a$9.mhml.chart=a$9.chart;a$9.mhml.days=a$9.days;a$9.mhml.startFrom=a$9.startFrom;a$9.mhml.inputs={};a$9.mhml.outputs={_MHML:null};M9Z.Studies.calculateMaxHighMinLow(r3B,a$9.mhml);a7Y=0;N2V=[];for(var G_W=Math.max(1,a$9.startFrom - a$9.days);G_W < x7L.length;G_W++){H8D=Math.abs(x7L[G_W].Close - x7L[G_W - 1].Close);N2V.push(H8D);a7Y+=H8D;if(N2V.length == a$9.days){x7L[G_W]["Result " + a$9.name]=x7L[G_W]["_MHML " + a$9.name] / a7Y;a7Y-=N2V.shift();}}};M9Z.Studies.studyLibrary=M9Z.extend(M9Z.Studies.studyLibrary,{"Donchian Channel":{name:"Donchian Channel",overlay:!"",calculateFN:M9Z.Studies.calculateMaxHighMinLow,seriesFN:M9Z.Studies.displayChannel,inputs:{"High Period":"20" ^ 0,"Low Period":+"20","Channel Fill":!!({})},outputs:{"Donchian High":c$a,"Donchian Median":y2b,"Donchian Low":a$f}},"Donchian Width":{name:"Donchian Width",calculateFN:M9Z.Studies.calculateMaxHighMinLow,inputs:{"High Period":20,"Low Period":20}},GAPO:{name:"Gopalakrishnan Range Index",calculateFN:M9Z.Studies.calculateMaxHighMinLow},HHV:{name:s_U,calculateFN:M9Z.Studies.calculateMaxHighMinLow,inputs:{Period:+"14"}},LLV:{name:F$E,calculateFN:M9Z.Studies.calculateMaxHighMinLow,inputs:{Period:14}},"Williams %R":{name:F0h,calculateFN:M9Z.Studies.calculateMaxHighMinLow,inputs:{Period:14},parameters:{init:{studyOverZonesEnabled:!!1,studyOverBoughtValue:-20,studyOverBoughtColor:"auto",studyOverSoldValue:-80,studyOverSoldColor:"auto"}}},"VT HZ Filter":{name:"Vertical Horizontal Filter",calculateFN:M9Z.Studies.calculateVerticalHorizontalFilter,inputs:{Period:28}},"High-Low":{name:"High Minus Low",calculateFN:function(N6p,N6E){var f$y;f$y=N6E.chart.scrubbed;for(var E8y=N6E.startFrom;E8y < f$y.length;E8y++){f$y[E8y]["Result " + N6E.name]=f$y[E8y].High - f$y[E8y].Low;}},inputs:{}}});}};W2=t2a=>{var j5B,w8F,a3t,t$4;j5B=typeof _CIQ !== "undefined"?_CIQ:t2a.CIQ;if(!j5B.Studies){console.error("ichimoku feature requires first activating studies feature.");}else {w8F="#";w8F+="808";w8F+="000";a3t="#FF";a3t+="0000";t$4="I";t$4+="chimoku Clouds";j5B.Studies.calculateIchimoku=function(j5S,n5d){var N1i=f3BGj;var V0H,h02,r7V,i0I,g9x,T76,m$T,X_d,w5r,I2y,Y6C,h0f,A9j;V0H="La";V0H+="gging Span Perio";V0H+="d";h02=n5d.chart.scrubbed;r7V={Base:Number(n5d.inputs["Base Line Period"]),Conv:Number(n5d.inputs["Conversion Line Period"]),LeadB:Number(n5d.inputs["Leading Span B Period"]),Lag:Number(n5d.inputs[V0H])};for(i0I=n5d.startFrom;i0I < h02.length;i0I++){T76="La";T76+="gging Span ";m$T="Conve";m$T+="rsion Line";m$T+=" ";if(!h02[i0I])continue;g9x=o_H(r7V.Conv,i0I);N1i.N_M(134);var R5P=N1i.a$j(7,4,8,4);N1i.N_M(122);var X7r=N1i.c0C(22,18,2,18);h02[i0I][m$T + n5d.name]=(g9x["1" - 0] + g9x["0" * R5P]) / X7r;g9x=o_H(r7V.Base,i0I);N1i.N_M(66);var V6k=N1i.c0C(18,12,6,35);N1i.j7J(44);var C1m=N1i.a$j(18,19,340,0);h02[i0I]["Base Line " + n5d.name]=(g9x[V6k] + g9x[0]) / C1m;if(i0I < r7V.Lag)continue;h02[i0I - r7V.Lag][T76 + n5d.name]=h02[i0I].Close;}X_d=[];for(i0I=Math.max(0,n5d.startFrom - r7V.Base);i0I < h02.length;i0I++){g9x=o_H(r7V.LeadB,i0I);N1i.j7J(27);var r$5=N1i.c0C(13,11);w5r=(h02[i0I]["Conversion Line " + n5d.name] + h02[i0I]["Base Line " + n5d.name]) / r$5;N1i.N_M(17);var i9I=N1i.a$j(127,10,11,18);I2y=(g9x[i9I] + g9x[0]) / +"2";if(h02[i0I + r7V.Base]){Y6C="Leadin";Y6C+="g";Y6C+=" Span";Y6C+=" A ";h02[i0I + r7V.Base][Y6C + n5d.name]=w5r;h02[i0I + r7V.Base]["Leading Span B " + n5d.name]=I2y;}else {h0f="Lead";h0f+="ing Span A ";A9j={};A9j[h0f + n5d.name]=w5r;A9j["Leading Span B " + n5d.name]=I2y;X_d.push(A9j);}}n5d.appendFutureTicks(j5S,X_d);function o_H(C_g,R2S){var S8O,Z5y;N1i.T$X();S8O=Number.MAX_VALUE;N1i.N_M(68);var c2w=N1i.c0C(4,5,0,15);Z5y=Number.MAX_VALUE * -("1" * c2w);for(var E0q=R2S - C_g + 1;E0q <= R2S;E0q++){if(E0q < 0)continue;S8O=Math.min(S8O,h02[E0q].Low);Z5y=Math.max(Z5y,h02[E0q].High);}return [S8O,Z5y];}};j5B.Studies.displayIchimoku=function(U9p,n0N,M69){var j82,g5T,g9y,R_L,s1B,A2u,M1E,z17;j82="L";j82+="eadi";j82+="ng Span A ";g5T=j82 + n0N.name;g9y="Leading Span B " + n0N.name;R_L=j5B.Studies.determineColor(n0N.outputs[n0N.outputMap[g5T]]);s1B=j5B.Studies.determineColor(n0N.outputs[n0N.outputMap[g9y]]);A2u=U9p.panels[n0N.panel];M1E=n0N.getYAxis(U9p);z17={topBand:g5T,bottomBand:g9y,topColor:R_L,bottomColor:s1B,skipTransform:A2u.name != n0N.chart.name,topAxis:M1E,bottomAxis:M1E,opacity:0.3};if(!n0N.highlight && U9p.highlightedDraggable){f3BGj.N_M(5);z17.opacity*=f3BGj.a$j(1,"0.3");}j5B.fillIntersecting(U9p,n0N.panel,z17);j5B.Studies.displaySeriesAsLine(U9p,n0N,M69);};j5B.Studies.studyLibrary=j5B.extend(j5B.Studies.studyLibrary,{"Ichimoku Clouds":{name:t$4,overlay:!!({}),calculateFN:j5B.Studies.calculateIchimoku,seriesFN:j5B.Studies.displayIchimoku,inputs:{"Conversion Line Period":9,"Base Line Period":26,"Leading Span B Period":52,"Lagging Span Period":+"26"},outputs:{"Conversion Line":"#0000FF","Base Line":"#FF0000","Leading Span A":"#00FF00","Leading Span B":a3t,"Lagging Span":w8F}}});}};K0=L0y=>{var q$d,p6D,l8b;q$d=typeof _CIQ !== "undefined"?_CIQ:L0y.CIQ;if(!q$d.Studies){console.error("intradayMomentum feature requires first activating studies feature.");}else {p6D="a";p6D+="u";p6D+="t";p6D+="o";l8b="a";l8b+="u";l8b+="to";q$d.Studies.calculateIntradayMomentum=function(I_8,D_5){var E9s=f3BGj;var R3q,z0X,T8e,s0H,y_x,q1j,Q3C;R3q=D_5.chart.scrubbed;z0X=D_5.days;if(R3q.length < z0X + 1){D_5.error=!![];return;}E9s.N_M(46);T8e=E9s.c0C("0",0);s0H=0;if(D_5.startFrom > 1){y_x="_totDn";y_x+=" ";E9s.N_M(34);var M5N=E9s.c0C(4,2,6);T8e=R3q[D_5.startFrom - M5N]["_totUp " + D_5.name];E9s.N_M(135);var S6B=E9s.a$j(2,1,20,21);s0H=R3q[D_5.startFrom - S6B][y_x + D_5.name];}for(var u4t=D_5.startFrom;u4t < R3q.length;u4t++){q1j=R3q[u4t].Close - R3q[u4t].Open;if(q1j > 0){T8e+=q1j;}else {s0H-=q1j;}if(u4t >= z0X){Q3C=R3q[u4t - z0X].Close - R3q[u4t - z0X].Open;if(Q3C > 0){T8e-=Q3C;}else {s0H+=Q3C;}}E9s.j7J(136);R3q[u4t]["Result " + D_5.name]=E9s.a$j(T8e,s0H,T8e,"100");R3q[u4t]["_totUp " + D_5.name]=T8e;R3q[u4t]["_totDn " + D_5.name]=s0H;}};q$d.Studies.studyLibrary=q$d.extend(q$d.Studies.studyLibrary,{"Intraday Mtm":{name:"Intraday Momentum Index",calculateFN:q$d.Studies.calculateIntradayMomentum,inputs:{Period:20},parameters:{init:{studyOverZonesEnabled:!!"1",studyOverBoughtValue:70,studyOverBoughtColor:l8b,studyOverSoldValue:30,studyOverSoldColor:p6D}}}});}};G_=B6D=>{f3BGj.f3X();var Z$$,h2d,K9M;Z$$=typeof _CIQ !== "undefined"?_CIQ:B6D.CIQ;if(!Z$$.Studies){console.error("keltner feature requires first activating studies feature.");}else {h2d="au";h2d+="t";h2d+="o";K9M="Ke";K9M+="ltner Cha";K9M+="nnel";Z$$.Studies.calculateKeltner=function(Z5B,S1v){var C$_,B4d,l0N;C$_="ATR";C$_+=" ";B4d="M";B4d+="A";l0N="Mo";f3BGj.f3X();l0N+="ving Average Type";Z$$.Studies.MA(S1v.inputs[l0N],S1v.days,"Close",0,B4d,Z5B,S1v);Z$$.Studies.calculateStudyATR(Z5B,S1v);Z$$.Studies.calculateGenericEnvelope(Z5B,S1v,S1v.inputs.Shift,"MA " + S1v.name,C$_ + S1v.name);};Z$$.Studies.studyLibrary=Z$$.extend(Z$$.Studies.studyLibrary,{Keltner:{name:K9M,overlay:!!({}),seriesFN:Z$$.Studies.displayChannel,calculateFN:Z$$.Studies.calculateKeltner,inputs:{Period:50,Shift:5,"Moving Average Type":"ema","Channel Fill":!![]},outputs:{"Keltner Top":h2d,"Keltner Median":"auto","Keltner Bottom":"auto"},attributes:{Shift:{min:0.1,step:0.1}}}});}};T8=m_l=>{var R3l,D$$;R3l=typeof _CIQ !== "undefined"?_CIQ:m_l.CIQ;if(!R3l.Studies){console.error("klinger feature requires first activating studies feature.");}else {D$$="#";D$$+="FF00";D$$+="0";D$$+="0";R3l.Studies.calculateKlinger=function(X3d,J2x){var d9S,Y89,m$M,K0Z,l0n,F$Y,B$Z,f4e,x8r,W1w,r9p,X1L,W_7,K8G,K7D,L1h,P5X,U5k,E0h;d9S="Sig";d9S+="nal Peri";d9S+="ods";Y89="expo";Y89+="nential";m$M="expon";m$M+="ential";K0Z="_EM";K0Z+="A";K0Z+="-S";l0n="_EMA";l0n+="-";l0n+="S ";F$Y="K";F$Y+="lingerSig";F$Y+="na";F$Y+="l ";B$Z="_";B$Z+="his";B$Z+="t";f4e=J2x.chart.scrubbed;x8r=Number(J2x.inputs["Short Cycle"]);W1w=Number(J2x.inputs["Long Cycle"]);if(f4e.length < Math.max(x8r,W1w) + 1){J2x.error=!!({});return;}f3BGj.T$X();r9p=J2x.name + B$Z;X1L="Klinger " + J2x.name;W_7=F$Y + J2x.name;K8G="_SV " + J2x.name;K7D=l0n + J2x.name;L1h="_EMA-L " + J2x.name;for(P5X=Math.max(1,J2x.startFrom);P5X < f4e.length;P5X++){U5k="hlc/";U5k+="3";E0h=f4e[P5X].Volume;if(f4e[P5X]["hlc/3"] < f4e[P5X - 1][U5k]){E0h*=-+"1";}if(E0h){f4e[P5X][K8G]=E0h;}}R3l.Studies.MA("exponential",x8r,K8G,+"0",K0Z,X3d,J2x);R3l.Studies.MA(m$M,W1w,K8G,0,"_EMA-L",X3d,J2x);for(P5X=Math.max(W1w,J2x.startFrom);P5X < f4e.length;P5X++){if(f4e[P5X].futureTick || f4e[P5X][K7D] === null || f4e[P5X][L1h] === null)break;f4e[P5X][X1L]=f4e[P5X][K7D] - f4e[P5X][L1h];}R3l.Studies.MA(Y89,Number(J2x.inputs[d9S]),X1L,0,"KlingerSignal",X3d,J2x);for(P5X=J2x.startFrom;P5X < f4e.length;P5X++){f4e[P5X][r9p]=f4e[P5X][X1L] - f4e[P5X][W_7];}J2x.outputMap[r9p]="";};R3l.Studies.studyLibrary=R3l.extend(R3l.Studies.studyLibrary,{Klinger:{name:"Klinger Volume Oscillator",seriesFN:R3l.Studies.displayHistogramWithSeries,calculateFN:R3l.Studies.calculateKlinger,inputs:{"Signal Periods":"13" - 0,"Short Cycle":34,"Long Cycle":55},outputs:{Klinger:"auto",KlingerSignal:D$$,"Increasing Bar":"#00DD00","Decreasing Bar":"#FF0000"}}});}};d8=e5D=>{var p6w,J1p,H$R,y06,A5a,M9y,p1o,D7w;p6w=typeof _CIQ !== "undefined"?_CIQ:e5D.CIQ;if(!p6w.Studies){console.error("linearRegression feature requires first activating studies feature.");}else {J1p="f";J1p+="ie";J1p+="l";J1p+="d";H$R="Linear";H$R+=" Reg ";H$R+="Forecast";y06="TimeSe";y06+="ries";A5a="ti";A5a+="me";A5a+=" s";A5a+="eries";M9y="t";M9y+="ime seri";M9y+="es";p1o="ts";p1o+="m";p1o+="a";D7w="time";D7w+=" series";p6w.Studies.prettify[D7w]=p1o;p6w.Studies.movingAverage.conversions.tsma=M9y;p6w.Studies.movingAverage.translations["time series"]="Time Series";p6w.Studies.movingAverage.typeMap.tsma="TimeSeries";p6w.Studies.movingAverage.typeMap[A5a]=y06;p6w.Studies.calculateMovingAverageTimeSeries=function(R3S,h4l){var Q2j=f3BGj;var i_V,H8o,k1e,L96,S07,I5d,G$j,d4Y,C0J,E0p,T9W;i_V="m";i_V+="a";h4l.ma=new p6w.Studies.StudyDescriptor(h4l.name,i_V,h4l.panel);h4l.ma.chart=h4l.chart;h4l.ma.days=h4l.days;h4l.ma.startFrom=h4l.startFrom;h4l.ma.inputs=h4l.inputs;p6w.Studies.calculateLinearRegressionIndicator(R3S,h4l.ma);H8o=h4l.name;for(var R_z in h4l.outputs){Q2j.N_M(82);H8o=Q2j.c0C(H8o,(1730,"6450" ^ 0) < 3310?8.20e+3:" ",R_z);}k1e=parseInt(h4l.inputs.Offset,10);if(isNaN(k1e)){k1e=0;}L96=h4l.chart.scrubbed;Q2j.f3X();S07=k1e;for(var b1I=h4l.startFrom - 1;b1I >= 0;b1I--){I5d=L96[b1I][H8o];if(!I5d && I5d !== +"0")continue;if(S07 > 0){S07--;continue;}break;}G$j=[];for(b1I++;b1I < L96.length;b1I++){d4Y=L96[b1I];if(b1I + k1e >= "0" << 64){C0J="Fo";C0J+="r";C0J+="ecast ";if(b1I + k1e < L96.length){Q2j.N_M(1);L96[Q2j.a$j(b1I,k1e)][H8o]=d4Y[C0J + h4l.name];}else {E0p="Fo";E0p+="re";E0p+="cas";E0p+="t ";T9W={};T9W[H8o]=d4Y[E0p + h4l.name];G$j.push(T9W);}}}h4l.appendFutureTicks(R3S,G$j);};p6w.Studies.calculateLinearRegressionIndicator=function(S7g,o1o){var e1h=f3BGj;var G4d,t8v,j7D,h26,k8s,b9r,u3q,d0c,b1C,D8C,T0M,j2Z,b4d,i3g,d0l,P2y;G4d="Cl";G4d+="ose";t8v=o1o.chart.scrubbed;if(t8v.length < o1o.days + 1){o1o.error=!!({});return;}e1h.T$X();j7D=o1o.inputs.Field;if(!j7D || j7D == "field"){j7D=G4d;}e1h.j7J(14);var G6t=e1h.c0C(4,3);e1h.j7J(3);var S9K=e1h.a$j(0,2,0);h26=o1o.days * (o1o.days + G6t) / S9K;k8s=Math.pow(h26,2);e1h.N_M(15);var W6J=e1h.a$j(0,10,9);e1h.N_M(137);var X7G=e1h.c0C(9,13,9,10);b9r=h26 * (+"2" * o1o.days + W6J) / X7G;u3q=0;d0c=0;b1C=+"0";if(o1o.startFrom){D8C="_";D8C+="s";D8C+="ums";D8C+=" ";e1h.N_M(14);var Z9D=e1h.a$j(1,0);T0M=t8v[o1o.startFrom - Z9D][D8C + o1o.name];if(T0M){d0c=T0M[0];u3q=T0M[1];b1C=T0M[2];}}for(var K3j=o1o.startFrom;K3j < t8v.length;K3j++){j2Z=t8v[K3j][j7D];if(j2Z && typeof j2Z == "object"){j2Z=j2Z[o1o.subField];}if(!j2Z && j2Z !== ("0" ^ 0))continue;d0c+=o1o.days * j2Z - u3q;u3q+=j2Z;b1C+=Math.pow(j2Z,2);if(K3j < o1o.days - 1)continue;else if(K3j > o1o.days - 1){b4d=t8v[K3j - o1o.days][j7D];if(b4d && typeof b4d == "object"){b4d=b4d[o1o.subField];}if(!b4d && b4d !== 0)continue;u3q-=b4d;b1C-=Math.pow(b4d,2);}i3g=(o1o.days * d0c - h26 * u3q) / (o1o.days * b9r - k8s);t8v[K3j]["Slope " + o1o.name]=i3g;d0l=(u3q - i3g * h26) / o1o.days;t8v[K3j]["Intercept " + o1o.name]=d0l;t8v[K3j]["Forecast " + o1o.name]=d0l + i3g * o1o.days;e1h.N_M(122);var N_d=e1h.a$j(0,2,1,4);P2y=(o1o.days * b9r - k8s) / (o1o.days * b1C - Math.pow(u3q,N_d));e1h.N_M(138);t8v[K3j]["RSquared " + o1o.name]=e1h.c0C(i3g,P2y,i3g);t8v[K3j]["_sums " + o1o.name]=[d0c,u3q,b1C];}};p6w.Studies.studyLibrary=p6w.extend(p6w.Studies.studyLibrary,{"Lin Fcst":{name:H$R,overlay:!"",calculateFN:p6w.Studies.calculateLinearRegressionIndicator,inputs:{Period:14,Field:"field"},outputs:{Forecast:"auto"}},"Lin Incpt":{name:"Linear Reg Intercept",overlay:!0,calculateFN:p6w.Studies.calculateLinearRegressionIndicator,inputs:{Period:14,Field:J1p},outputs:{Intercept:"auto"}},"Lin R2":{name:"Linear Reg R2",calculateFN:p6w.Studies.calculateLinearRegressionIndicator,inputs:{Period:14,Field:"field"},outputs:{RSquared:"auto"}},"LR Slope":{name:"Linear Reg Slope",calculateFN:p6w.Studies.calculateLinearRegressionIndicator,inputs:{Period:14,Field:"field"},outputs:{Slope:"auto"}},"Time Fcst":{name:"Time Series Forecast",overlay:!![],calculateFN:p6w.Studies.calculateLinearRegressionIndicator,inputs:{Period:+"14",Field:"field"},outputs:{Forecast:"auto"}}});}};T6=X2q=>{var I5V,n26,Z3I;I5V="undefin";I5V+="e";I5V+="d";n26=typeof _CIQ !== I5V?_CIQ:X2q.CIQ;if(!n26.Studies){console.error("macd feature requires first activating studies feature.");}else {Z3I="#FF0";Z3I+="000";n26.Studies.calculateMACD=function(G0U,s6p){var Y4t=f3BGj;var r0C,o0o,S5G,R3e,J9T,u3o,P4U,F3w,J63,h0N,G0Z,G8j,h_B,r5e,D9j,h$f;r0C="_h";r0C+="i";r0C+="s";r0C+="t";o0o="exponent";o0o+="i";o0o+="a";o0o+="l";S5G="Signal Pe";S5G+="riod";R3e="Sl";R3e+="ow MA Period";J9T="Fast M";J9T+="A Perio";J9T+="d";u3o=s6p.chart.scrubbed;P4U=s6p.inputs;F3w=s6p.name;if(!s6p.macd1Days){s6p.macd1Days=parseFloat(P4U[J9T]);}if(!s6p.macd2Days){s6p.macd2Days=parseFloat(P4U[R3e]);}if(!s6p.signalDays){s6p.signalDays=parseFloat(P4U[S5G]);}if(!s6p.days){s6p.days=Math.max(s6p.macd1Days,s6p.macd2Days,s6p.signalDays);}if(u3o.length < s6p.days + 1){s6p.error=!0;return;}J63=s6p.inputs.Field;if(!J63 || J63 == "field"){J63="Close";}h0N=P4U["Moving Average Type"];if(!h0N){h0N=o0o;}n26.Studies.MA(h0N,s6p.macd1Days,J63,0,"_MACD1",G0U,s6p);n26.Studies.MA(h0N,s6p.macd2Days,J63,"0" - 0,"_MACD2",G0U,s6p);h_B=Math.max(s6p.startFrom,s6p.days - 1);for(G0Z=h_B;G0Z < u3o.length;G0Z++){G8j=u3o[G0Z];if((G8j["_MACD1 " + F3w] || G8j["_MACD1 " + F3w] === 0) && (G8j["_MACD2 " + F3w] || G8j["_MACD2 " + F3w] === 0)){Y4t.N_M(1);G8j[Y4t.c0C("MACD ",F3w)]=G8j["_MACD1 " + F3w] - G8j["_MACD2 " + F3w];}}r5e=P4U["Signal MA Type"];if(!r5e){r5e="exponential";}n26.Studies.MA(r5e,s6p.signalDays,"MACD " + F3w,0,"Signal",G0U,s6p);Y4t.N_M(1);D9j=Y4t.c0C(F3w,r0C);for(G0Z=h_B;G0Z < u3o.length;G0Z++){G8j=u3o[G0Z];Y4t.j7J(1);h$f=G8j[Y4t.c0C("Signal ",F3w)];if(!h$f && h$f !== 0)continue;G8j[D9j]=G8j["MACD " + F3w] - G8j["Signal " + F3w];}s6p.outputMap[D9j]="";};n26.Studies.studyLibrary=n26.extend(n26.Studies.studyLibrary,{macd:{name:"MACD",calculateFN:n26.Studies.calculateMACD,seriesFN:n26.Studies.displayHistogramWithSeries,inputs:{"Fast MA Period":12,"Slow MA Period":26,"Signal Period":+"9"},outputs:{MACD:"auto",Signal:Z3I,"Increasing Bar":"#00DD00","Decreasing Bar":"#FF0000"}}});}};k1=v$V=>{var X30=f3BGj;var q18,z4T,v2X,R$R;X30.T$X();q18=typeof _CIQ !== "undefined"?_CIQ:v$V.CIQ;if(!q18.Studies){console.error("massIndex feature requires first activating studies feature.");}else {q18.Studies.calculateMassIndex=function(i3d,b2b){var c0N,M6P,t_b,q$n,h4T,Z17,a4i,k59;c0N="_";c0N+="EM";c0N+="A ";M6P=1078781190;t_b=1904025788;q$n=2;for(var B2E=1;X30.S9Y(B2E.toString(),B2E.toString().length,83617) !== M6P;B2E++){h4T=b2b.chart.scrubbed;q$n+=2;}if(X30.O1W(q$n.toString(),q$n.toString().length,25167) !== t_b){h4T=b2b.chart.scrubbed;}if(h4T.length < Math.max(9,b2b.days + 1)){b2b.error=!"";return;}for(var A1$=b2b.startFrom;A1$ < h4T.length;A1$++){h4T[A1$]["_High-Low " + b2b.name]=h4T[A1$].High - h4T[A1$].Low;}q18.Studies.MA("exponential",9,"_High-Low " + b2b.name,0,"_EMA",i3d,b2b);q18.Studies.MA("exponential",9,c0N + b2b.name,0,"_EMA2",i3d,b2b);Z17=0;if(h4T[b2b.startFrom - 1] && h4T[b2b.startFrom - +"1"]["_total " + b2b.name]){X30.j7J(14);var e6Q=X30.a$j(16,15);Z17=h4T[b2b.startFrom - e6Q]["_total " + b2b.name];}for(var N_Q=Math.max(+"17",b2b.startFrom);N_Q < h4T.length;N_Q++){a4i="_to";a4i+="ta";a4i+="l";a4i+=" ";k59="_";k59+="EMA2 ";Z17+=h4T[N_Q]["_EMA " + b2b.name] / h4T[N_Q][k59 + b2b.name];if(N_Q >= ("17" ^ 0) + b2b.days - 1){h4T[N_Q]["Result " + b2b.name]=Z17;X30.N_M(63);var S8j=X30.a$j(4,12,17);X30.j7J(52);var e6$=X30.a$j(6,8,1);Z17-=h4T[N_Q - b2b.days + S8j]["_EMA " + b2b.name] / h4T[N_Q - b2b.days + e6$]["_EMA2 " + b2b.name];}h4T[N_Q][a4i + b2b.name]=Z17;}};q18.Studies.displayMassIndex=function(G4R,X9q,d8e){var D3j,E0d,U8j,q9C,D3w,J8z;D3j="Bu";D3j+="lge Thr";D3j+="esh";D3j+="old";q18.Studies.displaySeriesAsLine(G4R,X9q,d8e);E0d=X9q.inputs[D3j];U8j=G4R.panels[X9q.panel];q9C=X9q.getYAxis(G4R);D3w=q18.Studies.determineColor(X9q.outputs.Result);J8z={skipTransform:G4R.panels[X9q.panel].name != X9q.chart.name,panelName:X9q.panel,band:"Result " + X9q.name,threshold:E0d,direction:1,color:D3w,yAxis:q9C,opacity:0.3};if(!X9q.highlight && G4R.highlightedDraggable){J8z.opacity*=0.3;}q18.preparePeakValleyFill(G4R,J8z);q18.Studies.drawHorizontal(G4R,X9q,null,E0d,q9C,D3w);};z4T=724537233;v2X=2069551907;R$R=2;for(var e5X=1;X30.S9Y(e5X.toString(),e5X.toString().length,73548) !== z4T;e5X++){q18.Studies.studyLibrary=q18.extend(q18.Studies.studyLibrary,{"Mass Idx":{name:"Mass Index",seriesFN:q18.Studies.displayMassIndex,calculateFN:q18.Studies.calculateMassIndex,inputs:{Period:14,"Bulge Threshold":63},attributes:{"Bulge Threshold":{min:+"57",max:14,step:780}}}});R$R+=2;}if(X30.S9Y(R$R.toString(),R$R.toString().length,+"45439") !== v2X){q18.Studies.studyLibrary=q18.extend(q18.Studies.studyLibrary,{"Mass Idx":{name:"Mass Index",seriesFN:q18.Studies.displayMassIndex,calculateFN:q18.Studies.calculateMassIndex,inputs:{Period:25,"Bulge Threshold":+"27"},attributes:{"Bulge Threshold":{min:20,max:35,step:0.1}}}});}}};e4=O7z=>{var i7t=f3BGj;i7t.T$X();var N3_,V5x;N3_=typeof _CIQ !== "undefined"?_CIQ:O7z.CIQ;if(!N3_.Studies){console.error("moneyFlow feature requires first activating studies feature.");}else {V5x="Money F";V5x+="low Ind";V5x+="e";V5x+="x";N3_.Studies.calculateMoneyFlowIndex=function(t9T,v7y){var p8N,d5m,O25,z1b,E92,v5L,a5S,M4c,u9x,P5O,e6F,N9v,d2n;p8N="_";p8N+="r";p8N+="awM";p8N+="F ";d5m=v7y.chart.scrubbed;if(d5m.length < v7y.days + 1){v7y.error=!!1;return;}O25=0;z1b=0;i7t.j7J(14);var g9E=i7t.a$j(1,0);E92=d5m[v7y.startFrom - g9E];v5L=p8N + v7y.name;a5S="_cumMF " + v7y.name;M4c="Result " + v7y.name;if(E92 && E92[a5S]){O25=E92[a5S][0];z1b=E92[a5S][1];}for(var J4A=v7y.startFrom;J4A < d5m.length;J4A++){u9x=d5m[J4A]["hlc/3"];if(J4A > 0 && !d5m[J4A].futureTick){P5O="hlc";P5O+="/3";i7t.N_M(14);e6F=d5m[i7t.a$j(J4A,1)][P5O];N9v=u9x * d5m[J4A].Volume;if(u9x > e6F){O25+=N9v;}else if(u9x < e6F){N9v*=-1;z1b-=N9v;}else {N9v=0;}if(J4A > v7y.days){d2n=d5m[J4A - v7y.days][v5L];if(d2n > 0){O25-=d2n;}else {z1b+=d2n;}if(z1b === 0){d5m[J4A][M4c]=100;}else if(d5m[J4A].Volume){i7t.j7J(139);d5m[J4A][M4c]=i7t.a$j(0,"100",O25,100,z1b,"1");}}d5m[J4A][v5L]=N9v;d5m[J4A][a5S]=[O25,z1b];}}};N3_.Studies.studyLibrary=N3_.extend(N3_.Studies.studyLibrary,{"M Flow":{name:V5x,range:"0 to 100",calculateFN:N3_.Studies.calculateMoneyFlowIndex,inputs:{Period:"14" << 0},parameters:{init:{studyOverZonesEnabled:!!1,studyOverBoughtValue:80,studyOverBoughtColor:"auto",studyOverSoldValue:20,studyOverSoldColor:"auto"}}}});}};A1=s2O=>{var S8i,q5H,H36,i7d,i7U,o6F,D1J,b4u,H8y,w7K,I$t;S8i="undefi";S8i+="ned";q5H=typeof _CIQ !== S8i?_CIQ:s2O.CIQ;if(!q5H.Studies){console.error("movingAverages feature requires first activating studies feature.");}else {H36="aut";H36+="o";i7d="Pe";i7d+="rcent";i7U="a";i7U+="ut";i7U+="o";o6F="p";o6F+="oints";D1J="TripleExponentia";D1J+="l";b4u="DoubleExpone";b4u+="ntial";H8y="2-e";H8y+="x";H8y+="pon";H8y+="ential";w7K="t";w7K+="ema";I$t="de";I$t+="m";I$t+="a";q5H.Studies.prettify=q5H.extend({"2-exponential":I$t,"3-exponential":w7K,hull:"hma"},q5H.Studies.prettify);q5H.extend(q5H.Studies.movingAverage,{conversions:{hma:"hull",dema:H8y,tema:"3-exponential"},translations:{hull:"Hull","2-exponential":"Double Exponential","3-exponential":"Triple Exponential"},typeMap:{hma:"Hull",hull:"Hull",dema:"DoubleExponential","2-exponential":b4u,tema:"TripleExponential","3-exponential":D1J}});q5H.Studies.calculateMovingAverageHull=function(e_s,J_J){var L$B=f3BGj;var e0_,j7y,O3e,a3I,J0k,Q1K,j1D,V4P,Y7L,B$0,M0_,q7X,m$h;e0_="_W";e0_+="MA2";j7y="w";j7y+="m";j7y+="a";O3e="_W";O3e+="M";O3e+="A";O3e+="1";a3I=J_J.chart.scrubbed;L$B.T$X();J0k=J_J.inputs.Field;if(!J0k || J0k == "field"){J0k="Close";}q5H.Studies.MA("wma",J_J.days,J0k,0,O3e,e_s,J_J);q5H.Studies.MA(j7y,Math.ceil(J_J.days / 2),J0k,0,e0_,e_s,J_J);for(Q1K=J_J.startFrom - 1;Q1K >= 0;Q1K--){j1D=a3I[Q1K][J0k];if(j1D && typeof j1D == "object"){j1D=j1D[J_J.subField];}if(j1D || j1D === 0)break;}for(Q1K++;Q1K < a3I.length;Q1K++){V4P="_WM";V4P+="A1";V4P+=" ";Y7L="_MMA";Y7L+=" ";B$0=a3I[Q1K];L$B.j7J(86);var i6u=L$B.a$j(18,19,3,12,4);B$0[Y7L + J_J.name]=i6u * B$0["_WMA2 " + J_J.name] - B$0[V4P + J_J.name];}M0_=parseInt(J_J.inputs.Offset,"10" - 0);if(isNaN(M0_)){L$B.j7J(46);M0_=L$B.a$j("0",0);}q7X=Math.floor(Math.sqrt(J_J.days));q5H.Studies.MA("wma",q7X,"_MMA " + J_J.name,M0_,"_HMA",e_s,J_J);m$h=J_J.name;for(var I3b in J_J.outputs){L$B.N_M(82);m$h=L$B.a$j(m$h,"957.13" - 0 >= (2249,4526)?(8.32e+3,282.25):227.21 != (606.9,8050)?(628.48,4480) === 3060?(841.87,"2.81e+3" << 64):" ":(+"0x26df",0x1b6e),I3b);}for(Q1K=Math.max(J_J.days + q7X - 1,J_J.startFrom);Q1K < a3I.length;Q1K++){a3I[Q1K][m$h]=a3I[Q1K]["_HMA " + J_J.name];}};q5H.Studies.calculateMovingAverageDoubleExponential=function(u63,V8Z){var R2e=f3BGj;var S6j,R3o,d_M,k9z,Q5s,X9m,h6f,a2T,y3S,M$y,P8W,c$u,O1u,C$a;S6j="_EM";S6j+="A";S6j+="1 ";R3o="e";R3o+="m";R3o+="a";d_M="f";d_M+="ie";d_M+="ld";k9z=V8Z.chart.scrubbed;Q5s=V8Z.inputs.Field;if(!Q5s || Q5s == d_M){Q5s="Close";}q5H.Studies.MA("ema",V8Z.days,Q5s,0,"_EMA1",u63,V8Z);q5H.Studies.MA(R3o,V8Z.days,S6j + V8Z.name,0,"_EMA2",u63,V8Z);X9m=parseInt(V8Z.inputs.Offset,10);if(isNaN(X9m)){X9m=0;}y3S=X9m;for(h6f=V8Z.startFrom - 1;h6f >= 0;h6f--){a2T=k9z[h6f][Q5s];if(a2T && typeof a2T == "object"){a2T=a2T[V8Z.subField];}if(!a2T && a2T !== 0)continue;if(y3S > 0){y3S--;continue;}break;}M$y=V8Z.name;for(var p7S in V8Z.outputs){R2e.N_M(82);M$y=R2e.c0C(M$y," ",p7S);}P8W=[];for(h6f++;h6f < k9z.length;h6f++){if(h6f < 2 * (V8Z.days - 1))continue;c$u=k9z[h6f];R2e.j7J(9);var M8l=R2e.c0C(49,3,17);O1u=M8l * c$u["_EMA1 " + V8Z.name] - c$u["_EMA2 " + V8Z.name];if(h6f + X9m >= 0){if(h6f + X9m < k9z.length){R2e.N_M(1);k9z[R2e.a$j(h6f,X9m)][M$y]=O1u;}else {C$a={};C$a[M$y]=O1u;P8W.push(C$a);}}}V8Z.appendFutureTicks(u63,P8W);};q5H.Studies.calculateMovingAverageTripleExponential=function(v0r,Y9i){var Y7y=f3BGj;var L3x,b7A,a6R,I2R,U5Z,F0a,E_4,Y8n,A6X,l_B,C1c,K23,O8b,g6b,Y0$,V3W,C$X;L3x="_E";L3x+="MA";L3x+="1 ";b7A="em";b7A+="a";a6R="_";a6R+="E";a6R+="MA";a6R+="1";I2R="e";I2R+="m";I2R+="a";U5Z=Y9i.chart.scrubbed;F0a=Y9i.inputs.Field;if(!F0a || F0a == "field"){F0a="Close";}q5H.Studies.MA(I2R,Y9i.days,F0a,0,a6R,v0r,Y9i);q5H.Studies.MA(b7A,Y9i.days,L3x + Y9i.name,"0" | 0,"_EMA2",v0r,Y9i);q5H.Studies.MA("ema",Y9i.days,"_EMA2 " + Y9i.name,0,"_EMA3",v0r,Y9i);E_4=parseInt(Y9i.inputs.Offset,10);if(isNaN(E_4)){E_4=0;}l_B=E_4;for(Y8n=Y9i.startFrom - 1;Y8n >= 0;Y8n--){A6X=U5Z[Y8n][F0a];if(A6X && typeof A6X == "object"){A6X=A6X[Y9i.subField];}if(!A6X && A6X !== 0)continue;if(l_B > 0){l_B--;continue;}break;}C1c=Y9i.name;for(var d0L in Y9i.outputs){Y7y.N_M(82);C1c=Y7y.a$j(C1c,9299 === 622.05?543.67 >= (+"7250",4160)?"B":(!({}),"l"):" ",d0L);}K23=[];for(Y8n++;Y8n < U5Z.length;Y8n++){O8b="_EM";O8b+="A3 ";g6b="_";g6b+="EM";g6b+="A";g6b+="2 ";if(Y8n < 3 * (Y9i.days - 1))continue;Y0$=U5Z[Y8n];Y7y.j7J(124);var F1t=Y7y.c0C(15,16,42,10,2);Y7y.j7J(9);var P_j=Y7y.c0C(237,20,12);V3W=F1t * Y0$["_EMA1 " + Y9i.name] - P_j * Y0$[g6b + Y9i.name] + Y0$[O8b + Y9i.name];if(Y8n + E_4 >= 0){if(Y8n + E_4 < U5Z.length){Y7y.N_M(1);U5Z[Y7y.a$j(Y8n,E_4)][C1c]=V3W;}else {C$X={};C$X[C1c]=V3W;K23.push(C$X);}}}Y9i.appendFutureTicks(v0r,K23);};q5H.Studies.calculateMAEnvelope=function(c_1,B$X){var U3W,i07,k2K,F_F,M6N;U3W="Shi";U3W+="ft Type";i07=B$X.inputs.Field;f3BGj.f3X();if(!i07 || i07 == "field"){i07="Close";}q5H.Studies.MA(B$X.inputs["Moving Average Type"],B$X.days,i07,0,"MA",c_1,B$X);k2K=B$X.inputs[U3W];F_F=B$X.inputs.Shift;if(!k2K){k2K="percent";F_F=B$X.inputs["Shift Percentage"];}if(k2K == "percent"){f3BGj.N_M(7);q5H.Studies.calculateGenericEnvelope(c_1,B$X,f3BGj.a$j(F_F,100),"MA " + B$X.name);}else if(k2K == "points"){M6N="M";M6N+="A";M6N+=" ";q5H.Studies.calculateGenericEnvelope(c_1,B$X,null,M6N + B$X.name,null,Number(F_F));}};q5H.Studies.calculateMADev=function(C53,B3w){var R7H=f3BGj;var o9D,j_8,f9V,a_D,P3E,y5R,R0a,T3J,h09,n$X,N7W;o9D="_";o9D+="M";o9D+="A";j_8="Po";j_8+="i";j_8+="nt";j_8+="s";R7H.f3X();f9V="C";f9V+="lose";a_D=B3w.chart.scrubbed;if(a_D.length < B3w.days + 1){B3w.error=!0;return;}P3E=B3w.inputs.Field;if(!P3E || P3E == "field"){P3E=f9V;}y5R=B3w.inputs["Points Or Percent"];if(!y5R){y5R=j_8;}R0a=B3w.inputs["Moving Average Type"];if(!R0a){R0a="exponential";}q5H.Studies.MA(R0a,B3w.days,P3E,+"0",o9D,C53,B3w);T3J=B3w.name + "_hist";for(var O7x=Math.max(B3w.startFrom,B3w.days - 1);O7x < a_D.length;O7x++){h09=a_D[O7x];n$X=h09[P3E];if(n$X && typeof n$X == "object"){n$X=n$X[B3w.subField];}N7W=h09["_MA " + B3w.name];if(N7W || N7W === 0){if(y5R == "Points"){R7H.j7J(14);h09[T3J]=R7H.a$j(n$X,N7W);}else {R7H.N_M(140);h09[T3J]=R7H.c0C(100,1,n$X,N7W);}}}B3w.outputMap={};B3w.outputMap[B3w.name + "_hist"]="";};q5H.Studies.studyLibrary=q5H.extend(q5H.Studies.studyLibrary,{"MA Env":{name:"Moving Average Envelope",overlay:!!"1",seriesFN:q5H.Studies.displayChannel,calculateFN:q5H.Studies.calculateMAEnvelope,inputs:{Period:50,Field:"field","Shift Type":["percent",o6F],Shift:5,"Moving Average Type":"ma","Channel Fill":!!({})},outputs:{"MA Env Top":i7U,"MA Env Median":"auto","MA Env Bottom":"auto"},attributes:{Shift:{min:0.1,step:0.1}}},"MA Dev":{name:"Moving Average Deviation",calculateFN:q5H.Studies.calculateMADev,seriesFN:q5H.Studies.displayHistogramWithSeries,inputs:{Period:12,Field:"field","Moving Average Type":"ma","Points Or Percent":["Points",i7d]},outputs:{"Increasing Bar":"#00DD00","Decreasing Bar":"#FF0000"}},"High Low":{name:"High Low Bands",overlay:!"",seriesFN:q5H.Studies.displayChannel,calculateFN:function(Q4X,B0l){f3BGj.T$X();var M3g;M3g="t";M3g+="r";M3g+="iangular";B0l.inputs["Moving Average Type"]=M3g;q5H.Studies.calculateMAEnvelope(Q4X,B0l);},inputs:{Period:10,Field:"field","Shift Percentage":"5" * 1,"Channel Fill":!0},outputs:{"High Low Top":"auto","High Low Median":H36,"High Low Bottom":"auto"},attributes:{"Shift Percentage":{min:0.1,step:0.1}}}});}};d_=y1V=>{var T89=f3BGj;var i2N,U7B;i2N=typeof _CIQ !== "undefined"?_CIQ:y1V.CIQ;T89.T$X();if(!i2N.Studies){U7B="parabolicSAR feature requires first activa";U7B+="ting studies feature.";console.error(U7B);}else {i2N.Studies.calculatePSAR=function(J6C,r5x){var J5P,p96,B4M,J48,K2Q,S8U,I0n,X0D,e2H,p8W,u6a,U3M,V9m;J5P=r5x.chart.scrubbed;p96=0;B4M=null;J48=!!"";function F8j(){p96=0;B4M=null;J48=!J48;}K2Q=0;S8U=parseFloat(r5x.inputs["Minimum AF"]);I0n=parseFloat(r5x.inputs["Maximum AF"]);T89.f3X();if(r5x.startFrom > 0){X0D="_";X0D+="st";X0D+="ate";X0D+=" ";e2H="Re";e2H+="su";e2H+="lt";e2H+=" ";T89.j7J(141);var y2A=T89.c0C(19,6,26);K2Q=J5P[r5x.startFrom - y2A][e2H + r5x.name];p8W=J5P[r5x.startFrom - +"1"][X0D + r5x.name];if(p8W && p8W.length == 3){p96=p8W[0];B4M=p8W[1];T89.N_M(46);J48=p8W[T89.c0C("2",0)];}}for(var O6U=r5x.startFrom - 1;O6U < J5P.length - +"1";O6U++){if(O6U < 0)continue;if(J5P[O6U].futureTick)break;u6a=K2Q;if(J48){if(!B4M || B4M < J5P[O6U].High){B4M=J5P[O6U].High;T89.j7J(1);p96=Math.min(T89.c0C(p96,S8U),I0n);}T89.j7J(142);K2Q=T89.c0C(u6a,p96,u6a,B4M);U3M=Math.min(J5P[Math.max(1,O6U) - +"1"].Low,J5P[O6U].Low);if(K2Q > J5P[O6U + 1].Low){K2Q=B4M;F8j();}else if(K2Q > U3M){K2Q=U3M;}}else {if(!B4M || B4M > J5P[O6U].Low){B4M=J5P[O6U].Low;T89.N_M(1);p96=Math.min(T89.a$j(p96,S8U),I0n);}T89.j7J(142);K2Q=T89.c0C(u6a,p96,u6a,B4M);V9m=Math.max(J5P[Math.max(1,O6U) - 1].High,J5P[O6U].High);if(K2Q < J5P[O6U + 1].High){K2Q=B4M;F8j();}else if(K2Q < V9m){K2Q=V9m;}}T89.N_M(1);J5P[T89.a$j(O6U,1)]["_state " + r5x.name]=[p96,B4M,J48];if(!isNaN(J5P[O6U].High) || !isNaN(J5P[O6U].Low)){T89.j7J(1);J5P[T89.a$j(O6U,1)]["Result " + r5x.name]=K2Q;}}};i2N.Studies.studyLibrary=i2N.extend(i2N.Studies.studyLibrary,{PSAR:{name:"Parabolic SAR",overlay:!!"1",calculateFN:i2N.Studies.calculatePSAR,seriesFN:i2N.Studies.displayPSAR2,inputs:{"Minimum AF":0.02,"Maximum AF":0.2}}});}};O9=W7c=>{var u$x,P9g,f2Q,k5H,z4w;u$x="und";u$x+="ef";u$x+="in";u$x+="ed";P9g=typeof _CIQ !== u$x?_CIQ:W7c.CIQ;if(!P9g.Studies){f2Q="pivotPoints feature re";f2Q+="quires first activating studies feature.";console.error(f2Q);}else {k5H="#b";k5H+="3d987";z4w="#b8";z4w+="2";z4w+="c0";z4w+="b";P9g.Studies.calculatePivotPoints=function(n3D,Q9Y){var V3B=f3BGj;var j4Y,E9D,r2L,c4T,a4h,T50,p67,x_D,N7b,N3x,p_H,x0A,m8H,U4n,B7_,D04,A_3,h4j,r9U,i8n;V3B.T$X();j4Y="market.beginnin";j4Y+="gDayOfWeek";E9D="mi";E9D+="lliseco";E9D+="nd";r2L=Q9Y.chart.scrubbed;c4T="day";a4h=n3D.layout.interval;T50=n3D.layout.timeUnit;if(a4h == "day"){c4T="month";}else if(P9g.ChartEngine.isDailyInterval(a4h)){c4T="year";}else if(a4h == "second" || a4h == "millisecond" || T50 == "second" || T50 == E9D){c4T="15min";}else {p67="minu";p67+="te";x_D=n3D.layout.periodicity;if(a4h != p67){x_D*=a4h;}if(x_D >= 30){c4T="week";}}N7b=null;V3B.j7J(82);var K_Q=V3B.a$j(2,4,1);N3x=K_Q - P9g.getFromNS(n3D.chart,j4Y,0);p_H={pivotPoint:NaN,high:0,low:0,prevHigh:0,prevLow:0,hlSpread:0};if(Q9Y.startFrom > 1 && r2L[Q9Y.startFrom - 1]["_pointers " + Q9Y.name]){p_H=P9g.clone(r2L[Q9Y.startFrom - +"1"]["_pointers " + Q9Y.name]);}for(var f5R=Math.max(1,Q9Y.startFrom);f5R < r2L.length;f5R++){x0A="fibo";x0A+="n";x0A+="ac";x0A+="ci";m8H="d";m8H+="a";m8H+="y";if(!r2L[f5R - 1])continue;p_H.high=Math.max(p_H.high,r2L[f5R - 1].High);p_H.low=Math.min(p_H.low > 0?p_H.low:r2L[f5R - 1].Low,r2L[f5R - 1].Low);if(Q9Y.inputs.Continuous){T4t();}else if(c4T == "year" && r2L[f5R].DT.getYear() != r2L[f5R - 1].DT.getYear()){T4t();}else if(c4T == "month" && r2L[f5R].DT.getMonth() != r2L[f5R - 1].DT.getMonth()){T4t();}else if(c4T == "week" && (r2L[f5R].DT.getDay() + N3x) % 7 < (r2L[f5R - 1].DT.getDay() + N3x) % 7){T4t();}else if(c4T == m8H){if(N7b === null){N7b=P9g.Studies.getMarketOffset({stx:n3D,localQuoteDate:r2L[f5R].DT,shiftToDateBoundary:!!({})});}U4n=new Date(new Date(+r2L[f5R].DT).setMilliseconds(r2L[f5R].DT.getMilliseconds() + N7b));B7_=new Date(new Date(+r2L[f5R - 1].DT).setMilliseconds(r2L[f5R - 1].DT.getMilliseconds() + N7b));if(B7_.getDate() !== U4n.getDate() && B7_.getDay() !== 0 && n3D.chart.market.isMarketDate(U4n)){N7b=null;T4t();}}else if(c4T == "15min" && (r2L[f5R].DT.getHours() != r2L[f5R - 1].DT.getHours() || Math.floor(r2L[f5R].DT.getMinutes() / 15) != Math.floor(r2L[f5R - 1].DT.getMinutes() / 15))){T4t();}r2L[f5R]["Pivot " + Q9Y.name]=p_H.pivotPoint;if(Q9Y.inputs.Type.toLowerCase() == x0A){D04="S";D04+="u";D04+="pport 3 ";A_3="Sup";A_3+="port ";A_3+="2 ";h4j="Res";h4j+="ista";h4j+="nce ";h4j+="2 ";r9U="Resi";r9U+="stanc";r9U+="e ";r9U+="1 ";r2L[f5R][r9U + Q9Y.name]=p_H.pivotPoint + +"0.382" * p_H.hlSpread;r2L[f5R][h4j + Q9Y.name]=p_H.pivotPoint + 0.618 * p_H.hlSpread;r2L[f5R]["Resistance 3 " + Q9Y.name]=p_H.pivotPoint + p_H.hlSpread;r2L[f5R]["Support 1 " + Q9Y.name]=p_H.pivotPoint - 0.382 * p_H.hlSpread;r2L[f5R][A_3 + Q9Y.name]=p_H.pivotPoint - 0.618 * p_H.hlSpread;r2L[f5R][D04 + Q9Y.name]=p_H.pivotPoint - p_H.hlSpread;}else {i8n="Resis";i8n+="tance ";i8n+="2 ";V3B.N_M(14);var H7E=V3B.a$j(18,16);r2L[f5R]["Resistance 1 " + Q9Y.name]=H7E * p_H.pivotPoint - p_H.prevLow;r2L[f5R][i8n + Q9Y.name]=p_H.pivotPoint + p_H.hlSpread;V3B.N_M(3);var M_8=V3B.a$j(9,5,6);r2L[f5R]["Resistance 3 " + Q9Y.name]=p_H.prevHigh + M_8 * (p_H.pivotPoint - p_H.prevLow);V3B.j7J(102);var I2k=V3B.a$j(15,3,4,12);r2L[f5R]["Support 1 " + Q9Y.name]=I2k * p_H.pivotPoint - p_H.prevHigh;r2L[f5R]["Support 2 " + Q9Y.name]=p_H.pivotPoint - p_H.hlSpread;r2L[f5R]["Support 3 " + Q9Y.name]=p_H.prevLow - ("2" | 0) * (p_H.prevHigh - p_H.pivotPoint);}r2L[f5R]["_pointers " + Q9Y.name]=P9g.clone(p_H);}function T4t(){V3B.j7J(71);var p$B=V3B.c0C(18,145,8,1,2);p_H.pivotPoint=(p_H.high + p_H.low + r2L[f5R - p$B].Close) / ("3" >> 0);p_H.prevHigh=p_H.high;p_H.prevLow=p_H.low;p_H.hlSpread=p_H.high - p_H.low;V3B.f3X();p_H.high=p_H.low=0;}};P9g.Studies.displayPivotPoints=function(q_G,e2M,K7g){var X20,N_n,b0D,f8q,g$O,u59,H76,b$S,T_c,N2L;e2M.noSlopes=!e2M.inputs.Continuous;P9g.Studies.displaySeriesAsLine(q_G,e2M,K7g);if(e2M.inputs.Shading){X20="Support";X20+=" 3";N_n="S";N_n+="u";N_n+="ppor";N_n+="t 2 ";b0D="S";b0D+="u";b0D+="ppo";b0D+="rt 1 ";f8q="Suppo";f8q+="rt 1";g$O="P";g$O+="i";g$O+="vot ";u59="Resistance ";u59+="3";H76="Resistan";H76+="ce 2 ";b$S="Res";b$S+="istance ";b$S+="3";b$S+=" ";T_c=q_G.panels[e2M.panel];N2L={noSlopes:e2M.noSlopes,opacity:e2M.parameters.opacity?e2M.parameters.opacity:0.2,skipTransform:T_c.name != e2M.chart.name,yAxis:e2M.getYAxis(q_G)};if(!e2M.highlight && q_G.highlightedDraggable){N2L.opacity*=0.3;}P9g.prepareChannelFill(q_G,P9g.extend({panelName:e2M.panel,topBand:b$S + e2M.name,bottomBand:H76 + e2M.name,color:P9g.Studies.determineColor(e2M.outputs[u59])},N2L));P9g.prepareChannelFill(q_G,P9g.extend({panelName:e2M.panel,topBand:"Resistance 2 " + e2M.name,bottomBand:"Resistance 1 " + e2M.name,color:P9g.Studies.determineColor(e2M.outputs["Resistance 2"])},N2L));P9g.prepareChannelFill(q_G,P9g.extend({panelName:e2M.panel,topBand:"Resistance 1 " + e2M.name,bottomBand:g$O + e2M.name,color:P9g.Studies.determineColor(e2M.outputs["Resistance 1"])},N2L));P9g.prepareChannelFill(q_G,P9g.extend({panelName:e2M.panel,topBand:"Support 1 " + e2M.name,bottomBand:"Pivot " + e2M.name,color:P9g.Studies.determineColor(e2M.outputs[f8q])},N2L));P9g.prepareChannelFill(q_G,P9g.extend({panelName:e2M.panel,topBand:"Support 2 " + e2M.name,bottomBand:b0D + e2M.name,color:P9g.Studies.determineColor(e2M.outputs["Support 2"])},N2L));P9g.prepareChannelFill(q_G,P9g.extend({panelName:e2M.panel,topBand:"Support 3 " + e2M.name,bottomBand:N_n + e2M.name,color:P9g.Studies.determineColor(e2M.outputs[X20])},N2L));}};P9g.Studies.studyLibrary=P9g.extend(P9g.Studies.studyLibrary,{"Pivot Points":{name:"Pivot Points",overlay:!!1,seriesFN:P9g.Studies.displayPivotPoints,calculateFN:P9g.Studies.calculatePivotPoints,inputs:{Type:["standard","fibonacci"],Continuous:!!"",Shading:!!""},outputs:{Pivot:"auto","Resistance 1":z4w,"Support 1":"#699158","Resistance 2":"#e36460","Support 2":k5H,"Resistance 3":"#ffd0cf","Support 3":"#d3e8ae"},parameters:{init:{opacity:0.2}}}});}};s4=k_W=>{var Z08,E7W;Z08=typeof _CIQ !== "undefined"?_CIQ:k_W.CIQ;if(!Z08.Studies){console.error("prettyGoodOscillator feature requires first activating studies feature.");}else {E7W="Pretty Good O";E7W+="scillator";Z08.Studies.calculatePrettyGoodOscillator=function(F40,V9S){f3BGj.f3X();var i06,g$$,l7y,u4g;i06="_EM";i06+="A";g$$="true";g$$+="Rang";g$$+="e";l7y=V9S.chart.scrubbed;if(l7y.length < V9S.days + ("1" << 0)){V9S.error=!![];return;}Z08.Studies.MA("exponential",V9S.days,g$$,+"0",i06,F40,V9S);Z08.Studies.MA("simple",V9S.days,"Close","0" >> 96,"_SMA",F40,V9S);for(var F6J=Math.max("1" ^ 0,V9S.startFrom);F6J < l7y.length;F6J++){u4g="_";u4g+="EMA ";if(!l7y[F6J]["_SMA " + V9S.name] || !l7y[F6J][u4g + V9S.name])continue;l7y[F6J]["Result " + V9S.name]=(l7y[F6J].Close - l7y[F6J]["_SMA " + V9S.name]) / l7y[F6J]["_EMA " + V9S.name];}};Z08.Studies.studyLibrary=Z08.extend(Z08.Studies.studyLibrary,{"Pretty Good":{name:E7W,calculateFN:Z08.Studies.calculatePrettyGoodOscillator,parameters:{init:{studyOverZonesEnabled:!!({}),studyOverBoughtValue:3,studyOverBoughtColor:"auto",studyOverSoldValue:-3,studyOverSoldColor:"auto"}}}});}};e5=D4M=>{var u$J=f3BGj;var v0H,T63,o7V,f1l;u$J.T$X();v0H=typeof _CIQ !== "undefined"?_CIQ:D4M.CIQ;if(!v0H.Studies){console.error("priceMomentumOscillator feature requires first activating studies feature.");}else {T63="0.0";T63+="5";o7V="#F";o7V+="F0";o7V+="000";f1l="aut";f1l+="o";v0H.Studies.calculatePMO=function(N1C,P_Q){var l2_,E_6,B2d,t1Z,d0m,Y$4,S3n,j6T,T_D,c3E,M8n,N4l;l2_="P";l2_+="M";l2_+="O";l2_+=" ";E_6="e";E_6+="x";E_6+="ponentia";E_6+="l";B2d="_";B2d+="EMAx";B2d+="1";B2d+="0";t1Z="_";t1Z+="RO";t1Z+="Cx10 ";d0m="Clos";d0m+="e";Y$4="fi";Y$4+="e";Y$4+="ld";S3n={Smooth:Number(P_Q.inputs["Smoothing Period"]) - 1,Double:Number(P_Q.inputs["Double Smoothing Period"]) - 1,Signal:Number(P_Q.inputs["Signal Period"])};j6T=P_Q.chart.scrubbed;if(j6T.length < S3n.Smooth + S3n.Double){P_Q.error=!![];return;}u$J.T$X();T_D=P_Q.inputs.Field;if(!T_D || T_D == Y$4){T_D=d0m;}for(c3E=P_Q.startFrom;c3E < j6T.length;c3E++){if(!j6T[c3E])continue;if(!j6T[c3E - 1])continue;u$J.N_M(14);M8n=j6T[u$J.a$j(c3E,1)][T_D];if(M8n){N4l="_";N4l+="RO";N4l+="Cx";N4l+="10 ";u$J.j7J(143);var y$z=u$J.c0C(59,59,13,986);j6T[c3E][N4l + P_Q.name]=y$z * (j6T[c3E][T_D] / M8n - +"1");}}v0H.Studies.MA("exponential",S3n.Smooth,t1Z + P_Q.name,0,B2d,N1C,P_Q);v0H.Studies.MA(E_6,S3n.Double,"_EMAx10 " + P_Q.name,0,"PMO",N1C,P_Q);v0H.Studies.MA("exponential",S3n.Signal,l2_ + P_Q.name,0,"PMOSignal",N1C,P_Q);P_Q.zoneOutput="PMO";};v0H.Studies.studyLibrary=v0H.extend(v0H.Studies.studyLibrary,{PMO:{name:"Price Momentum Oscillator",calculateFN:v0H.Studies.calculatePMO,inputs:{Field:"field","Smoothing Period":35,"Double Smoothing Period":"20" * 1,"Signal Period":10},outputs:{PMO:f1l,PMOSignal:o7V},parameters:{init:{studyOverZonesEnabled:!!1,studyOverBoughtValue:2.5,studyOverBoughtColor:"auto",studyOverSoldValue:-2.5,studyOverSoldColor:"auto"}},attributes:{studyOverBoughtValue:{min:0,step:T63},studyOverSoldValue:{max:0,step:"0.05"}}}});}};C$=r2t=>{var t3t=f3BGj;var H9H,E6w,K76,c_j,W8H,a6Y,u0c;t3t.T$X();H9H=typeof _CIQ !== "undefined"?_CIQ:r2t.CIQ;if(!H9H.Studies){E6w="priceVolumeOscillat";E6w+="or feature requires first ac";E6w+="tivating studies fe";E6w+="ature.";console.error(E6w);}else {K76="0";K76+=".";K76+="1";c_j="#F";c_j+="F0";c_j+="00";c_j+="0";W8H="vdm";W8H+="a";a6Y="Poi";a6Y+="nts";u0c="e";u0c+="m";u0c+="a";H9H.Studies.calculatePriceOscillator=function(z6z,p0E){var C_6,R4R,r72,O_i,Y7G,k_5,W4q,Q0z,J9b,F6g,x3w,M8S,i5K;C_6="P";C_6+="oints Or";C_6+=" ";C_6+="Percent";R4R=p0E.chart.scrubbed;r72=Number(p0E.inputs["Short Cycle"]);O_i=Number(p0E.inputs["Long Cycle"]);if(R4R.length < Math.max(r72,O_i) + 1){p0E.error=!![];return;}Y7G=p0E.inputs.Field;k_5=p0E.inputs["Moving Average Type"];if(!k_5){k_5="simple";}if(!Y7G || Y7G == "field"){Y7G="Close";}if(p0E.parameters.isVolume){Y7G="Volume";k_5="exponential";}W4q=p0E.inputs[C_6];if(!W4q){W4q="Percent";}H9H.Studies.MA(k_5,r72,Y7G,0,"_Short MA",z6z,p0E);t3t.j7J(29);H9H.Studies.MA(k_5,O_i,Y7G,t3t.c0C(32,"0"),"_Long MA",z6z,p0E);for(var x63=Math.max(O_i,p0E.startFrom);x63 < R4R.length;x63++){Q0z="_Sho";Q0z+="rt MA ";J9b=R4R[x63];if(!J9b)continue;F6g=J9b[Q0z + p0E.name];x3w=J9b["_Long MA " + p0E.name];if((F6g || F6g === ("0" ^ 0)) && (x3w || x3w === 0)){M8S="Point";M8S+="s";if(W4q == M8S){t3t.N_M(14);J9b["Result " + p0E.name]=t3t.c0C(F6g,x3w);}else {t3t.j7J(144);J9b["Result " + p0E.name]=t3t.a$j(0,F6g,x3w,"1",100);}if(p0E.outputs["Increasing Bar"]){i5K="Res";i5K+="ult ";J9b[p0E.name + "_hist"]=J9b[i5K + p0E.name];p0E.outputMap={};p0E.outputMap[p0E.name + "_hist"]="";}}}};H9H.Studies.displayRAVI=function(F6V,v$8,t3z){var V92,i43,r9Q,L_A,Q_z,g_O,V9J,s5P,L_R,P0B,S5e,M81,a9_,v5j,l6C;V92="stx";V92+="_histogram";i43=F6V.panels[v$8.panel];r9Q=v$8.getContext(F6V);t3t.T$X();L_A=v$8.getYAxis(F6V);Q_z=F6V.pixelFromPrice(0,i43,L_A);t3t.N_M(145);var p5r=t3t.a$j(8,8,3,18,4);g_O=F6V.layout.candleWidth - p5r;if(g_O < 2){g_O=1;}V9J=H9H.Studies.determineColor(v$8.outputs["Increasing Bar"]);s5P=H9H.Studies.determineColor(v$8.outputs["Decreasing Bar"]);F6V.startClip(v$8.panel);F6V.canvasColor(V92);if(!v$8.underlay){r9Q.globalAlpha=1;}if(!v$8.highlight && F6V.highlightedDraggable){r9Q.globalAlpha*=0.3;}for(var c_E=0;c_E < t3z.length;c_E++){L_R="_";L_R+="his";L_R+="t";P0B="_";P0B+="h";P0B+="is";P0B+="t";S5e="_";S5e+="hist";M81=t3z[c_E];t3t.N_M(14);a9_=t3z[t3t.a$j(c_E,1)];if(!a9_){a9_=F6V.getPreviousBar(F6V.chart,v$8.name + S5e,c_E);}if(!M81)continue;v5j=0;l6C=0;if(v$8.parameters && v$8.parameters.studyOverZonesEnabled){v5j=parseFloat(v$8.parameters.studyOverBoughtValue);l6C=parseFloat(v$8.parameters.studyOverSoldValue);}if(!a9_){r9Q.fillStyle="#CCCCCC";}else if(M81[v$8.name + P0B] > v5j && a9_[v$8.name + L_R] < M81[v$8.name + "_hist"]){r9Q.fillStyle=V9J;}else if(M81[v$8.name + "_hist"] < l6C && a9_[v$8.name + "_hist"] > M81[v$8.name + "_hist"]){r9Q.fillStyle=s5P;}else {r9Q.fillStyle="#CCCCCC";}if(M81.candleWidth){g_O=Math.floor(Math.max(1,M81.candleWidth - 2));}r9Q.fillRect(Math.floor(F6V.pixelFromBar(c_E,i43.chart) - g_O / 2),Math.floor(Q_z),Math.floor(g_O),Math.floor(F6V.pixelFromPrice(M81[v$8.name + "_hist"],i43,L_A) - Q_z));}F6V.endClip();};H9H.Studies.studyLibrary=H9H.extend(H9H.Studies.studyLibrary,{"Price Osc":{name:"Price Oscillator",calculateFN:H9H.Studies.calculatePriceOscillator,inputs:{Field:"field","Short Cycle":12,"Long Cycle":26,"Moving Average Type":u0c,"Points Or Percent":["Points","Percent"]}},"Vol Osc":{name:"Volume Oscillator",calculateFN:H9H.Studies.calculatePriceOscillator,inputs:{"Short Cycle":12,"Long Cycle":26,"Points Or Percent":[a6Y,"Percent"]},parameters:{init:{isVolume:!![]}}},RAVI:{name:"RAVI",seriesFN:H9H.Studies.displayRAVI,calculateFN:H9H.Studies.calculatePriceOscillator,inputs:{Field:"field","Moving Average Type":W8H,"Short Cycle":7,"Long Cycle":65},outputs:{"Increasing Bar":"#00DD00","Decreasing Bar":c_j},centerline:0,parameters:{init:{studyOverZonesEnabled:!![],studyOverBoughtValue:3,studyOverBoughtColor:"auto",studyOverSoldValue:-3,studyOverSoldColor:"auto"}},attributes:{studyOverBoughtValue:{min:0,step:"0.1"},studyOverSoldValue:{max:0,step:K76}}}});}};y9=i36=>{var F8M=f3BGj;var z_N,h8q,m4Z,O9Q;z_N="und";z_N+="e";z_N+="f";F8M.T$X();z_N+="ined";h8q=typeof _CIQ !== z_N?_CIQ:i36.CIQ;if(!h8q.Studies){m4Z="primeNumber feature r";m4Z+="equires first activating studies feature.";console.error(m4Z);}else {O9Q="Pr";O9Q+="ime Nu";O9Q+="mber ";O9Q+="Bands";h8q.Studies.calculatePrimeNumber=function(r7N,E74){var P9i,r1b,q2A,A80,h1g,F3E,M51,Q1F,e_S,G2d;P9i=[];r1b=E74.chart.scrubbed;for(var h$n=E74.startFrom;h$n < r1b.length;h$n++){q2A="Pri";q2A+="me Number Bands";A80=r1b[h$n];if(!A80)continue;h1g=A80.High;if(!isNaN(h1g)){for(var u2Z="0" << 32;h1g > 0 && h1g <= ("10" ^ 0);u2Z++){h1g*=10;}if(P_F(h1g)){h1g+=2;}h1g=Math.ceil(h1g);if(h1g % 2 === 0){h1g++;}while(!P_F(h1g)){h1g+=+"2";}F8M.N_M(31);h1g/=Math.pow(F8M.a$j("10",32),u2Z);}F3E=A80.Low;if(!isNaN(F3E)){for(var I85=0;F3E > +"0" && F3E <= ("10" | 0);I85++){F8M.N_M(29);F3E*=F8M.c0C(0,"10");}if(P_F(F3E)){F8M.j7J(14);F3E-=F8M.c0C("2",0);}F3E=Math.floor(F3E);if(F3E % 2 === 0){F3E--;}if(F3E > "0" - 0){while(!P_F(F3E)){F3E-=2;}F3E/=Math.pow(10,I85);}}if(E74.type == q2A){if(!isNaN(h1g)){A80["Prime Bands Top " + E74.name]=h1g;}if(!isNaN(F3E)){A80["Prime Bands Bottom " + E74.name]=Math.max(0,F3E);}}else {M51="Tolerance P";M51+="ercentage";Q1F=0;e_S=E74.inputs[M51] * (h1g - F3E) / ("100" ^ 0);F8M.N_M(63);var o8M=F8M.c0C(3,7,12);G2d=h1g + F3E - o8M * A80.Close;if(G2d < e_S){Q1F=1;}else if(G2d > e_S){Q1F=-1;}if(Q1F){A80["Result " + E74.name]=Q1F;}}}function P_F(e7B){var R2s;if(e7B <= 0){return !!"";}else if(e7B != Math.floor(e7B)){return ![];}else if(P9i[e7B] === !!({}) || P9i[e7B] === ![]){return P9i[e7B];}R2s=parseInt(Math.sqrt(e7B),10);for(var d1G=2;d1G <= R2s;d1G++){if(e7B % d1G === "0" * 1){P9i[e7B]=!({});return !1;}}P9i[e7B]=!0;return !0;}};h8q.Studies.studyLibrary=h8q.extend(h8q.Studies.studyLibrary,{"Prime Number":{name:"Prime Number Oscillator",range:"-1 to 1",calculateFN:h8q.Studies.calculatePrimeNumber,centerline:+"0",inputs:{"Tolerance Percentage":5},attributes:{"Tolerance Percentage":{min:0.1,step:0.1}}},"Prime Number Bands":{name:O9Q,overlay:!![],calculateFN:h8q.Studies.calculatePrimeNumber,seriesFN:h8q.Studies.displayChannel,inputs:{"Channel Fill":!!"1"},outputs:{"Prime Bands Top":"auto","Prime Bands Bottom":"auto","Prime Bands Channel":"auto"}}});}};v8=B7U=>{var q1w=f3BGj;var x06,d9v,d0j,J8K,o5J,F_2;x06=typeof _CIQ !== "undefined"?_CIQ:B7U.CIQ;q1w.f3X();if(!x06.Studies){d9v="pring feature ";d9v+="requires first activating s";d9v+="t";d9v+="udies feature.";console.error(d9v);}else {d0j="wee";d0j+="kly";J8K="#F";J8K+="F";J8K+="0";J8K+="000";o5J="#0";o5J+="0";o5J+="DD";o5J+="00";F_2="f";F_2+="ield";x06.Studies.calculateKST=function(P_u,j0G){var V9V,b4s,V8_,M4i,i_J,c11,O4t,C$U,S_1,U1a,V35,R2C,j4a,B3n,Q$R,e5s,P4D,j5y,O2a,a4a;V9V="Lig";V9V+="htest S";V9V+="MA";V9V+=" Period";b4s="Heavi";b4s+="est ";b4s+="Rate of Change Period";V8_="Heavy Rate of C";V8_+="hange Peri";V8_+="od";M4i="Light Rate of Change P";M4i+="eriod";i_J="Light";i_J+="es";i_J+="t Rate";i_J+=" of Change Period";c11="Cl";c11+="o";c11+="s";c11+="e";O4t=j0G.chart.scrubbed;C$U=j0G.inputs.Field;if(!C$U || C$U == "field"){C$U=c11;}S_1={};U1a={};S_1[1]=Number(j0G.inputs[i_J]);S_1[2]=Number(j0G.inputs[M4i]);S_1[3]=Number(j0G.inputs[V8_]);S_1[4]=Number(j0G.inputs[b4s]);q1w.N_M(46);U1a[q1w.c0C("1",0)]=Number(j0G.inputs[V9V]);U1a[2]=Number(j0G.inputs["Light SMA Period"]);U1a[+"3"]=Number(j0G.inputs["Heavy SMA Period"]);U1a[4]=Number(j0G.inputs["Heaviest SMA Period"]);V35=Number(j0G.inputs["Signal Period"]);for(R2C=j0G.startFrom;R2C < O4t.length;R2C++){if(!O4t[R2C])continue;for(j4a=1;j4a <= 4;j4a++){B3n="_";B3n+="RO";B3n+="C";if(R2C >= S_1[j4a] && O4t[R2C - S_1[j4a]] && O4t[R2C - S_1[j4a]][C$U]){q1w.N_M(82);var r11=q1w.a$j(12,7,13);O4t[R2C][B3n + j4a + " " + j0G.name]=("100" >> r11) * (O4t[R2C][C$U] / O4t[R2C - S_1[j4a]][C$U] - +"1");}}}for(j4a=1;j4a <= "4" - 0;j4a++){x06.Studies.MA("simple",U1a[j4a],"_ROC" + j4a + ((2382,1140) < 8215?" ":(6910,2120) <= ("123" ^ 0)?(33.59,4.91e+3):0x1377) + j0G.name,0,"_SMA" + j4a,P_u,j0G);}for(R2C=j0G.startFrom;R2C < O4t.length;R2C++){O4t[R2C]["KST " + j0G.name]=null;for(j4a=1;j4a <= 4;j4a++){q1w.j7J(1);var n_F=q1w.c0C(312,1558);q1w.N_M(82);var C$M=q1w.c0C(3657,9,193);q1w.j7J(14);var T1k=q1w.c0C(94428,89182);q1w.j7J(82);var E67=q1w.a$j(2,10,8846);q1w.j7J(38);var M4z=q1w.a$j(0,33,8,4);q1w.j7J(146);var b$e=q1w.c0C(21459,18,19,4,7152);q1w.N_M(17);var T5k=q1w.c0C(7,16,44,4);q1w.N_M(9);var w5o=q1w.c0C(517920,12,43680);q1w.j7J(147);var V80=q1w.c0C(1,6510,6520,3255);Q$R=O4t[R2C]["_SMA" + j4a + ((n_F,985.76) == (+"2816",C$M)?T1k:(E67,"523.31" * M4z) === b$e?(973.34,739.59) == (T5k,253.02)?w5o:(!!"1",V80):" ") + j0G.name];if(Q$R || Q$R === 0){q1w.N_M(5);O4t[R2C]["KST " + j0G.name]+=q1w.a$j(Q$R,j4a);}}}e5s=-1435656228;P4D=63420138;q1w.N_M(14);j5y=q1w.a$j("2",0);for(var D79=1;q1w.S9Y(D79.toString(),D79.toString().length,18216) !== e5s;D79++){x06.Studies.MA("simple",V35,"KST " + j0G.name,0,"KSTSignal",P_u,j0G);q1w.N_M(46);j5y+=q1w.c0C("2",0);}if(q1w.O1W(j5y.toString(),j5y.toString().length,20741) !== P4D){O2a="KSTSigna";O2a+="l";a4a="KS";a4a+="T";a4a+="Sign";a4a+="al";x06.Studies.MA("KST ",V35,a4a * j0G.name,+"7",O2a,P_u,j0G);}};x06.Studies.calculateSpecialK=function(T8d,J16){var U3T,y1w,R3c,l7r,c8c,p5L,e3h,R$k,n6q,v7d;U3T=J16.chart.scrubbed;y1w=J16.inputs.Field;if(!y1w || y1w == "field"){y1w="Close";}R3c=J16.inputs.Interval;if(!R3c){R3c="daily";}l7r={daily:[10,15,+"20",30,50,65,75,100,195,+"265",390,+"530"],weekly:[+"4",5,6,+"8",10,13,15,+"20",39,52,78,104]};c8c={daily:[+"10",10,10,+"15",50,65,75,100,130,"130" | 2,130,195],weekly:[4,5,6,+"8","10" | 2,13,15,20,26,26,26,39]};for(p5L=J16.startFrom;p5L < U3T.length;p5L++){if(!U3T[p5L])continue;for(e3h=0;e3h < l7r[R3c].length;e3h++){if(p5L >= l7r[R3c][e3h] && U3T[p5L - l7r[R3c][e3h]] && U3T[p5L - l7r[R3c][e3h]][y1w]){q1w.N_M(148);var A$o=q1w.a$j(97,97,20,20,4);q1w.j7J(14);var i2b=q1w.c0C(16,15);U3T[p5L]["_ROC" + e3h + " " + J16.name]=A$o * (U3T[p5L][y1w] / U3T[p5L - l7r[R3c][e3h]][y1w] - i2b);}}}for(e3h=0;e3h < c8c[R3c].length;e3h++){R$k="s";R$k+="im";R$k+="p";R$k+="le";n6q="da";n6q+="i";n6q+="l";n6q+="y";x06.Studies.MA(R3c == n6q?R$k:"exponential",c8c[R3c][e3h],"_ROC" + e3h + ((4608,"7413" << 32) < (+"9640",4740)?("909.46" - 0,7000) < +"9520"?("4790" * 1,3304) > (4110,641.88)?!![]:(!![],!1):0x30a:" ") + J16.name,0,"_MA" + e3h,T8d,J16);}for(p5L=J16.startFrom;p5L < U3T.length;p5L++){U3T[p5L]["Result " + J16.name]=null;for(e3h=0;e3h < c8c[R3c].length;e3h++){q1w.j7J(15);var C5e=q1w.c0C(69,833,7);q1w.j7J(149);var y9f=q1w.c0C(72580,3,11,1,68774);q1w.N_M(69);var g1G=q1w.a$j(223,28,11);v7d=U3T[p5L]["_MA" + e3h + (C5e > (y9f,g1G)?" ":("0x1452" << 0,!!"")) + J16.name];if(v7d || v7d === 0){q1w.j7J(150);U3T[p5L]["Result " + J16.name]+=q1w.a$j(1,e3h,4,v7d);}}}};x06.Studies.studyLibrary=x06.extend(x06.Studies.studyLibrary,{"Pring KST":{name:"Pring's Know Sure Thing",calculateFN:x06.Studies.calculateKST,inputs:{Field:F_2,"Lightest Rate of Change Period":10,"Lightest SMA Period":10,"Light Rate of Change Period":15,"Light SMA Period":10,"Heavy Rate of Change Period":+"20","Heavy SMA Period":10,"Heaviest Rate of Change Period":30,"Heaviest SMA Period":15,"Signal Period":9},outputs:{KST:o5J,KSTSignal:J8K}},"Pring Sp-K":{name:"Pring's Special K",calculateFN:x06.Studies.calculateSpecialK,inputs:{Field:"field",Interval:["daily",d0j]}}});}};L4=E2N=>{var k10=f3BGj;var i8f,q9S,h2w,M5Y,w4Z,A8C,j0c,y8q,c9T,Z8R,u5M,e2$;i8f=typeof _CIQ !== "undefined"?_CIQ:E2N.CIQ;q9S=typeof _timezoneJS !== "undefined"?_timezoneJS:E2N.timezoneJS;k10.T$X();if(!i8f.Studies){h2w="project";h2w+="edVolume feature requires first activating studies feature.";console.error(h2w);}else if(!i8f.Studies.studyLibrary.PVAT){M5Y="hh";M5Y+=":";M5Y+="mm:s";M5Y+="s";w4Z="#";w4Z+="b8";w4Z+="2c";w4Z+="0c";A8C="#fe6";A8C+="4";A8C+="1c";j0c="+";j0c+="50%";y8q="-";y8q+="15";y8q+="0";y8q+="%";c9T="-";c9T+="10";c9T+="0";c9T+="%";Z8R="-50";Z8R+="%";u5M="+5";u5M+="0";u5M+="%";e2$="Projected Volume at T";e2$+="ime";i8f.Studies.initProjectedVolume=function(g_E,I8U,s5w,h21,D8V,V8j){var q_s,J4b,c8O;var {market:X3o}=g_E.chart;q_s="00:00";if(X3o){q_s=X3o.getNormalOpen();}if(q_s.match(/^[\d]{2}:[\d]{2}$/)){q_s+=":00";}if(!s5w["Anchor Time"] || !s5w["Anchor Time"].length){J4b="Ancho";J4b+="r Time";s5w[J4b]=q_s;}c8O=i8f.Studies.initializeFN(g_E,I8U,s5w,h21,D8V,V8j);if(!g_E.currentlyImporting){c8O.defaultAnchorTime=q_s;}return c8O;};i8f.Studies.validateProjectedVolumeLookback=function(m4y,i$_){var {interval:l_b, periodicity:H6g}=m4y.layout;var {"Lookback Days":c25}=i$_.inputs;k10.j7J(151);return k10.a$j(c25,l_b,H6g,"10");};i8f.Studies.calculateProjectedVolume=function(w92,G1a){var k2n,S7C,l$S,j7X,f1O,i85,d6b,j5O,W9C,g3B,H9h,M7D,V2R,d2i,H0V,T5D,t_K,G27,o9X,k1I,W3W,m9M,Z7m,n4V,A$b,j6C,x22,y7o,f9$,o1z,a2o,Z_L,P_o,k8a,F2a,J8T,H_V,j_O,O$k,g8B,Z1m,o3c,O9R,o7D,a8$,L_5,l8L,B0C,J2N,n1v,A$F,N12,A4o,P5o,a9r,M$t,H2W,l0A,O9C,w6A;k2n="Aver";k2n+="age";k2n+=" Line";S7C="H";S7C+="H";S7C+=":m";S7C+="m";l$S="Market.Symbol";function V5f(n0y){k10.f3X();var r6b;k10.N_M(46);n0y.setHours(k10.a$j("0",0));k10.j7J(46);n0y.setMinutes(k10.c0C("0",0));r6b=i8f.Studies.getMarketOffset({stx:w92,localQuoteDate:n0y});return new Date(n0y.getTime() + r6b);}l$S+="o";l$S+="gy.isForexSymbol";j7X=":0";function K15(r1J,V7E,A83){while(V7E){r1J=new Date(new Date(r1J).setDate(r1J.getDate() + (A83?1:-1)));if(w$c.isMarketDate(r1J)){V7E--;}}return r1J;}j7X+="0";f1O="An";f1O+="chor Selector";var {interval:V_2, timeUnit:H1G, aggregationType:E$7}=w92.layout;var {symbol:B$i, scroll:G36, scrubbed:B2V, market:w$c}=w92.chart;i85=G1a.type === "PAV";function O88(L4s){return {hours:L4s.getHours(),minutes:L4s.getMinutes()};}d6b=G1a.study?G1a.study.name:G1a.type;if(i8f.ChartEngine.isDailyInterval(V_2)){G1a.error=`${d6b} is Intraday Only`;}else if(H1G === "tick"){G1a.error=`Tick mode not supported for ${d6b}`;}else if(H1G !== "minute"){k10.j7J(82);G1a.error=`${k10.c0C("ute periodicities not supported for ","b-min","Su")}${d6b}`;}else if(!E$7 || !["ohlc","heikinashi"].includes(E$7)){G1a.error=`Aggregation type not supported for ${d6b}`;}else if(!i8f.Studies.validateProjectedVolumeLookback(w92,G1a)){j5O=-2144216569;W9C=+"308328842";g3B=2;for(var m7b=1;k10.S9Y(m7b.toString(),m7b.toString().length,51491) !== j5O;m7b++){G1a.error=`Selected lookback/periodicity combo not supported for ${d6b}`;g3B+=2;}if(k10.O1W(g3B.toString(),g3B.toString().length,280) !== W9C){G1a.error=`Selected lookback/periodicity combo not supported for ${d6b}`;}}if(G1a.error){return;}if(G1a.inputs[f1O]){i8f.Studies.initAnchorHandle(w92,G1a);}else {i8f.Studies.removeAnchorHandle(w92,G1a);}H9h=w$c?w$c.getNormalOpen():"00:00";function C8A(r47){k10.f3X();console.error(`Expected data for ${d84(r47).toDateString()} but found none. This may be caused by gaps in your data or an improperly configured market definition.`);}if(H9h.match(/^[\d]{2}:[\d]{2}$/)){H9h+=j7X;}if(!w92.currentlyImporting){if(!G1a.defaultAnchorTime){G1a.defaultAnchorTime=H9h;}else if(H9h !== G1a.defaultAnchorTime){G1a.defaultAnchorTime=H9h;M7D=-1509490596;V2R=-948817835;d2i=2;for(var v7J=1;k10.S9Y(v7J.toString(),v7J.toString().length,38648) !== M7D;v7J++){G1a.inputs["Anchor Time"]=H9h;d2i+=2;}if(k10.O1W(d2i.toString(),d2i.toString().length,208) !== V2R){G1a.inputs[""]=H9h;}i8f.Studies.repositionAnchor(w92,G1a);return;}}var {"Lookback Days":A_U, "Anchor Time":o3p}=G1a.inputs;var [e8W,u9q,E8C = 0]=o3p.split(873 != (9000,384.38)?":":"e");function u0M(J$X,D4Q){var X_D,a3V,o9c;k10.f3X();X_D=d84(J$X);a3V=w$c.getOpen(X_D) || V5f(X_D);o9c=X8O(a3V);if(!D4Q){return o9c;}if(o9c < ("0" ^ 0)){o9c=X8O(K15(a3V,1,!!"1"));}if(o9c >= B2V.length){return !"1";}return o9c;}H0V=i8f.getFn(l$S)(B$i);T5D=G1a.getDependents(w92);t_K=0;G27=[];T5D.forEach(({inputs:R74, outputMap:k88})=>{k10.f3X();if(R74.Period){t_K=Math.max(parseInt(R74.Period),t_K);G27.push(...Object.keys(k88));}});G1a.dependentsOutputMap=G27;k1I=u0M(B2V.length - +"1",!!({}));W3W=Math.ceil(B2V.length - 1 - G36);k10.f3X();k10.N_M(14);m9M=u0M(k10.c0C(W3W,t_K));if(H0V && B2V[m9M] && i8f.dateToStr(B2V[m9M].DT,S7C) !== H9h){k10.N_M(14);m9M=u0M(k10.a$j(m9M,1));;}if(!H0V && G1a.startFrom > m9M && B2V[m9M] && B2V[m9M]["V " + G1a.name] !== undefined && G27.every(D8N=>{return ![undefined,null].includes(B2V[m9M][D8N]);}) && k1I !== !!""){o9X=k1I;;}else {o9X=m9M;}Z7m=K15(d84(m9M),A_U);Z7m.setHours(0,0,0);n4V=u0M(0,!0);A$b=(n4V || n4V === 0) && X8O(K15(B2V[n4V].DT,A_U,!!1));if(B2V[0].DT > Z7m){if(w92.quoteDriver){w92.quoteDriver.extendHistoricalData({from:Z7m});if(A$b > 0){o9X=A$b;}else {return;}}else {k10.j7J(1);return G1a.error=`${k10.c0C("Not e","nough data to calculate ")}${d6b}`;}}if(o9X < 0 || o9X > B2V.length - 1){return;}function d84(l69){var j5J;j5J="s";k10.f3X();j5J+="cr";j5J+="ubb";j5J+="ed";return w92.dateFromTick(l69,null,!!({}),j5J);}j6C=B2V.length - G1a.startFrom === 1 && G1a.cachedFutureTicks && G1a.cachedLastProjection && +G1a.cachedLastProjection.DT === +B2V[B2V.length - 1].DT && B2V[o9X]["PV " + G1a.name];if(j6C){k10.j7J(3);var f0c=k10.a$j(9,10,0);B2V[B2V.length - f0c]["PV " + G1a.name]=G1a.cachedLastProjection.projectedValue;G1a.appendFutureTicks(w92,G1a.cachedFutureTicks);o9X=G1a.startFrom;}else {x22="P";x22+="V";x22+=" ";G1a.cachedFutureTicks=null;G1a.cachedLastProjection=null;y7o=[k1I];f9$=[];for(var r_l=0;r_l < A_U;r_l++){o1z=u0M(y7o[+"0"] - 1);y7o.unshift(o1z);;}while(y7o[A_U] >= o9X){a2o=y7o.pop();if(!B2V[a2o]){return C8A(a2o);}Z_L=O88(B2V[a2o].DT);var {hours:E8Y, minutes:p9t}=Z_L;P_o=w$c.getClose(B2V[a2o].DT);k8a=void 0;if(!P_o){k8a={hours:24,minutes:0};}else {F2a=w$c.getNextClose(B2V[a2o].DT);k8a=O88(P_o);while(!(k8a.hours === 0 && k8a.minutes === 0) && P_o.getDate() === F2a.getDate()){P_o=F2a;F2a=w$c.getNextClose(F2a);}k8a=O88(P_o);if(k8a.hours === 0){k8a.hours=24;}}J8T=y7o.slice();for(var c_z=0;c_z < J8T.length;c_z++){H_V=J8T[c_z];if(!B2V[H_V]){return C8A(H_V);}var {hours:R2j, minutes:O3Y}=O88(B2V[H_V].DT);if(R2j < E8Y || R2j === E8Y && O3Y < p9t){do {H_V++;({hours:R2j, minutes:O3Y}=O88(B2V[H_V].DT));}while(!(R2j === E8Y && O3Y === p9t));}J8T[c_z]=H_V;}while(E8Y < k8a.hours || E8Y === k8a.hours && p9t < k8a.minutes){j_O=!1;O$k=void 0;g8B=void 0;Z1m=0;o3c=0;for(var U_f=0;U_f < J8T.length;U_f++){O9R=J8T[U_f];if(O9R === null)continue;o7D=B2V[O9R];if(!o7D){return C8A(O9R);}var {hours:T$3, minutes:f2_}=O88(o7D.DT);a8$=o7D.DT.getDate();if(T$3 === E8Y && f2_ === p9t){Z1m+=o7D.Volume;o3c++;J8T[U_f]++;if(B2V[J8T[U_f]].DT.getDate() !== a8$){J8T[U_f]=null;}else if(!j_O){({hours:O$k, minutes:g8B}=O88(B2V[J8T[U_f]].DT));j_O=!![];;}}}E8Y=O$k;p9t=g8B;if(o3c === 0)break;k10.N_M(7);L_5=k10.c0C(Z1m,o3c);if(B2V[a2o]){B2V[a2o]["PV " + G1a.name]=L_5;}else {l8L="P";l8L+="V";l8L+=" ";f9$.push({[l8L + G1a.name]:L_5});}a2o++;}y7o.unshift(u0M(y7o[0] - +"1"));;}G1a.cachedLastProjection={DT:B2V[B2V.length - 1].DT,projectedValue:B2V[B2V.length - 1][x22 + G1a.name]};G1a.cachedFutureTicks=f9$;G1a.appendFutureTicks(w92,f9$);}function X8O(s0Q){k10.T$X();return w92.tickFromDate(s0Q,null,null,!![],"scrubbed");}B0C=null;J2N=0;n1v=+"0";if(j6C && i85){while(o9X > +"0"){k10.N_M(14);N12=B2V[k10.c0C(o9X,1)]["V " + G1a.name];if(N12 || N12 === +"0"){J2N=N12;break;}o9X--;}}for(var q08=o9X;q08 < B2V.length;q08++){A4o="V";A4o+=" ";P5o="America/New_Y";P5o+="ork";a9r=B2V[q08];M$t=a9r.Volume;H2W=a9r["PV " + G1a.name];if(!a9r.futureTick){A$F=q08;}if(B0C === null){B0C=i8f.Studies.getMarketOffset({stx:w92,localQuoteDate:B2V[q08].DT,shiftToDateBoundary:!![]});}l0A=new Date(new Date(a9r.DT).getTime() + B0C);O9C=B2V[q08 - 1] && new Date(new Date(B2V[q08 - 1].DT).getTime() + B0C);w6A=new q9S.Date(a9r.DT,w$c.market_def.market_tz || P5o);w6A.setHours(e8W,u9q,E8C);k10.N_M(1);w6A=new Date(k10.a$j(w6A,B0C));w6A.setDate(l0A.getDate());if(O9C && l0A.getDate() !== O9C.getDate()){B0C=null;J2N=0;n1v=0;}if(l0A < w6A){a9r["V " + G1a.name]=0;a9r["PV " + G1a.name]=0;continue;}if(i85){J2N+=M$t;n1v+=H2W;}else {J2N=M$t;n1v=H2W;}a9r[A4o + G1a.name]=J2N;if(!j6C){a9r["PV " + G1a.name]=n1v;}if([NaN,null,undefined].includes(J2N) && !a9r.futureTick){k10.N_M(1);G1a.error=`${d6b}${k10.a$j(" requires vol","ume")}`;return;}}G1a.cachedLastProjection.projectedValue=B2V[A$F]["PV " + G1a.name];G1a.outputMap={};G1a.outputMap["V " + G1a.name]="";G1a.outputMap["PV " + G1a.name]=k2n;T5D.forEach(A0e=>{A0e.startFrom=o9X;A0e.study.calculateFN(w92,A0e);});};i8f.Studies.displayProjectedVolume=function(T6f,g0Z,p6G){var y6b,S9U,q8C,g1y,P53,W_k,s4I,G_J,I9E,C08,l5V;y6b="stx_volume_";y6b+="underla";y6b+="y_";y6b+="down";S9U="stx_volu";S9U+="me_";S9U+="under";S9U+="lay_up";q8C="o";q8C+="bj";q8C+="ect";g1y="A";g1y+="lert Bar";if(g0Z.error){return i8f.Studies.removeAnchorHandle(T6f,g0Z);}var {"Alert Threshold":m$0 = ""}=g0Z.inputs;k10.N_M(152);var L77=k10.a$j(13,15,2,0);k10.j7J(85);var h05=k10.c0C(110,10,15,1490);k10.j7J(9);var D_n=k10.c0C(1754,18,103);P53=parseInt(m$0.slice(0,L77),h05) / D_n;W_k=g0Z.outputs[g1y];if(typeof W_k === q8C){W_k=W_k.color;}g0Z.volumeField="V " + g0Z.name;g0Z.alignStepToSide=!!({});g0Z.extendToEndOfLastBar=!!({});g0Z.lineWidth=+"2";s4I=T6f.canvasStyle(S9U).opacity;G_J=T6f.canvasStyle(y6b).opacity;g0Z.colorFunction=function(x6I){var G5W,I92,o7T,s$D,m0v,M8N;var {Open:v2c, Close:y$a, iqPrevClose:F2N}=x6I;G5W=T6f.colorByCandleDirection?v2c:F2N;k10.N_M(153);I92=k10.a$j(G5W,y$a);k10.f3X();o7T=x6I["PV " + g0Z.name];s$D=x6I["V " + g0Z.name];k10.j7J(154);m0v=k10.a$j(o7T,1,P53);M8N=P53 < +"0"?s$D < m0v:s$D > m0v;return {fill_color:M8N && W_k || (I92?this.fill_color_down:this.fill_color_up),border_color:I92?this.border_color_down:this.border_color_up,opacity:M8N?1:I92?G_J:s4I,border_opacity:I92?G_J:s4I};};I9E=g0Z.study?g0Z.study.name:g0Z.type;var {loadingMore:K7F}=T6f.chart;C08=p6G.some(w36=>{return w36 && w36[g0Z.volumeField] && w36["PV " + g0Z.name];});l5V=p6G[0] && !p6G[0].futureTick && (p6G[0]["PV " + g0Z.name] === undefined || (g0Z.dependentsOutputMap || []).some(J3V=>{k10.T$X();return [undefined,null].includes(p6G[+"0"][J3V]);}));if(!C08 && K7F){return g0Z.error=`Fetching data for ${I9E}`;}i8f.Studies.createVolumeChart(T6f,g0Z,p6G);i8f.Studies.displaySeriesAsLine(T6f,g0Z,p6G);if(g0Z.anchorHandle){i8f.Studies.displayAnchorHandleAndLine(T6f,g0Z,p6G);}if(l5V){i8f.Studies.calculateProjectedVolume(T6f,g0Z);}};i8f.Studies.studyLibrary=i8f.extend(i8f.Studies.studyLibrary,{PVAT:{name:e2$,range:"0 to max",yAxis:{ground:!"",initialMarginTop:0,zoom:0},calculateFN:i8f.Studies.calculateProjectedVolume,seriesFN:i8f.Studies.displayProjectedVolume,initializeFN:i8f.Studies.initProjectedVolume,removeFN:i8f.Studies.removeAnchorHandle,inputs:{"Lookback Days":10,"Anchor Time":"","Alert Threshold":["+150%","+125%","+100%","+75%",u5M,"+25%","None","-25%",Z8R,"-75%",c9T,"-125%",y8q],"Anchor Selector":!!1},outputs:{"Average Line":"#fe641c","Alert Bar":"#cfbd0e","Up Volume":"#8cc176","Down Volume":"#b82c0c"},parameters:{plotType:"step"},attributes:{"Anchor Time":{placeholder:"hh:mm:ss",step:+"1"},"Alert Threshold":{defaultSelected:j0c}}},PAV:{name:"Projected Aggregate Volume",range:"0 to max",yAxis:{ground:!!"1",initialMarginTop:+"0",zoom:0},calculateFN:i8f.Studies.calculateProjectedVolume,seriesFN:i8f.Studies.displayProjectedVolume,initializeFN:i8f.Studies.initProjectedVolume,removeFN:i8f.Studies.removeAnchorHandle,inputs:{"Lookback Days":10,"Anchor Time":"","Anchor Selector":!!"1"},outputs:{"Average Line":A8C,"Up Volume":"#8cc176","Down Volume":w4Z},parameters:{plotType:"step"},attributes:{"Anchor Time":{placeholder:M5Y,step:1}}}});}};o3=c28=>{var H8u,I5T;H8u=typeof _CIQ !== "undefined"?_CIQ:c28.CIQ;if(!H8u.Studies){I5T="psychologic";I5T+="alLine feature requires first activating st";I5T+="udies feature.";console.error(I5T);}else {H8u.Studies.calculatePsychologicalLine=function(K97,P0t){var l89,D75,b_p,d_3,F$h,a6L;l89=P0t.chart.scrubbed;if(l89.length < P0t.days + 1){P0t.error=!!"1";return;}D75=[];f3BGj.N_M(85);var i37=f3BGj.c0C(1400,11,16,22124);b_p=i37 / P0t.days;f3BGj.f3X();d_3=0;for(var B6w=Math.max(P0t.startFrom - P0t.days,1);B6w < l89.length;B6w++){F$h="Re";F$h+="sult ";if(l89[B6w].futureTick)break;a6L=Number(l89[B6w].Close > l89[B6w - 1].Close);if(a6L){d_3+=b_p;}D75.push(a6L);if(D75.length > P0t.days){d_3-=D75.shift() * b_p;}if(B6w < P0t.startFrom)continue;if(!isNaN(l89[B6w].Close)){l89[B6w][F$h + P0t.name]=d_3;}}};H8u.Studies.studyLibrary=H8u.extend(H8u.Studies.studyLibrary,{PSY:{name:"Psychological Line",range:"0 to 100",calculateFN:H8u.Studies.calculatePsychologicalLine,inputs:{Period:20}}});}};i8=f8y=>{var W9k,Q_4,L_2;W9k=typeof _CIQ !== "undefined"?_CIQ:f8y.CIQ;f3BGj.f3X();if(!W9k.Studies){Q_4="qsti";Q_4+="ck feature requires first activating studies feature.";console.error(Q_4);}else {L_2="QSti";L_2+="c";L_2+="k";W9k.Studies.calculateQStick=function(A$P,M5i){var H2v,h6w;f3BGj.T$X();H2v="R";H2v+="e";H2v+="sult";h6w=M5i.chart.scrubbed;if(h6w.length < M5i.days + 1){M5i.error=!0;return;}for(var l8G=M5i.startFrom;l8G < h6w.length;l8G++){h6w[l8G]["_Close-Open " + M5i.name]=h6w[l8G].Close - h6w[l8G].Open;}W9k.Studies.MA(M5i.inputs["Moving Average Type"],M5i.days,"_Close-Open " + M5i.name,0,H2v,A$P,M5i);};W9k.Studies.studyLibrary=W9k.extend(W9k.Studies.studyLibrary,{QStick:{name:L_2,calculateFN:W9k.Studies.calculateQStick,inputs:{Period:8,"Moving Average Type":"ma"}}});}};O$=o6W=>{var I7n=f3BGj;var P2N,w7b,E4r,c7g,D3m,Y0Q,k0e;P2N=typeof _CIQ !== "undefined"?_CIQ:o6W.CIQ;I7n.T$X();if(!P2N.Studies){console.error("rainbow feature requires first activating studies feature.");}else {w7b="#";w7b+="FF";w7b+="0000";E4r="#F";E4r+="F";E4r+="00F";E4r+="F";c7g="#7";c7g+="F00FF";D3m="#";D3m+="0";D3m+="0";D3m+="00FF";Y0Q="#";Y0Q+="00F";Y0Q+="FFF";k0e="#";k0e+="7FF";k0e+="F";k0e+="00";P2N.Studies.calculateRainbow=function(H99,A7a){var E7V,G7u,V2A,v0I,k50,P49,j21,r$L,J$d,k9k,a_h,F1R,j4Q,m5G,k6q,R8k,w8z;function x4U(B0c,X5E){var Y7K,L_r;I7n.N_M(102);var I4v=I7n.c0C(16,14,12,19);Y7K=Number.MAX_VALUE * I4v;L_r=Number.MAX_VALUE;for(var c8o=X5E - B0c + 1;c8o <= X5E;c8o++){if(c8o < +"0")continue;Y7K=Math.max(Y7K,V2A[c8o].Close);L_r=Math.min(L_r,V2A[c8o].Close);}return [L_r,Y7K];}E7V="O";E7V+="s";E7V+="c";G7u="f";G7u+="i";G7u+="e";G7u+="ld";V2A=A7a.chart.scrubbed;if(V2A.length < A7a.days + 1){A7a.error=!"";return;}v0I=A7a.inputs.Field;if(!v0I || v0I == G7u){v0I="Close";}k50=v0I;for(var p3P=1;p3P <= 10;p3P++){P2N.Studies.MA("simple",A7a.days,k50,"0" - 0,"SMA" + p3P,H99,A7a);I7n.N_M(24);var m2z=I7n.c0C(68420,62170,11,19);k50="SMA" + p3P + (8214 !== 239.2?" ":m2z) + A7a.name;}for(var v7K=Math.max(A7a.startFrom,10);v7K < V2A.length;v7K++){if(!V2A[v7K])continue;if(V2A[v7K].futureTick)break;P49=0;I7n.j7J(31);j21=I7n.a$j("0",96);I7n.N_M(27);var j85=I7n.c0C(17,18);r$L=Number.MAX_VALUE * j85;J$d=Number.MAX_VALUE;for(p3P=1;p3P <= 10;p3P++){I7n.N_M(155);var R_x=I7n.c0C(1992,26000,58500,18);I7n.j7J(1);var z9b=I7n.a$j(538,2692);I7n.j7J(1);var g_N=I7n.c0C(6143,10);k9k=V2A[v7K]["SMA" + p3P + (R_x < (+"1788",z9b)?" ":g_N) + A7a.name];if(k9k || k9k === 0){P49+=k9k;j21++;r$L=Math.max(r$L,k9k);J$d=Math.min(J$d,k9k);}}if(A7a.name.indexOf("Osc") > -1){a_h=x4U(A7a.inputs["HHV/LLV Lookback"],v7K);if(j21){F1R="Zer";F1R+="o";F1R+=" ";j4Q="Ov";j4Q+="er ";m5G="O";m5G+="ver ";k6q="_hi";k6q+="st";I7n.j7J(156);var h53=I7n.c0C(150,1500,2,4,3);V2A[v7K][A7a.name + k6q]=h53 * (V2A[v7K][v0I] - P49 / j21) / Math.max(0.000001,a_h[+"1"] - a_h[0]);I7n.N_M(157);var e_M=I7n.c0C(16,8,18,0,5);V2A[v7K][m5G + A7a.name]=("100" ^ 0) * (r$L - J$d) / Math.max(0.000001,a_h[e_M] - a_h[+"0"]);V2A[v7K]["Under " + A7a.name]=-V2A[v7K][j4Q + A7a.name];V2A[v7K][F1R + A7a.name]=0;}}}if(A7a.name.indexOf(E7V) > -1){R8k="Under";R8k+=" ";w8z="Pos";w8z+="itive B";w8z+="ar";A7a.outputMap={};A7a.outputMap["Over " + A7a.name]=w8z;A7a.outputMap[R8k + A7a.name]="Negative Bar";A7a.outputMap["Zero " + A7a.name]="";A7a.outputMap[A7a.name + "_hist"]="";}};P2N.Studies.displayRainbowMA=function(o3W,t0u,z3c){var h1L;h1L=o3W.panels[t0u.panel];I7n.T$X();for(var Q_Y=10;Q_Y > 0;Q_Y--){P2N.Studies.displayIndividualSeriesAsLine(o3W,t0u,h1L,"SMA" + Q_Y + ((3150,643.16) != 1993?" ":(1890,6870) >= 1910?(3970,6401) <= (702.52,2550)?("x",0x227e):"I":(9.70e+3,"928.77" - 0)) + t0u.name,z3c);}};P2N.Studies.displayRainbowOsc=function(B_Z,J7V,z06){var d39,V8c,y4c,k8H,A6b,h96,f$x,z6f,K8a,p1s,j6n,w3b,l0x,e_3,J6c,J3G,B_7;d39="Un";d39+="d";d39+="er";d39+=" ";V8c="Ze";V8c+="ro";V8c+=" ";y4c="Neg";y4c+="at";y4c+="ive Bar";k8H="O";k8H+="v";k8H+="er";k8H+=" ";P2N.Studies.displaySeriesAsLine(B_Z,J7V,z06);A6b=B_Z.panels[J7V.panel];h96=J7V.getContext(B_Z);f$x=J7V.getYAxis(B_Z);B_Z.startClip(J7V.panel);if(!J7V.highlight && B_Z.highlightedDraggable){h96.globalAlpha*=0.3;}z6f=B_Z.pixelFromPrice(0,A6b,f$x);K8a=A6b.name != J7V.chart.name;p1s=P2N.Studies.determineColor(J7V.outputs["Positive Bar"]);h96.strokeStyle=p1s;B_Z.plotDataSegmentAsLine(k8H + J7V.name,A6b,{skipTransform:K8a,label:!1,yAxis:f$x});j6n=h96.createLinearGradient(0,z6f,0,f$x.flipped?f$x.bottom:f$x.top);j6n.addColorStop(0,B_Z.containerColor);j6n.addColorStop(+"1",p1s);P2N.prepareChannelFill(B_Z,{skipTransform:K8a,color:j6n,opacity:!J7V.highlight && B_Z.highlightedDraggable?"0.3" - 0:1,panelName:J7V.panel,topBand:"Over " + J7V.name,bottomBand:"Zero " + J7V.name,yAxis:f$x});w3b=P2N.Studies.determineColor(J7V.outputs[y4c]);h96.strokeStyle=w3b;B_Z.plotDataSegmentAsLine("Under " + J7V.name,A6b,{skipTransform:K8a,label:!({}),yAxis:f$x});l0x=h96.createLinearGradient(0,z6f,0,f$x.flipped?f$x.top:f$x.bottom);l0x.addColorStop(0,B_Z.containerColor);l0x.addColorStop(1,w3b);P2N.prepareChannelFill(B_Z,{skipTransform:K8a,color:l0x,opacity:!J7V.highlight && B_Z.highlightedDraggable?0.3:1,panelName:J7V.panel,topBand:V8c + J7V.name,bottomBand:d39 + J7V.name,yAxis:f$x});I7n.N_M(1);var O1Z=I7n.c0C(0,2);e_3=B_Z.layout.candleWidth - O1Z;if(e_3 < +"2"){e_3=1;}B_Z.canvasColor("stx_histogram");if(!J7V.underlay){h96.globalAlpha=+"1";}if(!J7V.highlight && B_Z.highlightedDraggable){h96.globalAlpha*=0.3;}h96.fillStyle="#CCCCCC";for(var Z1h=0;Z1h < z06.length;Z1h++){J6c="_his";J6c+="t";J3G="_hi";J3G+="s";J3G+="t";B_7=z06[Z1h];if(!B_7)continue;if(B_7[J7V.name + J3G] > +"0"){h96.fillStyle=p1s;}else if(B_7[J7V.name + "_hist"] < "0" * 1){h96.fillStyle=w3b;}if(B_7.candleWidth){e_3=Math.floor(Math.max(+"1",B_7.candleWidth - 2));}h96.fillRect(Math.floor(B_Z.pixelFromBar(Z1h,A6b.chart) - e_3 / 2),Math.floor(z6f),Math.floor(e_3),Math.floor(B_Z.pixelFromPrice(B_7[J7V.name + J6c],A6b,f$x) - z6f));}B_Z.endClip();};P2N.Studies.studyLibrary=P2N.extend(P2N.Studies.studyLibrary,{"Rainbow MA":{name:"Rainbow Moving Average",overlay:!!"1",calculateFN:P2N.Studies.calculateRainbow,seriesFN:P2N.Studies.displayRainbowMA,inputs:{Period:2,Field:"field"},outputs:{SMA1:"#FF0000",SMA2:"#FF7F00",SMA3:"#FFFF00",SMA4:k0e,SMA5:"#00FF7F",SMA6:Y0Q,SMA7:"#007FFF",SMA8:D3m,SMA9:c7g,SMA10:E4r}},"Rainbow Osc":{name:"Rainbow Oscillator",calculateFN:P2N.Studies.calculateRainbow,seriesFN:P2N.Studies.displayRainbowOsc,centerline:0,inputs:{Period:2,Field:"field","HHV/LLV Lookback":10},outputs:{"Positive Bar":"#00DD00","Negative Bar":w7b}}});}};r_=P6O=>{var a$B,Y6c,G19,q$o;a$B="undefi";a$B+="ned";Y6c=typeof _CIQ !== a$B?_CIQ:P6O.CIQ;if(!Y6c.Studies){console.error("randomWalk feature requires first activating studies feature.");}else {G19="#000";G19+="0FF";q$o="#F";q$o+="F0000";Y6c.Studies.calculateRandomWalk=function(m2n,b7Y){var d3t,a83,d8o,k_v,o5B,B1N,h7$,l3n,R$7,I7y;d3t=b7Y.chart.scrubbed;if(d3t.length < b7Y.days + +"1"){b7Y.error=!0;return;}for(var R1w=Math.max(2,b7Y.startFrom);R1w < d3t.length;R1w++){a83=+"0";d8o=d3t[R1w].High;k_v=d3t[R1w].Low;o5B=0;B1N=0;for(var C37=1;C37 <= b7Y.days;C37++){if(d3t[R1w].futureTick)break;if(R1w <= C37){o5B=B1N=0;break;}a83+=d3t[R1w - C37].trueRange;h7$=a83 / C37 * Math.sqrt(C37);if(h7$){l3n=(d8o - d3t[R1w - C37].Low) / h7$;R$7=(d3t[R1w - C37].High - k_v) / h7$;o5B=Math.max(o5B,l3n);B1N=Math.max(B1N,R$7);}}if(!d3t[R1w].futureTick && (!isNaN(d8o) || !isNaN(k_v))){I7y="Random Walk";I7y+=" L";I7y+="o";I7y+="w ";d3t[R1w]["Random Walk High " + b7Y.name]=o5B;d3t[R1w][I7y + b7Y.name]=B1N;}}};Y6c.Studies.studyLibrary=Y6c.extend(Y6c.Studies.studyLibrary,{"Random Walk":{name:"Random Walk Index",calculateFN:Y6c.Studies.calculateRandomWalk,outputs:{"Random Walk High":q$o,"Random Walk Low":G19}}});}};O5=H6W=>{var N96;N96=typeof _CIQ !== "undefined"?_CIQ:H6W.CIQ;if(!N96.Studies){console.error("relativeVigor feature requires first activating studies feature.");}else {N96.Studies.calculateRelativeVigor=function(z0I,X8k){var D4K,S05,d_H,d8U,G1Y,L0a,z5O,t0R,j27,h2L,b$9,H_I,S7x;D4K="R";D4K+="el Vig ";S05="_De";S05+="n";S05+="om";d_H="triang";d_H+="ul";d_H+="ar";d8U="triangul";d8U+="ar";G1Y=X8k.chart.scrubbed;if(G1Y.length < X8k.days + ("1" << 64)){X8k.error=!!({});return;}for(L0a=X8k.startFrom;L0a < G1Y.length;L0a++){z5O="_C";z5O+="ha";z5O+="n";z5O+="ge ";t0R=G1Y[L0a];if(!isNaN(t0R.Close) && !isNaN(t0R.Open)){t0R[z5O + X8k.name]=t0R.Close - t0R.Open;}if(!isNaN(t0R.High) && !isNaN(t0R.Low)){t0R["_Range " + X8k.name]=t0R.High - t0R.Low;}}N96.Studies.MA(d8U,4,"_Change " + X8k.name,0,"_Numer",z0I,X8k);N96.Studies.MA(d_H,4,"_Range " + X8k.name,0,S05,z0I,X8k);j27=[];h2L=[];for(L0a=Math.max(X8k.startFrom - X8k.days,0);L0a < G1Y.length;L0a++){if(G1Y[L0a].futureTick)break;if(G1Y[L0a]["_Numer " + X8k.name] === null && G1Y[L0a]["_Denom " + X8k.name] === null)continue;j27.push(G1Y[L0a]["_Numer " + X8k.name]);h2L.push(G1Y[L0a]["_Denom " + X8k.name]);if(j27.length > X8k.days){j27.shift();h2L.shift();}b$9=0;H_I=0;for(S7x=0;S7x < j27.length;S7x++){b$9+=j27[S7x];}for(S7x=0;S7x < h2L.length;S7x++){H_I+=h2L[S7x];}if(H_I === "0" * 1){H_I=0.00000001;}if(L0a < X8k.startFrom)continue;f3BGj.j7J(7);G1Y[L0a]["Rel Vig " + X8k.name]=f3BGj.a$j(b$9,H_I);}N96.Studies.MA("triangular",4,D4K + X8k.name,"0" >> 64,"RelVigSignal",z0I,X8k);for(L0a=X8k.startFrom;L0a < G1Y.length;L0a++){G1Y[L0a][X8k.name + "_hist"]=G1Y[L0a]["Rel Vig " + X8k.name] - G1Y[L0a]["RelVigSignal " + X8k.name];}X8k.outputMap[X8k.name + "_hist"]="";};N96.Studies.studyLibrary=N96.extend(N96.Studies.studyLibrary,{"Rel Vig":{name:"Relative Vigor Index",seriesFN:N96.Studies.displayHistogramWithSeries,calculateFN:N96.Studies.calculateRelativeVigor,inputs:{Period:10},outputs:{"Rel Vig":"auto",RelVigSignal:"#FF0000","Increasing Bar":"#00DD00","Decreasing Bar":"#FF0000"}}});}};i3=I6S=>{var R7i=f3BGj;var H1I,P5U;H1I="u";H1I+="n";H1I+="define";R7i.T$X();H1I+="d";P5U=typeof _CIQ !== H1I?_CIQ:I6S.CIQ;if(!P5U.Studies){console.error("rsi feature requires first activating studies feature.");}else {P5U.Studies.calculateRSI=function(K94,C$x){var Q6n,O3p,k$J,m1O,v2j,h6e,B87,Q2w;Q6n=C$x.chart.scrubbed;O3p=C$x.inputs.Field;R7i.T$X();if(!O3p || O3p == "field"){O3p="Close";}if(Q6n.length < C$x.days + 1){C$x.error=!0;return;}for(var v8L=C$x.startFrom;v8L < Q6n.length;v8L++){if(!v8L)continue;k$J=Q6n[v8L];R7i.j7J(14);m1O=Q6n[R7i.a$j(v8L,1)];if(!k$J[O3p] && k$J[O3p] !== "0" * 1)continue;if(!m1O[O3p] && m1O[O3p] !== 0)continue;v2j=k$J[O3p] - m1O[O3p];h6e=Math.min(v8L,C$x.days);B87=m1O["_avgG " + C$x.name];if(!B87){B87=0;}R7i.N_M(7);B87-=R7i.c0C(B87,h6e);Q2w=m1O["_avgL " + C$x.name];if(!Q2w){Q2w=0;}R7i.j7J(7);Q2w-=R7i.a$j(Q2w,h6e);if(v2j > "0" >> 32){R7i.N_M(7);B87+=R7i.a$j(v2j,h6e);}else if(v2j <= 0){R7i.j7J(7);Q2w-=R7i.a$j(v2j,h6e);}else continue;if(v8L >= C$x.days){if((B87 || B87 !== 0) && (Q2w || Q2w !== 0)){k$J["RSI " + C$x.name]=I8M(B87,Q2w);}}k$J["_avgG " + C$x.name]=B87;k$J["_avgL " + C$x.name]=Q2w;}function I8M(O9Y,C0d){var t84,W79,E7m,R1C;if(C0d === 0){return 100;}t84=1473040642;W79=-262708369;E7m=2;for(var G45=1;R7i.O1W(G45.toString(),G45.toString().length,68909) !== t84;G45++){R7i.N_M(14);R1C=R7i.a$j(O9Y,C0d);R7i.N_M(158);return R7i.a$j(465,"2",R1C,330);}R7i.T$X();if(R7i.O1W(E7m.toString(),E7m.toString().length,1299) !== W79){R7i.N_M(7);R1C=R7i.a$j(O9Y,C0d);R7i.N_M(159);return R7i.a$j(100,"1",R1C,100);}}C$x.zoneOutput="RSI";};P5U.Studies.studyLibrary=P5U.extend(P5U.Studies.studyLibrary,{rsi:{name:"RSI",inputs:{Period:+"14",Field:"field"},calculateFN:P5U.Studies.calculateRSI,range:"0 to 100",outputs:{RSI:"auto"},parameters:{init:{studyOverZonesEnabled:!![],studyOverBoughtValue:+"80",studyOverBoughtColor:"auto",studyOverSoldValue:20,studyOverSoldColor:"auto"}}}});}};f3BGj.T$X();Q7=u4v=>{var E0y=f3BGj;E0y.f3X();var K6o,M65,J3s,l5D,I5R,Y2L,u3i;K6o="un";K6o+="de";K6o+="fin";K6o+="ed";M65=typeof _CIQ !== K6o?_CIQ:u4v.CIQ;if(!M65.Studies){E0y.j7J(14);J3s=E0y.a$j("87314054",0);l5D=1060655783;E0y.N_M(14);I5R=E0y.a$j("2",0);for(var D6e=1;E0y.O1W(D6e.toString(),D6e.toString().length,82177) !== J3s;D6e++){console.error("");I5R+=2;}if(E0y.O1W(I5R.toString(),I5R.toString().length,7892) !== l5D){console.error("");}console.error("schaffTrendCycle feature requires first activating studies feature.");}else {Y2L="a";Y2L+="u";Y2L+="t";Y2L+="o";u3i="fiel";u3i+="d";M65.Studies.calculateSchaff=function(P_V,D3g){var n33,N10,R_K,v4G,f2A,Y8d,P$4,G7V,B2v,i6M,s8I,M6m,k2P,I7_,A0B,p5a,m8v,W5U,I53,u3z,H$L,t35,B3u;n33="_MAC";n33+="D";n33+="2";N10="Cl";N10+="o";N10+="s";N10+="e";R_K="Short";R_K+=" ";R_K+="Cycle";v4G=D3g.chart.scrubbed;function V9H(X$M,s1$,U3X){var A1M,d8m,q$1;A1M=null;d8m=null;for(var A67=s1$ - X$M + 1;A67 <= s1$;A67++){E0y.N_M(1);var y_M=E0y.a$j(1132,6);E0y.j7J(17);var A8Q=E0y.a$j(9615,2,9600,5);E0y.j7J(19);var y5H=E0y.a$j(14,10,656,91169);E0y.N_M(157);var P1Z=E0y.a$j(18,13,17,468,20);E0y.j7J(160);var n7f=E0y.a$j(15,9460,5070,56760);q$1=v4G[A67][U3X + (y_M < A8Q?+"341" != 812.88?708.76 == y5H?(!0,P1Z):" ":(!1,!!({})):(+"1.66e+3",n7f)) + D3g.name];if(!q$1)continue;A1M=A1M === null?q$1:Math.min(A1M,q$1);d8m=d8m === null?q$1:Math.max(d8m,q$1);}return [A1M,d8m];}f2A=D3g.days;Y8d=Number(D3g.inputs[R_K]);P$4=Number(D3g.inputs["Long Cycle"]);if(v4G.length < Math.max(f2A,Y8d,P$4) + 1){D3g.error=!0;return;}G7V=D3g.inputs.Field;if(!G7V || G7V == "field"){G7V=N10;}B2v=0.5;M65.Studies.MA(D3g.inputs["Moving Average Type"],Y8d,G7V,0,"_MACD1",P_V,D3g);M65.Studies.MA(D3g.inputs["Moving Average Type"],P$4,G7V,+"0",n33,P_V,D3g);i6M=0;s8I=0;for(var W76=D3g.startFrom;W76 < v4G.length;W76++){M6m="_";M6m+="MA";M6m+="C";M6m+="D2 ";k2P="_MA";k2P+="C";k2P+="D";k2P+="1 ";I7_=v4G[W76];if(W76 < P$4 - 1)continue;A0B=I7_[k2P + D3g.name];p5a=I7_[M6m + D3g.name];if(A0B || A0B === "0" * 1 || p5a || p5a === 0){E0y.j7J(14);I7_["_MACD " + D3g.name]=E0y.c0C(A0B,p5a);}m8v=I7_["_MACD " + D3g.name];if(W76 < P$4 + (f2A - 1))continue;W5U=V9H(f2A,W76,"_MACD");i6M=W5U[1] > W5U[0]?+"100" * (m8v - W5U[0]) / (W5U[1] - W5U["0" ^ 0]):i6M;if(m8v || m8v === 0){I53="_";I53+="P";I53+="F ";I7_["_PF " + D3g.name]=v4G[W76 - 1][I53 + D3g.name]?v4G[W76 - 1]["_PF " + D3g.name] + B2v * (i6M - v4G[W76 - 1]["_PF " + D3g.name]):i6M;}u3z=I7_["_PF " + D3g.name];if(W76 < P$4 + 2 * (f2A - 1))continue;W5U=V9H(f2A,W76,"_PF");s8I=W5U[1] > W5U[+"0"]?("100" >> 0) * (u3z - W5U[0]) / (W5U[1] - W5U[0]):s8I;if(u3z || u3z === 0){H$L="Res";H$L+="ult ";t35="Res";t35+="u";t35+="lt ";B3u="Res";B3u+="u";B3u+="lt";B3u+=" ";I7_["Result " + D3g.name]=v4G[W76 - 1][B3u + D3g.name]?v4G[W76 - 1][t35 + D3g.name] + B2v * (s8I - v4G[W76 - +"1"][H$L + D3g.name]):s8I;}}};M65.Studies.studyLibrary=M65.extend(M65.Studies.studyLibrary,{Schaff:{name:"Schaff Trend Cycle",range:"0 to 100",calculateFN:M65.Studies.calculateSchaff,inputs:{Period:10,Field:u3i,"Short Cycle":23,"Long Cycle":50,"Moving Average Type":"ema"},parameters:{init:{studyOverZonesEnabled:!"",studyOverBoughtValue:+"75",studyOverBoughtColor:"auto",studyOverSoldValue:25,studyOverSoldColor:Y2L}}}});}};Z4=F1G=>{var o5b=f3BGj;o5b.T$X();var t4i,i$k,C9j,G2t;t4i="un";t4i+="defined";i$k=typeof _CIQ !== t4i?_CIQ:F1G.CIQ;if(!i$k.Studies){C9j="shinohara feature requires first activating stud";C9j+="ies feature.";console.error(C9j);}else {G2t="#E99B";G2t+="5";G2t+="4";i$k.Studies.calculateShinohara=function(c7R,M38){o5b.T$X();var v0d,R6f,a$X,b7F;v0d=M38.chart.scrubbed;if(v0d.length < M38.days + 1){M38.error=!!({});return;}R6f={weakNum:0,weakDen:0,strongNum:0,strongDen:0};if(M38.startFrom > 1){a$X="_accu";a$X+="ms ";R6f=i$k.clone(v0d[M38.startFrom - +"1"][a$X + M38.name]);}for(var B$_=M38.startFrom;B$_ < v0d.length;B$_++){R6f.weakNum+=v0d[B$_].High - v0d[B$_].Close;R6f.weakDen+=v0d[B$_].Close - v0d[B$_].Low;if(B$_ > "0" * 1){o5b.N_M(21);var x1A=o5b.a$j(193,12,16);R6f.strongNum+=v0d[B$_].High - v0d[B$_ - x1A].Close;o5b.j7J(137);var w8s=o5b.a$j(2,6,5,2);R6f.strongDen+=v0d[B$_ - w8s].Close - v0d[B$_].Low;}if(B$_ >= M38.days){b7F="Weak R";b7F+="ati";b7F+="o";b7F+=" ";R6f.weakNum-=v0d[B$_ - M38.days].High - v0d[B$_ - M38.days].Close;R6f.weakDen-=v0d[B$_ - M38.days].Close - v0d[B$_ - M38.days].Low;o5b.j7J(14);var w3k=o5b.a$j(117,17);v0d[B$_][b7F + M38.name]=w3k * R6f.weakNum / R6f.weakDen;if(B$_ > M38.days){o5b.N_M(23);var p31=o5b.c0C(0,4,3,8);R6f.strongNum-=v0d[B$_ - M38.days].High - v0d[B$_ - M38.days - p31].Close;o5b.N_M(13);var R9T=o5b.c0C(0,6,5,0);R6f.strongDen-=v0d[B$_ - M38.days - R9T].Close - v0d[B$_ - M38.days].Low;v0d[B$_]["Strong Ratio " + M38.name]=+"100" * R6f.strongNum / R6f.strongDen;}}v0d[B$_]["_accums " + M38.name]=i$k.clone(R6f);}};i$k.Studies.studyLibrary=i$k.extend(i$k.Studies.studyLibrary,{Shinohara:{name:"Shinohara Intensity Ratio",calculateFN:i$k.Studies.calculateShinohara,inputs:{Period:+"26"},outputs:{"Strong Ratio":G2t,"Weak Ratio":"#5F7CB8"}}});}};T0=C1j=>{var c2y,C3o,g$o,p8t,n6n;c2y=typeof _CIQ !== "undefined"?_CIQ:C1j.CIQ;if(!c2y.Studies){console.error("stochastics feature requires first activating studies feature.");}else {C3o="#";C3o+="F";C3o+="F000";C3o+="0";g$o="f";g$o+="ie";g$o+="l";g$o+="d";p8t="#F";p8t+="F";p8t+="00";p8t+="00";n6n="Stocha";n6n+="sti";n6n+="c Momentum Index";c2y.Studies.calculateStochastics=function(O9m,e$I){var r8a=f3BGj;var e3t,A3F,i6H,H$$,S1K,a1O,e6h,D08,t6E,G1I;e3t="_F";e3t+="a";e3t+="st%K ";A3F="fie";A3F+="ld";if(!e$I.smooth){e$I.smooth=e$I.inputs.Smooth;}r8a.f3X();i6H=e$I.inputs.Field;if(!i6H || i6H == A3F){i6H="Close";}H$$=e$I.inputs["%K Periods"];if(!H$$){H$$=e$I.days;}S1K=e$I.chart.scrubbed;function N3w(T_i,Z1l,O10){var s48,w9v,H_Z,F41,W5c,K3B,z_W;r8a.N_M(15);s48=r8a.a$j(T_i,1,O10);w9v=Number.MAX_VALUE * -("1" - 0);r8a.f3X();H_Z=Number.MAX_VALUE;for(var g4I=s48;g4I <= T_i;g4I++){F41="L";F41+="ow";W5c=S1K[g4I][Z1l == "Close"?F41:Z1l];K3B=S1K[g4I][Z1l == "Close"?"High":Z1l];if(!W5c && W5c !== 0)continue;if(!K3B && K3B !== 0)continue;H_Z=Math.min(H_Z,W5c);w9v=Math.max(w9v,K3B);}if(w9v == Number.MAX_VALUE * -1 || H_Z == Number.MAX_VALUE){return null;}z_W=w9v == H_Z?0:(S1K[T_i][Z1l] - H_Z) / (w9v - H_Z) * 100;return z_W;}if(S1K.length < Math.max(H$$,e$I.days) + 1){e$I.error=!!"1";return;}a1O=e$I.inputs["%K Smoothing Periods"];if(a1O && !e$I.inputs.Fast){e$I.smooth=!!1;}else if(e$I.smooth){a1O=3;}e6h=e$I.inputs["%D Periods"];if(!e6h){e6h=+"3";}if(e$I.outputs.Fast){D08="F";D08+="a";D08+="st";e$I.outputMap={};e$I.outputMap["%K " + e$I.name]=D08;e$I.outputMap["%D " + e$I.name]="Slow";}for(var k_a=Math.max(H$$,e$I.startFrom);k_a < S1K.length;k_a++){t6E="_F";t6E+="ast%K ";G1I=N3w(k_a,i6H,H$$);if(G1I !== null){S1K[k_a][t6E + e$I.name]=N3w(k_a,i6H,H$$);}}c2y.Studies.MA("simple",e$I.smooth?a1O:1,e3t + e$I.name,0,"%K",O9m,e$I);c2y.Studies.MA("simple",e6h,"%K " + e$I.name,0,"%D",O9m,e$I);};c2y.Studies.calculateStochMomentum=function(D$k,K7J){var U8y=f3BGj;var d8k,N2S,A6v,O5U,Z$1,N0I,Y99,o0q,X0o,O$8,l4f,e_w,Q1C,f2I,T8B,A2v,a2U;d8k="%";d8k+="K ";N2S="_";N2S+="D";N2S+="HL1";N2S+=" ";A6v="_D";A6v+="H";A6v+="L";A6v+=" ";O5U="exponent";O5U+="ial";Z$1="_H";Z$1+="S2";N0I="_H";N0I+="S";N0I+="1";Y99="exp";Y99+="onen";Y99+="tial";o0q="%K Smoo";o0q+="thi";o0q+="ng Periods";X0o="%";X0o+="K Perio";U8y.T$X();X0o+="ds";O$8=Number(K7J.inputs[X0o]);l4f=Number(K7J.inputs[o0q]);function v5_(Z5l,v83){var L4Y,P8L;L4Y=null;P8L=null;U8y.f3X();for(var q0p=v83 - Z5l + ("1" | 0);q0p <= v83;q0p++){L4Y=L4Y === null?f2I[q0p].Low:Math.min(L4Y,f2I[q0p].Low);P8L=P8L === null?f2I[q0p].High:Math.max(P8L,f2I[q0p].High);}return [L4Y,P8L];}e_w=Number(K7J.inputs["%K Double Smoothing Periods"]);Q1C=Number(K7J.inputs["%D Periods"]);f2I=K7J.chart.scrubbed;if(f2I.length < O$8 + l4f + e_w - 1 || f2I.length < Q1C){K7J.error=!0;return;}for(T8B=Math.max(O$8,K7J.startFrom) - 1;T8B < f2I.length;T8B++){A2v=f2I[T8B];a2U=v5_(O$8,T8B);U8y.j7J(14);var s5t=U8y.c0C(5,4);U8y.j7J(161);var k_O=U8y.c0C(0,414,10,16,16);A2v["_H " + K7J.name]=A2v.Close - (a2U[0] + a2U[s5t]) / k_O;U8y.j7J(14);var C8$=U8y.a$j(10,9);A2v["_DHL " + K7J.name]=a2U[C8$] - a2U[0];}c2y.Studies.MA(Y99,l4f,"_H " + K7J.name,0,N0I,D$k,K7J);c2y.Studies.MA("exponential",e_w,"_HS1 " + K7J.name,0,Z$1,D$k,K7J);c2y.Studies.MA(O5U,l4f,A6v + K7J.name,+"0","_DHL1",D$k,K7J);c2y.Studies.MA("exponential",e_w,N2S + K7J.name,0,"_DHL2",D$k,K7J);for(T8B=O$8 - 1;T8B < f2I.length;T8B++){U8y.j7J(61);var G5C=U8y.c0C(1100,1100,99);f2I[T8B]["%K " + K7J.name]=f2I[T8B]["_HS2 " + K7J.name] / (0.5 * f2I[T8B]["_DHL2 " + K7J.name]) * G5C;}c2y.Studies.MA(K7J.inputs["%D Moving Average Type"],Q1C,d8k + K7J.name,0,"%D",D$k,K7J);K7J.zoneOutput="%K";};c2y.Studies.studyLibrary=c2y.extend(c2y.Studies.studyLibrary,{"Stch Mtm":{name:n6n,calculateFN:c2y.Studies.calculateStochMomentum,inputs:{"%K Periods":10,"%K Smoothing Periods":3,"%K Double Smoothing Periods":3,"%D Periods":"10" >> 64,"%D Moving Average Type":"ema"},outputs:{"%K":"auto","%D":p8t},parameters:{init:{studyOverZonesEnabled:!!1,studyOverBoughtValue:40,studyOverBoughtColor:"auto",studyOverSoldValue:-("40" >> 0),studyOverSoldColor:"auto"}}},stochastics:{name:"Stochastics (Simple)",range:"0 to 100",calculateFN:c2y.Studies.calculateStochastics,inputs:{Period:14,Field:g$o,Smooth:!!1},outputs:{Fast:"auto",Slow:C3o},parameters:{init:{studyOverZonesEnabled:!!({}),studyOverBoughtValue:80,studyOverBoughtColor:"auto",studyOverSoldValue:20,studyOverSoldColor:"auto"}}},Stochastics:{name:"Stochastics",range:"0 to 100",calculateFN:c2y.Studies.calculateStochastics,inputs:{Field:"field","%K Periods":14,Fast:![],"%K Smoothing Periods":3,"%D Periods":3},outputs:{"%K":"auto","%D":"#FF0000"},parameters:{init:{studyOverZonesEnabled:!![],studyOverBoughtValue:+"80",studyOverBoughtColor:"auto",studyOverSoldValue:20,studyOverSoldColor:"auto"}},attributes:{"%K Smoothing Periods":{hidden:function(){f3BGj.T$X();return this.inputs.Fast;}}},centerline:+"50"}});}};x$=T1X=>{var O_B=f3BGj;O_B.T$X();var u9Y;u9Y=typeof _CIQ !== "undefined"?_CIQ:T1X.CIQ;if(!u9Y.Studies){console.error("supertrend feature requires first activating studies feature.");}else {u9Y.Studies.calculateSupertrend=function(F59,q_R){var x5N,T3l,J65,x9w,M8Y,a9R,a5A,k0V,e1U,z7h,u_b;x5N=q_R.chart.scrubbed;if(x5N.length < q_R.days + 1){q_R.error=!!1;return;}u9Y.Studies.calculateStudyATR(F59,q_R);for(var f5w=q_R.startFrom;f5w < x5N.length;f5w++){T3l="_Down";T3l+="tren";T3l+="d ";J65="A";J65+="T";J65+="R";J65+=" ";x9w=x5N[f5w];if(!x9w)continue;O_B.N_M(162);var D6t=O_B.a$j(3,6,3,13,10);M8Y=(x9w.High + x9w.Low) / D6t;a9R=q_R.inputs.Multiplier * x9w[J65 + q_R.name];O_B.j7J(14);a5A=O_B.c0C(M8Y,a9R);O_B.j7J(1);k0V=O_B.c0C(M8Y,a9R);if(f5w){e1U="_";e1U+="Downtr";e1U+="end ";if(x5N[f5w - 1] && x5N[f5w - 1].Close && x5N[f5w - ("1" << 64)].Close > x5N[f5w - 1]["_Uptrend " + q_R.name] && x5N[f5w - ("1" ^ 0)]["_Uptrend " + q_R.name] > a5A){O_B.j7J(14);a5A=x5N[O_B.c0C(f5w,1)]["_Uptrend " + q_R.name];}if(x5N[f5w - 1] && x5N[f5w - "1" * 1].Close && x5N[f5w - 1].Close < x5N[f5w - 1]["_Downtrend " + q_R.name] && x5N[f5w - 1]["_Downtrend " + q_R.name] < k0V){O_B.j7J(14);k0V=x5N[O_B.a$j(f5w,1)][e1U + q_R.name];}}O_B.N_M(31);x9w["_Direction " + q_R.name]=O_B.c0C("1",32);if(f5w){z7h="_Direction";z7h+=" ";u_b="_Direction";u_b+=" ";O_B.j7J(14);x9w[u_b + q_R.name]=x5N[O_B.c0C(f5w,1)]["_Direction " + q_R.name];if(x9w.Close > x5N[f5w - 1]["_Downtrend " + q_R.name]){x9w[z7h + q_R.name]=1;}else if(x9w.Close < x5N[f5w - 1]["_Uptrend " + q_R.name]){x9w["_Direction " + q_R.name]=-1;}}x9w["_Uptrend " + q_R.name]=a5A;x9w[T3l + q_R.name]=k0V;x9w["Trend " + q_R.name]=x9w["_Direction " + q_R.name] > 0?a5A:k0V;if(!f5w)continue;}q_R.outputMap={};q_R.outputMap["Trend " + q_R.name]="";};u9Y.Studies.displaySupertrend=function(r5$,A2N,X96){var a_H,I5_,e6q,Q0a,T84,Q1r,B$K,V5q,T7j,I8D,i7J,A$E;a_H="T";a_H+="r";a_H+="e";a_H+="nd ";I5_=r5$.panels[A2N.panel];e6q=A2N.getContext(r5$);Q0a=A2N.getYAxis(r5$);T84={skipTransform:I5_.name != A2N.chart.name,skipProjections:!!({}),label:r5$.preferences.labels,yAxis:Q0a,highlight:A2N.highlight};e6q.strokeStyle=J2z(r5$,X96[X96.length - 1]);e6q.lineWidth=2;if(A2N.highlight){e6q.lineWidth=1.5;}Q1r=a_H + A2N.name;for(var t4p=+"0";I5_.chart.transformFunc && Q0a != I5_.chart.yAxis && t4p < X96.length;t4p++){B$K=X96[t4p];if(B$K && B$K.transform){B$K.transform[Q1r]=I5_.chart.transformFunc(r5$,I5_.chart,B$K[Q1r]);}}r5$.plotDataSegmentAsLine(Q1r,I5_,T84,J2z);e6q.lineWidth=+"1";e6q.globalAlpha=1;r5$.startClip(A2N.panel);if(!A2N.highlight && r5$.highlightedDraggable){e6q.globalAlpha*=0.3;}function J2z(W3M,S6Z,H8H){var K1L,y_j,a_9,B_i;K1L="_";K1L+="D";K1L+="irec";O_B.f3X();K1L+="tion ";if(S6Z && S6Z[K1L + A2N.name] < +"0"){return A2N.outputs.Downtrend;}y_j=-1291900641;a_9=-806501474;B_i=2;for(var O_q=+"1";O_B.S9Y(O_q.toString(),O_q.toString().length,45473) !== y_j;O_q++){return A2N.outputs.Uptrend;}if(O_B.S9Y(B_i.toString(),B_i.toString().length,46148) !== a_9){return A2N.outputs.Uptrend;}}O_B.N_M(163);var U_p=O_B.a$j(18,116,4,3,416);O_B.j7J(1);var t5D=O_B.c0C(981,6863);O_B.j7J(3);O_B.f3X();var k2Y=O_B.c0C(15658,10,16626);O_B.N_M(122);var Z$d=O_B.a$j(16,18,1,3);O_B.N_M(3);var N9Z=O_B.c0C(7,9,0);V5q=e6q.measureText(U_p != t5D?"\u25B2":(k2Y,+"224.01") > "271.12" * Z$d?!({}):(574.82,!1)).width / N9Z;for(T7j="0" ^ 0;T7j < X96.length;T7j++){if(!X96[T7j] || !X96[T7j - 1])continue;if(X96[T7j - 1]["_Direction " + A2N.name] > X96[T7j]["_Direction " + A2N.name]){e6q.fillStyle=A2N.outputs.Downtrend;e6q.textBaseline="bottom";I8D=r5$.pixelFromPrice(X96[T7j].High,I5_,Q0a);for(var H7P=5;H7P <= 45;H7P+="10" * 1){if(Q0a.flipped){e6q.fillText("\u25B2",r5$.pixelFromBar(T7j) - V5q,I8D + H7P);}else {e6q.fillText((5411,5634) != 1404?"\u25BC":!"",r5$.pixelFromBar(T7j) - V5q,I8D - H7P);}}}else if(X96[T7j - 1]["_Direction " + A2N.name] < X96[T7j]["_Direction " + A2N.name]){i7J="t";i7J+="op";e6q.fillStyle=A2N.outputs.Uptrend;e6q.textBaseline=i7J;A$E=r5$.pixelFromPrice(X96[T7j].Low,I5_,Q0a);for(var K4k=5;K4k <= "45" - 0;K4k+=10){if(Q0a.flipped){e6q.fillText((108.83,851) != 2670?"\u25BC":+"8040" != 56.89?3828 !== (524.49,858.99)?8.30e+3:("t",1.03e+3):855.95,r5$.pixelFromBar(T7j) - V5q,A$E - K4k);}else {e6q.fillText(147 <= (3706,1760)?783.05 !== "5090" - 0?"\u25B2":"8973" << 32 == (6026,3312)?![]:"t":(868.37,408.07),r5$.pixelFromBar(T7j) - V5q,A$E + K4k);}}}}r5$.endClip();};u9Y.Studies.studyLibrary=u9Y.extend(u9Y.Studies.studyLibrary,{Supertrend:{name:"Supertrend",overlay:!"",seriesFN:u9Y.Studies.displaySupertrend,calculateFN:u9Y.Studies.calculateSupertrend,inputs:{Period:7,Multiplier:3},outputs:{Uptrend:"#8cc176",Downtrend:"#b82c0c"},attributes:{Multiplier:{min:"0.1" - 0,step:0.1}}}});}};k4=M_u=>{var U5u=f3BGj;var r7I,R0Y;r7I="unde";U5u.T$X();r7I+="fi";r7I+="n";r7I+="ed";R0Y=typeof _CIQ !== r7I?_CIQ:M_u.CIQ;if(!R0Y.Studies){console.error("swingIndex feature requires first activating studies feature.");}else {R0Y.Studies.calculateSwingIndex=function(O5o,W$z){var i8U,R33,o6L,c6H,e0E,N66,S_d,X0h,i7C,Q3y,L$6,K2v,M1X;i8U="Re";i8U+="sult ";R33=W$z.inputs["Limit Move Value"];if(R33 === null || isNaN(R33)){R33=99999;}o6L=W$z.chart.scrubbed;c6H=0;if(W$z.startFrom > 1){c6H=o6L[W$z.startFrom - +"1"][i8U + W$z.name];}for(var I7b=Math.max(1,W$z.startFrom);I7b < o6L.length;I7b++){e0E="Re";e0E+="sult ";N66=Math.abs(o6L[I7b].High - o6L[I7b - 1].Close);S_d=Math.abs(o6L[I7b].Low - o6L[I7b - 1].Close);X0h=Math.abs(o6L[I7b].High - o6L[I7b].Low);i7C=Math.abs(o6L[I7b - +"1"].Close - o6L[I7b - 1].Open);Q3y=Math.max(N66,S_d);L$6=Math.max(X0h,Q3y);U5u.N_M(25);K2v=U5u.c0C(0.25,i7C,L$6);if(L$6 == N66){U5u.N_M(5);K2v-=U5u.c0C(S_d,0.5);}else if(L$6 == S_d){U5u.N_M(5);K2v-=U5u.c0C(N66,0.5);}U5u.N_M(164);var U69=U5u.c0C(3,20,29950,100,5);U5u.j7J(14);var z8O=U5u.a$j(14,13);U5u.j7J(34);var Q55=U5u.c0C(2,17,17);U5u.j7J(9);var E9a=U5u.c0C(104,15,7);M1X=U69 * (o6L[I7b].Close - o6L[I7b - z8O].Close + 0.5 * (o6L[I7b].Close - o6L[I7b].Open) + 0.25 * (o6L[I7b - Q55].Close - o6L[I7b - E9a].Open)) / K2v * (Q3y / R33);if(K2v === 0 || R33 === ("0" | 0)){M1X=0;}if(W$z.type == "Swing"){c6H=0;}c6H+=M1X;o6L[I7b][e0E + W$z.name]=c6H;}};R0Y.Studies.studyLibrary=R0Y.extend(R0Y.Studies.studyLibrary,{"Acc Swing":{name:"Accumulative Swing Index",calculateFN:R0Y.Studies.calculateSwingIndex,inputs:{"Limit Move Value":+"0.5"}},Swing:{name:"Swing Index",calculateFN:R0Y.Studies.calculateSwingIndex,inputs:{"Limit Move Value":0.5}}});}};N1=t59=>{var B_4=f3BGj;var t$3,O4k,n3q,l2T;t$3=typeof _CIQ !== "undefined"?_CIQ:t59.CIQ;B_4.f3X();if(!t$3.Studies){console.error("trendIntensity feature requires first activating studies feature.");}else {O4k="au";O4k+="t";O4k+="o";n3q="fi";n3q+="e";n3q+="l";n3q+="d";l2T="0 t";l2T+="o";l2T+=" 100";t$3.Studies.calculateTrendIntensity=function(z2t,U1L){var K9C,X3q,A47,D_q,h9b,B3H,n9J,E8N,z6W,r4v,J8Y,K0q;K9C="T";K9C+="I";K9C+="I";B_4.T$X();K9C+=" ";X3q="Signal ";X3q+="Period";A47="e";A47+="m";A47+="a";D_q="m";D_q+="a";h9b=U1L.chart.scrubbed;if(h9b.length < U1L.days + 1){U1L.error=!![];return;}B3H=U1L.inputs.Field;function B0K(z0$,R_7){if(Math.abs(R_7) < 0.00000001){return 100;}B_4.f3X();B_4.j7J(165);return B_4.a$j(1,z0$,R_7,100,0,"100");}if(!B3H || B3H == "field"){B3H="Close";}t$3.Studies.MA(D_q,U1L.days,B3H,0,"_SMA",z2t,U1L);n9J=0;E8N=0;J8Y=[];K0q=Math.ceil(U1L.days / ("2" | 2));for(z6W=Math.max(0,U1L.startFrom - K0q);z6W < h9b.length;z6W++){if(!h9b[z6W]["_SMA " + U1L.name] && h9b[z6W]["_SMA " + U1L.name] !== 0)continue;r4v=h9b[z6W][B3H] - h9b[z6W]["_SMA " + U1L.name];if(r4v < "0" << 0){B_4.N_M(166);E8N+=B_4.a$j(r4v,1);}else {n9J+=r4v;}J8Y.push(r4v);if(J8Y.length > K0q){r4v=J8Y.shift();if(r4v < 0){B_4.j7J(166);E8N-=B_4.c0C(r4v,1);}else {n9J-=r4v;}}if(z6W < U1L.startFrom)continue;h9b[z6W]["TII " + U1L.name]=B0K(n9J,E8N);}t$3.Studies.MA(A47,U1L.inputs[X3q],K9C + U1L.name,0,"Signal",z2t,U1L);};t$3.Studies.studyLibrary=t$3.extend(t$3.Studies.studyLibrary,{"Trend Int":{name:"Trend Intensity Index",calculateFN:t$3.Studies.calculateTrendIntensity,range:l2T,inputs:{Period:"14" >> 0,Field:n3q,"Signal Period":9},outputs:{TII:"auto",Signal:"#FF0000"},parameters:{init:{studyOverZonesEnabled:!![],studyOverBoughtValue:80,studyOverBoughtColor:O4k,studyOverSoldValue:20,studyOverSoldColor:"auto"}}}});}};a7=G$9=>{var A4H;A4H=typeof _CIQ !== "undefined"?_CIQ:G$9.CIQ;if(!A4H.Studies){console.error("trix feature requires first activating studies feature.");}else {A4H.Studies.calculateTRIX=function(Z0U,s7l){var W5Y=f3BGj;var w2z,w7C,I3z,W16,b0I,k1m,F6r,p2V;w2z="_";w2z+="MA";w2z+="1 ";w7C=s7l.chart.scrubbed;if(w7C.length < s7l.days + "1" * 1){s7l.error=!!({});return;}I3z=s7l.name;W5Y.j7J(1);W16=["Close",W5Y.a$j(w2z,I3z),W5Y.a$j("_MA2 ",I3z),W5Y.c0C("_MA3 ",I3z)];for(var m3A=0;m3A < W16.length - 1;m3A++){A4H.Studies.MA("exponential",s7l.days,W16[m3A],0,"_MA" + (m3A + 1).toString(),Z0U,s7l);}b0I=W16[3];for(var j2k=Math.max(1,s7l.startFrom);j2k < w7C.length;j2k++){k1m="R";k1m+="e";k1m+="sult";k1m+=" ";W5Y.N_M(167);F6r=w7C[W5Y.a$j(j2k,1,"1")][b0I];if(!F6r)continue;p2V=w7C[j2k][b0I];if(p2V || p2V === 0){W5Y.j7J(1);w7C[j2k][W5Y.a$j(k1m,I3z)]=W5Y.c0C("100",p2V,F6r,1,W5Y.j7J(168));}}};A4H.Studies.studyLibrary=A4H.extend(A4H.Studies.studyLibrary,{TRIX:{name:"TRIX",calculateFN:A4H.Studies.calculateTRIX}});}};h3=L2j=>{var p_y,X2S,r0c;p_y="undefi";p_y+="ned";X2S=typeof _CIQ !== p_y?_CIQ:L2j.CIQ;if(!X2S.Studies){r0c="twiggsMoneyFlow feature requires first activating stu";r0c+="dies feature.";console.error(r0c);}else {X2S.Studies.calculateTwiggsMoneyFlow=function(a8r,h6h){var Z5T=f3BGj;var T4x,D0p,m5X,O96,Q7T,b44,Y2f,d92,r37,M0B,x6$;T4x=h6h.chart.scrubbed;if(T4x.length < h6h.days){h6h.error=!![];return;}D0p=0;m5X=0;Z5T.N_M(3);var J1x=Z5T.a$j(4,5,0);O96=T4x[h6h.startFrom - J1x];if(O96){Q7T="_s";Q7T+="u";Q7T+="mV ";b44="_";b44+="sumMF";b44+=" ";if(O96[b44 + h6h.name]){D0p=O96["_sumMF " + h6h.name];}if(O96[Q7T + h6h.name]){m5X=O96["_sumV " + h6h.name];}}for(var x8O=Math.max(1,h6h.startFrom);x8O < T4x.length;x8O++){Y2f="_su";Y2f+="mV";Y2f+=" ";d92="_su";d92+="mMF";d92+=" ";r37="_";r37+="M";r37+="FV ";M0B=Math.max(T4x[x8O - 1].Close,T4x[x8O].High);x6$=Math.min(T4x[x8O - +"1"].Close,T4x[x8O].Low);Z5T.j7J(13);var S84=Z5T.c0C(15,13,5,9);Z5T.N_M(55);var p2y=Z5T.a$j(4,13999986,54999945,1);T4x[x8O]["_MFV " + h6h.name]=T4x[x8O].Volume * (S84 * T4x[x8O].Close - M0B - x6$) / (M0B - x6$ === 0?p2y:M0B - x6$);if(x8O > h6h.days - ("1" << 64)){D0p*=(h6h.days - +"1") / h6h.days;Z5T.j7J(34);var Q1a=Z5T.c0C(8,1,7);m5X*=(h6h.days - Q1a) / h6h.days;}D0p+=T4x[x8O][r37 + h6h.name];m5X+=T4x[x8O].Volume;if(x8O > h6h.days - +"1"){if(m5X){Z5T.N_M(7);T4x[x8O]["Result " + h6h.name]=Z5T.c0C(D0p,m5X > 0?m5X:+"999999");}}T4x[x8O][d92 + h6h.name]=D0p;T4x[x8O][Y2f + h6h.name]=m5X;}};X2S.Studies.studyLibrary=X2S.extend(X2S.Studies.studyLibrary,{Twiggs:{name:"Twiggs Money Flow",calculateFN:X2S.Studies.calculateTwiggsMoneyFlow,inputs:{Period:"21" >> 32}}});}};C6=h$X=>{var C_X,a0w,J7F,A8W;C_X="undefi";C_X+="ned";a0w=typeof _CIQ !== C_X?_CIQ:h$X.CIQ;if(!a0w.Studies){J7F="typicalPrice feature requires first activating ";J7F+="studies featu";J7F+="re.";console.error(J7F);}else if(!a0w.Studies.calculateTypicalPrice){console.error("typicalPrice feature requires first activating medianPrice feature.");}else {A8W="Weight";A8W+="ed Close";a0w.Studies.studyLibrary=a0w.extend(a0w.Studies.studyLibrary,{"Typical Price":{name:"Typical Price",calculateFN:a0w.Studies.calculateTypicalPrice,inputs:{Period:14}},"Weighted Close":{name:A8W,calculateFN:a0w.Studies.calculateTypicalPrice,inputs:{Period:+"14"}}});}};M$=x1K=>{var r8c,X4N,L0e,o7Q;r8c=+"1978925238";X4N=-1962589708;L0e=2;for(var x_4=1;f3BGj.S9Y(x_4.toString(),x_4.toString().length,+"39212") !== r8c;x_4++){o7Q=~_CIQ === ""?_CIQ:x1K.CIQ;L0e+=2;}f3BGj.f3X();if(f3BGj.S9Y(L0e.toString(),L0e.toString().length,50882) !== X4N){o7Q=~_CIQ === ""?_CIQ:x1K.CIQ;}o7Q=typeof _CIQ !== "undefined"?_CIQ:x1K.CIQ;if(!o7Q.Studies){console.error("ulcerIndex feature requires first activating studies feature.");}else {o7Q.Studies.calculateUlcerIndex=function(W52,h6g){var G8z,l3Y,Y5E,S3s,h7q,M7u,f1w;G8z="_";G8z+="M";G8z+="A";l3Y="s";function H7Z(f93,l6A,r9_){var w4D;w4D=null;for(var x7F=l6A - f93 + 1;x7F <= l6A;x7F++){if(x7F < 0)continue;w4D=w4D === null?Y5E[x7F][r9_]:Math.max(w4D,Y5E[x7F][r9_]);}return w4D;}l3Y+="i";l3Y+="m";l3Y+="ple";Y5E=h6g.chart.scrubbed;if(Y5E.length < ("2" | 0) * h6g.days - 1){h6g.error=!0;return;}S3s=h6g.inputs.Field;if(!S3s || S3s == "field"){S3s="Close";}for(h7q=Math.max(h6g.startFrom,h6g.days - 1);h7q < Y5E.length;h7q++){M7u="_P";M7u+="D";M7u+="2 ";Y5E[h7q][M7u + h6g.name]=Math.pow(100 * (Y5E[h7q][S3s] / H7Z(h6g.days,h7q,S3s) - 1),2);}o7Q.Studies.MA(l3Y,h6g.days,"_PD2 " + h6g.name,0,G8z,W52,h6g);for(h7q=Math.max(h6g.startFrom,2 * (h6g.days - 1));h7q < Y5E.length;h7q++){f1w=Y5E[h7q]["_MA " + h6g.name];if(f1w || f1w === 0){Y5E[h7q]["Result " + h6g.name]=Math.sqrt(f1w);}}};o7Q.Studies.studyLibrary=o7Q.extend(o7Q.Studies.studyLibrary,{Ulcer:{name:"Ulcer Index",calculateFN:o7Q.Studies.calculateUlcerIndex,inputs:{Period:14,Field:"field"}}});}};q7=p17=>{var u0Q=f3BGj;var s9e,e6o,z60;s9e=typeof _CIQ !== "undefined"?_CIQ:p17.CIQ;u0Q.T$X();if(!s9e.Studies){e6o="ultimateOscillator feature require";e6o+="s first activating studies feat";e6o+="ure.";console.error(e6o);}else {z60="U";z60+="ltim";z60+="ate Oscillator";s9e.Studies.calculateUltimateOscillator=function(Q7F,k9h){var f91,k1x,E3P,c8N,H8a,q4I,T5U,o3D,E5H,A6p,y5K,T$e,c20,j$3,D_T,j4e,I27,E47,l7P;f91=k9h.chart.scrubbed;k1x=[k9h.inputs["Cycle 1"],k9h.inputs["Cycle 2"],k9h.inputs["Cycle 3"]];E3P=Math.max(k1x[0],k1x[1],k1x[2]);if(f91.length < E3P + 1){k9h.error=!0;return;}u0Q.f3X();c8N=k1x[0] * k1x[1];H8a=k1x[0] * k1x[+"2"];u0Q.j7J(13);var J6j=u0Q.c0C(3,11,7,0);u0Q.N_M(169);var P5k=u0Q.a$j(1,11,3,16);q4I=k1x[J6j] * k1x[P5k];T5U=[+"0",0,0];o3D=[0,0,0];if(k9h.startFrom){E5H="_acc";E5H+="tr ";if(f91[k9h.startFrom - "1" * 1]["_accbp " + k9h.name]){T5U=f91[k9h.startFrom - ("1" << 64)]["_accbp " + k9h.name].slice();}if(f91[k9h.startFrom - 1]["_acctr " + k9h.name]){o3D=f91[k9h.startFrom - ("1" - 0)][E5H + k9h.name].slice();}}for(var f3u=Math.max(+"1",k9h.startFrom);f3u < f91.length;f3u++){A6p="Re";A6p+="s";A6p+="ult ";y5K="_a";y5K+="cct";y5K+="r ";T$e=Math.min(f91[f3u].Low,f91[f3u - "1" * 1].Close);c20=f91[f3u].Close - T$e;u0Q.j7J(170);var a2j=u0Q.c0C(6,2,7,0);j$3=Math.max(f91[f3u].High,f91[f3u - a2j].Close) - T$e;for(var r65=0;r65 < k1x.length;r65++){T5U[r65]+=c20;o3D[r65]+=j$3;if(f3u > k1x[r65]){D_T=Math.min(f91[f3u - k1x[r65]].Low,f91[f3u - k1x[r65] - 1].Close);j4e=f91[f3u - k1x[r65]].Close - D_T;u0Q.j7J(171);var N9x=u0Q.c0C(29,2,15,2,0);I27=Math.max(f91[f3u - k1x[r65]].High,f91[f3u - k1x[r65] - N9x].Close) - D_T;T5U[r65]-=j4e;o3D[r65]-=I27;}}f91[f3u]["_accbp " + k9h.name]=T5U.slice();f91[f3u][y5K + k9h.name]=o3D.slice();if(f3u < E3P)continue;u0Q.j7J(57);var l3U=u0Q.c0C(952,10,12,7,8);u0Q.j7J(27);var k60=u0Q.a$j(7,6);u0Q.N_M(172);var I_W=u0Q.a$j(7,5,1,5);u0Q.N_M(173);var U8Y=u0Q.a$j(15,1,19,5,10);E47=q4I * T5U[0] / o3D[0] + H8a * T5U[l3U] / o3D[k60] + c8N * T5U[I_W] / o3D[U8Y];u0Q.N_M(82);l7P=u0Q.a$j(c8N,H8a,q4I);u0Q.N_M(111);f91[f3u][A6p + k9h.name]=u0Q.a$j(E47,l7P,100);}};s9e.Studies.studyLibrary=s9e.extend(s9e.Studies.studyLibrary,{Ultimate:{name:z60,calculateFN:s9e.Studies.calculateUltimateOscillator,inputs:{"Cycle 1":7,"Cycle 2":14,"Cycle 3":28},parameters:{init:{studyOverZonesEnabled:!![],studyOverBoughtValue:70,studyOverBoughtColor:"auto",studyOverSoldValue:30,studyOverSoldColor:"auto"}}}});}};a9=I5u=>{var H1N=f3BGj;H1N.f3X();var y6Z,R3A,g26,H5b,G$v,g90,M1A;y6Z=typeof _CIQ !== "undefined"?_CIQ:I5u.CIQ;if(!y6Z.Studies){R3A="valuationLines feature requires first a";R3A+="ctivating studies feature.";console.error(R3A);}else {g26="#fff";g26+="69e";H5b="#";H5b+="e1";H5b+="e1e";H5b+="1";G$v="har";G$v+="mo";G$v+="nic";g90="media";g90+="n";M1A="m";M1A+="e";M1A+="a";M1A+="n";y6Z.Studies.calculateValuationLines=function(C5Y,F18,E4N){var g8T,M$z,k9F,a4V,V$q,z$g,w9n,m2d,c2E,H2m,l4n,F8G,L3W,V97,j6B,b$b,k3q;g8T="Di";g8T+="splay 3 Standard Deviat";g8T+="ion (3\u03C3)";M$z="Display 2 Standard Devi";M$z+="atio";M$z+="n (2\u03C3)";k9F="Aver";k9F+="ag";k9F+="e Type";a4V="Clos";a4V+="e";V$q=F18.inputs.Field == "field"?a4V:F18.inputs.Field;z$g=F18.inputs[k9F];w9n=F18.inputs["Display Average"];m2d=F18.inputs["Display 1 Standard Deviation (1\u03C3)"];c2E=F18.inputs[M$z];H2m=F18.inputs[g8T];l4n=[];for(var F4_=0;F4_ < E4N.length;++F4_){if(E4N[F4_] && !isNaN(E4N[F4_][V$q])){l4n.push(E4N[F4_][V$q]);}}F8G=(function(o83,h3I){var T_B,P3b,X9L,Y9$,Y6B,g3n,p2g,B0B,b6m;T_B="me";T_B+="d";T_B+="i";T_B+="an";P3b="h";P3b+="armoni";P3b+="c";X9L="m";X9L+="ean";Y9$=o83.length;Y6B=0;g3n=0;p2g=+"0";switch(h3I){case X9L:g3n=Y9$;for(;p2g < Y9$;++p2g){Y6B+=o83[p2g];}break;case P3b:Y6B=Y9$;for(;p2g < Y9$;++p2g){H1N.j7J(68);var B5n=H1N.c0C(2,4,13,17);g3n+=B5n / o83[p2g];}break;case T_B:H1N.N_M(7);B0B=Math.floor(H1N.a$j(Y9$,2));b6m=o83.slice().sort(function(i95,T1V){if(i95 > T1V){return +"1";}if(i95 < T1V){return -1;}return 0;});if(Y9$ % 2 === 0){H1N.N_M(174);var X5p=H1N.a$j(14,15,19,11,30);Y6B=b6m[B0B] + b6m[B0B - X5p];g3n=2;}else {Y6B=b6m[B0B];g3n=1;}break;}H1N.j7J(7);return H1N.a$j(Y6B,g3n);})(l4n,z$g);L3W=!(m2d || c2E || H2m) || (function(W1m,f1t){var S4r,n_n;S4r=W1m.length;n_n=0;H1N.T$X();for(var i4e=0;i4e < S4r;++i4e){n_n+=Math.pow(W1m[i4e] - f1t,2);}H1N.j7J(7);return Math.sqrt(H1N.a$j(n_n,S4r));})(l4n,F8G);F18.data={Average:w9n?[F8G]:null,"1 Standard Deviation (1\u03C3)":m2d?[F8G + L3W,F8G - L3W]:null,"2 Standard Deviation (2\u03C3)":c2E?[F8G + L3W * 2,F8G - L3W * 2]:null,"3 Standard Deviation (3\u03C3)":H2m?[F8G + L3W * ("3" | 3),F8G - L3W * 3]:null};V97=L3W;if(!F18.parameters){F18.parameters={};}if(H2m){H1N.N_M(175);F18.parameters.range=[H1N.a$j(3,V97,L3W,F8G),H1N.a$j(V97,L3W,F8G,3,H1N.j7J(176))];}else if(c2E){H1N.N_M(177);F18.parameters.range=[H1N.c0C(0,L3W,V97,F8G,"2"),H1N.a$j(V97,L3W,F8G,2,H1N.N_M(176))];}else if(m2d){H1N.j7J(63);F18.parameters.range=[H1N.a$j(L3W,V97,F8G),H1N.a$j(V97,L3W,F8G,H1N.N_M(82))];}else if(w9n){H1N.j7J(14);F18.parameters.range=[H1N.a$j(F8G,V97),H1N.a$j(F8G,V97,H1N.j7J(1))];}if(F18.panel){j6B=C5Y.panels[F18.panel];b$b=C5Y.getYAxisByName(j6B,F18.name);if(b$b){b$b.decimalPlaces=j6B.chart.yAxis.printDecimalPlaces;k3q={yAxis:b$b};C5Y.calculateYAxisRange(j6B,b$b,F18.parameters.range[0],F18.parameters.range[1]);C5Y.createYAxis(j6B,k3q);C5Y.drawYAxis(j6B,k3q);}}};y6Z.Studies.displayValuationLines=function(Z8J,K9N){var t4Q,C_Y,C5t,I7J,D3Q,Y9s,K1B,I9Z,n6F,N$m,m4N,i0N,q6h,q5Z,v87,x4I,B6h,I38,L_T,r2N,s3S,f0A,S5i,m7t,E2b,E$2,i1$,e1Y,R7Q,y2z,O8i,z4j;t4Q="stx_yax";t4Q+="i";t4Q+="s";C_Y="H";C_Y+="A";C_Y+="V";C_Y+="G";C5t="AV";C5t+="G";I7J=Z8J.panels[K9N.panel];D3Q=K9N.getYAxis(Z8J);Y9s=K9N.getContext(Z8J);K1B=K9N.data;I9Z=K9N.parameters.labels;n6F=K9N.inputs["Average Type"];N$m={mean:C5t,median:"MED",harmonic:C_Y};m4N=Z8J.canvasStyle("ciq-valuation-average-line");i0N=Z8J.canvasStyle("ciq-valuation-deviation-line");q6h=3;H1N.N_M(178);var j4U=H1N.a$j(13,0,1,5,2);q5Z=Z8J.getCanvasFontSize(t4Q) + q6h * j4U;for(var x55 in K1B){m7t="Av";m7t+="era";m7t+="ge";if(!K1B[x55])continue;H1N.N_M(179);v87=H1N.a$j(m7t,x55);x4I=y6Z.Studies.determineColor(K9N.outputs[x55]);B6h=K1B[x55];for(I38="0" >> 0;I38 < B6h.length;++I38){E2b="lef";E2b+="t";E$2=":";E$2+=" ";i1$="yaxi";i1$+="s";e1Y="li";e1Y+="ne";R7Q="da";R7Q+="sh";R7Q+="ed";y2z="s";y2z+="o";y2z+="lid";O8i="non";O8i+="e";L_T=B6h[I38];r2N=Z8J.pixelFromPrice(L_T,I7J,D3Q);if(r2N <= I7J.top || r2N >= I7J.yAxis.bottom)continue;S5i=v87?{pattern:m4N.borderStyle != O8i?m4N.borderStyle || y2z:"solid",lineWidth:parseFloat(m4N.borderWidth) || 1,opacity:parseFloat(m4N.opacity) || 1,yAxis:D3Q}:{pattern:i0N.borderStyle != "none"?i0N.borderStyle || "dashed":R7Q,lineWidth:parseFloat(i0N.borderWidth) || 1,opacity:parseFloat(i0N.opacity) || "1" ^ 0,yAxis:D3Q};Z8J.plotLine(I7J.left,I7J.right,r2N,r2N,x4I,e1Y,Y9s,I7J,S5i);if(I9Z === i1$){Z8J.createYAxisLabel(I7J,Z8J.formatYAxisPrice(L_T,I7J),r2N,x4I,null,Y9s,D3Q);continue;}r2N+=Math.floor(S5i.lineWidth / 2);if(r2N + q5Z >= I7J.yAxis.bottom)continue;s3S=(v87?N$m[n6F] + E$2:x55[0] + "\u03C3: ") + Z8J.formatYAxisPrice(L_T,I7J);f0A=Y9s.measureText(s3S).width;z4j=I7J.right - f0A - q6h;if(D3Q && D3Q.position == E2b){z4j=I7J.left + q6h;}H1N.N_M(180);Y9s.strokeText(s3S,z4j,H1N.a$j("2",q5Z,0,r2N,0.5));}}};y6Z.Studies.studyLibrary=y6Z.extend(y6Z.Studies.studyLibrary,{"val lines":{name:"Valuation Lines",calculateFN:function(){},seriesFN:function(F8X,R2v,v73){H1N.T$X();y6Z.Studies.calculateValuationLines(F8X,R2v,v73);y6Z.Studies.displayValuationLines(F8X,R2v);},overlay:!![],yAxisFN:function(){},inputs:{Field:"field","Average Type":[M1A,g90,G$v],"Display Average":!!1,"Display 1 Standard Deviation (1\u03C3)":!!0,"Display 2 Standard Deviation (2\u03C3)":![],"Display 3 Standard Deviation (3\u03C3)":!({})},outputs:{Average:"#00afed","1 Standard Deviation (1\u03C3)":H5b,"2 Standard Deviation (2\u03C3)":"#85c99e","3 Standard Deviation (3\u03C3)":g26}}});}};U9=P2z=>{var V$z,G9K,u0n,u$k;V$z=typeof _CIQ !== "undefined"?_CIQ:P2z.CIQ;if(!V$z.Studies){console.error("volatilityIndex feature requires first activating studies feature.");}else {G9K="a";G9K+="u";G9K+="t";G9K+="o";u0n="0 ";u0n+="to 10";u0n+="0";u$k="Relative Vol";u$k+="atility";V$z.Studies.calculateRelativeVolatility=function(N0N,k2x){var U9s=f3BGj;var B$C,b8$,G8d,i3n,d80,Z89,x46,Y9e;B$C="m";B$C+="a";k2x.days=Number(k2x.inputs["Smoothing Period"]);b8$=Number(k2x.inputs["STD Period"]);G8d=k2x.chart.scrubbed;if(G8d.length < k2x.days + b8$){k2x.error=!!1;return;}i3n=k2x.inputs.Field;if(!i3n || i3n == "field"){i3n="Close";}k2x.std=new V$z.Studies.StudyDescriptor(k2x.name,"sdev",k2x.panel);k2x.std.chart=k2x.chart;k2x.std.days=b8$;k2x.std.startFrom=k2x.startFrom;k2x.std.inputs={Field:i3n,"Standard Deviations":1,Type:B$C};k2x.std.outputs={_STD:null};function y2y(v1a,P6R){if(v1a + P6R === +"0"){return 100;}U9s.N_M(181);return U9s.c0C(100,P6R,v1a,v1a);}V$z.Studies.calculateStandardDeviation(N0N,k2x.std);d80=0;Z89=0;if(k2x.startFrom > +"1"){d80=G8d[k2x.startFrom - +"1"]["_avgG " + k2x.name] || 0;Z89=G8d[k2x.startFrom - 1]["_avgL " + k2x.name] || "0" | 0;}for(var n7Z=Math.max(k2x.startFrom,k2x.days);n7Z < G8d.length;n7Z++){x46=G8d[n7Z];U9s.j7J(94);Y9e=G8d[U9s.c0C(n7Z,"1")];if(!x46[i3n] && x46[i3n] !== 0)continue;if(!Y9e[i3n] && Y9e[i3n] !== +"0")continue;if(!x46["_STD " + k2x.name] && x46["_STD " + k2x.name] !== 0)continue;if(x46[i3n] > Y9e[i3n]){U9s.N_M(14);var k0C=U9s.a$j(8,7);d80=(d80 * (k2x.days - k0C) + x46["_STD " + k2x.name]) / k2x.days;U9s.j7J(14);var y5W=U9s.a$j(17,16);Z89=Z89 * (k2x.days - y5W) / k2x.days;}else {U9s.N_M(63);var X5y=U9s.c0C(11,8,20);Z89=(Z89 * (k2x.days - X5y) + x46["_STD " + k2x.name]) / k2x.days;U9s.N_M(182);var w4A=U9s.c0C(6,0,6,1,1);d80=d80 * (k2x.days - w4A) / k2x.days;}x46["Rel Vol " + k2x.name]=y2y(d80,Z89);x46["_avgG " + k2x.name]=d80;x46["_avgL " + k2x.name]=Z89;}k2x.zoneOutput="Rel Vol";};V$z.Studies.calculateHistoricalVolatility=function(i5G,W26){var k4I=f3BGj;var J58,x4M,M_W,V$i,f1K,K6t,I1h,T16,n4l;J58=W26.chart.scrubbed;function C0f(v3H){if(isNaN(v3H)){v3H=365;}if(i5G.layout.interval == "day"){return v3H;}else if(i5G.layout.interval == "week"){return 52;}else if(i5G.layout.interval == "month"){return 12;}k4I.T$X();return v3H;}if(J58.length < W26.days + 1){W26.error=!"";return;}x4M=W26.inputs.Field;if(!x4M || x4M == "field"){x4M="Close";}M_W=W26.inputs["Standard Deviations"];if(M_W < 0){M_W=1;}k4I.j7J(101);var w_J=k4I.c0C(1316,5,7,108,13);V$i=w_J * Math.sqrt(C0f(W26.inputs["Days Per Year"])) * M_W;f1K=[];K6t=0;if(W26.startFrom > "1" >> 0){K6t=J58[W26.startFrom - +"1"]["_state " + W26.name][0];f1K=J58[W26.startFrom - 1]["_state " + W26.name][1].slice();}for(var Y5W=Math.max(1,W26.startFrom);Y5W < J58.length;Y5W++){k4I.j7J(94);I1h=J58[k4I.c0C(Y5W,"1")][x4M];if(I1h){T16=Math.log(J58[Y5W][x4M] / I1h);f1K.push(T16);K6t+=T16;if(Y5W >= W26.days){n4l=+"0";K6t/=W26.days;for(var n4D=0;n4D < f1K.length;n4D++){n4l+=Math.pow(f1K[n4D] - K6t,2);}K6t*=W26.days;K6t-=f1K.shift();J58[Y5W]["Result " + W26.name]=Math.sqrt(n4l / W26.days) * V$i;}}J58[Y5W]["_state " + W26.name]=[K6t,f1K.slice()];}};V$z.Studies.studyLibrary=V$z.extend(V$z.Studies.studyLibrary,{"Hist Vol":{name:"Historical Volatility",calculateFN:V$z.Studies.calculateHistoricalVolatility,inputs:{Period:10,Field:"field","Days Per Year":[252,365],"Standard Deviations":1},attributes:{"Standard Deviations":{min:+"0.1",step:0.1}}},"Rel Vol":{name:u$k,range:u0n,calculateFN:V$z.Studies.calculateRelativeVolatility,inputs:{Field:"field","STD Period":10,"Smoothing Period":14},outputs:{"Rel Vol":G9K},centerline:50,parameters:{init:{studyOverZonesEnabled:!0,studyOverBoughtValue:70,studyOverBoughtColor:"auto",studyOverSoldValue:"30" - 0,studyOverSoldColor:"auto"}}}});}};d5=h5i=>{var T3w=f3BGj;var I3h,a7N;I3h=typeof _CIQ !== "undefined"?_CIQ:h5i.CIQ;T3w.T$X();if(!I3h.Studies){console.error("volumeProfile feature requires first activating studies feature.");}else {a7N="Volu";a7N+="m";a7N+="e Prof";a7N+="ile";I3h.Studies.displayVolumeProfile=function(P__,Z4c,a6g){var x3N,o7o,u81,F2b,h_8,A8D,b_O,l2r,j46,D$i,e9o,I2K,U7F,D4O,V$5,G74,i$e,i9Y,W5g,j5u,n6B,F$F,f2H,l_f,F1d;if(!P__ || !P__.chart.dataSet){return;}function k2F(D0y,F2M){var R$e,P9Z,c$Y,T$J,n0V,m1m,D9q,x3M,f69;if(!F2M){i9Y-=2;}F$F.canvasColor(D0y);U7F.beginPath();T3w.N_M(46);R$e=b_O[0][T3w.c0C("0",0)];P9Z=i9Y;for(var l3W="1" - 0;l3W < b_O.length;l3W++){if(b_O[l3W][1]){T3w.N_M(0);var h$u=T3w.a$j(320,3,18,18);c$Y=Math.round(i9Y - b_O[l3W][h$u] * W5g / l2r) - 0.5;T$J=Math.round(F$F.pixelFromTransformedValue(R$e,G74)) + ("0.5" - 0);n0V=Math.round(F$F.pixelFromTransformedValue(b_O[l3W][+"0"],G74)) + 0.5;if(!F2M){T$J-=0.5;n0V+=0.5;c$Y+=0.5;}if(T$J > i$e){T$J=i$e;}if(n0V < i$e){U7F.moveTo(i9Y,T$J);U7F.lineTo(i9Y,n0V);U7F.lineTo(c$Y,n0V);U7F.lineTo(c$Y,T$J);if(F2M){if(P9Z > c$Y || l3W == 1){U7F.lineTo(P9Z,T$J);};}else {U7F.lineTo(i9Y,T$J);if(h_8){m1m=I3h.condenseInt(b_O[l3W][1]);T3w.N_M(14);D9q=T3w.c0C(T$J,n0V);if(V$5 <= D9q - 2){try{x3M=U7F.measureText(m1m).width;}catch(I51){x3M=+"0";}U7F.textBaseline="top";f69=U7F.fillStyle;U7F.fillStyle=j5u;T3w.j7J(63);U7F.fillText(m1m,T3w.a$j(x3M,3,c$Y),T3w.a$j(D9q,V$5,2,2,n0V,T3w.j7J(183)));U7F.fillStyle=f69;}}}}P9Z=c$Y;}else {P9Z=i9Y;;}T3w.j7J(46);R$e=b_O[l3W][T3w.c0C("0",0)];}if(!Z4c.highlight && P__.highlightedDraggable){U7F.globalAlpha*=0.3;}if(!F2M){U7F.fill();}U7F.strokeStyle=j5u;if(F2M){U7F.stroke();}U7F.closePath();}x3N=P__.chart;o7o=Z4c.parameters.numberOfBars;u81=Z4c.parameters.widthPercentage;F2b=Z4c.parameters.displayBorder;h_8=Z4c.parameters.displayVolume;if(!o7o || o7o < +"0"){o7o=30;}o7o=Math.ceil(o7o);if(!u81 || u81 < 0){u81=0.25;}if(F2b !== !!""){F2b=!!1;}if(h_8 !== !0){h_8=!1;}A8D=(x3N.highValue - x3N.lowValue) / o7o;if(A8D === 0){return;}b_O=[];for(var b57=x3N.lowValue;b57 < x3N.highValue + 0.1;b57+=A8D){b_O.push([b57,+"0"]);}if(b_O.length < 2){P__.displayErrorAsWatermark("chart",P__.translateIf("Not enough data to render the Volume Profile"));return;}l2r=0;for(var s_t=0;s_t < a6g.length;s_t++){j46=a6g[s_t];if(!j46)continue;D$i=j46.Volume;if(Z4c.panel == x3N.name && j46.transform){j46=j46.transform;}e9o=b_O[0][0];I2K=0;for(var L2r=1;L2r < b_O.length;L2r++){I2K=b_O[L2r][0];if(j46.Low >= e9o && j46.Low <= I2K || j46.Low < e9o && j46.High > I2K || j46.High >= e9o && j46.High <= I2K){b_O[L2r][+"1"]+=D$i;if(b_O[L2r][1] > l2r){l2r=b_O[L2r][1];}}e9o=I2K;}}if(l2r === 0){P__.displayErrorAsWatermark("chart",P__.translateIf("Not enough data to render the Volume Profile"));return;}P__.setStyle("stx_volume_profile","color",I3h.Studies.determineColor(Z4c.outputs["Bars Color"]));U7F=Z4c.getContext(P__);D4O="stx-float-date";P__.canvasFont(D4O,U7F);V$5=P__.getCanvasFontSize(D4O);G74=x3N.panel;i$e=G74.yAxis.bottom;i9Y=Math.round(x3N.right) - 0.5;W5g=x3N.width * u81;j5u=P__.canvasStyle("stx_volume_profile").borderTopColor;n6B=!I3h.isTransparent(P__.canvasStyle("stx_volume_profile").borderTopColor) && F2b;F$F=P__;k2F("stx_volume_profile",!"1");if(n6B){k2F("stx_volume_profile",!![]);}T3w.j7J(4);f2H=-T3w.c0C("1922240287",1);l_f=-1247173282;F1d=2;for(var H5l=1;T3w.O1W(H5l.toString(),H5l.toString().length,96806) !== f2H;H5l++){U7F.globalAlpha=5;F1d+=2;}if(T3w.S9Y(F1d.toString(),F1d.toString().length,90616) !== l_f){U7F.globalAlpha=5;}U7F.globalAlpha=1;};I3h.Studies.studyLibrary=I3h.extend(I3h.Studies.studyLibrary,{"vol profile":{name:a7N,underlay:!"",seriesFN:I3h.Studies.displayVolumeProfile,calculateFN:null,inputs:{},outputs:{"Bars Color":"#b64a96"},customRemoval:!!1,parameters:{init:{displayBorder:!!({}),displayVolume:!({}),numberOfBars:30,widthPercentage:0.25}},attributes:{yaxisDisplayValue:{hidden:!!1},panelName:{hidden:!![]},flippedEnabled:{hidden:!![]}}}});}};o7=i8J=>{var f6b=f3BGj;var b3K,H9O,x4C,j7f,l4H,h$S,s2r,d0U,h72,S81,d1L,Y$z,q1B,w7M;b3K=-+"326070533";H9O=1405609193;x4C=2;for(var T9V=1;f6b.O1W(T9V.toString(),T9V.toString().length,12746) !== b3K;T9V++){j7f=typeof _CIQ !== "undefined"?_CIQ:i8J.CIQ;x4C+=2;}if(f6b.S9Y(x4C.toString(),x4C.toString().length,50755) !== H9O){j7f=-_CIQ == ""?_CIQ:i8J.CIQ;}if(!j7f.Studies){console.error("volumeStudies feature requires first activating studies feature.");}else {l4H="#b82";l4H+="c0c";h$S="Vo";h$S+="lu";h$S+="me Under";h$S+="lay";s2r="Trade Volume I";s2r+="ndex";d0U="Price Volume ";d0U+="Trend";h72="#F";h72+="F0";h72+="000";S81="a";S81+="u";S81+="t";S81+="o";d1L="#FF";d1L+="00";d1L+="00";Y$z="m";Y$z+="a";q1B="f";q1B+="iel";q1B+="d";w7M="Negative Vol";w7M+="ume ";w7M+="Inde";w7M+="x";j7f.Studies.calculateOnBalanceVolume=function(V99,s5z){var v6w,I68,g1n,N4f,d1M,g5Z,d1I,Y5O,b$q,s0h,M1S,y$p,O46,k0Q,p$C;v6w="f";v6w+="ield";I68=s5z.inputs.Field;if(!I68 || I68 == v6w){I68="Close";}g1n=s5z.inputs["Min Tick Value"];N4f=!!"";if(!g1n && g1n !== +"0"){N4f=!!({});d1M=1160176223;g5Z=1055944688;d1I=2;for(var f5D=1;f6b.S9Y(f5D.toString(),f5D.toString().length,"66165" << 32) !== d1M;f5D++){g1n=0;d1I+=2;}if(f6b.S9Y(d1I.toString(),d1I.toString().length,87319) !== g5Z){g1n=+"2";}}Y5O=s5z.chart.scrubbed;b$q=0;s0h=781454516;f6b.f3X();f6b.N_M(5);M1S=f6b.a$j(1,"2073931254");y$p=2;for(var S_c="1" << 32;f6b.S9Y(S_c.toString(),S_c.toString().length,15810) !== s0h;S_c++){y$p+=2;}if(f6b.S9Y(y$p.toString(),y$p.toString().length,79077) !== M1S){}for(var p9R=s5z.startFrom;p9R < Y5O.length;p9R++){O46=Y5O[p9R];if(!p9R || !O46[I68])continue;if(Y5O[p9R - 1][I68]){f6b.j7J(14);k0Q=Y5O[f6b.a$j(p9R,1)];}if(!k0Q)continue;if(O46[I68] - k0Q[I68] > g1n){b$q=1;}else if(k0Q[I68] - O46[I68] > g1n){b$q=-1;}else if(N4f){b$q=0;}p$C=k0Q["Result " + s5z.name];if(!p$C){p$C=+"0";}p$C+=O46.Volume * b$q;O46["Result " + s5z.name]=p$C;}};j7f.Studies.calculatePriceVolumeTrend=function(Y12,e5$){var o5a,T3W,y9a,L2Z;o5a=e5$.inputs.Field;if(!o5a || o5a == "field"){o5a="Close";}T3W=e5$.chart.scrubbed;y9a=0;if(e5$.startFrom > 1){L2Z="Re";L2Z+="su";L2Z+="lt ";f6b.j7J(184);var w55=f6b.c0C(25,1,7,46);y9a=T3W[e5$.startFrom - ("1" << w55)][L2Z + e5$.name];}for(var u4U=Math.max(1,e5$.startFrom);u4U < T3W.length;u4U++){if(!T3W[u4U][o5a])continue;if(!T3W[u4U - ("1" | 0)][o5a])continue;f6b.N_M(185);var s4p=f6b.c0C(9,4,19,2);f6b.N_M(184);var j7F=f6b.c0C(4,6,5,12);y9a+=T3W[u4U].Volume * (T3W[u4U][o5a] - T3W[u4U - s4p][o5a]) / T3W[u4U - j7F][o5a];T3W[u4U]["Result " + e5$.name]=y9a;}};j7f.Studies.calculateVolumeIndex=function(n1Y,d4v){var E6$,y$0,S8t,e8M,G9n,m7K,T$L,k3o,q$t,I05;E6$="I";E6$+="ndex ";y$0=d4v.inputs.Field;if(!y$0 || y$0 == "field"){y$0="Close";}S8t=d4v.chart.scrubbed;if(S8t.length < d4v.days + 1){d4v.error=!![];return;}f6b.T$X();e8M=100;if(d4v.startFrom > 1){f6b.N_M(123);var P71=f6b.a$j(1,18,6,0,4);e8M=S8t[d4v.startFrom - P71][E6$ + d4v.name];}for(var E8H=Math.max(1,d4v.startFrom);E8H < S8t.length;E8H++){G9n="In";G9n+="d";G9n+="ex ";m7K="Ne";m7K+="g Vol";T$L=S8t[E8H][y$0];k3o=S8t[E8H].Volume;if(T$L && typeof T$L == "object"){k3o=T$L.Volume;T$L=T$L[d4v.subField];}f6b.N_M(14);q$t=S8t[f6b.c0C(E8H,1)][y$0];I05=S8t[E8H - 1].Volume;if(q$t && typeof q$t == "object"){I05=q$t.Volume;q$t=q$t[d4v.subField];}if(!T$L)continue;if(!q$t)continue;if(d4v.type == "Pos Vol" && k3o > I05 || d4v.type == m7K && k3o < I05){f6b.N_M(7);e8M*=f6b.a$j(T$L,q$t);}S8t[E8H][G9n + d4v.name]=e8M;}j7f.Studies.MA(d4v.inputs["Moving Average Type"],d4v.days,"Index " + d4v.name,0,"MA",n1Y,d4v);};j7f.Studies.studyLibrary=j7f.extend(j7f.Studies.studyLibrary,{"Neg Vol":{name:w7M,calculateFN:j7f.Studies.calculateVolumeIndex,inputs:{Period:255,Field:q1B,"Moving Average Type":Y$z},outputs:{Index:"auto",MA:d1L}},"On Bal Vol":{name:"On Balance Volume",calculateFN:j7f.Studies.calculateOnBalanceVolume,inputs:{}},"Pos Vol":{name:"Positive Volume Index",calculateFN:j7f.Studies.calculateVolumeIndex,inputs:{Period:255,Field:"field","Moving Average Type":"ma"},outputs:{Index:S81,MA:h72}},"Price Vol":{name:d0U,calculateFN:j7f.Studies.calculatePriceVolumeTrend,inputs:{Field:"field"}},"Trade Vol":{name:s2r,calculateFN:j7f.Studies.calculateOnBalanceVolume,inputs:{"Min Tick Value":0.5}},"Vol ROC":{name:"Volume Rate of Change",calculateFN:function(F1M,Q9s){if(j7f.Studies.calculateRateOfChange){j7f.Studies.calculateRateOfChange(F1M,Q9s);}else {console.error("Volume Rate of Change study requires first activating momentum feature.");j7f.Studies.calculateRateOfChange=function(P$V,n_l){};}},parameters:{init:{isVolume:!!({})}}},"vol undr":{name:h$S,underlay:!!"1",range:"0 to max",yAxis:{ground:!![],initialMarginTop:"0" << 32,position:"none",zoom:0,heightFactor:"0.25" * 1},seriesFN:j7f.Studies.createVolumeChart,calculateFN:j7f.Studies.calculateVolume,inputs:{},outputs:{"Up Volume":"#8cc176","Down Volume":l4H},customRemoval:!![],removeFN:function(t9g,V_I){var b2F;b2F="l";b2F+="ayo";b2F+="u";b2F+="t";t9g.layout.volumeUnderlay=!({});t9g.changeOccurred(b2F);},attributes:{panelName:{hidden:!![]}}}});}};t2=g7j=>{var T9e,e2s,j2E,g02,W3q;T9e=typeof _CIQ !== "undefined"?_CIQ:g7j.CIQ;if(!T9e.Studies){e2s="vortex featu";e2s+="re requires firs";e2s+="t acti";e2s+="vating studies feature.";console.error(e2s);}else {j2E="0";j2E+=".0";j2E+="1";g02="#00";g02+="F";g02+="F00";W3q="Vo";W3q+="rtex Indicator";T9e.Studies.calculateVortex=function(Q$m,Z6d){var o64=f3BGj;var D8R,K$K,j40,P_R,L$v,u1P,H6K,X4j,u2v,b9m,w3U,h63;D8R=Z6d.chart.scrubbed;K$K=Z6d.days;if(D8R.length < K$K + 1){Z6d.error=!![];return;}o64.T$X();j40={tr:0,vmPlus:0,vmMinus:0};if(Z6d.startFrom > +"1"){j40=T9e.clone(D8R[Z6d.startFrom - +"1"]["_totals " + Z6d.name]);}for(var k8t=Math.max(Z6d.startFrom,+"1");k8t < D8R.length;k8t++){P_R=D8R[k8t];o64.j7J(14);L$v=D8R[o64.a$j(k8t,1)];u1P=Math.abs(P_R.High - L$v.Low);H6K=Math.abs(P_R.Low - L$v.High);X4j=Math.max(P_R.High,L$v.Close) - Math.min(P_R.Low,L$v.Close);j40.tr+=X4j;j40.vmPlus+=u1P;j40.vmMinus+=H6K;if(k8t > K$K){u2v="_VM";u2v+="Mi";u2v+="n";u2v+="us ";b9m="_VMP";b9m+="l";b9m+="u";b9m+="s ";w3U="_True Rang";w3U+="e ";o64.j7J(14);j40.tr-=D8R[o64.a$j(k8t,K$K)][w3U + Z6d.name];o64.N_M(14);j40.vmPlus-=D8R[o64.c0C(k8t,K$K)][b9m + Z6d.name];o64.j7J(14);j40.vmMinus-=D8R[o64.c0C(k8t,K$K)][u2v + Z6d.name];}P_R["_True Range " + Z6d.name]=X4j;P_R["_VMPlus " + Z6d.name]=u1P;P_R["_VMMinus " + Z6d.name]=H6K;if(k8t >= K$K){h63="-";h63+="V";h63+="I";h63+=" ";P_R["+VI " + Z6d.name]=j40.vmPlus / j40.tr;P_R[h63 + Z6d.name]=j40.vmMinus / j40.tr;}P_R["_totals " + Z6d.name]=T9e.clone(j40);}};T9e.Studies.studyLibrary=T9e.extend(T9e.Studies.studyLibrary,{Vortex:{name:W3q,calculateFN:T9e.Studies.calculateVortex,centerline:1,outputs:{"+VI":g02,"-VI":"#FF0000"},parameters:{init:{studyOverZonesEnabled:!!"1",studyOverBoughtValue:1.1,studyOverBoughtColor:"auto",studyOverSoldValue:0.9,studyOverSoldColor:"auto"}},attributes:{studyOverBoughtValue:{min:1,step:"0.01"},studyOverSoldValue:{max:1,step:j2E}}}});}};m_=G_6=>{var R1_=f3BGj;R1_.T$X();var R_q,L2x;R_q=typeof _CIQ !== "undefined"?_CIQ:G_6.CIQ;if(!R_q.Studies){console.error("williamsMFI feature requires first activating studies feature.");}else {L2x="#ffd0c";L2x+="f";R_q.Studies.calculateMFI=function(r0H,w31){var k$9,U_j,D2v,u0_,M61,d$O,U7x;R1_.T$X();k$9=w31.chart.scrubbed;R1_.j7J(31);D2v=R1_.a$j("0",32);u0_=w31.inputs["Scale Factor"];if(!u0_){u0_=w31.study.inputs["Scale Factor"];}M61=Math.pow(10,Number(u0_));if(w31.startFrom > "1" >> 96){R1_.N_M(119);var j8d=R1_.a$j(5,57,19,4);D2v=k$9[w31.startFrom - j8d]["_high " + w31.name];}for(d$O=w31.startFrom;d$O < k$9.length;d$O++){if(!k$9[d$O])continue;if(k$9[d$O].Volume){U7x="_";U7x+="hi";U7x+="st";k$9[d$O][w31.name + U7x]=U_j=M61 * (k$9[d$O].High - k$9[d$O].Low) / k$9[d$O].Volume;k$9[d$O]["_high " + w31.name]=D2v=Math.max(D2v,U_j);}}w31.outputMap={};w31.outputMap[w31.name + "_hist"]="";};R_q.Studies.displayMFI=function(n6W,N6X,K1c){var e_y,h$l,U2B,d3_,L8e,a9G,Z9g,S8T,f3i,p4p,d3h,m7C;e_y="stx_";e_y+="histogr";e_y+="am";h$l=n6W.panels[N6X.panel];U2B=N6X.getContext(n6W);d3_=N6X.getYAxis(n6W);L8e=d3_.flipped?d3_.top:d3_.bottom;R1_.N_M(186);var k97=R1_.c0C(18,15,15,4052);a9G=n6W.layout.candleWidth - k97;if(a9G < 2){a9G=1;}Z9g=R_q.Studies.determineColor(N6X.outputs.Green);S8T=R_q.Studies.determineColor(N6X.outputs.Fade);R1_.T$X();f3i=R_q.Studies.determineColor(N6X.outputs.Fake);p4p=R_q.Studies.determineColor(N6X.outputs.Squat);n6W.canvasColor(e_y);if(!N6X.underlay){U2B.globalAlpha=1;}U2B.fillStyle="#CCCCCC";n6W.startClip(N6X.panel);if(!N6X.highlight && n6W.highlightedDraggable){U2B.globalAlpha*=0.3;}for(var r1n=0;r1n < K1c.length;r1n++){d3h=K1c[r1n];R1_.N_M(14);m7C=K1c[R1_.c0C(r1n,1)];if(!m7C){m7C=n6W.getPreviousBar(n6W.chart,N6X.name + "_hist",r1n);}if(!d3h)continue;if(!m7C);else if(m7C[N6X.name + "_hist"] < d3h[N6X.name + "_hist"]){if(m7C.Volume < d3h.Volume){U2B.fillStyle=Z9g;}else if(m7C.Volume > d3h.Volume){U2B.fillStyle=f3i;}}else if(m7C[N6X.name + "_hist"] > d3h[N6X.name + "_hist"]){if(m7C.Volume < d3h.Volume){U2B.fillStyle=p4p;}else if(m7C.Volume > d3h.Volume){U2B.fillStyle=S8T;}}if(d3h.candleWidth){a9G=Math.floor(Math.max(1,d3h.candleWidth - 2));}U2B.fillRect(Math.floor(n6W.pixelFromBar(r1n,h$l.chart) - a9G / 2),Math.floor(L8e),Math.floor(a9G),Math.floor(n6W.pixelFromPrice(d3h[N6X.name + "_hist"],h$l,d3_) - L8e));}n6W.endClip();};R_q.Studies.studyLibrary=R_q.extend(R_q.Studies.studyLibrary,{"W MFI":{name:"Market Facilitation Index",seriesFN:R_q.Studies.displayMFI,calculateFN:R_q.Studies.calculateMFI,yAxis:{ground:!0},range:"0 to max",inputs:{"Scale Factor":6},outputs:{Green:"#8bc176",Fade:"#ab611f",Fake:"#5f7cb8",Squat:L2x}}});}};c7={CIQ:a4,SplinePlotter:p4,timezoneJS:j0,$$:J2,$$$:g9};export {N as aggregations};export {Q as drawingAdvanced};export {Z as equationsAdvanced};export {S as highPerformanceMarkers};export {W as renderersAdvanced};export {o as accumulationDistribution};export {U as adx};export {g as alligator};export {Y as aroon};export {G as atr};export {X as awesomeOscillator};export {E as balanceOfPower};export {F as bollinger};export {I as cci};export {M_ as centerOfGravity};export {h1 as chaikin};export {W3 as chande};export {W9 as choppiness};export {C5 as comparisonStudies};export {b4 as coppock};export {f3 as darvasBox};export {n8 as detrended};export {p9 as disparity};export {f8 as easeOfMovement};export {A3 as ehlerFisher};export {b0 as elder};export {j4 as fractalChaos};export {U1 as highLowStudies};export {W2 as ichimoku};export {K0 as intradayMomentum};export {G_ as keltner};export {T8 as klinger};export {d8 as linearRegression};export {T6 as macd};export {k1 as massIndex};export {e4 as moneyFlow};export {A1 as movingAverages};export {d_ as parabolicSAR};export {O9 as pivotPoints};export {s4 as prettyGoodOscillator};export {e5 as priceMomentumOscillator};export {C$ as priceVolumeOscillator};export {y9 as primeNumber};export {v8 as pring};export {L4 as projectedVolume};export {o3 as psychologicalLine};export {i8 as qstick};export {O$ as rainbow};export {r_ as randomWalk};export {O5 as relativeVigor};export {i3 as rsi};export {Q7 as schaffTrendCycle};export {Z4 as shinohara};export {T0 as stochastics};export {x$ as supertrend};export {k4 as swingIndex};export {N1 as trendIntensity};export {a7 as trix};export {h3 as twiggsMoneyFlow};export {C6 as typicalPrice};export {M$ as ulcerIndex};export {q7 as ultimateOscillator};export {a9 as valuationLines};export {U9 as volatilityIndex};export {d5 as volumeProfile};export {o7 as volumeStudies};export {t2 as vortex};export {m_ as williamsMFI};export {a4 as CIQ, p4 as SplinePlotter, j0 as timezoneJS, J2 as $$, g9 as $$$};if(typeof __TREE_SHAKE__ === "undefined" || !__TREE_SHAKE__){c7.CIQ.activateImports(N,Q,Z,S,W,o,U,g,Y,G,X,E,F,I,M_,h1,W3,W9,C5,b4,f3,n8,p9,f8,A3,b0,j4,U1,W2,K0,G_,T8,d8,T6,k1,e4,A1,d_,O9,s4,e5,C$,y9,v8,L4,o3,i8,O$,r_,O5,i3,Q7,Z4,T0,x$,k4,N1,a7,h3,C6,M$,q7,a9,U9,d5,o7,t2,m_,null);}/* eslint-enable */ /* jshint ignore:end */ /* ignore jslint end */ diff --git a/chartiq/production/js/chartiq.js b/chartiq/production/js/chartiq.js deleted file mode 100644 index cae54fe1aa..0000000000 --- a/chartiq/production/js/chartiq.js +++ /dev/null @@ -1,88 +0,0 @@ -/**! - * 8.2.0 - * Generation date: 2023-03-23T15:05:01.971Z - * Client name: deriv limited - * Package Type: Technical Analysis - * License type: annual - * Expiration date: "2024/04/01" - * Domain lock: ["127.0.0.1","localhost","deriv.com","deriv.app","deriv.me","binary.com","binary.sx","binary.me","binary.bot","deriv.be"] - * iFrame lock: true - */ - -/***********************************************************! - * Copyright by ChartIQ, Inc. - * Licensed under the ChartIQ, Inc. Developer License Agreement https://www.chartiq.com/developer-license-agreement -*************************************************************/ -/*************************************! DO NOT MAKE CHANGES TO THIS LIBRARY FILE!! !************************************* -* If you wish to overwrite default functionality, create a separate file with a copy of the methods you are overwriting * -* and load that file right after the library has been loaded, but before the chart engine is instantiated. * -* Directly modifying library files will prevent upgrades and the ability for ChartIQ to support your solution. * -*************************************************************************************************************************/ - -/*************************************************************************! -* Please note that manually changing the domain list or expiration dates * -* * -* >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> WILL NOT <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< * -* * -* modify the library locking mechanism. Any changes must be requested * -* directly from chartIQ. * -***************************************************************************/ - -(function() { - /* eslint-disable no-undef-init */ - var domains = ["127.0.0.1","localhost","deriv.com","deriv.app","deriv.me","binary.com","binary.sx","binary.me","binary.bot","deriv.be"]; - var filesystem = false; - var licenseExpiration = "2024/04/01"; - var trialExpiration = undefined; - var version = '8.2.0'; - var expiration; - - if (trialExpiration) expiration = new Date(trialExpiration).getTime(); - else if (licenseExpiration) expiration = new Date(licenseExpiration).getTime(); - - if (expiration) { - var now = new Date().getTime(); - - if (expiration <= now) { - if (trialExpiration) alert("This license has expired!"); - console.error("This license has expired!"); - } else if (trialExpiration) { - var diffDays = Math.round((expiration - now) / (1000 * 60 * 60 * 24)); - - if (diffDays < 3) { - alert("This trial license expires in " + diffDays + " days!"); - console.log("WARNING: This trial license expires in " + diffDays + " days!"); - } - } - } - if(typeof document!=='undefined'){ - if (filesystem === true && document.location.protocol == 'file:') { - return; // valid environment, skip domain check - } - if (domains && domains.length > 0) { - var href = document.location.href; - var found = false; - - for (var i = 0; i < domains.length; i++) { - if (href.indexOf(domains[i]) > -1) { - found = true; - break; - } - } - - if (!found) { - alert("ERROR: Not licensed for domain " + href); - console.error("ERROR: Not licensed for domain " + href); - } - } - } - if(version === 'alpha'){ - window.alert('This is an internal PRE-PRODUCTION release--not for external use!'); - } -})(); - -/* eslint-disable no-extra-parens */ - - -/* eslint-disable */ /* jshint ignore:start */ /* ignore jslint start */ -x2dci[370258]=(function(){var Y=2;for(;Y !== 9;){switch(Y){case 2:Y=typeof globalThis === '\x6f\x62\x6a\u0065\x63\x74'?1:5;break;case 1:return globalThis;break;case 5:var L;Y=4;break;case 4:try{var X=2;for(;X !== 6;){switch(X){case 2:Object['\u0064\x65\x66\u0069\x6e\u0065\u0050\u0072\u006f\u0070\x65\u0072\x74\x79'](Object['\x70\u0072\u006f\x74\u006f\x74\u0079\x70\x65'],'\x4c\u006c\u0036\u0052\x39',{'\x67\x65\x74':function(){var V=2;for(;V !== 1;){switch(V){case 2:return this;break;}}},'\x63\x6f\x6e\x66\x69\x67\x75\x72\x61\x62\x6c\x65':true});L=Ll6R9;X=5;break;case 5:L['\x42\u0042\u004f\x38\x38']=L;X=4;break;case 4:X=typeof BBO88 === '\x75\u006e\x64\u0065\u0066\u0069\u006e\u0065\x64'?3:9;break;case 3:throw "";X=9;break;case 9:delete L['\x42\x42\u004f\u0038\x38'];var H=Object['\u0070\x72\u006f\u0074\u006f\x74\x79\u0070\x65'];delete H['\x4c\x6c\u0036\x52\u0039'];X=6;break;}}}catch(k){L=window;}return L;break;}}})();u$FZV3(x2dci[370258]);x2dci[150014]=(function(L2m){var u5x=2;for(;u5x !== 10;){switch(u5x){case 11:return {R3ta_F9:function(d9p){var L58=2;for(;L58 !== 6;){switch(L58){case 5:L58=!d8I--?4:3;break;case 3:L58=!d8I--?9:8;break;case 2:var y2_=new Q3K[L2m[0]]()[L2m[1]]();L58=1;break;case 9:A6C=y2_ + 60000;L58=8;break;case 7:return R_9?S6O:!S6O;break;case 1:L58=y2_ > A6C?5:8;break;case 8:var R_9=(function(i04,j6H){var O1a=2;for(;O1a !== 10;){switch(O1a){case 9:O1a=o5N < i04[j6H[5]]?8:11;break;case 3:var Z5m,o5N=0;O1a=9;break;case 8:var Z2j=Q3K[j6H[4]](i04[j6H[2]](o5N),16)[j6H[3]](2);var P5J=Z2j[j6H[2]](Z2j[j6H[5]] - 1);O1a=6;break;case 13:o5N++;O1a=9;break;case 4:j6H=L2m;O1a=3;break;case 11:return Z5m;break;case 12:Z5m=Z5m ^ P5J;O1a=13;break;case 5:O1a=typeof j6H === 'undefined' && typeof L2m !== 'undefined'?4:3;break;case 6:O1a=o5N === 0?14:12;break;case 14:Z5m=P5J;O1a=13;break;case 1:i04=d9p;O1a=5;break;case 2:O1a=typeof i04 === 'undefined' && typeof d9p !== 'undefined'?1:5;break;}}})(undefined,undefined);L58=7;break;case 4:S6O=Y7T(y2_);L58=3;break;}}}};break;case 2:var Q3K,E$2,Z9n,d8I;u5x=1;break;case 4:var s0R='fromCharCode',u9z='RegExp';u5x=3;break;case 5:Q3K=x2dci[370258];u5x=4;break;case 13:u5x=!d8I--?12:11;break;case 12:var S6O,A6C=0;u5x=11;break;case 8:u5x=!d8I--?7:6;break;case 7:Z9n=E$2.T3NZuy(new Q3K[u9z]("^['-|]"),'S');u5x=6;break;case 6:u5x=!d8I--?14:13;break;case 14:L2m=L2m.Y8FL1O(function(z6x){var d8M=2;for(;d8M !== 13;){switch(d8M){case 8:v$y++;d8M=3;break;case 14:return a6L;break;case 7:d8M=!a6L?6:14;break;case 2:var a6L;d8M=1;break;case 4:var v$y=0;d8M=3;break;case 6:return;break;case 9:a6L+=Q3K[Z9n][s0R](z6x[v$y] + 93);d8M=8;break;case 1:d8M=!d8I--?5:4;break;case 3:d8M=v$y < z6x.length?9:7;break;case 5:a6L='';d8M=4;break;}}});u5x=13;break;case 1:u5x=!d8I--?5:4;break;case 9:E$2=typeof s0R;u5x=8;break;case 3:u5x=!d8I--?9:8;break;}}function Y7T(B8u){var g4H=2;for(;g4H !== 15;){switch(g4H){case 3:a3Y=27;g4H=9;break;case 20:X2g=B8u - A4$ > a3Y && S7e - B8u > a3Y;g4H=19;break;case 8:l7B=L2m[6];g4H=7;break;case 13:e9t=L2m[7];g4H=12;break;case 4:g4H=!d8I--?3:9;break;case 10:g4H=A4$ >= 0 && S7e >= 0?20:18;break;case 17:X2g=B8u - A4$ > a3Y;g4H=19;break;case 5:m6J=Q3K[L2m[4]];g4H=4;break;case 16:X2g=S7e - B8u > a3Y;g4H=19;break;case 19:return X2g;break;case 12:g4H=!d8I--?11:10;break;case 11:A4$=(e9t || e9t === 0) && m6J(e9t,a3Y);g4H=10;break;case 6:S7e=l7B && m6J(l7B,a3Y);g4H=14;break;case 7:g4H=!d8I--?6:14;break;case 14:g4H=!d8I--?13:12;break;case 1:g4H=!d8I--?5:4;break;case 2:var X2g,a3Y,l7B,S7e,e9t,A4$,m6J;g4H=1;break;case 18:g4H=A4$ >= 0?17:16;break;case 9:g4H=!d8I--?8:7;break;}}}})([[-25,4,23,8],[10,8,23,-9,12,16,8],[6,11,4,21,-28,23],[23,18,-10,23,21,12,17,10],[19,4,21,22,8,-20,17,23],[15,8,17,10,23,11],[-39,-44,18,6,19,17,8,7,-45],[]]);x2dci.h$V=function(){return typeof x2dci[539515].x96qQgs === 'function'?x2dci[539515].x96qQgs.apply(x2dci[539515],arguments):x2dci[539515].x96qQgs;};x2dci[238553]=(function(){var I$t=2;for(;I$t !== 9;){switch(I$t){case 2:var O2$=[arguments];O2$[2]=undefined;O2$[8]={};O2$[8].i9agN$W=function(){var h24=2;for(;h24 !== 90;){switch(h24){case 4:q4U[9]=[];q4U[3]={};q4U[3].E$t=['G$p'];h24=8;break;case 70:q4U[73]++;h24=57;break;case 53:q4U[9].I5beBg(q4U[68]);q4U[9].I5beBg(q4U[4]);q4U[9].I5beBg(q4U[53]);q4U[9].I5beBg(q4U[75]);h24=49;break;case 57:h24=q4U[73] < q4U[9].length?56:69;break;case 30:q4U[83]={};h24=29;break;case 38:q4U[57].E$t=['G$p'];q4U[57].v3c=function(){var L0m=function(){return String.fromCharCode(0x61);};var r3Z=!(/\060\x78\u0036\x31/).S$ysjf(L0m + []);return r3Z;};q4U[18]=q4U[57];q4U[9].I5beBg(q4U[97]);h24=53;break;case 68:h24=41?68:67;break;case 59:q4U[16]='t93';h24=58;break;case 58:q4U[73]=0;h24=57;break;case 75:q4U[49]={};q4U[49][q4U[16]]=q4U[28][q4U[48]][q4U[52]];q4U[49][q4U[61]]=q4U[10];h24=72;break;case 72:q4U[37].I5beBg(q4U[49]);h24=71;break;case 49:q4U[9].I5beBg(q4U[6]);q4U[9].I5beBg(q4U[8]);q4U[9].I5beBg(q4U[2]);h24=46;break;case 71:q4U[52]++;h24=76;break;case 46:q4U[9].I5beBg(q4U[18]);q4U[9].I5beBg(q4U[29]);h24=65;break;case 5:return 41;break;case 69:h24=(function(G7b){var c$3=2;for(;c$3 !== 22;){switch(c$3){case 11:D1D[9][D1D[5][q4U[16]]].t+=true;c$3=10;break;case 8:D1D[6]=0;c$3=7;break;case 6:D1D[5]=D1D[0][0][D1D[6]];c$3=14;break;case 26:c$3=D1D[7] >= 0.5?25:24;break;case 14:c$3=typeof D1D[9][D1D[5][q4U[16]]] === 'undefined'?13:11;break;case 15:D1D[4]=D1D[2][D1D[6]];D1D[7]=D1D[9][D1D[4]].h / D1D[9][D1D[4]].t;c$3=26;break;case 17:D1D[6]=0;c$3=16;break;case 10:c$3=D1D[5][q4U[61]] === q4U[80]?20:19;break;case 19:D1D[6]++;c$3=7;break;case 4:D1D[9]={};D1D[2]=[];D1D[6]=0;c$3=8;break;case 18:D1D[8]=false;c$3=17;break;case 2:var D1D=[arguments];c$3=1;break;case 1:c$3=D1D[0][0].length === 0?5:4;break;case 23:return D1D[8];break;case 20:D1D[9][D1D[5][q4U[16]]].h+=true;c$3=19;break;case 5:return;break;case 16:c$3=D1D[6] < D1D[2].length?15:23;break;case 24:D1D[6]++;c$3=16;break;case 12:D1D[2].I5beBg(D1D[5][q4U[16]]);c$3=11;break;case 7:c$3=D1D[6] < D1D[0][0].length?6:18;break;case 13:D1D[9][D1D[5][q4U[16]]]=(function(){var J$8=2;for(;J$8 !== 9;){switch(J$8){case 2:var y92=[arguments];y92[7]={};J$8=5;break;case 5:y92[7].h=0;y92[7].t=0;return y92[7];break;}}}).P8x2af(this,arguments);c$3=12;break;case 25:D1D[8]=true;c$3=24;break;}}})(q4U[37])?68:67;break;case 42:q4U[85].E$t=['G$p'];q4U[85].v3c=function(){var p0u=function(){return btoa('=');};var Y9_=!(/\142\x74\x6f\u0061/).S$ysjf(p0u + []);return Y9_;};q4U[29]=q4U[85];q4U[57]={};h24=38;break;case 1:h24=O2$[2]?5:4;break;case 56:q4U[28]=q4U[9][q4U[73]];try{q4U[10]=q4U[28][q4U[20]]()?q4U[80]:q4U[60];}catch(V7P){q4U[10]=q4U[60];}h24=77;break;case 65:q4U[37]=[];q4U[80]='N7n';q4U[60]='C2f';q4U[48]='E$t';q4U[61]='g5n';q4U[20]='v3c';h24=59;break;case 13:q4U[5].v3c=function(){var Z18=function(){return ('a|a').split('|');};var o89=!(/\174/).S$ysjf(Z18 + []);return o89;};q4U[4]=q4U[5];h24=11;break;case 8:q4U[3].v3c=function(){var Q5m=function(){return ('aaaa').padEnd(5,'a');};var a9A=(/\x61\x61\141\u0061\x61/).S$ysjf(Q5m + []);return a9A;};q4U[6]=q4U[3];q4U[5]={};q4U[5].E$t=['G$p'];h24=13;break;case 2:var q4U=[arguments];h24=1;break;case 11:q4U[7]={};q4U[7].E$t=['c53'];q4U[7].v3c=function(){var Z6N=typeof S0XDzw === 'function';return Z6N;};h24=19;break;case 35:q4U[97]=q4U[36];q4U[70]={};q4U[70].E$t=['c53'];q4U[70].v3c=function(){var R94=typeof R82foz === 'function';return R94;};q4U[75]=q4U[70];h24=30;break;case 76:h24=q4U[52] < q4U[28][q4U[48]].length?75:70;break;case 24:q4U[68]=q4U[13];q4U[36]={};q4U[36].E$t=['c53'];q4U[36].v3c=function(){var h6Z=typeof O_Xnak === 'function';return h6Z;};h24=35;break;case 15:q4U[8]=q4U[1];q4U[13]={};q4U[13].E$t=['c53'];q4U[13].v3c=function(){var W5m=false;var t7u=[];try{for(var Q9T in console){t7u.I5beBg(Q9T);}W5m=t7u.length === 0;}catch(g0$){}var v6b=W5m;return v6b;};h24=24;break;case 67:O2$[2]=64;return 68;break;case 29:q4U[83].E$t=['G$p'];q4U[83].v3c=function(){var t1h=function(){var s$W=function(X0Q){for(var W2d=0;W2d < 20;W2d++){X0Q+=W2d;}return X0Q;};s$W(2);};var X0R=(/\x31\x39\x32/).S$ysjf(t1h + []);return X0R;};q4U[53]=q4U[83];q4U[85]={};h24=42;break;case 19:q4U[2]=q4U[7];q4U[1]={};q4U[1].E$t=['G$p'];q4U[1].v3c=function(){var f5K=function(){return ['a','a'].join();};var v8Q=!(/(\x5b|\u005d)/).S$ysjf(f5K + []);return v8Q;};h24=15;break;case 77:q4U[52]=0;h24=76;break;}}};return O2$[8];break;}}})();x2dci.E2w=function(){return typeof x2dci[539515].q7DznqI === 'function'?x2dci[539515].q7DznqI.apply(x2dci[539515],arguments):x2dci[539515].q7DznqI;};x2dci.Y$r=function(){return typeof x2dci[150014].R3ta_F9 === 'function'?x2dci[150014].R3ta_F9.apply(x2dci[150014],arguments):x2dci[150014].R3ta_F9;};x2dci[156040]=x2dci[593596];x2dci.c6Y=function(){return typeof x2dci[593596].N$y1PkD === 'function'?x2dci[593596].N$y1PkD.apply(x2dci[593596],arguments):x2dci[593596].N$y1PkD;};x2dci[593596]=(function(F_h){return {N$y1PkD:function(){var l5l,a3p=arguments;switch(F_h){case 167:l5l=(a3p[3] + a3p[4]) * a3p[0] - a3p[1] - a3p[2];break;case 144:l5l=(-a3p[3] - a3p[2]) * a3p[1] + a3p[0] + a3p[4];break;case 65:l5l=(a3p[3] + a3p[2]) / a3p[1] - a3p[0];break;case 58:l5l=a3p[3] / a3p[2] + a3p[4] - a3p[1] - a3p[0];break;case 57:l5l=a3p[0] / a3p[2] - a3p[1] + a3p[3] - a3p[4];break;case 64:l5l=a3p[0] / a3p[3] / a3p[2] + a3p[1];break;case 155:l5l=a3p[3] / a3p[4] * a3p[0] * a3p[1] - a3p[2];break;case 86:l5l=(a3p[1] + a3p[3] - a3p[0]) / a3p[4] + a3p[2];break;case 15:l5l=-a3p[1] * a3p[3] * a3p[0] + a3p[2];break;case 163:l5l=a3p[1] / a3p[2] / a3p[0] * a3p[4] + a3p[3];break;case 46:l5l=a3p[0] << a3p[1];break;case 145:l5l=(a3p[2] >> a3p[0]) - a3p[1];break;case 110:l5l=(a3p[0] - a3p[4]) / a3p[2] + a3p[1] + a3p[3];break;case 3:l5l=a3p[3] + a3p[2] + a3p[1] - a3p[0];break;case 55:l5l=(a3p[0] / a3p[4] - a3p[1]) / a3p[3] + a3p[2];break;case 17:l5l=(a3p[2] - a3p[3]) / a3p[4] / a3p[0] + a3p[1];break;case 71:l5l=a3p[0] + a3p[7] + a3p[2] + a3p[6] + a3p[3] + a3p[5] + a3p[8] + a3p[1] + a3p[4];break;case 171:l5l=a3p[4] * a3p[3] - a3p[1] + a3p[0] - a3p[2];break;case 134:l5l=-a3p[2] * a3p[1] + a3p[0];break;case 48:l5l=a3p[3] + (a3p[6] - a3p[1]) * (a3p[5] / a3p[2] - a3p[4]) * a3p[0];break;case 51:l5l=a3p[3] - a3p[1] / (a3p[0] * a3p[2]);break;case 151:l5l=a3p[1] + a3p[3] / a3p[0] * a3p[2];break;case 106:l5l=a3p[0] == a3p[1];break;case 84:l5l=a3p[1] * a3p[3] - a3p[2] - a3p[0];break;case 80:l5l=a3p[2] + a3p[4] + a3p[1] + a3p[3] + a3p[0];break;case 30:l5l=a3p[1] - a3p[0] - a3p[2];break;case 104:l5l=a3p[0] !== a3p[1];break;case 32:l5l=(a3p[2] * a3p[1] - a3p[4]) * a3p[0] - a3p[3];break;case 6:l5l=a3p[0] - a3p[1] - a3p[2] + a3p[3] + a3p[4];break;case 79:l5l=a3p[3] + a3p[2] - a3p[1] - a3p[0];break;case 12:l5l=(a3p[4] - a3p[3] + a3p[0]) / a3p[1] - a3p[2];break;case 50:l5l=a3p[3] + a3p[1] / (a3p[2] ^ a3p[0]);break;case 35:l5l=a3p[4] * a3p[2] * a3p[1] - a3p[3] - a3p[0];break;case 89:l5l=(a3p[3] - a3p[2]) / a3p[0] - a3p[1];break;case 63:l5l=(a3p[4] - a3p[1]) / a3p[0] - a3p[2] + a3p[3];break;case 117:l5l=(a3p[1] - a3p[0]) * a3p[4] - a3p[2] - a3p[3];break;case 159:l5l=(-a3p[1] + a3p[4]) / a3p[3] + a3p[2] - a3p[0];break;case 5:l5l=a3p[2] - a3p[1] + a3p[4] + a3p[0] - a3p[3];break;case 67:l5l=a3p[0] / a3p[2] + a3p[1];break;case 146:l5l=a3p[0] * -a3p[1];break;case 78:l5l=a3p[2] - a3p[3] + a3p[1] - a3p[0];break;case 109:l5l=a3p[4] * a3p[2] - a3p[0] - a3p[3] + a3p[1];break;case 158:l5l=-a3p[1] * a3p[3] / a3p[2] - a3p[4] + a3p[0];break;case 45:l5l=(a3p[1] - a3p[3]) / a3p[4] + (a3p[0] | a3p[2]);break;case 118:l5l=(a3p[3] - a3p[2] - a3p[1]) * a3p[0] - a3p[4];break;case 85:l5l=a3p[0] + a3p[1] - a3p[3] - a3p[2] + a3p[4];break;case 9:l5l=a3p[0] * a3p[4] * a3p[2] + a3p[3] - a3p[1];break;case 99:l5l=a3p[1] / a3p[4] * a3p[3] * a3p[0] + a3p[2];break;case 108:l5l=(a3p[3] - a3p[0]) * a3p[1] + a3p[2] - a3p[4];break;case 29:l5l=(-a3p[0] - a3p[1]) * a3p[2] + a3p[3];break;case 18:l5l=-a3p[0] * a3p[3] / a3p[1] + a3p[2];break;case 41:l5l=a3p[1] * (a3p[3] - a3p[0] / (a3p[2] - a3p[4]));break;case 112:l5l=a3p[3] / a3p[2] + a3p[0] + a3p[1];break;case 115:l5l=a3p[1] / a3p[3] / a3p[2] - a3p[0] + a3p[4];break;case 150:l5l=a3p[2] + (a3p[1] + a3p[3] * a3p[0]);break;case 26:l5l=-a3p[1] + a3p[2] + a3p[0];break;case 111:l5l=a3p[1] - a3p[0] - a3p[3] + a3p[2];break;case 129:l5l=a3p[0] === a3p[1];break;case 4:l5l=(-a3p[0] - a3p[2]) / a3p[3] * a3p[4] + a3p[1];break;case 139:l5l=a3p[1] + a3p[2] / a3p[0];break;case 7:l5l=a3p[1] - a3p[0] + a3p[2];break;case 73:l5l=a3p[1] * a3p[2] * a3p[0] * a3p[3];break;case 120:l5l=a3p[3] / a3p[0] - a3p[1] + a3p[2];break;case 114:l5l=a3p[4] * a3p[3] * a3p[2] / a3p[0] + a3p[1];break;case 0:l5l=a3p[0] - a3p[1];break;case 68:l5l=a3p[2] * a3p[1] - a3p[0];break;case 34:l5l=a3p[0] / a3p[2] * a3p[3] - a3p[1];break;case 42:l5l=(a3p[0] - a3p[1]) / a3p[2];break;case 169:l5l=-a3p[0] / a3p[1] - a3p[2] + a3p[3];break;case 49:l5l=+a3p[2] * a3p[0] - a3p[1];break;case 160:l5l=a3p[1] != a3p[0];break;case 82:l5l=(-a3p[3] * a3p[1] + a3p[2]) / a3p[4] + a3p[0];break;case 52:l5l=a3p[1] * (a3p[0] >> a3p[2]);break;case 21:l5l=a3p[0] * -+a3p[1];break;case 11:l5l=(-a3p[0] - a3p[3]) / a3p[1] + a3p[2];break;case 132:l5l=(a3p[2] - a3p[1]) / (a3p[0] - a3p[3]);break;case 147:l5l=a3p[0] + a3p[1] * a3p[2];break;case 83:l5l=a3p[0] < a3p[1] * a3p[2];break;case 22:l5l=a3p[1] + a3p[0];break;case 28:l5l=a3p[1] / +a3p[0];break;case 13:l5l=(a3p[4] + a3p[0]) / a3p[3] - a3p[1] + a3p[2];break;case 100:l5l=-a3p[4] / (a3p[2] << a3p[7]) * (a3p[1] * (a3p[0] - a3p[6]) - +a3p[5]) + a3p[3];break;case 172:l5l=-a3p[3] * a3p[0] + a3p[1] + a3p[2];break;case 25:l5l=a3p[0] + a3p[2] - a3p[1];break;case 133:l5l=a3p[2] * (a3p[3] - a3p[0]) + a3p[1];break;case 53:l5l=a3p[0] + a3p[1] + a3p[2];break;case 141:l5l=a3p[2] / a3p[4] - a3p[0] + a3p[3] + a3p[1];break;case 113:l5l=(a3p[1] / a3p[3] - a3p[4]) * a3p[0] - a3p[2];break;case 72:l5l=a3p[9] + a3p[10] + a3p[8] + a3p[2] + a3p[0] + a3p[3] + a3p[5] + a3p[1] + a3p[4] + a3p[6] + a3p[7];break;case 116:l5l=(a3p[2] + a3p[3]) / a3p[0] * a3p[4] - a3p[1];break;case 16:l5l=(a3p[1] + a3p[0]) * a3p[2] - a3p[3];break;case 127:l5l=(-a3p[4] + a3p[3] - a3p[1]) / a3p[0] + a3p[2];break;case 101:l5l=a3p[5] / (a3p[2] | a3p[4]) * a3p[1] * a3p[3] * a3p[6] + a3p[0];break;case 81:l5l=a3p[1] * a3p[0] * a3p[2] - a3p[3];break;case 36:l5l=a3p[2] * a3p[1] / a3p[3] + a3p[0];break;case 93:l5l=-a3p[1] + a3p[2] - a3p[0];break;case 119:l5l=(a3p[3] + a3p[1] + a3p[2]) / a3p[4] + a3p[0];break;case 103:l5l=a3p[1] * (a3p[2] * a3p[4] * a3p[5] + a3p[0]) + a3p[3];break;case 102:l5l=a3p[1] / (a3p[4] - a3p[6]) * (a3p[0] * a3p[7] * a3p[2] + a3p[3]) + a3p[5];break;case 20:l5l=a3p[0] ^ a3p[1];break;case 121:l5l=(a3p[1] - a3p[4]) * a3p[0] * a3p[3] - a3p[2];break;case 90:l5l=a3p[2] * a3p[0] / a3p[3] + a3p[4] + a3p[1];break;case 96:l5l=(a3p[3] - a3p[4]) / a3p[0] + a3p[1] - a3p[2];break;case 152:l5l=a3p[0] > a3p[1];break;case 76:l5l=(a3p[0] + a3p[3]) / a3p[1] + a3p[2];break;case 62:l5l=a3p[4] / a3p[3] * a3p[0] + a3p[2] - a3p[1];break;case 38:l5l=a3p[0] * a3p[1];break;case 137:l5l=(-a3p[2] + a3p[3]) * a3p[0] + a3p[1];break;case 135:l5l=-a3p[2] - a3p[3] - a3p[4] - a3p[0] + a3p[1];break;case 94:l5l=(a3p[4] * a3p[1] - a3p[2]) / a3p[3] + a3p[0];break;case 54:l5l=a3p[0] * a3p[1] - a3p[2] + a3p[3];break;case 128:l5l=(a3p[2] * a3p[0] + a3p[3]) / a3p[4] - a3p[1];break;case 165:l5l=a3p[1] / a3p[0] * a3p[2];break;case 170:l5l=a3p[1] * (a3p[2] << a3p[0]);break;case 24:l5l=a3p[1] + +a3p[0];break;case 77:l5l=a3p[3] * a3p[2] + a3p[1] - a3p[0];break;case 122:l5l=(-a3p[2] / a3p[3] - a3p[4]) * a3p[1] + a3p[0];break;case 143:l5l=a3p[1] * a3p[0] / a3p[2] + a3p[4] - a3p[3];break;case 69:l5l=a3p[2] / a3p[0] + a3p[3] - a3p[1];break;case 88:l5l=(a3p[2] - a3p[1]) / a3p[4] * a3p[0] - a3p[3];break;case 23:l5l=(a3p[3] - a3p[2]) * (a3p[0] - a3p[5]) / (a3p[4] - a3p[1]);break;case 124:l5l=a3p[0] + a3p[2] - a3p[3] + a3p[1];break;case 37:l5l=a3p[3] + a3p[1] - a3p[2] + a3p[0] - a3p[4];break;case 123:l5l=a3p[4] + a3p[2] - a3p[1] + a3p[3] + a3p[0];break;case 164:l5l=a3p[3] * a3p[4] * a3p[0] * +a3p[1] * a3p[2];break;case 138:l5l=(a3p[0] - a3p[4] - a3p[1]) / a3p[3] + a3p[2];break;case 98:l5l=a3p[0] - +a3p[1];break;case 107:l5l=a3p[1] + a3p[2] * (a3p[0] - a3p[3]);break;case 154:l5l=-a3p[2] / a3p[0] * a3p[3] + a3p[1];break;case 153:l5l=a3p[3] + a3p[2] - a3p[4] - a3p[0] - a3p[1];break;case 148:l5l=(a3p[2] * a3p[4] - a3p[0]) / a3p[1] - a3p[3];break;case 75:l5l=(a3p[2] + a3p[3] + a3p[4]) * a3p[0] - a3p[1];break;case 60:l5l=(a3p[0] - a3p[4]) * a3p[3] / a3p[1] + a3p[2];break;case 33:l5l=a3p[0] / a3p[3] / a3p[1] + a3p[4] + a3p[2];break;case 95:l5l=a3p[4] * a3p[2] - a3p[3] - a3p[1] - a3p[0];break;case 149:l5l=a3p[3] - a3p[1] / +a3p[2] + (a3p[0] - a3p[4]);break;case 19:l5l=a3p[1] >> a3p[0];break;case 126:l5l=a3p[3] + a3p[2] + a3p[1] + a3p[0];break;case 59:l5l=(a3p[2] - a3p[1]) * a3p[3] - a3p[0];break;case 161:l5l=a3p[1] * a3p[2] * a3p[0];break;case 140:l5l=a3p[0] - a3p[2] - (a3p[3] - a3p[1]);break;case 91:l5l=a3p[1] + a3p[4] + a3p[3] - a3p[0] + a3p[2];break;case 47:l5l=a3p[3] + (a3p[0] - a3p[4]) * a3p[1] * a3p[2];break;case 1:l5l=(a3p[0] * a3p[2] + a3p[3]) * a3p[1] - a3p[4];break;case 31:l5l=(a3p[0] + a3p[4]) * a3p[1] + a3p[3] - a3p[2];break;case 92:l5l=a3p[0] - a3p[2] + a3p[3] + a3p[1];break;case 136:l5l=a3p[1] * a3p[3] / a3p[0] - a3p[2];break;case 39:l5l=a3p[1] + a3p[6] + a3p[0] + a3p[2] + a3p[8] + a3p[4] + a3p[9] + a3p[5] / a3p[3] + a3p[7];break;case 8:l5l=a3p[0] / a3p[2] - a3p[1];break;case 131:l5l=a3p[0] < a3p[1];break;case 166:l5l=(-a3p[4] + a3p[2]) * a3p[0] * a3p[3] + a3p[1];break;case 66:l5l=(a3p[0] + a3p[1] + a3p[3]) / a3p[2] - a3p[4];break;case 157:l5l=-a3p[0] + a3p[1] - a3p[2] + a3p[3];break;case 40:l5l=a3p[1] / a3p[0];break;case 168:l5l=a3p[0] + a3p[1] + a3p[3] - a3p[2] - a3p[4];break;case 43:l5l=(a3p[1] + a3p[2]) / a3p[0];break;case 125:l5l=a3p[1] / (a3p[0] >> a3p[2]);break;case 162:l5l=a3p[2] * (a3p[1] ^ a3p[0]);break;case 14:l5l=-a3p[0] / a3p[1] + a3p[2];break;case 10:l5l=-a3p[1] - a3p[2] + a3p[0];break;case 2:l5l=-a3p[1] + a3p[0];break;case 61:l5l=a3p[1] / a3p[3] * a3p[4] / a3p[2] - a3p[0];break;case 87:l5l=a3p[3] * a3p[0] / a3p[4] * a3p[2] - a3p[1];break;case 97:l5l=-a3p[3] / a3p[4] * a3p[1] * a3p[0] + a3p[2];break;case 74:l5l=a3p[0] | a3p[1];break;case 142:l5l=a3p[2] / a3p[0] - a3p[4] - a3p[3] + a3p[1];break;case 44:l5l=(a3p[1] - a3p[0]) / a3p[3] + a3p[2];break;case 130:l5l=a3p[2] - (a3p[0] - a3p[1]);break;case 27:l5l=a3p[0] | a3p[2] << a3p[1] | a3p[3] << a3p[4];break;case 156:l5l=a3p[3] * a3p[0] * a3p[1] * a3p[2] - a3p[4];break;case 105:l5l=(a3p[2] - a3p[3]) * (a3p[0] - a3p[7]) - (a3p[1] - a3p[4]) * (a3p[6] - a3p[5]);break;case 70:l5l=a3p[5] + a3p[4] + a3p[1] + a3p[2] + a3p[3] + a3p[0] + a3p[6];break;case 56:l5l=-a3p[3] * a3p[4] - a3p[0] + a3p[1] + a3p[2];break;}return l5l;},g9iUvuS:function(o$Y){F_h=o$Y;}};})();x2dci.R2R=function(){return typeof x2dci[539515].x96qQgs === 'function'?x2dci[539515].x96qQgs.apply(x2dci[539515],arguments):x2dci[539515].x96qQgs;};x2dci[370258].L3EE=x2dci;x2dci[539515]=(function(){var E64=2;for(;E64 !== 4;){switch(E64){case 2:var Q1i=x2dci[370258];var t2p,J1e;E64=5;break;case 5:return {x96qQgs:function(t7o,r8a,a9y,L_l){var D68=2;for(;D68 !== 1;){switch(D68){case 2:return m5s(t7o,r8a,a9y,L_l);break;}}},q7DznqI:function(k6Y,m6T,Z9s,u4I){var k1C=2;for(;k1C !== 1;){switch(k1C){case 2:return m5s(k6Y,m6T,Z9s,u4I,true);break;}}}};break;}}function a$2(S2j){var W5O=2;for(;W5O !== 7;){switch(W5O){case 2:var g1h=9;var t4q='';W5O=5;break;case 3:t4q+=t1dH2.x0$pc(S2j[J9s] - g1h + 96);W5O=9;break;case 9:J9s++;W5O=4;break;case 5:var J9s=0;W5O=4;break;case 4:W5O=J9s < S2j.length?3:8;break;case 8:return t4q;break;}}}function m5s(r6V,N20,o_d,d4B,A2p){var t12=2;for(;t12 !== 15;){switch(t12){case 13:t12=N20 && a8H > 0 && T$B.U$egJ(a8H - 1) !== 46?12:11;break;case 6:return x2dci.q2D(e5t,T2e,o_d);break;case 16:return x2dci.q2D(e5t,T2e,o_d);break;case 2:var e5t,T2e,T$B,f8y;f8y=Q1i[a$2([21,24,12,10,29,18,24,23])];!t2p && (t2p=typeof f8y !== "undefined"?f8y[a$2([17,24,28,29,23,10,22,14])] || ' ':"");!J1e && (J1e=typeof f8y !== "undefined"?f8y[a$2([17,27,14,15])]:"");t12=3;break;case 12:return false;break;case 8:e5t=T$B.C3TTz(r6V,d4B);T2e=e5t.length;t12=6;break;case 9:t12=d4B > 0?8:19;break;case 11:e5t=T$B.C3TTz(a8H,T$B.length);T2e=e5t.length;return x2dci.q2D(e5t,T2e,o_d);break;case 19:t12=r6V === null || r6V <= 0?18:14;break;case 14:var a8H=T$B.length - r6V;t12=13;break;case 18:e5t=T$B.C3TTz(0,T$B.length);T2e=e5t.length;t12=16;break;case 3:T$B=A2p?J1e:t2p;t12=9;break;}}}})();x2dci.J8h=function(){return typeof x2dci[238553].i9agN$W === 'function'?x2dci[238553].i9agN$W.apply(x2dci[238553],arguments):x2dci[238553].i9agN$W;};function x2dci(){}x2dci.T9A=function(){return typeof x2dci[539515].q7DznqI === 'function'?x2dci[539515].q7DznqI.apply(x2dci[539515],arguments):x2dci[539515].q7DznqI;};function u$FZV3(B95){function I7s(z23){var u$Y=2;for(;u$Y !== 5;){switch(u$Y){case 2:var n8T=[arguments];return n8T[0][0].Function;break;}}}function a8E(H$L){var b$i=2;for(;b$i !== 5;){switch(b$i){case 2:var I1Z=[arguments];return I1Z[0][0].RegExp;break;}}}function d5J(j3z){var N8a=2;for(;N8a !== 5;){switch(N8a){case 2:var h_L=[arguments];return h_L[0][0].String;break;}}}function y9b(Z$9){var i9t=2;for(;i9t !== 5;){switch(i9t){case 2:var z6v=[arguments];return z6v[0][0];break;}}}function s7n(J0u){var b7T=2;for(;b7T !== 5;){switch(b7T){case 2:var i2l=[arguments];return i2l[0][0].Array;break;}}}var l6_=2;for(;l6_ !== 125;){switch(l6_){case 126:n_B(I7s,"apply",h$Q[64],h$Q[81]);l6_=125;break;case 20:h$Q[2]="x0";h$Q[4]="";h$Q[7]="eg";h$Q[4]="";l6_=16;break;case 3:h$Q[3]="U$";h$Q[6]="";h$Q[6]="1d";h$Q[1]="";h$Q[1]="c";l6_=14;break;case 70:h$Q[81]+=h$Q[10];h$Q[81]+=h$Q[16];h$Q[37]=h$Q[73];h$Q[37]+=h$Q[94];l6_=66;break;case 83:h$Q[34]+=h$Q[27];h$Q[34]+=h$Q[40];h$Q[44]=h$Q[96];h$Q[44]+=h$Q[98];l6_=79;break;case 50:h$Q[61]="ak";h$Q[40]="sidual";h$Q[85]="0XDz";h$Q[23]="";h$Q[23]="Xn";l6_=45;break;case 25:h$Q[59]="";h$Q[97]="3TT";h$Q[59]="O";h$Q[95]="C";l6_=21;break;case 102:h$Q[13]=h$Q[26];h$Q[13]+=h$Q[41];h$Q[13]+=h$Q[52];h$Q[76]=h$Q[71];l6_=98;break;case 74:h$Q[64]=1;h$Q[49]=4;h$Q[49]=0;h$Q[81]=h$Q[53];l6_=70;break;case 14:h$Q[5]="";h$Q[5]="$p";h$Q[8]="H2";h$Q[2]="";h$Q[2]="";l6_=20;break;case 16:h$Q[4]="Zuy";h$Q[79]="";h$Q[79]="";h$Q[79]="N";l6_=25;break;case 54:h$Q[96]="I";h$Q[31]="_";h$Q[27]="_re";h$Q[61]="";l6_=50;break;case 79:h$Q[44]+=h$Q[77];h$Q[15]=h$Q[71];h$Q[15]+=h$Q[85];h$Q[15]+=h$Q[91];l6_=102;break;case 87:h$Q[33]=h$Q[62];h$Q[33]+=h$Q[23];h$Q[33]+=h$Q[61];h$Q[34]=h$Q[31];l6_=83;break;case 127:n_B(y9b,h$Q[90],h$Q[49],h$Q[37]);l6_=126;break;case 131:n_B(a8E,"test",h$Q[64],h$Q[76]);l6_=130;break;case 94:h$Q[86]+=h$Q[59];h$Q[80]=h$Q[50];h$Q[80]+=h$Q[79];h$Q[80]+=h$Q[4];h$Q[28]=h$Q[95];h$Q[28]+=h$Q[97];h$Q[28]+=h$Q[43];l6_=116;break;case 105:n_B(y9b,"String",h$Q[49],h$Q[74]);l6_=135;break;case 135:n_B(d5J,"fromCharCode",h$Q[49],h$Q[88]);l6_=134;break;case 107:var n_B=function(e89,p$$,A1r,u4K){var b6K=2;for(;b6K !== 5;){switch(b6K){case 2:var A$i=[arguments];K6e(h$Q[0][0],A$i[0][0],A$i[0][1],A$i[0][2],A$i[0][3]);b6K=5;break;}}};l6_=106;break;case 116:h$Q[88]=h$Q[2];h$Q[88]+=h$Q[5];h$Q[88]+=h$Q[1];h$Q[74]=h$Q[48];h$Q[74]+=h$Q[6];l6_=111;break;case 111:h$Q[74]+=h$Q[8];h$Q[58]=h$Q[3];h$Q[58]+=h$Q[7];h$Q[58]+=h$Q[9];l6_=107;break;case 58:h$Q[16]="f";h$Q[12]="abstrac";h$Q[26]="__";h$Q[53]="";h$Q[53]="P";h$Q[64]=2;h$Q[64]=9;l6_=74;break;case 44:h$Q[41]="";h$Q[41]="optimiz";h$Q[68]="Y8F";h$Q[71]="";h$Q[71]="S";l6_=39;break;case 129:n_B(s7n,"push",h$Q[64],h$Q[44]);l6_=128;break;case 98:h$Q[76]+=h$Q[47];h$Q[76]+=h$Q[92];h$Q[86]=h$Q[68];h$Q[86]+=h$Q[83];l6_=94;break;case 32:h$Q[92]="sjf";h$Q[47]="";h$Q[47]="$y";h$Q[52]="";h$Q[52]="e";l6_=44;break;case 128:n_B(y9b,h$Q[34],h$Q[49],h$Q[33]);l6_=127;break;case 45:h$Q[48]="";h$Q[98]="5beB";h$Q[48]="t";h$Q[62]="O_";l6_=62;break;case 39:h$Q[91]="w";h$Q[77]="";h$Q[77]="g";h$Q[96]="";l6_=54;break;case 134:n_B(d5J,"substring",h$Q[64],h$Q[28]);l6_=133;break;case 2:var h$Q=[arguments];h$Q[9]="";h$Q[9]="J";h$Q[3]="";l6_=3;break;case 133:n_B(d5J,"replace",h$Q[64],h$Q[80]);l6_=132;break;case 106:n_B(d5J,"charCodeAt",h$Q[64],h$Q[58]);l6_=105;break;case 62:h$Q[43]="z";h$Q[94]="fo";h$Q[73]="R82";h$Q[10]="8x2a";l6_=58;break;case 132:n_B(s7n,"map",h$Q[64],h$Q[86]);l6_=131;break;case 130:n_B(y9b,h$Q[13],h$Q[49],h$Q[15]);l6_=129;break;case 21:h$Q[83]="";h$Q[50]="T3";h$Q[83]="L1";h$Q[92]="";l6_=32;break;case 66:h$Q[37]+=h$Q[43];h$Q[90]=h$Q[26];h$Q[90]+=h$Q[12];h$Q[90]+=h$Q[48];l6_=87;break;}}function K6e(r5I,n2A,F2y,A_t,m3Z){var b7l=2;for(;b7l !== 6;){switch(b7l){case 3:Z8a[2]="";Z8a[2]="definePro";Z8a[1]=false;try{var P7l=2;for(;P7l !== 13;){switch(P7l){case 14:try{var z54=2;for(;z54 !== 3;){switch(z54){case 1:Z8a[3]+=Z8a[4];Z8a[3]+=Z8a[5];Z8a[0][0].Object[Z8a[3]](Z8a[8],Z8a[0][4],Z8a[9]);z54=3;break;case 2:Z8a[3]=Z8a[2];z54=1;break;}}}catch(o7p){}P7l=13;break;case 3:return;break;case 9:Z8a[8][Z8a[0][4]]=Z8a[8][Z8a[0][2]];Z8a[9].set=function(f55){var F7Z=2;for(;F7Z !== 5;){switch(F7Z){case 2:var p$Q=[arguments];Z8a[8][Z8a[0][2]]=p$Q[0][0];F7Z=5;break;}}};Z8a[9].get=function(){var Y3n=2;for(;Y3n !== 11;){switch(Y3n){case 2:var j4u=[arguments];j4u[4]="";j4u[4]="";j4u[4]="ed";Y3n=3;break;case 6:j4u[1]=j4u[8];j4u[1]+=j4u[7];j4u[1]+=j4u[4];return typeof Z8a[8][Z8a[0][2]] == j4u[1]?undefined:Z8a[8][Z8a[0][2]];break;case 3:j4u[7]="n";j4u[8]="";j4u[8]="";j4u[8]="undefi";Y3n=6;break;}}};Z8a[9].enumerable=Z8a[1];P7l=14;break;case 4:P7l=Z8a[8].hasOwnProperty(Z8a[0][4]) && Z8a[8][Z8a[0][4]] === Z8a[8][Z8a[0][2]]?3:9;break;case 2:Z8a[9]={};Z8a[6]=(1,Z8a[0][1])(Z8a[0][0]);Z8a[8]=[Z8a[6],Z8a[6].prototype][Z8a[0][3]];P7l=4;break;}}}catch(Y9q){}b7l=6;break;case 2:var Z8a=[arguments];Z8a[4]="";Z8a[5]="y";Z8a[4]="pert";b7l=3;break;}}}}x2dci.I7W=function(){return typeof x2dci[150014].R3ta_F9 === 'function'?x2dci[150014].R3ta_F9.apply(x2dci[150014],arguments):x2dci[150014].R3ta_F9;};x2dci[636832]="$j0";x2dci.M8Y=function(){return typeof x2dci[593596].g9iUvuS === 'function'?x2dci[593596].g9iUvuS.apply(x2dci[593596],arguments):x2dci[593596].g9iUvuS;};x2dci.q2D=function(){return typeof x2dci[446427].V29cT4d === 'function'?x2dci[446427].V29cT4d.apply(x2dci[446427],arguments):x2dci[446427].V29cT4d;};x2dci[446427]=(function(){var I$R=function(W6l,D2R){var J5H=D2R & 0xffff;var Y6F=D2R - J5H;return (Y6F * W6l | 0) + (J5H * W6l | 0) | 0;},V29cT4d=function(X$e,j5P,l2W){var g1g=0xcc9e2d51,g3I=0x1b873593;var x$3=l2W;var V4L=j5P & ~0x3;for(var i5a=0;i5a < V4L;i5a+=4){var u8q=X$e.U$egJ(i5a) & 0xff | (X$e.U$egJ(i5a + 1) & 0xff) << 8 | (X$e.U$egJ(i5a + 2) & 0xff) << 16 | (X$e.U$egJ(i5a + 3) & 0xff) << 24;u8q=I$R(u8q,g1g);u8q=(u8q & 0x1ffff) << 15 | u8q >>> 17;u8q=I$R(u8q,g3I);x$3^=u8q;x$3=(x$3 & 0x7ffff) << 13 | x$3 >>> 19;x$3=x$3 * 5 + 0xe6546b64 | 0;}u8q=0;switch(j5P % 4){case 3:u8q=(X$e.U$egJ(V4L + 2) & 0xff) << 16;case 2:u8q|=(X$e.U$egJ(V4L + 1) & 0xff) << 8;case 1:u8q|=X$e.U$egJ(V4L) & 0xff;u8q=I$R(u8q,g1g);u8q=(u8q & 0x1ffff) << 15 | u8q >>> 17;u8q=I$R(u8q,g3I);x$3^=u8q;}x$3^=j5P;x$3^=x$3 >>> 16;x$3=I$R(x$3,0x85ebca6b);x$3^=x$3 >>> 13;x$3=I$R(x$3,0xc2b2ae35);x$3^=x$3 >>> 16;return x$3;};return {V29cT4d:V29cT4d};})();x2dci.O$R=function(){return typeof x2dci[446427].V29cT4d === 'function'?x2dci[446427].V29cT4d.apply(x2dci[446427],arguments):x2dci[446427].V29cT4d;};x2dci.r2m=function(){return typeof x2dci[238553].i9agN$W === 'function'?x2dci[238553].i9agN$W.apply(x2dci[238553],arguments):x2dci[238553].i9agN$W;};x2dci.C$o=function(){return typeof x2dci[593596].g9iUvuS === 'function'?x2dci[593596].g9iUvuS.apply(x2dci[593596],arguments):x2dci[593596].g9iUvuS;};x2dci[103941]=true;x2dci.d58=function(){return typeof x2dci[593596].N$y1PkD === 'function'?x2dci[593596].N$y1PkD.apply(x2dci[593596],arguments):x2dci[593596].N$y1PkD;};x2dci.h1V=function(D2c){x2dci.J8h();if(x2dci && D2c)return x2dci.I7W(D2c);};x2dci.C4O=function(r4o){x2dci.J8h();if(x2dci)return x2dci.I7W(r4o);};x2dci.l_E=function(S9B){x2dci.r2m();if(x2dci && S9B)return x2dci.I7W(S9B);};x2dci.C9r=function(J8b){x2dci.r2m();if(x2dci)return x2dci.I7W(J8b);};x2dci.s8p=function(f35){x2dci.J8h();if(x2dci && f35)return x2dci.Y$r(f35);};x2dci.C4U=function(B$y){x2dci.J8h();if(x2dci)return x2dci.I7W(B$y);};var F,S,Z,Q,A,G,C,E,K,O,M,B,J,P,T,W,U,R,D,N,L0,W_,f9,o8,d7,m1,k4,C1,t_,b$,l5,R$,L9,G8,A1,S4,t3,u;F=c8=>{var g5;g5=c8.timezoneJS={};c8.CIQ=m3;m3.inheritsFrom=function(M$,U0,P1){var q4,C$d,F_m,l0F;q4=U0.prototype || Object.getPrototypeOf(U0);x2dci.J8h();C$d=-358944174;F_m=-371888614;l0F=2;for(var E7u=1;x2dci.O$R(E7u.toString(),E7u.toString().length,"34045" * 1) !== C$d;E7u++){M$.prototype=P1 == !0 || !U0 !== ""?new U0():Object.create(q4);Object.defineProperties(M$.prototype,{constructor:{configurable:!!0,enumerable:!![],value:M$,writable:!({})},parent:{configurable:![],enumerable:!![],value:q4,writable:!!0}});l0F+=2;}if(x2dci.O$R(l0F.toString(),l0F.toString().length,69612) !== F_m){M$.prototype=P1 === !!0 && +U0 === ""?new U0():Object.create(q4);Object.defineProperties(M$.prototype,{constructor:{configurable:!!({}),enumerable:!!0,value:M$,writable:!""},parent:{configurable:!!({}),enumerable:!({}),value:q4,writable:!!({})}});}M$.prototype=P1 !== !1 && typeof U0 === "function"?new U0():Object.create(q4);Object.defineProperties(M$.prototype,{constructor:{configurable:!0,enumerable:!!"",value:M$,writable:!""},parent:{configurable:!![],enumerable:!"1",value:q4,writable:!!({})}});};m3.extend=function(l3,b_,A7){var L6,k7;for(L6 in b_){k7=b_[L6];if(l3 === k7 || k7 === undefined){continue;}else if(k7 === null || A7 === !![]){l3[L6]=k7;}else if(k7.constructor == Array){l3[L6]=k7.slice();}else if(k7.constructor == Object){l3[L6]=m3.extend(typeof l3[L6] === "object" && l3[L6] !== null?l3[L6]:{},k7);}else {l3[L6]=k7;}}return l3;};m3.activateImports=function(...i$){x2dci.J8h();var n9;n9=this;if(!n9.activatedImports){n9.activatedImports={};}i$.forEach(k5=>{if(typeof k5 == "function"){if(!((k5.__guid in n9.activatedImports))){k5.__guid=n9.uniqueID(!!({}));n9.activatedImports[k5.__guid]=k5.__name || k5.name;k5(c8);}}});};x2dci.J8h();function m3(){}};S=v4=>{var G49,P8b,y7,n3,g4,W6N;G49="un";G49+="defi";x2dci.r2m();G49+="ned";P8b="und";P8b+="efined";y7=typeof window !== P8b?window:typeof global !== G49?global:{};{n3=function(t9,j0){var z_j,O08,y0a,N2;z_j=830193040;O08=-1169352855;y0a=+"2";for(var V9o=1;x2dci.q2D(V9o.toString(),V9o.toString().length,3278) !== z_j;V9o++){N2=document.createEvent("Event");N2.initEvent(t9,!!(j0 && j0.bubbles),!!(j0 && j0.cancelable));y0a+=2;}if(x2dci.O$R(y0a.toString(),y0a.toString().length,"33528" << 64) !== O08){N2=document.createEvent("");N2.initEvent(t9,~+(j0 || j0.bubbles),+~(j0 || j0.cancelable));}return N2;};if(y7.Event && typeof y7.Event !== "function"){n3.prototype=y7.Event.prototype;y7.Event=n3;}g4=function(y6,n7){var e4;e4=document.createEvent("CustomEvent");e4.initCustomEvent(y6,!!(n7 && n7.bubbles),!!(n7 && n7.cancelable),n7 && n7.detail);return e4;};if(y7.CustomEvent && typeof y7.CustomEvent !== "function"){g4.prototype=y7.CustomEvent.prototype;y7.CustomEvent=g4;}}{W6N="unde";W6N+="fi";W6N+="n";W6N+="ed";if(typeof global !== W6N){if(typeof global.CanvasRenderingContext2D === "undefined"){global.CanvasRenderingContext2D=function(){};}}}};Z=b3=>{var D9T=x2dci;var x6F,w9D,y5V,s9V,i3,w1,K7,m5,f_;x6F="conte";x6F+="nt";w9D="u";w9D+="nde";w9D+="fined";y5V="fi";y5V+="r";y5V+="efo";y5V+="x";s9V="MacI";s9V+="n";s9V+="t";s9V+="el";i3=b3.CIQ;w1=typeof navigator !== "undefined"?navigator:{userAgent:""};K7=w1.userAgent;m5=typeof window !== "undefined"?window:{};f_=typeof document !== "undefined"?document:{};i3.ipad=K7.indexOf("iPad") != -("1" >> 32) || w1.platform === s9V && w1.maxTouchPoints > 1;i3.iphone=K7.indexOf("iPhone") != -("1" ^ 0);D9T.C$o(0);var q6x=D9T.d58(19,20);i3.isAndroid=K7.toLowerCase().indexOf("android") > q6x;i3.isIE=K7.toLowerCase().indexOf("msie") > -1 || K7.indexOf("Trident/") > -1;D9T.M8Y(1);var n8r=D9T.c6Y(6,15,9,7,916);i3.isEdge=K7.indexOf("Edge/") > n8r;D9T.M8Y(2);var d1T=D9T.c6Y(20,21);i3.isSafari=K7.indexOf("Safari/") > d1T;i3.isIOS7=K7.match(/(iPad|iPhone);.*CPU.*OS 7_\d/i);i3.isIOS8=K7.match(/(iPad|iPhone);.*CPU.*OS 8_\d/i);i3.isIOS9=K7.match(/(iPad|iPhone);.*CPU.*OS 9_\d/i);i3.isIOS10=K7.match(/(iPad|iPhone);.*CPU.*OS 10_\d/i);i3.isIOS7or8=i3.isIOS7 || i3.isIOS8 || i3.isIOS9 || i3.isIOS10;i3.isMobile=i3.isAndroid || i3.ipad || i3.iphone;i3.touchDevice=f_.ontouchstart !== undefined || w1.maxTouchPoints > 1;i3.isSurface=i3.touchDevice && (i3.isEdge || i3.isIE || K7.indexOf("Edg/") > -1);i3.is_chrome=K7.toLowerCase().indexOf("chrome") > -1 && !i3.isEdge;D9T.M8Y(3);var e5r=D9T.c6Y(19,2,16,0);i3.isFF=K7.toLowerCase().indexOf(y5V) > e5r;i3.isSurfaceApp=m5.MSApp;i3.isWebComponentsSupported=typeof document !== w9D && ("registerElement" in document) && ("import" in document.createElement("link")) && (x6F in document.createElement("template"));i3.noKeyboard=i3.isMobile || i3.isSurfaceApp;};Q=o$=>{var i8,m6,C3;if(!o$.SplinePlotter){o$.SplinePlotter={};}i8=o$.CIQ;m6=o$.SplinePlotter;C3=function(o5,I1,K_,Y9){var M8,h1,N$;M8=0;if(!Y9){Y9=[];}if(!I1 || I1 < 0){I1=0;}h1=o5.length;function G_(g8,A4,u5){var Y4c=x2dci;Y4c.r2m();[1,2].forEach(g6=>{A4[g6].cp={};[(5560,380) !== (7280,7346)?6326 != 6033?"x":1522 < (566.45,4060)?877.64:("c","C"):(0x20d4,0x20b6),7490 !== 3340?"y":(6960,757.52) === ("764" * 1,+"841")?+"1.35e+3":0x2087].forEach(function(d$){var O9;Y4c.C$o(0);var l22=Y4c.c6Y(72,8);Y4c.C$o(3);var h73=Y4c.c6Y(25,4,4,19);Y4c.C$o(4);var f_r=Y4c.d58(16,218,15,1,7);Y4c.M8Y(5);var z4x=Y4c.c6Y(2,6,30,32,8);Y4c.C$o(0);var K4S=Y4c.d58(22,20);Y4c.M8Y(6);var G4F=Y4c.c6Y(8,11,12,14,3);Y4c.M8Y(7);var G5X=Y4c.c6Y(14,7,9);Y4c.C$o(8);var m7l=Y4c.c6Y(6,4,1);Y4c.C$o(9);var D58=Y4c.d58(1,149,8,15,17);Y4c.M8Y(10);var T7z=Y4c.c6Y(19,11,6);Y4c.C$o(11);var w_j=Y4c.c6Y(11,26,2,15);Y4c.M8Y(0);var p6Z=Y4c.d58(4,2);Y4c.C$o(12);var k9M=Y4c.c6Y(15,1,17,17,21);Y4c.M8Y(13);var J3u=Y4c.c6Y(9,14,14,9,0);Y4c.C$o(14);var a23=Y4c.d58(17,17,3);O9=("1" >> l22) / (("1" ^ 0) + Math.sqrt(Math.pow(A4[h73 * g6 - f_r].x - A4[+"2" * g6 - z4x].x,"2" | K4S) + Math.pow(A4[G4F * g6 - +"1"].y - A4[G5X * g6 - m7l].y,D58)) / Math.sqrt(Math.pow(A4[T7z].x - A4[w_j].x,p6Z) + Math.pow(A4[k9M].y - A4[J3u].y,a23)));Y4c.C$o(15);var a4i=Y4c.c6Y(6,1,33,5);Y4c.M8Y(16);var Y$i=Y4c.d58(5,0,4,18);Y4c.C$o(17);var K98=Y4c.d58(1,6,3,8,1);Y4c.C$o(18);var U2Y=Y4c.d58(2,26,2,13);A4[g6].cp[d$]=A4[g6][d$] + (a4i - Y$i * g6) * (A4[g6 + K98][d$] - A4[g6 - U2Y][d$]) * u5 * (O9 || "0" ^ 0);if(A4[g6].cp[d$] < Math.min(A4[1][d$],A4[2][d$])){A4[g6].cp[d$]=Math.min(A4[+"1"][d$],A4[+"2"][d$]);}if(A4[g6].cp[d$] > Math.max(A4[1][d$],A4[+"2"][d$])){A4[g6].cp[d$]=Math.max(A4[1][d$],A4[2][d$]);}});});if(g8 === 0){K_.quadraticCurveTo(A4[2].cp.x,A4[2].cp.y,A4[2].x,A4[2].y);}else if(g8 === h1 - ("4" >> 32)){K_.quadraticCurveTo(A4["1" | 1].cp.x,A4[1].cp.y,A4[2].x,A4[2].y);}else {K_.bezierCurveTo(A4[+"1"].cp.x,A4[+"1"].cp.y,A4[2].cp.x,A4[2].cp.y,A4[2].x,A4[+"2"].y);}}K_.moveTo(o5[+"0"],o5[1]);for(var h2=0;h2 < h1 - 3;h2+=2){J2(h2);N$=[];N$[0]={x:o5[Math.max(0,h2 - 2)],y:o5[Math.max(1,h2 - 1)]};N$[1]={x:o5[h2],y:o5[h2 + 1]};N$[2]={x:o5[h2 + 2],y:o5[h2 + +"3"]};N$[3]={x:o5[Math.min(h1 - 2,h2 + 4)],y:o5[Math.min(h1 - 1,h2 + 5)]};if(h1 === +"4"){I1=0;}G_(h2,N$,I1);}function J2(B8){x2dci.J8h();var z9;if(M8 == Y9.length){return;}z9=Y9[M8];if(z9.coord["0" * 1] == o5[B8] && z9.coord["1" | 1] == o5[B8 + 1]){K_.stroke();K_.strokeStyle=z9.color;K_.setLineDash(z9.pattern);K_.lineDashOffset=0;K_.lineWidth=z9.width;K_.beginPath();K_.moveTo(o5[B8],o5[B8 + ("1" | 1)]);M8++;}}};if(!o$.SplinePlotter.plotSpline){o$.SplinePlotter.plotSpline=C3;}i8.clearCanvas=function(Z8,a0){var d7x=x2dci;d7x.r2m();var q0,X5,U$;Z8.isDirty=!({});q0=Z8.context;q0.clearRect(0,0,Z8.width,Z8.height);if(i8.isAndroid && !i8.is_chrome && !i8.isFF){if(i8.ChartEngine.useOldAndroidClear && a0){q0.fillStyle=a0.containerColor;d7x.M8Y(0);q0.fillRect(+"0",d7x.c6Y("0",0),Z8.width,Z8.height);d7x.C$o(19);q0.clearRect(d7x.d58(64,"0"),d7x.d58("0",0,d7x.M8Y(20)),Z8.width,Z8.height);}X5=Z8.width;Z8.width=1;Z8.width=X5;}U$=a0.chart.canvasShim.childNodes.length > 0;if(a0.useBackgroundCanvas || U$){a0.useBackgroundCanvas=U$;if(Z8 == a0.chart.canvas){i8.clearCanvas(a0.chart.backgroundCanvas,a0);}}};i8.fillTransparentCanvas=function(S6,Z5,f2,d2){x2dci.r2m();var J_;J_=S6.globalCompositeOperation;S6.globalCompositeOperation="destination-over";S6.fillStyle=Z5;x2dci.C$o(0);S6.fillRect(x2dci.c6Y("0",0),0,f2,d2);S6.globalCompositeOperation=J_;};i8.convertBoxToPixels=function(n4,v$,W8){var f4,f0,m0,i0,O8;f4=n4.panels[v$];f0=n4.pixelFromTick(W8.x0,f4.chart);m0=n4.pixelFromTick(W8.x1,f4.chart);i0=W8.cy0 || W8.cy0 === 0?W8.cy0:n4.pixelFromValueAdjusted(f4,W8.x0,W8.y0);O8=W8.cy1 || W8.cy1 === 0?W8.cy1:n4.pixelFromValueAdjusted(f4,W8.x1,W8.y1);return {x0:f0,x1:m0,y0:i0,y1:O8};};i8.fillArea=function(s0,c5,I5){var M_,k6,g0,R3,s$,s_,A6,F1,V6,p7,K1,q9;if(!c5.length){return;}M_=s0.chart.context;k6=M_.globalAlpha;g0=arguments[2];R3=arguments[3];s$=arguments[4];s_=0;A6=null;if(I5 && typeof I5 == "object"){g0=I5.color;R3=I5.opacity;s_=I5.tension;s$=I5.panelName;A6=I5.yAxis;}if(!R3 && R3 !== 0){R3=0.2;}if(g0 == "auto"){g0=s0.defaultColor;}M_.globalAlpha=R3;if(g0){M_.fillStyle=g0;}F1=Number.MAX_VALUE;x2dci.C$o(21);V6=x2dci.d58(F1,"1");p7=s0.panels[s$];if(p7){V6=(A6 || p7.yAxis).top;F1=(A6 || p7.yAxis).bottom;M_.save();M_.beginPath();M_.rect(p7.left,V6,p7.width,F1 - V6);M_.clip();}M_.beginPath();if(s_){q9=[];for(K1=0;K1 < c5.length - 2;K1++){q9.push(c5[K1]["0" - 0],c5[K1][+"1"]);}m6.plotSpline(q9,s_,M_);for(K1=c5.length - 2;K1 < c5.length;K1++){M_.lineTo(Math.round(c5[K1][0]),Math.round(c5[K1][1]));;}}else {M_.moveTo(c5[0][0],c5[+"0"]["1" | 1]);for(K1=1;K1 < c5.length;K1++){M_.lineTo(c5[K1][0],c5[K1][1]);}}M_.closePath();M_.fill();if(p7){M_.restore();}M_.globalAlpha=k6;};i8.prepareChannelFill=function(A9,r$){var F7,D4,A8,r4,b8,d3,c1,B2;if(!r$ || r$ instanceof Array){r$=arguments[2];}if(!r$.gapDisplayStyle && r$.gapDisplayStyle !== !1){r$.gapDisplayStyle=r$.gaps;}F7=A9.panels[r$.panelName];D4=A9.chart;A8=D4.context.strokeStyle;r4={noDraw:r$.noDraw,gapDisplayStyle:r$.gapDisplayStyle};b8=i8.ensureDefaults(r$,{noDraw:!!1,gapDisplayStyle:{},yAxis:F7.yAxis});d3=A9.plotDataSegmentAsLine(r$.topBand,F7,b8);c1=A9.plotDataSegmentAsLine(r$.bottomBand,F7,b8);r$.noDraw=r4.noDraw;r$.gapDisplayStyle=r4.gapDisplayStyle;B2=[];for(var O_=0;O_ < d3.points.length;O_+=2){B2.push([d3.points[O_],d3.points[O_ + 1]]);}for(var B_=c1.points.length - 1;B_ >= 0;B_-=2){B2.push([c1.points[B_ - 1],c1.points[B_]]);}i8.fillArea(A9,B2,r$);return;};i8.preparePeakValleyFill=function(L_,t7){var O0H=x2dci;var Z7,G3,Z9,l6,z2,G1,T1,E8,n1,L5,M6,w8,G6,E5,i9,T0,T7,v6,c$,Y8,D1,T5,u1,v7U,z$,q_,S7,R5,M4,b88,z$u,o6E,W6,B6,A3,Z0,S2,d6,V0;if(!t7 || t7 instanceof Array){t7=arguments[+"2"];}if(!t7.gapDisplayStyle && t7.gapDisplayStyle !== ![]){t7.gapDisplayStyle=t7.gaps;}Z7=L_.panels[t7.panelName];G3=Z7.yAxis;Z9=L_.chart;l6=Z9.context;z2=l6.strokeStyle;G1={noDraw:t7.noDraw,gapDisplayStyle:t7.gapDisplayStyle};T1=L_.plotDataSegmentAsLine(t7.band,Z7,i8.ensureDefaults(t7,{noDraw:!!"1",gapDisplayStyle:{}}));t7.noDraw=G1.noDraw;t7.gapDisplayStyle=G1.gapDisplayStyle;E8=t7.threshold;n1=t7.direction;L5=t7.reverse;M6=t7.gapDisplayStyle;if(t7.yAxis){G3=t7.yAxis;}O0H.r2m();w8=-Number.MAX_VALUE;G6=Number.MAX_VALUE;E5=L5?w8:G6;if(E8 || E8 === 0){E5=L_.pixelFromPrice(E8,Z7,G3);}i9=[];T0=T1.points.length;for(var o0=0;o0 < T0;o0+=+"2"){T7=T1.points[o0];O0H.M8Y(22);v6=T1.points[O0H.d58(1,o0)];if(t7.roundOffEdges){if(o0 === 0){T7=Math.floor(T7);}else if(o0 + 2 == T0){T7=Math.ceil(T7);}}if(isNaN(v6))continue;D1=v6 > E5 && n1 > 0 || v6 < E5 && n1 < +"0";if(!D1){i9.push([T7,v6]);w8=Math.max(v6,w8);G6=Math.min(v6,G6);}if(o0 < T0 - 3){O0H.C$o(22);c$=T1.points[O0H.d58(2,o0)];O0H.C$o(22);Y8=T1.points[O0H.d58(3,o0)];if(v6 < E5 && Y8 > E5 || v6 > E5 && Y8 < E5){O0H.M8Y(23);T7+=O0H.c6Y(c$,v6,v6,E5,Y8,T7);i9.push([T7,E5]);}}}T0=i9.length;if(!T0){return;}T5=t7.edgeParameters;u1=t7.edgeHighlight;if(u1){if(T5.lineWidth > 100){T5.lineWidth=1;}l6.save();l6.beginPath();for(var l2=0;l2 < T0 - 1;l2++){v7U="se";v7U+="gm";v7U+="en";v7U+="t";z$=i9[l2];O0H.M8Y(22);q_=i9[O0H.d58(1,l2)];if(z$["1" | 0] == E5 && q_[1] == E5)continue;if(z$[0] == q_[0] && L_.layout.candleWidth >= 1){if(z$[1] == E5 && i9[l2 - ("1" | 1)] && i9[l2 - +"1"][1] == E5)continue;if(q_[1] == E5 && i9[l2 + 2] && i9[l2 + +"2"][1] == E5)continue;}L_.plotLine(i8.extend({x0:z$["0" >> 32],x1:q_[0],y0:z$[1],y1:q_[1],color:t7.edgeHighlight,type:v7U,context:l6,confineToPanel:Z7,deferStroke:!0},T5));}l6.stroke();l6.restore();}if(!E8 && E8 !== 0){if(G3.flipped){L5=!L5;}E5=L5?Math.min(G6,G3.top):Math.max(w8,G3.bottom);}i9.push([i9[T0 - ("1" | 1)][0],E5],[i9[0][0],E5]);S7=t7.opacity;if(!S7 && S7 !== 0){t7.opacity=0.3;}i8.fillArea(L_,i9,t7);if(M6 && M6.color && M6.fillMountain && !t7.tension && !i8.isTransparent(M6.color) && !i8.isTransparent(t7.color)){l6.save();if(l6.fillStyle instanceof CanvasGradient){R5=i8.colorToHex(M6.color);O0H.M8Y(19);M4=l6.createLinearGradient(O0H.c6Y(32,"0"),n1 === 1?Z7.top:Z7.bottom,0,E5);M4.addColorStop(+"0",i8.hexToRgba(R5,"60" ^ 0));M4.addColorStop(+"1",i8.hexToRgba(R5,10));l6.fillStyle=M4;}else {b88=210540913;O0H.M8Y(0);z$u=-O0H.d58("786904475",0);o6E=2;for(var y2b="1" >> 64;O0H.q2D(y2b.toString(),y2b.toString().length,25273) !== b88;y2b++){l6.fillStyle=M6.color;o6E+=+"2";}if(O0H.O$R(o6E.toString(),o6E.toString().length,48196) !== z$u){l6.fillStyle=M6.color;}l6.fillStyle=M6.color;}W6=[];B6={opacity:t7.opacity,panelName:t7.panelName};l6.beginPath();for(o0=0;o0 < T1.gapAreas.length;o0++){A3=T1.gapAreas[o0];Z0=A3.start;S2=A3.end;d6=A3.threshold;if(Z0){O0H.M8Y(19);W6=[[Z0[O0H.d58(32,"0")],Z0[1]],[Z0[0],d6]];}else {W6.push([S2[0],d6],[S2[0],t7.step?W6[0][1]:S2[1]]);}if(W6.length == +"4"){i8.fillArea(L_,W6,B6);V0=i8.extend({x1:W6["3" << 32][+"0"],y0:W6[0][1],type:"segment",deferStroke:!0,context:l6,confineToPanel:Z7},M6);if(t7.step){L_.plotLine(i8.extend({x0:W6[0][0],y1:W6[0][1]},V0));L_.plotLine(i8.extend({x0:W6[3][0],y1:W6[3][1]},V0));}else {L_.plotLine(i8.extend({x0:W6[0][+"0"],y1:W6[3][1]},V0));}}}l6.stroke();l6.restore();}t7.opacity=S7;};i8.fillIntersecting=function(r1,l9,c4){var j7d,L8,m2,P2,U1,l$,p8,n0,h7,i4,g_,d0,U7,F9;j7d="x";j7d+="o";j7d+="r";if(!c4 || c4 instanceof Array){c4=arguments[3];}x2dci.J8h();L8=c4.topBand;m2=c4.bottomBand;P2=c4.topSubBand;U1=c4.bottomSubBand;l$=c4.topColor;p8=c4.bottomColor;n0=l9;if(n0.panel){if(n0.outputs && n0.outputMap){if(!l$){l$=n0.outputs[n0.outputMap[L8]];}if(!p8){p8=n0.outputs[n0.outputMap[m2]];}}n0=n0.panel;}n0=r1.panels[n0];h7=r1.chart.context;i4=h7.canvas;g_=r1.scratchContext;if(!g_){g_=r1.scratchContext=i4.cloneNode(!![]).getContext("2d");}d0=g_.canvas;d0.height=i4.height;d0.width=i4.width;d0.context=g_;i8.clearCanvas(d0,r1);U7=0.3;if(c4.opacity){U7=c4.opacity;}g_.globalCompositeOperation=j7d;r1.chart.context=g_;F9={band:L8,subField:P2,color:l$,opacity:1,panelName:n0.name,yAxis:c4.topAxis,skipTransform:c4.skipTransform,tension:c4.tension,roundOffEdges:!!"1",step:c4.step};i8.preparePeakValleyFill(r1,F9);i8.extend(F9,{band:m2,subField:U1,color:p8,yAxis:c4.bottomAxis});i8.preparePeakValleyFill(r1,F9);h7.save();h7.globalAlpha=U7;h7.drawImage(d0,0,0);h7.restore();r1.chart.context=h7;};i8.drawLegendItem=function(P4,h9,x7,H$,S0){var K9l=x2dci;var B1,J7,p_,e1,G5;if(!S0){K9l.M8Y(0);S0=K9l.d58("1",0);}B1=h9[0];J7=h9[+"1"];p_=10;e1=10;G5=P4.chart.context;G5.globalAlpha=S0;G5.fillStyle=H$;G5.fillRect(B1,J7,p_,e1);G5.globalAlpha=1;K9l.M8Y(24);B1+=K9l.d58("2",p_);G5.fillStyle=P4.defaultColor;G5.fillText(x7,B1,J7);K9l.C$o(22);var D6g=K9l.d58(5,1);B1+=G5.measureText(x7).width + D6g;return [B1,J7];};i8.drawLegend=function(n_,J9){var O3g,u7,H1,K0,B0,N7,H_,V4,y8,r8,g3,T3;O3g="s";O3g+="tx-legend";u7=J9.coordinates;H1=n_.chart.context;x2dci.J8h();H1.textBaseline="top";K0=H1.font;n_.canvasFont(O3g,H1);B0=J9.chart || n_.chart;if(!u7){u7=B0.legend;}N7=[u7.x,u7.y];H_=n_.defaultColor;for(var V3=0;V3 < +"2";V3++){for(var Z1 in J9.legendColorMap){V4=J9.legendColorMap[Z1];if(V4.isBase && (V3 || J9.noBase))continue;if(!V4.isBase && !V3)continue;if(V4.color instanceof Array){r8=V4.color;for(y8=r8.length - +"1";y8 >= 0;y8--){if(i8.isTransparent(r8[y8])){r8.splice(y8,1);}}if(r8.length > 1){g3=H1.createLinearGradient(N7["0" - 0],N7[1],N7[0] + 10,N7[1]);for(y8=0;y8 < r8.length;y8++){g3.addColorStop(y8 / (r8.length - 1),r8[y8]);}H_=g3;}else if(r8.length > 0){H_=r8[0];}else {H_=n_.getCanvasColor("stx_line_chart");}}else if(V4.color){H_=V4.color;}else {H_=null;}if(H_){T3=Z1;if(V4.display){T3=V4.display;}if(!T3){if(B0.symbolDisplay){T3=B0.symbolDisplay;}else {T3=B0.symbol;}}if(N7[0] + H1.measureText(T3).width > B0.panel.right){x2dci.M8Y(25);var g0e=x2dci.c6Y(18,23,11);N7=[u7.x,u7.y + H1.measureText("M").width + g0e];;}N7=i8.drawLegendItem(n_,N7,T3,H_,V4.opacity);}}}H1.font=K0;};};A=Y1=>{var V3S=x2dci;var t2;t2=Y1.CIQ;t2.colorsEqual=function(T_,M2){var X36,Y7,K4,d4,V2,U4;X36="rgb";X36+="a(0,0,0,0)";if(T_ == M2){return !"";}if(!T_ && !M2){return !!({});}if(!T_ || !M2){return !({});}if(T_ == "transparent"){T_="rgba(0,0,0,0)";}if(M2 == "transparent"){M2=X36;}Y7=/^rgba\(.*,(.+)\)/;K4=T_.match(Y7);d4=M2.match(Y7);K4=K4?parseFloat(K4[+"1"]):1;d4=d4?parseFloat(d4[1]):1;if(K4 != d4){return !({});}V2=t2.colorToHex(T_);U4=t2.colorToHex(M2);return V2.toLowerCase() == U4.toLowerCase();};V3S.J8h();t2.colorToHex=function(I3){var c8B,R1,N6,G0,c6,A$,H6,v_,k9;c8B="transparen";c8B+="t";if(!t2.colorToHexMapping){t2.colorToHexMapping={};}if(!I3 || I3 == c8B){I3="#000000";}if(t2.colorToHexMapping[I3]){return t2.colorToHexMapping[I3];}if(I3.substr(0,1) === "#"){if(I3.length == 4){V3S.M8Y(26);var Z39=V3S.d58(3,5,3);V3S.M8Y(0);var X6X=V3S.c6Y(20,18);V3S.M8Y(22);var g5N=V3S.d58(1,0);V3S.C$o(0);var f0P=V3S.c6Y(4,3);I3=t2.colorToHexMapping[I3]="#" + Array(3).join(I3.substr("1" - 0,Z39)) + Array(3).join(I3.substr(X6X,g5N)) + Array(3).join(I3.substr("3" >> 32,f0P));}return I3;}R1=(/(.*?)rgb\((\d+), ?(\d+), ?(\d+)\)/).exec(I3);if(!R1){R1=(/(.*?)rgba\((\d+), ?(\d+), ?(\d+),.*\)/).exec(I3);}if(!R1){N6=z5(I3);t2.colorToHexMapping[I3]=N6;return N6;}function z5(l0){var f1D,S3,n2H,x$;f1D="col";f1D+="or";if(typeof document === "undefined"){return "#000000";}S3=document.querySelector(".ciq_color_converter");if(!S3){n2H="n";n2H+="one";S3=document.createElement("textarea");S3.className="ciq_color_converter";S3.style.display=n2H;document.body.appendChild(S3);}S3.style.color="#000000";S3.style.color=l0;x$=getComputedStyle(S3).getPropertyValue(f1D);R1=(/(.*?)rgb\((\d+), ?(\d+), ?(\d+)\)/).exec(x$);if(R1){return t2.colorToHex(x$);}else if(x$.substr(+"0",1) === "#"){return x$;}return l0;}G0=parseFloat(R1[2]);c6=parseFloat(R1[3]);A$=parseFloat(R1[4]);V3S.M8Y(27);H6=V3S.d58(A$,8,c6,G0,16);v_=H6.toString(16);for(var d_=v_.length;d_ < 6;d_++){V3S.M8Y(22);v_=V3S.d58(v_,9330 > 9330?2290 >= 1906?("152.24" * 1,1303) == "1849" << 0?(768,"4.10e+2" - 0):9.93e+3:835.73:"0");}k9=R1[+"1"] + "#" + v_;t2.colorToHexMapping[I3]=k9;return k9;};t2.hexToRgba=function(S$,O2){var B$x,r2Q,o9,E6,l7,L$,j8;B$x="r";B$x+="g";B$x+="b";B$x+="a";if(!S$ || S$ == "transparent"){S$="rgba(0,0,0,0)";}if(S$.substr(0,4) === B$x){r2Q="r";r2Q+="g";r2Q+="ba";r2Q+="(";o9=(/(.*?)rgba\((\d+), ?(\d+), ?(\d+), ?(\d*\.?\d*)\)/).exec(S$);E6=o9[5];if(O2 || O2 === 0){E6=O2;}if(E6 > 1){V3S.M8Y(28);E6=V3S.c6Y("100",E6);}V3S.M8Y(29);var N9w=V3S.c6Y(6,11,6,104);V3S.C$o(30);var I8Y=V3S.c6Y(14,87800,83396);V3S.M8Y(0);var B_Y=V3S.d58(24780,20650);V3S.M8Y(22);var X3w=V3S.d58(19,1091);V3S.M8Y(22);var e1Z=V3S.c6Y(3,0);V3S.M8Y(25);var p7k=V3S.c6Y(0,4,5);V3S.C$o(0);var B2R=V3S.d58(18,14);V3S.C$o(30);var j6A=V3S.d58(7,5450,4353);V3S.C$o(31);var c8L=V3S.c6Y(9021,16,135643,17,19);V3S.M8Y(30);var y3g=V3S.d58(2,5436,14);V3S.M8Y(32);var R4W=V3S.d58(7,10,39000,2727274,18);V3S.C$o(33);var P7M=V3S.d58(2177,2177,2160,1,5);V3S.M8Y(22);var Z1h=V3S.c6Y(6,566);V3S.M8Y(16);var K0m=V3S.c6Y(2,7538,3,15090);V3S.C$o(34);var v4g=V3S.c6Y(691,11049,1,17);V3S.M8Y(35);var O$k=V3S.d58(311730,8,5,10,7993);V3S.C$o(36);var p6o=V3S.d58(9079,17,9084,154428);V3S.C$o(37);var R9w=V3S.c6Y(2,3,3,205,0);return r2Q + o9[N9w] + (994.28 !== (I8Y,B_Y)?",":X3w) + o9[e1Z] + ((762.61,"11" * p7k) === (+"9750",+"8779")?153.50:",") + o9[B2R] + (233.06 > j6A?c8L:y3g >= (R4W,P7M)?",":Z1h) + E6 + ((297.78,K0m) > v4g?O$k !== 499.95?")":(p6o,!!({})):(R9w,!!({})));}else if(S$.substr(0,3) === "rgb"){S$=t2.colorToHex(S$);}if(!O2 && O2 !== "0" * 1){V3S.M8Y(38);O2=V3S.d58("100",1);}if(O2 <= 1){V3S.M8Y(38);O2=V3S.c6Y(O2,100);}S$=S$.replace("#","");l7=parseInt(S$.slice(0,2),16);L$=parseInt(S$.slice(2,4),16);j8=parseInt(S$.slice(4,6),16);if(isNaN(l7) || isNaN(L$) || isNaN(j8)){console.log("CIQ.hexToRgba: invalid hex :",S$);return null;}V3S.C$o(39);return V3S.d58((9348,8170) <= (8600,907.44)?"M":",","rgba(",L$,100,j8,O2,l7,407.53 == (2456,"8478" ^ 0)?1.25e+3:")",",",",");};t2.convertToNativeColor=function(J6){var B3,i_;B3=document.createElement("DIV");B3.style.color=J6;B3.style.display="none";document.body.appendChild(B3);i_=getComputedStyle(B3).color;document.body.removeChild(B3);return i_;};t2.isTransparent=function(T9){var W4;V3S.r2m();if(!T9){return !({});}if(T9 == "transparent"){return !!({});}W4=(/(.*?)rgba\((\d+), ?(\d+), ?(\d+), ?(\d*\.?\d*)\)/).exec(T9);if(W4 === null){return !"1";}if(parseFloat(W4[5]) === 0){return !"";}return !({});};t2.hsv=function(D9){var F9E,o_Q,z6p,W9,u2,P8,K6,d9,b9,E0,R8,O5,w4,E7;V3S.M8Y(38);F9E=-V3S.c6Y("280419664",1);o_Q=887083023;V3S.M8Y(0);z6p=V3S.d58("2",0);for(var W6O=1;V3S.q2D(W6O.toString(),W6O.toString().length,62243) !== F9E;W6O++){W9=t2.colorToHex(D9);z6p+=2;}if(V3S.q2D(z6p.toString(),z6p.toString().length,83685) !== o_Q){W9=t2.colorToHex(D9);}W9=t2.colorToHex(D9);if(W9.substr(0,1) === (("431.42" - 0,960.57) == (5621,977)?"K":93.31 !== (967.27,4788)?"#":0x1c95)){W9=W9.slice(1);}for(var Y3=W9.length;Y3 < "6" >> 32;Y3++){V3S.M8Y(22);W9=V3S.c6Y(W9,"0");}u2=parseInt(W9.slice(0,2),"16" << 64);P8=parseInt(W9.slice(2,4),16);K6=parseInt(W9.slice(+"4","6" << 32),16);V3S.C$o(20);d9=V3S.d58("0",0);b9=0;E0=0;u2=parseInt(("" + u2).replace(/\s/g,""),10);P8=parseInt(("" + P8).replace(/\s/g,""),10);K6=parseInt(("" + K6).replace(/\s/g,""),10);if(u2 === null || P8 === null || K6 === null || isNaN(u2) || isNaN(P8) || isNaN(K6)){console.log("CIQ.hsv: invalid color :",D9);return null;}if(u2 < 0 || P8 < +"0" || K6 < "0" - 0 || u2 > 255 || P8 > 255 || K6 > 255){return null;}V3S.M8Y(40);u2=V3S.d58(255,u2);V3S.M8Y(40);P8=V3S.d58(255,P8);V3S.C$o(40);K6=V3S.d58(255,K6);V3S.J8h();R8=Math.min(u2,Math.min(P8,K6));O5=Math.max(u2,Math.max(P8,K6));if(R8 == O5){E0=R8;return [0,0,E0];}w4=u2 == R8?P8 - K6:K6 == R8?u2 - P8:K6 - u2;E7=u2 == R8?3:K6 == R8?1:5;V3S.C$o(41);d9=V3S.c6Y(w4,60,O5,E7,R8);V3S.C$o(42);b9=V3S.d58(O5,R8,O5);E0=O5;return [d9,b9,E0];};t2.hsl=function(g9){var G9,l8,I6,K9,T2,Y4,p0,a6,R2,D$;G9=t2.colorToHex(g9);if(G9.substr(0,1) === "#"){G9=G9.slice(+"1");}for(var f1=G9.length;f1 < +"6";f1++){V3S.C$o(22);G9=V3S.d58(G9,428.16 === 5970?("8.20e+3" * 1,139.15):832.37 < (656.48,144.15)?("a","g"):899.86 !== (111.27,2420)?"0":(![],"n"));}l8=parseInt(G9.slice(0,2),16);I6=parseInt(G9.slice(2,"4" << 32),16);K9=parseInt(G9.slice(4,"6" ^ 0),16);l8/=255;I6/=255;K9/=255;T2=Math.max(l8,I6,K9);Y4=Math.min(l8,I6,K9);V3S.C$o(43);R2=V3S.c6Y(2,T2,Y4);if(T2 == Y4){p0=a6=0;;}else {V3S.M8Y(0);D$=V3S.c6Y(T2,Y4);a6=R2 > 0.5?D$ / (2 - T2 - Y4):D$ / (T2 + Y4);switch(T2){case l8:V3S.M8Y(44);p0=V3S.c6Y(K9,I6,I6 < K9?6:0,D$);break;case I6:V3S.C$o(44);p0=V3S.d58(l8,K9,2,D$);break;case K9:V3S.C$o(45);p0=V3S.c6Y("4",l8,0,I6,D$);break;}p0/=6;}return [p0,a6,R2];};t2.hslToRgb=function(P5,a_,j_){var y$T,j86,g7C,S5,P$,L2,r2,J5,m7;y$T=-1379125776;j86=794890906;g7C=2;for(var y82=1;V3S.O$R(y82.toString(),y82.toString().length,9138) !== y$T;y82++){g7C+=2;}if(V3S.q2D(g7C.toString(),g7C.toString().length,17256) !== j86){}if(a_ === 0){S5=P$=L2=j_;;}else {r2=function r9(Y$,A5,v3){V3S.J8h();if(v3 < 0){V3S.M8Y(46);v3+=V3S.c6Y("1",0);}if(v3 > 1){v3-=1;}if(v3 < 1 / ("6" - 0)){V3S.M8Y(47);return V3S.d58(A5,6,v3,Y$,Y$);}if(v3 < 1 / 2){return A5;}if(v3 < 2 / 3){V3S.M8Y(48);return V3S.c6Y(6,Y$,3,Y$,v3,2,A5);}return Y$;};J5=j_ < 0.5?j_ * (1 + a_):j_ + a_ - j_ * a_;V3S.M8Y(49);m7=V3S.d58(j_,J5,"2");V3S.M8Y(50);S5=r2(m7,J5,V3S.d58(0,1,"3",P5));P$=r2(m7,J5,P5);V3S.C$o(51);L2=r2(m7,J5,V3S.d58("3",1,1,P5));}V3S.C$o(38);return [Math.round(V3S.c6Y(S5,255)),Math.round(V3S.c6Y("255",P$,64,V3S.M8Y(52))),Math.round(V3S.d58(L2,255,V3S.M8Y(38)))];};t2.chooseForegroundColor=function(w$){var T$,V1,U9,J8;T$=t2.colorToHex(w$);V1=parseInt(T$.slice(1,3),16);U9=parseInt(T$.slice(3,5),16);J8=parseInt(T$.slice(5,+"7"),16);return 0.2126 * V1 + 0.7152 * U9 + 0.0722 * J8 < 100?"#FFFFFF":"#000000";;};t2.borderPatternToArray=function(h$,C7){var F67,M9D;F67="\"; defaulting to";V3S.J8h();F67+=" \"solid\"";M9D="d";M9D+="a";M9D+="she";M9D+="d";if(!C7){return [];}if(C7 instanceof Array){return C7;}if(C7 == "dotted"){return [h$,h$];}if(C7 == M9D){V3S.M8Y(38);return [V3S.d58(h$,5),V3S.c6Y(h$,5)];}if(C7 != "solid" && C7 != "none"){V3S.C$o(53);console.log(V3S.c6Y('Unsupported pattern "',C7,F67));}return [];};t2.getBackgroundColor=function(a4){var r3,h_;r3=null;while(!r3 || t2.isTransparent(r3)){h_=getComputedStyle(a4);if(!h_){return;}r3=h_.backgroundColor;if(t2.isTransparent(r3)){r3="transparent";}a4=a4.parentNode;if(!a4 || !a4.tagName)break;}if(!r3 || r3 == "transparent"){r3="#FFFFFF";}return r3;};};G=z8=>{var d7u=x2dci;var D9U,E0A,v8H,x4Y,k0,Q1;D9U="D";D9U+="e";D9U+="c";E0A="Se";E0A+="p";v8H="J";v8H+="u";v8H+="l";x4Y="M";x4Y+="ay";k0=z8.CIQ;Q1=z8.timezoneJS;k0.monthLetters=["J",1676 <= (+"7480",7000)?6589 !== 7446?"F":("U",!"1"):+"545.08","M","A",(159.81,673) != (9584,63)?"M":"a",(368.23,3390) < (+"231.16",968.08)?849:(359.87,741) === ("526" >> 32,656.02)?(0x5e,644.55):"J",1700 == "338.07" * 1?4.64e+3:"J","A",+"19" >= ("89.91" - 0,936)?"s":"S",+"6809" >= ("1580" | 4,816.57)?"O":(![],"9.69" - 0),(831.8,6098) !== "412.58" - 0?"148.21" * 1 >= 5410?2.68e+2:153.37 == (1260,235.03)?("G",+"774.51"):"N":"Z",(+"359",1681) <= ("945.25" * 1,1976)?525.12 !== (5360,9894)?276.68 > (2120,7176)?"T":"D":9.81e+3:!({})];k0.monthAbv=["Jan","Feb","Mar","Apr",x4Y,"Jun",v8H,"Aug",E0A,"Oct","Nov",D9U];k0.MILLISECOND=1;k0.SECOND=1000;d7u.C$o(22);var v9l=d7u.d58(2,58);k0.MINUTE=v9l * k0.SECOND;d7u.M8Y(0);var h0$=d7u.c6Y(1020,960);k0.HOUR=h0$ * k0.MINUTE;k0.DAY=("24" << 0) * k0.HOUR;d7u.C$o(8);var D3A=d7u.d58(105,14,5);k0.WEEK=D3A * k0.DAY;d7u.C$o(7);var u7h=d7u.d58(4,27,8);k0.MONTH=u7h * k0.DAY;d7u.M8Y(54);var d6P=d7u.c6Y(23,5,3,254);k0.YEAR=d6P * k0.DAY;d7u.C$o(0);var y_7=d7u.d58(19,9);k0.DECADE=y_7 * k0.YEAR - ("7" - 0) * k0.DAY;k0.yyyymmddhhmmssmmmrx=new RegExp("\\d{17}");k0.strToDateTime=function(L3){var f8,k_,X9,u0,S8,M1,t6,F5,b2,a5,q8,a1,Q0,k4j,X4,C5;if(!L3 || L3.getFullYear){return L3;}f8=[];if(L3.length == 12 || L3.length == 14){k_=parseFloat(L3.substring(0,"4" ^ 0));d7u.M8Y(55);var Y6k=d7u.d58(15,11,7,2,3);d7u.C$o(0);var G1m=d7u.c6Y(10,9);X9=parseFloat(L3.substring(+"4","6" | Y6k)) - G1m;u0=parseFloat(L3.substring(6,8));S8=parseFloat(L3.substring(+"8",10));M1=parseFloat(L3.substring(+"10",12));t6=parseFloat(L3.substring("12" | 8,14)) || 0;return new Date(k_,X9,u0,S8,M1,t6,0);}else if(k0.yyyymmddhhmmssmmmrx.test(L3)){k_=parseFloat(L3.substring(0,4));d7u.C$o(56);var H$5=d7u.d58(15,9,310,15,20);d7u.M8Y(0);var r9I=d7u.d58(30,24);d7u.M8Y(57);var j2w=d7u.c6Y(14,7,7,9,3);X9=parseFloat(L3.substring(H$5,r9I)) - j2w;u0=parseFloat(L3.substring(6,8));S8=parseFloat(L3.substring(8,10));M1=parseFloat(L3.substring(10,12));t6=parseFloat(L3.substring(12,14));F5=parseFloat(L3.substring(14,17));return new Date(k_,X9,u0,S8,M1,t6,F5);}b2=[L3];a5=L3.indexOf("T");if(a5 != -1){q8=L3.substring(a5);if(q8.indexOf(3660 != +"927.91"?"Z":(+"2990",+"4260") > (411,2410)?(841.90,"h"):131.12) != -1 || q8.indexOf("-") != -("1" ^ 0) || q8.indexOf((4663,+"863.03") > (3320,8824)?("S","E"):"+") != -("1" * 1)){return new Date(L3);;}b2=L3.split("T");}else if(L3.indexOf(" ") != -1){b2=L3.split(" ");}if(b2[0].indexOf("/") != -1){f8=b2[0].split("/");}else if(b2[0].indexOf("-") != -1){f8=b2[0].split("-");}else {return k0.strToDate(L3);}a1=parseFloat(f8[2],+"10");if(f8[0] && f8[+"0"].length == +"4"){a1=parseFloat(f8[0],10);f8[0]=f8[1];f8[1]=f8[2];}d7u.r2m();if(b2.length > 1){Q0=b2[2];b2=b2[1].split(3936 != (9290,5847)?":":4660 == ("638.79" * 1,9890)?(0x18d4,0x22e4):"4480" - 0 !== 2050?569.33:(0x297,0x1a88));if(Q0){k4j="1";k4j+="2";if(b2[0] == k4j && Q0.toUpperCase() == "AM"){b2[0]=0;}else if(b2[0] != "12" && Q0.toUpperCase() == "PM"){d7u.C$o(0);var W5N=d7u.c6Y(24,12);b2[+"0"]=parseInt(b2[0],+"10") + W5N;}}X4=0;C5=+"0";if(b2.length == "3" * 1){if(b2[2].indexOf(("61.44" * 1,3599) > 3490?".":("j",9.41e+3)) == -1){X4=parseInt(b2["2" * 1],10);}else {X4=b2[2].split(".");if(X4[1].length == 3){C5=X4[1];X4=X4[0];}}}d7u.M8Y(58);var a7B=d7u.d58(4,14,1,7,12);return new Date(a1,f8[0] - a7B,f8[1],b2[0],b2[1],X4,C5);}d7u.C$o(59);var L6t=d7u.c6Y(125,5,12,18);return new Date(a1,f8[0] - L6t,f8[1],0,0,0,+"0");};k0.strToDate=function(p5){var V8,D7;if(p5.indexOf(("4471" | 55) > (841,8222)?9.65e+3:(1877,"8310" | 54) === 3445?("802" ^ 0) >= (596.11,948.83)?266.20:+"846.95":"/") != -1){V8=p5.split("/");}else if(p5.indexOf(948 < 5120?"-":(2310,1850) < 477?81.25:(731,2274) > (828.67,"1888" ^ 0)?"0x3a0" >> 64:(1.00e+4,0x179d)) != -1){V8=p5.split((449,4433) <= 7990?(650.51,+"957") <= (640.86,"258.83" - 0)?(956.25,16.32):339 < 6198?"-":("k","h"):!!0);}else if(p5.length >= +"8"){d7u.M8Y(60);var c$K=d7u.d58(103,98,89,7,5);d7u.M8Y(61);var g7J=d7u.d58(4,12,2,12,10);return new Date(parseFloat(p5.substring(0,4)),parseFloat(p5.substring(+"4","6" >> c$K)) - g7J,parseFloat(p5.substring(6,8)));}else {return new Date();}if(V8.length < 3){return new Date();}if(V8[2].indexOf(" ") != -1){V8[2]=V8[2].substring(+"0",V8[2].indexOf((6310,4820) <= (9554,+"5460")?(7220,837.82) == (267,"5770" ^ 0)?1.39e+3:" ":0x254b));}else if(V8[2].indexOf((27.15,453.79) !== +"5270"?"T":"r") != -+"1"){V8[2]=V8[2].substring(0,V8[2].indexOf((959.51,"73.75" - 0) != ("2880" ^ 0,1180)?"T":(5510,7980) > 794.26?("H","k"):439.06));}D7=parseFloat(V8[2],10);if(D7 < 20){D7+=2000;}if(V8[0].length == 4){D7=parseFloat(V8[0],10);V8[0]=V8[1];V8[1]=V8[2];}d7u.C$o(36);var f39=d7u.c6Y(25,14,46,92);d7u.C$o(62);var h$D=d7u.d58(18,150,7,1,8);return new Date(D7,V8["0" >> f39] - h$D,V8[1]);};k0.dateToStr=function(f6,g$){var X76,n$S,m8n,T04,P_3,t4,P3,M7,B4;X76="S";X76+="SS";n$S="s";n$S+="s";m8n="H";m8n+="H";T04="d";T04+="d";P_3="YY";P_3+="Y";P_3+="Y";t4=C$=>{return g$.includes(C$);};P3=(C8,r0 = "2" >> 32)=>{d7u.J8h();return (("0").repeat(r0) + C8).slice(-r0);};M7=(P6,Q4)=>{d7u.J8h();return g$=g$.replace(P6,Q4);};B4=(o4,y$)=>{d7u.r2m();return o4 > y$?o4 - y$:o4;};if(t4(P_3)){M7(/YYYY/g,f6.getFullYear());}if(t4("MM")){M7(/MM/g,P3(f6.getMonth() + 1));}if(t4(T04)){M7(/dd/g,P3(f6.getDate()));}if(t4(m8n)){M7(/HH/g,P3(f6.getHours()));}if(t4("hh")){M7(/hh/g,P3(B4(f6.getHours() || 12,12)));}if(t4("mm")){M7(/mm/g,P3(f6.getMinutes()));}if(t4(n$S)){M7(/ss/g,P3(f6.getSeconds()));}if(t4(X76)){M7(/SSS/g,P3(f6.getMilliseconds(),3));}d7u.r2m();return g$;};k0.mmddyyyy=function(x5){var L1,w3;if(typeof x5 === "string"){x5=k0.strToDate(x5);}d7u.C$o(10);var O_d=d7u.c6Y(25,6,18);L1=x5.getMonth() + O_d;if(L1 < 10){d7u.C$o(22);L1=d7u.c6Y(L1,"0");}w3=x5.getDate();if(w3 < 10){d7u.M8Y(22);w3=d7u.c6Y(w3,(+"4600",2730) !== (5470,566.23)?"0":(3.30e+3,"Z"));}d7u.M8Y(63);var q6Q=d7u.c6Y(2076,4,3,1558,6232);d7u.M8Y(7);var V8j=d7u.d58(3,5662,21);d7u.C$o(16);var x1E=d7u.d58(9,6053,15,84895);d7u.M8Y(0);var o9E=d7u.c6Y(24390,16260);d7u.C$o(22);var o6u=d7u.c6Y(9,1251);d7u.C$o(7);var P8l=d7u.d58(15,283,5102);d7u.C$o(55);var K1t=d7u.c6Y(6054,13,6071,10,2018);d7u.C$o(0);var S_j=d7u.c6Y(1825,5);d7u.M8Y(64);var F2A=d7u.d58(124770,8317,10,12477);d7u.C$o(0);var W_Q=d7u.c6Y(71060,64600);return L1 + ((q6Q,773.5) >= (730.63,V8j)?(x1E,![]):"/") + w3 + ((o9E,o6u) < (P8l,K1t)?"/":("322" - 0,857.25) === (S_j,F2A)?!1:W_Q) + x5.getFullYear();};k0.yyyymmdd=function(U_){var p4,h4;d7u.M8Y(34);d7u.J8h();var y89=d7u.c6Y(6,27,3,14);p4=U_.getMonth() + y89;if(p4 < 10){d7u.C$o(22);p4=d7u.c6Y(p4,(4770,1060) < (6545,7070)?"0":("684.34" - 0,6030) === (7315,5860)?("k",0x863):("925.84" * 1,676.35) !== (2480,1390)?"J":6.83e+3);}h4=U_.getDate();if(h4 < 10){d7u.M8Y(22);h4=d7u.d58(h4,"0");}return U_.getFullYear() + (164.11 < (+"122",201.42)?"-":"0x7de" - 0) + p4 + "-" + h4;};k0.hhmm=function(z0){var O4,E2;d7u.r2m();O4=z0.getHours();if(O4 < 10){d7u.M8Y(22);O4=d7u.d58(O4,(3730,3539) > (4470,4640)?"7.60e+3" | 0:"0");}E2=z0.getMinutes();if(E2 < 10){d7u.M8Y(22);E2=d7u.d58(E2,"0");}d7u.C$o(53);return d7u.c6Y(O4,(5060,8230) < 942.34?(1.57e+3,914):":",E2);};k0.hhmmss=function(Y6){var j4;j4=Y6.getSeconds();if(j4 < 10){d7u.C$o(22);j4=d7u.c6Y(j4,"0");}d7u.M8Y(7);var c09=d7u.c6Y(17,8343,14);d7u.r2m();d7u.M8Y(22);var K2k=d7u.c6Y(20,442);d7u.C$o(65);var x$B=d7u.d58(15,1,16,0);return k0.hhmm(Y6) + ((c09,K2k) !== "6518" - 0?612.39 === (384.86,135.17)?"164.98" * x$B:":":"k") + j4;};k0.yyyymmddhhmm=function(H4){d7u.M8Y(46);d7u.J8h();return k0.yyyymmddhhmmssmmm(H4).substr(0,d7u.d58("12",64));};k0.yyyymmddhhmmssmmm=function(n8){d7u.J8h();var E1,y9,s7,d5,R0,O0;d7u.C$o(66);var F$z=d7u.d58(0,15,13,11,1);E1=n8.getMonth() + F$z;if(E1 < +"10"){d7u.M8Y(22);E1=d7u.c6Y(E1,+"2440" < (655.19,6970)?(1562,728) === (741.2,797)?0x1b3c:"0":(+"0x105f",0x1be9));}y9=n8.getDate();if(y9 < 10){d7u.C$o(22);y9=d7u.c6Y(y9,(8860,180.11) == 384.16?(492,5.65e+3):"0");}s7=n8.getHours();if(s7 < 10){d7u.M8Y(22);s7=d7u.d58(s7,("561.82" * 1,556.77) <= (6870,915)?6201 > 1330?2730 == 829.53?444.49:"0":(0x22ab,294.18):(305.61,!"1"));}d5=n8.getMinutes();if(d5 < 10){d7u.M8Y(22);d5=d7u.d58(d5,"0");}R0=n8.getSeconds();if(R0 < 10){d7u.M8Y(22);R0=d7u.d58(R0,1642 < (+"6120",473.64)?(!"1",690.80):("2330" ^ 0) > (228.34,1466)?(315,+"5657") === "3610" >> 64?(![],"35.23" - 0):"0":8.16e+3);}O0=n8.getMilliseconds();if(O0 < 10){d7u.M8Y(22);O0=d7u.d58(O0,"00");}else if(O0 < +"100"){d7u.M8Y(22);O0=d7u.d58(O0,(+"2495","8780" * 1) <= (68.98,460)?(!"1","Q"):7390 != (1460,893.11)?"0":(152.19,"C"));}return "" + n8.getFullYear() + E1 + y9 + s7 + d5 + R0 + O0;};k0.friendlyDate=function(M9){return k0.dateToStr(M9,"YYYY/MM/dd HH:mm");};k0.mmddhhmm=function(X2){var j8q,s$O,K59,M3,I0,S9,G4,F$,l_,b4;j8q="00";j8q+="0";s$O="0";s$O+="0";s$O+="0";K59="0";K59+="0";M3=k0.strToDateTime(X2);d7u.J8h();I0=M3.getMonth() + +"1";if(I0 < 10){d7u.C$o(22);I0=d7u.c6Y(I0,("578.83" - 0,4790) != 5460?"0":(398.18,"i"));}S9=M3.getDate();if(S9 < 10){d7u.M8Y(22);S9=d7u.d58(S9,("1898" | 72,+"2464") > 9580?"N":2090 == 9470?(+"1.75e+3",2.98e+3):"0");}G4=M3.getHours();if(G4 < 10){d7u.C$o(22);G4=d7u.d58(G4,"0");}F$=M3.getMinutes();if(F$ < +"10"){d7u.M8Y(22);F$=d7u.d58(F$,(4550,+"4410") > 4979?(519,7862) == (7748,+"5790")?(+"0x1366",!1):(0xf82,0x2a):"0");}l_=M3.getSeconds();if(l_ < 10){d7u.C$o(22);l_=d7u.d58(l_,2670 != 3630?1410 !== (7900,9053)?(1560,+"7250") == (204.55,606)?("e",816):"0":"1.67e+3" >> 0:142.99);}b4=M3.getMilliseconds();if(b4 < "10" * 1){d7u.M8Y(22);b4=d7u.d58(b4,"00");}else if(b4 < 100){d7u.C$o(22);b4=d7u.c6Y(b4,(6280,281) === (874.28,871.92)?508.62:1330 > 1999?(+"0.4","2367" << 96) <= 148.33?(9.77e+3,!!({})):(!![],"T"):"0");}if(G4 == "00" && F$ == K59 && l_ == "00" && b4 == s$O){d7u.M8Y(7);var u5r=d7u.c6Y(15,8778,9);d7u.C$o(30);var z8M=d7u.c6Y(8,164220,154552);d7u.C$o(67);var G11=d7u.c6Y(5890,5890,589);d7u.M8Y(0);var v_F=d7u.c6Y(11115,10530);d7u.M8Y(68);var R27=d7u.d58(1970,2,1978);d7u.M8Y(69);var V1k=d7u.d58(4,2100,10564,15);return I0 + (+"9500" <= (u5r,663.18)?("k",!"1"):(z8M,G11) != (131.47,388.51)?"-":(!"",!({}))) + S9 + ((v_F,R27) > (858.63,V1k)?"-":"I") + M3.getFullYear();}if(l_ == "00" && b4 == j8q){d7u.C$o(70);return d7u.d58((+"810.78",3980) < 6660?":":(2470,3596) <= (228.06,2372)?!({}):(8.17e+3,"858" ^ 0),S9,542 < 821.94?" ":(697.36,5880) < 4840?(342.02,"8.39e+2" ^ 0):(4.18e+3,+"107.40"),G4,395.78 < (4044,3660)?(7167,6950) !== (5031,2993)?"-":!!"1":(!1,![]),I0,F$);}if(b4 == "000"){d7u.C$o(71);return d7u.d58(I0,(567.82,9870) < (3390,8098)?0x6e8:":",S9,G4,l_,+"7662" < (+"2030",33.79)?9802 >= (8499,+"455.95")?(0x8c4,+"203.33"):(7.19e+3,"5.49e+3" ^ 0):":"," ",(664.35,"8910" >> 32) < +"551.62"?0x1581:(7094,7284) !== +"505.06"?"-":(228,512.74) !== 68.15?(!1,"j"):!({}),F$);}d7u.M8Y(72);return d7u.d58(G4,":"," ",3474 === 88?(![],"v"):(538.6,+"148") < (9686,6940)?("3980" * 1,+"4730") > (1810,2077)?":":!!1:(338.26,961.92),l_,F$,1868 == (+"7000",8710)?"i":+"448.39" >= (4880,2900)?(831.36,2929) < (+"532.41",822)?(2.50e+3,"7.81e+3" ^ 0):742.67:":",b4,S9,I0,18.38 <= (5644,3890)?("190.91" * 1,275) < (4550,7026)?"-":(8173,"655.27" - 0) < (448.12,9050)?("189.07" * 1,266.64):(307.66,!1):0x369);};k0.getYearDay=function(r_){d7u.J8h();var o7,V$,n2,C4,h5;o7=r_;if(!o7){o7=new Date();}d7u.M8Y(19);o7.setHours(0,d7u.c6Y(96,"0"),0,0);d7u.C$o(0);V$=new Date(o7.getFullYear(),d7u.c6Y("0",0),d7u.d58(0,"0",d7u.M8Y(19)));d7u.C$o(0);n2=d7u.d58(o7,V$);d7u.M8Y(73);C4=d7u.d58(60,1000,60,24);d7u.C$o(40);h5=Math.round(d7u.c6Y(C4,n2));return h5;};k0.getETDateTime=function(){var I_;I_=new Date();return k0.convertTimeZone(new Date(I_.getTime() + I_.getTimezoneOffset() * 60000),"UTC","America/New_York");};k0.fromET=function(r6){var k2,A0,F8,L4;k2=new Date();d7u.C$o(74);A0=d7u.c6Y("4",0);d7u.r2m();if(k2.getMonth() < "2" >> 32 || k2.getMonth() == 2 && k2.getDate() < ("11" | 11) || k2.getMonth() > 10 || k2.getMonth() == 10 && k2.getDate() >= ("4" ^ 0)){A0=5;}d7u.C$o(8);var L1_=d7u.d58(46800000,2250000,8);F8=r6.getTime() + L1_ * A0;L4=new Date(F8);return L4;};k0.monthAsDisplay=function(N8,J$,s9){if(J$){if(s9 && s9.monthLetters){return s9.monthLetters[N8];}return k0.monthLetters[N8];}if(s9 && s9.monthAbv){return s9.monthAbv[N8];}return k0.monthAbv[N8];};k0.timeAsDisplay=function(B$,E$,n5){var H0,m4,v1,o6,O1;H0=E$?E$.internationalizer:null;if(H0){if(n5 == k0.SECOND){return H0.hourMinuteSecond.format(B$);}else if(n5 == k0.MILLISECOND){return H0.hourMinuteSecond.format(B$) + "." + B$.getMilliseconds();}return H0.hourMinute.format(B$);}m4=B$.getMinutes();if(m4 < 10){d7u.M8Y(22);m4=d7u.c6Y(m4,(5485,+"703.61") <= (127,2120)?"0":![]);}v1=B$.getHours() + ":" + m4;d7u.J8h();o6="";if(n5 <= k0.SECOND){o6=B$.getSeconds();if(o6 < +"10"){d7u.C$o(22);o6=d7u.c6Y(o6,(+"6920",4920) > 1860?(53.3,2100) !== 2630?"0":7.27:("G",0xc67));}d7u.M8Y(22);v1+=d7u.d58(o6,":");}if(n5 == k0.MILLISECOND){O1=B$.getMilliseconds();if(O1 < 10){d7u.C$o(22);O1=d7u.d58(O1,"00");}else if(O1 < 100){d7u.C$o(22);O1=d7u.d58(O1,2305 < (51,9160)?"0":1413 <= (2520,+"1287")?(0x1055,"R"):7098 <= ("4242" << 0,4700)?(![],856.89):(+"6.52e+3",!!({})));}d7u.M8Y(22);v1+=d7u.c6Y(O1,+"7060" > (119.13,185.75)?".":"T");}return v1;};k0.displayableDate=function(x_,K$,Q7,R_){var j0D,e9,g7,l1,s4,z_,Z4L,P3X,j01,X1,R4,i2,O3,R_n,O$,W3,z7;j0D="millisec";j0D+="ond";e9="";d7u.r2m();g7=x_.layout.interval;l1=k0.ChartEngine.isDailyInterval(g7);s4=K$.xAxis.activeTimeUnit && K$.xAxis.activeTimeUnit <= k0.SECOND || x_.layout.timeUnit == "second";z_=K$.xAxis.activeTimeUnit && K$.xAxis.activeTimeUnit <= k0.MILLISECOND || x_.layout.timeUnit == j0D;function e6(I$){if(I$ < +"10"){d7u.C$o(22);return d7u.d58(I$,+"4820" == (842,530.25)?(+"0x57c",0x54a):3569 === 4109?(4270,9482) == (3786,"829.93" * 1)?0x207d:9.04e+3:"0");}return I$;}if(K$.xAxis.formatter){e9=K$.xAxis.formatter(Q7);}else if(x_.internationalizer){e9=x_.internationalizer.monthDay.format(Q7);if(s4 || z_){d7u.C$o(75);var T4z=d7u.d58(13,52012,4312,10,12);d7u.C$o(25);var c$e=d7u.d58(32320,28296,16);d7u.M8Y(22);var W5k=d7u.c6Y(1587,793);d7u.C$o(67);var z5o=d7u.c6Y(4253,4240,4253);d7u.M8Y(68);var k90=d7u.d58(2095,2,2103);d7u.C$o(25);var E$o=d7u.d58(383,7,4);e9+=(T4z > c$e?W5k !== z5o?" ":k90:E$o) + x_.internationalizer.hourMinuteSecond.format(Q7);if(z_){d7u.M8Y(22);var i2b=d7u.d58(17,9272);d7u.C$o(68);var D5e=d7u.c6Y(14,3,6);e9+=("1990" >> 0 != (i2b,"7588" | D5e)?".":"s") + Q7.getMilliseconds();}}else if(!l1){if(R_){e9=x_.internationalizer.yearMonthDay.format(Q7);}d7u.M8Y(76);var A9f=d7u.d58(10030,10043,1002,13);d7u.M8Y(77);var o1G=d7u.c6Y(94864,19,15,6775);d7u.C$o(22);var g0c=d7u.c6Y(17,245);d7u.C$o(0);var b87=d7u.c6Y(1722,2);d7u.M8Y(78);var w05=d7u.d58(13,2,7403,9);d7u.M8Y(67);var H_n=d7u.d58(476,3572,2);d7u.M8Y(78);var y37=d7u.c6Y(6,18,5368,10);d7u.M8Y(79);var O4v=d7u.d58(28708,16,20,30498);e9+=(A9f === o1G?"F":(g0c,b87) > +"7163"?(w05,94.2) > H_n?!!"1":(y37,O4v):" ") + x_.internationalizer.hourMinute.format(Q7);}else {Z4L=-1253199454;P3X=-156823918;j01=2;for(var Y3Z=1;d7u.O$R(Y3Z.toString(),Y3Z.toString().length,85259) !== Z4L;Y3Z++){if(g7 == "month"){e9=x_.internationalizer.yearMonth.format(Q7);}else {e9=x_.internationalizer.yearMonthDay.format(Q7);}j01+=2;}if(d7u.O$R(j01.toString(),j01.toString().length,17170) !== P3X){if(g7 != ""){e9=x_.internationalizer.yearMonth.format(Q7);}else {e9=x_.internationalizer.yearMonthDay.format(Q7);}}}}else {X1=e6(Q7.getMonth() + 1);R4=e6(Q7.getDate());i2=e6(Q7.getHours());O3=e6(Q7.getMinutes());if(l1){R_n="m";R_n+="o";R_n+="nth";e9=g7 == R_n?X1 + ((7040,276.35) != 3570?"/":(119,4.23e+3)):X1 + (1900 != 837.12?2565 < 103.73?0x2255:"/":!"1") + R4 + ((6901,427) != 5332?398.41 !== 695.79?"/":("1670" - 0,443.34) !== +"6430"?(0x23b0,![]):!1:"m");e9+=Q7.getFullYear();}else {d7u.C$o(53);O$=d7u.c6Y(X1,(5535,981.55) !== (+"2822",551.54)?(2730,4909) !== 2270?"/":+"0xd90":!!"",R4);if(R_){d7u.C$o(16);var t2z=d7u.c6Y(6,9,18,269);d7u.M8Y(0);var z85=d7u.c6Y(2595,1730);d7u.C$o(64);var X_x=d7u.d58(4055,3249,5,1);d7u.M8Y(80);var A9b=d7u.d58(26,16,62,9,11);O$+=("5530" * t2z !== (z85,X_x)?"/":(A9b,"b")) + Q7.getFullYear();}d7u.C$o(80);e9=d7u.c6Y(O3,i2,O$,(4110,430.8) >= (6160,6185)?(0x27c,127.45):(1512,826.51) > 5954?6.26e+3:":",+"5379" > (939.66,1460)?"6730" << 0 != +"2130"?(8037,+"730.52") === 1993?"Q":" ":(55.47,![]):0x85c);if(s4 || z_){W3=e6(Q7.getSeconds());d7u.M8Y(22);e9+=d7u.c6Y(W3,862 < ("6680" ^ 0,87)?(4490,7330) > 5468?7110 <= (2076,786.21)?(0xf26,"V"):"X":+"2.05e+2":":");if(z_){z7=e6(Q7.getMilliseconds());if(z7 < 100){d7u.M8Y(22);z7=d7u.c6Y(z7,"0");}d7u.C$o(22);e9+=d7u.d58(z7,(55.67,891) != (8234,205.39)?":":(2300,"3410" >> 64) != 566?"f":!0);}}}}return e9;};k0.convertTimeZone=function(H7,j6,x8){var a3;if(!Q1.Date){return H7;}a3=new Q1.Date(H7.getFullYear(),H7.getMonth(),H7.getDate(),H7.getHours(),H7.getMinutes(),H7.getSeconds(),H7.getMilliseconds(),j6);a3.setTimezone(x8);return a3;};k0.convertToLocalTime=function(p6,H2){var b7,q3,r5;if(!Q1.Date){return p6;}b7=p6.getSeconds();q3=p6.getMilliseconds();r5=new Q1.Date(p6.getFullYear(),p6.getMonth(),p6.getDate(),p6.getHours(),p6.getMinutes(),H2);return new Date(r5.getTime() + b7 * ("1000" ^ 0) + q3);};};C=j5=>{var C0t=x2dci;var P9,o_,e8,E_,Z8S;if(!j5.SplinePlotter){j5.SplinePlotter={};}P9=j5.CIQ;o_=j5.SplinePlotter;e8=function(N_,j2){var H3;if(!j2){return document.getElementById(N_);}if(j2.id == N_){return j2;}if(!j2.hasChildNodes){return null;}for(var H5=0;H5 < j2.childNodes.length;H5++){H3=e8(N_,j2.childNodes[H5]);if(H3){return H3;}}return null;};j5.$$=e8;E_=function(c0,i5){if(!i5){i5=document;}return i5.querySelectorAll(c0)[0];;};j5.$$$=E_;P9.wheelEvent=(function(){var t5H,F4w,l30;t5H="whe";t5H+="el";F4w="d";F4w+="i";F4w+="v";l30="undef";l30+="in";l30+="ed";if(typeof document === l30){return undefined;}if(P9.isIE || ("onwheel" in document.createElement(F4w))){return t5H;}if(document.onmousewheel !== undefined){return "mousewheel";}return "DOMMouseScroll";})();P9.newChild=function(N3,U8,R7,e5){var c7;c7=document.createElement(U8);C0t.J8h();if(R7){c7.className=R7;}N3.appendChild(c7);if(e5){c7.innerHTML=e5;}return c7;};P9.innerHTML=function(X$,h0){C0t.r2m();if(window.MSApp && window.MSApp.execUnsafeLocalFunction){window.MSApp.execUnsafeLocalFunction(function(){X$.innerHTML=h0;});}else {X$.innerHTML=h0;}};P9.focus=function(a7,u$){var v2;if(P9.isSurface || u$){v2=0;if(!isNaN(parseInt(u$,10))){v2=u$;}setTimeout(function(){C0t.J8h();a7.focus();},v2);}else {a7.focus();}};P9.blur=function(W1){if(!W1){W1=document.activeElement;}if(W1){W1.blur();}window.focus();};P9.findNodesByText=function(F3,a$){var V9,c_;if(F3.innerHTML == a$){return [F3];}V9=[];for(var c2=0;c2 < F3.childNodes.length;c2++){c_=P9.findNodesByText(F3.childNodes[c2],a$);if(c_){V9=V9.concat(c_);}}if(V9.length){return V9;}return null;};P9.hideByText=function(s8,s3){var E4;E4=P9.findNodesByText(s8,s3);C0t.J8h();for(var v8=0;v8 < E4.length;v8++){E4[v8].style.display="none";}};P9.pageHeight=function(){var {innerHeight:S_, top:V7, parent:O6, self:a9}=window;if(V7 != a9){try{if(S_ > O6.innerHeight){S_=O6.innerHeight;}}catch(j9){}}C0t.r2m();return S_;};C0t.r2m();P9.pageWidth=function(){var {innerWidth:w_, top:F0, parent:B5, self:v5}=window;if(F0 != v5){try{if(w_ > B5.innerWidth){w_=B5.innerWidth;}}catch(c3){}}C0t.J8h();return w_;};P9.stripPX=function(z6){if(!z6){return 0;}C0t.r2m();if(typeof z6 == "number"){return z6;}return parseInt(z6.substr(0,z6.indexOf("p")),10);};P9.withinElement=function(D6,W7,x9){var X7;X7=D6.getBoundingClientRect();if(W7 <= X7.left){return !!"";}if(x9 <= X7.top){return ![];}if(W7 >= X7.left + D6.offsetWidth){return ![];}if(x9 >= X7.top + D6.offsetHeight){return !"1";}return !!({});};P9.efficientDOMUpdate=function(a2,F6,O7){if(a2[F6] !== O7){a2[F6]=O7;return !![];}C0t.r2m();return !({});};P9.cqvirtual=function(i6){var P0;if(!i6){return;}P0=i6.cloneNode(!![]);P0.innerHTML="";P0.original=i6;return P0;};P9.cqrender=function(k$){var b5;if(!k$){return;}if(k$.innerHTML == k$.original.innerHTML){return k$.original;}P9.removeChildIfNot(k$.original,"template");C0t.r2m();b5=Array.from(k$.children);if(b5.length){b5.forEach(function(h6){k$.original.appendChild(k$.removeChild(h6));});}return k$.original;};P9.removeChildIfNot=function(X8,p3){var u3;C0t.r2m();u3=Array.from(X8.children);if(u3.length){u3.forEach(function(F2){if(!p3 || !F2.matches(p3)){X8.removeChild(F2);}});}return X8;};P9.safeMouseOut=function(y5,T4){y5.addEventListener("mouseout",Y2(y5,T4));function Y2(u_,H8){C0t.J8h();return function(I2){C0t.r2m();var w$$;w$$="u";w$$+="ndefi";w$$+="ned";if(typeof I2.pageX == w$$){I2.pageX=I2.clientX;I2.pageY=I2.clientY;}if(P9.withinElement(u_,I2.pageX,I2.pageY)){return;}u_.stxMouseOver=![];H8(I2);};}};P9.safeMouseOver=function(u6,h3){u6.addEventListener("mouseover",w7(u6,h3));C0t.J8h();function w7(C_,D3){return function(A2){if(typeof A2.pageX == "undefined"){A2.pageX=A2.clientX;A2.pageY=A2.clientY;}if(P9.withinElement(C_,A2.pageX,A2.pageY)){if(C_.stxMouseOver){return;}C_.stxMouseOver=!!1;D3(A2);}};}};P9.installTapEvent=function(U3,x6){var w5;C0t.r2m();w5=function(z4){var w4g,y06,C2,t9V,o4D,N_3;w4g="und";w4g+="ef";w4g+="i";w4g+="ned";y06="st";y06+="x";y06+="tap";C2=new Event(y06,{bubbles:!!"1",cancelable:!!({})});if(typeof z4.pageX == w4g){z4.pageX=z4.clientX;z4.pageY=z4.clientY;}C2.pageX=z4.pageX;t9V=-2029794677;C0t.M8Y(19);o4D=-C0t.c6Y(64,"788278568");N_3=2;for(var g7u=+"1";C0t.O$R(g7u.toString(),g7u.toString().length,20029) !== t9V;g7u++){C2.pageY=z4.pageY;C0t.C$o(38);N_3+=C0t.d58("2",1);}if(C0t.q2D(N_3.toString(),N_3.toString().length,95613) !== o4D){C2.pageY=z4.pageY;}z4.target.dispatchEvent(C2);if(x6 && x6.stopPropagation){z4.stopPropagation();}};P9.safeClickTouch(U3,w5,x6);};P9.safeClickTouch=function(u4,J3,C9){var S7W,Y_,G2,J0,k3,Y0,V_,T$R,O1p,V5V,j$,W$,h0m,n_4,Q4l;S7W="point";S7W+="e";S7W+="ru";S7W+="p";if(!C9){C9={};}Y_={};if(!C9.allowMultiple){P9.clearSafeClickTouches(u4);}if(C9.preventUnderlayClick !== !"1"){C9.preventUnderlayClick=!![];}if(C9.absorbDownEvent !== ![]){C9.absorbDownEvent=!"";}C9.allowAnotherDevice=0;C9.registeredClick=!({});G2=u4.safeClickTouchEvents;if(!G2){G2=u4.safeClickTouchEvents=[];}J0=D8("mouseup",C9,Y_);k3=D8("touchend",C9,Y_);Y0=D8(S7W,C9,Y_);V_=function(I7){I7.stopPropagation();};T$R=-1419556650;O1p=-27149222;V5V=2;function q5(q6,b0){C0t.J8h();return function(M5){C0t.J8h();var D2,Q$,T5v,b5R,C8w;D2=M5.clientX?M5.clientX:M5.pageX;Q$=M5.clientY?M5.clientY:M5.pageY;if(b0){q6.t=new Date().getTime();T5v=93380431;b5R=-656741645;C8w=2;for(var H8c=1;C0t.O$R(H8c.toString(),H8c.toString().length,35238) !== T5v;H8c++){q6.x=D2;C8w+=2;}if(C0t.O$R(C8w.toString(),C8w.toString().length,63843) !== b5R){q6.x=D2;}q6.x=D2;q6.y=Q$;}else if(q6.x){if(Math.pow(q6.x - D2,2) + Math.pow(q6.y - Q$,2) > "16" - 0){q6.t=null;}}};}for(var S3e=1;C0t.q2D(S3e.toString(),S3e.toString().length,82640) !== T$R;S3e++){j$={};V5V+=+"2";}if(C0t.O$R(V5V.toString(),V5V.toString().length,89913) !== O1p){j$={};}j$={};function D8(Z2,Q6,N1){C0t.J8h();return function(B9){var D5;if(!P9.safeClickTouchEvent){if(!N1.t){return;;}D5=N1.t;N1.t=null;if(D5 + 1000 < new Date().getTime()){return;};}if(Q6.safety && Q6.safety.recentlyDragged){return;}if(B9.which && B9.which >= 2 || B9.button && B9.button >= 2){return;}if(Q6.preventUnderlayClick){if(B9.target.tagName !== "INPUT"){B9.preventDefault();}}else {if(Q6.lastType != Z2 && Date.now() < Q6.allowAnotherDevice){return;}Q6.lastType=Z2;C0t.C$o(81);var r_N=C0t.d58(16,13000,16,3327000);Q6.allowAnotherDevice=Date.now() + r_N;;}J3(B9);};}if(P9.safeClickTouchEvent){W$=D8(P9.safeClickTouchEvent,C9);u4.addEventListener(P9.safeClickTouchEvent,W$);j$[P9.safeClickTouchEvent]=W$;G2.push(j$);}else if(("onpointerup" in document) && !P9.noPointerEvents){u4.addEventListener("pointerdown",q5(Y_,!!({})));u4.addEventListener("pointermove",q5(Y_));u4.addEventListener("pointerup",Y0);j$.pointerup=Y0;if(C9.absorbDownEvent){u4.addEventListener("pointerdown",V_);j$.pointerdown=V_;}G2.push(j$);}else {h0m="to";h0m+="u";h0m+="ch";h0m+="move";n_4="to";n_4+="uc";n_4+="hstart";u4.addEventListener("mousedown",q5(Y_,!""));u4.addEventListener("mousemove",q5(Y_));u4.addEventListener(n_4,q5(Y_,!!1));u4.addEventListener(h0m,q5(Y_));u4.addEventListener("mouseup",J0);u4.addEventListener("touchend",k3);j$.mouseup=J0;j$.touchend=k3;if(C9.absorbDownEvent){Q4l="moused";Q4l+="own";u4.addEventListener(Q4l,V_);j$.mousedown=V_;u4.addEventListener("touchstart",V_);j$.touchstart=V_;}G2.push(j$);}};P9.clearSafeClickTouches=function(f7){C0t.r2m();var n6,m9,m$;n6=f7.safeClickTouchEvents;if(!n6){return;}for(var d8=0;d8 < n6.length;d8++){m9=n6[d8];for(var M0 in m9){m$=m9[M0];f7.removeEventListener(M0,m$);}}f7.safeClickTouchEvents=null;};P9.safeDrag=function(w9,n$){var A7E,U_6,C2d,H1Z,e$,q$,b6,m8,j3,f3,Q3,z3;A7E="t";C0t.J8h();function t$(D0){return function(j1){var e2,P_;if(j3){return;}j3=!!1;P9.ChartEngine.ignoreTouch=!!({});e2=function(U5){var b7U,q79,D4u;if(U5 && U5.preventDefault){U5.preventDefault();}z3.recentlyDragged=!"";C0t.C$o(46);b7U=-C0t.c6Y("2059865880",64);q79=-+"1992592325";C0t.C$o(20);D4u=C0t.c6Y("2",0);for(var J7r=1;C0t.q2D(J7r.toString(),J7r.toString().length,41852) !== b7U;J7r++){U5.displacementX=q$(U5) * f3;D4u+=2;}if(C0t.O$R(D4u.toString(),D4u.toString().length,79583) !== q79){U5.displacementX=q$(U5) - f3;}U5.displacementY=b6(U5) - Q3;n$.move(U5);};if(n$.move){document.body.addEventListener(D0.move,e2);}P_=function(R6){P9.ChartEngine.ignoreTouch=![];if(n$.move){document.body.removeEventListener(D0.move,e2);}document.body.removeEventListener(D0.up,P_);C0t.r2m();R6.displacementX=q$(R6) - f3;R6.displacementY=b6(R6) - Q3;if(n$.up){n$.up(R6);}setTimeout(function(){z3.recentlyDragged=!"1";},50);};document.body.addEventListener(D0.up,P_);setTimeout(function(){C0t.J8h();j3=!({});},m8);f3=q$(j1);Q3=b6(j1);if(n$.down){n$.down(j1);}};}A7E+="o";A7E+="uc";A7E+="hend";U_6="p";U_6+="ointe";U_6+="r";U_6+="move";C2d="po";C2d+="i";C2d+="nt";C2d+="erdown";H1Z="cli";H1Z+="entX";e$=function(L7,Z6){C0t.J8h();return function(X3){if(X3.touches){if(X3.touches.length > 0){C0t.C$o(74);return X3.touches[C0t.d58("0",0)][L7];}else if(X3.changedTouches && X3.changedTouches.length > 0){return X3.changedTouches[0][L7];}}return typeof X3[L7] !== "undefined"?X3[L7]:X3[Z6];};};q$=e$("pageX",H1Z);b6=e$("pageY","clientY");if(typeof n$ === "function"){n$={down:arguments["1" ^ 0],move:arguments[2],up:arguments[3]};}n$=n$ || ({});m8=100;j3=![];f3=0;Q3=+"0";z3={recentlyDragged:!({})};w9.addEventListener("mousedown",t$({down:"mousedown",move:"mousemove",up:"mouseup"}));w9.addEventListener("pointerdown",t$({down:C2d,move:U_6,up:"pointerup"}));w9.addEventListener("touchstart",t$({down:"touchstart",move:"touchmove",up:A7E}),{passive:!!0});return z3;};P9.inputKeyEvents=function(w0,d1){w0.addEventListener("keyup",function(j7){var v9;v9=j7.keyCode;switch(v9){case 13:d1();break;case 27:w0.value="";break;default:break;}},!!0);};P9.fixScreen=function(){C0t.C$o(0);window.scrollTo(C0t.c6Y("0",0),0);};P9.setCaretPosition=function(o2,Z3){var N5;C0t.J8h();o2.style.zIndex=+"5000";if(o2.setSelectionRange){P9.focus(o2);try{o2.setSelectionRange(Z3,Z3);}catch(s6){}}else if(o2.createTextRange){N5=o2.createTextRange();N5.collapse(!0);N5.moveEnd("character",Z3);N5.moveStart("character",Z3);N5.select();}};P9.setValueIfNotActive=function(J1,f5){if(document.activeElement == J1){return;}J1.value=f5;};P9.hideKeyboard=function(c9){var i1l,p9;i1l="IN";i1l+="P";i1l+="U";i1l+="T";p9=document.activeElement;if(p9.tagName == i1l || p9.tagName == "TEXTAREA"){p9.blur();window.focus();if(c9){if(c9 === document.body || document.body.contains(c9)){c9.focus();}}}};P9.smartHover=function(){var B7,f$,i8L,h5P,o_M;if(!document || document.documentElement.hasAttribute("ciq-last-interaction")){return;}function Q8(T8){var B7V;B7V="to";B7V+="u";B7V+="ch";clearTimeout(f$);B7=!!({});if(document.documentElement.getAttribute("ciq-last-interaction") != "touch"){r7(B7V);}f$=setTimeout(function(){C0t.J8h();B7=![];},500);}B7=![];document.addEventListener("touchend",Q8,!({}));function r7(X_){C0t.J8h();document.documentElement.setAttribute("ciq-last-interaction",X_);}document.addEventListener("mouseover",y_,!({}));function y_(k1){C0t.r2m();if(!B7){r7("mouse");}}i8L=-1349354765;h5P=-69100854;o_M=2;for(var U6j=+"1";C0t.O$R(U6j.toString(),U6j.toString().length,23643) !== i8L;U6j++){r7("");o_M+=2;}if(C0t.q2D(o_M.toString(),o_M.toString().length,"91616" >> 0) !== h5P){r7("");}};P9.translatableTextNode=function(h8,g1,q7){var S1;C0t.J8h();if(h8.translationCallback){S1=document.createElement("translate");S1.setAttribute("original",g1);S1.innerHTML=h8.translationCallback(g1,q7);return S1;}return document.createTextNode(g1);};P9.climbUpDomTree=function(E9,Q2){var l4;C0t.r2m();if(!(E9 instanceof HTMLElement)){return null;}l4=[];while(E9){if(!Q2 || E9.matches(Q2)){l4.push(E9);}E9=E9.parentElement;}return l4;};P9.guaranteedSize=function(P7){var U2,e3;if(P7 === document){P7=window;}if(!P7.nodeType){return {width:P7.innerWidth,height:P7.innerHeight};}C0t.J8h();if(!P7 || P7.nodeType > 1){return {};}U2=P7.offsetWidth;e3=P7.offsetHeight;while(!U2 || !e3){if(P7.tagName === "BODY" || P7 === window){if(!U2){U2=window.innerWidth;}if(!e3){e3=window.innerHeight;}break;}P7=P7.parentElement;if(!U2){U2=P7.offsetWidth;}if(!e3){e3=P7.offsetHeight;}}return {width:U2,height:e3};};P9.trulyVisible=function(K8){var i73,e7;i73="hidd";i73+="e";i73+="n";if(!K8){return !![];}e7=getComputedStyle(K8);if(e7.opacity === ((6590,7250) <= ("6680" ^ 0,4890)?636.85:"0")){return !({});}if(e7.display === "none"){return ![];}if(e7.visibility === i73){return ![];}if(parseInt(e7.width,10) === 0){return !!0;}if(parseInt(e7.height,10) === 0 && e7.overflowY == "hidden"){return !({});}return P9.trulyVisible(K8.parentElement);};P9.elementDimensions=function(I9,C0){var K6w,G7,Z$,Q9,K3,X0z,S_6,A_;K6w="w";K6w+="id";C0t.J8h();K6w+="t";K6w+="h";if(!I9 || I9.nodeType !== 1){return {};}G7=getComputedStyle(I9);Z$={width:parseFloat(G7.width),height:parseFloat(G7.height)};Q9={margin:{},border:{},padding:{}};K3=[K6w,"height"];for(var t5 in Q9){X0z="B";X0z+="ottom";S_6="Wi";S_6+="dt";S_6+="h";A_=t5 == "border"?S_6:"";Q9[t5]={width:parseFloat(G7[t5 + "Left" + A_]) + parseFloat(G7[t5 + "Right" + A_]),height:parseFloat(G7[t5 + "Top" + A_]) + parseFloat(G7[t5 + X0z + A_])};}if(C0 && C0.margin){K3.forEach(function(X6){Z$[X6]+=Q9.margin[X6];});}if(C0 && G7.boxSizing === "content-box"){if(C0.padding){K3.forEach(function(v7){Z$[v7]+=Q9.padding[v7];});}if(C0.border){K3.forEach(function(Z_){Z$[Z_]+=Q9.border[Z_];});}}else if(G7.boxSizing === "border-box"){if(!C0 || !C0.padding){K3.forEach(function(K5){C0t.r2m();Z$[K5]-=Q9.padding[K5];});}if(!C0 || !C0.border){K3.forEach(function(a8){C0t.J8h();Z$[a8]-=Q9.border[a8];});}}return Z$;};P9.resizeObserver=function(F4,H9,N0,T6){if(T6){if(typeof ResizeObserver !== "undefined"){if(!N0){N0=new ResizeObserver(H9);N0.observe(F4);}}else {if(N0){clearInterval(N0);}N0=setInterval(H9,T6);}}else {if(N0){if(typeof ResizeObserver !== "undefined"){N0.disconnect();}else {clearInterval(N0);}}N0=null;}return N0;};P9.getLines=function(W0,N4,s5){var C6,F_,W2,Q5,V5,I8;C6=N4.split((+"78.6",9880) != (3295,5561)?(4280,7598) < 671?(242.92,0xc8d):" ":(9.16e+2,0x1c0c));F_=[];C0t.r2m();W2="";Q5=0;V5=!!"";for(var w6=0;w6 < C6.length;w6++){I8=C6[w6];Q5=W0.measureText(W2 + I8).width;if(Q5 < s5){if(V5){W2+=" ";}V5=!!({});W2+=I8;}else {F_.push(W2);W2=I8;}if(w6 === C6.length - 1){F_.push(W2);break;}}return F_;};P9.alert=function(Q_){C0t.r2m();var W_y,z$t,l6B;W_y=-1923671589;z$t=-2106280244;l6B=2;for(var W6x=1;C0t.O$R(W6x.toString(),W6x.toString().length,27188) !== W_y;W6x++){if(typeof window !== "undefined"){window.alert(Q_);}else {console.log(Q_);}l6B+=2;}if(C0t.O$R(l6B.toString(),l6B.toString().length,61558) !== z$t){if(-window === ""){window.alert(Q_);}else {console.log(Q_);}}};try{Z8S="undefin";Z8S+="e";Z8S+="d";if(typeof localStorage !== Z8S){P9.localStorage=localStorage;}}catch(E3){}if(!P9.localStorage){P9.localStorage={items:{},getItem:function(o3){C0t.r2m();return P9.localStorage.items[o3] || null;},setItem:function(p$,Z4){C0t.r2m();P9.localStorage.items[p$]=Z4;},removeItem:function(Y5){delete P9.localStorage.items[Y5];}};}P9.privateBrowsingAlert=!({});P9.localStorageSetItem=function(v0,X0){try{P9.localStorage.setItem(v0,X0);}catch(k8){if(!P9.privateBrowsingAlert){P9.alert("No storage space available. Possible causes include browser being in Private Browsing mode, or maximum storage space has been reached.");P9.privateBrowsingAlert=!!({});}}};};E=u9=>{var R_k=x2dci;var n1_,o6Y,u0c,X_R,X0B,T5e,I4,z1;n1_="ca";n1_+="ndl";n1_+="e";o6Y="d";o6Y+="ay";u0c="m";u0c+="i";u0c+="nut";u0c+="e";X_R="mont";X_R+="h";X0B="mi";X0B+="n";X0B+="ute";T5e="r";T5e+="oundRectAr";R_k.r2m();T5e+="row";I4=u9.CIQ;I4.ChartEngine=function(J4){var D_,K2;if(!J4){J4={container:null};}else if(typeof HTMLDivElement != "undefined" && J4.constructor == HTMLDivElement){D_={container:J4};J4=D_;}for(var i7 in z1){this[i7]=I4.clone(I4.ChartEngine.prototype[i7]);}this.container=null;this.createChartPanel=!"";this.markers={};this.panels={};this.overlays={};this.charts={};this.eventListeners=[];this.controls={};this.goneVertical=!1;this.pinchingScreen=![];this.grabbingScreen=!1;this.grabStartX=0;this.grabStartY=0;this.grabStartScrollX=0;this.grabStartScrollY=0;this.swipe={};this.grabStartCandleWidth=0;R_k.M8Y(20);this.grabStartZoom=R_k.c6Y("0",0);this.grabOverrideClick=!!"";this.grabMode="";this.vectorsShowing=!"1";this.mouseMode=!![];this.lineTravelSpacing=!!0;this.highlightedDataSetField=null;this.anyHighlighted=!!"";this.accessoryTimer=null;this.lastAccessoryUpdate=new Date().getTime();this.displayCrosshairs=!![];this.hrPanel=null;this.editingAnnotation=![];this.openDialog="";this.touches=[];this.changedTouches=[];this.crosshairTick=null;this.crosshairValue=null;this.pt={x1:-1,x2:-1,y1:-1,y2:-1};R_k.C$o(20);this.moveA=-R_k.d58("1",0);this.moveB=-1;this.touchStartTime=-1;this.touchPointerType="";this.gestureStartDistance=-1;this.grabStartPeriodicity=1;this.grabEndPeriodicity=-1;this.scrollEvent=null;this.cmd=!!0;this.ctrl=!({});this.shift=!!"";this.userPointerDown=![];this.cloneDrawing=!!0;this.insideChart=!!0;this.overXAxis=!({});this.overYAxis=!1;this.displayInitialized=!!0;this.cx=null;this.isHistoricalModeSet=null;this.cy=null;this.clicks={s1MS:-1,e1MS:-1,s2MS:-("1" ^ 0),e2MS:-+"1"};this.cancelTouchSingleClick=!1;this.locale=null;this.dataZone=null;this.displayZone=null;this.timeZoneOffset=+"0";this.masterData=null;this.transformDataSetPre=null;this.transformDataSetPost=null;this.dataCallback=null;this.drawingObjects=[];this.undoStamps=[];this.useBackgroundCanvas=![];this.mainSeriesRenderer=null;this.styles={};this.plugins={};this.currentVectorParameters=I4.clone(I4.ChartEngine.currentVectorParameters);this.chart=new I4.ChartEngine.Chart();K2=this.chart;K2.name="chart";K2.yAxis.name="chart";K2.canvas=null;K2.tempCanvas=null;K2.container=J4.container;if(I4.Market){K2.market=new I4.Market();}this.charts.chart=K2;I4.extend(this,J4);if(J4.container){if(this.registerHTMLElements){this.registerHTMLElements();}K2.width=K2.container.clientWidth - K2.yAxis.width;this.setCandleWidth(this.layout.candleWidth,K2);K2.canvasHeight=K2.container.clientHeight;}this.construct();};I4.ChartEngine.drawingLine=![];I4.ChartEngine.resizingPanel=null;R_k.C$o(38);I4.ChartEngine.crosshairX=R_k.c6Y("0",1);I4.ChartEngine.crosshairY=+"0";I4.ChartEngine.useAnimation=!"";I4.ChartEngine.enableCaching=![];I4.ChartEngine.ignoreTouch=!"1";I4.ChartEngine.useOldAndroidClear=!!({});I4.ChartEngine.currentVectorParameters={};I4.ChartEngine.defaultDisplayTimeZone=null;I4.ChartEngine.pluginBasePath="plugins/";I4.ChartEngine.registeredContainers=[];I4.ChartEngine.registerHelpers=function(R9){I4.ChartEngine.helpersToRegister.forEach(function(U6){R_k.r2m();U6(R9);});};I4.ChartEngine.helpersToRegister=[];I4.ChartEngine.prototype.construct=function(){var k$2,s5K;if(this.createChartPanel){k$2="c";k$2+="hart";s5K="ch";s5K+="ar";s5K+="t";this.stackPanel(s5K,k$2,1);this.adjustPanelPositions();this.chart.panel=this.panels[this.chart.name];}this.cx=0;this.cy=0;this.micropixels=0;this.callbackListeners={doubleTap:[],doubleClick:[],drawing:[],drawingEdit:[],floatingWindow:[],layout:[],longhold:[],move:[],newChart:[],notification:[],periodicity:[],preferences:[],rightClick:[],scroll:[],studyOverlayEdit:[],studyPanelEdit:[],symbolChange:[],symbolImport:[],tap:[],theme:[],undoStamp:[]};R_k.r2m();I4.ChartEngine.registerHelpers(this);};z1={longHoldTime:700,yTolerance:100,minimumLeftBars:"1" << 32,reverseMouseWheel:!({}),mouseWheelAcceleration:!"",minimumCandleWidth:1,maximumCandleWidth:200,minimumZoomTicks:9,allowZoom:!"",allowScroll:!"",allowSideswipe:!0,allowThreeFingerTouch:!1,bypassRightClick:{series:!({}),study:!!"",drawing:!!0},adjustHighlightedDataSetField:function(G$){R_k.r2m();return G$;},displayIconsUpDown:!!({}),displayIconsSolo:!!({}),displayIconsClose:!0,displayPanelResize:!0,soloPanelToFullScreen:!"1",markerDelay:null,useBackingStore:!!({}),disableBackingStoreDuringTouch:I4.isMobile || I4.isSurface && I4.isFF,captureTouchEvents:!!"1",captureMouseWheelEvents:!!({}),tapForHighlighting:!![],doubleClickTime:250,yaxisLabelStyle:T5e,axisBorders:null,singleDrawingHighlight:!![],crosshairXOffset:-+"40",crosshairYOffset:-40,extendLastTick:!"1",translationCallback:null,dontRoll:!1,allowEquations:!"",cleanupGaps:!1,staticRange:!({}),maxDataSetSize:20000,maxMasterDataSize:0,resizeDetectMS:1000,xAxisAsFooter:!!({}),xaxisHeight:+"30",displayGridLinesInStudies:!({}),escapeOnSerialize:!![],candleWidthPercent:0.65,colorByCandleDirection:!({}),noWicksOnCandles:{renko:!![],linebreak:!!1},fetchMaximumBars:{rangebars:!![],kagi:!![],renko:!![],linebreak:!![],pandf:!!({})},startComparisonsAtFirstVisibleBar:!({}),animations:{zoom:{isStub:!![],run:function(N9,l24,M$_){R_k.J8h();N9(M$_);},stop:function(){},reset:function(){},running:!"1",hasCompleted:!""}},staticRangePeriodicityMap:[{rangeInMS:I4.WEEK,periodicity:1,interval:5,timeUnit:"minute"},{rangeInMS:I4.MONTH,periodicity:1,interval:"30" * 1,timeUnit:X0B},{rangeInMS:I4.YEAR,periodicity:+"1",interval:"day"},{rangeInMS:I4.DECADE,periodicity:1,interval:"week"},{rangeInMS:I4.DECADE * 10,periodicity:"1" | 1,interval:X_R},{rangeInMS:Number.MAX_VALUE,periodicity:"12" << 32,interval:"month"}],dynamicRangePeriodicityMap:[{interval:+"1",timeUnit:"minute",rangeInMS:I4.MINUTE},{interval:5,timeUnit:"minute",rangeInMS:I4.MINUTE * 5},{interval:30,timeUnit:"minute",rangeInMS:I4.MINUTE * 30},{interval:60,timeUnit:u0c,rangeInMS:I4.MINUTE * 60},{interval:"day",rangeInMS:I4.DAY},{interval:"month",rangeInMS:I4.MONTH},{interval:"year",rangeInMS:I4.YEAR}],layout:{interval:o6Y,periodicity:1,timeUnit:null,candleWidth:8,flipped:!({}),volumeUnderlay:![],adj:!0,crosshair:!"1",chartType:n1_,extended:!!0,marketSessions:{},aggregationType:"ohlc",chartScale:"linear",studies:{},panels:{},setSpan:{},outliers:![]},preferences:{currentPriceLine:![],dragging:{series:!"",study:!!({}),yaxis:!!1},drawings:null,highlightsRadius:10,highlightsTapRadius:30,magnet:!"1",horizontalCrosshairField:null,labels:!!({}),language:null,timeZone:null,whitespace:50,zoomInSpeed:null,zoomOutSpeed:null,zoomAtCurrentMousePosition:!({})},streamParameters:{count:0,maxWait:1000,maxTicks:100,timeout:-1},autoPickCandleWidth:{turnOn:!"1",candleWidth:5}};I4.extend(I4.ChartEngine.prototype,z1);I4.ChartEngine.NONE=0;I4.ChartEngine.CLOSEUP=1;R_k.C$o(20);I4.ChartEngine.CLOSEDOWN=R_k.c6Y("2",0);I4.ChartEngine.CLOSEEVEN=+"4";I4.ChartEngine.CANDLEUP=8;I4.ChartEngine.CANDLEDOWN=16;I4.ChartEngine.CANDLEEVEN=32;;};K=O3W=>{var s3V=x2dci;var I7h;I7h=O3W.CIQ;I7h.convertFutureMonth=function(K8f){var a86,f_j,y2N,V4$;a86="1";a86+="2";f_j="1";f_j+="1";y2N=K8f.toString();if(y2N.length <= 0 || y2N.length > 2){return "";}switch(y2N){case "1":return "F";case ("6370" ^ 0) < ("161.21" * 1,+"274")?(846.24,8.96e+3):"2":return 4215 > (6592,5210)?4.39e+3:9190 !== 7255?"G":(+"18.42",2777) != +"8650"?![]:![];case "3":return (1000,150.8) !== "95.13" * 1?"H":4.66e+3;case "4":return "J";case 8829 >= ("1920" ^ 0)?993.15 != 8890?(8975,4820) != 787.26?"5":![]:(!1,0xd24):("P",4.86e+3):return 3120 <= 282?"i":"K";case 287.43 !== (7515,"931.27" * 1)?"6":!"1":return 4670 > (+"9454",2951)?"M":100.96;case (83,646.94) != 324?"7":(+"6.66e+3","O"):return "N";case "8":return "Q";case "9":return (87,"6871" - 0) != 944.53?(6800,980) != +"703.95"?"U":(473.98,96) > "5576" - 0?6.43e+3:("M",!!({})):![];case "10":return (2295,8160) > (+"869",2920)?+"2530" == "917" << 32?1390 <= 7542?("d",!!0):!!0:"V":(0x1f87,0x141c);case f_j:return (472.79,293) > (179,2390)?(627.78,3.53e+3):"X";case a86:return (+"2240",+"2606") != 973.76?(+"144.13",5650) >= (2789,64.6)?"Z":(2056,3136) <= 4120?"Q":"i":(!!"",!!1);case (3373,5635) >= (6400,232)?"F":(5950,"4980" - 0) != ("8551" * 1,8130)?("713.72" - 0,395.97):(0x1dc4,![]):return 9913 !== 432?"1":(5270,"5120" << 64) < (2792,"8920" * 1)?!({}):!![];case "G":return "2";case (4667,"361.85" - 0) <= 7590?(3824,135.99) != ("6048" << 0,549.76)?"H":5200 < 85.77?3.76e+3:(7.27e+3,"722.40" * 1):(+"6.89e+2",210.41):return "3";case "J":return "4";case "K":return "5";case 12.84 > 373?(3290,"84.08" * 1) <= ("67.28" * 1,6124)?+"6431" != 847.29?(99.24,!"1"):"z":("J",!!"1"):"M":return "6";case "N":return 4217 === ("543.02" - 0,6300)?("m",100.11):5942 > (+"6090",5110)?4770 < ("423.61" * 1,+"3236")?("A",0x2293):"7":0xcce;case (8660,4946) > (9640,199)?(804.58,"642.74" - 0) >= (4980,"744.36" * 1)?2370 >= ("399.31" - 0,8900)?("0x226a" | 64,8.53e+3):(+"0x1b2f",+"789.26"):"Q":450.54:return +"9910" >= 36.13?"8":8167 < "815.25" * 1?(+"6.61e+3",!!({})):306.16;case 9470 < (9621,4830)?(3720,621.82) != (6480,2863)?0xf63:4.89e+3:"U":return "520.57" - 0 != (432.45,9971)?"9":7155 > 1088?(+"139.5",2706) == 4231?0xa7f:(!!1,3.28e+3):![];case "V":V4$="1";V4$+="0";return V4$;case "X":return "11";case 1795 !== (7260,973)?420.6 >= 746.85?("j",29.66):297.8 != (818.67,271.45)?"Z":!![]:8.84e+3:return "12";}return y2N;};I7h.money=function(h$_,R9I,Z5i){s3V.J8h();if(!Z5i){Z5i="$";}if(Z5i.length == 3){Z5i+=" ";}if(!R9I && R9I !== 0){R9I=2;}return Z5i + I7h.commas((Math.round(h$_ * 10000) / 10000).toFixed(R9I));};I7h.convertCurrencyCode=function(v6H){var x2A,A4Z,o4v,p0Q;x2A="\u0440";x2A+="\u0443";x2A+="\u0431";A4Z="M";A4Z+="X";A4Z+="$";o4v={JPY:1480 >= (3508,"1914" - 0)?952.95:"¥",USD:268.6 < (6360,2883)?(9710,+"5357") <= (+"3707",7037)?"$":(9260,5736) != (2980,4830)?0x1382:(0x1aa1,!0):5.33e+3,AUD:"A$",BRL:"R$",CAD:"CA$",CNY:"CN¥",CZK:"Kč",DKK:"kr",EUR:4080 === 5610?"0x22c7" << 64:"775.02" * 1 !== (393.24,2520)?7300 !== 3990?"€":(0x971,5.99e+3):2.03e+3,GBP:(2560,7804) > 409?(778,2660) !== +"383.58"?1150 === (855,"825.43" - 0)?819.66:"£":8.02e+3:931.31,HKD:"HK$",HUF:"Ft",ILS:(932,242.32) != (3354,35)?(612.76,9240) <= "965.78" * 1?(+"0x2554","g"):"₪":!"",INR:"₹",KRW:"₩",MXN:A4Z,NOK:"kr",NZD:"NZ$",PLN:"zł",RUB:x2A,SAR:4980 < (103.95,860.9)?(!1,!![]):"﷼",SEK:"kr",SGD:"S$",THB:(909.84,2510) >= ("8435" | 81,4540)?0x168d:(5980,8400) >= +"747.17"?"฿":(5.53e+3,0xa29),TRY:(590,+"378.1") <= 4261?"₺":(3960,+"800") >= (8.89,9950)?(+"525",+"150.67"):556 === 275.38?(!!"",!({})):(5.68e+3,"c"),TWD:"NT$",VND:(6257,956.97) === (8591,"264.52" - 0)?(5.99e+2,0x2293):"₫",XAF:"FCFA",XCD:"EC$",XOF:"CFA",XPF:"CFPF",ZAR:(2340,+"561") >= "2490" << 32?(723,4.76e+3):+"979.93" !== "7110" - 0?"R":("s",0x5a0)};p0Q=o4v[v6H];if(p0Q){return p0Q;}return v6H;};I7h.commas=function(X0G){s3V.J8h();return X0G.toString().replace(/\B(?=(\d{3})+(?!\d))/g,(5683,8370) === (3357,380)?55.84:+"629.23" <= "783.62" * 1?(75.29,3177) != 6684?",":"x":!!"");};I7h.cleanPeriodicity=function(w2N,D0e,P8T){var j9v,Y0Z,x$M,M7y,a$Q,b61,q11;j9v="h";j9v+="o";s3V.r2m();j9v+="ur";if(isNaN(w2N)){w2N=1;}Y0Z=-1101956672;x$M=-270753879;M7y=2;for(var z02=1;s3V.O$R(z02.toString(),z02.toString().length,53220) !== Y0Z;z02++){if(!D0e){D0e=1;}M7y+=2;}if(s3V.q2D(M7y.toString(),M7y.toString().length,17676) !== x$M){if(~D0e){D0e=4;}}if(!isNaN(D0e) && P8T){a$Q="mill";a$Q+="i";a$Q+="second";b61="mi";b61+="nute";if(!(P8T == "hour" || P8T == b61 || P8T == "second" || P8T == a$Q)){D0e=P8T;P8T=null;}}else if(D0e == "tick"){P8T=null;}else if(!P8T && !isNaN(D0e)){P8T="minute";}if(P8T == j9v){P8T="minute";s3V.M8Y(38);D0e=s3V.d58(D0e,60);}if(D0e == "year"){q11="m";q11+="o";q11+="n";q11+="th";D0e=q11;if(!w2N){s3V.M8Y(74);w2N=s3V.d58("1",0);}s3V.C$o(38);w2N=s3V.c6Y(w2N,12);}return {period:w2N,interval:D0e,timeUnit:P8T};};s3V.r2m();I7h.readablePeriodicity=function(s74){var C1f,m$5;C1f=s74.layout.periodicity;m$5=s74.layout.interval;if(typeof s74.layout.interval == "number" && s74.layout.timeUnit){C1f=s74.layout.interval * s74.layout.periodicity;m$5=s74.layout.timeUnit;}else if(typeof s74.layout.interval == "number" && !s74.layout.timeUnit){C1f=s74.layout.interval * s74.layout.periodicity;m$5="minute";}if(C1f % 60 === 0 && m$5 == "minute"){C1f/=60;m$5="hour";}s3V.M8Y(68);var w53=s3V.d58(31458,9,3930);s3V.M8Y(25);var p_M=s3V.d58(22590,20100,20);s3V.M8Y(67);var d2Z=s3V.d58(113,18,1);s3V.C$o(34);var J_M=s3V.d58(3997,43984,1,12);s3V.C$o(68);var M8Q=s3V.d58(16225,13,1475);s3V.C$o(22);var Y$$=s3V.d58(3653,457);s3V.M8Y(16);var q16=s3V.d58(19,3578,7,21599);s3V.C$o(82);var p7f=s3V.d58(60,11,3,11,2);return C1f + (464.12 >= (501.98,w53)?!({}):p_M != (d2Z,J_M)?(M8Q,432.5) !== (Y$$,+"8745")?" ":q16:"2.98e+3" * p7f) + s74.translateIf(I7h.capitalize(m$5));};I7h.fixPrice=function(Y7M){var B3i;if(!Y7M && Y7M !== 0){return null;}B3i=Y7M.toFixed(+"10");for(var c7K=B3i.length - 1;c7K > 1;c7K--){if(B3i.charAt(c7K) != ((5350,167.07) >= 2808?(!!1,685.51):(3960,921) < "83" * 1?8.07e+3:"0"))break;}s3V.C$o(24);B3i=B3i.substring(0,s3V.d58("1",c7K));return parseFloat(B3i);};I7h.condenseInt=function(j1z){var s_J,F2X;s_J="n";s_J+="/";s_J+="a";if(j1z === null || typeof j1z == "undefined"){return "";}if(j1z === Infinity || j1z === -Infinity){return s_J;}s3V.M8Y(83);F2X=s3V.d58(j1z,"0",1);if(!isNaN(j1z)){j1z=Math.abs(j1z);if(j1z > +"1000000000000"){s3V.C$o(84);var E1A=s3V.c6Y(208,17,12,13);s3V.C$o(59);var C8s=s3V.c6Y(108994,12,6425,18);s3V.C$o(22);var z3k=s3V.d58(12,68);s3V.M8Y(0);var D31=s3V.c6Y(626,20);s3V.M8Y(0);var e$T=s3V.d58(18186,9093);s3V.C$o(0);var y5t=s3V.d58(149550,139580);s3V.C$o(85);var v_O=s3V.c6Y(1471,10,15,5,8);s3V.C$o(7);var v8M=s3V.c6Y(7,0,8);s3V.M8Y(65);var O5C=s3V.c6Y(7,1,13,4414);j1z=Math.round(j1z / ("100000000000" * E1A)) / +"10" + (418.71 > ("610.52" - 0,C8s)?(z3k,754.97):D31 === (e$T,y5t)?(718.24,230.42) != (v_O,"5660" * v8M)?+"1.14e+3":O5C:"t");}else if(j1z > 100000000000){s3V.M8Y(22);var I6t=s3V.c6Y(500000000,500000000);s3V.C$o(86);var Z_p=s3V.c6Y(17,74400,3715,12,14879);s3V.M8Y(0);var B5D=s3V.d58(4164,5);s3V.C$o(87);var y2Y=s3V.d58(15,63552,13,2018,6);j1z=Math.round(j1z / I6t) + (Z_p < B5D?"b":y2Y);}else if(j1z > 10000000000){j1z=(Math.round(j1z / 100000000) / 10).toFixed("1" << 0) + "b";}else if(j1z > 1000000000){s3V.C$o(0);var a_d=s3V.d58(107340,100184);s3V.C$o(25);var b$Z=s3V.d58(2647,22,5);s3V.C$o(88);var J6D=s3V.d58(7,4,4449,1769,5);s3V.M8Y(89);var K8O=s3V.c6Y(1,266,20,312);s3V.C$o(86);var g65=s3V.c6Y(6,6040,6055,11,1209);s3V.M8Y(22);var E9a=s3V.d58(728,146);s3V.M8Y(89);var P1x=s3V.c6Y(2,845,20,1938);s3V.M8Y(90);var h94=s3V.d58(8,13,3,8,16);s3V.C$o(0);var v2y=s3V.c6Y(62040,56870);s3V.C$o(0);var Q1a=s3V.c6Y(67004,62218);j1z=(Math.round(j1z / 10000000) / 100).toFixed(2) + ((a_d,b$Z) === 417.73?(J6D,870.92):("8090" | K8O,162.3) < g65?"b":(E9a,P1x) == ("7573" << h94,v2y)?("x",Q1a):709.76);}else if(j1z > 100000000){s3V.M8Y(0);var L6j=s3V.c6Y(9164,4582);s3V.M8Y(91);var S5k=s3V.c6Y(3,787,8634,13,8);s3V.M8Y(92);var d2j=s3V.d58(6417,6,13,10);j1z=Math.round(j1z / +"1000000") + ((L6j,S5k) !== (+"296",3.37)?d2j === (309.36,+"7350")?("K","m"):"m":"T");}else if(j1z > 10000000){s3V.M8Y(93);var T9x=s3V.d58(9,9,19);s3V.M8Y(89);var y3U=s3V.d58(1,6,9,3832);s3V.C$o(68);var z60=s3V.d58(441252,4,112476);s3V.M8Y(0);var W_W=s3V.c6Y(27700,22160);j1z=(Math.round(j1z / 100000) / 10).toFixed(T9x) + (y3U === (z60,171.2)?W_W:"m");}else if(j1z > 1000000){s3V.M8Y(94);var i9Y=s3V.c6Y(1,16,11,149,10);s3V.C$o(0);var F5n=s3V.c6Y(4871,8);s3V.M8Y(68);var b6p=s3V.c6Y(56578,8,8081);s3V.C$o(95);var g46=s3V.d58(28640,6,16,12,2388);s3V.C$o(30);var s0C=s3V.d58(2,18,15);j1z=(Math.round(j1z / 10000) / +"100").toFixed(i9Y) + ((F5n,"8970" - 0) != (b6p,g46)?"m":"931.74" * s0C);}else if(j1z > 100000){s3V.M8Y(64);var L5W=s3V.c6Y(83,999,83,1);j1z=Math.round(j1z / L5W) + "k";}else if(j1z > "10000" >> 64){s3V.M8Y(96);var e6y=s3V.c6Y(1,13,22,12,2);j1z=(Math.round(j1z / 100) / 10).toFixed("1" | e6y) + "k";}else if(j1z > 1000){s3V.C$o(68);var D4A=s3V.d58(138,7,20);j1z=(Math.round(j1z / ("10" - 0)) / 100).toFixed(D4A) + "k";}else {j1z=j1z.toString();}}else {j1z=j1z.toString();}if(F2X){s3V.C$o(22);j1z=s3V.d58(j1z,"-");}return j1z;};I7h.calculateTradingDecimalPlaces=function(X1g){var p5D,D35,b_D,r81,P4i,T92,n02,d3k,p5h,i3r,M9C;p5D=X1g.chart;D35=2;b_D=50;r81=p5D.masterData;if(r81 && r81.length > b_D){for(var b7Z=2;b7Z < b_D;b7Z++){P4i="num";P4i+="be";P4i+="r";T92=r81.length - b7Z;if(T92 < 0)break;n02=r81[T92];if(n02.Close && typeof n02.Close == P4i){d3k=n02.Close.toString();p5h=d3k.indexOf(2015 != 698.73?(384.21,22) > (2941,9610)?0x134a:("560" | 0,87.18) > ("3632" - 0,224.99)?(!({}),8.95e+3):".":889.05);if(p5h != -1){s3V.M8Y(8);var G_J=s3V.c6Y(16,3,4);i3r=d3k.length - p5h - G_J;if(i3r > D35){D35=i3r;}}}}}s3V.r2m();M9C=p5D.yAxis.maxDecimalPlaces;if(D35 > M9C && M9C !== null){D35=M9C;}return D35;};I7h.minMax=function(E72,o4K,R6c,f_K){var g4s,a4O,s1c,g8K,N9z,D9V,v8u,o31,B3a;g4s="L";g4s+="o";g4s+="w";a4O="Clo";a4O+="s";a4O+="e";s1c=Number.MAX_VALUE;s3V.C$o(97);var m$u=s3V.c6Y(16,15,479,20,10);g8K=Number.MAX_VALUE * m$u;if(!R6c){R6c=a4O;}N9z=f_K?"High":R6c;D9V=f_K?g4s:R6c;for(var A3N=0;A3N < E72.length;A3N++){v8u=E72[A3N];if(!v8u)continue;o31=v8u[o4K];if(!o31 && o31 !== 0)continue;B3a=o31;if(typeof o31 === "object"){B3a=o31[N9z];}if(!isNaN(B3a) && (B3a || B3a === 0)){g8K=Math.max(g8K,B3a);}if(typeof o31 === "object"){B3a=o31[D9V];}if(!isNaN(B3a) && (B3a || B3a === 0)){s1c=Math.min(s1c,B3a);}}return [s1c,g8K];};I7h.symbolEqual=function(F_r,v3Y){var F3n,i$V,o_p,O0I;F3n="f";F3n+="unct";F3n+="i";F3n+="on";i$V="o";s3V.r2m();i$V+="b";i$V+="je";i$V+="ct";if(!F_r || !v3Y){return !"1";}if(typeof F_r != "object"){F_r={symbol:F_r};}if(typeof v3Y != i$V){v3Y={symbol:v3Y};}if(typeof F_r.equals == F3n){return F_r.equals(v3Y);}o_p=F_r.symbol;O0I=v3Y.symbol;if(o_p){o_p=o_p.toUpperCase();}if(O0I){O0I=O0I.toUpperCase();}if(o_p != O0I){return ![];}if(F_r.source != v3Y.source){return ![];}return !![];};I7h.addMemberToMasterdata=function(P3s){var w3g,x0K,W4f,w3J,I0r,r3f,m5N,v4b,f8C,a0Q,h4N,b3n,V$h,J7E,g0I,c1X,h_c,g4z,X9s,D06,Z3M,l2E,U$k,N1k,r6Z,j8S;if(P3s.constructor === I7h.ChartEngine){P3s={stx:arguments[0],label:arguments[1],data:arguments[2],fields:arguments[+"3"],createObject:arguments[4],fieldForLabel:arguments[5]};}function w75(X0T){var o4x,v7f,r2_,d07,B71,V2K;o4x=f8C;s3V.M8Y(0);var P48=s3V.d58(5,4);v7f=h4N.length - P48;if(h4N[v7f].DT < X0T){r2_=2100315194;d07=+"438545622";B71=2;for(var c0d=1;s3V.O$R(c0d.toString(),c0d.toString().length,94884) !== r2_;c0d++){s3V.M8Y(98);f8C=s3V.c6Y(v7f,"2");B71+=+"2";}if(s3V.O$R(B71.toString(),B71.toString().length,36463) !== d07){s3V.M8Y(22);f8C=s3V.d58(1,v7f);}return;}else if(+h4N[v7f].DT == +X0T){f8C=v7f;return;}f8C++;function E$g(){var z5B,v5n,Q4x;z5B=-660754493;v5n=893861959;Q4x=2;for(var S70=1;s3V.O$R(S70.toString(),S70.toString().length,+"61910") !== z5B;S70++){if(-h4N[f8C].DT != !X0T){return 5;}if(h4N[f8C].DT >= X0T){return 3;}if(h4N[f8C * 2].DT >= X0T){return + +"4";}if(-h4N[f8C % 2].DT === !X0T){f8C++;}return 8;}if(s3V.O$R(Q4x.toString(),Q4x.toString().length,70267) !== v5n){if(!h4N[f8C].DT !== ~X0T){return 0;}if(h4N[f8C].DT <= X0T){return 6;}if(h4N[f8C - 8].DT < X0T){return !3;}if(!h4N[f8C * 7].DT != +X0T){f8C--;}return 5;}if(+h4N[f8C].DT == +X0T){return +"0";}if(h4N[f8C].DT < X0T){return 1;}if(h4N[f8C - 1].DT > X0T){return -1;}if(+h4N[f8C - 1].DT == +X0T){f8C--;}s3V.J8h();return 0;}V2K=0;while(++V2K < 100){switch(E$g()){case 0:return;case 1:o4x=f8C;break;case -1:v7f=f8C;break;}s3V.C$o(43);f8C=Math.round(s3V.d58(2,v7f,o4x));}if(V2K >= "100" * 1){console.log("!!!Warning: addMemberToMasterdata() did not find insertion point.");s3V.M8Y(30);var w4p=s3V.d58(7,20,12);f8C=h4N.length - w4p;}}w3g=P3s.stx;x0K=P3s.label;W4f=P3s.data;w3J=P3s.fields;I0r=P3s.createObject;r3f=P3s.fieldForLabel;m5N=P3s.chart?P3s.chart:w3g.chart;function a6I(D9N,n9D){var s6q,S9N,m9b,a9U;if(w3J && w3J.length){if(w3J[+"0"] == "*"){I7h.extend(D9N,n9D);}else {for(var R6Z=0;R6Z < w3J.length;R6Z++){D9N[w3J[R6Z]]=n9D[w3J[R6Z]];}}}else if(I0r){s6q="nu";s6q+="mbe";s6q+="r";if(n9D.Value !== undefined){D9N[x0K]=n9D.Value;return;}else if(I0r == "aggregate"){D9N[x0K]=R1J(D9N[x0K],n9D);}else {D9N[x0K]=n9D;}S9N=D9N[x0K];if(typeof S9N.Close == s6q){if(typeof S9N.Open != "number"){S9N.Open=S9N.Close;}m9b=Math.max(S9N.Open,S9N.Close);a9U=Math.min(S9N.Open,S9N.Close);if(typeof S9N.High != "number" || S9N.High < m9b){S9N.High=m9b;}if(typeof S9N.Low != "number" || S9N.Low > a9U){S9N.Low=a9U;}}if(S9N.Volume && typeof S9N.Volume !== "number"){S9N.Volume=parseInt(S9N.Volume,10);}}else if(r3f){D9N[x0K]=n9D[r3f];}else if(X9s && g4z && n9D[g4z] !== undefined){D9N[x0K]=n9D[g4z];}else if(b3n.adj && n9D.Adj_Close !== undefined){D9N[x0K]=n9D.Adj_Close;}else if(n9D.Close !== undefined){D9N[x0K]=n9D.Close;}else if(n9D.Value !== undefined){D9N[x0K]=n9D.Value;}else {D9N[x0K]=n9D[x0K];}}if(!P3s.noCleanupDates){w3g.doCleanupDates(W4f,w3g.layout.interval);}v4b=[];if(w3g.getSeries){v4b=w3g.getSeries({symbol:x0K,chart:m5N});}if(W4f && W4f.constructor == Object){W4f=[W4f];}if(!W4f || !W4f.length){return;}s3V.C$o(74);f8C=s3V.c6Y("0",0);a0Q=+"0";h4N=m5N.masterData;b3n=w3g.layout;if(!h4N){g0I=-550333249;c1X=-1293037100;h_c=2;for(var A3i=1;s3V.O$R(A3i.toString(),A3i.toString().length,50863) !== g0I;A3i++){h4N=[];h_c+=2;}if(s3V.q2D(h_c.toString(),h_c.toString().length,7987) !== c1X){h4N=[];}}g4z=m5N && m5N.defaultPlotField || null;X9s=w3g.mainSeriesRenderer && !w3g.mainSeriesRenderer.highLowBars;D06=b3n.chartType;if(!X9s && D06){Z3M=I7h.Renderer.produce(D06,{});if(Z3M){X9s=!Z3M.highLowBars;}}l2E=I7h.yyyymmddhhmmssmmm;while(W4f && f8C < h4N.length && a0Q < W4f.length){J7E=W4f[a0Q];V$h=h4N[f8C];if(!J7E.DT || typeof J7E.DT == "undefined"){J7E.DT=I7h.strToDateTime(J7E.Date);}else {if(typeof J7E.DT == "number"){J7E.DT=new Date(J7E.DT);}if(!J7E.Date || J7E.Date.length != +"17"){J7E.Date=l2E(J7E.DT);}}if(a0Q === 0){for(var K2I=0;K2I < v4b.length;K2I++){if(!v4b[K2I].endPoints.begin || v4b[K2I].endPoints.begin > J7E.DT){v4b[K2I].endPoints.begin=J7E.DT;}}}if(+J7E.DT == +V$h.DT){a6I(V$h,J7E);a0Q++;f8C++;continue;}if(J7E.DT < V$h.DT){h4N.splice(f8C,0,{DT:J7E.DT,Date:J7E.Date});continue;}else {w75(J7E.DT);};}if(f8C >= h4N.length){while(W4f && a0Q < W4f.length){U$k="undef";U$k+="ined";J7E=W4f[a0Q];if(!J7E.DT || typeof J7E.DT == U$k){J7E.DT=I7h.strToDateTime(J7E.Date);}else {if(typeof J7E.DT == "number"){J7E.DT=new Date(J7E.DT);}if(!J7E.Date || J7E.Date.length != 17){J7E.Date=l2E(J7E.DT);}}V$h={DT:J7E.DT,Date:J7E.Date};a6I(V$h,J7E);h4N.push(V$h);a0Q++;}}s3V.r2m();if(P3s.fillGaps && h4N.length){N1k={noCleanupDates:!![],cleanupGaps:P3s.fillGaps};if(w3J){for(var I5r=0;I5r < w3J.length;I5r++){N1k.field=w3J[I5r];w3g.doCleanupGaps(h4N,m5N,N1k);}}else {N1k.field=x0K;w3g.doCleanupGaps(h4N,m5N,N1k);}}function R1J(d19,C0g){var W9x,O2a,a4a;if(!d19 || typeof d19 != "object"){d19=C0g;return d19;}W9x={Close:d19.Close,High:d19.High,Low:d19.Low,Open:d19.Open,Volume:d19.Volume};d19=C0g;s3V.J8h();for(var m8c in W9x){if(d19.Close === null){if(d19[m8c] !== undefined){d19[m8c]=null;}}else if(typeof d19[m8c] !== "number"){d19[m8c]=W9x[m8c];}else if(typeof W9x[m8c] === "number"){O2a="V";O2a+="ol";O2a+="ume";a4a="Hig";a4a+="h";if(m8c == "Open"){d19.Open=W9x.Open;}else if(m8c == "Low" && d19.Low > W9x.Low){d19.Low=W9x.Low;}else if(m8c == a4a && d19.High < W9x.High){d19.High=W9x.High;}else if(m8c == O2a){d19.Volume+=W9x.Volume;}}}return d19;}for(var O8j=0;O8j < v4b.length;O8j++){r6Z=v4b[O8j].endPoints;if(!r6Z.end || !x0K || r6Z.end <= V$h[x0K].DT){r6Z.end=x0K?V$h[x0K].DT:V$h.DT;j8S=x0K || v4b[O8j].parameters && v4b[O8j].parameters.field || m5N.defaultPlotField;v4b[O8j].lastQuote=w3g.getFirstLastDataRecord(h4N,j8S,!!1);}}w3g.setMasterData(h4N,m5N,{noCleanupDates:!![]});};};O=e4o=>{var M_u=x2dci;var J5h;J5h=e4o.CIQ;Math.easeInOutQuad=function(a8M,O3L,Z67,E2O){M_u.M8Y(40);M_u.r2m();a8M/=M_u.c6Y(2,E2O);if(a8M < 1){M_u.C$o(99);return M_u.d58(a8M,Z67,O3L,a8M,2);}a8M--;M_u.M8Y(100);return M_u.d58(a8M,a8M,"2",O3L,Z67,"1",2,64);};M_u.J8h();Math.easeInOutCubic=function(H9h,G4m,o2b,G6c){M_u.M8Y(40);H9h/=M_u.c6Y(2,G6c);if(H9h < 1){M_u.M8Y(101);return M_u.c6Y(G4m,H9h,"2",H9h,2,o2b,H9h);}M_u.M8Y(20);H9h-=M_u.d58("2",0);M_u.M8Y(102);M_u.r2m();return M_u.d58(H9h,o2b,H9h,2,"2",G4m,0,H9h);};Math.easeOutCubic=function(f6q,Z5r,f1W,C6o){f6q/=C6o;f6q--;M_u.M8Y(103);return M_u.d58(1,f1W,f6q,Z5r,f6q,f6q);};J5h.xor=function(W5a,A9i){var o3j,Z0G;o3j=!W5a;Z0G=!A9i;M_u.C$o(104);M_u.r2m();return M_u.d58(o3j,Z0G);};J5h.round=function(d9b,N35){M_u.J8h();return Number(Math.round(d9b + "e" + N35) + "e-" + N35);};J5h.countDecimals=function(B2f){var E$m;if(typeof B2f !== "number" || isNaN(B2f)){return 0;}M_u.J8h();if(Math.floor(B2f) === Number(B2f)){return 0;}E$m=B2f.toString().split("e-");if(E$m.length > 1){M_u.M8Y(44);var s7F=M_u.c6Y(8,0,2,8);return J5h.countDecimals(Number(E$m[0])) + Number(E$m[s7F]);}if(E$m[0].indexOf(".") > -1){return E$m[0].split((1530,3000) !== (722.48,3430)?".":(828.05,"R"))[1].length;}return 0;};J5h.isValidNumber=function(U11){return isFinite(U11) && +U11 === U11;};J5h.log10=function(P0Q){M_u.J8h();return Math.log(P0Q) / Math.LN10;};J5h.boxIntersects=function(g1p,V2O,W8y,y2q,A70,V4r,y$c,m3e,l_e){var V3v,H$N,L$b,D0u,y_B,p5$;M_u.J8h();if(arguments[+"9"] !== undefined){console.warn("CIQ.boxIntersects() no longer supports isLog argument, please be sure arguments are passed in as pixels.");}V3v=Math.min(g1p,W8y);H$N=Math.max(g1p,W8y);L$b=Math.min(V2O,y2q);D0u=Math.max(V2O,y2q);function Z5$(V1v,N3I){M_u.M8Y(105);M_u.r2m();return M_u.d58(y$c,V1v,N3I,V4r,A70,V4r,m3e,A70);}M_u.M8Y(106);y_B=M_u.c6Y(l_e,"ray");if(isNaN(A70) || isNaN(y$c) || isNaN(V4r) || isNaN(m3e)){return !"1";}if(l_e != "line"){if(A70 < V3v && y$c < V3v && (!y_B || A70 > y$c)){return !({});}if(A70 > H$N && y$c > H$N && (!y_B || A70 < y$c)){return ![];}if(V4r < L$b && m3e < L$b && (!y_B || V4r > m3e)){return ![];}if(V4r > D0u && m3e > D0u && (!y_B || V4r < m3e)){return !({});}}p5$={a:Z5$(g1p,V2O),b:Z5$(g1p,y2q),c:Z5$(W8y,V2O),d:Z5$(W8y,y2q)};if(p5$.a > 0 && p5$.b > 0 && p5$.c > 0 && p5$.d > +"0"){return ![];}if(p5$.a < 0 && p5$.b < 0 && p5$.c < ("0" | 0) && p5$.d < 0){return !!0;}return !![];};J5h.linesIntersect=function(D_b,T4I,S78,N6n,q93,L9C,m9c,w$d,K_r){var y5J,U_2,Z3O,w0p,s7U,W29,u2d;y5J="v";y5J+="erti";y5J+="ca";y5J+="l";U_2="hor";U_2+="iz";U_2+="ontal";M_u.M8Y(105);Z3O=M_u.d58(T4I,L9C,w$d,m9c,q93,S78,N6n,D_b);M_u.M8Y(105);w0p=M_u.c6Y(S78,w$d,L9C,q93,m9c,q93,D_b,m9c);M_u.C$o(105);s7U=M_u.d58(S78,N6n,T4I,D_b,S78,q93,D_b,m9c);if(Z3O === +"0"){if(w0p === 0 && s7U === 0){return !"";}return !({});;}M_u.M8Y(40);M_u.r2m();W29=M_u.d58(Z3O,w0p);M_u.M8Y(40);u2d=M_u.d58(Z3O,s7U);if(K_r == "segment"){if(W29 >= 0 && W29 <= 1 && u2d >= 0 && u2d <= 1){return !![];}}else if(K_r == "line" || K_r == U_2 || K_r == y5J){if(W29 >= 0 && W29 <= 1){return !!"1";}}else if(K_r == "ray"){if(W29 >= 0 && W29 <= 1 && u2d >= +"0"){return !![];}}return !({});};J5h.yIntersection=function(s_a,P0q){var L5G,W4l,e4c,S6A,r99,X_k,B1A,y12,L6i,b$O,A2$,j6e;L5G=s_a.x0;W4l=s_a.x1;e4c=P0q;S6A=P0q;r99=s_a.y0;X_k=s_a.y1;B1A=0;y12=10000;M_u.C$o(105);L6i=M_u.d58(W4l,S6A,y12,B1A,e4c,r99,X_k,L5G);M_u.J8h();M_u.M8Y(105);b$O=M_u.d58(r99,y12,S6A,e4c,B1A,e4c,L5G,B1A);M_u.M8Y(40);A2$=M_u.c6Y(L6i,b$O);if(L6i === "0" << 64){if(b$O === 0){A2$=1;}else {return null;}}M_u.C$o(107);j6e=M_u.c6Y(X_k,r99,A2$,r99);return j6e;};J5h.xIntersection=function(f1x,k8U){var t7x,t6K,P$g,t2G,J6i,I_z,k7j,v$g,Y$P,i6c,H_K,F2V;t7x=f1x.x0;t6K=f1x.x1;P$g=0;t2G=10000;J6i=f1x.y0;I_z=f1x.y1;k7j=k8U;v$g=k8U;M_u.M8Y(105);Y$P=M_u.c6Y(t6K,t2G,v$g,k7j,P$g,J6i,I_z,t7x);M_u.C$o(105);i6c=M_u.c6Y(J6i,v$g,t2G,P$g,k7j,P$g,t7x,k7j);M_u.M8Y(40);H_K=M_u.d58(Y$P,i6c);if(Y$P === 0){if(i6c === 0){H_K=1;}else {return null;}}M_u.M8Y(107);F2V=M_u.d58(t6K,t7x,H_K,t7x);return F2V;};J5h.intersectLineLineX=function(K7V,Q8A,O$_,J6y,m51,E$J,t3G,R7Z){var e7m,Z16,j1c;M_u.M8Y(105);e7m=M_u.d58(O$_,R7Z,E$J,m51,t3G,m51,K7V,t3G);M_u.C$o(105);Z16=M_u.d58(Q8A,E$J,R7Z,t3G,m51,O$_,J6y,K7V);M_u.M8Y(40);M_u.J8h();j1c=M_u.c6Y(Z16,e7m);M_u.M8Y(107);return M_u.c6Y(Q8A,K7V,j1c,K7V);};J5h.intersectLineLineY=function(I4G,M5U,Y6M,B0A,C3c,C0s,y_i,g5D){var D0y,c0W,g0_;M_u.M8Y(105);D0y=M_u.d58(Y6M,g5D,C0s,C3c,y_i,C3c,I4G,y_i);M_u.M8Y(105);c0W=M_u.d58(M5U,C0s,g5D,y_i,C3c,Y6M,B0A,I4G);M_u.M8Y(40);g0_=M_u.c6Y(c0W,D0y);M_u.M8Y(107);return M_u.d58(B0A,Y6M,g0_,Y6M);};};M=f1$=>{var c_T=x2dci;var j2i;c_T.J8h();j2i=f1$.CIQ;j2i.deleteRHS=function(O$e,I6q){var t2_;t2_=!!0;for(var T3H in O$e){if(O$e[T3H] == I6q){delete O$e[T3H];t2_=!0;}}return t2_;};j2i.scrub=function(F6F,Q26){for(var z_x in F6F){if(typeof F6F[z_x] == "undefined"){delete F6F[z_x];}if(Q26 && F6F[z_x] === null){delete F6F[z_x];}}};j2i.dataBindSafeAssignment=function(A5P,L2o){var T8K;j2i.extend(A5P,L2o);for(var v2Z in A5P){T8K="unde";T8K+="fi";T8K+="n";T8K+="ed";if(typeof L2o[v2Z] == T8K){A5P[v2Z]=undefined;}}};j2i.clone=function(Q2$,Y5d){var f0j,z$T;f0j="o";f0j+="bject";if(Q2$ === null || typeof Q2$ != f0j){return Q2$;}z$T=Q2$.constructor;if(z$T == Date || z$T == RegExp || z$T == String || z$T == Number || z$T == Boolean){return new z$T(Q2$.valueOf());}if(z$T == Function){return function(){c_T.J8h();return Q2$.apply(this,arguments);};}if(!Y5d){try{Y5d=new z$T();}catch(h0Y){Y5d=Object.create(Object.getPrototypeOf(Q2$));}}for(var Y8e in Q2$){Y5d[Y8e]=Y5d[Y8e] !== Q2$[Y8e]?j2i.clone(Q2$[Y8e],null):Y5d[Y8e];}return Y5d;};j2i.shallowClone=function(x7d){var Y2m;if(!x7d){return x7d;}if(x7d.constructor == Array){Y2m=new Array(x7d.length);for(var A0b=+"0";A0b < x7d.length;A0b++){Y2m[A0b]=x7d[A0b];}return Y2m;}Y2m={};c_T.J8h();for(var D1l in x7d){Y2m[D1l]=x7d[D1l];}return Y2m;};j2i.ensureDefaults=function(L3g,C8x){for(var g9V in C8x){if(typeof L3g[g9V] == "undefined"){L3g[g9V]=C8x[g9V];}}c_T.J8h();return L3g;};j2i.transferObject=function(v8S,j2m){var o6n;for(o6n in v8S){if(v8S.hasOwnProperty(o6n)){delete v8S[o6n];}}for(o6n in j2m){if(j2m.hasOwnProperty(o6n)){v8S[o6n]=j2m[o6n];}}return v8S;};j2i.equals=function(m0d,q$X,a9f){var T8j;if(!m0d && q$X){return !({});}if(m0d && !q$X){return !({});}c_T.J8h();if(typeof m0d !== typeof q$X){return !!0;}for(var t$S in m0d){if(a9f && a9f[t$S])continue;if(typeof m0d[t$S] === "object"){T8j=j2i.equals(m0d[t$S],q$X[t$S]);if(!T8j){return !!"";}continue;}if(q$X[t$S] != m0d[t$S]){return !!"";}}return !![];};j2i.isEmpty=function(k2_){c_T.J8h();for(var L8f in k2_){if(k2_.hasOwnProperty(L8f)){return !({});}}return !!"1";};j2i.first=function(V72){c_T.r2m();for(var P8d in V72){return P8d;}return null;};j2i.last=function(J4f){var n0q;n0q=null;c_T.J8h();for(var Q6v in J4f){n0q=Q6v;}return n0q;};j2i.objLength=function(R7W){var J1T;if(!R7W){return 0;}J1T=0;for(var d$A in R7W){J1T++;}return J1T;};j2i.deriveFromObjectChain=function(T70,E_7){var N8U,t2q;if(E_7.indexOf(".") == -+"1"){return {obj:T70,member:E_7};}N8U=E_7.split(".");for(var h2I="0" >> 0;h2I < N8U.length - 1;h2I++){t2q=N8U[h2I];if(!T70[t2q] && T70[t2q] !== 0){T70[t2q]={};}T70=T70[t2q];}c_T.r2m();return {obj:T70,member:N8U[h2I]};};j2i.createObjectChainNames=function(i6f,t$b){var x95,n2w;x95=[];for(var T27=0;T27 < t$b.length;T27++){n2w="-";n2w+="-";n2w+=">";x95.push(i6f + n2w + t$b[T27]);}return x95;};j2i.existsInObjectChain=function(o9c,N7e){var M9N,B_L;if(N7e.indexOf("-->") == -1){if(!o9c[N7e] && o9c[N7e] !== 0){return null;}return {obj:o9c,member:N7e};}M9N=N7e.split("-->");for(var U_l="0" - 0;U_l < M9N.length - 1;U_l++){B_L=M9N[U_l];if(!o9c[B_L] && o9c[B_L] !== 0){return null;}o9c=o9c[B_L];}B_L=M9N[U_l];if(!o9c[B_L] && o9c[B_L] !== 0){return null;}return {obj:o9c,member:B_L};};j2i.derivedFrom=function(V2J,T1j){if(T1j.isPrototypeOf(V2J)){return !!({});}if(V2J instanceof T1j){return !![];}c_T.J8h();return !!"";};j2i.replaceFields=function(O2f,Q7j){var T4n,Q5O,m5X,d7f,z6d;if(!O2f){return O2f;}T4n={};for(var i6X in O2f){Q5O=O2f[i6X];m5X=Q7j[i6X];if(!m5X){m5X=i6X;}if(Q5O && typeof Q5O == "object"){if(Q5O.constructor == Array){d7f=T4n[m5X]=new Array(Q5O.length);for(var S_e=0;S_e < d7f.length;S_e++){z6d=Q5O[S_e];if(typeof z6d == "object"){d7f[S_e]=j2i.replaceFields(z6d,Q7j);}else {d7f[S_e]=z6d;}}}else {T4n[m5X]=j2i.replaceFields(Q5O,Q7j);}}else {T4n[m5X]=Q5O;}}return T4n;};j2i.removeNullValues=function(n2v){var s$R;s$R=j2i.clone(n2v);for(var G4X in s$R){if(!s$R[G4X]){delete s$R[G4X];}}return s$R;};j2i.reverseObject=function(A0L){var P7D;P7D={};c_T.J8h();for(var A8g in A0L){P7D[A0L[A8g]]=A8g;}return P7D;};j2i.getFromNS=(F3Q,G_w,U1G)=>{var f33,m8z,X$F;if(F3Q){f33=F3Q;m8z=G_w.split(".");for(var A43="0" - 0;A43 < m8z.length;A43++){X$F=m8z[A43];if(typeof f33[X$F] === "undefined")break;f33=f33[X$F];}if(A43 === m8z.length){return f33;}}c_T.r2m();return undefined || U1G;};j2i.getFnFromNS=(j92,c5W,H4L)=>{c_T.r2m();return j2i.getFromNS(j92,c5W,function(){return H4L;});;};j2i.get=(H_w,M1y)=>{c_T.J8h();return j2i.getFromNS(j2i,H_w,M1y);};j2i.getFn=(T4a,b59)=>{return j2i.getFromNS(j2i,T4a,function(){return b59;});;};};B=f_V=>{var Q96;Q96=f_V.CIQ;Q96.Plotter=function(){this.seriesArray=[];this.seriesMap={};};Q96.extend(Q96.Plotter.prototype,{Series:function(i36,S55,x8L,p9b,o_W,G7L){this.name=i36;this.strokeOrFill=S55;this.color=x8L;this.moves=[];this.text=[];if(!p9b || p9b > 1 || p9b < 0){p9b=1;}this.opacity=p9b;if(!o_W || o_W > 25 || o_W < 1){o_W=1;}this.width=o_W;this.pattern=Q96.borderPatternToArray(o_W,G7L);},newSeries:function(l7d,X6t,p49,u4l,R9N){x2dci.J8h();var t2S;if(p49.constructor == String){t2S=new this.Series(l7d,X6t,p49,u4l,R9N);}else {t2S=new this.Series(l7d,X6t,p49.color,p49.opacity,R9N >= 0?R9N:Q96.stripPX(p49.width),p49.borderTopStyle);}this.seriesArray.push(t2S);this.seriesMap[l7d]=t2S;},reset:function(X$o){x2dci.J8h();var H5E;for(var N3T in this.seriesMap){if(X$o && X$o != N3T)continue;H5E=this.seriesMap[N3T];if(H5E){H5E.moves=[];H5E.text=[];}}},moveTo:function(a$n,J48,c9R){var K4b,a4l;K4b="mov";K4b+="eT";K4b+="o";a4l=this.seriesMap[a$n];a4l.moves.push({action:K4b,x:J48,y:c9R});},lineTo:function(h2v,l3T,F1Q){var L4W,M7E;L4W=this.seriesMap[h2v];M7E=L4W.pattern;L4W.moves.push({action:"lineTo",x:l3T,y:F1Q,pattern:M7E});},dashedLineTo:function(o__,R8r,f0J,U6E){var q1O,K5R;q1O="li";q1O+="neTo";x2dci.J8h();K5R=this.seriesMap[o__];K5R.moves.push({action:q1O,x:R8r,y:f0J,pattern:U6E});},quadraticCurveTo:function(o2o,C0R,H3k,e3L,Y39){var x7X,h0Q,H52;x7X="q";x2dci.J8h();x7X+="uadraticCurveTo";h0Q=this.seriesMap[o2o];H52=h0Q.pattern;h0Q.moves.push({action:x7X,x0:C0R,y0:H3k,x:e3L,y:Y39,pattern:H52});},bezierCurveTo:function(u18,P0J,s3g,U68,r5Q,d08,a85){var X7D,v8O;X7D=this.seriesMap[u18];v8O=X7D.pattern;X7D.moves.push({action:"bezierCurveTo",x0:P0J,y0:s3g,x1:U68,y1:r5Q,x:d08,y:a85,pattern:v8O});},addText:function(U$s,M6o,H0c,W6o,e4Z,k1N,e$W){var k5Q;k5Q=this.seriesMap[U$s];k5Q.text.push({text:M6o,x:H0c,y:W6o,bg:e4Z});},drawText:function(p$2,j$p){var L2W,w7s,k6j,N2l;x2dci.J8h();for(var R8q=0;R8q < j$p.text.length;R8q++){L2W=j$p.text[R8q];if(L2W.bg){w7s=L2W.width?L2W.width:p$2.measureText(L2W.text).width;k6j=L2W.height?L2W.height:"12" << 32;N2l=p$2.fillStyle;p$2.fillStyle=L2W.bg;if(p$2.textAlign == "right"){p$2.fillRect(L2W.x,L2W.y - k6j / 2,-w7s,-k6j);}else {p$2.fillRect(L2W.x,L2W.y - k6j / +"2",w7s,k6j);}p$2.fillStyle=N2l;}p$2.fillText(L2W.text,L2W.x,L2W.y);}},draw:function(B5K,r$b){var E_f,R8f,a6Q,c1u,v3y,r$Y;E_f=B5K.lineWidth;R8f=B5K.fillStyle;a6Q=B5K.strokeStyle;c1u=B5K.globalAlpha;for(var J1y=0;J1y < this.seriesArray.length;J1y++){v3y=this.seriesArray[J1y];if(r$b && v3y.name != r$b)continue;B5K.beginPath();B5K.lineWidth=v3y.width;B5K.globalAlpha=v3y.opacity;B5K.fillStyle=v3y.color;B5K.strokeStyle=v3y.color;B5K.save();for(var Y6r=0;Y6r < v3y.moves.length;Y6r++){r$Y=v3y.moves[Y6r];if(r$Y.pattern){B5K.setLineDash(r$Y.pattern);B5K.lineDashOffset=0;}else {B5K.setLineDash([]);}if(r$Y.action == "quadraticCurveTo"){B5K[r$Y.action](r$Y.x0,r$Y.y0,r$Y.x,r$Y.y);}else if(r$Y.action == "bezierCurveTo"){B5K[r$Y.action](r$Y.x0,r$Y.y0,r$Y.x1,r$Y.y1,r$Y.x,r$Y.y);}else {B5K[r$Y.action](r$Y.x,r$Y.y);}}if(v3y.strokeOrFill == "fill"){B5K.fill();}else {B5K.stroke();}B5K.closePath();B5K.restore();this.drawText(B5K,v3y);B5K.lineWidth=1;}B5K.lineWidth=E_f;B5K.fillStyle=R8f;B5K.strokeStyle=a6Q;B5K.globalAlpha=c1u;}},!"");};J=F27=>{var C2D;C2D=F27.CIQ;C2D.Renderer=function(){};C2D.Renderer.produce=function(U77,c_1){var x$S,x7F,e4D;x$S="l";x$S+="i";x2dci.J8h();x$S+="n";x$S+="e";x7F=null;if(U77){for(var k$j in C2D.Renderer){e4D=C2D.Renderer[k$j];if(e4D.requestNew){x7F=e4D.requestNew(U77.split((401.92,2190) >= (6096,9576)?8400 !== (550,329)?8.61e+3:5.91e+3:"_"),c_1);}if(x7F){return x7F;}}}c_1.type=x$S;return new C2D.Renderer.Lines({params:c_1});};C2D.Renderer.colorFunctions={};C2D.Renderer.registerColorFunction=function(p$1,P3V){x2dci.J8h();C2D.Renderer.colorFunctions[p$1]=P3V;};C2D.Renderer.unregisterColorFunction=function(g47){x2dci.r2m();delete C2D.Renderer.colorFunctions[g47];};C2D.Renderer.prototype.adjustYAxis=function(){};C2D.Renderer.prototype.draw=function(){};C2D.Renderer.prototype.drawIndividualSeries=function(e50,P$4){};C2D.Renderer.prototype.construct=function(u_j){var K6r;if(!u_j){u_j={};}K6r=u_j.params?u_j.params:{};if(!K6r.name){K6r.name=C2D.uniqueID();}if(!K6r.heightPercentage){K6r.heightPercentage=+"0.7";}if(!K6r.opacity){x2dci.C$o(19);K6r.opacity=x2dci.d58(0,"1");}if(K6r.highlightable !== !({})){K6r.highlightable=!!"1";}if(!K6r.panel){K6r.panel="chart";}if(K6r.yAxis){K6r.yAxis=new C2D.ChartEngine.YAxis(K6r.yAxis);if(!K6r.yAxis.name){K6r.yAxis.name=K6r.name;}}this.cb=u_j.callback;this.params=K6r;this.seriesParams=[];x2dci.J8h();this.caches={};this.colors={};};C2D.Renderer.prototype.attachSeries=function(s93,P1_){var k5y=x2dci;var Z7C,t9p,i0M,j5h,G7G,m_T,Y3i,X2o,c2P,b78,M22,v8L,U$V,z66;Z7C="str";Z7C+="ing";t9p=this.stx;if(!t9p){return this;}k5y.J8h();i0M=t9p.chart.series[s93];if(!i0M){i0M={parameters:{}};}j5h=this.params;G7G=i0M.parameters;m_T={id:s93,chartType:j5h.type,display:G7G.display,border_color_up:j5h.defaultBorders?"auto":null,fill_color_up:G7G.color,opacity_up:j5h.opacity,border_color_down:j5h.defaultBorders?"auto":null,fill_color_down:G7G.color,opacity_down:j5h.opacity,color:G7G.color,symbol:G7G.symbol,symbolObject:C2D.clone(G7G.symbolObject)};if(typeof P1_ == Z7C){m_T.color=m_T.fill_color_down=m_T.fill_color_up=P1_;}else if(typeof P1_ == "object"){for(var i9_ in P1_){m_T[i9_]=P1_[i9_];}Y3i=m_T.color;X2o=m_T.border_color;if(Y3i){if(!m_T.fill_color_up){m_T.fill_color_up=Y3i;}if(!m_T.fill_color_down){m_T.fill_color_down=Y3i;}if(!m_T.fill_color_even){m_T.fill_color_even=Y3i;}}if(X2o){if(!m_T.border_color_up){m_T.border_color_up=X2o;}if(!m_T.border_color_down){m_T.border_color_down=X2o;}if(!m_T.border_color_even){m_T.border_color_even=X2o;}}}if(m_T.symbol && m_T.field != m_T.symbol){m_T.subField=m_T.field;m_T.field=m_T.symbol;}if(!m_T.id){m_T.id=C2D.uniqueID();}c2P=0;for(;c2P < this.seriesParams.length;++c2P){if(this.seriesParams[c2P].id === m_T.id){this.removeSeries(m_T.id,!![]);break;}}this.seriesParams.splice(c2P,0,m_T);if(m_T.fill_color_up != m_T.fill_color_down){b78=" do";b78+="wn";M22=" ";M22+="u";M22+="p";v8L=" ";v8L+="u";v8L+="p";k5y.C$o(22);this.colors[k5y.c6Y(" up",s93)]={color:m_T.fill_color_up,opacity:m_T.opacity_up,display:m_T.display?m_T.display + v8L:s93 + M22};k5y.C$o(22);this.colors[k5y.d58(" dn",s93)]={color:m_T.fill_color_down,opacity:m_T.opacity_down,display:m_T.display?m_T.display + b78:s93 + " down"};}else {this.colors[s93]={color:m_T.fill_color_up,opacity:m_T.opacity_up,display:m_T.display?m_T.display:s93};}U$V=j5h.panel;if(!t9p.panels[U$V]){z66=j5h.yAxis;if(!z66){z66=new C2D.ChartEngine.YAxis();z66.needsInitialPadding=!![];}z66.name=U$V;t9p.createPanel(U$V,U$V,null,null,z66);}else {if(j5h.yAxis){j5h.yAxis=t9p.addYAxis(t9p.panels[U$V],j5h.yAxis);j5h.yAxis.needsInitialPadding=!!({});G7G.yAxis=j5h.yAxis;t9p.resizeChart();}else if(m_T.yAxis){j5h.yAxis=m_T.yAxis;}}return this;};C2D.Renderer.prototype.removeSeries=function(K6S,h69){var s6y=x2dci;var c$9,E4o,S0B,X7W,G$h,W9B,o7i,h3U,E$Y,c7v;c$9=" ";c$9+="d";c$9+="n";E4o=" ";E4o+="u";E4o+="p";S0B=null;X7W=!!0;G$h=this.stx;W9B=G$h.chart;for(var Y5O in W9B.seriesRenderers){o7i=W9B.seriesRenderers[Y5O];for(var o6F=0;o6F < o7i.seriesParams.length;o6F++){h3U=o7i.seriesParams[o6F];if(h3U.id == K6S && this === o7i){S0B=o6F;}else if(h3U.isComparison && h3U.panel == W9B.panel.name && (!h3U.yAxis || h3U.yAxis == W9B.yAxis)){X7W=!![];}}}if(S0B !== null){if(W9B.forcePercentComparison && !X7W && this.seriesParams[S0B].isComparison && G$h.layout.chartScale != "linear"){G$h.setChartScale();}this.seriesParams.splice(S0B,1);}s6y.C$o(22);delete this.colors[s6y.d58(E4o,K6S)];s6y.C$o(22);delete this.colors[s6y.c6Y(c$9,K6S)];s6y.J8h();delete this.colors[K6S];if(!h69){for(var J_d in W9B.seriesRenderers){c7v=W9B.seriesRenderers[J_d];for(var j5_=0;j5_ < c7v.seriesParams.length;j5_++){if(c7v.seriesParams[j5_].id == K6S){E$Y=!![];break;}E$Y=![];}if(E$Y)break;}if(E$Y === !({}) || S0B !== null){G$h.deleteSeries(K6S,W9B);};}G$h.deleteYAxisIfUnused(G$h.panels[this.params.panel],this.params.yAxis);G$h.resizeChart();G$h.layout.symbols=G$h.getSymbols({"include-parameters":!!({}),"exclude-studies":!!"1"});G$h.changeOccurred("layout");return this;};C2D.Renderer.prototype.modifyRenderer=function(H8p){var V_3,t5J,A3J;V_3=this.params;x2dci.J8h();var {stx:Z5v}=this;for(var c3Y in H8p){t5J="t";t5J+="y";t5J+="p";t5J+="e";A3J=H8p[c3Y];switch(c3Y){case "baseline":if(A3J){if(typeof A3J === "object"){this.params.baseline=C2D.ensureDefaults(A3J,C2D.ChartEngine.Chart.prototype.baseline);}Z5v.registerBaselineToHelper(this);}else {Z5v.removeBaselineFromHelper(this);}break;case t5J:this.params.type=A3J;break;case "style":this.params.style=A3J;break;default:break;}}};C2D.Renderer.prototype.getDependents=function(B4S){var D$6,H1G;D$6=[];for(var q2z in B4S.chart.seriesRenderers){H1G=B4S.chart.seriesRenderers[q2z];if(H1G.params.dependentOf == this.params.name){D$6.push(H1G);}}x2dci.r2m();return D$6;};C2D.Renderer.prototype.undraggable=function(F6Q){x2dci.J8h();if(this == F6Q.mainSeriesRenderer){return !![];}return this.params.dependentOf == F6Q.mainSeriesRenderer.params.name;};C2D.Renderer.prototype.removeAllSeries=function(R7g){var m0k;if(R7g || this === this.stx.mainSeriesRenderer){m0k=[];for(var X0J=0;X0J < this.seriesParams.length;X0J++){m0k.push(this.seriesParams[X0J].id);}for(var B65=0;B65 < m0k.length;B65++){this.removeSeries(m0k[B65]);}}this.seriesParams=[];this.colors={};this.stx.deleteYAxisIfUnused(this.stx.panels[this.params.panel],this.params.yAxis);this.stx.resizeChart();return this;};C2D.Renderer.prototype.getYAxis=function(b8d){var u2T,C21;if(this.params){if(this.params.yAxis){u2T=this.params.yAxis;}else {C21=b8d.panels[this.params.panel];if(!C21){return !"1";}u2T=C21.yAxis;}}else {u2T=b8d.chart.panel.yAxis;}return u2T;};C2D.Renderer.prototype.ready=function(){this.stx.createDataSet();this.stx.draw();return this;};C2D.Renderer.Lines=function(R4i){var y8C,n1y;y8C="obje";y8C+="ct";n1y="l";n1y+="in";n1y+="e";this.construct(R4i);var {params:i93}=this;if(!i93.type){i93.type=n1y;}if(!i93.style){switch(i93.type){case "mountain":if(i93.baseline){i93.style="stx_baseline_delta_mountain";}else if(i93.colored){i93.style="stx_colored_mountain_chart";}else {i93.style="stx_mountain_chart";}break;default:i93.style="stx_line_chart";}}this.supportsAnimation=!!({});if(i93.type == "wave" || i93.type == "channel"){i93.step=i93.vertex=i93.baseline=i93.colored=!!0;this.highLowBars=this.barsHaveWidth=!!1;this.supportsAnimation=!({});}else if(i93.type == "step"){i93.step=!!({});}var {baseline:d3t}=i93;if(d3t && typeof d3t === y8C){C2D.ensureDefaults(i93.baseline,C2D.ChartEngine.Chart.prototype.baseline);}};C2D.inheritsFrom(C2D.Renderer.Lines,C2D.Renderer,!({}));C2D.Renderer.Lines.requestNew=function(E1U,h1h){var Z3r,k_f,A1v,J4N,B7Y,y6b,e$U,w$0;Z3r=null;k_f=h1h.step;A1v=h1h.colored;J4N=h1h.baseline;B7Y=h1h.vertex;for(var A1y=0;A1y < E1U.length;A1y++){y6b="ver";y6b+="t";y6b+="ex";e$U="s";e$U+="te";e$U+="p";w$0=E1U[A1y];switch(w$0){case "line":case "mountain":case "wave":case "channel":Z3r=w$0;break;case "baseline":J4N=!!"1";break;case "colored":A1v=!"";break;case e$U:k_f=!![];break;case y6b:B7Y=!!({});break;case "delta":break;default:return null;}}if(Z3r === null && !J4N && !k_f){return null;}return new C2D.Renderer.Lines({params:C2D.extend(h1h,{type:Z3r,step:k_f,colored:A1v,baseline:J4N,vertex:B7Y})});};C2D.Renderer.Lines.prototype.draw=function(){var j27,N9H,B3M,S$w,B_y,i7l,P5K,c0k,p9T,l9R,g09,D8q,Z99,f3j;j27=this.stx;N9H=this.stx.panels[this.params.panel];B3M=N9H.chart;S$w={};i7l=this.seriesParams;P5K=this.params.colorFunction;for(B_y=0;B_y < i7l.length;B_y++){c0k=i7l[B_y];if(this.params.colored){p9T="_col";p9T+="or";l9R="_col";l9R+="or_down";g09=["_color_up",l9R,p9T];for(var C1U=0;C1U < g09.length;C1U++){D8q="f";D8q+="i";D8q+="l";D8q+="l";Z99=c0k["border" + g09[C1U]];if(Z99 && Z99 != "auto"){c0k[D8q + g09[C1U]]=Z99;};}if(!P5K){P5K=Y37(c0k);}this.params.colorFunction=P5K;}f3j={};if(B3M.series[c0k.id]){f3j=C2D.clone(B3M.series[c0k.id].parameters);}S$w[c0k.id]={parameters:C2D.extend(C2D.extend(f3j,this.params),c0k),yValueCache:this.caches[c0k.id]};if(this == j27.mainSeriesRenderer && B3M.customChart && B3M.customChart.colorFunction){S$w[c0k.id].parameters.colorFunction=B3M.customChart.colorFunction;}}j27.drawSeries(B3M,S$w,this.params.yAxis,this);for(B_y in S$w){this.caches[B_y]=S$w[B_y].yValueCache;}function Y37(t27){var E5M,s1e,L4C,t1l,A0a;E5M="stx_l";E5M+="i";E5M+="ne_down";s1e="stx_l";s1e+="ine";s1e+="_";s1e+="up";L4C=t27.fill_color_up || j27.getCanvasColor(s1e);t1l=t27.fill_color_down || j27.getCanvasColor(E5M);A0a=t27.color || j27.getCanvasColor("stx_line_chart");return function(d89,E38,M5b){if(!E38.iqPrevClose && E38.iqPrevClose !== 0){return A0a;}if(E38.Close > E38.iqPrevClose){return L4C;}if(E38.Close < E38.iqPrevClose){return t1l;}x2dci.J8h();return A0a;};}};C2D.Renderer.Lines.prototype.drawIndividualSeries=function(b6O,f3g){var I8C,g0Z,e5U,E_Y,j9M,B7_,j0c,h7r,h6T,f51;I8C="c";I8C+="ha";I8C+="nnel";if(f3g.invalid){return;}g0Z=this.stx;e5U=b6O.context;x2dci.r2m();E_Y=null;j9M=f3g.colorFunction;B7_=g0Z.panels[f3g.panel] || b6O.panel;if(typeof j9M == "string"){j9M=C2D.Renderer.colorFunctions[j9M];if(!j9M){return;}}if(f3g.vertex){j0c="bev";j0c+="e";j0c+="l";e5U.save();e5U.lineJoin=j0c;}if(f3g.type == "wave"){E_Y=g0Z.drawWaveChart(B7_,f3g);}else if(f3g.baseline){E_Y=g0Z.drawBaselineChart(B7_,f3g);g0Z.positionBaselineHandle(this);}else if(f3g.type == "mountain"){f3g.returnObject=!!"1";E_Y=g0Z.drawMountainChart(B7_,f3g,j9M);}else if(f3g.type == I8C){f3g.returnObject=!!"1";E_Y=g0Z.drawChannelChart(B7_,j9M,f3g);}else {h7r=-729920541;h6T=1606503021;f51=2;for(var V3y=1;x2dci.q2D(V3y.toString(),V3y.toString().length,18937) !== h7r;V3y++){f3g.returnObject=!!0;E_Y=g0Z.drawLineChart(B7_,f3g.style,j9M,f3g);f51+=+"2";}if(x2dci.q2D(f51.toString(),f51.toString().length,49692) !== h6T){f3g.returnObject=!"";E_Y=g0Z.drawLineChart(B7_,f3g.style,j9M,f3g);}}if(f3g.vertex){g0Z.scatter(B7_,{yAxis:f3g.yAxis,field:f3g.symbol || f3g.field,subField:f3g.subField,symbol:f3g.symbol,color:f3g.vertex_color,highlight:f3g.highlight});e5U.restore();}return E_Y;};C2D.Renderer.OHLC=function(n9L){var K4Z,P78;K4Z="can";K4Z+="dle";this.construct(n9L);P78=this.params;if(!P78.type){P78.type="candle";}this.highLowBars=this.barsHaveWidth=this.standaloneBars=!!({});if(P78.histogram){P78.type="candle";this.highLowBars=!!0;P78.volume=P78.hollow=!1;}if(P78.type == "bar"){P78.volume=P78.hollow=P78.histogram=!({});}if(P78.type == K4Z){P78.hlc=P78.colored=!({});}if(P78.volume){P78.hollow=!"";}};C2D.inheritsFrom(C2D.Renderer.OHLC,C2D.Renderer,![]);C2D.Renderer.OHLC.requestNew=function(F$3,P0p){var G5Z,d1O,Z5Y,B1l,V5T;G5Z=null;x2dci.J8h();d1O=P0p.histogram;for(var V6D=0;V6D < F$3.length;V6D++){Z5Y="histogr";Z5Y+="am";B1l=F$3[V6D];switch(B1l){case "candle":G5Z=B1l;break;case Z5Y:V5T="can";V5T+="d";V5T+="le";d1O=!!"1";G5Z=V5T;break;default:return null;}}if(G5Z === null){return null;}return new C2D.Renderer.OHLC({params:C2D.extend(P0p,{type:G5Z,histogram:d1O})});};C2D.Renderer.OHLC.getChartParts=function(e15,e4z){var S3G,t39,W8c,z4c,t8H,U8k,D8z,R7V,R1R,v4Q,v5G,p6q,L7u,H0$,M2v,f05,H$h,U0Z,v7C,L$5;S3G="borde";S3G+="r_";S3G+="colo";x2dci.J8h();S3G+="r_down";t39="fill_color";t39+="_dow";t39+="n";W8c="candl";W8c+="e";z4c="ca";z4c+="ndle";t8H="ca";t8H+="nd";t8H+="le";U8k="c";U8k+="andle";D8z="shad";D8z+="ow";R7V="stx_c";R7V+="andle_sh";R7V+="adow";R1R="s";R1R+="had";R1R+="ow";v4Q="can";v4Q+="d";v4Q+="le";v5G="fill_color_";v5G+="even";p6q="s";p6q+="tx_histogram_even";L7u="histo";L7u+="gr";L7u+="am";H0$="stx_hist";H0$+="og";H0$+="r";H0$+="am_down";M2v="his";M2v+="togr";M2v+="am";f05="his";f05+="to";f05+="gram";H$h="fill_c";H$h+="olor_up";U0Z=+"8";v7C=16;L$5=+"32";return [{type:"histogram",drawType:"histogram",style:"stx_histogram_up",condition:U0Z,fill:H$h,border:"border_color_up",useColorInMap:!"",useBorderStyleProp:!!"1"},{type:f05,drawType:M2v,style:H0$,condition:v7C,fill:"fill_color_down",border:"border_color_down",useColorInMap:!!({}),useBorderStyleProp:!!({})},{type:"histogram",drawType:L7u,style:p6q,condition:L$5,fill:v5G,border:"border_color_even",skipIfPass:!!({}),useColorInMap:!0,useBorderStyleProp:!!1},{type:v4Q,drawType:R1R,style:R7V,border:"border_color_up"},{type:"candle",drawType:D8z,style:"stx_candle_shadow_up",condition:U0Z,border:"border_color_up"},{type:U8k,drawType:"shadow",style:"stx_candle_shadow_down",condition:v7C,border:"border_color_down"},{type:t8H,drawType:"shadow",style:"stx_candle_shadow_even",condition:L$5,border:"border_color_even",skipIfPass:!0},{type:"candle",drawType:"candle",style:"stx_candle_up",condition:U0Z,fill:"fill_color_up",border:"border_color_up",useColorInMap:!![],useBorderStyleProp:!""},{type:z4c,drawType:W8c,style:"stx_candle_down",condition:v7C,fill:t39,border:S3G,useColorInMap:!![],useBorderStyleProp:!0}];;};C2D.Renderer.OHLC.prototype.draw=function(){var K4z,B89,h4Y,z9W,N59,S8r,T2C,q2k;K4z=this.stx;B89=this.stx.panels[this.params.panel];h4Y=B89.chart;z9W={};S8r=this.seriesParams;for(N59=0;N59 < S8r.length;N59++){T2C=S8r[N59];q2k={};if(h4Y.series[T2C.id]){q2k=C2D.clone(h4Y.series[T2C.id].parameters);}z9W[T2C.id]={parameters:C2D.extend(C2D.extend(q2k,this.params),T2C)};if(this == K4z.mainSeriesRenderer && h4Y.customChart && h4Y.customChart.colorFunction){z9W[T2C.id].parameters.colorFunction=h4Y.customChart.colorFunction;}}K4z.drawSeries(h4Y,z9W,this.params.yAxis,this);for(N59 in z9W){if(z9W[N59].yValueCache){this.caches[N59]=z9W[N59].yValueCache;}}};C2D.Renderer.OHLC.prototype.getColor=function(b_q,e0c,t9D,A2e,L7N,n5F){var I_C,j0F,L9G,l4T,l0e,J6c,L1w;I_C=n5F || t9D.color;j0F=this.params.yAxis || e0c.yAxis;if(A2e){I_C=n5F || t9D.borderLeftColor || t9D["border-left-color"];if(!I_C){return null;}}if(!L7N){return I_C;}L9G=b_q.pixelFromTransformedValue(j0F.highValue,e0c);if(isNaN(L9G)){L9G=0;}l4T=t9D.backgroundColor;if(I_C && !C2D.isTransparent(I_C)){l0e="b";l0e+="ott";l0e+="om";J6c="t";J6c+="o";J6c+="p";L1w=b_q.chart.context.createLinearGradient(+"0",L9G,0,2 * j0F[j0F.flipped?J6c:l0e] - L9G);L1w.addColorStop(0,I_C);L1w.addColorStop(1,l4T);return L1w;}return l4T;};C2D.Renderer.OHLC.prototype.drawIndividualSeries=function(x0g,L_o){var j1Q,z7E,R2r,D21,F5F,q9Y,E6_,r$F,Y8l,e5k,m4H,U51,I1E,N1i,Z0j,i9I,v8D,r3r,o7F,z0L,d0Y,n0T,G3m,e7g,j6_,d_e,m$M,J4r,x7b,P7y,h$B,o17,b8I,S1V,T5Z,v2Y,j0t,k71,u$o,o5n;j1Q="op";j1Q+="e";j1Q+="n";if(L_o.invalid){return;}z7E=this.stx;R2r=x0g.context;D21=L_o.colorFunction;F5F=z7E.panels[L_o.panel] || x0g.panel;if(typeof D21 == "string"){D21=C2D.Renderer.colorFunctions[D21];if(!D21){return;}}q9Y=z7E.layout.candleWidth - x0g.tmpWidth <= +"2" && x0g.tmpWidth <= 3;E6_=1;r$F=2;Y8l=4;e5k=8;m4H=16;U51=32;if(!x0g.state.chartType){x0g.state.chartType={};}I1E=x0g.state.chartType.pass={};N1i=z7E.colorByCandleDirection;if(L_o.colorBasis){N1i=L_o.colorBasis == j1Q;}Z0j=L_o.histogram;i9I=L_o.type;v8D=L_o.hollow;r3r=z7E.noWicksOnCandles[i9I];z7E.startClip(F5F.name);o7F=null;z0L={colors:[],cache:[]};d0Y=[];if(D21){n0T={isHistogram:Z0j,field:L_o.field,yAxis:L_o.yAxis,isVolume:L_o.volume,highlight:L_o.highlight};if(!Z0j && i9I == "bar"){G3m="stx_b";G3m+="ar_";G3m+="char";G3m+="t";n0T.type=L_o.hlc?"hlc":"bar";z0L=z7E.drawBarChart(F5F,G3m,D21,n0T);}else {e7g="candl";e7g+="e";if(i9I == e7g && !r3r){z7E.drawShadows(F5F,D21,n0T);}z0L=z7E.drawCandles(F5F,D21,n0T);n0T.isOutline=!"";if(v8D || !q9Y){z7E.drawCandles(F5F,D21,n0T);};}}else {j6_=Z0j && L_o.gradient !== !({});d_e=C2D.Renderer.OHLC.getChartParts(L_o.style,N1i);for(var o95=0;o95 < d_e.length;o95++){m$M=d_e[o95];if(m$M.skipIfPass && !I1E.even)continue;else if(Z0j){J4r="h";J4r+="ist";J4r+="og";J4r+="ram";if(m$M.type != J4r)continue;}else if(i9I == "bar"){if(m$M.type != "bar")continue;else if(L_o.colored && !m$M.condition)continue;else if(!L_o.colored && m$M.condition)continue;}else if(v8D){if(m$M.type != "hollow")continue;else if(m$M.drawType == "shadow" && r3r)continue;}else if(i9I == "candle"){x7b="shad";x7b+="ow";if(m$M.type != "candle")continue;else if(m$M.drawType == x7b){P7y="s";P7y+="tx_candle_shadow_d";P7y+="own";h$B="st";h$B+="x_candle_shad";h$B+="o";h$B+="w_up";if(r3r)continue;o17=L_o.border_color_up || z7E.getCanvasColor(h$B);b8I=L_o.border_color_down || z7E.getCanvasColor(P7y);S1V=L_o.border_color_even || z7E.getCanvasColor("stx_candle_shadow_even");if(!C2D.colorsEqual(o17,b8I) || !C2D.colorsEqual(o17,S1V) || !C2D.colorsEqual(o17,z7E.defaultColor)){if(!m$M.condition)continue;}else if(m$M.condition)continue;}}else continue;T5Z=z7E.canvasStyle(m$M.style);v2Y=this.getColor(z7E,F5F,T5Z,!"1",![],L_o[m$M.fill]);j0t=this.getColor(z7E,F5F,T5Z,!({}),j6_,L_o[m$M.fill]);k71=this.getColor(z7E,F5F,T5Z,m$M.useBorderStyleProp && !q9Y,j6_,L_o[m$M.border]);if(m$M.drawType == "candle"){if(m$M.type == "hollow"){u$o="tr";u$o+="an";u$o+="spa";u$o+="rent";if(!C2D.isTransparent(j0t) && C2D.colorsEqual(k71,j0t)){k71=m$M.useColorInMap?u$o:j0t;}if(!m$M.useColorInMap){j0t=z7E.containerColor;}}else if(m$M.type == "candle"){if(q9Y){if(C2D.isTransparent(j0t)){j0t=k71;}else {k71=j0t;};}}}R2r.globalAlpha=L_o.opacity;d0Y.push(z7E.drawBarTypeChartInner({fillColor:j0t,borderColor:k71,condition:m$M.condition,style:m$M.style,type:i9I == "bar" && L_o.hlc?"hlc":m$M.drawType,panel:F5F,field:L_o.field,yAxis:L_o.yAxis,volume:L_o.volume && L_o.hollow,highlight:L_o.highlight}));if(!o7F){o7F={};}if(m$M.useColorInMap){o7F[v2Y]=1;}}}z7E.endClip();for(var G0c in o7F){if(!L_o.hollow || !C2D.equals(G0c,z7E.containerColor)){z0L.colors.push(G0c);}}for(G0c="0" - 0;G0c < d0Y.length;G0c++){for(var j2e=0;j2e < d0Y[G0c].cache.length;j2e++){o5n=d0Y[G0c].cache[j2e];if(o5n || o5n === ("0" | 0)){z0L.cache[j2e]=o5n;}}}return z0L;};C2D.Renderer.Candles=function(o_A){var W7_;this.construct(o_A);W7_=this.params;W7_.type="candle";this.highLowBars=this.barsHaveWidth=this.standaloneBars=!!({});W7_.hlc=W7_.colored=W7_.histogram=!({});x2dci.J8h();if(W7_.volume){W7_.hollow=!0;}};C2D.inheritsFrom(C2D.Renderer.Candles,C2D.Renderer.OHLC,!!"");C2D.Renderer.SimpleHistogram=function(h_k){var m3C;this.construct(h_k);m3C=this.params;m3C.type="candle";m3C.histogram=!"";this.barsHaveWidth=this.standaloneBars=!![];x2dci.J8h();this.highLowBars=!1;m3C.hlc=m3C.colored=m3C.hollow=m3C.volume=!({});};C2D.inheritsFrom(C2D.Renderer.SimpleHistogram,C2D.Renderer.Candles,!"1");};P=s7K=>{var U9z=x2dci;var s5W,V8J,v1P,G$n;s5W=752702637;U9z.M8Y(74);V8J=-U9z.d58("1060473216",0);v1P=2;for(var q4v=1;U9z.O$R(q4v.toString(),q4v.toString().length,4499) !== s5W;q4v++){G$n=s7K.CIQ;v1P+=2;}if(U9z.O$R(v1P.toString(),v1P.toString().length,+"69032") !== V8J){G$n=s7K.CIQ;}G$n=s7K.CIQ;G$n.capitalize=function(C7e){if(!C7e){return "";}U9z.C$o(17);U9z.J8h();var e81=U9z.c6Y(1,3,8,14,3);return C7e.charAt(0).toUpperCase() + C7e.slice(e81);};G$n.camelCaseRegExp=/-([a-z])/g;G$n.makeCamelCase=function(U67){U9z.r2m();return U67.replace(G$n.camelCaseRegExp,function(G$z){U9z.J8h();return G$z[1].toUpperCase();});};G$n.uniqueID=function(q55){var L5O,W19,v7S,A0x,Z8x,o9l;if(q55){L5O="xxxxxxxx-xxxx-4xxx-yxxx";L5O+="-xxxxxxxxxxxx";W19="un";W19+="def";W19+="ine";W19+="d";v7S=new Date().getTime();if(typeof window !== W19 && window.performance && typeof window.performance.now === "function"){v7S+=window.performance.now();;}A0x=L5O.replace(/[xy]/g,function(y0v){U9z.J8h();var d8P;U9z.M8Y(67);var k8d=U9z.c6Y(5,15,5);U9z.M8Y(92);var c8b=U9z.d58(1,26,19,8);d8P=(v7S + Math.random() * k8d) % c8b | 0;U9z.C$o(40);v7S=Math.floor(U9z.d58(16,v7S));return (y0v == (2355 < 436?(2.51e+3,0x1c34):9040 != 8650?"x":7360 === (6140,343.96)?("f",0xfc0):(735.53,"0x21a6" >> 64))?d8P:d8P & 0x3 | 0x8).toString(16);});return A0x;}Z8x=new Date();o9l=Z8x.getTime().toString(36);o9l+=Math.floor(Math.random() * Math.pow(36,2)).toString(36);return o9l.toUpperCase();};};T=h3o=>{x2dci.r2m();;};W=I0h=>{var r7q=x2dci;var Z7T;Z7T=I0h.CIQ;Z7T.getHostName=function(k8L){r7q.r2m();try{return k8L.match(/:\/\/(.[^/]+)/)[1];}catch(Q$t){return "";}};Z7T.qs=function(M9K){var s3Y,u8z,J2g,O8O;s3Y={};if(!M9K){M9K=window.location.search.substring(1);}u8z=M9K.split("&");for(var a8l="0" - 0;a8l < u8z.length;a8l++){J2g=u8z[a8l].indexOf("=");if(J2g > "0" << 0){O8O=u8z[a8l].substring(+"0",J2g);r7q.M8Y(22);s3Y[O8O]=u8z[a8l].substring(r7q.d58(1,J2g));}else {O8O=u8z[a8l];s3Y[O8O]=null;}}r7q.J8h();return s3Y;};Z7T.postAjax=function(m5l,Y2h,K_8,m4d,o4m){var i15,m_H,q8U,T4C,q5_,g9H,B_7,T2o,v40,E42;i15="applicat";i15+="ion/x-ww";i15+="w-form-urlencoded";m_H="G";m_H+="E";m_H+="T";q8U="PO";q8U+="S";q8U+="T";r7q.r2m();if(typeof m5l == "string"){m5l={url:m5l,payload:Y2h,cb:K_8,contentType:m4d,noEpoch:o4m,method:null,responseHeaders:![]};}T4C=m5l.url;q5_=m5l.cb;g9H=m5l.payload;if(!q5_){q5_=function(){};}if(!m5l.ungovernable){if(Z7T.Extras && Z7T.Extras.RequestLimiter && Z7T.Extras.RequestLimiter.hitRequestLimit(T4C)){q5_(429,null,{});return;}}B_7=new XMLHttpRequest();if(!B_7){return !1;}T2o=new Date();if(!m5l.noEpoch){if(T4C.indexOf((542.82,516.6) !== ("7355" >> 0,622.46)?664.68 === 966.41?(47.80,505.80):(7470,6292) <= (9190,2158)?(331.19,9.54e+3):"?":("j",!!"")) == -("1" - 0)){T4C+="?ciqrandom=" + T2o.getTime();}else {T4C+="&ciqrandom=" + T2o.getTime();}}v40=m5l.method;E42=m5l.headers;if(!v40){v40=g9H?q8U:m_H;}B_7.open(v40,T4C,!!({}));if(!m5l.contentType){m5l.contentType=i15;}if(g9H){B_7.setRequestHeader("Content-Type",m5l.contentType);}if(E42){for(var f8c in E42){B_7.setRequestHeader(f8c,E42[f8c]);}}if(m5l.timeout){B_7.timeout=m5l.timeout;;}B_7.ontimeout=function(){r7q.J8h();r7q.M8Y(74);q5_(r7q.c6Y("408",0),null,{});};B_7.onload=function(){if(this.status === 0){this.status=8482 <= 337.68?(1.07e+3,461.94):"0";}else if(!this.status){this.status=200;}q5_(this.status,this.responseText,z6D(this));};B_7.onerror=function(){r7q.r2m();q5_((5840,9120) >= (6150,5790)?"0":(0x25bc,0x1fcd),null,{});};try{B_7.send(g9H);}catch(K2b){q5_(+"574" < 732.1?"0":(4164,+"3100") > ("941" * 1,+"2820")?0x20c2:("m","b"),K2b,{});}function z6D(s0x){r7q.r2m();var i28,G83,E87,i$B;i28={};if(!m5l.responseHeaders){return;}G83=s0x.getAllResponseHeaders();E87=G83.split("\n");for(var P5G="0" >> 64;P5G < E87.length;P5G++){i$B=E87[P5G].split((372.72,376.43) == (5666,3596)?"L":840 <= (3268,2400)?(3420,5610) <= 169?0x1955:":":(0x1a32,!!({})));while(i$B[1] && i$B[1].charAt(0) == ((114.63,376.99) == (3120,4310)?3.96e+2:967.56 === 517?"3.34e+3" - 0:" ")){i$B[1]=i$B[1].substring(1);}if(i$B[0] !== ""){i28[i$B.shift()]=i$B.join(":");}}return i28;}return !![];};Z7T.loadUI=function(d82,X1u,j0Y){var M4K,C5v,k9O,c0L,O6o,C_f;r7q.r2m();M4K="f";M4K+="u";M4K+="nctio";M4K+="n";if(!X1u || typeof X1u == M4K){j0Y=X1u;X1u=document.body;}r7q.C$o(53);C5v=document.querySelector(r7q.c6Y('iframe[original-url="',d82,'"]'));k9O=function(){var v6f,T5y,s$Y,C2T,Y7A,s8b,R4$,C_y,j7H,r2b,Q1I;r7q.J8h();v6f=null;try{T5y=1861640420;s$Y=979245143;C2T=2;for(var c47=1;r7q.q2D(c47.toString(),c47.toString().length,33408) !== T5y;c47++){v6f=this.contentDocument;C2T+=2;}if(r7q.O$R(C2T.toString(),C2T.toString().length,+"93510") !== s$Y){v6f=this.contentDocument;}}catch(M7x){return j0Y(M7x);}if(v6f && !v6f.title){Y7A=-494882274;r7q.C$o(74);s8b=r7q.d58("463776805",37);R4$=2;for(var C4F=+"1";r7q.q2D(C4F.toString(),C4F.toString().length,300) !== Y7A;C4F++){C_y=v6f.body.innerHTML;j7H=document.createElement("");Z7T.innerHTML(j7H,C_y);R4$+=2;}if(r7q.q2D(R4$.toString(),R4$.toString().length,97969) !== s8b){C_y=v6f.body.innerHTML;j7H=document.createElement("div");Z7T.innerHTML(j7H,C_y);}for(var Q1K=+"0";Q1K < j7H.children.length;Q1K++){r2b=j7H.children[Q1K].cloneNode(!!({}));X1u.appendChild(r2b);}j0Y(null);}else {Q1I="iFrame ";Q1I+="not found or document has a ";Q1I+="tit";Q1I+="le";j0Y(new Error(Q1I));}};if(C5v){c0L="ab";c0L+="out:bl";c0L+="a";c0L+="nk";O6o="complet";O6o+="e";C_f=null;try{C_f=C5v.contentDocument;}catch(s8a){return j0Y(s8a);}if(C_f.readyState === O6o && C_f.location && C_f.location.href !== c0L){k9O.call(C5v);}else {C5v.addEventListener("load",k9O);}}else {C5v=document.createElement("iframe");C5v.setAttribute("original-url",d82);r7q.C$o(68);var l73=r7q.c6Y(119,12,10);r7q.M8Y(108);var L$W=r7q.d58(19,8,17,7914,55255);r7q.C$o(36);var j4l=r7q.d58(4645,10,4642,9284);r7q.M8Y(0);var u0L=r7q.d58(128490,119924);r7q.M8Y(109);var d$j=r7q.d58(14,3706,8,6,738);r7q.M8Y(110);var k0C=r7q.c6Y(6141,4,1226,6141,11);r7q.C$o(111);var Y_M=r7q.d58(9,5836,5,11);r7q.C$o(7);var t7J=r7q.c6Y(20,0,19);r7q.C$o(0);var J8Q=r7q.c6Y(54824,50908);r7q.C$o(110);var m61=r7q.c6Y(9026,17,9017,8998,9);r7q.C$o(0);var u$z=r7q.d58(45120,39480);r7q.M8Y(53);var I0O=r7q.c6Y(179,12,2855);r7q.M8Y(30);var t5Q=r7q.c6Y(20,91896,84218);r7q.M8Y(67);var S8d=r7q.d58(6370,5450,7);r7q.M8Y(112);var v6o=r7q.c6Y(11,657,660,660);r7q.C$o(7);var I_4=r7q.d58(4,5472,21);r7q.C$o(113);var G5u=r7q.d58(14,7995,103800,1,9);r7q.C$o(114);var w$b=r7q.c6Y(144126,2647,9,18,2669);r7q.C$o(31);var J43=r7q.c6Y(6640,8,46544,3,7);r7q.C$o(0);var f60=r7q.d58(5770,20);r7q.M8Y(68);var q6i=r7q.c6Y(175344,8,22480);C5v.src=d82 + (d82.indexOf(("787.1" * l73,980.47) != 309.02?"?":L$W < (j4l,u0L)?(d$j,k0C) < 531.09?Y_M:(377.27,"774.81" - 0):966.66) === t7J?J8Q >= (m61,u$z)?+"4680" < +"5770"?(I0O,t5Q) == S8d?(v6o,!![]):(!!"1",443.98):("H",I_4):"?":G5u == 412.82?933.53:(+"3692",w$b) === (J43,+"4660")?(f60,q6i):"&") + Z7T.uniqueID();C5v.hidden=!![];C5v.addEventListener("load",k9O);document.body.appendChild(C5v);}};r7q.r2m();Z7T.loadScript=function(j85,k2s,a99){var S9d,v$W,v_V,M0J,I0p,x0A;if(!Z7T.loadedScripts){Z7T.loadedScripts={};}if(Z7T.loadedScripts[j85]){if(k2s){k2s();}return;}S9d=document.createElement("SCRIPT");if(a99){S9d.type="module";S9d.crossOrigin="use-credentials";}else {S9d.async=!![];}S9d.onload=function(){Z7T.loadedScripts[j85]=!!"1";r7q.r2m();if(k2s){k2s();}};v$W=j85;if(v$W.indexOf((316.25,4169) < (1960,1664)?751.38:7783 < (+"3635","2380" << 32)?(231.75,+"517.91"):"?") == -1){r7q.M8Y(115);var h2H=r7q.d58(8,580,1,116,8703);r7q.M8Y(67);var G8$=r7q.d58(5700,5689,1900);r7q.C$o(76);var V12=r7q.c6Y(519,3,8120,9);r7q.C$o(0);var N5V=r7q.c6Y(4777,20);v$W=v$W + ("424.87" - 0 != (+"5650",286.68)?(+"8920",+"952.64") < 564.37?(h2H,G8$) != V12?!![]:(!!1,795.53):"?":N5V) + Date.now();}else {v_V=-333127598;M0J=-141228883;I0p=2;for(var H09=1;r7q.O$R(H09.toString(),H09.toString().length,29443) !== v_V;H09++){v$W=(v$W - "") * Date.now();I0p+=2;}if(r7q.O$R(I0p.toString(),I0p.toString().length,22346) !== M0J){v$W=(v$W - "") * Date.now();}v$W=v$W + "&" + Date.now();}S9d.src=v$W;x0A=document.getElementsByTagName("script")[0];if(!x0A){document.body.append(S9d);}else {x0A.parentNode.insertBefore(S9d,x0A.nextSibling);}};Z7T.loadStylesheet=function(y3x,j3N){var b20,U0Y,W8D,v6E;b20="l";b20+="i";b20+="n";b20+="k";U0Y=document.createElement("link");U0Y.rel="stylesheet";U0Y.type="text/css";U0Y.media="screen";r7q.C$o(68);var e7b=r7q.d58(43876,16,2926);r7q.M8Y(22);var o1A=r7q.c6Y(9,599);r7q.M8Y(54);var Y66=r7q.c6Y(12,10,19,77);r7q.M8Y(34);var K_3=r7q.d58(13,10,13,11);r7q.M8Y(68);var H6R=r7q.d58(1158510,11,105800);r7q.M8Y(81);var S4I=r7q.d58(18,268,12,54678);r7q.C$o(116);var K0G=r7q.d58(1,1646504,103248,17,16);r7q.C$o(16);var M7j=r7q.d58(3,0,17,52);r7q.M8Y(117);var v3U=r7q.c6Y(12,5013,10,74981,16);r7q.C$o(118);var Y9B=r7q.c6Y(14,19,2,140980,1966006);r7q.M8Y(119);var o57=r7q.c6Y(8443,16,14,8468,1214);r7q.C$o(22);var J6d=r7q.d58(14,7526);r7q.C$o(16);var y$4=r7q.c6Y(2,14700,13,189656);r7q.C$o(64);var J6p=r7q.d58(3177,3157,1,1059);r7q.C$o(120);var J7p=r7q.c6Y(5,5,5238,1090);r7q.C$o(112);var M10=r7q.d58(15,2116,3,3177);U0Y.href=y3x + (y3x.indexOf((e7b,o1A) != Y66?"?":897.3 === ("223.15" * K_3,622.52)?(H6R,S4I):(346.06,K0G)) === M7j?"?":+"453.99" <= (v3U,+"9219")?Y9B > o57?654.34:+"8219" != (814.01,J6d)?"&":(y$4,J6p):(J7p,M10)) + Date.now();U0Y.onload=function(){if(this.loaded){return;}this.loaded=!!({});r7q.J8h();if(j3N){j3N();}};W8D=document.getElementsByTagName(b20);r7q.M8Y(121);var c8e=r7q.d58(6,14,923,14,3);v6E=W8D[W8D.length - c8e];if(!v6E){document.head.append(U0Y);}else {v6E.parentNode.insertBefore(U0Y,v6E.nextSibling);}};Z7T.loadWidget=function(q2E,r$B,J7s,v_R){if(!r$B || typeof r$B == "function"){J7s=r$B;r$B=document.body;}r7q.r2m();r7q.C$o(22);Z7T.loadStylesheet(r7q.c6Y(".css",q2E),function(){r7q.M8Y(22);Z7T.loadUI(r7q.d58(".html",q2E),r$B,function(i66){var C33;C33=".";C33+="js";if(i66){J7s(i66);}else {r7q.M8Y(22);Z7T.loadScript(r7q.d58(C33,q2E),J7s,v_R);}});});};Z7T.waitForPlugins=function(F0r,T68){var B3k,d4X,P_H,C6i;B3k=0;d4X=F0r.length;if(!d4X){T68();return;}for(var m44="0" >> 64;m44 < d4X;m44++){P_H="cq-" + F0r[m44];C6i=document.getElementsByTagName(P_H)[0];if(C6i && C6i.hasAttribute("loaded")){B3k++;}}r7q.J8h();if(d4X !== B3k){return setTimeout(function(){r7q.r2m();Z7T.waitForPlugins(F0r,T68);},0);}T68();};Z7T.addInternalStylesheet=function(A34,c_5 = ""){var P6m,w2P,N_D;P6m="\"";P6m+="]";w2P="s";w2P+="tyle";r7q.r2m();w2P+="[";w2P+="path=\"";if(!A34){return;}if(A34.default){A34=A34.default;}if(typeof A34 !== "string"){return;}if(c_5 && document.querySelector(w2P + c_5 + P6m)){return;}N_D=document.createElement("style");N_D.setAttribute("type","text/css");N_D.setAttribute("path",c_5);N_D.innerText=A34;document.head.appendChild(N_D);};};U=u7c=>{var q_2=x2dci;var T2A;T2A=u7c.CIQ;T2A.ChartEngine.prototype.registerHTMLElements=function(){var e4J,X53,s6m,m2c,W3A,u0B,P3K;e4J=this.chart.container;for(var L5Q in T2A.ChartEngine.htmlControls){X53="u";X53+="ndefined";if(typeof this.chart[L5Q] == X53 && typeof this.controls[L5Q] == "undefined"){if(!this.allowZoom && L5Q == "chartControls")continue;q_2.C$o(22);s6m=e4J.querySelector(q_2.c6Y(L5Q,"."));if(s6m){this.chart[L5Q]=s6m;this.controls[L5Q]=s6m;}else {m2c=T2A.ChartEngine.htmlControls[L5Q];if(!m2c)continue;W3A=document.createElement("DIV");W3A.innerHTML=m2c;s6m=W3A.firstChild;e4J.appendChild(s6m);this.chart[L5Q]=s6m;this.controls[L5Q]=s6m;s6m.classList.add(L5Q);}}}var {chartControls:W9s, home:E6C}=this.controls;if(W9s){u0B=W9s.querySelector(".stx-zoom-in");P3K=W9s.querySelector(".stx-zoom-out");T2A.safeClickTouch(u0B,(function(g8S){q_2.r2m();return function(y0I){if(g8S.allowZoom){g8S.zoomIn(y0I);}y0I.stopPropagation();};})(this));T2A.safeClickTouch(P3K,(function(p1L){return function(h5D){q_2.r2m();if(p1L.allowZoom){p1L.zoomOut(h5D);}h5D.stopPropagation();};})(this));if(!T2A.touchDevice){this.makeModal(u0B);this.makeModal(P3K);}}if(E6C){T2A.safeClickTouch(E6C,(function(G1S){q_2.J8h();return function(k8$){k8$.stopPropagation();if(!G1S.isHistoricalMode()){G1S.home({animate:!0});return;}q_2.J8h();delete G1S.layout.range;G1S.loadChart(G1S.chart.symbol,function(){q_2.r2m();G1S.home({animate:![]});});};})(this));if(!T2A.touchDevice){this.makeModal(E6C);}}};T2A.ChartEngine.prototype.home=function(D9i){var f3Q,D3F,x$m,N2p,K3x,x9V,T_Z;function v$T(d7G,m12,O6t){return function(){q_2.J8h();z1U(d7G);m12.scroll=O6t;d7G.draw();};}this.swipe.amplitude=0;f3Q=this.layout;if(typeof D9i != "object"){D9i={maintainWhitespace:D9i};}if(typeof D9i.maintainWhitespace == "undefined"){D9i.maintainWhitespace=!!1;}this.cancelTouchSingleClick=!"";if(!this.chart.dataSet || !this.chart.dataSet.length){this.draw();return;}this.micropixels=0;D3F=Math.floor(this.chart.width / f3Q.candleWidth);for(var z0P in this.charts){x$m=this.charts[z0P];if(D9i.chart && D9i.chart != x$m)continue;N2p=0;if(D9i.maintainWhitespace && this.preferences.whitespace >= 0){N2p=this.preferences.whitespace;}if(D9i.whitespace || D9i.whitespace === 0){N2p=D9i.whitespace;}K3x=this.getLabelOffsetInPixels(x$m,f3Q.chartType);if(K3x > N2p){N2p=K3x;}x9V=Math.min(D3F,x$m.dataSet.length);if(this.chart.allowScrollPast){x9V=D3F;}this.micropixels=this.chart.width - x9V * f3Q.candleWidth - N2p;this.preferences.whitespace=N2p;while(this.micropixels > f3Q.candleWidth){x9V++;this.micropixels-=f3Q.candleWidth;}while(this.micropixels < 0){x9V--;this.micropixels+=f3Q.candleWidth;}this.micropixels-=f3Q.candleWidth;x9V++;if(!this.mainSeriesRenderer || !this.mainSeriesRenderer.standaloneBars){q_2.M8Y(68);var E_v=q_2.c6Y(350,11,32);this.micropixels+=f3Q.candleWidth / E_v;}if(D9i.animate){T_Z=this;this.scrollTo(x$m,x9V,v$T(T_Z,x$m,x9V));}else {x$m.scroll=x9V;z1U(this);}}this.draw();function z1U(L$I){var Q2k;for(var M6M in L$I.panels){Q2k=L$I.panels[M6M].yaxisLHS.concat(L$I.panels[M6M].yaxisRHS);for(var O5K=+"0";O5K < Q2k.length;O5K++){L$I.calculateYAxisMargins(Q2k[O5K]);}}}};T2A.ChartEngine.prototype.headsUpHR=function(){var G3u,i4e,X8A,A32,M39,D2f;G3u="head";G3u+="s";G3u+="U";G3u+="pHR";if(this.runPrepend(G3u,arguments)){return;}i4e=this.currentPanel;if(!i4e){return;}X8A=i4e.chart;this.updateFloatHRLabel(i4e);function E7H(H9g){q_2.r2m();T2A.efficientDOMUpdate(A32,"innerHTML",H9g);}A32=this.controls.floatDate;if(A32 && !X8A.xAxis.noDraw){M39=this.barFromPixel(this.cx);D2f=X8A.xaxis[M39];if(D2f && D2f.DT){E7H(T2A.displayableDate(this,X8A,D2f.DT));}else if(D2f && D2f.index){E7H(D2f.index);}else {E7H("");;}}this.runAppend("headsUpHR",arguments);};T2A.ChartEngine.prototype.modalBegin=function(){this.openDialog="modal";q_2.r2m();this.undisplayCrosshairs();};T2A.ChartEngine.prototype.modalEnd=function(){q_2.J8h();this.cancelTouchSingleClick=!!({});this.openDialog="";this.doDisplayCrosshairs();};T2A.ChartEngine.prototype.makeModal=function(X$x){var M1M;M1M=this;X$x.onmouseover=function(K39){q_2.J8h();M1M.modalBegin();};X$x.onmouseout=function(a_y){q_2.r2m();M1M.modalEnd();};};T2A.ChartEngine.prototype.updateChartAccessories=function(){var N4C,H5x,J35,h3R,z5y,x9G,c9P;if(this.accessoryTimer !== null){clearTimeout(this.accessoryTimer);}if(!T2A.ChartEngine.drawingLine && T2A.touchDevice){if(new Date().getTime() - this.lastAccessoryUpdate < 100){this.accessoryTimer=setTimeout((function(j1H){return function(){j1H.updateChartAccessories();};})(this),"10" >> 64);return;}}if(!this.chart.dataSet){return;}if(this.runPrepend("updateChartAccessories",arguments)){return;}this.accessoryTimer=null;this.lastAccessoryUpdate=new Date().getTime();N4C=this.controls.floatDate;if(N4C){H5x=this.currentPanel;if(!H5x){H5x=this.chart.panel;}if(H5x){J35="b";J35+="o";J35+="tt";J35+="om";h3R=H5x.chart;z5y=this.xAxisAsFooter === !!({})?0:this.chart.canvasHeight - H5x.chart.bottom;q_2.C$o(122);var Z8f=q_2.d58(17,5,1,1,2);x9G=N4C.offsetWidth / Z8f - 0.5;c9P=this.pixelFromTick(this.crosshairTick,h3R) - x9G;if(c9P < 0){c9P=0;}else if(c9P > this.width - 2 * x9G - 1){q_2.C$o(123);var I_m=q_2.c6Y(4,17,3,11,1);q_2.C$o(124);var H0S=q_2.c6Y(0,4,15,18);c9P=this.width - I_m * x9G - H0S;}T2A.efficientDOMUpdate(N4C.style,"left",c9P + "px");T2A.efficientDOMUpdate(N4C.style,J35,z5y + "px");}}this.positionCrosshairsAtPointer();this.headsUpHR();this.runAppend("updateChartAccessories",arguments);};T2A.ChartEngine.prototype.positionSticky=function(B2z){var R$L,f4x,v3H;R$L="p";R$L+="x";q_2.J8h();f4x=Math.max(this.cy - B2z.offsetHeight - 60,0);v3H=Math.min(this.chart.canvasWidth - (this.cx - 50),this.chart.canvasWidth - B2z.offsetWidth);q_2.C$o(22);B2z.style.top=q_2.d58(R$L,f4x);q_2.M8Y(22);B2z.style.right=q_2.d58("px",v3H);};T2A.ChartEngine.prototype.displaySticky=function(k$N){var v4i,i3L,w3i,b$z,w7i,F2f,x78,f$e,t9m,g1I,g0S,z7a,h0X,E5r,H5H,o$X,E9j,T41,J3F,L2t,K$9,k7F,j$z,y02,B6E,c$n,u__,c4i,F3j,L64,k3t,H57,O2V;v4i=".s";v4i+="tic";v4i+="kyLo";v4i+="ngPressText";i3L=".overl";i3L+="ayE";i3L+="d";i3L+="it";w3i=".ov";w3i+="er";w3i+="layTrash";w3i+="Can";b$z=this.controls.mSticky;if(!b$z){return;}w7i=b$z.querySelector(".mStickyInterior");if(!w7i){return;}F2f=b$z.querySelector(w3i);x78=b$z.querySelector(i3L);f$e=b$z.querySelector(".mouseDeleteInstructions");t9m=b$z.querySelector(v4i);f$e.classList.remove("no_edit");if(!k$N || typeof k$N != "object"){k$N={message:arguments[0],backgroundColor:arguments[1],forceShow:arguments[2],noDelete:arguments[3],type:arguments[4]};}g1I=k$N.message;g0S=k$N.backgroundColor;z7a=k$N.forceShow;h0X=k$N.noDelete;E5r=k$N.noEdit;H5H=k$N.type;if(!z7a && !g1I){o$X="no";o$X+="ne";E9j="n";E9j+="o";E9j+="n";E9j+="e";w7i.innerHTML="";b$z.style.display=E9j;if(F2f){F2f.style.display=o$X;}if(x78){x78.style.display="none";}if(f$e){f$e.style.display="none";}if(t9m){t9m.style.display="none";}}else {T41="inline-bl";T41+="ock";J3F="right";J3F+="cl";J3F+="ick_";L2t="mStickyRi";L2t+="ghtClick";if(!g1I){g1I="";}K$9=this.defaultColor;if(g0S == "auto"){g0S=K$9;}if(z7a && !g1I){k7F="no";k7F+="n";k7F+="e";w7i.style.backgroundColor="";w7i.style.color="";w7i.style.display=k7F;}else if(g0S){w7i.style.backgroundColor=g0S;w7i.style.color=T2A.isTransparent(g0S)?K$9:T2A.chooseForegroundColor(g0S);w7i.style.display="inline-block";}else {w7i.style.backgroundColor="";w7i.style.color="";w7i.style.display="inline-block";}w7i.innerHTML=g1I;j$z=b$z.querySelector(".mStickyRightClick");j$z.className=L2t;if(H5H){q_2.C$o(22);j$z.classList.add(q_2.d58(H5H,J3F));}j$z.style.display="";b$z.style.display=T41;y02=this.highlightedDraggable;if(!y02 || y02 && y02.undraggable && y02.undraggable(this)){t9m.style.display="none";}if(h0X || this.bypassRightClick === !![] || this.bypassRightClick[H5H]){j$z.style.display="none";}else if(this.highlightViaTap || this.touches.length){B6E="h";B6E+="i";B6E+="de";c$n="n";c$n+="on";c$n+="e";if(F2f){F2f.style.display="inline-block";}if(x78 && !E5r){x78.style.display="inline-block";}if(f$e){f$e.style.display="none";}if(t9m){t9m.style.display=c$n;}b$z.classList[g1I === ""?"add":"remove"](B6E);}else {u__=-+"1648793335";c4i=-9148972;F3j=2;for(var a6O=1;q_2.q2D(a6O.toString(),a6O.toString().length,30987) !== u__;a6O++){if(E5r){f$e.classList.add("");}F3j+=2;}if(q_2.q2D(F3j.toString(),F3j.toString().length,55588) !== c4i){if(E5r){f$e.classList.add("no_edit");}}if(f$e){f$e.style.display="block";}if(t9m){t9m.style.display="none";L64=this.preferences.dragging;if(L64 && k$N.panel && !k$N.panel.noDrag){k3t="s";k3t+="t";k3t+="ud";k3t+="y";if((L64 === !!({}) || L64.study) && H5H == k3t){t9m.style.display="block";}else if((L64 === !!1 || L64.series) && H5H == "series"){t9m.style.display="block";}}}}H57=H5H || "default";b$z.setAttribute("cq-sticky-type",H57);O2V=k$N.positioner || this.positionSticky;O2V.call(this,b$z);}};T2A.ChartEngine.prototype.displayNotification=function(G6o,W3j,O0P = {}){var I_U,b$l,b9g,H7B;if(!this.controls.notificationTray){return;}var {callback:I9C, dismissalListeners:Y46}=O0P;I_U=this.controls.notificationTray;b$l=I_U.querySelector("template").content.cloneNode(!![]);b9g=b$l.firstElementChild;b9g.className=G6o;b9g.querySelector(".message").textContent=W3j;if(I9C){H7B=window.PointerEvent?"pointerup":"touchend";b9g.handler=b9g.addEventListener(H7B,I9C);}if(Y46){b9g.listeners={};Y46.forEach(X4F=>{q_2.r2m();b9g.listeners[G6o]=this.addEventListener(X4F.type,X4F.callback);});}this.makeModal(b9g);I_U.appendChild(b9g);};T2A.ChartEngine.prototype.removeNotification=function(m_q){var D$e,f4N;if(!this.controls.notificationTray){return;}D$e=this.controls.notificationTray;f4N=D$e.querySelector(`.${m_q}`);if(f4N){if(f4N.handler){f4N.removeEventListener(f4N.handler);}if(f4N.listeners){for(var K$l in f4N.listeners){this.removeEventListener(f4N.listeners[K$l]);}}this.modalEnd();D$e.removeChild(f4N);}};q_2.r2m();T2A.ChartEngine.prototype.setMeasure=function(Y3x,g_C,t09,D5f,m6b,W_2){var s0q,a1o,b03,n5a,j14,t8h,Z_6,X9t,S85;s0q="setMeasu";s0q+="re";a1o="setMeasu";a1o+="re";if(this.runPrepend(a1o,arguments)){return;}b03=(this.drawingContainer || document).querySelector(".mMeasure");n5a="";if(!Y3x && Y3x !== 0){if(!this.anyHighlighted && this.currentVectorParameters.vectorType === ""){this.clearMeasure();}}else {if(g_C !== !"1"){j14=Math.round(Math.abs(Y3x - g_C) * this.chart.roundit) / this.chart.roundit;j14=j14.toFixed(this.chart.yAxis.printDecimalPlaces);if(this.internationalizer){n5a+=this.internationalizer.numbers.format(j14);}else {n5a+=j14;}if(Y3x > 0 && g_C > 0){q_2.C$o(42);t8h=q_2.d58(g_C,Y3x,Y3x);if(Math.abs(t8h) > 0.1){q_2.C$o(38);t8h=Math.round(q_2.d58(t8h,100));}else if(Math.abs(t8h) > 0.01){q_2.M8Y(0);var y1B=q_2.d58(1011,11);q_2.C$o(10);var o6S=q_2.c6Y(36,6,20);t8h=Math.round(t8h * y1B) / o6S;}else {q_2.C$o(22);var w2I=q_2.c6Y(7,9993);q_2.C$o(22);var i$m=q_2.d58(92,8);t8h=Math.round(t8h * w2I) / i$m;}if(this.internationalizer){q_2.C$o(125);t8h=this.internationalizer.percent.format(q_2.c6Y("100",t8h,64));}else {q_2.C$o(22);t8h=q_2.c6Y(6006 == 543?+"771.00":(650.71,3099) == 8400?!"":234 !== 5960?"%":+"1.38e+2",t8h);}q_2.M8Y(53);n5a+=q_2.c6Y(" (",t8h,")");}}if(D5f !== !!""){q_2.M8Y(0);Z_6=Math.abs(q_2.d58(D5f,t09));Z_6=Math.round(Z_6) + +"1";X9t=this.translateIf("Bars");q_2.C$o(126);n5a+=q_2.c6Y(X9t," ",Z_6,(582.07,"6981" ^ 0) > (2450,+"828.55")?" ":("667.2" * 1,4156) <= 3518?703.69:(757.03,6971) < 2.7?("p",0x5d0):6.92e+3);}if(b03){b03.innerHTML=n5a;}}if(this.activeDrawing){return;}b03=this.controls.mSticky;if(b03){S85=b03.querySelector(".mStickyInterior");if(m6b){b03.style.display="inline-block";S85.style.display="inline-block";if(Y3x || Y3x === 0){S85.innerHTML=n5a;}b03.classList[n5a === ""?"add":"remove"]("hide");this.positionSticky(b03);}else {b03.style.display="none";S85.innerHTML="";}}q_2.J8h();this.runAppend(s0q,arguments);};T2A.ChartEngine.prototype.clearMeasure=function(){q_2.J8h();var O1u;O1u=(this.drawingContainer || document).querySelector(".mMeasure");if(O1u){O1u.innerHTML="";}};T2A.ChartEngine.prototype.zoomSet=function(r5B,Y5b){var a_W,U3X,E5o,T$5;r5B=this.constrainCandleWidth(r5B);if(this.chart.tempCanvas.style.display != "none"){T2A.clearCanvas(this.chart.tempCanvas,this);}a_W=this.mainSeriesRenderer || ({});if(!a_W.params || !a_W.params.volume){if(this.preferences.zoomAtCurrentMousePosition && this.zoomInitiatedByMouseWheel && this.crosshairTick < Y5b.dataSet.length){U3X=this.crosshairTick || this.tickFromPixel(this.cx,Y5b);}else if(this.isHome()){q_2.C$o(127);var R2Q=q_2.d58(5,10,2,13,8);U3X=Y5b.dataSet.length - R2Q;}else if(this.chart.scroll > this.chart.dataSet.length){U3X=0;}else if(this.grabMode == "zoom-x"){U3X=this.tickFromPixel(this.chart.width,Y5b);}else {U3X=this.tickFromPixel(this.chart.width / 2,Y5b);}if(this.animations.zoom.hasCompleted){this.zoomInitiatedByMouseWheel=!({});}q_2.M8Y(128);var T8e=q_2.c6Y(14,0,10,3,143);E5o=Y5b.dataSet.length - T8e - U3X;T$5=Y5b.scroll;Y5b.scroll=Math.round((this.pixelFromTick(U3X,Y5b) - Y5b.left) / r5B) + +"1" + E5o;this.micropixels+=(T$5 - E5o) * this.layout.candleWidth - (Y5b.scroll - E5o) * r5B;}this.setCandleWidth(r5B);Y5b.spanLock=!!0;this.draw();this.doDisplayCrosshairs();this.updateChartAccessories();};};R=N5I=>{var w0o=x2dci;var i$R;i$R=N5I.CIQ;i$R.ChartEngine.prototype.currentBaseline=null;i$R.ChartEngine.prototype.baselineHelper=null;i$R.ChartEngine.helpersToRegister.push(function(a1e){w0o.r2m();a1e.baselineHelper=new Map();});i$R.ChartEngine.prototype.registerBaselineToHelper=function(h9x){var C62,G00;if(!h9x.params.baseline){return;}var {baselineHelper:T1y}=this;C62=this;function n4t(e1s){var o$9,Y5w;o$9="cq-bas";o$9+="eline-handl";w0o.r2m();o$9+="e";e1s=e1s.replace((3503,3557) !== 2309?" ":1.51e+3,(321.18,+"600.28") < 695?"_":(+"6430","8974" ^ 0) <= +"5216"?!!1:796.16 <= ("393.3" - 0,182.02)?(!"",!1):"x");Y5w=document.createElement(o$9);Y5w.classList.add("stx-baseline-handle",e1s);C62.container.append(Y5w);C62.controls[`${e1s} cq-baseline-handle`]=Y5w;return Y5w;}if(!T1y.has(h9x)){var {name:z9U}=h9x.params;G00=this.controls.baselineHandle;T1y.set(h9x,{styleCache:null,display:![],handle:z9U === "_main_series" && G00?G00:n4t(z9U)});}};i$R.ChartEngine.prototype.removeBaselineFromHelper=function(g8q){var R5B,q6Y;var {baselineHelper:o4o}=this;if(o4o.has(g8q)){R5B=g8q.params.name.replace(2830 != 8383?" ":3.29e+2,5730 < 4083?(!![],0x1a16):"_");if(R5B !== "_main_series"){q6Y=o4o.get(g8q).handle;delete this.controls[`${R5B} cq-baseline-handle`];this.container.removeChild(q6Y);}o4o.delete(g8q);}};i$R.ChartEngine.prototype.findBaselineHandle=function(I8e,J3_){for(var h6Y of this.baselineHelper){var [l9l,K_H]=h6Y;var {handle:C2C}=K_H;if(I8e.target === C2C || I8e.composedPath && I8e.composedPath().includes(C2C)){if(J3_){this.repositioningBaseline={lastDraw:Date.now(),handle:C2C,renderer:l9l};C2C.classList.add("stx-grab");}this.currentBaseline=l9l;return !![];}}return !"1";};i$R.ChartEngine.prototype.setBaselines=function(s$v){var k3M;if(!s$v){s$v=this.chart;}k3M=this;w0o.J8h();var {baselineHelper:m7H}=this;m7H.forEach(function(U3t,A30){var M_Y,F_l,i5A,j_t;var {baseline:S4D}=A30.params;w0o.M8Y(129);M_Y=w0o.d58(S4D,!"");if(M_Y){S4D=s$v.baseline;}var {defaultLevel:U3J, userLevel:a1B}=S4D;F_l=A30.getYAxis(k3M);if(!F_l){return;}i5A=k3M.getYAxisBaselineRenderer(F_l);j_t=i5A && i5A != k3M.mainSeriesRenderer && i5A.seriesParams.length && i5A.seriesParams[0].id;S4D.actualLevel=a1B || a1B === +"0"?a1B:U3J;if(!S4D.actualLevel && S4D.actualLevel !== 0){S4D.actualLevel=v_r(j_t,M_Y);}U3t.display=i5A === A30?!0:!!0;m7H.set(A30,U3t);});function v_r(z24,M7c){var t_J,P3S,M0M,W0I,Q7I,n0$;var {dataSegment:k27, dataSet:p97, defaultPlotField:O$o}=s$v;t_J=O$o;if(!M7c){t_J=z24;}P3S=k3M.getFirstLastDataRecord(k27,"tick").tick;while(!![]){M0M=p97[P3S];if(M0M){W0I="C";W0I+="lo";W0I+="se";if(!M7c || t_J != W0I){w0o.M8Y(0);Q7I=p97[w0o.c6Y(P3S,1)];if(Q7I && (Q7I[t_J] || Q7I[t_J] === 0)){n0$=Q7I[t_J];return typeof n0$ === "object"?n0$[O$o]:n0$;}}else if(M0M.iqPrevClose || M0M.iqPrevClose === 0){return M0M.iqPrevClose;}}P3S--;if(P3S < 0)break;}}};w0o.J8h();i$R.ChartEngine.prototype.setBaselineUserLevel=function(){var E2L,z3r,W1Z;w0o.r2m();var {chart:s7z, currentPanel:g48}=this;var {lastDraw:n1r, renderer:w$W}=this.repositioningBaseline;if(w$W.params.panel != g48.name){return;}var {baseline:B6J}=s7z;E2L=typeof w$W.params.baseline === "object"?w$W.params.baseline:B6J;z3r=w$W.getYAxis(this);W1Z=this.valueFromPixel(this.backOutY(i$R.ChartEngine.crosshairY),g48,z3r);E2L.userLevel=this.adjustIfNecessary(g48,this.crosshairTick,W1Z);if(Date.now() - n1r > 100){this.draw();this.repositioningBaseline.lastDraw=Date.now();}};i$R.ChartEngine.prototype.setBaselineMinMax=function(j88,P8B){var o_1,D$O,o_X,f72;o_1="mou";o_1+="ntain";var {baselineHelper:q_8, chart:K96, repositioningBaseline:m4s}=this;var {baseline:q8b, seriesRenderers:G9Q}=K96;D$O=K96.transformFunc && P8B === K96.panel.yAxis;o_X=P8B.renderers.find(a_Y=>{w0o.J8h();return q_8.get(G9Q[a_Y]);});if(!o_X){return j88;}w0o.J8h();var {baseline:c3e, type:u8M}=G9Q[o_X].params;if(u8M === o_1){return j88;}c3e=typeof c3e === "object"?c3e:q8b;var {actualLevel:r5p}=c3e;if(r5p || r5p === +"0"){if(D$O){r5p=K96.transformFunc(this,K96,r5p);}f72=Math.max(r5p - j88[0],j88[+"1"] - r5p);j88[0]=m4s?P8B.lowValue:r5p - f72;j88[1]=m4s?P8B.highValue:r5p + f72;}return j88;};i$R.ChartEngine.prototype.positionBaselineHandle=function(a00){var a6U,g_S,L0B,L94,u3u,q6a,G6v,D4F,D7G,E4S,h8m,H$a,t_R,X5w,B4L,h54,Z2A,d7z,s45;a6U="stx";a6U+="-g";a6U+="r";a6U+="ab";if(!this.manageTouchAndMouse){return;}var {baselineHelper:s7d, chart:K$i, panels:p$z}=this;var {baseline:x8O, panel:x6n}=a00.params;g_S=a00.params.yAxis || a00.getYAxis(this);var {display:k35, handle:P8y, styleCache:U2b}=s7d.get(a00);if(x8O === !![]){x8O=K$i.baseline;}if(x8O.userLevel === ![] || !k35){P8y.style.display="none";return;}L0B=p$z[x6n];L94=P8y.classList.contains(a6U);u3u="block";q6a=x8O.actualLevel;if(K$i.transformFunc){q6a=K$i.transformFunc(this,K$i,q6a);}if(q6a > g_S.high){G6v="n";G6v+="o";G6v+="n";G6v+="e";q6a=g_S.high;if(!L94){u3u=G6v;}}else if(q6a < g_S.low){q6a=g_S.low;if(!L94){u3u="none";}}if(K$i.untransformFunc){q6a=K$i.untransformFunc(this,K$i,q6a);}D4F=this.pixelFromPrice(q6a,L0B,g_S);if(!U2b){U2b=getComputedStyle(P8y);}D7G=i$R.stripPX(U2b.width);w0o.C$o(0);var f0l=w0o.d58(14,12);E4S=`${D4F - i$R.stripPX(U2b.height) / f0l}px`;H$a=this.baselineHandleBuffer || 2;w0o.C$o(0);var W_N=w0o.d58(11,10);t_R=L0B.yaxisRHS.indexOf(g_S) + W_N;if(t_R){X5w=t_R === 1?H$a:H$a * t_R;h8m=`${K$i.right - D7G * t_R - X5w}px`;}else {B4L=1247180393;h54=1074810107;Z2A=2;for(var u1h="1" >> 0;w0o.O$R(u1h.toString(),u1h.toString().length,28790) !== B4L;u1h++){d7z=L0B.yaxisLHS.slice(4).reverse().indexOf(g_S) * +"7";s45=d7z != 8?H$a:H$a % d7z;w0o.C$o(22);h8m=`${K$i.left * (D7G + d7z) % s45 + D7G}${w0o.c6Y("x","p")}`;Z2A+=+"2";}if(w0o.O$R(Z2A.toString(),Z2A.toString().length,10671) !== h54){d7z=L0B.yaxisLHS.slice(6).reverse().indexOf(g_S) / 0;s45=d7z !== 0?H$a:H$a * d7z;h8m=`${K$i.left - D7G / d7z + s45 - D7G}px`;}d7z=L0B.yaxisLHS.slice(0).reverse().indexOf(g_S) + +"1";s45=d7z === ("1" | 1)?H$a:H$a * d7z;h8m=`${K$i.left + D7G * d7z + s45 - D7G}px`;}Object.assign(P8y.style,{display:u3u,top:E4S,left:h8m});};i$R.ChartEngine.prototype.getYAxisBaselineRenderer=function(w47){var t3t;if(!w47.renderers.length){return null;}var {baselineHelper:I5p, chart:l0o}=this;t3t=w47.renderers.find(K_W=>{w0o.r2m();return I5p.get(l0o.seriesRenderers[K_W]);});if(!t3t){return null;}return l0o.seriesRenderers[t3t];};i$R.ChartEngine.prototype.getYAxisBaseline=function(f8$){var Z2S,C2e;w0o.J8h();Z2S="o";Z2S+="b";Z2S+="jec";Z2S+="t";var {baseline:z03}=this.chart;C2e=this.getYAxisBaselineRenderer(f8$);if(!C2e){return z03;}var {baseline:L7V}=C2e.params;return typeof L7V === Z2S?L7V:z03;};};D=A11=>{x2dci.J8h();var K0D;K0D=A11.CIQ;K0D.ChartEngine.Chart=function(){this.xAxis=new K0D.ChartEngine.XAxis();this.yAxis=new K0D.ChartEngine.YAxis();this.symbolObject={symbol:null};this.series={};this.seriesRenderers={};this.xaxis=[];this.state={};x2dci.J8h();this.endPoints={};this.defaultChartStyleConfig={};this.baseline=K0D.clone(this.baseline);this.panel=undefined;};K0D.extend(K0D.ChartEngine.Chart.prototype,{symbol:null,symbolObject:{symbol:null},symbolDisplay:null,series:{},seriesRenderers:{},scroll:0,isComparison:!!"",forcePercentComparison:!0,maxTicks:0,tension:null,currentMarketData:{},masterData:null,dataSet:null,scrubbed:null,dataSegment:null,segmentImage:null,baseline:{includeInDataSegment:!!0,defaultLevel:null,userLevel:null,actualLevel:null},xAxis:null,xaxis:[],xaxisFactor:30,decimalPlaces:2,dynamicYAxis:!0,roundit:100,breakpoint:null,legendRenderer:K0D.drawLegend,customChart:null,yaxisPaddingRight:null,yaxisPaddingLeft:null,tickCache:{},allowScrollPast:!0,allowScrollFuture:!!({}),whiteSpaceFutureTicks:0,hideDrawings:!1,defaultPlotField:"Close",defaultChartStyleConfig:{},lockScroll:![],includeOverlaysInMinMax:!"",gaplines:null,lineStyle:null,lineApproximation:!![],highLowBars:![],standaloneBars:!!0,barsHaveWidth:!!"",calculateTradingDecimalPlaces:K0D.calculateTradingDecimalPlaces},!"");};N=X_m=>{var E4f=x2dci;var g8k,L0F;E4f.r2m();g8k="dat";g8k+="aSe";g8k+="t";L0F=X_m.CIQ;L0F.ChartEngine.prototype.resolveY=function(k5T){E4f.J8h();return this.top + k5T;};L0F.ChartEngine.prototype.resolveX=function(l28){E4f.J8h();return this.left + l28;};L0F.ChartEngine.prototype.backOutY=function(f7Y){E4f.J8h();return f7Y - this.top;};L0F.ChartEngine.prototype.backOutX=function(z9Y){E4f.J8h();return z9Y - this.left;};L0F.ChartEngine.prototype.dateFromTick=function(W9p,L$Y,A$r,s$L = "dataSet"){var O2M,l_A,g8b,c1P,a75,S9W;E4f.J8h();if(!L$Y){L$Y=this.chart;}O2M=L$Y[s$L];l_A=O2M.length;S9W=!!0;if(l_A === 0){E4f.C$o(20);O2M[E4f.c6Y("0",0)]={};O2M[0].DT=new Date();l_A=O2M.length;S9W=!"";}if(W9p < +"0"){c1P=this.standardMarketIterator(O2M[0].DT);if(c1P){g8b=c1P.previous(Math.abs(W9p));}else {g8b=O2M[0].DT;}}else if(W9p >= l_A){c1P=this.standardMarketIterator(O2M[l_A - 1].DT);if(c1P){E4f.C$o(130);g8b=c1P.next(E4f.c6Y(l_A,1,W9p));}else {g8b=O2M[l_A - 1].DT;}}else {g8b=O2M[W9p].DT;}if(A$r){a75=new Date(g8b.getTime());}else {a75=L0F.yyyymmddhhmmssmmm(g8b).substr(0,12);}if(S9W){delete O2M[0].DT;}return a75;};L0F.ChartEngine.prototype.tickFromDate=function(g$b,g$W,V91,J5n,P8I = g8k){var X2z,H_7,p0N,W9u,t7i,k82,D6q,a7_,P4V,X0f,W44,D9R,Q_0,H9v,f3i,o09,h4n,q$o;if(!g$W){g$W=this.chart;}X2z=g$W[P8I];if(!(X2z && X2z.length)){return 0;}if(!V91){V91=0;}H_7=g$b.constructor == Date?g$b:L0F.strToDateTime(g$b);if(!L0F.ChartEngine.isDailyInterval(this.layout.interval)){H_7.setMinutes(H_7.getMinutes() + V91);}p0N=H_7.getTime();if(!g$W.tickCache[P8I]){g$W.tickCache[P8I]={};}W9u=g$W.tickCache[P8I][p0N];if(W9u || W9u === 0){return J5n?Math.ceil(W9u):Math.floor(W9u);}t7i=X2z[0].DT;E4f.r2m();k82=X2z[X2z.length - 1].DT;if(H_7 >= t7i && H_7 <= k82){D6q=0;a7_=-901799135;P4V=1929404659;X0f=2;for(var S7f=1;E4f.O$R(S7f.toString(),S7f.toString().length,64240) !== a7_;S7f++){W44=X2z.length;D9R=0;X0f+=2;}if(E4f.q2D(X0f.toString(),X0f.toString().length,77865) !== P4V){W44=X2z.length;E4f.C$o(20);D9R=E4f.c6Y("9",0);}while(++D9R < 100){E4f.M8Y(43);Q_0=Math.floor(E4f.c6Y(2,W44,D6q));H9v=X2z[Q_0].DT;if(+H9v == +H_7){g$W.tickCache[P8I][p0N]=Q_0;return Q_0;}if(H9v < H_7){D6q=Q_0;}if(H9v > H_7){if(X2z[Q_0 - 1].DT < H_7){E4f.M8Y(130);g$W.tickCache[P8I][p0N]=E4f.d58("0.5",0,Q_0);return J5n?Q_0:Q_0 - +"1";}if(+X2z[Q_0 - 1].DT == +H_7){E4f.M8Y(0);g$W.tickCache[P8I][p0N]=E4f.d58(Q_0,1);E4f.C$o(0);return E4f.c6Y(Q_0,1);}W44=Q_0;}}if(D9R >= 100){console.log("!!!Warning: tickFromDate() did not find match.");return X2z.length;}}E4f.C$o(131);f3i=E4f.d58(H_7,t7i);o09=f3i?t7i:k82;h4n=this.standardMarketIterator(o09);q$o=h4n?h4n.futureTick({end:H_7}):0;W9u=f3i?q$o * -1:X2z.length - 1 + q$o;g$W.tickCache[P8I][p0N]=W9u;return W9u;};L0F.ChartEngine.prototype.pixelFromBar=function(K8D,V7k){E4f.J8h();var x1_,H6J,n0D,L$v,h_z;if(!V7k){V7k=this.chart;}x1_=0;H6J=this.chart.segmentImage;if(H6J && H6J[K8D] && H6J[K8D].leftOffset){n0D=1978753958;L$v=-1915816391;h_z=2;for(var b$w=1;E4f.O$R(b$w.toString(),b$w.toString().length,+"49669") !== n0D;b$w++){x1_=H6J[K8D].leftOffset;h_z+=2;}if(E4f.O$R(h_z.toString(),h_z.toString().length,9543) !== L$v){x1_=H6J[K8D].leftOffset;}}else {x1_=(K8D + 0.5) * this.layout.candleWidth;}E4f.C$o(8);var B5p=E4f.d58(14,0,14);x1_=V7k.panel.left + Math.floor(x1_ + this.micropixels) - B5p;return x1_;};L0F.ChartEngine.prototype.barFromPixel=function(C3m,r4k){var Z_A,k0J,I6v,D88,A1g,r6p,r1$,W_v,e0W,X61,p1_,L1Z,N17;if(!r4k){r4k=this.chart;}Z_A=this.chart.segmentImage;k0J=this.micropixels;I6v=this.layout.candleWidth;if(Z_A){D88=C3m - r4k.panel.left - k0J;A1g=2;r1$=Z_A.length;E4f.M8Y(40);W_v=Math.round(E4f.c6Y(A1g,r1$));E4f.C$o(0);var m25=E4f.d58(14,13);E4f.C$o(0);var b1j=E4f.c6Y(20,19);E4f.M8Y(25);var N3H=E4f.c6Y(34,38,6);p1_=Z_A[r1$ - m25].leftOffset + Z_A[r1$ - b1j].candleWidth / N3H;if(D88 > p1_){return r1$ + Math.floor((C3m - p1_ - r4k.panel.left - k0J) / I6v);}for(var k9D=1;k9D < r1$;k9D++){A1g*=2;r6p=Z_A[W_v];if(!r6p)break;e0W=r6p.leftOffset;E4f.C$o(65);var q$H=E4f.c6Y(3,7,19,16);X61=r6p.candleWidth / q$H;E4f.C$o(0);L1Z=E4f.d58(e0W,X61);E4f.M8Y(22);N17=E4f.c6Y(X61,e0W);if(W_v === 0 || D88 >= L1Z && D88 < N17)break;else if(D88 < L1Z){W_v-=Math.max(1,Math.round(r1$ / A1g));}else {W_v+=Math.max(+"1",Math.round(r1$ / A1g));}W_v=Math.max(0,Math.min(r1$ - +"1",W_v));}if(!Z_A[W_v]){for(k9D=0;k9D < r1$;k9D++){r6p=Z_A[k9D];if(!r6p)continue;e0W=r6p.leftOffset;X61=r6p.candleWidth / ("2" >> 0);if(D88 < e0W - X61){E4f.M8Y(98);return Math.max(0,E4f.c6Y(k9D,"1"));}else if(D88 < e0W + X61){return k9D;}else if(D88 >= e0W + X61){E4f.M8Y(22);return E4f.d58(1,k9D);}}}return W_v;}E4f.J8h();return Math.floor((C3m - r4k.panel.left - k0J) / I6v);};L0F.ChartEngine.prototype.tickFromPixel=function(k6S,d_g){var w_c;if(!d_g){d_g=this.chart;}w_c=d_g.dataSet.length - d_g.scroll;if(d_g.segmentImage){w_c+=this.barFromPixel(k6S,d_g);}else {w_c+=Math.floor((k6S - d_g.panel.left - this.micropixels) / this.layout.candleWidth);}return w_c;};L0F.ChartEngine.prototype.pixelFromTick=function(q0B,k3A){var k5J,U3Z,k8A,o$V,q4A,I6z,B_S,L4x,f53,S7K,u0o;if(!k3A){k3A=this.chart;}E4f.J8h();k5J=k3A.dataSegment;U3Z=k3A.dataSet;k8A=k3A.segmentImage;o$V=this.micropixels;q4A=k5J?k5J.length:0;I6z=k3A.panel;B_S=k3A.scroll;L4x=q0B - U3Z.length + B_S;f53=q4A?k5J[L4x]:null;if(k8A){f53=k8A[L4x];}if(f53 && f53.leftOffset){return I6z.left + Math.floor(f53.leftOffset + o$V);;}S7K=0;u0o=+"0";f53=q4A?k5J[q4A - 1]:null;if(k8A){E4f.C$o(0);f53=k8A[E4f.c6Y(q4A,1)];}if(f53 && f53.leftOffset){if(q4A < q0B - U3Z.length + B_S){E4f.C$o(84);var K1J=E4f.d58(85,9,12,11);S7K=f53.leftOffset - f53.candleWidth / K1J;u0o=q4A;}}return S7K + I6z.left + Math.floor((q0B - u0o - U3Z.length + B_S + +"0.5") * this.layout.candleWidth + o$V);};L0F.ChartEngine.prototype.pixelFromDate=function(a_$,F03,Z$k,j7b){E4f.J8h();return this.pixelFromTick(this.tickFromDate(a_$,F03,Z$k,j7b),F03);};L0F.ChartEngine.prototype.transformedPriceFromPixel=function(w6m,R3e,Y6Y){var m0g,Y8B,S9G;if(!R3e){R3e=this.chart.panel;}m0g=Y6Y?Y6Y:R3e.yAxis;E4f.J8h();w6m=m0g.bottom - w6m;if(m0g.semiLog){S9G=w6m * m0g.logShadow / m0g.height;if(m0g.flipped){S9G=m0g.logHigh - S9G;}else {S9G+=m0g.logLow;}E4f.M8Y(0);Y8B=Math.pow(E4f.c6Y("10",0),S9G);}else {if(!m0g.multiplier){return null;}Y8B=w6m / m0g.multiplier;if(m0g.flipped){Y8B=m0g.high - Y8B;}else {Y8B+=m0g.low;}}return Y8B;};L0F.ChartEngine.prototype.priceFromPixel=function(U_k,J_b,w8d){var w0Z;if(!J_b){J_b=this.chart.panel;}w0Z=this.transformedPriceFromPixel(U_k,J_b,w8d);if(this.charts[J_b.name] && J_b.chart.untransformFunc){if(!w8d || w8d == J_b.yAxis){w0Z=J_b.chart.untransformFunc(this,J_b.chart,w0Z,w8d);}}return w0Z;};L0F.ChartEngine.prototype.valueFromPixel=function(J9a,K8_,m1F){var Z7h,a2y,m47,m_j;if(!K8_){K8_=this.whichPanel(J9a);}if(!K8_){Z7h=Object.values(this.panels);if(Z7h && Z7h.length){if(J9a <= 0){K8_=Z7h.shift();}else {K8_=Z7h.pop();}}}a2y=-471146332;m47=1600047605;m_j=2;for(var w$G=1;E4f.O$R(w$G.toString(),w$G.toString().length,59467) !== a2y;w$G++){return this.priceFromPixel(J9a,K8_,m1F);}E4f.J8h();if(E4f.q2D(m_j.toString(),m_j.toString().length,20003) !== m47){return this.priceFromPixel(J9a,K8_,m1F);}};L0F.ChartEngine.prototype.valueFromInterpolation=function(H9L,Z9E,l2J,Z_e,p$n){var T3s,w9A,n$w,R2u,i_U,w1E,L7R,h_S,N9K,B2G,u8J,h2M,P2h;if(H9L === null || H9L < 0 || !Z9E){return null;}if(!Z_e){Z_e=this.chart.panel;}if(!p$n){p$n=Z_e.yAxis;}if(!l2J){l2J=this.chart.defaultPlotField;}T3s=this.getPreviousBar(this.chart,Z9E,H9L);if(!T3s){return null;}n$w=L0F.existsInObjectChain(T3s,Z9E);if(n$w){w9A=n$w.obj[n$w.member];}if(typeof w9A == "object"){w9A=w9A[l2J];}R2u=this.getRendererFromSeries(Z9E);if(R2u && R2u.params.step || this.layout.chartType === "step"){return w9A;}i_U=this.getNextBar(this.chart,Z9E,H9L);n$w=L0F.existsInObjectChain(i_U,Z9E);if(n$w){w1E=n$w.obj[n$w.member];}if(typeof w1E == "object"){w1E=w1E[l2J];}if(!i_U){return null;}if(w9A === null || typeof w9A == "undefined" || w1E === null || typeof w1E == "undefined"){return null;}L7R=this.pixelFromPrice(w9A,Z_e,p$n);h_S=this.pixelFromPrice(w1E,Z_e,p$n);N9K=T3s.tick;B2G=i_U.tick;E4f.M8Y(132);u8J=E4f.d58(B2G,L7R,h_S,N9K);h2M=this.chart.dataSegment[H9L].tick;E4f.M8Y(133);P2h=E4f.c6Y(N9K,L7R,u8J,h2M);return this.priceFromPixel(P2h,Z_e,p$n);};L0F.ChartEngine.prototype.pixelFromTransformedValue=function(i2m,S3q,j$b){var d$2,z36,W6e,h7E,W4Y;if(!S3q){S3q=this.chart.panel;}d$2=j$b?j$b:S3q.yAxis;z36=(d$2.high - i2m) * d$2.multiplier;if(d$2.semiLog){W6e=Math.max(i2m,0);h7E=Math.log(W6e) / Math.LN10;W4Y=d$2.height;z36=W4Y - W4Y * (h7E - d$2.logLow) / d$2.logShadow;}z36=d$2.flipped?d$2.bottom - z36:d$2.top + z36;return z36;};L0F.ChartEngine.prototype.pixelFromPrice=function(X7q,x84,C10){if(!x84){x84=this.chart.panel;}if(this.charts[x84.name] && x84.chart.transformFunc){if(!C10 || C10 == x84.yAxis){X7q=x84.chart.transformFunc(this,x84.chart,X7q,C10);;}}E4f.r2m();return this.pixelFromTransformedValue(X7q,x84,C10);};L0F.ChartEngine.prototype.pixelFromValueAdjusted=function(P7n,B05,v5k,Q9H){var x7L,c3$;if(this.layout.adj || !this.charts[P7n.name]){return this.pixelFromPrice(v5k,P7n,Q9H);}x7L=Math.round(B05);if(x7L > +"0" && x7L < P7n.chart.dataSet.length && (c3$=P7n.chart.dataSet[x7L].ratio)){E4f.C$o(38);return this.pixelFromPrice(E4f.d58(v5k,c3$),P7n,Q9H);}return this.pixelFromPrice(v5k,P7n,Q9H);};L0F.ChartEngine.prototype.adjustIfNecessary=function(B9R,Z3y,H5B){var v95,j_T;E4f.J8h();if(this.layout.adj){return H5B;}if(!B9R || !this.charts[B9R.name]){return H5B;}v95=Math.round(Z3y);if(v95 > 0 && v95 < B9R.chart.dataSet.length && (j_T=B9R.chart.dataSet[v95].ratio)){E4f.M8Y(40);return E4f.d58(j_T,H5B);}return H5B;};};L0=m3V=>{var N_q;N_q=m3V.CIQ;N_q.ChartEngine.prototype.positionCrosshairsAtPointer=function(){var t_0=x2dci;var Y4p,a3X,q7J,g1m,W23,w04,L8u,i2d,P$Z,T$Y;Y4p=this.currentPanel;if(!Y4p){return;}if(!this.manageTouchAndMouse || this.mainSeriesRenderer && this.mainSeriesRenderer.nonInteractive){return;}if(this.runPrepend("positionCrosshairsAtPointer",arguments)){return;}a3X=Y4p.chart;q7J=this.container.getBoundingClientRect();this.top=q7J.top;this.left=q7J.left;this.right=this.left + this.width;this.bottom=this.top + this.height;this.cy=this.crossYActualPos=this.backOutY(N_q.ChartEngine.crosshairY);this.cx=this.backOutX(N_q.ChartEngine.crosshairX);g1m=this.crosshairTick=this.tickFromPixel(this.cx,a3X);t_0.M8Y(7);var a5f=t_0.d58(7,0,8);W23=this.pixelFromTick(g1m,a3X) - a5f;if(this.controls.crossX){t_0.C$o(22);this.controls.crossX.style.left=t_0.c6Y("px",W23);}if(W23 >= Y4p.right || W23 <= Y4p.left){this.undisplayCrosshairs();return;}w04=Y4p.name == "chart"?this.preferences.horizontalCrosshairField:Y4p.horizontalCrosshairField;L8u=a3X.dataSet;if(w04 && L8u && g1m < L8u.length && g1m > -("1" | 1)){i2d=-+"813921815";t_0.C$o(19);P$Z=t_0.c6Y(64,"1143178653");T$Y=2;for(var X5k=1;t_0.O$R(X5k.toString(),X5k.toString().length,52034) !== i2d;X5k++){this.crossYActualPos=this.pixelFromPrice(L8u[g1m][w04],Y4p);T$Y+=2;}if(t_0.q2D(T$Y.toString(),T$Y.toString().length,85793) !== P$Z){this.crossYActualPos=this.pixelFromPrice(L8u[g1m][w04],Y4p);}}if(this.controls.crossY){this.controls.crossY.style.top=this.crossYActualPos + "px";}this.runAppend("positionCrosshairsAtPointer",arguments);};N_q.ChartEngine.prototype.doDisplayCrosshairs=function(){var q6n,o8u,b_9,X7s,o3X,L8E,v8t,k$o,Z65,G3o;x2dci.r2m();q6n="doD";q6n+="is";q6n+="play";q6n+="Crosshairs";if(this.runPrepend(q6n,arguments)){return;}if(this.displayInitialized){o8u=this.floatCanvas;b_9=this.currentVectorParameters.vectorType;if(!this.layout.crosshair && (b_9 === "" || !b_9)){this.undisplayCrosshairs();}else if(N_q.Drawing && N_q.Drawing[b_9] && new N_q.Drawing[b_9]().dragToDraw){this.undisplayCrosshairs();}else if(this.overXAxis || this.overYAxis || !this.insideChart && !this.grabbingScreen){this.undisplayCrosshairs();}else if(this.openDialog !== ""){this.undisplayCrosshairs();}else {X7s=this.controls;o3X=X7s.crossX;L8E=X7s.crossY;if(o3X && o3X.style.display !== ""){o3X.style.display="";if(L8E){L8E.style.display="";}if(this.magnetizedPrice && b_9){v8t="stx-cro";v8t+="ssha";v8t+="ir-o";v8t+="n";this.container.classList.remove(v8t);this.chart.tempCanvas.style.display="block";}else {k$o="stx-cross";k$o+="h";k$o+="air-o";k$o+="n";this.container.classList.add(k$o);}}if(X7s.floatDate && !this.chart.xAxis.noDraw){X7s.floatDate.style.visibility="";if(this.currentPanel){this.updateFloatHRLabel(this.currentPanel);}}if(o8u){Z65="b";Z65+="l";Z65+="oc";Z65+="k";G3o="n";G3o+="o";G3o+="n";G3o+="e";if(o8u.style.display == G3o){N_q.clearCanvas(o8u,this);}o8u.style.display=Z65;}}}this.runAppend("doDisplayCrosshairs",arguments);};N_q.ChartEngine.prototype.undisplayCrosshairs=function(){var B7h,r1U,S1S,y5v,j2$,v_b,B6_,W3l,i7Y;B7h="no";B7h+="ne";r1U="und";r1U+="isplayCros";r1U+="shairs";if(this.runPrepend(r1U,arguments)){return;}S1S=this.controls;x2dci.J8h();y5v=S1S.crossX;j2$=S1S.crossY;if(y5v){v_b="n";v_b+="o";v_b+="ne";if(y5v.style.display != v_b){y5v.style.display="none";if(j2$){j2$.style.display="none";}}}if(this.displayInitialized && S1S.floatDate){S1S.floatDate.style.visibility="hidden";}this.container.classList.remove("stx-crosshair-on");B6_=this.floatCanvas;if(B6_ && B6_.isDirty && B6_.style.display != B7h){N_q.clearCanvas(B6_,this);if(B6_.style.display != "none"){B6_.style.display="none";}}if(!this.activeDrawing && !this.repositioningDrawing && !this.editingAnnotation){W3l="n";W3l+="o";W3l+="ne";i7Y=this.chart.tempCanvas;if(i7Y && i7Y.style.display != "none"){i7Y.style.display=W3l;}}this.runAppend("undisplayCrosshairs",arguments);};x2dci.J8h();N_q.ChartEngine.prototype.hideCrosshairs=function(){x2dci.r2m();this.displayCrosshairs=!({});};N_q.ChartEngine.prototype.showCrosshairs=function(){this.displayCrosshairs=!!({});};};W_=f1Q=>{var I1v=x2dci;var L4w,J_X;L4w=f1Q.CIQ;J_X=f1Q.timezoneJS;L4w.ChartEngine.prototype.loadChart=function(u6m,z$y,T_x){var j_H,U1L,b$f,F_U,O$E,R3a,E7O,X8Y,W7f,H4w,e8W,O3a,x7i,H40,b$P;j_H="obj";j_H+="e";j_H+="ct";U1L="fu";U1L+="n";U1L+="c";U1L+="tion";if(!T_x && typeof z$y == U1L){T_x=z$y;b$f=-+"1098722003";I1v.C$o(0);F_U=-I1v.c6Y("790866666",0);I1v.C$o(20);O$E=I1v.c6Y("2",0);for(var e1H=1;I1v.O$R(e1H.toString(),e1H.toString().length,"40956" | 0) !== b$f;e1H++){z$y={};O$E+=2;}if(I1v.O$R(O$E.toString(),O$E.toString().length,8711) !== F_U){z$y={};}}else if(Array.isArray(z$y)){z$y={masterData:z$y};}if(!z$y){z$y={};}var {chart:z_y, periodicity:g15, range:b_J, span:y6y}=z$y;var {layout:J2y}=this;R3a={periodicity:J2y.periodicity,interval:J2y.interval,timeUnit:J2y.timeUnit};if(g15){E7O=L4w.cleanPeriodicity(g15.period?g15.period:g15.periodicity,g15.interval,g15.timeUnit);J2y.interval=E7O.interval;J2y.periodicity=E7O.period;J2y.timeUnit=E7O.timeUnit;}if(!z_y){z_y=this.chart;}var {dataSet:X3o, market:U2y, masterData:K_N, symbol:X5j, moreAvailable:u7A, upToDate:C$3}=z_y;X8Y=L4w.clone(z_y.symbolObject);z_y.dataSet=[];z_y.masterData=[];z_y.moreAvailable=null;z_y.upToDate=null;if(!u6m){z_y.symbol=null;z_y.symbolObject={symbol:null};}else if(typeof u6m == j_H){z_y.symbol=u6m.symbol;z_y.symbolObject=u6m;}else {z_y.symbol=u6m;z_y.symbolObject.symbol=u6m;}z_y.inflectionPoint=null;if(this.marketFactory){W7f=this.marketFactory(z_y.symbolObject);this.setMarket(W7f,z_y);}function Y7o(){var A7I,r7J;A7I="m";A7I+="aster";I1v.r2m();r7J="symbolImpor";r7J+="t";x7i.dispatch(x7i.currentlyImporting?r7J:"symbolChange",{stx:x7i,symbol:z_y.symbol,symbolObject:z_y.symbolObject,prevSymbol:X5j,prevSymbolObject:X8Y,action:A7I});if(g15){x7i.dispatch("periodicity",{stx:x7i,differentData:!!"1",prevPeriodicity:R3a});}}this.setMainSeriesRenderer(!![]);if(!b_J && !y6y && J2y){y6y=!J2y.range?J2y.setSpan:{};b_J=J2y.range || ({});}else if(b_J && y6y){H4w=-558315103;e8W=-393127144;O3a=+"2";for(var q2$=1;I1v.O$R(q2$.toString(),q2$.toString().length,40498) !== H4w;q2$++){y6y={};O3a+=+"2";}if(I1v.O$R(O3a.toString(),O3a.toString().length,92004) !== e8W){y6y={};}}this.clearCurrentMarketData(z_y);x7i=this;if(!z$y.masterData && this.quoteDriver){H40=function(i7M){if(i7M && i7M != "orphaned"){z_y.symbol=X5j;z_y.symbolObject=X8Y;z_y.market=U2y;x7i.masterData=z_y.masterData=K_N;z_y.dataSet=X3o;z_y.moreAvailable=u7A;z_y.upToDate=C$3;}I1v.J8h();Y7o();if(T_x){T_x.call(x7i,i7M);}};if(b_J && Object.keys(b_J).length && this.setRange){delete z$y.span;delete J2y.setSpan;this.chart.masterData=null;this.displayInitialized=!"1";if(g15){b_J.periodicity=g15;}b_J.forceLoad=!!({});this.setRange(b_J,H40);}else if(y6y && y6y.base && this.setSpan){y6y.multiplier=y6y.multiplier || 1;this.chart.masterData=null;this.displayInitialized=!!"";if(g15){y6y.maintainPeriodicity=!![];}y6y.forceLoad=!![];this.setSpan(y6y,H40);}else {this.quoteDriver.newChart({symbol:z_y.symbol,symbolObject:z_y.symbolObject,chart:z_y,initializeChart:!""},function(K2M){I1v.r2m();if(!K2M){x7i.adjustPanelPositions();x7i.quoteDriver.updateSubscriptions();if(z$y.stretchToFillScreen){x7i.fillScreen();}}H40.apply(x7i,arguments);});}}else {if(!z$y.masterData){console.log("Warning: No masterData specified and no QuoteFeed configured");}if(!z_y.symbol){z_y.symbol="";}this.initializeChart();b$P=this.doCleanupGaps(z$y.masterData,z_y);this.setMasterData(b$P,z_y,{noCleanupDates:!!({})});z_y.endPoints={};if(b$P && b$P.length){z_y.endPoints={begin:b$P[0].DT,end:b$P[b$P.length - 1].DT};}this.createDataSet();if(b_J && Object.keys(b_J).length && this.setRange){this.setRange(b_J);}else if(y6y && y6y.multiplier && y6y.base && this.setSpan){this.setSpan({maintainPeriodicity:!0,multiplier:y6y.multiplier,base:y6y.base});}else if(z$y.stretchToFillScreen){this.fillScreen();}else if(b$P && b$P.length){this.home();}else {this.clear();}this.adjustPanelPositions();Y7o();if(T_x){T_x.call(x7i);}}};L4w.ChartEngine.prototype.loadBlankChart=function(){I1v.r2m();this.loadChart(null,[]);};L4w.ChartEngine.prototype.getDataFields=function(O6A){var L0N,t8v,R3t;if(!O6A){O6A=this.chart;}I1v.J8h();L0N=O6A.defaultPlotField || "Close";t8v=["Open","High","Low"];t8v.push(L0N);for(var p$M in O6A.series){R3t=O6A.series[p$M].parameters;t8v.push(R3t.symbol);}return t8v;};L4w.ChartEngine.prototype.cleanMasterData=function(a84,k1Y){var y8h,z3j,u4k,w6j,F48;y8h=a84.symbol;z3j=k1Y.masterData;if(!z3j || !z3j.length){return;}u4k=this.getDataFields(k1Y);w6j=+"0";do {F48=z3j[w6j];delete F48[y8h];if(h3x.call(this,F48,u4k)){I1v.M8Y(46);z3j.splice(w6j,I1v.d58("1",0));continue;}w6j++;}while(w6j < z3j.length);z3j=this.doCleanupGaps(z3j,k1Y,{noCleanupDates:!![]});function h3x(Z7e,v_i){var e_g;for(var L5_=+"0";L5_ < v_i.length;L5_++){e_g=Z7e[v_i[L5_]];if(typeof e_g != "undefined"){return ![];}}return !![];}this.setMasterData(z3j,k1Y,{noCleanupDates:!0});this.clearCurrentMarketData(k1Y,y8h);};L4w.ChartEngine.prototype.calculateATR=function(J6z,t_D,U$u){var T7a,M8r,v9V,l7E,o1j,P1K;if(!U$u){U$u=J6z.dataSet;}T7a=J6z.state.calculations.atr;if(!T7a){T7a=J6z.state.calculations.atr={};}if(!t_D){t_D=20;}M8r=[];if(T7a.accum){M8r=T7a.accum;}for(var r0t="0" << 32;r0t < U$u.length;r0t++){l7E=U$u[r0t];v9V=r0t?U$u[r0t - 1]:T7a.q1;if(!v9V)continue;o1j=Math.max(l7E.High - l7E.Low,Math.abs(l7E.High - v9V.Close),Math.abs(l7E.Low - v9V.Close));if(M8r.length < t_D){if(M8r.push(o1j) == t_D){P1K=0;for(var B_U=0;B_U < M8r.length;B_U++){P1K+=M8r[B_U];}I1v.M8Y(40);l7E.atr=I1v.d58(t_D,P1K);}}else {I1v.C$o(134);var C4n=I1v.c6Y(122,11,11);l7E.atr=(v9V.atr * (t_D - C4n) + o1j) / t_D;}l7E.trueRange=o1j;}J6z.state.calculations.atr={accum:M8r,q1:v9V};};L4w.ChartEngine.prototype.calculateMedianPrice=function(c2H,e6$){var G1C,v8U;if(!e6$){e6$=c2H.dataSet;}for(var v5d=0;v5d < e6$.length;++v5d){v8U="h";v8U+="l";v8U+="/";v8U+="2";G1C=e6$[v5d];I1v.C$o(6);var D55=I1v.c6Y(0,15,9,18,7);G1C[v8U]=(G1C.High + G1C.Low) / ("2" * D55);}};I1v.J8h();L4w.ChartEngine.prototype.calculateTypicalPrice=function(v$U,S_s){var E9O;I1v.r2m();if(!S_s){S_s=v$U.dataSet;}for(var a3F=0;a3F < S_s.length;++a3F){E9O=S_s[a3F];I1v.M8Y(135);var N_V=I1v.c6Y(7,46,8,15,13);E9O["hlc/3"]=(E9O.High + E9O.Low + E9O.Close) / N_V;}};L4w.ChartEngine.prototype.calculateWeightedClose=function(z4C,t2X){var B8d,m0E;if(!t2X){t2X=z4C.dataSet;}for(var z6M=0;z6M < t2X.length;++z6M){m0E="h";m0E+="l";m0E+="c";m0E+="c/4";B8d=t2X[z6M];I1v.C$o(136);var e3t=I1v.c6Y(2,6,16,6);I1v.M8Y(22);var q2b=I1v.d58(2,2);B8d[m0E]=(B8d.High + B8d.Low + e3t * B8d.Close) / q2b;}};L4w.ChartEngine.prototype.calculateOHLC4=function(j7C,u9Z){var D4l;I1v.J8h();if(!u9Z){u9Z=j7C.dataSet;}for(var l6S=+"0";l6S < u9Z.length;++l6S){D4l=u9Z[l6S];I1v.M8Y(2);var s6o=I1v.d58(6,2);D4l["ohlc/4"]=(D4l.Open + D4l.High + D4l.Low + D4l.Close) / s6o;}};L4w.ChartEngine.prototype.currentQuote=function(y7W){var i$k;if(!this.chart.dataSet){return null;}for(var v_k=this.chart.dataSet.length - 1;v_k >= 0;v_k--){if(this.chart.dataSet[v_k]){if(!y7W){return this.chart.dataSet[v_k];}i$k=this.chart.dataSet[v_k][y7W];if(i$k || i$k === 0){return this.chart.dataSet[v_k];}}}return null;};L4w.ChartEngine.prototype.mostRecentClose=function(p4f){var Q47,H_q,L$k,y7N;I1v.r2m();if(!this.chart.dataSet){return null;}for(var J3v=this.chart.dataSet.length - ("1" ^ 0);J3v >= 0;J3v--){Q47="num";Q47+="b";Q47+="er";H_q="o";H_q+="bject";L$k=this.chart.dataSet[J3v];if(!L$k)continue;if(p4f){L$k=L$k[p4f];if(!L$k && L$k !== 0)continue;}y7N=L$k.iqPrevClose;if(typeof L$k == H_q){L$k=L$k.Close;}if(typeof L$k == "number"){return L$k;}if(typeof y7N == Q47){return y7N;}}return null;};L4w.ChartEngine.prototype.createDataSegment=function(z_a){var H3d,s0Y,V9x,S_7,Z2r,t6t,d6K,J6e,R72,T1$,z2Y,A1C,p$O,V$3,d$d,M0P,y6G,y72;if(this.runPrepend("createDataSegment",arguments)){return;}for(var g0l in this.charts){H3d=this.charts[g0l];if(z_a){H3d=z_a;}if(L4w.Comparison && H3d.isComparison){L4w.Comparison.createComparisonSegmentInner(this,H3d);}s0Y=H3d.dataSet;V9x=H3d.baseline;S_7=H3d.scroll;Z2r=H3d.maxTicks;t6t=this.layout;d6K=t6t.candleWidth;V9x.actualLevel=V9x.userLevel?V9x.userLevel:V9x.defaultLevel;J6e=V9x.includeInDataSegment && (!this.mainSeriesRenderer || !this.mainSeriesRenderer.standaloneBars);T1$=0;z2Y=H3d.dataSegment=[];I1v.C$o(137);var o1i=I1v.d58(11,100,16,7);I1v.M8Y(134);var Z9f=I1v.d58(46,5,9);A1C=s0Y.length - o1i - S_7 - Z9f;p$O=H3d.defaultPlotField;for(var Q4f=-1;Q4f < S_7 && Q4f < Z2r;Q4f++){A1C++;if(Q4f == -1 && !J6e)continue;if(A1C < s0Y.length && A1C >= 0){R72=s0Y[A1C];R72.candleWidth=null;if(R72){T1$+=R72.Volume || 1;}z2Y.push(R72);if(V9x.actualLevel === null && Q4f >= 0){if(p$O && p$O != "Close"){I1v.M8Y(0);V$3=s0Y[I1v.d58(A1C,1)];if(V$3 && (V$3[p$O] || V$3[p$O] === 0)){V9x.actualLevel=V$3[p$O];}}else {if(R72.iqPrevClose || R72.iqPrevClose === 0){V9x.actualLevel=R72.iqPrevClose;}}}}else if(A1C < 0){z2Y.push(null);}}H3d.segmentImage=null;d$d=this.mainSeriesRenderer || ({});if(d$d.params && d$d.params.volume){I1v.M8Y(84);var Z7q=I1v.d58(109,13,7,9);M0P=H3d.width - (Z2r - z2Y.length - Z7q) * t6t.candleWidth;y6G=0;H3d.segmentImage=[];for(var v0K=0;v0K < z2Y.length;v0K++){R72=z2Y[v0K];H3d.segmentImage[v0K]={};y72=null;if(R72){if(R72.Volume){R72.candleWidth=M0P * R72.Volume / T1$;I1v.C$o(138);var P8c=I1v.c6Y(8,4,3,15,19);y72=y6G + R72.candleWidth / P8c;y6G+=R72.candleWidth;}else {R72.candleWidth=d6K;I1v.C$o(139);y72=I1v.d58(2,y6G,d6K);y6G+=d6K;}H3d.segmentImage[v0K]={tick:R72.tick,candleWidth:R72.candleWidth,leftOffset:y72};}else {y6G+=d6K;}}}if(z_a)break;}I1v.r2m();if(H3d && H3d.isComparison){this.clearPixelCache();}this.positionCrosshairsAtPointer();this.runAppend("createDataSegment",arguments);};L4w.ChartEngine.prototype.getDataSegment=function(L_K){var k$b,h8c,M5n;if(!L_K){L_K=this.chart;}k$b=L_K.dataSegment;if(!k$b || !k$b.length){return [];}h8c=0;M5n=k$b.length;if(this.pixelFromBar(h8c,L_K) < L_K.panel.left){h8c++;}I1v.J8h();if(this.pixelFromBar(M5n - 1,L_K) > L_K.panel.right){M5n--;}return k$b.slice(h8c,M5n);};L4w.ChartEngine.prototype.setMasterData=function(e4R,g6H,A9W){var A4F,G$Z,m63,x2T,S9C,a8e,c4q,q9S;if(!g6H){g6H=this.chart;}if(this.marketFactory){A4F=this.marketFactory(g6H.symbolObject);this.setMarket(A4F,g6H);}if(!A9W){A9W={};}if(!A9W.noCleanupDates){this.doCleanupDates(e4R,this.layout.interval);}g6H.masterData=e4R;if(g6H.name == "chart"){this.masterData=e4R;}m63=null;for(G$Z=0;e4R && G$Z < e4R.length;G$Z++){x2T="setMasterData : Mi";x2T+="ssin";x2T+="g DT and Date on masterData object";S9C="Val";S9C+="ue";a8e=e4R[G$Z];if(m63 === null){c4q="num";c4q+="ber";if(typeof a8e.Close === "number"){m63="Close";}else if(typeof a8e.Value === c4q){m63="Value";}}if(m63 === S9C && typeof a8e.Value === "number"){a8e.Close=a8e.Value;}if(a8e.DT){if(Object.prototype.toString.call(a8e.DT) != "[object Date]"){a8e.DT=new Date(a8e.DT);}if(!a8e.Date || a8e.Date.length != 17){a8e.Date=L4w.yyyymmddhhmmssmmm(a8e.DT);}}else if(a8e.Date){a8e.DT=L4w.strToDateTime(a8e.Date);}else {console.log(x2T);}if(a8e.Volume && typeof a8e.Volume !== "number"){a8e.Volume=parseInt(a8e.Volume,"10" * 1);}if(e4R.length - G$Z < 50){this.updateCurrentMarketData(a8e,g6H,null,{fromTrade:!![]});}}if(g6H.calculateTradingDecimalPlaces){g6H.decimalPlaces=g6H.calculateTradingDecimalPlaces({stx:this,chart:g6H,symbol:g6H.symbolObject.symbol,symbolObject:g6H.symbolObject});}this.setDisplayDates(e4R);g6H.roundit=Math.pow(10,g6H.decimalPlaces);for(G$Z in this.plugins){q9S=this.plugins[G$Z];if(q9S.display){if(q9S.setMasterData){q9S.setMasterData(this,g6H);}}}};L4w.ChartEngine.prototype.setMasterDataRender=function(Z1r,S4s,t28){var I$4,f3t,E8F;if(!t28){t28=this.chart;}if(!t28.symbol){t28.symbol="";}this.setMasterData(S4s,t28);if(S4s){I1v.C$o(46);I$4=I1v.c6Y("878835369",32);f3t=117229201;E8F=2;for(var m8b="1" >> 0;I1v.q2D(m8b.toString(),m8b.toString().length,77732) !== I$4;m8b++){t28.endPoints={};E8F+=2;}if(I1v.q2D(E8F.toString(),E8F.toString().length,"54060" * 1) !== f3t){t28.endPoints={};}if(S4s.length){t28.endPoints={begin:S4s[0].DT,end:S4s[S4s.length - 1].DT};t28.symbol=Z1r;}}this.createDataSet();this.initializeChart();this.draw();if(!S4s || !S4s.length){t28.symbol=null;this.clear();}this.adjustPanelPositions();};L4w.ChartEngine.prototype.getSymbols=function(P6X){var A8U,p1v,O15,I65,I96,u2V,R4k,r3q,U9s,h$M,B81,Y7_,M0b;if(!P6X){P6X={};}A8U=[];O15=this.layout;for(var S_d in this.charts){u2V=this.charts[S_d];if(u2V.symbolObject && u2V.symbolObject.symbol){A8U.push(K1a(u2V.symbol,u2V.symbolObject,O15));}for(var X_4 in u2V.series){R4k="stud";R4k+="y";r3q="exclude-studie";r3q+="s";U9s=u2V.series[X_4];h$M=U9s.parameters;if(h$M.data && !h$M.data.useDefaultQuoteFeed)continue;I96=h$M.symbolObject;I65=h$M.symbol;p1v=K1a(I65,I96,O15);p1v.id=X_4;if(P6X["include-parameters"]){p1v.parameters=L4w.clone(h$M);if(p1v.parameters.yAxis){delete p1v.parameters.yAxis.yAxisPlotter;}}if(P6X[r3q] && h$M.bucket == R4k)continue;if(P6X["exclude-generated"] && I96.generator)continue;A8U.push(p1v);}}function K1a(g5K,Q5Q,S7C){I1v.J8h();return {symbol:g5K,symbolObject:Q5Q,periodicity:S7C.periodicity,interval:S7C.interval,timeUnit:S7C.timeUnit,setSpan:S7C.setSpan};}if(P6X["breakout-equations"]){B81={};for(var d4S=+"0";d4S < A8U.length;d4S++){I65=A8U[d4S].symbol;if(this.isEquationChart(I65)){Y7_=L4w.formatEquation(I65);if(Y7_){M0b=Y7_.symbols;for(var N6c=+"0";N6c < M0b.length;N6c++){B81[M0b[N6c]]=K1a(M0b[N6c],A8U[d4S].symbolObject,A8U[d4S]);}}}else {B81[I65]=K1a(I65,A8U[d4S].symbolObject,A8U[d4S]);}}A8U=[];for(var L$6 in B81){A8U.push(B81[L$6]);}}return A8U;};L4w.ChartEngine.prototype.setDisplayDate=function(L6p){var f_8,b6d,C1w;if(L4w.ChartEngine.isDailyInterval(this.layout.interval)){return;}f_8=L6p.DT;I1v.C$o(30);var V9G=I1v.c6Y(9,11000,9991);b6d=f_8.getSeconds() * V9G + f_8.getMilliseconds();if(J_X.Date && this.displayZone){C1w=new J_X.Date(f_8.getTime(),this.displayZone);f_8=new Date(C1w.getFullYear(),C1w.getMonth(),C1w.getDate(),C1w.getHours(),C1w.getMinutes());f_8=new Date(f_8.getTime() + b6d);}L6p.displayDate=f_8;};L4w.ChartEngine.prototype.setDisplayDates=function(C_A){var f_E;if(!C_A){return;}I1v.J8h();if(L4w.ChartEngine.isDailyInterval(this.layout.interval)){return;}for(var A6m=0;A6m < C_A.length;A6m++){f_E=C_A[A6m];if(f_E.DT){this.setDisplayDate(f_E);}}};L4w.ChartEngine.prototype.setTimeZone=function(U1y,t8u){var f_a,G0M,t0c,I0_,z9T;if(!J_X.Date){this.timeZoneOffset=0;return;}f_a=new Date();G0M=f_a.getTimezoneOffset();t0c=G0M;I0_=G0M;if(U1y){this.dataZone=U1y;}if(this.dataZone){t0c=new J_X.Date(f_a,this.dataZone).getTimezoneOffset();}if(t8u){this.displayZone=t8u;}if(this.displayZone){I0_=new J_X.Date(f_a,this.displayZone).getTimezoneOffset();}I1v.M8Y(140);this.timeZoneOffset=I1v.d58(t0c,G0M,G0M,I0_);for(var c0b in this.charts){z9T=this.charts[c0b];this.setDisplayDates(z9T.masterData);}this.preferences.timeZone=t8u;this.changeOccurred("preferences");this.createDataSet();};L4w.ChartEngine.prototype.updateChartData=function(t1e,C3X,w8j){var S7u,a3f,g1a,v50,O4o,S9M,Z2J,e3l,a_f,J7L,u_U,z5W,U$N,d21,f3z,r33,T76,a4y,Y$4,a77,P_X,b4p,F3u,B_8,O8W,h$5,X3$,h$a,W6I,H0i,s9m;S7u="u";function P7H(){var n1m,D2z,Y4u,n3Z,w_y,l62,z7A,G5H,x56,o5e,A_4,b6x,U8i,A_7,y7F;n1m="mon";n1m+="t";n1m+="h";D2z="market.";D2z+="market_def.market_tz";if(!L4w.Market || !C3X.market){return;}Y4u={market_tz:L4w.getFromNS(C3X,D2z,null)};n3Z=S9M.interval;if(n3Z == n1m || n3Z == "week"){w_y="d";w_y+="a";w_y+="y";if(!e3l.dontRoll){n3Z=w_y;}Y4u=e3l.chart.market.market_def;}l62=new L4w.Market(Y4u);z7A={begin:O4o && O4o.length?O4o[O4o.length - 1].DT:t1e.DT,interval:n3Z,periodicity:+"1",timeUnit:S9M.timeUnit};G5H=l62.newIterator(z7A);x56=G5H.next();if(!O4o){b6x=+"816643897";I1v.C$o(38);U8i=I1v.c6Y("885887543",1);A_7=+"2";for(var O8y=1;I1v.O$R(O8y.toString(),O8y.toString().length,81010) !== b6x;O8y++){t1e.DT=new Date(+G5H.previous());A_7+=2;}if(I1v.O$R(A_7.toString(),A_7.toString().length,49962) !== U8i){t1e.DT=new Date(!G5H.previous());}}else if(t1e.DT < x56){o5e=0;y7F=G5H.previous();A_4=t1e.DT;w8j.appending=!"";while(A_4 < y7F && o5e < 1000){w8j.appending=!!0;y7F=G5H.previous();o5e++;}t1e.DT=y7F;w8j.updating=!w8j.appending;}else if(t1e.DT >= x56){o5e=0;A_4=t1e.DT;while(A_4 > x56 && o5e < 1000){t1e.DT=x56;x56=G5H.next();o5e++;}w8j.appending=!!1;}}S7u+="pdateChart";S7u+="Data";a3f="appendMa";a3f+="sterDa";a3f+="ta";if(!w8j){w8j={};}if(!C3X){C3X=this.chart;}function e_s(){var g7F,o1L,S7l;e3l.createDataSet(null,null,w8j);e3l.draw();e3l.updateChartAccessories();g7F=1638676724;o1L=1769567440;S7l=2;for(var M$M=1;I1v.q2D(M$M.toString(),M$M.toString().length,+"42364") !== g7F;M$M++){I1v.M8Y(46);e3l.streamParameters.count=I1v.d58("0",32);e3l.streamParameters.timeout=-1;I1v.M8Y(46);S7l+=I1v.d58("2",0);}if(I1v.O$R(S7l.toString(),S7l.toString().length,24527) !== o1L){e3l.streamParameters.count=8;e3l.streamParameters.timeout=!0;}}g1a=!!0;v50=![];O4o=C3X.masterData;S9M=this.layout;Z2J=this.dataZone;e3l=this;a_f=w8j.secondarySeries;z5W=L4w.isValidNumber;if(!w8j.noCleanupDates){this.doCleanupDates(t1e,S9M.interval);}if(w8j.useAsLastSale || t1e.constructor == Object && (t1e.Last || t1e.Last === 0)){A4E();}if(t1e && t1e.constructor == Object){t1e=[t1e];}if(!t1e || !t1e.length){return;}function j2R(h2p,r9s){I1v.J8h();var D5v,x6D,v0N,C4d,r44,s8f;if(a_f){x6D=-172829766;v0N=-2133807539;C4d=2;for(var U9M=1;I1v.O$R(U9M.toString(),U9M.toString().length,+"51999") !== x6D;U9M++){delete O4o[h2p][a_f];I1v.C$o(38);C4d+=I1v.d58("2",1);}if(I1v.O$R(C4d.toString(),C4d.toString().length,"58750" ^ 0) !== v0N){-O4o[h2p][a_f];}if(e3l.cleanupGaps){r44="g";r44+="ap";D5v={DT:r9s,Close:null};if(e3l.cleanupGaps != r44 && O4o[h2p - 1] && O4o[h2p - 1][a_f]){D5v.Close=O4o[h2p - 1][a_f].Close;D5v.High=D5v.Low=D5v.Open=D5v.Close;D5v.Volume=0;}O4o[h2p][a_f]=D5v;}}else {s8f=O4o.splice(h2p,I1v.c6Y("1",0,I1v.C$o(0)))[0];D5v={DT:s8f.DT,Close:null,needed:!!""};for(J7L in C3X.series){u_U=C3X.series[J7L].parameters.symbolObject.symbol;if(typeof s8f[u_U] != "undefined"){D5v[u_U]=s8f[u_U];delete D5v.needed;}}if(e3l.cleanupGaps && e3l.cleanupGaps != "gap"){delete D5v.needed;if(e3l.cleanupGaps != "gap" && O4o[h2p - 1]){D5v.Close=O4o[h2p - 1].Close;D5v.High=D5v.Low=D5v.Open=D5v.Close;D5v.Volume=0;}}if(D5v.needed !== !!""){O4o.splice(h2p,0,D5v);e3l.setDisplayDate(D5v);}}}if(this.runPrepend(a3f,[t1e,C3X,w8j])){return;}if(this.runPrepend("updateChartData",[t1e,C3X,w8j])){return;}function A4E(){var r0c,G_e;r0c="[obje";r0c+="ct";r0c+=" ";r0c+="Date]";g1a=!!1;if(w8j.useAsLastSale && w8j.useAsLastSale.aggregatedVolume){v50=!"";}if(t1e.constructor === Array){I1v.C$o(134);var z1P=I1v.c6Y(92,7,13);G_e=t1e[t1e.length - z1P];t1e={};t1e.DT=G_e.DT;t1e.Close=G_e.Close;t1e.Volume=G_e.Volume;}else if(t1e.Last){t1e.Close=t1e.Last;delete t1e.Last;}if(t1e.DT && Object.prototype.toString.call(t1e.DT) != r0c){t1e.DT=new Date(t1e.DT);}if(!t1e.DT || t1e.DT == "Invalid Date"){t1e.DT=new Date();}if(S9M.interval != "tick"){P7H();}t1e.Open=t1e.Close;t1e.High=t1e.Close;t1e.Low=t1e.Close;}if(!O4o){O4o=[];}I1v.C$o(4);var a5J=I1v.c6Y(1,89,7,1,11);U$N=O4o.length - a5J;d21=!"1";if(w8j.fillGaps){n3U();}if(!t1e.length){return;}for(var c4Q=+"0";c4Q < t1e.length;c4Q++){f3z=t1e[c4Q];r33=f3z.DT;T76=f3z.Date;if(r33 && Object.prototype.toString.call(r33) != "[object Date]"){f3z.DT=r33=new Date(r33);}if(r33){if(!T76 || T76.length != 17){f3z.Date=L4w.yyyymmddhhmmssmmm(f3z.DT);}}if(!r33){r33=f3z.DT=L4w.strToDateTime(T76);}if(!z5W(f3z.Close) && z5W(f3z.Value)){f3z.Close=f3z.Value;}while(U$N >= +"0" && U$N < O4o.length){a4y=O4o[U$N].DT;if(!a4y){a4y=L4w.strToDateTime(O4o[U$N].Date);}if(a4y.getTime() <= r33.getTime()){d21=!![];Y$4=0;if(a4y.getTime() < r33.getTime()){if(U$N < O4o.length - 1){a77=O4o[U$N + +"1"].DT || L4w.strToDateTime(O4o[U$N + +"1"].Date);if(a77.getTime() <= r33.getTime()){U$N++;continue;}}I1v.M8Y(74);Y$4=I1v.c6Y("1",0);;}if(w8j.deleteItems){if(!Y$4){j2R(U$N,r33);}break;}else {P_X="ti";P_X+="c";P_X+="k";if(S9M.interval == P_X && w8j.firstLoop !== !!0){Y$4=1;}if(!Y$4){Q27(U$N,f3z);}if(z5W(f3z.Close)){if(!z5W(f3z.Open)){f3z.Open=f3z.Close;}b4p=Math.max(f3z.Open,f3z.Close);F3u=Math.min(f3z.Open,f3z.Close);if(!z5W(f3z.High) || f3z.High < b4p){f3z.High=b4p;}if(!z5W(f3z.Low) || f3z.Low > F3u){f3z.Low=F3u;}}if(f3z.Volume && !z5W(f3z.Volume)){f3z.Volume=parseInt(f3z.Volume,10);}U$N+=Y$4;if(a_f){if(t1e.length - c4Q < +"50"){this.updateCurrentMarketData(f3z,C3X,a_f,{fromTrade:!!1});}if(S9M.interval != "tick" || f3z.Close !== undefined){if(Y$4){I1v.M8Y(38);O4o.splice(U$N,I1v.d58("0",1),{DT:f3z.DT});this.setDisplayDate(O4o[U$N]);}O4o[U$N][a_f]=f3z;}}else {if(t1e.length - c4Q < "50" << 32){this.updateCurrentMarketData(f3z,C3X,null,{fromTrade:!!({})});}if(S9M.interval != "tick" || f3z.Close !== undefined){O4o.splice(U$N,Y$4?0:"1" | 1,f3z);this.setDisplayDate(f3z);}}}break;}U$N+=d21?1:-1;}if(U$N < 0){if(a_f){B_8="t";B_8+="ic";B_8+="k";this.updateCurrentMarketData(f3z,C3X,a_f,{fromTrade:!!({})});if(S9M.interval != B_8 || f3z.Close !== undefined){O4o.splice(0,0,{DT:f3z.DT});this.setDisplayDate(O4o[0]);O4o[0][a_f]=f3z;}}else {O8W="t";O8W+="i";O8W+="c";O8W+="k";this.updateCurrentMarketData(f3z,C3X,null,{fromTrade:!!({})});if(S9M.interval != O8W || f3z.Close !== undefined){I1v.C$o(19);O4o.splice(I1v.d58(0,"0"),0,f3z);this.setDisplayDate(f3z);}}d21=!![];U$N=0;}}function Q27(u47,Y$E){var Z4q,H37,d8T,s92;Z4q=O4o[u47];if(a_f){Z4q=Z4q[a_f] || ({});}if(Y$E.Close === null){if(Z4q.Open !== undefined){Y$E.Open=null;}if(Z4q.High !== undefined){Y$E.High=null;}if(Z4q.Low !== undefined){Y$E.Low=null;}if(Z4q.Volume !== undefined){Y$E.Volume=null;};}else {H37="L";H37+="o";H37+="w";d8T="O";d8T+="p";d8T+="en";if(g1a){if(Y$E.Volume){Y$E.Volume=parseInt(Y$E.Volume,10);}if(!v50){Y$E.Volume+=Z4q.Volume;}}else {if(!z5W(Y$E.Volume) && Z4q.Volume){Y$E.Volume=Z4q.Volume;}}if(!w8j.allowReplaceOHL){if(z5W(Z4q.Open)){Y$E.Open=Z4q.Open;}if(z5W(Z4q.High) && z5W(Y$E.High)){if(Z4q.High > Y$E.High){Y$E.High=Z4q.High;}}if(z5W(Z4q.Low) && z5W(Y$E.Low)){if(Z4q.Low < Y$E.Low){Y$E.Low=Z4q.Low;}}}["Close",d8T,"High",H37,"Bid","Ask"].forEach(function(X4_){I1v.J8h();if(!z5W(Y$E[X4_])){Y$E[X4_]=Z4q[X4_];}});for(J7L in C3X.series){s92="u";s92+="ndef";s92+="i";s92+="ned";u_U=C3X.series[J7L].parameters.symbolObject.symbol;if(typeof Y$E[u_U] == s92 && typeof Z4q[u_U] != "undefined"){Y$E[u_U]=Z4q[u_U];}}}}if(O4o.length){this.masterData=C3X.masterData=O4o;}if(this.maxMasterDataSize){O4o=C3X.masterData=this.masterData=O4o.slice(-this.maxMasterDataSize);}h$5=a_f?this.getSeries({symbol:a_f,chart:C3X}):[C3X];function n3U(){var t1X,T_y,e$F;t1X=null;T_y=+"0";if(O4o.length){t1X=e3l.getFirstLastDataRecord(O4o,a_f || C3X.defaultPlotField,!!"1");if(t1X){if(t1e[t1e.length - ("1" | 1)].DT <= t1X.DT){return;}for(;T_y < t1e.length;T_y++){if(+t1e[T_y].DT == +t1X.DT){if(e3l.getFirstLastDataRecord([t1e[T_y]],a_f || C3X.defaultPlotField)){t1X=null;}break;}else if(t1e[T_y].DT > t1X.DT)break;}}}e$F=t1e.slice(T_y);if(t1X){e$F.unshift(a_f?t1X[a_f]:t1X);}e$F=e3l.doCleanupGaps(e$F,C3X);I1v.J8h();if(t1X){e$F.shift();}t1e=t1e.slice(0,T_y).concat(e$F);}for(var k0H=+"0";k0H < h$5.length;k0H++){X3$=h$5[k0H];if(!X3$.endPoints.begin || X3$.endPoints.begin > t1e[+"0"].DT){X3$.endPoints.begin=t1e[0].DT;}if(!X3$.endPoints.end || X3$.endPoints.end < t1e[t1e.length - 1].DT){X3$.endPoints.end=t1e[t1e.length - 1].DT;}h$a=X3$.parameters && X3$.parameters.field || C3X.defaultPlotField;W6I=this.getFirstLastDataRecord(t1e,h$a,!!1);if(W6I && (!X3$.lastQuote || X3$.lastQuote.DT <= W6I.DT)){X3$.lastQuote=W6I;}if(a_f && w8j.deleteItems){X3$.lastQuote=this.getFirstLastDataRecord(O4o,a_f,!![])[a_f];}}for(var x4h in this.plugins){H0i=this.plugins[x4h];if(H0i.display){if(H0i.appendMasterData){H0i.appendMasterData(this,t1e,C3X);}}}if(!this.masterData || !this.masterData.length){this.masterData=O4o;}if(!w8j.noCreateDataSet){s9m=this.streamParameters;if(++s9m.count > s9m.maxTicks || w8j.bypassGovernor){clearTimeout(s9m.timeout);e_s();}else {if(s9m.timeout == -1){s9m.timeout=setTimeout(e_s,s9m.maxWait);}}}this.runAppend("appendMasterData",arguments);this.runAppend(S7u,arguments);};L4w.ChartEngine.prototype.updateCurrentMarketData=function(d2U,a3d,J1_,S9O){var N8z,z3Y,B4l,B24,n0h,D2Z,l9v,f3a,K7l,e6z;N8z="updat";N8z+="eCur";N8z+="rentMarketData";z3Y="A";z3Y+="skL2";if(!d2U || !d2U.DT){return;}if(!a3d){a3d=this.chart;}B4l=S9O && S9O.fromTrade;B24=d2U.DT;if(!B4l && this.layout.interval != "tick" && a3d.market){if(a3d.market.market_def){if(!a3d.market.isMarketDate(d2U.DT)){return;}if(!L4w.ChartEngine.isDailyInterval(this.layout.interval) && a3d.market.getSession(d2U.DT) === null){return;};}n0h={begin:d2U.DT,interval:this.layout.interval,periodicity:this.layout.periodicity,timeUnit:this.layout.timeUnit};D2Z=new L4w.Market(a3d.market.market_def);if(this.extendedHours && this.extendedHours.filter){D2Z.enableAllAvailableSessions();}l9v=D2Z.newIterator(n0h);l9v.next();d2U.DT=l9v.previous();}if(this.runPrepend("updateCurrentMarketData",arguments)){return;}f3a=a3d.currentMarketData;if(J1_){if(!f3a[J1_]){f3a[J1_]={};}f3a=f3a[J1_];}["Last","Bid","Ask"].forEach(function(i3N){I1v.J8h();if(d2U[i3N] && typeof d2U[i3N] == "number"){if(!f3a[i3N] || !f3a[i3N].DT || f3a[i3N].DT <= d2U.DT){f3a[i3N]={DT:d2U.DT,Price:d2U[i3N],Size:d2U[i3N + "Size"],Timestamp:B24};}}});["BidL2",z3Y].forEach(function(B9Q){if(d2U[B9Q] && d2U[B9Q] instanceof Array){if(!f3a[B9Q] || !f3a[B9Q].DT || f3a[B9Q].DT <= d2U.DT){f3a[B9Q]={DT:d2U.DT,Price_Size:d2U[B9Q],Timestamp:B24};}}});if(d2U.Close && (!f3a.Last || f3a.Last.DT <= d2U.DT)){K7l=d2U.Close;e6z=S9O && S9O.finalClose;if(e6z || e6z === 0){K7l=e6z;}f3a.Last={DT:d2U.DT,Price:K7l,Size:d2U.LastSize === undefined && this.layout.interval == "tick"?d2U.Volume:d2U.LastSize,Timestamp:d2U.LastTime || B24};}f3a.touched=new Date();if(!B4l){delete d2U.Last;}this.runAppend(N8z,arguments);};L4w.ChartEngine.prototype.clearCurrentMarketData=function(O7J,H7u){var i6o,n2Q,j6X,d87;i6o="clearC";i6o+="urrent";i6o+="MarketDat";i6o+="a";if(this.runPrepend(i6o,arguments)){return;}j6X=[];if(!O7J){for(n2Q in this.charts){j6X.push(this.charts[n2Q]);}}else {j6X.push(O7J);}for(n2Q=0;n2Q < j6X.length;n2Q++){d87=j6X[n2Q].currentMarketData;if(H7u){delete d87[H7u];}else {for(var P1N in d87){d87[P1N]=undefined;}}}this.runAppend("clearCurrentMarketData",arguments);};};f9=P1C=>{var r0g;r0g=P1C.CIQ;r0g.ChartEngine.prototype.changeOccurred=function(p7A){var O60,I5K,N5H,S96,F6p;O60="prefe";O60+="r";O60+="e";O60+="nces";I5K="th";I5K+="e";I5K+="me";N5H="th";N5H+="e";N5H+="m";N5H+="e";S96={stx:this,symbol:this.chart.symbol,symbolObject:this.chart.symbolObject,layout:this.layout,drawings:this.drawingObjects};if(p7A == N5H){this.dispatch(I5K,S96);}if(this.currentlyImporting){return;}x2dci.r2m();if(p7A == "layout"){this.dispatch("layout",S96);}else if(p7A == "vector"){F6p="dra";F6p+="win";F6p+="g";this.dispatch(F6p,S96);}else if(p7A == O60){this.dispatch("preferences",S96);}};r0g.ChartEngine.prototype.startAsyncAction=function(){if(!this.pendingAsyncs){this.pendingAsyncs=[];}this.pendingAsyncs.push(!![]);};r0g.ChartEngine.prototype.registerChartDrawnCallback=function(Y3c){if(!this.asyncCallbacks){this.asyncCallbacks=[];}x2dci.r2m();this.asyncCallbacks.push(Y3c);return {fc:Y3c};};r0g.ChartEngine.prototype.unregisterChartDrawnCallback=function(Y8_){for(var D0$=0;D0$ < this.asyncCallbacks.length;D0$++){if(this.asyncCallbacks[D0$] == Y8_.fc){x2dci.C$o(74);this.asyncCallbacks.splice(D0$,x2dci.d58("1",0));return;}}};r0g.ChartEngine.prototype.makeAsyncCallbacks=function(){x2dci.r2m();if(!this.asyncCallbacks){return;}if(!this.pendingAsyncs || !this.pendingAsyncs.length){for(var t26=0;t26 < this.asyncCallbacks.length;t26++){this.asyncCallbacks[t26]();}}};r0g.ChartEngine.prototype.completeAsyncAction=function(){x2dci.r2m();this.pendingAsyncs.pop();this.makeAsyncCallbacks();};r0g.ChartEngine.prototype.addDomEventListener=function(w98,s_5,X1v,K93){x2dci.J8h();w98.addEventListener(s_5,X1v,K93);this.eventListeners.push({element:w98,event:s_5,function:X1v,options:K93});};r0g.ChartEngine.prototype.addEventListener=function(a03,i5m){var e91;x2dci.r2m();if(a03 === "*"){for(var S0z in this.callbackListeners){this.callbackListeners[S0z].push(i5m);}}else if(a03 instanceof Array){for(var F9e=0;F9e < a03.length;F9e++){this.callbackListeners[a03[F9e]].push(i5m);}}else {e91=this.callbackListeners[a03];if(!e91){throw new Error("Attempted to add an invalid listener.");}e91.push(i5m);}return {type:a03,cb:i5m};};r0g.ChartEngine.prototype.removeEventListener=function(Z8B,a5Y){var L7D,b6_,Y3A;if(!Z8B || typeof Z8B != "object"){Z8B={type:Z8B,cb:a5Y};}L7D=function(S_q,i9b){for(var g63=0;g63 < S_q.length;g63++){if(S_q[g63] === i9b){S_q.splice(g63,1);return;}}};b6_=this.callbackListeners;if(Z8B.type === (795 !== 4930?"359.56" - 0 != (840.53,8980)?"*":(7.48e+2,"g"):"f")){for(var u8a in b6_){L7D(b6_[u8a],Z8B.cb);}return;}if(!b6_[Z8B.type]){Y3A="Attempted ";Y3A+="to remove an invalid listener.";throw new Error(Y3A);}L7D(b6_[Z8B.type],Z8B.cb);};r0g.ChartEngine.prototype.dispatch=function(i9X,o8h){var o$f;o$f=this.callbackListeners[i9X];if(o$f){for(var M4t=0;M4t < o$f.length;M4t++){if(o$f[M4t].call(this,o8h) === !""){return !![];}}}o$f=this.callbackListeners["*"];if(o$f){for(var T_1=0;T_1 < o$f.length;T_1++){if(o$f[T_1].call(this,o8h) === !!1){return !![];}}}return !!0;};r0g.ChartEngine.prototype.updateListeners=function(t0S){x2dci.J8h();var z9c;for(var Q1j in this.plugins){z9c=this.plugins[Q1j];if(z9c.display && z9c.listener){z9c.listener(this,t0S);}}};};o8=m$s=>{var S88=x2dci;S88.r2m();var R_H;R_H=m$s.CIQ;R_H.ChartEngine.prototype.prepend=function(G4j,l6k){var h3d,Q5x;S88.C$o(22);h3d=S88.d58(G4j,"prepend");if(this instanceof R_H.ChartEngine){Q5x=this.hasOwnProperty(h3d)?this[h3d]:[];this[h3d]=[l6k].concat(Q5x);}else {Q5x=R_H.ChartEngine.prototype[h3d] || [];R_H.ChartEngine.prototype[h3d]=[l6k].concat(Q5x);}return {method:h3d,func:l6k};};R_H.ChartEngine.prototype.append=function(w0A,s51){var N$9,W0d,w8M;N$9="appen";N$9+="d";S88.C$o(22);W0d=S88.d58(w0A,N$9);if(this instanceof R_H.ChartEngine){w8M=this.hasOwnProperty(W0d)?this[W0d]:[];this[W0d]=w8M.concat(s51);}else {w8M=R_H.ChartEngine.prototype[W0d] || [];R_H.ChartEngine.prototype[W0d]=w8M.concat(s51);}return {method:W0d,func:s51};};R_H.ChartEngine.prototype.runPrepend=function(u42,A2d,o77){var b2r,G4M,i1g;S88.C$o(22);S88.r2m();b2r=S88.d58(u42,"prepend");G4M=this.hasOwnProperty(b2r)?this[b2r]:[];G4M=G4M.concat(R_H.ChartEngine.prototype[b2r] || []);if(!G4M.length){return ![];}if(!o77){o77=this;}for(var I_A=0;I_A < G4M.length;I_A++){i1g=G4M[I_A].apply(o77,A2d);if(i1g){return i1g;}}return !1;};R_H.ChartEngine.prototype.runAppend=function(j15,t9L,z_C){S88.r2m();var v4o,z$Y,z_W;S88.M8Y(22);v4o=S88.d58(j15,"append");z$Y=this.hasOwnProperty(v4o)?this[v4o]:[];z$Y=z$Y.concat(R_H.ChartEngine.prototype[v4o] || []);if(!z$Y.length){return !"1";}if(!z_C){z_C=this;}for(var V$C=0;V$C < z$Y.length;V$C++){z_W=z$Y[V$C].apply(z_C,t9L);if(z_W){return z_W;}}return ![];};R_H.ChartEngine.prototype.removeInjection=function(D4y){var X1D,h$l;X1D=D4y.method;if(this instanceof R_H.ChartEngine){if(!this[X1D]){return;}for(h$l=0;h$l < this[X1D].length;h$l++){if(this[X1D][h$l] == D4y.func){this[X1D].splice(h$l,+"1");return;}}}else {if(!R_H.ChartEngine.prototype[X1D]){return;}for(h$l=0;h$l < R_H.ChartEngine.prototype[X1D].length;h$l++){if(R_H.ChartEngine.prototype[X1D][h$l] == D4y.func){R_H.ChartEngine.prototype[X1D].splice(h$l,1);return;}}}};R_H.ChartEngine.prototype.remove=function(u3$){S88.J8h();var t9F;if(this instanceof R_H.ChartEngine){S88.C$o(22);delete this[S88.c6Y(u3$,"append")];S88.C$o(22);delete this[S88.d58(u3$,"prepend")];}else {t9F="appen";t9F+="d";S88.C$o(22);delete R_H.ChartEngine.prototype[S88.d58(u3$,t9F)];S88.M8Y(22);delete R_H.ChartEngine.prototype[S88.c6Y(u3$,"prepend")];}};};d7=V1n=>{var j13=x2dci;var k4o,S39;k4o=V1n.CIQ;S39=V1n.timezoneJS;k4o.ChartEngine.prototype.convertToDataZone=function(B1H){var H_s;if((B1H || B1H === 0) && this.dataZone){H_s=k4o.convertTimeZone(B1H,null,this.dataZone);B1H=new Date(H_s.getFullYear(),H_s.getMonth(),H_s.getDate(),H_s.getHours(),H_s.getMinutes(),H_s.getSeconds(),H_s.getMilliseconds());}return B1H;};k4o.ChartEngine.prototype.debug=function(){};k4o.ChartEngine.prototype.fps=function(Q0x,d_T){var T$z,z$Z,P4w,k_H;T$z=" sec";T$z+="onds";Q0x=Q0x || 5;z$Z=new Date().getTime();P4w=0;k_H=this;function r5F(){var C3z,l4E;C3z=(new Date().getTime() - z$Z) / +"1000";j13.r2m();if(C3z > Q0x){j13.C$o(40);l4E=j13.d58(C3z,P4w);j13.C$o(22);console.log(j13.c6Y(l4E,"FPS="));if(d_T){d_T(l4E);}return;}k_H.draw();P4w++;if(k4o.ChartEngine.useAnimation){requestAnimationFrame(r5F);}else {setTimeout(r5F,0);}}j13.M8Y(53);console.log(j13.d58("Running fps() for ",Q0x,T$z));r5F();};k4o.ChartEngine.htmlControls={mSticky:'
',iconsTemplate:'
'};k4o.ChartEngine.prototype.setChartType=function(x2p){var t1K,j2r;j13.J8h();t1K=this.layout;j2r=this.chart;if(t1K.aggregationType != "ohlc"){t1K.aggregationType="ohlc";if(j2r.canvas){this.createDataSet();}}t1K.chartType=x2p;this.setMainSeriesRenderer();if(this.mainSeriesRenderer.isAggregation && this.setAggregationType){return this.setAggregationType(x2p);}j2r.defaultChartStyleConfig={type:x2p};if(this.displayInitialized){this.draw();}this.changeOccurred("layout");};k4o.ChartEngine.prototype.setChartScale=function(f1T){var t1V;if(!f1T){f1T="linear";}t1V={percent:!!"1",relative:!![]};this.layout.chartScale=f1T;j13.J8h();if(this.chart.canvas){this.draw();}this.changeOccurred("layout");};k4o.ChartEngine.prototype.checkLogScale=function(){var t8T,m6d;t8T="lo";t8T+="g";if(this.runPrepend("checkLogScale",arguments)){return;}if(this.layout.chartScale !== t8T){return ![];}m6d=![];if(this.chart.yAxis.lowValue <= 0){this.setChartScale("linear");this.dispatch("notification","logdeactivated");m6d=!0;}this.runAppend("checkLogScale",arguments);return m6d;};k4o.ChartEngine.prototype.setAdjusted=function(z9t){this.layout.adj=z9t;if(this.chart.canvas){this.createDataSet();this.draw();}this.changeOccurred("layout");};k4o.ChartEngine.prototype.padOutPrice=function(b7W,A$X){var U0r,e3q,V8m,O1w;if(b7W !== 0 && (!b7W || typeof b7W != "number")){return "";}if(!A$X && A$X !== 0){A$X=b7W;}j13.C$o(22);U0r=j13.d58(A$X,"");e3q=+"0";if(U0r.indexOf(".") > -("1" | 0)){j13.M8Y(59);var X8I=j13.c6Y(1005,20,311,12);j13.C$o(0);var H42=j13.d58(7472,8);j13.C$o(67);var R6i=j13.c6Y(8490,2828,4245);j13.C$o(141);var L1g=j13.c6Y(5,2187,4362,6,2);j13.C$o(79);var q9C=j13.c6Y(14141,5,16,14915);j13.C$o(142);var U8c=j13.c6Y(2525,7603,7575,7,19);j13.M8Y(111);var v5O=j13.c6Y(8,10,1,2);e3q=U0r.substring(U0r.indexOf(+"480" === 215.42?(X8I,402.35):(H42,R6i) < L1g?(q9C,680.28) == "269.56" - 0?"x":".":U8c)).length - v5O;}if(A$X >= 1000){e3q=Math.max(e3q,0);}else if(A$X < 2){e3q=Math.max(e3q,4);}else {e3q=Math.max(e3q,2);}V8m=this.internationalizer;if(V8m){O1w=V8m.priceFormatters.length;if(e3q >= O1w){j13.C$o(0);e3q=j13.c6Y(O1w,1);}b7W=V8m.priceFormatters[e3q].format(b7W);}else {b7W=b7W.toFixed(e3q);}return b7W;};k4o.ChartEngine.prototype.formatPrice=function(g6y,G4S){var A1K,j97,h2e;if(g6y !== 0 && (!g6y || typeof g6y == "undefined")){return "";}if(!G4S){G4S=this.currentPanel;}if(!G4S){G4S=this.chart.panel;}j13.J8h();if(!G4S){return g6y.toString();}A1K=G4S.decimalPlaces;if(!A1K && A1K !== "0" << 64){A1K=G4S.chart.decimalPlaces;}if(!A1K && A1K !== 0){return g6y.toString();}j97=this.internationalizer;if(j97){h2e=j97.priceFormatters.length;if(A1K >= h2e){j13.M8Y(0);A1K=j13.d58(h2e,1);}g6y=j97.priceFormatters[A1K].format(g6y);}else {g6y=g6y.toFixed(A1K);}return g6y;};k4o.ChartEngine.prototype.determineMinMax=function(i53,X4l,i0y,K11,n4V,u9g,L9L,a1l,W0O){var B4k,t8V,J8s,O_i,O8c,n1B,Y2F,h$L,P8g,V30,B1n,A3A;j13.M8Y(124);var S8E=j13.d58(0,14,2,17);B4k=Number.MAX_VALUE * S8E;t8V=Number.MAX_VALUE;j13.J8h();J8s=!"1";O_i=i53.length;if(!W0O){W0O=[];}O8c=[];if(n4V){O_i=n4V;}for(var C4i=0;C4i <= O_i + 1;C4i++){if(X4l.length){if(C4i == O_i){n1B=this.getPreviousBar(this.chart,X4l["0" - 0],0);}else if(C4i == O_i + 1){n1B=this.getNextBar(this.chart,X4l[0],O_i - 1);}else {n1B=i53[C4i];}}if(!n1B)continue;if(!K11){if(n1B.transform){J8s=!![];n1B=n1B.transform;}else if(J8s)continue;;}Y2F=0;for(var g1Z=0;g1Z < X4l.length;g1Z++){h$L="n";h$L+="umber";P8g=k4o.existsInObjectChain(n1B,X4l[g1Z]);if(!P8g)continue;V30=P8g.obj[P8g.member];if(typeof V30 == h$L){V30=[V30];}for(var z4J=0;z4J < V30.length;z4J++){B1n=V30[z4J];if(u9g && B1n instanceof Array){B1n=B1n[0];}if(B1n || B1n === 0){if(i0y === !!({}) || i0y instanceof Array && i0y.indexOf(X4l[g1Z]) > -1){Y2F+=B1n;if(Y2F > B4k){B4k=Y2F;}if(Y2F < t8V){t8V=Y2F;}}else {if(B1n > B4k){B4k=B1n;}if(B1n < t8V){t8V=B1n;}O8c.push({value:B1n,quote:n1B});}}}}if(i0y === !![] || i0y instanceof Array && i0y.indexOf(X4l[g1Z]) > -1){O8c.push({value:Y2F,quote:n1B});}}A3A=[t8V,B4k];W0O.forEach(function(z7r){A3A=z7r(O8c,L9L,a1l) || A3A;});if(A3A[1] == Number.MAX_VALUE * -1){A3A[1]=+"0";}if(A3A[0] == Number.MAX_VALUE){A3A[0]=0;}return A3A;};k4o.ChartEngine.prototype.initializeDisplay=function(D9X){var b0C,P3b,B8T,F2F,v2d,r_x,m5Y,r_f,l2V,w1K,z2T,C4p,G1n,G_0,n7p,i6W;b0C="Clo";b0C+="se";P3b="H";P3b+="i";P3b+="g";P3b+="h";if(this.runPrepend("initializeDisplay",arguments)){return;}function d3R(K8c,w4G){var s$G,S6w,W93,W_J,p6t,a1_,c7h,m3s,W$l,p2j;s$G=!"1";S6w=r_x.layout && r_x.layout.studies && r_x.layout.studies[K8c.name];if(S6w && (!w4G || w4G.name == S6w.panel)){for(var f$u in S6w.outputMap){B8T.push(f$u);if(S6w.study){if(S6w.study.renderer){B8T=B8T.concat(k4o.createObjectChainNames(f$u,m5Y));}else if(!S6w.study.seriesFN){B8T=B8T.concat(k4o.createObjectChainNames(f$u,r_f));}}}for(var h$h=0;h$h <= 2;h$h++){B8T.push(S6w.name + "_hist" + (h$h?h$h:""));}s$G=!!({});}if(!w4G){return;}K8c.studies=[];K8c.renderers=[];if(s$G){K8c.studies.push(K8c.name);}for(var D3v in W9f){W93=W9f[D3v];W_J=W93.params;p6t=W_J.panel;if((W_J.yAxis || !r_x.panels[p6t] || r_x.panels[p6t].yAxis) != K8c)continue;if(p6t != w4G.name)continue;a1_=W93.highLowBars?m5Y:r_f;v2d=W93.bounded;for(var n2n=0;n2n < W93.seriesParams.length;n2n++){c7h=W93.seriesParams[n2n];if(c7h.hidden)continue;m3s=void 0;if(c7h.subField){m3s=k4o.createObjectChainNames(c7h.symbol,[c7h.subField]).concat(c7h.symbol);}else if(c7h.symbol){m3s=k4o.createObjectChainNames(c7h.symbol,a1_).concat(c7h.symbol);}else if(c7h.field){m3s=c7h.field;}else if(K8c == D9X.panel.yAxis){m3s=a1_;}if(m3s){B8T=B8T.concat(m3s);}if(W93.useSum){F2F=F2F.concat(m3s);}}K8c.renderers.push(D3v);}for(var Z_l in r_x.overlays){W$l=r_x.overlays[Z_l];if(W$l.panel != w4G.name)continue;if(W$l.name == K8c.name)continue;p2j=W$l.getYAxis(r_x);if(p2j != K8c)continue;K8c.studies.push(W$l.name);if(D9X.includeOverlaysInMinMax){d3R({name:W$l.name});}}}B8T=[];F2F=[];v2d=![];r_x=this;m5Y=["Close","Open",P3b,"Low"];r_f=[D9X.defaultPlotField || b0C];var {mainSeriesRenderer:j3G}=this;var {dataSegment:f31, seriesRenderers:W9f}=D9X;w1K=null;z2T=Math.floor((D9X.width - this.micropixels) / this.layout.candleWidth);if(D9X.scroll > D9X.maxTicks && D9X.maxTicks > z2T + 1){j13.C$o(44);var l3V=j13.d58(9,7,3,1);w1K=f31.length - l3V;}C4p=[];for(var C15 in this.panels){G1n=this.panels[C15];C4p=G1n.yaxisLHS.concat(G1n.yaxisRHS);for(var t8t=0;t8t < C4p.length;t8t++){G_0=C4p[t8t];B8T=[];F2F=[];n7p=D9X.transformFunc && G_0 == D9X.panel.yAxis;d3R(G_0,G1n);if(!this.currentlyImporting && !G_0.renderers.length && !G_0.studies.length){this.deleteYAxisIfUnused(G1n,G_0);continue;}if(j3G && j3G.determineMax){l2V=j3G.determineMax(f31,B8T,F2F,!n7p,w1K,v2d,G1n,G_0);}else {l2V=this.determineMinMax(f31,B8T,F2F,!n7p,w1K,v2d,G1n,G_0);}if(this.baselineHelper){l2V=this.setBaselineMinMax(l2V,G_0);}G_0.lowValue=l2V[0];G_0.highValue=l2V[1];if(G_0 == D9X.panel.yAxis){D9X.lowValue=G_0.lowValue;D9X.highValue=G_0.highValue;}}}i6W=D9X.state.aggregation;if(i6W && i6W.box){j13.M8Y(26);var l82=j13.d58(9,15,8);D9X.lowValue-=i6W.box / l82;j13.M8Y(143);var R3L=j13.c6Y(14,18,1,259,9);D9X.highValue+=i6W.box / R3L;}this.runAppend("initializeDisplay",arguments);};k4o.ChartEngine.prototype.setMarket=function(w1z,t8$){j13.J8h();if(!k4o.Market){return;}if(!t8$){t8$=this.chart;}t8$.market=new k4o.Market(w1z);for(var v8y in this.layout.marketSessions){t8$.market.disableSession(v8y,this.layout.marketSessions[v8y]);}};k4o.ChartEngine.prototype.setMarketFactory=function(w2D){j13.r2m();this.marketFactory=w2D;};k4o.ChartEngine.prototype.setResizeTimer=function(d9S){j13.J8h();this.resizeDetectMS=d9S;this.resizeHandle=k4o.resizeObserver(this.chart.container,S4a(this),this.resizeHandle,d9S);function S4a(D8y,F1D){var W2g;j13.J8h();W2g=function(){if(!D8y.chart.canvas){return;}j13.J8h();if(!k4o.isAndroid){if(D8y.chart.canvas.height != Math.floor(D8y.devicePixelRatio * D8y.chart.container.clientHeight) || D8y.chart.canvas.width != Math.floor(D8y.devicePixelRatio * D8y.chart.container.clientWidth)){D8y.resizeChart();}}};return function(){var H5t;H5t="undef";H5t+="ined";if(typeof ResizeObserver !== H5t){if(k4o.ChartEngine.useAnimation){requestAnimationFrame(W2g);}else {j13.C$o(46);setTimeout(W2g,j13.c6Y("0",0));}}else {W2g();}};}};k4o.ChartEngine.prototype.getRenderedItems=function(){var Q_Y,N4O,T1W,Y_o,G30,q0K,Z2d,r3J,n1L;Q_Y="Hig";Q_Y+="h";N4O=this.chart;T1W=this.currentPanel;if(!T1W){return;}Y_o=["Open",Q_Y,"Low","Close"];G30=["Close"];q0K=[];for(var K$k in this.overlays){if(this.overlays[K$k].panel !== T1W.name)continue;q0K=q0K.concat(Object.keys(this.overlays[K$k].outputMap));}for(var T7C in N4O.seriesRenderers){Z2d=N4O.seriesRenderers[T7C];if(Z2d.params.panel != T1W.name)continue;for(var X4j in Z2d.seriesParams){r3J=Z2d.seriesParams[X4j];n1L=Z2d.highLowBars?Y_o:G30;if(r3J.subField){q0K=q0K.concat(k4o.createObjectChainNames(r3J.symbol,[r3J.subField])).concat(r3J.symbol);}else if(r3J.symbol){q0K=q0K.concat(k4o.createObjectChainNames(r3J.symbol,n1L)).concat(r3J.symbol);}else if(r3J.field){q0K.push(r3J.field);}else if(T1W == N4O.panel){q0K=q0K.concat(n1L);}}}return q0K;};k4o.ChartEngine.prototype.setTransform=function(d4t,Y$e,M4i){d4t.transformFunc=Y$e;d4t.untransformFunc=M4i;};k4o.ChartEngine.prototype.unsetTransform=function(D7J){delete D7J.transformFunc;delete D7J.untransformFunc;for(var m66=0;D7J.dataSet && m66 < D7J.dataSet.length;m66++){D7J.dataSet[m66].transform=null;}};k4o.ChartEngine.prototype.isEquationChart=function(h6Q){if(h6Q && h6Q[+"0"] == "="){if(!this.allowEquations || !k4o.fetchEquationChart){console.warn("Error, equation chart option requires equationsAdvanced.js");return ![];}return !![];}return !({});};k4o.ChartEngine.prototype.correctIfOffEdge=function(C2t){var F4Q,E$q,d4u,O9$,w74,O2o,e0G,q6I,s21,h22,B2m;F4Q="cor";F4Q+="r";F4Q+="ectIfOffEdge";if(this.runPrepend("correctIfOffEdge",arguments)){return;}for(var L7y in this.charts){E$q=this.charts[L7y];d4u=E$q.dataSet;O9$=E$q.maxTicks;w74=this.layout;O2o=this.minimumLeftBars;e0G=Math.min(O2o,O9$);if(E$q.allowScrollPast){j13.C$o(0);q6I=j13.d58(O9$,e0G);if(e0G > d4u.length){q6I=O9$ - d4u.length;}if(E$q.scroll - q6I >= d4u.length){j13.C$o(69);var A_G=j13.d58(2,18,4,17);E$q.scroll=d4u.length + q6I - A_G;this.micropixels=0;}if(E$q.scroll <= e0G){E$q.scroll=e0G;this.micropixels=0;}}else {if(E$q.scroll < e0G){E$q.scroll=e0G;}if(E$q.scroll > d4u.length){E$q.scroll=d4u.length;}}if(E$q.allowScrollFuture === !({})){s21=this.getLabelOffsetInPixels(E$q,w74.chartType) + w74.candleWidth * E$q.whiteSpaceFutureTicks;j13.M8Y(85);var f1i=j13.c6Y(2,16,3,17,3);h22=O9$ - Math.round(s21 / w74.candleWidth) - f1i;B2m=this.micropixels < 0?E$q.scroll - 1:E$q.scroll;if(B2m < h22){E$q.scroll=h22;this.micropixels=0;}}}this.runAppend(F4Q,arguments);};j13.r2m();k4o.ChartEngine.prototype.getStartDateOffset=function(){for(var c3x=0;c3x < this.chart.dataSegment.length;c3x++){if(this.chart.dataSegment[c3x]){return c3x;}}return 0;};k4o.ChartEngine.prototype.setStartDate=function(C53){var C_3;for(var j$O=0;j$O < this.chart.dataSet.length;j$O++){C_3=this.chart.dataSet[j$O];if(C_3.DT.getTime() == C53.getTime()){this.chart.scroll=this.chart.dataSet.length - j$O;this.draw();return;}}};k4o.ChartEngine.prototype.clearPixelCache=function(){var n19,g8s;for(var V1e in this.panels){n19=this.panels[V1e];n19.cacheHigh=null;n19.cacheLow=null;n19.cacheLeft=1000000;n19.cacheRight=-1;}for(var m60 in this.charts){g8s=this.charts[m60];if(!g8s.dataSet)continue;for(var V4m=0;V4m < g8s.dataSet.length;V4m++){g8s.dataSet[V4m].cache={};}}};k4o.ChartEngine.prototype.adjustBackingStore=function(W_a,o1Y){var Y_C,P7s,t7X,d4r;this.devicePixelRatio=window.devicePixelRatio || 1;if(this.devicePixelRatio < 1.0){this.devicePixelRatio=1.0;}Y_C=o1Y.webkitBackingStorePixelRatio || o1Y.mozBackingStorePixelRatio || o1Y.msBackingStorePixelRatio || o1Y.oBackingStorePixelRatio || o1Y.backingStorePixelRatio || "1" << 0;P7s=this.devicePixelRatio / Y_C;if(!this.useBackingStore){this.devicePixelRatio=this.adjustedDisplayPixelRatio=1;return;}if(!k4o.isAndroid || k4o.is_chrome || k4o.isFF){t7X=W_a.width;d4r=W_a.height;j13.C$o(38);W_a.width=j13.d58(t7X,P7s);j13.M8Y(38);W_a.height=j13.c6Y(d4r,P7s);j13.C$o(22);W_a.style.width=j13.c6Y("px",t7X);j13.C$o(22);W_a.style.height=j13.c6Y("px",d4r);o1Y.scale(P7s,P7s);this.adjustedDisplayPixelRatio=P7s;this.backing={ratio:P7s,width:W_a.width,height:W_a.height,styleWidth:t7X,styleHeight:d4r};}};k4o.ChartEngine.prototype.reconstituteBackingStore=function(){var t6I,m3J,J7w,t1o,T9y;if(!this.useBackingStore || !this.backing){return;}t6I=[this.chart.canvas];if(this.useBackgroundCanvas){t6I.push(this.chart.backgroundCanvas);}m3J=this.backing;t6I.forEach(function(V6X){if(V6X.width == m3J.width){return;}V6X.width=m3J.width;V6X.height=m3J.height;j13.r2m();V6X.context.scale(m3J.ratio,m3J.ratio);});J7w=712748429;t1o=1654436079;T9y=2;for(var O06=1;j13.O$R(O06.toString(),O06.toString().length,15960) !== J7w;O06++){this.adjustedDisplayPixelRatio=m3J.ratio;T9y+=2;}if(j13.q2D(T9y.toString(),T9y.toString().length,11143) !== t1o){this.adjustedDisplayPixelRatio=m3J.ratio;}this.draw();};k4o.ChartEngine.prototype.disableBackingStore=function(){var y3T,E$W;if(!this.useBackingStore || !this.backing){return;}y3T=[this.chart.canvas];if(this.useBackgroundCanvas){y3T.push(this.chart.backgroundCanvas);}E$W=this.backing;y3T.forEach(function(U1e){var E$L,L33,E17;if(U1e.width == E$W.styleWidth){return;}E$L=-1933644852;L33=-581806431;E17=2;for(var y3p=1;j13.O$R(y3p.toString(),y3p.toString().length,493) !== E$L;y3p++){U1e.width=E$W.styleWidth;U1e.height=E$W.styleHeight;U1e.context.scale(1,1);E17+=2;}if(j13.O$R(E17.toString(),E17.toString().length,13839) !== L33){U1e.width=E$W.styleWidth;U1e.height=E$W.styleHeight;U1e.context.scale(7,3);}});j13.M8Y(19);j13.r2m();this.adjustedDisplayPixelRatio=j13.d58(0,"1");this.draw();};k4o.ChartEngine.prototype.getBackgroundCanvas=function(C9D){if(!C9D){C9D=this.chart;}return this.useBackgroundCanvas?C9D.backgroundCanvas:C9D.canvas;};k4o.ChartEngine.prototype.resizeCanvas=function(){var E3h,P5w,Z0v,s7t,Q$V,I4f,y49,n3V,z1E;j13.J8h();E3h=this.chart.canvas;P5w=this.chart.context;if(E3h && P5w){this.floatCanvas.height=this.chart.tempCanvas.height=this.chart.backgroundCanvas.height=E3h.height=this.chart.container.clientHeight;this.floatCanvas.width=this.chart.tempCanvas.width=this.chart.backgroundCanvas.width=E3h.width=this.chart.container.clientWidth;this.adjustBackingStore(E3h,P5w);this.adjustBackingStore(this.chart.tempCanvas,this.chart.tempCanvas.context);this.adjustBackingStore(this.floatCanvas,this.floatCanvas.context);this.adjustBackingStore(this.chart.backgroundCanvas,this.chart.backgroundCanvas.context);}Z0v=this.container.getBoundingClientRect();this.top=Z0v.top;this.left=Z0v.left;this.canvasWidth=this.chart.canvasWidth=this.chart.container.clientWidth;this.right=this.left + this.canvasWidth;this.height=this.chart.container.clientHeight;this.width=this.right - this.left;if(this.width === "0" >> 32 && !this.container.dimensionlessCanvas && this.container.closest("html")){s7t="warning: zero width chart. Check CSS for cha";s7t+="rt co";s7t+="ntainer.";console.log(s7t);}this.bottom=this.top + this.height;this.calculateYAxisPositions();this.chart.canvasRight=this.right;this.chart.canvasHeight=this.height;Q$V=this.layout.candleWidth;if(typeof Q$V == "undefined"){Q$V=8;}for(var s5g in this.charts){I4f=this.charts[s5g];this.setCandleWidth(Q$V,I4f);if(I4f.scroll < I4f.width / Q$V){I4f.scroll=Math.floor(I4f.width / Q$V);y49=Math.round(this.preferences.whitespace / this.layout.candleWidth);I4f.scroll-=y49;}n3V=10;try{j13.M8Y(0);var U_i=j13.d58(24,22);z1E=P5w.measureText("10:00").width * U_i;}catch(N$$){z1E=100;}while(n3V > 1){if(this.chart.width / z1E > n3V)break;n3V/=1.5;}I4f.xAxis.autoComputedTickSizePixels=Math.round(this.chart.width / n3V);if(I4f.xAxis.autoComputedTickSizePixels < 1){I4f.xAxis.autoComputedTickSizePixels=+"1";}}};k4o.ChartEngine.prototype.setCandleWidth=function(v_H,W3c){if(!W3c){W3c=this.chart;}v_H=this.constrainCandleWidth(v_H);this.layout.candleWidth=v_H;j13.C$o(144);var X0X=j13.d58(7,14,7,11,246);W3c.maxTicks=Math.round(W3c.width / v_H) + X0X;};k4o.ChartEngine.prototype.constrainCandleWidth=function(E6h){var Q2p,Q7E,Q5k;Q2p=this.minimumCandleWidth;Q7E=this.maximumCandleWidth;Q5k=this.animations.zoom;if(Q2p && E6h < Q2p){E6h=Q2p;if(Q5k && Q5k.running){Q5k.stop();}}if(Q7E && E6h > Q7E){E6h=Q7E;if(Q5k && Q5k.running){Q5k.stop();}}return E6h;};k4o.ChartEngine.prototype.resizeChart=function(t$T){var E0E;if(this.runPrepend("resizeChart",arguments)){return;}if(t$T !== !1){t$T=!!({});}if(t$T){this.preAdjustScroll();}E0E=this.chart.canvasHeight;this.resizeCanvas();if(t$T){this.postAdjustScroll();}if(this.displayInitialized){this.adjustPanelPositions();this.draw();;}else if(this.chart.canvasHeight !== 0 && E0E === 0){this.adjustPanelPositions();this.draw();}this.doDisplayCrosshairs();this.updateChartAccessories();this.runAppend("resizeChart",arguments);};k4o.ChartEngine.prototype.clear=function(){var b6C;this.displayInitialized=!1;for(var Z9Z in this.layout.studies){b6C=this.layout.studies[Z9Z];k4o.getFn("Studies.removeStudy")(this,b6C);}if(this.controls.chartControls){this.controls.chartControls.style.display="none";}this.chart.panel.title.innerHTML="";this.chart.panel.title.appendChild(document.createTextNode(this.chart.panel.display));};k4o.ChartEngine.prototype.fillScreen=function(){var g5J,w8Q,A9X,O8r,h5g;j13.r2m();g5J=this.chart;w8Q=this.layout.candleWidth;A9X=g5J.width - this.preferences.whitespace;O8r=g5J.dataSet.length;if(O8r * w8Q >= A9X){this.draw();return;}if(!this.mainSeriesRenderer || !this.mainSeriesRenderer.standaloneBars){O8r--;}j13.M8Y(40);h5g=j13.c6Y(O8r,A9X);this.setCandleWidth(h5g,g5J);this.home({maintainWhitespace:!![]});};k4o.ChartEngine.prototype.setMaxTicks=function(a6w,i3x){var L8n;if(!i3x){i3x={};}a6w=Math.round(a6w);if(a6w < 2){a6w=2;}L8n=i3x.padding?i3x.padding:0;j13.r2m();this.layout.candleWidth=(this.chart.width - L8n) / a6w;if(!this.layout.candleWidth){this.layout.candleWidth=+"8";}this.chart.maxTicks=Math.round(this.chart.width / this.layout.candleWidth - 0.499);if(i3x.padding || i3x.padding === 0){j13.C$o(22);this.chart.scroll=j13.c6Y(1,a6w);};};k4o.ChartEngine.prototype.initializeChart=function(n8Z){var E2b,u1X,s1Y,U4g,q$9,a3V,H7L,T_W,l$y,n7Y,i$$,E7V,T$2,o5d,y3B,v02,K8y,t2a,r0I,x_H,Y_d;E2b="in";E2b+="i";E2b+="tializeC";E2b+="hart";u1X="canva";u1X+="s";s1Y="c";s1Y+="an";s1Y+="va";s1Y+="s";if(this.runPrepend("initializeChart",arguments)){return;}U4g=this.chart;if(!U4g.symbolObject.symbol){U4g.symbolObject.symbol=U4g.symbol;}if(this.locale){this.setLocale(this.locale);}if(!this.displayZone && k4o.ChartEngine.defaultDisplayTimeZone){this.setTimeZone(null,k4o.ChartEngine.defaultDisplayTimeZone);}this.resetDynamicYAxis({noRecalculate:!![]});this.calculateYAxisPositions();this.micropixels=0;if(n8Z){U4g.container=n8Z;}else {n8Z=U4g.container;}n8Z.stx=this;if(!n8Z.CIQRegistered){n8Z.CIQRegistered=!"";k4o.ChartEngine.registeredContainers.push(n8Z);}if(this.registerHTMLElements){this.registerHTMLElements();}q$9=U4g.canvas;a3V=U4g.backgroundCanvas;H7L=U4g.tempCanvas;T_W=this.floatCanvas;l$y=U4g.canvasShim;if(q$9 && document.createElement("canvas").getContext){if(!q$9.id){n8Z.removeChild(q$9);U4g.canvas=null;}if(H7L && !H7L.id){n8Z.removeChild(H7L);U4g.tempCanvas=null;}if(T_W && !T_W.id){n8Z.removeChild(T_W);this.floatCanvas=null;}if(a3V && !a3V.id){n8Z.removeChild(a3V);U4g.backgroundCanvas=null;}}else {this.setCandleWidth(this.layout.candleWidth);}if(!U4g.backgroundCanvas){a3V=U4g.backgroundCanvas=document.createElement("canvas");}n8Z.appendChild(a3V);V6E(a3V);if(!U4g.canvasShim){l$y=U4g.canvasShim=document.createElement("div");}l$y.className="stx-canvas-shim";n8Z.appendChild(l$y);if(!U4g.canvas){q$9=U4g.canvas=document.createElement(s1Y);}n8Z.appendChild(q$9);V6E(q$9);U4g.context=q$9.context;if(!U4g.tempCanvas){H7L=U4g.tempCanvas=document.createElement("canvas");}n8Z.appendChild(H7L);V6E(H7L,!![]);if(!this.floatCanvas){T_W=this.floatCanvas=document.createElement(u1X);}n8Z.appendChild(T_W);V6E(T_W,!!({}));this.resizeCanvas();function V6E(A5r,v5S){var c8Q,F2z,Q8i,O2y;c8Q="n";c8Q+="on";c8Q+="e";F2z="a";F2z+="bs";F2z+="o";F2z+="lute";Q8i="2";Q8i+="d";A5r.context=A5r.getContext(Q8i);j13.C$o(0);A5r.context.lineWidth=j13.d58("1",0);O2y=A5r.style;O2y.position=F2z;O2y.left="0px";if(v5S){O2y.display=c8Q;}}if(k4o.isAndroid){H7L.ontouchstart=T_W.ontouchstart=function(J0q){if(J0q.preventDefault){J0q.preventDefault();}};}n7Y=this.panels;U4g.panel.display=U4g.symbol;if(U4g.symbolDisplay){U4g.panel.display=U4g.symbolDisplay;}this.adjustPanelPositions();U4g.panel=n7Y[U4g.name];for(var R6p in n7Y){i$$=n7Y[R6p].yaxisLHS.concat(n7Y[R6p].yaxisRHS);for(var O8D=0;O8D < i$$.length;O8D++){i$$[O8D].height=n7Y[R6p].yAxis.height;this.calculateYAxisMargins(i$$[O8D]);;}}this.initialWhitespace=this.preferences.whitespace;if(U4g.dataSet && U4g.dataSet.length > 0){U4g.scroll=Math.floor(U4g.width / this.layout.candleWidth);E7V=Math.round(this.preferences.whitespace / this.layout.candleWidth);U4g.scroll-=E7V;}if(k4o.touchDevice){T$2=".ov";T$2+="erla";T$2+="yTras";T$2+="hCan";o5d=n8Z.querySelector(".overlayEdit");y3B=n8Z.querySelector(T$2);v02=n8Z.querySelector(".vectorTrashCan");K8y=function(c9O,k_9,d3S){j13.r2m();return function(D_g){j13.r2m();c9O.deleteHighlighted(k_9,d3S);};};if(o5d){k4o.safeClickTouch(o5d,K8y(this,!![],!!({})));if(y3B){k4o.safeClickTouch(y3B,K8y(this,![]));}}else if(y3B){k4o.safeClickTouch(y3B,K8y(this,!![]));}if(v02){k4o.safeClickTouch(v02,K8y(this,!""));}}if(this.manageTouchAndMouse){this.registerTouchAndMouseEvents();}if(this.handleMouseOut){n8Z.onmouseout=(function(x0N){return function(Z9p){x0N.handleMouseOut(Z9p);};})(this);k4o.smartHover();}if(this.abortDrawings){this.abortDrawings();}this.undoStamps=[];for(var m9x in n7Y){t2a=n7Y[m9x];if(t2a.markerHolder){n8Z.removeChild(t2a.markerHolder);t2a.markerHolder=null;}}for(var D9j in this.plugins){r0I=this.plugins[D9j];if(r0I.display){if(r0I.initializeChart){r0I.initializeChart(this);}}}if(!this.resizeListenerInitialized){x_H=this;this.resizeListenerInitialized=!0;Y_d=function(){return function(r5T){x_H.resizeChart();};};this.addDomEventListener(window,"resize",Y_d(),!!1);}if(U4g.baseline.userLevel){U4g.baseline.userLevel=null;}this.setResizeTimer(this.resizeDetectMS);this.runAppend(E2b,arguments);};k4o.ChartEngine.prototype.destroy=function(){j13.r2m();var m9y,U1E,b0M,z1B;this.setResizeTimer(+"0");if(this.quoteDriver){this.quoteDriver.die();}this.styles={};for(var O17=0;O17 < this.eventListeners.length;O17++){m9y=this.eventListeners[O17];m9y.element.removeEventListener(m9y.event,m9y["function"],m9y.options);}this.touchAndMouseEventsRegistered=!"1";this.eventListeners=[];if(this.streamParameters.timeout){clearTimeout(this.streamParameters.timeout);}U1E=k4o.ChartEngine.registeredContainers;b0M=U1E.indexOf(this.chart.container);if(b0M > -("1" ^ 0)){U1E.splice(b0M,1);}if(this.slider){z1B=U1E.indexOf(this.slider.slider.chart.container);if(z1B > -1){U1E.splice(z1B,1);}}};k4o.ChartEngine.prototype.preAdjustScroll=function(F2u){j13.J8h();if(!F2u){F2u=this.chart;}this.previousAdjust={chart:F2u,scroll:F2u.scroll,maxTicks:F2u.maxTicks};};k4o.ChartEngine.prototype.postAdjustScroll=function(){var c79;if(!this.previousAdjust){return;}c79=this.previousAdjust.chart;c79.scroll=this.previousAdjust.scroll + (c79.maxTicks - this.previousAdjust.maxTicks);if(this.displayInitialized){this.draw();}};k4o.ChartEngine.prototype.translateIf=function(r$d){if(this.translationCallback){return this.translationCallback(r$d);}j13.J8h();return r$d;};k4o.ChartEngine.prototype.doCleanupDates=function(V3q,s1j){var T1A,S_5,R0y,u90,U8e,A0H,M0X;j13.J8h();if(!V3q || !V3q.length){return;}for(var z4t=0;z4t < V3q.length;z4t++){T1A="[obj";T1A+="ect Stri";T1A+="ng]";S_5=V3q[z4t];R0y=S_5.DT;if(!R0y && !S_5.Date)continue;if(S_5.DT && Object.prototype.toString.call(R0y) == T1A && R0y.length <= 10){R0y=new Date(R0y);R0y.setMinutes(R0y.getMinutes() + R0y.getTimezoneOffset());}else {u90="[obj";u90+="ect Da";u90+="te]";U8e=!"";if(!S_5.DT){R0y=k4o.strToDateTime(S_5.Date);if(S_5.Date.length <= 10){U8e=![];}}if(Object.prototype.toString.call(R0y) != u90){R0y=new Date(R0y);}if(S39.Date && this.dataZone && U8e){A0H=new S39.Date(R0y.getFullYear(),R0y.getMonth(),R0y.getDate(),R0y.getHours(),R0y.getMinutes(),this.dataZone);j13.M8Y(77);var t_5=j13.c6Y(8804,4,10,980);M0X=R0y.getSeconds() * t_5 + R0y.getMilliseconds();R0y=new Date(A0H.getTime() + M0X);}if(k4o.ChartEngine.isDailyInterval(s1j)){j13.C$o(38);R0y.setHours(0,+"0",0,j13.d58("0",1));}}if(!S_5.DT){S_5.Date=k4o.yyyymmddhhmmssmmm(R0y);}S_5.DT=R0y;}};k4o.ChartEngine.prototype.doCleanupGaps=function(X3C,h2L,g6B){var M$v,U3l,I6D,T8G,I5b,Y3d,p_l,p_$,C8r,v9p,Y1v,g4e,b6X,Y_8,c2w;function S7D(I$j,q4Y){var J$C,h17,v69,J5d,P7$;J$C="u";J$C+="ndefin";J$C+="ed";h17=g6B.field;if(h17){v69="undefin";v69+="ed";if(typeof I$j[h17] != "undefined" && typeof q4Y[h17] == v69){q4Y[h17]=T8G?null:I$j[h17];}return;}if(T8G){return;}J5d=I$j[g4e];P7$=q4Y[g4e];if(typeof J5d != "undefined" && typeof P7$ == J$C){k4o.ensureDefaults(q4Y,{Close:J5d,Open:J5d,High:J5d,Low:J5d,Volume:0,Adj_Close:I$j.Adj_Close});}}M$v="w";M$v+="e";M$v+="e";M$v+="k";if(!X3C || !X3C.length){return X3C;}function N1h(k1I,a$6){var k4l,v6w,m5D,L8o,l1e;k4l=g6B.field;j13.r2m();v6w=k4l?p_$[k4l]:p_$;if(v6w === undefined){v6w={};}m5D=T8G?null:v6w[g4e];L8o=T8G?null:v6w.Adj_Close;while(+k1I < +a$6){l1e={DT:k1I};if(k4l){}else {p_l.push(l1e);k4o.extend(l1e,{Open:m5D,High:m5D,Low:m5D,Close:m5D,Volume:0,Adj_Close:L8o});}k1I=Y1v.next();}}U3l=this.layout.interval;g6B=g6B?g6B:{};if(!h2L){h2L=this.chart;}if(!k4o.Market || !h2L.market){return X3C;}if(!g6B.noCleanupDates){this.doCleanupDates(X3C,U3l);}I6D=g6B.cleanupGaps;if(I6D === !!0){return X3C;}if(!I6D || I6D === !![]){I6D=this.cleanupGaps || I6D;}j13.M8Y(106);T8G=j13.c6Y(I6D,"gap");if(!I6D){return X3C;}if(U3l == "tick"){return X3C;}if(U3l == "month" || U3l == M$v){I5b="d";I5b+="a";I5b+="y";if(this.dontRoll){return X3C;}U3l=I5b;}Y3d=function(m08){j13.J8h();if(m08.DT){if(Object.prototype.toString.call(m08.DT) != "[object Date]"){return new Date(m08.DT);}return new Date(+m08.DT);}return k4o.strToDateTime(m08.Date);};p_l=[];p_$=X3C[0];j13.J8h();p_l.push(p_$);C8r={begin:Y3d(p_$),interval:U3l,periodicity:1,timeUnit:this.layout.timeUnit};v9p=new k4o.Market(h2L.market.market_def);Y1v=v9p.newIterator(C8r);if(this.extendedHours && this.extendedHours.filter){Y1v.market.enableAllAvailableSessions();}g4e=h2L.defaultPlotField;for(var G0h=0;G0h < X3C.length;G0h++){if(X3C[G0h][g4e] !== undefined)break;if(X3C[G0h].Value !== undefined){g4e="Value";break;}}for(var P2x=1;P2x < X3C.length;P2x++){Y_8=X3C[P2x];b6X=Y1v.next();c2w=Y3d(Y_8);if(b6X < c2w){N1h(b6X,c2w);b6X=Y1v.market._convertFromMarketTZ(Y1v.begin,Y1v.outZone);}while(c2w < b6X){if(++P2x == X3C.length){return p_l;}S7D(p_$,Y_8);p_l.push(Y_8);p_$=Y_8;Y_8=X3C[P2x];c2w=Y3d(Y_8);}if(b6X < c2w){P2x--;b6X=Y1v.previous();}else {S7D(p_$,Y_8);p_l.push(Y_8);p_$=Y_8;}}return p_l;};k4o.ChartEngine.prototype.getCreatingLibrary=function(){j13.r2m();return V1n;};};m1=Y_z=>{var g4U=x2dci;var c4S;c4S=Y_z.CIQ;g4U.r2m();c4S.ChartEngine.Panel=function(M3j,r1o){if(r1o){this.yAxis=r1o;}else {this.yAxis=new c4S.ChartEngine.YAxis();}this.name=M3j;g4U.J8h();this.state={};;};c4S.extend(c4S.ChartEngine.Panel.prototype,{name:null,display:null,chart:null,yAxis:null,shareChartXAxis:null,top:null,bottom:null,height:null,percent:null,displayEdgeIfPadded:!!1,noDrag:![],exportable:!!({})},!!"1");c4S.ChartEngine.prototype.whichPanel=function(x2Z){var z8v;for(var y3q in this.panels){z8v=this.panels[y3q];if(z8v.hidden)continue;if(x2Z >= z8v.top && x2Z < z8v.bottom){return z8v;}}return null;};c4S.ChartEngine.prototype.panelExists=function(j1C){var r7D;for(var c4d in this.panels){r7D=this.panels[c4d];if(r7D.name == j1C){return !!1;}}return !({});};c4S.ChartEngine.prototype.storePanels=function(){var w26,j3g;if(!this.layout){this.layout={};}w26=this.layout;w26.panels={};for(var H2_ in this.panels){j3g=this.panels[H2_];w26.panels[j3g.name]={percent:j3g.percent,display:j3g.display,yAxis:j3g.yAxis};}};c4S.ChartEngine.prototype.savePanels=function(d1M){this.storePanels();if(d1M !== ![]){this.changeOccurred("layout");}};c4S.ChartEngine.prototype.privateDeletePanel=function(p8s){var W2y,x$k,C26;for(var b3q in this.layout.studies){W2y=this.layout.studies[b3q];if(W2y.panel == p8s.name){this.cleanupRemovedStudy(W2y);}}delete this.panels[p8s.name];for(var g9r in this.overlays){if(this.overlays[g9r].panel == p8s.name){if(this.layout.studies){this.cleanupRemovedStudy(this.layout.studies[g9r]);}delete this.overlays[g9r];}}for(var U7g in this.chart.series){if(this.chart.series[U7g].parameters.panel == p8s.name){this.removeSeries(this.chart.series[U7g],this.chart);}}if(p8s.holder){this.chart.container.removeChild(p8s.holder);if(this.getMarkerArray){x$k="p";x$k+="anelName";C26=this.getMarkerArray(x$k,p8s.name);for(var w3$=0;w3$ < C26.length;w3$++){this.removeFromHolder(C26[w3$]);}}}if(p8s.handle){p8s.handle.remove();}this.currentPanel=null;};c4S.ChartEngine.prototype.plotsInPanel=function(J8j){var w6p,L3w,T0Z,y3o;w6p=[];L3w=J8j;if(typeof J8j == "object"){L3w=J8j.name;}for(var b5U in this.layout.studies){T0Z=this.layout.studies[b5U];if(L3w === T0Z.panel){w6p.push(T0Z);}}for(var Y63 in this.chart.seriesRenderers){y3o=this.chart.seriesRenderers[Y63];if(L3w === y3o.params.panel){w6p.push(y3o);}}return w6p;};c4S.ChartEngine.prototype.checkForEmptyPanel=function(s5e,j$f,s0N){g4U.r2m();var S0U,G9j;if(!s5e){return ![];}S0U=s5e;if(typeof s5e == "object"){S0U=s5e.name;}if(S0U === this.chart.name){return ![];}if(!s0N){s0N=[];}else if(!(s0N instanceof Array)){s0N=[s0N];}G9j=this.plotsInPanel(s5e);for(var o_B=0;o_B < G9j.length;o_B++){if(s0N.indexOf(G9j[o_B]) == -+"1"){return ![];}}if(!j$f){this.panelClose(this.panels[S0U]);}return !0;};c4S.ChartEngine.prototype.panelClose=function(F18){var H$V;if(!F18){return;}if(this.runPrepend("panelClose",arguments)){return;}this.cancelTouchSingleClick=!!({});c4S.ChartEngine.drawingLine=![];if(F18.soloing){this.panelSolo(F18);}if(this.charts[F18.name]){for(var b2b in this.panels){H$V=this.panels[b2b];if(H$V.chart.name == F18.name){this.privateDeletePanel(H$V);}}delete this.charts[F18.name];}else {this.privateDeletePanel(F18);}if(!this.currentlyImporting){this.showCrosshairs();this.resetDynamicYAxis({noRecalculate:!!"1"});this.calculateYAxisPositions();this.draw();this.savePanels();}this.userPointerDown=this.grabbingScreen=!({});if(this.openDialog){this.openDialog="";}this.runAppend("panelClose",arguments);};c4S.ChartEngine.prototype.deleteAllPanels=function(){var Z_Q;for(var t4T in this.panels){Z_Q=this.panels[t4T];this.privateDeletePanel(Z_Q);}this.layout.panels={};this.panels={};};c4S.ChartEngine.prototype.panelUp=function(o27){var j3d,c$q,y4h,S4R;this.cancelTouchSingleClick=!!1;c4S.ChartEngine.drawingLine=![];this.showCrosshairs();j3d={};c$q=0;g4U.r2m();for(y4h in this.panels){if(y4h == o27.name)break;c$q++;}if(!c$q){return;}S4R=0;for(y4h in this.panels){if(S4R == c$q - 1){j3d[o27.name]=o27;}if(y4h == o27.name)continue;j3d[y4h]=this.panels[y4h];S4R++;}this.panels=j3d;this.adjustPanelPositions();this.draw();this.savePanels();};c4S.ChartEngine.prototype.panelDown=function(y9C){var J3w,Q8z,F0d,X8j,e8e;g4U.r2m();this.cancelTouchSingleClick=!"";c4S.ChartEngine.drawingLine=!!0;this.showCrosshairs();J3w={};Q8z=+"0";for(F0d in this.panels){if(F0d == y9C.name)break;Q8z++;}X8j=+"0";for(F0d in this.panels){X8j++;}if(Q8z == X8j - 1){return;}e8e=0;for(F0d in this.panels){if(F0d == y9C.name){e8e++;continue;}J3w[F0d]=this.panels[F0d];if(e8e == Q8z + 1){J3w[y9C.name]=y9C;}e8e++;}this.panels=J3w;this.adjustPanelPositions();this.draw();this.savePanels();};c4S.ChartEngine.prototype.panelSolo=function(n0k){var Q4A,V7z,y0n,g5m,k7N,Q9K;this.cancelTouchSingleClick=!!({});c4S.ChartEngine.drawingLine=!({});this.showCrosshairs();Q4A=!!({});if(n0k.soloing){y0n="s";y0n+="tx_solo_lit";Q4A=!1;n0k.soloing=!!0;n0k.solo.classList.remove(y0n);n0k.percent=n0k.oldPercent;if(n0k.name != "chart"){if(this.soloPanelToFullScreen){if(n0k.percent == 1){for(V7z in this.panels){g5m=this.panels[V7z];if(g5m != n0k){n0k.percent-=g5m.percent;}}}}else {this.chart.panel.percent=this.chart.panel.oldPercent;}}if(this.soloPanelToFullScreen){this.xAxisAsFooter=this.chart.panel.oldXAxisAsFooter;}}else {k7N="ch";k7N+="art";Q9K="st";Q9K+="x_solo_lit";n0k.soloing=!!1;n0k.solo.classList.add(Q9K);n0k.oldPercent=n0k.percent;this.chart.panel.oldXAxisAsFooter=this.xAxisAsFooter;if(n0k.name != k7N){if(this.soloPanelToFullScreen){this.xAxisAsFooter=!!"1";}else {this.chart.panel.oldPercent=this.chart.panel.percent;g4U.M8Y(16);var M4T=g4U.c6Y(10,0,12,119);n0k.percent=M4T - this.chart.panel.percent;}}}for(V7z in this.panels){this.panels[V7z].hidden=Q4A;}if(!this.soloPanelToFullScreen){this.chart.panel.hidden=![];}n0k.hidden=!"1";this.resetDynamicYAxis({noRecalculate:!!1});this.calculateYAxisPositions();this.draw();this.savePanels();};c4S.ChartEngine.prototype.calculatePanelPercent=function(C7y){var A1b;A1b=C7y.bottom - C7y.top;C7y.percent=A1b / this.chart.canvasHeight;};c4S.ChartEngine.prototype.resizePanels=function(){var P_d,U6c,D8t,A9x,m5S,T9v,d35,F5L,S92;if(!c4S.ChartEngine.resizingPanel){return;}P_d=1868099388;g4U.C$o(38);U6c=-g4U.d58("872807414",1);D8t=2;for(var S$Q=1;g4U.q2D(S$Q.toString(),S$Q.toString().length,39756) !== P_d;S$Q++){F5L=c4S.ChartEngine.crosshairY >= this.resolveY(c4S.ChartEngine.resizingPanel.top);D8t+=2;}if(g4U.O$R(D8t.toString(),D8t.toString().length,42342) !== U6c){F5L=c4S.ChartEngine.crosshairY > this.resolveY(c4S.ChartEngine.resizingPanel.top);}for(var h2n in this.panels){if(this.panels[h2n] == c4S.ChartEngine.resizingPanel)break;if(this.panels[h2n].hidden)continue;A9x=this.panels[h2n];}S92=this.backOutY(c4S.ChartEngine.crosshairY);if(F5L){T9v=c4S.ChartEngine.resizingPanel.yaxisLHS.concat(c4S.ChartEngine.resizingPanel.yaxisRHS);for(d35=0;d35 < T9v.length;d35++){g4U.M8Y(16);var f$d=g4U.c6Y(10,1,3,23);m5S=T9v[d35].initialMarginTop + T9v[d35].initialMarginBottom + f$d;if(S92 > T9v[d35].bottom - m5S){S92=T9v[d35].bottom - m5S;}}}else {T9v=A9x.yaxisLHS.concat(A9x.yaxisRHS);for(d35="0" << 64;d35 < T9v.length;d35++){m5S=T9v[d35].initialMarginTop + T9v[d35].initialMarginBottom + +"10";if(S92 < T9v[d35].top + m5S){S92=T9v[d35].top + m5S;}}}c4S.ChartEngine.crosshairY=this.resolveY(S92);A9x.bottom=S92;c4S.ChartEngine.resizingPanel.top=S92;this.calculatePanelPercent(A9x);g4U.r2m();this.calculatePanelPercent(c4S.ChartEngine.resizingPanel);this.adjustPanelPositions();this.draw();this.savePanels();};c4S.ChartEngine.prototype.isPanelAboveChart=function(m6F){g4U.J8h();for(var N4c in this.panels){if(N4c == "chart"){return !!0;}if(N4c == m6F.name){return !![];}}return !!0;};c4S.ChartEngine.prototype.adjustPanelPositions=function(){var h91,B6w,D7X,r9z,I3b,i9Z,j3I,M0k,a2K,F9T,q1D,Z2Z,U6$,w7K,H7M,K9n,h7_,x1B,y5H,G99,f_z,v72,P$0,V5s,l2T,p0U,w2r;h91="stx-sho";h91+="w";B6w="adjus";B6w+="tPanelPos";B6w+="ition";B6w+="s";var {chart:D2O, panels:S_J}=this;if(D2O.tempCanvas){c4S.clearCanvas(D2O.tempCanvas,this);}if(this.runPrepend(B6w,arguments)){return;}D7X=0;r9z=D2O.canvasHeight;I3b=!({});i9Z=0;g4U.J8h();j3I=0;M0k=![];for(a2K in S_J){F9T=S_J[a2K];if(isNaN(F9T.percent) || F9T.percent <= +"0"){F9T.percent=0.05;}if(F9T.hidden)continue;i9Z+=F9T.percent;j3I++;if(F9T.soloing){M0k=!!"1";}}for(a2K in S_J){q1D=0;F9T=S_J[a2K];if(F9T.hidden){if(F9T.markerHolder){F9T.markerHolder.style.display="none";}continue;}if(this.manageTouchAndMouse){if(F9T.up){if(!I3b){I3b=!![];F9T.up.classList.remove("stx-show");}else {Z2Z="stx-sho";Z2Z+="w";if(this.displayIconsUpDown){F9T.up.classList.add(Z2Z);}}}if(F9T.solo){if(M0k){if(F9T.soloing && this.displayIconsSolo){F9T.solo.classList.add("stx-show");}else {F9T.solo.classList.remove("stx-show");}}else if(j3I == +"1"){F9T.solo.classList.remove("stx-show");}else if(j3I == 2 && !this.soloPanelToFullScreen){F9T.solo.classList.remove("stx-show");}else {U6$="stx";U6$+="-show";if(this.displayIconsSolo){F9T.solo.classList.add(U6$);}}}if(F9T.down){if(j3I == 1){w7K="st";w7K+="x-sh";w7K+="ow";F9T.down.classList.remove(w7K);}else {if(this.displayIconsUpDown){F9T.down.classList.add("stx-show");}}}if(F9T.edit){if(F9T.editFunction){F9T.edit.classList.add("stx-show");}else {F9T.edit.classList.remove("stx-show");}}if(F9T.close){H7M="s";H7M+="tx-show";K9n="st";K9n+="x-show";if(this.displayIconsClose){F9T.close.classList.add(K9n);}else {F9T.close.classList.remove(H7M);}}}F9T.percent=F9T.percent / i9Z;F9T.top=D7X;F9T.bottom=F9T.top + r9z * F9T.percent;F9T.height=F9T.bottom - F9T.top;if(F9T.chart.name == F9T.name){F9T.chart.top=F9T.top;F9T.chart.bottom=F9T.bottom;F9T.chart.height=F9T.height;}D7X=F9T.bottom;if(F9T.yaxisLHS){h7_=F9T.yaxisLHS.concat(F9T.yaxisRHS);for(var c1_=0;c1_ < h7_.length;c1_++){x1B="n";x1B+="o";x1B+="ne";y5H=h7_[c1_];if(y5H.zoom && y5H.height > 0){q1D=y5H.zoom / y5H.height;}this.adjustYAxisHeightOffset(F9T,y5H);y5H.height=y5H.bottom - y5H.top;if(q1D){y5H.scroll*=q1D * y5H.height / y5H.zoom;y5H.zoom=q1D * y5H.height;if(y5H.zoom > y5H.height){y5H.zoom=0;y5H.scroll=0;}}if(!y5H.high && y5H.high !== 0){y5H.high=100;y5H.low=0;y5H.shadow=100;}y5H.multiplier=y5H.height / y5H.shadow;if(y5H.position === x1B){this.calculateYAxisMargins(y5H);}}}if(F9T.holder){G99="p";G99+="x";f_z="p";f_z+="x";F9T.holder.style.right="0px";F9T.holder.style.top=F9T.top + "px";F9T.holder.style.left="0px";F9T.holder.style.height=F9T.height + "px";F9T.subholder.style.left=F9T.left + f_z;F9T.subholder.style.width=F9T.width + "px";F9T.subholder.style.top="0px";if(F9T.yAxis.height >= 0){F9T.subholder.style.height=F9T.yAxis.height + G99;}}}if(a2K && S_J[a2K].down){S_J[a2K].down.classList.remove(h91);}if(this.manageTouchAndMouse && j3I == 2 && !M0k && D2O.panel.solo){D2O.panel.solo.classList.add("stx-show");}if(D2O.panel){v72="p";v72+="x";if(M0k && this.soloPanelToFullScreen){P$0=D2O.canvasHeight - F9T.yAxis.bottom + +"12";}else {g4U.M8Y(0);var x6W=g4U.c6Y(43,11);P$0=D2O.canvasHeight - D2O.panel.yAxis.bottom + ("12" >> x6W);}V5s=this.controls;var {chartControls:a$m, home:o$h, notificationTray:j_s}=V5s;l2T=this.width - D2O.panel.right;if(a$m){g4U.C$o(22);a$m.style.bottom=g4U.d58(v72,P$0);}if(o$h){p0U="p";p0U+="x";g4U.M8Y(22);o$h.style.bottom=g4U.d58("px",P$0);g4U.M8Y(22);o$h.style.marginRight=g4U.d58(p0U,l2T);}if(j_s){w2r="p";w2r+="x";g4U.C$o(22);j_s.style.bottom=g4U.c6Y("px",P$0);g4U.M8Y(22);j_s.style.marginRight=g4U.d58(w2r,l2T);}}this.clearPixelCache();if(this.drawingObjects.length){this.adjustDrawings();}this.runAppend("adjustPanelPositions",arguments);};c4S.ChartEngine.prototype.createPanel=function(c9n,J3S,T$y,c9W,T_4,N6X){var J63,h$u,B7S,T1u,C$a;if(this.runPrepend("createPanel",arguments)){return;}if(!c9W){c9W="chart";}J63=this.chart.canvasHeight;if(!T$y){g4U.M8Y(38);T$y=g4U.d58(J63,0.2);}if(T$y > J63){g4U.M8Y(38);T$y=g4U.d58(J63,0.5);}g4U.M8Y(40);h$u=g4U.c6Y(J63,T$y);g4U.C$o(0);B7S=g4U.c6Y(1,h$u);T1u=!({});for(var a$i in this.panels){C$a=this.panels[a$i];C$a.percent*=B7S;if(C$a.soloing){T1u=!!({});}}this.stackPanel(c9n,J3S,h$u,c9W,T_4);this.panels[J3S].hidden=T1u;this.panels[J3S].exportable=!N6X;this.adjustPanelPositions();this.savePanels(!({}));this.runAppend("createPanel",arguments);return this.panels[J3S];};c4S.ChartEngine.prototype.modifyPanel=function(P$X,x09){var F0a,O$X,Y23,y07,z0r,q_1,H3w,o_9;F0a=P$X.name;var {studies:N_F}=this.layout;var {series:T77}=this.chart;var {name:i6Z, display:n0L, yAxis:D1c}=x09 || ({});if(!i6Z){i6Z=c4S.uniqueID();}if(!n0L){n0L=i6Z;}if(!D1c){D1c=P$X.yAxis;D1c.name=i6Z;}O$X={};for(var s_B in this.panels){if(s_B === P$X.name){Y23=this.panels[s_B];Y23.name=i6Z;Y23.display=n0L;Y23.yAxis=D1c;P$X=O$X[i6Z]=Y23;if(this.moveMarkers && F0a !== i6Z){this.moveMarkers(F0a,i6Z);}}else {O$X[s_B]=this.panels[s_B];}}this.panels=O$X;y07=![];for(var W3E in N_F){z0r=N_F[W3E];if(z0r.panel === F0a){z0r.panel=i6Z;if(z0r.parameters && z0r.parameters.panelName){y07=!!"1";z0r.parameters.panelName=i6Z;}}}for(var h4W in T77){if(T77[h4W].parameters.panel === F0a){y07=!0;q_1={panel:i6Z};if(T77[h4W].parameters.yAxis && T77[h4W].parameters.yAxis.name === F0a){q_1.yAxis=D1c;}this.modifySeries(h4W,q_1,!"");}}if(y07){this.changeOccurred("layout");}H3w=!"1";for(var t2K=0;t2K < this.drawingObjects.length;t2K++){o_9=this.drawingObjects[t2K];if(F0a === o_9.panelName){o_9.panelName=i6Z;H3w=!![];}}if(H3w){this.changeOccurred("vector");}this.calculateYAxisPositions();};c4S.ChartEngine.prototype.setPanelHeight=function(a8W,i_D){var J5R,c4J,Q53,E0l;if(!i_D){return;}if(Object.values(this.panels).slice(-1)[0] === a8W){i_D+=this.xaxisHeight;}var {canvasHeight:R0a}=this.chart;var {percent:U7x}=a8W;g4U.M8Y(40);J5R=g4U.c6Y(R0a,i_D);g4U.C$o(0);c4J=g4U.c6Y(1,U7x);g4U.M8Y(145);Q53=g4U.c6Y(64,J5R,"1");g4U.M8Y(40);E0l=g4U.d58(Q53,c4J);Object.values(this.panels).forEach(d5X=>{var z$L,s0I,w7U;g4U.r2m();g4U.C$o(74);z$L=-g4U.d58("390080432",16);s0I=-522222260;w7U=+"2";for(var W$f=1;g4U.O$R(W$f.toString(),W$f.toString().length,35159) !== z$L;W$f++){d5X.percent%=E0l;w7U+=2;}if(g4U.q2D(w7U.toString(),w7U.toString().length,9733) !== s0I){d5X.percent/=E0l;}});a8W.percent=J5R;this.adjustPanelPositions();this.savePanels();};c4S.ChartEngine.prototype.electNewPanelOwner=function(s2N,B8W){g4U.r2m();var a7U,L4M,U5P,L1V,f$z,L$9,Q$a,x5x,V2Q,u6a,Z48;function e9U(M0n){return M0n.name != L4M.name;}if(typeof s2N == "string"){s2N=this.panels[s2N];}L4M=s2N.yAxis;if(s2N && s2N != this.chart.panel){U5P=s2N.yAxis;L1V=U5P.studies[0];if(!L1V || L1V == L4M.name){L1V=U5P.renderers[0];}if(!L1V || L1V == L4M.name){L1V=U5P.studies[1];}if(!L1V){L1V=U5P.renderers[1];}if(B8W){U5P=s2N.yAxis=B8W;f$z=-2012665674;L$9=-592765991;Q$a=2;for(var T9Z=1;g4U.q2D(T9Z.toString(),T9Z.toString().length,"84711" * 1) !== f$z;T9Z++){a7U=B8W.name;Q$a+=2;}if(g4U.q2D(Q$a.toString(),Q$a.toString().length,21447) !== L$9){a7U=B8W.name;}a7U=B8W.name;}else if(!L1V){if(s2N.yaxisLHS){x5x=s2N.yaxisRHS.concat(s2N.yaxisLHS).filter(e9U);V2Q=x5x[0];for(var F96="0" >> 64;F96 < x5x.length;F96++){if(!x5x[F96].position){V2Q=x5x[F96];break;}}if(V2Q){U5P=s2N.yAxis=V2Q;a7U=V2Q.studies[0] || V2Q.renderers[0];}}}else {U5P=this.addYAxis(s2N,new c4S.ChartEngine.YAxis({name:L1V,position:U5P.position}));U5P.renderers=s2N.yAxis.renderers;U5P.studies=s2N.yAxis.studies;a7U=L1V;}if(a7U){L1V=a7U;if(L4M.name != s2N.name){L1V=s2N.name;}Z48=this.layout.studies;if(Z48 && Z48[a7U]){u6a=Z48[a7U].inputs.display;}this.modifyPanel(s2N,{name:L1V,display:u6a || a7U,yAxis:U5P});this.deleteYAxisIfUnused(s2N,L4M);this.calculateYAxisMargins(this.panels[L1V].yAxis);}else {this.checkForEmptyPanel(s2N);}}return a7U;};c4S.ChartEngine.prototype.configurePanelControls=function(e4M){var u4H,D7_,Y9m,R6C,k2F,H8j,j2s;u4H=".stx-ic";u4H+="o-";u4H+="edit";D7_=".stx";D7_+="-ico-down";Y9m=e4M.icons;if(!Y9m){return;}R6C=e4M.name == e4M.chart.name;Y9m.classList.add("stx-show");e4M.title=Y9m.querySelector(".stx-panel-title");e4M.up=Y9m.querySelector(".stx-ico-up");if(e4M.up){e4M.up=e4M.up.parentNode;}e4M.solo=Y9m.querySelector(".stx-ico-focus");if(e4M.solo){e4M.solo=e4M.solo.parentNode;}e4M.down=Y9m.querySelector(D7_);if(e4M.down){e4M.down=e4M.down.parentNode;}e4M.edit=Y9m.querySelector(u4H);if(e4M.edit){e4M.edit=e4M.edit.parentNode;}e4M.close=Y9m.querySelector(".stx-ico-close");if(e4M.close){e4M.close=e4M.close.parentNode;}if(e4M.title){e4M.title.innerHTML="";if(e4M.display){e4M.title.appendChild(document.createTextNode(e4M.display));}if(R6C){k2F="stx-chart-";k2F+="panel";e4M.title.classList.add("chart-title");Y9m.classList.add(k2F);}}if(!c4S.touchDevice || c4S.isSurface){this.makeModal(Y9m);}if(e4M.handle){if(!c4S.touchDevice || c4S.isSurface){e4M.handle.onmouseover=(function(R9g){return function(){R9g.hideCrosshairs();};})(this);}if(!c4S.touchDevice || c4S.isSurface){e4M.handle.onmouseout=(function(W7c){return function(){g4U.J8h();W7c.showCrosshairs();};})(this);}H8j=function(y_H,A2L){return function(q5R){if(c4S.ChartEngine.resizingPanel || y_H.openDialog !== ""){return;}y_H.grabHandle(A2L);};};if(c4S.isSurface){e4M.handle.onpointerdown=H8j(this,e4M);}else {e4M.handle.onmousedown=H8j(this,e4M);}if(c4S.touchDevice){e4M.handle.ontouchstart=H8j(this,e4M);}}if(e4M.up){c4S.safeClickTouch(e4M.up,(function(d$Y,n4T){g4U.r2m();return function(){g4U.r2m();d$Y.panelUp(n4T);};})(this,e4M));}if(e4M.down){c4S.safeClickTouch(e4M.down,(function(c4h,u3D){g4U.J8h();return function(){g4U.r2m();c4h.panelDown(u3D);};})(this,e4M));}if(e4M.solo){c4S.safeClickTouch(e4M.solo,(function(N7b,L50){g4U.r2m();return function(){g4U.r2m();N7b.panelSolo(L50);};})(this,e4M));}if(e4M.close){if(e4M.name == "chart"){j2s="non";j2s+="e";e4M.close.style.display=j2s;;}else {c4S.safeClickTouch(e4M.close,(function(Y4t,h60){return function(){g4U.J8h();Y4t.panelClose(h60);};})(this,e4M));}}};c4S.ChartEngine.prototype.stackPanel=function(o2M,z_G,L7g,R7_,X2L){var A2v,e9m,J3U,T3x,Y4n,F_D,U_c;A2v="d";A2v+="i";A2v+="v";e9m="d";e9m+="i";e9m+="v";J3U="cha";J3U+="rt";if(this.runPrepend("stackPanel",arguments)){return;}if(!R7_){R7_=J3U;}T3x=this.charts[R7_];g4U.M8Y(106);Y4n=g4U.c6Y(z_G,R7_);if(Y4n){o2M=T3x.symbol;if(T3x.symbolDisplay){o2M=T3x.symbolDisplay;}if(!X2L){X2L=T3x.yAxis;}}F_D=this.panels[z_G]=new c4S.ChartEngine.Panel(z_G,X2L);if(!Y4n && T3x.yAxis && F_D.yAxis.position == T3x.yAxis.position){F_D.yAxis.width=T3x.yAxis.width;;}if(Y4n && !T3x.panel){T3x.panel=F_D;}F_D.percent=L7g;F_D.chart=T3x;F_D.display=o2M;F_D.holder=c4S.newChild(this.container,e9m,"stx-holder");F_D.subholder=c4S.newChild(F_D.holder,A2v,"stx-subholder");F_D.subholder.style.zIndex=1;F_D.holder.panel=F_D;U_c=Y4n?"stx-panel-chart":"stx-panel-study";F_D.holder.classList.add(U_c);if(this.controls.handleTemplate && this.manageTouchAndMouse){F_D.handle=this.controls.handleTemplate.cloneNode(!![]);this.container.appendChild(F_D.handle);F_D.handle.panel=F_D;}if(this.controls.iconsTemplate){F_D.icons=this.controls.iconsTemplate.cloneNode(!![]);F_D.subholder.appendChild(F_D.icons);this.configurePanelControls(F_D);}if(!this.currentlyImporting){this.resizeCanvas();}this.runAppend("stackPanel",arguments);};c4S.ChartEngine.prototype.setPanelEdit=function(p18,x_W){p18.editFunction=x_W;if(p18.edit){c4S.safeClickTouch(p18.edit,x_W);}this.adjustPanelPositions();};c4S.ChartEngine.prototype.drawPanels=function(){var r2E,E0H,h$S,N4M,w63,s7y,b4q,O6J,a0R,u6T,T40,U79;r2E="draw";r2E+="P";r2E+="a";r2E+="nels";g4U.J8h();if(this.runPrepend("drawPanels",arguments)){return;}E0H=!!0;for(var k3E in this.panels){h$S=this.panels[k3E];h$S.state={};N4M=this.translateIf(h$S.display);if(h$S.title && h$S.title.textContent != N4M){h$S.title.innerHTML="";h$S.title.appendChild(document.createTextNode(N4M));}if(h$S.icons){h$S.icons.classList.add("stx-show");}if(h$S.hidden){w63="non";w63+="e";if(h$S.icons){h$S.icons.classList.remove("stx-show");}if(h$S.handle){h$S.handle.style.display="none";}h$S.holder.style.display=w63;continue;}else {if(h$S.name != "chart"){s7y=this.manageTouchAndMouse;if(h$S.up){h$S.up.style.display=this.displayIconsUpDown && s7y?"":"none";}if(h$S.down){h$S.down.style.display=this.displayIconsUpDown && s7y?"":"none";}if(h$S.solo){h$S.solo.style.display=this.displayIconsSolo && s7y?"":"none";}if(h$S.close){h$S.close.style.display=this.displayIconsClose && s7y?"":"none";}if(h$S.edit){h$S.edit.style.display=h$S.editFunction && s7y?"":"none";}}h$S.holder.style.display="block";}if(h$S.displayEdgeIfPadded){b4q="se";b4q+="g";b4q+="ment";O6J=Math.round(h$S.left) + 0.5;a0R=h$S.yAxis.top - 0.5;u6T=h$S.yAxis.bottom + 0.5;if(h$S.yaxisCalculatedPaddingLeft && !h$S.yaxisTotalWidthLeft){this.plotLine(O6J,O6J,a0R,u6T,this.canvasStyle("stx_grid_border"),b4q,this.chart.context,!!0,{lineWidth:1});}g4U.M8Y(58);var Y1R=g4U.d58(3,5,4,16,5);O6J=Math.round(h$S.right) + "0.5" * Y1R;if(h$S.yaxisCalculatedPaddingRight && !h$S.yaxisTotalWidthRight){this.plotLine(O6J,O6J,a0R,u6T,this.canvasStyle("stx_grid_border"),"segment",this.chart.context,!!"",{lineWidth:1});}}if(!E0H){if(h$S.handle){h$S.handle.style.display="none";}E0H=!!({});continue;}T40=h$S.top;T40=Math.round(T40) + 0.5;this.plotLine(h$S.left - 0.5,h$S.right + 0.5,T40,T40,this.canvasStyle("stx_panel_border"),"segment",this.chart.context,!({}),{});if(h$S.handle){if(!this.displayPanelResize){U79="non";U79+="e";h$S.handle.style.display=U79;}else {h$S.handle.style.display="";}g4U.M8Y(81);var C$P=g4U.c6Y(3,19,6,340);h$S.handle.style.top=T40 - h$S.handle.offsetHeight / C$P + "px";;}}this.runAppend(r2E,arguments);};};k4=b0E=>{var V3n;V3n=b0E.CIQ;V3n.ChartEngine.isDailyInterval=function(U1C){var k_y,a8x;k_y="w";x2dci.J8h();k_y+="e";k_y+="e";k_y+="k";a8x="d";a8x+="a";a8x+="y";if(U1C == a8x){return !![];}if(U1C == k_y){return !0;}if(U1C == "month"){return !!"1";}return !({});};V3n.ChartEngine.prototype.setPeriodicity=function(L_r,z_5){var E_N=x2dci;var S2x,G6z,s6C,x43,e$J,M$T,Q5$,w2t,K9b,C9Q,k_E,g8G,a5q,q_O,x36,N3E,G72;S2x="set";S2x+="P";S2x+="e";S2x+="riodicity";if(this.runPrepend(S2x,arguments)){return;}if(typeof arguments[0] !== "object"){L_r={period:arguments[0],interval:arguments[1],timeUnit:arguments[2]};E_N.C$o(97);var o4M=E_N.c6Y(4,10,121,3,1);z_5=arguments[arguments.length - o4M];if(arguments.length === 3){L_r.timeUnit=undefined;}}var {period:H6g, interval:D3w, timeUnit:c5R}=L_r;if(typeof z_5 !== "function"){z_5=null;}({period:H6g, interval:D3w, timeUnit:c5R}=V3n.cleanPeriodicity(H6g,D3w,c5R));var {layout:Q8n}=this;Q8n.setSpan={};Q8n.range={};function R6V(){var f7t;f7t="p";f7t+="eriodi";f7t+="ci";f7t+="ty";x43.dispatch(f7t,e$J);if(z_5){z_5(null);}}this.chart.inflectionPoint=null;G6z=![];if(this.chart.symbol){G6z=this.needDifferentData({period:H6g,interval:D3w,timeUnit:c5R});}var {candleWidth:L$8, periodicity:S_A, interval:X_z, timeUnit:x5j}=Q8n;s6C={prvPeriodicity:S_A,prvInterval:X_z,prvTimeUnit:x5j};Q8n.periodicity=H6g;Q8n.interval=D3w;Q8n.timeUnit=c5R;x43=this;e$J={stx:x43,differentData:G6z,prevPeriodicity:s6C};if(G6z){M$T="la";M$T+="yout";this.changeOccurred(M$T);this.clearCurrentMarketData();if(this.quoteDriver){for(var D5P in this.charts){Q5$=this.charts[D5P];if(Q5$.symbol){if(this.displayInitialized){this.quoteDriver.newChart({symbol:Q5$.symbol,symbolObject:Q5$.symbolObject,chart:Q5$},R6V);}else {this.loadChart(Q5$.symbol,{chart:Q5$},R6V);}}}}else if(this.dataCallback){this.dataCallback();R6V();}else {console.log("cannot change periodicity because neither dataCallback or quoteDriver are set");}this.home();return;}for(var l8q in this.charts){w2t=this.charts[l8q];var {dataSegment:x0E, dataSet:R_i, maxTicks:b91, scroll:z3z}=w2t;K9b=x0E?x0E.length:+"0";C9Q=R_i?R_i.length:"0" * 1;k_E=void +"0";g8G=Math.round(w2t.maxTicks / 2);this.setCandleWidth(L$8,w2t);a5q=!!1;q_O=!"1";if(z3z <= b91){a5q=!({});}else if(x0E && !x0E[g8G]){a5q=!({});E_N.C$o(0);q_O=E_N.d58(z3z,C9Q);;}if(a5q && K9b > 0){if(b91 < (Math.round(this.chart.width / L$8 - +"0.499") - ("1" << 64)) / 2){E_N.C$o(0);g8G=E_N.d58(K9b,1);}if(g8G >= K9b){k_E=x0E[K9b - 1].DT;E_N.C$o(0);g8G=E_N.d58(K9b,1);}else {k_E=x0E[g8G].DT;}}this.createDataSet();if(a5q){if(K9b > 0){for(var M63=C9Q - 1;M63 >= 0;M63--){x36=R_i[M63].DT;if(x36.getTime() < k_E.getTime()){E_N.C$o(111);w2t.scroll=E_N.d58(1,C9Q,g8G,M63);break;}}}}else if(!q_O){N3E=Math.round(this.preferences.whitespace / L$8);E_N.C$o(30);w2t.scroll=E_N.d58(N3E,b91,1);;}else {w2t.scroll=R_i.length + q_O;;}}if(this.displayInitialized){this.draw();}this.changeOccurred("layout");if(this.quoteDriver){for(var Y_9 in this.charts){G72=this.charts[Y_9];if(G72.symbol && (G72.moreAvailable || !G72.upToDate)){this.quoteDriver.checkLoadMore(G72);}}}R6V();this.runAppend("setPeriodicity",arguments);};V3n.ChartEngine.prototype.needDifferentData=function(R9i){var i8v,w4v,O80,X_F,Y1F,T74;i8v="min";i8v+="ute";w4v="minu";w4v+="t";w4v+="e";O80=this.layout;X_F=V3n.ChartEngine.isDailyInterval(R9i.interval);Y1F=V3n.ChartEngine.isDailyInterval(O80.interval);T74=!({});if(this.dontRoll || !Y1F){if(O80.interval != R9i.interval){T74=!!"1";}}else {if(X_F != Y1F){T74=!!({});}}if(!X_F && !R9i.timeUnit){R9i.timeUnit=w4v;}if(!Y1F && !O80.timeUnit){O80.timeUnit=i8v;}if(R9i.timeUnit != O80.timeUnit){T74=!!({});}x2dci.J8h();if(!this.masterData || !this.masterData.length){T74=!"";}return T74;};V3n.ChartEngine.prototype.getPeriodicity=function(){var l$n,s1b,H2Z;l$n=this.layout;s1b=l$n.interval;x2dci.r2m();H2Z=l$n.timeUnit;if(!H2Z){H2Z=s1b;s1b=1;}return {period:l$n.periodicity,interval:s1b,timeUnit:H2Z};};};C1=q_S=>{var V2m=x2dci;var X85;X85=q_S.CIQ;X85.ChartEngine.prototype.isHistoricalMode=function(){var H2d,C7N,l1G,r88,V2s,m7B,M06;H2d=new Date();C7N=!![];l1G=this.masterData;if(!this.isHistoricalModeSet){return !!0;}if(l1G.length){r88="D";r88+="T";V2s=this.getFirstLastDataRecord(l1G,r88,!"");m7B=this.standardMarketIterator(V2s.DT);C7N=(m7B?m7B.next():V2s.DT) <= H2d;if(C7N && X85.ChartEngine.isDailyInterval(m7B.interval)){M06=this.chart.market.getOpen();if(M06 && H2d < M06){V2m.M8Y(19);H2d.setHours(0,V2m.d58(0,"0"),0,0);if(+H2d == +m7B.begin){C7N=![];}}}}return C7N;};V2m.r2m();X85.ChartEngine.prototype.isHome=function(){var O7U,r0G,j4a;O7U=this.chart;r0G=O7U.dataSet;j4a=O7U.animatingHorizontalScroll;V2m.M8Y(0);V2m.r2m();var w40=V2m.c6Y(12,10);V2m.C$o(36);var g10=V2m.d58(31,11,47,517);return this.pixelFromTick(r0G.length - (j4a?w40:"1" >> g10),O7U) < O7U.width + O7U.panel.left;;};X85.ChartEngine.prototype.getPreviousBar=function(Y2C,T4t,g02){return this.getNextBarInternal(Y2C,T4t,g02,-+"1");};X85.ChartEngine.prototype.getNextBar=function(P$U,U1a,b_R){return this.getNextBarInternal(P$U,U1a,b_R,1);};X85.ChartEngine.prototype.getNextBarInternal=function(k45,R3c,Y16,E1w){var g4T,U_u,g3h,z5L;g4T=k45.dataSegment && k45.dataSegment[Y16];if(g4T){U_u=g4T.tick;while(U_u > 0 && U_u < k45.dataSet.length){V2m.M8Y(22);U_u=V2m.c6Y(E1w,U_u);g3h=k45.dataSet[U_u];if(g3h){z5L=X85.existsInObjectChain(g3h,R3c);if(z5L && z5L.obj[z5L.member]){return g3h;}}}}return null;};X85.ChartEngine.prototype.getFirstLastDataRecord=function(d8c,U8d,w7d){var p7r;if(d8c && d8c.length){p7r=w7d?d8c.length - 1:0;while(p7r >= 0 && p7r < d8c.length){if(d8c[p7r] && typeof d8c[p7r][U8d] != "undefined"){return d8c[p7r];}if(w7d){p7r--;}else {p7r++;}}}return null;};X85.ChartEngine.prototype.leftTick=function(){return this.chart.dataSet.length - this.chart.scroll;};X85.ChartEngine.prototype.getNextInterval=function(v_s,k8f,C9S){var O2N;if(!k8f){k8f=1;}if(C9S !== !({})){C9S=!0;}O2N=this.standardMarketIterator(v_s,C9S?this.dataZone:this.displayZone);if(!O2N){return v_s;}if(k8f < +"1"){V2m.C$o(146);return O2N.previous(V2m.d58(k8f,1));}return O2N.next(k8f);};X85.ChartEngine.prototype.standardMarketIterator=function(a4o,n8O,U8U){var y5w,o_E;y5w=U8U || this.chart;if(!y5w.market){return null;}o_E={begin:a4o,interval:this.layout.interval,periodicity:this.layout.interval == "tick"?this.chart.xAxis.futureTicksInterval:this.layout.periodicity,timeUnit:this.layout.timeUnit,outZone:n8O};return y5w.market.newIterator(o_E);};};t_=Q8V=>{var H4T=x2dci;var v21,J59;if(!Q8V.SplinePlotter){Q8V.SplinePlotter={};}v21=Q8V.CIQ;J59=Q8V.SplinePlotter;v21.ChartEngine.prototype.draw=function(){var v4O,J_6,l_b,y$_,G1a,I6g,w9M,A91,M0E,J02,t4y,r25,h$k,B9X;v4O="dr";v4O+="a";v4O+="w";J_6="n";J_6+="o";J_6+="n";J_6+="e";this.debug();l_b=this.chart;y$_=this.layout;if(!l_b.canvas){return;}if(!l_b.dataSet){return;}if(!l_b.canvasHeight){return;}H4T.M8Y(85);var u_I=H4T.c6Y(0,15,13,7,7);this.offset=y$_.candleWidth * this.candleWidthPercent / u_I;v21.clearCanvas(l_b.canvas,this);if(!this.masterData){return;}if(this.runPrepend("draw",arguments)){return;}if(!this.defaultColor){this.getDefaultColor();}this.vectorsShowing=![];this.drawPanels();this.yAxisLabels=[];this.correctIfOffEdge();this.createDataSegment();this.setBaselines(l_b);w9M=this.createXAxis(l_b);this.initializeDisplay(l_b);this.drawXAxis(l_b,w9M);try{this.renderYAxis(l_b);}catch(k8a){var L86;L86="reboo";L86+="t draw";if(k8a && k8a.message === L86){return this.draw();}throw k8a;}l_b.tmpWidth=Math.floor(y$_.candleWidth * this.candleWidthPercent);if(l_b.tmpWidth % 2 === "0" * 1){l_b.tmpWidth+=1;if(l_b.tmpWidth > y$_.candleWidth){H4T.M8Y(74);l_b.tmpWidth-=H4T.c6Y("2",2);}}H4T.r2m();if(l_b.tmpWidth < 0.5){l_b.tmpWidth=0.5;}for(G1a in this.plugins){I6g=this.plugins[G1a];if(I6g.display){if(I6g.drawUnder){I6g.drawUnder(this,l_b);}}}if(l_b.legend){l_b.legend.colorMap=null;}if(this.controls.baselineHandle){this.controls.baselineHandle.style.display=J_6;}this.rendererAction(l_b,"underlay");v21.getFn("Studies.displayStudies")(this,l_b,!!"1");this.displayChart(l_b);v21.getFn("Studies.displayStudies")(this,l_b,!({}));this.rendererAction(l_b,"overlay");if(l_b.legend && l_b.legend.colorMap && l_b.legendRenderer){A91=-914919967;M0E=761783298;H4T.C$o(74);J02=H4T.d58("2",2);for(var Q9G=1;H4T.O$R(Q9G.toString(),Q9G.toString().length,"98158" << 0) !== A91;Q9G++){l_b.legendRenderer(this,{chart:l_b,legendColorMap:l_b.legend.colorMap,coordinates:{x:l_b.legend.x,y:l_b.legend.y % l_b.panel.yAxis.top}});J02+=2;}if(H4T.q2D(J02.toString(),J02.toString().length,"41546" | 66) !== M0E){l_b.legendRenderer(this,{chart:l_b,legendColorMap:l_b.legend.colorMap,coordinates:{x:l_b.legend.x,y:l_b.legend.y + l_b.panel.yAxis.top}});}}for(G1a in this.plugins){I6g=this.plugins[G1a];if(I6g.display){if(I6g.drawOver){I6g.drawOver(this,l_b);}}}for(var L92 in this.panels){if(!this.panels[L92].hidden){this.plotYAxisText(this.panels[L92]);}}for(var N2V=0;N2V < this.yAxisLabels.length;N2V++){t4y=this.yAxisLabels[N2V];if(t4y.src == "series" && t4y.args[6] && t4y.args[6].drawSeriesPriceLabels === !1)continue;this.createYAxisLabel.apply(this,t4y.args);}if(this.createCrosshairs){this.createCrosshairs();}if(this.drawVectors){this.drawVectors();}this.drawCurrentHR();this.displayInitialized=!!({});r25=this.controls;if(r25){h$k="n";h$k+="one";B9X=this.manageTouchAndMouse && (!this.mainSeriesRenderer || !this.mainSeriesRenderer.nonInteractive);if(r25.home){r25.home.style.display=B9X && !this.isHome()?"block":"none";}if(r25.chartControls){r25.chartControls.style.display=B9X?"block":h$k;}}if(v21.Marker){this.positionMarkers();}if(this.quoteDriver && this.animations.zoom.hasCompleted){this.quoteDriver.checkLoadMore(l_b);}this.runAppend(v4O,arguments);this.makeAsyncCallbacks();};v21.ChartEngine.prototype.setSeriesRenderer=function(f9r){var {baseline:e2o, name:V8T, panel:d6b, yAxis:x$c}=f9r.params;if(this.chart.seriesRenderers[V8T]){return this.chart.seriesRenderers[V8T];;}if(x$c){f9r.params.yAxis=this.addYAxis(this.panels[d6b],x$c);this.resizeChart();}H4T.r2m();f9r.stx=this;this.chart.seriesRenderers[V8T]=f9r;if(e2o){this.registerBaselineToHelper(f9r);}return f9r;};v21.ChartEngine.prototype.setMainSeriesRenderer=function(T2N){var F7Y,u$6,O8U,J9h,I0C,T_V;F7Y="sta";F7Y+="nda";F7Y+="loneBars";u$6="highLow";u$6+="Bars";O8U="o";O8U+="hl";O8U+="c";var {chartType:C7o, aggregationType:W_f}=this.layout;var {chart:R8Y}=this;var {custom:G08}=R8Y;J9h=this.mainSeriesRenderer;I0C=this.displayInitialized;if(J9h){if(T2N){this.setMasterData();}this.displayInitialized=!({});J9h.removeAllSeries();this.removeSeriesRenderer(J9h);J9h=this.mainSeriesRenderer=null;}if(G08 && G08.chartType){C7o=G08.chartType;}if(C7o == "none"){return;}if(W_f && W_f != O8U){C7o=W_f;}T_V=v21.Renderer.produce(C7o,{panel:R8Y.panel.name,name:"_main_series",highlightable:!1,useChartLegend:!![]});if(T_V){this.setSeriesRenderer(T_V).attachSeries(null,{display:R8Y.symbol});J9h=this.mainSeriesRenderer=T_V;}this.displayInitialized=I0C;[u$6,F7Y,"barsHaveWidth"].forEach((function(e98){H4T.r2m();R8Y[e98]=this.mainSeriesRenderer && this.mainSeriesRenderer[e98];}).bind(this));};v21.ChartEngine.prototype.removeSeriesRenderer=function(D6A){var u9t;H4T.J8h();var {baseline:E0M, name:T_o}=D6A.params;u9t=this.controls[`${T_o} baseline-handle`];if(E0M){this.removeBaselineFromHelper(D6A);if(u9t){this.container.removeChild(u9t);delete this.controls[u9t];}}delete this.chart.seriesRenderers[T_o];};v21.ChartEngine.prototype.getSeriesRenderer=function(M_U){return this.chart.seriesRenderers[M_U];};v21.ChartEngine.prototype.getRendererFromSeries=function(w7D){var F2a;F2a=this.chart.seriesRenderers;H4T.J8h();for(var i_z in F2a){for(var U2j in F2a[i_z].seriesParams){if(F2a[i_z].seriesParams[U2j].id == w7D){return F2a[i_z];}}}return null;};v21.ChartEngine.prototype.startClip=function(c8m,q6C){var t1v,z4V,D_K,V27,t1I;if(!c8m){c8m=this.chart.panel.name;}t1v=this.panels[c8m];z4V=t1v.yAxis;D_K=this.chart;D_K.context.save();D_K.context.beginPath();V27=t1v.left;t1I=t1v.width;if(q6C){V27=0;t1I=this.width;}else if(t1v.yaxisLHS && t1v.yaxisLHS.length){V27++;t1I--;}D_K.context.rect(V27,z4V.top,t1I,z4V.height);D_K.context.clip();};v21.ChartEngine.prototype.endClip=function(){H4T.r2m();this.chart.context.restore();};v21.ChartEngine.prototype.setLineStyle=function(b4Y,o3c){var Q3S,a$R;Q3S={};if(b4Y && typeof b4Y == "object"){Q3S=b4Y;}else {Q3S.color=b4Y;}if(!Q3S.color && !Q3S.pattern && !Q3S.width && !Q3S.baseColor){Q3S=null;}if(!o3c){o3c=this.chart;}a$R=1;if(Q3S && Q3S.width){a$R=Q3S.width;}if(Q3S && Q3S.pattern){Q3S.pattern=v21.borderPatternToArray(a$R,Q3S.pattern);}o3c.lineStyle=Q3S;};v21.ChartEngine.prototype.setGapLines=function(s0A,P1G){var b22;if(!P1G){P1G=this.chart;}b22={};if(s0A && typeof s0A == "object"){b22=s0A;}else if(typeof s0A === "boolean"){return P1G.gaplines=s0A;}else {b22.color=s0A;}if(!b22.color && !b22.pattern && !b22.fillMountain){b22=null;}if(b22 && b22.pattern){b22.pattern=v21.borderPatternToArray(b22.width,b22.pattern);}if(b22 && b22.width <= 0){b22.width=null;}P1G.gaplines=b22;};v21.ChartEngine.prototype.getGapColorFunction=function(T0V,b6D,x85,U$7,L8C){if(typeof x85 != "object"){x85={color:x85};}return function(o8B,u_O,R$k){var B$b,u_l;B$b=L8C?L8C(o8B,u_O,R$k):x85;if(B$b.color){B$b=B$b.color;}H4T.r2m();u_l=u_O[T0V];if(!u_l && u_l !== 0){u_l=u_O[b6D];}if(!R$k && (u_l || u_l === 0)){return {color:B$b,pattern:x85.pattern,width:x85.width};}if(!U$7){return null;}if(typeof U$7 != "object"){if(typeof U$7 == "string"){U$7={color:U$7};}else {U$7={};}}return {color:U$7.color || B$b,pattern:U$7.pattern || x85.pattern,width:U$7.width || x85.width};};};v21.ChartEngine.prototype.drawLineChart=function(Z15,W36,y9q,c2m){var e9q,W9C,S$t,i9O,j03,s84,T2W,U0c,D$i,s3p,a06,r8W,J8A;e9q="C";H4T.r2m();e9q+="lo";e9q+="se";W9C=this.chart;S$t=W9C.context;i9O=W9C.lineStyle || ({});j03=this.canvasStyle(W36);if(!c2m){c2m={};}this.startClip(Z15.name);s84=c2m.width || i9O.width || j03.width;if(s84 && parseInt(s84,10) <= 25){S$t.lineWidth=Math.max(1,v21.stripPX(s84));}else {S$t.lineWidth=+"1";}c2m.pattern=c2m.pattern || i9O.pattern || j03.borderTopStyle;c2m.pattern=v21.borderPatternToArray(S$t.lineWidth,c2m.pattern);this.canvasColor(W36);T2W=c2m.color || i9O.color;if(T2W){U0c="a";U0c+="u";U0c+="to";if(T2W == U0c){T2W=this.defaultColor;}if(c2m.opacity && c2m.opacity !== 1){T2W=v21.hexToRgba(v21.colorToHex(T2W),parseFloat(c2m.opacity));}S$t.strokeStyle=T2W;}c2m.skipProjections=!"";D$i=c2m.field || W9C.defaultPlotField;s3p=c2m.subField || W9C.defaultPlotField || e9q;a06=c2m.gapDisplayStyle;if(!a06 && a06 !== !!""){a06=c2m.gaps;}if(!a06 && a06 !== ![]){a06=W9C.gaplines;}if(!a06){a06="transparent";}c2m.gapDisplayStyle=a06;r8W=this.getGapColorFunction(D$i,s3p,{color:S$t.strokeStyle,pattern:c2m.pattern,width:S$t.lineWidth},a06,y9q);if(Z15.chart.tension){c2m.tension=Z15.chart.tension;}J8A=this.plotDataSegmentAsLine(D$i,Z15,c2m,r8W);if(!J8A.colors.length){J8A.colors.push(S$t.strokeStyle);}S$t.lineWidth=1;this.endClip();return c2m.returnObject?J8A:J8A.colors;};v21.ChartEngine.prototype.drawChannelChart=function(J$F,A88,i_3){var t3l,X$M,i4W,j0M,N8N,B0e,v2_,q8$,u1z,X5f,g84,H47;t3l="subFi";t3l+="eld";X$M="H";X$M+="igh";i4W=v21.clone(i_3);i4W.color=i_3.color;j0M=this.drawLineChart(J$F,i4W.style,A88,i4W);N8N=i4W.border_color_up || this.getCanvasColor("stx_channel_up");B0e=i4W.border_color_down || this.getCanvasColor("stx_channel_down");i4W[i_3.field?"subField":"field"]=i4W.field_high || X$M;i4W.color=N8N;v2_=this.drawLineChart(J$F,i4W.style,A88,i4W);i4W[i_3.field?t3l:"field"]=i4W.field_low || "Low";i4W.color=B0e;q8$=this.drawLineChart(J$F,i4W.style,A88,i4W);i4W[i_3.field?"subField":"field"]=i_3.subField || this.chart.defaultPlotField || "Close";X5f=[];g84=[];for(u1z=0;u1z < v2_.points.length;u1z+=2){X5f.push([v2_.points[u1z],v2_.points[u1z + 1]]);}for(u1z=0;u1z < q8$.points.length;u1z+=2){g84.push([q8$.points[u1z],q8$.points[u1z + +"1"]]);}H47=this.chart.context.lineWidth / +"2";for(u1z=j0M.points.length - 2;u1z >= 0;u1z-=2){X5f.push([j0M.points[u1z],j0M.points[u1z + 1] - H47]);g84.push([j0M.points[u1z],j0M.points[u1z + 1] + H47]);}this.startClip(J$F.name);i4W.color=N8N;v21.fillArea(this,X5f,i4W);i4W.color=B0e;v21.fillArea(this,g84,i4W);this.endClip();j0M.colors=j0M.colors.concat(v2_.colors).concat(q8$.colors);H4T.J8h();return i_3.returnObject?j0M:j0M.colors;};v21.ChartEngine.prototype.connectTheDots=function(e0E,A1J,A$D,P4s,u0Z,d8E){var d63,B4I,Q9E,S7F,A$0,w2Z,t0y,P_J,U6f,H5$,W$X,x6G,Z_k,P83,O4Q,r6b,S08,x5V,W92,G6I;H4T.J8h();if(!d8E){d8E={};}if(d8E.pattern == "none"){return;}if(u0Z === !""){u0Z=this.chart.panel;}if(P4s === null || typeof P4s == "undefined"){P4s=this.chart.context;}if(e0E.length < 4){return;}d63=0;B4I=this.chart.canvasHeight;Q9E=0;S7F=this.chart.width;if(u0Z){B4I=u0Z.yAxis.bottom;d63=u0Z.yAxis.top;}P4s.lineWidth=+"1.1";if(typeof A1J == "object"){P4s.strokeStyle=A1J.color;if(A1J.opacity){P4s.globalAlpha=A1J.opacity;}else {P4s.globalAlpha=1;}P4s.lineWidth=v21.stripPX(A1J.width);}else {if(!A1J || A1J == "auto" || v21.isTransparent(A1J)){P4s.strokeStyle=this.defaultColor;}else {P4s.strokeStyle=A1J;}}if(d8E.opacity){P4s.globalAlpha=d8E.opacity;}if(d8E.lineWidth){P4s.lineWidth=d8E.lineWidth;}A$0=v21.borderPatternToArray(P4s.lineWidth,d8E.pattern);P4s.beginPath();for(var D0Q=0;D0Q < e0E.length - 2;D0Q+=2){w2Z=e0E[D0Q];H4T.M8Y(22);t0y=e0E[H4T.c6Y(1,D0Q)];H4T.C$o(22);P_J=e0E[H4T.d58(2,D0Q)];H4T.M8Y(22);U6f=e0E[H4T.d58(3,D0Q)];if(isNaN(w2Z) || isNaN(P_J) || isNaN(t0y) || isNaN(U6f)){return;}H5$=0.0;W$X=1.0;H4T.M8Y(0);x6G=H4T.c6Y(P_J,w2Z);H4T.M8Y(0);Z_k=H4T.d58(U6f,t0y);for(var p9c=0;p9c < +"4";p9c++){if(p9c === +"0"){P83=-x6G;H4T.M8Y(0);O4Q=-H4T.d58(Q9E,w2Z);}if(p9c == 1){P83=x6G;H4T.C$o(0);O4Q=H4T.c6Y(S7F,w2Z);}if(p9c == 2){P83=-Z_k;H4T.C$o(0);O4Q=-H4T.d58(d63,t0y);}if(p9c == ("3" ^ 0)){P83=Z_k;H4T.M8Y(0);O4Q=H4T.d58(B4I,t0y);}H4T.C$o(40);r6b=H4T.d58(P83,O4Q);if((U6f || U6f === 0) && P83 === 0 && O4Q < 0){return ![];;}if(P83 < 0){if(r6b > W$X){return ![];}else if(r6b > H5$){H5$=r6b;};}else if(P83 > 0){if(r6b < H5$){return !!0;}else if(r6b < W$X){W$X=r6b;};}}H4T.M8Y(147);S08=H4T.c6Y(w2Z,H5$,x6G);H4T.C$o(147);x5V=H4T.c6Y(t0y,H5$,Z_k);H4T.C$o(147);W92=H4T.c6Y(w2Z,W$X,x6G);H4T.M8Y(147);G6I=H4T.c6Y(t0y,W$X,Z_k);try{P4s.setLineDash(A$0 && A$0.length?A$0:[]);P4s.moveTo(S08,x5V);P4s.lineTo(W92,G6I);}catch(s0v){;}}P4s.stroke();P4s.closePath();P4s.globalAlpha=1;P4s.lineWidth=1;};v21.ChartEngine.prototype.plotSpline=function(A7T,L36,w2c,V3V,X8N,P2N,y$a){var b8h,T5W;if(!y$a){y$a={};}if(y$a.pattern == "none"){return;}if(P2N === !0){P2N=this.chart.panel;}if(X8N === null || typeof X8N == "undefined"){X8N=this.chart.context;}X8N.save();H4T.J8h();X8N.lineWidth=1.1;if(typeof w2c == "object"){X8N.strokeStyle=w2c.color;if(w2c.opacity){X8N.globalAlpha=w2c.opacity;}else {X8N.globalAlpha=1;}X8N.lineWidth=v21.stripPX(w2c.width);}else {b8h="a";b8h+="uto";if(!w2c || w2c == b8h || v21.isTransparent(w2c)){X8N.strokeStyle=this.defaultColor;}else {X8N.strokeStyle=w2c;}}if(y$a.opacity){X8N.globalAlpha=y$a.opacity;}if(y$a.lineWidth){X8N.lineWidth=y$a.lineWidth;}T5W=v21.borderPatternToArray(X8N.lineWidth,y$a.pattern);if(y$a.pattern && X8N.setLineDash){X8N.setLineDash(T5W);X8N.lineDashOffset=0;;}X8N.beginPath();J59.plotSpline(A7T,L36,X8N);X8N.stroke();X8N.closePath();X8N.restore();};v21.ChartEngine.prototype.rawWatermark=function(M8u,s28,U0t,G6w){this.canvasFont("stx_watermark",M8u);M8u.fillStyle=this.defaultColor;M8u.globalAlpha=0.5;this.chart.context.textBaseline="alphabetic";M8u.fillText(G6w,s28,U0t);M8u.globalAlpha=1;};H4T.r2m();v21.ChartEngine.prototype.watermark=function(a$7,R5k){var P0w,x5i,v8o,q6p,M5X,T75,r_3,f_p,k6L,u4$,b5o,q_G;P0w="ri";P0w+="g";P0w+="ht";x5i="m";x5i+="iddle";v8o="to";H4T.r2m();v8o+="p";q6p="bo";q6p+="ttom";M5X="obj";M5X+="e";M5X+="c";M5X+="t";if(R5k && typeof R5k != M5X){R5k={h:arguments[1],v:arguments[+"2"],text:arguments[3]};}R5k={h:R5k.h || "left",v:R5k.v || q6p,text:R5k.text || "",hOffset:R5k.hOffset === 0?0:R5k.hOffset || 10,vOffset:R5k.vOffset === 0?0:R5k.vOffset || 20,context:R5k.context || this.chart.context};T75=R5k.context;if(!T75){return;}r_3=this.panels[a$7];if(!r_3 || r_3.hidden){return;}f_p=r_3.yAxis.bottom - R5k.vOffset;if(R5k.v == v8o){f_p=r_3.top + R5k.vOffset;}else if(R5k.v == x5i){H4T.M8Y(2);var s9o=H4T.c6Y(17,15);f_p=(r_3.top + r_3.yAxis.bottom) / s9o;}T75.save();this.canvasFont("stx_watermark",T75);this.canvasColor("stx_watermark",T75);T75.textBaseline="alphabetic";k6L=r_3.left + R5k.hOffset;if(R5k.h == P0w){k6L=r_3.right - R5k.hOffset;}else if(R5k.h == "center"){H4T.C$o(25);var B3O=H4T.d58(8,8,2);k6L=(r_3.right + r_3.left - T75.measureText(R5k.text).width) / B3O;}T75.globalAlpha=+"0.5";if(this.highlightedDraggable){H4T.C$o(38);T75.globalAlpha*=H4T.c6Y("0.3",1);}u4$=1137626162;b5o=+"255910138";q_G=2;for(var o29=1;H4T.O$R(o29.toString(),o29.toString().length,46519) !== u4$;o29++){T75.fillText(R5k.text,k6L,f_p);T75.restore();q_G+=+"2";}if(H4T.O$R(q_G.toString(),q_G.toString().length,5622) !== b5o){T75.fillText(R5k.text,k6L,f_p);T75.restore();}};v21.ChartEngine.prototype.displayErrorAsWatermark=function(L$P,Z2N){var E06,P5i,m8y,u8G,n6w,A7a,c3A,E7K,Z9k,B6W,A3P,E0I;E06="c";E06+="hart";if(!Z2N){return;}if(!L$P){L$P=E06;}P5i=this.panels[L$P];if(!P5i || P5i.hidden){return;}m8y=P5i.state;if(!m8y){P5i.state=m8y={};}u8G=m8y.studyErrors;if(!u8G){m8y.studyErrors=u8G=new Set();}if(u8G.has(Z2N)){return;}n6w=m8y.watermarkOffset || 10;A7a=+"10";c3A=this.getCanvasFontSize("stx_watermark");if(this.chart && this.chart.chartControls){E7K=P5i.yAxis.bottom;Z9k=this.chart.chartControls;H4T.M8Y(0);B6W=H4T.d58(E7K,n6w);H4T.M8Y(0);A3P=H4T.c6Y(B6W,c3A);if(B6W > Z9k.offsetTop && B6W < Z9k.offsetTop + Z9k.offsetHeight || A3P > Z9k.offsetTop && A3P < Z9k.offsetTop + Z9k.offsetHeight){n6w=E7K - Z9k.offsetTop + A7a;}}u8G.add(Z2N);E0I={h:"center",v:"bottom",text:Z2N,vOffset:n6w};H4T.M8Y(22);n6w+=H4T.d58(A7a,c3A);m8y.watermarkOffset=n6w;this.watermark(L$P,E0I);};v21.ChartEngine.prototype.displayChart=function(n9k){if(this.runPrepend("displayChart",arguments)){return;}this.rendererAction(n9k,"main");this.runAppend("displayChart",arguments);};};b$=x21=>{var y$5=x2dci;y$5.r2m();var c_h;c_h=x21.CIQ;c_h.ChartEngine.prototype.cloneStyle=function(X99){var y50,J4U,B$L,g8o,j9Z,Q_r,h8K,f6E;y50={};function B0c(e0Z){return e0Z[1].toUpperCase();}J4U=!1;for(var K$d in X99){B$L=X99[K$d];if(K$d == "backgroundAttachment"){J4U=!0;}if(J4U){if(B$L && B$L.constructor == String && isNaN(K$d)){y50[K$d]=B$L;}}else if(!isNaN(K$d)){g8o=X99.getPropertyValue(B$L);if(g8o){B$L=B$L.split(9782 == ("615.87" * 1,5740)?5017 == "128" * 1?227.77:1420 > 344.34?(!![],0x7a):("l",0x249e):"-");j9Z=0;Q_r=B$L.length;h8K=B$L[0];while(++j9Z < Q_r){h8K+=B$L[j9Z].charAt(0).toUpperCase() + B$L[j9Z].slice(+"1");}y50[h8K]=g8o;}}else {f6E=K$d.replace(c_h.camelCaseRegExp,B0c);y50[f6E]=B$L;}}return y50;};c_h.ChartEngine.prototype.canvasStyle=function(A3W){var r1L,y0u,z3c;y$5.J8h();r1L=this.styles[A3W];if(!r1L){y0u=document.createElement("div");y0u.className=A3W;this.container.appendChild(y0u);z3c=getComputedStyle(y0u);r1L=this.styles[A3W]=this.cloneStyle(z3c);this.container.removeChild(y0u);if(!z3c){this.styles[A3W]=null;}}return r1L;};c_h.ChartEngine.prototype.colorOrStyle=function(W7V){if(W7V.indexOf(("7160" ^ 0) != (3900,+"1006")?"#":18.45 !== (199.03,+"1770")?+"163.98" === (3230,763.82)?!![]:(374.20,+"0x4f2"):("6.56e+3" | 0,"c")) != -1){return W7V;}y$5.r2m();if(W7V.indexOf("(") != -1){return W7V;}if(W7V == "transparent"){return W7V;}return this.canvasStyle(W7V);};c_h.ChartEngine.prototype.clearStyles=function(){this.styles={};this.defaultColor="";};c_h.ChartEngine.prototype.setStyle=function(P_Z,l$x,w96){if(!this.styles[P_Z]){this.canvasStyle(P_Z);}if(!this.styles[P_Z]){this.styles[P_Z]={};}y$5.J8h();this.styles[P_Z][c_h.makeCamelCase(l$x)]=w96;};c_h.ChartEngine.prototype.canvasFont=function(R_7,t_3){var s7R,B6b,B6f,S9D;s7R="und";s7R+="e";s7R+="fine";s7R+="d";if(!t_3){t_3=this.chart.context;}B6b=this.canvasStyle(R_7);if(!B6b){return;}y$5.M8Y(124);var F1X=y$5.d58(2446,20,10,17);y$5.C$o(76);var v2K=y$5.d58(1961,2,966,7);y$5.J8h();y$5.M8Y(148);var Q$F=y$5.c6Y(3,1,6075,12142,3);y$5.M8Y(77);var o53=y$5.d58(178169,19,9,20360);y$5.M8Y(0);var r6X=y$5.d58(2552,12);y$5.M8Y(0);var u_Z=y$5.c6Y(3028,8);y$5.M8Y(8);var F3o=y$5.d58(11,10,1);B6f=B6b.fontStyle + (497.5 < 544.17?" ":(293.58,![])) + B6b.fontWeight + " " + B6b.fontSize + (("586.2" - 0,F1X) >= (v2K,Q$F)?o53 <= (r6X,u_Z)?("688.76" * F3o,516.59):475.96:" ") + B6b.fontFamily;if(B6f.indexOf(s7R) == -1){t_3.font=B6f;}else {S9D="bad css style for clas";S9D+="s ";this.styles[R_7]=null;y$5.M8Y(22);console.log(y$5.c6Y(R_7,S9D));}};c_h.ChartEngine.prototype.canvasColor=function(x3b,K8a){y$5.J8h();var t1s,a2h,m6n;if(!K8a){K8a=this.chart.context;}t1s=this.canvasStyle(x3b);if(!t1s){return;}a2h=t1s.color;if(!a2h){a2h=this.defaultColor;}K8a.globalAlpha=+"1";K8a.fillStyle=a2h;K8a.strokeStyle=a2h;m6n=t1s.opacity;if(typeof m6n != "undefined"){K8a.globalAlpha=m6n;}};c_h.ChartEngine.prototype.getCanvasFontSize=function(Z6c){var P06,r0x;P06=this.canvasStyle(Z6c);r0x=P06.fontSize;if(!r0x){r0x="12";}return parseInt(c_h.stripPX(r0x),10);};c_h.ChartEngine.prototype.getCanvasColor=function(X1w){var a7O;y$5.J8h();a7O=this.canvasStyle(X1w);return a7O.color;};c_h.ChartEngine.prototype.getDefaultColor=function(){var i3t,S37,p7Y,o0Z,Z$R,v5B,M1N,f5s;y$5.J8h();this.defaultColor="#000000";i3t=null;S37=this.chart.container;while(!i3t || c_h.isTransparent(i3t)){p7Y=getComputedStyle(S37);if(!p7Y){return;}i3t=p7Y.backgroundColor;if(c_h.isTransparent(i3t)){i3t="transparent";}S37=S37.parentNode;if(!S37 || !S37.tagName)break;}if(i3t){o0Z="#";o0Z+="FF";o0Z+="FFFF";Z$R="tr";Z$R+="anspar";Z$R+="ent";if(i3t == Z$R){i3t=o0Z;}this.containerColor=i3t;if(!c_h.isTransparent(i3t)){v5B=c_h.hsv(i3t);M1N=v5B[2];if(M1N > 0.65){this.defaultColor="#000000";}else {this.defaultColor="#FFFFFF";}}else {this.defaultColor="#000000";}}else {f5s="#FF";f5s+="FFFF";this.containerColor=f5s;}};};l5=p83=>{var x7$;x7$=p83.CIQ;x7$.ChartEngine.XAxis=function(q_v){for(var h8o in q_v){this[h8o]=q_v[h8o];}};x7$.extend(x7$.ChartEngine.XAxis.prototype,{formatter:null,adjustTimeZone:!!({}),idealTickSizePixels:null,timeUnit:null,timeUnitMultiplier:null,displayBorder:!![],displayGridLines:!!1,noDraw:null,minimumLabelWidth:50,futureTicks:!![],futureTicksInterval:1},!!({}));x7$.ChartEngine.XAxisLabel=function(o3n,h_7,q2n){this.hz=o3n;x2dci.J8h();this.grid=h_7;this.text=q2n;};x7$.ChartEngine.prototype.createXAxis=function(U6W){var P8v,a9k,d$6;P8v="crea";P8v+="teX";P8v+="Axis";if(U6W.dataSegment.length <= 0){return null;}if(U6W.xAxis.noDraw){return null;}a9k=[U6W];x2dci.J8h();d$6=this.runPrepend("createXAxis",a9k);if(d$6){return d$6;}if(this.mainSeriesRenderer && this.mainSeriesRenderer.createXAxis){d$6=this.mainSeriesRenderer.createXAxis(U6W);}else {d$6=this.createTickXAxisWithDates(U6W);}this.headsUpHR();this.runAppend(P8v,a9k);return d$6;};x7$.ChartEngine.prototype.createXAxisLabel=function(z27){var S2q=x2dci;var E0R,U6S,T1Y,Q_I,I$x,S3p,I0I,L0a,R87,b6U,Y7x,q2L,V9f,z19;if(arguments[0] instanceof x7$.ChartEngine.Panel){z27={panel:arguments["0" - 0],txt:arguments[1],x:arguments[2],backgroundColor:arguments[+"3"],color:arguments[4],pointed:arguments[5],padding:arguments[6]};}E0R=z27.panel;U6S=z27.txt;S2q.r2m();T1Y=z27.x;Q_I=z27.backgroundColor;I$x=z27.color;S3p=z27.pointed;I0I=z27.padding === 0?"0" >> 64:z27.padding || 2;L0a=this.chart.context;R87="stx-float-date";S2q.C$o(25);var X1X=S2q.d58(21,23,4);b6U=this.getCanvasFontSize(R87) + I0I * X1X;this.canvasFont(R87,L0a);try{Y7x=L0a.measureText(U6S).width + I0I * ("2" - 0);}catch(W2w){Y7x=0;}q2L=E0R.top + E0R.height - b6U - I0I;if(T1Y + Y7x / 2 < E0R.left || T1Y - Y7x / 2 > E0R.right){return;}if(!S3p){if(T1Y + Y7x / ("2" >> 32) > E0R.right){S2q.M8Y(44);var g_K=S2q.d58(20,0,3,20);T1Y=E0R.right - Y7x / g_K;}if(T1Y - Y7x / 2 < E0R.left){S2q.C$o(136);var Y_x=S2q.d58(1,8,78,10);T1Y=E0R.left + Y7x / Y_x;}}L0a.fillStyle=Q_I;x7$.roundRect({ctx:L0a,x:T1Y - Y7x / +"2",top:q2L,width:Y7x,height:b6U,radius:3,fill:!0});V9f=E0R.bottom - E0R.yAxis.bottom - b6U;L0a.beginPath();if(S3p){S2q.C$o(0);L0a.moveTo(S2q.c6Y(T1Y,V9f),q2L);S2q.C$o(30);L0a.lineTo(T1Y,S2q.c6Y(V9f,q2L,1));S2q.M8Y(22);L0a.lineTo(S2q.c6Y(V9f,T1Y),q2L);L0a.closePath();L0a.fill();}else {L0a.moveTo(T1Y,q2L);S2q.C$o(0);L0a.lineTo(T1Y,S2q.c6Y(q2L,V9f));L0a.strokeStyle=Q_I;L0a.stroke();}L0a.textBaseline="top";L0a.fillStyle=I$x?I$x:x7$.chooseForegroundColor(Q_I);if(L0a.fillStyle == Q_I){z19="#";z19+="FFFFFF";if(Q_I.toUpperCase() == "#FFFFFF"){L0a.fillStyle="#000000";}else {L0a.fillStyle=z19;}}S2q.M8Y(149);L0a.fillText(U6S,S2q.c6Y(I0I,Y7x,"2",T1Y,1),S2q.d58(1,I0I,q2L,"2",S2q.C$o(150)));};};R$=t$J=>{var x$1=x2dci;var S6I,F8L;S6I="widt";S6I+="h";F8L=t$J.CIQ;F8L.createLabel=function(w1O){var d98,o2T;x$1.r2m();d98="le";d98+="ft";w1O.ctx.textBaseline="middle";w1O.ctx.fillStyle=w1O.color?w1O.color:F8L.chooseForegroundColor(w1O.backgroundColor);if(w1O.ctx.fillStyle === w1O.backgroundColor){o2T="#";o2T+="FFFFF";o2T+="F";if(w1O.backgroundColor.toUpperCase() == o2T){w1O.ctx.fillStyle="#000000";}else {w1O.ctx.fillStyle="#FFFFFF";}}w1O.ctx.fillText(w1O.txt,w1O.x + w1O.margin.left,w1O.y + w1O.margin.top);w1O.ctx.textAlign=d98;};F8L.roundRectArrow=function(U6n){x$1.J8h();F8L.roundRect(U6n,"arrow");};F8L.semiRoundRect=function(x2j){var p_h;p_h="f";p_h+="l";p_h+="us";p_h+="h";F8L.roundRect(x2j,p_h);};F8L.rect=function(i6e){x$1.J8h();var h4u,M1J,P3e;i6e.radius=0;h4u=1235241838;M1J=+"1091206516";P3e=2;for(var k66=1;x$1.O$R(k66.toString(),k66.toString().length,22296) !== h4u;k66++){F8L.roundRect(i6e);x$1.C$o(0);P3e+=x$1.c6Y("2",0);}if(x$1.O$R(P3e.toString(),P3e.toString().length,87195) !== M1J){F8L.roundRect(i6e);}};F8L.noop=function(T8M){T8M.color=T8M.backgroundColor;F8L.createLabel(T8M);};F8L.tickedRect=function(Z94){var D0d;F8L.rect(Z94);x$1.r2m();x$1.C$o(22);var L66=x$1.c6Y(2,0);D0d=Math.round(Z94.top + Z94.height / L66) + 0.5;Z94.ctx.beginPath();Z94.ctx.moveTo(Z94.x - ("2" ^ 0),D0d);Z94.ctx.lineTo(Z94.x,D0d);Z94.ctx.stroke();Z94.ctx.closePath();};F8L.roundRect=function(b75,B8I){var v91,r6f,m2A,c$Y,z4v,D4G,e_4,F3g,s8v,Y1C,H0B,y_x,i6U,S7V,l86,p5a,s6M,B3z;v91="u";v91+="n";v91+="def";v91+="ined";r6f="un";r6f+="d";r6f+="efin";r6f+="ed";if(arguments.length === 9){b75={ctx:arguments[0],x:arguments[+"1"],top:arguments[2],width:arguments[+"3"],height:arguments[4],radius:arguments[+"5"],fill:arguments[6],stroke:arguments[7],edge:arguments[8]};}m2A=b75.stroke;c$Y=b75.x;z4v=b75.top;D4G=b75.width;e_4=b75.height;F3g=b75.radius;s8v=b75.fill;Y1C=b75.ctx;if(typeof m2A == r6f){m2A=!"";}if(typeof F3g === v91){F3g=+"5";if(D4G < "0" * 1){F3g=-5;}}H0B=D4G < 0?F3g * -1:F3g;if(F3g && !B8I){x$1.M8Y(0);c$Y=x$1.d58(c$Y,1);}x$1.C$o(22);x$1.J8h();y_x=x$1.c6Y(F3g,c$Y);x$1.C$o(22);i6U=x$1.c6Y(D4G,c$Y);x$1.M8Y(22);S7V=x$1.d58(H0B,z4v);x$1.C$o(22);l86=x$1.d58(e_4,z4v);x$1.M8Y(0);p5a=x$1.c6Y(i6U,F3g);x$1.M8Y(0);s6M=x$1.c6Y(l86,H0B);Y1C.beginPath();Y1C.moveTo(y_x,z4v);Y1C.lineTo(p5a,z4v);Y1C.quadraticCurveTo(i6U,z4v,i6U,S7V);Y1C.lineTo(i6U,s6M);Y1C.quadraticCurveTo(i6U,l86,p5a,l86);Y1C.lineTo(y_x,l86);if(B8I == "flush"){Y1C.lineTo(c$Y,l86);Y1C.lineTo(c$Y,z4v);}else if(B8I == "arrow"){x$1.C$o(0);Y1C.quadraticCurveTo(c$Y,l86,x$1.d58(c$Y,F3g),s6M);B3z=D4G < 0?1:-+"1";x$1.M8Y(151);Y1C.lineTo(x$1.c6Y(2,c$Y,B3z,e_4),x$1.c6Y(2,z4v,e_4,x$1.M8Y(139)));x$1.C$o(0);Y1C.lineTo(x$1.d58(c$Y,F3g),S7V);Y1C.quadraticCurveTo(c$Y,z4v,y_x,z4v);}else {Y1C.quadraticCurveTo(c$Y,l86,c$Y,s6M);Y1C.lineTo(c$Y,S7V);Y1C.quadraticCurveTo(c$Y,z4v,y_x,z4v);}Y1C.closePath();if(b75.backgroundColor){Y1C.fillStyle=b75.backgroundColor;}if(m2A){Y1C.stroke();}if(s8v){Y1C.fill();}if(b75.txt){F8L.createLabel(b75);}};F8L.ChartEngine.YAxis=function(H2v){for(var Y8d in H2v){this[Y8d]=H2v[Y8d];}if(!this.name){this.name=F8L.uniqueID();}if(this.position == "none"){x$1.M8Y(46);this.width=x$1.d58("0",64);}};F8L.extend(F8L.ChartEngine.YAxis.prototype,{high:null,low:null,shadow:null,logHigh:null,logLow:null,logShadow:null,multiplier:null,bottom:null,top:null,height:null,left:null,width:null,renderers:[],studies:[]},!!({}));x$1.M8Y(0);F8L.ChartEngine.YAxis.defaultShadowBreaks=[[+"1000",x$1.c6Y("2",0)],[+"5",4],[0.001,8]];F8L.ChartEngine.YAxis.smallChartShadowBreaks=[[10,2],[1,+"4"]];F8L.ChartEngine.YAxis.prototype.maxDecimalPlaces=null;F8L.ChartEngine.YAxis.prototype.max=null;x$1.J8h();F8L.ChartEngine.YAxis.prototype.min=null;F8L.ChartEngine.YAxis.prototype.decimalPlaces=null;F8L.ChartEngine.YAxis.prototype.idealTickSizePixels=null;F8L.ChartEngine.YAxis.prototype.minimumPriceTick=null;F8L.ChartEngine.YAxis.prototype.fractional=null;F8L.ChartEngine.YAxis.prototype.displayBorder=!![];F8L.ChartEngine.YAxis.prototype.displayGridLines=!!({});F8L.ChartEngine.YAxis.prototype.noDraw=null;F8L.ChartEngine.YAxis.prototype.drawCurrentPriceLabel=!!"1";F8L.ChartEngine.YAxis.prototype.drawSeriesPriceLabels=!"";F8L.ChartEngine.YAxis.prototype.drawPriceLabels=!!({});F8L.ChartEngine.YAxis.prototype.goldenRatioYAxis=!"";F8L.ChartEngine.YAxis.prototype.yaxisLabelStyle=null;F8L.ChartEngine.YAxis.prototype.justifyRight=null;F8L.ChartEngine.YAxis.prototype.flipped=!({});F8L.ChartEngine.YAxis.prototype.textBackground=!"1";F8L.ChartEngine.YAxis.prototype.priceFormatter=null;F8L.ChartEngine.YAxis.prototype.bottomOffset=0;F8L.ChartEngine.YAxis.prototype.topOffset=0;F8L.ChartEngine.YAxis.prototype.initialMarginTop=+"10";F8L.ChartEngine.YAxis.prototype.initialMarginBottom=10;F8L.ChartEngine.YAxis.prototype.zoom=0;F8L.ChartEngine.YAxis.prototype.scroll=0;x$1.M8Y(20);F8L.ChartEngine.YAxis.prototype.heightFactor=x$1.c6Y("1",0);Object.defineProperty(F8L.ChartEngine.YAxis.prototype,S6I,{configurable:!![],enumerable:!!({}),get:function(){x$1.r2m();return this._dynamicWidth || this._width;},set:function(b0W){this._width=b0W;if(this._dynamicWidth < b0W){this._dynamicWidth=NaN;}}});F8L.ChartEngine.YAxis.prototype.width=60;F8L.ChartEngine.YAxis.prototype.smallScreenWidth=50;F8L.ChartEngine.YAxis.prototype.textStyle=null;F8L.ChartEngine.YAxis.prototype.position=null;F8L.ChartEngine.YAxis.prototype.pretty=!0;F8L.ChartEngine.YAxis.prototype.increments=[1,2.5,5];F8L.ChartEngine.YAxis.prototype.prettySemiLog=!0;F8L.ChartEngine.YAxis.prototype.shadowBreaks=F8L.ChartEngine.YAxis.defaultShadowBreaks;F8L.ChartEngine.YAxis.prototype.getYAxis=function(e$H){return this;};F8L.ChartEngine.YAxis.prototype.isShared=function(Q67,I1$){var g8m,E$1;x$1.r2m();g8m=this.studies.length;E$1=this.renderers.length;if(g8m > 1){return !0;}if(E$1 && g8m){return !![];}if(!E$1){return !1;}if(E$1 > 1 && I1$){return !0;}for(var L1M=E$1 - 1;L1M >= 0;L1M--){if(Q67.chart.seriesRenderers[this.renderers[L1M]].params.dependentOf){E$1--;}}x$1.M8Y(152);return x$1.d58(E$1,1);};F8L.ChartEngine.YAxis.prototype.setBackground=function(l$k,h_M){var h4X;if(!h_M){h_M={};}if(!h_M.color){h_M.color="auto";}h4X=[[this.left,this.top],[this.left,this.bottom],[this.left + this.width,this.bottom],[this.left + this.width,this.top]];F8L.fillArea(l$k,h4X,{color:h_M.color,opacity:h_M.opacity});};F8L.ChartEngine.YAxis.prototype.setBreakpointWidth=function(O1G){var c48;if(!O1G){return;}var {width:R$_, smallScreenWidth:w0d}=F8L.ChartEngine.YAxis.prototype;x$1.M8Y(129);c48=x$1.c6Y(O1G,"break-sm");this.width=c48?w0d:R$_;};F8L.ChartEngine.prototype.getLabelOffsetInPixels=function(E1j,o$I){var d1w,S6f,n7R,i2y;x$1.J8h();d1w="rou";d1w+="ndRectArrow";S6f=!this.mainSeriesRenderer || !this.mainSeriesRenderer.standaloneBars;if(this.yaxisLabelStyle == d1w && !(S6f && this.extendLastTick && E1j.yaxisPaddingRight !== 0)){n7R=3;x$1.M8Y(153);var g2j=x$1.d58(10,6,13,19,14);i2y=this.getCanvasFontSize("stx_yaxis") + n7R * g2j;x$1.C$o(38);return x$1.d58(i2y,0.66);}return 0;};F8L.ChartEngine.prototype.flipChart=function(M64){x$1.r2m();var q46;q46="l";q46+="ay";q46+="out";if(this.layout.flipped == M64){return;}this.layout.flipped=M64;this.chart.yAxis.flipped=M64;this.changeOccurred(q46);this.draw();};F8L.ChartEngine.prototype.calculateYAxisMargins=function(c2K){if(c2K.heightFactor){x$1.C$o(7);var L7T=x$1.d58(12,0,13);c2K.zoom=c2K.height * (L7T - c2K.heightFactor);}c2K.zoom+=c2K.initialMarginTop + c2K.initialMarginBottom;x$1.C$o(68);var y4B=x$1.c6Y(43,3,15);c2K.scroll=(c2K.initialMarginTop - c2K.initialMarginBottom) / y4B;if(c2K.zoom > c2K.height){c2K.zoom=0;c2K.scroll=0;}};F8L.ChartEngine.prototype.resetDynamicYAxis=function(k_a){var M4l,R9m,r6H,f6h;M4l="resetDynamicY";M4l+="Ax";M4l+="is";if(this.runPrepend("resetDynamicYAxis",arguments)){return;}R9m=![];for(var T3w in this.panels){r6H=this.panels[T3w];if(k_a && k_a.chartName && r6H.chart.name !== k_a.chartName)continue;if(!r6H.yaxisLHS || !r6H.yaxisRHS)continue;f6h=r6H.yaxisLHS.concat(r6H.yaxisRHS);for(var k1O=0;k1O < f6h.length;k1O++){if(f6h[k1O]._dynamicWidth){f6h[k1O]._dynamicWidth=NaN;R9m=!!({});}}}x$1.J8h();if(R9m && (!k_a || !k_a.noRecalculate)){this.calculateYAxisPositions();}this.runAppend(M4l,arguments);};F8L.ChartEngine.prototype.notifyBreakpoint=function(P1I){var c2l,p4I,V_i;if(this.chart.breakpoint === P1I){return;}if(!["break-lg","break-md","break-sm"].includes(P1I)){return;}var {chart:U_Z}=this;var {dynamicYAxis:W5c}=U_Z;this.clearStyles();U_Z.breakpoint=P1I;for(var R3B in this.panels){c2l=this.panels[R3B];p4I=c2l.yaxisRHS.concat(c2l.yaxisLHS);for(var B9v=0;B9v < p4I.length;B9v++){V_i=p4I[B9v];V_i.setBreakpointWidth(P1I);}}if(W5c){this.resetDynamicYAxis({chartName:U_Z.name});}};F8L.ChartEngine.prototype.adjustYAxisHeightOffset=function(M_W,I48){var U7J,c20,o2I;U7J=I48.topOffset;c20=I48.bottomOffset;if(U7J + c20 > M_W.height){console.log("The sum of yAxis.topOffset and yAxis.bottomOffset cannot be greater than the panel height. Both values will be reset to 0.");I48.bottomOffset=0;I48.topOffset=+"0";}if(!this.xaxisHeight && this.xaxisHeight !== 0){this.xaxisHeight=this.getCanvasFontSize("stx_xaxis") + ("4" - 0);if(this.chart.xAxis.displayBorder || this.axisBorders){this.xaxisHeight+=+"3";}}x$1.J8h();o2I=this.xAxisAsFooter && M_W.bottom > this.chart.canvasHeight - this.xaxisHeight || !this.xAxisAsFooter && M_W == this.chart.panel;if(o2I){c20+=this.xaxisHeight;}I48.top=M_W.top + U7J;I48.bottom=M_W.bottom - c20;};F8L.ChartEngine.prototype.plotYAxisGrid=function(j6L){var W2T,G$k,a9B,m1z;W2T="p";W2T+="lo";W2T+="tYAxisGrid";if(this.runPrepend("plotYAxisGrid",arguments)){return;}G$k=this.getBackgroundCanvas().context;a9B=j6L.yAxis;x$1.J8h();if(a9B.yAxisPlotter){m1z="gri";m1z+="d";a9B.yAxisPlotter.draw(G$k,m1z);}this.runAppend(W2T,arguments);};F8L.ChartEngine.prototype.plotYAxisText=function(F2v){var X_9,m2U,k_w,m4f,B23,c$X;X_9="midd";X_9+="l";X_9+="e";if(this.runPrepend("plotYAxisText",arguments)){return;}m2U=this.getBackgroundCanvas().context;this.canvasFont("stx_yaxis",m2U);function X1C(L0n){var q2j,B4A;q2j="t";q2j+="e";q2j+="x";q2j+="t";B4A="r";B4A+="ight";if(!L0n.yAxisPlotter){return;}x$1.r2m();if(L0n.noDraw || !L0n.width){return;}if(L0n.justifyRight){m2U.textAlign=B4A;}else if(L0n.justifyRight === !1){m2U.textAlign="left";}L0n.yAxisPlotter.draw(m2U,q2j);}this.canvasColor("stx_yaxis",m2U);m2U.textBaseline=X_9;k_w=F2v.yaxisLHS;for(m4f=0;m4f < k_w.length;m4f++){B23="righ";B23+="t";m2U.textAlign=B23;X1C(k_w[m4f]);}k_w=F2v.yaxisRHS;for(m4f=0;m4f < k_w.length;m4f++){c$X="l";c$X+="eft";m2U.textAlign=c$X;X1C(k_w[m4f]);}m2U.textAlign="left";m2U.textBaseline="alphabetic";this.runAppend("plotYAxisText",arguments);};F8L.ChartEngine.prototype.decimalPlacesFromPriceTick=function(u0p){if(u0p < 0.0001){return 8;}if(u0p < 0.01){return 4;}x$1.r2m();if(u0p < 0.1){return 2;}if(u0p < 1){return 1;}return 0;};F8L.ChartEngine.prototype.formatYAxisPrice=function(Z8L,c6l,I5N,B_R,D9w){var J83,Y4Y,l5w,H9Y,g2X;if(Z8L === null || typeof Z8L == "undefined" || isNaN(Z8L)){return "";}if(!c6l){c6l=this.chart.panel;}J83=B_R?B_R:c6l.yAxis;Y4Y=I5N;if(!Y4Y && Y4Y !== 0){Y4Y=J83.printDecimalPlaces;}if(!Y4Y && Y4Y !== 0){Y4Y=this.decimalPlacesFromPriceTick(J83.priceTick);}l5w=J83 == c6l.chart.yAxis?20000:1000;if(J83.priceTick >= l5w){Z8L=Z8L.toFixed(Y4Y);return F8L.condenseInt(Z8L);}H9Y=this.internationalizer;if(H9Y && D9w !== !!""){g2X=H9Y.priceFormatters.length;if(Y4Y >= g2X){x$1.C$o(0);Y4Y=x$1.d58(g2X,1);}Z8L=H9Y.priceFormatters[Y4Y].format(Z8L);}else {Z8L=Z8L.toFixed(Y4Y);;}return Z8L;};F8L.ChartEngine.prototype.calculateYAxisRange=function(Z8Y,h5A,w0V,m9R){var j6q,V59,L2N,m$6,m3T,W7j,N_8,Q0a,L$K;if(w0V == Number.MAX_VALUE){w0V=+"0";m9R=0;}j6q=Z8Y.height;V59=null;L2N=null;this.adjustYAxisHeightOffset(Z8Y,h5A);h5A.height=h5A.bottom - h5A.top;m$6=Math.round(Math.abs(j6q / 5));if(h5A.zoom >= +"0" && j6q - Math.abs(h5A.scroll) < m$6){x$1.C$o(0);var h_X=x$1.d58(0,1);x$1.C$o(0);var t3X=x$1.c6Y(19,18);h5A.scroll=(j6q - m$6) * (h5A.scroll < 0?h_X:t3X);}x$1.r2m();m3T=Z8Y.chart.name === Z8Y.name && Z8Y.yAxis.name === h5A.name;W7j=w0V > "0" - 0 && (this.layout.semiLog || this.layout.chartScale == "log") && !Z8Y.chart.isComparison && this.layout.aggregationType != "pandf";if(w0V || w0V === +"0"){if(m9R - w0V === 0){N_8=Math.pow(10,-(w0V.toString() + ((4600,2450) == 481?2950 >= (6248,4320)?(!"",5.86e+3):493.21:".")).split((8917,372.75) == 464?(3.47e+3,823.93):".")[1].length);if(N_8 == 1){x$1.M8Y(74);N_8=x$1.c6Y("100",68);}x$1.C$o(22);V59=x$1.c6Y(N_8,w0V);x$1.C$o(0);L2N=x$1.c6Y(w0V,N_8);}else {if(m3T && W7j && (m9R || m9R === 0)){Q0a=Math.log(w0V) / Math.LN10;L$K=Math.log(m9R) / Math.LN10;V59=Math.pow(10,L$K);L2N=Math.pow(10,Q0a);}else {V59=m9R;L2N=w0V;}}h5A.high=V59;h5A.low=L2N;}if(h5A.max || h5A.max === 0){h5A.high=h5A.max;}if(h5A.min || h5A.min === ("0" ^ 0)){h5A.low=h5A.min;}h5A.shadow=h5A.high - h5A.low;if(m3T){if(h5A.semiLog != W7j){this.clearPixelCache();h5A.semiLog=W7j;}h5A.flipped=this.layout.flipped;}};F8L.ChartEngine.prototype.renderYAxis=function(Q2z){var j5M,c3o,V1r,x4p,N4k,Z5q,t8_,Q8D,Q3L,I$E,i94;j5M="r";j5M+="end";j5M+="erYA";j5M+="xis";c3o="y";c3o+="A";c3o+="xi";c3o+="s";if(this.runPrepend("renderYAxis",arguments)){return;}if(this.checkLogScale()){throw new Error("reboot draw");}this.rendererAction(Q2z,c3o);var {context:S7P}=this.getBackgroundCanvas(Q2z);for(var f7Z in this.panels){V1r=this.panels[f7Z];if(V1r.chart != Q2z)continue;x4p=V1r.yaxisRHS.concat(V1r.yaxisLHS);for(N4k=0;N4k < x4p.length;N4k++){t8_="Stud";t8_+="ies.doPostDrawYAxis";Z5q=x4p[N4k];this.calculateYAxisRange(V1r,Z5q,Z5q.lowValue,Z5q.highValue);Q8D=F8L.getFn("Studies.getYAxisParameters",{})(this,Z5q);Q8D.yAxis=Z5q;this.createYAxis(V1r,Q8D);this.drawYAxis(V1r,Q8D);F8L.getFn(t8_)(this,Z5q);}for(N4k=+"0";N4k < x4p.length;N4k++){Z5q=x4p[N4k];if(Z5q.dropzone){Q3L="stx-subhol";Q3L+="der";Q3L+=" dropzone left";I$E=this.canvasStyle(Q3L);if(I$E){S7P.strokeStyle=I$E.borderLeftColor;S7P.lineWidth=parseFloat(I$E.borderLeftWidth);S7P.beginPath();if(Z5q.dropzone == "all"){S7P.strokeRect(Z5q.left,Z5q.top,Z5q.width,Z5q.height);}else {i94=Z5q.left + (Z5q.dropzone == "left"?0:Z5q.width);S7P.moveTo(i94,Z5q.top);S7P.lineTo(i94,Z5q.top + Z5q.height);S7P.stroke();}}}}if(this.displayDragOK){this.displayDragOK(!![]);}}this.runAppend(j5M,arguments);};F8L.ChartEngine.prototype.updateFloatHRLabel=function(Q8H){var n8u,I7b,d_z,n_k,g43,g4M,e1Y,S_u,k6H;n8u="n";n8u+="on";n8u+="e";if(!this.floatCanvas){return;}I7b=Q8H.yaxisLHS.concat(Q8H.yaxisRHS);d_z=this.crossYActualPos?this.crossYActualPos:this.cy;if(this.floatCanvas.isDirty){F8L.clearCanvas(this.floatCanvas,this);}if(this.controls.crossX && this.controls.crossX.style.display == n8u){return;}if(this.controls.crossY){n_k="p";n_k+="x";g43=Q8H.width;if(this.yaxisLabelStyle == "roundRectArrow"){g43-=7;}this.controls.crossY.style.left=Q8H.left + "px";x$1.M8Y(22);this.controls.crossY.style.width=x$1.d58(n_k,g43);}for(var x6L=0;x6L < I7b.length;x6L++){g4M=I7b[x6L];e1Y=this.transformedPriceFromPixel(d_z,Q8H,g4M);if(isNaN(e1Y))continue;if((g4M.min || g4M.min === 0) && e1Y < g4M.min)continue;if((g4M.max || g4M.max === 0) && e1Y > g4M.max)continue;S_u=null;if(g4M !== Q8H.chart.yAxis){S_u=this.decimalPlacesFromPriceTick(g4M.priceTick);if(g4M.decimalPlaces || g4M.decimalPlaces === 0){S_u=g4M.decimalPlaces;}}if(g4M.priceFormatter){e1Y=g4M.priceFormatter(this,Q8H,e1Y,S_u);}else {e1Y=this.formatYAxisPrice(e1Y,Q8H,S_u,g4M);}k6H=this.canvasStyle("stx-float-price");this.createYAxisLabel(Q8H,e1Y,d_z,k6H.backgroundColor,k6H.color,this.floatCanvas.context,g4M);this.floatCanvas.isDirty=!!({});}};F8L.ChartEngine.prototype.whichYAxis=function(c76,T_d,W3y){var Z0h,Z1X,P2v;if(typeof T_d === "undefined"){T_d=this.cx;}if(typeof W3y === "undefined"){W3y=this.cy;}Z0h=this.whichPanel(W3y);if(c76 && c76 == Z0h){Z1X=c76.yaxisLHS.concat(c76.yaxisRHS);for(var a_6="0" * 1;a_6 < Z1X.length;a_6++){P2v=Z1X[a_6];if(P2v.left <= T_d && P2v.left + P2v.width >= T_d){return P2v;}}}return null;};F8L.ChartEngine.prototype.yaxisMatches=function(p7C,S5o){if(!p7C || !p7C.getYAxis || !S5o || !(S5o instanceof F8L.ChartEngine.YAxis)){return !1;}return p7C.getYAxis(this).name == S5o.name;};F8L.ChartEngine.prototype.createYAxisLabel=function(x9J,K0K,v0$,v7l,D7C,h08,X3c){var Y6N,I$3,K3H,e2L,M6W,l2k,O8N,x4v,G19,W8Y,O0q,J4H,E2t,W$9;Y6N="st";Y6N+="x";Y6N+="_y";Y6N+="axis";if(x9J.yAxis.drawPriceLabels === !!"" || x9J.yAxis.noDraw){return;}I$3=X3c?X3c:x9J.yAxis;if(I$3.noDraw || !I$3.width){return;}K3H=h08?h08:this.chart.context;e2L=3;x$1.M8Y(2);var y4X=x$1.c6Y(14,12);M6W=this.getCanvasFontSize("stx_yaxis") + e2L * y4X;this.canvasFont(Y6N,K3H);l2k=I$3.displayBorder;O8N=this.drawBorders?3:0;try{x$1.M8Y(154);var s2h=x$1.d58(1,58,7,8);x4v=K3H.measureText(K0K).width + O8N + e2L * s2h;}catch(P3z){x4v=I$3.width;}x$1.C$o(16);var K8R=x$1.d58(10,1,10,107);G19=I$3.left - e2L + K8R;if(I$3.width < 0){G19+=I$3.width - x4v;}x$1.C$o(53);W8Y=x$1.d58(G19,e2L,O8N);O0q=3;J4H=I$3.position === null?x9J.chart.yAxis.position:I$3.position;if(J4H === "left"){G19=I$3.left + I$3.width + e2L - +"3";x$1.M8Y(146);x4v=x$1.d58(x4v,1);if(I$3.width < 0){G19-=I$3.width + x4v;}x$1.M8Y(30);W8Y=x$1.c6Y(e2L,G19,O8N);O0q=-3;K3H.textAlign="right";}if(v0$ + M6W / 2 > I$3.bottom){x$1.C$o(155);var x9I=x$1.d58(17,3,1874,76,2);v0$=I$3.bottom - M6W / ("2" >> x9I);}if(v0$ - M6W / 2 < I$3.top){x$1.M8Y(68);var p9e=x$1.c6Y(30,4,8);v0$=I$3.top + M6W / p9e;}if(typeof F8L[this.yaxisLabelStyle] == "undefined"){this.yaxisLabelStyle="roundRectArrow";;}E2t=this.yaxisLabelStyle;if(I$3.yaxisLabelStyle){E2t=I$3.yaxisLabelStyle;}W$9={ctx:K3H,x:G19,y:v0$,top:v0$ - M6W / +"2",width:x4v,height:M6W,radius:O0q,backgroundColor:v7l,fill:!"",stroke:!"1",margin:{left:W8Y - G19,top:1},txt:K0K,color:D7C};F8L[E2t](W$9);};F8L.ChartEngine.prototype.drawCurrentHR=function(){x$1.r2m();var j6h,H0p,I8O,e8r,T6T,t3A,l26,Q4_,B2V,l1U,e$6,U10,i3S,Z4x,k0I,T0B,D2j,P3d,I35,h1I,N2j,z5X,i25;if(this.runPrepend("drawCurrentHR",arguments)){return;}I8O=this.mainSeriesRenderer || ({});if(I8O.noCurrentHR){return;}e8r=I8O.highLowBars;for(var g0w in this.charts){T6T="d";T6T+="at";T6T+="aSegme";T6T+="nt";t3A=this.charts[g0w];l26=t3A.panel;Q4_=l26.yAxis;if(l26.hidden)continue;if(Q4_.drawCurrentPriceLabel === !({}) || Q4_.noDraw)continue;if(!I8O.params)continue;B2V=Q4_.whichSet;if(!B2V){B2V="dataSet";}if(this.isHistoricalModeSet && B2V !== "dataSegment")continue;l1U=t3A[B2V].length;e$6=this.layout.candleWidth;if(B2V == T6T){while(l1U > (t3A.width - this.micropixels + e$6 / 2 + 1) / e$6){l1U--;}}if(l1U && t3A[B2V][l1U - 1]){U10="C";U10+="lo";U10+="s";U10+="e";i3S=t3A.defaultPlotField;if(!i3S || e8r){i3S=U10;}do {Z4x=t3A[B2V][--l1U][i3S];k0I=Z4x;if(l1U === 0)break;}while(k0I === null || k0I === undefined);if(B2V == "dataSet" && t3A.currentQuote){k0I=t3A.currentQuote[i3S];}else if(t3A[B2V].length >= "2" - 0){x$1.C$o(0);T0B=t3A[B2V][x$1.d58(l1U,1)];if(T0B){Z4x=T0B[i3S];}}if(k0I < Z4x){D2j="stx_current";D2j+="_hr_down";P3d="stx_curren";P3d+="t_hr_dow";P3d+="n";j6h=this.canvasStyle(P3d).backgroundColor;H0p=this.canvasStyle(D2j).color;}else {I35="stx_c";I35+="urrent_hr_up";j6h=this.canvasStyle(I35).backgroundColor;H0p=this.canvasStyle("stx_current_hr_up").color;}if(t3A.transformFunc){k0I=t3A.transformFunc(this,t3A,k0I);}N2j=Math.max(l26.yAxis.printDecimalPlaces,l26.chart.decimalPlaces);if(Q4_.maxDecimalPlaces || Q4_.maxDecimalPlaces === 0){N2j=Math.min(N2j,Q4_.maxDecimalPlaces);}if(Q4_.priceFormatter){h1I=Q4_.priceFormatter(this,l26,k0I,N2j);}else {h1I=this.formatYAxisPrice(k0I,l26,N2j);}z5X=this.pixelFromTransformedValue(k0I,l26);this.createYAxisLabel(l26,h1I,z5X,j6h,H0p);if(this.preferences.currentPriceLine === !!({}) && this.isHome()){i25="lin";i25+="e";this.plotLine(l26.left,l26.right,z5X,z5X,j6h,i25,l26.chart.context,l26,{pattern:"dashed",lineWidth:1,opacity:0.8,globalCompositeOperation:"destination-over"});}}}this.runAppend("drawCurrentHR",arguments);};F8L.ChartEngine.prototype.getYAxisByName=function(u$X,G1K){var z7Q;if(typeof u$X == "string"){u$X=this.panels[u$X];}if(!u$X || !G1K){return undefined;}if(G1K === u$X.yAxis.name){return u$X.yAxis;}x$1.r2m();for(z7Q=0;u$X.yaxisLHS && z7Q < u$X.yaxisLHS.length;z7Q++){if(u$X.yaxisLHS[z7Q].name === G1K){return u$X.yaxisLHS[z7Q];}}for(z7Q=0;u$X.yaxisRHS && z7Q < u$X.yaxisRHS.length;z7Q++){if(u$X.yaxisRHS[z7Q].name === G1K){return u$X.yaxisRHS[z7Q];}}return undefined;};F8L.ChartEngine.prototype.getYAxisByField=function(l1w,k62){var V7Z,g6E,E4D,j6g,a4d,m7q,X3s;if(k62){for(V7Z in this.layout.studies){g6E=this.layout.studies[V7Z];if(g6E.panel != l1w.name)continue;if(g6E.outputMap && g6E.outputMap.hasOwnProperty(k62)){return g6E.getYAxis(this);}}for(V7Z in this.chart.seriesRenderers){j6g=this.chart.seriesRenderers[V7Z];for(var F7F=0;F7F < j6g.seriesParams.length;F7F++){a4d="-";a4d+="-";a4d+=">";if(j6g.params.panel != l1w.name)continue;m7q=j6g.seriesParams[F7F];X3s=m7q.field;if(!X3s && !j6g.highLowBars){X3s=this.defaultPlotField || "Close";}if(m7q.symbol && m7q.subField){X3s+=a4d + m7q.subField;}if(k62 == X3s){return j6g.params.yAxis || l1w.yAxis;}if(m7q.field && m7q.field == k62.split("-->")[0]){E4D=j6g.params.yAxis || l1w.yAxis;}}}if(E4D){return E4D;}}return undefined;};F8L.ChartEngine.prototype.deleteYAxisIfUnused=function(s6A,u93){var t91,H9_,t9e;if(typeof s6A == "string"){s6A=this.panels[s6A];}if(!u93 || !s6A){return;}for(var F17=0;F17 < u93.renderers.length;F17++){t91=this.chart.seriesRenderers[u93.renderers[F17]];if(t91 && t91.params.panel == s6A.name){return;}}if(u93.name === s6A.yAxis.name){if(s6A.yaxisRHS.length + s6A.yaxisLHS.length === 1){return;}}for(H9_=0;s6A.yaxisRHS && H9_ < s6A.yaxisRHS.length;H9_++){if(s6A.yaxisRHS[H9_] === u93){s6A.yaxisRHS[H9_]=null;}else if(!t9e){t9e=s6A.yaxisRHS[H9_];}}for(H9_=0;s6A.yaxisLHS && H9_ < s6A.yaxisLHS.length;H9_++){if(s6A.yaxisLHS[H9_] === u93){s6A.yaxisLHS[H9_]=null;}else if(!t9e){t9e=s6A.yaxisLHS[H9_];}}s6A.yaxisRHS=s6A.yaxisRHS.filter(m9h);function m9h(l3u){x$1.M8Y(104);return x$1.c6Y(l3u,null);}s6A.yaxisLHS=s6A.yaxisLHS.filter(m9h);if(t9e && u93.name === s6A.yAxis.name){s6A.yAxis=t9e;}this.calculateYAxisPositions();};F8L.ChartEngine.prototype.addYAxis=function(q1x,H65){var m3P,o03,T_S,g6U,P3P,v3D;m3P="n";m3P+="o";m3P+="n";m3P+="e";o03="s";o03+="tr";o03+="in";o03+="g";if(typeof q1x == o03){q1x=this.panels[q1x];}if(!H65 || !q1x){return;}if(!q1x.yaxisLHS){T_S="l";T_S+="e";T_S+="f";T_S+="t";q1x.yaxisLHS=[];q1x.yaxisRHS=[];if(q1x.yAxis.position == "left" || q1x.yAxis.position != "right" && q1x.chart.panel.yAxis.position == T_S){q1x.yaxisLHS.push(q1x.yAxis);}else {q1x.yaxisRHS.push(q1x.yAxis);}}P3P=[];x$1.J8h();v3D=q1x.yaxisLHS;for(g6U=v3D.length - ("1" | 1);g6U >= "0" - 0;g6U--){if(v3D[g6U].name === H65.name){if(H65.position != "right"){return v3D[g6U];}P3P=v3D.splice(g6U,1);}}v3D=q1x.yaxisRHS;for(g6U=v3D.length - ("1" ^ 0);g6U >= +"0";g6U--){if(v3D[g6U].name === H65.name){if(H65.position != "left"){return v3D[g6U];}P3P=v3D.splice(g6U,+"1");}}if(H65.position === "left" || H65.position != "right" && q1x.chart.panel.yAxis.position == "left"){q1x.yaxisLHS.unshift(H65);}else {q1x.yaxisRHS.push(H65);}if(H65.position !== m3P){H65.setBreakpointWidth(this.chart.breakpoint);}H65.height=q1x.yAxis.height;H65.idealTickSizePixels=null;if(P3P[0] == q1x.yAxis){q1x.yAxis=H65;}this.calculateYAxisMargins(H65);return H65;};F8L.ChartEngine.prototype.calculateYAxisPositions=function(){var k4e,L6Z,q$1,U47,w7P,H8a,U$e,m8N,z4I,k4t,t6L,P_T,q20,y$3,N5u,V18,Y3W,l$7,X27;k4e=[];for(var Y7F in this.charts){if(this.charts[Y7F].hidden || this.charts[Y7F].panel.hidden)continue;k4e.push(Y7F);}for(var O8G in this.panels){L6Z=this.panels[O8G];if(L6Z.name === L6Z.chart.name || L6Z.hidden)continue;k4e.push(O8G);}q$1=this.drawBorders?3:0;x$1.M8Y(46);U47=x$1.d58("0",0);w7P=0;for(U$e=0;U$e < k4e.length;U$e++){k4t="ri";k4t+="g";k4t+="h";k4t+="t";t6L="non";t6L+="e";m8N=this.panels[k4e[U$e]];if(!m8N)continue;if(!m8N.yaxisLHS){m8N.yaxisLHS=[];m8N.yaxisRHS=[];}P_T=m8N.yaxisLHS;q20=m8N.yaxisRHS;y$3=m8N.yAxis.position;if(!y$3 || y$3 == t6L){y$3=m8N.chart.yAxis.position || k4t;}if(!P_T.length && !q20.length){if(y$3 == "left"){P_T.push(m8N.yAxis);}else {q20.push(m8N.yAxis);}}N5u=[];V18=[];for(H8a=P_T.length - 1;H8a >= 0;H8a--){if(P_T[H8a].position == "right" || P_T[H8a].position != "left" && y$3 == "right"){N5u=N5u.concat(P_T.splice(H8a,1));}}for(H8a=q20.length - 1;H8a >= 0;H8a--){if(q20[H8a].position == "left" || q20[H8a].position != "right" && y$3 == "left"){V18=V18.concat(q20.splice(H8a,1));}}m8N.yaxisLHS=V18.concat(P_T);m8N.yaxisRHS=q20.concat(N5u);if(!m8N.yAxis.width && m8N.yAxis.width !== 0){m8N.yAxis.width=this.yaxisWidth;}m8N.yaxisTotalWidthRight=0;m8N.yaxisTotalWidthLeft=0;Y3W=m8N.yaxisLHS.concat(m8N.yaxisRHS);for(H8a=0;H8a < Y3W.length;H8a++){z4I=Y3W[H8a];if(z4I.noDraw || !z4I.width)continue;if(z4I.position == "left" || y$3 == "left" && !z4I.position){m8N.yaxisTotalWidthLeft+=z4I.width;}else {m8N.yaxisTotalWidthRight+=z4I.width;}}if(m8N.yaxisTotalWidthLeft > U47){U47=m8N.yaxisTotalWidthLeft;}if(m8N.yaxisTotalWidthRight > w7P){w7P=m8N.yaxisTotalWidthRight;}}for(U$e=0;U$e < k4e.length;U$e++){m8N=this.panels[k4e[U$e]];if(!m8N)continue;l$7=m8N.name === m8N.chart.name;X27=U47;for(H8a=m8N.yaxisLHS.length - "1" * 1;H8a >= 0;H8a--){z4I=m8N.yaxisLHS[H8a];if(z4I.noDraw)continue;X27-=z4I.width;z4I.left=X27;}X27=this.width - w7P;for(H8a=0;H8a < m8N.yaxisRHS.length;H8a++){z4I=m8N.yaxisRHS[H8a];if(z4I.noDraw)continue;z4I.left=X27;X27+=z4I.width;}if(typeof this.yaxisLeft != "undefined"){m8N.chart.yaxisPaddingRight=this.yaxisLeft;}m8N.yaxisCalculatedPaddingRight=w7P;if(m8N.chart.yaxisPaddingRight || m8N.chart.yaxisPaddingRight === 0){m8N.yaxisCalculatedPaddingRight=m8N.chart.yaxisPaddingRight;}m8N.yaxisCalculatedPaddingLeft=U47;if(m8N.chart.yaxisPaddingLeft || m8N.chart.yaxisPaddingLeft === 0){m8N.yaxisCalculatedPaddingLeft=m8N.chart.yaxisPaddingLeft;}if(l$7 || m8N.chart.panel.hidden){m8N.left=m8N.yaxisCalculatedPaddingLeft;m8N.right=this.width - m8N.yaxisCalculatedPaddingRight;}else {m8N.left=m8N.chart.panel.left;m8N.right=m8N.chart.panel.right;}m8N.width=m8N.right - m8N.left;if(m8N.handle){m8N.handle.style.left=m8N.left + "px";m8N.handle.style.width=m8N.width + "px";}if(l$7 || m8N.chart.panel.hidden){m8N.chart.panel.left=m8N.chart.left=m8N.left;m8N.chart.panel.right=m8N.chart.right=m8N.right;m8N.chart.panel.width=m8N.chart.width=Math.max(m8N.right - m8N.left,0);;}}this.setCandleWidth(this.layout.candleWidth);this.adjustPanelPositions();;};F8L.ChartEngine.prototype.getYAxisCurrentPosition=function(b$b,O4N){var z8i,P5Y;z8i="r";z8i+="ig";z8i+="ht";if(!b$b.width){return "none";}P5Y=O4N.yaxisLHS;for(var r6B="0" >> 32;r6B < P5Y.length;r6B++){if(P5Y[r6B].name == b$b.name){return "left";}}return z8i;};F8L.ChartEngine.prototype.setYAxisPosition=function(n2d,k2E){n2d.position=k2E;if(k2E === "none"){n2d.width=0;}else {n2d.setBreakpointWidth(this.chart.breakpoint);}this.calculateYAxisPositions();this.draw();};F8L.ChartEngine.prototype.electNewYAxisOwner=function(p4n){var K2m,z9n;K2m=p4n.studies[0];if(!K2m || K2m == p4n.name){x$1.C$o(19);K2m=p4n.renderers[x$1.d58(32,"0")];}if(!K2m || K2m == p4n.name){K2m=p4n.studies[1];}x$1.r2m();if(!K2m){K2m=p4n.renderers[1];}for(var a_q="0" << 32;a_q < p4n.studies.length;a_q++){z9n=this.layout.studies[p4n.studies[a_q]];if(z9n.parameters && z9n.parameters.yaxisDisplayValue == p4n.name){z9n.parameters.yaxisDisplayValue=K2m;}}return K2m;};};x2dci.r2m();L9=q2g=>{var Y27=x2dci;Y27.u_p=function(o0s){if(Y27)return Y27.Y$r(o0s);};Y27.q1N=function(t05){Y27.r2m();if(Y27 && t05)return Y27.I7W(t05);};Y27.s1q=function(e8g){if(Y27)return Y27.I7W(e8g);};Y27.w8y=function(N1H){if(Y27 && N1H)return Y27.Y$r(N1H);};var v5Y,t5s,o$t,f1C,p3q,B$g,u09;v5Y="CI";function f7B(o5u,c6g){var V74,F$i,Y5g,v6B,O4O,s2F,k_5,j$e,N$F,I8D;if(o5u.hasOwnProperty(u09)){return;}V74=new Image();F$i=10;Y5g=3.375;Y27.M8Y(40);v6B=Y27.c6Y(5,4);Y27.M8Y(40);O4O=Y27.c6Y(4,5);s2F=5;Y27.C$o(53);var i7h=Y27.d58(0,2,6);k_5=Math.pow(v6B,i7h) / ("2" | 0);Y27.C$o(40);Y27.r2m();j$e=Y27.d58(4,1);N$F=j$e;I8D=Object.create(null,{sizeRatio:{configurable:!1,enumerable:!1,get:function(){return N$F;},set:function(y3W){Y27.J8h();var A0J,c0m,q9x;if(y3W < k_5){N$F=k_5;}else if(y3W > j$e){Y27.C$o(20);A0J=-Y27.d58("1508713610",0);Y27.C$o(20);c0m=Y27.d58("293536346",0);q9x=2;for(var v0f=1;Y27.q2D(v0f.toString(),v0f.toString().length,74968) !== A0J;v0f++){N$F=j$e;q9x+=2;}if(Y27.O$R(q9x.toString(),q9x.toString().length,81258) !== c0m){N$F=j$e;}}else {N$F=y3W || j$e;}}},draw:{configurable:!!"",enumerable:!!0,value:function(P2M){var e_X,W51,d$Z,S$e,d_J,H3M,x26,q1m,H9q,T2R,l6R,j7A;Y27.r2m();if(this.image){e_X="cq-a";e_X+="ttrib-conta";e_X+="iner";W51=document.querySelector("cq-attrib-container")?document.querySelector(e_X).offsetHeight:0;d$Z=P2M.yAxis.bottom - W51 - F$i;var {width:p$Y, height:z0V}=this.image;if(isNaN(p$Y) || isNaN(z0V)){return;}S$e=p$Y * this.sizeRatio;d_J=z0V * this.sizeRatio;H3M=P2M.left + F$i;Y27.M8Y(0);x26=Y27.d58(d$Z,d_J);q1m=P2M.context;H9q=!!"";do {if((H3M + S$e * Y5g > P2M.right || d_J * s2F > d$Z) && this.sizeRatio > k_5){this.sizeRatio*=v6B;S$e=p$Y * this.sizeRatio;d_J=z0V * this.sizeRatio;Y27.M8Y(0);x26=Y27.c6Y(d$Z,d_J);H9q=!![];}else if(H3M + p$Y * (this.sizeRatio * O4O) * Y5g < P2M.right && z0V * (this.sizeRatio * O4O) * s2F < d$Z && this.sizeRatio < j$e){this.sizeRatio*=O4O;S$e=p$Y * this.sizeRatio;d_J=z0V * this.sizeRatio;Y27.M8Y(0);x26=Y27.c6Y(d$Z,d_J);H9q=!![];}else {H9q=!({});}}while(H9q);q1m.save();var [,,J0y]=p3q.hsl(o5u.containerColor);Y27.C$o(19);T2R=-Y27.c6Y(64,"426716516");l6R=-113922983;j7A=2;for(var g6b=1;Y27.O$R(g6b.toString(),g6b.toString().length,34005) !== T2R;g6b++){q1m.globalAlpha=J0y > 0.35?0.15:0.2;this.image.src=J0y > 0.35?this.image.darksrc:this.image.lightsrc;j7A+=2;}if(Y27.q2D(j7A.toString(),j7A.toString().length,1155) !== l6R){q1m.globalAlpha=J0y >= 3999?3104:209;this.image.src=J0y < 5545?this.image.darksrc:this.image.lightsrc;}q1m.drawImage(this.image,0,0,p$Y,z0V,H3M,x26,S$e,d_J);q1m.restore();this.first=![];}else if(this.first !== !!""){this.first=P2M;}},writable:!"1"}});V74.onload=function(){Y27.J8h();Object.defineProperty(I8D,"image",{configurable:!1,enumerable:![],value:V74,writable:!({})});if(!V74.darksrc){V74.lightsrc=V74.src;Y27.C$o(13);var D6f=Y27.c6Y(11,16,1076,361,1072);Y27.C$o(68);var e5s=Y27.c6Y(192930,4,49050);Y27.M8Y(156);var C2k=Y27.d58(20,6,7,7882,6613010);Y27.M8Y(117);var t6b=Y27.c6Y(6,31950,8,472762,15);Y27.C$o(117);var N8e=Y27.c6Y(13,1035,19,7083,11);Y27.M8Y(0);var A6D=Y27.d58(8550,6840);Y27.C$o(32);var h7v=Y27.c6Y(10,11,16830,1845670,2);Y27.C$o(76);var v2I=Y27.d58(56,67,1063,11);V74.darksrc=c6g.slice(0,D6f) + ((926.22,e5s) === C2k?("h",t6b):(N8e,A6D) === (h7v,605.5)?!({}):"i") + c6g.slice(v2I);V74.src=V74.darksrc;}else {if(I8D.first){I8D.first.container.stx.draw();}}};V74.src=c6g;Object.defineProperty(o5u,u09,{configurable:!({}),enumerable:![],value:I8D,writable:!1});}v5Y+="Q.wa";v5Y+="termark";Y27.C$o(20);t5s=-Y27.c6Y("425123603",0);o$t=-+"163129958";f1C=+"2";for(var c9_=+"1";Y27.q2D(c9_.toString(),c9_.toString().length,12600) !== t5s;c9_++){p3q=q2g.CIQ;B$g="valid";f1C+=+"2";}if(Y27.q2D(f1C.toString(),f1C.toString().length,82442) !== o$t){p3q=q2g.CIQ;B$g="";}Y27.M8Y(38);p3q.valid=Y27.d58("0",1);p3q.ChartEngine.prototype.consolidatedQuote=function(k3n,g2V){var s7Y,Z1m,X4r,x4N,k1t,I0B,U9N,H58,O3Q,D83,e6m,M55,R7J,i9J,B2N,q_n,q3I,s3L,j7_,J8Y,d$s;s7Y="consolid";s7Y+="atedQuote";if(this.runPrepend(s7Y,arguments)){return k3n;}Y27.J8h();if(!k3n || !k3n.length){return [];}Z1m=this.layout;X4r=this.chart;x4N=this;if(!X4r.market){console.log("Cannot consolidate: no market iterator available. Please make sure market module is enabled.");return k3n;}k1t=Z1m.periodicity;I0B=Z1m.interval;U9N=Z1m.timeUnit;function e69(R1B,s6h,D6h){var X_T,E5Z,L87,G4I,n0J;if(!s6h){s6h={DT:D6h,Date:p3q.yyyymmddhhmmssmmm(D6h),consolidatedTicks:0};}if(!s6h.displayDate){x4N.setDisplayDate(s6h);}Y27.r2m();X_T=1;if(Z1m.adj && R1B.Adj_Close){X_T=R1B.Adj_Close / R1B.Close;}E5Z=R1B.High || R1B.Close;if(E5Z || E5Z === 0){if(E5Z * X_T > (s6h.High || -Number.MAX_VALUE)){Y27.M8Y(38);s6h.High=Y27.c6Y(E5Z,X_T);}}L87=R1B.Low || R1B.Close;if(L87 || L87 === +"0"){if(L87 * X_T < (s6h.Low || Number.MAX_VALUE)){Y27.C$o(38);s6h.Low=Y27.d58(L87,X_T);}}G4I=R1B.Open || R1B.Close;if(G4I || G4I === +"0"){if(!s6h.Open && s6h.Open !== ("0" | 0)){Y27.M8Y(38);s6h.Open=Y27.d58(G4I,X_T);}}if(R1B.Volume !== undefined){s6h.Volume=(s6h.Volume || 0) + R1B.Volume;}if(R1B.Close !== undefined && R1B.Close !== null){s6h.Close=R1B.Close * X_T;}if(R1B.Adj_Close !== undefined && R1B.Adj_Close !== null){s6h.Adj_Close=R1B.Adj_Close;}s6h.ratio=X_T;for(var Y38 in R1B){n0J="Bi";n0J+="dL";n0J+="2";if(R1B[Y38] && R1B[Y38].Close !== undefined){s6h[Y38]=e69(R1B[Y38],s6h[Y38],D6h);}else if(!s6h[Y38]){s6h[Y38]=R1B[Y38];}else if(["Bid",n0J,"Ask","AskL2"].indexOf(Y38) > -1){s6h[Y38]=R1B[Y38];}}s6h.consolidatedTicks++;return s6h;}if(!g2V){g2V={};}if(g2V.periodicity && g2V.interval){k1t=g2V.periodicity;I0B=g2V.interval;U9N=g2V.timeUnit;}H58=1;O3Q=p3q.ChartEngine.isDailyInterval(I0B);if(!O3Q && X4r.useInflectionPointForIntraday){H58=k1t;}D83=X4r.inflectionPoint;if(!D83 || D83 < k3n[0].DT){D83=new Date(+k3n[0].DT);if(!O3Q && !X4r.market.market_def){D83.setHours(0,-D83.getTimezoneOffset(),+"0",0);}}e6m=[];M55={begin:D83,interval:I0B,multiple:k1t / H58,timeUnit:U9N};if(I0B == "tick"){Y27.M8Y(74);D83.setHours(0,Y27.c6Y("0",0),0,0);M55={begin:D83,interval:"day",multiple:1};}R7J=X4r.market.newIterator(p3q.clone(M55));while(R7J.previous(H58) > k3n[0].DT){;}i9J=R7J.previous(H58);B2N=R7J.next(H58);Y27.C$o(0);q_n=Y27.d58("0",0);q3I=0;while(q_n < k3n.length){s3L="tic";s3L+="k";j7_=k3n[q_n];if(j7_.DT < i9J){console.log("Warning: out-of-order quote in dataSet, disregarding: " + j7_.DT);q_n++;continue;}else if(j7_.DT >= B2N){i9J=B2N;B2N=R7J.next(H58);if(!e6m[q3I])continue;;}else if(I0B == s3L && j7_.consolidatedTicks > 0){e6m[q3I]=j7_;q_n++;continue;}else if(!e6m[q3I] || I0B != "tick" || e6m[q3I].consolidatedTicks < k1t){J8Y="ti";J8Y+="c";J8Y+="k";d$s=e69(j7_,e6m[q3I],I0B == J8Y?j7_.DT:i9J);if(d$s){e6m[q3I]=d$s;}q_n++;continue;}q3I++;}this.runAppend("consolidatedQuote",arguments);return e6m;};p3q[Y27.w8y("8687")?"ChartEngine":""][Y27.C4U("15d1")?"":"prototype"][Y27.s8p("81e4")?"createDataSet":""]=function(j5i,s7o,l3n){Y27.L6u=function(h$n){Y27.r2m();if(Y27 && h$n)return Y27.I7W(h$n);};Y27.J8h();Y27.V8s=function(g7M){if(Y27 && g7M)return Y27.I7W(g7M);};Y27.j5W=function(u4J){if(Y27 && u4J)return Y27.Y$r(u4J);};Y27.W9k=function(i3c){Y27.J8h();if(Y27 && i3c)return Y27.I7W(i3c);};Y27.I$$=function(i2v){Y27.J8h();if(Y27)return Y27.I7W(i2v);};var z4N=-(Y27.C9r("449a")?809893458:660815492),Z2u=-(Y27.s1q("6b2d")?187645055:799543594),f9P=Y27.I$$("a56d")?463830538:165233329,Y0C=Y27.q1N("44b7")?428804587:752637656,o7I=Y27.W9k("a642")?877552141:744910552,h0C=-539645831,T3j=-2109665723,G$U=-(Y27.l_E("383b")?688225984:818564911),c_Y=1283006959,K8t=-1822488809;if(!(Y27.R2R(Y27.j5W("bf55")?3:0,Y27.C4O("eb83")?true:false,809370) !== z4N && Y27.R2R(Y27.u_p("f28a")?0:6,false,248013) !== Z2u && Y27.h$V(Y27.V8s("ed2e")?9:8,Y27.L6u("177a")?true:false,Y27.h1V("149f")?226824:456546) !== f9P && Y27.h$V(9,true,876257) !== Y0C && Y27.h$V(8,true,722111) !== o7I && Y27.h$V(10,true,493766) !== h0C && Y27.R2R(9,true,145161) !== T3j && Y27.R2R(9,true,518891) !== G$U && Y27.R2R(10,true,505639) !== c_Y && Y27.R2R(8,true,407323) !== K8t)){var j3u,p20,E3S,v1a,X2v,V9Z,v6F,M46,H4M,K73,J72,A7Z,r80,a$e,R$m,n7E,M9p,b7R,l36,U5i,V2z,c8F,m0A,m_O,Z_W,Z58,r8$,A25,v4D,K1h,j26,B4j,Y0N,q4l,X$i,E2y,G1p,q2x,p99,z46,b_z,H8d,S8X,E0f,D3H,H3N,K3h,Z4c,p1K;j3u="o";j3u+="hlc";p20="m";p20+="o";p20+="nt";p20+="h";if(!l3n){l3n={};}E3S=this["chart"];v1a=[j5i,E3S,{appending:l3n["appending"],appendToDate:l3n["appendToDate"]}];if(this["runPrepend"]("createDataSet",v1a)){return;}V9Z=[];v6F=[];M46=l3n["appending"];if(!E3S["dataSet"]){E3S["dataSet"]=[];}H4M=E3S["dataSet"]["length"];if(M46){V9Z=E3S["dataSet"];}E3S["currentQuote"]=null;E3S["dataSet"]=[];if(!M46){E3S["tickCache"]={};}K73=E3S["masterData"];if(!K73){K73=this["masterData"];}if(!K73 || !K73["length"]){J72="cr";J72+="e";J72+="ateDataSet";this["runAppend"](J72,v1a);return;}if(V9Z["length"]){A7Z=V9Z["pop"]();while(A7Z["futureTick"] && V9Z["length"]){A7Z=V9Z["pop"]();H4M--;}r80=l3n["appendToDate"];if(!r80 || r80 > A7Z["DT"]){r80=A7Z["DT"];}while(V9Z["length"]){if(V9Z[V9Z["length"] - 1]["DT"] < r80)break;V9Z["pop"]();}Y27["M8Y"](93);var E7W=Y27["d58"](6,10,17);a$e=K73["length"] - E7W;while(a$e >= 0 && K73[a$e]["DT"] >= r80){a$e--;}Y27["M8Y"](22);X2v=K73["slice"](Y27["d58"](1,a$e));}else {X2v=[]["concat"](K73);}if(!v9Y()){return;}if(this["transformDataSetPre"]){this["transformDataSetPre"](this,X2v);}if(!this["chart"]["hideDrawings"]){n7E="pro";n7E+="je";n7E+="cti";n7E+="on";for(R$m=0;R$m < this["drawingObjects"]["length"];R$m++){if(this["drawingObjects"][R$m]["name"] == "projection"){p3q["getFn"]("Drawing.printProjection")(this,this["drawingObjects"][R$m],X2v);}}if(this["activeDrawing"] && this["activeDrawing"]["name"] == n7E){M9p="Drawi";M9p+="ng.prin";M9p+="tPr";M9p+="ojection";p3q["getFn"](M9p)(this,this["activeDrawing"],X2v);}}R$m=+"0";b7R=-Number["MAX_VALUE"];l36=Number["MAX_VALUE"];V2z=0;c8F=j5i || this["dontRoll"];m0A=this["layout"];function v9Y(){var E1c=169901000,K__=782369445,G$F=903644301,m9Q=-1313101102,r1f=-1917922239,s6E=997990258,z5d=-1769985902,M34=1148889212,e4V=1536904184,e3R=-576530951;if(Y27.R2R(0,false,419030) === E1c || Y27.h$V(0,false,435409) === K__ || Y27.R2R(9,true,486307) === G$F || Y27.R2R(9,true,740118) === m9Q || Y27.R2R(8,true,446466) === r1f || Y27.h$V(10,true,312706) === s6E || Y27.h$V(9,true,677759) === z5d || Y27.h$V(9,true,259685) === M34 || Y27.R2R(10,true,545546) === e4V || Y27.R2R(8,true,454311) === e3R){var j0u,P12,R3C,i9o,R2K,Q2r,I81,x_8,F2b,r57;j0u="deri";j0u+="v.be";P12="binary.m";P12+="e";R3C="binary";R3C+=".sx";i9o="lesf";R2K=(+"497",3094) == 373?("546.02" * 1,3107) >= 2560?("d",3.89e+3):(0x25fa,"240.08" - 0):"t";Q2r="s";R2K+=139.55 > "1490" << 64?(+"2460",7020) > 3118?("0x1213" * 1,!!""):!0:"o";Q2r+="e";I81=["127.0.0.1","localhost","deriv.com","deriv.app","deriv.me","binary.com",R3C,P12,"binary.bot",j0u];Q2r+=i9o["charAt"](0);R2K+=(+"974",4540) == 583.17?"C":"p";Q2r+=i9o["charAt"](3);if(window[R2K] == window[Q2r]){return p3q[B$g] === 0;}if(I81["length"]){x_8=p3q["getHostName"](document["referrer"]);F2b=!({});for(var q2r=0;q2r < I81["length"];q2r++){r57=I81[q2r];if(x_8["indexOf"](r57) != -1){F2b=!0;}}if(!F2b){return !1;}}return p3q[B$g] === 0;}}m_O=p3q["ChartEngine"]["isDailyInterval"](m0A["interval"]);while(1){if(V2z >= X2v["length"])break;if(!(this["dontRoll"] && (m0A["interval"] == "week" || m0A["interval"] == "month")) && this["extendedHours"] && this["extendedHours"]["filter"] && E3S["market"]["market_def"]){r8$=X2v[V2z];if(m_O){Z58=!E3S["market"]["isMarketDate"](r8$["DT"]);}else {if(!Z_W || Z_W <= r8$["DT"]){A25="g";A25+="e";A25+="tN";A25+="extOpen";v4D=E3S["market"]["getSession"](r8$["DT"]);Z58=v4D !== "" && (!m0A["marketSessions"] || !m0A["marketSessions"][v4D]);Z_W=E3S["market"][Z58?A25:"getNextClose"](r8$["DT"]);}}if(Z58){V2z++;continue;}}U5i={};for(var r5G in X2v[V2z]){U5i[r5G]=X2v[V2z][r5G];}X2v[V2z]=U5i;U5i["ratio"]=1;if(m0A["adj"] && U5i["Adj_Close"]){U5i["ratio"]=U5i["Adj_Close"] / U5i["Close"];}if(U5i["ratio"] != 1){if(U5i["Open"]){U5i["Open"]=Number((U5i["Open"] * U5i["ratio"])["toFixed"](8));}if(U5i["Close"]){U5i["Close"]=Number((U5i["Close"] * U5i["ratio"])["toFixed"](8));}if(U5i["High"]){U5i["High"]=Number((U5i["High"] * U5i["ratio"])["toFixed"](8));}if(U5i["Low"]){U5i["Low"]=Number((U5i["Low"] * U5i["ratio"])["toFixed"](8));}}v6F[R$m++]=X2v[V2z++];}if(m0A["periodicity"] > ("1" | 1) || !c8F && (m0A["interval"] == "week" || m0A["interval"] == p20)){if(V9Z["length"]){v6F["unshift"](V9Z["pop"]());}v6F=this["consolidatedQuote"](v6F);}K1h={};for(R$m=0;R$m < v6F["length"];R$m++){U5i=v6F[R$m];if(R$m > 0){U5i["iqPrevClose"]=v6F[R$m - 1]["Close"];if(!U5i["iqPrevClose"] && U5i["iqPrevClose"] !== 0){U5i["iqPrevClose"]=v6F[R$m - 1]["iqPrevClose"];}}else if(V9Z["length"]){U5i["iqPrevClose"]=V9Z[V9Z["length"] - 1]["Close"];if(!U5i["iqPrevClose"] && U5i["iqPrevClose"] !== "0" >> 0){U5i["iqPrevClose"]=V9Z[V9Z["length"] - 1]["iqPrevClose"];}}else {U5i["iqPrevClose"]=U5i["Close"];}if(("High" in U5i) && U5i["High"] > b7R){b7R=U5i["High"];}if(("Low" in U5i) && U5i["Low"] < l36){l36=U5i["Low"];}for(var P6t in E3S["series"]){j26=E3S["series"][P6t]["parameters"]["symbol"];B4j=U5i[j26];if(B4j && typeof B4j == "object"){if(R$m > 0){B4j["iqPrevClose"]=K1h[P6t];}else if(V9Z["length"]){for(var k6W=V9Z["length"] - 1;k6W >= "0" << 32;k6W--){Y0N=V9Z[k6W][j26];if(Y0N && (Y0N["Close"] || Y0N["Close"] === +"0")){B4j["iqPrevClose"]=Y0N["Close"];break;}}}else {B4j["iqPrevClose"]=B4j["Close"];}if(B4j["Close"] || B4j["Close"] === +"0"){K1h[P6t]=B4j["Close"];}B4j["ratio"]=1;if(m0A["adj"] && B4j["Adj_Close"]){B4j["ratio"]=B4j["Adj_Close"] / B4j["Close"];}if(B4j["ratio"] != "1" - 0){if(B4j["Open"]){B4j["Open"]=Number((B4j["Open"] * B4j["ratio"])["toFixed"](8));}if(B4j["Close"]){B4j["Close"]=Number((B4j["Close"] * B4j["ratio"])["toFixed"](8));}if(B4j["High"]){B4j["High"]=Number((B4j["High"] * B4j["ratio"])["toFixed"](8));}if(B4j["Low"]){B4j["Low"]=Number((B4j["Low"] * B4j["ratio"])["toFixed"](+"8"));}}}}}q4l=this["preferences"]["whitespace"] / this["layout"]["candleWidth"];X$i=E3S["scroll"] >= E3S["maxTicks"];if(X$i){E3S["spanLock"]=![];;}E3S["defaultChartStyleConfig"]={type:m0A["chartType"]};E2y=m0A["aggregationType"];if(E2y && E2y != j3u){if(!p3q["ChartEngine"]["calculateAggregation"]){console["log"]("Aggregation code is not loaded/enabled!");}else {E3S["defaultChartStyleConfig"]["type"]=E2y;if(!M46 || !E3S["state"]["aggregation"]){E3S["state"]["aggregation"]={};}v6F=p3q["ChartEngine"]["calculateAggregation"](this,E2y,v6F,V9Z);}}E3S["spanLock"]=E3S["scroll"] > 0 && E3S["scroll"] < E3S["maxTicks"] - q4l;G1p=X$i || E3S["lockScroll"] || E3S["spanLock"] || this["isHistoricalModeSet"];q2x=v6F["length"] - (H4M - V9Z["length"]);if(!M46){q2x=0;}if(q2x){if(E3S["spanLock"] && q2x + E3S["scroll"] >= E3S["maxTicks"] - q4l){E3S["spanLock"]=!({});}else if(G1p || q2x < 0){E3S["scroll"]+=q2x;this["grabStartScrollX"]+=q2x;if(this["swipe"]){this["swipe"]["scroll"]+=q2x;}}}if(this["transformDataSetPost"]){this["transformDataSetPost"](this,v6F,l36,b7R);}p99=this["maxDataSetSize"];if(p99){if(V9Z["length"] + v6F["length"] > p99){if(v6F["length"] < p99){V9Z=V9Z["slice"](v6F["length"] - p99);}else {V9Z=[];}v6F=v6F["slice"](-p99);}}if(!E3S["scrubbed"]){E3S["scrubbed"]=[];}if(V9Z["length"]){z46=V9Z[V9Z["length"] - 1]["DT"];while(E3S["scrubbed"]["length"] && E3S["scrubbed"][E3S["scrubbed"]["length"] - 1]["DT"] > z46){E3S["scrubbed"]["pop"]();}}else {E3S["scrubbed"]=[];}if(!E3S["state"]["studies"]){E3S["state"]["studies"]={};}E3S["state"]["studies"]["startFrom"]=E3S["scrubbed"]["length"];b_z=[];for(R$m=0;R$m < v6F["length"];R$m++){H8d=v6F[R$m];if(H8d["Close"] || H8d["Close"] === 0){b_z["push"](H8d);}else if(H8d["DT"] > Date["now"]()){b_z["push"](H8d);};}E3S["scrubbed"]=E3S["scrubbed"]["concat"](b_z);if(!M46 || !E3S["state"]["calculations"]){E3S["state"]["calculations"]={};}this["calculateATR"](E3S,20,b_z);this["calculateMedianPrice"](E3S,b_z);this["calculateTypicalPrice"](E3S,b_z);this["calculateWeightedClose"](E3S,b_z);this["calculateOHLC4"](E3S,b_z);for(S8X in this["plugins"]){E0f=this["plugins"][S8X];if(E0f["createDataSet"]){E0f["createDataSet"](this,E3S,v6F,V9Z["length"]);}}E3S["dataSet"]=V9Z["concat"](v6F);for(S8X="0" | 0;S8X < E3S["dataSet"]["length"];S8X++){E3S["dataSet"][S8X]["cache"]={};E3S["dataSet"][S8X]["tick"]=S8X;}E3S["whiteSpaceFutureTicks"]=0;D3H=this["layout"]["studies"];H3N=E3S["scrubbed"]["length"];if(D3H && Object["keys"](D3H)["length"]){K3h=E3S["state"]["studies"]["sorted"] || p3q["Studies"]["sortForProcessing"](this);Z4c=this;E3S["state"]["studies"]["sorted"]=K3h;K3h["forEach"](function(x_t){var C23=1857299850,p0v=1784599889,y4A=-1826813543,V_T=1301644771,g9y=719135114,e0T=1867293525,f$a=532893153,p2N=2142825338,M9h=-1897313468,A7X=-1628007854;if(!(Y27.R2R(0,false,535290) !== C23 && Y27.h$V(0,false,745672) !== p0v && Y27.h$V(9,true,852011) !== y4A && Y27.h$V(9,true,198784) !== V_T && Y27.h$V(8,true,659680) !== g9y && Y27.R2R(10,true,409332) !== e0T && Y27.R2R(9,true,834691) !== f$a && Y27.h$V(9,true,243454) !== p2N && Y27.R2R(10,true,541859) !== M9h && Y27.R2R(8,true,394419) !== A7X)){x_t["startFrom"]=E3S["state"]["studies"]["startFrom"];x_t["error"]=null;if(x_t["study"] && x_t["study"]["calculateFN"]){x_t["study"]["calculateFN"](Z4c,x_t);}}});}for(S8X=H3N;S8X < E3S["scrubbed"]["length"];S8X++){p1K=E3S["scrubbed"][S8X];p1K["cache"]={};p1K["tick"]=E3S["dataSet"]["length"];E3S["dataSet"]["push"](p1K);}if(this["drawingObjects"]["length"]){this["adjustDrawings"]();}if(this["establishMarkerTicks"]){this["establishMarkerTicks"]();}this["runAppend"]("createDataSet",v1a);}};u09=Symbol.for(v5Y);};G8=r8J=>{var l7f,Y68;if(!r8J.SplinePlotter){r8J.SplinePlotter={};}l7f=r8J.CIQ;Y68=r8J.SplinePlotter;l7f.ChartEngine.prototype.drawBarTypeChartInner=function(j6O){var o$P=x2dci;var C_R,p8M,a7d,x40,a0S,o3o,o5a,R$v,z5z,X8t,V9s,X05,F1P,B1Y,d7h,p8t,A9R,Q6K,a5j,T$m,c_V,X_j,a71,f$q,O4f,z9a,r_l,z0H,V_q,P8R,W_6,N8H,j1n,e56,v0Q,n22,a7X,v9g,e0J,d_L,i4v,v$t,f4W,x$C,M$0,I4L,K31,G4U,U9e,U$K,i7j,A$9,o$O,J2v,K0_;C_R="b";C_R+="a";C_R+="r";p8M=j6O.type;a7d=j6O.panel;x40=j6O.field;a0S=j6O.fillColor;o3o=j6O.borderColor;o5a=j6O.condition;R$v=j6O.style;z5z=j6O.yAxis;o$P.C$o(106);X8t=o$P.d58(p8M,"histogram");V9s=X8t || p8M == "candle";o$P.M8Y(106);X05=o$P.c6Y(p8M,"shadow");o$P.M8Y(106);F1P=o$P.d58(p8M,"hlc");B1Y=p8M == C_R || F1P;d7h=a7d.chart;p8t=d7h.dataSegment;A9R=this.chart.context;Q6K=new Array(p8t.length);a5j=this.layout;T$m=o3o && !l7f.isTransparent(o3o);c_V=0;if(T$m && !j6O.highlight){c_V=0.5;}X_j=A9R.globalAlpha;if(!j6O.highlight && this.highlightedDraggable){A9R.globalAlpha*=0.3;}o$P.C$o(22);var m2d=o$P.c6Y(1,0);a71=d7h.dataSet.length - d7h.scroll - m2d;o$P.J8h();A9R.beginPath();if(!z5z){z5z=a7d.yAxis;}f$q=z5z.top;O4f=z5z.bottom;z9a=a5j.candleWidth;o$P.M8Y(157);var t7c=o$P.c6Y(16,14,5,8);r_l=a7d.left - 0.5 * z9a + this.micropixels - t7c;o$P.M8Y(8);var m40=o$P.d58(4,0,2);z0H=d7h.tmpWidth / m40;o$P.M8Y(0);var o7t=o$P.c6Y(9,7);V_q=A9R.lineWidth / o7t;if(V9s){if(l7f.isTransparent(a0S)){a0S=this.containerColor;}A9R.fillStyle=a0S;}if(X05){o$P.M8Y(74);A9R.lineWidth=o$P.c6Y("1",0);}if(B1Y){P8R=this.canvasStyle(R$v);if(P8R.width && parseInt(P8R.width,10) <= +"25"){A9R.lineWidth=Math.max(1,l7f.stripPX(P8R.width));}else {A9R.lineWidth=1;}}W_6=d7h.state.chartType.pass;for(var P1M=0;P1M <= p8t.length;P1M++){N8H=z0H;o$P.M8Y(40);r_l+=o$P.d58(2,z9a);z9a=a5j.candleWidth;o$P.M8Y(40);r_l+=o$P.c6Y(2,z9a);j1n=p8t[P1M];if(!j1n)continue;if(j1n.projection)continue;if(j1n.candleWidth){o$P.C$o(158);var L37=o$P.d58(7,17,136,16,3);r_l+=(j1n.candleWidth - z9a) / L37;z9a=j1n.candleWidth;if(j6O.volume || z9a < d7h.tmpWidth){o$P.M8Y(40);N8H=o$P.c6Y(2,z9a);}}if(d7h.transformFunc && z5z == d7h.panel.yAxis && j1n.transform){j1n=j1n.transform;}if(j1n && x40 && x40 != "Close"){j1n=j1n[x40];}if(!j1n && j1n !== "0" << 64)continue;e56=j1n.Close;v0Q=j1n.Open === undefined?e56:j1n.Open;if(X8t && d7h.defaultPlotField){e56=j1n[d7h.defaultPlotField];}if(!e56 && e56 !== "0" * 1)continue;if(V9s && !X8t && (v0Q == e56 || v0Q === null))continue;if(o5a){n22=l7f.ChartEngine;if(o5a & n22.CLOSEDOWN){W_6.even|=e56 == j1n.iqPrevClose;}else if(o5a & n22.CANDLEDOWN){o$P.C$o(106);W_6.even|=o$P.d58(e56,v0Q);}if(o5a & n22.CANDLEUP && v0Q >= e56)continue;if(o5a & n22.CANDLEDOWN && v0Q <= e56)continue;if(o5a & n22.CANDLEEVEN && v0Q != e56)continue;if(o5a & n22.CLOSEUP && e56 <= j1n.iqPrevClose)continue;if(o5a & n22.CLOSEDOWN && e56 >= j1n.iqPrevClose)continue;if(o5a & n22.CLOSEEVEN && e56 != j1n.iqPrevClose)continue;}o$P.M8Y(22);a7X=o$P.c6Y(P1M,a71);v9g=v0Q;e0J=e56;if(X05 || B1Y){v9g=j1n.High === undefined?Math.max(e56,v0Q):j1n.High;e0J=j1n.Low === undefined?Math.min(e56,v0Q):j1n.Low;}d_L=z5z.semiLog?z5z.height * (1 - (Math.log(Math.max(v9g,+"0")) / Math.LN10 - z5z.logLow) / z5z.logShadow):(z5z.high - v9g) * z5z.multiplier;i4v=z5z.semiLog?z5z.height * (1 - (Math.log(Math.max(e0J,"0" - 0)) / Math.LN10 - z5z.logLow) / z5z.logShadow):(z5z.high - e0J) * z5z.multiplier;if(z5z.flipped){o$P.C$o(0);d_L=o$P.d58(O4f,d_L);o$P.M8Y(0);i4v=o$P.d58(O4f,i4v);}else {d_L+=f$q;i4v+=f$q;}x$C=Math.floor(X8t?z5z.flipped?z5z.top:i4v:Math.min(d_L,i4v)) + c_V;M$0=X8t?z5z.flipped?d_L:z5z.bottom:Math.max(d_L,i4v);o$P.C$o(0);I4L=Math.floor(o$P.d58(M$0,x$C));K31=i4v;if(B1Y || X05){v$t=z5z.semiLog?z5z.height * (1 - (Math.log(Math.max(v0Q,0)) / Math.LN10 - z5z.logLow) / z5z.logShadow):(z5z.high - v0Q) * z5z.multiplier;f4W=z5z.semiLog?z5z.height * (1 - (Math.log(Math.max(e56,0)) / Math.LN10 - z5z.logLow) / z5z.logShadow):(z5z.high - e56) * z5z.multiplier;if(z5z.flipped){o$P.M8Y(0);v$t=o$P.d58(O4f,v$t);o$P.C$o(0);f4W=o$P.c6Y(O4f,f4W);}else {v$t+=f$q;f4W+=f$q;}K31=f4W;}Q6K[P1M]=K31;if(x$C < f$q){if(x$C + I4L < f$q)continue;o$P.M8Y(0);I4L-=o$P.c6Y(f$q,x$C);x$C=f$q;}if(x$C + I4L > O4f){o$P.M8Y(25);I4L-=o$P.c6Y(x$C,O4f,I4L);}o$P.C$o(22);M$0=o$P.d58(I4L,x$C);if(x$C >= O4f)continue;if(M$0 <= f$q)continue;G4U=Math.floor(r_l) + (!j6O.highlight && 0.5);U9e=Math.floor(G4U - N8H) + c_V;U$K=Math.round(G4U + N8H) - c_V;i7j=U9e == U$K?N8H:+"0";if(I4L < 2){I4L=2;}if(V9s){if(X8t || e56 != v0Q){A9R.rect(U9e,x$C,Math.max(1,U$K - U9e),I4L);}}else if(X05){if(e56 == v0Q){if(f4W <= O4f && f4W >= f$q){A$9=Math.floor(f4W) + (!j6O.highlight && 0.5);o$P.M8Y(0);A9R.moveTo(o$P.c6Y(U9e,i7j),A$9);o$P.C$o(22);A9R.lineTo(o$P.c6Y(i7j,U$K),A$9);}}if(v9g != e0J){A9R.moveTo(G4U,x$C);A9R.lineTo(G4U,M$0);}}else if(B1Y){if(x$C < O4f && M$0 > f$q && j1n.High != j1n.Low){o$P.C$o(0);A9R.moveTo(G4U,o$P.d58(x$C,V_q));o$P.M8Y(22);A9R.lineTo(G4U,o$P.d58(V_q,M$0));}if(v$t > f$q && v$t < O4f && !F1P){o$O=Math.floor(v$t) + (!j6O.highlight && 0.5);A9R.moveTo(G4U,o$O);o$P.M8Y(30);A9R.lineTo(o$P.d58(N8H,G4U,i7j),o$O);}if(f4W > f$q && f4W < O4f){J2v=Math.floor(f4W) + (!j6O.highlight && 0.5);A9R.moveTo(G4U,J2v);o$P.M8Y(53);A9R.lineTo(o$P.c6Y(G4U,N8H,i7j),J2v);}}}K0_=A9R.globalAlpha;if(V9s){if(K0_ < 1){A9R.save();A9R.globalAlpha=1;A9R.fillStyle=this.containerColor;A9R.fill();A9R.restore();}A9R.fill();if(T$m){A9R.lineWidth=j6O.highlight?2:1;A9R.strokeStyle=o3o;A9R.stroke();}}else if(X05 || B1Y){this.canvasColor(R$v);A9R.globalAlpha=K0_;if(o3o){A9R.strokeStyle=o3o;}if(j6O.highlight){A9R.lineWidth*=2;}A9R.stroke();A9R.closePath();A9R.lineWidth=1;}A9R.globalAlpha=X_j;return {cache:Q6K};};l7f.ChartEngine.prototype.plotDataSegmentAsLine=function(F38,a$d,f3h,T9s){var J2n=x2dci;var L4T,O4p,L1c,F8X,P$G,L6M,e9T,t7C,t4M,q$5,I2X,u3g,d$n,d_R,Z4v,A3C,B_V,K2v,b3B,s24,P0P,r5X,n23,x9w,j9G,h3i,A6W,p54,D$s,X6c,w5v,x3c,Z3m,x2J,R2i,c0s,T1f,c64,A40,h6w,g6F,v3a,f$Y,L1k,M8e,a$g,Y2V,u5O,X89,R78,u1n,e$C,q7q,U84,n3B,E1J,g7G,t4p,I4W,k$l,V6q,I5S,f0U,o2H,s8L,n_f,L2M,G1d,l0w,d1g,l3k,B3s,n7b,x3l,o11,S0b,r66,j8I,b6P,I0N,K97,b2W,U1b,O45,J_G,S8P,K5l,q1j,K0l,N54,D15,l06,h4a,A$A,t4b,i2V,b6G,s0o,z0C;L4T=!"1";O4p=!({});L1c=!"1";F8X=!"1";P$G=!0;L6M=null;e9T=null;t7C=null;t4M=0;q$5=!({});I2X=!!0;u3g=![];d$n=!"1";d_R=null;Z4v=null;A3C=null;B_V=null;function H2u(u0h,A4G,z$2){var X4z,C$p,T_c,p1J;X4z="C";X4z+="ollat";X4z+="edHigh";A6W.setLineDash([]);C$p=Y1S("CollatedOpen");T_c=Y1S(X4z);p1J=Y1S("CollatedLow");J2n.J8h();A6W.lineTo(u0h,C$p);A6W.moveTo(u0h,T_c);A6W.lineTo(u0h,p1J);A6W.moveTo(u0h,A4G);b3B.push(u0h,C$p);function Y1S(k42){var u6S;u6S=t7C.semiLog?t7C.height * (+"1" - (Math.log(Math.max(z$2[k42],0)) / Math.LN10 - t7C.logLow) / t7C.logShadow):(t7C.high - z$2[k42]) * t7C.multiplier;if(t7C.flipped){u6S=t7C.bottom - u6S;}else {u6S+=t7C.top;}return u6S;}}K2v={};b3B=[];s24=[];P0P=[];r5X=[];n23=this;x9w=this.layout;j9G=a$d.chart;h3i=j9G.dataSegment;A6W=j9G.context;p54=new Array(h3i.length);D$s=A6W.strokeStyle;X6c=A6W.globalAlpha;if(j9G.dataSet.length){this.startClip(a$d.name);if(f3h){L4T=f3h.skipProjections;O4p=f3h.skipTransform;L1c=f3h.noSlopes;t4M=f3h.tension;F8X=f3h.step;e9T=f3h.pattern;P$G=f3h.extendOffChart;t7C=f3h.yAxis;L6M=f3h.gapDisplayStyle;q$5=f3h.noDraw;I2X=f3h.reverse;u3g=f3h.highlight;if(f3h.width){A6W.lineWidth=f3h.width;}d$n=f3h.shiftRight;d_R=f3h.subField;Z4v=f3h.threshold;A3C=f3h.lineTravelSpacing;B_V=f3h.extendToEndOfDataSet;}if(!L6M && L6M !== ![] && f3h){L6M=f3h.gaps;}if(!L6M){L6M={color:"transparent",fillMountain:!!1};}if(e9T instanceof Array){A6W.setLineDash(e9T);}if(u3g){A6W.lineWidth*=+"2";}if(!u3g && this.highlightedDraggable){A6W.globalAlpha*=0.3;}if(P$G !== ![]){P$G=!"";}w5v=d_R || j9G.defaultPlotField || "Close";if(!t7C){t7C=a$d.yAxis;}x3c=j9G.transformFunc && t7C == j9G.panel.yAxis;J2n.M8Y(84);var D$J=J2n.d58(343,61,20,7);Z3m=A6W.lineWidth * ("2" << D$J);x2J=I2X?j9G.top - Z3m:j9G.bottom + Z3m;if(Z4v || Z4v === +"0"){x2J=this.pixelFromPrice(Z4v,a$d,t7C);}R2i=!t4M && q$5 && L6M && L6M.fillMountain;c0s=F38;T1f=F38;for(var i_P=0;i_P < h3i.length;i_P++){c64="o";c64+="bj";c64+="ect";A40=h3i[i_P];if(A40 && typeof A40 == c64){if(A40[F38] || A40[F38] === 0){h6w="o";h6w+="bj";h6w+="ec";h6w+="t";if(typeof A40[F38] == h6w){T1f=l7f.createObjectChainNames(F38,[w5v])[J2n.d58("0",0,J2n.M8Y(0))];}break;}}}g6F={left:null,right:null};J2n.M8Y(111);var y3t=J2n.d58(18,0,36,17);v3a=j9G.dataSet.length - j9G.scroll - y3t;if(P$G){g6F.left=this.getPreviousBar(j9G,T1f,0);g6F.right=this.getNextBar(j9G,T1f,h3i.length - ("1" | 0));}f$Y=!!({});L1k=!!"";A6W.beginPath();Y2V=g6F.left;u5O=null;if(Y2V){u5O=Y2V.transform;}if(Y2V){a$g=x3c?u5O?u5O[F38]:null:Y2V[F38];if(a$g || a$g === ("0" | 0)){if(a$g[w5v] || a$g[w5v] === 0){a$g=a$g[w5v];}X89=this.pixelFromTick(Y2V.tick,j9G);R78=this.pixelFromTransformedValue(a$g,a$d,t7C);A6W.moveTo(X89,R78);b3B.push(X89,R78);if(h3i[0].tick - Y2V.tick > 1){P0P.push({start:b3B.slice(-2),threshold:x2J,tick:Y2V});L1k=!!1;}f$Y=![];}}u1n=a$d.left + this.micropixels - +"1";if(d$n){u1n+=d$n;}if(F8X && f3h && f3h.alignStepToSide){J2n.C$o(3);var Q8M=J2n.c6Y(35,5,14,18);u1n-=this.layout.candleWidth / Q8M;}U84=this.currentQuote();n3B=0;E1J=0;g7G=!({});t4p={reset:!!"1"};for(var l4N=0;l4N < h3i.length;l4N++){I4W="o";I4W+="bject";M8e=x9w.candleWidth;k$l=h3i[l4N];V6q=h3i[l4N];if(!k$l){k$l={};}I5S=k$l.lineTravel;if(L4T && k$l.projection){g6F.right=null;break;}if(k$l.candleWidth){M8e=k$l.candleWidth;}if(A3C){M8e=0;}if(x3c && k$l.transform){k$l=k$l.transform;}f0U=k$l[F38];if(f0U && typeof f0U == I4W){f0U=f0U[w5v];J2n.M8Y(53);c0s=J2n.c6Y(F38,(7479,"4840" >> 64) <= 269.02?"Z":".",w5v);}if(j9G.lineApproximation && x9w.candleWidth < 1 && !A3C){if(t4p.reset){t4p={CollatedHigh:-Number.MAX_VALUE,CollatedLow:Number.MAX_VALUE,CollatedOpen:null,CollatedClose:null};g7G=!1;}o2H=f0U;if(o2H || o2H === 0){t4p.CollatedHigh=Math.max(t4p.CollatedHigh,o2H);t4p.CollatedLow=Math.min(t4p.CollatedLow,o2H);t4p.CollatedClose=o2H;if(t4p.CollatedOpen === null){t4p.CollatedOpen=o2H;}else {g7G=!!"1";}}n3B+=M8e;if(n3B - E1J >= 1 || l4N == h3i.length - 1){E1J=Math.floor(n3B);t4p.reset=!!({});t4p[F38]=t4p.CollatedClose;k$l=t4p;k$l.cache={};}else {u1n+=M8e;continue;}}if(!L1c){J2n.C$o(40);u1n+=J2n.c6Y(2,M8e);}if(!f0U && f0U !== 0){s8L=b3B.slice(-2);if(R2i && !L1k && b3B.length){b3B.push(s8L["0" ^ 0],x2J);}if(!L1k){P0P.push({start:s8L,threshold:x2J,tick:q7q});}L1k=!"";u1n+=L1c?M8e:M8e / 2;if((F8X || L1c) && b3B.length){p54[l4N]=b3B.slice(-1)[0];}if(I5S){u1n+=I5S;}continue;}e$C=k$l;n_f=k$l.cache;J2n.C$o(22);L2M=J2n.c6Y(l4N,v3a);if(L2M < a$d.cacheLeft || L2M > a$d.cacheRight || !n_f[F38]){n_f[c0s]=t7C.semiLog?t7C.height * (("1" | 0) - (Math.log(Math.max(f0U,0)) / Math.LN10 - t7C.logLow) / t7C.logShadow):(t7C.high - f0U) * t7C.multiplier;if(t7C.flipped){n_f[c0s]=t7C.bottom - n_f[c0s];}else {n_f[c0s]+=t7C.top;}}G1d=p54[l4N]=n_f[c0s];if(V6q.tick == U84.tick && j9G.lastTickOffset){u1n+=j9G.lastTickOffset;}l0w=b3B.slice(-2);if(!f$Y && T9s){if(V6q[F38] && V6q[F38][w5v]){V6q=V6q[F38];}d1g=T9s(this,V6q,L1k);if(!d1g){u1n+=L1c?M8e:M8e / 2;continue;}l0w=r4a(d1g);}if(f$Y){A6W.moveTo(u1n,G1d);if(t4M){s24.push({coord:[u1n,G1d],color:A6W.strokeStyle,pattern:e9T?e9T:[],width:A6W.lineWidth});}}else {if(F8X || L1c){l3k=b3B.slice(-1)[0];if(g7G){H2u(u1n,l3k,k$l);}else {A6W.lineTo(u1n,l3k);}b3B.push(u1n,l3k);}if(g7G && !L1c){H2u(u1n,G1d,k$l);}else {A6W[L1c?"moveTo":"lineTo"](u1n,G1d);}}if(L1k){P0P.push({end:[u1n,G1d],threshold:x2J});q7q=V6q;if(R2i && !F8X && !L1c){b3B.push(u1n,x2J);}}b3B.push(u1n,G1d);f$Y=!!0;L1k=!"1";u1n+=L1c?M8e:M8e / 2;if(I5S){u1n+=I5S;};}B3s=g6F.right;n7b=null;if(B3s){n7b=B3s.transform;}if(!f$Y && B3s){a$g=x3c?n7b?n7b[F38]:null:B3s[F38];if(a$g && (a$g[w5v] || a$g[w5v] === 0)){a$g=a$g[w5v];}x3l=this.pixelFromTick(B3s.tick,j9G);o11=this.pixelFromTransformedValue(a$g,a$d,t7C);if(B3s.tick - h3i[h3i.length - 1].tick > 1){if(!L1k){S0b=b3B.slice(-2);if(R2i && b3B.length){b3B.push(S0b[0],x2J);}P0P.push({start:S0b,threshold:x2J,tick:h3i[h3i.length - 1]});}L1k=!!({});}if(!f$Y && T9s){r66=T9s(this,B3s,L1k);if(r66){j8I=r4a(r66);}}b6P=b3B.slice(-2);if(!e9T || !e9T.length){if(F8X || L1c){A6W.lineTo(x3l,b6P[1]);b3B.push(x3l,b6P[1]);}A6W[L1c?"moveTo":"lineTo"](x3l,o11);}if(L1k){P0P.push({end:[x3l,o11],threshold:x2J});if(R2i && !F8X && !L1c){b3B.push(x3l,x2J);}}b3B.push(x3l,o11);}for(var q7I in K2v){r5X.push(q7I);}if(f3h && f3h.extendToEndOfLastBar){I0N=b3B.slice(-2);A6W.lineTo(I0N[0] + M8e,I0N[1]);}else if(F8X || L1c || this.extendLastTick || B_V){K97=b3B.slice(-2);if(b3B.length){J2n.C$o(19);b2W=K97[J2n.c6Y(32,"0")];U1b=K97[1];if(B_V || F8X && B_V !== ![]){b2W=this.pixelFromTick(j9G.dataSet.length - +"1",j9G);if(L1c || this.extendLastTick){J2n.C$o(40);b2W+=J2n.c6Y(2,M8e);}}else if(L1c){b2W+=M8e;}else if(this.extendLastTick){J2n.C$o(40);b2W+=J2n.c6Y(2,M8e);}if(b2W > K97[0]){O45=null;if(T9s){O45=T9s(this,{},!!1);}if(O45){r4a(O45);}A6W.lineTo(b2W,U1b);if(!L1k || !R2i){b3B.push(b2W,U1b);}}}}if(!q$5){if(t4M && b3B.length){A6W.beginPath();if(f3h && f3h.pattern){A6W.setLineDash(f3h.pattern);}Y68.plotSpline(b3B,t4M,A6W,s24);}A6W.stroke();}this.endClip();if(!q$5 && f3h && f3h.label && e$C){J_G="noo";J_G+="p";K5l=e$C[F38];if(K5l && typeof K5l == "object"){K5l=K5l[w5v];}if(t7C.priceFormatter){S8P=t7C.priceFormatter(this,a$d,K5l,f3h.labelDecimalPlaces);}else {S8P=this.formatYAxisPrice(K5l,a$d,f3h.labelDecimalPlaces);}q1j=this.yaxisLabelStyle;if(t7C.yaxisLabelStyle){q1j=t7C.yaxisLabelStyle;}K0l=q1j == J_G?A6W.strokeStyle:null;N54=q1j == "noop"?"#FFFFFF":A6W.strokeStyle;this.yAxisLabels.push({src:"plot",args:[a$d,S8P,e$C.cache[c0s],N54,K0l,A6W,t7C]});}D15=typeof L6M == "object"?L6M.color:L6M;if(l7f.isTransparent(D15)){for(var I3$=0;I3$ < P0P.length;I3$+=2){l06=P0P[I3$].start;if(I3$){h4a=P0P[I3$ - 1].end;}if(h4a && l06["0" << 0] == h4a[0] && l06[1] == h4a[1]){A6W.beginPath();A$A=A6W.lineWidth;if(T9s){t4b="o";t4b+="bj";t4b+="ec";t4b+="t";i2V=T9s(this,P0P[I3$].tick || ({}),!!0);if(typeof i2V == t4b){J2n.C$o(89);var w1w=J2n.c6Y(1,15,4,21);J2n.C$o(159);var y10=J2n.d58(18,1,17,6,13);A$A=i2V.width * (u3g?w1w:y10);i2V=i2V.color;}A6W.strokeStyle=A6W.fillStyle=i2V;}A6W.lineWidth=A$A;A6W.arc(l06[0],l06[1],1,0,2 * Math.PI);A6W.stroke();A6W.fill();}}}}b6G=-43739053;J2n.C$o(38);s0o=-J2n.d58("1106869118",1);z0C=+"2";for(var n0N=1;J2n.O$R(n0N.toString(),n0N.toString().length,51349) !== b6G;n0N++){A6W.globalAlpha=X6c;z0C+=2;}if(J2n.O$R(z0C.toString(),z0C.toString().length,"20664" << 32) !== s0o){A6W.globalAlpha=X6c;}function r4a(V$l){var R8l,I9Y,c1r,Z4I,C$b,O7E,Z$2,f1U,S0m;R8l=A6W.getLineDash();I9Y=1;c1r=V$l;if(typeof c1r == "object"){J2n.C$o(124);var Z4S=J2n.c6Y(0,6,13,17);J2n.C$o(22);var M7n=J2n.c6Y(1,0);I9Y=c1r.width * (u3g?Z4S:M7n);e9T=l7f.borderPatternToArray(I9Y,c1r.pattern);c1r=c1r.color;}K2v[c1r]=1;if(q$5){return;}Z4I=b3B.slice(-2);C$b=e9T instanceof Array && e9T.join();O7E=R8l instanceof Array && R8l.join();J2n.M8Y(160);Z$2=J2n.c6Y(O7E,C$b);f1U=!l7f.colorsEqual(D$s,c1r);S0m=A6W.lineWidth != I9Y;if(f1U || Z$2 || S0m){if(t4M){s24.push({coord:Z4I,color:c1r,pattern:e9T?e9T:[],width:I9Y});}else {A6W.stroke();A6W.lineWidth=I9Y;if(Z$2){A6W.setLineDash(C$b?e9T:[]);}A6W.beginPath();A6W.moveTo(Z4I[0],Z4I[1]);;}}D$s=c1r;if(!t4M){if(!c1r || c1r == "auto"){A6W.strokeStyle=n23.defaultColor;}else {A6W.strokeStyle=c1r;}}J2n.r2m();return Z4I;}return {colors:r5X,points:b3B,cache:p54,gapAreas:P0P};};l7f.ChartEngine.prototype.drawMountainChart=function(s4M,O$t,m1I){var Q6W=x2dci;var n16,z_l,M8k,k0Q,K8n,j5b,A3f,S9A,H7m,o35,w0v,x_f,c8r,T$s,P2t,V45,p$R,J54,v$L,U0L,i8u,T2f,F35,v4P,h5N,v3L,U4F,g3c,o1M,H4W,o$T,n5D,B4X,C0$,x6r,I84,s8c,F4Z,t5Z;n16="t";n16+="ransparent";z_l="C";z_l+="l";z_l+="os";z_l+="e";M8k="obje";M8k+="ct";k0Q=this.chart.context;K8n=O$t;j5b=!({});A3f=!!0;S9A=null;H7m=null;o35=null;w0v=null;x_f=0;c8r=null;T$s=!"1";P2t=null;V45=null;p$R=!1;J54=null;v$L=null;U0L=1;i8u=!({});T2f=!({});F35=!"1";v4P=s4M.chart;h5N=v4P.dataSegment;v3L=v4P.lineStyle || ({});if(!O$t || typeof O$t != M8k){O$t={style:O$t};}K8n=O$t.style || "stx_mountain_chart";S9A=O$t.field || v4P.defaultPlotField || z_l;H7m=O$t.subField || v4P.defaultPlotField || "Close";c8r=O$t.gapDisplayStyle;if(!c8r && c8r !== !({})){c8r=O$t.gaps;}if(!c8r && c8r !== ![]){c8r=v4P.gaplines;}if(!c8r){c8r=n16;}o35=O$t.yAxis || s4M.yAxis;j5b=O$t.reverse || !1;w0v=O$t.tension;P2t=O$t.fillStyle;x_f=O$t.width || v3L.width;T$s=O$t.step;V45=O$t.pattern || v3L.pattern;p$R=O$t.highlight;v$L=O$t.color || v3L.color;J54=O$t.baseColor || v3L.baseColor;A3f=O$t.colored;U0L=O$t.opacity;i8u=O$t.extendToEndOfDataSet;T2f=O$t.isComparison;F35=O$t.returnObject;U4F=this.canvasStyle(K8n);g3c=o35.top;if(isNaN(g3c) || isNaN(g3c / g3c)){Q6W.C$o(74);g3c=Q6W.c6Y("0",0);}o1M=v$L || (K8n && U4F.backgroundColor?U4F.backgroundColor:this.defaultColor);H4W=J54 || (K8n && U4F.color?U4F.color:this.containerColor);if(P2t){k0Q.fillStyle=P2t;}else if(J54 || U4F.color){o$T=k0Q.createLinearGradient(0,g3c,+"0",o35.bottom);o$T.addColorStop(o35.flipped?1:0,o1M);o$T.addColorStop(o35.flipped?0:1,H4W);k0Q.fillStyle=o$T;}else {k0Q.fillStyle=o1M;}this.startClip(s4M.name);n5D=k0Q.lineWidth;if(!O$t.symbol){H7m=null;}O$t={skipProjections:!![],reverse:j5b,yAxis:o35,gapDisplayStyle:c8r,step:T$s,highlight:p$R,extendToEndOfDataSet:i8u,isComparison:T2f};if(v4P.tension){O$t.tension=v4P.tension;}if(w0v || w0v === 0){O$t.tension=w0v;}B4X=parseInt(U4F.paddingTop,10);C0$=v$L || U4F.borderTopColor;x6r=null;if(A3f || C0$ && !l7f.isTransparent(C0$)){if(B4X){I84=this.scratchContext;if(!I84){s8c=k0Q.canvas.cloneNode(!!({}));I84=this.scratchContext=s8c.getContext("2d");}I84.canvas.height=k0Q.canvas.height;I84.canvas.width=k0Q.canvas.width;I84.drawImage(k0Q.canvas,0,0);l7f.clearCanvas(k0Q.canvas,this);}}l7f.extend(O$t,{panelName:s4M.name,direction:O$t.reverse?-1:1,band:S9A,subField:H7m,opacity:U0L});if(!O$t.highlight && this.highlightedDraggable){O$t.opacity*=0.3;}l7f.preparePeakValleyFill(this,O$t);if(A3f || C0$ && !l7f.isTransparent(C0$)){if(B4X){F4Z="destination-ov";F4Z+="er";k0Q.save();Q6W.C$o(161);k0Q.lineWidth+=Q6W.d58(B4X,"2",1);k0Q.globalCompositeOperation="destination-out";k0Q.globalAlpha=1;this.plotDataSegmentAsLine(S9A,s4M,O$t);k0Q.globalCompositeOperation=F4Z;k0Q.scale(1 / this.adjustedDisplayPixelRatio,("1" << 96) / this.adjustedDisplayPixelRatio);k0Q.drawImage(this.scratchContext.canvas,+"0",0);k0Q.restore();}}k0Q.strokeStyle=C0$;if(x_f){k0Q.lineWidth=x_f;}else if(U4F.width && parseInt(U4F.width,10) <= 25){k0Q.lineWidth=Math.max(+"1",l7f.stripPX(U4F.width));}else {k0Q.lineWidth=1;}if(!V45){V45=U4F.borderTopStyle;}O$t.pattern=l7f.borderPatternToArray(k0Q.lineWidth,V45);t5Z=m1I;if(c8r){t5Z=this.getGapColorFunction(S9A,H7m,{color:C0$,pattern:O$t.pattern,width:k0Q.lineWidth},c8r,m1I);}x6r=this.plotDataSegmentAsLine(S9A,s4M,O$t,t5Z);k0Q.lineWidth=n5D;this.endClip();if(!x6r.colors.length){x6r.colors.push(C0$);}return F35?x6r:x6r.colors;};l7f.ChartEngine.prototype.drawBaselineChart=function(n3W,M0e){var o$d,N6H,N_4,n4L,f1p,c8w,P7X,t6n,y8D,w0$,O3s,s5D,U5R,K8m,F6e,Q6T,V6n,q5y,i4F,T79,O6x,A_j,I9E,n3Q,j5s,x8t,r3M,j0y,A7$,X4D,s2K,W$t;var {chart:g5B}=n3W;var {field:Q3o, id:q_9, yAxis:l7m}=M0e;var {gaplines:g07, defaultPlotField:D_i, lineStyle:q8_}=g5B;var {display:b_j}=this.baselineHelper.get(this.getRendererFromSeries(q_9));o$d=this.getYAxisBaseline(l7m).actualLevel;N6H=[];if(!Q3o){Q3o=D_i;}if(!q8_){q8_={};}N_4=M0e.gapDisplayStyle;x2dci.J8h();if(!N_4 && N_4 !== !({})){N_4=M0e.gaps;}if(o$d !== null && !isNaN(o$d)){n4L="s";n4L+="tx_baselin";n4L+="e_down";f1p="stx_b";f1p+="aseline_down";c8w="m";c8w+="ou";c8w+="nta";c8w+="in";P7X=M0e.type == c8w;if(P7X){N6H=this.drawMountainChart(n3W,{style:M0e.style,field:M0e.field,yAxis:l7m,gapDisplayStyle:N_4,colored:!![],tension:0});}t6n=this.pixelFromPrice(o$d,n3W,l7m);if(isNaN(t6n)){return;}this.startClip(n3W.name);y8D=M0e.pattern || q8_.pattern;w0$=M0e.fill_color_up || this.getCanvasColor("stx_baseline_up");O3s=M0e.fill_color_down || this.getCanvasColor("stx_baseline_down");s5D=M0e.border_color_up || this.getCanvasColor("stx_baseline_up");U5R=M0e.border_color_down || this.getCanvasColor(f1p);K8m=M0e.width || q8_.width || this.canvasStyle("stx_baseline_up").width;F6e=M0e.width || q8_.width || this.canvasStyle(n4L).width;Q6T=M0e.widthBaseline || q8_.width || l7f.stripPX(this.canvasStyle("stx_baseline").width);V6n=M0e.baselineOpacity || this.canvasStyle("stx_baseline").opacity;q5y={fill:w0$,edge:s5D,width:K8m};i4F={fill:O3s,edge:U5R,width:F6e};T79=M0e.yAxis.flipped;O6x={over:T79?i4F:q5y,under:T79?q5y:i4F};A_j=!"1";if(!N_4 && N_4 !== !({})){N_4=g07;}I9E=1;if(!M0e.highlight && this.highlightedDraggable){I9E*=0.3;}for(var j7T in O6x){n3Q="tra";n3Q+="n";n3Q+="spa";n3Q+="rent";j5s=parseInt(Math.max(1,l7f.stripPX(O6x[j7T].width)),10);if(M0e.highlight){j5s*=2;}y8D=l7f.borderPatternToArray(j5s,y8D);x8t={panelName:n3W.name,band:Q3o,threshold:o$d,color:P7X?n3Q:O6x[j7T].fill,direction:j7T == "over"?1:-("1" * 1),edgeHighlight:O6x[j7T].edge,edgeParameters:{pattern:y8D,lineWidth:j5s + 0.1,opacity:I9E},gapDisplayStyle:N_4,yAxis:M0e.yAxis};if(l7m){x8t.threshold=this.priceFromPixel(this.pixelFromPrice(x8t.threshold,n3W,l7m),n3W,l7m);}N6H.push(O6x[j7T].edge);r3M=x8t.color;if(!P7X && r3M && r3M != "transparent"){j0y=n3W.top;A7$=n3W.bottom;X4D=g5B.context.createLinearGradient(0,j7T == "over"?j0y:A7$,0,t6n);X4D.addColorStop(0,l7f.hexToRgba(l7f.colorToHex(r3M),60));X4D.addColorStop(+"1",l7f.hexToRgba(l7f.colorToHex(r3M),10));x8t.color=X4D;x8t.opacity=I9E;}l7f.preparePeakValleyFill(this,g5B.dataSegment,x8t);if(g07){if(!g07.fillMountain){this.drawLineChart(n3W,null,null,{color:"transparent",gapDisplayStyle:{color:this.containerColor,pattern:"solid",width:x8t.edgeParameters.lineWidth}});}if(!g07.color){A_j=!![];g07.color=this.defaultColor;}}this.drawLineChart(n3W,null,null,{color:"transparent",width:x8t.edgeParameters.lineWidth});if(A_j){g07.color=null;}}if(b_j){s2K="2.";s2K+="1";W$t="dott";W$t+="e";W$t+="d";this.plotLine(0,+"1",t6n,t6n,this.containerColor,"line",g5B.context,n3W,{lineWidth:"1.1"});this.plotLine(0,1,t6n,t6n,this.getCanvasColor("stx_baseline"),"line",g5B.context,n3W,{pattern:W$t,lineWidth:Q6T || s2K,opacity:V6n || 0.5 * I9E});}this.endClip();}return {colors:N6H};};l7f.ChartEngine.prototype.plotLine=function(I7X){var e5C=x2dci;var G$G,w5P,a41,n12,B5U,x3G,l5u,W96,u6K,W4v,B1M,T6H,O$m,l2L,c_y,w8E,T6c,e$2,R8z,G7A,L73,d8b,z0a,D8f,v1q,k3K,j1$,I9q,L$V,h_B,f$V,U87,A4m,E4C,P6z,Q9D,S0I,t6j;G$G="undefine";G$G+="d";w5P="numbe";w5P+="r";if(typeof arguments[0] == w5P){I7X={x0:arguments[0],x1:arguments[1],y0:arguments[2],y1:arguments[3],color:arguments[4],type:arguments[5],context:arguments[6],confineToPanel:arguments[+"7"]};for(var Q6i in arguments[8]){I7X[Q6i]=arguments[8][Q6i];}}if(!I7X){I7X={};}if(I7X.pattern == "none"){return;}a41=I7X.x0;n12=I7X.x1;B5U=I7X.y0;x3G=I7X.y1;l5u=I7X.color;W96=I7X.type;u6K=I7X.context;W4v=I7X.confineToPanel;B1M=I7X.deferStroke;if(W4v === !!({})){W4v=this.chart.panel;}if(u6K === null || typeof u6K == G$G){u6K=this.chart.context;}if(isNaN(a41) || isNaN(n12) || isNaN(B5U) || isNaN(x3G)){return;}T6H=0;O$m=this.chart.canvasHeight;l2L=0;c_y=this.right;if(W4v){O$m=W4v.yAxis.bottom;w8E=1832765480;T6c=-+"1049693747";e$2=2;for(var B8t=1;e5C.O$R(B8t.toString(),B8t.toString().length,50660) !== w8E;B8t++){T6H=W4v.yAxis.top;e$2+=2;}if(e5C.q2D(e$2.toString(),e$2.toString().length,+"23522") !== T6c){T6H=W4v.yAxis.top;}l2L=W4v.left;c_y=W4v.right;}if(W96 == "ray"){R8z=10000000;if(n12 < a41){R8z=-10000000;}L73={x0:a41,x1:n12,y0:B5U,y1:x3G};G7A=l7f.yIntersection(L73,R8z);n12=R8z;x3G=G7A;}if(W96 == "line" || W96 == "horizontal" || W96 == "vertical"){R8z=10000000;d8b=-10000000;L73={x0:a41,x1:n12,y0:B5U,y1:x3G};G7A=l7f.yIntersection(L73,R8z);z0a=l7f.yIntersection(L73,d8b);a41=d8b;n12=R8z;B5U=z0a;x3G=G7A;}e5C.M8Y(74);D8f=e5C.c6Y("0.0",0);e5C.M8Y(46);v1q=e5C.d58("1.0",32);e5C.M8Y(0);k3K=e5C.d58(n12,a41);e5C.M8Y(0);j1$=e5C.c6Y(x3G,B5U);for(var y3b=0;y3b < 4;y3b++){if(y3b === 0){I9q=-k3K;e5C.M8Y(0);L$V=-e5C.c6Y(l2L,a41);}if(y3b == 1){I9q=k3K;e5C.C$o(0);L$V=e5C.c6Y(c_y,a41);}if(y3b == 2){I9q=-j1$;e5C.M8Y(0);L$V=-e5C.d58(T6H,B5U);}if(y3b == "3" - 0){I9q=j1$;e5C.M8Y(0);L$V=e5C.c6Y(O$m,B5U);}e5C.C$o(40);h_B=e5C.c6Y(I9q,L$V);if((x3G || x3G === 0) && I9q === 0 && L$V < 0){return ![];;}if(I9q < 0){if(h_B > v1q){return !({});}else if(h_B > D8f){D8f=h_B;};}else if(I9q > 0){if(h_B < D8f){return ![];}else if(h_B < v1q){v1q=h_B;};}}e5C.C$o(147);f$V=e5C.d58(a41,D8f,k3K);e5C.C$o(147);U87=e5C.c6Y(B5U,D8f,j1$);e5C.M8Y(147);A4m=e5C.c6Y(a41,v1q,k3K);e5C.C$o(147);E4C=e5C.c6Y(B5U,v1q,j1$);if(!x3G && x3G !== 0 && !B5U && B5U !== 0){U87=T6H;E4C=O$m;f$V=L73.x0;A4m=L73.x0;if(L73.x0 > c_y){return !1;}if(L73.x0 < l2L){return !({});}}else if(!x3G && x3G !== "0" - 0){if(L73.y0 < L73.y1){E4C=O$m;}else {E4C=T6H;}f$V=L73.x0;A4m=L73.x0;if(L73.x0 > c_y){return !1;}if(L73.x0 < l2L){return !!0;}}if(!B1M){u6K.save();u6K.beginPath();}u6K.lineWidth=1.1;if(l5u && typeof l5u == "object"){u6K.strokeStyle=l5u.color;if(l5u.opacity){u6K.globalAlpha=l5u.opacity;}else {u6K.globalAlpha=1;}u6K.lineWidth=l7f.stripPX(l5u.width);}else {if(!l5u || l5u == "auto" || l7f.isTransparent(l5u)){P6z=-1042000019;Q9D=1879278794;S0I=2;for(var J$f=1;e5C.q2D(J$f.toString(),J$f.toString().length,42263) !== P6z;J$f++){u6K.strokeStyle=this.defaultColor;S0I+=2;}if(e5C.O$R(S0I.toString(),S0I.toString().length,95438) !== Q9D){u6K.strokeStyle=this.defaultColor;}u6K.strokeStyle=this.defaultColor;}else {u6K.strokeStyle=l5u;}}if(I7X.opacity){u6K.globalAlpha=I7X.opacity;}if(I7X.lineWidth){u6K.lineWidth=I7X.lineWidth;}if(I7X.globalCompositeOperation){u6K.globalCompositeOperation=I7X.globalCompositeOperation;}t6j=l7f.borderPatternToArray(u6K.lineWidth,I7X.pattern);u6K.setLineDash(I7X.pattern?t6j:[]);u6K.moveTo(f$V,U87);u6K.lineTo(A4m,E4C);if(!B1M){u6K.stroke();u6K.restore();}};l7f.ChartEngine.prototype.rendererAction=function(E44,E24){var d4M,U4Q,e48,Y0Y,X$H,v0M,H7q,K6h;function s2G(){var I$J,u_5;I$J="u";I$J+="n";I$J+="der";I$J+="lay";if(!d4M && E24 === I$J){u_5=Symbol.for("CIQ.watermark");if(this[u_5]){this[u_5].draw(E44);d4M=!![];}}}d4M=!!0;if(!this.runPrepend("rendererAction",arguments)){U4Q="rende";U4Q+="rerAction";for(var w9x in E44.seriesRenderers){e48="_";e48+="main_series";Y0Y="und";Y0Y+="er";Y0Y+="lay";X$H=E44.seriesRenderers[w9x];v0M=X$H.params;H7q=v0M.panel;K6h=this.panels[H7q];if(v0M.overChart && E24 == Y0Y)continue;if(v0M.name == "_main_series" && E24 == "underlay")continue;if(v0M.name != e48 && E24 == "main")continue;if(!v0M.overChart && E24 == "overlay")continue;if(!K6h)continue;if(K6h.chart !== E44)continue;if(K6h.hidden)continue;if(E24 == "yAxis"){X$H.adjustYAxis();}else {s2G.apply(this);X$H.draw();if(X$H.cb){X$H.cb(X$H.colors);}}}this.runAppend(U4Q,arguments);}s2G.apply(this);};l7f.ChartEngine.prototype.drawSeries=function(d$v,i5B,U7D,h0r){var D3Y,f2i,Y4b,R_l,g73,K$m,t0f,T25,H3v,g$k,q6X,L0u,N0z,g3R,v42,J2E,X6P;D3Y="drawSer";D3Y+="ies";if(this.runPrepend(D3Y,arguments)){return;}f2i=d$v.dataSegment;Y4b=null;if(!i5B){i5B=d$v.series;}for(var u$n in i5B){Y4b=i5B[u$n];R_l=Y4b.parameters;g73=R_l.panel?this.panels[R_l.panel]:d$v.panel;K$m=R_l.color;t0f=R_l.width;T25=R_l.field;if(!g73)continue;H3v=R_l.yAxis=U7D?U7D:g73.yAxis;if(!K$m){K$m=H3v.textStyle || this.defaultColor;}if(K$m == "auto"){K$m=this.defaultColor;}if(!T25){T25=d$v.defaultPlotField;}g$k=R_l.subField || d$v.defaultPlotField || "Close";if(!R_l._rawExtendToEndOfDataSet && R_l._rawExtendToEndOfDataSet !== ![]){R_l._rawExtendToEndOfDataSet=R_l.extendToEndOfDataSet;}if(d$v.animatingHorizontalScroll){R_l.extendToEndOfDataSet=!1;}else {R_l.extendToEndOfDataSet=R_l._rawExtendToEndOfDataSet;}q6X=R_l.colorFunction;if(Y4b.highlight || Y4b.parameters.highlight){R_l.highlight=!![];}L0u={colors:[]};if(h0r){if(h0r.params.highlight){R_l.highlight=!!({});}if(R_l.hidden)continue;L0u=h0r.drawIndividualSeries(d$v,R_l) || L0u;}else if(R_l.type == "mountain"){L0u=this.drawMountainChart(g73,l7f.extend({returnObject:!0},R_l),q6X);}else {L0u=this.drawLineChart(g73,R_l.style,q6X,l7f.extend({returnObject:!![]},R_l));}Y4b.yValueCache=L0u.cache;x2dci.C$o(25);var U7i=x2dci.d58(0,19,20);N0z=d$v.dataSegment[d$v.dataSegment.length - U7i];if(N0z){g3R=!R_l.skipTransform && d$v.transformFunc && H3v == d$v.panel.yAxis;if(!N0z[T25] && N0z[T25] !== 0){N0z=this.getPreviousBar(d$v,T25,d$v.dataSegment.length - 1);}if(g3R && N0z && N0z.transform){N0z=N0z.transform;}}if(R_l.displayFloatingLabel !== ![] && this.mainSeriesRenderer != h0r && N0z && !H3v.noDraw){v42=N0z[T25];if(v42){if(v42[g$k] || v42[g$k] === 0){v42=v42[g$k];}else {v42=v42.iqPrevClose;}}if(H3v.priceFormatter){J2E=H3v.priceFormatter(this,g73,v42);}else {J2E=this.formatYAxisPrice(v42,g73,null,H3v);}this.yAxisLabels.push({src:"series",args:[g73,J2E,this.pixelFromTransformedValue(v42,g73,H3v),l7f.hexToRgba(l7f.colorToHex(K$m),parseFloat(R_l.opacity)),null,null,H3v]});}if(d$v.legend && R_l.useChartLegend){if(!d$v.legend.colorMap){d$v.legend.colorMap={};}X6P=R_l.display;if(!X6P){X6P=R_l.symbol;}d$v.legend.colorMap[u$n]={color:L0u.colors,display:X6P,isBase:h0r == this.mainSeriesRenderer};;}}x2dci.r2m();this.runAppend("drawSeries",arguments);};};A1=y5U=>{var F7J;x2dci.J8h();F7J=y5U.CIQ;F7J.ChartEngine.prototype.scrollTo=function(w9i,y5I,D2r){var J7$,D1i;J7$=this.swipe;J7$.end=!![];J7$.amplitude=J7$.target=(y5I - w9i.scroll) * this.layout.candleWidth;J7$.timeConstant=100;J7$.timestamp=Date.now();x2dci.r2m();J7$.scroll=w9i.scroll;J7$.chart=w9i;J7$.cb=D2r;D1i=this;requestAnimationFrame(function(){D1i.autoscroll();});};F7J.ChartEngine.prototype.autoscroll=function(){var n9l,B7D,C2F,y4N;n9l=this;B7D=this.swipe;if(B7D.amplitude){B7D.elapsed=Date.now() - B7D.timestamp;C2F=-B7D.amplitude * Math.exp(-B7D.elapsed / B7D.timeConstant);y4N=(B7D.target + C2F) / this.layout.candleWidth;B7D.chart.scroll=B7D.scroll + Math.round(y4N);this.draw();this.updateChartAccessories();if(C2F > 0.5 || C2F < -0.5){requestAnimationFrame(function(){n9l.autoscroll();});}else {if(this.disableBackingStoreDuringTouch){this.reconstituteBackingStore();}if(B7D.cb){B7D.cb();}}}};};S4=j6S=>{var c8l=x2dci;var S0i;S0i=j6S.CIQ;S0i.ChartEngine.prototype.drawXAxis=function(K9a,l5I){var G0l,M7B,R4j,q$_,q86,Q4R,L1z,n_o,c3m,i_A,K8Z,P8w,o_G,w5u,a5o,q2u,D$d,g6u,u8$,A7h,g3M,X3m,v6n,J6b,n_G,x3z,w4U,t_$,Q4c,i$t;G0l="c";G0l+="e";G0l+="nte";G0l+="r";M7B="s";M7B+="t";M7B+="x_xaxi";M7B+="s";R4j="dr";R4j+="a";R4j+="wXAxis";q$_=[K9a,l5I];if(this.runPrepend(R4j,q$_)){return;}if(!l5I){return;}if(K9a.xAxis.noDraw){return;}q86=this.getBackgroundCanvas().context;this.canvasFont(M7B,q86);Q4R=this.getCanvasFontSize("stx_xaxis");q86.textAlign=G0l;q86.textBaseline="middle";n_o=q86.measureText(" ").width;for(var o2C=+"0";o2C < l5I.length;o2C++){L1z=l5I[o2C];c3m=q86.measureText(L1z.text).width;c8l.C$o(22);i_A=Math.max(c8l.d58(n_o,c3m),K9a.xAxis.minimumLabelWidth);L1z.hz=Math.floor(L1z.hz + this.micropixels) + ("0.5" - 0);c8l.M8Y(79);var L0y=c8l.c6Y(33,11,12,34);L1z.left=L1z.hz - i_A / L0y;c8l.C$o(11);var o5b=c8l.d58(1,8,4,15);L1z.right=L1z.hz + i_A / o5b;c8l.C$o(142);var V_B=c8l.c6Y(2,13,22,20,2);L1z.unpaddedRight=L1z.hz + c3m / V_B;}K8Z=this.xAxisAsFooter === !""?this.chart.canvasHeight:K9a.panel.bottom;c8l.M8Y(0);P8w=this.whichPanel(c8l.d58(K8Z,1));if(!P8w){return;}this.adjustYAxisHeightOffset(P8w,P8w.yAxis);o_G=K9a.xAxis.displayBorder || K9a.xAxis.displayBorder === null;if(this.axisBorders === !![]){o_G=!!1;}if(this.axisBorders === !({})){o_G=!1;}c8l.J8h();w5u=K8Z - this.xaxisHeight + Q4R;if(o_G){w5u+=3;}a5o=!"";for(var y8P in this.panels){q2u="b";q2u+="or";q2u+="de";q2u+="r";D$d="l";D$d+="ine";g6u=this.panels[y8P];if(g6u.hidden || g6u.shareChartXAxis === ![])continue;c8l.M8Y(106);u8$=c8l.d58(g6u,P8w);A7h=g6u.yAxis;if(!A7h)continue;g3M=-Number.MAX_VALUE;X3m=Number.MAX_VALUE;for(var c43=0;c43 < l5I.length;c43++){v6n="bound";v6n+="ary";if(l5I[c43].grid == v6n){X3m=l5I[c43].left;break;}}q86.save();q86.beginPath();q86.rect(g6u.left,g6u.top + (a5o?0:"1" >> 64),g6u.width,g6u.height - +"1");q86.clip();a5o=!({});J6b=new S0i.Plotter();J6b.newSeries(D$d,"stroke",this.canvasStyle("stx_grid"));J6b.newSeries("boundary","stroke",this.canvasStyle("stx_grid_dark"));J6b.newSeries(q2u,"stroke",this.canvasStyle("stx_grid_border"));for(var E_d="0" | 0;E_d < l5I.length;E_d++){L1z=l5I[E_d];if(E_d == c43){for(c43++;c43 < l5I.length;c43++){if(l5I[c43].grid == "boundary"){X3m=l5I[c43].left;break;}}if(c43 >= l5I.length){c43=-1;X3m=Number.MAX_VALUE;}}else {if(L1z.right > X3m)continue;}if(L1z.left < g3M)continue;if(L1z.left < 0){if(X3m < L1z.right)continue;if(c43 >= l5I.length){if(l5I[E_d + 1] && l5I[E_d + 1].left < L1z.right)continue;}}g3M=L1z.right;if(Math.floor(L1z.left) <= g6u.right){if(Math.floor(L1z.hz) > g6u.left){if(K9a.xAxis.displayGridLines){J6b.moveTo(L1z.grid,L1z.hz,A7h.top);J6b.lineTo(L1z.grid,L1z.hz,A7h.bottom);}if(u8$ && o_G){n_G="bor";n_G+="der";J6b.moveTo(n_G,L1z.hz,A7h.bottom + 0.5);J6b.lineTo("border",L1z.hz,A7h.bottom + +"6");}}if(u8$ && L1z.right > g6u.left){x3z="stx";x3z+="_xa";x3z+="xi";x3z+="s";w4U="s";w4U+="tx_xa";w4U+="xis_dark";this.canvasColor(L1z.grid == "boundary"?w4U:x3z,q86);q86.fillText(L1z.text,L1z.hz,w5u);}}}if(o_G){t_$="b";t_$+="o";t_$+="rde";t_$+="r";Q4c=Math.round(A7h.bottom) + 0.5;i$t=Math.round(g6u.right) + 0.5;J6b.moveTo("border",g6u.left,Q4c);J6b.lineTo(t_$,i$t,Q4c);}J6b.draw(q86);q86.restore();}q86.textAlign="left";this.runAppend("drawXAxis",q$_);};c8l.J8h();S0i.ChartEngine.prototype.createTickXAxisWithDates=function(N8k){var Z9I,k$V,C3d,Z52,Y93,t0u,j_P,E_y,j3o,W9z,n1t,c5i,z4U,r3i,R_d,V1L,t_o,D_c,R2m,e2x,m_S,G5f,h6x,V3I,H9C,o_o,q7A,G65,y$B,b45,d5W,X8s,l0a,g$3,f8_,W5F,D52,O5B,r6w,m56,Z4h,d2f,W5w,p5B,z5s,N9R,o8t,z7u,t3U,W1I,A6L,r67,O7X,z5m,O1Z,e8M,w5T,Y1Q,l2x,l$9,y8L,m3S,x2l,d29,c0C,D$l;Z9I="o";Z9I+="h";Z9I+="l";Z9I+="c";k$V="m";k$V+="inu";k$V+="te";C3d="s";C3d+="e";C3d+="c";c8l.r2m();C3d+="ond";if(!N8k){N8k=this.chart;}N8k.xaxis=[];Y93=N8k.context;t0u=[S0i.MILLISECOND,S0i.SECOND,S0i.MINUTE,S0i.HOUR,S0i.DAY,S0i.MONTH,S0i.YEAR];if(!this.timeIntervalMap){j_P="2";j_P+="0";j_P+="0";j_P+="0";E_y="10:";E_y+="00";E_y+=":";E_y+="00";j3o="10:00:0";j3o+="0.000";W9z=Y93.measureText.bind(Y93);Z52={};Z52[S0i.MILLISECOND]={arr:[1,"2" >> 64,+"5",10,20,50,100,250,500],minTimeUnit:0,maxTimeUnit:1000,measurement:W9z(j3o)};Z52[S0i.SECOND]={arr:[1,2,3,4,5,6,10,12,"15" - 0,+"20",30],minTimeUnit:0,maxTimeUnit:60,measurement:W9z(E_y)};Z52[S0i.MINUTE]={arr:[+"1",2,"3" >> 32,4,"5" | 5,6,10,12,+"15","20" * 1,30],minTimeUnit:0,maxTimeUnit:60,measurement:W9z("10:00")};Z52[S0i.HOUR]={arr:[+"1",2,3,4,6,12],minTimeUnit:"0" | 0,maxTimeUnit:"24" - 0,measurement:W9z("10:00")};Z52[S0i.DAY]={arr:[1,2,+"7",14],minTimeUnit:"1" << 32,maxTimeUnit:"32" << 32,measurement:W9z("30")};Z52[S0i.MONTH]={arr:[1,2,3,6],minTimeUnit:"1" >> 0,maxTimeUnit:"13" << 0,measurement:W9z("Mar")};Z52[S0i.YEAR]={arr:[+"1",2,+"3",5],minTimeUnit:1,maxTimeUnit:20000000,measurement:W9z(j_P)};Z52[S0i.DECADE]={arr:[10],minTimeUnit:0,maxTimeUnit:2000000,measurement:W9z("2000")};this.timeIntervalMap=Z52;}Z52=this.timeIntervalMap;c8l.C$o(0);n1t=[31,28,31,30,31,30,+"31",31,30,31,c8l.d58("30",0),+"31"];c5i=this.layout.periodicity;z4U=this.layout.interval;r3i=N8k.maxTicks;R_d=N8k.dataSegment;V1L=N8k.xAxis;t_o=R_d.length;D_c=V1L.idealTickSizePixels || V1L.autoComputedTickSizePixels;R2m=this.chart.width / D_c;for(var x74=0;x74 < t_o;x74++){if(R_d[x74])break;}if(x74 == t_o){return [];}c8l.M8Y(38);e2x=c8l.c6Y("0",1);m_S=this.layout.timeUnit || "minute";if(isNaN(z4U)){m_S=z4U;z4U=1;}G5f=0;switch(m_S){case "millisecond":G5f=1;break;case C3d:G5f=1000;c8l.C$o(19);t0u.splice(0,c8l.d58(96,"1"));break;case k$V:G5f=60000;t0u.splice(0,2);break;case "day":G5f=86400000;t0u.splice(0,4);break;case "week":c8l.C$o(38);G5f=c8l.c6Y(86400000,7);t0u.splice(0,4);break;case "month":c8l.M8Y(162);G5f=c8l.d58(0,"30",86400000);t0u.splice(0,5);break;}function S$r(P$O){var L7j,U4i;if(l0a == S0i.MILLISECOND){L7j=P$O.getMilliseconds();U4i=P$O.getSeconds();}else if(l0a == S0i.SECOND){L7j=P$O.getSeconds();U4i=P$O.getMinutes();}else if(l0a == S0i.MINUTE){L7j=P$O.getMinutes();U4i=P$O.getHours();}else if(l0a == S0i.HOUR){c8l.M8Y(22);var Z5u=c8l.d58(4,56);L7j=P$O.getHours() + P$O.getMinutes() / Z5u;U4i=P$O.getDate();}else if(l0a == S0i.DAY){L7j=P$O.getDate();c8l.C$o(2);var Q_4=c8l.c6Y(4,3);U4i=P$O.getMonth() + Q_4;}else if(l0a == S0i.MONTH){c8l.M8Y(16);var A$k=c8l.c6Y(8,0,11,87);L7j=P$O.getMonth() + A$k;U4i=P$O.getFullYear();}else if(l0a == S0i.YEAR){L7j=P$O.getFullYear();c8l.M8Y(163);var G0Q=c8l.c6Y(14,56,4,991,9);U4i=P$O.getFullYear() + G0Q;}else {L7j=P$O.getFullYear();U4i=0;}return [L7j,U4i];}h6x=this.layout.aggregationType;if(G5f && (!h6x || h6x == Z9I || h6x == "heikinashi")){c8l.C$o(73);e2x=c8l.d58(G5f,z4U,c5i,t_o);;}else {e2x=R_d[t_o - 1].DT.getTime() - R_d[x74].DT.getTime();;}if(e2x === 0){if(N8k.market){V3I=N8k.market.newIterator({begin:new Date(),interval:"day",periodicity:1});V3I.next();H9C=V3I.previous();V3I=this.standardMarketIterator(H9C,null,N8k);o_o=V3I.next();e2x=(o_o.getTime() - H9C.getTime()) * r3i;;}else {c8l.C$o(164);e2x=c8l.c6Y(60,"1000",r3i,24,60);;}}else {c8l.M8Y(165);e2x=c8l.c6Y(t_o,e2x,r3i);;}c8l.M8Y(40);q7A=c8l.d58(R2m,e2x);for(G65=0;G65 < t0u.length;G65++){if(t0u[G65] > q7A + "0.001" * 1)break;;}if(q7A < 1){y$B="createTickXAxisWithDates: Assertion";y$B+=" error. msPerGridLine < 1. Make sure your masterData has correct time stamps for the active periodi";y$B+="city and it is s";y$B+="orted from OLDEST to NEWEST.";console.log(y$B);}if(G65 == t0u.length){G65--;}else if(G65 > 0){c8l.C$o(0);b45=t0u[c8l.c6Y(G65,1)];d5W=Z52[b45].arr;c8l.M8Y(166);var S1N=c8l.c6Y(5,61,16,4,19);X8s=d5W[d5W.length - S1N];if(q7A - b45 * X8s < t0u[G65] - q7A){G65--;}}l0a=V1L.timeUnit || t0u[G65];V1L.activeTimeUnit=l0a;g$3=Z52[l0a];f8_=g$3.arr;for(G65=0;G65 < f8_.length;G65++){if(f8_[G65] * l0a > q7A)break;}if(G65 == f8_.length){G65--;}else {if(q7A - f8_[G65 - +"1"] * l0a < f8_[G65] * l0a - q7A){G65--;}}if(g$3.measurement.width * 2 < this.layout.candleWidth){G65=0;}W5F=V1L.timeUnitMultiplier || f8_[G65];D52=[];O5B=this.layout.candleWidth;for(G65=0;G65 <= r3i;G65++){if(R_d[G65])break;}if(G65 > 0 && G65 < r3i){if(N8k.market){r6w=this.standardMarketIterator(R_d[G65].DT,V1L.adjustTimeZone?this.displayZone:null);}for(var D0Z=G65;D0Z > 0;D0Z--){m56={};if(r6w && !(N8k.lineApproximation && O5B < 1)){m56.DT=r6w.previous();}N8k.xaxis.unshift(m56);}}Z4h=0;d2f=g$3.minTimeUnit;W5w=-+"1";p5B=!!({});z5s=S$r(R_d[G65].DT);o8t=0;z7u=0;t3U=R_d[G65].tick;for(o8t;o8t < t3U;o8t++){N9R=S$r(this.chart.dataSet[t3U - o8t].DT);if(N9R[+"1"] != z5s[1])break;z5s=N9R;}for(z7u;z7u < this.chart.dataSet.length - t3U;z7u++){N9R=S$r(this.chart.dataSet[t3U + z7u].DT);if(N9R[1] != z5s[1])break;z5s=N9R;}W1I=null;for(G65=0;G65 < r3i + z7u;G65++){A6L=R_d[G65];if(!A6L){A6L=N8k.xaxis[G65];}else if(o8t){A6L=N8k.dataSet[A6L.tick - o8t];}if(G65 < t_o){r67=A6L;if(r67.displayDate && V1L.adjustTimeZone){Z4h=r67.displayDate;}else {Z4h=r67.DT;}if(G65 && !o8t && N8k.segmentImage){O7X=N8k.segmentImage[G65];c8l.C$o(118);var Z3w=c8l.c6Y(19,4,14,26,150);O5B=(O7X.leftOffset - O7X.candleWidth / Z3w) / G65;}}else if(N8k.market){z5m="tic";z5m+="k";if(this.layout.interval == z5m && !V1L.futureTicksInterval)break;if(N8k.lineApproximation && O5B < 1)break;if(!V1L.futureTicks)break;if(!W1I){W1I=this.standardMarketIterator(R_d[t_o - 1].DT,V1L.adjustTimeZone?this.displayZone:null);}Z4h=W1I.next();}if(!Z4h)continue;O1Z=null;c8l.M8Y(0);w5T=c8l.c6Y(G65,o8t);Y1Q={DT:Z4h};if(G65 < t_o){Y1Q.data=A6L;}else {Y1Q.data=null;}if(o8t){o8t--;G65--;}else if(!N8k.xaxis[G65] && G65 < r3i){N8k.xaxis.push(Y1Q);}z5s=S$r(Z4h);c8l.M8Y(46);l2x=z5s[c8l.c6Y("0",0)];l$9=z5s[1];if(W5w != l$9){if(l2x <= d2f){d2f=g$3.minTimeUnit;}c8l.C$o(167);var f6b=c8l.c6Y(11,7,113,3,8);e8M=N8k.left + w5T * O5B - f6b;O1Z=null;if(l0a == S0i.HOUR || l0a == S0i.MINUTE && W5w > l$9){if(this.internationalizer){O1Z=this.internationalizer.monthDay.format(Z4h);}else {c8l.C$o(14);var h2_=c8l.d58(18,9,3);O1Z=Z4h.getMonth() + h2_ + "/" + Z4h.getDate();}if(V1L.formatter){y8L="bo";y8L+="undary";O1Z=V1L.formatter(Z4h,y8L,S0i.DAY,1,O1Z);}}else if(l0a == S0i.DAY){if(W5w > l$9){O1Z=Z4h.getFullYear();if(V1L.formatter){O1Z=V1L.formatter(Z4h,"boundary",S0i.YEAR,1,O1Z);}}else {O1Z=S0i.monthAsDisplay(Z4h.getMonth(),!({}),this);if(V1L.formatter){O1Z=V1L.formatter(Z4h,"boundary",S0i.MONTH,1,O1Z);}}}else if(l0a == S0i.MONTH){O1Z=Z4h.getFullYear();if(V1L.formatter){m3S="boun";m3S+="dary";O1Z=V1L.formatter(Z4h,m3S,S0i.YEAR,1,O1Z);}}if(O1Z && W5w != -1){D52.push(new S0i.ChartEngine.XAxisLabel(e8M,"boundary",O1Z));}}if(l2x >= d2f){if(d2f == g$3.minTimeUnit){if(l$9 == W5w)continue;;}x2l=new Date(+Z4h);c8l.M8Y(8);var I8b=c8l.d58(18,7,2);c8l.M8Y(0);var y$8=c8l.d58(16,15);c8l.M8Y(8);var B8s=c8l.d58(34,0,17);e8M=N8k.left + (I8b * w5T + y$8) * O5B / B8s - ("1" ^ 0);d29=Math.floor(l2x / W5F) * W5F;if(d29 < l2x){c0C="we";c0C+="ek";if(this.layout.interval == c0C){d29=l2x;}else {c8l.C$o(40);e8M-=c8l.c6Y(2,O5B);};}if(l0a == S0i.MILLISECOND){x2l.setMilliseconds(d29);}else if(l0a == S0i.SECOND){x2l.setMilliseconds(0);x2l.setSeconds(d29);}else if(l0a == S0i.MINUTE){x2l.setMilliseconds(0);x2l.setSeconds(0);x2l.setMinutes(d29);}else if(l0a == S0i.HOUR){x2l.setMilliseconds(0);x2l.setSeconds(0);x2l.setMinutes(0);x2l.setHours(d29);}else if(l0a == S0i.DAY){x2l.setDate(Math.max(+"1",d29));}else if(l0a == S0i.MONTH){x2l.setDate(1);c8l.C$o(0);x2l.setMonth(c8l.c6Y(d29,1));}else if(l0a == S0i.YEAR){x2l.setDate(1);x2l.setMonth(0);}else {c8l.M8Y(46);x2l.setDate(c8l.c6Y("1",0));x2l.setMonth(0);}c8l.M8Y(22);d2f=c8l.d58(W5F,d29);if(l0a == S0i.DAY){c8l.C$o(168);var u12=c8l.c6Y(10,16,17,18,26);g$3.maxTimeUnit=n1t[x2l.getMonth()] + u12;}if(d2f >= g$3.maxTimeUnit){d2f=g$3.minTimeUnit;}W5w=l$9;if(p5B && d29 < l2x){p5B=!({});continue;}if(l0a == S0i.DAY){O1Z=x2l.getDate();}else if(l0a == S0i.MONTH){O1Z=S0i.monthAsDisplay(x2l.getMonth(),!({}),this);}else if(l0a == S0i.YEAR || l0a == S0i.DECADE){O1Z=x2l.getFullYear();}else {O1Z=S0i.timeAsDisplay(x2l,this,l0a);}if(V1L.formatter){D$l="l";D$l+="i";D$l+="n";D$l+="e";O1Z=V1L.formatter(x2l,D$l,l0a,W5F,O1Z);}D52.push(new S0i.ChartEngine.XAxisLabel(e8M,"line",O1Z));}}return D52;};};t3=y$n=>{var k9J=x2dci;var d_N;d_N=y$n.CIQ;k9J.r2m();d_N.ChartEngine.prototype.createYAxis=function(I1y,B12){var g1H,B2e,J3A,N9Z,U4I,W6_,u_n,q9V,W0T,s67,D22,X9n,l0H,q5F,u1x,a8m,X5p,m8X,Q8Z,M4I,R$W,k8u,X7B,W1C,Z6C,r_p,Q3m;g1H="cr";g1H+="eat";g1H+="eYA";g1H+="xis";if(this.runPrepend(g1H,arguments)){return;}B2e=I1y.chart;J3A=I1y.name == B2e.name;if(!B12){B12={};}B12.noChange=!({});N9Z=B12.yAxis?B12.yAxis:I1y.yAxis;if(d_N.ChartEngine.enableCaching && N9Z.high == I1y.cacheHigh && N9Z.low == I1y.cacheLow){k9J.M8Y(169);var I_b=k9J.d58(10,1,12,23);U4I=B2e.dataSet.length - B2e.scroll - I_b;k9J.M8Y(75);var K65=k9J.d58(9,359,15,11,14);W6_=U4I + B2e.maxTicks + K65;I1y.cacheLeft=U4I;I1y.cacheRight=W6_;B12.noChange=!!({});}else {I1y.cacheLeft=+"1000000";I1y.cacheRight=-1;I1y.cacheHigh=N9Z.high;I1y.cacheLow=N9Z.low;}u_n=B2e.xAxis.idealTickSizePixels?B2e.xAxis.idealTickSizePixels:B2e.xAxis.autoComputedTickSizePixels;if(N9Z.goldenRatioYAxis){if(N9Z.idealTickSizePixels != u_n / ("1.618" - 0)){B12.noChange=!({});}}if(!B12.noChange){this.adjustYAxisHeightOffset(I1y,N9Z);W0T=N9Z.height=N9Z.bottom - N9Z.top;s67=(N9Z.high - N9Z.low) / (W0T - N9Z.zoom);if(!N9Z.semiLog){if(B12.ground){D22=-295149038;X9n=1734369358;k9J.M8Y(46);l0H=k9J.c6Y("2",64);for(var r0R=1;k9J.q2D(r0R.toString(),r0R.toString().length,16719) !== D22;r0R++){N9Z.high=N9Z.high * (N9Z.zoom - s67);l0H+=2;}if(k9J.q2D(l0H.toString(),l0H.toString().length,25369) !== X9n){N9Z.high=N9Z.high + N9Z.zoom * s67;}}else {k9J.M8Y(0);var t$Y=k9J.d58(10,8);N9Z.high=N9Z.high + (N9Z.zoom / t$Y + N9Z.scroll) * s67;k9J.M8Y(65);var H6U=k9J.d58(5,1,7,0);N9Z.low=N9Z.low - (N9Z.zoom / H6U - N9Z.scroll) * s67;}}if(N9Z.min || N9Z.min === ("0" ^ 0)){N9Z.low=N9Z.min;}if(N9Z.max || N9Z.max === 0){N9Z.high=N9Z.max;}N9Z.shadow=N9Z.high - N9Z.low;if(N9Z.semiLog && (!this.activeDrawing || this.activeDrawing.name != "projection")){q5F=function(){var V2N;N9Z.logHigh=Math.log(N9Z.high) / Math.LN10;V2N=Math.max(N9Z.low,0.000000001);N9Z.logLow=Math.log(V2N) / Math.LN10;if(N9Z.low <= 0){N9Z.logLow=0;}N9Z.logShadow=N9Z.logHigh - N9Z.logLow;};if(N9Z.semiLog){q5F();}u1x=N9Z.height / (N9Z.height - N9Z.zoom);if(N9Z.flipped){N9Z.high=this.transformedPriceFromPixel(N9Z.bottom + u1x * (N9Z.zoom / 2 + N9Z.scroll),I1y,N9Z);N9Z.low=this.transformedPriceFromPixel(N9Z.top - u1x * (N9Z.zoom / ("2" - 0) - N9Z.scroll),I1y,N9Z);k9J.C$o(74);a8m=-k9J.d58("1121413743",44);X5p=-2021505169;m8X=2;for(var L9p=1;k9J.O$R(L9p.toString(),L9p.toString().length,45142) !== a8m;L9p++){;k9J.M8Y(20);m8X+=k9J.d58("2",0);}if(k9J.O$R(m8X.toString(),m8X.toString().length,15993) !== X5p){;}}else {N9Z.high=this.transformedPriceFromPixel(N9Z.top - u1x * (N9Z.zoom / 2 + N9Z.scroll),I1y,N9Z);N9Z.low=this.transformedPriceFromPixel(N9Z.bottom + u1x * (N9Z.zoom / 2 - N9Z.scroll),I1y,N9Z);;}N9Z.shadow=N9Z.high - N9Z.low;if(N9Z.semiLog){q5F();}}if(N9Z.goldenRatioYAxis && J3A && N9Z == I1y.yAxis){k9J.M8Y(40);N9Z.idealTickSizePixels=k9J.d58(1.618,u_n);if(N9Z.idealTickSizePixels === +"0"){M4I="stx_yax";M4I+="i";M4I+="s";Q8Z=this.getCanvasFontSize(M4I);k9J.C$o(170);N9Z.idealTickSizePixels=k9J.c6Y(64,Q8Z,"5");}}else {if(!N9Z.idealTickSizePixels){Q8Z=this.getCanvasFontSize("stx_yaxis");if(J3A){k9J.M8Y(38);N9Z.idealTickSizePixels=k9J.d58(Q8Z,5);}else {k9J.M8Y(38);N9Z.idealTickSizePixels=k9J.c6Y(Q8Z,2);}}}R$W=Math.round(W0T / N9Z.idealTickSizePixels);q9V=B12.range?B12.range[1] - B12.range[+"0"]:N9Z.shadow;k9J.M8Y(40);N9Z.priceTick=Math.floor(k9J.d58(R$W,q9V));k8u=1;for(var u3x=0;u3x < 10;u3x++){if(N9Z.priceTick > 0)break;k8u*=10;N9Z.priceTick=Math.floor(q9V / R$W * k8u) / k8u;}if(u3x == +"10"){N9Z.priceTick=0.00000001;}N9Z.priceTick=Math.round(q9V / R$W * k8u) / k8u;X7B=Math.round(q9V / N9Z.priceTick);if(B12.range && X7B < q9V && !N9Z.noEvenDivisorTicks){while(X7B >= 1){if(q9V % X7B === 0)break;X7B--;}k9J.M8Y(40);N9Z.priceTick=k9J.d58(X7B,q9V);}if(N9Z.minimumPriceTick){W1C=N9Z.minimumPriceTick;Q8Z=this.getCanvasFontSize("stx_yaxis");for(var n3o=0;n3o < 100;n3o++){k9J.C$o(40);Z6C=k9J.d58(W1C,q9V);if(W0T / Z6C < Q8Z * 2){W1C+=N9Z.minimumPriceTick;}else break;}if(n3o < 100){N9Z.priceTick=W1C;}}}if(N9Z.priceTick <= 0 || N9Z.priceTick === Infinity){N9Z.priceTick=1;}N9Z.multiplier=N9Z.height / N9Z.shadow;if(N9Z.multiplier == Infinity){N9Z.multiplier=+"0";}if(!N9Z.decimalPlaces && N9Z.decimalPlaces !== 0){if(J3A){r_p=0;for(var K4J=0;K4J < I1y.yAxis.shadowBreaks.length;K4J++){Q3m=I1y.yAxis.shadowBreaks[K4J];if(I1y.yAxis.shadow < Q3m["0" * 1]){r_p=Q3m[1];}}N9Z.printDecimalPlaces=r_p;}else {N9Z.printDecimalPlaces=null;};}else {N9Z.printDecimalPlaces=N9Z.decimalPlaces;}this.runAppend("createYAxis",arguments);};d_N.ChartEngine.prototype.drawYAxis=function(A2Q,U9i){var U$T,i$6,y54,Q4u,g2E,F_W,d50,t6O,E8y,o5F,d4W,b1a,t_q,Y6q,s7w,M2t,T9K,K5U,V4t,I3B,P2b,Y4R,N$H,f0q,z3P,P$p,w1I,G7S,O4m,z2x,U3V,q$8,K5a,l3G,D96,e0C,a_4,e0d,s6W,t7D,V7C,X1b;if(!U9i){U9i={};}U$T=U9i.yAxis?U9i.yAxis:A2Q.yAxis;if(A2Q.hidden || U$T.noDraw || !U$T.width){return;}if(!d_N.Comparison || U$T.priceFormatter != d_N.Comparison.priceFormat){i$6=U$T.fractional;if(i$6){if(!U$T.originalPriceFormatter){U$T.originalPriceFormatter={func:U$T.priceFormatter};}if(!i$6.resolution){i$6.resolution=U$T.minimumPrice;}if(!i$6.formatter){i$6.formatter=(+"75.45",8516) === (604.84,+"9230")?9.56e+3:"'";}if(!U$T.priceFormatter){U$T.priceFormatter=function(w0z,s4S,Q0K){var v7$,N05,G8m,V6w;if(!i$6){return;}v7$="";if(Q0K < 0){v7$=8050 < 7390?4.00e+3:"-";Q0K=Math.abs(Q0K);}N05=Math.floor(Math.round(Q0K / i$6.resolution) * i$6.resolution);G8m=Math.round((Q0K - N05) / i$6.resolution);V6w=Math.floor(G8m);k9J.M8Y(7);var R_X=k9J.c6Y(15,6012,12);k9J.M8Y(68);var e9x=k9J.c6Y(20754,4,6923);k9J.C$o(1);var f1G=k9J.c6Y(352,6,18,10,31031);k9J.C$o(120);var a13=k9J.c6Y(565,8,568,565);k9J.C$o(171);var j_S=k9J.d58(6,15,44808,6,8967);return v7$ + N05 + i$6.formatter + (V6w < +"10"?211.56 > ("888.96" - 0,187.49)?("7762" ^ 0,104.62) === R_X?(603.56,e9x) >= (f1G,234.37)?(a13,340.92):j_S:"0":"760.23" - 0:"") + V6w + (G8m - V6w >= 0.5?"+":"");};}}else {if(U$T.originalPriceFormatter){U$T.priceFormatter=U$T.originalPriceFormatter.func;U$T.originalPriceFormatter=null;}}}y54=this.colorOrStyle(U$T.textStyle || "stx_yaxis");Q4u=this.highlightedDraggable;g2E=0;if(Q4u && this.yaxisMatches(Q4u,U$T)){g2E=0.15;}else if(U$T.highlight){g2E=+"0.1";}k9J.J8h();if(g2E){F_W=y54.constructor == String?y54:y54.color;U$T.setBackground(this,{color:F_W,opacity:g2E});}if(U$T.pretty){return this.drawYAxisPretty(A2Q,U9i);}if(this.runPrepend("drawYAxis",arguments)){return;}if(!U9i.noDraw && !U$T.noDraw){d50=U$T.yAxisPlotter;if(!d50 || !U9i.noChange){t6O="s";t6O+="tx_yax";t6O+="is";E8y="l";E8y+="eft";o5F="stro";o5F+="ke";d4W="g";d4W+="rid";d50=U$T.yAxisPlotter=new d_N.Plotter();b1a=A2Q.chart;t_q=A2Q.name == b1a.name && U$T.name === A2Q.yAxis.name;if(!U$T.priceTick){return;}Y6q=U$T.shadow;s7w=U9i.range;if(s7w){k9J.C$o(115);var Y0j=k9J.d58(4,7,7,1,4);Y6q=s7w[Y0j] - s7w[0];}M2t=Y6q / U$T.priceTick;M2t=Math.round(M2t);if(U$T.semiLog){T9K=Math.log(this.valueFromPixel(U$T.flipped?U$T.top:U$T.bottom,A2Q)) / Math.LN10;K5U=(U$T.logHigh - U$T.logLow) / M2t;}d50.newSeries(d4W,"stroke",this.canvasStyle("stx_grid"));d50.newSeries("text","fill",y54);d50.newSeries("border",o5F,this.canvasStyle("stx_grid_border"));V4t=0;I3B=s7w?s7w[1]:U$T.high;P2b=s7w?s7w[0]:U$T.low;Y4R=U$T.displayBorder === null?b1a.panel.yAxis.displayBorder:U$T.displayBorder;if(this.axisBorders === !1){Y4R=!({});}if(this.axisBorders === !!({})){Y4R=!!({});}f0q=b1a.dynamicYAxis;z3P=f0q?U$T.width:NaN;P$p=this.getYAxisCurrentPosition(U$T,A2Q);if(P$p == "left"){N$H=U$T.left + U$T.width;}else {N$H=U$T.left;}w1I=Math.round(N$H) + 0.5;G7S=Y4R?3:0;if(P$p == E8y){G7S=Y4R?-3:+"0";}if(t_q){if(U$T.shadow < "1" * 1){k9J.C$o(172);var L2y=k9J.d58(17,11,152,9);V4t=(parseInt(P2b / U$T.priceTick,L2y) + ("1" - 0)) * U$T.priceTick - P2b;}else {V4t=U$T.priceTick - Math.round(P2b % U$T.priceTick * A2Q.chart.roundit) / A2Q.chart.roundit;}}else {V4t=I3B % U$T.priceTick;}O4m=this.getCanvasFontSize(t6O);for(var a$k=+"0";a$k < M2t;a$k++){if(U$T.semiLog){k9J.M8Y(147);U3V=k9J.c6Y(T9K,a$k,K5U);z2x=Math.pow(10,U3V);}else {if(t_q){z2x=P2b + a$k * U$T.priceTick + V4t;}else {z2x=I3B - a$k * U$T.priceTick - V4t;}}q$8=this.pixelFromTransformedValue(z2x,A2Q,U$T);K5a=Math.round(q$8) + 0.5;if(K5a + O4m / +"2" > A2Q.bottom)continue;if(K5a - O4m / ("2" - 0) < A2Q.top)continue;if(Math.abs(K5a - U$T.bottom) < 1)continue;if(U$T.flipped){K5a=U$T.top + U$T.bottom - K5a;}if(U$T.displayGridLines){l3G="g";l3G+="ri";l3G+="d";d50.moveTo("grid",A2Q.left + 1,K5a);d50.lineTo(l3G,A2Q.right - 1,K5a);}if(Y4R){D96="bo";D96+="rd";D96+="er";k9J.M8Y(0);d50.moveTo("border",k9J.c6Y(w1I,0.5),K5a);k9J.M8Y(22);d50.lineTo(D96,k9J.c6Y(G7S,w1I),K5a);}if(U$T.priceFormatter){z2x=U$T.priceFormatter(this,A2Q,z2x);}else {z2x=this.formatYAxisPrice(z2x,A2Q,null,U$T);}e0C=U$T.textBackground?this.containerColor:null;a_4=3;k9J.M8Y(53);e0d=k9J.c6Y(N$H,G7S,a_4);if(P$p == "left"){e0d=U$T.left + a_4;if(U$T.justifyRight !== !"1"){e0d=U$T.left + U$T.width + G7S - a_4;}}else {if(U$T.justifyRight){e0d=N$H + U$T.width;}}d50.addText("text",z2x,e0d,K5a,e0C,null,O4m);if(f0q){z3P=Math.max(z3P,b1a.context.measureText(z2x).width + Math.abs(G7S) + a_4);}}if(Y4R){s6W="bor";s6W+="der";t7D="bo";t7D+="rd";t7D+="er";V7C=Math.round(U$T.bottom) + 0.5;d50.moveTo(t7D,w1I,U$T.top);d50.lineTo(s6W,w1I,V7C);d50.draw(this.getBackgroundCanvas(b1a).context,"border");}if(f0q && z3P > U$T.width){U$T._dynamicWidth=z3P;this.calculateYAxisPositions();throw new Error("reboot draw");}else if(!f0q && U$T._dynamicWidth){X1b="rebo";X1b+="ot draw";this.resetDynamicYAxis({chartName:b1a.name});throw new Error(X1b);}}if(U$T == A2Q.yAxis){this.plotYAxisGrid(A2Q);}}this.runAppend("drawYAxis",arguments);};d_N.ChartEngine.prototype.drawYAxisPretty=function(B3J,k_4){var J1q,O1F,F_Y,K6G,O64,j3W,R$O,Y8M,x1F,i8b,x8w,V7y,j2q,d0e,T4O,u2M,L26,n53,x3k,r5f,n6O,c2c,O18,O1K,w7T,N4Z,A7y,m7V,L7S,v7z,E6G,S3Z,v68,F72,E2J,B8A,J6x,i8x,S2B,b1s,p2_,D8n,v4f,a$J,F0l,c4e,G1h,h8J,w3o,x6Y,C8J,a7N,G80;if(this.runPrepend("drawYAxis",arguments)){return;}k9J.J8h();if(!k_4){k_4={};}J1q=k_4.yAxis?k_4.yAxis:B3J.yAxis;if(B3J.hidden || J1q.noDraw || !J1q.width){return;}if(!k_4.noDraw){O1F=J1q.yAxisPlotter;if(!O1F || !k_4.noChange){F_Y="st";F_Y+="x_";F_Y+="yax";F_Y+="is";K6G="bor";K6G+="der";O64="f";O64+="ill";j3W="t";j3W+="e";j3W+="x";j3W+="t";R$O="stx_";R$O+="grid";Y8M="stx";Y8M+="_";Y8M+="ya";Y8M+="xis";O1F=J1q.yAxisPlotter=new d_N.Plotter();x1F=B3J.chart;if(!J1q.priceTick){return;}if(isNaN(J1q.high) || isNaN(J1q.low)){return;}i8b=J1q.shadow;if(k_4.range){k9J.M8Y(7);var g2r=k9J.d58(17,0,18);i8b=k_4.range[g2r] - k_4.range[0];}x8w=J1q.height / J1q.idealTickSizePixels;x8w=Math.round(x8w);V7y=J1q.textStyle || Y8M;O1F.newSeries("grid","stroke",this.canvasStyle(R$O));O1F.newSeries(j3W,O64,this.colorOrStyle(V7y));O1F.newSeries(K6G,"stroke",this.canvasStyle("stx_grid_border"));j2q=k_4.range;d0e=j2q?j2q[1]:J1q.high;T4O=j2q?j2q[0]:J1q.low;u2M=J1q.displayBorder === null?x1F.panel.yAxis.displayBorder:J1q.displayBorder;if(this.axisBorders === ![]){u2M=!({});}if(this.axisBorders === !!1){u2M=!![];}n53=x1F.dynamicYAxis;x3k=n53?J1q.width:NaN;r5f=this.getYAxisCurrentPosition(J1q,B3J);if(r5f == "left"){L26=J1q.left + J1q.width;}else {L26=J1q.left;}n6O=Math.round(L26) + 0.5;c2c=u2M?3:0;if(r5f == "left"){c2c=u2M?-3:0;}O18=this.getCanvasFontSize(F_Y);O1K=J1q.increments;w7T=O1K.length;N4Z=0;A7y=1;m7V=0;L7S=0;v7z=0;E6G=Number.MAX_VALUE;for(var y$0=0;y$0 < 100;y$0++){k9J.M8Y(25);var M0$=k9J.d58(0,8,18);m7V=O1K[N4Z] * Math.pow(M0$,v7z);k9J.C$o(40);A7y=Math.floor(k9J.c6Y(m7V,i8b));k9J.M8Y(0);S3Z=Math.abs(k9J.c6Y(x8w,A7y));if(S3Z > E6G){break;}else {E6G=S3Z;}if(A7y == x8w){L7S=m7V;break;}else if(A7y > x8w){N4Z++;if(N4Z >= w7T){N4Z=0;v7z++;}}else {N4Z--;if(N4Z < 0){k9J.M8Y(0);N4Z=k9J.d58(w7T,1);v7z--;}}L7S=m7V;}v68=Math.ceil(T4O / L7S) * L7S;F72=J1q.bottom - this.pixelFromTransformedValue(v68,B3J,J1q);E2J=0;if(F72 > J1q.idealTickSizePixels && J1q.semiLog && J1q.prettySemiLog){B8A=Math.ceil(T4O);J6x=0;while(v68 - B8A >= 10000 && J6x <= "15" >> 32){v68/=10;B8A/=10;J6x++;}v68=Math.ceil(v68);B8A=Math.ceil(B8A);for(B8A;B8A < v68 && v68 % B8A !== 0;++B8A){;}v68*=Math.pow(10,J6x);B8A*=Math.pow(10,J6x);if(B8A < v68){if(v68 === L7S){L7S=B8A;E2J=B8A;}v68=B8A;}}if(J1q.height > J1q.zoom){k9J.C$o(38);i8x=k9J.d58("0",1);S2B=Number.MAX_VALUE;x1F.context.save();this.canvasFont("stx_yaxis",x1F.context);for(var R$c=0;R$c < 100;R$c++){b1s="le";b1s+="f";b1s+="t";k9J.C$o(147);p2_=k9J.d58(v68,i8x,L7S);if(p2_ > d0e)break;L7S+=E2J;i8x++;D8n=this.pixelFromTransformedValue(p2_,B3J,J1q);if(S2B - D8n < O18 + 1 && E2J > ("0" | 0)){R$c=i8x=0;S2B=Number.MAX_VALUE;L7S=E2J;E2J*=2;O1F.reset();continue;}S2B=D8n;k9J.M8Y(34);var z79=k9J.c6Y(17,203,1,12);v4f=Math.round(D8n) + "0.5" * z79;if(v4f + O18 / 2 > B3J.bottom)continue;if(v4f - O18 / +"2" < B3J.top)continue;if(Math.abs(v4f - J1q.bottom) < 1)continue;if(J1q.displayGridLines){O1F.moveTo("grid",B3J.left + 1,v4f);O1F.lineTo("grid",B3J.right - +"1",v4f);}if(u2M){k9J.C$o(0);O1F.moveTo("border",k9J.c6Y(n6O,0.5),v4f);k9J.C$o(22);O1F.lineTo("border",k9J.d58(c2c,n6O),v4f);}if(J1q.priceFormatter){p2_=J1q.priceFormatter(this,B3J,p2_);}else {p2_=this.formatYAxisPrice(p2_,B3J,null,J1q);}a$J=J1q.textBackground?this.containerColor:null;k9J.M8Y(20);F0l=k9J.d58("3",0);k9J.C$o(53);c4e=k9J.d58(L26,c2c,F0l);if(r5f == b1s){k9J.C$o(67);var B31=k9J.d58(18,1,9);c4e=J1q.left + B31;if(J1q.justifyRight !== ![]){c4e=J1q.left + J1q.width + c2c - F0l;}}else {if(J1q.justifyRight){c4e=L26 + J1q.width;}}O1F.addText("text",p2_,c4e,v4f,a$J,null,O18);if(n53){k9J.C$o(22);G1h=k9J.c6Y("\xA0",p2_);x3k=Math.max(x3k,x1F.context.measureText(G1h).width + Math.abs(c2c) + F0l);}}x1F.context.restore();if(R$c >= 100){console.log("drawYAxisPretty: assertion error. zz reached 100");}}if(u2M){h8J="bor";h8J+="d";h8J+="er";w3o="bo";w3o+="rder";x6Y=Math.round(J1q.bottom) + 0.5;O1F.moveTo(w3o,n6O,J1q.top);O1F.lineTo("border",n6O,x6Y);O1F.draw(this.getBackgroundCanvas(x1F).context,h8J);}if(n53 && x3k > J1q.width){J1q._dynamicWidth=x3k;this.calculateYAxisPositions();throw new Error("reboot draw");}else if(!n53 && J1q._dynamicWidth){C8J=-668306934;a7N=1199601349;G80=2;for(var x8M=1;k9J.O$R(x8M.toString(),x8M.toString().length,99153) !== C8J;x8M++){this.resetDynamicYAxis({chartName:x1F.name});G80+=2;}if(k9J.q2D(G80.toString(),G80.toString().length,"70338" * 1) !== a7N){this.resetDynamicYAxis({chartName:x1F.name});}throw new Error("reboot draw");}}if(J1q == B3J.yAxis){this.plotYAxisGrid(B3J);}}this.runAppend("drawYAxis",arguments);};};u={};F(u);S(u);Z(u);Q(u);A(u);G(u);C(u);E(u);K(u);O(u);M(u);B(u);J(u);P(u);T(u);W(u);U(u);R(u);D(u);N(u);L0(u);W_(u);f9(u);o8(u);d7(u);m1(u);k4(u);C1(u);t_(u);b$(u);l5(u);R$(u);L9(u);G8(u);A1(u);S4(u);t3(u);var {CIQ:u8, SplinePlotter:e_, timezoneJS:g2, $$:t8, $$$:W5}=u;export {u8 as CIQ, e_ as SplinePlotter, g2 as timezoneJS, t8 as $$, W5 as $$$};/* eslint-enable */ /* jshint ignore:end */ /* ignore jslint end */ diff --git a/chartiq/production/js/deprecated.js b/chartiq/production/js/deprecated.js deleted file mode 100644 index c15ec4ecae..0000000000 --- a/chartiq/production/js/deprecated.js +++ /dev/null @@ -1,2864 +0,0 @@ -/**! - * 8.2.0 - * Generation date: 2023-03-23T15:05:01.971Z - * Client name: deriv limited - * Package Type: Technical Analysis - * License type: annual - * Expiration date: "2024/04/01" - * Domain lock: ["127.0.0.1","localhost","deriv.com","deriv.app","deriv.me","binary.com","binary.sx","binary.me","binary.bot","deriv.be"] - * iFrame lock: true - */ - -/***********************************************************! - * Copyright by ChartIQ, Inc. - * Licensed under the ChartIQ, Inc. Developer License Agreement https://www.chartiq.com/developer-license-agreement -*************************************************************/ -/*************************************! DO NOT MAKE CHANGES TO THIS LIBRARY FILE!! !************************************* -* If you wish to overwrite default functionality, create a separate file with a copy of the methods you are overwriting * -* and load that file right after the library has been loaded, but before the chart engine is instantiated. * -* Directly modifying library files will prevent upgrades and the ability for ChartIQ to support your solution. * -*************************************************************************************************************************/ -/* eslint-disable no-extra-parens */ - - -/***********************************************************! - * Copyright by ChartIQ, Inc. - * Licensed under the ChartIQ, Inc. Developer License Agreement https://www.chartiq.com/developer-license-agreement -*************************************************************/ -/*************************************! DO NOT MAKE CHANGES TO THIS LIBRARY FILE!! !************************************* -* If you wish to overwrite default functionality, create a separate file with a copy of the methods you are overwriting * -* and load that file right after the library has been loaded, but before the chart engine is instantiated. * -* Directly modifying library files will prevent upgrades and the ability for ChartIQ to support your solution. * -*************************************************************************************************************************/ -import {CIQ} from "../js/chartiq.js"; - - - -/* - Deprecated functions - lite -*/ - -var WARN_INTERVAL = 10000; -/** - * Warn developer of use of deprecated function. - * - * All deprecated functions should be calling this log whenever it is used. - * Warning will be output to the console up to 10 seconds after it is logged, in order to help suppress duplicates. - * - * @param {string} message Message to output - * @private - */ -var warnings = null; -CIQ.deprecationWarning = function (message) { - if (!warnings) { - warnings = {}; - setInterval(function () { - for (var m in warnings) { - console.warn(m + " (" + warnings[m] + " occurrences)"); - delete warnings[m]; - } - }, WARN_INTERVAL); - } - if (!warnings[message]) warnings[message] = 1; - else warnings[message]++; -}; - -var log = CIQ.deprecationWarning; - -/* Function.ciqInheritsFrom, Function.stxInheritsFrom */ -if (!Function.prototype.ciqInheritsFrom) { - /** - * The built-in Function object. - * @external Function - * @see [Function]{@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function} on the Mozilla Developer Network. - */ - - /** - * **Deprecated since 7.4.0.** Use {@link CIQ.inheritsFrom} instead. - * - * Template for JavaScript inheritance. - * - * By default the constructor (ctor) is called with no arguments. - * - * @param {object} ctor The parent class or object. - * @param {boolean} [autosuper=true] Set to false to prevent the base class constructor from being called automatically. - * @memberof external:Function - * @alias external:Function#ciqInheritsFrom - * @deprecated As of 7.4.0. Use {@link CIQ.inheritsFrom} instead. - */ - Function.prototype.ciqInheritsFrom = function (ctor, autosuper) { - log( - "Function.prototype.ciqInheritsFrom() has been deprecated. Use CIQ.inheritsFrom(me, ctor, autosuper) instead." - ); - CIQ.inheritsFrom(this, ctor, autosuper); - }; - Function.prototype.stxInheritsFrom = Function.prototype.ciqInheritsFrom; // backward compatibility -} - -/** - * The built-in String object. - * @external String - * @see [String]{@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String} on the Mozilla Developer Network. - */ - -/** - * **Deprecated since 7.4.0.** Use {@link CIQ.capitalize} instead. - * - * Capitalizes the first letter of a string. - * - * @return {string} Capitalized version of the string. - * @memberof external:String - * @alias external:String#capitalize - * @deprecated As of 7.4.0. Use {@link CIQ.capitalize} instead. - */ -String.prototype.capitalize = function () { - log( - "String.prototype.capitalize() has been deprecated. Use CIQ.capitalize(string) instead." - ); - return CIQ.capitalize(this); -}; - -/** - * **Deprecated since 7.4.0.** Use native CanvasRenderingContext2D methods such as moveTo(), lineTo() and setLineDash() instead. - * - * Dashed line polyfill for the canvas. Note that dashed lines are expensive operations when not supported natively. - * See {@link external:CanvasRenderingContext2D#stxLine}. - * - * @param {number} fromX Starting point of the X-axis. - * @param {number} fromY Starting point of the Y-axis. - * @param {number} toX Destination on the X-axis. - * @param {number} toY Destination on the Y-axis. - * @param {string[]} pattern Array of stroke patterns. - * @memberof external:CanvasRenderingContext2D - * @alias external:CanvasRenderingContext2D#dashedLineTo - * @deprecated As of 7.4.0. Use native CanvasRenderingContext2D methods such as moveTo(), lineTo() and setLineDash() instead. - * - * @example - * Native [CanvasRenderingContext2D]{@link https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D} - * methods used to draw a horizontal dashed line across the center of the screen: - * var canvas = stxx.chart.backgroundCanvas; - * var ctx = canvas.getContext("2d"); - * ctx.beginPath(); - * ctx.setLineDash([10, 10]); - * ctx.moveTo(0, canvas.height/2); - * ctx.lineTo(canvas.width, canvas.height/2); - * ctx.stroke(); - */ -CanvasRenderingContext2D.prototype.dashedLineTo = function ( - fromX, - fromY, - toX, - toY, - pattern -) { - log( - "CanvasRenderingContext2D.prototype.dashedLineTo() has been deprecated. Use native CanvasRenderingContext2D methods such as moveTo(), lineTo() and setLineDash() instead." - ); - // Error check. - if (!(pattern instanceof Array)) { - if (pattern) - console.log( - 'WARNING: Unsupported drawing pattern "' + - pattern + - '"; defaulting to "solid"' - ); - this.stxLine( - fromX, - fromY, - toX, - toY, - this.strokeStyle, - this.globalAlpha, - this.lineWidth - ); - return; - } - - // can't dash if we do not have proper values - if ( - fromY === Infinity || - fromX === Infinity || - toY === Infinity || - toX === Infinity - ) - return; - - // Our growth rate for our line can be one of the following: - // (+,+), (+,-), (-,+), (-,-) - // Because of this, our algorithm needs to understand if the x-coord and - // y-coord should be getting smaller or larger and properly cap the - // values - // based on (x,y). - var lt = function (a, b) { - return a - b <= 0.00000001; - }; - var gt = function (a, b) { - return a - b >= -0.00000001; - }; - var capmin = function (a, b) { - return Math.min(a, b); - }; - var capmax = function (a, b) { - return Math.max(a, b); - }; - - var checkX = { thereYet: gt, cap: capmin }; - var checkY = { thereYet: gt, cap: capmin }; - - if (fromY - toY > 0) { - checkY.thereYet = lt; - checkY.cap = capmax; - } - if (fromX - toX > 0) { - checkX.thereYet = lt; - checkX.cap = capmax; - } - - this.moveTo(fromX, fromY); - if (isNaN(fromX) || isNaN(fromY)) return; - var offsetX = fromX; - var offsetY = fromY; - var idx = 0, - dash = true; - while (!(checkX.thereYet(offsetX, toX) && checkY.thereYet(offsetY, toY))) { - var ang = Math.atan2(toY - fromY, toX - fromX); - var len = pattern[idx]; - - offsetX = checkX.cap(toX, offsetX + Math.cos(ang) * len); - offsetY = checkY.cap(toY, offsetY + Math.sin(ang) * len); - - if (dash) this.lineTo(offsetX, offsetY); - else this.moveTo(offsetX, offsetY); - - idx = (idx + 1) % pattern.length; - dash = !dash; - } -}; - -/** - * **Deprecated since 7.4.0.** Use native CanvasRenderingContext2D methods such as moveTo() and lineTo() instead. - * - * @param {number} fromX Starting point of the X-axis. - * @param {number} fromY Starting point of the Y-axis. - * @param {number} toX Destination on the X-axis. - * @param {number} toY Destination on the Y-axis. - * @param {string} color CSS-compatible color, such as hex, rgb, rgba or even color names such as "orange". - * @param {number} opacity The alpha. A number between 0 and 1. - * @param {number} lineWidth The line width in pixels. - * @param {number[]} [pattern] An array that contains the number of pixels on and then the number of pixels off. - * For instance [1,1] would create a dotted pattern by turning one pixel on and then one pixel off repeatedly. - * @memberof external:CanvasRenderingContext2D - * @alias external:CanvasRenderingContext2D#stxLine - * @deprecated As of 7.4.0. Use native CanvasRenderingContext2D methods such as moveTo() and lineTo() instead. - * - * @example - * Native [CanvasRenderingContext2D]{@link https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D} - * methods used to draw a thick blue line diagonally across the screen: - * var canvas = stxx.chart.backgroundCanvas; - * var ctx = canvas.getContext("2d"); - * ctx.beginPath(); - * ctx.strokeStyle = "blue"; - * ctx.lineWidth = 2; - * ctx.moveTo(0, 0); - * ctx.lineTo(canvas.width, canvas.height/2); - * ctx.stroke(); - */ -CanvasRenderingContext2D.prototype.stxLine = function ( - fromX, - fromY, - toX, - toY, - color, - opacity, - lineWidth, - pattern -) { - log( - "CanvasRenderingContext2D.prototype.stxLine() has been deprecated. Use native CanvasRenderingContext2D methods such as moveTo() and lineTo() instead." - ); - this.beginPath(); - this.lineWidth = lineWidth; - this.strokeStyle = color; - this.globalAlpha = opacity; - if (pattern && pattern.length) { - this.dashedLineTo(fromX, fromY, toX, toY, pattern); - } else { - this.moveTo(fromX, fromY); - this.lineTo(toX, toY); - } - this.stroke(); - this.closePath(); - this.lineWidth = 1; -}; - -/** - * **Deprecated since 7.4.0.** Use native CanvasRenderingContext2D methods such as arc() instead. - * - * Add native circle drawing to the canvas. - * - * @param {number} x X-axis position of the center of the circle. - * @param {number} y Y-axis position of the center of the circle. - * @param {number} radius Radius of the circle. - * @param {boolean} filled If true, then the circle is filled. - * @memberof external:CanvasRenderingContext2D - * @alias external:CanvasRenderingContext2D#stxCircle - * @deprecated As of 7.4.0. Use native CanvasRenderingContext2D methods such as arc() instead. - * - * @example - * Native [CanvasRenderingContext2D]{@link https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D} - * methods used to draw a red circle in the center of the screen: - * var canvas = stxx.chart.backgroundCanvas; - * var ctx = canvas.getContext("2d"); - * ctx.beginPath(); - * ctx.fillStyle = "red"; - * ctx.arc(canvas.width/2, canvas.height/2, 100, 0, 2 * Math.PI); - * ctx.fill(); - */ -CanvasRenderingContext2D.prototype.stxCircle = function (x, y, radius, filled) { - log( - "CanvasRenderingContext2D.prototype.stxCircle() has been deprecated. Use native CanvasRenderingContext2D methods such as arc() instead." - ); - this.beginPath(); - this.arc(x, y, radius, 0, 2 * Math.PI, false); - if (filled) this.fill(); - this.stroke(); - this.closePath(); -}; - -/** - * Returns an instance of - * [XMLHttpRequest]{@link https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest}. - * - * @param {string} url The URL to which the request is sent (not used). - * @return {object} An XMLHttpRequest instance. - * - * @memberof CIQ - * @deprecated As of 8.0.0. Use `new XMLHttpRequest()`. - */ -CIQ.getAjaxServer = function (url) { - log( - "CIQ.getAjaxServer() has been deprecated. Use `new XMLHttpRequest` instead." - ); - return new XMLHttpRequest(); -}; - -/** - * Converts an onClick event to an ontouchend event. If the device is known to be a touch device then this can be used - * to change onclick events that are set as attributes (in HTML). ontouchend events are more responsive than onclick events - * and can improve the user experience. When coding for cross-device implementations it is recommended to use {@link CIQ.safeClickTouch} - * programmatically rather than using hardcoded attributes - * @param {string} id The id of a node containing an onClick attribute - * @memberof CIQ - * @deprecated - * @since 6.0.0 Deprecated - */ -CIQ.convertClickToTouchEnd = function (id) { - log( - "CIQ.convertClickToTouchEnd() has been deprecated. Use CIQ.safeClickTouch() instead." - ); - var node = document.getElementById(id); - var s = node.getAttribute("onClick"); - if (s) { - node.removeAttribute("onClick"); - node.setAttribute("onTouchEnd", s); - } -}; - -/** - * Converts a date to YYYY-MM-DDTHH:MM:SSZ format (UTC). - * - * @param {date} dt The JavaScript `Date` object to be converted. - * @return {string} The date in YYYY-MM-DDTHH:MM:SSZ format. - * - * @memberof CIQ - * @deprecated As of 8.0.0. Use [Date.prototype.toISOString]{@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString} method. - */ -CIQ.standardUTCDate = function (dt) { - log( - "CIQ.standardUTCDate(dt) has been deprecated. Use dt.toISOString() instead." - ); - var m = dt.getUTCMonth() + 1; - if (m < 10) m = "0" + m; - var d = dt.getUTCDate(); - if (d < 10) d = "0" + d; - var h = dt.getUTCHours(); - if (h < 10) h = "0" + h; - var mn = dt.getUTCMinutes(); - if (mn < 10) mn = "0" + mn; - var s = dt.getUTCSeconds(); - if (s < 10) s = "0" + s; - return ( - "" + - dt.getUTCFullYear() + - "-" + - m + - "-" + - d + - "T" + - h + - ":" + - mn + - ":" + - s + - "Z" - ); -}; - -/** - * Determines whether the input date is during daylight saving time (DST). - * - * @param {date} [dt] The date to check. If the parameter is omitted, the current date is used. - * @return {boolean} True for DST, otherwise false. - * - * @memberof CIQ - * @deprecated As of 8.0.0. This function may return inaccurate results for some - * countries. - */ -CIQ.isDST = function (dt) { - log("CIQ.isDST() has been deprecated. Use dt.toISOString() instead."); - if (!dt) dt = new Date(); - var jan = new Date(dt.getFullYear(), 0, 1); - var jul = new Date(dt.getFullYear(), 6, 1); - var stdOffset = Math.max(jan.getTimezoneOffset(), jul.getTimezoneOffset()); - return dt.getTimezoneOffset() != stdOffset; -}; - -/** - * Gets the source element for a DOM event. - * - * @param {object} [e] The DOM event, if available from the browser. If an event is not - * provided, the window event is used. - * @return {object} The DOM node that registered the event. - * - * @memberof CIQ - * @deprecated As of 8.0.0. Use [Event.target]{@link https://developer.mozilla.org/en-US/docs/Web/API/Event/target}. - */ -CIQ.getEventDOM = function (e) { - log("CIQ.getEventDOM() has been deprecated. Use `e.target` instead."); - return e ? e.target : window.event.srcElement; -}; - -/** - * **Deprecated since 8.1.0.** Use {@link CIQ.elementDimensions} instead. - * - * Measures the width of a DOM element, including left and right margins. - * - * @param {HTMLElement} node The DOM element for which the width is measured. - * @return {number} The width of the DOM element, including margins. - * - * @memberof CIQ - * @deprecated Use {@link CIQ.elementDimensions}; for example, - * `CIQ.elementDimensions(node, {margin:1, padding:1, border:1}).width`. - * @since 8.1.0 Deprecated. - */ -CIQ.outerWidth = function (node) { - log( - "CIQ.outerWidth() has been deprecated. Use `CIQ.elementDimensions(node, {margin:1, padding:1, border:1}).width` instead." - ); - var width = node.offsetWidth; - width += CIQ.stripPX(getComputedStyle(node).marginLeft); - width += CIQ.stripPX(getComputedStyle(node).marginRight); - return width; -}; - -/** - * **Deprecated since 8.1.0.** Use `node.innerHTML=""` instead. - * - * Removes all DOM elements from within a given node. This is extremely useful when dynamically - * generating content. - * - * @param {HTMLElement} node The node from which all DOM elements are removed. - * - * @memberof CIQ - * @deprecated Use `node.innerHTML=""`. - * @since 8.1.0 Deprecated. - */ -CIQ.clearNode = function (node) { - log("CIQ.clearNode() has been deprecated. Use `node.innerHTML=''` instead."); - if (node.hasChildNodes()) { - while (node.childNodes.length >= 1) { - node.removeChild(node.firstChild); - } - } -}; - -/** - * **Deprecated since 8.1.0.** Use `Element.parentElement.prototype.closest()` instead. - * - * Convenience function for selecting a DOM element's closest parent element matching a selector. - * - * Use instead of `jQuery.closest()`. - * - * @param {HTMLElement} el The DOM element for which the parent element is obtained. - * @param {string} selector A CSS selector used to select the parent element. - * @return {HTMLElement} The parent element of `el` matching `selector`, or null if no match is - * found. - * - * @memberof CIQ - * @deprecated Use `Element.parentElement.prototype.closest()`. - * @since - * - 7.3.0 - * - 8.1.0 Deprecated. - */ -CIQ.findClosestParent = function (el, selector) { - log( - "CIQ.findClosestParent() has been deprecated. Use `Element.parentElement.prototype.closest()` instead." - ); - var matchesFn; - // find vendor prefix - [ - "matches", - "webkitMatchesSelector", - "mozMatchesSelector", - "msMatchesSelector", - "oMatchesSelector" - ].some(function (fn) { - if (typeof document.body[fn] == "function") { - matchesFn = fn; - return true; - } - return false; - }); - if (!matchesFn) return false; - var parent; - // traverse parents - while (el) { - parent = el.parentElement; - if (parent && parent[matchesFn](selector)) { - return parent; - } - el = parent; - } - return null; -}; - -/** - * Appends a class name to a node if the node doesn't already have that class. Used to - * control dynamic behavior via CSS. - * - * @param {object} node The DOM element to which the class is added. - * @param {string} className Name of the class to add to the DOM element. - * - * @memberof CIQ - * @deprecated As of 8.0.0. Use [Element.classList.add(className)]{@link https://developer.mozilla.org/en-US/docs/Web/API/DOMTokenList/add}. - * - * @example - * // Apply an "active" css look to an object. - * CIQ.appendClassName(myNode, "active"); - */ -CIQ.appendClassName = function (node, className) { - log( - "CIQ.appendClassName() has been deprecated. Use `node.classList.add(className)` instead." - ); - if (!node) return; - if (node.className == className) return; // already a class - var s = node.className.split(" "); - for (var i = 0; i < s.length; i++) { - if (s[i] == className) return; // already a class - } - if (!node.className) node.className = className; - else node.className += " " + className; -}; - -/** - * Removes a class name from a DOM node. - * - * @param {object} node The DOM element from which the class name is removed. - * @param {string} className The class name to remove. - * - * @memberof CIQ - * @deprecated As of 8.0.0. Use [Element.classList.remove(className)]{@link https://developer.mozilla.org/en-US/docs/Web/API/DOMTokenList/remove}. - */ -CIQ.unappendClassName = function (node, className) { - log( - "CIQ.unappendClassName() has been deprecated. Use `node.classList.remove(className)` instead." - ); - if (!node) return; - if (node.className.indexOf(className) == -1) return; - if (node.className == className) { - node.className = ""; - } else { - var s = node.className.split(" "); - var newClassName = ""; - for (var i = 0; i < s.length; i++) { - if (s[i] == className) continue; - if (newClassName !== "") newClassName += " "; - newClassName += s[i]; - } - node.className = newClassName; - } -}; - -/** - * Convenience method for swapping two class names on a DOM node. Typically used to change - * state. - * - * @param {object} node The DOM element on which the class names are swapped. - * @param {string} newClassName The class name to swap in. - * @param {string} oldClassName The class name to swap out. - * - * @memberof CIQ - * @deprecated As of 8.0.0. Use [Element.classList.replace(oldClassName, newClassName)]{@link https://developer.mozilla.org/en-US/docs/Web/API/DOMTokenList/replace}. - */ -CIQ.swapClassName = function (node, newClassName, oldClassName) { - log( - "CIQ.swapClassName() has been deprecated. Use `node.classList.replace(oldClassName, newClassName)` instead." - ); - CIQ.unappendClassName(node, oldClassName); - CIQ.appendClassName(node, newClassName); -}; - -/** - * Determines whether a class name is currently assigned to a DOM element. - * - * @param {object} node The DOM node checked for the presence of the class name. - * @param {string} className The class name for which to check. - * @return {boolean} True, if the class name is currently assigned to the DOM element; - * otherwise, false. - * - * @memberof CIQ - * @deprecated As of 8.0.0. Use [Element.classList.contains(className)]{@link https://developer.mozilla.org/en-US/docs/Web/API/DOMTokenList/contains}. - */ -CIQ.hasClassName = function (node, className) { - log( - "CIQ.hasClassName() has been deprecated. Use `node.classList.contains(className)` instead." - ); - if (!node) return false; - if ((" " + node.className + " ").indexOf(" " + className + " ") > -1) - return true; - return false; -}; - -/** - * Toggles the class name on or off on a DOM element. - * - * @param {HTMLElement} node The DOM element on which the class name is toggled on or off. - * @param {string} className The class name to toggle on or off. - * - * @memberof CIQ - * @deprecated As of 8.0.0. Use [Element.classList.toggle(className)]{@link https://developer.mozilla.org/en-US/docs/Web/API/DOMTokenList/toggle}. - */ -CIQ.toggleClassName = function (node, className) { - log( - "CIQ.toggleClassName() has been deprecated. Use `node.classList.toggle(className)` instead." - ); - if (CIQ.hasClassName(node, className)) CIQ.unappendClassName(node, className); - else CIQ.appendClassName(node, className); -}; - -/* - * http://www.backalleycoder.com/2013/03/18/cross-browser-event-based-element-resize-detection/ - */ - -(function () { - var attachEvent = document.attachEvent; - var isIE = navigator.userAgent.match(/Trident/); - var requestFrame = (function () { - var raf = - window.requestAnimationFrame || - window.mozRequestAnimationFrame || - window.webkitRequestAnimationFrame || - function (fn) { - return setTimeout(fn, 20); - }; - return function (fn) { - return raf(fn); - }; - })(); - - var cancelFrame = (function () { - var cancel = - window.cancelAnimationFrame || - window.mozCancelAnimationFrame || - window.webkitCancelAnimationFrame || - window.clearTimeout; - return function (id) { - return cancel(id); - }; - })(); - - function resizeListener(e) { - var win = e.target || e.srcElement; - if (win.__resizeRAF__) cancelFrame(win.__resizeRAF__); - win.__resizeRAF__ = requestFrame(function () { - var trigger = win.__resizeTrigger__; - trigger.__resizeListeners__.forEach(function (fn) { - fn.call(trigger, e); - }); - }); - } - - function objectLoad(e) { - this.contentDocument.defaultView.__resizeTrigger__ = this.__resizeElement__; - this.contentDocument.defaultView.addEventListener("resize", resizeListener); - } - - /** - * **Deprecated since 7.4.0.** Use {@link CIQ.UI.addResizeListener} instead. - * - * Attaches a callback to listen for resize events on the DOM. - * - * Designed to be used as a helper method for the included {@link WebComponents}. A full tutorial on how to work with - * and customize the Web Components can be found here: {@tutorial Web Component Interface}. - * - * @param {node} element The node to which the listener is attached. - * @param {function} callback The listener function to attach to the DOM element. - * @memberof CIQ - * @deprecated As of 7.4.0. Use {@link CIQ.UI.addResizeListener}. - */ - CIQ.addResizeListener = function (element, fn) { - log( - "CIQ.addResizeListener() has been deprecated. Use CIQ.UI.addResizeListener() instead." - ); - var uiManager = document.querySelector("cq-ui-manager"); - if (uiManager.length > 0) { - uiManager = uiManager[0]; - uiManager.registerForResize(element); - } - if (!element.__resizeListeners__) { - element.__resizeListeners__ = []; - if (attachEvent) { - element.__resizeTrigger__ = element; - element.attachEvent("onresize", resizeListener); - } else { - //if (!getComputedStyle(element) || getComputedStyle(element).position == 'static') element.style.position = 'relative'; - var obj = (element.__resizeTrigger__ = document.createElement( - "object" - )); - obj.setAttribute( - "style", - "visibility:hidden; display: block; position: absolute; top: 0; left: 0; height: 100%; width: 100%; overflow: hidden; pointer-events: none; z-index: -1; border:0px;" - ); - obj.__resizeElement__ = element; - obj.onload = objectLoad; - obj.type = "text/html"; - if (isIE) element.appendChild(obj); - obj.data = "about:blank"; - if (!isIE) element.appendChild(obj); - } - } - element.__resizeListeners__.push(fn); - }; - - /** - * Removes an attached resize event listener from a DOM element. - * - * Designed to be used as a helper method for the included {@link WebComponents}. - * A full tutorial on how to work with and customize the Web Components can be found here: {@tutorial Web Component Interface}. - * - * @param {node} element The node from which the listener is removed. - * @param {function} callback The listener function to be removed. - * @memberof CIQ - * @deprecated As of 7.4.0. Use {@link CIQ.UI.removeResizeListener}. - */ - CIQ.removeResizeListener = function (element, fn) { - log( - "CIQ.removeResizeListener() has been deprecated. Use CIQ.UI.removeResizeListener() instead." - ); - var uiManager = document.querySelector("cq-ui-manager"); - if (uiManager.length > 0) { - uiManager = uiManager[0]; - uiManager.unregisterForResize(element); - } - element.__resizeListeners__.splice( - element.__resizeListeners__.indexOf(fn), - 1 - ); - if (!element.__resizeListeners__.length) { - if (attachEvent) element.detachEvent("onresize", resizeListener); - else { - element.__resizeTrigger__.contentDocument.defaultView.removeEventListener( - "resize", - resizeListener - ); - element.__resizeTrigger__ = !element.removeChild( - element.__resizeTrigger__ - ); - } - } - }; -})(); - -/** - * This function is no longer used by the library. Use {@link CIQ.Renderer#adjustYAxis} instead. - * @memberof CIQ.Renderer - * @deprecated As of 5.2.0. no longer used in library.. - */ -CIQ.Renderer.prototype.performCalculations = function () { - log( - "CIQ.Renderer.prototype.performCalculations has been deprecated. Use CIQ.Renderer.prototype.adjustYAxis instead." - ); -}; - -/** - * **Deprecated** Use {@link CIQ.ChartEngine.XAxis#noDraw} and {@link CIQ.ChartEngine.YAxis#noDraw} instead. - * - * Override this function to hide the date which floats along the X axis when crosshairs are enabled. Return `true` to hide the date or `false` to display. - * @memberof CIQ.ChartEngine - * @deprecated as of 6.0.0 no longer used in library. - */ -CIQ.ChartEngine.hideDates = function () { - log( - "CIQ.Renderer.hideDates is no longer supported. To hide an axis, set its noDraw property. To hide the floating date label, set stxx.controls.floatDate=null." - ); - return false; -}; - -/** - * Returns true if the chartType displays OHL data. - * @param {string} chartType The chart type (layout.chartType) - * @return {boolean} True if the chart type only displays close values - * @memberof CIQ.ChartEngine - * @since 05-2016-10.1 "baseline_delta_mountain" and "colored_mountain" are also available. - * @deprecated - */ -CIQ.ChartEngine.chartShowsHighs = function (chartType) { - log( - "CIQ.ChartEngine.prototype.chartShowsHighs has been deprecated. Use CIQ.ChartEngine.Chart.prototype.highLowBars instead." - ); - if ( - { - line: 1, - colored_line: 1, - mountain: 1, - colored_mountain: 1, - baseline_delta: 1, - baseline_delta_mountain: 1, - histogram: 1, - scatterplot: 1, - step: 1, - colored_step: 1 - }[chartType] == 1 - ) - return false; - return true; -}; - -/** - * Draws a filled rectangle on the chart. - * - * @param {number} left The x-axis coordinate of the starting point of the rectangle. - * @param {number} width The width of the rectangle. - * @param {number} top The y-axis coordinate of the starting point of the rectangle. - * @param {number} height The height of the rectangle. - * @param {string} className A CSS class name used to set the fill color of the rectangle. - * @param {external:CanvasRenderingContext2D} [context] The canvas context on which the - * rectangle is drawn. If this parameter is not provided, the chart context is used. - * - * @memberOf CIQ.ChartEngine - * @deprecated As of 8.0.0. Use [CanvasRenderingContext2D.fillRect()]{@link https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/fillRect}. - */ -CIQ.ChartEngine.prototype.createBlock = function ( - left, - width, - top, - height, - className, - context -) { - log( - "CIQ.ChartEngine.prototype.createBlock has been deprecated. Use native canvas context operation fillRect instead." - ); - if (!context) context = this.chart.context; - if (typeof height == "undefined") { - return; - } - this.canvasColor(className, context); - context.fillRect(left, top, width, height); - context.globalAlpha = 1; -}; - -/** - * Turns the volume underlay indicator on or off. - * - * @param {boolean} data True to turn on the underlay, false to turn it off. - * - * @memberof CIQ.ChartEngine - * @deprecated As of 8.0.0. To enable a volume underlay, use {@link CIQ.Studies.addStudy}; - * to disable a volume underlay, {@link CIQ.Studies.removeStudy}. - */ -CIQ.ChartEngine.prototype.setVolumeUnderlay = function (data) { - log( - "CIQ.ChartEngine.prototype.setVolumeUnderlay is no longer supported. To enable a volume underlay, use CIQ.Studies.addStudy(stxx, 'vol undr'). To disable, use CIQ.Studies.removeStudy." - ); - this.layout.volumeUnderlay = data; - if (this.chart.canvas) this.draw(); - this.changeOccurred("layout"); -}; - -/** - * Exports all of the drawings on the chart(s) so that they can be saved to an external database and later reconstructed. - * - * Note: This function has been renamed {@link CIQ.ChartEngine#exportDrawings}. - * - * @see {@link CIQ.ChartEngine#exportDrawings} - * @see {@link CIQ.ChartEngine#importDrawings} - * @return {array} An array of objects representing each drawing - * @memberof CIQ.ChartEngine - * @deprecated since 3.0.0 - */ -CIQ.ChartEngine.prototype.serializeDrawings = function () { - log( - "CIQ.ChartEngine.prototype.serializeDrawings has been deprecated. Use CIQ.ChartEngine.prototype.exportDrawings instead." - ); - return this.exportDrawings(); -}; - -/** - * Imports drawings from an array originally created by {@link CIQ.ChartEngine#serializeDrawings}. - * - * Note: This function and serializeDrawings have been renamed {@link CIQ.ChartEngine#importDrawings} and {@link CIQ.ChartEngine#exportDrawings} respectively. - * - * To immediately render the reconstructed drawings, you must call `draw()`. - * See {@tutorial Using and Customizing Drawing Tools} for more details. - * @see {@link CIQ.ChartEngine#exportDrawings} - * @see {@link CIQ.ChartEngine#importDrawings} - * @param {array} arr An array of serialized drawings - * @memberof CIQ.ChartEngine - * @deprecated since 4.0.0 - */ -CIQ.ChartEngine.prototype.reconstructDrawings = function (arr) { - log( - "CIQ.ChartEngine.prototype.reconstructDrawings has been deprecated. Use CIQ.ChartEngine.prototype.importDrawings instead." - ); - this.importDrawings(arr); -}; - -// @deprecated Use pixelFromBar -CIQ.ChartEngine.prototype.computePosition = function (x, offset) { - log( - "CIQ.ChartEngine.prototype.computePosition has been deprecated. Use CIQ.ChartEngine.prototype.pixelFromBar instead." - ); - if (typeof offset == "undefined") offset = 0; - var position = x * this.layout.candleWidth + offset + this.micropixels; - return position; -}; - -// @deprecated -CIQ.ChartEngine.prototype.computeColor = function (open, close) { - log( - "CIQ.ChartEngine.prototype.computeColor has been deprecated. There is no suggested alternative." - ); - if (open < close) return "stx_candle_up"; - if (open > close) return "stx_candle_down"; - return "stx_candle_shadow"; -}; - -// @deprecated -CIQ.ChartEngine.prototype.computeLength = function (high, low) { - log( - "CIQ.ChartEngine.prototype.computeLength has been deprecated. Use CIQ.ChartEngine.prototype.pixelFromPrice to compute values and find the difference." - ); - var h = this.pixelFromPrice(high); - var l = this.pixelFromPrice(low); - return l - h; -}; - -// deprecated -CIQ.ChartEngine.prototype.setCrosshairColors = function () { - log( - "CIQ.ChartEngine.prototype.setCrosshairColors is no longer supported. Use CSS to set the crosshair color" - ); -}; - -/** - * A version of {@link CIQ.ChartEngine#valueFromPixel} that will untransform a transformation such as a comparison chart. - * @param {number} y The y pixel location - * @param {CIQ.ChartEngine.Panel} panel A panel object. It is strongly recommended to pass the panel! (see {@link CIQ.ChartEngine#valueFromPixel}) - * @param {CIQ.ChartEngine.YAxis} [yAxis] The yaxis to use. Defaults to panel.yAxis. - * @return {number} The price or value - * @memberof CIQ.ChartEngine - * @deprecated Use {@link CIQ.ChartEngine#valueFromPixel} instead - */ -CIQ.ChartEngine.prototype.valueFromPixelUntransform = function ( - y, - panel, - yAxis -) { - log( - "CIQ.ChartEngine.prototype.valueFromPixelUntransform has been deprecated. Use CIQ.ChartEngine.prototype.valueFromPixel instead." - ); - return this.valueFromPixel(y, panel, yAxis); -}; - -/** - * > ** This function has been deprecated in favor of {@link CIQ.ChartEngine#pixelFromPrice}. It should no longer be used. - * >
Use {@link CIQ.ChartEngine#pixelFromTransformedValue} to get the pixel location based on the transformed value (percentage comparison change, for example). - * - * @param {number} price The price or value - * @param {CIQ.ChartEngine.Panel} panel A panel object (see {@link CIQ.ChartEngine#pixelFromPrice}) - * @param {CIQ.ChartEngine.YAxis} [yAxis] The yaxis to use - * @return {number} The y axis pixel location - * @memberof CIQ.ChartEngine - * @deprecated Use {@link CIQ.ChartEngine#pixelFromPrice} instead - * @since 4.0.0 Now behaves like pixelFromPriceTransform. That is, on a comparison chart, pixelFromPrice accepts an actual stock price, not a percentage value. - */ -CIQ.ChartEngine.prototype.pixelFromPriceTransform = function ( - price, - panel, - yAxis -) { - log( - "CIQ.ChartEngine.prototype.pixelFromPriceTransform has been deprecated. Use CIQ.ChartEngine.prototype.pixelFromPrice instead." - ); - return this.pixelFromPrice(price, panel, yAxis); -}; - -//deprecated, use static version -CIQ.ChartEngine.prototype.isDailyInterval = function (interval) { - log( - "CIQ.ChartEngine.prototype.isDailyInterval has been deprecated. Use CIQ.ChartEngine.isDailyInterval instead." - ); - return CIQ.ChartEngine.isDailyInterval(interval); -}; - -/** - * Renders a chart for a particular instrument from the data passed in or fetches new data from the attached {@link quotefeed}. - * - * This method has been deprecated, use {@link CIQ.ChartEngine#loadChart}. - * - * @param {string|object} symbol The symbol or equation for the new chart - a symbol string, equation or an object representing the symbol can be used. - *
After the new chart is initialized, it will contain both a symbol string (stxx.chart.symbol) and a symbol object (stxx.chart.symbolObject). - *
You can send anything you want in the symbol object, but you must always include at least a 'symbol' element. Both these variables will be available for use wherever the {@link CIQ.ChartEngine.Chart} object is present. For example, if using a {@link quotefeed} for gathering data, params.stx.chart.symbolObject will contain your symbol object. - *
To allow equations to be used on a chart, the {@link CIQ.ChartEngine#allowEquations} parameter must be set to `true` and the equation needs to be preceded by an equals sign (=) in order for it to be parsed as an equation. - *
See {@link CIQ.formatEquation} and {@link CIQ.computeEquationChart} for more details on allowed equations syntax. - * @param {array} [masterData] An array of [properly formatted OHLC objects]{@tutorial InputDataFormat} to create a chart. Each element should at a minimum contain a "Close" field (capitalized). - * If the charting engine has been configured to use a [QuoteFeed]{@link CIQ.ChartEngine#attachQuoteFeed} - * then masterData does not need to be passed in. The quote feed will be queried instead. - * @param {CIQ.ChartEngine.Chart} chart] Which chart to create. Defaults to the default chart. - * @param {function} [cb] Callback when newChart is loaded. See {@tutorial Adding additional content on chart} for a tutorial on how to use this callback function. - * @param {object} [params] Parameters to dictate initial rendering behavior - * @param {Object} [params.range] Default range to be used upon initial rendering. If both `range` and `span` parameters are passed in, range takes precedence. If periodicity is not set, the range will be displayed at the most optimal periodicity. See {@link CIQ.ChartEngine#setRange} for complete list of parameters this object will accept. - * @param {object} [params.span] Default span to display upon initial rendering. If both `range` and `span` parameters are passed in, range takes precedence. If periodicity is not set, the span will be displayed at the most optimal periodicity. See {@link CIQ.ChartEngine#setSpan} for complete list of parameters this object will accept. - * @param {object} [params.periodicity] Periodicity to be used upon initial rendering. See {@link CIQ.ChartEngine#setPeriodicity} for complete list of parameters this object will accept. If no periodicity has been set it will default to `1 day`. - * @param {boolean} [params.stretchToFillScreen] Increase the candleWidth to fill the left-side gap created by a small dataSet. Respects CIQ.ChartEngine.preferences.whitespace. Ignored when params `span` or `range` are used. See {@link CIQ.ChartEngine#fillScreen} - * @memberof CIQ.ChartEngine - * @example - * // using a symbol object and embedded span and periodicity requirements - * stxx.newChart( - * {symbol:newSymbol,other:'stuff'}, - * null, - * null, - * callbackFunction, - * { - * span:{base:'day',multiplier:2}, - * periodicity:{period:1,interval:5,timeUnit:'minute'}, - * stretchToFillScreen:true - * } - * ); - * - * @example - * // using a symbol string - * stxx.newChart( - * "IBM", - * null, - * null, - * callbackFunction - * ); - * - * @example - * // using an equation string - * stxx.newChart( - * "=2*IBM-GM", - * null, - * null, - * callbackFunction - * ); - * - * @deprecated use {@link CIQ.ChartEngine#loadChart} - * @since - * - 2015-11-1 newChart is capable of setting periodicity and span via `params` settings. - * - 04-2016-08 Added `params.stretchToFillScreen`. - * - 5.1.0 newChart is capable of setting range via `params` settings. - * - 6.0.0 Statically provided data will be gap-filled if that functionality is enabled. - * - 7.0.0 Deprecated, replaced by {@link CIQ.ChartEngine#loadChart}. - */ -CIQ.ChartEngine.prototype.newChart = function ( - symbol, - masterData, - chart, - cb, - params -) { - log( - "CIQ.ChartEngine.prototype.newChart has been deprecated. Use CIQ.ChartEngine.prototype.loadChart instead." - ); - var parameters = { - masterData: masterData, - chart: chart - }; - CIQ.extend(parameters, params, true); - // console.log('WARNING: newChart is deprecated for removal. Please use loadChart.'); - return this.loadChart(symbol, parameters, cb); -}; - -/** - * Streams "last sale" prices into the chart. - * - * - * >**This function has been deprecated in favor of {@link CIQ.ChartEngine#updateChartData}. - * This also means that {@link CIQ.ChartEngine#streamParameters.fillGaps} is deprecated. - * Developers should instead call {@link CIQ.ChartEngine#updateChartData} with `params.fillGaps=true` or rely on cleanupGaps as default behavior.** - * - * >`streamTrade` to `updateChartData` migration examples: - * - * >Note that updateChartData follows the 'OHLC' format. - * So `V`olume (upper case) is used rather than `v`olume (lower case). - * Similarly `L`ast (upper case) is used rather than `l`ast (lower case). - * - * >Example 1: streaming a secondary series: - * - * >`streamTrade({"last":102.05}, null, "IBM");` - *
Translates to :
- * `updateChartData({"Last":102.05}, null, {fillGaps: true, secondarySeries: "IBM"});` - * - * >Example 2: streaming a primary series: - * - * >`streamTrade({"last":102.05, "volume":100});` - *
Translates to :
- * `updateChartData({"Last": 102.05,"Volume":100}, null, {fillGaps: true});` - * - * This method is designed to append ticks to the master data while maintaining the existing periodicity, appending to the last tick or creating new ticks as needed. - * It will also fill in gaps if there are missing bars in a particular interval. - * If a trade has a date older than the beginning of the next bar, the last bar will be updated even if the trade belongs to a prior bar; this could happen if a trade is sent in after hours at a time when the market is closed, or if it is received out of order. - * When in 'tick' interval, each trade will be added to a new bar and no aggregation to previous bars will be done. - * If the optional timestamp [now] is sent in, and it is older than the next period to be rendered, the last tick on the dataset will be updated instead of creating a new tick. - * - * **It is crucial that you ensure the date/time of the trade is in line with your `masterData` and `dataZone`** See `now` parameter for more details. - * - * This method leverages {@link CIQ.ChartEngine#updateChartData} for the actual data insertion into masterData. Please see {@link CIQ.ChartEngine#updateChartData} for additional details and performance throttle settings. - * - * See the [Streaming]{@tutorial DataIntegrationStreaming} tutorial for more the details. - * - * **Note:** versions prior to 15-07-01 must use the legacy arguments : streamTrade(price, volume, now, symbol) - * - * @param {object} data Price & Volume Data, may include any or all of the following: - * @param {number} data.last Last sale price - * @param {number} [data.volume] Trade volume - * @param {number} [data.bid] Bid price - * @param {number} [data.ask] Offer/Ask price - * @param {date} [now] Date of trade. It must be a java script date [new Date().getTime()]. **If omitted, defaults to "right now" in the set `dataZone`** (see {@link CIQ.ChartEngine#setTimeZone}); or if no `dataZone` is set, it will default to the browser's timezone (not recommended for international client-base since different users will see different times). It is important to note that this value must be in the same timezone as the rest of the masterData already sent into the charting engine to prevent tick gaps or overlaps. - * @param {string} [symbol] trade symbol for series streaming ONLY. Leave out or set to `null` when streaming the primary chart symbol. - * @param {object} [params] Params to be passed to {@link CIQ.ChartEngine#updateChartData} - * @memberof CIQ.ChartEngine - * @example - * // streaming last sale for the primary chart symbol - * stxx.streamTrade({"last":102.05, "volume":100}); - * @example - * // streaming last sale for an additional series on the chart - * stxx.streamTrade({"last":102.05, "volume":100}, null, "IBM"); - * @deprecated Please use {@link CIQ.ChartEngine#updateChartData} for streaming last ticket. - * @since 4.0.0 Deprecated this function. This also means that streamParameters.fillGaps is deprecated. Developers should - * call {@link CIQ.ChartEngine#updateChartData} with `params.fillGaps=true` or rely on cleanupGaps as default behavior. - */ -CIQ.ChartEngine.prototype.streamTrade = function ( - priceData, - now, - symbol, - params -) { - log( - "CIQ.ChartEngine.prototype.streamTrade has been deprecated. Use CIQ.ChartEngine.prototype.updateChartData instead." - ); - var chart = this.chart; - if (!params) params = {}; - if (params.chart) chart = params.chart; - params.fillGaps = this.streamParameters.fillGaps; - var newArgs = typeof priceData == "object"; - - var price = newArgs ? priceData.last : arguments[0], - volume = newArgs ? priceData.volume : arguments[1], - bid = newArgs ? priceData.bid : null, - ask = newArgs ? priceData.ask : null; - - if (!newArgs) { - now = arguments[2]; - symbol = arguments[3]; - } - - if (symbol) { - //series element - params.secondarySeries = symbol; - } - - var data = { - DT: now, - Last: price, - Volume: volume, - Bid: bid, - Ask: ask - }; - - this.updateChartData(data, chart, params); -}; - -/** - * As of version 5.1, his method has been **deprecated** in favor of {@link CIQ.ChartEngine#updateChartData} which provides improved functionality. - * - * The following parameters are only applicable for legacy versions (pre 5.1): - * @deprecated Please use {@link CIQ.ChartEngine#updateChartData} - * @param {array/object} appendQuotes An array of properly formatted OHLC quote object(s). [See Data Format]{@tutorial InputDataFormat}.
- * Or a last sale object with the following elements: - * @param {number} appendQuotes.Last Last sale price - * @param {number} [appendQuotes.Volume] Trade volume - * @param {number} [appendQuotes.Bid] Bid price - * @param {number} [appendQuotes.Ask] Offer/Ask price - * @param {number} [appendQuotes.DT] Date of trade. - * It must be a java script date [new Date().getTime()]. - * **If omitted, defaults to "right now" in the set `dataZone`** (see {@link CIQ.ChartEngine#setTimeZone}); - * or if no `dataZone` is set, it will default to the browser's timezone (not recommended for international client-base since different users - * will see different times). It is important to note that this value must be in the same timezone as the rest of the masterData already - * sent into the charting engine to prevent tick gaps or overlaps. - * @param {CIQ.ChartEngine.Chart} [chart] The chart to append the quotes. Defaults to the default chart. - * @param {object} [params] Parameters to dictate behavior - * @param {boolean} [params.noCreateDataSet] If true then do not create the data set automatically, just add the data to the masterData - * @param {boolean} [params.allowReplaceOHL] Set to true to bypass internal logic that maintains OHL - * @param {boolean} [params.bypassGovernor] If true then masterdata will be immediately updated regardless of {@link CIQ.ChartEngine#streamParameters} - * @param {boolean} [params.fillGaps] If true then {@link CIQ.ChartEngine#doCleanupGaps} is called using the {@link CIQ.ChartEngine#cleanupGaps} setting. This will ensure gaps will be filled in the master data from the last tick in the chart to the date of the trade.
Reminder: `tick` does not fill any gaps as it is not a predictable interval. - * @param {boolean} [params.secondarySeries] Set to the name of the element ( valid comparison symbol, for example) to load data as a secondary series. - * @param {boolean} [params.useAsLastSale] If not using a 'last sale' formatted object in `appendQuotes`, - * you can simply set this parameter to `true` to force the data as a last sale price; or further define it by creating an object including other settings as needed. - * This option is available in cases when a feed may always return OHLC formatted objects or a 'Close' field instead of a 'Last' field, - * even for last sale streaming updates. - * By definition a 'last' sale can only be a single record indicating the very 'last' sale price. As such, even if multiple records are sent in the `appendQuotes` array when this flag is enabled, - * only the last record's data will be used. Specifically the 'Close' and 'Volume' fields will be streamed. - * @param {boolean} [params.useAsLastSale.aggregatedVolume] If your last sale updates send current volume for the bar instead of just the trade volume, set this parameter to 'true' in the `params.useAsLastSale` object. The sent in volume will be used as is instead of being added to the existing bar's volume. - * - * @memberof CIQ.ChartEngine - * @since - * - 2015-11-1 Added `params.bypassGovernor` and `params.allowReplaceOHL`. - * - 2015-11-1 Deprecated `params.force`. Every call will update the tick to maintain the proper volume, and `createDataSet` is now controlled by `sp.maxTicks`, `sp.timeout`, or `params.bypassGovernor`. - * - 3.0.0 Now `appendQuotes` also takes last sale data to allow streaming capabilities. This can now be used instead of streamTrade. - * - 3.0.0 New `params.fillGaps`, `params.secondarySeries`, and `params.useAsLastSale`. - * - 4.0.0 Last sale streaming will now update a bar in the past to comply with the date sent in instead of just updating the current tick. - * - 4.0.3 Added `params.useAsLastSale.aggregatedVolume`. - * - 5.0.1 Now calls doCleanupDates in case is is being called directly when not using a quoteFeed, to update an entire candle. - */ -CIQ.ChartEngine.prototype.appendMasterData = function ( - appendQuotes, - chart, - params -) { - log( - "CIQ.ChartEngine.prototype.appendMasterData has been deprecated. Use CIQ.ChartEngine.prototype.updateChartData instead." - ); - this.updateChartData(appendQuotes, chart, params); -}; - -/** - * INJECTABLE - * - * **Legacy** function to set the periodicity and interval for the chart. - * - * **Replaced by {@link CIQ.ChartEngine#setPeriodicity}, but maintained for backwards comparibility. Uses same function signature.** - * - * @param {number} period The number of elements from masterData to roll-up together into one data point on the chart (one candle, for example). If set to 30 in a candle chart, for example, each candle will represent 30 raw elements of `interval` type. - * @param {string} interval The type of data to base the `period` on. This can be a numeric value representing minutes, seconds or millisecond as inicated by `timeUnit`, "day","week", "month" or 'tick' for variable time x-axis. **"hour" is NOT a valid interval.** (This is not how much data you want the chart to show on the screen; for that you can use {@link CIQ.ChartEngine#setRange} or {@link CIQ.ChartEngine#setSpan}) - * @param {string} [timeUnit] Time unit to further qualify the specified numeric interval. Valid values are "millisecond","second","minute",null. If not set, will default to "minute". **only applicable and used on numeric intervals** - * @param {function} [cb] Callback after periodicity is changed. First parameter of callback will be null unless there was an error. - * - * @memberof CIQ.ChartEngine - * @since - * - 2015-11-1 Second and millisecond periodicities are now supported by setting the `timeUnit` parameter. - * - 3.0.0 Replaced by {@link CIQ.ChartEngine#setPeriodicity}, but maintained for backwards comparibility. - * - 8.0.0 Deprecated - * @deprecated Use {@link CIQ.ChartEngine#setPeriodicity}. - */ -CIQ.ChartEngine.prototype.setPeriodicityV2 = function ( - period, - interval, - timeUnit, - cb -) { - log( - "CIQ.ChartEngine.prototype.setPeriodicityV2 has been deprecated. Use CIQ.ChartEngine.prototype.setPeriodicity instead." - ); - if (typeof timeUnit === "function") { - cb = timeUnit; // backward compatibility - timeUnit = null; - } - if (this.runPrepend("setPeriodicityV2", arguments)) return; - this.setPeriodicity(period, interval, timeUnit, cb); - this.runAppend("setPeriodicityV2", arguments); -}; - -//Unused -CIQ.ChartEngine.prototype.addChart = function (name, chart) { - log( - "CIQ.ChartEngine.prototype.addChart has been deprecated. Add manually to stxx.charts object instead." - ); - chart.name = name; - this.charts[name] = chart; -}; - -var changeOccurred = CIQ.ChartEngine.prototype.changeOccurred; -CIQ.ChartEngine.prototype.changeOccurred = function (change) { - if (this.currentlyImporting) return; - if (this.changeCallback) this.changeCallback(this, change); - changeOccurred.call(this, change); -}; - -var engineConstruct = CIQ.ChartEngine.prototype.construct; -CIQ.ChartEngine.prototype.construct = function () { - function getValue(obj, name, def) { - if (!obj._deprecatedPropertyValues) obj._deprecatedPropertyValues = {}; - if (!(name in obj._deprecatedPropertyValues)) - obj._deprecatedPropertyValues[name] = def; - return obj._deprecatedPropertyValues[name]; - } - function setValue(obj, name, val) { - if (!obj._deprecatedPropertyValues) obj._deprecatedPropertyValues = {}; - obj._deprecatedPropertyValues[name] = val; - } - - engineConstruct.call(this); - - Object.defineProperties(this, { - /** - * **This function has been deprecated. Please use {@link CIQ.ChartEngine#addEventListener} instead.** - * - * This is the callback function used to react to {@link CIQ.ChartEngine#changeOccurred}. - * - * Use this for storing chart configurations or drawings real time as users make changes. - * - * Expected format : - * - * fc(stxChart, eventType); - * - * Currently implemented values for "eventType" are "layout" and "vector". - * - * You can create any additional event types and trigger them by calling 'CIQ.ChartEngine.changeOccurred(eventType)' - * - * **Note** only one changeCallback function can be registered per chart object. As such, you must program it to handle any and all possible events triggered by {@link CIQ.ChartEngine#changeOccurred}. - * @type {function} - * @alias changeCallback - * @memberof CIQ.ChartEngine.prototype - * @deprecated - * @since 4.0.0 Deprecated - * @example - * stxx.changeCallback=function(stxx, eventType){ - * if(eventType=="layout") saveLayout(); - * if(eventType=="vector") saveDrawing(); - * } - */ - changeCallback: { - enumerable: true, - get: (function (stx) { - return function () { - //log("CIQ.ChartEngine.prototype.changeCallback has been deprecated. Use CIQ.ChartEngine.prototype.addEventListener instead."); - return getValue(this, "changeCallback", null); - }; - })(this), - set: (function (stx) { - return function (func) { - log( - "CIQ.ChartEngine.prototype.changeCallback has been deprecated. Use CIQ.ChartEngine.prototype.addEventListener instead." - ); - setValue(this, "changeCallback", func); - }; - })(this) - }, - /** - * Chart types which plot more than one data field (OHLC charts). - * Putting a chart type here will disable the use of {@link CIQ.ChartEngine.Chart#defaultPlotField}. - * @type object - * @default - * @alias highLowBars - * @deprecated, access property in chart instead (stxx.chart.highLowBars) - * @memberof CIQ.ChartEngine.prototype - * @since 4.0.0 - */ - highLowBars: { - enumerable: true, - get: (function (stx) { - return function () { - log( - "CIQ.ChartEngine.prototype.highLowBars is no longer supported. Use CIQ.ChartEngine.Chart.prototype.highLowBars instead." - ); - return getValue(this, "highLowBars", { - bar: true, - colored_bar: true, - candle: true, - hollow_candle: true, - volume_candle: true, - hlc: true, - colored_hlc: true, - hlc_box: true, - hlc_shaded_box: true, - wave: true, - rangechannel: true, - none: true - }); - }; - })(this), - set: (function (stx) { - return function (val) { - log( - "CIQ.ChartEngine.prototype.highLowBars is no longer supported. Use CIQ.ChartEngine.Chart.prototype.highLowBars instead." - ); - setValue(this, "highLowBars", val); - }; - })(this) - }, - /** - * Chart types whose bars represent a stand-alone entity as opposed to a vertex in a line-type chart. - * This is important when the engine tries to render the data points right off the chart; in a stand-alone bar, - * the points right off the chart need not be considered. - * @type object - * @default - * @alias standaloneBars - * @deprecated, access property in chart instead (stxx.chart.standaloneBars) - * @memberof CIQ.ChartEngine.prototype - * @since 4.0.0 - */ - standaloneBars: { - enumerable: true, - get: (function (stx) { - return function () { - log( - "CIQ.ChartEngine.prototype.standaloneBars is no longer supported. Use CIQ.ChartEngine.Chart.prototype.standaloneBars instead." - ); - return getValue(this, "standaloneBars", { - bar: true, - colored_bar: true, - candle: true, - hollow_candle: true, - volume_candle: true, - hlc: true, - colored_hlc: true, - hlc_box: true, - hlc_shaded_box: true, - histogram: true, - scatterplot: true - }); - }; - })(this), - set: (function (stx) { - return function (val) { - log( - "CIQ.ChartEngine.prototype.standaloneBars is no longer supported. Use CIQ.ChartEngine.Chart.prototype.standaloneBars instead." - ); - setValue(this, "standaloneBars", val); - }; - })(this) - }, - /** - * Chart types whose bars have width, as opposed to a line-type chart whose "bars" are just a point on the chart. - * This is useful when the engine adjusts the chart for smooth scrolling and homing. - * @type object - * @default - * @alias barsHaveWidth - * @deprecated, access property in chart instead (stxx.chart.barsHaveWidth) - * @memberof CIQ.ChartEngine.prototype - * @since 4.0.0 - */ - barsHaveWidth: { - enumerable: true, - get: (function (stx) { - return function () { - log( - "CIQ.ChartEngine.prototype.barsHaveWidth is no longer supported. Use CIQ.ChartEngine.Chart.prototype.barsHaveWidth instead." - ); - return getValue(this, "barsHaveWidth", { - bar: true, - colored_bar: true, - candle: true, - hollow_candle: true, - volume_candle: true, - hlc: true, - colored_hlc: true, - hlc_box: true, - hlc_shaded_box: true, - histogram: true, - scatterplot: true, - wave: true - }); - }; - })(this), - set: (function (stx) { - return function (val) { - log( - "CIQ.ChartEngine.prototype.barsHaveWidth is no longer supported. Use CIQ.ChartEngine.Chart.prototype.barsHaveWidth instead." - ); - setValue(this, "barsHaveWidth", val); - }; - })(this) - } - }); - - /** - * Specify a callback by assigning a function to the event. Once the event triggers the callback will be executed. - * - * **Note: All callbacks have been deprecated in favor of {@link CIQ.ChartEngine#addEventListener}** - * - * @type object - * @alias callbacks - * @memberof CIQ.ChartEngine# - * @example - * // using event listener - * stxx.addEventListener("callbackNameHere", function(callBackParametersHere){ - * CIQ.alert('triggered!'); - * }); - * @example - * // using callback function - * stxx.callbacks.callbackNameHere=function(callBackParametersHere){ - * CIQ.alert('triggered!'); - * }; - * @deprecated 4.0.0 - */ - this.callbacks = {}; - - function callbackGetter(name, stx, def) { - return function () { - log( - "CIQ.ChartEngine.prototype.callbacks have been deprecated. Iterate through CIQ.ChartEngine.prototype.callbackListeners instead." - ); - return getValue(this, name, def || null); - }; - } - - function callbackSetter(name, stx) { - return function (func) { - log( - "CIQ.ChartEngine.prototype.callbacks have been deprecated. Utilize CIQ.ChartEngine.prototype.addEventListener to add a callback, and/or CIQ.ChartEngine.prototype.removeEventListener to remove one." - ); - if (!this._deprecatedPropertyValues) this._deprecatedPropertyValues = {}; - var origFunc = this._deprecatedPropertyValues[name]; - if (origFunc) stx.removeEventListener(name, origFunc); - if (func) stx.addEventListener(name, func); - this._deprecatedPropertyValues[name] = func; - }; - } - - Object.defineProperties(this.callbacks, { - /** - * Called when a user right clicks on an overlay study. If `forceEdit==true` then a user has clicked - * on an edit button (cog wheel) so pull up an edit dialog. Otherwise they have simply right clicked so - * give them a context menu. - * - * ***Please note that this callback must be set *before* you call {@link CIQ.ChartEngine#importLayout}. - * Otherwise your imported studies will not have an edit capability*** - * - * Format:
- * studyOverlayEdit({stx:stx,sd:sd,inputs:inputs,outputs:outputs, parameters:parameters, forceEdit: forceEdit}); - * - * The following CSS entry must also be present to enable the `Right click to Manage` text on the mouse-over context menu (div class="mSticky" generated by {@link CIQ.ChartEngine.htmlControls}): - * ``` - * .rightclick_study .mouseManageText { - * display: inline; } - * ``` - * See {@link CIQ.Studies.addStudy} for more details. - * - * @type function - * @alias CIQ.ChartEngine#callbacks[`studyOverlayEdit`] - * @memberof CIQ.ChartEngine#callbacks - */ - studyOverlayEdit: { - enumerable: true, - get: callbackGetter("studyOverlayEdit", this), - set: callbackSetter("studyOverlayEdit", this) - }, - /** - * Called when a user clicks the edit button on a study panel. - * - * ***Please note that this callback should be set *before* you call {@link CIQ.ChartEngine#importLayout}. - * Otherwise your imported studies will not have an edit capability*** - * - * Format:
- * studyPanelEdit({stx:stx,sd:sd,inputs:inputs,outputs:outputs, parameters:parameters}); - * - * See {@link CIQ.Studies.addStudy} for more details. - * - * @type function - * @alias CIQ.ChartEngine#callbacks[`studyPanelEdit`] - * @memberof CIQ.ChartEngine#callbacks - */ - studyPanelEdit: { - enumerable: true, - get: callbackGetter("studyPanelEdit", this), - set: callbackSetter("studyPanelEdit", this) - }, - /** - * Called when a user clicks or taps on the chart. Not called if a drawing tool is active! - * - * Format:
- * callback({stx:CIQ.ChartEngine, panel:CIQ.ChartEngine.Panel, x:this.cx, y:this.cy}) - * @type function - * @alias CIQ.ChartEngine#callbacks[`tap`] - * @memberof CIQ.ChartEngine#callbacks - * @example - * // using event listener - * stxx.addEventListener("tap", function(tapObject){ - * CIQ.alert('tap event at x: ' + tapObject.x + ' y: '+ tapObject.y); - * }); - * @example - * // using callback - * // this example uses barFromPixel() to get the actual bar from the pixel location - * stxx.callbacks.tap= function(tapObject){ - * var msg= 'tap event at x: ' + tapObject.x + ' y: '+ tapObject.y; - * var bar=this.barFromPixel(this.cx); - * if(this.chart.dataSegment[bar]) { - * msg+=' Date:' + this.chart.dataSegment[bar].DT; - * msg+=' Close:' + this.chart.dataSegment[bar].Close; - * } - * alert (msg); - * }; - */ - tap: { - enumerable: true, - get: callbackGetter("tap", this), - set: callbackSetter("tap", this) - }, - /** - * Called when a user clicks or right clicks on the chart. Not called if the user right clicks on a drawing or study - * when [stxx.bypassRightClick]{@link CIQ.ChartEngine#bypassRightClick}=true - * - * Format:
- * callback({stx:CIQ.ChartEngine, panel:CIQ.ChartEngine.Panel, x:this.cx, y:this.cy}) - * @type function - * @alias CIQ.ChartEngine#callbacks[`rightClick`] - * @memberof CIQ.ChartEngine#callbacks - * @example - * // using event listener - * stxx.addEventListener("rightClick", function(rcObject){ - * alert('right click event at x: ' + rcObject.x + ' y: '+ rcObject.y); - * }); - * @since 09-2016-19 - */ - rightClick: { - enumerable: true, - get: callbackGetter("rightClick", this), - set: callbackSetter("rightClick", this) - }, - /** - * Called when a user "long holds" on the chart. By default this is set to 700 milliseconds. - * Optionally change the value of stxx.longHoldTime to a different setting, or set to zero to disable. - * - * Format:
- * callback({stx:CIQ.ChartEngine, panel:CIQ.ChartEngine.Panel, x:this.cx, y:this.cy}) - * @type function - * @alias CIQ.ChartEngine#callbacks[`longhold`] - * @memberof CIQ.ChartEngine#callbacks - * @example - * // using event listener - * stxx.longHoldTime=... // Optionally override default value of 700ms - * stxx.addEventListener("longhold", function(lhObject){ - * CIQ.alert('longhold event at x: ' + lhObject.x + ' y: '+ lhObject.y); - * }); - * @example - * // using callback function - * stxx.longHoldTime=... // Optionally override default value of 700ms - * stxx.callbacks.longhold=function(lhObject){ - * CIQ.alert('longhold event at x: ' + lhObject.x + ' y: '+ lhObject.y); - * }); - * @since 2016-06-22 - */ - longhold: { - enumerable: true, - get: callbackGetter("longHold", this), - set: callbackSetter("longHold", this) - }, - /** - * Called when a user moves on the chart. Not called if a drawing tool is active, panel resizing, etc - * grab is true if a mouse user has the mouse button down while moving. For touch users it is true - * if they do not have the crosshair tool enabled. - * - * Format:
- * callback({stx:CIQ.ChartEngine, panel:CIQ.ChartEngine.Panel, x:this.cx, y:this.cy, grab:boolean}) - * @type function - * @alias CIQ.ChartEngine#callbacks[`move`] - * @memberof CIQ.ChartEngine#callbacks - */ - move: { - enumerable: true, - get: callbackGetter("move", this), - set: callbackSetter("move", this) - }, - /** - * Called when the layout changes - * - * Format:
- * callback({stx:CIQ.ChartEngine, chart:CIQ.ChartEngine.Chart, symbol: String, symbolObject:Object, layout: Object}) - * @type function - * @alias CIQ.ChartEngine#callbacks[`layout`] - * @memberof CIQ.ChartEngine#callbacks - */ - layout: { - enumerable: true, - get: callbackGetter("layout", this), - set: callbackSetter("layout", this) - }, - /** - * Called when a drawing is added or deleted (all the drawings are returned, not just the new one) - * - * Format:
- * callback({stx:CIQ.ChartEngine, symbol: String, symbolObject:Object, drawings: Object}) - * @type function - * @alias CIQ.ChartEngine#callbacks[`drawing`] - * @memberof CIQ.ChartEngine#callbacks - */ - drawing: { - enumerable: true, - get: callbackGetter("drawing", this), - set: callbackSetter("drawing", this) - }, - /** - * Called when a right-click is detected on a highlighted drawing. - * - * Format:
- * callback({stx:CIQ.ChartEngine, drawing:CIQ.Drawing}) - * @type function - * @alias CIQ.ChartEngine#callbacks[`drawingEdit`] - * @memberof CIQ.ChartEngine#callbacks - * @since 6.2.0 - */ - drawingEdit: { - enumerable: true, - get: callbackGetter("drawingEdit", this), - set: callbackSetter("drawingEdit", this) - }, - /** - * Called when preferences are changed - * - * Format:
- * callback({stx:CIQ.ChartEngine}) - * @type function - * @alias CIQ.ChartEngine#callbacks[`preferences`] - * @memberof CIQ.ChartEngine#callbacks - */ - preferences: { - enumerable: true, - get: callbackGetter("preferences", this), - set: callbackSetter("preferences", this) - }, - /** - * Called when a theme is changed - * - * Format:
- * callback({stx:CIQ.ChartEngine}) - * @type function - * @alias CIQ.ChartEngine#callbacks[`theme`] - * @memberof CIQ.ChartEngine#callbacks - */ - theme: { - enumerable: true, - get: callbackGetter("theme", this), - set: callbackSetter("theme", this) - }, - /** - * Called when the symbol is changed (when loadChart is called), added (addSeries, addStudy) or removed (removeSeries, removeStudy). Note - * that this is not called if the symbol change occurs during an importLayout - * - * Format:
- * callback({stx:CIQ.ChartEngine, symbol: String, symbolObject:Object, action:["master"|"add-series"|"remove-series"}) - * @type function - * @alias CIQ.ChartEngine#callbacks[`symbolChange`] - * @memberof CIQ.ChartEngine#callbacks - * @since 06-2016-21 - */ - symbolChange: { - enumerable: true, - get: callbackGetter("symbolChange", this), - set: callbackSetter("symbolChange", this) - }, - /** - * Called when the symbol is first imported into the layout. - * - * Format:
- * callback({stx:CIQ.ChartEngine, symbol: String, symbolObject:Object, action:"master"}) - * @type function - * @alias CIQ.ChartEngine#callbacks[`symbolImport`] - * @memberof CIQ.ChartEngine#callbacks - * @since 4.0.0 - */ - symbolImport: { - enumerable: true, - get: callbackGetter("symbolImport", this), - set: callbackSetter("symbolImport", this) - }, - /** - * Called to determine how many decimal places the stock trades in. - * - * This is used for heads up display and also for the current price pointer label. - * - * By default it is set to {@link CIQ.calculateTradingDecimalPlaces} - * - * Format:
- * callback({stx:CIQ.ChartEngine, chart:CIQ.ChartEngine.Chart, symbol: String, symbolObject:Object}) - * - * @type function - * @alias CIQ.ChartEngine#callbacks[`calculateTradingDecimalPlaces`] - * @memberof CIQ.ChartEngine#callbacks - * @deprecated As of 8.0.0. Use {@link CIQ.ChartEngine.Chart#calculateTradingDecimalPlaces}. - */ - calculateTradingDecimalPlaces: { - enumerable: true, - get: (function (stx) { - return function () { - log( - "CIQ.ChartEngine.prototype.callbacks.calculateTradingDecimalPlaces has been deprecated. Utilize CIQ.ChartEngine.Chart.prototype.calculateTradingDecimalPlaces instead." - ); - return getValue( - this, - "calculateTradingDecimalPlaces", - stx.chart.calculateTradingDecimalPlaces - ); - }; - })(this), - set: (function (stx) { - return function (func) { - log( - "CIQ.ChartEngine.prototype.callbacks.calculateTradingDecimalPlaces has been deprecated. Utilize CIQ.ChartEngine.Chart.prototype.calculateTradingDecimalPlaces instead." - ); - setValue(this, "calculateTradingDecimalPlaces", func); - stx.chart.calculateTradingDecimalPlaces = func; - }; - })(this) - } - }); - - /** - * If true then {@link CIQ.ChartEngine#doCleanupGaps} is called so long as {@link CIQ.ChartEngine#cleanupGaps} is also set. - * This will ensure gaps will be filled in the master data from the last tick in the chart to the date of the trade. - * - * **Only applicable when using streamTrade()**.
Reminder: `tick` does not fill any gaps as it is not a predictable interval. - * - * @type boolean - * @default - * @alias CIQ.ChartEngine#streamParameters[`fillGaps`] - * @memberof CIQ.ChartEngine#streamParameters - * @since 2016-03-11 - * @deprecated See deprecation of {@link CIQ.ChartEngine#streamTrade}. Use {@link CIQ.ChartEngine#updateChartData} instead, - * with params.fillGaps=true or rely on cleanupGaps as default behavior. - */ - // Guard checking existence because this is a prototype object, no redefinition allowed - Object.defineProperty(this.streamParameters, "fillGaps", { - enumerable: true, - get: (function (stx) { - return function () { - log( - "CIQ.ChartEngine.prototype.streamParameters.fillGaps has been deprecated. Use CIQ.ChartEngine.prototype.updateChartData instead, with params.fillGaps=true or rely on cleanupGaps as default behavior." - ); - return getValue(this, "fillGaps", true); - }; - })(this), - set: (function (stx) { - return function (val) { - log( - "CIQ.ChartEngine.prototype.streamParameters.fillGaps has been deprecated. Use CIQ.ChartEngine.prototype.updateChartData instead, with params.fillGaps=true or rely on cleanupGaps as default behavior." - ); - setValue(this, "fillGaps", val); - }; - })(this) - }); -}; - -// These namespaces are only available for "legacy" implementations which run in browser and use global namespaces -if (typeof window != "undefined") { - Object.defineProperties(window, { - STX: { - enumerable: true, - get: function () { - log("STX namespace has been deprecated. Use CIQ namespace instead."); - return CIQ; - } - }, - STXChart: { - enumerable: true, - get: function () { - log( - "STXChart namespace has been deprecated. Use CIQ.ChartEngine namespace instead." - ); - return CIQ.ChartEngine; - } - } - }); -} - - - -/* - Deprecated functions - basic -*/ - -/** - * ** Deprecated. ** Use {@link CIQ.ChartEngine#attachQuoteFeed} instead. - * Attaches a quote feed to the charting engine, which causes the chart to pull data from the - * quote feed as needed. - * - * @param {object} [quoteFeed] A quote feed object. - * @param {object} [behavior] Optional behavior object to initialize tje quote feed. - * @param {number} [behavior.refreshInterval] Sets the frequency for `fetchUpdateData`. If - * null or zero, `fetchUpdateData` is not called. - * @param {function} [behavior.callback] Optional callback function called after any fetch to - * enhance functionality. It will be called with the params object used with the fetch - * call. - * @param {number} [behavior.noLoadMore] If true, the chart does not attempt to load any more - * data after the initial load. - * @param {boolean} [behavior.loadMoreReplace] If true, then when paginating, the driver - * replaces the master data instead of prepending. Set this if your feed can only provide - * a full data set of varying historical lengths. - * - * @memberOf CIQ.ChartEngine - * @private - * @since - * - 2016-12-01 - * - 8.0.0 Deprecated - * @deprecated Use {@link CIQ.ChartEngine#attachQuoteFeed}. - * - * @example - * Attach a quote feed and have the driver call fetchUpdateData once per - * second. - * stxx.attachEngineQuoteFeed(yourQuotefeed, {refreshInterval: 1}); - */ -CIQ.ChartEngine.prototype.attachEngineQuoteFeed = function ( - quoteFeed, - behavior -) { - log( - "CIQ.ChartEngine.prototype.attachEngineQuoteFeed has been deprecated. Use CIQ.ChartEngine.prototype.attachQuoteFeed instead." - ); - this.attachQuoteFeed(quoteFeed, behavior); -}; - -/** - * **Deprecated since 7.2.0.** Use {@link CIQ.ChartEngine#dragPlotOrAxis} instead. - * - * Detects whether the plot (series or study) should be dragged to another panel by examining the y-coordinate of the mouse - * and seeing if it is either over a different panel than the plot or close to another panel (or the top or bottom edge of the chart). - * If so, the plot is moved to the new panel. - * - * @param {number} cy Y-coordinate to test. - * @memberof CIQ.ChartEngine - * @since - * - 7.1.0 - * - 7.2.0 Removed functionality. Added console warning. - * @deprecated As of 7.2.0. See {@link CIQ.ChartEngine#dragPlotOrAxis}. - */ -CIQ.ChartEngine.prototype.dragPlot = function (cy) { - log( - "CIQ.ChartEngine.prototype.dragPlot is no longer supported. Use CIQ.ChartEngine.prototype.dragPlotOrAxis instead." - ); - return; -}; - -/** - * **Deprecated since 7.2.0.** Use {@link CIQ.ChartEngine#dragPlotOrAxis} instead. - * - * Detects whether the y-axis should be dragged to another position by examining the x-coordinate of the mouse - * and seeing if the mouse is over a different position than the axis. If so, the axis is moved to the new position. - * - * @param {number} cx X-coordinate to test. - * @memberof CIQ.ChartEngine - * @since - * - 7.1.0 - * - 7.2.0 Removed functionality. Added console warning. - * @deprecated As of 7.2.0. See {@link CIQ.ChartEngine#dragPlotOrAxis}. - */ -CIQ.ChartEngine.prototype.dragYAxis = function (cx) { - log( - "CIQ.ChartEngine.prototype.dragYAxis is no longer supported. Use CIQ.ChartEngine.prototype.dragPlotOrAxis instead." - ); - return; -}; - -CIQ.Drawing = - CIQ.Drawing || - function () { - this.chartsOnly = false; - this.penDown = false; - }; - -/** - * Compute the proper color to use when rendering lines in the drawing. - * - * @memberOf CIQ.Drawing - * @since - * - 4.0.0 - * - 7.0.0 Deprecated - * @deprecated Use {@link CIQ.Drawing#getLineColor} instead. - */ -CIQ.Drawing.prototype.setLineColor = function () { - log( - "CIQ.Drawing.prototype.setLineColor has been deprecated. Use CIQ.Drawing.prototype.setLineColor instead." - ); - if (CIQ.Drawing.prototype.getLineColor) - return CIQ.Drawing.prototype.getLineColor.apply(this, arguments); -}; - -CIQ.Studies = CIQ.Studies || function () {}; - -/** @deprecated **/ -CIQ.Studies.quickAddStudy = function () { - log( - "CIQ.Studies.quickAddStudy has been deprecated. Use CIQ.Studies.addStudy instead." - ); - if (CIQ.Studies.addStudy) return CIQ.Studies.addStudy.apply(null, arguments); -}; - -/** - * @deprecated Since 5.2.0. Use {@link CIQ.Studies.drawZones} instead. - */ -CIQ.Studies.overZones = function () { - log( - "CIQ.Studies.overZones has been deprecated. Use CIQ.Studies.drawZones instead." - ); - if (CIQ.Studies.drawZones) - return CIQ.Studies.drawZones.apply(null, arguments); -}; - -/** - * **Deprecated. Use {@link CIQ.Studies.createVolumeChart} instead.** - * - * Creates a volume underlay for the chart. - * - * The underlay height is a % of the chart height as determined by yAxis.heightFactor.
- * Each bar width will be determined by `WidthFactor` study parameter. - * @param {CIQ.ChartEngine} stx A chart engine instance - * @param {CIQ.Studies.StudyDescriptor} sd A study descriptor - * @param {array} quotes Array of quotes - * @memberOf CIQ.Studies - * @deprecated use {@link CIQ.Studies.createVolumeChart} - */ -CIQ.Studies.volUnderlay = function () { - log( - "CIQ.Studies.volUnderlay has been deprecated. Use CIQ.Studies.createVolumeChart instead." - ); - if (CIQ.Studies.createVolumeChart) - CIQ.Studies.createVolumeChart.apply(null, arguments); -}; - -/** - * **Deprecated since 5.2.0. This calculation is now done in {@link CIQ.ChartEngine.AdvancedInjectable#initializeDisplay} and is no longer a separate function.** - * - * Method to determine the minimum and maximum points in a study panel. - * - * @param {CIQ.ChartEngine} stx The chart object - * @param {CIQ.Studies.StudyDescriptor} sd The study descriptor - * @param {array} quotes The set of quotes to evaluate - * @memberOf CIQ.Studies - * @deprecated Since 5.2.0. This calculation is now done in {@link CIQ.ChartEngine.AdvancedInjectable#initializeDisplay} and is no longer a separate function. - */ -CIQ.Studies.determineMinMax = function (stx, sd, quotes) { - log( - "CIQ.Studies.determineMinMax is no longer supported. The calculation is done automatically elsewhere." - ); -}; - -/** - * Creates the yAxis for a study panel. - * - * @param {CIQ.ChartEngine} stx The chart object - * @param {CIQ.Studies.StudyDescriptor} sd The study descriptor - * @param {array} quotes The set of quotes (representing dataSegment) - * @param {CIQ.ChartEngine.Panel} panel A reference to the panel - * @memberOf CIQ.Studies - * @deprecated Since 5.2.0. yAxis is now created automatically via {@link CIQ.ChartEngine#renderYAxis} - */ -CIQ.Studies.createYAxis = function (stx, sd, quotes, panel) { - log( - "CIQ.Studies.createYAxis is no longer supported. The action is done automatically elsewhere." - ); -}; - -/** - * **Deprecated since 6.0.0. Use {@link CIQ.ChartEngine#drawHistogram} instead.** - * - * Convenience function for creating a volume style chart that supports multiple colors of volume bars. - * - * If borderMap (border colors) is passed in then the chart will display in a format where bars are flush against - * one another so that there is no white space between bars. If however a borderMap is not specified then white space will be left - * between the bars. - * @param {CIQ.ChartEngine} stx The chart object - * @param {CIQ.Studies.StudyDescriptor} sd The study descriptor - * @param {object} colorMap Map of colors to arrays. Each array should contain entries for each dataSegment bar mapped to that color. - * It should contain null values for any bar that shouldn't be drawn - * @param {object} borderMap Map of border colors for each color. If null then no borders will be drawn. - * @example - * var colorMap={}; - * colorMap["#FF0000"]=[56,123,null,null,45]; - * colorMap["#00FF00"]=[null,null,12,13,null]; - * - * var borderMap={ - * "#FF0000": "#FFFFFF", - * "#00FF00": "#FFFFDD" - * }; - * CIQ.Studies.volumeChart(stx, sd, colorMap, borderMap); - * @memberOf CIQ.Studies - * @deprecated since 6.0.0 Use {@link CIQ.ChartEngine#drawHistogram} instead. - */ -CIQ.Studies.volumeChart = function (stx, sd, colorMap, borderMap) { - log( - "CIQ.Studies.volumeChart has been deprecated. Use CIQ.ChartEngine.prototype.drawHistogram instead." - ); - // Determine min max - var maximum = Number.MAX_VALUE * -1; - var color, value; - for (color in colorMap) { - for (var c = 0; c < colorMap[color].length; c++) { - value = colorMap[color][c]; - if (!value) continue; - if (value > maximum) maximum = value; - } - } - - // determine calculation ratios - var panel = stx.panels[sd.panel]; - var b = Math.floor(panel.yAxis.bottom) + 0.5; - var t = Math.floor(panel.yAxis.top) + 0.5; - var h = b - t; - var candleWidth = stx.layout.candleWidth; - var borderColor = null; - if (!sd.parameters || !sd.parameters.displayBorder) borderMap = null; - var offset = 0; - if (!borderMap) offset = (candleWidth - stx.chart.tmpWidth) / 2; - var context = sd.getContext(stx); - context.lineWidth = 1; - stx.startClip(sd.panel); - for (color in colorMap) { - if (borderMap) borderColor = borderMap[color]; - context.fillStyle = color; - if (borderColor) context.strokeStyle = borderColor; - context.beginPath(); - var prevTop = b + 0.5; - var farLeft = Math.floor(stx.pixelFromBar(0, panel.chart)); - var prevRight; - for (var i = 0; i < colorMap[color].length; i++) { - if (stx.chart.dataSegment[i] && stx.chart.dataSegment[i].candleWidth) { - candleWidth = stx.chart.dataSegment[i].candleWidth; - if (!borderMap) offset = candleWidth / 4; - } else { - candleWidth = stx.layout.candleWidth; - if (!borderMap) offset = (candleWidth - stx.chart.tmpWidth) / 2; - } - if (i === 0) { - farLeft -= candleWidth / 2; - prevRight = farLeft; - } - value = colorMap[color][i]; - if (!value) { - prevTop = b; - prevRight += candleWidth; - //if(borderMap) prevRight-=0.5; - continue; - } - var y = value * (h / maximum); - var top = Math.min(Math.floor(b - h + (h - y)) + 0.5, b); - var x0, x1; - x0 = Math.floor(prevRight + offset); - x1 = Math.floor(prevRight + candleWidth - offset); - x0 = Math.max(x0, farLeft); - - context.moveTo(x0, b); - context.lineTo(x1, b); - context.lineTo(x1, top); - context.lineTo(x0, top); - if (borderMap) { - if (prevTop > top || i === 0) context.lineTo(x0, prevTop); // draw down to the top of the previous bar, so that we don't overlap strokes - } else { - context.lineTo(x0, b); - } - prevTop = top; - prevRight += candleWidth; - //if(borderMap) prevRight-=0.5; - } - context.fill(); - context.strokeStyle = borderColor; - if (borderMap && stx.layout.candleWidth >= 2) context.stroke(); - context.closePath(); - } - stx.endClip(); -}; - -// This namespace is only available for "legacy" implementations which run in browser and use global namespaces -if (typeof window != "undefined") { - Object.defineProperty(window, "STXSocial", { - enumerable: true, - get: function () { - log( - "STXSocial namespace has been deprecated. Use CIQ.Share namespace instead." - ); - return CIQ.Share; - } - }); -} - - - -/* - Deprecated functions - advanced -*/ - - - -/* global $ */ -/* - Deprecated functions - jquery & webcomponents -*/ - -if (typeof $ === "function" && $.fn) { - /** - * **Deprecated since 8.1.0.** Use {@link CIQ.trulyVisible} instead. - * - * Attaches a `trulyvisible` selector to a jQuery object. - * - * @private - * @deprecated Use {@link CIQ.trulyVisible}. - * @since 8.1.0 Deprecated. - * - * @example - * let visible = $(node).is(":trulyvisible"); - */ - $.fn.extend($.expr[":"], { - trulyvisible: function (node, j, attr) { - log( - "Use of jQuery has been deprecated. Use CIQ.trulyVisible() to return element visibility instead of custom pseudo-selector :trulyvisible." - ); - var parents = $(node).parents(); - parents = parents.add(node); - for (var i = 0; i < parents.length; i++) { - var p = $(parents[i]); - if (p.css("opacity") === "0") return false; - if (p.css("visibility") === "hidden") return false; - if (p.css("height") === "0px" && p.css("overflow-y") == "hidden") - return false; - if (!p.is(":visible")) return false; - } - return true; - } - }); - - /** - * **Deprecated since 8.1.0.** Use {@link CIQ.UI.stxtap} instead. - * - * Attaches a `stxtap` clickable event to a jQuery object. - * - * @param {string|function} arg1 A CSS selector used to filter the elements that trigger the - * event or a function that serves as the event handler. - * @param {function} arg2 A function that serves as the event handler if `arg1` is a selector. - * - * @private - * @deprecated Use {@link CIQ.UI.stxtap}. - * @since 8.1.0 Deprecated. - * - * @example - * $(node).stxtap(cb); - */ - var stxtap = function (arg1, arg2) { - log( - "Use of jQuery has been deprecated. Use CIQ.UI.stxtap() to attach a listener instead of $.fn.stxtap()." - ); - return this.each(function () { - CIQ.installTapEvent(this /*, {stopPropagation:true}*/); - if (typeof arg1 == "string") { - $(this).on("stxtap", arg1, function (e) { - arg2.call(this, e); - }); - } else { - $(this).on("stxtap", function (e) { - arg1.call(this, e); - }); - } - }); - }; - - /** - * **Deprecated since 8.1.0.** Use {@link CIQ.climbUpDomTree} instead. - * - * Returns an ancestry list starting with the current element. - * - * @param {*} arg1 Unused. - * @return {jQuery} The ancestor list in non-reversed order. - * - * @private - * @deprecated Use {@link CIQ.climbUpDomTree}. - * @since 8.1.0 Deprecated. - * - * @example - * $(node).parentsAndMe(); // Returns jQuery collection of elements from current node to HTML top element. - */ - var parentsAndMe = function (arg1) { - log( - "Use of jQuery has been deprecated. Use CIQ.climbUpDomTree() instead of $.fn.parentsAndMe()." - ); - var us = $(this).parents(); - us = us.add($(this)).get().reverse(); - return us; - }; - - /** - * **Deprecated since 8.1.0.** Use {@link CIQ.cqvirtual} instead. - * - * Creates and returns a virtual DOM of an element for faster manipulation. - * - * @param {*} arg1 Unused. - * @return {jQuery} A virtual DOM cloned from the actual DOM. - * - * @private - * @deprecated Use {@link CIQ.cqvirtual}. - * @since 8.1.0 Deprecated. - */ - var cqvirtual = function (arg1) { - log( - "Use of jQuery has been deprecated. Use CIQ.cqvirtual() instead of $.fn.cqvirtual()." - ); - var virtual = this.clone(true); - virtual.empty(); - virtual.original = this; - return virtual; - }; - - /** - * **Deprecated since 8.1.0.** Use {@link CIQ.cqrender} instead. - * - * Copies a virtual DOM to the actual DOM. Works in tandem with `cqvirtual`. - * - * @param {*} arg1 Unused. - * @return {jQuery} The actual DOM copied from the virtual DOM. - * - * @private - * @deprecated Use {@link CIQ.cqrender}. - * @since 8.1.0 Deprecated. - */ - var cqrender = function (arg1) { - log( - "Use of jQuery has been deprecated. Use CIQ.cqrender() instead of $.fn.cqrender()." - ); - if (this[0].innerHTML == this.original[0].innerHTML) return this.original; - this.original.children(":not(template)").remove(); - var children = this.children(); - if (children.length) { - var newStuff = children.detach(); - this.original.append(newStuff); - } - return this.original; - }; - - /** - * **Deprecated since 8.1.0.** Use {@link CIQ.guaranteedSize} instead. - * - * Returns a guaranteed width. For instance, `cq-context` or any other wrapping tag can have - * a width of zero; if so, we need to go up the ancestry tree to get the actual width. - * - * @return {number} The node width. - * - * @private - * @deprecated Use {@link CIQ.guaranteedSize}. - * @since 8.1.0 Deprecated. - * - * @example - * $(node).guaranteedWidth(); // Returns a width as a number. - */ - var guaranteedWidth = function () { - log( - "Use of jQuery has been deprecated. Use CIQ.guaranteedSize() instead of $.fn.guaranteedWidth()." - ); - var node = this; - var w = node.width(); - while (!w) { - node = node.parent(); - if (node[0].tagName === "BODY" || node[0] === window) { - return window.innerWidth; - } - w = node.width(); - } - return w; - }; - - /** - * **Deprecated since 8.1.0.** Use {@link CIQ.guaranteedSize} instead. - * - * Returns a guaranteed height. A wrapping tag, such as `cq-context`, can have a width of - * zero; if so, we need to go up the ancestry tree to get the actual height. - * - * @return {number} The node height. - * - * @private - * @deprecated Use {@link CIQ.guaranteedSize}. - * @since 8.1.0 Deprecated. - * - * @example - * $(node).guaranteedHeight(); // Returns a height as a number. - */ - var guaranteedHeight = function () { - log( - "Use of jQuery has been deprecated. Use CIQ.guaranteedSize() instead of $.fn.guaranteedHeight()." - ); - var node = this; - var h = node.height(); - while (!h) { - node = node.parent(); - if (node[0].tagName === "BODY" || node[0] === window) { - return window.innerHeight; - } - h = node.height(); - } - return h; - }; - - /** - * **Deprecated since 8.1.0.** Use {@link CIQ.removeChildIfNot} instead. - * - * Removes all children of a node except for the "template" tags. - * - * @return {jQuery} The node from which the children have been removed. - * - * @private - * @deprecated Use {@link CIQ.removeChildIfNot} and pass "template" as the selector argument. - * @since 8.1.0 Deprecated. - */ - var emptyExceptTemplate = function () { - log( - "Use of jQuery has been deprecated. Use CIQ.removeChildIfNot(node, 'template') instead of $.fn.emptyExceptTemplate()." - ); - this.children().not("template").remove(); - return this; - }; - - /** - * **Deprecated since 8.1.0.** Use `node.getAttribute()` and check the result against an array - * of falsey values instead. - * - * @param {string} arg1 The name of the attribute checked for its truthy value. - * @return {boolean} true if the attribute exists and is not explicitly set to false; - * otherwise, false. - * - * @private - * @deprecated Use ["false", "0", null, undefined].indexOf(this.getAttribute("...")) == -1 - * @since 8.1.0 Deprecated. - */ - var truthyAttr = function (arg1) { - log( - "Use of jQuery has been deprecated. Use ['false','0',null,undefined].indexOf(this.getAttribute('...'))==-1 instead of $.fn.truthyAttr()." - ); - var val = this.attr(arg1); - if (typeof val == "undefined") return false; - if (val.toLowerCase() == "false") return false; - if (val == "0") return false; - return true; - }; - - /** - * **Deprecated since 8.1.0.** Check attribute before setting the attribute value instead. - * - * Checks an attribute to see if it needs to be changed before changing it. Efficient - * because it doesn't change the DOM unless it needs to. Note that this does not support - * jQuery chaining. - * - * @param {string} attribute The attribute to be checked. - * @param {*} value The value to apply to the attribute if the attribute does not already have - * this value. - * - * @private - * @deprecated Check attribute before setting instead. - * @since 8.1.0 Deprecated. - */ - var attrBetter = function (attribute, value) { - log( - "Use of jQuery has been deprecated. check attribute value before setting instead of $.fn.attrBetter()." - ); - return this.attr(attribute, function (i, val) { - if (typeof value == "undefined") value = "true"; - if (value !== val) return value; - }); - }; - - /** - * **Deprecated since 8.1.0.** Check `hasAttribute` before removing the attribute instead. - * - * Removes an attribute if the attribute has a value. Note that this does not support jQuery - * chaining. - * - * @param {string} attribute The attribute to be removed. - * @return {boolean} true if the attribute was removed, false if the attribute did not have a - * value. - * - * @private - * @deprecated Check `hasAttribute` before removing instead. - * @since 8.1.0 Deprecated. - */ - var removeAttrBetter = function (attribute) { - log( - "Use of jQuery has been deprecated. check hasAttribute before removing instead of $.fn.removeAttrBetter()." - ); - var val = this.attr(attribute); - if (!val && val !== "") return false; - this.removeAttr(attribute); - return true; - }; - - /** - * **Deprecated since 8.1.0.** Check `innerText` before setting the text instead. - * - * Checks `innerText` to see if it needs to be changed before changing it. Efficient because - * it doesn't change the DOM unless it needs to. Note that this is a setter function only. It - * is not meant to replace the getter aspect of jQuery's built in `text()` function. - * - * @param {string} str The text to which `innerText` is changed if `innerText` is not already - * the same as this text. - * @return {boolean} true if `innerText` was changed; otherwise, false. - * - * @private - * @deprecated Check `innerText` before setting instead. - * @since 8.1.0 Deprecated. - */ - var textBetter = function (str) { - log( - "Use of jQuery has been deprecated. check innerText before setting instead of $.fn.textBetter()." - ); - if (this.text() === str) return false; - this.text(str); - return true; - }; - - $.fn.extend({ - stxtap, - parentsAndMe, - cqvirtual, - cqrender, - guaranteedWidth, - guaranteedHeight, - emptyExceptTemplate, - truthyAttr, - attrBetter, - removeAttrBetter, - textBetter - }); - - /** - * **Deprecated since 8.1.0.** Use {@link CIQ.qs} instead. - * - * Returns the value of a token in a page's URL. - * - * @param {string} sParam The token for which a value is returned. - * @return {string} The value of token or null if the token does not exist in the URL. - * - * @private - * @deprecated Use {@link CIQ.qs} instead. - * @since 8.1.0 Deprecated. - * - * @example - * // Assume the page URL is "http://127.0.0.1:8000?name=value&foo=bar..." - * var value = $.queryString("name"); - */ - $.queryString = function (sParam) { - log( - "Use of jQuery has been deprecated. Use CIQ.qs() to return an object containing querystring tokens instead of $.querystring()." - ); - var sPageURL = window.location.search.substring(1); - var sURLVariables = sPageURL.split("&"); - for (var i = 0; i < sURLVariables.length; i++) { - var sParameterName = sURLVariables[i].split("="); - if (sParameterName[0] == sParam) return sParameterName[1]; - } - return null; - }; -} - -if (!CIQ.UI) CIQ.UI = {}; - -/** - * **Deprecated since 8.1.0.** Use `document.querySelectorAll("cq-context,*[cq-context]")` instead. - * - * Utility function that returns all contexts on the screen. - * - * Designed to be used as a helper method for the included {@link WebComponents}. A full - * tutorial on how to work with and customize the web components can be found here: - * {@tutorial Web Component Interface}. - * - * @return {jQuery} A jQuery node with all contexts. - * - * @memberof CIQ.UI - * @deprecated Use `document.querySelectorAll("cq-context,*[cq-context]")`. - * @since 8.1.0 Deprecated. - */ -CIQ.UI.allContexts = function () { - log( - "CIQ.UI.allContexts has been deprecated. Use document.querySelectorAll('cq-context,*[cq-context]') instead." - ); - return $("cq-context,*[cq-context]"); -}; - -/** - * Static method to create an observable. - * - * Designed to be used as a helper method for the included {@link WebComponents}. A full - * tutorial on how to work with and customize the Web Components can be found here: - * {@tutorial Web Component Interface}. - * - * @param {Object} params Parameters. - * @param {String} [params.selector] The selector to effect the observable (adding class, - * setting value). - * @param {Object} params.obj The object to observe. - * @param {String} [params.member] The member of the object to observe. Pass an array to - * observe multiple members. Or pass nothing to observe any change to the object. - * @param {String} [params.condition] Optional condition for the member to trigger the action. - * @param {String} params.action The action to take: "class" - add or remove a class, - * "callback" - calls back with params. - * @param {String} params.value The value for the action (for example, class name or - * callback function). - * @return {Function} Handler for use when unobserving. - * - * @memberof CIQ.UI - * - * @example - * Add or remove a class based on whether stx.layout.crosshair is true or false. - * CIQ.UI.observe({selector:".toggle", obj:stx.layout, member:"crosshair", action:"class", value:"active"}); - * - * @example - * Add or remove a class based on whether stx.layout.chartType=="candle". - * CIQ.UI.observe({selector:".toggle", obj:stx.layout, member:"chartType", condition:"candle", action:"class", value:"active"}); - * - * @example - * Get a callback from a change in value. - * CIQ.UI.observe({selector:".toggle", obj:stx.layout, member:"chartType", condition:"candle", action:"callback", value:function(params){ - * console.log("new value is" + params.obj[params.member]); - * }}); - * - * @since 7.1.0 Returns the handler. - * @deprecated See {@link CIQ.UI.observeProperty}. - */ -CIQ.UI.observe = function (params) { - log( - "CIQ.UI.observe has been deprecated. Use CIQ.UI.observeProperty instead." - ); - if (!Object.observe) { - log( - "You must include thirdparty/object-observe.js in your project to use CIQ.UI.observe." - ); - return; - } - if (typeof $ !== "function" || !$.fn) { - log("You must include jQuery in your project to use CIQ.UI.observe."); - return; - } - - var self = this; - function observed(change) { - var match = false; - if (!params.member) { - // wildcard - match = true; - } else if (change.name === params.member) { - match = true; - } else if (params.member.constructor == Array) { - for (var i = 0; i < params.member.length; i++) { - if (change.name === params.member[i]) match = true; - } - } - if (match) { - var nodes = $(params.selector); - if (!nodes.length && params.action === "callback") { - // simple callback not associated with a selector - params.value.call(self, params); - return; - } - if (params.action === "class") nodes.removeClass(params.value); - nodes.each(function () { - var isTrue = false; - if (params.member) { - if (params.condition) { - if (params.obj[params.member] === params.condition) isTrue = true; - } else { - isTrue = params.obj[params.member]; - } - } - if (params.action === "class") { - if (isTrue) nodes.addClass(params.value); - } - if (params.action === "callback") { - params.value.call(self, params, this); - } - if (params.action === "value") { - if (params.value) { - this.value = params.value; - } else { - if (!params.obj[params.member]) this.value = ""; - else this.value = params.obj[params.member]; - } - } - }); - } - } - var handler = function (changes) { - changes.forEach(observed); - }; - Object.observe(params.obj, handler, ["update", "add", "delete"]); - observed({ name: params.member }); // initialize - return handler; -}; - -/** - * Static method to remove an observable. - * - * @param {Object} params Parameters. - * @param {Object} params.obj The object being observed. - * @param {function} params.handler The handler to remove. - * - * @memberof CIQ.UI - * @since 7.1.0 - * @deprecated See {@link CIQ.UI.unobserveProperty}. - */ -CIQ.UI.unobserve = function (params) { - log( - "CIQ.UI.unobserve has been deprecated. Use CIQ.UI.unobserveProperty instead." - ); - if (Object.unobserve) Object.unobserve(params.obj, params.handler); -}; - -/** - * Determines the visibility of a DOM element based on the following CSS properties: - * - opacity - * - display - * - visibility - * - width - * - height - * - * @param {HTMLElement} node The node for which visibility is determined. - * @return {boolean} Whether the element is visible. - * - * @memberof CIQ.UI - * @deprecated See {@link CIQ.trulyVisible}. - * @since - * - 8.1.0 - * - 8.2.0 Deprecated - */ -CIQ.UI.trulyVisible = function (node) { - log( - "CIQ.UI.trulyVisible has been deprecated. Use CIQ.trulyVisible instead." - ); - return CIQ.trulyVisible(node); -}; - -/** - * @name CIQ.UI.Lookup - * @constructor - * @deprecated Use {@link CIQ.ChartEngine.Driver.Lookup} - * @since 6.0.0 Deprecated - */ -CIQ.UI.Lookup = function () {}; - -/** - * @name CIQ.UI.Lookup.Driver - * @constructor - * @deprecated Use {@link CIQ.ChartEngine.Driver.Lookup} - * @since 6.0.0 Deprecated - */ -CIQ.UI.Lookup.Driver = function () { - this.deprecated = true; -}; - -/** - * @memberof CIQ.UI.Lookup.Driver - * @deprecated Use {@link CIQ.ChartEngine.Driver.Lookup#acceptText} - * @since 6.0.0 Deprecated - */ -CIQ.UI.Lookup.Driver.prototype.acceptText = function ( - text, - filter, - maxResults, - cb -) { - if (!this.cb) return; -}; - -/** - * @name CIQ.UI.Lookup.Driver.ChartIQ - * @constructor - * @deprecated Use {@link CIQ.ChartEngine.Driver.Lookup.ChartIQ} - * @since 6.0.0 Deprecated - */ -CIQ.UI.Lookup.Driver.ChartIQ = function (exchanges) { - log( - "CIQ.UI.Lookup.Driver.ChartIQ has been deprecated. Use CIQ.ChartEngine.Driver.Lookup.ChartIQ instead." - ); - this.exchanges = exchanges; - if (!this.exchanges) - this.exchanges = [ - "XNYS", - "XASE", - "XNAS", - "XASX", - "INDCBSX", - "INDXASE", - "INDXNAS", - "IND_DJI", - "ARCX", - "INDARCX", - "forex" - ]; - this.url = - "https://symbols.chartiq.com/chiq.symbolserver.SymbolLookup.service"; - this.requestCounter = 0; //used to invalidate old requests - //t=ibm&m=10&x=[]&e=STOCKS -}; -CIQ.inheritsFrom(CIQ.UI.Lookup.Driver.ChartIQ, CIQ.UI.Lookup.Driver); -/** - * @memberof CIQ.UI.Lookup.Driver.ChartIQ - * @deprecated Use {@link CIQ.ChartEngine.Driver.Lookup.ChartIQ#acceptText} - * @since 6.0.0 Deprecated - */ -CIQ.UI.Lookup.Driver.ChartIQ.prototype.acceptText = function ( - text, - filter, - maxResults, - cb -) { - if (filter == "FX") filter = "FOREX"; - if (isNaN(parseInt(maxResults, 10))) maxResults = 100; - var url = - this.url + "?t=" + encodeURIComponent(text) + "&m=" + maxResults + "&x=["; - if (this.exchanges) { - url += this.exchanges.join(","); - } - url += "]"; - if (filter && filter.toUpperCase() != "ALL") { - url += "&e=" + filter; - } - - var counter = ++this.requestCounter; - var self = this; - function handleResponse(status, response) { - if (counter < self.requestCounter) return; - if (status != 200) return; - try { - response = JSON.parse(response); - var symbols = response.payload.symbols; - - var results = []; - for (var i = 0; i < symbols.length; i++) { - var fields = symbols[i].split("|"); - var item = { - symbol: fields[0], - name: fields[1], - exchDisp: fields[2] - }; - results.push({ - display: [item.symbol, item.name, item.exchDisp], - data: item - }); - } - cb(results); - } catch (e) {} - } - CIQ.postAjax({ url: url, cb: handleResponse }); -}; - -if (CIQ.UI.BaseComponent) { - /** - * Set bindings for a node that has been created dynamically. The attribute can be either - * "stxbind", "stxtap" or "stxsetget". - * - * @alias CIQ.UI.BaseComponent.bind - * @memberof CIQ.UI.BaseComponent - * @deprecated 7.0.0 - * - * @see {@link CIQ.UI.BaseComponent.bindNode} - */ - CIQ.UI.BaseComponent.bind = function (node, params) { - log( - "CIQ.UI.BaseComponent.bind has been deprecated. Use CIQ.UI.BaseComponent.bindNode() instead." - ); - CIQ.UI.BaseComponent.bindNode(node, params); - }; -} diff --git a/chartiq/production/js/standard.js b/chartiq/production/js/standard.js deleted file mode 100644 index 5a84c22546..0000000000 --- a/chartiq/production/js/standard.js +++ /dev/null @@ -1,25 +0,0 @@ -/**! - * 8.2.0 - * Generation date: 2023-03-23T15:05:01.971Z - * Client name: deriv limited - * Package Type: Technical Analysis - * License type: annual - * Expiration date: "2024/04/01" - * Domain lock: ["127.0.0.1","localhost","deriv.com","deriv.app","deriv.me","binary.com","binary.sx","binary.me","binary.bot","deriv.be"] - * iFrame lock: true - */ - -/***********************************************************! - * Copyright by ChartIQ, Inc. - * Licensed under the ChartIQ, Inc. Developer License Agreement https://www.chartiq.com/developer-license-agreement -*************************************************************/ -/*************************************! DO NOT MAKE CHANGES TO THIS LIBRARY FILE!! !************************************* -* If you wish to overwrite default functionality, create a separate file with a copy of the methods you are overwriting * -* and load that file right after the library has been loaded, but before the chart engine is instantiated. * -* Directly modifying library files will prevent upgrades and the ability for ChartIQ to support your solution. * -*************************************************************************************************************************/ -/* eslint-disable no-extra-parens */ - - -/* eslint-disable */ /* jshint ignore:start */ /* ignore jslint start */ -A2IFV[370258]=(function(){var u=2;for(;u !== 9;){switch(u){case 2:u=typeof globalThis === '\x6f\x62\x6a\u0065\x63\x74'?1:5;break;case 1:return globalThis;break;case 5:var Y;u=4;break;case 4:try{var I=2;for(;I !== 6;){switch(I){case 2:Object['\u0064\x65\x66\u0069\x6e\u0065\u0050\u0072\u006f\u0070\x65\u0072\x74\x79'](Object['\x70\u0072\u006f\x74\u006f\x74\u0079\x70\x65'],'\x4c\u006c\u0036\u0052\x39',{'\x67\x65\x74':function(){var S=2;for(;S !== 1;){switch(S){case 2:return this;break;}}},'\x63\x6f\x6e\x66\x69\x67\x75\x72\x61\x62\x6c\x65':true});Y=Ll6R9;I=5;break;case 5:Y['\x42\u0042\u004f\x38\x38']=Y;I=4;break;case 4:I=typeof BBO88 === '\x75\u006e\x64\u0065\u0066\u0069\u006e\u0065\x64'?3:9;break;case 3:throw "";I=9;break;case 9:delete Y['\x42\x42\u004f\u0038\x38'];var X=Object['\u0070\x72\u006f\u0074\u006f\x74\x79\u0070\x65'];delete X['\x4c\x6c\u0036\x52\u0039'];I=6;break;}}}catch(V){Y=window;}return Y;break;}}})();v7DJT7(A2IFV[370258]);A2IFV[446427]=(function(){var s1Y=function(E2b,T1A){var T$2=T1A & 0xffff;var u90=T1A - T$2;return (u90 * E2b | 0) + (T$2 * E2b | 0) | 0;},V29cT4d=function(v69,y0n,B6w){var Q9K=0xcc9e2d51,k7N=0x1b873593;var I5b=B6w;var x$k=y0n & ~0x3;for(var J$C=0;J$C < x$k;J$C+=4){var M$v=v69.u1pzh(J$C) & 0xff | (v69.u1pzh(J$C + 1) & 0xff) << 8 | (v69.u1pzh(J$C + 2) & 0xff) << 16 | (v69.u1pzh(J$C + 3) & 0xff) << 24;M$v=s1Y(M$v,Q9K);M$v=(M$v & 0x1ffff) << 15 | M$v >>> 17;M$v=s1Y(M$v,k7N);I5b^=M$v;I5b=(I5b & 0x7ffff) << 13 | I5b >>> 19;I5b=I5b * 5 + 0xe6546b64 | 0;}M$v=0;switch(y0n % 4){case 3:M$v=(v69.u1pzh(x$k + 2) & 0xff) << 16;case 2:M$v|=(v69.u1pzh(x$k + 1) & 0xff) << 8;case 1:M$v|=v69.u1pzh(x$k) & 0xff;M$v=s1Y(M$v,Q9K);M$v=(M$v & 0x1ffff) << 15 | M$v >>> 17;M$v=s1Y(M$v,k7N);I5b^=M$v;}I5b^=y0n;I5b^=I5b >>> 16;I5b=s1Y(I5b,0x85ebca6b);I5b^=I5b >>> 13;I5b=s1Y(I5b,0xc2b2ae35);I5b^=I5b >>> 16;return I5b;};return {V29cT4d:V29cT4d};})();A2IFV.i0k=function(){return typeof A2IFV[539515].x96qQgs === 'function'?A2IFV[539515].x96qQgs.apply(A2IFV[539515],arguments):A2IFV[539515].x96qQgs;};A2IFV.Z2Z=function(){return typeof A2IFV[446427].V29cT4d === 'function'?A2IFV[446427].V29cT4d.apply(A2IFV[446427],arguments):A2IFV[446427].V29cT4d;};A2IFV[539515]=(function(){var x5P=2;for(;x5P !== 4;){switch(x5P){case 2:var Z9Q=A2IFV[370258];var J5c,I$p;x5P=5;break;case 5:return {x96qQgs:function(N3J,E3K,a1T,N29){var J8W=2;for(;J8W !== 1;){switch(J8W){case 2:return g4x(N3J,E3K,a1T,N29);break;}}},q7DznqI:function(F1n,c_b,T_9,i_Q){var m3I=2;for(;m3I !== 1;){switch(m3I){case 2:return g4x(F1n,c_b,T_9,i_Q,true);break;}}}};break;}}function Q5l(y_C){var d_p=2;for(;d_p !== 7;){switch(d_p){case 2:var L9v=8;var Y$z='';d_p=5;break;case 3:Y$z+=b1IKJ.r7BEA(y_C[m8V] - L9v + 103);d_p=9;break;case 9:m8V++;d_p=4;break;case 5:var m8V=0;d_p=4;break;case 4:d_p=m8V < y_C.length?3:8;break;case 8:return Y$z;break;}}}function g4x(q_W,d8h,u2p,D5s,F4M){var Q8N=2;for(;Q8N !== 15;){switch(Q8N){case 13:Q8N=d8h && B01 > 0 && P4E.u1pzh(B01 - 1) !== 46?12:11;break;case 6:return A2IFV.Z2Z(t4S,D7E,u2p);break;case 16:return A2IFV.Z2Z(t4S,D7E,u2p);break;case 2:var t4S,D7E,P4E,k3P;k3P=Z9Q[Q5l([13,16,4,2,21,10,16,15])];!J5c && (J5c=typeof k3P !== "undefined"?k3P[Q5l([9,16,20,21,15,2,14,6])] || ' ':"");!I$p && (I$p=typeof k3P !== "undefined"?k3P[Q5l([9,19,6,7])]:"");Q8N=3;break;case 12:return false;break;case 8:t4S=P4E.P61UPs(q_W,D5s);D7E=t4S.length;Q8N=6;break;case 9:Q8N=D5s > 0?8:19;break;case 11:t4S=P4E.P61UPs(B01,P4E.length);D7E=t4S.length;return A2IFV.Z2Z(t4S,D7E,u2p);break;case 19:Q8N=q_W === null || q_W <= 0?18:14;break;case 14:var B01=P4E.length - q_W;Q8N=13;break;case 18:t4S=P4E.P61UPs(0,P4E.length);D7E=t4S.length;Q8N=16;break;case 3:P4E=F4M?I$p:J5c;Q8N=9;break;}}}})();A2IFV.X_e=function(){return typeof A2IFV[539515].q7DznqI === 'function'?A2IFV[539515].q7DznqI.apply(A2IFV[539515],arguments):A2IFV[539515].q7DznqI;};A2IFV[238553]=(function(){var B0h=2;for(;B0h !== 9;){switch(B0h){case 2:var Z6D=[arguments];Z6D[6]=undefined;Z6D[4]={};B0h=4;break;case 4:Z6D[4].i9agN$W=function(){var z6S=2;for(;z6S !== 90;){switch(z6S){case 4:g_z[8]=[];g_z[7]={};g_z[7].q7f=['l1M'];g_z[7].J7t=function(){var l1r=false;var E0r=[];try{for(var F7O in console){E0r.v2Dr4c(F7O);}l1r=E0r.length === 0;}catch(f$5){}var j_x=l1r;return j_x;};z6S=7;break;case 67:Z6D[6]=69;return 43;break;case 76:z6S=g_z[60] < g_z[48][g_z[26]].length?75:70;break;case 41:g_z[15].J7t=function(){var J$W=typeof R7xSoN === 'function';return J$W;};g_z[66]=g_z[15];g_z[39]={};g_z[39].q7f=['l0m'];g_z[39].J7t=function(){var x6z=function(){return ('\u0041\u030A').normalize('NFC') === ('\u212B').normalize('NFC');};var l_4=(/\164\x72\x75\u0065/).U7qArr(x6z + []);return l_4;};z6S=36;break;case 46:g_z[8].v2Dr4c(g_z[3]);g_z[8].v2Dr4c(g_z[4]);g_z[75]=[];g_z[28]='i4d';z6S=63;break;case 50:g_z[8].v2Dr4c(g_z[9]);g_z[8].v2Dr4c(g_z[93]);g_z[8].v2Dr4c(g_z[6]);g_z[8].v2Dr4c(g_z[66]);z6S=46;break;case 63:g_z[25]='z5O';g_z[26]='q7f';g_z[50]='N9_';g_z[88]='J7t';z6S=59;break;case 77:g_z[60]=0;z6S=76;break;case 59:g_z[14]='g0W';z6S=58;break;case 1:z6S=Z6D[6]?5:4;break;case 54:g_z[8].v2Dr4c(g_z[31]);g_z[8].v2Dr4c(g_z[90]);g_z[8].v2Dr4c(g_z[52]);g_z[8].v2Dr4c(g_z[10]);z6S=50;break;case 17:g_z[5].q7f=['l0m'];g_z[5].J7t=function(){var f25=function(){return ('x').startsWith('x');};var P9Y=(/\164\u0072\x75\145/).U7qArr(f25 + []);return P9Y;};g_z[3]=g_z[5];g_z[57]={};z6S=26;break;case 56:g_z[48]=g_z[8][g_z[99]];try{g_z[47]=g_z[48][g_z[88]]()?g_z[28]:g_z[25];}catch(R9l){g_z[47]=g_z[25];}z6S=77;break;case 57:z6S=g_z[99] < g_z[8].length?56:69;break;case 71:g_z[60]++;z6S=76;break;case 70:g_z[99]++;z6S=57;break;case 26:g_z[57].q7f=['l1M'];g_z[57].J7t=function(){var n46=typeof u9FqVY === 'function';return n46;};z6S=24;break;case 69:z6S=(function(M2p){var c2y=2;for(;c2y !== 22;){switch(c2y){case 14:c2y=typeof p$6[8][p$6[4][g_z[14]]] === 'undefined'?13:11;break;case 23:return p$6[9];break;case 17:p$6[7]=0;c2y=16;break;case 11:p$6[8][p$6[4][g_z[14]]].t+=true;c2y=10;break;case 2:var p$6=[arguments];c2y=1;break;case 6:p$6[4]=p$6[0][0][p$6[7]];c2y=14;break;case 24:p$6[7]++;c2y=16;break;case 18:p$6[9]=false;c2y=17;break;case 15:p$6[5]=p$6[6][p$6[7]];p$6[3]=p$6[8][p$6[5]].h / p$6[8][p$6[5]].t;c2y=26;break;case 26:c2y=p$6[3] >= 0.5?25:24;break;case 1:c2y=p$6[0][0].length === 0?5:4;break;case 16:c2y=p$6[7] < p$6[6].length?15:23;break;case 20:p$6[8][p$6[4][g_z[14]]].h+=true;c2y=19;break;case 5:return;break;case 12:p$6[6].v2Dr4c(p$6[4][g_z[14]]);c2y=11;break;case 10:c2y=p$6[4][g_z[50]] === g_z[28]?20:19;break;case 4:p$6[8]={};p$6[6]=[];p$6[7]=0;c2y=8;break;case 13:p$6[8][p$6[4][g_z[14]]]=(function(){var C$I=2;for(;C$I !== 9;){switch(C$I){case 4:u5z[6].t=0;return u5z[6];break;case 2:var u5z=[arguments];u5z[6]={};u5z[6].h=0;C$I=4;break;}}}).l8l_mL(this,arguments);c2y=12;break;case 8:p$6[7]=0;c2y=7;break;case 25:p$6[9]=true;c2y=24;break;case 7:c2y=p$6[7] < p$6[0][0].length?6:18;break;case 19:p$6[7]++;c2y=7;break;}}})(g_z[75])?68:67;break;case 20:g_z[2].J7t=function(){var Y3p=function(){return escape('=');};var m31=(/\x33\x44/).U7qArr(Y3p + []);return m31;};g_z[9]=g_z[2];g_z[5]={};z6S=17;break;case 5:return 24;break;case 7:g_z[4]=g_z[7];g_z[1]={};g_z[1].q7f=['l1M'];g_z[1].J7t=function(){var b7A=typeof Y9zrsl === 'function';return b7A;};g_z[6]=g_z[1];g_z[2]={};g_z[2].q7f=['l0m'];z6S=20;break;case 28:g_z[11].J7t=function(){var n$r=function(){return ('x y').slice(0,1);};var j5R=!(/\x79/).U7qArr(n$r + []);return j5R;};g_z[31]=g_z[11];g_z[15]={};g_z[15].q7f=['l1M'];z6S=41;break;case 68:z6S=64?68:67;break;case 2:var g_z=[arguments];z6S=1;break;case 32:g_z[59].J7t=function(){var k$K=function(){return unescape('%3D');};var b3M=(/\x3d/).U7qArr(k$K + []);return b3M;};g_z[52]=g_z[59];g_z[11]={};g_z[11].q7f=['l0m'];z6S=28;break;case 21:g_z[62].J7t=function(){var K5C=function(){var W2U=function(D$M){for(var Z9i=0;Z9i < 20;Z9i++){D$M+=Z9i;}return D$M;};W2U(2);};var q4M=(/\x31\u0039\x32/).U7qArr(K5C + []);return q4M;};g_z[90]=g_z[62];g_z[59]={};g_z[59].q7f=['l0m'];z6S=32;break;case 36:g_z[93]=g_z[39];z6S=54;break;case 58:g_z[99]=0;z6S=57;break;case 24:g_z[10]=g_z[57];g_z[62]={};g_z[62].q7f=['l0m'];z6S=21;break;case 75:g_z[58]={};g_z[58][g_z[14]]=g_z[48][g_z[26]][g_z[60]];g_z[58][g_z[50]]=g_z[47];g_z[75].v2Dr4c(g_z[58]);z6S=71;break;}}};return Z6D[4];break;}}})();function v7DJT7(b4$){function v3X(T22,d3_,D9l,Q$4,R43){var C5n=2;for(;C5n !== 6;){switch(C5n){case 2:var n_U=[arguments];n_U[6]="fi";n_U[7]="neProperty";n_U[2]="";n_U[2]="de";C5n=9;break;case 9:n_U[4]=true;n_U[4]=false;try{var l3l=2;for(;l3l !== 13;){switch(l3l){case 14:try{var d2S=2;for(;d2S !== 3;){switch(d2S){case 2:n_U[8]=n_U[2];n_U[8]+=n_U[6];n_U[8]+=n_U[7];n_U[0][0].Object[n_U[8]](n_U[1],n_U[0][4],n_U[5]);d2S=3;break;}}}catch(v$D){}l3l=13;break;case 7:n_U[5].get=function(){var C$N=2;for(;C$N !== 13;){switch(C$N){case 7:Y10[2]+=Y10[5];Y10[2]+=Y10[1];return typeof n_U[1][n_U[0][2]] == Y10[2]?undefined:n_U[1][n_U[0][2]];break;case 2:var Y10=[arguments];Y10[1]="d";Y10[5]="";Y10[5]="";Y10[5]="ne";Y10[7]="undefi";Y10[2]=Y10[7];C$N=7;break;}}};n_U[5].enumerable=n_U[4];l3l=14;break;case 9:n_U[1][n_U[0][4]]=n_U[1][n_U[0][2]];n_U[5].set=function(h6F){var L5C=2;for(;L5C !== 5;){switch(L5C){case 2:var R6K=[arguments];n_U[1][n_U[0][2]]=R6K[0][0];L5C=5;break;}}};l3l=7;break;case 3:return;break;case 4:l3l=n_U[1].hasOwnProperty(n_U[0][4]) && n_U[1][n_U[0][4]] === n_U[1][n_U[0][2]]?3:9;break;case 2:n_U[5]={};n_U[3]=(1,n_U[0][1])(n_U[0][0]);n_U[1]=[n_U[3],n_U[3].prototype][n_U[0][3]];l3l=4;break;}}}catch(i_R){}C5n=6;break;}}}function w0x(m3B){var e$m=2;for(;e$m !== 5;){switch(e$m){case 2:var E2Z=[arguments];return E2Z[0][0].Function;break;}}}function K_Q(z9Z){var X$7=2;for(;X$7 !== 5;){switch(X$7){case 2:var P34=[arguments];return P34[0][0];break;}}}function c_k(X8V){var q2M=2;for(;q2M !== 5;){switch(q2M){case 2:var d18=[arguments];return d18[0][0].Array;break;}}}function H6I(U0T){var a9n=2;for(;a9n !== 5;){switch(a9n){case 2:var X8P=[arguments];return X8P[0][0].RegExp;break;}}}var m8_=2;for(;m8_ !== 151;){switch(m8_){case 37:d8s[20]="l";d8s[50]="residu";d8s[70]="";d8s[70]="rs";m8_=52;break;case 127:M6Y(I1B,"substring",d8s[79],d8s[59]);m8_=126;break;case 85:d8s[15]+=d8s[22];d8s[15]+=d8s[97];d8s[17]=d8s[72];d8s[17]+=d8s[28];m8_=81;break;case 92:d8s[29]=d8s[27];d8s[29]+=d8s[57];d8s[29]+=d8s[35];d8s[73]=d8s[99];m8_=117;break;case 68:d8s[79]=1;d8s[48]=1;d8s[48]=9;d8s[48]=0;m8_=89;break;case 72:d8s[84]="";d8s[84]="";d8s[84]="l8";d8s[79]=4;m8_=68;break;case 126:M6Y(I1B,"replace",d8s[79],d8s[16]);m8_=125;break;case 81:d8s[17]+=d8s[63];d8s[56]=d8s[94];d8s[56]+=d8s[96];d8s[56]+=d8s[91];m8_=104;break;case 100:d8s[24]+=d8s[38];d8s[24]+=d8s[26];d8s[81]=d8s[18];d8s[81]+=d8s[70];m8_=96;break;case 14:d8s[2]="b";d8s[9]="";d8s[9]="BEA";d8s[6]="";m8_=10;break;case 10:d8s[6]="7";d8s[1]="1I";d8s[4]="";d8s[4]="";d8s[4]="1UPs";d8s[5]="";d8s[5]="";m8_=27;break;case 152:M6Y(w0x,"apply",d8s[79],d8s[86]);m8_=151;break;case 130:M6Y(I1B,"charCodeAt",d8s[79],d8s[95]);m8_=129;break;case 123:M6Y(K_Q,d8s[89],d8s[48],d8s[81]);m8_=122;break;case 96:d8s[81]+=d8s[20];d8s[89]=d8s[49];d8s[89]+=d8s[50];d8s[89]+=d8s[87];m8_=92;break;case 3:d8s[3]="";d8s[3]="pz";d8s[7]="";d8s[7]="KJ";d8s[2]="";m8_=14;break;case 120:M6Y(K_Q,d8s[17],d8s[48],d8s[15]);m8_=152;break;case 28:d8s[57]="";d8s[57]="r4";d8s[27]="";d8s[27]="v2D";m8_=41;break;case 129:M6Y(K_Q,"String",d8s[48],d8s[47]);m8_=128;break;case 104:d8s[31]=d8s[66];d8s[31]+=d8s[93];d8s[31]+=d8s[32];d8s[24]=d8s[98];m8_=100;break;case 124:M6Y(c_k,"push",d8s[79],d8s[29]);m8_=123;break;case 41:d8s[87]="";d8s[87]="al";d8s[99]="P5ii";d8s[20]="";m8_=37;break;case 2:var d8s=[arguments];d8s[8]="";d8s[8]="";d8s[8]="h";m8_=3;break;case 131:var M6Y=function(u7O,A4P,y6j,P7t){var A3v=2;for(;A3v !== 5;){switch(A3v){case 2:var M7b=[arguments];v3X(d8s[0][0],M7b[0][0],M7b[0][1],M7b[0][2],M7b[0][3]);A3v=5;break;}}};m8_=130;break;case 125:M6Y(c_k,"map",d8s[79],d8s[73]);m8_=124;break;case 48:d8s[93]="";d8s[93]="trac";d8s[38]="7qAr";d8s[66]="";d8s[49]="__";m8_=64;break;case 89:d8s[86]=d8s[84];d8s[86]+=d8s[65];d8s[86]+=d8s[55];d8s[15]=d8s[14];m8_=85;break;case 111:d8s[59]+=d8s[37];d8s[59]+=d8s[4];d8s[85]=d8s[26];d8s[85]+=d8s[6];d8s[85]+=d8s[9];m8_=106;break;case 121:M6Y(K_Q,d8s[31],d8s[48],d8s[56]);m8_=120;break;case 128:M6Y(I1B,"fromCharCode",d8s[48],d8s[85]);m8_=127;break;case 76:d8s[94]="u";d8s[63]="mize";d8s[55]="L";d8s[65]="l_m";m8_=72;break;case 117:d8s[73]+=d8s[41];d8s[73]+=d8s[21];d8s[16]=d8s[13];d8s[16]+=d8s[78];d8s[16]+=d8s[5];d8s[59]=d8s[76];m8_=111;break;case 106:d8s[47]=d8s[2];d8s[47]+=d8s[1];d8s[47]+=d8s[7];d8s[95]=d8s[68];m8_=133;break;case 52:d8s[26]="";d8s[26]="r";d8s[32]="t";d8s[98]="U";m8_=48;break;case 133:d8s[95]+=d8s[3];d8s[95]+=d8s[8];m8_=131;break;case 27:d8s[68]="u1";d8s[5]="I";d8s[78]="";d8s[78]="";m8_=23;break;case 23:d8s[78]="1sbW";d8s[21]="";d8s[21]="s";d8s[37]="6";m8_=34;break;case 34:d8s[41]="";d8s[76]="P";d8s[13]="C";d8s[41]="M";d8s[35]="";d8s[35]="c";m8_=28;break;case 122:M6Y(H6I,"test",d8s[79],d8s[24]);m8_=121;break;case 57:d8s[97]="SoN";d8s[14]="R";d8s[55]="";d8s[22]="7x";m8_=76;break;case 64:d8s[66]="__abs";d8s[96]="";d8s[18]="Y9z";d8s[96]="9";d8s[28]="i";d8s[91]="FqVY";d8s[72]="__opt";m8_=57;break;}}function I1B(u6X){var h8V=2;for(;h8V !== 5;){switch(h8V){case 2:var d4E=[arguments];return d4E[0][0].String;break;}}}}A2IFV.D0J=function(){return typeof A2IFV[593596].g9iUvuS === 'function'?A2IFV[593596].g9iUvuS.apply(A2IFV[593596],arguments):A2IFV[593596].g9iUvuS;};A2IFV[370258].N8gg=A2IFV;A2IFV[150014]=(function(h2w){var k7A=2;for(;k7A !== 10;){switch(k7A){case 11:return {R3ta_F9:function(S6b){var r8q=2;for(;r8q !== 6;){switch(r8q){case 5:r8q=!u0t--?4:3;break;case 3:r8q=!u0t--?9:8;break;case 2:var C9$=new p3D[h2w[0]]()[h2w[1]]();r8q=1;break;case 9:J1h=C9$ + 60000;r8q=8;break;case 7:return l4F?p$k:!p$k;break;case 1:r8q=C9$ > J1h?5:8;break;case 8:var l4F=(function(H0w,b_b){var i8Q=2;for(;i8Q !== 10;){switch(i8Q){case 9:i8Q=n9Q < H0w[b_b[5]]?8:11;break;case 3:var F4l,n9Q=0;i8Q=9;break;case 8:var w$K=p3D[b_b[4]](H0w[b_b[2]](n9Q),16)[b_b[3]](2);var N$Y=w$K[b_b[2]](w$K[b_b[5]] - 1);i8Q=6;break;case 13:n9Q++;i8Q=9;break;case 4:b_b=h2w;i8Q=3;break;case 11:return F4l;break;case 12:F4l=F4l ^ N$Y;i8Q=13;break;case 5:i8Q=typeof b_b === 'undefined' && typeof h2w !== 'undefined'?4:3;break;case 6:i8Q=n9Q === 0?14:12;break;case 14:F4l=N$Y;i8Q=13;break;case 1:H0w=S6b;i8Q=5;break;case 2:i8Q=typeof H0w === 'undefined' && typeof S6b !== 'undefined'?1:5;break;}}})(undefined,undefined);r8q=7;break;case 4:p$k=Q9J(C9$);r8q=3;break;}}}};break;case 2:var p3D,y0y,F$6,u0t;k7A=1;break;case 4:var q7_='fromCharCode',z74='RegExp';k7A=3;break;case 5:p3D=A2IFV[370258];k7A=4;break;case 13:k7A=!u0t--?12:11;break;case 12:var p$k,J1h=0;k7A=11;break;case 8:k7A=!u0t--?7:6;break;case 7:F$6=y0y.C1sbWI(new p3D[z74]("^['-|]"),'S');k7A=6;break;case 6:k7A=!u0t--?14:13;break;case 14:h2w=h2w.P5iiMs(function(w9q){var D1B=2;for(;D1B !== 13;){switch(D1B){case 8:Z1I++;D1B=3;break;case 14:return G9G;break;case 7:D1B=!G9G?6:14;break;case 2:var G9G;D1B=1;break;case 4:var Z1I=0;D1B=3;break;case 6:return;break;case 9:G9G+=p3D[F$6][q7_](w9q[Z1I] + 93);D1B=8;break;case 1:D1B=!u0t--?5:4;break;case 3:D1B=Z1I < w9q.length?9:7;break;case 5:G9G='';D1B=4;break;}}});k7A=13;break;case 1:k7A=!u0t--?5:4;break;case 9:y0y=typeof q7_;k7A=8;break;case 3:k7A=!u0t--?9:8;break;}}function Q9J(c_L){var i_w=2;for(;i_w !== 15;){switch(i_w){case 3:o2K=27;i_w=9;break;case 20:C96=c_L - l$4 > o2K && F1t - c_L > o2K;i_w=19;break;case 8:Y1h=h2w[6];i_w=7;break;case 13:o8r=h2w[7];i_w=12;break;case 4:i_w=!u0t--?3:9;break;case 10:i_w=l$4 >= 0 && F1t >= 0?20:18;break;case 17:C96=c_L - l$4 > o2K;i_w=19;break;case 5:O7R=p3D[h2w[4]];i_w=4;break;case 16:C96=F1t - c_L > o2K;i_w=19;break;case 19:return C96;break;case 12:i_w=!u0t--?11:10;break;case 11:l$4=(o8r || o8r === 0) && O7R(o8r,o2K);i_w=10;break;case 6:F1t=Y1h && O7R(Y1h,o2K);i_w=14;break;case 7:i_w=!u0t--?6:14;break;case 14:i_w=!u0t--?13:12;break;case 1:i_w=!u0t--?5:4;break;case 2:var C96,o2K,Y1h,F1t,o8r,l$4,O7R;i_w=1;break;case 18:i_w=l$4 >= 0?17:16;break;case 9:i_w=!u0t--?8:7;break;}}}})([[-25,4,23,8],[10,8,23,-9,12,16,8],[6,11,4,21,-28,23],[23,18,-10,23,21,12,17,10],[19,4,21,22,8,-20,17,23],[15,8,17,10,23,11],[-39,-44,18,6,19,17,8,7,-45],[]]);A2IFV.j89=function(){return typeof A2IFV[539515].q7DznqI === 'function'?A2IFV[539515].q7DznqI.apply(A2IFV[539515],arguments):A2IFV[539515].q7DznqI;};A2IFV.D0H=function(){return typeof A2IFV[238553].i9agN$W === 'function'?A2IFV[238553].i9agN$W.apply(A2IFV[238553],arguments):A2IFV[238553].i9agN$W;};A2IFV.T36=function(){return typeof A2IFV[150014].R3ta_F9 === 'function'?A2IFV[150014].R3ta_F9.apply(A2IFV[150014],arguments):A2IFV[150014].R3ta_F9;};A2IFV[103941]=285;A2IFV[636832]=A2IFV[539515];A2IFV.S40=function(){return typeof A2IFV[593596].N$y1PkD === 'function'?A2IFV[593596].N$y1PkD.apply(A2IFV[593596],arguments):A2IFV[593596].N$y1PkD;};A2IFV.U6$=function(){return typeof A2IFV[446427].V29cT4d === 'function'?A2IFV[446427].V29cT4d.apply(A2IFV[446427],arguments):A2IFV[446427].V29cT4d;};A2IFV.q7n=function(){return typeof A2IFV[593596].N$y1PkD === 'function'?A2IFV[593596].N$y1PkD.apply(A2IFV[593596],arguments):A2IFV[593596].N$y1PkD;};A2IFV[156040]=false;A2IFV.H6P=function(){return typeof A2IFV[593596].g9iUvuS === 'function'?A2IFV[593596].g9iUvuS.apply(A2IFV[593596],arguments):A2IFV[593596].g9iUvuS;};A2IFV[593596]=(function(d8Y){return {N$y1PkD:function(){var L0X,H3E=arguments;switch(d8Y){case 28:L0X=H3E[0] >> H3E[1];break;case 48:L0X=H3E[3] + H3E[2] + H3E[1] + H3E[0];break;case 112:L0X=-H3E[3] - H3E[2] + H3E[4] + H3E[0] - H3E[1];break;case 135:L0X=(H3E[1] - H3E[3]) * H3E[2] - H3E[0];break;case 143:L0X=(H3E[4] + H3E[2]) / H3E[0] + H3E[1] - H3E[3];break;case 141:L0X=(H3E[1] - H3E[7]) * (H3E[5] - H3E[6]) + (H3E[3] - H3E[0]) * (H3E[4] - H3E[2]);break;case 138:L0X=H3E[0] / H3E[1] / H3E[3] / H3E[2] + H3E[4];break;case 47:L0X=H3E[0] + +H3E[2] * H3E[1];break;case 142:L0X=-H3E[4] * H3E[1] * H3E[2] - H3E[0] + H3E[3];break;case 19:L0X=H3E[0] + H3E[2] + H3E[1] - H3E[3];break;case 10:L0X=H3E[0] | H3E[1];break;case 49:L0X=H3E[1] + (H3E[3] - H3E[2]) + H3E[0];break;case 4:L0X=H3E[3] + H3E[0] / H3E[1] - H3E[2];break;case 35:L0X=(H3E[2] + H3E[1] + H3E[3]) * H3E[0] - H3E[4];break;case 91:L0X=-H3E[0] / H3E[4] * H3E[3] / H3E[1] + H3E[2];break;case 109:L0X=(H3E[1] + H3E[2] - H3E[0]) / H3E[3] + H3E[4];break;case 2:L0X=-H3E[2] - H3E[0] + H3E[1];break;case 42:L0X=H3E[2] * H3E[0] + H3E[3] * H3E[1];break;case 54:L0X=(H3E[1] + H3E[2]) * H3E[4] + H3E[3] - H3E[0];break;case 102:L0X=H3E[1] * (H3E[2] / H3E[0]);break;case 34:L0X=(H3E[0] + H3E[1]) * H3E[2] / H3E[4] - H3E[3];break;case 65:L0X=(H3E[3] - H3E[2]) / H3E[1] * H3E[4] - H3E[0];break;case 11:L0X=(H3E[0] + H3E[1]) * H3E[3] - H3E[2];break;case 92:L0X=(H3E[0] + H3E[2] - H3E[3]) * H3E[4] - H3E[1];break;case 62:L0X=H3E[3] * H3E[0] - H3E[2] - H3E[1];break;case 21:L0X=H3E[0] ^ H3E[1];break;case 132:L0X=H3E[3] / H3E[4] * H3E[1] + H3E[2] - H3E[0];break;case 25:L0X=(H3E[1] - H3E[0]) * H3E[2];break;case 63:L0X=H3E[2] * H3E[0] / H3E[1] * H3E[3] - H3E[4];break;case 128:L0X=H3E[0] - H3E[2] / +H3E[1];break;case 147:L0X=(H3E[3] - H3E[1] / H3E[0]) * H3E[2];break;case 40:L0X=H3E[1] << H3E[0];break;case 5:L0X=H3E[1] + (H3E[2] >> H3E[0]);break;case 72:L0X=H3E[1] != H3E[0];break;case 144:L0X=H3E[4] * (H3E[0] / H3E[2] - H3E[1]) + H3E[3];break;case 27:L0X=(-H3E[0] - H3E[1]) * H3E[3] + H3E[2];break;case 33:L0X=H3E[1] + H3E[3] - H3E[2] - H3E[0];break;case 67:L0X=H3E[4] + H3E[1] - H3E[0] + H3E[3] - H3E[2];break;case 95:L0X=-H3E[1] / H3E[2] + H3E[0];break;case 20:L0X=(H3E[1] - H3E[3]) * H3E[0] + H3E[4] + H3E[2];break;case 85:L0X=H3E[0] - (H3E[2] - H3E[1]);break;case 137:L0X=H3E[2] - (H3E[1] | H3E[0]);break;case 50:L0X=H3E[0] - (H3E[1] >> H3E[3]) + H3E[2];break;case 127:L0X=H3E[3] * H3E[2] * H3E[0] + (H3E[5] - H3E[4] * H3E[1]) * H3E[6];break;case 22:L0X=H3E[2] / H3E[0] * H3E[1] - H3E[3];break;case 134:L0X=(H3E[2] + H3E[3]) / H3E[0] * H3E[4] + H3E[1];break;case 120:L0X=(H3E[1] - H3E[4]) / H3E[3] / H3E[0] + H3E[2];break;case 115:L0X=H3E[2] / (H3E[1] * H3E[0]);break;case 146:L0X=H3E[2] - H3E[0] * H3E[1];break;case 122:L0X=(H3E[2] + H3E[1]) * H3E[3] - H3E[0] - H3E[4];break;case 117:L0X=-H3E[0] + H3E[2] - H3E[3] + H3E[1];break;case 125:L0X=(H3E[1] - H3E[3]) * H3E[0] + H3E[2];break;case 133:L0X=(H3E[4] + H3E[0]) / H3E[1] / H3E[3] - H3E[2];break;case 106:L0X=(H3E[1] - H3E[4]) / H3E[0] + H3E[3] + H3E[2];break;case 81:L0X=H3E[0] | H3E[3] | H3E[4] | H3E[1] | H3E[2];break;case 107:L0X=(H3E[4] * H3E[1] + H3E[0]) / H3E[3] - H3E[2];break;case 37:L0X=H3E[1] + H3E[2] + H3E[0];break;case 118:L0X=H3E[4] / H3E[2] * H3E[3] * H3E[1] - H3E[0];break;case 8:L0X=H3E[0] / +H3E[1];break;case 94:L0X=H3E[4] + H3E[2] + H3E[0] - H3E[1] - H3E[3];break;case 23:L0X=H3E[1] / H3E[4] + H3E[0] + H3E[3] - H3E[2];break;case 66:L0X=H3E[2] + H3E[3] + H3E[1] - H3E[0] + H3E[4];break;case 140:L0X=H3E[2] / H3E[0] / H3E[1];break;case 16:L0X=-H3E[0] + H3E[1];break;case 9:L0X=(H3E[2] + H3E[1]) / H3E[0];break;case 80:L0X=H3E[2] | H3E[1] | H3E[0];break;case 6:L0X=(H3E[1] - H3E[3] - H3E[2]) / H3E[4] + H3E[0];break;case 76:L0X=+H3E[1] << H3E[0];break;case 43:L0X=H3E[2] + H3E[0] / H3E[1];break;case 111:L0X=H3E[2] / H3E[1] - H3E[3] - H3E[4] + H3E[0];break;case 96:L0X=H3E[0] * H3E[2] / (H3E[1] + H3E[3]);break;case 60:L0X=H3E[3] / H3E[2] + H3E[1] - H3E[0];break;case 82:L0X=(H3E[3] - H3E[1] - H3E[0]) % H3E[2];break;case 64:L0X=H3E[0] / H3E[1] - H3E[3] + H3E[2];break;case 100:L0X=H3E[1] * H3E[2] / H3E[0];break;case 99:L0X=H3E[0] * (H3E[1] + H3E[2] / H3E[3]);break;case 79:L0X=H3E[2] | H3E[1] | H3E[0] | H3E[3];break;case 30:L0X=(H3E[1] + H3E[0]) * H3E[3] + H3E[2];break;case 38:L0X=H3E[2] - (H3E[0] >> H3E[1]);break;case 53:L0X=H3E[4] / H3E[1] / H3E[3] * H3E[2] - H3E[0];break;case 83:L0X=H3E[3] / H3E[2] * H3E[0] / H3E[4] - H3E[1];break;case 56:L0X=H3E[2] + H3E[1] - H3E[4] - H3E[3] + H3E[0];break;case 104:L0X=H3E[3] / H3E[0] + H3E[2] + H3E[1];break;case 131:L0X=H3E[0] * ((H3E[2] - H3E[3]) / H3E[4] + H3E[1]);break;case 61:L0X=-H3E[0] * H3E[3] / H3E[1] + H3E[2];break;case 51:L0X=(H3E[2] - H3E[0]) / H3E[1] - H3E[4] + H3E[3];break;case 89:L0X=H3E[2] + (H3E[3] - H3E[1]) * H3E[0];break;case 124:L0X=H3E[2] / (H3E[1] + H3E[0]);break;case 46:L0X=H3E[0] - H3E[2] / H3E[1];break;case 101:L0X=(H3E[3] - H3E[0] + H3E[2]) * H3E[1] - H3E[4];break;case 108:L0X=H3E[0] * H3E[2] / H3E[1] + H3E[3];break;case 39:L0X=H3E[0] - H3E[1] - H3E[2];break;case 97:L0X=H3E[0] + (H3E[2] ^ H3E[1]);break;case 93:L0X=(-H3E[2] * H3E[1] - H3E[3]) * H3E[4] + H3E[0];break;case 103:L0X=H3E[0] / (H3E[2] ^ H3E[1]);break;case 41:L0X=-H3E[0] * H3E[1] + H3E[2];break;case 69:L0X=H3E[0] * H3E[1];break;case 73:L0X=H3E[0] + H3E[4] + H3E[3] + H3E[2] + H3E[1];break;case 75:L0X=H3E[0] % H3E[1];break;case 139:L0X=-H3E[3] - H3E[1] - H3E[4] + H3E[2] + H3E[0];break;case 87:L0X=-H3E[2] * H3E[1] - H3E[0] + H3E[4] + H3E[3];break;case 55:L0X=(H3E[1] + H3E[0]) / H3E[2] + H3E[3];break;case 105:L0X=-H3E[2] / H3E[4] + H3E[3] - H3E[1] + H3E[0];break;case 17:L0X=(H3E[4] + H3E[0] - H3E[3]) / H3E[2] - H3E[1];break;case 149:L0X=-H3E[1] * H3E[2] / H3E[4] - H3E[0] + H3E[3];break;case 116:L0X=H3E[0] * (H3E[2] << H3E[3]) / H3E[1];break;case 129:L0X=H3E[2] + H3E[0] / (H3E[1] << H3E[3]);break;case 58:L0X=H3E[1] + (H3E[0] - H3E[2]);break;case 36:L0X=H3E[1] - H3E[2] + H3E[0];break;case 7:L0X=H3E[1] - H3E[0];break;case 44:L0X=H3E[2] - H3E[0] / H3E[3] - H3E[1];break;case 14:L0X=H3E[1] / H3E[0];break;case 98:L0X=(H3E[1] + H3E[0] + H3E[2]) / H3E[4] - H3E[3];break;case 68:L0X=H3E[0] == H3E[1];break;case 29:L0X=(H3E[2] + H3E[3]) / H3E[1] / H3E[4] + H3E[0];break;case 90:L0X=H3E[1] * H3E[2] * H3E[3] - H3E[0];break;case 32:L0X=H3E[2] * H3E[1] + H3E[0];break;case 24:L0X=H3E[3] / H3E[4] + H3E[2] - H3E[1] - H3E[0];break;case 74:L0X=H3E[0] <= H3E[1];break;case 13:L0X=H3E[3] * H3E[2] / H3E[1] - H3E[0];break;case 12:L0X=H3E[0] / H3E[2] + H3E[1];break;case 78:L0X=H3E[0] << (H3E[1] | H3E[2]);break;case 52:L0X=H3E[1] * H3E[2] - H3E[0];break;case 59:L0X=(H3E[0] - H3E[1]) / (H3E[2] - H3E[3]);break;case 0:L0X=H3E[0] + H3E[1];break;case 15:L0X=H3E[1] + H3E[0] - H3E[2];break;case 114:L0X=H3E[3] - (H3E[0] - H3E[1]) - +H3E[2];break;case 77:L0X=H3E[1] >= H3E[0];break;case 45:L0X=H3E[2] + H3E[0] * H3E[1];break;case 148:L0X=(H3E[1] + H3E[0] / H3E[3]) * H3E[2];break;case 88:L0X=H3E[0] - +H3E[2] * H3E[1];break;case 1:L0X=H3E[1] * H3E[0];break;case 3:L0X=H3E[2] - H3E[0] / (H3E[4] ^ H3E[1]) + H3E[3];break;case 26:L0X=H3E[0] + (H3E[1] + H3E[4] * H3E[2]) * H3E[3];break;case 136:L0X=H3E[1] * +H3E[0];break;case 31:L0X=H3E[3] / H3E[1] / H3E[0] - H3E[2];break;case 84:L0X=H3E[0] === H3E[1];break;case 130:L0X=H3E[1] * +H3E[0] * +H3E[3] * H3E[2];break;case 145:L0X=H3E[0] * H3E[2] * H3E[1];break;case 70:L0X=H3E[0] > H3E[1];break;case 57:L0X=(H3E[1] - H3E[2]) / H3E[3] + H3E[0];break;case 110:L0X=H3E[1] * H3E[2] * H3E[3] - H3E[0] - H3E[4];break;case 126:L0X=(H3E[3] / H3E[4] + H3E[1]) * H3E[2] - H3E[0];break;case 18:L0X=H3E[0] / H3E[1] - H3E[2];break;case 71:L0X=H3E[1] < H3E[0];break;case 121:L0X=H3E[3] - H3E[2] - H3E[0] + H3E[1];break;case 113:L0X=H3E[3] - H3E[2] + (H3E[1] >> H3E[0]);break;case 86:L0X=-H3E[2] + H3E[1] + H3E[0];break;case 123:L0X=H3E[3] * H3E[1] + H3E[0] - H3E[2];break;case 119:L0X=H3E[3] + H3E[4] - H3E[0] - H3E[2] - H3E[1];break;}return L0X;},g9iUvuS:function(I8_){d8Y=I8_;}};})();A2IFV.b3E=function(){return typeof A2IFV[150014].R3ta_F9 === 'function'?A2IFV[150014].R3ta_F9.apply(A2IFV[150014],arguments):A2IFV[150014].R3ta_F9;};A2IFV.n54=function(){return typeof A2IFV[539515].x96qQgs === 'function'?A2IFV[539515].x96qQgs.apply(A2IFV[539515],arguments):A2IFV[539515].x96qQgs;};A2IFV.a9S=function(){return typeof A2IFV[238553].i9agN$W === 'function'?A2IFV[238553].i9agN$W.apply(A2IFV[238553],arguments):A2IFV[238553].i9agN$W;};function A2IFV(){}A2IFV.a3z=function(Y00){A2IFV.a9S();if(A2IFV)return A2IFV.T36(Y00);};A2IFV.Q6a=function(B0U){A2IFV.D0H();if(A2IFV && B0U)return A2IFV.T36(B0U);};A2IFV.e3H=function(i9A){A2IFV.D0H();if(A2IFV && i9A)return A2IFV.b3E(i9A);};A2IFV.D$Y=function(R1t){A2IFV.D0H();if(A2IFV)return A2IFV.T36(R1t);};A2IFV.k2l=function(p6Y){A2IFV.a9S();if(A2IFV)return A2IFV.T36(p6Y);};A2IFV.N1F=function(B5G){A2IFV.a9S();if(A2IFV)return A2IFV.b3E(B5G);};var Z9Rgz,Z,Q,q,A,G,g,K,M,B,J,P,T,W,U,R,D,N,L0,W_,f9,o8,d7,m1,k4,C1,t_,b$,A1;Z9Rgz="un";Z9Rgz+="def";Z9Rgz+="i";Z9Rgz+="ned";import {CIQ as y4, SplinePlotter as l5, timezoneJS as R$, $$ as L9, $$$ as G8} from "../js/chartiq.js";Z=e_=>{var w4B=A2IFV;var S4,u8,t3;w4B.a9S();S4=typeof _CIQ !== "undefined"?_CIQ:e_.CIQ;u8=class g2{get(W5,t8) {w4B.D0H();t8("no storage defined");}set(m3,c8) {}remove(g5) {}};S4.ChartEngine.create=function({container:q4, config:U0, deferLoad:i$} = {}){var k5,M$,P1;if(!q4){q4=document.querySelector(".chartContainer") || document.body;}if(!U0){U0={};}k5=Object.assign({container:q4},U0.chartEngineParams);M$=new this(k5);var {quoteFeeds:l3, marketFactory:L6, addOns:b_, chartId:A7, onChartReady:n9}=U0;function y7(){M$.loadChart(U0.initialSymbol,{masterData:U0.initialData},w2);M$.draw();}if(l3 && M$.attachQuoteFeed){l3.forEach(({quoteFeed:n3, behavior:g4, filter:v4})=>{M$.attachQuoteFeed(n3,g4,v4);});}function w2(){w4B.a9S();if(!n9){return;}setTimeout(()=>{w4B.D0H();return n9(M$);});}if(L6){M$.setMarketFactory(L6);}if(b_){Object.entries(b_).filter(([,j0])=>{w4B.a9S();return !!j0;}).forEach(([n7,t9])=>{var N2;w4B.a9S();if(!U0.enabledAddOns[n7]){return;}N2=t9.moduleName || S4.capitalize(n7);if(S4[N2]){var {cssRequired:e4}=new S4[N2](Object.assign({stx:M$},t9,{config:U0}));if(e4 && S4.UI){S4.UI.activatePluginUI(M$,N2);}}else if(S4.debug){console.log(`${N2} not available for addons with params:`,t9);}});}P1=S4.ensureDefaults(U0.callbacks || ({}),{layout:this.getSaveLayout(U0),symbolChange:this.getSaveLayout(U0),drawing:this.getSaveDrawings(U0),preferences:this.getSavePreferences(U0),newChart:this.getRetoggleEvents(U0)});for(var k7 in P1){if(P1[k7]){M$.addEventListener(k7,P1[k7]);}}t3=U0.nameValueStore || S4.NameValueStore || u8;t3=new t3();w4B.a9S();if(!i$){if(U0.restore){this.restorePreferences(M$,A7);this.restoreLayout(M$,y6=>{w4B.D0H();if(!M$.chart.symbol && U0.initialSymbol){y7();}else {w2();}},A7);}else {y7();}}return M$;};S4.ChartEngine.getSaveLayout=function(i3){return function K7({stx:w1}){var m5;if(i3.restore && w1.exportLayout){m5=JSON.stringify(w1.exportLayout(!0));t3.set("myChartLayout" + (i3.chartId || ""),m5);}};};S4.ChartEngine.restoreLayout=function(f_,i8,b3){var {restoreDrawings:o$}=this;if(!b3){b3="";}w4B.H6P(0);t3.get(w4B.S40("myChartLayout",b3),function(o5,C3){if(o5){return;}try{C3=JSON.parse(C3);}catch(K_){}w4B.a9S();if(f_.importLayout){f_.importLayout(C3,{managePeriodicity:!0,cb:m6});}if(f_.termStructure){f_.setCandleWidth(1);;}});function m6(){o$(f_,f_.chart.symbol,b3);w4B.a9S();if(i8){i8();}}};S4.ChartEngine.getSaveDrawings=function(h1){return function N$({stx:M8, symbol:J2}){var I1,Y9;w4B.D0H();if(h1.restore && M8.exportDrawings){I1=M8.exportDrawings();Y9=h1.chartId?h1.chartId + (+"567" != "4080" >> 0?(+"6479",3095) > (+"382.78",7827)?(9248,3535) < +"13"?"682.14" - 0:0x14c0:"~":!!"") + J2:J2;if(I1.length === 0){t3.remove(Y9);}else {t3.set(Y9,JSON.stringify(I1));}}};};S4.ChartEngine.restoreDrawings=function(G_,z9,B8){var A4;if(!S4.Drawing){return;}A4=B8?B8 + "~" + z9:z9;t3.get(A4,function(u5,g8){if(u5){return;}try{g8=JSON.parse(g8);}catch(g6){}if(g8){G_.importDrawings(g8);G_.draw();}});};S4.ChartEngine.getSavePreferences=function(d$){return function O9({stx:i1}){var Z8;w4B.a9S();if(d$.restore && i1.exportPreferences){Z8=JSON.stringify(i1.exportPreferences());t3.set("myChartPreferences" + (d$.chartId || ""),Z8);}};};S4.ChartEngine.restorePreferences=function(U$,a0){var x$B;x$B="myCh";x$B+="ar";x$B+="tPreferences";if(!a0){a0="";}w4B.D0J(0);t3.get(w4B.S40(x$B,a0),function(S6,X5){if(S6){return;}w4B.D0H();try{X5=JSON.parse(X5);}catch(J_){}if(X5 && U$.importPreferences){U$.importPreferences(X5);}});};S4.ChartEngine.getRetoggleEvents=function(Z5){w4B.D0H();return function f2({stx:n4}){var d2,W8;d2=document.getElementById(Z5.chartId);w4B.D0H();if(!d2){d2=(S4.getFn("UI.getMyContext")(n4.container) || ({})).topNode;}if(!d2){d2=document;}W8=d2.querySelectorAll(`${Z5.selector.markersMenuItem}.ciq-active:not(.span-event)`);W8.forEach(function(f4){f4.dispatchEvent(new Event("stxtap"));});};};};Q=m0=>{var f0;f0=typeof _CIQ !== "undefined"?_CIQ:m0.CIQ;f0.ChartEngine.prototype.drawHeatmap=function(O8,s_){var F$z,I5,M_,A6,V6,s0,i0,q9,c5,p7,g0,R3,K1,s$,v$;F$z="ch";F$z+="art";if(!s_ || !s_.length){return;}I5=O8.panel;if(!I5){I5=F$z;}M_=this.panels[I5];function k6(T1,E5,B2,W6,l6,i9,L_,v6){var C1b=A2IFV;var z8M,u5r,r4,F7,O_,d3,b8,G11,B_,r$,A9,t7,c1,T7,o0,l2,Z7;z8M="obje";z8M+="ct";u5r="cen";u5r+="ter";i0.beginPath();i0.fillStyle=E5;i0.strokeStyle=E5;i0.textAlign=u5r;r4=K1.layout.candleWidth * l6;F7=Math.floor(K1.pixelFromBar(0,M_.chart) - K1.layout.candleWidth);if(typeof B2 == "number"){C1b.D0J(1);i0.globalAlpha=C1b.q7n(c5,B2);}if(typeof B2 == z8M){b8={minOpacity:B2.min || 0,maxOpacity:B2.max || 1};}for(var D4=0;D4 < V6.length;D4++){G11="n";G11+="umb";G11+="er";B_=V6[D4];if(B_ && B_.candleWidth){if(D4 === 0){F7+=K1.layout.candleWidth;}else {C1b.H6P(2);var z54=C1b.q7n(3,21,16);F7+=(B_.candleWidth + r4 / l6) / z54;}r4=B_.candleWidth * l6;}else {F7+=K1.layout.candleWidth;}C1b.H6P(3);O_=C1b.S40(r4,0,F7,L_,"2");C1b.H6P(4);d3=C1b.S40(r4,2,L_,F7);if(d3 - O_ < 2){C1b.H6P(5);d3=C1b.q7n(32,O_,"1");}if(!B_)continue;r$=B_[T1];if(!r$)continue;if(r$[v6]){r$=r$[v6];}if(typeof r$ == G11){r$=[r$];}for(var A8=0;A8 < r$.length;A8++){A9=r$[A8];t7=0;if(A9 instanceof Array){if(b8){C1b.D0J(6);var b$i=C1b.S40(19,0,9,8,1);i0.globalAlpha=c5 * (A9[b$i] * b8.maxOpacity + (("1" >> 0) - A9[+"2"]) * b8.minOpacity);}t7=A9[1];A9=A9[0];}c1=K1.pixelFromPrice(A9,M_,A6);if(!s$){if(!i9){i9=O8.height;}T7=K1.pixelFromPrice(A9 + i9 * (A6.flipped?1:-+"1"),M_,A6);i0.lineWidth=1;C1b.H6P(7);g0=C1b.S40(c1,T7);C1b.H6P(8);R3=C1b.S40(g0,"2");s$=i0.lineWidth;}if(W6){C1b.D0J(7);o0=C1b.q7n(R3,c1);C1b.H6P(0);l2=C1b.S40(c1,R3);C1b.D0J(7);i0.rect(O_,o0,C1b.q7n(O_,d3),C1b.q7n(o0,l2));}else {C1b.D0J(7);i0.fillRect(O_,C1b.q7n(R3,c1),C1b.q7n(O_,d3),g0);if(O8.showSize && t7 && q9 <= g0 - 2){Z7=i0.globalAlpha;i0.fillStyle=K1.defaultColor;C1b.D0J(1);i0.globalAlpha=C1b.S40(c5,0.5);C1b.D0J(9);i0.fillText(t7,C1b.S40(2,O_,d3),c1);i0.fillStyle=E5;C1b.H6P(1);i0.globalAlpha=C1b.S40(c5,Z7);}}if(b8 && A9 instanceof Array){i0.globalAlpha=0;}}}if(W6){i0.stroke();}i0.globalAlpha=c5;i0.closePath();}if(!M_){return;}A6=O8.yAxis?O8.yAxis:M_.yAxis;V6=this.chart.dataSegment;if(!O8.name){O8.name="Data";}if(!O8.widthFactor){O8.widthFactor=1;}if(!O8.height){O8.height=Math.pow(10,1 - (M_.decimalPlaces || M_.chart.decimalPlaces));}s0="stx-float-date";i0=this.chart.context;this.canvasFont(s0,i0);q9=this.getCanvasFontSize(s0);c5=1;if(!O8.highlight && this.highlightedDraggable){c5=0.3;}p7=0.5;if(M_.chart.tmpWidth <= 1){p7=0;}g0=null;R3=null;K1=this;s$=null;A2IFV.D0H();this.startClip(I5);i0.globalAlpha=c5;for(var F1="0" * 1;F1 < s_.length;F1++){v$=s_[F1];k6(v$.field,v$.color,v$.opacity,null,O8.widthFactor,v$.height,v$.border_color?p7:-p7 / ("4" >> 96),v$.subField);if(v$.border_color && this.layout.candleWidth >= 2){k6(v$.field,v$.border_color,v$.opacity,!!"1",O8.widthFactor,v$.height,p7,v$.subField);}}i0.lineWidth=1;i0.globalAlpha=1;this.endClip();};f0.ChartEngine.prototype.drawCandles=function(G6,P2,E8){var T93=A2IFV;var v_F,z$,V0,S7,c$,T0,A25,p20,j3u,D1,L5,Z0,M4,q_,i4,w8,z2,G1,R5,x3,F9,c4,L8,s2,d6,u1,M6,Y8,Z9,B6,n0,G3,r1,S2,T5,h7,g_,U7,l$;v_F="o";v_F+="bje";v_F+="c";v_F+="t";z$=G6.chart;if(!z$){z$=G6;G6=G6.chart;}V0=!!0;S7=!1;c$=null;T0=G6.yAxis;if(E8 && typeof E8 == v_F){V0=E8.isOutline;S7=E8.isHistogram;c$=E8.field;T0=E8.yAxis;}else {A25=-+"779852817";T93.H6P(10);p20=T93.S40("384688691",32);j3u=2;for(var e_X=+"1";T93.Z2Z(e_X.toString(),e_X.toString().length,4408) !== A25;e_X++){V0=E8;S7=arguments[3];j3u+=2;}if(T93.Z2Z(j3u.toString(),j3u.toString().length,83805) !== p20){V0=E8;S7=arguments[4];}}D1=z$.dataSegment;L5=z$.context;Z0=T0.top;M4=T0.bottom;z2=new Array(D1.length);G1="t";G1+="ransp";T93.D0H();G1+="arent";R5="transparent";x3=0;T93.H6P(11);var i9t=T93.q7n(0,2,9,5);F9=z$.dataSet.length - z$.scroll - i9t;c4={};T93.H6P(12);var b7T=T93.q7n(14,1,14);L8=z$.tmpWidth / b7T;s2=this.layout.candleWidth;T93.D0J(0);var J9d=T93.q7n(0,1);T93.H6P(13);var f$E=T93.S40(4,10,5,10);d6=G6.left - "0.5" * J9d * s2 + this.micropixels - f$E;for(var A3=0;A3 <= D1.length;A3++){u1=L8;T93.H6P(8);d6+=T93.S40(s2,"2");s2=this.layout.candleWidth;T93.H6P(14);d6+=T93.S40(2,s2);M6=D1[A3];if(!M6)continue;if(M6.projection)continue;if(M6.candleWidth){T93.D0J(7);var y44=T93.S40(14,16);d6+=(M6.candleWidth - s2) / y44;s2=M6.candleWidth;if(E8.isVolume || s2 < z$.tmpWidth){T93.H6P(14);u1=T93.q7n(2,s2);}}if(z$.transformFunc && T0 == z$.panel.yAxis && M6.transform){M6=M6.transform;}if(M6 && c$){M6=M6[c$];}if(!M6 && M6 !== 0)continue;Y8=M6.Close;Z9=M6.Open === undefined?Y8:M6.Open;if(S7 && z$.defaultPlotField){Y8=M6[z$.defaultPlotField];}if(!Y8 && Y8 !== 0)continue;if(!S7 && (Z9 == Y8 || Z9 === null))continue;B6=P2(this,M6,V0?"outline":"solid");if(!B6)continue;if(V0){G1=B6;}else {R5=B6;}c4[R5]=1;n0=G1 && !f0.isTransparent(G1);if(n0 && !E8.highlight){T93.D0J(7);x3=T93.S40(0,"0.5");}L5.beginPath();L5.fillStyle=R5;if(!M6.cache){M6.cache={};}G3=M6.cache;T93.D0J(0);r1=T93.S40(F9,A3);if(r1 < G6.cacheLeft || r1 > G6.cacheRight || !G3.open){S2=T0.semiLog?T0.height * (1 - (Math.log(Math.max(Z9,0)) / Math.LN10 - T0.logLow) / T0.logShadow):(T0.high - Z9) * T0.multiplier;T5=T0.semiLog?T0.height * (1 - (Math.log(Math.max(Y8,0)) / Math.LN10 - T0.logLow) / T0.logShadow):(T0.high - Y8) * T0.multiplier;if(T0.flipped){T93.H6P(7);S2=T93.S40(S2,M4);T93.H6P(7);T5=T93.q7n(T5,M4);}else {S2+=Z0;T5+=Z0;}z2[A3]=T5;q_=Math.floor(S7?T5:Math.min(S2,T5)) + x3;i4=S7?T0.bottom:Math.max(S2,T5);T93.H6P(7);w8=Math.floor(T93.S40(q_,i4));if(q_ < Z0){if(q_ + w8 < Z0){G3.open=q_;G3.close=q_;continue;}T93.D0J(7);w8-=T93.q7n(q_,Z0);q_=Z0;}if(q_ + w8 > M4){T93.D0J(15);w8-=T93.q7n(w8,q_,M4);}w8=Math.max(w8,+"2");G3.open=q_;G3.close=G3.open + w8;}if(G3.open >= M4)continue;if(G3.close <= Z0)continue;h7=Math.floor(d6) + (!E8.highlight && 0.5);g_=Math.floor(h7 - u1) + x3;U7=Math.round(h7 + u1) - x3;if(G3.open != G3.close){L5.rect(g_,G3.open,Math.max(1,U7 - g_),Math.max(1,G3.close - G3.open));}if(!E8.highlight && this.highlightedDraggable){L5.globalAlpha*=0.3;}if(R5 != "transparent"){L5.fill();}if(n0){L5.lineWidth=1;if(E8.highlight){L5.lineWidth*=2;}L5.strokeStyle=G1;L5.stroke();}}l$={colors:[],cache:z2};for(var p8 in c4){if(!E8.hollow || !f0.equals(p8,this.containerColor)){l$.colors.push(p8);}}return l$;};f0.ChartEngine.prototype.drawShadows=function(P4,M2,y8){var i8A=A2IFV;var h9,J9,B1,V3,l9,S0,x7,K0,e1,r8,U1,Z1,p_,u7,T3,n_,J7,g3,G5,H1,V4,H_,B0,Y1,T_,H$;h9=P4.chart;if(!h9){h9=P4;P4=P4.chart;}J9=h9.dataSegment;B1=this.chart.context;B1.lineWidth=1;if(y8.highlight){B1.lineWidth*=2;}if(!y8.highlight && this.highlightedDraggable){B1.globalAlpha*=0.3;}V3=y8.field;l9=y8.yAxis || P4.yAxis;S0=l9.top;x7=l9.bottom;K0=h9.dataSet.length - h9.scroll - +"1";e1=this.layout.candleWidth;i8A.D0J(16);var h6V=i8A.S40(13,14);r8=P4.left - 0.5 * e1 + this.micropixels - h6V;i8A.D0H();for(var N7=+"0";N7 <= J9.length;N7++){i8A.D0J(14);r8+=i8A.q7n(2,e1);e1=this.layout.candleWidth;i8A.H6P(14);r8+=i8A.q7n(2,e1);U1=J9[N7];if(!U1)continue;if(U1.projection)continue;if(U1.candleWidth){i8A.D0J(17);var Y_q=i8A.q7n(13,19,1,7,15);r8+=(U1.candleWidth - e1) / Y_q;e1=U1.candleWidth;}Z1=M2(this,U1,"shadow");if(!Z1)continue;if(h9.transformFunc && l9 == h9.panel.yAxis && U1.transform){U1=U1.transform;}if(U1 && V3){U1=U1[V3];}if(!U1 && U1 !== 0)continue;p_=U1.Close;u7=U1.Open === undefined?p_:U1.Open;T3=U1.High === undefined?Math.max(p_,u7):U1.High;n_=U1.Low === undefined?Math.min(p_,u7):U1.Low;if(!p_ && p_ !== 0)continue;if(!U1.cache){U1.cache={};}J7=U1.cache;i8A.H6P(0);g3=i8A.q7n(K0,N7);if(g3 < P4.cacheLeft || g3 > P4.cacheRight || !J7.top){G5=l9.semiLog?l9.height * (1 - (Math.log(Math.max(T3,0)) / Math.LN10 - l9.logLow) / l9.logShadow):(l9.high - T3) * l9.multiplier;H1=l9.semiLog?l9.height * (+"1" - (Math.log(Math.max(n_,0)) / Math.LN10 - l9.logLow) / l9.logShadow):(l9.high - n_) * l9.multiplier;if(l9.flipped){i8A.H6P(7);G5=i8A.q7n(G5,x7);i8A.D0J(7);H1=i8A.S40(H1,x7);}else {G5+=S0;H1+=S0;}i8A.H6P(7);V4=i8A.S40(G5,H1);if(G5 < S0){if(G5 + V4 < S0){J7.top=G5;J7.bottom=G5;continue;}i8A.D0J(7);V4-=i8A.q7n(G5,S0);G5=S0;}if(G5 + V4 > x7){i8A.H6P(15);V4-=i8A.S40(V4,G5,x7);}J7.top=G5;J7.bottom=J7.top + V4;}if(J7.top >= x7)continue;if(J7.bottom <= S0)continue;H_=Math.floor(r8) + (!y8.highlight && 0.5);B1.beginPath();if(p_ == u7){B0=this.offset;if(y8.isVolume){i8A.D0J(14);B0=i8A.q7n(2,e1);}i8A.H6P(7);Y1=i8A.S40(B0,H_);i8A.H6P(0);T_=i8A.S40(H_,B0);H$=l9.semiLog?l9.height * (1 - (Math.log(Math.max(p_,0)) / Math.LN10 - l9.logLow) / l9.logShadow):(l9.high - p_) * l9.multiplier;if(l9.flipped){i8A.D0J(7);H$=i8A.S40(H$,x7);}else {H$+=S0;}if(H$ <= x7 && H$ >= S0){B1.moveTo(Y1,H$);B1.lineTo(T_,H$);}}if(T3 != n_){B1.moveTo(H_,J7.top);B1.lineTo(H_,J7.bottom);}B1.strokeStyle=Z1;B1.stroke();}};f0.ChartEngine.prototype.drawBarChart=function(U4,W4,u2,G0){var Q$S=A2IFV;var I3,S3,S$,Y7,x$,O2,x4,R1,c6,N6,i_,E6,o9,l7,d_,H6,R27,K4,l0,v_,z5,J6,q1,d4,L$,V2,T9,k9,j8;I3=U4.chart;if(!I3){I3=U4;U4=U4.chart;}S3=I3.dataSegment;S$=new Array(S3.length);Y7=I3.context;x$=this.canvasStyle(W4);if(x$.width && parseInt(x$.width,10) <= 25){Y7.lineWidth=Math.max(1,f0.stripPX(x$.width));}else {Y7.lineWidth=1;}if(G0.highlight){Y7.lineWidth*=2;}if(!G0.highlight && this.highlightedDraggable){Y7.globalAlpha*=0.3;}O2=G0.field;x4=G0.yAxis || U4.yAxis;R1=x4.top;c6=x4.bottom;Q$S.D0J(18);var V6I=Q$S.q7n(13,13,0);i_=I3.dataSet.length - I3.scroll - V6I;E6={};Q$S.D0J(13);var q7x=Q$S.S40(0,25,10,5);o9=I3.tmpWidth / q7x;Q$S.H6P(19);var A4R=Q$S.S40(0,15,20,33);l7=Y7.lineWidth / A4R;d_=this.layout.candleWidth;H6=U4.left - 0.5 * d_ + this.micropixels - +"1";for(var A$=0;A$ <= S3.length;A$++){R27="h";R27+="l";R27+="c";Q$S.H6P(14);H6+=Q$S.S40(2,d_);d_=this.layout.candleWidth;Q$S.H6P(14);H6+=Q$S.S40(2,d_);K4=S3[A$];if(!K4)continue;if(K4.projection)break;if(K4.candleWidth){Q$S.H6P(20);var N0G=Q$S.S40(13,0,123,10,9);H6+=(K4.candleWidth - d_) / N0G;d_=K4.candleWidth;}l0=u2(this,K4);if(!l0)continue;Q$S.H6P(21);E6[l0]=Q$S.S40("1",0);Y7.strokeStyle=l0;Y7.beginPath();if(I3.transformFunc && x4 == I3.panel.yAxis && K4.transform){K4=K4.transform;}if(K4 && O2){K4=K4[O2];}if(!K4 && K4 !== 0)continue;v_=K4.Close;z5=K4.Open === undefined?v_:K4.Open;J6=K4.High === undefined?Math.max(v_,z5):K4.High;q1=K4.Low === undefined?Math.min(v_,z5):K4.Low;if(!v_ && v_ !== 0)continue;if(!K4.cache){K4.cache={};}d4=K4.cache;Q$S.D0J(0);L$=Q$S.q7n(i_,A$);if(L$ < U4.cacheLeft || L$ > U4.cacheRight || !d4.top){V2=this.pixelFromTransformedValue(J6,U4,x4);T9=this.pixelFromTransformedValue(q1,U4,x4);d4.open=x4.semiLog?x4.height * (1 - (Math.log(Math.max(z5,0)) / Math.LN10 - x4.logLow) / x4.logShadow):(x4.high - z5) * x4.multiplier;d4.close=x4.semiLog?x4.height * (+"1" - (Math.log(Math.max(v_,0)) / Math.LN10 - x4.logLow) / x4.logShadow):(x4.high - v_) * x4.multiplier;if(x4.flipped){d4.open=x4.bottom - d4.open;d4.close=x4.bottom - d4.close;}else {d4.open+=x4.top;d4.close+=x4.top;}S$[A$]=d4.close;Q$S.H6P(7);N6=Q$S.S40(V2,T9);if(V2 < R1){if(V2 + N6 < R1){d4.top=V2;d4.bottom=V2;continue;}Q$S.H6P(7);N6-=Q$S.q7n(V2,R1);V2=R1;}if(V2 + N6 > c6){Q$S.H6P(15);N6-=Q$S.S40(N6,V2,c6);}d4.top=V2;Q$S.D0J(0);d4.bottom=Q$S.S40(V2,N6);}Q$S.H6P(7);var M6s=Q$S.S40(18,19);k9=Math.floor(H6) + (!G0.highlight && "0.5" * M6s);if(d4.top < c6 && d4.bottom > R1 && K4.High != K4.Low){Y7.moveTo(k9,d4.top - l7);Y7.lineTo(k9,d4.bottom + l7);}if(G0.type != R27 && d4.open > R1 && d4.open < c6){Y7.moveTo(k9,d4.open);Q$S.D0J(7);Y7.lineTo(Q$S.S40(o9,k9),d4.open);}if(d4.close > R1 && d4.close < c6){Y7.moveTo(k9,d4.close);Q$S.D0J(0);Y7.lineTo(Q$S.S40(k9,o9),d4.close);}Y7.stroke();}Y7.lineWidth=1;j8={colors:[],cache:S$};for(var B3 in E6){if(!f0.equals(B3,this.containerColor)){j8.colors.push(B3);}}return j8;};f0.ChartEngine.prototype.drawWaveChart=function(d9,Y3){var b9$=A2IFV;var V1k,b9,T2,f1,P8,a6,R2,E7,O5,E0,g9,a_,W9,D9,K9,j_,J5,R8,K6,Y4,l8,I6,D$,m7;V1k="stx";V1k+="_line_ch";V1k+="art";b9=d9.chart;T2=b9.dataSegment;f1=new Array(T2.length);P8=b9.context;if(!Y3){Y3={};}a6=Y3.yAxis || d9.yAxis;this.startClip(d9.name);P8.beginPath();R2=!1;function w4(P5){return a_.pixelFromTransformedValue(P5,d9,a6);}E7=![];O5=d9.yAxis.top;E0=d9.yAxis.bottom;g9=d9.left + Math.floor(-+"0.5" * this.layout.candleWidth + this.micropixels);a_=this;for(var G9=0;G9 <= T2.length;G9++){g9+=this.layout.candleWidth;W9=T2[G9];if(!W9)continue;if(W9.projection)break;if(b9.transformFunc && a6 == b9.panel.yAxis && W9.transform){W9=W9.transform;}if(W9 && Y3.field){W9=W9[Y3.field];}if(!W9 && W9 !== 0)continue;D9=W9.Close;K9=W9.Open === undefined?D9:W9.Open;j_=W9.High === undefined?Math.max(D9,K9):W9.High;J5=W9.Low === undefined?Math.min(D9,K9):W9.Low;if(!D9 && D9 !== 0)continue;b9$.D0J(22);var f4I=b9$.q7n(1,11,23,250);b9$.H6P(23);var c3b=b9$.S40(7,24,34,11,1);R8=g9 - f4I * this.layout.candleWidth / c3b;K6=w4(K9);if(K6 < O5){K6=O5;if(E7){P8.moveTo(R8,K6);continue;}E7=!![];}else if(K6 > E0){K6=E0;if(E7){P8.moveTo(R8,K6);continue;}E7=!0;}else {E7=![];}if(!R2){R2=!![];Y4=b9.dataSet.length - b9.scroll - +"1";if(Y4 < 0){P8.moveTo(R8,K6);}else if(Y4 >= 0){l8=b9.dataSet[Y4];if(l8.transform){l8=l8.transform;}I6=l8.Close;I6=w4(I6);I6=Math.min(Math.max(I6,O5),E0);P8.moveTo(d9.left + (G9 - 1) * this.layout.candleWidth + this.micropixels,I6);P8.lineTo(R8,K6);}P8.moveTo(R8,K6);}else {P8.lineTo(R8,K6);}b9$.D0J(16);var P6B=b9$.q7n(7,11);R8+=this.layout.candleWidth / P6B;if(K9 < D9){K6=w4(J5);if(K6 < O5){K6=O5;}if(K6 > E0){K6=E0;}P8.lineTo(R8,K6);b9$.H6P(16);var r5Y=b9$.S40(10,14);R8+=this.layout.candleWidth / r5Y;K6=w4(j_);if(K6 < O5){K6=O5;}if(K6 > E0){K6=E0;}P8.lineTo(R8,K6);}else {K6=w4(j_);if(K6 < O5){K6=O5;}if(K6 > E0){K6=E0;}P8.lineTo(R8,K6);R8+=this.layout.candleWidth / +"4";K6=w4(J5);if(K6 < O5){K6=O5;}if(K6 > E0){K6=E0;}P8.lineTo(R8,K6);}b9$.D0J(24);var E$B=b9$.S40(5,9,16,10,5);R8+=this.layout.candleWidth / E$B;K6=w4(D9);f1[G9]=K6;if(K6 < O5){K6=O5;}if(K6 > E0){K6=E0;}P8.lineTo(R8,K6);}D$=this.canvasStyle("stx_line_chart");if(D$.width && parseInt(D$.width,10) <= 25){P8.lineWidth=Math.max(1,f0.stripPX(D$.width));}else {P8.lineWidth=1;}if(Y3.highlight){P8.lineWidth*=2;}this.canvasColor(V1k);if(Y3.color){P8.strokeStyle=Y3.color;}if(!Y3.highlight && this.highlightedDraggable){P8.globalAlpha*=+"0.3";}P8.stroke();P8.closePath();m7={colors:[P8.strokeStyle],cache:f1};this.endClip();P8.lineWidth=1;return m7;};f0.ChartEngine.prototype.drawHistogram=function(r9,v3){var j2E=A2IFV;var L1_,z8,L3,A5,b2,T$,a4,X9,u0,p2,S5,q8,S8,w$,a1,h_,U9,c$e,T4z,W5k,k0,Q0,a5,M1,P$,C7,h$,e0,J8,V1,A9f,i2b,Y$,r3,L2,X4,k_,D5e;L1_="c";L1_+="ha";L1_+="rt";if(!v3 || !v3.length){return;}z8=r9.panel;if(!z8){z8=L1_;}L3=this.panels[z8];function f8(w3,p4,g$,Q4,p5,h4,o4,P6,y$){var f6,s1,P3,k90,z5o,F5,t4,B4,x5,r0,V8,C8,C$,D7,M7,L1,E$o;if(!Q4){Q4=1;}P$.globalAlpha=Q4;P$.beginPath();j2E.D0J(0);f6=j2E.S40(k0,0.5);s1=Math.floor(J8.pixelFromBar(0,L3.chart) - J8.layout.candleWidth / ("2" ^ 0));P3=s1;for(var C5=0;C5 < T$.length;C5++){k90="clu";k90+="stered";z5o="o";z5o+="b";z5o+="jec";z5o+="t";F5=e0[C5] || k0;if(C5 === 0){f6=F5;}if(!T$[C5] || !T$[C5][w3]){f6=F5;P3+=J8.layout.candleWidth;continue;}t4=T$[C5];B4=t4[w3];if(typeof B4 == z5o && B4[p4]){B4=B4[p4];}j2E.D0J(25);x5=j2E.q7n(w$,B4,q8);if(isNaN(x5))continue;r0=J8.layout.candleWidth;if(t4.candleWidth){r0=t4.candleWidth;if(C5 === 0){s1=P3=Math.floor(J8.pixelFromBar(0,L3.chart) - t4.candleWidth / 2);}}V8=Math.floor(F5 - x5) + 0.5;if(V8 > F5 && !Q0){V8=F5;}if(y$ && y$.indexOf(C5) == -1 || !y$ && (h4 && t4.Close < t4.iqPrevClose || !h4 && t4.Close >= t4.iqPrevClose)){f6=V8;P3+=r0;continue;}C8=r0 / J8.layout.candleWidth;if(C7){j2E.H6P(26);C$=Math.round(j2E.S40(P3,C7,P6,C8,o4));j2E.D0J(0);D7=j2E.q7n(C$,p5?0:M1);j2E.D0J(27);var d06=j2E.S40(18,8,209,8);M7=C$ + Math.round(P6 * C8) - (p5?"0" * d06:M1);}else {j2E.D0J(26);C$=j2E.S40(P3,C7,P6,C8,o4);D7=Math.round(C$) + (p5?+"0":M1);M7=Math.round(C$ + P6 * C8) - (p5?0:M1);}if(M7 - D7 < 2){j2E.D0J(0);M7=j2E.S40(D7,1);}L1=p5?0:0.5;if(D7 % 1 == L1){D7+=0.5;}if(M7 % 1 == L1){M7+=0.5;}P$.moveTo(M7,F5);if(k0 != F5 && p5 && !C7 && e0[C5 + 1]){P$.moveTo(M7,Math.max(V8,Math.min(F5,e0[C5 + 1])));}P$.lineTo(M7,V8);P$.lineTo(D7,V8);if(p5 && o4){if(h$[C5] > V8 || C5 === 0){P$.lineTo(D7,Math.min(F5,h$[C5]));}}else if(p5 && !C7 && b2 == "clustered"){if(C5 > ("0" | 0) && h$[C5 - 1] && h$[C5 - 1] > V8){P$.lineTo(D7,Math.min(F5,h$[C5 - 1]));}}else if(p5 && !C7){if(f6 > V8 || C5 === 0){P$.lineTo(D7,Math.min(F5,f6));}}else {P$.lineTo(D7,F5);}f6=V8;P3+=r0;if(b2 != k90 || p5){h$[C5]=V8;}}if(p5){E$o="a";E$o+="uto";P$.strokeStyle=!g$ || g$ == E$o?J8.defaultColor:g$;P$.stroke();}else {P$.fillStyle=!g$ || g$ == "auto"?J8.defaultColor:g$;P$.fill();}P$.closePath();}if(!L3){return;}A5=r9.yAxis?r9.yAxis:L3.yAxis;b2=r9.type;T$=this.chart.dataSegment;a4=!({});X9=1;j2E.D0J(7);u0=j2E.S40(0,"1");for(S5=0;S5 < v3.length;S5++){a4|=v3[S5].border_color_up && !f0.isTransparent(v3[S5].border_color_up);a4|=v3[S5].border_color_down && !f0.isTransparent(v3[S5].border_color_down);X9=v3[S5].opacity_up;u0=v3[S5].opacity_down;if(!r9.highlight && this.highlightedDraggable){X9*=0.3;u0*=0.3;}}if(r9.borders === !1){a4=!1;}if(!r9.name){r9.name="Data";}q8=A5.multiplier;if(!r9.heightPercentage){r9.heightPercentage=+"0.7";}if(!r9.widthFactor){r9.widthFactor=0.8;}j2E.H6P(28);S8=j2E.q7n("0",0);w$=0;for(var t6=+"0";t6 < this.chart.maxTicks;t6++){a1=T$[t6];if(!a1)continue;h_=0;for(S5=+"0";S5 < v3.length;S5++){U9=a1[v3[S5].field];if(U9 || U9 === 0){c$e="st";c$e+="ac";c$e+="k";c$e+="ed";T4z="C";T4z+="los";T4z+="e";p2=v3[S5].subField || this.chart.defaultPlotField || T4z;if(typeof U9 == "object" && U9[p2]){U9=U9[p2];}if(b2 == c$e){h_+=U9;}else {h_=U9;}if(h_ > S8){S8=h_;}if(h_ < w$){w$=h_;}}}}j2E.a9S();if(S8 === 0 && w$ === "0" * 1){W5k=" Not ";W5k+="Ava";W5k+="ilab";W5k+="le";this.displayErrorAsWatermark(z8,this.translateIf(r9.name + W5k));return;}Q0=![];if(!r9.bindToYAxis){if(A5.flipped){k0=Math.floor(A5.top) - 0.5;a5=Math.floor(A5.bottom) - ("0.5" - 0);}else {k0=Math.floor(A5.bottom) + 0.5;a5=Math.floor(A5.top) + 0.5;}q8=Math.abs(k0 - a5) * r9.heightPercentage / (S8 - w$);}else {if(A5.baseline){w$=A5.baseline.value;Q0=!!({});}k0=Math.floor(this.pixelFromPrice(w$,L3,A5)) + (A5.flipped?-0.5:0.5);}this.startClip(z8);M1=this.layout.candleWidth <= 1 || !a4?0:0.5;P$=this.chart.context;if(A5.flipped){P$.translate(0,("2" - 0) * A5.top);P$.scale(1,-1);}C7=Math.max(0,(1 - r9.widthFactor) * this.layout.candleWidth / 2);h$=new Array(T$.length);e0=[];J8=this;V1=1;for(S5=0;S5 < v3.length;S5++){A9f="s";A9f+="tac";A9f+="k";A9f+="ed";i2b="clus";i2b+="tere";i2b+="d";Y$=v3[S5];V1=this.layout.candleWidth * r9.widthFactor;if(C7){if(this.layout.candleWidth - V1 <= 2){a4=![];}}r3=0;if(b2 == i2b){r3=S5;V1/=v3.length;}p2=Y$.subField || this.chart.defaultPlotField || "Close";if(typeof Y$.color_function == "function"){X4={};for(var Q1=0;Q1 < T$.length;Q1++){if(T$[Q1]){D5e="border_op";D5e+="acit";D5e+="y";L2=Y$.color_function(T$[Q1]);if(typeof L2 == "string"){L2={fill_color:L2,border_color:L2};}if(!L2.hasOwnProperty(D5e)){L2.border_opacity=L2.opacity;}j2E.H6P(15);var D1r=j2E.q7n(12,18714,15607);j2E.D0J(7);var T9b=j2E.q7n(42480,50976);j2E.H6P(29);var Z50=j2E.S40(2853,1,25686,17,25703);j2E.D0J(0);var J1G=j2E.q7n(2,30);j2E.H6P(30);var p1C=j2E.q7n(7,304,232,10);j2E.H6P(31);var c7t=j2E.S40(2,1,7973,17822);j2E.H6P(32);var T8c=j2E.q7n(5030,2,387);j2E.D0J(15);var m33=j2E.S40(19,1097,16);j2E.D0J(13);var p3J=j2E.S40(18661,3,9,9337);k_=L2.fill_color + ((D1r,+"5530") != (T9b,+"139.69")?Z50 === "9200" << J1G?713.18:(484.23,p1C) <= (c7t,T8c)?",":m33:p3J) + L2.border_color;if((k_ in X4)){X4[k_].positions.push(Q1);}else {L2.positions=[Q1];X4[k_]=L2;}}}for(k_ in X4){L2=X4[k_];f8(Y$.field,p2,L2.fill_color,L2.opacity,null,null,r3,V1,L2.positions);f8(Y$.field,p2,L2.border_color,L2.border_opacity,!"",null,r3,V1,L2.positions);}}else {f8(Y$.field,p2,Y$.fill_color_up,X9,null,!!1,r3,V1);f8(Y$.field,p2,Y$.fill_color_down,u0,null,null,r3,V1);if(this.layout.candleWidth >= 2 && a4){f8(Y$.field,p2,Y$.border_color_up,X9,!"",!!({}),r3,V1);f8(Y$.field,p2,Y$.border_color_down,u0,!"",null,r3,V1);}}if(b2 == A9f){e0=f0.shallowClone(h$);}}P$.globalAlpha=1;this.endClip();};f0.ChartEngine.prototype.scatter=function(s7,j4){var D_D=A2IFV;var o1G,n8,d5,M3,O4,F$,z0,I0,S9,G4,O0,E1,E2,U_,R0,M9,H4,b4,l_;o1G="s";o1G+="tx_sca";o1G+="tter_ch";o1G+="art";n8=s7.chart;d5=n8.dataSegment;M3=new Array(d5.length);O4=this.chart.context;this.canvasColor(o1G);if(!j4){j4={};}F$=j4.field || n8.defaultPlotField;z0=j4.yAxis || s7.yAxis;I0=j4.subField || n8.defaultPlotField || "Close";this.startClip(s7.name);O4.beginPath();O4.lineWidth=j4.lineWidth || 4;if(j4.highlight){O4.lineWidth*=+"2";}if(!j4.highlight && this.highlightedDraggable){O4.globalAlpha*=0.3;}if(j4.color){O4.strokeStyle=j4.color;}S9=z0.top;G4=z0.bottom;O0=this.layout.candleWidth;D_D.H6P(33);var C_m=D_D.S40(5,17,18,7);D_D.H6P(18);var O3I=D_D.S40(7,1,6);E1=s7.left - "0.5" * C_m * O0 + this.micropixels - O3I;for(var y9=0;y9 <= d5.length;y9++){D_D.H6P(14);E1+=D_D.S40(2,O0);O0=this.layout.candleWidth;D_D.H6P(14);E1+=D_D.q7n(2,O0);E2=d5[y9];if(!E2)continue;if(E2.candleWidth){D_D.D0J(34);var d84=D_D.S40(0,13,20,3,52);E1+=(E2.candleWidth - O0) / d84;O0=E2.candleWidth;}if(!E2.projection){if(n8.transformFunc && z0 == n8.panel.yAxis && E2.transform){E2=E2.transform;}U_=E2[F$];if(U_ && U_[I0] !== undefined){U_=U_[I0];}if(!(U_ instanceof Array)){U_=[U_];}if(("Scatter" in E2)){U_=E2.Scatter;}for(var Y6=0;Y6 < U_.length;Y6++){if(!U_[Y6] && U_[Y6] !== 0)continue;R0=U_[Y6];M9=0;if(U_[Y6] instanceof Array){R0=U_[Y6][0];M9=U_[Y6][2];}H4=z0.semiLog?z0.height * ("1" * 1 - (Math.log(Math.max(R0,0)) / Math.LN10 - z0.logLow) / z0.logShadow):(z0.high - R0) * z0.multiplier;if(z0.flipped){D_D.D0J(7);H4=D_D.q7n(H4,G4);}else {H4+=S9;}if(H4 < S9)continue;if(H4 > G4)continue;b4=2;if(M9){D_D.H6P(1);b4=D_D.q7n(M9,O0);}D_D.D0J(7);O4.moveTo(D_D.q7n(b4,E1),H4);D_D.D0J(0);O4.lineTo(D_D.q7n(E1,b4),H4);M3[y9]=H4;}}}O4.stroke();O4.closePath();l_={colors:[O4.strokeStyle],cache:M3};this.endClip();O4.lineWidth=1;return l_;};};q=V$=>{var G8$,h2H,I_4,v6o,S8d,u$z,m61,d2Z,p_M,w53,r_N,A9b,X_x,z85,t2z,O4v,y37,H_n,w05,b87,g0c,X2,o7;G8$="lin";G8$+="eWid";G8$+="th";h2H="c";h2H+="olor";I_4="ax";I_4+="i";I_4+="sLa";I_4+="bel";v6o="pat";v6o+="te";v6o+="r";v6o+="n";S8d="lineWid";S8d+="th";u$z="pa";u$z+="t";u$z+="te";u$z+="rn";m61="c";m61+="olor";d2Z="sol";d2Z+="i";d2Z+="d";p_M="a";p_M+="u";p_M+="t";p_M+="o";w53="a";w53+="u";w53+="t";w53+="o";r_N="a";r_N+="u";r_N+="t";r_N+="o";A9b="a";A9b+="u";A9b+="t";A9b+="o";X_x="a";X_x+="u";X_x+="t";X_x+="o";z85="soli";z85+="d";t2z="a";t2z+="u";t2z+="t";t2z+="o";O4v="a";O4v+="u";O4v+="to";y37="s";y37+="oli";y37+="d";H_n="so";H_n+="lid";w05="a";w05+="ut";w05+="o";b87="#7";b87+="DA6";b87+="F";b87+="5";g0c="u";g0c+="nde";g0c+="fined";X2=typeof _CIQ !== "undefined"?_CIQ:V$.CIQ;o7=typeof _timezoneJS !== g0c?_timezoneJS:V$.timezoneJS;X2.ChartEngine.drawingTools={};X2.ChartEngine.currentVectorParameters={vectorType:null,pattern:"solid",lineWidth:1,fillColor:b87,currentColor:w05,axisLabel:!0,fibonacci:{trend:{color:"auto",parameters:{pattern:H_n,opacity:0.25,lineWidth:"1" >> 32}},fibs:[{level:-0.786,color:"auto",parameters:{pattern:y37,opacity:+"0.25",lineWidth:1}},{level:-0.618,color:"auto",parameters:{pattern:"solid",opacity:0.25,lineWidth:1},display:!!"1"},{level:-0.5,color:"auto",parameters:{pattern:"solid",opacity:0.25,lineWidth:+"1"}},{level:-0.382,color:O4v,parameters:{pattern:"solid",opacity:0.25,lineWidth:1},display:!!({})},{level:-0.236,color:"auto",parameters:{pattern:"solid",opacity:"0.25" - 0,lineWidth:1}},{level:0,color:"auto",parameters:{pattern:"solid",lineWidth:1},display:!""},{level:0.236,color:t2z,parameters:{pattern:z85,opacity:+"0.25",lineWidth:1}},{level:0.382,color:X_x,parameters:{pattern:"solid",opacity:0.25,lineWidth:"1" | 0},display:!!"1"},{level:0.5,color:A9b,parameters:{pattern:"solid",opacity:0.25,lineWidth:1},display:!![]},{level:+"0.618",color:r_N,parameters:{pattern:"solid",opacity:0.25,lineWidth:1},display:!""},{level:0.786,color:"auto",parameters:{pattern:"solid",opacity:0.25,lineWidth:+"1"}},{level:1,color:"auto",parameters:{pattern:"solid",lineWidth:1},display:!""},{level:1.272,color:w53,parameters:{pattern:"solid",opacity:0.25,lineWidth:1}},{level:+"1.382",color:"auto",parameters:{pattern:"solid",opacity:0.25,lineWidth:1},display:!!1},{level:+"1.618",color:"auto",parameters:{pattern:"solid",opacity:"0.25" - 0,lineWidth:1},display:!!"1"},{level:2.618,color:p_M,parameters:{pattern:"solid",opacity:"0.25" * 1,lineWidth:1}},{level:4.236,color:"auto",parameters:{pattern:d2Z,opacity:"0.25" * 1,lineWidth:+"1"}}],extendLeft:!({}),printLevels:!!({}),printValues:!!"",timezone:{color:"auto",parameters:{pattern:"solid",opacity:0.25,lineWidth:+"1"}}},annotation:{font:{style:null,size:null,weight:null,family:null}}};X2.ChartEngine.registerDrawingTool=function(C4,h5){X2.ChartEngine.drawingTools[C4]=h5;};X2.ChartEngine.prototype.setDrawingContainer=function(r_){this.drawingContainer=r_;};X2.ChartEngine.prototype.exportDrawings=function(){var k2;A2IFV.D0H();k2=[];for(var I_=+"0";I_ < this.drawingObjects.length;I_++){k2.push(this.drawingObjects[I_].serialize());}return k2;};X2.ChartEngine.prototype.abortDrawings=function(F8){var L4;if(F8 !== !"1"){F8=!![];}for(var A0=this.drawingObjects.length - 1;A0 >= 0;A0--){L4=this.drawingObjects[A0];L4.abort(!0);if(F8 || !L4.permanent){this.drawingObjects.splice(A0,1);}}};X2.ChartEngine.prototype.importDrawings=function(B$){var r6,s9,J$;if(!X2.Drawing){return;}for(var N8=0;N8 < B$.length;N8++){r6=B$[N8];if(r6.name == "fibonacci"){r6.name="retracement";}s9=X2.ChartEngine.drawingTools[r6.name];if(!s9){if(X2.Drawing[r6.name]){s9=X2.Drawing[r6.name];X2.ChartEngine.registerDrawingTool(r6.name,s9);}}if(s9){J$=new s9();J$.reconstruct(this,r6);this.drawingObjects.push(J$);}}};X2.ChartEngine.prototype.clearDrawings=function(m4,o6){A2IFV.a9S();var H0,O1;if(o6 !== !({})){o6=!"";}H0=this.exportDrawings();this.abortDrawings(o6);if(m4){this.undoStamps=[];}else {this.undoStamp(H0,this.exportDrawings());}this.changeOccurred("vector");this.cancelTouchSingleClick=!![];X2.clearCanvas(this.chart.tempCanvas,this);this.draw();O1=this.controls.mSticky;if(O1){O1.style.display="none";O1.children[0].innerHTML="";}};X2.ChartEngine.prototype.createDrawing=function(e9,x_){var n5,E$;if(!X2.Drawing){return;}n5=new X2.Drawing[e9]();A2IFV.D0H();n5.reconstruct(this,x_);E$=new X2.Drawing[e9]();E$.stx=this;E$.copyConfig();for(var Q7 in E$){n5[Q7]=n5[Q7] || E$[Q7];}this.drawingObjects.push(n5);this.draw();return n5;};X2.ChartEngine.prototype.removeDrawing=function(e6){for(var K$=0;K$ < this.drawingObjects.length;K$++){if(this.drawingObjects[K$] == e6){this.drawingObjects.splice(K$,1);this.changeOccurred("vector");this.draw();return;}};};X2.ChartEngine.prototype.undo=function(){var p7f,J_M,q16,Y$$,M8Q;p7f="un";p7f+="do";J_M="u";J_M+="nd";J_M+="o";if(this.runPrepend(J_M,arguments)){return;}if(this.activeDrawing){q16="stx";q16+="_crosshair";Y$$="st";Y$$+="x_cr";Y$$+="ossha";Y$$+="ir_drawing";M8Q="stx";M8Q+="_cr";M8Q+="osshair";this.activeDrawing.abort();this.activeDrawing.hidden=!({});this.drawingSnapshot=null;this.activateDrawing(null);X2.clearCanvas(this.chart.tempCanvas,this);this.draw();this.controls.crossX.classList.replace("stx_crosshair_drawing",M8Q);this.controls.crossY.classList.replace(Y$$,q16);X2.ChartEngine.drawingLine=!({});}this.runAppend(p7f,arguments);};X2.ChartEngine.prototype.undoStamp=function(z_,z7){var E1A;E1A="u";E1A+="ndoStamp";this.undoStamps.push(z_);this.dispatch(E1A,{before:z_,after:z7,stx:this});};X2.ChartEngine.prototype.undoLast=function(){if(this.activeDrawing){this.undo();}else {if(this.undoStamps.length){this.drawingObjects=[];this.importDrawings(this.undoStamps.pop());this.changeOccurred("vector");this.draw();}}};X2.ChartEngine.prototype.addDrawing=function(X1){var g7;g7=this.exportDrawings();this.drawingObjects.push(X1);A2IFV.D0H();this.undoStamp(g7,this.exportDrawings());};X2.ChartEngine.prototype.repositionDrawing=function(l1,R_){var R4,O$,s4;R4=this.panels[l1.panelName];A2IFV.D0H();O$=this.adjustIfNecessary(R4,this.crosshairTick,this.valueFromPixel(this.backOutY(X2.ChartEngine.crosshairY),R4));s4=this.chart.tempCanvas;X2.clearCanvas(s4,this);if(R_){this.drawingSnapshot=this.exportDrawings();l1.render(s4.context);}else {l1.reposition(s4.context,l1.repositioner,this.crosshairTick,O$);if(this.drawingSnapshot){this.undoStamp(X2.shallowClone(this.drawingSnapshot),this.exportDrawings());}this.drawingSnapshot=null;}if(l1.measure){l1.measure();}};X2.ChartEngine.prototype.activateRepositioning=function(i2){var C8s,O3;A2IFV.D0H();C8s="n";C8s+="o";C8s+="ne";O3=this.repositioningDrawing=i2;if(i2){this.draw();this.repositionDrawing(i2,!!1);}this.chart.tempCanvas.style.display=i2?"block":C8s;};X2.ChartEngine.prototype.activateDrawing=function(I$,H7){var z3k,W3;z3k="b";z3k+="lo";function a3(x8){var j6;if(!x8.layout.studies){return;}j6=x8.layout.studies[H7.name];if(j6 && !j6.overlay){delete x8.overlays[j6.name];}}z3k+="ck";if(!H7){H7=this.currentPanel;}if(!I$){this.activeDrawing=null;this.chart.tempCanvas.style.display="none";a3(this);return !!0;}W3=X2.ChartEngine.drawingTools[I$];if(!W3){if(X2.Drawing[I$]){W3=X2.Drawing[I$];X2.ChartEngine.registerDrawingTool(I$,W3);}}if(W3){this.activeDrawing=new W3();this.activeDrawing.construct(this,H7);if(!this.charts[H7.name]){if(this.activeDrawing.chartsOnly){this.activeDrawing=null;a3(this);return !!"";}}}this.chart.tempCanvas.style.display=z3k;if(this.controls.drawOk){this.controls.drawOk.style.display="none";}a3(this);return !0;};X2.ChartEngine.prototype.drawingClick=function(q3,H2,P9){var p6,b7,r5,y5t,e$T,D31;if(!X2.Drawing){return;}A2IFV.a9S();if(!q3){return;}if(this.openDialog !== ""){return;}if(!this.activeDrawing){if(!this.activateDrawing(this.currentVectorParameters.vectorType,q3)){return;}}if(this.activeDrawing){if(this.userPointerDown && !this.activeDrawing.dragToDraw){if(!X2.ChartEngine.drawingLine){this.activateDrawing(null);}return;}p6=this.tickFromPixel(H2,q3.chart);b7=this.panels[this.activeDrawing.panelName];r5=this.adjustIfNecessary(b7,p6,this.valueFromPixel(P9,b7));if(this.magnetizedPrice){r5=this.adjustIfNecessary(b7,p6,this.magnetizedPrice);}if(this.activeDrawing.click(this.chart.tempCanvas.context,p6,r5)){if(this.activeDrawing){X2.ChartEngine.drawingLine=!({});X2.clearCanvas(this.chart.tempCanvas,this);this.addDrawing(this.activeDrawing);this.activateDrawing(null);this.adjustDrawings();this.draw();this.changeOccurred("vector");this.controls.crossX.classList.replace("stx_crosshair_drawing","stx_crosshair");this.controls.crossY.classList.replace("stx_crosshair_drawing","stx_crosshair");}}else {y5t="stx";y5t+="_cross";y5t+="h";y5t+="air_drawing";e$T="stx";e$T+="_cro";e$T+="s";e$T+="shair";D31="dra";D31+="wing";this.changeOccurred(D31);X2.ChartEngine.drawingLine=!![];this.controls.crossX.classList.replace("stx_crosshair","stx_crosshair_drawing");this.controls.crossY.classList.replace(e$T,y5t);}return !!({});}return ![];};X2.ChartEngine.prototype.rightClickDrawing=function(j5,o_){var e8,E_;if(this.runPrepend("rightClickDrawing",arguments)){return;}if(j5.permanent){return;}if(this.callbackListeners.drawingEdit.length){this.dispatch("drawingEdit",{stx:this,drawing:j5,forceEdit:o_});}else {e8=j5.abort();if(!e8){E_=this.exportDrawings();this.removeDrawing(j5);this.undoStamp(E_,this.exportDrawings());}this.changeOccurred("vector");}this.runAppend("rightClickDrawing",arguments);};X2.ChartEngine.prototype.magnetize=function(){var g0N=A2IFV;var Z_p,O5C,v8M,v_O,c0,c7,H5,N3,H3,h0,a7,N_,u$,I6t,U8,v2,R7,W1,X$,e5,V9,F3,j2,c2;Z_p="magn";Z_p+="etize";O5C="H";O5C+="igh";v8M="fr";v8M+="e";v8M+="e";v8M+="form";v_O="proj";v_O+="ection";this.magnetizedPrice=null;if(!this.preferences.magnet){return;}if(this.runPrepend("magnetize",arguments)){return;}if(this.repositioningDrawing){return;}c0=this.currentVectorParameters.vectorType;if(!c0 || c0 == v_O || c0 == v8M){return;}if((c0 == "annotation" || c0 == "callout") && X2.ChartEngine.drawingLine){return;}c7=this.currentPanel;H5=c7.chart;N3=this.crosshairTick;if(N3 > H5.dataSet.length){return;}H3=H5.dataSet[N3];if(!H3){return;}h0=H5.transformFunc && c7.yAxis === H5.yAxis;if(h0 && H3.transform){H3=H3.transform;}N_=this.getRenderedItems();u$=["Open",O5C,"Low","Close"];if(this.magneticHold && this.activeDrawing && this.activeDrawing.penDown){I6t="H";I6t+="igh";if(u$.indexOf(this.magneticHold) != -1 && N_.indexOf(I6t) != -1){N_=u$;}else {N_=[this.magneticHold];}}else {this.magneticHold=null;}U8=1000000000;v2=parseFloat(this.preferences.magnet);for(var i5=+"0";i5 < N_.length;i5++){R7=H3[N_[i5]];W1=this.getYAxisByField(c7,N_[i5]);X$=X2.existsInObjectChain(H3,N_[i5]);if(X$){R7=X$.obj[X$.member];}if(R7 || R7 === 0){e5=this.pixelFromTransformedValue(R7,c7,W1);if(Math.abs(this.cy - e5) < U8){U8=Math.abs(this.cy - e5);if(v2 && v2 <= U8)continue;this.magnetizedPrice=h0?this.valueFromPixel(e5,c7):R7;a7=e5;this.magneticHold=N_[i5];}}}V9=this.pixelFromTick(N3,H5);F3=a7;X2.clearCanvas(H5.tempCanvas,this);j2=H5.tempCanvas.context;j2.beginPath();j2.lineWidth=1;g0N.D0J(22);var a1L=g0N.S40(4,8,108,204);g0N.D0J(35);var l4C=g0N.q7n(3,10,18,18,135);c2=Math.max(this.layout.candleWidth,a1L) / l4C;j2.arc(V9,F3,Math.min(c2,"8" | 8),0,2 * Math.PI,!"1");j2.fillStyle="#398dff";g0N.D0H();j2.strokeStyle="#398dff";j2.fill();j2.stroke();j2.closePath();H5.tempCanvas.style.display="block";if(this.anyHighlighted){this.container.classList.remove("stx-draggable");}if(this.activeDrawing){this.activeDrawing.move(j2,this.crosshairTick,this.magnetizedPrice);}this.runAppend(Z_p,arguments);};X2.ChartEngine.prototype.changeVectorType=function(c_){this.currentVectorParameters.vectorType=c_;if(X2.Drawing){X2.Drawing.initializeSettings(this,c_);}if(X2.ChartEngine.drawingLine){this.undo();}A2IFV.D0H();if(this.insideChart){this.doDisplayCrosshairs();}};X2.ChartEngine.prototype.changeVectorParameter=function(a$,v8){var b$Z,a_d,y2Y,B5D,E4,J6D;b$Z="f";b$Z+="o";b$Z+="nt";a_d="p";a_d+="x";y2Y="tr";y2Y+="ue";B5D="axi";B5D+="sL";B5D+="abel";if(a$ == B5D){v8=v8.toString() === y2Y || Number(v8);}else if(a$ == "lineWidth"){v8=Number(v8);}else if(a$ == "fontSize"){A2IFV.D0J(36);var I1Q=A2IFV.q7n(19,0,9);v8=parseInt(v8,I1Q) + a_d;}E4=this.currentVectorParameters;if(typeof E4[a$] !== "undefined"){E4[a$]=v8;return !![];}else if(a$.substr(0,4) == b$Z){J6D="fam";J6D+="i";J6D+="ly";a$=a$.substr(4).toLowerCase();if(a$ == J6D && v8.toLowerCase() == "default"){v8=null;}E4=E4.annotation.font;if(typeof E4[a$] !== "undefined"){E4[a$]=v8;return !!({});}}return ![];};X2.ChartEngine.prototype.drawVectors=function(){var g65,K8O,O6,s3,s8,S_,V7;g65="draw";g65+="Vecto";g65+="rs";A2IFV.D0H();K8O="d";K8O+="raw";K8O+="V";K8O+="ectors";if(this.vectorsShowing){return;}if(this.runPrepend(K8O,arguments)){return;}this.vectorsShowing=!"";if(!this.chart.hideDrawings && !this.highlightedDraggable){O6={};for(s8=+"0";s8 < this.drawingObjects.length;s8++){S_=this.drawingObjects[s8];if(S_.hidden)continue;if(this.repositioningDrawing === S_)continue;s3=S_.panelName;if(!this.panels[S_.panelName] || this.panels[S_.panelName].hidden)continue;if(!O6[s3]){O6[s3]=[];}O6[s3].push(S_);}for(s3 in O6){this.startClip(s3);V7=O6[s3];for(s8=0;s8 < V7.length;s8++){V7[s8].render(this.chart.context);}this.endClip();}}this.runAppend(g65,arguments);};X2.ChartEngine.prototype.adjustDrawings=function(){var q2;for(var a9=0;a9 < this.drawingObjects.length;a9++){q2=this.drawingObjects[a9];if(this.panels[q2.panelName]){q2.adjust();}}};X2.Drawing=X2.Drawing || (function(){this.chartsOnly=!({});this.penDown=!({});;});X2.Drawing.getDrawingParameters=function(c3,o1){var w_,j9,v5,B5;try{w_=new X2.Drawing[o1]();}catch(z6){}if(!w_){return null;}w_.stx=c3;w_.copyConfig(!!1);j9={};v5=w_.configs;for(var F0=0;F0 < v5.length;F0++){j9[v5[F0]]=w_[v5[F0]];}B5=c3.canvasStyle("stx_annotation");A2IFV.D0H();if(B5 && j9.font){j9.font.size=B5.fontSize;j9.font.family=B5.fontFamily;j9.font.style=B5.fontStyle;j9.font.weight=B5.fontWeight;}return j9;};X2.Drawing.saveConfig=function(x9,W7){var E9a,X7,D6;E9a="prefer";E9a+="ences";if(!W7){return;}X7=x9.preferences;if(!X7.drawings){X7.drawings={};}X7.drawings[W7]={};D6=new X2.Drawing[W7]();D6.stx=x9;X2.Drawing.copyConfig(D6);D6.configs.forEach(function(a2){X7.drawings[W7][a2]=D6[a2];});x9.changeOccurred(E9a);};X2.Drawing.restoreDefaultConfig=function(F6,O7,P0){if(P0){F6.preferences.drawings=null;}else {F6.preferences.drawings[O7]=null;}A2IFV.a9S();F6.changeOccurred("preferences");F6.currentVectorParameters=X2.clone(X2.ChartEngine.currentVectorParameters);F6.currentVectorParameters.vectorType=O7;};X2.Drawing.initializeSettings=function(b5,h6){var i6,k$;i6=X2.Drawing[h6];if(i6){k$=new i6();if(k$.initializeSettings){k$.initializeSettings(b5);}}};X2.Drawing.updateSource=function(F2,u3,y5,Y2){var P1x,p3,X8;P1x="vect";P1x+="o";P1x+="r";if(!u3){return;}p3=!({});for(var T4 in F2.drawingObjects){X8=F2.drawingObjects[T4];if(!X8.field)continue;if(y5){if(X8.field == u3){X8.field=y5;p3=!0;}else if(X8.field.indexOf(u3) > -+"1" && X8.field.indexOf(u3 + "-") == -("1" * 1)){X8.field=X8.field.replace(u3,y5);p3=!"";}}else {if(X8.field.split("-->")[0] == u3 || X8.panelName == u3){X8.panelName=Y2;p3=!!({});}}}A2IFV.D0H();if(p3){F2.changeOccurred(P1x);}};X2.Drawing.prototype.copyConfig=function(u_){X2.Drawing.copyConfig(this,u_);};X2.Drawing.copyConfig=function(H8,D3){var u6,w7,h3,I2,h94,C_,v2y;u6=H8.stx.currentVectorParameters;w7=H8.configs;for(h3="0" >> 64;h3 < w7.length;h3++){h94="par";h94+="a";h94+="meters";I2=w7[h3];if(I2 == "color"){H8.color=u6.currentColor;}else if(I2 == h94){H8.parameters=X2.clone(u6.fibonacci);}else if(I2 == "font"){H8.font=X2.clone(u6.annotation.font);}else {H8[I2]=u6[I2];}}if(!D3){return;}C_=H8.stx.preferences;A2IFV.D0H();if(C_ && C_.drawings){X2.extend(H8,C_.drawings[u6.vectorType]);for(h3=+"0";h3 < w7.length;h3++){v2y="f";v2y+="o";v2y+="n";v2y+="t";I2=w7[h3];if(I2 == "color"){u6.currentColor=H8.color;}else if(I2 == "parameters"){u6.fibonacci=X2.clone(H8.parameters);}else if(I2 == v2y){u6.annotation.font=X2.clone(H8.font);}else {u6[I2]=H8[I2];}}}};X2.Drawing.prototype.dragToDraw=![];X2.Drawing.prototype.permanent=!!0;X2.Drawing.prototype.chartsOnly=!!0;X2.Drawing.prototype.abort=function(A2){};X2.Drawing.prototype.measure=function(){};X2.Drawing.prototype.construct=function(x6,w5){this.stx=x6;this.panelName=w5.name;};X2.Drawing.prototype.render=function(U3){console.warn("must implement render function!");};X2.Drawing.prototype.click=function(z4,C2,u4){console.warn("must implement click function!");};X2.Drawing.prototype.move=function(C9,j$,Y_){console.warn("must implement move function!");};X2.Drawing.prototype.reposition=function(V_,q5,G2,D8){};X2.Drawing.prototype.intersected=function(J0,k3,Y0){console.warn("must implement intersected function!");};X2.Drawing.prototype.reconstruct=function(W$,J3){console.warn("must implement reconstruct function!");};X2.Drawing.prototype.serialize=function(){A2IFV.a9S();console.warn("must implement serialize function!");};X2.Drawing.prototype.adjust=function(){A2IFV.D0H();console.warn("must implement adjust function!");};X2.Drawing.prototype.highlight=function(Q6){A2IFV.a9S();if(Q6 && !this.highlighted){this.highlighted=Q6;}else if(!Q6 && this.highlighted){this.highlighted=Q6;}return this.highlighted;};X2.Drawing.prototype.littleCircleRadius=function(){var y3;y3=6;return y3;};X2.Drawing.prototype.littleCircle=function(N1,B9,D5,q6){var b1,Z2;if(this.permanent){return;}b1=this.stx.defaultColor;Z2=X2.chooseForegroundColor(b1);N1.beginPath();A2IFV.D0H();N1.lineWidth=+"1";N1.arc(B9,D5,this.littleCircleRadius(),0,2 * Math.PI,![]);if(q6){N1.fillStyle=b1;}else {N1.fillStyle=Z2;}N1.strokeStyle=b1;N1.setLineDash([]);N1.fill();N1.stroke();N1.closePath();};X2.Drawing.prototype.rotator=function(b0,D2,Q$,d8){var M9O=A2IFV;var I7,n6,M5;if(this.permanent){return;}I7=this.littleCircleRadius();n6=this.stx.defaultColor;b0.beginPath();M9O.H6P(10);b0.lineWidth=M9O.q7n("2",0);if(!d8){b0.globalAlpha=0.5;}M9O.H6P(0);M5=M9O.S40(4,I7);b0.arc(D2,Q$,M5,0,3 * Math.PI / 2,!!"");M9O.D0J(37);b0.moveTo(M9O.S40(M5,D2,2),M9O.S40(Q$,2,M9O.H6P(0)));M9O.D0J(0);b0.lineTo(M9O.S40(D2,M5),Q$);M9O.H6P(36);b0.lineTo(M9O.q7n(M5,D2,2),M9O.S40(Q$,2,M9O.D0J(0)));M9O.H6P(7);b0.moveTo(M9O.q7n(2,D2),M9O.S40(2,Q$,M5,M9O.H6P(15)));M9O.H6P(7);b0.lineTo(D2,M9O.q7n(M5,Q$));M9O.D0J(38);b0.lineTo(M9O.q7n("2",32,D2),M9O.q7n(Q$,2,M5,M9O.D0J(39)));b0.strokeStyle=n6;b0.stroke();b0.closePath();M9O.D0J(40);b0.globalAlpha=M9O.S40(0,"1");};X2.Drawing.prototype.mover=function(f7,b6,j3,f3){var a$_=A2IFV;var n$,q$,M0,m9;if(this.permanent){return;}n$=this.littleCircleRadius();q$=this.stx.defaultColor;a$_.H6P(40);M0=a$_.q7n(64,"5");a$_.H6P(0);m9=a$_.q7n(n$,1);f7.save();a$_.D0J(40);f7.lineWidth=a$_.S40(32,"2");f7.strokeStyle=q$;f7.translate(b6,j3);if(!f3){f7.globalAlpha=0.5;}for(var m$=0;m$ < 4;m$++){f7.rotate(Math.PI / 2);f7.beginPath();f7.moveTo(0,m9);a$_.H6P(0);f7.lineTo(0,a$_.S40(m9,M0));a$_.D0J(15);f7.moveTo(-2,a$_.q7n(M0,m9,2));a$_.H6P(0);f7.lineTo(0,a$_.S40(m9,M0));a$_.H6P(15);f7.lineTo(2,a$_.S40(M0,m9,2));f7.closePath();f7.stroke();}a$_.a9S();f7.globalAlpha=1;f7.restore();};X2.Drawing.prototype.resizer=function(Q3,e$,t$,X3){var K5j=A2IFV;var L7,Z6,w9,z3;if(this.permanent){return;}L7=this.littleCircleRadius();Z6=this.stx.defaultColor;K5j.a9S();K5j.H6P(22);var Q4M=K5j.q7n(10,16,100,155);K5j.H6P(41);var u51=K5j.q7n(6,15,92);w9=Q4M * Math.sqrt(u51);K5j.H6P(0);z3=K5j.q7n(L7,1);Q3.save();Q3.lineWidth=2;Q3.strokeStyle=Z6;Q3.translate(e$,t$);Q3.rotate(-(e$ * t$) / Math.abs(e$ * t$) * Math.PI / ("4" | 4));if(!X3){Q3.globalAlpha=+"0.5";}for(var m8=0;m8 < 2;m8++){Q3.rotate(Math.PI);Q3.beginPath();Q3.moveTo(0,z3);K5j.H6P(0);Q3.lineTo(0,K5j.q7n(z3,w9));K5j.D0J(15);Q3.moveTo(-2,K5j.S40(w9,z3,2));K5j.D0J(0);Q3.lineTo(0,K5j.q7n(z3,w9));K5j.H6P(15);Q3.lineTo(2,K5j.q7n(w9,z3,2));Q3.closePath();Q3.stroke();}Q3.globalAlpha=1;Q3.restore();};X2.Drawing.prototype.pointIntersection=function(j1,e2,D0,U5){var P_;P_=this.stx.panels[this.panelName];if(!P_){return !"1";}if(U5){if(j1 >= D0.cx0 && j1 <= D0.cx1 && e2 >= D0.cy0 && e2 <= D0.cy1){return !![];}}else {if(j1 >= D0.x0 && j1 <= D0.x1 && e2 >= Math.min(D0.y0,D0.y1) && e2 <= Math.max(D0.y0,D0.y1)){return !!1;}}return !"1";};X2.Drawing.prototype.setPoint=function(w0,j7,o2,s6){var c7T=A2IFV;var v9,N5,R6,Q1a,J1,Z3;v9=null;N5=null;if(typeof j7 == "number"){v9=j7;}else if(j7.length >= +"8"){N5=j7;}else {v9=Number(j7);}if(o2 || o2 === 0){c7T.H6P(0);this[c7T.q7n((3460,9553) === (6130,"704" * 1)?9.55e+3:"v",w0)]=o2;}if(v9 !== null){R6=this.stx.dateFromTick(v9,s6,!!({}));c7T.D0J(0);this[c7T.q7n("tzo",w0)]=R6.getTimezoneOffset();c7T.D0J(0);this[c7T.S40(+"8680" < +"2070"?8.76e+3:(667.13,4870) != 302.02?"d":217.58,w0)]=X2.yyyymmddhhmmssmmm(R6);c7T.D0J(0);this[c7T.S40((6989,7610) == ("2424" ^ 0)?(0xb5f,0x142b):"p",w0)]=[v9,o2];}else if(N5 !== null){Q1a="t";Q1a+="z";Q1a+="o";R6=X2.strToDateTime(N5);if(!this[Q1a + w0] && this["tzo" + w0] !== ("0" ^ 0)){c7T.D0J(0);this[c7T.q7n("tzo",w0)]=R6.getTimezoneOffset();}c7T.D0J(0);this[c7T.S40((212.74,440.25) <= (1900,119)?710.4 == 3120?"b":8789 > 1260?(0x1309,"F"):"S":"d",w0)]=N5;J1=this["tzo" + w0] - R6.getTimezoneOffset();R6.setMinutes(R6.getMinutes() + J1);Z3=!"1";if(this.name != "freeform" && !X2.ChartEngine.isDailyInterval(this.stx.layout.interval) && !R6.getHours() && !R6.getMinutes() && !R6.getSeconds() && !R6.getMilliseconds()){Z3=!!({});}c7T.H6P(0);this[c7T.q7n(+"2808" != 8345?704.33 === 1740?"b":2839 != 3940?"p":!!0:(!!"","g"),w0)]=[this.stx.tickFromDate(X2.yyyymmddhhmmssmmm(R6),s6,null,Z3),o2];}};X2.Drawing.prototype.getLineColor=function(X_){var c9,f5,L6j,r7,T8,f$,k1,Q8,S5k,p9,B7;if(!X_){X_=this.color;}c9=this.stx;A2IFV.D0H();f5=X_;if(this.highlighted){L6j="st";L6j+="x_highli";L6j+="ght_vector";f5=c9.getCanvasColor(L6j);}else if(X2.isTransparent(f5)){f5=c9.defaultColor;}else if(f5 == "auto"){f5=c9.defaultColor;if(this.field){for(r7 in c9.layout.studies){T8=c9.layout.studies[r7];f$=T8.outputs[T8.outputMap[this.field]];if(f$){f5=f$.color || f$;break;}}for(r7 in c9.chart.seriesRenderers){Q8=c9.chart.seriesRenderers[r7];for(var y_=0;y_ < Q8.seriesParams.length;y_++){S5k="-";S5k+="-";S5k+=">";p9=Q8.seriesParams[y_];B7=p9.field;if(!B7 && !Q8.highLowBars){B7=this.defaultPlotField || "Close";}if(p9.symbol && p9.subField){B7+="-->" + p9.subField;}if(this.field == B7){f5=p9.color;break;}if(p9.field && p9.field == this.field.split(S5k)[0]){k1=p9.color;}}}if(k1){f5=k1;}}}if(f5 == "auto"){f5=c9.defaultColor;}return f5;};X2.Drawing.BaseTwoPoint=function(){this.p0=null;this.p1=null;this.color="";};X2.inheritsFrom(X2.Drawing.BaseTwoPoint,X2.Drawing);X2.Drawing.BaseTwoPoint.prototype.configs=[];X2.Drawing.BaseTwoPoint.prototype.lineIntersection=function(P7,U2,E9,l4,h8,m_,Q2){var q7,g1,S1;if(!h8){h8=this.p0;}if(!m_){m_=this.p1;}q7=this.stx;if(!(h8 && m_)){return ![];}g1=X2.convertBoxToPixels(q7,this.panelName,E9);if(g1.x0 === undefined){return !1;}S1={x0:h8[0],x1:m_["0" - 0],y0:h8[1],y1:m_[1]};if(!Q2){S1=X2.convertBoxToPixels(q7,this.panelName,S1);}return X2.boxIntersects(g1.x0,g1.y0,g1.x1,g1.y1,S1.x0,S1.y0,S1.x1,S1.y1,l4);};X2.Drawing.BaseTwoPoint.prototype.boxIntersection=function(e7,K8,e3){if(!this.p0 || !this.p1){return !"1";}A2IFV.D0H();if(e3.x0 > Math.max(this.p0[0],this.p1[0]) || e3.x1 < Math.min(this.p0[0],this.p1[0])){return !({});}if(e3.y1 > Math.max(this.p0[+"1"],this.p1[+"1"]) || e3.y0 < Math.min(this.p0[1],this.p1[1])){return ![];}return !!1;};X2.Drawing.BaseTwoPoint.prototype.accidentalClick=function(Z$,v7){var p29=A2IFV;var C0,t5,K3,A_,I9,G7,Q9,X6;C0=this.stx.panels[this.panelName];t5=this.stx.pixelFromTick(this.p0[0],C0.chart);K3=this.stx.pixelFromTick(Z$,C0.chart);A_=this.stx.pixelFromValueAdjusted(C0,this.p0[0],this.p0[1]);I9=this.stx.pixelFromValueAdjusted(C0,Z$,v7);p29.H6P(7);G7=Math.abs(p29.q7n(t5,K3));p29.H6P(7);Q9=Math.abs(p29.q7n(A_,I9));p29.D0J(42);X6=Math.sqrt(p29.S40(G7,Q9,G7,Q9));if(X6 < "10" >> 0){this.penDown=![];if(this.dragToDraw){this.stx.undo();}return !![];}};X2.Drawing.BaseTwoPoint.prototype.click=function(N0,Z_,K5){A2IFV.D0H();var a8;this.copyConfig();a8=this.stx.panels[this.panelName];if(!this.penDown){this.setPoint(0,Z_,K5,a8.chart);this.penDown=!![];return ![];}if(this.accidentalClick(Z_,K5)){return this.dragToDraw;}this.setPoint(1,Z_,K5,a8.chart);this.penDown=!({});return !![];;};X2.Drawing.BaseTwoPoint.prototype.adjust=function(){var H9;H9=this.stx.panels[this.panelName];if(!H9){return;}this.setPoint(+"0",this.d0,this.v0,H9.chart);this.setPoint(1,this.d1,this.v1,H9.chart);};X2.Drawing.BaseTwoPoint.prototype.move=function(T6,F4,W2){if(!this.penDown){return;}this.copyConfig();A2IFV.a9S();this.p1=[F4,W2];this.render(T6);};X2.Drawing.BaseTwoPoint.prototype.measure=function(){var F_,C6,w6;A2IFV.D0H();if(this.p0 && this.p1){this.stx.setMeasure(this.p0[1],this.p1[1],this.p0[0],this.p1[0],!!"1",this.name);F_=this.stx.controls.mSticky;C6=F_ && F_.querySelector(".mStickyInterior");if(C6){w6=[];w6.push(X2.capitalize(this.name));if(this.getYValue){w6.push(this.field || this.stx.defaultPlotField || "Close");}w6.push(C6.innerHTML);C6.innerHTML=w6.join("
");}}};X2.Drawing.BaseTwoPoint.prototype.reposition=function(N4,I8,s5,Q_){var d2j,Q5,V5,W0;d2j="m";d2j+="ove";if(!I8){return;}Q5=this.stx.panels[this.panelName];A2IFV.a9S();V5=I8.tick - s5;W0=I8.value - Q_;if(I8.action == d2j){this.setPoint(0,I8.p0["0" >> 0] - V5,I8.p0[1] - W0,Q5.chart);this.setPoint(1,I8.p1[0] - V5,I8.p1[1] - W0,Q5.chart);this.render(N4);}else if(I8.action == "drag"){this[I8.point]=[s5,Q_];this.setPoint(0,this.p0[0],this.p0["1" - 0],Q5.chart);this.setPoint(1,this.p1[0],this.p1[1],Q5.chart);this.render(N4);}};X2.Drawing.BaseTwoPoint.prototype.drawDropZone=function(o3,z1,u9,Z4,Y5){var b38=A2IFV;var T9x,E3,p$,X0,k8,I4;T9x="#008";T9x+="00";T9x+="0";E3=this.stx.panels[this.panelName];if(!E3){return;}p$=E3.left;X0=E3.width;if(Z4 || Z4 === 0){p$=this.stx.pixelFromTick(Z4,E3.chart);}if(Y5 || Y5 === +"0"){X0=this.stx.pixelFromTick(Y5,E3.chart);}k8=this.stx.pixelFromPrice(z1,E3);I4=this.stx.pixelFromPrice(u9,E3);o3.fillStyle=T9x;b38.D0J(1);o3.globalAlpha=b38.q7n(1,"0.2");b38.D0J(7);o3.fillRect(p$,k8,b38.q7n(p$,X0),b38.S40(k8,I4));b38.D0H();o3.globalAlpha=1;};X2.Drawing.annotation=function(){var O91=A2IFV;O91.a9S();this.name="annotation";this.arr=[];this.w=0;O91.H6P(1);this.h=O91.S40(1,"0");this.padding=4;this.text="";this.ta=null;O91.H6P(7);this.fontSize=O91.q7n(0,"0");this.font={};};X2.inheritsFrom(X2.Drawing.annotation,X2.Drawing.BaseTwoPoint);X2.Drawing.annotation.prototype.getFontString=function(){var K2,J4;this.fontDef={style:null,weight:null,size:"12px",family:null};K2=this.stx.canvasStyle("stx_annotation");if(K2){if(K2.fontStyle){this.fontDef.style=K2.fontStyle;}if(K2.fontWeight){this.fontDef.weight=K2.fontWeight;}if(K2.fontSize){this.fontDef.size=K2.fontSize;}if(K2.fontFamily){this.fontDef.family=K2.fontFamily;}}if(this.font.style){this.fontDef.style=this.font.style;}A2IFV.a9S();if(this.font.weight){this.fontDef.weight=this.font.weight;}if(this.font.size){this.fontDef.size=this.font.size;}if(this.font.family){this.fontDef.family=this.font.family;}this.fontString="";J4=!"";for(var i7 in this.fontDef){if(this.fontDef[i7]){if(!J4){this.fontString+=594 == "714.62" * 1?(0x14b4,!""):(176.33,"2360" | 48) > (2760,+"871")?" ":("1412" >> 0,+"284.05") === 797.11?(!"1",!({})):(!!"",9.63e+3);}else {J4=!({});}this.fontString+=this.fontDef[i7];}}};X2.Drawing.annotation.prototype.configs=["color","font"];X2.Drawing.annotation.prototype.measure=function(){};X2.Drawing.annotation.prototype.render=function(D_){var j1D=A2IFV;var l24,h$_,p0Q,G$,R9,M$_,U6,O3W,y2N,K8f,Z5i,R9I,N9;if(this.ta){return;}l24=this.stx.panels[this.panelName];if(!l24){return;}h$_=this.stx.pixelFromTick(this.p0[0],l24.chart);p0Q=this.stx.pixelFromValueAdjusted(l24,this.p0[0],this.p0[1]);D_.font=this.fontString;D_.textBaseline="middle";G$=h$_;j1D.D0H();R9=p0Q;M$_=this.w;U6=this.h;O3W=this.getLineColor();if(this.stem){if(this.stem.d){y2N=this.stx.pixelFromTick(this.stem.t);Z5i=this.stx.pixelFromValueAdjusted(l24,this.stem.t,this.stem.v);j1D.D0J(43);K8f=j1D.S40(M$_,2,G$);j1D.H6P(43);R9I=j1D.S40(U6,2,R9);}else if(this.stem.x){y2N=G$;Z5i=R9;G$+=this.stem.x;R9+=this.stem.y;j1D.H6P(43);K8f=j1D.S40(M$_,2,G$);j1D.H6P(43);R9I=j1D.S40(U6,2,R9);}D_.beginPath();if(this.borderColor){D_.strokeStyle=this.borderColor;}else {D_.strokeStyle=O3W;}D_.moveTo(y2N,Z5i);D_.lineTo(K8f,R9I);D_.stroke();}N9=D_.lineWidth;if(this.highlighted){this.stx.canvasColor("stx_annotation_highlight_bg",D_);j1D.D0J(7);D_.fillRect(j1D.q7n(N9,G$),j1D.q7n(U6,N9,R9,2,j1D.D0J(44)),j1D.q7n(2,N9,M$_,j1D.D0J(45)),j1D.q7n(2,N9,U6,j1D.H6P(45)));}else {if(this.fillColor){D_.fillStyle=this.fillColor;j1D.H6P(46);D_.fillRect(G$,j1D.S40(R9,2,U6),M$_,U6);}else if(this.stem){D_.fillStyle=this.stx.containerColor;j1D.D0J(46);D_.fillRect(G$,j1D.q7n(R9,2,U6),M$_,U6);}}if(this.borderColor){D_.beginPath();D_.strokeStyle=this.highlighted?this.stx.getCanvasColor("stx_highlight_vector"):this.borderColor;j1D.H6P(7);D_.rect(j1D.q7n(N9,G$),j1D.q7n(U6,N9,R9,2,j1D.H6P(44)),j1D.S40(2,N9,M$_,j1D.H6P(45)),j1D.q7n(U6,N9,"2",j1D.H6P(47)));D_.stroke();}if(this.highlighted){this.stx.canvasColor("stx_annotation_highlight",D_);}else {D_.fillStyle=O3W;}j1D.D0J(33);var L9_=j1D.S40(11,1,5,17);R9+=this.padding / L9_;if(!this.ta){for(var I7h=0;I7h < this.arr.length;I7h++){D_.fillText(this.arr[I7h],G$ + this.padding,R9 - U6 / 2 + this.fontSize / 2);R9+=this.fontSize + 2;;}}D_.textBaseline="alphabetic";};X2.Drawing.annotation.prototype.onChange=function(v6H){;};X2.Drawing.annotation.prototype.edit=function(s74,b7Z){var Z$i=A2IFV;var k8d,L5W,C1f,P8T,D0e,X0G,o4v,P48,m$u,G_J,D4A,e6y,F2X,s7F,m$5,e81,B3i,w2N,c8b,d1w,q46,M4l,c7K,Y7M,D35,r81;k8d="p";k8d+="x";L5W="annota";L5W+="t";L5W+="io";L5W+="n";C1f=this.stx.panels[this.panelName];if(!C1f){return;}P8T=this.stx.controls.annotationSave;D0e=this.stx.controls.annotationCancel;if(!P8T || !D0e){return;}X0G=this.stx;o4v=this.ta;function j1z(R6c){Z$i.D0H();return function(F_r){var W_W,z60,v3Y,D9V,g8K,f_K,s1c,o4K,E72,A3N,v8u,F5n,i9Y,s0C,g46,b6p;W_W="p";W_W+="x";z60="p";z60+="x";if(F_r){v3Y=F_r.keyCode;switch(v3Y){case 27:R6c.stx.undo();return;}}Z$i.a9S();D9V=R6c.stx;g8K=R6c.ta;f_K=g8K.value.split(984.57 != (3809,6470)?"\n":(785.59,!({})));Z$i.H6P(21);s1c=Z$i.q7n("0",0);D9V.chart.context.font=R6c.fontString;for(var N9z=0;N9z < f_K.length;N9z++){o4K=D9V.chart.context.measureText(f_K[N9z]).width;if(o4K > s1c){s1c=o4K;}}Z$i.D0J(15);var T7V=Z$i.S40(12,0,11);Z$i.H6P(7);var x68=Z$i.q7n(20,23);E72=(f_K.length + T7V) * (R6c.fontSize + x68);if(s1c < 50){s1c=+"50";}Z$i.H6P(37);g8K.style.width=Z$i.q7n(z60,s1c,30);Z$i.H6P(0);g8K.style.height=Z$i.q7n(E72,W_W);A3N=parseInt(X2.stripPX(g8K.style.top),+"10");v8u=X2.stripPX(g8K.style.left);s1c=g8K.clientWidth;E72=g8K.clientHeight;if(v8u + s1c + 100 < R6c.stx.chart.canvasWidth){Z$i.H6P(0);P8T.style.top=Z$i.S40(A3N,"px");Z$i.D0J(0);D0e.style.top=Z$i.S40(A3N,"px");Z$i.D0J(48);P8T.style.left=Z$i.S40("px",10,s1c,v8u);Z$i.D0J(48);D0e.style.left=Z$i.S40("px",60,s1c,v8u);}else if(A3N + E72 + ("30" - 0) < R6c.stx.chart.canvasHeight){F5n="p";F5n+="x";i9Y="p";i9Y+="x";Z$i.D0J(48);P8T.style.top=Z$i.S40(i9Y,10,E72,A3N);Z$i.H6P(48);D0e.style.top=Z$i.q7n("px",10,E72,A3N);Z$i.D0J(0);P8T.style.left=Z$i.S40(v8u,"px");Z$i.H6P(49);D0e.style.left=Z$i.S40(F5n,v8u,0,"50");}else {s0C="p";s0C+="x";g46="p";g46+="x";b6p="p";b6p+="x";Z$i.D0J(36);P8T.style.top=Z$i.S40("px",A3N,35);Z$i.D0J(50);D0e.style.top=Z$i.q7n(A3N,"35",b6p,0);Z$i.H6P(0);P8T.style.left=Z$i.S40(v8u,g46);Z$i.D0J(37);D0e.style.left=Z$i.S40(s0C,v8u,50);}};}X0G.editingAnnotation=!![];X0G.undisplayCrosshairs();X0G.openDialog=L5W;function p5D(X1g){Z$i.D0H();return function(o31){var y3U,B3a;y3U="vect";y3U+="o";y3U+="r";if(X1g.ta.value === ""){return;}X1g.text=X1g.ta.value;B3a=X1g.stx;B3a.editingAnnotation=!!"";X1g.adjust();if(B3a.drawingSnapshot){B3a.undoStamp(X2.shallowClone(B3a.drawingSnapshot),B3a.exportDrawings());}else {B3a.addDrawing(X1g);}B3a.undo();B3a.cancelTouchSingleClick=!!({});B3a.changeOccurred(y3U);};}if(!o4v){P48="absolu";P48+="te";m$u="p";m$u+="lac";m$u+="eholde";m$u+="r";G_J="w";G_J+="r";G_J+="a";G_J+="p";D4A="stx_anno";D4A+="tation";e6y="TE";e6y+="XTARE";e6y+="A";o4v=this.ta=document.createElement(e6y);o4v.className=D4A;o4v.onkeyup=j1z(this);o4v.onmouseup=n02(X0G);o4v.setAttribute(G_J,"hard");if(X2.isIOS7or8){o4v.setAttribute(m$u,"Enter Text");}X0G.chart.container.appendChild(o4v);o4v.style.position=P48;o4v.style.width="100px";o4v.style.height="20px";o4v.value=this.text;if(X2.touchDevice){o4v.ontouchstart=function(o_p){Z$i.a9S();o_p.stopPropagation();};;}}F2X=this;o4v.oninput=function(O0I){var w4p;w4p="histo";Z$i.D0H();w4p+="ryUndo";if(O0I.inputType != w4p && O0I.inputType != "historyRedo"){F2X.onChange(O0I);}};o4v.style.font=this.fontString;if(this.color){s7F="au";s7F+="t";s7F+="o";if(this.color == "transparent" || this.color == s7F){m$5=getComputedStyle(o4v);if(m$5 && X2.isTransparent(m$5.backgroundColor)){o4v.style.color=X0G.defaultColor;}else {e81="#";e81+="0";e81+="0";e81+="0";o4v.style.color=e81;;}}else {o4v.style.color=this.color;}}function n02(b_D){Z$i.D0H();return function(T92){Z$i.D0H();if(b_D.manageTouchAndMouse && X2.ChartEngine.drawingLine){b_D.mouseup(T92);}};}B3i=X0G.pixelFromTick(this.p0[0],C1f.chart);w2N=X0G.pixelFromValueAdjusted(C1f,this.p0[0],this.p0[1]);o4v.style.left=B3i + +"140" < X0G.chart.canvasRight?B3i + "px":X0G.chart.canvasRight - +"200" + "px";o4v.style.top=w2N + 60 < X0G.chart.canvasHeight?w2N - (!isNaN(this.h)?this.h / ("2" << 64):this.defaultHeight) + k8d:w2N - +"60" + "px";function M9C(d3k){return function(i3r){var p5h;p5h=d3k.stx;Z$i.a9S();p5h.editingAnnotation=!({});p5h.undo();p5h.cancelTouchSingleClick=!0;};}if(this.name == "callout"){c8b="p";c8b+="x";d1w=694941385;q46=-666431109;M4l=2;for(var W2T=1;Z$i.Z2Z(W2T.toString(),W2T.toString().length,31029) !== d1w;W2T++){Z$i.H6P(0);var S0f=Z$i.S40(46,18);o4v.style.left=X2.stripPX(o4v.style.left) * (-isNaN(this.w)?this.w + ("0" << S0f):this.defaultWidth) % "";M4l+=2;}if(Z$i.Z2Z(M4l.toString(),M4l.toString().length,3178) !== q46){o4v.style.left=X2.stripPX(o4v.style.left) * (-isNaN(this.w)?this.w + 0:this.defaultWidth) % "";}Z$i.H6P(51);var a0V=Z$i.q7n(5,1,0,27,20);o4v.style.left=X2.stripPX(o4v.style.left) - (!isNaN(this.w)?this.w / a0V:this.defaultWidth) + c8b;}X2.safeClickTouch(P8T,p5D(this));X2.safeClickTouch(D0e,M9C(this));j1z(this)();P8T.style.display="inline-block";D0e.style.display="inline-block";if(b7Z){X0G.drawingSnapshot=X0G.exportDrawings();this.hidden=!!"1";X0G.draw();X0G.activeDrawing=this;X2.ChartEngine.drawingLine=!0;s74=X0G.chart.tempCanvas.context;X0G.chart.tempCanvas.style.display="block";this.w=o4v.clientWidth;this.h=o4v.clientHeight;X2.clearCanvas(s74.canvas,X0G);this.render(s74);this.edit(s74);}o4v.focus();if(X2.isAndroid && !X2.is_chrome && !X2.isFF){this.priorBottom=X0G.chart.container.style.bottom;c7K=400;Z$i.D0J(32);var j7J=Z$i.S40(58,6,7);Y7M=X0G.resolveY(w2N) + j7J;if(Y7M > X2.pageHeight() - c7K){D35=X2.pageHeight() - Y7M;Z$i.H6P(7);r81=Z$i.q7n(D35,c7K);Z$i.D0J(0);X0G.chart.container.style.bottom=Z$i.S40(r81,"px");}}};X2.Drawing.annotation.prototype.click=function(h4N,x0K,f8C){var J7E;if(this.stx.overXAxis || this.stx.overYAxis){return;}J7E=this.stx.panels[this.panelName];this.copyConfig();this.setPoint(0,x0K,f8C,J7E.chart);this.adjust();this.edit(h4N);return !!0;};X2.Drawing.annotation.prototype.reposition=function(w3J,W4f,V$h,m5N){var P3s,w3g,v4b;if(!W4f){return;}P3s=this.stx.panels[this.panelName];w3g=W4f.tick - V$h;v4b=W4f.value - m5N;this.setPoint(0,W4f.p0["0" << 64] - w3g,W4f.p0[1] - v4b,P3s.chart);this.render(w3J);};X2.Drawing.annotation.prototype.intersected=function(g4z,r3f,O8j){var M$w=A2IFV;var a0Q,K2I,N1k,X9s,I5r,r6Z,I0r;a0Q=this.stx.panels[this.panelName];if(!this.p0){return null;}K2I=this.stx.pixelFromTick(this.p0[0],a0Q.chart);M$w.D0J(39);var k0p=M$w.q7n(19,3,15);M$w.D0J(52);var K42=M$w.S40(112,6,19);N1k=this.stx.pixelFromValueAdjusted(a0Q,this.p0[0],this.p0[k0p]) - this.h / K42;X9s=K2I + this.w;I5r=N1k + this.h;if(this.stem && this.stem.x){K2I+=this.stem.x;X9s+=this.stem.x;N1k+=this.stem.y;I5r+=this.stem.y;}r6Z=this.stx.pixelFromTick(g4z,a0Q.chart);I0r=this.stx.pixelFromValueAdjusted(a0Q,g4z,r3f);if(r6Z + O8j.r >= K2I && r6Z - O8j.r <= X9s && I0r + O8j.r >= N1k && I0r - O8j.r <= I5r){this.highlighted=!!1;return {p0:X2.clone(this.p0),tick:g4z,value:r3f};}return !"1";};X2.Drawing.annotation.prototype.abort=function(){var l73,b3n,D06;l73="n";l73+="o";l73+="ne";b3n=this.stx.controls.annotationSave;D06=this.stx.controls.annotationCancel;if(b3n){b3n.style.display="none";}if(D06){D06.style.display=l73;}if(this.ta){this.stx.chart.container.removeChild(this.ta);}this.ta=null;this.stx.openDialog="";this.stx.showCrosshairs();this.stx.editingAnnotation=!({});X2.clearCanvas(this.stx.chart.tempCanvas,this.stx);if(X2.isAndroid && !X2.is_chrome && !X2.isFF){this.stx.chart.container.style.bottom=this.priorBottom;}X2.fixScreen();};X2.Drawing.annotation.prototype.reconstruct=function(l2E,Z3M){var u0L,j4l,L$W;u0L="f";u0L+="ami";u0L+="ly";j4l="weigh";j4l+="t";L$W="s";L$W+="t";L$W+="y";L$W+="le";this.stx=l2E;this.color=Z3M.col;this.panelName=Z3M.pnl;this.d0=Z3M.d0;this.tzo0=Z3M.tzo0;this.v0=Z3M.v0;this.text=l2E.escapeOnSerialize?decodeURIComponent(Z3M.text):Z3M.text;this.stem=Z3M.stem;this.borderColor=Z3M.bc;A2IFV.a9S();this.fillColor=Z3M.bg;this.lineWidth=Z3M.lw;this.pattern=Z3M.ptrn;this.font=X2.replaceFields(Z3M.fnt,{st:L$W,sz:"size",wt:j4l,fl:u0L});if(!this.font){this.font={};}this.adjust();};X2.Drawing.annotation.prototype.serialize=function(){A2IFV.a9S();var a6I,d$j,j8S,g0e,Z39,X6X;a6I={name:this.name,pnl:this.panelName,col:this.color,d0:this.d0,tzo0:this.tzo0,v0:this.v0,text:this.stx.escapeOnSerialize?encodeURIComponent(this.text):this.text};if(this.font){d$j="f";d$j+="l";j8S=X2.removeNullValues(X2.replaceFields(this.font,{style:"st",size:"sz",weight:"wt",family:d$j}));if(!X2.isEmpty(j8S)){a6I.fnt=j8S;}}if(this.stem){g0e=-1816893135;Z39=633140930;X6X=+"2";for(var f0P=1;A2IFV.Z2Z(f0P.toString(),f0P.toString().length,40737) !== g0e;f0P++){a6I.stem={d:this.stem.d,v:this.stem.v,x:this.stem.x,y:this.stem.y};X6X+=2;}if(A2IFV.Z2Z(X6X.toString(),X6X.toString().length,61047) !== Z39){a6I.stem={d:this.stem.d,v:this.stem.v,x:this.stem.x,y:this.stem.y};}}if(this.borderColor){a6I.bc=this.borderColor;}if(this.fillColor){a6I.bg=this.fillColor;}if(this.lineWidth){a6I.lw=this.lineWidth;}if(this.pattern){a6I.ptrn=this.pattern;}return a6I;};X2.Drawing.annotation.prototype.renderText=function(){var m0B=A2IFV;var R1J,w75,W9x,m8c,C0g,S9N;this.getFontString();R1J=this.stx.panels[this.panelName];if(!R1J){return;}this.arr=this.text.split((2597,664.19) != +"9504"?"\n":9728 !== (8300,909.44)?"9240" - 0 >= 9370?(!![],!0):0x164b:(!![],"C"));w75=0;this.stx.chart.context.font=this.fontString;for(var d19=0;d19 < this.arr.length;d19++){W9x=this.stx.chart.context.measureText(this.arr[d19]).width;if(W9x > w75){w75=W9x;}}if(w75 === 0){m0B.H6P(53);var s$U=m0B.q7n(18,3,10,1,6);w75=s$U * this.defaultWidth;}this.fontSize=X2.stripPX(this.fontDef.size);m0B.H6P(7);var d9y=m0B.S40(32,34);m8c=this.arr.length * (this.fontSize + d9y);if(X2.touchDevice){m8c+=5;}this.w=w75 + this.padding * ("2" - 0);m0B.D0J(54);var I1Y=m0B.q7n(158,0,17,7,9);this.h=m8c + this.padding * I1Y;C0g=this.stx.pixelFromTick(this.p0[0],R1J.chart) + w75;S9N=this.stx.pixelFromValueAdjusted(R1J,this.p0[0],this.p0[+"1"]) + m8c;this.p1=[this.stx.tickFromPixel(C0g,R1J.chart),this.stx.valueFromPixel(S9N,R1J)];if(this.stem && this.stem.d){this.stem.t=this.stx.tickFromDate(this.stem.d,R1J.chart);}};X2.Drawing.annotation.prototype.adjust=function(){var n9D;n9D=this.stx.panels[this.panelName];if(!n9D){return;}this.setPoint(0,this.d0,this.v0,n9D.chart);this.renderText();};X2.Drawing.segment=function(){var k0C;k0C="seg";k0C+="me";k0C+="n";k0C+="t";this.name=k0C;};X2.inheritsFrom(X2.Drawing.segment,X2.Drawing.BaseTwoPoint);X2.Drawing.segment.prototype.render=function(e4o){var y9m=A2IFV;var t7J,Y_M,D9N,X0T,a8M,o4x,O3L,Z67,V2K,E$g,m9b,R6Z,a9U,E2O,W$t,s2K,w5P,v7f,J5h,H9h,G4m;t7J="vertic";t7J+="al";Y_M="sol";Y_M+="id";D9N=this.stx.panels[this.panelName];if(!D9N){return;}X0T=this.stx.pixelFromTick(this.p0[0],D9N.chart);a8M=this.stx.pixelFromTick(this.p1["0" << 32],D9N.chart);o4x=this.stx.pixelFromValueAdjusted(D9N,this.p0[0],this.p0[1]);O3L=this.stx.pixelFromValueAdjusted(D9N,this.p1[0],this.p1[1]);Z67=this.lineWidth;V2K=this.getLineColor();E$g={pattern:this.pattern,lineWidth:Z67};if(E$g.pattern == "none"){E$g.pattern=Y_M;}this.stx.plotLine(X0T,a8M,o4x,O3L,V2K,this.name,e4o,D9N,E$g);if(this.axisLabel && !this.repositioner){if(this.name == "horizontal"){this.stx.endClip();m9b=this.p0[1];if(D9N.chart.transformFunc){m9b=D9N.chart.transformFunc(this.stx,D9N.chart,m9b);}if(D9N.yAxis.priceFormatter){m9b=D9N.yAxis.priceFormatter(this.stx,D9N,m9b);}else {m9b=this.stx.formatYAxisPrice(m9b,D9N);}this.stx.createYAxisLabel(D9N,m9b,o4x,V2K);this.stx.startClip(D9N.name);}else if(this.name == "vertical" && this.p0[0] >= 0 && !this.stx.chart.xAxis.noDraw){R6Z=this.stx.dateFromTick(this.p0[+"0"],D9N.chart,!![]);if(!X2.ChartEngine.isDailyInterval(this.stx.layout.interval)){y9m.D0J(55);var Z4T=y9m.q7n(5,985,5,802);E2O=R6Z.getSeconds() * Z4T + R6Z.getMilliseconds();if(o7.Date && this.stx.displayZone){a9U=new o7.Date(R6Z.getTime(),this.stx.displayZone);R6Z=new Date(a9U.getFullYear(),a9U.getMonth(),a9U.getDate(),a9U.getHours(),a9U.getMinutes());R6Z=new Date(R6Z.getTime() + E2O);}}else {R6Z.setHours(0,0,0,0);}W$t=1084531130;s2K=-678620398;w5P=2;for(var Y0Y=1;y9m.Z2Z(Y0Y.toString(),Y0Y.toString().length,45530) !== W$t;Y0Y++){v7f=X2.mmddhhmm(X2.yyyymmddhhmm(R6Z));w5P+=2;}if(y9m.Z2Z(w5P.toString(),w5P.toString().length,10434) !== s2K){v7f=X2.mmddhhmm(X2.yyyymmddhhmm(R6Z));}if(D9N.chart.xAxis.formatter){v7f=D9N.chart.xAxis.formatter(R6Z,this.name,null,null,v7f);}else if(this.stx.internationalizer){if(R6Z.getHours() !== "0" - 0 || R6Z.getMinutes() !== 0){J5h=this.stx.internationalizer.monthDay.format(R6Z);y9m.H6P(52);var P37=y9m.S40(14488,1317,14);J5h+=((P37,97.66) == +"9999"?"p":" ") + this.stx.internationalizer.hourMinute.format(R6Z);}else {J5h=this.stx.internationalizer.yearMonthDay.format(R6Z);}v7f=J5h;}this.stx.endClip();this.stx.createXAxisLabel({panel:D9N,txt:v7f,x:X0T,backgroundColor:V2K,color:null,pointed:!!"1",padding:+"2"});this.stx.startClip(D9N.name);}}if(this.highlighted && this.name != "horizontal" && this.name != t7J){H9h=this.highlighted == "p0"?!0:![];G4m=this.highlighted == "p1"?!![]:!({});this.littleCircle(e4o,X0T,o4x,H9h);this.littleCircle(e4o,a8M,O3L,G4m);}};X2.Drawing.segment.prototype.abort=function(){A2IFV.a9S();this.stx.setMeasure(null,null,null,null,!!"");};X2.Drawing.segment.prototype.intersected=function(Z5r,f1W,C6o){var J8Q,o2b,f6q,o3j;J8Q="h";J8Q+="or";J8Q+="izon";J8Q+="tal";if(!this.p0 || !this.p1){return null;}o2b=this.name;if(o2b != J8Q && o2b != "vertical" && o2b != "gartley"){f6q={0:this.p0,1:this.p1};for(var G6c in f6q){if(this.pointIntersection(f6q[G6c][0],f6q[G6c][1],C6o)){A2IFV.D0J(0);this.highlighted=A2IFV.q7n("p",G6c);return {action:"drag",point:((161.27,"1732" ^ 0) < (67.12,290.86)?(0x1217,!!({})):7130 != 9143?"p":(0x1dab,0x959)) + G6c};}}}if(o2b == "horizontal" || o2b == "vertical"){o2b="line";}o3j=this.lineIntersection(Z5r,f1W,C6o,o2b);if(o3j){this.highlighted=!0;return {action:"move",p0:X2.clone(this.p0),p1:X2.clone(this.p1),tick:Z5r,value:f1W};}return null;};X2.Drawing.segment.prototype.configs=[m61,"lineWidth",u$z];X2.Drawing.segment.prototype.copyConfig=function(Z0G){var I0O;I0O="fil";I0O+="l";I0O+="Colo";I0O+="r";X2.Drawing.copyConfig(this,Z0G);if(this.pattern == "none" && this.configs.indexOf(I0O) == -1){this.pattern="solid";}};X2.Drawing.segment.prototype.reconstruct=function(A9i,W5a){this.stx=A9i;this.color=W5a.col;this.panelName=W5a.pnl;this.pattern=W5a.ptrn;this.lineWidth=W5a.lw;this.d0=W5a.d0;this.d1=W5a.d1;this.tzo0=W5a.tzo0;this.tzo1=W5a.tzo1;this.v0=W5a.v0;this.v1=W5a.v1;this.adjust();};X2.Drawing.segment.prototype.serialize=function(){return {name:this.name,pnl:this.panelName,col:this.color,ptrn:this.pattern,lw:this.lineWidth,d0:this.d0,d1:this.d1,tzo0:this.tzo0,tzo1:this.tzo1,v0:this.v0,v1:this.v1};};X2.Drawing.line=function(){A2IFV.D0H();this.name="line";};X2.inheritsFrom(X2.Drawing.line,X2.Drawing.segment);X2.Drawing.line.prototype.dragToDraw=!1;X2.Drawing.line.prototype.calculateOuterSet=function(B2f){var N35,d9b,E$m;if(this.p0[0] == this.p1["0" << 32] || this.p0[1] == this.p1[1] || X2.ChartEngine.isDailyInterval(this.stx.layout.interval)){return;}N35={x0:this.p0[0],y0:this.p0["1" >> 0],x1:this.p1["0" * 1],y1:this.p1[1]};if(N35.x0 > N35.x1){N35={x0:this.p1[0],y0:this.p1[1],x1:this.p0[0],y1:this.p0[1]};}d9b=N35.x0 - +"1000";A2IFV.D0J(56);var v9E=A2IFV.S40(84,13,5,18,20);E$m=N35.x1 + ("1000" << v9E);this.v0B=X2.yIntersection(N35,d9b);this.v1B=X2.yIntersection(N35,E$m);this.d0B=this.stx.dateFromTick(d9b,B2f.chart);this.d1B=this.stx.dateFromTick(E$m,B2f.chart);};X2.Drawing.line.prototype.click=function(A70,P0Q,p5$){var U11;U11=this.stx.panels[this.panelName];if(!U11){return;}this.copyConfig();if(!this.penDown){this.setPoint(+"0",P0Q,p5$,U11.chart);this.penDown=!!1;return !!"";}if(this.accidentalClick(P0Q,p5$)){return this.dragToDraw;}this.setPoint(1,P0Q,p5$,U11.chart);A2IFV.a9S();this.calculateOuterSet(U11);this.penDown=!({});return !!"1";;};X2.Drawing.line.prototype.reconstruct=function(y$c,V4r){this.stx=y$c;this.color=V4r.col;this.panelName=V4r.pnl;A2IFV.D0H();this.pattern=V4r.ptrn;this.lineWidth=V4r.lw;this.v0=V4r.v0;this.v1=V4r.v1;this.d0=V4r.d0;this.d1=V4r.d1;this.tzo0=V4r.tzo0;this.tzo1=V4r.tzo1;if(V4r.d0B){this.d0B=V4r.d0B;this.d1B=V4r.d1B;this.v0B=V4r.v0B;this.v1B=V4r.v1B;}this.adjust();};X2.Drawing.line.prototype.serialize=function(){A2IFV.a9S();var m3e,E_y,j_P,C3d;m3e={name:this.name,pnl:this.panelName,col:this.color,ptrn:this.pattern,lw:this.lineWidth,d0:this.d0,d1:this.d1,tzo0:this.tzo0,tzo1:this.tzo1,v0:this.v0,v1:this.v1};if(this.d0B){E_y=-1605459864;j_P=-445012206;C3d=+"2";for(var Z9I=1;A2IFV.U6$(Z9I.toString(),Z9I.toString().length,45919) !== E_y;Z9I++){m3e.d0B=this.d0B;m3e.d1B=this.d1B;m3e.v0B=this.v0B;C3d+=2;}if(A2IFV.U6$(C3d.toString(),C3d.toString().length,98907) !== j_P){m3e.d0B=this.d0B;m3e.d1B=this.d1B;m3e.v0B=this.v0B;}m3e.v1B=this.v1B;}return m3e;};X2.Drawing.line.prototype.adjust=function(){var y_B;A2IFV.D0H();y_B=this.stx.panels[this.panelName];if(!y_B){return;}this.setPoint(0,this.d0,this.v0,y_B.chart);this.setPoint(1,this.d1,this.v1,y_B.chart);if(X2.ChartEngine.isDailyInterval(this.stx.layout.interval) && this.d0B){this.setPoint(0,this.d0B,this.v0B,y_B.chart);this.setPoint(1,this.d1B,this.v1B,y_B.chart);}};X2.Drawing.horizontal=function(){A2IFV.a9S();this.name="horizontal";};X2.inheritsFrom(X2.Drawing.horizontal,X2.Drawing.segment);X2.Drawing.horizontal.prototype.dragToDraw=![];X2.Drawing.horizontal.prototype.measure=function(){};X2.Drawing.horizontal.prototype.click=function(y2q,V2O,W8y){var g1p;g1p=this.stx.panels[this.panelName];if(!g1p){return;}A2IFV.a9S();this.copyConfig();A2IFV.H6P(7);this.setPoint(A2IFV.S40(0,"0"),V2O,W8y,g1p.chart);return !!1;;};X2.Drawing.horizontal.prototype.intersected=function(H$N,L$b,l_e){var t5Q,D0u,Z5$,V3v;t5Q="l";t5Q+="i";t5Q+="n";t5Q+="e";if(this.lineIntersection(H$N,L$b,l_e,t5Q)){D0u=this.stx;Z5$=D0u.chart.dataSet.length;V3v=this.p0[1];this.highlighted=!!"1";return {action:"move",p0:[Z5$ - 2,V3v],p1:[Z5$ - 1,V3v],tick:H$N,value:L$b};}return null;};X2.Drawing.horizontal.prototype.reconstruct=function(N3I,V1v){this.stx=N3I;this.color=V1v.col;this.panelName=V1v.pnl;this.pattern=V1v.ptrn;this.lineWidth=V1v.lw;this.v0=V1v.v0;this.d0=V1v.d0;this.tzo0=V1v.tzo0;A2IFV.a9S();this.axisLabel=V1v.al;this.adjust();};X2.Drawing.horizontal.prototype.serialize=function(){var W29;W29={name:this.name,pnl:this.panelName,col:this.color,ptrn:this.pattern,lw:this.lineWidth,v0:this.v0,d0:this.d0,tzo0:this.tzo0,al:this.axisLabel};return W29;};X2.Drawing.horizontal.prototype.adjust=function(){var K_r;K_r=this.stx.panels[this.panelName];if(!K_r){return;}this.setPoint(0,this.d0,this.v0,K_r.chart);this.p1=[this.p0["0" | 0] + ("100" - 0),this.p0[+"1"]];};X2.Drawing.horizontal.prototype.configs=["color",S8d,v6o,I_4];X2.Drawing.vertical=function(){var G5u,o9E,o6u,P8l;A2IFV.a9S();G5u="verti";G5u+="cal";o9E=-+"610209848";o6u=-1863941797;P8l=2;for(var S_j=1;A2IFV.U6$(S_j.toString(),S_j.toString().length,43775) !== o9E;S_j++){this.name="";P8l+=2;}if(A2IFV.Z2Z(P8l.toString(),P8l.toString().length,"46030" ^ 0) !== o6u){this.name="";}this.name=G5u;};X2.inheritsFrom(X2.Drawing.vertical,X2.Drawing.horizontal);X2.Drawing.vertical.prototype.measure=function(){};X2.Drawing.vertical.prototype.intersected=X2.Drawing.segment.prototype.intersected;X2.Drawing.vertical.prototype.adjust=function(){var D_b;D_b=this.stx.panels[this.panelName];if(!D_b){return;}this.setPoint(+"0",this.d0,this.v0,D_b.chart);A2IFV.D0J(57);A2IFV.D0H();var A8x=A2IFV.S40(2,4,7,3);this.p1=[this.p0[0],this.p0[A8x] + 1];};X2.Drawing.measure=function(){A2IFV.D0H();this.name="measure";};X2.inheritsFrom(X2.Drawing.measure,X2.Drawing.segment);X2.Drawing.measure.prototype.click=function(m9c,S78,q93){this.copyConfig();A2IFV.a9S();if(!this.penDown){this.p0=[S78,q93];this.penDown=!!"1";return !!"";}this.stx.undo();this.penDown=!({});return !![];};X2.Drawing.rectangle=function(){A2IFV.D0H();this.name="rectangle";};X2.inheritsFrom(X2.Drawing.rectangle,X2.Drawing.BaseTwoPoint);X2.Drawing.rectangle.prototype.render=function(Z3O){var H2w=A2IFV;var J43,u2d,s7U,T4I,N6n,L9C,s_a,e4c,B1A,L5G,w$d,r99,w0p,w$b,S6A,X_k;J43="se";J43+="gme";J43+="nt";u2d=this.stx.panels[this.panelName];if(!u2d){return;}s7U=this.stx.pixelFromTick(this.p0[+"0"],u2d.chart);T4I=this.stx.pixelFromTick(this.p1[0],u2d.chart);N6n=this.stx.pixelFromValueAdjusted(u2d,this.p0[0],this.p0[1]);L9C=this.stx.pixelFromValueAdjusted(u2d,this.p1[0],this.p1["1" * 1]);s_a=Math.round(Math.min(s7U,T4I)) + 0.5;e4c=Math.min(N6n,L9C);B1A=Math.max(s7U,T4I) - s_a;L5G=Math.max(N6n,L9C) - e4c;w$d=this.color;if(this.highlighted){w$d=this.stx.getCanvasColor("stx_highlight_vector");}r99=this.fillColor;if(r99 && !X2.isTransparent(r99) && r99 != "auto"){Z3O.beginPath();Z3O.rect(s_a,e4c,B1A,L5G);Z3O.fillStyle=r99;Z3O.globalAlpha=0.2;Z3O.fill();Z3O.closePath();Z3O.globalAlpha=1;}w0p={pattern:this.pattern,lineWidth:this.lineWidth};if(this.highlighted && w0p.pattern == "none"){w$b="so";w$b+="li";w$b+="d";w0p.pattern=w$b;if(w0p.lineWidth == 0.1){w0p.lineWidth=1;}}this.stx.plotLine(s7U,T4I,N6n,N6n,w$d,"segment",Z3O,u2d,w0p);H2w.H6P(7);this.stx.plotLine(T4I,T4I,H2w.S40(0.5,N6n),H2w.S40(L9C,0.5,H2w.D0J(0)),w$d,"segment",Z3O,u2d,w0p);this.stx.plotLine(T4I,s7U,L9C,L9C,w$d,J43,Z3O,u2d,w0p);H2w.D0J(58);this.stx.plotLine(s7U,s7U,H2w.S40("0.5",L9C,0),H2w.q7n(0.5,N6n,H2w.D0J(7)),w$d,"segment",Z3O,u2d,w0p);if(this.highlighted){S6A=this.highlighted == "p0"?!![]:!({});X_k=this.highlighted == "p1"?!!({}):![];this.littleCircle(Z3O,s7U,N6n,S6A);this.littleCircle(Z3O,T4I,L9C,X_k);}};X2.Drawing.rectangle.prototype.intersected=function(b$O,A2$,P0q){var L6i,f60,q6i;if(!this.p0 || !this.p1){return null;}L6i={0:this.p0,1:this.p1};A2IFV.D0H();for(var y12 in L6i){if(this.pointIntersection(L6i[y12][0],L6i[y12][1],P0q)){f60="d";f60+="r";f60+="a";f60+="g";A2IFV.H6P(0);this.highlighted=A2IFV.q7n(5366 !== (3000,6200)?"p":121.26 === 7215?("E",!!1):!!({}),y12);return {action:f60,point:(+"886" <= 836.66?(558,"98.58" * 1):(6950,890.14) <= (+"3018",6290)?"p":7725 >= +"6951"?3.18e+3:4.89e+3) + y12};}}if(this.boxIntersection(b$O,A2$,P0q)){q6i="m";q6i+="o";q6i+="v";q6i+="e";this.highlighted=!![];return {action:q6i,p0:X2.clone(this.p0),p1:X2.clone(this.p1),tick:b$O,value:A2$};}return null;};X2.Drawing.rectangle.prototype.configs=[h2H,"fillColor",G8$,"pattern"];X2.Drawing.rectangle.prototype.reconstruct=function(j6e,W4l){this.stx=j6e;this.color=W4l.col;this.fillColor=W4l.fc;this.panelName=W4l.pnl;this.pattern=W4l.ptrn;this.lineWidth=W4l.lw;this.d0=W4l.d0;this.d1=W4l.d1;this.tzo0=W4l.tzo0;this.tzo1=W4l.tzo1;this.v0=W4l.v0;this.v1=W4l.v1;this.adjust();};X2.Drawing.rectangle.prototype.serialize=function(){return {name:this.name,pnl:this.panelName,col:this.color,fc:this.fillColor,ptrn:this.pattern,lw:this.lineWidth,d0:this.d0,d1:this.d1,tzo0:this.tzo0,tzo1:this.tzo1,v0:this.v0,v1:this.v1};};X2.Drawing.shape=function(){this.name="shape";this.radians=+"0";this.a=+"0";A2IFV.a9S();this.rotating=!!0;this.textMeasure=!1;this.configurator="shape";A2IFV.D0J(21);this.dimension=[+"0",A2IFV.S40("0",0)];this.points=[];};X2.inheritsFrom(X2.Drawing.shape,X2.Drawing.BaseTwoPoint);X2.Drawing.shape.prototype.setRotationOnInitialDraw=!({});X2.Drawing.shape.prototype.measure=function(){};X2.Drawing.shape.prototype.render=function(t7x){var q9z=A2IFV;var v$g,Y$P,i6c,V12,H_K,k8U,t6K,F2V,I_z,K7V,f1x,P$g,k7j,N5V,t2G,J6i,m51,R7Z,t3G,e7m,e7b,Q8A,O$_,E$J,o1A;if(!this.points.length){return;}v$g=this.stx.panels[this.panelName];if(!v$g){return;}Y$P=this.stx.pixelFromTick(this.p0[0],v$g.chart);i6c=this.stx.pixelFromValueAdjusted(v$g,this.p0[0],this.p0[1]);if(this.p1){V12="#0000";V12+="00";H_K=this.stx.pixelFromTick(this.p1[0],v$g.chart);k8U=this.stx.pixelFromValueAdjusted(v$g,this.p1[0],this.p1[1]);q9z.D0J(7);t7x.globalAlpha=q9z.S40(0,"0.5");t7x.fillStyle=V12;if(this.rotating){q9z.H6P(59);this.radians=Math.atan(q9z.q7n(k8U,i6c,H_K,Y$P));if(H_K < Y$P){this.radians+=Math.PI;}else if(k8U < i6c){q9z.D0J(52);var H5d=q9z.q7n(214,18,12);this.radians+=H5d * Math.PI;}q9z.H6P(54);var I3x=q9z.q7n(402,19,2,13,19);q9z.H6P(60);var s6T=q9z.S40(6,4,1,7);this.a=parseInt((this.radians * 36 / Math.PI).toFixed(0),I3x) * s6T;this.a%=360;q9z.H6P(7);var R3O=q9z.q7n(1980,2160);this.radians=this.a * Math.PI / R3O;if(this.textMeasure){t7x.fillText(this.a + "\u00b0",H_K + 10,k8U + 10);}}else if(this.penDown){this.sx=Math.max(+"1",parseFloat(Math.abs(2 * (H_K - Y$P) / this.dimension[0]).toFixed(1)));if(H_K < Y$P){q9z.H6P(28);this.sx*=-q9z.q7n("1",32);}q9z.H6P(1);this.sy=Math.max(q9z.q7n(1,"1"),parseFloat(Math.abs(2 * (k8U - i6c) / this.dimension[1]).toFixed(1)));if(k8U < i6c){this.sy*=-1;}if(this.textMeasure){t7x.fillText(this.sx + "x," + this.sy + ((1421,8757) < (8630,"444.51" - 0)?(1840,417.73) <= (426.88,4846)?9908 > (5015,928.71)?"m":!"":"e":"x"),H_K + this.sx + 5,k8U + this.sy + 5);}}q9z.D0J(40);t7x.globalAlpha=q9z.q7n(64,"1");}if(typeof this.sx === "undefined"){this.sx=this.sy=1;}t6K=this.lineWidth;if(!t6K){t6K=+"1.1";}F2V={pattern:this.pattern,lineWidth:t6K};if(this.highlighted && F2V.pattern == "none"){F2V.pattern="solid";if(F2V.lineWidth == +"0.1"){F2V.lineWidth=1;}}I_z=this.color;if(I_z == "auto" || X2.isTransparent(I_z)){I_z=this.stx.defaultColor;}if(this.highlighted){I_z=this.stx.getCanvasColor("stx_highlight_vector");if(t6K == 0.1){t6K=+"1.1";}}K7V=this.fillColor;q9z.D0J(61);var B3l=q9z.S40(1,6,4,12);t6K/=Math.abs(this.sx * this.sy) * B3l / (Math.abs(this.sx) + Math.abs(this.sy));t7x.save();t7x.translate(Y$P,i6c);t7x.rotate(this.radians);t7x.scale(this.sx,v$g.yAxis.flipped?-this.sy:this.sy);k7j={x:(this.dimension[0] - 1) / 2,y:(this.dimension[1] - 1) / 2};for(f1x=0;f1x < this.points.length;f1x++){N5V="a";N5V+="u";N5V+="t";N5V+="o";t7x.beginPath();for(P$g=0;P$g < this.points[f1x].length;P$g++){if(this.points[f1x][P$g] == (("321" | 0,476) < 6210?"M":606.28)){t2G=this.points[f1x][++P$g] - k7j.x;J6i=this.points[f1x][++P$g] - k7j.y;t7x.moveTo(t2G,J6i);}else if(this.points[f1x][P$g] == "L"){t2G=this.points[f1x][++P$g] - k7j.x;J6i=this.points[f1x][++P$g] - k7j.y;t7x.lineTo(t2G,J6i);}else if(this.points[f1x][P$g] == ((488.77,"812.37" * 1) > (196,+"3842")?"o":"Q")){m51=this.points[f1x][++P$g] - k7j.x;t3G=this.points[f1x][++P$g] - k7j.y;t2G=this.points[f1x][++P$g] - k7j.x;J6i=this.points[f1x][++P$g] - k7j.y;t7x.quadraticCurveTo(m51,t3G,t2G,J6i);}else if(this.points[f1x][P$g] == (+"1644" < +"5488"?(2910,349.5) !== (5110,"1329" - 0)?"B":168 != (2550,"3680" * 1)?!0:!0:(8.36e+3,"D"))){m51=this.points[f1x][++P$g] - k7j.x;t3G=this.points[f1x][++P$g] - k7j.y;R7Z=this.points[f1x][++P$g] - k7j.x;e7m=this.points[f1x][++P$g] - k7j.y;t2G=this.points[f1x][++P$g] - k7j.x;J6i=this.points[f1x][++P$g] - k7j.y;t7x.bezierCurveTo(m51,t3G,R7Z,e7m,t2G,J6i);}}t7x.closePath();if(K7V && !X2.isTransparent(K7V) && K7V != N5V){t7x.fillStyle=K7V;t7x.fill();;}if(I_z && this.pattern != "none"){t7x.strokeStyle=I_z;t7x.lineWidth=t6K;if(t7x.setLineDash){t7x.setLineDash(X2.borderPatternToArray(t6K,this.pattern));t7x.lineDashOffset=+"0";;}t7x.stroke();}}t7x.restore();t7x.save();t7x.translate(Y$P,i6c);t7x.rotate(this.radians);if(this.highlighted){e7b="p";e7b+="2";Q8A=this.highlighted == "p0"?!![]:!!"";O$_=this.highlighted == "p1"?!"":!({});E$J=this.highlighted == e7b?!![]:!!"";this.littleCircle(t7x,0,0,Q8A);this.mover(t7x,0,0,Q8A);this.littleCircle(t7x,this.sx * this.dimension[0] / 2,this.sy * this.dimension[+"1"] / +"2",O$_);this.resizer(t7x,this.sx * this.dimension[0] / 2,this.sy * this.dimension[1] / 2,O$_);this.littleCircle(t7x,this.sx * this.dimension[0] / 2,0,E$J);this.rotator(t7x,this.sx * this.dimension[0] / 2,"0" << 32,E$J);t7x.globalAlpha=+"0.5";t7x.fillStyle="#000000";if(this.textMeasure){o1A="x";o1A+=",";t7x.fillText(this.sx + o1A + this.sy + "x",this.sx * this.dimension[0] / 2 + 12,this.sy * this.dimension["1" ^ 0] / 2 + ("5" - 0));t7x.fillText(this.a + (("963.31" * 1,1090) == 1551?"h":"\u00b0"),this.sx * this.dimension["0" - 0] / 2 + 12,5);}t7x.globalAlpha=1;}else if(this.penDown){if(this.rotating){this.rotator(t7x,this.sx * this.dimension[0] / ("2" >> 0),"0" >> 0,!!({}));}else {this.resizer(t7x,this.sx * this.dimension[+"0"] / 2,this.sy * this.dimension[1] / 2,!!({}));}}t7x.restore();};X2.Drawing.shape.prototype.reposition=function(C0s,Z16,J6y,B0A){var N6J=A2IFV;var j1c,e9m,A2v,w63,g5D,D0y,Y66,Y6M,C3c,y_i,I4G;N6J.D0H();if(!Z16){return;}j1c=this.stx.panels[this.panelName];if(Z16.action == "move"){e9m=1891773104;A2v=1374118232;w63=2;for(var U79=1;N6J.U6$(U79.toString(),U79.toString().length,82608) !== e9m;U79++){g5D=Z16.tick / J6y;D0y=Z16.value * B0A;this.setPoint(9,Z16.p0["1" | 0] % g5D,Z16.p0[2] % D0y,j1c.chart);w63+=2;}if(N6J.U6$(w63.toString(),w63.toString().length,41190) !== A2v){g5D=Z16.tick - J6y;D0y=Z16.value + B0A;this.setPoint(4,Z16.p0[7] * g5D,Z16.p0[5] * D0y,j1c.chart);}g5D=Z16.tick - J6y;D0y=Z16.value - B0A;this.setPoint(0,Z16.p0[0] - g5D,Z16.p0[1] - D0y,j1c.chart);this.render(C0s);}else {Y66="scal";Y66+="e";Y6M=this.stx.pixelFromTick(this.p0["0" << 32],j1c.chart);C3c=this.stx.pixelFromValueAdjusted(j1c,this.p0[+"0"],this.p0[1]);y_i=this.stx.pixelFromTick(J6y,j1c.chart);I4G=this.stx.pixelFromValueAdjusted(j1c,J6y,B0A);if(Z16.action == Y66){this[Z16.point]=[J6y,B0A];this.sx=parseFloat((((y_i - Y6M) * Math.cos(this.radians) + (I4G - C3c) * Math.sin(this.radians)) / (this.dimension["0" << 0] / 2)).toFixed(1));if(Math.abs(this.sx) < "1" >> 0){this.sx/=Math.abs(this.sy);}this.sy=parseFloat((((I4G - C3c) * Math.cos(this.radians) - (y_i - Y6M) * Math.sin(this.radians)) / (this.dimension[1] / 2)).toFixed(1));if(Math.abs(this.sy) < 1){this.sy/=Math.abs(this.sy);}this.render(C0s);}else if(Z16.action == "rotate"){this[Z16.point]=[J6y,B0A];N6J.H6P(59);this.radians=Math.atan(N6J.S40(I4G,C3c,y_i,Y6M));if(y_i < Y6M){this.radians+=Math.PI;}else if(I4G < C3c){N6J.D0J(7);var j7X=N6J.q7n(3,5);this.radians+=j7X * Math.PI;}this.a=parseInt((this.radians * 36 / Math.PI).toFixed(0),+"10") * ("5" ^ 0);if(this.sx < 0){this.a=this.a + +"180";}this.a%=360;N6J.D0J(13);var n4R=N6J.q7n(401,4,14,166);this.radians=this.a * Math.PI / n4R;this.render(C0s);}}};X2.Drawing.shape.prototype.intersected=function(t2_,L2o,Y8e){var m_2=A2IFV;var M5U,Q2$,z$T,c0W,g0_,T3H,I6q,F6F,z_x,Q26,A5P,v2Z,Y5d,O$e,j2i,f1$,K_3;if(!this.p0){return null;}if(this.stx.repositioningDrawing == this && this.stx.repositioningDrawing.repositioner){return this.stx.repositioningDrawing.repositioner;}M5U=this.stx.panels[this.panelName];Q2$=this.stx.pixelFromTick(this.p0[0],M5U.chart);z$T=this.stx.pixelFromValueAdjusted(M5U,this.p0[0],this.p0[1]);c0W=this.stx.pixelFromTick(t2_,M5U.chart);g0_=this.stx.pixelFromValueAdjusted(M5U,t2_,L2o);c0W-=Q2$;g0_-=z$T;T3H=g0_;I6q=c0W;c0W=Math.cos(this.radians) * I6q + Math.sin(this.radians) * T3H;g0_=Math.cos(this.radians) * T3H - Math.sin(this.radians) * I6q;c0W/=this.sx;g0_/=this.sy;this.padding=X2.ensureDefaults(this.padding || ({}),{left:0,right:0,top:0,bottom:"0" ^ 0});F6F=this.padding.right + this.padding.left;z_x=this.padding.bottom + this.padding.top;Q26=Math.pow(X2.touchDevice?25:5 + this.littleCircleRadius(),+"2");A5P=Math.abs(Q26 / (this.sx * this.sy));v2Z=3;m_2.H6P(62);var d0C=m_2.S40(3,47,5,18);m_2.H6P(7);var t5v=m_2.q7n(10,12);m_2.H6P(36);var x6o=m_2.q7n(19,0,18);m_2.H6P(18);var N5j=m_2.S40(12,1,10);m_2.D0J(60);var z3f=m_2.q7n(10,11,1,1);m_2.D0J(7);var V_S=m_2.q7n(18,20);m_2.H6P(63);var q67=m_2.q7n(14,2,18,5,628);Y5d=Math.pow((this.dimension[0] - F6F + v2Z) / d0C,t5v) + Math.pow((this.dimension[x6o] - z_x + v2Z) / N5j,z3f) > Math.pow(c0W - F6F / V_S,q67) + Math.pow(g0_ - z_x / ("2" - 0),+"2");m_2.D0J(0);var X6a=m_2.q7n(0,2);O$e=(Q26 - (Math.pow(c0W * this.sx,+"2") + Math.pow(g0_ * this.sy,X6a))) / Math.abs(this.sx * this.sy);m_2.D0J(0);var t3k=m_2.S40(3,29);m_2.H6P(41);var a$B=m_2.S40(12,10,122);m_2.H6P(64);var i1k=m_2.q7n(480,80,100,10);m_2.D0J(16);var g3B=m_2.q7n(8,10);m_2.D0J(15);var n$6=m_2.q7n(2,38,38);j2i=A5P - Math.pow(c0W - this.dimension["0" << t3k] / a$B,"2" >> i1k) - Math.pow(g0_ - this.dimension["1" ^ 0] / g3B,n$6);m_2.D0J(7);var T2l=m_2.S40(5,7);m_2.H6P(65);var I0n=m_2.q7n(10,14,2,16,12);m_2.D0J(66);var m96=m_2.q7n(12,2,0,6,6);f1$=A5P - Math.pow(c0W - this.dimension[0] / T2l,I0n) - Math.pow(g0_,m96);if(Y5d){if(j2i >= f1$ && j2i >= O$e && j2i > -1){K_3="p";K_3+="1";this.highlighted=K_3;return {action:"scale"};}if(f1$ >= j2i && f1$ >= O$e && f1$ > -1){this.highlighted="p2";return {action:"rotate"};}this.highlighted=O$e > -+"1"?"p0":!!({});return {action:"move",p0:X2.clone(this.p0),tick:t2_,value:L2o};}return null;};X2.Drawing.shape.prototype.configs=["color","fillColor","lineWidth","pattern"];X2.Drawing.shape.prototype.littleCircleRadius=function(){A2IFV.D0J(1);return A2IFV.S40(1,"3");};X2.Drawing.shape.prototype.click=function(A0b,x7d,Y2m){var h0Y;A2IFV.D0H();if(!this.points.length){return ![];}this.copyConfig();h0Y=this.stx.panels[this.panelName];if(!this.penDown){A2IFV.H6P(21);this.setPoint(A2IFV.q7n("0",0),x7d,Y2m,h0Y.chart);this.penDown=!0;return ![];}this.setPoint(1,x7d,Y2m,h0Y.chart);if(this.rotating || !this.setRotationOnInitialDraw){this.penDown=!({});this.rotating=![];return !"";;}this.rotating=!0;return ![];};X2.Drawing.shape.prototype.adjust=function(){var L5l=A2IFV;var H6R,g9V,L3g,D1l,J_G,t4b,M8k;H6R="_";H6R+="v";g9V=this.stx.panels[this.panelName];if(!g9V){return;}L3g=this.name + H6R + (this.version || 0);if(X2.Drawing[L3g]){D1l=new X2.Drawing[L3g]();this.name=D1l.name;this.dimension=D1l.dimension;this.padding=D1l.padding;this.points=D1l.points;this.version=D1l.version;}J_G=-+"1095542851";L5l.D0J(7);t4b=-L5l.S40(0,"1790571903");M8k=2;for(var n16=1;L5l.U6$(n16.toString(),n16.toString().length,70654) !== J_G;n16++){this.setPoint(7,this.d0,this.v0,g9V.chart);L5l.H6P(57);var h4F=L5l.q7n(40,66,10,7);this.radians=Math.round(this.a - +"3") - Math.PI + h4F;L5l.H6P(28);M8k+=L5l.S40("2",32);}if(L5l.U6$(M8k.toString(),M8k.toString().length,58480) !== t4b){this.setPoint(0,this.d0,this.v0,g9V.chart);L5l.H6P(67);var G_R=L5l.S40(14,17,16,18,0);L5l.D0J(37);var A7z=L5l.q7n(17,4,15);this.radians=Math.round(this.a / G_R) * Math.PI / A7z;}};X2.Drawing.shape.prototype.reconstruct=function(o6n,C8x){this.stx=o6n;this.color=C8x.col;this.fillColor=C8x.fc;this.panelName=C8x.pnl;this.pattern=C8x.ptrn;this.lineWidth=C8x.lw;this.d0=C8x.d0;this.v0=C8x.v0;this.tzo0=C8x.tzo0;this.a=C8x.a;A2IFV.D0H();this.sx=C8x.sx;this.sy=C8x.sy;this.version=C8x.ver;this.adjust();};X2.Drawing.shape.prototype.serialize=function(){return {name:this.name,pnl:this.panelName,col:this.color,fc:this.fillColor,ptrn:this.pattern,lw:this.lineWidth,d0:this.d0,v0:this.v0,tzo0:this.tzo0,a:this.a,sx:this.sx,sy:this.sy,ver:this.version};};X2.Drawing.arrow=function(){var f8d=A2IFV;var S4I;S4I="a";S4I+="r";S4I+="row";this.name=S4I;this.version=1;this.dimension=[11,22];this.padding={left:0,right:0,top:11,bottom:0};f8d.a9S();f8d.H6P(1);this.points=[["M",3,+"21","L",7,21,(564,4203) > 2515?"880.62" * 1 >= 1127?"n":"L":(!![],0x183b),7,16,"L",10,16,5254 == (5441,6440)?+"9048" <= (863.64,+"6192")?!({}):+"4640" >= (7692,452)?"k":!![]:"L",5,11,(8270,462.42) != 5879?"L":(9070,8141) !== (3385,673.46)?(+"4030","513.35" - 0) >= (688.34,398.13)?0x120f:(288,0x1d99):2.80e+3,0,16,"L",f8d.S40(1,"3"),16,"L",f8d.S40(32,"3",f8d.H6P(40)),21]];;};X2.inheritsFrom(X2.Drawing.arrow,X2.Drawing.shape);X2.Drawing.getDrawingToolList=function(t$S){var j2m,m0d;j2m={};m0d={arrow_v0:!![],BaseTwoPoint:!!({}),fibonacci:!![],shape:!!({})};A2IFV.a9S();X2.extend(m0d,t$S);for(var v8S in X2.Drawing){if(!m0d[v8S] && X2.Drawing[v8S].prototype.render){j2m[new X2.Drawing[v8S]().name]=v8S;}}return j2m;};};A=a9f=>{var K0G,q$X;K0G="un";K0G+="defined";q$X=typeof _CIQ !== K0G?_CIQ:a9f.CIQ;q$X.EaseMachine=function(k2_,L8f,T8j,P8d){this.fc=k2_;A2IFV.D0H();this.ms=L8f;if(T8j || T8j === 0){this.reset(T8j,P8d);}};q$X.EaseMachine.prototype.reset=function(V72,Q6v){if(!V72 && V72 !== 0){V72=this.currentValues;}this.hasCompleted=![];this.running=![];this.okayToRun=!!({});A2IFV.D0J(68);this.useNameValuePairs=A2IFV.S40(typeof Q6v,"object");this.startTime=Date.now();A2IFV.D0H();if(this.useNameValuePairs){this.startValues=V72;this.endValues=Q6v;}else {this.startValues={default:V72};this.endValues={default:Q6v};}this.changeValues={};this.currentValues={};for(var n0q in this.startValues){this.changeValues[n0q]=this.endValues[n0q] - this.startValues[n0q];}};q$X.EaseMachine.prototype.next=function(){var J4f;J4f=Date.now();if(J4f >= this.startTime + this.ms){J4f=this.startTime + this.ms;this.hasCompleted=!!"1";this.running=!"1";}this.currentValues={};for(var J1T in this.changeValues){this.currentValues[J1T]=this.fc(J4f - this.startTime,this.startValues[J1T],this.changeValues[J1T],this.ms);}if(!this.useNameValuePairs){return this.currentValues["default"];}A2IFV.a9S();return this.currentValues;};q$X.EaseMachine.prototype.hasCompleted=!!1;q$X.EaseMachine.prototype.run=function(t2q,T70,d$A,N8U){var R7W;if(this.afid){cancelAnimationFrame(this.afid);}function h2I(){var E_7;R7W.afid=null;if(!R7W.okayToRun){return;}E_7=R7W.next();t2q(E_7);if(R7W.hasCompleted){return;}A2IFV.D0H();R7W.afid=requestAnimationFrame(h2I);}A2IFV.a9S();if(T70 || T70 === 0){this.reset(T70,d$A);}else if(d$A || d$A === 0){this.reset(this.currentValues,d$A);}R7W=this;this.running=!!({});if(N8U){this.afid=requestAnimationFrame(h2I);}else {h2I();}};q$X.EaseMachine.prototype.stop=function(){if(this.afid){cancelAnimationFrame(this.afid);}this.afid=null;this.okayToRun=!({});this.hasCompleted=!!1;this.running=!1;if(typeof this.useNameValuePairs == "undefined"){return {};}if(!this.useNameValuePairs){return this.currentValues["default"];}return this.currentValues;};if(q$X.ChartEngine.prototype.animations.zoom.isStub){A2IFV.H6P(1);q$X.ChartEngine.prototype.animations.zoom=new q$X.EaseMachine(Math.easeOutCubic,A2IFV.S40(1,"400"));}};A2IFV.a9S();G=t$b=>{var T27,x95;T27=typeof _CIQ !== "undefined"?_CIQ:t$b.CIQ;x95=function(){var B15=A2IFV;var J6d,o57,Y9B,v3U,i6f,m5X,V2J,T1j,z6d,H4L,Q7j,A8g,N7e,S_e,Q5O,o9c,T4n,O2f,i6X,n2v,P7D;J6d="\\";function G4X(){var Y5O,J_d;if(Math.hypot){return Math.hypot.apply(this,arguments);}Y5O=0;J_d=arguments.length;for(var c7v="0" << 0;c7v < J_d;c7v++){if(arguments[c7v] === Infinity || arguments[c7v] === -Infinity){return Infinity;}Y5O+=arguments[c7v] * arguments[c7v];}return Math.sqrt(Y5O);}function A0L(i0M){B15.a9S();return Math.sinh?Math.sinh(i0M):(Math.exp(i0M) - Math.exp(-i0M)) / +"2";}function B_L(X$o,a4l,a$n,N3T){this.type_=X$o;this.index_=a4l || 0;this.prio_=a$n || 0;B15.a9S();this.number_=N3T !== undefined && N3T !== null?N3T:0;this.toString=function(){B15.a9S();var M7j;switch(this.type_){case i6f:return this.number_;case m5X:case V2J:case T1j:return this.index_;case z6d:return "CALL";default:M7j="In";M7j+="va";M7j+="lid Toke";M7j+="n";return M7j;}};}J6d+="f";o57="\\";function j92(j5_){var X7W;j5_=Math.floor(j5_);X7W=j5_;while(j5_ > 1){B15.H6P(69);X7W=B15.q7n(X7W,--j5_);}return X7W;}function b59(F27,x7F){B15.H6P(1);return B15.S40(x7F,F27);}o57+="n";function A43(G$h){B15.D0H();if(Math.tanh){return Math.tanh(G$h);}if(G$h === Infinity){return 1;}if(G$h === -Infinity){return -1;}return (Math.exp(G$h) - Math.exp(-G$h)) / (Math.exp(G$h) + Math.exp(-G$h));}function U_l(H5E){u4l.prototype=H5E;function u4l(){}return new u4l();}function t2S(P1_,Y3i){return Boolean(P1_ && Y3i);}function S55(u_j,m_T){B15.H6P(70);return B15.S40(u_j,m_T);}function F3Q(S0B){return Math.atanh?Math.atanh(S0B):Math.log((+"1" + S0B) / (1 - S0B)) / 2;}Y9B="\\";function f33(i9_){return Math.cosh?Math.cosh(i9_):(Math.exp(i9_) + Math.exp(-i9_)) / 2;}function x8L(j5h,s93){B15.H6P(71);return B15.q7n(s93,j5h);}Y9B+="t";function X6t(c3Y,H8p){if(Object.prototype.toString.call(c3Y) != "[object Array]"){return [c3Y,H8p];}c3Y=c3Y.slice();B15.a9S();c3Y.push(H8p);return c3Y;}v3U="\\";v3U+="b";function i36(P$4,K6r){B15.H6P(72);B15.D0H();return B15.S40(K6r,P$4);}function s$R(h3U){B15.a9S();return Math.log(h3U) * Math.LOG10E;}i6f=0;m5X=1;V2J=2;function p9b(g47,e50){B15.H6P(68);return B15.S40(g47,e50);}function G_w(o7i){if(Math.trunc){return Math.trunc(o7i);}return o7i < 0?Math.ceil(o7i):Math.floor(o7i);}B15.H6P(21);T1j=B15.q7n("3",0);z6d=+"4";function U1G(E$Y){B15.H6P(15);var W6t=B15.q7n(3,0,2);return Math.random() * (E$Y || W6t);}function c5W(h69,A3J,Z5v){B15.D0H();return h69?A3J:Z5v;}H4L=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;Q7j=/[\\'\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;A8g={"\b":v3U,"\t":Y9B,"\n":o57,"\f":J6d,"\r":"\\r","'":"\\'","\\":"\\\\"};T27.extend(d7f.prototype,{simplify:function(h0Q){var K5R,R8r,H52,C0R,o2o,H3k,o__,f0J,U6E;h0Q=h0Q || ({});K5R=[];R8r=[];H3k=this.tokens.length;f0J=0;for(f0J=0;f0J < H3k;f0J++){o__=this.tokens[f0J];U6E=o__.type_;if(U6E === i6f){K5R.push(o__);}else if(U6E === T1j && (o__.index_ in h0Q)){o__=new B_L(i6f,0,0,h0Q[o__.index_]);K5R.push(o__);}else if(U6E === V2J && K5R.length > "1" << 64){C0R=K5R.pop();H52=K5R.pop();o2o=this.ops2[o__.index_];o__=new B_L(i6f,0,0,o2o(H52.number_,C0R.number_));K5R.push(o__);}else if(U6E === m5X && K5R.length > 0){H52=K5R.pop();o2o=this.ops1[o__.index_];o__=new B_L(i6f,+"0",0,o2o(H52.number_));K5R.push(o__);}else {while(K5R.length > 0){R8r.push(K5R.shift());}R8r.push(o__);}}while(K5R.length > 0){R8r.push(K5R.shift());}B15.D0H();return new d7f(R8r,U_l(this.ops1),U_l(this.ops2),U_l(this.functions));},substitute:function(a85,e3L){var v8O,s3g,u18,Y39,U68,X7D,r5Q,d08;if(!(e3L instanceof d7f)){e3L=new M9N().parse(String(e3L));}v8O=[];s3g=this.tokens.length;Y39=0;for(Y39="0" - 0;Y39 < s3g;Y39++){u18=this.tokens[Y39];U68=u18.type_;if(U68 === T1j && u18.index_ === a85){for(var P0J=0;P0J < e3L.tokens.length;P0J++){X7D=e3L.tokens[P0J];r5Q=new B_L(X7D.type_,X7D.index_,X7D.prio_,X7D.number_);v8O.push(r5Q);}}else {v8O.push(u18);}}d08=new d7f(v8O,U_l(this.ops1),U_l(this.ops2),U_l(this.functions));return d08;},evaluate:function(k1N){var k5Q,H0c,e$W,U$s,L2W,M6o,e4Z,W6o,J7p;k1N=k1N || ({});k5Q=[];L2W=this.tokens.length;B15.D0H();e4Z=0;for(e4Z=0;e4Z < L2W;e4Z++){M6o=this.tokens[e4Z];W6o=M6o.type_;if(W6o === i6f){k5Q.push(M6o.number_);}else if(W6o === V2J){e$W=k5Q.pop();H0c=k5Q.pop();U$s=this.ops2[M6o.index_];k5Q.push(U$s(H0c,e$W));}else if(W6o === T1j){if((M6o.index_ in k1N)){k5Q.push(k1N[M6o.index_]);}else if((M6o.index_ in this.functions)){k5Q.push(this.functions[M6o.index_]);}else {throw new Error("undefined variable: " + M6o.index_);}}else if(W6o === m5X){H0c=k5Q.pop();U$s=this.ops1[M6o.index_];k5Q.push(U$s(H0c));}else if(W6o === z6d){H0c=k5Q.pop();U$s=k5Q.pop();if(U$s.apply && U$s.call){if(Object.prototype.toString.call(H0c) == "[object Array]"){k5Q.push(U$s.apply(undefined,H0c));}else {k5Q.push(U$s.call(undefined,H0c));}}else {B15.H6P(0);throw new Error(B15.q7n(U$s," is not a function"));}}else {J7p="invalid Expressio";J7p+="n";throw new Error(J7p);}}if(k5Q.length > 1){throw new Error("invalid Expression (parity)");}return k5Q[+"0"];},toString:function(v3y){B15.D0H();var p$2,R8q,B5K,k6j,r$Y,w7s,N2l,j$p,M10;p$2=[];r$Y=this.tokens.length;N2l=0;for(N2l=0;N2l < r$Y;N2l++){w7s=this.tokens[N2l];j$p=w7s.type_;if(j$p === i6f){p$2.push(H_w(w7s.number_));}else if(j$p === V2J){B5K=p$2.pop();R8q=p$2.pop();k6j=w7s.index_;if(v3y && k6j == "^"){B15.D0J(73);p$2.push(B15.S40("Math.pow(",577.99 <= 5850?")":(454.61,5051) >= (9629,4660)?(588,8440) < (93.46,"2729" >> 64)?(3.86e+2,0x215e):!!"1":("2.14e+3" - 0,339.79),B5K,",",R8q));}else {B15.D0J(73);p$2.push(B15.S40("(",+"5089" == (9270,5280)?3522 <= (393.11,771.44)?(!!({}),71.68):"A":")",B5K,k6j,R8q));}}else if(j$p === T1j){p$2.push(w7s.index_);}else if(j$p === m5X){R8q=p$2.pop();k6j=w7s.index_;if(k6j === ((7492,"2110" - 0) > ("2366" - 0,8456)?(!![],"P"):"-")){B15.D0J(48);p$2.push(B15.S40(")",R8q,k6j,"("));}else {B15.D0J(48);p$2.push(B15.S40(2150 === 5150?(8765,2568) !== (134.43,848.98)?(4.56e+3,0x2602):("4.86e+2" ^ 0,5.58e+3):")",R8q,"(",k6j));}}else if(j$p === z6d){R8q=p$2.pop();k6j=p$2.pop();B15.D0J(48);p$2.push(B15.S40(")",R8q,(3763,899) == 5800?"j":(5300,4010) <= (667.49,4277)?+"454" != (9180,658.73)?"(":858.36:0x369,k6j));}else {M10="i";M10+="nval";M10+="id Expression";throw new Error(M10);}}if(p$2.length > 1){throw new Error("invalid Expression (parity)");}return p$2[0];},variables:function(){var E_f,J1y,r$b;E_f=this.tokens.length;J1y=[];for(var Y6r=0;Y6r < E_f;Y6r++){r$b=this.tokens[Y6r];if(r$b.type_ === T1j && J1y.indexOf(r$b.index_) == -+"1"){J1y.push(r$b.index_);}}return J1y;}},!!"1");M9N.parse=function(V_3){return new M9N().parse(V_3);};function d7f(J48,c9R,L4W,M7E){this.tokens=J48;this.ops1=c9R;this.ops2=L4W;B15.D0H();this.functions=M7E;}M9N.evaluate=function(D$6,H1G){B15.D0H();return M9N.parse(D$6).evaluate(H1G);};M9N.Expression=d7f;M9N.values={sin:Math.sin,cos:Math.cos,tan:Math.tan,asin:Math.asin,acos:Math.acos,atan:Math.atan,sinh:A0L,cosh:f33,tanh:A43,asinh:m8z,acosh:X$F,atanh:F3Q,sqrt:Math.sqrt,log:Math.log,lg:s$R,log10:s$R,abs:Math.abs,ceil:Math.ceil,floor:Math.floor,round:Math.round,trunc:G_w,random:U1G,fac:j92,exp:Math.exp,min:Math.min,max:Math.max,hypot:G4X,pyt:G4X,pow:Math.pow,atan2:Math.atan2,if:c5W,E:Math.E,PI:Math.PI};function R9N(o6F){B15.a9S();return -o6F;}B15.H6P(40);N7e=B15.q7n(0,1);function M9N(){var P12,j0u,J72;this.success=!({});B15.D0H();this.errormsg="";this.expression="";this.pos=+"0";this.tokennumber=0;this.tokenprio=+"0";P12=1200710508;j0u=-938172973;J72=2;for(var M9p=1;B15.U6$(M9p.toString(),M9p.toString().length,81280) !== P12;M9p++){this.tokenindex=1;this.tmpprio=6;this.ops1={sin:Math.sin,cos:Math.cos,tan:Math.tan,asin:Math.asin,acos:Math.acos,atan:Math.atan,sinh:A0L,cosh:f33,tanh:A43,asinh:m8z,acosh:X$F,atanh:F3Q,sqrt:Math.sqrt,log:Math.log,lg:s$R,log10:s$R,abs:Math.abs,ceil:Math.ceil,floor:Math.floor,round:Math.round,trunc:G_w,"-":R9N,exp:Math.exp};this.ops2={"+":M1y,"-":T4a,"*":b59,"/":Q96,"%":f_V,"^":Math.pow,",":X6t,"||":o_W,"==":p9b,"!=":i36,">":S55,"<":x8L,">=":G7L,"<=":p49,and:t2S,or:l7d};this.functions={random:U1G,fac:j92,min:Math.min,max:Math.max,hypot:G4X,pyt:G4X,pow:Math.pow,atan2:Math.atan2,if:c5W};J72+=2;}if(B15.Z2Z(J72.toString(),J72.toString().length,53036) !== j0u){B15.D0J(28);this.tokenindex=B15.S40("0",64);this.tmpprio=0;this.ops1={sin:Math.sin,cos:Math.cos,tan:Math.tan,asin:Math.asin,acos:Math.acos,atan:Math.atan,sinh:A0L,cosh:f33,tanh:A43,asinh:m8z,acosh:X$F,atanh:F3Q,sqrt:Math.sqrt,log:Math.log,lg:s$R,log10:s$R,abs:Math.abs,ceil:Math.ceil,floor:Math.floor,round:Math.round,trunc:G_w,"-":R9N,exp:Math.exp};this.ops2={"+":M1y,"-":T4a,"*":b59,"/":Q96,"%":f_V,"^":Math.pow,",":X6t,"||":o_W,"==":p9b,"!=":i36,">":S55,"<":x8L,">=":G7L,"<=":p49,and:t2S,or:l7d};this.functions={random:U1G,fac:j92,min:Math.min,max:Math.max,hypot:G4X,pyt:G4X,pow:Math.pow,atan2:Math.atan2,if:c5W};}this.consts={E:Math.E,PI:Math.PI};}function p49(U$V,z66){B15.H6P(74);return B15.q7n(U$V,z66);}B15.H6P(40);S_e=B15.S40(1,1);B15.H6P(40);Q5O=B15.S40(2,1);function T4a(c1u,C2D){B15.D0H();B15.H6P(7);return B15.S40(C2D,c1u);}function X$F(K6S){B15.a9S();return Math.acosh?Math.acosh(K6S):Math.log(K6S + Math.sqrt(K6S * K6S - 1));}function f_V(U77,k$j){var D3A,u7h,d6P;D3A=-1174419827;u7h=-1368956127;d6P=2;for(var Y6k=1;B15.U6$(Y6k.toString(),Y6k.toString().length,1489) !== D3A;Y6k++){B15.H6P(7);return B15.S40(k$j,U77);}if(B15.U6$(d6P.toString(),d6P.toString().length,54444) !== u7h){B15.H6P(7);return B15.S40(k$j,U77);}B15.H6P(75);return B15.q7n(U77,k$j);}B15.H6P(40);o9c=B15.q7n(3,1);function M1y(R8f,a6Q){return Number(R8f) + Number(a6Q);}B15.D0J(40);T4n=B15.S40(4,1);B15.H6P(76);O2f=B15.q7n(5,"1");function G7L(t9p,G7G){B15.H6P(77);return B15.q7n(G7G,t9p);}function m8z(W9B){B15.a9S();if(Math.asinh){return Math.asinh(W9B);}if(W9B === -Infinity){return W9B;}return Math.log(W9B + Math.sqrt(W9B * W9B + 1));}B15.D0J(40);i6X=B15.S40(6,1);B15.D0J(78);n2v=B15.q7n(1,"7",7);function l7d(X2o,c2P){return Boolean(X2o || c2P);}function H_w(h2v){var y$4;y$4="st";B15.a9S();y$4+="ring";if(typeof h2v === y$4){Q7j.lastIndex=0;return Q7j.test(h2v)?(957 == 2548?987.85:"'") + h2v.replace(Q7j,function(F1Q){var J6p,l3T;J6p="st";J6p+="rin";J6p+="g";l3T=A8g[F1Q];return typeof l3T === J6p?l3T:"\\u" + ("0000" + F1Q.charCodeAt(0).toString(16)).slice(-4);}) + ((315,4991) === (8570,301.83)?"0x2578" ^ 0:"'"):"'" + h2v + (+"339.92" <= 894.46?"'":908 >= 1569?("Z",868.87):"0x4fd" ^ 0);}return h2v;}B15.D0J(40);P7D=B15.S40(8,1);function Q96(c_1,e4D){B15.D0J(14);B15.a9S();return B15.q7n(e4D,c_1);}function o_W(p$1,P3V){B15.a9S();B15.D0J(37);return B15.q7n(P3V,"",p$1);}T27.extend(M9N.prototype,{parse:function(C21){var F6Q,q2z,B4S,m0k,X0J,c8e,B65,R7g,u2T;this.errormsg="";this.success=!!1;F6Q=[];q2z=[];this.tmpprio=0;B15.H6P(79);B4S=B15.S40(Q5O,o9c,N7e,i6X);m0k=+"0";this.expression=C21;B15.D0J(10);this.pos=B15.S40("0",0);while(this.pos < this.expression.length){if(this.isOperator()){if(this.isSign() && B4S & i6X){if(this.isNegativeSign()){this.tokenprio=2;this.tokenindex=5230 >= +"878"?"-":(6060,4330) <= (721.7,8789)?("2.42e+3" * 1,1.54e+3):("x",!!0);m0k++;this.addfunc(q2z,F6Q,m5X);}B15.D0J(79);B4S=B15.S40(Q5O,o9c,N7e,i6X);}else if(this.isComment()){}else {if((B4S & S_e) === ("0" ^ 0)){this.error_parsing(this.pos,"unexpected operator");}m0k+=2;this.addfunc(q2z,F6Q,V2J);B15.D0J(79);B4S=B15.S40(Q5O,o9c,N7e,i6X);}}else if(this.isNumber()){if((B4S & N7e) === +"0"){this.error_parsing(this.pos,"unexpected number");}X0J=new B_L(i6f,0,0,this.tokennumber);q2z.push(X0J);B15.D0J(80);B4S=B15.S40(O2f,T4n,S_e);}else if(this.isString()){if((B4S & N7e) === 0){c8e="une";c8e+="xpected s";c8e+="tring";this.error_parsing(this.pos,c8e);}B15.D0J(7);X0J=new B_L(i6f,0,B15.q7n(0,"0"),this.tokennumber);q2z.push(X0J);B15.H6P(80);B4S=B15.q7n(O2f,T4n,S_e);}else if(this.isLeftParenth()){if((B4S & o9c) === +"0"){this.error_parsing(this.pos,'unexpected "("');}if(B4S & n2v){m0k+=2;this.tokenprio=-2;this.tokenindex=-1;this.addfunc(q2z,F6Q,z6d);}B15.D0J(81);B4S=B15.q7n(N7e,i6X,P7D,o9c,Q5O);}else if(this.isRightParenth()){if(B4S & P7D){X0J=new B_L(i6f,0,0,[]);q2z.push(X0J);}else if((B4S & T4n) === 0){this.error_parsing(this.pos,'unexpected ")"');}B15.H6P(81);B4S=B15.q7n(S_e,o9c,n2v,T4n,O2f);}else if(this.isComma()){if((B4S & O2f) === 0){this.error_parsing(this.pos,'unexpected ","');}this.addfunc(q2z,F6Q,V2J);m0k+=2;B15.D0J(79);B4S=B15.q7n(Q5O,o9c,N7e,i6X);}else if(this.isConst()){if((B4S & N7e) === ("0" ^ 0)){this.error_parsing(this.pos,"unexpected constant");}B65=new B_L(i6f,0,0,this.tokennumber);q2z.push(B65);B15.H6P(80);B4S=B15.S40(O2f,T4n,S_e);}else if(this.isOp2()){if((B4S & Q5O) === 0){this.error_parsing(this.pos,"unexpected function");}this.addfunc(q2z,F6Q,V2J);m0k+=2;B4S=o9c;}else if(this.isOp1()){if((B4S & Q5O) === "0" - 0){this.error_parsing(this.pos,"unexpected function");}this.addfunc(q2z,F6Q,m5X);m0k++;B4S=o9c;}else if(this.isVar()){if((B4S & N7e) === 0){this.error_parsing(this.pos,"unexpected variable");}R7g=new B_L(T1j,this.tokenindex,0,0);q2z.push(R7g);B15.H6P(81);B4S=B15.S40(S_e,o9c,n2v,T4n,O2f);}else if(this.isWhite()){}else {if(this.errormsg === ""){this.error_parsing(this.pos,"unknown character");}else {this.error_parsing(this.pos,this.errormsg);}}}if(this.tmpprio < 0 || this.tmpprio >= 10){this.error_parsing(this.pos,'unmatched "()"');}while(F6Q.length > 0){u2T=F6Q.pop();q2z.push(u2T);}if(m0k + 1 !== q2z.length){this.error_parsing(this.pos,"parity");}return new d7f(q2z,U_l(this.ops1),U_l(this.ops2),U_l(this.functions));},evaluate:function(b8d,i93){B15.a9S();return this.parse(b8d).evaluate(i93);},error_parsing:function(d3t,R4i){var J_6,h$k,v4O,E_v,Z8f;J_6=1455174355;h$k=1895193469;v4O=2;for(var u$6=1;B15.U6$(u$6.toString(),u$6.toString().length,98541) !== J_6;u$6++){E_v="]:";E_v+=" ";this.success=!!1;B15.H6P(82);this.errormsg=B15.S40("]: ",d3t,R4i,E_v);this.column=d3t;throw new Error(this.errormsg);v4O+=2;}if(B15.U6$(v4O.toString(),v4O.toString().length,+"80487") !== h$k){Z8f="]";Z8f+=":";Z8f+=" ";this.success=!!0;B15.H6P(48);this.errormsg=B15.q7n(R4i,Z8f,d3t,"parse error [column ");this.column=d3t;throw new Error(this.errormsg);}},addfunc:function(k_f,h1h,J4N){var Z3r;Z3r=new B_L(J4N,this.tokenindex,this.tokenprio + this.tmpprio,0);while(h1h.length > 0){if(Z3r.prio_ <= h1h[h1h.length - 1].prio_){k_f.push(h1h.pop());}else {break;}}B15.D0H();h1h.push(Z3r);},isNumber:function(){var A1v,B7Y,A1y;A1v=!!0;B7Y="";while(this.pos < this.expression.length){A1y=this.expression.charCodeAt(this.pos);if(A1y >= "48" - 0 && A1y <= "57" - 0 || A1y === 46){B7Y+=this.expression.charAt(this.pos);this.pos++;this.tokennumber=parseFloat(B7Y);A1v=!"";}else {break;}}return A1v;},unescape:function(B_y,S$w){var w$0,B3M,c0k,j27,I_m;w$0=[];B3M=!!"";for(var E1U=0;E1U < B_y.length;E1U++){c0k=B_y.charAt(E1U);if(B3M){switch(c0k){case (37.85,"118.52" - 0) === 320?("7.05e+3" | 10,3.49e+3):(245,451.38) != 6250?986 >= (270.15,9100)?(3.55e+3,407.12):"'":3.58e+3:w$0.push("'");break;case (8750,50.26) === 7944?(0xb4f,!!({})):"\\":w$0.push((3578,3429) != (+"5498",+"4194")?"\\":(0x13e0,2.86e+3));break;case (3800,293.88) >= (+"3704",799.04)?+"2.47e+3":"/":w$0.push(2590 > +"4190"?(69.48,8880) == (5856,5060)?(0xc46,!!({})):(829.42,"G"):"/");break;case 28.31 !== (9090,814.49)?"b":4286 == (5290,5564)?(936.89,520.13):"O":w$0.push((3830,9620) <= (651.61,+"157.03")?(![],+"362.89"):1329 < 764.56?(0x329,301.57):426.29 >= (6046,9210)?9.43e+3:"\b");break;case "f":w$0.push("\f");break;case 5710 != 145?"n":(6.76e+3,0xbfc):w$0.push("\n");break;case ("8479" | 20) == (7740,5590)?"L":(+"536.7",653.81) === 98.92?(+"758.96","x"):"r":w$0.push((+"9510",846.47) != (2340,8460)?302 !== 2490?"\r":![]:("z",3.89e+3));break;case ("7550" >> 0,355.35) !== (2099,973)?"t":("z",!![]):w$0.push(6831 != "8133" * 1?"\t":+"393.51");break;case "u":j27=parseInt(B_y.substring(E1U + 1,E1U + 5),16);w$0.push(String.fromCharCode(j27));E1U+=4;break;default:I_m="Il";I_m+="legal escape sequen";I_m+="ce: '\\";B15.D0J(0);throw this.error_parsing(B15.q7n(S$w,E1U),B15.q7n((3.44,115) == (723.92,230.28)?!!"":"'",I_m,c0k,B15.H6P(37)));}B3M=![];}else {if(c0k == (278.88 != 4040?"\\":"Q")){B3M=!![];}else {w$0.push(c0k);}}}B15.a9S();return w$0.join("");},isString:function(){var P5K,C1U,g09,Z99;P5K=![];C1U="";g09=this.pos;if(this.pos < this.expression.length && this.expression.charAt(this.pos) == ((45.09,554.4) == (2949,+"798.41")?(5860,663.56) > (842.97,"244.92" * 1)?("262.66" - 0,6.14e+3):!!"":"'")){this.pos++;while(this.pos < this.expression.length){Z99=this.expression.charAt(this.pos);if(Z99 != (9920 > (4030,5798)?"'":8990 !== 6515?9.25e+3:(![],"355" >> 32)) || C1U.slice(-("1" >> 0)) == (("6720" >> 0,527.72) != 3981?"\\":(0x2435,!({})))){C1U+=this.expression.charAt(this.pos);this.pos++;}else {this.pos++;this.tokennumber=this.unescape(C1U,g09);P5K=!!({});break;}}}B15.D0H();return P5K;},isConst:function(){var N9H,f3j;for(var i7l in this.consts){if(!![]){f3j=i7l.length;N9H=this.expression.substr(this.pos,f3j);if(i7l === N9H){this.tokennumber=this.consts[i7l];this.pos+=f3j;return !![];}}}return !"1";},isOperator:function(){var Y37,H0S,y1B;Y37=this.expression.charCodeAt(this.pos);if(Y37 === 43){B15.H6P(10);this.tokenprio=B15.q7n("2",2);this.tokenindex=(9725,4010) != 3512?(398.15,62) !== +"516.69"?"+":"S":(270.23,"A");}else if(Y37 === 45){B15.D0J(10);this.tokenprio=B15.q7n("2",2);this.tokenindex="-";}else if(Y37 === ("62" | 16)){if(this.expression.charCodeAt(this.pos + 1) === 61){this.pos++;this.tokenprio=1;this.tokenindex=">=";}else {this.tokenprio=1;this.tokenindex=470.9 !== 5910?">":9290 < 3390?("u",972.02):3726 == 2920?![]:(!!({}),0x1f8f);}}else if(Y37 === +"60"){if(this.expression.charCodeAt(this.pos + 1) === 61){H0S="<";H0S+="=";this.pos++;this.tokenprio=1;this.tokenindex=H0S;}else {this.tokenprio=1;this.tokenindex="<";}}else if(Y37 === 124){if(this.expression.charCodeAt(this.pos + ("1" >> 64)) === 124){this.pos++;this.tokenprio=1;this.tokenindex="||";}else {return !({});}}else if(Y37 === 61){if(this.expression.charCodeAt(this.pos + 1) === 61){this.pos++;B15.H6P(28);this.tokenprio=B15.S40("1",64);this.tokenindex="==";}else {return !1;}}else if(Y37 === +"33"){if(this.expression.charCodeAt(this.pos + 1) === "61" << 64){this.pos++;this.tokenprio=+"1";this.tokenindex="!=";}else {return ![];}}else if(Y37 === +"97"){if(this.expression.charCodeAt(this.pos + 1) === 110 && this.expression.charCodeAt(this.pos + 2) === 100){y1B="a";y1B+="n";y1B+="d";this.pos++;this.pos++;this.tokenprio=+"0";this.tokenindex=y1B;}else {return ![];}}else if(Y37 === +"111"){if(this.expression.charCodeAt(this.pos + 1) === 114){this.pos++;this.tokenprio=0;this.tokenindex="or";}else {return !!"";}}else if(Y37 === 42 || Y37 === 8729 || Y37 === +"8226"){this.tokenprio=3;this.tokenindex=787.94 <= 1700?"*":(9325,"4713" ^ 0) != (525.21,597.88)?295.04 == (4190,872.46)?358.60:(0x1ff4,480.67):!!1;}else if(Y37 === 47){this.tokenprio=4;this.tokenindex=1190 < (895.92,1640)?"/":(9240,2750) === "4670" >> 32?(737.81,"2" - 0):"N";}else if(Y37 === 37){this.tokenprio=4;this.tokenindex=(7020,"639" | 64) === (4290,"2469" * 1)?1620 != (+"1810",976.99)?(8837,7768) == 411?(32.98,0x1889):!![]:(0x182c,+"0x25b6"):"%";}else if(Y37 === 94){this.tokenprio=5;this.tokenindex=("492.13" - 0,3226) < "9190" * 1?"^":(7880,"9120" << 0) == 485.83?(415.82,5.12e+3):5.14e+2;}else {return !"1";}B15.a9S();this.pos++;return !![];},isSign:function(){var t27;B15.a9S();t27=this.expression.charCodeAt(this.pos - 1);if(t27 === 45 || t27 === 43){return !!"1";}return !({});},isPositiveSign:function(){var A0a;A0a=this.expression.charCodeAt(this.pos - 1);if(A0a === 43){return !!({});}B15.D0H();return !!0;},isNegativeSign:function(){B15.D0H();var L4C;L4C=this.expression.charCodeAt(this.pos - 1);if(L4C === 45){return !!"1";}return ![];},isLeftParenth:function(){var t1l;t1l=this.expression.charCodeAt(this.pos);if(t1l === 40){this.pos++;this.tmpprio+=10;return !!1;}B15.D0H();return !({});},isRightParenth:function(){var E38;E38=this.expression.charCodeAt(this.pos);if(E38 === 41){this.pos++;this.tmpprio-=10;return !![];}return ![];},isComma:function(){var d89;d89=this.expression.charCodeAt(this.pos);B15.D0H();if(d89 === 44){this.pos++;this.tokenprio=-1;this.tokenindex=777 <= (494.72,+"5153")?(2600,928.51) <= 576.46?(746.44,!!"1"):",":("95.47" - 0,!!"1");return !!({});}return !({});},isWhite:function(){var M5b;B15.a9S();M5b=this.expression.charCodeAt(this.pos);if(M5b === 32 || M5b === 9 || M5b === 10 || M5b === 13){this.pos++;return !!({});}return !({});},isOp1:function(){var g0Z,f3g;g0Z="";for(var j9M=this.pos;j9M < this.expression.length;j9M++){f3g=this.expression.charAt(j9M);if(f3g.toUpperCase() === f3g.toLowerCase()){if(j9M === this.pos || f3g != ((1724,1180) === (199.29,411.31)?(!1,+"0x279"):"_") && (f3g < ("46" << 32 == ("4740" | 0,157.15)?("8924" ^ 0,6050) >= 792.99?814.41:(+"745.44",416.75):"0") || f3g > (3754 != (3920,919.03)?1503 >= 973.9?"9":(8.56e+3,"L"):3.08e+3))){break;}}g0Z+=f3g;}if(g0Z.length > 0 && (g0Z in this.ops1)){this.tokenindex=g0Z;this.tokenprio=5;this.pos+=g0Z.length;return !"";}return ![];},isOp2:function(){var B7_,E_Y;B7_="";for(var e5U=this.pos;e5U < this.expression.length;e5U++){E_Y=this.expression.charAt(e5U);if(E_Y.toUpperCase() === E_Y.toLowerCase()){if(e5U === this.pos || E_Y != (5411 < +"1990"?2224 > 9490?(7.82e+3,!1):("6" >> 64,"1330" | 0) !== (1480,5863)?(562.38,!""):(6.57e+3,"a"):"_") && (E_Y < ((4790,1083) != (2691,974)?"0":(+"5.13e+3",0xd43)) || E_Y > ((5990,1646) !== (8000,986.06)?"9":(6.41e+3,!!({}))))){break;}}B7_+=E_Y;}if(B7_.length > 0 && (B7_ in this.ops2)){this.tokenindex=B7_;this.tokenprio=5;this.pos+=B7_.length;return !!1;}return !!0;},isVar:function(){var P78,b6O;P78="";for(var n9L=this.pos;n9L < this.expression.length;n9L++){b6O=this.expression.charAt(n9L);if(b6O.toUpperCase() === b6O.toLowerCase()){if(n9L === this.pos || b6O != (3910 !== 631.56?(8160,+"633.27") >= (3102,942)?7274 >= 243.91?(620.04,0x22ef):(!({}),2.23e+3):"_":+"7.83e+3") && (b6O < "0" || b6O > "9")){break;}}P78+=b6O;}if(P78.length > 0){this.tokenindex=P78;this.tokenprio=4;this.pos+=P78.length;return !![];}return !({});},isComment:function(){var G5Z,o6S;B15.D0H();G5Z=this.expression.charCodeAt(this.pos - 1);if(G5Z === 47 && this.expression.charCodeAt(this.pos) === 42){o6S="*";o6S+="/";B15.D0J(83);var L$m=B15.q7n(15,598,1,40,1);this.pos=this.expression.indexOf(o6S,this.pos) + L$m;if(this.pos === 1){this.pos=this.expression.length;}return !![];}return !!0;}},!!"1");return M9N;};T27.computeEquationChart=function(e4z,d1O){var N9E=A2IFV;var z9W,w2I,j0F,v7C,S8r,P0p,T2C,U0Z,B1l,q2k,K4z,I_C,e15,L1w,l4T,L9G,V6D,N59,h4Y,e0c,L$5;e4z=e4z.replace(/[:]/,(230.82,266.12) < ("3130" * 1,263.01)?(0x240,1.94e+3):"/");N9E.H6P(7);z9W=N9E.S40(0,"0");for(var F$3 in d1O){w2I="\\$";w2I+="&";j0F=new RegExp("\\[" + F$3.replace(/\[/g,"\\[").replace(/\]/g,"\\]").replace(/\$/g,"\\$").replace(/\^/g,"\\^").replace(/[+\-*/%()]/g,w2I) + "\\]",("854.64" * 1,"532.39" * 1) < 8500?"g":(!({}),"j"));N9E.D0J(0);e4z=e4z.replace(j0F,N9E.S40("symbol",z9W));z9W++;}v7C=x95().parse(e4z);S8r=[];P0p={};T2C=0;B1l=null;q2k=!!0;function n5F(){var L_o,L7N;L_o=null;L7N=null;for(var m$M in P0p){if(!L7N){L7N=P0p[m$M];}else if(P0p[m$M].d.getTime() < L7N.d.getTime()){L_o=L7N=P0p[m$M];}else if(P0p[m$M].d.getTime() > L7N.d.getTime()){L_o=L7N;}}if(L_o){if(!b_q(L_o)){return 0;}N9E.H6P(7);return -N9E.q7n(0,"1");}return 1;}K4z=[];for(F$3 in d1O){I_C={sym:F$3,map:d1O[F$3]};if(d1O[F$3]){K4z.unshift(I_C);}else {K4z.push(I_C);}}for(var B89=0;B89 < K4z.length;B89++){e15=K4z[B89];P0p[e15.sym]={i:0,s:e15.sym};if(e15.map){T2C++;U0Z=e15.map[0];}else if(T2C == 1){q2k=e15.sym;}if(!U0Z.DT){U0Z.DT=T27.strToDateTime(U0Z.Date);}P0p[e15.sym].d=U0Z.DT;if(!B1l){B1l=P0p[e15.sym];}}N9E.D0J(84);L1w=N9E.q7n(T2C,0);l4T=T2C == "1" - 0 && e4z.indexOf("%") == -("1" | 1);a:while(!0){L9G=n5F();if(!L9G)break;if(L9G == 1){if(q2k){N59=d1O[B1l.s][B1l.i][q2k];if(N59 && (N59.Close || N59.Close === 0)){N59=N59.Close;}h4Y=v7C.evaluate({symbol0:d1O[B1l.s][B1l.i].Close,symbol1:N59});h4Y=Number(h4Y.toFixed(8));V6D={DT:B1l.d,Close:h4Y,Adj_Close:h4Y};V6D[B1l.s]=d1O[B1l.s][B1l.i].Close;if(!isNaN(h4Y) && h4Y != Infinity){S8r.push(V6D);}}else if(L1w){e0c=v7C.evaluate({});N9E.D0J(37);T27.alert(N9E.S40(e0c,e4z,(5388,553.67) != (273.53,8900)?"=":+"4707" != (3870,7099)?("0x1a65" >> 32,0x14fd):(4.64e+3,"342.17" * 1)));throw {name:"NoException",message:""};}else {z9W=0;L$5={Adj_Close:{},Close:{},Open:{},High:{},Low:{},Volume:{}};for(F$3 in d1O){for(var t9D in L$5){N9E.H6P(0);L$5[t9D][N9E.S40("symbol",z9W)]=d1O[F$3][P0p[F$3].i][t9D];}z9W++;}V6D={DT:B1l.d};V6D.Adj_Close=v7C.evaluate(L$5.Adj_Close);V6D.Close=v7C.evaluate(L$5.Close);V6D.Open=v7C.evaluate(L$5.Open);V6D.Volume=v7C.evaluate(L$5.Volume);if(isNaN(V6D.Volume)){V6D.Volume=+"0";}if(l4T){V6D.High=v7C.evaluate(L$5.High);V6D.Low=v7C.evaluate(L$5.Low);}else {V6D.High=Math.max(V6D.Open,V6D.Close);V6D.Low=Math.min(V6D.Open,V6D.Close);}if(!isNaN(V6D.Close) && V6D.Close != Infinity){S8r.push(V6D);}if(!isNaN(V6D.High)){V6D.High=Number(V6D.High.toFixed(8));}if(!isNaN(V6D.Low)){V6D.Low=Number(V6D.Low.toFixed(8));}if(!isNaN(V6D.Open)){V6D.Open=Number(V6D.Open.toFixed(8));}if(!isNaN(V6D.Close)){V6D.Close=Number(V6D.Close.toFixed(8));}if(!isNaN(V6D.Adj_Close)){V6D.Adj_Close=Number(V6D.Adj_Close.toFixed(8));}else {V6D.Adj_Close=V6D.Close;}}for(F$3 in d1O){if(!b_q(P0p[F$3]))break a;}}}function b_q(A2e){A2e.i++;if(d1O[A2e.s]){if(A2e.i >= d1O[A2e.s].length){N9E.D0J(28);return N9E.q7n("0",32);}U0Z=d1O[A2e.s][A2e.i];}if(!U0Z.DT){U0Z.DT=T27.strToDateTime(U0Z.Date);}A2e.d=U0Z.DT;return 1;}return S8r;};};g=D21=>{var q9a=A2IFV;var b1j,D2j,I35,i25,i$m,z7E;b1j="e";b1j+="n";D2j=+"469093628";I35=-944710622;q9a.a9S();i25=2;for(var o03=1;q9a.U6$(o03.toString(),o03.toString().length,29353) !== D2j;o03++){i$m="und";i$m+="ef";i$m+="ined";z7E=typeof _CIQ !== i$m?_CIQ:D21.CIQ;q9a.D0J(7);i25+=q9a.q7n(0,"2");}if(q9a.U6$(i25.toString(),i25.toString().length,84834) !== I35){z7E=!_CIQ === ""?_CIQ:D21.CIQ;}z7E.ChartEngine.prototype.setLocale=function(n0T,x0g){var m25,B5p,W_N,f0l,T8e,R2Q,j0t,F5F,i9I,G0c;m25="nume";m25+="r";m25+="ic";B5p="n";B5p+="umeric";W_N="2-";W_N+="d";W_N+="igit";f0l="2-";f0l+="di";f0l+="gi";f0l+="t";T8e="2";T8e+="-digit";R2Q="h";R2Q+="23";if(typeof Intl == "undefined"){return;}if(this.locale != n0T){this.locale=n0T;}else {return;}F5F=this.internationalizer={};F5F.hourMinute=new Intl.DateTimeFormat(this.locale,{hour:"numeric",minute:"numeric",hourCycle:"h23"});F5F.hourMinuteSecond=new Intl.DateTimeFormat(this.locale,{hour:"numeric",minute:"numeric",second:"numeric",hourCycle:R2Q});F5F.mdhm=new Intl.DateTimeFormat(this.locale,{year:T8e,month:"2-digit",day:"2-digit",hour:f0l,minute:W_N});F5F.monthDay=new Intl.DateTimeFormat(this.locale,{month:"numeric",day:B5p});F5F.yearMonthDay=new Intl.DateTimeFormat(this.locale,{year:"numeric",month:"numeric",day:"numeric"});F5F.yearMonth=new Intl.DateTimeFormat(this.locale,{year:"numeric",month:m25});F5F.month=new Intl.DateTimeFormat(this.locale,{month:"short"});F5F.numbers=new Intl.NumberFormat(this.locale);F5F.priceFormatters=[];if(!x0g){x0g=8;}for(j0t=0;j0t < x0g + +"1";j0t++){F5F.priceFormatters.push(new Intl.NumberFormat(this.locale,{maximumFractionDigits:j0t,minimumFractionDigits:j0t}));}for(j0t=0;j0t < +"5";j0t++){i9I=j0t;G0c=j0t;if(!j0t){i9I="";G0c=2;}q9a.H6P(0);F5F[q9a.q7n("percent",i9I)]=new Intl.NumberFormat(this.locale,{style:"percent",minimumFractionDigits:G0c,maximumFractionDigits:G0c});}if(z7E.I18N.createMonthArrays){z7E.I18N.createMonthArrays(this,F5F.month,this.locale);}};z7E.I18N=function(){};z7E.I18N.hereDoc=function(z0L){return z0L.toString().replace(/^[^/]+\/\*!?/,"").replace(/\*\/[^/]+$/,"");};z7E.I18N.language=b1j;z7E.I18N.longMonths={zh:!![]};z7E.I18N.reverseColorsByLocale={zh:!![],ja:!!1};z7E.I18N.findAllTextNodes=function(d0Y){q9a.a9S();var N3H,j2e,o95,o17,T5Z,d_e,o7F,v2Y,R2r,k71,E6_,Z0j,o5n,r$F,I1E,q$H,N1i,K1J,v8D,r3r;if(!d0Y){d0Y=document.body;}if(d0Y == document.body){if(!document.querySelector(".ciq_stashed_texts")){N3H="input,t";N3H+="extarea,.editable_content";j2e=document.createElement("div");j2e.className="ciq_stashed_texts";j2e.style.display="none";d0Y.appendChild(j2e);o95=document.querySelectorAll(N3H);for(var q9Y=+"0";q9Y < o95.length;q9Y++){o17=o95[q9Y].getAttribute("placeholder");if(o17){T5Z=j2e.appendChild(document.createElement("translate"));T5Z.setAttribute("original",o17);T5Z.placeholderFor=o95[q9Y];T5Z.appendChild(document.createTextNode(o17));}}}}d_e=document.createTreeWalker(d0Y,NodeFilter.SHOW_TEXT,null,![]);o7F=d_e.nextNode();v2Y=new RegExp("^\\s*$");R2r=new RegExp("\n|\t|\f",(742,9370) > 469.5?"g":6.36e+3);k71={};E6_={SCRIPT:!0,STYLE:!!({}),TEXTAREA:!![]};while(o7F){Z0j=o7F.nodeValue;if(!v2Y.test(Z0j)){o5n=o7F.parentNode;r$F=o7F.nextSibling;I1E=o5n.tagName;if(!E6_[I1E]){if(I1E != "TRANSLATE"){q$H="transl";q$H+="a";q$H+="te";N1i=document.createElement(q$H);N1i.setAttribute("original",Z0j);N1i.appendChild(o7F);o5n.insertBefore(N1i,r$F);}else {K1J="or";K1J+="i";K1J+="gi";K1J+="nal";Z0j=o5n.getAttribute(K1J);}if(R2r.test(Z0j)){Z0j=Z0j.replace(R2r,"");}if(!k71[Z0j]){k71[Z0j]=[];}k71[Z0j].push(o7F);}}o7F=d_e.nextNode();}if(d0Y == document.body){v8D=z7E.Studies?z7E.Studies.studyLibrary:null;if(v8D){for(var j6_ in v8D){if(k71[j6_] === null){k71[j6_]=[];}r3r=v8D[j6_];if(r3r.inputs){for(var b8I in r3r.inputs){if(!k71[b8I]){k71[b8I]=[];}}}if(r3r.outputs){for(var S1V in r3r.outputs){if(!k71[S1V]){k71[S1V]=[];}}}}}}return k71;};z7E.I18N.missingWordList=function(m3C){var e3t,N_V,G$n,U51,W7_,Y8l,e5k,m4H,D55,C4n;e3t="Y";e3t+="-";e3t+="Axi";e3t+="s";N_V="Sh";N_V+="ow Z";N_V+="o";N_V+="nes";if(!m3C){m3C=z7E.I18N.language;}G$n=z7E.I18N.findAllTextNodes();U51={};W7_=z7E.I18N.wordLists[m3C];if(!W7_){W7_={};}Y8l=function(G$z){q9a.a9S();var a5f;a5f="u";a5f+="ndefin";a5f+="ed";if(typeof W7_[G$z] == a5f){U51[G$z]="";}};for(var s7K in G$n){Y8l(s7K);}if(!(z7E.Studies && z7E.Studies.studyLibrary)){return U51;}for(var C7e in z7E.Studies.studyLibrary){e5k=z7E.Studies.studyLibrary[C7e];Y8l(e5k.name);for(var h_k in e5k.inputs){D55="[object Ar";D55+="ray]";C4n="[";C4n+="object String]";Y8l(h_k);m4H=e5k.inputs[h_k];switch(Object.prototype.toString.call(m4H)){case C4n:Y8l(m4H);break;case D55:for(var o_A=0;o_A < m4H.length;++o_A){Y8l(m4H[o_A]);}break;}}for(var U67 in e5k.outputs){Y8l(U67);}}Y8l(N_V);Y8l("OverBought");Y8l("OverSold");Y8l("Panel");Y8l("Show as Underlay");Y8l(e3t);Y8l("Invert Y-Axis");return U51;};z7E.I18N.printableMissingWordList=function(o9l){var v7S;v7S=JSON.stringify(z7E.I18N.missingWordList(o9l));v7S=v7S.replace(/","/g,'",\n"');return v7S;};z7E.I18N.translateUI=function(Z8x,u8z){var d8P,y0v,A0x,Z7T,q2b,I0h,k8L,a8l,Q$t;if(Z8x == "pu"){Z8x="pt";}q9a.a9S();if(!z7E.I18N.wordLists){return;}if(!Z8x){Z8x=z7E.I18N.language;}d8P=z7E.I18N.findAllTextNodes(u8z);y0v=z7E.I18N.wordLists[Z8x];if(!y0v){return;}for(var h3o in d8P){A0x=z7E.I18N.translateSections(h3o,y0v);Z7T=d8P[h3o];for(var q55=0;q55 < Z7T.length;q55++){q2b="origi";q2b+="nal";I0h=Z7T[q55];k8L=I0h.parentNode;a8l=k8L.getAttribute(q2b);if(A0x === ((3950,+"1710") !== (5300,+"839.92")?(1478,526.78) > (5168,7280)?"E":+"5510" === 5139?!![]:",":!"") || !A0x){A0x=a8l;}Q$t=k8L.placeholderFor;if(Q$t){Q$t.placeholder=A0x;}else {I0h.data=A0x;}}}};z7E.I18N.translate=function(s3Y,O8O){var M9K,J2g;if(!O8O){O8O=z7E.I18N.language;}if(!z7E.I18N.wordLists){console.log("Must include translations.js in order to use CIQ.I18N.translate()");return s3Y;}M9K=z7E.I18N.wordLists[O8O];J2g=null;if(M9K){J2g=z7E.I18N.translateSections(s3Y,M9K) || s3Y;}return J2g === (4030 === 5711?("4350" - 0,+"1230") < 5220?4960 == ("1846" | 20)?("A","i"):"u":(!!"1","g"):",")?s3Y:J2g;};z7E.I18N.translateSections=function(m5l,T4C){q9a.a9S();var B_7,q5_;B_7=4600 != 794.82?"\u200c":(1560,"62" ^ 0) === (+"706",880.22)?"g":(+"400.74","29.89" * 1) == 415?+"0x1a2f":(560.73,302.60);if(typeof m5l == "string" && m5l.indexOf(B_7) != -+"1"){q9a.D0J(37);m5l=m5l.replace(/([(),])/g,q9a.q7n(B_7,B_7,"$1"));q5_=m5l.split(B_7);q5_.forEach(function(E42,T2o,f8c){var v40,g9H;q9a.a9S();v40=E42.match(/^(\s*).*\S(\s*)$/);g9H=T4C[E42.trim()];if(g9H){if(v40){q9a.D0J(52);var P$f=q9a.S40(0,1,2);g9H=v40[+"1"] + g9H + v40[P$f];}f8c[T2o]=g9H;}});return q5_.join("");}return T4C[m5l];};z7E.I18N.convertCSV=function(z6D){var s6o,K2b,K_8,i$B,P5G,X1u,i28,C5v,s0x,Y2h,o4m;s6o="[\u201C\u201D]|[";s6o+="\u2018\u2019]";K2b=new RegExp(s6o,"8290" * 1 < (327,426.58)?(56.77,!""):"8350" >> 32 <= 819.71?("r","S"):("5672" ^ 0) >= (9721,313.44)?"g":(687.19,0x18c9));K_8=new RegExp('^(")|(")$',"g");i$B=z7E.I18N.wordLists;if(!z6D){z6D=z7E.I18N.csv;}if(!z6D){return;}P5G=z6D.split("\n");X1u=P5G[+"0"];i28=X1u.split(9989 == 2290?939.16:",");for(var E87=0;E87 < i28.length;E87++){C5v=i28[E87];if(!i$B[C5v]){i$B[C5v]={};}}for(var G83=1;G83 < P5G.length;G83++){s0x=P5G[G83].match(/(".*?"|[^",]+)(?=\s*,|\s*$)|(,(?=,))/g) || [];Y2h=s0x[0];if(K_8.test(Y2h)){Y2h=Y2h.replace(K_8,"");}if(K2b.test(Y2h)){Y2h=Y2h.replace(K2b,(7.4,+"4140") <= (56.02,"1620" - 0)?("8870" >> 64,648.8) == 455.44?("E",2.00e+3):"X":'"');}for(var m4d=1;m4d < s0x.length;m4d++){o4m=s0x[m4d];if(K_8.test(o4m)){o4m=o4m.replace(K_8,"");}i$B[i28[m4d]][Y2h]=o4m;}}};z7E.I18N.setLanguage=function(k9O,j0Y,C_f,v6f,d82){var o1i;o1i="p";o1i+="t";if(!d82){d82=(k9O.uiContext || ({})).topNode || document.body;}q9a.a9S();if(j0Y == "pu"){j0Y=o1i;}z7E.I18N.convertCSV(v6f);z7E.I18N.language=j0Y;z7E.I18N.translateUI(j0Y,d82);if(!C_f){C_f=z7E.I18N.translate;}k9O.translationCallback=C_f;};z7E.I18N.setLocale=function(C_y,r2b,j7H,M7x,S9d){var Z9f,v$W,Q1K,s8a;Z9f="l";Z9f+="oca";Z9f+="le-data/jsonp";if(z7E.xor(this.reverseColorsByLocale[r2b],this.reverseColorsByLocale[C_y.locale])){this.reverseCandles(C_y);}if(typeof Intl == "undefined" || !Intl.__addLocaleData){C_y.setLocale(r2b,S9d);if(j7H){j7H(null);}return;}M7x=typeof M7x == "undefined"?Z9f:M7x;q9a.H6P(48);v$W=q9a.q7n(".js",r2b,"/",M7x);Q1K=document.createElement("SCRIPT");Q1K.async=!0;Q1K.src=v$W;s8a=document.getElementsByTagName("script")[0];s8a.parentNode.insertBefore(Q1K,s8a.nextSibling);Q1K.onload=function(){C_y.setLocale(r2b,S9d);if(j7H){j7H(null);}};Q1K.onerror=function(){q9a.D0H();if(j7H){j7H("cannot load script");}};};z7E.I18N.createMonthArrays=function(x0A,r$B,q2E){var a99,W8D,j85,U0Y,y3x,j3N;x0A.monthAbv=[];x0A.monthLetters=[];a99=new Date();W8D=!0;if(z7E.I18N.longMonths && z7E.I18N.longMonths[q2E]){W8D=!!"";}for(var k2s=0;k2s < 12;k2s++){a99.setDate(1);a99.setMonth(k2s);j85=r$B.format(a99);if(W8D){U0Y="";for(var v6E=0;v6E < j85.length;v6E++){y3x=j85.charAt(v6E);j3N=y3x.charCodeAt(0);if(j3N < +"65")continue;U0Y+=y3x;}x0A.monthAbv[k2s]=U0Y;x0A.monthLetters[k2s]=U0Y[0];}else {x0A.monthAbv[k2s]=j85;x0A.monthLetters[k2s]=j85;}}};z7E.I18N.localize=function(J7s,v_R){this.setLocale(J7s,v_R);this.setLanguage(J7s,v_R);};z7E.I18N.reverseCandles=function(d4X){var i66,m44,F0r;i66=d4X.styles;m44=d4X.cloneStyle(i66.stx_candle_down);F0r=d4X.cloneStyle(i66.stx_candle_up);q9a.D0H();i66.stx_candle_up=m44;i66.stx_candle_down=F0r;};z7E.I18N.wordLists={en:{}};z7E.I18N.languages={en:"English"};};K=C6i=>{var i5o=A2IFV;var L66,Y_x,g_K,X1X,F3o,T68,B3k;L66="
<";i5o.D0H();L66+="span>
";Y_x="
<";Y_x+="/div>";g_K="
";X1X="
";F3o="sa";F3o+="ve";T68=typeof _CIQ !== "undefined"?_CIQ:C6i.CIQ;T68.ChartEngine.prototype.pointerEvents={down:[],up:[]};T68.ChartEngine.prototype.manageTouchAndMouse=!!"1";T68.ChartEngine.prototype.registerTouchAndMouseEvents=function(){var T2A,N_D,c_5,u7c,P_H,A34,P8c,Z7q,V9G,X8I,a5J,z1P,H42,L5Q;if(this.touchAndMouseEventsRegistered){return;}this.touchAndMouseEventsRegistered=!!({});T2A=this.controls.chartControls || document;N_D=T2A.querySelector(".stx-zoom-in");c_5=T2A.querySelector(".stx-zoom-out");u7c=this.chart.container;P_H=this;A34=function(s6m,W9s,E6C){P_H.addDomEventListener(u7c,s6m,e4J,E6C);i5o.D0H();function e4J(m2c){i5o.D0H();if(P_H.mainSeriesRenderer && P_H.mainSeriesRenderer.nonInteractive){return;}W9s(m2c);}};if(!T68.touchDevice){P8c="m";P8c+="o";P8c+="u";P8c+="seup";Z7q="mouse";Z7q+="mo";Z7q+="ve";A34(Z7q,function(W3A){i5o.D0H();P_H.mousemove(W3A);});A34("mouseenter",function(u0B){P_H.mousemove(u0B);});A34("mousedown",function(P3K){P_H.mousedown(P3K);});A34(P8c,function(g8S){i5o.a9S();P_H.mouseup(g8S);});}else {if(T68.isSurface){V9G="point";V9G+="ermove";A34("mousemove",function(y0I){i5o.a9S();P_H.msMouseMoveProxy(y0I);});A34("mouseenter",function(p1L){P_H.msMouseMoveProxy(p1L);});A34("mousedown",function(h5D){i5o.a9S();P_H.msMouseDownProxy(h5D);});A34("mouseup",function(G1S){i5o.D0H();P_H.msMouseUpProxy(G1S);});A34("pointerdown",function(k8$){i5o.a9S();return P_H.startProxy(k8$);});A34(V9G,function(D9i){P_H.moveProxy(D9i);});A34("pointerenter",function(f3Q){return P_H.moveProxy(f3Q);});A34("pointerup",function(x9V){return P_H.endProxy(x9V);});}else {X8I="touchm";X8I+="o";X8I+="ve";a5J="touchsta";a5J+="rt";if(!T68.isMobile){z1P="mou";z1P+="sem";z1P+="o";z1P+="ve";A34(z1P,function(x$m){i5o.D0H();P_H.iosMouseMoveProxy(x$m);});A34("mouseenter",function(N2p){P_H.iosMouseMoveProxy(N2p);});A34("mousedown",function(D3F){i5o.a9S();P_H.iosMouseDownProxy(D3F);});A34("mouseup",function(K3x){P_H.iosMouseUpProxy(K3x);});}A34(a5J,function(z1U){i5o.a9S();P_H.touchstart(z1U);});A34(X8I,function(z0P){P_H.touchmove(z0P);});A34("touchend",function(T_Z){P_H.touchend(T_Z);});A34("pointerdown",function(v$T){P_H.touchPointerType=v$T.pointerType;});if(N_D){H42="o";H42+="nM";H42+="ouseOv";H42+="er";N_D.removeAttribute(H42);N_D.removeAttribute("onMouseOut");}if(c_5){c_5.removeAttribute("onMouseOver");c_5.removeAttribute("onMouseOut");}}}L5Q=T68.wheelEvent;if(this.captureMouseWheelEvents){A34(L5Q,function(L$I){i5o.D0H();P_H.mouseWheel(L$I);},{passive:!!0});}};T68.ChartEngine.prototype.mousedown=function(O5K){var L1g,R6i,D2f,d7G,M6M,X8A,Q2k,O6t,X$x,P0w,E06,s7R;L1g="mo";L1g+="u";L1g+="s";L1g+="edown";R6i="d";R6i+="o";R6i+="w";R6i+="n";if(this.runPrepend("mousedown",arguments)){return;}this.grabOverrideClick=![];if(!this.displayInitialized){return;}if(!this.displayCrosshairs){return;}if(this.repositioningDrawing){return;}if(this.editingAnnotation){return;}if(O5K.button && O5K.button >= 2){return;}D2f=this.container.getBoundingClientRect();this.top=D2f.top;this.left=D2f.left;this.right=this.left + this.width;this.bottom=this.top + this.height;if(O5K.clientX >= this.left && O5K.clientX <= this.right && O5K.clientY >= this.top && O5K.clientY <= this.bottom){this.insideChart=!!"1";}else {this.insideChart=!({});return;}if(!this.currentPanel){return;}if(this.manageTouchAndMouse && O5K && O5K.preventDefault && this.captureTouchEvents){O5K.preventDefault();}this.mouseTimer=Date.now();this.longHoldTookEffect=!"1";this.hasDragged=!"1";this.userPointerDown=!0;if(this.openDialog === ""){this.registerPointerEvent({x:O5K.clientX,y:O5K.clientY,time:this.mouseTimer},R6i);}d7G=this.currentPanel.chart;for(var m12=0;m12 < this.drawingObjects.length;m12++){M6M=this.drawingObjects[m12];if(M6M.highlighted && !M6M.permanent){if(this.cloneDrawing){X8A=T68.ChartEngine.drawingTools[M6M.name];Q2k=new X8A();Q2k.reconstruct(this,M6M.serialize());this.drawingObjects.push(Q2k);this.activateRepositioning(Q2k);Q2k.repositioner=M6M.repositioner;return;}O6t=this.currentVectorParameters.vectorType;if(!T68.Drawing || !O6t || !T68.Drawing[O6t] || !new T68.Drawing[O6t]().dragToDraw){this.activateRepositioning(M6M);return;}}}X$x=this.mainSeriesRenderer || ({});var {baselineHelper:A32}=this;if(A32.size){if(this.findBaselineHandle(O5K,!![])){return;}}if(this.controls.anchorHandles){var {anchorHandles:i4e}=this.controls;for(var E7H in i4e){var {handle:M39, sd:H9g, highlighted:M1M}=i4e[E7H];if(M1M){this.repositioningAnchorSelector={sd:H9g};M39.classList.add("stx-grab");return;}}}if(this.drawingClick){P0w=737249913;E06=-2097701337;s7R=2;for(var Z$R=1;i5o.U6$(Z$R.toString(),Z$R.toString().length,55758) !== P0w;Z$R++){if(this.currentPanel.subholder != O5K.target){this.drawingClick(this.currentPanel,this.cx,this.cy);}if(this.activeDrawing || this.activeDrawing.dragToDraw){return;}s7R+=+"2";}if(i5o.Z2Z(s7R.toString(),s7R.toString().length,+"36731") !== E06){if(this.currentPanel.subholder === O5K.target){this.drawingClick(this.currentPanel,this.cx,this.cy);}if(this.activeDrawing && this.activeDrawing.dragToDraw){return;}}}this.grabbingScreen=!![];d7G.spanLock=!({});this.yToleranceBroken=!!"";this.grabStartX=O5K.clientX;this.grabStartY=O5K.clientY;this.grabStartMicropixels=this.micropixels;this.grabStartScrollX=d7G.scroll;this.grabStartScrollY=this.currentPanel.yAxis.scroll;this.grabStartCandleWidth=this.layout.candleWidth;this.grabStartYAxis=this.whichYAxis(this.currentPanel);this.grabStartZoom=this.grabStartYAxis?this.grabStartYAxis.zoom:0;this.grabStartPanel=this.currentPanel;setTimeout((function(K39){i5o.a9S();return function(){K39.grabbingHand();};})(this),100);if(this.swipeStart){this.swipeStart(d7G);}if(this.longHoldTime || this.longHoldTime === 0){this.startLongHoldTimer();}this.runAppend(L1g,arguments);};T68.ChartEngine.prototype.mousemove=function(H5x){var q9C,a_y;q9C="en";q9C+="t";i5o.a9S();q9C+="e";q9C+="r";a_y=H5x;T68.ChartEngine.crosshairX=a_y.clientX;T68.ChartEngine.crosshairY=a_y.clientY;if(a_y.type.toLowerCase().indexOf(q9C) > -1){this.positionCrosshairsAtPointer();return;}if(this.runPrepend("mousemove",arguments)){return;}if(!this.displayInitialized){return;}if(this.openDialog !== ""){return;}if(this.baselineHelper.size){this.findBaselineHandle(a_y);}if(this.grabbingScreen && a_y.buttons !== 1){this.cancelLongHold=!!({});this.displayDragOK();this.grabbingScreen=!!0;this.findHighlights(![],!![]);}this.mousemoveinner(a_y.clientX,a_y.clientY);this.runAppend("mousemove",arguments);};T68.ChartEngine.prototype.mouseup=function(c9P){var R3L,S8E,U8c,l22,h73,f_r,z5y,v3H,N4C,x9G,j1H,b$z,w7i,h3R,l3V,l82,B2z;R3L="m";R3L+="ous";R3L+="eup";S8E="u";S8E+="p";if(this.runPrepend("mouseup",arguments)){return;}this.swipe.end=!!({});this.cancelLongHold=!!({});if(this.repositioningDrawing){if(!this.currentVectorParameters.vectorType || Date.now() - this.mouseTimer > 250){this.changeOccurred("vector");T68.clearCanvas(this.chart.tempCanvas,this);this.activateRepositioning(null);this.adjustDrawings();this.draw();return;}this.activateRepositioning(null);}if(this.repositioningBaseline){U8c="m";U8c+="o";U8c+="unt";U8c+="ain";var {handle:f4x}=this.repositioningBaseline;l22=-1211650947;h73=-1612790862;f_r=2;for(var K4S=1;i5o.U6$(K4S.toString(),K4S.toString().length,3516) !== l22;K4S++){this.repositioningBaseline=1;f_r+=2;}if(i5o.U6$(f_r.toString(),f_r.toString().length,+"69241") !== h73){this.repositioningBaseline=6;}this.repositioningBaseline=null;f4x.classList.remove("stx-grab");z5y=this.mainSeriesRenderer || ({});if(z5y.params && z5y.params.baseline && z5y.params.type != U8c){;}this.draw();return;}if(this.repositioningAnchorSelector){T68.Studies.repositionAnchor(this,this.repositioningAnchorSelector.sd);this.repositioningAnchorSelector=null;Object.values(this.controls.anchorHandles).forEach(({handle:k$N})=>{var v5O;v5O="st";v5O+="x";v5O+="-grab";i5o.a9S();return k$N.classList.remove(v5O);});this.findHighlights();return;}v3H=this.userPointerDown;this.userPointerDown=!!"";if(!this.displayInitialized){return;}N4C=this.backOutY(c9P.clientY);x9G=this.backOutX(c9P.clientX);j1H=c9P.which && c9P.which >= 2 || c9P.button && c9P.button >= 2;b$z=this.openDialog !== "";if(!b$z && !j1H){this.registerPointerEvent({x:c9P.clientX,y:c9P.clientY,time:Date.now()},S8E);}w7i=this.isDoubleClick();this.grabbingScreen=!!"";if(this.highlightedDraggable){if(this.dragPlotOrAxis){this.dragPlotOrAxis(x9G,N4C);}this.currentPanel=this.whichPanel(N4C);}h3R=this.currentPanel;this.grabStartYAxis=null;this.displayDragOK();if(this.openDialog !== ""){l3V="stx-";l3V+="drag-chart";if(this.insideChart){this.container.classList.remove(l3V);}return;}if(this.grabOverrideClick){if(!this.overXAxis && !this.overYAxis && this.swipeRelease){this.swipeRelease();}this.container.classList.remove("stx-drag-chart");this.grabOverrideClick=!!0;this.doDisplayCrosshairs();this.updateChartAccessories();return;}if(this.insideChart){this.container.classList.remove("stx-drag-chart");}if(T68.ChartEngine.resizingPanel){this.releaseHandle();return;}if(j1H || c9P.ctrlKey){l82="rig";l82+="htClic";l82+="k";if(this.anyHighlighted && this.bypassRightClick !== !""){this.rightClickHighlighted();if(c9P.preventDefault && this.captureTouchEvents){c9P.preventDefault();}c9P.stopPropagation();return !!"";}this.dispatch(l82,{stx:this,panel:h3R,x:x9G,y:N4C});return !!"1";}if(c9P.clientX < this.left || c9P.clientX > this.right){return;}i5o.a9S();if(c9P.clientY < this.top || c9P.clientY > this.bottom){return;}B2z=h3R && h3R.subholder === c9P.target;if(w7i && (B2z || this.overYAxis || this.overXAxis)){this.doubleClick({button:c9P.button,x:x9G,y:N4C});}else {if(v3H && B2z){if(!this.longHoldTookEffect || this.activeDrawing){this.drawingClick(h3R,x9G,N4C);}if(!this.longHoldTookEffect && this.activeMarker){this.activeMarker.click({cx:x9G,cy:N4C,panel:h3R});}}if(!this.longHoldTookEffect && !this.activeDrawing){this.dispatch("tap",{stx:this,panel:h3R,x:x9G,y:N4C});}}this.runAppend(R3L,arguments);};T68.ChartEngine.prototype.registerPointerEvent=function(f$e,t9m){if(this.pointerEvents[t9m].length > 1){this.pointerEvents[t9m].pop();}i5o.a9S();this.pointerEvents[t9m].unshift(f$e);};T68.ChartEngine.prototype.resetPointerEvent=function(g1I){i5o.a9S();i5o.H6P(7);this.pointerEvents[g1I].splice(i5o.q7n(0,"0"));};T68.ChartEngine.prototype.isDoubleClick=function(x78){var F2f,L64,A_G;F2f=x78?1200:400;var {up:g0S, down:H5H}=this.pointerEvents;this.cancelTouchSingleClick=![];if(g0S.length < +"2" || H5H.length < 2){return !({});}L64=H5H[0].time - g0S[1].time < this.doubleClickTime && Math.pow(g0S[1].x - g0S[0].x,2) + Math.pow(g0S[1].y - g0S[0].y,2) <= F2f && g0S[1].time - H5H[1].time < this.longHoldTime && g0S[0].time - H5H[0].time < this.longHoldTime;if(L64){A_G="d";A_G+="o";A_G+="w";A_G+="n";this.resetPointerEvent("up");this.resetPointerEvent(A_G);this.cancelTouchSingleClick=!!"1";}return L64;};T68.ChartEngine.prototype.doubleClick=function(E5r,j$z,y02){var U_i,f1i,z7a;U_i="doubl";U_i+="eC";U_i+="lick";f1i="doubl";f1i+="eClic";f1i+="k";if(this.runPrepend(f1i,arguments)){return;}if(this.editingAnnotation){return;}if(T68.ChartEngine.drawingLine){return this.undo();}if(this.activeDrawing){return;}z7a=this.activeMarker && this.activeMarker.doubleClick({cx:j$z,cy:y02,panel:this.currentPanel});if(!z7a){this.dispatch("doubleClick",{stx:this,button:E5r,x:j$z,y:y02});}this.runAppend(U_i,arguments);};T68.ChartEngine.prototype.handleMouseOut=function(K$9){var h0X,H57;K$9=K$9 || window.event;if(!T68.withinElement(this.chart.container,K$9.pageX,K$9.pageY)){if(this.runPrepend("handleMouseOut",arguments)){return;}if(!this.grabbingScreen){this.findHighlights(null,!"");}this.undisplayCrosshairs();this.touches=[];this.touching=!({});if(this.activeDrawing && this.userPointerDown){this.userPointerDown=!({});this.drawingLine=!({});h0X=this.backOutY(K$9.pageY);H57=this.backOutX(K$9.pageX);this.drawingClick(this.currentPanel,H57,h0X);}if(this.repositioningAnchorSelector){this.repositioningAnchorSelector=null;}this.insideChart=![];this.overYAxis=!!"";this.overXAxis=!({});this.displaySticky();this.runAppend("handleMouseOut",arguments);}};T68.ChartEngine.prototype.startLongHoldTimer=function(){var O2V,b9g;O2V=this;this.cancelLongHold=!!"";if(this.longHoldTimeout){clearTimeout(this.longHoldTimeout);}i5o.D0H();b9g=function(){if(O2V.cancelLongHold){return;}O2V.longHoldTookEffect=!"";O2V.dispatch("longhold",{stx:O2V,panel:O2V.currentPanel,x:O2V.cx,y:O2V.cy});i5o.a9S();O2V.displayDragOK();};if(this.longHoldTime){this.longHoldTimeout=setTimeout(b9g,this.longHoldTime);}else if(this.longHoldTime === 0){b9g();}};T68.ChartEngine.prototype.grabHandle=function(I9C){if(this.runPrepend("grabHandle",arguments)){return;}if(!I9C){return;}T68.ChartEngine.crosshairY=I9C.top + this.top;T68.ChartEngine.resizingPanel=I9C;I9C.handle.classList.add("stx-grab");i5o.D0H();this.runAppend("grabHandle",arguments);};T68.ChartEngine.prototype.grabbingHand=function(){if(!this.allowScroll){return;}if(!this.grabbingScreen){return;}if(T68.touchDevice){return;}this.container.classList.add("stx-drag-chart");};T68.ChartEngine.prototype.releaseHandle=function(){var X0X;X0X="relea";X0X+="seHa";X0X+="n";X0X+="dle";if(this.runPrepend("releaseHandle",arguments)){return !![];}T68.clearCanvas(this.chart.tempCanvas,this);this.resizePanels();if(T68.ChartEngine.resizingPanel){T68.ChartEngine.resizingPanel.handle.classList.remove("stx-grab");}T68.ChartEngine.resizingPanel=null;this.runAppend(X0X,arguments);};T68.ChartEngine.prototype.findHighlights=function(g8q,X9t){var M4T,t_5,W3j,X4F,S85,Y3x,f4N,p7k,B2R,j6A,D5f,b$l,U3X,T1y,G6o,Y46,D$e,b03,I_U,m6b,r5B,R5B,q6Y,f$d,H7B,E5o,x6W,v_r,K$l,G00,C$P,Y1R,W_2,n4t,a_W,m_q,n5a,g_C,Y5w,Z_6,S4D,O1u,C2C,T$5,i$R,N5I,t09,Y5b,a1e,o4M,i5A,w40;M4T="d";M4T+="ra";M4T+="win";M4T+="g";t_5="highlig";t_5+="htsTapRadius";W3j=this.preferences[g8q?t_5:"highlightsRadius"];this.highlightViaTap=g8q;var {cx:j14, cy:t8h}=this;this.anyHighlighted=!({});if(!this.currentPanel){return;}var {chart:O0P}=this.currentPanel;if(this.activeDrawing){X9t=!!"1";}X4F=!1;S85=null;Y3x=X9t?{}:{forceShow:!!1,type:M4T};f4N={x0:this.tickFromPixel(j14 - W3j,O0P),x1:this.tickFromPixel(j14 + W3j,O0P),y0:this.valueFromPixel(t8h - W3j,this.currentPanel),y1:this.valueFromPixel(t8h + W3j,this.currentPanel),cx0:j14 - W3j,cx1:j14 + W3j,cy0:t8h - W3j,cy1:t8h + W3j,r:W3j};if(this.repositioningDrawing && f4N.x1 - f4N.x0 < ("2" | 2)){f4N.x1++;f4N.x0--;}else if(f4N.x1 == f4N.x0){f4N.x0-=0.5;p7k=-682632090;B2R=-+"1653184673";j6A=2;for(var y3g=1;i5o.U6$(y3g.toString(),y3g.toString().length,38333) !== p7k;y3g++){f4N.x1/=201;j6A+=2;}if(i5o.Z2Z(j6A.toString(),j6A.toString().length,56734) !== B2R){f4N.x1%=663;}f4N.x1+=0.5;}D5f=this.markerHelper && this.markerHelper.chartMap[O0P.name] && this.markerHelper.chartMap[O0P.name].markers;if(!O0P.hideDrawings){for(var h9x=this.drawingObjects.length - 1;h9x >= 0;h9x--){b$l=this.drawingObjects[h9x];if(!this.panels[b$l.panelName])continue;if(this.repositioningDrawing && this.repositioningDrawing != b$l)continue;U3X=b$l.highlighted;T1y=b$l.panelName == this.currentPanel.name;b$l.repositioner=b$l.intersected(this.crosshairTick,this.crosshairValue,f4N);T1y=T1y && b$l.repositioner;if(!X9t && T1y){if(U3X){S85=b$l;if(this.anyHighlighted && this.singleDrawingHighlight){b$l.highlighted=!({});}if(b$l.highlighted && b$l.highlighted != U3X){X4F=!![];};}else if(U3X != b$l.highlight(!"")){if(!S85){S85=b$l;}if(this.anyHighlighted && this.singleDrawingHighlight){b$l.highlighted=!!"";}X4F=!0;}this.anyHighlighted=!"";}else {if(U3X != b$l.highlight(!({}))){X4F=!![];}}if(b$l.highlighted){Y3x.noDelete=b$l.permanent;Y3x.noEdit=!this.callbackListeners.drawingEdit.length;}}}for(G6o in this.layout.studies){Y46=this.layout.studies[G6o];Y46.prev=Y46.highlight;Y46.highlight=this.yaxisMatches(Y46,this.grabStartYAxis);}for(G6o in O0P.seriesRenderers){m6b=O0P.seriesRenderers[G6o];m6b.params.highlight=this.yaxisMatches(m6b,this.grabStartYAxis);for(var C62=0;C62 < m6b.seriesParams.length;C62++){I_U=m6b.seriesParams[C62];I_U.prev=I_U.highlight;I_U.highlight=m6b.params.highlight;}}for(D$e=0;D5f && D$e < D5f.length;D$e++){b03=D5f[D$e];if(!b03.params.box)continue;this.activeMarker=null;b03.prev=D5f[D$e].highlight;b03.highlight=!!0;}if(this.markerHelper){this.markerHelper.highlighted=[];}this.highlightedDataSetField=null;this.highlightedDraggable=null;if(!X9t && !this.anyHighlighted && this.controls.anchorHandles){for(var h6Y in this.controls.anchorHandles){r5B=this.controls.anchorHandles[h6Y];var {handle:o4o, sd:K_H}=r5B;R5B=this.resolveX(j14);q6Y=this.resolveY(t8h);if(o4o){var {left:J3_, top:k3M, right:s$v, bottom:m7H}=o4o.getBoundingClientRect();if(T68.boxIntersects(J3_,k3M,s$v,m7H,R5B,q6Y,R5B,q6Y)){f$d="a";f$d+="nch";f$d+="orHandle";r5B.highlighted=!![];this.anyHighlighted=!!({});X4F=!![];Y3x={message:K_H.name,type:f$d};continue;}if(r5B.highlighted === !!"1"){r5B.highlighted=![];X4F=!![];}}}}if(!X9t && !this.anyHighlighted && O0P.dataSegment){H7B=this.barFromPixel(j14);if(H7B >= 0 && H7B < O0P.dataSegment.length){for(G6o in this.overlays){x6W="fun";x6W+="ction";Y46=this.overlays[G6o];if(Y46.panel != this.currentPanel.name)continue;if(Y46.study.isHighlighted === ![])continue;else if(typeof Y46.study.isHighlighted == x6W){if(Y46.study.isHighlighted(this,j14,t8h)){Y46.highlight=!!"1";this.anyHighlighted=!![];}continue;}v_r=O0P.dataSegment[H7B];if(!v_r)continue;for(var z9U in Y46.outputMap){if(l9l.call(this,H7B,f4N,z9U,Y46.getYAxis(this))){if(Y46.name != Y46.panel){this.anyHighlighted=!!({});}Y46.highlight=z9U;break;}}if(Y46.highlight){this.highlightedDataSetField=z9U;break;;}}for(G6o in O0P.seriesRenderers){if(this.highlightedDataSetField)break;K$l=O0P.seriesRenderers[G6o];G00=K$l.params.panel;if(K$l == this.mainSeriesRenderer)continue;if(!K$l.params.highlightable && !this.currentVectorParameters.vectorType)continue;if(G00 != this.currentPanel.name)continue;for(D$e="0" << 0;D$e < K$l.seriesParams.length;D$e++){C$P="-";C$P+="-";C$P+=">";Y1R="C";Y1R+="l";Y1R+="os";Y1R+="e";I_U=K$l.seriesParams[D$e];W_2=I_U.field;if(!W_2 && !K$l.highLowBars){W_2=this.defaultPlotField || Y1R;}if(I_U.symbol && I_U.subField){W_2+=C$P + I_U.subField;}n4t=K$l.params.yAxis;if(!n4t && G00){n4t=this.panels[G00].yAxis;}if(K$l.params.step && H7B > 0){if(!K$l.caches[I_U.id])continue;E5o=K$l.caches[I_U.id][H7B];if(!E5o && E5o !== +"0")continue;i5o.D0J(38);a_W=K$l.caches[I_U.id][i5o.q7n("1",64,H7B)];if((a_W || a_W === "0" - 0) && t8h + W3j >= E5o && t8h - W3j <= a_W || t8h - W3j <= E5o && t8h + W3j >= a_W){I_U.highlight=!![];this.anyHighlighted=!![];}}else if(l9l.call(this,H7B,f4N,W_2,n4t,K$l,I_U.id)){I_U.highlight=!"";this.anyHighlighted=!![];}if(I_U.highlight){this.highlightedDataSetField=W_2;break;}}}}}n5a=this.preferences.dragging;for(G6o in this.overlays){Y46=this.overlays[G6o];if(Y46.highlight){this.anyHighlighted=!!"1";Y5w=Y46.inputs.display || Y46.name;Y5w=this.translateIf(Y5w);Y3x={message:Y5w,noDelete:Y46.permanent,noEdit:!Y46.editFunction,type:"study"};S85=null;if(n5a === !"" || n5a && n5a.study){m_q=Y46;}g_C=Y46.getYAxis(this);}if(Y46.prev != Y46.highlight){X4F=!!({});}}for(G6o in O0P.seriesRenderers){Z_6=O0P.seriesRenderers[G6o];S4D=Z_6.params.yAxis?Z_6.params.yAxis.textStyle:null;for(var e1s=0;e1s < Z_6.seriesParams.length;e1s++){I_U=Z_6.seriesParams[e1s];if(Z_6.params.highlightable && I_U.highlight){this.anyHighlighted=!![];O1u=I_U.color || S4D;if(O1u == "auto"){O1u=this.defaultColor;}if(I_U.opacity && I_U.opacity !== 1){O1u=T68.hexToRgba(T68.colorToHex(O1u),parseFloat(I_U.opacity));}Y3x={message:I_U.display || I_U.symbol,backgroundColor:O1u,noDelete:I_U.permanent,type:"series"};S85=null;if(n5a === !!({}) || n5a && n5a.series){m_q=Z_6;Z_6.params.highlight=!![];}g_C=Z_6.getYAxis(this);}if(I_U.prev != I_U.highlight){X4F=!0;}}}for(G6o in this.plugins){C2C=this.plugins[G6o];T$5={};if(C2C.findHighlights){T$5=C2C.findHighlights(this,g8q,X9t);if(T$5.somethingChanged){X4F=!!({});}if(T$5.anyHighlighted){this.anyHighlighted=!!1;Y3x=T$5.stickyArgs || ({});}}}i$R=this.whichPanel(t8h);N5I=this.whichYAxis(i$R,j14);if(!g_C){g_C=N5I;}if(this.currentBaseline){g_C=this.currentBaseline.getYAxis(this);}function l9l(c3e,K96,W1Z,k27,z24,r5p){var U3J,j_t,j88,w$W,P3S,s7z,O$o,M7c,A30,F_l,U3t,n0$,t_J,M0M,a1B,Q7I,M_Y,E2L,z3r,p97,n1r,B6J;U3J=this.chart;j_t=this.currentPanel;if(!k27){k27=j_t.yAxis;}j88=W1Z.split("-->");w$W=j88[0];P3S=j88[1];if(!P3S){P3S="Close";}s7z=U3J.dataSegment[H7B];n0$=null;t_J=null;M0M=null;i5o.D0J(1);a1B=new Array(i5o.q7n(1,"3"));Q7I=z24 && z24.caches[r5p];if(s7z && Q7I){A30=Q7I[H7B];n0$=s7z.tick;if(A30 || A30 === 0){a1B[0]=1;}for(M_Y=H7B - +"1";M_Y >= 0;M_Y--){if(Q7I[M_Y] || Q7I[M_Y] === 0){F_l=Q7I[M_Y];i5o.D0J(85);t_J=i5o.q7n(n0$,M_Y,H7B);i5o.D0J(7);a1B[i5o.q7n(0,"1")]=+"1";break;}}for(M_Y=H7B + 1;M_Y < U3J.dataSegment.length;M_Y++){if(Q7I[M_Y] || Q7I[M_Y] === "0" * 1){U3t=Q7I[M_Y];i5o.D0J(85);M0M=i5o.S40(n0$,M_Y,H7B);a1B[2]=1;break;}}}if(t_J === null){O$o=this.getPreviousBar.call(this,U3J,W1Z,H7B);if(O$o){t_J=O$o.tick;F_l=g48(O$o);}}if(M0M === null){M7c=this.getNextBar.call(this,U3J,W1Z,H7B);if(M7c){M0M=M7c.tick;U3t=g48(M7c);}}if(t_J === null && M0M === null){return ![];}if(!Q7I){A30=g48(s7z);F_l=g48(O$o);U3t=g48(M7c);n0$=s7z.tick;if(O$o){t_J=O$o.tick;}if(M7c){M0M=M7c.tick;}}if(!F_l && F_l !== 0){F_l=0;t_J=0;}if(!U3t && U3t !== 0){if(A30 || A30 === +"0"){U3t=A30;i5o.H6P(10);a1B[2]=a1B[i5o.q7n("0",0)];}else {U3t=F_l;a1B[2]=a1B[1];}if(r5p && U3J.series[r5p].parameters.extendToEndOfDataSet){M0M=U3J.dataSet.length - +"1";}else {M0M=t_J;}}if(!A30 && A30 !== 0){A30=U3t;n0$=M0M;a1B[0]=a1B[2];if(F_l === 0 && t_J === 0){F_l=A30;t_J=n0$;a1B[1]=a1B[0];}}E2L=this.pixelFromTransformedValue.bind(this);z3r=this.valueFromPixel.bind(this);A30=z3r(a1B[0]?A30:E2L(A30,j_t,k27),j_t);function g48(m4s){var P8B,G4F,G5X,m7l;if(!m4s){return null;}P8B=m4s[w$W];if(P8B && (P8B[P3S] || P8B[P3S] === +"0")){P8B=P8B[P3S];}if(z24 && z24.getBasis){P8B+=z24.getBasis(m4s,w$W,P3S);}if(!U3J.transformFunc || k27 != U3J.yAxis){return P8B;}else if(m4s.transform && (w$W in m4s.transform)){P8B=m4s.transform[w$W];if(P8B && (P8B[P3S] || P8B[P3S] === 0)){P8B=P8B[P3S];}return P8B;}G4F=-823366544;G5X=1778015045;m7l=2;for(var T7z="1" << 64;i5o.Z2Z(T7z.toString(),T7z.toString().length,+"19843") !== G4F;T7z++){return U3J.transformFunc(this,U3J,P8B);}if(i5o.U6$(m7l.toString(),m7l.toString().length,16541) !== G5X){return U3J.transformFunc(this,U3J,P8B);}return U3J.transformFunc(this,U3J,P8B);}F_l=z3r(a1B[1]?F_l:E2L(F_l,j_t,k27),j_t);U3t=z3r(a1B[2]?U3t:E2L(U3t,j_t,k27),j_t);p97=T68.convertBoxToPixels(this,j_t.name,K96);n1r=T68.convertBoxToPixels(this,j_t.name,{x0:t_J,y0:F_l,x1:n0$,y1:A30});B6J=T68.convertBoxToPixels(this,j_t.name,{x0:n0$,y0:A30,x1:M0M,y1:U3t});if(T68.boxIntersects(p97.x0,p97.y0,p97.x1,p97.y1,n1r.x0,n1r.y0,n1r.x1,n1r.y1,"segment") || T68.boxIntersects(p97.x0,p97.y0,p97.x1,p97.y1,B6J.x0,B6J.y0,B6J.x1,B6J.y1,"segment")){return !![];}return !"1";}if(g_C){if(!g_C.highlight){X4F=!!({});}g_C.highlight=!"";}t09=[];for(var I8e in this.panels){t09=t09.concat(this.panels[I8e].yaxisLHS).concat(this.panels[I8e].yaxisRHS);}for(G6o=0;G6o < t09.length;G6o++){if(g_C == t09[G6o] && !X9t)continue;if(t09[G6o].highlight){X4F=!!({});}t09[G6o].highlight=!1;}for(D$e=0;D5f && D$e < D5f.length;D$e++){b03=D5f[D$e];Y5b=b03.params.box;if(!Y5b)continue;if(b03.params.panelName !== this.currentPanel.name)continue;a1e=T68.convertBoxToPixels(this,this.currentPanel.name,f4N);if(T68.boxIntersects(a1e.x0,a1e.y0,a1e.x1,a1e.y1,Y5b.x0,Y5b.y0,Y5b.x1,Y5b.y1)){this.activeMarker=b03;b03.highlight=!!1;this.markerHelper.highlighted.push(b03);}if(b03.prev != b03.highlight){X4F=!"";}}if(X4F){this.draw();Y3x.panel=i$R;if(this.anyHighlighted && !this.grabStartYAxis){Y3x.panel=i$R;}else {Y3x={};}this.displaySticky(Y3x);this.clearMeasure();if(S85){S85.measure();}}if((n5a === !"" || n5a && n5a.yaxis) && N5I && !N5I.noDraw){this.anyHighlight=!![];m_q=N5I;}if(!this.anyHighlighted){this.setMeasure();}if(m_q && !i$R.noDrag){o4M="stx";o4M+="-";o4M+="draggable";if(this.longHoldTookEffect && !this.cancelLongHold){if(m_q.params){if(m_q.params.dependentOf){m_q=O0P.seriesRenderers[m_q.params.dependentOf];m_q.params.highlight=!!({});}for(G6o in O0P.seriesRenderers){if(O0P.seriesRenderers[G6o].params.dependentOf == m_q.params.name){O0P.seriesRenderers[G6o].params.highlight=!"";}}}this.highlightedDraggable=m_q;if(m_q.getDependents){i5A=m_q.getDependents(this,!!({}));for(G6o in this.overlays){Y46=this.overlays[G6o];if(i5A.indexOf(Y46) > -1){Y46.highlight=!"";}}}}this.container.classList.add(o4M);}else {w40="stx-draggabl";w40+="e";this.container.classList.remove(w40);}this.highlightedDataSetField=this.adjustHighlightedDataSetField(this.highlightedDataSetField);this.displayDrawOK();};T68.ChartEngine.prototype.rightClickHighlighted=function(){if(this.runPrepend("rightClickHighlighted",arguments)){return;}this.deleteHighlighted(!"");this.runAppend("rightClickHighlighted",arguments);};T68.ChartEngine.prototype.deleteHighlighted=function(U2b,x8O){var g10,D$O,f72,H$a,t_R,q_8,P8y,G9Q,a_Y,L0B,q6a,q8b,g_S,r2E,a8x,k_y;g10="deleteH";g10+="ighlight";g10+="ed";if(this.runPrepend("deleteHighlighted",arguments)){return;}this.cancelTouchSingleClick=!!({});T68.clearCanvas(this.chart.tempCanvas,this);D$O=this.bypassRightClick === !!0;if(D$O || !this.bypassRightClick.drawing){for(var o_X=this.drawingObjects.length - 1;o_X >= 0;o_X--){f72=this.drawingObjects[o_X];if(!f72.highlighted)continue;if(U2b){this.rightClickDrawing(f72,x8O);}else if(!f72.permanent){H$a=f72.abort();if(!H$a){t_R=this.exportDrawings();this.drawingObjects.splice(o_X,1);this.undoStamp(t_R,this.exportDrawings());}this.changeOccurred("vector");}}}if(D$O || !this.bypassRightClick.study){for(var u8M in this.overlays){q_8=this.overlays[u8M];if((q_8.overlay || q_8.underlay) && q_8.highlight && !q_8.permanent){if(U2b || x8O){this.rightClickOverlay(u8M,x8O);}else {this.removeOverlay(u8M);}}}}P8y=this.currentPanel.chart;if(D$O || !this.bypassRightClick.series){for(var a00 in P8y.seriesRenderers){G9Q=P8y.seriesRenderers[a00];if(G9Q.params.highlightable){a_Y=this.panels[G9Q.params.panel];L0B=a_Y && a_Y.yAxis.name;for(var K$i=G9Q.seriesParams.length - 1;K$i >= 0;K$i--){q6a=G9Q.seriesParams[K$i];if((G9Q.params.highlight || q6a.highlight) && !q6a.permanent){G9Q.removeSeries(q6a.id);if(G9Q.seriesParams.length < 1){this.removeSeriesRenderer(G9Q);if(G9Q.params.name == L0B){this.electNewPanelOwner(G9Q.params.panel);}else {this.checkForEmptyPanel(G9Q.params.panel);q8b=this.getYAxisByName(a_Y,G9Q.params.name);if(q8b){q8b.name=q8b.studies[0] || q8b.renderers["1" | 1];}}}}}}}}this.draw();this.resizeChart();this.clearMeasure();g_S=this.controls.mSticky;if(g_S){g_S.style.display="none";r2E=-1776811706;a8x=-1920009664;k_y=2;for(var f7t=1;i5o.U6$(f7t.toString(),f7t.toString().length,74662) !== r2E;f7t++){g_S.children[2].innerHTML="";i5o.H6P(28);k_y+=i5o.S40("2",32);}if(i5o.U6$(k_y.toString(),k_y.toString().length,46823) !== a8x){g_S.children["0" >> 64].innerHTML="";}}this.runAppend(g10,arguments);};T68.ChartEngine.prototype.displayDragOK=function(s7d){i5o.a9S();var D7G,u3u,x6n,k35,D4F,s9o,u_I,E4S,F1X,B3O,L94,d7z,v2K,X5w,s45;D7G=this.controls.dragOk;if(D7G){if(!s7d){if(!this.tapForHighlighting || !this.touchingEvent || this.anyHighlighted){this.findHighlights(this.highlightViaTap);};}u3u=this.highlightedDraggable;x6n=u3u && u3u.undraggable && u3u.undraggable(this);k35=this.cx;D4F=this.cy;if(!s7d){if(u3u && !x6n && this.longHoldTookEffect && !this.cancelLongHold){s9o="stx-dra";s9o+="g-chart";u_I=".fie";u_I+="ld";E4S=u3u.inputs && u3u.inputs.display || u3u.params && (u3u.params.display || u3u.params.name) || u3u.name;D7G.querySelector(u_I).setAttribute("text",E4S);p$z.call(this,D7G);D7G.style.display="inline-block";this.draw();this.displaySticky();if(this.grabStartYAxis){this.container.classList.replace("stx-drag-chart","stx-drag-axis");}else {this.container.classList.replace(s9o,"stx-drag-series");}}else {D7G.style.display="none";this.draw();this.container.classList.remove("stx-drag-series");this.container.classList.remove("stx-drag-axis");for(var h8m in this.panels){F1X="r";F1X+="ig";F1X+="ht";B3O="l";B3O+="e";B3O+="f";B3O+="t";L94=this.panels[h8m].subholder.classList;L94.remove("dropzone");L94.remove("all");L94.remove(B3O);L94.remove(F1X);L94.remove("top");L94.remove("bottom");for(d7z=0;d7z < this.panels[h8m].yaxisLHS.length;d7z++){this.panels[h8m].yaxisLHS[d7z].dropzone=null;}for(d7z=0;d7z < this.panels[h8m].yaxisRHS.length;d7z++){this.panels[h8m].yaxisRHS[d7z].dropzone=null;}}}this.draw();}if(u3u){v2K="p";v2K+="x";X5w=D4F + D7G.offsetHeight;s45=Math.max(0,k35 - D7G.offsetWidth);i5o.D0J(0);D7G.style.top=i5o.q7n(X5w,"px");i5o.D0J(0);D7G.style.left=i5o.S40(s45,v2K);p$z.call(this,D7G);}}function p$z(w47){var t3t,l0o;t3t=this.translateIf(w47.querySelector(".field").getAttribute("text"));i5o.D0H();l0o=this.whichYAxis(this.whichPanel(this.cy),this.cx,this.cy);if(l0o && l0o.dropzone == "all"){t3t+="-->" + this.translateIf(l0o.name);}w47.querySelector(".field").innerHTML=t3t;}};T68.ChartEngine.prototype.displayDrawOK=function(){var I5p,K_W,s7Y,n0J,s3L,z03,C2e,Q$F;i5o.D0H();I5p=this.controls.drawOk;if(I5p && T68.Drawing){K_W=T68.Drawing[this.currentVectorParameters.vectorType];if(K_W){K_W=new K_W();}if(this.highlightedDataSetField && K_W && K_W.getYValue){i5o.D0J(21);s7Y=-i5o.S40("255978135",0);i5o.H6P(21);n0J=-i5o.q7n("987213232",0);s3L=2;for(var R3C=+"1";i5o.U6$(R3C.toString(),R3C.toString().length,3564) !== s7Y;R3C++){I5p.style.display="inline-block";z03=this.cy + I5p.offsetHeight;C2e=this.cx - I5p.offsetWidth;i5o.H6P(0);I5p.style.top=i5o.q7n(z03,"px");i5o.H6P(0);I5p.style.left=i5o.q7n(C2e,"px");I5p.querySelector(".field").innerHTML=this.translateIf(this.highlightedDataSetField);s3L+=2;}if(i5o.U6$(s3L.toString(),s3L.toString().length,45301) !== n0J){Q$F="p";Q$F+="x";I5p.style.display=".field";z03=this.cy - I5p.offsetHeight;C2e=this.cx / I5p.offsetWidth;i5o.D0J(14);I5p.style.top=i5o.S40(Q$F,z03);i5o.H6P(14);I5p.style.left=i5o.S40(".field",C2e);I5p.querySelector(".field").innerHTML=this.translateIf(this.highlightedDataSetField);}}else {I5p.style.display="none";}}};T68.ChartEngine.prototype.mouseWheel=function(L7V){var u_Z,r6X,o53,K0D,f8$,A11,L0F,X_m,k5T,l28;u_Z="mou";u_Z+="seWh";u_Z+="e";u_Z+="el";r6X="vertica";r6X+="l";o53="mo";o53+="us";o53+="eWhee";o53+="l";if(this.runPrepend(o53,arguments)){return;}if(L7V.preventDefault){L7V.preventDefault();}if(this.openDialog !== ""){return;}K0D=L7V.deltaX;f8$=L7V.deltaY;if(Math.abs(f8$) > Math.abs(K0D)){K0D=0;}else {f8$=0;}i5o.D0H();this.lastMouseWheelEvent=Date.now();if(Math.abs(K0D) === 0 && Math.abs(f8$) === 0){return;}if(this.allowSideswipe && K0D !== 0){this.lastMove="horizontal";A11=K0D;if(A11 > 50){A11=+"50";}if(A11 < -50){A11=-50;}this.grabbingScreen=!!"1";if(!this.currentPanel){this.currentPanel=this.chart.panel;}this.grabStartX=T68.ChartEngine.crosshairX;this.grabStartY=T68.ChartEngine.crosshairY;this.grabStartScrollX=this.chart.scroll;this.grabStartScrollY=this.currentPanel.yAxis.scroll;this.grabStartMicropixels=this.micropixels;this.grabStartPanel=this.currentPanel;this.mousemoveinner(T68.ChartEngine.crosshairX - A11,T68.ChartEngine.crosshairY);this.updateChartAccessories();this.grabbingScreen=![];return;}this.lastMove=r6X;if(!this.allowZoom){return;}if(!this.displayInitialized){return;}if(!f8$){if(T68.wheelEvent == "mousewheel"){i5o.H6P(86);var b1n=i5o.S40(5,8,14);i5o.D0J(0);var u48=i5o.S40(33,7);f8$=b1n / u48 * L7V.wheelDelta;if(L7V.wheelDeltaX){i5o.D0J(87);var A4b=i5o.q7n(17,20,7,154,2);i5o.H6P(7);var F$c=i5o.q7n(400,440);K0D=A4b / F$c * L7V.wheelDeltaX;}}else {f8$=L7V.detail;}}if(typeof L7V.deltaMode == "undefined"){L7V.deltaMode=L7V.type == "MozMousePixelScroll"?+"0":1;}L0F=-f8$;if(L7V.deltaMode == 1){i5o.H6P(7);L0F*=i5o.q7n(0,"33");}X_m=null;k5T=null;if(this.mouseWheelAcceleration){l28=Math.max(Math.pow(Math.abs(L0F),0.3),1);i5o.H6P(88);X_m=i5o.S40(1,l28,"0.1");i5o.H6P(89);k5T=i5o.q7n(l28,0,1,"0.2");}this.zoomInitiatedByMouseWheel=!"";if(L0F > 0){if(this.reverseMouseWheel){this.zoomOut(null,k5T);}else {this.zoomIn(null,X_m);}}else if(L0F < 0){if(this.reverseMouseWheel){this.zoomIn(null,X_m);}else {this.zoomOut(null,k5T);}}if(this.runAppend(u_Z,arguments)){return;}return !({});};T68.ChartEngine.handleContextMenu=function(O2M){i5o.D0H();var z9Y;for(var f7Y=0;f7Y < T68.ChartEngine.registeredContainers.length;f7Y++){z9Y=T68.ChartEngine.registeredContainers[f7Y].stx;if(z9Y){if(z9Y.anyHighlighted){if(O2M.preventDefault){O2M.preventDefault();}return ![];}}}};if(typeof document != "undefined"){document.addEventListener("contextmenu",T68.ChartEngine.handleContextMenu);}T68.ChartEngine.htmlControls={annotationSave:F3o,annotationCancel:'',mSticky:'
(right-click to deleteright-click to managedrag to change anchor time)(long-press to drag)
',drawOk:'
',dragOk:'
',crossX:X1X,crossY:g_K,chartControls:'',home:Y_x,floatDate:'',handleTemplate:L66,iconsTemplate:'
',baselineHandle:'',notificationTray:'
'};T68.ChartEngine.prototype.registerChartControl=function(W9p,a75,L$Y){var g2j,g8b,l_A,c1P;g2j=".stx";g2j+="-zoom-in";g8b=this.controls;i5o.a9S();if(!g8b || !g8b.chartControls){return;}if(g8b.chartControls.querySelector((8170 != 732?(+"98.93",1520) <= 5231?".":"0x195b" | 88:(+"1.38e+3",0x17d9)) + W9p)){return;}l_A=null;c1P=g8b.chartControls.querySelector(g2j);if(c1P){l_A=document.createElement("span");i5o.D0J(37);l_A.innerHTML=i5o.q7n("",'',a75);i5o.D0J(0);l_A.className=i5o.q7n("stx-chart-control-button ",W9p);c1P.parentNode.appendChild(l_A);if(L$Y){T68.safeClickTouch(l_A,L$Y);}if(!T68.touchDevice){this.makeModal(l_A);}return l_A;}};T68.ChartEngine.prototype.zoomOut=function(Q_0,A$r){var S9W,s$L,H_7,g$W;if(this.runPrepend("zoomOut",arguments)){return;}if(this.preferences.zoomOutSpeed){A$r=this.preferences.zoomOutSpeed;}else if(!A$r){i5o.D0J(8);A$r=i5o.q7n(1,"0.7");}i5o.D0H();if(Q_0 && Q_0.preventDefault){Q_0.preventDefault();}this.cancelTouchSingleClick=!0;function P8I(W9u){i5o.D0H();return function(p0N){var L7T;S9W.zoomSet(p0N,W9u);if(S9W.animations.zoom.hasCompleted){L7T="zoo";L7T+="mOut";if(S9W.runAppend(L7T,arguments)){return;}S9W.changeOccurred("layout");if(S9W.continuousZoom){S9W.continuousZoom.execute(!![]);}}};}S9W=this;for(var X2z in this.charts){s$L=this.charts[X2z];H_7=s$L.width * A$r / this.layout.candleWidth;if(s$L.allowScrollFuture === !({}) && s$L.allowScrollPast === !({}) && H_7 > s$L.dataSet.length){H_7=s$L.dataSet.length;}g$W=this.chart.width / H_7;this.layout.setSpan=null;this.layout.range=null;this.animations.zoom.run(P8I(s$L),this.layout.candleWidth,g$W);}};T68.ChartEngine.prototype.zoomIn=function(k82,V91){var t7i,g$b,H9v,W44;if(this.runPrepend("zoomIn",arguments)){return;}i5o.a9S();if(this.preferences.zoomInSpeed){V91=this.preferences.zoomInSpeed;}else if(!V91){V91=0.7;}if(k82 && k82.preventDefault){k82.preventDefault();}function D9R(f3i){i5o.D0H();return function(h4n){var y4B;t7i.zoomSet(h4n,f3i);if(t7i.animations.zoom.hasCompleted){y4B="la";y4B+="y";y4B+="ou";y4B+="t";if(t7i.runAppend("zoomIn",arguments)){return;}t7i.changeOccurred(y4B);if(t7i.continuousZoom){t7i.continuousZoom.execute();}}};}this.cancelTouchSingleClick=!![];t7i=this;for(var D6q in this.charts){g$b=this.charts[D6q];H9v=g$b.width * V91 / this.layout.candleWidth;if(g$b.maxTicks - H9v < "1" << 0){i5o.D0J(7);var Q6_=i5o.q7n(9,10);H9v=g$b.maxTicks - Q6_;}if(H9v < this.minimumZoomTicks){H9v=this.minimumZoomTicks;}W44=this.chart.width / H9v;this.layout.setSpan=null;this.layout.range=null;this.animations.zoom.run(D9R(g$b),this.layout.candleWidth,W44);}};T68.ChartEngine.prototype.createCrosshairs=function(){var t3X,h_X,q$o,J5n;t3X="createCrossh";t3X+="airs";h_X="cre";h_X+="a";h_X+="teCrosshairs";if(this.runPrepend(h_X,arguments)){return;}if(!this.manageTouchAndMouse || this.mainSeriesRenderer && this.mainSeriesRenderer.nonInteractive){return;}q$o=this.controls.crossX;J5n=this.controls.crossY;if(q$o){if(!q$o.onmousedown){q$o.onmousedown=function(o09){if(o09.preventDefault){o09.preventDefault();}return ![];};}}if(J5n){if(!J5n.onmousedown){J5n.onmousedown=function(x1_){if(x1_.preventDefault){x1_.preventDefault();}return ![];};}}this.runAppend(t3X,arguments);};B3k=!1;T68.ChartEngine.prototype.mousemoveinner=T68.ChartEngine.prototype.mousemoveinner || (function(H6J,K8D){i5o.D0H();if(!B3k){console.error("interaction feature requires activating movement feature.");}B3k=!!({});});};M=r1$=>{var g9l=A2IFV;var V7k;g9l.D0H();V7k=typeof _CIQ !== "undefined"?_CIQ:r1$.CIQ;if(!V7k.Marker){V7k.ChartEngine.helpersToRegister.push(function(k9D){k9D.markerHelper={chartMap:{},classMap:{},domMarkers:[],highlighted:[]};});V7k.ChartEngine.prototype.addToHolder=function(Z_A){var D88,r6p,e0W,W_v;D88=this.panels[Z_A.params.panelName];if(!D88){return;}r6p=Z_A.params;e0W=Z_A.node;W_v=Z_A.stxNodeCreator;if(W_v && W_v.prepareForHolder){e0W=W_v.prepareForHolder(Z_A);}if(r6p.chartContainer){this.container.appendChild(Z_A.node);}else if(r6p.includeAxis){D88.holder.appendChild(Z_A.node);}else {D88.subholder.appendChild(e0W);}Z_A.chart=D88.chart;if(W_v && W_v.addToHolder){W_v.addToHolder(Z_A);}g9l.D0H();if(W_v && W_v.expand){V7k.Marker.initializeScrollBehavior(W_v);}};V7k.ChartEngine.prototype.getMarkerArray=function(C3m,I6v){var X61,y4X,r4k;X61=[];g9l.D0H();for(var A1g in this.markers){for(var k0J="0" ^ 0;k0J < this.markers[A1g].length;k0J++){y4X="pa";y4X+="n";y4X+="elNam";y4X+="e";r4k=this.markers[A1g][k0J];if(C3m == y4X){if(r4k.params.panelName == I6v){X61.push(r4k);}}else if(C3m == "label"){if(A1g == I6v){X61.push(r4k);}}else if(C3m == "all"){X61.push(r4k);}}}return X61;};V7k.ChartEngine.prototype.removeFromHolder=function(L1Z){var N17,d_g,p1_,w_c,f53,k6S;N17=this.panels[L1Z.params.panelName];if(N17){if(L1Z.node.parentNode == N17.holder){N17.holder.removeChild(L1Z.node);}else if(L1Z.node.parentNode == N17.subholder){N17.subholder.removeChild(L1Z.node);}else if(L1Z.node.parentNode == this.container){this.container.removeChild(L1Z.node);}}d_g=this.markers[L1Z.params.label];if(!d_g){return;}for(p1_=0;p1_ < d_g.length;p1_++){if(d_g[p1_] === L1Z){d_g.splice(p1_,1);break;}}w_c=this.markerHelper.chartMap[L1Z.chart.name];if(w_c){for(p1_=0;p1_ < w_c.markers.length;p1_++){if(w_c.markers[p1_] === L1Z){w_c.markers.splice(p1_,1);break;}}}f53=this.markerHelper.classMap[L1Z.className];if(f53){k6S=f53[L1Z.params.panelName];if(k6S){for(p1_=0;p1_ < k6S.length;p1_++){if(k6S[p1_] === L1Z){k6S.splice(p1_,1);break;}}}}};V7k.ChartEngine.prototype.moveMarkers=function(k5J,B_S){var k8A,U3Z;k8A=this.getMarkerArray("panelName",k5J);for(var k3A=0;k3A < k8A.length;k3A++){k8A[k3A].params.panelName=B_S;}for(var q4A in this.markerHelper.classMap){U3Z=this.markerHelper.classMap[q4A][k5J];if(U3Z){this.markerHelper.classMap[q4A][B_S]=U3Z;delete this.markerHelper.classMap[q4A][k5J];}}};V7k.ChartEngine.prototype.establishMarkerTicks=function(){var I6z,q0B;I6z=this.markerHelper.chartMap;for(var L4x in I6z){q0B=I6z[L4x];if(q0B.dataSetLength == this.charts[L4x].dataSet.length)continue;for(var o$V=0;o$V < q0B.markers.length;o$V++){this.setMarkerTick(q0B.markers[o$V]);}}};V7k.ChartEngine.prototype.futureTickIfDisplayed=function(u0o){var S7K,Z$k,Y8B,S9G,w6m,m0g,F03,R3e,j7b;S7K=u0o.chart;if(S7K.dataSet.length < 1){return;}Z$k=S7K.xaxis[S7K.xaxis.length - 1].DT;g9l.H6P(90);var W$k=g9l.q7n(4740640,60008,8,10);Z$k=new Date(Z$k.getTime() - this.timeZoneOffset * W$k);if(u0o.params.x > Z$k){return;}Y8B=S7K.maxTicks - S7K.dataSegment.length;S9G=S7K.dataSet.length + Y8B;g9l.D0H();F03=new Date(+S7K.dataSet[S7K.dataSet.length - 1].DT);R3e=this.standardMarketIterator(F03,null,S7K);j7b=u0o.params.x.getTime();for(var a_$=S7K.dataSet.length;a_$ < S9G;a_$++){w6m=F03.getTime();F03=R3e.next();m0g=F03.getTime();if(m0g == j7b){u0o.tick=a_$;return;}else if(m0g > j7b && w6m < j7b){g9l.H6P(7);u0o.tick=Math.max(g9l.q7n(1,a_$),0);return;}}};V7k.ChartEngine.prototype.setMarkerTick=function(Y6Y){var w8d,K8_,U_k,w0Z,Z7h,J9a;w8d=Y6Y.chart;if(Y6Y.params.xPositioner == "master" && Y6Y.params.x){Y6Y.tick=Math.floor(Y6Y.params.x / this.layout.periodicity);return;}else if(Y6Y.params.xPositioner == "date" && Y6Y.params.x){w0Z=Y6Y.params.x.getTime();for(var J_b=0;J_b < w8d.dataSet.length;J_b++){Z7h=w8d.dataSet[J_b];U_k=Z7h.DT.getTime();K8_=U_k;if(J_b > +"0"){K8_=w8d.dataSet[J_b - 1].DT.getTime();}if(U_k == w0Z){Y6Y.tick=J_b;return;}else if(U_k > w0Z && K8_ < w0Z){g9l.H6P(7);Y6Y.tick=Math.max(g9l.S40(1,J_b),0);return;}else if(w0Z < U_k){Y6Y.tick=null;return;}}if(w8d.dataSet.length < 1){return;}J9a=new Date(+w8d.dataSet[J_b - 1].DT);if(J9a.getTime() < w0Z){Y6Y.params.future=!!({});}Y6Y.tick=null;;}};V7k.ChartEngine.prototype.positionMarkers=function(){var m1F,Z9E,Z_e,H9L,p$n,w9A,n$w;m1F=this;Z9E=this.chart;if(!m1F.markerHelper){return;}if(this.markerDelay || this.markerDelay === ("0" ^ 0)){if(!this.markerTimeout){this.markerTimeout=setTimeout(l2J,this.markerDelay);}}else {l2J();}Z_e=this.getFirstLastDataRecord(Z9E.dataSegment,"tick");g9l.a9S();H9L=this.getFirstLastDataRecord(Z9E.dataSegment,"tick",!"");if(!Z_e || !H9L){return;}p$n=this.getMarkerArray("all");for(var w1E=0;w1E < p$n.length;w1E++){w9A=p$n[w1E];n$w=w9A.stxNodeCreator;if(Z_e.tick <= w9A.tick && w9A.tick <= H9L.tick){if(n$w && n$w.drawMarker){n$w.drawMarker(w9A);}}else if(w9A.attached && n$w.expand){n$w.expand.style.visibility="hidden";}}function l2J(){var R2u,i_U,T3s,h_S;if(m1F.runPrepend("positionMarkers",arguments)){return;}m1F.markerTimeout=null;for(var L7R in m1F.markerHelper.classMap){for(var N9K in m1F.markerHelper.classMap[L7R]){R2u=m1F.markerHelper.classMap[L7R][N9K];i_U=m1F.panels[N9K];if(R2u.length){T3s={stx:m1F,arr:R2u,panel:i_U};T3s.firstTick=i_U.chart.dataSet.length - i_U.chart.scroll;T3s.lastTick=T3s.firstTick + i_U.chart.dataSegment.length;h_S=R2u[0].constructor.placementFunction;if(h_S){h_S(T3s);}else {m1F.defaultMarkerPlacement(T3s);}}}}g9l.D0H();m1F.runAppend("positionMarkers",arguments);}};V7k.Marker=V7k.Marker || (function(z36){var s2h,B2G,K8R,h2M,P2h,u8J,d$2;this.params={xPositioner:"date",yPositioner:"value",panelName:"chart",permanent:!"1",label:"generic",includeAxis:!"1"};V7k.extend(this.params,z36);if(!this.params.node){s2h="D";s2h+="I";s2h+="V";this.params.node=document.createElement(s2h);}B2G=this.params.stx;if(!B2G){K8R="Marker created";K8R+=" without specifying stx";console.log(K8R);return;}if(!this.className){this.className="CIQ.Marker";}if(V7k.derivedFrom(this.params.node,V7k.Marker.NodeCreator)){this.stxNodeCreator=this.params.node;this.node=this.stxNodeCreator.node;}else {this.node=this.params.node;}h2M=this.params.label;if(!B2G.markers[h2M]){B2G.markers[h2M]=[];}B2G.markers[h2M].push(this);P2h=B2G.panels[this.params.panelName];this.chart=P2h.chart;if(!B2G.markerHelper.chartMap[this.chart.name]){B2G.markerHelper.chartMap[this.chart.name]={dataSetLength:0,markers:[]};}B2G.markerHelper.chartMap[this.chart.name].markers.push(this);u8J=B2G.markerHelper.classMap[this.className];if(!u8J){u8J=B2G.markerHelper.classMap[this.className]={};}if(!u8J[this.params.panelName]){u8J[this.params.panelName]=[];}u8J[this.params.panelName].push(this);d$2=this.stxNodeCreator && this.stxNodeCreator.deferAttach;if(!d$2){B2G.addToHolder(this);}B2G.setMarkerTick(this);if(this.stxNodeCreator && this.stxNodeCreator.drawMarker){this.stxNodeCreator.drawMarker(this);}});V7k.Marker.prototype.remove=function(){this.params.stx.removeFromHolder(this);};V7k.Marker.prototype.click=function(W4Y){var S3q;if(typeof arguments[0] === "number"){W4Y={cx:arguments["0" - 0],cy:arguments[+"1"],panel:arguments[3]};}var {cx:i2m, cy:j$b, panel:W6e}=W4Y;g9l.a9S();if(!this.params.stx){return;}S3q=this.params.node;if(S3q.click){S3q.click(i2m,j$b,this,W6e);}};V7k.Marker.prototype.doubleClick=function({cx:h7E, cy:x84, panel:C10}){g9l.D0H();return ![];};V7k.Marker.prototype.render=function(){g9l.D0H();var X7q,P7n;X7q=[this];P7n={stx:this.params.stx,arr:X7q,panel:this.params.stx.panels[this.params.panelName],showClass:this.showClass};this.constructor.placementFunction(P7n);};V7k.Marker.removeByLabel=function(Q9H,B05){var x9I,c3$,x7L;x9I="l";x9I+="ab";x9I+="e";x9I+="l";c3$=Q9H.getMarkerArray(x9I,B05);for(var v5k="0" ^ 0;v5k < c3$.length;v5k++){x7L=c3$[v5k];Q9H.removeFromHolder(x7L);if(x7L.stxNodeCreator && x7L.stxNodeCreator.remove){x7L.stxNodeCreator.remove(x7L);}}Q9H.draw();};V7k.Marker.positionContentVerticalAndHorizontal=function(H5B){var v95,Z3y,B9R,N_q,m3V,g1m,a3X,W23,Y4p,L8u,j_T,p9e;v95=H5B.querySelectorAll(".stx-marker-expand")[0];if(!v95 || !V7k.trulyVisible(v95)){return;}g9l.a9S();Z3y=v95.offsetHeight;B9R=v95.style;B9R.left=B9R.right="";B9R.bottom=B9R.top="";N_q=getComputedStyle(v95);m3V=N_q.left;g1m=N_q.bottom;g9l.H6P(36);var m8S=g9l.q7n(19,3,12);a3X=H5B.offsetLeft + parseInt(m3V,m8S);W23=parseInt(g1m,10);Y4p=H5B.offsetTop - (W23 + Z3y - H5B.offsetHeight);L8u=H5B.parentNode.offsetWidth;j_T=H5B.parentNode.offsetHeight;if(a3X + v95.offsetWidth > L8u){B9R.right=m3V;B9R.left="auto";}if(H5B.offsetTop <= j_T){if(Y4p > j_T - Z3y){B9R.top=j_T - H5B.offsetTop - Z3y + "px";B9R.bottom="auto";}}else {g9l.H6P(0);B9R.top=g9l.q7n(j_T,"px");}if(H5B.offsetTop + H5B.offsetHeight >= 0){if(Y4p < "0" >> 32){p9e="p";p9e+="x";B9R.top=-H5B.offsetTop + p9e;B9R.bottom="auto";}}else {B9R.bottom="0px";}};V7k.Marker.initializeScrollBehavior=function(b_9){var i7h;var {expand:q7J}=b_9;if(!q7J){return;}q7J.addEventListener(V7k.wheelEvent,o8u=>{return o8u.stopPropagation();});var {scrollbarStyling:w04}=V7k.UI || ({});if(w04){w04.refresh(q7J);}else {i7h="scr";i7h+="o";i7h+="l";i7h+="l";q7J.style.overflowY=i7h;}};V7k.ChartEngine.prototype.getBarBounds=function(X7s){var D6f,i7Y,B6_,o3X,L8E,S1S,y5v;D6f="p";D6f+="an";g9l.a9S();D6f+="d";D6f+="f";i7Y=this.layout.chartType;B6_=this.layout.aggregationType;if(B6_ == D6f){o3X={high:Math.max(X7s.pfOpen,X7s.pfClose),low:Math.min(X7s.pfOpen,X7s.pfClose)};}else {o3X={high:X7s.High,low:X7s.Low};}if(X7s.markerHigh){o3X.high=X7s.markerHigh;}if(X7s.markerLow){o3X.low=X7s.markerLow;}if(X7s.Open === undefined){L8E=X7s.Close;}if(X7s.High === undefined){S1S=Math.max(X7s.Open || L8E,X7s.Close);}if(X7s.Low === undefined){y5v=Math.min(X7s.Open || L8E,X7s.Close);}if(!o3X.high && o3X.high !== 0){o3X.high=S1S;}if(!o3X.low && o3X.low !== 0){o3X.low=y5v;}return o3X;};V7k.ChartEngine.prototype.defaultMarkerPlacement=function(g15){var e5s,b$P,u6m,J_X,f1Q,R3a,H40,X3o,C2k,j2$,y6y,z_y,L4w,W7f,z$y,x7i,T_x,u7A,Y7o,i7M,K2M,C$3,X5j,b_J,v2I,A6D,t6b,U2y,X8Y,J2y,E7O,N8e,h7v,E7W;e5s="Clo";e5s+="s";e5s+="e";b$P=g15.panel;u6m=g15.yAxis?g15.yAxis:g15.panel.yAxis;J_X=b$P.chart;f1Q=g15.stx;R3a=f1Q.chart.highLowBars;H40=J_X.defaultPlotField;if(!H40 || R3a){H40=e5s;}X3o={};for(var K_N="0" - 0;K_N < g15.arr.length;K_N++){C2k="a";C2k+="u";C2k+="t";C2k+="o";j2$=g15.arr[K_N];y6y=j2$.params;if(j2$.params.box)continue;z_y=j2$.node;if(!j2$.clientWidth){j2$.clientWidth=z_y.clientWidth;}if(!j2$.clientHeight){j2$.clientHeight=z_y.clientHeight;}L4w=null;W7f=y6y.xPositioner;z$y=y6y.yPositioner;x7i=j2$.tick;T_x=J_X.dataSet;u7A=j2$.clientWidth;if(W7f != "none"){if(W7f == "bar" && y6y.x){if(y6y.x < J_X.xaxis.length){Y7o=J_X.xaxis[y6y.x];if(Y7o){L4w=Y7o.data;}}g9l.H6P(36);var g9N=g9l.q7n(11,0,10);z_y.style.left=Math.round(f1Q.pixelFromBar(y6y.x,J_X) - u7A / +"2") + g9N + "px";}else {if(!x7i && x7i !== 0){if(y6y.future && J_X.scroll < J_X.maxTicks){f1Q.futureTickIfDisplayed(j2$);x7i=j2$.tick;if(!x7i && x7i !== 0){z_y.style.left="-1000px";continue;}}else {z_y.style.left="-1000px";continue;}}if(x7i < T_x.length){L4w=T_x[x7i];}j2$.leftpx=Math.round(f1Q.pixelFromTick(x7i,J_X) - J_X.left - u7A / 2);j2$.rightEdge=j2$.leftpx + u7A;z_y.style.left=j2$.leftpx + "px";if(x7i < g15.firstTick && j2$.rightEdge < J_X.left - 50)continue;;}if(!L4w){g9l.D0J(7);var L3U=g9l.S40(20,21);L4w=T_x[T_x.length - ("1" | L3U)];};}else if(z$y.indexOf("candle") > -1){i7M=getComputedStyle(z_y).left;if(i7M){K2M=f1Q.barFromPixel(parseInt(i7M,10),J_X);if(K2M >= 0){L4w=J_X.xaxis[K2M].data;if(!L4w){g9l.D0J(35);var W9j=g9l.q7n(11,8,5,3,175);L4w=T_x[T_x.length - W9j];};}}}z_y.style.top=C2k;C$3=y6y.y;X5j=j2$.clientHeight;if(z$y != "none"){v2I="b";v2I+="o";v2I+="ttom";A6D="o";A6D+="n_";A6D+="candle";t6b="und";t6b+="er_candle";g9l.D0J(0);var p6m=g9l.q7n(859,15);g9l.D0J(52);var R$G=g9l.q7n(96978,8817,12);g9l.D0J(91);var a8O=g9l.q7n(9,1,6,5,9);g9l.H6P(15);var U59=g9l.q7n(6,135,96);g9l.D0J(11);var X2f=g9l.S40(0,4,39,10);g9l.D0J(39);var z7j=g9l.q7n(27958,3,23961);g9l.H6P(0);var h1B=g9l.S40(604,9066);U2y=z$y + ((p6m,R$G) > "238.66" * a8O?"-":(U59,"7990" * X2f) < (996.14,z7j)?+"0x18f":h1B) + z_y.style.left;X8Y=y6y.chartContainer?f1Q.height:b$P.yAxis.bottom;J2y=0;E7O=0;if(typeof X3o[U2y] == "undefined"){X3o[U2y]=0;}E7O=X3o[U2y];X3o[U2y]+=X5j;if(z$y == "value" && (C$3 || C$3 === "0" - 0)){g9l.H6P(92);var l3Z=g9l.S40(1,58,18,16,20);J2y=Math.round(X8Y - f1Q.pixelFromPrice(C$3,b$P,u6m) - X5j / l3Z) + "px";}else if((z$y == "below_candle" || z$y == t6b) && L4w){N8e="h";N8e+="i";N8e+="g";N8e+="h";b_J=L4w[H40];if(R3a){b_J=f1Q.getBarBounds(L4w)[u6m.flipped?N8e:"low"];}J2y=Math.round(X8Y - f1Q.pixelFromPrice(b_J,b$P,u6m) - X5j - E7O) + "px";}else if(z$y == A6D && L4w){h7v="p";h7v+="x";b_J=L4w[H40];if(R3a){g9l.H6P(41);var a2S=g9l.S40(3,12,38);b_J=(L4w.Low + L4w.High) / a2S;}g9l.D0J(39);var i49=g9l.S40(36,19,15);J2y=Math.round(X8Y - f1Q.pixelFromPrice(b_J,b$P,u6m) - X5j / i49 - E7O) + h7v;}else if(z$y == "top"){J2y=Math.round(X8Y - X5j - E7O - b$P.top) + "px";}else if(z$y == v2I){E7W="p";E7W+="x";J2y=Math.round(E7O) + E7W;}else if(L4w){b_J=L4w[H40];if(R3a){b_J=f1Q.getBarBounds(L4w)[u6m.flipped?"low":"high"];}J2y=Math.round(X8Y - f1Q.pixelFromPrice(b_J,b$P,u6m) + E7O) + "px";}if(z_y.style.bottom != J2y){z_y.style.bottom=J2y;}}V7k.Marker.positionContentVerticalAndHorizontal(z_y);}};V7k.Marker.NodeCreator=function(){};V7k.Marker.NodeCreator.toNode=function(){g9l.D0H();return this.node;};V7k.Marker.Simple=function(t8v){var O6A,p$M,L0N,m2d,R3t;O6A=this.node=document.createElement("div");O6A.className="stx-marker";function z3j(){g9l.D0H();V7k.Marker.positionContentVerticalAndHorizontal(O6A);}O6A.classList.add(t8v.type);if(t8v.category){O6A.classList.add(t8v.category);}p$M=V7k.newChild(O6A,"div","stx-visual");V7k.newChild(O6A,"div","stx-stem");if(t8v.type == "callout"){m2d="di";m2d+="v";R3t=V7k.newChild(p$M,"div","stx-marker-content");V7k.newChild(R3t,"h4",null,t8v.headline);L0N=V7k.newChild(R3t,m2d,"stx-marker-expand");V7k.newChild(L0N,"p",null,t8v.story);}else {L0N=V7k.newChild(O6A,"div","stx-marker-expand");V7k.newChild(L0N,"h4",null,t8v.headline);V7k.newChild(L0N,1176 > (118.59,298.1)?"p":736.93 == (395.28,2710)?(4.21e+3,!({})):(0x256c,4.58e+3),null,t8v.story);V7k.safeClickTouch(L0N,function(k1Y){g9l.D0H();O6A.classList.toggle("highlight");});}V7k.safeClickTouch(p$M,function(w6j){O6A.classList.toggle("highlight");setTimeout(z3j,10);});this.nodeType="Simple";this.expand=L0N;};V7k.inheritsFrom(V7k.Marker.Simple,V7k.Marker.NodeCreator,!({}));}};B=e_g=>{var s4_=A2IFV;var t7c,y8h,L5_,h3x,a84,v_i,u4k,F48;t7c="undefin";t7c+="ed";y8h=typeof _CIQ !== t7c?_CIQ:e_g.CIQ;L5_=typeof _timezoneJS !== "undefined"?_timezoneJS:e_g.timezoneJS;h3x=60000 * 60;a84=h3x * 24;v_i=y8h.Market;y8h.Market=function(Z7e){var m40,o7t;m40="un";m40+="defined";this.market_def=![];this.rules=![];this.normalHours=[];this.extraHours=[];this.class_name="Market";if(!L5_.Date){this.tz_lib=Date;;}else {this.tz_lib=L5_.Date;}this.market_tz="";this.hour_aligned=!"1";this.convertOnDaily=!!"";this.enabled_by_default=![];if(typeof Z7e != m40 && Z7e && !y8h.isEmpty(Z7e)){o7t="und";o7t+="ef";o7t+="ined";if(Z7e.market_definition){Z7e=Z7e.market_definition;}if(Z7e.rules){this.rules=Z7e.rules;}if(Z7e.market_tz){this.market_tz=Z7e.market_tz;}if(Z7e.convertOnDaily){this.convertOnDaily=Z7e.convertOnDaily;}if(typeof Z7e.hour_aligned){this.hour_aligned=Z7e.hour_aligned;}if(typeof Z7e.beginningDayOfWeek !== "undefined"){this.beginningDayOfWeek=Z7e.beginningDayOfWeek;}if(typeof Z7e.enabled_by_default !== o7t){if(Z7e.enabled_by_default instanceof Array){this.enabled_by_default=Z7e.enabled_by_default;}}this.market_def=Z7e;if(this.market_def.name === undefined){this.market_def.name="no market name specified";}}else {return;}y8h.Market._createTimeSegments(this);this.getSessionNames();};y8h.Market.Symbology=function(){};y8h.Market.Symbology.isForeignSymbol=function(l7E){return !1;};s4_.D0H();y8h.Market.Symbology.isFuturesSymbol=function(t_D){return !"1";};y8h.Market.Symbology.isRateSymbol=function(M8r){return !({});};y8h.Market.Symbology.isForexSymbol=function(T7a){s4_.D0H();return !({});};y8h.Market.Symbology.isForexMetal=function(v9V,r0t){s4_.a9S();return !({});};y8h.Market.Symbology.isForexFuturesSymbol=function(U$u){if(y8h.Market.Symbology.isForexSymbol(U$u))return !!({});if(y8h.Market.Symbology.isFuturesSymbol(U$u))return !!"1";s4_.D0H();return ![];};y8h.Market.Symbology.factory=function(J6z){return null;;};y8h.Market.Symbology.encodeTermStructureInstrumentSymbol=function(o1j,B_U){var L37;L37="You are trying to call `CIQ.Mar";L37+="ket.Symbology.encodeTe";L37+="rmStructureInstrumentSymbol` but have not imple";L37+="mented it.";s4_.D0H();console.warn(L37);};if(v_i)y8h.extend(y8h.Market,v_i);y8h.Market.prototype.sessions=null;y8h.Market.prototype.beginningDayOfWeek="0" ^ 0;y8h.Market.prototype.getSessionNames=function(){var P1K,e6$;if(!this.rules){this.sessions=[];}else if(!this.sessions){P1K=[];e6$=[];this.rules.map(function(G1C){if(G1C.name && P1K.indexOf(G1C.name) === -("1" | 0)){P1K.push(G1C.name);e6$.push({name:G1C.name,enabled:G1C.enabled?G1C.enabled:!!0});}});this.sessions=e6$;}s4_.D0H();return this.sessions.slice();};y8h.Market.prototype._find_next_segment=function(a3F,v$U){var v5d,c2H,E9O,S_s;if(!this.market_def)return null;if(!this.rules)return null;v5d=new Date(+a3F);c2H=this.newIterator({begin:v5d,interval:1,inZone:this.market_tz,outZone:this.market_tz});if(this._wasOpenIntraDay(v5d)){E9O=this.zseg_match.close_parts.hours;S_s=this.zseg_match.close_parts.minutes;v5d.setHours(E9O);v5d.setMinutes(S_s);c2H=this.newIterator({begin:v5d,interval:1,inZone:this.market_tz,outZone:this.market_tz});}return c2H.next();};y8h.Market.prototype._find_prev_segment=function(l6S,z6M){var B8d,t2X,z4C,D4l,u9Z;if(!this.market_def)return null;if(!this.rules)return null;B8d=new Date(+l6S);s4_.D0H();t2X=this.newIterator({begin:B8d,interval:"1" | 0,inZone:this.market_tz,outZone:this.market_tz});z4C=this._wasOpenIntraDay(B8d);if(z4C === null){B8d=new Date(B8d - 60000);z4C=this._wasOpenIntraDay(B8d);}else {if(z6M && B8d.getHours() === this.zseg_match.open_parts.hours && B8d.getMinutes() === this.zseg_match.open_parts.minutes || !z6M && B8d.getHours() === this.zseg_match.close_parts.hours && B8d.getMinutes() === this.zseg_match.close_parts.minutes){B8d=t2X.previous();}}if(z4C){D4l=this.zseg_match.open_parts.hours;u9Z=this.zseg_match.open_parts.minutes;B8d.setHours(D4l);B8d.setMinutes(u9Z);t2X=this.newIterator({begin:B8d,interval:1,inZone:this.market_tz,outZone:this.market_tz});B8d=t2X.previous();if(this.zseg_match.close_parts.hours === D4l){if(this.zseg_match.close_parts.minutes === u9Z){if(z6M){return t2X.next();}return B8d;}}if(this.zseg_match.adjacent_child){return B8d;}if(z6M){return t2X.next();}return B8d;}return t2X.previous();};y8h.Market.prototype.disableSession=function(i$k,y7W){var v_k;v_k=!({});if(typeof y7W !== "undefined" && y7W){v_k=!!({});}if(i$k){for(var j7C=0;j7C < this.normalHours.length;j7C++){if(this.normalHours[j7C].name === i$k){this.normalHours[j7C].enabled=v_k;}}for(j7C=0;j7C < this.extraHours.length;j7C++){if(this.extraHours[j7C].name === i$k){this.extraHours[j7C].enabled=v_k;}}}};y8h.Market.prototype.enableSession=function(L$k){var D$J;D$J="enable_in";D$J+="stead";this.disableSession(L$k,D$J);};y8h.Market.prototype.enableAllAvailableSessions=function(){var y7N;s4_.a9S();y7N=this.getSessionNames();for(var J3v=0;J3v < y7N.length;J3v++){this.enableSession(y7N[J3v].name);}};y8h.Market.prototype.getClose=function(H3d,V9x,A1C,z2Y){var p4f,R72;if(!this.market_def)return null;if(!this.rules)return null;p4f=H3d;if(!H3d){p4f=new Date();A1C=null;;}p4f=this._convertToMarketTZ(p4f,A1C);if(typeof V9x !== "undefined"){if(this._wasOpenIntraDay(p4f)){if(this.zseg_match.name === V9x){p4f.setHours(this.zseg_match.close_parts.hours,this.zseg_match.close_parts.minutes,+"0",0);p4f=this._convertFromMarketTZ(p4f,z2Y);return p4f;}}}else {if(this._wasOpenDaily(p4f)){R72=this.zseg_match;while(R72.child_){R72=R72.child_;}while(!R72.enabled){R72=R72.parent_;}p4f.setHours(R72.close_parts.hours,R72.close_parts.minutes,0,0);p4f=this._convertFromMarketTZ(p4f,z2Y);return p4f;}}return null;};y8h.Market.prototype.getNextClose=function(v0K,s0Y,V$3){var p$O,d6K,y6G,Q4f;if(!this.market_def)return null;if(!this.rules)return null;p$O=v0K;if(!v0K){p$O=new Date();s0Y=null;;}p$O=this._convertToMarketTZ(p$O,s0Y);if(!this._wasOpenIntraDay(p$O)){d6K=this.newIterator({begin:p$O,interval:1,inZone:this.market_tz,outZone:this.market_tz});p$O=d6K.next();}y6G=p$O.getDate();Q4f=this.zseg_match;while(Q4f.adjacent_child){Q4f=Q4f.adjacent_child;y6G+=1;}p$O.setDate(y6G);p$O.setHours(Q4f.close_parts.hours,Q4f.close_parts.minutes,0,0);p$O=this._convertFromMarketTZ(p$O,V$3);return p$O;};y8h.Market.prototype.getNextOpen=function(z_a,S_7,Z2r){var y72;if(!this.market_def)return null;if(!this.rules)return null;y72=z_a;if(!z_a){y72=new Date();S_7=null;;}y72=this._convertToMarketTZ(y72,S_7);y72=this._find_next_segment(y72);if(this.zseg_match.adjacent_parent){y72=this.getNextOpen(y72,this.market_tz,this.market_tz);y72=this._convertFromMarketTZ(y72,Z2r);return y72;}y72.setHours(this.zseg_match.open_parts.hours);y72.setMinutes(this.zseg_match.open_parts.minutes);y72=this._convertFromMarketTZ(y72,Z2r);return y72;};y8h.Market.prototype.getOpen=function(d$d,g0l,J6e,M0P){var t6t,T1$;if(!this.market_def)return null;if(!this.rules)return null;t6t=d$d;if(!d$d){t6t=new Date();J6e=null;;}t6t=this._convertToMarketTZ(t6t,J6e);if(typeof g0l !== "undefined"){if(this._wasOpenIntraDay(t6t)){if(this.zseg_match.name == g0l){t6t.setHours(this.zseg_match.open_parts.hours,this.zseg_match.open_parts.minutes,0,"0" >> 32);t6t=this._convertFromMarketTZ(t6t,M0P);return t6t;}}}else {if(this._wasOpenDaily(t6t)){T1$=this.zseg_match;while(T1$.parent_){T1$=T1$.parent_;}while(!T1$.enabled){T1$=T1$.child_;}t6t.setHours(T1$.open_parts.hours,T1$.open_parts.minutes,0,0);t6t=this._convertFromMarketTZ(t6t,M0P);return t6t;}}return null;};y8h.Market.prototype.getNormalOpen=function(){var y3t;y3t="F";y3t+="O";y3t+="RE";y3t+="X";var {market_def:L_K, rules:k$b}=this;if(!(L_K && k$b))return "00:00";if(L_K.normal_daily_open)return L_K.normal_daily_open;if(L_K.name === y3t)return "17:00";return k$b.find(({name:h8c})=>!h8c || h8c === "").open;};y8h.Market.prototype.getNormalClose=function(){var Q8M;Q8M="FO";Q8M+="R";Q8M+="E";Q8M+="X";var {market_def:M5n, rules:a8e}=this;if(!(M5n && a8e))return "24:00";if(M5n.normal_daily_close)return M5n.normal_daily_close;if(M5n.name === Q8M)return "17:00";return a8e.filter(({dayofweek:e4R, name:g6H})=>e4R && (!g6H || g6H === "")).pop().close;};y8h.Market.prototype.getPreviousClose=function(m63,q9S,A9W){var G$Z;if(!this.market_def)return null;if(!this.rules)return null;G$Z=m63;if(!m63){G$Z=new Date();q9S=null;;}G$Z=this._convertToMarketTZ(G$Z,q9S);G$Z=this._find_prev_segment(G$Z,!!0);if(this.zseg_match.adjacent_child){return this.getPreviousClose(G$Z,this.market_tz,this.market_tz);}G$Z.setHours(this.zseg_match.close_parts.hours);G$Z.setMinutes(this.zseg_match.close_parts.minutes);G$Z=this._convertFromMarketTZ(G$Z,A9W);s4_.D0H();return G$Z;};y8h.Market.prototype.getPreviousOpen=function(t28,S4s,Z1r){s4_.D0H();var A4F;if(!this.market_def)return null;if(!this.rules)return null;A4F=t28;if(!t28){A4F=new Date();S4s=null;;}A4F=this._convertToMarketTZ(A4F,S4s);A4F=this._find_prev_segment(A4F,!!"1");if(this.zseg_match.adjacent_parent){return this.getPreviousOpen(A4F,this.market_tz,this.market_tz);}A4F.setHours(this.zseg_match.open_parts.hours);A4F.setMinutes(this.zseg_match.open_parts.minutes);A4F=this._convertFromMarketTZ(A4F,Z1r);return A4F;};y8h.Market.prototype.getSession=function(A8U,d4S){s4_.D0H();A8U=this._convertToMarketTZ(A8U,d4S);if(this._wasOpenIntraDay(A8U) && this.zseg_match){return this.zseg_match.name;}return null;};y8h.Market.prototype.marketZoneNow=function(){s4_.D0H();return this._convertToMarketTZ(new Date());};y8h.Market.prototype.isHourAligned=function(){return this.hour_aligned;};y8h.Market.prototype.isOpen=function(){var I65;I65=new Date();if(this.market_tz){I65=new this.tz_lib(I65.getTime(),this.market_tz);}return this._wasOpenIntraDay(I65);};y8h.Market.prototype.isMarketDay=function(){var u2V;u2V=new Date();if(this.market_tz){u2V=new this.tz_lib(u2V.getTime(),this.market_tz);}return this._wasOpenDaily(u2V);};y8h.Market.prototype.isMarketDate=function(h$M){s4_.D0H();return this._wasOpenDaily(h$M);};y8h.Market.prototype.newIterator=function(p1v){var B81,P6X,w1w,y10,Z4S,U7i,M7n;B81=!({});if(p1v.periodicity){B81=p1v.periodicity;}else if(p1v.multiple){B81=p1v.multiple;}P6X=p1v.interval;if(!P6X){w1w="m";w1w+="in";w1w+="u";w1w+="te";P6X=w1w;}if(P6X == "hour")P6X=60;if(!B81){B81=1;}if(!p1v.begin){p1v.begin=new Date();p1v.inZone=null;}if(P6X == parseInt(P6X,10)){P6X=parseInt(P6X,10);if(p1v.periodicity < 1 / 60){y10="mil";y10+="l";y10+="isecon";y10+="d";B81=B81 * P6X * 60000;P6X=y10;}else if(p1v.periodicity < 1){Z4S="s";Z4S+="econd";B81=B81 * P6X * 60;P6X=Z4S;}else {B81=B81 * P6X;P6X="minute";}}if(p1v.timeUnit){U7i="secon";U7i+="d";M7n="mill";M7n+="isecond";if(p1v.timeUnit === M7n){P6X=p1v.timeUnit;}else if(p1v.timeUnit === U7i){P6X=p1v.timeUnit;}else if(p1v.timeUnit === "tick"){P6X="second";}}if(P6X == "tick")P6X="second";p1v.interval=P6X;p1v.multiple=B81;p1v.market=this;return new y8h.Market.Iterator(p1v);};y8h.Market.prototype._wasOpenDaily=function(N6c){return this._was_open(N6c,![]);};y8h.Market.prototype._wasOpenIntraDay=function(K1a){return this._was_open(K1a,!!({}));};y8h.Market.prototype._was_open=function(X_4,O15){var L$6,S_d,U9s,S7C,g5K,Q5Q,f_8,C1w,L6p,b6d,M0b,Y7_,I96;L$6=this.zseg_match;this.zopen_hour=0;this.zopen_minute="0" ^ 0;this.zclose_hour=0;this.zclose_minute=0;this.zmatch_open=!({});this.zseg_match=null;if(!this.market_def || !this.rules){this.zclose_hour=24;return !!"1";}S_d=!!"";U9s=!!0;S7C=X_4.getFullYear();g5K=X_4.getMonth() + 1;Q5Q=X_4.getDay();s4_.a9S();f_8=X_4.getDate();C1w=X_4.getHours();L6p=X_4.getMinutes();b6d=X_4.getSeconds();Y7_=C1w * 60 * +"60" + L6p * 60 + b6d;if(typeof O15 === "undefined"){O15=!![];}for(I96=0;I96 < this.normalHours.length;I96++){M0b=this.normalHours[I96];if(!M0b.enabled){continue;}S_d=M0b.dayofweek === Q5Q;if(S_d && O15){S_d=Y7_ >= M0b.open && Y7_ < M0b.close;}if(S_d){if(!O15 && this.zseg_match){if(M0b.open_parts.hours > this.zopen_hour || M0b.open_parts.hours == this.zopen_hour && M0b.open_parts.minutes > this.zopen_minute){continue;}}if(M0b !== L$6 && !M0b.adjacent_parent && !M0b.adjacent_child){this.shouldResetToBeginningOfSegment=!!({});}this.zopen_hour=M0b.open_parts.hours;this.zopen_minute=M0b.open_parts.minutes;this.zclose_hour=M0b.close_parts.hours;this.zclose_minute=M0b.close_parts.minutes;this.zmatch_open=Y7_ === M0b.open;this.zseg_match=M0b;if(O15)break;}}for(I96=+"0";I96 < this.extraHours.length;I96++){M0b=this.extraHours[I96];if(!M0b.enabled){continue;}if((1455 < (+"1540",9585)?"2638" >> 0 < (327.75,6113)?(6009,988.33) > +"839.81"?"*":"X":!!"":![]) === M0b.year || S7C === M0b.year){if(g5K === M0b.month && f_8 === M0b.day){U9s=!O15 && M0b.open || Y7_ >= M0b.open && Y7_ < M0b.close;if(!U9s && this.zseg_match){S_d=![];this.zopen_hour=0;this.zopen_minute=0;this.zclose_hour=0;this.zclose_minute="0" * 1;this.zmatch_open=!!"";this.zseg_match=null;}if(U9s){if(!O15 && this.zseg_match){if(M0b.open_parts.hours > this.zopen_hour || M0b.open_parts.hours == this.zopen_hour && M0b.open_parts.minutes > this.zopen_minute){continue;}}this.zopen_hour=M0b.open_parts.hours;this.zopen_minute=M0b.open_parts.minutes;this.zclose_hour=M0b.close_parts.hours;this.zclose_minute=M0b.close_parts.minutes;this.zmatch_open=Y7_ === M0b.open;this.zseg_match=M0b;if(O15)break;}}}}return this.zseg_match;};y8h.Market.prototype._wasClosed=function(A6m){return !this._was_open(A6m,!!"1");};y8h.Market.prototype._wasOpen=function(C_A){return this._was_open(C_A,!!({}));};y8h.Market.prototype._tzDifferenceMillis=function(G0M,I0_,U1y){var f_E,f_a,t8u,t0c;f_E=0;f_a=G0M;t8u=G0M;t0c=f_a.getTimezoneOffset() - t8u.getTimezoneOffset();f_E=t0c * 60 * 1000;return f_E;};y8h.Market._createTimeSegments=function(f3z){var a_f,t1e,V_B,L0y,c0b,o5b,Z5u,z9T,w8j;a_f=function(e3l,U$N){s4_.D0H();if(e3l.close_parts.hours === 24 && U$N.open_parts.hours === 0){if(U$N.open_parts.minutes === ("0" ^ 0)){if(t1e.dayofweek === z9T.dayofweek - 1){return !!1;}if(t1e.dayofweek === 6 && z9T.dayofweek === "0" >> 0){return !!({});}}}return !!0;};for(var O4o=0;O4o < f3z.rules.length;O4o++){V_B="n";V_B+="a";V_B+="m";V_B+="e";L0y="und";L0y+="efine";L0y+="d";c0b=JSON.parse(JSON.stringify(f3z.rules[O4o]));if(typeof c0b.open === L0y && typeof c0b.close === "undefined"){o5b="0";o5b+="0:";o5b+="00";c0b.open="00:00";c0b.close=o5b;}if(!c0b.hasOwnProperty(V_B)){c0b.name="";}try{Z5u="und";Z5u+="ef";Z5u+="i";Z5u+="ned";if(typeof c0b.dayofweek !== Z5u){c0b.year="*";z9T=u4k._createDayOfWeekSegment(f3z,c0b);if(t1e){if(t1e.dayofweek === z9T.dayofweek){t1e.child_=z9T;z9T.parent_=t1e;}else {if(a_f(t1e,z9T)){t1e.adjacent_child=z9T;z9T.adjacent_parent=t1e;}}}t1e=z9T;}else if(typeof c0b.date !== "undefined"){c0b.isDayOfWeek=!"1";c0b.dayofweek=-("1" ^ 0);z9T=u4k._createDateTimeSegment(f3z,c0b);}else {console.log("Error, unknown rule type " + c0b);}if(f3z.enabled_by_default){for(var C3X=0;C3X < f3z.enabled_by_default.length;C3X++){w8j=f3z.enabled_by_default[C3X];if(z9T.name === w8j){z9T.enabled=!![];break;}}}else {;}}catch(z5W){var Q_4;Q_4="Error, creating market ru";Q_4+="les ";console.log(Q_4 + z5W);}}};y8h.Market._timeSegment={};u4k=y8h.Market._timeSegment;u4k.re_wild_card_iso=/^(\*)-(\d\d)-(\d\d)$/;u4k.re_regular_iso=/^(\d\d\d\d)-(\d\d)-(\d\d)$/;u4k.re_split_hours_minutes=/^(\d\d):(\d\d)$/;u4k.re_split_hour_minutes=/^(\d):(\d\d)$/;u4k._hashCode=function(S9M){var X3$,r33,u_U,Y$4;X3$=+"0";if(S9M.length === +"0")return X3$;for((r33=0,Y$4=S9M.length);r33 < Y$4;r33++){u_U=S9M.charCodeAt(r33);X3$=(X3$ << 5) - X3$ + u_U;X3$|=0;;}return X3$;};u4k._splitHoursMinutes=function(a4y){var s9m,c4Q;s9m=u4k.re_split_hour_minutes.exec(a4y);c4Q={hours:NaN,minutes:NaN};if(s9m === null){s9m=u4k.re_split_hours_minutes.exec(a4y);if(s9m === null){return c4Q;}}c4Q.hours=parseInt(s9m[1],10);c4Q.minutes=parseInt(s9m[2],10);return c4Q;};u4k._createDayOfWeekSegment=function(T76,d21){var J7L;J7L={name:d21.name,isDayOfWeek:!!({}),dayofweek:d21.dayofweek,date_str:(602.3,378) > 6960?0xc30:"*",open_parts:u4k._splitHoursMinutes(d21.open),close_parts:u4k._splitHoursMinutes(d21.close),open:u4k._secSinceMidnight(T76,d21.open,!![]),close:u4k._secSinceMidnight(T76,d21.close,!!0),child_:!({}),parent_:!1,adjacent_child:!({}),adjacent_parent:!!"",enabled:![]};if(J7L.name === ""){J7L.enabled=!!1;}J7L.hash_code=this._hashCode((J7L.open + J7L.close).toString());T76.normalHours.push(J7L);return J7L;};u4k._createDateTimeSegment=function(g1a,k0H){var H0i,v50,W6I;H0i=this.re_regular_iso.exec(k0H.date);if(H0i === null){H0i=this.re_wild_card_iso.exec(k0H.date);if(H0i === null){console.log("Warning: invalid date format on rule -> " + k0H.date);return;}v50=(8679,"987" >> 0) != ("7470" ^ 0,494)?+"4230" < (54,"3260" * 1)?"S":(774.92,4830) <= (5640,1340)?611.10:"*":5.17e+2;;}else {v50=parseInt(H0i[1],10);}W6I={name:k0H.name,isDayOfWeek:!({}),dayofweek:-1,year:v50,month:parseInt(H0i[2],10),day:parseInt(H0i["3" << 64],10),date_str:k0H.date,open_parts:u4k._splitHoursMinutes(k0H.open),close_parts:u4k._splitHoursMinutes(k0H.close),open:u4k._secSinceMidnight(g1a,k0H.open,!!"1"),close:u4k._secSinceMidnight(g1a,k0H.close,![]),enabled:![]};if(W6I.name === ""){W6I.enabled=!!1;}W6I.hash_key=this._hashCode(W6I.date_str + W6I.open + W6I.close);g1a.extraHours.push(W6I);return W6I;};u4k._secSinceMidnight=function(e_s,h$a,x4h){var F3u,b4p,a77,h$5;F3u=h$a.split(":");b4p=parseInt(F3u[0],10);a77=parseInt(F3u[1],"10" >> 64);h$5=b4p * 60 * 60 + a77 * 60;if(!x4h){if(b4p === 24){h$5=b4p * 60 * 60 + 1;}}return h$5;};y8h.Market.prototype._convertToMarketTZ=function(Z2J,A4E){var P7H,d98,p_h,r6f;if(A4E){P7H=new this.tz_lib(Z2J.getFullYear(),Z2J.getMonth(),Z2J.getDate(),Z2J.getHours(),Z2J.getMinutes(),Z2J.getSeconds(),Z2J.getMilliseconds(),A4E);}else {d98=-1229625172;p_h=807487669;r6f=2;for(var S6I=+"1";s4_.Z2Z(S6I.toString(),S6I.toString().length,50758) !== d98;S6I++){P7H=new this.tz_lib(Z2J.getFullYear(),Z2J.getMonth(),Z2J.getDate(),Z2J.getHours(),Z2J.getMinutes(),Z2J.getSeconds(),Z2J.getMilliseconds());r6f+=+"2";}if(s4_.U6$(r6f.toString(),r6f.toString().length,52538) !== p_h){P7H=new this.tz_lib(Z2J.getFullYear(),Z2J.getMonth(),Z2J.getDate(),Z2J.getHours(),Z2J.getMinutes(),Z2J.getSeconds(),Z2J.getMilliseconds());}}if(P7H.setTimezone)P7H.setTimezone(this.market_tz);return new Date(P7H.getFullYear(),P7H.getMonth(),P7H.getDate(),P7H.getHours(),P7H.getMinutes(),P7H.getSeconds(),P7H.getMilliseconds());};y8h.Market.prototype._convertFromMarketTZ=function(j2R,Q27){s4_.D0H();var n3U;n3U=new this.tz_lib(j2R.getFullYear(),j2R.getMonth(),j2R.getDate(),j2R.getHours(),j2R.getMinutes(),j2R.getSeconds(),j2R.getMilliseconds(),this.market_tz);if(Q27){if(n3U.setTimezone)n3U.setTimezone(Q27);}else {return new Date(n3U.getTime());}return new Date(n3U.getFullYear(),n3U.getMonth(),n3U.getDate(),n3U.getHours(),n3U.getMinutes(),n3U.getSeconds(),n3U.getMilliseconds());};y8h.Market.Iterator=function(G5H){this.market=G5H.market;this.begin=G5H.begin;this.interval=G5H.interval;this.multiple=G5H.multiple;this.inZone=G5H.inZone;this.outZone=G5H.outZone;this.clock=new y8h.Market.Iterator._Clock(G5H.market,G5H.interval,G5H.multiple);this.intraDay=this.clock.intra_day;if(this.intraDay)this.begin=this.market._convertToMarketTZ(this.begin,G5H.inZone);this.clock._setStart(this.begin);this.clock.minutes_aligned=![];};y8h.Market.Iterator.prototype.date=function(){return this.clock._date();};y8h.Market.Iterator.prototype.futureTick=function(y7F){var x56,o5e,n3Z,Y4u,G_e,A_4,t1X,l62,z7A;this.clock.skip=1;x56=0;if(this.intraDay)o5e=this.market._convertToMarketTZ(y7F.end,this.inZone).getTime();else o5e=y7F.end.getTime();n3Z=this.clock.ctime;if(o5e === n3Z){return x56;}Y4u=2;G_e=+"1000";A_4=0;if(y7F.sample_size){Y4u=y7F.sample_size;}t1X=new Date().getTime();if(o5e > n3Z){this.clock.forward=!0;while(this.clock.ctime < o5e){x56+="1" ^ 0;A_4+=1;this.clock._findNext();if(A_4 === G_e){A_4=0;l62=new Date().getTime();if(l62 - t1X >= Y4u){z7A=(this.clock.ctime - n3Z) / x56;x56=Math.floor((o5e - n3Z) / z7A);break;}}}if(this.clock.ctime > o5e){x56--;}}else {this.clock.forward=![];while(this.clock.ctime > o5e){x56+=1;A_4+=1;this.clock._findPrevious();if(A_4 === G_e){A_4=0;l62=new Date().getTime();if(l62 - t1X >= Y4u){z7A=(n3Z - this.clock.ctime) / x56;x56=Math.floor((n3Z - o5e) / z7A);break;}}}}return x56;};y8h.Market.Iterator.prototype.isHourAligned=function(){s4_.a9S();return !this.intraDay || this.market.isHourAligned();};y8h.Market.Iterator.prototype.isOpen=function(){return this.market.isOpen();};y8h.Market.Iterator.prototype.next=function(e$F){this.clock.skip=1;if(e$F){this.clock.skip=e$F;}s4_.a9S();this.clock.forward=!0;for(var T_y=+"0";T_y < this.clock.skip;T_y++){this.begin=this.clock._findNext();}if(this.intraDay || this.market.convertOnDaily){return this.market._convertFromMarketTZ(this.clock.display_date,this.outZone);}return this.clock.display_date;};y8h.Market.Iterator.prototype.peek=function(){s4_.a9S();return this.clock._peek();};y8h.Market.Iterator.prototype.previous=function(h2p){this.clock.skip=1;s4_.D0H();if(h2p){this.clock.skip=h2p;}this.clock.forward=![];for(var D5v=0;D5v < this.clock.skip;D5v++){this.begin=this.clock._findPrevious();}if(this.intraDay || this.market.convertOnDaily){return this.market._convertFromMarketTZ(this.clock.display_date,this.outZone);}return this.clock.display_date;};y8h.Market.Iterator._Clock=function(u47,s8f,Z4q){var S1N,A$k,G0Q,r9s,Y$E;S1N="millise";S1N+="cond";A$k="s";A$k+="e";A$k+="con";A$k+="d";if(Z4q % +"60" === 0 && s8f === A$k){G0Q="m";G0Q+="inute";s8f=G0Q;Z4q=Z4q / 60;}this.market=u47;this.interval=s8f;this.multiple=Z4q;this.intra_day=![];this.intervals=[];this.max_iters=+"10080";r9s=a84;Y$E=this._dayImpl;if(s8f === S1N){Y$E=this._millisImpl;r9s=1;}else if(s8f === "second"){Y$E=this._secondImpl;r9s=1000;}else if(s8f === "minute"){Y$E=this._minuteImpl;r9s=60000;}else if(s8f === "hour"){Y$E=this._hourImpl;r9s=h3x;}else if(s8f === "day"){Y$E=this._dayImpl;r9s=a84;}else if(s8f === "week"){Y$E=this._weekImpl;r9s=a84 * 7;}else if(s8f === "month"){Y$E=this._monthImpl;r9s=a84 * 30;}else {console.log('Periodicity ERROR: "' + s8f + '" is not a valid interval. Please see setPeriodicity() for details.');}this.tick_time=r9s * Z4q;this.intra_day=this.tick_time < a84;this._findPrevious=this._findNext=Y$E;};F48=y8h.Market.Iterator._Clock.prototype;F48._total_minutes=function(X4_,d2U,f3a,a3d){return (f3a - X4_) * ("60" - 0) - d2U + a3d;};F48._alignMinutes=function(){var J1_,S9O,B4l,e6z,B24;if(!this.market.market_def || this.market.zopen_minute === undefined){return [];}J1_=this.market.zopen_minute;S9O=this.market.zseg_match;if(S9O && S9O.adjacent_parent){J1_=S9O.adjacent_parent.open / 60 - +"1440";}else {if(this.market.isHourAligned() && this.multiple % 60 === 0)J1_=0;}s4_.a9S();B4l=this._total_minutes(this.market.zopen_hour,J1_,this.market.zclose_hour,this.market.zclose_minute);e6z=[];B24=0;while(B24 < B4l){e6z.push(J1_ + B24);B24+=this.multiple;}return e6z;};F48._alignBaseZero=function(K7l){var D2Z,l9v;D2Z=0;l9v=[D2Z];while(!![]){D2Z+=this.multiple;if(D2Z >= K7l){break;}l9v.push(D2Z);}return l9v;};F48._date=function(){var n0h,i3N;n0h=Math.round(this.ctime);i3N=new Date(n0h);s4_.D0H();if(this.intra_day){this.display_date=new Date(n0h + this.shift_millis);}else {this.display_date=i3N;}return i3N;};F48._alignToBoundary=function(O7J,n2Q){var j6X,d87,H7u;j6X=0;d87=+"0";H7u=n2Q;for(var B9Q=0;B9Q < O7J.length - 1;B9Q++){j6X=O7J[B9Q];d87=O7J[B9Q + 1];if(n2Q === j6X || n2Q === d87){break;;}if(n2Q > j6X && n2Q < d87){H7u=j6X;break;}else if(B9Q + 1 === O7J.length - 1){H7u=d87;}}s4_.a9S();return H7u;};F48._peek=function(){return this._date().toString();};F48._seekHr=function(){if(this.forward){this.ctime-=h3x;}else {this.ctime+=h3x;}};F48._setStart=function(P1N){var r0g,P1C;r0g=this.market._tzDifferenceMillis(P1N);P1C=new Date(P1N.getTime() + r0g);this.shift_millis=r0g;this.ctime=P1C.getTime();this.shift_millis=0;this.ctime=P1N.getTime();};F48._tickTock=function(){s4_.a9S();if(this.forward){this.ctime+=this.tick_time;}else {this.ctime-=this.tick_time;}};F48._tockTick=function(){s4_.D0H();if(this.forward){this.ctime-=this.tick_time;}else {this.ctime+=this.tick_time;}};F48._tickTock24=function(){s4_.a9S();this.ctime+=a84;};F48._tockTick24=function(){this.ctime-=a84;};F48._windMaybe=function(Y8_,t26){var S96,p7A,Y3c,D0$;S96=0;p7A=new Date(this.ctime);s4_.a9S();Y3c=![];while(!Y8_.call(this.market,p7A)){t26.call(this);Y3c=!![];p7A=new Date(this.ctime);S96+=1;if(S96 > this.max_iters){D0$="Warning! max iterations (" + this.max_iters;D0$+=") reached with no rule match.";console.log(D0$);break;}}return Y3c;};F48._millisImpl=function(){var X1v,K93,w98,s_5,a03,i5m,F9e,e91,S0z,Z8B;X1v=!"1";if(!this.mperiods_aligned){K93=this._alignBaseZero(1000);w98=new Date(this.ctime);s_5=w98.getMilliseconds();s_5=this._alignToBoundary(K93,s_5);w98.setMilliseconds(0);this.ctime=w98.getTime() + s_5;this.mperiods_aligned=!!"1";X1v=!![];}a03=this._date().getMinutes();this._tickTock();i5m=this._date().getMinutes();if((X1v || a03 != i5m) && !this.market._wasOpenIntraDay(this._date())){F9e=this._date().getSeconds();e91=this._date().getMilliseconds();S0z=this.tick_time;this.tick_time="60000" | 0;Z8B=this.multiple;this.multiple="1" * 1;this._minuteImpl();this.tick_time=S0z;this.multiple=Z8B;this.ctime+="1000" * 1 * F9e + e91;}return this._date();};F48._secondImpl=function(){var u8a,a5Y,b6_,L7D,g63,S_q,i9b,o$f,M4t;u8a=![];if(!this.speriod_aligned){a5Y=this._alignBaseZero(60);b6_=new Date(this.ctime);L7D=b6_.getSeconds();L7D=this._alignToBoundary(a5Y,L7D);b6_.setSeconds(L7D);b6_.setMilliseconds(0);this.ctime=b6_.getTime();this.speriod_aligned=!!1;u8a=!![];}g63=this._date().getMinutes();this._tickTock();S_q=this._date().getMinutes();if((u8a || g63 != S_q) && !this.market._wasOpenIntraDay(this._date())){i9b=this._date().getSeconds();o$f=this.tick_time;this.tick_time=60000;M4t=this.multiple;this.multiple="1" * 1;this._minuteImpl();this.tick_time=o$f;this.multiple=M4t;this.ctime+=1000 * i9b;}return this._date();};F48._minuteImpl=function(){var R_H,T_1,m$s,h3d,z9c,o8h,i9X,Q1j,Q5x,t0S;R_H=this._windMaybe(this.market._wasOpenIntraDay,this._tockTick);T_1=new Date(this.ctime);m$s=T_1.getTimezoneOffset();h3d=T_1.getMinutes();z9c=T_1.getHours();o8h=this._alignMinutes();i9X=this._total_minutes(this.market.zopen_hour,this.market.zopen_minute,z9c,h3d) + this.market.zopen_minute;if(R_H){if(this.forward){i9X=o8h[o8h.length - 1];}else {i9X=o8h[0];}}else {i9X=this._alignToBoundary(o8h,i9X);}z9c=Math.floor(i9X / 60) + this.market.zopen_hour;T_1.setHours(z9c,i9X % 60,0,0);Q1j=T_1.getTimezoneOffset() - m$s;if(this.forward && Q1j < 0 || !this.forward && Q1j > 0){T_1.setTime(T_1.getTime() - Q1j * ("60000" >> 64));}this.ctime=T_1.getTime();this._tickTock();Q5x=this.market.hour_aligned && this.multiple % 60 === 0;if(this._windMaybe(this.market._wasOpenIntraDay,this._tickTock) || !Q5x && this.shouldResetToBeginningOfSegment){T_1=new Date(this.ctime);if(this.forward){T_1.setMinutes(this.market.zopen_minute);T_1.setHours(this.market.zopen_hour);}else {o8h=this._alignMinutes();t0S=o8h[o8h.length - 1];T_1.setMinutes(t0S % +"60");T_1.setHours(Math.floor(t0S / 60) + this.market.zopen_hour);}this.ctime=T_1.getTime();}s4_.a9S();return this._date();};F48._hourImpl=function(){var l6k,s51,G4j,W0d,w8M;this._windMaybe(this.market._wasOpenIntraDay,this._tockTick);l6k=new Date(this.ctime);if(this.market.isHourAligned()){l6k.setMinutes("0" << 32);}else {l6k.setMinutes(this.market.zopen_minute);}l6k.setSeconds(+"0");l6k.setMilliseconds(0);this.ctime=l6k.getTime();this._tickTock();s51=this.market.zseg_match;if(this._windMaybe(this.market._wasOpenIntraDay,this._tickTock) || !this.market.hour_aligned && s51 != this.market.zseg_match){G4j=new Date(this.ctime);if(this.forward){G4j.setMinutes(this.market.zopen_minute);G4j.setHours(this.market.zopen_hour);}else {W0d=this._alignMinutes();w8M=W0d[W0d.length - 1];G4j.setMinutes(w8M % +"60");G4j.setHours(Math.floor(w8M / 60) + this.market.zopen_hour);}this.ctime=G4j.getTime();}return this._date();};F48._dayImpl=function(){var w0A,G4M;this._windMaybe(this.market._wasOpenDaily,this._seekHr);w0A=new Date(this.ctime);w0A.setHours(12,0,0,+"0");this.ctime=w0A.getTime();G4M=0;while(G4M < this.multiple){if(this.forward){this._tickTock24();}else {this._tockTick24();}if(!this.market._wasOpenDaily(this._date())){continue;}G4M+=1;}w0A=new Date(this.ctime);s4_.D0H();w0A.setHours("0" >> 0);this.ctime=w0A.getTime();return this._date();};F48._weekImpl=function(){var I_A,b2r;I_A=this.market;b2r=new Date(this.ctime);b2r.setHours(12);this.ctime=b2r.getTime();this._tickTock();b2r=new Date(this.ctime);while(b2r.getDay() !== I_A.beginningDayOfWeek){this._tockTick24();b2r=new Date(this.ctime);}this._windMaybe(I_A._wasOpenDaily,this._tickTock24);b2r=new Date(this.ctime);b2r.setHours(0,+"0","0" - 0,"0" >> 64);this.ctime=b2r.getTime();return this._date();};F48._monthImpl=function(){var o77;o77=new Date(this.ctime);o77.setDate(15);this.ctime=o77.getTime();this._tickTock();o77=new Date(this.ctime);o77.setDate(1);o77.setHours(12);this.ctime=o77.getTime();this._windMaybe(this.market._wasOpenDaily,this._tickTock24);o77=new Date(this.ctime);o77.setHours(0,0,0,0);this.ctime=o77.getTime();return this._date();};F48._findNext=null;F48._findPrevious=null;};J=z$Y=>{var i4J=A2IFV;i4J.W9l=function(L39){if(i4J && L39)return i4J.b3E(L39);};i4J.t8k=function(D04){if(i4J && D04)return i4J.T36(D04);};i4J.p$N=function(s2O){if(i4J)return i4J.T36(s2O);};i4J.T8d=function(a3I){i4J.a9S();if(i4J)return i4J.T36(a3I);};var Z3w,i1g,u42,A2d;Z3w="u";Z3w+="ndefined";i1g=typeof _CIQ !== Z3w?_CIQ:z$Y.CIQ;i4J.D0H();u42="valid";i1g.valid=0;i1g[i4J.N1F("b2c4")?"ChartEngine":""][i4J.k2l("7ffa")?"prototype":""][i4J.T8d("4161")?"":"mousemoveinner"]=function(d_T,z$Z){i4J.Z8y=function(N7u){i4J.a9S();if(i4J && N7u)return i4J.b3E(N7u);};i4J.h$W=function(a$u){i4J.D0H();if(i4J)return i4J.T36(a$u);};i4J.E_H=function(S6t){i4J.a9S();if(i4J)return i4J.b3E(S6t);};i4J.W8S=function(r6k){if(i4J && r6k)return i4J.T36(r6k);};i4J.T88=function(e0o){if(i4J)return i4J.T36(e0o);};var D9k=-(i4J.D$Y("92a7")?844542962:324290841),z0f=-(i4J.p$N("1a74")?3302050485:1048811085),w7X=i4J.T88("1c18")?8315121327:1094513846,q1Q=-(i4J.t8k("3be7")?457334356:220651779),m76=-(i4J.e3H("4bf3")?203811305:160172757),R_8=938329254,t_6=-(i4J.W8S("13c3")?841488028:606335826),K3U=-(i4J.Q6a("97be")?1125489557:9123140606),G2J=-(i4J.a3z("c2a4")?456310199:119647035),u_G=-1009981692;if(!(i4J.n54(0,false,156439) !== D9k && i4J.i0k(0,false,i4J.W9l("847a")?943323:752378) !== z0f && i4J.i0k(i4J.E_H("a9aa")?9:3,i4J.h$W("5ec6")?true:false,773926) !== w7X && i4J.i0k(i4J.Z8y("1f8c")?1:9,true,690418) !== q1Q && i4J.i0k(8,true,312995) !== m76 && i4J.i0k(10,true,301501) !== R_8 && i4J.i0k(9,true,915786) !== t_6 && i4J.i0k(9,true,934133) !== K3U && i4J.i0k(10,true,326031) !== G2J && i4J.i0k(8,true,619256) !== u_G)){var j15,k_H,B1H,V1n,Q0x,C3z,l4E,v4o,P4w,r5F,S39,X1D,h2_,f6b,H_s,z_W,z_C,V$C,t9L,y$8,I8b,t1K,u12,B8s,x2p,D4y,u3$,k4o,I_b;if(!this["chart"]["canvas"]){return;}if(!i1g["isAndroid"] && !i1g["isIOS7or8"]){if(this["chart"]["canvas"]["height"] != Math["floor"](this["devicePixelRatio"] * this["chart"]["container"]["clientHeight"]) || this["chart"]["canvas"]["width"] != Math["floor"](this["devicePixelRatio"] * this["chart"]["container"]["clientWidth"])){this["resizeChart"]();return;}}if(this["runPrepend"]("mousemoveinner",arguments)){return;}k_H=arguments;B1H=this["container"]["getBoundingClientRect"]();this["top"]=B1H["top"];this["left"]=B1H["left"];this["right"]=this["left"] + this["width"];this["bottom"]=this["top"] + this["height"];this["hasDragged"]=!!"1";i1g["ChartEngine"]["crosshairX"]=d_T;i1g["ChartEngine"]["crosshairY"]=z$Z;V1n=this["cy"]=this["crossYActualPos"]=this["backOutY"](i1g["ChartEngine"]["crosshairY"]);function h$l(j2r){var c_X=993328910,h2u=2095898763,W7u=582624611,z_6=-1720030956,b0F=1778808651,n2x=1110901479,v3Q=-1633607308,T3p=-497724238,r3l=-1857759905,o$F=-2061065206;if(!(i4J.i0k(0,false,604262) !== c_X && i4J.i0k(0,false,895612) !== h2u && i4J.i0k(9,true,614852) !== W7u && i4J.n54(9,true,939183) !== z_6 && i4J.i0k(8,true,249190) !== b0F && i4J.i0k(10,true,641023) !== n2x && i4J.n54(9,true,872180) !== v3Q && i4J.i0k(9,true,541880) !== T3p && i4J.i0k(10,true,296497) !== r3l && i4J.i0k(8,true,123661) !== o$F)){var F7Y,U0c,e9q;j2r["currentBaseline"]=null;F7Y=-1073236151;i4J["H6P"](21);U0c=-i4J["S40"]("1654866714",0);i4J["D0J"](21);e9q=i4J["S40"]("2",0);for(var t3l=1;i4J["U6$"](t3l["toString"](),t3l["toString"]()["length"],47096) !== F7Y;t3l++){j2r["runAppend"]("",k_H);i4J["H6P"](28);e9q+=i4J["q7n"]("2",64);}if(i4J["Z2Z"](e9q["toString"](),e9q["toString"]()["length"],20404) !== U0c){j2r["runAppend"]("mousemoveinner",k_H);}}}Q0x=this["cx"]=this["crossXActualPos"]=this["backOutX"](i1g["ChartEngine"]["crosshairX"]);if(this["grabbingScreen"] && this["anyHighlighted"]){i4J["D0J"](93);var Z4B=i4J["S40"](5762,17,16,16,20);i4J["D0J"](94);var x0v=i4J["q7n"](9,17,7,13,16);C3z=Math["pow"](this["grabStartX"] - d_T,Z4B) + Math["pow"](this["grabStartY"] - z$Z,x0v);if(C3z < 36){return;}}this["cancelLongHold"]=!0;l4E=function(f1T,t1V){var E0L=-1375377331,r6v=1709747795,g30=2101416112,S0y=1473004637,V2$=-570364054,K26=485238424,Z82=-277515614,X$4=-720212561,c_P=-156853376,L$G=-2142817629;if(!(i4J.n54(0,false,988309) !== E0L && i4J.n54(0,false,512672) !== r6v && i4J.n54(9,true,285223) !== g30 && i4J.i0k(9,true,820859) !== S0y && i4J.i0k(8,true,386337) !== V2$ && i4J.n54(10,true,635588) !== K26 && i4J.n54(9,true,236778) !== Z82 && i4J.i0k(9,true,691052) !== X$4 && i4J.i0k(10,true,438322) !== c_P && i4J.i0k(8,true,996088) !== L$G)){if(i1g[u42] === 0){return f1T["whichPanel"](t1V) || f1T["chart"]["panel"];}if(!f1T["draw"][u42]){f1T["draw"]=function(){i4J.a9S();var h_w=2137621837,Z$1=-1316499516,D8N=77316148,N7P=-1276284452,j4Q=-1949278359,e0O=1330680705,P6S=-695431039,D$Z=1589160700,W0f=-1223308209,z5D=-2139150734;if(i4J.i0k(0,false,161315) === h_w || i4J.i0k(0,false,272674) === Z$1 || i4J.n54(9,true,116838) === D8N || i4J.n54(9,true,799075) === N7P || i4J.n54(8,true,694869) === j4Q || i4J.n54(10,true,213141) === e0O || i4J.n54(9,true,525393) === P6S || i4J.n54(9,true,834294) === D$Z || i4J.i0k(10,true,855574) === W0f || i4J.i0k(8,true,619691) === z5D){i1g["clearCanvas"](this["chart"]["canvas"],this);}};f1T["draw"][u42]=!"";}}};this["currentPanel"]=l4E(this,V1n);if(!this["currentPanel"]){return;}v4o=this["currentPanel"]["chart"];if(v4o["dataSet"]){this["crosshairTick"]=this["tickFromPixel"](Q0x,v4o);j15=this["valueFromPixel"](V1n,this["currentPanel"]);this["crosshairValue"]=this["adjustIfNecessary"](this["currentPanel"],this["crosshairTick"],j15);P4w=this["currentPanel"]["name"] == "chart"?this["preferences"]["horizontalCrosshairField"]:this["currentPanel"]["horizontalCrosshairField"];if(P4w && this["crosshairTick"] < v4o["dataSet"]["length"] && this["crosshairTick"] > -1){j15=v4o["dataSet"][this["crosshairTick"]][P4w];this["crossYActualPos"]=this["pixelFromPrice"](j15,this["currentPanel"]);}}if(i1g["ChartEngine"]["crosshairX"] >= this["left"] && i1g["ChartEngine"]["crosshairX"] <= this["right"] && i1g["ChartEngine"]["crosshairY"] >= this["top"] && i1g["ChartEngine"]["crosshairY"] <= this["bottom"]){this["insideChart"]=!![];}else {this["insideChart"]=!!0;}r5F=this["xAxisAsFooter"] === !![]?this["chart"]["canvasHeight"]:this["chart"]["panel"]["bottom"];this["overXAxis"]=this["insideChart"] && i1g["ChartEngine"]["crosshairY"] <= r5F + this["top"] && i1g["ChartEngine"]["crosshairY"] > r5F - this["xaxisHeight"] + this["top"];this["overYAxis"]=(this["cx"] >= this["currentPanel"]["right"] || this["cx"] <= this["currentPanel"]["left"]) && this["insideChart"];if(this["overXAxis"] || this["overYAxis"] || !this["insideChart"] && !this["grabbingScreen"]){this["undisplayCrosshairs"]();if(!this["overXAxis"] && !this["overYAxis"]){return;};}if(!this["displayCrosshairs"] && !i1g["ChartEngine"]["resizingPanel"]){this["undisplayCrosshairs"]();return;}if(this["repositioningBaseline"]){this["setBaselineUserLevel"]();return h$l(this);}if(this["repositioningAnchorSelector"]){S39=this["repositioningAnchorSelector"]["hoverTick"];X1D=this["tickFromPixel"](this["cx"],this["chart"]);if(X1D >= 0 && X1D < this["chart"]["dataSet"]["length"] && (!(S39 && S39 !== 0) || X1D !== S39)){this["repositioningAnchorSelector"]["hoverTick"]=X1D;this["draw"]();}return h$l(this);}if(this["grabbingScreen"] && !i1g["ChartEngine"]["resizingPanel"]){h2_="z";h2_+="oo";h2_+="m";f6b="p";f6b+="a";f6b+="n";if(this["highlightedDraggable"]){this["displayDragOK"](!!({}));this["dragPlotOrAxis"](Q0x,V1n);return h$l(this);}if(this["anyHighlighted"]){i1g["clearCanvas"](this["chart"]["tempCanvas"],this);this["anyHighlighted"]=!({});for(H_s in this["overlays"]){this["overlays"][H_s]["highlight"]=!!"";}for(H_s in v4o["series"]){v4o["series"][H_s]["highlight"]=![];}this["displaySticky"]();}if(this["grabStartX"] == -1){this["grabStartX"]=i1g["ChartEngine"]["crosshairX"];this["grabStartScrollX"]=v4o["scroll"];}if(this["grabStartY"] == -1){this["grabStartY"]=i1g["ChartEngine"]["crosshairY"];this["grabStartScrollY"]=this["currentPanel"]["yAxis"]["scroll"];}z_W=i1g["ChartEngine"]["crosshairX"] - this["grabStartX"];z_C=i1g["ChartEngine"]["crosshairY"] - this["grabStartY"];if(z_W === 0 && z_C === 0){return;}if(Math["abs"](z_W) + Math["abs"](z_C) > +"5"){this["grabOverrideClick"]=!"";}t9L=this["layout"]["candleWidth"];if(this["allowZoom"] && this["grabMode"] != f6b && (this["grabMode"]["indexOf"](h2_) === 0 || this["overXAxis"] || this["grabStartYAxis"])){y$8="z";y$8+="oom-";y$8+="y";if(this["grabMode"] === ""){I8b="zo";I8b+="o";I8b+="m";I8b+="-y";if(this["overXAxis"]){this["grabMode"]="zoom-x";}else if(this["grabStartYAxis"]){this["grabMode"]=I8b;}}if(this["grabMode"] == "zoom-x"){z_C=0;}else if(this["grabMode"] == y$8){z_W=0;}if(z_W){this["grabStartX"]=i1g["ChartEngine"]["crosshairX"];t1K=t9L - z_W / this["chart"]["maxTicks"];this["zoomSet"](t1K,this["chart"]);}if(this["layout"]["setSpan"]){this["layout"]["setSpan"]=null;this["changeOccurred"]("layout");}V$C=this["grabStartYAxis"];if(V$C){if(V$C["flipped"]){z_C*=-1;}V$C["zoom"]=Math["round"](this["grabStartZoom"] + z_C);if(this["grabStartZoom"] < V$C["height"]){if(V$C["zoom"] >= V$C["height"]){i4J["D0J"](16);var j2t=i4J["S40"](15,16);V$C["zoom"]=V$C["height"] - j2t;}}else {if(V$C["zoom"] <= V$C["height"]){i4J["D0J"](95);var B79=i4J["S40"](15,14,1);V$C["zoom"]=V$C["height"] + B79;}}}}else if(!this["overYAxis"]){this["dispatch"]("move",{stx:this,panel:this["currentPanel"],x:this["cx"],y:this["cy"],grab:!""});if(this["allowScroll"]){u12="s";u12+="c";u12+="roll";B8s="p";B8s+="a";B8s+="n";if(Math["abs"](z_C) < this["yTolerance"]){if(!this["yToleranceBroken"]){i4J["H6P"](28);z_C=i4J["q7n"]("0",0);if(z_W === 0){return;}}}else {this["yToleranceBroken"]=!!"1";}if(!this["grabStartMicropixels"]){this["grabStartMicropixels"]=0;}this["grabMode"]=B8s;v4o["scroll"]=this["grabStartScrollX"];i4J["D0J"](7);var a9J=i4J["q7n"](75,80);i4J["D0J"](35);var z$g=i4J["S40"](3,8,0,20,83);this["micropixels"]=this["grabStartMicropixels"] + z_W * (this["shift"]?a9J:z$g);if(!this["lineTravelSpacing"]){while(this["micropixels"] > 0){this["micropixels"]-=t9L;v4o["scroll"]++;}while(this["micropixels"] < -t9L){this["micropixels"]+=t9L;v4o["scroll"]--;}}if(v4o["scroll"] >= v4o["maxTicks"]){this["preferences"]["whitespace"]=this["initialWhitespace"];}else {this["preferences"]["whitespace"]=(v4o["maxTicks"] - v4o["scroll"]) * t9L;}if(this["currentPanel"] == this["grabStartPanel"]){V$C=this["currentPanel"]["yAxis"];if(V$C["flipped"]){z_C*=-1;}V$C["scroll"]=this["grabStartScrollY"] + z_C;}this["dispatch"](u12,{stx:this,panel:this["currentPanel"],x:this["cx"],y:this["cy"]});}}x2p=function(m6d){var G$6=1884413784,f0X=843305499,t95=-1828805273,z3G=-237356123,n9A=-416237720,D7P=-896677701,j3v=-2073281220,d85=-699202426,v7G=1224353024,U1v=-431992262;i4J.a9S();if(i4J.n54(0,false,344643) === G$6 || i4J.n54(0,false,248261) === f0X || i4J.n54(9,true,510641) === t95 || i4J.n54(9,true,537059) === z3G || i4J.n54(8,true,990150) === n9A || i4J.i0k(10,true,899186) === D7P || i4J.n54(9,true,420358) === j3v || i4J.i0k(9,true,117347) === d85 || i4J.i0k(10,true,899180) === v7G || i4J.n54(8,true,704648) === U1v){return function(){var p7Q=-1293231227,t9J=646952451,N9i=1991222530,B4y=963808928,T4Y=74811302,L4E=-1013306543,A0D=347559400,v0i=753282069,f2o=-1020650155,c0H=777206014;if(!(i4J.i0k(0,false,569305) !== p7Q && i4J.i0k(0,false,691864) !== t9J && i4J.n54(9,true,932806) !== N9i && i4J.n54(9,true,103712) !== B4y && i4J.n54(8,true,622995) !== T4Y && i4J.n54(10,true,895631) !== L4E && i4J.n54(9,true,438279) !== A0D && i4J.i0k(9,true,986995) !== v0i && i4J.n54(10,true,837758) !== f2o && i4J.i0k(8,true,898309) !== c0H)){m6d["draw"]();m6d["updateChartAccessories"]();}};}};if(i1g["ChartEngine"]["useAnimation"]){window["requestAnimationFrame"](x2p(this));}else {this["draw"]();this["updateChartAccessories"]();}if(this["activeDrawing"]){i1g["clearCanvas"](this["chart"]["tempCanvas"],this);this["activeDrawing"]["render"](this["chart"]["tempCanvas"]["context"]);this["activeDrawing"]["measure"]();}this["undisplayCrosshairs"]();return;}this["grabMode"]="";if(this["overXAxis"] || this["overYAxis"]){this["updateChartAccessories"]();if(!this["tapForHighlighting"] || !this["touchingEvent"] || this["anyHighlighted"]){this["findHighlights"]();}return h$l(this);;}if(this["controls"]["crossX"]){this["controls"]["crossX"]["style"]["left"]=this["pixelFromTick"](this["crosshairTick"],v4o) - 0.5 + "px";}if(this["controls"]["crossY"]){this["controls"]["crossY"]["style"]["top"]=this["crossYActualPos"] + "px";}if(this["insideChart"] && !i1g["ChartEngine"]["resizingPanel"]){D4y=this["currentVectorParameters"]["vectorType"];if(this["layout"]["studies"]){u3$=this["layout"]["studies"][this["currentPanel"]["name"]];if(u3$){if(!this["preferences"]["dragging"] || !this["preferences"]["dragging"]["study"]){delete this["overlays"][u3$["name"]];}if(D4y){this["overlays"][u3$["name"]]=u3$;}}}if(!i1g["Drawing"] || !D4y || !i1g["Drawing"][D4y] || !new i1g["Drawing"][D4y]()["dragToDraw"]){this["doDisplayCrosshairs"]();}this["updateChartAccessories"]();}else {this["undisplayCrosshairs"]();}if(this["magnetize"]){this["magnetize"]();}if(this["repositioningDrawing"]){this["repositionDrawing"](this["repositioningDrawing"]);}else if(i1g["ChartEngine"]["drawingLine"]){if(this["activeDrawing"]){k4o=this["panels"][this["activeDrawing"]["panelName"]];j15=this["adjustIfNecessary"](k4o,this["crosshairTick"],this["valueFromPixel"](this["backOutY"](i1g["ChartEngine"]["crosshairY"]),k4o));if(this["magnetizedPrice"] && k4o["name"] == this["currentPanel"]["name"]){j15=this["adjustIfNecessary"](k4o,this["crosshairTick"],this["magnetizedPrice"]);}if(this["magnetizedPrice"] === null){i1g["clearCanvas"](this["chart"]["tempCanvas"],this);}this["activeDrawing"]["move"](this["chart"]["tempCanvas"]["context"],this["crosshairTick"],j15);if(this["activeDrawing"]["measure"]){this["activeDrawing"]["measure"]();}}}else if(i1g["ChartEngine"]["resizingPanel"]){this["resizePanels"]();}if(this["insideChart"]){I_b="m";I_b+="ove";this["dispatch"](I_b,{stx:this,panel:this["currentPanel"],x:this["cx"],y:this["cy"],grab:!!0});if(!this["tapForHighlighting"] || !this["touchingEvent"] || this["anyHighlighted"]){this["findHighlights"]();}}return h$l(this);}};i1g.ChartEngine.prototype.swipeStart=function(z9t){var e3q;if(this.swipe && this.swipe.interval){clearInterval(this.swipe.interval);}this.swipe.velocity=0;this.swipe.amplitude=0;this.swipe.frame=z9t.scroll;this.swipe.micropixels=this.micropixels;this.swipe.timestamp=Date.now();this.swipe.chart=z9t;this.swipe.end=!!"";this.swipe.timeConstant=325;this.swipe.cb=null;e3q=this;requestAnimationFrame(function(){i4J.a9S();e3q.swipeSample();});};i1g.ChartEngine.prototype.swipeSample=function(){var b7W,A$X,U0r,V8m,O1w,A1K,G4S,j97,g6y;b7W=this.swipe;if(b7W.end){return;}A$X=this;G4S=+"20";U0r=Date.now();V8m=U0r - b7W.timestamp;if(V8m < G4S){requestAnimationFrame(function(){i4J.D0H();A$X.swipeSample();});return;}j97=i1g.touchDevice?0.4:0.8;b7W.timestamp=U0r;O1w=(b7W.chart.scroll - b7W.frame) * this.layout.candleWidth + this.micropixels - b7W.micropixels;b7W.frame=b7W.chart.scroll;b7W.micropixels=this.micropixels;i4J.D0J(96);A1K=i4J.S40(1000,1,O1w,V8m);g6y=j97 * A1K + 0.2 * b7W.velocity;if(Math.abs(g6y) > Math.abs(b7W.velocity)){b7W.velocity=g6y;}if(Math.abs(O1w) < +"6"){b7W.velocity=0;;}i4J.a9S();requestAnimationFrame(function(){A$X.swipeSample();});};i1g.ChartEngine.prototype.swipeRelease=function(){var h2e,B1n;h2e=this.swipe;if(h2e.velocity > 3000){h2e.velocity=3000;}if(h2e.velocity < -3000){h2e.velocity=-3000;}i4J.D0H();if(h2e.velocity > 10 || h2e.velocity < -10){h2e.amplitude=("0.8" - 0) * h2e.velocity;h2e.scroll=h2e.chart.scroll;h2e.target=h2e.amplitude;h2e.timestamp=Date.now();B1n=this;if(this.disableBackingStoreDuringTouch){this.disableBackingStore();}requestAnimationFrame(function(){i4J.a9S();B1n.autoscroll();});}};i1g.ChartEngine.prototype.dragPlotOrAxis=function(g1Z,P8g){var f1G,i6W,v2d,n7p,j3G,W0O,n1B,A3A,Y2F,V30,O8c,K11,J8s,O_i,u9g,t$Y,i53,C4i,X4l,L9L,a1l,K8c,f31,w1K,c7h,B4k,t8V,H6U,e9x,R_X,a13,d3R,z2T,C15,r_x,i0y,G1n,m3s,j_S,W$l,C4p,z7r,w4G,g2r,n4V,F2F,l2V,M0$,t8t,a4i,Y$i,K98,z4J,m5Y,G_0,B8T,z79,B31,r_f,W9f;f1G="non";f1G+="e";if(!f$u.call(this) && !this.grabbingScreen){return;}i6W=null;v2d=20;n7p=10;i4J.H6P(7);j3G=this.whichPanel(i4J.S40(v2d,P8g));i4J.D0J(0);W0O=this.whichPanel(i4J.q7n(P8g,v2d));n1B=this.whichPanel(P8g);A3A=this.highlightedDraggable;if(!n1B){return;}if(A3A.undraggable && A3A.undraggable(this)){return;}Y2F=this.whichYAxis(n1B,g1Z,P8g);i4J.D0J(7);V30=this.whichYAxis(n1B,i4J.q7n(n7p,g1Z),P8g);i4J.H6P(0);O8c=this.whichYAxis(n1B,i4J.q7n(g1Z,n7p),P8g);if(this.xAxisAsFooter && n1B.name == Object.keys(this.panels).pop()){W0O=this.whichPanel(P8g + v2d + this.xaxisHeight);if(i6W){i6W+=this.xaxisHeight;}}K11=!!0;i4J.D0H();J8s=![];O_i=!"1";if(i1g.Renderer){K11=A3A instanceof i1g.Renderer;}if(i1g.Studies){J8s=A3A instanceof i1g.Studies.StudyDescriptor;}O_i=A3A instanceof i1g.ChartEngine.YAxis;u9g=function(Z_l){i4J.D0H();if(!O_i){if(Z_l == "right"){return n1B.right - n1B.width / +"6";}if(Z_l == "left"){return n1B.left + n1B.width / ("6" ^ 0);}}i4J.D0J(33);var m0D=i4J.q7n(18,11,7,16);return (n1B.left + n1B.right) / m0D;};if(!O_i && !Y2F){t$Y="rig";t$Y+="h";t$Y+="t";if(g1Z < u9g("left")){V30=this.whichYAxis(n1B,n1B.left - 1,P8g);}else if(g1Z > u9g(t$Y)){O8c=this.whichYAxis(n1B,n1B.right + 1,P8g);}}i53=[];if(A3A.getDependents){i53=A3A.getDependents(this,!![]);}C4i=A3A.panel;X4l=A3A.getYAxis(this);if(K11){C4i=A3A.params.panel;}else if(O_i){C4i=this.grabStartPanel.name;}L9L=this.panels[C4i];for(a1l in this.panels){if(this.panels[a1l].soloing){K8c=!!({});}}f31=X4l.isShared(this);w1K=!O_i && !K8c && (L9L !== n1B && L9L != j3G && L9L != W0O || !this.checkForEmptyPanel(L9L,!0,[A3A].concat(i53)));c7h=C4i == n1B.name && X4l !== Y2F && X4l !== O8c && X4l !== V30 || f31;if(w1K && (!j3G || n1B !== j3G)){H6U="d";H6U+="ro";H6U+="pz";H6U+="one";n1B.subholder.classList.add(H6U);n1B.subholder.classList.add("top");W0O=n1B;}else if(w1K && (!W0O || n1B !== W0O)){n1B.subholder.classList.add("dropzone");n1B.subholder.classList.add("bottom");}else if(n1B !== L9L){if(!O_i && !n1B.noDrag){e9x="a";e9x+="l";e9x+="l";R_X="d";R_X+="ro";R_X+="pzone";n1B.subholder.classList.add(R_X);n1B.subholder.classList.add(e9x);B4k=n1B.name;}}else if((!n1B.yaxisRHS.length || n1B.yaxisRHS.length == +"1" && n1B.yaxisRHS[+"0"] == X4l && X4l.position == "none") && !Y2F && !O8c && g1Z > u9g("right")){n1B.subholder.classList.add("dropzone");n1B.subholder.classList.add("right");t8V="right";}else if((!n1B.yaxisLHS.length || n1B.yaxisLHS.length == 1 && n1B.yaxisLHS[0] == X4l && X4l.position == f1G) && !Y2F && !V30 && g1Z < u9g("left")){a13="d";a13+="ropzon";a13+="e";n1B.subholder.classList.add(a13);n1B.subholder.classList.add("left");t8V="left";}else if(c7h){if(O_i && g1Z > n1B.left && g1Z < n1B.right){i4J.D0J(2);var O_C=i4J.S40(5,13,7);d3R=n1B.yaxisLHS[n1B.yaxisLHS.length - O_C];z2T=n1B.yaxisRHS[0];C15=u9g();if(g1Z < C15 && d3R != X4l){V30=d3R;}else if(g1Z > C15 && z2T != X4l){O8c=z2T;}}if(!O_i || Y2F !== X4l){r_x=!O_i && f31;if(O8c && (O8c !== X4l || r_x) && (!Y2F || Y2F !== O8c)){O8c.dropzone="left";t8V=O8c.position || this.chart.panel.yAxis.position || "right";}else if(V30 && (V30 !== X4l || r_x) && (!Y2F || Y2F !== V30)){V30.dropzone="right";t8V=V30.position || this.chart.panel.yAxis.position || "right";}else if(Y2F){if(!O8c && (Y2F !== X4l || r_x)){Y2F.dropzone="right";}else if(!V30 && (Y2F !== X4l || r_x)){Y2F.dropzone="left";}else if(Y2F !== X4l){Y2F.dropzone="all";}if(Y2F.dropzone){t8V=Y2F.position || this.chart.panel.yAxis.position || "right";}}}}if(this.grabbingScreen || !n1B.subholder.classList.contains("dropzone") && !t8V){this.draw();return;}function f$u(){i4J.a9S();var s$G,K65,p6t;s$G=!({});for(var n2n in this.panels){K65="a";K65+="l";K65+="l";["dropzone",K65,"left","right","top","bottom"].forEach(D3v(this.panels[n2n]));for(p6t=0;p6t < this.panels[n2n].yaxisLHS.length;p6t++){if(this.panels[n2n].yaxisLHS[p6t].dropzone){s$G=!0;}this.panels[n2n].yaxisLHS[p6t].dropzone=null;}for(p6t=0;p6t < this.panels[n2n].yaxisRHS.length;p6t++){if(this.panels[n2n].yaxisRHS[p6t].dropzone){s$G=!!({});}this.panels[n2n].yaxisRHS[p6t].dropzone=null;}}function D3v(W_J){return function(a1_){i4J.a9S();if(W_J.subholder.classList.contains(a1_)){W_J.subholder.classList.remove(a1_);s$G=!0;}};}return s$G;}G1n=-1;if(!B4k && !t8V && w1K){B4k=J8s?A3A.inputs.id:A3A.params.name || i1g.uniqueID();for(var S6w in this.panels){G1n++;if(this.panels[S6w] == W0O)break;}if(!W0O){G1n++;}if(this.panels[C4i].yAxis.name == B4k){C4i=this.electNewPanelOwner(C4i);}m3s=J8s?A3A.inputs.display:null;if(C4i){this.createPanel(m3s || B4k,B4k,i6W,this.chart.name,new i1g.ChartEngine.YAxis({name:B4k}));}else {C4i=B4k;}if(J8s){A3A.panel=C4i;}else {A3A.params.panel=C4i;}}if(B4k){if(J8s){j_S="Stu";j_S+="d";j_S+="ies.replaceStu";j_S+="dy";if(!A3A.parameters){A3A.parameters={};}A3A.parameters.panelName=B4k;this.highlightedDraggable=i1g.getFn(j_S)(this,A3A.inputs.id,A3A.type,A3A.inputs,A3A.outputs,A3A.parameters,null,A3A.study);}else if(K11){for(var W93 in A3A.seriesParams){W$l=A3A.seriesParams[W93];C4p=null;if(A3A.params.yAxis){if(A3A.params.yAxis !== this.chart.panel.yAxis){C4p=A3A.params.yAxis;C4p.name=A3A.params.name;}}this.modifySeries(W$l.id,{panel:B4k,yAxis:C4p});}}if(G1n > -1){z7r={};w4G=0;for(a1l in this.panels){if(G1n == w4G++){z7r[B4k]=this.panels[B4k];}if(a1l == B4k)continue;z7r[a1l]=this.panels[a1l];}if(!z7r[B4k]){z7r[B4k]=this.panels[B4k];}this.panels=z7r;}this.checkForEmptyPanel(C4i);for(var D9X=0;D9X < i53.length;D9X++){if(i53[D9X].params){this.checkForEmptyPanel(i53[D9X].params.name);}else {this.checkForEmptyPanel(i53[D9X].name);}}this.adjustPanelPositions();}else if(t8V){g2r="a";g2r+="l";g2r+="l";n4V=function(w1z,p2j,w2D,t8$){var Y0j,v8y,L2y,S4a;Y0j="stu";i4J.a9S();Y0j+="dy";if(w2D == Y0j){L2y="Studies.";L2y+="replaceStudy";if(!p2j.parameters){p2j.parameters={};}if(t8$){p2j.parameters.yaxisDisplayValue=t8$.position;}else {delete p2j.parameters.yaxisDisplayValue;}v8y=i1g.getFn(L2y)(w1z,p2j.inputs.id,p2j.type,p2j.inputs,p2j.outputs,p2j.parameters,p2j.panel,p2j.study);}if(w2D == "renderer"){for(var d9S in p2j.seriesParams){S4a=p2j.seriesParams[d9S];v8y=w1z.modifySeries(S4a.id,{panel:B4k,yAxis:t8$});}}return v8y;};F2F=Y2F && Y2F.dropzone == g2r;if(!F2F){if(O_i){A3A.position=t8V;if(this.layout.studies){l2V=this.layout.studies[A3A.name];if(l2V){if(!l2V.parameters){l2V.parameters={};}l2V.parameters.yaxisDisplayValue=t8V;}}}else if(J8s){M0$="stu";M0$+="d";M0$+="y";this.highlightedDraggable=n4V(this,A3A,M0$,{position:t8V});}else if(K11){n4V(this,A3A,"renderer",new i1g.ChartEngine.YAxis({name:A3A.params.name || i1g.uniqueID(),position:t8V}));}X4l=this.highlightedDraggable.getYAxis(this);}if(!f31 || !F2F || O_i){t8t=X4l;if(F2F && X4l == this.chart.panel.yAxis){t8t=Y2F;}for(i0y=0;i0y < n1B.yaxisLHS.length;i0y++){if(n1B.yaxisLHS[i0y] == t8t){n1B.yaxisLHS.splice(i0y,1);break;}}for(i0y=0;i0y < n1B.yaxisRHS.length;i0y++){if(n1B.yaxisRHS[i0y] == t8t){n1B.yaxisRHS.splice(i0y,1);break;}}}a4i=922850339;Y$i=-64993701;K98=2;for(var D6g=1;i4J.Z2Z(D6g.toString(),D6g.toString().length,76373) !== a4i;D6g++){K98+=+"2";}if(i4J.U6$(K98.toString(),K98.toString().length,77999) !== Y$i){}if(F2F){if(this.getYAxisByName(n1B,X4l.name) == n1B.yAxis){this.electNewPanelOwner(n1B,Y2F);}if(O_i){G_0=X4l;B8T=Y2F;if(X4l == this.chart.panel.yAxis){G_0=Y2F;B8T=X4l;}for(m5Y in G_0.studies){z79="s";z79+="t";z79+="ud";z79+="y";n4V(this,this.layout.studies[G_0.studies[m5Y]],z79,B8T === this.chart.panel.yAxis?null:{position:B8T.name});}for(m5Y in G_0.renderers){n4V(this,this.chart.seriesRenderers[G_0.renderers[m5Y]],"renderer",B8T);}this.highlightedDraggable=B8T;}else if(J8s){B31="st";B31+="u";B31+="dy";this.highlightedDraggable=n4V(this,A3A,B31,{position:Y2F.name});}else if(K11){n4V(this,A3A,"renderer",Y2F);}}else {if(X4l.position == "none"){X4l.width=i1g.ChartEngine.YAxis.prototype.width;}X4l.position=t8V;z4J=t8V == "left"?n1B.yaxisLHS:n1B.yaxisRHS;for(i0y=0;i0y < z4J.length;i0y++){if(z4J[i0y] !== X4l){if(z4J[i0y].dropzone == "left"){z4J.splice(i0y,0,X4l);}else if(z4J[i0y].dropzone == "right"){i4J.D0J(97);z4J.splice(i4J.S40(i0y,0,"1"),0,X4l);}else continue;}break;}if(i0y == z4J.length){z4J.push(X4l);}}}for(var h$h in this.panels){r_f=this.panels[h$h];W9f=r_f.yaxisLHS.concat(r_f.yaxisRHS);for(i0y=0;i0y < W9f.length;i0y++){W9f[i0y].height=r_f.yAxis.height;this.calculateYAxisMargins(W9f[i0y]);}}this.displayDragOK();this.draw();this.calculateYAxisPositions();this.draw();this.findHighlights(null,!!({}));this.savePanels();};A2d=!({});i1g.ChartEngine.prototype.findHighlights=i1g.ChartEngine.prototype.findHighlights || (function(D8y,W2g){if(!A2d){console.error("movement feature requires activating interaction feature.");}A2d=!"";});};P=q0K=>{var F_h,F1D;F_h="u";F_h+="n";F_h+="defi";F_h+="ned";F1D=typeof _CIQ !== F_h?_CIQ:q0K.CIQ;F1D.NameValueStore=F1D.NameValueStore || (function(){});F1D.NameValueStore.prototype.toJSONIfNecessary=function(r3J){var T1W;if(r3J.constructor == String){return r3J;}try{T1W=JSON.stringify(r3J);return T1W;}catch(Z2d){A2IFV.H6P(0);console.log(A2IFV.S40("Cannot convert to JSON: ",r3J));return null;}};F1D.NameValueStore.prototype.fromJSONIfNecessary=function(N4O){var K$k;A2IFV.D0H();try{K$k=JSON.parse(N4O);return K$k;}catch(n1L){return N4O;}};F1D.NameValueStore.prototype.get=function(G30,T7C){var Y_o;Y_o=F1D.localStorage.getItem(G30);T7C(null,this.fromJSONIfNecessary(Y_o));};F1D.NameValueStore.prototype.set=function(d4t,Y$e,X4j){F1D.localStorageSetItem(d4t,this.toJSONIfNecessary(Y$e));A2IFV.D0H();if(X4j){X4j(null);}};F1D.NameValueStore.prototype.remove=function(D7J,M4i){A2IFV.a9S();F1D.localStorage.removeItem(D7J);if(M4i){M4i(null);}};};T=E$q=>{var i4r=A2IFV;var m66;m66=typeof _CIQ !== "undefined"?_CIQ:E$q.CIQ;if(!m66.ChartEngine){m66.ChartEngine=function(){};}h6Q.fetchInitialData=function(d4u,e0G,O9$,w74,q6I){};h6Q.fetchUpdateData=function(h22,L7y,O2o,s21){};h6Q.fetchPaginationData=function(B2m,C2t,c3x,j$O,C_3){};h6Q.subscribe=function(C53){};h6Q.unsubscribe=function(n19){};m66.QuoteFeed=m66.QuoteFeed || (function(){});m66.QuoteFeed.prototype.fetch=function(g8s,V4m){var a3p;if(!this.v2QuoteFeed){a3p="You m";a3p+="ust implement CIQ.QuoteFeed.[yourfeedname].prototype.fetch()";console.log(a3p);}};m66.QuoteFeed.prototype.announceError=function(V1e,m60){var l5l;if(V1e.suppressErrors || m60.suppressAlert){return;}i4r.D0H();if(V1e.startDate){;}else if(V1e.endDate){;}else if(m60.error){l5l="Error fetchi";l5l+="ng qu";l5l+="ote:";m66.alert(l5l + m60.error);}else {;}};m66.QuoteFeed.prototype.multiFetch=function(W_a,P7s){if(W_a.length === 0){P7s([]);}return W_a[0].stx.driver.multiFetch(W_a,P7s);};m66.QuoteFeed.Subscriptions=function(){i4r.D0H();this.subscriptions=[];};m66.inheritsFrom(m66.QuoteFeed.Subscriptions,m66.QuoteFeed);m66.QuoteFeed.Subscriptions.prototype.checkSubscriptions=function(Y_C){var t7X,o1Y,m3J,t6I,o$Y,V6X,d58,c6Y;m3J=Y_C.getSymbols({"breakout-equations":!![]});t6I=this;m3J=m3J.filter(function(U1e){var y3T;y3T=Y_C.quoteDriver.getQuoteFeed(U1e);return y3T && y3T.engine == t6I;});for(var d4r=0;d4r < this.subscriptions.length;d4r++){this.subscriptions[d4r].match=!({});}i4r.D0H();for(var E$W=0;E$W < m3J.length;E$W++){o$Y="mon";o$Y+="th";o1Y=m3J[E$W];V6X=o1Y.interval;if((V6X == o$Y || V6X == "week") && !Y_C.dontRoll){V6X="day";}o1Y.interval=V6X;o1Y.period=1;o1Y.match=!"1";if(!isNaN(o1Y.interval)){o1Y.period=o1Y.interval;o1Y.interval=o1Y.timeUnit;if(!o1Y.interval){o1Y.interval="minute";}}delete o1Y.periodicity;delete o1Y.timeUnit;delete o1Y.setSpan;for(d4r=0;d4r < this.subscriptions.length;d4r++){t7X=this.subscriptions[d4r];if(t7X.symbol == o1Y.symbol && t7X.period == o1Y.period && t7X.interval == o1Y.interval){o1Y.match=!"";t7X.match=!!({});break;}else if(t7X.symbol != o1Y.symbol){d58="symbo";d58+="l";if(o1Y.reason != "period"){o1Y.reason=d58;}t7X.reason="symbol";}else {c6Y="peri";c6Y+="od";o1Y.reason="period";t7X.reason=c6Y;}}}this.subscriptions=this.subscriptions.filter(function(C9D){if(!C9D.match){if(!C9D.stx){C9D.stx=Y_C;}t6I.unsubscribe(C9D);}return C9D.match;});m3J.forEach(function(I4f){if(!I4f.match){if(!I4f.stx){I4f.stx=Y_C;}if(!I4f.reason){I4f.reason="initialize";}if(I4f.symbol !== Y_C.chart.symbol){I4f.series=!![];}t6I.subscribe(I4f);t6I.subscriptions.push(I4f);}});};m66.QuoteFeed.Subscriptions.prototype.fetch=function(Q$V,n3V){var E3h;i4r.D0H();E3h=this;this.fetchFromSource(Q$V,function(P5w){i4r.D0H();if(!P5w.error){E3h.checkSubscriptions(Q$V.stx);}n3V(P5w);});};m66.QuoteFeed.Subscriptions.prototype.subscribe=function(Z0v){i4r.D0H();console.log("subscribe",Z0v);};m66.QuoteFeed.Subscriptions.prototype.unsubscribe=function(z1E){i4r.a9S();console.log("unsubscribe",z1E);};m66.QuoteFeed.Subscriptions.prototype.fetchFromSource=function(s5g,y49){var C$o;C$o="Please provi";C$o+="de implementation of";C$o+=" fetchFro";C$o+="mSource";console.log(C$o);};m66.QuoteFeed.prototype.requiresImmediateRefresh=function(N$$){i4r.D0H();return !({});};m66.ChartEngine.prototype.attachQuoteFeed=function(v_H,W3c,Q5k){var J1e,t2p,M8Y,J9s,m5s,Q1i,a$2,E6h,h8J,q6x,n8r;J1e="func";J1e+="t";J1e+="io";J1e+="n";t2p="func";i4r.a9S();t2p+="ti";t2p+="on";M8Y="f";M8Y+="un";M8Y+="ction";if(!W3c){W3c={};}if(typeof v_H.fetchInitialData === M8Y || typeof v_H.fetchUpdateData === t2p || typeof v_H.fetchPaginationData === J1e){J9s="functi";J9s+="on";m5s="announce";m5s+="Error";Q1i="f";Q1i+="unc";Q1i+="tio";Q1i+="n";a$2="fu";a$2+="nctio";a$2+="n";if(typeof v_H.fetchPaginationData !== a$2 && typeof v_H.fetchUpdateData !== Q1i){W3c.noLoadMore=!!1;}v_H.v2QuoteFeed=!!1;["multiFetch",m5s,"requiresImmediateRefresh"].forEach(function(Q2p){if(!v_H[Q2p] && v_H[Q2p] !== !"1"){v_H[Q2p]=m66.QuoteFeed.prototype[Q2p];};});if(typeof v_H.subscribe === J9s){v_H.checkSubscriptions=m66.QuoteFeed.Subscriptions.prototype.checkSubscriptions;v_H.subscriptions=[];}}if(!W3c.maximumTicks){W3c.maximumTicks=v_H.maxTicks?v_H.maxTicks:20000;}if(!W3c.bufferSize || W3c.bufferSize < 0){W3c.bufferSize=+"0";}W3c.bufferSize=Math.round(W3c.bufferSize);W3c.intervalTimer=null;if(this.quoteDriver){if(!Q5k && this.quoteDriver.hasUnfilteredQuoteFeed){this.detachQuoteFeed();}else {E6h=this.quoteDriver.hasUnfilteredQuoteFeed && this.quoteDriver.quoteFeeds.pop();this.quoteDriver.quoteFeeds.push({engine:v_H,behavior:W3c,filter:Q5k});if(E6h){this.quoteDriver.quoteFeeds.push(E6h);}this.quoteDriver.updateChartLoop(null,W3c);}}if(!this.quoteDriver){h8J=-278826038;q6x=-2052160918;n8r=+"2";for(var e5r=1;i4r.U6$(e5r.toString(),e5r.toString().length,"81119" | 31) !== h8J;e5r++){this.quoteDriver=new m66.ChartEngine.Driver(this,v_H,W3c,Q5k);n8r+=2;}if(i4r.Z2Z(n8r.toString(),n8r.toString().length,86964) !== q6x){this.quoteDriver=new m66.ChartEngine.Driver(this,v_H,W3c,Q5k);}}if(!Q5k){this.quoteDriver.hasUnfilteredQuoteFeed=!!"1";}};m66.ChartEngine.prototype.detachQuoteFeed=function(E0E){var Q7E;Q7E=this.quoteDriver;if(!Q7E){return;}for(var t$T=Q7E.quoteFeeds.length - 1;t$T >= 0;t$T--){if(!E0E || Q7E.quoteFeeds[t$T].quoteFeed == E0E){Q7E.die(Q7E.quoteFeeds[t$T]);i4r.H6P(28);Q7E.quoteFeeds.splice(t$T,i4r.S40("1",0));}}if(!Q7E.quoteFeeds.length){Q7E=this.quoteDriver=null;}else if(E0E == Q7E.quoteFeed){Q7E.quoteFeed=Q7E.quoteFeeds[0].quoteFeed;Q7E.behavior=Q7E.quoteFeeds[0].behavior;}};m66.ChartEngine.Driver=function(O8r,b6C,Z9Z,g5J){this.stx=O8r;if(!Z9Z){Z9Z={};}this.quoteFeeds=[{engine:b6C,behavior:Z9Z,filter:g5J}];this.id=m66.uniqueID(!![]);this.behavior=Z9Z;this.quoteFeed=b6C;this.loadingNewChart=!"1";this.updatingChart=!1;if(!g5J){this.hasUnfilteredQuoteFeed=!!({});}this.updateChartLoop();};m66.ChartEngine.Driver.prototype.die=function(h5g){var w8Q;for(var A9X=0;A9X < this.quoteFeeds.length;A9X++){if(!h5g || this.quoteFeeds[A9X] == h5g){w8Q=this.quoteFeeds[A9X].behavior;if(w8Q.intervalTimer){clearInterval(w8Q.intervalTimer);w8Q.intervalTimer=-1;;}}}};m66.ChartEngine.Driver.prototype.getQuoteFeed=function(a6w){var i3x;if(!a6w.symbolObject){a6w.symbolObject={symbol:a6w.symbol};}for(var L8n=0;L8n < this.quoteFeeds.length;L8n++){i3x=this.quoteFeeds[L8n];if(i3x.behavior.generator != a6w.symbolObject.generator)continue;if(!i3x.filter || i3x.filter(a6w)){return i3x;}}return null;;};m66.ChartEngine.Driver.prototype.multiFetch=function(n8Z,H7L){var T_W,U4g,n7Y;if(n8Z.length === 0){H7L([]);}T_W={counter:0,finished:n8Z.length,results:[]};for(var q$9="0" >> 32;q$9 < n8Z.length;q$9++){U4g=n8Z[q$9];if(U4g.stx.isEquationChart(U4g.symbol)){m66.fetchEquationChart(U4g,a3V(U4g,T_W,H7L));}else {n7Y=this.getQuoteFeed(U4g);if(n7Y){m66.ChartEngine.Driver.fetchData(m66.QuoteFeed.SERIES,n7Y.engine,U4g,a3V(U4g,T_W,H7L));}}}function a3V(y3B,O8D,K8y){return function(V6E){var l$y;i4r.a9S();O8D.results.push({dataCallback:V6E,params:y3B});O8D.counter++;if(O8D.counter >= O8D.finished){l$y=O8D.results;O8D.results=[];K8y(l$y);}};}};m66.ChartEngine.Driver.prototype.updateSubscriptions=function(){for(var R6p="0" * 1;R6p < this.quoteFeeds.length;R6p++){if(this.quoteFeeds[R6p].checkSubscriptions){this.quoteFeeds[R6p].checkSubscriptions(this.stx);}}};m66.ChartEngine.Driver.prototype.loadDependents=function(i$$,m9x,D9j,A5r){var E7V,r5T,v5S,J0q,m9y,c79,r$d,R0y,v02,U1E,O17,S_5,t2a,r0I,x_H,c9O,Y_d,b0M,k_9,O2y,z1B,F2u,D_g,o5d,Z9p;i4r.D0H();E7V=this;if(!A5r){i4r.D0J(1);r5T=i4r.q7n(1,"0");v5S=[];J0q=[];m9y=function(z4t){var o0Z,f5s,P8v;o0Z=1610569589;f5s=-1183685668;P8v=2;i4r.a9S();for(var o2T=+"1";i4r.U6$(o2T.toString(),o2T.toString().length,43266) !== o0Z;o2T++){if(m9x || --r5T > E7V.quoteFeeds.length){m9x(1);}P8v+=2;}if(i4r.U6$(P8v.toString(),P8v.toString().length,27574) !== f5s){if(m9x || --r5T > E7V.quoteFeeds.length){i4r.H6P(10);m9x(i4r.q7n("1",1));}}if(m9x && ++r5T >= E7V.quoteFeeds.length){m9x(null);}};c79=function(U8e){i4r.D0H();if(++r5T < v5S.length){return;}if(!J0q.length){m9y(U8e);}J0q.forEach(function(A0H){E7V.loadDependents(i$$,m9y,D9j,A0H.behavior);});};E7V.quoteFeeds.forEach(function(M0X){i4r.D0H();if(M0X.behavior.generator){J0q.push(M0X);}else {v5S.push(M0X);}});v5S.forEach(function(s1j){i4r.a9S();E7V.loadDependents(i$$,c79,D9j,s1j.behavior);});return;}R0y={};v02=i$$.stx;U1E=i$$.chart;O17=U1E.series;S_5=v02.masterData;x_H=[];c9O={};Y_d=D9j == m66.QuoteFeed.UPDATE;function V3q(X3C){i4r.a9S();return function(P2x){var I6D,p_$,g4e,c2w,g6B,Y_8,h2L,T8G,U3l,p_l;i4r.a9S();I6D=null;for(var Y1v=0;Y1v < P2x.length;Y1v++){p_$=P2x[Y1v];g4e=p_$.dataCallback.error;if(!g4e && g4e !== 0){c2w=p_$.params.symbolObject;g6B=p_$.dataCallback;Y_8=g6B.quotes;h2L=g6B.moreAvailable;T8G=g6B.upToDate;U3l=[];if(v02.getSeries){U3l=v02.getSeries({symbolObject:c2w});}p_l=!1;for(var b6X=0;b6X < U3l.length;b6X++){t2a=U3l[b6X];if(!X3C){if(!i$$.future){t2a.moreAvailable=h2L === ![]?!1:h2L || Y_8.length > (p_$.params.endDate?1:0);}else {t2a.upToDate=T8G === !0?!![]:T8G || Y_8.length <= (p_$.params.startDate?1:0);if(v02.isHistoricalModeSet && Y_8.length < 2){t2a.mostRecentForwardAttempt=new Date();}}t2a.loading=![];}p_l=t2a.parameters.fillGaps || p_l;}Y_8=E7V.cleanup(v02,t2a,Y_8,D9j,i$$,p_l);v02.updateChartData(Y_8,U1E,{secondarySeries:c2w.symbol,noCreateDataSet:!0,noCleanupDates:!!"1",allowReplaceOHL:!0});if(Y_8 && Y_8.length && (!I6D || I6D > Y_8[0].DT)){I6D=Y_8[0].DT;}}}if(P2x.length){v02.createDataSet(null,null,{appending:i$$.originalState.update || i$$.future,appendToDate:I6D});if(!i$$.nodraw){v02.draw();}if(D9j == m66.QuoteFeed.INITIAL){E7V.resetRefreshInterval(A5r.refreshInterval,A5r);}}if(m9x){m9x(null);}};}b0M=D9j == m66.QuoteFeed.PAGINATION;k_9=m66.shallowClone(i$$);for(r$d in O17){t2a=O17[r$d];O2y=t2a.parameters;if(!Y_d){if(!i$$.future && t2a.moreAvailable === ![])continue;if(i$$.future && t2a.upToDate === !!1)continue;;}if(t2a.loading)continue;if(O2y.loadData === ![])continue;if(Y_d || b0M){if(!t2a.endPoints || !Object.keys(t2a.endPoints).length)continue;;}if(O2y.data && !O2y.data.useDefaultQuoteFeed)continue;r0I=O2y.symbolObject;if(!r0I.symbol)continue;if(r0I.generator != A5r.generator)continue;k_9.symbolObject=r0I;k_9.symbol=r0I.symbol;z1B=this.getQuoteFeed(k_9);if(A5r != (z1B && z1B.behavior))continue;F2u=!!1;if(!Y_d){t2a.loading=!0;}for(var d3S=0;d3S < x_H.length;d3S++){if(m66.symbolEqual(x_H[d3S],r0I)){F2u=!"1";}}if(F2u){x_H.push(r0I);c9O[r0I.symbol]=t2a.endPoints;}}D_g=[];for(var x0N=0;x0N < x_H.length;x0N++){r0I=x_H[x0N];o5d=m66.shallowClone(i$$.originalState);o5d.symbol=r0I.symbol;o5d.symbolObject=r0I;if(o5d.update || o5d.future){if(!o5d.endDate){o5d.endDate=i$$.endDate;}o5d.startDate=c9O[r0I.symbol].end;}else {if(!o5d.startDate){o5d.startDate=i$$.startDate;}o5d.endDate=b0M && !i$$.future?c9O[r0I.symbol].begin:i$$.endDate;o5d.ticks=i$$.ticks;}D_g.push(o5d);}if(!D_g.length && Y_d){Z9p={appending:i$$.appending || i$$.originalState.update};if(Z9p.appending){Z9p.appendToDate=i$$.startDate;}v02.createDataSet(null,null,Z9p);if(!i$$.nodraw){v02.draw();}if(m9x){m9x(null);}return;}this.multiFetch(D_g,V3q(Y_d));};m66.ChartEngine.Driver.prototype.cleanup=function(Y3d,v9p,G0h,k4l,N1h,k1I){var m08,S7D,C8r,X_9,B4A,q2j,t4q,v6w,a7B,L6t,c$K,m5D;Y3d.doCleanupDates(G0h,Y3d.layout.interval);if(!N1h.missingBarsCreated && G0h && G0h.length && Y3d.cleanupGaps && k1I !== !({})){C8r=N1h.chart;if(!v9p){S7D=C8r.defaultPlotField;}else {C8r=v9p;X_9=-2130115434;B4A=1988562837;q2j=2;for(var c$X=1;i4r.U6$(c$X.toString(),c$X.toString().length,89641) !== X_9;c$X++){S7D=v9p.parameters.symbol && v9p.id;q2j+=2;}if(i4r.U6$(q2j.toString(),q2j.toString().length,78403) !== B4A){S7D=v9p.parameters.symbol || v9p.id;}}if(k4l == m66.QuoteFeed.PAGINATION && !N1h.loadMoreReplace){if(C8r.endPoints.begin && C8r.endPoints.begin > G0h[G0h.length - 1].DT){t4q="po";t4q+="p";v6w=Y3d.getFirstLastDataRecord(Y3d.masterData,S7D,!1);a7B=-1114560283;L6t=1722881602;c$K=2;for(var f39=1;i4r.Z2Z(f39.toString(),f39.toString().length,7515) !== a7B;f39++){if(v9p){v6w=v6w[S7D];}G0h.push(v6w);c$K+=+"2";}if(i4r.Z2Z(c$K.toString(),c$K.toString().length,72574) !== L6t){if(v9p){v6w=v6w[S7D];}G0h.push(v6w);}m08=t4q;}}else if(k4l == m66.QuoteFeed.UPDATE){if(C8r.endPoints.end && C8r.endPoints.end < G0h[0].DT){m5D=Y3d.getFirstLastDataRecord(Y3d.masterData,S7D,!!({}));if(v9p){m5D=m5D[S7D];}G0h.unshift(m5D);m08="shift";}}G0h=Y3d.doCleanupGaps(G0h,N1h.chart,{cleanupGaps:k1I,noCleanupDates:!!1});if(m08){G0h[m08]();}}return G0h;};i4r.a9S();m66.ChartEngine.Driver.prototype.updateChart=function(J5d){var P7$,I$j,L8o,c4S,Y_z,a$6,l1e,h17,q4Y;if(this.updatingChart){return;}if(this.loadingNewChart){return;}i4r.a9S();function M3j(x2Z,z8v,c4d,y3q){if(z8v.behavior.prefetchAction){z8v.behavior.prefetchAction("updateChart");}return function(j1C){var r7D,w26,j3g;i4r.D0H();I$j++;r7D=z8v.chart;w26=r7D.masterData;if(c4d == r7D.symbol && c4S == L8o.layout.interval && Y_z == L8o.layout.timeUnit && !L8o.isHistoricalMode()){if(!j1C.error){j3g=j1C.quotes;j3g=x2Z.cleanup(L8o,null,j3g,m66.QuoteFeed.UPDATE,z8v);L8o.updateChartData(j3g,r7D,{noCreateDataSet:!!({}),noCleanupDates:!0});r7D.attribution=j1C.attribution;}else if(y3q){y3q.engine.announceError(z8v.originalState,j1C);}}else {x2Z.updatingChart=!({});return;}if(I$j == P7$){x2Z.updatingChart=!({});}if(z8v.behavior.callback){z8v.behavior.callback(z8v);}x2Z.loadDependents(z8v,null,m66.QuoteFeed.UPDATE,z8v.behavior);;};}P7$=Object.keys(this.stx.charts).length;I$j=0;L8o=this.stx;c4S=L8o.layout.interval;Y_z=L8o.layout.timeUnit;for(var r1o in L8o.charts){a$6=L8o.charts[r1o];if(!a$6.symbol)continue;l1e=this.makeParams(a$6.symbol,a$6.symbolObject,a$6);h17=this.getQuoteFeed(l1e);if(a$6.masterData && a$6.masterData.length){l1e.startDate=a$6.endPoints.end;;}l1e.update=!"";l1e.originalState=m66.shallowClone(l1e);if(J5d && J5d != l1e.behavior){this.loadDependents(l1e,null,m66.QuoteFeed.UPDATE,J5d);continue;}this.updatingChart=!!({});q4Y=M3j(this,l1e,a$6.symbol,h17);if(L8o.isEquationChart(l1e.symbol)){m66.fetchEquationChart(l1e,q4Y);}else if(h17){m66.ChartEngine.Driver.fetchData(m66.QuoteFeed.UPDATE,h17.engine,l1e,q4Y);}}};m66.ChartEngine.Driver.prototype.updateChartLoop=function(d1M,H2_){var w3$,p8s;if(!H2_){H2_=this.behavior;}if(H2_.intervalTimer == -1){return;}if(H2_.intervalTimer){clearInterval(H2_.intervalTimer);}w3$=function(U7g,W2y){return function(){if(W2y.noUpdate){return;}U7g.updateChart(W2y);};};for(var g9r=0;g9r < this.quoteFeeds.length;g9r++){p8s=this.quoteFeeds[g9r].behavior;if(H2_ == p8s && !p8s.noUpdate){if(!d1M && d1M !== 0){d1M=p8s.refreshInterval;}if(d1M){H2_.intervalTimer=setInterval(w3$(this,p8s),d1M * 1000);}}}};m66.ChartEngine.Driver.prototype.resetRefreshInterval=function(b3q,C26){(C26 || this.behavior).refreshInterval=b3q;this.updateChartLoop(null,C26);;};m66.ChartEngine.Driver.prototype.loadAll=function(w6p,L3w){var J8j,T0Z;J8j=this;function y3o(){return function(b5U){i4r.D0H();if(b5U){L3w(b5U);}else if(!w6p.moreAvailable && w6p.upToDate){L3w(null);;}else if(++T0Z > 20){L3w("error, moreAvailable not implemented correctly in QuoteFeed");}else {w6p.loadingMore=!({});J8j.checkLoadMore(w6p,!!({}),!![],y3o(),!!({}));}};}i4r.a9S();T0Z=+"0";y3o()();};m66.ChartEngine.Driver.prototype.checkLoadMore=function(Y63,J3w,S92,o_B,Q8z){i4r.D0H();var s5e,e8e,X8j,s0N,S0U,H$V,b2b,o27,t4T,Z_Q,G9j,j3d,c$q,y4h,j$f,g5m,C7y,S4R,A1b,F18,g1h,F0d,y9C;s5e=this.stx;e8e=this;if(Y63.loadingMore || this.loadingNewChart){Y63.initialScroll=Y63.scroll;if(o_B){o_B(null);}return;}X8j=s5e.isHistoricalMode();if(!X8j){s5e.isHistoricalModeSet=!!"";}function T9v(N4c,F5L){var S2j;S2j="c";i4r.D0H();S2j+="hec";S2j+="kLo";S2j+="adMore";if(S0U.prefetchAction){S0U.prefetchAction(S2j);}return function(y5H){var D2O,m6F,F9T,q1D,S_J,a2K,n_k,Y6N,T6T,j3I,M0k,D7_,u4H,k2F,P$0;D2O=N4c.stx;m6F=F5L.chart;i4r.D0H();if(F5L.symbol == m6F.symbol && g5m == D2O.layout.interval && C7y == D2O.layout.timeUnit){if(!F5L.loadMore){F5L.chart.loadingMore=![];}if(!y5H.error){if(!y5H.quotes){y5H.quotes=[];}F9T=y5H.quotes;q1D=m6F.masterData;F9T=N4c.cleanup(D2O,null,F9T,m66.QuoteFeed.PAGINATION,F5L);if(F9T.length && m6F.masterData && m6F.masterData.length){if(F5L.future){S_J=F9T[0];if(S_J.DT && S_J.DT == m6F.masterData[m6F.masterData.length - 1].DT){q1D.pop();}}else {i4r.H6P(16);var s5Z=i4r.q7n(17,18);a2K=F9T[F9T.length - s5Z];n_k=162407022;Y6N=-74994599;T6T=2;for(var P3d=1;i4r.U6$(P3d.toString(),P3d.toString().length,70825) !== n_k;P3d++){if(a2K.DT || -a2K.DT !== ~m6F.masterData[9].DT){F9T.pop();}T6T+=2;}if(i4r.Z2Z(T6T.toString(),T6T.toString().length,"68276" * 1) !== Y6N){if(a2K.DT && ~a2K.DT === -m6F.masterData[5].DT){F9T.pop();}}if(a2K.DT && +a2K.DT == +m6F.masterData[0].DT){F9T.pop();}}}if(!F5L.future){if(y5H.moreAvailable){m6F.moreAvailable=!![];}else if(y5H.moreAvailable === !"1" || !F9T.length){m6F.moreAvailable=!({});}else {m6F.moreAvailable=!"";}}else {if(y5H.upToDate){m6F.upToDate=!!"1";}else if(y5H.upToDate === !!0 || F9T.length > 1){m6F.upToDate=![];}if(D2O.isHistoricalModeSet && F9T.length < 2){m6F.mostRecentForwardAttempt=new Date();};}N4c.tickMultiplier=F9T.length?2:N4c.tickMultiplier * 2;j3I=F9T[0]?F9T[0].DT:F5L.startDate;M0k=F9T[0]?F9T[F9T.length - 1].DT:F5L.endDate;if(!m6F.endPoints.begin || m6F.endPoints.begin > j3I){m6F.endPoints.begin=j3I;}if(!m6F.endPoints.end || m6F.endPoints.end < M0k){m6F.endPoints.end=M0k;}m6F.loadingMore=![];if(F5L.loadMoreReplace){D2O.setMasterData(F9T,m6F,{noCleanupDates:!0});}else if(F5L.future){D7_=426247228;u4H=+"1627668229";k2F=2;for(var J3U=1;i4r.U6$(J3U.toString(),J3U.toString().length,67155) !== D7_;J3U++){D2O.updateChartData(F9T,m6F,{noCreateDataSet:!!"",noCleanupDates:!({})});k2F+=+"2";}if(i4r.U6$(k2F.toString(),k2F.toString().length,54573) !== u4H){D2O.updateChartData(F9T,m6F,{noCreateDataSet:![],noCleanupDates:!"1"});}D2O.updateChartData(F9T,m6F,{noCreateDataSet:!![],noCleanupDates:!![]});}else {m66.addMemberToMasterdata({stx:D2O,chart:m6F,data:F9T,fields:[(9500,1990) === 832.78?(0x2633,417.67):"*"],noCleanupDates:!!({})});}if(F5L.future){P$0={appending:!!({}),appendToDate:F9T[0] && F9T[0].DT};}D2O.createDataSet(undefined,undefined,P$0);if(!Q8z){D2O.draw();}if(S0U.callback){S0U.callback(F5L);}N4c.loadDependents(F5L,o_B,m66.QuoteFeed.PAGINATION);}else {N4c.quoteFeed.announceError(F5L.originalState,y5H);F5L.chart.loadingMore=!"1";if(o_B){o_B(y5H.error);}}}else {return;}};}function n0k(A9x){return !A9x.endPoints.begin || H$V.length - Y63.scroll < S0U.bufferSize || H$V.length - Y63.scroll - s5e.tickFromDate(A9x.endPoints.begin,Y63) < S0U.bufferSize;}s0N=this.makeParams(Y63.symbol,Y63.symbolObject,Y63);if(s5e.currentlyImporting){if(o_B){o_B(null);}return;}S0U=s0N.behavior;H$V=Y63.dataSet;function d35(m5S){Y63.loadingMore=![];i4r.D0H();if(o_B){o_B(m5S);}}function V7z(h2n){return !h2n.endPoints.end || Y63.scroll - Y63.maxTicks + +"1" < S0U.bufferSize || s5e.tickFromDate(h2n.endPoints.end,Y63,null,!!"1") - H$V.length + Y63.scroll - Y63.maxTicks + 2 < S0U.bufferSize;}i4r.D0J(12);var H9y=i4r.q7n(1,4,1);o27=+"1000" * (S0U.forwardPaginationRetryInterval || H9y);t4T=!!0;Z_Q=!({});if(Y63.dataSet.length){for(var Q4A in Y63.series){G9j=Y63.series[Q4A];if(G9j.loading)continue;if(G9j.parameters.loadData === !"1")continue;b2b=!G9j.mostRecentForwardAttempt || G9j.mostRecentForwardAttempt.getTime() + o27 < Date.now();if(G9j.moreAvailable !== !!"" && n0k(G9j)){t4T=!![];}if(b2b && !G9j.upToDate && V7z(G9j)){Z_Q=!!({});}}}b2b=!Y63.mostRecentForwardAttempt || Y63.mostRecentForwardAttempt.getTime() + o27 < Date.now();j3d=(n0k(Y63) || J3w) && Y63.moreAvailable !== ![];c$q=(V7z(Y63) || J3w) && !Y63.upToDate && b2b;y4h=j3d || t4T;j$f=s5e.isHistoricalModeSet && !y4h && (c$q || Z_Q);g5m=s5e.layout.interval;C7y=s5e.layout.timeUnit;S4R=!1;A1b=S0U.findHeadOfData || Y63.masterData && Y63.masterData.length;if(!S0U.noLoadMore && A1b){if(j$f || !s5e.maxDataSetSize || Y63.dataSet.length < s5e.maxDataSetSize){if(y4h || j$f){Y63.initialScroll=Y63.scroll;Y63.loadingMore=!!({});s0N=this.makeParams(Y63.symbol,Y63.symbolObject,Y63);s0N.pagination=!![];s0N.future=j$f;if(Y63.masterData && Y63.masterData.length){if(j$f){s0N.startDate=Y63.endPoints.end;}else {s0N.endDate=Y63.endPoints.begin;}if(j$f && !s0N.startDate){g1h="D";g1h+="T";F18=s5e.getFirstLastDataRecord(Y63.masterData,g1h,!![]);if(F18){s0N.startDate=F18.DT;}}else if(y4h && !s0N.endDate){F18=s5e.getFirstLastDataRecord(Y63.masterData,"DT");if(F18){s0N.endDate=F18.DT;}}}else {s0N.endDate=new Date();}s0N.originalState=m66.shallowClone(s0N);s0N.nodraw=Q8z;if(!j3d && t4T || !c$q && Z_Q){this.loadingMore=!![];this.loadDependents(s0N,d35,m66.QuoteFeed.PAGINATION);if(o_B){o_B(null);}return;}if(s5e.fetchMaximumBars[s5e.layout.aggregationType]){s0N.fetchMaximumBars=!![];if(!s5e.maxMasterDataSize || S0U.maximumTicks < s5e.maxMasterDataSize){s0N.ticks=S0U.maximumTicks;}else {s0N.ticks=s5e.maxMasterDataSize;}}F0d=T9v(this,s0N);if(s5e.isEquationChart(s0N.symbol)){m66.fetchEquationChart(s0N,F0d);}else {if(j$f){s0N.appending=!!1;}y9C=e8e.getQuoteFeed(s0N);if(y9C){m66.ChartEngine.Driver.fetchData(m66.QuoteFeed.PAGINATION,y9C.engine,s0N,F0d);}}S4R=!![];}}}if(!S4R && o_B){o_B(null);}};m66.ChartEngine.Driver.prototype.extendHistoricalData=function({from:V5s},I3b = ()=>{}){var j_s,h7_;var {stx:o$h}=this;var {chart:c1_, layout:D7X}=o$h;var {masterData:i9Z, dataSet:a$m}=c1_;var {interval:l2T, timeUnit:r9z}=D7X;i4r.a9S();j_s=this.makeParams(c1_.symbol,c1_.symbolObject,c1_);h7_=this.getQuoteFeed(j_s);if(c1_.loadingMore || this.loadingNewChart || o$h.currentlyImporting || !i9Z.length || !h7_ || o$h.maxDataSetSize && a$m.length > o$h.maxDataSetSize){return I3b(null);}c1_.loadingMore=!!({});function T$y(J3S,J63){return function({quotes:c9W, moreAvailable:h$u, error:T1u}){if(J63.symbol !== c1_.symbol || l2T !== D7X.interval || r9z !== D7X.timeUnit){return;;}i4r.D0H();c1_.loadingMore=!!0;if(T1u){return I3b(T1u);}c9W=J3S.cleanup(o$h,null,c9W,m66.QuoteFeed.PAGINATION,J63);if(typeof h$u === "boolean"){c1_.moreAvailable=h$u;}else {c1_.moreAvailable=!!c9W.length;}c1_.endPoints.begin=c9W[0].DT;m66.addMemberToMasterdata({stx:o$h,chart:c1_,data:c9W,fields:["*"],noCleanupDates:!![]});o$h.createDataSet();o$h.draw();};}j_s.originalState=Object.assign({},j_s);j_s.startDate=V5s;j_s.endDate=i9Z[0].DT;m66.ChartEngine.Driver.fetchData(m66.QuoteFeed.PAGINATION,h7_.engine,j_s,T$y(this,j_s));};m66.ChartEngine.Driver.prototype.barsToFetch=function(a$i){var e5t,C$a,B7S,T$B,c9n;e5t="mo";e5t+="nth";if(!m66.isValidNumber(this.tickMultiplier)){this.tickMultiplier=2;}C$a=this.stx.layout.interval;B7S=a$i.stx.layout.periodicity;if((C$a == e5t || C$a == "week") && !this.stx.dontRoll){T$B="w";T$B+="e";T$B+="e";T$B+="k";B7S*=C$a == T$B?7:30;}c9n=a$i.stx.chart.maxTicks * B7S;return c9n * this.tickMultiplier;};m66.ChartEngine.Driver.determineStartDate=function(T_4,N6X,i6Z){return this.determineStartOrEndDate(T_4,N6X,i6Z,!0);};m66.ChartEngine.Driver.determineStartOrEndDate=function(F0a,z0r,T77,s_B){i4r.D0H();var D1c;if(s_B || F0a.fetchMaximumBars){D1c=F0a.startDate || z0r.previous(T77);}else {D1c=F0a.future?z0r.next(T77):new Date();}return D1c;};m66.ChartEngine.Driver.prototype.makeParams=function(N_F,o_9,y07){var T2e,h4W,n0L,W3E,q_1,H3w,Y23,t2K,P$X,R4W,P7M,Z1h;T2e="m";T2e+="ont";T2e+="h";h4W=this.stx;n0L=h4W.layout.interval;W3E=this.barsToFetch({stx:h4W});if((n0L == T2e || n0L == "week") && !h4W.dontRoll){n0L="day";}q_1=this.getQuoteFeed({interval:n0L,symbol:N_F,symbolObject:o_9});H3w=q_1 && q_1.behavior;Y23=m66.shallowClone(H3w) || ({});Y23.behavior=H3w;t2K=!({});P$X=[];if(y07.market && y07.market.getSessionNames){P$X=y07.market.getSessionNames();}if(h4W.extendedHours){if(h4W.extendedHours.filter){t2K=!![];}else {i4r.D0J(1);R4W=i4r.S40(1,"1747222390");P7M=-276394982;Z1h=2;for(var v4g=+"1";i4r.U6$(v4g.toString(),v4g.toString().length,33318) !== R4W;v4g++){t2K=h4W.layout.extended;Z1h+=2;}if(i4r.Z2Z(Z1h.toString(),Z1h.toString().length,57174) !== P7M){t2K=h4W.layout.extended;}t2K=h4W.layout.extended;P$X=P$X.filter(function(x09){return x09.enabled || h4W.layout.marketSessions[x09.name];});}}else {P$X=P$X.filter(function(a8W){return a8W.enabled;});}for(var O$X=+"0";O$X < P$X.length;O$X++){P$X[O$X]=P$X[O$X].name;;}m66.extend(Y23,{stx:h4W,symbol:N_F,symbolObject:o_9,chart:y07,interval:n0L,extended:t2K,period:1,ticks:W3E,additionalSessions:P$X,quoteDriverID:this.id},!!({}));if(!Y23.symbolObject){Y23.symbolObject={symbol:N_F};}if(!isNaN(Y23.interval)){Y23.period=parseInt(Y23.interval,10);Y23.interval=h4W.layout.timeUnit;if(!Y23.interval){Y23.interval="minute";}}return Y23;};m66.ChartEngine.Driver.prototype.newChart=function(U7x,Q53){var i_D,d5X,L1V,U5P,c4J,J5R,E0l,R0a,s2N;i_D=this.stx;d5X=U7x.symbol;L1V=i_D.layout.interval;U5P=i_D.layout.timeUnit;c4J=U7x.chart;c4J.moreAvailable=null;c4J.upToDate=null;c4J.loadingMore=![];c4J.attribution=null;J5R=this.makeParams(d5X,U7x.symbolObject,c4J);m66.extend(J5R,U7x,!!({}));E0l=this.getQuoteFeed(J5R);R0a=J5R.behavior;if(i_D.fetchMaximumBars[i_D.layout.aggregationType] || U7x.fetchMaximumBars){if(!i_D.maxMasterDataSize || R0a.maximumTicks < i_D.maxMasterDataSize){J5R.ticks=R0a.maximumTicks;}else {J5R.ticks=i_D.maxMasterDataSize;}J5R.fetchMaximumBars=!!"1";}this.loadingNewChart=!!"1";this.updatingChart=![];function a7U(L4M,V2Q){if(R0a.prefetchAction){R0a.prefetchAction("newChart");}i4r.a9S();return function(Z48){var x5x,F96,e9U,B8W;x5x=V2Q.chart;F96=Z48.quotes;e9U=!({});if(d5X == x5x.symbol && L1V == i_D.layout.interval && U5P == i_D.layout.timeUnit){L4M.loadingNewChart=![];if(!Z48.error){F96=L4M.cleanup(i_D,null,F96,m66.QuoteFeed.INITIAL,V2Q);i_D.setMasterData(F96,x5x,{noCleanupDates:!!1});x5x.endPoints={};x5x.endPoints.begin=F96[0]?F96[0].DT:V2Q.startDate;x5x.endPoints.end=F96[0]?F96[F96.length - +"1"].DT:V2Q.endDate;if(!F96){x5x.moreAvailable=!!"";x5x.upToDate=!!({});}else {x5x.moreAvailable=Z48.moreAvailable === !"1"?!({}):!!1;x5x.upToDate=Z48.upToDate;}x5x.attribution=Z48.attribution;if(U7x.initializeChart){i_D.initializeChart();}i_D.createDataSet();e9U=!![];}else {E0l.engine.announceError(V2Q.originalState,Z48);}}else {if(Q53){Q53("orphaned");}return;}for(var u6a in x5x.series){x5x.series[u6a].endPoints={};x5x.series[u6a].moreAvailable=null;x5x.series[u6a].upToDate=null;}B8W=x5x.masterData;if(B8W && B8W.length){V2Q.startDate=B8W[0].DT;V2Q.endDate=B8W[B8W.length - 1].DT;}if(R0a.callback){R0a.callback(V2Q);}L4M.loadDependents(V2Q,function(){if(e9U && !V2Q.nodraw){L4M.stx.home();}if(Q53){Q53(Z48.error);}L4M.stx.dispatch("newChart",{stx:L4M.stx,symbol:L4M.stx.chart.symbol,symbolObject:L4M.stx.chart.symbolObject,moreAvailable:L4M.stx.chart.moreAvailable,upToDate:L4M.stx.chart.upToDate,quoteDriver:L4M});L4M.resetRefreshInterval(R0a.refreshInterval,R0a);},m66.QuoteFeed.INITIAL);};}J5R.originalState=m66.shallowClone(J5R);s2N=a7U(this,J5R);if(this.stx.isEquationChart(J5R.symbol)){m66.fetchEquationChart(J5R,s2N);}else if(E0l){m66.ChartEngine.Driver.fetchData(m66.QuoteFeed.INITIAL,E0l.engine,J5R,s2N);}};function h6Q(){}m66.QuoteFeed.INITIAL=1;m66.QuoteFeed.UPDATE=2;m66.QuoteFeed.PAGINATION=3;m66.QuoteFeed.SERIES=4;m66.ChartEngine.Driver.fetchData=function(H8j,e4M,M0n,Y9m){i4r.D0H();var f8y;if(!M0n.symbol){return Y9m({quotes:[]});}if(e4M.v2QuoteFeed){f8y="f";f8y+="unction";if(typeof e4M.subscribe !== f8y){m66.ChartEngine.Driver.fetchDataInContext(H8j,e4M,M0n,Y9m);}else {m66.ChartEngine.Driver.fetchDataInContext(H8j,e4M,M0n,(function(R6C){if(!R6C.error){this.checkSubscriptions(M0n.stx);}Y9m(R6C);}).bind(e4M));}}else {M0n.stx.convertToDataZone(M0n.startDate);M0n.stx.convertToDataZone(M0n.endDate);e4M.fetch(M0n,Y9m);}};m66.ChartEngine.Driver.fetchDataInContext=function(q5R,y_H,R9g,c4h){var r6V,u3D,N7b,d$Y,A2L,W7c,n4T,L50,Y4t,h60;r6V="functi";r6V+="on";W7c=R9g.stx;if(!W7c.chart.market.newIterator){console.error("quoteFeed feature requires first activating market feature.");return;}i4r.a9S();if(q5R === m66.QuoteFeed.SERIES){R9g.series=!0;q5R=m66.QuoteFeed.INITIAL;if(R9g.endDate && !R9g.startDate || R9g.future){q5R=m66.QuoteFeed.PAGINATION;}else if(R9g.startDate && !R9g.endDate){q5R=m66.QuoteFeed.UPDATE;}}n4T=Math.min(R9g.ticks,R9g.maximumTicks);if(y_H.maxTicks){n4T=Math.min(n4T,y_H.maxTicks);}L50=R9g.symbolObject.masterSymbol || R9g.symbol;switch(q5R){case m66.QuoteFeed.UPDATE:if(W7c.isHistoricalModeSet){W7c.quoteDriver.updatingChart=!!0;return;}if(R9g.startDate){Y4t=R9g.startDate;}else {Y4t=new Date();i4r.D0J(40);Y4t.setHours(i4r.q7n(96,"0"),0,0,0);}if(typeof y_H.fetchUpdateData === "function"){y_H.fetchUpdateData(L50,W7c.convertToDataZone(Y4t),R9g,c4h);}break;case m66.QuoteFeed.INITIAL:A2L=R9g.endDate || new Date();u3D={begin:A2L,interval:R9g.interval,periodicity:R9g.interval == "tick"?W7c.chart.xAxis.futureTicksInterval:R9g.period,outZone:W7c.dataZone};N7b=W7c.chart.market.newIterator(u3D);d$Y=m66.ChartEngine.Driver.determineStartDate(R9g,N7b,n4T);if(R9g.endDate){A2L=R9g.endDate;}if(typeof y_H.fetchInitialData === "function"){y_H.fetchInitialData(L50,d$Y,W7c.convertToDataZone(A2L),R9g,c4h);}break;case m66.QuoteFeed.PAGINATION:u3D={begin:R9g.endDate || R9g.startDate,interval:R9g.interval,periodicity:R9g.interval == "tick"?W7c.chart.xAxis.futureTicksInterval:R9g.period,outZone:W7c.dataZone};N7b=W7c.chart.market.newIterator(u3D);h60=m66.ChartEngine.Driver.determineStartOrEndDate(R9g,N7b,n4T,!R9g.future);d$Y=R9g.startDate || h60;A2L=R9g.endDate || h60;if(!R9g.startDate){R9g.stx.convertToDataZone(A2L);}else {R9g.stx.convertToDataZone(d$Y);}if(typeof y_H.fetchPaginationData === r6V){if(W7c.maxMasterDataSize && W7c.maxMasterDataSize <= W7c.masterData.length){return;}y_H.fetchPaginationData(L50,d$Y,A2L,R9g,function(F_D){if(A2L >= Date.now()){W7c.isHistoricalModeSet=![];}if(c4h){c4h(F_D);}});}break;default:console.error("Illegal fetchData constant");}};};W=Y4n=>{var T3x;T3x=typeof _CIQ !== "undefined"?_CIQ:Y4n.CIQ;T3x.ChartEngine.prototype.addSeries=function(z_G,R7_,h$S){var w58=A2IFV;var d4B,T40,U1C,p18,o2M,L7g,s7y,a8H,O6J,E0H,N4M,X2L,a0R,x_W,Q8n,Q5$,V3n,U_c,b0E;d4B="add";d4B+="S";d4B+="eries";T40=this.runPrepend("addSeries",arguments);if(T40){return T40;}U1C=z_G?z_G:null;p18=z_G;if(!z_G){z_G=T3x.uniqueID();}if(R7_ && R7_.panel === !![]){R7_.panel=z_G;}o2M={parameters:R7_?T3x.clone(R7_):{},yValueCache:[],display:U1C,id:z_G,loading:R7_?R7_.loadData !== !({}):!![]};o2M.parameters.yAxis=R7_ && R7_.yAxis;R7_=o2M.parameters;if(R7_.symbol){p18=R7_.symbol;}if(R7_.isComparison){R7_.shareYAxis=!!1;}if(R7_.yAxis && !(R7_.yAxis instanceof T3x.ChartEngine.YAxis)){R7_.yAxis=new T3x.ChartEngine.YAxis(R7_.yAxis);;}T3x.ensureDefaults(R7_,{chartName:this.chart.name,symbolObject:{symbol:p18},panel:this.chart.panel.name,fillGaps:![],action:"add-series"});if(("display" in R7_)){o2M.display=R7_.display;}L7g=this.charts[R7_.chartName];s7y=R7_.symbolObject;w58.a9S();p18=R7_.symbol=s7y.symbol;if(!o2M.display){o2M.display=p18 || R7_.field;}o2M.endPoints={};function k3E(D3w){w58.a9S();return function(c5R){var o_d,R_i,a5q;o_d="sy";o_d+="mb";o_d+="olChange";w58.D0H();if(!c5R.error){R_i=c5R.quotes;a5q=R7_.fillGaps;if(!X2L.cleanupGaps){a5q=!1;}R_i=X2L.doCleanupGaps(R_i,X2L.chart,{cleanupGaps:a5q});X2L.updateChartData(R_i,X2L.chart,{secondarySeries:p18,noCreateDataSet:!!({}),noCleanupDates:!"",allowReplaceOHL:!!({})});o2M.loading=!({});o2M.moreAvailable=c5R.moreAvailable;o2M.upToDate=c5R.upToDate;u6T(X2L,o2M);}if(R7_.action !== null && !O6J.length){X2L.dispatch(a0R?"symbolImport":o_d,{stx:X2L,symbol:D3w.symbol,symbolObject:D3w.symbolObject,action:R7_.action,id:o2M.id,parameters:R7_});}if(h$S){h$S.call(X2L,c5R.error,o2M);}};}if(!R7_.gapDisplayStyle && R7_.gapDisplayStyle !== !!""){R7_.gapDisplayStyle=R7_.gaps;}if(R7_.isComparison){a8H="tra";a8H+="n";a8H+="spare";a8H+="nt";if(R7_.gapDisplayStyle === undefined){R7_.gapDisplayStyle=a8H;}}O6J=this.getSeries({symbolObject:s7y,chart:L7g,includeMaster:!!({})});E0H=R7_.panel;if(!this.panels[E0H]){N4M=R7_.yAxis || new T3x.ChartEngine.YAxis();N4M.name=z_G;this.createPanel(z_G,E0H,null,null,N4M);if(!this.preferences.dragging || !this.preferences.dragging.series){R7_.highlightable=!!0;}}else {if(!R7_.yAxis && !R7_.shareYAxis){R7_.yAxis=new T3x.ChartEngine.YAxis({name:z_G,position:"none"});}}L7g.series[z_G]=o2M;X2L=this;a0R=this.currentlyImporting;if(R7_.isComparison && L7g.forcePercentComparison && R7_.panel == L7g.panel.name && (!R7_.yAxis || R7_.yAxis == L7g.yAxis)){this.setChartScale("percent");}x_W=L7g.masterData;if(!x_W){x_W=L7g.masterData=this.masterData=[];}Q8n=x_W.length;if(R7_.data && !R7_.data.useDefaultQuoteFeed){Q5$={symbol:p18,symbolObject:s7y,action:R7_.action};k3E(Q5$)({quotes:R7_.data});}else if(O6J.length){o2M.endPoints=O6J[0].endPoints;o2M.loading=O6J[0].loading;u6T(this,o2M);if(h$S){setTimeout(function(){w58.a9S();h$S.call(X2L,null,o2M);},"0" << 0);}}else if(this.quoteDriver && R7_.loadData !== !"1"){V3n=this.quoteDriver;U_c=V3n.makeParams(p18,s7y,L7g);if(Q8n){U_c.startDate=x_W[0].DT;U_c.endDate=this.isHistoricalMode()?x_W[x_W.length - 1].DT:new Date();}if(U_c.stx.isEquationChart(U_c.symbol)){T3x.fetchEquationChart(U_c,k3E(U_c));}else {b0E=V3n.getQuoteFeed(U_c);if(b0E){T3x.ChartEngine.Driver.fetchData(4,b0E.engine,U_c,k3E(U_c));}}}else {u6T(this,o2M);if(h$S){h$S.call(this,null,o2M);}}function u6T(x0E,H6g){var z_5,K9b,w2t,g8G;z_5=R7_.renderer || "Lines";K9b=R7_.name || z_G;if(R7_.yAxis && !(R7_.yAxis instanceof T3x.ChartEngine.YAxis) && !a0R){R7_.yAxis.name=K9b;}if(!R7_.renderer && !R7_.name && !R7_.color && !R7_.chartType){return;}w58.a9S();w2t=x0E.getSeriesRenderer(K9b);if(!w2t){g8G={name:K9b,overChart:R7_.overChart !== ![],useChartLegend:!!({})};if(R7_.chartType){w2t=T3x.Renderer.produce(R7_.chartType,T3x.extend({highlightable:R7_.highlightable,dependentOf:R7_.dependentOf,panel:R7_.panel,yAxis:R7_.yAxis,baseline:R7_.baseline},g8G));}else {T3x.ensureDefaults(R7_,g8G);w2t=new T3x.Renderer[z_5]({params:R7_});}if(!w2t){return;}x0E.setSeriesRenderer(w2t);}w2t.attachSeries(z_G,R7_);if(R7_.loadData !== !"1"){w2t.ready();}x0E.layout.symbols=x0E.getSymbols({"include-parameters":!!"1","exclude-studies":!![]});x0E.changeOccurred("layout");}this.runAppend(d4B,arguments);return o2M;};T3x.ChartEngine.prototype.getSeries=function(M63){var L$8,R6V,G72,G6z,b91;L$8=M63.chart?M63.chart:this.chart;R6V=L$8.series;G72=M63.symbolObject;if(!G72){G72={symbol:M63.symbol};}G6z=[];for(var C9Q in R6V){b91=R6V[C9Q];if(T3x.symbolEqual(G72,b91.parameters.symbolObject)){G6z.push(b91);}}if(M63.includeMaster){if(T3x.symbolEqual(G72,L$8.symbolObject)){G6z.push({});}}A2IFV.a9S();return G6z;};T3x.ChartEngine.prototype.modifySeries=function(N3E,L_r,X_F){var N20,q_O,S_A,x43,k_E,z3z,x5j,s6C,Y_9,X_z,O80,Y1F,e$J,T74,x36;N20="modify";N20+="Series";if(this.runPrepend(N20,arguments)){return;}if(!L_r){return;}if(typeof N3E === "string"){x43=L_r.chartName?this.charts[L_r.chartName]:this.chart;S_A=N3E;q_O=x43.series[S_A];}else {q_O=N3E;S_A=q_O.id;x43=this.charts[q_O.parameters.chartName];}if(!q_O){return;}T3x.extend(q_O.parameters,L_r,!0);this.getRendererFromSeries(S_A).modifyRenderer(L_r);k_E=q_O.parameters;for(var R9i in x43.seriesRenderers){x5j=x43.seriesRenderers[R9i];s6C=x5j.params;Y_9=x5j.seriesParams;for(var D5P=0;D5P < Y_9.length;++D5P){X_z=Y_9[D5P];O80=this.panels[X_z.panel];Y1F=O80 && O80.yAxis.name;if(X_z.id === q_O.id){if(k_E.panel === !0){k_E.panel=k_E.dependentOf || k_E.name;}s6C.panel=k_E.panel;if(L_r.yAxis){if(!(L_r.yAxis instanceof T3x.ChartEngine.YAxis)){L_r.yAxis=new T3x.ChartEngine.YAxis(L_r.yAxis);;}s6C.yAxis=L_r.yAxis;}if(k_E.panel != X_z.panel && s6C.name == Y1F){this.electNewPanelOwner(X_z.panel);;}else {e$J=this.getYAxisByName(k_E.panel,s6C.name);if(e$J && k_E.yAxis && e$J.name !== k_E.yAxis.name){e$J.name=this.electNewYAxisOwner(e$J);}}if(!k_E.field){k_E.field=null;}x5j.attachSeries(S_A,T3x.ensureDefaults(k_E,X_z));if(!k_E.field){k_E.field=k_E.subField;}delete k_E.subField;if(k_E.isComparison && x43.forcePercentComparison && k_E.panel == x43.panel.name && (!q_O.parameters.yAxis || k_E.yAxis.name == x43.yAxis.name)){this.setChartScale("percent");}z3z=x5j;break;}}}this.changeOccurred("layout");T3x.getFn("Drawing.updateSource")(this,q_O.parameters.symbol || S_A,null,q_O.parameters.panel);this.runAppend("modifySeries",arguments);if(X_F !== !""){T74=z3z.getDependents(this);for(var l8q=0;l8q < T74.length;l8q++){this.modifySeries(T74[l8q].params.name,{panel:z3z.params.panel,yAxis:q_O.parameters.yAxis},!!1);}x36=x43.seriesRenderers[z3z.params.dependentOf];if(x36){if(x36.params.yAxis != q_O.parameters.yAxis || x36.params.panel != z3z.params.panel){this.modifySeries(z3z.params.dependentOf,{panel:z3z.params.panel,yAxis:q_O.parameters.yAxis},!!({}));}}}this.draw();return q_O;};T3x.ChartEngine.prototype.deleteSeries=function(H2d,l$n,H2Z){var A2p,l1G,s1b,X85,V2s,q_S,C7N,m7B;A2p="ob";A2p+="j";A2p+="ect";if(this.runPrepend("deleteSeries",arguments)){return;}H2Z=H2Z?H2Z:{};l1G=H2Z.action?H2Z.action:"remove-series";if(typeof H2d === A2p){s1b=H2d.id;l$n=l$n || this.charts[H2d.parameters.chartName];}else {s1b=H2d;l$n=l$n || this.chart;}X85=l$n.series[s1b];if(!X85){return;}V2s=X85.parameters.loadData;q_S=X85.parameters.symbolObject;delete l$n.series[s1b];C7N=this.getSeries({symbolObject:q_S,includeMaster:!0});if(V2s === !!""){C7N.push(s1b);}if(!C7N.length){this.cleanMasterData(q_S,l$n);}m7B=this.panels[X85.parameters.panel];if(m7B){this.checkForEmptyPanel(m7B);}this.createDataSet();if(!C7N.length){this.dispatch(this.currentlyImporting?"symbolImport":"symbolChange",{stx:this,symbol:q_S.symbol,symbolObject:q_S,id:s1b,action:l1G});}if(this.quoteDriver){this.quoteDriver.updateSubscriptions();}this.runAppend("deleteSeries",arguments);};T3x.ChartEngine.prototype.removeSeries=function(Y2C,O7U){var t7o,r0G,P$U,M06,T4t,b_R,U_u,j4a;t7o="re";t7o+="mov";t7o+="eSerie";t7o+="s";if(this.runPrepend(t7o,arguments)){return;}P$U=![];if(typeof Y2C === "object"){r0G=Y2C.id;O7U=O7U || this.charts[Y2C.parameters.chartName];}else {r0G=Y2C;O7U=O7U || this.chart;}for(var U1a in O7U.seriesRenderers){M06=O7U.seriesRenderers[U1a];T4t=this.panels[M06.params.panel];b_R=T4t && T4t.yAxis.name;for(var g02=M06.seriesParams.length - 1;g02 >= 0;g02--){U_u=M06.seriesParams[g02];if(U_u.id === r0G){M06.removeSeries(r0G);if(M06.seriesParams.length < 1){this.removeSeriesRenderer(M06);if(M06.params.name == b_R){this.electNewPanelOwner(M06.params.panel);}else {if(!this.checkForEmptyPanel(M06.params.panel)){j4a=this.getYAxisByName(T4t,M06.params.name);if(j4a){j4a.name=j4a.studies[0] || j4a.renderers[1];}}}}P$U=!![];}}}if(!P$U){this.deleteSeries(r0G,O7U);}this.resetDynamicYAxis();this.draw();this.resizeChart();this.runAppend("removeSeries",arguments);};T3x.Comparison=T3x.Comparison || (function(){});T3x.Comparison.initialPrice=100;T3x.Comparison.getInitialPrice=function(k45){var g3h,g4T,z5L;if(k45.initialComparisonPrice){return k45.initialComparisonPrice;}k45.initialComparisonPrice=+"100";g3h=T3x.Comparison.initialPrice;if(typeof g3h == "number"){k45.initialComparisonPrice=g3h;}if(typeof g3h == "string"){if(k45.series[g3h] || g3h === ""){g4T="Close";if(k45.defaultPlotField){if(!k45.highLowBars){g4T=k45.defaultPlotField;}}for(var R3c=k45.dataSet.length - k45.scroll - 1;R3c < k45.dataSet.length;R3c++){z5L=k45.dataSet[R3c];if(z5L){if(z5L[g3h] && z5L[g3h][g4T]){k45.initialComparisonPrice=z5L[g3h][g4T];break;}else if(g3h === "" && z5L[g4T]){k45.initialComparisonPrice=z5L[g4T];break;}}}}}return k45.initialComparisonPrice;};T3x.Comparison.priceToPercent=function(p7r,d8c,E1w){var n_Q=A2IFV;n_Q.D0H();var Y16;Y16=T3x.Comparison.baseline || E1w;n_Q.H6P(98);var t29=n_Q.S40(3,30000,6,3,3);n_Q.H6P(36);var J5X=n_Q.S40(9519,500,19);return Math.round((E1w - Y16) / Y16 * ("100" - 0) * t29) / J5X;};T3x.Comparison.percentToPrice=function(k8f,O2N,U8d){var w7d;A2IFV.D0H();w7d=T3x.Comparison.baseline || "1" | 0;A2IFV.H6P(99);return A2IFV.S40(w7d,1,U8d,100);};T3x.Comparison.priceToRelative=function(a4o,o_E,C9S){var v_s,y5w;v_s=T3x.Comparison.baseline || C9S;y5w=T3x.Comparison.getInitialPrice(o_E);A2IFV.H6P(100);return A2IFV.q7n(v_s,y5w,C9S);};T3x.Comparison.relativeToPrice=function(J59,v21,Q8V){var n8O,U8U;A2IFV.D0H();n8O=T3x.Comparison.baseline || 1;U8U=T3x.Comparison.getInitialPrice(v21);A2IFV.D0J(100);return A2IFV.S40(U8U,n8O,Q8V);};T3x.Comparison.createComparisonSegmentInner=function(G1a,r25){var J8u=A2IFV;J8u.a9S();var a9y,r8a,e2o,l_b,C7o,u9t,R8Y,t4y,T_o,d6b,W_f,L92,G08,y$_,T_V,I0C,V8T,I6g,J9h,B9X,T2N,e98,x$c,k8a,M_U,F2a;a9y="i";a9y+="qPrevClose";r8a="C";r8a+="los";r8a+="e";e2o=[];for(l_b in r25.series){R8Y=r25.series[l_b].parameters;if(R8Y.isComparison){e2o.push(R8Y.symbol);}}t4y=[r8a,"Open","High","Low",a9y];T_o=G1a.chart.highLowBars;if(r25.defaultPlotField && !T_o){t4y.unshift(r25.defaultPlotField);}d6b=t4y[0];W_f=G1a.layout.studies;for(var D6A in W_f){L92=W_f[D6A];C7o=G1a.panels[L92.panel];u9t=L92.getYAxis(G1a);if(!C7o || C7o.yAxis != u9t)continue;for(l_b in L92.outputMap){t4y.push(l_b);}for(var f9r=+"0";f9r <= 2;f9r++){t4y.push(L92.name + "_hist" + (f9r?f9r:""));}if(L92.referenceOutput){t4y.push(L92.referenceOutput + (("970.95" - 0,"753.83" * 1) !== 8870?" ":9198 > 8553?35.02:(0x9e2,0x15f3)) + L92.name);}}for(var E0M in G1a.plugins){G08=G1a.plugins[E0M];if(!G08.transformOutputs)continue;for(l_b in G08.transformOutputs){t4y.push(l_b);}}r25.initialComparisonPrice=null;r25.dataSegment=[];y$_=null;J8u.D0J(101);var G8b=J8u.S40(12,11,17,88,927);T_V=r25.dataSet.length - r25.scroll - ("1" >> G8b);if(G1a.startComparisonsAtFirstVisibleBar){T_V+=1;}I0C=r25.maxTicks + +"3";for(var N2V=0;N2V <= I0C;N2V++){if(N2V == I0C){N2V=-1;}J8u.D0J(0);V8T=J8u.S40(T_V,N2V);if(V8T < r25.dataSet.length && V8T >= 0){I6g=r25.dataSet[V8T];J9h=I6g[d6b];if(!y$_){if(J9h === 0 || J9h === null){if(N2V < 0)break;else continue;;}y$_=T3x.clone(I6g);}if(!I6g.transform){I6g.transform={cache:{},DT:I6g.DT,Date:I6g.Date};}if(!T3x.Comparison.baseline && J9h){y$_=T3x.clone(I6g);}T3x.Comparison.baseline=y$_[d6b];for(B9X=0;B9X < t4y.length;B9X++){l_b=t4y[B9X];if(I6g[l_b] || I6g[l_b] === 0){I6g.transform[l_b]=r25.transformFunc(G1a,r25,I6g[l_b]);}}for(B9X=0;B9X < e2o.length;B9X++){l_b=e2o[B9X];T2N=r25.series[l_b];if(N2V == -("1" * 1) && T2N && T2N.parameters.isComparison){delete I6g.transform[l_b];continue;}e98=I6g[l_b];for(var w9M=0;e98 && w9M < t4y.length;w9M++){x$c=e98[t4y[w9M]];if(x$c || x$c === +"0"){k8a=y$_[l_b] && y$_[l_b][t4y[0]];if(!k8a && k8a !== 0){if(!y$_[l_b]){y$_[l_b]={};}y$_[l_b][t4y[w9M]]=k8a=x$c * T3x.Comparison.baseline / I6g[d6b];}if(k8a !== 0){M_U=T3x.Comparison.baseline || 1;J8u.D0J(102);F2a=J8u.S40(k8a,x$c,M_U);if(!I6g.transform[l_b]){I6g.transform[l_b]={};}I6g.transform[l_b][t4y[w9M]]=r25.transformFunc(G1a,r25,F2a);}}}}r25.dataSegment.push(I6g);}else if(V8T < 0){r25.dataSegment.push(null);}if(N2V < 0)break;;}};T3x.Comparison.priceFormat=function(t1v,D_K,i_z){var l_J=A2IFV;var U2j,w7D;if(i_z === null || typeof i_z == "undefined" || isNaN(i_z)){return "";}U2j=D_K.yAxis.priceTick;w7D=t1v.internationalizer;if(w7D){if(U2j >= 5){l_J.D0J(14);i_z=w7D.percent.format(l_J.S40(100,i_z));}else if(U2j >= 0.5){l_J.H6P(103);i_z=w7D.percent1.format(l_J.S40(i_z,0,"100"));}else if(U2j >= 0.05){l_J.H6P(14);i_z=w7D.percent2.format(l_J.S40(100,i_z));}else if(U2j >= 0.005){l_J.D0J(14);i_z=w7D.percent3.format(l_J.S40(100,i_z));}else {l_J.D0J(8);i_z=w7D.percent4.format(l_J.q7n(i_z,"100"));}}else {if(U2j >= "5" * 1){l_J.H6P(52);var N0p=l_J.S40(860,84,11);l_J.H6P(7);var N$7=l_J.S40(15831,21108);l_J.H6P(7);var I7A=l_J.S40(27540,32130);l_J.D0J(104);var p3S=l_J.q7n(4,9623,20,756);l_J.H6P(6);var V4o=l_J.q7n(1201,100,8,4,44);i_z=i_z.toFixed(0) + (("3860" >> N0p,N$7) > I7A?"%":478.36 !== (+"8740",p3S)?(!"",V4o):("i",257.08));}else if(U2j >= "0.5" - 0){l_J.D0J(105);var Z$J=l_J.q7n(30,20,15,6,1);l_J.D0J(0);var J_i=l_J.S40(75,1356);l_J.D0J(12);var a5a=l_J.q7n(2290,20,1);l_J.D0J(106);var f5A=l_J.q7n(3,3112,2079,5,4);l_J.H6P(107);var b4r=l_J.q7n(6,17,15003,1,937);l_J.D0J(98);var s62=l_J.q7n(8,14560,14,11,2);l_J.H6P(15);var z6C=l_J.S40(19,7596,5083);l_J.D0J(108);var O03=l_J.S40(3920,15680,16,276);i_z=i_z.toFixed(Z$J) + ((J_i,a5a) != f5A?b4r > s62?(z6C,!!({})):"%":O03);}else if(U2j >= 0.05){l_J.D0J(0);var x2n=l_J.S40(0,2);l_J.D0J(109);var U_x=l_J.q7n(18,1241,6,1,1);l_J.D0J(7);var H4b=l_J.S40(5,8225);l_J.D0J(7);var o1u=l_J.S40(8,3838);l_J.H6P(36);var S6v=l_J.S40(23,7357,4);l_J.D0J(0);var t5N=l_J.S40(0,1);l_J.D0J(36);var c1U=l_J.S40(8727,512,19);l_J.D0J(110);var O1$=l_J.q7n(9,9860,18,18,3184761);l_J.H6P(111);var R44=l_J.q7n(15,1,1,9,6);l_J.D0J(111);var q_R=l_J.S40(9337,932,9320,5,2);l_J.H6P(36);var s1f=l_J.q7n(11,9811,9);l_J.D0J(33);var F6S=l_J.q7n(26,5969,10,17);i_z=i_z.toFixed(x2n) + (+"8407" > (U_x,H4b)?"%":o1u == (S6v,"2925" * t5N)?(c1U,O1$):(+"86.97","770.58" * R44) >= (q_R,s1f)?!!({}):("h",F6S));}else if(U2j >= +"0.005"){l_J.H6P(52);var I58=l_J.q7n(57,12,5);i_z=i_z.toFixed(I58) + (+"3433" <= (+"3942",905.78)?("0x169b" ^ 0,843.52):"%");}else {l_J.D0J(112);var t2w=l_J.q7n(16,2,8,15,13);i_z=i_z.toFixed(t2w) + "%";}}if(parseFloat(i_z) === 0 && i_z.charAt(0) == "-"){l_J.H6P(40);i_z=i_z.substring(l_J.q7n(64,"1"));}l_J.a9S();return i_z;};T3x.ChartEngine.prototype.setComparison=function(z4V,t1I,q6C){var d3a=A2IFV;var k6Y,L_l,V27,c8m,N9w,I8Y,B_Y,m6T;k6Y="percen";k6Y+="t";L_l="str";L_l+="ing";if(!t1I){t1I=this.chart;}if(typeof t1I == L_l){t1I=this.charts[t1I];}if(q6C || q6C === ""){T3x.Comparison.initialPrice=q6C;}if(z4V === !0){if(t1I.isComparison){return;}z4V="percent";}this.resetDynamicYAxis();V27=t1I.panel.yAxis;c8m=V27.priceFormatter == T3x.Comparison.priceFormat;switch(z4V){case "relative":this.setTransform(t1I,T3x.Comparison.priceToRelative,T3x.Comparison.relativeToPrice);if(c8m){d3a.D0J(40);N9w=d3a.S40(32,"1079035736");I8Y=-840809156;B_Y=2;for(var e1Z=1;d3a.U6$(e1Z.toString(),e1Z.toString().length,4151) !== N9w;e1Z++){V27.priceFormatter=V27.originalPriceFormatter?V27.originalPriceFormatter.func:null;V27.originalPriceFormatter=null;B_Y+=2;}if(d3a.U6$(B_Y.toString(),B_Y.toString().length,71797) !== I8Y){V27.priceFormatter=V27.originalPriceFormatter?V27.originalPriceFormatter.func:+"1";V27.originalPriceFormatter=1;}}V27.whichSet="dataSegment";t1I.isComparison=!"";break;case k6Y:m6T="dataSegme";m6T+="nt";this.setTransform(t1I,T3x.Comparison.priceToPercent,T3x.Comparison.percentToPrice);if(!c8m){V27.originalPriceFormatter={func:V27.priceFormatter};V27.priceFormatter=T3x.Comparison.priceFormat;}V27.whichSet=m6T;t1I.isComparison=!![];break;default:this.unsetTransform(t1I);if(c8m){V27.priceFormatter=V27.originalPriceFormatter?V27.originalPriceFormatter.func:null;V27.originalPriceFormatter=null;}V27.whichSet="dataSet";t1I.isComparison=!1;break;}};T3x.ChartEngine.prototype.setChartScale=function(Q3S){var Z9s,b4Y,o3c;Z9s="li";Z9s+="n";Z9s+="ea";Z9s+="r";b4Y=this.chart;o3c={percent:!!"1",relative:!![]};if(!Q3S){Q3S=Z9s;}if(o3c[Q3S]){this.setComparison(Q3S,b4Y,T3x.Comparison.initialPrice);}else if(o3c[this.layout.chartScale]){this.setComparison(!"1",b4Y);}this.layout.chartScale=Q3S;if(b4Y.canvas){this.draw();}this.changeOccurred("layout");};};U=U$7=>{var z$W=A2IFV;var a$R,b22;function L8C(){var t12,C_R,X4z,c64,J$F,D68,q8$;t12="scri";t12+="pt";C_R=-708624285;X4z=-1302474083;c64=2;for(var I4W=1;z$W.Z2Z(I4W.toString(),I4W.toString().length,1096) !== C_R;I4W++){if(a$R.Share.html2canvasLocation){return a$R.Share.html2canvasLocation;}c64+=2;}if(z$W.U6$(c64.toString(),c64.toString().length,61088) !== X4z){if(a$R.Share.html2canvasLocation){return a$R.Share.html2canvasLocation;}}z$W.a9S();J$F=document.getElementsByTagName(t12);for(var v2_=0;v2_ < J$F.length;v2_++){D68="s";D68+="h";D68+="are.js";q8$=J$F[v2_];if(q8$.src && q8$.src.indexOf(D68) > -+"1"){return q8$.src.replace(/standard\/share\.js/,"") + "thirdparty/";}}return "js/thirdparty/";}function P1G(D$i,S$t,W9C){var r8W,W36,J8A,s3p,s84,T2W,i9O,a06,j03;if(!S$t){S$t={};}r8W=[];W36="ciq-no-share";J8A=document.querySelector("body");if(S$t.hide && S$t.hide instanceof Array){s3p=S$t.hide.join(", ");s84=document.querySelectorAll(s3p);for(var Z15=0;Z15 < s84.length;Z15++){s84[Z15].classList.add(W36);}}J8A.classList.add("sharing");T2W=D$i.chart.container.getElementsByTagName("svg");i9O=[];a06=0;for(;a06 < T2W.length;a06++){j03=T2W[a06];i9O.push(j03.innerHTML);s0A(j03);}b22(D$i.chart.container,{allowTaint:!({}),logging:![],width:S$t.width || null,height:S$t.height || null,backgroundColor:S$t.background || null,useCORS:!0}).then(function(y9q){if(W9C){W9C(null,S$t.data?y9q.toDataURL("image/png"):y9q);}for(a06=0;a06 < T2W.length;a06++){T2W[a06].innerHTML=i9O[a06];}J8A.classList.remove("sharing");}).catch(function(i4W){var W5O;W5O="sh";W5O+="ari";W5O+="ng";if(W9C){W9C(i4W);}for(a06=+"0";a06 < T2W.length;a06++){T2W[a06].innerHTML=i9O[a06];}J8A.classList.remove(W5O);});}z$W.a9S();function s0A(u_l){var E64,u_O,R$k;E64="alignment";E64+="-baseline";if(!u_l.style){return;}u_O=getComputedStyle(u_l);R$k=[E64,"dominant-baseline","fill","fill-opacity","font-family","font-size","font-variant","font-weight","text-align","text-anchor"];R$k.forEach(function(c2m){z$W.a9S();if(!u_l.style[c2m] && u_O[c2m]){u_l.style[c2m]=u_O[c2m];}});for(var o8B in u_l.children){s0A(u_l.children[o8B]);}}function x85(u1z){z$W.a9S();if(typeof html2canvas === "undefined"){if(typeof requirejs !== "undefined"){try{return requirejs(["html2canvas.min.js"],function(j0M){b22=j0M;z$W.D0H();return u1z();});}catch(i_3){console.warn("Require loading has failed, attempting to load html2canvas manually.");}}a$R.loadScript(L8C() + "html2canvas.min.js",function(){z$W.a9S();b22=html2canvas;return u1z();});}else {b22=html2canvas;return u1z();}}a$R=typeof _CIQ !== "undefined"?_CIQ:U$7.CIQ;a$R.Share=a$R.Share || (function(){});a$R.Share.FullChart2PNG=function(T0V,b6D,B$b){var u4I;z$W.D0H();u4I="u";u4I+="nd";u4I+="efined";if(!T0V || !T0V.chart){return;}if(typeof html2canvas === u4I){return x85(function(){return P1G(T0V,b6D,B$b);});}b22=html2canvas;P1G(T0V,b6D,B$b);};a$R.Share.createImage=function(X5f,g84,d8E){var k1C,H47,A88,P4s,P83,N8N,B0e,D0Q,A1J;k1C="im";k1C+="g";H47=[].slice.call(arguments);d8E=H47.pop();if(g84 === null || typeof g84 != "object"){g84={widthPX:H47[1],heightPX:H47[2],imageType:H47[3]};}A88=g84.widthPX;P4s=g84.heightPX;P83=g84.imageType;N8N=X5f.chart.canvas.height;B0e=X5f.chart.canvas.width;if(X5f.chart.canvas.style.height){N8N=a$R.stripPX(X5f.chart.canvas.style.height);B0e=a$R.stripPX(X5f.chart.canvas.style.width);}if(A88 && P4s){N8N=P4s;B0e=A88;}else if(P4s){B0e=X5f.chart.canvas.width * (N8N / X5f.chart.canvas.height);}else if(A88){B0e=A88;N8N=X5f.chart.canvas.height * (A88 / X5f.chart.canvas.width);}D0Q=P83?"image/" + P83:"image/png";A1J=document.createElement(k1C);A1J.onload=function(){a$R.Share.FullChart2PNG(X5f,{image:this,width:B0e,height:N8N,hide:g84.hide},function(w2Z,t0y){z$W.D0H();var h$V;if(w2Z){h$V="Error producin";h$V+="g canvas snap";h$V+="shot: ";z$W.D0J(0);console.warn(z$W.q7n(h$V,w2Z));}else {try{d8E(t0y.toDataURL(D0Q));;}catch(r6b){console.warn("Safari devices do not handle CORS enabled images. Using the charts' canvas as a fallback.");d8E(A1J.src);}}});};A1J.src=X5f.chart.canvas.toDataURL(D0Q);};a$R.Share.uploadImage=function(W$X,O4Q,p9c,e0E){var H5$;if(!p9c){p9c={};}z$W.D0H();p9c.image=W$X;H5$=a$R.postAjax(O4Q,JSON.stringify(p9c),function(u0Z,U6f){if(u0Z != 200){e0E(u0Z,null);return;}e0E(null,U6f);});if(!H5$){e0E(0,null);}};a$R.Share.shareChart=function(x6G,Z_k,A$0){a$R.Share.createImage(x6G,{},function(S7F){var d63,B4I,P_J,Q9E,S08,x5V;z$W.a9S();d63=a$R.uniqueID();B4I="https://share.chartiq.com";z$W.D0J(37);P_J=z$W.q7n(d63,B4I,"/upload/");if(Z_k){if(Z_k.host){B4I=Z_k.host;}if(Z_k.path){P_J=B4I + Z_k.path + (("5133" << 0,520.23) != +"537.56"?"/":+"0x96c") + d63;}}Q9E=x6G.getStartDateOffset();S08={layout:x6G.exportLayout(),drawings:x6G.exportDrawings(),xOffset:Q9E,startDate:x6G.chart.dataSegment[Q9E].Date,endDate:x6G.chart.dataSegment[x6G.chart.dataSegment.length - 1].Date,id:d63,symbol:x6G.chart.symbol};x5V={id:d63,image:S7F,config:S08};a$R.Share.uploadImage(S7F,P_J,x5V,function(W92,G6I){if(W92 !== null){a$R.alert("error sharing chart: ",W92);}else {z$W.D0J(0);A$0(z$W.q7n(B4I,G6I));}});;});};};R=s0v=>{var r6U=A2IFV;var G99,h91,v72,A$D;G99=1908465696;h91=+"1307475919";v72=+"2";for(var w2r=1;r6U.Z2Z(w2r.toString(),w2r.toString().length,46458) !== G99;w2r++){A$D=!_CIQ === ""?_CIQ:s0v.CIQ;v72+=2;}if(r6U.U6$(v72.toString(),v72.toString().length,14190) !== h91){A$D=typeof _CIQ !== "undefined"?_CIQ:s0v.CIQ;}r6U.a9S();A$D.ChartEngine.prototype.setRange=function(X8N,M8u){var f_p,w2c,P2N,T5W,R5k,y$a,k6L,A7T,L36,V3V,a$7,u8G,L$P,T75,Z2N,m8y,B6W,s28,c_h,A7a,x21,B$L,c3A,E7K,A3P,P5i,h0C,o7I,G6w,T_S,m3P,t6L,r_3,E0I;function n6w(h8K){var z4N,E2w,R2R,g8o,j9Z,W7V,e0Z,y0u,Q_r,P_Z,F2A,W_Q,y89,l$x,X99,y50,A3W,r1L,f6E,R_7,T9A,B0c,z3c,w96;z4N="l";z4N+="a";z4N+="you";z4N+="t";E2w="d";E2w+="a";E2w+="y";R2R="undef";R2R+="ined";if(typeof h8K == R2R){h8K=null;}g8o=+"0";j9Z=+"0";W7V=new Date();r6U.a9S();e0Z=X8N.base;y0u=X8N.periodicity;Q_r=y$a.layout;if(X8N.goIntoFuture && (!w2c.masterData.length || P2N > w2c.masterData[w2c.masterData.length - 1].DT)){P_Z=w2c.masterData.length?w2c.masterData.pop():{DT:P2N};r6U.H6P(40);F2A=r6U.S40(32,"33390567");W_Q=+"1303637610";y89=2;for(var K2k=1;r6U.U6$(K2k.toString(),K2k.toString().length,27995) !== F2A;K2k++){l$x=y$a.doCleanupGaps([P_Z,{DT:T5W}],w2c,{cleanupGaps:"",noCleanupDates:!!0});y$a.setMasterData(w2c.masterData.concat(l$x),w2c,{noCleanupDates:!1});r6U.D0J(40);y$a.createDataSet(1,r6U.q7n(64,"1"),{appending:!1});y89+=2;}if(r6U.Z2Z(y89.toString(),y89.toString().length,81742) !== W_Q){l$x=y$a.doCleanupGaps([P_Z,{DT:T5W}],w2c,{cleanupGaps:"gap",noCleanupDates:!!({})});y$a.setMasterData(w2c.masterData.concat(l$x),w2c,{noCleanupDates:!!({})});y$a.createDataSet(null,null,{appending:!![]});}}X99=w2c.dataSet;y50=X99.length;if(!X99 || y50 === 0){if(M8u){M8u(h8K);}return;}if(e0Z === E2w && y0u && y0u.interval === "day"){r1L=X8N.multiplier;g8o=y50 < r1L?0:y50 - r1L;r6U.D0J(7);j9Z=r6U.S40(1,y50);}else if(e0Z === "today" && X99[y50 - 1].DT.getDate() < W7V.getDate()){f6E=new Date(X99[y50 - +"1"].DT.getTime());R_7=f6E.getTime();A3W=+"0";for(var J4U=y50 - 1;J4U >= 0;J4U--){if(X99[J4U] && X99[J4U].DT.getDate() != f6E.getDate()){f6E=new Date(+X99[J4U + 1].DT);r6U.H6P(0);A3W=r6U.q7n(J4U,1);break;}}g8o=A3W;r6U.D0J(7);j9Z=r6U.q7n(1,y50);}else {T9A="a";T9A+="l";T9A+="l";if(X8N.base != T9A && (P2N.getTime() >= X99[0].DT.getTime() || X8N.goIntoPast)){g8o=y$a.tickFromDate(P2N,w2c,null,!0);}else {g8o=0;}if(X8N.base != "all" && (T5W.getTime() <= X99[y50 - 1].DT.getTime() || X8N.goIntoFuture)){j9Z=y$a.tickFromDate(T5W,w2c);if(j9Z > y50 - 1){j9Z--;};}else {r6U.H6P(7);j9Z=r6U.q7n(1,y50);}}r6U.D0J(113);B0c=r6U.S40(64,"1",g8o,j9Z);if(B0c < 1){if(M8u){M8u(h8K);}return;}z3c=X8N.padding || 0;if(j9Z < y50 - 1){z3c=0;}w96=(w2c.width - z3c) / B0c;y$a.setCandleWidth(w96,w2c);r6U.D0J(114);w2c.scroll=r6U.S40(j9Z,y50,"1",B0c);y$a.micropixels=1;for(var B6b in y$a.panels){y$a.calculateYAxisMargins(y$a.panels[B6b].yAxis);}if(!X8N.dontSaveRangeToLayout){delete X8N.chart;delete Q_r.setSpan;Q_r.range=X8N;;}else {delete Q_r.range;}y$a.draw();y$a.changeOccurred(z4N);if(!f_p){y$a.dispatch("periodicity",{stx:y$a,differentData:P5i,prevPeriodicity:{interval:c3A,periodicity:E7K,timeUnit:A3P}});}if(M8u){M8u(h8K);}}if(A$D.isEmpty(X8N)){X8N={dtLeft:arguments[0],dtRight:arguments[1],padding:arguments[2],chart:arguments[3]};M8u=arguments[4];}if(this.staticRange){X8N.goIntoPast=X8N.goIntoFuture=!!"1";}if(!X8N.chart){X8N.chart=this.chart;}if(typeof X8N.padding == "undefined"){X8N.padding=0;}f_p=![];w2c=X8N.chart;P2N=typeof X8N.dtLeft === "string"?new Date(X8N.dtLeft):X8N.dtLeft;T5W=new Date();function K$d(x3b,r0x,K8a,t1s,m6n,P06){var B6f,a2h,f9P,Y0C;B6f=0;r6U.H6P(7);a2h=r6U.q7n(r0x,x3b);if(A$D.ChartEngine.isDailyInterval(K8a)){f9P="w";f9P+="eek";if(K8a == "month"){B6f=a2h / A$D.MONTH / t1s;}else if(K8a == f9P){B6f=a2h / A$D.WEEK / t1s;}else {B6f=a2h / A$D.DAY / t1s;}}else {if(!isNaN(K8a)){Y0C="secon";Y0C+="d";if(m6n == "millisecond"){r6U.H6P(115);B6f=r6U.q7n(K8a,t1s,a2h);}else if(m6n == Y0C){B6f=a2h / A$D.SECOND / (t1s * K8a);}else {B6f=a2h / A$D.MINUTE / (t1s * K8a);}}}return Math.round(B6f);;}if(X8N.dtRight){T5W=typeof X8N.dtRight === "string"?new Date(X8N.dtRight):X8N.dtRight;}if(!P2N){R5k=this.standardMarketIterator(T5W,null,w2c);P2N=R5k.previous(w2c.maxTicks);if(!X8N.periodicity){f_p=!!({});}}r6U.a9S();w2c.inflectionPoint=P2N;this.layout.range={dtLeft:P2N,dtRight:T5W};y$a=this;k6L=0;if(this.quoteDriver){if(f_p){A7T=this.layout.interval;V3V=this.layout.timeUnit;L36=this.layout.periodicity;}else if(X8N.periodicity){a$7=A$D.cleanPeriodicity(X8N.periodicity.period,X8N.periodicity.interval,X8N.periodicity.timeUnit);A7T=a$7.interval;V3V=a$7.timeUnit;L36=a$7.period;}else {u8G=T5W.getTime() - P2N.getTime();if(!this.autoPickCandleWidth.turnOn){L$P=this.staticRangePeriodicityMap;T75=null;for(var Z9k=+"0";Z9k < L$P.length;Z9k++){Z2N=L$P[Z9k];if(u8G / Z2N.rangeInMS < +"1.001"){T75=Z2N;break;}}A7T=T75.interval;L36=T75.periodicity;V3V=T75.timeUnit;}else {m8y=0;if(this.autoPickCandleWidth.candleWidth){m8y=this.autoPickCandleWidth.candleWidth;}else {m8y=this.chart.barsHaveWidth?"5" << 64:2;}B6W=w2c.width / m8y;s28=this.dynamicRangePeriodicityMap;A7T=s28[0].interval;L36=1;for(var U0t=0;U0t < s28.length;U0t++){A7a=u8G / s28[U0t].rangeInMS;if(A7a < B6W){if(s28[U0t - 1]){A7T=s28[U0t - 1].interval;V3V=s28[U0t - 1].timeUnit;r6U.D0J(14);L36=Math.ceil(r6U.q7n(B6W,c_h));}else {A7T=s28[U0t].interval;V3V=s28[U0t].timeUnit;L36=1;}break;}c_h=A7a;}}}x21=this.chart.scroll;B$L=this.layout.candleWidth;c3A=this.layout.interval;E7K=this.layout.periodicity;A3P=this.layout.timeUnit;this.chart.scroll=this.chart.maxTicks=K$d(T5W.getTime(),P2N.getTime(),A7T,L36,V3V,this.dontRoll);this.layout.candleWidth=this.chart.width / this.chart.maxTicks;P5i=this.needDifferentData({period:L36,interval:A7T,timeUnit:V3V});if(Object.keys(this.chart.endPoints).length && (this.chart.endPoints.begin > P2N || this.chart.endPoints.end < T5W)){P5i=!0;}if(!this.chart.masterData || !this.chart.masterData.length || P5i || X8N.forceLoad){h0C="w";h0C+="e";h0C+="e";h0C+="k";this.layout.interval=A7T;this.layout.periodicity=L36;this.layout.timeUnit=V3V;if(!this.layout.timeUnit){o7I="t";o7I+="i";o7I+="c";o7I+="k";if(A$D.ChartEngine.isDailyInterval(this.layout.interval)){this.layout.timeUnit=null;}else if(this.layout.interval == "second"){this.layout.timeUnit="second";}else if(this.layout.interval != o7I){this.layout.timeUnit="minute";}}G6w={symbol:w2c.symbol,symbolObject:w2c.symbolObject,chart:w2c,nodraw:!!"1"};if(this.layout.interval == "tick"){r6U.H6P(10);T_S=r6U.q7n("1123097109",20);m3P=-953471532;t6L=2;for(var z8i="1" | 1;r6U.Z2Z(z8i.toString(),z8i.toString().length,19603) !== T_S;z8i++){G6w.startDate=P2N;t6L+=2;}if(r6U.Z2Z(t6L.toString(),t6L.toString().length,34020) !== m3P){G6w.startDate=P2N;}G6w.startDate=P2N;G6w.endDate=T5W;}if(!this.displayInitialized){G6w.initializeChart=!!1;}r_3={symbol:w2c.symbol,symbolObject:w2c.symbolObject,interval:this.layout.interval};if((r_3.interval == "month" || r_3.interval == h0C) && !this.dontRoll){r_3.interval="day";}E0I=Math.max(this.quoteDriver.getQuoteFeed(r_3).behavior.bufferSize + 50,+"200");R5k=this.standardMarketIterator(P2N,null,w2c);G6w.startDate=new Date(R5k.previous(E0I).getTime());R5k=this.standardMarketIterator(T5W,null,w2c);G6w.endDate=new Date(R5k.next(E0I).getTime());if(G6w.endDate < Date.now()){this.isHistoricalModeSet=!!({});}this.clearCurrentMarketData(this.chart);clearTimeout(this.streamParameters.timeout);this.quoteDriver.newChart(G6w,n9k);}else {if(this.layout.interval != A7T || this.layout.periodicity != L36 || this.layout.timeUnit != V3V || !this.chart.dataSegment || !this.chart.dataSegment["0" * 1] || this.chart.dataSegment[0].DT != w2c.inflectionPoint){this.layout.interval=A7T;this.layout.periodicity=L36;this.layout.timeUnit=V3V;this.createDataSet();}n9k();}}else {n6w();}function n9k(t_3){var Z2u;if(t_3 && k6L === "0" * 1){w2c.scroll=x21;y$a.setCandleWidth(B$L);y$a.layout.interval=c3A;y$a.layout.periodicity=E7K;y$a.layout.timeUnit=A3P;if(M8u){M8u(t_3);}return;}k6L++;if(k6L > 10){Z2u="CIQ.ChartEngine.setRange(): Too many loads (10) from server. Stoppi";Z2u+="ng. Check periodicity logic.";console.log(Z2u);n6w();return;}n6w();;}};A$D.ChartEngine.prototype.setSpan=function(a7O,p83){var T3j,p7Y,X1w,h_7,v5B,i3t,M1N,h8o,q2n,G$U,S37,x7$,Z6c,d$6,a9k,L0a,T1Y,E0R,c_Y,U6W;T3j="ob";function o3n(z27,Q_I){var q2L;if(!d$6){return z27;}q2L=7;if(Q_I){z27.setHours(z27.getHours() + q2L);}else {z27.setHours(z27.getHours() - q2L);if(!i3t.isMarketDate(z27)){z27.setDate(z27.getDate() - 2);};}return z27;}T3j+="j";T3j+="e";T3j+="ct";p7Y=arguments[0];X1w=arguments[1];h_7=arguments[2];v5B=arguments[+"3"];if(typeof a7O == T3j){p7Y=a7O.period?a7O.period:a7O.multiplier?a7O.multiplier:1;X1w=a7O.interval?a7O.interval:a7O.base?a7O.base:a7O.span?a7O.span:a7O.period;h_7=a7O.padding;v5B=a7O.chart;}else {a7O={period:p7Y,interval:X1w,padding:h_7,chart:v5B};p83=arguments[5];}if(!v5B){v5B=this.chart;}i3t=v5B.market;X1w=X1w.toLowerCase();if(X1w == "all"){a7O.dontSaveRangeToLayout=!!"1";this.displayAll(a7O,p83);return;}h8o=X1w;q2n=1;if(X1w == "today"){h8o="day";}else if(X1w == "year"){G$U="m";G$U+="on";G$U+="t";G$U+="h";h8o=G$U;q2n=12;}S37=A$D.shallowClone(a7O);x7$={begin:i3t.marketZoneNow(),interval:h8o,period:q2n};Z6c=x7$.begin;d$6=A$D.Market.Symbology.isForexSymbol(v5B.symbol);if(X1w === "ytd"){Z6c=q_v(Z6c);Z6c.setMonth(0);Z6c.setDate(1);}else if(X1w === "month"){Z6c=q_v(new Date());Z6c.setMonth(Z6c.getMonth() - p7Y);}else if(X1w === "year"){Z6c=q_v(new Date());Z6c.setFullYear(Z6c.getFullYear() - p7Y);}else if(X1w === "week"){Z6c=q_v(new Date());Z6c.setDate(Z6c.getDate() - p7Y * 7);}else if(X1w === "day" && p7Y == "1" * 1 && i3t.isMarketDay()){a9k=Z6c.getHours();L0a=Z6c.getMinutes();T1Y=Z6c.getSeconds();E0R=Z6c.getMilliseconds();M1N=i3t.newIterator(x7$);Z6c=M1N.previous();Z6c.setHours(a9k,L0a,T1Y,E0R);Z6c=i3t._convertFromMarketTZ(Z6c);}else if(X1w === "today"){x7$.begin=o3n(Z6c,!![]);M1N=i3t.newIterator(x7$);if(i3t.isOpen() || i3t.getPreviousOpen().getDate() == Z6c.getDate()){M1N.next();}Z6c=M1N.previous();o3n(Z6c);S37.goIntoFuture=!!1;S37.dtRight=new Date(+Z6c);S37.dtRight.setDate(Z6c.getDate() + 1);S37.dtRight=i3t._convertFromMarketTZ(S37.dtRight);if(!d$6){Z6c.setHours(M1N.market.zopen_hour);Z6c.setMinutes(M1N.market.zopen_minute);Z6c.setSeconds(0);}Z6c=i3t._convertFromMarketTZ(Z6c);}else {c_Y="d";c_Y+="ay";if(X1w == "day"){x7$.begin=o3n(Z6c,!!({}));}M1N=i3t.newIterator(x7$);if(p7Y == 1){p7Y++;}r6U.H6P(7);Z6c=M1N.previous(r6U.S40(1,p7Y));if(X1w == c_Y){Z6c=i3t._convertFromMarketTZ(o3n(Z6c));}}S37.dtLeft=Z6c;if(S37.maintainPeriodicity){S37.periodicity={};S37.periodicity.interval=this.layout.interval;S37.periodicity.period=this.layout.periodicity;}v5B.spanLock=![];S37.dontSaveRangeToLayout=!"";function q_v(Y7x){Y7x.setHours(0);Y7x.setMinutes(0);Y7x.setSeconds(+"0");Y7x.setMilliseconds(0);return Y7x;}U6W=this;this.setRange(S37,function(I0I){U6W.layout.setSpan=a7O;U6W.changeOccurred("layout");r6U.a9S();if(X1w == "today"){v5B.spanLock=!!({});;}if(p83){p83(I0I);}});};A$D.ChartEngine.prototype.getSpanCandleWidth=function(U6S){var K8t,I$x,b6U,R87,V9f,w7K,K9n,H7M,S3p,W2w;K8t="mont";K8t+="h";if(!U6S || !U6S.base || !U6S.multiplier){return;}I$x=parseFloat(U6S.multiplier);b6U=U6S.base;R87=new Date();V9f=new Date();if(b6U == "year"){V9f.setFullYear(V9f.getFullYear() - I$x);}else if(b6U == K8t){w7K=391528754;K9n=1131678275;H7M=2;for(var f_z=1;r6U.Z2Z(f_z.toString(),f_z.toString().length,84725) !== w7K;f_z++){V9f.setMonth(V9f.getMonth() % I$x);H7M+=2;}if(r6U.U6$(H7M.toString(),H7M.toString().length,90186) !== K9n){V9f.setMonth(V9f.getMonth() - I$x);}}else if(b6U == "day"){V9f.setDate(V9f.getDate() - I$x);}else if(b6U == "week"){V9f.setDate(V9f.getDate() - 7 * I$x);}else if(b6U == "YTD"){V9f.setMonth(0);r6U.H6P(10);V9f.setDate(r6U.S40("1",0));}r6U.H6P(94);var X49=r6U.q7n(2,7,16,12011,13000);r6U.H6P(52);r6U.a9S();var z25=r6U.q7n(660,72,10);r6U.D0J(0);var U4O=r6U.S40(49,11);r6U.H6P(94);var e49=r6U.S40(14,18,3,17,42);S3p=(R87.getTime() - V9f.getTime()) / X49 / z25 / U4O / e49;r6U.H6P(116);S3p=r6U.S40(S3p,7,"5",32);W2w=this.chart.width / S3p;return W2w;};A$D.ChartEngine.prototype.displayAll=function(t$J,T8M){var U6n,F8L,D0d;var {chart:w1O, layout:x2j}=this;if(t$J && t$J.chart){w1O=t$J.chart;}function Z94(z4v){if(!z4v){U6n.quoteDriver.loadAll(w1O,i6e);}}function i6e(){var Y1C;if(!w1O.masterData || !w1O.masterData.length){return;}Y1C=A$D.clone(t$J);Y1C.dtLeft=w1O.endPoints.begin.DT;Y1C.dtRight=w1O.endPoints.end.DT;Y1C.periodicity={};Y1C.periodicity.interval=x2j.interval;Y1C.periodicity.period=x2j.periodicity;Y1C.periodicity.timeUnit=x2j.timeUnit;r6U.D0H();U6n.setRange(Y1C,function(b75){U6n.layout.setSpan={base:t$J.base,multiplier:t$J.multiplier};U6n.changeOccurred("layout");r6U.a9S();for(var c$Y in U6n.panels){U6n.calculateYAxisMargins(U6n.panels[c$Y].yAxis);}U6n.draw();if(T8M){T8M(b75);}});}U6n=this;if(!this.quoteDriver){i6e();return;}F8L=t$J.maintainPeriodicity?{period:x2j.periodicity,interval:x2j.interval,timeUnit:x2j.timeUnit}:{period:+"1",interval:"month",timeUnit:null};F8L=t$J.periodicity?t$J.periodicity:F8L;F8L=A$D.cleanPeriodicity(F8L.period,F8L.interval,F8L.timeUnit);D0d=this.needDifferentData(F8L);this.layout.periodicity=F8L.period;this.layout.interval=F8L.interval;this.layout.timeUnit=F8L.timeUnit;r6U.a9S();if(t$J.forceLoad || D0d){this.clearCurrentMarketData(this.chart);this.quoteDriver.newChart({noDraw:!![],symbol:this.chart.symbol,symbolObject:this.chart.symbolObject,chart:this.chart,initializeChart:!![],fetchMaximumBars:!!"1"},Z94);}else {if(w1O.moreAvailable || !w1O.upToDate){Z94();}else {this.createDataSet();i6e();}}};};D=l86=>{var X8z=A2IFV;X8z.a9S();var F3g;F3g=typeof _CIQ !== "undefined"?_CIQ:l86.CIQ;F3g.ChartEngine.prototype.importLayout=function(i2y,s6M){var y_x,B8I,D4G,S7V,p5a,e_4,R$_,E1j,s8v,L1M,M64,w0d,i6U,b0W,g8m,m2A,c2K,Q67,I1$,H0B,B3z,r6H,n7R,Y8d,H2v,k1O,h4X,l$k,O1G,f6h;if(!i2y){if(s6M.cb){s6M.cb();}return;}y_x=this;B8I=[];if(typeof s6M !== "object"){s6M={managePeriodicity:arguments[1],preserveTicksAndCandleWidth:arguments[2]};}D4G=this.layout;S7V=F3g.shallowClone(D4G);p5a=s6M.managePeriodicity;e_4=s6M.cb;R$_=s6M.seriesCB;E1j=s6M.noDataLoad;s8v=s6M.preserveTicksAndCandleWidth;L1M=null;if(this.exportDrawings){L1M=this.exportDrawings();this.abortDrawings();}this.currentlyImporting=!![];for(var o$I in D4G.studies){M64=D4G.studies[o$I];F3g.getFn("Studies.removeStudy")(this,M64);}this.overlays={};w0d=F3g.shallowClone(this.panels);this.panels={};i6U=F3g.clone(i2y);D4G.periodicity=S7V.periodicity;function E$1(B9v){var E1c,P1I;for(var T3w=+"0";T3w < B8I.length;T3w++){E1c="yaxisL";E1c+="HS";P1I=B8I[T3w];U_Z(P1I,E1c);U_Z(P1I,"yaxisRHS");}y_x.chart.yAxis=y_x.chart.panel.yAxis;function U_Z(M_W,V_i){var c20,W5c,I48,U7J;if(!M_W[V_i] || !M_W[V_i].length){return;}c20=B9v[M_W.name];if(!c20){return;}W5c=c20[V_i];I48=new Array(W5c.length);for(var R3B=+"0";R3B < W5c.length;R3B++){U7J=M_W[V_i].indexOf(W5c[R3B].name);if(U7J > -1){I48[U7J]=W5c[R3B];}else {I48.push(W5c[R3B]);}}if(I48.length){c20[V_i]=I48.filter(c2l);}}function c2l(p4I){return !!p4I;}}D4G.interval=S7V.interval;D4G.timeUnit=S7V.timeUnit;D4G.setSpan=S7V.setSpan;function e$H(F2v){var G$F,m4f,G$k,j6L,K__;G$F="lay";G$F+="out";if(L1M){y_x.importDrawings(L1M);}y_x.currentlyImporting=!"1";if(F2v){return;}j6L=[];for(var k_w in y_x.chart.series){K__="s";K__+="tu";K__+="dy";if(!y_x.removeSeries)break;G$k=y_x.chart.series[k_w];if(G$k.parameters.bucket == K__){m4f=!!({});y_x.removeSeries(G$k);j6L.push(G$k);}}for(var m2U=0;m2U < j6L.length;m2U++){G$k=j6L[m2U];y_x.addSeries(G$k.id,G$k.parameters,X1C);}if(!m4f){y_x.draw();}y_x.updateListeners(G$F);function X1C(){y_x.createDataSet();E$1(y_x.panels);y_x.calculateYAxisPositions();y_x.draw();}X8z.D0H();y_x.changeOccurred("layout");;}D4G.range=S7V.range;if(s8v){D4G.candleWidth=S7V.candleWidth;}else {if(!D4G.candleWidth){D4G.candleWidth=+"8";}}this.setCandleWidth(D4G.candleWidth);if(D4G.flipped){this.flipChart(D4G.flipped);}b0W=i6U.panels;Q67=function(o2I,a9B){X8z.a9S();return o2I.index < a9B.index?-1:"1" ^ 0;};for(g8m in b0W){if(!(("index" in b0W[g8m]))){Q67=null;}m2A=b0W[g8m];m2A.name=g8m;B8I.push(m2A);}D4G.panels={};I1$=null;if(B8I.length > 0){if(Q67){B8I.sort(Q67);}for(var h_M="0" >> 64;h_M < B8I.length;++h_M){m2A=B8I[h_M];c2K=m2A.yAxis?new F3g.ChartEngine.YAxis(m2A.yAxis):null;this.stackPanel(m2A.display,m2A.name,m2A.percent,m2A.chartName,c2K);if(m2A.soloing){I1$=this.panels[m2A.name];}}}if(F3g.isEmpty(b0W)){this.stackPanel("chart","chart",1,"chart");}this.resizeCanvas();for(var c48 in w0d){H0B=w0d[c48];B3z=this.panels[c48];if(B3z){this.container.removeChild(B3z.holder);if(H0B.handle){this.container.removeChild(H0B.handle);}r6H={holder:!![],subholder:!!"1",display:!"",icons:!0};for(var S6f in r6H){B3z[S6f]=H0B[S6f];}this.configurePanelControls(B3z);if(H0B.chart.panel == H0B){H0B.chart.panel=B3z;};}else {this.privateDeletePanel(H0B);}}this.chart.panel=this.panels.chart;E$1(this.panels);F3g.dataBindSafeAssignment(D4G,F3g.clone(i6U));n7R=F3g.clone(D4G.studies);delete D4G.studies;for(var k_a in n7R){Y8d=n7R[k_a];F3g.getFn("Studies.addStudy")(this,Y8d.type,Y8d.inputs,Y8d.outputs,Y8d.parameters,Y8d.panel);}if(this.extendedHours){this.extendedHours.prepare(D4G.extended,D4G.marketSessions);}if(typeof D4G.chartType == "undefined"){D4G.chartType="line";}this.setMainSeriesRenderer();if(I1$){this.panelSolo(I1$);}this.adjustPanelPositions();E$1(this.panels);this.storePanels();if(!E1j){if(i6U.symbols && i6U.symbols.length){H2v={chart:this.chart};if(!s8v && p5a && i6U.range && Object.keys(i6U.range).length){H2v.range=i6U.range;}else if(!s8v && p5a && i6U.setSpan && Object.keys(i6U.setSpan).length){H2v.span=i6U.setSpan;}else if(p5a && i6U.interval){H2v.periodicity={interval:i6U.interval,period:i6U.periodicity,timeUnit:i6U.timeUnit};}else {H2v.periodicity={interval:S7V.interval,period:S7V.periodicity,timeUnit:S7V.timeUnit};}k1O=i6U.symbols[0].symbolObject || i6U.symbols[0].symbol;this.loadChart(k1O,H2v,function(Z8L){X8z.a9S();var Y4Y,m9Q;if(!Z8L){for(var L0n,u0p=1;u0p < i6U.symbols.length;++u0p){if(!y_x.addSeries)break;L0n=i6U.symbols[u0p];if(!L0n.parameters){L0n.parameters={};}Y4Y=F3g.clone(L0n.parameters);if(this.panels[Y4Y.panel]){y_x.addSeries(L0n.id,Y4Y,R9m);}else {m9Q="Warning: Seri";m9Q+="es \"";console.warn(m9Q + L0n.id + '" could not be imported due to a missing corresponding panel "' + Y4Y.panel + ((2540,+"616") >= "2100" * 1?+"578.57" <= 8680?(7.32e+3,"S"):!!0:'"'));}}if(i6U.chartScale){y_x.setChartScale(i6U.chartScale);}}e$H(Z8L);if(e_4){e_4.apply(null,arguments);}});return;}if(p5a){if(!s8v && this.setRange){h4X=i6U.range;if(h4X && Object.keys(h4X).length && this.chart.symbol){this.setRange(h4X,function(){e$H();if(e_4){e_4();}});return;}else if(i6U.setSpan && Object.keys(i6U.setSpan).length && this.chart.symbol){this.setSpan(i6U.setSpan,function(){X8z.a9S();e$H();if(e_4){e_4();}});return;}}l$k=i6U.interval;O1G=i6U.periodicity;f6h=i6U.timeUnit;if(isNaN(O1G)){O1G=1;}if(!l$k){l$k="day";}this.setPeriodicity({period:O1G,interval:l$k,timeUnit:f6h},function(){e$H();if(e_4){e_4();}});return;}}if(p5a){D4G.periodicity=i6U.periodicity;D4G.interval=i6U.interval;D4G.timeUnit=i6U.timeUnit;D4G.setSpan=i6U.setSpan;}this.createDataSet();if(!s8v){this.home();}function R9m(){y_x.calculateYAxisPositions();E$1(y_x.panels);if(R$_){R$_();}}e$H();if(e_4){e_4();}};F3g.ChartEngine.prototype.exportLayout=function(Z8Y){X8z.D0H();var c6l,s6E,r1f,w0V,J83,H9Y,B_R,l5w;c6l={};for(var g2X in this.layout){s6E="pane";s6E+="ls";r1f="stu";r1f+="d";r1f+="ies";if(g2X != "studies" && g2X != "panels" && g2X != "drawing"){c6l[g2X]=F3g.clone(this.layout[g2X]);}else if(g2X == r1f){c6l.studies={};}else if(g2X == s6E){c6l.panels={};}}w0V=0;for(var I5N in this.panels){J83=this.panels[I5N];if(J83.exportable === ![])continue;H9Y=c6l.panels[I5N]={};H9Y.percent=J83.percent;H9Y.display=J83.display;H9Y.chartName=J83.chart.name;H9Y.soloing=J83.soloing;H9Y.index=w0V++;H9Y.yAxis={name:J83.yAxis.name,position:J83.yAxis.position};if(J83.yaxisLHS){H9Y.yaxisLHS=h5A(J83.yaxisLHS);}if(J83.yaxisRHS){H9Y.yaxisRHS=h5A(J83.yaxisRHS);}}function h5A(L2N){var V59;V59=[];for(var m9R=0;m9R < L2N.length;m9R++){V59.push(L2N[m9R].name);}X8z.a9S();return V59;}for(var D9w in this.layout.studies){B_R=c6l.studies[D9w]={};l5w=this.layout.studies[D9w];B_R.type=l5w.type;B_R.inputs=F3g.clone(l5w.inputs);B_R.outputs=F3g.clone(l5w.outputs);B_R.panel=l5w.panel;B_R.parameters=F3g.clone(l5w.parameters);}if(Z8Y){c6l.symbols=this.getSymbols({"include-parameters":!![],"exclude-studies":!"","exclude-generated":!0});}else {delete c6l.symbols;}return c6l;};F3g.ChartEngine.prototype.importPreferences=function(N_8){F3g.extend(this.preferences,N_8);if(N_8.timeZone){this.setTimeZone(this.dataZone,N_8.timeZone);}if(N_8.language && F3g.I18N){F3g.I18N.localize(this,N_8.language);}this.changeOccurred("preferences");};F3g.ChartEngine.prototype.exportPreferences=function(){X8z.D0H();return this.preferences;};};N=m$6=>{var p8o,S9B,W9k,i3c,q1N,t05,I$$,i2v,s1q,w8y,N1H,Y$r,M34,z5d,j6q,W7j;p8o="Tr";p8o+="ue Ra";p8o+="nge";S9B="Expo";S9B+="ne";S9B+="ntial";W9k="Trian";W9k+="gular";i3c="Exponenti";i3c+="al";q1N="Expo";q1N+="ne";q1N+="ntial";t05="W";t05+="e";t05+="lles Wilder";I$$="Weigh";I$$+="t";I$$+="ed";i2v="Triangul";i2v+="ar";s1q="exponen";s1q+="tial";w8y="w";w8y+="ma";N1H="em";N1H+="a";Y$r="m";Y$r+="a";M34="u";M34+="n";M34+="defined";z5d="un";z5d+="defined";j6q=typeof _CIQ !== z5d?_CIQ:m$6.CIQ;W7j=typeof _timezoneJS !== M34?_timezoneJS:m$6.timezoneJS;if(j6q.ChartEngine){j6q.ChartEngine.prototype.rightClickOverlay=function(Q0a,L$K){var e4V,m3T;e4V="rig";e4V+="htClickOverla";e4V+="y";if(this.runPrepend("rightClickOverlay",arguments)){return;}m3T=this.overlays[Q0a];if(m3T.editFunction){m3T.editFunction(L$K);}else {this.removeOverlay(Q0a);}this.runAppend(e4V,arguments);};j6q.ChartEngine.prototype.addOverlay=function(Z5q){var e3R,O64,K6G,F_Y;e3R="a";e3R+="ddOverl";e3R+="ay";if(this.runPrepend(e3R,arguments)){return;}A2IFV.D0H();O64=+"1520886097";K6G=1981641975;F_Y=2;for(var w3o=1;A2IFV.U6$(w3o.toString(),w3o.toString().length,3782) !== O64;w3o++){this.overlays[Z5q.name]=Z5q;this.runAppend("addOverlay",arguments);F_Y+=2;}if(A2IFV.U6$(F_Y.toString(),F_Y.toString().length,5784) !== K6G){this.overlays[Z5q.name]=Z5q;this.runAppend("",arguments);}};j6q.ChartEngine.prototype.removeOverlay=function(Q8D){var C23,S7P,p0v,N4k,V1r,Q2z,y4A;C23="remo";C23+="veOv";C23+="erl";C23+="ay";if(this.runPrepend(C23,arguments)){return;}S7P=this.overlays[Q8D];for(var I$E in this.overlays){p0v="F";p0v+="i";p0v+="el";p0v+="d";N4k=this.overlays[I$E];V1r=[p0v];if(j6q.Studies){V1r=j6q.Studies.getFieldInputs(N4k);}for(var x4p="0" ^ 0;x4p < V1r.length;x4p++){if(S7P.outputMap[N4k.inputs[V1r[x4p]]]){this.removeOverlay(N4k.name);}}}A2IFV.a9S();if(S7P){this.cleanupRemovedStudy(S7P);Q2z=this.panels[S7P.panel];delete this.overlays[Q8D];this.checkForEmptyPanel(S7P.panel);}if(!this.currentlyImporting){y4A="lay";y4A+="out";this.displaySticky();this.createDataSet();this.changeOccurred(y4A);}this.resetDynamicYAxis();this.runAppend("removeOverlay",arguments);};j6q.ChartEngine.prototype.cleanupRemovedStudy=function(i94){if(!i94){return;}if(i94.study.removeFN){i94.study.removeFN(this,i94);}for(var f7Z in this.plugins){if(f7Z.indexOf("{" + i94.id + (+"459.68" != (541.96,9440)?"}":265.78)) > -1){delete this.plugins[f7Z];}}if(this.layout.studies){delete this.layout.studies[i94.name];}delete this.overlays[i94.name];if(j6q.Studies){j6q.Studies.removeStudySymbols(i94,this);}A2IFV.D0H();if(this.quoteDriver){this.quoteDriver.updateSubscriptions();}};}j6q.Studies=j6q.Studies || (function(){});j6q.Studies.DEFAULT_INPUTS={Period:14};j6q.Studies.DEFAULT_OUTPUTS={Result:"auto"};j6q.Studies.sortForProcessing=e1Y=>{var g4M,Q8H;g4M=[];function S_u(I7b,x6L){I7b.forEach(d_z=>{var g43;if(x6L.indexOf(d_z) == -+"1"){g43=d_z.getDependents(e1Y);if(g43.length){S_u(g43,x6L);}x6L.unshift(d_z);}});}Q8H=e1Y.layout.studies;if(Q8H){S_u(Object.values(Q8H),g4M);}return g4M;};j6q.Studies.StudyDescriptor=function(a_6,T_d,P2v,W3y,Z1X,c76){var g9y,V_T,k6H;g9y="u";g9y+="nde";g9y+="fin";g9y+="ed";V_T="Cl";V_T+="o";V_T+="s";V_T+="e";this.name=a_6;this.type=T_d;this.panel=P2v;this.inputs=W3y;this.outputs=Z1X;this.parameters=c76;this.outputMap={};this.min=null;this.max=null;A2IFV.D0J(1);this.startFrom=A2IFV.q7n(1,"0");this.subField=V_T;k6H=j6q.Studies.studyLibrary[T_d];if(!k6H){k6H={};if(P2v == "chart" || !P2v && c76 && c76.chartName == "chart"){this.overlay=!"";}}if(typeof k6H.inputs == "undefined"){k6H.inputs=j6q.clone(j6q.Studies.DEFAULT_INPUTS);}if(typeof k6H.outputs == g9y){k6H.outputs=j6q.clone(j6q.Studies.DEFAULT_OUTPUTS);}this.study=k6H;A2IFV.D0H();this.libraryEntry=k6H;;};j6q.Studies.StudyDescriptor.prototype.getYAxis=function(Z0h){var p7C,I$3,S5o;p7C=this.yAxis;if(this.parameters){I$3=this.parameters.yaxisDisplayValue;}if(!p7C){S5o=Z0h.panels[this.panel];if(S5o){p7C=Z0h.getYAxisByName(S5o,I$3) || Z0h.getYAxisByName(S5o,this.name) || S5o.yAxis;}}if(!p7C){p7C=Z0h.getYAxisByName(Z0h.chart.panel,I$3) || Z0h.chart.panel.yAxis;}return p7C;};j6q.Studies.StudyDescriptor.prototype.getContext=function(G19){return G19.chart.context;};j6q.Studies.StudyDescriptor.prototype.getDependents=function(v0$,x9J){var M6W,e2L,K3H;M6W=[];for(var O8N in v0$.layout.studies){e2L=v0$.layout.studies[O8N];if(e2L == this)continue;K3H=j6q.Studies.getFieldInputs(e2L);for(var x4v=0;x4v < K3H.length;x4v++){if(e2L.inputs[K3H[x4v]].includes(this.name)){if(x9J && e2L.parameters && e2L.parameters.panelName)continue;M6W.push(e2L);M6W=M6W.concat(e2L.getDependents(v0$,x9J));break;}}}A2IFV.a9S();return M6W;};j6q.Studies.StudyDescriptor.prototype.undraggable=function(O0q){var W8Y;W8Y=this.study.attributes;if(W8Y){if(W8Y.panelName && W8Y.panelName.hidden){return !!"1";}if(W8Y.yaxisDisplayValue && W8Y.yaxisDisplayValue.hidden){return !"";}}return !!0;};j6q.Studies.StudyDescriptor.prototype.appendFutureTicks=function(J4H,h08){var X3c,v7l,K0K,E2t;X3c=J4H.chart.scrubbed;A2IFV.a9S();if(!X3c.length){return;}v7l=J4H.standardMarketIterator(X3c[X3c.length - 1].DT);for(K0K=h08.length - ("1" >> 0);K0K >= 0;K0K--){E2t=h08[K0K];for(var W$9 in E2t){if(E2t[W$9] || E2t[W$9] === 0){K0K=-1;break;}}if(K0K == -1)break;h08.pop();}for(K0K=0;K0K < h08.length;K0K++){E2t=h08[K0K];if(!E2t.DT){E2t.DT=v7l.next();}if(!E2t.displayDate){J4H.setDisplayDate(E2t);}E2t.futureTick=!![];X3c.push(E2t);}};j6q.Studies.generateID=function(l26,N2j,B2V,k0I,I8O){var r9M=A2IFV;var Q4_,j6h,D7C,P3z,e0T,l2k,f$a,i3S;Q4_=j6q.Studies.studyLibrary[N2j];r9M.H6P(37);j6h=r9M.q7n("\u200c","\u200c",I8O || N2j);D7C=j6h;if(Q4_){if(Q4_.customRemoval){return D7C;}}r9M.D0H();if(!j6q.isEmpty(B2V)){P3z=!!1;for(var l1U in B2V){e0T="Anc";e0T+="h";e0T+="or Selector";if(["id","display","Shading",e0T].includes(l1U)){continue;}l2k=B2V[l1U];if(l2k == "field")continue;l2k=l2k.toString();if(j6q.Studies.prettify[l2k] !== undefined){l2k=j6q.Studies.prettify[l2k];}if(P3z){f$a=" ";f$a+="(";P3z=!!0;D7C+=f$a;}else {if(l2k){D7C+=",";}}D7C+=l2k;}if(!P3z){D7C+=(372.94,+"5750") == 459?6814 === "9149" << 64?6.33e+3:("e",0x24ee):")";}}if(k0I && k0I.indexOf(D7C) === 0){return k0I;}if(l26.layout.studies && l26.layout.studies[D7C]){for(var t3A=2;t3A < 50;t3A++){r9M.D0J(37);i3S=r9M.q7n(t3A,D7C,446.63 == 522.61?!!({}):"-");if(!l26.layout.studies[i3S]){D7C=i3S;break;}}}return D7C;};j6q.Studies.DialogHelper=function(G1K){var e_2=A2IFV;var p2N,H0p,z5X,h1I,m7q,m8N,g6E,t91,F7F,m9h,Z4x,u$X,q1x,M9h,E4D,A7X,H65,g6U,Q3K,L2m,d8I,s0R,u93,S6O,v3D,A6C,P3P,j6g,e$6,g0w,e8r,E$2,l1w,F17,v$y,A4$,a3Y,D$l,g1H,M4I,z7Q,a6L,m6J,l7B,B8u;p2N="u";p2N+="ndefi";p2N+="n";p2N+="ed";H0p=this.stx=G1K.stx;z5X=this.sd=G1K.sd;this.name=z5X?z5X.type:G1K.name;function V7Z(y$3,k4e){if(!this.attributes[y$3]){this.attributes[y$3]={};}if(k4e){this.attributes[y$3].hidden=!!({});}}this.signal=1;this.inputs=[];function U$e(X27){var Z9n,L6Z,U47,Y7F;Z9n="se";Z9n+="lect";L6Z={};U47=X27.defaults;Y7F={name:X27.name,heading:H0p.translateIf(X27.label),defaultValue:U47[0],value:X27.value,options:L6Z,type:Z9n};for(var w7P=0;w7P < U47.length;w7P++){L6Z[U47[w7P]]=H0p.translateIf(U47[w7P]);}if(X27.color !== undefined){Y7F.defaultColor=H0p.defaultColor;Y7F.color=X27.color;}return Y7F;}this.outputs=[];this.parameters=[];h1I=this.libraryEntry=z5X?z5X.study:j6q.Studies.studyLibrary[G1K.name];if(typeof h1I.inputs == p2N){h1I.inputs=j6q.clone(j6q.Studies.DEFAULT_INPUTS);}if(typeof h1I.outputs == "undefined"){h1I.outputs=j6q.clone(j6q.Studies.DEFAULT_OUTPUTS);}m7q=z5X && H0p.panels[z5X.panel]?H0p.panels[z5X.panel]:H0p.chart.panel;m8N=m7q.chart;this.title=H0p.translateIf(h1I.name);this.attributes=j6q.clone(h1I.attributes);if(!this.attributes){this.attributes={};}for(var H8a in this.attributes){g6E=this.attributes[H8a];for(var k62 in g6E){if(typeof g6E[k62] == "function"){g6E[k62]=g6E[k62].call(z5X);}}}t91=[];F7F=H0p.layout.studies;m9h=[];if(z5X){m9h=Array.prototype.concat(z5X,z5X.getDependents(H0p));}function q20(l$7){var Y7T,O8G;Y7T="a";Y7T+="li";function q$1(P5Y,r6B){e_2.a9S();return "Panel " + r6B.toString();}Y7T+="a";Y7T+="s";if(l1w == Y7T){O8G=1;for(var Y3W in H0p.panels){if(Y3W == l$7){return q$1(Y3W,O8G);}O8G++;}}return l$7;}for(var l3u in F7F){if(m9h.indexOf(F7F[l3u]) > -1)continue;for(var z4I in F7F[l3u].outputMap){t91.push(z4I);}}function P_T(N5u){var u9z,V18;u9z="checkb";u9z+="ox";e_2.D0H();V18={name:N5u.name,heading:H0p.translateIf(N5u.label),defaultValue:N5u.defaults,value:N5u.value,type:u9z};return V18;}for(var T0B in h1I.inputs){Z4x={};this.inputs.push(Z4x);Z4x.name=T0B;Z4x.heading=H0p.translateIf(T0B);u$X=h1I.inputs[T0B];if(z5X && z5X.inputs && typeof z5X.inputs[T0B] != "undefined" && z5X.inputs[T0B] !== null){Z4x.value=z5X.inputs[T0B];}else {Z4x.value=h1I.inputs[T0B];}Z4x.defaultInput=h1I.inputs[T0B];if(!this.attributes[T0B]){this.attributes[T0B]=j6q.Studies.inputAttributeDefaultGenerator(Z4x.defaultInput);}if(u$X.constructor == Number){Z4x.type="number";}else if(u$X.constructor == String){q1x=j6q.Studies.movingAverageHelper(H0p,Z4x.defaultInput);if(q1x){M9h="o";M9h+="p";M9h+="t";M9h+="ions";Z4x.type="select";Z4x.defaultInput=q1x;E4D=j6q.Studies.movingAverageHelper(H0p,Z4x.value);if(!E4D){E4D=Z4x.value;}Z4x.value=E4D;Z4x.options=j6q.Studies.movingAverageHelper(H0p,M9h);}else if(u$X == "field"){A7X="hl/";A7X+="2";Z4x.type="select";Z4x.options={};H65=["Open","High","Low","Close","Adj_Close",A7X,"hlc/3","hlcc/4","ohlc/4",m8N.defaultPlotField].concat(t91);for(var s6A=0;s6A < H65.length;s6A++){g6U=H65[s6A];Z4x.options[g6U]=H0p.translateIf(g6U);}if(Z4x.value == "field"){Z4x.value="Close";}if(Z4x.defaultInput == "field"){Z4x.defaultInput="Close";}}else {Q3K="hh:mm";Q3K+=":ss";L2m="yyyy-m";L2m+="m-dd";d8I="t";d8I+="e";d8I+="x";d8I+="t";Z4x.type=d8I;if(this.attributes[T0B].placeholder == L2m){Z4x.type="date";}else if(this.attributes[T0B].placeholder == Q3K){Z4x.type="time";}}}else if(u$X.constructor == Boolean){Z4x.type="checkbox";if(Z4x.value === !0 || Z4x.value == "true" || Z4x.value == "on"){Z4x.value=!!1;}}else if(u$X.constructor == Array){Z4x.type="select";Z4x.options={};for(var X3s=0;X3s < u$X.length;X3s++){Z4x.options[u$X[X3s]]=H0p.translateIf(u$X[X3s]);}if(Z4x.value.constructor == Array){Z4x.value=Z4x.value[0];}if(this.attributes[T0B].defaultSelected){Z4x.defaultInput=this.attributes[T0B].defaultSelected;}else {e_2.D0J(21);Z4x.defaultInput=u$X[e_2.S40("0",0)];}}}this.dateTimeInputs=[];for(var H9_=0;H9_ < this.inputs.length;H9_++){s0R="d";s0R+="at";s0R+="e";u93=this.inputs[H9_];if(u93.type == s0R){S6O=" ";S6O+="Date";v3D=u93.name.substring(0,u93.name.indexOf(S6O));for(var t9e=0;t9e < this.inputs.length;t9e++){A6C="t";A6C+="i";A6C+="m";A6C+="e";P3P=this.inputs[t9e];if(P3P.type == A6C){if(P3P.name == v3D + " Time"){this.dateTimeInputs.push(v3D);break;}}}}}this.adjustInputTimesForDisplayZone();for(T0B in h1I.outputs){j6g={name:T0B,heading:H0p.translateIf(T0B)};j6g.color=j6g.defaultOutput=h1I.outputs[T0B];if(z5X && z5X.outputs && z5X.outputs[T0B]){j6g.color=z5X.outputs[T0B];}if(j6g.color == "auto"){j6g.color=H0p.defaultColor;}this.outputs.push(j6g);}e$6=z5X?z5X.parameters:null;if(h1I.parameters){g0w=h1I.parameters.init;if(g0w){if(g0w.studyOverZonesEnabled !== undefined){e8r={name:"studyOverZones",heading:H0p.translateIf("Show Zones"),defaultValue:g0w.studyOverZonesEnabled,value:g0w.studyOverZonesEnabled};if(e$6 && (e$6.studyOverZonesEnabled || e$6.studyOverZonesEnabled === !({}))){e8r.value=e$6.studyOverZonesEnabled;}e8r.type="checkbox";this.parameters.push(e8r);}if(g0w.studyOverBoughtValue !== undefined){E$2="t";E$2+="e";E$2+="x";E$2+="t";e8r={name:"studyOverBought",heading:H0p.translateIf("OverBought"),defaultValue:g0w.studyOverBoughtValue,value:g0w.studyOverBoughtValue,defaultColor:g0w.studyOverBoughtColor,color:g0w.studyOverBoughtColor};if(e$6 && e$6.studyOverBoughtValue){e8r.value=e$6.studyOverBoughtValue;}if(e$6 && e$6.studyOverBoughtColor){e8r.color=e$6.studyOverBoughtColor;}if(e8r.color == "auto"){e8r.color=H0p.defaultColor;}e8r.type=E$2;this.parameters.push(e8r);}if(g0w.studyOverSoldValue !== undefined){e8r={name:"studyOverSold",heading:H0p.translateIf("OverSold"),defaultValue:g0w.studyOverSoldValue,value:g0w.studyOverSoldValue,defaultColor:g0w.studyOverSoldColor,color:g0w.studyOverSoldColor};if(e$6 && e$6.studyOverSoldValue){e8r.value=e$6.studyOverSoldValue;}if(e$6 && e$6.studyOverSoldColor){e8r.color=e$6.studyOverSoldColor;}if(e8r.color == "auto"){e8r.color=H0p.defaultColor;}e8r.type="text";this.parameters.push(e8r);}if(!this.attributes.studyOverBoughtValue){this.attributes.studyOverBoughtValue={};}if(!this.attributes.studyOverSoldValue){this.attributes.studyOverSoldValue={};}}}l1w=this.panelSelect=G1K.panelSelect;F17=this.axisSelect=G1K.axisSelect;e_2.a9S();if(G1K.addWhenDone){F17=l1w=!({});}if(F17 || l1w){v$y="yaxisDis";v$y+="play";v$y+="Valu";v$y+="e";if(!z5X){z5X=j6q.Studies.addStudy(H0p,G1K.name,null,null,{calculateOnly:!!({})});j6q.Studies.removeStudy(H0p,z5X);}if(l1w){A4$="Sho";A4$+="w";A4$+=" ";A4$+="as Underlay";a3Y="A";a3Y+="uto";this.parameters.push(U$e({label:"Panel",name:"panelName",defaults:(function(){var b$b;b$b=[];e_2.a9S();b$b.push("Auto");for(var O4N in H0p.panels){if(O4N != z5X.panel || !e$6 || !e$6.panelName){b$b.push(q20(O4N));}}if(!H0p.checkForEmptyPanel(z5X.panel,!![],z5X)){b$b.push("New panel");}return b$b;})(),value:e$6 && e$6.panelName?q20(e$6.panelName):a3Y}),P_T({label:A4$,name:"underlay",defaults:!!"",value:z5X.underlay || z5X.parameters && z5X.parameters.underlayEnabled}));}e_2.H6P(1);D$l=-e_2.S40(1,"1361208857");e_2.D0J(1);g1H=-e_2.q7n(1,"729350451");M4I=2;for(var o5F="1" - 0;e_2.U6$(o5F.toString(),o5F.toString().length,66596) !== D$l;o5F++){z7Q=H0p.getYAxisByName(m7q,z5X.name);M4I+=2;}if(e_2.U6$(M4I.toString(),M4I.toString().length,59405) !== g1H){z7Q=H0p.getYAxisByName(m7q,z5X.name);}if(F17){a6L="flip";a6L+="p";a6L+="ed";m6J="I";m6J+="nvert Y-Axi";m6J+="s";l7B="d";l7B+="ef";l7B+="au";l7B+="lt";B8u="Y-A";B8u+="x";B8u+="is";this.parameters.push(U$e({label:B8u,name:"yaxisDisplay",defaults:(function(){var e9t,S7e,X2g,k2E,K2m;e9t="shar";e9t+="ed";S7e="lef";S7e+="t";X2g="r";X2g+="i";X2g+="gh";X2g+="t";k2E=m7q.yaxisLHS.concat(m7q.yaxisRHS);K2m=[];K2m.push("default",X2g,S7e,"none",e9t);for(var n2d=+"0";n2d < k2E.length;n2d++){if(k2E[n2d] != z7Q){K2m.push(k2E[n2d].name);}}return K2m;})(),value:e$6 && e$6.yaxisDisplayValue || z7Q && z7Q.position || (z5X.panel != z5X.name?"shared":m7q.yAxis.position || l7B),color:z7Q && z7Q.textStyle?z7Q.textStyle:"auto"}),P_T({label:m6J,name:a6L,defaults:![],value:e$6?e$6.flippedEnabled:z7Q?z7Q.flipped:![]}));}V7Z.call(this,"flippedEnabled",!z7Q && z5X.panel != z5X.name);V7Z.call(this,"underlayEnabled",h1I.underlay);V7Z.call(this,"panelName",h1I.seriesFN === null);V7Z.call(this,v$y,h1I.seriesFN === null || h1I.yAxis && h1I.yAxis.noDraw);}};j6q.Studies.DialogHelper.prototype.updateStudy=function(z9n){var p4n,a_q,p3q,u09;p4n={};a_q=this.sd;p3q=this.libraryEntry;if(!p3q){p3q={};}if(!a_q){a_q=p3q;}p4n.inputs=j6q.clone(a_q.inputs);p4n.outputs=j6q.clone(a_q.outputs);p4n.parameters=j6q.clone(a_q.parameters);function q2g(k3n){var c88=A2IFV;var f7B,O$k,p6o,R9w;if(this.panelSelect == "alias"){f7B=I0B(k3n);if(f7B){for(var D83 in this.stx.panels){if(!--f7B){return D83;}}}}O$k=-1771844819;p6o=-225640795;c88.H6P(21);R9w=c88.q7n("2",0);function I0B(q3I){c88.D0H();var e6m;e6m=q3I.match(/.* (\d)/);return e6m && e6m[+"1"];}for(var h0$=1;c88.U6$(h0$.toString(),h0$.toString().length,84155) !== O$k;h0$++){return k3n;}if(c88.Z2Z(R9w.toString(),R9w.toString().length,+"20071") !== p6o){return k3n;}}this.adjustInputTimesForDisplayZone(z9n);if(z9n.parameters && z9n.parameters.panelName){z9n.parameters.panelName=q2g.call(this,z9n.parameters.panelName);}j6q.extend(p4n,z9n);if(!p4n.parameters){p4n.parameters={};}if(p4n.inputs && p4n.inputs.id){a_q=j6q.Studies.replaceStudy(this.stx,p4n.inputs.id,this.name,p4n.inputs,p4n.outputs,p4n.parameters,null,a_q.study);}else {a_q=j6q.Studies.addStudy(this.stx,this.name,p4n.inputs,p4n.outputs,p4n.parameters,null,a_q.study);}u09=new j6q.Studies.DialogHelper({stx:this.stx,sd:a_q,axisSelect:this.axisSelect,panelSelect:this.panelSelect});for(var B$g in u09){if(B$g != "signal"){this[B$g]=u09[B$g];}}A2IFV.D0H();this.signal*=-1;;};j6q.Studies.DialogHelper.prototype.adjustInputTimesForDisplayZone=function(H58){var t6G=A2IFV;var X4r,q_n,k1t,R7J,j7_,g2V,z6x,B2N,Z1m,y2_;if(this.stx.displayZone){for(var i9J=0;i9J < this.dateTimeInputs.length;i9J++){X4r=this.dateTimeInputs[i9J];g2V="";if(H58 && H58.inputs){t6G.H6P(0);k1t=H58.inputs[t6G.S40(X4r," Date")];t6G.D0J(0);R7J=H58.inputs[t6G.S40(X4r," Time")];if(k1t){g2V=k1t;}if(R7J){g2V+=R7J;}}for(q_n=0;q_n < this.inputs.length;q_n++){z6x=" D";z6x+="ate";j7_=this.inputs[q_n];if(!k1t && k1t !== "" && j7_.name == X4r + z6x){g2V=j7_.value + g2V;}else if(!R7J && R7J !== "" && j7_.name == X4r + " Time"){g2V+=j7_.value;}}g2V=g2V.replace(/\D/g,"");if(g2V.length < 12){return;}B2N=j6q.strToDateTime(g2V);if(!isNaN(B2N.valueOf())){if(H58){if(!H58.inputs){H58.inputs={};}Z1m=j6q.convertTimeZone(B2N,this.stx.displayZone);t6G.D0J(0);H58.inputs[t6G.q7n(X4r," Date")]=j6q.yyyymmdd(Z1m);t6G.H6P(0);H58.inputs[t6G.S40(X4r," Time")]=j6q.hhmmss(Z1m);}else {Z1m=j6q.convertTimeZone(B2N,null,this.stx.displayZone);for(q_n=0;q_n < this.inputs.length;q_n++){y2_=" Tim";y2_+="e";j7_=this.inputs[q_n];if(j7_.name == X4r + " Date"){j7_.value=j6q.yyyymmdd(Z1m);}if(j7_.name == X4r + y2_){j7_.value=j6q.hhmmss(Z1m);}}}}}}};j6q.Studies.prepareStudy=function(d$s,M55,U9N){var j71=A2IFV;var d9p;d9p="undefin";d9p+="e";d9p+="d";if(typeof M55.calculateFN == d9p){M55.useRawValues=!!({});}if(j6q.isEmpty(U9N.outputMap)){for(var O3Q in U9N.outputs){if(M55.useRawValues){U9N.outputMap[O3Q]=O3Q;}else {j71.D0J(62);var f2R=j71.S40(11,423,7,42);j71.D0J(101);var C6d=j71.S40(4,14,11,4286,55804);j71.H6P(57);var u0F=j71.S40(4772,9548,6,2);j71.D0J(90);var F7B=j71.q7n(113050,7106,2,8);j71.D0J(0);var B5L=j71.q7n(1040,10);j71.D0J(52);var r0P=j71.q7n(67090,3532,20);j71.D0J(0);var o0o=j71.S40(489,3421);j71.H6P(109);var P3M=j71.q7n(2,602,20,10,6558);j71.D0J(117);var g51=j71.S40(8,5,20,16);j71.H6P(118);var c2M=j71.q7n(780,15,65,15,325);j71.D0J(15);var n$X=j71.q7n(10,1160,30);U9N.outputMap[O3Q + (("4849" | f2R) > C6d?" ":(u0F,F7B) !== (B5L,"3990" | 0)?r0P < (o0o,P3M)?"0x1ca7" * g51:(c2M,"k"):(n$X,+"5.07e+3")) + U9N.name]=O3Q;}}}};j6q.Studies.rejiggerDerivedStudies=function(G4I,X_T,U5i){var D6h,B4j,E5Z,x4N,e69,L87,V9Z,Y38,E3S;D6h=X_T.name;B4j=X_T.panel;E5Z=X_T.getDependents(G4I);for(var s6h=+"0";s6h < E5Z.length;s6h++){x4N=E5Z[s6h];e69=j6q.clone(x4N.inputs);L87=e69.id;if(!L87)continue;V9Z=!({});Y38=j6q.Studies.getFieldInputs(x4N);for(var R1B=0;R1B < Y38.length;R1B++){e69[Y38[R1B]]=e69[Y38[R1B]].replace(D6h,U5i);}E3S=j6q.Studies.replaceStudy(G4I,L87,x4N.type,e69,x4N.outputs,j6q.extend(x4N.parameters,{rejiggering:!![]}),null,x4N.study);delete E3S.parameters.rejiggering;}};j6q.Studies.removeStudySymbols=function(v6F,m0A){A2IFV.D0H();if(v6F.series){for(var R$m in v6F.series){m0A.deleteSeries(v6F.series[R$m],null,{action:"remove-study"});}};};j6q.Studies.replaceStudy=function(S8X,l3n,r80,M46,p99,q2x,H8d,A7Z){var K73,X2v,b_z,V2z;if(!q2x){q2x={};}if(l3n){q2x.replaceID=l3n;}l3n=q2x.replaceID;K73=S8X.layout.studies[l3n];j6q.Studies.removeStudySymbols(K73,S8X);if(K73.attribution){S8X.removeFromHolder(K73.attribution.marker);}if(S8X.quoteDriver){S8X.quoteDriver.updateSubscriptions();}if(M46){if(M46.id == M46.display){delete M46.display;}delete M46.id;}X2v=j6q.Studies.addStudy(S8X,r80,M46,p99,q2x,H8d,A7Z);X2v.highlight=K73.highlight;X2v.uniqueId=K73.uniqueId;V2z={};for(b_z in S8X.layout.studies){if(b_z == l3n){V2z[X2v.name]=X2v;}else {V2z[b_z]=S8X.layout.studies[b_z];}}S8X.layout.studies=V2z;V2z={};for(b_z in S8X.overlays){if(b_z == l3n){if(X2v.overlay || X2v.underlay){V2z[X2v.name]=X2v;}}else {V2z[b_z]=S8X.overlays[b_z];}}S8X.overlays=V2z;if(!S8X.overlays[X2v.name] && (X2v.overlay || X2v.underlay)){S8X.addOverlay(X2v);}S8X.checkForEmptyPanel(K73.panel);if(!q2x.rejiggering){S8X.initializeDisplay(S8X.chart);j6q.Studies.rejiggerDerivedStudies(S8X,K73,X2v.inputs.id,X2v.panel);S8X.changeOccurred("layout");if(!S8X.currentlyImporting && !q2x.calculateOnly && X2v.chart.dataSet){S8X.createDataSet(null,X2v.chart);}S8X.draw();}j6q.transferObject(K73,X2v);S8X.layout.studies[X2v.name]=K73;S8X.overlays[X2v.name]=K73;S8X.chart.state.studies.sorted=null;return K73;};j6q.Studies.addStudy=function(r8$,H4M,v1a,b7R,Y0N,X$i,l36){var I9I=A2IFV;var E2y,k6W,Z_W,a$e,K1h,E0f,R_9,p1K,v4D,j26,r5G,Z58,j6H;E2y=l36?l36:j6q.Studies.studyLibrary[H4M];if(!Y0N){Y0N={};}if(E2y){if(E2y.inputs){k6W=j6q.clone(E2y.inputs);for(var P6t in k6W){if(k6W[P6t] instanceof Array){if(E2y.attributes && E2y.attributes[P6t] && E2y.attributes[P6t].defaultSelected){k6W[P6t]=E2y.attributes[P6t].defaultSelected;}else {k6W[P6t]=k6W[P6t][0];}}}v1a=j6q.extend(k6W,v1a);}if(E2y.outputs){b7R=j6q.extend(j6q.clone(E2y.outputs),b7R);}Z_W=E2y.parameters;if(Z_W && Z_W.init){Y0N=j6q.extend(j6q.clone(Z_W.init),Y0N);}if(Z_W && !Y0N.display){Y0N.display=Z_W.display;}}if(!v1a){v1a=j6q.clone(j6q.Studies.DEFAULT_INPUTS);}if(!b7R){b7R=j6q.clone(j6q.Studies.DEFAULT_OUTPUTS);}if(!Y0N.chartName){Y0N.chartName="chart";}if(Y0N.panelName == "Auto" || Y0N.panelName == "Default panel"){Y0N.panelName="";}if(v1a.Period < 1){v1a.Period=1;}a$e=null;if(!r8$.layout.studies){r8$.layout.studies={};}if(E2y && E2y.initializeFN){a$e=E2y.initializeFN(r8$,H4M,v1a,b7R,Y0N,X$i,l36);}else {a$e=j6q.Studies.initializeFN(r8$,H4M,v1a,b7R,Y0N,X$i,l36);}if(!a$e){I9I.H6P(0);console.log(I9I.q7n("CIQ.Studies.addStudy: initializeFN() returned null for ",H4M));return;}l36=a$e.study;a$e.chart=r8$.charts[Y0N.chartName];a$e.type=H4M;a$e.permanent=l36.permanent;a$e.customLegend=l36.customLegend;a$e.uniqueId=j6q.uniqueID();j6q.Studies.prepareStudy(r8$,l36,a$e);K1h=r8$.chart.state.studies;if(!K1h){K1h=r8$.chart.state.studies={};}K1h.sorted=null;if(!Y0N.replaceID){r8$.layout.studies[a$e.inputs.id]=a$e;if(a$e.overlay || a$e.underlay){r8$.addOverlay(a$e);}if(!r8$.currentlyImporting && !Y0N.calculateOnly && a$e.chart.dataSet){r8$.createDataSet(null,a$e.chart);}}else {E0f=!0;delete Y0N.replaceID;}if(r8$.quoteDriver){r8$.quoteDriver.updateSubscriptions();}if(Y0N.calculateOnly){R_9="lay";R_9+="o";R_9+="u";R_9+="t";r8$.changeOccurred(R_9);return a$e;}p1K=r8$.panels[a$e.panel];v4D=![];j26=!(a$e.overlay || a$e.underlay);if(j26 && l36.horizontalCrosshairFieldFN){p1K.horizontalCrosshairField=l36.horizontalCrosshairFieldFN(r8$,a$e);}if(r8$.editCallback){v4D=!0;}else if(j26){if(r8$.callbackListeners.studyPanelEdit && r8$.callbackListeners.studyPanelEdit.length){v4D=!!({});}}else {if(r8$.callbackListeners.studyOverlayEdit && r8$.callbackListeners.studyOverlayEdit.length){v4D=!!({});}}if(v4D){Y0N.editMode=!!({});r5G=![];for(var q4l in a$e.inputs){if(q4l == "id")continue;if(q4l == "display")continue;r5G=!!1;break;}if(!r5G){for(var D3H in a$e.outputs){r5G=!![];break;}}if(r5G){if(typeof a$e.study.edit != "undefined"){if(a$e.study.edit){Z58=(function(K3h,j5i,c8F,m_O){I9I.D0H();return function(){j6q.clearCanvas(K3h.chart.tempCanvas,K3h);j5i.study.edit(j5i,{stx:K3h,inputs:c8F,outputs:m_O,parameters:Y0N});};})(r8$,a$e,v1a,b7R,Y0N);r8$.setPanelEdit(p1K,Z58);a$e.editFunction=Z58;}}else if(!j26){Z58=(function(G1p,z46,H3N,Z4c,v9Y){I9I.a9S();return function(s7o){I9I.a9S();j6q.clearCanvas(G1p.chart.tempCanvas,G1p);G1p.dispatch("studyOverlayEdit",{stx:G1p,sd:z46,inputs:H3N,outputs:Z4c,parameters:v9Y,forceEdit:s7o});};})(r8$,a$e,v1a,b7R,Y0N);a$e.editFunction=Z58;}else {if(r8$.editCallback){Z58=(function(Q2r,R2K,I81,q2r){I9I.a9S();return function(){var i9o;i9o=Q2r.editCallback(Q2r,R2K);j6q.clearCanvas(Q2r.chart.tempCanvas,Q2r);j6q.Studies.studyDialog(Q2r,H4M,i9o,{inputs:I81,outputs:q2r,parameters:Y0N});};})(r8$,a$e,v1a,b7R,Y0N);if(p1K.name != "chart"){r8$.setPanelEdit(p1K,Z58);}}else {j6H="ch";j6H+="a";j6H+="rt";Z58=(function(F2b,x_8,r57,x_t,V74){return function(){j6q.clearCanvas(F2b.chart.tempCanvas,F2b);F2b.dispatch("studyPanelEdit",{stx:F2b,sd:x_8,inputs:r57,outputs:x_t,parameters:V74});};})(r8$,a$e,v1a,b7R,Y0N);if(p1K.name != j6H){r8$.setPanelEdit(p1K,Z58);a$e.editFunction=Z58;}}}}}r8$.changeOccurred("layout");if(!E0f){r8$.draw();}return a$e;};j6q.Studies.removeStudy=function(N$F,j$e){var k_5,o5u,O4O,I8D;k_5=N$F.panels[j$e.panel];o5u=k_5 && k_5.yAxis.name;if(j$e.overlay || j$e.underlay){N$F.removeOverlay(j$e.name);}O4O=N$F.panels[j$e.panel];if(j$e.attribution){N$F.removeFromHolder(j$e.attribution.marker);}delete N$F.layout.studies[j$e.name];if(O4O && !N$F.checkForEmptyPanel(O4O)){if(o5u == j$e.name){N$F.electNewPanelOwner(O4O);}I8D=N$F.getYAxisByName(j$e.panel,j$e.name);if(I8D){I8D.name=I8D.studies[+"1"] || I8D.renderers[0];}}N$F.draw();A2IFV.D0H();N$F.resizeChart();};j6q.Studies.getPanelFromFieldName=function(P2M,p$Y){var F$i,c6g,v6B,y3W,d_J;F$i=j6q.Studies.getFieldInputs(p$Y);if(!F$i.length){return null;}c6g=P2M.layout.studies;if(!c6g){return null;}v6B={};for(var s2F in c6g){for(var z0V in c6g[s2F].outputMap){v6B[z0V]=c6g[s2F].panel;}}for(var Y5g=0;Y5g < F$i.length;Y5g++){y3W=p$Y.inputs[F$i[Y5g]];if(y3W){d_J=v6B[y3W];if(d_J){return d_J;}}}return null;};j6q.Studies.createLibraryHash=function(){var u6E=A2IFV;var c3o,t8_,Q3L;c3o=-308398831;u6E.D0J(10);t8_=-u6E.q7n("231253380",0);u6E.H6P(21);Q3L=u6E.q7n("2",0);for(var n8u=1;u6E.Z2Z(n8u.toString(),n8u.toString().length,23553) !== c3o;n8u++){return Object.keys(j6q.Studies.studyLibrary).join(1191 == ("1431" * 1,2918)?(128847,545935) === (929733,97506)?183067 == (4745,788)?("h",!({})):!![]:("h","|"):"h");}if(u6E.Z2Z(Q3L.toString(),Q3L.toString().length,60065) !== t8_){return Object.keys(j6q.Studies.studyLibrary).join(9850 === (6966,3044)?(958.62,460.86) !== ("698.48" - 0,551.6)?817.11 !== (4200,266)?("I",!0):!!"":("i","h"):"|");};};j6q.Studies.displayStudies=function(q1m,e56,j6O){var J0y,l7f,i04,d$Z,x26,v0Q,H3M,S$e,W51,o5N,r8J,Y68,H9q,z5z,j1n,d7h;if(j6O){e56.studyLibraryHash=j6q.Studies.createLibraryHash();}J0y=q1m.layout.studies;if(!J0y){return;}l7f={};l7f[e56.name]=!0;for(var f$q in J0y){i04="u";i04+="n";i04+="defined";d$Z=J0y[f$q];x26=d$Z.study;if(!x26)continue;v0Q=d$Z.underlay || d$Z.parameters && d$Z.parameters.underlayEnabled;if(j6O && !v0Q || !j6O && v0Q)continue;H3M=j6q.clone(x26.renderer);if(H3M && !(H3M instanceof Array)){H3M=[H3M];}S$e=q1m.panels[d$Z.panel];if(S$e){if(S$e.chart != e56)continue;if(S$e.hidden)continue;if(!l7f[S$e.name]){W51=d$Z.permanent || !q1m.manageTouchAndMouse;if(S$e.closeX){if(W51){S$e.closeX.style.display="none";}}else if(S$e.close){o5N="no";o5N+="ne";if(W51){S$e.close.style.display=o5N;}}if(S$e.edit){if(W51){S$e.edit.style.display="none";}}l7f[S$e.name]=W51;}}else {if(q1m.currentlyImporting){delete J0y[f$q];}continue;}r8J=d$Z.chart.dataSegment;if(d$Z.panel == d$Z.parameters.chartName && (!d$Z.parameters || !d$Z.parameters.panelName)){Y68=j6q.Studies.getPanelFromFieldName(q1m,d$Z);if(Y68 && d$Z.panel != Y68){d$Z.panel=Y68;}}if(typeof x26.seriesFN == i04){if(H3M){if(!d$Z.overlay){j6q.Studies.createYAxis(q1m,d$Z,r8J,S$e);}for(var A9R=0;A9R < H3M.length;A9R++){H9q=H3M[A9R];for(var x$C in d$Z.outputMap){if(d$Z.outputMap[x$C] == H9q.field){H9q.field=x$C;}}if(!H9q.field)continue;H9q.panel=d$Z.panel;z5z=H9q.binding;if(z5z){for(var O4f in z5z){j1n=j6q.Studies.determineColor(d$Z.outputs[z5z[O4f]]);if(j1n && j1n != "auto"){H9q[O4f]=j1n;};}}H9q.yAxis=null;d7h=j6q.Renderer.produce(H9q.type,H9q);d7h.stx=q1m;d7h.attachSeries(null,H9q).draw();}}else {j6q.Studies.displaySeriesAsLine(q1m,d$Z,r8J);}if(S$e){j6q.Studies.displayError(q1m,d$Z);}}else {if(x26.seriesFN){if(S$e){x26.seriesFN(q1m,d$Z,r8J);j6q.Studies.displayError(q1m,d$Z);}}}}};j6q.Studies.displayError=function(G4U,o5a,f4W){var Z5m,I4L,z9a;Z5m="Not enough da";Z5m+="ta to";Z5m+=" compu";Z5m+="te ";if(!o5a.error){return;}I4L=f4W && f4W.panel?f4W.panel:o5a.panel;z9a=o5a.error === !!({})?G4U.translateIf(Z5m) + G4U.translateIf(o5a.study.name):G4U.translateIf(o5a.error);if(f4W && (f4W.h !== "center" || f4W.v !== "bottom")){G4U.watermark(I4L,f4W);return;}G4U.displayErrorAsWatermark(I4L,z9a);};j6q.Studies.calculateMinMaxForDataPoint=function(M$0,v$t,d_L){A2IFV.D0H();var i4v,X8t,n22;i4v=Number.MAX_VALUE;X8t=Number.MAX_VALUE * -("1" - 0);for(var N8H=0;N8H < d_L.length;N8H++){n22=d_L[N8H][v$t];if(n22 === null || typeof n22 == "undefined")continue;if(isNaN(n22))continue;i4v=Math.min(n22,i4v);X8t=Math.max(n22,X8t);}return {min:i4v,max:X8t};};j6q.Studies.getYAxisParameters=function(P1M,X05){var o3o,B1Y,p8M,Z2j;A2IFV.a9S();o3o={};B1Y=P1M.layout.studies && P1M.layout.studies[X05.name];if(B1Y){p8M=B1Y.study;if(p8M.yaxis || p8M.yAxisFN){o3o.noDraw=!![];}else {if(p8M.parameters && p8M.parameters.excludeYAxis){o3o.noDraw=!!"1";}o3o.ground=p8M.yAxis && p8M.yAxis.ground;if(X05){if(p8M.range != "bypass"){Z2j="0 t";Z2j+="o 100";if(p8M.range == Z2j){o3o.range=[0,100];}else if(p8M.range == "-1 to 1"){o3o.range=[-1,1];}else {if(p8M.range == "0 to max"){o3o.range=[0,Math.max(0,X05.high)];}else if(p8M.centerline || p8M.centerline === 0){o3o.range=[Math.min(p8M.centerline,X05.low),Math.max(p8M.centerline,X05.high)];}}}if(o3o.range){X05.low=o3o.range[0];X05.high=o3o.range[1];}if(B1Y.min){X05.min=B1Y.min;}if(B1Y.max){X05.max=B1Y.max;}if(B1Y.parameters && B1Y.parameters.studyOverZonesEnabled){o3o.noDraw=!!1;}}}}return o3o;};j6q.Studies.doPostDrawYAxis=function(c_V,v9g){var V9s,U9e,a7d,r_l,e0J;for(var i7j in c_V.layout.studies){V9s=c_V.layout.studies[i7j];U9e=c_V.panels[V9s.panel];if(!U9e || U9e.hidden)continue;a7d=V9s.getYAxis(c_V);if(a7d != v9g)continue;r_l=V9s.study;if(v9g.name == V9s.name){if(r_l.yaxis){r_l.yaxis(c_V,V9s);}if(r_l.yAxisFN){r_l.yAxisFN(c_V,V9s);};}j6q.Studies.drawZones(c_V,V9s);if(!V9s.error){e0J=r_l.centerline;if(e0J || e0J === 0 || e0J !== null && v9g.highValue > +"0" && v9g.lowValue < +"0"){j6q.Studies.drawHorizontal(c_V,V9s,null,e0J || 0,v9g);}}}};j6q.Studies.displaySeriesAsLine=function(p8t,a0S,P8R){var x40;if(!P8R.length){return;}x40=p8t.panels[a0S.panel];if(!x40 || x40.hidden){return;}A2IFV.D0H();for(var U$K in a0S.outputMap){j6q.Studies.displayIndividualSeriesAsLine(p8t,a0S,x40,U$K,P8R);}};j6q.Studies.displaySeriesAsHistogram=function(T$m,R$v,a71){var V_q,W_6,F1P,A$9,Q6K,K0_,a5j,o$O,J2v,X_j;if(!a71.length){return;}V_q=T$m.panels[R$v.panel];if(!V_q){return;}if(V_q.hidden){return;}W_6=[];for(var K31 in R$v.outputMap){F1P=R$v.outputs[R$v.outputMap[K31]];if(!F1P)continue;A$9=0.3;if(typeof F1P == "object"){A$9=F1P.opacity;F1P=F1P.color;}Q6K={field:K31,fill_color_up:F1P,border_color_up:F1P,fill_color_down:F1P,border_color_down:F1P};if(R$v.underlay){Q6K.opacity_up=Q6K.opacity_down=A$9 || "0.3" * 1;}W_6.push(Q6K);}A2IFV.D0H();K0_=R$v.getYAxis(T$m);a5j=R$v.inputs;o$O=a5j.WidthFactor;if(R$v.study && R$v.study.parameters){J2v=R$v.study.parameters;if(typeof J2v.widthFactor !== "undefined"){o$O=J2v.widthFactor;}}X_j={name:R$v.name,type:a5j.HistogramType?a5j.HistogramType:"overlaid",panel:R$v.panel,yAxis:K0_,widthFactor:o$O || 0.5,bindToYAxis:!![],highlight:R$v.highlight};T$m.drawHistogram(X_j,W_6);};j6q.Studies.displayIndividualSeriesAsLine=function(a7X,z0H,b3B,k$l,P0P){var u5x,P5J,f3h,A6W,M8e,t4p,F38,a$g,u1n,L1c,t7C,e9T,h3i,a$d,j9G,L6M,w5v;u5x="t";u5x+="rans";u5x+="p";u5x+="arent";P5J="st";P5J+="ring";if(!b3B.height){b3B.height=b3B.bottom - b3B.top;}f3h=z0H.getContext(a7X);A6W=z0H.outputs[z0H.outputMap[k$l]];if(!A6W){return;}f3h.save();if(typeof A6W === P5J){A6W={color:A6W,width:1};}f3h.lineWidth=A6W.width || 1;M8e=A6W.color;if(M8e == "auto"){M8e=a7X.defaultColor;}f3h.strokeStyle=M8e;t4p=A6W.pattern;f3h.setLineDash(j6q.borderPatternToArray(f3h.lineWidth,t4p));f3h.lineDashOffset=0;F38=+"0";a$g=z0H.study;u1n=z0H.getYAxis(a7X);F38=a7X.decimalPlacesFromPriceTick(u1n.priceTick);if(z0H.overlay || z0H.underlay){F38=null;}if(u1n.decimalPlaces || u1n.decimalPlaces === 0){F38=u1n.decimalPlaces;}L1c=null;if(z0H.parameters){L1c=z0H.parameters.label;}t7C=a$g.parameters;if(!t7C){t7C={};}e9T=t7C.plotType == "step";if(z0H.series){for(var L1k in z0H.series){h3i=z0H.series[L1k].parameters.type;if(h3i){A2IFV.H6P(68);e9T=A2IFV.S40(h3i,"step");}}}if(t7C.noLabels){L1c=![];}if(!z0H.noSlopes && z0H.noSlopes !== !({})){z0H.noSlopes=t7C.noSlopes;}if(!z0H.extendToEnd && z0H.extendToEnd !== !!""){z0H.extendToEnd=t7C.extendToEnd;}a$d=L1c || a7X.preferences.labels && L1c !== ![];j9G=z0H.gaplines;if(j9G === !({})){j9G=u5x;}A2IFV.a9S();L6M=z0H.inputs.Symbol;w5v=j9G?a7X.getGapColorFunction(L6M,k$l,A6W,j9G):null;a7X.plotDataSegmentAsLine(k$l,b3B,{yAxis:u1n,skipTransform:a7X.panels[z0H.panel].name != z0H.chart.name,label:a$d,labelDecimalPlaces:F38,noSlopes:z0H.noSlopes,step:e9T,alignStepToSide:z0H.alignStepToSide,extendToEndOfLastBar:z0H.extendToEndOfLastBar,width:z0H.lineWidth,extendToEndOfDataSet:z0H.extendToEnd,gapDisplayStyle:j9G,highlight:z0H.highlight},w5v);if(a$g.appendDisplaySeriesAsLine){a$g.appendDisplaySeriesAsLine(a7X,z0H,P0P,k$l,b3B);}f3h.restore();};j6q.Studies.drawHorizontal=function(l4N,c0s,V6q,Y2V,T9s,x2J){var F8X,t4M,f0U;F8X=l4N.panels[c0s.panel];t4M=l4N.getBackgroundCanvas().context;if(!F8X){return;}if(!x2J){x2J=T9s.textStyle;}A2IFV.D0H();f0U=l4N.pixelFromPrice(Y2V,F8X,T9s);if(f0U > T9s.top && f0U < T9s.bottom){l4N.plotLine(F8X.left,F8X.right,f0U,f0U,x2J,"segment",t4M,!!0,{opacity:x2J && x2J.opacity?x2J.opacity:0.5});}};j6q.Studies.displayHistogramWithSeries=function(b2W,B3s,o2H){var n_f,f$Y;n_f=b2W.panels[B3s.panel];f$Y=0.5;A2IFV.D0H();if(B3s.underlay){f$Y=0.3;}j6q.Studies.createHistogram(b2W,B3s,o2H,!!"",f$Y);j6q.Studies.displaySeriesAsLine(b2W,B3s,o2H);};j6q.Studies.drawZones=function(x3l,I3$,l3k){var e2Y=A2IFV;var L58,d8M,g4H,s24,p54,q$5,u3g,d$n,i2V,R2i,K5l,P$G,e$C,B_V,g6F,Z4v,A3C,G1d,T1f,g7G,I5S,A40,i_P,u5O,x3c,n3B,O1a,l06;L58="borde";L58+="r";d8M="l";d8M+="ef";d8M+="t";g4H="aut";g4H+="o";if(!I3$.parameters || !I3$.parameters.studyOverZonesEnabled){return;}s24=parseFloat(I3$.parameters.studyOverSoldValue);p54=parseFloat(I3$.parameters.studyOverBoughtValue);q$5=I3$.parameters.studyOverSoldColor;u3g=I3$.parameters.studyOverBoughtColor;d$n=I3$.zoneOutput;if(!d$n){d$n="Result";}i2V=j6q.Studies.determineColor(I3$.outputs[d$n]);if(!i2V || i2V == g4H || j6q.isTransparent(i2V)){i2V=x3l.defaultColor;}if(!q$5){q$5=i2V;}if(!q$5 || q$5 == "auto" || j6q.isTransparent(q$5)){q$5=x3l.defaultColor;}if(!u3g){u3g=i2V;}if(!u3g || u3g == "auto" || j6q.isTransparent(u3g)){u3g=x3l.defaultColor;}R2i=x3l.panels[I3$.panel];K5l=I3$.getYAxis(x3l);P$G=K5l.displayBorder;if(x3l.axisBorders === !"1"){P$G=!({});}if(x3l.axisBorders === !""){P$G=!!({});}if(K5l.width === 0){P$G=!"1";}e$C=x3l.getYAxisCurrentPosition(K5l,R2i);e2Y.D0J(68);B_V=e2Y.S40(e$C,d8M);g6F=K5l.justifyRight;if(!g6F && g6F !== !!0){if(x3l.chart.yAxis.justifyRight || x3l.chart.yAxis.justifyRight === !"1"){g6F=x3l.chart.yAxis.justifyRight;}else {g6F=B_V;}}Z4v=Math.round(K5l.left + (B_V?K5l.width:0)) + 0.5;A3C=P$G?3:0;G1d=x3l.getBackgroundCanvas().context;T1f=G1d.fillStyle;G1d.globalAlpha=0.2;x3l.startClip(R2i.name,!![]);G1d.beginPath();g7G=Math.round(x3l.pixelFromPrice(p54,R2i,K5l)) + 0.5;G1d.strokeStyle=u3g;G1d.moveTo(R2i.left,g7G);G1d.lineTo(R2i.right,g7G);G1d.stroke();G1d.closePath();G1d.beginPath();e2Y.H6P(119);var J$Z=e2Y.q7n(3,3,7,0,14);I5S=Math.round(x3l.pixelFromPrice(s24,R2i,K5l)) + "0.5" * J$Z;G1d.strokeStyle=q$5;G1d.moveTo(R2i.left,I5S);G1d.lineTo(R2i.right,I5S);G1d.stroke();G1d.closePath();A40=new j6q.Plotter();A40.newSeries(L58,"stroke",x3l.canvasStyle("stx_grid_border"));if(P$G){i_P=B_V?Z4v - A3C:Z4v - 0.5;u5O=B_V?Z4v + 0.5:Z4v + A3C;A40.moveTo("border",i_P,g7G);A40.lineTo("border",u5O,g7G);A40.moveTo("border",i_P,I5S);A40.lineTo("border",u5O,I5S);}G1d.fillStyle=T1f;x3c={skipTransform:x3l.panels[I3$.panel].name != I3$.chart.name,panelName:I3$.panel,band:d$n + " " + I3$.name,yAxis:K5l,opacity:"0.3" - 0};if(!I3$.highlight && x3l.highlightedDraggable){e2Y.D0J(1);x3c.opacity*=e2Y.q7n(1,"0.3");}j6q.preparePeakValleyFill(x3l,j6q.extend(x3c,{threshold:p54,direction:K5l.flipped?-1:1,color:u3g}));j6q.preparePeakValleyFill(x3l,j6q.extend(x3c,{threshold:s24,direction:K5l.flipped?1:-1,color:q$5}));G1d.globalAlpha=1;if(!I3$.study || !I3$.study.yaxis){if(P$G){n3B=Math.round(K5l.bottom) + 0.5;A40.moveTo("border",Z4v,K5l.top);A40.lineTo("border",Z4v,n3B);A40.draw(G1d,"border");}if(K5l.width !== +"0"){O1a="ri";O1a+="ght";x3l.canvasFont("stx_yaxis",G1d);x3l.canvasColor("stx_yaxis",G1d);G1d.textAlign=g6F?O1a:"left";if(B_V){e2Y.D0J(120);var n5P=e2Y.S40(1,0,4,6,6);l06=K5l.left + n5P;if(g6F){e2Y.D0J(121);var r$c=e2Y.S40(10,24,11,0);l06=K5l.left + K5l.width - A3C - r$c;}}else {e2Y.H6P(16);var h5s=e2Y.S40(17,20);l06=K5l.left + A3C + h5s;if(g6F){l06=K5l.left + K5l.width;}}G1d.fillStyle=u3g;G1d.fillText(p54,l06,g7G);G1d.fillStyle=q$5;G1d.fillText(s24,l06,I5S);G1d.fillStyle=T1f;}}x3l.endClip();G1d.globalAlpha=1;if(K5l.name == I3$.name){K5l.yAxisPlotter=new j6q.Plotter();}};j6q.Studies.createHistogram=function(n7b,L4T,S0b,I0N,r4a){var O45,K97,h4a,I2X,d_R,Z3m,r66,q1j,o11,K2v,I7W,x9w,X89,b6P,R78,E1J,s8L,L2M,d1g,D$s;O45=n7b.panels[L4T.panel];K97=L4T.getContext(n7b);h4a=L4T.getYAxis(n7b);n7b.startClip(O45.name);I2X=n7b.layout.candleWidth - 2;if(I2X < 2){I2X=1;}d_R=n7b.pixelFromPrice(0,O45,h4a);if(h4a.min > 0){d_R=n7b.pixelFromPrice(h4a.min,O45,h4a);}if(I0N){d_R=Math.floor(O45.top + O45.height / 2);}Z3m=L4T.name + "_hist";n7b.canvasColor("stx_histogram");r66=K97.fillStyle;if(r4a || r4a === 0){K97.globalAlpha=r4a;}if(!L4T.highlight && n7b.highlightedDraggable){K97.globalAlpha*=0.3;}q1j=null;o11=null;K2v=L4T.outputs;for(var r5X=0;r5X < S0b.length;r5X++){I7W="Positive";I7W+=" ";I7W+="Bar";x9w=S0b[r5X];if(!x9w)continue;if(x9w.candleWidth){I2X=Math.floor(Math.max("1" - 0,x9w.candleWidth - 2));}X89=Math.floor(n7b.pixelFromBar(r5X,O45.chart) - I2X / 2);b6P=Math.floor(I2X);if(q1j === null){R78=n7b.tickFromPixel(X89,O45.chart) - ("1" >> 0);if(R78 < 0){q1j=o11;}else {q1j=n7b.pixelFromPrice(n7b.chart.dataSet[R78][Z3m],O45,h4a) - d_R;}}else {q1j=o11;}o11=n7b.pixelFromPrice(x9w[Z3m],O45,h4a) - d_R;E1J=j6q.Studies.determineColor(K2v["Decreasing Bar"]);s8L=j6q.Studies.determineColor(K2v["Increasing Bar"]);L2M=j6q.Studies.determineColor(K2v[I7W]);d1g=j6q.Studies.determineColor(K2v["Negative Bar"]);D$s=h4a.flipped;K97.fillStyle=r66;if(E1J && (D$s?o11 < q1j:o11 > q1j)){K97.fillStyle=E1J;}else if(s8L && (D$s?o11 > q1j:o11 < q1j)){K97.fillStyle=s8L;}else if(L2M && (D$s?o11 > 0:o11 < 0)){K97.fillStyle=L2M;}else if(d1g && (D$s?o11 < 0:o11 > 0)){K97.fillStyle=d1g;}K97.fillRect(X89,d_R,b6P,Math.floor(o11));}A2IFV.D0H();K97.globalAlpha=1;n7b.endClip();};j6q.Studies.prettify={Close:3200 !== 5295?("186.47" * 1,4959) >= 1570?2870 > 470?"C":(+"0x22c5",4.71e+3):0xe2f:"D",Open:2920 < (9643,1470)?!"":"O",High:(+"356.52",6616) == ("590" * 1,7220)?("d","x"):(348.89,1239) == 680.59?181.98:+"8690" == (218.86,407.92)?"0x2485" * 1:"H",Low:(882.35,8261) > 3480?"L":(996.35,824.32) < 5853?1674 <= 7436?2.35e+2:"683" ^ 0:+"43.30",simple:Y$r,exponential:N1H,triangular:"tma",VIDYA:"vdma",weighted:w8y,"welles wilder":"smma",true:"y",false:"n"};j6q.Studies.prettyRE=/^.*\((.*?)\).*$/;j6q.Studies.prettyDisplay=function(U1b){var A$A,S8P;A$A=j6q.Studies.prettyRE.exec(U1b);if(!A$A){return U1b;}A2IFV.D0J(21);S8P=A$A[A2IFV.q7n("1",0)];if(S8P){for(var O4p in j6q.Studies.prettify){S8P=S8P.replace(O4p,j6q.Studies.prettify[O4p]);}U1b=U1b.replace(A$A[1],S8P);}A2IFV.D0H();return U1b;};j6q.Studies.getFieldInputs=function(v3a){var n23,X6c;A2IFV.D0H();n23=[];X6c=v3a.study.inputs;for(var H2u in X6c){if(X6c[H2u] == "field"){n23.push(H2u);}}return n23;};j6q.Studies.initializeFN=function(l0w,Y1S,q7I,T_c,U84,D15,K0l){var o9L=A2IFV;var B$y,b8h,M5X,q6p,q7q,I9Y,Z4I,Z$2,R8l,C$b,C4U,S0m,C$p,V$l,M7B,G0l,v6n,u0h,N54,O7E,j8I,J8b,s8p,f35,C9r,f1U,c1r;B$y="st";B$y+="r";B$y+="in";B$y+="g";if(!q7I){q7I={};}if(!U84){U84={};}if(!q7I.id){b8h=-197226571;M5X=-+"1759371641";q6p=2;for(var x5i=1;o9L.Z2Z(x5i.toString(),x5i.toString().length,"21588" * 1) !== b8h;x5i++){q7I.id=j6q.Studies.generateID(l0w,Y1S,q7I,U84.replaceID,U84.display);q6p+=2;}if(o9L.U6$(q6p.toString(),q6p.toString().length,10804) !== M5X){q7I.id=j6q.Studies.generateID(l0w,Y1S,q7I,U84.replaceID,U84.display);}}if(!q7I.display){q7I.display=q7I.id;}q7q=new j6q.Studies.StudyDescriptor(q7I.id,Y1S,q7I.id,q7I,T_c,U84);if(q7I.Period){o9L.H6P(1);q7q.days=Math.max(o9L.q7n(1,"1"),parseInt(q7q.inputs.Period,"10" ^ 0));}if(K0l){if(!K0l.inputs){K0l.inputs=q7q.study.inputs;}if(!K0l.outputs){K0l.outputs=q7q.study.outputs;}q7q.study=K0l;}else {K0l=q7q.study;}if(K0l.display){q7I.display=K0l.display;}if(typeof U84.panelName == B$y){D15=U84.panelName;}if(D15 == q7I.id || D15 && !l0w.panelExists(D15)){q7q.underlay=q7q.overlay=!({});}if(D15 == "Own panel" || D15 == "New panel"){D15=null;}I9Y=q7q.overlay || q7I.Overlay || q7q.overlay !== ![] && K0l.overlay;Z4I=q7q.underlay || q7I.Underlay || q7q.underlay !== !1 && K0l.underlay;if(I9Y && U84.underlayEnabled){Z4I=!![];}if(Z4I){q7q.underlay=!!({});}if(!Z4I && l0w.chart.panel && D15 == l0w.chart.panel.name){I9Y=!!"1";}if(I9Y){q7q.overlay=!!1;}Z$2=l0w.preferences.dragging;if(Z$2 === !0 || Z$2 && Z$2.study){q7q.overlay=!"";}if(D15){U84.panelName=D15;}else if(!I9Y && !Z4I){D15=q7I.id;}if(U84.calculateOnly){if(I9Y || Z4I){if(l0w.panels[U84.panelName]){q7q.panel=U84.panelName;}else {q7q.panel=j6q.Studies.getPanelFromFieldName(l0w,q7q) || U84.chartName;}}return q7q;}R8l={};C$b=l0w.layout.studies[U84.replaceID];if(C$b){R8l={outputMap:j6q.clone(C$b.outputMap),panel:C$b.panel};}q7q.panel="";if(D15){C4U="New p";C4U+="anel";S0m=j6q.Studies.smartMovePanel(l0w,q7q.inputs,D15,U84.replaceID,U84.panelName == C4U);if(S0m){q7q.panel=S0m.name;}}else if(I9Y || Z4I){q7q.panel=j6q.Studies.getPanelFromFieldName(l0w,q7q) || U84.chartName;}if(!q7q.panel){C$p=K0l.panelHeight || null;V$l=K0l.yAxis || ({});V$l.name=q7q.inputs.id;q7q.panel=q7q.inputs.id;M7B=-199681504;o9L.H6P(40);G0l=o9L.S40(32,"1232114324");v6n=2;for(var q2u=1;o9L.U6$(q2u.toString(),q2u.toString().length,74241) !== M7B;q2u++){l0w.createPanel(q7q.inputs.display,q7q.panel,C$p,U84.chartName,new j6q.ChartEngine.YAxis(V$l));o9L.H6P(1);v6n+=o9L.q7n(1,"2");}if(o9L.U6$(v6n.toString(),v6n.toString().length,65180) !== G0l){l0w.createPanel(q7q.inputs.display,q7q.panel,C$p,U84.chartName,new j6q.ChartEngine.YAxis(V$l));}l0w.createPanel(q7q.inputs.display,q7q.panel,C$p,U84.chartName,new j6q.ChartEngine.YAxis(V$l));}if(q7q.parameters && q7q.parameters.panelName){q7q.parameters.panelName=q7q.panel;}u0h=l0w.panels[q7q.panel];N54=j6q.Studies.smartCreateYAxis(l0w,u0h,q7q.inputs.id,U84.yaxisDisplayValue,U84.yAxis || K0l.yAxis);O7E=K0l?j6q.clone(K0l.yAxis):null;j8I=O7E || N54;if(j8I){if(j8I.ground){j8I.initialMarginBottom=0;}if(j8I.initialMarginTop || j8I.initialMarginTop === 0 || j8I.initialMarginBottom || j8I.initialMarginBottom === +"0"){l0w.calculateYAxisMargins(j8I);}if(j8I.name == U84.replaceID){j8I.name=q7q.inputs.id;}}if(N54){J8b="defa";J8b+="u";J8b+="l";J8b+="t";s8p="s";s8p+="har";s8p+="e";s8p+="d";f35="n";f35+="o";f35+="n";f35+="e";N54.width=N54.position == f35?0:j6q.ChartEngine.YAxis.prototype.width;if(U84.yaxisDisplayValue == s8p || U84.yaxisDisplayValue == J8b){delete U84.yaxisDisplayValue;}else {if(O7E){j6q.ensureDefaults(N54,O7E);}else if(N54.name == q7q.name){C9r="au";C9r+="t";C9r+="o";if(!U84.yaxisDisplayColor || U84.yaxisDisplayColor == C9r){delete N54.textStyle;}else {N54.textStyle=j6q.colorToHex(U84.yaxisDisplayColor);}N54.justifyRight=null;N54.flipped=U84.flippedEnabled;}}if(N54 != u0h.yAxis){N54.displayGridLines=!({});}else if(N54 != l0w.chart.yAxis){N54.displayGridLines=l0w.displayGridLinesInStudies;}}l0w.calculateYAxisPositions();if(C$b){f1U=!({});for(var z$2 in l0w.drawingObjects){c1r=l0w.drawingObjects[z$2];if(R8l.outputMap && R8l.outputMap.hasOwnProperty(c1r.field)){c1r.field=c1r.field.replace(U84.replaceID,q7q.inputs.id);if(q7q.parameters && q7q.parameters.panelName){c1r.panelName=q7q.parameters.panelName;}else {c1r.panelName=q7q.panel;}f1U=!"";}else if(R8l.panel && R8l.panel == c1r.panelName){c1r.panelName=c1r.panelName.replace(U84.replaceID,q7q.inputs.id);f1U=!"";}}if(f1U){l0w.changeOccurred("vector");}}return q7q;};j6q.Studies.smartMovePanel=function(p1J,U4F,k42,u6S,v4P){var O$t,k0Q,A4G,c8r;k0Q=U4F.id;if(u6S){O$t=p1J.layout.studies[u6S];}if(O$t){A4G=p1J.panels[O$t.panel];if(A4G){if(A4G.yAxis.name == u6S){if((v4P || k42 != u6S) && !p1J.checkForEmptyPanel(A4G.name,!!"1",O$t)){p1J.electNewPanelOwner(A4G);c8r=O$t.getYAxis(p1J);if(c8r.name == u6S){p1J.electNewYAxisOwner(c8r);};}else if(k42 == u6S || !p1J.panels[k42]){if(k0Q != A4G.name){p1J.modifyPanel(A4G,{name:k0Q,display:U4F.display});}k42=k0Q;}}}}A2IFV.a9S();return p1J.panels[k42];};j6q.Studies.smartCreateYAxis=function(s4M,o35,K8n,S9A,I84){var e8g,C0$,g3c,H7m,x6r;e8g="n";e8g+="o";e8g+="n";e8g+="e";C0$=s4M.getYAxisByName(o35,K8n);if(!S9A && I84){S9A=I84.position;}if(S9A == "default" || S9A == "shared" || S9A == o35.yAxis.name){S9A="";}if(["left","right",e8g].indexOf(S9A) > -+"1"){if(!C0$ || C0$.isShared(s4M)){g3c=I84 || ({});j6q.extend(g3c,{name:K8n,position:S9A});if(!C0$ && !s4M.currentlyImporting && o35 != o35.chart.panel && !o35.yAxis.studies.length && !o35.yAxis.renderers.length){C0$=o35.yAxis;j6q.extend(C0$,g3c);}else {H7m=C0$ == o35.yAxis;if(C0$){C0$.name=s4M.electNewYAxisOwner(C0$);}C0$=s4M.addYAxis(o35,new j6q.ChartEngine.YAxis(g3c));if(H7m){o35.yAxis=C0$;}}}else {C0$.position=S9A;}return C0$;}if(S9A){x6r=s4M.getYAxisByName(o35,S9A);if(x6r && C0$ == o35.yAxis && !C0$.isShared(s4M)){o35.yAxis=x6r;}if(C0$ && C0$.isShared(s4M)){C0$.name=s4M.electNewYAxisOwner(C0$);}else {if(C0$ !== o35.yAxis){s4M.deleteYAxisIfUnused(o35,C0$);}}return x6r;}if(C0$){if(C0$.isShared(s4M)){C0$.name=s4M.electNewYAxisOwner(C0$);}else {delete C0$.position;if(C0$ !== o35.yAxis){s4M.deleteYAxisIfUnused(o35,C0$);}}}s4M.resizeChart();return o35.yAxis;};j6q.Studies.calculateVolume=function(w0v,V45){var v3L,A3f,x_f;if(V45.type == "vol undr"){if(!w0v || !w0v.chart.dataSet){return;}v3L=w0v.layout;A3f=V45.parameters.removeStudy;x_f=v3L.volumeUnderlay;v3L.volumeUnderlay=!A3f;if(x_f != v3L.volumeUnderlay){w0v.changeOccurred("layout");}if(A3f){j6q.Studies.removeStudy(w0v,V45);}}V45.outputMap={};V45.outputMap.Volume="";};j6q.Studies.MA=function(v$L,T$s,o$T,B4X,p$R,U0L,J54,j5b){var P2t;P2t=new j6q.Studies.StudyDescriptor(p$R + " " + J54.name,"ma",J54.panel);P2t.chart=J54.chart;P2t.days=parseInt(T$s,10);P2t.startFrom=J54.startFrom;if(j5b){P2t.subField=j5b;}A2IFV.D0H();P2t.inputs={};if(v$L){P2t.inputs.Type=v$L;}if(o$T){P2t.inputs.Field=o$T;}if(B4X){P2t.inputs.Offset=parseInt(B4X,10);}j6q.Studies.calculateMovingAverage(U0L,P2t);};j6q.Studies.movingAverage={conversions:{ma:"simple",sma:"simple",ema:s1q,tma:"triangular",vdma:"vidya",wma:"weighted",smma:"welles wilder"},translations:{simple:"Simple",exponential:"Exponential",triangular:i2v,vidya:"VIDYA",weighted:I$$,"welles wilder":t05},typeMap:{ema:q1N,exponential:i3c,tma:"Triangular",triangular:W9k,vdma:"VIDYA",vidya:"VIDYA",wma:"Weighted",weighted:"Weighted",smma:"Exponential","welles wilder":S9B}};j6q.Studies.movingAverageHelper=function(o1M,F35){A2IFV.D0H();var i8u;if(F35 == "options"){i8u={};for(var T2f in j6q.Studies.movingAverage.translations){i8u[T2f]=o1M.translateIf(j6q.Studies.movingAverage.translations[T2f]);}return i8u;}return j6q.Studies.movingAverage.conversions[F35];};j6q.Studies.createVolumeChart=function(m1I,t5Z,j7T){var d04=A2IFV;var r4o,j5W,u4J,l_E,n3W,q8_,s8c,N_4,t6n,x8t,l7m,n5D,M0e,H4W,o0s,C4O,g07,h5N;r4o="_";r4o+="up";j5W="V";j5W+="olu";j5W+="m";j5W+="e";u4J="colo";u4J+="r";l_E="s";l_E+="tx_volume";n3W=t5Z.panel;q8_=t5Z.inputs;s8c=t5Z.underlay;N_4=t5Z.overlay;t6n=s8c || N_4;x8t=j6q.Studies.determineColor(t5Z.outputs["Up Volume"]);l7m=j6q.Studies.determineColor(t5Z.outputs["Down Volume"]);n5D=s8c?"stx_volume_underlay":l_E;d04.D0J(0);m1I.setStyle(d04.S40(n5D,"_up"),"color",x8t);d04.H6P(0);m1I.setStyle(d04.S40(n5D,"_down"),u4J,l7m);M0e=[{field:t5Z.volumeField || j5W,fill_color_up:m1I.canvasStyle(n5D + r4o).color,border_color_up:m1I.canvasStyle(n5D + "_up").borderLeftColor,opacity_up:m1I.canvasStyle(n5D + "_up").opacity,fill_color_down:m1I.canvasStyle(n5D + "_down").color,border_color_down:m1I.canvasStyle(n5D + "_down").borderLeftColor,opacity_down:m1I.canvasStyle(n5D + "_down").opacity,color_function:t5Z.colorFunction}];H4W=M0e[0];if(!s8c && H4W.border_color_down === "rgb(184, 44, 12)"){o0s="#";o0s+="00";o0s+="00";o0s+="00";C4O="#0";C4O+="0";C4O+="00";C4O+="00";H4W.border_color_down=C4O;H4W.border_color_up=o0s;}g07=t5Z.getYAxis(m1I);h5N={name:"Volume",panel:n3W,yAxis:g07,widthFactor:"1" << 64,bindToYAxis:!"",highlight:t5Z.highlight};j6q.extend(h5N,t5Z.study.parameters);j6q.extend(h5N,t5Z.parameters);if(m1I.colorByCandleDirection && !t5Z.colorFunction){H4W.color_function=function(o$d){var g5B,O6x;g5B=o$d.Open;O6x=o$d.Close;return {fill_color:g5B > O6x?H4W.fill_color_down:H4W.fill_color_up,border_color:g5B > O6x?H4W.border_color_down:H4W.border_color_up,opacity:g5B > O6x?H4W.opacity_down:H4W.opacity_up};};}m1I.drawHistogram(h5N,M0e);};j6q.Studies.calculateStandardDeviation=function(w0$,I9E){var M8s=A2IFV;M8s.a9S();var y8D,P7X,i4F,X4D,q5y,j5s,T79,A_j,Q3o,r3M,D_i,u_p,q_9,N6H;y8D=I9E.chart.scrubbed;if(y8D.length < I9E.days + 1){I9E.error=!![];return;}P7X=I9E.inputs.Field;if(!P7X || P7X == "field"){P7X="Close";}i4F=I9E.inputs["Moving Average Type"];if(!i4F){i4F=I9E.inputs.Type;}j6q.Studies.MA(i4F,I9E.days,P7X,I9E.inputs.Offset,"_MA",w0$,I9E);X4D=0;q5y=+"0";j5s=0;T79=Number(I9E.inputs["Standard Deviations"]);if(T79 < 0){T79=2;}A_j=I9E.name;for(var b_j in I9E.outputs){M8s.H6P(37);A_j=M8s.S40(A_j,b_j,(+"2690",4480) < 2760?("S",454.54):" ");}for((Q3o=I9E.startFrom - 1,D_i=0);Q3o >= 0 && D_i < I9E.days;(Q3o--,D_i++)){r3M=y8D[Q3o][P7X];if(r3M && typeof r3M == "object"){r3M=r3M[I9E.subField];}if(isNaN(r3M)){r3M=0;}X4D+=Math.pow(r3M,2);q5y+=r3M;}for(Q3o=I9E.startFrom;Q3o < y8D.length;Q3o++){u_p="_M";u_p+="A";u_p+=" ";q_9=y8D[Q3o];r3M=q_9[P7X];if(r3M && typeof r3M == "object"){r3M=r3M[I9E.subField];}if(!r3M && r3M !== 0){r3M=0;}X4D+=Math.pow(r3M,+"2");q5y+=r3M;if(Q3o < I9E.days - 1)continue;if(Q3o >= I9E.days){N6H=y8D[Q3o - I9E.days][P7X];if(N6H && typeof N6H == "object"){N6H=N6H[I9E.subField];}if(isNaN(N6H)){N6H=0;}X4D-=Math.pow(N6H,+"2");q5y-=N6H;}j5s=q_9[u_p + I9E.name];if(j5s || j5s === 0){M8s.D0J(122);var t0k=M8s.q7n(20,19,0,4,54);M8s.D0J(16);var u8N=M8s.q7n(2,4);q_9[A_j]=Math.sqrt((X4D + I9E.days * Math.pow(j5s,t0k) - u8N * j5s * q5y) / I9E.days) * T79;}}};j6q.Studies.calculateMovingAverage=function(W4v,O3s){var g7M,Q6T,a41,V6n,u6K,K8m,j0y,A7$,F6e,U5R,s5D,I7X,x3G,l5u,V8s,B5U,h$n,R8z,h_B,L73,n12;g7M="Clos";g7M+="e";if(!O3s.chart.scrubbed){return;}Q6T=O3s.inputs.Type;if(Q6T == "ma" || Q6T == "sma" || !Q6T){Q6T="simple";}a41=j6q.Studies.movingAverage.typeMap;A2IFV.a9S();if((Q6T in a41)){return j6q.Studies["calculateMovingAverage" + a41[Q6T]](W4v,O3s);}else if(Q6T !== "simple"){return;}V6n=O3s.chart.scrubbed;u6K=0;K8m=[];j0y=O3s.name;for(var I9q in O3s.outputs){A2IFV.D0J(37);j0y=A2IFV.q7n(j0y,I9q,(528.04,7840) < 269.57?(677.22,!!"1"):" ");}A7$=O3s.inputs.Field;if(!A7$ || A7$ == "field"){A7$=g7M;}F6e=parseInt(O3s.inputs.Offset,10);if(isNaN(F6e)){F6e=0;}x3G=O3s.startFrom;l5u=F6e;for(U5R=O3s.startFrom - +"1";U5R >= 0;U5R--){V8s="obj";V8s+="e";V8s+="c";V8s+="t";s5D=V6n[U5R][A7$];if(s5D && typeof s5D == V8s){s5D=s5D[O3s.subField];}if(!s5D && s5D !== 0)continue;if(l5u > 0){l5u--;x3G=U5R;continue;}if(K8m.length == O3s.days - 1)break;u6K+=s5D;K8m.unshift(s5D);}if(K8m.length < O3s.days - 1){K8m=[];x3G=0;;}B5U=[];for(U5R=x3G;U5R < V6n.length;U5R++){h$n="o";h$n+="bject";R8z=V6n[U5R];s5D=R8z[A7$];if(s5D && typeof s5D == h$n){s5D=s5D[O3s.subField];}h_B=U5R + F6e >= 0 && U5R + F6e < V6n.length;L73=h_B?V6n[U5R + F6e]:null;if(!s5D && s5D !== 0){if(L73){L73[j0y]=null;}else if(U5R + F6e >= V6n.length){I7X={};I7X[j0y]=null;B5U.push(I7X);}continue;}u6K+=s5D;K8m.push(s5D);if(K8m.length > O3s.days){u6K-=K8m.shift();}n12=K8m.length == O3s.days?u6K / O3s.days:null;if(L73){L73[j0y]=n12;}else if(U5R + F6e >= V6n.length){I7X={};I7X[j0y]=n12;B5U.push(I7X);}}O3s.appendFutureTicks(W4v,B5U);};j6q.Studies.calculateMovingAverageExponential=function(E24,y3b){var V1c=A2IFV;var f$V,O$m,l2L,W96,c_y,A4m,L$V,j1$,E4C,T6H,v1q,D8f,G7A,Q6i,M$T,w4v,i8v,B1M,L6u,t6j,X$H,d8b,k3K,U87;f$V=y3b.inputs.Type;O$m=y3b.chart.scrubbed;l2L=0;W96=0;c_y=0;V1c.H6P(11);var Y9k=V1c.S40(32,13,178,4);V1c.D0J(123);var p_U=V1c.S40(4,2,19,8);A4m=Y9k / (y3b.days + p_U);if(f$V === "welles wilder" || f$V === "smma"){V1c.H6P(19);var I1P=V1c.S40(18,17,2,36);A4m=I1P / y3b.days;}L$V=null;j1$=y3b.name;for(var z0a in y3b.outputs){V1c.H6P(37);j1$=V1c.q7n(j1$,z0a,531.97 >= (5452,1650)?(176.83,"6550" * 1) <= 312.28?(8.76e+3,"G"):3467 != 775.98?670.67:0x236e:" ");}E4C=y3b.inputs.Field;if(!E4C || E4C == "field"){E4C="Close";}T6H=parseInt(y3b.inputs.Offset,10);if(isNaN(T6H)){T6H=0;}G7A=y3b.startFrom;Q6i=T6H;for(v1q=y3b.startFrom - 1;v1q >= 0;v1q--){D8f=O$m[v1q][j1$];if(!D8f && D8f !== 0)continue;if(L$V === null){L$V=D8f;}c_y=y3b.days;if(Q6i <= 0)break;Q6i--;G7A=v1q;}if(L$V === null){M$T=-431256440;w4v=1650909003;i8v=2;for(var L86=1;V1c.Z2Z(L86.toString(),L86.toString().length,"52360" >> 64) !== M$T;L86++){L$V=G7A=6;i8v+=2;}if(V1c.U6$(i8v.toString(),i8v.toString().length,284) !== w4v){L$V=G7A=6;}L$V=G7A=0;}B1M=[];V1c.a9S();for(v1q=G7A;v1q < O$m.length;v1q++){L6u="obje";L6u+="ct";t6j=O$m[v1q];D8f=t6j[E4C];if(D8f && typeof D8f == L6u){D8f=D8f[y3b.subField];}X$H=v1q + T6H >= 0 && v1q + T6H < O$m.length;d8b=X$H?O$m[v1q + T6H]:null;if(!D8f && D8f !== 0){k3K=null;}else {if(c_y == y3b.days - +"1"){l2L+=D8f;W96=l2L / y3b.days;k3K=W96;}else if(c_y < y3b.days - 1){l2L+=D8f;V1c.H6P(124);W96=V1c.q7n(1,c_y,l2L);k3K=null;}else if(c_y === 0){l2L+=D8f;W96=l2L;k3K=null;}else if(L$V || L$V === 0){V1c.H6P(125);W96=V1c.q7n(A4m,D8f,L$V,L$V);k3K=W96;}L$V=W96;c_y++;}if(d8b){d8b[j1$]=k3K;}else if(v1q + T6H >= O$m.length){U87={};U87[j1$]=k3K;B1M.push(U87);}}y3b.appendFutureTicks(E24,B1M);};j6q.Studies.calculateMovingAverageVIDYA=function(T25,v0M){var e31=A2IFV;var h1V,D2c,g$k,w9x,L0u,s2G,H7q,u_5,d4M,E44,K6h,R_l,g73,Y4b,H3v,N7n,d$v,i5B,N0z,K$m,v42;h1V="_M";h1V+="A";h1V+="ST";h1V+="D";D2c="sd";D2c+="ev";g$k=v0M.inputs.Type;w9x=v0M.chart.scrubbed;e31.D0J(126);var t3d=e31.S40(94,15,6,5,5);L0u=t3d / (v0M.days + +"1");s2G=null;H7q=v0M.name;for(var h0r in v0M.outputs){e31.H6P(37);H7q=e31.S40(H7q,h0r," ");}u_5=v0M.inputs.Field;if(!u_5 || u_5 == "field"){u_5="Close";}v0M.std=new j6q.Studies.StudyDescriptor(v0M.name,D2c,v0M.panel);v0M.std.chart=v0M.chart;v0M.std.days=5;v0M.std.startFrom=v0M.startFrom;v0M.std.inputs={Field:u_5,"Standard Deviations":1,Type:"ma"};v0M.std.outputs={_STD:null};j6q.Studies.calculateStandardDeviation(T25,v0M.std);j6q.Studies.MA("ma",20,"_STD " + v0M.name,0,h1V,T25,v0M);d4M=parseInt(v0M.inputs.Offset,10);if(isNaN(d4M)){d4M=0;}g73=v0M.startFrom;Y4b=d4M;for(E44=v0M.startFrom - 1;E44 >= 0;E44--){K6h=w9x[E44][H7q];if(!K6h && K6h !== 0)continue;if(s2G === null){s2G=K6h;}if(Y4b <= 0)break;Y4b--;g73=E44;}if(s2G === null){s2G=g73=0;}H3v=[];for(E44=g73;E44 < w9x.length;E44++){N7n="o";N7n+="b";N7n+="jec";N7n+="t";d$v=w9x[E44];K6h=d$v[u_5];if(K6h && typeof K6h == N7n){K6h=K6h[v0M.subField];}i5B=E44 + d4M >= 0 && E44 + d4M < w9x.length;N0z=i5B?w9x[E44 + d4M]:null;if(!K6h && K6h !== 0){if(N0z){N0z[H7q]=null;}else if(E44 + d4M >= w9x.length){R_l={};R_l[H7q]=null;H3v.push(R_l);}continue;}if(!d$v["_MASTD " + v0M.name] && d$v["_MASTD " + v0M.name] !== 0)continue;K$m=d$v["_STD " + v0M.name] / d$v["_MASTD " + v0M.name];e31.H6P(127);v42=e31.q7n(K6h,K$m,K$m,L0u,L0u,1,s2G);s2G=v42;if(E44 < v0M.days){v42=null;}if(N0z){N0z[H7q]=v42;}else if(E44 + d4M >= w9x.length){R_l={};R_l[H7q]=v42;H3v.push(R_l);}}v0M.appendFutureTicks(T25,H3v);};j6q.Studies.calculateMovingAverageTriangular=function(f2i,X6P){var k6B=A2IFV;var J64,c8n,C2f,u$n,U7D,g3R,J2E,q6X,t0f,F7J,y5U,J7$;J64="T";k6B.D0H();J64+="R";J64+="I";J64+="2";c8n="T";c8n+="RI";c8n+="1 ";C2f="f";C2f+="ield";u$n=X6P.chart.scrubbed;U7D=X6P.inputs.Field;if(!U7D || U7D == C2f){U7D="Close";}g3R=Math.ceil(X6P.days / 2);j6q.Studies.MA("simple",g3R,U7D,0,"TRI1",f2i,X6P);if(X6P.days % 2 === 0){g3R++;}j6q.Studies.MA("simple",g3R,c8n + X6P.name,"0" | 0,J64,f2i,X6P);J2E=X6P.name;for(var w9i in X6P.outputs){k6B.D0J(37);J2E=k6B.S40(J2E,w9i," ");}q6X=parseInt(X6P.inputs.Offset,10);if(isNaN(q6X)){k6B.D0J(40);q6X=k6B.S40(0,"0");}t0f=q6X;for(var u_b=X6P.startFrom - 1;u_b >= 0;u_b--){F7J=u$n[u_b][J2E];if(!F7J && F7J !== 0)continue;if(t0f > 0){t0f--;continue;}break;}y5U=[];for(u_b++;u_b < u$n.length;u_b++){if(u_b + q6X >= 0){if(u_b + q6X < u$n.length){k6B.H6P(0);u$n[k6B.S40(u_b,q6X)][J2E]=u$n[u_b]["TRI2 " + X6P.name];}else {J7$={};J7$[J2E]=u$n[u_b]["TRI2 " + X6P.name];y5U.push(J7$);}}}X6P.appendFutureTicks(f2i,y5U);};j6q.Studies.calculateMovingAverageWeighted=function(P8w,D2r){var L2_=A2IFV;var n9l,L1z,l5I,S0i,A7h,y4N,C2F,D1i,y5I,j6S,B7D,g6u,J6b,c43,t93,o_G,X3m,q86,K9a;n9l=D2r.chart.scrubbed;L1z=0;l5I=0;S0i=D2r.inputs.Field;if(!S0i || S0i == "field"){S0i="Close";}L2_.H6P(39);var o8C=L2_.q7n(12,8,3);L2_.D0J(7);var Z1v=L2_.S40(12,14);A7h=D2r.days * (D2r.days + o8C) / Z1v;y4N=D2r.name;for(var E_d in D2r.outputs){L2_.H6P(37);y4N=L2_.S40(y4N,E_d,4530 !== 726.05?(858.91,888.55) <= (2586,964.86)?" ":61.37 <= 3330?0x1937:(+"124.27",0x3b6):(135.18,170.12));}C2F=parseInt(D2r.inputs.Offset,10);if(isNaN(C2F)){C2F=0;}L2_.D0H();B7D=[];g6u=D2r.startFrom;J6b=C2F;for(D1i=D2r.startFrom - 1;D1i >= 0;D1i--){y5I=n9l[D1i][S0i];if(y5I && typeof y5I == "object"){y5I=y5I[D2r.subField];}if(!y5I && y5I !== ("0" ^ 0))continue;if(J6b > 0){J6b--;g6u=D1i;continue;}if(B7D.length == D2r.days - 1)break;B7D.unshift(y5I);}if(B7D.length < D2r.days - ("1" ^ 0)){B7D=[];g6u=0;;}for(D1i=0;D1i < B7D.length;D1i++){L2_.D0J(123);var f$w=L2_.q7n(7,7,55,7);L1z+=(D1i + f$w) * B7D[D1i];l5I+=B7D[D1i];}c43=[];for(D1i=g6u;D1i < n9l.length;D1i++){t93="obj";t93+="e";t93+="ct";o_G=n9l[D1i];y5I=o_G[S0i];if(y5I && typeof y5I == t93){y5I=y5I[D2r.subField];}X3m=D1i + C2F >= 0 && D1i + C2F < n9l.length;q86=X3m?n9l[D1i + C2F]:null;if(!y5I && y5I !== 0){if(q86){q86[y4N]=null;}else if(D1i + C2F >= n9l.length){j6S={};j6S[y4N]=null;c43.push(j6S);}continue;}B7D.push(y5I);if(B7D.length > D2r.days){L1z-=l5I;l5I-=B7D.shift();}L1z+=B7D.length * y5I;l5I+=y5I;K9a=D1i < D2r.days - 1?null:L1z / A7h;if(q86){q86[y4N]=K9a;}else if(D1i + C2F >= n9l.length){j6S={};j6S[y4N]=K9a;c43.push(j6S);}}D2r.appendFutureTicks(P8w,c43);};j6q.Studies.calculateStudyATR=function(Q4c,a5o){var Q4J=A2IFV;var i_A,o2C,K8Z,q$_,W9D,E$t,z_J,w5u,u8$,g3M;i_A=a5o.chart.scrubbed;o2C=a5o.days;if(i_A.length < o2C + 1){a5o.error=!!({});return;}K8Z=0;Q4J.D0H();q$_=a5o.name;for(var c3m=Math.max(a5o.startFrom,1);c3m < i_A.length;c3m++){W9D="A";W9D+="TR";W9D+=" ";E$t="AT";E$t+="R ";z_J="True";z_J+=" ";z_J+="Range";z_J+=" ";w5u=i_A[c3m];Q4J.H6P(7);u8$=i_A[Q4J.q7n(1,c3m)];g3M=w5u.trueRange;if(u8$["Sum True Range " + q$_]){Q4J.H6P(0);K8Z=u8$[Q4J.q7n("Sum True Range ",q$_)];}K8Z+=g3M;if(c3m > o2C){Q4J.D0J(7);K8Z-=i_A[Q4J.q7n(o2C,c3m)][Q4J.q7n("True Range ",q$_,Q4J.D0J(0))];}Q4J.H6P(0);w5u[Q4J.S40(z_J,q$_)]=g3M;Q4J.H6P(0);w5u[Q4J.q7n("Sum True Range ",q$_)]=K8Z;if(c3m == o2C){Q4J.H6P(0);w5u[Q4J.q7n(E$t,q$_)]=Q4J.S40(o2C,K8Z,Q4J.H6P(14));}else if(c3m > o2C){Q4J.D0J(0);w5u[Q4J.q7n("ATR ",q$_)]=(u8$[W9D + q$_] * (o2C - 1) + g3M) / o2C;}}};j6q.Studies.displayPSAR2=function(y8P,Q4R,x2l){var A4s=A2IFV;var Z52,t0u,o8t,n_o,d29,g5n,l0a,Z4h,t_o,G65,O1Z,V1L,N8k,R_d;Z52=y8P.panels[Q4R.panel];t0u=Q4R.getYAxis(y8P);o8t=t0u == y8P.chart.panel.yAxis;y8P.startClip(Z52.name);n_o=Q4R.getContext(y8P);d29=Q4R.inputs["Plot Type"] == "squarewave";for(var W9z in Q4R.outputs){g5n="a";g5n+="u";g5n+="t";g5n+="o";A4s.H6P(0);var P3o=A4s.q7n(2645,7);A4s.D0J(19);var W2I=A4s.S40(54560,8,6,47754);A4s.D0J(0);var m6A=A4s.q7n(9262,8);A4s.D0J(62);var L6T=A4s.q7n(4,3270,10,1090);A4s.H6P(18);var e5E=A4s.S40(17808,1,11872);l0a=W9z + ((P3o,442.57) > (W2I,m6A)?(965.45,L6T) != 275.62?(779.78,!1):(e5E,"x"):" ") + Q4R.name;n_o.beginPath();Z4h=y8P.layout.candleWidth;t_o=Math.max(3,Math.floor(y8P.chart.tmpWidth / 2));for(var i$t=0;i$t < x2l.length;i$t++){G65=x2l[i$t];if(!G65 || !G65[l0a] && G65[l0a] !== 0)continue;if(G65.candleWidth){Z4h=G65.candleWidth;}if(o8t && G65.transform){G65=G65.transform;}O1Z=y8P.pixelFromBar(i$t,Z52.chart);if(d29){A4s.D0J(14);O1Z-=A4s.S40(2,Z4h);}V1L=y8P.pixelFromTransformedValue(G65[Q4R.referenceOutput?Q4R.referenceOutput + ((6850,6821) >= 2720?(940.09,2090) !== 1125?+"796" < 889.08?" ":"F":958.27:"K") + Q4R.name:l0a],Z52,t0u);if(i$t === +"0" || !x2l[i$t - +"1"] || !x2l[i$t - 1][l0a] && x2l[i$t - +"1"][l0a] !== 0){n_o.moveTo(O1Z,V1L);}if(d29){n_o.lineTo(O1Z,V1L);A4s.H6P(0);n_o.lineTo(A4s.q7n(O1Z,Z4h),V1L);if(x2l[i$t + 1]){A4s.H6P(0);N8k=x2l[A4s.S40(i$t,1)];if(o8t && N8k.transform){N8k=N8k.transform;}if(!N8k[l0a] && N8k[l0a] !== 0){A4s.H6P(0);n_o.lineTo(A4s.q7n(O1Z,Z4h),y8P.pixelFromTransformedValue(N8k[Q4R.referenceOutput?Q4R.referenceOutput + (756.3 < 5063?(8350,"8497" << 64) >= (4579,297.37)?" ":(265.69,6.71e+3):!({})) + Q4R.name:l0a],y8P.panels[Q4R.panel],t0u));}}}else {A4s.H6P(128);n_o.moveTo(A4s.q7n(O1Z,"2",t_o),V1L);A4s.H6P(129);n_o.lineTo(A4s.S40(t_o,"2",O1Z,64),V1L);}}n_o.lineWidth=1;if(Q4R.highlight){n_o.lineWidth=3;}R_d=j6q.Studies.determineColor(Q4R.outputs[W9z]);if(R_d == g5n){R_d=y8P.defaultColor;}n_o.strokeStyle=R_d;if(!Q4R.highlight && y8P.highlightedDraggable){n_o.globalAlpha*=0.3;}n_o.stroke();n_o.closePath();n_o.lineWidth=1;}y8P.endClip();};j6q.Studies.inputAttributeDefaultGenerator=function(e2x){if(!e2x && e2x !== 0){return {};}if(e2x.constructor == Number){if(Math.floor(e2x) == e2x){if(e2x > 0){return {min:1,step:1};}return {step:"1" << 64};;}if(e2x > 0){return {min:0,step:0.01};}return {step:0.01};;}return {};};j6q.Studies.getMarketOffset=function({stx:q7A, localQuoteDate:d2f, shiftToDateBoundary:W5w}){var Q2b=A2IFV;var D2B,g$3,O5B,v3c,r3i,G5f,f8_;D2B="U";D2B+="TC";if(arguments.length > 1){q7A=arguments[0];d2f=arguments[1];g$3=arguments[2];}var {symbol:z5s}=q7A.chart;O5B=j6q.getFn("Market.Symbology.isForexMetal")(z5s);if(g$3 === undefined){v3c="Market.Symbolog";v3c+="y.isForexSymbol";g$3=j6q.getFn(v3c)(z5s);}if(!q7A.chart.market){r3i=null;}else {r3i=g$3?"America/New_York":q7A.chart.market.market_tz;}Q2b.D0J(33);var M75=Q2b.S40(14,60009,8,13);G5f=new Date(d2f.getTime() + d2f.getTimezoneOffset() * M75);if(!r3i || r3i.indexOf("UTC") == -1){G5f=j6q.convertTimeZone(G5f,D2B,r3i);}f8_=new Date(G5f.getFullYear(),G5f.getMonth(),G5f.getDate(),G5f.getHours(),G5f.getMinutes(),G5f.getSeconds(),G5f.getMilliseconds()).getTime() - d2f.getTime();if(W5w && g$3){Q2b.H6P(130);f8_+=Q2b.S40("60",O5B?6:+"7",1000,"60");}return f8_;};j6q.Studies.getStudyList=function(N9R){var l2x,x74;l2x={};x74={};j6q.extend(x74,N9R);A2IFV.a9S();for(var A6L in j6q.Studies.studyLibrary){if(!x74[A6L]){l2x[j6q.Studies.studyLibrary[A6L].name]=A6L;}}return l2x;};j6q.Studies.determineColor=function(z7u){var R5X;R5X="ob";R5X+="j";R5X+="e";R5X+="ct";if(!z7u){return null;}else if(typeof z7u === R5X){return z7u.color;}return z7u;};j6q.Studies.calculateGenericEnvelope=function(m_S,l$9,r67,W5F,Y1Q,Y93){var K8E=A2IFV;var I_9,S$r,h6x,G$p,z4U,t3U,V3I,e8M,D52;I_9="f";I_9+="i";I_9+="e";I_9+="ld";if(!r67){r67=0;}if(!Y93){Y93=0;}if(!W5F || W5F == "field"){W5F="Close";}if(!Y1Q){Y1Q=W5F;}S$r=l$9.chart.scrubbed;h6x=l$9.inputs.Field;if(!h6x || h6x === I_9){h6x="Close";}for(var W1I=l$9.startFrom;S$r && W1I < S$r.length;W1I++){G$p="Band";G$p+="w";G$p+="idth";G$p+=" ";z4U=S$r[W1I];if(!z4U)continue;if(!z4U[W5F])continue;t3U=z4U[h6x];if(t3U && typeof t3U == "object"){t3U=t3U.Close;}V3I=z4U[W5F];if(V3I && typeof V3I == "object"){V3I=V3I[l$9.subField];}e8M=z4U[Y1Q];if(e8M && typeof e8M == "object"){e8M=e8M[l$9.subField];}K8E.D0J(32);D52=K8E.S40(Y93,e8M,r67);K8E.H6P(0);z4U[l$9.type + " Top " + l$9.name]=K8E.S40(V3I,D52);K8E.D0J(7);z4U[l$9.type + " Bottom " + l$9.name]=K8E.S40(D52,V3I);z4U[l$9.type + " Median " + l$9.name]=V3I;z4U[G$p + l$9.name]=V3I?200 * D52 / V3I:"0" | 0;K8E.D0J(131);z4U["%b " + l$9.name]=K8E.S40(50,1,t3U,V3I,D52);}};j6q.Studies.displayChannel=function(r6w,H9C,p5B){A2IFV.D0H();var Z1B,b45,H$o,d5W,m56;Z1B="C";Z1B+="h";Z1B+="an";Z1B+="nel Fill";if(H9C.inputs[Z1B]){b45={panelName:H9C.panel};for(var D0Z in H9C.outputs){H$o="Bo";H$o+="tt";H$o+="om";d5W=D0Z.split(6480 >= 325.28?" ":(1160,258) !== (6870,"832.56" * 1)?(320.14,941.60):1.41e+2).pop();if(d5W == "Top" || d5W == "High"){b45.topBand=D0Z + " " + H9C.name;}else if(d5W == H$o || d5W == "Low"){b45.bottomBand=D0Z + " " + H9C.name;}else if(d5W == "Median" || d5W == "Channel"){b45.color=j6q.Studies.determineColor(H9C.outputs[D0Z]);}}if(H9C.parameters && H9C.parameters.opacity){b45.opacity=H9C.parameters.opacity;}else {b45.opacity=0.2;}m56=r6w.panels[H9C.panel];b45.skipTransform=m56.name != H9C.chart.name;b45.yAxis=H9C.getYAxis(r6w);if(!H9C.highlight && r6w.highlightedDraggable){b45.opacity*=0.3;}j6q.prepareChannelFill(r6w,b45);}j6q.Studies.displaySeriesAsLine(r6w,H9C,p5B);};j6q.Studies.initAnchorHandle=function(n1t,w5T){var {handle:O7X}=w5T;A2IFV.D0H();if(O7X){return;}if(!n1t.controls.anchorHandles){n1t.controls.anchorHandles={};}if(n1t.controls.anchorHandles[w5T.uniqueId]){({handle:O7X}=n1t.controls.anchorHandles[w5T.uniqueId]);}else {O7X=document.createElement("div");O7X.classList.add("stx_anchor_handle");O7X.setAttribute(w5T.uniqueId,"");n1t.controls.anchorHandles[w5T.uniqueId]={handle:O7X,sd:w5T};n1t.controls.chartControls.parentElement.appendChild(O7X);}w5T.anchorHandle=O7X;};j6q.Studies.removeAnchorHandle=function(D_c,R2m){var {handle:c5i}=(D_c.controls.anchorHandles || ({}))[R2m.uniqueId] || ({});if(c5i){delete D_c.controls.anchorHandles[R2m.uniqueId];c5i.remove();}};j6q.Studies.repositionAnchor=function(P$O,o_o){var U4i,f5M,L4k,N9Z,X8s,I1y,B12,k8u,X7B;var {currentAnchorTime:q9V, uniqueId:B2e}=o_o;var {hoverTick:L7j}=P$O.repositioningAnchorSelector || ({});var {dataSet:d_N, market:y$n}=P$O.chart;var {anchorHandles:Q8Z}=P$O.controls;U4i={};A2IFV.a9S();if(L7j || L7j === 0){f5M="HH";f5M+=":m";f5M+="m:s";f5M+="s";L4k="Anchor ";L4k+="Date";if(L7j >= d_N.length){return;}N9Z=!o_o.inputs[L4k];X8s=d_N[L7j].DT;I1y=j6q.Studies.getMarketOffset({stx:P$O,localQuoteDate:X8s,shiftToDateBoundary:!0});if(N9Z && new Date(X8s.getTime() + I1y).getDate() !== new Date(q9V.getTime() + I1y).getDate()){return;}if(y$n.market_def){X8s=new W7j.Date(X8s,y$n.market_def.market_tz);}B12=!N9Z && j6q.dateToStr(X8s,"YYYY-MM-dd");k8u=j6q.dateToStr(X8s,f5M);U4i={"Anchor Time":k8u};if(B12){U4i["Anchor Date"]=B12;}}X7B=j6q.Studies.replaceStudy(P$O,o_o.inputs.id,o_o.type,Object.assign(o_o.inputs,U4i),o_o.outputs,o_o.parameters,o_o.panel);Q8Z[B2e].sd=X7B;P$O.draw();};j6q.Studies.displayAnchorHandleAndLine=function(J3A,R$W,u_n){var J9A=A2IFV;var G7S,q5F,W6_,e0d,i$6,K5a,z2x,U4I,u1x,s7w,W1C,n3o,V4t,F_W,T9K,K5U;G7S=(J3A.repositioningAnchorSelector || ({})).sd === R$W;var {hoverTick:s67}=G7S && J3A.repositioningAnchorSelector;var {chart:V2N, panels:a$k, xaxisHeight:y54}=J3A;var {market:W0T = {}, symbol:g2E}=V2N;q5F=a$k[R$W.panel];var {top:M2t, bottom:r_p, right:U$T, left:P2b, height:N$H}=q5F;var {inputs:Q3m, anchorHandle:K4J, currentAnchorTime:f0q}=R$W;var {backgroundColor:A2Q, borderLeftColor:z3P}=J3A.canvasStyle("stx_anchor_handle");var [w1I,a_4,d50 = +"0"]=(Q3m["Anchor Time"] || "").split(":");W6_=!Q3m["Anchor Date"];e0d=j6q.getFn("Market.Symbology.isForexSymbol")(g2E);i$6=(s67 || s67 === 0) && (J3A.chart.dataSet[s67] || ({})).DT;K5a=j6q.Studies.getMarketOffset({stx:J3A,localQuoteDate:u_n[u_n.length - +"1"].DT,shiftToDateBoundary:!![]});z2x=i$6 && W6_ && new Date(i$6.getTime() + K5a).getDate() !== new Date(f0q.getTime() + K5a).getDate();var {highlighted:P$p}=J3A.controls.anchorHandles[R$W.uniqueId];var [U9i,O4m]=W0T.getNormalOpen().split(6958 !== ("483" ^ 0)?(367.59,3068) < (4953,867.97)?(655.31,405.05) >= 934?(![],968.63):(0xb3f,2.96e+3):":":(![],438.72)).map(U3V=>{J9A.D0H();return parseInt(U3V);});U4I=e0C=>{var q$8;q$8=e0C?J3A.tickFromDate(e0C,null,null,!!({})):s67;J9A.a9S();return [J3A.pixelFromTick(q$8,V2N),q$8];};u1x=W6_?new Date(u_n[u_n.length - "1" * 1].DT):j6q.strToDate(Q3m["Anchor Date"]);if(W0T.market_def){u1x=new W7j.Date(u1x,W0T.market_def.market_tz);}u1x.setHours(w1I,a_4,d50);s7w=e0d && (u1x.getHours() > U9i || u1x.getHours() === U9i && u1x.getMinutes() >= O4m);if(s7w){u1x.setDate(u1x.getDate() - 1);}var [Z6C]=U4I();var [u3x,b1a]=U4I(u1x);W1C=new Date(u1x);W1C.setHours(...W0T.getNormalClose().split((415.47,"661.86" * 1) <= "1960" >> 0?191.13 !== 4218?":":1890 == 2430?"M":("0x121a" | 24,!!({})):!!"1"));if(s7w){W1C.setDate(W1C.getDate() + 1);}var [Q4u]=W1C && U4I(W1C) || [];if(W6_ && (u3x > U$T || Q4u > U$T)){n3o=new Date(u1x);do {n3o.setDate(n3o.getDate() - 1);}while(W0T && !W0T.isMarketDate(n3o));var [Y4R,t_q]=U4I(n3o);if(Y4R > P2b){u1x=n3o;u3x=Y4R;b1a=t_q;}}V4t={y0:M2t,y1:r_p,type:"line",confineToPanel:q5F};J3A.plotLine(Object.assign(V4t,{x0:u3x,x1:u3x,color:A2Q,pattern:"solid",lineWidth:P$p?3:"2" << 96,opacity:1}));J3A.plotLine(Object.assign(V4t,{x0:Z6C,x1:Z6C,color:z2x?z3P:A2Q,pattern:[6,+"6"],lineWidth:2,opacity:z2x?0.5:1}));J9A.D0J(132);var t1w=J9A.S40(100,12,17,7,1);K4J.style.height=[8,N$H / 4,"50" - 0].sort((V7C,Q0K)=>{J9A.D0J(7);J9A.D0H();return J9A.q7n(Q0K,V7C);})[t1w] + "px";var {height:Y6q, width:I3B}=K4J.getBoundingClientRect();F_W=Math.round(r_p) === J3A.height?y54:0;T9K=q5F.name === "chart"?35:+"0";J9A.H6P(48);K5U=J9A.q7n(Y6q,T9K,F_W,10);J9A.D0J(36);K4J.style.top=J9A.q7n("px",r_p,K5U);K4J.style.left=s67 || s67 === 0?Z6C:u3x - I3B / 2 + "px";R$W.currentAnchorTime=u1x;R$W.currentAnchorTick=b1a;};j6q.Studies.studyScriptLibrary={};j6q.Studies.studyLibrary=j6q.Studies.studyLibrary || ({});j6q.extend(j6q.Studies.studyLibrary,{ma:{name:"Moving Average",overlay:!![],calculateFN:j6q.Studies.calculateMovingAverage,inputs:{Period:50,Field:"field",Type:"ma",Offset:0},outputs:{MA:"#FF0000"}},"STD Dev":{name:"Standard Deviation",calculateFN:j6q.Studies.calculateStandardDeviation,inputs:{Period:+"14",Field:"field","Standard Deviations":"2" | 2,"Moving Average Type":"ma"},attributes:{"Standard Deviations":{min:0.1,step:0.1}}},"True Range":{name:p8o,calculateFN:j6q.Studies.calculateStudyATR,inputs:{},outputs:{"True Range":"auto"}},volume:{name:"Volume Chart",range:"0 to max",yAxis:{ground:!!({}),initialMarginTop:0,zoom:"0" - 0},seriesFN:j6q.Studies.createVolumeChart,calculateFN:j6q.Studies.calculateVolume,inputs:{},outputs:{"Up Volume":"#8cc176","Down Volume":"#b82c0c"}}});};L0=v7$=>{var V6w;V6w=typeof _CIQ !== "undefined"?_CIQ:v7$.CIQ;A2IFV.D0H();if(!V6w.ChartEngine.Driver){console.error("symbolLookupBase feature requires first activating quoteFeed feature.");}else {V6w.ChartEngine.Driver.Lookup=function(N05){};V6w.ChartEngine.Driver.Lookup.prototype.acceptText=function(G8m,w0z,s4S,J1q){A2IFV.a9S();if(!this.cb){return;}};}};W_=B3J=>{var c1g,O1F;c1g="und";c1g+="efin";c1g+="ed";O1F=typeof _CIQ !== c1g?_CIQ:B3J.CIQ;O1F.ThemeHelper=O1F.ThemeHelper || (function(k_4){var j1I,M6D,c53,D2T,q4w,k4i,N_u,b99,e4h,B8A,v68;j1I="stx_mou";A2IFV.D0H();j1I+="ntain_chart";M6D="Ca";M6D+="nd";M6D+="le/Bar";c53="stx_";c53+="ca";c53+="ndle_dow";c53+="n";D2T="Can";D2T+="dl";D2T+="e/Bar";q4w="stx_can";q4w+="dle_shad";q4w+="ow_dow";q4w+="n";k4i="Candle/B";k4i+="ar";N_u="Cand";N_u+="l";N_u+="e/";N_u+="Bar";b99="Candl";b99+="e/Bar";e4h="stx_gri";e4h+="d";this.params=k_4;B8A=k_4.stx;v68="#FFFFFF";if(B8A.chart.container){v68=getComputedStyle(B8A.chart.container).backgroundColor;if(O1F.isTransparent(v68)){v68=B8A.containerColor;}}this.settings.chart.Background.color=O1F.hexToRgba(v68);this.settings.chart["Grid Lines"].color=O1F.hexToRgba(B8A.canvasStyle(e4h).color);this.settings.chart["Grid Dividers"].color=O1F.hexToRgba(B8A.canvasStyle("stx_grid_dark").color);this.settings.chart["Axis Text"].color=O1F.hexToRgba(B8A.canvasStyle("stx_xaxis").color);this.settings.chartTypes[b99].up.color=O1F.hexToRgba(B8A.canvasStyle("stx_candle_up").color);this.settings.chartTypes["Candle/Bar"].down.color=O1F.hexToRgba(B8A.canvasStyle("stx_candle_down").color);this.settings.chartTypes[N_u].up.wick=O1F.hexToRgba(B8A.canvasStyle("stx_candle_shadow_up").color);this.settings.chartTypes[k4i].down.wick=O1F.hexToRgba(B8A.canvasStyle(q4w).color);this.settings.chartTypes["Candle/Bar"].even.wick=O1F.hexToRgba(B8A.canvasStyle("stx_candle_shadow_even").color);this.settings.chartTypes["Candle/Bar"].up.border=O1F.hexToRgba(B8A.canvasStyle("stx_candle_up").borderLeftColor);this.settings.chartTypes[D2T].down.border=O1F.hexToRgba(B8A.canvasStyle(c53).borderLeftColor);if(O1F.isTransparent(B8A.canvasStyle("stx_candle_up").borderLeftColor)){this.settings.chartTypes["Candle/Bar"].up.border=null;}if(O1F.isTransparent(B8A.canvasStyle("stx_candle_down").borderLeftColor)){this.settings.chartTypes[M6D].down.border=null;}this.settings.chartTypes.Line.color=O1F.hexToRgba(B8A.canvasStyle("stx_line_chart").color);this.settings.chartTypes.Mountain.color=O1F.hexToRgba(B8A.canvasStyle("stx_mountain_chart").backgroundColor);this.settings.chartTypes.Mountain.basecolor=O1F.hexToRgba(B8A.canvasStyle(j1I).color);});O1F.ThemeHelper.prototype.settings={chart:{Background:{color:null},"Grid Lines":{color:null},"Grid Dividers":{color:null},"Axis Text":{color:null}},chartTypes:{"Candle/Bar":{up:{color:null,wick:null,border:null},down:{color:null,wick:null,border:null},even:{color:null,wick:null,border:null}},Line:{color:null},Mountain:{color:null,basecolor:null}}};O1F.ThemeHelper.prototype.update=function(L7S){var e4C,f37,L4N,M41,S8M,T_K,a7Y,x6d,Z6Q,P_v,v4f,x1F,P8o;function p2_(x8w,c2c,E2J){var N4Z;N4Z=v4f[x8w];for(var u2M in N4Z){L7S.setStyle(u2M,c2c,E2J);}}e4C="st";e4C+="x_mountain_chart";f37="colo";f37+="r";L4N="s";L4N+="tx_li";L4N+="ne_chart";M41="c";M41+="ol";M41+="or";S8M="stx_candle_";S8M+="even";T_K="stx_c";T_K+="andle";T_K+="_dow";T_K+="n";a7Y="stx_can";a7Y+="dle_up";x6d="st";x6d+="x_xaxis";Z6Q="co";Z6Q+="lo";Z6Q+="r";P_v="stx";P_v+="_grid";if(!L7S){L7S=this.params.stx;}v4f={stx_candle_up:{stx_candle_up:!!1,stx_bar_up:!!({}),stx_hollow_candle_up:!!"1",stx_line_up:!!({}),stx_baseline_up:!![]},stx_candle_down:{stx_candle_down:!![],stx_bar_down:!"",stx_hollow_candle_down:!"",stx_line_down:!!1,stx_baseline_down:!!1},stx_candle_even:{stx_hollow_candle_even:!"",stx_bar_even:!0},stx_shadow_up:{stx_candle_shadow_up:!!({})},stx_shadow_down:{stx_candle_shadow_down:!!({})},stx_shadow_even:{stx_candle_shadow_even:!!({})},stx_line_chart:{stx_bar_chart:!![],stx_line_chart:!!({})},stx_grid:{stx_grid:!![]},stx_grid_dark:{stx_grid_dark:!!1},stx_xaxis:{stx_xaxis_dark:!![],stx_xaxis:!!({}),stx_yaxis:!0,stx_yaxis_dark:!!({}),stx_grid_border:!0},stx_mountain_chart:{stx_mountain_chart:!!({})},stx_market_session:{stx_market_session:!!1}};L7S.chart.container.style.backgroundColor=this.settings.chart.Background.color;L7S.defaultColor="";p2_(P_v,"color",this.settings.chart["Grid Lines"].color);p2_("stx_grid_dark",Z6Q,this.settings.chart["Grid Dividers"].color);p2_(x6d,"color",this.settings.chart["Axis Text"].color);x1F=this.settings.chartTypes["Candle/Bar"];if(!x1F.even){P8o="stx_candle_";P8o+="shadow_even";x1F.even={color:null,wick:O1F.hexToRgba(L7S.canvasStyle(P8o).color),border:null};}p2_(a7Y,"color",x1F.up.color);p2_(T_K,"color",x1F.down.color);p2_(S8M,M41,x1F.even.color);p2_("stx_shadow_up","color",x1F.up.wick);p2_("stx_shadow_down","color",x1F.down.wick);p2_("stx_shadow_even","color",x1F.even.wick);L7S.setStyle("stx_candle_up","borderLeftColor",x1F.up.border);A2IFV.a9S();L7S.setStyle("stx_candle_down","borderLeftColor",x1F.down.border);p2_(L4N,f37,this.settings.chartTypes.Line.color);L7S.setStyle("stx_mountain_chart","borderTopColor",O1F.hexToRgba(this.settings.chartTypes.Mountain.color,1));L7S.setStyle("stx_mountain_chart","backgroundColor",O1F.hexToRgba(this.settings.chartTypes.Mountain.color,0.5));L7S.setStyle(e4C,"color",O1F.hexToRgba(this.settings.chartTypes.Mountain.basecolor,0.01));L7S.draw();};O1F.ChartEngine.prototype.setThemeSettings=function(L26){var O6U,j2q;O6U="t";O6U+="heme";this.styles={};this.chart.container.style.backgroundColor="";this.defaultColor="";A2IFV.D0H();if(L26){j2q=new O1F.ThemeHelper({stx:this});j2q.settings=L26;j2q.update();}this.updateListeners(O6U);this.changeOccurred("theme");if(this.displayInitialized){this.headsUpHR();this.clearPixelCache();this.updateListeners("theme");this.draw();}};};f9=n6O=>{var b9a,I6f,g9J,v_c,D_T,z1v,w69,X7_,b0l,j1J,f4F,M8l,N8S,i4R,f91,G9R,X8v,w5R,C5q,w2F,j0G,o6d,w$C,a0Z,E7Y,W6m,b9l,U17,x7Q,k1L,a12,X9J,Y_p,r$P,v5$,h$f,p2x,r86,M1n,l7u,S6F,d4i,X84,Y9q,o7p,F0q,t3R,F1S,t6U,r_7,K_p,d0A,v4z,n5A,q2Y,d3p,p4_,A6s,E5z,U9l,a8E,K6e,I7s,k2Y,s7n,y9b,d5J,n_B,T6n,B4v,C13,a3J,f13,N6e,o04,F$Q,f1q,d2I,N4h,x2e,e5P,p_e,A8o,Y4c,F5e,e5C,m17,Q6W,J2n,o$P,S2q,i42,U25,j4p,X9h,E_N,r92,K6K,c7r,x2f,A_5,u29,s3D,f2m,n9m,U_G,y11,t_0,j5L,Q0N,Y4l,c55,s$6,i$J,j7U,A2n,s6y,k5y,h8z,i3W,Q4p,g$w,r$L,g3r,c29,X94,q23,G3_,K9l,n9S,O0H,W72,x$T,d7x,L8w,P1e,k9J,c8l,u2u,Y27,Y9_,p0u,X0Q,W2d,s$W,X0R,t1h,R94,h6Z,g0$,v6b,Q9T,t7u,W5m,v8Q,f5K,Z6N,o89,Z18,a9A,Q5m,E8n,K1K,T0X,Y7z,G8y,N5K,F2x,H27,F$t,g2H,b9W,t$9,Y3H,T$4,E4O,U4Z,x3k,n53;b9a="m";b9a+="a";b9a+="x";I6f="S";I6f+="u";I6f+="n>";I6f+="=1";g9J="m";g9J+="ax";v_c="S";v_c+="un>=";v_c+="2";D_T="Su";D_T+="n>=";D_T+="9";z1v="M";z1v+="ay";w69="N";w69+="o";w69+="v";X7_="o";X7_+="nly";b0l="Su";b0l+="n>=1";j1J="S";j1J+="un";j1J+=">=";j1J+="8";f4F="Su";f4F+="n>";f4F+="=1";M8l="N";M8l+="o";M8l+="v";N8S="lastS";N8S+="un";i4R="m";i4R+="a";i4R+="x";f91="m";f91+="a";f91+="x";G9R="Sun";G9R+=">=8";X8v="M";X8v+="a";X8v+="r";w5R="ma";w5R+="x";C5q="S";C5q+="un>";C5q+="=1";w2F="m";w2F+="a";w2F+="x";j0G="Ma";j0G+="r";o6d="N";o6d+="o";o6d+="v";w$C="m";w$C+="ax";a0Z="Ma";a0Z+="r";E7Y="l";E7Y+="astSun";W6m="ma";W6m+="x";b9l="m";b9l+="a";b9l+="x";U17="last";U17+="S";U17+="un";x7Q="m";x7Q+="a";x7Q+="x";k1L="S";k1L+="un>=";k1L+="15";a12="on";a12+="l";a12+="y";X9J="Su";X9J+="n>=1";Y_p="A";Y_p+="p";Y_p+="r";r$P="m";r$P+="a";r$P+="x";v5$="S";v5$+="un>=1";h$f="A";h$f+="p";h$f+="r";p2x="S";p2x+="e";p2x+="p";r86="o";r86+="n";r86+="l";r86+="y";M1n="Su";M1n+="n>";M1n+="=8";l7u="on";l7u+="ly";S6F="Oc";S6F+="t";d4i="Sun>";d4i+="=1";X84="m";X84+="ax";Y9q="m";Y9q+="ax";o7p="m";o7p+="a";o7p+="x";F0q="Su";F0q+="n>=1";t3R="Ap";t3R+="r";F1S="m";F1S+="a";F1S+="x";t6U="O";t6U+="ct";r_7="Sun>";r_7+="=1";K_p="m";K_p+="a";K_p+="x";d0A="A";d0A+="p";d0A+="r";v4z="m";v4z+="a";v4z+="x";n5A="M";n5A+="ar";q2Y="Sat>=2";q2Y+="4";d3p="la";d3p+="s";d3p+="t";d3p+="Sun";p4_="O";p4_+="ct";A6s="Oc";A6s+="t";E5z="m";E5z+="a";E5z+="x";U9l="lastS";U9l+="un";a8E="2";a8E+="0";K6e="M";K6e+="a";K6e+="r";I7s="2";I7s+="1";k2Y="m";k2Y+="a";k2Y+="x";s7n="M";s7n+="a";s7n+="r";y9b="m";y9b+="a";y9b+="x";d5J="m";d5J+="a";d5J+="x";n_B="W";n_B+="A";n_B+="T";T6n="CA";T6n+="T";B4v="Ap";B4v+="r";C13="2";C13+="3";a3J="F";a3J+="e";a3J+="b";f13="o";f13+="nl";f13+="y";N6e="1";N6e+="0";o04="1";o04+="9";F$Q="o";F$Q+="nly";f1q="o";f1q+="n";f1q+="l";f1q+="y";d2I="2";d2I+="7";N4h="M";N4h+="a";N4h+="r";x2e="1";x2e+="1";e5P="1";e5P+="9";p_e="J";p_e+="u";p_e+="n";A8o="o";A8o+="nl";A8o+="y";Y4c="J";Y4c+="u";Y4c+="n";F5e="1";F5e+="3";e5C="M";e5C+="a";e5C+="y";m17="onl";m17+="y";Q6W="A";Q6W+="si";Q6W+="a/Riyadh";J2n="Europe";J2n+="/Moscow";o$P="E";o$P+="urope";o$P+="/Bucharest";S2q="-";S2q+="0";S2q+="3/-02";i42="-0";i42+="2";U25="-04/-";U25+="03";j4p="-05/-";j4p+="04";X9h="C";X9h+="hile";E_N="B";E_N+="ra";E_N+="z";E_N+="il";r92="-03";r92+="/-";r92+="02";K6K="E";K6K+="S";K6K+="T";c7r="E%";c7r+="sT";x2f="C";x2f+="u";x2f+="b";x2f+="a";A_5="M%";A_5+="sT";u29="M";u29+="exico";s3D="Canad";s3D+="a";f2m="HS";f2m+="T";n9m="M";n9m+="%";n9m+="sT";U_G="C%s";U_G+="T";y11="+";y11+="0";y11+="3";t_0="+";t_0+="1";t_0+="1";j5L="+";j5L+="11";Q0N="+";Q0N+="1";Q0N+="0";Y4l="+";Y4l+="0";Y4l+="4";c55="E";c55+="U";s$6="E";s$6+="U";i$J="E";i$J+="U";j7U="C";j7U+="E%";j7U+="sT";A2n="E";A2n+="U";s6y="Thul";s6y+="e";k5y="E";k5y+="U";h8z="E";h8z+="U";i3W="G";i3W+="M";i3W+="T/BS";i3W+="T";Q4p="To";Q4p+="nga";g$w="+1";g$w+="3/+14";r$L="W";r$L+="S";g3r="+";g3r+="12/";g3r+="+13";c29="AE%s";c29+="T";X94="AC%s";X94+="T";q23="A";q23+="Q";G3_="A";G3_+="W";K9l="+";K9l+="0";K9l+="3";n9S="+054";n9S+="5";O0H="M";O0H+="on";O0H+="g";O0H+="ol";W72="+07/+";W72+="08";x$T="Leb";x$T+="a";x$T+="no";x$T+="n";d7x="I";d7x+="S";d7x+="T";L8w="H";L8w+="K";P1e="C";P1e+="%";P1e+="s";P1e+="T";k9J="%";k9J+="s";c8l="S";c8l+="A";u2u="%";u2u+="s";Y27="Nami";Y27+="bia";Y9_="Pacifi";Y9_+="c/Apia";p0u="Pacific/Ch";p0u+="atha";p0u+="m";X0Q="P";X0Q+="acifi";X0Q+="c/Auckland";W2d="Asia/Ka";W2d+="mc";W2d+="h";W2d+="atka";s$W="Pacifi";s$W+="c/Noumea";X0R="Australia/Bri";X0R+="sbane";t1h="Asia/P";t1h+="yongyang";R94="Asia/To";R94+="k";R94+="yo";h6Z="Australi";h6Z+="a/Euc";h6Z+="la";g0$="Asi";g0$+="a";g0$+="/Taipei";v6b="Asia";v6b+="/Kual";v6b+="a_Lumpur";Q9T="Asi";Q9T+="a/Bangkok";t7u="A";t7u+="s";t7u+="ia/Kab";t7u+="ul";W5m="Asia";W5m+="/Du";W5m+="bai";v8Q="Asia/Te";v8Q+="hran";f5K="Euro";f5K+="pe/Mo";f5K+="scow";Z6N="Eu";Z6N+="rope/Istanb";Z6N+="ul";o89="Asi";o89+="a/Damasc";o89+="us";Z18="Europe/H";Z18+="elsinki";a9A="Africa/Joh";a9A+="annes";a9A+="burg";Q5m="Eur";Q5m+="ope/Bucharest";E8n="Afric";E8n+="a/Casablanc";E8n+="a";K1K="Afr";K1K+="ic";K1K+="a/Tun";K1K+="is";T0X="Atla";T0X+="ntic/South_";T0X+="Georgia";Y7z="America/Punta_Arena";Y7z+="s";G8y="America";G8y+="/Panama";N5K="Americ";N5K+="a/St_Johns";F2x="Am";F2x+="erica/Puerto_Rico";H27="Ame";H27+="rica/Santiag";H27+="o";F$t="America/";F$t+="N";F$t+="ew_Yor";F$t+="k";g2H="Amer";g2H+="ica/Reg";g2H+="i";g2H+="na";b9W="Americ";b9W+="a/Mexi";b9W+="co_City";t$9="America/Chic";t$9+="ago";Y3H="America/Costa_";Y3H+="Rica";T$4="Ameri";T$4+="ca/Denver";E4O="Paci";E4O+="fic/";E4O+="P";E4O+="ago_Pago";U4Z="undefi";U4Z+="n";U4Z+="ed";x3k=typeof _CIQ !== "undefined"?_CIQ:n6O.CIQ;n53=typeof _timezoneJS !== U4Z?_timezoneJS:n6O.timezoneJS;x3k.timeZoneMap={"(UTC-11:00) American Samoa, Midway Island":E4O,"(UTC-10:00) Hawaii":"Pacific/Honolulu","(UTC-09:00) Alaska":"America/Juneau","(UTC-08:00) Pacific Time (US and Canada), Tijuana":"America/Los_Angeles","(UTC-07:00) Arizona":"America/Phoenix","(UTC-07:00) Chihuahua, Mazatlan":"America/Chihuahua","(UTC-07:00) Mountain Time (US and Canada)":T$4,"(UTC-06:00) Central America":Y3H,"(UTC-06:00) Central Time (US and Canada)":t$9,"(UTC-06:00) Guadalajara, Mexico City, Monterrey":b9W,"(UTC-06:00) Saskatchewan":g2H,"(UTC-05:00) Bogota, Lima, Quito, Rio Branco":"America/Bogota","(UTC-05:00) Eastern Time (US and Canada)":F$t,"(UTC-05:00) Havana":"America/Havana","(UTC-05:00) Port-au-Prince":"America/Port-au-Prince","(UTC-04:00) Asuncion":"America/Asuncion","(UTC-04:00) Santiago":H27,"(UTC-04:00) Caracas":"America/Caracas","(UTC-04:00) Atlantic Time (Canada)":"America/Halifax","(UTC-04:00) Georgetown, La Paz, Manaus, San Juan":F2x,"(UTC-03:30) Newfoundland and Labrador":N5K,"(UTC-03:00) Cancun, Jamaica, Panama":G8y,"(UTC-03:00) Buenos Aires":"America/Argentina/Buenos_Aires","(UTC-03:00) Punta Arenas":Y7z,"(UTC-03:00) Montevideo":"America/Montevideo","(UTC-03:00) Sao Paulo":"America/Sao_Paulo","(UTC-02:00) Mid-Atlantic":T0X,"(UTC-01:00) Azores":"Atlantic/Azores","(UTC-01:00) Cape Verde Islands":"Atlantic/Cape_Verde","(UTC) Greenwich Mean Time, Reykjavik":"UTC","(UTC) Dublin":"Europe/Dublin","(UTC) Lisbon, London":"Europe/London","(UTC+01:00) Algiers, Tunis":K1K,"(UTC+01:00) Casablanca":E8n,"(UTC+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna":"Europe/Amsterdam","(UTC+01:00) Belgrade, Bratislava, Budapest, Ljubljana, Prague":"Europe/Belgrade","(UTC+01:00) Brussels, Copenhagen, Madrid, Paris":"Europe/Brussels","(UTC+01:00) Sarajevo, Skopje, Warsaw, Zagreb":"Europe/Sarajevo","(UTC+02:00) Kaliningrad":"Europe/Kaliningrad","(UTC+02:00) Athens, Bucharest":Q5m,"(UTC+02:00) Cairo":"Africa/Cairo","(UTC+02:00) Harare, Johannesburg":a9A,"(UTC+02:00) Helsinki, Kiev, Riga, Sofia, Tallinn, Vilnius":Z18,"(UTC+02:00) Cyprus":"Asia/Nicosia","(UTC+02:00) Beirut":"Asia/Beirut","(UTC+02:00) Damascus":o89,"(UTC+02:00) Jerusalem":"Asia/Jerusalem","(UTC+02:00) Amman":"Asia/Amman","(UTC+03:00) Istanbul":Z6N,"(UTC+03:00) Baghdad, Kuwait, Qatar, Riyadh":"Asia/Riyadh","(UTC+03:00) Minsk, Moscow, Kirov, Simferopol":f5K,"(UTC+03:00) Volgograd":"Europe/Volgograd","(UTC+03:00) Nairobi":"Africa/Nairobi","(UTC+03:30) Tehran":v8Q,"(UTC+04:00) Baku":"Asia/Baku","(UTC+04:00) Dubai, Muscat":W5m,"(UTC+04:00) Astrakhan, Samara, Saratov, Ulyanovsk":"Europe/Samara","(UTC+04:30) Kabul":t7u,"(UTC+05:00) Karachi, Tashkent":"Asia/Karachi","(UTC+05:00) Yekaterinburg":"Asia/Yekaterinburg","(UTC+05:30) Chennai, Kolkata, Mumbai, New Delhi":"Asia/Kolkata","(UTC+05:45) Kathmandu":"Asia/Kathmandu","(UTC+06:00) Almaty":"Asia/Almaty","(UTC+06:00) Omsk":"Asia/Omsk","(UTC+06:00) Astana, Dhaka":"Asia/Dhaka","(UTC+06:30) Yangon":"Asia/Yangon","(UTC+07:00) Bangkok, Jakarta, Vietnam":Q9T,"(UTC+07:00) Hovd":"Asia/Hovd","(UTC+07:00) Krasnoyarsk":"Asia/Krasnoyarsk","(UTC+07:00) Novokuznetsk":"Asia/Novokuznetsk","(UTC+07:00) Barnaul, Novosibirsk, Tomsk":"Asia/Novosibirsk","(UTC+08:00) Beijing, Chongqing, Hong Kong SAR":"Asia/Hong_Kong","(UTC+08:00) Brunei, Kuala Lumpur, Singapore":v6b,"(UTC+08:00) Irkutsk":"Asia/Irkutsk","(UTC+08:00) Choibalsan, Ulaanbaatar":"Asia/Ulaanbaatar","(UTC+08:00) Manila, Taipei":g0$,"(UTC+08:00) Perth":"Australia/Perth","(UTC+08:45) Eucla":h6Z,"(UTC+09:00) Osaka, Sapporo, Tokyo":R94,"(UTC+09:00) Pyongyang":t1h,"(UTC+09:00) Seoul":"Asia/Seoul","(UTC+09:00) Chita, Khandyga, Yakutsk":"Asia/Yakutsk","(UTC+09:30) Adelaide":"Australia/Adelaide","(UTC+09:30) Darwin":"Australia/Darwin","(UTC+10:00) Brisbane":X0R,"(UTC+10:00) Canberra, Melbourne, Sydney":"Australia/Sydney","(UTC+10:00) Guam, Port Moresby":"Pacific/Guam","(UTC+10:00) Ust-Nera, Vladivostok":"Asia/Vladivostok","(UTC+11:00) Noumea, Solomon Islands":s$W,"(UTC+11:00) Magadan":"Asia/Magadan","(UTC+11:00) Sakhalin, Srednekolymsk":"Asia/Srednekolymsk","(UTC+12:00) Anadyr, Kamchatka":W2d,"(UTC+12:00) Auckland, Wellington":X0Q,"(UTC+12:00) Fiji":"Pacific/Fiji","(UTC+12:45) Chatham":p0u,"(UTC+13:00) Tonga":"Pacific/Tongatapu","(UTC+13:00) Samoa":Y9_,"(UTC+14:00) Kiritimati":"Pacific/Kiritimati"};(function(){var L9E=A2IFV;var R97,f7O,W50,f7A,k7U,p8I,n4l,V7P,r3Z,L0m,D8n,c4e,r5f,m7V,v7z,S2B,R$c,i8x,O18,i8b,J6x,F0l;R97="N";R97+="ov";R97+="em";R97+="ber";f7O="O";f7O+="ct";f7O+="obe";f7O+="r";W50="S";W50+="eptem";W50+="be";W50+="r";f7A="Ju";f7A+="ne";k7U="M";k7U+="a";k7U+="y";p8I="A";p8I+="pril";n4l="M";n4l+="arch";V7P="S";V7P+="at";V7P+="urda";V7P+="y";r3Z="M";r3Z+="o";r3Z+="nda";r3Z+="y";L0m="un";L0m+="defin";L0m+="ed";"use strict";D8n=typeof window !== "undefined"?window:null;c4e=D8n || (typeof global !== L0m?global:{});n53.VERSION="0.4.11";r5f=c4e.$ || c4e.jQuery || c4e.Zepto;m7V=c4e.fleegix;v7z=n53.Days=["Sunday",r3Z,"Tuesday","Wednesday","Thursday","Friday",V7P];S2B=n53.Months=["January","February",n4l,p8I,k7U,f7A,"July","August",W50,f7O,R97,"December"];R$c={};i8x={};O18={};for(var A7y=0;A7y < S2B.length;A7y++){R$c[S2B[A7y].substr(L9E.S40(1,"0",L9E.D0J(1)),3)]=A7y;}for(A7y=+"0";A7y < v7z.length;A7y++){i8x[v7z[A7y].substr(0,L9E.q7n(1,"3",L9E.D0J(1)))]=A7y;}i8b=Array.prototype.indexOf || (function(y$0){var E6G,w7T,T4O,e48,U4Q,I$J,O1K;if(this === null){throw new TypeError();}E6G=Object(this);w7T=E6G.length >>> 0;if(w7T === +"0"){return -1;}T4O=0;if(arguments.length > 1){T4O=Number(arguments[1]);if(T4O != T4O){T4O=0;}else if(T4O !== 0 && T4O !== Infinity && T4O !== -Infinity){e48=932114445;U4Q=372162485;I$J=2;for(var R4j=1;L9E.Z2Z(R4j.toString(),R4j.toString().length,67787) !== e48;R4j++){L9E.D0J(7);var N4a=L9E.S40(8,9);L9E.H6P(133);var V0W=L9E.S40(2,2,1,3,10);T4O=(T4O <= N4a && ~("6" * V0W)) / Math.floor(Math.abs(T4O));I$J+=2;}if(L9E.Z2Z(I$J.toString(),I$J.toString().length,46816) !== U4Q){L9E.H6P(18);var u3s=L9E.q7n(16,4,3);L9E.D0J(7);var z_v=L9E.q7n(9,15);T4O=(T4O <= u3s && ~z_v) / Math.floor(Math.abs(T4O));}L9E.H6P(22);var b_$=L9E.q7n(1,5,11,56);T4O=(T4O > 0 || b_$) * Math.floor(Math.abs(T4O));}}if(T4O >= w7T){return -1;}O1K=T4O >= 0?T4O:Math.max(w7T - Math.abs(T4O),0);for(;O1K < w7T;O1K++){if((O1K in E6G) && E6G[O1K] === y$0){return O1K;}}L9E.D0J(40);return -L9E.q7n(0,"1");});J6x=function(d0e,F72){var E8K,a$J,S3Z,V7y;E8K="nu";E8K+="mber";if(typeof d0e !== E8K){L9E.H6P(0);throw L9E.S40("not a number: ",d0e);}L9E.H6P(70);a$J=L9E.q7n(d0e,1000);S3Z=d0e.toString();V7y=S3Z.length;if(a$J && V7y > F72){L9E.H6P(7);return S3Z.substr(L9E.S40(F72,V7y),V7y);}S3Z=[S3Z];while(V7y < F72){S3Z.unshift((5020,"1007" ^ 0) <= +"4470"?679.89 < +"3623"?"0":8755 != 751?"B":(!!0,7.04e+3):629.34);V7y++;}return S3Z.join("");};F0l=function(G1h){var l8U,i_y,B6L;l8U="u";l8U+="nd";l8U+="efi";l8U+="ned";i_y="un";i_y+="defined";B6L="URL m";B6L+="ust be specified";if(!G1h){return;}if(!G1h.url){throw new Error(B6L);}if(!(("async" in G1h))){G1h.async=!!"1";}if((!m7V || typeof m7V.xhr === i_y) && (!r5f || typeof r5f.ajax === l8U)){throw new Error("Please use the Fleegix.js XHR module, jQuery ajax, Zepto ajax, or define your own transport mechanism for downloading zone files.");}if(!G1h.async){return m7V && m7V.xhr?m7V.xhr.doReq({url:G1h.url,async:![]}):r5f.ajax({url:G1h.url,async:!({}),dataType:"text"}).responseText;}return m7V && m7V.xhr?m7V.xhr.send({url:G1h.url,method:"get",handleSuccess:G1h.success,handleErr:G1h.error}):r5f.ajax({url:G1h.url,dataType:"text",method:"GET",error:G1h.error,success:G1h.success});};n53.ruleCache={};n53.Date=function(){var E$i,x6Y,I17,D2R,I$R,Y6F,J5H;E$i="s";E$i+="t";E$i+="ri";E$i+="ng";if(this === n53){throw "timezoneJS.Date object must be constructed with 'new'";}x6Y=Array.prototype.slice.apply(arguments);I17=null;D2R=null;I$R=[];Y6F=![];if(Object.prototype.toString.call(x6Y[0]) === "[object Array]"){x6Y=x6Y[0];}if(typeof x6Y[x6Y.length - 1] === E$i){Y6F=Date.parse(x6Y[x6Y.length - 1].replace(/GMT[+-]\d+/,""));if(isNaN(Y6F) || Y6F === null){D2R=x6Y.pop();}}J5H=!1;switch(x6Y.length){case "0" | 0:I17=new Date();break;case 1:I17=new Date(x6Y[0]);if(typeof x6Y[0] == "string" && x6Y[0].search(/[+-][0-9]{4}/) == -1 && x6Y[0].search(/Z/) == -1 && x6Y[0].search(/T/) == -1){J5H=!0;}break;case 2:I17=new Date(x6Y[+"0"],x6Y[1]);J5H=!!({});break;default:for(var W6l=0;W6l < "7" << 0;W6l++){I$R[W6l]=x6Y[W6l] || 0;}L9E.D0J(10);I17=new Date(I$R[0],I$R[+"1"],I$R[2],I$R[3],I$R[4],I$R[5],I$R[L9E.S40("6",4)]);J5H=!"";break;}if(isNaN(I17.getTime())){throw new Error("Invalid date");}this._useCache=![];this._tzInfo={};this._day=0;L9E.D0J(40);this.year=L9E.S40(0,"0");this.month=0;this.date=0;this.hours=0;this.minutes=0;this.seconds=0;this.milliseconds=0;this.timezone=D2R || null;if(J5H){this.setFromDateObjProxy(I17);}else {this.setFromTimeProxy(I17.getTime(),D2R);}};x3k.extend(n53.Date.prototype,{getDate:function(){return this.date;},getDay:function(){L9E.D0H();return this._day;},getFullYear:function(){return this.year;},getMonth:function(){return this.month;},getYear:function(){L9E.H6P(121);var g$_=L9E.S40(10,1689,17,238);return this.year - g$_;},getHours:function(){return this.hours;},getMilliseconds:function(){return this.milliseconds;},getMinutes:function(){return this.minutes;},getSeconds:function(){L9E.D0H();return this.seconds;},getUTCDate:function(){L9E.D0H();return this.getUTCDateProxy().getUTCDate();},getUTCDay:function(){L9E.a9S();return this.getUTCDateProxy().getUTCDay();},getUTCFullYear:function(){L9E.a9S();return this.getUTCDateProxy().getUTCFullYear();},getUTCHours:function(){return this.getUTCDateProxy().getUTCHours();},getUTCMilliseconds:function(){return this.getUTCDateProxy().getUTCMilliseconds();},getUTCMinutes:function(){L9E.D0H();return this.getUTCDateProxy().getUTCMinutes();},getUTCMonth:function(){L9E.a9S();return this.getUTCDateProxy().getUTCMonth();},getUTCSeconds:function(){L9E.D0H();return this.getUTCDateProxy().getUTCSeconds();},getTime:function(){L9E.H6P(52);L9E.a9S();var K2r=L9E.S40(16740,1200,14);L9E.D0J(134);var v$X=L9E.q7n(20011,995,20000,11,5);return this._timeProxy + this.getTimezoneOffset() * K2r * v$X;},getTimezone:function(){return this.timezone;},getTimezoneOffset:function(){return this.getTimezoneInfo().tzOffset;},getTimezoneAbbreviation:function(){L9E.a9S();return this.getTimezoneInfo().tzAbbr;},getTimezoneInfo:function(){var u8q,k9L,A0p;if(this._useCache){return this._tzInfo;}if(this.timezone){k9L="U";k9L+="T";k9L+="C";A0p="Etc";A0p+="/U";A0p+="T";A0p+="C";u8q=this.timezone === A0p || this.timezone === "Etc/GMT"?{tzOffset:0,tzAbbr:k9L}:n53.timezone.getTzInfo(this._timeProxy,this.timezone);}else {u8q={tzOffset:this.getLocalOffset(),tzAbbr:null};}this._tzInfo=u8q;L9E.a9S();this._useCache=!!({});return u8q;},getUTCDateProxy:function(){var x$3;x$3=new Date(this._timeProxy);L9E.a9S();x$3.setUTCMinutes(x$3.getUTCMinutes() + this.getTimezoneOffset());return x$3;},setDate:function(X$e){this.setAttribute("date",X$e);L9E.a9S();return this.getTime();},setFullYear:function(j5P,V4L,i5a){var A4f;L9E.a9S();if(i5a !== undefined){this.setAttribute("date",1);}this.setAttribute("year",j5P);if(V4L !== undefined){A4f="mo";A4f+="nt";A4f+="h";this.setAttribute(A4f,V4L);}if(i5a !== undefined){this.setAttribute("date",i5a);}return this.getTime();},setMonth:function(g3I,g1g){this.setAttribute("month",g3I);if(g1g !== undefined){this.setAttribute("date",g1g);}L9E.D0H();return this.getTime();},setYear:function(l2W){l2W=Number(l2W);if(0 <= l2W && l2W <= 99){l2W+=1900;}this.setUTCAttribute("year",l2W);return this.getTime();},setHours:function(v5n,O$R,q2D,z5B){L9E.D0H();this.setAttribute("hours",v5n);if(O$R !== undefined){this.setAttribute("minutes",O$R);}if(q2D !== undefined){this.setAttribute("seconds",q2D);}if(z5B !== undefined){this.setAttribute("milliseconds",z5B);}return this.getTime();},setMinutes:function(S70,Q4x,T52){var N99;this.setAttribute("minutes",S70);if(Q4x !== undefined){N99="s";N99+="ec";N99+="on";N99+="ds";this.setAttribute(N99,Q4x);}if(T52 !== undefined){this.setAttribute("milliseconds",T52);}return this.getTime();},setSeconds:function(o4D,t9V){this.setAttribute("seconds",o4D);if(t9V !== undefined){this.setAttribute("milliseconds",t9V);}return this.getTime();},setMilliseconds:function(N_3){var y1x;y1x="millise";y1x+="conds";this.setAttribute(y1x,N_3);return this.getTime();},setTime:function(B9m){if(isNaN(B9m)){throw new Error("Units must be a number.");}this.setFromTimeProxy(B9m,this.timezone);return this.getTime();},setUTCFullYear:function(b5R,T5v,g7u){L9E.a9S();var s6W,X1b,Y8M;if(g7u !== undefined){s6W=-+"107761421";X1b=1862984064;Y8M=+"2";for(var j3W=1;L9E.U6$(j3W.toString(),j3W.toString().length,49801) !== s6W;j3W++){this.setUTCAttribute("",3);Y8M+=+"2";}if(L9E.U6$(Y8M.toString(),Y8M.toString().length,25666) !== X1b){this.setUTCAttribute("",3);}this.setUTCAttribute("date",1);}this.setUTCAttribute("year",b5R);if(T5v !== undefined){this.setUTCAttribute("month",T5v);}if(g7u !== undefined){this.setUTCAttribute("date",g7u);}return this.getTime();},setUTCMonth:function(E8_,C8w){this.setUTCAttribute("month",E8_);if(C8w !== undefined){this.setUTCAttribute("date",C8w);}L9E.D0H();return this.getTime();},setUTCDate:function(H8c){var L0$;L0$="da";L0$+="te";this.setUTCAttribute(L0$,H8c);return this.getTime();},setUTCHours:function(s8H,A91,M0E,J02){var G4u;G4u="h";G4u+="o";G4u+="ur";G4u+="s";this.setUTCAttribute(G4u,s8H);if(A91 !== undefined){this.setUTCAttribute("minutes",A91);}if(M0E !== undefined){this.setUTCAttribute("seconds",M0E);}if(J02 !== undefined){this.setUTCAttribute("milliseconds",J02);}return this.getTime();},setUTCMinutes:function(L$v,Q9G,n0D){this.setUTCAttribute("minutes",L$v);if(Q9G !== undefined){this.setUTCAttribute("seconds",Q9G);}if(n0D !== undefined){this.setUTCAttribute("milliseconds",n0D);}return this.getTime();},setUTCSeconds:function(i0N,h_z){var I6R;this.setUTCAttribute("seconds",i0N);if(h_z !== undefined){I6R="millise";I6R+="con";I6R+="ds";this.setUTCAttribute(I6R,h_z);}return this.getTime();},setUTCMilliseconds:function(b$w){this.setUTCAttribute("milliseconds",b$w);return this.getTime();},setFromDateObjProxy:function(w8E){this.year=w8E.getFullYear();this.month=w8E.getMonth();this.date=w8E.getDate();this.hours=w8E.getHours();this.minutes=w8E.getMinutes();this.seconds=w8E.getSeconds();this.milliseconds=w8E.getMilliseconds();this._day=w8E.getDay();this._dateProxy=w8E;this._timeProxy=Date.UTC(this.year,this.month,this.date,this.hours,this.minutes,this.seconds,this.milliseconds);this._useCache=!"1";},setFromTimeProxy:function(e$2,m$V){var T6c,B8t;T6c=new Date(e$2);L9E.D0H();B8t=m$V?n53.timezone.getTzInfo(e$2,m$V,!0).tzOffset:T6c.getTimezoneOffset();T6c.setTime(e$2 + (T6c.getTimezoneOffset() - B8t) * 60000);this.setFromDateObjProxy(T6c);},setAttribute:function(h7r,f51){var O2$,h6T,d3x;if(isNaN(f51)){O2$="Uni";O2$+="ts must be a number.";throw new Error(O2$);}h6T=this._dateProxy;d3x=h7r === "year"?"FullYear":h7r.substr(0,1).toUpperCase() + h7r.substr(1);h6T["set" + d3x](f51);this.setFromDateObjProxy(h6T);},setUTCAttribute:function(u4$,b5o){var q_G,V3y;if(isNaN(b5o)){throw new Error("Units must be a number.");}L9E.a9S();q_G=u4$ === "year"?"FullYear":u4$.substr(0,1).toUpperCase() + u4$.substr("1" >> 0);V3y=this.getUTCDateProxy();V3y["setUTC" + q_G](b5o);V3y.setUTCMinutes(V3y.getUTCMinutes() - this.getTimezoneOffset());this.setFromTimeProxy(V3y.getTime() + this.getTimezoneOffset() * 60000,this.timezone);},setTimezone:function(o29){var T1D;T1D=this.getTimezoneInfo().tzOffset;this.timezone=o29;this._useCache=!({});L9E.D0H();this.setUTCMinutes(this.getUTCMinutes() - this.getTimezoneInfo().tzOffset + T1D);},removeTimezone:function(){this.timezone=null;this._useCache=![];},valueOf:function(){return this.getTime();},clone:function(){return this.timezone?new n53.Date(this.getTime(),this.timezone):new n53.Date(this.getTime());},toGMTString:function(){var q4U;q4U="Etc";q4U+="/GMT";return this.toString("EEE, dd MMM yyyy HH:mm:ss Z",q4U);},toLocaleStringIntl:function(){},toLocaleDateString:function(){},toLocaleTimeString:function(){},toSource:function(){},toISOString:function(){var D1D;D1D="Etc";L9E.a9S();D1D+="/";D1D+="UTC";L9E.H6P(36);var r0s=L9E.S40(12,7033,15);L9E.D0J(135);var c3S=L9E.S40(19490,1642,18,12);return this.toString("yyyy-MM-ddTHH:mm:ss.SSS",D1D) + (r0s < c3S?"Z":"a");},toJSON:function(){L9E.a9S();return this.toISOString();},toDateString:function(){var y92;y92="E";L9E.a9S();y92+="EE M";y92+="MM dd yyy";y92+="y";return this.toString(y92);},toTimeString:function(){L9E.a9S();return this.toString("H:mm k");},toString:function(G6H,m8X){var G7b,L9p,B4L,a8m,X5p;G7b="yyyy-MM-ddTHH:";G7b+="mm";G7b+=":ss.SSS";if(!G6H){G6H=G7b;}L9p=G6H;L9E.D0H();B4L=m8X?n53.timezone.getTzInfo(this.getTime(),m8X):this.getTimezoneInfo();a8m=this;if(m8X){a8m=this.clone();a8m.setTimezone(m8X);}X5p=a8m.getHours();return L9p.replace(/a+/g,function(){return (6330,1920) <= (891.18,7580)?"k":(5350,"281.12" * 1) != (949,"120.62" - 0)?5.94e+3:+"346.59";}).replace(/y+/g,function(h54){return J6x(a8m.getFullYear(),h54.length);}).replace(/d+/g,function(Z2A){return J6x(a8m.getDate(),Z2A.length);}).replace(/m+/g,function(T1g){L9E.D0H();return J6x(a8m.getMinutes(),T1g.length);}).replace(/s+/g,function(u1h){return J6x(a8m.getSeconds(),u1h.length);}).replace(/S+/g,function(D22){return J6x(a8m.getMilliseconds(),D22.length);}).replace(/h+/g,function(X9n){return J6x(X5p % +"12" === 0?12:X5p % ("12" | 12),X9n.length);}).replace(/M+/g,function(r0R){var j9j,l0H;L9E.D0H();j9j=a8m.getMonth();l0H=r0R.length;if(l0H > +"3"){return n53.Months[j9j];}else if(l0H > +"2"){return n53.Months[j9j].substring(0,l0H);}L9E.D0J(0);return J6x(L9E.q7n(j9j,1),l0H);}).replace(/k+/g,function(){if(X5p >= ("12" ^ 0)){if(X5p > "12" - 0){X5p-=12;}return "PM";}L9E.a9S();return "AM";}).replace(/H+/g,function(g0I){L9E.a9S();return J6x(X5p,g0I.length);}).replace(/E+/g,function(c1X){L9E.D0J(28);L9E.D0H();return v7z[a8m.getDay()].substring(L9E.q7n("0",96),c1X.length);}).replace(/Z+/gi,function(){return B4L.tzAbbr;});},toUTCString:function(){L9E.D0H();return this.toGMTString();},civilToJulianDayNumber:function(A3i,h_c,E17){var U1J,E$L,L33;h_c++;if(h_c > "12" << 32){L9E.D0J(14);U1J=parseInt(L9E.S40(12,h_c),10);L9E.D0J(75);h_c=L9E.q7n(h_c,12);A3i+=U1J;}if(h_c <= 2){A3i-=1;h_c+=12;}L9E.D0J(8);U1J=Math.floor(L9E.S40(A3i,"100"));L9E.D0J(39);var R65=L9E.S40(9,4,3);L9E.H6P(12);var F5b=L9E.S40(7,3,7);E$L=R65 - U1J + Math.floor(U1J / F5b);L9E.H6P(52);var I1m=L9E.q7n(44,15,3);L9E.D0J(106);var S$u=L9E.S40(15,152,1496,19,17);L9E.a9S();L33=Math.floor(365.25 * (A3i + +"4716")) + Math.floor(+"30.6001" * (h_c + I1m)) + E17 + E$L - S$u;return L33;},getLocalOffset:function(){L9E.D0H();return this._dateProxy.getTimezoneOffset();}},!!1);n53.timezone=new (function(){var I1v,h1S,E4f,d6u,w0o,R_k,C0t,d7u,V3S,D9T,u$D,t4j,G8A,I91,q$k,h5k,n1T,Y_O,J8h,r2m,J$8,c$3,h24,I$t,c$Z,B71,F$X;I1v="m";I1v+="an";I1v+="ualLoa";I1v+="d";h1S="p";h1S+="r";h1S+="el";h1S+="oadAll";E4f="e";E4f+="u";E4f+="rope";d6u="etcete";d6u+="ra";w0o="a";w0o+="fr";function E7u(o$t,U6c,D8t,j5d){var r7q,f1C,Q9D,L6Y,S0I,q_2,X5W,J$f,c9_,P_d,C4F,s8b,P6z,t5s,j0I;r7q="nu";r7q+="mber";f1C=typeof o$t === r7q?new Date(o$t):o$t;Q9D=U6c[1];L6Y=U6c[0];S0I=Q9D.match(/^([0-9]):([0-9][0-9])$/);if(S0I){q_2="m";q_2+="a";q_2+="x";L9E.D0J(123);var f2E=L9E.q7n(20,14,271,18);L9E.H6P(7);var Z$U=L9E.q7n(19,29);L9E.D0J(19);var U_o=L9E.S40(120,9,20,89);L9E.D0J(52);var P85=L9E.q7n(36,19,2);L9E.D0J(1);return [-1000000,q_2,337.42 >= 5080?0x69c:4020 >= (6720,100.04)?"925" - 0 > 2650?(0x1486,0x1dce):"-":(246.19,0x74e),"Jan",L9E.S40(1,"1"),[+"0",0,0],parseInt(S0I[f2E],Z$U) * U_o + parseInt(S0I[P85],"10" - 0),"-"];}X5W=function(s$Y,S$Q,C2T){var T5y;T5y=0;if(S$Q === "u" || S$Q === (9752 === 7560?432.49:"g") || S$Q === ((434.62,"9460" >> 64) >= 3200?(282,680.96) >= 6070?("0x139d" - 0,890.28):"z":0x2329)){T5y=0;}else if(S$Q === "s"){T5y=L6Y;}else if(S$Q === "w" || !S$Q){T5y=F_m(L6Y,C2T[6]);}else {L9E.H6P(0);throw new Error(L9E.S40("unknown type ",S$Q));}L9E.H6P(136);T5y*=L9E.S40("1000",60);return new Date(s$Y.getTime() + T5y);};J$f=function(a2y,m47){var e8W,o_n,H4w,c47,O3a,q2$,U8f;L9E.a9S();e8W=a2y[0];o_n=a2y[1];H4w=o_n[5];if(!O18[e8W]){O18[e8W]={};}if(O18[e8W][o_n]){c47=O18[e8W][o_n];}else {if(!isNaN(o_n[4])){c47=new Date(Date.UTC(e8W,R$c[o_n[3]],o_n["4" - 0],H4w[0],H4w[1],H4w[2],0));}else {if(o_n[4].substr("0" * 1,4) === "last"){c47=new Date(Date.UTC(e8W,R$c[o_n[+"3"]] + +"1",1,H4w[0] - +"24",H4w[1],H4w[2],0));O3a=i8x[o_n[4].substr(L9E.S40(1,"4",L9E.H6P(1)),+"3")];q2$="<=";}else {c47=new Date(Date.UTC(e8W,R$c[o_n[3]],o_n[4].substr("5" | 1),H4w[0],H4w[+"1"],H4w[2],0));O3a=i8x[o_n[4].substr(0,L9E.q7n(1,"3",L9E.H6P(1)))];q2$=o_n["4" << 32].substr(3,2);}U8f=c47.getUTCDay();if(q2$ === ">="){c47.setUTCDate(c47.getUTCDate() + (O3a - U8f + (O3a < U8f?7:0)));}else {c47.setUTCDate(c47.getUTCDate() + (O3a - U8f - (O3a > U8f?7:0)));}}O18[e8W][o_n]=c47;}if(m47){c47=X5W(c47,H4w["3" | 1],m47);}return c47;};c9_=function(w$G,H95){var f$z;f$z=[];for(var m_j=0;H95 && m_j < H95.length;m_j++){if(H95[m_j][+"0"] <= w$G && (H95[m_j][1] >= w$G || H95[m_j][0] === w$G && H95[m_j]["1" | 1] === "only" || H95[m_j][1] === "max")){f$z.push([w$G,H95[m_j]]);}}return f$z;};P_d=function(L$9,Q$a,C9E){var T9Z,A0J;if(!(L$9 instanceof Date)){T9Z=L$9[0];A0J=L$9[1];L$9=!C9E && O18[T9Z] && O18[T9Z][A0J]?O18[T9Z][A0J]:J$f(L$9,C9E);}else if(C9E){L$9=X5W(L$9,D8t?959.67 < (5096,9950)?(876.65,783) === 4140?(640.58,"N"):"u":(!({}),"865.13" * 1):+"4380" > ("647.73" - 0,8889)?(3.82e+3,"K"):(6230,4480) > (1100,1176)?"4141" - 0 === 1270?(4.00e+3,"Z"):"w":(170.58,5.03e+3),C9E);}if(!(Q$a instanceof Date)){T9Z=Q$a[0];A0J=Q$a[1];Q$a=!C9E && O18[T9Z] && O18[T9Z][A0J]?O18[T9Z][A0J]:J$f(Q$a,C9E);}else if(C9E){Q$a=X5W(Q$a,D8t?(6490,9710) != (683.18,1260)?"u":6920 == 256.29?(+"0xa46",!"1"):+"780.47":"w",C9E);}L$9=Number(L$9);L9E.a9S();Q$a=Number(Q$a);L9E.H6P(7);return L9E.q7n(Q$a,L$9);};C4F=f1C.getUTCFullYear();P6z=n53.ruleCache[j5d];if(!P6z){P6z=n53.ruleCache[j5d]={};}s8b=P6z[C4F];if(!s8b){L9E.H6P(7);s8b=c9_(L9E.S40(1,C4F),c$Z.rules[Q9D]);s8b=s8b.concat(c9_(C4F,c$Z.rules[Q9D]));s8b.sort(P_d);P6z[C4F]=s8b;}if(!s8b || !s8b.length){return null;}for(var R4$=s8b.length - 1;R4$ >= 0;R4$--){if(R4$ > 0){L9E.D0J(137);t5s=s8b[L9E.q7n(1,"1",R4$)][L9E.q7n(1,"1",L9E.D0J(1))];}else {t5s=null;}j0I=s8b[R4$];if(!j0I[2]){j0I[2]=J$f(j0I,t5s);;}if(P_d(f1C,j0I,t5s) >= 0){L9E.D0J(40);return j0I[L9E.S40(32,"1")];}}return null;;}w0o+="ic";w0o+="a";R_k="asi";function l0F(M$M,S7l){var i3p;L9E.D0J(7);var Z7x=L9E.q7n(5330,10660);L9E.D0H();L9E.H6P(138);var P6H=L9E.q7n(63960,4,3,2,2665);L9E.D0J(12);var R7H=L9E.S40(17,135,17);L9E.H6P(36);var q7M=L9E.S40(20,6190,14);i3p=c$Z.zoneFileBasePath + (Z7x != +"48.02"?"/":23.26 >= P6H?R7H:("C",q7M)) + M$M;return !S7l || !S7l.async?c$Z.parseZones(c$Z.transport({url:i3p,async:![]})):c$Z.transport({async:!![],url:i3p,success:function(F9E){return c$Z.parseZones(F9E) && typeof S7l.callback === "function" && S7l.callback();},error:function(){L9E.D0H();L9E.D0J(37);throw new Error(L9E.S40("' zoneinfo files","Error retrieving '",i3p));}});}R_k+="a";C0t="e";C0t+="tceter";function r2_(J5e){var G80,a7N;G80=/(\d+)(?::0*(\d*))?(?::0*(\d*))?([wsugz])?$/;a7N=J5e.match(G80);a7N[1]=parseInt(a7N[1],10);L9E.H6P(21);a7N[L9E.q7n("2",0)]=a7N[2]?parseInt(a7N[2],+"10"):0;a7N[3]=a7N[3]?parseInt(a7N[3],10):0;return a7N.slice(1,5);}C0t+="a";d7u="e";d7u+="uro";d7u+="p";d7u+="e";V3S="e";V3S+="uro";V3S+="pe";D9T="e";D9T+="u";D9T+="rope";u$D="eu";u$D+="r";u$D+="ope";t4j="eu";t4j+="rop";t4j+="e";G8A="asi";G8A+="a";I91="a";I91+="fr";I91+="ic";function y3p(o_Q){var z6p,C8J,J$N,W6O,M_u;z6p=F$X[o_Q];if(z6p){return z6p;}C8J=o_Q.split((6730,9880) != 8170?"/":(6.19e+3,650.85))[L9E.S40("0",0,L9E.D0J(21))];J$N=B71[C8J];L9E.D0H();if(J$N){return J$N;}W6O=c$Z.zones[o_Q];if(typeof W6O === "string"){return y3p(W6O);}if(!c$Z.loadedZones.backward){M_u="bac";M_u+="kwa";M_u+="rd";c$Z.loadZoneFile(M_u);return y3p(o_Q);}c0d(o_Q);}I91+="a";q$k="eu";q$k+="r";function F_m(W6x,Y7A){L9E.D0J(7);L9E.D0H();return -Math.ceil(L9E.S40(W6x,Y7A));}q$k+="o";function p0F(x8M){var b1M,s0I,w7U,z$L;L9E.a9S();if(!x8M[3]){return;}b1M=parseInt(x8M[3],"10" << 0);s0I=11;w7U=31;if(x8M[4]){s0I=R$c[x8M[4].substr(L9E.S40("0",0,L9E.H6P(10)),3)];w7U=parseInt(x8M[5],10) || 1;}z$L=x8M[+"6"]?r2_(x8M[6]):[+"0",0,0];L9E.H6P(28);return [b1M,s0I,w7U,z$L[L9E.S40("0",0)],z$L[1],z$L[2]];}q$k+="pe";h5k="eu";h5k+="ro";h5k+="pe";n1T="a";n1T+="us";n1T+="tralasia";Y_O="a";Y_O+="s";Y_O+="ia";J8h="anta";J8h+="rc";function c0d(o1L){var s3V;L9E.a9S();s3V="' is either incorrect, or not l";s3V+="oaded in the timezone registry.";L9E.H6P(37);throw new Error(L9E.S40(s3V,"Timezone '",o1L));}J8h+="tica";r2m="a";r2m+="u";r2m+="str";function d07(q79,z8t){var c_T,W_y,W$f,b7U,W00,U9z,J7r;c_T="stri";c_T+="n";c_T+="g";W_y=typeof q79 === "number"?q79:new Date(+q79).getTime();W$f=z8t;b7U=c$Z.zones[W$f];while(typeof b7U === c_T){W$f=b7U;b7U=c$Z.zones[W$f];}if(!b7U){if(!c$Z.loadedZones.backward){c$Z.loadZoneFile("backward");return d07(q79,z8t);}else if(W$f && W$f !== z8t){c$Z.lazyLoadZoneFiles(W$f);return d07(q79,W$f);}c0d(W$f);}if(b7U.length === 0){W00="' on";W00+=" ";U9z="No Zone ";U9z+="f";U9z+="ound f";U9z+="or '";L9E.H6P(48);throw new Error(L9E.S40(q79,W00,z8t,U9z));}for(var D4u=b7U.length - ("1" - 0);D4u >= 0;D4u--){J7r=b7U[D4u];if(J7r[3] && W_y > J7r[3])break;}L9E.H6P(0);return b7U[L9E.q7n(D4u,1)];}r2m+="alasia";J$8="sou";J$8+="th";J$8+="am";J$8+="erica";c$3="northam";c$3+="erica";h24="northam";h24+="e";h24+="rica";I$t="northa";I$t+="merica";c$Z=this;B71={Etc:"etcetera",EST:"northamerica",MST:"northamerica",HST:I$t,EST5EDT:"northamerica",CST6CDT:h24,MST7MDT:c$3,PST8PDT:"northamerica",America:["northamerica",J$8],Pacific:r2m,Atlantic:"europe",Africa:"africa",Indian:"africa",Antarctica:J8h,Asia:Y_O,Australia:n1T,Europe:"europe",WET:"europe",CET:h5k,MET:"europe",EET:q$k};F$X={"Pacific/Honolulu":"northamerica","Atlantic/Bermuda":"northamerica","Atlantic/Cape_Verde":I91,"Atlantic/St_Helena":"africa","Indian/Kerguelen":"antarctica","Indian/Chagos":G8A,"Indian/Maldives":"asia","Indian/Christmas":"australasia","Indian/Cocos":"australasia","America/Danmarkshavn":"europe","America/Scoresbysund":"europe","America/Godthab":t4j,"America/Thule":u$D,"Asia/Istanbul":"europe","Asia/Yekaterinburg":"europe","Asia/Omsk":"europe","Asia/Novosibirsk":D9T,"Asia/Krasnoyarsk":"europe","Asia/Irkutsk":V3S,"Asia/Yakutsk":"europe","Asia/Vladivostok":"europe","Asia/Sakhalin":"europe","Asia/Magadan":d7u,"Asia/Kamchatka":"europe","Asia/Anadyr":"europe","Africa/Ceuta":"europe",GMT:C0t,"Europe/Nicosia":R_k};this.zoneFileBasePath=null;this.zoneFiles=[w0o,"antarctica","asia","australasia","backward",d6u,E4f,"northamerica","pacificnew","southamerica"];this.loadingSchemes={PRELOAD_ALL:h1S,LAZY_LOAD:"lazyLoad",MANUAL_LOAD:I1v};this.getRegionForTimezone=y3p;this.loadingScheme=this.loadingSchemes.LAZY_LOAD;this.loadedZones={};this.zones={};this.rules={};this.init=function(X0f){var S88,a7_,y7v;S88="northam";S88+="erica";a7_={async:!![]};y7v=this.loadingScheme === this.loadingSchemes.PRELOAD_ALL?this.zoneFiles:this.defaultZoneFile || S88;for(var P4V in X0f){a7_[P4V]=X0f[P4V];}return this.loadZoneFiles(y7v,a7_);};this.loadZoneFiles=function(z_j,S7f){var y0a,Z89;Z89=0;if(typeof z_j === "string"){return this.loadZoneFile(z_j,S7f);}S7f=S7f || ({});L9E.a9S();y0a=S7f.callback;S7f.callback=function(){var j13;j13="funct";j13+="i";j13+="on";L9E.D0H();Z89++;Z89 === z_j.length && typeof y0a === j13 && y0a();};for(var O08=+"0";O08 < z_j.length;O08++){this.loadZoneFile(z_j[O08],S7f);}};this.loadZoneFile=function(V9o,s5W){var g4U,V2m;g4U="undef";g4U+="ined";L9E.D0H();if(typeof this.zoneFileBasePath === g4U){V2m="Plea";V2m+="se define a b";V2m+="ase path ";V2m+="to your zone file directory -- timezoneJS.timezone.zoneFileBasePath.";throw new Error(V2m);}if(this.loadedZones[V9o]){return;}this.loadedZones[V9o]=!!"1";return l0F(V9o,s5W);};this.loadZoneJSONData=function(v1P,W7C){var V8J;V8J=function(q4v){q4v=JSON.parse(q4v);for(var Z4L in q4v.zones){c$Z.zones[Z4L]=q4v.zones[Z4L];}for(var P3X in q4v.rules){c$Z.rules[P3X]=q4v.rules[P3X];}};return W7C?V8J(c$Z.transport({url:v1P,async:!!""})):c$Z.transport({url:v1P,success:V8J});};function C$d(l6B){var z$t,Y1Z;z$t=r2_(l6B);Y1Z=l6B.charAt("0" << 0) === ((917.32,730.63) >= 769?0x1499:(3790,+"8881") != "816.54" * 1?"-":542.76 > (536.88,7980)?(7.07e+2,"k"):239.28)?-1:1;L9E.D0J(0);var t$s=L9E.S40(46,14);L9E.D0J(139);var v2g=L9E.q7n(7,6,14,6,8);L9E.H6P(0);var G$I=L9E.q7n(4,56);L9E.H6P(39);var f$g=L9E.q7n(20,16,2);L9E.D0J(39);var y7x=L9E.S40(20000,8,18992);z$t=Y1Z * (((z$t[0] * t$s + z$t[v2g]) * G$I + z$t[f$g]) * y7x);L9E.D0J(140);return L9E.S40(60,1000,z$t);}this.loadZoneDataFromObject=function(j01){if(!j01){return;}L9E.D0H();for(var N2Q in j01.zones){c$Z.zones[N2Q]=j01.zones[N2Q];}for(var Y3Z in j01.rules){c$Z.rules[Y3Z]=j01.rules[Y3Z];}};this.getAllZones=function(){var b88;L9E.D0H();b88=[];for(var z$u in this.zones){b88.push(z$u);}return b88.sort();};this.parseZones=function(e1H){L9E.D0H();var O$E,o6E,H0h,c$a,y2b,b$f,y$5,H4T,x$1;if(!e1H){return ![];}O$E=e1H.split(2827 !== 344?("9640" ^ 0) >= (403.59,4780)?(2030,1783) == 605.47?("z",!0):"\n":(0x1c0e,"9.56e+3" * 1):(0x10ee,396.21));o6E=[];H0h="";y2b=null;b$f=null;for(var F_U=0;F_U < O$E.length;F_U++){c$a=O$E[F_U];if(c$a.match(/^\s/)){L9E.H6P(37);c$a=L9E.q7n(c$a,"Zone ",y2b);}c$a=c$a.split(831.85 != 4243?"#":(0x9,0x6f7))[0];if(c$a.length > 3){y$5="R";y$5+="ule";H4T="Zo";H4T+="n";H4T+="e";o6E=c$a.split(/\s+/);H0h=o6E.shift();switch(H0h){case H4T:y2b=o6E.shift();if(!c$Z.zones[y2b]){c$Z.zones[y2b]=[];}if(o6E.length < +"3")break;o6E.splice(3,o6E.length,p0F(o6E));if(o6E[3]){o6E[+"3"]=Date.UTC.apply(null,o6E[3]);}L9E.H6P(10);o6E[L9E.q7n("0",0)]=-C$d(o6E[0]);c$Z.zones[y2b].push(o6E);break;case y$5:b$f=o6E.shift();if(!c$Z.rules[b$f]){c$Z.rules[b$f]=[];}o6E[0]=parseInt(o6E[0],10);o6E[1]=parseInt(o6E[1],10) || o6E[1];o6E[5]=r2_(o6E[5]);o6E[6]=C$d(o6E[6]);c$Z.rules[b$f].push(o6E);break;case "Link":if(c$Z.zones[o6E[1]]){x$1=". Cannot create link o";x$1+="f a preexis";x$1+="ted zone";x$1+=".";L9E.D0J(15);var I4U=L9E.S40(2,12,13);throw new Error("Error with Link " + o6E[I4U] + x$1);}if(isNaN(o6E[0])){c$Z.zones[o6E[1]]=o6E[0];}else {c$Z.zones[o6E[1]]=parseInt(o6E[0],10);}break;}}}return !!1;};this.transport=F0l;this.getTzInfo=function(y82,i0f,f3t){var y$T,j86,g7C,I$4;this.lazyLoadZoneFiles(i0f);L9E.D0H();y$T=d07(y82,i0f);j86=+y$T[0];g7C=E7u(y82,y$T,f3t,i0f);if(g7C){j86=F_m(j86,g7C[6]);}I$4=g7F(y$T,g7C);return {tzOffset:j86,tzAbbr:I$4};};function g7F(v0f,q9x){L9E.a9S();var c0m,i8j;c0m=v0f[2];if(c0m.indexOf("%s") > -1){if(q9x){i8j=q9x[7] === ((+"4244",8313) > 795.44?"-":(+"3060",1720) != 2550?(495,1085) != 8540?820:0x141e:"C")?"":q9x[7];}else {i8j="S";}return c0m.replace("%s",i8j);}else if(c0m.indexOf("/") > -1){return c0m.split("/",2)[q9x?q9x[6]?1:+"0":0];}return c0m;}this.lazyLoadZoneFiles=function(F_x){var E8F;if(this.loadingScheme === this.loadingSchemes.LAZY_LOAD){E8F=y3p(F_x);if(!E8F){throw new Error("Not a valid timezone ID.");}this.loadZoneFiles(E8F);}};})();}).call(typeof window !== "undefined"?window:this);n53.timezone.loadingScheme=n53.timezone.loadingSchemes.MANUAL_LOAD;n53.timezone.loadZoneDataFromObject({zones:{"Atlantic/Cape_Verde":[[60,(1960,"645.34" - 0) == ("1260" | 72)?9.46e+3:"-","-01",null]],"Africa/Cairo":[[-120,"Egypt","EE%sT",null]],"Africa/Nairobi":[[-180,+"8726" >= (3820,1270)?454.16 === (820.97,1850)?0x1be1:(267,"777.22" * 1) <= ("8860" >> 64,435.69)?![]:"-":(510.64,0xfbf),"EAT",null]],"Africa/Casablanca":[[+"0","Morocco","+00/+01",1540695600000],[-60,"Morocco","+01/+00",null]],"Africa/Windhoek":[[-120,Y27,u2u,null]],"Africa/Johannesburg":[[-120,c8l,"SAST",null]],"Africa/Tunis":[[-60,"Tunisia","CE%sT",null]],"Antarctica/Troll":[[0,"Troll",k9J,null]],"Asia/Kabul":[[-270,(5960,688.46) >= "6658" << 0?"4080" >> 32 === (8490,5660)?(![],6.25e+3):(9639,+"851") <= 4010?5.69e+3:(!!"1",6.64e+3):"-","+0430",null]],"Asia/Baku":[[-("240" >> 64),"Azer","+04/+05",null]],"Asia/Dhaka":[[-360,"Dhaka","+06/+07",null]],"Asia/Yangon":[[-390,"-","+0630",null]],"Asia/Shanghai":[[-480,"PRC",P1e,null]],"Asia/Hong_Kong":[[-480,L8w,"HK%sT",null]],"Asia/Taipei":[[-480,"Taiwan","C%sT",null]],"Asia/Nicosia":[[-120,"EUAsia","EE%sT",null]],"Asia/Kolkata":[[-330,("4365" ^ 0) == 187.6?0x4a9:"-",d7x,null]],"Asia/Tehran":[[-210,"Iran","+0330/+0430",null]],"Asia/Jerusalem":[[-120,"Zion","I%sT",null]],"Asia/Tokyo":[[-540,"Japan","J%sT",null]],"Asia/Amman":[[-120,"Jordan","EE%sT",null]],"Asia/Almaty":[[-360,"-","ALMT",null]],"Asia/Seoul":[[-540,"ROK","K%sT",null]],"Asia/Pyongyang":[[-510,(4600,4920) !== 8650?"-":(328,"641" - 0) > (6400,8460)?810.12:("5.61e+3" ^ 0,"B"),"KST","1525476600000" - 0],[-540,"-","KST",null]],"Asia/Beirut":[[-120,x$T,"EE%sT",null]],"Asia/Kuala_Lumpur":[[-480,"-","+08",null]],"Asia/Hovd":[[-+"420","Mongol",W72,null]],"Asia/Ulaanbaatar":[[-480,O0H,"+08/+09",null]],"Asia/Kathmandu":[[-345,"-",n9S,null]],"Asia/Karachi":[[-300,"Pakistan","PK%sT",null]],"Asia/Hebron":[[-("120" ^ 0),"Palestine","EE%sT",null]],"Asia/Riyadh":[[-180,6240 !== 9570?"-":+"3190" !== +"8500"?4.74e+3:(408.30,"0x2215" ^ 0),K9l,null]],"Asia/Damascus":[[-120,"Syria","EE%sT",null]],"Asia/Bangkok":[[-420,"-","+07",null]],"Asia/Dubai":[[-("240" * 1),523 > 4405?(618.86,254.59):3640 > 7.73?6076 != 316?"-":(704,!!""):(2.99e+3,![]),"+04",null]],"Australia/Darwin":[[-570,"Aus","AC%sT",null]],"Australia/Perth":[[-("480" - 0),"AW","AW%sT",null]],"Australia/Eucla":[[-("525" | 4),G3_,"+0845/+0945",null]],"Australia/Brisbane":[[-600,q23,"AE%sT",null]],"Australia/Adelaide":[[-570,"AS",X94,null]],"Australia/Hobart":[[-600,"AT",c29,null]],"Australia/Melbourne":[[-+"600","AV","AE%sT",null]],"Australia/Sydney":[[-+"600","AN","AE%sT",null]],"Australia/Lord_Howe":[[-630,"LH","+1030/+11",null]],"Pacific/Fiji":[[-720,"Fiji",g3r,null]],"Pacific/Guam":[[-600,7300 != (3842,5241)?"-":733 !== 617.35?"g":"r","ChST",null]],"Pacific/Kiritimati":[[-840,(8154,452) > (23.25,"570.31" - 0)?(!!({}),7.56e+2):"-","+14",null]],"Pacific/Noumea":[[-660,"NC","+11/+12",null]],"Pacific/Auckland":[[-720,"NZ","NZ%sT",null]],"Pacific/Chatham":[[-765,"Chatham","+1245/+1345",null]],"Pacific/Pago_Pago":[["660" >> 64,544.79 >= 1650?"z":"-","SST",null]],"Pacific/Apia":[[-780,r$L,g$w,null]],"Pacific/Tongatapu":[[-780,Q4p,"+13/+14",null]],"Etc/UTC":[[0,"-","UTC",null]],UTC:"Etc/UTC","Europe/London":[["0" * 1,"EU",i3W,null]],"Europe/Dublin":[[0,"Eire","IST/GMT",null]],WET:[[0,"EU","WE%sT",null]],CET:[[-60,"C-Eur","CE%sT",null]],MET:[[-("60" | 4),"C-Eur","ME%sT",null]],EET:[[-120,h8z,"EE%sT",null]],"Europe/Brussels":[[-60,k5y,"CE%sT",null]],"America/Thule":[["240" * 1,s6y,"A%sT",null]],"Europe/Helsinki":[[-("120" - 0),"EU","EE%sT",null]],"Europe/Paris":[[-60,A2n,j7U,null]],"Europe/Berlin":[[-60,i$J,"CE%sT",null]],"Europe/Amsterdam":[[-60,s$6,"CE%sT",null]],"Atlantic/Azores":[[60,"EU","-01/+00",null]],"Europe/Bucharest":[[-120,c55,"EE%sT",null]],"Europe/Kaliningrad":[[-+"120",(481.64,2788) < 943.03?(7.80e+3,"X"):(7150,8415) != (879.69,7816)?"-":(!![],!![]),"EET",null]],"Europe/Moscow":[[-+"180",(2202,910.18) > "81.42" - 0?"-":+"7550" >= (2956,2560)?(![],0xb33):!1,"MSK",null]],"Europe/Volgograd":[[-180,"-","+03",1540692000000],[-240,(369.94,3279) !== (938.46,452.63)?"-":!!1,Y4l,+"1609034400000"],[-180,"-","+03",null]],"Europe/Samara":[[-240,(816.67,+"1080") === 6178?71.98:(5344,+"829.24") <= +"4517"?(8992,1120) <= 5430?"-":(0xb21,!1):(!!({}),"o"),"+04",null]],"Asia/Yekaterinburg":[[-300,"-","+05",null]],"Asia/Omsk":[[-+"360","-","+06",null]],"Asia/Novosibirsk":[[-+"420",8370 === 185.29?(0x16f9,"k"):("105" ^ 0) === 4504?(7750,+"49") > (718.12,4970)?(0x15ae,!({})):("Q",0x1d15):"-","+07",null]],"Asia/Novokuznetsk":[[-420,6231 >= 496.83?+"3500" === (3622,7420)?810.79 >= (894.86,587.56)?7.10e+3:(133.25,"P"):"-":("L",896.08),"+07",null]],"Asia/Krasnoyarsk":[[-420,("831.4" - 0,7959) <= (5850,1950)?(+"55.45",6.74e+3):"-","+07",null]],"Asia/Irkutsk":[[-480,("3700" * 1,2530) > 262.35?"-":(9693,437) > (493.46,5154)?628.80:!"1","+08",null]],"Asia/Yakutsk":[[-("540" ^ 0),(304,4810) <= 4660?!!"":+"245.57" == (105.41,2571)?("1.98e+3" >> 0,"J"):"-","+09",null]],"Asia/Vladivostok":[[-("600" ^ 0),"6270" - 0 !== 9380?"-":"300.57" - 0 >= 896.31?!!0:(18.57,271.11),Q0N,null]],"Asia/Magadan":[[-+"660","-",j5L,null]],"Asia/Srednekolymsk":[[-660,("5190" * 1,925.96) != (586.59,3216)?(4190,3060) > 252.62?"-":(!!({}),84.57):(!!"1",6.15e+3),t_0,null]],"Asia/Kamchatka":[[-720,(7069,5180) == (372.83,4813)?8080 != (685.82,"9283" * 1)?(1.50e+3,+"0xccc"):"s":"-","+12",null]],"Europe/Belgrade":[[-("60" * 1),"EU","CE%sT",null]],"Europe/Sarajevo":"Europe/Belgrade","Europe/Istanbul":[[-180,"-",y11,null]],"America/New_York":[[300,"US","E%sT",null]],"America/Chicago":[[360,"US",U_G,null]],"America/Denver":[["420" << 64,"US",n9m,null]],"America/Los_Angeles":[[480,"US","P%sT",null]],"America/Juneau":[[+"540","US","AK%sT",null]],"Pacific/Honolulu":[[600,(+"1760",4920) > (2510,146.54)?3540 === (7532,+"7970")?"0xf99" ^ 0:"-":("b",396.66),f2m,null]],"America/Phoenix":[[420,754.12 !== ("8980" ^ 0)?6430 === +"4258"?(2.37e+3,"u"):"-":(0xd1a,"H"),"MST",null]],"America/St_Johns":[[+"210","Canada","N%sT",null]],"America/Halifax":[[240,s3D,"A%sT",null]],"America/Regina":[[360,+"551" != (9449,52)?"-":("2220" ^ 0,3126) !== (4394,335.52)?421.64:!!({}),"CST",null]],"America/Mexico_City":[[360,u29,"C%sT",null]],"America/Chihuahua":[[420,"Mexico",A_5,null]],"America/Costa_Rica":[[360,"CR","C%sT",null]],"America/Havana":[[300,x2f,"C%sT",null]],"America/Port-au-Prince":[[300,"Haiti",c7r,null]],"America/Panama":[[300,"-",K6K,null]],"America/Puerto_Rico":[[240,(4515,5610) >= 889.31?465.09 <= (+"434.49",7850)?"-":0x142b:(0x1b94,!"1"),"AST",null]],"America/Argentina/Buenos_Aires":[[180,"Arg",r92,null]],"America/Sao_Paulo":[["180" - 0,E_N,"-03/-02",null]],"America/Santiago":[[240,X9h,"-04/-03",null]],"America/Punta_Arenas":[[240,"Chile","-04/-03",+"1480809600000"],[180,"-","-03",null]],"America/Bogota":[[300,"CO",j4p,null]],"America/Asuncion":[[240,"Para",U25,null]],"Atlantic/South_Georgia":[[120,"-",i42,null]],"America/Montevideo":[[180,"Uruguay",S2q,null]],"America/Caracas":[[+"240",+"325.09" >= 332.98?1530 > (+"2660",1108)?(!"",131.85):9.67e+3:"-","-04",null]],"Europe/Athens":o$P,"Europe/Simferopol":J2n,"Asia/Rangoon":"Asia/Yangon","Atlantic/Reykjavik":"UTC","Asia/Kuwait":Q6W,"Asia/Muscat":"Asia/Riyadh","Asia/Istanbul":"Europe/Istanbul"},rules:{Egypt:[],Morocco:[[2013,2018,"-","Oct","lastSun",[3,0,0,null],0,"-"],[2014,2018,"7017" * 1 > (47.86,828.74)?(3920,624) !== 9910?"-":("c",501.27):!!({}),"Mar","lastSun",[2,0,0,null],"60" ^ 0,("844" ^ 0,3718) != +"9592"?"-":0x1fc3],["2017" ^ 0,"only",(270.9,416.85) <= 453.3?"-":430.22 !== "2910" * 1?2180 != (243.01,+"663")?(276.43,"a"):("h",7.55e+3):!![],"May","21",[3,0,0,null],0,"-"],[2017,"only",444.36 == 246.18?(!({}),!1):6 > (5214,9470)?6027 !== +"912"?(0x2646,6.43e+3):(!!0,8.86e+3):"-","Jul",(7440,6520) >= +"768"?(738,5567) !== +"3430"?(9600,+"2730") == ("6136" * 1,5897)?("608.16" - 0,4.59e+3):"2":(0x2699,!![]):("f",8.35e+3),[2,0,0,null],60,"-"],[2018,m17,5170 != (6023,6813)?"-":(9600,"516" * 1) <= +"2277"?(282.38,+"2481") != +"6430"?("k",0xc7e):(0x2532,!1):5.46e+3,e5C,F5e,[3,0,0,null],0,521 < 2592?"-":1342 === "5134" >> 64?742:+"9.32e+3"],[2018,"only",1621 !== 6903?(1169,6031) === 5992?("M",!({})):"-":490.23,Y4c,"17",[2,0,0,null],60,("5870" - 0,4890) != 4480?"-":!!({})],[2019,"only","-","May",5600 <= 710.65?(0x1354,![]):"5",[3,0,0,null],-+"60","-"],[2019,A8o,"-",p_e,"9",[2,0,0,null],0,713.56 > 663.49?"-":5.47e+3],[+"2020","only","-","Apr",e5P,[+"3",0,0,null],-("60" | 60),"-"],[2020,"only",(3570,"9050" ^ 0) > (2070,"7870" * 1)?"-":(+"0x1e39",5.11e+2),"May","31",[2,0,0,null],0,"-"],[2021,"only","-","Apr",x2e,[3,0,0,null],-60,(3000,2210) >= +"4410"?!"":6890 === (1360,3400)?(6360,376) < (7205,4061)?("T",!!({})):6.82e+3:"-"],[2021,"only","-","May","16",[2,0,0,null],0,(3380,5998) === (939.77,145)?0xcae:"-"],[2022,"only","-",N4h,d2I,["3" << 64,+"0",0,null],-60,+"124.86" <= (6230,4036)?"-":3.18e+3],[2022,f1q,"-","May",("8150" | 18) === 730?0x1d27:"8",[2,0,+"0",null],0,500.56 == ("8190" << 32,2171)?(0x95d,"f"):"-"],[2023,F$Q,(5524,9688) == (+"135.55",5390)?(873.76,"V"):(406.96,6156) === (+"854.81",1596)?(203.94,8570) >= (3753,"4511" * 1)?0x1bb7:(!0,0x1411):"-","Mar",o04,["3" ^ 0,0,0,null],-60,152 == 555.17?![]:"-"],[+"2023","only",(27.07,5180) > (2203,2830)?"-":("4850" ^ 0,985.19) >= (+"971",542)?960.98 <= (5386,8030)?(!!({}),"U"):0x25ca:!!0,"Apr","30",[2,"0" * 1,0,null],0,"-"],[2024,"only",5795 == 4190?0x26f3:"-","Mar",N6e,[3,0,0,null],-("60" | 16),"-"],[2024,"only",(+"8410",829.31) === (337.81,9852)?+"57" !== +"1360"?689 > 5488?9.04e+3:8.54e+3:627.16:"-","Apr","14",[2,0,"0" << 0,null],0,"-"],[+"2025",f13,877.6 > 6107?("F",!![]):980.74 < ("1486" | 4)?7270 === 3786?(0x714,1.17e+3):"-":(!!0,!![]),a3J,C13,[3,+"0",0,null],-60,265.06 > (6221,2580)?(+"246",472.28) != 5474?"R":(!![],!![]):"-"],[2025,"only","-",B4v,"6",[2,0,+"0",null],"0" ^ 0,647.04 < 6280?(2010,510.81) >= (+"123",6037)?("v",5.86e+3):(423.79,+"160.77") > 147.49?"-":7.03e+3:(79.45,!({}))]],Namibia:[["1994" << 64,2017,(3110,4393) >= (2290,228.25)?"-":7553 !== (3454,6981)?+"859.35" > (308.42,940.45)?("z",!""):(0x1288,688.87):(6.20e+3,!!({})),"Sep","Sun>=1",[2,+"0",0,null],"0" - 0,T6n],[1995,2017,8648 == 730.34?(684.69,"0xc3d" - 0):"-","Apr","Sun>=1",[2,0,0,null],-60,n_B]],SA:[],Tunisia:[],Troll:[[2005,d5J,799 >= 9800?7638 != (861,6802)?(3.58e+3,!({})):8.05e+3:"-","Mar","lastSun",[1,+"0",0,"u"],"120" ^ 0,"+02"],[2004,y9b,2861 == +"716.27"?7.81e+3:6025 === (327.6,3430)?(8702,4470) !== 260.17?(0x1661,!![]):365:"-","Oct","lastSun",[1,0,0,8530 == 599.62?(!!"","O"):("6430" << 64,9215) >= (2190,888.28)?(4032,8162) > +"186.67"?"u":"0x2602" ^ 0:("o",![])],+"0","+00"]],EUAsia:[[1981,"max","-",s7n,"lastSun",[1,0,0,(695.52,6790) >= (+"4570",39)?"u":"i"],60,(5610,1015) >= (820.83,9541)?913.92:751.51 >= 5440?(609,343.72) < 3529?7.00e+3:"h":"S"],[1996,k2Y,+"907.79" > (790.09,6530)?"N":471.72 <= (993.59,2900)?"-":("V","i"),"Oct","lastSun",[1,"0" | 0,0,"u"],0,"-"]],Azer:[],Dhaka:[],PRC:[],HK:[],Taiwan:[],Iran:[[2017,2019,(133,6198) === 2710?(755.13,5.47e+3):(8148,642.81) < 8087?"-":7030 == 8243?("6.73e+3" - 0,6.56e+3):(0x46b,"E"),"Mar","21",[24,0,0,null],60,"-"],[2017,"2019" >> 0,"-","Sep",I7s,[24,"0" * 1,0,null],0,"-"],[2020,"only","-",K6e,"20",[24,0,+"0",null],"60" ^ 0,137.67 <= (201.02,27.29)?("6511" | 0,"1094" << 0) === "272.84" - 0?(0x1b04,!!1):394.20:"-"],[2020,"only",5007 <= (303,3900)?(3829,440.15) !== (6114,2434)?50.76:(3.01e+3,0x107b):"-","Sep","20",[24,0,0,null],"0" ^ 0,(8810,469.88) > 4789?(!!1,"H"):"-"],[2021,2023,624.05 === 6030?1.54e+3:9433 > 7200?"-":(57.92,!!({})),"Mar","21",[24,0,0,null],60,(987.55,6346) === (180,685.37)?"0x1478" >> 0:"-"],["2021" - 0,2023,"-","Sep","21",[24,0,0,null],0,992.95 === (3227,989.6)?(403.00,"g"):(+"7900",275) != 4490?"-":("6046" ^ 0,887) > (4071,4230)?![]:8.52e+3],[2024,"only",(+"3270",5410) == (4839,7141)?(510.47,+"871.27") <= (5046,845.46)?("d",94.02):4630 === "407" * 1?(!!({}),0x1b1b):241:"-","Mar","20",[24,0,+"0",null],60,("916.09" * 1,130.21) > 868.9?664.65 < (816.99,9499)?0x6cb:"g":"-"],[2024,"only","-","Sep",a8E,[24,0,0,null],0,"-"],[2025,2027,("3270" * 1,"8680" << 32) > (6271,633)?"2910" >> 64 >= 4803?"1689" - 0 === (337.12,674.37)?"J":("358.91" * 1,"k"):"-":2.40e+3,"Mar","21",[24,0,0,null],"60" | 20,8.13 !== 875.04?46.38 == 1760?(1540,1816) == "2270" >> 64?(953.81,+"0x10b6"):(!!"1","H"):"-":"O"],[2025,2027,(+"263.65",8754) >= (237.67,654.43)?(966.84,6993) !== 1375?"-":258.28:617,"Sep","21",[24,0,"0" ^ 0,null],0,637.73 == 497.73?("U",149.43):"-"]],Zion:[[2013,"max","-","Mar","Fri>=23",[2,0,0,null],60,"2170" * 1 >= 3440?+"0x14ba":"D"],[2013,"max",(280.69,880.7) === 5280?0x671:"-","Oct",U9l,["2" - 0,0,0,null],0,(33.11,931.99) == 8290?(+"747.98",2526) === (441.99,944)?(5.64e+3,!"1"):"c":"S"]],Japan:[],Jordan:[[2014,"max","-","Mar","lastThu",[24,0,0,null],"60" - 0,"S"],[2014,E5z,7663 === 1090?683 != ("5390" | 6)?0x536:(1.15e+3,8.55e+3):"-",A6s,"lastFri",[0,"0" | 0,0,(4350,186.86) === (7414,8226)?+"68.10":(6531,+"3557") < ("548" << 32,8982)?"s":0xcf1],0,(933.29,720.43) != (1570,351.34)?"-":934.96]],ROK:[],Lebanon:[[1993,"max",7970 <= 4660?(1290,187) != 7110?(267.37,+"190.49") == +"118.81"?"U":("2.24e+3" | 0,324):(454.15,0x22df):"-","Mar","lastSun",[0,0,"0" - 0,null],"60" * 1,"S"],[+"1999","max",(+"1726",4750) !== (575.8,"3730" >> 0)?(874.93,2950) > 9336?("9305" | 65,6267) == (2250,1551)?!![]:(!!"",0x2082):"-":("d",0x508),p4_,d3p,[0,0,0,null],0,+"6749" <= 644?(+"0x1be9",0x18b7):(701.4,2860) >= 7151?(179.11,443.73) > (+"760.56",345.8)?(115.47,2.30e+3):!!"1":"-"]],Mongol:[],Pakistan:[],Palestine:[[2016,2018,"-","Mar","Sat>=24",[1,0,0,null],60,"S"],[2016,2018,(7730,221.69) !== 718.84?(206.74,4750) >= (201.79,843)?"-":"l":"p","Oct",q2Y,[1,0,0,null],0,(3985,111.13) !== 32?"-":8530 != (615,1150)?7939 !== (1860,7210)?(!!({}),0x1475):(0x1e76,!!1):(!"1","g")],[2019,"only",(+"558.46",9790) > 1470?(2380,6519) >= 50.35?"-":+"0x3ac":"l","Mar","29",[0,0,0,null],60,887.93 < (948.15,156.23)?("X",!!"1"):9188 == 6108?(2140,8210) != 2050?!({}):(4.28e+3,"J"):"S"],[2019,"only",247.43 != 1600?(2113,+"356.29") === (7875,922.67)?7.57e+3:2540 >= (7989,"1658" * 1)?"-":!"":(![],+"278.21"),"Oct","Sat>=24",["0" * 1,0,0,null],"60" << 0,(+"7549",7750) == 8510?289.92:(2290,350) > 1580?("c","Z"):"-"],[2020,"max",(9620,+"135.58") >= (5717,+"7253")?803.79 == 255.59?(0x21ac,0x1e33):4881 >= 1010?(301.86,+"3.90e+2"):"x":"-",n5A,"Sat>=24",[0,0,0,null],60,(9598,+"7017") === (518.28,9500)?(497.70,+"6.87e+3"):791.4 > 2466?0x2ca:"S"],[2020,"max","-","Oct","Sat>=24",[1,+"0",0,null],60,"-"]],Syria:[["2012" | 24,"max",(605.81,+"337.16") > (7880,6860)?(+"60.45","6.84e+3" | 8):"-","Mar","lastFri",["0" ^ 0,+"0",+"0",null],60,4318 != 7848?8100 === (+"9553",1350)?(4.20e+3,0x1377):"S":("x","N")],[+"2009",v4z,"-","Oct","lastFri",[0,"0" ^ 0,"0" << 64,null],0,(948,7011) !== 9510?"-":962 > (2590,6770)?(9.85e+3,5.95e+3):(715.14,!!"")]],Aus:[],AW:[],AQ:[],AS:[[+"2008","max",2689 != (8450,16.81)?1654 == (3390,+"7300")?"k":"-":"r",d0A,"Sun>=1",[2,0,+"0","s"],0,("655" | 2,4799) !== (49.99,1107)?145.16 < (3150,1351)?(834,1440) != 1041?"S":342.15:(!!0,65.37):(!"1",457.70)],[2008,K_p,(+"2577",7793) >= (312.34,+"9002")?125.08:"-","Oct",r_7,[2,0,0,"s"],60,("759" | 36,831) < (8380,656)?!1:2997 < 7940?"D":975.51]],AT:[[2001,"max","-",t6U,"Sun>=1",[2,"0" << 64,0,1020 <= 5570?"s":!1],"60" - 0,"D"],[2008,F1S,"-","Apr","Sun>=1",[2,+"0",0,(9230,+"980.78") !== +"142"?"s":5751 < 764.82?(![],!!0):("0x1452" * 1,"g")],0,418.22 < (803.34,6200)?"S":"D"]],AV:[[2008,"max",642.31 == (887.84,4580)?("g",+"849"):8463 >= 5220?77.25 != (785.98,92.39)?"-":0x2554:!({}),t3R,F0q,[2,0,0,(+"689.73",5390) === (593,"70" - 0)?(+"1760",1363) === 6090?943.68:(876.01,"D"):"s"],0,"S"],[2008,"max","-","Oct","Sun>=1",[2,"0" - 0,0,(1840,5670) < 5520?0x11e6:+"5742" === 227.22?+"289.55":"s"],+"60",(4420,7913) !== "4000" - 0?"D":(![],"0x1b30" | 32)]],AN:[[2008,o7p,(52,23.86) < ("671.96" * 1,9590)?"-":(416,119.41),"Apr","Sun>=1",[+"2",+"0",0,(524.1,9483) !== (344,396)?"s":604.99 === (164,+"2920")?(997,997.44):(4788,120.34) > 501.58?1.20e+3:8.09e+3],+"0",6160 >= "4392" >> 0?"S":!({})],[+"2008",Y9q,"-","Oct","Sun>=1",[2,0,0,"s"],60,(9567,424) < (193.17,9253)?7858 != (7320,63.52)?+"976.2" >= (+"4640",940.99)?"D":("a",6.90e+3):(!1,+"626.85"):"N"]],LH:[[+"2008",X84,"-","Apr",d4i,[+"2",+"0",0,null],0,307 <= (549.71,365.33)?"-":"124.27" * 1 > 1340?!!"1":9865 > (91.12,3980)?(4.44e+3,494):(3.20e+3,331.76)],[2008,"max",(+"3793",2678) == (8868,824.12)?7.37e+3:2229 >= "59" - 0?"-":"638.61" - 0,S6F,"Sun>=1",[2,"0" * 1,0,null],30,"-"]],Fiji:[[2014,2018,"-","Nov","Sun>=1",[2,0,+"0",null],+"60","-"],[2015,"max",3730 >= 953.83?(3073,4730) >= ("600.11" - 0,9731)?![]:"-":583,"Jan","Sun>=12",[3,0,0,null],"0" | 0,(4085,"5090" | 34) >= ("984.82" * 1,1360)?(+"2691","141.05" - 0) < ("4870" | 0,8540)?"-":(!!"",!!0):(7.54e+3,"1.43e+3" >> 32)],[2019,l7u,(7360,"3440" >> 64) <= 441?"139.64" * 1:506.59 != "570.43" * 1?"-":(7.77e+3,"h"),"Nov",M1n,[2,+"0",0,null],60,"-"],[2020,r86,7760 <= (+"34",+"184.46")?(4910,193.5) > "4110" * 1?("0xbf5" - 0,6.29e+3):(0x2094,![]):"-","Dec","20",[+"2","0" * 1,0,null],+"60",71.82 !== (+"721.13",4620)?"-":(0xb3a,6.39e+3)],[2021,"max","-","Nov","Sun>=8",[+"2",0,0,null],"60" * 1,(+"867.13",3282) > (1852,2913)?"-":("5933" * 1,8455) !== (1130,1224)?386.96 == (698.84,9110)?![]:!!1:("v",411.01)]],NC:[],NZ:[[2007,"max","-",p2x,"lastSun",[2,0,0,("117.43" - 0,+"2260") <= (2003,"3720" * 1)?"s":638.15 < 384?8.11e+3:("s",0x1e9a)],60,+"566.19" < 7670?"D":(6966,7500) != 8288?"M":(!"1","M")],[2008,"max","-",h$f,v5$,[2,0,+"0",(8417,220) < 4970?("6790" | 0) == 958?"371.87" * 1:"s":(153.50,485.13)],0,4690 >= 613.82?(3608,293.47) >= 246.69?563.82 > ("9351" ^ 0,1235)?("G",!1):"S":5.95e+3:("R","1.77e+3" << 64)]],Chatham:[[2007,"max","-","Sep","lastSun",[2,"45" << 32,0,"s"],60,7750 < ("976" | 16)?(![],0x162b):"-"],[2008,r$P,"-",Y_p,X9J,[2,45,0,808 < (+"8260",9670)?9330 <= (734.71,6703)?4.97e+3:(5880,50) <= (97,58.01)?"s":9.25e+3:(!"1","9.00e+3" << 32)],0,"-"]],WS:[[+"2012","max","-","Apr","Sun>=1",[4,0,0,null],0,"-"],[2012,"max",2400 >= (168.79,305.61)?("280.21" * 1,5356) < (4449,277.55)?(0x25f8,375.24):("9595" ^ 0) === +"9358"?("g",!!({})):"-":("l",0xff3),"Sep","lastSun",[3,0,0,null],60,(3337,3185) !== (2251,6867)?6506 > (3890,5010)?"-":(7740,2760) !== (95.81,898.55)?(6.92e+3,+"3.98e+3"):(![],!!1):(0x249b,!({}))]],Tonga:[[2016,"only",483.85 == +"4234"?9.66e+3:656 < +"3150"?4935 === 696?(![],"1.89e+2" * 1):"-":(!!({}),"0x17e7" << 32),"Nov","Sun>=1",[2,0,0,null],60,(368,3869) == (7932,"436.55" * 1)?647 > (7640,240.22)?(0x233b,744.81):467.32:"-"],[2017,a12,8071 > (+"1540",289)?"-":(424.92,7635) >= 5475?(7630,2076) === (789.12,591.19)?(2.32e+3,2.75e+3):(0x1de4,558.16):"A","Jan",k1L,[3,+"0",0,null],0,"-"]],Eire:[["1981" << 32,x7Q,("424" | 0) == (306,9540)?(!0,"U"):(552.3,591.37) <= 285?(!!"",0x254f):"-","Mar",U17,[1,+"0","0" - 0,7757 >= +"6718"?(267.13,5483) !== +"8532"?(2322,3328) == 2380?2.49e+3:"u":!({}):0x200c],0,(+"6715",5642) !== (45.11,1619)?(3090,1570) >= 5938?("20.90" - 0,"0x26da" >> 0):"-":0xb2f],[1996,b9l,(4880,764.21) > 5227?!![]:"-","Oct","lastSun",[+"1",+"0",0,("826.29" * 1,3340) >= 5181?(0x2521,7.29e+3):"u"],-60,"-"]],EU:[["1981" | 12,"max","-","Mar","lastSun",[1,0,0,(516.75,661.65) < 525?(+"4.57e+3",920.12):"u"],60,+"3640" > "5724" - 0?(369.14,!({})):2020 >= 528.41?"S":(0x1d8d,379.16)],[1996,W6m,7691 <= (+"6930",+"4749")?(1539,4258) <= (960,7761)?1720 >= 417.99?("U",+"951.14"):0x120c:!"":"-","Oct","lastSun",[1,0,"0" | 0,4490 == (3189,502)?676.56 < (7229,3950)?(7040,596.88) === (2800,940.48)?"b":(1.29e+3,"834" - 0):567.67:"u"],0,902.39 != 151.64?"-":(9010,565.52) == 118.41?("K","X"):750.06]],"C-Eur":[[1981,"max","-","Mar","lastSun",[+"2",0,0,(7505,1070) > ("81.09" * 1,"46" * 1)?(3163,824.18) < (182.52,164.95)?"0xc21" << 32:"s":(8.87e+3,0x1210)],60,"S"],[1996,"max","-","Oct",E7Y,[2,+"0",0,"s"],0,("3470" ^ 0,+"880.25") <= 1537?"-":2560 > 6220?("b",6.32e+3):"479.71" - 0 != (434,"9362" >> 32)?(766.25,+"4.21e+3"):(!![],1.93e+3)]],Thule:[[+"2007","max",6872 == (2100,955.05)?128.63:(+"1333",70.18) <= (28,+"671.84")?"-":"7.71e+3" | 6,a0Z,"Sun>=8",[2,+"0",0,null],60,8020 === 41.38?("S",413.02):"D"],[2007,w$C,"-",o6d,"Sun>=1",[2,0,0,null],0,9400 != 8670?"S":4.97e+3]],US:[[2007,"max","-",j0G,"Sun>=8",[2,0,0,null],60,"D"],[2007,w2F,"-","Nov",C5q,[2,+"0","0" << 0,null],0,"S"]],Canada:[[2007,w5R,"-",X8v,G9R,[2,0,0,null],60,(4872,764.23) == 4740?(!"","c"):(3610,+"511.41") >= +"541"?908.36:"D"],[2007,"max","-","Nov","Sun>=1",[2,+"0",0,null],0,467 <= ("4530" ^ 0)?7210 >= (4836,867)?("754.07" * 1,+"936.74") === 733.1?("0x1be5" - 0,"459.66" - 0):"S":(+"0x6f",521.29):137]],Mexico:[[2002,f91,7380 == (211,7820)?("k",710.06):(936.84,164.19) !== (5860,187)?"-":(2280,698.61) > 1224?"R":!![],"Apr","Sun>=1",[2,"0" >> 32,"0" - 0,null],60,4980 >= (2050,+"270.27")?"D":7435 !== 1930?("F",0x1fd9):(+"0x934",720.63)],[+"2002",i4R,(654.96,+"2106") > (2140,319.82)?686.79 !== 507?"-":(130.63,745.74) !== 2816?9.61e+3:"u":("a",+"0x12b2"),"Oct",N8S,["2" * 1,0,"0" - 0,null],0,"333.25" * 1 >= ("210" | 2)?987.79 >= 9880?(0x4df,6.55e+3):"S":"G"]],CR:[],Cuba:[[2012,"max",877.5 >= 6147?(181.94,0x14e0):(4400,6200) > (1710,8559)?0x259c:("494.71" - 0,6400) !== 8171?"-":909.46,M8l,f4F,[0,"0" - 0,+"0","s"],0,"S"],["2013" >> 32,"max",(+"7782","8480" * 1) != (1182,77.79)?"-":(255.07,8423) !== (7110,1609)?("0x125b" - 0,924.12):(136.35,!![]),"Mar","Sun>=8",[0,0,0,"s"],"60" ^ 0,105 != 1760?"D":0x194e]],Haiti:[[2017,"max",3140 > "534.75" * 1?"-":(148.18,"d"),"Mar",j1J,[2,0,0,null],"60" * 1,"D"],[2017,"max","-","Nov",b0l,[2,0,0,null],"0" ^ 0,"S"]],Arg:[],Brazil:[[2008,2017,"-","Oct","Sun>=15",["0" ^ 0,0,0,null],60,(1980,5037) != 269?578.66 === (3735,+"6141")?("2337" ^ 0) <= (1287,157.08)?("f",0x13cb):("0x1d30" * 1,"E"):"-":"373.00" ^ 0],[2016,+"2019",23.21 <= (607.13,+"5480")?"-":"0x925" ^ 0,"Feb","Sun>=15",[+"0","0" ^ 0,0,null],0,(623,6760) < 355.27?!!"":(1143,5720) < (2078,762)?!!0:"-"],[2018,X7_,(4463,980) != 9230?"-":(103.26,0x4b),w69,"Sun>=1",["0" | 0,0,0,null],"60" - 0,(1980,"3920" << 32) != (9456,628.89)?"-":(!({}),"f")]],Chile:[[2016,2018,(155,6011) != (7969,6320)?"-":+"1689" === 2070?0x1bd6:(7830,1920) < +"6930"?!1:(9.19e+3,!!"1"),z1v,D_T,[3,0,0,"u"],0,(289,1770) === (7796,"359.26" * 1)?("g",!!1):"-"],[+"2016",2018,473.26 === (9150,5492)?"5040" * 1 <= (6720,+"8690")?(!0,75.83):(0x104f,0x212d):"-","Aug","Sun>=9",[4,0,0,2224 !== 187.02?"u":1.77e+3],60,9140 == ("2440" ^ 0)?!!1:"-"],[+"2019","max",(5310,3280) >= 5960?8050 >= 8130?!"":!!0:"-","Apr","Sun>=2",[3,+"0","0" * 1,"u"],0,(9250,742.52) <= 1081?"-":(8312,160.43) < 8100?("g",565.36):325.30],[2019,"max","-","Sep",v_c,[+"4",0,0,"u"],60,"128.52" - 0 == (6662,"308" << 64)?5382 === ("87.44" - 0,2627)?(0x9f7,+"7.24e+3"):(+"0x166a","g"):"-"]],CO:[],Para:[["2010" - 0,g9J,"-","Oct",I6f,[0,"0" * 1,0,null],60,(7200,7950) == 2757?(1450,639) !== (754,849.29)?"4.54e+3" >> 32:0x1ff1:"-"],[2013,b9a,(640.95,3010) <= (5550,143.53)?581.14:"-","Mar","Sun>=22",[0,0,+"0",null],0,"-"]],Uruguay:[]}});};o8=C4d=>{var m8b,x6D;m8b=typeof _CIQ !== "undefined"?_CIQ:C4d.CIQ;m8b.ChartEngine.prototype.touchSingleClick=function(x$M,p0n,X5k){var Y0Z,T$Y;A2IFV.a9S();Y0Z=this;T$Y=arguments;return function(){(function(){var U1R,M7y,p9S,z02,J7w;U1R="touc";U1R+="hSingl";U1R+="eC";U1R+="lick";if(!this.cancelTouchSingleClick){if(this.runPrepend("touchSingleClick",T$Y)){return;}if(this.editingAnnotation){return;}this.clicks={s1MS:-("1" ^ 0),e1MS:-1,s2MS:-1,e2MS:-1};if(!this.displayCrosshairs){return;}if(!this.displayInitialized){return;}if(this.openDialog !== ""){return;}if(p0n < this.left || p0n > this.right || X5k < this.top || X5k > this.bottom){return;}M7y=this.backOutY(m8b.ChartEngine.crosshairY);p9S=this.backOutX(m8b.ChartEngine.crosshairX);this.currentPanel=this.whichPanel(M7y);z02=this.currentVectorParameters.vectorType;if(!m8b.Drawing || !z02 || !m8b.Drawing[z02] || !new m8b.Drawing[z02]().dragToDraw){if(!this.drawingClick(this.currentPanel,p9S,M7y)){v0N(this,p0n,X5k);}if(!this.currentVectorParameters.vectorType){J7w=this.activeMarker && this.activeMarker.click({cx:p9S,cy:M7y,panel:this.currentPanel});if(!J7w){this.dispatch("tap",{stx:this,panel:this.currentPanel,x:p9S,y:M7y});}}}}this.runAppend(U1R,T$Y);}).apply(Y0Z,T$Y);};};m8b.ChartEngine.prototype.touchDoubleClick=function(O06,t1o,T9y){var U0X,D7h,y$B,z5m,y8L,A5a;U0X="d";U0X+="ou";U0X+="bl";U0X+="eTap";D7h="touchDoubleCl";D7h+="ic";D7h+="k";y$B=654591386;z5m=-1914874400;y8L=2;for(var c0C=1;A2IFV.Z2Z(c0C.toString(),c0C.toString().length,20973) !== y$B;c0C++){if(this.runPrepend("",arguments)){return;}if(this.editingAnnotation){return;}y8L+=2;}if(A2IFV.U6$(y8L.toString(),y8L.toString().length,82311) !== z5m){if(this.runPrepend("",arguments)){return;}if(this.editingAnnotation){return;}}if(this.runPrepend(D7h,arguments)){return;}if(this.editingAnnotation){return;}if(m8b.ChartEngine.drawingLine){return this.undo();}if(this.activeDrawing){return;}v0N(this,t1o,T9y);A5a=this.activeMarker && this.activeMarker.doubleClick({cx:t1o,cy:T9y,panel:this.currentPanel});A2IFV.D0H();if(!A5a){this.dispatch(U0X,{stx:this,finger:O06,x:t1o,y:T9y});}this.runAppend("touchDoubleClick",arguments);};m8b.ChartEngine.prototype.startProxy=function(v_V){var b5r;b5r="to";b5r+="u";b5r+="c";b5r+="h";this.touchPointerType=v_V.pointerType;if(this.touchPointerType != b5r){this.mouseMode=!"";return;}this.mouseMode=!1;this.touches[this.touches.length]={pointerId:v_V.pointerId,pageX:v_V.clientX,pageY:v_V.clientY,clientX:v_V.clientX,clientY:v_V.clientY};this.changedTouches=[{pointerId:v_V.pointerId,pageX:v_V.clientX,pageY:v_V.clientY,clientX:v_V.clientX,clientY:v_V.clientY}];if(this.touches.length == +"1"){this.gesturePointerId=v_V.pointerId;}this.touchstart(v_V);};m8b.ChartEngine.prototype.moveProxy=function(M0J){if(M0J.pointerType && M0J.pointerType != "touch"){this.mouseMode=!!1;return;}A2IFV.a9S();this.mouseMode=!1;this.touchmove(M0J);};m8b.ChartEngine.prototype.endProxy=function(I0p){var R2M=A2IFV;var H09,n_G,w4U,x3z;if(this.touchPointerType != "touch"){this.mouseMode=!!({});return;}this.mouseMode=![];H09=this.touches.length;for(var H4d=0;H4d < this.touches.length;H4d++){if(this.touches[H4d].pointerId == I0p.pointerId){this.touches.splice(H4d,1);break;}}if(H4d == H09){this.touches=[];this.grabbingScreen=!1;this.touching=!!"";return;}this.changedTouches=[{pointerId:I0p.pointerId,pageX:I0p.clientX,pageY:I0p.clientY,clientX:I0p.clientX,clientY:I0p.clientY}];R2M.D0J(28);n_G=-R2M.q7n("802980364",64);w4U=-1900874754;x3z=2;for(var j3o=1;R2M.U6$(j3o.toString(),j3o.toString().length,23292) !== n_G;j3o++){this.touchend(I0p);x3z+=2;}if(R2M.Z2Z(x3z.toString(),x3z.toString().length,1617) !== w4U){this.touchend(I0p);}};m8b.ChartEngine.prototype.msMouseMoveProxy=function(T$R){if(this.touches.length || !this.mouseMode){return;}this.mousemove(T$R);};m8b.ChartEngine.prototype.msMouseDownProxy=function(O1p){A2IFV.a9S();if(!this.mouseMode){return;}this.mousedown(O1p);};m8b.ChartEngine.prototype.msMouseUpProxy=function(V5V){A2IFV.D0H();if(!this.mouseMode){return;}this.mouseup(V5V);};m8b.ChartEngine.prototype.iosMouseMoveProxy=function(W9T){if(this.touching){return;}A2IFV.a9S();this.mousemove(W9T);};m8b.ChartEngine.prototype.iosMouseDownProxy=function(S3e){if(this.touching){this.mouseMode=!1;return;}this.mouseMode=!![];A2IFV.a9S();this.mousedown(S3e);};m8b.ChartEngine.prototype.iosMouseUpProxy=function(b6G){if(this.touching){return;}this.mouseup(b6G);};m8b.ChartEngine.prototype.touchmove=function(s0o){var z_B=A2IFV;var z0C,q7y,k66,i8L,P8b,O8y,h4u,G49,M1J,A_7,U8i,h5P,u__,o_M,P3e,V3o,U6j,F3j,z8N,T2R,a6O,b6x,W6N,l6R,c4i,j7A,s9V,G7K,y5V,w9D,x6F,v7U,R3x,g6b,n0N,G1m,H$5,r9I,j7d,O3g;if(!this.displayInitialized){return;}if(this.openDialog !== ""){return;}if(m8b.ChartEngine.ignoreTouch === !!1){return;}z0C=[];if(!this.overYAxis || this.controls && this.controls.crossX && this.controls.crossX.style.display != "none"){if(s0o && s0o.preventDefault && s0o.cancelable && this.captureTouchEvents){s0o.preventDefault();}if(s0o){s0o.stopPropagation();}}q7y=new Date().getTime();if(this.clicks.s2MS == -1){this.clicks.e1MS=q7y;if(this.clicks.e1MS - this.clicks.s1MS < +"25"){return;}}else {this.clicks.e2MS=q7y;if(this.clicks.e2MS - this.clicks.s2MS < 25){return;}}if(!s0o.pointerType){s0o.pointerType=this.touchPointerType;}if(m8b.isSurface){if(this.mouseMode){return;}if(!s0o.pointerId){s0o.pointerId=this.gesturePointerId;}for(var j4I=0;j4I < this.touches.length;j4I++){if(this.touches[j4I].pointerId == s0o.pointerId){k66=Math.abs(this.touches[j4I].pageX - s0o.clientX);i8L=Math.abs(this.touches[j4I].pageY - s0o.clientY);z_B.H6P(42);P8b=Math.sqrt(z_B.q7n(k66,i8L,k66,i8L));if(!P8b){return;}this.clicks.e1MS=new Date().getTime();if(this.clicks.e1MS - this.clicks.s1MS < 50){return;}if(this.touches[j4I].pageX == s0o.clientX && this.touches[j4I].pageY == s0o.clientY){return;}this.touches[j4I].pageX=this.touches[j4I].clientX=s0o.clientX;this.touches[j4I].pageY=this.touches[j4I].clientY=s0o.clientY;break;}}if(j4I === 0){this.movedPrimary=!![];}else {this.movedSecondary=!"";}if(j4I == this.touches.length){return;}this.changedTouches=[{pointerId:s0o.pointerId,pageX:s0o.clientX,pageY:s0o.clientY,clientX:s0o.clientX,clientY:s0o.clientY}];z0C=this.touches.length?this.touches:this.changedTouches;}else {z0C=s0o.touches;this.changedTouches=s0o.changedTouches;}if(z0C.length == 1){if(Math.pow(this.clicks.x - z0C[0].clientX,2) + Math.pow(this.clicks.y - z0C[0].clientY,2) <= 16){return;}}O8y=this.crosshairXOffset;h4u=this.crosshairYOffset;G49=this.currentVectorParameters.vectorType && this.currentVectorParameters.vectorType !== "";M1J=!this.layout.crosshair && !G49 && !this.touchNoPan;if(s0o.pointerType == "pen" || M1J || this.activeDrawing && this.activeDrawing.name == "freeform"){z_B.D0J(7);O8y=h4u=z_B.q7n(0,"0");}if(this.runPrepend("touchmove",arguments)){return;}if(m8b.ChartEngine.resizingPanel){h5P=z0C[0];A_7=h5P.clientX;U8i=h5P.clientY;z_B.D0J(0);this.mousemoveinner(z_B.q7n(A_7,O8y),z_B.q7n(U8i,h4u));return;}z_B.D0H();if(this.moveB != -1){this.touchMoveTime=new Date();}this.moveA=this.moveB;this.moveB=z0C[0].pageX;if(z0C.length == 1 && !this.twoFingerStart){o_M=z0C[0];A_7=o_M.clientX;U8i=o_M.clientY;this.pinchingScreen=0;z_B.D0J(0);this.mousemoveinner(z_B.S40(A_7,O8y),z_B.S40(U8i,h4u));P3e=this.whichPanel(U8i);V3o=this.xAxisAsFooter === !!1?this.chart.canvasHeight:this.chart.panel.bottom;this.overXAxis=U8i <= this.top + V3o && U8i >= V3o - this.xaxisHeight + this.top && this.insideChart;if(!P3e){this.overYAxis=!1;}else {this.overYAxis=(A_7 >= P3e.right || A_7 <= P3e.left) && this.insideChart;}}else if(z0C.length == 2 && this.allowZoom){if(!this.displayCrosshairs){return;}U6j=z0C[0];F3j=U6j.clientX;z8N=U6j.clientY;T2R=z0C[1];a6O=T2R.clientX;b6x=T2R.clientY;z_B.D0J(141);u__=Math.sqrt(z_B.q7n(z8N,a6O,z8N,b6x,b6x,a6O,F3j,F3j));z_B.D0J(0);var V9I=z_B.q7n(0,2);this.pinchingCenter=(Math.min(F3j,a6O) - Math.max(F3j,a6O)) / V9I;W6N=Math.round(this.gestureStartDistance - u__);if(M1J){this.pinchingScreen=5;}this.clearPixelCache();if(this.pinchingScreen < 2){if(m8b.isSurface && (!this.movedPrimary || !this.movedSecondary)){return;}if(F3j < this.pt.x1 && a6O < this.pt.x2 || F3j > this.pt.x1 && a6O > this.pt.x2 || z8N < this.pt.y1 && b6x < this.pt.y2 || z8N > this.pt.y1 && b6x > this.pt.y2){this.pinchingScreen=0;}else {this.pinchingScreen++;if(this.pinchingScreen < 2){return;}}}this.pt={x1:F3j,x2:a6O,y1:z8N,y2:b6x};if(this.pinchingScreen === 0){this.grabMode="pan";z_B.H6P(0);this.mousemoveinner(z_B.S40(F3j,O8y),z_B.q7n(z8N,h4u));this.gestureStartDistance=u__;}else {l6R=Math.asin((Math.max(b6x,z8N) - Math.min(b6x,z8N)) / u__);if(Math.abs(W6N) < 12 && !M1J){this.moveCount++;if(this.moveCount == 4){this.pinchingScreen=0;this.moveCount=0;return;}}else {this.moveCount=0;}if(l6R < 1 || !this.goneVertical && l6R < 1.37){if(!this.currentPanel){return;}c4i=this.currentPanel.chart;this.goneVertical=![];u__=this.pt.x2 - this.pt.x1;j7A=this.grabStartValues.t2 - this.grabStartValues.t1;s9V=this.grabStartValues.t1 + j7A / ("2" ^ 0);z_B.D0J(14);G7K=z_B.q7n(j7A,u__);if(c4i.allowScrollFuture === !"1" && c4i.allowScrollPast === !({})){G7K=Math.max(G7K,c4i.width / c4i.dataSet.length);}y5V=this.layout.candleWidth;this.setCandleWidth(G7K,c4i);if(c4i.maxTicks < this.minimumZoomTicks){this.setCandleWidth(y5V,c4i);return;}this.micropixels=0;w9D=this.pixelFromTick(Math.round(s9V),c4i);x6F=this.pt.x1 - this.left + Math.round(u__ / +"2");z_B.H6P(7);v7U=z_B.q7n(x6F,w9D);z_B.H6P(14);R3x=z_B.q7n(G7K,v7U);g6b=Math.round(R3x);c4i.scroll-=g6b;z_B.H6P(7);this.microscroll=z_B.q7n(R3x,g6b);this.micropixels=G7K * this.microscroll;this.draw();}else {n0N=this.grabStartYAxis;this.goneVertical=!0;if(n0N){G1m=-396170675;H$5=1039071863;r9I=2;for(var W5N=+"1";z_B.U6$(W5N.toString(),W5N.toString().length,47121) !== G1m;W5N++){n0N.zoom=this.grabStartZoom + (this.gestureStartDistance - u__);r9I+=2;}if(z_B.U6$(r9I.toString(),r9I.toString().length,+"25025") !== H$5){n0N.zoom=this.grabStartZoom % (this.gestureStartDistance + u__);}if(this.grabStartZoom < n0N.height){if(n0N.zoom >= n0N.height){z_B.H6P(41);var r_W=z_B.q7n(6,17,103);n0N.zoom=n0N.height - r_W;}}else {if(n0N.zoom <= n0N.height){z_B.D0J(142);var d$1=z_B.S40(14,6,12,447,6);n0N.zoom=n0N.height + d$1;}}this.draw();;}}this.updateChartAccessories();}}else if(z0C.length == 3 && m8b.ChartEngine.allowThreeFingerTouch){if(!this.displayCrosshairs){return;}j7d=z0C[0];O3g=j7d.clientX;u__=this.grabStartX - O3g;z_B.D0J(143);var o0X=z_B.S40(1,6,4,190,190);this.grabEndPeriodicity=this.grabStartPeriodicity + Math.round(u__ / o0X);if(this.grabEndPeriodicity < 1){z_B.D0J(21);this.grabEndPeriodicity=z_B.S40("1",0);}}this.runAppend("touchmove",arguments);};function v0N(S$_,i2d,P$Z){var U9M;if(!S$_.layout.crosshair){m8b.ChartEngine.crosshairY=0;m8b.ChartEngine.crosshairX=0;S$_.cx=S$_.backOutX(0);S$_.cy=S$_.backOutY(0);S$_.findHighlights(null,!!1);m8b.ChartEngine.crosshairY=P$Z;m8b.ChartEngine.crosshairX=i2d;U9M=S$_.container.getBoundingClientRect();S$_.top=U9M.top;S$_.left=U9M.left;S$_.right=S$_.left + S$_.width;S$_.bottom=S$_.top + S$_.height;S$_.cx=S$_.backOutX(i2d);S$_.cy=S$_.backOutY(P$Z);if(S$_.currentPanel && S$_.currentPanel.chart.dataSet){S$_.crosshairTick=S$_.tickFromPixel(S$_.cx,S$_.currentPanel.chart);S$_.crosshairValue=S$_.adjustIfNecessary(S$_.currentPanel,S$_.crosshairTick,S$_.valueFromPixel(S$_.cy,S$_.currentPanel));}S$_.headsUpHR();}S$_.findHighlights(!![]);S$_.draw();}m8b.ChartEngine.prototype.touchstart=function(f1D){var T1e=A2IFV;var A_o,r2Q,M9D,D9U,F67,c8B,n2H,X36,n$S,m4m,X76,w4g,K59,k4j,B$x,S7W,h$D,O_d,q6Q,s$O,j8q,w_j,p6Z,k9M,j0D,v8H,l30,F4w,J7S,T04,y06,E0A,m8n,C2d,U_6;A_o="touchst";A_o+="ar";A_o+="t";if(m8b.ChartEngine.ignoreTouch){return;}if(m8b.isSurface){this.movedPrimary=![];this.movedSecondary=!({});}else {if(this.touchingEvent){clearTimeout(this.touchingEvent);}this.touching=!!"1";this.touches=f1D.touches;this.changedTouches=f1D.changedTouches;}if(m8b.ChartEngine.resizingPanel){return;}r2Q=this.crosshairXOffset;M9D=this.crosshairYOffset;if(this.touchPointerType == "pen"){r2Q=M9D=0;}if(this.runPrepend("touchstart",arguments)){return;}if(this.manageTouchAndMouse && f1D && f1D.preventDefault && f1D.cancelable && this.captureTouchEvents){f1D.preventDefault();}this.hasDragged=![];this.doubleFingerMoves=0;this.moveCount=0;this.twoFingerStart=!!"";if(this.touches.length == 1 || this.touches.length == 2){this.touchMoveTime=Date.now();n$S=this.touches[0];c8B=n$S.clientX;n2H=n$S.clientY;this.moveA=c8B;this.moveB=-1;if(this.openDialog === ""){m4m="do";m4m+="wn";this.registerPointerEvent({x:c8B,y:n2H,time:this.touchMoveTime},m4m);if(this.changedTouches.length == 1 && !this.isDoubleClick(!!"1")){m8b.extend(this.clicks,{s1MS:this.touchMoveTime,e1MS:-1,s2MS:-1,e2MS:-1,x:this.changedTouches["0" - 0].pageX,y:this.changedTouches[0].pageY});}}X76=this.container.getBoundingClientRect();this.top=X76.top;this.left=X76.left;this.right=this.left + this.width;this.bottom=this.top + this.height;if(this.touches.length == 1){w4g=this.backOutY(n2H);this.currentPanel=this.whichPanel(w4g);}if(!this.currentPanel){this.currentPanel=this.chart.panel;}X36=this.currentPanel;if(c8B >= this.left && c8B <= this.right && n2H >= this.top && n2H <= this.bottom){this.insideChart=!!({});K59=this.xAxisAsFooter === !""?this.chart.canvasHeight:this.chart.panel.bottom;this.overXAxis=n2H <= this.top + K59 && n2H >= this.top + K59 - this.xaxisHeight;this.overYAxis=c8B >= this.left + X36.right || c8B <= this.left + X36.left;k4j=-1;this.cy=this.backOutY(n2H);this.cx=this.backOutX(c8B);this.crosshairTick=this.tickFromPixel(this.cx,X36.chart);this.crosshairValue=this.adjustIfNecessary(X36,this.crosshairTick,this.valueFromPixel(this.cy,this.currentPanel));for(var x4Y=0;x4Y < this.drawingObjects.length;x4Y++){B$x=this.drawingObjects[x4Y];if(B$x.highlighted){if(k4j < "0" >> 0){k4j=x4Y;}S7W=B$x.highlighted;this.findHighlights(!0);if(x4Y == k4j && B$x.highlighted && !B$x.permanent){if(this.clicks.s2MS == -1){this.activateRepositioning(B$x);;}else {this.findHighlights(!1,!!"1");;}return;}this.anyHighlighted=!!1;B$x.highlighted=S7W;}}}else {h$D=398187641;T1e.H6P(1);O_d=-T1e.S40(1,"403517388");q6Q=2;for(var x1E=+"1";T1e.U6$(x1E.toString(),x1E.toString().length,"29189" | 1) !== h$D;x1E++){this.insideChart=!"";q6Q+=2;}if(T1e.U6$(q6Q.toString(),q6Q.toString().length,83258) !== O_d){this.insideChart=!!({});}this.insideChart=!!"";}s$O=this.currentVectorParameters.vectorType && this.currentVectorParameters.vectorType !== "";if(!this.layout.crosshair && !(this.layout.headsUp && this.layout.headsUp.floating) && !s$O && this.insideChart && !this.touchNoPan){r2Q=M9D=0;var {baselineHelper:n_4}=this;if(n_4.size){if(this.findBaselineHandle(f1D,!"")){return;}}if(this.controls.anchorHandles){j8q=Object.values(this.controls.anchorHandles);w_j=-896458940;T1e.H6P(10);p6Z=-T1e.S40("412015577",9);k9M=2;for(var a23=+"1";T1e.U6$(a23.toString(),a23.toString().length,"59047" ^ 0) !== w_j;a23++){j0D=!"";T1e.H6P(21);k9M+=T1e.q7n("2",0);}if(T1e.Z2Z(k9M.toString(),k9M.toString().length,94686) !== p6Z){j0D=!1;}j0D=!"1";for(var P_3=0;P_3 < j8q.length;P_3++){v8H=j8q[P_3];var {handle:R_n, sd:h0m}=v8H;l30=this.resolveX(this.cx);F4w=this.resolveY(this.cy);var {left:t5H, top:Q4l, right:w$$, bottom:H1Z}=R_n.getBoundingClientRect();t5H-=10;w$$+=10;if(m8b.boxIntersects(t5H,Q4l,w$$,H1Z,l30,F4w,l30,F4w)){J7S="st";J7S+="x-g";J7S+="rab";v8H.highlighted=!!({});this.repositioningAnchorSelector={sd:h0m};R_n.classList.add(J7S);j0D=!0;}if(v8H.highlighted === !""){v8H.highlighted=![];}}if(j0D){return;}}for(D9U in this.panels){F67=this.panels[D9U];if(F67.highlighted){this.grabHandle(F67);return;}}this.grabbingScreen=!!1;if(this.disableBackingStoreDuringTouch){this.disableBackingStore();}X36.chart.spanLock=!({});this.yToleranceBroken=![];T1e.H6P(0);this.grabStartX=T1e.q7n(c8B,r2Q);T1e.D0J(0);this.grabStartY=T1e.q7n(n2H,M9D);this.grabStartMicropixels=this.micropixels;this.grabStartScrollX=X36.chart.scroll;this.grabStartScrollY=X36.yAxis.scroll;this.grabStartPanel=this.currentPanel;if(this.swipeStart){this.swipeStart(X36.chart);}this.grabStartYAxis=this.whichYAxis(X36,this.backOutX(c8B));this.grabStartZoom=this.grabStartYAxis?this.grabStartYAxis.zoom:0;setTimeout((function(A7E){return function(){T1e.D0H();A7E.grabbingHand();};})(this),100);}else {this.grabbingScreen=!({});if(this.insideChart && X36.subholder === f1D.target){T04=this.currentVectorParameters.vectorType;if(m8b.Drawing && T04 && m8b.Drawing[T04] && new m8b.Drawing[T04]().dragToDraw){this.userPointerDown=!!1;m8b.ChartEngine.crosshairX=c8B;m8b.ChartEngine.crosshairY=n2H;if(X36 && X36.chart.dataSet){this.crosshairTick=this.tickFromPixel(this.backOutX(m8b.ChartEngine.crosshairX),this.currentPanel.chart);this.crosshairValue=this.adjustIfNecessary(X36,this.crosshairTick,this.valueFromPixel(this.backOutY(m8b.ChartEngine.crosshairY),this.currentPanel));}this.drawingClick(X36,this.backOutX(c8B),this.backOutY(n2H));this.headsUpHR();return;}}}if(this.touches.length === 1 && this.layout.crosshair && !s$O && X36.subholder === f1D.target){T1e.H6P(0);this.mousemoveinner(T1e.S40(c8B,r2Q),T1e.q7n(n2H,M9D));}}if(this.touches.length == 2){this.cancelLongHold=!!({});this.swipe.end=!![];if(!this.displayCrosshairs && !this.touchNoPan || !this.insideChart){return;}y06=this.touches[1];E0A=y06.clientX;m8n=y06.clientY;for(D9U in this.panels){F67=this.panels[D9U];if(F67.highlighted){this.grabHandle(F67);return;}}X36=this.currentPanel;T1e.D0J(141);this.gestureStartDistance=Math.sqrt(T1e.q7n(n2H,E0A,n2H,m8n,m8n,E0A,c8B,c8B));this.pt={x1:c8B,x2:E0A,y1:n2H,y2:m8n};this.grabbingScreen=!!({});if(this.disableBackingStoreDuringTouch){this.disableBackingStore();}X36.chart.spanLock=!1;T1e.H6P(0);this.grabStartX=T1e.S40(c8B,r2Q);T1e.H6P(0);this.grabStartY=T1e.q7n(n2H,M9D);this.grabStartMicropixels=this.micropixels;this.grabStartScrollX=X36.chart.scroll;this.grabStartScrollY=X36.yAxis.scroll;this.grabStartPanel=X36;if(this.swipeStart){this.swipeStart(X36.chart);}this.grabStartCandleWidth=this.layout.candleWidth;this.grabStartYAxis=this.whichYAxis(X36,this.backOutX((c8B + E0A) / 2)) || X36.yAxis;this.grabStartZoom=this.grabStartYAxis?this.grabStartYAxis.zoom:0;this.grabStartPt=this.pt;this.grabStartValues={x1:this.pt.x1,x2:this.pt.x2,y1:this.valueFromPixel(this.pt.y1 - this.top,X36),y2:this.valueFromPixel(this.pt.y2 - this.top,X36),t1:this.tickFromPixel(this.pt.x1 - this.left,X36.chart),t2:this.tickFromPixel(this.pt.x2 - this.left,X36.chart)};this.twoFingerStart=!![];setTimeout((function(i1l){T1e.D0H();return function(){i1l.grabbingHand();};})(this),100);}else if(this.touches.length == 3){if(!this.displayCrosshairs){return;}C2d=this.touches[+"0"];U_6=C2d.clientX;this.grabStartX=U_6;this.grabStartPeriodicity=this.layout.periodicity;}if(this.touches.length == 1 && !this.layout.crosshair){this.mouseTimer=Date.now();this.longHoldTookEffect=![];if(this.longHoldTime || this.longHoldTime === 0){this.startLongHoldTimer();}}this.runAppend(A_o,arguments);};m8b.ChartEngine.prototype.touchend=function(B7V){var s5K,i73,G78,P_O,K6w,S_6,k$2,X0z,X0B,X_R,Z8S,T5e;if(m8b.ChartEngine.ignoreTouch){return;}this.swipe.end=!!"1";if(m8b.isSurface){}else {this.touches=B7V.touches;this.changedTouches=B7V.changedTouches;}if(this.runPrepend("touchend",arguments)){return;}this.cancelLongHold=!0;if(this.touches.length <= 1){if(this.layout.crosshair || this.currentVectorParameters.vectorType){if(!this.touches.length || !this.twoFingerStart){this.grabbingScreen=!({});}}}if(this.touches.length){this.grabStartX=-1;this.grabStartY=-1;}s5K=this.pinchingScreen;if(this.disableBackingStoreDuringTouch){this.reconstituteBackingStore();}if(!this.touches.length){this.touchingEvent=setTimeout((function(u0c){A2IFV.D0H();return function(){A2IFV.a9S();u0c.touching=!"1";};})(this),500);if(m8b.ChartEngine.resizingPanel){this.releaseHandle();return;}this.pinchingScreen=null;this.pinchingCenter=null;this.goneVertical=!!"";this.grabbingScreen=![];this.grabMode="";if(this.highlightedDraggable){if(this.dragPlotOrAxis){this.dragPlotOrAxis(this.cx,this.cy);}this.currentPanel=this.whichPanel(this.cy);}this.grabStartYAxis=null;this.displayDragOK();this.doDisplayCrosshairs();this.updateChartAccessories();}else {if(m8b.ChartEngine.resizingPanel){return;}}i73=this.touches.length + +"1";if(this.changedTouches.length == 1){if(this.repositioningDrawing){G78="v";G78+="ec";G78+="t";G78+="or";this.changeOccurred(G78);m8b.clearCanvas(this.chart.tempCanvas,this);this.activateRepositioning(null);this.draw();if(!this.layout.crosshair && !this.currentVectorParameters.vectorType){this.findHighlights(!({}),!0);}return;}if(this.repositioningBaseline){P_O="st";P_O+="x-gra";P_O+="b";this.repositioningBaseline=null;this.controls.baselineHandle.classList.remove(P_O);K6w=this.mainSeriesRenderer || ({});if(K6w.params && K6w.params.baseline && K6w.params.type != "mountain"){;}this.draw();return;}if(this.repositioningAnchorSelector){m8b.Studies.repositionAnchor(this,this.repositioningAnchorSelector.sd);this.repositioningAnchorSelector=null;Object.values(this.controls.anchorHandles).forEach(({handle:o6Y})=>{A2IFV.D0H();return o6Y.classList.remove("stx-grab");});return;}S_6=Date.now();if(this.openDialog === "" && B7V.changedTouches.length){k$2=B7V.changedTouches[0];this.registerPointerEvent({x:k$2.clientX,y:k$2.clientY,time:S_6},"up");}if(this.clicks.s2MS == -("1" | 1)){this.clicks.e1MS=S_6;X0z=this.currentVectorParameters.vectorType;if(!m8b.Drawing || !X0z || !m8b.Drawing[X0z] || !new m8b.Drawing[X0z]().dragToDraw){if(this.clicks.e1MS - this.clicks.s1MS < ("750" ^ 0) && !this.longHoldTookEffect && (!this.hasDragged || this.layout.crosshair)){setTimeout(this.touchSingleClick(i73,this.clicks.x,this.clicks.y),this.doubleClickTime + 1);;}else {this.clicks={s1MS:-1,e1MS:-1,s2MS:-("1" - 0),e2MS:-1};}}this.userPointerDown=!({});X0B=this.backOutY(this.changedTouches[0].pageY) + this.crosshairYOffset;X_R=this.backOutX(this.changedTouches[0].pageX) + this.crosshairXOffset;Z8S=this.currentPanel;T5e=Z8S && Z8S.subholder === B7V.target;if(m8b.Drawing && this.activeDrawing && this.activeDrawing.dragToDraw && T5e){this.drawingClick(Z8S,X_R,X0B);return;}if(this.isDoubleClick(!![]) && (T5e || this.overYAxis || this.overXAxis)){this.touchDoubleClick(i73,this.clicks.x,this.clicks.y);}}else {this.clicks.e2MS=S_6;this.clicks={s1MS:-1,e1MS:-+"1",s2MS:-("1" | 0),e2MS:-+"1"};}}else if(this.displayCrosshairs){if(this.grabEndPeriodicity != -1 && !isNaN(this.grabEndPeriodicity)){if(m8b.ChartEngine.isDailyInterval(this.layout.interval) || this.allowIntradayNMinute){this.setPeriodicity({period:this.grabEndPeriodicity,interval:this.layout.interval});}this.grabEndPeriodicity=-1;}}if(this.changedTouches.length){if(!this.layout.crosshair && !this.currentVectorParameters.vectorType && i73 == 1 || this.twoFingerStart && !s5K && !this.touches.length){if(this.swipeRelease){this.swipeRelease();}this.findHighlights(!1,!"");}if(s5K && this.continuousZoom){this.continuousZoom.execute();this.continuousZoom.execute(!!({}));}}if(!this.touches.length){this.twoFingerStart=!({});}this.runAppend("touchend",arguments);};x6D=!({});m8b.ChartEngine.prototype.mousemoveinner=m8b.ChartEngine.prototype.mousemoveinner || (function(n1_,f_j){var F4Z,c8w,f1p;F4Z=1014480928;c8w=+"1052536454";f1p=2;A2IFV.a9S();for(var n3Q=1;A2IFV.U6$(n3Q.toString(),n3Q.toString().length,"93281" * 1) !== F4Z;n3Q++){if(~x6D){console.error("");}f1p+=2;}if(A2IFV.U6$(f1p.toString(),f1p.toString().length,32804) !== c8w){if(+x6D){console.error("");}}if(!x6D){console.error("touch feature requires activating movement feature.");}x6D=!!1;});};d7=V4$=>{var s_A=A2IFV;var b3w,a86;b3w="und";b3w+="efined";a86=typeof _CIQ !== b3w?_CIQ:V4$.CIQ;s_A.D0H();a86.Visualization=a86.Visualization || (function(A4Z){var L76;if(!A4Z){L76="C";L76+="IQ.Visualization() missing attribu";L76+="t";L76+="es argument.";console.log(L76);return;}if(typeof A4Z.renderFunction !== "function"){console.log("CIQ.Visualization() missing renderFunction property in attributes.");return;}this.container=null;s_A.D0H();this.attributes=A4Z;this.data=null;this.object=null;});a86.extend(a86.Visualization.prototype,{destroy:function(b61){var x2A;x2A=this.container;a86.resizeObserver(x2A,null,x2A.resizeHandle);if(x2A.autoGenerated){x2A.remove();delete this.container;}else {x2A.innerHTML="";}if(b61){return;}s_A.a9S();this.attributes=null;this.container=null;this.data=null;this.object=null;this.destroy=this.draw=this.setAttributes=function(){};this.updateData=function(){s_A.a9S();return undefined;};},draw:function(a4O){s_A.D0H();var b0T,p7i,j9v,a$Q,q11,P4i,s_J,E8y,t6O,l3G;b0T="str";b0T+="ing";p7i="o";p7i+="b";p7i+="jec";p7i+="t";if(!this.data || typeof this.data !== p7i){console.log("CIQ.Visualization.draw() missing data.");return;}j9v=this.attributes;a$Q=j9v.container || this.container;if(typeof a$Q === b0T){a$Q=document.querySelector(a$Q);}if(!a$Q){a$Q=document.createElement("div");a$Q.style.height=a$Q.style.width="300px";document.body.appendChild(a$Q);a$Q.autoGenerated=!!({});}if(j9v.stx){q11=j9v.stx.chart.canvasShim;if(j9v.useCanvasShim && q11 && q11 !== a$Q && q11 !== a$Q.parentNode){if(!a$Q.autoGenerated){a$Q=a$Q.cloneNode();a$Q.id="";a$Q.autoGenerated=!!1;}q11.appendChild(a$Q);}}if(this.container && this.container !== a$Q){this.destroy(!0);}if(!a$Q.resizeHandle){P4i=function(a4a){s_A.a9S();return function(){if(a4a.data && a4a.container && document.body.contains(a4a.container)){a4a.draw.call(a4a,!!1);}};};a$Q.resizeHandle=a86.resizeObserver(a$Q,P4i(this),null,100);}this.container=a$Q;this.attributes=j9v;j9v=a86.ensureDefaults({container:this.container},this.attributes);s_J=j9v.renderFunction(Object.values(this.data).sort(g4s),j9v);if(s_J){E8y=+"698908642";t6O=530697098;l3G=2;for(var t7D=1;s_A.U6$(t7D.toString(),t7D.toString().length,82003) !== E8y;t7D++){if(j9v.id){s_J.id=j9v.id;}l3G+=2;}if(s_A.U6$(l3G.toString(),l3G.toString().length,61980) !== t6O){if(j9v.id){s_J.id=j9v.id;}}if(a4O || j9v.forceReplace){this.container.innerHTML="";this.container.appendChild(s_J);}}this.attributes=j9v;function g4s(i$V,F3n){s_A.D0H();return i$V.index < F3n.index?-1:i$V.index > F3n.index?1:0;}this.object=s_J;},setAttributes:function(U$k,T8K){var J3O,y5J,U_2,O2a;J3O="contain";J3O+="er";y5J=["renderFunction",J3O,"stx","useCanvasShim","id","forceReplace"];U_2=![];s_A.a9S();O2a=U$k;if(typeof U$k == "string"){O2a={};O2a[U$k]=T8K;}if(typeof O2a == "object"){for(var s6q in O2a){if(this.attributes[s6q] !== O2a[s6q] && y5J.indexOf(s6q) !== -1){U_2=!![];}this.attributes[s6q]=O2a[s6q];}}this.draw(U_2);},updateData:function(x$S,q1O){var X7V,J5z,f0j,K4b,n2w,U4J,c3h;X7V="up";X7V+="d";X7V+="at";X7V+="e";J5z="r";J5z+="epl";J5z+="a";J5z+="ce";n2w=Array.isArray(x$S)?x$S.reduce(function(Z7C,v8L){s_A.D0H();Z7C[v8L.name]=v8L;return Z7C;},{}):a86.shallowClone(x$S);for(f0j in n2w){K4b=n2w[f0j];if(Object.prototype.toString.call(K4b) !== "[object Object]"){n2w[f0j]={value:K4b};}if(!n2w[f0j].name){n2w[f0j].name=f0j;}if(!n2w[f0j].value){n2w[f0j].value=0;}}if(!q1O){q1O="replace";}switch(q1O.toLowerCase()){case "delete":for(f0j in n2w){delete this.data[f0j];}break;case J5z:this.data={};case X7V:case "add":for(f0j in n2w){U4J="[ob";U4J+="j";U4J+="ect Nu";U4J+="mber]";if(!this.data[f0j]){this.data[f0j]={name:f0j};}K4b=n2w[f0j].value;if(Object.prototype.toString.call(K4b) == U4J){c3h="u";c3h+="p";c3h+="d";c3h+="ate";if(!this.data[f0j].value || q1O == c3h){this.data[f0j].value=0;}this.data[f0j].value+=K4b;}else {this.data[f0j].value=K4b;}for(var x7X in n2w[f0j]){if(x7X !== "value"){this.data[f0j][x7X]=n2w[f0j][x7X];}}}break;default:console.log("Invalid or missing action. Valid values are 'add', 'delete', 'replace', or 'update'.");}this.draw(this.attributes.forceReplace);return this;}});a86.ChartEngine.prototype.embedVisualization=function(M22){if(!M22){M22={};}M22.stx=this;M22.useCanvasShim=!![];s_A.a9S();M22.translator=function(b78){s_A.a9S();return M22.stx.translateIf(b78);};return new a86.Visualization(M22);};};m1=c$9=>{var a6m,E4o,M4W,s4h;a6m="u";a6m+="n";a6m+="defined";E4o=typeof _CIQ !== a6m?_CIQ:c$9.CIQ;if(!E4o.Studies){M4W="medianPrice feature requires first activating studies fea";M4W+="ture.";console.error(M4W);}else {s4h="Median P";s4h+="rice";E4o.Studies.calculateTypicalPrice=function(p9T,t5J){var b2E=A2IFV;var y8C,e$U,y6b,s1e,E5M;y8C=t5J.chart.scrubbed;e$U=t5J.days;if(y8C.length < e$U + 1){if(!t5J.overlay){t5J.error=!"";}return;}y6b=t5J.name;for(var l9R in t5J.outputs){b2E.H6P(37);y6b=b2E.S40(y6b,l9R,(5214,+"2672") == 295?(!({}),0x2024):(4840,148) <= 9300?" ":1583 == 6312?(+"0xa5e",+"978.36"):("O",107.48));}s1e="h";s1e+="l";s1e+="c/3";if(t5J.type == "Med Price"){s1e="hl/2";}else if(t5J.type == "Weighted Close"){s1e="hlcc/4";}E5M=0;if(t5J.startFrom <= e$U){b2E.D0J(28);t5J.startFrom=b2E.q7n("0",32);}for(var n1y=t5J.startFrom;n1y < y8C.length;n1y++){if(n1y && y8C[n1y - 1][y6b]){b2E.H6P(7);var I5X=b2E.S40(2,3);E5M=y8C[n1y - I5X][y6b] * e$U;}E5M+=y8C[n1y][s1e];if(n1y >= e$U){b2E.H6P(7);E5M-=y8C[b2E.q7n(e$U,n1y)][s1e];b2E.H6P(14);y8C[n1y][y6b]=b2E.q7n(e$U,E5M);}}};E4o.Studies.studyLibrary=E4o.extend(E4o.Studies.studyLibrary,{"Med Price":{name:s4h,calculateFN:E4o.Studies.calculateTypicalPrice,inputs:{Period:14}}});}};k4=j0c=>{var c5N=A2IFV;var D8q,l3e;c5N.D0H();D8q=typeof _CIQ !== "undefined"?_CIQ:j0c.CIQ;if(!D8q.Studies){console.error("momentum feature requires first activating studies feature.");}else {l3e="Price Rat";l3e+="e of Change";D8q.Studies.calculateRateOfChange=function(v5G,I8C){var x8z,k$p,P$7,K4Z,Z5Y,H0$,V5T,l0b,h1t,f05,M2v,L7u;x8z="V";x8z+="olu";x8z+="me";k$p="C";k$p+="lo";k$p+="s";k$p+="e";P$7="f";P$7+="ie";P$7+="l";P$7+="d";K4Z=I8C.chart.scrubbed;if(K4Z.length < I8C.days + +"1"){I8C.error=!!({});return;}Z5Y=I8C.inputs.Field;if(!Z5Y || Z5Y == P$7){Z5Y=k$p;}if(I8C.parameters.isVolume){Z5Y=x8z;}H0$=I8C.name;for(var p6q in I8C.outputs){c5N.H6P(37);H0$=c5N.S40(H0$,p6q,"1330" - 0 !== 271?("8590" ^ 0,3416) > "381.69" - 0?5704 === 1382?5.35e+3:" ":(9.59e+3,3.05e+3):(379.23,!!"1"));}V5T=I8C.inputs["Center Line"];if(!V5T){c5N.D0J(10);V5T=c5N.S40("0",0);}else {V5T=parseInt(V5T,10);}for(var H$h=Math.max(I8C.startFrom,I8C.days);H$h < K4Z.length;H$h++){l0b="M";l0b+="oment";l0b+="um";h1t="ob";h1t+="j";h1t+="ect";f05=K4Z[H$h][Z5Y];if(f05 && typeof f05 == h1t){f05=f05[I8C.subField];}M2v=K4Z[H$h - I8C.days][Z5Y];if(M2v && typeof M2v == "object"){M2v=M2v[I8C.subField];}if(I8C.type == l0b){c5N.D0J(36);K4Z[H$h][H0$]=c5N.S40(V5T,f05,M2v);}else {L7u=M2v;if(L7u){c5N.H6P(144);K4Z[H$h][H0$]=c5N.q7n(f05,1,L7u,V5T,100);}}}};D8q.Studies.studyLibrary=D8q.extend(D8q.Studies.studyLibrary,{"Price ROC":{name:l3e,calculateFN:D8q.Studies.calculateRateOfChange,inputs:{Period:14,Field:"field"}},Momentum:{name:"Momentum Indicator",calculateFN:D8q.Studies.calculateRateOfChange,inputs:{Period:14},centerline:0}});}};C1=R1R=>{var v4Q,h$Q;v4Q=typeof _CIQ !== "undefined"?_CIQ:R1R.CIQ;if(!v4Q.Studies){console.error("priceRelative feature requires first activating studies feature.");}else {h$Q="Pric";h$Q+="e Relative";v4Q.Studies.initPriceRelative=function(D8z,t8H,z4c,W8c,t39,S3G){var R7V,U8k;R7V=v4Q.Studies.initializeFN(D8z,t8H,z4c,W8c,t39,S3G);U8k=[R7V.inputs["Comparison Symbol"].toUpperCase()];v4Q.Studies.fetchAdditionalInstruments(D8z,R7V,U8k);return R7V;};v4Q.Studies.calculatePriceRelative=function(P7y,j1Q){var G3m,e7g,h$B,l0e,J4r,J6c;G3m=j1Q.chart.scrubbed;e7g=j1Q.inputs["Comparison Symbol"].toUpperCase();if(!e7g){e7g=j1Q.study.inputs["Comparison Symbol"];}A2IFV.a9S();h$B={};l0e=P7y.chart.symbol || "";l0e=l0e.replace(/[=+\-*\\%]/g,"");h$B[l0e]=G3m.slice(j1Q.startFrom);if(!h$B[l0e].length){return;}if(l0e != e7g){h$B[e7g]=null;}A2IFV.D0J(73);J4r=v4Q.computeEquationChart(A2IFV.S40((3038,9520) !== ("5880" | 24,293.33)?"[":("H",90.93),(544.73,+"232") === +"1192"?526:"]",e7g,"]/[",l0e),h$B);J6c=0;for(var x7b=j1Q.startFrom;x7b < G3m.length && J6c < J4r.length;x7b++){while(J6c < J4r.length && G3m[x7b].DT.getTime() > J4r[J6c].DT.getTime()){J6c++;}if(G3m[x7b].DT.getTime() < J4r[J6c].DT.getTime())continue;G3m[x7b]["Result " + j1Q.name]=J4r[J6c].Close;J6c++;}};v4Q.Studies.displayVsComparisonSymbol=function(W19,u$o,m_H){var M4K,L5O,Q1I,i15;M4K=u$o.inputs["Comparison Symbol"].toUpperCase();if(!W19.getSeries({symbol:M4K,chart:u$o.chart}).length){W19.displayErrorAsWatermark(u$o.panel,W19.translateIf(u$o.study.name) + ": " + W19.translateIf("Not Available"));return;}L5O={skipTransform:W19.panels[u$o.panel].name != u$o.chart.name,panelName:u$o.panel,band:"Result " + u$o.name,threshold:u$o.study.centerline,yAxis:u$o.getYAxis(W19),gapDisplayStyle:!!({})};A2IFV.D0H();Q1I=L5O.yAxis?L5O.yAxis.flipped:W19.panels[u$o.panel].yAxis.flipped;i15=0.3;if(!u$o.highlight && W19.highlightedDraggable){i15*=0.3;}for(var q8U=m_H.length - 1;q8U >= +"0";q8U--){if(m_H[q8U] && m_H[q8U][M4K]){v4Q.Studies.displaySeriesAsLine(W19,u$o,m_H);if(u$o.study.centerline || u$o.study.centerline === 0){if(u$o.outputs.Gain){v4Q.preparePeakValleyFill(W19,v4Q.extend(L5O,{direction:Q1I?-1:"1" | 0,color:v4Q.Studies.determineColor(u$o.outputs.Gain),opacity:i15}));}if(u$o.outputs.Loss){v4Q.preparePeakValleyFill(W19,v4Q.extend(L5O,{direction:Q1I?1:-1,color:v4Q.Studies.determineColor(u$o.outputs.Loss),opacity:i15}));}}return;}}};v4Q.Studies.fetchAdditionalInstruments=function(c0L,O6o,X53,R$L){var G3u,P6m,b20,C33,w2P,J35;if(!c0L.quoteDriver){console.log("CIQ.Studies.fetchAdditionalInstruments: No quotefeed to fetch symbol");return;}G3u=c0L.panels[O6o.panel].chart;function w3i(){c0L.createDataSet();c0L.draw();}O6o.symbols=X53;for(P6m=+"0";P6m < X53.length;P6m++){b20=C33=X53[P6m];if(typeof C33 == "object"){b20=C33.symbol;}else {C33={symbol:b20};}w2P={symbol:b20,symbolObject:C33,bucket:"study",studyName:O6o.name,chartName:G3u.name,action:"add-study"};v4Q.extend(w2P,R$L);J35=w2P.loadData;if(c0L.currentlyImporting){w2P.loadData=![];}if(!O6o.series){O6o.series={};}O6o.series[b20]=c0L.addSeries(null,w2P,w3i);O6o.series[b20].parameters.loadData=J35;}};v4Q.Studies.studyLibrary=v4Q.extend(v4Q.Studies.studyLibrary,{"P Rel":{name:h$Q,initializeFN:v4Q.Studies.initPriceRelative,seriesFN:v4Q.Studies.displayVsComparisonSymbol,calculateFN:v4Q.Studies.calculatePriceRelative,centerline:+"0",inputs:{"Comparison Symbol":"SPY"},deferUpdate:!""}});}};t_=v4i=>{var P5e=A2IFV;var A$i,i3L,m3Z,A_t,F2y,n2A,r5I,j3z;A$i="un";A$i+="d";A$i+="efi";P5e.a9S();A$i+="ned";i3L=typeof _CIQ !== A$i?_CIQ:v4i.CIQ;if(!i3L.Studies){console.error("vwap feature requires first activating studies feature.");}else {m3Z="#8";m3Z+="5c";m3Z+="99e";A_t="#";A_t+="FF";A_t+="0000";F2y="V";F2y+="W";F2y+="A";F2y+="P";n2A="h";n2A+="h:";n2A+="mm:";n2A+="ss";r5I="#fff";r5I+="69e";j3z="#e1e1e";j3z+="1";i3L.Studies.calculateVWAP=function(T41,E9j){var n8T,c$n,o$X,s0q,o$9,J3F,B6E,W0I,G6v,Z8a,h_L,p$Q,k3t,Z2S,j4u,g8k,k$o,a6U,o_1,q6n,v8t,I1Z,z6v,i2l;n8T="AVWA";n8T+="P";c$n=E9j.type == n8T;o$X=E9j.chart.scrubbed;P5e.D0H();if(!c$n && i3L.ChartEngine.isDailyInterval(T41.layout.interval)){E9j.error="VWAP is Intraday Only";return;}s0q="hl";s0q+="c/";s0q+="3";if(c$n){s0q=E9j.inputs.Field;if(!s0q || s0q == "field"){s0q=E9j.inputs.Field="hlc/3";T41.changeOccurred("layout");}}o$9=null;J3F=0;B6E=0;W0I=+"0";G6v=!({});if(E9j.startFrom > 1){Z8a="_";Z8a+="VxP ";h_L="_V";h_L+=" ";J3F=o$X[E9j.startFrom - 1][h_L + E9j.name] || "0" - 0;B6E=o$X[E9j.startFrom - 1][Z8a + E9j.name] || 0;W0I=o$X[E9j.startFrom - 1]["_VxP2 " + E9j.name] || 0;}if(c$n){p$Q="Anc";p$Q+="hor ";p$Q+="D";p$Q+="ate";k3t=E9j.inputs[p$Q].replace(/-/g,"");if(k3t.search(/^\d{8}$/)){E9j.error="Invalid Anchor Date";return;}Z2S=E9j.inputs["Anchor Time"].replace(/:/g,"");if(!Z2S.search(/^\d{4,6}$/)){k3t+=Z2S;}k3t=i3L.strToDateTime(k3t.replace(/\D/g,""));if(!E9j.startFrom && k3t >= o$X[0].DT){E9j.startFrom=T41.tickFromDate(k3t,T41.chart,null,!0);}if(E9j.inputs["Anchor Selector"]){i3L.Studies.initAnchorHandle(T41,E9j);}else {i3L.Studies.removeAnchorHandle(T41,E9j);}}for(var k7F=E9j.startFrom;k7F < o$X.length;k7F++){j4u="_";j4u+="SDVWAP ";if(!c$n){if(o$9 === null){o$9=i3L.Studies.getMarketOffset({stx:T41,localQuoteDate:o$X[k7F].DT,shiftToDateBoundary:!!({})});}if(o$X[k7F - ("1" << 32)] && o$X[k7F - 1].DT){g8k=new Date(new Date(+o$X[k7F].DT).setMilliseconds(o$X[k7F].DT.getMilliseconds() + o$9));k$o=new Date(new Date(+o$X[k7F - 1].DT).setMilliseconds(o$X[k7F - 1].DT.getMilliseconds() + o$9));if(k$o.getDate() != g8k.getDate() && T41.chart.market.isMarketDate(g8k)){o$9=null;J3F=B6E=W0I=0;}}}a6U=o$X[k7F][s0q];o_1=o$X[k7F].Volume;if(c$n && !o_1){o_1=1;}J3F+=o_1;P5e.D0J(1);B6E+=P5e.q7n(a6U,o_1);P5e.H6P(145);W0I+=P5e.q7n(o_1,a6U,a6U);if(!c$n && !J3F)continue;o$X[k7F]["_V " + E9j.name]=J3F;o$X[k7F]["_VxP " + E9j.name]=B6E;o$X[k7F]["_VxP2 " + E9j.name]=W0I;q6n=o$X[k7F][j4u + E9j.name]=Math.sqrt(Math.max(0,W0I / J3F - Math.pow(B6E / J3F,2)));P5e.D0J(14);v8t=o$X[k7F]["VWAP " + E9j.name]=P5e.S40(J3F,B6E);for(var a1o=1;a1o <= 3;a1o++){I1Z="-";I1Z+=" ";P5e.H6P(45);o$X[k7F]["SDVWAP" + a1o + "+ " + E9j.name]=P5e.S40(a1o,q6n,v8t);P5e.H6P(146);o$X[k7F]["SDVWAP" + a1o + I1Z + E9j.name]=P5e.S40(a1o,q6n,v8t);}G6v=!!({});}for(var L2t=1;L2t <= 3;L2t++){z6v="\u03C3";z6v+=")";if(E9j.inputs["Display " + L2t + " Standard Deviation (" + L2t + z6v]){i2l=" Sta";i2l+="ndard ";i2l+="Deviati";i2l+="on (";P5e.D0J(48);E9j.outputMap["SDVWAP" + L2t + "+ " + E9j.name]=P5e.S40("\u03C3)",L2t,i2l,L2t);P5e.H6P(48);E9j.outputMap["SDVWAP" + L2t + "- " + E9j.name]=P5e.S40("\u03C3)",L2t," Standard Deviation (",L2t);}}if(!c$n && !G6v){E9j.error="VWAP Requires Volume";}};i3L.Studies.initAnchoredVWAP=function(B7h,U1L,G3o,j_H,r7J,A7I){var B95,p$$,e89,W3l;B95="Anc";B95+="hor Ti";B95+="me";if(!G3o["Anchor Date"] && !G3o[B95]){var {dataSegment:Z65}=B7h.chart;for(var r1U=0;Z65 && r1U < Z65.length;r1U++){if(Z65[r1U]){p$$="YYYY";p$$+="-MM-dd";e89="Anch";e89+="or Date";var {DT:v_b}=Z65[r1U];G3o[e89]=i3L.dateToStr(v_b,p$$);G3o["Anchor Time"]=i3L.dateToStr(v_b,"HH:mm:ss");break;}}}W3l=i3L.Studies.initializeFN(B7h,U1L,G3o,j_H,r7J,A7I);P5e.a9S();return W3l;};i3L.Studies.displayVWAP=function(m0E,v8U,R4k){var A1r,S9C,x2T,r3q,u4K,D2z,H_q,Q47,c4q,z23;A1r="Display 1 Standard Deviati";A1r+="o";A1r+="n ";A1r+="(1\u03C3)";i3L.Studies.displaySeriesAsLine(m0E,v8U,R4k);S9C=v8U.inputs[A1r];x2T=v8U.inputs["Display 2 Standard Deviation (2\u03C3)"];r3q=v8U.inputs["Display 3 Standard Deviation (3\u03C3)"];if((S9C || x2T || r3q) && v8U.inputs.Shading){u4K="V";u4K+="W";u4K+="AP";u4K+=" ";D2z=m0E.panels[v8U.panel];H_q={opacity:v8U.parameters.opacity?v8U.parameters.opacity:0.2,skipTransform:D2z.name != v8U.chart.name,yAxis:v8U.getYAxis(m0E)};if(!v8U.highlight && m0E.highlightedDraggable){H_q.opacity*=0.3;}Q47=u4K + v8U.name;c4q="VWAP " + v8U.name;if(S9C){z23="S";z23+="D";z23+="VWAP1+ ";i3L.prepareChannelFill(m0E,i3L.extend({panelName:v8U.panel,topBand:"SDVWAP1+ " + v8U.name,bottomBand:Q47,color:i3L.Studies.determineColor(v8U.outputs[v8U.outputMap["SDVWAP1+ " + v8U.name]])},H_q));i3L.prepareChannelFill(m0E,i3L.extend({panelName:v8U.panel,topBand:"SDVWAP1- " + v8U.name,bottomBand:c4q,color:i3L.Studies.determineColor(v8U.outputs[v8U.outputMap["SDVWAP1- " + v8U.name]])},H_q));Q47=z23 + v8U.name;c4q="SDVWAP1- " + v8U.name;}if(x2T){i3L.prepareChannelFill(m0E,i3L.extend({panelName:v8U.panel,topBand:"SDVWAP2+ " + v8U.name,bottomBand:Q47,color:i3L.Studies.determineColor(v8U.outputs[v8U.outputMap["SDVWAP2+ " + v8U.name]])},H_q));i3L.prepareChannelFill(m0E,i3L.extend({panelName:v8U.panel,topBand:"SDVWAP2- " + v8U.name,bottomBand:c4q,color:i3L.Studies.determineColor(v8U.outputs[v8U.outputMap["SDVWAP2- " + v8U.name]])},H_q));Q47="SDVWAP2+ " + v8U.name;c4q="SDVWAP2- " + v8U.name;}if(r3q){i3L.prepareChannelFill(m0E,i3L.extend({panelName:v8U.panel,topBand:"SDVWAP3+ " + v8U.name,bottomBand:Q47,color:i3L.Studies.determineColor(v8U.outputs[v8U.outputMap["SDVWAP3+ " + v8U.name]])},H_q));i3L.prepareChannelFill(m0E,i3L.extend({panelName:v8U.panel,topBand:"SDVWAP3- " + v8U.name,bottomBand:c4q,color:i3L.Studies.determineColor(v8U.outputs[v8U.outputMap["SDVWAP3- " + v8U.name]])},H_q));}}if(v8U.anchorHandle){i3L.Studies.displayAnchorHandleAndLine(m0E,v8U,R4k);}};i3L.Studies.studyLibrary=i3L.extend(i3L.Studies.studyLibrary,{AVWAP:{name:"Anchored VWAP",overlay:!!({}),calculateFN:i3L.Studies.calculateVWAP,seriesFN:i3L.Studies.displayVWAP,initializeFN:i3L.Studies.initAnchoredVWAP,removeFN:i3L.Studies.removeAnchorHandle,inputs:{Field:"field","Anchor Date":"","Anchor Time":"","Display 1 Standard Deviation (1\u03C3)":!({}),"Display 2 Standard Deviation (2\u03C3)":!({}),"Display 3 Standard Deviation (3\u03C3)":!"1",Shading:![],"Anchor Selector":!![]},outputs:{VWAP:"#FF0000","1 Standard Deviation (1\u03C3)":j3z,"2 Standard Deviation (2\u03C3)":"#85c99e","3 Standard Deviation (3\u03C3)":r5I},parameters:{init:{opacity:0.2}},attributes:{"Anchor Date":{placeholder:"yyyy-mm-dd"},"Anchor Time":{placeholder:n2A,step:1}}},VWAP:{name:F2y,overlay:!!"1",calculateFN:i3L.Studies.calculateVWAP,seriesFN:i3L.Studies.displayVWAP,inputs:{"Display 1 Standard Deviation (1\u03C3)":!({}),"Display 2 Standard Deviation (2\u03C3)":!1,"Display 3 Standard Deviation (3\u03C3)":!({}),Shading:!({})},outputs:{VWAP:A_t,"1 Standard Deviation (1\u03C3)":"#e1e1e1","2 Standard Deviation (2\u03C3)":m3Z,"3 Standard Deviation (3\u03C3)":"#fff69e"},parameters:{init:{opacity:0.2}}}});}};b$=w_y=>{var i4L=A2IFV;i4L.D0H();var n1m;n1m=typeof _CIQ !== "undefined"?_CIQ:w_y.CIQ;if(!n1m.Studies){console.error("zigzag feature requires first activating studies feature.");}else {n1m.Studies.calculateZigZag=function(t9F,d8T){var b6K,l6_,r0c,z3Y,s92,a3f,Y3A,H37,r44,B_8,N8z,i6o,N$9,H$L,O8W,I5K,F6p,J0u,Z$9,S7u,N8a,u$Y;b6K="H";b6K+="i";b6K+="g";function O60(t8T,h$L){var f55;for(var T$z=t8T + 1;T$z < h$L;T$z++){f55="R";f55+="es";f55+="ul";f55+="t ";r0c[T$z]["ShadowResult " + d8T.name]=(r0c[h$L][f55 + d8T.name] - r0c[t8T]["Result " + d8T.name]) * (T$z - t8T) / (h$L - t8T) + r0c[t8T]["Result " + d8T.name];delete r0c[T$z]["Result " + d8T.name];}}b6K+="h";l6_="L";l6_+="o";l6_+="w";r0c=d8T.chart.scrubbed;if(!r0c || !r0c.length){return;}z3Y=d8T.highLowChart;s92=null;a3f=null;Y3A=d8T.inputs["Distance(%)"];H37=0;r44=0;B_8=0;N8z=null;i6o=null;N$9=0;for(var N5H=Math.min(r0c.length - 1,d8T.startFrom);N5H >= 0;N5H--){H$L="_sta";H$L+="t";H$L+="e ";N$9=N5H;if(r0c[N5H][H$L + d8T.name]){O8W=r0c[N5H]["_state " + d8T.name];s92=O8W[0];a3f=O8W[1];H37=O8W[+"2"];r44=O8W[3];B_8=O8W[4];N8z=O8W[+"5"];i6o=O8W[6];break;}}for(var P_X=N$9;P_X < r0c.length;P_X++){I5K=r0c[P_X][z3Y?"High":"Close"];F6p=r0c[P_X][z3Y?"Low":"Close"];if(a3f === null || a3f < I5K){a3f=I5K;if(H37 < 0){s92=F6p;}i4L.D0J(147);N8z=i4L.q7n(100,Y3A,a3f,1);if(H37 > -1){if(i6o !== null && a3f > i6o){J0u="L";J0u+="o";J0u+="w";Z$9="Resu";Z$9+="lt ";r0c[r44][Z$9 + d8T.name]=r0c[r44][z3Y?J0u:"Close"];O60(B_8,r44);H37=-1;s92=F6p;B_8=r44;r44=P_X;continue;}}else {r44=P_X;}}if(s92 === null || s92 > F6p){s92=F6p;if(H37 > ("0" ^ 0)){a3f=I5K;}i4L.D0J(148);i6o=i4L.S40(Y3A,1,s92,100);if(H37 < +"1"){if(N8z !== null && s92 < N8z){r0c[r44]["Result " + d8T.name]=r0c[r44][z3Y?"High":"Close"];O60(B_8,r44);H37=1;a3f=I5K;B_8=r44;r44=P_X;continue;}}else {r44=P_X;}}}r0c[r44]["Result " + d8T.name]=r0c[r44][z3Y?H37 == 1?l6_:b6K:"Close"];r0c[r44]["_state " + d8T.name]=[s92,a3f,H37,r44,B_8,N8z,i6o];O60(B_8,r44);i4L.H6P(52);var O9y=i4L.q7n(59,3,20);S7u=r0c.length - O9y;while(S7u > r44){if(r0c[S7u].Close || r0c[S7u].Close === 0){N8a="Hi";N8a+="g";N8a+="h";u$Y="Resul";u$Y+="t";u$Y+=" ";r0c[S7u][u$Y + d8T.name]=r0c[S7u][z3Y?H37 == 1?N8a:"Low":"Close"];break;}S7u--;}i4L.a9S();O60(r44,S7u);};n1m.Studies.displayZigZag=function(F4Q,P3b,s7t){var c8Q,Q8i,Q_Y,b7l,P7l,b0C,H5t,F7Z,Y3n;c8Q=F4Q.chart.highLowBars;if(P3b.highLowChart != c8Q){P3b.highLowChart=c8Q;P3b.startFrom=0;P3b.study.calculateFN(F4Q,P3b);}Q8i=F4Q.chart;for(var F2z=0;F2z < s7t.length;F2z++){Q_Y=s7t[F2z];if(Q_Y){b7l="R";b7l+="esult ";if(Q_Y["_shadowCopy " + P3b.name]){delete Q_Y["Result " + P3b.name];delete Q_Y["_shadowCopy " + P3b.name];}if(!Q_Y[b7l + P3b.name]){P7l="R";P7l+="esul";P7l+="t";P7l+=" ";if(Q_Y.transform){delete Q_Y.transform[P7l + P3b.name];}}}}b0C=s7t[0];i4L.H6P(149);var x$H=i4L.S40(19,18,7,34,9);H5t=s7t[s7t.length - x$H];if(b0C && b0C["ShadowResult " + P3b.name]){F7Z="ShadowRe";F7Z+="su";F7Z+="l";F7Z+="t ";b0C["Result " + P3b.name]=b0C[F7Z + P3b.name];if(b0C.transform){b0C.transform["Result " + P3b.name]=Q8i.transformFunc(F4Q,Q8i,b0C["ShadowResult " + P3b.name]);}i4L.H6P(1);b0C["_shadowCopy " + P3b.name]=i4L.q7n(1,"1");}if(H5t && H5t["ShadowResult " + P3b.name]){Y3n="Re";Y3n+="sul";Y3n+="t ";H5t[Y3n + P3b.name]=H5t["ShadowResult " + P3b.name];if(H5t.transform){H5t.transform["Result " + P3b.name]=Q8i.transformFunc(F4Q,Q8i,H5t["ShadowResult " + P3b.name]);}H5t["_shadowCopy " + P3b.name]=1;}n1m.Studies.displaySeriesAsLine(F4Q,P3b,s7t);};n1m.Studies.studyLibrary=n1m.extend(n1m.Studies.studyLibrary,{ZigZag:{name:"ZigZag",overlay:!![],seriesFN:n1m.Studies.displayZigZag,calculateFN:n1m.Studies.calculateZigZag,inputs:{"Distance(%)":10},parameters:{init:{label:!1}},attributes:{"Distance(%)":{min:0.1,step:0.1}}}});}};A1={CIQ:y4,SplinePlotter:l5,timezoneJS:R$,$$:L9,$$$:G8};export {Z as createEngine};export {Q as customCharts};export {q as drawing};export {A as easeMachine};export {G as equations};export {g as i18n};export {K as interaction};export {M as markers};export {B as market};export {J as movement};export {P as nameValueStore};export {T as quoteFeed};export {W as series};export {U as share};export {R as span};export {D as storage};export {N as studies};export {L0 as symbolLookupBase};export {W_ as theme};export {f9 as timezone};export {o8 as touch};export {d7 as visualization};export {m1 as medianPrice};export {k4 as momentum};export {C1 as priceRelative};export {t_ as vwap};export {b$ as zigzag};export {y4 as CIQ, l5 as SplinePlotter, R$ as timezoneJS, L9 as $$, G8 as $$$};if(typeof __TREE_SHAKE__ === Z9Rgz || !__TREE_SHAKE__){A1.CIQ.activateImports(Z,Q,q,A,G,g,K,M,B,J,P,T,W,U,R,D,N,L0,W_,f9,o8,d7,m1,k4,C1,t_,b$,null);}/* eslint-enable */ /* jshint ignore:end */ /* ignore jslint end */ diff --git a/chartiq/splines.js b/chartiq/splines.js deleted file mode 100644 index 93dcb826ee..0000000000 --- a/chartiq/splines.js +++ /dev/null @@ -1,129 +0,0 @@ -(function (definition) { - "use strict"; - // This file will function properly as a