Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/matomo-org/matomo.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Steur <tsteur@users.noreply.github.com>2016-03-10 02:58:08 +0300
committerThomas Steur <tsteur@users.noreply.github.com>2016-03-10 02:58:08 +0300
commit1854f5c456a76af807431d52bcb19ad207ba658e (patch)
tree6445a40013d17339b3a170176eb2bbd6aeb2abac
parentdd408624eb63ce74385a94f4ab471b35e23fa21b (diff)
parent09dc2dbb041e63100c651879e83c8ac73b9d4f3e (diff)
Merge pull request #9905 from piwik/3.0
Merge 3.0 => 3.x-dev
-rw-r--r--.travis.yml29
-rw-r--r--CHANGELOG.md38
-rw-r--r--bower.json10
-rw-r--r--composer.json2
-rw-r--r--core/API/DataTableGenericFilter.php40
-rw-r--r--core/API/DataTableManipulator/ReportTotalsCalculator.php4
-rw-r--r--core/API/DataTablePostProcessor.php3
-rw-r--r--core/Category/Category.php118
-rw-r--r--core/Category/CategoryList.php95
-rw-r--r--core/Category/Subcategory.php146
-rw-r--r--core/Common.php29
-rw-r--r--core/DataTable.php8
-rw-r--r--core/DataTable/Filter/ColumnDelete.php13
-rw-r--r--core/DataTable/Filter/PivotByDimension.php3
-rw-r--r--core/DataTable/Filter/Sort.php230
-rw-r--r--core/DataTable/Row.php60
-rw-r--r--core/Http/ControllerResolver.php51
-rw-r--r--core/Menu/MenuMain.php19
-rw-r--r--core/Menu/MenuReporting.php143
-rw-r--r--core/Metrics/Sorter.php237
-rw-r--r--core/Metrics/Sorter/Config.php24
-rw-r--r--core/Plugin.php2
-rw-r--r--core/Plugin/Categories.php71
-rw-r--r--core/Plugin/Controller.php67
-rw-r--r--core/Plugin/ControllerAdmin.php30
-rw-r--r--core/Plugin/Menu.php12
-rw-r--r--core/Plugin/Metric.php19
-rw-r--r--core/Plugin/Report.php287
-rw-r--r--core/Plugin/Reports.php189
-rw-r--r--core/Plugin/ViewDataTable.php18
-rw-r--r--core/Plugin/Visualization.php7
-rw-r--r--core/Plugin/Widgets.php233
-rw-r--r--core/Report/ReportWidgetConfig.php92
-rw-r--r--core/Report/ReportWidgetFactory.php119
-rw-r--r--core/Updates/3.0.0-b1.php351
-rw-r--r--core/Version.php2
-rw-r--r--core/View/ReportsByDimension.php129
-rw-r--r--core/ViewDataTable/Config.php4
-rw-r--r--core/ViewDataTable/Factory.php11
-rw-r--r--core/Widget/Widget.php37
-rw-r--r--core/Widget/WidgetConfig.php343
-rw-r--r--core/Widget/WidgetContainerConfig.php131
-rw-r--r--core/Widget/WidgetsList.php247
-rw-r--r--core/WidgetsList.php287
-rw-r--r--core/testMinimumPhpVersion.php2
-rw-r--r--lang/en.json3
-rw-r--r--libs/bower_components/angular-animate/.bower.json12
-rw-r--r--libs/bower_components/angular-animate/README.md13
-rw-r--r--libs/bower_components/angular-animate/angular-animate.js4855
-rw-r--r--libs/bower_components/angular-animate/angular-animate.min.js72
-rw-r--r--libs/bower_components/angular-animate/angular-animate.min.js.map6
-rw-r--r--libs/bower_components/angular-animate/bower.json4
-rw-r--r--libs/bower_components/angular-animate/index.js2
-rw-r--r--libs/bower_components/angular-animate/package.json4
-rw-r--r--libs/bower_components/angular-cookies/.bower.json12
-rw-r--r--libs/bower_components/angular-cookies/README.md13
-rw-r--r--libs/bower_components/angular-cookies/angular-cookies.js401
-rw-r--r--libs/bower_components/angular-cookies/angular-cookies.min.js9
-rw-r--r--libs/bower_components/angular-cookies/angular-cookies.min.js.map6
-rw-r--r--libs/bower_components/angular-cookies/bower.json4
-rw-r--r--libs/bower_components/angular-cookies/index.js2
-rw-r--r--libs/bower_components/angular-cookies/package.json4
-rw-r--r--libs/bower_components/angular-mocks/.bower.json12
-rw-r--r--libs/bower_components/angular-mocks/README.md16
-rw-r--r--libs/bower_components/angular-mocks/angular-mocks.js705
-rw-r--r--libs/bower_components/angular-mocks/bower.json4
-rw-r--r--libs/bower_components/angular-mocks/ngAnimateMock.js2
-rw-r--r--libs/bower_components/angular-mocks/ngMock.js2
-rw-r--r--libs/bower_components/angular-mocks/ngMockE2E.js2
-rw-r--r--libs/bower_components/angular-mocks/package.json2
-rw-r--r--libs/bower_components/angular-sanitize/.bower.json12
-rw-r--r--libs/bower_components/angular-sanitize/README.md13
-rw-r--r--libs/bower_components/angular-sanitize/angular-sanitize.js234
-rw-r--r--libs/bower_components/angular-sanitize/angular-sanitize.min.js23
-rw-r--r--libs/bower_components/angular-sanitize/angular-sanitize.min.js.map6
-rw-r--r--libs/bower_components/angular-sanitize/bower.json4
-rw-r--r--libs/bower_components/angular-sanitize/index.js2
-rw-r--r--libs/bower_components/angular-sanitize/package.json4
-rw-r--r--libs/bower_components/angular/.bower.json10
-rw-r--r--libs/bower_components/angular/README.md7
-rw-r--r--libs/bower_components/angular/angular-csp.css13
-rw-r--r--libs/bower_components/angular/angular.js17532
-rw-r--r--libs/bower_components/angular/angular.min.js499
-rw-r--r--libs/bower_components/angular/angular.min.js.gzipbin40123 -> 51629 bytes
-rw-r--r--libs/bower_components/angular/angular.min.js.map6
-rw-r--r--libs/bower_components/angular/bower.json2
-rw-r--r--libs/bower_components/angular/index.js2
-rw-r--r--libs/bower_components/angular/package.json4
-rw-r--r--misc/others/iframeWidget_localhost.php31
-rw-r--r--plugins/API/API.php155
-rw-r--r--plugins/API/ProcessedReport.php102
-rw-r--r--plugins/API/Reports/Get.php6
-rw-r--r--plugins/API/SegmentMetadata.php171
-rw-r--r--plugins/API/WidgetMetadata.php283
-rw-r--r--plugins/API/tests/Unit/WidgetMetadataTest.php283
-rw-r--r--plugins/Actions/API.php3
-rw-r--r--plugins/Actions/Actions.php1
-rw-r--r--plugins/Actions/Categories/DownloadsSubcategory.php19
-rw-r--r--plugins/Actions/Categories/EntryPagesSubcategory.php19
-rw-r--r--plugins/Actions/Categories/ExitPagesSubcategory.php19
-rw-r--r--plugins/Actions/Categories/OutlinksSubcategory.php19
-rw-r--r--plugins/Actions/Categories/PageTitlesSubcategory.php19
-rw-r--r--plugins/Actions/Categories/PagesSubcategory.php19
-rw-r--r--plugins/Actions/Categories/SiteSearchSubcategory.php19
-rw-r--r--plugins/Actions/Controller.php45
-rw-r--r--plugins/Actions/Menu.php29
-rw-r--r--plugins/Actions/Reports/Base.php2
-rw-r--r--plugins/Actions/Reports/GetDownloads.php3
-rw-r--r--plugins/Actions/Reports/GetEntryPageTitles.php12
-rw-r--r--plugins/Actions/Reports/GetEntryPageUrls.php8
-rw-r--r--plugins/Actions/Reports/GetExitPageTitles.php14
-rw-r--r--plugins/Actions/Reports/GetExitPageUrls.php8
-rw-r--r--plugins/Actions/Reports/GetOutlinks.php3
-rw-r--r--plugins/Actions/Reports/GetPageTitles.php10
-rw-r--r--plugins/Actions/Reports/GetPageTitlesFollowingSiteSearch.php6
-rw-r--r--plugins/Actions/Reports/GetPageUrls.php10
-rw-r--r--plugins/Actions/Reports/GetPageUrlsFollowingSiteSearch.php8
-rw-r--r--plugins/Actions/Reports/GetSiteSearchCategories.php5
-rw-r--r--plugins/Actions/Reports/GetSiteSearchKeywords.php2
-rw-r--r--plugins/Actions/Reports/GetSiteSearchNoResultKeywords.php5
-rw-r--r--plugins/Actions/Reports/SiteSearchBase.php2
-rw-r--r--plugins/Actions/templates/indexSiteSearch.twig21
-rwxr-xr-xplugins/Annotations/javascripts/annotations.js3
-rw-r--r--plugins/Contents/Categories/ContentsSubcategory.php19
-rw-r--r--plugins/Contents/Contents.php2
-rw-r--r--plugins/Contents/Controller.php51
-rw-r--r--plugins/Contents/Menu.php24
-rw-r--r--plugins/Contents/Reports/Base.php12
-rw-r--r--plugins/Contents/Reports/GetContentNames.php1
-rw-r--r--plugins/Contents/Reports/GetContentPieces.php2
-rw-r--r--plugins/Contents/Widgets/ContentsByDimension.php21
-rw-r--r--plugins/Contents/tests/System/expected/.gitkeep0
-rw-r--r--plugins/Contents/tests/System/expected/test_Contents_Contents.getContentNames_lastN__API.getProcessedReport_day.xml1
-rw-r--r--plugins/Contents/tests/System/expected/test_Contents_Contents.getContentPieces_lastN__API.getProcessedReport_day.xml1
-rw-r--r--plugins/CoreAdminHome/javascripts/generalSettings.js1
-rw-r--r--plugins/CoreConsole/Commands/GenerateReport.php24
-rw-r--r--plugins/CoreConsole/Commands/GenerateWidget.php76
-rw-r--r--plugins/CoreConsole/Commands/ManagePlugin.php108
-rw-r--r--plugins/CoreHome/Categories/ActionsCategory.php18
-rw-r--r--plugins/CoreHome/Categories/DevicesSubcategory.php19
-rw-r--r--plugins/CoreHome/Categories/EngagementSubcategory.php19
-rw-r--r--plugins/CoreHome/Categories/SoftwareSubcategory.php19
-rw-r--r--plugins/CoreHome/Categories/VisitorsCategory.php18
-rw-r--r--plugins/CoreHome/Categories/VisitorsOverviewSubcategory.php19
-rw-r--r--plugins/CoreHome/Columns/Metrics/AverageTimeOnSite.php2
-rw-r--r--plugins/CoreHome/Controller.php36
-rw-r--r--plugins/CoreHome/CoreHome.php34
-rw-r--r--plugins/CoreHome/Widgets.php63
-rw-r--r--plugins/CoreHome/Widgets/GetDonateForm.php48
-rw-r--r--plugins/CoreHome/Widgets/GetPromoVideo.php44
-rw-r--r--plugins/CoreHome/angularjs/activity-indicator/activityindicator.directive.js31
-rw-r--r--plugins/CoreHome/angularjs/activity-indicator/activityindicator.html3
-rw-r--r--plugins/CoreHome/angularjs/ajax-form/ajax-form.controller.js4
-rw-r--r--plugins/CoreHome/angularjs/ajax-form/ajax-form.directive.js4
-rw-r--r--plugins/CoreHome/angularjs/common/directives/focus-anywhere-but-here.js8
-rw-r--r--plugins/CoreHome/angularjs/common/filters/escape.js16
-rw-r--r--plugins/CoreHome/angularjs/common/services/global-ajax-queue.js14
-rw-r--r--plugins/CoreHome/angularjs/common/services/piwik-api.js21
-rw-r--r--plugins/CoreHome/angularjs/common/services/piwik-url.js54
-rw-r--r--plugins/CoreHome/angularjs/common/services/report-metadata-model.js52
-rw-r--r--plugins/CoreHome/angularjs/common/services/reporting-pages-model.js58
-rw-r--r--plugins/CoreHome/angularjs/enrichedheadline/enrichedheadline.directive.js27
-rw-r--r--plugins/CoreHome/angularjs/http404check.js6
-rw-r--r--plugins/CoreHome/angularjs/menudropdown/menudropdown.directive.html2
-rw-r--r--plugins/CoreHome/angularjs/menudropdown/menudropdown.directive.js13
-rw-r--r--plugins/CoreHome/angularjs/popover-handler/popover-handler.directive.js74
-rw-r--r--plugins/CoreHome/angularjs/reporting-menu/reportingmenu-model.js164
-rw-r--r--plugins/CoreHome/angularjs/reporting-menu/reportingmenu.controller.js135
-rw-r--r--plugins/CoreHome/angularjs/reporting-menu/reportingmenu.directive.html38
-rw-r--r--plugins/CoreHome/angularjs/reporting-menu/reportingmenu.directive.js32
-rw-r--r--plugins/CoreHome/angularjs/reporting-page/reportingpage-model.js196
-rw-r--r--plugins/CoreHome/angularjs/reporting-page/reportingpage.controller.js68
-rw-r--r--plugins/CoreHome/angularjs/reporting-page/reportingpage.directive.html25
-rw-r--r--plugins/CoreHome/angularjs/reporting-page/reportingpage.directive.js31
-rw-r--r--plugins/CoreHome/angularjs/siteselector/siteselector-model.service.js2
-rw-r--r--plugins/CoreHome/angularjs/siteselector/siteselector.directive.js1
-rw-r--r--plugins/CoreHome/angularjs/widget-bydimension-container/widget-bydimension-container.directive.html25
-rw-r--r--plugins/CoreHome/angularjs/widget-bydimension-container/widget-bydimension-container.directive.js67
-rw-r--r--plugins/CoreHome/angularjs/widget-container/widgetcontainer.directive.html10
-rw-r--r--plugins/CoreHome/angularjs/widget-container/widgetcontainer.directive.js32
-rw-r--r--plugins/CoreHome/angularjs/widget-loader/widgetloader.directive.html13
-rw-r--r--plugins/CoreHome/angularjs/widget-loader/widgetloader.directive.js135
-rw-r--r--plugins/CoreHome/angularjs/widget/widget.directive.html24
-rw-r--r--plugins/CoreHome/angularjs/widget/widget.directive.js103
-rw-r--r--plugins/CoreHome/javascripts/broadcast.js67
-rw-r--r--plugins/CoreHome/javascripts/calendar.js2
-rwxr-xr-xplugins/CoreHome/javascripts/corehome.js67
-rw-r--r--plugins/CoreHome/javascripts/dataTable.js3
-rw-r--r--plugins/CoreHome/javascripts/menu.js176
-rw-r--r--plugins/CoreHome/javascripts/menu_init.js40
-rw-r--r--plugins/CoreHome/javascripts/popover.js2
-rw-r--r--plugins/CoreHome/javascripts/sparkline.js28
-rw-r--r--plugins/CoreHome/javascripts/top_controls.js17
-rw-r--r--plugins/CoreHome/lang/en.json3
-rw-r--r--plugins/CoreHome/stylesheets/coreHome.less6
-rw-r--r--plugins/CoreHome/stylesheets/layout.less8
-rw-r--r--plugins/CoreHome/stylesheets/zen-mode.less20
-rw-r--r--plugins/CoreHome/templates/ReportsByDimension/_reportsByDimension.twig29
-rw-r--r--plugins/CoreHome/templates/_indexContent.twig22
-rw-r--r--plugins/CoreHome/templates/_menu.twig64
-rw-r--r--plugins/CoreHome/templates/getDefaultIndexView.twig3
-rwxr-xr-xplugins/CoreHome/templates/widgetContainer.twig18
-rw-r--r--plugins/CoreUpdater/templates/layout.twig2
-rw-r--r--plugins/CoreVisualizations/JqplotDataGenerator/Evolution.php41
-rw-r--r--plugins/CoreVisualizations/Visualizations/Sparkline.php4
-rw-r--r--plugins/CoreVisualizations/Visualizations/Sparklines.php147
-rw-r--r--plugins/CoreVisualizations/Visualizations/Sparklines/Config.php354
-rw-r--r--plugins/CoreVisualizations/javascripts/jqplotEvolutionGraph.js40
-rw-r--r--plugins/CoreVisualizations/templates/_dataTableViz_sparklines.twig34
-rw-r--r--plugins/CoreVisualizations/templates/macros.twig32
-rw-r--r--plugins/CoreVisualizations/tests/Integration/SparklinesConfigTest.php138
-rw-r--r--plugins/CoreVisualizations/tests/Unit/SparklinesConfigTest.php130
m---------plugins/CustomDimensions0
-rw-r--r--plugins/CustomVariables/Categories/CustomVariablesSubcategory.php19
-rw-r--r--plugins/CustomVariables/Reports/Base.php2
-rw-r--r--plugins/CustomVariables/Reports/GetCustomVariables.php4
-rw-r--r--plugins/CustomVariables/tests/System/expected/test_CustomVariablesSystemTest__CustomVariables.getCustomVariables_day.xml288
-rw-r--r--plugins/CustomVariables/tests/UI/expected-ui-screenshots/CustomVariables_manage.pngbin68494 -> 68512 bytes
-rw-r--r--plugins/DBStats/Reports/GetMetricDataSummary.php3
-rw-r--r--plugins/DBStats/Reports/GetMetricDataSummaryByYear.php3
-rw-r--r--plugins/DBStats/Reports/GetReportDataSummary.php3
-rw-r--r--plugins/DBStats/Reports/GetReportDataSummaryByYear.php3
-rw-r--r--plugins/Dashboard/API.php54
-rw-r--r--plugins/Dashboard/Categories/DashboardCategory.php18
-rw-r--r--plugins/Dashboard/Controller.php17
-rw-r--r--plugins/Dashboard/Dashboard.php102
-rw-r--r--plugins/Dashboard/Menu.php30
-rw-r--r--plugins/Dashboard/Model.php8
-rw-r--r--plugins/Dashboard/angularjs/common/services/dashboards-model.js70
-rw-r--r--plugins/Dashboard/angularjs/dashboard/dashboard.directive.js108
-rw-r--r--plugins/Dashboard/javascripts/dashboard.js109
-rw-r--r--plugins/Dashboard/javascripts/dashboardObject.js217
-rwxr-xr-xplugins/Dashboard/javascripts/dashboardWidget.js16
-rw-r--r--plugins/Dashboard/javascripts/widgetMenu.js102
-rw-r--r--plugins/Dashboard/templates/embeddedIndex.twig8
-rw-r--r--plugins/DevicePlugins/Reports/Base.php2
-rw-r--r--plugins/DevicePlugins/Reports/GetPlugin.php5
-rw-r--r--plugins/DevicePlugins/tests/System/expected/test_UserSettingsBCTestUserSettings_UserSettings.getPlugin___API.getMetadata_day.xml3
-rw-r--r--plugins/DevicesDetection/Controller.php41
-rw-r--r--plugins/DevicesDetection/Menu.php7
-rw-r--r--plugins/DevicesDetection/Reports/Base.php2
-rw-r--r--plugins/DevicesDetection/Reports/GetBrand.php5
-rw-r--r--plugins/DevicesDetection/Reports/GetBrowserEngines.php5
-rw-r--r--plugins/DevicesDetection/Reports/GetBrowserVersions.php8
-rw-r--r--plugins/DevicesDetection/Reports/GetBrowsers.php10
-rw-r--r--plugins/DevicesDetection/Reports/GetModel.php3
-rw-r--r--plugins/DevicesDetection/Reports/GetOsFamilies.php8
-rw-r--r--plugins/DevicesDetection/Reports/GetOsVersions.php8
-rw-r--r--plugins/DevicesDetection/Reports/GetType.php3
-rw-r--r--plugins/DevicesDetection/templates/devices.twig19
-rw-r--r--plugins/DevicesDetection/templates/software.twig23
-rw-r--r--plugins/DevicesDetection/tests/System/expected/test_UserSettingsBCTestUserSettings_UserSettings.getBrowserType___API.getMetadata_day.xml3
-rw-r--r--plugins/DevicesDetection/tests/System/expected/test_UserSettingsBCTestUserSettings_UserSettings.getBrowserVersion___API.getMetadata_day.xml10
-rw-r--r--plugins/DevicesDetection/tests/System/expected/test_UserSettingsBCTestUserSettings_UserSettings.getBrowser___API.getMetadata_day.xml12
-rw-r--r--plugins/DevicesDetection/tests/System/expected/test_UserSettingsBCTestUserSettings_UserSettings.getMobileVsDesktop___API.getMetadata_day.xml3
-rw-r--r--plugins/DevicesDetection/tests/System/expected/test_UserSettingsBCTestUserSettings_UserSettings.getOSFamily___API.getMetadata_day.xml10
-rw-r--r--plugins/DevicesDetection/tests/System/expected/test_UserSettingsBCTestUserSettings_UserSettings.getOS___API.getMetadata_day.xml10
-rw-r--r--plugins/Ecommerce/Categories/EcommerceCategory.php18
-rw-r--r--plugins/Ecommerce/Categories/EcommerceLogSubcategory.php19
-rw-r--r--plugins/Ecommerce/Categories/EcommerceOverviewSubcategory.php19
-rw-r--r--plugins/Ecommerce/Categories/ProductSubcategory.php19
-rw-r--r--plugins/Ecommerce/Categories/SalesSubcategory.php19
-rw-r--r--plugins/Ecommerce/Controller.php118
-rw-r--r--plugins/Ecommerce/Menu.php39
-rw-r--r--plugins/Ecommerce/Reports/Base.php2
-rw-r--r--plugins/Ecommerce/Reports/BaseItem.php45
-rw-r--r--plugins/Ecommerce/Reports/GetItemsCategory.php3
-rw-r--r--plugins/Ecommerce/Reports/GetItemsName.php3
-rw-r--r--plugins/Ecommerce/Reports/GetItemsSku.php3
-rw-r--r--plugins/Ecommerce/Widgets.php35
-rw-r--r--plugins/Ecommerce/Widgets/GetEcommerceLog.php28
-rw-r--r--plugins/Ecommerce/Widgets/ProductsByDimension.php34
-rw-r--r--plugins/Ecommerce/templates/conversionOverview.twig19
-rw-r--r--plugins/Ecommerce/templates/ecommerceLog.twig3
-rw-r--r--plugins/Ecommerce/templates/getSparklines.twig56
-rw-r--r--plugins/Events/Categories/EventsSubcategory.php19
-rw-r--r--plugins/Events/Controller.php104
-rw-r--r--plugins/Events/Events.php3
-rw-r--r--plugins/Events/Menu.php21
-rw-r--r--plugins/Events/Reports/Base.php20
-rw-r--r--plugins/Events/Reports/GetAction.php1
-rw-r--r--plugins/Events/Reports/GetActionFromCategoryId.php2
-rw-r--r--plugins/Events/Reports/GetActionFromNameId.php2
-rw-r--r--plugins/Events/Reports/GetCategory.php1
-rw-r--r--plugins/Events/Reports/GetCategoryFromActionId.php2
-rw-r--r--plugins/Events/Reports/GetCategoryFromNameId.php2
-rw-r--r--plugins/Events/Reports/GetName.php1
-rw-r--r--plugins/Events/Reports/GetNameFromActionId.php2
-rw-r--r--plugins/Events/Reports/GetNameFromCategoryId.php5
-rw-r--r--plugins/Events/Widgets/EventsByDimension.php22
-rw-r--r--plugins/Events/templates/index.twig2
-rw-r--r--plugins/ExamplePlugin/Menu.php13
-rw-r--r--plugins/ExamplePlugin/Widgets.php67
-rw-r--r--plugins/ExamplePlugin/Widgets/MyExampleWidget.php80
-rw-r--r--plugins/ExamplePlugin/javascripts/plugin.js2
-rw-r--r--plugins/ExampleReport/Reports/Base.php2
-rw-r--r--plugins/ExampleReport/Reports/GetExampleReport.php8
-rw-r--r--plugins/ExampleRssWidget/Widgets/RssChangelog.php (renamed from plugins/ExampleRssWidget/Widgets.php)31
-rw-r--r--plugins/ExampleRssWidget/Widgets/RssPiwik.php47
-rw-r--r--plugins/ExampleUI/API.php1
-rw-r--r--plugins/ExampleUI/Categories/ExampleUiCategory.php17
-rw-r--r--plugins/ExampleUI/Controller.php154
-rw-r--r--plugins/ExampleUI/Menu.php25
-rw-r--r--plugins/ExampleUI/Reports/Base.php19
-rw-r--r--plugins/ExampleUI/Reports/GetPlanetRatios.php74
-rw-r--r--plugins/ExampleUI/Reports/GetPlanetRatiosWithLogos.php44
-rw-r--r--plugins/ExampleUI/Reports/GetTemperatures.php93
-rw-r--r--plugins/ExampleUI/Reports/GetTemperaturesEvolution.php95
-rw-r--r--plugins/ExampleUI/lang/en.json8
-rw-r--r--plugins/ExampleUI/plugin.json17
-rw-r--r--plugins/Goals/API.php3
-rw-r--r--plugins/Goals/Categories/AddANewGoalSubcategory.php19
-rw-r--r--plugins/Goals/Categories/GoalsCategory.php18
-rw-r--r--plugins/Goals/Categories/GoalsOverviewSubcategory.php19
-rw-r--r--plugins/Goals/Categories/ManageGoalsSubcategory.php19
-rw-r--r--plugins/Goals/Controller.php257
-rw-r--r--plugins/Goals/Conversions.php45
-rw-r--r--plugins/Goals/Goals.php59
-rw-r--r--plugins/Goals/Menu.php46
-rw-r--r--plugins/Goals/Pages.php346
-rw-r--r--plugins/Goals/Reports/Base.php2
-rw-r--r--plugins/Goals/Reports/Get.php131
-rw-r--r--plugins/Goals/Widgets.php39
-rw-r--r--plugins/Goals/Widgets/AddNewGoal.php38
-rw-r--r--plugins/Goals/Widgets/EditGoals.php37
-rw-r--r--plugins/Goals/lang/en.json7
-rw-r--r--plugins/Goals/templates/_titleAndEvolutionGraph.twig86
-rw-r--r--plugins/Goals/templates/addNewGoal.twig1
-rw-r--r--plugins/Goals/templates/conversionOverview.twig19
-rw-r--r--plugins/Goals/templates/editGoals.twig2
-rw-r--r--plugins/Goals/templates/getGoalReportView.twig70
-rw-r--r--plugins/Goals/templates/getOverviewView.twig58
-rw-r--r--plugins/Insights/Widgets.php20
-rw-r--r--plugins/Insights/Widgets/GetInsightsOverview.php20
-rw-r--r--plugins/Insights/Widgets/GetOverallMoversAndShakers.php20
-rw-r--r--plugins/Installation/templates/layout.twig2
-rw-r--r--plugins/Live/Categories/LiveCategory.php17
-rw-r--r--plugins/Live/Categories/VisitorLogSubcategory.php19
-rw-r--r--plugins/Live/Reports/Base.php2
-rw-r--r--plugins/Live/Reports/GetLastVisitsDetails.php24
-rw-r--r--plugins/Live/Reports/GetSimpleLastVisitCount.php9
-rw-r--r--plugins/Live/Widgets.php27
-rw-r--r--plugins/Live/Widgets/GetVisitorProfilePopup.php33
-rw-r--r--plugins/Live/Widgets/Widget.php21
-rw-r--r--plugins/Live/templates/index.twig2
-rw-r--r--plugins/Login/Controller.php10
-rw-r--r--plugins/Login/stylesheets/login.less5
-rw-r--r--plugins/Morpheus/Menu.php11
-rw-r--r--plugins/Morpheus/javascripts/ajaxHelper.js22
-rw-r--r--plugins/Morpheus/javascripts/piwikHelper.js59
-rw-r--r--plugins/Morpheus/stylesheets/base/mixins.less3
-rw-r--r--plugins/Morpheus/stylesheets/general/_utils.less5
-rw-r--r--plugins/Morpheus/stylesheets/main.less2
-rw-r--r--plugins/Morpheus/stylesheets/ui/_map.less4
-rw-r--r--plugins/Morpheus/templates/admin.twig2
-rw-r--r--plugins/Morpheus/templates/dashboard.twig12
-rw-r--r--plugins/Morpheus/templates/layout.twig5
-rw-r--r--plugins/Morpheus/templates/user.twig2
-rw-r--r--plugins/MultiSites/Categories/MultiSitesCategory.php17
-rw-r--r--plugins/MultiSites/Reports/Base.php2
-rw-r--r--plugins/MultiSites/angularjs/dashboard/dashboard-model.service.js2
-rw-r--r--plugins/MultiSites/templates/getSitesInfo.twig6
-rw-r--r--plugins/Overlay/client/client.js56
-rw-r--r--plugins/PiwikPro/Widgets/PromoPiwikPro.php55
-rw-r--r--plugins/PiwikPro/Widgets/RssPiwikPro.php49
-rw-r--r--plugins/PrivacyManager/javascripts/privacySettings.js1
-rw-r--r--plugins/Provider/Reports/GetProvider.php13
-rw-r--r--plugins/Referrers/Categories/AllReferrersSubcategory.php19
-rw-r--r--plugins/Referrers/Categories/CampaignsSubcategory.php19
-rw-r--r--plugins/Referrers/Categories/ReferrersCategory.php18
-rw-r--r--plugins/Referrers/Categories/ReferrersOverviewSubcategory.php19
-rw-r--r--plugins/Referrers/Categories/SearchEnginesSubcategory.php19
-rw-r--r--plugins/Referrers/Categories/WebsitesSubcategory.php19
-rw-r--r--plugins/Referrers/Controller.php211
-rw-r--r--plugins/Referrers/Menu.php23
-rw-r--r--plugins/Referrers/Reports/Base.php2
-rw-r--r--plugins/Referrers/Reports/GetAll.php12
-rw-r--r--plugins/Referrers/Reports/GetCampaigns.php4
-rw-r--r--plugins/Referrers/Reports/GetKeywords.php4
-rw-r--r--plugins/Referrers/Reports/GetReferrerType.php36
-rw-r--r--plugins/Referrers/Reports/GetSearchEngines.php3
-rw-r--r--plugins/Referrers/Reports/GetSocials.php11
-rw-r--r--plugins/Referrers/Reports/GetWebsites.php5
-rw-r--r--plugins/Referrers/Widgets.php24
-rw-r--r--plugins/Referrers/Widgets/GetKeywordsForPage.php23
-rw-r--r--plugins/Referrers/templates/allReferrers.twig11
-rw-r--r--plugins/Referrers/templates/getSearchEnginesAndKeywords.twig13
-rw-r--r--plugins/Referrers/templates/index.twig89
-rw-r--r--plugins/Referrers/templates/indexWebsites.twig13
-rw-r--r--plugins/Referrers/tests/System/expected/test_Referrers_getReferrerType__API.getProcessedReport_day.xml1
-rw-r--r--plugins/Resolution/Reports/Base.php2
-rw-r--r--plugins/Resolution/Reports/GetConfiguration.php8
-rw-r--r--plugins/Resolution/Reports/GetResolution.php8
-rw-r--r--plugins/Resolution/tests/System/expected/test_UserSettingsBCTestUserSettings_UserSettings.getConfiguration___API.getMetadata_day.xml12
-rw-r--r--plugins/Resolution/tests/System/expected/test_UserSettingsBCTestUserSettings_UserSettings.getResolution___API.getMetadata_day.xml10
-rw-r--r--plugins/SEO/Widgets/GetRank.php (renamed from plugins/SEO/Widgets.php)15
-rw-r--r--plugins/ScheduledReports/ScheduledReports.php3
-rw-r--r--plugins/SitesManager/angularjs/sites-manager/sites-manager-admin-sites-model.js2
-rw-r--r--plugins/SitesManager/angularjs/sites-manager/sites-manager.controller.js2
-rw-r--r--plugins/TestRunner/Commands/TestsRun.php4
-rw-r--r--plugins/Transitions/Controller.php6
-rw-r--r--plugins/Transitions/lang/en.json3
-rw-r--r--plugins/UserCountry/Categories/LocationsSubcategory.php19
-rw-r--r--plugins/UserCountry/Controller.php9
-rw-r--r--plugins/UserCountry/Menu.php6
-rw-r--r--plugins/UserCountry/Reports/Base.php2
-rw-r--r--plugins/UserCountry/Reports/GetCity.php5
-rw-r--r--plugins/UserCountry/Reports/GetContinent.php17
-rw-r--r--plugins/UserCountry/Reports/GetCountry.php3
-rw-r--r--plugins/UserCountry/Reports/GetRegion.php4
-rwxr-xr-xplugins/UserCountry/javascripts/userCountry.js3
-rw-r--r--plugins/UserCountry/templates/getDistinctCountries.twig5
-rw-r--r--plugins/UserCountry/templates/index.twig29
-rw-r--r--plugins/UserCountryMap/Categories/RealTimeMapSubcategory.php19
-rw-r--r--plugins/UserCountryMap/Controller.php2
-rw-r--r--plugins/UserCountryMap/Menu.php24
-rw-r--r--plugins/UserCountryMap/UserCountryMap.php16
-rw-r--r--plugins/UserCountryMap/Widgets/GetRealtimeMap.php29
-rw-r--r--plugins/UserCountryMap/Widgets/GetVisitorMap.php23
-rw-r--r--plugins/UserCountryMap/templates/visitorMap.twig2
-rw-r--r--plugins/UserLanguage/Reports/Base.php3
-rw-r--r--plugins/UserLanguage/Reports/GetLanguage.php6
-rw-r--r--plugins/UserLanguage/Reports/GetLanguageCode.php4
-rw-r--r--plugins/UserLanguage/tests/System/expected/test_UserSettingsBCTestUserSettings_UserSettings.getLanguageCode___API.getMetadata_day.xml10
-rw-r--r--plugins/UserLanguage/tests/System/expected/test_UserSettingsBCTestUserSettings_UserSettings.getLanguage___API.getMetadata_day.xml10
-rw-r--r--plugins/UsersManager/javascripts/usersSettings.js2
-rw-r--r--plugins/UsersManager/stylesheets/usersManager.less2
-rw-r--r--plugins/VisitFrequency/Controller.php63
-rw-r--r--plugins/VisitFrequency/Menu.php19
-rw-r--r--plugins/VisitFrequency/Reports/Get.php90
-rw-r--r--plugins/VisitFrequency/Widgets.php23
-rw-r--r--plugins/VisitFrequency/lang/en.json10
-rw-r--r--plugins/VisitFrequency/templates/_sparklines.twig39
-rw-r--r--plugins/VisitFrequency/templates/getSparklines.twig1
-rw-r--r--plugins/VisitFrequency/templates/index.twig9
-rw-r--r--plugins/VisitTime/Categories/TimesSubcategory.php19
-rw-r--r--plugins/VisitTime/Controller.php25
-rw-r--r--plugins/VisitTime/Menu.php19
-rw-r--r--plugins/VisitTime/Reports/Base.php2
-rw-r--r--plugins/VisitTime/Reports/GetByDayOfWeek.php10
-rw-r--r--plugins/VisitTime/Reports/GetVisitInformationPerLocalTime.php18
-rw-r--r--plugins/VisitTime/Reports/GetVisitInformationPerServerTime.php7
-rw-r--r--plugins/VisitTime/templates/index.twig13
-rw-r--r--plugins/VisitorInterest/Controller.php24
-rw-r--r--plugins/VisitorInterest/Menu.php20
-rw-r--r--plugins/VisitorInterest/Reports/Base.php3
-rw-r--r--plugins/VisitorInterest/Reports/GetNumberOfVisitsByDaysSinceLast.php11
-rw-r--r--plugins/VisitorInterest/Reports/GetNumberOfVisitsByVisitCount.php1
-rw-r--r--plugins/VisitorInterest/Reports/GetNumberOfVisitsPerPage.php10
-rw-r--r--plugins/VisitorInterest/Reports/GetNumberOfVisitsPerVisitDuration.php10
-rw-r--r--plugins/VisitorInterest/templates/index.twig21
-rw-r--r--plugins/VisitsSummary/API.php3
-rw-r--r--plugins/VisitsSummary/Controller.php133
-rw-r--r--plugins/VisitsSummary/Menu.php20
-rw-r--r--plugins/VisitsSummary/Reports/Get.php168
-rw-r--r--plugins/VisitsSummary/Widgets.php22
-rw-r--r--plugins/VisitsSummary/Widgets/Index.php47
-rw-r--r--plugins/VisitsSummary/lang/en.json30
-rw-r--r--plugins/Widgetize/Controller.php4
-rw-r--r--plugins/Widgetize/templates/iframe.twig3
-rw-r--r--plugins/Widgetize/templates/index.twig1
-rw-r--r--plugins/Widgetize/tests/System/WidgetTest.php1851
-rw-r--r--tests/PHPUnit/Fixtures/OmniFixture.php13
-rw-r--r--tests/PHPUnit/Fixtures/UITestFixture.php17
-rw-r--r--tests/PHPUnit/Framework/Mock/Category/Categeories.php63
-rwxr-xr-xtests/PHPUnit/Framework/TestCase/SystemTestCase.php7
-rw-r--r--tests/PHPUnit/Framework/TestRequest/Response.php4
-rw-r--r--tests/PHPUnit/Integration/Category/CategoryListTest.php133
-rw-r--r--tests/PHPUnit/Integration/DataTable/Filter/PivotByDimensionTest.php2
-rw-r--r--tests/PHPUnit/Integration/Menu/MenuReportingTest.php80
-rw-r--r--tests/PHPUnit/Integration/Plugin/CategoriesTest.php89
-rw-r--r--tests/PHPUnit/Integration/Plugin/ManagerTest.php26
-rw-r--r--tests/PHPUnit/Integration/Plugin/SettingsTest.php1
-rw-r--r--tests/PHPUnit/Integration/Plugin/WidgetsTest.php81
-rw-r--r--tests/PHPUnit/Integration/Report/ReportsTest.php72
-rw-r--r--tests/PHPUnit/Integration/ReportTest.php148
-rw-r--r--tests/PHPUnit/Integration/WidgetsListTest.php147
-rwxr-xr-xtests/PHPUnit/System/ApiGetReportMetadataTest.php1
-rw-r--r--tests/PHPUnit/System/ArchiveCronTest.php4
-rw-r--r--tests/PHPUnit/System/AutoSuggestAPITest.php6
-rw-r--r--tests/PHPUnit/System/CliMultiTest.php3
-rwxr-xr-xtests/PHPUnit/System/ManyVisitorsOneWebsiteTest.php90
-rw-r--r--tests/PHPUnit/System/PivotByQueryParamTest.php4
-rwxr-xr-xtests/PHPUnit/System/TwoVisitorsTwoWebsitesDifferentDaysArchivingDisabledTest.php3
-rwxr-xr-xtests/PHPUnit/System/TwoVisitorsTwoWebsitesDifferentDaysConversionsTest.php13
-rwxr-xr-xtests/PHPUnit/System/TwoVisitorsTwoWebsitesDifferentDaysTest.php3
-rwxr-xr-xtests/PHPUnit/System/TwoVisitsWithCustomVariablesSegmentMatchVisitorTypeTest.php2
-rw-r--r--tests/PHPUnit/System/expected/test_ArchiveCronTest_archive_php_cron_output.txt168
-rw-r--r--tests/PHPUnit/System/expected/test_CustomEvents_Events.getAction_flat__API.getProcessedReport_day.xml15
-rw-r--r--tests/PHPUnit/System/expected/test_CustomEvents_Events.getAction_lastN__API.getProcessedReport_day.xml3
-rw-r--r--tests/PHPUnit/System/expected/test_CustomEvents_Events.getCategory_flat__API.getProcessedReport_day.xml3
-rw-r--r--tests/PHPUnit/System/expected/test_CustomEvents_Events.getCategory_lastN__API.getProcessedReport_day.xml3
-rw-r--r--tests/PHPUnit/System/expected/test_CustomEvents_Events.getName_flat__API.getProcessedReport_day.xml15
-rw-r--r--tests/PHPUnit/System/expected/test_CustomEvents_Events.getName_lastN__API.getProcessedReport_day.xml5
-rw-r--r--tests/PHPUnit/System/expected/test_CustomEvents__Events.getAction_day.xml12
-rw-r--r--tests/PHPUnit/System/expected/test_CustomEvents__Events.getAction_month.xml12
-rw-r--r--tests/PHPUnit/System/expected/test_CustomEvents__Events.getName_day.xml2
-rw-r--r--tests/PHPUnit/System/expected/test_CustomEvents__Events.getName_month.xml2
-rw-r--r--tests/PHPUnit/System/expected/test_CustomEvents__Live.getLastVisitsDetails_day.xml28
-rw-r--r--tests/PHPUnit/System/expected/test_CustomEvents__Live.getLastVisitsDetails_month.xml28
-rw-r--r--tests/PHPUnit/System/expected/test_CustomEvents_eventCategoryOrNameMatch__Events.getAction_day.xml12
-rw-r--r--tests/PHPUnit/System/expected/test_CustomEvents_eventCategoryOrNameMatch__Events.getName_day.xml2
-rw-r--r--tests/PHPUnit/System/expected/test_CustomEvents_secondaryDimensionIsEventAction__Events.getName_day.xml2
-rw-r--r--tests/PHPUnit/System/expected/test_CustomEvents_secondaryDimensionIsEventAction__Events.getName_month.xml2
-rw-r--r--tests/PHPUnit/System/expected/test_CustomEvents_secondaryDimensionIsEventCategory__Events.getName_day.xml2
-rw-r--r--tests/PHPUnit/System/expected/test_CustomEvents_secondaryDimensionIsEventCategory__Events.getName_month.xml2
-rw-r--r--tests/PHPUnit/System/expected/test_CustomEvents_secondaryDimensionIsEventName__Events.getAction_day.xml12
-rw-r--r--tests/PHPUnit/System/expected/test_CustomEvents_secondaryDimensionIsEventName__Events.getAction_month.xml12
-rw-r--r--tests/PHPUnit/System/expected/test_CustomEvents_secondaryDimensionIsEventName__Events.getCategory_day.xml2
-rw-r--r--tests/PHPUnit/System/expected/test_CustomEvents_secondaryDimensionIsEventName__Events.getCategory_month.xml2
-rw-r--r--tests/PHPUnit/System/expected/test_CustomEvents_segmentMatchesEventActionPlay__Events.getAction_day.xml10
-rw-r--r--tests/PHPUnit/System/expected/test_CustomEvents_segmentMatchesEventActionPlay__Events.getName_day.xml2
-rw-r--r--tests/PHPUnit/System/expected/test_FlattenReports__CustomVariables.getCustomVariables_day.xml32
-rw-r--r--tests/PHPUnit/System/expected/test_LabelFilter_thisiscool__Actions.getPageUrls_day.xml2
-rw-r--r--tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_Live.getLastVisitsDetails_offsetAndLimit_1__Live.getLastVisitsDetails_month.xml2
-rw-r--r--tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_Live.getLastVisitsDetails_offsetAndLimit_2__Live.getLastVisitsDetails_month.xml4
-rw-r--r--tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_Live.getLastVisitsDetails_sortByIdVisit__Live.getLastVisitsDetails_month.xml8
-rw-r--r--tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_Live.getLastVisitsDetails_sortDesc__Live.getLastVisitsDetails_month.xml8
-rw-r--r--tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest__Live.getLastVisitsDetails_month.xml10
-rw-r--r--tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_sortByProcessedMetric__API.getProcessedReport_day.xml21
-rw-r--r--tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_sortByProcessedMetric_constantRowsCountShouldKeepEmptyRows__API.getProcessedReport_day.xml5
-rw-r--r--tests/PHPUnit/System/expected/test_OneVisitorTwoVisits__subtable__API.getProcessedReport_week.xml1
-rw-r--r--tests/PHPUnit/System/expected/test_OneVisitorTwoVisits_hideColumns___API.getProcessedReport_day.xml13
-rw-r--r--tests/PHPUnit/System/expected/test_OneVisitorTwoVisits_showColumnsWithProcessedMetrics___API.getProcessedReport_day.xml5
-rw-r--r--tests/PHPUnit/System/expected/test_OneVisitorTwoVisits_showColumns___API.getProcessedReport_day.xml13
-rw-r--r--tests/PHPUnit/System/expected/test_OneVisitorTwoVisits_showColumns_onlyOne__API.getProcessedReport_day.xml3
-rw-r--r--tests/PHPUnit/System/expected/test_PivotByQueryParamTest_test_PivotByParam_PlaysNiceWithDataTableMaps__Referrers.getKeywords_day.xml34
-rw-r--r--tests/PHPUnit/System/expected/test_PivotByQueryParamTest_test_PivotByParam_WorksWithColumnLimiting__Referrers.getKeywords_week.xml28
-rw-r--r--tests/PHPUnit/System/expected/test_PivotByQueryParamTest_test_PivotByParam_WorksWithCsvOutput__Referrers.getKeywords_week.csvbin458 -> 458 bytes
-rw-r--r--tests/PHPUnit/System/expected/test_PivotByQueryParamTest_test_PivotByParam_WorksWithJsonOutput__Referrers.getKeywords_week.json2
-rw-r--r--tests/PHPUnit/System/expected/test_PivotByQueryParamTest_test_PivotByParam_WorksWithReportWhoseSubtableIsSelf__Actions.getPageUrls_week.xml72
-rw-r--r--tests/PHPUnit/System/expected/test_PivotByQueryParamTest_test_PivotBySegment_CreatesCorrectPivotTable_WhenPeriodIsRange__Referrers.getKeywords_range.xml34
-rw-r--r--tests/PHPUnit/System/expected/test_PivotByQueryParamTest_test_PivotBySegment_CreatesCorrectPivotTable_WhenSegmentUsedInRequest__Referrers.getKeywords_week.xml4
-rw-r--r--tests/PHPUnit/System/expected/test_PivotByQueryParamTest_test_PivotBySegment_CreatesCorrectPivotTable__Referrers.getKeywords_week.xml34
-rw-r--r--tests/PHPUnit/System/expected/test_PivotByQueryParamTest_test_PivotBySubtableDimension_CreatesCorrectPivotTable_WhenPeriodIsDateRange__Referrers.getKeywords_range.xml40
-rw-r--r--tests/PHPUnit/System/expected/test_PivotByQueryParamTest_test_PivotBySubtableDimension_CreatesCorrectPivotTable__Referrers.getKeywords_week.xml40
-rw-r--r--tests/PHPUnit/System/expected/test_PivotByQueryParamTest_test_PivotBySubtableDimension_WhenEntireHirearchyIsNotLoaded__Referrers.getKeywords_week.xml40
-rw-r--r--tests/PHPUnit/System/expected/test_SiteSearch_Actions.getPageTitlesFollowingSiteSearch_firstSite_lastN__API.getProcessedReport_day.xml10
-rw-r--r--tests/PHPUnit/System/expected/test_SiteSearch_Actions.getPageTitlesFollowingSiteSearch_firstSite_lastN__API.getProcessedReport_month.xml10
-rw-r--r--tests/PHPUnit/System/expected/test_SiteSearch_Actions.getPageTitles_firstSite_lastN__API.getProcessedReport_day.xml13
-rw-r--r--tests/PHPUnit/System/expected/test_SiteSearch_Actions.getPageTitles_firstSite_lastN__API.getProcessedReport_month.xml13
-rw-r--r--tests/PHPUnit/System/expected/test_SiteSearch_Actions.getPageUrlsFollowingSiteSearch_firstSite_lastN__API.getProcessedReport_day.xml10
-rw-r--r--tests/PHPUnit/System/expected/test_SiteSearch_Actions.getPageUrlsFollowingSiteSearch_firstSite_lastN__API.getProcessedReport_month.xml10
-rw-r--r--tests/PHPUnit/System/expected/test_SiteSearch_Actions.getPageUrls_firstSite_lastN__API.getProcessedReport_day.xml1
-rw-r--r--tests/PHPUnit/System/expected/test_SiteSearch_Actions.getPageUrls_firstSite_lastN__API.getProcessedReport_month.xml1
-rw-r--r--tests/PHPUnit/System/expected/test_SiteSearch_Actions.getSiteSearchCategories_firstSite_lastN__API.getProcessedReport_day.xml3
-rw-r--r--tests/PHPUnit/System/expected/test_SiteSearch_Actions.getSiteSearchCategories_firstSite_lastN__API.getProcessedReport_month.xml3
-rw-r--r--tests/PHPUnit/System/expected/test_SiteSearch_Actions.getSiteSearchKeywords_firstSite_lastN__API.getProcessedReport_day.xml3
-rw-r--r--tests/PHPUnit/System/expected/test_SiteSearch_Actions.getSiteSearchKeywords_firstSite_lastN__API.getProcessedReport_month.xml3
-rw-r--r--tests/PHPUnit/System/expected/test_SiteSearch_Actions.getSiteSearchNoResultKeywords_firstSite_lastN__API.getProcessedReport_day.xml3
-rw-r--r--tests/PHPUnit/System/expected/test_SiteSearch_Actions.getSiteSearchNoResultKeywords_firstSite_lastN__API.getProcessedReport_month.xml3
-rw-r--r--tests/PHPUnit/System/expected/test_SiteSearch_CustomVariables.getCustomVariables_firstSite_lastN__API.getProcessedReport_day.xml1
-rw-r--r--tests/PHPUnit/System/expected/test_SiteSearch_CustomVariables.getCustomVariables_firstSite_lastN__API.getProcessedReport_month.xml1
-rw-r--r--tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_Actions.getOutlinks_firstSite_lastN__API.getProcessedReport_day.xml1
-rw-r--r--tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_Actions.getPageTitles_firstSite_lastN__API.getProcessedReport_day.xml13
-rw-r--r--tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_Actions.getPageUrls_firstSite_lastN__API.getProcessedReport_day.xml1
-rw-r--r--tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_Referrers.getWebsites_firstSite_lastN__API.getProcessedReport_day.xml1
-rw-r--r--tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_VisitFrequency.get_firstSite_lastN__API.getProcessedReport_day.xml1
-rw-r--r--tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_VisitorInterest.getNumberOfVisitsByDaysSinceLast_firstSite_lastN__API.getProcessedReport_day.xml1
-rw-r--r--tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_VisitsSummary.get_firstSite_lastN__API.getProcessedReport_day.xml3
-rw-r--r--tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_scheduled_report_in_csv__ScheduledReports.generateReport_month.original.csv432
-rw-r--r--tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_scheduled_report_in_html_tables_only__ScheduledReports.generateReport_month.original.html4480
-rw-r--r--tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_scheduled_report_in_pdf_tables_only__ScheduledReports.generateReport_month.original.pdfbin512633 -> 512416 bytes
-rw-r--r--tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getGlossaryMetrics.xml6
-rw-r--r--tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getGlossaryReports.xml46
-rw-r--r--tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getMetadata_day.xml1
-rw-r--r--tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getProcessedReport_day.xml1
-rw-r--r--tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getReportMetadata_day.xml2024
-rw-r--r--tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getReportPagesMetadata.xml4193
-rw-r--r--tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getSegmentsMetadata.xml32
-rw-r--r--tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getWidgetMetadata.xml2821
-rw-r--r--tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getWidgetMetadata_day.xml1987
-rw-r--r--tests/PHPUnit/System/expected/test_apiGetReportMetadata_showRawMetrics__API.getProcessedReport_day.xml1
-rw-r--r--tests/PHPUnit/System/expected/test_apiGetReportMetadata_year__API.getProcessedReport_year.xml1
-rw-r--r--tests/PHPUnit/System/expected/test_csvExport_xp0__CustomVariables.getCustomVariables_day.csvbin1984 -> 1984 bytes
-rw-r--r--tests/PHPUnit/System/expected/test_csvExport_xp1_inner1_trans-de__CustomVariables.getCustomVariables_day.csvbin3468 -> 3468 bytes
-rw-r--r--tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_Metadata_ItemsCategory__API.getProcessedReport_day.xml1
-rw-r--r--tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_Metadata_ItemsSku__API.getProcessedReport_day.xml1
-rwxr-xr-xtests/PHPUnit/System/expected/test_ecommerceOrderWithItems_Metadata_VisitTime.getVisitInformationPerServerTime__API.getProcessedReport_day.xml5
-rw-r--r--tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_SegmentPageUrlContains__Goals.getItemsName_day.xml12
-rw-r--r--tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_SegmentPageUrlContains__Goals.getItemsName_week.xml12
-rwxr-xr-xtests/PHPUnit/System/expected/test_ecommerceOrderWithItems__API.getProcessedReport_day.xml1
-rw-r--r--tests/PHPUnit/System/expected/test_ecommerceOrderWithItems__Goals.getItemsName_day.xml12
-rw-r--r--tests/PHPUnit/System/expected/test_ecommerceOrderWithItems__Goals.getItemsName_week.xml12
-rw-r--r--tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_scheduled_report_in_csv__ScheduledReports.generateReport_week.original.csv586
-rw-r--r--tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_scheduled_report_in_html_tables_only__ScheduledReports.generateReport_week.original.html5248
-rw-r--r--tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_scheduled_report_in_pdf_tables_only__ScheduledReports.generateReport_week.original.pdfbin516593 -> 534576 bytes
-rw-r--r--tests/PHPUnit/System/expected/test_ecommerceOrderWithItemsmultipleDates__Goals.getItemsName_day.xml12
-rw-r--r--tests/PHPUnit/System/expected/test_periodIsRange_dateIsLastN_MetadataAndNormalAPI__API.getProcessedReport_range.xml1
-rw-r--r--tests/PHPUnit/System/expected/test_periodIsRange_dateIsLastN_MetadataAndNormalAPI__CustomVariables.getCustomVariables_range.xml58
-rw-r--r--tests/PHPUnit/System/expected/test_periodIsRange_dateIsLastN_MetadataAndNormalAPI_pagesegment__API.getProcessedReport_range.xml1
-rw-r--r--tests/PHPUnit/System/expected/test_periodIsRange_dateIsLastN_MetadataAndNormalAPI_pagesegment__CustomVariables.getCustomVariables_range.xml58
-rw-r--r--tests/PHPUnit/System/expected/test_reportLimiting__CustomVariables.getCustomVariables_day.xml16
-rw-r--r--tests/PHPUnit/System/expected/test_reportLimiting__UserCountry.getCity_day.xml2
-rw-r--r--tests/PHPUnit/System/expected/test_reportLimiting__UserCountry.getRegion_day.xml2
-rw-r--r--tests/PHPUnit/System/expected/test_reportLimiting_flattened__CustomVariables.getCustomVariables_day.xml20
-rw-r--r--tests/PHPUnit/System/expected/test_reportLimiting_flattened__UserCountry.getCity_day.xml2
-rw-r--r--tests/PHPUnit/System/expected/test_reportLimiting_flattened__UserCountry.getRegion_day.xml2
-rw-r--r--tests/PHPUnit/System/expected/test_reportLimiting_rankingQuery__CustomVariables.getCustomVariables_day.xml16
-rw-r--r--tests/PHPUnit/System/expected/test_reportLimiting_rankingQuery__UserCountry.getCity_day.xml2
-rw-r--r--tests/PHPUnit/System/expected/test_reportLimiting_rankingQuery__UserCountry.getRegion_day.xml2
-rw-r--r--tests/PHPUnit/System/expected/test_twoVisitsWithCustomVariables__CustomVariables.getCustomVariables_day.xml2
-rw-r--r--tests/PHPUnit/System/expected/test_twoVisitsWithCustomVariables__CustomVariables.getCustomVariables_week.xml2
-rw-r--r--tests/PHPUnit/System/expected/test_twoVisitsWithCustomVariables_segmentMatchALL_noGoalData__CustomVariables.getCustomVariables_day.xml54
-rw-r--r--tests/PHPUnit/System/expected/test_twoVisitsWithCustomVariables_segmentMatchALL_noGoalData__CustomVariables.getCustomVariables_week.xml58
-rw-r--r--tests/PHPUnit/System/expected/test_twoVisitsWithCustomVariables_segmentMatchVisitorType__CustomVariables.getCustomVariables_day.xml54
-rw-r--r--tests/PHPUnit/System/expected/test_twoVisitsWithCustomVariables_segmentMatchVisitorType__CustomVariables.getCustomVariables_week.xml58
-rw-r--r--tests/PHPUnit/Unit/Category/CategoryListTest.php92
-rw-r--r--tests/PHPUnit/Unit/Category/CategoryTest.php141
-rw-r--r--tests/PHPUnit/Unit/Category/SubcategoryTest.php89
-rw-r--r--tests/PHPUnit/Unit/CommonTest.php8
-rw-r--r--tests/PHPUnit/Unit/DataTable/Filter/SortTest.php145
-rw-r--r--tests/PHPUnit/Unit/Metrics/SorterTest.php405
-rw-r--r--tests/PHPUnit/Unit/Report/ReportWidgetConfigTest.php262
-rw-r--r--tests/PHPUnit/Unit/Report/ReportWidgetFactoryTest.php112
-rw-r--r--tests/PHPUnit/Unit/UrlHelperTest.php10
-rw-r--r--tests/PHPUnit/Unit/Widget/WidgetConfigTest.php224
-rw-r--r--tests/PHPUnit/Unit/Widget/WidgetContainerConfigTest.php280
-rw-r--r--tests/PHPUnit/Unit/Widget/WidgetsListTest.php177
-rw-r--r--tests/UI/diff.pngbin0 -> 13648 bytes
m---------tests/UI/expected-ui-screenshots0
-rw-r--r--tests/UI/specs/DashboardManager_spec.js6
-rw-r--r--tests/UI/specs/Dashboard_spec.js29
-rw-r--r--tests/UI/specs/Menus_spec.js8
-rw-r--r--tests/UI/specs/Overlay_spec.js2
-rw-r--r--tests/UI/specs/PeriodSelector_spec.js3
-rw-r--r--tests/UI/specs/PivotByDimension_spec.js6
-rw-r--r--tests/UI/specs/ReportExporting_spec.js4
-rw-r--r--tests/UI/specs/RowEvolution_spec.js1
-rw-r--r--tests/UI/specs/SegmentSelectorEditor_spec.js7
-rw-r--r--tests/UI/specs/Transitions_spec.js4
-rw-r--r--tests/UI/specs/UIIntegration_spec.js113
-rw-r--r--tests/lib/screenshot-testing/support/chai-extras.js6
-rw-r--r--tests/lib/screenshot-testing/support/page-renderer.js4
634 files changed, 47185 insertions, 21215 deletions
diff --git a/.travis.yml b/.travis.yml
index 889a879980..a672f9eb38 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -13,7 +13,7 @@ group: legacy
php:
- 5.6
- - 5.3.3
+ - 5.5
# - hhvm
services:
@@ -60,15 +60,15 @@ matrix:
- php: 7
exclude:
# Run test suites separately only on PHP 5.6 with PDO
- - php: 5.3.3
+ - php: 5.5
env: TEST_SUITE=SystemTests MYSQL_ADAPTER=PDO_MYSQL
- - php: 5.3.3
+ - php: 5.5
env: TEST_SUITE=IntegrationTests MYSQL_ADAPTER=PDO_MYSQL
- - php: 5.3.3
+ - php: 5.5
env: TEST_SUITE=AllTests MYSQL_ADAPTER=PDO_MYSQL
- php: 7
env: TEST_SUITE=AllTests MYSQL_ADAPTER=PDO_MYSQL
- - php: 5.3.3
+ - php: 5.5
env: TEST_SUITE=UnitTests MYSQL_ADAPTER=PDO_MYSQL
- php: hhvm
env: TEST_SUITE=SystemTests MYSQL_ADAPTER=PDO_MYSQL
@@ -76,7 +76,7 @@ matrix:
env: TEST_SUITE=IntegrationTests MYSQL_ADAPTER=PDO_MYSQL
- php: hhvm
env: TEST_SUITE=UnitTests MYSQL_ADAPTER=PDO_MYSQL
- # run UI tests on PHP 5.3.3 only
+ # run UI tests on PHP 5.5 only
- php: 5.6
env: TEST_SUITE=UITests MYSQL_ADAPTER=PDO_MYSQL UITEST_EXTRA_OPTIONS="--run-first-half-only"
- php: 5.6
@@ -84,21 +84,21 @@ matrix:
# run all tests not on PHP 5.6 and run MySQLI tests only on 5.6
- php: 5.6
env: TEST_SUITE=AllTests MYSQL_ADAPTER=PDO_MYSQL
- - php: 5.3.3
+ - php: 5.5
env: TEST_SUITE=AllTests MYSQL_ADAPTER=MYSQLI
- php: 7
env: TEST_SUITE=AllTests MYSQL_ADAPTER=MYSQLI
- php: hhvm
env: TEST_SUITE=AllTests MYSQL_ADAPTER=MYSQLI
# Javascript tests need to run only on one PHP version
- - php: 5.3.3
+ - php: 5.5
env: TEST_SUITE=JavascriptTests MYSQL_ADAPTER=PDO_MYSQL
- php: hhvm
env: TEST_SUITE=JavascriptTests MYSQL_ADAPTER=PDO_MYSQL
- php: 7
env: TEST_SUITE=JavascriptTests MYSQL_ADAPTER=PDO_MYSQL
# AngularJS tests need to run only on one PHP version
- - php: 5.3.3
+ - php: 5.5
env: TEST_SUITE=AngularJSTests MYSQL_ADAPTER=PDO_MYSQL SKIP_COMPOSER_INSTALL=1
- php: hhvm
env: TEST_SUITE=AngularJSTests MYSQL_ADAPTER=PDO_MYSQL SKIP_COMPOSER_INSTALL=1
@@ -109,15 +109,12 @@ sudo: required
script: $PIWIK_ROOT_DIR/tests/travis/travis.sh
-before_install:
- # do not use the Zend allocator on PHP 5.3 since it will randomly segfault after program execution
- - '[[ "$TRAVIS_PHP_VERSION" == 5.3* ]] && export USE_ZEND_ALLOC=0 || true'
-
install:
- git fetch -q
- - export GENERATE_TRAVIS_YML_COMMAND="php ./tests/travis/generator/main.php generate:travis-yml --core --verbose"
- - '[[ "$TRAVIS_JOB_NUMBER" != *.1 || "$TRAVIS_PULL_REQUEST" != "false" ]] || ./tests/travis/autoupdate_travis_yml.sh'
+ # Disable it until this is in master, otherwise we have to create a branch for travis submodule
+ #- export GENERATE_TRAVIS_YML_COMMAND="php ./tests/travis/generator/main.php generate:travis-yml --core --verbose"
+ #- '[[ "$TRAVIS_JOB_NUMBER" != *.1 || "$TRAVIS_PULL_REQUEST" != "false" ]] || ./tests/travis/autoupdate_travis_yml.sh'
- ./tests/travis/configure_git.sh
@@ -195,4 +192,4 @@ notifications:
- "irc.freenode.org#piwik-dev"
template:
- "%{repository} (%{commit}) : %{message} %{foo} "
- - "Build details: %{build_url}" \ No newline at end of file
+ - "Build details: %{build_url}"
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0bdf98fe7c..df034f4ea8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,44 @@
This is a changelog for Piwik platform developers. All changes for our HTTP API's, Plugins, Themes, etc will be listed here.
+## Piwik 3.0.0
+
+### Breaking Changes
+* The menu classes `Piwik\Menu\MenuReporting` and `Piwik\Menu\MenuMain` have been removed
+* The class `Piwik\Plugin\Widgets` has been removed and replaced by `Piwik\Widget\Widget`. For each widget one class is needed from now on. You can generate a widget via `./console generate:widget`.
+* The class `Piwik\WidgetList` class has been moved to `Piwik\Widget\WidgetsList`.
+* The method `Piwik\Plugin\Menu::configureReportingMenu` has been removed. To add something to the reporting menu you need to create widgets
+* The method `Report::configureWidget()`, `Report::getWidgetTitle()` and `Report::configureReportingMenu()` have been removed, use the new method `Report::configureWidgets()` instead.
+* The method `Report::getCategory()` has been moved to `Report::getCategoryId()` and does no longer return the translated category but the translation key of the category.
+* The property `Report::$category` has been renamed to `Report::$categoryId`
+* The methods `Report::factory()`, `Report::getAllReportClasses()`, `Report::getAllReports` have been moved to the `Piwik\Plugin\Reports` class.
+* The properties `Report::$widgetTitle`, `Report::$widgetParams` and `Report::$menuTitle` were removed, use the method `Report::configureWidgets()` to create widgets instead
+* In the HTTP API methods `Dashboard.getDefaultDashboard` and `Dashboard.getUserDashboards` we do no longer remove not existing widgets as it is up to the client which widgets actually exist
+* The method `Piwik\Plugin\Controller::getEvolutionHtml` has been removed without a replacement as it should be no longer needed. The evolution is generated by ViewDataTables directly
+* The `core:plugin` console command has been removed in favor of the new `plugin:list`, `plugin:activate` and `plugin:deactivate` commands as anounced in Piwik 2.11
+* The visibility of private properties and methods in `Piwik\Plugins\Login\Controller` were changed to `protected`
+* Controller actions are now case sensitive. This means the URL and events have to use the same case as the name of the action defined in a controller.
+
+### New APIs
+* Multiple widgets for one report can now be created via the `Report::configureWidgets()` method via the new classes `Piwik\Widget\ReportWidgetFactory` and `Piwik\Widget\ReportWidgetConfig`
+* There is a new property `Report::$subCategory` that let's you add a report to the reporting UI. If a page having that name does not exist yet, it will be created automatically. The newly added method `Report::getSubCategory()` let's you get this value.
+* The new classes `Piwik\Widget\Widget`, `Piwik\Widget\WidgetConfig` and `Piwik\Widget\WidgetContainerConfig` let's you create a new widget.
+* The new class `Piwik\Category\Subcategory` let you change the name and order of menu items
+* New HTTP API method `API.getWidgetMetadata` to get a list of available widgets
+* New HTTP API method `API.getReportPagesMetadata` to get a list of all available pages that exist including the widgets they include
+* The JavaScript AjaxHelper has a new method `ajaxHelper.withTokenInUrl()` to easily send a token along a XHR. Within the Controller the existence of this token can be checked via `$this->checkTokenInUrl();` to prevent CSRF attacks.
+
+### New features
+* New "Sparklines" visualization that let's you create a widget showing multiple sparklines
+
+### Library updates
+* Updated AngularJS from 1.2.28 to 1.4.3
+
+### Internal change
+* Support for IE8 was dropped. This affects only the Piwik UI, not the Piwik.js Tracker.
+* Required PHP version was changed from 5.3 to 5.5
+
+
## Piwik 2.16.1
### New features
diff --git a/bower.json b/bower.json
index 49252d932e..0dc775985a 100644
--- a/bower.json
+++ b/bower.json
@@ -15,11 +15,11 @@
"dependencies": {
"jquery-ui": "1.10.4",
"jquery": "~1.11.0",
- "angular": "~1.2.0",
- "angular-sanitize": "~1.2.0",
- "angular-animate": "~1.2.0",
- "angular-cookies": "~1.2.0",
- "angular-mocks": "~1.2.0",
+ "angular": "~1.4.0",
+ "angular-sanitize": "~1.4.0",
+ "angular-animate": "~1.4.0",
+ "angular-cookies": "~1.4.0",
+ "angular-mocks": "~1.4.0",
"ngDialog": "~0.2.0",
"html5shiv": "~3.7.0",
"mousetrap": "~1.4.0",
diff --git a/composer.json b/composer.json
index 3c6521b827..b7ebee8d64 100644
--- a/composer.json
+++ b/composer.json
@@ -47,7 +47,7 @@
"piwik/network": "~0.1.0",
"piwik/cache": "~0.2.5",
"piwik/ini": "^1.0.6",
- "php-di/php-di": "5.0.0-beta1",
+ "php-di/php-di": "^5.0.0",
"psr/log": "~1.0",
"monolog/monolog": "~1.11",
"symfony/monolog-bridge": "~2.6.0",
diff --git a/core/API/DataTableGenericFilter.php b/core/API/DataTableGenericFilter.php
index 5d4ba49422..696e94f756 100644
--- a/core/API/DataTableGenericFilter.php
+++ b/core/API/DataTableGenericFilter.php
@@ -98,6 +98,9 @@ class DataTableGenericFilter
array(
'filter_sort_column' => array('string'),
'filter_sort_order' => array('string', 'desc'),
+ $naturalSort = true,
+ $recursiveSort = true,
+ $doSortBySecondaryColumn = true
)),
array('Truncate',
array(
@@ -159,22 +162,27 @@ class DataTableGenericFilter
}
foreach ($filterParams as $name => $info) {
- // parameter type to cast to
- $type = $info[0];
-
- // default value if specified, when the parameter doesn't have a value
- $defaultValue = null;
- if (isset($info[1])) {
- $defaultValue = $info[1];
- }
-
- try {
- $value = Common::getRequestVar($name, $defaultValue, $type, $this->request);
- settype($value, $type);
- $filterParameters[] = $value;
- } catch (Exception $e) {
- $exceptionRaised = true;
- break;
+ if (!is_array($info)) {
+ // hard coded value that cannot be changed via API, see eg $naturalSort = true in 'Sort'
+ $filterParameters[] = $info;
+ } else {
+ // parameter type to cast to
+ $type = $info[0];
+
+ // default value if specified, when the parameter doesn't have a value
+ $defaultValue = null;
+ if (isset($info[1])) {
+ $defaultValue = $info[1];
+ }
+
+ try {
+ $value = Common::getRequestVar($name, $defaultValue, $type, $this->request);
+ settype($value, $type);
+ $filterParameters[] = $value;
+ } catch (Exception $e) {
+ $exceptionRaised = true;
+ break;
+ }
}
}
diff --git a/core/API/DataTableManipulator/ReportTotalsCalculator.php b/core/API/DataTableManipulator/ReportTotalsCalculator.php
index 83fef53a27..7906077b1e 100644
--- a/core/API/DataTableManipulator/ReportTotalsCalculator.php
+++ b/core/API/DataTableManipulator/ReportTotalsCalculator.php
@@ -13,6 +13,7 @@ use Piwik\DataTable;
use Piwik\Metrics;
use Piwik\Period;
use Piwik\Plugin\Report;
+use Piwik\Plugin\Reports;
/**
* This class is responsible for setting the metadata property 'totals' on each dataTable if the report
@@ -211,7 +212,8 @@ class ReportTotalsCalculator extends DataTableManipulator
private function findFirstLevelReport()
{
- foreach (Report::getAllReports() as $report) {
+ $reports = new Reports();
+ foreach ($reports->getAllReports() as $report) {
$actionToLoadSubtables = $report->getActionToLoadSubTables();
if ($actionToLoadSubtables == $this->apiMethod
&& $this->apiModule == $report->getModule()
diff --git a/core/API/DataTablePostProcessor.php b/core/API/DataTablePostProcessor.php
index 9a67311679..c6424ea793 100644
--- a/core/API/DataTablePostProcessor.php
+++ b/core/API/DataTablePostProcessor.php
@@ -19,6 +19,7 @@ use Piwik\DataTable\Filter\PivotByDimension;
use Piwik\Metrics\Formatter;
use Piwik\Plugin\ProcessedMetric;
use Piwik\Plugin\Report;
+use Piwik\Plugin\Reports;
/**
* Processes DataTables that should be served through Piwik's APIs. This processing handles
@@ -71,7 +72,7 @@ class DataTablePostProcessor
$this->apiMethod = $apiMethod;
$this->setRequest($request);
- $this->report = Report::factory($apiModule, $apiMethod);
+ $this->report = Reports::factory($apiModule, $apiMethod);
$this->apiInconsistencies = new Inconsistencies();
$this->setFormatter(new Formatter());
}
diff --git a/core/Category/Category.php b/core/Category/Category.php
new file mode 100644
index 0000000000..9694054d11
--- /dev/null
+++ b/core/Category/Category.php
@@ -0,0 +1,118 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+namespace Piwik\Category;
+
+/**
+ * Base type for category. Let's you change the name for a categoryId and specifiy a different order
+ * so the category appears eg at a different order in the reporting menu.
+ *
+ * This class is for now not exposed as public API until needed. Categories of plugins will be automatically
+ * displayed in the menu at the very right after all core categories.
+ */
+class Category
+{
+ /**
+ * The id of the category as specified eg in {@link Piwik\Widget\WidgetConfig::setCategoryId()`} or
+ * {@link Piwik\Report\getCategoryId()}. The id is used as the name in the menu and will be visible in the
+ * URL.
+ *
+ * @var string Should be a translation key, eg 'General_Vists'
+ */
+ protected $id = '';
+
+ /**
+ * @var Subcategory[]
+ */
+ protected $subcategories = array();
+
+ /**
+ * The order of the category. The lower the value the further left the category will appear in the menu.
+ * @var int
+ */
+ protected $order = 99;
+
+ /**
+ * The icon for this category, eg 'icon-user'
+ * @var int
+ */
+ protected $icon = '';
+
+ /**
+ * @param int $order
+ * @return static
+ */
+ public function setOrder($order)
+ {
+ $this->order = (int) $order;
+ return $this;
+ }
+
+ public function getOrder()
+ {
+ return $this->order;
+ }
+
+ public function setId($id)
+ {
+ $this->id = $id;
+ return $this;
+ }
+
+ public function getId()
+ {
+ return $this->id;
+ }
+
+ public function addSubcategory(Subcategory $subcategory)
+ {
+ $subcategoryId = $subcategory->getId();
+
+ if ($this->hasSubcategory($subcategoryId)) {
+ throw new \Exception(sprintf('Subcategory %s already exists', $subcategoryId));
+ }
+
+ $this->subcategories[$subcategoryId] = $subcategory;
+ }
+
+ public function hasSubcategory($subcategoryId)
+ {
+ return isset($this->subcategories[$subcategoryId]);
+ }
+
+ public function getSubcategory($subcategoryId)
+ {
+ if ($this->hasSubcategory($subcategoryId)) {
+ return $this->subcategories[$subcategoryId];
+ }
+ }
+
+ /**
+ * @return Subcategory[]
+ */
+ public function getSubcategories()
+ {
+ return array_values($this->subcategories);
+ }
+
+ public function hasSubCategories()
+ {
+ return !empty($this->subcategories);
+ }
+
+ public function setIcon($icon)
+ {
+ $this->icon = $icon;
+ return $this;
+ }
+
+ public function getIcon()
+ {
+ return $this->icon;
+ }
+
+} \ No newline at end of file
diff --git a/core/Category/CategoryList.php b/core/Category/CategoryList.php
new file mode 100644
index 0000000000..298d9039ce
--- /dev/null
+++ b/core/Category/CategoryList.php
@@ -0,0 +1,95 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+namespace Piwik\Category;
+
+use Piwik\Container\StaticContainer;
+use Piwik\Plugin;
+
+/**
+ * Base type for category. Let's you change the name for a categoryId and specifiy a different order
+ * so the category appears eg at a different order in the reporting menu.
+ *
+ * This class is for now not exposed as public API until needed. Categories of plugins will be automatically
+ * displayed in the menu at the very right after all core categories.
+ */
+class CategoryList
+{
+ /**
+ * @var Category[] indexed by categoryId
+ */
+ private $categories = array();
+
+ public function addCategory(Category $category)
+ {
+ $categoryId = $category->getId();
+
+ if ($this->hasCategory($categoryId)) {
+ throw new \Exception(sprintf('Category %s already exists', $categoryId));
+ }
+
+ $this->categories[$categoryId] = $category;
+ }
+
+ public function getCategories()
+ {
+ return $this->categories;
+ }
+
+ public function hasCategory($categoryId)
+ {
+ return isset($this->categories[$categoryId]);
+ }
+
+ /**
+ * Get the category having the given id, if possible.
+ *
+ * @param string $categoryId
+ * @return Category|null
+ */
+ public function getCategory($categoryId)
+ {
+ if ($this->hasCategory($categoryId)) {
+ return $this->categories[$categoryId];
+ }
+ }
+
+ /**
+ * @return CategoryList
+ */
+ public static function get()
+ {
+ $list = new CategoryList();
+
+ $categories = StaticContainer::get('Piwik\Plugin\Categories');
+
+ foreach ($categories->getAllCategories() as $category) {
+ $list->addCategory($category);
+ }
+
+ // move subcategories into categories
+ foreach ($categories->getAllSubcategories() as $subcategory) {
+ $categoryId = $subcategory->getCategoryId();
+
+ if (!$categoryId) {
+ continue;
+ }
+
+ if ($list->hasCategory($categoryId)) {
+ $category = $list->getCategory($categoryId);
+ } else {
+ $category = new Category();
+ $category->setId($categoryId);
+ $list->addCategory($category);
+ }
+
+ $category->addSubcategory($subcategory);
+ }
+
+ return $list;
+ }
+} \ No newline at end of file
diff --git a/core/Category/Subcategory.php b/core/Category/Subcategory.php
new file mode 100644
index 0000000000..7b6854f95c
--- /dev/null
+++ b/core/Category/Subcategory.php
@@ -0,0 +1,146 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+namespace Piwik\Category;
+
+/**
+ * Base type for subcategories.
+ *
+ * All widgets within a subcategory will be rendered in the Piwik reporting UI under the same page. By default
+ * you do not have to specify any subcategory as they are created automatically. Only create a subcategory if you
+ * want to change the name for a specific subcategoryId or if you want to specifiy a different order so the subcategory
+ * appears eg at a different order in the reporting menu. It also affects the order of reports in
+ * `API.getReportMetadata` and wherever we display any reports.
+ *
+ * To define a subcategory just place a subclass within the `Categories` folder of your plugin.
+ *
+ * Subcategories can also be added through the {@hook Subcategory.addSubcategories} event.
+ *
+ * @api since Piwik 3.0.0
+ */
+class Subcategory
+{
+ /**
+ * The id of the subcategory, see eg {@link Piwik\Widget\WidgetConfig::setSubcategoryId()`} or
+ * {@link Piwik\Report\getSubcategoryId()}. The id will be used in the Piwik reporting URL and as the name
+ * in the Piwik reporting submenu. If you want to define a different URL and name, specify a {@link $name}.
+ * For example you might want to have the actual GoalId (eg '4') in the URL but the actual goal name in the
+ * submenu (eg 'Downloads'). In this case one should specify `$id=4;$name='Downloads'`.
+ *
+ * @var string eg 'General_Overview' or 'VisitTime_ByServerTimeWidgetName'.
+ */
+ protected $id = '';
+
+ /**
+ * The id of the category the subcategory belongs to, must be specified.
+ * See {@link Piwik\Widget\WidgetConfig::setCategoryId()`} or {@link Piwik\Report\getCategoryId()}.
+ *
+ * @var string A translation key eg 'General_Visits' or 'Goals_Goals'
+ */
+ protected $categoryId = '';
+
+ /**
+ * The name that shall be used in the menu etc, defaults to the specified {@link $id}. See {@link $id}.
+ * @var string
+ */
+ protected $name = '';
+
+ /**
+ * The order of the subcategory. The lower the value the earlier a widget or a report will be displayed.
+ * @var int
+ */
+ protected $order = 99;
+
+ /**
+ * Sets (overwrites) the id of the subcategory see {@link $id}.
+ *
+ * @param string $id A translation key eg 'General_Overview'.
+ * @return static
+ */
+ public function setId($id)
+ {
+ $this->id = $id;
+ return $this;
+ }
+
+ /**
+ * Get the id of the subcategory.
+ * @return string
+ */
+ public function getId()
+ {
+ return $this->id;
+ }
+
+ /**
+ * Get the specifed categoryId see {@link $categoryId}.
+ *
+ * @return string
+ */
+ public function getCategoryId()
+ {
+ return $this->categoryId;
+ }
+
+ /**
+ * Sets (overwrites) the categoryId see {@link $categoryId}.
+ *
+ * @param string $categoryId
+ * @return static
+ */
+ public function setCategoryId($categoryId)
+ {
+ $this->categoryId = $categoryId;
+ return $this;
+ }
+
+ /**
+ * Sets (overwrites) the name see {@link $name} and {@link $id}.
+ *
+ * @param string $name A translation key eg 'General_Overview'.
+ * @return static
+ */
+ public function setName($name)
+ {
+ $this->name = $name;
+ return $this;
+ }
+
+ /**
+ * Get the name of the subcategory.
+ * @return string
+ */
+ public function getName()
+ {
+ if (!empty($this->name)) {
+ return $this->name;
+ }
+
+ return $this->id;
+ }
+
+ /**
+ * Sets (overwrites) the order see {@link $order}.
+ *
+ * @param int $order
+ * @return static
+ */
+ public function setOrder($order)
+ {
+ $this->order = (int) $order;
+ return $this;
+ }
+
+ /**
+ * Get the order of the subcategory.
+ * @return int
+ */
+ public function getOrder()
+ {
+ return $this->order;
+ }
+} \ No newline at end of file
diff --git a/core/Common.php b/core/Common.php
index 7992275a56..03e05214c7 100644
--- a/core/Common.php
+++ b/core/Common.php
@@ -273,12 +273,6 @@ class Common
return $value;
} elseif (is_string($value)) {
$value = self::sanitizeString($value);
-
- if (!$alreadyStripslashed) {
- // a JSON array was already stripslashed, don't do it again for each value
-
- $value = self::undoMagicQuotes($value);
- }
} elseif (is_array($value)) {
foreach (array_keys($value) as $key) {
$newKey = $key;
@@ -379,27 +373,6 @@ class Common
}
/**
- * Undo the damage caused by magic_quotes; deprecated in php 5.3 but not removed until php 5.4
- *
- * @param string
- * @return string modified or not
- */
- private static function undoMagicQuotes($value)
- {
- static $shouldUndo;
-
- if (!isset($shouldUndo)) {
- $shouldUndo = version_compare(PHP_VERSION, '5.4', '<') && get_magic_quotes_gpc();
- }
-
- if ($shouldUndo) {
- $value = stripslashes($value);
- }
-
- return $value;
- }
-
- /**
* @param string $value
* @return string Line breaks and line carriage removed
*/
@@ -475,7 +448,7 @@ class Common
// we deal w/ json differently
if ($varType == 'json') {
- $value = self::undoMagicQuotes($requestArrayToUse[$varName]);
+ $value = $requestArrayToUse[$varName];
$value = json_decode($value, $assoc = true);
return self::sanitizeInputValues($value, $alreadyStripslashed = true);
}
diff --git a/core/DataTable.php b/core/DataTable.php
index 0b68a96f50..1cfe92491d 100644
--- a/core/DataTable.php
+++ b/core/DataTable.php
@@ -878,6 +878,14 @@ class DataTable implements DataTableInterface, \IteratorAggregate, \ArrayAccess
}
/**
+ * @ignore
+ */
+ public function getRowsCountWithoutSummaryRow()
+ {
+ return count($this->rows);
+ }
+
+ /**
* Returns an array containing all column values for the requested column.
*
* @param string $name The column name.
diff --git a/core/DataTable/Filter/ColumnDelete.php b/core/DataTable/Filter/ColumnDelete.php
index a0fba5a963..60e53fd7dd 100644
--- a/core/DataTable/Filter/ColumnDelete.php
+++ b/core/DataTable/Filter/ColumnDelete.php
@@ -103,6 +103,10 @@ class ColumnDelete extends BaseFilter
if (!empty($this->columnsToRemove)) {
foreach ($table as $index => $row) {
foreach ($this->columnsToRemove as $column) {
+ if (!array_key_exists($column, $row)) {
+ continue;
+ }
+
if ($this->deleteIfZeroOnly) {
$value = $row[$column];
if ($value === false || !empty($value)) {
@@ -115,11 +119,13 @@ class ColumnDelete extends BaseFilter
}
$recurse = true;
+
}
// remove columns not specified in $columnsToKeep
if (!empty($this->columnsToKeep)) {
foreach ($table as $index => $row) {
+ $columnsToDelete = array();
foreach ($row as $name => $value) {
$keep = false;
// @see self::APPEND_TO_COLUMN_NAME_TO_KEEP
@@ -133,9 +139,14 @@ class ColumnDelete extends BaseFilter
&& $name != 'label' // label cannot be removed via whitelisting
&& !isset($this->columnsToKeep[$name])
) {
- unset($table[$index][$name]);
+ // we cannot remove row directly to prevent notice "ArrayIterator::next(): Array was modified
+ // outside object and internal position is no longer valid in /var/www..."
+ $columnsToDelete[] = $name;
}
}
+ foreach ($columnsToDelete as $columnToDelete) {
+ unset($table[$index][$columnToDelete]);
+ }
}
$recurse = true;
diff --git a/core/DataTable/Filter/PivotByDimension.php b/core/DataTable/Filter/PivotByDimension.php
index b7f5ca1cf2..bbc72f46d9 100644
--- a/core/DataTable/Filter/PivotByDimension.php
+++ b/core/DataTable/Filter/PivotByDimension.php
@@ -21,6 +21,7 @@ use Piwik\Period;
use Piwik\Piwik;
use Piwik\Plugin\Report;
use Piwik\Plugin\Segment;
+use Piwik\Plugin\Reports;
use Piwik\Site;
/**
@@ -328,7 +329,7 @@ class PivotByDimension extends BaseFilter
{
list($module, $method) = explode('.', $report);
- $this->thisReport = Report::factory($module, $method);
+ $this->thisReport = Reports::factory($module, $method);
if (empty($this->thisReport)) {
throw new Exception("Unable to find report '$report'.");
}
diff --git a/core/DataTable/Filter/Sort.php b/core/DataTable/Filter/Sort.php
index 8f2df8c9f6..f3174e88de 100644
--- a/core/DataTable/Filter/Sort.php
+++ b/core/DataTable/Filter/Sort.php
@@ -13,6 +13,7 @@ use Piwik\DataTable\Row;
use Piwik\DataTable\Simple;
use Piwik\DataTable;
use Piwik\Metrics;
+use Piwik\Metrics\Sorter;
/**
* Sorts a {@link DataTable} based on the value of a specific column.
@@ -25,7 +26,8 @@ class Sort extends BaseFilter
{
protected $columnToSort;
protected $order;
- protected $sign;
+ protected $naturalSort;
+ protected $isSecondaryColumnSortEnabled;
const ORDER_DESC = 'desc';
const ORDER_ASC = 'asc';
@@ -38,8 +40,10 @@ class Sort extends BaseFilter
* @param string $order order `'asc'` or `'desc'`.
* @param bool $naturalSort Whether to use a natural sort or not (see {@link http://php.net/natsort}).
* @param bool $recursiveSort Whether to sort all subtables or not.
+ * @param bool $doSortBySecondaryColumn If true will sort by a secondary column. The column is automatically
+ * detected and will be either nb_visits or label, if possible.
*/
- public function __construct($table, $columnToSort, $order = 'desc', $naturalSort = true, $recursiveSort = true)
+ public function __construct($table, $columnToSort, $order = 'desc', $naturalSort = true, $recursiveSort = true, $doSortBySecondaryColumn = false)
{
parent::__construct($table);
@@ -48,144 +52,9 @@ class Sort extends BaseFilter
}
$this->columnToSort = $columnToSort;
- $this->naturalSort = $naturalSort;
- $this->setOrder($order);
- }
-
- /**
- * Updates the order
- *
- * @param string $order asc|desc
- */
- public function setOrder($order)
- {
- if ($order == 'asc') {
- $this->order = 'asc';
- $this->sign = 1;
- } else {
- $this->order = 'desc';
- $this->sign = -1;
- }
- }
-
- /**
- * Sorting method used for sorting numbers
- *
- * @param array $rowA array[0 => value of column to sort, 1 => label]
- * @param array $rowB array[0 => value of column to sort, 1 => label]
- * @return int
- */
- public function numberSort($rowA, $rowB)
- {
- if (isset($rowA[0]) && isset($rowB[0])) {
- if ($rowA[0] != $rowB[0] || !isset($rowA[1])) {
- return $this->sign * ($rowA[0] < $rowB[0] ? -1 : 1);
- } else {
- return -1 * $this->sign * strnatcasecmp($rowA[1], $rowB[1]);
- }
- } elseif (!isset($rowB[0]) && !isset($rowA[0])) {
- return -1 * $this->sign * strnatcasecmp($rowA[1], $rowB[1]);
- } elseif (!isset($rowA[0])) {
- return 1;
- }
-
- return -1;
- }
-
- /**
- * Sorting method used for sorting values natural
- *
- * @param mixed $valA
- * @param mixed $valB
- * @return int
- */
- public function naturalSort($valA, $valB)
- {
- return !isset($valA)
- && !isset($valB)
- ? 0
- : (!isset($valA)
- ? 1
- : (!isset($valB)
- ? -1
- : $this->sign * strnatcasecmp(
- $valA,
- $valB
- )
- )
- );
- }
-
- /**
- * Sorting method used for sorting values
- *
- * @param mixed $valA
- * @param mixed $valB
- * @return int
- */
- public function sortString($valA, $valB)
- {
- return !isset($valA)
- && !isset($valB)
- ? 0
- : (!isset($valA)
- ? 1
- : (!isset($valB)
- ? -1
- : $this->sign *
- strcasecmp($valA,
- $valB
- )
- )
- );
- }
-
- protected function getColumnValue(Row $row)
- {
- $value = $row->getColumn($this->columnToSort);
-
- if ($value === false || is_array($value)) {
- return null;
- }
-
- return $value;
- }
-
- /**
- * Sets the column to be used for sorting
- *
- * @param Row $row
- * @return int
- */
- protected function selectColumnToSort($row)
- {
- $value = $row->hasColumn($this->columnToSort);
- if ($value) {
- return $this->columnToSort;
- }
-
- $columnIdToName = Metrics::getMappingFromNameToId();
- // sorting by "nb_visits" but the index is Metrics::INDEX_NB_VISITS in the table
- if (isset($columnIdToName[$this->columnToSort])) {
- $column = $columnIdToName[$this->columnToSort];
- $value = $row->hasColumn($column);
-
- if ($value) {
- return $column;
- }
- }
-
- // eg. was previously sorted by revenue_per_visit, but this table
- // doesn't have this column; defaults with nb_visits
- $column = Metrics::INDEX_NB_VISITS;
- $value = $row->hasColumn($column);
- if ($value) {
- return $column;
- }
-
- // even though this column is not set properly in the table,
- // we select it for the sort, so that the table's internal state is set properly
- return $this->columnToSort;
+ $this->naturalSort = $naturalSort;
+ $this->order = strtolower($order);
+ $this->isSecondaryColumnSortEnabled = $doSortBySecondaryColumn;
}
/**
@@ -204,87 +73,48 @@ class Sort extends BaseFilter
return;
}
- if (!$table->getRowsCount()) {
+ if (!$table->getRowsCountWithoutSummaryRow()) {
return;
}
$row = $table->getFirstRow();
+
if ($row === false) {
return;
}
- $this->columnToSort = $this->selectColumnToSort($row);
+ $config = new Sorter\Config();
+ $sorter = new Sorter($config);
- $value = $this->getFirstValueFromDataTable($table);
+ $config->naturalSort = $this->naturalSort;
+ $config->primaryColumnToSort = $sorter->getPrimaryColumnToSort($table, $this->columnToSort);
+ $config->primarySortOrder = $sorter->getPrimarySortOrder($this->order);
+ $config->primarySortFlags = $sorter->getBestSortFlags($table, $config->primaryColumnToSort);
+ $config->secondaryColumnToSort = $sorter->getSecondaryColumnToSort($row, $config->primaryColumnToSort);
+ $config->secondarySortOrder = $sorter->getSecondarySortOrder($this->order, $config->secondaryColumnToSort);
+ $config->secondarySortFlags = $sorter->getBestSortFlags($table, $config->secondaryColumnToSort);
- if (is_numeric($value) && $this->columnToSort !== 'label') {
- $methodToUse = "numberSort";
- } else {
- if ($this->naturalSort) {
- $methodToUse = "naturalSort";
- } else {
- $methodToUse = "sortString";
- }
- }
+ // secondary sort should not be needed for all other sort flags (eg string/natural sort) as label is unique and would make it slower
+ $isSecondaryColumnSortNeeded = $config->primarySortFlags === SORT_NUMERIC;
+ $config->isSecondaryColumnSortEnabled = $this->isSecondaryColumnSortEnabled && $isSecondaryColumnSortNeeded;
- $this->sort($table, $methodToUse);
+ $this->sort($sorter, $table);
}
- private function getFirstValueFromDataTable($table)
+ private function sort(Sorter $sorter, DataTable $table)
{
- foreach ($table->getRowsWithoutSummaryRow() as $row) {
- $value = $this->getColumnValue($row);
- if (!is_null($value)) {
- return $value;
- }
- }
- }
-
- /**
- * Sorts the DataTable rows using the supplied callback function.
- *
- * @param string $functionCallback A comparison callback compatible with {@link usort}.
- * @param string $columnSortedBy The column name `$functionCallback` sorts by. This is stored
- * so we can determine how the DataTable was sorted in the future.
- */
- private function sort(DataTable $table, $functionCallback)
- {
- $table->setTableSortedBy($this->columnToSort);
-
- $rows = $table->getRowsWithoutSummaryRow();
-
- // get column value and label only once for performance tweak
- $values = array();
- if ($functionCallback === 'numberSort') {
- foreach ($rows as $key => $row) {
- $values[$key] = array($this->getColumnValue($row), $row->getColumn('label'));
- }
- } else {
- foreach ($rows as $key => $row) {
- $values[$key] = $this->getColumnValue($row);
- }
- }
-
- uasort($values, array($this, $functionCallback));
-
- $sortedRows = array();
- foreach ($values as $key => $value) {
- $sortedRows[] = $rows[$key];
- }
-
- $table->setRows($sortedRows);
-
- unset($rows);
- unset($sortedRows);
+ $sorter->sort($table);
if ($table->isSortRecursiveEnabled()) {
foreach ($table->getRowsWithoutSummaryRow() as $row) {
$subTable = $row->getSubtable();
+
if ($subTable) {
$subTable->enableRecursiveSort();
- $this->sort($subTable, $functionCallback);
+ $this->sort($sorter, $subTable);
}
}
}
}
-}
+
+} \ No newline at end of file
diff --git a/core/DataTable/Row.php b/core/DataTable/Row.php
index ad8a850ca0..3bd3b023d8 100644
--- a/core/DataTable/Row.php
+++ b/core/DataTable/Row.php
@@ -21,7 +21,7 @@ use Piwik\Metrics;
*
* @api
*/
-class Row implements \ArrayAccess, \IteratorAggregate
+class Row extends \ArrayObject
{
/**
* List of columns that cannot be summed. An associative array for speed.
@@ -36,7 +36,6 @@ class Row implements \ArrayAccess, \IteratorAggregate
// @see sumRow - implementation detail
public $maxVisitsSummed = 0;
- private $columns = array();
private $metadata = array();
private $isSubtableLoaded = false;
@@ -67,7 +66,7 @@ class Row implements \ArrayAccess, \IteratorAggregate
public function __construct($row = array())
{
if (isset($row[self::COLUMNS])) {
- $this->columns = $row[self::COLUMNS];
+ $this->exchangeArray($row[self::COLUMNS]);
}
if (isset($row[self::METADATA])) {
$this->metadata = $row[self::METADATA];
@@ -89,7 +88,7 @@ class Row implements \ArrayAccess, \IteratorAggregate
public function export()
{
return array(
- self::COLUMNS => $this->columns,
+ self::COLUMNS => $this->getArrayCopy(),
self::METADATA => $this->metadata,
self::DATATABLE_ASSOCIATED => $this->subtableId,
);
@@ -148,11 +147,11 @@ class Row implements \ArrayAccess, \IteratorAggregate
*/
public function deleteColumn($name)
{
- if (!array_key_exists($name, $this->columns)) {
+ if (!$this->offsetExists($name)) {
return false;
}
- unset($this->columns[$name]);
+ unset($this[$name]);
return true;
}
@@ -164,12 +163,14 @@ class Row implements \ArrayAccess, \IteratorAggregate
*/
public function renameColumn($oldName, $newName)
{
- if (isset($this->columns[$oldName])) {
- $this->columns[$newName] = $this->columns[$oldName];
+ if (isset($this[$oldName])) {
+ $this[$newName] = $this[$oldName];
}
// outside the if () since we want to delete nulled columns
- unset($this->columns[$oldName]);
+ if ($this->offsetExists($oldName)) {
+ unset($this[$oldName]);
+ }
}
/**
@@ -180,11 +181,11 @@ class Row implements \ArrayAccess, \IteratorAggregate
*/
public function getColumn($name)
{
- if (!isset($this->columns[$name])) {
+ if (!isset($this[$name])) {
return false;
}
- return $this->columns[$name];
+ return $this[$name];
}
/**
@@ -213,7 +214,7 @@ class Row implements \ArrayAccess, \IteratorAggregate
*/
public function hasColumn($name)
{
- return array_key_exists($name, $this->columns);
+ return $this->offsetExists($name);
}
/**
@@ -229,7 +230,7 @@ class Row implements \ArrayAccess, \IteratorAggregate
*/
public function getColumns()
{
- return $this->columns;
+ return $this->getArrayCopy();
}
/**
@@ -336,7 +337,7 @@ class Row implements \ArrayAccess, \IteratorAggregate
*/
public function setColumns($columns)
{
- $this->columns = $columns;
+ $this->exchangeArray($columns);
}
/**
@@ -347,7 +348,7 @@ class Row implements \ArrayAccess, \IteratorAggregate
*/
public function setColumn($name, $value)
{
- $this->columns[$name] = $value;
+ $this[$name] = $value;
}
/**
@@ -389,7 +390,7 @@ class Row implements \ArrayAccess, \IteratorAggregate
*/
public function addColumn($name, $value)
{
- if (isset($this->columns[$name])) {
+ if (isset($this[$name])) {
throw new Exception("Column $name already in the array!");
}
$this->setColumn($name, $value);
@@ -452,7 +453,7 @@ class Row implements \ArrayAccess, \IteratorAggregate
*/
public function sumRow(Row $rowToSum, $enableCopyMetadata = true, $aggregationOperations = false)
{
- foreach ($rowToSum->getColumns() as $columnToSumName => $columnToSumValue) {
+ foreach ($rowToSum as $columnToSumName => $columnToSumValue) {
if (!$this->isSummableColumn($columnToSumName)) {
continue;
}
@@ -702,31 +703,6 @@ class Row implements \ArrayAccess, \IteratorAggregate
return true;
}
- public function offsetExists($offset)
- {
- return $this->hasColumn($offset);
- }
-
- public function offsetGet($offset)
- {
- return $this->getColumn($offset);
- }
-
- public function offsetSet($offset, $value)
- {
- $this->setColumn($offset, $value);
- }
-
- public function offsetUnset($offset)
- {
- $this->deleteColumn($offset);
- }
-
- public function getIterator()
- {
- return new \ArrayIterator($this->columns);
- }
-
private function warnIfSubtableAlreadyExists()
{
if (!is_null($this->subtableId)) {
diff --git a/core/Http/ControllerResolver.php b/core/Http/ControllerResolver.php
index 569fbee49e..e0fe7d98e3 100644
--- a/core/Http/ControllerResolver.php
+++ b/core/Http/ControllerResolver.php
@@ -10,8 +10,10 @@ namespace Piwik\Http;
use DI\FactoryInterface;
use Exception;
+use Piwik\Plugin;
use Piwik\Plugin\Controller;
-use Piwik\Plugin\Report;
+use Piwik\Plugin\Reports;
+use Piwik\Session;
use Piwik\Plugin\Widgets;
/**
@@ -26,9 +28,15 @@ class ControllerResolver
*/
private $abstractFactory;
- public function __construct(FactoryInterface $abstractFactory)
+ /**
+ * @var Widgets
+ */
+ private $widgets;
+
+ public function __construct(FactoryInterface $abstractFactory, Widgets $widgets)
{
$this->abstractFactory = $abstractFactory;
+ $this->widgets = $widgets;
}
/**
@@ -55,11 +63,6 @@ class ControllerResolver
return $controller;
}
- $controller = $this->createReportMenuController($module, $action, $parameters);
- if ($controller) {
- return $controller;
- }
-
throw new Exception(sprintf("Action '%s' not found in the module '%s'", $action, $module));
}
@@ -75,7 +78,7 @@ class ControllerResolver
$action = $action ?: $controller->getDefaultAction();
- if (!is_callable(array($controller, $action))) {
+ if (!is_callable(array($controller, $action)) || !in_array($action, get_class_methods($controller))) {
return null;
}
@@ -84,21 +87,20 @@ class ControllerResolver
private function createWidgetController($module, $action, array &$parameters)
{
- $widget = Widgets::factory($module, $action);
+ $widget = $this->widgets->factory($module, $action);
if (!$widget) {
- return null;
+ return;
}
$parameters['widget'] = $widget;
- $parameters['method'] = $action;
return array($this->createCoreHomeController(), 'renderWidget');
}
private function createReportController($module, $action, array &$parameters)
{
- $report = Report::factory($module, $action);
+ $report = Reports::factory($module, $action);
if (!$report) {
return null;
@@ -109,31 +111,6 @@ class ControllerResolver
return array($this->createCoreHomeController(), 'renderReportWidget');
}
- private function createReportMenuController($module, $action, array &$parameters)
- {
- if (!$this->isReportMenuAction($action)) {
- return null;
- }
-
- $action = lcfirst(substr($action, 4)); // menuGetPageUrls => getPageUrls
- $report = Report::factory($module, $action);
-
- if (!$report) {
- return null;
- }
-
- $parameters['report'] = $report;
-
- return array($this->createCoreHomeController(), 'renderReportMenu');
- }
-
- private function isReportMenuAction($action)
- {
- $startsWithMenu = (Report::PREFIX_ACTION_IN_MENU === substr($action, 0, strlen(Report::PREFIX_ACTION_IN_MENU)));
-
- return !empty($action) && $startsWithMenu;
- }
-
private function createCoreHomeController()
{
return $this->abstractFactory->make('Piwik\Plugins\CoreHome\Controller');
diff --git a/core/Menu/MenuMain.php b/core/Menu/MenuMain.php
deleted file mode 100644
index adb6b538e9..0000000000
--- a/core/Menu/MenuMain.php
+++ /dev/null
@@ -1,19 +0,0 @@
-<?php
-/**
- * Piwik - free/libre analytics platform
- *
- * @link http://piwik.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- *
- */
-namespace Piwik\Menu;
-
-/**
- * @deprecated since 2.4.0
- * @see MenuReporting
- * @method static MenuMain getInstance()
- * @ignore
- */
-class MenuMain extends MenuReporting
-{
-}
diff --git a/core/Menu/MenuReporting.php b/core/Menu/MenuReporting.php
deleted file mode 100644
index 598a757633..0000000000
--- a/core/Menu/MenuReporting.php
+++ /dev/null
@@ -1,143 +0,0 @@
-<?php
-/**
- * Piwik - free/libre analytics platform
- *
- * @link http://piwik.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- *
- */
-namespace Piwik\Menu;
-
-use Piwik\Piwik;
-use Piwik\Plugin\Report;
-
-/**
- * Contains menu entries for the Reporting menu (the menu displayed under the Piwik logo).
- * Plugins can implement the `configureReportingMenu()` method of the `Menu` plugin class to add, rename of remove
- * items. If your plugin does not have a `Menu` class yet you can create one using `./console generate:menu`.
- *
- * **Example**
- *
- * public function configureReportingMenu(MenuReporting $menu)
- * {
- * $menu->add(
- * 'MyPlugin_MyTranslatedMenuCategory',
- * 'MyPlugin_MyTranslatedMenuName',
- * array('module' => 'MyPlugin', 'action' => 'index'),
- * Piwik::isUserHasSomeAdminAccess(),
- * $order = 2
- * );
- * }
- *
- * @api
- * @method static \Piwik\Menu\MenuReporting getInstance()
- */
-class MenuReporting extends MenuAbstract
-{
-
- /**
- * See {@link add()}. Adds a new menu item to the visitors section of the reporting menu.
- * @param string $menuName
- * @param array $url
- * @param int $order
- * @param bool|string $tooltip
- * @api
- * @since 2.5.0
- */
- public function addVisitorsItem($menuName, $url, $order = 50, $tooltip = false)
- {
- $this->addItem('General_Visitors', $menuName, $url, $order, $tooltip);
- }
-
- /**
- * See {@link add()}. Adds a new menu item to the actions section of the reporting menu.
- * @param string $menuName
- * @param array $url
- * @param int $order
- * @param bool|string $tooltip
- * @api
- * @since 2.5.0
- */
- public function addActionsItem($menuName, $url, $order = 50, $tooltip = false)
- {
- $this->addItem('General_Actions', $menuName, $url, $order, $tooltip);
- }
-
- /**
- * Should not be a public API yet. We probably have to change the API once we have another use case.
- * @ignore
- */
- public function addGroup($menuName, $defaultTitle, Group $group, $order = 50, $tooltip = false)
- {
- $this->menuEntries[] = array(
- $menuName,
- $defaultTitle,
- $group,
- $order,
- $tooltip
- );
- }
-
- /**
- * See {@link add()}. Adds a new menu item to the referrers section of the reporting menu.
- * @param string $menuName
- * @param array $url
- * @param int $order
- * @param bool|string $tooltip
- * @api
- * @since 2.5.0
- */
- public function addReferrersItem($menuName, $url, $order = 50, $tooltip = false)
- {
- $this->addItem('Referrers_Referrers', $menuName, $url, $order, $tooltip);
- }
-
- /**
- * Returns if the URL was found in the menu.
- *
- * @param string $url
- * @return boolean
- */
- public function isUrlFound($url)
- {
- $menu = $this->getMenu();
-
- foreach ($menu as $subMenus) {
- foreach ($subMenus as $subMenuName => $menuUrl) {
- if (strpos($subMenuName, '_') !== 0 && $menuUrl['_url'] == $url) {
- return true;
- }
- }
- }
- return false;
- }
-
- /**
- * Triggers the Menu.Reporting.addItems hook and returns the menu.
- *
- * @return Array
- */
- public function getMenu()
- {
- if (!$this->menu) {
-
- /**
- * @ignore
- * @deprecated
- */
- Piwik::postEvent('Menu.Reporting.addItems', array());
-
- foreach (Report::getAllReports() as $report) {
- if ($report->isEnabled()) {
- $report->configureReportingMenu($this);
- }
- }
-
- foreach ($this->getAllMenus() as $menu) {
- $menu->configureReportingMenu($this);
- }
- }
-
- return parent::getMenu();
- }
-}
diff --git a/core/Metrics/Sorter.php b/core/Metrics/Sorter.php
new file mode 100644
index 0000000000..822b509d78
--- /dev/null
+++ b/core/Metrics/Sorter.php
@@ -0,0 +1,237 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+namespace Piwik\Metrics;
+
+use Piwik\DataTable;
+use Piwik\DataTable\Row;
+use Piwik\Metrics;
+use Piwik\Plugin\Metric;
+use Piwik\Plugin\Report;
+
+class Sorter
+{
+ /**
+ * @var Sorter\Config
+ */
+ private $config;
+
+ public function __construct(Sorter\Config $config)
+ {
+ $this->config = $config;
+ }
+
+ /**
+ * Sorts the DataTable rows using the supplied callback function.
+ *
+ * @param DataTable $table The table to sort.
+ */
+ public function sort(DataTable $table)
+ {
+ // all that code is in here and not in separate methods for best performance. It does make a difference once
+ // php has to copy many (eg 50k) rows otherwise.
+
+ $table->setTableSortedBy($this->config->primaryColumnToSort);
+
+ $rows = $table->getRowsWithoutSummaryRow();
+
+ // we need to sort rows that have a value separately from rows that do not have a value since we always want
+ // to append rows that do not have a value at the end.
+ $rowsWithValues = array();
+ $rowsWithoutValues = array();
+
+ $valuesToSort = array();
+ foreach ($rows as $key => $row) {
+ $value = $this->getColumnValue($row);
+ if (isset($value)) {
+ $valuesToSort[] = $value;
+ $rowsWithValues[] = $row;
+ } else {
+ $rowsWithoutValues[] = $row;
+ }
+ }
+
+ unset($rows);
+
+ if ($this->config->isSecondaryColumnSortEnabled && $this->config->secondaryColumnToSort) {
+ $secondaryValues = array();
+ foreach ($rowsWithValues as $key => $row) {
+ $secondaryValues[$key] = $row->getColumn($this->config->secondaryColumnToSort);
+ }
+
+ array_multisort($valuesToSort, $this->config->primarySortOrder, $this->config->primarySortFlags, $secondaryValues, $this->config->secondarySortOrder, $this->config->secondarySortFlags, $rowsWithValues);
+
+ } else {
+ array_multisort($valuesToSort, $this->config->primarySortOrder, $this->config->primarySortFlags, $rowsWithValues);
+ }
+
+ if (!empty($rowsWithoutValues) && $this->config->secondaryColumnToSort) {
+ $secondaryValues = array();
+ foreach ($rowsWithoutValues as $key => $row) {
+ $secondaryValues[$key] = $row->getColumn($this->config->secondaryColumnToSort);
+ }
+
+ array_multisort($secondaryValues, $this->config->secondarySortOrder, $this->config->secondarySortFlags, $rowsWithoutValues);
+ }
+
+ unset($secondaryValues);
+
+ foreach ($rowsWithoutValues as $row) {
+ $rowsWithValues[] = $row;
+ }
+
+ $table->setRows(array_values($rowsWithValues));
+ }
+
+ private function getColumnValue(Row $row)
+ {
+ $value = $row->getColumn($this->config->primaryColumnToSort);
+
+ if ($value === false || is_array($value)) {
+ return null;
+ }
+
+ return $value;
+ }
+
+ /**
+ * @param string $order 'asc' or 'desc'
+ * @return int
+ */
+ public function getPrimarySortOrder($order)
+ {
+ if ($order === 'asc') {
+ return SORT_ASC;
+ }
+
+ return SORT_DESC;
+ }
+
+ /**
+ * @param string $order 'asc' or 'desc'
+ * @param string|int $secondarySortColumn column name or column id
+ * @return int
+ */
+ public function getSecondarySortOrder($order, $secondarySortColumn)
+ {
+ if ($secondarySortColumn === 'label') {
+
+ $secondaryOrder = SORT_ASC;
+ if ($order === 'asc') {
+ $secondaryOrder = SORT_DESC;
+ }
+
+ return $secondaryOrder;
+ }
+
+ return $this->getPrimarySortOrder($order);
+ }
+
+ /**
+ * Detect the column to be used for sorting
+ *
+ * @param DataTable $table
+ * @param string|int $columnToSort column name or column id
+ * @return int
+ */
+ public function getPrimaryColumnToSort(DataTable $table, $columnToSort)
+ {
+ // we fallback to nb_visits in case columnToSort does not exist
+ $columnsToCheck = array($columnToSort, 'nb_visits');
+
+ $row = $table->getFirstRow();
+
+ foreach ($columnsToCheck as $column) {
+ $column = Metric::getActualMetricColumn($table, $column);
+
+ if ($row->hasColumn($column)) {
+ // since getActualMetricColumn() returns a default value, we need to make sure it actually has that column
+ return $column;
+ }
+ }
+
+ return $columnToSort;
+ }
+
+ /**
+ * Detect the secondary sort column to be used for sorting
+ *
+ * @param Row $row
+ * @param int|string $primaryColumnToSort
+ * @return int
+ */
+ public function getSecondaryColumnToSort(Row $row, $primaryColumnToSort)
+ {
+ $defaultSecondaryColumn = array(Metrics::INDEX_NB_VISITS, 'nb_visits');
+
+ if (in_array($primaryColumnToSort, $defaultSecondaryColumn)) {
+ // if sorted by visits, then sort by label as a secondary column
+ $column = 'label';
+ $value = $row->hasColumn($column);
+ if ($value !== false) {
+ return $column;
+ }
+
+ return null;
+ }
+
+ if ($primaryColumnToSort !== 'label') {
+ // we do not add this by default to make sure we do not sort by label as a first and secondary column
+ $defaultSecondaryColumn[] = 'label';
+ }
+
+ foreach ($defaultSecondaryColumn as $column) {
+ $value = $row->hasColumn($column);
+ if ($value !== false) {
+ return $column;
+ }
+ }
+ }
+
+ /**
+ * @param DataTable $table
+ * @param string|int $columnToSort A column name or column id. Make sure that column actually exists in the row.
+ * You might want to get a valid column via {@link getPrimaryColumnToSort()} or
+ * {@link getSecondaryColumnToSort()}
+ * @return int
+ */
+ public function getBestSortFlags(DataTable $table, $columnToSort)
+ {
+ // when column is label we always to sort by string or natural
+ if (isset($columnToSort) && $columnToSort !== 'label') {
+ foreach ($table->getRowsWithoutSummaryRow() as $row) {
+ $value = $row->getColumn($columnToSort);
+
+ if ($value !== false && $value !== null && !is_array($value)) {
+
+ if (is_numeric($value)) {
+ $sortFlags = SORT_NUMERIC;
+ } else {
+ $sortFlags = $this->getStringSortFlags();
+ }
+
+ return $sortFlags;
+ }
+ }
+ }
+
+ return $this->getStringSortFlags();
+ }
+
+ private function getStringSortFlags()
+ {
+ if ($this->config->naturalSort) {
+ $sortFlags = SORT_NATURAL | SORT_FLAG_CASE;
+ } else {
+ $sortFlags = SORT_STRING | SORT_FLAG_CASE;
+ }
+
+ return $sortFlags;
+ }
+
+
+} \ No newline at end of file
diff --git a/core/Metrics/Sorter/Config.php b/core/Metrics/Sorter/Config.php
new file mode 100644
index 0000000000..a62b4e4c08
--- /dev/null
+++ b/core/Metrics/Sorter/Config.php
@@ -0,0 +1,24 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+namespace Piwik\Metrics\Sorter;
+
+class Config
+{
+ public $naturalSort = false;
+
+ public $primaryColumnToSort;
+ public $primarySortFlags;
+ public $primarySortOrder;
+
+ public $secondaryColumnToSort;
+ public $secondarySortOrder;
+ public $secondarySortFlags;
+
+ public $isSecondaryColumnSortEnabled = true;
+
+} \ No newline at end of file
diff --git a/core/Plugin.php b/core/Plugin.php
index ff938a659f..852e09522e 100644
--- a/core/Plugin.php
+++ b/core/Plugin.php
@@ -490,7 +490,7 @@ class Plugin
require_once $file;
$fileName = str_replace(array($baseDir . '/', '.php'), '', $file);
- $klassName = sprintf('Piwik\\Plugins\\%s\\%s\\%s', $this->pluginName, $directoryWithinPlugin, str_replace('/', '\\', $fileName));
+ $klassName = sprintf('Piwik\\Plugins\\%s\\%s\\%s', $this->pluginName, str_replace('/', '\\', $directoryWithinPlugin), str_replace('/', '\\', $fileName));
if (!class_exists($klassName)) {
continue;
diff --git a/core/Plugin/Categories.php b/core/Plugin/Categories.php
new file mode 100644
index 0000000000..4d0543e014
--- /dev/null
+++ b/core/Plugin/Categories.php
@@ -0,0 +1,71 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+namespace Piwik\Plugin;
+
+use Piwik\Container\StaticContainer;
+use Piwik\Piwik;
+use Piwik\Plugin;
+
+/**
+ * Get categories and subcategories that are defined by plugins.
+ */
+class Categories
+{
+ private $pluginManager;
+
+ public function __construct(Plugin\Manager $pluginManager)
+ {
+ $this->pluginManager = $pluginManager;
+ }
+
+ /** @return \Piwik\Category\Category[] */
+ public function getAllCategories()
+ {
+ $categories = $this->pluginManager->findMultipleComponents('Categories', '\\Piwik\\Category\\Category');
+
+ $instances = array();
+ foreach ($categories as $category) {
+ $cat = StaticContainer::getContainer()->make($category);
+ $instances[$cat->getId()] = $cat;
+ }
+
+ return $instances;
+ }
+
+ /** @return \Piwik\Category\Subcategory[] */
+ public function getAllSubcategories()
+ {
+ $subcategories = array();
+
+ /**
+ * Triggered to add custom subcategories.
+ *
+ * **Example**
+ *
+ * public function addSubcategories(&$subcategories)
+ * {
+ * $subcategory = new Subcategory();
+ * $subcategory->setId('General_Overview');
+ * $subcategory->setCategoryId('General_Visits');
+ * $subcategory->setOrder(5);
+ * $subcategories[] = $subcategory;
+ * }
+ *
+ * @param array &$subcategories An array containing a list of subcategories.
+ */
+ Piwik::postEvent('Category.addSubcategories', array(&$subcategories));
+
+ $classes = $this->pluginManager->findMultipleComponents('Categories', '\\Piwik\\Category\\Subcategory');
+
+ foreach ($classes as $subcategory) {
+ $subcategories[] = StaticContainer::getContainer()->make($subcategory);
+ }
+
+ return $subcategories;
+ }
+} \ No newline at end of file
diff --git a/core/Plugin/Controller.php b/core/Plugin/Controller.php
index e6a21fd6f4..636303e929 100644
--- a/core/Plugin/Controller.php
+++ b/core/Plugin/Controller.php
@@ -33,6 +33,7 @@ use Piwik\Piwik;
use Piwik\Plugins\CoreAdminHome\CustomLogo;
use Piwik\Plugins\CoreVisualizations\Visualizations\JqplotGraph\Evolution;
use Piwik\Plugins\LanguagesManager\LanguagesManager;
+use Piwik\Plugin\Reports;
use Piwik\SettingsPiwik;
use Piwik\Site;
use Piwik\Url;
@@ -313,7 +314,7 @@ abstract class Controller
protected function renderReport($apiAction, $controllerAction = false)
{
if (empty($controllerAction) && is_string($apiAction)) {
- $report = Report::factory($this->pluginName, $apiAction);
+ $report = Reports::factory($this->pluginName, $apiAction);
if (!empty($report)) {
$apiAction = $report;
@@ -898,6 +899,9 @@ abstract class Controller
* This is a protection against CSRF and should be used in all controller
* methods that modify Piwik or any user settings.
*
+ * If called from JavaScript by using the `ajaxHelper` you have to call `ajaxHelper.withTokenInUrl();` before
+ * `ajaxHandler.send();` to send the token along with the request.
+ *
* **The token_auth should never appear in the browser's address bar.**
*
* @throws \Piwik\NoAccessException If the token doesn't match.
@@ -947,67 +951,6 @@ abstract class Controller
return self::getCalendarPrettyDate(Period\Factory::build($period, Date::factory($date)));
}
- /**
- * Calculates the evolution from one value to another and returns HTML displaying
- * the evolution percent. The HTML includes an up/down arrow and is colored red, black or
- * green depending on whether the evolution is negative, 0 or positive.
- *
- * No HTML is returned if the current value and evolution percent are both 0.
- *
- * @param string $date The date of the current value.
- * @param int $currentValue The value to calculate evolution to.
- * @param string $pastDate The date of past value.
- * @param int $pastValue The value in the past to calculate evolution from.
- * @return string|false The HTML or `false` if the evolution is 0 and the current value is 0.
- * @api
- */
- protected function getEvolutionHtml($date, $currentValue, $pastDate, $pastValue)
- {
- $evolutionPercent = CalculateEvolutionFilter::calculate(
- $currentValue, $pastValue, $precision = 1);
-
- // do not display evolution if evolution percent is 0 and current value is 0
- if ($evolutionPercent == 0
- && $currentValue == 0
- ) {
- return false;
- }
-
- $titleEvolutionPercent = $evolutionPercent;
- if ($evolutionPercent < 0) {
- $class = "negative-evolution";
- $img = "arrow_down.png";
- } elseif ($evolutionPercent == 0) {
- $class = "neutral-evolution";
- $img = "stop.png";
- } else {
- $class = "positive-evolution";
- $img = "arrow_up.png";
- $titleEvolutionPercent = '+' . $titleEvolutionPercent;
- }
-
- $currentValue = NumberFormatter::getInstance()->format($currentValue);
- $pastValue = NumberFormatter::getInstance()->format($pastValue);
-
- $title = Piwik::translate('General_EvolutionSummaryGeneric', array(
- Piwik::translate('General_NVisits', $currentValue),
- $date,
- Piwik::translate('General_NVisits', $pastValue),
- $pastDate,
- $titleEvolutionPercent
- ));
-
- $result = '<span class="metricEvolution" title="' . $title
- . '"><img style="padding-right:4px" src="plugins/MultiSites/images/' . $img . '"/><strong';
-
- if (isset($class)) {
- $result .= ' class="' . $class . '"';
- }
- $result .= '>' . $evolutionPercent . '</strong></span>';
-
- return $result;
- }
-
protected function checkSitePermission()
{
if (!empty($this->idSite) && empty($this->site)) {
diff --git a/core/Plugin/ControllerAdmin.php b/core/Plugin/ControllerAdmin.php
index e503a615e6..a0658c4142 100644
--- a/core/Plugin/ControllerAdmin.php
+++ b/core/Plugin/ControllerAdmin.php
@@ -155,31 +155,20 @@ abstract class ControllerAdmin extends Controller
private static function notifyWhenPhpVersionIsEOL()
{
- $deprecatedMajorPhpVersion = null;
- if(self::isPhpVersion53()) {
- $deprecatedMajorPhpVersion = '5.3';
- } elseif(self::isPhpVersion54()) {
- $deprecatedMajorPhpVersion = '5.4';
- }
-
- $notifyPhpIsEOL = Piwik::hasUserSuperUserAccess() && $deprecatedMajorPhpVersion;
+ return; // no supported version (5.5+) has currently ended support
+ $notifyPhpIsEOL = Piwik::hasUserSuperUserAccess() && self::isPhpVersionAtLeast55();
if (!$notifyPhpIsEOL) {
return;
}
- $nextRequiredMinimumPHP = '5.5';
-
- $message = Piwik::translate('General_WarningPiwikWillStopSupportingPHPVersion', array($deprecatedMajorPhpVersion, $nextRequiredMinimumPHP))
- . "\n "
- . Piwik::translate('General_WarningPhpVersionXIsTooOld', $deprecatedMajorPhpVersion);
-
+ $message = Piwik::translate('General_WarningPhpVersionXIsTooOld', '5.5');
$notification = new Notification($message);
$notification->title = Piwik::translate('General_Warning');
$notification->priority = Notification::PRIORITY_LOW;
$notification->context = Notification::CONTEXT_WARNING;
$notification->type = Notification::TYPE_TRANSIENT;
$notification->flags = Notification::FLAG_NO_CLEAR;
- NotificationManager::notify('DeprecatedPHPVersionCheck', $notification);
+ NotificationManager::notify('PHP54VersionCheck', $notification);
}
private static function notifyWhenDebugOnDemandIsEnabled($trackerSetting)
@@ -278,16 +267,11 @@ abstract class ControllerAdmin extends Controller
private static function checkPhpVersion($view)
{
$view->phpVersion = PHP_VERSION;
- $view->phpIsNewEnough = version_compare($view->phpVersion, '5.3.0', '>=');
- }
-
- private static function isPhpVersion53()
- {
- return strpos(PHP_VERSION, '5.3') === 0;
+ $view->phpIsNewEnough = self::isPhpVersionAtLeast55();
}
- private static function isPhpVersion54()
+ private static function isPhpVersionAtLeast55()
{
- return strpos(PHP_VERSION, '5.4') === 0;
+ return version_compare(PHP_VERSION, '5.5', '>=');
}
}
diff --git a/core/Plugin/Menu.php b/core/Plugin/Menu.php
index dd1dcaf7f3..c90e6d851f 100644
--- a/core/Plugin/Menu.php
+++ b/core/Plugin/Menu.php
@@ -11,11 +11,11 @@ namespace Piwik\Plugin;
use Piwik\Common;
use Piwik\Development;
use Piwik\Menu\MenuAdmin;
-use Piwik\Menu\MenuReporting;
use Piwik\Menu\MenuTop;
use Piwik\Menu\MenuUser;
use Piwik\Plugin\Manager as PluginManager;
use Piwik\Plugins\UsersManager\UserPreferences;
+use Piwik\Plugin\Reports;
/**
* Base class of all plugin menu providers. Plugins that define their own menu items can extend this class to easily
@@ -210,14 +210,6 @@ class Menu
}
/**
- * Configures the reporting menu which should only contain links to reports of a specific site such as
- * "Search Engines", "Page Titles" or "Locations & Provider".
- */
- public function configureReportingMenu(MenuReporting $menu)
- {
- }
-
- /**
* Configures the top menu which is supposed to contain analytics related items such as the
* "All Websites Dashboard".
*/
@@ -254,7 +246,7 @@ class Menu
}
$reportAction = lcfirst(substr($action, 4));
- if (Report::factory($module, $reportAction)) {
+ if (Reports::factory($module, $reportAction)) {
return;
}
diff --git a/core/Plugin/Metric.php b/core/Plugin/Metric.php
index 6349ca6999..e1bdb78cad 100644
--- a/core/Plugin/Metric.php
+++ b/core/Plugin/Metric.php
@@ -174,16 +174,19 @@ abstract class Metric
*/
public static function getActualMetricColumn(DataTable $table, $columnName, $mappingNameToId = null)
{
- if (empty($mappingIdToName)) {
- $mappingNameToId = Metrics::getMappingFromNameToId();
- }
-
$firstRow = $table->getFirstRow();
- if (!empty($firstRow)
- && $firstRow->getColumn($columnName) === false
- ) {
- $columnName = $mappingNameToId[$columnName];
+
+ if (!empty($firstRow) && $firstRow->hasColumn($columnName) === false) {
+
+ if (empty($mappingIdToName)) {
+ $mappingNameToId = Metrics::getMappingFromNameToId();
+ }
+
+ if (array_key_exists($columnName, $mappingNameToId)) {
+ $columnName = $mappingNameToId[$columnName];
+ }
}
+
return $columnName;
}
}
diff --git a/core/Plugin/Report.php b/core/Plugin/Report.php
index 5ab8583a5a..c98d38e849 100644
--- a/core/Plugin/Report.php
+++ b/core/Plugin/Report.php
@@ -11,19 +11,20 @@ namespace Piwik\Plugin;
use Piwik\API\Proxy;
use Piwik\API\Request;
use Piwik\Cache;
-use Piwik\CacheId;
use Piwik\Columns\Dimension;
+use Piwik\Common;
use Piwik\DataTable;
use Piwik\DataTable\Filter\Sort;
-use Piwik\Menu\MenuReporting;
use Piwik\Metrics;
use Piwik\Cache as PiwikCache;
use Piwik\Piwik;
-use Piwik\Plugin\Manager as PluginManager;
use Piwik\Plugins\CoreVisualizations\Visualizations\HtmlTable;
-use Piwik\WidgetsList;
+use Piwik\Plugins\CoreVisualizations\Visualizations\JqplotGraph\Evolution;
+use Piwik\Plugin\Reports;
use Piwik\ViewDataTable\Factory as ViewDataTableFactory;
use Exception;
+use Piwik\Widget\WidgetsList;
+use Piwik\Report\ReportWidgetFactory;
/**
* Defines a new report. This class contains all information a report defines except the corresponding API method which
@@ -82,30 +83,14 @@ class Report
* @var string
* @api
*/
- protected $category;
+ protected $categoryId;
/**
- * The translation key of the widget title. If a widget title is set, the platform will automatically configure/add
- * a widget for this report. Alternatively, this behavior can be overwritten in {@link configureWidget()}.
+ * The translation key of the subcategory the report belongs to.
* @var string
* @api
*/
- protected $widgetTitle;
-
- /**
- * Optional widget params that will be appended to the widget URL if a {@link $widgetTitle} is set.
- * @var array
- * @api
- */
- protected $widgetParams = array();
-
- /**
- * The translation key of the menu title. If a menu title is set, the platform will automatically add a menu item
- * to the reporting menu. Alternatively, this behavior can be overwritten in {@link configureReportingMenu()}.
- * @var string
- * @api
- */
- protected $menuTitle;
+ protected $subcategoryId;
/**
* An array of supported metrics. Eg `array('nb_visits', 'nb_actions', ...)`. Defaults to the platform default
@@ -204,33 +189,14 @@ class Report
protected $defaultSortOrderDesc = true;
/**
- * @var array
- * @ignore
- */
- public static $orderOfReports = array(
- 'General_MultiSitesSummary',
- 'VisitsSummary_VisitsSummary',
- 'Goals_Ecommerce',
- 'General_Actions',
- 'Events_Events',
- 'Actions_SubmenuSitesearch',
- 'Referrers_Referrers',
- 'Goals_Goals',
- 'General_Visitors',
- 'DevicesDetection_DevicesDetection',
- 'General_VisitorSettings',
- 'API'
- );
-
- /**
* The constructur initializes the module, action and the default metrics. If you want to overwrite any of those
* values or if you want to do any work during initializing overwrite the method {@link init()}.
* @ignore
*/
final public function __construct()
{
- $classname = get_class($this);
- $parts = explode('\\', $classname);
+ $classname = get_class($this);
+ $parts = explode('\\', $classname);
if (5 === count($parts)) {
$this->module = $parts[2];
@@ -268,9 +234,9 @@ class Report
* containing a message that will be displayed to the user. You can overwrite this message in case you want to
* customize the error message. Eg.
* ```
- if (!$this->isEnabled()) {
- throw new Exception('Setting XYZ is not enabled or the user has not enough permission');
- }
+ * if (!$this->isEnabled()) {
+ * throw new Exception('Setting XYZ is not enabled or the user has not enough permission');
+ * }
* ```
* @throws \Exception
* @api
@@ -325,55 +291,48 @@ class Report
*/
public function render()
{
+ $viewDataTable = Common::getRequestVar('viewDataTable', false, 'string');
+ $fixed = Common::getRequestVar('forceView', 0, 'int');
+
+ $module = $this->getModule();
+ $action = $this->getAction();
+
$apiProxy = Proxy::getInstance();
- if (!$apiProxy->isExistingApiAction($this->module, $this->action)) {
- throw new Exception("Invalid action name '$this->action' for '$this->module' plugin.");
+ if (!$apiProxy->isExistingApiAction($module, $action)) {
+ throw new Exception("Invalid action name '$module' for '$action' plugin.");
}
- $apiAction = $apiProxy->buildApiActionName($this->module, $this->action);
-
- $view = ViewDataTableFactory::build(null, $apiAction, $this->module . '.' . $this->action);
+ $apiAction = $apiProxy->buildApiActionName($module, $action);
- $rendered = $view->render();
+ $view = ViewDataTableFactory::build($viewDataTable, $apiAction, $module . '.' . $action, $fixed);
- return $rendered;
+ return $view->render();
}
/**
- * By default a widget will be configured for this report if a {@link $widgetTitle} is set. If you want to customize
- * the way the widget is added or modify any other behavior you can overwrite this method.
- * @param WidgetsList $widget
- * @api
- */
- public function configureWidget(WidgetsList $widget)
- {
- if ($this->widgetTitle) {
- $params = array();
- if (!empty($this->widgetParams) && is_array($this->widgetParams)) {
- $params = $this->widgetParams;
- }
- $widget->add($this->category, $this->widgetTitle, $this->module, $this->action, $params);
- }
- }
-
- /**
- * By default a menu item will be added to the reporting menu if a {@link $menuTitle} is set. If you want to
- * customize the way the item is added or modify any other behavior you can overwrite this method. For instance
- * in case you need to add additional url properties beside module and action which are added by default.
- * @param \Piwik\Menu\MenuReporting $menu
+ * Let's you add any amount of widgets for this report. If a report defines a {@link $categoryId} and a
+ * {@link $subcategoryId} a widget will be generated automatically.
+ *
+ * Example to add a widget manually by overwriting this method in your report:
+ * $widgetsList->addWidgetConfig($factory->createWidget());
+ *
+ * If you want to have the name and the order of the widget differently to the name and order of the report you can
+ * do the following:
+ * $widgetsList->addWidgetConfig($factory->createWidget()->setName('Custom')->setOrder(5));
+ *
+ * If you want to add a widget to any container defined by your plugin or by another plugin you can do
+ * this:
+ * $widgetsList->addToContainerWidget($containerId = 'Products', $factory->createWidget());
+ *
+ * @param WidgetsList $widgetsList
+ * @param ReportWidgetFactory $factory
* @api
*/
- public function configureReportingMenu(MenuReporting $menu)
+ public function configureWidgets(WidgetsList $widgetsList, ReportWidgetFactory $factory)
{
- if ($this->menuTitle) {
- $action = $this->getMenuControllerAction();
- if ($this->isEnabled()) {
- $menu->addItem($this->category,
- $this->menuTitle,
- array('module' => $this->module, 'action' => $action),
- $this->order);
- }
+ if ($this->categoryId && $this->subcategoryId) {
+ $widgetsList->addWidgetConfig($factory->createWidget());
}
}
@@ -549,11 +508,14 @@ class Report
* {@link configureReportMetadata()}.
* @return array
* @ignore
+ *
+ * TODO we should move this out to API::getReportMetadata
*/
protected function buildReportMetadata()
{
$report = array(
- 'category' => $this->getCategory(),
+ 'category' => $this->getCategoryId(),
+ 'subcategory' => $this->getSubcategoryId(),
'name' => $this->getName(),
'module' => $this->getModule(),
'action' => $this->getAction()
@@ -587,6 +549,20 @@ class Report
$report['constantRowsCount'] = $this->constantRowsCount;
}
+ $relatedReports = $this->getRelatedReports();
+ if (!empty($relatedReports)) {
+ $report['relatedReports'] = array();
+ foreach ($relatedReports as $relatedReport) {
+ if (!empty($relatedReport)) {
+ $report['relatedReports'][] = array(
+ 'name' => $relatedReport->getName(),
+ 'module' => $relatedReport->getModule(),
+ 'action' => $relatedReport->getAction()
+ );
+ }
+ }
+ }
+
$report['order'] = $this->order;
return $report;
@@ -625,18 +601,6 @@ class Report
}
/**
- * Gets the translated widget title if one is defined.
- * @return string
- * @ignore
- */
- public function getWidgetTitle()
- {
- if ($this->widgetTitle) {
- return Piwik::translate($this->widgetTitle);
- }
- }
-
- /**
* Get the name of the report
* @return string
* @ignore
@@ -666,24 +630,29 @@ class Report
return $this->action;
}
+ public function getParameters()
+ {
+ return $this->parameters;
+ }
+
/**
* Get the translated name of the category the report belongs to.
* @return string
* @ignore
*/
- public function getCategory()
+ public function getCategoryId()
{
- return Piwik::translate($this->category);
+ return $this->categoryId;
}
/**
- * Get the translation key of the category the report belongs to.
+ * Get the translated name of the subcategory the report belongs to.
* @return string
* @ignore
*/
- public function getCategoryKey()
+ public function getSubcategoryId()
{
- return $this->category;
+ return $this->subcategoryId;
}
/**
@@ -706,16 +675,6 @@ class Report
}
/**
- * Get the menu title if one is defined.
- * @return string
- * @ignore
- */
- public function getMenuTitle()
- {
- return $this->menuTitle;
- }
-
- /**
* Get the action to load sub tables if one is defined.
* @return string
* @ignore
@@ -740,7 +699,7 @@ class Report
list($subtableReportModule, $subtableReportAction) = $this->getSubtableApiMethod();
- $subtableReport = self::factory($subtableReportModule, $subtableReportAction);
+ $subtableReport = Reports::factory($subtableReportModule, $subtableReportAction);
if (empty($subtableReport)) {
return null;
}
@@ -786,103 +745,6 @@ class Report
return Request::processRequest($module . '.' . $action, $paramOverride);
}
- /**
- * Get an instance of a specific report belonging to the given module and having the given action.
- * @param string $module
- * @param string $action
- * @return null|\Piwik\Plugin\Report
- * @api
- */
- public static function factory($module, $action)
- {
- $listApiToReport = self::getMapOfModuleActionsToReport();
- $api = $module . '.' . ucfirst($action);
-
- if (!array_key_exists($api, $listApiToReport)) {
- return null;
- }
-
- $klassName = $listApiToReport[$api];
-
- return new $klassName;
- }
-
- private static function getMapOfModuleActionsToReport()
- {
- $cacheId = CacheId::pluginAware('ReportFactoryMap');
-
- $cache = Cache::getEagerCache();
- if ($cache->contains($cacheId)) {
- $mapApiToReport = $cache->fetch($cacheId);
- } else {
- $reports = self::getAllReports();
-
- $mapApiToReport = array();
- foreach ($reports as $report) {
- $key = $report->getModule() . '.' . ucfirst($report->getAction());
- $mapApiToReport[$key] = get_class($report);
- }
-
- $cache->save($cacheId, $mapApiToReport);
- }
-
- return $mapApiToReport;
- }
-
- /**
- * Returns a list of all available reports. Even not enabled reports will be returned. They will be already sorted
- * depending on the order and category of the report.
- * @return \Piwik\Plugin\Report[]
- * @api
- */
- public static function getAllReports()
- {
- $reports = self::getAllReportClasses();
- $cacheId = CacheId::languageAware('Reports' . md5(implode('', $reports)));
- $cache = PiwikCache::getTransientCache();
-
-
- if (!$cache->contains($cacheId)) {
- $instances = array();
-
- foreach ($reports as $report) {
- $instances[] = new $report();
- }
-
- usort($instances, array('self', 'sort'));
-
- $cache->save($cacheId, $instances);
- }
-
- return $cache->fetch($cacheId);
- }
-
- /**
- * Returns class names of all Report metadata classes.
- *
- * @return string[]
- * @api
- */
- public static function getAllReportClasses()
- {
- return PluginManager::getInstance()->findMultipleComponents('Reports', '\\Piwik\\Plugin\\Report');
- }
-
- /**
- * API metadata are sorted by category/name,
- * with a little tweak to replicate the standard Piwik category ordering
- *
- * @param Report $a
- * @param Report $b
- * @return int
- */
- private static function sort($a, $b)
- {
- return ($category = strcmp(array_search($a->category, self::$orderOfReports), array_search($b->category, self::$orderOfReports))) == 0
- ? ($a->order < $b->order ? -1 : 1)
- : $category;
- }
-
private function getMetricTranslations($metricsToTranslate)
{
$translations = Metrics::getDefaultMetricTranslations();
@@ -903,11 +765,6 @@ class Report
return $metrics;
}
- private function getMenuControllerAction()
- {
- return self::PREFIX_ACTION_IN_MENU . ucfirst($this->action);
- }
-
private function getSubtableApiMethod()
{
if (strpos($this->actionToLoadSubTables, '.') !== false) {
diff --git a/core/Plugin/Reports.php b/core/Plugin/Reports.php
new file mode 100644
index 0000000000..56d69e5453
--- /dev/null
+++ b/core/Plugin/Reports.php
@@ -0,0 +1,189 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugin;
+
+use Piwik\CacheId;
+use Piwik\Category\CategoryList;
+use Piwik\Plugin;
+use Piwik\Cache as PiwikCache;
+
+/**
+ * Get reports that are defined by plugins.
+ */
+class Reports
+{
+
+ /**
+ * Get an instance of a specific report belonging to the given module and having the given action.
+ * @param string $module
+ * @param string $action
+ * @return null|\Piwik\Plugin\Report
+ * @api
+ */
+ public static function factory($module, $action)
+ {
+ $listApiToReport = self::getMapOfModuleActionsToReport();
+ $api = $module . '.' . ucfirst($action);
+
+ if (!array_key_exists($api, $listApiToReport)) {
+ return null;
+ }
+
+ $klassName = $listApiToReport[$api];
+
+ return new $klassName;
+ }
+
+ private static function getMapOfModuleActionsToReport()
+ {
+ $cacheId = CacheId::pluginAware('ReportFactoryMap');
+
+ $cache = PiwikCache::getEagerCache();
+ if ($cache->contains($cacheId)) {
+ $mapApiToReport = $cache->fetch($cacheId);
+ } else {
+ $reports = new static();
+ $reports = $reports->getAllReports();
+
+ $mapApiToReport = array();
+ foreach ($reports as $report) {
+ $key = $report->getModule() . '.' . ucfirst($report->getAction());
+
+ if (isset($mapApiToReport[$key]) && $report->getParameters()) {
+ // sometimes there are multiple reports with same module/action but different parameters.
+ // we might pick the "wrong" one. At some point we should compare all parameters and if there is
+ // a report which parameters mach $_REQUEST then we should prefer that report
+ continue;
+ }
+ $mapApiToReport[$key] = get_class($report);
+ }
+
+ $cache->save($cacheId, $mapApiToReport);
+ }
+
+ return $mapApiToReport;
+ }
+
+ /**
+ * Returns a list of all available reports. Even not enabled reports will be returned. They will be already sorted
+ * depending on the order and category of the report.
+ * @return \Piwik\Plugin\Report[]
+ * @api
+ */
+ public function getAllReports()
+ {
+ $reports = $this->getAllReportClasses();
+ $cacheId = CacheId::languageAware('Reports' . md5(implode('', $reports)));
+ $cache = PiwikCache::getTransientCache();
+
+ if (!$cache->contains($cacheId)) {
+ $instances = array();
+
+ foreach ($reports as $report) {
+ $instances[] = new $report();
+ }
+
+ usort($instances, array($this, 'sort'));
+
+ $cache->save($cacheId, $instances);
+ }
+
+ return $cache->fetch($cacheId);
+ }
+
+ /**
+ * API metadata are sorted by category/name,
+ * with a little tweak to replicate the standard Piwik category ordering
+ *
+ * @param Report $a
+ * @param Report $b
+ * @return int
+ */
+ private function sort($a, $b)
+ {
+ return $this->compareCategories($a->getCategoryId(), $a->getSubcategoryId(), $a->getOrder(), $b->getCategoryId(), $b->getSubcategoryId(), $b->getOrder());
+ }
+
+ public function compareCategories($catIdA, $subcatIdA, $orderA, $catIdB, $subcatIdB, $orderB)
+ {
+ static $categoryList;
+
+ if (!isset($categoryList)) {
+ $categoryList = CategoryList::get();
+ }
+
+ $catA = $categoryList->getCategory($catIdA);
+ $catB = $categoryList->getCategory($catIdB);
+
+ // in case there is a category class for both reports
+ if (isset($catA) && isset($catB)) {
+
+ if ($catA->getOrder() == $catB->getOrder()) {
+ // same category order, compare subcategory order
+ $subcatA = $catA->getSubcategory($subcatIdA);
+ $subcatB = $catB->getSubcategory($subcatIdB);
+
+ // both reports have a subcategory with custom subcategory class
+ if ($subcatA && $subcatB) {
+ if ($subcatA->getOrder() == $subcatB->getOrder()) {
+ // same subcategory order, compare order of report
+
+ if ($orderA == $orderB) {
+ return 0;
+ }
+
+ return $orderA < $orderB ? -1 : 1;
+ }
+
+ return $subcatA->getOrder() < $subcatB->getOrder() ? -1 : 1;
+
+ } elseif ($subcatA) {
+ return -1;
+ } elseif ($subcatB) {
+ return 1;
+ }
+
+ if ($orderA == $orderB) {
+ return 0;
+ }
+
+ return $orderA < $orderB ? -1 : 1;
+ }
+
+ return $catA->getOrder() < $catB->getOrder() ? -1 : 1;
+
+ } elseif (isset($catA)) {
+ return -1;
+ } elseif (isset($catB)) {
+ return 1;
+ }
+
+ if ($catIdA === $catIdB) {
+ // both have same category, compare order
+ if ($orderA == $orderB) {
+ return 0;
+ }
+
+ return $orderA < $orderB ? -1 : 1;
+ }
+
+ return strnatcasecmp($catIdA, $catIdB);
+ }
+
+ /**
+ * Returns class names of all Report metadata classes.
+ *
+ * @return string[]
+ * @api
+ */
+ public function getAllReportClasses()
+ {
+ return Plugin\Manager::getInstance()->findMultipleComponents('Reports', '\\Piwik\\Plugin\\Report');
+ }
+} \ No newline at end of file
diff --git a/core/Plugin/ViewDataTable.php b/core/Plugin/ViewDataTable.php
index 6e190388b6..5ca7e2e9ba 100644
--- a/core/Plugin/ViewDataTable.php
+++ b/core/Plugin/ViewDataTable.php
@@ -13,6 +13,7 @@ use Piwik\Common;
use Piwik\DataTable;
use Piwik\Period;
use Piwik\Piwik;
+use Piwik\Plugin\Reports;
use Piwik\View;
use Piwik\View\ViewInterface;
use Piwik\ViewDataTable\Config as VizConfig;
@@ -191,7 +192,7 @@ abstract class ViewDataTable implements ViewInterface
$this->requestConfig->apiMethodToRequestDataTable = $apiMethodToRequestDataTable;
- $report = Report::factory($this->requestConfig->getApiModuleToRequest(), $this->requestConfig->getApiMethodToRequest());
+ $report = Reports::factory($this->requestConfig->getApiModuleToRequest(), $this->requestConfig->getApiMethodToRequest());
if (!empty($report)) {
/** @var Report $report */
@@ -205,13 +206,7 @@ abstract class ViewDataTable implements ViewInterface
$relatedReports = $report->getRelatedReports();
if (!empty($relatedReports)) {
foreach ($relatedReports as $relatedReport) {
- $widgetTitle = $relatedReport->getWidgetTitle();
-
- if ($widgetTitle && Common::getRequestVar('widget', 0, 'int')) {
- $relatedReportName = $widgetTitle;
- } else {
- $relatedReportName = $relatedReport->getName();
- }
+ $relatedReportName = $relatedReport->getName();
$this->config->addRelatedReport($relatedReport->getModule() . '.' . $relatedReport->getAction(),
$relatedReportName);
@@ -273,7 +268,7 @@ abstract class ViewDataTable implements ViewInterface
$this->overrideViewPropertiesWithQueryParams();
}
- protected function assignRelatedReportsTitle()
+ private function assignRelatedReportsTitle()
{
if (!empty($this->config->related_reports_title)) {
// title already assigned by a plugin
@@ -411,12 +406,9 @@ abstract class ViewDataTable implements ViewInterface
*/
public function render()
{
- $view = $this->buildView();
- return $view->render();
+ return '';
}
- abstract protected function buildView();
-
protected function getDefaultDataTableCssClass()
{
return 'dataTableViz' . Piwik::getUnnamespacedClassName(get_class($this));
diff --git a/core/Plugin/Visualization.php b/core/Plugin/Visualization.php
index fcd8891280..da2c60c18e 100644
--- a/core/Plugin/Visualization.php
+++ b/core/Plugin/Visualization.php
@@ -23,6 +23,7 @@ use Piwik\Period;
use Piwik\Piwik;
use Piwik\Plugins\API\API as ApiApi;
use Piwik\Plugins\PrivacyManager\PrivacyManager;
+use Piwik\Plugin\Reports;
use Piwik\View;
use Piwik\ViewDataTable\Manager as ViewDataTableManager;
use Piwik\Plugin\Manager as PluginManager;
@@ -168,10 +169,10 @@ class Visualization extends ViewDataTable
parent::__construct($controllerAction, $apiMethodToRequestDataTable, $params);
- $this->report = Report::factory($this->requestConfig->getApiModuleToRequest(), $this->requestConfig->getApiMethodToRequest());
+ $this->report = Reports::factory($this->requestConfig->getApiModuleToRequest(), $this->requestConfig->getApiMethodToRequest());
}
- protected function buildView()
+ public function render()
{
$this->overrideSomeConfigPropertiesIfNeeded();
@@ -233,7 +234,7 @@ class Visualization extends ViewDataTable
$view->footerIcons = $this->config->footer_icons;
$view->isWidget = Common::getRequestVar('widget', 0, 'int');
- return $view;
+ return $view->render();
}
/**
diff --git a/core/Plugin/Widgets.php b/core/Plugin/Widgets.php
index 10566a9a7a..e67f2bce61 100644
--- a/core/Plugin/Widgets.php
+++ b/core/Plugin/Widgets.php
@@ -8,191 +8,162 @@
*/
namespace Piwik\Plugin;
-use Piwik\Development;
-use Piwik\Plugin\Manager as PluginManager;
-use Piwik\WidgetsList;
+use Piwik\Container\StaticContainer;
+use Piwik\Piwik;
+use Piwik\Plugin;
+use Exception;
+use Piwik\Widget\Widget;
+use Piwik\Widget\WidgetConfig;
+use Piwik\Widget\WidgetContainerConfig;
/**
- * Base class of all plugin widget providers. Plugins that define their own widgets can extend this class to easily
- * add new widgets or to remove widgets defined by other plugins.
- *
- * For an example, see the {@link https://github.com/piwik/piwik/blob/master/plugins/ExamplePlugin/Widgets.php} plugin.
- *
- * @api
+ * Get widgets that are defined by plugins.
*/
class Widgets
{
- protected $category = '';
- protected $widgets = array();
-
- public function __construct()
- {
- // Constructor kept for BC (because called in implementations)
- }
-
/**
- * @ignore
+ * @var Plugin\Manager
*/
- public function getCategory()
- {
- return $this->category;
- }
+ private $pluginManager;
- private function getModule()
+ public function __construct(Plugin\Manager $pluginManager)
{
- $className = get_class($this);
- $className = explode('\\', $className);
-
- return $className[2];
- }
-
- /**
- * Adds a widget. You can add a widget by calling this method and passing the name of the widget as well as a method
- * name that will be executed to render the widget. The method can be defined either directly here in this widget
- * class or in the controller in case you want to reuse the same action for instance in the menu etc.
- * @api
- */
- protected function addWidget($name, $method, $parameters = array())
- {
- $this->addWidgetWithCustomCategory($this->category, $name, $method, $parameters);
+ $this->pluginManager = $pluginManager;
}
/**
- * Adds a widget with a custom category. By default all widgets that you define in your class will be added under
- * the same category which is defined in the {@link $category} property. Sometimes you may have a widget that
- * belongs to a different category where this method comes handy. It does the same as {@link addWidget()} but
- * allows you to define the category name as well.
- * @api
+ * Get all existing widget configs.
+ *
+ * @return WidgetConfig[]
*/
- protected function addWidgetWithCustomCategory($category, $name, $method, $parameters = array())
+ public function getWidgetConfigs()
{
- $this->checkIsValidWidget($name, $method);
-
- $this->widgets[] = array('category' => $category,
- 'name' => $name,
- 'params' => $parameters,
- 'method' => $method,
- 'module' => $this->getModule());
- }
+ $widgetClasses = $this->getAllWidgetClassNames();
+
+ $configs = array();
+
+ /**
+ * Triggered to add custom widget configs. To filder widgets have a look at the {@hook Widget.filterWidgets}
+ * event.
+ *
+ * **Example**
+ *
+ * public function addWidgetConfigs(&$configs)
+ * {
+ * $config = new WidgetConfig();
+ * $config->setModule('PluginName');
+ * $config->setAction('renderDashboard');
+ * $config->setCategoryId('Dashboard_Dashboard');
+ * $config->setSubcategoryId('dashboardId');
+ * $configs[] = $config;
+ * }
+ *
+ * @param array &$configs An array containing a list of widget config entries.
+ */
+ Piwik::postEvent('Widget.addWidgetConfigs', array(&$configs));
+
+ foreach ($widgetClasses as $widgetClass) {
+ $configs[] = $this->getWidgetConfigForClassName($widgetClass);
+ }
- /**
- * Here you can add one or multiple widgets. To do so call the method {@link addWidget()} or
- * {@link addWidgetWithCustomCategory()}.
- * @api
- */
- protected function init()
- {
+ return $configs;
}
/**
- * @ignore
+ * Get all existing widget container configs.
+ * @return WidgetContainerConfig[]
*/
- public function getWidgets()
+ public function getWidgetContainerConfigs()
{
- $this->widgets = array();
+ $configs = array();
- $this->init();
+ $widgetContainerConfigs = $this->getAllWidgetContainerConfigClassNames();
+ foreach ($widgetContainerConfigs as $widgetClass) {
+ $configs[] = StaticContainer::get($widgetClass);
+ }
- return $this->widgets;
+ return $configs;
}
/**
- * Allows you to configure previously added widgets.
- * For instance you can remove any widgets defined by any plugin by calling the
- * {@link \Piwik\WidgetsList::remove()} method.
+ * Get the widget defined by the given module and action.
*
- * @param WidgetsList $widgetsList
- * @api
- */
- public function configureWidgetsList(WidgetsList $widgetsList)
- {
- }
-
- /**
- * @return \Piwik\Plugin\Widgets[]
- * @ignore
- */
- public static function getAllWidgets()
- {
- return PluginManager::getInstance()->findComponents('Widgets', 'Piwik\\Plugin\\Widgets');
- }
-
- /**
- * @ignore
- * @return Widgets|null
+ * @param string $module Aka plugin name, eg 'CoreHome'
+ * @param string $action An action eg 'renderMe'
+ * @return Widget|null
+ * @throws \Exception Throws an exception if the widget is not enabled.
*/
- public static function factory($module, $action)
+ public function factory($module, $action)
{
if (empty($module) || empty($action)) {
return;
}
- $pluginManager = PluginManager::getInstance();
-
try {
- if (!$pluginManager->isPluginActivated($module)) {
+ if (!$this->pluginManager->isPluginActivated($module)) {
return;
}
- $plugin = $pluginManager->getLoadedPlugin($module);
+ $plugin = $this->pluginManager->getLoadedPlugin($module);
} catch (\Exception $e) {
// we are not allowed to use possible widgets, plugin is not active
return;
}
- /** @var Widgets $widgetContainer */
- $widgetContainer = $plugin->findComponent('Widgets', 'Piwik\\Plugin\\Widgets');
-
- if (empty($widgetContainer)) {
- // plugin does not define any widgets, we cannot do anything
- return;
- }
+ /** @var Widget[] $widgetContainer */
+ $widgets = $plugin->findMultipleComponents('Widgets', 'Piwik\\Widget\\Widget');
- if (!is_callable(array($widgetContainer, $action))) {
- // widget does not implement such a method, we cannot do anything
- return;
+ foreach ($widgets as $widgetClass) {
+ $config = $this->getWidgetConfigForClassName($widgetClass);
+ if ($config->getAction() === $action) {
+ $config->checkIsEnabled();
+ return StaticContainer::get($widgetClass);
+ }
}
+ }
- // the widget class implements such an action, but we have to check whether it is actually exposed and whether
- // it was maybe disabled by another plugin, this is only possible by checking the widgetslist, unfortunately
- if (!WidgetsList::isDefined($module, $action)) {
- return;
- }
+ private function getWidgetConfigForClassName($widgetClass)
+ {
+ /** @var string|Widget $widgetClass */
+ $config = new WidgetConfig();
+ $config->setModule($this->getModuleFromWidgetClassName($widgetClass));
+ $config->setAction($this->getActionFromWidgetClassName($widgetClass));
+ $widgetClass::configure($config);
- return $widgetContainer;
+ return $config;
}
- private function checkIsValidWidget($name, $method)
+ /**
+ * @return string[]
+ */
+ private function getAllWidgetClassNames()
{
- if (!Development::isEnabled()) {
- return;
- }
+ return $this->pluginManager->findMultipleComponents('Widgets', 'Piwik\\Widget\\Widget');
+ }
- if (empty($name)) {
- Development::error('No name is defined for added widget having method "' . $method . '" in ' . get_class($this));
- }
+ private function getModuleFromWidgetClassName($widgetClass)
+ {
+ $parts = explode('\\', $widgetClass);
- if (Development::isCallableMethod($this, $method)) {
- return;
- }
+ return $parts[2];
+ }
- $controllerClass = 'Piwik\\Plugins\\' . $this->getModule() . '\\Controller';
+ private function getActionFromWidgetClassName($widgetClass)
+ {
+ $parts = explode('\\', $widgetClass);
- if (!Development::methodExists($this, $method) &&
- !Development::methodExists($controllerClass, $method)) {
- Development::error('The added method "' . $method . '" neither exists in "' . get_class($this) . '" nor "' . $controllerClass . '". Make sure to define such a method.');
+ if (count($parts) >= 4) {
+ return lcfirst(end($parts));
}
- $definedInClass = get_class($this);
-
- if (Development::methodExists($controllerClass, $method)) {
- if (Development::isCallableMethod($controllerClass, $method)) {
- return;
- }
-
- $definedInClass = $controllerClass;
- }
+ return '';
+ }
- Development::error('The method "' . $method . '" is not callable on "' . $definedInClass . '". Make sure the method is public.');
+ /**
+ * @return string[]
+ */
+ private function getAllWidgetContainerConfigClassNames()
+ {
+ return $this->pluginManager->findMultipleComponents('Widgets', 'Piwik\\Widget\\WidgetContainerConfig');
}
}
diff --git a/core/Report/ReportWidgetConfig.php b/core/Report/ReportWidgetConfig.php
new file mode 100644
index 0000000000..cb3b576b4d
--- /dev/null
+++ b/core/Report/ReportWidgetConfig.php
@@ -0,0 +1,92 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Report;
+use Piwik\ViewDataTable\Factory;
+use Piwik\Widget\WidgetConfig;
+
+/**
+ * Defines a widget config that is used to render a report.
+ *
+ * @api since Piwik 3.0.0
+ */
+class ReportWidgetConfig extends WidgetConfig
+{
+ protected $viewDataTable = null;
+ protected $forceViewDataTable = false;
+
+ /**
+ * Sets a default viewDataTable that should be used to render the report. This is not neccessarily the
+ * view that will be actually used to render the report. Eg if a user switched manually to another viewDataTable
+ * Piwik will re-use the viewDataTable that was used the last time. If you want to force the usage of a
+ * viewDataTable use {@link forceViewDataTable()}.
+ *
+ * @param string $viewDataTableId eg 'table' or 'graph'
+ * @return static
+ */
+ public function setDefaultViewDataTable($viewDataTableId)
+ {
+ $this->viewDataTable = $viewDataTableId;
+ return $this;
+ }
+
+ /**
+ * Forces the usage of the given viewDataTable in order to render the report.
+ *
+ * @param string $viewDataTableId eg 'table' or 'graph'
+ * @return $this
+ */
+ public function forceViewDataTable($viewDataTableId)
+ {
+ $this->forceViewDataTable = true;
+ $this->setDefaultViewDataTable($viewDataTableId);
+
+ return $this;
+ }
+
+ /**
+ * Detect whether a defined viewDataTable should be forced in order to render a report.
+ * @return bool
+ */
+ public function isViewDataTableForced()
+ {
+ return $this->forceViewDataTable;
+ }
+
+ /**
+ * Get the specified viewDataTable.
+ * @return string
+ */
+ public function getViewDataTable()
+ {
+ return $this->viewDataTable;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function getParameters()
+ {
+ $parameters = parent::getParameters();
+
+ $defaultParams = array();
+
+ if ($this->forceViewDataTable) {
+ $defaultParams['forceView'] = '1';
+ }
+
+ if ($this->viewDataTable &&
+ ($this->forceViewDataTable || $this->viewDataTable !== Factory::DEFAULT_VIEW)) {
+ // URL param is not needed for default view dataTable
+ $defaultParams['viewDataTable'] = $this->viewDataTable;
+ }
+
+ return $defaultParams + $parameters;
+ }
+
+} \ No newline at end of file
diff --git a/core/Report/ReportWidgetFactory.php b/core/Report/ReportWidgetFactory.php
new file mode 100644
index 0000000000..b3ea165ec4
--- /dev/null
+++ b/core/Report/ReportWidgetFactory.php
@@ -0,0 +1,119 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Report;
+
+use Piwik\Plugin\Report;
+use Piwik\Widget\WidgetContainerConfig;
+
+/**
+ * Report widget factory. This factory allows you to create widgets for a given report without having to re-specify
+ * redundant information like module, action, category, subcategory, order, ... When creating a widget from a report
+ * these values will be automatically specified so that ideally `$factory->createWidget()` is all one has to do in
+ * order to create a new widget.
+ *
+ * @api since Piwik 3.0.0
+ */
+class ReportWidgetFactory
+{
+ /**
+ * @var Report
+ */
+ private $report = null;
+
+ /**
+ * Generates a new report widget factory.
+ * @param Report $report A report instance, widgets will be created based on the data provided by this report.
+ */
+ public function __construct(Report $report)
+ {
+ $this->report = $report;
+ }
+
+ /**
+ * Creates a widget based on the specified report in {@link construct()}.
+ *
+ * It will automatically use the report's name, categoryId, subcategoryId (if specified),
+ * defaultViewDataTable, module, action, order and parameters in order to create the widget.
+ *
+ * @return ReportWidgetConfig
+ */
+ public function createWidget()
+ {
+ $widget = new ReportWidgetConfig();
+ $widget->setName($this->report->getName());
+ $widget->setCategoryId($this->report->getCategoryId());
+
+ if ($this->report->getDefaultTypeViewDataTable()) {
+ $widget->setDefaultViewDataTable($this->report->getDefaultTypeViewDataTable());
+ }
+
+ if ($this->report->getSubcategoryId()) {
+ $widget->setSubcategoryId($this->report->getSubcategoryId());
+ }
+
+ $widget->setModule($this->report->getModule());
+ $widget->setAction($this->report->getAction());
+
+ $orderThatListsReportsAtTheEndOfEachCategory = 100 + $this->report->getOrder();
+ $widget->setOrder($orderThatListsReportsAtTheEndOfEachCategory);
+
+ $parameters = $this->report->getParameters();
+ if (!empty($parameters)) {
+ $widget->setParameters($parameters);
+ }
+
+ return $widget;
+ }
+
+ /**
+ * Creates a new container widget based on the specified report in {@link construct()}.
+ *
+ * It will automatically use the report's categoryId, subcategoryId (if specified) and order in order to
+ * create the container.
+ *
+ * @param string $containerId eg 'Products' or 'Contents' see {Piwik\Widget\WidgetContainerConfig::setId()}.
+ * Other reports or widgets will be able to add more widgets to this container.
+ * This is useful when you want to show for example multiple related widgets
+ * together.
+ * @return WidgetContainerConfig
+ */
+ public function createContainerWidget($containerId)
+ {
+ $widget = new WidgetContainerConfig();
+ $widget->setCategoryId($this->report->getCategoryId());
+ $widget->setId($containerId);
+
+ if ($this->report->getSubcategoryId()) {
+ $widget->setSubcategoryId($this->report->getSubcategoryId());
+ }
+
+ $orderThatListsReportsAtTheEndOfEachCategory = 100 + $this->report->getOrder();
+ $widget->setOrder($orderThatListsReportsAtTheEndOfEachCategory);
+
+ return $widget;
+ }
+
+ /**
+ * Creates a custom widget that doesn't use a viewDataTable to render the report but instead a custom
+ * controller action. Make sure the specified `$action` exists in the plugin's controller. Otherwise
+ * behaves as {@link createWidget()}.
+ *
+ * @param string $action eg 'conversionReports' (requires a method `public function conversionReports()` in
+ * the plugin's controller).
+ * @return ReportWidgetConfig
+ */
+ public function createCustomWidget($action)
+ {
+ $widget = $this->createWidget();
+ $widget->setDefaultViewDataTable(null);
+ $widget->setAction($action);
+
+ return $widget;
+ }
+} \ No newline at end of file
diff --git a/core/Updates/3.0.0-b1.php b/core/Updates/3.0.0-b1.php
new file mode 100644
index 0000000000..301bc44a1b
--- /dev/null
+++ b/core/Updates/3.0.0-b1.php
@@ -0,0 +1,351 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+
+namespace Piwik\Updates;
+
+use Piwik\Common;
+use Piwik\Db;
+use Piwik\Updater;
+use Piwik\Updates;
+use Piwik\Plugins\Dashboard;
+
+/**
+ * Update for version 3.0.0-b1.
+ */
+class Updates_3_0_0_b1 extends Updates
+{
+ /**
+ * Here you can define one or multiple SQL statements that should be executed during the update.
+ * @return array
+ */
+ public function getMigrationQueries(Updater $updater)
+ {
+ $db = Db::get();
+ $allGoals = $db->fetchAll(sprintf("SELECT DISTINCT idgoal FROM %s", Common::prefixTable('goal')));
+ $allDashboards = $db->fetchAll(sprintf("SELECT * FROM %s", Common::prefixTable('user_dashboard')));
+
+ return $this->getDashboardMigrationSqls($allDashboards, $allGoals);
+ }
+
+ public function doUpdate(Updater $updater)
+ {
+ $updater->executeMigrationQueries(__FILE__, $this->getMigrationQueries($updater));
+ }
+
+ private function getDashboardMigrationSqls($allDashboards, $allGoals)
+ {
+ $sqls = array();
+
+
+ // update dashboard to use new widgets
+ $oldWidgets = array(
+ array (
+ 'module' => 'VisitTime',
+ 'action' => 'getVisitInformationPerServerTime',
+ 'params' =>
+ array (
+ ),
+ ),array (
+ 'module' => 'VisitTime',
+ 'action' => 'getVisitInformationPerLocalTime',
+ 'params' =>
+ array (
+ ),
+ ),array (
+ 'module' => 'VisitTime',
+ 'action' => 'getByDayOfWeek',
+ 'params' =>
+ array (
+ ),
+ ),array (
+ 'module' => 'VisitsSummary',
+ 'action' => 'getEvolutionGraph',
+ 'params' =>
+ array (
+ 'columns' => array ('nb_visits'),
+ ),
+ ),array (
+ 'module' => 'VisitsSummary',
+ 'action' => 'getSparklines',
+ 'params' =>
+ array (
+ ),
+ ),array (
+ 'module' => 'VisitsSummary',
+ 'action' => 'index',
+ 'params' =>
+ array (
+ ),
+ ),array (
+ 'module' => 'Live',
+ 'action' => 'getVisitorLog',
+ 'params' =>
+ array ('small' => 1),
+ ),array (
+ 'module' => 'VisitorInterest',
+ 'action' => 'getNumberOfVisitsPerVisitDuration',
+ 'params' =>
+ array (
+ ),
+ ),array (
+ 'module' => 'VisitorInterest',
+ 'action' => 'getNumberOfVisitsPerPage',
+ 'params' =>
+ array (
+ ),
+ ),array (
+ 'module' => 'VisitFrequency',
+ 'action' => 'getSparklines',
+ 'params' =>
+ array (
+ ),
+ ),array (
+ 'module' => 'VisitFrequency',
+ 'action' => 'getEvolutionGraph',
+ 'params' =>
+ array (
+ 'columns' => array ('nb_visits_returning'),
+ ),
+ ),array (
+ 'module' => 'DevicesDetection',
+ 'action' => 'getBrowserEngines',
+ 'params' =>
+ array (
+ ),
+ ),array (
+ 'module' => 'Referrers',
+ 'action' => 'getReferrerType',
+ 'params' =>
+ array (
+ ),
+ ),array (
+ 'module' => 'Referrers',
+ 'action' => 'getAll',
+ 'params' =>
+ array (
+ ),
+ ),array (
+ 'module' => 'Referrers',
+ 'action' => 'getSocials',
+ 'params' =>
+ array (
+ ),
+ ),array (
+ 'module' => 'Goals',
+ 'action' => 'widgetGoalsOverview',
+ 'params' =>
+ array (
+ ),
+ ),array (
+ 'module' => 'Goals',
+ 'action' => 'getItemsSku',
+ 'params' =>
+ array (
+ ),
+ ),array (
+ 'module' => 'Goals',
+ 'action' => 'getItemsName',
+ 'params' =>
+ array (
+ ),
+ ),array (
+ 'module' => 'Goals',
+ 'action' => 'getItemsCategory',
+ 'params' =>
+ array (
+ ),
+ ),array (
+ 'module' => 'Ecommerce',
+ 'action' => 'widgetGoalReport',
+ 'params' =>
+ array (
+ 'idGoal' => 'ecommerceOrder',
+ ),
+ ),
+ );
+
+ foreach ($allGoals as $goal) {
+ $oldWidgets[] = array (
+ 'module' => 'Goals',
+ 'action' => 'widgetGoalReport',
+ 'params' =>
+ array (
+ 'idGoal' => (int) $goal['idgoal'],
+ ));
+ }
+
+ $newWidgets = array(
+ array (
+ 'module' => 'VisitTime',
+ 'action' => 'getVisitInformationPerServerTime',
+ 'params' =>
+ array (
+ 'viewDataTable' => 'graphVerticalBar',
+ ),
+ ),array (
+ 'module' => 'VisitTime',
+ 'action' => 'getVisitInformationPerLocalTime',
+ 'params' =>
+ array (
+ 'viewDataTable' => 'graphVerticalBar',
+ ),
+ ),array (
+ 'module' => 'VisitTime',
+ 'action' => 'getByDayOfWeek',
+ 'params' =>
+ array (
+ 'viewDataTable' => 'graphVerticalBar'
+ ),
+ ),array (
+ 'module' => 'VisitsSummary',
+ 'action' => 'getEvolutionGraph',
+ 'params' =>
+ array (
+ 'forceView' => '1',
+ 'viewDataTable' => 'graphEvolution',
+ ),
+ ),array (
+ 'module' => 'VisitsSummary',
+ 'action' => 'get',
+ 'params' =>
+ array (
+ 'forceView' => '1',
+ 'viewDataTable' => 'sparklines',
+ ),
+ ),array (
+ 'module' => 'CoreHome',
+ 'action' => 'renderWidgetContainer',
+ 'uniqueId' => 'widgetVisitOverviewWithGraph',
+ 'params' =>
+ array (
+ 'containerId' => 'VisitOverviewWithGraph',
+ ),
+ ),array (
+ 'module' => 'Live',
+ 'action' => 'getLastVisitsDetails',
+ 'params' =>
+ array (
+ 'forceView' => '1',
+ 'viewDataTable' => 'Piwik\\Plugins\\Live\\VisitorLog',
+ 'small' => '1',
+ ),
+ ),array (
+ 'module' => 'VisitorInterest',
+ 'action' => 'getNumberOfVisitsPerVisitDuration',
+ 'params' =>
+ array (
+ 'viewDataTable' => 'cloud',
+ ),
+ ),array (
+ 'module' => 'VisitorInterest',
+ 'action' => 'getNumberOfVisitsPerPage',
+ 'params' =>
+ array (
+ 'viewDataTable' => 'cloud',
+ ),
+ ),array (
+ 'module' => 'VisitFrequency',
+ 'action' => 'get',
+ 'params' =>
+ array (
+ 'forceView' => '1',
+ 'viewDataTable' => 'sparklines'
+ ),
+ ),array (
+ 'module' => 'VisitFrequency',
+ 'action' => 'getEvolutionGraph',
+ 'params' =>
+ array (
+ 'forceView' => 1,
+ 'viewDataTable' => 'graphEvolution',
+ ),
+ ),array (
+ 'module' => 'DevicesDetection',
+ 'action' => 'getBrowserEngines',
+ 'params' =>
+ array (
+ 'viewDataTable' => 'graphPie',
+ ),
+ ),array (
+ 'module' => 'Referrers',
+ 'action' => 'getReferrerType',
+ 'params' =>
+ array (
+ 'viewDataTable' => 'tableAllColumns',
+ ),
+ ),array (
+ 'module' => 'Referrers',
+ 'action' => 'getAll',
+ 'params' =>
+ array (
+ 'viewDataTable' => 'tableAllColumns',
+ ),
+ ),array (
+ 'module' => 'Referrers',
+ 'action' => 'getSocials',
+ 'params' =>
+ array (
+ 'viewDataTable' => 'graphPie',
+ ),
+ ),array (
+ 'module' => 'CoreHome',
+ 'action' => 'renderWidgetContainer',
+ 'uniqueId' => 'widgetGoalsOverview',
+ 'params' =>
+ array (
+ 'containerId' => 'GoalsOverview'
+ ),
+ ),array (
+ 'module' => 'Goals',
+ 'action' => 'getItemsSku',
+ 'params' => array (),
+ ),array (
+ 'module' => 'Goals',
+ 'action' => 'getItemsName',
+ 'params' => array (),
+ ),array (
+ 'module' => 'Goals',
+ 'action' => 'getItemsCategory',
+ 'params' => array (),
+ ),array (
+ 'module' => 'CoreHome',
+ 'action' => 'renderWidgetContainer',
+ 'uniqueId' => 'widgetEcommerceOverview',
+ 'params' =>
+ array (
+ 'containerId' => 'EcommerceOverview',
+ ),
+ ),
+ );
+
+ foreach ($allGoals as $goal) {
+ $newWidgets[] = array (
+ 'module' => 'CoreHome',
+ 'action' => 'renderWidgetContainer',
+ 'uniqueId' => 'widgetGoal_' . (int) $goal['idgoal'],
+ 'params' =>
+ array (
+ 'containerId' => 'Goal_' . (int) $goal['idgoal'],
+ ));
+ }
+
+ foreach ($allDashboards as $dashboard) {
+ $dashboardLayout = json_decode($dashboard['layout']);
+
+ $dashboardLayout = Dashboard\Model::replaceDashboardWidgets($dashboardLayout, $oldWidgets, $newWidgets);
+
+ $newLayout = json_encode($dashboardLayout);
+ if ($newLayout != $dashboard['layout']) {
+ $sqls["UPDATE " . Common::prefixTable('user_dashboard') . " SET layout = '".addslashes($newLayout)."' WHERE iddashboard = ".$dashboard['iddashboard']] = false;
+ }
+ }
+
+ return $sqls;
+ }
+}
diff --git a/core/Version.php b/core/Version.php
index 9e9036a0ac..224db01a2c 100644
--- a/core/Version.php
+++ b/core/Version.php
@@ -20,7 +20,7 @@ final class Version
* The current Piwik version.
* @var string
*/
- const VERSION = '2.16.1-b1';
+ const VERSION = '3.0.0-b1';
public function isStableVersion($version)
{
diff --git a/core/View/ReportsByDimension.php b/core/View/ReportsByDimension.php
deleted file mode 100644
index dbb59be930..0000000000
--- a/core/View/ReportsByDimension.php
+++ /dev/null
@@ -1,129 +0,0 @@
-<?php
-/**
- * Piwik - free/libre analytics platform
- *
- * @link http://piwik.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- *
- */
-namespace Piwik\View;
-
-use Piwik\FrontController;
-use Piwik\Piwik;
-use Piwik\Url;
-use Piwik\View;
-
-/**
- * A facade that makes it easier to use the '_reportsByDimension.twig' template.
- *
- * This view will output HTML that displays a list of report names by category and
- * loads them by AJAX when clicked. The loaded report is displayed to the right
- * of the report listing.
- */
-class ReportsByDimension extends View
-{
- /**
- * Constructor.
- *
- * @param string $id
- */
- public function __construct($id)
- {
- parent::__construct('@CoreHome/ReportsByDimension/_reportsByDimension');
- $this->dimensionCategories = array();
- $this->id = $id;
- }
-
- /**
- * Adds a report to the list of reports to display.
- *
- * @param string $category The report's category. Can be a i18n token.
- * @param string $title The report's title. Can be a i18n token.
- * @param string $action The controller action used to load the report, ie, Referrers.getAll
- * @param array $params The list of query parameters to use when loading the report.
- * This list overrides query parameters currently in use. For example,
- * array('idSite' => 2, 'viewDataTable' => 'goalsTable')
- * would mean the goals report for site w/ ID=2 will always be loaded.
- */
- public function addReport($category, $title, $action, $params = array())
- {
- list($module, $action) = explode('.', $action);
- $params = array('module' => $module, 'action' => $action) + $params;
-
- $categories = $this->dimensionCategories;
- $categories[$category][] = array(
- 'title' => $title,
- 'params' => $params,
- 'url' => Url::getCurrentQueryStringWithParametersModified($params)
- );
- $this->dimensionCategories = $categories;
- }
-
- /**
- * Adds a set of reports to the list of reports to display.
- *
- * @param array $reports An array containing report information. The array requires
- * the 'category', 'title', 'action' and 'params' elements.
- * For information on what they should contain, @see addReport.
- */
- public function addReports($reports)
- {
- foreach ($reports as $report) {
- $this->addReport($report['category'], $report['title'], $report['action'], $report['params']);
- }
- }
-
- /**
- * @return string The ID specified in the constructor, usually the plugin name
- */
- public function getId()
- {
- return $this->id;
- }
-
- /**
- * Renders this view.
- *
- * @return string The rendered view.
- */
- public function render()
- {
- /**
- * Triggered before rendering {@link ReportsByDimension} views.
- *
- * Plugins can use this event to configure {@link ReportsByDimension} instances by
- * adding or removing reports to display.
- *
- * @param ReportsByDimension $this The view instance.
- */
- Piwik::postEvent('View.ReportsByDimension.render', array($this));
-
- $this->firstReport = "";
-
- // if there are reports & report categories added, render the first one so we can
- // display it initially
- $categories = $this->dimensionCategories;
- if (!empty($categories)) {
- $firstCategory = reset($categories);
- $firstReportInfo = reset($firstCategory);
-
- $oldGet = $_GET;
- $oldPost = $_POST;
-
- foreach ($firstReportInfo['params'] as $key => $value) {
- $_GET[$key] = $value;
- }
-
- $_POST = array();
-
- $module = $firstReportInfo['params']['module'];
- $action = $firstReportInfo['params']['action'];
- $this->firstReport = FrontController::getInstance()->fetchDispatch($module, $action);
-
- $_GET = $oldGet;
- $_POST = $oldPost;
- }
-
- return parent::render();
- }
-}
diff --git a/core/ViewDataTable/Config.php b/core/ViewDataTable/Config.php
index bd73ea846a..f275aebe58 100644
--- a/core/ViewDataTable/Config.php
+++ b/core/ViewDataTable/Config.php
@@ -14,8 +14,8 @@ use Piwik\Common;
use Piwik\DataTable;
use Piwik\DataTable\Filter\PivotByDimension;
use Piwik\Metrics;
-use Piwik\Plugin\Report;
use Piwik\Plugins\API\API;
+use Piwik\Plugin\Reports;
/**
* Contains base display properties for {@link Piwik\Plugin\ViewDataTable}s. Manipulating these
@@ -717,7 +717,7 @@ class Config
private function setShouldShowPivotBySubtable()
{
- $report = Report::factory($this->controllerName, $this->controllerAction);
+ $report = Reports::factory($this->controllerName, $this->controllerAction);
if (empty($report)) {
$this->show_pivot_by_subtable = false;
diff --git a/core/ViewDataTable/Factory.php b/core/ViewDataTable/Factory.php
index 43db3161e9..543f1280cf 100644
--- a/core/ViewDataTable/Factory.php
+++ b/core/ViewDataTable/Factory.php
@@ -12,6 +12,7 @@ use Piwik\Common;
use Piwik\Piwik;
use Piwik\Plugin\Report;
use Piwik\Plugins\CoreVisualizations\Visualizations\HtmlTable;
+use Piwik\Plugin\Reports;
/**
* Provides a means of creating {@link Piwik\Plugin\ViewDataTable} instances by ID.
@@ -58,6 +59,8 @@ use Piwik\Plugins\CoreVisualizations\Visualizations\HtmlTable;
*/
class Factory
{
+ const DEFAULT_VIEW = HtmlTable::ID;
+
/**
* Cache for getDefaultTypeViewDataTable result.
*
@@ -132,7 +135,7 @@ class Factory
// Common::getRequestVar removes backslashes from the defaultValue in case magic quotes are enabled.
// therefore do not pass this as a default value to getRequestVar()
if ('' === $type) {
- $type = $defaultType ?: HtmlTable::ID;
+ $type = $defaultType ?: self::DEFAULT_VIEW;
}
} else {
$type = $defaultViewType;
@@ -150,8 +153,8 @@ class Factory
return self::createViewDataTableInstance($visualizations[$defaultType], $controllerAction, $apiAction, $params);
}
- if (array_key_exists(HtmlTable::ID, $visualizations)) {
- return self::createViewDataTableInstance($visualizations[HtmlTable::ID], $controllerAction, $apiAction, $params);
+ if (array_key_exists(self::DEFAULT_VIEW, $visualizations)) {
+ return self::createViewDataTableInstance($visualizations[self::DEFAULT_VIEW], $controllerAction, $apiAction, $params);
}
throw new \Exception('No visualization found to render ViewDataTable');
@@ -165,7 +168,7 @@ class Factory
private static function getReport($apiAction)
{
list($module, $action) = explode('.', $apiAction);
- $report = Report::factory($module, $action);
+ $report = Reports::factory($module, $action);
return $report;
}
diff --git a/core/Widget/Widget.php b/core/Widget/Widget.php
new file mode 100644
index 0000000000..3a27331bd1
--- /dev/null
+++ b/core/Widget/Widget.php
@@ -0,0 +1,37 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Widget;
+
+/**
+ * Defines a new widget. You can create a new widget using the console command `./console generate:widget`.
+ * The generated widget will guide you through the creation of a widget.
+ *
+ * For an example, see {@link https://github.com/piwik/piwik/blob/master/plugins/ExamplePlugin/Widgets/MyExampleWidget.php}
+ *
+ * @api since Piwik 3.0.0
+ */
+class Widget
+{
+ /**
+ * @param WidgetConfig $config
+ * @api
+ */
+ public static function configure(WidgetConfig $config)
+ {
+ }
+
+ /**
+ * @return string
+ */
+ public function render()
+ {
+ return '';
+ }
+
+}
diff --git a/core/Widget/WidgetConfig.php b/core/Widget/WidgetConfig.php
new file mode 100644
index 0000000000..f4d8cf4681
--- /dev/null
+++ b/core/Widget/WidgetConfig.php
@@ -0,0 +1,343 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Widget;
+
+use Piwik\Piwik;
+use Exception;
+
+/**
+ * Configures a widget. Use this class to configure a {@link Piwik\Widget\Widget`} or to
+ * add a widget to the WidgetsList via {@link WidgetsList::addWidget}.
+ *
+ * @api since Piwik 3.0.0
+ */
+class WidgetConfig
+{
+ protected $categoryId = '';
+ protected $subcategoryId = '';
+ protected $module = '';
+ protected $action = '';
+ protected $parameters = array();
+ protected $middlewareParameters = array();
+ protected $name = '';
+ protected $order = 99;
+ protected $isEnabled = true;
+ protected $isWidgetizable = true;
+
+ /**
+ * Set the id of the category the widget belongs to.
+ * @param string $categoryId Usually a translation key, eg 'General_Visits', 'Goals_Goals', ...
+ * @return static
+ */
+ public function setCategoryId($categoryId)
+ {
+ $this->categoryId = $categoryId;
+
+ return $this;
+ }
+
+ /**
+ * Get the id of the category the widget belongs to.
+ * @return string
+ */
+ public function getCategoryId()
+ {
+ return $this->categoryId;
+ }
+
+ /**
+ * Set the id of the subcategory the widget belongs to. If a subcategory is specified, the widget
+ * will be shown in the Piwik reporting UI. The subcategoryId will be used as a translation key for
+ * the submenu item.
+ *
+ * @param string $subcategoryId Usually a translation key, eg 'General_Overview', 'Actions_Pages', ...
+ * @return static
+ */
+ public function setSubcategoryId($subcategoryId)
+ {
+ $this->subcategoryId = $subcategoryId;
+
+ return $this;
+ }
+
+ public function getSubcategoryId()
+ {
+ return $this->subcategoryId;
+ }
+
+ /**
+ * Set the module (aka plugin name) of the widget. The correct module is usually detected automatically and
+ * not needed to be configured manually.
+ *
+ * @param string $module eg 'CoreHome'
+ * @return static
+ */
+ public function setModule($module)
+ {
+ $this->module = $module;
+
+ return $this;
+ }
+
+ public function getModule()
+ {
+ return $this->module;
+ }
+
+ /**
+ * Set the action of the widget that shall be used in the URL to render the widget.
+ * The correct action is usually detected automatically and not needed to be configured manually.
+ *
+ * @param string $action eg 'renderMyWidget'
+ * @return static
+ */
+ public function setAction($action)
+ {
+ $this->action = $action;
+
+ return $this;
+ }
+
+ public function getAction()
+ {
+ return $this->action;
+ }
+
+ /**
+ * Sets (overwrites) the parameters of the widget. These parameters will be added to the URL when rendering the
+ * widget. You can access these parameters via `Piwik\Common::getRequestVar(...)`.
+ *
+ * @param array $parameters eg. ('urlparam' => 'urlvalue')
+ * @return static
+ */
+ public function setParameters($parameters)
+ {
+ $this->parameters = $parameters;
+
+ return $this;
+ }
+
+ /**
+ * Add new parameters and only overwrite parameters that have the same name. See {@link setParameters()}
+ *
+ * @param array $parameters eg. ('urlparam' => 'urlvalue')
+ * @return static
+ */
+ public function addParameters($parameters)
+ {
+ $this->parameters = array_merge($this->parameters, $parameters);
+
+ return $this;
+ }
+
+ /**
+ * Get all URL parameters needed to render this widget.
+ * @return array Eg ('urlparam' => 'urlvalue').
+ */
+ public function getParameters()
+ {
+ $defaultParams = array(
+ 'module' => $this->getModule(),
+ 'action' => $this->getAction()
+ );
+
+ return $defaultParams + $this->parameters;
+ }
+
+ /**
+ * Set the name of the widget.
+ *
+ * @param string $name Usually a translation key, eg 'VisitTime_ByServerTimeWidgetName'
+ * @return static
+ */
+ public function setName($name)
+ {
+ $this->name = $name;
+
+ return $this;
+ }
+
+ /**
+ * Get the name of the widget.
+ *
+ * @return string
+ */
+ public function getName()
+ {
+ return $this->name;
+ }
+
+ /**
+ * Set the order of the widget.
+ *
+ * @param int $order eg. 5
+ * @return static
+ */
+ public function setOrder($order)
+ {
+ $this->order = (int) $order;
+
+ return $this;
+ }
+
+ /**
+ * Returns the order of the widget.
+ * @return int
+ */
+ public function getOrder()
+ {
+ return $this->order;
+ }
+
+ /**
+ * Defines whether a widget is enabled or not. For instance some widgets might not be available to every user or
+ * might depend on a setting (such as Ecommerce) of a site. In such a case you can perform any checks and then
+ * return `true` or `false`. If your report is only available to users having super user access you can do the
+ * following: `return Piwik::hasUserSuperUserAccess();`
+ * @return bool
+ * @api
+ */
+ public function isEnabled()
+ {
+ return $this->isEnabled;
+ }
+
+ /**
+ * Enable / disable the widget. See {@link isEnabled()}
+ *
+ * @param bool $isEnabled
+ * @return static
+ */
+ public function setIsEnabled($isEnabled)
+ {
+ $this->isEnabled = (bool) $isEnabled;
+ return $this;
+ }
+
+ /**
+ * Enables the widget. See {@link isEnabled()}
+ */
+ public function enable()
+ {
+ $this->setIsEnabled(true);
+ }
+
+ /**
+ * Disables the widget. See {@link isEnabled()}
+ */
+ public function disable()
+ {
+ $this->setIsEnabled(false);
+ }
+
+ /**
+ * This method checks whether the widget is available, see {@link isEnabled()}. If not, it triggers an exception
+ * containing a message that will be displayed to the user. You can overwrite this message in case you want to
+ * customize the error message. Eg.
+ * ```
+ * if (!$this->isEnabled()) {
+ * throw new Exception('Setting XYZ is not enabled or the user has not enough permission');
+ * }
+ * ```
+ * @throws \Exception
+ * @api
+ */
+ public function checkIsEnabled()
+ {
+ if (!$this->isEnabled()) {
+ throw new Exception(Piwik::translate('General_ExceptionWidgetNotEnabled'));
+ }
+ }
+
+ /**
+ * Returns the unique id of an widget based on module, action and the set parameters.
+ *
+ * @return string
+ */
+ public function getUniqueId()
+ {
+ $parameters = $this->getParameters();
+ unset($parameters['module']);
+ unset($parameters['action']);
+
+ return WidgetsList::getWidgetUniqueId($this->getModule(), $this->getAction(), $parameters);
+ }
+
+ /**
+ * Sets the widget as not widgetizable {@link isWidgetizeable()}.
+ *
+ * @return static
+ */
+ public function setIsNotWidgetizable()
+ {
+ $this->isWidgetizable = false;
+ return $this;
+ }
+
+ /**
+ * Sets the widget as widgetizable {@link isWidgetizeable()}.
+ *
+ * @return static
+ */
+ public function setIsWidgetizable()
+ {
+ $this->isWidgetizable = true;
+ return $this;
+ }
+
+ /**
+ * Detect whether the widget is widgetizable meaning it won't be able to add it to the dashboard and it won't
+ * be possible to export the widget via an iframe if it is not widgetizable. This is usually not needed but useful
+ * when you eg want to display a widget within the Piwik UI but not want to have it widgetizable.
+ *
+ * @return bool
+ */
+ public function isWidgetizeable()
+ {
+ return $this->isWidgetizable;
+ }
+
+ /**
+ * If middleware parameters are specified, the corresponding action will be executed before showing the
+ * actual widget in the UI. Only if this action (can be a controller method or API method) returns JSON `true`
+ * the widget will be actually shown. It is similar to `isEnabled()` but the specified action is performed each
+ * time the widget is requested in the UI whereas `isEnabled` is only checked once on the inital page load when
+ * we load the inital list of widgets. So if your widget's visibility depends on archived data
+ * (aka idSite/period/date) you should specify middle parameters. This has mainly two reasons:
+ *
+ * - This way the inital page load time is faster as we won't have to request archived data on the initial page
+ * load for widgets that are potentially never shown.
+ * - We execute that action every time before showing it. As the initial list of widgets is loaded on page load
+ * it is possible that some archives have no data yet, but at a later time there might be actually archived data.
+ * As we never reload the initial list of widgets we would still not show the widget even there we should. Example:
+ * On page load there are no conversions, a few minutes later there might be conversions. As the middleware is
+ * executed before showing it, we detect correctly that there are now conversions whereas `isEnabled` is only
+ * checked once on the initial Piwik page load.
+ *
+ * @param array $parameters URL parameters eg array('module' => 'Goals', 'action' => 'Conversions')
+ * @return static
+ */
+ public function setMiddlewareParameters($parameters)
+ {
+ $this->middlewareParameters = $parameters;
+ return $this;
+ }
+
+ /**
+ * Get defined middleware parameters (if any).
+ *
+ * @return array
+ */
+ public function getMiddlewareParameters()
+ {
+ return $this->middlewareParameters;
+ }
+
+
+} \ No newline at end of file
diff --git a/core/Widget/WidgetContainerConfig.php b/core/Widget/WidgetContainerConfig.php
new file mode 100644
index 0000000000..258d182ab4
--- /dev/null
+++ b/core/Widget/WidgetContainerConfig.php
@@ -0,0 +1,131 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Widget;
+
+/**
+ * Defines a new widget container. Widget containers are useful when you want to combine several widgets
+ * into one unique widgets. For example you could combine an evolution graph widget with a sparklines widget
+ * and combine them to a single "overview widget". It also allows you to specify layouts meaning you can
+ * define a layout that will group multiple widgets into one widget displaying a menu on the left side for each
+ * widget and the actual widget on the right side. By default widgets within a container are displayed vertically
+ * one after another.
+ *
+ * To define a widget container just place a subclass within the `Widgets` folder of your plugin.
+ *
+ * @api since Piwik 3.0.0
+ */
+class WidgetContainerConfig extends WidgetConfig
+{
+ /**
+ * @var WidgetConfig[]
+ */
+ protected $widgets = array();
+ protected $layout = '';
+ protected $id = '';
+
+ protected $module = 'CoreHome';
+ protected $action = 'renderWidgetContainer';
+ protected $isWidgetizable = false;
+
+ /**
+ * Sets (overwrites) the id of the widget container.
+ *
+ * The id can be used by any plugins to add more widgets to this container and it will be also used for the unique
+ * widget id and in the URL to render this widget.
+ *
+ * @param string $id eg 'Products' or 'Contents'
+ * @return static
+ */
+ public function setId($id)
+ {
+ $this->id = $id;
+ return $this;
+ }
+
+ /**
+ * Get the id of the widget.
+ * @return string
+ */
+ public function getId()
+ {
+ return $this->id;
+ }
+
+ /**
+ * Sets the layout of the container widget.
+ *
+ * By default widgets within a container are displayed one after another. In case you want to change this
+ * behaviour you can specify a layout that will be recognized by the UI. It is not yet possible to define
+ * custom layouts.
+ *
+ * @param string $layout eg 'ByDimension' see {@link Piwik\Plugins\CoreHome\CoreHome::WIDGET_CONTAINER_LAYOUT_BY_DIMENSION}
+ * @return static
+ */
+ public function setLayout($layout)
+ {
+ $this->layout = $layout;
+ return $this;
+ }
+
+ /**
+ * Gets the currently set layout.
+ * @return string
+ */
+ public function getLayout()
+ {
+ return $this->layout;
+ }
+
+ /**
+ * Adds a new widget to the container widget.
+ *
+ * @param WidgetConfig $widget
+ * @return static
+ */
+ public function addWidgetConfig(WidgetConfig $widget)
+ {
+ $this->widgets[] = $widget;
+
+ return $this;
+ }
+
+ /**
+ * Get all added widget configs.
+ *
+ * @return WidgetConfig[]
+ */
+ public function getWidgetConfigs()
+ {
+ return $this->widgets;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function getUniqueId()
+ {
+ $parameters = $this->getParameters();
+ unset($parameters['module']);
+ unset($parameters['action']);
+ unset($parameters['containerId']);
+
+ return WidgetsList::getWidgetUniqueId($this->id, '', $parameters);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function getParameters()
+ {
+ $params = parent::getParameters();
+ $params['containerId'] = $this->getId();
+ return $params;
+ }
+
+} \ No newline at end of file
diff --git a/core/Widget/WidgetsList.php b/core/Widget/WidgetsList.php
new file mode 100644
index 0000000000..dfeb004277
--- /dev/null
+++ b/core/Widget/WidgetsList.php
@@ -0,0 +1,247 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Widget;
+
+use Piwik\Cache as PiwikCache;
+use Piwik\Container\StaticContainer;
+use Piwik\Development;
+use Piwik\Piwik;
+use Piwik\Report\ReportWidgetFactory;
+
+/**
+ * Manages the global list of reports that can be displayed as dashboard widgets.
+ *
+ * Widgets are added through the {@hook WidgetsList.addWidgets} and filtered through the {@hook Widgets.filterWidgets}
+ * event. Observers for this event should call the {@link addWidget()} method to add widgets or use any of the other
+ * methods to remove widgets.
+ *
+ * @api since Piwik 3.0.0
+ */
+class WidgetsList
+{
+ /**
+ * List of widgets
+ *
+ * @var WidgetConfig[]
+ */
+ private $widgets = array();
+
+ /**
+ * @var WidgetContainerConfig[]
+ */
+ private $container;
+
+ /**
+ * @var array
+ */
+ private $containerWidgets;
+
+ /**
+ * Adds a new widget to the widget config. Please make sure the widget is enabled before adding a widget as
+ * no such checks will be performed.
+ *
+ * @param WidgetConfig $widget
+ */
+ public function addWidgetConfig(WidgetConfig $widget)
+ {
+ if ($widget instanceof WidgetContainerConfig) {
+ $this->addContainer($widget);
+ } elseif (Development::isEnabled()) {
+ $this->checkIsValidWidget($widget);
+ }
+
+ $this->widgets[] = $widget;
+ }
+
+ /**
+ * Add multiple widget configs at once. See {@link addWidgetConfig()}.
+ *
+ * @param WidgetConfig[] $widgets
+ */
+ public function addWidgetConfigs($widgets)
+ {
+ foreach ($widgets as $widget) {
+ $this->addWidgetConfig($widget);
+ }
+ }
+
+ private function addContainer(WidgetContainerConfig $containerWidget)
+ {
+ $widgetId = $containerWidget->getId();
+
+ $this->container[$widgetId] = $containerWidget;
+
+ // widgets were added to this container, but the container did not exist yet.
+ if (isset($this->containerWidgets[$widgetId])) {
+ foreach ($this->containerWidgets[$widgetId] as $widget) {
+ $containerWidget->addWidgetConfig($widget);
+ }
+ unset($this->containerWidgets[$widgetId]);
+ }
+ }
+
+ /**
+ * Get all added widget configs.
+ *
+ * @return WidgetConfig[]
+ */
+ public function getWidgetConfigs()
+ {
+ return $this->widgets;
+ }
+
+ private function checkIsValidWidget(WidgetConfig $widget)
+ {
+ if (!$widget->getModule()) {
+ Development::error('No module is defined for added widget having name "' . $widget->getName());
+ }
+
+ if (!$widget->getAction()) {
+ Development::error('No action is defined for added widget having name "' . $widget->getName());
+ }
+ }
+
+ /**
+ * Add a widget to a widget container. It doesn't matter whether the container was added to this list already
+ * or whether the container is added later. As long as a container having the same containerId is added at
+ * some point the widget will be added to that container. If no container having this id is added the widget
+ * will not be recognized.
+ *
+ * @param string $containerId eg 'Products' or 'Contents'. See {@link WidgetContainerConfig::setId}
+ * @param WidgetConfig $widget
+ */
+ public function addToContainerWidget($containerId, WidgetConfig $widget)
+ {
+ if (isset($this->container[$containerId])) {
+ $this->container[$containerId]->addWidgetConfig($widget);
+ } else {
+ if (!isset($this->containerWidgets[$containerId])) {
+ $this->containerWidgets[$containerId] = array();
+ }
+
+ $this->containerWidgets[$containerId][] = $widget;
+ }
+ }
+
+ /**
+ * Removes one or more widgets from the widget list.
+ *
+ * @param string $widgetCategoryId The widget category id. Can be a translation token eg 'General_Visits'
+ * see {@link WidgetConfig::setCategoryId()}.
+ * @param string|false $widgetName The name of the widget to remove eg 'VisitTime_ByServerTimeWidgetName'.
+ * If not supplied, all widgets within that category will be removed.
+ */
+ public function remove($widgetCategoryId, $widgetName = false)
+ {
+ foreach ($this->widgets as $index => $widget) {
+ if ($widget->getCategoryId() === $widgetCategoryId) {
+ if (!$widgetName || $widget->getName() === $widgetName) {
+ unset($this->widgets[$index]);
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns `true` if a widget exists in the widget list, `false` if otherwise.
+ *
+ * @param string $module The controller name of the widget.
+ * @param string $action The controller action of the widget.
+ * @return bool
+ */
+ public function isDefined($module, $action)
+ {
+ foreach ($this->widgets as $widget) {
+ if ($widget->getModule() === $module && $widget->getAction() === $action) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Get all widgets defined in the Piwik platform.
+ * @ignore
+ * @return static
+ */
+ public static function get()
+ {
+ $list = new static;
+
+ $widgets = StaticContainer::get('Piwik\Plugin\Widgets');
+
+ $widgetContainerConfigs = $widgets->getWidgetContainerConfigs();
+ foreach ($widgetContainerConfigs as $config) {
+ if ($config->isEnabled()) {
+ $list->addWidgetConfig($config);
+ }
+ }
+
+ $widgetConfigs = $widgets->getWidgetConfigs();
+ foreach ($widgetConfigs as $widget) {
+ if ($widget->isEnabled()) {
+ $list->addWidgetConfig($widget);
+ }
+ }
+
+ $reports = StaticContainer::get('Piwik\Plugin\Reports');
+ $reports = $reports->getAllReports();
+ foreach ($reports as $report) {
+ if ($report->isEnabled()) {
+ $factory = new ReportWidgetFactory($report);
+ $report->configureWidgets($list, $factory);
+ }
+ }
+
+ /**
+ * Triggered to filter widgets.
+ *
+ * **Example**
+ *
+ * public function addWidgetConfigs(Piwik\Widget\WidgetsList $list)
+ * {
+ * $list->remove($category='General_Visits'); // remove all widgets having this category
+ * }
+ *
+ * @param WidgetsList $list An instance of the WidgetsList. You can change the list of widgets this way.
+ */
+ Piwik::postEvent('Widget.filterWidgets', array($list));
+
+ return $list;
+ }
+
+ /**
+ * CAUTION! If you ever change this method, existing updates will fail as they currently use that method!
+ * If you change the output the uniqueId for existing widgets would not be found anymore
+ *
+ * Returns the unique id of an widget with the given parameters
+ *
+ * @param $controllerName
+ * @param $controllerAction
+ * @param array $customParameters
+ * @return string
+ */
+ public static function getWidgetUniqueId($controllerName, $controllerAction, $customParameters = array())
+ {
+ $widgetUniqueId = 'widget' . $controllerName . $controllerAction;
+
+ foreach ($customParameters as $name => $value) {
+ if (is_array($value)) {
+ // use 'Array' for backward compatibility;
+ // could we switch to using $value[0]?
+ $value = 'Array';
+ }
+ $widgetUniqueId .= $name . urlencode($value);
+ }
+
+ return $widgetUniqueId;
+ }
+
+}
diff --git a/core/WidgetsList.php b/core/WidgetsList.php
deleted file mode 100644
index 8380d7a1ee..0000000000
--- a/core/WidgetsList.php
+++ /dev/null
@@ -1,287 +0,0 @@
-<?php
-/**
- * Piwik - free/libre analytics platform
- *
- * @link http://piwik.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- *
- */
-namespace Piwik;
-
-use Piwik\Cache as PiwikCache;
-use Piwik\Plugin\Report;
-use Piwik\Plugin\Widgets;
-
-/**
- * Manages the global list of reports that can be displayed as dashboard widgets.
- *
- * Reports are added as dashboard widgets through the {@hook WidgetsList.addWidgets}
- * event. Observers for this event should call the {@link add()} method to add reports.
- *
- * @api
- * @method static \Piwik\WidgetsList getInstance()
- */
-class WidgetsList extends Singleton
-{
- /**
- * List of widgets
- *
- * @var array
- */
- protected static $widgets = array();
-
- /**
- * Indicates whether the hook was posted or not
- *
- * @var bool
- */
- protected static $hookCalled = false;
-
- /**
- * In get() we won't use a cached result in case this is true. Instead we will sort the widgets again and cache
- * a new result. To make tests work...
- * @var bool
- */
- private static $listCacheToBeInvalidated = false;
-
- /**
- * Returns all available widgets.
- *
- * @return array Array Mapping widget categories with an array of widget information, eg,
- * ```
- * array(
- * 'Visitors' => array(
- * array(...), // info about first widget in this category
- * array(...) // info about second widget in this category, etc.
- * ),
- * 'Visits' => array(
- * array(...),
- * array(...)
- * ),
- * )
- * ```
- */
- public static function get()
- {
- $cache = self::getCacheForCompleteList();
- $cacheId = self::getCacheId();
-
- if (!self::$listCacheToBeInvalidated && $cache->contains($cacheId)) {
- return $cache->fetch($cacheId);
- }
-
- self::addWidgets();
-
- uksort(self::$widgets, array('Piwik\WidgetsList', '_sortWidgetCategories'));
-
- $widgets = array();
- foreach (self::$widgets as $key => $v) {
- $category = Piwik::translate($key);
-
- if (isset($widgets[$category])) {
- $v = array_merge($widgets[$category], $v);
- }
-
- $widgets[$category] = $v;
- }
-
- $cache->save($cacheId, $widgets);
- self::$listCacheToBeInvalidated = false;
-
- return $widgets;
- }
-
- private static function addWidgets()
- {
- if (!self::$hookCalled) {
- self::$hookCalled = true;
-
- /**
- * @ignore
- * @deprecated
- */
- Piwik::postEvent('WidgetsList.addWidgets');
-
- $widgetsList = self::getInstance();
-
- foreach (Report::getAllReports() as $report) {
- if ($report->isEnabled()) {
- $report->configureWidget($widgetsList);
- }
- }
-
- $widgetContainers = Widgets::getAllWidgets();
- foreach ($widgetContainers as $widgetContainer) {
- $widgets = $widgetContainer->getWidgets();
-
- foreach ($widgets as $widget) {
- $widgetsList->add($widget['category'], $widget['name'], $widget['module'], $widget['method'], $widget['params']);
- }
- }
-
- foreach ($widgetContainers as $widgetContainer) {
- $widgetContainer->configureWidgetsList($widgetsList);
- }
- }
- }
-
- /**
- * Sorting method for widget categories
- *
- * @param string $a
- * @param string $b
- * @return bool
- */
- protected static function _sortWidgetCategories($a, $b)
- {
- $order = array(
- 'VisitsSummary_VisitsSummary',
- 'Live!',
- 'General_Visitors',
- 'General_VisitorSettings',
- 'DevicesDetection_DevicesDetection',
- 'General_Actions',
- 'Events_Events',
- 'Actions_SubmenuSitesearch',
- 'Referrers_Referrers',
- 'Goals_Goals',
- 'Goals_Ecommerce',
- '_others_',
- 'About Piwik',
- 'ExamplePlugin_exampleWidgets',
- );
-
- if (($oa = array_search($a, $order)) === false) {
- $oa = array_search('_others_', $order);
- }
- if (($ob = array_search($b, $order)) === false) {
- $ob = array_search('_others_', $order);
- }
- return $oa > $ob;
- }
-
- /**
- * Returns the unique id of an widget with the given parameters
- *
- * @param $controllerName
- * @param $controllerAction
- * @param array $customParameters
- * @return string
- */
- public static function getWidgetUniqueId($controllerName, $controllerAction, $customParameters = array())
- {
- $widgetUniqueId = 'widget' . $controllerName . $controllerAction;
-
- foreach ($customParameters as $name => $value) {
- if (is_array($value)) {
- // use 'Array' for backward compatibility;
- // could we switch to using $value[0]?
- $value = 'Array';
- }
- $widgetUniqueId .= $name . $value;
- }
-
- return $widgetUniqueId;
- }
-
- /**
- * Adds a report to the list of dashboard widgets.
- *
- * @param string $widgetCategory The widget category. This can be a translation token.
- * @param string $widgetName The name of the widget. This can be a translation token.
- * @param string $controllerName The report's controller name (same as the plugin name).
- * @param string $controllerAction The report's controller action method name.
- * @param array $customParameters Extra query parameters that should be sent while getting
- * this report.
- */
- public static function add($widgetCategory, $widgetName, $controllerName, $controllerAction, $customParameters = array())
- {
- $widgetName = Piwik::translate($widgetName);
- $widgetUniqueId = self::getWidgetUniqueId($controllerName, $controllerAction, $customParameters);
-
- if (!array_key_exists($widgetCategory, self::$widgets)) {
- self::$widgets[$widgetCategory] = array();
- }
-
- self::$listCacheToBeInvalidated = true;
- self::$widgets[$widgetCategory][] = array(
- 'name' => $widgetName,
- 'uniqueId' => $widgetUniqueId,
- 'parameters' => array('module' => $controllerName,
- 'action' => $controllerAction
- ) + $customParameters
- );
- }
-
- /**
- * Removes one or more widgets from the widget list.
- *
- * @param string $widgetCategory The widget category. Can be a translation token.
- * @param string|false $widgetName The name of the widget to remove. Cannot be a
- * translation token. If not supplied, the entire category
- * will be removed.
- */
- public static function remove($widgetCategory, $widgetName = false)
- {
- if (!isset(self::$widgets[$widgetCategory])) {
- return;
- }
-
- if (empty($widgetName)) {
- unset(self::$widgets[$widgetCategory]);
- self::$listCacheToBeInvalidated = true;
- return;
- }
- foreach (self::$widgets[$widgetCategory] as $id => $widget) {
- if ($widget['name'] == $widgetName || $widget['name'] == Piwik::translate($widgetName)) {
- unset(self::$widgets[$widgetCategory][$id]);
- self::$listCacheToBeInvalidated = true;
- return;
- }
- }
- }
-
- /**
- * Returns `true` if a report exists in the widget list, `false` if otherwise.
- *
- * @param string $controllerName The controller name of the report.
- * @param string $controllerAction The controller action of the report.
- * @return bool
- */
- public static function isDefined($controllerName, $controllerAction)
- {
- $widgetsList = self::get();
- foreach ($widgetsList as $widgets) {
- foreach ($widgets as $widget) {
- if ($widget['parameters']['module'] == $controllerName
- && $widget['parameters']['action'] == $controllerAction
- ) {
- return true;
- }
- }
- }
- return false;
- }
-
- /**
- * Method to reset the widget list
- * For testing only
- * @ignore
- */
- public static function _reset()
- {
- self::$widgets = array();
- self::$hookCalled = false;
- self::getCacheForCompleteList()->delete(self::getCacheId());
- }
-
- private static function getCacheId()
- {
- return CacheId::pluginAware('WidgetsList');
- }
-
- private static function getCacheForCompleteList()
- {
- return PiwikCache::getTransientCache();
- }
-}
diff --git a/core/testMinimumPhpVersion.php b/core/testMinimumPhpVersion.php
index 034c9d7e6b..19388d7bb1 100644
--- a/core/testMinimumPhpVersion.php
+++ b/core/testMinimumPhpVersion.php
@@ -19,7 +19,7 @@ $piwik_errorMessage = '';
// NOTE: when changing this variable, we also need to update
// 1) api.piwik.org
// 2) tests/travis/generator/Generator.php
-$piwik_minimumPHPVersion = '5.3.3';
+$piwik_minimumPHPVersion = '5.5.0';
$piwik_currentPHPVersion = PHP_VERSION;
$minimumPhpInvalid = version_compare($piwik_minimumPHPVersion, $piwik_currentPHPVersion) > 0;
if ($minimumPhpInvalid) {
diff --git a/lang/en.json b/lang/en.json
index 67e812bd9f..810c4bc81b 100644
--- a/lang/en.json
+++ b/lang/en.json
@@ -169,6 +169,7 @@
"ExceptionReportNotFound": "The requested report does not exist.",
"ExceptionWidgetNotFound": "The requested widget does not exist.",
"ExceptionReportNotEnabled": "The requested report is not enabled. This means usually either the plugin that defines the report is deactivated or you do not have enough permission to access this report.",
+ "ExceptionWidgetNotEnabled": "The requested widget is not enabled. This means usually either the plugin that defines the widget is deactivated or you do not have enough permission to access this widget.",
"ExpandDataTableFooter": "Change the visualization or configure the report",
"Export": "Export",
"ExportAsImage": "Export as Image",
@@ -503,4 +504,4 @@
"PickAnotherRow": "Pick another row to compare",
"PickARow": "Pick a row to compare"
}
-} \ No newline at end of file
+}
diff --git a/libs/bower_components/angular-animate/.bower.json b/libs/bower_components/angular-animate/.bower.json
index 7a01c31da9..39c2c06f6e 100644
--- a/libs/bower_components/angular-animate/.bower.json
+++ b/libs/bower_components/angular-animate/.bower.json
@@ -1,19 +1,19 @@
{
"name": "angular-animate",
- "version": "1.2.28",
+ "version": "1.4.3",
"main": "./angular-animate.js",
"ignore": [],
"dependencies": {
- "angular": "1.2.28"
+ "angular": "1.4.3"
},
"homepage": "https://github.com/angular/bower-angular-animate",
- "_release": "1.2.28",
+ "_release": "1.4.3",
"_resolution": {
"type": "version",
- "tag": "v1.2.28",
- "commit": "a42cca9915517f26d639471b5f622dc086161fe0"
+ "tag": "v1.4.3",
+ "commit": "4ce2a76359401102d2e0146ccf69e6c060799ff8"
},
"_source": "git://github.com/angular/bower-angular-animate.git",
- "_target": "~1.2.0",
+ "_target": "~1.4.0",
"_originalSource": "angular-animate"
} \ No newline at end of file
diff --git a/libs/bower_components/angular-animate/README.md b/libs/bower_components/angular-animate/README.md
index 930b5dcc59..8313da67c3 100644
--- a/libs/bower_components/angular-animate/README.md
+++ b/libs/bower_components/angular-animate/README.md
@@ -14,21 +14,12 @@ You can install this package either with `npm` or with `bower`.
npm install angular-animate
```
-Add a `<script>` to your `index.html`:
-
-```html
-<script src="/node_modules/angular-animate/angular-animate.js"></script>
-```
-
Then add `ngAnimate` as a dependency for your app:
```javascript
-angular.module('myApp', ['ngAnimate']);
+angular.module('myApp', [require('angular-animate')]);
```
-Note that this package is not in CommonJS format, so doing `require('angular-animate')` will
-return `undefined`.
-
### bower
```shell
@@ -56,7 +47,7 @@ Documentation is available on the
The MIT License
-Copyright (c) 2010-2012 Google, Inc. http://angularjs.org
+Copyright (c) 2010-2015 Google, Inc. http://angularjs.org
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/libs/bower_components/angular-animate/angular-animate.js b/libs/bower_components/angular-animate/angular-animate.js
index f602fccf9f..fc0e217f7e 100644
--- a/libs/bower_components/angular-animate/angular-animate.js
+++ b/libs/bower_components/angular-animate/angular-animate.js
@@ -1,1702 +1,3721 @@
/**
- * @license AngularJS v1.2.28
- * (c) 2010-2014 Google, Inc. http://angularjs.org
+ * @license AngularJS v1.4.3
+ * (c) 2010-2015 Google, Inc. http://angularjs.org
* License: MIT
*/
(function(window, angular, undefined) {'use strict';
-/* jshint maxlen: false */
+/* jshint ignore:start */
+var noop = angular.noop;
+var extend = angular.extend;
+var jqLite = angular.element;
+var forEach = angular.forEach;
+var isArray = angular.isArray;
+var isString = angular.isString;
+var isObject = angular.isObject;
+var isUndefined = angular.isUndefined;
+var isDefined = angular.isDefined;
+var isFunction = angular.isFunction;
+var isElement = angular.isElement;
+
+var ELEMENT_NODE = 1;
+var COMMENT_NODE = 8;
+
+var NG_ANIMATE_CLASSNAME = 'ng-animate';
+var NG_ANIMATE_CHILDREN_DATA = '$$ngAnimateChildren';
+
+var isPromiseLike = function(p) {
+ return p && p.then ? true : false;
+}
+
+function assertArg(arg, name, reason) {
+ if (!arg) {
+ throw ngMinErr('areq', "Argument '{0}' is {1}", (name || '?'), (reason || "required"));
+ }
+ return arg;
+}
+
+function mergeClasses(a,b) {
+ if (!a && !b) return '';
+ if (!a) return b;
+ if (!b) return a;
+ if (isArray(a)) a = a.join(' ');
+ if (isArray(b)) b = b.join(' ');
+ return a + ' ' + b;
+}
+
+function packageStyles(options) {
+ var styles = {};
+ if (options && (options.to || options.from)) {
+ styles.to = options.to;
+ styles.from = options.from;
+ }
+ return styles;
+}
+
+function pendClasses(classes, fix, isPrefix) {
+ var className = '';
+ classes = isArray(classes)
+ ? classes
+ : classes && isString(classes) && classes.length
+ ? classes.split(/\s+/)
+ : [];
+ forEach(classes, function(klass, i) {
+ if (klass && klass.length > 0) {
+ className += (i > 0) ? ' ' : '';
+ className += isPrefix ? fix + klass
+ : klass + fix;
+ }
+ });
+ return className;
+}
+
+function removeFromArray(arr, val) {
+ var index = arr.indexOf(val);
+ if (val >= 0) {
+ arr.splice(index, 1);
+ }
+}
+
+function stripCommentsFromElement(element) {
+ if (element instanceof jqLite) {
+ switch (element.length) {
+ case 0:
+ return [];
+ break;
+
+ case 1:
+ // there is no point of stripping anything if the element
+ // is the only element within the jqLite wrapper.
+ // (it's important that we retain the element instance.)
+ if (element[0].nodeType === ELEMENT_NODE) {
+ return element;
+ }
+ break;
+
+ default:
+ return jqLite(extractElementNode(element));
+ break;
+ }
+ }
+
+ if (element.nodeType === ELEMENT_NODE) {
+ return jqLite(element);
+ }
+}
+
+function extractElementNode(element) {
+ if (!element[0]) return element;
+ for (var i = 0; i < element.length; i++) {
+ var elm = element[i];
+ if (elm.nodeType == ELEMENT_NODE) {
+ return elm;
+ }
+ }
+}
+
+function $$addClass($$jqLite, element, className) {
+ forEach(element, function(elm) {
+ $$jqLite.addClass(elm, className);
+ });
+}
+
+function $$removeClass($$jqLite, element, className) {
+ forEach(element, function(elm) {
+ $$jqLite.removeClass(elm, className);
+ });
+}
+
+function applyAnimationClassesFactory($$jqLite) {
+ return function(element, options) {
+ if (options.addClass) {
+ $$addClass($$jqLite, element, options.addClass);
+ options.addClass = null;
+ }
+ if (options.removeClass) {
+ $$removeClass($$jqLite, element, options.removeClass);
+ options.removeClass = null;
+ }
+ }
+}
+
+function prepareAnimationOptions(options) {
+ options = options || {};
+ if (!options.$$prepared) {
+ var domOperation = options.domOperation || noop;
+ options.domOperation = function() {
+ options.$$domOperationFired = true;
+ domOperation();
+ domOperation = noop;
+ };
+ options.$$prepared = true;
+ }
+ return options;
+}
+
+function applyAnimationStyles(element, options) {
+ applyAnimationFromStyles(element, options);
+ applyAnimationToStyles(element, options);
+}
+
+function applyAnimationFromStyles(element, options) {
+ if (options.from) {
+ element.css(options.from);
+ options.from = null;
+ }
+}
+
+function applyAnimationToStyles(element, options) {
+ if (options.to) {
+ element.css(options.to);
+ options.to = null;
+ }
+}
+
+function mergeAnimationOptions(element, target, newOptions) {
+ var toAdd = (target.addClass || '') + ' ' + (newOptions.addClass || '');
+ var toRemove = (target.removeClass || '') + ' ' + (newOptions.removeClass || '');
+ var classes = resolveElementClasses(element.attr('class'), toAdd, toRemove);
+
+ extend(target, newOptions);
+
+ if (classes.addClass) {
+ target.addClass = classes.addClass;
+ } else {
+ target.addClass = null;
+ }
+
+ if (classes.removeClass) {
+ target.removeClass = classes.removeClass;
+ } else {
+ target.removeClass = null;
+ }
+
+ return target;
+}
+
+function resolveElementClasses(existing, toAdd, toRemove) {
+ var ADD_CLASS = 1;
+ var REMOVE_CLASS = -1;
+
+ var flags = {};
+ existing = splitClassesToLookup(existing);
+
+ toAdd = splitClassesToLookup(toAdd);
+ forEach(toAdd, function(value, key) {
+ flags[key] = ADD_CLASS;
+ });
+
+ toRemove = splitClassesToLookup(toRemove);
+ forEach(toRemove, function(value, key) {
+ flags[key] = flags[key] === ADD_CLASS ? null : REMOVE_CLASS;
+ });
+
+ var classes = {
+ addClass: '',
+ removeClass: ''
+ };
+
+ forEach(flags, function(val, klass) {
+ var prop, allow;
+ if (val === ADD_CLASS) {
+ prop = 'addClass';
+ allow = !existing[klass];
+ } else if (val === REMOVE_CLASS) {
+ prop = 'removeClass';
+ allow = existing[klass];
+ }
+ if (allow) {
+ if (classes[prop].length) {
+ classes[prop] += ' ';
+ }
+ classes[prop] += klass;
+ }
+ });
+
+ function splitClassesToLookup(classes) {
+ if (isString(classes)) {
+ classes = classes.split(' ');
+ }
+
+ var obj = {};
+ forEach(classes, function(klass) {
+ // sometimes the split leaves empty string values
+ // incase extra spaces were applied to the options
+ if (klass.length) {
+ obj[klass] = true;
+ }
+ });
+ return obj;
+ }
+
+ return classes;
+}
+
+function getDomNode(element) {
+ return (element instanceof angular.element) ? element[0] : element;
+}
+
+var $$rAFSchedulerFactory = ['$$rAF', function($$rAF) {
+ var tickQueue = [];
+ var cancelFn;
+
+ function scheduler(tasks) {
+ // we make a copy since RAFScheduler mutates the state
+ // of the passed in array variable and this would be difficult
+ // to track down on the outside code
+ tickQueue.push([].concat(tasks));
+ nextTick();
+ }
+
+ /* waitUntilQuiet does two things:
+ * 1. It will run the FINAL `fn` value only when an uncancelled RAF has passed through
+ * 2. It will delay the next wave of tasks from running until the quiet `fn` has run.
+ *
+ * The motivation here is that animation code can request more time from the scheduler
+ * before the next wave runs. This allows for certain DOM properties such as classes to
+ * be resolved in time for the next animation to run.
+ */
+ scheduler.waitUntilQuiet = function(fn) {
+ if (cancelFn) cancelFn();
+
+ cancelFn = $$rAF(function() {
+ cancelFn = null;
+ fn();
+ nextTick();
+ });
+ };
+
+ return scheduler;
+
+ function nextTick() {
+ if (!tickQueue.length) return;
+
+ var updatedQueue = [];
+ for (var i = 0; i < tickQueue.length; i++) {
+ var innerQueue = tickQueue[i];
+ runNextTask(innerQueue);
+ if (innerQueue.length) {
+ updatedQueue.push(innerQueue);
+ }
+ }
+ tickQueue = updatedQueue;
+
+ if (!cancelFn) {
+ $$rAF(function() {
+ if (!cancelFn) nextTick();
+ });
+ }
+ }
+
+ function runNextTask(tasks) {
+ var nextTask = tasks.shift();
+ nextTask();
+ }
+}];
+
+var $$AnimateChildrenDirective = [function() {
+ return function(scope, element, attrs) {
+ var val = attrs.ngAnimateChildren;
+ if (angular.isString(val) && val.length === 0) { //empty attribute
+ element.data(NG_ANIMATE_CHILDREN_DATA, true);
+ } else {
+ attrs.$observe('ngAnimateChildren', function(value) {
+ value = value === 'on' || value === 'true';
+ element.data(NG_ANIMATE_CHILDREN_DATA, value);
+ });
+ }
+ };
+}];
/**
- * @ngdoc module
- * @name ngAnimate
- * @description
- *
- * # ngAnimate
- *
- * The `ngAnimate` module provides support for JavaScript, CSS3 transition and CSS3 keyframe animation hooks within existing core and custom directives.
- *
- *
- * <div doc-module-components="ngAnimate"></div>
+ * @ngdoc service
+ * @name $animateCss
+ * @kind object
*
- * # Usage
- *
- * To see animations in action, all that is required is to define the appropriate CSS classes
- * or to register a JavaScript animation via the myModule.animation() function. The directives that support animation automatically are:
- * `ngRepeat`, `ngInclude`, `ngIf`, `ngSwitch`, `ngShow`, `ngHide`, `ngView` and `ngClass`. Custom directives can take advantage of animation
- * by using the `$animate` service.
- *
- * Below is a more detailed breakdown of the supported animation events provided by pre-existing ng directives:
+ * @description
+ * The `$animateCss` service is a useful utility to trigger customized CSS-based transitions/keyframes
+ * from a JavaScript-based animation or directly from a directive. The purpose of `$animateCss` is NOT
+ * to side-step how `$animate` and ngAnimate work, but the goal is to allow pre-existing animations or
+ * directives to create more complex animations that can be purely driven using CSS code.
*
- * | Directive | Supported Animations |
- * |---------------------------------------------------------- |----------------------------------------------------|
- * | {@link ng.directive:ngRepeat#usage_animations ngRepeat} | enter, leave and move |
- * | {@link ngRoute.directive:ngView#usage_animations ngView} | enter and leave |
- * | {@link ng.directive:ngInclude#usage_animations ngInclude} | enter and leave |
- * | {@link ng.directive:ngSwitch#usage_animations ngSwitch} | enter and leave |
- * | {@link ng.directive:ngIf#usage_animations ngIf} | enter and leave |
- * | {@link ng.directive:ngClass#usage_animations ngClass} | add and remove |
- * | {@link ng.directive:ngShow#usage_animations ngShow & ngHide} | add and remove (the ng-hide class value) |
- * | {@link ng.directive:form#usage_animations form} | add and remove (dirty, pristine, valid, invalid & all other validations) |
- * | {@link ng.directive:ngModel#usage_animations ngModel} | add and remove (dirty, pristine, valid, invalid & all other validations) |
+ * Note that only browsers that support CSS transitions and/or keyframe animations are capable of
+ * rendering animations triggered via `$animateCss` (bad news for IE9 and lower).
*
- * You can find out more information about animations upon visiting each directive page.
+ * ## Usage
+ * Once again, `$animateCss` is designed to be used inside of a registered JavaScript animation that
+ * is powered by ngAnimate. It is possible to use `$animateCss` directly inside of a directive, however,
+ * any automatic control over cancelling animations and/or preventing animations from being run on
+ * child elements will not be handled by Angular. For this to work as expected, please use `$animate` to
+ * trigger the animation and then setup a JavaScript animation that injects `$animateCss` to trigger
+ * the CSS animation.
*
- * Below is an example of how to apply animations to a directive that supports animation hooks:
+ * The example below shows how we can create a folding animation on an element using `ng-if`:
*
* ```html
- * <style type="text/css">
- * .slide.ng-enter, .slide.ng-leave {
- * -webkit-transition:0.5s linear all;
- * transition:0.5s linear all;
- * }
- *
- * .slide.ng-enter { } /&#42; starting animations for enter &#42;/
- * .slide.ng-enter.ng-enter-active { } /&#42; terminal animations for enter &#42;/
- * .slide.ng-leave { } /&#42; starting animations for leave &#42;/
- * .slide.ng-leave.ng-leave-active { } /&#42; terminal animations for leave &#42;/
- * </style>
- *
- * <!--
- * the animate service will automatically add .ng-enter and .ng-leave to the element
- * to trigger the CSS transition/animations
- * -->
- * <ANY class="slide" ng-include="..."></ANY>
+ * <!-- notice the `fold-animation` CSS class -->
+ * <div ng-if="onOff" class="fold-animation">
+ * This element will go BOOM
+ * </div>
+ * <button ng-click="onOff=true">Fold In</button>
* ```
*
- * Keep in mind that, by default, if an animation is running, any child elements cannot be animated
- * until the parent element's animation has completed. This blocking feature can be overridden by
- * placing the `ng-animate-children` attribute on a parent container tag.
+ * Now we create the **JavaScript animation** that will trigger the CSS transition:
*
- * ```html
- * <div class="slide-animation" ng-if="on" ng-animate-children>
- * <div class="fade-animation" ng-if="on">
- * <div class="explode-animation" ng-if="on">
- * ...
- * </div>
- * </div>
- * </div>
+ * ```js
+ * ngModule.animation('.fold-animation', ['$animateCss', function($animateCss) {
+ * return {
+ * enter: function(element, doneFn) {
+ * var height = element[0].offsetHeight;
+ * return $animateCss(element, {
+ * from: { height:'0px' },
+ * to: { height:height + 'px' },
+ * duration: 1 // one second
+ * });
+ * }
+ * }
+ * }]);
* ```
*
- * When the `on` expression value changes and an animation is triggered then each of the elements within
- * will all animate without the block being applied to child elements.
+ * ## More Advanced Uses
*
- * <h2>CSS-defined Animations</h2>
- * The animate service will automatically apply two CSS classes to the animated element and these two CSS classes
- * are designed to contain the start and end CSS styling. Both CSS transitions and keyframe animations are supported
- * and can be used to play along with this naming structure.
+ * `$animateCss` is the underlying code that ngAnimate uses to power **CSS-based animations** behind the scenes. Therefore CSS hooks
+ * like `.ng-EVENT`, `.ng-EVENT-active`, `.ng-EVENT-stagger` are all features that can be triggered using `$animateCss` via JavaScript code.
*
- * The following code below demonstrates how to perform animations using **CSS transitions** with Angular:
- *
- * ```html
- * <style type="text/css">
- * /&#42;
- * The animate class is apart of the element and the ng-enter class
- * is attached to the element once the enter animation event is triggered
- * &#42;/
- * .reveal-animation.ng-enter {
- * -webkit-transition: 1s linear all; /&#42; Safari/Chrome &#42;/
- * transition: 1s linear all; /&#42; All other modern browsers and IE10+ &#42;/
- *
- * /&#42; The animation preparation code &#42;/
- * opacity: 0;
- * }
+ * This also means that just about any combination of adding classes, removing classes, setting styles, dynamically setting a keyframe animation,
+ * applying a hardcoded duration or delay value, changing the animation easing or applying a stagger animation are all options that work with
+ * `$animateCss`. The service itself is smart enough to figure out the combination of options and examine the element styling properties in order
+ * to provide a working animation that will run in CSS.
*
- * /&#42;
- * Keep in mind that you want to combine both CSS
- * classes together to avoid any CSS-specificity
- * conflicts
- * &#42;/
- * .reveal-animation.ng-enter.ng-enter-active {
- * /&#42; The animation code itself &#42;/
- * opacity: 1;
- * }
- * </style>
+ * The example below showcases a more advanced version of the `.fold-animation` from the example above:
*
- * <div class="view-container">
- * <div ng-view class="reveal-animation"></div>
- * </div>
+ * ```js
+ * ngModule.animation('.fold-animation', ['$animateCss', function($animateCss) {
+ * return {
+ * enter: function(element, doneFn) {
+ * var height = element[0].offsetHeight;
+ * return $animateCss(element, {
+ * addClass: 'red large-text pulse-twice',
+ * easing: 'ease-out',
+ * from: { height:'0px' },
+ * to: { height:height + 'px' },
+ * duration: 1 // one second
+ * });
+ * }
+ * }
+ * }]);
* ```
*
- * The following code below demonstrates how to perform animations using **CSS animations** with Angular:
+ * Since we're adding/removing CSS classes then the CSS transition will also pick those up:
*
- * ```html
- * <style type="text/css">
- * .reveal-animation.ng-enter {
- * -webkit-animation: enter_sequence 1s linear; /&#42; Safari/Chrome &#42;/
- * animation: enter_sequence 1s linear; /&#42; IE10+ and Future Browsers &#42;/
- * }
- * @-webkit-keyframes enter_sequence {
- * from { opacity:0; }
- * to { opacity:1; }
+ * ```css
+ * /&#42; since a hardcoded duration value of 1 was provided in the JavaScript animation code,
+ * the CSS classes below will be transitioned despite them being defined as regular CSS classes &#42;/
+ * .red { background:red; }
+ * .large-text { font-size:20px; }
+ *
+ * /&#42; we can also use a keyframe animation and $animateCss will make it work alongside the transition &#42;/
+ * .pulse-twice {
+ * animation: 0.5s pulse linear 2;
+ * -webkit-animation: 0.5s pulse linear 2;
* }
- * @keyframes enter_sequence {
- * from { opacity:0; }
- * to { opacity:1; }
+ *
+ * @keyframes pulse {
+ * from { transform: scale(0.5); }
+ * to { transform: scale(1.5); }
* }
- * </style>
*
- * <div class="view-container">
- * <div ng-view class="reveal-animation"></div>
- * </div>
+ * @-webkit-keyframes pulse {
+ * from { -webkit-transform: scale(0.5); }
+ * to { -webkit-transform: scale(1.5); }
+ * }
* ```
*
- * Both CSS3 animations and transitions can be used together and the animate service will figure out the correct duration and delay timing.
+ * Given this complex combination of CSS classes, styles and options, `$animateCss` will figure everything out and make the animation happen.
*
- * Upon DOM mutation, the event class is added first (something like `ng-enter`), then the browser prepares itself to add
- * the active class (in this case `ng-enter-active`) which then triggers the animation. The animation module will automatically
- * detect the CSS code to determine when the animation ends. Once the animation is over then both CSS classes will be
- * removed from the DOM. If a browser does not support CSS transitions or CSS animations then the animation will start and end
- * immediately resulting in a DOM element that is at its final state. This final state is when the DOM element
- * has no CSS transition/animation classes applied to it.
+ * ## How the Options are handled
*
- * <h3>CSS Staggering Animations</h3>
- * A Staggering animation is a collection of animations that are issued with a slight delay in between each successive operation resulting in a
- * curtain-like effect. The ngAnimate module, as of 1.2.0, supports staggering animations and the stagger effect can be
- * performed by creating a **ng-EVENT-stagger** CSS class and attaching that class to the base CSS class used for
- * the animation. The style property expected within the stagger class can either be a **transition-delay** or an
- * **animation-delay** property (or both if your animation contains both transitions and keyframe animations).
+ * `$animateCss` is very versatile and intelligent when it comes to figuring out what configurations to apply to the element to ensure the animation
+ * works with the options provided. Say for example we were adding a class that contained a keyframe value and we wanted to also animate some inline
+ * styles using the `from` and `to` properties.
+ *
+ * ```js
+ * var animator = $animateCss(element, {
+ * from: { background:'red' },
+ * to: { background:'blue' }
+ * });
+ * animator.start();
+ * ```
*
* ```css
- * .my-animation.ng-enter {
- * /&#42; standard transition code &#42;/
- * -webkit-transition: 1s linear all;
- * transition: 1s linear all;
- * opacity:0;
+ * .rotating-animation {
+ * animation:0.5s rotate linear;
+ * -webkit-animation:0.5s rotate linear;
* }
- * .my-animation.ng-enter-stagger {
- * /&#42; this will have a 100ms delay between each successive leave animation &#42;/
- * -webkit-transition-delay: 0.1s;
- * transition-delay: 0.1s;
*
- * /&#42; in case the stagger doesn't work then these two values
- * must be set to 0 to avoid an accidental CSS inheritance &#42;/
- * -webkit-transition-duration: 0s;
- * transition-duration: 0s;
+ * @keyframes rotate {
+ * from { transform: rotate(0deg); }
+ * to { transform: rotate(360deg); }
* }
- * .my-animation.ng-enter.ng-enter-active {
- * /&#42; standard transition styles &#42;/
- * opacity:1;
+ *
+ * @-webkit-keyframes rotate {
+ * from { -webkit-transform: rotate(0deg); }
+ * to { -webkit-transform: rotate(360deg); }
* }
* ```
*
- * Staggering animations work by default in ngRepeat (so long as the CSS class is defined). Outside of ngRepeat, to use staggering animations
- * on your own, they can be triggered by firing multiple calls to the same event on $animate. However, the restrictions surrounding this
- * are that each of the elements must have the same CSS className value as well as the same parent element. A stagger operation
- * will also be reset if more than 10ms has passed after the last animation has been fired.
- *
- * The following code will issue the **ng-leave-stagger** event on the element provided:
+ * The missing pieces here are that we do not have a transition set (within the CSS code nor within the `$animateCss` options) and the duration of the animation is
+ * going to be detected from what the keyframe styles on the CSS class are. In this event, `$animateCss` will automatically create an inline transition
+ * style matching the duration detected from the keyframe style (which is present in the CSS class that is being added) and then prepare both the transition
+ * and keyframe animations to run in parallel on the element. Then when the animation is underway the provided `from` and `to` CSS styles will be applied
+ * and spread across the transition and keyframe animation.
*
- * ```js
- * var kids = parent.children();
+ * ## What is returned
*
- * $animate.leave(kids[0]); //stagger index=0
- * $animate.leave(kids[1]); //stagger index=1
- * $animate.leave(kids[2]); //stagger index=2
- * $animate.leave(kids[3]); //stagger index=3
- * $animate.leave(kids[4]); //stagger index=4
+ * `$animateCss` works in two stages: a preparation phase and an animation phase. Therefore when `$animateCss` is first called it will NOT actually
+ * start the animation. All that is going on here is that the element is being prepared for the animation (which means that the generated CSS classes are
+ * added and removed on the element). Once `$animateCss` is called it will return an object with the following properties:
*
- * $timeout(function() {
- * //stagger has reset itself
- * $animate.leave(kids[5]); //stagger index=0
- * $animate.leave(kids[6]); //stagger index=1
- * }, 100, false);
+ * ```js
+ * var animator = $animateCss(element, { ... });
* ```
*
- * Stagger animations are currently only supported within CSS-defined animations.
- *
- * <h2>JavaScript-defined Animations</h2>
- * In the event that you do not want to use CSS3 transitions or CSS3 animations or if you wish to offer animations on browsers that do not
- * yet support CSS transitions/animations, then you can make use of JavaScript animations defined inside of your AngularJS module.
+ * Now what do the contents of our `animator` variable look like:
*
* ```js
- * //!annotate="YourApp" Your AngularJS Module|Replace this or ngModule with the module that you used to define your application.
- * var ngModule = angular.module('YourApp', ['ngAnimate']);
- * ngModule.animation('.my-crazy-animation', function() {
- * return {
- * enter: function(element, done) {
- * //run the animation here and call done when the animation is complete
- * return function(cancelled) {
- * //this (optional) function will be called when the animation
- * //completes or when the animation is cancelled (the cancelled
- * //flag will be set to true if cancelled).
- * };
- * },
- * leave: function(element, done) { },
- * move: function(element, done) { },
+ * {
+ * // starts the animation
+ * start: Function,
+ *
+ * // ends (aborts) the animation
+ * end: Function
+ * }
+ * ```
*
- * //animation that can be triggered before the class is added
- * beforeAddClass: function(element, className, done) { },
+ * To actually start the animation we need to run `animation.start()` which will then return a promise that we can hook into to detect when the animation ends.
+ * If we choose not to run the animation then we MUST run `animation.end()` to perform a cleanup on the element (since some CSS classes and stlyes may have been
+ * applied to the element during the preparation phase). Note that all other properties such as duration, delay, transitions and keyframes are just properties
+ * and that changing them will not reconfigure the parameters of the animation.
*
- * //animation that can be triggered after the class is added
- * addClass: function(element, className, done) { },
+ * ### runner.done() vs runner.then()
+ * It is documented that `animation.start()` will return a promise object and this is true, however, there is also an additional method available on the
+ * runner called `.done(callbackFn)`. The done method works the same as `.finally(callbackFn)`, however, it does **not trigger a digest to occur**.
+ * Therefore, for performance reasons, it's always best to use `runner.done(callback)` instead of `runner.then()`, `runner.catch()` or `runner.finally()`
+ * unless you really need a digest to kick off afterwards.
*
- * //animation that can be triggered before the class is removed
- * beforeRemoveClass: function(element, className, done) { },
+ * Keep in mind that, to make this easier, ngAnimate has tweaked the JS animations API to recognize when a runner instance is returned from $animateCss
+ * (so there is no need to call `runner.done(doneFn)` inside of your JavaScript animation code).
+ * Check the {@link ngAnimate.$animateCss#usage animation code above} to see how this works.
*
- * //animation that can be triggered after the class is removed
- * removeClass: function(element, className, done) { }
- * };
- * });
- * ```
+ * @param {DOMElement} element the element that will be animated
+ * @param {object} options the animation-related options that will be applied during the animation
*
- * JavaScript-defined animations are created with a CSS-like class selector and a collection of events which are set to run
- * a javascript callback function. When an animation is triggered, $animate will look for a matching animation which fits
- * the element's CSS class attribute value and then run the matching animation event function (if found).
- * In other words, if the CSS classes present on the animated element match any of the JavaScript animations then the callback function will
- * be executed. It should be also noted that only simple, single class selectors are allowed (compound class selectors are not supported).
+ * * `event` - The DOM event (e.g. enter, leave, move). When used, a generated CSS class of `ng-EVENT` and `ng-EVENT-active` will be applied
+ * to the element during the animation. Multiple events can be provided when spaces are used as a separator. (Note that this will not perform any DOM operation.)
+ * * `easing` - The CSS easing value that will be applied to the transition or keyframe animation (or both).
+ * * `transition` - The raw CSS transition style that will be used (e.g. `1s linear all`).
+ * * `keyframeStyle` - The raw CSS keyframe animation style that will be used (e.g. `1s my_animation linear`).
+ * * `from` - The starting CSS styles (a key/value object) that will be applied at the start of the animation.
+ * * `to` - The ending CSS styles (a key/value object) that will be applied across the animation via a CSS transition.
+ * * `addClass` - A space separated list of CSS classes that will be added to the element and spread across the animation.
+ * * `removeClass` - A space separated list of CSS classes that will be removed from the element and spread across the animation.
+ * * `duration` - A number value representing the total duration of the transition and/or keyframe (note that a value of 1 is 1000ms). If a value of `0`
+ * is provided then the animation will be skipped entirely.
+ * * `delay` - A number value representing the total delay of the transition and/or keyframe (note that a value of 1 is 1000ms). If a value of `true` is
+ * used then whatever delay value is detected from the CSS classes will be mirrored on the elements styles (e.g. by setting delay true then the style value
+ * of the element will be `transition-delay: DETECTED_VALUE`). Using `true` is useful when you want the CSS classes and inline styles to all share the same
+ * CSS delay value.
+ * * `stagger` - A numeric time value representing the delay between successively animated elements
+ * ({@link ngAnimate#css-staggering-animations Click here to learn how CSS-based staggering works in ngAnimate.})
+ * * `staggerIndex` - The numeric index representing the stagger item (e.g. a value of 5 is equal to the sixth item in the stagger; therefore when a
+ * `stagger` option value of `0.1` is used then there will be a stagger delay of `600ms`)
+ * `applyClassesEarly` - Whether or not the classes being added or removed will be used when detecting the animation. This is set by `$animate` when enter/leave/move animations are fired to ensure that the CSS classes are resolved in time. (Note that this will prevent any transitions from occuring on the classes being added and removed.)
*
- * Within a JavaScript animation, an object containing various event callback animation functions is expected to be returned.
- * As explained above, these callbacks are triggered based on the animation event. Therefore if an enter animation is run,
- * and the JavaScript animation is found, then the enter callback will handle that animation (in addition to the CSS keyframe animation
- * or transition code that is defined via a stylesheet).
+ * @return {object} an object with start and end methods and details about the animation.
*
+ * * `start` - The method to start the animation. This will return a `Promise` when called.
+ * * `end` - This method will cancel the animation and remove all applied CSS classes and styles.
*/
-angular.module('ngAnimate', ['ng'])
+// Detect proper transitionend/animationend event names.
+var CSS_PREFIX = '', TRANSITION_PROP, TRANSITIONEND_EVENT, ANIMATION_PROP, ANIMATIONEND_EVENT;
+
+// If unprefixed events are not supported but webkit-prefixed are, use the latter.
+// Otherwise, just use W3C names, browsers not supporting them at all will just ignore them.
+// Note: Chrome implements `window.onwebkitanimationend` and doesn't implement `window.onanimationend`
+// but at the same time dispatches the `animationend` event and not `webkitAnimationEnd`.
+// Register both events in case `window.onanimationend` is not supported because of that,
+// do the same for `transitionend` as Safari is likely to exhibit similar behavior.
+// Also, the only modern browser that uses vendor prefixes for transitions/keyframes is webkit
+// therefore there is no reason to test anymore for other vendor prefixes:
+// http://caniuse.com/#search=transition
+if (window.ontransitionend === undefined && window.onwebkittransitionend !== undefined) {
+ CSS_PREFIX = '-webkit-';
+ TRANSITION_PROP = 'WebkitTransition';
+ TRANSITIONEND_EVENT = 'webkitTransitionEnd transitionend';
+} else {
+ TRANSITION_PROP = 'transition';
+ TRANSITIONEND_EVENT = 'transitionend';
+}
+
+if (window.onanimationend === undefined && window.onwebkitanimationend !== undefined) {
+ CSS_PREFIX = '-webkit-';
+ ANIMATION_PROP = 'WebkitAnimation';
+ ANIMATIONEND_EVENT = 'webkitAnimationEnd animationend';
+} else {
+ ANIMATION_PROP = 'animation';
+ ANIMATIONEND_EVENT = 'animationend';
+}
+
+var DURATION_KEY = 'Duration';
+var PROPERTY_KEY = 'Property';
+var DELAY_KEY = 'Delay';
+var TIMING_KEY = 'TimingFunction';
+var ANIMATION_ITERATION_COUNT_KEY = 'IterationCount';
+var ANIMATION_PLAYSTATE_KEY = 'PlayState';
+var ELAPSED_TIME_MAX_DECIMAL_PLACES = 3;
+var CLOSING_TIME_BUFFER = 1.5;
+var ONE_SECOND = 1000;
+var BASE_TEN = 10;
+
+var SAFE_FAST_FORWARD_DURATION_VALUE = 9999;
+
+var ANIMATION_DELAY_PROP = ANIMATION_PROP + DELAY_KEY;
+var ANIMATION_DURATION_PROP = ANIMATION_PROP + DURATION_KEY;
+
+var TRANSITION_DELAY_PROP = TRANSITION_PROP + DELAY_KEY;
+var TRANSITION_DURATION_PROP = TRANSITION_PROP + DURATION_KEY;
+
+var DETECT_CSS_PROPERTIES = {
+ transitionDuration: TRANSITION_DURATION_PROP,
+ transitionDelay: TRANSITION_DELAY_PROP,
+ transitionProperty: TRANSITION_PROP + PROPERTY_KEY,
+ animationDuration: ANIMATION_DURATION_PROP,
+ animationDelay: ANIMATION_DELAY_PROP,
+ animationIterationCount: ANIMATION_PROP + ANIMATION_ITERATION_COUNT_KEY
+};
+
+var DETECT_STAGGER_CSS_PROPERTIES = {
+ transitionDuration: TRANSITION_DURATION_PROP,
+ transitionDelay: TRANSITION_DELAY_PROP,
+ animationDuration: ANIMATION_DURATION_PROP,
+ animationDelay: ANIMATION_DELAY_PROP
+};
+
+function computeCssStyles($window, element, properties) {
+ var styles = Object.create(null);
+ var detectedStyles = $window.getComputedStyle(element) || {};
+ forEach(properties, function(formalStyleName, actualStyleName) {
+ var val = detectedStyles[formalStyleName];
+ if (val) {
+ var c = val.charAt(0);
+
+ // only numerical-based values have a negative sign or digit as the first value
+ if (c === '-' || c === '+' || c >= 0) {
+ val = parseMaxTime(val);
+ }
- /**
- * @ngdoc provider
- * @name $animateProvider
- * @description
- *
- * The `$animateProvider` allows developers to register JavaScript animation event handlers directly inside of a module.
- * When an animation is triggered, the $animate service will query the $animate service to find any animations that match
- * the provided name value.
- *
- * Requires the {@link ngAnimate `ngAnimate`} module to be installed.
- *
- * Please visit the {@link ngAnimate `ngAnimate`} module overview page learn more about how to use animations in your application.
- *
- */
- .directive('ngAnimateChildren', function() {
- var NG_ANIMATE_CHILDREN = '$$ngAnimateChildren';
- return function(scope, element, attrs) {
- var val = attrs.ngAnimateChildren;
- if(angular.isString(val) && val.length === 0) { //empty attribute
- element.data(NG_ANIMATE_CHILDREN, true);
+ // by setting this to null in the event that the delay is not set or is set directly as 0
+ // then we can still allow for zegative values to be used later on and not mistake this
+ // value for being greater than any other negative value.
+ if (val === 0) {
+ val = null;
+ }
+ styles[actualStyleName] = val;
+ }
+ });
+
+ return styles;
+}
+
+function parseMaxTime(str) {
+ var maxValue = 0;
+ var values = str.split(/\s*,\s*/);
+ forEach(values, function(value) {
+ // it's always safe to consider only second values and omit `ms` values since
+ // getComputedStyle will always handle the conversion for us
+ if (value.charAt(value.length - 1) == 's') {
+ value = value.substring(0, value.length - 1);
+ }
+ value = parseFloat(value) || 0;
+ maxValue = maxValue ? Math.max(value, maxValue) : value;
+ });
+ return maxValue;
+}
+
+function truthyTimingValue(val) {
+ return val === 0 || val != null;
+}
+
+function getCssTransitionDurationStyle(duration, applyOnlyDuration) {
+ var style = TRANSITION_PROP;
+ var value = duration + 's';
+ if (applyOnlyDuration) {
+ style += DURATION_KEY;
+ } else {
+ value += ' linear all';
+ }
+ return [style, value];
+}
+
+function getCssKeyframeDurationStyle(duration) {
+ return [ANIMATION_DURATION_PROP, duration + 's'];
+}
+
+function getCssDelayStyle(delay, isKeyframeAnimation) {
+ var prop = isKeyframeAnimation ? ANIMATION_DELAY_PROP : TRANSITION_DELAY_PROP;
+ return [prop, delay + 's'];
+}
+
+function blockTransitions(node, duration) {
+ // we use a negative delay value since it performs blocking
+ // yet it doesn't kill any existing transitions running on the
+ // same element which makes this safe for class-based animations
+ var value = duration ? '-' + duration + 's' : '';
+ applyInlineStyle(node, [TRANSITION_DELAY_PROP, value]);
+ return [TRANSITION_DELAY_PROP, value];
+}
+
+function blockKeyframeAnimations(node, applyBlock) {
+ var value = applyBlock ? 'paused' : '';
+ var key = ANIMATION_PROP + ANIMATION_PLAYSTATE_KEY;
+ applyInlineStyle(node, [key, value]);
+ return [key, value];
+}
+
+function applyInlineStyle(node, styleTuple) {
+ var prop = styleTuple[0];
+ var value = styleTuple[1];
+ node.style[prop] = value;
+}
+
+function createLocalCacheLookup() {
+ var cache = Object.create(null);
+ return {
+ flush: function() {
+ cache = Object.create(null);
+ },
+
+ count: function(key) {
+ var entry = cache[key];
+ return entry ? entry.total : 0;
+ },
+
+ get: function(key) {
+ var entry = cache[key];
+ return entry && entry.value;
+ },
+
+ put: function(key, value) {
+ if (!cache[key]) {
+ cache[key] = { total: 1, value: value };
} else {
- scope.$watch(val, function(value) {
- element.data(NG_ANIMATE_CHILDREN, !!value);
- });
+ cache[key].total++;
}
- };
- })
-
- //this private service is only used within CSS-enabled animations
- //IE8 + IE9 do not support rAF natively, but that is fine since they
- //also don't support transitions and keyframes which means that the code
- //below will never be used by the two browsers.
- .factory('$$animateReflow', ['$$rAF', '$document', function($$rAF, $document) {
- var bod = $document[0].body;
- return function(fn) {
- //the returned function acts as the cancellation function
- return $$rAF(function() {
- //the line below will force the browser to perform a repaint
- //so that all the animated elements within the animation frame
- //will be properly updated and drawn on screen. This is
- //required to perform multi-class CSS based animations with
- //Firefox. DO NOT REMOVE THIS LINE.
- var a = bod.offsetWidth + 1;
- fn();
- });
- };
- }])
-
- .config(['$provide', '$animateProvider', function($provide, $animateProvider) {
- var noop = angular.noop;
- var forEach = angular.forEach;
- var selectors = $animateProvider.$$selectors;
-
- var ELEMENT_NODE = 1;
- var NG_ANIMATE_STATE = '$$ngAnimateState';
- var NG_ANIMATE_CHILDREN = '$$ngAnimateChildren';
- var NG_ANIMATE_CLASS_NAME = 'ng-animate';
- var rootAnimateState = {running: true};
-
- function extractElementNode(element) {
- for(var i = 0; i < element.length; i++) {
- var elm = element[i];
- if(elm.nodeType == ELEMENT_NODE) {
- return elm;
+ }
+ };
+}
+
+var $AnimateCssProvider = ['$animateProvider', function($animateProvider) {
+ var gcsLookup = createLocalCacheLookup();
+ var gcsStaggerLookup = createLocalCacheLookup();
+
+ this.$get = ['$window', '$$jqLite', '$$AnimateRunner', '$timeout',
+ '$document', '$sniffer', '$$rAFScheduler',
+ function($window, $$jqLite, $$AnimateRunner, $timeout,
+ $document, $sniffer, $$rAFScheduler) {
+
+ var applyAnimationClasses = applyAnimationClassesFactory($$jqLite);
+
+ var parentCounter = 0;
+ function gcsHashFn(node, extraClasses) {
+ var KEY = "$$ngAnimateParentKey";
+ var parentNode = node.parentNode;
+ var parentID = parentNode[KEY] || (parentNode[KEY] = ++parentCounter);
+ return parentID + '-' + node.getAttribute('class') + '-' + extraClasses;
+ }
+
+ function computeCachedCssStyles(node, className, cacheKey, properties) {
+ var timings = gcsLookup.get(cacheKey);
+
+ if (!timings) {
+ timings = computeCssStyles($window, node, properties);
+ if (timings.animationIterationCount === 'infinite') {
+ timings.animationIterationCount = 1;
}
}
+
+ // we keep putting this in multiple times even though the value and the cacheKey are the same
+ // because we're keeping an interal tally of how many duplicate animations are detected.
+ gcsLookup.put(cacheKey, timings);
+ return timings;
}
- function prepareElement(element) {
- return element && angular.element(element);
+ function computeCachedCssStaggerStyles(node, className, cacheKey, properties) {
+ var stagger;
+
+ // if we have one or more existing matches of matching elements
+ // containing the same parent + CSS styles (which is how cacheKey works)
+ // then staggering is possible
+ if (gcsLookup.count(cacheKey) > 0) {
+ stagger = gcsStaggerLookup.get(cacheKey);
+
+ if (!stagger) {
+ var staggerClassName = pendClasses(className, '-stagger');
+
+ $$jqLite.addClass(node, staggerClassName);
+
+ stagger = computeCssStyles($window, node, properties);
+
+ // force the conversion of a null value to zero incase not set
+ stagger.animationDuration = Math.max(stagger.animationDuration, 0);
+ stagger.transitionDuration = Math.max(stagger.transitionDuration, 0);
+
+ $$jqLite.removeClass(node, staggerClassName);
+
+ gcsStaggerLookup.put(cacheKey, stagger);
+ }
+ }
+
+ return stagger || {};
}
- function stripCommentsFromElement(element) {
- return angular.element(extractElementNode(element));
+ var bod = getDomNode($document).body;
+ var rafWaitQueue = [];
+ function waitUntilQuiet(callback) {
+ rafWaitQueue.push(callback);
+ $$rAFScheduler.waitUntilQuiet(function() {
+ gcsLookup.flush();
+ gcsStaggerLookup.flush();
+
+ //the line below will force the browser to perform a repaint so
+ //that all the animated elements within the animation frame will
+ //be properly updated and drawn on screen. This is required to
+ //ensure that the preparation animation is properly flushed so that
+ //the active state picks up from there. DO NOT REMOVE THIS LINE.
+ //DO NOT OPTIMIZE THIS LINE. THE MINIFIER WILL REMOVE IT OTHERWISE WHICH
+ //WILL RESULT IN AN UNPREDICTABLE BUG THAT IS VERY HARD TO TRACK DOWN AND
+ //WILL TAKE YEARS AWAY FROM YOUR LIFE.
+ var width = bod.offsetWidth + 1;
+
+ // we use a for loop to ensure that if the queue is changed
+ // during this looping then it will consider new requests
+ for (var i = 0; i < rafWaitQueue.length; i++) {
+ rafWaitQueue[i](width);
+ }
+ rafWaitQueue.length = 0;
+ });
}
- function isMatchingElement(elm1, elm2) {
- return extractElementNode(elm1) == extractElementNode(elm2);
+ return init;
+
+ function computeTimings(node, className, cacheKey) {
+ var timings = computeCachedCssStyles(node, className, cacheKey, DETECT_CSS_PROPERTIES);
+ var aD = timings.animationDelay;
+ var tD = timings.transitionDelay;
+ timings.maxDelay = aD && tD
+ ? Math.max(aD, tD)
+ : (aD || tD);
+ timings.maxDuration = Math.max(
+ timings.animationDuration * timings.animationIterationCount,
+ timings.transitionDuration);
+
+ return timings;
}
- $provide.decorator('$animate', ['$delegate', '$injector', '$sniffer', '$rootElement', '$$asyncCallback', '$rootScope', '$document',
- function($delegate, $injector, $sniffer, $rootElement, $$asyncCallback, $rootScope, $document) {
+ function init(element, options) {
+ var node = getDomNode(element);
+ if (!node || !node.parentNode) {
+ return closeAndReturnNoopAnimator();
+ }
+
+ options = prepareAnimationOptions(options);
+
+ var temporaryStyles = [];
+ var classes = element.attr('class');
+ var styles = packageStyles(options);
+ var animationClosed;
+ var animationPaused;
+ var animationCompleted;
+ var runner;
+ var runnerHost;
+ var maxDelay;
+ var maxDelayTime;
+ var maxDuration;
+ var maxDurationTime;
+
+ if (options.duration === 0 || (!$sniffer.animations && !$sniffer.transitions)) {
+ return closeAndReturnNoopAnimator();
+ }
- var globalAnimationCounter = 0;
- $rootElement.data(NG_ANIMATE_STATE, rootAnimateState);
+ var method = options.event && isArray(options.event)
+ ? options.event.join(' ')
+ : options.event;
- // disable animations during bootstrap, but once we bootstrapped, wait again
- // for another digest until enabling animations. The reason why we digest twice
- // is because all structural animations (enter, leave and move) all perform a
- // post digest operation before animating. If we only wait for a single digest
- // to pass then the structural animation would render its animation on page load.
- // (which is what we're trying to avoid when the application first boots up.)
- $rootScope.$$postDigest(function() {
- $rootScope.$$postDigest(function() {
- rootAnimateState.running = false;
- });
- });
+ var isStructural = method && options.structural;
+ var structuralClassName = '';
+ var addRemoveClassName = '';
- var classNameFilter = $animateProvider.classNameFilter();
- var isAnimatableClassName = !classNameFilter
- ? function() { return true; }
- : function(className) {
- return classNameFilter.test(className);
- };
+ if (isStructural) {
+ structuralClassName = pendClasses(method, 'ng-', true);
+ } else if (method) {
+ structuralClassName = method;
+ }
- function blockElementAnimations(element) {
- var data = element.data(NG_ANIMATE_STATE) || {};
- data.running = true;
- element.data(NG_ANIMATE_STATE, data);
- }
-
- function lookup(name) {
- if (name) {
- var matches = [],
- flagMap = {},
- classes = name.substr(1).split('.');
-
- //the empty string value is the default animation
- //operation which performs CSS transition and keyframe
- //animations sniffing. This is always included for each
- //element animation procedure if the browser supports
- //transitions and/or keyframe animations. The default
- //animation is added to the top of the list to prevent
- //any previous animations from affecting the element styling
- //prior to the element being animated.
- if ($sniffer.transitions || $sniffer.animations) {
- matches.push($injector.get(selectors['']));
- }
+ if (options.addClass) {
+ addRemoveClassName += pendClasses(options.addClass, '-add');
+ }
- for(var i=0; i < classes.length; i++) {
- var klass = classes[i],
- selectorFactoryName = selectors[klass];
- if(selectorFactoryName && !flagMap[klass]) {
- matches.push($injector.get(selectorFactoryName));
- flagMap[klass] = true;
- }
- }
- return matches;
+ if (options.removeClass) {
+ if (addRemoveClassName.length) {
+ addRemoveClassName += ' ';
}
+ addRemoveClassName += pendClasses(options.removeClass, '-remove');
}
- function animationRunner(element, animationEvent, className) {
- //transcluded directives may sometimes fire an animation using only comment nodes
- //best to catch this early on to prevent any animation operations from occurring
- var node = element[0];
- if(!node) {
- return;
+ // there may be a situation where a structural animation is combined together
+ // with CSS classes that need to resolve before the animation is computed.
+ // However this means that there is no explicit CSS code to block the animation
+ // from happening (by setting 0s none in the class name). If this is the case
+ // we need to apply the classes before the first rAF so we know to continue if
+ // there actually is a detected transition or keyframe animation
+ if (options.applyClassesEarly && addRemoveClassName.length) {
+ applyAnimationClasses(element, options);
+ addRemoveClassName = '';
+ }
+
+ var setupClasses = [structuralClassName, addRemoveClassName].join(' ').trim();
+ var fullClassName = classes + ' ' + setupClasses;
+ var activeClasses = pendClasses(setupClasses, '-active');
+ var hasToStyles = styles.to && Object.keys(styles.to).length > 0;
+ var containsKeyframeAnimation = (options.keyframeStyle || '').length > 0;
+
+ // there is no way we can trigger an animation if no styles and
+ // no classes are being applied which would then trigger a transition,
+ // unless there a is raw keyframe value that is applied to the element.
+ if (!containsKeyframeAnimation
+ && !hasToStyles
+ && !setupClasses) {
+ return closeAndReturnNoopAnimator();
+ }
+
+ var cacheKey, stagger;
+ if (options.stagger > 0) {
+ var staggerVal = parseFloat(options.stagger);
+ stagger = {
+ transitionDelay: staggerVal,
+ animationDelay: staggerVal,
+ transitionDuration: 0,
+ animationDuration: 0
+ };
+ } else {
+ cacheKey = gcsHashFn(node, fullClassName);
+ stagger = computeCachedCssStaggerStyles(node, setupClasses, cacheKey, DETECT_STAGGER_CSS_PROPERTIES);
+ }
+
+ $$jqLite.addClass(element, setupClasses);
+
+ var applyOnlyDuration;
+
+ if (options.transitionStyle) {
+ var transitionStyle = [TRANSITION_PROP, options.transitionStyle];
+ applyInlineStyle(node, transitionStyle);
+ temporaryStyles.push(transitionStyle);
+ }
+
+ if (options.duration >= 0) {
+ applyOnlyDuration = node.style[TRANSITION_PROP].length > 0;
+ var durationStyle = getCssTransitionDurationStyle(options.duration, applyOnlyDuration);
+
+ // we set the duration so that it will be picked up by getComputedStyle later
+ applyInlineStyle(node, durationStyle);
+ temporaryStyles.push(durationStyle);
+ }
+
+ if (options.keyframeStyle) {
+ var keyframeStyle = [ANIMATION_PROP, options.keyframeStyle];
+ applyInlineStyle(node, keyframeStyle);
+ temporaryStyles.push(keyframeStyle);
+ }
+
+ var itemIndex = stagger
+ ? options.staggerIndex >= 0
+ ? options.staggerIndex
+ : gcsLookup.count(cacheKey)
+ : 0;
+
+ var isFirst = itemIndex === 0;
+
+ // this is a pre-emptive way of forcing the setup classes to be added and applied INSTANTLY
+ // without causing any combination of transitions to kick in. By adding a negative delay value
+ // it forces the setup class' transition to end immediately. We later then remove the negative
+ // transition delay to allow for the transition to naturally do it's thing. The beauty here is
+ // that if there is no transition defined then nothing will happen and this will also allow
+ // other transitions to be stacked on top of each other without any chopping them out.
+ if (isFirst) {
+ blockTransitions(node, SAFE_FAST_FORWARD_DURATION_VALUE);
+ }
+
+ var timings = computeTimings(node, fullClassName, cacheKey);
+ var relativeDelay = timings.maxDelay;
+ maxDelay = Math.max(relativeDelay, 0);
+ maxDuration = timings.maxDuration;
+
+ var flags = {};
+ flags.hasTransitions = timings.transitionDuration > 0;
+ flags.hasAnimations = timings.animationDuration > 0;
+ flags.hasTransitionAll = flags.hasTransitions && timings.transitionProperty == 'all';
+ flags.applyTransitionDuration = hasToStyles && (
+ (flags.hasTransitions && !flags.hasTransitionAll)
+ || (flags.hasAnimations && !flags.hasTransitions));
+ flags.applyAnimationDuration = options.duration && flags.hasAnimations;
+ flags.applyTransitionDelay = truthyTimingValue(options.delay) && (flags.applyTransitionDuration || flags.hasTransitions);
+ flags.applyAnimationDelay = truthyTimingValue(options.delay) && flags.hasAnimations;
+ flags.recalculateTimingStyles = addRemoveClassName.length > 0;
+
+ if (flags.applyTransitionDuration || flags.applyAnimationDuration) {
+ maxDuration = options.duration ? parseFloat(options.duration) : maxDuration;
+
+ if (flags.applyTransitionDuration) {
+ flags.hasTransitions = true;
+ timings.transitionDuration = maxDuration;
+ applyOnlyDuration = node.style[TRANSITION_PROP + PROPERTY_KEY].length > 0;
+ temporaryStyles.push(getCssTransitionDurationStyle(maxDuration, applyOnlyDuration));
+ }
+
+ if (flags.applyAnimationDuration) {
+ flags.hasAnimations = true;
+ timings.animationDuration = maxDuration;
+ temporaryStyles.push(getCssKeyframeDurationStyle(maxDuration));
+ }
+ }
+
+ if (maxDuration === 0 && !flags.recalculateTimingStyles) {
+ return closeAndReturnNoopAnimator();
+ }
+
+ // we need to recalculate the delay value since we used a pre-emptive negative
+ // delay value and the delay value is required for the final event checking. This
+ // property will ensure that this will happen after the RAF phase has passed.
+ if (options.duration == null && timings.transitionDuration > 0) {
+ flags.recalculateTimingStyles = flags.recalculateTimingStyles || isFirst;
+ }
+
+ maxDelayTime = maxDelay * ONE_SECOND;
+ maxDurationTime = maxDuration * ONE_SECOND;
+ if (!options.skipBlocking) {
+ flags.blockTransition = timings.transitionDuration > 0;
+ flags.blockKeyframeAnimation = timings.animationDuration > 0 &&
+ stagger.animationDelay > 0 &&
+ stagger.animationDuration === 0;
+ }
+
+ applyAnimationFromStyles(element, options);
+ if (!flags.blockTransition) {
+ blockTransitions(node, false);
+ }
+
+ applyBlocking(maxDuration);
+
+ // TODO(matsko): for 1.5 change this code to have an animator object for better debugging
+ return {
+ $$willAnimate: true,
+ end: endFn,
+ start: function() {
+ if (animationClosed) return;
+
+ runnerHost = {
+ end: endFn,
+ cancel: cancelFn,
+ resume: null, //this will be set during the start() phase
+ pause: null
+ };
+
+ runner = new $$AnimateRunner(runnerHost);
+
+ waitUntilQuiet(start);
+
+ // we don't have access to pause/resume the animation
+ // since it hasn't run yet. AnimateRunner will therefore
+ // set noop functions for resume and pause and they will
+ // later be overridden once the animation is triggered
+ return runner;
}
+ };
+
+ function endFn() {
+ close();
+ }
- var isSetClassOperation = animationEvent == 'setClass';
- var isClassBased = isSetClassOperation ||
- animationEvent == 'addClass' ||
- animationEvent == 'removeClass';
+ function cancelFn() {
+ close(true);
+ }
+
+ function close(rejected) { // jshint ignore:line
+ // if the promise has been called already then we shouldn't close
+ // the animation again
+ if (animationClosed || (animationCompleted && animationPaused)) return;
+ animationClosed = true;
+ animationPaused = false;
+
+ $$jqLite.removeClass(element, setupClasses);
+ $$jqLite.removeClass(element, activeClasses);
+
+ blockKeyframeAnimations(node, false);
+ blockTransitions(node, false);
- var classNameAdd, classNameRemove;
- if(angular.isArray(className)) {
- classNameAdd = className[0];
- classNameRemove = className[1];
- className = classNameAdd + ' ' + classNameRemove;
+ forEach(temporaryStyles, function(entry) {
+ // There is only one way to remove inline style properties entirely from elements.
+ // By using `removeProperty` this works, but we need to convert camel-cased CSS
+ // styles down to hyphenated values.
+ node.style[entry[0]] = '';
+ });
+
+ applyAnimationClasses(element, options);
+ applyAnimationStyles(element, options);
+
+ // the reason why we have this option is to allow a synchronous closing callback
+ // that is fired as SOON as the animation ends (when the CSS is removed) or if
+ // the animation never takes off at all. A good example is a leave animation since
+ // the element must be removed just after the animation is over or else the element
+ // will appear on screen for one animation frame causing an overbearing flicker.
+ if (options.onDone) {
+ options.onDone();
}
- var currentClassName = element.attr('class');
- var classes = currentClassName + ' ' + className;
- if(!isAnimatableClassName(classes)) {
- return;
+ // if the preparation function fails then the promise is not setup
+ if (runner) {
+ runner.complete(!rejected);
}
+ }
- var beforeComplete = noop,
- beforeCancel = [],
- before = [],
- afterComplete = noop,
- afterCancel = [],
- after = [];
-
- var animationLookup = (' ' + classes).replace(/\s+/g,'.');
- forEach(lookup(animationLookup), function(animationFactory) {
- var created = registerAnimation(animationFactory, animationEvent);
- if(!created && isSetClassOperation) {
- registerAnimation(animationFactory, 'addClass');
- registerAnimation(animationFactory, 'removeClass');
- }
+ function applyBlocking(duration) {
+ if (flags.blockTransition) {
+ blockTransitions(node, duration);
+ }
+
+ if (flags.blockKeyframeAnimation) {
+ blockKeyframeAnimations(node, !!duration);
+ }
+ }
+
+ function closeAndReturnNoopAnimator() {
+ runner = new $$AnimateRunner({
+ end: endFn,
+ cancel: cancelFn
});
- function registerAnimation(animationFactory, event) {
- var afterFn = animationFactory[event];
- var beforeFn = animationFactory['before' + event.charAt(0).toUpperCase() + event.substr(1)];
- if(afterFn || beforeFn) {
- if(event == 'leave') {
- beforeFn = afterFn;
- //when set as null then animation knows to skip this phase
- afterFn = null;
+ close();
+
+ return {
+ $$willAnimate: false,
+ start: function() {
+ return runner;
+ },
+ end: endFn
+ };
+ }
+
+ function start() {
+ if (animationClosed) return;
+ if (!node.parentNode) {
+ close();
+ return;
+ }
+
+ var startTime, events = [];
+
+ // even though we only pause keyframe animations here the pause flag
+ // will still happen when transitions are used. Only the transition will
+ // not be paused since that is not possible. If the animation ends when
+ // paused then it will not complete until unpaused or cancelled.
+ var playPause = function(playAnimation) {
+ if (!animationCompleted) {
+ animationPaused = !playAnimation;
+ if (timings.animationDuration) {
+ var value = blockKeyframeAnimations(node, animationPaused);
+ animationPaused
+ ? temporaryStyles.push(value)
+ : removeFromArray(temporaryStyles, value);
}
- after.push({
- event : event, fn : afterFn
- });
- before.push({
- event : event, fn : beforeFn
- });
- return true;
+ } else if (animationPaused && playAnimation) {
+ animationPaused = false;
+ close();
}
+ };
+
+ // checking the stagger duration prevents an accidently cascade of the CSS delay style
+ // being inherited from the parent. If the transition duration is zero then we can safely
+ // rely that the delay value is an intential stagger delay style.
+ var maxStagger = itemIndex > 0
+ && ((timings.transitionDuration && stagger.transitionDuration === 0) ||
+ (timings.animationDuration && stagger.animationDuration === 0))
+ && Math.max(stagger.animationDelay, stagger.transitionDelay);
+ if (maxStagger) {
+ $timeout(triggerAnimationStart,
+ Math.floor(maxStagger * itemIndex * ONE_SECOND),
+ false);
+ } else {
+ triggerAnimationStart();
}
- function run(fns, cancellations, allCompleteFn) {
- var animations = [];
- forEach(fns, function(animation) {
- animation.fn && animations.push(animation);
+ // this will decorate the existing promise runner with pause/resume methods
+ runnerHost.resume = function() {
+ playPause(true);
+ };
+
+ runnerHost.pause = function() {
+ playPause(false);
+ };
+
+ function triggerAnimationStart() {
+ // just incase a stagger animation kicks in when the animation
+ // itself was cancelled entirely
+ if (animationClosed) return;
+
+ applyBlocking(false);
+
+ forEach(temporaryStyles, function(entry) {
+ var key = entry[0];
+ var value = entry[1];
+ node.style[key] = value;
});
- var count = 0;
- function afterAnimationComplete(index) {
- if(cancellations) {
- (cancellations[index] || noop)();
- if(++count < animations.length) return;
- cancellations = null;
+ applyAnimationClasses(element, options);
+ $$jqLite.addClass(element, activeClasses);
+
+ if (flags.recalculateTimingStyles) {
+ fullClassName = node.className + ' ' + setupClasses;
+ cacheKey = gcsHashFn(node, fullClassName);
+
+ timings = computeTimings(node, fullClassName, cacheKey);
+ relativeDelay = timings.maxDelay;
+ maxDelay = Math.max(relativeDelay, 0);
+ maxDuration = timings.maxDuration;
+
+ if (maxDuration === 0) {
+ close();
+ return;
}
- allCompleteFn();
+
+ flags.hasTransitions = timings.transitionDuration > 0;
+ flags.hasAnimations = timings.animationDuration > 0;
}
- //The code below adds directly to the array in order to work with
- //both sync and async animations. Sync animations are when the done()
- //operation is called right away. DO NOT REFACTOR!
- forEach(animations, function(animation, index) {
- var progress = function() {
- afterAnimationComplete(index);
- };
- switch(animation.event) {
- case 'setClass':
- cancellations.push(animation.fn(element, classNameAdd, classNameRemove, progress));
- break;
- case 'addClass':
- cancellations.push(animation.fn(element, classNameAdd || className, progress));
- break;
- case 'removeClass':
- cancellations.push(animation.fn(element, classNameRemove || className, progress));
- break;
- default:
- cancellations.push(animation.fn(element, progress));
- break;
+ if (flags.applyTransitionDelay || flags.applyAnimationDelay) {
+ relativeDelay = typeof options.delay !== "boolean" && truthyTimingValue(options.delay)
+ ? parseFloat(options.delay)
+ : relativeDelay;
+
+ maxDelay = Math.max(relativeDelay, 0);
+
+ var delayStyle;
+ if (flags.applyTransitionDelay) {
+ timings.transitionDelay = relativeDelay;
+ delayStyle = getCssDelayStyle(relativeDelay);
+ temporaryStyles.push(delayStyle);
+ node.style[delayStyle[0]] = delayStyle[1];
}
- });
- if(cancellations && cancellations.length === 0) {
- allCompleteFn();
+ if (flags.applyAnimationDelay) {
+ timings.animationDelay = relativeDelay;
+ delayStyle = getCssDelayStyle(relativeDelay, true);
+ temporaryStyles.push(delayStyle);
+ node.style[delayStyle[0]] = delayStyle[1];
+ }
}
- }
- return {
- node : node,
- event : animationEvent,
- className : className,
- isClassBased : isClassBased,
- isSetClassOperation : isSetClassOperation,
- before : function(allCompleteFn) {
- beforeComplete = allCompleteFn;
- run(before, beforeCancel, function() {
- beforeComplete = noop;
- allCompleteFn();
- });
- },
- after : function(allCompleteFn) {
- afterComplete = allCompleteFn;
- run(after, afterCancel, function() {
- afterComplete = noop;
- allCompleteFn();
- });
- },
- cancel : function() {
- if(beforeCancel) {
- forEach(beforeCancel, function(cancelFn) {
- (cancelFn || noop)(true);
- });
- beforeComplete(true);
+ maxDelayTime = maxDelay * ONE_SECOND;
+ maxDurationTime = maxDuration * ONE_SECOND;
+
+ if (options.easing) {
+ var easeProp, easeVal = options.easing;
+ if (flags.hasTransitions) {
+ easeProp = TRANSITION_PROP + TIMING_KEY;
+ temporaryStyles.push([easeProp, easeVal]);
+ node.style[easeProp] = easeVal;
}
- if(afterCancel) {
- forEach(afterCancel, function(cancelFn) {
- (cancelFn || noop)(true);
- });
- afterComplete(true);
+ if (flags.hasAnimations) {
+ easeProp = ANIMATION_PROP + TIMING_KEY;
+ temporaryStyles.push([easeProp, easeVal]);
+ node.style[easeProp] = easeVal;
}
}
- };
+
+ if (timings.transitionDuration) {
+ events.push(TRANSITIONEND_EVENT);
+ }
+
+ if (timings.animationDuration) {
+ events.push(ANIMATIONEND_EVENT);
+ }
+
+ startTime = Date.now();
+ element.on(events.join(' '), onAnimationProgress);
+ $timeout(onAnimationExpired, maxDelayTime + CLOSING_TIME_BUFFER * maxDurationTime);
+
+ applyAnimationToStyles(element, options);
+ }
+
+ function onAnimationExpired() {
+ // although an expired animation is a failed animation, getting to
+ // this outcome is very easy if the CSS code screws up. Therefore we
+ // should still continue normally as if the animation completed correctly.
+ close();
+ }
+
+ function onAnimationProgress(event) {
+ event.stopPropagation();
+ var ev = event.originalEvent || event;
+ var timeStamp = ev.$manualTimeStamp || ev.timeStamp || Date.now();
+
+ /* Firefox (or possibly just Gecko) likes to not round values up
+ * when a ms measurement is used for the animation */
+ var elapsedTime = parseFloat(ev.elapsedTime.toFixed(ELAPSED_TIME_MAX_DECIMAL_PLACES));
+
+ /* $manualTimeStamp is a mocked timeStamp value which is set
+ * within browserTrigger(). This is only here so that tests can
+ * mock animations properly. Real events fallback to event.timeStamp,
+ * or, if they don't, then a timeStamp is automatically created for them.
+ * We're checking to see if the timeStamp surpasses the expected delay,
+ * but we're using elapsedTime instead of the timeStamp on the 2nd
+ * pre-condition since animations sometimes close off early */
+ if (Math.max(timeStamp - startTime, 0) >= maxDelayTime && elapsedTime >= maxDuration) {
+ // we set this flag to ensure that if the transition is paused then, when resumed,
+ // the animation will automatically close itself since transitions cannot be paused.
+ animationCompleted = true;
+ close();
+ }
+ }
+ }
+ }
+ }];
+}];
+
+var $$AnimateCssDriverProvider = ['$$animationProvider', function($$animationProvider) {
+ $$animationProvider.drivers.push('$$animateCssDriver');
+
+ var NG_ANIMATE_SHIM_CLASS_NAME = 'ng-animate-shim';
+ var NG_ANIMATE_ANCHOR_CLASS_NAME = 'ng-anchor';
+
+ var NG_OUT_ANCHOR_CLASS_NAME = 'ng-anchor-out';
+ var NG_IN_ANCHOR_CLASS_NAME = 'ng-anchor-in';
+
+ this.$get = ['$animateCss', '$rootScope', '$$AnimateRunner', '$rootElement', '$document', '$sniffer',
+ function($animateCss, $rootScope, $$AnimateRunner, $rootElement, $document, $sniffer) {
+
+ // only browsers that support these properties can render animations
+ if (!$sniffer.animations && !$sniffer.transitions) return noop;
+
+ var bodyNode = getDomNode($document).body;
+ var rootNode = getDomNode($rootElement);
+
+ var rootBodyElement = jqLite(bodyNode.parentNode === rootNode ? bodyNode : rootNode);
+
+ return function initDriverFn(animationDetails) {
+ return animationDetails.from && animationDetails.to
+ ? prepareFromToAnchorAnimation(animationDetails.from,
+ animationDetails.to,
+ animationDetails.classes,
+ animationDetails.anchors)
+ : prepareRegularAnimation(animationDetails);
+ };
+
+ function filterCssClasses(classes) {
+ //remove all the `ng-` stuff
+ return classes.replace(/\bng-\S+\b/g, '');
+ }
+
+ function getUniqueValues(a, b) {
+ if (isString(a)) a = a.split(' ');
+ if (isString(b)) b = b.split(' ');
+ return a.filter(function(val) {
+ return b.indexOf(val) === -1;
+ }).join(' ');
+ }
+
+ function prepareAnchoredAnimation(classes, outAnchor, inAnchor) {
+ var clone = jqLite(getDomNode(outAnchor).cloneNode(true));
+ var startingClasses = filterCssClasses(getClassVal(clone));
+
+ outAnchor.addClass(NG_ANIMATE_SHIM_CLASS_NAME);
+ inAnchor.addClass(NG_ANIMATE_SHIM_CLASS_NAME);
+
+ clone.addClass(NG_ANIMATE_ANCHOR_CLASS_NAME);
+
+ rootBodyElement.append(clone);
+
+ var animatorIn, animatorOut = prepareOutAnimation();
+
+ // the user may not end up using the `out` animation and
+ // only making use of the `in` animation or vice-versa.
+ // In either case we should allow this and not assume the
+ // animation is over unless both animations are not used.
+ if (!animatorOut) {
+ animatorIn = prepareInAnimation();
+ if (!animatorIn) {
+ return end();
+ }
}
- /**
- * @ngdoc service
- * @name $animate
- * @kind function
- *
- * @description
- * The `$animate` service provides animation detection support while performing DOM operations (enter, leave and move) as well as during addClass and removeClass operations.
- * When any of these operations are run, the $animate service
- * will examine any JavaScript-defined animations (which are defined by using the $animateProvider provider object)
- * as well as any CSS-defined animations against the CSS classes present on the element once the DOM operation is run.
- *
- * The `$animate` service is used behind the scenes with pre-existing directives and animation with these directives
- * will work out of the box without any extra configuration.
- *
- * Requires the {@link ngAnimate `ngAnimate`} module to be installed.
- *
- * Please visit the {@link ngAnimate `ngAnimate`} module overview page learn more about how to use animations in your application.
- *
- */
+ var startingAnimator = animatorOut || animatorIn;
+
return {
- /**
- * @ngdoc method
- * @name $animate#enter
- * @kind function
- *
- * @description
- * Appends the element to the parentElement element that resides in the document and then runs the enter animation. Once
- * the animation is started, the following CSS classes will be present on the element for the duration of the animation:
- *
- * Below is a breakdown of each step that occurs during enter animation:
- *
- * | Animation Step | What the element class attribute looks like |
- * |----------------------------------------------------------------------------------------------|---------------------------------------------|
- * | 1. $animate.enter(...) is called | class="my-animation" |
- * | 2. element is inserted into the parentElement element or beside the afterElement element | class="my-animation" |
- * | 3. $animate runs any JavaScript-defined animations on the element | class="my-animation ng-animate" |
- * | 4. the .ng-enter class is added to the element | class="my-animation ng-animate ng-enter" |
- * | 5. $animate scans the element styles to get the CSS transition/animation duration and delay | class="my-animation ng-animate ng-enter" |
- * | 6. $animate waits for 10ms (this performs a reflow) | class="my-animation ng-animate ng-enter" |
- * | 7. the .ng-enter-active and .ng-animate-active classes are added (this triggers the CSS transition/animation) | class="my-animation ng-animate ng-animate-active ng-enter ng-enter-active" |
- * | 8. $animate waits for X milliseconds for the animation to complete | class="my-animation ng-animate ng-animate-active ng-enter ng-enter-active" |
- * | 9. The animation ends and all generated CSS classes are removed from the element | class="my-animation" |
- * | 10. The doneCallback() callback is fired (if provided) | class="my-animation" |
- *
- * @param {DOMElement} element the element that will be the focus of the enter animation
- * @param {DOMElement} parentElement the parent element of the element that will be the focus of the enter animation
- * @param {DOMElement} afterElement the sibling element (which is the previous element) of the element that will be the focus of the enter animation
- * @param {function()=} doneCallback the callback function that will be called once the animation is complete
- */
- enter : function(element, parentElement, afterElement, doneCallback) {
- element = angular.element(element);
- parentElement = prepareElement(parentElement);
- afterElement = prepareElement(afterElement);
-
- blockElementAnimations(element);
- $delegate.enter(element, parentElement, afterElement);
- $rootScope.$$postDigest(function() {
- element = stripCommentsFromElement(element);
- performAnimation('enter', 'ng-enter', element, parentElement, afterElement, noop, doneCallback);
- });
- },
-
- /**
- * @ngdoc method
- * @name $animate#leave
- * @kind function
- *
- * @description
- * Runs the leave animation operation and, upon completion, removes the element from the DOM. Once
- * the animation is started, the following CSS classes will be added for the duration of the animation:
- *
- * Below is a breakdown of each step that occurs during leave animation:
- *
- * | Animation Step | What the element class attribute looks like |
- * |----------------------------------------------------------------------------------------------|---------------------------------------------|
- * | 1. $animate.leave(...) is called | class="my-animation" |
- * | 2. $animate runs any JavaScript-defined animations on the element | class="my-animation ng-animate" |
- * | 3. the .ng-leave class is added to the element | class="my-animation ng-animate ng-leave" |
- * | 4. $animate scans the element styles to get the CSS transition/animation duration and delay | class="my-animation ng-animate ng-leave" |
- * | 5. $animate waits for 10ms (this performs a reflow) | class="my-animation ng-animate ng-leave" |
- * | 6. the .ng-leave-active and .ng-animate-active classes is added (this triggers the CSS transition/animation) | class="my-animation ng-animate ng-animate-active ng-leave ng-leave-active" |
- * | 7. $animate waits for X milliseconds for the animation to complete | class="my-animation ng-animate ng-animate-active ng-leave ng-leave-active" |
- * | 8. The animation ends and all generated CSS classes are removed from the element | class="my-animation" |
- * | 9. The element is removed from the DOM | ... |
- * | 10. The doneCallback() callback is fired (if provided) | ... |
- *
- * @param {DOMElement} element the element that will be the focus of the leave animation
- * @param {function()=} doneCallback the callback function that will be called once the animation is complete
- */
- leave : function(element, doneCallback) {
- element = angular.element(element);
- cancelChildAnimations(element);
- blockElementAnimations(element);
- $rootScope.$$postDigest(function() {
- performAnimation('leave', 'ng-leave', stripCommentsFromElement(element), null, null, function() {
- $delegate.leave(element);
- }, doneCallback);
+ start: function() {
+ var runner;
+
+ var currentAnimation = startingAnimator.start();
+ currentAnimation.done(function() {
+ currentAnimation = null;
+ if (!animatorIn) {
+ animatorIn = prepareInAnimation();
+ if (animatorIn) {
+ currentAnimation = animatorIn.start();
+ currentAnimation.done(function() {
+ currentAnimation = null;
+ end();
+ runner.complete();
+ });
+ return currentAnimation;
+ }
+ }
+ // in the event that there is no `in` animation
+ end();
+ runner.complete();
});
- },
-
- /**
- * @ngdoc method
- * @name $animate#move
- * @kind function
- *
- * @description
- * Fires the move DOM operation. Just before the animation starts, the animate service will either append it into the parentElement container or
- * add the element directly after the afterElement element if present. Then the move animation will be run. Once
- * the animation is started, the following CSS classes will be added for the duration of the animation:
- *
- * Below is a breakdown of each step that occurs during move animation:
- *
- * | Animation Step | What the element class attribute looks like |
- * |----------------------------------------------------------------------------------------------|---------------------------------------------|
- * | 1. $animate.move(...) is called | class="my-animation" |
- * | 2. element is moved into the parentElement element or beside the afterElement element | class="my-animation" |
- * | 3. $animate runs any JavaScript-defined animations on the element | class="my-animation ng-animate" |
- * | 4. the .ng-move class is added to the element | class="my-animation ng-animate ng-move" |
- * | 5. $animate scans the element styles to get the CSS transition/animation duration and delay | class="my-animation ng-animate ng-move" |
- * | 6. $animate waits for 10ms (this performs a reflow) | class="my-animation ng-animate ng-move" |
- * | 7. the .ng-move-active and .ng-animate-active classes is added (this triggers the CSS transition/animation) | class="my-animation ng-animate ng-animate-active ng-move ng-move-active" |
- * | 8. $animate waits for X milliseconds for the animation to complete | class="my-animation ng-animate ng-animate-active ng-move ng-move-active" |
- * | 9. The animation ends and all generated CSS classes are removed from the element | class="my-animation" |
- * | 10. The doneCallback() callback is fired (if provided) | class="my-animation" |
- *
- * @param {DOMElement} element the element that will be the focus of the move animation
- * @param {DOMElement} parentElement the parentElement element of the element that will be the focus of the move animation
- * @param {DOMElement} afterElement the sibling element (which is the previous element) of the element that will be the focus of the move animation
- * @param {function()=} doneCallback the callback function that will be called once the animation is complete
- */
- move : function(element, parentElement, afterElement, doneCallback) {
- element = angular.element(element);
- parentElement = prepareElement(parentElement);
- afterElement = prepareElement(afterElement);
-
- cancelChildAnimations(element);
- blockElementAnimations(element);
- $delegate.move(element, parentElement, afterElement);
- $rootScope.$$postDigest(function() {
- element = stripCommentsFromElement(element);
- performAnimation('move', 'ng-move', element, parentElement, afterElement, noop, doneCallback);
+
+ runner = new $$AnimateRunner({
+ end: endFn,
+ cancel: endFn
});
- },
-
- /**
- * @ngdoc method
- * @name $animate#addClass
- *
- * @description
- * Triggers a custom animation event based off the className variable and then attaches the className value to the element as a CSS class.
- * Unlike the other animation methods, the animate service will suffix the className value with {@type -add} in order to provide
- * the animate service the setup and active CSS classes in order to trigger the animation (this will be skipped if no CSS transitions
- * or keyframes are defined on the -add or base CSS class).
- *
- * Below is a breakdown of each step that occurs during addClass animation:
- *
- * | Animation Step | What the element class attribute looks like |
- * |------------------------------------------------------------------------------------------------|---------------------------------------------|
- * | 1. $animate.addClass(element, 'super') is called | class="my-animation" |
- * | 2. $animate runs any JavaScript-defined animations on the element | class="my-animation ng-animate" |
- * | 3. the .super-add class are added to the element | class="my-animation ng-animate super-add" |
- * | 4. $animate scans the element styles to get the CSS transition/animation duration and delay | class="my-animation ng-animate super-add" |
- * | 5. $animate waits for 10ms (this performs a reflow) | class="my-animation ng-animate super-add" |
- * | 6. the .super, .super-add-active and .ng-animate-active classes are added (this triggers the CSS transition/animation) | class="my-animation ng-animate ng-animate-active super super-add super-add-active" |
- * | 7. $animate waits for X milliseconds for the animation to complete | class="my-animation super super-add super-add-active" |
- * | 8. The animation ends and all generated CSS classes are removed from the element | class="my-animation super" |
- * | 9. The super class is kept on the element | class="my-animation super" |
- * | 10. The doneCallback() callback is fired (if provided) | class="my-animation super" |
- *
- * @param {DOMElement} element the element that will be animated
- * @param {string} className the CSS class that will be added to the element and then animated
- * @param {function()=} doneCallback the callback function that will be called once the animation is complete
- */
- addClass : function(element, className, doneCallback) {
- element = angular.element(element);
- element = stripCommentsFromElement(element);
- performAnimation('addClass', className, element, null, null, function() {
- $delegate.addClass(element, className);
- }, doneCallback);
- },
-
- /**
- * @ngdoc method
- * @name $animate#removeClass
- *
- * @description
- * Triggers a custom animation event based off the className variable and then removes the CSS class provided by the className value
- * from the element. Unlike the other animation methods, the animate service will suffix the className value with {@type -remove} in
- * order to provide the animate service the setup and active CSS classes in order to trigger the animation (this will be skipped if
- * no CSS transitions or keyframes are defined on the -remove or base CSS classes).
- *
- * Below is a breakdown of each step that occurs during removeClass animation:
- *
- * | Animation Step | What the element class attribute looks like |
- * |-----------------------------------------------------------------------------------------------|---------------------------------------------|
- * | 1. $animate.removeClass(element, 'super') is called | class="my-animation super" |
- * | 2. $animate runs any JavaScript-defined animations on the element | class="my-animation super ng-animate" |
- * | 3. the .super-remove class are added to the element | class="my-animation super ng-animate super-remove"|
- * | 4. $animate scans the element styles to get the CSS transition/animation duration and delay | class="my-animation super ng-animate super-remove" |
- * | 5. $animate waits for 10ms (this performs a reflow) | class="my-animation super ng-animate super-remove" |
- * | 6. the .super-remove-active and .ng-animate-active classes are added and .super is removed (this triggers the CSS transition/animation) | class="my-animation ng-animate ng-animate-active super-remove super-remove-active" |
- * | 7. $animate waits for X milliseconds for the animation to complete | class="my-animation ng-animate ng-animate-active super-remove super-remove-active" |
- * | 8. The animation ends and all generated CSS classes are removed from the element | class="my-animation" |
- * | 9. The doneCallback() callback is fired (if provided) | class="my-animation" |
- *
- *
- * @param {DOMElement} element the element that will be animated
- * @param {string} className the CSS class that will be animated and then removed from the element
- * @param {function()=} doneCallback the callback function that will be called once the animation is complete
- */
- removeClass : function(element, className, doneCallback) {
- element = angular.element(element);
- element = stripCommentsFromElement(element);
- performAnimation('removeClass', className, element, null, null, function() {
- $delegate.removeClass(element, className);
- }, doneCallback);
- },
-
- /**
- *
- * @ngdoc function
- * @name $animate#setClass
- * @function
- * @description Adds and/or removes the given CSS classes to and from the element.
- * Once complete, the done() callback will be fired (if provided).
- * @param {DOMElement} element the element which will its CSS classes changed
- * removed from it
- * @param {string} add the CSS classes which will be added to the element
- * @param {string} remove the CSS class which will be removed from the element
- * @param {Function=} done the callback function (if provided) that will be fired after the
- * CSS classes have been set on the element
- */
- setClass : function(element, add, remove, doneCallback) {
- element = angular.element(element);
- element = stripCommentsFromElement(element);
- performAnimation('setClass', [add, remove], element, null, null, function() {
- $delegate.setClass(element, add, remove);
- }, doneCallback);
- },
-
- /**
- * @ngdoc method
- * @name $animate#enabled
- * @kind function
- *
- * @param {boolean=} value If provided then set the animation on or off.
- * @param {DOMElement=} element If provided then the element will be used to represent the enable/disable operation
- * @return {boolean} Current animation state.
- *
- * @description
- * Globally enables/disables animations.
- *
- */
- enabled : function(value, element) {
- switch(arguments.length) {
- case 2:
- if(value) {
- cleanup(element);
- } else {
- var data = element.data(NG_ANIMATE_STATE) || {};
- data.disabled = true;
- element.data(NG_ANIMATE_STATE, data);
- }
- break;
- case 1:
- rootAnimateState.disabled = !value;
- break;
+ return runner;
- default:
- value = !rootAnimateState.disabled;
- break;
+ function endFn() {
+ if (currentAnimation) {
+ currentAnimation.end();
+ }
}
- return !!value;
- }
+ }
};
- /*
- all animations call this shared animation triggering function internally.
- The animationEvent variable refers to the JavaScript animation event that will be triggered
- and the className value is the name of the animation that will be applied within the
- CSS code. Element, parentElement and afterElement are provided DOM elements for the animation
- and the onComplete callback will be fired once the animation is fully complete.
- */
- function performAnimation(animationEvent, className, element, parentElement, afterElement, domOperation, doneCallback) {
-
- var runner = animationRunner(element, animationEvent, className);
- if(!runner) {
- fireDOMOperation();
- fireBeforeCallbackAsync();
- fireAfterCallbackAsync();
- closeAnimation();
- return;
- }
+ function calculateAnchorStyles(anchor) {
+ var styles = {};
+
+ var coords = getDomNode(anchor).getBoundingClientRect();
+
+ // we iterate directly since safari messes up and doesn't return
+ // all the keys for the coods object when iterated
+ forEach(['width','height','top','left'], function(key) {
+ var value = coords[key];
+ switch (key) {
+ case 'top':
+ value += bodyNode.scrollTop;
+ break;
+ case 'left':
+ value += bodyNode.scrollLeft;
+ break;
+ }
+ styles[key] = Math.floor(value) + 'px';
+ });
+ return styles;
+ }
- className = runner.className;
- var elementEvents = angular.element._data(runner.node);
- elementEvents = elementEvents && elementEvents.events;
+ function prepareOutAnimation() {
+ var animator = $animateCss(clone, {
+ addClass: NG_OUT_ANCHOR_CLASS_NAME,
+ delay: true,
+ from: calculateAnchorStyles(outAnchor)
+ });
- if (!parentElement) {
- parentElement = afterElement ? afterElement.parent() : element.parent();
- }
+ // read the comment within `prepareRegularAnimation` to understand
+ // why this check is necessary
+ return animator.$$willAnimate ? animator : null;
+ }
- var ngAnimateState = element.data(NG_ANIMATE_STATE) || {};
- var runningAnimations = ngAnimateState.active || {};
- var totalActiveAnimations = ngAnimateState.totalActive || 0;
- var lastAnimation = ngAnimateState.last;
-
- //only allow animations if the currently running animation is not structural
- //or if there is no animation running at all
- var skipAnimations;
- if (runner.isClassBased) {
- skipAnimations = ngAnimateState.running ||
- ngAnimateState.disabled ||
- (lastAnimation && !lastAnimation.isClassBased);
- }
+ function getClassVal(element) {
+ return element.attr('class') || '';
+ }
- //skip the animation if animations are disabled, a parent is already being animated,
- //the element is not currently attached to the document body or then completely close
- //the animation if any matching animations are not found at all.
- //NOTE: IE8 + IE9 should close properly (run closeAnimation()) in case an animation was found.
- if (skipAnimations || animationsDisabled(element, parentElement)) {
- fireDOMOperation();
- fireBeforeCallbackAsync();
- fireAfterCallbackAsync();
- closeAnimation();
- return;
+ function prepareInAnimation() {
+ var endingClasses = filterCssClasses(getClassVal(inAnchor));
+ var toAdd = getUniqueValues(endingClasses, startingClasses);
+ var toRemove = getUniqueValues(startingClasses, endingClasses);
+
+ var animator = $animateCss(clone, {
+ to: calculateAnchorStyles(inAnchor),
+ addClass: NG_IN_ANCHOR_CLASS_NAME + ' ' + toAdd,
+ removeClass: NG_OUT_ANCHOR_CLASS_NAME + ' ' + toRemove,
+ delay: true
+ });
+
+ // read the comment within `prepareRegularAnimation` to understand
+ // why this check is necessary
+ return animator.$$willAnimate ? animator : null;
+ }
+
+ function end() {
+ clone.remove();
+ outAnchor.removeClass(NG_ANIMATE_SHIM_CLASS_NAME);
+ inAnchor.removeClass(NG_ANIMATE_SHIM_CLASS_NAME);
+ }
+ }
+
+ function prepareFromToAnchorAnimation(from, to, classes, anchors) {
+ var fromAnimation = prepareRegularAnimation(from);
+ var toAnimation = prepareRegularAnimation(to);
+
+ var anchorAnimations = [];
+ forEach(anchors, function(anchor) {
+ var outElement = anchor['out'];
+ var inElement = anchor['in'];
+ var animator = prepareAnchoredAnimation(classes, outElement, inElement);
+ if (animator) {
+ anchorAnimations.push(animator);
}
+ });
- var skipAnimation = false;
- if(totalActiveAnimations > 0) {
- var animationsToCancel = [];
- if(!runner.isClassBased) {
- if(animationEvent == 'leave' && runningAnimations['ng-leave']) {
- skipAnimation = true;
- } else {
- //cancel all animations when a structural animation takes place
- for(var klass in runningAnimations) {
- animationsToCancel.push(runningAnimations[klass]);
- cleanup(element, klass);
- }
- runningAnimations = {};
- totalActiveAnimations = 0;
- }
- } else if(lastAnimation.event == 'setClass') {
- animationsToCancel.push(lastAnimation);
- cleanup(element, className);
+ // no point in doing anything when there are no elements to animate
+ if (!fromAnimation && !toAnimation && anchorAnimations.length === 0) return;
+
+ return {
+ start: function() {
+ var animationRunners = [];
+
+ if (fromAnimation) {
+ animationRunners.push(fromAnimation.start());
}
- else if(runningAnimations[className]) {
- var current = runningAnimations[className];
- if(current.event == animationEvent) {
- skipAnimation = true;
- } else {
- animationsToCancel.push(current);
- cleanup(element, className);
- }
+
+ if (toAnimation) {
+ animationRunners.push(toAnimation.start());
}
- if(animationsToCancel.length > 0) {
- forEach(animationsToCancel, function(operation) {
- operation.cancel();
+ forEach(anchorAnimations, function(animation) {
+ animationRunners.push(animation.start());
+ });
+
+ var runner = new $$AnimateRunner({
+ end: endFn,
+ cancel: endFn // CSS-driven animations cannot be cancelled, only ended
+ });
+
+ $$AnimateRunner.all(animationRunners, function(status) {
+ runner.complete(status);
+ });
+
+ return runner;
+
+ function endFn() {
+ forEach(animationRunners, function(runner) {
+ runner.end();
});
}
}
+ };
+ }
- if(runner.isClassBased && !runner.isSetClassOperation && !skipAnimation) {
- skipAnimation = (animationEvent == 'addClass') == element.hasClass(className); //opposite of XOR
+ function prepareRegularAnimation(animationDetails) {
+ var element = animationDetails.element;
+ var options = animationDetails.options || {};
+
+ if (animationDetails.structural) {
+ // structural animations ensure that the CSS classes are always applied
+ // before the detection starts.
+ options.structural = options.applyClassesEarly = true;
+
+ // we special case the leave animation since we want to ensure that
+ // the element is removed as soon as the animation is over. Otherwise
+ // a flicker might appear or the element may not be removed at all
+ options.event = animationDetails.event;
+ if (options.event === 'leave') {
+ options.onDone = options.domOperation;
}
+ } else {
+ options.event = null;
+ }
- if(skipAnimation) {
- fireDOMOperation();
- fireBeforeCallbackAsync();
- fireAfterCallbackAsync();
- fireDoneCallbackAsync();
- return;
+ var animator = $animateCss(element, options);
+
+ // the driver lookup code inside of $$animation attempts to spawn a
+ // driver one by one until a driver returns a.$$willAnimate animator object.
+ // $animateCss will always return an object, however, it will pass in
+ // a flag as a hint as to whether an animation was detected or not
+ return animator.$$willAnimate ? animator : null;
+ }
+ }];
+}];
+
+// TODO(matsko): use caching here to speed things up for detection
+// TODO(matsko): add documentation
+// by the time...
+
+var $$AnimateJsProvider = ['$animateProvider', function($animateProvider) {
+ this.$get = ['$injector', '$$AnimateRunner', '$$rAFMutex', '$$jqLite',
+ function($injector, $$AnimateRunner, $$rAFMutex, $$jqLite) {
+
+ var applyAnimationClasses = applyAnimationClassesFactory($$jqLite);
+ // $animateJs(element, 'enter');
+ return function(element, event, classes, options) {
+ // the `classes` argument is optional and if it is not used
+ // then the classes will be resolved from the element's className
+ // property as well as options.addClass/options.removeClass.
+ if (arguments.length === 3 && isObject(classes)) {
+ options = classes;
+ classes = null;
+ }
+
+ options = prepareAnimationOptions(options);
+ if (!classes) {
+ classes = element.attr('class') || '';
+ if (options.addClass) {
+ classes += ' ' + options.addClass;
}
+ if (options.removeClass) {
+ classes += ' ' + options.removeClass;
+ }
+ }
- if(animationEvent == 'leave') {
- //there's no need to ever remove the listener since the element
- //will be removed (destroyed) after the leave animation ends or
- //is cancelled midway
- element.one('$destroy', function(e) {
- var element = angular.element(this);
- var state = element.data(NG_ANIMATE_STATE);
- if(state) {
- var activeLeaveAnimation = state.active['ng-leave'];
- if(activeLeaveAnimation) {
- activeLeaveAnimation.cancel();
- cleanup(element, 'ng-leave');
- }
- }
- });
+ var classesToAdd = options.addClass;
+ var classesToRemove = options.removeClass;
+
+ // the lookupAnimations function returns a series of animation objects that are
+ // matched up with one or more of the CSS classes. These animation objects are
+ // defined via the module.animation factory function. If nothing is detected then
+ // we don't return anything which then makes $animation query the next driver.
+ var animations = lookupAnimations(classes);
+ var before, after;
+ if (animations.length) {
+ var afterFn, beforeFn;
+ if (event == 'leave') {
+ beforeFn = 'leave';
+ afterFn = 'afterLeave'; // TODO(matsko): get rid of this
+ } else {
+ beforeFn = 'before' + event.charAt(0).toUpperCase() + event.substr(1);
+ afterFn = event;
+ }
+
+ if (event !== 'enter' && event !== 'move') {
+ before = packageAnimations(element, event, options, animations, beforeFn);
}
+ after = packageAnimations(element, event, options, animations, afterFn);
+ }
- //the ng-animate class does nothing, but it's here to allow for
- //parent animations to find and cancel child animations when needed
- element.addClass(NG_ANIMATE_CLASS_NAME);
+ // no matching animations
+ if (!before && !after) return;
- var localAnimationCount = globalAnimationCounter++;
- totalActiveAnimations++;
- runningAnimations[className] = runner;
+ function applyOptions() {
+ options.domOperation();
+ applyAnimationClasses(element, options);
+ }
- element.data(NG_ANIMATE_STATE, {
- last : runner,
- active : runningAnimations,
- index : localAnimationCount,
- totalActive : totalActiveAnimations
- });
+ return {
+ start: function() {
+ var closeActiveAnimations;
+ var chain = [];
- //first we run the before animations and when all of those are complete
- //then we perform the DOM operation and run the next set of animations
- fireBeforeCallbackAsync();
- runner.before(function(cancelled) {
- var data = element.data(NG_ANIMATE_STATE);
- cancelled = cancelled ||
- !data || !data.active[className] ||
- (runner.isClassBased && data.active[className].event != animationEvent);
-
- fireDOMOperation();
- if(cancelled === true) {
- closeAnimation();
+ if (before) {
+ chain.push(function(fn) {
+ closeActiveAnimations = before(fn);
+ });
+ }
+
+ if (chain.length) {
+ chain.push(function(fn) {
+ applyOptions();
+ fn(true);
+ });
} else {
- fireAfterCallbackAsync();
- runner.after(closeAnimation);
+ applyOptions();
}
- });
- function fireDOMCallback(animationPhase) {
- var eventName = '$animate:' + animationPhase;
- if(elementEvents && elementEvents[eventName] && elementEvents[eventName].length > 0) {
- $$asyncCallback(function() {
- element.triggerHandler(eventName, {
- event : animationEvent,
- className : className
- });
+ if (after) {
+ chain.push(function(fn) {
+ closeActiveAnimations = after(fn);
});
}
+
+ var animationClosed = false;
+ var runner = new $$AnimateRunner({
+ end: function() {
+ endAnimations();
+ },
+ cancel: function() {
+ endAnimations(true);
+ }
+ });
+
+ $$AnimateRunner.chain(chain, onComplete);
+ return runner;
+
+ function onComplete(success) {
+ animationClosed = true;
+ applyOptions();
+ applyAnimationStyles(element, options);
+ runner.complete(success);
+ }
+
+ function endAnimations(cancelled) {
+ if (!animationClosed) {
+ (closeActiveAnimations || noop)(cancelled);
+ onComplete(cancelled);
+ }
+ }
}
+ };
+
+ function executeAnimationFn(fn, element, event, options, onDone) {
+ var args;
+ switch (event) {
+ case 'animate':
+ args = [element, options.from, options.to, onDone];
+ break;
+
+ case 'setClass':
+ args = [element, classesToAdd, classesToRemove, onDone];
+ break;
+
+ case 'addClass':
+ args = [element, classesToAdd, onDone];
+ break;
+
+ case 'removeClass':
+ args = [element, classesToRemove, onDone];
+ break;
- function fireBeforeCallbackAsync() {
- fireDOMCallback('before');
+ default:
+ args = [element, onDone];
+ break;
}
- function fireAfterCallbackAsync() {
- fireDOMCallback('after');
+ args.push(options);
+
+ var value = fn.apply(fn, args);
+ if (value) {
+ if (isFunction(value.start)) {
+ value = value.start();
+ }
+
+ if (value instanceof $$AnimateRunner) {
+ value.done(onDone);
+ } else if (isFunction(value)) {
+ // optional onEnd / onCancel callback
+ return value;
+ }
}
- function fireDoneCallbackAsync() {
- fireDOMCallback('close');
- if(doneCallback) {
- $$asyncCallback(function() {
- doneCallback();
+ return noop;
+ }
+
+ function groupEventedAnimations(element, event, options, animations, fnName) {
+ var operations = [];
+ forEach(animations, function(ani) {
+ var animation = ani[fnName];
+ if (!animation) return;
+
+ // note that all of these animations will run in parallel
+ operations.push(function() {
+ var runner;
+ var endProgressCb;
+
+ var resolved = false;
+ var onAnimationComplete = function(rejected) {
+ if (!resolved) {
+ resolved = true;
+ (endProgressCb || noop)(rejected);
+ runner.complete(!rejected);
+ }
+ };
+
+ runner = new $$AnimateRunner({
+ end: function() {
+ onAnimationComplete();
+ },
+ cancel: function() {
+ onAnimationComplete(true);
+ }
+ });
+
+ endProgressCb = executeAnimationFn(animation, element, event, options, function(result) {
+ var cancelled = result === false;
+ onAnimationComplete(cancelled);
});
+
+ return runner;
+ });
+ });
+
+ return operations;
+ }
+
+ function packageAnimations(element, event, options, animations, fnName) {
+ var operations = groupEventedAnimations(element, event, options, animations, fnName);
+ if (operations.length === 0) {
+ var a,b;
+ if (fnName === 'beforeSetClass') {
+ a = groupEventedAnimations(element, 'removeClass', options, animations, 'beforeRemoveClass');
+ b = groupEventedAnimations(element, 'addClass', options, animations, 'beforeAddClass');
+ } else if (fnName === 'setClass') {
+ a = groupEventedAnimations(element, 'removeClass', options, animations, 'removeClass');
+ b = groupEventedAnimations(element, 'addClass', options, animations, 'addClass');
+ }
+
+ if (a) {
+ operations = operations.concat(a);
+ }
+ if (b) {
+ operations = operations.concat(b);
}
}
- //it is less complicated to use a flag than managing and canceling
- //timeouts containing multiple callbacks.
- function fireDOMOperation() {
- if(!fireDOMOperation.hasBeenRun) {
- fireDOMOperation.hasBeenRun = true;
- domOperation();
+ if (operations.length === 0) return;
+
+ // TODO(matsko): add documentation
+ return function startAnimation(callback) {
+ var runners = [];
+ if (operations.length) {
+ forEach(operations, function(animateFn) {
+ runners.push(animateFn());
+ });
}
+
+ runners.length ? $$AnimateRunner.all(runners, callback) : callback();
+
+ return function endFn(reject) {
+ forEach(runners, function(runner) {
+ reject ? runner.cancel() : runner.end();
+ });
+ };
+ };
+ }
+ };
+
+ function lookupAnimations(classes) {
+ classes = isArray(classes) ? classes : classes.split(' ');
+ var matches = [], flagMap = {};
+ for (var i=0; i < classes.length; i++) {
+ var klass = classes[i],
+ animationFactory = $animateProvider.$$registeredAnimations[klass];
+ if (animationFactory && !flagMap[klass]) {
+ matches.push($injector.get(animationFactory));
+ flagMap[klass] = true;
}
+ }
+ return matches;
+ }
+ }];
+}];
+
+var $$AnimateJsDriverProvider = ['$$animationProvider', function($$animationProvider) {
+ $$animationProvider.drivers.push('$$animateJsDriver');
+ this.$get = ['$$animateJs', '$$AnimateRunner', function($$animateJs, $$AnimateRunner) {
+ return function initDriverFn(animationDetails) {
+ if (animationDetails.from && animationDetails.to) {
+ var fromAnimation = prepareAnimation(animationDetails.from);
+ var toAnimation = prepareAnimation(animationDetails.to);
+ if (!fromAnimation && !toAnimation) return;
+
+ return {
+ start: function() {
+ var animationRunners = [];
+
+ if (fromAnimation) {
+ animationRunners.push(fromAnimation.start());
+ }
+
+ if (toAnimation) {
+ animationRunners.push(toAnimation.start());
+ }
- function closeAnimation() {
- if(!closeAnimation.hasBeenRun) {
- closeAnimation.hasBeenRun = true;
- var data = element.data(NG_ANIMATE_STATE);
- if(data) {
- /* only structural animations wait for reflow before removing an
- animation, but class-based animations don't. An example of this
- failing would be when a parent HTML tag has a ng-class attribute
- causing ALL directives below to skip animations during the digest */
- if(runner && runner.isClassBased) {
- cleanup(element, className);
- } else {
- $$asyncCallback(function() {
- var data = element.data(NG_ANIMATE_STATE) || {};
- if(localAnimationCount == data.index) {
- cleanup(element, className, animationEvent);
- }
+ $$AnimateRunner.all(animationRunners, done);
+
+ var runner = new $$AnimateRunner({
+ end: endFnFactory(),
+ cancel: endFnFactory()
+ });
+
+ return runner;
+
+ function endFnFactory() {
+ return function() {
+ forEach(animationRunners, function(runner) {
+ // at this point we cannot cancel animations for groups just yet. 1.5+
+ runner.end();
});
- element.data(NG_ANIMATE_STATE, data);
- }
+ };
+ }
+
+ function done(status) {
+ runner.complete(status);
}
- fireDoneCallbackAsync();
}
- }
+ };
+ } else {
+ return prepareAnimation(animationDetails);
}
+ };
- function cancelChildAnimations(element) {
- var node = extractElementNode(element);
- if (node) {
- var nodes = angular.isFunction(node.getElementsByClassName) ?
- node.getElementsByClassName(NG_ANIMATE_CLASS_NAME) :
- node.querySelectorAll('.' + NG_ANIMATE_CLASS_NAME);
- forEach(nodes, function(element) {
- element = angular.element(element);
- var data = element.data(NG_ANIMATE_STATE);
- if(data && data.active) {
- forEach(data.active, function(runner) {
- runner.cancel();
- });
+ function prepareAnimation(animationDetails) {
+ // TODO(matsko): make sure to check for grouped animations and delegate down to normal animations
+ var element = animationDetails.element;
+ var event = animationDetails.event;
+ var options = animationDetails.options;
+ var classes = animationDetails.classes;
+ return $$animateJs(element, event, classes, options);
+ }
+ }];
+}];
+
+var NG_ANIMATE_ATTR_NAME = 'data-ng-animate';
+var NG_ANIMATE_PIN_DATA = '$ngAnimatePin';
+var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
+ var PRE_DIGEST_STATE = 1;
+ var RUNNING_STATE = 2;
+
+ var rules = this.rules = {
+ skip: [],
+ cancel: [],
+ join: []
+ };
+
+ function isAllowed(ruleType, element, currentAnimation, previousAnimation) {
+ return rules[ruleType].some(function(fn) {
+ return fn(element, currentAnimation, previousAnimation);
+ });
+ }
+
+ function hasAnimationClasses(options, and) {
+ options = options || {};
+ var a = (options.addClass || '').length > 0;
+ var b = (options.removeClass || '').length > 0;
+ return and ? a && b : a || b;
+ }
+
+ rules.join.push(function(element, newAnimation, currentAnimation) {
+ // if the new animation is class-based then we can just tack that on
+ return !newAnimation.structural && hasAnimationClasses(newAnimation.options);
+ });
+
+ rules.skip.push(function(element, newAnimation, currentAnimation) {
+ // there is no need to animate anything if no classes are being added and
+ // there is no structural animation that will be triggered
+ return !newAnimation.structural && !hasAnimationClasses(newAnimation.options);
+ });
+
+ rules.skip.push(function(element, newAnimation, currentAnimation) {
+ // why should we trigger a new structural animation if the element will
+ // be removed from the DOM anyway?
+ return currentAnimation.event == 'leave' && newAnimation.structural;
+ });
+
+ rules.skip.push(function(element, newAnimation, currentAnimation) {
+ // if there is a current animation then skip the class-based animation
+ return currentAnimation.structural && !newAnimation.structural;
+ });
+
+ rules.cancel.push(function(element, newAnimation, currentAnimation) {
+ // there can never be two structural animations running at the same time
+ return currentAnimation.structural && newAnimation.structural;
+ });
+
+ rules.cancel.push(function(element, newAnimation, currentAnimation) {
+ // if the previous animation is already running, but the new animation will
+ // be triggered, but the new animation is structural
+ return currentAnimation.state === RUNNING_STATE && newAnimation.structural;
+ });
+
+ rules.cancel.push(function(element, newAnimation, currentAnimation) {
+ var nO = newAnimation.options;
+ var cO = currentAnimation.options;
+
+ // if the exact same CSS class is added/removed then it's safe to cancel it
+ return (nO.addClass && nO.addClass === cO.removeClass) || (nO.removeClass && nO.removeClass === cO.addClass);
+ });
+
+ this.$get = ['$$rAF', '$rootScope', '$rootElement', '$document', '$$HashMap',
+ '$$animation', '$$AnimateRunner', '$templateRequest', '$$jqLite',
+ function($$rAF, $rootScope, $rootElement, $document, $$HashMap,
+ $$animation, $$AnimateRunner, $templateRequest, $$jqLite) {
+
+ var activeAnimationsLookup = new $$HashMap();
+ var disabledElementsLookup = new $$HashMap();
+
+ var animationsEnabled = null;
+
+ // Wait until all directive and route-related templates are downloaded and
+ // compiled. The $templateRequest.totalPendingRequests variable keeps track of
+ // all of the remote templates being currently downloaded. If there are no
+ // templates currently downloading then the watcher will still fire anyway.
+ var deregisterWatch = $rootScope.$watch(
+ function() { return $templateRequest.totalPendingRequests === 0; },
+ function(isEmpty) {
+ if (!isEmpty) return;
+ deregisterWatch();
+
+ // Now that all templates have been downloaded, $animate will wait until
+ // the post digest queue is empty before enabling animations. By having two
+ // calls to $postDigest calls we can ensure that the flag is enabled at the
+ // very end of the post digest queue. Since all of the animations in $animate
+ // use $postDigest, it's important that the code below executes at the end.
+ // This basically means that the page is fully downloaded and compiled before
+ // any animations are triggered.
+ $rootScope.$$postDigest(function() {
+ $rootScope.$$postDigest(function() {
+ // we check for null directly in the event that the application already called
+ // .enabled() with whatever arguments that it provided it with
+ if (animationsEnabled === null) {
+ animationsEnabled = true;
}
});
- }
+ });
}
+ );
- function cleanup(element, className) {
- if(isMatchingElement(element, $rootElement)) {
- if(!rootAnimateState.disabled) {
- rootAnimateState.running = false;
- rootAnimateState.structural = false;
- }
- } else if(className) {
- var data = element.data(NG_ANIMATE_STATE) || {};
+ var bodyElement = jqLite($document[0].body);
- var removeAnimations = className === true;
- if(!removeAnimations && data.active && data.active[className]) {
- data.totalActive--;
- delete data.active[className];
- }
+ var callbackRegistry = {};
+
+ // remember that the classNameFilter is set during the provider/config
+ // stage therefore we can optimize here and setup a helper function
+ var classNameFilter = $animateProvider.classNameFilter();
+ var isAnimatableClassName = !classNameFilter
+ ? function() { return true; }
+ : function(className) {
+ return classNameFilter.test(className);
+ };
+
+ var applyAnimationClasses = applyAnimationClassesFactory($$jqLite);
+
+ function normalizeAnimationOptions(element, options) {
+ return mergeAnimationOptions(element, options, {});
+ }
- if(removeAnimations || !data.totalActive) {
- element.removeClass(NG_ANIMATE_CLASS_NAME);
- element.removeData(NG_ANIMATE_STATE);
+ function findCallbacks(element, event) {
+ var targetNode = getDomNode(element);
+
+ var matches = [];
+ var entries = callbackRegistry[event];
+ if (entries) {
+ forEach(entries, function(entry) {
+ if (entry.node.contains(targetNode)) {
+ matches.push(entry.callback);
}
- }
+ });
}
- function animationsDisabled(element, parentElement) {
- if (rootAnimateState.disabled) {
- return true;
- }
+ return matches;
+ }
+
+ function triggerCallback(event, element, phase, data) {
+ $$rAF(function() {
+ forEach(findCallbacks(element, event), function(callback) {
+ callback(element, phase, data);
+ });
+ });
+ }
- if (isMatchingElement(element, $rootElement)) {
- return rootAnimateState.running;
+ return {
+ on: function(event, container, callback) {
+ var node = extractElementNode(container);
+ callbackRegistry[event] = callbackRegistry[event] || [];
+ callbackRegistry[event].push({
+ node: node,
+ callback: callback
+ });
+ },
+
+ off: function(event, container, callback) {
+ var entries = callbackRegistry[event];
+ if (!entries) return;
+
+ callbackRegistry[event] = arguments.length === 1
+ ? null
+ : filterFromRegistry(entries, container, callback);
+
+ function filterFromRegistry(list, matchContainer, matchCallback) {
+ var containerNode = extractElementNode(matchContainer);
+ return list.filter(function(entry) {
+ var isMatch = entry.node === containerNode &&
+ (!matchCallback || entry.callback === matchCallback);
+ return !isMatch;
+ });
}
+ },
+
+ pin: function(element, parentElement) {
+ assertArg(isElement(element), 'element', 'not an element');
+ assertArg(isElement(parentElement), 'parentElement', 'not an element');
+ element.data(NG_ANIMATE_PIN_DATA, parentElement);
+ },
+
+ push: function(element, event, options, domOperation) {
+ options = options || {};
+ options.domOperation = domOperation;
+ return queueAnimation(element, event, options);
+ },
+
+ // this method has four signatures:
+ // () - global getter
+ // (bool) - global setter
+ // (element) - element getter
+ // (element, bool) - element setter<F37>
+ enabled: function(element, bool) {
+ var argCount = arguments.length;
+
+ if (argCount === 0) {
+ // () - Global getter
+ bool = !!animationsEnabled;
+ } else {
+ var hasElement = isElement(element);
- var allowChildAnimations, parentRunningAnimation, hasParent;
- do {
- //the element did not reach the root element which means that it
- //is not apart of the DOM. Therefore there is no reason to do
- //any animations on it
- if (parentElement.length === 0) break;
-
- var isRoot = isMatchingElement(parentElement, $rootElement);
- var state = isRoot ? rootAnimateState : (parentElement.data(NG_ANIMATE_STATE) || {});
- if (state.disabled) {
- return true;
+ if (!hasElement) {
+ // (bool) - Global setter
+ bool = animationsEnabled = !!element;
+ } else {
+ var node = getDomNode(element);
+ var recordExists = disabledElementsLookup.get(node);
+
+ if (argCount === 1) {
+ // (element) - Element getter
+ bool = !recordExists;
+ } else {
+ // (element, bool) - Element setter
+ bool = !!bool;
+ if (!bool) {
+ disabledElementsLookup.put(node, true);
+ } else if (recordExists) {
+ disabledElementsLookup.remove(node);
+ }
+ }
}
+ }
+
+ return bool;
+ }
+ };
+
+ function queueAnimation(element, event, options) {
+ var node, parent;
+ element = stripCommentsFromElement(element);
+ if (element) {
+ node = getDomNode(element);
+ parent = element.parent();
+ }
+
+ options = prepareAnimationOptions(options);
+
+ // we create a fake runner with a working promise.
+ // These methods will become available after the digest has passed
+ var runner = new $$AnimateRunner();
+
+ // there are situations where a directive issues an animation for
+ // a jqLite wrapper that contains only comment nodes... If this
+ // happens then there is no way we can perform an animation
+ if (!node) {
+ close();
+ return runner;
+ }
+
+ if (isArray(options.addClass)) {
+ options.addClass = options.addClass.join(' ');
+ }
+
+ if (isArray(options.removeClass)) {
+ options.removeClass = options.removeClass.join(' ');
+ }
+
+ if (options.from && !isObject(options.from)) {
+ options.from = null;
+ }
+
+ if (options.to && !isObject(options.to)) {
+ options.to = null;
+ }
+
+ var className = [node.className, options.addClass, options.removeClass].join(' ');
+ if (!isAnimatableClassName(className)) {
+ close();
+ return runner;
+ }
+
+ var isStructural = ['enter', 'move', 'leave'].indexOf(event) >= 0;
+
+ // this is a hard disable of all animations for the application or on
+ // the element itself, therefore there is no need to continue further
+ // past this point if not enabled
+ var skipAnimations = !animationsEnabled || disabledElementsLookup.get(node);
+ var existingAnimation = (!skipAnimations && activeAnimationsLookup.get(node)) || {};
+ var hasExistingAnimation = !!existingAnimation.state;
+
+ // there is no point in traversing the same collection of parent ancestors if a followup
+ // animation will be run on the same element that already did all that checking work
+ if (!skipAnimations && (!hasExistingAnimation || existingAnimation.state != PRE_DIGEST_STATE)) {
+ skipAnimations = !areAnimationsAllowed(element, parent, event);
+ }
+
+ if (skipAnimations) {
+ close();
+ return runner;
+ }
- //no matter what, for an animation to work it must reach the root element
- //this implies that the element is attached to the DOM when the animation is run
- if (isRoot) {
- hasParent = true;
+ if (isStructural) {
+ closeChildAnimations(element);
+ }
+
+ var newAnimation = {
+ structural: isStructural,
+ element: element,
+ event: event,
+ close: close,
+ options: options,
+ runner: runner
+ };
+
+ if (hasExistingAnimation) {
+ var skipAnimationFlag = isAllowed('skip', element, newAnimation, existingAnimation);
+ if (skipAnimationFlag) {
+ if (existingAnimation.state === RUNNING_STATE) {
+ close();
+ return runner;
+ } else {
+ mergeAnimationOptions(element, existingAnimation.options, options);
+ return existingAnimation.runner;
}
+ }
- //once a flag is found that is strictly false then everything before
- //it will be discarded and all child animations will be restricted
- if (allowChildAnimations !== false) {
- var animateChildrenFlag = parentElement.data(NG_ANIMATE_CHILDREN);
- if(angular.isDefined(animateChildrenFlag)) {
- allowChildAnimations = animateChildrenFlag;
+ var cancelAnimationFlag = isAllowed('cancel', element, newAnimation, existingAnimation);
+ if (cancelAnimationFlag) {
+ if (existingAnimation.state === RUNNING_STATE) {
+ // this will end the animation right away and it is safe
+ // to do so since the animation is already running and the
+ // runner callback code will run in async
+ existingAnimation.runner.end();
+ } else if (existingAnimation.structural) {
+ // this means that the animation is queued into a digest, but
+ // hasn't started yet. Therefore it is safe to run the close
+ // method which will call the runner methods in async.
+ existingAnimation.close();
+ } else {
+ // this will merge the existing animation options into this new follow-up animation
+ mergeAnimationOptions(element, newAnimation.options, existingAnimation.options);
+ }
+ } else {
+ // a joined animation means that this animation will take over the existing one
+ // so an example would involve a leave animation taking over an enter. Then when
+ // the postDigest kicks in the enter will be ignored.
+ var joinAnimationFlag = isAllowed('join', element, newAnimation, existingAnimation);
+ if (joinAnimationFlag) {
+ if (existingAnimation.state === RUNNING_STATE) {
+ normalizeAnimationOptions(element, options);
+ } else {
+ event = newAnimation.event = existingAnimation.event;
+ options = mergeAnimationOptions(element, existingAnimation.options, newAnimation.options);
+ return runner;
}
}
-
- parentRunningAnimation = parentRunningAnimation ||
- state.running ||
- (state.last && !state.last.isClassBased);
}
- while(parentElement = parentElement.parent());
-
- return !hasParent || (!allowChildAnimations && parentRunningAnimation);
- }
- }]);
-
- $animateProvider.register('', ['$window', '$sniffer', '$timeout', '$$animateReflow',
- function($window, $sniffer, $timeout, $$animateReflow) {
- // Detect proper transitionend/animationend event names.
- var CSS_PREFIX = '', TRANSITION_PROP, TRANSITIONEND_EVENT, ANIMATION_PROP, ANIMATIONEND_EVENT;
-
- // If unprefixed events are not supported but webkit-prefixed are, use the latter.
- // Otherwise, just use W3C names, browsers not supporting them at all will just ignore them.
- // Note: Chrome implements `window.onwebkitanimationend` and doesn't implement `window.onanimationend`
- // but at the same time dispatches the `animationend` event and not `webkitAnimationEnd`.
- // Register both events in case `window.onanimationend` is not supported because of that,
- // do the same for `transitionend` as Safari is likely to exhibit similar behavior.
- // Also, the only modern browser that uses vendor prefixes for transitions/keyframes is webkit
- // therefore there is no reason to test anymore for other vendor prefixes: http://caniuse.com/#search=transition
- if (window.ontransitionend === undefined && window.onwebkittransitionend !== undefined) {
- CSS_PREFIX = '-webkit-';
- TRANSITION_PROP = 'WebkitTransition';
- TRANSITIONEND_EVENT = 'webkitTransitionEnd transitionend';
} else {
- TRANSITION_PROP = 'transition';
- TRANSITIONEND_EVENT = 'transitionend';
+ // normalization in this case means that it removes redundant CSS classes that
+ // already exist (addClass) or do not exist (removeClass) on the element
+ normalizeAnimationOptions(element, options);
}
- if (window.onanimationend === undefined && window.onwebkitanimationend !== undefined) {
- CSS_PREFIX = '-webkit-';
- ANIMATION_PROP = 'WebkitAnimation';
- ANIMATIONEND_EVENT = 'webkitAnimationEnd animationend';
- } else {
- ANIMATION_PROP = 'animation';
- ANIMATIONEND_EVENT = 'animationend';
- }
-
- var DURATION_KEY = 'Duration';
- var PROPERTY_KEY = 'Property';
- var DELAY_KEY = 'Delay';
- var ANIMATION_ITERATION_COUNT_KEY = 'IterationCount';
- var NG_ANIMATE_PARENT_KEY = '$$ngAnimateKey';
- var NG_ANIMATE_CSS_DATA_KEY = '$$ngAnimateCSS3Data';
- var NG_ANIMATE_BLOCK_CLASS_NAME = 'ng-animate-block-transitions';
- var ELAPSED_TIME_MAX_DECIMAL_PLACES = 3;
- var CLOSING_TIME_BUFFER = 1.5;
- var ONE_SECOND = 1000;
-
- var lookupCache = {};
- var parentCounter = 0;
- var animationReflowQueue = [];
- var cancelAnimationReflow;
- function clearCacheAfterReflow() {
- if (!cancelAnimationReflow) {
- cancelAnimationReflow = $$animateReflow(function() {
- animationReflowQueue = [];
- cancelAnimationReflow = null;
- lookupCache = {};
- });
- }
+ // when the options are merged and cleaned up we may end up not having to do
+ // an animation at all, therefore we should check this before issuing a post
+ // digest callback. Structural animations will always run no matter what.
+ var isValidAnimation = newAnimation.structural;
+ if (!isValidAnimation) {
+ // animate (from/to) can be quickly checked first, otherwise we check if any classes are present
+ isValidAnimation = (newAnimation.event === 'animate' && Object.keys(newAnimation.options.to || {}).length > 0)
+ || hasAnimationClasses(newAnimation.options);
}
- function afterReflow(element, callback) {
- if(cancelAnimationReflow) {
- cancelAnimationReflow();
- }
- animationReflowQueue.push(callback);
- cancelAnimationReflow = $$animateReflow(function() {
- forEach(animationReflowQueue, function(fn) {
- fn();
- });
+ if (!isValidAnimation) {
+ close();
+ clearElementAnimationState(element);
+ return runner;
+ }
- animationReflowQueue = [];
- cancelAnimationReflow = null;
- lookupCache = {};
- });
+ if (isStructural) {
+ closeParentClassBasedAnimations(parent);
}
- var closingTimer = null;
- var closingTimestamp = 0;
- var animationElementQueue = [];
- function animationCloseHandler(element, totalTime) {
- var node = extractElementNode(element);
- element = angular.element(node);
+ // the counter keeps track of cancelled animations
+ var counter = (existingAnimation.counter || 0) + 1;
+ newAnimation.counter = counter;
+
+ markElementAnimationState(element, PRE_DIGEST_STATE, newAnimation);
+
+ $rootScope.$$postDigest(function() {
+ var animationDetails = activeAnimationsLookup.get(node);
+ var animationCancelled = !animationDetails;
+ animationDetails = animationDetails || {};
+
+ // if addClass/removeClass is called before something like enter then the
+ // registered parent element may not be present. The code below will ensure
+ // that a final value for parent element is obtained
+ var parentElement = element.parent() || [];
+
+ // animate/structural/class-based animations all have requirements. Otherwise there
+ // is no point in performing an animation. The parent node must also be set.
+ var isValidAnimation = parentElement.length > 0
+ && (animationDetails.event === 'animate'
+ || animationDetails.structural
+ || hasAnimationClasses(animationDetails.options));
+
+ // this means that the previous animation was cancelled
+ // even if the follow-up animation is the same event
+ if (animationCancelled || animationDetails.counter !== counter || !isValidAnimation) {
+ // if another animation did not take over then we need
+ // to make sure that the domOperation and options are
+ // handled accordingly
+ if (animationCancelled) {
+ applyAnimationClasses(element, options);
+ applyAnimationStyles(element, options);
+ }
+
+ // if the event changed from something like enter to leave then we do
+ // it, otherwise if it's the same then the end result will be the same too
+ if (animationCancelled || (isStructural && animationDetails.event !== event)) {
+ options.domOperation();
+ runner.end();
+ }
- //this item will be garbage collected by the closing
- //animation timeout
- animationElementQueue.push(element);
+ // in the event that the element animation was not cancelled or a follow-up animation
+ // isn't allowed to animate from here then we need to clear the state of the element
+ // so that any future animations won't read the expired animation data.
+ if (!isValidAnimation) {
+ clearElementAnimationState(element);
+ }
- //but it may not need to cancel out the existing timeout
- //if the timestamp is less than the previous one
- var futureTimestamp = Date.now() + totalTime;
- if(futureTimestamp <= closingTimestamp) {
return;
}
- $timeout.cancel(closingTimer);
+ // this combined multiple class to addClass / removeClass into a setClass event
+ // so long as a structural event did not take over the animation
+ event = !animationDetails.structural && hasAnimationClasses(animationDetails.options, true)
+ ? 'setClass'
+ : animationDetails.event;
- closingTimestamp = futureTimestamp;
- closingTimer = $timeout(function() {
- closeAllAnimations(animationElementQueue);
- animationElementQueue = [];
- }, totalTime, false);
- }
+ if (animationDetails.structural) {
+ closeParentClassBasedAnimations(parentElement);
+ }
- function closeAllAnimations(elements) {
- forEach(elements, function(element) {
- var elementData = element.data(NG_ANIMATE_CSS_DATA_KEY);
- if(elementData) {
- (elementData.closeAnimationFn || noop)();
+ markElementAnimationState(element, RUNNING_STATE);
+ var realRunner = $$animation(element, event, animationDetails.options);
+ realRunner.done(function(status) {
+ close(!status);
+ var animationDetails = activeAnimationsLookup.get(node);
+ if (animationDetails && animationDetails.counter === counter) {
+ clearElementAnimationState(getDomNode(element));
}
+ notifyProgress(runner, event, 'close', {});
});
- }
- function getElementAnimationDetails(element, cacheKey) {
- var data = cacheKey ? lookupCache[cacheKey] : null;
- if(!data) {
- var transitionDuration = 0;
- var transitionDelay = 0;
- var animationDuration = 0;
- var animationDelay = 0;
- var transitionDelayStyle;
- var animationDelayStyle;
- var transitionDurationStyle;
- var transitionPropertyStyle;
+ // this will update the runner's flow-control events based on
+ // the `realRunner` object.
+ runner.setHost(realRunner);
+ notifyProgress(runner, event, 'start', {});
+ });
- //we want all the styles defined before and after
- forEach(element, function(element) {
- if (element.nodeType == ELEMENT_NODE) {
- var elementStyles = $window.getComputedStyle(element) || {};
+ return runner;
- transitionDurationStyle = elementStyles[TRANSITION_PROP + DURATION_KEY];
+ function notifyProgress(runner, event, phase, data) {
+ triggerCallback(event, element, phase, data);
+ runner.progress(event, phase, data);
+ }
- transitionDuration = Math.max(parseMaxTime(transitionDurationStyle), transitionDuration);
+ function close(reject) { // jshint ignore:line
+ applyAnimationClasses(element, options);
+ applyAnimationStyles(element, options);
+ options.domOperation();
+ runner.complete(!reject);
+ }
+ }
- transitionPropertyStyle = elementStyles[TRANSITION_PROP + PROPERTY_KEY];
+ function closeChildAnimations(element) {
+ var node = getDomNode(element);
+ var children = node.querySelectorAll('[' + NG_ANIMATE_ATTR_NAME + ']');
+ forEach(children, function(child) {
+ var state = parseInt(child.getAttribute(NG_ANIMATE_ATTR_NAME));
+ var animationDetails = activeAnimationsLookup.get(child);
+ switch (state) {
+ case RUNNING_STATE:
+ animationDetails.runner.end();
+ /* falls through */
+ case PRE_DIGEST_STATE:
+ if (animationDetails) {
+ activeAnimationsLookup.remove(child);
+ }
+ break;
+ }
+ });
+ }
- transitionDelayStyle = elementStyles[TRANSITION_PROP + DELAY_KEY];
+ function clearElementAnimationState(element) {
+ var node = getDomNode(element);
+ node.removeAttribute(NG_ANIMATE_ATTR_NAME);
+ activeAnimationsLookup.remove(node);
+ }
- transitionDelay = Math.max(parseMaxTime(transitionDelayStyle), transitionDelay);
+ function isMatchingElement(nodeOrElmA, nodeOrElmB) {
+ return getDomNode(nodeOrElmA) === getDomNode(nodeOrElmB);
+ }
- animationDelayStyle = elementStyles[ANIMATION_PROP + DELAY_KEY];
+ function closeParentClassBasedAnimations(startingElement) {
+ var parentNode = getDomNode(startingElement);
+ do {
+ if (!parentNode || parentNode.nodeType !== ELEMENT_NODE) break;
- animationDelay = Math.max(parseMaxTime(animationDelayStyle), animationDelay);
+ var animationDetails = activeAnimationsLookup.get(parentNode);
+ if (animationDetails) {
+ examineParentAnimation(parentNode, animationDetails);
+ }
- var aDuration = parseMaxTime(elementStyles[ANIMATION_PROP + DURATION_KEY]);
+ parentNode = parentNode.parentNode;
+ } while (true);
- if(aDuration > 0) {
- aDuration *= parseInt(elementStyles[ANIMATION_PROP + ANIMATION_ITERATION_COUNT_KEY], 10) || 1;
- }
+ // since animations are detected from CSS classes, we need to flush all parent
+ // class-based animations so that the parent classes are all present for child
+ // animations to properly function (otherwise any CSS selectors may not work)
+ function examineParentAnimation(node, animationDetails) {
+ // enter/leave/move always have priority
+ if (animationDetails.structural || !hasAnimationClasses(animationDetails.options)) return;
- animationDuration = Math.max(aDuration, animationDuration);
- }
- });
- data = {
- total : 0,
- transitionPropertyStyle: transitionPropertyStyle,
- transitionDurationStyle: transitionDurationStyle,
- transitionDelayStyle: transitionDelayStyle,
- transitionDelay: transitionDelay,
- transitionDuration: transitionDuration,
- animationDelayStyle: animationDelayStyle,
- animationDelay: animationDelay,
- animationDuration: animationDuration
- };
- if(cacheKey) {
- lookupCache[cacheKey] = data;
- }
+ if (animationDetails.state === RUNNING_STATE) {
+ animationDetails.runner.end();
}
- return data;
+ clearElementAnimationState(node);
}
+ }
- function parseMaxTime(str) {
- var maxValue = 0;
- var values = angular.isString(str) ?
- str.split(/\s*,\s*/) :
- [];
- forEach(values, function(value) {
- maxValue = Math.max(parseFloat(value) || 0, maxValue);
- });
- return maxValue;
+ function areAnimationsAllowed(element, parentElement, event) {
+ var bodyElementDetected = false;
+ var rootElementDetected = false;
+ var parentAnimationDetected = false;
+ var animateChildren;
+
+ var parentHost = element.data(NG_ANIMATE_PIN_DATA);
+ if (parentHost) {
+ parentElement = parentHost;
}
- function getCacheKey(element) {
- var parentElement = element.parent();
- var parentID = parentElement.data(NG_ANIMATE_PARENT_KEY);
- if(!parentID) {
- parentElement.data(NG_ANIMATE_PARENT_KEY, ++parentCounter);
- parentID = parentCounter;
+ while (parentElement && parentElement.length) {
+ if (!rootElementDetected) {
+ // angular doesn't want to attempt to animate elements outside of the application
+ // therefore we need to ensure that the rootElement is an ancestor of the current element
+ rootElementDetected = isMatchingElement(parentElement, $rootElement);
}
- return parentID + '-' + extractElementNode(element).getAttribute('class');
- }
- function animateSetup(animationEvent, element, className, calculationDecorator) {
- var cacheKey = getCacheKey(element);
- var eventCacheKey = cacheKey + ' ' + className;
- var itemIndex = lookupCache[eventCacheKey] ? ++lookupCache[eventCacheKey].total : 0;
+ var parentNode = parentElement[0];
+ if (parentNode.nodeType !== ELEMENT_NODE) {
+ // no point in inspecting the #document element
+ break;
+ }
- var stagger = {};
- if(itemIndex > 0) {
- var staggerClassName = className + '-stagger';
- var staggerCacheKey = cacheKey + ' ' + staggerClassName;
- var applyClasses = !lookupCache[staggerCacheKey];
+ var details = activeAnimationsLookup.get(parentNode) || {};
+ // either an enter, leave or move animation will commence
+ // therefore we can't allow any animations to take place
+ // but if a parent animation is class-based then that's ok
+ if (!parentAnimationDetected) {
+ parentAnimationDetected = details.structural || disabledElementsLookup.get(parentNode);
+ }
- applyClasses && element.addClass(staggerClassName);
+ if (isUndefined(animateChildren) || animateChildren === true) {
+ var value = parentElement.data(NG_ANIMATE_CHILDREN_DATA);
+ if (isDefined(value)) {
+ animateChildren = value;
+ }
+ }
- stagger = getElementAnimationDetails(element, staggerCacheKey);
+ // there is no need to continue traversing at this point
+ if (parentAnimationDetected && animateChildren === false) break;
+
+ if (!rootElementDetected) {
+ // angular doesn't want to attempt to animate elements outside of the application
+ // therefore we need to ensure that the rootElement is an ancestor of the current element
+ rootElementDetected = isMatchingElement(parentElement, $rootElement);
+ if (!rootElementDetected) {
+ parentHost = parentElement.data(NG_ANIMATE_PIN_DATA);
+ if (parentHost) {
+ parentElement = parentHost;
+ }
+ }
+ }
- applyClasses && element.removeClass(staggerClassName);
+ if (!bodyElementDetected) {
+ // we also need to ensure that the element is or will be apart of the body element
+ // otherwise it is pointless to even issue an animation to be rendered
+ bodyElementDetected = isMatchingElement(parentElement, bodyElement);
}
- /* the animation itself may need to add/remove special CSS classes
- * before calculating the anmation styles */
- calculationDecorator = calculationDecorator ||
- function(fn) { return fn(); };
+ parentElement = parentElement.parent();
+ }
+
+ var allowAnimation = !parentAnimationDetected || animateChildren;
+ return allowAnimation && rootElementDetected && bodyElementDetected;
+ }
- element.addClass(className);
+ function markElementAnimationState(element, state, details) {
+ details = details || {};
+ details.state = state;
- var formerData = element.data(NG_ANIMATE_CSS_DATA_KEY) || {};
+ var node = getDomNode(element);
+ node.setAttribute(NG_ANIMATE_ATTR_NAME, state);
- var timings = calculationDecorator(function() {
- return getElementAnimationDetails(element, eventCacheKey);
- });
+ var oldValue = activeAnimationsLookup.get(node);
+ var newValue = oldValue
+ ? extend(oldValue, details)
+ : details;
+ activeAnimationsLookup.put(node, newValue);
+ }
+ }];
+}];
+
+var $$rAFMutexFactory = ['$$rAF', function($$rAF) {
+ return function() {
+ var passed = false;
+ $$rAF(function() {
+ passed = true;
+ });
+ return function(fn) {
+ passed ? fn() : $$rAF(fn);
+ };
+ };
+}];
+
+var $$AnimateRunnerFactory = ['$q', '$$rAFMutex', function($q, $$rAFMutex) {
+ var INITIAL_STATE = 0;
+ var DONE_PENDING_STATE = 1;
+ var DONE_COMPLETE_STATE = 2;
+
+ AnimateRunner.chain = function(chain, callback) {
+ var index = 0;
+
+ next();
+ function next() {
+ if (index === chain.length) {
+ callback(true);
+ return;
+ }
- var transitionDuration = timings.transitionDuration;
- var animationDuration = timings.animationDuration;
- if(transitionDuration === 0 && animationDuration === 0) {
- element.removeClass(className);
- return false;
+ chain[index](function(response) {
+ if (response === false) {
+ callback(false);
+ return;
}
+ index++;
+ next();
+ });
+ }
+ };
+
+ AnimateRunner.all = function(runners, callback) {
+ var count = 0;
+ var status = true;
+ forEach(runners, function(runner) {
+ runner.done(onProgress);
+ });
+
+ function onProgress(response) {
+ status = status && response;
+ if (++count === runners.length) {
+ callback(status);
+ }
+ }
+ };
+
+ function AnimateRunner(host) {
+ this.setHost(host);
+
+ this._doneCallbacks = [];
+ this._runInAnimationFrame = $$rAFMutex();
+ this._state = 0;
+ }
+
+ AnimateRunner.prototype = {
+ setHost: function(host) {
+ this.host = host || {};
+ },
- element.data(NG_ANIMATE_CSS_DATA_KEY, {
- running : formerData.running || 0,
- itemIndex : itemIndex,
- stagger : stagger,
- timings : timings,
- closeAnimationFn : noop
+ done: function(fn) {
+ if (this._state === DONE_COMPLETE_STATE) {
+ fn();
+ } else {
+ this._doneCallbacks.push(fn);
+ }
+ },
+
+ progress: noop,
+
+ getPromise: function() {
+ if (!this.promise) {
+ var self = this;
+ this.promise = $q(function(resolve, reject) {
+ self.done(function(status) {
+ status === false ? reject() : resolve();
+ });
});
+ }
+ return this.promise;
+ },
- //temporarily disable the transition so that the enter styles
- //don't animate twice (this is here to avoid a bug in Chrome/FF).
- var isCurrentlyAnimating = formerData.running > 0 || animationEvent == 'setClass';
- if(transitionDuration > 0) {
- blockTransitions(element, className, isCurrentlyAnimating);
- }
+ then: function(resolveHandler, rejectHandler) {
+ return this.getPromise().then(resolveHandler, rejectHandler);
+ },
- //staggering keyframe animations work by adjusting the `animation-delay` CSS property
- //on the given element, however, the delay value can only calculated after the reflow
- //since by that time $animate knows how many elements are being animated. Therefore,
- //until the reflow occurs the element needs to be blocked (where the keyframe animation
- //is set to `none 0s`). This blocking mechanism should only be set for when a stagger
- //animation is detected and when the element item index is greater than 0.
- if(animationDuration > 0 && stagger.animationDelay > 0 && stagger.animationDuration === 0) {
- blockKeyframeAnimations(element);
- }
+ 'catch': function(handler) {
+ return this.getPromise()['catch'](handler);
+ },
+
+ 'finally': function(handler) {
+ return this.getPromise()['finally'](handler);
+ },
- return true;
+ pause: function() {
+ if (this.host.pause) {
+ this.host.pause();
}
+ },
- function isStructuralAnimation(className) {
- return className == 'ng-enter' || className == 'ng-move' || className == 'ng-leave';
+ resume: function() {
+ if (this.host.resume) {
+ this.host.resume();
}
+ },
- function blockTransitions(element, className, isAnimating) {
- if(isStructuralAnimation(className) || !isAnimating) {
- extractElementNode(element).style[TRANSITION_PROP + PROPERTY_KEY] = 'none';
- } else {
- element.addClass(NG_ANIMATE_BLOCK_CLASS_NAME);
- }
+ end: function() {
+ if (this.host.end) {
+ this.host.end();
}
+ this._resolve(true);
+ },
- function blockKeyframeAnimations(element) {
- extractElementNode(element).style[ANIMATION_PROP] = 'none 0s';
+ cancel: function() {
+ if (this.host.cancel) {
+ this.host.cancel();
}
+ this._resolve(false);
+ },
+
+ complete: function(response) {
+ var self = this;
+ if (self._state === INITIAL_STATE) {
+ self._state = DONE_PENDING_STATE;
+ self._runInAnimationFrame(function() {
+ self._resolve(response);
+ });
+ }
+ },
- function unblockTransitions(element, className) {
- var prop = TRANSITION_PROP + PROPERTY_KEY;
- var node = extractElementNode(element);
- if(node.style[prop] && node.style[prop].length > 0) {
- node.style[prop] = '';
- }
- element.removeClass(NG_ANIMATE_BLOCK_CLASS_NAME);
+ _resolve: function(response) {
+ if (this._state !== DONE_COMPLETE_STATE) {
+ forEach(this._doneCallbacks, function(fn) {
+ fn(response);
+ });
+ this._doneCallbacks.length = 0;
+ this._state = DONE_COMPLETE_STATE;
}
+ }
+ };
- function unblockKeyframeAnimations(element) {
- var prop = ANIMATION_PROP;
- var node = extractElementNode(element);
- if(node.style[prop] && node.style[prop].length > 0) {
- node.style[prop] = '';
- }
+ return AnimateRunner;
+}];
+
+var $$AnimationProvider = ['$animateProvider', function($animateProvider) {
+ var NG_ANIMATE_REF_ATTR = 'ng-animate-ref';
+
+ var drivers = this.drivers = [];
+
+ var RUNNER_STORAGE_KEY = '$$animationRunner';
+
+ function setRunner(element, runner) {
+ element.data(RUNNER_STORAGE_KEY, runner);
+ }
+
+ function removeRunner(element) {
+ element.removeData(RUNNER_STORAGE_KEY);
+ }
+
+ function getRunner(element) {
+ return element.data(RUNNER_STORAGE_KEY);
+ }
+
+ this.$get = ['$$jqLite', '$rootScope', '$injector', '$$AnimateRunner', '$$rAFScheduler',
+ function($$jqLite, $rootScope, $injector, $$AnimateRunner, $$rAFScheduler) {
+
+ var animationQueue = [];
+ var applyAnimationClasses = applyAnimationClassesFactory($$jqLite);
+
+ var totalPendingClassBasedAnimations = 0;
+ var totalActiveClassBasedAnimations = 0;
+ var classBasedAnimationsQueue = [];
+
+ // TODO(matsko): document the signature in a better way
+ return function(element, event, options) {
+ options = prepareAnimationOptions(options);
+ var isStructural = ['enter', 'move', 'leave'].indexOf(event) >= 0;
+
+ // there is no animation at the current moment, however
+ // these runner methods will get later updated with the
+ // methods leading into the driver's end/cancel methods
+ // for now they just stop the animation from starting
+ var runner = new $$AnimateRunner({
+ end: function() { close(); },
+ cancel: function() { close(true); }
+ });
+
+ if (!drivers.length) {
+ close();
+ return runner;
}
- function animateRun(animationEvent, element, className, activeAnimationComplete) {
- var node = extractElementNode(element);
- var elementData = element.data(NG_ANIMATE_CSS_DATA_KEY);
- if(node.getAttribute('class').indexOf(className) == -1 || !elementData) {
- activeAnimationComplete();
- return;
- }
+ setRunner(element, runner);
+
+ var classes = mergeClasses(element.attr('class'), mergeClasses(options.addClass, options.removeClass));
+ var tempClasses = options.tempClasses;
+ if (tempClasses) {
+ classes += ' ' + tempClasses;
+ options.tempClasses = null;
+ }
+
+ var classBasedIndex;
+ if (!isStructural) {
+ classBasedIndex = totalPendingClassBasedAnimations;
+ totalPendingClassBasedAnimations += 1;
+ }
+
+ animationQueue.push({
+ // this data is used by the postDigest code and passed into
+ // the driver step function
+ element: element,
+ classes: classes,
+ event: event,
+ classBasedIndex: classBasedIndex,
+ structural: isStructural,
+ options: options,
+ beforeStart: beforeStart,
+ close: close
+ });
+
+ element.on('$destroy', handleDestroyedElement);
- var activeClassName = '';
- forEach(className.split(' '), function(klass, i) {
- activeClassName += (i > 0 ? ' ' : '') + klass + '-active';
+ // we only want there to be one function called within the post digest
+ // block. This way we can group animations for all the animations that
+ // were apart of the same postDigest flush call.
+ if (animationQueue.length > 1) return runner;
+
+ $rootScope.$$postDigest(function() {
+ totalActiveClassBasedAnimations = totalPendingClassBasedAnimations;
+ totalPendingClassBasedAnimations = 0;
+ classBasedAnimationsQueue.length = 0;
+
+ var animations = [];
+ forEach(animationQueue, function(entry) {
+ // the element was destroyed early on which removed the runner
+ // form its storage. This means we can't animate this element
+ // at all and it already has been closed due to destruction.
+ if (getRunner(entry.element)) {
+ animations.push(entry);
+ }
});
- var stagger = elementData.stagger;
- var timings = elementData.timings;
- var itemIndex = elementData.itemIndex;
- var maxDuration = Math.max(timings.transitionDuration, timings.animationDuration);
- var maxDelay = Math.max(timings.transitionDelay, timings.animationDelay);
- var maxDelayTime = maxDelay * ONE_SECOND;
-
- var startTime = Date.now();
- var css3AnimationEvents = ANIMATIONEND_EVENT + ' ' + TRANSITIONEND_EVENT;
-
- var style = '', appliedStyles = [];
- if(timings.transitionDuration > 0) {
- var propertyStyle = timings.transitionPropertyStyle;
- if(propertyStyle.indexOf('all') == -1) {
- style += CSS_PREFIX + 'transition-property: ' + propertyStyle + ';';
- style += CSS_PREFIX + 'transition-duration: ' + timings.transitionDurationStyle + ';';
- appliedStyles.push(CSS_PREFIX + 'transition-property');
- appliedStyles.push(CSS_PREFIX + 'transition-duration');
+ // now any future animations will be in another postDigest
+ animationQueue.length = 0;
+
+ forEach(groupAnimations(animations), function(animationEntry) {
+ if (animationEntry.structural) {
+ triggerAnimationStart();
+ } else {
+ classBasedAnimationsQueue.push({
+ node: getDomNode(animationEntry.element),
+ fn: triggerAnimationStart
+ });
+
+ if (animationEntry.classBasedIndex === totalActiveClassBasedAnimations - 1) {
+ // we need to sort each of the animations in order of parent to child
+ // relationships. This ensures that the child classes are applied at the
+ // right time.
+ classBasedAnimationsQueue = classBasedAnimationsQueue.sort(function(a,b) {
+ return b.node.contains(a.node);
+ }).map(function(entry) {
+ return entry.fn;
+ });
+
+ $$rAFScheduler(classBasedAnimationsQueue);
+ }
}
- }
- if(itemIndex > 0) {
- if(stagger.transitionDelay > 0 && stagger.transitionDuration === 0) {
- var delayStyle = timings.transitionDelayStyle;
- style += CSS_PREFIX + 'transition-delay: ' +
- prepareStaggerDelay(delayStyle, stagger.transitionDelay, itemIndex) + '; ';
- appliedStyles.push(CSS_PREFIX + 'transition-delay');
+ function triggerAnimationStart() {
+ // it's important that we apply the `ng-animate` CSS class and the
+ // temporary classes before we do any driver invoking since these
+ // CSS classes may be required for proper CSS detection.
+ animationEntry.beforeStart();
+
+ var startAnimationFn, closeFn = animationEntry.close;
+
+ // in the event that the element was removed before the digest runs or
+ // during the RAF sequencing then we should not trigger the animation.
+ var targetElement = animationEntry.anchors
+ ? (animationEntry.from.element || animationEntry.to.element)
+ : animationEntry.element;
+
+ if (getRunner(targetElement) && getDomNode(targetElement).parentNode) {
+ var operation = invokeFirstDriver(animationEntry);
+ if (operation) {
+ startAnimationFn = operation.start;
+ }
+ }
+
+ if (!startAnimationFn) {
+ closeFn();
+ } else {
+ var animationRunner = startAnimationFn();
+ animationRunner.done(function(status) {
+ closeFn(!status);
+ });
+ updateAnimationRunners(animationEntry, animationRunner);
+ }
}
+ });
+ });
- if(stagger.animationDelay > 0 && stagger.animationDuration === 0) {
- style += CSS_PREFIX + 'animation-delay: ' +
- prepareStaggerDelay(timings.animationDelayStyle, stagger.animationDelay, itemIndex) + '; ';
- appliedStyles.push(CSS_PREFIX + 'animation-delay');
+ return runner;
+
+ // TODO(matsko): change to reference nodes
+ function getAnchorNodes(node) {
+ var SELECTOR = '[' + NG_ANIMATE_REF_ATTR + ']';
+ var items = node.hasAttribute(NG_ANIMATE_REF_ATTR)
+ ? [node]
+ : node.querySelectorAll(SELECTOR);
+ var anchors = [];
+ forEach(items, function(node) {
+ var attr = node.getAttribute(NG_ANIMATE_REF_ATTR);
+ if (attr && attr.length) {
+ anchors.push(node);
}
- }
+ });
+ return anchors;
+ }
- if(appliedStyles.length > 0) {
- //the element being animated may sometimes contain comment nodes in
- //the jqLite object, so we're safe to use a single variable to house
- //the styles since there is always only one element being animated
- var oldStyle = node.getAttribute('style') || '';
- node.setAttribute('style', oldStyle + '; ' + style);
- }
+ function groupAnimations(animations) {
+ var preparedAnimations = [];
+ var refLookup = {};
+ forEach(animations, function(animation, index) {
+ var element = animation.element;
+ var node = getDomNode(element);
+ var event = animation.event;
+ var enterOrMove = ['enter', 'move'].indexOf(event) >= 0;
+ var anchorNodes = animation.structural ? getAnchorNodes(node) : [];
+
+ if (anchorNodes.length) {
+ var direction = enterOrMove ? 'to' : 'from';
+
+ forEach(anchorNodes, function(anchor) {
+ var key = anchor.getAttribute(NG_ANIMATE_REF_ATTR);
+ refLookup[key] = refLookup[key] || {};
+ refLookup[key][direction] = {
+ animationID: index,
+ element: jqLite(anchor)
+ };
+ });
+ } else {
+ preparedAnimations.push(animation);
+ }
+ });
- element.on(css3AnimationEvents, onAnimationProgress);
- element.addClass(activeClassName);
- elementData.closeAnimationFn = function() {
- onEnd();
- activeAnimationComplete();
- };
+ var usedIndicesLookup = {};
+ var anchorGroups = {};
+ forEach(refLookup, function(operations, key) {
+ var from = operations.from;
+ var to = operations.to;
+
+ if (!from || !to) {
+ // only one of these is set therefore we can't have an
+ // anchor animation since all three pieces are required
+ var index = from ? from.animationID : to.animationID;
+ var indexKey = index.toString();
+ if (!usedIndicesLookup[indexKey]) {
+ usedIndicesLookup[indexKey] = true;
+ preparedAnimations.push(animations[index]);
+ }
+ return;
+ }
+
+ var fromAnimation = animations[from.animationID];
+ var toAnimation = animations[to.animationID];
+ var lookupKey = from.animationID.toString();
+ if (!anchorGroups[lookupKey]) {
+ var group = anchorGroups[lookupKey] = {
+ structural: true,
+ beforeStart: function() {
+ fromAnimation.beforeStart();
+ toAnimation.beforeStart();
+ },
+ close: function() {
+ fromAnimation.close();
+ toAnimation.close();
+ },
+ classes: cssClassesIntersection(fromAnimation.classes, toAnimation.classes),
+ from: fromAnimation,
+ to: toAnimation,
+ anchors: [] // TODO(matsko): change to reference nodes
+ };
- var staggerTime = itemIndex * (Math.max(stagger.animationDelay, stagger.transitionDelay) || 0);
- var animationTime = (maxDelay + maxDuration) * CLOSING_TIME_BUFFER;
- var totalTime = (staggerTime + animationTime) * ONE_SECOND;
-
- elementData.running++;
- animationCloseHandler(element, totalTime);
- return onEnd;
-
- // This will automatically be called by $animate so
- // there is no need to attach this internally to the
- // timeout done method.
- function onEnd(cancelled) {
- element.off(css3AnimationEvents, onAnimationProgress);
- element.removeClass(activeClassName);
- animateClose(element, className);
- var node = extractElementNode(element);
- for (var i in appliedStyles) {
- node.style.removeProperty(appliedStyles[i]);
+ // the anchor animations require that the from and to elements both have at least
+ // one shared CSS class which effictively marries the two elements together to use
+ // the same animation driver and to properly sequence the anchor animation.
+ if (group.classes.length) {
+ preparedAnimations.push(group);
+ } else {
+ preparedAnimations.push(fromAnimation);
+ preparedAnimations.push(toAnimation);
+ }
}
- }
- function onAnimationProgress(event) {
- event.stopPropagation();
- var ev = event.originalEvent || event;
- var timeStamp = ev.$manualTimeStamp || ev.timeStamp || Date.now();
+ anchorGroups[lookupKey].anchors.push({
+ 'out': from.element, 'in': to.element
+ });
+ });
- /* Firefox (or possibly just Gecko) likes to not round values up
- * when a ms measurement is used for the animation */
- var elapsedTime = parseFloat(ev.elapsedTime.toFixed(ELAPSED_TIME_MAX_DECIMAL_PLACES));
+ return preparedAnimations;
+ }
- /* $manualTimeStamp is a mocked timeStamp value which is set
- * within browserTrigger(). This is only here so that tests can
- * mock animations properly. Real events fallback to event.timeStamp,
- * or, if they don't, then a timeStamp is automatically created for them.
- * We're checking to see if the timeStamp surpasses the expected delay,
- * but we're using elapsedTime instead of the timeStamp on the 2nd
- * pre-condition since animations sometimes close off early */
- if(Math.max(timeStamp - startTime, 0) >= maxDelayTime && elapsedTime >= maxDuration) {
- activeAnimationComplete();
+ function cssClassesIntersection(a,b) {
+ a = a.split(' ');
+ b = b.split(' ');
+ var matches = [];
+
+ for (var i = 0; i < a.length; i++) {
+ var aa = a[i];
+ if (aa.substring(0,3) === 'ng-') continue;
+
+ for (var j = 0; j < b.length; j++) {
+ if (aa === b[j]) {
+ matches.push(aa);
+ break;
+ }
}
}
+
+ return matches.join(' ');
}
- function prepareStaggerDelay(delayStyle, staggerDelay, index) {
- var style = '';
- forEach(delayStyle.split(','), function(val, i) {
- style += (i > 0 ? ',' : '') +
- (index * staggerDelay + parseInt(val, 10)) + 's';
- });
- return style;
+ function invokeFirstDriver(animationDetails) {
+ // we loop in reverse order since the more general drivers (like CSS and JS)
+ // may attempt more elements, but custom drivers are more particular
+ for (var i = drivers.length - 1; i >= 0; i--) {
+ var driverName = drivers[i];
+ if (!$injector.has(driverName)) continue; // TODO(matsko): remove this check
+
+ var factory = $injector.get(driverName);
+ var driver = factory(animationDetails);
+ if (driver) {
+ return driver;
+ }
+ }
}
- function animateBefore(animationEvent, element, className, calculationDecorator) {
- if(animateSetup(animationEvent, element, className, calculationDecorator)) {
- return function(cancelled) {
- cancelled && animateClose(element, className);
- };
+ function beforeStart() {
+ element.addClass(NG_ANIMATE_CLASSNAME);
+ if (tempClasses) {
+ $$jqLite.addClass(element, tempClasses);
}
}
- function animateAfter(animationEvent, element, className, afterAnimationComplete) {
- if(element.data(NG_ANIMATE_CSS_DATA_KEY)) {
- return animateRun(animationEvent, element, className, afterAnimationComplete);
+ function updateAnimationRunners(animation, newRunner) {
+ if (animation.from && animation.to) {
+ update(animation.from.element);
+ update(animation.to.element);
} else {
- animateClose(element, className);
- afterAnimationComplete();
+ update(animation.element);
+ }
+
+ function update(element) {
+ getRunner(element).setHost(newRunner);
}
}
- function animate(animationEvent, element, className, animationComplete) {
- //If the animateSetup function doesn't bother returning a
- //cancellation function then it means that there is no animation
- //to perform at all
- var preReflowCancellation = animateBefore(animationEvent, element, className);
- if (!preReflowCancellation) {
- clearCacheAfterReflow();
- animationComplete();
- return;
+ function handleDestroyedElement() {
+ var runner = getRunner(element);
+ if (runner && (event !== 'leave' || !options.$$domOperationFired)) {
+ runner.end();
}
+ }
- //There are two cancellation functions: one is before the first
- //reflow animation and the second is during the active state
- //animation. The first function will take care of removing the
- //data from the element which will not make the 2nd animation
- //happen in the first place
- var cancel = preReflowCancellation;
- afterReflow(element, function() {
- unblockTransitions(element, className);
- unblockKeyframeAnimations(element);
- //once the reflow is complete then we point cancel to
- //the new cancellation function which will remove all of the
- //animation properties from the active animation
- cancel = animateAfter(animationEvent, element, className, animationComplete);
- });
+ function close(rejected) { // jshint ignore:line
+ element.off('$destroy', handleDestroyedElement);
+ removeRunner(element);
- return function(cancelled) {
- (cancel || noop)(cancelled);
- };
- }
+ applyAnimationClasses(element, options);
+ applyAnimationStyles(element, options);
+ options.domOperation();
- function animateClose(element, className) {
- element.removeClass(className);
- var data = element.data(NG_ANIMATE_CSS_DATA_KEY);
- if(data) {
- if(data.running) {
- data.running--;
- }
- if(!data.running || data.running === 0) {
- element.removeData(NG_ANIMATE_CSS_DATA_KEY);
- }
+ if (tempClasses) {
+ $$jqLite.removeClass(element, tempClasses);
}
+
+ element.removeClass(NG_ANIMATE_CLASSNAME);
+ runner.complete(!rejected);
}
+ };
+ }];
+}];
+
+/* global angularAnimateModule: true,
+
+ $$rAFMutexFactory,
+ $$rAFSchedulerFactory,
+ $$AnimateChildrenDirective,
+ $$AnimateRunnerFactory,
+ $$AnimateQueueProvider,
+ $$AnimationProvider,
+ $AnimateCssProvider,
+ $$AnimateCssDriverProvider,
+ $$AnimateJsProvider,
+ $$AnimateJsDriverProvider,
+*/
- return {
- enter : function(element, animationCompleted) {
- return animate('enter', element, 'ng-enter', animationCompleted);
- },
-
- leave : function(element, animationCompleted) {
- return animate('leave', element, 'ng-leave', animationCompleted);
- },
-
- move : function(element, animationCompleted) {
- return animate('move', element, 'ng-move', animationCompleted);
- },
-
- beforeSetClass : function(element, add, remove, animationCompleted) {
- var className = suffixClasses(remove, '-remove') + ' ' +
- suffixClasses(add, '-add');
- var cancellationMethod = animateBefore('setClass', element, className, function(fn) {
- /* when classes are removed from an element then the transition style
- * that is applied is the transition defined on the element without the
- * CSS class being there. This is how CSS3 functions outside of ngAnimate.
- * http://plnkr.co/edit/j8OzgTNxHTb4n3zLyjGW?p=preview */
- var klass = element.attr('class');
- element.removeClass(remove);
- element.addClass(add);
- var timings = fn();
- element.attr('class', klass);
- return timings;
+/**
+ * @ngdoc module
+ * @name ngAnimate
+ * @description
+ *
+ * The `ngAnimate` module provides support for CSS-based animations (keyframes and transitions) as well as JavaScript-based animations via
+ * callback hooks. Animations are not enabled by default, however, by including `ngAnimate` then the animation hooks are enabled for an Angular app.
+ *
+ * <div doc-module-components="ngAnimate"></div>
+ *
+ * # Usage
+ * Simply put, there are two ways to make use of animations when ngAnimate is used: by using **CSS** and **JavaScript**. The former works purely based
+ * using CSS (by using matching CSS selectors/styles) and the latter triggers animations that are registered via `module.animation()`. For
+ * both CSS and JS animations the sole requirement is to have a matching `CSS class` that exists both in the registered animation and within
+ * the HTML element that the animation will be triggered on.
+ *
+ * ## Directive Support
+ * The following directives are "animation aware":
+ *
+ * | Directive | Supported Animations |
+ * |----------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------|
+ * | {@link ng.directive:ngRepeat#animations ngRepeat} | enter, leave and move |
+ * | {@link ngRoute.directive:ngView#animations ngView} | enter and leave |
+ * | {@link ng.directive:ngInclude#animations ngInclude} | enter and leave |
+ * | {@link ng.directive:ngSwitch#animations ngSwitch} | enter and leave |
+ * | {@link ng.directive:ngIf#animations ngIf} | enter and leave |
+ * | {@link ng.directive:ngClass#animations ngClass} | add and remove (the CSS class(es) present) |
+ * | {@link ng.directive:ngShow#animations ngShow} & {@link ng.directive:ngHide#animations ngHide} | add and remove (the ng-hide class value) |
+ * | {@link ng.directive:form#animation-hooks form} & {@link ng.directive:ngModel#animation-hooks ngModel} | add and remove (dirty, pristine, valid, invalid & all other validations) |
+ * | {@link module:ngMessages#animations ngMessages} | add and remove (ng-active & ng-inactive) |
+ * | {@link module:ngMessages#animations ngMessage} | enter and leave |
+ *
+ * (More information can be found by visiting each the documentation associated with each directive.)
+ *
+ * ## CSS-based Animations
+ *
+ * CSS-based animations with ngAnimate are unique since they require no JavaScript code at all. By using a CSS class that we reference between our HTML
+ * and CSS code we can create an animation that will be picked up by Angular when an the underlying directive performs an operation.
+ *
+ * The example below shows how an `enter` animation can be made possible on a element using `ng-if`:
+ *
+ * ```html
+ * <div ng-if="bool" class="fade">
+ * Fade me in out
+ * </div>
+ * <button ng-click="bool=true">Fade In!</button>
+ * <button ng-click="bool=false">Fade Out!</button>
+ * ```
+ *
+ * Notice the CSS class **fade**? We can now create the CSS transition code that references this class:
+ *
+ * ```css
+ * /&#42; The starting CSS styles for the enter animation &#42;/
+ * .fade.ng-enter {
+ * transition:0.5s linear all;
+ * opacity:0;
+ * }
+ *
+ * /&#42; The finishing CSS styles for the enter animation &#42;/
+ * .fade.ng-enter.ng-enter-active {
+ * opacity:1;
+ * }
+ * ```
+ *
+ * The key thing to remember here is that, depending on the animation event (which each of the directives above trigger depending on what's going on) two
+ * generated CSS classes will be applied to the element; in the example above we have `.ng-enter` and `.ng-enter-active`. For CSS transitions, the transition
+ * code **must** be defined within the starting CSS class (in this case `.ng-enter`). The destination class is what the transition will animate towards.
+ *
+ * If for example we wanted to create animations for `leave` and `move` (ngRepeat triggers move) then we can do so using the same CSS naming conventions:
+ *
+ * ```css
+ * /&#42; now the element will fade out before it is removed from the DOM &#42;/
+ * .fade.ng-leave {
+ * transition:0.5s linear all;
+ * opacity:1;
+ * }
+ * .fade.ng-leave.ng-leave-active {
+ * opacity:0;
+ * }
+ * ```
+ *
+ * We can also make use of **CSS Keyframes** by referencing the keyframe animation within the starting CSS class:
+ *
+ * ```css
+ * /&#42; there is no need to define anything inside of the destination
+ * CSS class since the keyframe will take charge of the animation &#42;/
+ * .fade.ng-leave {
+ * animation: my_fade_animation 0.5s linear;
+ * -webkit-animation: my_fade_animation 0.5s linear;
+ * }
+ *
+ * @keyframes my_fade_animation {
+ * from { opacity:1; }
+ * to { opacity:0; }
+ * }
+ *
+ * @-webkit-keyframes my_fade_animation {
+ * from { opacity:1; }
+ * to { opacity:0; }
+ * }
+ * ```
+ *
+ * Feel free also mix transitions and keyframes together as well as any other CSS classes on the same element.
+ *
+ * ### CSS Class-based Animations
+ *
+ * Class-based animations (animations that are triggered via `ngClass`, `ngShow`, `ngHide` and some other directives) have a slightly different
+ * naming convention. Class-based animations are basic enough that a standard transition or keyframe can be referenced on the class being added
+ * and removed.
+ *
+ * For example if we wanted to do a CSS animation for `ngHide` then we place an animation on the `.ng-hide` CSS class:
+ *
+ * ```html
+ * <div ng-show="bool" class="fade">
+ * Show and hide me
+ * </div>
+ * <button ng-click="bool=true">Toggle</button>
+ *
+ * <style>
+ * .fade.ng-hide {
+ * transition:0.5s linear all;
+ * opacity:0;
+ * }
+ * </style>
+ * ```
+ *
+ * All that is going on here with ngShow/ngHide behind the scenes is the `.ng-hide` class is added/removed (when the hidden state is valid). Since
+ * ngShow and ngHide are animation aware then we can match up a transition and ngAnimate handles the rest.
+ *
+ * In addition the addition and removal of the CSS class, ngAnimate also provides two helper methods that we can use to further decorate the animation
+ * with CSS styles.
+ *
+ * ```html
+ * <div ng-class="{on:onOff}" class="highlight">
+ * Highlight this box
+ * </div>
+ * <button ng-click="onOff=!onOff">Toggle</button>
+ *
+ * <style>
+ * .highlight {
+ * transition:0.5s linear all;
+ * }
+ * .highlight.on-add {
+ * background:white;
+ * }
+ * .highlight.on {
+ * background:yellow;
+ * }
+ * .highlight.on-remove {
+ * background:black;
+ * }
+ * </style>
+ * ```
+ *
+ * We can also make use of CSS keyframes by placing them within the CSS classes.
+ *
+ *
+ * ### CSS Staggering Animations
+ * A Staggering animation is a collection of animations that are issued with a slight delay in between each successive operation resulting in a
+ * curtain-like effect. The ngAnimate module (versions >=1.2) supports staggering animations and the stagger effect can be
+ * performed by creating a **ng-EVENT-stagger** CSS class and attaching that class to the base CSS class used for
+ * the animation. The style property expected within the stagger class can either be a **transition-delay** or an
+ * **animation-delay** property (or both if your animation contains both transitions and keyframe animations).
+ *
+ * ```css
+ * .my-animation.ng-enter {
+ * /&#42; standard transition code &#42;/
+ * transition: 1s linear all;
+ * opacity:0;
+ * }
+ * .my-animation.ng-enter-stagger {
+ * /&#42; this will have a 100ms delay between each successive leave animation &#42;/
+ * transition-delay: 0.1s;
+ *
+ * /&#42; in case the stagger doesn't work then the duration value
+ * must be set to 0 to avoid an accidental CSS inheritance &#42;/
+ * transition-duration: 0s;
+ * }
+ * .my-animation.ng-enter.ng-enter-active {
+ * /&#42; standard transition styles &#42;/
+ * opacity:1;
+ * }
+ * ```
+ *
+ * Staggering animations work by default in ngRepeat (so long as the CSS class is defined). Outside of ngRepeat, to use staggering animations
+ * on your own, they can be triggered by firing multiple calls to the same event on $animate. However, the restrictions surrounding this
+ * are that each of the elements must have the same CSS className value as well as the same parent element. A stagger operation
+ * will also be reset if one or more animation frames have passed since the multiple calls to `$animate` were fired.
+ *
+ * The following code will issue the **ng-leave-stagger** event on the element provided:
+ *
+ * ```js
+ * var kids = parent.children();
+ *
+ * $animate.leave(kids[0]); //stagger index=0
+ * $animate.leave(kids[1]); //stagger index=1
+ * $animate.leave(kids[2]); //stagger index=2
+ * $animate.leave(kids[3]); //stagger index=3
+ * $animate.leave(kids[4]); //stagger index=4
+ *
+ * window.requestAnimationFrame(function() {
+ * //stagger has reset itself
+ * $animate.leave(kids[5]); //stagger index=0
+ * $animate.leave(kids[6]); //stagger index=1
+ *
+ * $scope.$digest();
+ * });
+ * ```
+ *
+ * Stagger animations are currently only supported within CSS-defined animations.
+ *
+ * ### The `ng-animate` CSS class
+ *
+ * When ngAnimate is animating an element it will apply the `ng-animate` CSS class to the element for the duration of the animation.
+ * This is a temporary CSS class and it will be removed once the animation is over (for both JavaScript and CSS-based animations).
+ *
+ * Therefore, animations can be applied to an element using this temporary class directly via CSS.
+ *
+ * ```css
+ * .zipper.ng-animate {
+ * transition:0.5s linear all;
+ * }
+ * .zipper.ng-enter {
+ * opacity:0;
+ * }
+ * .zipper.ng-enter.ng-enter-active {
+ * opacity:1;
+ * }
+ * .zipper.ng-leave {
+ * opacity:1;
+ * }
+ * .zipper.ng-leave.ng-leave-active {
+ * opacity:0;
+ * }
+ * ```
+ *
+ * (Note that the `ng-animate` CSS class is reserved and it cannot be applied on an element directly since ngAnimate will always remove
+ * the CSS class once an animation has completed.)
+ *
+ *
+ * ## JavaScript-based Animations
+ *
+ * ngAnimate also allows for animations to be consumed by JavaScript code. The approach is similar to CSS-based animations (where there is a shared
+ * CSS class that is referenced in our HTML code) but in addition we need to register the JavaScript animation on the module. By making use of the
+ * `module.animation()` module function we can register the ainmation.
+ *
+ * Let's see an example of a enter/leave animation using `ngRepeat`:
+ *
+ * ```html
+ * <div ng-repeat="item in items" class="slide">
+ * {{ item }}
+ * </div>
+ * ```
+ *
+ * See the **slide** CSS class? Let's use that class to define an animation that we'll structure in our module code by using `module.animation`:
+ *
+ * ```js
+ * myModule.animation('.slide', [function() {
+ * return {
+ * // make note that other events (like addClass/removeClass)
+ * // have different function input parameters
+ * enter: function(element, doneFn) {
+ * jQuery(element).fadeIn(1000, doneFn);
+ *
+ * // remember to call doneFn so that angular
+ * // knows that the animation has concluded
+ * },
+ *
+ * move: function(element, doneFn) {
+ * jQuery(element).fadeIn(1000, doneFn);
+ * },
+ *
+ * leave: function(element, doneFn) {
+ * jQuery(element).fadeOut(1000, doneFn);
+ * }
+ * }
+ * }]
+ * ```
+ *
+ * The nice thing about JS-based animations is that we can inject other services and make use of advanced animation libraries such as
+ * greensock.js and velocity.js.
+ *
+ * If our animation code class-based (meaning that something like `ngClass`, `ngHide` and `ngShow` triggers it) then we can still define
+ * our animations inside of the same registered animation, however, the function input arguments are a bit different:
+ *
+ * ```html
+ * <div ng-class="color" class="colorful">
+ * this box is moody
+ * </div>
+ * <button ng-click="color='red'">Change to red</button>
+ * <button ng-click="color='blue'">Change to blue</button>
+ * <button ng-click="color='green'">Change to green</button>
+ * ```
+ *
+ * ```js
+ * myModule.animation('.colorful', [function() {
+ * return {
+ * addClass: function(element, className, doneFn) {
+ * // do some cool animation and call the doneFn
+ * },
+ * removeClass: function(element, className, doneFn) {
+ * // do some cool animation and call the doneFn
+ * },
+ * setClass: function(element, addedClass, removedClass, doneFn) {
+ * // do some cool animation and call the doneFn
+ * }
+ * }
+ * }]
+ * ```
+ *
+ * ## CSS + JS Animations Together
+ *
+ * AngularJS 1.4 and higher has taken steps to make the amalgamation of CSS and JS animations more flexible. However, unlike earlier versions of Angular,
+ * defining CSS and JS animations to work off of the same CSS class will not work anymore. Therefore the example below will only result in **JS animations taking
+ * charge of the animation**:
+ *
+ * ```html
+ * <div ng-if="bool" class="slide">
+ * Slide in and out
+ * </div>
+ * ```
+ *
+ * ```js
+ * myModule.animation('.slide', [function() {
+ * return {
+ * enter: function(element, doneFn) {
+ * jQuery(element).slideIn(1000, doneFn);
+ * }
+ * }
+ * }]
+ * ```
+ *
+ * ```css
+ * .slide.ng-enter {
+ * transition:0.5s linear all;
+ * transform:translateY(-100px);
+ * }
+ * .slide.ng-enter.ng-enter-active {
+ * transform:translateY(0);
+ * }
+ * ```
+ *
+ * Does this mean that CSS and JS animations cannot be used together? Do JS-based animations always have higher priority? We can make up for the
+ * lack of CSS animations by using the `$animateCss` service to trigger our own tweaked-out, CSS-based animations directly from
+ * our own JS-based animation code:
+ *
+ * ```js
+ * myModule.animation('.slide', ['$animateCss', function($animateCss) {
+ * return {
+ * enter: function(element, doneFn) {
+* // this will trigger `.slide.ng-enter` and `.slide.ng-enter-active`.
+ * var runner = $animateCss(element, {
+ * event: 'enter',
+ * structural: true
+ * }).start();
+* runner.done(doneFn);
+ * }
+ * }
+ * }]
+ * ```
+ *
+ * The nice thing here is that we can save bandwidth by sticking to our CSS-based animation code and we don't need to rely on a 3rd-party animation framework.
+ *
+ * The `$animateCss` service is very powerful since we can feed in all kinds of extra properties that will be evaluated and fed into a CSS transition or
+ * keyframe animation. For example if we wanted to animate the height of an element while adding and removing classes then we can do so by providing that
+ * data into `$animateCss` directly:
+ *
+ * ```js
+ * myModule.animation('.slide', ['$animateCss', function($animateCss) {
+ * return {
+ * enter: function(element, doneFn) {
+ * var runner = $animateCss(element, {
+ * event: 'enter',
+ * addClass: 'maroon-setting',
+ * from: { height:0 },
+ * to: { height: 200 }
+ * }).start();
+ *
+ * runner.done(doneFn);
+ * }
+ * }
+ * }]
+ * ```
+ *
+ * Now we can fill in the rest via our transition CSS code:
+ *
+ * ```css
+ * /&#42; the transition tells ngAnimate to make the animation happen &#42;/
+ * .slide.ng-enter { transition:0.5s linear all; }
+ *
+ * /&#42; this extra CSS class will be absorbed into the transition
+ * since the $animateCss code is adding the class &#42;/
+ * .maroon-setting { background:red; }
+ * ```
+ *
+ * And `$animateCss` will figure out the rest. Just make sure to have the `done()` callback fire the `doneFn` function to signal when the animation is over.
+ *
+ * To learn more about what's possible be sure to visit the {@link ngAnimate.$animateCss $animateCss service}.
+ *
+ * ## Animation Anchoring (via `ng-animate-ref`)
+ *
+ * ngAnimate in AngularJS 1.4 comes packed with the ability to cross-animate elements between
+ * structural areas of an application (like views) by pairing up elements using an attribute
+ * called `ng-animate-ref`.
+ *
+ * Let's say for example we have two views that are managed by `ng-view` and we want to show
+ * that there is a relationship between two components situated in within these views. By using the
+ * `ng-animate-ref` attribute we can identify that the two components are paired together and we
+ * can then attach an animation, which is triggered when the view changes.
+ *
+ * Say for example we have the following template code:
+ *
+ * ```html
+ * <!-- index.html -->
+ * <div ng-view class="view-animation">
+ * </div>
+ *
+ * <!-- home.html -->
+ * <a href="#/banner-page">
+ * <img src="./banner.jpg" class="banner" ng-animate-ref="banner">
+ * </a>
+ *
+ * <!-- banner-page.html -->
+ * <img src="./banner.jpg" class="banner" ng-animate-ref="banner">
+ * ```
+ *
+ * Now, when the view changes (once the link is clicked), ngAnimate will examine the
+ * HTML contents to see if there is a match reference between any components in the view
+ * that is leaving and the view that is entering. It will scan both the view which is being
+ * removed (leave) and inserted (enter) to see if there are any paired DOM elements that
+ * contain a matching ref value.
+ *
+ * The two images match since they share the same ref value. ngAnimate will now create a
+ * transport element (which is a clone of the first image element) and it will then attempt
+ * to animate to the position of the second image element in the next view. For the animation to
+ * work a special CSS class called `ng-anchor` will be added to the transported element.
+ *
+ * We can now attach a transition onto the `.banner.ng-anchor` CSS class and then
+ * ngAnimate will handle the entire transition for us as well as the addition and removal of
+ * any changes of CSS classes between the elements:
+ *
+ * ```css
+ * .banner.ng-anchor {
+ * /&#42; this animation will last for 1 second since there are
+ * two phases to the animation (an `in` and an `out` phase) &#42;/
+ * transition:0.5s linear all;
+ * }
+ * ```
+ *
+ * We also **must** include animations for the views that are being entered and removed
+ * (otherwise anchoring wouldn't be possible since the new view would be inserted right away).
+ *
+ * ```css
+ * .view-animation.ng-enter, .view-animation.ng-leave {
+ * transition:0.5s linear all;
+ * position:fixed;
+ * left:0;
+ * top:0;
+ * width:100%;
+ * }
+ * .view-animation.ng-enter {
+ * transform:translateX(100%);
+ * }
+ * .view-animation.ng-leave,
+ * .view-animation.ng-enter.ng-enter-active {
+ * transform:translateX(0%);
+ * }
+ * .view-animation.ng-leave.ng-leave-active {
+ * transform:translateX(-100%);
+ * }
+ * ```
+ *
+ * Now we can jump back to the anchor animation. When the animation happens, there are two stages that occur:
+ * an `out` and an `in` stage. The `out` stage happens first and that is when the element is animated away
+ * from its origin. Once that animation is over then the `in` stage occurs which animates the
+ * element to its destination. The reason why there are two animations is to give enough time
+ * for the enter animation on the new element to be ready.
+ *
+ * The example above sets up a transition for both the in and out phases, but we can also target the out or
+ * in phases directly via `ng-anchor-out` and `ng-anchor-in`.
+ *
+ * ```css
+ * .banner.ng-anchor-out {
+ * transition: 0.5s linear all;
+ *
+ * /&#42; the scale will be applied during the out animation,
+ * but will be animated away when the in animation runs &#42;/
+ * transform: scale(1.2);
+ * }
+ *
+ * .banner.ng-anchor-in {
+ * transition: 1s linear all;
+ * }
+ * ```
+ *
+ *
+ *
+ *
+ * ### Anchoring Demo
+ *
+ <example module="anchoringExample"
+ name="anchoringExample"
+ id="anchoringExample"
+ deps="angular-animate.js;angular-route.js"
+ animations="true">
+ <file name="index.html">
+ <a href="#/">Home</a>
+ <hr />
+ <div class="view-container">
+ <div ng-view class="view"></div>
+ </div>
+ </file>
+ <file name="script.js">
+ angular.module('anchoringExample', ['ngAnimate', 'ngRoute'])
+ .config(['$routeProvider', function($routeProvider) {
+ $routeProvider.when('/', {
+ templateUrl: 'home.html',
+ controller: 'HomeController as home'
});
-
- if(cancellationMethod) {
- afterReflow(element, function() {
- unblockTransitions(element, className);
- unblockKeyframeAnimations(element);
- animationCompleted();
- });
- return cancellationMethod;
- }
- clearCacheAfterReflow();
- animationCompleted();
- },
-
- beforeAddClass : function(element, className, animationCompleted) {
- var cancellationMethod = animateBefore('addClass', element, suffixClasses(className, '-add'), function(fn) {
-
- /* when a CSS class is added to an element then the transition style that
- * is applied is the transition defined on the element when the CSS class
- * is added at the time of the animation. This is how CSS3 functions
- * outside of ngAnimate. */
- element.addClass(className);
- var timings = fn();
- element.removeClass(className);
- return timings;
+ $routeProvider.when('/profile/:id', {
+ templateUrl: 'profile.html',
+ controller: 'ProfileController as profile'
});
+ }])
+ .run(['$rootScope', function($rootScope) {
+ $rootScope.records = [
+ { id:1, title: "Miss Beulah Roob" },
+ { id:2, title: "Trent Morissette" },
+ { id:3, title: "Miss Ava Pouros" },
+ { id:4, title: "Rod Pouros" },
+ { id:5, title: "Abdul Rice" },
+ { id:6, title: "Laurie Rutherford Sr." },
+ { id:7, title: "Nakia McLaughlin" },
+ { id:8, title: "Jordon Blanda DVM" },
+ { id:9, title: "Rhoda Hand" },
+ { id:10, title: "Alexandrea Sauer" }
+ ];
+ }])
+ .controller('HomeController', [function() {
+ //empty
+ }])
+ .controller('ProfileController', ['$rootScope', '$routeParams', function($rootScope, $routeParams) {
+ var index = parseInt($routeParams.id, 10);
+ var record = $rootScope.records[index - 1];
+
+ this.title = record.title;
+ this.id = record.id;
+ }]);
+ </file>
+ <file name="home.html">
+ <h2>Welcome to the home page</h1>
+ <p>Please click on an element</p>
+ <a class="record"
+ ng-href="#/profile/{{ record.id }}"
+ ng-animate-ref="{{ record.id }}"
+ ng-repeat="record in records">
+ {{ record.title }}
+ </a>
+ </file>
+ <file name="profile.html">
+ <div class="profile record" ng-animate-ref="{{ profile.id }}">
+ {{ profile.title }}
+ </div>
+ </file>
+ <file name="animations.css">
+ .record {
+ display:block;
+ font-size:20px;
+ }
+ .profile {
+ background:black;
+ color:white;
+ font-size:100px;
+ }
+ .view-container {
+ position:relative;
+ }
+ .view-container > .view.ng-animate {
+ position:absolute;
+ top:0;
+ left:0;
+ width:100%;
+ min-height:500px;
+ }
+ .view.ng-enter, .view.ng-leave,
+ .record.ng-anchor {
+ transition:0.5s linear all;
+ }
+ .view.ng-enter {
+ transform:translateX(100%);
+ }
+ .view.ng-enter.ng-enter-active, .view.ng-leave {
+ transform:translateX(0%);
+ }
+ .view.ng-leave.ng-leave-active {
+ transform:translateX(-100%);
+ }
+ .record.ng-anchor-out {
+ background:red;
+ }
+ </file>
+ </example>
+ *
+ * ### How is the element transported?
+ *
+ * When an anchor animation occurs, ngAnimate will clone the starting element and position it exactly where the starting
+ * element is located on screen via absolute positioning. The cloned element will be placed inside of the root element
+ * of the application (where ng-app was defined) and all of the CSS classes of the starting element will be applied. The
+ * element will then animate into the `out` and `in` animations and will eventually reach the coordinates and match
+ * the dimensions of the destination element. During the entire animation a CSS class of `.ng-animate-shim` will be applied
+ * to both the starting and destination elements in order to hide them from being visible (the CSS styling for the class
+ * is: `visibility:hidden`). Once the anchor reaches its destination then it will be removed and the destination element
+ * will become visible since the shim class will be removed.
+ *
+ * ### How is the morphing handled?
+ *
+ * CSS Anchoring relies on transitions and keyframes and the internal code is intelligent enough to figure out
+ * what CSS classes differ between the starting element and the destination element. These different CSS classes
+ * will be added/removed on the anchor element and a transition will be applied (the transition that is provided
+ * in the anchor class). Long story short, ngAnimate will figure out what classes to add and remove which will
+ * make the transition of the element as smooth and automatic as possible. Be sure to use simple CSS classes that
+ * do not rely on DOM nesting structure so that the anchor element appears the same as the starting element (since
+ * the cloned element is placed inside of root element which is likely close to the body element).
+ *
+ * Note that if the root element is on the `<html>` element then the cloned node will be placed inside of body.
+ *
+ *
+ * ## Using $animate in your directive code
+ *
+ * So far we've explored how to feed in animations into an Angular application, but how do we trigger animations within our own directives in our application?
+ * By injecting the `$animate` service into our directive code, we can trigger structural and class-based hooks which can then be consumed by animations. Let's
+ * imagine we have a greeting box that shows and hides itself when the data changes
+ *
+ * ```html
+ * <greeting-box active="onOrOff">Hi there</greeting-box>
+ * ```
+ *
+ * ```js
+ * ngModule.directive('greetingBox', ['$animate', function($animate) {
+ * return function(scope, element, attrs) {
+ * attrs.$observe('active', function(value) {
+ * value ? $animate.addClass(element, 'on') : $animate.removeClass(element, 'on');
+ * });
+ * });
+ * }]);
+ * ```
+ *
+ * Now the `on` CSS class is added and removed on the greeting box component. Now if we add a CSS class on top of the greeting box element
+ * in our HTML code then we can trigger a CSS or JS animation to happen.
+ *
+ * ```css
+ * /&#42; normally we would create a CSS class to reference on the element &#42;/
+ * greeting-box.on { transition:0.5s linear all; background:green; color:white; }
+ * ```
+ *
+ * The `$animate` service contains a variety of other methods like `enter`, `leave`, `animate` and `setClass`. To learn more about what's
+ * possible be sure to visit the {@link ng.$animate $animate service API page}.
+ *
+ *
+ * ### Preventing Collisions With Third Party Libraries
+ *
+ * Some third-party frameworks place animation duration defaults across many element or className
+ * selectors in order to make their code small and reuseable. This can lead to issues with ngAnimate, which
+ * is expecting actual animations on these elements and has to wait for their completion.
+ *
+ * You can prevent this unwanted behavior by using a prefix on all your animation classes:
+ *
+ * ```css
+ * /&#42; prefixed with animate- &#42;/
+ * .animate-fade-add.animate-fade-add-active {
+ * transition:1s linear all;
+ * opacity:0;
+ * }
+ * ```
+ *
+ * You then configure `$animate` to enforce this prefix:
+ *
+ * ```js
+ * $animateProvider.classNameFilter(/animate-/);
+ * ```
+ *
+ * This also may provide your application with a speed boost since only specific elements containing CSS class prefix
+ * will be evaluated for animation when any DOM changes occur in the application.
+ *
+ * ## Callbacks and Promises
+ *
+ * When `$animate` is called it returns a promise that can be used to capture when the animation has ended. Therefore if we were to trigger
+ * an animation (within our directive code) then we can continue performing directive and scope related activities after the animation has
+ * ended by chaining onto the returned promise that animation method returns.
+ *
+ * ```js
+ * // somewhere within the depths of the directive
+ * $animate.enter(element, parent).then(function() {
+ * //the animation has completed
+ * });
+ * ```
+ *
+ * (Note that earlier versions of Angular prior to v1.4 required the promise code to be wrapped using `$scope.$apply(...)`. This is not the case
+ * anymore.)
+ *
+ * In addition to the animation promise, we can also make use of animation-related callbacks within our directives and controller code by registering
+ * an event listener using the `$animate` service. Let's say for example that an animation was triggered on our view
+ * routing controller to hook into that:
+ *
+ * ```js
+ * ngModule.controller('HomePageController', ['$animate', function($animate) {
+ * $animate.on('enter', ngViewElement, function(element) {
+ * // the animation for this route has completed
+ * }]);
+ * }])
+ * ```
+ *
+ * (Note that you will need to trigger a digest within the callback to get angular to notice any scope-related changes.)
+ */
- if(cancellationMethod) {
- afterReflow(element, function() {
- unblockTransitions(element, className);
- unblockKeyframeAnimations(element);
- animationCompleted();
- });
- return cancellationMethod;
- }
- clearCacheAfterReflow();
- animationCompleted();
- },
-
- setClass : function(element, add, remove, animationCompleted) {
- remove = suffixClasses(remove, '-remove');
- add = suffixClasses(add, '-add');
- var className = remove + ' ' + add;
- return animateAfter('setClass', element, className, animationCompleted);
- },
-
- addClass : function(element, className, animationCompleted) {
- return animateAfter('addClass', element, suffixClasses(className, '-add'), animationCompleted);
- },
-
- beforeRemoveClass : function(element, className, animationCompleted) {
- var cancellationMethod = animateBefore('removeClass', element, suffixClasses(className, '-remove'), function(fn) {
- /* when classes are removed from an element then the transition style
- * that is applied is the transition defined on the element without the
- * CSS class being there. This is how CSS3 functions outside of ngAnimate.
- * http://plnkr.co/edit/j8OzgTNxHTb4n3zLyjGW?p=preview */
- var klass = element.attr('class');
- element.removeClass(className);
- var timings = fn();
- element.attr('class', klass);
- return timings;
- });
+/**
+ * @ngdoc service
+ * @name $animate
+ * @kind object
+ *
+ * @description
+ * The ngAnimate `$animate` service documentation is the same for the core `$animate` service.
+ *
+ * Click here {@link ng.$animate $animate to learn more about animations with `$animate`}.
+ */
+angular.module('ngAnimate', [])
+ .directive('ngAnimateChildren', $$AnimateChildrenDirective)
- if(cancellationMethod) {
- afterReflow(element, function() {
- unblockTransitions(element, className);
- unblockKeyframeAnimations(element);
- animationCompleted();
- });
- return cancellationMethod;
- }
- animationCompleted();
- },
+ .factory('$$rAFMutex', $$rAFMutexFactory)
+ .factory('$$rAFScheduler', $$rAFSchedulerFactory)
- removeClass : function(element, className, animationCompleted) {
- return animateAfter('removeClass', element, suffixClasses(className, '-remove'), animationCompleted);
- }
- };
+ .factory('$$AnimateRunner', $$AnimateRunnerFactory)
- function suffixClasses(classes, suffix) {
- var className = '';
- classes = angular.isArray(classes) ? classes : classes.split(/\s+/);
- forEach(classes, function(klass, i) {
- if(klass && klass.length > 0) {
- className += (i > 0 ? ' ' : '') + klass + suffix;
- }
- });
- return className;
- }
- }]);
- }]);
+ .provider('$$animateQueue', $$AnimateQueueProvider)
+ .provider('$$animation', $$AnimationProvider)
+
+ .provider('$animateCss', $AnimateCssProvider)
+ .provider('$$animateCssDriver', $$AnimateCssDriverProvider)
+
+ .provider('$$animateJs', $$AnimateJsProvider)
+ .provider('$$animateJsDriver', $$AnimateJsDriverProvider);
})(window, window.angular);
diff --git a/libs/bower_components/angular-animate/angular-animate.min.js b/libs/bower_components/angular-animate/angular-animate.min.js
index 42d8557ed2..a99eac13cc 100644
--- a/libs/bower_components/angular-animate/angular-animate.min.js
+++ b/libs/bower_components/angular-animate/angular-animate.min.js
@@ -1,28 +1,52 @@
/*
- AngularJS v1.2.28
- (c) 2010-2014 Google, Inc. http://angularjs.org
+ AngularJS v1.4.3
+ (c) 2010-2015 Google, Inc. http://angularjs.org
License: MIT
*/
-(function(G,d,P){'use strict';d.module("ngAnimate",["ng"]).directive("ngAnimateChildren",function(){return function(H,z,e){e=e.ngAnimateChildren;d.isString(e)&&0===e.length?z.data("$$ngAnimateChildren",!0):H.$watch(e,function(d){z.data("$$ngAnimateChildren",!!d)})}}).factory("$$animateReflow",["$$rAF","$document",function(d,z){return function(e){return d(function(){e()})}}]).config(["$provide","$animateProvider",function(H,z){function e(d){for(var e=0;e<d.length;e++){var g=d[e];if(g.nodeType==ba)return g}}
-function E(g){return d.element(e(g))}var q=d.noop,w=d.forEach,Q=z.$$selectors,ba=1,g="$$ngAnimateState",ga="$$ngAnimateChildren",I="ng-animate",h={running:!0};H.decorator("$animate",["$delegate","$injector","$sniffer","$rootElement","$$asyncCallback","$rootScope","$document",function(y,G,aa,J,K,k,P){function R(a){var b=a.data(g)||{};b.running=!0;a.data(g,b)}function ha(a){if(a){var b=[],c={};a=a.substr(1).split(".");(aa.transitions||aa.animations)&&b.push(G.get(Q[""]));for(var f=0;f<a.length;f++){var d=
-a[f],e=Q[d];e&&!c[d]&&(b.push(G.get(e)),c[d]=!0)}return b}}function M(a,b,c){function f(a,b){var c=a[b],d=a["before"+b.charAt(0).toUpperCase()+b.substr(1)];if(c||d)return"leave"==b&&(d=c,c=null),S.push({event:b,fn:c}),n.push({event:b,fn:d}),!0}function e(b,d,f){var g=[];w(b,function(a){a.fn&&g.push(a)});var r=0;w(g,function(b,e){var C=function(){a:{if(d){(d[e]||q)();if(++r<g.length)break a;d=null}f()}};switch(b.event){case "setClass":d.push(b.fn(a,l,A,C));break;case "addClass":d.push(b.fn(a,l||c,
-C));break;case "removeClass":d.push(b.fn(a,A||c,C));break;default:d.push(b.fn(a,C))}});d&&0===d.length&&f()}var g=a[0];if(g){var p="setClass"==b,h=p||"addClass"==b||"removeClass"==b,l,A;d.isArray(c)&&(l=c[0],A=c[1],c=l+" "+A);var k=a.attr("class")+" "+c;if(U(k)){var t=q,v=[],n=[],x=q,u=[],S=[],k=(" "+k).replace(/\s+/g,".");w(ha(k),function(a){!f(a,b)&&p&&(f(a,"addClass"),f(a,"removeClass"))});return{node:g,event:b,className:c,isClassBased:h,isSetClassOperation:p,before:function(a){t=a;e(n,v,function(){t=
-q;a()})},after:function(a){x=a;e(S,u,function(){x=q;a()})},cancel:function(){v&&(w(v,function(a){(a||q)(!0)}),t(!0));u&&(w(u,function(a){(a||q)(!0)}),x(!0))}}}}}function F(a,b,c,f,e,m,p){function k(d){var e="$animate:"+d;x&&(x[e]&&0<x[e].length)&&K(function(){c.triggerHandler(e,{event:a,className:b})})}function l(){k("before")}function A(){k("after")}function q(){k("close");p&&K(function(){p()})}function t(){t.hasBeenRun||(t.hasBeenRun=!0,m())}function v(){if(!v.hasBeenRun){v.hasBeenRun=!0;var e=
-c.data(g);e&&(n&&n.isClassBased?B(c,b):(K(function(){var e=c.data(g)||{};s==e.index&&B(c,b,a)}),c.data(g,e)));q()}}var n=M(c,a,b);if(n){b=n.className;var x=d.element._data(n.node),x=x&&x.events;f||(f=e?e.parent():c.parent());var u=c.data(g)||{};e=u.active||{};var h=u.totalActive||0,C=u.last,D;n.isClassBased&&(D=u.running||u.disabled||C&&!C.isClassBased);if(D||N(c,f))t(),l(),A(),v();else{f=!1;if(0<h){D=[];if(n.isClassBased)"setClass"==C.event?(D.push(C),B(c,b)):e[b]&&(y=e[b],y.event==a?f=!0:(D.push(y),
-B(c,b)));else if("leave"==a&&e["ng-leave"])f=!0;else{for(var y in e)D.push(e[y]),B(c,y);e={};h=0}0<D.length&&w(D,function(a){a.cancel()})}!n.isClassBased||(n.isSetClassOperation||f)||(f="addClass"==a==c.hasClass(b));if(f)t(),l(),A(),q();else{if("leave"==a)c.one("$destroy",function(a){a=d.element(this);var b=a.data(g);b&&(b=b.active["ng-leave"])&&(b.cancel(),B(a,"ng-leave"))});c.addClass(I);var s=O++;h++;e[b]=n;c.data(g,{last:n,active:e,index:s,totalActive:h});l();n.before(function(e){var d=c.data(g);
-e=e||!d||!d.active[b]||n.isClassBased&&d.active[b].event!=a;t();!0===e?v():(A(),n.after(v))})}}}else t(),l(),A(),v()}function V(a){if(a=e(a))a=d.isFunction(a.getElementsByClassName)?a.getElementsByClassName(I):a.querySelectorAll("."+I),w(a,function(a){a=d.element(a);(a=a.data(g))&&a.active&&w(a.active,function(a){a.cancel()})})}function B(a,b){if(e(a)==e(J))h.disabled||(h.running=!1,h.structural=!1);else if(b){var c=a.data(g)||{},d=!0===b;!d&&(c.active&&c.active[b])&&(c.totalActive--,delete c.active[b]);
-if(d||!c.totalActive)a.removeClass(I),a.removeData(g)}}function N(a,b){if(h.disabled)return!0;if(e(a)==e(J))return h.running;var c,f,k;do{if(0===b.length)break;var m=e(b)==e(J),p=m?h:b.data(g)||{};if(p.disabled)return!0;m&&(k=!0);!1!==c&&(m=b.data(ga),d.isDefined(m)&&(c=m));f=f||p.running||p.last&&!p.last.isClassBased}while(b=b.parent());return!k||!c&&f}var O=0;J.data(g,h);k.$$postDigest(function(){k.$$postDigest(function(){h.running=!1})});var W=z.classNameFilter(),U=W?function(a){return W.test(a)}:
-function(){return!0};return{enter:function(a,b,c,e){a=d.element(a);b=b&&d.element(b);c=c&&d.element(c);R(a);y.enter(a,b,c);k.$$postDigest(function(){a=E(a);F("enter","ng-enter",a,b,c,q,e)})},leave:function(a,b){a=d.element(a);V(a);R(a);k.$$postDigest(function(){F("leave","ng-leave",E(a),null,null,function(){y.leave(a)},b)})},move:function(a,b,c,e){a=d.element(a);b=b&&d.element(b);c=c&&d.element(c);V(a);R(a);y.move(a,b,c);k.$$postDigest(function(){a=E(a);F("move","ng-move",a,b,c,q,e)})},addClass:function(a,
-b,c){a=d.element(a);a=E(a);F("addClass",b,a,null,null,function(){y.addClass(a,b)},c)},removeClass:function(a,b,c){a=d.element(a);a=E(a);F("removeClass",b,a,null,null,function(){y.removeClass(a,b)},c)},setClass:function(a,b,c,e){a=d.element(a);a=E(a);F("setClass",[b,c],a,null,null,function(){y.setClass(a,b,c)},e)},enabled:function(a,b){switch(arguments.length){case 2:if(a)B(b);else{var c=b.data(g)||{};c.disabled=!0;b.data(g,c)}break;case 1:h.disabled=!a;break;default:a=!h.disabled}return!!a}}}]);z.register("",
-["$window","$sniffer","$timeout","$$animateReflow",function(g,h,z,J){function K(){L||(L=J(function(){T=[];L=null;s={}}))}function k(a,X){L&&L();T.push(X);L=J(function(){w(T,function(a){a()});T=[];L=null;s={}})}function E(a,X){var b=e(a);a=d.element(b);Y.push(a);b=Date.now()+X;b<=fa||(z.cancel(ea),fa=b,ea=z(function(){R(Y);Y=[]},X,!1))}function R(a){w(a,function(a){(a=a.data(u))&&(a.closeAnimationFn||q)()})}function I(a,b){var c=b?s[b]:null;if(!c){var e=0,d=0,f=0,k=0,h,Z,$,m;w(a,function(a){if(a.nodeType==
-ba){a=g.getComputedStyle(a)||{};$=a[p+Q];e=Math.max(M($),e);m=a[p+t];h=a[p+v];d=Math.max(M(h),d);Z=a[l+v];k=Math.max(M(Z),k);var b=M(a[l+Q]);0<b&&(b*=parseInt(a[l+n],10)||1);f=Math.max(b,f)}});c={total:0,transitionPropertyStyle:m,transitionDurationStyle:$,transitionDelayStyle:h,transitionDelay:d,transitionDuration:e,animationDelayStyle:Z,animationDelay:k,animationDuration:f};b&&(s[b]=c)}return c}function M(a){var b=0;a=d.isString(a)?a.split(/\s*,\s*/):[];w(a,function(a){b=Math.max(parseFloat(a)||
-0,b)});return b}function F(a){var b=a.parent(),c=b.data(x);c||(b.data(x,++da),c=da);return c+"-"+e(a).getAttribute("class")}function V(a,b,c,d){var f=F(b),g=f+" "+c,k=s[g]?++s[g].total:0,h={};if(0<k){var m=c+"-stagger",h=f+" "+m;(f=!s[h])&&b.addClass(m);h=I(b,h);f&&b.removeClass(m)}d=d||function(a){return a()};b.addClass(c);var m=b.data(u)||{},n=d(function(){return I(b,g)});d=n.transitionDuration;f=n.animationDuration;if(0===d&&0===f)return b.removeClass(c),!1;b.data(u,{running:m.running||0,itemIndex:k,
-stagger:h,timings:n,closeAnimationFn:q});a=0<m.running||"setClass"==a;0<d&&B(b,c,a);0<f&&(0<h.animationDelay&&0===h.animationDuration)&&(e(b).style[l]="none 0s");return!0}function B(a,b,c){"ng-enter"!=b&&("ng-move"!=b&&"ng-leave"!=b)&&c?a.addClass(S):e(a).style[p+t]="none"}function N(a,b){var c=p+t,d=e(a);d.style[c]&&0<d.style[c].length&&(d.style[c]="");a.removeClass(S)}function O(a){var b=l;a=e(a);a.style[b]&&0<a.style[b].length&&(a.style[b]="")}function W(a,b,c,d){function g(a){b.off(z,h);b.removeClass(n);
-f(b,c);a=e(b);for(var d in s)a.style.removeProperty(s[d])}function h(a){a.stopPropagation();var b=a.originalEvent||a;a=b.$manualTimeStamp||b.timeStamp||Date.now();b=parseFloat(b.elapsedTime.toFixed(C));Math.max(a-y,0)>=x&&b>=t&&d()}var k=e(b);a=b.data(u);if(-1!=k.getAttribute("class").indexOf(c)&&a){var n="";w(c.split(" "),function(a,b){n+=(0<b?" ":"")+a+"-active"});var p=a.stagger,l=a.timings,q=a.itemIndex,t=Math.max(l.transitionDuration,l.animationDuration),v=Math.max(l.transitionDelay,l.animationDelay),
-x=v*ca,y=Date.now(),z=A+" "+H,r="",s=[];if(0<l.transitionDuration){var B=l.transitionPropertyStyle;-1==B.indexOf("all")&&(r+=m+"transition-property: "+B+";",r+=m+"transition-duration: "+l.transitionDurationStyle+";",s.push(m+"transition-property"),s.push(m+"transition-duration"))}0<q&&(0<p.transitionDelay&&0===p.transitionDuration&&(r+=m+"transition-delay: "+U(l.transitionDelayStyle,p.transitionDelay,q)+"; ",s.push(m+"transition-delay")),0<p.animationDelay&&0===p.animationDuration&&(r+=m+"animation-delay: "+
-U(l.animationDelayStyle,p.animationDelay,q)+"; ",s.push(m+"animation-delay")));0<s.length&&(l=k.getAttribute("style")||"",k.setAttribute("style",l+"; "+r));b.on(z,h);b.addClass(n);a.closeAnimationFn=function(){g();d()};k=(q*(Math.max(p.animationDelay,p.transitionDelay)||0)+(v+t)*D)*ca;a.running++;E(b,k);return g}d()}function U(a,b,c){var d="";w(a.split(","),function(a,e){d+=(0<e?",":"")+(c*b+parseInt(a,10))+"s"});return d}function a(a,b,c,d){if(V(a,b,c,d))return function(a){a&&f(b,c)}}function b(a,
-b,c,d){if(b.data(u))return W(a,b,c,d);f(b,c);d()}function c(c,d,e,f){var g=a(c,d,e);if(g){var h=g;k(d,function(){N(d,e);O(d);h=b(c,d,e,f)});return function(a){(h||q)(a)}}K();f()}function f(a,b){a.removeClass(b);var c=a.data(u);c&&(c.running&&c.running--,c.running&&0!==c.running||a.removeData(u))}function r(a,b){var c="";a=d.isArray(a)?a:a.split(/\s+/);w(a,function(a,d){a&&0<a.length&&(c+=(0<d?" ":"")+a+b)});return c}var m="",p,H,l,A;G.ontransitionend===P&&G.onwebkittransitionend!==P?(m="-webkit-",
-p="WebkitTransition",H="webkitTransitionEnd transitionend"):(p="transition",H="transitionend");G.onanimationend===P&&G.onwebkitanimationend!==P?(m="-webkit-",l="WebkitAnimation",A="webkitAnimationEnd animationend"):(l="animation",A="animationend");var Q="Duration",t="Property",v="Delay",n="IterationCount",x="$$ngAnimateKey",u="$$ngAnimateCSS3Data",S="ng-animate-block-transitions",C=3,D=1.5,ca=1E3,s={},da=0,T=[],L,ea=null,fa=0,Y=[];return{enter:function(a,b){return c("enter",a,"ng-enter",b)},leave:function(a,
-b){return c("leave",a,"ng-leave",b)},move:function(a,b){return c("move",a,"ng-move",b)},beforeSetClass:function(b,c,d,e){var f=r(d,"-remove")+" "+r(c,"-add"),g=a("setClass",b,f,function(a){var e=b.attr("class");b.removeClass(d);b.addClass(c);a=a();b.attr("class",e);return a});if(g)return k(b,function(){N(b,f);O(b);e()}),g;K();e()},beforeAddClass:function(b,c,d){var e=a("addClass",b,r(c,"-add"),function(a){b.addClass(c);a=a();b.removeClass(c);return a});if(e)return k(b,function(){N(b,c);O(b);d()}),
-e;K();d()},setClass:function(a,c,d,e){d=r(d,"-remove");c=r(c,"-add");return b("setClass",a,d+" "+c,e)},addClass:function(a,c,d){return b("addClass",a,r(c,"-add"),d)},beforeRemoveClass:function(b,c,d){var e=a("removeClass",b,r(c,"-remove"),function(a){var d=b.attr("class");b.removeClass(c);a=a();b.attr("class",d);return a});if(e)return k(b,function(){N(b,c);O(b);d()}),e;d()},removeClass:function(a,c,d){return b("removeClass",a,r(c,"-remove"),d)}}}])}])})(window,window.angular);
+(function(F,t,W){'use strict';function ua(a,b,c){if(!a)throw ngMinErr("areq",b||"?",c||"required");return a}function va(a,b){if(!a&&!b)return"";if(!a)return b;if(!b)return a;X(a)&&(a=a.join(" "));X(b)&&(b=b.join(" "));return a+" "+b}function Ea(a){var b={};a&&(a.to||a.from)&&(b.to=a.to,b.from=a.from);return b}function ba(a,b,c){var d="";a=X(a)?a:a&&U(a)&&a.length?a.split(/\s+/):[];u(a,function(a,s){a&&0<a.length&&(d+=0<s?" ":"",d+=c?b+a:a+b)});return d}function Fa(a){if(a instanceof G)switch(a.length){case 0:return[];
+case 1:if(1===a[0].nodeType)return a;break;default:return G(ka(a))}if(1===a.nodeType)return G(a)}function ka(a){if(!a[0])return a;for(var b=0;b<a.length;b++){var c=a[b];if(1==c.nodeType)return c}}function Ga(a,b,c){u(b,function(b){a.addClass(b,c)})}function Ha(a,b,c){u(b,function(b){a.removeClass(b,c)})}function ha(a){return function(b,c){c.addClass&&(Ga(a,b,c.addClass),c.addClass=null);c.removeClass&&(Ha(a,b,c.removeClass),c.removeClass=null)}}function ia(a){a=a||{};if(!a.$$prepared){var b=a.domOperation||
+H;a.domOperation=function(){a.$$domOperationFired=!0;b();b=H};a.$$prepared=!0}return a}function ca(a,b){wa(a,b);xa(a,b)}function wa(a,b){b.from&&(a.css(b.from),b.from=null)}function xa(a,b){b.to&&(a.css(b.to),b.to=null)}function R(a,b,c){var d=(b.addClass||"")+" "+(c.addClass||""),e=(b.removeClass||"")+" "+(c.removeClass||"");a=Ia(a.attr("class"),d,e);ya(b,c);b.addClass=a.addClass?a.addClass:null;b.removeClass=a.removeClass?a.removeClass:null;return b}function Ia(a,b,c){function d(a){U(a)&&(a=a.split(" "));
+var b={};u(a,function(a){a.length&&(b[a]=!0)});return b}var e={};a=d(a);b=d(b);u(b,function(a,b){e[b]=1});c=d(c);u(c,function(a,b){e[b]=1===e[b]?null:-1});var s={addClass:"",removeClass:""};u(e,function(b,c){var d,e;1===b?(d="addClass",e=!a[c]):-1===b&&(d="removeClass",e=a[c]);e&&(s[d].length&&(s[d]+=" "),s[d]+=c)});return s}function z(a){return a instanceof t.element?a[0]:a}function za(a,b,c){var d=Object.create(null),e=a.getComputedStyle(b)||{};u(c,function(a,b){var c=e[a];if(c){var k=c.charAt(0);
+if("-"===k||"+"===k||0<=k)c=Ja(c);0===c&&(c=null);d[b]=c}});return d}function Ja(a){var b=0;a=a.split(/\s*,\s*/);u(a,function(a){"s"==a.charAt(a.length-1)&&(a=a.substring(0,a.length-1));a=parseFloat(a)||0;b=b?Math.max(a,b):a});return b}function la(a){return 0===a||null!=a}function Aa(a,b){var c=O,d=a+"s";b?c+="Duration":d+=" linear all";return[c,d]}function ja(a,b){var c=b?"-"+b+"s":"";da(a,[ea,c]);return[ea,c]}function ma(a,b){var c=b?"paused":"",d=V+"PlayState";da(a,[d,c]);return[d,c]}function da(a,
+b){a.style[b[0]]=b[1]}function Ba(){var a=Object.create(null);return{flush:function(){a=Object.create(null)},count:function(b){return(b=a[b])?b.total:0},get:function(b){return(b=a[b])&&b.value},put:function(b,c){a[b]?a[b].total++:a[b]={total:1,value:c}}}}var H=t.noop,ya=t.extend,G=t.element,u=t.forEach,X=t.isArray,U=t.isString,na=t.isObject,Ka=t.isUndefined,La=t.isDefined,Ca=t.isFunction,oa=t.isElement,O,pa,V,qa;F.ontransitionend===W&&F.onwebkittransitionend!==W?(O="WebkitTransition",pa="webkitTransitionEnd transitionend"):
+(O="transition",pa="transitionend");F.onanimationend===W&&F.onwebkitanimationend!==W?(V="WebkitAnimation",qa="webkitAnimationEnd animationend"):(V="animation",qa="animationend");var ra=V+"Delay",sa=V+"Duration",ea=O+"Delay";F=O+"Duration";var Ma={transitionDuration:F,transitionDelay:ea,transitionProperty:O+"Property",animationDuration:sa,animationDelay:ra,animationIterationCount:V+"IterationCount"},Na={transitionDuration:F,transitionDelay:ea,animationDuration:sa,animationDelay:ra};t.module("ngAnimate",
+[]).directive("ngAnimateChildren",[function(){return function(a,b,c){a=c.ngAnimateChildren;t.isString(a)&&0===a.length?b.data("$$ngAnimateChildren",!0):c.$observe("ngAnimateChildren",function(a){b.data("$$ngAnimateChildren","on"===a||"true"===a)})}}]).factory("$$rAFMutex",["$$rAF",function(a){return function(){var b=!1;a(function(){b=!0});return function(c){b?c():a(c)}}}]).factory("$$rAFScheduler",["$$rAF",function(a){function b(a){d.push([].concat(a));c()}function c(){if(d.length){for(var b=[],n=
+0;n<d.length;n++){var h=d[n];h.shift()();h.length&&b.push(h)}d=b;e||a(function(){e||c()})}}var d=[],e;b.waitUntilQuiet=function(b){e&&e();e=a(function(){e=null;b();c()})};return b}]).factory("$$AnimateRunner",["$q","$$rAFMutex",function(a,b){function c(a){this.setHost(a);this._doneCallbacks=[];this._runInAnimationFrame=b();this._state=0}c.chain=function(a,b){function c(){if(n===a.length)b(!0);else a[n](function(a){!1===a?b(!1):(n++,c())})}var n=0;c()};c.all=function(a,b){function c(s){h=h&&s;++n===
+a.length&&b(h)}var n=0,h=!0;u(a,function(a){a.done(c)})};c.prototype={setHost:function(a){this.host=a||{}},done:function(a){2===this._state?a():this._doneCallbacks.push(a)},progress:H,getPromise:function(){if(!this.promise){var b=this;this.promise=a(function(a,c){b.done(function(b){!1===b?c():a()})})}return this.promise},then:function(a,b){return this.getPromise().then(a,b)},"catch":function(a){return this.getPromise()["catch"](a)},"finally":function(a){return this.getPromise()["finally"](a)},pause:function(){this.host.pause&&
+this.host.pause()},resume:function(){this.host.resume&&this.host.resume()},end:function(){this.host.end&&this.host.end();this._resolve(!0)},cancel:function(){this.host.cancel&&this.host.cancel();this._resolve(!1)},complete:function(a){var b=this;0===b._state&&(b._state=1,b._runInAnimationFrame(function(){b._resolve(a)}))},_resolve:function(a){2!==this._state&&(u(this._doneCallbacks,function(b){b(a)}),this._doneCallbacks.length=0,this._state=2)}};return c}]).provider("$$animateQueue",["$animateProvider",
+function(a){function b(a,b,c,h){return d[a].some(function(a){return a(b,c,h)})}function c(a,b){a=a||{};var c=0<(a.addClass||"").length,d=0<(a.removeClass||"").length;return b?c&&d:c||d}var d=this.rules={skip:[],cancel:[],join:[]};d.join.push(function(a,b,d){return!b.structural&&c(b.options)});d.skip.push(function(a,b,d){return!b.structural&&!c(b.options)});d.skip.push(function(a,b,c){return"leave"==c.event&&b.structural});d.skip.push(function(a,b,c){return c.structural&&!b.structural});d.cancel.push(function(a,
+b,c){return c.structural&&b.structural});d.cancel.push(function(a,b,c){return 2===c.state&&b.structural});d.cancel.push(function(a,b,c){a=b.options;c=c.options;return a.addClass&&a.addClass===c.removeClass||a.removeClass&&a.removeClass===c.addClass});this.$get=["$$rAF","$rootScope","$rootElement","$document","$$HashMap","$$animation","$$AnimateRunner","$templateRequest","$$jqLite",function(d,s,n,h,k,D,A,Z,I){function w(a,b){var c=z(a),f=[],m=l[b];m&&u(m,function(a){a.node.contains(c)&&f.push(a.callback)});
+return f}function B(a,b,c,f){d(function(){u(w(b,a),function(a){a(b,c,f)})})}function r(a,S,p){function d(b,c,f,p){B(c,a,f,p);b.progress(c,f,p)}function g(b){Da(a,p);ca(a,p);p.domOperation();l.complete(!b)}var P,E;if(a=Fa(a))P=z(a),E=a.parent();p=ia(p);var l=new A;if(!P)return g(),l;X(p.addClass)&&(p.addClass=p.addClass.join(" "));X(p.removeClass)&&(p.removeClass=p.removeClass.join(" "));p.from&&!na(p.from)&&(p.from=null);p.to&&!na(p.to)&&(p.to=null);var e=[P.className,p.addClass,p.removeClass].join(" ");
+if(!v(e))return g(),l;var M=0<=["enter","move","leave"].indexOf(S),h=!x||L.get(P),e=!h&&m.get(P)||{},k=!!e.state;h||k&&1==e.state||(h=!ta(a,E,S));if(h)return g(),l;M&&K(a);h={structural:M,element:a,event:S,close:g,options:p,runner:l};if(k){if(b("skip",a,h,e)){if(2===e.state)return g(),l;R(a,e.options,p);return e.runner}if(b("cancel",a,h,e))2===e.state?e.runner.end():e.structural?e.close():R(a,h.options,e.options);else if(b("join",a,h,e))if(2===e.state)R(a,p,{});else return S=h.event=e.event,p=R(a,
+e.options,h.options),l}else R(a,p,{});(k=h.structural)||(k="animate"===h.event&&0<Object.keys(h.options.to||{}).length||c(h.options));if(!k)return g(),C(a),l;M&&f(E);var r=(e.counter||0)+1;h.counter=r;ga(a,1,h);s.$$postDigest(function(){var b=m.get(P),v=!b,b=b||{},e=a.parent()||[],E=0<e.length&&("animate"===b.event||b.structural||c(b.options));if(v||b.counter!==r||!E){v&&(Da(a,p),ca(a,p));if(v||M&&b.event!==S)p.domOperation(),l.end();E||C(a)}else S=!b.structural&&c(b.options,!0)?"setClass":b.event,
+b.structural&&f(e),ga(a,2),b=D(a,S,b.options),b.done(function(b){g(!b);(b=m.get(P))&&b.counter===r&&C(z(a));d(l,S,"close",{})}),l.setHost(b),d(l,S,"start",{})});return l}function K(a){a=z(a).querySelectorAll("[data-ng-animate]");u(a,function(a){var b=parseInt(a.getAttribute("data-ng-animate")),c=m.get(a);switch(b){case 2:c.runner.end();case 1:c&&m.remove(a)}})}function C(a){a=z(a);a.removeAttribute("data-ng-animate");m.remove(a)}function E(a,b){return z(a)===z(b)}function f(a){a=z(a);do{if(!a||1!==
+a.nodeType)break;var b=m.get(a);if(b){var f=a;!b.structural&&c(b.options)&&(2===b.state&&b.runner.end(),C(f))}a=a.parentNode}while(1)}function ta(a,b,c){var f=c=!1,d=!1,v;for((a=a.data("$ngAnimatePin"))&&(b=a);b&&b.length;){f||(f=E(b,n));a=b[0];if(1!==a.nodeType)break;var e=m.get(a)||{};d||(d=e.structural||L.get(a));if(Ka(v)||!0===v)a=b.data("$$ngAnimateChildren"),La(a)&&(v=a);if(d&&!1===v)break;f||(f=E(b,n),f||(a=b.data("$ngAnimatePin"))&&(b=a));c||(c=E(b,g));b=b.parent()}return(!d||v)&&f&&c}function ga(a,
+b,c){c=c||{};c.state=b;a=z(a);a.setAttribute("data-ng-animate",b);c=(b=m.get(a))?ya(b,c):c;m.put(a,c)}var m=new k,L=new k,x=null,M=s.$watch(function(){return 0===Z.totalPendingRequests},function(a){a&&(M(),s.$$postDigest(function(){s.$$postDigest(function(){null===x&&(x=!0)})}))}),g=G(h[0].body),l={},P=a.classNameFilter(),v=P?function(a){return P.test(a)}:function(){return!0},Da=ha(I);return{on:function(a,b,c){b=ka(b);l[a]=l[a]||[];l[a].push({node:b,callback:c})},off:function(a,b,c){function f(a,
+b,c){var d=ka(b);return a.filter(function(a){return!(a.node===d&&(!c||a.callback===c))})}var d=l[a];d&&(l[a]=1===arguments.length?null:f(d,b,c))},pin:function(a,b){ua(oa(a),"element","not an element");ua(oa(b),"parentElement","not an element");a.data("$ngAnimatePin",b)},push:function(a,b,c,f){c=c||{};c.domOperation=f;return r(a,b,c)},enabled:function(a,b){var c=arguments.length;if(0===c)b=!!x;else if(oa(a)){var f=z(a),d=L.get(f);1===c?b=!d:(b=!!b)?d&&L.remove(f):L.put(f,!0)}else b=x=!!a;return b}}}]}]).provider("$$animation",
+["$animateProvider",function(a){function b(a){return a.data("$$animationRunner")}var c=this.drivers=[];this.$get=["$$jqLite","$rootScope","$injector","$$AnimateRunner","$$rAFScheduler",function(a,e,s,n,h){var k=[],D=ha(a),A=0,Z=0,I=[];return function(w,B,r){function K(a){a=a.hasAttribute("ng-animate-ref")?[a]:a.querySelectorAll("[ng-animate-ref]");var b=[];u(a,function(a){var c=a.getAttribute("ng-animate-ref");c&&c.length&&b.push(a)});return b}function C(a){var b=[],c={};u(a,function(a,f){var d=z(a.element),
+m=0<=["enter","move"].indexOf(a.event),d=a.structural?K(d):[];if(d.length){var g=m?"to":"from";u(d,function(a){var b=a.getAttribute("ng-animate-ref");c[b]=c[b]||{};c[b][g]={animationID:f,element:G(a)}})}else b.push(a)});var f={},d={};u(c,function(c,m){var g=c.from,e=c.to;if(g&&e){var l=a[g.animationID],h=a[e.animationID],x=g.animationID.toString();if(!d[x]){var B=d[x]={structural:!0,beforeStart:function(){l.beforeStart();h.beforeStart()},close:function(){l.close();h.close()},classes:E(l.classes,h.classes),
+from:l,to:h,anchors:[]};B.classes.length?b.push(B):(b.push(l),b.push(h))}d[x].anchors.push({out:g.element,"in":e.element})}else g=g?g.animationID:e.animationID,e=g.toString(),f[e]||(f[e]=!0,b.push(a[g]))});return b}function E(a,b){a=a.split(" ");b=b.split(" ");for(var c=[],f=0;f<a.length;f++){var d=a[f];if("ng-"!==d.substring(0,3))for(var g=0;g<b.length;g++)if(d===b[g]){c.push(d);break}}return c.join(" ")}function f(a){for(var b=c.length-1;0<=b;b--){var f=c[b];if(s.has(f)&&(f=s.get(f)(a)))return f}}
+function ta(a,c){a.from&&a.to?(b(a.from.element).setHost(c),b(a.to.element).setHost(c)):b(a.element).setHost(c)}function ga(){var a=b(w);!a||"leave"===B&&r.$$domOperationFired||a.end()}function m(b){w.off("$destroy",ga);w.removeData("$$animationRunner");D(w,r);ca(w,r);r.domOperation();g&&a.removeClass(w,g);w.removeClass("ng-animate");x.complete(!b)}r=ia(r);var L=0<=["enter","move","leave"].indexOf(B),x=new n({end:function(){m()},cancel:function(){m(!0)}});if(!c.length)return m(),x;w.data("$$animationRunner",
+x);var M=va(w.attr("class"),va(r.addClass,r.removeClass)),g=r.tempClasses;g&&(M+=" "+g,r.tempClasses=null);var l;L||(l=A,A+=1);k.push({element:w,classes:M,event:B,classBasedIndex:l,structural:L,options:r,beforeStart:function(){w.addClass("ng-animate");g&&a.addClass(w,g)},close:m});w.on("$destroy",ga);if(1<k.length)return x;e.$$postDigest(function(){Z=A;A=0;I.length=0;var a=[];u(k,function(c){b(c.element)&&a.push(c)});k.length=0;u(C(a),function(a){function c(){a.beforeStart();var d,g=a.close,e=a.anchors?
+a.from.element||a.to.element:a.element;b(e)&&z(e).parentNode&&(e=f(a))&&(d=e.start);d?(d=d(),d.done(function(a){g(!a)}),ta(a,d)):g()}a.structural?c():(I.push({node:z(a.element),fn:c}),a.classBasedIndex===Z-1&&(I=I.sort(function(a,b){return b.node.contains(a.node)}).map(function(a){return a.fn}),h(I)))})});return x}}]}]).provider("$animateCss",["$animateProvider",function(a){var b=Ba(),c=Ba();this.$get=["$window","$$jqLite","$$AnimateRunner","$timeout","$document","$sniffer","$$rAFScheduler",function(a,
+e,s,n,h,k,D){function A(a,b){var c=a.parentNode;return(c.$$ngAnimateParentKey||(c.$$ngAnimateParentKey=++r))+"-"+a.getAttribute("class")+"-"+b}function Z(h,f,B,k){var m;0<b.count(B)&&(m=c.get(B),m||(f=ba(f,"-stagger"),e.addClass(h,f),m=za(a,h,k),m.animationDuration=Math.max(m.animationDuration,0),m.transitionDuration=Math.max(m.transitionDuration,0),e.removeClass(h,f),c.put(B,m)));return m||{}}function I(a){C.push(a);D.waitUntilQuiet(function(){b.flush();c.flush();for(var a=K.offsetWidth+1,d=0;d<
+C.length;d++)C[d](a);C.length=0})}function w(c,f,e){f=b.get(e);f||(f=za(a,c,Ma),"infinite"===f.animationIterationCount&&(f.animationIterationCount=1));b.put(e,f);c=f;e=c.animationDelay;f=c.transitionDelay;c.maxDelay=e&&f?Math.max(e,f):e||f;c.maxDuration=Math.max(c.animationDuration*c.animationIterationCount,c.transitionDuration);return c}var B=ha(e),r=0,K=z(h).body,C=[];return function(a,c){function d(){m()}function h(){m(!0)}function m(b){if(!(K||C&&D)){K=!0;D=!1;e.removeClass(a,Y);e.removeClass(a,
+W);ma(g,!1);ja(g,!1);u(l,function(a){g.style[a[0]]=""});B(a,c);ca(a,c);if(c.onDone)c.onDone();p&&p.complete(!b)}}function L(a){q.blockTransition&&ja(g,a);q.blockKeyframeAnimation&&ma(g,!!a)}function x(){p=new s({end:d,cancel:h});m();return{$$willAnimate:!1,start:function(){return p},end:d}}function M(){function b(){if(!K){L(!1);u(l,function(a){g.style[a[0]]=a[1]});B(a,c);e.addClass(a,W);if(q.recalculateTimingStyles){fa=g.className+" "+Y;$=A(g,fa);y=w(g,fa,$);Q=y.maxDelay;H=Math.max(Q,0);J=y.maxDuration;
+if(0===J){m();return}q.hasTransitions=0<y.transitionDuration;q.hasAnimations=0<y.animationDuration}if(q.applyTransitionDelay||q.applyAnimationDelay){Q="boolean"!==typeof c.delay&&la(c.delay)?parseFloat(c.delay):Q;H=Math.max(Q,0);var k;q.applyTransitionDelay&&(y.transitionDelay=Q,k=[ea,Q+"s"],l.push(k),g.style[k[0]]=k[1]);q.applyAnimationDelay&&(y.animationDelay=Q,k=[ra,Q+"s"],l.push(k),g.style[k[0]]=k[1])}F=1E3*H;G=1E3*J;if(c.easing){var r=c.easing;q.hasTransitions&&(k=O+"TimingFunction",l.push([k,
+r]),g.style[k]=r);q.hasAnimations&&(k=V+"TimingFunction",l.push([k,r]),g.style[k]=r)}y.transitionDuration&&p.push(pa);y.animationDuration&&p.push(qa);x=Date.now();a.on(p.join(" "),h);n(d,F+1.5*G);xa(a,c)}}function d(){m()}function h(a){a.stopPropagation();var b=a.originalEvent||a;a=b.$manualTimeStamp||b.timeStamp||Date.now();b=parseFloat(b.elapsedTime.toFixed(3));Math.max(a-x,0)>=F&&b>=J&&(C=!0,m())}if(!K)if(g.parentNode){var x,p=[],k=function(a){if(C)D&&a&&(D=!1,m());else if(D=!a,y.animationDuration)if(a=
+ma(g,D),D)l.push(a);else{var b=l,c=b.indexOf(a);0<=a&&b.splice(c,1)}},r=0<U&&(y.transitionDuration&&0===T.transitionDuration||y.animationDuration&&0===T.animationDuration)&&Math.max(T.animationDelay,T.transitionDelay);r?n(b,Math.floor(r*U*1E3),!1):b();t.resume=function(){k(!0)};t.pause=function(){k(!1)}}else m()}var g=z(a);if(!g||!g.parentNode)return x();c=ia(c);var l=[],r=a.attr("class"),v=Ea(c),K,D,C,p,t,H,F,J,G;if(0===c.duration||!k.animations&&!k.transitions)return x();var aa=c.event&&X(c.event)?
+c.event.join(" "):c.event,R="",N="";aa&&c.structural?R=ba(aa,"ng-",!0):aa&&(R=aa);c.addClass&&(N+=ba(c.addClass,"-add"));c.removeClass&&(N.length&&(N+=" "),N+=ba(c.removeClass,"-remove"));c.applyClassesEarly&&N.length&&(B(a,c),N="");var Y=[R,N].join(" ").trim(),fa=r+" "+Y,W=ba(Y,"-active"),r=v.to&&0<Object.keys(v.to).length;if(!(0<(c.keyframeStyle||"").length||r||Y))return x();var $,T;0<c.stagger?(v=parseFloat(c.stagger),T={transitionDelay:v,animationDelay:v,transitionDuration:0,animationDuration:0}):
+($=A(g,fa),T=Z(g,Y,$,Na));e.addClass(a,Y);c.transitionStyle&&(v=[O,c.transitionStyle],da(g,v),l.push(v));0<=c.duration&&(v=0<g.style[O].length,v=Aa(c.duration,v),da(g,v),l.push(v));c.keyframeStyle&&(v=[V,c.keyframeStyle],da(g,v),l.push(v));var U=T?0<=c.staggerIndex?c.staggerIndex:b.count($):0;(aa=0===U)&&ja(g,9999);var y=w(g,fa,$),Q=y.maxDelay;H=Math.max(Q,0);J=y.maxDuration;var q={};q.hasTransitions=0<y.transitionDuration;q.hasAnimations=0<y.animationDuration;q.hasTransitionAll=q.hasTransitions&&
+"all"==y.transitionProperty;q.applyTransitionDuration=r&&(q.hasTransitions&&!q.hasTransitionAll||q.hasAnimations&&!q.hasTransitions);q.applyAnimationDuration=c.duration&&q.hasAnimations;q.applyTransitionDelay=la(c.delay)&&(q.applyTransitionDuration||q.hasTransitions);q.applyAnimationDelay=la(c.delay)&&q.hasAnimations;q.recalculateTimingStyles=0<N.length;if(q.applyTransitionDuration||q.applyAnimationDuration)J=c.duration?parseFloat(c.duration):J,q.applyTransitionDuration&&(q.hasTransitions=!0,y.transitionDuration=
+J,v=0<g.style[O+"Property"].length,l.push(Aa(J,v))),q.applyAnimationDuration&&(q.hasAnimations=!0,y.animationDuration=J,l.push([sa,J+"s"]));if(0===J&&!q.recalculateTimingStyles)return x();null==c.duration&&0<y.transitionDuration&&(q.recalculateTimingStyles=q.recalculateTimingStyles||aa);F=1E3*H;G=1E3*J;c.skipBlocking||(q.blockTransition=0<y.transitionDuration,q.blockKeyframeAnimation=0<y.animationDuration&&0<T.animationDelay&&0===T.animationDuration);wa(a,c);q.blockTransition||ja(g,!1);L(J);return{$$willAnimate:!0,
+end:d,start:function(){if(!K)return t={end:d,cancel:h,resume:null,pause:null},p=new s(t),I(M),p}}}}]}]).provider("$$animateCssDriver",["$$animationProvider",function(a){a.drivers.push("$$animateCssDriver");this.$get=["$animateCss","$rootScope","$$AnimateRunner","$rootElement","$document","$sniffer",function(a,c,d,e,s,n){function h(a){return a.replace(/\bng-\S+\b/g,"")}function k(a,b){U(a)&&(a=a.split(" "));U(b)&&(b=b.split(" "));return a.filter(function(a){return-1===b.indexOf(a)}).join(" ")}function D(c,
+e,A){function D(a){var b={},c=z(a).getBoundingClientRect();u(["width","height","top","left"],function(a){var d=c[a];switch(a){case "top":d+=I.scrollTop;break;case "left":d+=I.scrollLeft}b[a]=Math.floor(d)+"px"});return b}function s(){var c=h(A.attr("class")||""),d=k(c,t),c=k(t,c),d=a(n,{to:D(A),addClass:"ng-anchor-in "+d,removeClass:"ng-anchor-out "+c,delay:!0});return d.$$willAnimate?d:null}function f(){n.remove();e.removeClass("ng-animate-shim");A.removeClass("ng-animate-shim")}var n=G(z(e).cloneNode(!0)),
+t=h(n.attr("class")||"");e.addClass("ng-animate-shim");A.addClass("ng-animate-shim");n.addClass("ng-anchor");w.append(n);var m;c=function(){var c=a(n,{addClass:"ng-anchor-out",delay:!0,from:D(e)});return c.$$willAnimate?c:null}();if(!c&&(m=s(),!m))return f();var L=c||m;return{start:function(){function a(){c&&c.end()}var b,c=L.start();c.done(function(){c=null;if(!m&&(m=s()))return c=m.start(),c.done(function(){c=null;f();b.complete()}),c;f();b.complete()});return b=new d({end:a,cancel:a})}}}function A(a,
+b,c,e){var h=t(a),f=t(b),k=[];u(e,function(a){(a=D(c,a.out,a["in"]))&&k.push(a)});if(h||f||0!==k.length)return{start:function(){function a(){u(b,function(a){a.end()})}var b=[];h&&b.push(h.start());f&&b.push(f.start());u(k,function(a){b.push(a.start())});var c=new d({end:a,cancel:a});d.all(b,function(a){c.complete(a)});return c}}}function t(c){var d=c.element,e=c.options||{};c.structural?(e.structural=e.applyClassesEarly=!0,e.event=c.event,"leave"===e.event&&(e.onDone=e.domOperation)):e.event=null;
+c=a(d,e);return c.$$willAnimate?c:null}if(!n.animations&&!n.transitions)return H;var I=z(s).body;c=z(e);var w=G(I.parentNode===c?I:c);return function(a){return a.from&&a.to?A(a.from,a.to,a.classes,a.anchors):t(a)}}]}]).provider("$$animateJs",["$animateProvider",function(a){this.$get=["$injector","$$AnimateRunner","$$rAFMutex","$$jqLite",function(b,c,d,e){function s(c){c=X(c)?c:c.split(" ");for(var d=[],e={},A=0;A<c.length;A++){var n=c[A],s=a.$$registeredAnimations[n];s&&!e[n]&&(d.push(b.get(s)),e[n]=
+!0)}return d}var n=ha(e);return function(a,b,d,e){function t(){e.domOperation();n(a,e)}function z(a,b,d,e,g){switch(d){case "animate":b=[b,e.from,e.to,g];break;case "setClass":b=[b,r,K,g];break;case "addClass":b=[b,r,g];break;case "removeClass":b=[b,K,g];break;default:b=[b,g]}b.push(e);if(a=a.apply(a,b))if(Ca(a.start)&&(a=a.start()),a instanceof c)a.done(g);else if(Ca(a))return a;return H}function w(a,b,d,e,g){var f=[];u(e,function(e){var h=e[g];h&&f.push(function(){var e,g,f=!1,l=function(a){f||
+(f=!0,(g||H)(a),e.complete(!a))};e=new c({end:function(){l()},cancel:function(){l(!0)}});g=z(h,a,b,d,function(a){l(!1===a)});return e})});return f}function B(a,b,d,e,g){var f=w(a,b,d,e,g);if(0===f.length){var h,k;"beforeSetClass"===g?(h=w(a,"removeClass",d,e,"beforeRemoveClass"),k=w(a,"addClass",d,e,"beforeAddClass")):"setClass"===g&&(h=w(a,"removeClass",d,e,"removeClass"),k=w(a,"addClass",d,e,"addClass"));h&&(f=f.concat(h));k&&(f=f.concat(k))}if(0!==f.length)return function(a){var b=[];f.length&&
+u(f,function(a){b.push(a())});b.length?c.all(b,a):a();return function(a){u(b,function(b){a?b.cancel():b.end()})}}}3===arguments.length&&na(d)&&(e=d,d=null);e=ia(e);d||(d=a.attr("class")||"",e.addClass&&(d+=" "+e.addClass),e.removeClass&&(d+=" "+e.removeClass));var r=e.addClass,K=e.removeClass,C=s(d),E,f;if(C.length){var F,G;"leave"==b?(G="leave",F="afterLeave"):(G="before"+b.charAt(0).toUpperCase()+b.substr(1),F=b);"enter"!==b&&"move"!==b&&(E=B(a,b,e,C,G));f=B(a,b,e,C,F)}if(E||f)return{start:function(){function b(c){n=
+!0;t();ca(a,e);g.complete(c)}var d,k=[];E&&k.push(function(a){d=E(a)});k.length?k.push(function(a){t();a(!0)}):t();f&&k.push(function(a){d=f(a)});var n=!1,g=new c({end:function(){n||((d||H)(void 0),b(void 0))},cancel:function(){n||((d||H)(!0),b(!0))}});c.chain(k,b);return g}}}}]}]).provider("$$animateJsDriver",["$$animationProvider",function(a){a.drivers.push("$$animateJsDriver");this.$get=["$$animateJs","$$AnimateRunner",function(a,c){function d(c){return a(c.element,c.event,c.classes,c.options)}
+return function(a){if(a.from&&a.to){var b=d(a.from),n=d(a.to);if(b||n)return{start:function(){function a(){return function(){u(d,function(a){a.end()})}}var d=[];b&&d.push(b.start());n&&d.push(n.start());c.all(d,function(a){e.complete(a)});var e=new c({end:a(),cancel:a()});return e}}}else return d(a)}}]}])})(window,window.angular);
//# sourceMappingURL=angular-animate.min.js.map
diff --git a/libs/bower_components/angular-animate/angular-animate.min.js.map b/libs/bower_components/angular-animate/angular-animate.min.js.map
index c79d4f55cd..8254e64933 100644
--- a/libs/bower_components/angular-animate/angular-animate.min.js.map
+++ b/libs/bower_components/angular-animate/angular-animate.min.js.map
@@ -1,8 +1,8 @@
{
"version":3,
"file":"angular-animate.min.js",
-"lineCount":27,
-"mappings":"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",
+"lineCount":51,
+"mappings":"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",
"sources":["angular-animate.js"],
-"names":["window","angular","undefined","module","directive","scope","element","attrs","val","ngAnimateChildren","isString","length","data","NG_ANIMATE_CHILDREN","$watch","value","factory","$$rAF","$document","fn","config","$provide","$animateProvider","extractElementNode","i","elm","nodeType","ELEMENT_NODE","stripCommentsFromElement","noop","forEach","selectors","$$selectors","NG_ANIMATE_STATE","NG_ANIMATE_CLASS_NAME","rootAnimateState","decorator","$delegate","$injector","$sniffer","$rootElement","$$asyncCallback","$rootScope","blockElementAnimations","running","lookup","name","matches","flagMap","classes","substr","split","transitions","animations","push","get","klass","selectorFactoryName","animationRunner","animationEvent","className","registerAnimation","animationFactory","event","afterFn","beforeFn","charAt","toUpperCase","after","before","run","fns","cancellations","allCompleteFn","animation","count","index","progress","classNameAdd","classNameRemove","node","isSetClassOperation","isClassBased","isArray","attr","currentClassName","isAnimatableClassName","beforeComplete","beforeCancel","afterComplete","afterCancel","animationLookup","replace","created","cancel","cancelFn","performAnimation","parentElement","afterElement","domOperation","doneCallback","fireDOMCallback","animationPhase","eventName","elementEvents","triggerHandler","fireBeforeCallbackAsync","fireAfterCallbackAsync","fireDoneCallbackAsync","fireDOMOperation","hasBeenRun","closeAnimation","runner","cleanup","localAnimationCount","_data","events","parent","ngAnimateState","runningAnimations","active","totalActiveAnimations","totalActive","lastAnimation","last","skipAnimations","disabled","animationsDisabled","skipAnimation","animationsToCancel","current","operation","hasClass","one","e","state","activeLeaveAnimation","addClass","globalAnimationCounter","cancelled","cancelChildAnimations","nodes","isFunction","getElementsByClassName","querySelectorAll","structural","removeAnimations","removeClass","removeData","allowChildAnimations","parentRunningAnimation","hasParent","isRoot","animateChildrenFlag","isDefined","$$postDigest","classNameFilter","test","enter","leave","move","setClass","add","remove","enabled","arguments","register","$window","$timeout","$$animateReflow","clearCacheAfterReflow","cancelAnimationReflow","animationReflowQueue","lookupCache","afterReflow","callback","animationCloseHandler","totalTime","animationElementQueue","futureTimestamp","Date","now","closingTimestamp","closingTimer","closeAllAnimations","elements","elementData","NG_ANIMATE_CSS_DATA_KEY","closeAnimationFn","getElementAnimationDetails","cacheKey","transitionDuration","transitionDelay","animationDuration","animationDelay","transitionDelayStyle","animationDelayStyle","transitionDurationStyle","transitionPropertyStyle","elementStyles","getComputedStyle","TRANSITION_PROP","DURATION_KEY","Math","max","parseMaxTime","PROPERTY_KEY","DELAY_KEY","ANIMATION_PROP","aDuration","parseInt","ANIMATION_ITERATION_COUNT_KEY","str","maxValue","values","parseFloat","getCacheKey","parentID","NG_ANIMATE_PARENT_KEY","parentCounter","getAttribute","animateSetup","calculationDecorator","eventCacheKey","itemIndex","total","stagger","staggerClassName","staggerCacheKey","applyClasses","formerData","timings","isCurrentlyAnimating","blockTransitions","style","isAnimating","NG_ANIMATE_BLOCK_CLASS_NAME","unblockTransitions","prop","unblockKeyframeAnimations","animateRun","activeAnimationComplete","onEnd","off","css3AnimationEvents","onAnimationProgress","activeClassName","animateClose","appliedStyles","removeProperty","stopPropagation","ev","originalEvent","timeStamp","$manualTimeStamp","elapsedTime","toFixed","ELAPSED_TIME_MAX_DECIMAL_PLACES","startTime","maxDelayTime","maxDuration","indexOf","maxDelay","ONE_SECOND","ANIMATIONEND_EVENT","TRANSITIONEND_EVENT","propertyStyle","CSS_PREFIX","prepareStaggerDelay","oldStyle","setAttribute","on","elementData.closeAnimationFn","CLOSING_TIME_BUFFER","delayStyle","staggerDelay","animateBefore","animateAfter","afterAnimationComplete","animate","animationComplete","preReflowCancellation","suffixClasses","suffix","ontransitionend","onwebkittransitionend","onanimationend","onwebkitanimationend","animationCompleted","beforeSetClass","cancellationMethod","beforeAddClass","beforeRemoveClass"]
+"names":["window","angular","undefined","assertArg","arg","name","reason","ngMinErr","mergeClasses","a","b","isArray","join","packageStyles","options","styles","to","from","pendClasses","classes","fix","isPrefix","className","isString","length","split","forEach","klass","i","stripCommentsFromElement","element","jqLite","ELEMENT_NODE","nodeType","extractElementNode","elm","$$addClass","$$jqLite","addClass","$$removeClass","removeClass","applyAnimationClassesFactory","prepareAnimationOptions","$$prepared","domOperation","noop","options.domOperation","$$domOperationFired","applyAnimationStyles","applyAnimationFromStyles","applyAnimationToStyles","css","mergeAnimationOptions","target","newOptions","toAdd","toRemove","resolveElementClasses","attr","extend","existing","splitClassesToLookup","obj","flags","value","key","ADD_CLASS","REMOVE_CLASS","val","prop","allow","getDomNode","computeCssStyles","$window","properties","Object","create","detectedStyles","getComputedStyle","formalStyleName","actualStyleName","c","charAt","parseMaxTime","str","maxValue","values","substring","parseFloat","Math","max","truthyTimingValue","getCssTransitionDurationStyle","duration","applyOnlyDuration","style","TRANSITION_PROP","DURATION_KEY","blockTransitions","node","applyInlineStyle","TRANSITION_DELAY_PROP","blockKeyframeAnimations","applyBlock","ANIMATION_PROP","ANIMATION_PLAYSTATE_KEY","styleTuple","createLocalCacheLookup","cache","flush","count","entry","total","get","put","isObject","isUndefined","isDefined","isFunction","isElement","TRANSITIONEND_EVENT","ANIMATIONEND_EVENT","ontransitionend","onwebkittransitionend","onanimationend","onwebkitanimationend","ANIMATION_DELAY_PROP","DELAY_KEY","ANIMATION_DURATION_PROP","TRANSITION_DURATION_PROP","DETECT_CSS_PROPERTIES","transitionDuration","transitionDelay","transitionProperty","PROPERTY_KEY","animationDuration","animationDelay","animationIterationCount","ANIMATION_ITERATION_COUNT_KEY","DETECT_STAGGER_CSS_PROPERTIES","module","directive","$$AnimateChildrenDirective","scope","attrs","ngAnimateChildren","data","NG_ANIMATE_CHILDREN_DATA","$observe","factory","$$rAFMutexFactory","$$rAF","passed","fn","$$rAFSchedulerFactory","scheduler","tasks","tickQueue","push","concat","nextTick","updatedQueue","innerQueue","shift","nextTask","cancelFn","waitUntilQuiet","scheduler.waitUntilQuiet","$$AnimateRunnerFactory","$q","$$rAFMutex","AnimateRunner","host","setHost","_doneCallbacks","_runInAnimationFrame","_state","chain","AnimateRunner.chain","callback","next","index","response","all","AnimateRunner.all","runners","onProgress","status","runner","done","prototype","DONE_COMPLETE_STATE","progress","getPromise","promise","self","resolve","reject","then","resolveHandler","rejectHandler","catch","handler","finally","pause","resume","end","_resolve","cancel","complete","INITIAL_STATE","DONE_PENDING_STATE","provider","$$AnimateQueueProvider","$animateProvider","isAllowed","ruleType","currentAnimation","previousAnimation","rules","some","hasAnimationClasses","and","skip","newAnimation","structural","event","RUNNING_STATE","state","nO","cO","$get","$rootScope","$rootElement","$document","$$HashMap","$$animation","$$AnimateRunner","$templateRequest","findCallbacks","targetNode","matches","entries","callbackRegistry","contains","triggerCallback","phase","queueAnimation","notifyProgress","close","applyAnimationClasses","parent","isAnimatableClassName","isStructural","indexOf","skipAnimations","animationsEnabled","disabledElementsLookup","existingAnimation","activeAnimationsLookup","hasExistingAnimation","PRE_DIGEST_STATE","areAnimationsAllowed","closeChildAnimations","skipAnimationFlag","cancelAnimationFlag","joinAnimationFlag","isValidAnimation","keys","clearElementAnimationState","closeParentClassBasedAnimations","counter","markElementAnimationState","$$postDigest","animationDetails","animationCancelled","parentElement","realRunner","children","querySelectorAll","child","parseInt","getAttribute","NG_ANIMATE_ATTR_NAME","remove","removeAttribute","isMatchingElement","nodeOrElmA","nodeOrElmB","startingElement","parentNode","rootElementDetected","bodyElementDetected","parentAnimationDetected","animateChildren","parentHost","NG_ANIMATE_PIN_DATA","details","bodyElement","setAttribute","newValue","oldValue","deregisterWatch","$watch","totalPendingRequests","isEmpty","body","classNameFilter","test","on","container","off","filterFromRegistry","list","matchContainer","matchCallback","containerNode","filter","arguments","pin","enabled","bool","argCount","hasElement","recordExists","$$AnimationProvider","getRunner","RUNNER_STORAGE_KEY","drivers","$injector","$$rAFScheduler","animationQueue","totalPendingClassBasedAnimations","totalActiveClassBasedAnimations","classBasedAnimationsQueue","getAnchorNodes","items","hasAttribute","NG_ANIMATE_REF_ATTR","SELECTOR","anchors","groupAnimations","animations","preparedAnimations","refLookup","animation","enterOrMove","anchorNodes","direction","anchor","animationID","usedIndicesLookup","anchorGroups","operations","fromAnimation","toAnimation","lookupKey","toString","group","beforeStart","cssClassesIntersection","indexKey","aa","j","invokeFirstDriver","driverName","has","driver","updateAnimationRunners","newRunner","handleDestroyedElement","rejected","removeData","tempClasses","NG_ANIMATE_CLASSNAME","classBasedIndex","animationEntry","triggerAnimationStart","startAnimationFn","closeFn","targetElement","operation","start","animationRunner","sort","map","$AnimateCssProvider","gcsLookup","gcsStaggerLookup","$timeout","$sniffer","gcsHashFn","extraClasses","parentCounter","computeCachedCssStaggerStyles","cacheKey","stagger","staggerClassName","rafWaitQueue","width","bod","offsetWidth","computeTimings","timings","aD","tD","maxDelay","maxDuration","init","endFn","animationClosed","animationCompleted","animationPaused","setupClasses","activeClasses","temporaryStyles","onDone","applyBlocking","blockTransition","blockKeyframeAnimation","closeAndReturnNoopAnimator","$$willAnimate","recalculateTimingStyles","fullClassName","relativeDelay","hasTransitions","hasAnimations","applyTransitionDelay","applyAnimationDelay","delay","delayStyle","maxDelayTime","ONE_SECOND","maxDurationTime","easing","easeVal","easeProp","TIMING_KEY","events","startTime","Date","now","onAnimationProgress","onAnimationExpired","CLOSING_TIME_BUFFER","stopPropagation","ev","originalEvent","timeStamp","$manualTimeStamp","elapsedTime","toFixed","ELAPSED_TIME_MAX_DECIMAL_PLACES","playPause","playAnimation","arr","splice","maxStagger","itemIndex","floor","runnerHost","runnerHost.resume","runnerHost.pause","transitions","method","structuralClassName","addRemoveClassName","applyClassesEarly","trim","hasToStyles","keyframeStyle","staggerVal","transitionStyle","durationStyle","staggerIndex","isFirst","SAFE_FAST_FORWARD_DURATION_VALUE","hasTransitionAll","applyTransitionDuration","applyAnimationDuration","skipBlocking","$$AnimateCssDriverProvider","$$animationProvider","$animateCss","filterCssClasses","replace","getUniqueValues","prepareAnchoredAnimation","outAnchor","inAnchor","calculateAnchorStyles","coords","getBoundingClientRect","bodyNode","scrollTop","scrollLeft","prepareInAnimation","endingClasses","startingClasses","animator","clone","NG_ANIMATE_SHIM_CLASS_NAME","cloneNode","NG_ANIMATE_ANCHOR_CLASS_NAME","rootBodyElement","append","animatorIn","animatorOut","prepareOutAnimation","NG_OUT_ANCHOR_CLASS_NAME","startingAnimator","prepareFromToAnchorAnimation","prepareRegularAnimation","anchorAnimations","outElement","inElement","animationRunners","rootNode","initDriverFn","$$AnimateJsProvider","lookupAnimations","flagMap","animationFactory","$$registeredAnimations","applyOptions","executeAnimationFn","args","classesToAdd","classesToRemove","apply","groupEventedAnimations","fnName","ani","endProgressCb","resolved","onAnimationComplete","result","packageAnimations","startAnimation","animateFn","before","after","afterFn","beforeFn","toUpperCase","substr","onComplete","success","closeActiveAnimations","cancelled","$$AnimateJsDriverProvider","$$animateJs","prepareAnimation","endFnFactory"]
}
diff --git a/libs/bower_components/angular-animate/bower.json b/libs/bower_components/angular-animate/bower.json
index 2cdde934a4..599fb192c1 100644
--- a/libs/bower_components/angular-animate/bower.json
+++ b/libs/bower_components/angular-animate/bower.json
@@ -1,9 +1,9 @@
{
"name": "angular-animate",
- "version": "1.2.28",
+ "version": "1.4.3",
"main": "./angular-animate.js",
"ignore": [],
"dependencies": {
- "angular": "1.2.28"
+ "angular": "1.4.3"
}
}
diff --git a/libs/bower_components/angular-animate/index.js b/libs/bower_components/angular-animate/index.js
new file mode 100644
index 0000000000..6ec0a3510e
--- /dev/null
+++ b/libs/bower_components/angular-animate/index.js
@@ -0,0 +1,2 @@
+require('./angular-animate');
+module.exports = 'ngAnimate';
diff --git a/libs/bower_components/angular-animate/package.json b/libs/bower_components/angular-animate/package.json
index 4f492a09fa..226acee34e 100644
--- a/libs/bower_components/angular-animate/package.json
+++ b/libs/bower_components/angular-animate/package.json
@@ -1,8 +1,8 @@
{
"name": "angular-animate",
- "version": "1.2.28",
+ "version": "1.4.3",
"description": "AngularJS module for animations",
- "main": "angular-animate.js",
+ "main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
diff --git a/libs/bower_components/angular-cookies/.bower.json b/libs/bower_components/angular-cookies/.bower.json
index cd45423cce..355b37504b 100644
--- a/libs/bower_components/angular-cookies/.bower.json
+++ b/libs/bower_components/angular-cookies/.bower.json
@@ -1,19 +1,19 @@
{
"name": "angular-cookies",
- "version": "1.2.28",
+ "version": "1.4.3",
"main": "./angular-cookies.js",
"ignore": [],
"dependencies": {
- "angular": "1.2.28"
+ "angular": "1.4.3"
},
"homepage": "https://github.com/angular/bower-angular-cookies",
- "_release": "1.2.28",
+ "_release": "1.4.3",
"_resolution": {
"type": "version",
- "tag": "v1.2.28",
- "commit": "3bbaa39114fa18101a69ed368fb39bc2e1c2a78b"
+ "tag": "v1.4.3",
+ "commit": "1ef7a87fc52ed419322aefe14890bdb24e717fc9"
},
"_source": "git://github.com/angular/bower-angular-cookies.git",
- "_target": "~1.2.0",
+ "_target": "~1.4.0",
"_originalSource": "angular-cookies"
} \ No newline at end of file
diff --git a/libs/bower_components/angular-cookies/README.md b/libs/bower_components/angular-cookies/README.md
index a1dc09bc5c..7b190d3461 100644
--- a/libs/bower_components/angular-cookies/README.md
+++ b/libs/bower_components/angular-cookies/README.md
@@ -14,21 +14,12 @@ You can install this package either with `npm` or with `bower`.
npm install angular-cookies
```
-Add a `<script>` to your `index.html`:
-
-```html
-<script src="/node_modules/angular-cookies/angular-cookies.js"></script>
-```
-
Then add `ngCookies` as a dependency for your app:
```javascript
-angular.module('myApp', ['ngCookies']);
+angular.module('myApp', [require('angular-cookies')]);
```
-Note that this package is not in CommonJS format, so doing `require('angular-cookies')` will
-return `undefined`.
-
### bower
```shell
@@ -56,7 +47,7 @@ Documentation is available on the
The MIT License
-Copyright (c) 2010-2012 Google, Inc. http://angularjs.org
+Copyright (c) 2010-2015 Google, Inc. http://angularjs.org
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/libs/bower_components/angular-cookies/angular-cookies.js b/libs/bower_components/angular-cookies/angular-cookies.js
index 22f00e5e8c..ddfcd1469d 100644
--- a/libs/bower_components/angular-cookies/angular-cookies.js
+++ b/libs/bower_components/angular-cookies/angular-cookies.js
@@ -1,6 +1,6 @@
/**
- * @license AngularJS v1.2.28
- * (c) 2010-2014 Google, Inc. http://angularjs.org
+ * @license AngularJS v1.4.3
+ * (c) 2010-2015 Google, Inc. http://angularjs.org
* License: MIT
*/
(function(window, angular, undefined) {'use strict';
@@ -17,190 +17,305 @@
*
* <div doc-module-components="ngCookies"></div>
*
- * See {@link ngCookies.$cookies `$cookies`} and
- * {@link ngCookies.$cookieStore `$cookieStore`} for usage.
+ * See {@link ngCookies.$cookies `$cookies`} for usage.
*/
angular.module('ngCookies', ['ng']).
/**
- * @ngdoc service
- * @name $cookies
- *
+ * @ngdoc provider
+ * @name $cookiesProvider
* @description
- * Provides read/write access to browser's cookies.
- *
- * Only a simple Object is exposed and by adding or removing properties to/from this object, new
- * cookies are created/deleted at the end of current $eval.
- * The object's properties can only be strings.
- *
- * Requires the {@link ngCookies `ngCookies`} module to be installed.
- *
- * @example
- *
- * ```js
- * angular.module('cookiesExample', ['ngCookies'])
- * .controller('ExampleController', ['$cookies', function($cookies) {
- * // Retrieving a cookie
- * var favoriteCookie = $cookies.myFavorite;
- * // Setting a cookie
- * $cookies.myFavorite = 'oatmeal';
- * }]);
- * ```
- */
- factory('$cookies', ['$rootScope', '$browser', function ($rootScope, $browser) {
- var cookies = {},
- lastCookies = {},
- lastBrowserCookies,
- runEval = false,
- copy = angular.copy,
- isUndefined = angular.isUndefined;
-
- //creates a poller fn that copies all cookies from the $browser to service & inits the service
- $browser.addPollFn(function() {
- var currentCookies = $browser.cookies();
- if (lastBrowserCookies != currentCookies) { //relies on browser.cookies() impl
- lastBrowserCookies = currentCookies;
- copy(currentCookies, lastCookies);
- copy(currentCookies, cookies);
- if (runEval) $rootScope.$apply();
- }
- })();
-
- runEval = true;
-
- //at the end of each eval, push cookies
- //TODO: this should happen before the "delayed" watches fire, because if some cookies are not
- // strings or browser refuses to store some cookies, we update the model in the push fn.
- $rootScope.$watch(push);
-
- return cookies;
-
-
- /**
- * Pushes all the cookies from the service to the browser and verifies if all cookies were
- * stored.
- */
- function push() {
- var name,
- value,
- browserCookies,
- updated;
-
- //delete any cookies deleted in $cookies
- for (name in lastCookies) {
- if (isUndefined(cookies[name])) {
- $browser.cookies(name, undefined);
- }
- }
-
- //update all cookies updated in $cookies
- for(name in cookies) {
- value = cookies[name];
- if (!angular.isString(value)) {
- value = '' + value;
- cookies[name] = value;
- }
- if (value !== lastCookies[name]) {
- $browser.cookies(name, value);
- updated = true;
- }
- }
-
- //verify what was actually stored
- if (updated){
- updated = false;
- browserCookies = $browser.cookies();
-
- for (name in cookies) {
- if (cookies[name] !== browserCookies[name]) {
- //delete or reset all cookies that the browser dropped from $cookies
- if (isUndefined(browserCookies[name])) {
- delete cookies[name];
- } else {
- cookies[name] = browserCookies[name];
- }
- updated = true;
- }
- }
- }
- }
- }]).
-
+ * Use `$cookiesProvider` to change the default behavior of the {@link ngCookies.$cookies $cookies} service.
+ * */
+ provider('$cookies', [function $CookiesProvider() {
+ /**
+ * @ngdoc property
+ * @name $cookiesProvider#defaults
+ * @description
+ *
+ * Object containing default options to pass when setting cookies.
+ *
+ * The object may have following properties:
+ *
+ * - **path** - `{string}` - The cookie will be available only for this path and its
+ * sub-paths. By default, this would be the URL that appears in your base tag.
+ * - **domain** - `{string}` - The cookie will be available only for this domain and
+ * its sub-domains. For obvious security reasons the user agent will not accept the
+ * cookie if the current domain is not a sub domain or equals to the requested domain.
+ * - **expires** - `{string|Date}` - String of the form "Wdy, DD Mon YYYY HH:MM:SS GMT"
+ * or a Date object indicating the exact date/time this cookie will expire.
+ * - **secure** - `{boolean}` - The cookie will be available only in secured connection.
+ *
+ * Note: by default the address that appears in your `<base>` tag will be used as path.
+ * This is import so that cookies will be visible for all routes in case html5mode is enabled
+ *
+ **/
+ var defaults = this.defaults = {};
- /**
- * @ngdoc service
- * @name $cookieStore
- * @requires $cookies
- *
- * @description
- * Provides a key-value (string-object) storage, that is backed by session cookies.
- * Objects put or retrieved from this storage are automatically serialized or
- * deserialized by angular's toJson/fromJson.
- *
- * Requires the {@link ngCookies `ngCookies`} module to be installed.
- *
- * @example
- *
- * ```js
- * angular.module('cookieStoreExample', ['ngCookies'])
- * .controller('ExampleController', ['$cookieStore', function($cookieStore) {
- * // Put cookie
- * $cookieStore.put('myFavorite','oatmeal');
- * // Get cookie
- * var favoriteCookie = $cookieStore.get('myFavorite');
- * // Removing a cookie
- * $cookieStore.remove('myFavorite');
- * }]);
- * ```
- */
- factory('$cookieStore', ['$cookies', function($cookies) {
+ function calcOptions(options) {
+ return options ? angular.extend({}, defaults, options) : defaults;
+ }
+ /**
+ * @ngdoc service
+ * @name $cookies
+ *
+ * @description
+ * Provides read/write access to browser's cookies.
+ *
+ * <div class="alert alert-info">
+ * Up until Angular 1.3, `$cookies` exposed properties that represented the
+ * current browser cookie values. In version 1.4, this behavior has changed, and
+ * `$cookies` now provides a standard api of getters, setters etc.
+ * </div>
+ *
+ * Requires the {@link ngCookies `ngCookies`} module to be installed.
+ *
+ * @example
+ *
+ * ```js
+ * angular.module('cookiesExample', ['ngCookies'])
+ * .controller('ExampleController', ['$cookies', function($cookies) {
+ * // Retrieving a cookie
+ * var favoriteCookie = $cookies.get('myFavorite');
+ * // Setting a cookie
+ * $cookies.put('myFavorite', 'oatmeal');
+ * }]);
+ * ```
+ */
+ this.$get = ['$$cookieReader', '$$cookieWriter', function($$cookieReader, $$cookieWriter) {
return {
/**
* @ngdoc method
- * @name $cookieStore#get
+ * @name $cookies#get
*
* @description
* Returns the value of given cookie key
*
* @param {string} key Id to use for lookup.
- * @returns {Object} Deserialized cookie value.
+ * @returns {string} Raw cookie value.
*/
get: function(key) {
- var value = $cookies[key];
+ return $$cookieReader()[key];
+ },
+
+ /**
+ * @ngdoc method
+ * @name $cookies#getObject
+ *
+ * @description
+ * Returns the deserialized value of given cookie key
+ *
+ * @param {string} key Id to use for lookup.
+ * @returns {Object} Deserialized cookie value.
+ */
+ getObject: function(key) {
+ var value = this.get(key);
return value ? angular.fromJson(value) : value;
},
/**
* @ngdoc method
- * @name $cookieStore#put
+ * @name $cookies#getAll
+ *
+ * @description
+ * Returns a key value object with all the cookies
+ *
+ * @returns {Object} All cookies
+ */
+ getAll: function() {
+ return $$cookieReader();
+ },
+
+ /**
+ * @ngdoc method
+ * @name $cookies#put
*
* @description
* Sets a value for given cookie key
*
* @param {string} key Id for the `value`.
+ * @param {string} value Raw value to be stored.
+ * @param {Object=} options Options object.
+ * See {@link ngCookies.$cookiesProvider#defaults $cookiesProvider.defaults}
+ */
+ put: function(key, value, options) {
+ $$cookieWriter(key, value, calcOptions(options));
+ },
+
+ /**
+ * @ngdoc method
+ * @name $cookies#putObject
+ *
+ * @description
+ * Serializes and sets a value for given cookie key
+ *
+ * @param {string} key Id for the `value`.
* @param {Object} value Value to be stored.
+ * @param {Object=} options Options object.
+ * See {@link ngCookies.$cookiesProvider#defaults $cookiesProvider.defaults}
*/
- put: function(key, value) {
- $cookies[key] = angular.toJson(value);
+ putObject: function(key, value, options) {
+ this.put(key, angular.toJson(value), options);
},
/**
* @ngdoc method
- * @name $cookieStore#remove
+ * @name $cookies#remove
*
* @description
* Remove given cookie
*
* @param {string} key Id of the key-value pair to delete.
+ * @param {Object=} options Options object.
+ * See {@link ngCookies.$cookiesProvider#defaults $cookiesProvider.defaults}
*/
- remove: function(key) {
- delete $cookies[key];
+ remove: function(key, options) {
+ $$cookieWriter(key, undefined, calcOptions(options));
}
};
+ }];
+ }]);
+
+angular.module('ngCookies').
+/**
+ * @ngdoc service
+ * @name $cookieStore
+ * @deprecated
+ * @requires $cookies
+ *
+ * @description
+ * Provides a key-value (string-object) storage, that is backed by session cookies.
+ * Objects put or retrieved from this storage are automatically serialized or
+ * deserialized by angular's toJson/fromJson.
+ *
+ * Requires the {@link ngCookies `ngCookies`} module to be installed.
+ *
+ * <div class="alert alert-danger">
+ * **Note:** The $cookieStore service is **deprecated**.
+ * Please use the {@link ngCookies.$cookies `$cookies`} service instead.
+ * </div>
+ *
+ * @example
+ *
+ * ```js
+ * angular.module('cookieStoreExample', ['ngCookies'])
+ * .controller('ExampleController', ['$cookieStore', function($cookieStore) {
+ * // Put cookie
+ * $cookieStore.put('myFavorite','oatmeal');
+ * // Get cookie
+ * var favoriteCookie = $cookieStore.get('myFavorite');
+ * // Removing a cookie
+ * $cookieStore.remove('myFavorite');
+ * }]);
+ * ```
+ */
+ factory('$cookieStore', ['$cookies', function($cookies) {
+
+ return {
+ /**
+ * @ngdoc method
+ * @name $cookieStore#get
+ *
+ * @description
+ * Returns the value of given cookie key
+ *
+ * @param {string} key Id to use for lookup.
+ * @returns {Object} Deserialized cookie value, undefined if the cookie does not exist.
+ */
+ get: function(key) {
+ return $cookies.getObject(key);
+ },
+
+ /**
+ * @ngdoc method
+ * @name $cookieStore#put
+ *
+ * @description
+ * Sets a value for given cookie key
+ *
+ * @param {string} key Id for the `value`.
+ * @param {Object} value Value to be stored.
+ */
+ put: function(key, value) {
+ $cookies.putObject(key, value);
+ },
+
+ /**
+ * @ngdoc method
+ * @name $cookieStore#remove
+ *
+ * @description
+ * Remove given cookie
+ *
+ * @param {string} key Id of the key-value pair to delete.
+ */
+ remove: function(key) {
+ $cookies.remove(key);
+ }
+ };
+
+ }]);
+
+/**
+ * @name $$cookieWriter
+ * @requires $document
+ *
+ * @description
+ * This is a private service for writing cookies
+ *
+ * @param {string} name Cookie name
+ * @param {string=} value Cookie value (if undefined, cookie will be deleted)
+ * @param {Object=} options Object with options that need to be stored for the cookie.
+ */
+function $$CookieWriter($document, $log, $browser) {
+ var cookiePath = $browser.baseHref();
+ var rawDocument = $document[0];
+
+ function buildCookieString(name, value, options) {
+ var path, expires;
+ options = options || {};
+ expires = options.expires;
+ path = angular.isDefined(options.path) ? options.path : cookiePath;
+ if (value === undefined) {
+ expires = 'Thu, 01 Jan 1970 00:00:00 GMT';
+ value = '';
+ }
+ if (angular.isString(expires)) {
+ expires = new Date(expires);
+ }
+
+ var str = encodeURIComponent(name) + '=' + encodeURIComponent(value);
+ str += path ? ';path=' + path : '';
+ str += options.domain ? ';domain=' + options.domain : '';
+ str += expires ? ';expires=' + expires.toUTCString() : '';
+ str += options.secure ? ';secure' : '';
+
+ // per http://www.ietf.org/rfc/rfc2109.txt browser must allow at minimum:
+ // - 300 cookies
+ // - 20 cookies per unique domain
+ // - 4096 bytes per cookie
+ var cookieLength = str.length + 1;
+ if (cookieLength > 4096) {
+ $log.warn("Cookie '" + name +
+ "' possibly not set or overflowed because it was too large (" +
+ cookieLength + " > 4096 bytes)!");
+ }
+
+ return str;
+ }
+
+ return function(name, value, options) {
+ rawDocument.cookie = buildCookieString(name, value, options);
+ };
+}
+
+$$CookieWriter.$inject = ['$document', '$log', '$browser'];
- }]);
+angular.module('ngCookies').provider('$$cookieWriter', function $$CookieWriterProvider() {
+ this.$get = $$CookieWriter;
+});
})(window, window.angular);
diff --git a/libs/bower_components/angular-cookies/angular-cookies.min.js b/libs/bower_components/angular-cookies/angular-cookies.min.js
index abec0652dc..36b74e96fd 100644
--- a/libs/bower_components/angular-cookies/angular-cookies.min.js
+++ b/libs/bower_components/angular-cookies/angular-cookies.min.js
@@ -1,8 +1,9 @@
/*
- AngularJS v1.2.28
- (c) 2010-2014 Google, Inc. http://angularjs.org
+ AngularJS v1.4.3
+ (c) 2010-2015 Google, Inc. http://angularjs.org
License: MIT
*/
-(function(p,f,n){'use strict';f.module("ngCookies",["ng"]).factory("$cookies",["$rootScope","$browser",function(e,b){var c={},g={},h,k=!1,l=f.copy,m=f.isUndefined;b.addPollFn(function(){var a=b.cookies();h!=a&&(h=a,l(a,g),l(a,c),k&&e.$apply())})();k=!0;e.$watch(function(){var a,d,e;for(a in g)m(c[a])&&b.cookies(a,n);for(a in c)d=c[a],f.isString(d)||(d=""+d,c[a]=d),d!==g[a]&&(b.cookies(a,d),e=!0);if(e)for(a in d=b.cookies(),c)c[a]!==d[a]&&(m(d[a])?delete c[a]:c[a]=d[a])});return c}]).factory("$cookieStore",
-["$cookies",function(e){return{get:function(b){return(b=e[b])?f.fromJson(b):b},put:function(b,c){e[b]=f.toJson(c)},remove:function(b){delete e[b]}}}])})(window,window.angular);
+(function(p,g,l){'use strict';function m(b,a,f){var c=f.baseHref(),k=b[0];return function(b,d,e){var f,h;e=e||{};h=e.expires;f=g.isDefined(e.path)?e.path:c;d===l&&(h="Thu, 01 Jan 1970 00:00:00 GMT",d="");g.isString(h)&&(h=new Date(h));d=encodeURIComponent(b)+"="+encodeURIComponent(d);d=d+(f?";path="+f:"")+(e.domain?";domain="+e.domain:"");d+=h?";expires="+h.toUTCString():"";d+=e.secure?";secure":"";e=d.length+1;4096<e&&a.warn("Cookie '"+b+"' possibly not set or overflowed because it was too large ("+
+e+" > 4096 bytes)!");k.cookie=d}}g.module("ngCookies",["ng"]).provider("$cookies",[function(){var b=this.defaults={};this.$get=["$$cookieReader","$$cookieWriter",function(a,f){return{get:function(c){return a()[c]},getObject:function(c){return(c=this.get(c))?g.fromJson(c):c},getAll:function(){return a()},put:function(c,a,n){f(c,a,n?g.extend({},b,n):b)},putObject:function(c,b,a){this.put(c,g.toJson(b),a)},remove:function(a,k){f(a,l,k?g.extend({},b,k):b)}}}]}]);g.module("ngCookies").factory("$cookieStore",
+["$cookies",function(b){return{get:function(a){return b.getObject(a)},put:function(a,f){b.putObject(a,f)},remove:function(a){b.remove(a)}}}]);m.$inject=["$document","$log","$browser"];g.module("ngCookies").provider("$$cookieWriter",function(){this.$get=m})})(window,window.angular);
//# sourceMappingURL=angular-cookies.min.js.map
diff --git a/libs/bower_components/angular-cookies/angular-cookies.min.js.map b/libs/bower_components/angular-cookies/angular-cookies.min.js.map
index 26f3616897..84e6a5701f 100644
--- a/libs/bower_components/angular-cookies/angular-cookies.min.js.map
+++ b/libs/bower_components/angular-cookies/angular-cookies.min.js.map
@@ -1,8 +1,8 @@
{
"version":3,
"file":"angular-cookies.min.js",
-"lineCount":7,
-"mappings":"A;;;;;aAKC,SAAQ,CAACA,CAAD,CAASC,CAAT,CAAkBC,CAAlB,CAA6B,CAmBtCD,CAAAE,OAAA,CAAe,WAAf,CAA4B,CAAC,IAAD,CAA5B,CAAAC,QAAA,CA0BW,UA1BX,CA0BuB,CAAC,YAAD,CAAe,UAAf,CAA2B,QAAS,CAACC,CAAD,CAAaC,CAAb,CAAuB,CAAA,IACxEC,EAAU,EAD8D,CAExEC,EAAc,EAF0D,CAGxEC,CAHwE,CAIxEC,EAAU,CAAA,CAJ8D,CAKxEC,EAAOV,CAAAU,KALiE,CAMxEC,EAAcX,CAAAW,YAGlBN,EAAAO,UAAA,CAAmB,QAAQ,EAAG,CAC5B,IAAIC,EAAiBR,CAAAC,QAAA,EACjBE,EAAJ,EAA0BK,CAA1B,GACEL,CAGA,CAHqBK,CAGrB,CAFAH,CAAA,CAAKG,CAAL,CAAqBN,CAArB,CAEA,CADAG,CAAA,CAAKG,CAAL,CAAqBP,CAArB,CACA,CAAIG,CAAJ,EAAaL,CAAAU,OAAA,EAJf,CAF4B,CAA9B,CAAA,EAUAL,EAAA,CAAU,CAAA,CAKVL,EAAAW,OAAA,CASAC,QAAa,EAAG,CAAA,IACVC,CADU,CAEVC,CAFU,CAIVC,CAGJ,KAAKF,CAAL,GAAaV,EAAb,CACMI,CAAA,CAAYL,CAAA,CAAQW,CAAR,CAAZ,CAAJ,EACEZ,CAAAC,QAAA,CAAiBW,CAAjB,CAAuBhB,CAAvB,CAKJ,KAAIgB,CAAJ,GAAYX,EAAZ,CACEY,CAKA,CALQZ,CAAA,CAAQW,CAAR,CAKR,CAJKjB,CAAAoB,SAAA,CAAiBF,CAAjB,CAIL,GAHEA,CACA,CADQ,EACR,CADaA,CACb,CAAAZ,CAAA,CAAQW,CAAR,CAAA,CAAgBC,CAElB,EAAIA,CAAJ,GAAcX,CAAA,CAAYU,CAAZ,CAAd,GACEZ,CAAAC,QAAA,CAAiBW,CAAjB,CAAuBC,CAAvB,CACA,CAAAC,CAAA,CAAU,CAAA,CAFZ,CAOF,IAAIA,CAAJ,CAIE,IAAKF,CAAL,GAFAI,EAEaf,CAFID,CAAAC,QAAA,EAEJA,CAAAA,CAAb,CACMA,CAAA,CAAQW,CAAR,CAAJ,GAAsBI,CAAA,CAAeJ,CAAf,CAAtB,GAEMN,CAAA,CAAYU,CAAA,CAAeJ,CAAf,CAAZ,CAAJ,CACE,OAAOX,CAAA,CAAQW,CAAR,CADT,CAGEX,CAAA,CAAQW,CAAR,CAHF,CAGkBI,CAAA,CAAeJ,CAAf,CALpB,CAhCU,CAThB,CAEA,OAAOX,EA1BqE,CAA3D,CA1BvB,CAAAH,QAAA,CAoIW,cApIX;AAoI2B,CAAC,UAAD,CAAa,QAAQ,CAACmB,CAAD,CAAW,CAErD,MAAO,KAWAC,QAAQ,CAACC,CAAD,CAAM,CAEjB,MAAO,CADHN,CACG,CADKI,CAAA,CAASE,CAAT,CACL,EAAQxB,CAAAyB,SAAA,CAAiBP,CAAjB,CAAR,CAAkCA,CAFxB,CAXd,KA0BAQ,QAAQ,CAACF,CAAD,CAAMN,CAAN,CAAa,CACxBI,CAAA,CAASE,CAAT,CAAA,CAAgBxB,CAAA2B,OAAA,CAAeT,CAAf,CADQ,CA1BrB,QAuCGU,QAAQ,CAACJ,CAAD,CAAM,CACpB,OAAOF,CAAA,CAASE,CAAT,CADa,CAvCjB,CAF8C,CAAhC,CApI3B,CAnBsC,CAArC,CAAA,CAwMEzB,MAxMF,CAwMUA,MAAAC,QAxMV;",
+"lineCount":8,
+"mappings":"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",
"sources":["angular-cookies.js"],
-"names":["window","angular","undefined","module","factory","$rootScope","$browser","cookies","lastCookies","lastBrowserCookies","runEval","copy","isUndefined","addPollFn","currentCookies","$apply","$watch","push","name","value","updated","isString","browserCookies","$cookies","get","key","fromJson","put","toJson","remove"]
+"names":["window","angular","undefined","$$CookieWriter","$document","$log","$browser","cookiePath","baseHref","rawDocument","name","value","options","path","expires","isDefined","isString","Date","str","encodeURIComponent","domain","toUTCString","secure","cookieLength","length","warn","cookie","module","provider","$CookiesProvider","defaults","$get","$$cookieReader","$$cookieWriter","get","key","getObject","fromJson","getAll","put","extend","putObject","toJson","remove","factory","$cookies","$inject","$$CookieWriterProvider"]
}
diff --git a/libs/bower_components/angular-cookies/bower.json b/libs/bower_components/angular-cookies/bower.json
index aa202dc0c4..9ab6d5f01b 100644
--- a/libs/bower_components/angular-cookies/bower.json
+++ b/libs/bower_components/angular-cookies/bower.json
@@ -1,9 +1,9 @@
{
"name": "angular-cookies",
- "version": "1.2.28",
+ "version": "1.4.3",
"main": "./angular-cookies.js",
"ignore": [],
"dependencies": {
- "angular": "1.2.28"
+ "angular": "1.4.3"
}
}
diff --git a/libs/bower_components/angular-cookies/index.js b/libs/bower_components/angular-cookies/index.js
new file mode 100644
index 0000000000..657667549a
--- /dev/null
+++ b/libs/bower_components/angular-cookies/index.js
@@ -0,0 +1,2 @@
+require('./angular-cookies');
+module.exports = 'ngCookies';
diff --git a/libs/bower_components/angular-cookies/package.json b/libs/bower_components/angular-cookies/package.json
index 84ea78c9cb..a9862f9bcc 100644
--- a/libs/bower_components/angular-cookies/package.json
+++ b/libs/bower_components/angular-cookies/package.json
@@ -1,8 +1,8 @@
{
"name": "angular-cookies",
- "version": "1.2.28",
+ "version": "1.4.3",
"description": "AngularJS module for cookies",
- "main": "angular-cookies.js",
+ "main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
diff --git a/libs/bower_components/angular-mocks/.bower.json b/libs/bower_components/angular-mocks/.bower.json
index 94f5bbaab0..21dfd23718 100644
--- a/libs/bower_components/angular-mocks/.bower.json
+++ b/libs/bower_components/angular-mocks/.bower.json
@@ -1,19 +1,19 @@
{
"name": "angular-mocks",
- "version": "1.2.28",
+ "version": "1.4.3",
"main": "./angular-mocks.js",
"ignore": [],
"dependencies": {
- "angular": "1.2.28"
+ "angular": "1.4.3"
},
"homepage": "https://github.com/angular/bower-angular-mocks",
- "_release": "1.2.28",
+ "_release": "1.4.3",
"_resolution": {
"type": "version",
- "tag": "v1.2.28",
- "commit": "6bb9b6fd3fdb2eba0f64dc615fa55c5f0050af75"
+ "tag": "v1.4.3",
+ "commit": "7e3beec84afceeb060a3c6def0d7ca965727851c"
},
"_source": "git://github.com/angular/bower-angular-mocks.git",
- "_target": "~1.2.0",
+ "_target": "~1.4.0",
"_originalSource": "angular-mocks"
} \ No newline at end of file
diff --git a/libs/bower_components/angular-mocks/README.md b/libs/bower_components/angular-mocks/README.md
index 1604ef8804..440cce9b78 100644
--- a/libs/bower_components/angular-mocks/README.md
+++ b/libs/bower_components/angular-mocks/README.md
@@ -14,10 +14,16 @@ You can install this package either with `npm` or with `bower`.
npm install angular-mocks
```
-The mocks are then available at `node_modules/angular-mocks/angular-mocks.js`.
-
-Note that this package is not in CommonJS format, so doing `require('angular-mocks')` will
-return `undefined`.
+You can `require` ngMock modules:
+
+```js
+var angular = require('angular');
+angular.module('myMod', [
+ require('angular-animate'),
+ require('angular-mocks/ngMock')
+ require('angular-mocks/ngAnimateMock')
+]);
+```
### bower
@@ -36,7 +42,7 @@ Documentation is available on the
The MIT License
-Copyright (c) 2010-2012 Google, Inc. http://angularjs.org
+Copyright (c) 2010-2015 Google, Inc. http://angularjs.org
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/libs/bower_components/angular-mocks/angular-mocks.js b/libs/bower_components/angular-mocks/angular-mocks.js
index de2a966ad9..9482b702b3 100644
--- a/libs/bower_components/angular-mocks/angular-mocks.js
+++ b/libs/bower_components/angular-mocks/angular-mocks.js
@@ -1,6 +1,6 @@
/**
- * @license AngularJS v1.2.28
- * (c) 2010-2014 Google, Inc. http://angularjs.org
+ * @license AngularJS v1.4.3
+ * (c) 2010-2015 Google, Inc. http://angularjs.org
* License: MIT
*/
(function(window, angular, undefined) {
@@ -53,9 +53,10 @@ angular.mock.$Browser = function() {
self.onUrlChange = function(listener) {
self.pollFns.push(
function() {
- if (self.$$lastUrl != self.$$url) {
+ if (self.$$lastUrl !== self.$$url || self.$$state !== self.$$lastState) {
self.$$lastUrl = self.$$url;
- listener(self.$$url);
+ self.$$lastState = self.$$state;
+ listener(self.$$url, self.$$state);
}
}
);
@@ -63,17 +64,16 @@ angular.mock.$Browser = function() {
return listener;
};
+ self.$$applicationDestroyed = angular.noop;
self.$$checkUrlChange = angular.noop;
- self.cookieHash = {};
- self.lastCookieHash = {};
self.deferredFns = [];
self.deferredNextId = 0;
self.defer = function(fn, delay) {
delay = delay || 0;
self.deferredFns.push({time:(self.defer.now + delay), fn:fn, id: self.deferredNextId});
- self.deferredFns.sort(function(a,b){ return a.time - b.time;});
+ self.deferredFns.sort(function(a, b) { return a.time - b.time;});
return self.deferredNextId++;
};
@@ -116,7 +116,7 @@ angular.mock.$Browser = function() {
self.defer.now += delay;
} else {
if (self.deferredFns.length) {
- self.defer.now = self.deferredFns[self.deferredFns.length-1].time;
+ self.defer.now = self.deferredFns[self.deferredFns.length - 1].time;
} else {
throw new Error('No deferred tasks to be flushed');
}
@@ -127,7 +127,7 @@ angular.mock.$Browser = function() {
}
};
- self.$$baseHref = '';
+ self.$$baseHref = '/';
self.baseHref = function() {
return this.$$baseHref;
};
@@ -141,42 +141,27 @@ angular.mock.$Browser.prototype = {
* run all fns in pollFns
*/
poll: function poll() {
- angular.forEach(this.pollFns, function(pollFn){
+ angular.forEach(this.pollFns, function(pollFn) {
pollFn();
});
},
- addPollFn: function(pollFn) {
- this.pollFns.push(pollFn);
- return pollFn;
- },
-
- url: function(url, replace) {
+ url: function(url, replace, state) {
+ if (angular.isUndefined(state)) {
+ state = null;
+ }
if (url) {
this.$$url = url;
+ // Native pushState serializes & copies the object; simulate it.
+ this.$$state = angular.copy(state);
return this;
}
return this.$$url;
},
- cookies: function(name, value) {
- if (name) {
- if (angular.isUndefined(value)) {
- delete this.cookieHash[name];
- } else {
- if (angular.isString(value) && //strings only
- value.length <= 4096) { //strict cookie storage limits
- this.cookieHash[name] = value;
- }
- }
- } else {
- if (!angular.equals(this.cookieHash, this.lastCookieHash)) {
- this.lastCookieHash = angular.copy(this.cookieHash);
- this.cookieHash = angular.copy(this.cookieHash);
- }
- return this.cookieHash;
- }
+ state: function() {
+ return this.$$state;
},
notifyWhenNoOutstandingRequests: function(fn) {
@@ -191,7 +176,7 @@ angular.mock.$Browser.prototype = {
*
* @description
* Configures the mock implementation of {@link ng.$exceptionHandler} to rethrow or to log errors
- * passed into the `$exceptionHandler`.
+ * passed to the `$exceptionHandler`.
*/
/**
@@ -200,7 +185,7 @@ angular.mock.$Browser.prototype = {
*
* @description
* Mock implementation of {@link ng.$exceptionHandler} that rethrows or logs errors passed
- * into it. See {@link ngMock.$exceptionHandlerProvider $exceptionHandlerProvider} for configuration
+ * to it. See {@link ngMock.$exceptionHandlerProvider $exceptionHandlerProvider} for configuration
* information.
*
*
@@ -240,32 +225,31 @@ angular.mock.$ExceptionHandlerProvider = function() {
*
* @param {string} mode Mode of operation, defaults to `rethrow`.
*
- * - `rethrow`: If any errors are passed into the handler in tests, it typically
- * means that there is a bug in the application or test, so this mock will
- * make these tests fail.
* - `log`: Sometimes it is desirable to test that an error is thrown, for this case the `log`
* mode stores an array of errors in `$exceptionHandler.errors`, to allow later
* assertion of them. See {@link ngMock.$log#assertEmpty assertEmpty()} and
* {@link ngMock.$log#reset reset()}
+ * - `rethrow`: If any errors are passed to the handler in tests, it typically means that there
+ * is a bug in the application or test, so this mock will make these tests fail.
+ * For any implementations that expect exceptions to be thrown, the `rethrow` mode
+ * will also maintain a log of thrown errors.
*/
this.mode = function(mode) {
- switch(mode) {
- case 'rethrow':
- handler = function(e) {
- throw e;
- };
- break;
+
+ switch (mode) {
case 'log':
+ case 'rethrow':
var errors = [];
-
handler = function(e) {
if (arguments.length == 1) {
errors.push(e);
} else {
errors.push([].slice.call(arguments, 0));
}
+ if (mode === "rethrow") {
+ throw e;
+ }
};
-
handler.errors = errors;
break;
default:
@@ -307,7 +291,7 @@ angular.mock.$LogProvider = function() {
}
};
- this.$get = function () {
+ this.$get = function() {
var $log = {
log: function() { $log.log.logs.push(concat([], arguments, 0)); },
warn: function() { $log.warn.logs.push(concat([], arguments, 0)); },
@@ -327,13 +311,13 @@ angular.mock.$LogProvider = function() {
* @description
* Reset all of the logging arrays to empty.
*/
- $log.reset = function () {
+ $log.reset = function() {
/**
* @ngdoc property
* @name $log#log.logs
*
* @description
- * Array of messages logged using {@link ngMock.$log#log}.
+ * Array of messages logged using {@link ng.$log#log `log()`}.
*
* @example
* ```js
@@ -347,7 +331,7 @@ angular.mock.$LogProvider = function() {
* @name $log#info.logs
*
* @description
- * Array of messages logged using {@link ngMock.$log#info}.
+ * Array of messages logged using {@link ng.$log#info `info()`}.
*
* @example
* ```js
@@ -361,7 +345,7 @@ angular.mock.$LogProvider = function() {
* @name $log#warn.logs
*
* @description
- * Array of messages logged using {@link ngMock.$log#warn}.
+ * Array of messages logged using {@link ng.$log#warn `warn()`}.
*
* @example
* ```js
@@ -375,7 +359,7 @@ angular.mock.$LogProvider = function() {
* @name $log#error.logs
*
* @description
- * Array of messages logged using {@link ngMock.$log#error}.
+ * Array of messages logged using {@link ng.$log#error `error()`}.
*
* @example
* ```js
@@ -389,7 +373,7 @@ angular.mock.$LogProvider = function() {
* @name $log#debug.logs
*
* @description
- * Array of messages logged using {@link ngMock.$log#debug}.
+ * Array of messages logged using {@link ng.$log#debug `debug()`}.
*
* @example
* ```js
@@ -405,21 +389,21 @@ angular.mock.$LogProvider = function() {
* @name $log#assertEmpty
*
* @description
- * Assert that the all of the logging methods have no logged messages. If messages present, an
- * exception is thrown.
+ * Assert that all of the logging methods have no logged messages. If any messages are present,
+ * an exception is thrown.
*/
$log.assertEmpty = function() {
var errors = [];
angular.forEach(['error', 'warn', 'info', 'log', 'debug'], function(logLevel) {
angular.forEach($log[logLevel].logs, function(log) {
- angular.forEach(log, function (logItem) {
+ angular.forEach(log, function(logItem) {
errors.push('MOCK $log (' + logLevel + '): ' + String(logItem) + '\n' +
(logItem.stack || ''));
});
});
});
if (errors.length) {
- errors.unshift("Expected $log to be empty! Either a message was logged unexpectedly, or "+
+ errors.unshift("Expected $log to be empty! Either a message was logged unexpectedly, or " +
"an expected log message was not checked and removed:");
errors.push('');
throw new Error(errors.join('\n---------\n'));
@@ -449,23 +433,28 @@ angular.mock.$LogProvider = function() {
* indefinitely.
* @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
* will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
+ * @param {...*=} Pass additional parameters to the executed function.
* @returns {promise} A promise which will be notified on each iteration.
*/
angular.mock.$IntervalProvider = function() {
- this.$get = ['$rootScope', '$q',
- function($rootScope, $q) {
+ this.$get = ['$browser', '$rootScope', '$q', '$$q',
+ function($browser, $rootScope, $q, $$q) {
var repeatFns = [],
nextRepeatId = 0,
now = 0;
var $interval = function(fn, delay, count, invokeApply) {
- var deferred = $q.defer(),
- promise = deferred.promise,
+ var hasParams = arguments.length > 4,
+ args = hasParams ? Array.prototype.slice.call(arguments, 4) : [],
iteration = 0,
- skipApply = (angular.isDefined(invokeApply) && !invokeApply);
+ skipApply = (angular.isDefined(invokeApply) && !invokeApply),
+ deferred = (skipApply ? $$q : $q).defer(),
+ promise = deferred.promise;
count = (angular.isDefined(count)) ? count : 0;
- promise.then(null, null, fn);
+ promise.then(null, null, (!hasParams) ? fn : function() {
+ fn.apply(null, args);
+ });
promise.$$intervalId = nextRepeatId;
@@ -485,7 +474,11 @@ angular.mock.$IntervalProvider = function() {
}
}
- if (!skipApply) $rootScope.$apply();
+ if (skipApply) {
+ $browser.defer.flush();
+ } else {
+ $rootScope.$apply();
+ }
}
repeatFns.push({
@@ -495,7 +488,7 @@ angular.mock.$IntervalProvider = function() {
id: nextRepeatId,
deferred: deferred
});
- repeatFns.sort(function(a,b){ return a.nextTime - b.nextTime;});
+ repeatFns.sort(function(a, b) { return a.nextTime - b.nextTime;});
nextRepeatId++;
return promise;
@@ -511,7 +504,7 @@ angular.mock.$IntervalProvider = function() {
* @returns {boolean} Returns `true` if the task was successfully cancelled.
*/
$interval.cancel = function(promise) {
- if(!promise) return false;
+ if (!promise) return false;
var fnIndex;
angular.forEach(repeatFns, function(fn, index) {
@@ -544,7 +537,7 @@ angular.mock.$IntervalProvider = function() {
var task = repeatFns[0];
task.fn();
task.nextTime += task.delay;
- repeatFns.sort(function(a,b){ return a.nextTime - b.nextTime;});
+ repeatFns.sort(function(a, b) { return a.nextTime - b.nextTime;});
}
return millis;
};
@@ -568,20 +561,20 @@ function jsonStringToDate(string) {
tzHour = 0,
tzMin = 0;
if (match[9]) {
- tzHour = int(match[9] + match[10]);
- tzMin = int(match[9] + match[11]);
+ tzHour = toInt(match[9] + match[10]);
+ tzMin = toInt(match[9] + match[11]);
}
- date.setUTCFullYear(int(match[1]), int(match[2]) - 1, int(match[3]));
- date.setUTCHours(int(match[4]||0) - tzHour,
- int(match[5]||0) - tzMin,
- int(match[6]||0),
- int(match[7]||0));
+ date.setUTCFullYear(toInt(match[1]), toInt(match[2]) - 1, toInt(match[3]));
+ date.setUTCHours(toInt(match[4] || 0) - tzHour,
+ toInt(match[5] || 0) - tzMin,
+ toInt(match[6] || 0),
+ toInt(match[7] || 0));
return date;
}
return string;
}
-function int(str) {
+function toInt(str) {
return parseInt(str, 10);
}
@@ -592,9 +585,10 @@ function padNumber(num, digits, trim) {
num = -num;
}
num = '' + num;
- while(num.length < digits) num = '0' + num;
- if (trim)
+ while (num.length < digits) num = '0' + num;
+ if (trim) {
num = num.substr(num.length - digits);
+ }
return neg + num;
}
@@ -636,7 +630,7 @@ function padNumber(num, digits, trim) {
* ```
*
*/
-angular.mock.TzDate = function (offset, timestamp) {
+angular.mock.TzDate = function(offset, timestamp) {
var self = new Date(0);
if (angular.isString(timestamp)) {
var tsStr = timestamp;
@@ -644,17 +638,18 @@ angular.mock.TzDate = function (offset, timestamp) {
self.origDate = jsonStringToDate(timestamp);
timestamp = self.origDate.getTime();
- if (isNaN(timestamp))
+ if (isNaN(timestamp)) {
throw {
name: "Illegal Argument",
message: "Arg '" + tsStr + "' passed into TzDate constructor is not a valid date string"
};
+ }
} else {
self.origDate = new Date(timestamp);
}
var localOffset = new Date(timestamp).getTimezoneOffset();
- self.offsetDiff = localOffset*60*1000 - offset*1000*60*60;
+ self.offsetDiff = localOffset * 60 * 1000 - offset * 1000 * 60 * 60;
self.date = new Date(timestamp + self.offsetDiff);
self.getTime = function() {
@@ -776,14 +771,23 @@ angular.mock.animate = angular.module('ngAnimateMock', ['ng'])
};
});
- $provide.decorator('$animate', function($delegate, $$asyncCallback) {
+ $provide.decorator('$animate', ['$delegate', '$timeout', '$browser', '$$rAF',
+ function($delegate, $timeout, $browser, $$rAF) {
var animate = {
- queue : [],
- enabled : $delegate.enabled,
- triggerCallbacks : function() {
- $$asyncCallback.flush();
+ queue: [],
+ cancel: $delegate.cancel,
+ enabled: $delegate.enabled,
+ triggerCallbackEvents: function() {
+ $$rAF.flush();
+ },
+ triggerCallbackPromise: function() {
+ $timeout.flush(0);
},
- triggerReflow : function() {
+ triggerCallbacks: function() {
+ this.triggerCallbackEvents();
+ this.triggerCallbackPromise();
+ },
+ triggerReflow: function() {
angular.forEach(reflowQueue, function(fn) {
fn();
});
@@ -792,19 +796,20 @@ angular.mock.animate = angular.module('ngAnimateMock', ['ng'])
};
angular.forEach(
- ['enter','leave','move','addClass','removeClass','setClass'], function(method) {
+ ['animate','enter','leave','move','addClass','removeClass','setClass'], function(method) {
animate[method] = function() {
animate.queue.push({
- event : method,
- element : arguments[0],
- args : arguments
+ event: method,
+ element: arguments[0],
+ options: arguments[arguments.length - 1],
+ args: arguments
});
- $delegate[method].apply($delegate, arguments);
+ return $delegate[method].apply($delegate, arguments);
};
});
return animate;
- });
+ }]);
}]);
@@ -864,13 +869,13 @@ angular.mock.dump = function(object) {
function serializeScope(scope, offset) {
offset = offset || ' ';
var log = [offset + 'Scope(' + scope.$id + '): {'];
- for ( var key in scope ) {
+ for (var key in scope) {
if (Object.prototype.hasOwnProperty.call(scope, key) && !key.match(/^(\$|this)/)) {
log.push(' ' + key + ': ' + angular.toJson(scope[key]));
}
}
var child = scope.$$childHead;
- while(child) {
+ while (child) {
log.push(serializeScope(child, offset + ' '));
child = child.$$nextSibling;
}
@@ -982,6 +987,11 @@ angular.mock.dump = function(object) {
* First we create the controller under test:
*
```js
+ // The module code
+ angular
+ .module('MyApp', [])
+ .controller('MyController', MyController);
+
// The controller code
function MyController($scope, $http) {
var authToken;
@@ -1009,13 +1019,17 @@ angular.mock.dump = function(object) {
```js
// testing controller
describe('MyController', function() {
- var $httpBackend, $rootScope, createController;
+ var $httpBackend, $rootScope, createController, authRequestHandler;
+
+ // Set up the module
+ beforeEach(module('MyApp'));
beforeEach(inject(function($injector) {
// Set up the mock http service responses
$httpBackend = $injector.get('$httpBackend');
// backend definition common for all tests
- $httpBackend.when('GET', '/auth.py').respond({userId: 'userX'}, {'A-Token': 'xxx'});
+ authRequestHandler = $httpBackend.when('GET', '/auth.py')
+ .respond({userId: 'userX'}, {'A-Token': 'xxx'});
// Get hold of a scope (i.e. the root scope)
$rootScope = $injector.get('$rootScope');
@@ -1041,6 +1055,18 @@ angular.mock.dump = function(object) {
});
+ it('should fail authentication', function() {
+
+ // Notice how you can change the response even after it was set
+ authRequestHandler.respond(401, '');
+
+ $httpBackend.expectGET('/auth.py');
+ var controller = createController();
+ $httpBackend.flush();
+ expect($rootScope.status).toBe('Failed...');
+ });
+
+
it('should send msg to server', function() {
var controller = createController();
$httpBackend.flush();
@@ -1063,7 +1089,7 @@ angular.mock.dump = function(object) {
$httpBackend.flush();
$httpBackend.expectPOST('/add-msg.py', undefined, function(headers) {
- // check if the header was send, if it wasn't the expectation won't
+ // check if the header was sent, if it wasn't the expectation won't
// match the request and the test will fail
return headers['Authorization'] == 'xxx';
}).respond(201, '');
@@ -1075,7 +1101,7 @@ angular.mock.dump = function(object) {
```
*/
angular.mock.$HttpBackendProvider = function() {
- this.$get = ['$rootScope', createHttpBackendMock];
+ this.$get = ['$rootScope', '$timeout', createHttpBackendMock];
};
/**
@@ -1092,7 +1118,7 @@ angular.mock.$HttpBackendProvider = function() {
* @param {Object=} $browser Auto-flushing enabled if specified
* @return {Object} Instance of $httpBackend mock
*/
-function createHttpBackendMock($rootScope, $delegate, $browser) {
+function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
var definitions = [],
expectations = [],
responses = [],
@@ -1105,7 +1131,7 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
return function() {
return angular.isNumber(status)
? [status, data, headers, statusText]
- : [200, status, data];
+ : [200, status, data, headers];
};
}
@@ -1122,7 +1148,9 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
}
function wrapResponse(wrapped) {
- if (!$browser && timeout && timeout.then) timeout.then(handleTimeout);
+ if (!$browser && timeout) {
+ timeout.then ? timeout.then(handleTimeout) : $timeout(handleTimeout, timeout);
+ }
return handleResponse;
@@ -1145,14 +1173,16 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
}
if (expectation && expectation.match(method, url)) {
- if (!expectation.matchData(data))
+ if (!expectation.matchData(data)) {
throw new Error('Expected ' + expectation + ' with different data\n' +
'EXPECTED: ' + prettyPrint(expectation.data) + '\nGOT: ' + data);
+ }
- if (!expectation.matchHeaders(headers))
+ if (!expectation.matchHeaders(headers)) {
throw new Error('Expected ' + expectation + ' with different headers\n' +
'EXPECTED: ' + prettyPrint(expectation.headers) + '\nGOT: ' +
prettyPrint(headers));
+ }
expectations.shift();
@@ -1188,32 +1218,39 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
* Creates a new backend definition.
*
* @param {string} method HTTP method.
- * @param {string|RegExp} url HTTP url.
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
+ * and returns true if the url matches the current definition.
* @param {(string|RegExp|function(string))=} data HTTP request body or function that receives
* data string and returns true if the data is as expected.
* @param {(Object|function(Object))=} headers HTTP headers or function that receives http header
* object and returns true if the headers match the current definition.
- * @returns {requestHandler} Returns an object with a `respond` method that controls how a matched
- * request is handled.
+ * @returns {requestHandler} Returns an object with `respond` method that controls how a matched
+ * request is handled. You can save this object for later use and invoke `respond` again in
+ * order to change how a matched request is handled.
*
* - respond –
* `{function([status,] data[, headers, statusText])
* | function(function(method, url, data, headers)}`
* – The respond method takes a set of static data to be returned or a function that can
* return an array containing response status (number), response data (string), response
- * headers (Object), and the text for the status (string).
+ * headers (Object), and the text for the status (string). The respond method returns the
+ * `requestHandler` object for possible overrides.
*/
$httpBackend.when = function(method, url, data, headers) {
var definition = new MockHttpExpectation(method, url, data, headers),
chain = {
respond: function(status, data, headers, statusText) {
+ definition.passThrough = undefined;
definition.response = createResponse(status, data, headers, statusText);
+ return chain;
}
};
if ($browser) {
chain.passThrough = function() {
+ definition.response = undefined;
definition.passThrough = true;
+ return chain;
};
}
@@ -1227,10 +1264,12 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
* @description
* Creates a new backend definition for GET requests. For more info see `when()`.
*
- * @param {string|RegExp} url HTTP url.
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
+ * and returns true if the url matches the current definition.
* @param {(Object|function(Object))=} headers HTTP headers.
- * @returns {requestHandler} Returns an object with a `respond` method that controls how a matched
- * request is handled.
+ * @returns {requestHandler} Returns an object with `respond` method that controls how a matched
+ * request is handled. You can save this object for later use and invoke `respond` again in
+ * order to change how a matched request is handled.
*/
/**
@@ -1239,10 +1278,12 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
* @description
* Creates a new backend definition for HEAD requests. For more info see `when()`.
*
- * @param {string|RegExp} url HTTP url.
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
+ * and returns true if the url matches the current definition.
* @param {(Object|function(Object))=} headers HTTP headers.
- * @returns {requestHandler} Returns an object with a `respond` method that controls how a matched
- * request is handled.
+ * @returns {requestHandler} Returns an object with `respond` method that controls how a matched
+ * request is handled. You can save this object for later use and invoke `respond` again in
+ * order to change how a matched request is handled.
*/
/**
@@ -1251,10 +1292,12 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
* @description
* Creates a new backend definition for DELETE requests. For more info see `when()`.
*
- * @param {string|RegExp} url HTTP url.
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
+ * and returns true if the url matches the current definition.
* @param {(Object|function(Object))=} headers HTTP headers.
- * @returns {requestHandler} Returns an object with a `respond` method that controls how a matched
- * request is handled.
+ * @returns {requestHandler} Returns an object with `respond` method that controls how a matched
+ * request is handled. You can save this object for later use and invoke `respond` again in
+ * order to change how a matched request is handled.
*/
/**
@@ -1263,12 +1306,14 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
* @description
* Creates a new backend definition for POST requests. For more info see `when()`.
*
- * @param {string|RegExp} url HTTP url.
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
+ * and returns true if the url matches the current definition.
* @param {(string|RegExp|function(string))=} data HTTP request body or function that receives
* data string and returns true if the data is as expected.
* @param {(Object|function(Object))=} headers HTTP headers.
- * @returns {requestHandler} Returns an object with a `respond` method that controls how a matched
- * request is handled.
+ * @returns {requestHandler} Returns an object with `respond` method that controls how a matched
+ * request is handled. You can save this object for later use and invoke `respond` again in
+ * order to change how a matched request is handled.
*/
/**
@@ -1277,26 +1322,14 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
* @description
* Creates a new backend definition for PUT requests. For more info see `when()`.
*
- * @param {string|RegExp} url HTTP url.
- * @param {(string|RegExp|function(string))=} data HTTP request body or function that receives
- * data string and returns true if the data is as expected.
- * @param {(Object|function(Object))=} headers HTTP headers.
- * @returns {requestHandler} Returns an object with a `respond` method that controls how a matched
- * request is handled.
- */
-
- /**
- * @ngdoc method
- * @name $httpBackend#whenPATCH
- * @description
- * Creates a new backend definition for PATCH requests. For more info see `when()`.
- *
- * @param {string|RegExp} url HTTP url.
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
+ * and returns true if the url matches the current definition.
* @param {(string|RegExp|function(string))=} data HTTP request body or function that receives
* data string and returns true if the data is as expected.
* @param {(Object|function(Object))=} headers HTTP headers.
- * @returns {requestHandler} Returns an object with a `respond` method that controls how a matched
- * request is handled.
+ * @returns {requestHandler} Returns an object with `respond` method that controls how a matched
+ * request is handled. You can save this object for later use and invoke `respond` again in
+ * order to change how a matched request is handled.
*/
/**
@@ -1305,9 +1338,11 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
* @description
* Creates a new backend definition for JSONP requests. For more info see `when()`.
*
- * @param {string|RegExp} url HTTP url.
- * @returns {requestHandler} Returns an object with a `respond` method that controls how a matched
- * request is handled.
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
+ * and returns true if the url matches the current definition.
+ * @returns {requestHandler} Returns an object with `respond` method that controls how a matched
+ * request is handled. You can save this object for later use and invoke `respond` again in
+ * order to change how a matched request is handled.
*/
createShortMethods('when');
@@ -1319,30 +1354,36 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
* Creates a new request expectation.
*
* @param {string} method HTTP method.
- * @param {string|RegExp} url HTTP url.
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
+ * and returns true if the url matches the current definition.
* @param {(string|RegExp|function(string)|Object)=} data HTTP request body or function that
* receives data string and returns true if the data is as expected, or Object if request body
* is in JSON format.
* @param {(Object|function(Object))=} headers HTTP headers or function that receives http header
* object and returns true if the headers match the current expectation.
- * @returns {requestHandler} Returns an object with a `respond` method that controls how a matched
- * request is handled.
+ * @returns {requestHandler} Returns an object with `respond` method that controls how a matched
+ * request is handled. You can save this object for later use and invoke `respond` again in
+ * order to change how a matched request is handled.
*
* - respond –
* `{function([status,] data[, headers, statusText])
* | function(function(method, url, data, headers)}`
* – The respond method takes a set of static data to be returned or a function that can
* return an array containing response status (number), response data (string), response
- * headers (Object), and the text for the status (string).
+ * headers (Object), and the text for the status (string). The respond method returns the
+ * `requestHandler` object for possible overrides.
*/
$httpBackend.expect = function(method, url, data, headers) {
- var expectation = new MockHttpExpectation(method, url, data, headers);
+ var expectation = new MockHttpExpectation(method, url, data, headers),
+ chain = {
+ respond: function(status, data, headers, statusText) {
+ expectation.response = createResponse(status, data, headers, statusText);
+ return chain;
+ }
+ };
+
expectations.push(expectation);
- return {
- respond: function (status, data, headers, statusText) {
- expectation.response = createResponse(status, data, headers, statusText);
- }
- };
+ return chain;
};
@@ -1352,10 +1393,12 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
* @description
* Creates a new request expectation for GET requests. For more info see `expect()`.
*
- * @param {string|RegExp} url HTTP url.
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
+ * and returns true if the url matches the current definition.
* @param {Object=} headers HTTP headers.
- * @returns {requestHandler} Returns an object with a `respond` method that controls how a matched
- * request is handled. See #expect for more info.
+ * @returns {requestHandler} Returns an object with `respond` method that controls how a matched
+ * request is handled. You can save this object for later use and invoke `respond` again in
+ * order to change how a matched request is handled. See #expect for more info.
*/
/**
@@ -1364,10 +1407,12 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
* @description
* Creates a new request expectation for HEAD requests. For more info see `expect()`.
*
- * @param {string|RegExp} url HTTP url.
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
+ * and returns true if the url matches the current definition.
* @param {Object=} headers HTTP headers.
- * @returns {requestHandler} Returns an object with a `respond` method that controls how a matched
- * request is handled.
+ * @returns {requestHandler} Returns an object with `respond` method that controls how a matched
+ * request is handled. You can save this object for later use and invoke `respond` again in
+ * order to change how a matched request is handled.
*/
/**
@@ -1376,10 +1421,12 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
* @description
* Creates a new request expectation for DELETE requests. For more info see `expect()`.
*
- * @param {string|RegExp} url HTTP url.
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
+ * and returns true if the url matches the current definition.
* @param {Object=} headers HTTP headers.
- * @returns {requestHandler} Returns an object with a `respond` method that controls how a matched
- * request is handled.
+ * @returns {requestHandler} Returns an object with `respond` method that controls how a matched
+ * request is handled. You can save this object for later use and invoke `respond` again in
+ * order to change how a matched request is handled.
*/
/**
@@ -1388,13 +1435,15 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
* @description
* Creates a new request expectation for POST requests. For more info see `expect()`.
*
- * @param {string|RegExp} url HTTP url.
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
+ * and returns true if the url matches the current definition.
* @param {(string|RegExp|function(string)|Object)=} data HTTP request body or function that
* receives data string and returns true if the data is as expected, or Object if request body
* is in JSON format.
* @param {Object=} headers HTTP headers.
- * @returns {requestHandler} Returns an object with a `respond` method that controls how a matched
- * request is handled.
+ * @returns {requestHandler} Returns an object with `respond` method that controls how a matched
+ * request is handled. You can save this object for later use and invoke `respond` again in
+ * order to change how a matched request is handled.
*/
/**
@@ -1403,13 +1452,15 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
* @description
* Creates a new request expectation for PUT requests. For more info see `expect()`.
*
- * @param {string|RegExp} url HTTP url.
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
+ * and returns true if the url matches the current definition.
* @param {(string|RegExp|function(string)|Object)=} data HTTP request body or function that
* receives data string and returns true if the data is as expected, or Object if request body
* is in JSON format.
* @param {Object=} headers HTTP headers.
- * @returns {requestHandler} Returns an object with a `respond` method that controls how a matched
- * request is handled.
+ * @returns {requestHandler} Returns an object with `respond` method that controls how a matched
+ * request is handled. You can save this object for later use and invoke `respond` again in
+ * order to change how a matched request is handled.
*/
/**
@@ -1418,13 +1469,15 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
* @description
* Creates a new request expectation for PATCH requests. For more info see `expect()`.
*
- * @param {string|RegExp} url HTTP url.
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
+ * and returns true if the url matches the current definition.
* @param {(string|RegExp|function(string)|Object)=} data HTTP request body or function that
* receives data string and returns true if the data is as expected, or Object if request body
* is in JSON format.
* @param {Object=} headers HTTP headers.
- * @returns {requestHandler} Returns an object with a `respond` method that controls how a matched
- * request is handled.
+ * @returns {requestHandler} Returns an object with `respond` method that controls how a matched
+ * request is handled. You can save this object for later use and invoke `respond` again in
+ * order to change how a matched request is handled.
*/
/**
@@ -1433,9 +1486,11 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
* @description
* Creates a new request expectation for JSONP requests. For more info see `expect()`.
*
- * @param {string|RegExp} url HTTP url.
- * @returns {requestHandler} Returns an object with a `respond` method that controls how a matched
- * request is handled.
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives an url
+ * and returns true if the url matches the current definition.
+ * @returns {requestHandler} Returns an object with `respond` method that controls how a matched
+ * request is handled. You can save this object for later use and invoke `respond` again in
+ * order to change how a matched request is handled.
*/
createShortMethods('expect');
@@ -1450,11 +1505,11 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
* all pending requests will be flushed. If there are no pending requests when the flush method
* is called an exception is thrown (as this typically a sign of programming error).
*/
- $httpBackend.flush = function(count) {
- $rootScope.$digest();
+ $httpBackend.flush = function(count, digest) {
+ if (digest !== false) $rootScope.$digest();
if (!responses.length) throw new Error('No pending request to flush !');
- if (angular.isDefined(count)) {
+ if (angular.isDefined(count) && count !== null) {
while (count--) {
if (!responses.length) throw new Error('No more pending request to flush !');
responses.shift()();
@@ -1464,7 +1519,7 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
responses.shift()();
}
}
- $httpBackend.verifyNoOutstandingExpectation();
+ $httpBackend.verifyNoOutstandingExpectation(digest);
};
@@ -1482,8 +1537,8 @@ function createHttpBackendMock($rootScope, $delegate, $browser) {
* afterEach($httpBackend.verifyNoOutstandingExpectation);
* ```
*/
- $httpBackend.verifyNoOutstandingExpectation = function() {
- $rootScope.$digest();
+ $httpBackend.verifyNoOutstandingExpectation = function(digest) {
+ if (digest !== false) $rootScope.$digest();
if (expectations.length) {
throw new Error('Unsatisfied requests: ' + expectations.join(', '));
}
@@ -1557,6 +1612,7 @@ function MockHttpExpectation(method, url, data, headers) {
this.matchUrl = function(u) {
if (!url) return true;
if (angular.isFunction(url.test)) return url.test(u);
+ if (angular.isFunction(url)) return url(u);
return url == u;
};
@@ -1645,7 +1701,7 @@ function MockXhr() {
* that adds a "flush" and "verifyNoPendingTasks" methods.
*/
-angular.mock.$TimeoutDecorator = function($delegate, $browser) {
+angular.mock.$TimeoutDecorator = ['$delegate', '$browser', function($delegate, $browser) {
/**
* @ngdoc method
@@ -1684,9 +1740,9 @@ angular.mock.$TimeoutDecorator = function($delegate, $browser) {
}
return $delegate;
-};
+}];
-angular.mock.$RAFDecorator = function($delegate) {
+angular.mock.$RAFDecorator = ['$delegate', function($delegate) {
var queue = [];
var rafFn = function(fn) {
var index = queue.length;
@@ -1699,34 +1755,20 @@ angular.mock.$RAFDecorator = function($delegate) {
rafFn.supported = $delegate.supported;
rafFn.flush = function() {
- if(queue.length === 0) {
+ if (queue.length === 0) {
throw new Error('No rAF callbacks present');
}
var length = queue.length;
- for(var i=0;i<length;i++) {
+ for (var i = 0; i < length; i++) {
queue[i]();
}
- queue = [];
+ queue = queue.slice(i);
};
return rafFn;
-};
-
-angular.mock.$AsyncCallbackDecorator = function($delegate) {
- var callbacks = [];
- var addFn = function(fn) {
- callbacks.push(fn);
- };
- addFn.flush = function() {
- angular.forEach(callbacks, function(fn) {
- fn();
- });
- callbacks = [];
- };
- return addFn;
-};
+}];
/**
*
@@ -1738,6 +1780,77 @@ angular.mock.$RootElementProvider = function() {
};
/**
+ * @ngdoc service
+ * @name $controller
+ * @description
+ * A decorator for {@link ng.$controller} with additional `bindings` parameter, useful when testing
+ * controllers of directives that use {@link $compile#-bindtocontroller- `bindToController`}.
+ *
+ *
+ * ## Example
+ *
+ * ```js
+ *
+ * // Directive definition ...
+ *
+ * myMod.directive('myDirective', {
+ * controller: 'MyDirectiveController',
+ * bindToController: {
+ * name: '@'
+ * }
+ * });
+ *
+ *
+ * // Controller definition ...
+ *
+ * myMod.controller('MyDirectiveController', ['log', function($log) {
+ * $log.info(this.name);
+ * })];
+ *
+ *
+ * // In a test ...
+ *
+ * describe('myDirectiveController', function() {
+ * it('should write the bound name to the log', inject(function($controller, $log) {
+ * var ctrl = $controller('MyDirective', { /* no locals &#42;/ }, { name: 'Clark Kent' });
+ * expect(ctrl.name).toEqual('Clark Kent');
+ * expect($log.info.logs).toEqual(['Clark Kent']);
+ * });
+ * });
+ *
+ * ```
+ *
+ * @param {Function|string} constructor If called with a function then it's considered to be the
+ * controller constructor function. Otherwise it's considered to be a string which is used
+ * to retrieve the controller constructor using the following steps:
+ *
+ * * check if a controller with given name is registered via `$controllerProvider`
+ * * check if evaluating the string on the current scope returns a constructor
+ * * if $controllerProvider#allowGlobals, check `window[constructor]` on the global
+ * `window` object (not recommended)
+ *
+ * The string can use the `controller as property` syntax, where the controller instance is published
+ * as the specified property on the `scope`; the `scope` must be injected into `locals` param for this
+ * to work correctly.
+ *
+ * @param {Object} locals Injection locals for Controller.
+ * @param {Object=} bindings Properties to add to the controller before invoking the constructor. This is used
+ * to simulate the `bindToController` feature and simplify certain kinds of tests.
+ * @return {Object} Instance of given controller.
+ */
+angular.mock.$ControllerDecorator = ['$delegate', function($delegate) {
+ return function(expression, locals, later, ident) {
+ if (later && typeof later === 'object') {
+ var create = $delegate(expression, locals, true, ident);
+ angular.extend(create.instance, later);
+ return create();
+ }
+ return $delegate(expression, locals, later, ident);
+ };
+}];
+
+
+/**
* @ngdoc module
* @name ngMock
* @packageName angular-mocks
@@ -1763,7 +1876,8 @@ angular.module('ngMock', ['ng']).provider({
}).config(['$provide', function($provide) {
$provide.decorator('$timeout', angular.mock.$TimeoutDecorator);
$provide.decorator('$$rAF', angular.mock.$RAFDecorator);
- $provide.decorator('$$asyncCallback', angular.mock.$AsyncCallbackDecorator);
+ $provide.decorator('$rootScope', angular.mock.$RootScopeDecorator);
+ $provide.decorator('$controller', angular.mock.$ControllerDecorator);
}]);
/**
@@ -1840,12 +1954,14 @@ angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) {
* Creates a new backend definition.
*
* @param {string} method HTTP method.
- * @param {string|RegExp} url HTTP url.
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
+ * and returns true if the url matches the current definition.
* @param {(string|RegExp)=} data HTTP request body.
* @param {(Object|function(Object))=} headers HTTP headers or function that receives http header
* object and returns true if the headers match the current definition.
* @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
- * control how a matched request is handled.
+ * control how a matched request is handled. You can save this object for later use and invoke
+ * `respond` or `passThrough` again in order to change how a matched request is handled.
*
* - respond –
* `{function([status,] data[, headers, statusText])
@@ -1856,6 +1972,7 @@ angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) {
* - passThrough – `{function()}` – Any request matching a backend definition with
* `passThrough` handler will be passed through to the real backend (an XHR request will be made
* to the server.)
+ * - Both methods return the `requestHandler` object for possible overrides.
*/
/**
@@ -1865,10 +1982,12 @@ angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) {
* @description
* Creates a new backend definition for GET requests. For more info see `when()`.
*
- * @param {string|RegExp} url HTTP url.
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
+ * and returns true if the url matches the current definition.
* @param {(Object|function(Object))=} headers HTTP headers.
* @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
- * control how a matched request is handled.
+ * control how a matched request is handled. You can save this object for later use and invoke
+ * `respond` or `passThrough` again in order to change how a matched request is handled.
*/
/**
@@ -1878,10 +1997,12 @@ angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) {
* @description
* Creates a new backend definition for HEAD requests. For more info see `when()`.
*
- * @param {string|RegExp} url HTTP url.
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
+ * and returns true if the url matches the current definition.
* @param {(Object|function(Object))=} headers HTTP headers.
* @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
- * control how a matched request is handled.
+ * control how a matched request is handled. You can save this object for later use and invoke
+ * `respond` or `passThrough` again in order to change how a matched request is handled.
*/
/**
@@ -1891,10 +2012,12 @@ angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) {
* @description
* Creates a new backend definition for DELETE requests. For more info see `when()`.
*
- * @param {string|RegExp} url HTTP url.
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
+ * and returns true if the url matches the current definition.
* @param {(Object|function(Object))=} headers HTTP headers.
* @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
- * control how a matched request is handled.
+ * control how a matched request is handled. You can save this object for later use and invoke
+ * `respond` or `passThrough` again in order to change how a matched request is handled.
*/
/**
@@ -1904,11 +2027,13 @@ angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) {
* @description
* Creates a new backend definition for POST requests. For more info see `when()`.
*
- * @param {string|RegExp} url HTTP url.
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
+ * and returns true if the url matches the current definition.
* @param {(string|RegExp)=} data HTTP request body.
* @param {(Object|function(Object))=} headers HTTP headers.
* @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
- * control how a matched request is handled.
+ * control how a matched request is handled. You can save this object for later use and invoke
+ * `respond` or `passThrough` again in order to change how a matched request is handled.
*/
/**
@@ -1918,11 +2043,13 @@ angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) {
* @description
* Creates a new backend definition for PUT requests. For more info see `when()`.
*
- * @param {string|RegExp} url HTTP url.
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
+ * and returns true if the url matches the current definition.
* @param {(string|RegExp)=} data HTTP request body.
* @param {(Object|function(Object))=} headers HTTP headers.
* @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
- * control how a matched request is handled.
+ * control how a matched request is handled. You can save this object for later use and invoke
+ * `respond` or `passThrough` again in order to change how a matched request is handled.
*/
/**
@@ -1932,11 +2059,13 @@ angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) {
* @description
* Creates a new backend definition for PATCH requests. For more info see `when()`.
*
- * @param {string|RegExp} url HTTP url.
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
+ * and returns true if the url matches the current definition.
* @param {(string|RegExp)=} data HTTP request body.
* @param {(Object|function(Object))=} headers HTTP headers.
* @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
- * control how a matched request is handled.
+ * control how a matched request is handled. You can save this object for later use and invoke
+ * `respond` or `passThrough` again in order to change how a matched request is handled.
*/
/**
@@ -1946,45 +2075,132 @@ angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) {
* @description
* Creates a new backend definition for JSONP requests. For more info see `when()`.
*
- * @param {string|RegExp} url HTTP url.
+ * @param {string|RegExp|function(string)} url HTTP url or function that receives a url
+ * and returns true if the url matches the current definition.
* @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
- * control how a matched request is handled.
+ * control how a matched request is handled. You can save this object for later use and invoke
+ * `respond` or `passThrough` again in order to change how a matched request is handled.
*/
angular.mock.e2e = {};
angular.mock.e2e.$httpBackendDecorator =
- ['$rootScope', '$delegate', '$browser', createHttpBackendMock];
+ ['$rootScope', '$timeout', '$delegate', '$browser', createHttpBackendMock];
-angular.mock.clearDataCache = function() {
- var key,
- cache = angular.element.cache;
+/**
+ * @ngdoc type
+ * @name $rootScope.Scope
+ * @module ngMock
+ * @description
+ * {@link ng.$rootScope.Scope Scope} type decorated with helper methods useful for testing. These
+ * methods are automatically available on any {@link ng.$rootScope.Scope Scope} instance when
+ * `ngMock` module is loaded.
+ *
+ * In addition to all the regular `Scope` methods, the following helper methods are available:
+ */
+angular.mock.$RootScopeDecorator = ['$delegate', function($delegate) {
+
+ var $rootScopePrototype = Object.getPrototypeOf($delegate);
+
+ $rootScopePrototype.$countChildScopes = countChildScopes;
+ $rootScopePrototype.$countWatchers = countWatchers;
+
+ return $delegate;
+
+ // ------------------------------------------------------------------------------------------ //
+
+ /**
+ * @ngdoc method
+ * @name $rootScope.Scope#$countChildScopes
+ * @module ngMock
+ * @description
+ * Counts all the direct and indirect child scopes of the current scope.
+ *
+ * The current scope is excluded from the count. The count includes all isolate child scopes.
+ *
+ * @returns {number} Total number of child scopes.
+ */
+ function countChildScopes() {
+ // jshint validthis: true
+ var count = 0; // exclude the current scope
+ var pendingChildHeads = [this.$$childHead];
+ var currentScope;
+
+ while (pendingChildHeads.length) {
+ currentScope = pendingChildHeads.shift();
+
+ while (currentScope) {
+ count += 1;
+ pendingChildHeads.push(currentScope.$$childHead);
+ currentScope = currentScope.$$nextSibling;
+ }
+ }
+
+ return count;
+ }
- for(key in cache) {
- if (Object.prototype.hasOwnProperty.call(cache,key)) {
- var handle = cache[key].handle;
- handle && angular.element(handle.elem).off();
- delete cache[key];
+ /**
+ * @ngdoc method
+ * @name $rootScope.Scope#$countWatchers
+ * @module ngMock
+ * @description
+ * Counts all the watchers of direct and indirect child scopes of the current scope.
+ *
+ * The watchers of the current scope are included in the count and so are all the watchers of
+ * isolate child scopes.
+ *
+ * @returns {number} Total number of watchers.
+ */
+ function countWatchers() {
+ // jshint validthis: true
+ var count = this.$$watchers ? this.$$watchers.length : 0; // include the current scope
+ var pendingChildHeads = [this.$$childHead];
+ var currentScope;
+
+ while (pendingChildHeads.length) {
+ currentScope = pendingChildHeads.shift();
+
+ while (currentScope) {
+ count += currentScope.$$watchers ? currentScope.$$watchers.length : 0;
+ pendingChildHeads.push(currentScope.$$childHead);
+ currentScope = currentScope.$$nextSibling;
+ }
}
+
+ return count;
}
-};
+}];
-if(window.jasmine || window.mocha) {
+if (window.jasmine || window.mocha) {
var currentSpec = null,
+ annotatedFunctions = [],
isSpecRunning = function() {
return !!currentSpec;
};
+ angular.mock.$$annotate = angular.injector.$$annotate;
+ angular.injector.$$annotate = function(fn) {
+ if (typeof fn === 'function' && !fn.$inject) {
+ annotatedFunctions.push(fn);
+ }
+ return angular.mock.$$annotate.apply(this, arguments);
+ };
+
(window.beforeEach || window.setup)(function() {
+ annotatedFunctions = [];
currentSpec = this;
});
(window.afterEach || window.teardown)(function() {
var injector = currentSpec.$injector;
+ annotatedFunctions.forEach(function(fn) {
+ delete fn.$inject;
+ });
+
angular.forEach(currentSpec.$modules, function(module) {
if (module && module.$$hashKey) {
module.$$hashKey = undefined;
@@ -1997,11 +2213,8 @@ if(window.jasmine || window.mocha) {
if (injector) {
injector.get('$rootElement').off();
- injector.get('$browser').pollFns.length = 0;
}
- angular.mock.clearDataCache();
-
// clean up jquery's fragment cache
angular.forEach(angular.element.fragments, function(val, key) {
delete angular.element.fragments[key];
@@ -2164,14 +2377,28 @@ if(window.jasmine || window.mocha) {
/////////////////////
function workFn() {
var modules = currentSpec.$modules || [];
-
+ var strictDi = !!currentSpec.$injectorStrict;
modules.unshift('ngMock');
modules.unshift('ng');
var injector = currentSpec.$injector;
if (!injector) {
- injector = currentSpec.$injector = angular.injector(modules);
+ if (strictDi) {
+ // If strictDi is enabled, annotate the providerInjector blocks
+ angular.forEach(modules, function(moduleFn) {
+ if (typeof moduleFn === "function") {
+ angular.injector.$$annotate(moduleFn);
+ }
+ });
+ }
+ injector = currentSpec.$injector = angular.injector(modules, strictDi);
+ currentSpec.$injectorStrict = strictDi;
}
- for(var i = 0, ii = blockFns.length; i < ii; i++) {
+ for (var i = 0, ii = blockFns.length; i < ii; i++) {
+ if (currentSpec.$injectorStrict) {
+ // If the injector is strict / strictDi, and the spec wants to inject using automatic
+ // annotation, then annotate the function here.
+ injector.annotate(blockFns[i]);
+ }
try {
/* jshint -W040 *//* Jasmine explicitly provides a `this` object when calling functions */
injector.invoke(blockFns[i] || angular.noop, this);
@@ -2187,6 +2414,22 @@ if(window.jasmine || window.mocha) {
}
}
};
+
+
+ angular.mock.inject.strictDi = function(value) {
+ value = arguments.length ? !!value : true;
+ return isSpecRunning() ? workFn() : workFn;
+
+ function workFn() {
+ if (value !== currentSpec.$injectorStrict) {
+ if (currentSpec.$injector) {
+ throw new Error('Injector already created, can not modify strict annotations');
+ } else {
+ currentSpec.$injectorStrict = value;
+ }
+ }
+ }
+ };
}
diff --git a/libs/bower_components/angular-mocks/bower.json b/libs/bower_components/angular-mocks/bower.json
index 3ff4edcab1..43a3eed447 100644
--- a/libs/bower_components/angular-mocks/bower.json
+++ b/libs/bower_components/angular-mocks/bower.json
@@ -1,9 +1,9 @@
{
"name": "angular-mocks",
- "version": "1.2.28",
+ "version": "1.4.3",
"main": "./angular-mocks.js",
"ignore": [],
"dependencies": {
- "angular": "1.2.28"
+ "angular": "1.4.3"
}
}
diff --git a/libs/bower_components/angular-mocks/ngAnimateMock.js b/libs/bower_components/angular-mocks/ngAnimateMock.js
new file mode 100644
index 0000000000..6f99e62ef6
--- /dev/null
+++ b/libs/bower_components/angular-mocks/ngAnimateMock.js
@@ -0,0 +1,2 @@
+require('./angular-mocks');
+module.exports = 'ngAnimateMock';
diff --git a/libs/bower_components/angular-mocks/ngMock.js b/libs/bower_components/angular-mocks/ngMock.js
new file mode 100644
index 0000000000..7944de7d5b
--- /dev/null
+++ b/libs/bower_components/angular-mocks/ngMock.js
@@ -0,0 +1,2 @@
+require('./angular-mocks');
+module.exports = 'ngMock';
diff --git a/libs/bower_components/angular-mocks/ngMockE2E.js b/libs/bower_components/angular-mocks/ngMockE2E.js
new file mode 100644
index 0000000000..fc2e539dbd
--- /dev/null
+++ b/libs/bower_components/angular-mocks/ngMockE2E.js
@@ -0,0 +1,2 @@
+require('./angular-mocks');
+module.exports = 'ngMockE2E';
diff --git a/libs/bower_components/angular-mocks/package.json b/libs/bower_components/angular-mocks/package.json
index 06fe12f6d5..f1c285856d 100644
--- a/libs/bower_components/angular-mocks/package.json
+++ b/libs/bower_components/angular-mocks/package.json
@@ -1,6 +1,6 @@
{
"name": "angular-mocks",
- "version": "1.2.28",
+ "version": "1.4.3",
"description": "AngularJS mocks for testing",
"main": "angular-mocks.js",
"scripts": {
diff --git a/libs/bower_components/angular-sanitize/.bower.json b/libs/bower_components/angular-sanitize/.bower.json
index a594b10295..75ff26dc6a 100644
--- a/libs/bower_components/angular-sanitize/.bower.json
+++ b/libs/bower_components/angular-sanitize/.bower.json
@@ -1,19 +1,19 @@
{
"name": "angular-sanitize",
- "version": "1.2.28",
+ "version": "1.4.3",
"main": "./angular-sanitize.js",
"ignore": [],
"dependencies": {
- "angular": "1.2.28"
+ "angular": "1.4.3"
},
"homepage": "https://github.com/angular/bower-angular-sanitize",
- "_release": "1.2.28",
+ "_release": "1.4.3",
"_resolution": {
"type": "version",
- "tag": "v1.2.28",
- "commit": "d2f6ee551c1df7e412042d847302b37a058b82e2"
+ "tag": "v1.4.3",
+ "commit": "0367ee4c3f9cb8af5d1da9ec35b71a8b523d9fc0"
},
"_source": "git://github.com/angular/bower-angular-sanitize.git",
- "_target": "~1.2.0",
+ "_target": "~1.4.0",
"_originalSource": "angular-sanitize"
} \ No newline at end of file
diff --git a/libs/bower_components/angular-sanitize/README.md b/libs/bower_components/angular-sanitize/README.md
index 6bc0a3013b..b84aaf6dbf 100644
--- a/libs/bower_components/angular-sanitize/README.md
+++ b/libs/bower_components/angular-sanitize/README.md
@@ -14,21 +14,12 @@ You can install this package either with `npm` or with `bower`.
npm install angular-sanitize
```
-Add a `<script>` to your `index.html`:
-
-```html
-<script src="/node_modules/angular-sanitize/angular-sanitize.js"></script>
-```
-
Then add `ngSanitize` as a dependency for your app:
```javascript
-angular.module('myApp', ['ngSanitize']);
+angular.module('myApp', [require('angular-sanitize')]);
```
-Note that this package is not in CommonJS format, so doing `require('angular-sanitize')` will
-return `undefined`.
-
### bower
```shell
@@ -56,7 +47,7 @@ Documentation is available on the
The MIT License
-Copyright (c) 2010-2012 Google, Inc. http://angularjs.org
+Copyright (c) 2010-2015 Google, Inc. http://angularjs.org
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/libs/bower_components/angular-sanitize/angular-sanitize.js b/libs/bower_components/angular-sanitize/angular-sanitize.js
index 831e5f2a30..bebe1a72ab 100644
--- a/libs/bower_components/angular-sanitize/angular-sanitize.js
+++ b/libs/bower_components/angular-sanitize/angular-sanitize.js
@@ -1,10 +1,21 @@
/**
- * @license AngularJS v1.2.28
- * (c) 2010-2014 Google, Inc. http://angularjs.org
+ * @license AngularJS v1.4.3
+ * (c) 2010-2015 Google, Inc. http://angularjs.org
* License: MIT
*/
(function(window, angular, undefined) {'use strict';
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Any commits to this file should be reviewed with security in mind. *
+ * Changes to this file can potentially create security vulnerabilities. *
+ * An approval from 2 Core members with history of modifying *
+ * this file is required. *
+ * *
+ * Does the change somehow allow for arbitrary javascript to be executed? *
+ * Or allows for someone to change the prototype of built-in objects? *
+ * Or gives undesired access to variables likes document or window? *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
var $sanitizeMinErr = angular.$$minErr('$sanitize');
/**
@@ -45,16 +56,16 @@ var $sanitizeMinErr = angular.$$minErr('$sanitize');
* @kind function
*
* @description
- * The input is sanitized by parsing the html into tokens. All safe tokens (from a whitelist) are
+ * The input is sanitized by parsing the HTML into tokens. All safe tokens (from a whitelist) are
* then serialized back to properly escaped html string. This means that no unsafe input can make
* it into the returned string, however, since our parser is more strict than a typical browser
* parser, it's possible that some obscure input, which would be recognized as valid HTML by a
- * browser, won't make it through the sanitizer.
+ * browser, won't make it through the sanitizer. The input may also contain SVG markup.
* The whitelist is configured using the functions `aHrefSanitizationWhitelist` and
* `imgSrcSanitizationWhitelist` of {@link ng.$compileProvider `$compileProvider`}.
*
- * @param {string} html Html input.
- * @returns {string} Sanitized html.
+ * @param {string} html HTML input.
+ * @returns {string} Sanitized HTML.
*
* @example
<example module="sanitizeExample" deps="angular-sanitize.js">
@@ -198,6 +209,13 @@ var inlineElements = angular.extend({}, optionalEndTagInlineElements, makeMap("a
"bdi,bdo,big,br,cite,code,del,dfn,em,font,i,img,ins,kbd,label,map,mark,q,ruby,rp,rt,s," +
"samp,small,span,strike,strong,sub,sup,time,tt,u,var"));
+// SVG Elements
+// https://wiki.whatwg.org/wiki/Sanitization_rules#svg_Elements
+// Note: the elements animate,animateColor,animateMotion,animateTransform,set are intentionally omitted.
+// They can potentially allow for arbitrary javascript to be executed. See #11290
+var svgElements = makeMap("circle,defs,desc,ellipse,font-face,font-face-name,font-face-src,g,glyph," +
+ "hkern,image,linearGradient,line,marker,metadata,missing-glyph,mpath,path,polygon,polyline," +
+ "radialGradient,rect,stop,svg,switch,text,title,tspan,use");
// Special Elements (can contain anything)
var specialElements = makeMap("script,style");
@@ -206,20 +224,46 @@ var validElements = angular.extend({},
voidElements,
blockElements,
inlineElements,
- optionalEndTagElements);
+ optionalEndTagElements,
+ svgElements);
//Attributes that have href and hence need to be sanitized
-var uriAttrs = makeMap("background,cite,href,longdesc,src,usemap");
-var validAttrs = angular.extend({}, uriAttrs, makeMap(
- 'abbr,align,alt,axis,bgcolor,border,cellpadding,cellspacing,class,clear,'+
- 'color,cols,colspan,compact,coords,dir,face,headers,height,hreflang,hspace,'+
- 'ismap,lang,language,nohref,nowrap,rel,rev,rows,rowspan,rules,'+
- 'scope,scrolling,shape,size,span,start,summary,target,title,type,'+
- 'valign,value,vspace,width'));
-
-function makeMap(str) {
+var uriAttrs = makeMap("background,cite,href,longdesc,src,usemap,xlink:href");
+
+var htmlAttrs = makeMap('abbr,align,alt,axis,bgcolor,border,cellpadding,cellspacing,class,clear,' +
+ 'color,cols,colspan,compact,coords,dir,face,headers,height,hreflang,hspace,' +
+ 'ismap,lang,language,nohref,nowrap,rel,rev,rows,rowspan,rules,' +
+ 'scope,scrolling,shape,size,span,start,summary,tabindex,target,title,type,' +
+ 'valign,value,vspace,width');
+
+// SVG attributes (without "id" and "name" attributes)
+// https://wiki.whatwg.org/wiki/Sanitization_rules#svg_Attributes
+var svgAttrs = makeMap('accent-height,accumulate,additive,alphabetic,arabic-form,ascent,' +
+ 'baseProfile,bbox,begin,by,calcMode,cap-height,class,color,color-rendering,content,' +
+ 'cx,cy,d,dx,dy,descent,display,dur,end,fill,fill-rule,font-family,font-size,font-stretch,' +
+ 'font-style,font-variant,font-weight,from,fx,fy,g1,g2,glyph-name,gradientUnits,hanging,' +
+ 'height,horiz-adv-x,horiz-origin-x,ideographic,k,keyPoints,keySplines,keyTimes,lang,' +
+ 'marker-end,marker-mid,marker-start,markerHeight,markerUnits,markerWidth,mathematical,' +
+ 'max,min,offset,opacity,orient,origin,overline-position,overline-thickness,panose-1,' +
+ 'path,pathLength,points,preserveAspectRatio,r,refX,refY,repeatCount,repeatDur,' +
+ 'requiredExtensions,requiredFeatures,restart,rotate,rx,ry,slope,stemh,stemv,stop-color,' +
+ 'stop-opacity,strikethrough-position,strikethrough-thickness,stroke,stroke-dasharray,' +
+ 'stroke-dashoffset,stroke-linecap,stroke-linejoin,stroke-miterlimit,stroke-opacity,' +
+ 'stroke-width,systemLanguage,target,text-anchor,to,transform,type,u1,u2,underline-position,' +
+ 'underline-thickness,unicode,unicode-range,units-per-em,values,version,viewBox,visibility,' +
+ 'width,widths,x,x-height,x1,x2,xlink:actuate,xlink:arcrole,xlink:role,xlink:show,xlink:title,' +
+ 'xlink:type,xml:base,xml:lang,xml:space,xmlns,xmlns:xlink,y,y1,y2,zoomAndPan', true);
+
+var validAttrs = angular.extend({},
+ uriAttrs,
+ svgAttrs,
+ htmlAttrs);
+
+function makeMap(str, lowercaseKeys) {
var obj = {}, items = str.split(','), i;
- for (i = 0; i < items.length; i++) obj[items[i]] = true;
+ for (i = 0; i < items.length; i++) {
+ obj[lowercaseKeys ? angular.lowercase(items[i]) : items[i]] = true;
+ }
return obj;
}
@@ -236,7 +280,7 @@ function makeMap(str) {
* @param {string} html string
* @param {object} handler
*/
-function htmlParser( html, handler ) {
+function htmlParser(html, handler) {
if (typeof html !== 'string') {
if (html === null || typeof html === 'undefined') {
html = '';
@@ -245,52 +289,52 @@ function htmlParser( html, handler ) {
}
}
var index, chars, match, stack = [], last = html, text;
- stack.last = function() { return stack[ stack.length - 1 ]; };
+ stack.last = function() { return stack[stack.length - 1]; };
- while ( html ) {
+ while (html) {
text = '';
chars = true;
// Make sure we're not in a script or style element
- if ( !stack.last() || !specialElements[ stack.last() ] ) {
+ if (!stack.last() || !specialElements[stack.last()]) {
// Comment
- if ( html.indexOf("<!--") === 0 ) {
+ if (html.indexOf("<!--") === 0) {
// comments containing -- are not allowed unless they terminate the comment
index = html.indexOf("--", 4);
- if ( index >= 0 && html.lastIndexOf("-->", index) === index) {
- if (handler.comment) handler.comment( html.substring( 4, index ) );
- html = html.substring( index + 3 );
+ if (index >= 0 && html.lastIndexOf("-->", index) === index) {
+ if (handler.comment) handler.comment(html.substring(4, index));
+ html = html.substring(index + 3);
chars = false;
}
// DOCTYPE
- } else if ( DOCTYPE_REGEXP.test(html) ) {
- match = html.match( DOCTYPE_REGEXP );
+ } else if (DOCTYPE_REGEXP.test(html)) {
+ match = html.match(DOCTYPE_REGEXP);
- if ( match ) {
- html = html.replace( match[0], '');
+ if (match) {
+ html = html.replace(match[0], '');
chars = false;
}
// end tag
- } else if ( BEGING_END_TAGE_REGEXP.test(html) ) {
- match = html.match( END_TAG_REGEXP );
+ } else if (BEGING_END_TAGE_REGEXP.test(html)) {
+ match = html.match(END_TAG_REGEXP);
- if ( match ) {
- html = html.substring( match[0].length );
- match[0].replace( END_TAG_REGEXP, parseEndTag );
+ if (match) {
+ html = html.substring(match[0].length);
+ match[0].replace(END_TAG_REGEXP, parseEndTag);
chars = false;
}
// start tag
- } else if ( BEGIN_TAG_REGEXP.test(html) ) {
- match = html.match( START_TAG_REGEXP );
+ } else if (BEGIN_TAG_REGEXP.test(html)) {
+ match = html.match(START_TAG_REGEXP);
- if ( match ) {
+ if (match) {
// We only have a valid start-tag if there is a '>'.
- if ( match[4] ) {
- html = html.substring( match[0].length );
- match[0].replace( START_TAG_REGEXP, parseStartTag );
+ if (match[4]) {
+ html = html.substring(match[0].length);
+ match[0].replace(START_TAG_REGEXP, parseStartTag);
}
chars = false;
} else {
@@ -300,29 +344,30 @@ function htmlParser( html, handler ) {
}
}
- if ( chars ) {
+ if (chars) {
index = html.indexOf("<");
- text += index < 0 ? html : html.substring( 0, index );
- html = index < 0 ? "" : html.substring( index );
+ text += index < 0 ? html : html.substring(0, index);
+ html = index < 0 ? "" : html.substring(index);
- if (handler.chars) handler.chars( decodeEntities(text) );
+ if (handler.chars) handler.chars(decodeEntities(text));
}
} else {
- html = html.replace(new RegExp("(.*)<\\s*\\/\\s*" + stack.last() + "[^>]*>", 'i'),
- function(all, text){
+ // IE versions 9 and 10 do not understand the regex '[^]', so using a workaround with [\W\w].
+ html = html.replace(new RegExp("([\\W\\w]*)<\\s*\\/\\s*" + stack.last() + "[^>]*>", 'i'),
+ function(all, text) {
text = text.replace(COMMENT_REGEXP, "$1").replace(CDATA_REGEXP, "$1");
- if (handler.chars) handler.chars( decodeEntities(text) );
+ if (handler.chars) handler.chars(decodeEntities(text));
return "";
});
- parseEndTag( "", stack.last() );
+ parseEndTag("", stack.last());
}
- if ( html == last ) {
+ if (html == last) {
throw $sanitizeMinErr('badparse', "The sanitizer was unable to parse the following block " +
"of html: {0}", html);
}
@@ -332,22 +377,23 @@ function htmlParser( html, handler ) {
// Clean up any remaining tags
parseEndTag();
- function parseStartTag( tag, tagName, rest, unary ) {
+ function parseStartTag(tag, tagName, rest, unary) {
tagName = angular.lowercase(tagName);
- if ( blockElements[ tagName ] ) {
- while ( stack.last() && inlineElements[ stack.last() ] ) {
- parseEndTag( "", stack.last() );
+ if (blockElements[tagName]) {
+ while (stack.last() && inlineElements[stack.last()]) {
+ parseEndTag("", stack.last());
}
}
- if ( optionalEndTagElements[ tagName ] && stack.last() == tagName ) {
- parseEndTag( "", tagName );
+ if (optionalEndTagElements[tagName] && stack.last() == tagName) {
+ parseEndTag("", tagName);
}
- unary = voidElements[ tagName ] || !!unary;
+ unary = voidElements[tagName] || !!unary;
- if ( !unary )
- stack.push( tagName );
+ if (!unary) {
+ stack.push(tagName);
+ }
var attrs = {};
@@ -360,22 +406,23 @@ function htmlParser( html, handler ) {
attrs[name] = decodeEntities(value);
});
- if (handler.start) handler.start( tagName, attrs, unary );
+ if (handler.start) handler.start(tagName, attrs, unary);
}
- function parseEndTag( tag, tagName ) {
+ function parseEndTag(tag, tagName) {
var pos = 0, i;
tagName = angular.lowercase(tagName);
- if ( tagName )
+ if (tagName) {
// Find the closest opened tag of the same type
- for ( pos = stack.length - 1; pos >= 0; pos-- )
- if ( stack[ pos ] == tagName )
- break;
+ for (pos = stack.length - 1; pos >= 0; pos--) {
+ if (stack[pos] == tagName) break;
+ }
+ }
- if ( pos >= 0 ) {
+ if (pos >= 0) {
// Close all the open elements, up the stack
- for ( i = stack.length - 1; i >= pos; i-- )
- if (handler.end) handler.end( stack[ i ] );
+ for (i = stack.length - 1; i >= pos; i--)
+ if (handler.end) handler.end(stack[i]);
// Remove the open elements from the stack
stack.length = pos;
@@ -384,7 +431,6 @@ function htmlParser( html, handler ) {
}
var hiddenPre=document.createElement("pre");
-var spaceRe = /^(\s*)([\s\S]*?)(\s*)$/;
/**
* decodes all entities into regular string
* @param value
@@ -393,22 +439,10 @@ var spaceRe = /^(\s*)([\s\S]*?)(\s*)$/;
function decodeEntities(value) {
if (!value) { return ''; }
- // Note: IE8 does not preserve spaces at the start/end of innerHTML
- // so we must capture them and reattach them afterward
- var parts = spaceRe.exec(value);
- var spaceBefore = parts[1];
- var spaceAfter = parts[3];
- var content = parts[2];
- if (content) {
- hiddenPre.innerHTML=content.replace(/</g,"&lt;");
- // innerText depends on styling as it doesn't display hidden elements.
- // Therefore, it's better to use textContent not to cause unnecessary
- // reflows. However, IE<9 don't support textContent so the innerText
- // fallback is necessary.
- content = 'textContent' in hiddenPre ?
- hiddenPre.textContent : hiddenPre.innerText;
- }
- return spaceBefore + content + spaceAfter;
+ hiddenPre.innerHTML = value.replace(/</g,"&lt;");
+ // innerText depends on styling as it doesn't display hidden elements.
+ // Therefore, it's better to use textContent not to cause unnecessary reflows.
+ return hiddenPre.textContent;
}
/**
@@ -421,12 +455,12 @@ function decodeEntities(value) {
function encodeEntities(value) {
return value.
replace(/&/g, '&amp;').
- replace(SURROGATE_PAIR_REGEXP, function (value) {
+ replace(SURROGATE_PAIR_REGEXP, function(value) {
var hi = value.charCodeAt(0);
var low = value.charCodeAt(1);
return '&#' + (((hi - 0xD800) * 0x400) + (low - 0xDC00) + 0x10000) + ';';
}).
- replace(NON_ALPHANUMERIC_REGEXP, function(value){
+ replace(NON_ALPHANUMERIC_REGEXP, function(value) {
return '&#' + value.charCodeAt(0) + ';';
}).
replace(/</g, '&lt;').
@@ -443,11 +477,11 @@ function encodeEntities(value) {
* comment: function(text) {}
* }
*/
-function htmlSanitizeWriter(buf, uriValidator){
+function htmlSanitizeWriter(buf, uriValidator) {
var ignore = false;
var out = angular.bind(buf, buf.push);
return {
- start: function(tag, attrs, unary){
+ start: function(tag, attrs, unary) {
tag = angular.lowercase(tag);
if (!ignore && specialElements[tag]) {
ignore = tag;
@@ -455,7 +489,7 @@ function htmlSanitizeWriter(buf, uriValidator){
if (!ignore && validElements[tag] === true) {
out('<');
out(tag);
- angular.forEach(attrs, function(value, key){
+ angular.forEach(attrs, function(value, key) {
var lkey=angular.lowercase(key);
var isImage = (tag === 'img' && lkey === 'src') || (lkey === 'background');
if (validAttrs[lkey] === true &&
@@ -470,7 +504,7 @@ function htmlSanitizeWriter(buf, uriValidator){
out(unary ? '/>' : '>');
}
},
- end: function(tag){
+ end: function(tag) {
tag = angular.lowercase(tag);
if (!ignore && validElements[tag] === true) {
out('</');
@@ -481,7 +515,7 @@ function htmlSanitizeWriter(buf, uriValidator){
ignore = false;
}
},
- chars: function(chars){
+ chars: function(chars) {
if (!ignore) {
out(encodeEntities(chars));
}
@@ -597,8 +631,8 @@ angular.module('ngSanitize', []).provider('$sanitize', $SanitizeProvider);
*/
angular.module('ngSanitize').filter('linky', ['$sanitize', function($sanitize) {
var LINKY_URL_REGEXP =
- /((ftp|https?):\/\/|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s.;,(){}<>"]/,
- MAILTO_REGEXP = /^mailto:/;
+ /((ftp|https?):\/\/|(www\.)|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s.;,(){}<>"”’]/i,
+ MAILTO_REGEXP = /^mailto:/i;
return function(text, target) {
if (!text) return text;
@@ -610,8 +644,10 @@ angular.module('ngSanitize').filter('linky', ['$sanitize', function($sanitize) {
while ((match = raw.match(LINKY_URL_REGEXP))) {
// We can not end in these as they are sometimes found at the end of the sentence
url = match[0];
- // if we did not match ftp/http/mailto then assume mailto
- if (match[2] == match[3]) url = 'mailto:' + url;
+ // if we did not match ftp/http/www/mailto then assume mailto
+ if (!match[2] && !match[4]) {
+ url = (match[3] ? 'http://' : 'mailto:') + url;
+ }
i = match.index;
addText(raw.substr(0, i));
addLink(url, match[0].replace(MAILTO_REGEXP, ''));
@@ -630,12 +666,12 @@ angular.module('ngSanitize').filter('linky', ['$sanitize', function($sanitize) {
function addLink(url, text) {
html.push('<a ');
if (angular.isDefined(target)) {
- html.push('target="');
- html.push(target);
- html.push('" ');
+ html.push('target="',
+ target,
+ '" ');
}
html.push('href="',
- url.replace('"', '&quot;'),
+ url.replace(/"/g, '&quot;'),
'">');
addText(text);
html.push('</a>');
diff --git a/libs/bower_components/angular-sanitize/angular-sanitize.min.js b/libs/bower_components/angular-sanitize/angular-sanitize.min.js
index 57eade6f9f..e8c4226487 100644
--- a/libs/bower_components/angular-sanitize/angular-sanitize.min.js
+++ b/libs/bower_components/angular-sanitize/angular-sanitize.min.js
@@ -1,15 +1,16 @@
/*
- AngularJS v1.2.28
- (c) 2010-2014 Google, Inc. http://angularjs.org
+ AngularJS v1.4.3
+ (c) 2010-2015 Google, Inc. http://angularjs.org
License: MIT
*/
-(function(q,g,r){'use strict';function F(a){var d=[];t(d,g.noop).chars(a);return d.join("")}function l(a){var d={};a=a.split(",");var c;for(c=0;c<a.length;c++)d[a[c]]=!0;return d}function G(a,d){function c(a,b,c,h){b=g.lowercase(b);if(u[b])for(;f.last()&&v[f.last()];)e("",f.last());w[b]&&f.last()==b&&e("",b);(h=x[b]||!!h)||f.push(b);var n={};c.replace(H,function(a,b,d,c,e){n[b]=s(d||c||e||"")});d.start&&d.start(b,n,h)}function e(a,b){var c=0,e;if(b=g.lowercase(b))for(c=f.length-1;0<=c&&f[c]!=b;c--);
-if(0<=c){for(e=f.length-1;e>=c;e--)d.end&&d.end(f[e]);f.length=c}}"string"!==typeof a&&(a=null===a||"undefined"===typeof a?"":""+a);var b,k,f=[],n=a,h;for(f.last=function(){return f[f.length-1]};a;){h="";k=!0;if(f.last()&&y[f.last()])a=a.replace(RegExp("(.*)<\\s*\\/\\s*"+f.last()+"[^>]*>","i"),function(a,b){b=b.replace(I,"$1").replace(J,"$1");d.chars&&d.chars(s(b));return""}),e("",f.last());else{if(0===a.indexOf("\x3c!--"))b=a.indexOf("--",4),0<=b&&a.lastIndexOf("--\x3e",b)===b&&(d.comment&&d.comment(a.substring(4,
-b)),a=a.substring(b+3),k=!1);else if(z.test(a)){if(b=a.match(z))a=a.replace(b[0],""),k=!1}else if(K.test(a)){if(b=a.match(A))a=a.substring(b[0].length),b[0].replace(A,e),k=!1}else L.test(a)&&((b=a.match(B))?(b[4]&&(a=a.substring(b[0].length),b[0].replace(B,c)),k=!1):(h+="<",a=a.substring(1)));k&&(b=a.indexOf("<"),h+=0>b?a:a.substring(0,b),a=0>b?"":a.substring(b),d.chars&&d.chars(s(h)))}if(a==n)throw M("badparse",a);n=a}e()}function s(a){if(!a)return"";var d=N.exec(a);a=d[1];var c=d[3];if(d=d[2])p.innerHTML=
-d.replace(/</g,"&lt;"),d="textContent"in p?p.textContent:p.innerText;return a+d+c}function C(a){return a.replace(/&/g,"&amp;").replace(O,function(a){var c=a.charCodeAt(0);a=a.charCodeAt(1);return"&#"+(1024*(c-55296)+(a-56320)+65536)+";"}).replace(P,function(a){return"&#"+a.charCodeAt(0)+";"}).replace(/</g,"&lt;").replace(/>/g,"&gt;")}function t(a,d){var c=!1,e=g.bind(a,a.push);return{start:function(a,k,f){a=g.lowercase(a);!c&&y[a]&&(c=a);c||!0!==D[a]||(e("<"),e(a),g.forEach(k,function(c,f){var m=
-g.lowercase(f),k="img"===a&&"src"===m||"background"===m;!0!==Q[m]||!0===E[m]&&!d(c,k)||(e(" "),e(f),e('="'),e(C(c)),e('"'))}),e(f?"/>":">"))},end:function(a){a=g.lowercase(a);c||!0!==D[a]||(e("</"),e(a),e(">"));a==c&&(c=!1)},chars:function(a){c||e(C(a))}}}var M=g.$$minErr("$sanitize"),B=/^<((?:[a-zA-Z])[\w:-]*)((?:\s+[\w:-]+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)\s*(>?)/,A=/^<\/\s*([\w:-]+)[^>]*>/,H=/([\w:-]+)(?:\s*=\s*(?:(?:"((?:[^"])*)")|(?:'((?:[^'])*)')|([^>\s]+)))?/g,L=/^</,
-K=/^<\//,I=/\x3c!--(.*?)--\x3e/g,z=/<!DOCTYPE([^>]*?)>/i,J=/<!\[CDATA\[(.*?)]]\x3e/g,O=/[\uD800-\uDBFF][\uDC00-\uDFFF]/g,P=/([^\#-~| |!])/g,x=l("area,br,col,hr,img,wbr");q=l("colgroup,dd,dt,li,p,tbody,td,tfoot,th,thead,tr");r=l("rp,rt");var w=g.extend({},r,q),u=g.extend({},q,l("address,article,aside,blockquote,caption,center,del,dir,div,dl,figure,figcaption,footer,h1,h2,h3,h4,h5,h6,header,hgroup,hr,ins,map,menu,nav,ol,pre,script,section,table,ul")),v=g.extend({},r,l("a,abbr,acronym,b,bdi,bdo,big,br,cite,code,del,dfn,em,font,i,img,ins,kbd,label,map,mark,q,ruby,rp,rt,s,samp,small,span,strike,strong,sub,sup,time,tt,u,var")),
-y=l("script,style"),D=g.extend({},x,u,v,w),E=l("background,cite,href,longdesc,src,usemap"),Q=g.extend({},E,l("abbr,align,alt,axis,bgcolor,border,cellpadding,cellspacing,class,clear,color,cols,colspan,compact,coords,dir,face,headers,height,hreflang,hspace,ismap,lang,language,nohref,nowrap,rel,rev,rows,rowspan,rules,scope,scrolling,shape,size,span,start,summary,target,title,type,valign,value,vspace,width")),p=document.createElement("pre"),N=/^(\s*)([\s\S]*?)(\s*)$/;g.module("ngSanitize",[]).provider("$sanitize",
-function(){this.$get=["$$sanitizeUri",function(a){return function(d){var c=[];G(d,t(c,function(c,b){return!/^unsafe/.test(a(c,b))}));return c.join("")}}]});g.module("ngSanitize").filter("linky",["$sanitize",function(a){var d=/((ftp|https?):\/\/|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s.;,(){}<>"]/,c=/^mailto:/;return function(e,b){function k(a){a&&m.push(F(a))}function f(a,c){m.push("<a ");g.isDefined(b)&&(m.push('target="'),m.push(b),m.push('" '));m.push('href="',a.replace('"',"&quot;"),'">');k(c);m.push("</a>")}
-if(!e)return e;for(var n,h=e,m=[],l,p;n=h.match(d);)l=n[0],n[2]==n[3]&&(l="mailto:"+l),p=n.index,k(h.substr(0,p)),f(l,n[0].replace(c,"")),h=h.substring(p+n[0].length);k(h);return a(m.join(""))}}])})(window,window.angular);
+(function(n,h,p){'use strict';function E(a){var f=[];r(f,h.noop).chars(a);return f.join("")}function g(a,f){var d={},c=a.split(","),b;for(b=0;b<c.length;b++)d[f?h.lowercase(c[b]):c[b]]=!0;return d}function F(a,f){function d(a,b,d,l){b=h.lowercase(b);if(s[b])for(;e.last()&&t[e.last()];)c("",e.last());u[b]&&e.last()==b&&c("",b);(l=v[b]||!!l)||e.push(b);var m={};d.replace(G,function(b,a,f,c,d){m[a]=q(f||c||d||"")});f.start&&f.start(b,m,l)}function c(b,a){var c=0,d;if(a=h.lowercase(a))for(c=e.length-
+1;0<=c&&e[c]!=a;c--);if(0<=c){for(d=e.length-1;d>=c;d--)f.end&&f.end(e[d]);e.length=c}}"string"!==typeof a&&(a=null===a||"undefined"===typeof a?"":""+a);var b,k,e=[],m=a,l;for(e.last=function(){return e[e.length-1]};a;){l="";k=!0;if(e.last()&&w[e.last()])a=a.replace(new RegExp("([\\W\\w]*)<\\s*\\/\\s*"+e.last()+"[^>]*>","i"),function(a,b){b=b.replace(H,"$1").replace(I,"$1");f.chars&&f.chars(q(b));return""}),c("",e.last());else{if(0===a.indexOf("\x3c!--"))b=a.indexOf("--",4),0<=b&&a.lastIndexOf("--\x3e",
+b)===b&&(f.comment&&f.comment(a.substring(4,b)),a=a.substring(b+3),k=!1);else if(x.test(a)){if(b=a.match(x))a=a.replace(b[0],""),k=!1}else if(J.test(a)){if(b=a.match(y))a=a.substring(b[0].length),b[0].replace(y,c),k=!1}else K.test(a)&&((b=a.match(z))?(b[4]&&(a=a.substring(b[0].length),b[0].replace(z,d)),k=!1):(l+="<",a=a.substring(1)));k&&(b=a.indexOf("<"),l+=0>b?a:a.substring(0,b),a=0>b?"":a.substring(b),f.chars&&f.chars(q(l)))}if(a==m)throw L("badparse",a);m=a}c()}function q(a){if(!a)return"";A.innerHTML=
+a.replace(/</g,"&lt;");return A.textContent}function B(a){return a.replace(/&/g,"&amp;").replace(M,function(a){var d=a.charCodeAt(0);a=a.charCodeAt(1);return"&#"+(1024*(d-55296)+(a-56320)+65536)+";"}).replace(N,function(a){return"&#"+a.charCodeAt(0)+";"}).replace(/</g,"&lt;").replace(/>/g,"&gt;")}function r(a,f){var d=!1,c=h.bind(a,a.push);return{start:function(a,k,e){a=h.lowercase(a);!d&&w[a]&&(d=a);d||!0!==C[a]||(c("<"),c(a),h.forEach(k,function(d,e){var k=h.lowercase(e),g="img"===a&&"src"===k||
+"background"===k;!0!==O[k]||!0===D[k]&&!f(d,g)||(c(" "),c(e),c('="'),c(B(d)),c('"'))}),c(e?"/>":">"))},end:function(a){a=h.lowercase(a);d||!0!==C[a]||(c("</"),c(a),c(">"));a==d&&(d=!1)},chars:function(a){d||c(B(a))}}}var L=h.$$minErr("$sanitize"),z=/^<((?:[a-zA-Z])[\w:-]*)((?:\s+[\w:-]+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)\s*(>?)/,y=/^<\/\s*([\w:-]+)[^>]*>/,G=/([\w:-]+)(?:\s*=\s*(?:(?:"((?:[^"])*)")|(?:'((?:[^'])*)')|([^>\s]+)))?/g,K=/^</,J=/^<\//,H=/\x3c!--(.*?)--\x3e/g,x=/<!DOCTYPE([^>]*?)>/i,
+I=/<!\[CDATA\[(.*?)]]\x3e/g,M=/[\uD800-\uDBFF][\uDC00-\uDFFF]/g,N=/([^\#-~| |!])/g,v=g("area,br,col,hr,img,wbr");n=g("colgroup,dd,dt,li,p,tbody,td,tfoot,th,thead,tr");p=g("rp,rt");var u=h.extend({},p,n),s=h.extend({},n,g("address,article,aside,blockquote,caption,center,del,dir,div,dl,figure,figcaption,footer,h1,h2,h3,h4,h5,h6,header,hgroup,hr,ins,map,menu,nav,ol,pre,script,section,table,ul")),t=h.extend({},p,g("a,abbr,acronym,b,bdi,bdo,big,br,cite,code,del,dfn,em,font,i,img,ins,kbd,label,map,mark,q,ruby,rp,rt,s,samp,small,span,strike,strong,sub,sup,time,tt,u,var"));
+n=g("circle,defs,desc,ellipse,font-face,font-face-name,font-face-src,g,glyph,hkern,image,linearGradient,line,marker,metadata,missing-glyph,mpath,path,polygon,polyline,radialGradient,rect,stop,svg,switch,text,title,tspan,use");var w=g("script,style"),C=h.extend({},v,s,t,u,n),D=g("background,cite,href,longdesc,src,usemap,xlink:href");n=g("abbr,align,alt,axis,bgcolor,border,cellpadding,cellspacing,class,clear,color,cols,colspan,compact,coords,dir,face,headers,height,hreflang,hspace,ismap,lang,language,nohref,nowrap,rel,rev,rows,rowspan,rules,scope,scrolling,shape,size,span,start,summary,tabindex,target,title,type,valign,value,vspace,width");
+p=g("accent-height,accumulate,additive,alphabetic,arabic-form,ascent,baseProfile,bbox,begin,by,calcMode,cap-height,class,color,color-rendering,content,cx,cy,d,dx,dy,descent,display,dur,end,fill,fill-rule,font-family,font-size,font-stretch,font-style,font-variant,font-weight,from,fx,fy,g1,g2,glyph-name,gradientUnits,hanging,height,horiz-adv-x,horiz-origin-x,ideographic,k,keyPoints,keySplines,keyTimes,lang,marker-end,marker-mid,marker-start,markerHeight,markerUnits,markerWidth,mathematical,max,min,offset,opacity,orient,origin,overline-position,overline-thickness,panose-1,path,pathLength,points,preserveAspectRatio,r,refX,refY,repeatCount,repeatDur,requiredExtensions,requiredFeatures,restart,rotate,rx,ry,slope,stemh,stemv,stop-color,stop-opacity,strikethrough-position,strikethrough-thickness,stroke,stroke-dasharray,stroke-dashoffset,stroke-linecap,stroke-linejoin,stroke-miterlimit,stroke-opacity,stroke-width,systemLanguage,target,text-anchor,to,transform,type,u1,u2,underline-position,underline-thickness,unicode,unicode-range,units-per-em,values,version,viewBox,visibility,width,widths,x,x-height,x1,x2,xlink:actuate,xlink:arcrole,xlink:role,xlink:show,xlink:title,xlink:type,xml:base,xml:lang,xml:space,xmlns,xmlns:xlink,y,y1,y2,zoomAndPan",
+!0);var O=h.extend({},D,p,n),A=document.createElement("pre");h.module("ngSanitize",[]).provider("$sanitize",function(){this.$get=["$$sanitizeUri",function(a){return function(f){var d=[];F(f,r(d,function(c,b){return!/^unsafe/.test(a(c,b))}));return d.join("")}}]});h.module("ngSanitize").filter("linky",["$sanitize",function(a){var f=/((ftp|https?):\/\/|(www\.)|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s.;,(){}<>"\u201d\u2019]/i,d=/^mailto:/i;return function(c,b){function k(a){a&&g.push(E(a))}function e(a,
+c){g.push("<a ");h.isDefined(b)&&g.push('target="',b,'" ');g.push('href="',a.replace(/"/g,"&quot;"),'">');k(c);g.push("</a>")}if(!c)return c;for(var m,l=c,g=[],n,p;m=l.match(f);)n=m[0],m[2]||m[4]||(n=(m[3]?"http://":"mailto:")+n),p=m.index,k(l.substr(0,p)),e(n,m[0].replace(d,"")),l=l.substring(p+m[0].length);k(l);return a(g.join(""))}}])})(window,window.angular);
//# sourceMappingURL=angular-sanitize.min.js.map
diff --git a/libs/bower_components/angular-sanitize/angular-sanitize.min.js.map b/libs/bower_components/angular-sanitize/angular-sanitize.min.js.map
index 5baa1dfbc1..2f360f4df7 100644
--- a/libs/bower_components/angular-sanitize/angular-sanitize.min.js.map
+++ b/libs/bower_components/angular-sanitize/angular-sanitize.min.js.map
@@ -1,8 +1,8 @@
{
"version":3,
"file":"angular-sanitize.min.js",
-"lineCount":14,
-"mappings":"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",
+"lineCount":15,
+"mappings":"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",
"sources":["angular-sanitize.js"],
-"names":["window","angular","undefined","sanitizeText","chars","buf","htmlSanitizeWriter","writer","noop","join","makeMap","str","obj","items","split","i","length","htmlParser","html","handler","parseStartTag","tag","tagName","rest","unary","lowercase","blockElements","stack","last","inlineElements","parseEndTag","optionalEndTagElements","voidElements","push","attrs","replace","ATTR_REGEXP","match","name","doubleQuotedValue","singleQuotedValue","unquotedValue","decodeEntities","start","pos","end","index","text","stack.last","specialElements","RegExp","all","COMMENT_REGEXP","CDATA_REGEXP","indexOf","lastIndexOf","comment","substring","DOCTYPE_REGEXP","test","BEGING_END_TAGE_REGEXP","END_TAG_REGEXP","BEGIN_TAG_REGEXP","START_TAG_REGEXP","$sanitizeMinErr","value","parts","spaceRe","exec","spaceBefore","spaceAfter","content","hiddenPre","innerHTML","textContent","innerText","encodeEntities","SURROGATE_PAIR_REGEXP","hi","charCodeAt","low","NON_ALPHANUMERIC_REGEXP","uriValidator","ignore","out","bind","validElements","forEach","key","lkey","isImage","validAttrs","uriAttrs","$$minErr","optionalEndTagBlockElements","optionalEndTagInlineElements","extend","document","createElement","module","provider","$SanitizeProvider","$get","$$sanitizeUri","uri","filter","$sanitize","LINKY_URL_REGEXP","MAILTO_REGEXP","target","addText","addLink","url","isDefined","raw","substr"]
+"names":["window","angular","undefined","sanitizeText","chars","buf","htmlSanitizeWriter","writer","noop","join","makeMap","str","lowercaseKeys","obj","items","split","i","length","lowercase","htmlParser","html","handler","parseStartTag","tag","tagName","rest","unary","blockElements","stack","last","inlineElements","parseEndTag","optionalEndTagElements","voidElements","push","attrs","replace","ATTR_REGEXP","match","name","doubleQuotedValue","singleQuotedValue","unquotedValue","decodeEntities","start","pos","end","index","text","stack.last","specialElements","RegExp","all","COMMENT_REGEXP","CDATA_REGEXP","indexOf","lastIndexOf","comment","substring","DOCTYPE_REGEXP","test","BEGING_END_TAGE_REGEXP","END_TAG_REGEXP","BEGIN_TAG_REGEXP","START_TAG_REGEXP","$sanitizeMinErr","value","hiddenPre","innerHTML","textContent","encodeEntities","SURROGATE_PAIR_REGEXP","hi","charCodeAt","low","NON_ALPHANUMERIC_REGEXP","uriValidator","ignore","out","bind","validElements","forEach","key","lkey","isImage","validAttrs","uriAttrs","$$minErr","optionalEndTagBlockElements","optionalEndTagInlineElements","extend","svgElements","htmlAttrs","svgAttrs","document","createElement","module","provider","$SanitizeProvider","$get","$$sanitizeUri","uri","filter","$sanitize","LINKY_URL_REGEXP","MAILTO_REGEXP","target","addText","addLink","url","isDefined","raw","substr"]
}
diff --git a/libs/bower_components/angular-sanitize/bower.json b/libs/bower_components/angular-sanitize/bower.json
index 8c4afc7e4a..ffa9554222 100644
--- a/libs/bower_components/angular-sanitize/bower.json
+++ b/libs/bower_components/angular-sanitize/bower.json
@@ -1,9 +1,9 @@
{
"name": "angular-sanitize",
- "version": "1.2.28",
+ "version": "1.4.3",
"main": "./angular-sanitize.js",
"ignore": [],
"dependencies": {
- "angular": "1.2.28"
+ "angular": "1.4.3"
}
}
diff --git a/libs/bower_components/angular-sanitize/index.js b/libs/bower_components/angular-sanitize/index.js
new file mode 100644
index 0000000000..dd5d22e4a5
--- /dev/null
+++ b/libs/bower_components/angular-sanitize/index.js
@@ -0,0 +1,2 @@
+require('./angular-sanitize');
+module.exports = 'ngSanitize';
diff --git a/libs/bower_components/angular-sanitize/package.json b/libs/bower_components/angular-sanitize/package.json
index 8242c27373..d8ee360019 100644
--- a/libs/bower_components/angular-sanitize/package.json
+++ b/libs/bower_components/angular-sanitize/package.json
@@ -1,8 +1,8 @@
{
"name": "angular-sanitize",
- "version": "1.2.28",
+ "version": "1.4.3",
"description": "AngularJS module for sanitizing HTML",
- "main": "angular-sanitize.js",
+ "main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
diff --git a/libs/bower_components/angular/.bower.json b/libs/bower_components/angular/.bower.json
index c467f9945b..02a61a8c5f 100644
--- a/libs/bower_components/angular/.bower.json
+++ b/libs/bower_components/angular/.bower.json
@@ -1,17 +1,17 @@
{
"name": "angular",
- "version": "1.2.28",
+ "version": "1.4.3",
"main": "./angular.js",
"ignore": [],
"dependencies": {},
"homepage": "https://github.com/angular/bower-angular",
- "_release": "1.2.28",
+ "_release": "1.4.3",
"_resolution": {
"type": "version",
- "tag": "v1.2.28",
- "commit": "d1369fe05d3a7d85961a2223292b67ee82b9f80a"
+ "tag": "v1.4.3",
+ "commit": "dbd689e8103a6366e53e1f6786727f7c65ccfd75"
},
"_source": "git://github.com/angular/bower-angular.git",
- "_target": "~1.2.0",
+ "_target": "1.4.3",
"_originalSource": "angular"
} \ No newline at end of file
diff --git a/libs/bower_components/angular/README.md b/libs/bower_components/angular/README.md
index 897fb7f013..d1bc0eddf4 100644
--- a/libs/bower_components/angular/README.md
+++ b/libs/bower_components/angular/README.md
@@ -20,10 +20,7 @@ Then add a `<script>` to your `index.html`:
<script src="/node_modules/angular/angular.js"></script>
```
-Note that this package is not in CommonJS format, so doing `require('angular')` will return `undefined`.
-If you're using [Browserify](https://github.com/substack/node-browserify), you can use
-[exposify](https://github.com/thlorenz/exposify) to have `require('angular')` return the `angular`
-global.
+Or `require('angular')` from your code.
### bower
@@ -46,7 +43,7 @@ Documentation is available on the
The MIT License
-Copyright (c) 2010-2012 Google, Inc. http://angularjs.org
+Copyright (c) 2010-2015 Google, Inc. http://angularjs.org
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/libs/bower_components/angular/angular-csp.css b/libs/bower_components/angular/angular-csp.css
index 3abb3a0e66..f3cd926cb3 100644
--- a/libs/bower_components/angular/angular-csp.css
+++ b/libs/bower_components/angular/angular-csp.css
@@ -4,7 +4,7 @@
[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak],
.ng-cloak, .x-ng-cloak,
-.ng-hide {
+.ng-hide:not(.ng-hide-animate) {
display: none !important;
}
@@ -12,13 +12,10 @@ ng\:form {
display: block;
}
-.ng-animate-block-transitions {
- transition:0s all!important;
- -webkit-transition:0s all!important;
+.ng-animate-shim {
+ visibility:hidden;
}
-/* show the element during a show/hide animation when the
- * animation is ongoing, but the .ng-hide class is active */
-.ng-hide-add-active, .ng-hide-remove {
- display: block!important;
+.ng-anchor {
+ position:absolute;
}
diff --git a/libs/bower_components/angular/angular.js b/libs/bower_components/angular/angular.js
index a72a457951..7082434896 100644
--- a/libs/bower_components/angular/angular.js
+++ b/libs/bower_components/angular/angular.js
@@ -1,6 +1,6 @@
/**
- * @license AngularJS v1.2.28
- * (c) 2010-2014 Google, Inc. http://angularjs.org
+ * @license AngularJS v1.4.3
+ * (c) 2010-2015 Google, Inc. http://angularjs.org
* License: MIT
*/
(function(window, document, undefined) {'use strict';
@@ -30,138 +30,139 @@
* should all be static strings, not variables or general expressions.
*
* @param {string} module The namespace to use for the new minErr instance.
+ * @param {function} ErrorConstructor Custom error constructor to be instantiated when returning
+ * error from returned function, for cases when a particular type of error is useful.
* @returns {function(code:string, template:string, ...templateArgs): Error} minErr instance
*/
-function minErr(module) {
- return function () {
- var code = arguments[0],
- prefix = '[' + (module ? module + ':' : '') + code + '] ',
- template = arguments[1],
- templateArgs = arguments,
- stringify = function (obj) {
- if (typeof obj === 'function') {
- return obj.toString().replace(/ \{[\s\S]*$/, '');
- } else if (typeof obj === 'undefined') {
- return 'undefined';
- } else if (typeof obj !== 'string') {
- return JSON.stringify(obj);
- }
- return obj;
- },
- message, i;
-
- message = prefix + template.replace(/\{\d+\}/g, function (match) {
- var index = +match.slice(1, -1), arg;
-
- if (index + 2 < templateArgs.length) {
- arg = templateArgs[index + 2];
- if (typeof arg === 'function') {
- return arg.toString().replace(/ ?\{[\s\S]*$/, '');
- } else if (typeof arg === 'undefined') {
- return 'undefined';
- } else if (typeof arg !== 'string') {
- return toJson(arg);
- }
- return arg;
+function minErr(module, ErrorConstructor) {
+ ErrorConstructor = ErrorConstructor || Error;
+ return function() {
+ var SKIP_INDEXES = 2;
+
+ var templateArgs = arguments,
+ code = templateArgs[0],
+ message = '[' + (module ? module + ':' : '') + code + '] ',
+ template = templateArgs[1],
+ paramPrefix, i;
+
+ message += template.replace(/\{\d+\}/g, function(match) {
+ var index = +match.slice(1, -1),
+ shiftedIndex = index + SKIP_INDEXES;
+
+ if (shiftedIndex < templateArgs.length) {
+ return toDebugString(templateArgs[shiftedIndex]);
}
+
return match;
});
- message = message + '\nhttp://errors.angularjs.org/1.2.28/' +
+ message += '\nhttp://errors.angularjs.org/1.4.3/' +
(module ? module + '/' : '') + code;
- for (i = 2; i < arguments.length; i++) {
- message = message + (i == 2 ? '?' : '&') + 'p' + (i-2) + '=' +
- encodeURIComponent(stringify(arguments[i]));
+
+ for (i = SKIP_INDEXES, paramPrefix = '?'; i < templateArgs.length; i++, paramPrefix = '&') {
+ message += paramPrefix + 'p' + (i - SKIP_INDEXES) + '=' +
+ encodeURIComponent(toDebugString(templateArgs[i]));
}
- return new Error(message);
+ return new ErrorConstructor(message);
};
}
/* We need to tell jshint what variables are being exported */
/* global angular: true,
- msie: true,
- jqLite: true,
- jQuery: true,
- slice: true,
- push: true,
- toString: true,
- ngMinErr: true,
- angularModule: true,
- nodeName_: true,
- uid: true,
- VALIDITY_STATE_PROPERTY: true,
-
- lowercase: true,
- uppercase: true,
- manualLowercase: true,
- manualUppercase: true,
- nodeName_: true,
- isArrayLike: true,
- forEach: true,
- sortedKeys: true,
- forEachSorted: true,
- reverseParams: true,
- nextUid: true,
- setHashKey: true,
- extend: true,
- int: true,
- inherit: true,
- noop: true,
- identity: true,
- valueFn: true,
- isUndefined: true,
- isDefined: true,
- isObject: true,
- isString: true,
- isNumber: true,
- isDate: true,
- isArray: true,
- isFunction: true,
- isRegExp: true,
- isWindow: true,
- isScope: true,
- isFile: true,
- isBlob: true,
- isBoolean: true,
- isPromiseLike: true,
- trim: true,
- isElement: true,
- makeMap: true,
- map: true,
- size: true,
- includes: true,
- indexOf: true,
- arrayRemove: true,
- isLeafNode: true,
- copy: true,
- shallowCopy: true,
- equals: true,
- csp: true,
- concat: true,
- sliceArgs: true,
- bind: true,
- toJsonReplacer: true,
- toJson: true,
- fromJson: true,
- toBoolean: true,
- startingTag: true,
- tryDecodeURIComponent: true,
- parseKeyValue: true,
- toKeyValue: true,
- encodeUriSegment: true,
- encodeUriQuery: true,
- angularInit: true,
- bootstrap: true,
- snake_case: true,
- bindJQuery: true,
- assertArg: true,
- assertArgFn: true,
- assertNotHasOwnProperty: true,
- getter: true,
- getBlockElements: true,
- hasOwnProperty: true,
+ msie: true,
+ jqLite: true,
+ jQuery: true,
+ slice: true,
+ splice: true,
+ push: true,
+ toString: true,
+ ngMinErr: true,
+ angularModule: true,
+ uid: true,
+ REGEX_STRING_REGEXP: true,
+ VALIDITY_STATE_PROPERTY: true,
+
+ lowercase: true,
+ uppercase: true,
+ manualLowercase: true,
+ manualUppercase: true,
+ nodeName_: true,
+ isArrayLike: true,
+ forEach: true,
+ forEachSorted: true,
+ reverseParams: true,
+ nextUid: true,
+ setHashKey: true,
+ extend: true,
+ toInt: true,
+ inherit: true,
+ merge: true,
+ noop: true,
+ identity: true,
+ valueFn: true,
+ isUndefined: true,
+ isDefined: true,
+ isObject: true,
+ isBlankObject: true,
+ isString: true,
+ isNumber: true,
+ isDate: true,
+ isArray: true,
+ isFunction: true,
+ isRegExp: true,
+ isWindow: true,
+ isScope: true,
+ isFile: true,
+ isFormData: true,
+ isBlob: true,
+ isBoolean: true,
+ isPromiseLike: true,
+ trim: true,
+ escapeForRegexp: true,
+ isElement: true,
+ makeMap: true,
+ includes: true,
+ arrayRemove: true,
+ copy: true,
+ shallowCopy: true,
+ equals: true,
+ csp: true,
+ jq: true,
+ concat: true,
+ sliceArgs: true,
+ bind: true,
+ toJsonReplacer: true,
+ toJson: true,
+ fromJson: true,
+ convertTimezoneToLocal: true,
+ timezoneToOffset: true,
+ startingTag: true,
+ tryDecodeURIComponent: true,
+ parseKeyValue: true,
+ toKeyValue: true,
+ encodeUriSegment: true,
+ encodeUriQuery: true,
+ angularInit: true,
+ bootstrap: true,
+ getTestability: true,
+ snake_case: true,
+ bindJQuery: true,
+ assertArg: true,
+ assertArgFn: true,
+ assertNotHasOwnProperty: true,
+ getter: true,
+ getBlockNodes: true,
+ hasOwnProperty: true,
+ createMap: true,
+
+ NODE_TYPE_ELEMENT: true,
+ NODE_TYPE_ATTRIBUTE: true,
+ NODE_TYPE_TEXT: true,
+ NODE_TYPE_COMMENT: true,
+ NODE_TYPE_DOCUMENT: true,
+ NODE_TYPE_DOCUMENT_FRAGMENT: true,
*/
////////////////////////////////////
@@ -181,6 +182,8 @@ function minErr(module) {
* <div doc-module-components="ng"></div>
*/
+var REGEX_STRING_REGEXP = /^\/(.+)\/([a-z]*)$/;
+
// The name of a form control's ValidityState property.
// This is used so that it's possible for internal tests to create mock ValidityStates.
var VALIDITY_STATE_PROPERTY = 'validity';
@@ -195,7 +198,7 @@ var VALIDITY_STATE_PROPERTY = 'validity';
* @param {string} string String to be converted to lowercase.
* @returns {string} Lowercased string.
*/
-var lowercase = function(string){return isString(string) ? string.toLowerCase() : string;};
+var lowercase = function(string) {return isString(string) ? string.toLowerCase() : string;};
var hasOwnProperty = Object.prototype.hasOwnProperty;
/**
@@ -208,7 +211,7 @@ var hasOwnProperty = Object.prototype.hasOwnProperty;
* @param {string} string String to be converted to uppercase.
* @returns {string} Uppercased string.
*/
-var uppercase = function(string){return isString(string) ? string.toUpperCase() : string;};
+var uppercase = function(string) {return isString(string) ? string.toUpperCase() : string;};
var manualLowercase = function(s) {
@@ -239,24 +242,22 @@ var
jqLite, // delay binding since jQuery could be loaded after us.
jQuery, // delay binding
slice = [].slice,
+ splice = [].splice,
push = [].push,
toString = Object.prototype.toString,
+ getPrototypeOf = Object.getPrototypeOf,
ngMinErr = minErr('ng'),
/** @name angular */
angular = window.angular || (window.angular = {}),
angularModule,
- nodeName_,
- uid = ['0', '0', '0'];
+ uid = 0;
/**
- * IE 11 changed the format of the UserAgent string.
- * See http://msdn.microsoft.com/en-us/library/ms537503.aspx
+ * documentMode is an IE-only property
+ * http://msdn.microsoft.com/en-us/library/ie/cc196988(v=vs.85).aspx
*/
-msie = int((/msie (\d+)/.exec(lowercase(navigator.userAgent)) || [])[1]);
-if (isNaN(msie)) {
- msie = int((/trident\/.*; rv:(\d+)/.exec(lowercase(navigator.userAgent)) || [])[1]);
-}
+msie = document.documentMode;
/**
@@ -270,9 +271,11 @@ function isArrayLike(obj) {
return false;
}
- var length = obj.length;
+ // Support: iOS 8.2 (not reproducible in simulator)
+ // "length" in obj used to prevent JIT error (gh-11508)
+ var length = "length" in Object(obj) && obj.length;
- if (obj.nodeType === 1 && length) {
+ if (obj.nodeType === NODE_TYPE_ELEMENT && length) {
return true;
}
@@ -288,13 +291,18 @@ function isArrayLike(obj) {
*
* @description
* Invokes the `iterator` function once for each item in `obj` collection, which can be either an
- * object or an array. The `iterator` function is invoked with `iterator(value, key)`, where `value`
- * is the value of an object property or an array element and `key` is the object property key or
- * array element index. Specifying a `context` for the function is optional.
+ * object or an array. The `iterator` function is invoked with `iterator(value, key, obj)`, where `value`
+ * is the value of an object property or an array element, `key` is the object property key or
+ * array element index and obj is the `obj` itself. Specifying a `context` for the function is optional.
*
* It is worth noting that `.forEach` does not iterate over inherited properties because it filters
* using the `hasOwnProperty` method.
*
+ * Unlike ES262's
+ * [Array.prototype.forEach](http://www.ecma-international.org/ecma-262/5.1/#sec-15.4.4.18),
+ * Providing 'undefined' or 'null' values for `obj` will not throw a TypeError, but rather just
+ * return the value provided.
+ *
```js
var values = {name: 'misko', gender: 'male'};
var log = [];
@@ -309,27 +317,44 @@ function isArrayLike(obj) {
* @param {Object=} context Object to become context (`this`) for the iterator function.
* @returns {Object|Array} Reference to `obj`.
*/
+
function forEach(obj, iterator, context) {
- var key;
+ var key, length;
if (obj) {
if (isFunction(obj)) {
for (key in obj) {
// Need to check if hasOwnProperty exists,
// as on IE8 the result of querySelectorAll is an object without a hasOwnProperty function
if (key != 'prototype' && key != 'length' && key != 'name' && (!obj.hasOwnProperty || obj.hasOwnProperty(key))) {
- iterator.call(context, obj[key], key);
+ iterator.call(context, obj[key], key, obj);
}
}
} else if (isArray(obj) || isArrayLike(obj)) {
- for (key = 0; key < obj.length; key++) {
- iterator.call(context, obj[key], key);
+ var isPrimitive = typeof obj !== 'object';
+ for (key = 0, length = obj.length; key < length; key++) {
+ if (isPrimitive || key in obj) {
+ iterator.call(context, obj[key], key, obj);
+ }
}
} else if (obj.forEach && obj.forEach !== forEach) {
- obj.forEach(iterator, context);
- } else {
+ obj.forEach(iterator, context, obj);
+ } else if (isBlankObject(obj)) {
+ // createMap() fast path --- Safe to avoid hasOwnProperty check because prototype chain is empty
+ for (key in obj) {
+ iterator.call(context, obj[key], key, obj);
+ }
+ } else if (typeof obj.hasOwnProperty === 'function') {
+ // Slow path for objects inheriting Object.prototype, hasOwnProperty check needed
for (key in obj) {
if (obj.hasOwnProperty(key)) {
- iterator.call(context, obj[key], key);
+ iterator.call(context, obj[key], key, obj);
+ }
+ }
+ } else {
+ // Slow path for objects which do not have a method `hasOwnProperty`
+ for (key in obj) {
+ if (hasOwnProperty.call(obj, key)) {
+ iterator.call(context, obj[key], key, obj);
}
}
}
@@ -337,19 +362,9 @@ function forEach(obj, iterator, context) {
return obj;
}
-function sortedKeys(obj) {
- var keys = [];
- for (var key in obj) {
- if (obj.hasOwnProperty(key)) {
- keys.push(key);
- }
- }
- return keys.sort();
-}
-
function forEachSorted(obj, iterator, context) {
- var keys = sortedKeys(obj);
- for ( var i = 0; i < keys.length; i++) {
+ var keys = Object.keys(obj).sort();
+ for (var i = 0; i < keys.length; i++) {
iterator.call(context, obj[keys[i]], keys[i]);
}
return keys;
@@ -366,33 +381,17 @@ function reverseParams(iteratorFn) {
}
/**
- * A consistent way of creating unique IDs in angular. The ID is a sequence of alpha numeric
- * characters such as '012ABC'. The reason why we are not using simply a number counter is that
- * the number string gets longer over time, and it can also overflow, where as the nextId
- * will grow much slower, it is a string, and it will never overflow.
+ * A consistent way of creating unique IDs in angular.
+ *
+ * Using simple numbers allows us to generate 28.6 million unique ids per second for 10 years before
+ * we hit number precision issues in JavaScript.
+ *
+ * Math.pow(2,53) / 60 / 60 / 24 / 365 / 10 = 28.6M
*
- * @returns {string} an unique alpha-numeric string
+ * @returns {number} an unique alpha-numeric string
*/
function nextUid() {
- var index = uid.length;
- var digit;
-
- while(index) {
- index--;
- digit = uid[index].charCodeAt(0);
- if (digit == 57 /*'9'*/) {
- uid[index] = 'A';
- return uid.join('');
- }
- if (digit == 90 /*'Z'*/) {
- uid[index] = '0';
- } else {
- uid[index] = String.fromCharCode(digit + 1);
- return uid.join('');
- }
- }
- uid.unshift('0');
- return uid.join('');
+ return ++uid;
}
@@ -404,12 +403,40 @@ function nextUid() {
function setHashKey(obj, h) {
if (h) {
obj.$$hashKey = h;
- }
- else {
+ } else {
delete obj.$$hashKey;
}
}
+
+function baseExtend(dst, objs, deep) {
+ var h = dst.$$hashKey;
+
+ for (var i = 0, ii = objs.length; i < ii; ++i) {
+ var obj = objs[i];
+ if (!isObject(obj) && !isFunction(obj)) continue;
+ var keys = Object.keys(obj);
+ for (var j = 0, jj = keys.length; j < jj; j++) {
+ var key = keys[j];
+ var src = obj[key];
+
+ if (deep && isObject(src)) {
+ if (isDate(src)) {
+ dst[key] = new Date(src.valueOf());
+ } else {
+ if (!isObject(dst[key])) dst[key] = isArray(src) ? [] : {};
+ baseExtend(dst[key], [src], true);
+ }
+ } else {
+ dst[key] = src;
+ }
+ }
+ }
+
+ setHashKey(dst, h);
+ return dst;
+}
+
/**
* @ngdoc function
* @name angular.extend
@@ -418,33 +445,52 @@ function setHashKey(obj, h) {
*
* @description
* Extends the destination object `dst` by copying own enumerable properties from the `src` object(s)
- * to `dst`. You can specify multiple `src` objects.
+ * to `dst`. You can specify multiple `src` objects. If you want to preserve original objects, you can do so
+ * by passing an empty object as the target: `var object = angular.extend({}, object1, object2)`.
+ *
+ * **Note:** Keep in mind that `angular.extend` does not support recursive merge (deep copy). Use
+ * {@link angular.merge} for this.
*
* @param {Object} dst Destination object.
* @param {...Object} src Source object(s).
* @returns {Object} Reference to `dst`.
*/
function extend(dst) {
- var h = dst.$$hashKey;
- forEach(arguments, function(obj) {
- if (obj !== dst) {
- forEach(obj, function(value, key) {
- dst[key] = value;
- });
- }
- });
+ return baseExtend(dst, slice.call(arguments, 1), false);
+}
- setHashKey(dst,h);
- return dst;
+
+/**
+* @ngdoc function
+* @name angular.merge
+* @module ng
+* @kind function
+*
+* @description
+* Deeply extends the destination object `dst` by copying own enumerable properties from the `src` object(s)
+* to `dst`. You can specify multiple `src` objects. If you want to preserve original objects, you can do so
+* by passing an empty object as the target: `var object = angular.merge({}, object1, object2)`.
+*
+* Unlike {@link angular.extend extend()}, `merge()` recursively descends into object properties of source
+* objects, performing a deep copy.
+*
+* @param {Object} dst Destination object.
+* @param {...Object} src Source object(s).
+* @returns {Object} Reference to `dst`.
+*/
+function merge(dst) {
+ return baseExtend(dst, slice.call(arguments, 1), true);
}
-function int(str) {
+
+
+function toInt(str) {
return parseInt(str, 10);
}
function inherit(parent, extra) {
- return extend(new (extend(function() {}, {prototype:parent}))(), extra);
+ return extend(Object.create(parent), extra);
}
/**
@@ -482,6 +528,8 @@ noop.$inject = [];
return (transformationFn || angular.identity)(value);
};
```
+ * @param {*} value to be returned.
+ * @returns {*} the value passed in.
*/
function identity($) {return $;}
identity.$inject = [];
@@ -489,6 +537,11 @@ identity.$inject = [];
function valueFn(value) {return function() {return value;};}
+function hasCustomToString(obj) {
+ return isFunction(obj.toString) && obj.toString !== Object.prototype.toString;
+}
+
+
/**
* @ngdoc function
* @name angular.isUndefined
@@ -501,7 +554,7 @@ function valueFn(value) {return function() {return value;};}
* @param {*} value Reference to check.
* @returns {boolean} True if `value` is undefined.
*/
-function isUndefined(value){return typeof value === 'undefined';}
+function isUndefined(value) {return typeof value === 'undefined';}
/**
@@ -516,7 +569,7 @@ function isUndefined(value){return typeof value === 'undefined';}
* @param {*} value Reference to check.
* @returns {boolean} True if `value` is defined.
*/
-function isDefined(value){return typeof value !== 'undefined';}
+function isDefined(value) {return typeof value !== 'undefined';}
/**
@@ -532,7 +585,20 @@ function isDefined(value){return typeof value !== 'undefined';}
* @param {*} value Reference to check.
* @returns {boolean} True if `value` is an `Object` but not `null`.
*/
-function isObject(value){return value != null && typeof value === 'object';}
+function isObject(value) {
+ // http://jsperf.com/isobject4
+ return value !== null && typeof value === 'object';
+}
+
+
+/**
+ * Determine if a value is an object with a null prototype
+ *
+ * @returns {boolean} True if `value` is an `Object` with a null prototype
+ */
+function isBlankObject(value) {
+ return value !== null && typeof value === 'object' && !getPrototypeOf(value);
+}
/**
@@ -547,7 +613,7 @@ function isObject(value){return value != null && typeof value === 'object';}
* @param {*} value Reference to check.
* @returns {boolean} True if `value` is a `String`.
*/
-function isString(value){return typeof value === 'string';}
+function isString(value) {return typeof value === 'string';}
/**
@@ -559,10 +625,16 @@ function isString(value){return typeof value === 'string';}
* @description
* Determines if a reference is a `Number`.
*
+ * This includes the "special" numbers `NaN`, `+Infinity` and `-Infinity`.
+ *
+ * If you wish to exclude these then you can use the native
+ * [`isFinite'](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/isFinite)
+ * method.
+ *
* @param {*} value Reference to check.
* @returns {boolean} True if `value` is a `Number`.
*/
-function isNumber(value){return typeof value === 'number';}
+function isNumber(value) {return typeof value === 'number';}
/**
@@ -594,14 +666,7 @@ function isDate(value) {
* @param {*} value Reference to check.
* @returns {boolean} True if `value` is an `Array`.
*/
-var isArray = (function() {
- if (!isFunction(Array.isArray)) {
- return function(value) {
- return toString.call(value) === '[object Array]';
- };
- }
- return Array.isArray;
-})();
+var isArray = Array.isArray;
/**
* @ngdoc function
@@ -615,7 +680,7 @@ var isArray = (function() {
* @param {*} value Reference to check.
* @returns {boolean} True if `value` is a `Function`.
*/
-function isFunction(value){return typeof value === 'function';}
+function isFunction(value) {return typeof value === 'function';}
/**
@@ -638,7 +703,7 @@ function isRegExp(value) {
* @returns {boolean} True if `obj` is a window obj.
*/
function isWindow(obj) {
- return obj && obj.document && obj.location && obj.alert && obj.setInterval;
+ return obj && obj.window === obj;
}
@@ -652,6 +717,11 @@ function isFile(obj) {
}
+function isFormData(obj) {
+ return toString.call(obj) === '[object FormData]';
+}
+
+
function isBlob(obj) {
return toString.call(obj) === '[object Blob]';
}
@@ -667,19 +737,23 @@ function isPromiseLike(obj) {
}
-var trim = (function() {
- // native trim is way faster: http://jsperf.com/angular-trim-test
- // but IE doesn't have it... :-(
- // TODO: we should move this into IE/ES5 polyfill
- if (!String.prototype.trim) {
- return function(value) {
- return isString(value) ? value.replace(/^\s\s*/, '').replace(/\s\s*$/, '') : value;
- };
- }
- return function(value) {
- return isString(value) ? value.trim() : value;
- };
-})();
+var TYPED_ARRAY_REGEXP = /^\[object (Uint8(Clamped)?)|(Uint16)|(Uint32)|(Int8)|(Int16)|(Int32)|(Float(32)|(64))Array\]$/;
+function isTypedArray(value) {
+ return TYPED_ARRAY_REGEXP.test(toString.call(value));
+}
+
+
+var trim = function(value) {
+ return isString(value) ? value.trim() : value;
+};
+
+// Copied from:
+// http://docs.closure-library.googlecode.com/git/local_closure_goog_string_string.js.source.html#line1021
+// Prereq: s is a string.
+var escapeForRegexp = function(s) {
+ return s.replace(/([-()\[\]{}+?*.$\^|,:#<!\\])/g, '\\$1').
+ replace(/\x08/g, '\\x08');
+};
/**
@@ -706,91 +780,27 @@ function isElement(node) {
*/
function makeMap(str) {
var obj = {}, items = str.split(","), i;
- for ( i = 0; i < items.length; i++ )
- obj[ items[i] ] = true;
+ for (i = 0; i < items.length; i++) {
+ obj[items[i]] = true;
+ }
return obj;
}
-if (msie < 9) {
- nodeName_ = function(element) {
- element = element.nodeName ? element : element[0];
- return (element.scopeName && element.scopeName != 'HTML')
- ? uppercase(element.scopeName + ':' + element.nodeName) : element.nodeName;
- };
-} else {
- nodeName_ = function(element) {
- return element.nodeName ? element.nodeName : element[0].nodeName;
- };
-}
-
-
-function map(obj, iterator, context) {
- var results = [];
- forEach(obj, function(value, index, list) {
- results.push(iterator.call(context, value, index, list));
- });
- return results;
-}
-
-
-/**
- * @description
- * Determines the number of elements in an array, the number of properties an object has, or
- * the length of a string.
- *
- * Note: This function is used to augment the Object type in Angular expressions. See
- * {@link angular.Object} for more information about Angular arrays.
- *
- * @param {Object|Array|string} obj Object, array, or string to inspect.
- * @param {boolean} [ownPropsOnly=false] Count only "own" properties in an object
- * @returns {number} The size of `obj` or `0` if `obj` is neither an object nor an array.
- */
-function size(obj, ownPropsOnly) {
- var count = 0, key;
-
- if (isArray(obj) || isString(obj)) {
- return obj.length;
- } else if (isObject(obj)) {
- for (key in obj)
- if (!ownPropsOnly || obj.hasOwnProperty(key))
- count++;
- }
-
- return count;
+function nodeName_(element) {
+ return lowercase(element.nodeName || (element[0] && element[0].nodeName));
}
-
function includes(array, obj) {
- return indexOf(array, obj) != -1;
-}
-
-function indexOf(array, obj) {
- if (array.indexOf) return array.indexOf(obj);
-
- for (var i = 0; i < array.length; i++) {
- if (obj === array[i]) return i;
- }
- return -1;
+ return Array.prototype.indexOf.call(array, obj) != -1;
}
function arrayRemove(array, value) {
- var index = indexOf(array, value);
- if (index >=0)
+ var index = array.indexOf(value);
+ if (index >= 0) {
array.splice(index, 1);
- return value;
-}
-
-function isLeafNode (node) {
- if (node) {
- switch (node.nodeName) {
- case "OPTION":
- case "PRE":
- case "TITLE":
- return true;
- }
}
- return false;
+ return index;
}
/**
@@ -803,7 +813,7 @@ function isLeafNode (node) {
* Creates a deep copy of `source`, which should be an object or an array.
*
* * If no destination is supplied, a copy of the object or array is created.
- * * If a destination is provided, all of its elements (for array) or properties (for objects)
+ * * If a destination is provided, all of its elements (for arrays) or properties (for objects)
* are deleted and then all elements/properties from the source are copied to it.
* * If `source` is not an object or array (inc. `null` and `undefined`), `source` is returned.
* * If `source` is identical to 'destination' an exception will be thrown.
@@ -856,19 +866,40 @@ function copy(source, destination, stackSource, stackDest) {
throw ngMinErr('cpws',
"Can't copy! Making copies of Window or Scope instances is not supported.");
}
+ if (isTypedArray(destination)) {
+ throw ngMinErr('cpta',
+ "Can't copy! TypedArray destination cannot be mutated.");
+ }
if (!destination) {
destination = source;
- if (source) {
+ if (isObject(source)) {
+ var index;
+ if (stackSource && (index = stackSource.indexOf(source)) !== -1) {
+ return stackDest[index];
+ }
+
+ // TypedArray, Date and RegExp have specific copy functionality and must be
+ // pushed onto the stack before returning.
+ // Array and other objects create the base object and recurse to copy child
+ // objects. The array/object will be pushed onto the stack when recursed.
if (isArray(source)) {
- destination = copy(source, [], stackSource, stackDest);
+ return copy(source, [], stackSource, stackDest);
+ } else if (isTypedArray(source)) {
+ destination = new source.constructor(source);
} else if (isDate(source)) {
destination = new Date(source.getTime());
} else if (isRegExp(source)) {
destination = new RegExp(source.source, source.toString().match(/[^\/]*$/)[0]);
destination.lastIndex = source.lastIndex;
- } else if (isObject(source)) {
- destination = copy(source, {}, stackSource, stackDest);
+ } else {
+ var emptyObject = Object.create(getPrototypeOf(source));
+ return copy(source, emptyObject, stackSource, stackDest);
+ }
+
+ if (stackDest) {
+ stackSource.push(source);
+ stackDest.push(destination);
}
}
} else {
@@ -879,23 +910,15 @@ function copy(source, destination, stackSource, stackDest) {
stackDest = stackDest || [];
if (isObject(source)) {
- var index = indexOf(stackSource, source);
- if (index !== -1) return stackDest[index];
-
stackSource.push(source);
stackDest.push(destination);
}
- var result;
+ var result, key;
if (isArray(source)) {
destination.length = 0;
- for ( var i = 0; i < source.length; i++) {
- result = copy(source[i], null, stackSource, stackDest);
- if (isObject(source[i])) {
- stackSource.push(source[i]);
- stackDest.push(result);
- }
- destination.push(result);
+ for (var i = 0; i < source.length; i++) {
+ destination.push(copy(source[i], null, stackSource, stackDest));
}
} else {
var h = destination.$$hashKey;
@@ -906,36 +929,49 @@ function copy(source, destination, stackSource, stackDest) {
delete destination[key];
});
}
- for ( var key in source) {
- result = copy(source[key], null, stackSource, stackDest);
- if (isObject(source[key])) {
- stackSource.push(source[key]);
- stackDest.push(result);
+ if (isBlankObject(source)) {
+ // createMap() fast path --- Safe to avoid hasOwnProperty check because prototype chain is empty
+ for (key in source) {
+ destination[key] = copy(source[key], null, stackSource, stackDest);
+ }
+ } else if (source && typeof source.hasOwnProperty === 'function') {
+ // Slow path, which must rely on hasOwnProperty
+ for (key in source) {
+ if (source.hasOwnProperty(key)) {
+ destination[key] = copy(source[key], null, stackSource, stackDest);
+ }
+ }
+ } else {
+ // Slowest path --- hasOwnProperty can't be called as a method
+ for (key in source) {
+ if (hasOwnProperty.call(source, key)) {
+ destination[key] = copy(source[key], null, stackSource, stackDest);
+ }
}
- destination[key] = result;
}
setHashKey(destination,h);
}
-
}
return destination;
}
/**
- * Creates a shallow copy of an object, an array or a primitive
+ * Creates a shallow copy of an object, an array or a primitive.
+ *
+ * Assumes that there are no proto properties for objects.
*/
function shallowCopy(src, dst) {
if (isArray(src)) {
dst = dst || [];
- for ( var i = 0; i < src.length; i++) {
+ for (var i = 0, ii = src.length; i < ii; i++) {
dst[i] = src[i];
}
} else if (isObject(src)) {
dst = dst || {};
for (var key in src) {
- if (hasOwnProperty.call(src, key) && !(key.charAt(0) === '$' && key.charAt(1) === '$')) {
+ if (!(key.charAt(0) === '$' && key.charAt(1) === '$')) {
dst[key] = src[key];
}
}
@@ -984,26 +1020,27 @@ function equals(o1, o2) {
if (isArray(o1)) {
if (!isArray(o2)) return false;
if ((length = o1.length) == o2.length) {
- for(key=0; key<length; key++) {
+ for (key = 0; key < length; key++) {
if (!equals(o1[key], o2[key])) return false;
}
return true;
}
} else if (isDate(o1)) {
if (!isDate(o2)) return false;
- return (isNaN(o1.getTime()) && isNaN(o2.getTime())) || (o1.getTime() === o2.getTime());
- } else if (isRegExp(o1) && isRegExp(o2)) {
- return o1.toString() == o2.toString();
+ return equals(o1.getTime(), o2.getTime());
+ } else if (isRegExp(o1)) {
+ return isRegExp(o2) ? o1.toString() == o2.toString() : false;
} else {
- if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2) || isArray(o2)) return false;
- keySet = {};
- for(key in o1) {
+ if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2) ||
+ isArray(o2) || isDate(o2) || isRegExp(o2)) return false;
+ keySet = createMap();
+ for (key in o1) {
if (key.charAt(0) === '$' || isFunction(o1[key])) continue;
if (!equals(o1[key], o2[key])) return false;
keySet[key] = true;
}
- for(key in o2) {
- if (!keySet.hasOwnProperty(key) &&
+ for (key in o2) {
+ if (!(key in keySet) &&
key.charAt(0) !== '$' &&
o2[key] !== undefined &&
!isFunction(o2[key])) return false;
@@ -1034,7 +1071,58 @@ var csp = function() {
return (csp.isActive_ = active);
};
+/**
+ * @ngdoc directive
+ * @module ng
+ * @name ngJq
+ *
+ * @element ANY
+ * @param {string=} ngJq the name of the library available under `window`
+ * to be used for angular.element
+ * @description
+ * Use this directive to force the angular.element library. This should be
+ * used to force either jqLite by leaving ng-jq blank or setting the name of
+ * the jquery variable under window (eg. jQuery).
+ *
+ * Since angular looks for this directive when it is loaded (doesn't wait for the
+ * DOMContentLoaded event), it must be placed on an element that comes before the script
+ * which loads angular. Also, only the first instance of `ng-jq` will be used and all
+ * others ignored.
+ *
+ * @example
+ * This example shows how to force jqLite using the `ngJq` directive to the `html` tag.
+ ```html
+ <!doctype html>
+ <html ng-app ng-jq>
+ ...
+ ...
+ </html>
+ ```
+ * @example
+ * This example shows how to use a jQuery based library of a different name.
+ * The library name must be available at the top most 'window'.
+ ```html
+ <!doctype html>
+ <html ng-app ng-jq="jQueryLib">
+ ...
+ ...
+ </html>
+ ```
+ */
+var jq = function() {
+ if (isDefined(jq.name_)) return jq.name_;
+ var el;
+ var i, ii = ngAttrPrefixes.length, prefix, name;
+ for (i = 0; i < ii; ++i) {
+ prefix = ngAttrPrefixes[i];
+ if (el = document.querySelector('[' + prefix.replace(':', '\\:') + 'jq]')) {
+ name = el.getAttribute(prefix + 'jq');
+ break;
+ }
+ }
+ return (jq.name_ = name);
+};
function concat(array1, array2, index) {
return array1.concat(slice.call(array2, index));
@@ -1070,7 +1158,7 @@ function bind(self, fn) {
return curryArgs.length
? function() {
return arguments.length
- ? fn.apply(self, curryArgs.concat(slice.call(arguments, 0)))
+ ? fn.apply(self, concat(curryArgs, arguments, 0))
: fn.apply(self, curryArgs);
}
: function() {
@@ -1088,7 +1176,7 @@ function bind(self, fn) {
function toJsonReplacer(key, value) {
var val = value;
- if (typeof key === 'string' && key.charAt(0) === '$') {
+ if (typeof key === 'string' && key.charAt(0) === '$' && key.charAt(1) === '$') {
val = undefined;
} else if (isWindow(value)) {
val = '$WINDOW';
@@ -1109,16 +1197,20 @@ function toJsonReplacer(key, value) {
* @kind function
*
* @description
- * Serializes input into a JSON-formatted string. Properties with leading $ characters will be
+ * Serializes input into a JSON-formatted string. Properties with leading $$ characters will be
* stripped since angular uses this notation internally.
*
* @param {Object|Array|Date|string|number} obj Input to be serialized into JSON.
- * @param {boolean=} pretty If set to true, the JSON output will contain newlines and whitespace.
+ * @param {boolean|number} [pretty=2] If set to true, the JSON output will contain newlines and whitespace.
+ * If set to an integer, the JSON output will contain that many spaces per indentation.
* @returns {string|undefined} JSON-ified string representing `obj`.
*/
function toJson(obj, pretty) {
if (typeof obj === 'undefined') return undefined;
- return JSON.stringify(obj, toJsonReplacer, pretty ? ' ' : null);
+ if (!isNumber(pretty)) {
+ pretty = pretty ? 2 : null;
+ }
+ return JSON.stringify(obj, toJsonReplacer, pretty);
}
@@ -1132,7 +1224,7 @@ function toJson(obj, pretty) {
* Deserializes a JSON string.
*
* @param {string} json JSON string to deserialize.
- * @returns {Object|Array|string|number} Deserialized thingy.
+ * @returns {Object|Array|string|number} Deserialized JSON string.
*/
function fromJson(json) {
return isString(json)
@@ -1141,18 +1233,26 @@ function fromJson(json) {
}
-function toBoolean(value) {
- if (typeof value === 'function') {
- value = true;
- } else if (value && value.length !== 0) {
- var v = lowercase("" + value);
- value = !(v == 'f' || v == '0' || v == 'false' || v == 'no' || v == 'n' || v == '[]');
- } else {
- value = false;
- }
- return value;
+function timezoneToOffset(timezone, fallback) {
+ var requestedTimezoneOffset = Date.parse('Jan 01, 1970 00:00:00 ' + timezone) / 60000;
+ return isNaN(requestedTimezoneOffset) ? fallback : requestedTimezoneOffset;
+}
+
+
+function addDateMinutes(date, minutes) {
+ date = new Date(date.getTime());
+ date.setMinutes(date.getMinutes() + minutes);
+ return date;
}
+
+function convertTimezoneToLocal(date, timezone, reverse) {
+ reverse = reverse ? -1 : 1;
+ var timezoneOffset = timezoneToOffset(timezone, date.getTimezoneOffset());
+ return addDateMinutes(date, reverse * (timezoneOffset - date.getTimezoneOffset()));
+}
+
+
/**
* @returns {string} Returns the string representation of the element.
*/
@@ -1162,16 +1262,14 @@ function startingTag(element) {
// turns out IE does not let you set .html() on elements which
// are not allowed to have children. So we just ignore it.
element.empty();
- } catch(e) {}
- // As Per DOM Standards
- var TEXT_NODE = 3;
+ } catch (e) {}
var elemHtml = jqLite('<div>').append(element).html();
try {
- return element[0].nodeType === TEXT_NODE ? lowercase(elemHtml) :
+ return element[0].nodeType === NODE_TYPE_TEXT ? lowercase(elemHtml) :
elemHtml.
match(/^(<[^>]+>)/)[1].
replace(/^<([\w\-]+)/, function(match, nodeName) { return '<' + lowercase(nodeName); });
- } catch(e) {
+ } catch (e) {
return lowercase(elemHtml);
}
@@ -1191,7 +1289,7 @@ function startingTag(element) {
function tryDecodeURIComponent(value) {
try {
return decodeURIComponent(value);
- } catch(e) {
+ } catch (e) {
// Ignore any invalid uri component
}
}
@@ -1204,14 +1302,14 @@ function tryDecodeURIComponent(value) {
function parseKeyValue(/**string*/keyValue) {
var obj = {}, key_value, key;
forEach((keyValue || "").split('&'), function(keyValue) {
- if ( keyValue ) {
+ if (keyValue) {
key_value = keyValue.replace(/\+/g,'%20').split('=');
key = tryDecodeURIComponent(key_value[0]);
- if ( isDefined(key) ) {
+ if (isDefined(key)) {
var val = isDefined(key_value[1]) ? tryDecodeURIComponent(key_value[1]) : true;
if (!hasOwnProperty.call(obj, key)) {
obj[key] = val;
- } else if(isArray(obj[key])) {
+ } else if (isArray(obj[key])) {
obj[key].push(val);
} else {
obj[key] = [obj[key],val];
@@ -1275,9 +1373,22 @@ function encodeUriQuery(val, pctEncodeSpaces) {
replace(/%3A/gi, ':').
replace(/%24/g, '$').
replace(/%2C/gi, ',').
+ replace(/%3B/gi, ';').
replace(/%20/g, (pctEncodeSpaces ? '%20' : '+'));
}
+var ngAttrPrefixes = ['ng-', 'data-ng-', 'ng:', 'x-ng-'];
+
+function getNgAttribute(element, ngAttr) {
+ var attr, i, ii = ngAttrPrefixes.length;
+ for (i = 0; i < ii; ++i) {
+ attr = ngAttrPrefixes[i] + ngAttr;
+ if (isString(attr = element.getAttribute(attr))) {
+ return attr;
+ }
+ }
+ return null;
+}
/**
* @ngdoc directive
@@ -1287,6 +1398,11 @@ function encodeUriQuery(val, pctEncodeSpaces) {
* @element ANY
* @param {angular.Module} ngApp an optional application
* {@link angular.module module} name to load.
+ * @param {boolean=} ngStrictDi if this attribute is present on the app element, the injector will be
+ * created in "strict-di" mode. This means that the application will fail to invoke functions which
+ * do not use explicit function annotation (and are thus unsuitable for minification), as described
+ * in {@link guide/di the Dependency Injection guide}, and useful debugging info will assist in
+ * tracking down the root of these bugs.
*
* @description
*
@@ -1300,7 +1416,7 @@ function encodeUriQuery(val, pctEncodeSpaces) {
* {@link angular.bootstrap} instead. AngularJS applications cannot be nested within each other.
*
* You can specify an **AngularJS module** to be used as the root module for the application. This
- * module will be loaded into the {@link auto.$injector} when the application is bootstrapped and
+ * module will be loaded into the {@link auto.$injector} when the application is bootstrapped. It
* should contain the application code needed or have dependencies on other modules that will
* contain the code. See {@link angular.module} for more information.
*
@@ -1308,7 +1424,7 @@ function encodeUriQuery(val, pctEncodeSpaces) {
* document would not be compiled, the `AppController` would not be instantiated and the `{{ a+b }}`
* would not be resolved to `3`.
*
- * `ngApp` is the easiest, and most common, way to bootstrap an application.
+ * `ngApp` is the easiest, and most common way to bootstrap an application.
*
<example module="ngAppDemo">
<file name="index.html">
@@ -1324,48 +1440,109 @@ function encodeUriQuery(val, pctEncodeSpaces) {
</file>
</example>
*
+ * Using `ngStrictDi`, you would see something like this:
+ *
+ <example ng-app-included="true">
+ <file name="index.html">
+ <div ng-app="ngAppStrictDemo" ng-strict-di>
+ <div ng-controller="GoodController1">
+ I can add: {{a}} + {{b}} = {{ a+b }}
+
+ <p>This renders because the controller does not fail to
+ instantiate, by using explicit annotation style (see
+ script.js for details)
+ </p>
+ </div>
+
+ <div ng-controller="GoodController2">
+ Name: <input ng-model="name"><br />
+ Hello, {{name}}!
+
+ <p>This renders because the controller does not fail to
+ instantiate, by using explicit annotation style
+ (see script.js for details)
+ </p>
+ </div>
+
+ <div ng-controller="BadController">
+ I can add: {{a}} + {{b}} = {{ a+b }}
+
+ <p>The controller could not be instantiated, due to relying
+ on automatic function annotations (which are disabled in
+ strict mode). As such, the content of this section is not
+ interpolated, and there should be an error in your web console.
+ </p>
+ </div>
+ </div>
+ </file>
+ <file name="script.js">
+ angular.module('ngAppStrictDemo', [])
+ // BadController will fail to instantiate, due to relying on automatic function annotation,
+ // rather than an explicit annotation
+ .controller('BadController', function($scope) {
+ $scope.a = 1;
+ $scope.b = 2;
+ })
+ // Unlike BadController, GoodController1 and GoodController2 will not fail to be instantiated,
+ // due to using explicit annotations using the array style and $inject property, respectively.
+ .controller('GoodController1', ['$scope', function($scope) {
+ $scope.a = 1;
+ $scope.b = 2;
+ }])
+ .controller('GoodController2', GoodController2);
+ function GoodController2($scope) {
+ $scope.name = "World";
+ }
+ GoodController2.$inject = ['$scope'];
+ </file>
+ <file name="style.css">
+ div[ng-controller] {
+ margin-bottom: 1em;
+ -webkit-border-radius: 4px;
+ border-radius: 4px;
+ border: 1px solid;
+ padding: .5em;
+ }
+ div[ng-controller^=Good] {
+ border-color: #d6e9c6;
+ background-color: #dff0d8;
+ color: #3c763d;
+ }
+ div[ng-controller^=Bad] {
+ border-color: #ebccd1;
+ background-color: #f2dede;
+ color: #a94442;
+ margin-bottom: 0;
+ }
+ </file>
+ </example>
*/
function angularInit(element, bootstrap) {
- var elements = [element],
- appElement,
+ var appElement,
module,
- names = ['ng:app', 'ng-app', 'x-ng-app', 'data-ng-app'],
- NG_APP_CLASS_REGEXP = /\sng[:\-]app(:\s*([\w\d_]+);?)?\s/;
+ config = {};
- function append(element) {
- element && elements.push(element);
- }
+ // The element `element` has priority over any other element
+ forEach(ngAttrPrefixes, function(prefix) {
+ var name = prefix + 'app';
- forEach(names, function(name) {
- names[name] = true;
- append(document.getElementById(name));
- name = name.replace(':', '\\:');
- if (element.querySelectorAll) {
- forEach(element.querySelectorAll('.' + name), append);
- forEach(element.querySelectorAll('.' + name + '\\:'), append);
- forEach(element.querySelectorAll('[' + name + ']'), append);
+ if (!appElement && element.hasAttribute && element.hasAttribute(name)) {
+ appElement = element;
+ module = element.getAttribute(name);
}
});
+ forEach(ngAttrPrefixes, function(prefix) {
+ var name = prefix + 'app';
+ var candidate;
- forEach(elements, function(element) {
- if (!appElement) {
- var className = ' ' + element.className + ' ';
- var match = NG_APP_CLASS_REGEXP.exec(className);
- if (match) {
- appElement = element;
- module = (match[2] || '').replace(/\s+/g, ',');
- } else {
- forEach(element.attributes, function(attr) {
- if (!appElement && names[attr.name]) {
- appElement = element;
- module = attr.value;
- }
- });
- }
+ if (!appElement && (candidate = element.querySelector('[' + name.replace(':', '\\:') + ']'))) {
+ appElement = candidate;
+ module = candidate.getAttribute(name);
}
});
if (appElement) {
- bootstrap(appElement, module ? [module] : []);
+ config.strictDi = getNgAttribute(appElement, "strict-di") !== null;
+ bootstrap(appElement, module ? [module] : [], config);
}
}
@@ -1378,7 +1555,7 @@ function angularInit(element, bootstrap) {
*
* See: {@link guide/bootstrap Bootstrap}
*
- * Note that ngScenario-based end-to-end tests cannot use this function to bootstrap manually.
+ * Note that Protractor based end-to-end tests cannot use this function to bootstrap manually.
* They must use {@link ng.directive:ngApp ngApp}.
*
* Angular will detect if it has been loaded into the browser more than once and only allow the
@@ -1386,44 +1563,45 @@ function angularInit(element, bootstrap) {
* each of the subsequent scripts. This prevents strange results in applications, where otherwise
* multiple instances of Angular try to work on the DOM.
*
- * <example name="multi-bootstrap" module="multi-bootstrap">
- * <file name="index.html">
- * <script src="../../../angular.js"></script>
- * <div ng-controller="BrokenTable">
- * <table>
- * <tr>
- * <th ng-repeat="heading in headings">{{heading}}</th>
- * </tr>
- * <tr ng-repeat="filling in fillings">
- * <td ng-repeat="fill in filling">{{fill}}</td>
- * </tr>
- * </table>
+ * ```html
+ * <!doctype html>
+ * <html>
+ * <body>
+ * <div ng-controller="WelcomeController">
+ * {{greeting}}
* </div>
- * </file>
- * <file name="controller.js">
- * var app = angular.module('multi-bootstrap', [])
*
- * .controller('BrokenTable', function($scope) {
- * $scope.headings = ['One', 'Two', 'Three'];
- * $scope.fillings = [[1, 2, 3], ['A', 'B', 'C'], [7, 8, 9]];
- * });
- * </file>
- * <file name="protractor.js" type="protractor">
- * it('should only insert one table cell for each item in $scope.fillings', function() {
- * expect(element.all(by.css('td')).count())
- * .toBe(9);
- * });
- * </file>
- * </example>
+ * <script src="angular.js"></script>
+ * <script>
+ * var app = angular.module('demo', [])
+ * .controller('WelcomeController', function($scope) {
+ * $scope.greeting = 'Welcome!';
+ * });
+ * angular.bootstrap(document, ['demo']);
+ * </script>
+ * </body>
+ * </html>
+ * ```
*
* @param {DOMElement} element DOM element which is the root of angular application.
* @param {Array<String|Function|Array>=} modules an array of modules to load into the application.
* Each item in the array should be the name of a predefined module or a (DI annotated)
- * function that will be invoked by the injector as a run block.
+ * function that will be invoked by the injector as a `config` block.
* See: {@link angular.module modules}
+ * @param {Object=} config an object for defining configuration options for the application. The
+ * following keys are supported:
+ *
+ * * `strictDi` - disable automatic function annotation for the application. This is meant to
+ * assist in finding bugs which break minified code. Defaults to `false`.
+ *
* @returns {auto.$injector} Returns the newly created injector for this app.
*/
-function bootstrap(element, modules) {
+function bootstrap(element, modules, config) {
+ if (!isObject(config)) config = {};
+ var defaultConfig = {
+ strictDi: false
+ };
+ config = extend(defaultConfig, config);
var doBootstrap = function() {
element = jqLite(element);
@@ -1440,10 +1618,18 @@ function bootstrap(element, modules) {
modules.unshift(['$provide', function($provide) {
$provide.value('$rootElement', element);
}]);
+
+ if (config.debugInfoEnabled) {
+ // Pushing so that this overrides `debugInfoEnabled` setting defined in user's `modules`.
+ modules.push(['$compileProvider', function($compileProvider) {
+ $compileProvider.debugInfoEnabled(true);
+ }]);
+ }
+
modules.unshift('ng');
- var injector = createInjector(modules);
- injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector', '$animate',
- function(scope, element, compile, injector, animate) {
+ var injector = createInjector(modules, config.strictDi);
+ injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector',
+ function bootstrapApply(scope, element, compile, injector) {
scope.$apply(function() {
element.data('$injector', injector);
compile(element)(scope);
@@ -1453,8 +1639,14 @@ function bootstrap(element, modules) {
return injector;
};
+ var NG_ENABLE_DEBUG_INFO = /^NG_ENABLE_DEBUG_INFO!/;
var NG_DEFER_BOOTSTRAP = /^NG_DEFER_BOOTSTRAP!/;
+ if (window && NG_ENABLE_DEBUG_INFO.test(window.name)) {
+ config.debugInfoEnabled = true;
+ window.name = window.name.replace(NG_ENABLE_DEBUG_INFO, '');
+ }
+
if (window && !NG_DEFER_BOOTSTRAP.test(window.name)) {
return doBootstrap();
}
@@ -1464,8 +1656,44 @@ function bootstrap(element, modules) {
forEach(extraModules, function(module) {
modules.push(module);
});
- doBootstrap();
+ return doBootstrap();
};
+
+ if (isFunction(angular.resumeDeferredBootstrap)) {
+ angular.resumeDeferredBootstrap();
+ }
+}
+
+/**
+ * @ngdoc function
+ * @name angular.reloadWithDebugInfo
+ * @module ng
+ * @description
+ * Use this function to reload the current application with debug information turned on.
+ * This takes precedence over a call to `$compileProvider.debugInfoEnabled(false)`.
+ *
+ * See {@link ng.$compileProvider#debugInfoEnabled} for more.
+ */
+function reloadWithDebugInfo() {
+ window.name = 'NG_ENABLE_DEBUG_INFO!' + window.name;
+ window.location.reload();
+}
+
+/**
+ * @name angular.getTestability
+ * @module ng
+ * @description
+ * Get the testability service for the instance of Angular on the given
+ * element.
+ * @param {DOMElement} element DOM element which is the root of angular application.
+ */
+function getTestability(rootElement) {
+ var injector = angular.element(rootElement).injector();
+ if (!injector) {
+ throw ngMinErr('test',
+ 'no injector found for element argument to getTestability');
+ }
+ return injector.get('$$testability');
}
var SNAKE_CASE_REGEXP = /[A-Z]/g;
@@ -1476,11 +1704,26 @@ function snake_case(name, separator) {
});
}
+var bindJQueryFired = false;
+var skipDestroyOnNextJQueryCleanData;
function bindJQuery() {
+ var originalCleanData;
+
+ if (bindJQueryFired) {
+ return;
+ }
+
// bind to jQuery if present;
- jQuery = window.jQuery;
+ var jqName = jq();
+ jQuery = window.jQuery; // use default jQuery.
+ if (isDefined(jqName)) { // `ngJq` present
+ jQuery = jqName === null ? undefined : window[jqName]; // if empty; use jqLite. if not empty, use jQuery specified by `ngJq`.
+ }
+
// Use jQuery if it exists with proper functionality, otherwise default to us.
- // Angular 1.2+ requires jQuery 1.7.1+ for on()/off() support.
+ // Angular 1.2+ requires jQuery 1.7+ for on()/off() support.
+ // Angular 1.3+ technically requires at least jQuery 2.1+ but it may work with older
+ // versions. It will not work for sure with jQuery <1.7, though.
if (jQuery && jQuery.fn.on) {
jqLite = jQuery;
extend(jQuery.fn, {
@@ -1490,15 +1733,33 @@ function bindJQuery() {
injector: JQLitePrototype.injector,
inheritedData: JQLitePrototype.inheritedData
});
- // Method signature:
- // jqLitePatchJQueryRemove(name, dispatchThis, filterElems, getterIfNoArguments)
- jqLitePatchJQueryRemove('remove', true, true, false);
- jqLitePatchJQueryRemove('empty', false, false, false);
- jqLitePatchJQueryRemove('html', false, false, true);
+
+ // All nodes removed from the DOM via various jQuery APIs like .remove()
+ // are passed through jQuery.cleanData. Monkey-patch this method to fire
+ // the $destroy event on all removed nodes.
+ originalCleanData = jQuery.cleanData;
+ jQuery.cleanData = function(elems) {
+ var events;
+ if (!skipDestroyOnNextJQueryCleanData) {
+ for (var i = 0, elem; (elem = elems[i]) != null; i++) {
+ events = jQuery._data(elem, "events");
+ if (events && events.$destroy) {
+ jQuery(elem).triggerHandler('$destroy');
+ }
+ }
+ } else {
+ skipDestroyOnNextJQueryCleanData = false;
+ }
+ originalCleanData(elems);
+ };
} else {
jqLite = JQLite;
}
+
angular.element = jqLite;
+
+ // Prevent double-proxying.
+ bindJQueryFired = true;
}
/**
@@ -1562,27 +1823,47 @@ function getter(obj, path, bindFnToScope) {
/**
* Return the DOM siblings between the first and last node in the given array.
* @param {Array} array like object
- * @returns {DOMElement} object containing the elements
+ * @returns {jqLite} jqLite collection containing the nodes
*/
-function getBlockElements(nodes) {
- var startNode = nodes[0],
- endNode = nodes[nodes.length - 1];
- if (startNode === endNode) {
- return jqLite(startNode);
- }
-
- var element = startNode;
- var elements = [element];
+function getBlockNodes(nodes) {
+ // TODO(perf): just check if all items in `nodes` are siblings and if they are return the original
+ // collection, otherwise update the original collection.
+ var node = nodes[0];
+ var endNode = nodes[nodes.length - 1];
+ var blockNodes = [node];
do {
- element = element.nextSibling;
- if (!element) break;
- elements.push(element);
- } while (element !== endNode);
+ node = node.nextSibling;
+ if (!node) break;
+ blockNodes.push(node);
+ } while (node !== endNode);
- return jqLite(elements);
+ return jqLite(blockNodes);
}
+
+/**
+ * Creates a new object without a prototype. This object is useful for lookup without having to
+ * guard against prototypically inherited properties via hasOwnProperty.
+ *
+ * Related micro-benchmarks:
+ * - http://jsperf.com/object-create2
+ * - http://jsperf.com/proto-map-lookup/2
+ * - http://jsperf.com/for-in-vs-object-keys2
+ *
+ * @returns {Object}
+ */
+function createMap() {
+ return Object.create(null);
+}
+
+var NODE_TYPE_ELEMENT = 1;
+var NODE_TYPE_ATTRIBUTE = 2;
+var NODE_TYPE_TEXT = 3;
+var NODE_TYPE_COMMENT = 8;
+var NODE_TYPE_DOCUMENT = 9;
+var NODE_TYPE_DOCUMENT_FRAGMENT = 11;
+
/**
* @ngdoc type
* @name angular.Module
@@ -1683,14 +1964,18 @@ function setupModuleLoader(window) {
var invokeQueue = [];
/** @type {!Array.<Function>} */
+ var configBlocks = [];
+
+ /** @type {!Array.<Function>} */
var runBlocks = [];
- var config = invokeLater('$injector', 'invoke');
+ var config = invokeLater('$injector', 'invoke', 'push', configBlocks);
/** @type {angular.Module} */
var moduleInstance = {
// Private state
_invokeQueue: invokeQueue,
+ _configBlocks: configBlocks,
_runBlocks: runBlocks,
/**
@@ -1725,7 +2010,7 @@ function setupModuleLoader(window) {
* @description
* See {@link auto.$provide#provider $provide.provider()}.
*/
- provider: invokeLater('$provide', 'provider'),
+ provider: invokeLaterAndSetModuleName('$provide', 'provider'),
/**
* @ngdoc method
@@ -1736,7 +2021,7 @@ function setupModuleLoader(window) {
* @description
* See {@link auto.$provide#factory $provide.factory()}.
*/
- factory: invokeLater('$provide', 'factory'),
+ factory: invokeLaterAndSetModuleName('$provide', 'factory'),
/**
* @ngdoc method
@@ -1747,7 +2032,7 @@ function setupModuleLoader(window) {
* @description
* See {@link auto.$provide#service $provide.service()}.
*/
- service: invokeLater('$provide', 'service'),
+ service: invokeLaterAndSetModuleName('$provide', 'service'),
/**
* @ngdoc method
@@ -1772,6 +2057,18 @@ function setupModuleLoader(window) {
*/
constant: invokeLater('$provide', 'constant', 'unshift'),
+ /**
+ * @ngdoc method
+ * @name angular.Module#decorator
+ * @module ng
+ * @param {string} The name of the service to decorate.
+ * @param {Function} This function will be invoked when the service needs to be
+ * instantiated and should return the decorated service instance.
+ * @description
+ * See {@link auto.$provide#decorator $provide.decorator()}.
+ */
+ decorator: invokeLaterAndSetModuleName('$provide', 'decorator'),
+
/**
* @ngdoc method
* @name angular.Module#animation
@@ -1785,7 +2082,7 @@ function setupModuleLoader(window) {
*
*
* Defines an animation hook that can be later used with
- * {@link ngAnimate.$animate $animate} service and directives that use this service.
+ * {@link $animate $animate} service and directives that use this service.
*
* ```js
* module.animation('.animation-name', function($inject1, $inject2) {
@@ -1801,21 +2098,28 @@ function setupModuleLoader(window) {
* })
* ```
*
- * See {@link ngAnimate.$animateProvider#register $animateProvider.register()} and
+ * See {@link ng.$animateProvider#register $animateProvider.register()} and
* {@link ngAnimate ngAnimate module} for more information.
*/
- animation: invokeLater('$animateProvider', 'register'),
+ animation: invokeLaterAndSetModuleName('$animateProvider', 'register'),
/**
* @ngdoc method
* @name angular.Module#filter
* @module ng
- * @param {string} name Filter name.
+ * @param {string} name Filter name - this must be a valid angular expression identifier
* @param {Function} filterFactory Factory function for creating new instance of filter.
* @description
* See {@link ng.$filterProvider#register $filterProvider.register()}.
+ *
+ * <div class="alert alert-warning">
+ * **Note:** Filter names must be valid angular {@link expression} identifiers, such as `uppercase` or `orderBy`.
+ * Names with special characters, such as hyphens and dots, are not allowed. If you wish to namespace
+ * your filters, then you can use capitalization (`myappSubsectionFilterx`) or underscores
+ * (`myapp_subsection_filterx`).
+ * </div>
*/
- filter: invokeLater('$filterProvider', 'register'),
+ filter: invokeLaterAndSetModuleName('$filterProvider', 'register'),
/**
* @ngdoc method
@@ -1827,7 +2131,7 @@ function setupModuleLoader(window) {
* @description
* See {@link ng.$controllerProvider#register $controllerProvider.register()}.
*/
- controller: invokeLater('$controllerProvider', 'register'),
+ controller: invokeLaterAndSetModuleName('$controllerProvider', 'register'),
/**
* @ngdoc method
@@ -1840,7 +2144,7 @@ function setupModuleLoader(window) {
* @description
* See {@link ng.$compileProvider#directive $compileProvider.directive()}.
*/
- directive: invokeLater('$compileProvider', 'directive'),
+ directive: invokeLaterAndSetModuleName('$compileProvider', 'directive'),
/**
* @ngdoc method
@@ -1851,7 +2155,7 @@ function setupModuleLoader(window) {
* @description
* Use this method to register work which needs to be performed on module loading.
* For more about how to configure services, see
- * {@link providers#providers_provider-recipe Provider Recipe}.
+ * {@link providers#provider-recipe Provider Recipe}.
*/
config: config,
@@ -1875,7 +2179,7 @@ function setupModuleLoader(window) {
config(configFn);
}
- return moduleInstance;
+ return moduleInstance;
/**
* @param {string} provider
@@ -1883,9 +2187,23 @@ function setupModuleLoader(window) {
* @param {String=} insertMethod
* @returns {angular.Module}
*/
- function invokeLater(provider, method, insertMethod) {
+ function invokeLater(provider, method, insertMethod, queue) {
+ if (!queue) queue = invokeQueue;
return function() {
- invokeQueue[insertMethod || 'push']([provider, method, arguments]);
+ queue[insertMethod || 'push']([provider, method, arguments]);
+ return moduleInstance;
+ };
+ }
+
+ /**
+ * @param {string} provider
+ * @param {string} method
+ * @returns {angular.Module}
+ */
+ function invokeLaterAndSetModuleName(provider, method) {
+ return function(recipeName, factoryFunction) {
+ if (factoryFunction && isFunction(factoryFunction)) factoryFunction.$$moduleName = name;
+ invokeQueue.push([provider, method, arguments]);
return moduleInstance;
};
}
@@ -1895,80 +2213,124 @@ function setupModuleLoader(window) {
}
+/* global: toDebugString: true */
+
+function serializeObject(obj) {
+ var seen = [];
+
+ return JSON.stringify(obj, function(key, val) {
+ val = toJsonReplacer(key, val);
+ if (isObject(val)) {
+
+ if (seen.indexOf(val) >= 0) return '<<already seen>>';
+
+ seen.push(val);
+ }
+ return val;
+ });
+}
+
+function toDebugString(obj) {
+ if (typeof obj === 'function') {
+ return obj.toString().replace(/ \{[\s\S]*$/, '');
+ } else if (typeof obj === 'undefined') {
+ return 'undefined';
+ } else if (typeof obj !== 'string') {
+ return serializeObject(obj);
+ }
+ return obj;
+}
+
/* global angularModule: true,
version: true,
$LocaleProvider,
$CompileProvider,
- htmlAnchorDirective,
- inputDirective,
- inputDirective,
- formDirective,
- scriptDirective,
- selectDirective,
- styleDirective,
- optionDirective,
- ngBindDirective,
- ngBindHtmlDirective,
- ngBindTemplateDirective,
- ngClassDirective,
- ngClassEvenDirective,
- ngClassOddDirective,
- ngCspDirective,
- ngCloakDirective,
- ngControllerDirective,
- ngFormDirective,
- ngHideDirective,
- ngIfDirective,
- ngIncludeDirective,
- ngIncludeFillContentDirective,
- ngInitDirective,
- ngNonBindableDirective,
- ngPluralizeDirective,
- ngRepeatDirective,
- ngShowDirective,
- ngStyleDirective,
- ngSwitchDirective,
- ngSwitchWhenDirective,
- ngSwitchDefaultDirective,
- ngOptionsDirective,
- ngTranscludeDirective,
- ngModelDirective,
- ngListDirective,
- ngChangeDirective,
- requiredDirective,
- requiredDirective,
- ngValueDirective,
- ngAttributeAliasDirectives,
- ngEventDirectives,
-
- $AnchorScrollProvider,
- $AnimateProvider,
- $BrowserProvider,
- $CacheFactoryProvider,
- $ControllerProvider,
- $DocumentProvider,
- $ExceptionHandlerProvider,
- $FilterProvider,
- $InterpolateProvider,
- $IntervalProvider,
- $HttpProvider,
- $HttpBackendProvider,
- $LocationProvider,
- $LogProvider,
- $ParseProvider,
- $RootScopeProvider,
- $QProvider,
- $$SanitizeUriProvider,
- $SceProvider,
- $SceDelegateProvider,
- $SnifferProvider,
- $TemplateCacheProvider,
- $TimeoutProvider,
- $$RAFProvider,
- $$AsyncCallbackProvider,
- $WindowProvider
+ htmlAnchorDirective,
+ inputDirective,
+ inputDirective,
+ formDirective,
+ scriptDirective,
+ selectDirective,
+ styleDirective,
+ optionDirective,
+ ngBindDirective,
+ ngBindHtmlDirective,
+ ngBindTemplateDirective,
+ ngClassDirective,
+ ngClassEvenDirective,
+ ngClassOddDirective,
+ ngCspDirective,
+ ngCloakDirective,
+ ngControllerDirective,
+ ngFormDirective,
+ ngHideDirective,
+ ngIfDirective,
+ ngIncludeDirective,
+ ngIncludeFillContentDirective,
+ ngInitDirective,
+ ngNonBindableDirective,
+ ngPluralizeDirective,
+ ngRepeatDirective,
+ ngShowDirective,
+ ngStyleDirective,
+ ngSwitchDirective,
+ ngSwitchWhenDirective,
+ ngSwitchDefaultDirective,
+ ngOptionsDirective,
+ ngTranscludeDirective,
+ ngModelDirective,
+ ngListDirective,
+ ngChangeDirective,
+ patternDirective,
+ patternDirective,
+ requiredDirective,
+ requiredDirective,
+ minlengthDirective,
+ minlengthDirective,
+ maxlengthDirective,
+ maxlengthDirective,
+ ngValueDirective,
+ ngModelOptionsDirective,
+ ngAttributeAliasDirectives,
+ ngEventDirectives,
+
+ $AnchorScrollProvider,
+ $AnimateProvider,
+ $$CoreAnimateQueueProvider,
+ $$CoreAnimateRunnerProvider,
+ $BrowserProvider,
+ $CacheFactoryProvider,
+ $ControllerProvider,
+ $DocumentProvider,
+ $ExceptionHandlerProvider,
+ $FilterProvider,
+ $InterpolateProvider,
+ $IntervalProvider,
+ $$HashMapProvider,
+ $HttpProvider,
+ $HttpParamSerializerProvider,
+ $HttpParamSerializerJQLikeProvider,
+ $HttpBackendProvider,
+ $LocationProvider,
+ $LogProvider,
+ $ParseProvider,
+ $RootScopeProvider,
+ $QProvider,
+ $$QProvider,
+ $$SanitizeUriProvider,
+ $SceProvider,
+ $SceDelegateProvider,
+ $SnifferProvider,
+ $TemplateCacheProvider,
+ $TemplateRequestProvider,
+ $$TestabilityProvider,
+ $TimeoutProvider,
+ $$RAFProvider,
+ $WindowProvider,
+ $$jqLiteProvider,
+ $$CookieReaderProvider
*/
@@ -1987,19 +2349,20 @@ function setupModuleLoader(window) {
* - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
*/
var version = {
- full: '1.2.28', // all of these placeholder strings will be replaced by grunt's
+ full: '1.4.3', // all of these placeholder strings will be replaced by grunt's
major: 1, // package task
- minor: 2,
- dot: 28,
- codeName: 'finnish-disembarkation'
+ minor: 4,
+ dot: 3,
+ codeName: 'foam-acceleration'
};
-function publishExternalAPI(angular){
+function publishExternalAPI(angular) {
extend(angular, {
'bootstrap': bootstrap,
'copy': copy,
'extend': extend,
+ 'merge': merge,
'equals': equals,
'element': jqLite,
'forEach': forEach,
@@ -2022,8 +2385,10 @@ function publishExternalAPI(angular){
'lowercase': lowercase,
'uppercase': uppercase,
'callbacks': {counter: 0},
+ 'getTestability': getTestability,
'$$minErr': minErr,
- '$$csp': csp
+ '$$csp': csp,
+ 'reloadWithDebugInfo': reloadWithDebugInfo
});
angularModule = setupModuleLoader(window);
@@ -2075,9 +2440,16 @@ function publishExternalAPI(angular){
ngModel: ngModelDirective,
ngList: ngListDirective,
ngChange: ngChangeDirective,
+ pattern: patternDirective,
+ ngPattern: patternDirective,
required: requiredDirective,
ngRequired: requiredDirective,
- ngValue: ngValueDirective
+ minlength: minlengthDirective,
+ ngMinlength: minlengthDirective,
+ maxlength: maxlengthDirective,
+ ngMaxlength: maxlengthDirective,
+ ngValue: ngValueDirective,
+ ngModelOptions: ngModelOptionsDirective
}).
directive({
ngInclude: ngIncludeFillContentDirective
@@ -2087,6 +2459,8 @@ function publishExternalAPI(angular){
$provide.provider({
$anchorScroll: $AnchorScrollProvider,
$animate: $AnimateProvider,
+ $$animateQueue: $$CoreAnimateQueueProvider,
+ $$AnimateRunner: $$CoreAnimateRunnerProvider,
$browser: $BrowserProvider,
$cacheFactory: $CacheFactoryProvider,
$controller: $ControllerProvider,
@@ -2096,29 +2470,48 @@ function publishExternalAPI(angular){
$interpolate: $InterpolateProvider,
$interval: $IntervalProvider,
$http: $HttpProvider,
+ $httpParamSerializer: $HttpParamSerializerProvider,
+ $httpParamSerializerJQLike: $HttpParamSerializerJQLikeProvider,
$httpBackend: $HttpBackendProvider,
$location: $LocationProvider,
$log: $LogProvider,
$parse: $ParseProvider,
$rootScope: $RootScopeProvider,
$q: $QProvider,
+ $$q: $$QProvider,
$sce: $SceProvider,
$sceDelegate: $SceDelegateProvider,
$sniffer: $SnifferProvider,
$templateCache: $TemplateCacheProvider,
+ $templateRequest: $TemplateRequestProvider,
+ $$testability: $$TestabilityProvider,
$timeout: $TimeoutProvider,
$window: $WindowProvider,
$$rAF: $$RAFProvider,
- $$asyncCallback : $$AsyncCallbackProvider
+ $$jqLite: $$jqLiteProvider,
+ $$HashMap: $$HashMapProvider,
+ $$cookieReader: $$CookieReaderProvider
});
}
]);
}
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Any commits to this file should be reviewed with security in mind. *
+ * Changes to this file can potentially create security vulnerabilities. *
+ * An approval from 2 Core members with history of modifying *
+ * this file is required. *
+ * *
+ * Does the change somehow allow for arbitrary javascript to be executed? *
+ * Or allows for someone to change the prototype of built-in objects? *
+ * Or gives undesired access to variables likes document or window? *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
/* global JQLitePrototype: true,
addEventListenerFn: true,
removeEventListenerFn: true,
- BOOLEAN_ATTR: true
+ BOOLEAN_ATTR: true,
+ ALIASED_ATTR: true,
*/
//////////////////////////////////
@@ -2142,7 +2535,7 @@ function publishExternalAPI(angular){
* Angular to manipulate the DOM in a cross-browser compatible way. **jqLite** implements only the most
* commonly needed functionality with the goal of having a very small footprint.</div>
*
- * To use jQuery, simply load it before `DOMContentLoaded` event fired.
+ * To use `jQuery`, simply ensure it is loaded before the `angular.js` file.
*
* <div class="alert">**Note:** all element references in Angular are always wrapped with jQuery or
* jqLite; they are never raw DOM references.</div>
@@ -2153,13 +2546,14 @@ function publishExternalAPI(angular){
* - [`addClass()`](http://api.jquery.com/addClass/)
* - [`after()`](http://api.jquery.com/after/)
* - [`append()`](http://api.jquery.com/append/)
- * - [`attr()`](http://api.jquery.com/attr/)
+ * - [`attr()`](http://api.jquery.com/attr/) - Does not support functions as parameters
* - [`bind()`](http://api.jquery.com/bind/) - Does not support namespaces, selectors or eventData
* - [`children()`](http://api.jquery.com/children/) - Does not support selectors
* - [`clone()`](http://api.jquery.com/clone/)
* - [`contents()`](http://api.jquery.com/contents/)
- * - [`css()`](http://api.jquery.com/css/) - Only retrieves inline-styles, does not call `getComputedStyles()`
+ * - [`css()`](http://api.jquery.com/css/) - Only retrieves inline-styles, does not call `getComputedStyle()`. As a setter, does not convert numbers to strings or append 'px'.
* - [`data()`](http://api.jquery.com/data/)
+ * - [`detach()`](http://api.jquery.com/detach/)
* - [`empty()`](http://api.jquery.com/empty/)
* - [`eq()`](http://api.jquery.com/eq/)
* - [`find()`](http://api.jquery.com/find/) - Limited to lookups by tag name
@@ -2200,10 +2594,12 @@ function publishExternalAPI(angular){
* `'ngModel'`).
* - `injector()` - retrieves the injector of the current element or its parent.
* - `scope()` - retrieves the {@link ng.$rootScope.Scope scope} of the current
- * element or its parent.
+ * element or its parent. Requires {@link guide/production#disabling-debug-data Debug Data} to
+ * be enabled.
* - `isolateScope()` - retrieves an isolate {@link ng.$rootScope.Scope scope} if one is attached directly to the
* current element. This getter should be used only on elements that contain a directive which starts a new isolate
* scope. Calling `scope()` on this element always returns the original non-isolate scope.
+ * Requires {@link guide/production#disabling-debug-data Debug Data} to be enabled.
* - `inheritedData()` - same as `data()`, but walks up the DOM until a value is found or the top
* parent element is reached.
*
@@ -2215,17 +2611,17 @@ JQLite.expando = 'ng339';
var jqCache = JQLite.cache = {},
jqId = 1,
- addEventListenerFn = (window.document.addEventListener
- ? function(element, type, fn) {element.addEventListener(type, fn, false);}
- : function(element, type, fn) {element.attachEvent('on' + type, fn);}),
- removeEventListenerFn = (window.document.removeEventListener
- ? function(element, type, fn) {element.removeEventListener(type, fn, false); }
- : function(element, type, fn) {element.detachEvent('on' + type, fn); });
+ addEventListenerFn = function(element, type, fn) {
+ element.addEventListener(type, fn, false);
+ },
+ removeEventListenerFn = function(element, type, fn) {
+ element.removeEventListener(type, fn, false);
+ };
/*
* !!! This is an undocumented "private" function !!!
*/
-var jqData = JQLite._data = function(node) {
+JQLite._data = function(node) {
//jQuery always returns an object on cache miss
return this.cache[node[this.expando]] || {};
};
@@ -2235,6 +2631,7 @@ function jqNextId() { return ++jqId; }
var SPECIAL_CHARS_REGEXP = /([\:\-\_]+(.))/g;
var MOZ_HACK_REGEXP = /^moz([A-Z])/;
+var MOUSE_EVENT_MAP= { mouseleave: "mouseout", mouseenter: "mouseover"};
var jqLiteMinErr = minErr('jqLite');
/**
@@ -2250,49 +2647,6 @@ function camelCase(name) {
replace(MOZ_HACK_REGEXP, 'Moz$1');
}
-/////////////////////////////////////////////
-// jQuery mutation patch
-//
-// In conjunction with bindJQuery intercepts all jQuery's DOM destruction apis and fires a
-// $destroy event on all DOM nodes being removed.
-//
-/////////////////////////////////////////////
-
-function jqLitePatchJQueryRemove(name, dispatchThis, filterElems, getterIfNoArguments) {
- var originalJqFn = jQuery.fn[name];
- originalJqFn = originalJqFn.$original || originalJqFn;
- removePatch.$original = originalJqFn;
- jQuery.fn[name] = removePatch;
-
- function removePatch(param) {
- // jshint -W040
- var list = filterElems && param ? [this.filter(param)] : [this],
- fireEvent = dispatchThis,
- set, setIndex, setLength,
- element, childIndex, childLength, children;
-
- if (!getterIfNoArguments || param != null) {
- while(list.length) {
- set = list.shift();
- for(setIndex = 0, setLength = set.length; setIndex < setLength; setIndex++) {
- element = jqLite(set[setIndex]);
- if (fireEvent) {
- element.triggerHandler('$destroy');
- } else {
- fireEvent = !fireEvent;
- }
- for(childIndex = 0, childLength = (children = element.children()).length;
- childIndex < childLength;
- childIndex++) {
- list.push(jQuery(children[childIndex]));
- }
- }
- }
- }
- return originalJqFn.apply(this, arguments);
- }
-}
-
var SINGLE_TAG_REGEXP = /^<(\w+)\s*\/?>(?:<\/\1>|)$/;
var HTML_REGEXP = /<|&#?\w+;/;
var TAG_NAME_REGEXP = /<([\w:]+)/;
@@ -2312,26 +2666,39 @@ wrapMap.optgroup = wrapMap.option;
wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
wrapMap.th = wrapMap.td;
+
function jqLiteIsTextNode(html) {
return !HTML_REGEXP.test(html);
}
+function jqLiteAcceptsData(node) {
+ // The window object can accept data but has no nodeType
+ // Otherwise we are only interested in elements (1) and documents (9)
+ var nodeType = node.nodeType;
+ return nodeType === NODE_TYPE_ELEMENT || !nodeType || nodeType === NODE_TYPE_DOCUMENT;
+}
+
+function jqLiteHasData(node) {
+ for (var key in jqCache[node.ng339]) {
+ return true;
+ }
+ return false;
+}
+
function jqLiteBuildFragment(html, context) {
- var elem, tmp, tag, wrap,
+ var tmp, tag, wrap,
fragment = context.createDocumentFragment(),
- nodes = [], i, j, jj;
+ nodes = [], i;
if (jqLiteIsTextNode(html)) {
// Convert non-html into a text node
nodes.push(context.createTextNode(html));
} else {
- tmp = fragment.appendChild(context.createElement('div'));
// Convert html into DOM nodes
+ tmp = tmp || fragment.appendChild(context.createElement("div"));
tag = (TAG_NAME_REGEXP.exec(html) || ["", ""])[1].toLowerCase();
wrap = wrapMap[tag] || wrapMap._default;
- tmp.innerHTML = '<div>&#160;</div>' +
- wrap[1] + html.replace(XHTML_TAG_REGEXP, "<$1></$2>") + wrap[2];
- tmp.removeChild(tmp.firstChild);
+ tmp.innerHTML = wrap[1] + html.replace(XHTML_TAG_REGEXP, "<$1></$2>") + wrap[2];
// Descend through wrappers to the right content
i = wrap[0];
@@ -2339,7 +2706,7 @@ function jqLiteBuildFragment(html, context) {
tmp = tmp.lastChild;
}
- for (j=0, jj=tmp.childNodes.length; j<jj; ++j) nodes.push(tmp.childNodes[j]);
+ nodes = concat(nodes, tmp.childNodes);
tmp = fragment.firstChild;
tmp.textContent = "";
@@ -2348,7 +2715,11 @@ function jqLiteBuildFragment(html, context) {
// Remove wrapper from fragment
fragment.textContent = "";
fragment.innerHTML = ""; // Clear inner HTML
- return nodes;
+ forEach(nodes, function(node) {
+ fragment.appendChild(node);
+ });
+
+ return fragment;
}
function jqLiteParseHTML(html, context) {
@@ -2359,7 +2730,11 @@ function jqLiteParseHTML(html, context) {
return [context.createElement(parsed[1])];
}
- return jqLiteBuildFragment(html, context);
+ if ((parsed = jqLiteBuildFragment(html, context))) {
+ return parsed.childNodes;
+ }
+
+ return [];
}
/////////////////////////////////////////////
@@ -2367,20 +2742,22 @@ function JQLite(element) {
if (element instanceof JQLite) {
return element;
}
+
+ var argIsString;
+
if (isString(element)) {
element = trim(element);
+ argIsString = true;
}
if (!(this instanceof JQLite)) {
- if (isString(element) && element.charAt(0) != '<') {
+ if (argIsString && element.charAt(0) != '<') {
throw jqLiteMinErr('nosel', 'Looking up elements via selectors is not supported by jqLite! See: http://docs.angularjs.org/api/angular.element');
}
return new JQLite(element);
}
- if (isString(element)) {
+ if (argIsString) {
jqLiteAddNodes(this, jqLiteParseHTML(element));
- var fragment = jqLite(document.createDocumentFragment());
- fragment.append(this);
} else {
jqLiteAddNodes(this, element);
}
@@ -2390,50 +2767,63 @@ function jqLiteClone(element) {
return element.cloneNode(true);
}
-function jqLiteDealoc(element){
- jqLiteRemoveData(element);
- for ( var i = 0, children = element.childNodes || []; i < children.length; i++) {
- jqLiteDealoc(children[i]);
+function jqLiteDealoc(element, onlyDescendants) {
+ if (!onlyDescendants) jqLiteRemoveData(element);
+
+ if (element.querySelectorAll) {
+ var descendants = element.querySelectorAll('*');
+ for (var i = 0, l = descendants.length; i < l; i++) {
+ jqLiteRemoveData(descendants[i]);
+ }
}
}
function jqLiteOff(element, type, fn, unsupported) {
if (isDefined(unsupported)) throw jqLiteMinErr('offargs', 'jqLite#off() does not support the `selector` argument');
- var events = jqLiteExpandoStore(element, 'events'),
- handle = jqLiteExpandoStore(element, 'handle');
+ var expandoStore = jqLiteExpandoStore(element);
+ var events = expandoStore && expandoStore.events;
+ var handle = expandoStore && expandoStore.handle;
if (!handle) return; //no listeners registered
- if (isUndefined(type)) {
- forEach(events, function(eventHandler, type) {
- removeEventListenerFn(element, type, eventHandler);
+ if (!type) {
+ for (type in events) {
+ if (type !== '$destroy') {
+ removeEventListenerFn(element, type, handle);
+ }
delete events[type];
- });
+ }
} else {
forEach(type.split(' '), function(type) {
- if (isUndefined(fn)) {
- removeEventListenerFn(element, type, events[type]);
- delete events[type];
- } else {
- arrayRemove(events[type] || [], fn);
+ if (isDefined(fn)) {
+ var listenerFns = events[type];
+ arrayRemove(listenerFns || [], fn);
+ if (listenerFns && listenerFns.length > 0) {
+ return;
+ }
}
+
+ removeEventListenerFn(element, type, handle);
+ delete events[type];
});
}
}
function jqLiteRemoveData(element, name) {
- var expandoId = element.ng339,
- expandoStore = jqCache[expandoId];
+ var expandoId = element.ng339;
+ var expandoStore = expandoId && jqCache[expandoId];
if (expandoStore) {
if (name) {
- delete jqCache[expandoId].data[name];
+ delete expandoStore.data[name];
return;
}
if (expandoStore.handle) {
- expandoStore.events.$destroy && expandoStore.handle({}, '$destroy');
+ if (expandoStore.events.$destroy) {
+ expandoStore.handle({}, '$destroy');
+ }
jqLiteOff(element);
}
delete jqCache[expandoId];
@@ -2441,43 +2831,42 @@ function jqLiteRemoveData(element, name) {
}
}
-function jqLiteExpandoStore(element, key, value) {
+
+function jqLiteExpandoStore(element, createIfNecessary) {
var expandoId = element.ng339,
- expandoStore = jqCache[expandoId || -1];
+ expandoStore = expandoId && jqCache[expandoId];
- if (isDefined(value)) {
- if (!expandoStore) {
- element.ng339 = expandoId = jqNextId();
- expandoStore = jqCache[expandoId] = {};
- }
- expandoStore[key] = value;
- } else {
- return expandoStore && expandoStore[key];
+ if (createIfNecessary && !expandoStore) {
+ element.ng339 = expandoId = jqNextId();
+ expandoStore = jqCache[expandoId] = {events: {}, data: {}, handle: undefined};
}
+
+ return expandoStore;
}
+
function jqLiteData(element, key, value) {
- var data = jqLiteExpandoStore(element, 'data'),
- isSetter = isDefined(value),
- keyDefined = !isSetter && isDefined(key),
- isSimpleGetter = keyDefined && !isObject(key);
+ if (jqLiteAcceptsData(element)) {
- if (!data && !isSimpleGetter) {
- jqLiteExpandoStore(element, 'data', data = {});
- }
+ var isSimpleSetter = isDefined(value);
+ var isSimpleGetter = !isSimpleSetter && key && !isObject(key);
+ var massGetter = !key;
+ var expandoStore = jqLiteExpandoStore(element, !isSimpleGetter);
+ var data = expandoStore && expandoStore.data;
- if (isSetter) {
- data[key] = value;
- } else {
- if (keyDefined) {
- if (isSimpleGetter) {
- // don't create data in this case.
- return data && data[key];
+ if (isSimpleSetter) { // data('key', value)
+ data[key] = value;
+ } else {
+ if (massGetter) { // data()
+ return data;
} else {
- extend(data, key);
+ if (isSimpleGetter) { // data('key')
+ // don't force creation of expandoStore if it doesn't exist yet
+ return data && data[key];
+ } else { // mass-setter: data({key1: val1, key2: val2})
+ extend(data, key);
+ }
}
- } else {
- return data;
}
}
}
@@ -2485,7 +2874,7 @@ function jqLiteData(element, key, value) {
function jqLiteHasClass(element, selector) {
if (!element.getAttribute) return false;
return ((" " + (element.getAttribute('class') || '') + " ").replace(/[\n\t]/g, " ").
- indexOf( " " + selector + " " ) > -1);
+ indexOf(" " + selector + " ") > -1);
}
function jqLiteRemoveClass(element, cssClasses) {
@@ -2516,25 +2905,41 @@ function jqLiteAddClass(element, cssClasses) {
}
}
+
function jqLiteAddNodes(root, elements) {
+ // THIS CODE IS VERY HOT. Don't make changes without benchmarking.
+
if (elements) {
- elements = (!elements.nodeName && isDefined(elements.length) && !isWindow(elements))
- ? elements
- : [ elements ];
- for(var i=0; i < elements.length; i++) {
- root.push(elements[i]);
+
+ // if a Node (the most common case)
+ if (elements.nodeType) {
+ root[root.length++] = elements;
+ } else {
+ var length = elements.length;
+
+ // if an Array or NodeList and not a Window
+ if (typeof length === 'number' && elements.window !== elements) {
+ if (length) {
+ for (var i = 0; i < length; i++) {
+ root[root.length++] = elements[i];
+ }
+ }
+ } else {
+ root[root.length++] = elements;
+ }
}
}
}
+
function jqLiteController(element, name) {
- return jqLiteInheritedData(element, '$' + (name || 'ngController' ) + 'Controller');
+ return jqLiteInheritedData(element, '$' + (name || 'ngController') + 'Controller');
}
function jqLiteInheritedData(element, name, value) {
// if element is the document object work with the html element instead
// this makes $(document).scope() possible
- if(element.nodeType == 9) {
+ if (element.nodeType == NODE_TYPE_DOCUMENT) {
element = element.documentElement;
}
var names = isArray(name) ? name : [name];
@@ -2547,19 +2952,37 @@ function jqLiteInheritedData(element, name, value) {
// If dealing with a document fragment node with a host element, and no parent, use the host
// element as the parent. This enables directives within a Shadow DOM or polyfilled Shadow DOM
// to lookup parent controllers.
- element = element.parentNode || (element.nodeType === 11 && element.host);
+ element = element.parentNode || (element.nodeType === NODE_TYPE_DOCUMENT_FRAGMENT && element.host);
}
}
function jqLiteEmpty(element) {
- for (var i = 0, childNodes = element.childNodes; i < childNodes.length; i++) {
- jqLiteDealoc(childNodes[i]);
- }
+ jqLiteDealoc(element, true);
while (element.firstChild) {
element.removeChild(element.firstChild);
}
}
+function jqLiteRemove(element, keepData) {
+ if (!keepData) jqLiteDealoc(element);
+ var parent = element.parentNode;
+ if (parent) parent.removeChild(element);
+}
+
+
+function jqLiteDocumentLoaded(action, win) {
+ win = win || window;
+ if (win.document.readyState === 'complete') {
+ // Force the action to be run async for consistent behaviour
+ // from the action's point of view
+ // i.e. it will definitely not be in a $apply
+ win.setTimeout(action);
+ } else {
+ // No need to unbind this handler as load is only ever called once
+ jqLite(win).on('load', action);
+ }
+}
+
//////////////////////////////////////////
// Functions which are declared directly.
//////////////////////////////////////////
@@ -2573,8 +2996,8 @@ var JQLitePrototype = JQLite.prototype = {
fn();
}
- // check if document already is loaded
- if (document.readyState === 'complete'){
+ // check if document is already loaded
+ if (document.readyState === 'complete') {
setTimeout(trigger);
} else {
this.on('DOMContentLoaded', trigger); // works for modern browsers and IE9
@@ -2586,7 +3009,7 @@ var JQLitePrototype = JQLite.prototype = {
},
toString: function() {
var value = [];
- forEach(this, function(e){ value.push('' + e);});
+ forEach(this, function(e) { value.push('' + e);});
return '[' + value.join(', ') + ']';
},
@@ -2611,20 +3034,33 @@ forEach('multiple,selected,checked,disabled,readOnly,required,open'.split(','),
});
var BOOLEAN_ELEMENTS = {};
forEach('input,select,option,textarea,button,form,details'.split(','), function(value) {
- BOOLEAN_ELEMENTS[uppercase(value)] = true;
+ BOOLEAN_ELEMENTS[value] = true;
});
+var ALIASED_ATTR = {
+ 'ngMinlength': 'minlength',
+ 'ngMaxlength': 'maxlength',
+ 'ngMin': 'min',
+ 'ngMax': 'max',
+ 'ngPattern': 'pattern'
+};
function getBooleanAttrName(element, name) {
// check dom last since we will most likely fail on name
var booleanAttr = BOOLEAN_ATTR[name.toLowerCase()];
// booleanAttr is here twice to minimize DOM access
- return booleanAttr && BOOLEAN_ELEMENTS[element.nodeName] && booleanAttr;
+ return booleanAttr && BOOLEAN_ELEMENTS[nodeName_(element)] && booleanAttr;
+}
+
+function getAliasedAttrName(element, name) {
+ var nodeName = element.nodeName;
+ return (nodeName === 'INPUT' || nodeName === 'TEXTAREA') && ALIASED_ATTR[name];
}
forEach({
data: jqLiteData,
- removeData: jqLiteRemoveData
+ removeData: jqLiteRemoveData,
+ hasData: jqLiteHasData
}, function(fn, name) {
JQLite[name] = fn;
});
@@ -2649,7 +3085,7 @@ forEach({
return jqLiteInheritedData(element, '$injector');
},
- removeAttr: function(element,name) {
+ removeAttr: function(element, name) {
element.removeAttribute(name);
},
@@ -2661,26 +3097,15 @@ forEach({
if (isDefined(value)) {
element.style[name] = value;
} else {
- var val;
-
- if (msie <= 8) {
- // this is some IE specific weirdness that jQuery 1.6.4 does not sure why
- val = element.currentStyle && element.currentStyle[name];
- if (val === '') val = 'auto';
- }
-
- val = val || element.style[name];
-
- if (msie <= 8) {
- // jquery weirdness :-/
- val = (val === '') ? undefined : val;
- }
-
- return val;
+ return element.style[name];
}
},
- attr: function(element, name, value){
+ attr: function(element, name, value) {
+ var nodeType = element.nodeType;
+ if (nodeType === NODE_TYPE_TEXT || nodeType === NODE_TYPE_ATTRIBUTE || nodeType === NODE_TYPE_COMMENT) {
+ return;
+ }
var lowercasedName = lowercase(name);
if (BOOLEAN_ATTR[lowercasedName]) {
if (isDefined(value)) {
@@ -2693,7 +3118,7 @@ forEach({
}
} else {
return (element[name] ||
- (element.attributes.getNamedItem(name)|| noop).specified)
+ (element.attributes.getNamedItem(name) || noop).specified)
? lowercasedName
: undefined;
}
@@ -2717,31 +3142,23 @@ forEach({
},
text: (function() {
- var NODE_TYPE_TEXT_PROPERTY = [];
- if (msie < 9) {
- NODE_TYPE_TEXT_PROPERTY[1] = 'innerText'; /** Element **/
- NODE_TYPE_TEXT_PROPERTY[3] = 'nodeValue'; /** Text **/
- } else {
- NODE_TYPE_TEXT_PROPERTY[1] = /** Element **/
- NODE_TYPE_TEXT_PROPERTY[3] = 'textContent'; /** Text **/
- }
getText.$dv = '';
return getText;
function getText(element, value) {
- var textProp = NODE_TYPE_TEXT_PROPERTY[element.nodeType];
if (isUndefined(value)) {
- return textProp ? element[textProp] : '';
+ var nodeType = element.nodeType;
+ return (nodeType === NODE_TYPE_ELEMENT || nodeType === NODE_TYPE_TEXT) ? element.textContent : '';
}
- element[textProp] = value;
+ element.textContent = value;
}
})(),
val: function(element, value) {
if (isUndefined(value)) {
- if (nodeName_(element) === 'SELECT' && element.multiple) {
+ if (element.multiple && nodeName_(element) === 'select') {
var result = [];
- forEach(element.options, function (option) {
+ forEach(element.options, function(option) {
if (option.selected) {
result.push(option.value || option.text);
}
@@ -2757,14 +3174,12 @@ forEach({
if (isUndefined(value)) {
return element.innerHTML;
}
- for (var i = 0, childNodes = element.childNodes; i < childNodes.length; i++) {
- jqLiteDealoc(childNodes[i]);
- }
+ jqLiteDealoc(element, true);
element.innerHTML = value;
},
empty: jqLiteEmpty
-}, function(fn, name){
+}, function(fn, name) {
/**
* Properties: writes return selection, reads return first value
*/
@@ -2816,57 +3231,50 @@ forEach({
});
function createEventHandler(element, events) {
- var eventHandler = function (event, type) {
- if (!event.preventDefault) {
- event.preventDefault = function() {
- event.returnValue = false; //ie
- };
- }
+ var eventHandler = function(event, type) {
+ // jQuery specific api
+ event.isDefaultPrevented = function() {
+ return event.defaultPrevented;
+ };
- if (!event.stopPropagation) {
- event.stopPropagation = function() {
- event.cancelBubble = true; //ie
- };
- }
+ var eventFns = events[type || event.type];
+ var eventFnsLength = eventFns ? eventFns.length : 0;
- if (!event.target) {
- event.target = event.srcElement || document;
- }
+ if (!eventFnsLength) return;
+
+ if (isUndefined(event.immediatePropagationStopped)) {
+ var originalStopImmediatePropagation = event.stopImmediatePropagation;
+ event.stopImmediatePropagation = function() {
+ event.immediatePropagationStopped = true;
+
+ if (event.stopPropagation) {
+ event.stopPropagation();
+ }
- if (isUndefined(event.defaultPrevented)) {
- var prevent = event.preventDefault;
- event.preventDefault = function() {
- event.defaultPrevented = true;
- prevent.call(event);
+ if (originalStopImmediatePropagation) {
+ originalStopImmediatePropagation.call(event);
+ }
};
- event.defaultPrevented = false;
}
- event.isDefaultPrevented = function() {
- return event.defaultPrevented || event.returnValue === false;
+ event.isImmediatePropagationStopped = function() {
+ return event.immediatePropagationStopped === true;
};
// Copy event handlers in case event handlers array is modified during execution.
- var eventHandlersCopy = shallowCopy(events[type || event.type] || []);
-
- forEach(eventHandlersCopy, function(fn) {
- fn.call(element, event);
- });
+ if ((eventFnsLength > 1)) {
+ eventFns = shallowCopy(eventFns);
+ }
- // Remove monkey-patched methods (IE),
- // as they would cause memory leaks in IE8.
- if (msie <= 8) {
- // IE7/8 does not allow to delete property on native object
- event.preventDefault = null;
- event.stopPropagation = null;
- event.isDefaultPrevented = null;
- } else {
- // It shouldn't affect normal browsers (native methods are defined on prototype).
- delete event.preventDefault;
- delete event.stopPropagation;
- delete event.isDefaultPrevented;
+ for (var i = 0; i < eventFnsLength; i++) {
+ if (!event.isImmediatePropagationStopped()) {
+ eventFns[i].call(element, event);
+ }
}
};
+
+ // TODO: this is a hack for angularMocks/clearDataCache that makes it possible to deregister all
+ // events on `element`
eventHandler.elem = element;
return eventHandler;
}
@@ -2879,68 +3287,56 @@ function createEventHandler(element, events) {
forEach({
removeData: jqLiteRemoveData,
- dealoc: jqLiteDealoc,
-
- on: function onFn(element, type, fn, unsupported){
+ on: function jqLiteOn(element, type, fn, unsupported) {
if (isDefined(unsupported)) throw jqLiteMinErr('onargs', 'jqLite#on() does not support the `selector` or `eventData` parameters');
- var events = jqLiteExpandoStore(element, 'events'),
- handle = jqLiteExpandoStore(element, 'handle');
+ // Do not add event handlers to non-elements because they will not be cleaned up.
+ if (!jqLiteAcceptsData(element)) {
+ return;
+ }
- if (!events) jqLiteExpandoStore(element, 'events', events = {});
- if (!handle) jqLiteExpandoStore(element, 'handle', handle = createEventHandler(element, events));
+ var expandoStore = jqLiteExpandoStore(element, true);
+ var events = expandoStore.events;
+ var handle = expandoStore.handle;
- forEach(type.split(' '), function(type){
+ if (!handle) {
+ handle = expandoStore.handle = createEventHandler(element, events);
+ }
+
+ // http://jsperf.com/string-indexof-vs-split
+ var types = type.indexOf(' ') >= 0 ? type.split(' ') : [type];
+ var i = types.length;
+
+ while (i--) {
+ type = types[i];
var eventFns = events[type];
if (!eventFns) {
- if (type == 'mouseenter' || type == 'mouseleave') {
- var contains = document.body.contains || document.body.compareDocumentPosition ?
- function( a, b ) {
- // jshint bitwise: false
- var adown = a.nodeType === 9 ? a.documentElement : a,
- bup = b && b.parentNode;
- return a === bup || !!( bup && bup.nodeType === 1 && (
- adown.contains ?
- adown.contains( bup ) :
- a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
- ));
- } :
- function( a, b ) {
- if ( b ) {
- while ( (b = b.parentNode) ) {
- if ( b === a ) {
- return true;
- }
- }
- }
- return false;
- };
-
- events[type] = [];
+ events[type] = [];
+ if (type === 'mouseenter' || type === 'mouseleave') {
// Refer to jQuery's implementation of mouseenter & mouseleave
// Read about mouseenter and mouseleave:
// http://www.quirksmode.org/js/events_mouse.html#link8
- var eventmap = { mouseleave : "mouseout", mouseenter : "mouseover"};
- onFn(element, eventmap[type], function(event) {
+ jqLiteOn(element, MOUSE_EVENT_MAP[type], function(event) {
var target = this, related = event.relatedTarget;
// For mousenter/leave call the handler if related is outside the target.
// NB: No relatedTarget if the mouse left/entered the browser window
- if ( !related || (related !== target && !contains(target, related)) ){
+ if (!related || (related !== target && !target.contains(related))) {
handle(event, type);
}
});
} else {
- addEventListenerFn(element, type, handle);
- events[type] = [];
+ if (type !== '$destroy') {
+ addEventListenerFn(element, type, handle);
+ }
}
eventFns = events[type];
}
eventFns.push(fn);
- });
+ }
},
off: jqLiteOff,
@@ -2961,7 +3357,7 @@ forEach({
replaceWith: function(element, replaceNode) {
var index, parent = element.parentNode;
jqLiteDealoc(element);
- forEach(new JQLite(replaceNode), function(node){
+ forEach(new JQLite(replaceNode), function(node) {
if (index) {
parent.insertBefore(node, index.nextSibling);
} else {
@@ -2973,9 +3369,10 @@ forEach({
children: function(element) {
var children = [];
- forEach(element.childNodes, function(element){
- if (element.nodeType === 1)
+ forEach(element.childNodes, function(element) {
+ if (element.nodeType === NODE_TYPE_ELEMENT) {
children.push(element);
+ }
});
return children;
},
@@ -2985,24 +3382,28 @@ forEach({
},
append: function(element, node) {
- forEach(new JQLite(node), function(child){
- if (element.nodeType === 1 || element.nodeType === 11) {
- element.appendChild(child);
- }
- });
+ var nodeType = element.nodeType;
+ if (nodeType !== NODE_TYPE_ELEMENT && nodeType !== NODE_TYPE_DOCUMENT_FRAGMENT) return;
+
+ node = new JQLite(node);
+
+ for (var i = 0, ii = node.length; i < ii; i++) {
+ var child = node[i];
+ element.appendChild(child);
+ }
},
prepend: function(element, node) {
- if (element.nodeType === 1) {
+ if (element.nodeType === NODE_TYPE_ELEMENT) {
var index = element.firstChild;
- forEach(new JQLite(node), function(child){
+ forEach(new JQLite(node), function(child) {
element.insertBefore(child, index);
});
}
},
wrap: function(element, wrapNode) {
- wrapNode = jqLite(wrapNode)[0];
+ wrapNode = jqLite(wrapNode).eq(0).clone()[0];
var parent = element.parentNode;
if (parent) {
parent.replaceChild(wrapNode, element);
@@ -3010,18 +3411,21 @@ forEach({
wrapNode.appendChild(element);
},
- remove: function(element) {
- jqLiteDealoc(element);
- var parent = element.parentNode;
- if (parent) parent.removeChild(element);
+ remove: jqLiteRemove,
+
+ detach: function(element) {
+ jqLiteRemove(element, true);
},
after: function(element, newElement) {
var index = element, parent = element.parentNode;
- forEach(new JQLite(newElement), function(node){
+ newElement = new JQLite(newElement);
+
+ for (var i = 0, ii = newElement.length; i < ii; i++) {
+ var node = newElement[i];
parent.insertBefore(node, index.nextSibling);
index = node;
- });
+ }
},
addClass: jqLiteAddClass,
@@ -3029,7 +3433,7 @@ forEach({
toggleClass: function(element, selector, condition) {
if (selector) {
- forEach(selector.split(' '), function(className){
+ forEach(selector.split(' '), function(className) {
var classCondition = condition;
if (isUndefined(classCondition)) {
classCondition = !jqLiteHasClass(element, className);
@@ -3041,20 +3445,11 @@ forEach({
parent: function(element) {
var parent = element.parentNode;
- return parent && parent.nodeType !== 11 ? parent : null;
+ return parent && parent.nodeType !== NODE_TYPE_DOCUMENT_FRAGMENT ? parent : null;
},
next: function(element) {
- if (element.nextElementSibling) {
- return element.nextElementSibling;
- }
-
- // IE8 doesn't have nextElementSibling
- var elm = element.nextSibling;
- while (elm != null && elm.nodeType !== 1) {
- elm = elm.nextSibling;
- }
- return elm;
+ return element.nextElementSibling;
},
find: function(element, selector) {
@@ -3071,14 +3466,17 @@ forEach({
var dummyEvent, eventFnsCopy, handlerArgs;
var eventName = event.type || event;
- var eventFns = (jqLiteExpandoStore(element, 'events') || {})[eventName];
+ var expandoStore = jqLiteExpandoStore(element);
+ var events = expandoStore && expandoStore.events;
+ var eventFns = events && events[eventName];
if (eventFns) {
-
// Create a dummy event to pass to the handlers
dummyEvent = {
preventDefault: function() { this.defaultPrevented = true; },
isDefaultPrevented: function() { return this.defaultPrevented === true; },
+ stopImmediatePropagation: function() { this.immediatePropagationStopped = true; },
+ isImmediatePropagationStopped: function() { return this.immediatePropagationStopped === true; },
stopPropagation: noop,
type: eventName,
target: element
@@ -3094,18 +3492,20 @@ forEach({
handlerArgs = extraParameters ? [dummyEvent].concat(extraParameters) : [dummyEvent];
forEach(eventFnsCopy, function(fn) {
- fn.apply(element, handlerArgs);
+ if (!dummyEvent.isImmediatePropagationStopped()) {
+ fn.apply(element, handlerArgs);
+ }
});
-
}
}
-}, function(fn, name){
+}, function(fn, name) {
/**
* chaining functions
*/
JQLite.prototype[name] = function(arg1, arg2, arg3) {
var value;
- for(var i=0; i < this.length; i++) {
+
+ for (var i = 0, ii = this.length; i < ii; i++) {
if (isUndefined(value)) {
value = fn(this[i], arg1, arg2, arg3);
if (isDefined(value)) {
@@ -3124,6 +3524,27 @@ forEach({
JQLite.prototype.unbind = JQLite.prototype.off;
});
+
+// Provider for private $$jqLite service
+function $$jqLiteProvider() {
+ this.$get = function $$jqLite() {
+ return extend(JQLite, {
+ hasClass: function(node, classes) {
+ if (node.attr) node = node[0];
+ return jqLiteHasClass(node, classes);
+ },
+ addClass: function(node, classes) {
+ if (node.attr) node = node[0];
+ return jqLiteAddClass(node, classes);
+ },
+ removeClass: function(node, classes) {
+ if (node.attr) node = node[0];
+ return jqLiteRemoveClass(node, classes);
+ }
+ });
+ };
+}
+
/**
* Computes a hash of an 'obj'.
* Hash of a:
@@ -3137,21 +3558,23 @@ forEach({
* The resulting string key is in 'type:hashKey' format.
*/
function hashKey(obj, nextUidFn) {
- var objType = typeof obj,
- key;
+ var key = obj && obj.$$hashKey;
- if (objType == 'function' || (objType == 'object' && obj !== null)) {
- if (typeof (key = obj.$$hashKey) == 'function') {
- // must invoke on object to keep the right this
+ if (key) {
+ if (typeof key === 'function') {
key = obj.$$hashKey();
- } else if (key === undefined) {
- key = obj.$$hashKey = (nextUidFn || nextUid)();
}
+ return key;
+ }
+
+ var objType = typeof obj;
+ if (objType == 'function' || (objType == 'object' && obj !== null)) {
+ key = obj.$$hashKey = objType + ':' + (nextUidFn || nextUid)();
} else {
- key = obj;
+ key = objType + ':' + obj;
}
- return objType + ':' + key;
+ return key;
}
/**
@@ -3195,6 +3618,12 @@ HashMap.prototype = {
}
};
+var $$HashMapProvider = [function() {
+ this.$get = [function() {
+ return HashMap;
+ }];
+}];
+
/**
* @ngdoc function
* @module ng
@@ -3205,9 +3634,10 @@ HashMap.prototype = {
* Creates an injector object that can be used for retrieving services as well as for
* dependency injection (see {@link guide/di dependency injection}).
*
-
* @param {Array.<string|Function>} modules A list of module functions or their aliases. See
- * {@link angular.module}. The `ng` module must be explicitly added.
+ * {@link angular.module}. The `ng` module must be explicitly added.
+ * @param {boolean=} [strictDi=false] Whether the injector should be in strict mode, which
+ * disallows argument name annotation inference.
* @returns {injector} Injector object. See {@link auto.$injector $injector}.
*
* @example
@@ -3218,7 +3648,7 @@ HashMap.prototype = {
*
* // use the injector to kick off your application
* // use the type inference to auto inject arguments, or use implicit injection
- * $injector.invoke(function($rootScope, $compile, $document){
+ * $injector.invoke(function($rootScope, $compile, $document) {
* $compile($document)($rootScope);
* $rootScope.$digest();
* });
@@ -3261,7 +3691,19 @@ var FN_ARG_SPLIT = /,/;
var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/;
var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
var $injectorMinErr = minErr('$injector');
-function annotate(fn) {
+
+function anonFn(fn) {
+ // For anonymous functions, showing at the very least the function signature can help in
+ // debugging.
+ var fnText = fn.toString().replace(STRIP_COMMENTS, ''),
+ args = fnText.match(FN_ARGS);
+ if (args) {
+ return 'function(' + (args[1] || '').replace(/[\s\r\n]+/, ' ') + ')';
+ }
+ return 'fn';
+}
+
+function annotate(fn, strictDi, name) {
var $inject,
fnText,
argDecl,
@@ -3271,10 +3713,17 @@ function annotate(fn) {
if (!($inject = fn.$inject)) {
$inject = [];
if (fn.length) {
+ if (strictDi) {
+ if (!isString(name) || !name) {
+ name = fn.name || anonFn(fn);
+ }
+ throw $injectorMinErr('strictdi',
+ '{0} is not using explicit annotation and cannot be invoked in strict mode', name);
+ }
fnText = fn.toString().replace(STRIP_COMMENTS, '');
argDecl = fnText.match(FN_ARGS);
- forEach(argDecl[1].split(FN_ARG_SPLIT), function(arg){
- arg.replace(FN_ARG, function(all, underscore, name){
+ forEach(argDecl[1].split(FN_ARG_SPLIT), function(arg) {
+ arg.replace(FN_ARG, function(all, underscore, name) {
$inject.push(name);
});
});
@@ -3308,7 +3757,7 @@ function annotate(fn) {
* ```js
* var $injector = angular.injector();
* expect($injector.get('$injector')).toBe($injector);
- * expect($injector.invoke(function($injector){
+ * expect($injector.invoke(function($injector) {
* return $injector;
* })).toBe($injector);
* ```
@@ -3334,8 +3783,10 @@ function annotate(fn) {
* ## Inference
*
* In JavaScript calling `toString()` on a function returns the function definition. The definition
- * can then be parsed and the function arguments can be extracted. *NOTE:* This does not work with
- * minification, and obfuscation tools since these tools change the argument names.
+ * can then be parsed and the function arguments can be extracted. This method of discovering
+ * annotations is disallowed when the injector is in strict mode.
+ * *NOTE:* This does not work with minification, and obfuscation tools since these tools change the
+ * argument names.
*
* ## `$inject` Annotation
* By adding an `$inject` property onto a function the injection parameters can be specified.
@@ -3352,6 +3803,7 @@ function annotate(fn) {
* Return an instance of the service.
*
* @param {string} name The name of the instance to retrieve.
+ * @param {string=} caller An optional string to provide the origin of the function call for error messages.
* @return {*} The instance.
*/
@@ -3362,8 +3814,8 @@ function annotate(fn) {
* @description
* Invoke the method and supply the method arguments from the `$injector`.
*
- * @param {!Function} fn The function to invoke. Function parameters are injected according to the
- * {@link guide/di $inject Annotation} rules.
+ * @param {Function|Array.<string|Function>} fn The injectable function to invoke. Function parameters are
+ * injected according to the {@link guide/di $inject Annotation} rules.
* @param {Object=} self The `this` for the invoked method.
* @param {Object=} locals Optional object. If preset then any argument names are read from this
* object first, before the `$injector` is consulted.
@@ -3420,6 +3872,8 @@ function annotate(fn) {
* expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
* ```
*
+ * You can disallow this method by using strict injection mode.
+ *
* This method does not work with code minification / obfuscation. For this reason the following
* annotation strategies are supported.
*
@@ -3472,6 +3926,8 @@ function annotate(fn) {
* @param {Function|Array.<string|Function>} fn Function for which dependent service names need to
* be retrieved as described above.
*
+ * @param {boolean=} [strictDi=false] Disallow argument name annotation inference.
+ *
* @returns {Array.<string>} The names of the services which the function requires.
*/
@@ -3626,8 +4082,8 @@ function annotate(fn) {
* configure your service in a provider.
*
* @param {string} name The name of the instance.
- * @param {function()} $getFn The $getFn for the instance creation. Internally this is a short hand
- * for `$provide.provider(name, {$get: $getFn})`.
+ * @param {Function|Array.<string|Function>} $getFn The injectable $getFn for the instance creation.
+ * Internally this is a short hand for `$provide.provider(name, {$get: $getFn})`.
* @returns {Object} registered provider instance
*
* @example
@@ -3662,7 +4118,8 @@ function annotate(fn) {
* as a type/class.
*
* @param {string} name The name of the instance.
- * @param {Function} constructor A class (constructor function) that will be instantiated.
+ * @param {Function|Array.<string|Function>} constructor An injectable class (constructor function)
+ * that will be instantiated.
* @returns {Object} registered provider instance
*
* @example
@@ -3761,7 +4218,7 @@ function annotate(fn) {
* object which replaces or wraps and delegates to the original service.
*
* @param {string} name The name of the service to decorate.
- * @param {function()} decorator This function will be invoked when the service needs to be
+ * @param {Function|Array.<string|Function>} decorator This function will be invoked when the service needs to be
* instantiated and should return the decorated service instance. The function is called using
* the {@link auto.$injector#invoke injector.invoke} method and is therefore fully injectable.
* Local injection arguments:
@@ -3781,7 +4238,8 @@ function annotate(fn) {
*/
-function createInjector(modulesToLoad) {
+function createInjector(modulesToLoad, strictDi) {
+ strictDi = (strictDi === true);
var INSTANTIATING = {},
providerSuffix = 'Provider',
path = [],
@@ -3797,18 +4255,21 @@ function createInjector(modulesToLoad) {
}
},
providerInjector = (providerCache.$injector =
- createInternalInjector(providerCache, function() {
+ createInternalInjector(providerCache, function(serviceName, caller) {
+ if (angular.isString(caller)) {
+ path.push(caller);
+ }
throw $injectorMinErr('unpr', "Unknown provider: {0}", path.join(' <- '));
})),
instanceCache = {},
instanceInjector = (instanceCache.$injector =
- createInternalInjector(instanceCache, function(servicename) {
- var provider = providerInjector.get(servicename + providerSuffix);
- return instanceInjector.invoke(provider.$get, provider);
+ createInternalInjector(instanceCache, function(serviceName, caller) {
+ var provider = providerInjector.get(serviceName + providerSuffix, caller);
+ return instanceInjector.invoke(provider.$get, provider, undefined, serviceName);
}));
- forEach(loadModules(modulesToLoad), function(fn) { instanceInjector.invoke(fn || noop); });
+ forEach(loadModules(modulesToLoad), function(fn) { if (fn) instanceInjector.invoke(fn); });
return instanceInjector;
@@ -3837,7 +4298,21 @@ function createInjector(modulesToLoad) {
return providerCache[name + providerSuffix] = provider_;
}
- function factory(name, factoryFn) { return provider(name, { $get: factoryFn }); }
+ function enforceReturnValue(name, factory) {
+ return function enforcedReturnValue() {
+ var result = instanceInjector.invoke(factory, this);
+ if (isUndefined(result)) {
+ throw $injectorMinErr('undef', "Provider '{0}' must return a value from $get factory method.", name);
+ }
+ return result;
+ };
+ }
+
+ function factory(name, factoryFn, enforce) {
+ return provider(name, {
+ $get: enforce !== false ? enforceReturnValue(name, factoryFn) : factoryFn
+ });
+ }
function service(name, constructor) {
return factory(name, ['$injector', function($injector) {
@@ -3845,7 +4320,7 @@ function createInjector(modulesToLoad) {
}]);
}
- function value(name, val) { return factory(name, valueFn(val)); }
+ function value(name, val) { return factory(name, valueFn(val), false); }
function constant(name, value) {
assertNotHasOwnProperty(name, 'constant');
@@ -3866,23 +4341,28 @@ function createInjector(modulesToLoad) {
////////////////////////////////////
// Module Loading
////////////////////////////////////
- function loadModules(modulesToLoad){
- var runBlocks = [], moduleFn, invokeQueue, i, ii;
+ function loadModules(modulesToLoad) {
+ var runBlocks = [], moduleFn;
forEach(modulesToLoad, function(module) {
if (loadedModules.get(module)) return;
loadedModules.put(module, true);
+ function runInvokeQueue(queue) {
+ var i, ii;
+ for (i = 0, ii = queue.length; i < ii; i++) {
+ var invokeArgs = queue[i],
+ provider = providerInjector.get(invokeArgs[0]);
+
+ provider[invokeArgs[1]].apply(provider, invokeArgs[2]);
+ }
+ }
+
try {
if (isString(module)) {
moduleFn = angularModule(module);
runBlocks = runBlocks.concat(loadModules(moduleFn.requires)).concat(moduleFn._runBlocks);
-
- for(invokeQueue = moduleFn._invokeQueue, i = 0, ii = invokeQueue.length; i < ii; i++) {
- var invokeArgs = invokeQueue[i],
- provider = providerInjector.get(invokeArgs[0]);
-
- provider[invokeArgs[1]].apply(provider, invokeArgs[2]);
- }
+ runInvokeQueue(moduleFn._invokeQueue);
+ runInvokeQueue(moduleFn._configBlocks);
} else if (isFunction(module)) {
runBlocks.push(providerInjector.invoke(module));
} else if (isArray(module)) {
@@ -3915,7 +4395,7 @@ function createInjector(modulesToLoad) {
function createInternalInjector(cache, factory) {
- function getService(serviceName) {
+ function getService(serviceName, caller) {
if (cache.hasOwnProperty(serviceName)) {
if (cache[serviceName] === INSTANTIATING) {
throw $injectorMinErr('cdep', 'Circular dependency found: {0}',
@@ -3926,7 +4406,7 @@ function createInjector(modulesToLoad) {
try {
path.unshift(serviceName);
cache[serviceName] = INSTANTIATING;
- return cache[serviceName] = factory(serviceName);
+ return cache[serviceName] = factory(serviceName, caller);
} catch (err) {
if (cache[serviceName] === INSTANTIATING) {
delete cache[serviceName];
@@ -3938,13 +4418,18 @@ function createInjector(modulesToLoad) {
}
}
- function invoke(fn, self, locals){
+ function invoke(fn, self, locals, serviceName) {
+ if (typeof locals === 'string') {
+ serviceName = locals;
+ locals = null;
+ }
+
var args = [],
- $inject = annotate(fn),
+ $inject = createInjector.$$annotate(fn, strictDi, serviceName),
length, i,
key;
- for(i = 0, length = $inject.length; i < length; i++) {
+ for (i = 0, length = $inject.length; i < length; i++) {
key = $inject[i];
if (typeof key !== 'string') {
throw $injectorMinErr('itkn',
@@ -3953,7 +4438,7 @@ function createInjector(modulesToLoad) {
args.push(
locals && locals.hasOwnProperty(key)
? locals[key]
- : getService(key)
+ : getService(key, serviceName)
);
}
if (isArray(fn)) {
@@ -3965,15 +4450,12 @@ function createInjector(modulesToLoad) {
return fn.apply(self, args);
}
- function instantiate(Type, locals) {
- var Constructor = function() {},
- instance, returnedValue;
-
+ function instantiate(Type, locals, serviceName) {
// Check if Type is annotated and use just the given function at n-1 as parameter
// e.g. someModule.factory('greeter', ['$window', function(renamed$window) {}]);
- Constructor.prototype = (isArray(Type) ? Type[Type.length - 1] : Type).prototype;
- instance = new Constructor();
- returnedValue = invoke(Type, instance, locals);
+ // Object creation: http://jsperf.com/create-constructor/2
+ var instance = Object.create((isArray(Type) ? Type[Type.length - 1] : Type).prototype || null);
+ var returnedValue = invoke(Type, instance, locals, serviceName);
return isObject(returnedValue) || isFunction(returnedValue) ? returnedValue : instance;
}
@@ -3982,7 +4464,7 @@ function createInjector(modulesToLoad) {
invoke: invoke,
instantiate: instantiate,
get: getService,
- annotate: annotate,
+ annotate: createInjector.$$annotate,
has: function(name) {
return providerCache.hasOwnProperty(name + providerSuffix) || cache.hasOwnProperty(name);
}
@@ -3990,54 +4472,15 @@ function createInjector(modulesToLoad) {
}
}
+createInjector.$$annotate = annotate;
+
/**
- * @ngdoc service
- * @name $anchorScroll
- * @kind function
- * @requires $window
- * @requires $location
- * @requires $rootScope
+ * @ngdoc provider
+ * @name $anchorScrollProvider
*
* @description
- * When called, it checks current value of `$location.hash()` and scrolls to the related element,
- * according to rules specified in
- * [Html5 spec](http://dev.w3.org/html5/spec/Overview.html#the-indicated-part-of-the-document).
- *
- * It also watches the `$location.hash()` and scrolls whenever it changes to match any anchor.
- * This can be disabled by calling `$anchorScrollProvider.disableAutoScrolling()`.
- *
- * @example
- <example>
- <file name="index.html">
- <div id="scrollArea" ng-controller="ScrollCtrl">
- <a ng-click="gotoBottom()">Go to bottom</a>
- <a id="bottom"></a> You're at the bottom!
- </div>
- </file>
- <file name="script.js">
- function ScrollCtrl($scope, $location, $anchorScroll) {
- $scope.gotoBottom = function (){
- // set the location.hash to the id of
- // the element you wish to scroll to.
- $location.hash('bottom');
-
- // call $anchorScroll()
- $anchorScroll();
- };
- }
- </file>
- <file name="style.css">
- #scrollArea {
- height: 350px;
- overflow: auto;
- }
-
- #bottom {
- display: block;
- margin-top: 2000px;
- }
- </file>
- </example>
+ * Use `$anchorScrollProvider` to disable automatic scrolling whenever
+ * {@link ng.$location#hash $location.hash()} changes.
*/
function $AnchorScrollProvider() {
@@ -4060,43 +4503,241 @@ function $AnchorScrollProvider() {
autoScrollingEnabled = false;
};
+ /**
+ * @ngdoc service
+ * @name $anchorScroll
+ * @kind function
+ * @requires $window
+ * @requires $location
+ * @requires $rootScope
+ *
+ * @description
+ * When called, it scrolls to the element related to the specified `hash` or (if omitted) to the
+ * current value of {@link ng.$location#hash $location.hash()}, according to the rules specified
+ * in the
+ * [HTML5 spec](http://dev.w3.org/html5/spec/Overview.html#the-indicated-part-of-the-document).
+ *
+ * It also watches the {@link ng.$location#hash $location.hash()} and automatically scrolls to
+ * match any anchor whenever it changes. This can be disabled by calling
+ * {@link ng.$anchorScrollProvider#disableAutoScrolling $anchorScrollProvider.disableAutoScrolling()}.
+ *
+ * Additionally, you can use its {@link ng.$anchorScroll#yOffset yOffset} property to specify a
+ * vertical scroll-offset (either fixed or dynamic).
+ *
+ * @param {string=} hash The hash specifying the element to scroll to. If omitted, the value of
+ * {@link ng.$location#hash $location.hash()} will be used.
+ *
+ * @property {(number|function|jqLite)} yOffset
+ * If set, specifies a vertical scroll-offset. This is often useful when there are fixed
+ * positioned elements at the top of the page, such as navbars, headers etc.
+ *
+ * `yOffset` can be specified in various ways:
+ * - **number**: A fixed number of pixels to be used as offset.<br /><br />
+ * - **function**: A getter function called everytime `$anchorScroll()` is executed. Must return
+ * a number representing the offset (in pixels).<br /><br />
+ * - **jqLite**: A jqLite/jQuery element to be used for specifying the offset. The distance from
+ * the top of the page to the element's bottom will be used as offset.<br />
+ * **Note**: The element will be taken into account only as long as its `position` is set to
+ * `fixed`. This option is useful, when dealing with responsive navbars/headers that adjust
+ * their height and/or positioning according to the viewport's size.
+ *
+ * <br />
+ * <div class="alert alert-warning">
+ * In order for `yOffset` to work properly, scrolling should take place on the document's root and
+ * not some child element.
+ * </div>
+ *
+ * @example
+ <example module="anchorScrollExample">
+ <file name="index.html">
+ <div id="scrollArea" ng-controller="ScrollController">
+ <a ng-click="gotoBottom()">Go to bottom</a>
+ <a id="bottom"></a> You're at the bottom!
+ </div>
+ </file>
+ <file name="script.js">
+ angular.module('anchorScrollExample', [])
+ .controller('ScrollController', ['$scope', '$location', '$anchorScroll',
+ function ($scope, $location, $anchorScroll) {
+ $scope.gotoBottom = function() {
+ // set the location.hash to the id of
+ // the element you wish to scroll to.
+ $location.hash('bottom');
+
+ // call $anchorScroll()
+ $anchorScroll();
+ };
+ }]);
+ </file>
+ <file name="style.css">
+ #scrollArea {
+ height: 280px;
+ overflow: auto;
+ }
+
+ #bottom {
+ display: block;
+ margin-top: 2000px;
+ }
+ </file>
+ </example>
+ *
+ * <hr />
+ * The example below illustrates the use of a vertical scroll-offset (specified as a fixed value).
+ * See {@link ng.$anchorScroll#yOffset $anchorScroll.yOffset} for more details.
+ *
+ * @example
+ <example module="anchorScrollOffsetExample">
+ <file name="index.html">
+ <div class="fixed-header" ng-controller="headerCtrl">
+ <a href="" ng-click="gotoAnchor(x)" ng-repeat="x in [1,2,3,4,5]">
+ Go to anchor {{x}}
+ </a>
+ </div>
+ <div id="anchor{{x}}" class="anchor" ng-repeat="x in [1,2,3,4,5]">
+ Anchor {{x}} of 5
+ </div>
+ </file>
+ <file name="script.js">
+ angular.module('anchorScrollOffsetExample', [])
+ .run(['$anchorScroll', function($anchorScroll) {
+ $anchorScroll.yOffset = 50; // always scroll by 50 extra pixels
+ }])
+ .controller('headerCtrl', ['$anchorScroll', '$location', '$scope',
+ function ($anchorScroll, $location, $scope) {
+ $scope.gotoAnchor = function(x) {
+ var newHash = 'anchor' + x;
+ if ($location.hash() !== newHash) {
+ // set the $location.hash to `newHash` and
+ // $anchorScroll will automatically scroll to it
+ $location.hash('anchor' + x);
+ } else {
+ // call $anchorScroll() explicitly,
+ // since $location.hash hasn't changed
+ $anchorScroll();
+ }
+ };
+ }
+ ]);
+ </file>
+ <file name="style.css">
+ body {
+ padding-top: 50px;
+ }
+
+ .anchor {
+ border: 2px dashed DarkOrchid;
+ padding: 10px 10px 200px 10px;
+ }
+
+ .fixed-header {
+ background-color: rgba(0, 0, 0, 0.2);
+ height: 50px;
+ position: fixed;
+ top: 0; left: 0; right: 0;
+ }
+
+ .fixed-header > a {
+ display: inline-block;
+ margin: 5px 15px;
+ }
+ </file>
+ </example>
+ */
this.$get = ['$window', '$location', '$rootScope', function($window, $location, $rootScope) {
var document = $window.document;
- // helper function to get first anchor from a NodeList
- // can't use filter.filter, as it accepts only instances of Array
- // and IE can't convert NodeList to an array using [].slice
- // TODO(vojta): use filter if we change it to accept lists as well
+ // Helper function to get first anchor from a NodeList
+ // (using `Array#some()` instead of `angular#forEach()` since it's more performant
+ // and working in all supported browsers.)
function getFirstAnchor(list) {
var result = null;
- forEach(list, function(element) {
- if (!result && lowercase(element.nodeName) === 'a') result = element;
+ Array.prototype.some.call(list, function(element) {
+ if (nodeName_(element) === 'a') {
+ result = element;
+ return true;
+ }
});
return result;
}
- function scroll() {
- var hash = $location.hash(), elm;
+ function getYOffset() {
+
+ var offset = scroll.yOffset;
+
+ if (isFunction(offset)) {
+ offset = offset();
+ } else if (isElement(offset)) {
+ var elem = offset[0];
+ var style = $window.getComputedStyle(elem);
+ if (style.position !== 'fixed') {
+ offset = 0;
+ } else {
+ offset = elem.getBoundingClientRect().bottom;
+ }
+ } else if (!isNumber(offset)) {
+ offset = 0;
+ }
+
+ return offset;
+ }
+
+ function scrollTo(elem) {
+ if (elem) {
+ elem.scrollIntoView();
+
+ var offset = getYOffset();
+
+ if (offset) {
+ // `offset` is the number of pixels we should scroll UP in order to align `elem` properly.
+ // This is true ONLY if the call to `elem.scrollIntoView()` initially aligns `elem` at the
+ // top of the viewport.
+ //
+ // IF the number of pixels from the top of `elem` to the end of the page's content is less
+ // than the height of the viewport, then `elem.scrollIntoView()` will align the `elem` some
+ // way down the page.
+ //
+ // This is often the case for elements near the bottom of the page.
+ //
+ // In such cases we do not need to scroll the whole `offset` up, just the difference between
+ // the top of the element and the offset, which is enough to align the top of `elem` at the
+ // desired position.
+ var elemTop = elem.getBoundingClientRect().top;
+ $window.scrollBy(0, elemTop - offset);
+ }
+ } else {
+ $window.scrollTo(0, 0);
+ }
+ }
+
+ function scroll(hash) {
+ hash = isString(hash) ? hash : $location.hash();
+ var elm;
// empty hash, scroll to the top of the page
- if (!hash) $window.scrollTo(0, 0);
+ if (!hash) scrollTo(null);
// element with given id
- else if ((elm = document.getElementById(hash))) elm.scrollIntoView();
+ else if ((elm = document.getElementById(hash))) scrollTo(elm);
// first anchor with given name :-D
- else if ((elm = getFirstAnchor(document.getElementsByName(hash)))) elm.scrollIntoView();
+ else if ((elm = getFirstAnchor(document.getElementsByName(hash)))) scrollTo(elm);
// no element and hash == 'top', scroll to the top of the page
- else if (hash === 'top') $window.scrollTo(0, 0);
+ else if (hash === 'top') scrollTo(null);
}
// does not scroll when user clicks on anchor link that is currently on
// (no url change, no $location.hash() change), browser native does scroll
if (autoScrollingEnabled) {
$rootScope.$watch(function autoScrollWatch() {return $location.hash();},
- function autoScrollWatchAction() {
- $rootScope.$evalAsync(scroll);
+ function autoScrollWatchAction(newVal, oldVal) {
+ // skip the initial scroll if $location.hash is empty
+ if (newVal === oldVal && newVal === '') return;
+
+ jqLiteDocumentLoaded(function() {
+ $rootScope.$evalAsync(scroll);
+ });
});
}
@@ -4105,6 +4746,168 @@ function $AnchorScrollProvider() {
}
var $animateMinErr = minErr('$animate');
+var ELEMENT_NODE = 1;
+var NG_ANIMATE_CLASSNAME = 'ng-animate';
+
+function mergeClasses(a,b) {
+ if (!a && !b) return '';
+ if (!a) return b;
+ if (!b) return a;
+ if (isArray(a)) a = a.join(' ');
+ if (isArray(b)) b = b.join(' ');
+ return a + ' ' + b;
+}
+
+function extractElementNode(element) {
+ for (var i = 0; i < element.length; i++) {
+ var elm = element[i];
+ if (elm.nodeType === ELEMENT_NODE) {
+ return elm;
+ }
+ }
+}
+
+function splitClasses(classes) {
+ if (isString(classes)) {
+ classes = classes.split(' ');
+ }
+
+ // Use createMap() to prevent class assumptions involving property names in
+ // Object.prototype
+ var obj = createMap();
+ forEach(classes, function(klass) {
+ // sometimes the split leaves empty string values
+ // incase extra spaces were applied to the options
+ if (klass.length) {
+ obj[klass] = true;
+ }
+ });
+ return obj;
+}
+
+// if any other type of options value besides an Object value is
+// passed into the $animate.method() animation then this helper code
+// will be run which will ignore it. While this patch is not the
+// greatest solution to this, a lot of existing plugins depend on
+// $animate to either call the callback (< 1.2) or return a promise
+// that can be changed. This helper function ensures that the options
+// are wiped clean incase a callback function is provided.
+function prepareAnimateOptions(options) {
+ return isObject(options)
+ ? options
+ : {};
+}
+
+var $$CoreAnimateRunnerProvider = function() {
+ this.$get = ['$q', '$$rAF', function($q, $$rAF) {
+ function AnimateRunner() {}
+ AnimateRunner.all = noop;
+ AnimateRunner.chain = noop;
+ AnimateRunner.prototype = {
+ end: noop,
+ cancel: noop,
+ resume: noop,
+ pause: noop,
+ complete: noop,
+ then: function(pass, fail) {
+ return $q(function(resolve) {
+ $$rAF(function() {
+ resolve();
+ });
+ }).then(pass, fail);
+ }
+ };
+ return AnimateRunner;
+ }];
+};
+
+// this is prefixed with Core since it conflicts with
+// the animateQueueProvider defined in ngAnimate/animateQueue.js
+var $$CoreAnimateQueueProvider = function() {
+ var postDigestQueue = new HashMap();
+ var postDigestElements = [];
+
+ this.$get = ['$$AnimateRunner', '$rootScope',
+ function($$AnimateRunner, $rootScope) {
+ return {
+ enabled: noop,
+ on: noop,
+ off: noop,
+ pin: noop,
+
+ push: function(element, event, options, domOperation) {
+ domOperation && domOperation();
+
+ options = options || {};
+ options.from && element.css(options.from);
+ options.to && element.css(options.to);
+
+ if (options.addClass || options.removeClass) {
+ addRemoveClassesPostDigest(element, options.addClass, options.removeClass);
+ }
+
+ return new $$AnimateRunner(); // jshint ignore:line
+ }
+ };
+
+ function addRemoveClassesPostDigest(element, add, remove) {
+ var data = postDigestQueue.get(element);
+ var classVal;
+
+ if (!data) {
+ postDigestQueue.put(element, data = {});
+ postDigestElements.push(element);
+ }
+
+ if (add) {
+ forEach(add.split(' '), function(className) {
+ if (className) {
+ data[className] = true;
+ }
+ });
+ }
+
+ if (remove) {
+ forEach(remove.split(' '), function(className) {
+ if (className) {
+ data[className] = false;
+ }
+ });
+ }
+
+ if (postDigestElements.length > 1) return;
+
+ $rootScope.$$postDigest(function() {
+ forEach(postDigestElements, function(element) {
+ var data = postDigestQueue.get(element);
+ if (data) {
+ var existing = splitClasses(element.attr('class'));
+ var toAdd = '';
+ var toRemove = '';
+ forEach(data, function(status, className) {
+ var hasClass = !!existing[className];
+ if (status !== hasClass) {
+ if (status) {
+ toAdd += (toAdd.length ? ' ' : '') + className;
+ } else {
+ toRemove += (toRemove.length ? ' ' : '') + className;
+ }
+ }
+ });
+
+ forEach(element, function(elm) {
+ toAdd && jqLiteAddClass(elm, toAdd);
+ toRemove && jqLiteRemoveClass(elm, toRemove);
+ });
+ postDigestQueue.remove(element);
+ }
+ });
+
+ postDigestElements.length = 0;
+ });
+ }
+ }];
+};
/**
* @ngdoc provider
@@ -4112,20 +4915,18 @@ var $animateMinErr = minErr('$animate');
*
* @description
* Default implementation of $animate that doesn't perform any animations, instead just
- * synchronously performs DOM
- * updates and calls done() callbacks.
+ * synchronously performs DOM updates and resolves the returned runner promise.
*
- * In order to enable animations the ngAnimate module has to be loaded.
+ * In order to enable animations the `ngAnimate` module has to be loaded.
*
- * To see the functional implementation check out src/ngAnimate/animate.js
+ * To see the functional implementation check out `src/ngAnimate/animate.js`.
*/
var $AnimateProvider = ['$provide', function($provide) {
+ var provider = this;
+ this.$$registeredAnimations = Object.create(null);
- this.$$selectors = {};
-
-
- /**
+ /**
* @ngdoc method
* @name $animateProvider#register
*
@@ -4134,33 +4935,43 @@ var $AnimateProvider = ['$provide', function($provide) {
* animation object which contains callback functions for each event that is expected to be
* animated.
*
- * * `eventFn`: `function(Element, doneFunction)` The element to animate, the `doneFunction`
- * must be called once the element animation is complete. If a function is returned then the
- * animation service will use this function to cancel the animation whenever a cancel event is
- * triggered.
+ * * `eventFn`: `function(element, ... , doneFunction, options)`
+ * The element to animate, the `doneFunction` and the options fed into the animation. Depending
+ * on the type of animation additional arguments will be injected into the animation function. The
+ * list below explains the function signatures for the different animation methods:
+ *
+ * - setClass: function(element, addedClasses, removedClasses, doneFunction, options)
+ * - addClass: function(element, addedClasses, doneFunction, options)
+ * - removeClass: function(element, removedClasses, doneFunction, options)
+ * - enter, leave, move: function(element, doneFunction, options)
+ * - animate: function(element, fromStyles, toStyles, doneFunction, options)
*
+ * Make sure to trigger the `doneFunction` once the animation is fully complete.
*
* ```js
* return {
- * eventFn : function(element, done) {
- * //code to run the animation
- * //once complete, then run done()
- * return function cancellationFunction() {
- * //code to cancel the animation
- * }
- * }
- * }
+ * //enter, leave, move signature
+ * eventFn : function(element, done, options) {
+ * //code to run the animation
+ * //once complete, then run done()
+ * return function endFunction(wasCancelled) {
+ * //code to cancel the animation
+ * }
+ * }
+ * }
* ```
*
- * @param {string} name The name of the animation.
+ * @param {string} name The name of the animation (this is what the class-based CSS value will be compared to).
* @param {Function} factory The factory function that will be executed to return the animation
* object.
*/
this.register = function(name, factory) {
+ if (name && name.charAt(0) !== '.') {
+ throw $animateMinErr('notcsel', "Expecting class selector starting with '.' got '{0}'.", name);
+ }
+
var key = name + '-animation';
- if (name && name.charAt(0) != '.') throw $animateMinErr('notcsel',
- "Expecting class selector starting with '.' got '{0}'.", name);
- this.$$selectors[name.substr(1)] = key;
+ provider.$$registeredAnimations[name.substr(1)] = key;
$provide.factory(key, factory);
};
@@ -4171,86 +4982,203 @@ var $AnimateProvider = ['$provide', function($provide) {
* @description
* Sets and/or returns the CSS class regular expression that is checked when performing
* an animation. Upon bootstrap the classNameFilter value is not set at all and will
- * therefore enable $animate to attempt to perform an animation on any element.
- * When setting the classNameFilter value, animations will only be performed on elements
+ * therefore enable $animate to attempt to perform an animation on any element that is triggered.
+ * When setting the `classNameFilter` value, animations will only be performed on elements
* that successfully match the filter expression. This in turn can boost performance
* for low-powered devices as well as applications containing a lot of structural operations.
* @param {RegExp=} expression The className expression which will be checked against all animations
* @return {RegExp} The current CSS className expression value. If null then there is no expression value
*/
this.classNameFilter = function(expression) {
- if(arguments.length === 1) {
+ if (arguments.length === 1) {
this.$$classNameFilter = (expression instanceof RegExp) ? expression : null;
+ if (this.$$classNameFilter) {
+ var reservedRegex = new RegExp("(\\s+|\\/)" + NG_ANIMATE_CLASSNAME + "(\\s+|\\/)");
+ if (reservedRegex.test(this.$$classNameFilter.toString())) {
+ throw $animateMinErr('nongcls','$animateProvider.classNameFilter(regex) prohibits accepting a regex value which matches/contains the "{0}" CSS class.', NG_ANIMATE_CLASSNAME);
+
+ }
+ }
}
return this.$$classNameFilter;
};
- this.$get = ['$timeout', '$$asyncCallback', function($timeout, $$asyncCallback) {
-
- function async(fn) {
- fn && $$asyncCallback(fn);
+ this.$get = ['$$animateQueue', function($$animateQueue) {
+ function domInsert(element, parentElement, afterElement) {
+ // if for some reason the previous element was removed
+ // from the dom sometime before this code runs then let's
+ // just stick to using the parent element as the anchor
+ if (afterElement) {
+ var afterNode = extractElementNode(afterElement);
+ if (afterNode && !afterNode.parentNode && !afterNode.previousElementSibling) {
+ afterElement = null;
+ }
+ }
+ afterElement ? afterElement.after(element) : parentElement.prepend(element);
}
/**
- *
* @ngdoc service
* @name $animate
- * @description The $animate service provides rudimentary DOM manipulation functions to
- * insert, remove and move elements within the DOM, as well as adding and removing classes.
- * This service is the core service used by the ngAnimate $animator service which provides
- * high-level animation hooks for CSS and JavaScript.
+ * @description The $animate service exposes a series of DOM utility methods that provide support
+ * for animation hooks. The default behavior is the application of DOM operations, however,
+ * when an animation is detected (and animations are enabled), $animate will do the heavy lifting
+ * to ensure that animation runs with the triggered DOM operation.
+ *
+ * By default $animate doesn't trigger an animations. This is because the `ngAnimate` module isn't
+ * included and only when it is active then the animation hooks that `$animate` triggers will be
+ * functional. Once active then all structural `ng-` directives will trigger animations as they perform
+ * their DOM-related operations (enter, leave and move). Other directives such as `ngClass`,
+ * `ngShow`, `ngHide` and `ngMessages` also provide support for animations.
*
- * $animate is available in the AngularJS core, however, the ngAnimate module must be included
- * to enable full out animation support. Otherwise, $animate will only perform simple DOM
- * manipulation operations.
+ * It is recommended that the`$animate` service is always used when executing DOM-related procedures within directives.
*
- * To learn more about enabling animation support, click here to visit the {@link ngAnimate
- * ngAnimate module page} as well as the {@link ngAnimate.$animate ngAnimate $animate service
- * page}.
+ * To learn more about enabling animation support, click here to visit the
+ * {@link ngAnimate ngAnimate module page}.
*/
return {
+ // we don't call it directly since non-existant arguments may
+ // be interpreted as null within the sub enabled function
/**
*
* @ngdoc method
- * @name $animate#enter
+ * @name $animate#on
* @kind function
- * @description Inserts the element into the DOM either after the `after` element or within
- * the `parent` element. Once complete, the done() callback will be fired (if provided).
- * @param {DOMElement} element the element which will be inserted into the DOM
- * @param {DOMElement} parent the parent element which will append the element as
- * a child (if the after element is not present)
- * @param {DOMElement} after the sibling element which will append the element
- * after itself
- * @param {Function=} done callback function that will be called after the element has been
- * inserted into the DOM
+ * @description Sets up an event listener to fire whenever the animation event (enter, leave, move, etc...)
+ * has fired on the given element or among any of its children. Once the listener is fired, the provided callback
+ * is fired with the following params:
+ *
+ * ```js
+ * $animate.on('enter', container,
+ * function callback(element, phase) {
+ * // cool we detected an enter animation within the container
+ * }
+ * );
+ * ```
+ *
+ * @param {string} event the animation event that will be captured (e.g. enter, leave, move, addClass, removeClass, etc...)
+ * @param {DOMElement} container the container element that will capture each of the animation events that are fired on itself
+ * as well as among its children
+ * @param {Function} callback the callback function that will be fired when the listener is triggered
+ *
+ * The arguments present in the callback function are:
+ * * `element` - The captured DOM element that the animation was fired on.
+ * * `phase` - The phase of the animation. The two possible phases are **start** (when the animation starts) and **close** (when it ends).
*/
- enter : function(element, parent, after, done) {
- if (after) {
- after.after(element);
- } else {
- if (!parent || !parent[0]) {
- parent = after.parent();
- }
- parent.append(element);
- }
- async(done);
+ on: $$animateQueue.on,
+
+ /**
+ *
+ * @ngdoc method
+ * @name $animate#off
+ * @kind function
+ * @description Deregisters an event listener based on the event which has been associated with the provided element. This method
+ * can be used in three different ways depending on the arguments:
+ *
+ * ```js
+ * // remove all the animation event listeners listening for `enter`
+ * $animate.off('enter');
+ *
+ * // remove all the animation event listeners listening for `enter` on the given element and its children
+ * $animate.off('enter', container);
+ *
+ * // remove the event listener function provided by `listenerFn` that is set
+ * // to listen for `enter` on the given `element` as well as its children
+ * $animate.off('enter', container, callback);
+ * ```
+ *
+ * @param {string} event the animation event (e.g. enter, leave, move, addClass, removeClass, etc...)
+ * @param {DOMElement=} container the container element the event listener was placed on
+ * @param {Function=} callback the callback function that was registered as the listener
+ */
+ off: $$animateQueue.off,
+
+ /**
+ * @ngdoc method
+ * @name $animate#pin
+ * @kind function
+ * @description Associates the provided element with a host parent element to allow the element to be animated even if it exists
+ * outside of the DOM structure of the Angular application. By doing so, any animation triggered via `$animate` can be issued on the
+ * element despite being outside the realm of the application or within another application. Say for example if the application
+ * was bootstrapped on an element that is somewhere inside of the `<body>` tag, but we wanted to allow for an element to be situated
+ * as a direct child of `document.body`, then this can be achieved by pinning the element via `$animate.pin(element)`. Keep in mind
+ * that calling `$animate.pin(element, parentElement)` will not actually insert into the DOM anywhere; it will just create the association.
+ *
+ * Note that this feature is only active when the `ngAnimate` module is used.
+ *
+ * @param {DOMElement} element the external element that will be pinned
+ * @param {DOMElement} parentElement the host parent element that will be associated with the external element
+ */
+ pin: $$animateQueue.pin,
+
+ /**
+ *
+ * @ngdoc method
+ * @name $animate#enabled
+ * @kind function
+ * @description Used to get and set whether animations are enabled or not on the entire application or on an element and its children. This
+ * function can be called in four ways:
+ *
+ * ```js
+ * // returns true or false
+ * $animate.enabled();
+ *
+ * // changes the enabled state for all animations
+ * $animate.enabled(false);
+ * $animate.enabled(true);
+ *
+ * // returns true or false if animations are enabled for an element
+ * $animate.enabled(element);
+ *
+ * // changes the enabled state for an element and its children
+ * $animate.enabled(element, true);
+ * $animate.enabled(element, false);
+ * ```
+ *
+ * @param {DOMElement=} element the element that will be considered for checking/setting the enabled state
+ * @param {boolean=} enabled whether or not the animations will be enabled for the element
+ *
+ * @return {boolean} whether or not animations are enabled
+ */
+ enabled: $$animateQueue.enabled,
+
+ /**
+ * @ngdoc method
+ * @name $animate#cancel
+ * @kind function
+ * @description Cancels the provided animation.
+ *
+ * @param {Promise} animationPromise The animation promise that is returned when an animation is started.
+ */
+ cancel: function(runner) {
+ runner.end && runner.end();
},
/**
*
* @ngdoc method
- * @name $animate#leave
+ * @name $animate#enter
* @kind function
- * @description Removes the element from the DOM. Once complete, the done() callback will be
- * fired (if provided).
- * @param {DOMElement} element the element which will be removed from the DOM
- * @param {Function=} done callback function that will be called after the element has been
- * removed from the DOM
+ * @description Inserts the element into the DOM either after the `after` element (if provided) or
+ * as the first child within the `parent` element and then triggers an animation.
+ * A promise is returned that will be resolved during the next digest once the animation
+ * has completed.
+ *
+ * @param {DOMElement} element the element which will be inserted into the DOM
+ * @param {DOMElement} parent the parent element which will append the element as
+ * a child (so long as the after element is not present)
+ * @param {DOMElement=} after the sibling element after which the element will be appended
+ * @param {object=} options an optional collection of options/styles that will be applied to the element
+ *
+ * @return {Promise} the animation callback promise
*/
- leave : function(element, done) {
- element.remove();
- async(done);
+ enter: function(element, parent, after, options) {
+ parent = parent && jqLite(parent);
+ after = after && jqLite(after);
+ parent = parent || after.parent();
+ domInsert(element, parent, after);
+ return $$animateQueue.push(element, 'enter', prepareAnimateOptions(options));
},
/**
@@ -4258,99 +5186,155 @@ var $AnimateProvider = ['$provide', function($provide) {
* @ngdoc method
* @name $animate#move
* @kind function
- * @description Moves the position of the provided element within the DOM to be placed
- * either after the `after` element or inside of the `parent` element. Once complete, the
- * done() callback will be fired (if provided).
+ * @description Inserts (moves) the element into its new position in the DOM either after
+ * the `after` element (if provided) or as the first child within the `parent` element
+ * and then triggers an animation. A promise is returned that will be resolved
+ * during the next digest once the animation has completed.
*
- * @param {DOMElement} element the element which will be moved around within the
- * DOM
- * @param {DOMElement} parent the parent element where the element will be
- * inserted into (if the after element is not present)
- * @param {DOMElement} after the sibling element where the element will be
- * positioned next to
- * @param {Function=} done the callback function (if provided) that will be fired after the
- * element has been moved to its new position
+ * @param {DOMElement} element the element which will be moved into the new DOM position
+ * @param {DOMElement} parent the parent element which will append the element as
+ * a child (so long as the after element is not present)
+ * @param {DOMElement=} after the sibling element after which the element will be appended
+ * @param {object=} options an optional collection of options/styles that will be applied to the element
+ *
+ * @return {Promise} the animation callback promise
*/
- move : function(element, parent, after, done) {
- // Do not remove element before insert. Removing will cause data associated with the
- // element to be dropped. Insert will implicitly do the remove.
- this.enter(element, parent, after, done);
+ move: function(element, parent, after, options) {
+ parent = parent && jqLite(parent);
+ after = after && jqLite(after);
+ parent = parent || after.parent();
+ domInsert(element, parent, after);
+ return $$animateQueue.push(element, 'move', prepareAnimateOptions(options));
},
/**
- *
* @ngdoc method
- * @name $animate#addClass
+ * @name $animate#leave
* @kind function
- * @description Adds the provided className CSS class value to the provided element. Once
- * complete, the done() callback will be fired (if provided).
- * @param {DOMElement} element the element which will have the className value
- * added to it
- * @param {string} className the CSS class which will be added to the element
- * @param {Function=} done the callback function (if provided) that will be fired after the
- * className value has been added to the element
+ * @description Triggers an animation and then removes the element from the DOM.
+ * When the function is called a promise is returned that will be resolved during the next
+ * digest once the animation has completed.
+ *
+ * @param {DOMElement} element the element which will be removed from the DOM
+ * @param {object=} options an optional collection of options/styles that will be applied to the element
+ *
+ * @return {Promise} the animation callback promise
*/
- addClass : function(element, className, done) {
- className = isString(className) ?
- className :
- isArray(className) ? className.join(' ') : '';
- forEach(element, function (element) {
- jqLiteAddClass(element, className);
+ leave: function(element, options) {
+ return $$animateQueue.push(element, 'leave', prepareAnimateOptions(options), function() {
+ element.remove();
});
- async(done);
},
/**
+ * @ngdoc method
+ * @name $animate#addClass
+ * @kind function
*
+ * @description Triggers an addClass animation surrounding the addition of the provided CSS class(es). Upon
+ * execution, the addClass operation will only be handled after the next digest and it will not trigger an
+ * animation if element already contains the CSS class or if the class is removed at a later step.
+ * Note that class-based animations are treated differently compared to structural animations
+ * (like enter, move and leave) since the CSS classes may be added/removed at different points
+ * depending if CSS or JavaScript animations are used.
+ *
+ * @param {DOMElement} element the element which the CSS classes will be applied to
+ * @param {string} className the CSS class(es) that will be added (multiple classes are separated via spaces)
+ * @param {object=} options an optional collection of options/styles that will be applied to the element
+ *
+ * @return {Promise} the animation callback promise
+ */
+ addClass: function(element, className, options) {
+ options = prepareAnimateOptions(options);
+ options.addClass = mergeClasses(options.addclass, className);
+ return $$animateQueue.push(element, 'addClass', options);
+ },
+
+ /**
* @ngdoc method
* @name $animate#removeClass
* @kind function
- * @description Removes the provided className CSS class value from the provided element.
- * Once complete, the done() callback will be fired (if provided).
- * @param {DOMElement} element the element which will have the className value
- * removed from it
- * @param {string} className the CSS class which will be removed from the element
- * @param {Function=} done the callback function (if provided) that will be fired after the
- * className value has been removed from the element
+ *
+ * @description Triggers a removeClass animation surrounding the removal of the provided CSS class(es). Upon
+ * execution, the removeClass operation will only be handled after the next digest and it will not trigger an
+ * animation if element does not contain the CSS class or if the class is added at a later step.
+ * Note that class-based animations are treated differently compared to structural animations
+ * (like enter, move and leave) since the CSS classes may be added/removed at different points
+ * depending if CSS or JavaScript animations are used.
+ *
+ * @param {DOMElement} element the element which the CSS classes will be applied to
+ * @param {string} className the CSS class(es) that will be removed (multiple classes are separated via spaces)
+ * @param {object=} options an optional collection of options/styles that will be applied to the element
+ *
+ * @return {Promise} the animation callback promise
*/
- removeClass : function(element, className, done) {
- className = isString(className) ?
- className :
- isArray(className) ? className.join(' ') : '';
- forEach(element, function (element) {
- jqLiteRemoveClass(element, className);
- });
- async(done);
+ removeClass: function(element, className, options) {
+ options = prepareAnimateOptions(options);
+ options.removeClass = mergeClasses(options.removeClass, className);
+ return $$animateQueue.push(element, 'removeClass', options);
},
/**
- *
* @ngdoc method
* @name $animate#setClass
* @kind function
- * @description Adds and/or removes the given CSS classes to and from the element.
- * Once complete, the done() callback will be fired (if provided).
- * @param {DOMElement} element the element which will have its CSS classes changed
- * removed from it
- * @param {string} add the CSS classes which will be added to the element
- * @param {string} remove the CSS class which will be removed from the element
- * @param {Function=} done the callback function (if provided) that will be fired after the
- * CSS classes have been set on the element
+ *
+ * @description Performs both the addition and removal of a CSS classes on an element and (during the process)
+ * triggers an animation surrounding the class addition/removal. Much like `$animate.addClass` and
+ * `$animate.removeClass`, `setClass` will only evaluate the classes being added/removed once a digest has
+ * passed. Note that class-based animations are treated differently compared to structural animations
+ * (like enter, move and leave) since the CSS classes may be added/removed at different points
+ * depending if CSS or JavaScript animations are used.
+ *
+ * @param {DOMElement} element the element which the CSS classes will be applied to
+ * @param {string} add the CSS class(es) that will be added (multiple classes are separated via spaces)
+ * @param {string} remove the CSS class(es) that will be removed (multiple classes are separated via spaces)
+ * @param {object=} options an optional collection of options/styles that will be applied to the element
+ *
+ * @return {Promise} the animation callback promise
*/
- setClass : function(element, add, remove, done) {
- forEach(element, function (element) {
- jqLiteAddClass(element, add);
- jqLiteRemoveClass(element, remove);
- });
- async(done);
+ setClass: function(element, add, remove, options) {
+ options = prepareAnimateOptions(options);
+ options.addClass = mergeClasses(options.addClass, add);
+ options.removeClass = mergeClasses(options.removeClass, remove);
+ return $$animateQueue.push(element, 'setClass', options);
},
- enabled : noop
+ /**
+ * @ngdoc method
+ * @name $animate#animate
+ * @kind function
+ *
+ * @description Performs an inline animation on the element which applies the provided to and from CSS styles to the element.
+ * If any detected CSS transition, keyframe or JavaScript matches the provided className value then the animation will take
+ * on the provided styles. For example, if a transition animation is set for the given className then the provided from and
+ * to styles will be applied alongside the given transition. If a JavaScript animation is detected then the provided styles
+ * will be given in as function paramters into the `animate` method (or as apart of the `options` parameter).
+ *
+ * @param {DOMElement} element the element which the CSS styles will be applied to
+ * @param {object} from the from (starting) CSS styles that will be applied to the element and across the animation.
+ * @param {object} to the to (destination) CSS styles that will be applied to the element and across the animation.
+ * @param {string=} className an optional CSS class that will be applied to the element for the duration of the animation. If
+ * this value is left as empty then a CSS class of `ng-inline-animate` will be applied to the element.
+ * (Note that if no animation is detected then this value will not be appplied to the element.)
+ * @param {object=} options an optional collection of options/styles that will be applied to the element
+ *
+ * @return {Promise} the animation callback promise
+ */
+ animate: function(element, from, to, className, options) {
+ options = prepareAnimateOptions(options);
+ options.from = options.from ? extend(options.from, from) : from;
+ options.to = options.to ? extend(options.to, to) : to;
+
+ className = className || 'ng-inline-animate';
+ options.tempClasses = mergeClasses(options.tempClasses, className);
+ return $$animateQueue.push(element, 'animate', options);
+ }
};
}];
}];
-function $$AsyncCallbackProvider(){
+function $$AsyncCallbackProvider() {
this.$get = ['$$rAF', '$timeout', function($$rAF, $timeout) {
return $$rAF.supported
? function(fn) { return $$rAF(fn); }
@@ -4380,8 +5364,7 @@ function $$AsyncCallbackProvider(){
/**
* @param {object} window The global window object.
* @param {object} document jQuery wrapped document.
- * @param {function()} XHR XMLHttpRequest constructor.
- * @param {object} $log console.log or an object with the same interface.
+ * @param {object} $log window.console or an object with the same interface.
* @param {object} $sniffer $sniffer service
*/
function Browser(window, document, $log, $sniffer) {
@@ -4412,7 +5395,7 @@ function Browser(window, document, $log, $sniffer) {
} finally {
outstandingRequestCount--;
if (outstandingRequestCount === 0) {
- while(outstandingRequestCallbacks.length) {
+ while (outstandingRequestCallbacks.length) {
try {
outstandingRequestCallbacks.pop()();
} catch (e) {
@@ -4423,6 +5406,11 @@ function Browser(window, document, $log, $sniffer) {
}
}
+ function getHash(url) {
+ var index = url.indexOf('#');
+ return index === -1 ? '' : url.substr(index);
+ }
+
/**
* @private
* Note: this method is used only by scenario runner
@@ -4430,11 +5418,6 @@ function Browser(window, document, $log, $sniffer) {
* @param {function()} callback Function that will be called when no outstanding request
*/
self.notifyWhenNoOutstandingRequests = function(callback) {
- // force browser to execute all pollFns - this is needed so that cookies and other pollers fire
- // at some deterministic time in respect to the test runner's actions. Leaving things up to the
- // regular poller would result in flaky tests.
- forEach(pollFns, function(pollFn){ pollFn(); });
-
if (outstandingRequestCount === 0) {
callback();
} else {
@@ -4443,51 +5426,17 @@ function Browser(window, document, $log, $sniffer) {
};
//////////////////////////////////////////////////////////////
- // Poll Watcher API
- //////////////////////////////////////////////////////////////
- var pollFns = [],
- pollTimeout;
-
- /**
- * @name $browser#addPollFn
- *
- * @param {function()} fn Poll function to add
- *
- * @description
- * Adds a function to the list of functions that poller periodically executes,
- * and starts polling if not started yet.
- *
- * @returns {function()} the added function
- */
- self.addPollFn = function(fn) {
- if (isUndefined(pollTimeout)) startPoller(100, setTimeout);
- pollFns.push(fn);
- return fn;
- };
-
- /**
- * @param {number} interval How often should browser call poll functions (ms)
- * @param {function()} setTimeout Reference to a real or fake `setTimeout` function.
- *
- * @description
- * Configures the poller to run in the specified intervals, using the specified
- * setTimeout fn and kicks it off.
- */
- function startPoller(interval, setTimeout) {
- (function check() {
- forEach(pollFns, function(pollFn){ pollFn(); });
- pollTimeout = setTimeout(check, interval);
- })();
- }
-
- //////////////////////////////////////////////////////////////
// URL API
//////////////////////////////////////////////////////////////
- var lastBrowserUrl = location.href,
+ var cachedState, lastHistoryState,
+ lastBrowserUrl = location.href,
baseElement = document.find('base'),
reloadLocation = null;
+ cacheState();
+ lastHistoryState = cachedState;
+
/**
* @name $browser#url
*
@@ -4505,37 +5454,53 @@ function Browser(window, document, $log, $sniffer) {
* {@link ng.$location $location service} to change url.
*
* @param {string} url New url (when used as setter)
- * @param {boolean=} replace Should new url replace current history record ?
+ * @param {boolean=} replace Should new url replace current history record?
+ * @param {object=} state object to use with pushState/replaceState
*/
- self.url = function(url, replace) {
+ self.url = function(url, replace, state) {
+ // In modern browsers `history.state` is `null` by default; treating it separately
+ // from `undefined` would cause `$browser.url('/foo')` to change `history.state`
+ // to undefined via `pushState`. Instead, let's change `undefined` to `null` here.
+ if (isUndefined(state)) {
+ state = null;
+ }
+
// Android Browser BFCache causes location, history reference to become stale.
if (location !== window.location) location = window.location;
if (history !== window.history) history = window.history;
// setter
if (url) {
- if (lastBrowserUrl == url) return;
+ var sameState = lastHistoryState === state;
+
+ // Don't change anything if previous and current URLs and states match. This also prevents
+ // IE<10 from getting into redirect loop when in LocationHashbangInHtml5Url mode.
+ // See https://github.com/angular/angular.js/commit/ffb2701
+ if (lastBrowserUrl === url && (!$sniffer.history || sameState)) {
+ return self;
+ }
var sameBase = lastBrowserUrl && stripHash(lastBrowserUrl) === stripHash(url);
lastBrowserUrl = url;
+ lastHistoryState = state;
// Don't use history API if only the hash changed
// due to a bug in IE10/IE11 which leads
// to not firing a `hashchange` nor `popstate` event
// in some cases (see #9143).
- if (!sameBase && $sniffer.history) {
- if (replace) history.replaceState(null, '', url);
- else {
- history.pushState(null, '', url);
- // Crazy Opera Bug: http://my.opera.com/community/forums/topic.dml?id=1185462
- baseElement.attr('href', baseElement.attr('href'));
- }
+ if ($sniffer.history && (!sameBase || !sameState)) {
+ history[replace ? 'replaceState' : 'pushState'](state, '', url);
+ cacheState();
+ // Do the assignment again so that those two variables are referentially identical.
+ lastHistoryState = cachedState;
} else {
- if (!sameBase) {
+ if (!sameBase || reloadLocation) {
reloadLocation = url;
}
if (replace) {
location.replace(url);
- } else {
+ } else if (!sameBase) {
location.href = url;
+ } else {
+ location.hash = getHash(url);
}
}
return self;
@@ -4548,15 +5513,59 @@ function Browser(window, document, $log, $sniffer) {
}
};
+ /**
+ * @name $browser#state
+ *
+ * @description
+ * This method is a getter.
+ *
+ * Return history.state or null if history.state is undefined.
+ *
+ * @returns {object} state
+ */
+ self.state = function() {
+ return cachedState;
+ };
+
var urlChangeListeners = [],
urlChangeInit = false;
+ function cacheStateAndFireUrlChange() {
+ cacheState();
+ fireUrlChange();
+ }
+
+ function getCurrentState() {
+ try {
+ return history.state;
+ } catch (e) {
+ // MSIE can reportedly throw when there is no state (UNCONFIRMED).
+ }
+ }
+
+ // This variable should be used *only* inside the cacheState function.
+ var lastCachedState = null;
+ function cacheState() {
+ // This should be the only place in $browser where `history.state` is read.
+ cachedState = getCurrentState();
+ cachedState = isUndefined(cachedState) ? null : cachedState;
+
+ // Prevent callbacks fo fire twice if both hashchange & popstate were fired.
+ if (equals(cachedState, lastCachedState)) {
+ cachedState = lastCachedState;
+ }
+ lastCachedState = cachedState;
+ }
+
function fireUrlChange() {
- if (lastBrowserUrl == self.url()) return;
+ if (lastBrowserUrl === self.url() && lastHistoryState === cachedState) {
+ return;
+ }
lastBrowserUrl = self.url();
+ lastHistoryState = cachedState;
forEach(urlChangeListeners, function(listener) {
- listener(self.url());
+ listener(self.url(), cachedState);
});
}
@@ -4589,11 +5598,9 @@ function Browser(window, document, $log, $sniffer) {
// changed by push/replaceState
// html5 history api - popstate event
- if ($sniffer.history) jqLite(window).on('popstate', fireUrlChange);
+ if ($sniffer.history) jqLite(window).on('popstate', cacheStateAndFireUrlChange);
// hashchange event
- if ($sniffer.hashchange) jqLite(window).on('hashchange', fireUrlChange);
- // polling
- else self.addPollFn(fireUrlChange);
+ jqLite(window).on('hashchange', cacheStateAndFireUrlChange);
urlChangeInit = true;
}
@@ -4603,6 +5610,16 @@ function Browser(window, document, $log, $sniffer) {
};
/**
+ * @private
+ * Remove popstate and hashchange handler from window.
+ *
+ * NOTE: this api is intended for use only by $rootScope.
+ */
+ self.$$applicationDestroyed = function() {
+ jqLite(window).off('hashchange popstate', cacheStateAndFireUrlChange);
+ };
+
+ /**
* Checks whether the url has changed outside of Angular.
* Needs to be exported to be able to check for changes that have been done in sync,
* as hashchange/popstate events fire in async.
@@ -4627,82 +5644,6 @@ function Browser(window, document, $log, $sniffer) {
return href ? href.replace(/^(https?\:)?\/\/[^\/]*/, '') : '';
};
- //////////////////////////////////////////////////////////////
- // Cookies API
- //////////////////////////////////////////////////////////////
- var lastCookies = {};
- var lastCookieString = '';
- var cookiePath = self.baseHref();
-
- /**
- * @name $browser#cookies
- *
- * @param {string=} name Cookie name
- * @param {string=} value Cookie value
- *
- * @description
- * The cookies method provides a 'private' low level access to browser cookies.
- * It is not meant to be used directly, use the $cookie service instead.
- *
- * The return values vary depending on the arguments that the method was called with as follows:
- *
- * - cookies() -> hash of all cookies, this is NOT a copy of the internal state, so do not modify
- * it
- * - cookies(name, value) -> set name to value, if value is undefined delete the cookie
- * - cookies(name) -> the same as (name, undefined) == DELETES (no one calls it right now that
- * way)
- *
- * @returns {Object} Hash of all cookies (if called without any parameter)
- */
- self.cookies = function(name, value) {
- /* global escape: false, unescape: false */
- var cookieLength, cookieArray, cookie, i, index;
-
- if (name) {
- if (value === undefined) {
- rawDocument.cookie = escape(name) + "=;path=" + cookiePath +
- ";expires=Thu, 01 Jan 1970 00:00:00 GMT";
- } else {
- if (isString(value)) {
- cookieLength = (rawDocument.cookie = escape(name) + '=' + escape(value) +
- ';path=' + cookiePath).length + 1;
-
- // per http://www.ietf.org/rfc/rfc2109.txt browser must allow at minimum:
- // - 300 cookies
- // - 20 cookies per unique domain
- // - 4096 bytes per cookie
- if (cookieLength > 4096) {
- $log.warn("Cookie '"+ name +
- "' possibly not set or overflowed because it was too large ("+
- cookieLength + " > 4096 bytes)!");
- }
- }
- }
- } else {
- if (rawDocument.cookie !== lastCookieString) {
- lastCookieString = rawDocument.cookie;
- cookieArray = lastCookieString.split("; ");
- lastCookies = {};
-
- for (i = 0; i < cookieArray.length; i++) {
- cookie = cookieArray[i];
- index = cookie.indexOf('=');
- if (index > 0) { //ignore nameless cookies
- name = unescape(cookie.substring(0, index));
- // the first value that is seen for a cookie is the most
- // specific one. values for the same cookie name that
- // follow are for less specific paths.
- if (lastCookies[name] === undefined) {
- lastCookies[name] = unescape(cookie.substring(index + 1));
- }
- }
- }
- }
- return lastCookies;
- }
- };
-
-
/**
* @name $browser#defer
* @param {function()} fn A function, who's execution should be deferred.
@@ -4751,9 +5692,9 @@ function Browser(window, document, $log, $sniffer) {
}
-function $BrowserProvider(){
+function $BrowserProvider() {
this.$get = ['$window', '$log', '$sniffer', '$document',
- function( $window, $log, $sniffer, $document){
+ function($window, $log, $sniffer, $document) {
return new Browser($window, $document, $log, $sniffer);
}];
}
@@ -4917,13 +5858,13 @@ function $CacheFactoryProvider() {
* @returns {*} the value stored.
*/
put: function(key, value) {
+ if (isUndefined(value)) return;
if (capacity < Number.MAX_VALUE) {
var lruEntry = lruHash[key] || (lruHash[key] = {key: key});
refresh(lruEntry);
}
- if (isUndefined(value)) return;
if (!(key in data)) size++;
data[key] = value;
@@ -5130,7 +6071,7 @@ function $CacheFactoryProvider() {
* the document, but it must be a descendent of the {@link ng.$rootElement $rootElement} (IE,
* element with ng-app attribute), otherwise the template will be ignored.
*
- * Adding via the $templateCache service:
+ * Adding via the `$templateCache` service:
*
* ```js
* var myApp = angular.module('myApp', []);
@@ -5158,6 +6099,17 @@ function $TemplateCacheProvider() {
}];
}
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Any commits to this file should be reviewed with security in mind. *
+ * Changes to this file can potentially create security vulnerabilities. *
+ * An approval from 2 Core members with history of modifying *
+ * this file is required. *
+ * *
+ * Does the change somehow allow for arbitrary javascript to be executed? *
+ * Or allows for someone to change the prototype of built-in objects? *
+ * Or gives undesired access to variables likes document or window? *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
/* ! VARIABLE/FUNCTION NAMING CONVENTIONS THAT APPLY TO THIS FILE!
*
* DOM-related variables:
@@ -5219,9 +6171,11 @@ function $TemplateCacheProvider() {
* // templateUrl: 'directive.html', // or // function(tElement, tAttrs) { ... },
* transclude: false,
* restrict: 'A',
+ * templateNamespace: 'html',
* scope: false,
* controller: function($scope, $element, $attrs, $transclude, otherInjectables) { ... },
- * controllerAs: 'stringAlias',
+ * controllerAs: 'stringIdentifier',
+ * bindToController: false,
* require: 'siblingDirectiveName', // or // ['^parentDirectiveName', '?optionalDirectiveName', '?^optionalParent'],
* compile: function compile(tElement, tAttrs, transclude) {
* return {
@@ -5269,6 +6223,13 @@ function $TemplateCacheProvider() {
* The directive definition object provides instructions to the {@link ng.$compile
* compiler}. The attributes are:
*
+ * #### `multiElement`
+ * When this property is set to true, the HTML compiler will collect DOM nodes between
+ * nodes with the attributes `directive-name-start` and `directive-name-end`, and group them
+ * together as the directive elements. It is recommended that this feature be used on directives
+ * which are not strictly behavioural (such as {@link ngClick}), and which
+ * do not manipulate or replace child nodes (such as {@link ngInclude}).
+ *
* #### `priority`
* When there are multiple directives defined on a single DOM element, sometimes it
* is necessary to specify the order in which the directives are applied. The `priority` is used
@@ -5280,7 +6241,8 @@ function $TemplateCacheProvider() {
* #### `terminal`
* If set to true then the current `priority` will be the last set of directives
* which will execute (any directives at the current priority will still execute
- * as the order of execution on same `priority` is undefined).
+ * as the order of execution on same `priority` is undefined). Note that expressions
+ * and other directives used in the directive's template will also be excluded from execution.
*
* #### `scope`
* **If set to `true`,** then a new scope will be created for this directive. If multiple directives on the
@@ -5313,7 +6275,9 @@ function $TemplateCacheProvider() {
* value of `parentModel` on the parent scope. Any changes to `parentModel` will be reflected
* in `localModel` and any changes in `localModel` will reflect in `parentModel`. If the parent
* scope property doesn't exist, it will throw a NON_ASSIGNABLE_MODEL_EXPRESSION exception. You
- * can avoid this behavior using `=?` or `=?attr` in order to flag the property as optional.
+ * can avoid this behavior using `=?` or `=?attr` in order to flag the property as optional. If
+ * you want to shallow watch for changes (i.e. $watchCollection instead of $watch) you can use
+ * `=*` or `=*attr` (`=*?` or `=*?attr` if the property is optional).
*
* * `&` or `&attr` - provides a way to execute an expression in the context of the parent scope.
* If no `attr` name is specified then the attribute name is assumed to be the same as the
@@ -5326,6 +6290,10 @@ function $TemplateCacheProvider() {
* by calling the `localFn` as `localFn({amount: 22})`.
*
*
+ * #### `bindToController`
+ * When an isolate scope is used for a component (see above), and `controllerAs` is used, `bindToController: true` will
+ * allow a component to have its properties bound to the controller, rather than to scope. When the controller
+ * is instantiated, the initial values of the isolate scope bindings are already available.
*
* #### `controller`
* Controller constructor function. The controller is instantiated before the
@@ -5336,40 +6304,66 @@ function $TemplateCacheProvider() {
* * `$scope` - Current scope associated with the element
* * `$element` - Current element
* * `$attrs` - Current attributes object for the element
- * * `$transclude` - A transclude linking function pre-bound to the correct transclusion scope.
- * The scope can be overridden by an optional first argument.
- * `function([scope], cloneLinkingFn)`.
+ * * `$transclude` - A transclude linking function pre-bound to the correct transclusion scope:
+ * `function([scope], cloneLinkingFn, futureParentElement)`.
+ * * `scope`: optional argument to override the scope.
+ * * `cloneLinkingFn`: optional argument to create clones of the original transcluded content.
+ * * `futureParentElement`:
+ * * defines the parent to which the `cloneLinkingFn` will add the cloned elements.
+ * * default: `$element.parent()` resp. `$element` for `transclude:'element'` resp. `transclude:true`.
+ * * only needed for transcludes that are allowed to contain non html elements (e.g. SVG elements)
+ * and when the `cloneLinkinFn` is passed,
+ * as those elements need to created and cloned in a special way when they are defined outside their
+ * usual containers (e.g. like `<svg>`).
+ * * See also the `directive.templateNamespace` property.
*
*
* #### `require`
* Require another directive and inject its controller as the fourth argument to the linking function. The
* `require` takes a string name (or array of strings) of the directive(s) to pass in. If an array is used, the
* injected argument will be an array in corresponding order. If no such directive can be
- * found, or if the directive does not have a controller, then an error is raised. The name can be prefixed with:
+ * found, or if the directive does not have a controller, then an error is raised (unless no link function
+ * is specified, in which case error checking is skipped). The name can be prefixed with:
*
* * (no prefix) - Locate the required controller on the current element. Throw an error if not found.
* * `?` - Attempt to locate the required controller or pass `null` to the `link` fn if not found.
* * `^` - Locate the required controller by searching the element and its parents. Throw an error if not found.
+ * * `^^` - Locate the required controller by searching the element's parents. Throw an error if not found.
* * `?^` - Attempt to locate the required controller by searching the element and its parents or pass
* `null` to the `link` fn if not found.
+ * * `?^^` - Attempt to locate the required controller by searching the element's parents, or pass
+ * `null` to the `link` fn if not found.
*
*
* #### `controllerAs`
- * Controller alias at the directive scope. An alias for the controller so it
- * can be referenced at the directive template. The directive needs to define a scope for this
- * configuration to be used. Useful in the case when directive is used as component.
+ * Identifier name for a reference to the controller in the directive's scope.
+ * This allows the controller to be referenced from the directive template. The directive
+ * needs to define a scope for this configuration to be used. Useful in the case when
+ * directive is used as component.
*
*
* #### `restrict`
* String of subset of `EACM` which restricts the directive to a specific directive
- * declaration style. If omitted, the default (attributes only) is used.
+ * declaration style. If omitted, the defaults (elements and attributes) are used.
*
- * * `E` - Element name: `<my-directive></my-directive>`
+ * * `E` - Element name (default): `<my-directive></my-directive>`
* * `A` - Attribute (default): `<div my-directive="exp"></div>`
* * `C` - Class: `<div class="my-directive: exp;"></div>`
* * `M` - Comment: `<!-- directive: my-directive exp -->`
*
*
+ * #### `templateNamespace`
+ * String representing the document type used by the markup in the template.
+ * AngularJS needs this information as those elements need to be created and cloned
+ * in a special way when they are defined outside their usual containers like `<svg>` and `<math>`.
+ *
+ * * `html` - All root nodes in the template are HTML. Root nodes may also be
+ * top-level elements such as `<svg>` or `<math>`.
+ * * `svg` - The root nodes in the template are SVG elements (excluding `<math>`).
+ * * `math` - The root nodes in the template are MathML elements (excluding `<svg>`).
+ *
+ * If no `templateNamespace` is specified, then the namespace is considered to be `html`.
+ *
* #### `template`
* HTML markup that may:
* * Replace the contents of the directive's element (default).
@@ -5384,34 +6378,42 @@ function $TemplateCacheProvider() {
*
*
* #### `templateUrl`
- * Same as `template` but the template is loaded from the specified URL. Because
- * the template loading is asynchronous the compilation/linking is suspended until the template
- * is loaded.
+ * This is similar to `template` but the template is loaded from the specified URL, asynchronously.
+ *
+ * Because template loading is asynchronous the compiler will suspend compilation of directives on that element
+ * for later when the template has been resolved. In the meantime it will continue to compile and link
+ * sibling and parent elements as though this element had not contained any directives.
+ *
+ * The compiler does not suspend the entire compilation to wait for templates to be loaded because this
+ * would result in the whole app "stalling" until all templates are loaded asynchronously - even in the
+ * case when only one deeply nested directive has `templateUrl`.
+ *
+ * Template loading is asynchronous even if the template has been preloaded into the {@link $templateCache}
*
* You can specify `templateUrl` as a string representing the URL or as a function which takes two
* arguments `tElement` and `tAttrs` (described in the `compile` function api below) and returns
* a string value representing the url. In either case, the template URL is passed through {@link
- * api/ng.$sce#getTrustedResourceUrl $sce.getTrustedResourceUrl}.
+ * $sce#getTrustedResourceUrl $sce.getTrustedResourceUrl}.
*
*
- * #### `replace` ([*DEPRECATED*!], will be removed in next major release)
+ * #### `replace` ([*DEPRECATED*!], will be removed in next major release - i.e. v2.0)
* specify what the template should replace. Defaults to `false`.
*
* * `true` - the template will replace the directive's element.
* * `false` - the template will replace the contents of the directive's element.
*
* The replacement process migrates all of the attributes / classes from the old element to the new
- * one. See the {@link guide/directive#creating-custom-directives_creating-directives_template-expanding-directive
+ * one. See the {@link guide/directive#template-expanding-directive
* Directives Guide} for an example.
*
+ * There are very few scenarios where element replacement is required for the application function,
+ * the main one being reusable custom components that are used within SVG contexts
+ * (because SVG doesn't work with custom elements in the DOM tree).
+ *
* #### `transclude`
- * compile the content of the element and make it available to the directive.
- * Typically used with {@link ng.directive:ngTransclude
- * ngTransclude}. The advantage of transclusion is that the linking function receives a
- * transclusion function which is pre-bound to the correct scope. In a typical setup the widget
- * creates an `isolate` scope, but the transclusion is not a child, but a sibling of the `isolate`
- * scope. This makes it possible for the widget to have private state, and the transclusion to
- * be bound to the parent (pre-`isolate`) scope.
+ * Extract the contents of the element where the directive appears and make it available to the directive.
+ * The contents are compiled and provided to the directive as a **transclusion function**. See the
+ * {@link $compile#transclusion Transclusion} section below.
*
* There are two kinds of transclusion depending upon whether you want to transclude just the contents of the
* directive's element or the entire element:
@@ -5421,11 +6423,6 @@ function $TemplateCacheProvider() {
* element that defined at a lower priority than this directive. When used, the `template`
* property is ignored.
*
- * <div class="alert alert-warning">
- * **Note:** When testing an element transclude directive you must not place the directive at the root of the
- * DOM fragment that is being compiled. See {@link guide/unit-testing#testing-transclusion-directives
- * Testing Transclusion Directives}.
- * </div>
*
* #### `compile`
*
@@ -5461,7 +6458,7 @@ function $TemplateCacheProvider() {
* `templateUrl` declaration or manual compilation inside the compile function.
* </div>
*
- * <div class="alert alert-error">
+ * <div class="alert alert-danger">
* **Note:** The `transclude` function that is passed to the compile function is deprecated, as it
* e.g. does not know about the right outer scope. Please use the transclude function that is passed
* to the link function instead.
@@ -5498,15 +6495,23 @@ function $TemplateCacheProvider() {
* * `iAttrs` - instance attributes - Normalized list of attributes declared on this element shared
* between all directive linking functions.
*
- * * `controller` - a controller instance - A controller instance if at least one directive on the
- * element defines a controller. The controller is shared among all the directives, which allows
- * the directives to use the controllers as a communication channel.
+ * * `controller` - the directive's required controller instance(s) - Instances are shared
+ * among all directives, which allows the directives to use the controllers as a communication
+ * channel. The exact value depends on the directive's `require` property:
+ * * no controller(s) required: the directive's own controller, or `undefined` if it doesn't have one
+ * * `string`: the controller instance
+ * * `array`: array of controller instances
*
- * * `transcludeFn` - A transclude linking function pre-bound to the correct transclusion scope.
- * The scope can be overridden by an optional first argument. This is the same as the `$transclude`
- * parameter of directive controllers.
- * `function([scope], cloneLinkingFn)`.
+ * If a required controller cannot be found, and it is optional, the instance is `null`,
+ * otherwise the {@link error:$compile:ctreq Missing Required Controller} error is thrown.
*
+ * Note that you can also require the directive's own controller - it will be made available like
+ * like any other controller.
+ *
+ * * `transcludeFn` - A transclude linking function pre-bound to the correct transclusion scope.
+ * This is the same as the `$transclude`
+ * parameter of directive controllers, see there for details.
+ * `function([scope], cloneLinkingFn, futureParentElement)`.
*
* #### Pre-linking function
*
@@ -5515,9 +6520,130 @@ function $TemplateCacheProvider() {
*
* #### Post-linking function
*
- * Executed after the child elements are linked. It is safe to do DOM transformation in the post-linking function.
+ * Executed after the child elements are linked.
+ *
+ * Note that child elements that contain `templateUrl` directives will not have been compiled
+ * and linked since they are waiting for their template to load asynchronously and their own
+ * compilation and linking has been suspended until that occurs.
+ *
+ * It is safe to do DOM transformation in the post-linking function on elements that are not waiting
+ * for their async templates to be resolved.
+ *
+ *
+ * ### Transclusion
+ *
+ * Transclusion is the process of extracting a collection of DOM element from one part of the DOM and
+ * copying them to another part of the DOM, while maintaining their connection to the original AngularJS
+ * scope from where they were taken.
+ *
+ * Transclusion is used (often with {@link ngTransclude}) to insert the
+ * original contents of a directive's element into a specified place in the template of the directive.
+ * The benefit of transclusion, over simply moving the DOM elements manually, is that the transcluded
+ * content has access to the properties on the scope from which it was taken, even if the directive
+ * has isolated scope.
+ * See the {@link guide/directive#creating-a-directive-that-wraps-other-elements Directives Guide}.
+ *
+ * This makes it possible for the widget to have private state for its template, while the transcluded
+ * content has access to its originating scope.
+ *
+ * <div class="alert alert-warning">
+ * **Note:** When testing an element transclude directive you must not place the directive at the root of the
+ * DOM fragment that is being compiled. See {@link guide/unit-testing#testing-transclusion-directives
+ * Testing Transclusion Directives}.
+ * </div>
+ *
+ * #### Transclusion Functions
+ *
+ * When a directive requests transclusion, the compiler extracts its contents and provides a **transclusion
+ * function** to the directive's `link` function and `controller`. This transclusion function is a special
+ * **linking function** that will return the compiled contents linked to a new transclusion scope.
+ *
+ * <div class="alert alert-info">
+ * If you are just using {@link ngTransclude} then you don't need to worry about this function, since
+ * ngTransclude will deal with it for us.
+ * </div>
+ *
+ * If you want to manually control the insertion and removal of the transcluded content in your directive
+ * then you must use this transclude function. When you call a transclude function it returns a a jqLite/JQuery
+ * object that contains the compiled DOM, which is linked to the correct transclusion scope.
+ *
+ * When you call a transclusion function you can pass in a **clone attach function**. This function accepts
+ * two parameters, `function(clone, scope) { ... }`, where the `clone` is a fresh compiled copy of your transcluded
+ * content and the `scope` is the newly created transclusion scope, to which the clone is bound.
+ *
+ * <div class="alert alert-info">
+ * **Best Practice**: Always provide a `cloneFn` (clone attach function) when you call a translude function
+ * since you then get a fresh clone of the original DOM and also have access to the new transclusion scope.
+ * </div>
+ *
+ * It is normal practice to attach your transcluded content (`clone`) to the DOM inside your **clone
+ * attach function**:
+ *
+ * ```js
+ * var transcludedContent, transclusionScope;
+ *
+ * $transclude(function(clone, scope) {
+ * element.append(clone);
+ * transcludedContent = clone;
+ * transclusionScope = scope;
+ * });
+ * ```
+ *
+ * Later, if you want to remove the transcluded content from your DOM then you should also destroy the
+ * associated transclusion scope:
+ *
+ * ```js
+ * transcludedContent.remove();
+ * transclusionScope.$destroy();
+ * ```
+ *
+ * <div class="alert alert-info">
+ * **Best Practice**: if you intend to add and remove transcluded content manually in your directive
+ * (by calling the transclude function to get the DOM and calling `element.remove()` to remove it),
+ * then you are also responsible for calling `$destroy` on the transclusion scope.
+ * </div>
+ *
+ * The built-in DOM manipulation directives, such as {@link ngIf}, {@link ngSwitch} and {@link ngRepeat}
+ * automatically destroy their transluded clones as necessary so you do not need to worry about this if
+ * you are simply using {@link ngTransclude} to inject the transclusion into your directive.
+ *
+ *
+ * #### Transclusion Scopes
+ *
+ * When you call a transclude function it returns a DOM fragment that is pre-bound to a **transclusion
+ * scope**. This scope is special, in that it is a child of the directive's scope (and so gets destroyed
+ * when the directive's scope gets destroyed) but it inherits the properties of the scope from which it
+ * was taken.
+ *
+ * For example consider a directive that uses transclusion and isolated scope. The DOM hierarchy might look
+ * like this:
+ *
+ * ```html
+ * <div ng-app>
+ * <div isolate>
+ * <div transclusion>
+ * </div>
+ * </div>
+ * </div>
+ * ```
+ *
+ * The `$parent` scope hierarchy will look like this:
+ *
+ * ```
+ * - $rootScope
+ * - isolate
+ * - transclusion
+ * ```
+ *
+ * but the scopes will inherit prototypically from different scopes to their `$parent`.
+ *
+ * ```
+ * - $rootScope
+ * - transclusion
+ * - isolate
+ * ```
+ *
*
- * <a name="Attributes"></a>
* ### Attributes
*
* The {@link ng.$compile.directive.Attributes Attributes} object - passed as a parameter in the
@@ -5597,8 +6723,8 @@ function $TemplateCacheProvider() {
}]);
</script>
<div ng-controller="GreeterController">
- <input ng-model="name"> <br>
- <textarea ng-model="html"></textarea> <br>
+ <input ng-model="name"> <br/>
+ <textarea ng-model="html"></textarea> <br/>
<div compile="html"></div>
</div>
</file>
@@ -5618,21 +6744,41 @@ function $TemplateCacheProvider() {
*
*
* @param {string|DOMElement} element Element or HTML string to compile into a template function.
- * @param {function(angular.Scope, cloneAttachFn=)} transclude function available to directives.
+ * @param {function(angular.Scope, cloneAttachFn=)} transclude function available to directives - DEPRECATED.
+ *
+ * <div class="alert alert-danger">
+ * **Note:** Passing a `transclude` function to the $compile function is deprecated, as it
+ * e.g. will not use the right outer scope. Please pass the transclude function as a
+ * `parentBoundTranscludeFn` to the link function instead.
+ * </div>
+ *
* @param {number} maxPriority only apply directives lower than given priority (Only effects the
* root element(s), not their children)
- * @returns {function(scope, cloneAttachFn=)} a link function which is used to bind template
+ * @returns {function(scope, cloneAttachFn=, options=)} a link function which is used to bind template
* (a DOM element/tree) to a scope. Where:
*
* * `scope` - A {@link ng.$rootScope.Scope Scope} to bind to.
* * `cloneAttachFn` - If `cloneAttachFn` is provided, then the link function will clone the
* `template` and call the `cloneAttachFn` function allowing the caller to attach the
* cloned elements to the DOM document at the appropriate place. The `cloneAttachFn` is
- * called as: <br> `cloneAttachFn(clonedElement, scope)` where:
+ * called as: <br/> `cloneAttachFn(clonedElement, scope)` where:
*
* * `clonedElement` - is a clone of the original `element` passed into the compiler.
* * `scope` - is the current scope with which the linking function is working with.
*
+ * * `options` - An optional object hash with linking options. If `options` is provided, then the following
+ * keys may be used to control linking behavior:
+ *
+ * * `parentBoundTranscludeFn` - the transclude function made available to
+ * directives; if given, it will be passed through to the link functions of
+ * directives found in `element` during compilation.
+ * * `transcludeControllers` - an object hash with keys that map controller names
+ * to controller instances; if given, it will make the controllers
+ * available to directives.
+ * * `futureParentElement` - defines the parent to which the `cloneAttachFn` will add
+ * the cloned elements; only needed for transcludes that are allowed to contain non html
+ * elements (e.g. SVG elements). See also the directive.controller property.
+ *
* Calling the linking function returns the element of the template. It is either the original
* element passed in, or the clone of the element if the `cloneAttachFn` is provided.
*
@@ -5671,7 +6817,6 @@ var $compileMinErr = minErr('$compile');
/**
* @ngdoc provider
* @name $compileProvider
- * @kind function
*
* @description
*/
@@ -5679,14 +6824,93 @@ $CompileProvider.$inject = ['$provide', '$$sanitizeUriProvider'];
function $CompileProvider($provide, $$sanitizeUriProvider) {
var hasDirectives = {},
Suffix = 'Directive',
- COMMENT_DIRECTIVE_REGEXP = /^\s*directive\:\s*([\d\w_\-]+)\s+(.*)$/,
- CLASS_DIRECTIVE_REGEXP = /(([\d\w_\-]+)(?:\:([^;]+))?;?)/;
+ COMMENT_DIRECTIVE_REGEXP = /^\s*directive\:\s*([\w\-]+)\s+(.*)$/,
+ CLASS_DIRECTIVE_REGEXP = /(([\w\-]+)(?:\:([^;]+))?;?)/,
+ ALL_OR_NOTHING_ATTRS = makeMap('ngSrc,ngSrcset,src,srcset'),
+ REQUIRE_PREFIX_REGEXP = /^(?:(\^\^?)?(\?)?(\^\^?)?)?/;
// Ref: http://developers.whatwg.org/webappapis.html#event-handler-idl-attributes
// The assumption is that future DOM event attribute names will begin with
// 'on' and be composed of only English letters.
var EVENT_HANDLER_ATTR_REGEXP = /^(on[a-z]+|formaction)$/;
+ function parseIsolateBindings(scope, directiveName, isController) {
+ var LOCAL_REGEXP = /^\s*([@&]|=(\*?))(\??)\s*(\w*)\s*$/;
+
+ var bindings = {};
+
+ forEach(scope, function(definition, scopeName) {
+ var match = definition.match(LOCAL_REGEXP);
+
+ if (!match) {
+ throw $compileMinErr('iscp',
+ "Invalid {3} for directive '{0}'." +
+ " Definition: {... {1}: '{2}' ...}",
+ directiveName, scopeName, definition,
+ (isController ? "controller bindings definition" :
+ "isolate scope definition"));
+ }
+
+ bindings[scopeName] = {
+ mode: match[1][0],
+ collection: match[2] === '*',
+ optional: match[3] === '?',
+ attrName: match[4] || scopeName
+ };
+ });
+
+ return bindings;
+ }
+
+ function parseDirectiveBindings(directive, directiveName) {
+ var bindings = {
+ isolateScope: null,
+ bindToController: null
+ };
+ if (isObject(directive.scope)) {
+ if (directive.bindToController === true) {
+ bindings.bindToController = parseIsolateBindings(directive.scope,
+ directiveName, true);
+ bindings.isolateScope = {};
+ } else {
+ bindings.isolateScope = parseIsolateBindings(directive.scope,
+ directiveName, false);
+ }
+ }
+ if (isObject(directive.bindToController)) {
+ bindings.bindToController =
+ parseIsolateBindings(directive.bindToController, directiveName, true);
+ }
+ if (isObject(bindings.bindToController)) {
+ var controller = directive.controller;
+ var controllerAs = directive.controllerAs;
+ if (!controller) {
+ // There is no controller, there may or may not be a controllerAs property
+ throw $compileMinErr('noctrl',
+ "Cannot bind to controller without directive '{0}'s controller.",
+ directiveName);
+ } else if (!identifierForController(controller, controllerAs)) {
+ // There is a controller, but no identifier or controllerAs property
+ throw $compileMinErr('noident',
+ "Cannot bind to controller without identifier for directive '{0}'.",
+ directiveName);
+ }
+ }
+ return bindings;
+ }
+
+ function assertValidDirectiveName(name) {
+ var letter = name.charAt(0);
+ if (!letter || letter !== lowercase(letter)) {
+ throw $compileMinErr('baddir', "Directive name '{0}' is invalid. The first character must be a lowercase letter", name);
+ }
+ if (name !== name.trim()) {
+ throw $compileMinErr('baddir',
+ "Directive name '{0}' is invalid. The name should not contain leading or trailing whitespaces",
+ name);
+ }
+ }
+
/**
* @ngdoc method
* @name $compileProvider#directive
@@ -5705,6 +6929,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
this.directive = function registerDirective(name, directiveFactory) {
assertNotHasOwnProperty(name, 'directive');
if (isString(name)) {
+ assertValidDirectiveName(name);
assertArg(directiveFactory, 'directiveFactory');
if (!hasDirectives.hasOwnProperty(name)) {
hasDirectives[name] = [];
@@ -5723,7 +6948,13 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
directive.index = index;
directive.name = directive.name || name;
directive.require = directive.require || (directive.controller && directive.name);
- directive.restrict = directive.restrict || 'A';
+ directive.restrict = directive.restrict || 'EA';
+ var bindings = directive.$$bindings =
+ parseDirectiveBindings(directive, directive.name);
+ if (isObject(bindings.isolateScope)) {
+ directive.$$isolateBindings = bindings.isolateScope;
+ }
+ directive.$$moduleName = directiveFactory.$$moduleName;
directives.push(directive);
} catch (e) {
$exceptionHandler(e);
@@ -5749,7 +6980,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
* Retrieves or overrides the default regular expression that is used for whitelisting of safe
* urls during a[href] sanitization.
*
- * The sanitization is a security measure aimed at prevent XSS attacks via html links.
+ * The sanitization is a security measure aimed at preventing XSS attacks via html links.
*
* Any url about to be assigned to a[href] via data-binding is first normalized and turned into
* an absolute url. Afterwards, the url is matched against the `aHrefSanitizationWhitelist`
@@ -5799,15 +7030,57 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
}
};
+ /**
+ * @ngdoc method
+ * @name $compileProvider#debugInfoEnabled
+ *
+ * @param {boolean=} enabled update the debugInfoEnabled state if provided, otherwise just return the
+ * current debugInfoEnabled state
+ * @returns {*} current value if used as getter or itself (chaining) if used as setter
+ *
+ * @kind function
+ *
+ * @description
+ * Call this method to enable/disable various debug runtime information in the compiler such as adding
+ * binding information and a reference to the current scope on to DOM elements.
+ * If enabled, the compiler will add the following to DOM elements that have been bound to the scope
+ * * `ng-binding` CSS class
+ * * `$binding` data property containing an array of the binding expressions
+ *
+ * You may want to disable this in production for a significant performance boost. See
+ * {@link guide/production#disabling-debug-data Disabling Debug Data} for more.
+ *
+ * The default value is true.
+ */
+ var debugInfoEnabled = true;
+ this.debugInfoEnabled = function(enabled) {
+ if (isDefined(enabled)) {
+ debugInfoEnabled = enabled;
+ return this;
+ }
+ return debugInfoEnabled;
+ };
+
this.$get = [
- '$injector', '$interpolate', '$exceptionHandler', '$http', '$templateCache', '$parse',
+ '$injector', '$interpolate', '$exceptionHandler', '$templateRequest', '$parse',
'$controller', '$rootScope', '$document', '$sce', '$animate', '$$sanitizeUri',
- function($injector, $interpolate, $exceptionHandler, $http, $templateCache, $parse,
+ function($injector, $interpolate, $exceptionHandler, $templateRequest, $parse,
$controller, $rootScope, $document, $sce, $animate, $$sanitizeUri) {
- var Attributes = function(element, attr) {
+ var Attributes = function(element, attributesToCopy) {
+ if (attributesToCopy) {
+ var keys = Object.keys(attributesToCopy);
+ var i, l, key;
+
+ for (i = 0, l = keys.length; i < l; i++) {
+ key = keys[i];
+ this[key] = attributesToCopy[key];
+ }
+ } else {
+ this.$attr = {};
+ }
+
this.$$element = element;
- this.$attr = attr || {};
};
Attributes.prototype = {
@@ -5840,8 +7113,8 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
*
* @param {string} classVal The className value that will be added to the element
*/
- $addClass : function(classVal) {
- if(classVal && classVal.length > 0) {
+ $addClass: function(classVal) {
+ if (classVal && classVal.length > 0) {
$animate.addClass(this.$$element, classVal);
}
},
@@ -5857,8 +7130,8 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
*
* @param {string} classVal The className value that will be removed from the element
*/
- $removeClass : function(classVal) {
- if(classVal && classVal.length > 0) {
+ $removeClass: function(classVal) {
+ if (classVal && classVal.length > 0) {
$animate.removeClass(this.$$element, classVal);
}
},
@@ -5875,16 +7148,15 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
* @param {string} newClasses The current CSS className value
* @param {string} oldClasses The former CSS className value
*/
- $updateClass : function(newClasses, oldClasses) {
+ $updateClass: function(newClasses, oldClasses) {
var toAdd = tokenDifference(newClasses, oldClasses);
- var toRemove = tokenDifference(oldClasses, newClasses);
+ if (toAdd && toAdd.length) {
+ $animate.addClass(this.$$element, toAdd);
+ }
- if(toAdd.length === 0) {
+ var toRemove = tokenDifference(oldClasses, newClasses);
+ if (toRemove && toRemove.length) {
$animate.removeClass(this.$$element, toRemove);
- } else if(toRemove.length === 0) {
- $animate.addClass(this.$$element, toAdd);
- } else {
- $animate.setClass(this.$$element, toAdd, toRemove);
}
},
@@ -5902,13 +7174,18 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
//is set through this function since it may cause $updateClass to
//become unstable.
- var booleanKey = getBooleanAttrName(this.$$element[0], key),
- normalizedVal,
+ var node = this.$$element[0],
+ booleanKey = getBooleanAttrName(node, key),
+ aliasedKey = getAliasedAttrName(node, key),
+ observer = key,
nodeName;
if (booleanKey) {
this.$$element.prop(key, value);
attrName = booleanKey;
+ } else if (aliasedKey) {
+ this[aliasedKey] = value;
+ observer = aliasedKey;
}
this[key] = value;
@@ -5925,10 +7202,44 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
nodeName = nodeName_(this.$$element);
- // sanitize a[href] and img[src] values
- if ((nodeName === 'A' && key === 'href') ||
- (nodeName === 'IMG' && key === 'src')) {
+ if ((nodeName === 'a' && key === 'href') ||
+ (nodeName === 'img' && key === 'src')) {
+ // sanitize a[href] and img[src] values
this[key] = value = $$sanitizeUri(value, key === 'src');
+ } else if (nodeName === 'img' && key === 'srcset') {
+ // sanitize img[srcset] values
+ var result = "";
+
+ // first check if there are spaces because it's not the same pattern
+ var trimmedSrcset = trim(value);
+ // ( 999x ,| 999w ,| ,|, )
+ var srcPattern = /(\s+\d+x\s*,|\s+\d+w\s*,|\s+,|,\s+)/;
+ var pattern = /\s/.test(trimmedSrcset) ? srcPattern : /(,)/;
+
+ // split srcset into tuple of uri and descriptor except for the last item
+ var rawUris = trimmedSrcset.split(pattern);
+
+ // for each tuples
+ var nbrUrisWith2parts = Math.floor(rawUris.length / 2);
+ for (var i = 0; i < nbrUrisWith2parts; i++) {
+ var innerIdx = i * 2;
+ // sanitize the uri
+ result += $$sanitizeUri(trim(rawUris[innerIdx]), true);
+ // add the descriptor
+ result += (" " + trim(rawUris[innerIdx + 1]));
+ }
+
+ // split the last item into uri and descriptor
+ var lastTuple = trim(rawUris[i * 2]).split(/\s/);
+
+ // sanitize the last uri
+ result += $$sanitizeUri(trim(lastTuple[0]), true);
+
+ // and add the last descriptor if any
+ if (lastTuple.length === 2) {
+ result += (" " + trim(lastTuple[1]));
+ }
+ this[key] = value = result;
}
if (writeAttr !== false) {
@@ -5941,7 +7252,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
// fire observers
var $$observers = this.$$observers;
- $$observers && forEach($$observers[key], function(fn) {
+ $$observers && forEach($$observers[observer], function(fn) {
try {
fn(value);
} catch (e) {
@@ -5966,25 +7277,39 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
* @param {string} key Normalized key. (ie ngAttribute) .
* @param {function(interpolatedValue)} fn Function that will be called whenever
the interpolated value of the attribute changes.
- * See the {@link guide/directive#Attributes Directives} guide for more info.
- * @returns {function()} the `fn` parameter.
+ * See the {@link guide/directive#text-and-attribute-bindings Directives} guide for more info.
+ * @returns {function()} Returns a deregistration function for this observer.
*/
$observe: function(key, fn) {
var attrs = this,
- $$observers = (attrs.$$observers || (attrs.$$observers = {})),
+ $$observers = (attrs.$$observers || (attrs.$$observers = createMap())),
listeners = ($$observers[key] || ($$observers[key] = []));
listeners.push(fn);
$rootScope.$evalAsync(function() {
- if (!listeners.$$inter) {
+ if (!listeners.$$inter && attrs.hasOwnProperty(key)) {
// no one registered attribute interpolation function, so lets call it manually
fn(attrs[key]);
}
});
- return fn;
+
+ return function() {
+ arrayRemove(listeners, fn);
+ };
}
};
+
+ function safeAddClass($element, className) {
+ try {
+ $element.addClass(className);
+ } catch (e) {
+ // ignore, since it means that we are trying to set class on
+ // SVG element, where class name is read-only.
+ }
+ }
+
+
var startSymbol = $interpolate.startSymbol(),
endSymbol = $interpolate.endSymbol(),
denormalizeTemplate = (startSymbol == '{{' || endSymbol == '}}')
@@ -5994,6 +7319,30 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
},
NG_ATTR_BINDING = /^ngAttr[A-Z]/;
+ compile.$$addBindingInfo = debugInfoEnabled ? function $$addBindingInfo($element, binding) {
+ var bindings = $element.data('$binding') || [];
+
+ if (isArray(binding)) {
+ bindings = bindings.concat(binding);
+ } else {
+ bindings.push(binding);
+ }
+
+ $element.data('$binding', bindings);
+ } : noop;
+
+ compile.$$addBindingClass = debugInfoEnabled ? function $$addBindingClass($element) {
+ safeAddClass($element, 'ng-binding');
+ } : noop;
+
+ compile.$$addScopeInfo = debugInfoEnabled ? function $$addScopeInfo($element, scope, isolated, noTemplate) {
+ var dataName = isolated ? (noTemplate ? '$isolateScopeNoTemplate' : '$isolateScope') : '$scope';
+ $element.data(dataName, scope);
+ } : noop;
+
+ compile.$$addScopeClass = debugInfoEnabled ? function $$addScopeClass($element, isolated) {
+ safeAddClass($element, isolated ? 'ng-isolate-scope' : 'ng-scope');
+ } : noop;
return compile;
@@ -6008,48 +7357,74 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
}
// We can not compile top level text elements since text nodes can be merged and we will
// not be able to attach scope data to them, so we will wrap them in <span>
- forEach($compileNodes, function(node, index){
- if (node.nodeType == 3 /* text node */ && node.nodeValue.match(/\S+/) /* non-empty */ ) {
- $compileNodes[index] = node = jqLite(node).wrap('<span></span>').parent()[0];
+ forEach($compileNodes, function(node, index) {
+ if (node.nodeType == NODE_TYPE_TEXT && node.nodeValue.match(/\S+/) /* non-empty */ ) {
+ $compileNodes[index] = jqLite(node).wrap('<span></span>').parent()[0];
}
});
var compositeLinkFn =
compileNodes($compileNodes, transcludeFn, $compileNodes,
maxPriority, ignoreDirective, previousCompileContext);
- safeAddClass($compileNodes, 'ng-scope');
- return function publicLinkFn(scope, cloneConnectFn, transcludeControllers, parentBoundTranscludeFn){
+ compile.$$addScopeClass($compileNodes);
+ var namespace = null;
+ return function publicLinkFn(scope, cloneConnectFn, options) {
assertArg(scope, 'scope');
- // important!!: we must call our jqLite.clone() since the jQuery one is trying to be smart
- // and sometimes changes the structure of the DOM.
- var $linkNode = cloneConnectFn
- ? JQLitePrototype.clone.call($compileNodes) // IMPORTANT!!!
- : $compileNodes;
-
- forEach(transcludeControllers, function(instance, name) {
- $linkNode.data('$' + name + 'Controller', instance);
- });
- // Attach scope only to non-text nodes.
- for(var i = 0, ii = $linkNode.length; i<ii; i++) {
- var node = $linkNode[i],
- nodeType = node.nodeType;
- if (nodeType === 1 /* element */ || nodeType === 9 /* document */) {
- $linkNode.eq(i).data('$scope', scope);
+ options = options || {};
+ var parentBoundTranscludeFn = options.parentBoundTranscludeFn,
+ transcludeControllers = options.transcludeControllers,
+ futureParentElement = options.futureParentElement;
+
+ // When `parentBoundTranscludeFn` is passed, it is a
+ // `controllersBoundTransclude` function (it was previously passed
+ // as `transclude` to directive.link) so we must unwrap it to get
+ // its `boundTranscludeFn`
+ if (parentBoundTranscludeFn && parentBoundTranscludeFn.$$boundTransclude) {
+ parentBoundTranscludeFn = parentBoundTranscludeFn.$$boundTransclude;
+ }
+
+ if (!namespace) {
+ namespace = detectNamespaceForChildElements(futureParentElement);
+ }
+ var $linkNode;
+ if (namespace !== 'html') {
+ // When using a directive with replace:true and templateUrl the $compileNodes
+ // (or a child element inside of them)
+ // might change, so we need to recreate the namespace adapted compileNodes
+ // for call to the link function.
+ // Note: This will already clone the nodes...
+ $linkNode = jqLite(
+ wrapTemplate(namespace, jqLite('<div>').append($compileNodes).html())
+ );
+ } else if (cloneConnectFn) {
+ // important!!: we must call our jqLite.clone() since the jQuery one is trying to be smart
+ // and sometimes changes the structure of the DOM.
+ $linkNode = JQLitePrototype.clone.call($compileNodes);
+ } else {
+ $linkNode = $compileNodes;
+ }
+
+ if (transcludeControllers) {
+ for (var controllerName in transcludeControllers) {
+ $linkNode.data('$' + controllerName + 'Controller', transcludeControllers[controllerName].instance);
}
}
+ compile.$$addScopeInfo($linkNode, scope);
+
if (cloneConnectFn) cloneConnectFn($linkNode, scope);
if (compositeLinkFn) compositeLinkFn(scope, $linkNode, $linkNode, parentBoundTranscludeFn);
return $linkNode;
};
}
- function safeAddClass($element, className) {
- try {
- $element.addClass(className);
- } catch(e) {
- // ignore, since it means that we are trying to set class on
- // SVG element, where class name is read-only.
+ function detectNamespaceForChildElements(parentElement) {
+ // TODO: Make this detect MathML as well...
+ var node = parentElement && parentElement[0];
+ if (!node) {
+ return 'html';
+ } else {
+ return nodeName_(node) !== 'foreignobject' && node.toString().match(/SVG/) ? 'svg' : 'html';
}
}
@@ -6071,7 +7446,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
function compileNodes(nodeList, transcludeFn, $rootElement, maxPriority, ignoreDirective,
previousCompileContext) {
var linkFns = [],
- attrs, directives, nodeLinkFn, childNodes, childLinkFn, linkFnFound;
+ attrs, directives, nodeLinkFn, childNodes, childLinkFn, linkFnFound, nodeLinkFnFound;
for (var i = 0; i < nodeList.length; i++) {
attrs = new Attributes();
@@ -6086,7 +7461,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
: null;
if (nodeLinkFn && nodeLinkFn.scope) {
- safeAddClass(attrs.$$element, 'ng-scope');
+ compile.$$addScopeClass(attrs.$$element);
}
childLinkFn = (nodeLinkFn && nodeLinkFn.terminal ||
@@ -6098,8 +7473,12 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
(nodeLinkFn.transcludeOnThisElement || !nodeLinkFn.templateOnThisElement)
&& nodeLinkFn.transclude) : transcludeFn);
- linkFns.push(nodeLinkFn, childLinkFn);
- linkFnFound = linkFnFound || nodeLinkFn || childLinkFn;
+ if (nodeLinkFn || childLinkFn) {
+ linkFns.push(i, nodeLinkFn, childLinkFn);
+ linkFnFound = true;
+ nodeLinkFnFound = nodeLinkFnFound || nodeLinkFn;
+ }
+
//use the previous context only for the first element in the virtual group
previousCompileContext = null;
}
@@ -6108,30 +7487,46 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
return linkFnFound ? compositeLinkFn : null;
function compositeLinkFn(scope, nodeList, $rootElement, parentBoundTranscludeFn) {
- var nodeLinkFn, childLinkFn, node, childScope, i, ii, n, childBoundTranscludeFn;
+ var nodeLinkFn, childLinkFn, node, childScope, i, ii, idx, childBoundTranscludeFn;
+ var stableNodeList;
- // copy nodeList so that linking doesn't break due to live list updates.
- var nodeListLength = nodeList.length,
- stableNodeList = new Array(nodeListLength);
- for (i = 0; i < nodeListLength; i++) {
- stableNodeList[i] = nodeList[i];
+
+ if (nodeLinkFnFound) {
+ // copy nodeList so that if a nodeLinkFn removes or adds an element at this DOM level our
+ // offsets don't get screwed up
+ var nodeListLength = nodeList.length;
+ stableNodeList = new Array(nodeListLength);
+
+ // create a sparse array by only copying the elements which have a linkFn
+ for (i = 0; i < linkFns.length; i+=3) {
+ idx = linkFns[i];
+ stableNodeList[idx] = nodeList[idx];
+ }
+ } else {
+ stableNodeList = nodeList;
}
- for(i = 0, n = 0, ii = linkFns.length; i < ii; n++) {
- node = stableNodeList[n];
+ for (i = 0, ii = linkFns.length; i < ii;) {
+ node = stableNodeList[linkFns[i++]];
nodeLinkFn = linkFns[i++];
childLinkFn = linkFns[i++];
if (nodeLinkFn) {
if (nodeLinkFn.scope) {
childScope = scope.$new();
- jqLite.data(node, '$scope', childScope);
+ compile.$$addScopeInfo(jqLite(node), childScope);
+ var destroyBindings = nodeLinkFn.$$destroyBindings;
+ if (destroyBindings) {
+ nodeLinkFn.$$destroyBindings = null;
+ childScope.$on('$destroyed', destroyBindings);
+ }
} else {
childScope = scope;
}
- if ( nodeLinkFn.transcludeOnThisElement ) {
- childBoundTranscludeFn = createBoundTranscludeFn(scope, nodeLinkFn.transclude, parentBoundTranscludeFn);
+ if (nodeLinkFn.transcludeOnThisElement) {
+ childBoundTranscludeFn = createBoundTranscludeFn(
+ scope, nodeLinkFn.transclude, parentBoundTranscludeFn);
} else if (!nodeLinkFn.templateOnThisElement && parentBoundTranscludeFn) {
childBoundTranscludeFn = parentBoundTranscludeFn;
@@ -6143,7 +7538,8 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
childBoundTranscludeFn = null;
}
- nodeLinkFn(childLinkFn, childScope, node, $rootElement, childBoundTranscludeFn);
+ nodeLinkFn(childLinkFn, childScope, node, $rootElement, childBoundTranscludeFn,
+ nodeLinkFn);
} else if (childLinkFn) {
childLinkFn(scope, node.childNodes, undefined, parentBoundTranscludeFn);
@@ -6154,20 +7550,18 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
function createBoundTranscludeFn(scope, transcludeFn, previousBoundTranscludeFn) {
- var boundTranscludeFn = function(transcludedScope, cloneFn, controllers) {
- var scopeCreated = false;
+ var boundTranscludeFn = function(transcludedScope, cloneFn, controllers, futureParentElement, containingScope) {
if (!transcludedScope) {
- transcludedScope = scope.$new();
+ transcludedScope = scope.$new(false, containingScope);
transcludedScope.$$transcluded = true;
- scopeCreated = true;
}
- var clone = transcludeFn(transcludedScope, cloneFn, controllers, previousBoundTranscludeFn);
- if (scopeCreated) {
- clone.on('$destroy', function() { transcludedScope.$destroy(); });
- }
- return clone;
+ return transcludeFn(transcludedScope, cloneFn, {
+ parentBoundTranscludeFn: previousBoundTranscludeFn,
+ transcludeControllers: controllers,
+ futureParentElement: futureParentElement
+ });
};
return boundTranscludeFn;
@@ -6189,11 +7583,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
match,
className;
- switch(nodeType) {
- case 1: /* Element */
+ switch (nodeType) {
+ case NODE_TYPE_ELEMENT: /* Element */
// use the node name: <directive>
addDirective(directives,
- directiveNormalize(nodeName_(node).toLowerCase()), 'E', maxPriority, ignoreDirective);
+ directiveNormalize(nodeName_(node)), 'E', maxPriority, ignoreDirective);
// iterate over the attributes
for (var attr, name, nName, ngAttrName, value, isNgAttr, nAttrs = node.attributes,
@@ -6202,39 +7596,46 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
var attrEndName = false;
attr = nAttrs[j];
- if (!msie || msie >= 8 || attr.specified) {
- name = attr.name;
- value = trim(attr.value);
-
- // support ngAttr attribute binding
- ngAttrName = directiveNormalize(name);
- if (isNgAttr = NG_ATTR_BINDING.test(ngAttrName)) {
- name = snake_case(ngAttrName.substr(6), '-');
- }
+ name = attr.name;
+ value = trim(attr.value);
+
+ // support ngAttr attribute binding
+ ngAttrName = directiveNormalize(name);
+ if (isNgAttr = NG_ATTR_BINDING.test(ngAttrName)) {
+ name = name.replace(PREFIX_REGEXP, '')
+ .substr(8).replace(/_(.)/g, function(match, letter) {
+ return letter.toUpperCase();
+ });
+ }
- var directiveNName = ngAttrName.replace(/(Start|End)$/, '');
+ var directiveNName = ngAttrName.replace(/(Start|End)$/, '');
+ if (directiveIsMultiElement(directiveNName)) {
if (ngAttrName === directiveNName + 'Start') {
attrStartName = name;
attrEndName = name.substr(0, name.length - 5) + 'end';
name = name.substr(0, name.length - 6);
}
+ }
- nName = directiveNormalize(name.toLowerCase());
- attrsMap[nName] = name;
- if (isNgAttr || !attrs.hasOwnProperty(nName)) {
- attrs[nName] = value;
- if (getBooleanAttrName(node, nName)) {
- attrs[nName] = true; // presence means true
- }
- }
- addAttrInterpolateDirective(node, directives, value, nName);
- addDirective(directives, nName, 'A', maxPriority, ignoreDirective, attrStartName,
- attrEndName);
+ nName = directiveNormalize(name.toLowerCase());
+ attrsMap[nName] = name;
+ if (isNgAttr || !attrs.hasOwnProperty(nName)) {
+ attrs[nName] = value;
+ if (getBooleanAttrName(node, nName)) {
+ attrs[nName] = true; // presence means true
+ }
}
+ addAttrInterpolateDirective(node, directives, value, nName, isNgAttr);
+ addDirective(directives, nName, 'A', maxPriority, ignoreDirective, attrStartName,
+ attrEndName);
}
// use class as directive
className = node.className;
+ if (isObject(className)) {
+ // Maybe SVGAnimatedString
+ className = className.animVal;
+ }
if (isString(className) && className !== '') {
while (match = CLASS_DIRECTIVE_REGEXP.exec(className)) {
nName = directiveNormalize(match[2]);
@@ -6245,10 +7646,17 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
}
}
break;
- case 3: /* Text Node */
+ case NODE_TYPE_TEXT: /* Text Node */
+ if (msie === 11) {
+ // Workaround for #11781
+ while (node.parentNode && node.nextSibling && node.nextSibling.nodeType === NODE_TYPE_TEXT) {
+ node.nodeValue = node.nodeValue + node.nextSibling.nodeValue;
+ node.parentNode.removeChild(node.nextSibling);
+ }
+ }
addTextInterpolateDirective(directives, node.nodeValue);
break;
- case 8: /* Comment */
+ case NODE_TYPE_COMMENT: /* Comment */
try {
match = COMMENT_DIRECTIVE_REGEXP.exec(node.nodeValue);
if (match) {
@@ -6281,14 +7689,13 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
var nodes = [];
var depth = 0;
if (attrStart && node.hasAttribute && node.hasAttribute(attrStart)) {
- var startNode = node;
do {
if (!node) {
throw $compileMinErr('uterdir',
"Unterminated attribute, found '{0}' but no matching '{1}' found.",
attrStart, attrEnd);
}
- if (node.nodeType == 1 /** Element **/) {
+ if (node.nodeType == NODE_TYPE_ELEMENT) {
if (node.hasAttribute(attrStart)) depth++;
if (node.hasAttribute(attrEnd)) depth--;
}
@@ -6346,7 +7753,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
previousCompileContext = previousCompileContext || {};
var terminalPriority = -Number.MAX_VALUE,
- newScopeDirective,
+ newScopeDirective = previousCompileContext.newScopeDirective,
controllerDirectives = previousCompileContext.controllerDirectives,
newIsolateScopeDirective = previousCompileContext.newIsolateScopeDirective,
templateDirective = previousCompileContext.templateDirective,
@@ -6364,7 +7771,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
directiveValue;
// executes all directives on the current element
- for(var i = 0, ii = directives.length; i < ii; i++) {
+ for (var i = 0, ii = directives.length; i < ii; i++) {
directive = directives[i];
var attrStart = directive.$$start;
var attrEnd = directive.$$end;
@@ -6380,24 +7787,32 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
}
if (directiveValue = directive.scope) {
- newScopeDirective = newScopeDirective || directive;
// skip the check for directives with async templates, we'll check the derived sync
// directive when the template arrives
if (!directive.templateUrl) {
- assertNoDuplicate('new/isolated scope', newIsolateScopeDirective, directive,
- $compileNode);
if (isObject(directiveValue)) {
+ // This directive is trying to add an isolated scope.
+ // Check that there is no scope of any kind already
+ assertNoDuplicate('new/isolated scope', newIsolateScopeDirective || newScopeDirective,
+ directive, $compileNode);
newIsolateScopeDirective = directive;
+ } else {
+ // This directive is trying to add a child scope.
+ // Check that there is no isolated scope already
+ assertNoDuplicate('new/isolated scope', newIsolateScopeDirective, directive,
+ $compileNode);
}
}
+
+ newScopeDirective = newScopeDirective || directive;
}
directiveName = directive.name;
if (!directive.templateUrl && directive.controller) {
directiveValue = directive.controller;
- controllerDirectives = controllerDirectives || {};
+ controllerDirectives = controllerDirectives || createMap();
assertNoDuplicate("'" + directiveName + "' controller",
controllerDirectives[directiveName], directive, $compileNode);
controllerDirectives[directiveName] = directive;
@@ -6458,11 +7873,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
if (jqLiteIsTextNode(directiveValue)) {
$template = [];
} else {
- $template = jqLite(trim(directiveValue));
+ $template = removeComments(wrapTemplate(directive.templateNamespace, trim(directiveValue)));
}
compileNode = $template[0];
- if ($template.length != 1 || compileNode.nodeType !== 1) {
+ if ($template.length != 1 || compileNode.nodeType !== NODE_TYPE_ELEMENT) {
throw $compileMinErr('tplrt',
"Template for directive '{0}' must have exactly one root element. {1}",
directiveName, '');
@@ -6504,6 +7919,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
nodeLinkFn = compileTemplateUrl(directives.splice(i, directives.length - i), $compileNode,
templateAttrs, jqCollection, hasTranscludeDirective && childTranscludeFn, preLinkFns, postLinkFns, {
controllerDirectives: controllerDirectives,
+ newScopeDirective: (newScopeDirective !== directive) && newScopeDirective,
newIsolateScopeDirective: newIsolateScopeDirective,
templateDirective: templateDirective,
nonTlbTranscludeDirective: nonTlbTranscludeDirective
@@ -6564,176 +7980,159 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
function getControllers(directiveName, require, $element, elementControllers) {
- var value, retrievalMethod = 'data', optional = false;
+ var value;
+
if (isString(require)) {
- while((value = require.charAt(0)) == '^' || value == '?') {
- require = require.substr(1);
- if (value == '^') {
- retrievalMethod = 'inheritedData';
- }
- optional = optional || value == '?';
+ var match = require.match(REQUIRE_PREFIX_REGEXP);
+ var name = require.substring(match[0].length);
+ var inheritType = match[1] || match[3];
+ var optional = match[2] === '?';
+
+ //If only parents then start at the parent element
+ if (inheritType === '^^') {
+ $element = $element.parent();
+ //Otherwise attempt getting the controller from elementControllers in case
+ //the element is transcluded (and has no data) and to avoid .data if possible
+ } else {
+ value = elementControllers && elementControllers[name];
+ value = value && value.instance;
}
- value = null;
- if (elementControllers && retrievalMethod === 'data') {
- value = elementControllers[require];
+ if (!value) {
+ var dataName = '$' + name + 'Controller';
+ value = inheritType ? $element.inheritedData(dataName) : $element.data(dataName);
}
- value = value || $element[retrievalMethod]('$' + require + 'Controller');
if (!value && !optional) {
throw $compileMinErr('ctreq',
"Controller '{0}', required by directive '{1}', can't be found!",
- require, directiveName);
+ name, directiveName);
}
- return value;
} else if (isArray(require)) {
value = [];
- forEach(require, function(require) {
- value.push(getControllers(directiveName, require, $element, elementControllers));
- });
+ for (var i = 0, ii = require.length; i < ii; i++) {
+ value[i] = getControllers(directiveName, require[i], $element, elementControllers);
+ }
}
- return value;
- }
-
-
- function nodeLinkFn(childLinkFn, scope, linkNode, $rootElement, boundTranscludeFn) {
- var attrs, $element, i, ii, linkFn, controller, isolateScope, elementControllers = {}, transcludeFn;
- attrs = (compileNode === linkNode)
- ? templateAttrs
- : shallowCopy(templateAttrs, new Attributes(jqLite(linkNode), templateAttrs.$attr));
- $element = attrs.$$element;
-
- if (newIsolateScopeDirective) {
- var LOCAL_REGEXP = /^\s*([@=&])(\??)\s*(\w*)\s*$/;
+ return value || null;
+ }
- isolateScope = scope.$new(true);
+ function setupControllers($element, attrs, transcludeFn, controllerDirectives, isolateScope, scope) {
+ var elementControllers = createMap();
+ for (var controllerKey in controllerDirectives) {
+ var directive = controllerDirectives[controllerKey];
+ var locals = {
+ $scope: directive === newIsolateScopeDirective || directive.$$isolateScope ? isolateScope : scope,
+ $element: $element,
+ $attrs: attrs,
+ $transclude: transcludeFn
+ };
- if (templateDirective && (templateDirective === newIsolateScopeDirective ||
- templateDirective === newIsolateScopeDirective.$$originalDirective)) {
- $element.data('$isolateScope', isolateScope);
- } else {
- $element.data('$isolateScopeNoTemplate', isolateScope);
+ var controller = directive.controller;
+ if (controller == '@') {
+ controller = attrs[directive.name];
}
+ var controllerInstance = $controller(controller, locals, true, directive.controllerAs);
+ // For directives with element transclusion the element is a comment,
+ // but jQuery .data doesn't support attaching data to comment nodes as it's hard to
+ // clean up (http://bugs.jquery.com/ticket/8335).
+ // Instead, we save the controllers for the element in a local hash and attach to .data
+ // later, once we have the actual element.
+ elementControllers[directive.name] = controllerInstance;
+ if (!hasElementTranscludeDirective) {
+ $element.data('$' + directive.name + 'Controller', controllerInstance.instance);
+ }
+ }
+ return elementControllers;
+ }
- safeAddClass($element, 'ng-isolate-scope');
-
- forEach(newIsolateScopeDirective.scope, function(definition, scopeName) {
- var match = definition.match(LOCAL_REGEXP) || [],
- attrName = match[3] || scopeName,
- optional = (match[2] == '?'),
- mode = match[1], // @, =, or &
- lastValue,
- parentGet, parentSet, compare;
-
- isolateScope.$$isolateBindings[scopeName] = mode + attrName;
-
- switch (mode) {
+ function nodeLinkFn(childLinkFn, scope, linkNode, $rootElement, boundTranscludeFn,
+ thisLinkFn) {
+ var i, ii, linkFn, controller, isolateScope, elementControllers, transcludeFn, $element,
+ attrs;
- case '@':
- attrs.$observe(attrName, function(value) {
- isolateScope[scopeName] = value;
- });
- attrs.$$observers[attrName].$$scope = scope;
- if( attrs[attrName] ) {
- // If the attribute has been provided then we trigger an interpolation to ensure
- // the value is there for use in the link fn
- isolateScope[scopeName] = $interpolate(attrs[attrName])(scope);
- }
- break;
+ if (compileNode === linkNode) {
+ attrs = templateAttrs;
+ $element = templateAttrs.$$element;
+ } else {
+ $element = jqLite(linkNode);
+ attrs = new Attributes($element, templateAttrs);
+ }
- case '=':
- if (optional && !attrs[attrName]) {
- return;
- }
- parentGet = $parse(attrs[attrName]);
- if (parentGet.literal) {
- compare = equals;
- } else {
- compare = function(a,b) { return a === b || (a !== a && b !== b); };
- }
- parentSet = parentGet.assign || function() {
- // reset the change, or we will throw this exception on every $digest
- lastValue = isolateScope[scopeName] = parentGet(scope);
- throw $compileMinErr('nonassign',
- "Expression '{0}' used with directive '{1}' is non-assignable!",
- attrs[attrName], newIsolateScopeDirective.name);
- };
- lastValue = isolateScope[scopeName] = parentGet(scope);
- isolateScope.$watch(function parentValueWatch() {
- var parentValue = parentGet(scope);
- if (!compare(parentValue, isolateScope[scopeName])) {
- // we are out of sync and need to copy
- if (!compare(parentValue, lastValue)) {
- // parent changed and it has precedence
- isolateScope[scopeName] = parentValue;
- } else {
- // if the parent can be assigned then do so
- parentSet(scope, parentValue = isolateScope[scopeName]);
- }
- }
- return lastValue = parentValue;
- }, null, parentGet.literal);
- break;
-
- case '&':
- parentGet = $parse(attrs[attrName]);
- isolateScope[scopeName] = function(locals) {
- return parentGet(scope, locals);
- };
- break;
+ if (newIsolateScopeDirective) {
+ isolateScope = scope.$new(true);
+ }
- default:
- throw $compileMinErr('iscp',
- "Invalid isolate scope definition for directive '{0}'." +
- " Definition: {... {1}: '{2}' ...}",
- newIsolateScopeDirective.name, scopeName, definition);
- }
- });
+ if (boundTranscludeFn) {
+ // track `boundTranscludeFn` so it can be unwrapped if `transcludeFn`
+ // is later passed as `parentBoundTranscludeFn` to `publicLinkFn`
+ transcludeFn = controllersBoundTransclude;
+ transcludeFn.$$boundTransclude = boundTranscludeFn;
}
- transcludeFn = boundTranscludeFn && controllersBoundTransclude;
+
if (controllerDirectives) {
- forEach(controllerDirectives, function(directive) {
- var locals = {
- $scope: directive === newIsolateScopeDirective || directive.$$isolateScope ? isolateScope : scope,
- $element: $element,
- $attrs: attrs,
- $transclude: transcludeFn
- }, controllerInstance;
-
- controller = directive.controller;
- if (controller == '@') {
- controller = attrs[directive.name];
- }
+ elementControllers = setupControllers($element, attrs, transcludeFn, controllerDirectives, isolateScope, scope);
+ }
- controllerInstance = $controller(controller, locals);
- // For directives with element transclusion the element is a comment,
- // but jQuery .data doesn't support attaching data to comment nodes as it's hard to
- // clean up (http://bugs.jquery.com/ticket/8335).
- // Instead, we save the controllers for the element in a local hash and attach to .data
- // later, once we have the actual element.
- elementControllers[directive.name] = controllerInstance;
- if (!hasElementTranscludeDirective) {
- $element.data('$' + directive.name + 'Controller', controllerInstance);
+ if (newIsolateScopeDirective) {
+ // Initialize isolate scope bindings for new isolate scope directive.
+ compile.$$addScopeInfo($element, isolateScope, true, !(templateDirective && (templateDirective === newIsolateScopeDirective ||
+ templateDirective === newIsolateScopeDirective.$$originalDirective)));
+ compile.$$addScopeClass($element, true);
+ isolateScope.$$isolateBindings =
+ newIsolateScopeDirective.$$isolateBindings;
+ initializeDirectiveBindings(scope, attrs, isolateScope,
+ isolateScope.$$isolateBindings,
+ newIsolateScopeDirective, isolateScope);
+ }
+ if (elementControllers) {
+ // Initialize bindToController bindings for new/isolate scopes
+ var scopeDirective = newIsolateScopeDirective || newScopeDirective;
+ var bindings;
+ var controllerForBindings;
+ if (scopeDirective && elementControllers[scopeDirective.name]) {
+ bindings = scopeDirective.$$bindings.bindToController;
+ controller = elementControllers[scopeDirective.name];
+
+ if (controller && controller.identifier && bindings) {
+ controllerForBindings = controller;
+ thisLinkFn.$$destroyBindings =
+ initializeDirectiveBindings(scope, attrs, controller.instance,
+ bindings, scopeDirective);
}
-
- if (directive.controllerAs) {
- locals.$scope[directive.controllerAs] = controllerInstance;
+ }
+ for (i in elementControllers) {
+ controller = elementControllers[i];
+ var controllerResult = controller();
+
+ if (controllerResult !== controller.instance) {
+ // If the controller constructor has a return value, overwrite the instance
+ // from setupControllers and update the element data
+ controller.instance = controllerResult;
+ $element.data('$' + i + 'Controller', controllerResult);
+ if (controller === controllerForBindings) {
+ // Remove and re-install bindToController bindings
+ thisLinkFn.$$destroyBindings();
+ thisLinkFn.$$destroyBindings =
+ initializeDirectiveBindings(scope, attrs, controllerResult, bindings, scopeDirective);
+ }
}
- });
+ }
}
// PRELINKING
- for(i = 0, ii = preLinkFns.length; i < ii; i++) {
- try {
- linkFn = preLinkFns[i];
- linkFn(linkFn.isolateScope ? isolateScope : scope, $element, attrs,
- linkFn.require && getControllers(linkFn.directiveName, linkFn.require, $element, elementControllers), transcludeFn);
- } catch (e) {
- $exceptionHandler(e, startingTag($element));
- }
+ for (i = 0, ii = preLinkFns.length; i < ii; i++) {
+ linkFn = preLinkFns[i];
+ invokeLinkFn(linkFn,
+ linkFn.isolateScope ? isolateScope : scope,
+ $element,
+ attrs,
+ linkFn.require && getControllers(linkFn.directiveName, linkFn.require, $element, elementControllers),
+ transcludeFn
+ );
}
// RECURSION
@@ -6746,22 +8145,25 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
childLinkFn && childLinkFn(scopeToChild, linkNode.childNodes, undefined, boundTranscludeFn);
// POSTLINKING
- for(i = postLinkFns.length - 1; i >= 0; i--) {
- try {
- linkFn = postLinkFns[i];
- linkFn(linkFn.isolateScope ? isolateScope : scope, $element, attrs,
- linkFn.require && getControllers(linkFn.directiveName, linkFn.require, $element, elementControllers), transcludeFn);
- } catch (e) {
- $exceptionHandler(e, startingTag($element));
- }
+ for (i = postLinkFns.length - 1; i >= 0; i--) {
+ linkFn = postLinkFns[i];
+ invokeLinkFn(linkFn,
+ linkFn.isolateScope ? isolateScope : scope,
+ $element,
+ attrs,
+ linkFn.require && getControllers(linkFn.directiveName, linkFn.require, $element, elementControllers),
+ transcludeFn
+ );
}
// This is the function that is injected as `$transclude`.
- function controllersBoundTransclude(scope, cloneAttachFn) {
+ // Note: all arguments are optional!
+ function controllersBoundTransclude(scope, cloneAttachFn, futureParentElement) {
var transcludeControllers;
- // no scope passed
- if (arguments.length < 2) {
+ // No scope passed in:
+ if (!isScope(scope)) {
+ futureParentElement = cloneAttachFn;
cloneAttachFn = scope;
scope = undefined;
}
@@ -6769,8 +8171,10 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
if (hasElementTranscludeDirective) {
transcludeControllers = elementControllers;
}
-
- return boundTranscludeFn(scope, cloneAttachFn, transcludeControllers);
+ if (!futureParentElement) {
+ futureParentElement = hasElementTranscludeDirective ? $element.parent() : $element;
+ }
+ return boundTranscludeFn(scope, cloneAttachFn, transcludeControllers, futureParentElement, scopeToChild);
}
}
}
@@ -6801,11 +8205,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
if (name === ignoreDirective) return null;
var match = null;
if (hasDirectives.hasOwnProperty(name)) {
- for(var directive, directives = $injector.get(name + Suffix),
- i = 0, ii = directives.length; i<ii; i++) {
+ for (var directive, directives = $injector.get(name + Suffix),
+ i = 0, ii = directives.length; i < ii; i++) {
try {
directive = directives[i];
- if ( (maxPriority === undefined || maxPriority > directive.priority) &&
+ if ((maxPriority === undefined || maxPriority > directive.priority) &&
directive.restrict.indexOf(location) != -1) {
if (startAttrName) {
directive = inherit(directive, {$$start: startAttrName, $$end: endAttrName});
@@ -6813,7 +8217,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
tDirectives.push(directive);
match = directive;
}
- } catch(e) { $exceptionHandler(e); }
+ } catch (e) { $exceptionHandler(e); }
}
}
return match;
@@ -6821,6 +8225,27 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
/**
+ * looks up the directive and returns true if it is a multi-element directive,
+ * and therefore requires DOM nodes between -start and -end markers to be grouped
+ * together.
+ *
+ * @param {string} name name of the directive to look up.
+ * @returns true if directive was registered as multi-element.
+ */
+ function directiveIsMultiElement(name) {
+ if (hasDirectives.hasOwnProperty(name)) {
+ for (var directive, directives = $injector.get(name + Suffix),
+ i = 0, ii = directives.length; i < ii; i++) {
+ directive = directives[i];
+ if (directive.multiElement) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
* When the element is replaced with HTML template then the new attributes
* on the template need to be merged with the existing attributes in the DOM.
* The desired effect is to have both of the attributes present.
@@ -6869,18 +8294,18 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
afterTemplateChildLinkFn,
beforeTemplateCompileNode = $compileNode[0],
origAsyncDirective = directives.shift(),
- // The fact that we have to copy and patch the directive seems wrong!
- derivedSyncDirective = extend({}, origAsyncDirective, {
+ derivedSyncDirective = inherit(origAsyncDirective, {
templateUrl: null, transclude: null, replace: null, $$originalDirective: origAsyncDirective
}),
templateUrl = (isFunction(origAsyncDirective.templateUrl))
? origAsyncDirective.templateUrl($compileNode, tAttrs)
- : origAsyncDirective.templateUrl;
+ : origAsyncDirective.templateUrl,
+ templateNamespace = origAsyncDirective.templateNamespace;
$compileNode.empty();
- $http.get($sce.getTrustedResourceUrl(templateUrl), {cache: $templateCache}).
- success(function(content) {
+ $templateRequest(templateUrl)
+ .then(function(content) {
var compileNode, tempTemplateAttrs, $template, childBoundTranscludeFn;
content = denormalizeTemplate(content);
@@ -6889,11 +8314,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
if (jqLiteIsTextNode(content)) {
$template = [];
} else {
- $template = jqLite(trim(content));
+ $template = removeComments(wrapTemplate(templateNamespace, trim(content)));
}
compileNode = $template[0];
- if ($template.length != 1 || compileNode.nodeType !== 1) {
+ if ($template.length != 1 || compileNode.nodeType !== NODE_TYPE_ELEMENT) {
throw $compileMinErr('tplrt',
"Template for directive '{0}' must have exactly one root element. {1}",
origAsyncDirective.name, templateUrl);
@@ -6925,13 +8350,15 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
});
afterTemplateChildLinkFn = compileNodes($compileNode[0].childNodes, childTranscludeFn);
- while(linkQueue.length) {
+ while (linkQueue.length) {
var scope = linkQueue.shift(),
beforeTemplateLinkNode = linkQueue.shift(),
linkRootElement = linkQueue.shift(),
boundTranscludeFn = linkQueue.shift(),
linkNode = $compileNode[0];
+ if (scope.$$destroyed) continue;
+
if (beforeTemplateLinkNode !== beforeTemplateCompileNode) {
var oldClasses = beforeTemplateLinkNode.className;
@@ -6940,7 +8367,6 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
// it was cloned therefore we have to clone as well.
linkNode = jqLiteClone(compileNode);
}
-
replaceWith(linkRootElement, jqLite(beforeTemplateLinkNode), linkNode);
// Copy in CSS classes from original node
@@ -6952,26 +8378,25 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
childBoundTranscludeFn = boundTranscludeFn;
}
afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, linkNode, $rootElement,
- childBoundTranscludeFn);
+ childBoundTranscludeFn, afterTemplateNodeLinkFn);
}
linkQueue = null;
- }).
- error(function(response, code, headers, config) {
- throw $compileMinErr('tpload', 'Failed to load template: {0}', config.url);
});
return function delayedNodeLinkFn(ignoreChildLinkFn, scope, node, rootElement, boundTranscludeFn) {
var childBoundTranscludeFn = boundTranscludeFn;
+ if (scope.$$destroyed) return;
if (linkQueue) {
- linkQueue.push(scope);
- linkQueue.push(node);
- linkQueue.push(rootElement);
- linkQueue.push(childBoundTranscludeFn);
+ linkQueue.push(scope,
+ node,
+ rootElement,
+ childBoundTranscludeFn);
} else {
if (afterTemplateNodeLinkFn.transcludeOnThisElement) {
childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude, boundTranscludeFn);
}
- afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, node, rootElement, childBoundTranscludeFn);
+ afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, node, rootElement, childBoundTranscludeFn,
+ afterTemplateNodeLinkFn);
}
};
}
@@ -6987,40 +8412,61 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
return a.index - b.index;
}
-
function assertNoDuplicate(what, previousDirective, directive, element) {
+
+ function wrapModuleNameIfDefined(moduleName) {
+ return moduleName ?
+ (' (module: ' + moduleName + ')') :
+ '';
+ }
+
if (previousDirective) {
- throw $compileMinErr('multidir', 'Multiple directives [{0}, {1}] asking for {2} on: {3}',
- previousDirective.name, directive.name, what, startingTag(element));
- }
- }
-
-
- function addTextInterpolateDirective(directives, text) {
- var interpolateFn = $interpolate(text, true);
- if (interpolateFn) {
- directives.push({
- priority: 0,
- compile: function textInterpolateCompileFn(templateNode) {
- // when transcluding a template that has bindings in the root
- // then we don't have a parent and should do this in the linkFn
- var parent = templateNode.parent(), hasCompileParent = parent.length;
- if (hasCompileParent) safeAddClass(templateNode.parent(), 'ng-binding');
-
- return function textInterpolateLinkFn(scope, node) {
- var parent = node.parent(),
- bindings = parent.data('$binding') || [];
- bindings.push(interpolateFn);
- parent.data('$binding', bindings);
- if (!hasCompileParent) safeAddClass(parent, 'ng-binding');
- scope.$watch(interpolateFn, function interpolateFnWatchAction(value) {
- node[0].nodeValue = value;
- });
- };
- }
- });
- }
+ throw $compileMinErr('multidir', 'Multiple directives [{0}{1}, {2}{3}] asking for {4} on: {5}',
+ previousDirective.name, wrapModuleNameIfDefined(previousDirective.$$moduleName),
+ directive.name, wrapModuleNameIfDefined(directive.$$moduleName), what, startingTag(element));
+ }
+ }
+
+
+ function addTextInterpolateDirective(directives, text) {
+ var interpolateFn = $interpolate(text, true);
+ if (interpolateFn) {
+ directives.push({
+ priority: 0,
+ compile: function textInterpolateCompileFn(templateNode) {
+ var templateNodeParent = templateNode.parent(),
+ hasCompileParent = !!templateNodeParent.length;
+
+ // When transcluding a template that has bindings in the root
+ // we don't have a parent and thus need to add the class during linking fn.
+ if (hasCompileParent) compile.$$addBindingClass(templateNodeParent);
+
+ return function textInterpolateLinkFn(scope, node) {
+ var parent = node.parent();
+ if (!hasCompileParent) compile.$$addBindingClass(parent);
+ compile.$$addBindingInfo(parent, interpolateFn.expressions);
+ scope.$watch(interpolateFn, function interpolateFnWatchAction(value) {
+ node[0].nodeValue = value;
+ });
+ };
+ }
+ });
+ }
+ }
+
+
+ function wrapTemplate(type, template) {
+ type = lowercase(type || 'html');
+ switch (type) {
+ case 'svg':
+ case 'math':
+ var wrapper = document.createElement('div');
+ wrapper.innerHTML = '<' + type + '>' + template + '</' + type + '>';
+ return wrapper.childNodes[0].childNodes;
+ default:
+ return template;
}
+ }
function getTrustedContext(node, attrNormalizedName) {
@@ -7030,22 +8476,25 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
var tag = nodeName_(node);
// maction[xlink:href] can source SVG. It's not limited to <maction>.
if (attrNormalizedName == "xlinkHref" ||
- (tag == "FORM" && attrNormalizedName == "action") ||
- (tag != "IMG" && (attrNormalizedName == "src" ||
+ (tag == "form" && attrNormalizedName == "action") ||
+ (tag != "img" && (attrNormalizedName == "src" ||
attrNormalizedName == "ngSrc"))) {
return $sce.RESOURCE_URL;
}
}
- function addAttrInterpolateDirective(node, directives, value, name) {
- var interpolateFn = $interpolate(value, true);
+ function addAttrInterpolateDirective(node, directives, value, name, allOrNothing) {
+ var trustedContext = getTrustedContext(node, name);
+ allOrNothing = ALL_OR_NOTHING_ATTRS[name] || allOrNothing;
+
+ var interpolateFn = $interpolate(value, true, trustedContext, allOrNothing);
// no interpolation found -> ignore
if (!interpolateFn) return;
- if (name === "multiple" && nodeName_(node) === "SELECT") {
+ if (name === "multiple" && nodeName_(node) === "select") {
throw $compileMinErr("selmulti",
"Binding to the 'multiple' attribute is not supported. Element: {0}",
startingTag(node));
@@ -7064,17 +8513,25 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
"ng- versions (such as ng-click instead of onclick) instead.");
}
- // we need to interpolate again, in case the attribute value has been updated
- // (e.g. by another directive's compile function)
- interpolateFn = $interpolate(attr[name], true, getTrustedContext(node, name));
+ // If the attribute has changed since last $interpolate()ed
+ var newValue = attr[name];
+ if (newValue !== value) {
+ // we need to interpolate again since the attribute value has been updated
+ // (e.g. by another directive's compile function)
+ // ensure unset/empty values make interpolateFn falsy
+ interpolateFn = newValue && $interpolate(newValue, true, trustedContext, allOrNothing);
+ value = newValue;
+ }
// if attribute was updated so that there is no interpolation going on we don't want to
// register any observers
if (!interpolateFn) return;
- // TODO(i): this should likely be attr.$set(name, iterpolateFn(scope) so that we reset the
- // actual attr value
+ // initialize attr object so that it's ready in case we need the value for isolate
+ // scope initialization, otherwise the value would not be available from isolate
+ // directive's linking fn during linking phase
attr[name] = interpolateFn(scope);
+
($$observers[name] || ($$observers[name] = [])).$$inter = true;
(attr.$$observers && attr.$$observers[name].$$scope || scope).
$watch(interpolateFn, function interpolateFnWatchAction(newValue, oldValue) {
@@ -7084,7 +8541,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
//skip animations when the first digest occurs (when
//both the new and the old values are the same) since
//the CSS classes are the non-interpolated values
- if(name === 'class' && newValue != oldValue) {
+ if (name === 'class' && newValue != oldValue) {
attr.$updateClass(newValue, oldValue);
} else {
attr.$set(name, newValue);
@@ -7114,7 +8571,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
i, ii;
if ($rootElement) {
- for(i = 0, ii = $rootElement.length; i < ii; i++) {
+ for (i = 0, ii = $rootElement.length; i < ii; i++) {
if ($rootElement[i] == firstElementToRemove) {
$rootElement[i++] = newNode;
for (var j = i, j2 = j + removeCount - 1,
@@ -7127,6 +8584,13 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
}
}
$rootElement.length -= removeCount - 1;
+
+ // If the replaced element is also the jQuery .context then replace it
+ // .context is a deprecated jQuery api, so we should set it only when jQuery set it
+ // http://api.jquery.com/context/
+ if ($rootElement.context === firstElementToRemove) {
+ $rootElement.context = newNode;
+ }
break;
}
}
@@ -7135,9 +8599,35 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
if (parent) {
parent.replaceChild(newNode, firstElementToRemove);
}
+
+ // TODO(perf): what's this document fragment for? is it needed? can we at least reuse it?
var fragment = document.createDocumentFragment();
fragment.appendChild(firstElementToRemove);
- newNode[jqLite.expando] = firstElementToRemove[jqLite.expando];
+
+ if (jqLite.hasData(firstElementToRemove)) {
+ // Copy over user data (that includes Angular's $scope etc.). Don't copy private
+ // data here because there's no public interface in jQuery to do that and copying over
+ // event listeners (which is the main use of private data) wouldn't work anyway.
+ jqLite(newNode).data(jqLite(firstElementToRemove).data());
+
+ // Remove data of the replaced element. We cannot just call .remove()
+ // on the element it since that would deallocate scope that is needed
+ // for the new node. Instead, remove the data "manually".
+ if (!jQuery) {
+ delete jqLite.cache[firstElementToRemove[jqLite.expando]];
+ } else {
+ // jQuery 2.x doesn't expose the data storage. Use jQuery.cleanData to clean up after
+ // the replaced element. The cleanData version monkey-patched by Angular would cause
+ // the scope to be trashed and we do need the very same scope to work with the new
+ // element. However, we cannot just cache the non-patched version and use it here as
+ // that would break if another library patches the method after Angular does (one
+ // example is jQuery UI). Instead, set a flag indicating scope destroying should be
+ // skipped this one time.
+ skipDestroyOnNextJQueryCleanData = true;
+ jQuery.cleanData([firstElementToRemove]);
+ }
+ }
+
for (var k = 1, kk = elementsToRemove.length; k < kk; k++) {
var element = elementsToRemove[k];
jqLite(element).remove(); // must do this way to clean up expando
@@ -7153,10 +8643,123 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
function cloneAndAnnotateFn(fn, annotation) {
return extend(function() { return fn.apply(null, arguments); }, fn, annotation);
}
+
+
+ function invokeLinkFn(linkFn, scope, $element, attrs, controllers, transcludeFn) {
+ try {
+ linkFn(scope, $element, attrs, controllers, transcludeFn);
+ } catch (e) {
+ $exceptionHandler(e, startingTag($element));
+ }
+ }
+
+
+ // Set up $watches for isolate scope and controller bindings. This process
+ // only occurs for isolate scopes and new scopes with controllerAs.
+ function initializeDirectiveBindings(scope, attrs, destination, bindings,
+ directive, newScope) {
+ var onNewScopeDestroyed;
+ forEach(bindings, function(definition, scopeName) {
+ var attrName = definition.attrName,
+ optional = definition.optional,
+ mode = definition.mode, // @, =, or &
+ lastValue,
+ parentGet, parentSet, compare;
+
+ if (!hasOwnProperty.call(attrs, attrName)) {
+ // In the case of user defined a binding with the same name as a method in Object.prototype but didn't set
+ // the corresponding attribute. We need to make sure subsequent code won't access to the prototype function
+ attrs[attrName] = undefined;
+ }
+
+ switch (mode) {
+
+ case '@':
+ if (!attrs[attrName] && !optional) {
+ destination[scopeName] = undefined;
+ }
+
+ attrs.$observe(attrName, function(value) {
+ destination[scopeName] = value;
+ });
+ attrs.$$observers[attrName].$$scope = scope;
+ if (attrs[attrName]) {
+ // If the attribute has been provided then we trigger an interpolation to ensure
+ // the value is there for use in the link fn
+ destination[scopeName] = $interpolate(attrs[attrName])(scope);
+ }
+ break;
+
+ case '=':
+ if (optional && !attrs[attrName]) {
+ return;
+ }
+ parentGet = $parse(attrs[attrName]);
+
+ if (parentGet.literal) {
+ compare = equals;
+ } else {
+ compare = function(a, b) { return a === b || (a !== a && b !== b); };
+ }
+ parentSet = parentGet.assign || function() {
+ // reset the change, or we will throw this exception on every $digest
+ lastValue = destination[scopeName] = parentGet(scope);
+ throw $compileMinErr('nonassign',
+ "Expression '{0}' used with directive '{1}' is non-assignable!",
+ attrs[attrName], directive.name);
+ };
+ lastValue = destination[scopeName] = parentGet(scope);
+ var parentValueWatch = function parentValueWatch(parentValue) {
+ if (!compare(parentValue, destination[scopeName])) {
+ // we are out of sync and need to copy
+ if (!compare(parentValue, lastValue)) {
+ // parent changed and it has precedence
+ destination[scopeName] = parentValue;
+ } else {
+ // if the parent can be assigned then do so
+ parentSet(scope, parentValue = destination[scopeName]);
+ }
+ }
+ return lastValue = parentValue;
+ };
+ parentValueWatch.$stateful = true;
+ var unwatch;
+ if (definition.collection) {
+ unwatch = scope.$watchCollection(attrs[attrName], parentValueWatch);
+ } else {
+ unwatch = scope.$watch($parse(attrs[attrName], parentValueWatch), null, parentGet.literal);
+ }
+ onNewScopeDestroyed = (onNewScopeDestroyed || []);
+ onNewScopeDestroyed.push(unwatch);
+ break;
+
+ case '&':
+ parentGet = $parse(attrs[attrName]);
+
+ // Don't assign noop to destination if expression is not valid
+ if (parentGet === noop && optional) break;
+
+ destination[scopeName] = function(locals) {
+ return parentGet(scope, locals);
+ };
+ break;
+ }
+ });
+ var destroyBindings = onNewScopeDestroyed ? function destroyBindings() {
+ for (var i = 0, ii = onNewScopeDestroyed.length; i < ii; ++i) {
+ onNewScopeDestroyed[i]();
+ }
+ } : noop;
+ if (newScope && destroyBindings !== noop) {
+ newScope.$on('$destroy', destroyBindings);
+ return noop;
+ }
+ return destroyBindings;
+ }
}];
}
-var PREFIX_REGEXP = /^(x[\:\-_]|data[\:\-_])/i;
+var PREFIX_REGEXP = /^((?:x|data)[\:\-_])/i;
/**
* Converts all accepted directives format into proper directive name.
* @param name Name to normalize
@@ -7215,7 +8818,7 @@ function nodesetLinkingFn(
/* NodeList */ nodeList,
/* Element */ rootElement,
/* function(Function) */ boundTranscludeFn
-){}
+) {}
function directiveLinkingFn(
/* nodesetLinkingFn */ nodesetLinkingFn,
@@ -7223,7 +8826,7 @@ function directiveLinkingFn(
/* Node */ node,
/* Element */ rootElement,
/* function(Function) */ boundTranscludeFn
-){}
+) {}
function tokenDifference(str1, str2) {
var values = '',
@@ -7231,16 +8834,46 @@ function tokenDifference(str1, str2) {
tokens2 = str2.split(/\s+/);
outer:
- for(var i = 0; i < tokens1.length; i++) {
+ for (var i = 0; i < tokens1.length; i++) {
var token = tokens1[i];
- for(var j = 0; j < tokens2.length; j++) {
- if(token == tokens2[j]) continue outer;
+ for (var j = 0; j < tokens2.length; j++) {
+ if (token == tokens2[j]) continue outer;
}
values += (values.length > 0 ? ' ' : '') + token;
}
return values;
}
+function removeComments(jqNodes) {
+ jqNodes = jqLite(jqNodes);
+ var i = jqNodes.length;
+
+ if (i <= 1) {
+ return jqNodes;
+ }
+
+ while (i--) {
+ var node = jqNodes[i];
+ if (node.nodeType === NODE_TYPE_COMMENT) {
+ splice.call(jqNodes, i, 1);
+ }
+ }
+ return jqNodes;
+}
+
+var $controllerMinErr = minErr('$controller');
+
+
+var CNTRL_REG = /^(\S+)(\s+as\s+(\w+))?$/;
+function identifierForController(controller, ident) {
+ if (ident && isString(ident)) return ident;
+ if (isString(controller)) {
+ var match = CNTRL_REG.exec(controller);
+ if (match) return match[3];
+ }
+}
+
+
/**
* @ngdoc provider
* @name $controllerProvider
@@ -7253,8 +8886,7 @@ function tokenDifference(str1, str2) {
*/
function $ControllerProvider() {
var controllers = {},
- CNTRL_REG = /^(\S+)(\s+as\s+(\w+))?$/;
-
+ globals = false;
/**
* @ngdoc method
@@ -7273,6 +8905,15 @@ function $ControllerProvider() {
}
};
+ /**
+ * @ngdoc method
+ * @name $controllerProvider#allowGlobals
+ * @description If called, allows `$controller` to find controller constructors on `window`
+ */
+ this.allowGlobals = function() {
+ globals = true;
+ };
+
this.$get = ['$injector', '$window', function($injector, $window) {
@@ -7287,7 +8928,12 @@ function $ControllerProvider() {
*
* * check if a controller with given name is registered via `$controllerProvider`
* * check if evaluating the string on the current scope returns a constructor
- * * check `window[constructor]` on the global `window` object
+ * * if $controllerProvider#allowGlobals, check `window[constructor]` on the global
+ * `window` object (not recommended)
+ *
+ * The string can use the `controller as property` syntax, where the controller instance is published
+ * as the specified property on the `scope`; the `scope` must be injected into `locals` param for this
+ * to work correctly.
*
* @param {Object} locals Injection locals for Controller.
* @return {Object} Instance of given controller.
@@ -7298,34 +8944,91 @@ function $ControllerProvider() {
* It's just a simple call to {@link auto.$injector $injector}, but extracted into
* a service, so that one can override this service with [BC version](https://gist.github.com/1649788).
*/
- return function(expression, locals) {
+ return function(expression, locals, later, ident) {
+ // PRIVATE API:
+ // param `later` --- indicates that the controller's constructor is invoked at a later time.
+ // If true, $controller will allocate the object with the correct
+ // prototype chain, but will not invoke the controller until a returned
+ // callback is invoked.
+ // param `ident` --- An optional label which overrides the label parsed from the controller
+ // expression, if any.
var instance, match, constructor, identifier;
+ later = later === true;
+ if (ident && isString(ident)) {
+ identifier = ident;
+ }
- if(isString(expression)) {
- match = expression.match(CNTRL_REG),
+ if (isString(expression)) {
+ match = expression.match(CNTRL_REG);
+ if (!match) {
+ throw $controllerMinErr('ctrlfmt',
+ "Badly formed controller string '{0}'. " +
+ "Must match `__name__ as __id__` or `__name__`.", expression);
+ }
constructor = match[1],
- identifier = match[3];
+ identifier = identifier || match[3];
expression = controllers.hasOwnProperty(constructor)
? controllers[constructor]
- : getter(locals.$scope, constructor, true) || getter($window, constructor, true);
+ : getter(locals.$scope, constructor, true) ||
+ (globals ? getter($window, constructor, true) : undefined);
assertArgFn(expression, constructor, true);
}
- instance = $injector.instantiate(expression, locals);
-
- if (identifier) {
- if (!(locals && typeof locals.$scope === 'object')) {
- throw minErr('$controller')('noscp',
- "Cannot export controller '{0}' as '{1}'! No $scope object provided via `locals`.",
- constructor || expression.name, identifier);
+ if (later) {
+ // Instantiate controller later:
+ // This machinery is used to create an instance of the object before calling the
+ // controller's constructor itself.
+ //
+ // This allows properties to be added to the controller before the constructor is
+ // invoked. Primarily, this is used for isolate scope bindings in $compile.
+ //
+ // This feature is not intended for use by applications, and is thus not documented
+ // publicly.
+ // Object creation: http://jsperf.com/create-constructor/2
+ var controllerPrototype = (isArray(expression) ?
+ expression[expression.length - 1] : expression).prototype;
+ instance = Object.create(controllerPrototype || null);
+
+ if (identifier) {
+ addIdentifier(locals, identifier, instance, constructor || expression.name);
}
- locals.$scope[identifier] = instance;
+ var instantiate;
+ return instantiate = extend(function() {
+ var result = $injector.invoke(expression, instance, locals, constructor);
+ if (result !== instance && (isObject(result) || isFunction(result))) {
+ instance = result;
+ if (identifier) {
+ // If result changed, re-assign controllerAs value to scope.
+ addIdentifier(locals, identifier, instance, constructor || expression.name);
+ }
+ }
+ return instance;
+ }, {
+ instance: instance,
+ identifier: identifier
+ });
+ }
+
+ instance = $injector.instantiate(expression, locals, constructor);
+
+ if (identifier) {
+ addIdentifier(locals, identifier, instance, constructor || expression.name);
}
return instance;
};
+
+ function addIdentifier(locals, identifier, instance, name) {
+ if (!(locals && isObject(locals.$scope))) {
+ throw minErr('$controller')('noscp',
+ "Cannot export controller '{0}' as '{1}'! No $scope object provided via `locals`.",
+ name, identifier);
+ }
+
+ locals.$scope[identifier] = instance;
+ }
}];
}
@@ -7354,8 +9057,8 @@ function $ControllerProvider() {
</file>
</example>
*/
-function $DocumentProvider(){
- this.$get = ['$window', function(window){
+function $DocumentProvider() {
+ this.$get = ['$window', function(window) {
return jqLite(window.document);
}];
}
@@ -7376,8 +9079,8 @@ function $DocumentProvider(){
* ## Example:
*
* ```js
- * angular.module('exceptionOverride', []).factory('$exceptionHandler', function () {
- * return function (exception, cause) {
+ * angular.module('exceptionOverride', []).factory('$exceptionHandler', function() {
+ * return function(exception, cause) {
* exception.message += ' (caused by "' + cause + '")';
* throw exception;
* };
@@ -7387,6 +9090,14 @@ function $DocumentProvider(){
* This example will override the normal action of `$exceptionHandler`, to make angular
* exceptions fail hard when they happen, instead of just logging to the console.
*
+ * <hr />
+ * Note, that code executed in event-listeners (even those registered using jqLite's `on`/`bind`
+ * methods) does not delegate exceptions to the {@link ng.$exceptionHandler $exceptionHandler}
+ * (unless executed during a digest).
+ *
+ * If you wish, you can manually delegate exceptions, e.g.
+ * `try { ... } catch(e) { $exceptionHandler(e); }`
+ *
* @param {Error} exception Exception associated with the error.
* @param {string=} cause optional information about the context in which
* the error was thrown.
@@ -7400,6 +9111,153 @@ function $ExceptionHandlerProvider() {
}];
}
+var APPLICATION_JSON = 'application/json';
+var CONTENT_TYPE_APPLICATION_JSON = {'Content-Type': APPLICATION_JSON + ';charset=utf-8'};
+var JSON_START = /^\[|^\{(?!\{)/;
+var JSON_ENDS = {
+ '[': /]$/,
+ '{': /}$/
+};
+var JSON_PROTECTION_PREFIX = /^\)\]\}',?\n/;
+
+function serializeValue(v) {
+ if (isObject(v)) {
+ return isDate(v) ? v.toISOString() : toJson(v);
+ }
+ return v;
+}
+
+
+function $HttpParamSerializerProvider() {
+ /**
+ * @ngdoc service
+ * @name $httpParamSerializer
+ * @description
+ *
+ * Default {@link $http `$http`} params serializer that converts objects to strings
+ * according to the following rules:
+ *
+ * * `{'foo': 'bar'}` results in `foo=bar`
+ * * `{'foo': Date.now()}` results in `foo=2015-04-01T09%3A50%3A49.262Z` (`toISOString()` and encoded representation of a Date object)
+ * * `{'foo': ['bar', 'baz']}` results in `foo=bar&foo=baz` (repeated key for each array element)
+ * * `{'foo': {'bar':'baz'}}` results in `foo=%7B%22bar%22%3A%22baz%22%7D"` (stringified and encoded representation of an object)
+ *
+ * Note that serializer will sort the request parameters alphabetically.
+ * */
+
+ this.$get = function() {
+ return function ngParamSerializer(params) {
+ if (!params) return '';
+ var parts = [];
+ forEachSorted(params, function(value, key) {
+ if (value === null || isUndefined(value)) return;
+ if (isArray(value)) {
+ forEach(value, function(v, k) {
+ parts.push(encodeUriQuery(key) + '=' + encodeUriQuery(serializeValue(v)));
+ });
+ } else {
+ parts.push(encodeUriQuery(key) + '=' + encodeUriQuery(serializeValue(value)));
+ }
+ });
+
+ return parts.join('&');
+ };
+ };
+}
+
+function $HttpParamSerializerJQLikeProvider() {
+ /**
+ * @ngdoc service
+ * @name $httpParamSerializerJQLike
+ * @description
+ *
+ * Alternative {@link $http `$http`} params serializer that follows
+ * jQuery's [`param()`](http://api.jquery.com/jquery.param/) method logic.
+ * The serializer will also sort the params alphabetically.
+ *
+ * To use it for serializing `$http` request parameters, set it as the `paramSerializer` property:
+ *
+ * ```js
+ * $http({
+ * url: myUrl,
+ * method: 'GET',
+ * params: myParams,
+ * paramSerializer: '$httpParamSerializerJQLike'
+ * });
+ * ```
+ *
+ * It is also possible to set it as the default `paramSerializer` in the
+ * {@link $httpProvider#defaults `$httpProvider`}.
+ *
+ * Additionally, you can inject the serializer and use it explicitly, for example to serialize
+ * form data for submission:
+ *
+ * ```js
+ * .controller(function($http, $httpParamSerializerJQLike) {
+ * //...
+ *
+ * $http({
+ * url: myUrl,
+ * method: 'POST',
+ * data: $httpParamSerializerJQLike(myData),
+ * headers: {
+ * 'Content-Type': 'application/x-www-form-urlencoded'
+ * }
+ * });
+ *
+ * });
+ * ```
+ *
+ * */
+ this.$get = function() {
+ return function jQueryLikeParamSerializer(params) {
+ if (!params) return '';
+ var parts = [];
+ serialize(params, '', true);
+ return parts.join('&');
+
+ function serialize(toSerialize, prefix, topLevel) {
+ if (toSerialize === null || isUndefined(toSerialize)) return;
+ if (isArray(toSerialize)) {
+ forEach(toSerialize, function(value) {
+ serialize(value, prefix + '[]');
+ });
+ } else if (isObject(toSerialize) && !isDate(toSerialize)) {
+ forEachSorted(toSerialize, function(value, key) {
+ serialize(value, prefix +
+ (topLevel ? '' : '[') +
+ key +
+ (topLevel ? '' : ']'));
+ });
+ } else {
+ parts.push(encodeUriQuery(prefix) + '=' + encodeUriQuery(serializeValue(toSerialize)));
+ }
+ }
+ };
+ };
+}
+
+function defaultHttpResponseTransform(data, headers) {
+ if (isString(data)) {
+ // Strip json vulnerability protection prefix and trim whitespace
+ var tempData = data.replace(JSON_PROTECTION_PREFIX, '').trim();
+
+ if (tempData) {
+ var contentType = headers('Content-Type');
+ if ((contentType && (contentType.indexOf(APPLICATION_JSON) === 0)) || isJsonLike(tempData)) {
+ data = fromJson(tempData);
+ }
+ }
+ }
+
+ return data;
+}
+
+function isJsonLike(str) {
+ var jsonStart = str.match(JSON_START);
+ return jsonStart && JSON_ENDS[jsonStart[0]].test(str);
+}
+
/**
* Parse headers into key value object
*
@@ -7407,19 +9265,24 @@ function $ExceptionHandlerProvider() {
* @returns {Object} Parsed headers as key value object
*/
function parseHeaders(headers) {
- var parsed = {}, key, val, i;
-
- if (!headers) return parsed;
-
- forEach(headers.split('\n'), function(line) {
- i = line.indexOf(':');
- key = lowercase(trim(line.substr(0, i)));
- val = trim(line.substr(i + 1));
+ var parsed = createMap(), i;
+ function fillInParsed(key, val) {
if (key) {
parsed[key] = parsed[key] ? parsed[key] + ', ' + val : val;
}
- });
+ }
+
+ if (isString(headers)) {
+ forEach(headers.split('\n'), function(line) {
+ i = line.indexOf(':');
+ fillInParsed(lowercase(trim(line.substr(0, i))), trim(line.substr(i + 1)));
+ });
+ } else if (isObject(headers)) {
+ forEach(headers, function(headerVal, headerKey) {
+ fillInParsed(lowercase(headerKey), trim(headerVal));
+ });
+ }
return parsed;
}
@@ -7438,13 +9301,17 @@ function parseHeaders(headers) {
* - if called with no arguments returns an object containing all headers.
*/
function headersGetter(headers) {
- var headersObj = isObject(headers) ? headers : undefined;
+ var headersObj;
return function(name) {
if (!headersObj) headersObj = parseHeaders(headers);
if (name) {
- return headersObj[lowercase(name)] || null;
+ var value = headersObj[lowercase(name)];
+ if (value === void 0) {
+ value = null;
+ }
+ return value;
}
return headersObj;
@@ -7458,16 +9325,18 @@ function headersGetter(headers) {
* This function is used for both request and response transforming
*
* @param {*} data Data to transform.
- * @param {function(string=)} headers Http headers getter fn.
+ * @param {function(string=)} headers HTTP headers getter fn.
+ * @param {number} status HTTP status code of the response.
* @param {(Function|Array.<Function>)} fns Function or an array of functions.
* @returns {*} Transformed data.
*/
-function transformData(data, headers, fns) {
- if (isFunction(fns))
- return fns(data, headers);
+function transformData(data, headers, status, fns) {
+ if (isFunction(fns)) {
+ return fns(data, headers, status);
+ }
forEach(fns, function(fn) {
- data = fn(data, headers);
+ data = fn(data, headers, status);
});
return data;
@@ -7486,11 +9355,6 @@ function isSuccess(status) {
* Use `$httpProvider` to change the default behavior of the {@link ng.$http $http} service.
* */
function $HttpProvider() {
- var JSON_START = /^\s*(\[|\{[^\{])/,
- JSON_END = /[\}\]]\s*$/,
- PROTECTION_PREFIX = /^\)\]\}',?\n/,
- CONTENT_TYPE_APPLICATION_JSON = {'Content-Type': 'application/json;charset=utf-8'};
-
/**
* @ngdoc property
* @name $httpProvider#defaults
@@ -7498,6 +9362,11 @@ function $HttpProvider() {
*
* Object containing default values for all {@link ng.$http $http} requests.
*
+ * - **`defaults.cache`** - {Object} - an object built with {@link ng.$cacheFactory `$cacheFactory`}
+ * that will provide the cache for all requests who set their `cache` property to `true`.
+ * If you set the `defaults.cache = false` then only requests that specify their own custom
+ * cache object will be cached. See {@link $http#caching $http Caching} for more information.
+ *
* - **`defaults.xsrfCookieName`** - {string} - Name of cookie containing the XSRF token.
* Defaults value is `'XSRF-TOKEN'`.
*
@@ -7511,22 +9380,21 @@ function $HttpProvider() {
* - **`defaults.headers.post`**
* - **`defaults.headers.put`**
* - **`defaults.headers.patch`**
+ *
+ *
+ * - **`defaults.paramSerializer`** - `{string|function(Object<string,string>):string}` - A function
+ * used to the prepare string representation of request parameters (specified as an object).
+ * If specified as string, it is interpreted as a function registered with the {@link auto.$injector $injector}.
+ * Defaults to {@link ng.$httpParamSerializer $httpParamSerializer}.
+ *
**/
var defaults = this.defaults = {
// transform incoming response data
- transformResponse: [function(data) {
- if (isString(data)) {
- // strip json vulnerability protection prefix
- data = data.replace(PROTECTION_PREFIX, '');
- if (JSON_START.test(data) && JSON_END.test(data))
- data = fromJson(data);
- }
- return data;
- }],
+ transformResponse: [defaultHttpResponseTransform],
// transform outgoing request data
transformRequest: [function(d) {
- return isObject(d) && !isFile(d) && !isBlob(d) ? toJson(d) : d;
+ return isObject(d) && !isFile(d) && !isBlob(d) && !isFormData(d) ? toJson(d) : d;
}],
// default headers
@@ -7540,7 +9408,37 @@ function $HttpProvider() {
},
xsrfCookieName: 'XSRF-TOKEN',
- xsrfHeaderName: 'X-XSRF-TOKEN'
+ xsrfHeaderName: 'X-XSRF-TOKEN',
+
+ paramSerializer: '$httpParamSerializer'
+ };
+
+ var useApplyAsync = false;
+ /**
+ * @ngdoc method
+ * @name $httpProvider#useApplyAsync
+ * @description
+ *
+ * Configure $http service to combine processing of multiple http responses received at around
+ * the same time via {@link ng.$rootScope.Scope#$applyAsync $rootScope.$applyAsync}. This can result in
+ * significant performance improvement for bigger applications that make many HTTP requests
+ * concurrently (common during application bootstrap).
+ *
+ * Defaults to false. If no value is specified, returns the current configured value.
+ *
+ * @param {boolean=} value If true, when requests are loaded, they will schedule a deferred
+ * "apply" on the next tick, giving time for subsequent requests in a roughly ~10ms window
+ * to load and share the same digest cycle.
+ *
+ * @returns {boolean|Object} If a value is specified, returns the $httpProvider for chaining.
+ * otherwise, returns the current configured value.
+ **/
+ this.useApplyAsync = function(value) {
+ if (isDefined(value)) {
+ useApplyAsync = !!value;
+ return this;
+ }
+ return useApplyAsync;
};
/**
@@ -7558,18 +9456,18 @@ function $HttpProvider() {
**/
var interceptorFactories = this.interceptors = [];
- /**
- * For historical reasons, response interceptors are ordered by the order in which
- * they are applied to the response. (This is the opposite of interceptorFactories)
- */
- var responseInterceptorFactories = this.responseInterceptors = [];
-
- this.$get = ['$httpBackend', '$browser', '$cacheFactory', '$rootScope', '$q', '$injector',
- function($httpBackend, $browser, $cacheFactory, $rootScope, $q, $injector) {
+ this.$get = ['$httpBackend', '$$cookieReader', '$cacheFactory', '$rootScope', '$q', '$injector',
+ function($httpBackend, $$cookieReader, $cacheFactory, $rootScope, $q, $injector) {
var defaultCache = $cacheFactory('$http');
/**
+ * Make sure that default param serializer is exposed as a function
+ */
+ defaults.paramSerializer = isString(defaults.paramSerializer) ?
+ $injector.get(defaults.paramSerializer) : defaults.paramSerializer;
+
+ /**
* Interceptors stored in reverse order. Inner interceptors before outer interceptors.
* The reversal is needed so that we can build up the interception chain around the
* server request.
@@ -7581,27 +9479,6 @@ function $HttpProvider() {
? $injector.get(interceptorFactory) : $injector.invoke(interceptorFactory));
});
- forEach(responseInterceptorFactories, function(interceptorFactory, index) {
- var responseFn = isString(interceptorFactory)
- ? $injector.get(interceptorFactory)
- : $injector.invoke(interceptorFactory);
-
- /**
- * Response interceptors go before "around" interceptors (no real reason, just
- * had to pick one.) But they are already reversed, so we can't use unshift, hence
- * the splice.
- */
- reversedInterceptors.splice(index, 0, {
- response: function(response) {
- return responseFn($q.when(response));
- },
- responseError: function(response) {
- return responseFn($q.reject(response));
- }
- });
- });
-
-
/**
* @ngdoc service
* @kind function
@@ -7628,13 +9505,14 @@ function $HttpProvider() {
* it is important to familiarize yourself with these APIs and the guarantees they provide.
*
*
- * # General usage
+ * ## General usage
* The `$http` service is a function which takes a single argument — a configuration object —
* that is used to generate an HTTP request and returns a {@link ng.$q promise}
* with two $http specific methods: `success` and `error`.
*
* ```js
- * $http({method: 'GET', url: '/someUrl'}).
+ * // Simple GET request example :
+ * $http.get('/someUrl').
* success(function(data, status, headers, config) {
* // this callback will be called asynchronously
* // when the response is available
@@ -7645,6 +9523,20 @@ function $HttpProvider() {
* });
* ```
*
+ * ```js
+ * // Simple POST request example (passing data) :
+ * $http.post('/someUrl', {msg:'hello word!'}).
+ * success(function(data, status, headers, config) {
+ * // this callback will be called asynchronously
+ * // when the response is available
+ * }).
+ * error(function(data, status, headers, config) {
+ * // called asynchronously if an error occurs
+ * // or server returns response with an error status.
+ * });
+ * ```
+ *
+ *
* Since the returned value of calling the $http function is a `promise`, you can also use
* the `then` method to register callbacks, and these callbacks will receive a single argument –
* an object representing the response. See the API signature and type info below for more
@@ -7655,7 +9547,7 @@ function $HttpProvider() {
* XMLHttpRequest will transparently follow it, meaning that the error callback will not be
* called for such responses.
*
- * # Writing Unit Tests that use $http
+ * ## Writing Unit Tests that use $http
* When unit testing (using {@link ngMock ngMock}), it is necessary to call
* {@link ngMock.$httpBackend#flush $httpBackend.flush()} to flush each pending
* request using trained responses.
@@ -7666,7 +9558,7 @@ function $HttpProvider() {
* $httpBackend.flush();
* ```
*
- * # Shortcut methods
+ * ## Shortcut methods
*
* Shortcut methods are also available. All shortcut methods require passing in the URL, and
* request data must be passed in for POST/PUT requests.
@@ -7687,7 +9579,7 @@ function $HttpProvider() {
* - {@link ng.$http#patch $http.patch}
*
*
- * # Setting HTTP Headers
+ * ## Setting HTTP Headers
*
* The $http service will automatically add certain HTTP headers to all requests. These defaults
* can be fully configured by accessing the `$httpProvider.defaults.headers` configuration
@@ -7703,7 +9595,7 @@ function $HttpProvider() {
* To add or overwrite these defaults, simply add or remove a property from these configuration
* objects. To add headers for an HTTP method other than POST or PUT, simply add a new object
* with the lowercased HTTP method name as the key, e.g.
- * `$httpProvider.defaults.headers.get = { 'My-Header' : 'value' }.
+ * `$httpProvider.defaults.headers.get = { 'My-Header' : 'value' }`.
*
* The defaults can also be set at runtime via the `$http.defaults` object in the same
* fashion. For example:
@@ -7727,42 +9619,75 @@ function $HttpProvider() {
* headers: {
* 'Content-Type': undefined
* },
- * data: { test: 'test' },
+ * data: { test: 'test' }
* }
*
* $http(req).success(function(){...}).error(function(){...});
* ```
*
- * # Transforming Requests and Responses
+ * ## Transforming Requests and Responses
+ *
+ * Both requests and responses can be transformed using transformation functions: `transformRequest`
+ * and `transformResponse`. These properties can be a single function that returns
+ * the transformed value (`function(data, headersGetter, status)`) or an array of such transformation functions,
+ * which allows you to `push` or `unshift` a new transformation function into the transformation chain.
*
- * Both requests and responses can be transformed using transform functions. By default, Angular
- * applies these transformations:
+ * ### Default Transformations
*
- * Request transformations:
+ * The `$httpProvider` provider and `$http` service expose `defaults.transformRequest` and
+ * `defaults.transformResponse` properties. If a request does not provide its own transformations
+ * then these will be applied.
+ *
+ * You can augment or replace the default transformations by modifying these properties by adding to or
+ * replacing the array.
+ *
+ * Angular provides the following default transformations:
+ *
+ * Request transformations (`$httpProvider.defaults.transformRequest` and `$http.defaults.transformRequest`):
*
* - If the `data` property of the request configuration object contains an object, serialize it
* into JSON format.
*
- * Response transformations:
+ * Response transformations (`$httpProvider.defaults.transformResponse` and `$http.defaults.transformResponse`):
*
* - If XSRF prefix is detected, strip it (see Security Considerations section below).
* - If JSON response is detected, deserialize it using a JSON parser.
*
- * To globally augment or override the default transforms, modify the
- * `$httpProvider.defaults.transformRequest` and `$httpProvider.defaults.transformResponse`
- * properties. These properties are by default an array of transform functions, which allows you
- * to `push` or `unshift` a new transformation function into the transformation chain. You can
- * also decide to completely override any default transformations by assigning your
- * transformation functions to these properties directly without the array wrapper. These defaults
- * are again available on the $http factory at run-time, which may be useful if you have run-time
- * services you wish to be involved in your transformations.
*
- * Similarly, to locally override the request/response transforms, augment the
- * `transformRequest` and/or `transformResponse` properties of the configuration object passed
+ * ### Overriding the Default Transformations Per Request
+ *
+ * If you wish override the request/response transformations only for a single request then provide
+ * `transformRequest` and/or `transformResponse` properties on the configuration object passed
* into `$http`.
*
+ * Note that if you provide these properties on the config object the default transformations will be
+ * overwritten. If you wish to augment the default transformations then you must include them in your
+ * local transformation array.
*
- * # Caching
+ * The following code demonstrates adding a new response transformation to be run after the default response
+ * transformations have been run.
+ *
+ * ```js
+ * function appendTransform(defaults, transform) {
+ *
+ * // We can't guarantee that the default transformation is an array
+ * defaults = angular.isArray(defaults) ? defaults : [defaults];
+ *
+ * // Append the new transformation to the defaults
+ * return defaults.concat(transform);
+ * }
+ *
+ * $http({
+ * url: '...',
+ * method: 'GET',
+ * transformResponse: appendTransform($http.defaults.transformResponse, function(value) {
+ * return doTransform(value);
+ * })
+ * });
+ * ```
+ *
+ *
+ * ## Caching
*
* To enable caching, set the request configuration `cache` property to `true` (to use default
* cache) or to a custom cache object (built with {@link ng.$cacheFactory `$cacheFactory`}).
@@ -7779,13 +9704,13 @@ function $HttpProvider() {
*
* You can change the default cache to a new object (built with
* {@link ng.$cacheFactory `$cacheFactory`}) by updating the
- * {@link ng.$http#properties_defaults `$http.defaults.cache`} property. All requests who set
+ * {@link ng.$http#defaults `$http.defaults.cache`} property. All requests who set
* their `cache` property to `true` will now use this cache object.
*
* If you set the default cache to `false` then only requests that specify their own custom
* cache object will be cached.
*
- * # Interceptors
+ * ## Interceptors
*
* Before you start creating interceptors, be sure to understand the
* {@link ng.$q $q and deferred/promise APIs}.
@@ -7870,52 +9795,7 @@ function $HttpProvider() {
* });
* ```
*
- * # Response interceptors (DEPRECATED)
- *
- * Before you start creating interceptors, be sure to understand the
- * {@link ng.$q $q and deferred/promise APIs}.
- *
- * For purposes of global error handling, authentication or any kind of synchronous or
- * asynchronous preprocessing of received responses, it is desirable to be able to intercept
- * responses for http requests before they are handed over to the application code that
- * initiated these requests. The response interceptors leverage the {@link ng.$q
- * promise apis} to fulfil this need for both synchronous and asynchronous preprocessing.
- *
- * The interceptors are service factories that are registered with the $httpProvider by
- * adding them to the `$httpProvider.responseInterceptors` array. The factory is called and
- * injected with dependencies (if specified) and returns the interceptor — a function that
- * takes a {@link ng.$q promise} and returns the original or a new promise.
- *
- * ```js
- * // register the interceptor as a service
- * $provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) {
- * return function(promise) {
- * return promise.then(function(response) {
- * // do something on success
- * return response;
- * }, function(response) {
- * // do something on error
- * if (canRecover(response)) {
- * return responseOrNewPromise
- * }
- * return $q.reject(response);
- * });
- * }
- * });
- *
- * $httpProvider.responseInterceptors.push('myHttpInterceptor');
- *
- *
- * // register the interceptor via an anonymous factory
- * $httpProvider.responseInterceptors.push(function($q, dependency1, dependency2) {
- * return function(promise) {
- * // same as above
- * }
- * });
- * ```
- *
- *
- * # Security Considerations
+ * ## Security Considerations
*
* When designing web applications, consider security threats from:
*
@@ -7926,7 +9806,7 @@ function $HttpProvider() {
* pre-configured with strategies that address these issues, but for this to work backend server
* cooperation is required.
*
- * ## JSON Vulnerability Protection
+ * ### JSON Vulnerability Protection
*
* A [JSON vulnerability](http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx)
* allows third party website to turn your JSON resource URL into
@@ -7948,7 +9828,7 @@ function $HttpProvider() {
* Angular will strip the prefix, before processing the JSON.
*
*
- * ## Cross Site Request Forgery (XSRF) Protection
+ * ### Cross Site Request Forgery (XSRF) Protection
*
* [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery) is a technique by which
* an unauthorized site can gain your user's private data. Angular provides a mechanism
@@ -7971,29 +9851,42 @@ function $HttpProvider() {
* properties of either $httpProvider.defaults at config-time, $http.defaults at run-time,
* or the per-request config object.
*
+ * In order to prevent collisions in environments where multiple Angular apps share the
+ * same domain or subdomain, we recommend that each application uses unique cookie name.
+ *
*
* @param {object} config Object describing the request to be made and how it should be
* processed. The object has following properties:
*
* - **method** – `{string}` – HTTP method (e.g. 'GET', 'POST', etc)
* - **url** – `{string}` – Absolute or relative URL of the resource that is being requested.
- * - **params** – `{Object.<string|Object>}` – Map of strings or objects which will be turned
- * to `?key1=value1&key2=value2` after the url. If the value is not a string, it will be
- * JSONified.
+ * - **params** – `{Object.<string|Object>}` – Map of strings or objects which will be serialized
+ * with the `paramSerializer` and appended as GET parameters.
* - **data** – `{string|Object}` – Data to be sent as the request message data.
* - **headers** – `{Object}` – Map of strings or functions which return strings representing
* HTTP headers to send to the server. If the return value of a function is null, the
- * header will not be sent.
+ * header will not be sent. Functions accept a config object as an argument.
* - **xsrfHeaderName** – `{string}` – Name of HTTP header to populate with the XSRF token.
* - **xsrfCookieName** – `{string}` – Name of cookie containing the XSRF token.
* - **transformRequest** –
* `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
* transform function or an array of such functions. The transform function takes the http
* request body and headers and returns its transformed (typically serialized) version.
+ * See {@link ng.$http#overriding-the-default-transformations-per-request
+ * Overriding the Default Transformations}
* - **transformResponse** –
- * `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
+ * `{function(data, headersGetter, status)|Array.<function(data, headersGetter, status)>}` –
* transform function or an array of such functions. The transform function takes the http
- * response body and headers and returns its transformed (typically deserialized) version.
+ * response body, headers and status and returns its transformed (typically deserialized) version.
+ * See {@link ng.$http#overriding-the-default-transformations-per-request
+ * Overriding the Default TransformationjqLiks}
+ * - **paramSerializer** - `{string|function(Object<string,string>):string}` - A function used to
+ * prepare the string representation of request parameters (specified as an object).
+ * If specified as string, it is interpreted as function registered with the
+ * {@link $injector $injector}, which means you can create your own serializer
+ * by registering it as a {@link auto.$provide#service service}.
+ * The default serializer is the {@link $httpParamSerializer $httpParamSerializer};
+ * alternatively, you can use the {@link $httpParamSerializerJQLike $httpParamSerializerJQLike}
* - **cache** – `{boolean|Cache}` – If true, a default $http cache will be used to cache the
* GET request, otherwise if a cache instance built with
* {@link ng.$cacheFactory $cacheFactory}, this cache will be used for
@@ -8004,7 +9897,7 @@ function $HttpProvider() {
* XHR object. See [requests with credentials](https://developer.mozilla.org/docs/Web/HTTP/Access_control_CORS#Requests_with_credentials)
* for more information.
* - **responseType** - `{string}` - see
- * [requestType](https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest#responseType).
+ * [XMLHttpRequest.responseType](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#xmlhttprequest-responsetype).
*
* @returns {HttpPromise} Returns a {@link ng.$q promise} object with the
* standard `then` method and two http specific methods: `success` and `error`. The `then`
@@ -8029,11 +9922,11 @@ function $HttpProvider() {
<example module="httpExample">
<file name="index.html">
<div ng-controller="FetchController">
- <select ng-model="method">
+ <select ng-model="method" aria-label="Request method">
<option>GET</option>
<option>JSONP</option>
</select>
- <input type="text" ng-model="url" size="80"/>
+ <input type="text" ng-model="url" size="80" aria-label="URL" />
<button id="fetchbtn" ng-click="fetch()">fetch</button><br>
<button id="samplegetbtn" ng-click="updateModel('GET', 'http-hello.html')">Sample GET</button>
<button id="samplejsonpbtn"
@@ -8114,20 +10007,26 @@ function $HttpProvider() {
</example>
*/
function $http(requestConfig) {
- var config = {
+
+ if (!angular.isObject(requestConfig)) {
+ throw minErr('$http')('badreq', 'Http request configuration must be an object. Received: {0}', requestConfig);
+ }
+
+ var config = extend({
method: 'get',
transformRequest: defaults.transformRequest,
- transformResponse: defaults.transformResponse
- };
- var headers = mergeHeaders(requestConfig);
+ transformResponse: defaults.transformResponse,
+ paramSerializer: defaults.paramSerializer
+ }, requestConfig);
- extend(config, requestConfig);
- config.headers = headers;
+ config.headers = mergeHeaders(requestConfig);
config.method = uppercase(config.method);
+ config.paramSerializer = isString(config.paramSerializer) ?
+ $injector.get(config.paramSerializer) : config.paramSerializer;
var serverRequest = function(config) {
- headers = config.headers;
- var reqData = transformData(config.data, headersGetter(headers), config.transformRequest);
+ var headers = config.headers;
+ var reqData = transformData(config.data, headersGetter(headers), undefined, config.transformRequest);
// strip content-type if data is undefined
if (isUndefined(reqData)) {
@@ -8143,7 +10042,7 @@ function $HttpProvider() {
}
// send request
- return sendReq(config, reqData, headers).then(transformResponse, transformResponse);
+ return sendReq(config, reqData).then(transformResponse, transformResponse);
};
var chain = [serverRequest, undefined];
@@ -8159,7 +10058,7 @@ function $HttpProvider() {
}
});
- while(chain.length) {
+ while (chain.length) {
var thenFn = chain.shift();
var rejectFn = chain.shift();
@@ -8167,6 +10066,8 @@ function $HttpProvider() {
}
promise.success = function(fn) {
+ assertArgFn(fn, 'fn');
+
promise.then(function(response) {
fn(response.data, response.status, response.headers, config);
});
@@ -8174,6 +10075,8 @@ function $HttpProvider() {
};
promise.error = function(fn) {
+ assertArgFn(fn, 'fn');
+
promise.then(null, function(response) {
fn(response.data, response.status, response.headers, config);
});
@@ -8184,14 +10087,34 @@ function $HttpProvider() {
function transformResponse(response) {
// make a copy since the response must be cacheable
- var resp = extend({}, response, {
- data: transformData(response.data, response.headers, config.transformResponse)
- });
+ var resp = extend({}, response);
+ if (!response.data) {
+ resp.data = response.data;
+ } else {
+ resp.data = transformData(response.data, response.headers, response.status, config.transformResponse);
+ }
return (isSuccess(response.status))
? resp
: $q.reject(resp);
}
+ function executeHeaderFns(headers, config) {
+ var headerContent, processedHeaders = {};
+
+ forEach(headers, function(headerFn, header) {
+ if (isFunction(headerFn)) {
+ headerContent = headerFn(config);
+ if (headerContent != null) {
+ processedHeaders[header] = headerContent;
+ }
+ } else {
+ processedHeaders[header] = headerFn;
+ }
+ });
+
+ return processedHeaders;
+ }
+
function mergeHeaders(config) {
var defHeaders = defaults.headers,
reqHeaders = extend({}, config.headers),
@@ -8214,23 +10137,7 @@ function $HttpProvider() {
}
// execute if header value is a function for merged headers
- execHeaders(reqHeaders);
- return reqHeaders;
-
- function execHeaders(headers) {
- var headerContent;
-
- forEach(headers, function(headerFn, header) {
- if (isFunction(headerFn)) {
- headerContent = headerFn();
- if (headerContent != null) {
- headers[header] = headerContent;
- } else {
- delete headers[header];
- }
- }
- });
- }
+ return executeHeaderFns(reqHeaders, shallowCopy(config));
}
}
@@ -8312,30 +10219,30 @@ function $HttpProvider() {
* @returns {HttpPromise} Future object
*/
- /**
- * @ngdoc method
- * @name $http#patch
- *
- * @description
- * Shortcut method to perform `PATCH` request.
- *
- * @param {string} url Relative or absolute URL specifying the destination of the request
- * @param {*} data Request content
- * @param {Object=} config Optional configuration object
- * @returns {HttpPromise} Future object
- */
+ /**
+ * @ngdoc method
+ * @name $http#patch
+ *
+ * @description
+ * Shortcut method to perform `PATCH` request.
+ *
+ * @param {string} url Relative or absolute URL specifying the destination of the request
+ * @param {*} data Request content
+ * @param {Object=} config Optional configuration object
+ * @returns {HttpPromise} Future object
+ */
createShortMethodsWithData('post', 'put', 'patch');
- /**
- * @ngdoc property
- * @name $http#defaults
- *
- * @description
- * Runtime equivalent of the `$httpProvider.defaults` property. Allows configuration of
- * default headers, withCredentials as well as request and response transformations.
- *
- * See "Setting HTTP Headers" and "Transforming Requests and Responses" sections above.
- */
+ /**
+ * @ngdoc property
+ * @name $http#defaults
+ *
+ * @description
+ * Runtime equivalent of the `$httpProvider.defaults` property. Allows configuration of
+ * default headers, withCredentials as well as request and response transformations.
+ *
+ * See "Setting HTTP Headers" and "Transforming Requests and Responses" sections above.
+ */
$http.defaults = defaults;
@@ -8345,7 +10252,7 @@ function $HttpProvider() {
function createShortMethods(names) {
forEach(arguments, function(name) {
$http[name] = function(url, config) {
- return $http(extend(config || {}, {
+ return $http(extend({}, config || {}, {
method: name,
url: url
}));
@@ -8357,7 +10264,7 @@ function $HttpProvider() {
function createShortMethodsWithData(name) {
forEach(arguments, function(name) {
$http[name] = function(url, data, config) {
- return $http(extend(config || {}, {
+ return $http(extend({}, config || {}, {
method: name,
url: url,
data: data
@@ -8373,12 +10280,13 @@ function $HttpProvider() {
* !!! ACCESSES CLOSURE VARS:
* $httpBackend, defaults, $log, $rootScope, defaultCache, $http.pendingRequests
*/
- function sendReq(config, reqData, reqHeaders) {
+ function sendReq(config, reqData) {
var deferred = $q.defer(),
promise = deferred.promise,
cache,
cachedResp,
- url = buildUrl(config.url, config.params);
+ reqHeaders = config.headers,
+ url = buildUrl(config.url, config.paramSerializer(config.params));
$http.pendingRequests.push(config);
promise.then(removePendingReq, removePendingReq);
@@ -8396,8 +10304,7 @@ function $HttpProvider() {
if (isDefined(cachedResp)) {
if (isPromiseLike(cachedResp)) {
// cached request has already been sent, but there is no response yet
- cachedResp.then(removePendingReq, removePendingReq);
- return cachedResp;
+ cachedResp.then(resolvePromiseWithResult, resolvePromiseWithResult);
} else {
// serving from cache
if (isArray(cachedResp)) {
@@ -8417,7 +10324,7 @@ function $HttpProvider() {
// send the request to the backend
if (isUndefined(cachedResp)) {
var xsrfValue = urlIsSameOrigin(config.url)
- ? $browser.cookies()[config.xsrfCookieName || defaults.xsrfCookieName]
+ ? $$cookieReader()[config.xsrfCookieName || defaults.xsrfCookieName]
: undefined;
if (xsrfValue) {
reqHeaders[(config.xsrfHeaderName || defaults.xsrfHeaderName)] = xsrfValue;
@@ -8446,8 +10353,16 @@ function $HttpProvider() {
}
}
- resolvePromise(response, status, headersString, statusText);
- if (!$rootScope.$$phase) $rootScope.$apply();
+ function resolveHttpPromise() {
+ resolvePromise(response, status, headersString, statusText);
+ }
+
+ if (useApplyAsync) {
+ $rootScope.$applyAsync(resolveHttpPromise);
+ } else {
+ resolveHttpPromise();
+ if (!$rootScope.$$phase) $rootScope.$apply();
+ }
}
@@ -8463,57 +10378,32 @@ function $HttpProvider() {
status: status,
headers: headersGetter(headers),
config: config,
- statusText : statusText
+ statusText: statusText
});
}
+ function resolvePromiseWithResult(result) {
+ resolvePromise(result.data, result.status, shallowCopy(result.headers()), result.statusText);
+ }
function removePendingReq() {
- var idx = indexOf($http.pendingRequests, config);
+ var idx = $http.pendingRequests.indexOf(config);
if (idx !== -1) $http.pendingRequests.splice(idx, 1);
}
}
- function buildUrl(url, params) {
- if (!params) return url;
- var parts = [];
- forEachSorted(params, function(value, key) {
- if (value === null || isUndefined(value)) return;
- if (!isArray(value)) value = [value];
-
- forEach(value, function(v) {
- if (isObject(v)) {
- if (isDate(v)){
- v = v.toISOString();
- } else {
- v = toJson(v);
- }
- }
- parts.push(encodeUriQuery(key) + '=' +
- encodeUriQuery(v));
- });
- });
- if(parts.length > 0) {
- url += ((url.indexOf('?') == -1) ? '?' : '&') + parts.join('&');
+ function buildUrl(url, serializedParams) {
+ if (serializedParams.length > 0) {
+ url += ((url.indexOf('?') == -1) ? '?' : '&') + serializedParams;
}
return url;
}
}];
}
-function createXhr(method) {
- //if IE and the method is not RFC2616 compliant, or if XMLHttpRequest
- //is not available, try getting an ActiveXObject. Otherwise, use XMLHttpRequest
- //if it is available
- if (msie <= 8 && (!method.match(/^(get|post|head|put|delete|options)$/i) ||
- !window.XMLHttpRequest)) {
- return new window.ActiveXObject("Microsoft.XMLHTTP");
- } else if (window.XMLHttpRequest) {
- return new window.XMLHttpRequest();
- }
-
- throw minErr('$httpBackend')('noxhr', "This browser does not support XMLHttpRequest.");
+function createXhr() {
+ return new window.XMLHttpRequest();
}
/**
@@ -8539,11 +10429,8 @@ function $HttpBackendProvider() {
}
function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDocument) {
- var ABORTED = -1;
-
// TODO(vojta): fix the signature
return function(method, url, post, callback, headers, timeout, withCredentials, responseType) {
- var status;
$browser.$$incOutstandingRequestCount();
url = url || $browser.url();
@@ -8561,7 +10448,7 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc
});
} else {
- var xhr = createXhr(method);
+ var xhr = createXhr();
xhr.open(method, url, true);
forEach(headers, function(value, key) {
@@ -8570,44 +10457,39 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc
}
});
- // In IE6 and 7, this might be called synchronously when xhr.send below is called and the
- // response is in the cache. the promise api will ensure that to the app code the api is
- // always async
- xhr.onreadystatechange = function() {
- // onreadystatechange might get called multiple times with readyState === 4 on mobile webkit caused by
- // xhrs that are resolved while the app is in the background (see #5426).
- // since calling completeRequest sets the `xhr` variable to null, we just check if it's not null before
- // continuing
- //
- // we can't set xhr.onreadystatechange to undefined or delete it because that breaks IE8 (method=PATCH) and
- // Safari respectively.
- if (xhr && xhr.readyState == 4) {
- var responseHeaders = null,
- response = null,
- statusText = '';
-
- if(status !== ABORTED) {
- responseHeaders = xhr.getAllResponseHeaders();
-
- // responseText is the old-school way of retrieving response (supported by IE8 & 9)
- // response/responseType properties were introduced in XHR Level2 spec (supported by IE10)
- response = ('response' in xhr) ? xhr.response : xhr.responseText;
- }
+ xhr.onload = function requestLoaded() {
+ var statusText = xhr.statusText || '';
- // Accessing statusText on an aborted xhr object will
- // throw an 'c00c023f error' in IE9 and lower, don't touch it.
- if (!(status === ABORTED && msie < 10)) {
- statusText = xhr.statusText;
- }
+ // responseText is the old-school way of retrieving response (supported by IE8 & 9)
+ // response/responseType properties were introduced in XHR Level2 spec (supported by IE10)
+ var response = ('response' in xhr) ? xhr.response : xhr.responseText;
+
+ // normalize IE9 bug (http://bugs.jquery.com/ticket/1450)
+ var status = xhr.status === 1223 ? 204 : xhr.status;
- completeRequest(callback,
- status || xhr.status,
- response,
- responseHeaders,
- statusText);
+ // fix status code when it is 0 (0 status is undocumented).
+ // Occurs when accessing file resources or on Android 4.1 stock browser
+ // while retrieving files from application cache.
+ if (status === 0) {
+ status = response ? 200 : urlResolve(url).protocol == 'file' ? 404 : 0;
}
+
+ completeRequest(callback,
+ status,
+ response,
+ xhr.getAllResponseHeaders(),
+ statusText);
+ };
+
+ var requestError = function() {
+ // The response is always empty
+ // See https://xhr.spec.whatwg.org/#request-error-steps and https://fetch.spec.whatwg.org/#concept-network-error
+ completeRequest(callback, -1, null, null, '');
};
+ xhr.onerror = requestError;
+ xhr.onabort = requestError;
+
if (withCredentials) {
xhr.withCredentials = true;
}
@@ -8629,7 +10511,7 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc
}
}
- xhr.send(post || null);
+ xhr.send(post);
}
if (timeout > 0) {
@@ -8640,26 +10522,16 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc
function timeoutRequest() {
- status = ABORTED;
jsonpDone && jsonpDone();
xhr && xhr.abort();
}
function completeRequest(callback, status, response, headersString, statusText) {
// cancel timeout and subsequent timeout promise resolution
- timeoutId && $browserDefer.cancel(timeoutId);
- jsonpDone = xhr = null;
-
- // fix status code when it is 0 (0 status is undocumented).
- // Occurs when accessing file resources or on Android 4.1 stock browser
- // while retrieving files from application cache.
- if (status === 0) {
- status = response ? 200 : urlResolve(url).protocol == 'file' ? 404 : 0;
+ if (timeoutId !== undefined) {
+ $browserDefer.cancel(timeoutId);
}
-
- // normalize IE bug (http://bugs.jquery.com/ticket/1450)
- status = status === 1223 ? 204 : status;
- statusText = statusText || '';
+ jsonpDone = xhr = null;
callback(status, response, headersString, statusText);
$browser.$$completeOutstandingRequest(noop);
@@ -8667,7 +10539,7 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc
};
function jsonpReq(url, callbackId, done) {
- // we can't use jQuery/jqLite here because jQuery does crazy shit with script elements, e.g.:
+ // we can't use jQuery/jqLite here because jQuery does crazy stuff with script elements, e.g.:
// - fetches local scripts via XHR and evals them
// - adds and immediately removes script elements from the document
var script = rawDocument.createElement('script'), callback = null;
@@ -8698,29 +10570,26 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc
addEventListenerFn(script, "load", callback);
addEventListenerFn(script, "error", callback);
-
- if (msie <= 8) {
- script.onreadystatechange = function() {
- if (isString(script.readyState) && /loaded|complete/.test(script.readyState)) {
- script.onreadystatechange = null;
- callback({
- type: 'load'
- });
- }
- };
- }
-
rawDocument.body.appendChild(script);
return callback;
}
}
-var $interpolateMinErr = minErr('$interpolate');
+var $interpolateMinErr = angular.$interpolateMinErr = minErr('$interpolate');
+$interpolateMinErr.throwNoconcat = function(text) {
+ throw $interpolateMinErr('noconcat',
+ "Error while interpolating: {0}\nStrict Contextual Escaping disallows " +
+ "interpolations that concatenate multiple expressions when a trusted value is " +
+ "required. See http://docs.angularjs.org/api/ng.$sce", text);
+};
+
+$interpolateMinErr.interr = function(text, err) {
+ return $interpolateMinErr('interr', "Can't interpolate: {0}\n{1}", text, err.toString());
+};
/**
* @ngdoc provider
* @name $interpolateProvider
- * @kind function
*
* @description
*
@@ -8766,7 +10635,7 @@ function $InterpolateProvider() {
* @param {string=} value new value to set the starting symbol to.
* @returns {string|self} Returns the symbol when used as getter and self if used as setter.
*/
- this.startSymbol = function(value){
+ this.startSymbol = function(value) {
if (value) {
startSymbol = value;
return this;
@@ -8784,7 +10653,7 @@ function $InterpolateProvider() {
* @param {string=} value new value to set the ending symbol to.
* @returns {string|self} Returns the symbol when used as getter and self if used as setter.
*/
- this.endSymbol = function(value){
+ this.endSymbol = function(value) {
if (value) {
endSymbol = value;
return this;
@@ -8796,7 +10665,35 @@ function $InterpolateProvider() {
this.$get = ['$parse', '$exceptionHandler', '$sce', function($parse, $exceptionHandler, $sce) {
var startSymbolLength = startSymbol.length,
- endSymbolLength = endSymbol.length;
+ endSymbolLength = endSymbol.length,
+ escapedStartRegexp = new RegExp(startSymbol.replace(/./g, escape), 'g'),
+ escapedEndRegexp = new RegExp(endSymbol.replace(/./g, escape), 'g');
+
+ function escape(ch) {
+ return '\\\\\\' + ch;
+ }
+
+ function unescapeText(text) {
+ return text.replace(escapedStartRegexp, startSymbol).
+ replace(escapedEndRegexp, endSymbol);
+ }
+
+ function stringify(value) {
+ if (value == null) { // null || undefined
+ return '';
+ }
+ switch (typeof value) {
+ case 'string':
+ break;
+ case 'number':
+ value = '' + value;
+ break;
+ default:
+ value = toJson(value);
+ }
+
+ return value;
+ }
/**
* @ngdoc service
@@ -8820,6 +10717,62 @@ function $InterpolateProvider() {
* expect(exp({name:'Angular'}).toEqual('Hello ANGULAR!');
* ```
*
+ * `$interpolate` takes an optional fourth argument, `allOrNothing`. If `allOrNothing` is
+ * `true`, the interpolation function will return `undefined` unless all embedded expressions
+ * evaluate to a value other than `undefined`.
+ *
+ * ```js
+ * var $interpolate = ...; // injected
+ * var context = {greeting: 'Hello', name: undefined };
+ *
+ * // default "forgiving" mode
+ * var exp = $interpolate('{{greeting}} {{name}}!');
+ * expect(exp(context)).toEqual('Hello !');
+ *
+ * // "allOrNothing" mode
+ * exp = $interpolate('{{greeting}} {{name}}!', false, null, true);
+ * expect(exp(context)).toBeUndefined();
+ * context.name = 'Angular';
+ * expect(exp(context)).toEqual('Hello Angular!');
+ * ```
+ *
+ * `allOrNothing` is useful for interpolating URLs. `ngSrc` and `ngSrcset` use this behavior.
+ *
+ * ####Escaped Interpolation
+ * $interpolate provides a mechanism for escaping interpolation markers. Start and end markers
+ * can be escaped by preceding each of their characters with a REVERSE SOLIDUS U+005C (backslash).
+ * It will be rendered as a regular start/end marker, and will not be interpreted as an expression
+ * or binding.
+ *
+ * This enables web-servers to prevent script injection attacks and defacing attacks, to some
+ * degree, while also enabling code examples to work without relying on the
+ * {@link ng.directive:ngNonBindable ngNonBindable} directive.
+ *
+ * **For security purposes, it is strongly encouraged that web servers escape user-supplied data,
+ * replacing angle brackets (&lt;, &gt;) with &amp;lt; and &amp;gt; respectively, and replacing all
+ * interpolation start/end markers with their escaped counterparts.**
+ *
+ * Escaped interpolation markers are only replaced with the actual interpolation markers in rendered
+ * output when the $interpolate service processes the text. So, for HTML elements interpolated
+ * by {@link ng.$compile $compile}, or otherwise interpolated with the `mustHaveExpression` parameter
+ * set to `true`, the interpolated text must contain an unescaped interpolation expression. As such,
+ * this is typically useful only when user-data is used in rendering a template from the server, or
+ * when otherwise untrusted data is used by a directive.
+ *
+ * <example>
+ * <file name="index.html">
+ * <div ng-init="username='A user'">
+ * <p ng-init="apptitle='Escaping demo'">{{apptitle}}: \{\{ username = "defaced value"; \}\}
+ * </p>
+ * <p><strong>{{username}}</strong> attempts to inject code which will deface the
+ * application, but fails to accomplish their task, because the server has correctly
+ * escaped the interpolation start/end markers with REVERSE SOLIDUS U+005C (backslash)
+ * characters.</p>
+ * <p>Instead, the result of the attempted script injection is visible, and can be removed
+ * from the database by an administrator.</p>
+ * </div>
+ * </file>
+ * </example>
*
* @param {string} text The text with markup to interpolate.
* @param {boolean=} mustHaveExpression if set to true then the interpolation string must have
@@ -8829,103 +10782,110 @@ function $InterpolateProvider() {
* result through {@link ng.$sce#getTrusted $sce.getTrusted(interpolatedResult,
* trustedContext)} before returning it. Refer to the {@link ng.$sce $sce} service that
* provides Strict Contextual Escaping for details.
+ * @param {boolean=} allOrNothing if `true`, then the returned function returns undefined
+ * unless all embedded expressions evaluate to a value other than `undefined`.
* @returns {function(context)} an interpolation function which is used to compute the
* interpolated string. The function has these parameters:
*
- * * `context`: an object against which any expressions embedded in the strings are evaluated
- * against.
- *
+ * - `context`: evaluation context for all expressions embedded in the interpolated text
*/
- function $interpolate(text, mustHaveExpression, trustedContext) {
+ function $interpolate(text, mustHaveExpression, trustedContext, allOrNothing) {
+ allOrNothing = !!allOrNothing;
var startIndex,
endIndex,
index = 0,
- parts = [],
- length = text.length,
- hasInterpolation = false,
- fn,
+ expressions = [],
+ parseFns = [],
+ textLength = text.length,
exp,
- concat = [];
-
- while(index < length) {
- if ( ((startIndex = text.indexOf(startSymbol, index)) != -1) &&
- ((endIndex = text.indexOf(endSymbol, startIndex + startSymbolLength)) != -1) ) {
- (index != startIndex) && parts.push(text.substring(index, startIndex));
- parts.push(fn = $parse(exp = text.substring(startIndex + startSymbolLength, endIndex)));
- fn.exp = exp;
+ concat = [],
+ expressionPositions = [];
+
+ while (index < textLength) {
+ if (((startIndex = text.indexOf(startSymbol, index)) != -1) &&
+ ((endIndex = text.indexOf(endSymbol, startIndex + startSymbolLength)) != -1)) {
+ if (index !== startIndex) {
+ concat.push(unescapeText(text.substring(index, startIndex)));
+ }
+ exp = text.substring(startIndex + startSymbolLength, endIndex);
+ expressions.push(exp);
+ parseFns.push($parse(exp, parseStringifyInterceptor));
index = endIndex + endSymbolLength;
- hasInterpolation = true;
+ expressionPositions.push(concat.length);
+ concat.push('');
} else {
- // we did not find anything, so we have to add the remainder to the parts array
- (index != length) && parts.push(text.substring(index));
- index = length;
+ // we did not find an interpolation, so we have to add the remainder to the separators array
+ if (index !== textLength) {
+ concat.push(unescapeText(text.substring(index)));
+ }
+ break;
}
}
- if (!(length = parts.length)) {
- // we added, nothing, must have been an empty string.
- parts.push('');
- length = 1;
- }
-
// Concatenating expressions makes it hard to reason about whether some combination of
// concatenated values are unsafe to use and could easily lead to XSS. By requiring that a
// single expression be used for iframe[src], object[src], etc., we ensure that the value
// that's used is assigned or constructed by some JS code somewhere that is more testable or
// make it obvious that you bound the value to some user controlled value. This helps reduce
// the load when auditing for XSS issues.
- if (trustedContext && parts.length > 1) {
- throw $interpolateMinErr('noconcat',
- "Error while interpolating: {0}\nStrict Contextual Escaping disallows " +
- "interpolations that concatenate multiple expressions when a trusted value is " +
- "required. See http://docs.angularjs.org/api/ng.$sce", text);
+ if (trustedContext && concat.length > 1) {
+ $interpolateMinErr.throwNoconcat(text);
}
- if (!mustHaveExpression || hasInterpolation) {
- concat.length = length;
- fn = function(context) {
- try {
- for(var i = 0, ii = length, part; i<ii; i++) {
- if (typeof (part = parts[i]) == 'function') {
- part = part(context);
- if (trustedContext) {
- part = $sce.getTrusted(trustedContext, part);
- } else {
- part = $sce.valueOf(part);
- }
- if (part == null) { // null || undefined
- part = '';
- } else {
- switch (typeof part) {
- case 'string':
- {
- break;
- }
- case 'number':
- {
- part = '' + part;
- break;
- }
- default:
- {
- part = toJson(part);
- }
- }
- }
+ if (!mustHaveExpression || expressions.length) {
+ var compute = function(values) {
+ for (var i = 0, ii = expressions.length; i < ii; i++) {
+ if (allOrNothing && isUndefined(values[i])) return;
+ concat[expressionPositions[i]] = values[i];
+ }
+ return concat.join('');
+ };
+
+ var getValue = function(value) {
+ return trustedContext ?
+ $sce.getTrusted(trustedContext, value) :
+ $sce.valueOf(value);
+ };
+
+ return extend(function interpolationFn(context) {
+ var i = 0;
+ var ii = expressions.length;
+ var values = new Array(ii);
+
+ try {
+ for (; i < ii; i++) {
+ values[i] = parseFns[i](context);
}
- concat[i] = part;
+
+ return compute(values);
+ } catch (err) {
+ $exceptionHandler($interpolateMinErr.interr(text, err));
}
- return concat.join('');
- }
- catch(err) {
- var newErr = $interpolateMinErr('interr', "Can't interpolate: {0}\n{1}", text,
- err.toString());
- $exceptionHandler(newErr);
+
+ }, {
+ // all of these properties are undocumented for now
+ exp: text, //just for compatibility with regular watchers created via $watch
+ expressions: expressions,
+ $$watchDelegate: function(scope, listener) {
+ var lastValue;
+ return scope.$watchGroup(parseFns, function interpolateFnWatcher(values, oldValues) {
+ var currValue = compute(values);
+ if (isFunction(listener)) {
+ listener.call(this, currValue, values !== oldValues ? lastValue : currValue, scope);
+ }
+ lastValue = currValue;
+ });
}
- };
- fn.exp = text;
- fn.parts = parts;
- return fn;
+ });
+ }
+
+ function parseStringifyInterceptor(value) {
+ try {
+ value = getValue(value);
+ return allOrNothing && !isDefined(value) ? value : stringify(value);
+ } catch (err) {
+ $exceptionHandler($interpolateMinErr.interr(text, err));
+ }
}
}
@@ -8966,8 +10926,8 @@ function $InterpolateProvider() {
}
function $IntervalProvider() {
- this.$get = ['$rootScope', '$window', '$q',
- function($rootScope, $window, $q) {
+ this.$get = ['$rootScope', '$window', '$q', '$$q',
+ function($rootScope, $window, $q, $$q) {
var intervals = {};
@@ -9003,6 +10963,7 @@ function $IntervalProvider() {
* indefinitely.
* @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
* will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
+ * @param {...*=} Pass additional parameters to the executed function.
* @returns {promise} A promise which will be notified on each iteration.
*
* @example
@@ -9072,7 +11033,7 @@ function $IntervalProvider() {
*
* // listen on DOM destroy (removal) event, and cancel the next UI update
* // to prevent updating time after the DOM element was removed.
- * element.bind('$destroy', function() {
+ * element.on('$destroy', function() {
* $interval.cancel(stopTime);
* });
* }
@@ -9081,7 +11042,7 @@ function $IntervalProvider() {
*
* <div>
* <div ng-controller="ExampleController">
- * Date format: <input ng-model="format"> <hr/>
+ * <label>Date format: <input ng-model="format"></label> <hr/>
* Current time is: <span my-current-time="format"></span>
* <hr/>
* Blood 1 : <font color='red'>{{blood_1}}</font>
@@ -9096,16 +11057,20 @@ function $IntervalProvider() {
* </example>
*/
function interval(fn, delay, count, invokeApply) {
- var setInterval = $window.setInterval,
+ var hasParams = arguments.length > 4,
+ args = hasParams ? sliceArgs(arguments, 4) : [],
+ setInterval = $window.setInterval,
clearInterval = $window.clearInterval,
- deferred = $q.defer(),
- promise = deferred.promise,
iteration = 0,
- skipApply = (isDefined(invokeApply) && !invokeApply);
+ skipApply = (isDefined(invokeApply) && !invokeApply),
+ deferred = (skipApply ? $$q : $q).defer(),
+ promise = deferred.promise;
count = isDefined(count) ? count : 0;
- promise.then(null, null, fn);
+ promise.then(null, null, (!hasParams) ? fn : function() {
+ fn.apply(null, args);
+ });
promise.$$intervalId = setInterval(function tick() {
deferred.notify(iteration++);
@@ -9160,7 +11125,7 @@ function $IntervalProvider() {
*
* * `id` – `{string}` – locale id formatted as `languageId-countryId` (e.g. `en-us`)
*/
-function $LocaleProvider(){
+function $LocaleProvider() {
this.$get = function() {
return {
id: 'en-us',
@@ -9203,13 +11168,21 @@ function $LocaleProvider(){
SHORTDAY: 'Sun,Mon,Tue,Wed,Thu,Fri,Sat'.split(','),
AMPMS: ['AM','PM'],
medium: 'MMM d, y h:mm:ss a',
- short: 'M/d/yy h:mm a',
+ 'short': 'M/d/yy h:mm a',
fullDate: 'EEEE, MMMM d, y',
longDate: 'MMMM d, y',
mediumDate: 'MMM d, y',
shortDate: 'M/d/yy',
mediumTime: 'h:mm:ss a',
- shortTime: 'h:mm a'
+ shortTime: 'h:mm a',
+ ERANAMES: [
+ "Before Christ",
+ "Anno Domini"
+ ],
+ ERAS: [
+ "BC",
+ "AD"
+ ]
},
pluralCat: function(num) {
@@ -9244,21 +11217,21 @@ function encodePath(path) {
return segments.join('/');
}
-function parseAbsoluteUrl(absoluteUrl, locationObj, appBase) {
- var parsedUrl = urlResolve(absoluteUrl, appBase);
+function parseAbsoluteUrl(absoluteUrl, locationObj) {
+ var parsedUrl = urlResolve(absoluteUrl);
locationObj.$$protocol = parsedUrl.protocol;
locationObj.$$host = parsedUrl.hostname;
- locationObj.$$port = int(parsedUrl.port) || DEFAULT_PORTS[parsedUrl.protocol] || null;
+ locationObj.$$port = toInt(parsedUrl.port) || DEFAULT_PORTS[parsedUrl.protocol] || null;
}
-function parseAppUrl(relativeUrl, locationObj, appBase) {
+function parseAppUrl(relativeUrl, locationObj) {
var prefixed = (relativeUrl.charAt(0) !== '/');
if (prefixed) {
relativeUrl = '/' + relativeUrl;
}
- var match = urlResolve(relativeUrl, appBase);
+ var match = urlResolve(relativeUrl);
locationObj.$$path = decodeURIComponent(prefixed && match.pathname.charAt(0) === '/' ?
match.pathname.substring(1) : match.pathname);
locationObj.$$search = parseKeyValue(match.search);
@@ -9290,6 +11263,10 @@ function stripHash(url) {
return index == -1 ? url : url.substr(0, index);
}
+function trimEmptyHash(url) {
+ return url.replace(/(#.+)|#$/, '$1');
+}
+
function stripFile(url) {
return url.substr(0, stripHash(url).lastIndexOf('/') + 1);
@@ -9313,12 +11290,12 @@ function LocationHtml5Url(appBase, basePrefix) {
this.$$html5 = true;
basePrefix = basePrefix || '';
var appBaseNoFile = stripFile(appBase);
- parseAbsoluteUrl(appBase, this, appBase);
+ parseAbsoluteUrl(appBase, this);
/**
* Parse given html5 (regular) url string into properties
- * @param {string} newAbsoluteUrl HTML5 url
+ * @param {string} url HTML5 url
* @private
*/
this.$$parse = function(url) {
@@ -9328,7 +11305,7 @@ function LocationHtml5Url(appBase, basePrefix) {
appBaseNoFile);
}
- parseAppUrl(pathUrl, this, appBase);
+ parseAppUrl(pathUrl, this);
if (!this.$$path) {
this.$$path = '/';
@@ -9350,17 +11327,23 @@ function LocationHtml5Url(appBase, basePrefix) {
};
this.$$parseLinkUrl = function(url, relHref) {
+ if (relHref && relHref[0] === '#') {
+ // special case for links to hash fragments:
+ // keep the old url and only replace the hash fragment
+ this.hash(relHref.slice(1));
+ return true;
+ }
var appUrl, prevAppUrl;
var rewrittenUrl;
- if ( (appUrl = beginsWith(appBase, url)) !== undefined ) {
+ if ((appUrl = beginsWith(appBase, url)) !== undefined) {
prevAppUrl = appUrl;
- if ( (appUrl = beginsWith(basePrefix, appUrl)) !== undefined ) {
+ if ((appUrl = beginsWith(basePrefix, appUrl)) !== undefined) {
rewrittenUrl = appBaseNoFile + (beginsWith('/', appUrl) || appUrl);
} else {
rewrittenUrl = appBase + prevAppUrl;
}
- } else if ( (appUrl = beginsWith(appBaseNoFile, url)) !== undefined ) {
+ } else if ((appUrl = beginsWith(appBaseNoFile, url)) !== undefined) {
rewrittenUrl = appBaseNoFile + appUrl;
} else if (appBaseNoFile == url + '/') {
rewrittenUrl = appBaseNoFile;
@@ -9385,7 +11368,7 @@ function LocationHtml5Url(appBase, basePrefix) {
function LocationHashbangUrl(appBase, hashPrefix) {
var appBaseNoFile = stripFile(appBase);
- parseAbsoluteUrl(appBase, this, appBase);
+ parseAbsoluteUrl(appBase, this);
/**
@@ -9395,17 +11378,34 @@ function LocationHashbangUrl(appBase, hashPrefix) {
*/
this.$$parse = function(url) {
var withoutBaseUrl = beginsWith(appBase, url) || beginsWith(appBaseNoFile, url);
- var withoutHashUrl = withoutBaseUrl.charAt(0) == '#'
- ? beginsWith(hashPrefix, withoutBaseUrl)
- : (this.$$html5)
- ? withoutBaseUrl
- : '';
+ var withoutHashUrl;
+
+ if (!isUndefined(withoutBaseUrl) && withoutBaseUrl.charAt(0) === '#') {
+
+ // The rest of the url starts with a hash so we have
+ // got either a hashbang path or a plain hash fragment
+ withoutHashUrl = beginsWith(hashPrefix, withoutBaseUrl);
+ if (isUndefined(withoutHashUrl)) {
+ // There was no hashbang prefix so we just have a hash fragment
+ withoutHashUrl = withoutBaseUrl;
+ }
- if (!isString(withoutHashUrl)) {
- throw $locationMinErr('ihshprfx', 'Invalid url "{0}", missing hash prefix "{1}".', url,
- hashPrefix);
+ } else {
+ // There was no hashbang path nor hash fragment:
+ // If we are in HTML5 mode we use what is left as the path;
+ // Otherwise we ignore what is left
+ if (this.$$html5) {
+ withoutHashUrl = withoutBaseUrl;
+ } else {
+ withoutHashUrl = '';
+ if (isUndefined(withoutBaseUrl)) {
+ appBase = url;
+ this.replace();
+ }
+ }
}
- parseAppUrl(withoutHashUrl, this, appBase);
+
+ parseAppUrl(withoutHashUrl, this);
this.$$path = removeWindowsDriveName(this.$$path, withoutHashUrl, appBase);
@@ -9422,7 +11422,7 @@ function LocationHashbangUrl(appBase, hashPrefix) {
* Inside of Angular, we're always using pathnames that
* do not include drive names for routing.
*/
- function removeWindowsDriveName (path, url, base) {
+ function removeWindowsDriveName(path, url, base) {
/*
Matches paths for file protocol on windows,
such as /C:/foo/bar, and captures only /foo/bar.
@@ -9459,7 +11459,7 @@ function LocationHashbangUrl(appBase, hashPrefix) {
};
this.$$parseLinkUrl = function(url, relHref) {
- if(stripHash(appBase) == stripHash(url)) {
+ if (stripHash(appBase) == stripHash(url)) {
this.$$parse(url);
return true;
}
@@ -9484,14 +11484,21 @@ function LocationHashbangInHtml5Url(appBase, hashPrefix) {
var appBaseNoFile = stripFile(appBase);
this.$$parseLinkUrl = function(url, relHref) {
+ if (relHref && relHref[0] === '#') {
+ // special case for links to hash fragments:
+ // keep the old url and only replace the hash fragment
+ this.hash(relHref.slice(1));
+ return true;
+ }
+
var rewrittenUrl;
var appUrl;
- if ( appBase == stripHash(url) ) {
+ if (appBase == stripHash(url)) {
rewrittenUrl = url;
- } else if ( (appUrl = beginsWith(appBaseNoFile, url)) ) {
+ } else if ((appUrl = beginsWith(appBaseNoFile, url))) {
rewrittenUrl = appBase + hashPrefix + appUrl;
- } else if ( appBaseNoFile === url + '/') {
+ } else if (appBaseNoFile === url + '/') {
rewrittenUrl = appBaseNoFile;
}
if (rewrittenUrl) {
@@ -9512,9 +11519,7 @@ function LocationHashbangInHtml5Url(appBase, hashPrefix) {
}
-LocationHashbangInHtml5Url.prototype =
- LocationHashbangUrl.prototype =
- LocationHtml5Url.prototype = {
+var locationPrototype = {
/**
* Are we in html5 mode?
@@ -9523,7 +11528,7 @@ LocationHashbangInHtml5Url.prototype =
$$html5: false,
/**
- * Has any change been replacing ?
+ * Has any change been replacing?
* @private
*/
$$replace: false,
@@ -9538,6 +11543,13 @@ LocationHashbangInHtml5Url.prototype =
* Return full url representation with all segments encoded according to rules specified in
* [RFC 3986](http://www.ietf.org/rfc/rfc3986.txt).
*
+ *
+ * ```js
+ * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
+ * var absUrl = $location.absUrl();
+ * // => "http://example.com/#/some/path?foo=bar&baz=xoxo"
+ * ```
+ *
* @return {string} full url
*/
absUrl: locationGetter('$$absUrl'),
@@ -9553,16 +11565,24 @@ LocationHashbangInHtml5Url.prototype =
*
* Change path, search and hash, when called with parameter and return `$location`.
*
+ *
+ * ```js
+ * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
+ * var url = $location.url();
+ * // => "/some/path?foo=bar&baz=xoxo"
+ * ```
+ *
* @param {string=} url New url without base prefix (e.g. `/path?a=b#hash`)
* @return {string} url
*/
url: function(url) {
- if (isUndefined(url))
+ if (isUndefined(url)) {
return this.$$url;
+ }
var match = PATH_MATCH.exec(url);
- if (match[1]) this.path(decodeURIComponent(match[1]));
- if (match[2] || match[1]) this.search(match[3] || '');
+ if (match[1] || url === '') this.path(decodeURIComponent(match[1]));
+ if (match[2] || match[1] || url === '') this.search(match[3] || '');
this.hash(match[5] || '');
return this;
@@ -9577,6 +11597,13 @@ LocationHashbangInHtml5Url.prototype =
*
* Return protocol of current url.
*
+ *
+ * ```js
+ * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
+ * var protocol = $location.protocol();
+ * // => "http"
+ * ```
+ *
* @return {string} protocol of current url
*/
protocol: locationGetter('$$protocol'),
@@ -9590,6 +11617,21 @@ LocationHashbangInHtml5Url.prototype =
*
* Return host of current url.
*
+ * Note: compared to the non-angular version `location.host` which returns `hostname:port`, this returns the `hostname` portion only.
+ *
+ *
+ * ```js
+ * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
+ * var host = $location.host();
+ * // => "example.com"
+ *
+ * // given url http://user:password@example.com:8080/#/some/path?foo=bar&baz=xoxo
+ * host = $location.host();
+ * // => "example.com"
+ * host = location.host;
+ * // => "example.com:8080"
+ * ```
+ *
* @return {string} host of current url.
*/
host: locationGetter('$$host'),
@@ -9603,6 +11645,13 @@ LocationHashbangInHtml5Url.prototype =
*
* Return port of current url.
*
+ *
+ * ```js
+ * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
+ * var port = $location.port();
+ * // => 80
+ * ```
+ *
* @return {Number} port
*/
port: locationGetter('$$port'),
@@ -9621,6 +11670,13 @@ LocationHashbangInHtml5Url.prototype =
* Note: Path should always begin with forward slash (/), this method will add the forward slash
* if it is missing.
*
+ *
+ * ```js
+ * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
+ * var path = $location.path();
+ * // => "/some/path"
+ * ```
+ *
* @param {(string|number)=} path New path
* @return {string} path
*/
@@ -9646,10 +11702,9 @@ LocationHashbangInHtml5Url.prototype =
* var searchObject = $location.search();
* // => {foo: 'bar', baz: 'xoxo'}
*
- *
* // set foo to 'yipee'
* $location.search('foo', 'yipee');
- * // => $location
+ * // $location.search() => {foo: 'yipee', baz: 'xoxo'}
* ```
*
* @param {string|Object.<string>|Object.<Array.<string>>} search New search params - string or
@@ -9684,6 +11739,7 @@ LocationHashbangInHtml5Url.prototype =
search = search.toString();
this.$$search = parseKeyValue(search);
} else if (isObject(search)) {
+ search = copy(search, {});
// remove object undefined or null properties
forEach(search, function(value, key) {
if (value == null) delete search[key];
@@ -9718,6 +11774,13 @@ LocationHashbangInHtml5Url.prototype =
*
* Change hash fragment when called with parameter and return `$location`.
*
+ *
+ * ```js
+ * // given url http://example.com/#/some/path?foo=bar&baz=xoxo#hashValue
+ * var hash = $location.hash();
+ * // => "hashValue"
+ * ```
+ *
* @param {(string|number)=} hash New hash fragment
* @return {string} hash
*/
@@ -9739,6 +11802,47 @@ LocationHashbangInHtml5Url.prototype =
}
};
+forEach([LocationHashbangInHtml5Url, LocationHashbangUrl, LocationHtml5Url], function(Location) {
+ Location.prototype = Object.create(locationPrototype);
+
+ /**
+ * @ngdoc method
+ * @name $location#state
+ *
+ * @description
+ * This method is getter / setter.
+ *
+ * Return the history state object when called without any parameter.
+ *
+ * Change the history state object when called with one parameter and return `$location`.
+ * The state object is later passed to `pushState` or `replaceState`.
+ *
+ * NOTE: This method is supported only in HTML5 mode and only in browsers supporting
+ * the HTML5 History API (i.e. methods `pushState` and `replaceState`). If you need to support
+ * older browsers (like IE9 or Android < 4.0), don't use this method.
+ *
+ * @param {object=} state State object for pushState or replaceState
+ * @return {object} state
+ */
+ Location.prototype.state = function(state) {
+ if (!arguments.length) {
+ return this.$$state;
+ }
+
+ if (Location !== LocationHtml5Url || !this.$$html5) {
+ throw $locationMinErr('nostate', 'History API state support is available only ' +
+ 'in HTML5 mode and only in browsers supporting HTML5 History API');
+ }
+ // The user might modify `stateObject` after invoking `$location.state(stateObject)`
+ // but we're changing the $$state reference to $browser.state() during the $digest
+ // so the modification window is narrow.
+ this.$$state = isUndefined(state) ? null : state;
+
+ return this;
+ };
+});
+
+
function locationGetter(property) {
return function() {
return this[property];
@@ -9748,8 +11852,9 @@ function locationGetter(property) {
function locationGetterSetter(property, preprocess) {
return function(value) {
- if (isUndefined(value))
+ if (isUndefined(value)) {
return this[property];
+ }
this[property] = preprocess(value);
this.$$compose();
@@ -9791,9 +11896,13 @@ function locationGetterSetter(property, preprocess) {
* @description
* Use the `$locationProvider` to configure how the application deep linking paths are stored.
*/
-function $LocationProvider(){
+function $LocationProvider() {
var hashPrefix = '',
- html5Mode = false;
+ html5Mode = {
+ enabled: false,
+ requireBase: true,
+ rewriteLinks: true
+ };
/**
* @ngdoc method
@@ -9815,12 +11924,39 @@ function $LocationProvider(){
* @ngdoc method
* @name $locationProvider#html5Mode
* @description
- * @param {boolean=} mode Use HTML5 strategy if available.
- * @returns {*} current value if used as getter or itself (chaining) if used as setter
+ * @param {(boolean|Object)=} mode If boolean, sets `html5Mode.enabled` to value.
+ * If object, sets `enabled`, `requireBase` and `rewriteLinks` to respective values. Supported
+ * properties:
+ * - **enabled** – `{boolean}` – (default: false) If true, will rely on `history.pushState` to
+ * change urls where supported. Will fall back to hash-prefixed paths in browsers that do not
+ * support `pushState`.
+ * - **requireBase** - `{boolean}` - (default: `true`) When html5Mode is enabled, specifies
+ * whether or not a <base> tag is required to be present. If `enabled` and `requireBase` are
+ * true, and a base tag is not present, an error will be thrown when `$location` is injected.
+ * See the {@link guide/$location $location guide for more information}
+ * - **rewriteLinks** - `{boolean}` - (default: `true`) When html5Mode is enabled,
+ * enables/disables url rewriting for relative links.
+ *
+ * @returns {Object} html5Mode object if used as getter or itself (chaining) if used as setter
*/
this.html5Mode = function(mode) {
- if (isDefined(mode)) {
- html5Mode = mode;
+ if (isBoolean(mode)) {
+ html5Mode.enabled = mode;
+ return this;
+ } else if (isObject(mode)) {
+
+ if (isBoolean(mode.enabled)) {
+ html5Mode.enabled = mode.enabled;
+ }
+
+ if (isBoolean(mode.requireBase)) {
+ html5Mode.requireBase = mode.requireBase;
+ }
+
+ if (isBoolean(mode.rewriteLinks)) {
+ html5Mode.rewriteLinks = mode.rewriteLinks;
+ }
+
return this;
} else {
return html5Mode;
@@ -9832,14 +11968,21 @@ function $LocationProvider(){
* @name $location#$locationChangeStart
* @eventType broadcast on root scope
* @description
- * Broadcasted before a URL will change. This change can be prevented by calling
+ * Broadcasted before a URL will change.
+ *
+ * This change can be prevented by calling
* `preventDefault` method of the event. See {@link ng.$rootScope.Scope#$on} for more
* details about event object. Upon successful change
- * {@link ng.$location#events_$locationChangeSuccess $locationChangeSuccess} is fired.
+ * {@link ng.$location#$locationChangeSuccess $locationChangeSuccess} is fired.
+ *
+ * The `newState` and `oldState` parameters may be defined only in HTML5 mode and when
+ * the browser supports the HTML5 History API.
*
* @param {Object} angularEvent Synthetic event object.
* @param {string} newUrl New URL
* @param {string=} oldUrl URL that was before it was changed.
+ * @param {string=} newState New history state object
+ * @param {string=} oldState History state object that was before it was changed.
*/
/**
@@ -9849,20 +11992,29 @@ function $LocationProvider(){
* @description
* Broadcasted after a URL was changed.
*
+ * The `newState` and `oldState` parameters may be defined only in HTML5 mode and when
+ * the browser supports the HTML5 History API.
+ *
* @param {Object} angularEvent Synthetic event object.
* @param {string} newUrl New URL
* @param {string=} oldUrl URL that was before it was changed.
+ * @param {string=} newState New history state object
+ * @param {string=} oldState History state object that was before it was changed.
*/
- this.$get = ['$rootScope', '$browser', '$sniffer', '$rootElement',
- function( $rootScope, $browser, $sniffer, $rootElement) {
+ this.$get = ['$rootScope', '$browser', '$sniffer', '$rootElement', '$window',
+ function($rootScope, $browser, $sniffer, $rootElement, $window) {
var $location,
LocationMode,
baseHref = $browser.baseHref(), // if base[href] is undefined, it defaults to ''
initialUrl = $browser.url(),
appBase;
- if (html5Mode) {
+ if (html5Mode.enabled) {
+ if (!baseHref && html5Mode.requireBase) {
+ throw $locationMinErr('nobase',
+ "$location in HTML5 mode requires a <base> tag to be present!");
+ }
appBase = serverBase(initialUrl) + (baseHref || '/');
LocationMode = $sniffer.history ? LocationHtml5Url : LocationHashbangInHtml5Url;
} else {
@@ -9872,18 +12024,39 @@ function $LocationProvider(){
$location = new LocationMode(appBase, '#' + hashPrefix);
$location.$$parseLinkUrl(initialUrl, initialUrl);
+ $location.$$state = $browser.state();
+
var IGNORE_URI_REGEXP = /^\s*(javascript|mailto):/i;
+ function setBrowserUrlWithFallback(url, replace, state) {
+ var oldUrl = $location.url();
+ var oldState = $location.$$state;
+ try {
+ $browser.url(url, replace, state);
+
+ // Make sure $location.state() returns referentially identical (not just deeply equal)
+ // state object; this makes possible quick checking if the state changed in the digest
+ // loop. Checking deep equality would be too expensive.
+ $location.$$state = $browser.state();
+ } catch (e) {
+ // Restore old values if pushState fails
+ $location.url(oldUrl);
+ $location.$$state = oldState;
+
+ throw e;
+ }
+ }
+
$rootElement.on('click', function(event) {
// TODO(vojta): rewrite link when opening in new tab/window (in legacy browser)
// currently we open nice url link and redirect then
- if (event.ctrlKey || event.metaKey || event.which == 2) return;
+ if (!html5Mode.rewriteLinks || event.ctrlKey || event.metaKey || event.shiftKey || event.which == 2 || event.button == 2) return;
var elm = jqLite(event.target);
// traverse the DOM up to find first A tag
- while (lowercase(elm[0].nodeName) !== 'a') {
+ while (nodeName_(elm[0]) !== 'a') {
// ignore rewriting if no A tag (reached root element, or no parent - removed from document)
if (elm[0] === $rootElement[0] || !(elm = elm.parent())[0]) return;
}
@@ -9912,7 +12085,7 @@ function $LocationProvider(){
if ($location.absUrl() != $browser.url()) {
$rootScope.$apply();
// hack to work around FF6 bug 684208 when scenario runner clicks on links
- window.angular['ff-684208-preventDefault'] = true;
+ $window.angular['ff-684208-preventDefault'] = true;
}
}
}
@@ -9920,56 +12093,86 @@ function $LocationProvider(){
// rewrite hashbang url <> html5 url
- if ($location.absUrl() != initialUrl) {
+ if (trimEmptyHash($location.absUrl()) != trimEmptyHash(initialUrl)) {
$browser.url($location.absUrl(), true);
}
- // update $location when $browser url changes
- $browser.onUrlChange(function(newUrl) {
- if ($location.absUrl() != newUrl) {
- $rootScope.$evalAsync(function() {
- var oldUrl = $location.absUrl();
+ var initializing = true;
- $location.$$parse(newUrl);
- if ($rootScope.$broadcast('$locationChangeStart', newUrl,
- oldUrl).defaultPrevented) {
- $location.$$parse(oldUrl);
- $browser.url(oldUrl);
- } else {
- afterLocationChange(oldUrl);
- }
- });
- if (!$rootScope.$$phase) $rootScope.$digest();
- }
+ // update $location when $browser url changes
+ $browser.onUrlChange(function(newUrl, newState) {
+ $rootScope.$evalAsync(function() {
+ var oldUrl = $location.absUrl();
+ var oldState = $location.$$state;
+ var defaultPrevented;
+
+ $location.$$parse(newUrl);
+ $location.$$state = newState;
+
+ defaultPrevented = $rootScope.$broadcast('$locationChangeStart', newUrl, oldUrl,
+ newState, oldState).defaultPrevented;
+
+ // if the location was changed by a `$locationChangeStart` handler then stop
+ // processing this location change
+ if ($location.absUrl() !== newUrl) return;
+
+ if (defaultPrevented) {
+ $location.$$parse(oldUrl);
+ $location.$$state = oldState;
+ setBrowserUrlWithFallback(oldUrl, false, oldState);
+ } else {
+ initializing = false;
+ afterLocationChange(oldUrl, oldState);
+ }
+ });
+ if (!$rootScope.$$phase) $rootScope.$digest();
});
// update browser
- var changeCounter = 0;
$rootScope.$watch(function $locationWatch() {
- var oldUrl = $browser.url();
+ var oldUrl = trimEmptyHash($browser.url());
+ var newUrl = trimEmptyHash($location.absUrl());
+ var oldState = $browser.state();
var currentReplace = $location.$$replace;
+ var urlOrStateChanged = oldUrl !== newUrl ||
+ ($location.$$html5 && $sniffer.history && oldState !== $location.$$state);
+
+ if (initializing || urlOrStateChanged) {
+ initializing = false;
- if (!changeCounter || oldUrl != $location.absUrl()) {
- changeCounter++;
$rootScope.$evalAsync(function() {
- if ($rootScope.$broadcast('$locationChangeStart', $location.absUrl(), oldUrl).
- defaultPrevented) {
+ var newUrl = $location.absUrl();
+ var defaultPrevented = $rootScope.$broadcast('$locationChangeStart', newUrl, oldUrl,
+ $location.$$state, oldState).defaultPrevented;
+
+ // if the location was changed by a `$locationChangeStart` handler then stop
+ // processing this location change
+ if ($location.absUrl() !== newUrl) return;
+
+ if (defaultPrevented) {
$location.$$parse(oldUrl);
+ $location.$$state = oldState;
} else {
- $browser.url($location.absUrl(), currentReplace);
- afterLocationChange(oldUrl);
+ if (urlOrStateChanged) {
+ setBrowserUrlWithFallback(newUrl, currentReplace,
+ oldState === $location.$$state ? null : $location.$$state);
+ }
+ afterLocationChange(oldUrl, oldState);
}
});
}
+
$location.$$replace = false;
- return changeCounter;
+ // we don't need to return anything because $evalAsync will make the digest loop dirty when
+ // there is a change
});
return $location;
- function afterLocationChange(oldUrl) {
- $rootScope.$broadcast('$locationChangeSuccess', $location.absUrl(), oldUrl);
+ function afterLocationChange(oldUrl, oldState) {
+ $rootScope.$broadcast('$locationChangeSuccess', $location.absUrl(), oldUrl,
+ $location.$$state, oldState);
}
}];
}
@@ -10000,12 +12203,13 @@ function $LocationProvider(){
<file name="index.html">
<div ng-controller="LogController">
<p>Reload this page with open console, enter text and hit the log button...</p>
- Message:
- <input type="text" ng-model="message"/>
+ <label>Message:
+ <input type="text" ng-model="message" /></label>
<button ng-click="$log.log(message)">log</button>
<button ng-click="$log.warn(message)">warn</button>
<button ng-click="$log.info(message)">info</button>
<button ng-click="$log.error(message)">error</button>
+ <button ng-click="$log.debug(message)">debug</button>
</div>
</file>
</example>
@@ -10017,7 +12221,7 @@ function $LocationProvider(){
* @description
* Use the `$logProvider` to configure how the application logs messages
*/
-function $LogProvider(){
+function $LogProvider() {
var debug = true,
self = this;
@@ -10037,7 +12241,7 @@ function $LogProvider(){
}
};
- this.$get = ['$window', function($window){
+ this.$get = ['$window', function($window) {
return {
/**
* @ngdoc method
@@ -10082,7 +12286,7 @@ function $LogProvider(){
* @description
* Write a debug message
*/
- debug: (function () {
+ debug: (function() {
var fn = consoleLog('debug');
return function() {
@@ -10136,9 +12340,18 @@ function $LogProvider(){
}];
}
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Any commits to this file should be reviewed with security in mind. *
+ * Changes to this file can potentially create security vulnerabilities. *
+ * An approval from 2 Core members with history of modifying *
+ * this file is required. *
+ * *
+ * Does the change somehow allow for arbitrary javascript to be executed? *
+ * Or allows for someone to change the prototype of built-in objects? *
+ * Or gives undesired access to variables likes document or window? *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
var $parseMinErr = minErr('$parse');
-var promiseWarningCache = {};
-var promiseWarning;
// Sandboxing Angular Expressions
// ------------------------------
@@ -10170,7 +12383,7 @@ function ensureSafeMemberName(name, fullExpression) {
|| name === "__proto__") {
throw $parseMinErr('isecfld',
'Attempting to access a disallowed field in Angular expressions! '
- +'Expression: {0}', fullExpression);
+ + 'Expression: {0}', fullExpression);
}
return name;
}
@@ -10183,7 +12396,7 @@ function ensureSafeObject(obj, fullExpression) {
'Referencing Function in Angular expressions is disallowed! Expression: {0}',
fullExpression);
} else if (// isWindow(obj)
- obj.document && obj.location && obj.alert && obj.setInterval) {
+ obj.window === obj) {
throw $parseMinErr('isecwindow',
'Referencing the Window in Angular expressions is disallowed! Expression: {0}',
fullExpression);
@@ -10212,7 +12425,7 @@ function ensureSafeFunction(obj, fullExpression) {
throw $parseMinErr('isecfn',
'Referencing Function in Angular expressions is disallowed! Expression: {0}',
fullExpression);
- } else if (obj === CALL || obj === APPLY || (BIND && obj === BIND)) {
+ } else if (obj === CALL || obj === APPLY || obj === BIND) {
throw $parseMinErr('isecff',
'Referencing call, apply or bind in Angular expressions is disallowed! Expression: {0}',
fullExpression);
@@ -10220,46 +12433,8 @@ function ensureSafeFunction(obj, fullExpression) {
}
}
-var OPERATORS = {
- /* jshint bitwise : false */
- 'null':function(){return null;},
- 'true':function(){return true;},
- 'false':function(){return false;},
- undefined:noop,
- '+':function(self, locals, a,b){
- a=a(self, locals); b=b(self, locals);
- if (isDefined(a)) {
- if (isDefined(b)) {
- return a + b;
- }
- return a;
- }
- return isDefined(b)?b:undefined;},
- '-':function(self, locals, a,b){
- a=a(self, locals); b=b(self, locals);
- return (isDefined(a)?a:0)-(isDefined(b)?b:0);
- },
- '*':function(self, locals, a,b){return a(self, locals)*b(self, locals);},
- '/':function(self, locals, a,b){return a(self, locals)/b(self, locals);},
- '%':function(self, locals, a,b){return a(self, locals)%b(self, locals);},
- '^':function(self, locals, a,b){return a(self, locals)^b(self, locals);},
- '=':noop,
- '===':function(self, locals, a, b){return a(self, locals)===b(self, locals);},
- '!==':function(self, locals, a, b){return a(self, locals)!==b(self, locals);},
- '==':function(self, locals, a,b){return a(self, locals)==b(self, locals);},
- '!=':function(self, locals, a,b){return a(self, locals)!=b(self, locals);},
- '<':function(self, locals, a,b){return a(self, locals)<b(self, locals);},
- '>':function(self, locals, a,b){return a(self, locals)>b(self, locals);},
- '<=':function(self, locals, a,b){return a(self, locals)<=b(self, locals);},
- '>=':function(self, locals, a,b){return a(self, locals)>=b(self, locals);},
- '&&':function(self, locals, a,b){return a(self, locals)&&b(self, locals);},
- '||':function(self, locals, a,b){return a(self, locals)||b(self, locals);},
- '&':function(self, locals, a,b){return a(self, locals)&b(self, locals);},
-// '|':function(self, locals, a,b){return a|b;},
- '|':function(self, locals, a,b){return b(self, locals)(self, locals, a(self, locals));},
- '!':function(self, locals, a){return !a(self, locals);}
-};
-/* jshint bitwise: true */
+var OPERATORS = createMap();
+forEach('+ - * / % === !== == != < > <= >= && || ! = |'.split(' '), function(operator) { OPERATORS[operator] = true; });
var ESCAPE = {"n":"\n", "f":"\f", "r":"\r", "t":"\t", "v":"\v", "'":"'", '"':'"'};
@@ -10269,73 +12444,51 @@ var ESCAPE = {"n":"\n", "f":"\f", "r":"\r", "t":"\t", "v":"\v", "'":"'", '"':'"'
/**
* @constructor
*/
-var Lexer = function (options) {
+var Lexer = function(options) {
this.options = options;
};
Lexer.prototype = {
constructor: Lexer,
- lex: function (text) {
+ lex: function(text) {
this.text = text;
-
this.index = 0;
- this.ch = undefined;
- this.lastCh = ':'; // can start regexp
-
this.tokens = [];
while (this.index < this.text.length) {
- this.ch = this.text.charAt(this.index);
- if (this.is('"\'')) {
- this.readString(this.ch);
- } else if (this.isNumber(this.ch) || this.is('.') && this.isNumber(this.peek())) {
+ var ch = this.text.charAt(this.index);
+ if (ch === '"' || ch === "'") {
+ this.readString(ch);
+ } else if (this.isNumber(ch) || ch === '.' && this.isNumber(this.peek())) {
this.readNumber();
- } else if (this.isIdent(this.ch)) {
+ } else if (this.isIdent(ch)) {
this.readIdent();
- } else if (this.is('(){}[].,;:?')) {
- this.tokens.push({
- index: this.index,
- text: this.ch
- });
+ } else if (this.is(ch, '(){}[].,;:?')) {
+ this.tokens.push({index: this.index, text: ch});
this.index++;
- } else if (this.isWhitespace(this.ch)) {
+ } else if (this.isWhitespace(ch)) {
this.index++;
- continue;
} else {
- var ch2 = this.ch + this.peek();
+ var ch2 = ch + this.peek();
var ch3 = ch2 + this.peek(2);
- var fn = OPERATORS[this.ch];
- var fn2 = OPERATORS[ch2];
- var fn3 = OPERATORS[ch3];
- if (fn3) {
- this.tokens.push({index: this.index, text: ch3, fn: fn3});
- this.index += 3;
- } else if (fn2) {
- this.tokens.push({index: this.index, text: ch2, fn: fn2});
- this.index += 2;
- } else if (fn) {
- this.tokens.push({
- index: this.index,
- text: this.ch,
- fn: fn
- });
- this.index += 1;
+ var op1 = OPERATORS[ch];
+ var op2 = OPERATORS[ch2];
+ var op3 = OPERATORS[ch3];
+ if (op1 || op2 || op3) {
+ var token = op3 ? ch3 : (op2 ? ch2 : ch);
+ this.tokens.push({index: this.index, text: token, operator: true});
+ this.index += token.length;
} else {
this.throwError('Unexpected next character ', this.index, this.index + 1);
}
}
- this.lastCh = this.ch;
}
return this.tokens;
},
- is: function(chars) {
- return chars.indexOf(this.ch) !== -1;
- },
-
- was: function(chars) {
- return chars.indexOf(this.lastCh) !== -1;
+ is: function(ch, chars) {
+ return chars.indexOf(ch) !== -1;
},
peek: function(i) {
@@ -10344,7 +12497,7 @@ Lexer.prototype = {
},
isNumber: function(ch) {
- return ('0' <= ch && ch <= '9');
+ return ('0' <= ch && ch <= '9') && typeof ch === "string";
},
isWhitespace: function(ch) {
@@ -10397,88 +12550,28 @@ Lexer.prototype = {
}
this.index++;
}
- number = 1 * number;
this.tokens.push({
index: start,
text: number,
- literal: true,
constant: true,
- fn: function() { return number; }
+ value: Number(number)
});
},
readIdent: function() {
- var parser = this;
-
- var ident = '';
var start = this.index;
-
- var lastDot, peekIndex, methodName, ch;
-
while (this.index < this.text.length) {
- ch = this.text.charAt(this.index);
- if (ch === '.' || this.isIdent(ch) || this.isNumber(ch)) {
- if (ch === '.') lastDot = this.index;
- ident += ch;
- } else {
+ var ch = this.text.charAt(this.index);
+ if (!(this.isIdent(ch) || this.isNumber(ch))) {
break;
}
this.index++;
}
-
- //check if this is not a method invocation and if it is back out to last dot
- if (lastDot) {
- peekIndex = this.index;
- while (peekIndex < this.text.length) {
- ch = this.text.charAt(peekIndex);
- if (ch === '(') {
- methodName = ident.substr(lastDot - start + 1);
- ident = ident.substr(0, lastDot - start);
- this.index = peekIndex;
- break;
- }
- if (this.isWhitespace(ch)) {
- peekIndex++;
- } else {
- break;
- }
- }
- }
-
-
- var token = {
+ this.tokens.push({
index: start,
- text: ident
- };
-
- // OPERATORS is our own object so we don't need to use special hasOwnPropertyFn
- if (OPERATORS.hasOwnProperty(ident)) {
- token.fn = OPERATORS[ident];
- token.literal = true;
- token.constant = true;
- } else {
- var getter = getterFn(ident, this.options, this.text);
- token.fn = extend(function(self, locals) {
- return (getter(self, locals));
- }, {
- assign: function(self, value) {
- return setter(self, ident, value, parser.text, parser.options);
- }
- });
- }
-
- this.tokens.push(token);
-
- if (methodName) {
- this.tokens.push({
- index:lastDot,
- text: '.'
- });
- this.tokens.push({
- index: lastDot + 1,
- text: methodName
- });
- }
+ text: this.text.slice(start, this.index),
+ identifier: true
+ });
},
readString: function(quote) {
@@ -10493,8 +12586,9 @@ Lexer.prototype = {
if (escape) {
if (ch === 'u') {
var hex = this.text.substring(this.index + 1, this.index + 5);
- if (!hex.match(/[\da-f]{4}/i))
+ if (!hex.match(/[\da-f]{4}/i)) {
this.throwError('Invalid unicode escape [\\u' + hex + ']');
+ }
this.index += 4;
string += String.fromCharCode(parseInt(hex, 16));
} else {
@@ -10509,10 +12603,8 @@ Lexer.prototype = {
this.tokens.push({
index: start,
text: rawString,
- string: string,
- literal: true,
constant: true,
- fn: function() { return string; }
+ value: string
});
return;
} else {
@@ -10524,198 +12616,66 @@ Lexer.prototype = {
}
};
-
-/**
- * @constructor
- */
-var Parser = function (lexer, $filter, options) {
+var AST = function(lexer, options) {
this.lexer = lexer;
- this.$filter = $filter;
this.options = options;
};
-Parser.ZERO = extend(function () {
- return 0;
-}, {
- constant: true
-});
-
-Parser.prototype = {
- constructor: Parser,
-
- parse: function (text) {
+AST.Program = 'Program';
+AST.ExpressionStatement = 'ExpressionStatement';
+AST.AssignmentExpression = 'AssignmentExpression';
+AST.ConditionalExpression = 'ConditionalExpression';
+AST.LogicalExpression = 'LogicalExpression';
+AST.BinaryExpression = 'BinaryExpression';
+AST.UnaryExpression = 'UnaryExpression';
+AST.CallExpression = 'CallExpression';
+AST.MemberExpression = 'MemberExpression';
+AST.Identifier = 'Identifier';
+AST.Literal = 'Literal';
+AST.ArrayExpression = 'ArrayExpression';
+AST.Property = 'Property';
+AST.ObjectExpression = 'ObjectExpression';
+AST.ThisExpression = 'ThisExpression';
+
+// Internal use only
+AST.NGValueParameter = 'NGValueParameter';
+
+AST.prototype = {
+ ast: function(text) {
this.text = text;
-
this.tokens = this.lexer.lex(text);
- var value = this.statements();
+ var value = this.program();
if (this.tokens.length !== 0) {
this.throwError('is an unexpected token', this.tokens[0]);
}
- value.literal = !!value.literal;
- value.constant = !!value.constant;
-
return value;
},
- primary: function () {
- var primary;
- if (this.expect('(')) {
- primary = this.filterChain();
- this.consume(')');
- } else if (this.expect('[')) {
- primary = this.arrayDeclaration();
- } else if (this.expect('{')) {
- primary = this.object();
- } else {
- var token = this.expect();
- primary = token.fn;
- if (!primary) {
- this.throwError('not a primary expression', token);
- }
- primary.literal = !!token.literal;
- primary.constant = !!token.constant;
- }
-
- var next, context;
- while ((next = this.expect('(', '[', '.'))) {
- if (next.text === '(') {
- primary = this.functionCall(primary, context);
- context = null;
- } else if (next.text === '[') {
- context = primary;
- primary = this.objectIndex(primary);
- } else if (next.text === '.') {
- context = primary;
- primary = this.fieldAccess(primary);
- } else {
- this.throwError('IMPOSSIBLE');
- }
- }
- return primary;
- },
-
- throwError: function(msg, token) {
- throw $parseMinErr('syntax',
- 'Syntax Error: Token \'{0}\' {1} at column {2} of the expression [{3}] starting at [{4}].',
- token.text, msg, (token.index + 1), this.text, this.text.substring(token.index));
- },
-
- peekToken: function() {
- if (this.tokens.length === 0)
- throw $parseMinErr('ueoe', 'Unexpected end of expression: {0}', this.text);
- return this.tokens[0];
- },
-
- peek: function(e1, e2, e3, e4) {
- if (this.tokens.length > 0) {
- var token = this.tokens[0];
- var t = token.text;
- if (t === e1 || t === e2 || t === e3 || t === e4 ||
- (!e1 && !e2 && !e3 && !e4)) {
- return token;
- }
- }
- return false;
- },
-
- expect: function(e1, e2, e3, e4){
- var token = this.peek(e1, e2, e3, e4);
- if (token) {
- this.tokens.shift();
- return token;
- }
- return false;
- },
-
- consume: function(e1){
- if (!this.expect(e1)) {
- this.throwError('is unexpected, expecting [' + e1 + ']', this.peek());
- }
- },
-
- unaryFn: function(fn, right) {
- return extend(function(self, locals) {
- return fn(self, locals, right);
- }, {
- constant:right.constant
- });
- },
-
- ternaryFn: function(left, middle, right){
- return extend(function(self, locals){
- return left(self, locals) ? middle(self, locals) : right(self, locals);
- }, {
- constant: left.constant && middle.constant && right.constant
- });
- },
-
- binaryFn: function(left, fn, right) {
- return extend(function(self, locals) {
- return fn(self, locals, left, right);
- }, {
- constant:left.constant && right.constant
- });
- },
-
- statements: function() {
- var statements = [];
+ program: function() {
+ var body = [];
while (true) {
if (this.tokens.length > 0 && !this.peek('}', ')', ';', ']'))
- statements.push(this.filterChain());
+ body.push(this.expressionStatement());
if (!this.expect(';')) {
- // optimize for the common case where there is only one statement.
- // TODO(size): maybe we should not support multiple statements?
- return (statements.length === 1)
- ? statements[0]
- : function(self, locals) {
- var value;
- for (var i = 0; i < statements.length; i++) {
- var statement = statements[i];
- if (statement) {
- value = statement(self, locals);
- }
- }
- return value;
- };
+ return { type: AST.Program, body: body};
}
}
},
+ expressionStatement: function() {
+ return { type: AST.ExpressionStatement, expression: this.filterChain() };
+ },
+
filterChain: function() {
var left = this.expression();
var token;
- while (true) {
- if ((token = this.expect('|'))) {
- left = this.binaryFn(left, token.fn, this.filter());
- } else {
- return left;
- }
- }
- },
-
- filter: function() {
- var token = this.expect();
- var fn = this.$filter(token.text);
- var argsFn = [];
- while (true) {
- if ((token = this.expect(':'))) {
- argsFn.push(this.expression());
- } else {
- var fnInvoke = function(self, locals, input) {
- var args = [input];
- for (var i = 0; i < argsFn.length; i++) {
- args.push(argsFn[i](self, locals));
- }
- return fn.apply(self, args);
- };
- return function() {
- return fnInvoke;
- };
- }
+ while ((token = this.expect('|'))) {
+ left = this.filter(left);
}
+ return left;
},
expression: function() {
@@ -10723,55 +12683,39 @@ Parser.prototype = {
},
assignment: function() {
- var left = this.ternary();
- var right;
- var token;
- if ((token = this.expect('='))) {
- if (!left.assign) {
- this.throwError('implies assignment but [' +
- this.text.substring(0, token.index) + '] can not be assigned to', token);
- }
- right = this.ternary();
- return function(scope, locals) {
- return left.assign(scope, right(scope, locals), locals);
- };
+ var result = this.ternary();
+ if (this.expect('=')) {
+ result = { type: AST.AssignmentExpression, left: result, right: this.assignment(), operator: '='};
}
- return left;
+ return result;
},
ternary: function() {
- var left = this.logicalOR();
- var middle;
- var token;
- if ((token = this.expect('?'))) {
- middle = this.assignment();
- if ((token = this.expect(':'))) {
- return this.ternaryFn(left, middle, this.assignment());
- } else {
- this.throwError('expected :', token);
+ var test = this.logicalOR();
+ var alternate;
+ var consequent;
+ if (this.expect('?')) {
+ alternate = this.expression();
+ if (this.consume(':')) {
+ consequent = this.expression();
+ return { type: AST.ConditionalExpression, test: test, alternate: alternate, consequent: consequent};
}
- } else {
- return left;
}
+ return test;
},
logicalOR: function() {
var left = this.logicalAND();
- var token;
- while (true) {
- if ((token = this.expect('||'))) {
- left = this.binaryFn(left, token.fn, this.logicalAND());
- } else {
- return left;
- }
+ while (this.expect('||')) {
+ left = { type: AST.LogicalExpression, operator: '||', left: left, right: this.logicalAND() };
}
+ return left;
},
logicalAND: function() {
var left = this.equality();
- var token;
- if ((token = this.expect('&&'))) {
- left = this.binaryFn(left, token.fn, this.logicalAND());
+ while (this.expect('&&')) {
+ left = { type: AST.LogicalExpression, operator: '&&', left: left, right: this.equality()};
}
return left;
},
@@ -10779,8 +12723,8 @@ Parser.prototype = {
equality: function() {
var left = this.relational();
var token;
- if ((token = this.expect('==','!=','===','!=='))) {
- left = this.binaryFn(left, token.fn, this.equality());
+ while ((token = this.expect('==','!=','===','!=='))) {
+ left = { type: AST.BinaryExpression, operator: token.text, left: left, right: this.relational() };
}
return left;
},
@@ -10788,8 +12732,8 @@ Parser.prototype = {
relational: function() {
var left = this.additive();
var token;
- if ((token = this.expect('<', '>', '<=', '>='))) {
- left = this.binaryFn(left, token.fn, this.relational());
+ while ((token = this.expect('<', '>', '<=', '>='))) {
+ left = { type: AST.BinaryExpression, operator: token.text, left: left, right: this.additive() };
}
return left;
},
@@ -10798,7 +12742,7 @@ Parser.prototype = {
var left = this.multiplicative();
var token;
while ((token = this.expect('+','-'))) {
- left = this.binaryFn(left, token.fn, this.multiplicative());
+ left = { type: AST.BinaryExpression, operator: token.text, left: left, right: this.multiplicative() };
}
return left;
},
@@ -10807,426 +12751,1239 @@ Parser.prototype = {
var left = this.unary();
var token;
while ((token = this.expect('*','/','%'))) {
- left = this.binaryFn(left, token.fn, this.unary());
+ left = { type: AST.BinaryExpression, operator: token.text, left: left, right: this.unary() };
}
return left;
},
unary: function() {
var token;
- if (this.expect('+')) {
- return this.primary();
- } else if ((token = this.expect('-'))) {
- return this.binaryFn(Parser.ZERO, token.fn, this.unary());
- } else if ((token = this.expect('!'))) {
- return this.unaryFn(token.fn, this.unary());
+ if ((token = this.expect('+', '-', '!'))) {
+ return { type: AST.UnaryExpression, operator: token.text, prefix: true, argument: this.unary() };
} else {
return this.primary();
}
},
- fieldAccess: function(object) {
- var parser = this;
- var field = this.expect().text;
- var getter = getterFn(field, this.options, this.text);
+ primary: function() {
+ var primary;
+ if (this.expect('(')) {
+ primary = this.filterChain();
+ this.consume(')');
+ } else if (this.expect('[')) {
+ primary = this.arrayDeclaration();
+ } else if (this.expect('{')) {
+ primary = this.object();
+ } else if (this.constants.hasOwnProperty(this.peek().text)) {
+ primary = copy(this.constants[this.consume().text]);
+ } else if (this.peek().identifier) {
+ primary = this.identifier();
+ } else if (this.peek().constant) {
+ primary = this.constant();
+ } else {
+ this.throwError('not a primary expression', this.peek());
+ }
- return extend(function(scope, locals, self) {
- return getter(self || object(scope, locals));
- }, {
- assign: function(scope, value, locals) {
- var o = object(scope, locals);
- if (!o) object.assign(scope, o = {});
- return setter(o, field, value, parser.text, parser.options);
+ var next;
+ while ((next = this.expect('(', '[', '.'))) {
+ if (next.text === '(') {
+ primary = {type: AST.CallExpression, callee: primary, arguments: this.parseArguments() };
+ this.consume(')');
+ } else if (next.text === '[') {
+ primary = { type: AST.MemberExpression, object: primary, property: this.expression(), computed: true };
+ this.consume(']');
+ } else if (next.text === '.') {
+ primary = { type: AST.MemberExpression, object: primary, property: this.identifier(), computed: false };
+ } else {
+ this.throwError('IMPOSSIBLE');
}
- });
+ }
+ return primary;
},
- objectIndex: function(obj) {
- var parser = this;
+ filter: function(baseExpression) {
+ var args = [baseExpression];
+ var result = {type: AST.CallExpression, callee: this.identifier(), arguments: args, filter: true};
- var indexFn = this.expression();
- this.consume(']');
+ while (this.expect(':')) {
+ args.push(this.expression());
+ }
- return extend(function(self, locals) {
- var o = obj(self, locals),
- i = indexFn(self, locals),
- v, p;
-
- ensureSafeMemberName(i, parser.text);
- if (!o) return undefined;
- v = ensureSafeObject(o[i], parser.text);
- if (v && v.then && parser.options.unwrapPromises) {
- p = v;
- if (!('$$v' in v)) {
- p.$$v = undefined;
- p.then(function(val) { p.$$v = val; });
- }
- v = v.$$v;
- }
- return v;
- }, {
- assign: function(self, value, locals) {
- var key = ensureSafeMemberName(indexFn(self, locals), parser.text);
- // prevent overwriting of Function.constructor which would break ensureSafeObject check
- var o = ensureSafeObject(obj(self, locals), parser.text);
- if (!o) obj.assign(self, o = {});
- return o[key] = value;
- }
- });
+ return result;
},
- functionCall: function(fn, contextGetter) {
- var argsFn = [];
+ parseArguments: function() {
+ var args = [];
if (this.peekToken().text !== ')') {
do {
- argsFn.push(this.expression());
+ args.push(this.expression());
} while (this.expect(','));
}
- this.consume(')');
-
- var parser = this;
-
- return function(scope, locals) {
- var args = [];
- var context = contextGetter ? contextGetter(scope, locals) : scope;
-
- for (var i = 0; i < argsFn.length; i++) {
- args.push(ensureSafeObject(argsFn[i](scope, locals), parser.text));
- }
- var fnPtr = fn(scope, locals, context) || noop;
-
- ensureSafeObject(context, parser.text);
- ensureSafeFunction(fnPtr, parser.text);
+ return args;
+ },
- // IE doesn't have apply for some native functions
- var v = fnPtr.apply
- ? fnPtr.apply(context, args)
- : fnPtr(args[0], args[1], args[2], args[3], args[4]);
+ identifier: function() {
+ var token = this.consume();
+ if (!token.identifier) {
+ this.throwError('is not a valid identifier', token);
+ }
+ return { type: AST.Identifier, name: token.text };
+ },
- return ensureSafeObject(v, parser.text);
- };
+ constant: function() {
+ // TODO check that it is a constant
+ return { type: AST.Literal, value: this.consume().value };
},
- // This is used with json array declaration
- arrayDeclaration: function () {
- var elementFns = [];
- var allConstant = true;
+ arrayDeclaration: function() {
+ var elements = [];
if (this.peekToken().text !== ']') {
do {
if (this.peek(']')) {
// Support trailing commas per ES5.1.
break;
}
- var elementFn = this.expression();
- elementFns.push(elementFn);
- if (!elementFn.constant) {
- allConstant = false;
- }
+ elements.push(this.expression());
} while (this.expect(','));
}
this.consume(']');
- return extend(function(self, locals) {
- var array = [];
- for (var i = 0; i < elementFns.length; i++) {
- array.push(elementFns[i](self, locals));
- }
- return array;
- }, {
- literal: true,
- constant: allConstant
- });
+ return { type: AST.ArrayExpression, elements: elements };
},
- object: function () {
- var keyValues = [];
- var allConstant = true;
+ object: function() {
+ var properties = [], property;
if (this.peekToken().text !== '}') {
do {
if (this.peek('}')) {
// Support trailing commas per ES5.1.
break;
}
- var token = this.expect(),
- key = token.string || token.text;
- this.consume(':');
- var value = this.expression();
- keyValues.push({key: key, value: value});
- if (!value.constant) {
- allConstant = false;
+ property = {type: AST.Property, kind: 'init'};
+ if (this.peek().constant) {
+ property.key = this.constant();
+ } else if (this.peek().identifier) {
+ property.key = this.identifier();
+ } else {
+ this.throwError("invalid key", this.peek());
}
+ this.consume(':');
+ property.value = this.expression();
+ properties.push(property);
} while (this.expect(','));
}
this.consume('}');
- return extend(function(self, locals) {
- var object = {};
- for (var i = 0; i < keyValues.length; i++) {
- var keyValue = keyValues[i];
- object[keyValue.key] = keyValue.value(self, locals);
+ return {type: AST.ObjectExpression, properties: properties };
+ },
+
+ throwError: function(msg, token) {
+ throw $parseMinErr('syntax',
+ 'Syntax Error: Token \'{0}\' {1} at column {2} of the expression [{3}] starting at [{4}].',
+ token.text, msg, (token.index + 1), this.text, this.text.substring(token.index));
+ },
+
+ consume: function(e1) {
+ if (this.tokens.length === 0) {
+ throw $parseMinErr('ueoe', 'Unexpected end of expression: {0}', this.text);
+ }
+
+ var token = this.expect(e1);
+ if (!token) {
+ this.throwError('is unexpected, expecting [' + e1 + ']', this.peek());
+ }
+ return token;
+ },
+
+ peekToken: function() {
+ if (this.tokens.length === 0) {
+ throw $parseMinErr('ueoe', 'Unexpected end of expression: {0}', this.text);
+ }
+ return this.tokens[0];
+ },
+
+ peek: function(e1, e2, e3, e4) {
+ return this.peekAhead(0, e1, e2, e3, e4);
+ },
+
+ peekAhead: function(i, e1, e2, e3, e4) {
+ if (this.tokens.length > i) {
+ var token = this.tokens[i];
+ var t = token.text;
+ if (t === e1 || t === e2 || t === e3 || t === e4 ||
+ (!e1 && !e2 && !e3 && !e4)) {
+ return token;
}
- return object;
- }, {
- literal: true,
- constant: allConstant
- });
+ }
+ return false;
+ },
+
+ expect: function(e1, e2, e3, e4) {
+ var token = this.peek(e1, e2, e3, e4);
+ if (token) {
+ this.tokens.shift();
+ return token;
+ }
+ return false;
+ },
+
+
+ /* `undefined` is not a constant, it is an identifier,
+ * but using it as an identifier is not supported
+ */
+ constants: {
+ 'true': { type: AST.Literal, value: true },
+ 'false': { type: AST.Literal, value: false },
+ 'null': { type: AST.Literal, value: null },
+ 'undefined': {type: AST.Literal, value: undefined },
+ 'this': {type: AST.ThisExpression }
}
};
+function ifDefined(v, d) {
+ return typeof v !== 'undefined' ? v : d;
+}
-//////////////////////////////////////////////////
-// Parser helper functions
-//////////////////////////////////////////////////
-
-function setter(obj, path, setValue, fullExp, options) {
- ensureSafeObject(obj, fullExp);
+function plusFn(l, r) {
+ if (typeof l === 'undefined') return r;
+ if (typeof r === 'undefined') return l;
+ return l + r;
+}
- //needed?
- options = options || {};
+function isStateless($filter, filterName) {
+ var fn = $filter(filterName);
+ return !fn.$stateful;
+}
- var element = path.split('.'), key;
- for (var i = 0; element.length > 1; i++) {
- key = ensureSafeMemberName(element.shift(), fullExp);
- var propertyObj = ensureSafeObject(obj[key], fullExp);
- if (!propertyObj) {
- propertyObj = {};
- obj[key] = propertyObj;
+function findConstantAndWatchExpressions(ast, $filter) {
+ var allConstants;
+ var argsToWatch;
+ switch (ast.type) {
+ case AST.Program:
+ allConstants = true;
+ forEach(ast.body, function(expr) {
+ findConstantAndWatchExpressions(expr.expression, $filter);
+ allConstants = allConstants && expr.expression.constant;
+ });
+ ast.constant = allConstants;
+ break;
+ case AST.Literal:
+ ast.constant = true;
+ ast.toWatch = [];
+ break;
+ case AST.UnaryExpression:
+ findConstantAndWatchExpressions(ast.argument, $filter);
+ ast.constant = ast.argument.constant;
+ ast.toWatch = ast.argument.toWatch;
+ break;
+ case AST.BinaryExpression:
+ findConstantAndWatchExpressions(ast.left, $filter);
+ findConstantAndWatchExpressions(ast.right, $filter);
+ ast.constant = ast.left.constant && ast.right.constant;
+ ast.toWatch = ast.left.toWatch.concat(ast.right.toWatch);
+ break;
+ case AST.LogicalExpression:
+ findConstantAndWatchExpressions(ast.left, $filter);
+ findConstantAndWatchExpressions(ast.right, $filter);
+ ast.constant = ast.left.constant && ast.right.constant;
+ ast.toWatch = ast.constant ? [] : [ast];
+ break;
+ case AST.ConditionalExpression:
+ findConstantAndWatchExpressions(ast.test, $filter);
+ findConstantAndWatchExpressions(ast.alternate, $filter);
+ findConstantAndWatchExpressions(ast.consequent, $filter);
+ ast.constant = ast.test.constant && ast.alternate.constant && ast.consequent.constant;
+ ast.toWatch = ast.constant ? [] : [ast];
+ break;
+ case AST.Identifier:
+ ast.constant = false;
+ ast.toWatch = [ast];
+ break;
+ case AST.MemberExpression:
+ findConstantAndWatchExpressions(ast.object, $filter);
+ if (ast.computed) {
+ findConstantAndWatchExpressions(ast.property, $filter);
}
- obj = propertyObj;
- if (obj.then && options.unwrapPromises) {
- promiseWarning(fullExp);
- if (!("$$v" in obj)) {
- (function(promise) {
- promise.then(function(val) { promise.$$v = val; }); }
- )(obj);
+ ast.constant = ast.object.constant && (!ast.computed || ast.property.constant);
+ ast.toWatch = [ast];
+ break;
+ case AST.CallExpression:
+ allConstants = ast.filter ? isStateless($filter, ast.callee.name) : false;
+ argsToWatch = [];
+ forEach(ast.arguments, function(expr) {
+ findConstantAndWatchExpressions(expr, $filter);
+ allConstants = allConstants && expr.constant;
+ if (!expr.constant) {
+ argsToWatch.push.apply(argsToWatch, expr.toWatch);
}
- if (obj.$$v === undefined) {
- obj.$$v = {};
+ });
+ ast.constant = allConstants;
+ ast.toWatch = ast.filter && isStateless($filter, ast.callee.name) ? argsToWatch : [ast];
+ break;
+ case AST.AssignmentExpression:
+ findConstantAndWatchExpressions(ast.left, $filter);
+ findConstantAndWatchExpressions(ast.right, $filter);
+ ast.constant = ast.left.constant && ast.right.constant;
+ ast.toWatch = [ast];
+ break;
+ case AST.ArrayExpression:
+ allConstants = true;
+ argsToWatch = [];
+ forEach(ast.elements, function(expr) {
+ findConstantAndWatchExpressions(expr, $filter);
+ allConstants = allConstants && expr.constant;
+ if (!expr.constant) {
+ argsToWatch.push.apply(argsToWatch, expr.toWatch);
}
- obj = obj.$$v;
- }
+ });
+ ast.constant = allConstants;
+ ast.toWatch = argsToWatch;
+ break;
+ case AST.ObjectExpression:
+ allConstants = true;
+ argsToWatch = [];
+ forEach(ast.properties, function(property) {
+ findConstantAndWatchExpressions(property.value, $filter);
+ allConstants = allConstants && property.value.constant;
+ if (!property.value.constant) {
+ argsToWatch.push.apply(argsToWatch, property.value.toWatch);
+ }
+ });
+ ast.constant = allConstants;
+ ast.toWatch = argsToWatch;
+ break;
+ case AST.ThisExpression:
+ ast.constant = false;
+ ast.toWatch = [];
+ break;
}
- key = ensureSafeMemberName(element.shift(), fullExp);
- ensureSafeObject(obj[key], fullExp);
- obj[key] = setValue;
- return setValue;
}
-var getterFnCacheDefault = {};
-var getterFnCacheExpensive = {};
+function getInputs(body) {
+ if (body.length != 1) return;
+ var lastExpression = body[0].expression;
+ var candidate = lastExpression.toWatch;
+ if (candidate.length !== 1) return candidate;
+ return candidate[0] !== lastExpression ? candidate : undefined;
+}
-function isPossiblyDangerousMemberName(name) {
- return name == 'constructor';
+function isAssignable(ast) {
+ return ast.type === AST.Identifier || ast.type === AST.MemberExpression;
}
-/**
- * Implementation of the "Black Hole" variant from:
- * - http://jsperf.com/angularjs-parse-getter/4
- * - http://jsperf.com/path-evaluation-simplified/7
- */
-function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, options) {
- ensureSafeMemberName(key0, fullExp);
- ensureSafeMemberName(key1, fullExp);
- ensureSafeMemberName(key2, fullExp);
- ensureSafeMemberName(key3, fullExp);
- ensureSafeMemberName(key4, fullExp);
- var eso = function(o) {
- return ensureSafeObject(o, fullExp);
- };
- var expensiveChecks = options.expensiveChecks;
- var eso0 = (expensiveChecks || isPossiblyDangerousMemberName(key0)) ? eso : identity;
- var eso1 = (expensiveChecks || isPossiblyDangerousMemberName(key1)) ? eso : identity;
- var eso2 = (expensiveChecks || isPossiblyDangerousMemberName(key2)) ? eso : identity;
- var eso3 = (expensiveChecks || isPossiblyDangerousMemberName(key3)) ? eso : identity;
- var eso4 = (expensiveChecks || isPossiblyDangerousMemberName(key4)) ? eso : identity;
+function assignableAST(ast) {
+ if (ast.body.length === 1 && isAssignable(ast.body[0].expression)) {
+ return {type: AST.AssignmentExpression, left: ast.body[0].expression, right: {type: AST.NGValueParameter}, operator: '='};
+ }
+}
+
+function isLiteral(ast) {
+ return ast.body.length === 0 ||
+ ast.body.length === 1 && (
+ ast.body[0].expression.type === AST.Literal ||
+ ast.body[0].expression.type === AST.ArrayExpression ||
+ ast.body[0].expression.type === AST.ObjectExpression);
+}
- return !options.unwrapPromises
- ? function cspSafeGetter(scope, locals) {
- var pathVal = (locals && locals.hasOwnProperty(key0)) ? locals : scope;
+function isConstant(ast) {
+ return ast.constant;
+}
- if (pathVal == null) return pathVal;
- pathVal = eso0(pathVal[key0]);
+function ASTCompiler(astBuilder, $filter) {
+ this.astBuilder = astBuilder;
+ this.$filter = $filter;
+}
- if (!key1) return pathVal;
- if (pathVal == null) return undefined;
- pathVal = eso1(pathVal[key1]);
+ASTCompiler.prototype = {
+ compile: function(expression, expensiveChecks) {
+ var self = this;
+ var ast = this.astBuilder.ast(expression);
+ this.state = {
+ nextId: 0,
+ filters: {},
+ expensiveChecks: expensiveChecks,
+ fn: {vars: [], body: [], own: {}},
+ assign: {vars: [], body: [], own: {}},
+ inputs: []
+ };
+ findConstantAndWatchExpressions(ast, self.$filter);
+ var extra = '';
+ var assignable;
+ this.stage = 'assign';
+ if ((assignable = assignableAST(ast))) {
+ this.state.computing = 'assign';
+ var result = this.nextId();
+ this.recurse(assignable, result);
+ extra = 'fn.assign=' + this.generateFunction('assign', 's,v,l');
+ }
+ var toWatch = getInputs(ast.body);
+ self.stage = 'inputs';
+ forEach(toWatch, function(watch, key) {
+ var fnKey = 'fn' + key;
+ self.state[fnKey] = {vars: [], body: [], own: {}};
+ self.state.computing = fnKey;
+ var intoId = self.nextId();
+ self.recurse(watch, intoId);
+ self.return_(intoId);
+ self.state.inputs.push(fnKey);
+ watch.watchId = key;
+ });
+ this.state.computing = 'fn';
+ this.stage = 'main';
+ this.recurse(ast);
+ var fnString =
+ // The build and minification steps remove the string "use strict" from the code, but this is done using a regex.
+ // This is a workaround for this until we do a better job at only removing the prefix only when we should.
+ '"' + this.USE + ' ' + this.STRICT + '";\n' +
+ this.filterPrefix() +
+ 'var fn=' + this.generateFunction('fn', 's,l,a,i') +
+ extra +
+ this.watchFns() +
+ 'return fn;';
- if (!key2) return pathVal;
- if (pathVal == null) return undefined;
- pathVal = eso2(pathVal[key2]);
+ /* jshint -W054 */
+ var fn = (new Function('$filter',
+ 'ensureSafeMemberName',
+ 'ensureSafeObject',
+ 'ensureSafeFunction',
+ 'ifDefined',
+ 'plus',
+ 'text',
+ fnString))(
+ this.$filter,
+ ensureSafeMemberName,
+ ensureSafeObject,
+ ensureSafeFunction,
+ ifDefined,
+ plusFn,
+ expression);
+ /* jshint +W054 */
+ this.state = this.stage = undefined;
+ fn.literal = isLiteral(ast);
+ fn.constant = isConstant(ast);
+ return fn;
+ },
- if (!key3) return pathVal;
- if (pathVal == null) return undefined;
- pathVal = eso3(pathVal[key3]);
+ USE: 'use',
- if (!key4) return pathVal;
- if (pathVal == null) return undefined;
- pathVal = eso4(pathVal[key4]);
+ STRICT: 'strict',
- return pathVal;
+ watchFns: function() {
+ var result = [];
+ var fns = this.state.inputs;
+ var self = this;
+ forEach(fns, function(name) {
+ result.push('var ' + name + '=' + self.generateFunction(name, 's'));
+ });
+ if (fns.length) {
+ result.push('fn.inputs=[' + fns.join(',') + '];');
+ }
+ return result.join('');
+ },
+
+ generateFunction: function(name, params) {
+ return 'function(' + params + '){' +
+ this.varsPrefix(name) +
+ this.body(name) +
+ '};';
+ },
+
+ filterPrefix: function() {
+ var parts = [];
+ var self = this;
+ forEach(this.state.filters, function(id, filter) {
+ parts.push(id + '=$filter(' + self.escape(filter) + ')');
+ });
+ if (parts.length) return 'var ' + parts.join(',') + ';';
+ return '';
+ },
+
+ varsPrefix: function(section) {
+ return this.state[section].vars.length ? 'var ' + this.state[section].vars.join(',') + ';' : '';
+ },
+
+ body: function(section) {
+ return this.state[section].body.join('');
+ },
+
+ recurse: function(ast, intoId, nameId, recursionFn, create, skipWatchIdCheck) {
+ var left, right, self = this, args, expression;
+ recursionFn = recursionFn || noop;
+ if (!skipWatchIdCheck && isDefined(ast.watchId)) {
+ intoId = intoId || this.nextId();
+ this.if_('i',
+ this.lazyAssign(intoId, this.computedMember('i', ast.watchId)),
+ this.lazyRecurse(ast, intoId, nameId, recursionFn, create, true)
+ );
+ return;
+ }
+ switch (ast.type) {
+ case AST.Program:
+ forEach(ast.body, function(expression, pos) {
+ self.recurse(expression.expression, undefined, undefined, function(expr) { right = expr; });
+ if (pos !== ast.body.length - 1) {
+ self.current().body.push(right, ';');
+ } else {
+ self.return_(right);
}
- : function cspSafePromiseEnabledGetter(scope, locals) {
- var pathVal = (locals && locals.hasOwnProperty(key0)) ? locals : scope,
- promise;
-
- if (pathVal == null) return pathVal;
-
- pathVal = eso0(pathVal[key0]);
- if (pathVal && pathVal.then) {
- promiseWarning(fullExp);
- if (!("$$v" in pathVal)) {
- promise = pathVal;
- promise.$$v = undefined;
- promise.then(function(val) { promise.$$v = eso0(val); });
+ });
+ break;
+ case AST.Literal:
+ expression = this.escape(ast.value);
+ this.assign(intoId, expression);
+ recursionFn(expression);
+ break;
+ case AST.UnaryExpression:
+ this.recurse(ast.argument, undefined, undefined, function(expr) { right = expr; });
+ expression = ast.operator + '(' + this.ifDefined(right, 0) + ')';
+ this.assign(intoId, expression);
+ recursionFn(expression);
+ break;
+ case AST.BinaryExpression:
+ this.recurse(ast.left, undefined, undefined, function(expr) { left = expr; });
+ this.recurse(ast.right, undefined, undefined, function(expr) { right = expr; });
+ if (ast.operator === '+') {
+ expression = this.plus(left, right);
+ } else if (ast.operator === '-') {
+ expression = this.ifDefined(left, 0) + ast.operator + this.ifDefined(right, 0);
+ } else {
+ expression = '(' + left + ')' + ast.operator + '(' + right + ')';
+ }
+ this.assign(intoId, expression);
+ recursionFn(expression);
+ break;
+ case AST.LogicalExpression:
+ intoId = intoId || this.nextId();
+ self.recurse(ast.left, intoId);
+ self.if_(ast.operator === '&&' ? intoId : self.not(intoId), self.lazyRecurse(ast.right, intoId));
+ recursionFn(intoId);
+ break;
+ case AST.ConditionalExpression:
+ intoId = intoId || this.nextId();
+ self.recurse(ast.test, intoId);
+ self.if_(intoId, self.lazyRecurse(ast.alternate, intoId), self.lazyRecurse(ast.consequent, intoId));
+ recursionFn(intoId);
+ break;
+ case AST.Identifier:
+ intoId = intoId || this.nextId();
+ if (nameId) {
+ nameId.context = self.stage === 'inputs' ? 's' : this.assign(this.nextId(), this.getHasOwnProperty('l', ast.name) + '?l:s');
+ nameId.computed = false;
+ nameId.name = ast.name;
+ }
+ ensureSafeMemberName(ast.name);
+ self.if_(self.stage === 'inputs' || self.not(self.getHasOwnProperty('l', ast.name)),
+ function() {
+ self.if_(self.stage === 'inputs' || 's', function() {
+ if (create && create !== 1) {
+ self.if_(
+ self.not(self.nonComputedMember('s', ast.name)),
+ self.lazyAssign(self.nonComputedMember('s', ast.name), '{}'));
}
- pathVal = eso0(pathVal.$$v);
- }
-
- if (!key1) return pathVal;
- if (pathVal == null) return undefined;
- pathVal = eso1(pathVal[key1]);
- if (pathVal && pathVal.then) {
- promiseWarning(fullExp);
- if (!("$$v" in pathVal)) {
- promise = pathVal;
- promise.$$v = undefined;
- promise.then(function(val) { promise.$$v = eso1(val); });
+ self.assign(intoId, self.nonComputedMember('s', ast.name));
+ });
+ }, intoId && self.lazyAssign(intoId, self.nonComputedMember('l', ast.name))
+ );
+ if (self.state.expensiveChecks || isPossiblyDangerousMemberName(ast.name)) {
+ self.addEnsureSafeObject(intoId);
+ }
+ recursionFn(intoId);
+ break;
+ case AST.MemberExpression:
+ left = nameId && (nameId.context = this.nextId()) || this.nextId();
+ intoId = intoId || this.nextId();
+ self.recurse(ast.object, left, undefined, function() {
+ self.if_(self.notNull(left), function() {
+ if (ast.computed) {
+ right = self.nextId();
+ self.recurse(ast.property, right);
+ self.addEnsureSafeMemberName(right);
+ if (create && create !== 1) {
+ self.if_(self.not(self.computedMember(left, right)), self.lazyAssign(self.computedMember(left, right), '{}'));
}
- pathVal = eso1(pathVal.$$v);
- }
-
- if (!key2) return pathVal;
- if (pathVal == null) return undefined;
- pathVal = eso2(pathVal[key2]);
- if (pathVal && pathVal.then) {
- promiseWarning(fullExp);
- if (!("$$v" in pathVal)) {
- promise = pathVal;
- promise.$$v = undefined;
- promise.then(function(val) { promise.$$v = eso2(val); });
+ expression = self.ensureSafeObject(self.computedMember(left, right));
+ self.assign(intoId, expression);
+ if (nameId) {
+ nameId.computed = true;
+ nameId.name = right;
}
- pathVal = eso2(pathVal.$$v);
- }
-
- if (!key3) return pathVal;
- if (pathVal == null) return undefined;
- pathVal = eso3(pathVal[key3]);
- if (pathVal && pathVal.then) {
- promiseWarning(fullExp);
- if (!("$$v" in pathVal)) {
- promise = pathVal;
- promise.$$v = undefined;
- promise.then(function(val) { promise.$$v = eso3(val); });
+ } else {
+ ensureSafeMemberName(ast.property.name);
+ if (create && create !== 1) {
+ self.if_(self.not(self.nonComputedMember(left, ast.property.name)), self.lazyAssign(self.nonComputedMember(left, ast.property.name), '{}'));
}
- pathVal = eso3(pathVal.$$v);
- }
-
- if (!key4) return pathVal;
- if (pathVal == null) return undefined;
- pathVal = eso4(pathVal[key4]);
- if (pathVal && pathVal.then) {
- promiseWarning(fullExp);
- if (!("$$v" in pathVal)) {
- promise = pathVal;
- promise.$$v = undefined;
- promise.then(function(val) { promise.$$v = eso4(val); });
+ expression = self.nonComputedMember(left, ast.property.name);
+ if (self.state.expensiveChecks || isPossiblyDangerousMemberName(ast.property.name)) {
+ expression = self.ensureSafeObject(expression);
+ }
+ self.assign(intoId, expression);
+ if (nameId) {
+ nameId.computed = false;
+ nameId.name = ast.property.name;
}
- pathVal = eso4(pathVal.$$v);
}
- return pathVal;
- };
-}
+ }, function() {
+ self.assign(intoId, 'undefined');
+ });
+ recursionFn(intoId);
+ }, !!create);
+ break;
+ case AST.CallExpression:
+ intoId = intoId || this.nextId();
+ if (ast.filter) {
+ right = self.filter(ast.callee.name);
+ args = [];
+ forEach(ast.arguments, function(expr) {
+ var argument = self.nextId();
+ self.recurse(expr, argument);
+ args.push(argument);
+ });
+ expression = right + '(' + args.join(',') + ')';
+ self.assign(intoId, expression);
+ recursionFn(intoId);
+ } else {
+ right = self.nextId();
+ left = {};
+ args = [];
+ self.recurse(ast.callee, right, left, function() {
+ self.if_(self.notNull(right), function() {
+ self.addEnsureSafeFunction(right);
+ forEach(ast.arguments, function(expr) {
+ self.recurse(expr, self.nextId(), undefined, function(argument) {
+ args.push(self.ensureSafeObject(argument));
+ });
+ });
+ if (left.name) {
+ if (!self.state.expensiveChecks) {
+ self.addEnsureSafeObject(left.context);
+ }
+ expression = self.member(left.context, left.name, left.computed) + '(' + args.join(',') + ')';
+ } else {
+ expression = right + '(' + args.join(',') + ')';
+ }
+ expression = self.ensureSafeObject(expression);
+ self.assign(intoId, expression);
+ }, function() {
+ self.assign(intoId, 'undefined');
+ });
+ recursionFn(intoId);
+ });
+ }
+ break;
+ case AST.AssignmentExpression:
+ right = this.nextId();
+ left = {};
+ if (!isAssignable(ast.left)) {
+ throw $parseMinErr('lval', 'Trying to assing a value to a non l-value');
+ }
+ this.recurse(ast.left, undefined, left, function() {
+ self.if_(self.notNull(left.context), function() {
+ self.recurse(ast.right, right);
+ self.addEnsureSafeObject(self.member(left.context, left.name, left.computed));
+ expression = self.member(left.context, left.name, left.computed) + ast.operator + right;
+ self.assign(intoId, expression);
+ recursionFn(intoId || expression);
+ });
+ }, 1);
+ break;
+ case AST.ArrayExpression:
+ args = [];
+ forEach(ast.elements, function(expr) {
+ self.recurse(expr, self.nextId(), undefined, function(argument) {
+ args.push(argument);
+ });
+ });
+ expression = '[' + args.join(',') + ']';
+ this.assign(intoId, expression);
+ recursionFn(expression);
+ break;
+ case AST.ObjectExpression:
+ args = [];
+ forEach(ast.properties, function(property) {
+ self.recurse(property.value, self.nextId(), undefined, function(expr) {
+ args.push(self.escape(
+ property.key.type === AST.Identifier ? property.key.name :
+ ('' + property.key.value)) +
+ ':' + expr);
+ });
+ });
+ expression = '{' + args.join(',') + '}';
+ this.assign(intoId, expression);
+ recursionFn(expression);
+ break;
+ case AST.ThisExpression:
+ this.assign(intoId, 's');
+ recursionFn('s');
+ break;
+ case AST.NGValueParameter:
+ this.assign(intoId, 'v');
+ recursionFn('v');
+ break;
+ }
+ },
-function getterFnWithExtraArgs(fn, fullExpression) {
- return function(s, l) {
- return fn(s, l, promiseWarning, ensureSafeObject, fullExpression);
- };
-}
+ getHasOwnProperty: function(element, property) {
+ var key = element + '.' + property;
+ var own = this.current().own;
+ if (!own.hasOwnProperty(key)) {
+ own[key] = this.nextId(false, element + '&&(' + this.escape(property) + ' in ' + element + ')');
+ }
+ return own[key];
+ },
-function getterFn(path, options, fullExp) {
- var expensiveChecks = options.expensiveChecks;
- var getterFnCache = (expensiveChecks ? getterFnCacheExpensive : getterFnCacheDefault);
- // Check whether the cache has this getter already.
- // We can use hasOwnProperty directly on the cache because we ensure,
- // see below, that the cache never stores a path called 'hasOwnProperty'
- if (getterFnCache.hasOwnProperty(path)) {
- return getterFnCache[path];
- }
+ assign: function(id, value) {
+ if (!id) return;
+ this.current().body.push(id, '=', value, ';');
+ return id;
+ },
+
+ filter: function(filterName) {
+ if (!this.state.filters.hasOwnProperty(filterName)) {
+ this.state.filters[filterName] = this.nextId(true);
+ }
+ return this.state.filters[filterName];
+ },
- var pathKeys = path.split('.'),
- pathKeysLength = pathKeys.length,
- fn;
+ ifDefined: function(id, defaultValue) {
+ return 'ifDefined(' + id + ',' + this.escape(defaultValue) + ')';
+ },
+
+ plus: function(left, right) {
+ return 'plus(' + left + ',' + right + ')';
+ },
- // http://jsperf.com/angularjs-parse-getter/6
- if (options.csp) {
- if (pathKeysLength < 6) {
- fn = cspSafeGetterFn(pathKeys[0], pathKeys[1], pathKeys[2], pathKeys[3], pathKeys[4], fullExp,
- options);
+ return_: function(id) {
+ this.current().body.push('return ', id, ';');
+ },
+
+ if_: function(test, alternate, consequent) {
+ if (test === true) {
+ alternate();
} else {
- fn = function(scope, locals) {
- var i = 0, val;
- do {
- val = cspSafeGetterFn(pathKeys[i++], pathKeys[i++], pathKeys[i++], pathKeys[i++],
- pathKeys[i++], fullExp, options)(scope, locals);
+ var body = this.current().body;
+ body.push('if(', test, '){');
+ alternate();
+ body.push('}');
+ if (consequent) {
+ body.push('else{');
+ consequent();
+ body.push('}');
+ }
+ }
+ },
- locals = undefined; // clear after first iteration
- scope = val;
- } while (i < pathKeysLength);
- return val;
- };
+ not: function(expression) {
+ return '!(' + expression + ')';
+ },
+
+ notNull: function(expression) {
+ return expression + '!=null';
+ },
+
+ nonComputedMember: function(left, right) {
+ return left + '.' + right;
+ },
+
+ computedMember: function(left, right) {
+ return left + '[' + right + ']';
+ },
+
+ member: function(left, right, computed) {
+ if (computed) return this.computedMember(left, right);
+ return this.nonComputedMember(left, right);
+ },
+
+ addEnsureSafeObject: function(item) {
+ this.current().body.push(this.ensureSafeObject(item), ';');
+ },
+
+ addEnsureSafeMemberName: function(item) {
+ this.current().body.push(this.ensureSafeMemberName(item), ';');
+ },
+
+ addEnsureSafeFunction: function(item) {
+ this.current().body.push(this.ensureSafeFunction(item), ';');
+ },
+
+ ensureSafeObject: function(item) {
+ return 'ensureSafeObject(' + item + ',text)';
+ },
+
+ ensureSafeMemberName: function(item) {
+ return 'ensureSafeMemberName(' + item + ',text)';
+ },
+
+ ensureSafeFunction: function(item) {
+ return 'ensureSafeFunction(' + item + ',text)';
+ },
+
+ lazyRecurse: function(ast, intoId, nameId, recursionFn, create, skipWatchIdCheck) {
+ var self = this;
+ return function() {
+ self.recurse(ast, intoId, nameId, recursionFn, create, skipWatchIdCheck);
+ };
+ },
+
+ lazyAssign: function(id, value) {
+ var self = this;
+ return function() {
+ self.assign(id, value);
+ };
+ },
+
+ stringEscapeRegex: /[^ a-zA-Z0-9]/g,
+
+ stringEscapeFn: function(c) {
+ return '\\u' + ('0000' + c.charCodeAt(0).toString(16)).slice(-4);
+ },
+
+ escape: function(value) {
+ if (isString(value)) return "'" + value.replace(this.stringEscapeRegex, this.stringEscapeFn) + "'";
+ if (isNumber(value)) return value.toString();
+ if (value === true) return 'true';
+ if (value === false) return 'false';
+ if (value === null) return 'null';
+ if (typeof value === 'undefined') return 'undefined';
+
+ throw $parseMinErr('esc', 'IMPOSSIBLE');
+ },
+
+ nextId: function(skip, init) {
+ var id = 'v' + (this.state.nextId++);
+ if (!skip) {
+ this.current().vars.push(id + (init ? '=' + init : ''));
}
- } else {
- var code = 'var p;\n';
- if (expensiveChecks) {
- code += 's = eso(s, fe);\nl = eso(l, fe);\n';
- }
- var needsEnsureSafeObject = expensiveChecks;
- forEach(pathKeys, function(key, index) {
- ensureSafeMemberName(key, fullExp);
- var lookupJs = (index
- // we simply dereference 's' on any .dot notation
- ? 's'
- // but if we are first then we check locals first, and if so read it first
- : '((l&&l.hasOwnProperty("' + key + '"))?l:s)') + '["' + key + '"]';
- var wrapWithEso = expensiveChecks || isPossiblyDangerousMemberName(key);
- if (wrapWithEso) {
- lookupJs = 'eso(' + lookupJs + ', fe)';
- needsEnsureSafeObject = true;
- }
- code += 'if(s == null) return undefined;\n' +
- 's=' + lookupJs + ';\n';
- if (options.unwrapPromises) {
- code += 'if (s && s.then) {\n' +
- ' pw("' + fullExp.replace(/(["\r\n])/g, '\\$1') + '");\n' +
- ' if (!("$$v" in s)) {\n' +
- ' p=s;\n' +
- ' p.$$v = undefined;\n' +
- ' p.then(function(v) {p.$$v=' + (wrapWithEso ? 'eso(v)' : 'v') + ';});\n' +
- '}\n' +
- ' s=' + (wrapWithEso ? 'eso(s.$$v)' : 's.$$v') + '\n' +
- '}\n';
+ return id;
+ },
- }
+ current: function() {
+ return this.state[this.state.computing];
+ }
+};
+
+
+function ASTInterpreter(astBuilder, $filter) {
+ this.astBuilder = astBuilder;
+ this.$filter = $filter;
+}
+
+ASTInterpreter.prototype = {
+ compile: function(expression, expensiveChecks) {
+ var self = this;
+ var ast = this.astBuilder.ast(expression);
+ this.expression = expression;
+ this.expensiveChecks = expensiveChecks;
+ findConstantAndWatchExpressions(ast, self.$filter);
+ var assignable;
+ var assign;
+ if ((assignable = assignableAST(ast))) {
+ assign = this.recurse(assignable);
+ }
+ var toWatch = getInputs(ast.body);
+ var inputs;
+ if (toWatch) {
+ inputs = [];
+ forEach(toWatch, function(watch, key) {
+ var input = self.recurse(watch);
+ watch.input = input;
+ inputs.push(input);
+ watch.watchId = key;
+ });
+ }
+ var expressions = [];
+ forEach(ast.body, function(expression) {
+ expressions.push(self.recurse(expression.expression));
});
- code += 'return s;';
+ var fn = ast.body.length === 0 ? function() {} :
+ ast.body.length === 1 ? expressions[0] :
+ function(scope, locals) {
+ var lastValue;
+ forEach(expressions, function(exp) {
+ lastValue = exp(scope, locals);
+ });
+ return lastValue;
+ };
+ if (assign) {
+ fn.assign = function(scope, value, locals) {
+ return assign(scope, locals, value);
+ };
+ }
+ if (inputs) {
+ fn.inputs = inputs;
+ }
+ fn.literal = isLiteral(ast);
+ fn.constant = isConstant(ast);
+ return fn;
+ },
- /* jshint -W054 */
- // s=scope, l=locals, pw=promiseWarning, eso=ensureSafeObject, fe=fullExpression
- var evaledFnGetter = new Function('s', 'l', 'pw', 'eso', 'fe', code);
- /* jshint +W054 */
- evaledFnGetter.toString = valueFn(code);
- if (needsEnsureSafeObject || options.unwrapPromises) {
- evaledFnGetter = getterFnWithExtraArgs(evaledFnGetter, fullExp);
+ recurse: function(ast, context, create) {
+ var left, right, self = this, args, expression;
+ if (ast.input) {
+ return this.inputs(ast.input, ast.watchId);
}
- fn = evaledFnGetter;
+ switch (ast.type) {
+ case AST.Literal:
+ return this.value(ast.value, context);
+ case AST.UnaryExpression:
+ right = this.recurse(ast.argument);
+ return this['unary' + ast.operator](right, context);
+ case AST.BinaryExpression:
+ left = this.recurse(ast.left);
+ right = this.recurse(ast.right);
+ return this['binary' + ast.operator](left, right, context);
+ case AST.LogicalExpression:
+ left = this.recurse(ast.left);
+ right = this.recurse(ast.right);
+ return this['binary' + ast.operator](left, right, context);
+ case AST.ConditionalExpression:
+ return this['ternary?:'](
+ this.recurse(ast.test),
+ this.recurse(ast.alternate),
+ this.recurse(ast.consequent),
+ context
+ );
+ case AST.Identifier:
+ ensureSafeMemberName(ast.name, self.expression);
+ return self.identifier(ast.name,
+ self.expensiveChecks || isPossiblyDangerousMemberName(ast.name),
+ context, create, self.expression);
+ case AST.MemberExpression:
+ left = this.recurse(ast.object, false, !!create);
+ if (!ast.computed) {
+ ensureSafeMemberName(ast.property.name, self.expression);
+ right = ast.property.name;
+ }
+ if (ast.computed) right = this.recurse(ast.property);
+ return ast.computed ?
+ this.computedMember(left, right, context, create, self.expression) :
+ this.nonComputedMember(left, right, self.expensiveChecks, context, create, self.expression);
+ case AST.CallExpression:
+ args = [];
+ forEach(ast.arguments, function(expr) {
+ args.push(self.recurse(expr));
+ });
+ if (ast.filter) right = this.$filter(ast.callee.name);
+ if (!ast.filter) right = this.recurse(ast.callee, true);
+ return ast.filter ?
+ function(scope, locals, assign, inputs) {
+ var values = [];
+ for (var i = 0; i < args.length; ++i) {
+ values.push(args[i](scope, locals, assign, inputs));
+ }
+ var value = right.apply(undefined, values, inputs);
+ return context ? {context: undefined, name: undefined, value: value} : value;
+ } :
+ function(scope, locals, assign, inputs) {
+ var rhs = right(scope, locals, assign, inputs);
+ var value;
+ if (rhs.value != null) {
+ ensureSafeObject(rhs.context, self.expression);
+ ensureSafeFunction(rhs.value, self.expression);
+ var values = [];
+ for (var i = 0; i < args.length; ++i) {
+ values.push(ensureSafeObject(args[i](scope, locals, assign, inputs), self.expression));
+ }
+ value = ensureSafeObject(rhs.value.apply(rhs.context, values), self.expression);
+ }
+ return context ? {value: value} : value;
+ };
+ case AST.AssignmentExpression:
+ left = this.recurse(ast.left, true, 1);
+ right = this.recurse(ast.right);
+ return function(scope, locals, assign, inputs) {
+ var lhs = left(scope, locals, assign, inputs);
+ var rhs = right(scope, locals, assign, inputs);
+ ensureSafeObject(lhs.value, self.expression);
+ lhs.context[lhs.name] = rhs;
+ return context ? {value: rhs} : rhs;
+ };
+ case AST.ArrayExpression:
+ args = [];
+ forEach(ast.elements, function(expr) {
+ args.push(self.recurse(expr));
+ });
+ return function(scope, locals, assign, inputs) {
+ var value = [];
+ for (var i = 0; i < args.length; ++i) {
+ value.push(args[i](scope, locals, assign, inputs));
+ }
+ return context ? {value: value} : value;
+ };
+ case AST.ObjectExpression:
+ args = [];
+ forEach(ast.properties, function(property) {
+ args.push({key: property.key.type === AST.Identifier ?
+ property.key.name :
+ ('' + property.key.value),
+ value: self.recurse(property.value)
+ });
+ });
+ return function(scope, locals, assign, inputs) {
+ var value = {};
+ for (var i = 0; i < args.length; ++i) {
+ value[args[i].key] = args[i].value(scope, locals, assign, inputs);
+ }
+ return context ? {value: value} : value;
+ };
+ case AST.ThisExpression:
+ return function(scope) {
+ return context ? {value: scope} : scope;
+ };
+ case AST.NGValueParameter:
+ return function(scope, locals, assign, inputs) {
+ return context ? {value: assign} : assign;
+ };
+ }
+ },
+
+ 'unary+': function(argument, context) {
+ return function(scope, locals, assign, inputs) {
+ var arg = argument(scope, locals, assign, inputs);
+ if (isDefined(arg)) {
+ arg = +arg;
+ } else {
+ arg = 0;
+ }
+ return context ? {value: arg} : arg;
+ };
+ },
+ 'unary-': function(argument, context) {
+ return function(scope, locals, assign, inputs) {
+ var arg = argument(scope, locals, assign, inputs);
+ if (isDefined(arg)) {
+ arg = -arg;
+ } else {
+ arg = 0;
+ }
+ return context ? {value: arg} : arg;
+ };
+ },
+ 'unary!': function(argument, context) {
+ return function(scope, locals, assign, inputs) {
+ var arg = !argument(scope, locals, assign, inputs);
+ return context ? {value: arg} : arg;
+ };
+ },
+ 'binary+': function(left, right, context) {
+ return function(scope, locals, assign, inputs) {
+ var lhs = left(scope, locals, assign, inputs);
+ var rhs = right(scope, locals, assign, inputs);
+ var arg = plusFn(lhs, rhs);
+ return context ? {value: arg} : arg;
+ };
+ },
+ 'binary-': function(left, right, context) {
+ return function(scope, locals, assign, inputs) {
+ var lhs = left(scope, locals, assign, inputs);
+ var rhs = right(scope, locals, assign, inputs);
+ var arg = (isDefined(lhs) ? lhs : 0) - (isDefined(rhs) ? rhs : 0);
+ return context ? {value: arg} : arg;
+ };
+ },
+ 'binary*': function(left, right, context) {
+ return function(scope, locals, assign, inputs) {
+ var arg = left(scope, locals, assign, inputs) * right(scope, locals, assign, inputs);
+ return context ? {value: arg} : arg;
+ };
+ },
+ 'binary/': function(left, right, context) {
+ return function(scope, locals, assign, inputs) {
+ var arg = left(scope, locals, assign, inputs) / right(scope, locals, assign, inputs);
+ return context ? {value: arg} : arg;
+ };
+ },
+ 'binary%': function(left, right, context) {
+ return function(scope, locals, assign, inputs) {
+ var arg = left(scope, locals, assign, inputs) % right(scope, locals, assign, inputs);
+ return context ? {value: arg} : arg;
+ };
+ },
+ 'binary===': function(left, right, context) {
+ return function(scope, locals, assign, inputs) {
+ var arg = left(scope, locals, assign, inputs) === right(scope, locals, assign, inputs);
+ return context ? {value: arg} : arg;
+ };
+ },
+ 'binary!==': function(left, right, context) {
+ return function(scope, locals, assign, inputs) {
+ var arg = left(scope, locals, assign, inputs) !== right(scope, locals, assign, inputs);
+ return context ? {value: arg} : arg;
+ };
+ },
+ 'binary==': function(left, right, context) {
+ return function(scope, locals, assign, inputs) {
+ var arg = left(scope, locals, assign, inputs) == right(scope, locals, assign, inputs);
+ return context ? {value: arg} : arg;
+ };
+ },
+ 'binary!=': function(left, right, context) {
+ return function(scope, locals, assign, inputs) {
+ var arg = left(scope, locals, assign, inputs) != right(scope, locals, assign, inputs);
+ return context ? {value: arg} : arg;
+ };
+ },
+ 'binary<': function(left, right, context) {
+ return function(scope, locals, assign, inputs) {
+ var arg = left(scope, locals, assign, inputs) < right(scope, locals, assign, inputs);
+ return context ? {value: arg} : arg;
+ };
+ },
+ 'binary>': function(left, right, context) {
+ return function(scope, locals, assign, inputs) {
+ var arg = left(scope, locals, assign, inputs) > right(scope, locals, assign, inputs);
+ return context ? {value: arg} : arg;
+ };
+ },
+ 'binary<=': function(left, right, context) {
+ return function(scope, locals, assign, inputs) {
+ var arg = left(scope, locals, assign, inputs) <= right(scope, locals, assign, inputs);
+ return context ? {value: arg} : arg;
+ };
+ },
+ 'binary>=': function(left, right, context) {
+ return function(scope, locals, assign, inputs) {
+ var arg = left(scope, locals, assign, inputs) >= right(scope, locals, assign, inputs);
+ return context ? {value: arg} : arg;
+ };
+ },
+ 'binary&&': function(left, right, context) {
+ return function(scope, locals, assign, inputs) {
+ var arg = left(scope, locals, assign, inputs) && right(scope, locals, assign, inputs);
+ return context ? {value: arg} : arg;
+ };
+ },
+ 'binary||': function(left, right, context) {
+ return function(scope, locals, assign, inputs) {
+ var arg = left(scope, locals, assign, inputs) || right(scope, locals, assign, inputs);
+ return context ? {value: arg} : arg;
+ };
+ },
+ 'ternary?:': function(test, alternate, consequent, context) {
+ return function(scope, locals, assign, inputs) {
+ var arg = test(scope, locals, assign, inputs) ? alternate(scope, locals, assign, inputs) : consequent(scope, locals, assign, inputs);
+ return context ? {value: arg} : arg;
+ };
+ },
+ value: function(value, context) {
+ return function() { return context ? {context: undefined, name: undefined, value: value} : value; };
+ },
+ identifier: function(name, expensiveChecks, context, create, expression) {
+ return function(scope, locals, assign, inputs) {
+ var base = locals && (name in locals) ? locals : scope;
+ if (create && create !== 1 && base && !(base[name])) {
+ base[name] = {};
+ }
+ var value = base ? base[name] : undefined;
+ if (expensiveChecks) {
+ ensureSafeObject(value, expression);
+ }
+ if (context) {
+ return {context: base, name: name, value: value};
+ } else {
+ return value;
+ }
+ };
+ },
+ computedMember: function(left, right, context, create, expression) {
+ return function(scope, locals, assign, inputs) {
+ var lhs = left(scope, locals, assign, inputs);
+ var rhs;
+ var value;
+ if (lhs != null) {
+ rhs = right(scope, locals, assign, inputs);
+ ensureSafeMemberName(rhs, expression);
+ if (create && create !== 1 && lhs && !(lhs[rhs])) {
+ lhs[rhs] = {};
+ }
+ value = lhs[rhs];
+ ensureSafeObject(value, expression);
+ }
+ if (context) {
+ return {context: lhs, name: rhs, value: value};
+ } else {
+ return value;
+ }
+ };
+ },
+ nonComputedMember: function(left, right, expensiveChecks, context, create, expression) {
+ return function(scope, locals, assign, inputs) {
+ var lhs = left(scope, locals, assign, inputs);
+ if (create && create !== 1 && lhs && !(lhs[right])) {
+ lhs[right] = {};
+ }
+ var value = lhs != null ? lhs[right] : undefined;
+ if (expensiveChecks || isPossiblyDangerousMemberName(right)) {
+ ensureSafeObject(value, expression);
+ }
+ if (context) {
+ return {context: lhs, name: right, value: value};
+ } else {
+ return value;
+ }
+ };
+ },
+ inputs: function(input, watchId) {
+ return function(scope, value, locals, inputs) {
+ if (inputs) return inputs[watchId];
+ return input(scope, value, locals);
+ };
}
+};
+
+/**
+ * @constructor
+ */
+var Parser = function(lexer, $filter, options) {
+ this.lexer = lexer;
+ this.$filter = $filter;
+ this.options = options;
+ this.ast = new AST(this.lexer);
+ this.astCompiler = options.csp ? new ASTInterpreter(this.ast, $filter) :
+ new ASTCompiler(this.ast, $filter);
+};
+
+Parser.prototype = {
+ constructor: Parser,
+
+ parse: function(text) {
+ return this.astCompiler.compile(text, this.options.expensiveChecks);
+ }
+};
+
+//////////////////////////////////////////////////
+// Parser helper functions
+//////////////////////////////////////////////////
+
+function setter(obj, path, setValue, fullExp) {
+ ensureSafeObject(obj, fullExp);
- // Only cache the value if it's not going to mess up the cache object
- // This is more performant that using Object.prototype.hasOwnProperty.call
- if (path !== 'hasOwnProperty') {
- getterFnCache[path] = fn;
+ var element = path.split('.'), key;
+ for (var i = 0; element.length > 1; i++) {
+ key = ensureSafeMemberName(element.shift(), fullExp);
+ var propertyObj = ensureSafeObject(obj[key], fullExp);
+ if (!propertyObj) {
+ propertyObj = {};
+ obj[key] = propertyObj;
+ }
+ obj = propertyObj;
}
- return fn;
+ key = ensureSafeMemberName(element.shift(), fullExp);
+ ensureSafeObject(obj[key], fullExp);
+ obj[key] = setValue;
+ return setValue;
+}
+
+var getterFnCacheDefault = createMap();
+var getterFnCacheExpensive = createMap();
+
+function isPossiblyDangerousMemberName(name) {
+ return name == 'constructor';
+}
+
+var objectValueOf = Object.prototype.valueOf;
+
+function getValueOf(value) {
+ return isFunction(value.valueOf) ? value.valueOf() : objectValueOf.call(value);
}
///////////////////////////////////
@@ -11275,152 +14032,221 @@ function getterFn(path, options, fullExp) {
/**
* @ngdoc provider
* @name $parseProvider
- * @kind function
*
* @description
* `$parseProvider` can be used for configuring the default behavior of the {@link ng.$parse $parse}
* service.
*/
function $ParseProvider() {
- var cacheDefault = {};
- var cacheExpensive = {};
-
- var $parseOptions = {
- csp: false,
- unwrapPromises: false,
- logPromiseWarnings: true,
- expensiveChecks: false
- };
+ var cacheDefault = createMap();
+ var cacheExpensive = createMap();
+ this.$get = ['$filter', '$sniffer', function($filter, $sniffer) {
+ var $parseOptions = {
+ csp: $sniffer.csp,
+ expensiveChecks: false
+ },
+ $parseOptionsExpensive = {
+ csp: $sniffer.csp,
+ expensiveChecks: true
+ };
- /**
- * @deprecated Promise unwrapping via $parse is deprecated and will be removed in the future.
- *
- * @ngdoc method
- * @name $parseProvider#unwrapPromises
- * @description
- *
- * **This feature is deprecated, see deprecation notes below for more info**
- *
- * If set to true (default is false), $parse will unwrap promises automatically when a promise is
- * found at any part of the expression. In other words, if set to true, the expression will always
- * result in a non-promise value.
- *
- * While the promise is unresolved, it's treated as undefined, but once resolved and fulfilled,
- * the fulfillment value is used in place of the promise while evaluating the expression.
- *
- * **Deprecation notice**
- *
- * This is a feature that didn't prove to be wildly useful or popular, primarily because of the
- * dichotomy between data access in templates (accessed as raw values) and controller code
- * (accessed as promises).
- *
- * In most code we ended up resolving promises manually in controllers anyway and thus unifying
- * the model access there.
- *
- * Other downsides of automatic promise unwrapping:
- *
- * - when building components it's often desirable to receive the raw promises
- * - adds complexity and slows down expression evaluation
- * - makes expression code pre-generation unattractive due to the amount of code that needs to be
- * generated
- * - makes IDE auto-completion and tool support hard
- *
- * **Warning Logs**
- *
- * If the unwrapping is enabled, Angular will log a warning about each expression that unwraps a
- * promise (to reduce the noise, each expression is logged only once). To disable this logging use
- * `$parseProvider.logPromiseWarnings(false)` api.
- *
- *
- * @param {boolean=} value New value.
- * @returns {boolean|self} Returns the current setting when used as getter and self if used as
- * setter.
- */
- this.unwrapPromises = function(value) {
- if (isDefined(value)) {
- $parseOptions.unwrapPromises = !!value;
- return this;
- } else {
- return $parseOptions.unwrapPromises;
- }
- };
+ return function $parse(exp, interceptorFn, expensiveChecks) {
+ var parsedExpression, oneTime, cacheKey;
+ switch (typeof exp) {
+ case 'string':
+ exp = exp.trim();
+ cacheKey = exp;
- /**
- * @deprecated Promise unwrapping via $parse is deprecated and will be removed in the future.
- *
- * @ngdoc method
- * @name $parseProvider#logPromiseWarnings
- * @description
- *
- * Controls whether Angular should log a warning on any encounter of a promise in an expression.
- *
- * The default is set to `true`.
- *
- * This setting applies only if `$parseProvider.unwrapPromises` setting is set to true as well.
- *
- * @param {boolean=} value New value.
- * @returns {boolean|self} Returns the current setting when used as getter and self if used as
- * setter.
- */
- this.logPromiseWarnings = function(value) {
- if (isDefined(value)) {
- $parseOptions.logPromiseWarnings = value;
- return this;
- } else {
- return $parseOptions.logPromiseWarnings;
- }
- };
+ var cache = (expensiveChecks ? cacheExpensive : cacheDefault);
+ parsedExpression = cache[cacheKey];
+ if (!parsedExpression) {
+ if (exp.charAt(0) === ':' && exp.charAt(1) === ':') {
+ oneTime = true;
+ exp = exp.substring(2);
+ }
+ var parseOptions = expensiveChecks ? $parseOptionsExpensive : $parseOptions;
+ var lexer = new Lexer(parseOptions);
+ var parser = new Parser(lexer, $filter, parseOptions);
+ parsedExpression = parser.parse(exp);
+ if (parsedExpression.constant) {
+ parsedExpression.$$watchDelegate = constantWatchDelegate;
+ } else if (oneTime) {
+ parsedExpression.$$watchDelegate = parsedExpression.literal ?
+ oneTimeLiteralWatchDelegate : oneTimeWatchDelegate;
+ } else if (parsedExpression.inputs) {
+ parsedExpression.$$watchDelegate = inputsWatchDelegate;
+ }
+ cache[cacheKey] = parsedExpression;
+ }
+ return addInterceptor(parsedExpression, interceptorFn);
- this.$get = ['$filter', '$sniffer', '$log', function($filter, $sniffer, $log) {
- $parseOptions.csp = $sniffer.csp;
- var $parseOptionsExpensive = {
- csp: $parseOptions.csp,
- unwrapPromises: $parseOptions.unwrapPromises,
- logPromiseWarnings: $parseOptions.logPromiseWarnings,
- expensiveChecks: true
- };
+ case 'function':
+ return addInterceptor(exp, interceptorFn);
- promiseWarning = function promiseWarningFn(fullExp) {
- if (!$parseOptions.logPromiseWarnings || promiseWarningCache.hasOwnProperty(fullExp)) return;
- promiseWarningCache[fullExp] = true;
- $log.warn('[$parse] Promise found in the expression `' + fullExp + '`. ' +
- 'Automatic unwrapping of promises in Angular expressions is deprecated.');
+ default:
+ return noop;
+ }
};
- return function(exp, expensiveChecks) {
- var parsedExpression;
+ function expressionInputDirtyCheck(newValue, oldValueOfValue) {
- switch (typeof exp) {
- case 'string':
+ if (newValue == null || oldValueOfValue == null) { // null/undefined
+ return newValue === oldValueOfValue;
+ }
- var cache = (expensiveChecks ? cacheExpensive : cacheDefault);
- if (cache.hasOwnProperty(exp)) {
- return cache[exp];
+ if (typeof newValue === 'object') {
+
+ // attempt to convert the value to a primitive type
+ // TODO(docs): add a note to docs that by implementing valueOf even objects and arrays can
+ // be cheaply dirty-checked
+ newValue = getValueOf(newValue);
+
+ if (typeof newValue === 'object') {
+ // objects/arrays are not supported - deep-watching them would be too expensive
+ return false;
+ }
+
+ // fall-through to the primitive equality check
+ }
+
+ //Primitive or NaN
+ return newValue === oldValueOfValue || (newValue !== newValue && oldValueOfValue !== oldValueOfValue);
+ }
+
+ function inputsWatchDelegate(scope, listener, objectEquality, parsedExpression, prettyPrintExpression) {
+ var inputExpressions = parsedExpression.inputs;
+ var lastResult;
+
+ if (inputExpressions.length === 1) {
+ var oldInputValueOf = expressionInputDirtyCheck; // init to something unique so that equals check fails
+ inputExpressions = inputExpressions[0];
+ return scope.$watch(function expressionInputWatch(scope) {
+ var newInputValue = inputExpressions(scope);
+ if (!expressionInputDirtyCheck(newInputValue, oldInputValueOf)) {
+ lastResult = parsedExpression(scope, undefined, undefined, [newInputValue]);
+ oldInputValueOf = newInputValue && getValueOf(newInputValue);
}
+ return lastResult;
+ }, listener, objectEquality, prettyPrintExpression);
+ }
+
+ var oldInputValueOfValues = [];
+ var oldInputValues = [];
+ for (var i = 0, ii = inputExpressions.length; i < ii; i++) {
+ oldInputValueOfValues[i] = expressionInputDirtyCheck; // init to something unique so that equals check fails
+ oldInputValues[i] = null;
+ }
- var parseOptions = expensiveChecks ? $parseOptionsExpensive : $parseOptions;
- var lexer = new Lexer(parseOptions);
- var parser = new Parser(lexer, $filter, parseOptions);
- parsedExpression = parser.parse(exp);
+ return scope.$watch(function expressionInputsWatch(scope) {
+ var changed = false;
- if (exp !== 'hasOwnProperty') {
- // Only cache the value if it's not going to mess up the cache object
- // This is more performant that using Object.prototype.hasOwnProperty.call
- cache[exp] = parsedExpression;
+ for (var i = 0, ii = inputExpressions.length; i < ii; i++) {
+ var newInputValue = inputExpressions[i](scope);
+ if (changed || (changed = !expressionInputDirtyCheck(newInputValue, oldInputValueOfValues[i]))) {
+ oldInputValues[i] = newInputValue;
+ oldInputValueOfValues[i] = newInputValue && getValueOf(newInputValue);
}
+ }
- return parsedExpression;
+ if (changed) {
+ lastResult = parsedExpression(scope, undefined, undefined, oldInputValues);
+ }
- case 'function':
- return exp;
+ return lastResult;
+ }, listener, objectEquality, prettyPrintExpression);
+ }
- default:
- return noop;
+ function oneTimeWatchDelegate(scope, listener, objectEquality, parsedExpression) {
+ var unwatch, lastValue;
+ return unwatch = scope.$watch(function oneTimeWatch(scope) {
+ return parsedExpression(scope);
+ }, function oneTimeListener(value, old, scope) {
+ lastValue = value;
+ if (isFunction(listener)) {
+ listener.apply(this, arguments);
+ }
+ if (isDefined(value)) {
+ scope.$$postDigest(function() {
+ if (isDefined(lastValue)) {
+ unwatch();
+ }
+ });
+ }
+ }, objectEquality);
+ }
+
+ function oneTimeLiteralWatchDelegate(scope, listener, objectEquality, parsedExpression) {
+ var unwatch, lastValue;
+ return unwatch = scope.$watch(function oneTimeWatch(scope) {
+ return parsedExpression(scope);
+ }, function oneTimeListener(value, old, scope) {
+ lastValue = value;
+ if (isFunction(listener)) {
+ listener.call(this, value, old, scope);
+ }
+ if (isAllDefined(value)) {
+ scope.$$postDigest(function() {
+ if (isAllDefined(lastValue)) unwatch();
+ });
+ }
+ }, objectEquality);
+
+ function isAllDefined(value) {
+ var allDefined = true;
+ forEach(value, function(val) {
+ if (!isDefined(val)) allDefined = false;
+ });
+ return allDefined;
}
- };
+ }
+
+ function constantWatchDelegate(scope, listener, objectEquality, parsedExpression) {
+ var unwatch;
+ return unwatch = scope.$watch(function constantWatch(scope) {
+ return parsedExpression(scope);
+ }, function constantListener(value, old, scope) {
+ if (isFunction(listener)) {
+ listener.apply(this, arguments);
+ }
+ unwatch();
+ }, objectEquality);
+ }
+
+ function addInterceptor(parsedExpression, interceptorFn) {
+ if (!interceptorFn) return parsedExpression;
+ var watchDelegate = parsedExpression.$$watchDelegate;
+
+ var regularWatch =
+ watchDelegate !== oneTimeLiteralWatchDelegate &&
+ watchDelegate !== oneTimeWatchDelegate;
+
+ var fn = regularWatch ? function regularInterceptedExpression(scope, locals, assign, inputs) {
+ var value = parsedExpression(scope, locals, assign, inputs);
+ return interceptorFn(value, scope, locals);
+ } : function oneTimeInterceptedExpression(scope, locals, assign, inputs) {
+ var value = parsedExpression(scope, locals, assign, inputs);
+ var result = interceptorFn(value, scope, locals);
+ // we only return the interceptor's result if the
+ // initial value is defined (for bind-once)
+ return isDefined(value) ? result : value;
+ };
+
+ // Propagate $$watchDelegates other then inputsWatchDelegate
+ if (parsedExpression.$$watchDelegate &&
+ parsedExpression.$$watchDelegate !== inputsWatchDelegate) {
+ fn.$$watchDelegate = parsedExpression.$$watchDelegate;
+ } else if (!interceptorFn.$stateful) {
+ // If there is an interceptor, but no watchDelegate then treat the interceptor like
+ // we treat filters - it is assumed to be a pure function unless flagged with $stateful
+ fn.$$watchDelegate = inputsWatchDelegate;
+ fn.inputs = parsedExpression.inputs ? parsedExpression.inputs : [parsedExpression];
+ }
+
+ return fn;
+ }
}];
}
@@ -11436,6 +14262,49 @@ function $ParseProvider() {
* This is an implementation of promises/deferred objects inspired by
* [Kris Kowal's Q](https://github.com/kriskowal/q).
*
+ * $q can be used in two fashions --- one which is more similar to Kris Kowal's Q or jQuery's Deferred
+ * implementations, and the other which resembles ES6 promises to some degree.
+ *
+ * # $q constructor
+ *
+ * The streamlined ES6 style promise is essentially just using $q as a constructor which takes a `resolver`
+ * function as the first argument. This is similar to the native Promise implementation from ES6 Harmony,
+ * see [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise).
+ *
+ * While the constructor-style use is supported, not all of the supporting methods from ES6 Harmony promises are
+ * available yet.
+ *
+ * It can be used like so:
+ *
+ * ```js
+ * // for the purpose of this example let's assume that variables `$q` and `okToGreet`
+ * // are available in the current lexical scope (they could have been injected or passed in).
+ *
+ * function asyncGreet(name) {
+ * // perform some asynchronous operation, resolve or reject the promise when appropriate.
+ * return $q(function(resolve, reject) {
+ * setTimeout(function() {
+ * if (okToGreet(name)) {
+ * resolve('Hello, ' + name + '!');
+ * } else {
+ * reject('Greeting ' + name + ' is not allowed.');
+ * }
+ * }, 1000);
+ * });
+ * }
+ *
+ * var promise = asyncGreet('Robin Hood');
+ * promise.then(function(greeting) {
+ * alert('Success: ' + greeting);
+ * }, function(reason) {
+ * alert('Failed: ' + reason);
+ * });
+ * ```
+ *
+ * Note: progress/notify callbacks are not currently supported via the ES6-style interface.
+ *
+ * However, the more traditional CommonJS-style usage is still available, and documented below.
+ *
* [The CommonJS Promise proposal](http://wiki.commonjs.org/wiki/Promises) describes a promise as an
* interface for interacting with an object that represents the result of an action that is
* performed asynchronously, and may or may not be finished at any given point in time.
@@ -11444,7 +14313,7 @@ function $ParseProvider() {
* asynchronous programming what `try`, `catch` and `throw` keywords are to synchronous programming.
*
* ```js
- * // for the purpose of this example let's assume that variables `$q`, `scope` and `okToGreet`
+ * // for the purpose of this example let's assume that variables `$q` and `okToGreet`
* // are available in the current lexical scope (they could have been injected or passed in).
*
* function asyncGreet(name) {
@@ -11482,7 +14351,6 @@ function $ParseProvider() {
* For more on this please see the [Q documentation](https://github.com/kriskowal/q) especially the
* section on serial or parallel joining of promises.
*
- *
* # The Deferred API
*
* A new instance of deferred is constructed by calling `$q.defer()`.
@@ -11522,26 +14390,20 @@ function $ParseProvider() {
* provide a progress indication, before the promise is resolved or rejected.
*
* This method *returns a new promise* which is resolved or rejected via the return value of the
- * `successCallback`, `errorCallback`. It also notifies via the return value of the
- * `notifyCallback` method. The promise can not be resolved or rejected from the notifyCallback
- * method.
+ * `successCallback`, `errorCallback` (unless that value is a promise, in which case it is resolved
+ * with the value which is resolved in that promise using
+ * [promise chaining](http://www.html5rocks.com/en/tutorials/es6/promises/#toc-promises-queues)).
+ * It also notifies via the return value of the `notifyCallback` method. The promise cannot be
+ * resolved or rejected from the notifyCallback method.
*
* - `catch(errorCallback)` – shorthand for `promise.then(null, errorCallback)`
*
- * Because `catch` is a reserved word in JavaScript and reserved keywords are not supported as
- * property names by ES3, you'll need to invoke the method like `promise['catch'](callback)` or
- * `promise.then(null, errorCallback)` to make your code IE8 and Android 2.x compatible.
- *
- * - `finally(callback)` – allows you to observe either the fulfillment or rejection of a promise,
+ * - `finally(callback, notifyCallback)` – allows you to observe either the fulfillment or rejection of a promise,
* but to do so without modifying the final value. This is useful to release resources or do some
* clean-up that needs to be done whether the promise was rejected or resolved. See the [full
* specification](https://github.com/kriskowal/q/wiki/API-Reference#promisefinallycallback) for
* more information.
*
- * Because `finally` is a reserved word in JavaScript and reserved keywords are not supported as
- * property names by ES3, you'll need to invoke the method like `promise['finally'](callback)` to
- * make your code IE8 and Android 2.x compatible.
- *
* # Chaining promises
*
* Because calling the `then` method of a promise returns a new derived promise, it is easily
@@ -11595,6 +14457,12 @@ function $ParseProvider() {
* expect(resolvedValue).toEqual(123);
* }));
* ```
+ *
+ * @param {function(function, function)} resolver Function which is responsible for resolving or
+ * rejecting the newly created promise. The first parameter is a function which resolves the
+ * promise, the second parameter is a function which rejects the promise.
+ *
+ * @returns {Promise} The newly created promise.
*/
function $QProvider() {
@@ -11605,20 +14473,40 @@ function $QProvider() {
}];
}
+function $$QProvider() {
+ this.$get = ['$browser', '$exceptionHandler', function($browser, $exceptionHandler) {
+ return qFactory(function(callback) {
+ $browser.defer(callback);
+ }, $exceptionHandler);
+ }];
+}
/**
* Constructs a promise manager.
*
- * @param {function(Function)} nextTick Function for executing functions in the next turn.
+ * @param {function(function)} nextTick Function for executing functions in the next turn.
* @param {function(...*)} exceptionHandler Function into which unexpected exceptions are passed for
* debugging purposes.
* @returns {object} Promise manager.
*/
function qFactory(nextTick, exceptionHandler) {
+ var $qMinErr = minErr('$q', TypeError);
+ function callOnce(self, resolveFn, rejectFn) {
+ var called = false;
+ function wrap(fn) {
+ return function(value) {
+ if (called) return;
+ called = true;
+ fn.call(self, value);
+ };
+ }
+
+ return [wrap(resolveFn), wrap(rejectFn)];
+ }
/**
* @ngdoc method
- * @name $q#defer
+ * @name ng.$q#defer
* @kind function
*
* @description
@@ -11627,152 +14515,147 @@ function qFactory(nextTick, exceptionHandler) {
* @returns {Deferred} Returns a new instance of deferred.
*/
var defer = function() {
- var pending = [],
- value, deferred;
-
- deferred = {
-
- resolve: function(val) {
- if (pending) {
- var callbacks = pending;
- pending = undefined;
- value = ref(val);
-
- if (callbacks.length) {
- nextTick(function() {
- var callback;
- for (var i = 0, ii = callbacks.length; i < ii; i++) {
- callback = callbacks[i];
- value.then(callback[0], callback[1], callback[2]);
- }
- });
- }
- }
- },
-
-
- reject: function(reason) {
- deferred.resolve(createInternalRejectedPromise(reason));
- },
+ return new Deferred();
+ };
+ function Promise() {
+ this.$$state = { status: 0 };
+ }
- notify: function(progress) {
- if (pending) {
- var callbacks = pending;
+ Promise.prototype = {
+ then: function(onFulfilled, onRejected, progressBack) {
+ var result = new Deferred();
- if (pending.length) {
- nextTick(function() {
- var callback;
- for (var i = 0, ii = callbacks.length; i < ii; i++) {
- callback = callbacks[i];
- callback[2](progress);
- }
- });
- }
- }
- },
+ this.$$state.pending = this.$$state.pending || [];
+ this.$$state.pending.push([result, onFulfilled, onRejected, progressBack]);
+ if (this.$$state.status > 0) scheduleProcessQueue(this.$$state);
+ return result.promise;
+ },
- promise: {
- then: function(callback, errback, progressback) {
- var result = defer();
+ "catch": function(callback) {
+ return this.then(null, callback);
+ },
- var wrappedCallback = function(value) {
- try {
- result.resolve((isFunction(callback) ? callback : defaultCallback)(value));
- } catch(e) {
- result.reject(e);
- exceptionHandler(e);
- }
- };
+ "finally": function(callback, progressBack) {
+ return this.then(function(value) {
+ return handleCallback(value, true, callback);
+ }, function(error) {
+ return handleCallback(error, false, callback);
+ }, progressBack);
+ }
+ };
- var wrappedErrback = function(reason) {
- try {
- result.resolve((isFunction(errback) ? errback : defaultErrback)(reason));
- } catch(e) {
- result.reject(e);
- exceptionHandler(e);
- }
- };
+ //Faster, more basic than angular.bind http://jsperf.com/angular-bind-vs-custom-vs-native
+ function simpleBind(context, fn) {
+ return function(value) {
+ fn.call(context, value);
+ };
+ }
- var wrappedProgressback = function(progress) {
- try {
- result.notify((isFunction(progressback) ? progressback : defaultCallback)(progress));
- } catch(e) {
- exceptionHandler(e);
- }
- };
+ function processQueue(state) {
+ var fn, deferred, pending;
- if (pending) {
- pending.push([wrappedCallback, wrappedErrback, wrappedProgressback]);
- } else {
- value.then(wrappedCallback, wrappedErrback, wrappedProgressback);
- }
+ pending = state.pending;
+ state.processScheduled = false;
+ state.pending = undefined;
+ for (var i = 0, ii = pending.length; i < ii; ++i) {
+ deferred = pending[i][0];
+ fn = pending[i][state.status];
+ try {
+ if (isFunction(fn)) {
+ deferred.resolve(fn(state.value));
+ } else if (state.status === 1) {
+ deferred.resolve(state.value);
+ } else {
+ deferred.reject(state.value);
+ }
+ } catch (e) {
+ deferred.reject(e);
+ exceptionHandler(e);
+ }
+ }
+ }
- return result.promise;
- },
+ function scheduleProcessQueue(state) {
+ if (state.processScheduled || !state.pending) return;
+ state.processScheduled = true;
+ nextTick(function() { processQueue(state); });
+ }
- "catch": function(callback) {
- return this.then(null, callback);
- },
+ function Deferred() {
+ this.promise = new Promise();
+ //Necessary to support unbound execution :/
+ this.resolve = simpleBind(this, this.resolve);
+ this.reject = simpleBind(this, this.reject);
+ this.notify = simpleBind(this, this.notify);
+ }
- "finally": function(callback) {
+ Deferred.prototype = {
+ resolve: function(val) {
+ if (this.promise.$$state.status) return;
+ if (val === this.promise) {
+ this.$$reject($qMinErr(
+ 'qcycle',
+ "Expected promise to be resolved with value other than itself '{0}'",
+ val));
+ } else {
+ this.$$resolve(val);
+ }
- function makePromise(value, resolved) {
- var result = defer();
- if (resolved) {
- result.resolve(value);
- } else {
- result.reject(value);
- }
- return result.promise;
- }
+ },
- function handleCallback(value, isResolved) {
- var callbackOutput = null;
- try {
- callbackOutput = (callback ||defaultCallback)();
- } catch(e) {
- return makePromise(e, false);
- }
- if (isPromiseLike(callbackOutput)) {
- return callbackOutput.then(function() {
- return makePromise(value, isResolved);
- }, function(error) {
- return makePromise(error, false);
- });
- } else {
- return makePromise(value, isResolved);
- }
- }
+ $$resolve: function(val) {
+ var then, fns;
- return this.then(function(value) {
- return handleCallback(value, true);
- }, function(error) {
- return handleCallback(error, false);
- });
+ fns = callOnce(this, this.$$resolve, this.$$reject);
+ try {
+ if ((isObject(val) || isFunction(val))) then = val && val.then;
+ if (isFunction(then)) {
+ this.promise.$$state.status = -1;
+ then.call(val, fns[0], fns[1], this.notify);
+ } else {
+ this.promise.$$state.value = val;
+ this.promise.$$state.status = 1;
+ scheduleProcessQueue(this.promise.$$state);
}
+ } catch (e) {
+ fns[1](e);
+ exceptionHandler(e);
}
- };
+ },
- return deferred;
- };
+ reject: function(reason) {
+ if (this.promise.$$state.status) return;
+ this.$$reject(reason);
+ },
+ $$reject: function(reason) {
+ this.promise.$$state.value = reason;
+ this.promise.$$state.status = 2;
+ scheduleProcessQueue(this.promise.$$state);
+ },
- var ref = function(value) {
- if (isPromiseLike(value)) return value;
- return {
- then: function(callback) {
- var result = defer();
+ notify: function(progress) {
+ var callbacks = this.promise.$$state.pending;
+
+ if ((this.promise.$$state.status <= 0) && callbacks && callbacks.length) {
nextTick(function() {
- result.resolve(callback(value));
+ var callback, result;
+ for (var i = 0, ii = callbacks.length; i < ii; i++) {
+ result = callbacks[i][0];
+ callback = callbacks[i][3];
+ try {
+ result.notify(isFunction(callback) ? callback(progress) : progress);
+ } catch (e) {
+ exceptionHandler(e);
+ }
+ }
});
- return result.promise;
}
- };
+ }
};
-
/**
* @ngdoc method
* @name $q#reject
@@ -11810,28 +14693,38 @@ function qFactory(nextTick, exceptionHandler) {
* @returns {Promise} Returns a promise that was already resolved as rejected with the `reason`.
*/
var reject = function(reason) {
- var result = defer();
+ var result = new Deferred();
result.reject(reason);
return result.promise;
};
- var createInternalRejectedPromise = function(reason) {
- return {
- then: function(callback, errback) {
- var result = defer();
- nextTick(function() {
- try {
- result.resolve((isFunction(errback) ? errback : defaultErrback)(reason));
- } catch(e) {
- result.reject(e);
- exceptionHandler(e);
- }
- });
- return result.promise;
- }
- };
+ var makePromise = function makePromise(value, resolved) {
+ var result = new Deferred();
+ if (resolved) {
+ result.resolve(value);
+ } else {
+ result.reject(value);
+ }
+ return result.promise;
};
+ var handleCallback = function handleCallback(value, isResolved, callback) {
+ var callbackOutput = null;
+ try {
+ if (isFunction(callback)) callbackOutput = callback();
+ } catch (e) {
+ return makePromise(e, false);
+ }
+ if (isPromiseLike(callbackOutput)) {
+ return callbackOutput.then(function() {
+ return makePromise(value, isResolved);
+ }, function(error) {
+ return makePromise(error, false);
+ });
+ } else {
+ return makePromise(value, isResolved);
+ }
+ };
/**
* @ngdoc method
@@ -11846,64 +14739,26 @@ function qFactory(nextTick, exceptionHandler) {
* @param {*} value Value or a promise
* @returns {Promise} Returns a promise of the passed value or promise
*/
- var when = function(value, callback, errback, progressback) {
- var result = defer(),
- done;
-
- var wrappedCallback = function(value) {
- try {
- return (isFunction(callback) ? callback : defaultCallback)(value);
- } catch (e) {
- exceptionHandler(e);
- return reject(e);
- }
- };
-
- var wrappedErrback = function(reason) {
- try {
- return (isFunction(errback) ? errback : defaultErrback)(reason);
- } catch (e) {
- exceptionHandler(e);
- return reject(e);
- }
- };
-
- var wrappedProgressback = function(progress) {
- try {
- return (isFunction(progressback) ? progressback : defaultCallback)(progress);
- } catch (e) {
- exceptionHandler(e);
- }
- };
- nextTick(function() {
- ref(value).then(function(value) {
- if (done) return;
- done = true;
- result.resolve(ref(value).then(wrappedCallback, wrappedErrback, wrappedProgressback));
- }, function(reason) {
- if (done) return;
- done = true;
- result.resolve(wrappedErrback(reason));
- }, function(progress) {
- if (done) return;
- result.notify(wrappedProgressback(progress));
- });
- });
- return result.promise;
+ var when = function(value, callback, errback, progressBack) {
+ var result = new Deferred();
+ result.resolve(value);
+ return result.promise.then(callback, errback, progressBack);
};
-
- function defaultCallback(value) {
- return value;
- }
-
-
- function defaultErrback(reason) {
- return reject(reason);
- }
-
+ /**
+ * @ngdoc method
+ * @name $q#resolve
+ * @kind function
+ *
+ * @description
+ * Alias of {@link ng.$q#when when} to maintain naming consistency with ES6.
+ *
+ * @param {*} value Value or a promise
+ * @returns {Promise} Returns a promise of the passed value or promise
+ */
+ var resolve = when;
/**
* @ngdoc method
@@ -11920,14 +14775,15 @@ function qFactory(nextTick, exceptionHandler) {
* If any of the promises is resolved with a rejection, this resulting promise will be rejected
* with the same rejection value.
*/
+
function all(promises) {
- var deferred = defer(),
+ var deferred = new Deferred(),
counter = 0,
results = isArray(promises) ? [] : {};
forEach(promises, function(promise, key) {
counter++;
- ref(promise).then(function(value) {
+ when(promise).then(function(value) {
if (results.hasOwnProperty(key)) return;
results[key] = value;
if (!(--counter)) deferred.resolve(results);
@@ -11944,27 +14800,51 @@ function qFactory(nextTick, exceptionHandler) {
return deferred.promise;
}
- return {
- defer: defer,
- reject: reject,
- when: when,
- all: all
+ var $Q = function Q(resolver) {
+ if (!isFunction(resolver)) {
+ throw $qMinErr('norslvr', "Expected resolverFn, got '{0}'", resolver);
+ }
+
+ if (!(this instanceof Q)) {
+ // More useful when $Q is the Promise itself.
+ return new Q(resolver);
+ }
+
+ var deferred = new Deferred();
+
+ function resolveFn(value) {
+ deferred.resolve(value);
+ }
+
+ function rejectFn(reason) {
+ deferred.reject(reason);
+ }
+
+ resolver(resolveFn, rejectFn);
+
+ return deferred.promise;
};
+
+ $Q.defer = defer;
+ $Q.reject = reject;
+ $Q.when = when;
+ $Q.resolve = resolve;
+ $Q.all = all;
+
+ return $Q;
}
-function $$RAFProvider(){ //rAF
+function $$RAFProvider() { //rAF
this.$get = ['$window', '$timeout', function($window, $timeout) {
var requestAnimationFrame = $window.requestAnimationFrame ||
- $window.webkitRequestAnimationFrame ||
- $window.mozRequestAnimationFrame;
+ $window.webkitRequestAnimationFrame;
var cancelAnimationFrame = $window.cancelAnimationFrame ||
$window.webkitCancelAnimationFrame ||
- $window.mozCancelAnimationFrame ||
$window.webkitCancelRequestAnimationFrame;
var rafSupported = !!requestAnimationFrame;
- var raf = rafSupported
+ var rafFn = rafSupported
? function(fn) {
var id = requestAnimationFrame(fn);
return function() {
@@ -11978,9 +14858,47 @@ function $$RAFProvider(){ //rAF
};
};
- raf.supported = rafSupported;
+ queueFn.supported = rafSupported;
+
+ var cancelLastRAF;
+ var taskCount = 0;
+ var taskQueue = [];
+ return queueFn;
- return raf;
+ function flush() {
+ for (var i = 0; i < taskQueue.length; i++) {
+ var task = taskQueue[i];
+ if (task) {
+ taskQueue[i] = null;
+ task();
+ }
+ }
+ taskCount = taskQueue.length = 0;
+ }
+
+ function queueFn(asyncFn) {
+ var index = taskQueue.length;
+
+ taskCount++;
+ taskQueue.push(asyncFn);
+
+ if (index === 0) {
+ cancelLastRAF = rafFn(flush);
+ }
+
+ return function cancelQueueFn() {
+ if (index >= 0) {
+ taskQueue[index] = null;
+ index = null;
+
+ if (--taskCount === 0 && cancelLastRAF) {
+ cancelLastRAF();
+ cancelLastRAF = null;
+ taskQueue.length = 0;
+ }
+ }
+ };
+ }
}];
}
@@ -12051,10 +14969,11 @@ function $$RAFProvider(){ //rAF
* They also provide an event emission/broadcast and subscription facility. See the
* {@link guide/scope developer guide on scopes}.
*/
-function $RootScopeProvider(){
+function $RootScopeProvider() {
var TTL = 10;
var $rootScopeMinErr = minErr('$rootScope');
var lastDirtyWatch = null;
+ var applyAsyncId = null;
this.digestTtl = function(value) {
if (arguments.length) {
@@ -12063,8 +14982,26 @@ function $RootScopeProvider(){
return TTL;
};
+ function createChildScopeClass(parent) {
+ function ChildScope() {
+ this.$$watchers = this.$$nextSibling =
+ this.$$childHead = this.$$childTail = null;
+ this.$$listeners = {};
+ this.$$listenerCount = {};
+ this.$$watchersCount = 0;
+ this.$id = nextUid();
+ this.$$ChildScope = null;
+ }
+ ChildScope.prototype = parent;
+ return ChildScope;
+ }
+
this.$get = ['$injector', '$exceptionHandler', '$parse', '$browser',
- function( $injector, $exceptionHandler, $parse, $browser) {
+ function($injector, $exceptionHandler, $parse, $browser) {
+
+ function destroyChildScope($event) {
+ $event.currentScope.$$destroyed = true;
+ }
/**
* @ngdoc type
@@ -12088,7 +15025,6 @@ function $RootScopeProvider(){
var child = parent.$new();
parent.salutation = "Hello";
- child.name = "World";
expect(child.salutation).toEqual('Hello');
child.salutation = "Welcome";
@@ -12096,6 +15032,10 @@ function $RootScopeProvider(){
expect(parent.salutation).toEqual('Hello');
* ```
*
+ * When interacting with `Scope` in tests, additional helper methods are available on the
+ * instances of `Scope` type. See {@link ngMock.$rootScope.Scope ngMock Scope} for additional
+ * details.
+ *
*
* @param {Object.<string, function()>=} providers Map of service factory which need to be
* provided for the current scope. Defaults to {@link ng}.
@@ -12111,13 +15051,12 @@ function $RootScopeProvider(){
this.$$phase = this.$parent = this.$$watchers =
this.$$nextSibling = this.$$prevSibling =
this.$$childHead = this.$$childTail = null;
- this['this'] = this.$root = this;
+ this.$root = this;
this.$$destroyed = false;
- this.$$asyncQueue = [];
- this.$$postDigestQueue = [];
this.$$listeners = {};
this.$$listenerCount = {};
- this.$$isolateBindings = {};
+ this.$$watchersCount = 0;
+ this.$$isolateBindings = null;
}
/**
@@ -12166,44 +15105,47 @@ function $RootScopeProvider(){
* When creating widgets, it is useful for the widget to not accidentally read parent
* state.
*
+ * @param {Scope} [parent=this] The {@link ng.$rootScope.Scope `Scope`} that will be the `$parent`
+ * of the newly created scope. Defaults to `this` scope if not provided.
+ * This is used when creating a transclude scope to correctly place it
+ * in the scope hierarchy while maintaining the correct prototypical
+ * inheritance.
+ *
* @returns {Object} The newly created child scope.
*
*/
- $new: function(isolate) {
- var ChildScope,
- child;
+ $new: function(isolate, parent) {
+ var child;
+
+ parent = parent || this;
if (isolate) {
child = new Scope();
child.$root = this.$root;
- // ensure that there is just one async queue per $rootScope and its children
- child.$$asyncQueue = this.$$asyncQueue;
- child.$$postDigestQueue = this.$$postDigestQueue;
} else {
// Only create a child scope class if somebody asks for one,
// but cache it to allow the VM to optimize lookups.
- if (!this.$$childScopeClass) {
- this.$$childScopeClass = function() {
- this.$$watchers = this.$$nextSibling =
- this.$$childHead = this.$$childTail = null;
- this.$$listeners = {};
- this.$$listenerCount = {};
- this.$id = nextUid();
- this.$$childScopeClass = null;
- };
- this.$$childScopeClass.prototype = this;
+ if (!this.$$ChildScope) {
+ this.$$ChildScope = createChildScopeClass(this);
}
- child = new this.$$childScopeClass();
+ child = new this.$$ChildScope();
}
- child['this'] = child;
- child.$parent = this;
- child.$$prevSibling = this.$$childTail;
- if (this.$$childHead) {
- this.$$childTail.$$nextSibling = child;
- this.$$childTail = child;
+ child.$parent = parent;
+ child.$$prevSibling = parent.$$childTail;
+ if (parent.$$childHead) {
+ parent.$$childTail.$$nextSibling = child;
+ parent.$$childTail = child;
} else {
- this.$$childHead = this.$$childTail = child;
+ parent.$$childHead = parent.$$childTail = child;
}
+
+ // When the new scope is not isolated or we inherit from `this`, and
+ // the parent scope is destroyed, the property `$$destroyed` is inherited
+ // prototypically. In all other cases, this property needs to be set
+ // when the parent scope is destroyed.
+ // The listener needs to be added after the parent is set
+ if (isolate || parent != this) child.$on('$destroy', destroyChildScope);
+
return child;
},
@@ -12247,7 +15189,6 @@ function $RootScopeProvider(){
* can compare the `newVal` and `oldVal`. If these two values are identical (`===`) then the
* listener was called due to initialization.
*
- * The example below contains an illustration of using a function as your $watch listener
*
*
* # Example
@@ -12277,14 +15218,14 @@ function $RootScopeProvider(){
- // Using a listener function
+ // Using a function as a watchExpression
var food;
scope.foodCounter = 0;
expect(scope.foodCounter).toEqual(0);
scope.$watch(
- // This is the listener function
+ // This function returns the value being watched. It is called for each turn of the $digest loop
function() { return food; },
- // This is the change handler
+ // This is the change listener, called when the value returned from the above function changes
function(newValue, oldValue) {
if ( newValue !== oldValue ) {
// Only increment the counter if the value changed
@@ -12314,43 +15255,36 @@ function $RootScopeProvider(){
*
* - `string`: Evaluated as {@link guide/expression expression}
* - `function(scope)`: called with current `scope` as a parameter.
- * @param {(function()|string)=} listener Callback called whenever the return value of
- * the `watchExpression` changes.
- *
- * - `string`: Evaluated as {@link guide/expression expression}
- * - `function(newValue, oldValue, scope)`: called with current and previous values as
- * parameters.
+ * @param {function(newVal, oldVal, scope)} listener Callback called whenever the value
+ * of `watchExpression` changes.
*
+ * - `newVal` contains the current value of the `watchExpression`
+ * - `oldVal` contains the previous value of the `watchExpression`
+ * - `scope` refers to the current scope
* @param {boolean=} objectEquality Compare for object equality using {@link angular.equals} instead of
* comparing for reference equality.
* @returns {function()} Returns a deregistration function for this listener.
*/
- $watch: function(watchExp, listener, objectEquality) {
+ $watch: function(watchExp, listener, objectEquality, prettyPrintExpression) {
+ var get = $parse(watchExp);
+
+ if (get.$$watchDelegate) {
+ return get.$$watchDelegate(this, listener, objectEquality, get, watchExp);
+ }
var scope = this,
- get = compileToFn(watchExp, 'watch'),
array = scope.$$watchers,
watcher = {
fn: listener,
last: initWatchVal,
get: get,
- exp: watchExp,
+ exp: prettyPrintExpression || watchExp,
eq: !!objectEquality
};
lastDirtyWatch = null;
- // in the case user pass string, we need to compile it, do we really need this ?
if (!isFunction(listener)) {
- var listenFn = compileToFn(listener || noop, 'listener');
- watcher.fn = function(newVal, oldVal, scope) {listenFn(scope);};
- }
-
- if (typeof watchExp == 'string' && get.constant) {
- var originalFn = watcher.fn;
- watcher.fn = function(newVal, oldVal, scope) {
- originalFn.call(this, newVal, oldVal, scope);
- arrayRemove(array, watcher);
- };
+ watcher.fn = noop;
}
if (!array) {
@@ -12359,13 +15293,99 @@ function $RootScopeProvider(){
// we use unshift since we use a while loop in $digest for speed.
// the while loop reads in reverse order.
array.unshift(watcher);
+ incrementWatchersCount(this, 1);
return function deregisterWatch() {
- arrayRemove(array, watcher);
+ if (arrayRemove(array, watcher) >= 0) {
+ incrementWatchersCount(scope, -1);
+ }
lastDirtyWatch = null;
};
},
+ /**
+ * @ngdoc method
+ * @name $rootScope.Scope#$watchGroup
+ * @kind function
+ *
+ * @description
+ * A variant of {@link ng.$rootScope.Scope#$watch $watch()} where it watches an array of `watchExpressions`.
+ * If any one expression in the collection changes the `listener` is executed.
+ *
+ * - The items in the `watchExpressions` array are observed via standard $watch operation and are examined on every
+ * call to $digest() to see if any items changes.
+ * - The `listener` is called whenever any expression in the `watchExpressions` array changes.
+ *
+ * @param {Array.<string|Function(scope)>} watchExpressions Array of expressions that will be individually
+ * watched using {@link ng.$rootScope.Scope#$watch $watch()}
+ *
+ * @param {function(newValues, oldValues, scope)} listener Callback called whenever the return value of any
+ * expression in `watchExpressions` changes
+ * The `newValues` array contains the current values of the `watchExpressions`, with the indexes matching
+ * those of `watchExpression`
+ * and the `oldValues` array contains the previous values of the `watchExpressions`, with the indexes matching
+ * those of `watchExpression`
+ * The `scope` refers to the current scope.
+ * @returns {function()} Returns a de-registration function for all listeners.
+ */
+ $watchGroup: function(watchExpressions, listener) {
+ var oldValues = new Array(watchExpressions.length);
+ var newValues = new Array(watchExpressions.length);
+ var deregisterFns = [];
+ var self = this;
+ var changeReactionScheduled = false;
+ var firstRun = true;
+
+ if (!watchExpressions.length) {
+ // No expressions means we call the listener ASAP
+ var shouldCall = true;
+ self.$evalAsync(function() {
+ if (shouldCall) listener(newValues, newValues, self);
+ });
+ return function deregisterWatchGroup() {
+ shouldCall = false;
+ };
+ }
+
+ if (watchExpressions.length === 1) {
+ // Special case size of one
+ return this.$watch(watchExpressions[0], function watchGroupAction(value, oldValue, scope) {
+ newValues[0] = value;
+ oldValues[0] = oldValue;
+ listener(newValues, (value === oldValue) ? newValues : oldValues, scope);
+ });
+ }
+
+ forEach(watchExpressions, function(expr, i) {
+ var unwatchFn = self.$watch(expr, function watchGroupSubAction(value, oldValue) {
+ newValues[i] = value;
+ oldValues[i] = oldValue;
+ if (!changeReactionScheduled) {
+ changeReactionScheduled = true;
+ self.$evalAsync(watchGroupAction);
+ }
+ });
+ deregisterFns.push(unwatchFn);
+ });
+
+ function watchGroupAction() {
+ changeReactionScheduled = false;
+
+ if (firstRun) {
+ firstRun = false;
+ listener(newValues, newValues, self);
+ } else {
+ listener(newValues, oldValues, self);
+ }
+ }
+
+ return function deregisterWatchGroup() {
+ while (deregisterFns.length) {
+ deregisterFns.shift()();
+ }
+ };
+ },
+
/**
* @ngdoc method
@@ -12423,6 +15443,8 @@ function $RootScopeProvider(){
* de-registration function is executed, the internal watch operation is terminated.
*/
$watchCollection: function(obj, listener) {
+ $watchCollectionInterceptor.$stateful = true;
+
var self = this;
// the current value, updated on each dirty-check run
var newValue;
@@ -12434,15 +15456,18 @@ function $RootScopeProvider(){
// only track veryOldValue if the listener is asking for it
var trackVeryOldValue = (listener.length > 1);
var changeDetected = 0;
- var objGetter = $parse(obj);
+ var changeDetector = $parse(obj, $watchCollectionInterceptor);
var internalArray = [];
var internalObject = {};
var initRun = true;
var oldLength = 0;
- function $watchCollectionWatch() {
- newValue = objGetter(self);
- var newLength, key, bothNaN;
+ function $watchCollectionInterceptor(_value) {
+ newValue = _value;
+ var newLength, key, bothNaN, newItem, oldItem;
+
+ // If the new value is undefined, then return undefined as the watch may be a one-time watch
+ if (isUndefined(newValue)) return;
if (!isObject(newValue)) { // if primitive
if (oldValue !== newValue) {
@@ -12466,11 +15491,13 @@ function $RootScopeProvider(){
}
// copy the items to oldValue and look for changes.
for (var i = 0; i < newLength; i++) {
- bothNaN = (oldValue[i] !== oldValue[i]) &&
- (newValue[i] !== newValue[i]);
- if (!bothNaN && (oldValue[i] !== newValue[i])) {
+ oldItem = oldValue[i];
+ newItem = newValue[i];
+
+ bothNaN = (oldItem !== oldItem) && (newItem !== newItem);
+ if (!bothNaN && (oldItem !== newItem)) {
changeDetected++;
- oldValue[i] = newValue[i];
+ oldValue[i] = newItem;
}
}
} else {
@@ -12485,16 +15512,18 @@ function $RootScopeProvider(){
for (key in newValue) {
if (newValue.hasOwnProperty(key)) {
newLength++;
- if (oldValue.hasOwnProperty(key)) {
- bothNaN = (oldValue[key] !== oldValue[key]) &&
- (newValue[key] !== newValue[key]);
- if (!bothNaN && (oldValue[key] !== newValue[key])) {
+ newItem = newValue[key];
+ oldItem = oldValue[key];
+
+ if (key in oldValue) {
+ bothNaN = (oldItem !== oldItem) && (newItem !== newItem);
+ if (!bothNaN && (oldItem !== newItem)) {
changeDetected++;
- oldValue[key] = newValue[key];
+ oldValue[key] = newItem;
}
} else {
oldLength++;
- oldValue[key] = newValue[key];
+ oldValue[key] = newItem;
changeDetected++;
}
}
@@ -12502,8 +15531,8 @@ function $RootScopeProvider(){
if (oldLength > newLength) {
// we used to have more keys, need to find them and destroy them.
changeDetected++;
- for(key in oldValue) {
- if (oldValue.hasOwnProperty(key) && !newValue.hasOwnProperty(key)) {
+ for (key in oldValue) {
+ if (!newValue.hasOwnProperty(key)) {
oldLength--;
delete oldValue[key];
}
@@ -12542,7 +15571,7 @@ function $RootScopeProvider(){
}
}
- return this.$watch($watchCollectionWatch, $watchCollectionAction);
+ return this.$watch(changeDetector, $watchCollectionAction);
},
/**
@@ -12562,7 +15591,7 @@ function $RootScopeProvider(){
* {@link ng.directive:ngController controllers} or in
* {@link ng.$compileProvider#directive directives}.
* Instead, you should call {@link ng.$rootScope.Scope#$apply $apply()} (typically from within
- * a {@link ng.$compileProvider#directive directives}), which will force a `$digest()`.
+ * a {@link ng.$compileProvider#directive directive}), which will force a `$digest()`.
*
* If you want to be notified whenever `$digest()` is called,
* you can register a `watchExpression` function with
@@ -12599,8 +15628,6 @@ function $RootScopeProvider(){
$digest: function() {
var watch, value, last,
watchers,
- asyncQueue = this.$$asyncQueue,
- postDigestQueue = this.$$postDigestQueue,
length,
dirty, ttl = TTL,
next, current, target = this,
@@ -12611,18 +15638,24 @@ function $RootScopeProvider(){
// Check for changes to browser url that happened in sync before the call to $digest
$browser.$$checkUrlChange();
+ if (this === $rootScope && applyAsyncId !== null) {
+ // If this is the root scope, and $applyAsync has scheduled a deferred $apply(), then
+ // cancel the scheduled $apply and flush the queue of expressions to be evaluated.
+ $browser.defer.cancel(applyAsyncId);
+ flushApplyAsync();
+ }
+
lastDirtyWatch = null;
do { // "while dirty" loop
dirty = false;
current = target;
- while(asyncQueue.length) {
+ while (asyncQueue.length) {
try {
asyncTask = asyncQueue.shift();
- asyncTask.scope.$eval(asyncTask.expression);
+ asyncTask.scope.$eval(asyncTask.expression, asyncTask.locals);
} catch (e) {
- clearPhase();
$exceptionHandler(e);
}
lastDirtyWatch = null;
@@ -12651,11 +15684,11 @@ function $RootScopeProvider(){
if (ttl < 5) {
logIdx = 4 - ttl;
if (!watchLog[logIdx]) watchLog[logIdx] = [];
- logMsg = (isFunction(watch.exp))
- ? 'fn: ' + (watch.exp.name || watch.exp.toString())
- : watch.exp;
- logMsg += '; newVal: ' + toJson(value) + '; oldVal: ' + toJson(last);
- watchLog[logIdx].push(logMsg);
+ watchLog[logIdx].push({
+ msg: isFunction(watch.exp) ? 'fn: ' + (watch.exp.name || watch.exp.toString()) : watch.exp,
+ newVal: value,
+ oldVal: last
+ });
}
} else if (watch === lastDirtyWatch) {
// If the most recently dirty watcher is now clean, short circuit since the remaining watchers
@@ -12665,7 +15698,6 @@ function $RootScopeProvider(){
}
}
} catch (e) {
- clearPhase();
$exceptionHandler(e);
}
}
@@ -12674,9 +15706,9 @@ function $RootScopeProvider(){
// Insanity Warning: scope depth-first traversal
// yes, this code is a bit crazy, but it works and we have tests to prove it!
// this piece should be kept in sync with the traversal in $broadcast
- if (!(next = (current.$$childHead ||
+ if (!(next = ((current.$$watchersCount && current.$$childHead) ||
(current !== target && current.$$nextSibling)))) {
- while(current !== target && !(next = current.$$nextSibling)) {
+ while (current !== target && !(next = current.$$nextSibling)) {
current = current.$parent;
}
}
@@ -12684,19 +15716,19 @@ function $RootScopeProvider(){
// `break traverseScopesLoop;` takes us to here
- if((dirty || asyncQueue.length) && !(ttl--)) {
+ if ((dirty || asyncQueue.length) && !(ttl--)) {
clearPhase();
throw $rootScopeMinErr('infdig',
'{0} $digest() iterations reached. Aborting!\n' +
'Watchers fired in the last 5 iterations: {1}',
- TTL, toJson(watchLog));
+ TTL, watchLog);
}
} while (dirty || asyncQueue.length);
clearPhase();
- while(postDigestQueue.length) {
+ while (postDigestQueue.length) {
try {
postDigestQueue.shift()();
} catch (e) {
@@ -12741,23 +15773,34 @@ function $RootScopeProvider(){
* clean up DOM bindings before an element is removed from the DOM.
*/
$destroy: function() {
- // we can't destroy the root scope or a scope that has been already destroyed
+ // We can't destroy a scope that has been already destroyed.
if (this.$$destroyed) return;
var parent = this.$parent;
this.$broadcast('$destroy');
this.$$destroyed = true;
- if (this === $rootScope) return;
- forEach(this.$$listenerCount, bind(null, decrementListenerCount, this));
+ if (this === $rootScope) {
+ //Remove handlers attached to window when $rootScope is removed
+ $browser.$$applicationDestroyed();
+ }
+
+ incrementWatchersCount(this, -this.$$watchersCount);
+ for (var eventName in this.$$listenerCount) {
+ decrementListenerCount(this, this.$$listenerCount[eventName], eventName);
+ }
// sever all the references to parent scopes (after this cleanup, the current scope should
// not be retained by any of our references and should be eligible for garbage collection)
- if (parent.$$childHead == this) parent.$$childHead = this.$$nextSibling;
- if (parent.$$childTail == this) parent.$$childTail = this.$$prevSibling;
+ if (parent && parent.$$childHead == this) parent.$$childHead = this.$$nextSibling;
+ if (parent && parent.$$childTail == this) parent.$$childTail = this.$$prevSibling;
if (this.$$prevSibling) this.$$prevSibling.$$nextSibling = this.$$nextSibling;
if (this.$$nextSibling) this.$$nextSibling.$$prevSibling = this.$$prevSibling;
+ // Disable listeners, watchers and apply/digest methods
+ this.$destroy = this.$digest = this.$apply = this.$evalAsync = this.$applyAsync = noop;
+ this.$on = this.$watch = this.$watchGroup = function() { return noop; };
+ this.$$listeners = {};
// All of the code below is bogus code that works around V8's memory leak via optimized code
// and inline caches.
@@ -12768,15 +15811,7 @@ function $RootScopeProvider(){
// - https://github.com/angular/angular.js/issues/1313#issuecomment-10378451
this.$parent = this.$$nextSibling = this.$$prevSibling = this.$$childHead =
- this.$$childTail = this.$root = null;
-
- // don't reset these to null in case some async task tries to register a listener/watch/task
- this.$$listeners = {};
- this.$$watchers = this.$$asyncQueue = this.$$postDigestQueue = [];
-
- // prevent NPEs since these methods have references to properties we nulled out
- this.$destroy = this.$digest = this.$apply = noop;
- this.$on = this.$watch = function() { return noop; };
+ this.$$childTail = this.$root = this.$$watchers = null;
},
/**
@@ -12839,23 +15874,24 @@ function $RootScopeProvider(){
* - `string`: execute using the rules as defined in {@link guide/expression expression}.
* - `function(scope)`: execute the function with the current `scope` parameter.
*
+ * @param {(object)=} locals Local variables object, useful for overriding values in scope.
*/
- $evalAsync: function(expr) {
+ $evalAsync: function(expr, locals) {
// if we are outside of an $digest loop and this is the first time we are scheduling async
// task also schedule async auto-flush
- if (!$rootScope.$$phase && !$rootScope.$$asyncQueue.length) {
+ if (!$rootScope.$$phase && !asyncQueue.length) {
$browser.defer(function() {
- if ($rootScope.$$asyncQueue.length) {
+ if (asyncQueue.length) {
$rootScope.$digest();
}
});
}
- this.$$asyncQueue.push({scope: this, expression: expr});
+ asyncQueue.push({scope: this, expression: expr, locals: locals});
},
- $$postDigest : function(fn) {
- this.$$postDigestQueue.push(fn);
+ $$postDigest: function(fn) {
+ postDigestQueue.push(fn);
},
/**
@@ -12922,6 +15958,33 @@ function $RootScopeProvider(){
/**
* @ngdoc method
+ * @name $rootScope.Scope#$applyAsync
+ * @kind function
+ *
+ * @description
+ * Schedule the invocation of $apply to occur at a later time. The actual time difference
+ * varies across browsers, but is typically around ~10 milliseconds.
+ *
+ * This can be used to queue up multiple expressions which need to be evaluated in the same
+ * digest.
+ *
+ * @param {(string|function())=} exp An angular expression to be executed.
+ *
+ * - `string`: execute using the rules as defined in {@link guide/expression expression}.
+ * - `function(scope)`: execute the function with current `scope` parameter.
+ */
+ $applyAsync: function(expr) {
+ var scope = this;
+ expr && applyAsyncQueue.push($applyAsyncExpression);
+ scheduleApplyAsync();
+
+ function $applyAsyncExpression() {
+ scope.$eval(expr);
+ }
+ },
+
+ /**
+ * @ngdoc method
* @name $rootScope.Scope#$on
* @kind function
*
@@ -12934,7 +15997,8 @@ function $RootScopeProvider(){
*
* - `targetScope` - `{Scope}`: the scope on which the event was `$emit`-ed or
* `$broadcast`-ed.
- * - `currentScope` - `{Scope}`: the current scope which is handling the event.
+ * - `currentScope` - `{Scope}`: the scope that is currently handling the event. Once the
+ * event propagates through the scope hierarchy, this property is set to null.
* - `name` - `{string}`: name of the event.
* - `stopPropagation` - `{function=}`: calling `stopPropagation` function will cancel
* further event propagation (available only for events that were `$emit`-ed).
@@ -12963,7 +16027,7 @@ function $RootScopeProvider(){
var self = this;
return function() {
- var indexOfListener = indexOf(namedListeners, listener);
+ var indexOfListener = namedListeners.indexOf(listener);
if (indexOfListener !== -1) {
namedListeners[indexOfListener] = null;
decrementListenerCount(self, 1, name);
@@ -13014,7 +16078,7 @@ function $RootScopeProvider(){
do {
namedListeners = scope.$$listeners[name] || empty;
event.currentScope = scope;
- for (i=0, length=namedListeners.length; i<length; i++) {
+ for (i = 0, length = namedListeners.length; i < length; i++) {
// if listeners were deregistered, defragment the array
if (!namedListeners[i]) {
@@ -13031,11 +16095,16 @@ function $RootScopeProvider(){
}
}
//if any listener on the current scope stops propagation, prevent bubbling
- if (stopPropagation) return event;
+ if (stopPropagation) {
+ event.currentScope = null;
+ return event;
+ }
//traverse upwards
scope = scope.$parent;
} while (scope);
+ event.currentScope = null;
+
return event;
},
@@ -13072,15 +16141,18 @@ function $RootScopeProvider(){
event.defaultPrevented = true;
},
defaultPrevented: false
- },
- listenerArgs = concat([event], arguments, 1),
+ };
+
+ if (!target.$$listenerCount[name]) return event;
+
+ var listenerArgs = concat([event], arguments, 1),
listeners, i, length;
//down while you can, then up and next sibling or up and next sibling until back at root
while ((current = next)) {
event.currentScope = current;
listeners = current.$$listeners[name] || [];
- for (i=0, length = listeners.length; i<length; i++) {
+ for (i = 0, length = listeners.length; i < length; i++) {
// if listeners were deregistered, defragment the array
if (!listeners[i]) {
listeners.splice(i, 1);
@@ -13091,7 +16163,7 @@ function $RootScopeProvider(){
try {
listeners[i].apply(null, listenerArgs);
- } catch(e) {
+ } catch (e) {
$exceptionHandler(e);
}
}
@@ -13102,18 +16174,24 @@ function $RootScopeProvider(){
// (though it differs due to having the extra check for $$listenerCount)
if (!(next = ((current.$$listenerCount[name] && current.$$childHead) ||
(current !== target && current.$$nextSibling)))) {
- while(current !== target && !(next = current.$$nextSibling)) {
+ while (current !== target && !(next = current.$$nextSibling)) {
current = current.$parent;
}
}
}
+ event.currentScope = null;
return event;
}
};
var $rootScope = new Scope();
+ //The internal queues. Expose them on the $rootScope for debugging/testing purposes.
+ var asyncQueue = $rootScope.$$asyncQueue = [];
+ var postDigestQueue = $rootScope.$$postDigestQueue = [];
+ var applyAsyncQueue = $rootScope.$$applyAsyncQueue = [];
+
return $rootScope;
@@ -13129,10 +16207,10 @@ function $RootScopeProvider(){
$rootScope.$$phase = null;
}
- function compileToFn(exp, name) {
- var fn = $parse(exp);
- assertArgFn(fn, name);
- return fn;
+ function incrementWatchersCount(current, count) {
+ do {
+ current.$$watchersCount += count;
+ } while ((current = current.$parent));
}
function decrementListenerCount(current, count, name) {
@@ -13150,6 +16228,25 @@ function $RootScopeProvider(){
* because it's unique we can easily tell it apart from other values
*/
function initWatchVal() {}
+
+ function flushApplyAsync() {
+ while (applyAsyncQueue.length) {
+ try {
+ applyAsyncQueue.shift()();
+ } catch (e) {
+ $exceptionHandler(e);
+ }
+ }
+ applyAsyncId = null;
+ }
+
+ function scheduleApplyAsync() {
+ if (applyAsyncId === null) {
+ applyAsyncId = $browser.defer(function() {
+ $rootScope.$apply(flushApplyAsync);
+ });
+ }
+ }
}];
}
@@ -13159,7 +16256,7 @@ function $RootScopeProvider(){
*/
function $$SanitizeUriProvider() {
var aHrefSanitizationWhitelist = /^\s*(https?|ftp|mailto|tel|file):/,
- imgSrcSanitizationWhitelist = /^\s*((https?|ftp|file):|data:image\/)/;
+ imgSrcSanitizationWhitelist = /^\s*((https?|ftp|file|blob):|data:image\/)/;
/**
* @description
@@ -13214,18 +16311,26 @@ function $$SanitizeUriProvider() {
return function sanitizeUri(uri, isImage) {
var regex = isImage ? imgSrcSanitizationWhitelist : aHrefSanitizationWhitelist;
var normalizedVal;
- // NOTE: urlResolve() doesn't support IE < 8 so we don't sanitize for that case.
- if (!msie || msie >= 8 ) {
- normalizedVal = urlResolve(uri).href;
- if (normalizedVal !== '' && !normalizedVal.match(regex)) {
- return 'unsafe:'+normalizedVal;
- }
+ normalizedVal = urlResolve(uri).href;
+ if (normalizedVal !== '' && !normalizedVal.match(regex)) {
+ return 'unsafe:' + normalizedVal;
}
return uri;
};
};
}
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Any commits to this file should be reviewed with security in mind. *
+ * Changes to this file can potentially create security vulnerabilities. *
+ * An approval from 2 Core members with history of modifying *
+ * this file is required. *
+ * *
+ * Does the change somehow allow for arbitrary javascript to be executed? *
+ * Or allows for someone to change the prototype of built-in objects? *
+ * Or gives undesired access to variables likes document or window? *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
var $sceMinErr = minErr('$sce');
var SCE_CONTEXTS = {
@@ -13240,15 +16345,6 @@ var SCE_CONTEXTS = {
// Helper functions follow.
-// Copied from:
-// http://docs.closure-library.googlecode.com/git/closure_goog_string_string.js.source.html#line962
-// Prereq: s is a string.
-function escapeForRegexp(s) {
- return s.replace(/([-()\[\]{}+?*.$\^|,:#<!\\])/g, '\\$1').
- replace(/\x08/g, '\\x08');
-}
-
-
function adjustMatcher(matcher) {
if (matcher === 'self') {
return matcher;
@@ -13384,7 +16480,7 @@ function $SceDelegateProvider() {
* @description
* Sets/Gets the whitelist of trusted resource URLs.
*/
- this.resourceUrlWhitelist = function (value) {
+ this.resourceUrlWhitelist = function(value) {
if (arguments.length) {
resourceUrlWhitelist = adjustMatchers(value);
}
@@ -13418,7 +16514,7 @@ function $SceDelegateProvider() {
* Sets/Gets the blacklist of trusted resource URLs.
*/
- this.resourceUrlBlacklist = function (value) {
+ this.resourceUrlBlacklist = function(value) {
if (arguments.length) {
resourceUrlBlacklist = adjustMatchers(value);
}
@@ -13636,7 +16732,7 @@ function $SceDelegateProvider() {
*
* As of version 1.2, Angular ships with SCE enabled by default.
*
- * Note: When enabled (the default), IE8 in quirks mode is not supported. In this mode, IE8 allows
+ * Note: When enabled (the default), IE<11 in quirks mode is not supported. In this mode, IE<11 allow
* one to execute arbitrary javascript by the use of the expression() syntax. Refer
* <http://blogs.msdn.com/b/ie/archive/2008/10/16/ending-expressions.aspx> to learn more about them.
* You can ensure your document is in standards mode and not quirks mode by adding `<!doctype html>`
@@ -13648,7 +16744,7 @@ function $SceDelegateProvider() {
* Here's an example of a binding in a privileged context:
*
* ```
- * <input ng-model="userHtml">
+ * <input ng-model="userHtml" aria-label="User input">
* <div ng-bind-html="userHtml"></div>
* ```
*
@@ -13683,7 +16779,7 @@ function $SceDelegateProvider() {
*
* In privileged contexts, directives and code will bind to the result of {@link ng.$sce#getTrusted
* $sce.getTrusted(context, value)} rather than to the value directly. Directives use {@link
- * ng.$sce#parse $sce.parseAs} rather than `$parse` to watch attribute bindings, which performs the
+ * ng.$sce#parseAs $sce.parseAs} rather than `$parse` to watch attribute bindings, which performs the
* {@link ng.$sce#getTrusted $sce.getTrusted} behind the scenes on non-constant literals.
*
* As an example, {@link ng.directive:ngBindHtml ngBindHtml} uses {@link
@@ -13720,7 +16816,7 @@ function $SceDelegateProvider() {
* won't work on all browsers. Also, loading templates from `file://` URL does not work on some
* browsers.
*
- * ## This feels like too much overhead for the developer?
+ * ## This feels like too much overhead
*
* It's important to remember that SCE only applies to interpolation expressions.
*
@@ -13804,7 +16900,7 @@ function $SceDelegateProvider() {
*
* <example module="mySceApp" deps="angular-sanitize.js">
* <file name="index.html">
- * <div ng-controller="myAppController as myCtrl">
+ * <div ng-controller="AppController as myCtrl">
* <i ng-bind-html="myCtrl.explicitlyTrustedHtml" id="explicitlyTrustedHtml"></i><br><br>
* <b>User comments</b><br>
* By default, HTML that isn't explicitly trusted (e.g. Alice's comment) is sanitized when
@@ -13821,17 +16917,17 @@ function $SceDelegateProvider() {
* </file>
*
* <file name="script.js">
- * var mySceApp = angular.module('mySceApp', ['ngSanitize']);
- *
- * mySceApp.controller("myAppController", function myAppController($http, $templateCache, $sce) {
- * var self = this;
- * $http.get("test_data.json", {cache: $templateCache}).success(function(userComments) {
- * self.userComments = userComments;
- * });
- * self.explicitlyTrustedHtml = $sce.trustAsHtml(
- * '<span onmouseover="this.textContent=&quot;Explicitly trusted HTML bypasses ' +
- * 'sanitization.&quot;">Hover over this text.</span>');
- * });
+ * angular.module('mySceApp', ['ngSanitize'])
+ * .controller('AppController', ['$http', '$templateCache', '$sce',
+ * function($http, $templateCache, $sce) {
+ * var self = this;
+ * $http.get("test_data.json", {cache: $templateCache}).success(function(userComments) {
+ * self.userComments = userComments;
+ * });
+ * self.explicitlyTrustedHtml = $sce.trustAsHtml(
+ * '<span onmouseover="this.textContent=&quot;Explicitly trusted HTML bypasses ' +
+ * 'sanitization.&quot;">Hover over this text.</span>');
+ * }]);
* </file>
*
* <file name="test_data.json">
@@ -13899,7 +16995,7 @@ function $SceProvider() {
* @description
* Enables/disables SCE and returns the current value.
*/
- this.enabled = function (value) {
+ this.enabled = function(value) {
if (arguments.length) {
enabled = !!value;
}
@@ -13953,13 +17049,13 @@ function $SceProvider() {
* sce.js and sceSpecs.js would need to be aware of this detail.
*/
- this.$get = ['$parse', '$sniffer', '$sceDelegate', function(
- $parse, $sniffer, $sceDelegate) {
- // Prereq: Ensure that we're not running in IE8 quirks mode. In that mode, IE allows
+ this.$get = ['$parse', '$sceDelegate', function(
+ $parse, $sceDelegate) {
+ // Prereq: Ensure that we're not running in IE<11 quirks mode. In that mode, IE < 11 allow
// the "expression(javascript expression)" syntax which is insecure.
- if (enabled && $sniffer.msie && $sniffer.msieDocumentMode < 8) {
+ if (enabled && msie < 8) {
throw $sceMinErr('iequirks',
- 'Strict Contextual Escaping does not support Internet Explorer version < 9 in quirks ' +
+ 'Strict Contextual Escaping does not support Internet Explorer version < 11 in quirks ' +
'mode. You can fix this by adding the text <!doctype html> to the top of your HTML ' +
'document. See http://docs.angularjs.org/api/ng.$sce for more information.');
}
@@ -13977,7 +17073,7 @@ function $SceProvider() {
* @description
* Returns a boolean indicating if SCE is enabled.
*/
- sce.isEnabled = function () {
+ sce.isEnabled = function() {
return enabled;
};
sce.trustAs = $sceDelegate.trustAs;
@@ -14013,9 +17109,9 @@ function $SceProvider() {
if (parsed.literal && parsed.constant) {
return parsed;
} else {
- return function sceParseAsTrusted(self, locals) {
- return sce.getTrusted(type, parsed(self, locals));
- };
+ return $parse(expr, function(value) {
+ return sce.getTrusted(type, value);
+ });
}
};
@@ -14032,7 +17128,7 @@ function $SceProvider() {
* escaping.
*
* @param {string} type The kind of context in which this value is safe for use. e.g. url,
- * resource_url, html, js and css.
+ * resourceUrl, html, js and css.
* @param {*} value The value that that should be considered trusted/safe.
* @returns {*} A value that can be used to stand in for the provided `value` in places
* where Angular expects a $sce.trustAs() return value.
@@ -14182,7 +17278,7 @@ function $SceProvider() {
*
* @description
* Shorthand method. `$sce.parseAsHtml(expression string)` →
- * {@link ng.$sce#parse `$sce.parseAs($sce.HTML, value)`}
+ * {@link ng.$sce#parseAs `$sce.parseAs($sce.HTML, value)`}
*
* @param {string} expression String expression to compile.
* @returns {function(context, locals)} a function which represents the compiled expression:
@@ -14199,7 +17295,7 @@ function $SceProvider() {
*
* @description
* Shorthand method. `$sce.parseAsCss(value)` →
- * {@link ng.$sce#parse `$sce.parseAs($sce.CSS, value)`}
+ * {@link ng.$sce#parseAs `$sce.parseAs($sce.CSS, value)`}
*
* @param {string} expression String expression to compile.
* @returns {function(context, locals)} a function which represents the compiled expression:
@@ -14216,7 +17312,7 @@ function $SceProvider() {
*
* @description
* Shorthand method. `$sce.parseAsUrl(value)` →
- * {@link ng.$sce#parse `$sce.parseAs($sce.URL, value)`}
+ * {@link ng.$sce#parseAs `$sce.parseAs($sce.URL, value)`}
*
* @param {string} expression String expression to compile.
* @returns {function(context, locals)} a function which represents the compiled expression:
@@ -14233,7 +17329,7 @@ function $SceProvider() {
*
* @description
* Shorthand method. `$sce.parseAsResourceUrl(value)` →
- * {@link ng.$sce#parse `$sce.parseAs($sce.RESOURCE_URL, value)`}
+ * {@link ng.$sce#parseAs `$sce.parseAs($sce.RESOURCE_URL, value)`}
*
* @param {string} expression String expression to compile.
* @returns {function(context, locals)} a function which represents the compiled expression:
@@ -14250,7 +17346,7 @@ function $SceProvider() {
*
* @description
* Shorthand method. `$sce.parseAsJs(value)` →
- * {@link ng.$sce#parse `$sce.parseAs($sce.JS, value)`}
+ * {@link ng.$sce#parseAs `$sce.parseAs($sce.JS, value)`}
*
* @param {string} expression String expression to compile.
* @returns {function(context, locals)} a function which represents the compiled expression:
@@ -14266,15 +17362,15 @@ function $SceProvider() {
getTrusted = sce.getTrusted,
trustAs = sce.trustAs;
- forEach(SCE_CONTEXTS, function (enumValue, name) {
+ forEach(SCE_CONTEXTS, function(enumValue, name) {
var lName = lowercase(name);
- sce[camelCase("parse_as_" + lName)] = function (expr) {
+ sce[camelCase("parse_as_" + lName)] = function(expr) {
return parse(enumValue, expr);
};
- sce[camelCase("get_trusted_" + lName)] = function (value) {
+ sce[camelCase("get_trusted_" + lName)] = function(value) {
return getTrusted(enumValue, value);
};
- sce[camelCase("trust_as_" + lName)] = function (value) {
+ sce[camelCase("trust_as_" + lName)] = function(value) {
return trustAs(enumValue, value);
};
});
@@ -14291,7 +17387,6 @@ function $SceProvider() {
* @requires $document
*
* @property {boolean} history Does the browser support html5 history api ?
- * @property {boolean} hashchange Does the browser support hashchange event ?
* @property {boolean} transitions Does the browser support CSS transition events ?
* @property {boolean} animations Does the browser support CSS animation events ?
*
@@ -14302,36 +17397,35 @@ function $SnifferProvider() {
this.$get = ['$window', '$document', function($window, $document) {
var eventSupport = {},
android =
- int((/android (\d+)/.exec(lowercase(($window.navigator || {}).userAgent)) || [])[1]),
+ toInt((/android (\d+)/.exec(lowercase(($window.navigator || {}).userAgent)) || [])[1]),
boxee = /Boxee/i.test(($window.navigator || {}).userAgent),
document = $document[0] || {},
- documentMode = document.documentMode,
vendorPrefix,
- vendorRegex = /^(Moz|webkit|O|ms)(?=[A-Z])/,
+ vendorRegex = /^(Moz|webkit|ms)(?=[A-Z])/,
bodyStyle = document.body && document.body.style,
transitions = false,
animations = false,
match;
if (bodyStyle) {
- for(var prop in bodyStyle) {
- if(match = vendorRegex.exec(prop)) {
+ for (var prop in bodyStyle) {
+ if (match = vendorRegex.exec(prop)) {
vendorPrefix = match[0];
vendorPrefix = vendorPrefix.substr(0, 1).toUpperCase() + vendorPrefix.substr(1);
break;
}
}
- if(!vendorPrefix) {
+ if (!vendorPrefix) {
vendorPrefix = ('WebkitOpacity' in bodyStyle) && 'webkit';
}
transitions = !!(('transition' in bodyStyle) || (vendorPrefix + 'Transition' in bodyStyle));
animations = !!(('animation' in bodyStyle) || (vendorPrefix + 'Animation' in bodyStyle));
- if (android && (!transitions||!animations)) {
- transitions = isString(document.body.style.webkitTransition);
- animations = isString(document.body.style.webkitAnimation);
+ if (android && (!transitions || !animations)) {
+ transitions = isString(bodyStyle.webkitTransition);
+ animations = isString(bodyStyle.webkitAnimation);
}
}
@@ -14348,14 +17442,13 @@ function $SnifferProvider() {
// jshint -W018
history: !!($window.history && $window.history.pushState && !(android < 4) && !boxee),
// jshint +W018
- hashchange: 'onhashchange' in $window &&
- // IE8 compatible mode lies
- (!documentMode || documentMode > 7),
hasEvent: function(event) {
// IE9 implements 'input' event it's so fubared that we rather pretend that it doesn't have
// it. In particular the event is not fired when backspace or delete key are pressed or
// when cut operation is performed.
- if (event == 'input' && msie == 9) return false;
+ // IE10+ implements 'input' event but it erroneously fires under various situations,
+ // e.g. when placeholder changes, or a form is focused.
+ if (event === 'input' && msie <= 11) return false;
if (isUndefined(eventSupport[event])) {
var divElm = document.createElement('div');
@@ -14366,18 +17459,206 @@ function $SnifferProvider() {
},
csp: csp(),
vendorPrefix: vendorPrefix,
- transitions : transitions,
- animations : animations,
- android: android,
- msie : msie,
- msieDocumentMode: documentMode
+ transitions: transitions,
+ animations: animations,
+ android: android
+ };
+ }];
+}
+
+var $compileMinErr = minErr('$compile');
+
+/**
+ * @ngdoc service
+ * @name $templateRequest
+ *
+ * @description
+ * The `$templateRequest` service runs security checks then downloads the provided template using
+ * `$http` and, upon success, stores the contents inside of `$templateCache`. If the HTTP request
+ * fails or the response data of the HTTP request is empty, a `$compile` error will be thrown (the
+ * exception can be thwarted by setting the 2nd parameter of the function to true). Note that the
+ * contents of `$templateCache` are trusted, so the call to `$sce.getTrustedUrl(tpl)` is omitted
+ * when `tpl` is of type string and `$templateCache` has the matching entry.
+ *
+ * @param {string|TrustedResourceUrl} tpl The HTTP request template URL
+ * @param {boolean=} ignoreRequestError Whether or not to ignore the exception when the request fails or the template is empty
+ *
+ * @return {Promise} a promise for the HTTP response data of the given URL.
+ *
+ * @property {number} totalPendingRequests total amount of pending template requests being downloaded.
+ */
+function $TemplateRequestProvider() {
+ this.$get = ['$templateCache', '$http', '$q', '$sce', function($templateCache, $http, $q, $sce) {
+ function handleRequestFn(tpl, ignoreRequestError) {
+ handleRequestFn.totalPendingRequests++;
+
+ // We consider the template cache holds only trusted templates, so
+ // there's no need to go through whitelisting again for keys that already
+ // are included in there. This also makes Angular accept any script
+ // directive, no matter its name. However, we still need to unwrap trusted
+ // types.
+ if (!isString(tpl) || !$templateCache.get(tpl)) {
+ tpl = $sce.getTrustedResourceUrl(tpl);
+ }
+
+ var transformResponse = $http.defaults && $http.defaults.transformResponse;
+
+ if (isArray(transformResponse)) {
+ transformResponse = transformResponse.filter(function(transformer) {
+ return transformer !== defaultHttpResponseTransform;
+ });
+ } else if (transformResponse === defaultHttpResponseTransform) {
+ transformResponse = null;
+ }
+
+ var httpOptions = {
+ cache: $templateCache,
+ transformResponse: transformResponse
+ };
+
+ return $http.get(tpl, httpOptions)
+ ['finally'](function() {
+ handleRequestFn.totalPendingRequests--;
+ })
+ .then(function(response) {
+ $templateCache.put(tpl, response.data);
+ return response.data;
+ }, handleError);
+
+ function handleError(resp) {
+ if (!ignoreRequestError) {
+ throw $compileMinErr('tpload', 'Failed to load template: {0} (HTTP status: {1} {2})',
+ tpl, resp.status, resp.statusText);
+ }
+ return $q.reject(resp);
+ }
+ }
+
+ handleRequestFn.totalPendingRequests = 0;
+
+ return handleRequestFn;
+ }];
+}
+
+function $$TestabilityProvider() {
+ this.$get = ['$rootScope', '$browser', '$location',
+ function($rootScope, $browser, $location) {
+
+ /**
+ * @name $testability
+ *
+ * @description
+ * The private $$testability service provides a collection of methods for use when debugging
+ * or by automated test and debugging tools.
+ */
+ var testability = {};
+
+ /**
+ * @name $$testability#findBindings
+ *
+ * @description
+ * Returns an array of elements that are bound (via ng-bind or {{}})
+ * to expressions matching the input.
+ *
+ * @param {Element} element The element root to search from.
+ * @param {string} expression The binding expression to match.
+ * @param {boolean} opt_exactMatch If true, only returns exact matches
+ * for the expression. Filters and whitespace are ignored.
+ */
+ testability.findBindings = function(element, expression, opt_exactMatch) {
+ var bindings = element.getElementsByClassName('ng-binding');
+ var matches = [];
+ forEach(bindings, function(binding) {
+ var dataBinding = angular.element(binding).data('$binding');
+ if (dataBinding) {
+ forEach(dataBinding, function(bindingName) {
+ if (opt_exactMatch) {
+ var matcher = new RegExp('(^|\\s)' + escapeForRegexp(expression) + '(\\s|\\||$)');
+ if (matcher.test(bindingName)) {
+ matches.push(binding);
+ }
+ } else {
+ if (bindingName.indexOf(expression) != -1) {
+ matches.push(binding);
+ }
+ }
+ });
+ }
+ });
+ return matches;
+ };
+
+ /**
+ * @name $$testability#findModels
+ *
+ * @description
+ * Returns an array of elements that are two-way found via ng-model to
+ * expressions matching the input.
+ *
+ * @param {Element} element The element root to search from.
+ * @param {string} expression The model expression to match.
+ * @param {boolean} opt_exactMatch If true, only returns exact matches
+ * for the expression.
+ */
+ testability.findModels = function(element, expression, opt_exactMatch) {
+ var prefixes = ['ng-', 'data-ng-', 'ng\\:'];
+ for (var p = 0; p < prefixes.length; ++p) {
+ var attributeEquals = opt_exactMatch ? '=' : '*=';
+ var selector = '[' + prefixes[p] + 'model' + attributeEquals + '"' + expression + '"]';
+ var elements = element.querySelectorAll(selector);
+ if (elements.length) {
+ return elements;
+ }
+ }
+ };
+
+ /**
+ * @name $$testability#getLocation
+ *
+ * @description
+ * Shortcut for getting the location in a browser agnostic way. Returns
+ * the path, search, and hash. (e.g. /path?a=b#hash)
+ */
+ testability.getLocation = function() {
+ return $location.url();
+ };
+
+ /**
+ * @name $$testability#setLocation
+ *
+ * @description
+ * Shortcut for navigating to a location without doing a full page reload.
+ *
+ * @param {string} url The location url (path, search and hash,
+ * e.g. /path?a=b#hash) to go to.
+ */
+ testability.setLocation = function(url) {
+ if (url !== $location.url()) {
+ $location.url(url);
+ $rootScope.$digest();
+ }
};
+
+ /**
+ * @name $$testability#whenStable
+ *
+ * @description
+ * Calls the callback when $timeout and $http requests are completed.
+ *
+ * @param {function} callback
+ */
+ testability.whenStable = function(callback) {
+ $browser.notifyWhenNoOutstandingRequests(callback);
+ };
+
+ return testability;
}];
}
function $TimeoutProvider() {
- this.$get = ['$rootScope', '$browser', '$q', '$exceptionHandler',
- function($rootScope, $browser, $q, $exceptionHandler) {
+ this.$get = ['$rootScope', '$browser', '$q', '$$q', '$exceptionHandler',
+ function($rootScope, $browser, $q, $$q, $exceptionHandler) {
+
var deferreds = {};
@@ -14390,32 +17671,43 @@ function $TimeoutProvider() {
* block and delegates any exceptions to
* {@link ng.$exceptionHandler $exceptionHandler} service.
*
- * The return value of registering a timeout function is a promise, which will be resolved when
- * the timeout is reached and the timeout function is executed.
+ * The return value of calling `$timeout` is a promise, which will be resolved when
+ * the delay has passed and the timeout function, if provided, is executed.
*
* To cancel a timeout request, call `$timeout.cancel(promise)`.
*
* In tests you can use {@link ngMock.$timeout `$timeout.flush()`} to
* synchronously flush the queue of deferred functions.
*
- * @param {function()} fn A function, whose execution should be delayed.
+ * If you only want a promise that will be resolved after some specified delay
+ * then you can call `$timeout` without the `fn` function.
+ *
+ * @param {function()=} fn A function, whose execution should be delayed.
* @param {number=} [delay=0] Delay in milliseconds.
* @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
* will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
+ * @param {...*=} Pass additional parameters to the executed function.
* @returns {Promise} Promise that will be resolved when the timeout is reached. The value this
* promise will be resolved with is the return value of the `fn` function.
*
*/
function timeout(fn, delay, invokeApply) {
- var deferred = $q.defer(),
- promise = deferred.promise,
+ if (!isFunction(fn)) {
+ invokeApply = delay;
+ delay = fn;
+ fn = noop;
+ }
+
+ var args = sliceArgs(arguments, 3),
skipApply = (isDefined(invokeApply) && !invokeApply),
+ deferred = (skipApply ? $$q : $q).defer(),
+ promise = deferred.promise,
timeoutId;
timeoutId = $browser.defer(function() {
try {
- deferred.resolve(fn());
- } catch(e) {
+ deferred.resolve(fn.apply(null, args));
+ } catch (e) {
deferred.reject(e);
$exceptionHandler(e);
}
@@ -14466,7 +17758,7 @@ function $TimeoutProvider() {
// exactly the behavior needed here. There is little value is mocking these out for this
// service.
var urlParsingNode = document.createElement("a");
-var originUrl = urlResolve(window.location.href, true);
+var originUrl = urlResolve(window.location.href);
/**
@@ -14521,7 +17813,7 @@ var originUrl = urlResolve(window.location.href, true);
* | pathname | The pathname, beginning with "/"
*
*/
-function urlResolve(url, base) {
+function urlResolve(url) {
var href = url;
if (msie) {
@@ -14581,7 +17873,7 @@ function urlIsSameOrigin(requestUrl) {
<file name="index.html">
<script>
angular.module('windowExample', [])
- .controller('ExampleController', ['$scope', '$window', function ($scope, $window) {
+ .controller('ExampleController', ['$scope', '$window', function($scope, $window) {
$scope.greeting = 'Hello, World!';
$scope.doGreeting = function(greeting) {
$window.alert(greeting);
@@ -14589,7 +17881,7 @@ function urlIsSameOrigin(requestUrl) {
}]);
</script>
<div ng-controller="ExampleController">
- <input type="text" ng-model="greeting" />
+ <input type="text" ng-model="greeting" aria-label="greeting" />
<button ng-click="doGreeting(greeting)">ALERT</button>
</div>
</file>
@@ -14602,10 +17894,65 @@ function urlIsSameOrigin(requestUrl) {
</file>
</example>
*/
-function $WindowProvider(){
+function $WindowProvider() {
this.$get = valueFn(window);
}
+/**
+ * @name $$cookieReader
+ * @requires $document
+ *
+ * @description
+ * This is a private service for reading cookies used by $http and ngCookies
+ *
+ * @return {Object} a key/value map of the current cookies
+ */
+function $$CookieReader($document) {
+ var rawDocument = $document[0] || {};
+ var lastCookies = {};
+ var lastCookieString = '';
+
+ function safeDecodeURIComponent(str) {
+ try {
+ return decodeURIComponent(str);
+ } catch (e) {
+ return str;
+ }
+ }
+
+ return function() {
+ var cookieArray, cookie, i, index, name;
+ var currentCookieString = rawDocument.cookie || '';
+
+ if (currentCookieString !== lastCookieString) {
+ lastCookieString = currentCookieString;
+ cookieArray = lastCookieString.split('; ');
+ lastCookies = {};
+
+ for (i = 0; i < cookieArray.length; i++) {
+ cookie = cookieArray[i];
+ index = cookie.indexOf('=');
+ if (index > 0) { //ignore nameless cookies
+ name = safeDecodeURIComponent(cookie.substring(0, index));
+ // the first value that is seen for a cookie is the most
+ // specific one. values for the same cookie name that
+ // follow are for less specific paths.
+ if (lastCookies[name] === undefined) {
+ lastCookies[name] = safeDecodeURIComponent(cookie.substring(index + 1));
+ }
+ }
+ }
+ }
+ return lastCookies;
+ };
+}
+
+$$CookieReader.$inject = ['$document'];
+
+function $$CookieReaderProvider() {
+ this.$get = $$CookieReader;
+}
+
/* global currencyFilter: true,
dateFilter: true,
filterFilter: true,
@@ -14626,6 +17973,13 @@ function $WindowProvider(){
* Dependency Injected. To achieve this a filter definition consists of a factory function which is
* annotated with dependencies and is responsible for creating a filter function.
*
+ * <div class="alert alert-warning">
+ * **Note:** Filter names must be valid angular {@link expression} identifiers, such as `uppercase` or `orderBy`.
+ * Names with special characters, such as hyphens and dots, are not allowed. If you wish to namespace
+ * your filters, then you can use capitalization (`myappSubsectionFilterx`) or underscores
+ * (`myapp_subsection_filterx`).
+ * </div>
+ *
* ```js
* // Filter registration
* function MyModule($provide, $filterProvider) {
@@ -14707,11 +18061,18 @@ function $FilterProvider($provide) {
* @name $filterProvider#register
* @param {string|Object} name Name of the filter function, or an object map of filters where
* the keys are the filter names and the values are the filter factories.
+ *
+ * <div class="alert alert-warning">
+ * **Note:** Filter names must be valid angular {@link expression} identifiers, such as `uppercase` or `orderBy`.
+ * Names with special characters, such as hyphens and dots, are not allowed. If you wish to namespace
+ * your filters, then you can use capitalization (`myappSubsectionFilterx`) or underscores
+ * (`myapp_subsection_filterx`).
+ * </div>
* @returns {Object} Registered filter instance, or if a map of filters was provided then a map
* of the registered filter instances.
*/
function register(name, factory) {
- if(isObject(name)) {
+ if (isObject(name)) {
var filters = {};
forEach(name, function(filter, key) {
filters[key] = register(key, filter);
@@ -14768,22 +18129,31 @@ function $FilterProvider($provide) {
*
* Can be one of:
*
- * - `string`: The string is evaluated as an expression and the resulting value is used for substring match against
- * the contents of the `array`. All strings or objects with string properties in `array` that contain this string
- * will be returned. The predicate can be negated by prefixing the string with `!`.
+ * - `string`: The string is used for matching against the contents of the `array`. All strings or
+ * objects with string properties in `array` that match this string will be returned. This also
+ * applies to nested object properties.
+ * The predicate can be negated by prefixing the string with `!`.
*
* - `Object`: A pattern object can be used to filter specific properties on objects contained
* by `array`. For example `{name:"M", phone:"1"}` predicate will return an array of items
* which have property `name` containing "M" and property `phone` containing "1". A special
* property name `$` can be used (as in `{$:"text"}`) to accept a match against any
- * property of the object. That's equivalent to the simple substring match with a `string`
- * as described above. The predicate can be negated by prefixing the string with `!`.
- * For Example `{name: "!M"}` predicate will return an array of items which have property `name`
+ * property of the object or its nested object properties. That's equivalent to the simple
+ * substring match with a `string` as described above. The predicate can be negated by prefixing
+ * the string with `!`.
+ * For example `{name: "!M"}` predicate will return an array of items which have property `name`
* not containing "M".
*
- * - `function(value)`: A predicate function can be used to write arbitrary filters. The function is
- * called for each element of `array`. The final result is an array of those elements that
- * the predicate returned true for.
+ * Note that a named property will match properties on the same level only, while the special
+ * `$` property will match properties on the same level or deeper. E.g. an array item like
+ * `{name: {first: 'John', last: 'Doe'}}` will **not** be matched by `{name: 'John'}`, but
+ * **will** be matched by `{$: 'John'}`.
+ *
+ * - `function(value, index, array)`: A predicate function can be used to write arbitrary filters.
+ * The function is called for each element of the array, with the element, its index, and
+ * the entire array itself as arguments.
+ *
+ * The final result is an array of those elements that the predicate returned true for.
*
* @param {function(actual, expected)|true|undefined} comparator Comparator which is used in
* determining if the expected value (from the filter expression) and actual value (from
@@ -14793,14 +18163,17 @@ function $FilterProvider($provide) {
*
* - `function(actual, expected)`:
* The function will be given the object value and the predicate value to compare and
- * should return true if the item should be included in filtered result.
+ * should return true if both values should be considered equal.
*
- * - `true`: A shorthand for `function(actual, expected) { return angular.equals(expected, actual)}`.
- * this is essentially strict comparison of expected and actual.
+ * - `true`: A shorthand for `function(actual, expected) { return angular.equals(actual, expected)}`.
+ * This is essentially strict comparison of expected and actual.
*
* - `false|undefined`: A short hand for a function which will look for a substring match in case
* insensitive way.
*
+ * Primitive values are converted to strings. Objects are not compared against primitives,
+ * unless they have a custom `toString` method (e.g. `Date` objects).
+ *
* @example
<example>
<file name="index.html">
@@ -14811,7 +18184,7 @@ function $FilterProvider($provide) {
{name:'Julie', phone:'555-8765'},
{name:'Juliette', phone:'555-5678'}]"></div>
- Search: <input ng-model="searchText">
+ <label>Search: <input ng-model="searchText"></label>
<table id="searchTextResults">
<tr><th>Name</th><th>Phone</th></tr>
<tr ng-repeat="friend in friends | filter:searchText">
@@ -14820,10 +18193,10 @@ function $FilterProvider($provide) {
</tr>
</table>
<hr>
- Any: <input ng-model="search.$"> <br>
- Name only <input ng-model="search.name"><br>
- Phone only <input ng-model="search.phone"><br>
- Equality <input type="checkbox" ng-model="strict"><br>
+ <label>Any: <input ng-model="search.$"></label> <br>
+ <label>Name only <input ng-model="search.name"></label><br>
+ <label>Phone only <input ng-model="search.phone"></label><br>
+ <label>Equality <input type="checkbox" ng-model="strict"></label><br>
<table id="searchObjResults">
<tr><th>Name</th><th>Phone</th></tr>
<tr ng-repeat="friendObj in friends | filter:search:strict">
@@ -14871,108 +18244,130 @@ function $FilterProvider($provide) {
*/
function filterFilter() {
return function(array, expression, comparator) {
- if (!isArray(array)) return array;
-
- var comparatorType = typeof(comparator),
- predicates = [];
-
- predicates.check = function(value) {
- for (var j = 0; j < predicates.length; j++) {
- if(!predicates[j](value)) {
- return false;
- }
- }
- return true;
- };
-
- if (comparatorType !== 'function') {
- if (comparatorType === 'boolean' && comparator) {
- comparator = function(obj, text) {
- return angular.equals(obj, text);
- };
+ if (!isArrayLike(array)) {
+ if (array == null) {
+ return array;
} else {
- comparator = function(obj, text) {
- if (obj && text && typeof obj === 'object' && typeof text === 'object') {
- for (var objKey in obj) {
- if (objKey.charAt(0) !== '$' && hasOwnProperty.call(obj, objKey) &&
- comparator(obj[objKey], text[objKey])) {
- return true;
- }
- }
- return false;
- }
- text = (''+text).toLowerCase();
- return (''+obj).toLowerCase().indexOf(text) > -1;
- };
+ throw minErr('filter')('notarray', 'Expected array but received: {0}', array);
}
}
- var search = function(obj, text){
- if (typeof text === 'string' && text.charAt(0) === '!') {
- return !search(obj, text.substr(1));
- }
- switch (typeof obj) {
- case 'boolean':
- case 'number':
- case 'string':
- return comparator(obj, text);
- case 'object':
- switch (typeof text) {
- case 'object':
- return comparator(obj, text);
- default:
- for ( var objKey in obj) {
- if (objKey.charAt(0) !== '$' && search(obj[objKey], text)) {
- return true;
- }
- }
- break;
- }
- return false;
- case 'array':
- for ( var i = 0; i < obj.length; i++) {
- if (search(obj[i], text)) {
- return true;
- }
- }
- return false;
- default:
- return false;
- }
- };
- switch (typeof expression) {
+ var expressionType = getTypeForFilter(expression);
+ var predicateFn;
+ var matchAgainstAnyProp;
+
+ switch (expressionType) {
+ case 'function':
+ predicateFn = expression;
+ break;
case 'boolean':
+ case 'null':
case 'number':
case 'string':
- // Set up expression object and fall through
- expression = {$:expression};
- // jshint -W086
+ matchAgainstAnyProp = true;
+ //jshint -W086
case 'object':
- // jshint +W086
- for (var key in expression) {
- (function(path) {
- if (typeof expression[path] === 'undefined') return;
- predicates.push(function(value) {
- return search(path == '$' ? value : (value && value[path]), expression[path]);
- });
- })(key);
- }
- break;
- case 'function':
- predicates.push(expression);
+ //jshint +W086
+ predicateFn = createPredicateFn(expression, comparator, matchAgainstAnyProp);
break;
default:
return array;
}
- var filtered = [];
- for ( var j = 0; j < array.length; j++) {
- var value = array[j];
- if (predicates.check(value)) {
- filtered.push(value);
+
+ return Array.prototype.filter.call(array, predicateFn);
+ };
+}
+
+// Helper functions for `filterFilter`
+function createPredicateFn(expression, comparator, matchAgainstAnyProp) {
+ var shouldMatchPrimitives = isObject(expression) && ('$' in expression);
+ var predicateFn;
+
+ if (comparator === true) {
+ comparator = equals;
+ } else if (!isFunction(comparator)) {
+ comparator = function(actual, expected) {
+ if (isUndefined(actual)) {
+ // No substring matching against `undefined`
+ return false;
+ }
+ if ((actual === null) || (expected === null)) {
+ // No substring matching against `null`; only match against `null`
+ return actual === expected;
}
+ if (isObject(expected) || (isObject(actual) && !hasCustomToString(actual))) {
+ // Should not compare primitives against objects, unless they have custom `toString` method
+ return false;
+ }
+
+ actual = lowercase('' + actual);
+ expected = lowercase('' + expected);
+ return actual.indexOf(expected) !== -1;
+ };
+ }
+
+ predicateFn = function(item) {
+ if (shouldMatchPrimitives && !isObject(item)) {
+ return deepCompare(item, expression.$, comparator, false);
}
- return filtered;
+ return deepCompare(item, expression, comparator, matchAgainstAnyProp);
};
+
+ return predicateFn;
+}
+
+function deepCompare(actual, expected, comparator, matchAgainstAnyProp, dontMatchWholeObject) {
+ var actualType = getTypeForFilter(actual);
+ var expectedType = getTypeForFilter(expected);
+
+ if ((expectedType === 'string') && (expected.charAt(0) === '!')) {
+ return !deepCompare(actual, expected.substring(1), comparator, matchAgainstAnyProp);
+ } else if (isArray(actual)) {
+ // In case `actual` is an array, consider it a match
+ // if ANY of it's items matches `expected`
+ return actual.some(function(item) {
+ return deepCompare(item, expected, comparator, matchAgainstAnyProp);
+ });
+ }
+
+ switch (actualType) {
+ case 'object':
+ var key;
+ if (matchAgainstAnyProp) {
+ for (key in actual) {
+ if ((key.charAt(0) !== '$') && deepCompare(actual[key], expected, comparator, true)) {
+ return true;
+ }
+ }
+ return dontMatchWholeObject ? false : deepCompare(actual, expected, comparator, false);
+ } else if (expectedType === 'object') {
+ for (key in expected) {
+ var expectedVal = expected[key];
+ if (isFunction(expectedVal) || isUndefined(expectedVal)) {
+ continue;
+ }
+
+ var matchAnyProperty = key === '$';
+ var actualVal = matchAnyProperty ? actual : actual[key];
+ if (!deepCompare(actualVal, expectedVal, comparator, matchAnyProperty, matchAnyProperty)) {
+ return false;
+ }
+ }
+ return true;
+ } else {
+ return comparator(actual, expected);
+ }
+ break;
+ case 'function':
+ return false;
+ default:
+ return comparator(actual, expected);
+ }
+}
+
+// Used for easily differentiating between `null` and actual `object`
+function getTypeForFilter(val) {
+ return (val === null) ? 'null' : typeof val;
}
/**
@@ -14986,6 +18381,7 @@ function filterFilter() {
*
* @param {number} amount Input to filter.
* @param {string=} symbol Currency symbol or identifier to be displayed.
+ * @param {number=} fractionSize Number of decimal places to round the amount to, defaults to default max fraction size for current locale
* @returns {string} Formatted number.
*
*
@@ -14999,15 +18395,17 @@ function filterFilter() {
}]);
</script>
<div ng-controller="ExampleController">
- <input type="number" ng-model="amount"> <br>
+ <input type="number" ng-model="amount" aria-label="amount"> <br>
default currency symbol ($): <span id="currency-default">{{amount | currency}}</span><br>
- custom currency identifier (USD$): <span>{{amount | currency:"USD$"}}</span>
+ custom currency identifier (USD$): <span id="currency-custom">{{amount | currency:"USD$"}}</span>
+ no fractions (0): <span id="currency-no-fractions">{{amount | currency:"USD$":0}}</span>
</div>
</file>
<file name="protractor.js" type="protractor">
it('should init with 1234.56', function() {
expect(element(by.id('currency-default')).getText()).toBe('$1,234.56');
- expect(element(by.binding('amount | currency:"USD$"')).getText()).toBe('USD$1,234.56');
+ expect(element(by.id('currency-custom')).getText()).toBe('USD$1,234.56');
+ expect(element(by.id('currency-no-fractions')).getText()).toBe('USD$1,235');
});
it('should update', function() {
if (browser.params.browser == 'safari') {
@@ -15018,7 +18416,8 @@ function filterFilter() {
element(by.model('amount')).clear();
element(by.model('amount')).sendKeys('-1234');
expect(element(by.id('currency-default')).getText()).toBe('($1,234.00)');
- expect(element(by.binding('amount | currency:"USD$"')).getText()).toBe('(USD$1,234.00)');
+ expect(element(by.id('currency-custom')).getText()).toBe('(USD$1,234.00)');
+ expect(element(by.id('currency-no-fractions')).getText()).toBe('(USD$1,234)');
});
</file>
</example>
@@ -15026,10 +18425,20 @@ function filterFilter() {
currencyFilter.$inject = ['$locale'];
function currencyFilter($locale) {
var formats = $locale.NUMBER_FORMATS;
- return function(amount, currencySymbol){
- if (isUndefined(currencySymbol)) currencySymbol = formats.CURRENCY_SYM;
- return formatNumber(amount, formats.PATTERNS[1], formats.GROUP_SEP, formats.DECIMAL_SEP, 2).
- replace(/\u00A4/g, currencySymbol);
+ return function(amount, currencySymbol, fractionSize) {
+ if (isUndefined(currencySymbol)) {
+ currencySymbol = formats.CURRENCY_SYM;
+ }
+
+ if (isUndefined(fractionSize)) {
+ fractionSize = formats.PATTERNS[1].maxFrac;
+ }
+
+ // if null or undefined pass it through
+ return (amount == null)
+ ? amount
+ : formatNumber(amount, formats.PATTERNS[1], formats.GROUP_SEP, formats.DECIMAL_SEP, fractionSize).
+ replace(/\u00A4/g, currencySymbol);
};
}
@@ -15041,8 +18450,11 @@ function currencyFilter($locale) {
* @description
* Formats a number as text.
*
+ * If the input is null or undefined, it will just be returned.
+ * If the input is infinite (Infinity/-Infinity) the Infinity symbol '∞' is returned.
* If the input is not a number an empty string is returned.
*
+ *
* @param {number|string} number Number to format.
* @param {(number|string)=} fractionSize Number of decimal places to round the number to.
* If this is not provided then the fraction size is computed from the current locale's number
@@ -15059,7 +18471,7 @@ function currencyFilter($locale) {
}]);
</script>
<div ng-controller="ExampleController">
- Enter number: <input ng-model='val'><br>
+ <label>Enter number: <input ng-model='val'></label><br>
Default formatting: <span id='number-default'>{{val | number}}</span><br>
No fractions: <span>{{val | number:0}}</span><br>
Negative number: <span>{{-val | number:4}}</span>
@@ -15088,26 +18500,35 @@ numberFilter.$inject = ['$locale'];
function numberFilter($locale) {
var formats = $locale.NUMBER_FORMATS;
return function(number, fractionSize) {
- return formatNumber(number, formats.PATTERNS[0], formats.GROUP_SEP, formats.DECIMAL_SEP,
- fractionSize);
+
+ // if null or undefined pass it through
+ return (number == null)
+ ? number
+ : formatNumber(number, formats.PATTERNS[0], formats.GROUP_SEP, formats.DECIMAL_SEP,
+ fractionSize);
};
}
var DECIMAL_SEP = '.';
function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
- if (number == null || !isFinite(number) || isObject(number)) return '';
+ if (isObject(number)) return '';
var isNegative = number < 0;
number = Math.abs(number);
+
+ var isInfinity = number === Infinity;
+ if (!isInfinity && !isFinite(number)) return '';
+
var numStr = number + '',
formatedText = '',
+ hasExponent = false,
parts = [];
- var hasExponent = false;
- if (numStr.indexOf('e') !== -1) {
+ if (isInfinity) formatedText = '\u221e';
+
+ if (!isInfinity && numStr.indexOf('e') !== -1) {
var match = numStr.match(/([\d\.]+)e(-?)(\d+)/);
if (match && match[2] == '-' && match[3] > fractionSize + 1) {
- numStr = '0';
number = 0;
} else {
formatedText = numStr;
@@ -15115,7 +18536,7 @@ function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
}
}
- if (!hasExponent) {
+ if (!isInfinity && !hasExponent) {
var fractionLen = (numStr.split(DECIMAL_SEP)[1] || '').length;
// determine fractionSize if it is not specified
@@ -15128,10 +18549,6 @@ function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round
number = +(Math.round(+(number.toString() + 'e' + fractionSize)).toString() + 'e' + -fractionSize);
- if (number === 0) {
- isNegative = false;
- }
-
var fraction = ('' + number).split(DECIMAL_SEP);
var whole = fraction[0];
fraction = fraction[1] || '';
@@ -15143,7 +18560,7 @@ function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
if (whole.length >= (lgroup + group)) {
pos = whole.length - lgroup;
for (i = 0; i < pos; i++) {
- if ((pos - i)%group === 0 && i !== 0) {
+ if ((pos - i) % group === 0 && i !== 0) {
formatedText += groupSep;
}
formatedText += whole.charAt(i);
@@ -15151,28 +18568,32 @@ function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
}
for (i = pos; i < whole.length; i++) {
- if ((whole.length - i)%lgroup === 0 && i !== 0) {
+ if ((whole.length - i) % lgroup === 0 && i !== 0) {
formatedText += groupSep;
}
formatedText += whole.charAt(i);
}
// format fraction part.
- while(fraction.length < fractionSize) {
+ while (fraction.length < fractionSize) {
fraction += '0';
}
if (fractionSize && fractionSize !== "0") formatedText += decimalSep + fraction.substr(0, fractionSize);
} else {
-
- if (fractionSize > 0 && number > -1 && number < 1) {
+ if (fractionSize > 0 && number < 1) {
formatedText = number.toFixed(fractionSize);
+ number = parseFloat(formatedText);
}
}
- parts.push(isNegative ? pattern.negPre : pattern.posPre);
- parts.push(formatedText);
- parts.push(isNegative ? pattern.negSuf : pattern.posSuf);
+ if (number === 0) {
+ isNegative = false;
+ }
+
+ parts.push(isNegative ? pattern.negPre : pattern.posPre,
+ formatedText,
+ isNegative ? pattern.negSuf : pattern.posSuf);
return parts.join('');
}
@@ -15183,9 +18604,10 @@ function padNumber(num, digits, trim) {
num = -num;
}
num = '' + num;
- while(num.length < digits) num = '0' + num;
- if (trim)
+ while (num.length < digits) num = '0' + num;
+ if (trim) {
num = num.substr(num.length - digits);
+ }
return neg + num;
}
@@ -15194,9 +18616,10 @@ function dateGetter(name, size, offset, trim) {
offset = offset || 0;
return function(date) {
var value = date['get' + name]();
- if (offset > 0 || value > -offset)
+ if (offset > 0 || value > -offset) {
value += offset;
- if (value === 0 && offset == -12 ) value = 12;
+ }
+ if (value === 0 && offset == -12) value = 12;
return padNumber(value, size, trim);
};
}
@@ -15210,8 +18633,8 @@ function dateStrGetter(name, shortForm) {
};
}
-function timeZoneGetter(date) {
- var zone = -1 * date.getTimezoneOffset();
+function timeZoneGetter(date, formats, offset) {
+ var zone = -1 * offset;
var paddedZone = (zone >= 0) ? "+" : "";
paddedZone += padNumber(Math[zone > 0 ? 'floor' : 'ceil'](zone / 60), 2) +
@@ -15220,10 +18643,44 @@ function timeZoneGetter(date) {
return paddedZone;
}
+function getFirstThursdayOfYear(year) {
+ // 0 = index of January
+ var dayOfWeekOnFirst = (new Date(year, 0, 1)).getDay();
+ // 4 = index of Thursday (+1 to account for 1st = 5)
+ // 11 = index of *next* Thursday (+1 account for 1st = 12)
+ return new Date(year, 0, ((dayOfWeekOnFirst <= 4) ? 5 : 12) - dayOfWeekOnFirst);
+}
+
+function getThursdayThisWeek(datetime) {
+ return new Date(datetime.getFullYear(), datetime.getMonth(),
+ // 4 = index of Thursday
+ datetime.getDate() + (4 - datetime.getDay()));
+}
+
+function weekGetter(size) {
+ return function(date) {
+ var firstThurs = getFirstThursdayOfYear(date.getFullYear()),
+ thisThurs = getThursdayThisWeek(date);
+
+ var diff = +thisThurs - +firstThurs,
+ result = 1 + Math.round(diff / 6.048e8); // 6.048e8 ms per week
+
+ return padNumber(result, size);
+ };
+}
+
function ampmGetter(date, formats) {
return date.getHours() < 12 ? formats.AMPMS[0] : formats.AMPMS[1];
}
+function eraGetter(date, formats) {
+ return date.getFullYear() <= 0 ? formats.ERAS[0] : formats.ERAS[1];
+}
+
+function longEraGetter(date, formats) {
+ return date.getFullYear() <= 0 ? formats.ERANAMES[0] : formats.ERANAMES[1];
+}
+
var DATE_FORMATS = {
yyyy: dateGetter('FullYear', 4),
yy: dateGetter('FullYear', 2, 0, true),
@@ -15248,10 +18705,16 @@ var DATE_FORMATS = {
EEEE: dateStrGetter('Day'),
EEE: dateStrGetter('Day', true),
a: ampmGetter,
- Z: timeZoneGetter
+ Z: timeZoneGetter,
+ ww: weekGetter(2),
+ w: weekGetter(1),
+ G: eraGetter,
+ GG: eraGetter,
+ GGG: eraGetter,
+ GGGG: longEraGetter
};
-var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+|H+|h+|m+|s+|a|Z))(.*)/,
+var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZEwG']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+|H+|h+|m+|s+|a|Z|G+|w+))(.*)/,
NUMBER_STRING = /^\-?\d+$/;
/**
@@ -15277,29 +18740,33 @@ var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+
* * `'EEE'`: Day in Week, (Sun-Sat)
* * `'HH'`: Hour in day, padded (00-23)
* * `'H'`: Hour in day (0-23)
- * * `'hh'`: Hour in am/pm, padded (01-12)
- * * `'h'`: Hour in am/pm, (1-12)
+ * * `'hh'`: Hour in AM/PM, padded (01-12)
+ * * `'h'`: Hour in AM/PM, (1-12)
* * `'mm'`: Minute in hour, padded (00-59)
* * `'m'`: Minute in hour (0-59)
* * `'ss'`: Second in minute, padded (00-59)
* * `'s'`: Second in minute (0-59)
- * * `'.sss' or ',sss'`: Millisecond in second, padded (000-999)
- * * `'a'`: am/pm marker
+ * * `'sss'`: Millisecond in second, padded (000-999)
+ * * `'a'`: AM/PM marker
* * `'Z'`: 4 digit (+sign) representation of the timezone offset (-1200-+1200)
+ * * `'ww'`: Week of year, padded (00-53). Week 01 is the week with the first Thursday of the year
+ * * `'w'`: Week of year (0-53). Week 1 is the week with the first Thursday of the year
+ * * `'G'`, `'GG'`, `'GGG'`: The abbreviated form of the era string (e.g. 'AD')
+ * * `'GGGG'`: The long form of the era string (e.g. 'Anno Domini')
*
* `format` string can also be one of the following predefined
* {@link guide/i18n localizable formats}:
*
* * `'medium'`: equivalent to `'MMM d, y h:mm:ss a'` for en_US locale
- * (e.g. Sep 3, 2010 12:05:08 pm)
- * * `'short'`: equivalent to `'M/d/yy h:mm a'` for en_US locale (e.g. 9/3/10 12:05 pm)
- * * `'fullDate'`: equivalent to `'EEEE, MMMM d,y'` for en_US locale
+ * (e.g. Sep 3, 2010 12:05:08 PM)
+ * * `'short'`: equivalent to `'M/d/yy h:mm a'` for en_US locale (e.g. 9/3/10 12:05 PM)
+ * * `'fullDate'`: equivalent to `'EEEE, MMMM d, y'` for en_US locale
* (e.g. Friday, September 3, 2010)
* * `'longDate'`: equivalent to `'MMMM d, y'` for en_US locale (e.g. September 3, 2010)
* * `'mediumDate'`: equivalent to `'MMM d, y'` for en_US locale (e.g. Sep 3, 2010)
* * `'shortDate'`: equivalent to `'M/d/yy'` for en_US locale (e.g. 9/3/10)
- * * `'mediumTime'`: equivalent to `'h:mm:ss a'` for en_US locale (e.g. 12:05:08 pm)
- * * `'shortTime'`: equivalent to `'h:mm a'` for en_US locale (e.g. 12:05 pm)
+ * * `'mediumTime'`: equivalent to `'h:mm:ss a'` for en_US locale (e.g. 12:05:08 PM)
+ * * `'shortTime'`: equivalent to `'h:mm a'` for en_US locale (e.g. 12:05 PM)
*
* `format` string can contain literal values. These need to be escaped by surrounding with single quotes (e.g.
* `"h 'in the morning'"`). In order to output a single quote, escape it - i.e., two single quotes in a sequence
@@ -15311,6 +18778,10 @@ var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+
* specified in the string input, the time is considered to be in the local timezone.
* @param {string=} format Formatting rules (see Description). If not specified,
* `mediumDate` is used.
+ * @param {string=} timezone Timezone to be used for formatting. It understands UTC/GMT and the
+ * continental US time zone abbreviations, but for general use, use a time zone offset, for
+ * example, `'+0430'` (4 hours, 30 minutes east of the Greenwich meridian)
+ * If not specified, the timezone of the browser will be used.
* @returns {string} Formatted string or the input if input is not recognized as date/millis.
*
* @example
@@ -15355,14 +18826,14 @@ function dateFilter($locale) {
timeSetter = match[8] ? date.setUTCHours : date.setHours;
if (match[9]) {
- tzHour = int(match[9] + match[10]);
- tzMin = int(match[9] + match[11]);
- }
- dateSetter.call(date, int(match[1]), int(match[2]) - 1, int(match[3]));
- var h = int(match[4]||0) - tzHour;
- var m = int(match[5]||0) - tzMin;
- var s = int(match[6]||0);
- var ms = Math.round(parseFloat('0.' + (match[7]||0)) * 1000);
+ tzHour = toInt(match[9] + match[10]);
+ tzMin = toInt(match[9] + match[11]);
+ }
+ dateSetter.call(date, toInt(match[1]), toInt(match[2]) - 1, toInt(match[3]));
+ var h = toInt(match[4] || 0) - tzHour;
+ var m = toInt(match[5] || 0) - tzMin;
+ var s = toInt(match[6] || 0);
+ var ms = Math.round(parseFloat('0.' + (match[7] || 0)) * 1000);
timeSetter.call(date, h, m, s, ms);
return date;
}
@@ -15370,7 +18841,7 @@ function dateFilter($locale) {
}
- return function(date, format) {
+ return function(date, format, timezone) {
var text = '',
parts = [],
fn, match;
@@ -15378,18 +18849,18 @@ function dateFilter($locale) {
format = format || 'mediumDate';
format = $locale.DATETIME_FORMATS[format] || format;
if (isString(date)) {
- date = NUMBER_STRING.test(date) ? int(date) : jsonStringToDate(date);
+ date = NUMBER_STRING.test(date) ? toInt(date) : jsonStringToDate(date);
}
if (isNumber(date)) {
date = new Date(date);
}
- if (!isDate(date)) {
+ if (!isDate(date) || !isFinite(date.getTime())) {
return date;
}
- while(format) {
+ while (format) {
match = DATE_FORMATS_SPLIT.exec(format);
if (match) {
parts = concat(parts, match, 1);
@@ -15400,9 +18871,14 @@ function dateFilter($locale) {
}
}
- forEach(parts, function(value){
+ var dateTimezoneOffset = date.getTimezoneOffset();
+ if (timezone) {
+ dateTimezoneOffset = timezoneToOffset(timezone, date.getTimezoneOffset());
+ date = convertTimezoneToLocal(date, timezone, true);
+ }
+ forEach(parts, function(value) {
fn = DATE_FORMATS[value];
- text += fn ? fn(date, $locale.DATETIME_FORMATS)
+ text += fn ? fn(date, $locale.DATETIME_FORMATS, dateTimezoneOffset)
: value.replace(/(^'|'$)/g, '').replace(/''/g, "'");
});
@@ -15423,25 +18899,31 @@ function dateFilter($locale) {
* the binding is automatically converted to JSON.
*
* @param {*} object Any JavaScript object (including arrays and primitive types) to filter.
+ * @param {number=} spacing The number of spaces to use per indentation, defaults to 2.
* @returns {string} JSON string.
*
*
* @example
<example>
<file name="index.html">
- <pre>{{ {'name':'value'} | json }}</pre>
+ <pre id="default-spacing">{{ {'name':'value'} | json }}</pre>
+ <pre id="custom-spacing">{{ {'name':'value'} | json:4 }}</pre>
</file>
<file name="protractor.js" type="protractor">
it('should jsonify filtered objects', function() {
- expect(element(by.binding("{'name':'value'}")).getText()).toMatch(/\{\n "name": ?"value"\n}/);
+ expect(element(by.id('default-spacing')).getText()).toMatch(/\{\n "name": ?"value"\n}/);
+ expect(element(by.id('custom-spacing')).getText()).toMatch(/\{\n "name": ?"value"\n}/);
});
</file>
</example>
*
*/
function jsonFilter() {
- return function(object) {
- return toJson(object, true);
+ return function(object, spacing) {
+ if (isUndefined(spacing)) {
+ spacing = 2;
+ }
+ return toJson(object, spacing);
};
}
@@ -15474,14 +18956,18 @@ var uppercaseFilter = valueFn(uppercase);
*
* @description
* Creates a new array or string containing only a specified number of elements. The elements
- * are taken from either the beginning or the end of the source array or string, as specified by
- * the value and sign (positive or negative) of `limit`.
+ * are taken from either the beginning or the end of the source array, string or number, as specified by
+ * the value and sign (positive or negative) of `limit`. If a number is used as input, it is
+ * converted to a string.
*
- * @param {Array|string} input Source array or string to be limited.
+ * @param {Array|string|number} input Source array, string or number to be limited.
* @param {string|number} limit The length of the returned array or string. If the `limit` number
* is positive, `limit` number of items from the beginning of the source array/string are copied.
* If the number is negative, `limit` number of items from the end of the source array/string
- * are copied. The `limit` will be trimmed if it exceeds `array.length`
+ * are copied. The `limit` will be trimmed if it exceeds `array.length`. If `limit` is undefined,
+ * the input will be returned unchanged.
+ * @param {(string|number)=} begin Index at which to begin limitation. As a negative index, `begin`
+ * indicates an offset from the end of `input`. Defaults to `0`.
* @returns {Array|string} A new sub-array or substring of length `limit` or less if input array
* had less than `limit` elements.
*
@@ -15493,28 +18979,45 @@ var uppercaseFilter = valueFn(uppercase);
.controller('ExampleController', ['$scope', function($scope) {
$scope.numbers = [1,2,3,4,5,6,7,8,9];
$scope.letters = "abcdefghi";
+ $scope.longNumber = 2345432342;
$scope.numLimit = 3;
$scope.letterLimit = 3;
+ $scope.longNumberLimit = 3;
}]);
</script>
<div ng-controller="ExampleController">
- Limit {{numbers}} to: <input type="number" step="1" ng-model="numLimit">
+ <label>
+ Limit {{numbers}} to:
+ <input type="number" step="1" ng-model="numLimit">
+ </label>
<p>Output numbers: {{ numbers | limitTo:numLimit }}</p>
- Limit {{letters}} to: <input type="number" step="1" ng-model="letterLimit">
+ <label>
+ Limit {{letters}} to:
+ <input type="number" step="1" ng-model="letterLimit">
+ </label>
<p>Output letters: {{ letters | limitTo:letterLimit }}</p>
+ <label>
+ Limit {{longNumber}} to:
+ <input type="number" step="1" ng-model="longNumberLimit">
+ </label>
+ <p>Output long number: {{ longNumber | limitTo:longNumberLimit }}</p>
</div>
</file>
<file name="protractor.js" type="protractor">
var numLimitInput = element(by.model('numLimit'));
var letterLimitInput = element(by.model('letterLimit'));
+ var longNumberLimitInput = element(by.model('longNumberLimit'));
var limitedNumbers = element(by.binding('numbers | limitTo:numLimit'));
var limitedLetters = element(by.binding('letters | limitTo:letterLimit'));
+ var limitedLongNumber = element(by.binding('longNumber | limitTo:longNumberLimit'));
it('should limit the number array to first three items', function() {
expect(numLimitInput.getAttribute('value')).toBe('3');
expect(letterLimitInput.getAttribute('value')).toBe('3');
+ expect(longNumberLimitInput.getAttribute('value')).toBe('3');
expect(limitedNumbers.getText()).toEqual('Output numbers: [1,2,3]');
expect(limitedLetters.getText()).toEqual('Output letters: abc');
+ expect(limitedLongNumber.getText()).toEqual('Output long number: 234');
});
// There is a bug in safari and protractor that doesn't like the minus key
@@ -15523,8 +19026,11 @@ var uppercaseFilter = valueFn(uppercase);
// numLimitInput.sendKeys('-3');
// letterLimitInput.clear();
// letterLimitInput.sendKeys('-3');
+ // longNumberLimitInput.clear();
+ // longNumberLimitInput.sendKeys('-3');
// expect(limitedNumbers.getText()).toEqual('Output numbers: [7,8,9]');
// expect(limitedLetters.getText()).toEqual('Output letters: ghi');
+ // expect(limitedLongNumber.getText()).toEqual('Output long number: 342');
// });
it('should not exceed the maximum size of input array', function() {
@@ -15532,53 +19038,39 @@ var uppercaseFilter = valueFn(uppercase);
numLimitInput.sendKeys('100');
letterLimitInput.clear();
letterLimitInput.sendKeys('100');
+ longNumberLimitInput.clear();
+ longNumberLimitInput.sendKeys('100');
expect(limitedNumbers.getText()).toEqual('Output numbers: [1,2,3,4,5,6,7,8,9]');
expect(limitedLetters.getText()).toEqual('Output letters: abcdefghi');
+ expect(limitedLongNumber.getText()).toEqual('Output long number: 2345432342');
});
</file>
</example>
- */
-function limitToFilter(){
- return function(input, limit) {
- if (!isArray(input) && !isString(input)) return input;
-
+*/
+function limitToFilter() {
+ return function(input, limit, begin) {
if (Math.abs(Number(limit)) === Infinity) {
limit = Number(limit);
} else {
- limit = int(limit);
- }
-
- if (isString(input)) {
- //NaN check on limit
- if (limit) {
- return limit >= 0 ? input.slice(0, limit) : input.slice(limit, input.length);
- } else {
- return "";
- }
+ limit = toInt(limit);
}
+ if (isNaN(limit)) return input;
- var out = [],
- i, n;
+ if (isNumber(input)) input = input.toString();
+ if (!isArray(input) && !isString(input)) return input;
- // if abs(limit) exceeds maximum length, trim it
- if (limit > input.length)
- limit = input.length;
- else if (limit < -input.length)
- limit = -input.length;
+ begin = (!begin || isNaN(begin)) ? 0 : toInt(begin);
+ begin = (begin < 0 && begin >= -input.length) ? input.length + begin : begin;
- if (limit > 0) {
- i = 0;
- n = limit;
+ if (limit >= 0) {
+ return input.slice(begin, begin + limit);
} else {
- i = input.length + limit;
- n = input.length;
- }
-
- for (; i<n; i++) {
- out.push(input[i]);
+ if (begin === 0) {
+ return input.slice(limit, input.length);
+ } else {
+ return input.slice(Math.max(0, begin + limit), begin);
+ }
}
-
- return out;
};
}
@@ -15590,7 +19082,7 @@ function limitToFilter(){
* @description
* Orders a specified `array` by the `expression` predicate. It is ordered alphabetically
* for strings and numerically for numbers. Note: if you notice numbers are not being sorted
- * correctly, make sure they are actually being saved as numbers and not strings.
+ * as expected, make sure they are actually being saved as numbers and not strings.
*
* @param {Array} array The array to sort.
* @param {function(*)|string|Array.<(function(*)|string)>=} expression A predicate to be
@@ -15599,7 +19091,7 @@ function limitToFilter(){
* Can be one of:
*
* - `function`: Getter function. The result of this function will be sorted using the
- * `<`, `=`, `>` operator.
+ * `<`, `===`, `>` operator.
* - `string`: An Angular expression. The result of this expression is used to compare elements
* (for example `name` to sort by a property called `name` or `name.substr(0, 3)` to sort by
* 3 first characters of a property called `name`). The result of a constant expression
@@ -15616,7 +19108,11 @@ function limitToFilter(){
* @param {boolean=} reverse Reverse the order of the array.
* @returns {Array} Sorted copy of the source array.
*
+ *
* @example
+ * The example below demonstrates a simple ngRepeat, where the data is sorted
+ * by age in descending order (predicate is set to `'-age'`).
+ * `reverse` is not set, which means it defaults to `false`.
<example module="orderByExample">
<file name="index.html">
<script>
@@ -15628,19 +19124,73 @@ function limitToFilter(){
{name:'Mike', phone:'555-4321', age:21},
{name:'Adam', phone:'555-5678', age:35},
{name:'Julie', phone:'555-8765', age:29}];
- $scope.predicate = '-age';
}]);
</script>
<div ng-controller="ExampleController">
+ <table class="friend">
+ <tr>
+ <th>Name</th>
+ <th>Phone Number</th>
+ <th>Age</th>
+ </tr>
+ <tr ng-repeat="friend in friends | orderBy:'-age'">
+ <td>{{friend.name}}</td>
+ <td>{{friend.phone}}</td>
+ <td>{{friend.age}}</td>
+ </tr>
+ </table>
+ </div>
+ </file>
+ </example>
+ *
+ * The predicate and reverse parameters can be controlled dynamically through scope properties,
+ * as shown in the next example.
+ * @example
+ <example module="orderByExample">
+ <file name="index.html">
+ <script>
+ angular.module('orderByExample', [])
+ .controller('ExampleController', ['$scope', function($scope) {
+ $scope.friends =
+ [{name:'John', phone:'555-1212', age:10},
+ {name:'Mary', phone:'555-9876', age:19},
+ {name:'Mike', phone:'555-4321', age:21},
+ {name:'Adam', phone:'555-5678', age:35},
+ {name:'Julie', phone:'555-8765', age:29}];
+ $scope.predicate = 'age';
+ $scope.reverse = true;
+ $scope.order = function(predicate) {
+ $scope.reverse = ($scope.predicate === predicate) ? !$scope.reverse : false;
+ $scope.predicate = predicate;
+ };
+ }]);
+ </script>
+ <style type="text/css">
+ .sortorder:after {
+ content: '\25b2';
+ }
+ .sortorder.reverse:after {
+ content: '\25bc';
+ }
+ </style>
+ <div ng-controller="ExampleController">
<pre>Sorting predicate = {{predicate}}; reverse = {{reverse}}</pre>
<hr/>
[ <a href="" ng-click="predicate=''">unsorted</a> ]
<table class="friend">
<tr>
- <th><a href="" ng-click="predicate = 'name'; reverse=false">Name</a>
- (<a href="" ng-click="predicate = '-name'; reverse=false">^</a>)</th>
- <th><a href="" ng-click="predicate = 'phone'; reverse=!reverse">Phone Number</a></th>
- <th><a href="" ng-click="predicate = 'age'; reverse=!reverse">Age</a></th>
+ <th>
+ <a href="" ng-click="order('name')">Name</a>
+ <span class="sortorder" ng-show="predicate === 'name'" ng-class="{reverse:reverse}"></span>
+ </th>
+ <th>
+ <a href="" ng-click="order('phone')">Phone Number</a>
+ <span class="sortorder" ng-show="predicate === 'phone'" ng-class="{reverse:reverse}"></span>
+ </th>
+ <th>
+ <a href="" ng-click="order('age')">Age</a>
+ <span class="sortorder" ng-show="predicate === 'age'" ng-class="{reverse:reverse}"></span>
+ </th>
</tr>
<tr ng-repeat="friend in friends | orderBy:predicate:reverse">
<td>{{friend.name}}</td>
@@ -15698,69 +19248,118 @@ function limitToFilter(){
</example>
*/
orderByFilter.$inject = ['$parse'];
-function orderByFilter($parse){
+function orderByFilter($parse) {
return function(array, sortPredicate, reverseOrder) {
+
if (!(isArrayLike(array))) return array;
- sortPredicate = isArray(sortPredicate) ? sortPredicate: [sortPredicate];
+
+ if (!isArray(sortPredicate)) { sortPredicate = [sortPredicate]; }
if (sortPredicate.length === 0) { sortPredicate = ['+']; }
- sortPredicate = map(sortPredicate, function(predicate){
- var descending = false, get = predicate || identity;
- if (isString(predicate)) {
+
+ var predicates = processPredicates(sortPredicate, reverseOrder);
+
+ // The next three lines are a version of a Swartzian Transform idiom from Perl
+ // (sometimes called the Decorate-Sort-Undecorate idiom)
+ // See https://en.wikipedia.org/wiki/Schwartzian_transform
+ var compareValues = Array.prototype.map.call(array, getComparisonObject);
+ compareValues.sort(doComparison);
+ array = compareValues.map(function(item) { return item.value; });
+
+ return array;
+
+ function getComparisonObject(value, index) {
+ return {
+ value: value,
+ predicateValues: predicates.map(function(predicate) {
+ return getPredicateValue(predicate.get(value), index);
+ })
+ };
+ }
+
+ function doComparison(v1, v2) {
+ var result = 0;
+ for (var index=0, length = predicates.length; index < length; ++index) {
+ result = compare(v1.predicateValues[index], v2.predicateValues[index]) * predicates[index].descending;
+ if (result) break;
+ }
+ return result;
+ }
+ };
+
+ function processPredicates(sortPredicate, reverseOrder) {
+ reverseOrder = reverseOrder ? -1 : 1;
+ return sortPredicate.map(function(predicate) {
+ var descending = 1, get = identity;
+
+ if (isFunction(predicate)) {
+ get = predicate;
+ } else if (isString(predicate)) {
if ((predicate.charAt(0) == '+' || predicate.charAt(0) == '-')) {
- descending = predicate.charAt(0) == '-';
+ descending = predicate.charAt(0) == '-' ? -1 : 1;
predicate = predicate.substring(1);
}
- if ( predicate === '' ) {
- // Effectively no predicate was passed so we compare identity
- return reverseComparator(function(a,b) {
- return compare(a, b);
- }, descending);
- }
- get = $parse(predicate);
- if (get.constant) {
- var key = get();
- return reverseComparator(function(a,b) {
- return compare(a[key], b[key]);
- }, descending);
+ if (predicate !== '') {
+ get = $parse(predicate);
+ if (get.constant) {
+ var key = get();
+ get = function(value) { return value[key]; };
+ }
}
}
- return reverseComparator(function(a,b){
- return compare(get(a),get(b));
- }, descending);
+ return { get: get, descending: descending * reverseOrder };
});
- return slice.call(array).sort(reverseComparator(comparator, reverseOrder));
-
- function comparator(o1, o2){
- for ( var i = 0; i < sortPredicate.length; i++) {
- var comp = sortPredicate[i](o1, o2);
- if (comp !== 0) return comp;
- }
- return 0;
- }
- function reverseComparator(comp, descending) {
- return toBoolean(descending)
- ? function(a,b){return comp(b,a);}
- : comp;
- }
- function compare(v1, v2){
- var t1 = typeof v1;
- var t2 = typeof v2;
- if (t1 == t2) {
- if (isDate(v1) && isDate(v2)) {
- v1 = v1.valueOf();
- v2 = v2.valueOf();
- }
- if (t1 == "string") {
- v1 = v1.toLowerCase();
- v2 = v2.toLowerCase();
- }
- if (v1 === v2) return 0;
- return v1 < v2 ? -1 : 1;
- } else {
- return t1 < t2 ? -1 : 1;
+ }
+
+ function isPrimitive(value) {
+ switch (typeof value) {
+ case 'number': /* falls through */
+ case 'boolean': /* falls through */
+ case 'string':
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ function objectValue(value, index) {
+ // If `valueOf` is a valid function use that
+ if (typeof value.valueOf === 'function') {
+ value = value.valueOf();
+ if (isPrimitive(value)) return value;
+ }
+ // If `toString` is a valid function and not the one from `Object.prototype` use that
+ if (hasCustomToString(value)) {
+ value = value.toString();
+ if (isPrimitive(value)) return value;
+ }
+ // We have a basic object so we use the position of the object in the collection
+ return index;
+ }
+
+ function getPredicateValue(value, index) {
+ var type = typeof value;
+ if (value === null) {
+ type = 'string';
+ value = 'null';
+ } else if (type === 'string') {
+ value = value.toLowerCase();
+ } else if (type === 'object') {
+ value = objectValue(value, index);
+ }
+ return { value: value, type: type };
+ }
+
+ function compare(v1, v2) {
+ var result = 0;
+ if (v1.type === v2.type) {
+ if (v1.value !== v2.value) {
+ result = v1.value < v2.value ? -1 : 1;
}
+ } else {
+ result = v1.type < v2.type ? -1 : 1;
}
- };
+ return result;
+ }
}
function ngDirective(directive) {
@@ -15789,28 +19388,15 @@ function ngDirective(directive) {
var htmlAnchorDirective = valueFn({
restrict: 'E',
compile: function(element, attr) {
-
- if (msie <= 8) {
-
- // turn <a href ng-click="..">link</a> into a stylable link in IE
- // but only if it doesn't have name attribute, in which case it's an anchor
- if (!attr.href && !attr.name) {
- attr.$set('href', '');
- }
-
- // add a comment node to anchors to workaround IE bug that causes element content to be reset
- // to new attribute content if attribute is updated with value containing @ and element also
- // contains value with @
- // see issue #1949
- element.append(document.createComment('IE fix'));
- }
-
- if (!attr.href && !attr.xlinkHref && !attr.name) {
+ if (!attr.href && !attr.xlinkHref) {
return function(scope, element) {
+ // If the linked element is not an anchor tag anymore, do nothing
+ if (element[0].nodeName.toLowerCase() !== 'a') return;
+
// SVGAElement does not use the href attribute, but rather the 'xlinkHref' attribute.
var href = toString.call(element.prop('href')) === '[object SVGAnimatedString]' ?
'xlink:href' : 'href';
- element.on('click', function(event){
+ element.on('click', function(event) {
// if we have no href url, then don't navigate anywhere.
if (!element.attr(href)) {
event.preventDefault();
@@ -15837,12 +19423,12 @@ var htmlAnchorDirective = valueFn({
*
* The wrong way to write it:
* ```html
- * <a href="http://www.gravatar.com/avatar/{{hash}}"/>
+ * <a href="http://www.gravatar.com/avatar/{{hash}}">link1</a>
* ```
*
* The correct way to write it:
* ```html
- * <a ng-href="http://www.gravatar.com/avatar/{{hash}}"/>
+ * <a ng-href="http://www.gravatar.com/avatar/{{hash}}">link1</a>
* ```
*
* @element A
@@ -15889,7 +19475,7 @@ var htmlAnchorDirective = valueFn({
}, 5000, 'page should navigate to /123');
});
- xit('should execute ng-click but not reload when href empty string and name specified', function() {
+ it('should execute ng-click but not reload when href empty string and name specified', function() {
element(by.id('link-4')).click();
expect(element(by.model('value')).getAttribute('value')).toEqual('4');
expect(element(by.id('link-4')).getAttribute('href')).toBe('');
@@ -15934,12 +19520,12 @@ var htmlAnchorDirective = valueFn({
*
* The buggy way to write it:
* ```html
- * <img src="http://www.gravatar.com/avatar/{{hash}}"/>
+ * <img src="http://www.gravatar.com/avatar/{{hash}}" alt="Description"/>
* ```
*
* The correct way to write it:
* ```html
- * <img ng-src="http://www.gravatar.com/avatar/{{hash}}"/>
+ * <img ng-src="http://www.gravatar.com/avatar/{{hash}}" alt="Description" />
* ```
*
* @element IMG
@@ -15960,12 +19546,12 @@ var htmlAnchorDirective = valueFn({
*
* The buggy way to write it:
* ```html
- * <img srcset="http://www.gravatar.com/avatar/{{hash}} 2x"/>
+ * <img srcset="http://www.gravatar.com/avatar/{{hash}} 2x" alt="Description"/>
* ```
*
* The correct way to write it:
* ```html
- * <img ng-srcset="http://www.gravatar.com/avatar/{{hash}} 2x"/>
+ * <img ng-srcset="http://www.gravatar.com/avatar/{{hash}} 2x" alt="Description" />
* ```
*
* @element IMG
@@ -15980,25 +19566,29 @@ var htmlAnchorDirective = valueFn({
*
* @description
*
- * We shouldn't do this, because it will make the button enabled on Chrome/Firefox but not on IE8 and older IEs:
+ * This directive sets the `disabled` attribute on the element if the
+ * {@link guide/expression expression} inside `ngDisabled` evaluates to truthy.
+ *
+ * A special directive is necessary because we cannot use interpolation inside the `disabled`
+ * attribute. The following example would make the button enabled on Chrome/Firefox
+ * but not on older IEs:
+ *
* ```html
- * <div ng-init="scope = { isDisabled: false }">
- * <button disabled="{{scope.isDisabled}}">Disabled</button>
+ * <!-- See below for an example of ng-disabled being used correctly -->
+ * <div ng-init="isDisabled = false">
+ * <button disabled="{{isDisabled}}">Disabled</button>
* </div>
* ```
*
- * The HTML specification does not require browsers to preserve the values of boolean attributes
- * such as disabled. (Their presence means true and their absence means false.)
+ * This is because the HTML specification does not require browsers to preserve the values of
+ * boolean attributes such as `disabled` (Their presence means true and their absence means false.)
* If we put an Angular interpolation expression into such an attribute then the
* binding information would be lost when the browser removes the attribute.
- * The `ngDisabled` directive solves this problem for the `disabled` attribute.
- * This complementary directive is not removed by the browser and so provides
- * a permanent reliable place to store the binding information.
*
* @example
<example>
<file name="index.html">
- Click me to toggle: <input type="checkbox" ng-model="checked"><br/>
+ <label>Click me to toggle: <input type="checkbox" ng-model="checked"></label><br/>
<button ng-model="button" ng-disabled="checked">Button</button>
</file>
<file name="protractor.js" type="protractor">
@@ -16012,7 +19602,7 @@ var htmlAnchorDirective = valueFn({
*
* @element INPUT
* @param {expression} ngDisabled If the {@link guide/expression expression} is truthy,
- * then special attribute "disabled" will be set on the element
+ * then the `disabled` attribute will be set on the element
*/
@@ -16023,6 +19613,13 @@ var htmlAnchorDirective = valueFn({
* @priority 100
*
* @description
+ * Sets the `checked` attribute on the element, if the expression inside `ngChecked` is truthy.
+ *
+ * Note that this directive should not be used together with {@link ngModel `ngModel`},
+ * as this can lead to unexpected behavior.
+ *
+ * ### Why do we need `ngChecked`?
+ *
* The HTML specification does not require browsers to preserve the values of boolean attributes
* such as checked. (Their presence means true and their absence means false.)
* If we put an Angular interpolation expression into such an attribute then the
@@ -16033,8 +19630,8 @@ var htmlAnchorDirective = valueFn({
* @example
<example>
<file name="index.html">
- Check me to check both: <input type="checkbox" ng-model="master"><br/>
- <input id="checkSlave" type="checkbox" ng-checked="master">
+ <label>Check me to check both: <input type="checkbox" ng-model="master"></label><br/>
+ <input id="checkSlave" type="checkbox" ng-checked="master" aria-label="Slave input">
</file>
<file name="protractor.js" type="protractor">
it('should check both checkBoxes', function() {
@@ -16047,7 +19644,7 @@ var htmlAnchorDirective = valueFn({
*
* @element INPUT
* @param {expression} ngChecked If the {@link guide/expression expression} is truthy,
- * then special attribute "checked" will be set on the element
+ * then the `checked` attribute will be set on the element
*/
@@ -16068,8 +19665,8 @@ var htmlAnchorDirective = valueFn({
* @example
<example>
<file name="index.html">
- Check me to make text readonly: <input type="checkbox" ng-model="checked"><br/>
- <input type="text" ng-readonly="checked" value="I'm Angular"/>
+ <label>Check me to make text readonly: <input type="checkbox" ng-model="checked"></label><br/>
+ <input type="text" ng-readonly="checked" value="I'm Angular" aria-label="Readonly field" />
</file>
<file name="protractor.js" type="protractor">
it('should toggle readonly attr', function() {
@@ -16104,8 +19701,8 @@ var htmlAnchorDirective = valueFn({
* @example
<example>
<file name="index.html">
- Check me to select: <input type="checkbox" ng-model="selected"><br/>
- <select>
+ <label>Check me to select: <input type="checkbox" ng-model="selected"></label><br/>
+ <select aria-label="ngSelected demo">
<option>Hello!</option>
<option id="greet" ng-selected="selected">Greetings!</option>
</select>
@@ -16141,7 +19738,7 @@ var htmlAnchorDirective = valueFn({
* @example
<example>
<file name="index.html">
- Check me check multiple: <input type="checkbox" ng-model="open"><br/>
+ <label>Check me check multiple: <input type="checkbox" ng-model="open"></label><br/>
<details id="details" ng-open="open">
<summary>Show/Hide me</summary>
</details>
@@ -16162,26 +19759,62 @@ var htmlAnchorDirective = valueFn({
var ngAttributeAliasDirectives = {};
-
// boolean attrs are evaluated
forEach(BOOLEAN_ATTR, function(propName, attrName) {
// binding to multiple is not supported
if (propName == "multiple") return;
+ function defaultLinkFn(scope, element, attr) {
+ scope.$watch(attr[normalized], function ngBooleanAttrWatchAction(value) {
+ attr.$set(attrName, !!value);
+ });
+ }
+
var normalized = directiveNormalize('ng-' + attrName);
+ var linkFn = defaultLinkFn;
+
+ if (propName === 'checked') {
+ linkFn = function(scope, element, attr) {
+ // ensuring ngChecked doesn't interfere with ngModel when both are set on the same input
+ if (attr.ngModel !== attr[normalized]) {
+ defaultLinkFn(scope, element, attr);
+ }
+ };
+ }
+
ngAttributeAliasDirectives[normalized] = function() {
return {
+ restrict: 'A',
+ priority: 100,
+ link: linkFn
+ };
+ };
+});
+
+// aliased input attrs are evaluated
+forEach(ALIASED_ATTR, function(htmlAttr, ngAttr) {
+ ngAttributeAliasDirectives[ngAttr] = function() {
+ return {
priority: 100,
link: function(scope, element, attr) {
- scope.$watch(attr[normalized], function ngBooleanAttrWatchAction(value) {
- attr.$set(attrName, !!value);
+ //special case ngPattern when a literal regular expression value
+ //is used as the expression (this way we don't have to watch anything).
+ if (ngAttr === "ngPattern" && attr.ngPattern.charAt(0) == "/") {
+ var match = attr.ngPattern.match(REGEX_STRING_REGEXP);
+ if (match) {
+ attr.$set("ngPattern", new RegExp(match[1], match[2]));
+ return;
+ }
+ }
+
+ scope.$watch(attr[ngAttr], function ngAttrAliasWatchAction(value) {
+ attr.$set(ngAttr, value);
});
}
};
};
});
-
// ng-src, ng-srcset, ng-href are interpolated
forEach(['src', 'srcset', 'href'], function(attrName) {
var normalized = directiveNormalize('ng-' + attrName);
@@ -16220,14 +19853,22 @@ forEach(['src', 'srcset', 'href'], function(attrName) {
};
});
-/* global -nullFormCtrl */
+/* global -nullFormCtrl, -SUBMITTED_CLASS, addSetValidityMethod: true
+ */
var nullFormCtrl = {
$addControl: noop,
+ $$renameControl: nullFormRenameControl,
$removeControl: noop,
$setValidity: noop,
$setDirty: noop,
- $setPristine: noop
-};
+ $setPristine: noop,
+ $setSubmitted: noop
+},
+SUBMITTED_CLASS = 'ng-submitted';
+
+function nullFormRenameControl(control, name) {
+ control.$name = name;
+}
/**
* @ngdoc type
@@ -16237,13 +19878,13 @@ var nullFormCtrl = {
* @property {boolean} $dirty True if user has already interacted with the form.
* @property {boolean} $valid True if all of the containing forms and controls are valid.
* @property {boolean} $invalid True if at least one containing control or form is invalid.
+ * @property {boolean} $submitted True if user has submitted the form even if its invalid.
*
- * @property {Object} $error Is an object hash, containing references to all invalid controls or
- * forms, where:
+ * @property {Object} $error Is an object hash, containing references to controls or
+ * forms with failing validators, where:
*
* - keys are validation tokens (error names),
- * - values are arrays of controls or forms that are invalid for given error name.
- *
+ * - values are arrays of controls or forms that have a failing validator for given error name.
*
* Built-in validation tokens:
*
@@ -16256,6 +19897,11 @@ var nullFormCtrl = {
* - `pattern`
* - `required`
* - `url`
+ * - `date`
+ * - `datetimelocal`
+ * - `time`
+ * - `week`
+ * - `month`
*
* @description
* `FormController` keeps track of all its controls and nested forms as well as the state of them,
@@ -16266,34 +19912,59 @@ var nullFormCtrl = {
*
*/
//asks for $scope to fool the BC controller module
-FormController.$inject = ['$element', '$attrs', '$scope', '$animate'];
-function FormController(element, attrs, $scope, $animate) {
+FormController.$inject = ['$element', '$attrs', '$scope', '$animate', '$interpolate'];
+function FormController(element, attrs, $scope, $animate, $interpolate) {
var form = this,
- parentForm = element.parent().controller('form') || nullFormCtrl,
- invalidCount = 0, // used to easily determine if we are valid
- errors = form.$error = {},
controls = [];
+ var parentForm = form.$$parentForm = element.parent().controller('form') || nullFormCtrl;
+
// init state
- form.$name = attrs.name || attrs.ngForm;
+ form.$error = {};
+ form.$$success = {};
+ form.$pending = undefined;
+ form.$name = $interpolate(attrs.name || attrs.ngForm || '')($scope);
form.$dirty = false;
form.$pristine = true;
form.$valid = true;
form.$invalid = false;
+ form.$submitted = false;
parentForm.$addControl(form);
- // Setup initial state of the control
- element.addClass(PRISTINE_CLASS);
- toggleValidCss(true);
+ /**
+ * @ngdoc method
+ * @name form.FormController#$rollbackViewValue
+ *
+ * @description
+ * Rollback all form controls pending updates to the `$modelValue`.
+ *
+ * Updates may be pending by a debounced event or because the input is waiting for a some future
+ * event defined in `ng-model-options`. This method is typically needed by the reset button of
+ * a form that uses `ng-model-options` to pend updates.
+ */
+ form.$rollbackViewValue = function() {
+ forEach(controls, function(control) {
+ control.$rollbackViewValue();
+ });
+ };
- // convenience method for easy toggling of classes
- function toggleValidCss(isValid, validationErrorKey) {
- validationErrorKey = validationErrorKey ? '-' + snake_case(validationErrorKey, '-') : '';
- $animate.setClass(element,
- (isValid ? VALID_CLASS : INVALID_CLASS) + validationErrorKey,
- (isValid ? INVALID_CLASS : VALID_CLASS) + validationErrorKey);
- }
+ /**
+ * @ngdoc method
+ * @name form.FormController#$commitViewValue
+ *
+ * @description
+ * Commit all form controls pending updates to the `$modelValue`.
+ *
+ * Updates may be pending by a debounced event or because the input is waiting for a some future
+ * event defined in `ng-model-options`. This method is rarely needed as `NgModelController`
+ * usually handles calling this in response to input events.
+ */
+ form.$commitViewValue = function() {
+ forEach(controls, function(control) {
+ control.$commitViewValue();
+ });
+ };
/**
* @ngdoc method
@@ -16315,6 +19986,17 @@ function FormController(element, attrs, $scope, $animate) {
}
};
+ // Private API: rename a form control
+ form.$$renameControl = function(control, newName) {
+ var oldName = control.$name;
+
+ if (form[oldName] === control) {
+ delete form[oldName];
+ }
+ form[newName] = control;
+ control.$name = newName;
+ };
+
/**
* @ngdoc method
* @name form.FormController#$removeControl
@@ -16328,13 +20010,20 @@ function FormController(element, attrs, $scope, $animate) {
if (control.$name && form[control.$name] === control) {
delete form[control.$name];
}
- forEach(errors, function(queue, validationToken) {
- form.$setValidity(validationToken, true, control);
+ forEach(form.$pending, function(value, name) {
+ form.$setValidity(name, null, control);
+ });
+ forEach(form.$error, function(value, name) {
+ form.$setValidity(name, null, control);
+ });
+ forEach(form.$$success, function(value, name) {
+ form.$setValidity(name, null, control);
});
arrayRemove(controls, control);
};
+
/**
* @ngdoc method
* @name form.FormController#$setValidity
@@ -16344,43 +20033,33 @@ function FormController(element, attrs, $scope, $animate) {
*
* This method will also propagate to parent forms.
*/
- form.$setValidity = function(validationToken, isValid, control) {
- var queue = errors[validationToken];
-
- if (isValid) {
- if (queue) {
- arrayRemove(queue, control);
- if (!queue.length) {
- invalidCount--;
- if (!invalidCount) {
- toggleValidCss(isValid);
- form.$valid = true;
- form.$invalid = false;
- }
- errors[validationToken] = false;
- toggleValidCss(true, validationToken);
- parentForm.$setValidity(validationToken, true, form);
+ addSetValidityMethod({
+ ctrl: this,
+ $element: element,
+ set: function(object, property, controller) {
+ var list = object[property];
+ if (!list) {
+ object[property] = [controller];
+ } else {
+ var index = list.indexOf(controller);
+ if (index === -1) {
+ list.push(controller);
}
}
-
- } else {
- if (!invalidCount) {
- toggleValidCss(isValid);
+ },
+ unset: function(object, property, controller) {
+ var list = object[property];
+ if (!list) {
+ return;
}
- if (queue) {
- if (includes(queue, control)) return;
- } else {
- errors[validationToken] = queue = [];
- invalidCount++;
- toggleValidCss(false, validationToken);
- parentForm.$setValidity(validationToken, false, form);
+ arrayRemove(list, controller);
+ if (list.length === 0) {
+ delete object[property];
}
- queue.push(control);
-
- form.$valid = false;
- form.$invalid = true;
- }
- };
+ },
+ parentForm: parentForm,
+ $animate: $animate
+ });
/**
* @ngdoc method
@@ -16414,17 +20093,48 @@ function FormController(element, attrs, $scope, $animate) {
* Setting a form back to a pristine state is often useful when we want to 'reuse' a form after
* saving or resetting it.
*/
- form.$setPristine = function () {
- $animate.removeClass(element, DIRTY_CLASS);
- $animate.addClass(element, PRISTINE_CLASS);
+ form.$setPristine = function() {
+ $animate.setClass(element, PRISTINE_CLASS, DIRTY_CLASS + ' ' + SUBMITTED_CLASS);
form.$dirty = false;
form.$pristine = true;
+ form.$submitted = false;
forEach(controls, function(control) {
control.$setPristine();
});
};
-}
+ /**
+ * @ngdoc method
+ * @name form.FormController#$setUntouched
+ *
+ * @description
+ * Sets the form to its untouched state.
+ *
+ * This method can be called to remove the 'ng-touched' class and set the form controls to their
+ * untouched state (ng-untouched class).
+ *
+ * Setting a form controls back to their untouched state is often useful when setting the form
+ * back to its pristine state.
+ */
+ form.$setUntouched = function() {
+ forEach(controls, function(control) {
+ control.$setUntouched();
+ });
+ };
+
+ /**
+ * @ngdoc method
+ * @name form.FormController#$setSubmitted
+ *
+ * @description
+ * Sets the form to its submitted state.
+ */
+ form.$setSubmitted = function() {
+ $animate.addClass(element, SUBMITTED_CLASS);
+ form.$submitted = true;
+ parentForm.$setSubmitted();
+ };
+}
/**
* @ngdoc directive
@@ -16459,7 +20169,7 @@ function FormController(element, attrs, $scope, $animate) {
*
* # Alias: {@link ng.directive:ngForm `ngForm`}
*
- * In Angular forms can be nested. This means that the outer form is valid when all of the child
+ * In Angular, forms can be nested. This means that the outer form is valid when all of the child
* forms are valid as well. However, browsers do not allow nesting of `<form>` elements, so
* Angular provides the {@link ng.directive:ngForm `ngForm`} directive which behaves identically to
* `<form>` but can be nested. This allows you to have nested forms, which is very useful when
@@ -16474,6 +20184,7 @@ function FormController(element, attrs, $scope, $animate) {
* - `ng-invalid` is set if the form is invalid.
* - `ng-pristine` is set if the form is pristine.
* - `ng-dirty` is set if the form is dirty.
+ * - `ng-submitted` is set if the form was submitted.
*
* Keep in mind that ngAnimate can detect each of these classes when added and removed.
*
@@ -16507,6 +20218,9 @@ function FormController(element, attrs, $scope, $animate) {
* hitting enter in any of the input fields will trigger the click handler on the *first* button or
* input[type=submit] (`ngClick`) *and* a submit handler on the enclosing form (`ngSubmit`)
*
+ * Any pending `ngModelOptions` changes will take place immediately when an enclosing form is
+ * submitted. Note that `ngClick` events will occur before the model is updated. Use `ngSubmit`
+ * to have access to the updated model.
*
* ## Animation Hooks
*
@@ -16554,11 +20268,11 @@ function FormController(element, attrs, $scope, $animate) {
<form name="myForm" ng-controller="FormController" class="my-form">
userType: <input name="input" ng-model="userType" required>
<span class="error" ng-show="myForm.input.$error.required">Required!</span><br>
- <tt>userType = {{userType}}</tt><br>
- <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br>
- <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br>
- <tt>myForm.$valid = {{myForm.$valid}}</tt><br>
- <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br>
+ <code>userType = {{userType}}</code><br>
+ <code>myForm.input.$valid = {{myForm.input.$valid}}</code><br>
+ <code>myForm.input.$error = {{myForm.input.$error}}</code><br>
+ <code>myForm.$valid = {{myForm.$valid}}</code><br>
+ <code>myForm.$error.required = {{!!myForm.$error.required}}</code><br>
</form>
</file>
<file name="protractor.js" type="protractor">
@@ -16593,48 +20307,60 @@ var formDirectiveFactory = function(isNgForm) {
name: 'form',
restrict: isNgForm ? 'EAC' : 'E',
controller: FormController,
- compile: function() {
+ compile: function ngFormCompile(formElement, attr) {
+ // Setup initial state of the control
+ formElement.addClass(PRISTINE_CLASS).addClass(VALID_CLASS);
+
+ var nameAttr = attr.name ? 'name' : (isNgForm && attr.ngForm ? 'ngForm' : false);
+
return {
- pre: function(scope, formElement, attr, controller) {
- if (!attr.action) {
+ pre: function ngFormPreLink(scope, formElement, attr, controller) {
+ // if `action` attr is not present on the form, prevent the default action (submission)
+ if (!('action' in attr)) {
// we can't use jq events because if a form is destroyed during submission the default
// action is not prevented. see #1238
//
// IE 9 is not affected because it doesn't fire a submit event and try to do a full
// page reload if the form was destroyed by submission of the form via a click handler
// on a button in the form. Looks like an IE9 specific bug.
- var preventDefaultListener = function(event) {
- event.preventDefault
- ? event.preventDefault()
- : event.returnValue = false; // IE
+ var handleFormSubmission = function(event) {
+ scope.$apply(function() {
+ controller.$commitViewValue();
+ controller.$setSubmitted();
+ });
+
+ event.preventDefault();
};
- addEventListenerFn(formElement[0], 'submit', preventDefaultListener);
+ addEventListenerFn(formElement[0], 'submit', handleFormSubmission);
// unregister the preventDefault listener so that we don't not leak memory but in a
// way that will achieve the prevention of the default action.
formElement.on('$destroy', function() {
$timeout(function() {
- removeEventListenerFn(formElement[0], 'submit', preventDefaultListener);
+ removeEventListenerFn(formElement[0], 'submit', handleFormSubmission);
}, 0, false);
});
}
- var parentFormCtrl = formElement.parent().controller('form'),
- alias = attr.name || attr.ngForm;
+ var parentFormCtrl = controller.$$parentForm;
- if (alias) {
- setter(scope, alias, controller, alias);
- }
- if (parentFormCtrl) {
- formElement.on('$destroy', function() {
- parentFormCtrl.$removeControl(controller);
- if (alias) {
- setter(scope, alias, undefined, alias);
- }
- extend(controller, nullFormCtrl); //stop propagating child destruction handlers upwards
+ if (nameAttr) {
+ setter(scope, controller.$name, controller, controller.$name);
+ attr.$observe(nameAttr, function(newValue) {
+ if (controller.$name === newValue) return;
+ setter(scope, controller.$name, undefined, controller.$name);
+ parentFormCtrl.$$renameControl(controller, newValue);
+ setter(scope, controller.$name, controller, controller.$name);
});
}
+ formElement.on('$destroy', function() {
+ parentFormCtrl.$removeControl(controller);
+ if (nameAttr) {
+ setter(scope, attr[nameAttr], undefined, controller.$name);
+ }
+ extend(controller, nullFormCtrl); //stop propagating child destruction handlers upwards
+ });
}
};
}
@@ -16647,15 +20373,25 @@ var formDirectiveFactory = function(isNgForm) {
var formDirective = formDirectiveFactory();
var ngFormDirective = formDirectiveFactory(true);
-/* global VALID_CLASS: true,
- INVALID_CLASS: true,
- PRISTINE_CLASS: true,
- DIRTY_CLASS: true
+/* global VALID_CLASS: false,
+ INVALID_CLASS: false,
+ PRISTINE_CLASS: false,
+ DIRTY_CLASS: false,
+ UNTOUCHED_CLASS: false,
+ TOUCHED_CLASS: false,
+ $ngModelMinErr: false,
*/
+// Regex code is obtained from SO: https://stackoverflow.com/questions/3143070/javascript-regex-iso-datetime#answer-3143231
+var ISO_DATE_REGEXP = /\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z)/;
var URL_REGEXP = /^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/;
var EMAIL_REGEXP = /^[a-z0-9!#$%&'*+\/=?^_`{|}~.-]+@[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i;
-var NUMBER_REGEXP = /^\s*(\-|\+)?(\d+|(\d*(\.\d*)))\s*$/;
+var NUMBER_REGEXP = /^\s*(\-|\+)?(\d+|(\d*(\.\d*)))([eE][+-]?\d+)?\s*$/;
+var DATE_REGEXP = /^(\d{4})-(\d{2})-(\d{2})$/;
+var DATETIMELOCAL_REGEXP = /^(\d{4})-(\d\d)-(\d\d)T(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/;
+var WEEK_REGEXP = /^(\d{4})-W(\d\d)$/;
+var MONTH_REGEXP = /^(\d{4})-(\d\d)$/;
+var TIME_REGEXP = /^(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/;
var inputType = {
@@ -16666,7 +20402,6 @@ var inputType = {
* @description
* Standard HTML text input with angular data binding, inherited by most of the `input` elements.
*
- * *NOTE* Not every feature offered is available for all input types.
*
* @param {string} ngModel Assignable angular expression to data-bind to.
* @param {string=} name Property name of the form under which the control is published.
@@ -16677,10 +20412,20 @@ var inputType = {
* @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
* minlength.
* @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
- * maxlength.
- * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
- * RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
- * patterns defined as scope expressions.
+ * maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
+ * any length.
+ * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
+ * that contains the regular expression body that will be converted to a regular expression
+ * as in the ngPattern directive.
+ * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
+ * a RegExp found by evaluating the Angular expression given in the attribute value.
+ * If the expression evaluates to a RegExp object, then this is used directly.
+ * If the expression evaluates to a string, then it will be converted to a RegExp
+ * after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
+ * `new RegExp('^abc$')`.<br />
+ * **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
+ * start at the index of the last search's match, thus not taking the whole input value into
+ * account.
* @param {string=} ngChange Angular expression to be executed when input changes due to user
* interaction with the input element.
* @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.
@@ -16693,19 +20438,24 @@ var inputType = {
<script>
angular.module('textInputExample', [])
.controller('ExampleController', ['$scope', function($scope) {
- $scope.text = 'guest';
- $scope.word = /^\s*\w*\s*$/;
+ $scope.example = {
+ text: 'guest',
+ word: /^\s*\w*\s*$/
+ };
}]);
</script>
<form name="myForm" ng-controller="ExampleController">
- Single word: <input type="text" name="input" ng-model="text"
- ng-pattern="word" required ng-trim="false">
- <span class="error" ng-show="myForm.input.$error.required">
- Required!</span>
- <span class="error" ng-show="myForm.input.$error.pattern">
- Single word only!</span>
-
- <tt>text = {{text}}</tt><br/>
+ <label>Single word:
+ <input type="text" name="input" ng-model="example.text"
+ ng-pattern="example.word" required ng-trim="false">
+ </label>
+ <div role="alert">
+ <span class="error" ng-show="myForm.input.$error.required">
+ Required!</span>
+ <span class="error" ng-show="myForm.input.$error.pattern">
+ Single word only!</span>
+ </div>
+ <tt>text = {{example.text}}</tt><br/>
<tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
<tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
<tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
@@ -16713,9 +20463,9 @@ var inputType = {
</form>
</file>
<file name="protractor.js" type="protractor">
- var text = element(by.binding('text'));
+ var text = element(by.binding('example.text'));
var valid = element(by.binding('myForm.input.$valid'));
- var input = element(by.model('text'));
+ var input = element(by.model('example.text'));
it('should initialize to model', function() {
expect(text.getText()).toContain('guest');
@@ -16741,6 +20491,485 @@ var inputType = {
*/
'text': textInputType,
+ /**
+ * @ngdoc input
+ * @name input[date]
+ *
+ * @description
+ * Input with date validation and transformation. In browsers that do not yet support
+ * the HTML5 date input, a text element will be used. In that case, text must be entered in a valid ISO-8601
+ * date format (yyyy-MM-dd), for example: `2009-01-06`. Since many
+ * modern browsers do not yet support this input type, it is important to provide cues to users on the
+ * expected input format via a placeholder or label.
+ *
+ * The model must always be a Date object, otherwise Angular will throw an error.
+ * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
+ *
+ * The timezone to be used to read/write the `Date` instance in the model can be defined using
+ * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
+ *
+ * @param {string} ngModel Assignable angular expression to data-bind to.
+ * @param {string=} name Property name of the form under which the control is published.
+ * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be a
+ * valid ISO date string (yyyy-MM-dd).
+ * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. This must be
+ * a valid ISO date string (yyyy-MM-dd).
+ * @param {string=} required Sets `required` validation error key if the value is not entered.
+ * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
+ * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
+ * `required` when you want to data-bind to the `required` attribute.
+ * @param {string=} ngChange Angular expression to be executed when input changes due to user
+ * interaction with the input element.
+ *
+ * @example
+ <example name="date-input-directive" module="dateInputExample">
+ <file name="index.html">
+ <script>
+ angular.module('dateInputExample', [])
+ .controller('DateController', ['$scope', function($scope) {
+ $scope.example = {
+ value: new Date(2013, 9, 22)
+ };
+ }]);
+ </script>
+ <form name="myForm" ng-controller="DateController as dateCtrl">
+ <label for="exampleInput">Pick a date in 2013:</label>
+ <input type="date" id="exampleInput" name="input" ng-model="example.value"
+ placeholder="yyyy-MM-dd" min="2013-01-01" max="2013-12-31" required />
+ <div role="alert">
+ <span class="error" ng-show="myForm.input.$error.required">
+ Required!</span>
+ <span class="error" ng-show="myForm.input.$error.date">
+ Not a valid date!</span>
+ </div>
+ <tt>value = {{example.value | date: "yyyy-MM-dd"}}</tt><br/>
+ <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
+ <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
+ <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
+ <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
+ </form>
+ </file>
+ <file name="protractor.js" type="protractor">
+ var value = element(by.binding('example.value | date: "yyyy-MM-dd"'));
+ var valid = element(by.binding('myForm.input.$valid'));
+ var input = element(by.model('example.value'));
+
+ // currently protractor/webdriver does not support
+ // sending keys to all known HTML5 input controls
+ // for various browsers (see https://github.com/angular/protractor/issues/562).
+ function setInput(val) {
+ // set the value of the element and force validation.
+ var scr = "var ipt = document.getElementById('exampleInput'); " +
+ "ipt.value = '" + val + "';" +
+ "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
+ browser.executeScript(scr);
+ }
+
+ it('should initialize to model', function() {
+ expect(value.getText()).toContain('2013-10-22');
+ expect(valid.getText()).toContain('myForm.input.$valid = true');
+ });
+
+ it('should be invalid if empty', function() {
+ setInput('');
+ expect(value.getText()).toEqual('value =');
+ expect(valid.getText()).toContain('myForm.input.$valid = false');
+ });
+
+ it('should be invalid if over max', function() {
+ setInput('2015-01-01');
+ expect(value.getText()).toContain('');
+ expect(valid.getText()).toContain('myForm.input.$valid = false');
+ });
+ </file>
+ </example>
+ */
+ 'date': createDateInputType('date', DATE_REGEXP,
+ createDateParser(DATE_REGEXP, ['yyyy', 'MM', 'dd']),
+ 'yyyy-MM-dd'),
+
+ /**
+ * @ngdoc input
+ * @name input[datetime-local]
+ *
+ * @description
+ * Input with datetime validation and transformation. In browsers that do not yet support
+ * the HTML5 date input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
+ * local datetime format (yyyy-MM-ddTHH:mm:ss), for example: `2010-12-28T14:57:00`.
+ *
+ * The model must always be a Date object, otherwise Angular will throw an error.
+ * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
+ *
+ * The timezone to be used to read/write the `Date` instance in the model can be defined using
+ * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
+ *
+ * @param {string} ngModel Assignable angular expression to data-bind to.
+ * @param {string=} name Property name of the form under which the control is published.
+ * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be a
+ * valid ISO datetime format (yyyy-MM-ddTHH:mm:ss).
+ * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. This must be
+ * a valid ISO datetime format (yyyy-MM-ddTHH:mm:ss).
+ * @param {string=} required Sets `required` validation error key if the value is not entered.
+ * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
+ * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
+ * `required` when you want to data-bind to the `required` attribute.
+ * @param {string=} ngChange Angular expression to be executed when input changes due to user
+ * interaction with the input element.
+ *
+ * @example
+ <example name="datetimelocal-input-directive" module="dateExample">
+ <file name="index.html">
+ <script>
+ angular.module('dateExample', [])
+ .controller('DateController', ['$scope', function($scope) {
+ $scope.example = {
+ value: new Date(2010, 11, 28, 14, 57)
+ };
+ }]);
+ </script>
+ <form name="myForm" ng-controller="DateController as dateCtrl">
+ <label for="exampleInput">Pick a date between in 2013:</label>
+ <input type="datetime-local" id="exampleInput" name="input" ng-model="example.value"
+ placeholder="yyyy-MM-ddTHH:mm:ss" min="2001-01-01T00:00:00" max="2013-12-31T00:00:00" required />
+ <div role="alert">
+ <span class="error" ng-show="myForm.input.$error.required">
+ Required!</span>
+ <span class="error" ng-show="myForm.input.$error.datetimelocal">
+ Not a valid date!</span>
+ </div>
+ <tt>value = {{example.value | date: "yyyy-MM-ddTHH:mm:ss"}}</tt><br/>
+ <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
+ <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
+ <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
+ <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
+ </form>
+ </file>
+ <file name="protractor.js" type="protractor">
+ var value = element(by.binding('example.value | date: "yyyy-MM-ddTHH:mm:ss"'));
+ var valid = element(by.binding('myForm.input.$valid'));
+ var input = element(by.model('example.value'));
+
+ // currently protractor/webdriver does not support
+ // sending keys to all known HTML5 input controls
+ // for various browsers (https://github.com/angular/protractor/issues/562).
+ function setInput(val) {
+ // set the value of the element and force validation.
+ var scr = "var ipt = document.getElementById('exampleInput'); " +
+ "ipt.value = '" + val + "';" +
+ "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
+ browser.executeScript(scr);
+ }
+
+ it('should initialize to model', function() {
+ expect(value.getText()).toContain('2010-12-28T14:57:00');
+ expect(valid.getText()).toContain('myForm.input.$valid = true');
+ });
+
+ it('should be invalid if empty', function() {
+ setInput('');
+ expect(value.getText()).toEqual('value =');
+ expect(valid.getText()).toContain('myForm.input.$valid = false');
+ });
+
+ it('should be invalid if over max', function() {
+ setInput('2015-01-01T23:59:00');
+ expect(value.getText()).toContain('');
+ expect(valid.getText()).toContain('myForm.input.$valid = false');
+ });
+ </file>
+ </example>
+ */
+ 'datetime-local': createDateInputType('datetimelocal', DATETIMELOCAL_REGEXP,
+ createDateParser(DATETIMELOCAL_REGEXP, ['yyyy', 'MM', 'dd', 'HH', 'mm', 'ss', 'sss']),
+ 'yyyy-MM-ddTHH:mm:ss.sss'),
+
+ /**
+ * @ngdoc input
+ * @name input[time]
+ *
+ * @description
+ * Input with time validation and transformation. In browsers that do not yet support
+ * the HTML5 date input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
+ * local time format (HH:mm:ss), for example: `14:57:00`. Model must be a Date object. This binding will always output a
+ * Date object to the model of January 1, 1970, or local date `new Date(1970, 0, 1, HH, mm, ss)`.
+ *
+ * The model must always be a Date object, otherwise Angular will throw an error.
+ * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
+ *
+ * The timezone to be used to read/write the `Date` instance in the model can be defined using
+ * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
+ *
+ * @param {string} ngModel Assignable angular expression to data-bind to.
+ * @param {string=} name Property name of the form under which the control is published.
+ * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be a
+ * valid ISO time format (HH:mm:ss).
+ * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. This must be a
+ * valid ISO time format (HH:mm:ss).
+ * @param {string=} required Sets `required` validation error key if the value is not entered.
+ * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
+ * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
+ * `required` when you want to data-bind to the `required` attribute.
+ * @param {string=} ngChange Angular expression to be executed when input changes due to user
+ * interaction with the input element.
+ *
+ * @example
+ <example name="time-input-directive" module="timeExample">
+ <file name="index.html">
+ <script>
+ angular.module('timeExample', [])
+ .controller('DateController', ['$scope', function($scope) {
+ $scope.example = {
+ value: new Date(1970, 0, 1, 14, 57, 0)
+ };
+ }]);
+ </script>
+ <form name="myForm" ng-controller="DateController as dateCtrl">
+ <label for="exampleInput">Pick a between 8am and 5pm:</label>
+ <input type="time" id="exampleInput" name="input" ng-model="example.value"
+ placeholder="HH:mm:ss" min="08:00:00" max="17:00:00" required />
+ <div role="alert">
+ <span class="error" ng-show="myForm.input.$error.required">
+ Required!</span>
+ <span class="error" ng-show="myForm.input.$error.time">
+ Not a valid date!</span>
+ </div>
+ <tt>value = {{example.value | date: "HH:mm:ss"}}</tt><br/>
+ <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
+ <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
+ <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
+ <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
+ </form>
+ </file>
+ <file name="protractor.js" type="protractor">
+ var value = element(by.binding('example.value | date: "HH:mm:ss"'));
+ var valid = element(by.binding('myForm.input.$valid'));
+ var input = element(by.model('example.value'));
+
+ // currently protractor/webdriver does not support
+ // sending keys to all known HTML5 input controls
+ // for various browsers (https://github.com/angular/protractor/issues/562).
+ function setInput(val) {
+ // set the value of the element and force validation.
+ var scr = "var ipt = document.getElementById('exampleInput'); " +
+ "ipt.value = '" + val + "';" +
+ "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
+ browser.executeScript(scr);
+ }
+
+ it('should initialize to model', function() {
+ expect(value.getText()).toContain('14:57:00');
+ expect(valid.getText()).toContain('myForm.input.$valid = true');
+ });
+
+ it('should be invalid if empty', function() {
+ setInput('');
+ expect(value.getText()).toEqual('value =');
+ expect(valid.getText()).toContain('myForm.input.$valid = false');
+ });
+
+ it('should be invalid if over max', function() {
+ setInput('23:59:00');
+ expect(value.getText()).toContain('');
+ expect(valid.getText()).toContain('myForm.input.$valid = false');
+ });
+ </file>
+ </example>
+ */
+ 'time': createDateInputType('time', TIME_REGEXP,
+ createDateParser(TIME_REGEXP, ['HH', 'mm', 'ss', 'sss']),
+ 'HH:mm:ss.sss'),
+
+ /**
+ * @ngdoc input
+ * @name input[week]
+ *
+ * @description
+ * Input with week-of-the-year validation and transformation to Date. In browsers that do not yet support
+ * the HTML5 week input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
+ * week format (yyyy-W##), for example: `2013-W02`.
+ *
+ * The model must always be a Date object, otherwise Angular will throw an error.
+ * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
+ *
+ * The timezone to be used to read/write the `Date` instance in the model can be defined using
+ * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
+ *
+ * @param {string} ngModel Assignable angular expression to data-bind to.
+ * @param {string=} name Property name of the form under which the control is published.
+ * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be a
+ * valid ISO week format (yyyy-W##).
+ * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. This must be
+ * a valid ISO week format (yyyy-W##).
+ * @param {string=} required Sets `required` validation error key if the value is not entered.
+ * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
+ * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
+ * `required` when you want to data-bind to the `required` attribute.
+ * @param {string=} ngChange Angular expression to be executed when input changes due to user
+ * interaction with the input element.
+ *
+ * @example
+ <example name="week-input-directive" module="weekExample">
+ <file name="index.html">
+ <script>
+ angular.module('weekExample', [])
+ .controller('DateController', ['$scope', function($scope) {
+ $scope.example = {
+ value: new Date(2013, 0, 3)
+ };
+ }]);
+ </script>
+ <form name="myForm" ng-controller="DateController as dateCtrl">
+ <label>Pick a date between in 2013:
+ <input id="exampleInput" type="week" name="input" ng-model="example.value"
+ placeholder="YYYY-W##" min="2012-W32"
+ max="2013-W52" required />
+ </label>
+ <div role="alert">
+ <span class="error" ng-show="myForm.input.$error.required">
+ Required!</span>
+ <span class="error" ng-show="myForm.input.$error.week">
+ Not a valid date!</span>
+ </div>
+ <tt>value = {{example.value | date: "yyyy-Www"}}</tt><br/>
+ <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
+ <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
+ <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
+ <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
+ </form>
+ </file>
+ <file name="protractor.js" type="protractor">
+ var value = element(by.binding('example.value | date: "yyyy-Www"'));
+ var valid = element(by.binding('myForm.input.$valid'));
+ var input = element(by.model('example.value'));
+
+ // currently protractor/webdriver does not support
+ // sending keys to all known HTML5 input controls
+ // for various browsers (https://github.com/angular/protractor/issues/562).
+ function setInput(val) {
+ // set the value of the element and force validation.
+ var scr = "var ipt = document.getElementById('exampleInput'); " +
+ "ipt.value = '" + val + "';" +
+ "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
+ browser.executeScript(scr);
+ }
+
+ it('should initialize to model', function() {
+ expect(value.getText()).toContain('2013-W01');
+ expect(valid.getText()).toContain('myForm.input.$valid = true');
+ });
+
+ it('should be invalid if empty', function() {
+ setInput('');
+ expect(value.getText()).toEqual('value =');
+ expect(valid.getText()).toContain('myForm.input.$valid = false');
+ });
+
+ it('should be invalid if over max', function() {
+ setInput('2015-W01');
+ expect(value.getText()).toContain('');
+ expect(valid.getText()).toContain('myForm.input.$valid = false');
+ });
+ </file>
+ </example>
+ */
+ 'week': createDateInputType('week', WEEK_REGEXP, weekParser, 'yyyy-Www'),
+
+ /**
+ * @ngdoc input
+ * @name input[month]
+ *
+ * @description
+ * Input with month validation and transformation. In browsers that do not yet support
+ * the HTML5 month input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
+ * month format (yyyy-MM), for example: `2009-01`.
+ *
+ * The model must always be a Date object, otherwise Angular will throw an error.
+ * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
+ * If the model is not set to the first of the month, the next view to model update will set it
+ * to the first of the month.
+ *
+ * The timezone to be used to read/write the `Date` instance in the model can be defined using
+ * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
+ *
+ * @param {string} ngModel Assignable angular expression to data-bind to.
+ * @param {string=} name Property name of the form under which the control is published.
+ * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be
+ * a valid ISO month format (yyyy-MM).
+ * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. This must
+ * be a valid ISO month format (yyyy-MM).
+ * @param {string=} required Sets `required` validation error key if the value is not entered.
+ * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
+ * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
+ * `required` when you want to data-bind to the `required` attribute.
+ * @param {string=} ngChange Angular expression to be executed when input changes due to user
+ * interaction with the input element.
+ *
+ * @example
+ <example name="month-input-directive" module="monthExample">
+ <file name="index.html">
+ <script>
+ angular.module('monthExample', [])
+ .controller('DateController', ['$scope', function($scope) {
+ $scope.example = {
+ value: new Date(2013, 9, 1)
+ };
+ }]);
+ </script>
+ <form name="myForm" ng-controller="DateController as dateCtrl">
+ <label for="exampleInput">Pick a month in 2013:</label>
+ <input id="exampleInput" type="month" name="input" ng-model="example.value"
+ placeholder="yyyy-MM" min="2013-01" max="2013-12" required />
+ <div role="alert">
+ <span class="error" ng-show="myForm.input.$error.required">
+ Required!</span>
+ <span class="error" ng-show="myForm.input.$error.month">
+ Not a valid month!</span>
+ </div>
+ <tt>value = {{example.value | date: "yyyy-MM"}}</tt><br/>
+ <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
+ <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
+ <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
+ <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
+ </form>
+ </file>
+ <file name="protractor.js" type="protractor">
+ var value = element(by.binding('example.value | date: "yyyy-MM"'));
+ var valid = element(by.binding('myForm.input.$valid'));
+ var input = element(by.model('example.value'));
+
+ // currently protractor/webdriver does not support
+ // sending keys to all known HTML5 input controls
+ // for various browsers (https://github.com/angular/protractor/issues/562).
+ function setInput(val) {
+ // set the value of the element and force validation.
+ var scr = "var ipt = document.getElementById('exampleInput'); " +
+ "ipt.value = '" + val + "';" +
+ "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
+ browser.executeScript(scr);
+ }
+
+ it('should initialize to model', function() {
+ expect(value.getText()).toContain('2013-10');
+ expect(valid.getText()).toContain('myForm.input.$valid = true');
+ });
+
+ it('should be invalid if empty', function() {
+ setInput('');
+ expect(value.getText()).toEqual('value =');
+ expect(valid.getText()).toContain('myForm.input.$valid = false');
+ });
+
+ it('should be invalid if over max', function() {
+ setInput('2015-01');
+ expect(value.getText()).toContain('');
+ expect(valid.getText()).toContain('myForm.input.$valid = false');
+ });
+ </file>
+ </example>
+ */
+ 'month': createDateInputType('month', MONTH_REGEXP,
+ createDateParser(MONTH_REGEXP, ['yyyy', 'MM']),
+ 'yyyy-MM'),
/**
* @ngdoc input
@@ -16750,6 +20979,22 @@ var inputType = {
* Text input with number validation and transformation. Sets the `number` validation
* error if not a valid number.
*
+ * <div class="alert alert-warning">
+ * The model must always be of type `number` otherwise Angular will throw an error.
+ * Be aware that a string containing a number is not enough. See the {@link ngModel:numfmt}
+ * error docs for more information and an example of how to convert your model if necessary.
+ * </div>
+ *
+ * ## Issues with HTML5 constraint validation
+ *
+ * In browsers that follow the
+ * [HTML5 specification](https://html.spec.whatwg.org/multipage/forms.html#number-state-%28type=number%29),
+ * `input[number]` does not work as expected with {@link ngModelOptions `ngModelOptions.allowInvalid`}.
+ * If a non-number is entered in the input, the browser will report the value as an empty string,
+ * which means the view / model values in `ngModel` and subsequently the scope value
+ * will also be an empty string.
+ *
+ *
* @param {string} ngModel Assignable angular expression to data-bind to.
* @param {string=} name Property name of the form under which the control is published.
* @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
@@ -16761,10 +21006,20 @@ var inputType = {
* @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
* minlength.
* @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
- * maxlength.
- * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
- * RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
- * patterns defined as scope expressions.
+ * maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
+ * any length.
+ * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
+ * that contains the regular expression body that will be converted to a regular expression
+ * as in the ngPattern directive.
+ * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
+ * a RegExp found by evaluating the Angular expression given in the attribute value.
+ * If the expression evaluates to a RegExp object, then this is used directly.
+ * If the expression evaluates to a string, then it will be converted to a RegExp
+ * after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
+ * `new RegExp('^abc$')`.<br />
+ * **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
+ * start at the index of the last search's match, thus not taking the whole input value into
+ * account.
* @param {string=} ngChange Angular expression to be executed when input changes due to user
* interaction with the input element.
*
@@ -16774,17 +21029,23 @@ var inputType = {
<script>
angular.module('numberExample', [])
.controller('ExampleController', ['$scope', function($scope) {
- $scope.value = 12;
+ $scope.example = {
+ value: 12
+ };
}]);
</script>
<form name="myForm" ng-controller="ExampleController">
- Number: <input type="number" name="input" ng-model="value"
- min="0" max="99" required>
- <span class="error" ng-show="myForm.input.$error.required">
- Required!</span>
- <span class="error" ng-show="myForm.input.$error.number">
- Not valid number!</span>
- <tt>value = {{value}}</tt><br/>
+ <label>Number:
+ <input type="number" name="input" ng-model="example.value"
+ min="0" max="99" required>
+ </label>
+ <div role="alert">
+ <span class="error" ng-show="myForm.input.$error.required">
+ Required!</span>
+ <span class="error" ng-show="myForm.input.$error.number">
+ Not valid number!</span>
+ </div>
+ <tt>value = {{example.value}}</tt><br/>
<tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
<tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
<tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
@@ -16792,9 +21053,9 @@ var inputType = {
</form>
</file>
<file name="protractor.js" type="protractor">
- var value = element(by.binding('value'));
+ var value = element(by.binding('example.value'));
var valid = element(by.binding('myForm.input.$valid'));
- var input = element(by.model('value'));
+ var input = element(by.model('example.value'));
it('should initialize to model', function() {
expect(value.getText()).toContain('12');
@@ -16828,6 +21089,12 @@ var inputType = {
* Text input with URL validation. Sets the `url` validation error key if the content is not a
* valid URL.
*
+ * <div class="alert alert-warning">
+ * **Note:** `input[url]` uses a regex to validate urls that is derived from the regex
+ * used in Chromium. If you need stricter validation, you can use `ng-pattern` or modify
+ * the built-in validators (see the {@link guide/forms Forms guide})
+ * </div>
+ *
* @param {string} ngModel Assignable angular expression to data-bind to.
* @param {string=} name Property name of the form under which the control is published.
* @param {string=} required Sets `required` validation error key if the value is not entered.
@@ -16837,10 +21104,20 @@ var inputType = {
* @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
* minlength.
* @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
- * maxlength.
- * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
- * RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
- * patterns defined as scope expressions.
+ * maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
+ * any length.
+ * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
+ * that contains the regular expression body that will be converted to a regular expression
+ * as in the ngPattern directive.
+ * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
+ * a RegExp found by evaluating the Angular expression given in the attribute value.
+ * If the expression evaluates to a RegExp object, then this is used directly.
+ * If the expression evaluates to a string, then it will be converted to a RegExp
+ * after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
+ * `new RegExp('^abc$')`.<br />
+ * **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
+ * start at the index of the last search's match, thus not taking the whole input value into
+ * account.
* @param {string=} ngChange Angular expression to be executed when input changes due to user
* interaction with the input element.
*
@@ -16850,16 +21127,22 @@ var inputType = {
<script>
angular.module('urlExample', [])
.controller('ExampleController', ['$scope', function($scope) {
- $scope.text = 'http://google.com';
+ $scope.url = {
+ text: 'http://google.com'
+ };
}]);
</script>
<form name="myForm" ng-controller="ExampleController">
- URL: <input type="url" name="input" ng-model="text" required>
- <span class="error" ng-show="myForm.input.$error.required">
- Required!</span>
- <span class="error" ng-show="myForm.input.$error.url">
- Not valid url!</span>
- <tt>text = {{text}}</tt><br/>
+ <label>URL:
+ <input type="url" name="input" ng-model="url.text" required>
+ <label>
+ <div role="alert">
+ <span class="error" ng-show="myForm.input.$error.required">
+ Required!</span>
+ <span class="error" ng-show="myForm.input.$error.url">
+ Not valid url!</span>
+ </div>
+ <tt>text = {{url.text}}</tt><br/>
<tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
<tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
<tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
@@ -16868,9 +21151,9 @@ var inputType = {
</form>
</file>
<file name="protractor.js" type="protractor">
- var text = element(by.binding('text'));
+ var text = element(by.binding('url.text'));
var valid = element(by.binding('myForm.input.$valid'));
- var input = element(by.model('text'));
+ var input = element(by.model('url.text'));
it('should initialize to model', function() {
expect(text.getText()).toContain('http://google.com');
@@ -16905,6 +21188,12 @@ var inputType = {
* Text input with email validation. Sets the `email` validation error key if not a valid email
* address.
*
+ * <div class="alert alert-warning">
+ * **Note:** `input[email]` uses a regex to validate email addresses that is derived from the regex
+ * used in Chromium. If you need stricter validation (e.g. requiring a top-level domain), you can
+ * use `ng-pattern` or modify the built-in validators (see the {@link guide/forms Forms guide})
+ * </div>
+ *
* @param {string} ngModel Assignable angular expression to data-bind to.
* @param {string=} name Property name of the form under which the control is published.
* @param {string=} required Sets `required` validation error key if the value is not entered.
@@ -16914,10 +21203,20 @@ var inputType = {
* @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
* minlength.
* @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
- * maxlength.
- * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
- * RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
- * patterns defined as scope expressions.
+ * maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
+ * any length.
+ * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
+ * that contains the regular expression body that will be converted to a regular expression
+ * as in the ngPattern directive.
+ * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
+ * a RegExp found by evaluating the Angular expression given in the attribute value.
+ * If the expression evaluates to a RegExp object, then this is used directly.
+ * If the expression evaluates to a string, then it will be converted to a RegExp
+ * after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
+ * `new RegExp('^abc$')`.<br />
+ * **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
+ * start at the index of the last search's match, thus not taking the whole input value into
+ * account.
* @param {string=} ngChange Angular expression to be executed when input changes due to user
* interaction with the input element.
*
@@ -16927,16 +21226,22 @@ var inputType = {
<script>
angular.module('emailExample', [])
.controller('ExampleController', ['$scope', function($scope) {
- $scope.text = 'me@example.com';
+ $scope.email = {
+ text: 'me@example.com'
+ };
}]);
</script>
<form name="myForm" ng-controller="ExampleController">
- Email: <input type="email" name="input" ng-model="text" required>
- <span class="error" ng-show="myForm.input.$error.required">
- Required!</span>
- <span class="error" ng-show="myForm.input.$error.email">
- Not valid email!</span>
- <tt>text = {{text}}</tt><br/>
+ <label>Email:
+ <input type="email" name="input" ng-model="email.text" required>
+ </label>
+ <div role="alert">
+ <span class="error" ng-show="myForm.input.$error.required">
+ Required!</span>
+ <span class="error" ng-show="myForm.input.$error.email">
+ Not valid email!</span>
+ </div>
+ <tt>text = {{email.text}}</tt><br/>
<tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
<tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
<tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
@@ -16945,9 +21250,9 @@ var inputType = {
</form>
</file>
<file name="protractor.js" type="protractor">
- var text = element(by.binding('text'));
+ var text = element(by.binding('email.text'));
var valid = element(by.binding('myForm.input.$valid'));
- var input = element(by.model('text'));
+ var input = element(by.model('email.text'));
it('should initialize to model', function() {
expect(text.getText()).toContain('me@example.com');
@@ -16981,12 +21286,15 @@ var inputType = {
* HTML radio button.
*
* @param {string} ngModel Assignable angular expression to data-bind to.
- * @param {string} value The value to which the expression should be set when selected.
+ * @param {string} value The value to which the `ngModel` expression should be set when selected.
+ * Note that `value` only supports `string` values, i.e. the scope model needs to be a string,
+ * too. Use `ngValue` if you need complex models (`number`, `object`, ...).
* @param {string=} name Property name of the form under which the control is published.
* @param {string=} ngChange Angular expression to be executed when input changes due to user
* interaction with the input element.
- * @param {string} ngValue Angular expression which sets the value to which the expression should
- * be set when selected.
+ * @param {string} ngValue Angular expression to which `ngModel` will be be set when the radio
+ * is selected. Should be used instead of the `value` attribute if you need
+ * a non-string `ngModel` (`boolean`, `array`, ...).
*
* @example
<example name="radio-input-directive" module="radioExample">
@@ -16994,7 +21302,9 @@ var inputType = {
<script>
angular.module('radioExample', [])
.controller('ExampleController', ['$scope', function($scope) {
- $scope.color = 'blue';
+ $scope.color = {
+ name: 'blue'
+ };
$scope.specialValue = {
"id": "12345",
"value": "green"
@@ -17002,20 +21312,29 @@ var inputType = {
}]);
</script>
<form name="myForm" ng-controller="ExampleController">
- <input type="radio" ng-model="color" value="red"> Red <br/>
- <input type="radio" ng-model="color" ng-value="specialValue"> Green <br/>
- <input type="radio" ng-model="color" value="blue"> Blue <br/>
- <tt>color = {{color | json}}</tt><br/>
+ <label>
+ <input type="radio" ng-model="color.name" value="red">
+ Red
+ </label><br/>
+ <label>
+ <input type="radio" ng-model="color.name" ng-value="specialValue">
+ Green
+ </label><br/>
+ <label>
+ <input type="radio" ng-model="color.name" value="blue">
+ Blue
+ </label><br/>
+ <tt>color = {{color.name | json}}</tt><br/>
</form>
Note that `ng-value="specialValue"` sets radio item's value to be the value of `$scope.specialValue`.
</file>
<file name="protractor.js" type="protractor">
it('should change state', function() {
- var color = element(by.binding('color'));
+ var color = element(by.binding('color.name'));
expect(color.getText()).toContain('blue');
- element.all(by.model('color')).get(0).click();
+ element.all(by.model('color.name')).get(0).click();
expect(color.getText()).toContain('red');
});
@@ -17034,8 +21353,8 @@ var inputType = {
*
* @param {string} ngModel Assignable angular expression to data-bind to.
* @param {string=} name Property name of the form under which the control is published.
- * @param {string=} ngTrueValue The value to which the expression should be set when selected.
- * @param {string=} ngFalseValue The value to which the expression should be set when not selected.
+ * @param {expression=} ngTrueValue The value to which the expression should be set when selected.
+ * @param {expression=} ngFalseValue The value to which the expression should be set when not selected.
* @param {string=} ngChange Angular expression to be executed when input changes due to user
* interaction with the input element.
*
@@ -17045,28 +21364,34 @@ var inputType = {
<script>
angular.module('checkboxExample', [])
.controller('ExampleController', ['$scope', function($scope) {
- $scope.value1 = true;
- $scope.value2 = 'YES'
+ $scope.checkboxModel = {
+ value1 : true,
+ value2 : 'YES'
+ };
}]);
</script>
<form name="myForm" ng-controller="ExampleController">
- Value1: <input type="checkbox" ng-model="value1"> <br/>
- Value2: <input type="checkbox" ng-model="value2"
- ng-true-value="YES" ng-false-value="NO"> <br/>
- <tt>value1 = {{value1}}</tt><br/>
- <tt>value2 = {{value2}}</tt><br/>
+ <label>Value1:
+ <input type="checkbox" ng-model="checkboxModel.value1">
+ </label><br/>
+ <label>Value2:
+ <input type="checkbox" ng-model="checkboxModel.value2"
+ ng-true-value="'YES'" ng-false-value="'NO'">
+ </label><br/>
+ <tt>value1 = {{checkboxModel.value1}}</tt><br/>
+ <tt>value2 = {{checkboxModel.value2}}</tt><br/>
</form>
</file>
<file name="protractor.js" type="protractor">
it('should change state', function() {
- var value1 = element(by.binding('value1'));
- var value2 = element(by.binding('value2'));
+ var value1 = element(by.binding('checkboxModel.value1'));
+ var value2 = element(by.binding('checkboxModel.value2'));
expect(value1.getText()).toContain('true');
expect(value2.getText()).toContain('YES');
- element(by.model('value1')).click();
- element(by.model('value2')).click();
+ element(by.model('checkboxModel.value1')).click();
+ element(by.model('checkboxModel.value2')).click();
expect(value1.getText()).toContain('false');
expect(value2.getText()).toContain('NO');
@@ -17083,50 +21408,19 @@ var inputType = {
'file': noop
};
-// A helper function to call $setValidity and return the value / undefined,
-// a pattern that is repeated a lot in the input validation logic.
-function validate(ctrl, validatorName, validity, value){
- ctrl.$setValidity(validatorName, validity);
- return validity ? value : undefined;
-}
-
-function testFlags(validity, flags) {
- var i, flag;
- if (flags) {
- for (i=0; i<flags.length; ++i) {
- flag = flags[i];
- if (validity[flag]) {
- return true;
- }
- }
- }
- return false;
+function stringBasedInputType(ctrl) {
+ ctrl.$formatters.push(function(value) {
+ return ctrl.$isEmpty(value) ? value : value.toString();
+ });
}
-// Pass validity so that behaviour can be mocked easier.
-function addNativeHtml5Validators(ctrl, validatorName, badFlags, ignoreFlags, validity) {
- if (isObject(validity)) {
- ctrl.$$hasNativeValidators = true;
- var validator = function(value) {
- // Don't overwrite previous validation, don't consider valueMissing to apply (ng-required can
- // perform the required validation)
- if (!ctrl.$error[validatorName] &&
- !testFlags(validity, ignoreFlags) &&
- testFlags(validity, badFlags)) {
- ctrl.$setValidity(validatorName, false);
- return;
- }
- return value;
- };
- ctrl.$parsers.push(validator);
- }
+function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
+ baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
+ stringBasedInputType(ctrl);
}
-function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
- var validity = element.prop(VALIDITY_STATE_PROPERTY);
- var placeholder = element[0].placeholder, noevent = {};
+function baseInputType(scope, element, attr, ctrl, $sniffer, $browser) {
var type = lowercase(element[0].type);
- ctrl.$$validityState = validity;
// In composition mode, users are still inputing intermediate text buffer,
// hold the listener until composition is done.
@@ -17145,37 +21439,26 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
}
var listener = function(ev) {
- if (composing) return;
- var value = element.val();
-
- // IE (11 and under) seem to emit an 'input' event if the placeholder value changes.
- // We don't want to dirty the value when this happens, so we abort here. Unfortunately,
- // IE also sends input events for other non-input-related things, (such as focusing on a
- // form control), so this change is not entirely enough to solve this.
- if (msie && (ev || noevent).type === 'input' && element[0].placeholder !== placeholder) {
- placeholder = element[0].placeholder;
- return;
+ if (timeout) {
+ $browser.defer.cancel(timeout);
+ timeout = null;
}
+ if (composing) return;
+ var value = element.val(),
+ event = ev && ev.type;
// By default we will trim the value
// If the attribute ng-trim exists we will avoid trimming
// If input type is 'password', the value is never trimmed
- if (type !== 'password' && (toBoolean(attr.ngTrim || 'T'))) {
+ if (type !== 'password' && (!attr.ngTrim || attr.ngTrim !== 'false')) {
value = trim(value);
}
- // If a control is suffering from bad input, browsers discard its value, so it may be
- // necessary to revalidate even if the control's value is the same empty value twice in
- // a row.
- var revalidate = validity && ctrl.$$hasNativeValidators;
- if (ctrl.$viewValue !== value || (value === '' && revalidate)) {
- if (scope.$root.$$phase) {
- ctrl.$setViewValue(value);
- } else {
- scope.$apply(function() {
- ctrl.$setViewValue(value);
- });
- }
+ // If a control is suffering from bad input (due to native validators), browsers discard its
+ // value, so it may be necessary to revalidate (by calling $setViewValue again) even if the
+ // control's value is the same empty value twice in a row.
+ if (ctrl.$viewValue !== value || (value === '' && ctrl.$$hasNativeValidators)) {
+ ctrl.$setViewValue(value, event);
}
};
@@ -17186,11 +21469,13 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
} else {
var timeout;
- var deferListener = function() {
+ var deferListener = function(ev, input, origValue) {
if (!timeout) {
timeout = $browser.defer(function() {
- listener();
timeout = null;
+ if (!input || input.value !== origValue) {
+ listener(ev);
+ }
});
}
};
@@ -17202,7 +21487,7 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
// command modifiers arrows
if (key === 91 || (15 < key && key < 19) || (37 <= key && key <= 40)) return;
- deferListener();
+ deferListener(event, this, this.value);
});
// if user modifies input value using context menu in IE, we need "paste" and "cut" events to catch it
@@ -17218,129 +21503,255 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
ctrl.$render = function() {
element.val(ctrl.$isEmpty(ctrl.$viewValue) ? '' : ctrl.$viewValue);
};
+}
- // pattern validator
- var pattern = attr.ngPattern,
- patternValidator,
- match;
+function weekParser(isoWeek, existingDate) {
+ if (isDate(isoWeek)) {
+ return isoWeek;
+ }
- if (pattern) {
- var validateRegex = function(regexp, value) {
- return validate(ctrl, 'pattern', ctrl.$isEmpty(value) || regexp.test(value), value);
- };
- match = pattern.match(/^\/(.*)\/([gim]*)$/);
- if (match) {
- pattern = new RegExp(match[1], match[2]);
- patternValidator = function(value) {
- return validateRegex(pattern, value);
- };
- } else {
- patternValidator = function(value) {
- var patternObj = scope.$eval(pattern);
+ if (isString(isoWeek)) {
+ WEEK_REGEXP.lastIndex = 0;
+ var parts = WEEK_REGEXP.exec(isoWeek);
+ if (parts) {
+ var year = +parts[1],
+ week = +parts[2],
+ hours = 0,
+ minutes = 0,
+ seconds = 0,
+ milliseconds = 0,
+ firstThurs = getFirstThursdayOfYear(year),
+ addDays = (week - 1) * 7;
+
+ if (existingDate) {
+ hours = existingDate.getHours();
+ minutes = existingDate.getMinutes();
+ seconds = existingDate.getSeconds();
+ milliseconds = existingDate.getMilliseconds();
+ }
- if (!patternObj || !patternObj.test) {
- throw minErr('ngPattern')('noregexp',
- 'Expected {0} to be a RegExp but was {1}. Element: {2}', pattern,
- patternObj, startingTag(element));
+ return new Date(year, 0, firstThurs.getDate() + addDays, hours, minutes, seconds, milliseconds);
+ }
+ }
+
+ return NaN;
+}
+
+function createDateParser(regexp, mapping) {
+ return function(iso, date) {
+ var parts, map;
+
+ if (isDate(iso)) {
+ return iso;
+ }
+
+ if (isString(iso)) {
+ // When a date is JSON'ified to wraps itself inside of an extra
+ // set of double quotes. This makes the date parsing code unable
+ // to match the date string and parse it as a date.
+ if (iso.charAt(0) == '"' && iso.charAt(iso.length - 1) == '"') {
+ iso = iso.substring(1, iso.length - 1);
+ }
+ if (ISO_DATE_REGEXP.test(iso)) {
+ return new Date(iso);
+ }
+ regexp.lastIndex = 0;
+ parts = regexp.exec(iso);
+
+ if (parts) {
+ parts.shift();
+ if (date) {
+ map = {
+ yyyy: date.getFullYear(),
+ MM: date.getMonth() + 1,
+ dd: date.getDate(),
+ HH: date.getHours(),
+ mm: date.getMinutes(),
+ ss: date.getSeconds(),
+ sss: date.getMilliseconds() / 1000
+ };
+ } else {
+ map = { yyyy: 1970, MM: 1, dd: 1, HH: 0, mm: 0, ss: 0, sss: 0 };
}
- return validateRegex(patternObj, value);
- };
+
+ forEach(parts, function(part, index) {
+ if (index < mapping.length) {
+ map[mapping[index]] = +part;
+ }
+ });
+ return new Date(map.yyyy, map.MM - 1, map.dd, map.HH, map.mm, map.ss || 0, map.sss * 1000 || 0);
+ }
}
- ctrl.$formatters.push(patternValidator);
- ctrl.$parsers.push(patternValidator);
- }
+ return NaN;
+ };
+}
- // min length validator
- if (attr.ngMinlength) {
- var minlength = int(attr.ngMinlength);
- var minLengthValidator = function(value) {
- return validate(ctrl, 'minlength', ctrl.$isEmpty(value) || value.length >= minlength, value);
- };
+function createDateInputType(type, regexp, parseDate, format) {
+ return function dynamicDateInputType(scope, element, attr, ctrl, $sniffer, $browser, $filter) {
+ badInputChecker(scope, element, attr, ctrl);
+ baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
+ var timezone = ctrl && ctrl.$options && ctrl.$options.timezone;
+ var previousDate;
+
+ ctrl.$$parserName = type;
+ ctrl.$parsers.push(function(value) {
+ if (ctrl.$isEmpty(value)) return null;
+ if (regexp.test(value)) {
+ // Note: We cannot read ctrl.$modelValue, as there might be a different
+ // parser/formatter in the processing chain so that the model
+ // contains some different data format!
+ var parsedDate = parseDate(value, previousDate);
+ if (timezone) {
+ parsedDate = convertTimezoneToLocal(parsedDate, timezone);
+ }
+ return parsedDate;
+ }
+ return undefined;
+ });
- ctrl.$parsers.push(minLengthValidator);
- ctrl.$formatters.push(minLengthValidator);
- }
+ ctrl.$formatters.push(function(value) {
+ if (value && !isDate(value)) {
+ throw $ngModelMinErr('datefmt', 'Expected `{0}` to be a date', value);
+ }
+ if (isValidDate(value)) {
+ previousDate = value;
+ if (previousDate && timezone) {
+ previousDate = convertTimezoneToLocal(previousDate, timezone, true);
+ }
+ return $filter('date')(value, format, timezone);
+ } else {
+ previousDate = null;
+ return '';
+ }
+ });
- // max length validator
- if (attr.ngMaxlength) {
- var maxlength = int(attr.ngMaxlength);
- var maxLengthValidator = function(value) {
- return validate(ctrl, 'maxlength', ctrl.$isEmpty(value) || value.length <= maxlength, value);
- };
+ if (isDefined(attr.min) || attr.ngMin) {
+ var minVal;
+ ctrl.$validators.min = function(value) {
+ return !isValidDate(value) || isUndefined(minVal) || parseDate(value) >= minVal;
+ };
+ attr.$observe('min', function(val) {
+ minVal = parseObservedDateValue(val);
+ ctrl.$validate();
+ });
+ }
- ctrl.$parsers.push(maxLengthValidator);
- ctrl.$formatters.push(maxLengthValidator);
- }
+ if (isDefined(attr.max) || attr.ngMax) {
+ var maxVal;
+ ctrl.$validators.max = function(value) {
+ return !isValidDate(value) || isUndefined(maxVal) || parseDate(value) <= maxVal;
+ };
+ attr.$observe('max', function(val) {
+ maxVal = parseObservedDateValue(val);
+ ctrl.$validate();
+ });
+ }
+
+ function isValidDate(value) {
+ // Invalid Date: getTime() returns NaN
+ return value && !(value.getTime && value.getTime() !== value.getTime());
+ }
+
+ function parseObservedDateValue(val) {
+ return isDefined(val) ? (isDate(val) ? val : parseDate(val)) : undefined;
+ }
+ };
}
-var numberBadFlags = ['badInput'];
+function badInputChecker(scope, element, attr, ctrl) {
+ var node = element[0];
+ var nativeValidation = ctrl.$$hasNativeValidators = isObject(node.validity);
+ if (nativeValidation) {
+ ctrl.$parsers.push(function(value) {
+ var validity = element.prop(VALIDITY_STATE_PROPERTY) || {};
+ // Detect bug in FF35 for input[email] (https://bugzilla.mozilla.org/show_bug.cgi?id=1064430):
+ // - also sets validity.badInput (should only be validity.typeMismatch).
+ // - see http://www.whatwg.org/specs/web-apps/current-work/multipage/forms.html#e-mail-state-(type=email)
+ // - can ignore this case as we can still read out the erroneous email...
+ return validity.badInput && !validity.typeMismatch ? undefined : value;
+ });
+ }
+}
function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
- textInputType(scope, element, attr, ctrl, $sniffer, $browser);
+ badInputChecker(scope, element, attr, ctrl);
+ baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
+ ctrl.$$parserName = 'number';
ctrl.$parsers.push(function(value) {
- var empty = ctrl.$isEmpty(value);
- if (empty || NUMBER_REGEXP.test(value)) {
- ctrl.$setValidity('number', true);
- return value === '' ? null : (empty ? value : parseFloat(value));
- } else {
- ctrl.$setValidity('number', false);
- return undefined;
- }
+ if (ctrl.$isEmpty(value)) return null;
+ if (NUMBER_REGEXP.test(value)) return parseFloat(value);
+ return undefined;
});
- addNativeHtml5Validators(ctrl, 'number', numberBadFlags, null, ctrl.$$validityState);
-
ctrl.$formatters.push(function(value) {
- return ctrl.$isEmpty(value) ? '' : '' + value;
+ if (!ctrl.$isEmpty(value)) {
+ if (!isNumber(value)) {
+ throw $ngModelMinErr('numfmt', 'Expected `{0}` to be a number', value);
+ }
+ value = value.toString();
+ }
+ return value;
});
- if (attr.min) {
- var minValidator = function(value) {
- var min = parseFloat(attr.min);
- return validate(ctrl, 'min', ctrl.$isEmpty(value) || value >= min, value);
+ if (isDefined(attr.min) || attr.ngMin) {
+ var minVal;
+ ctrl.$validators.min = function(value) {
+ return ctrl.$isEmpty(value) || isUndefined(minVal) || value >= minVal;
};
- ctrl.$parsers.push(minValidator);
- ctrl.$formatters.push(minValidator);
+ attr.$observe('min', function(val) {
+ if (isDefined(val) && !isNumber(val)) {
+ val = parseFloat(val, 10);
+ }
+ minVal = isNumber(val) && !isNaN(val) ? val : undefined;
+ // TODO(matsko): implement validateLater to reduce number of validations
+ ctrl.$validate();
+ });
}
- if (attr.max) {
- var maxValidator = function(value) {
- var max = parseFloat(attr.max);
- return validate(ctrl, 'max', ctrl.$isEmpty(value) || value <= max, value);
+ if (isDefined(attr.max) || attr.ngMax) {
+ var maxVal;
+ ctrl.$validators.max = function(value) {
+ return ctrl.$isEmpty(value) || isUndefined(maxVal) || value <= maxVal;
};
- ctrl.$parsers.push(maxValidator);
- ctrl.$formatters.push(maxValidator);
+ attr.$observe('max', function(val) {
+ if (isDefined(val) && !isNumber(val)) {
+ val = parseFloat(val, 10);
+ }
+ maxVal = isNumber(val) && !isNaN(val) ? val : undefined;
+ // TODO(matsko): implement validateLater to reduce number of validations
+ ctrl.$validate();
+ });
}
-
- ctrl.$formatters.push(function(value) {
- return validate(ctrl, 'number', ctrl.$isEmpty(value) || isNumber(value), value);
- });
}
function urlInputType(scope, element, attr, ctrl, $sniffer, $browser) {
- textInputType(scope, element, attr, ctrl, $sniffer, $browser);
-
- var urlValidator = function(value) {
- return validate(ctrl, 'url', ctrl.$isEmpty(value) || URL_REGEXP.test(value), value);
+ // Note: no badInputChecker here by purpose as `url` is only a validation
+ // in browsers, i.e. we can always read out input.value even if it is not valid!
+ baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
+ stringBasedInputType(ctrl);
+
+ ctrl.$$parserName = 'url';
+ ctrl.$validators.url = function(modelValue, viewValue) {
+ var value = modelValue || viewValue;
+ return ctrl.$isEmpty(value) || URL_REGEXP.test(value);
};
-
- ctrl.$formatters.push(urlValidator);
- ctrl.$parsers.push(urlValidator);
}
function emailInputType(scope, element, attr, ctrl, $sniffer, $browser) {
- textInputType(scope, element, attr, ctrl, $sniffer, $browser);
-
- var emailValidator = function(value) {
- return validate(ctrl, 'email', ctrl.$isEmpty(value) || EMAIL_REGEXP.test(value), value);
+ // Note: no badInputChecker here by purpose as `url` is only a validation
+ // in browsers, i.e. we can always read out input.value even if it is not valid!
+ baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
+ stringBasedInputType(ctrl);
+
+ ctrl.$$parserName = 'email';
+ ctrl.$validators.email = function(modelValue, viewValue) {
+ var value = modelValue || viewValue;
+ return ctrl.$isEmpty(value) || EMAIL_REGEXP.test(value);
};
-
- ctrl.$formatters.push(emailValidator);
- ctrl.$parsers.push(emailValidator);
}
function radioInputType(scope, element, attr, ctrl) {
@@ -17349,13 +21760,13 @@ function radioInputType(scope, element, attr, ctrl) {
element.attr('name', nextUid());
}
- element.on('click', function() {
+ var listener = function(ev) {
if (element[0].checked) {
- scope.$apply(function() {
- ctrl.$setViewValue(attr.value);
- });
+ ctrl.$setViewValue(attr.value, ev && ev.type);
}
- });
+ };
+
+ element.on('click', listener);
ctrl.$render = function() {
var value = attr.value;
@@ -17365,30 +21776,42 @@ function radioInputType(scope, element, attr, ctrl) {
attr.$observe('value', ctrl.$render);
}
-function checkboxInputType(scope, element, attr, ctrl) {
- var trueValue = attr.ngTrueValue,
- falseValue = attr.ngFalseValue;
+function parseConstantExpr($parse, context, name, expression, fallback) {
+ var parseFn;
+ if (isDefined(expression)) {
+ parseFn = $parse(expression);
+ if (!parseFn.constant) {
+ throw minErr('ngModel')('constexpr', 'Expected constant expression for `{0}`, but saw ' +
+ '`{1}`.', name, expression);
+ }
+ return parseFn(context);
+ }
+ return fallback;
+}
- if (!isString(trueValue)) trueValue = true;
- if (!isString(falseValue)) falseValue = false;
+function checkboxInputType(scope, element, attr, ctrl, $sniffer, $browser, $filter, $parse) {
+ var trueValue = parseConstantExpr($parse, scope, 'ngTrueValue', attr.ngTrueValue, true);
+ var falseValue = parseConstantExpr($parse, scope, 'ngFalseValue', attr.ngFalseValue, false);
- element.on('click', function() {
- scope.$apply(function() {
- ctrl.$setViewValue(element[0].checked);
- });
- });
+ var listener = function(ev) {
+ ctrl.$setViewValue(element[0].checked, ev && ev.type);
+ };
+
+ element.on('click', listener);
ctrl.$render = function() {
element[0].checked = ctrl.$viewValue;
};
- // Override the standard `$isEmpty` because a value of `false` means empty in a checkbox.
+ // Override the standard `$isEmpty` because the $viewValue of an empty checkbox is always set to `false`
+ // This is because of the parser below, which compares the `$modelValue` with `trueValue` to convert
+ // it to a boolean.
ctrl.$isEmpty = function(value) {
- return value !== trueValue;
+ return value === false;
};
ctrl.$formatters.push(function(value) {
- return value === trueValue;
+ return equals(value, trueValue);
});
ctrl.$parsers.push(function(value) {
@@ -17416,10 +21839,17 @@ function checkboxInputType(scope, element, attr, ctrl) {
* @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
* minlength.
* @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
- * maxlength.
- * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
- * RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
- * patterns defined as scope expressions.
+ * maxlength. Setting the attribute to a negative or non-numeric value, allows view values of any
+ * length.
+ * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
+ * a RegExp found by evaluating the Angular expression given in the attribute value.
+ * If the expression evaluates to a RegExp object, then this is used directly.
+ * If the expression evaluates to a string, then it will be converted to a RegExp
+ * after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
+ * `new RegExp('^abc$')`.<br />
+ * **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
+ * start at the index of the last search's match, thus not taking the whole input value into
+ * account.
* @param {string=} ngChange Angular expression to be executed when input changes due to user
* interaction with the input element.
* @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.
@@ -17432,10 +21862,14 @@ function checkboxInputType(scope, element, attr, ctrl) {
* @restrict E
*
* @description
- * HTML input element control with angular data-binding. Input control follows HTML5 input types
- * and polyfills the HTML5 validation behavior for older browsers.
+ * HTML input element control. When used together with {@link ngModel `ngModel`}, it provides data-binding,
+ * input state control, and validation.
+ * Input control follows HTML5 input types and polyfills the HTML5 validation behavior for older browsers.
*
- * *NOTE* Not every feature offered is available for all input types.
+ * <div class="alert alert-warning">
+ * **Note:** Not every feature offered is available for all input types.
+ * Specifically, data binding and event handling via `ng-model` is unsupported for `input[file]`.
+ * </div>
*
* @param {string} ngModel Assignable angular expression to data-bind to.
* @param {string=} name Property name of the form under which the control is published.
@@ -17444,10 +21878,17 @@ function checkboxInputType(scope, element, attr, ctrl) {
* @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
* minlength.
* @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
- * maxlength.
- * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
- * RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
- * patterns defined as scope expressions.
+ * maxlength. Setting the attribute to a negative or non-numeric value, allows view values of any
+ * length.
+ * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
+ * a RegExp found by evaluating the Angular expression given in the attribute value.
+ * If the expression evaluates to a RegExp object, then this is used directly.
+ * If the expression evaluates to a string, then it will be converted to a RegExp
+ * after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
+ * `new RegExp('^abc$')`.<br />
+ * **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
+ * start at the index of the last search's match, thus not taking the whole input value into
+ * account.
* @param {string=} ngChange Angular expression to be executed when input changes due to user
* interaction with the input element.
* @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.
@@ -17465,30 +21906,40 @@ function checkboxInputType(scope, element, attr, ctrl) {
</script>
<div ng-controller="ExampleController">
<form name="myForm">
- User name: <input type="text" name="userName" ng-model="user.name" required>
- <span class="error" ng-show="myForm.userName.$error.required">
- Required!</span><br>
- Last name: <input type="text" name="lastName" ng-model="user.last"
- ng-minlength="3" ng-maxlength="10">
- <span class="error" ng-show="myForm.lastName.$error.minlength">
- Too short!</span>
- <span class="error" ng-show="myForm.lastName.$error.maxlength">
- Too long!</span><br>
+ <label>
+ User name:
+ <input type="text" name="userName" ng-model="user.name" required>
+ </label>
+ <div role="alert">
+ <span class="error" ng-show="myForm.userName.$error.required">
+ Required!</span>
+ </div>
+ <label>
+ Last name:
+ <input type="text" name="lastName" ng-model="user.last"
+ ng-minlength="3" ng-maxlength="10">
+ </label>
+ <div role="alert">
+ <span class="error" ng-show="myForm.lastName.$error.minlength">
+ Too short!</span>
+ <span class="error" ng-show="myForm.lastName.$error.maxlength">
+ Too long!</span>
+ </div>
</form>
<hr>
<tt>user = {{user}}</tt><br/>
- <tt>myForm.userName.$valid = {{myForm.userName.$valid}}</tt><br>
- <tt>myForm.userName.$error = {{myForm.userName.$error}}</tt><br>
- <tt>myForm.lastName.$valid = {{myForm.lastName.$valid}}</tt><br>
- <tt>myForm.lastName.$error = {{myForm.lastName.$error}}</tt><br>
- <tt>myForm.$valid = {{myForm.$valid}}</tt><br>
- <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br>
- <tt>myForm.$error.minlength = {{!!myForm.$error.minlength}}</tt><br>
- <tt>myForm.$error.maxlength = {{!!myForm.$error.maxlength}}</tt><br>
+ <tt>myForm.userName.$valid = {{myForm.userName.$valid}}</tt><br/>
+ <tt>myForm.userName.$error = {{myForm.userName.$error}}</tt><br/>
+ <tt>myForm.lastName.$valid = {{myForm.lastName.$valid}}</tt><br/>
+ <tt>myForm.lastName.$error = {{myForm.lastName.$error}}</tt><br/>
+ <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
+ <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
+ <tt>myForm.$error.minlength = {{!!myForm.$error.minlength}}</tt><br/>
+ <tt>myForm.$error.maxlength = {{!!myForm.$error.maxlength}}</tt><br/>
</div>
</file>
<file name="protractor.js" type="protractor">
- var user = element(by.binding('{{user}}'));
+ var user = element(by.exactBinding('user'));
var userNameValid = element(by.binding('myForm.userName.$valid'));
var lastNameValid = element(by.binding('myForm.lastName.$valid'));
var lastNameError = element(by.binding('myForm.lastName.$error'));
@@ -17542,682 +21993,22 @@ function checkboxInputType(scope, element, attr, ctrl) {
</file>
</example>
*/
-var inputDirective = ['$browser', '$sniffer', function($browser, $sniffer) {
+var inputDirective = ['$browser', '$sniffer', '$filter', '$parse',
+ function($browser, $sniffer, $filter, $parse) {
return {
restrict: 'E',
- require: '?ngModel',
- link: function(scope, element, attr, ctrl) {
- if (ctrl) {
- (inputType[lowercase(attr.type)] || inputType.text)(scope, element, attr, ctrl, $sniffer,
- $browser);
- }
- }
- };
-}];
-
-var VALID_CLASS = 'ng-valid',
- INVALID_CLASS = 'ng-invalid',
- PRISTINE_CLASS = 'ng-pristine',
- DIRTY_CLASS = 'ng-dirty';
-
-/**
- * @ngdoc type
- * @name ngModel.NgModelController
- *
- * @property {string} $viewValue Actual string value in the view.
- * @property {*} $modelValue The value in the model, that the control is bound to.
- * @property {Array.<Function>} $parsers Array of functions to execute, as a pipeline, whenever
- the control reads value from the DOM. Each function is called, in turn, passing the value
- through to the next. The last return value is used to populate the model.
- Used to sanitize / convert the value as well as validation. For validation,
- the parsers should update the validity state using
- {@link ngModel.NgModelController#$setValidity $setValidity()},
- and return `undefined` for invalid values.
-
- *
- * @property {Array.<Function>} $formatters Array of functions to execute, as a pipeline, whenever
- the model value changes. Each function is called, in turn, passing the value through to the
- next. Used to format / convert values for display in the control and validation.
- * ```js
- * function formatter(value) {
- * if (value) {
- * return value.toUpperCase();
- * }
- * }
- * ngModel.$formatters.push(formatter);
- * ```
- *
- * @property {Array.<Function>} $viewChangeListeners Array of functions to execute whenever the
- * view value has changed. It is called with no arguments, and its return value is ignored.
- * This can be used in place of additional $watches against the model value.
- *
- * @property {Object} $error An object hash with all errors as keys.
- *
- * @property {boolean} $pristine True if user has not interacted with the control yet.
- * @property {boolean} $dirty True if user has already interacted with the control.
- * @property {boolean} $valid True if there is no error.
- * @property {boolean} $invalid True if at least one error on the control.
- *
- * @description
- *
- * `NgModelController` provides API for the `ng-model` directive. The controller contains
- * services for data-binding, validation, CSS updates, and value formatting and parsing. It
- * purposefully does not contain any logic which deals with DOM rendering or listening to
- * DOM events. Such DOM related logic should be provided by other directives which make use of
- * `NgModelController` for data-binding.
- *
- * ## Custom Control Example
- * This example shows how to use `NgModelController` with a custom control to achieve
- * data-binding. Notice how different directives (`contenteditable`, `ng-model`, and `required`)
- * collaborate together to achieve the desired result.
- *
- * Note that `contenteditable` is an HTML5 attribute, which tells the browser to let the element
- * contents be edited in place by the user. This will not work on older browsers.
- *
- * We are using the {@link ng.service:$sce $sce} service here and include the {@link ngSanitize $sanitize}
- * module to automatically remove "bad" content like inline event listener (e.g. `<span onclick="...">`).
- * However, as we are using `$sce` the model can still decide to provide unsafe content if it marks
- * that content using the `$sce` service.
- *
- * <example name="NgModelController" module="customControl" deps="angular-sanitize.js">
- <file name="style.css">
- [contenteditable] {
- border: 1px solid black;
- background-color: white;
- min-height: 20px;
- }
-
- .ng-invalid {
- border: 1px solid red;
- }
-
- </file>
- <file name="script.js">
- angular.module('customControl', ['ngSanitize']).
- directive('contenteditable', ['$sce', function($sce) {
- return {
- restrict: 'A', // only activate on element attribute
- require: '?ngModel', // get a hold of NgModelController
- link: function(scope, element, attrs, ngModel) {
- if(!ngModel) return; // do nothing if no ng-model
-
- // Specify how UI should be updated
- ngModel.$render = function() {
- element.html($sce.getTrustedHtml(ngModel.$viewValue || ''));
- };
-
- // Listen for change events to enable binding
- element.on('blur keyup change', function() {
- scope.$evalAsync(read);
- });
- read(); // initialize
-
- // Write data to the model
- function read() {
- var html = element.html();
- // When we clear the content editable the browser leaves a <br> behind
- // If strip-br attribute is provided then we strip this out
- if( attrs.stripBr && html == '<br>' ) {
- html = '';
- }
- ngModel.$setViewValue(html);
- }
- }
- };
- }]);
- </file>
- <file name="index.html">
- <form name="myForm">
- <div contenteditable
- name="myWidget" ng-model="userContent"
- strip-br="true"
- required>Change me!</div>
- <span ng-show="myForm.myWidget.$error.required">Required!</span>
- <hr>
- <textarea ng-model="userContent"></textarea>
- </form>
- </file>
- <file name="protractor.js" type="protractor">
- it('should data-bind and become invalid', function() {
- if (browser.params.browser == 'safari' || browser.params.browser == 'firefox') {
- // SafariDriver can't handle contenteditable
- // and Firefox driver can't clear contenteditables very well
- return;
- }
- var contentEditable = element(by.css('[contenteditable]'));
- var content = 'Change me!';
-
- expect(contentEditable.getText()).toEqual(content);
-
- contentEditable.clear();
- contentEditable.sendKeys(protractor.Key.BACK_SPACE);
- expect(contentEditable.getText()).toEqual('');
- expect(contentEditable.getAttribute('class')).toMatch(/ng-invalid-required/);
- });
- </file>
- * </example>
- *
- *
- */
-var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$parse', '$animate',
- function($scope, $exceptionHandler, $attr, $element, $parse, $animate) {
- this.$viewValue = Number.NaN;
- this.$modelValue = Number.NaN;
- this.$parsers = [];
- this.$formatters = [];
- this.$viewChangeListeners = [];
- this.$pristine = true;
- this.$dirty = false;
- this.$valid = true;
- this.$invalid = false;
- this.$name = $attr.name;
-
- var ngModelGet = $parse($attr.ngModel),
- ngModelSet = ngModelGet.assign;
-
- if (!ngModelSet) {
- throw minErr('ngModel')('nonassign', "Expression '{0}' is non-assignable. Element: {1}",
- $attr.ngModel, startingTag($element));
- }
-
- /**
- * @ngdoc method
- * @name ngModel.NgModelController#$render
- *
- * @description
- * Called when the view needs to be updated. It is expected that the user of the ng-model
- * directive will implement this method.
- */
- this.$render = noop;
-
- /**
- * @ngdoc method
- * @name ngModel.NgModelController#$isEmpty
- *
- * @description
- * This is called when we need to determine if the value of the input is empty.
- *
- * For instance, the required directive does this to work out if the input has data or not.
- * The default `$isEmpty` function checks whether the value is `undefined`, `''`, `null` or `NaN`.
- *
- * You can override this for input directives whose concept of being empty is different to the
- * default. The `checkboxInputType` directive does this because in its case a value of `false`
- * implies empty.
- *
- * @param {*} value Reference to check.
- * @returns {boolean} True if `value` is empty.
- */
- this.$isEmpty = function(value) {
- return isUndefined(value) || value === '' || value === null || value !== value;
- };
-
- var parentForm = $element.inheritedData('$formController') || nullFormCtrl,
- invalidCount = 0, // used to easily determine if we are valid
- $error = this.$error = {}; // keep invalid keys here
-
-
- // Setup initial state of the control
- $element.addClass(PRISTINE_CLASS);
- toggleValidCss(true);
-
- // convenience method for easy toggling of classes
- function toggleValidCss(isValid, validationErrorKey) {
- validationErrorKey = validationErrorKey ? '-' + snake_case(validationErrorKey, '-') : '';
- $animate.removeClass($element, (isValid ? INVALID_CLASS : VALID_CLASS) + validationErrorKey);
- $animate.addClass($element, (isValid ? VALID_CLASS : INVALID_CLASS) + validationErrorKey);
- }
-
- /**
- * @ngdoc method
- * @name ngModel.NgModelController#$setValidity
- *
- * @description
- * Change the validity state, and notifies the form when the control changes validity. (i.e. it
- * does not notify form if given validator is already marked as invalid).
- *
- * This method should be called by validators - i.e. the parser or formatter functions.
- *
- * @param {string} validationErrorKey Name of the validator. the `validationErrorKey` will assign
- * to `$error[validationErrorKey]=!isValid` so that it is available for data-binding.
- * The `validationErrorKey` should be in camelCase and will get converted into dash-case
- * for class name. Example: `myError` will result in `ng-valid-my-error` and `ng-invalid-my-error`
- * class and can be bound to as `{{someForm.someControl.$error.myError}}` .
- * @param {boolean} isValid Whether the current state is valid (true) or invalid (false).
- */
- this.$setValidity = function(validationErrorKey, isValid) {
- // Purposeful use of ! here to cast isValid to boolean in case it is undefined
- // jshint -W018
- if ($error[validationErrorKey] === !isValid) return;
- // jshint +W018
-
- if (isValid) {
- if ($error[validationErrorKey]) invalidCount--;
- if (!invalidCount) {
- toggleValidCss(true);
- this.$valid = true;
- this.$invalid = false;
- }
- } else {
- toggleValidCss(false);
- this.$invalid = true;
- this.$valid = false;
- invalidCount++;
- }
-
- $error[validationErrorKey] = !isValid;
- toggleValidCss(isValid, validationErrorKey);
-
- parentForm.$setValidity(validationErrorKey, isValid, this);
- };
-
- /**
- * @ngdoc method
- * @name ngModel.NgModelController#$setPristine
- *
- * @description
- * Sets the control to its pristine state.
- *
- * This method can be called to remove the 'ng-dirty' class and set the control to its pristine
- * state (ng-pristine class).
- */
- this.$setPristine = function () {
- this.$dirty = false;
- this.$pristine = true;
- $animate.removeClass($element, DIRTY_CLASS);
- $animate.addClass($element, PRISTINE_CLASS);
- };
-
- /**
- * @ngdoc method
- * @name ngModel.NgModelController#$setViewValue
- *
- * @description
- * Update the view value.
- *
- * This method should be called when the view value changes, typically from within a DOM event handler.
- * For example {@link ng.directive:input input} and
- * {@link ng.directive:select select} directives call it.
- *
- * It will update the $viewValue, then pass this value through each of the functions in `$parsers`,
- * which includes any validators. The value that comes out of this `$parsers` pipeline, be applied to
- * `$modelValue` and the **expression** specified in the `ng-model` attribute.
- *
- * Lastly, all the registered change listeners, in the `$viewChangeListeners` list, are called.
- *
- * Note that calling this function does not trigger a `$digest`.
- *
- * @param {string} value Value from the view.
- */
- this.$setViewValue = function(value) {
- this.$viewValue = value;
-
- // change to dirty
- if (this.$pristine) {
- this.$dirty = true;
- this.$pristine = false;
- $animate.removeClass($element, PRISTINE_CLASS);
- $animate.addClass($element, DIRTY_CLASS);
- parentForm.$setDirty();
- }
-
- forEach(this.$parsers, function(fn) {
- value = fn(value);
- });
-
- if (this.$modelValue !== value) {
- this.$modelValue = value;
- ngModelSet($scope, value);
- forEach(this.$viewChangeListeners, function(listener) {
- try {
- listener();
- } catch(e) {
- $exceptionHandler(e);
+ require: ['?ngModel'],
+ link: {
+ pre: function(scope, element, attr, ctrls) {
+ if (ctrls[0]) {
+ (inputType[lowercase(attr.type)] || inputType.text)(scope, element, attr, ctrls[0], $sniffer,
+ $browser, $filter, $parse);
}
- });
- }
- };
-
- // model -> value
- var ctrl = this;
-
- $scope.$watch(function ngModelWatch() {
- var value = ngModelGet($scope);
-
- // if scope model value and ngModel value are out of sync
- if (ctrl.$modelValue !== value) {
-
- var formatters = ctrl.$formatters,
- idx = formatters.length;
-
- ctrl.$modelValue = value;
- while(idx--) {
- value = formatters[idx](value);
- }
-
- if (ctrl.$viewValue !== value) {
- ctrl.$viewValue = value;
- ctrl.$render();
}
}
-
- return value;
- });
-}];
-
-
-/**
- * @ngdoc directive
- * @name ngModel
- *
- * @element input
- *
- * @description
- * The `ngModel` directive binds an `input`,`select`, `textarea` (or custom form control) to a
- * property on the scope using {@link ngModel.NgModelController NgModelController},
- * which is created and exposed by this directive.
- *
- * `ngModel` is responsible for:
- *
- * - Binding the view into the model, which other directives such as `input`, `textarea` or `select`
- * require.
- * - Providing validation behavior (i.e. required, number, email, url).
- * - Keeping the state of the control (valid/invalid, dirty/pristine, validation errors).
- * - Setting related css classes on the element (`ng-valid`, `ng-invalid`, `ng-dirty`, `ng-pristine`) including animations.
- * - Registering the control with its parent {@link ng.directive:form form}.
- *
- * Note: `ngModel` will try to bind to the property given by evaluating the expression on the
- * current scope. If the property doesn't already exist on this scope, it will be created
- * implicitly and added to the scope.
- *
- * For best practices on using `ngModel`, see:
- *
- * - [Understanding Scopes](https://github.com/angular/angular.js/wiki/Understanding-Scopes)
- *
- * For basic examples, how to use `ngModel`, see:
- *
- * - {@link ng.directive:input input}
- * - {@link input[text] text}
- * - {@link input[checkbox] checkbox}
- * - {@link input[radio] radio}
- * - {@link input[number] number}
- * - {@link input[email] email}
- * - {@link input[url] url}
- * - {@link ng.directive:select select}
- * - {@link ng.directive:textarea textarea}
- *
- * # CSS classes
- * The following CSS classes are added and removed on the associated input/select/textarea element
- * depending on the validity of the model.
- *
- * - `ng-valid` is set if the model is valid.
- * - `ng-invalid` is set if the model is invalid.
- * - `ng-pristine` is set if the model is pristine.
- * - `ng-dirty` is set if the model is dirty.
- *
- * Keep in mind that ngAnimate can detect each of these classes when added and removed.
- *
- * ## Animation Hooks
- *
- * Animations within models are triggered when any of the associated CSS classes are added and removed
- * on the input element which is attached to the model. These classes are: `.ng-pristine`, `.ng-dirty`,
- * `.ng-invalid` and `.ng-valid` as well as any other validations that are performed on the model itself.
- * The animations that are triggered within ngModel are similar to how they work in ngClass and
- * animations can be hooked into using CSS transitions, keyframes as well as JS animations.
- *
- * The following example shows a simple way to utilize CSS transitions to style an input element
- * that has been rendered as invalid after it has been validated:
- *
- * <pre>
- * //be sure to include ngAnimate as a module to hook into more
- * //advanced animations
- * .my-input {
- * transition:0.5s linear all;
- * background: white;
- * }
- * .my-input.ng-invalid {
- * background: red;
- * color:white;
- * }
- * </pre>
- *
- * @example
- * <example deps="angular-animate.js" animations="true" fixBase="true" module="inputExample">
- <file name="index.html">
- <script>
- angular.module('inputExample', [])
- .controller('ExampleController', ['$scope', function($scope) {
- $scope.val = '1';
- }]);
- </script>
- <style>
- .my-input {
- -webkit-transition:all linear 0.5s;
- transition:all linear 0.5s;
- background: transparent;
- }
- .my-input.ng-invalid {
- color:white;
- background: red;
- }
- </style>
- Update input to see transitions when valid/invalid.
- Integer is a valid value.
- <form name="testForm" ng-controller="ExampleController">
- <input ng-model="val" ng-pattern="/^\d+$/" name="anim" class="my-input" />
- </form>
- </file>
- * </example>
- */
-var ngModelDirective = function() {
- return {
- require: ['ngModel', '^?form'],
- controller: NgModelController,
- link: function(scope, element, attr, ctrls) {
- // notify others, especially parent forms
-
- var modelCtrl = ctrls[0],
- formCtrl = ctrls[1] || nullFormCtrl;
-
- formCtrl.$addControl(modelCtrl);
-
- scope.$on('$destroy', function() {
- formCtrl.$removeControl(modelCtrl);
- });
- }
- };
-};
-
-
-/**
- * @ngdoc directive
- * @name ngChange
- *
- * @description
- * Evaluate the given expression when the user changes the input.
- * The expression is evaluated immediately, unlike the JavaScript onchange event
- * which only triggers at the end of a change (usually, when the user leaves the
- * form element or presses the return key).
- * The expression is not evaluated when the value change is coming from the model.
- *
- * Note, this directive requires `ngModel` to be present.
- *
- * @element input
- * @param {expression} ngChange {@link guide/expression Expression} to evaluate upon change
- * in input value.
- *
- * @example
- * <example name="ngChange-directive" module="changeExample">
- * <file name="index.html">
- * <script>
- * angular.module('changeExample', [])
- * .controller('ExampleController', ['$scope', function($scope) {
- * $scope.counter = 0;
- * $scope.change = function() {
- * $scope.counter++;
- * };
- * }]);
- * </script>
- * <div ng-controller="ExampleController">
- * <input type="checkbox" ng-model="confirmed" ng-change="change()" id="ng-change-example1" />
- * <input type="checkbox" ng-model="confirmed" id="ng-change-example2" />
- * <label for="ng-change-example2">Confirmed</label><br />
- * <tt>debug = {{confirmed}}</tt><br/>
- * <tt>counter = {{counter}}</tt><br/>
- * </div>
- * </file>
- * <file name="protractor.js" type="protractor">
- * var counter = element(by.binding('counter'));
- * var debug = element(by.binding('confirmed'));
- *
- * it('should evaluate the expression if changing from view', function() {
- * expect(counter.getText()).toContain('0');
- *
- * element(by.id('ng-change-example1')).click();
- *
- * expect(counter.getText()).toContain('1');
- * expect(debug.getText()).toContain('true');
- * });
- *
- * it('should not evaluate the expression if changing from model', function() {
- * element(by.id('ng-change-example2')).click();
-
- * expect(counter.getText()).toContain('0');
- * expect(debug.getText()).toContain('true');
- * });
- * </file>
- * </example>
- */
-var ngChangeDirective = valueFn({
- require: 'ngModel',
- link: function(scope, element, attr, ctrl) {
- ctrl.$viewChangeListeners.push(function() {
- scope.$eval(attr.ngChange);
- });
- }
-});
-
-
-var requiredDirective = function() {
- return {
- require: '?ngModel',
- link: function(scope, elm, attr, ctrl) {
- if (!ctrl) return;
- attr.required = true; // force truthy in case we are on non input element
-
- var validator = function(value) {
- if (attr.required && ctrl.$isEmpty(value)) {
- ctrl.$setValidity('required', false);
- return;
- } else {
- ctrl.$setValidity('required', true);
- return value;
- }
- };
-
- ctrl.$formatters.push(validator);
- ctrl.$parsers.unshift(validator);
-
- attr.$observe('required', function() {
- validator(ctrl.$viewValue);
- });
- }
};
-};
-
-
-/**
- * @ngdoc directive
- * @name ngList
- *
- * @description
- * Text input that converts between a delimited string and an array of strings. The delimiter
- * can be a fixed string (by default a comma) or a regular expression.
- *
- * @element input
- * @param {string=} ngList optional delimiter that should be used to split the value. If
- * specified in form `/something/` then the value will be converted into a regular expression.
- *
- * @example
- <example name="ngList-directive" module="listExample">
- <file name="index.html">
- <script>
- angular.module('listExample', [])
- .controller('ExampleController', ['$scope', function($scope) {
- $scope.names = ['igor', 'misko', 'vojta'];
- }]);
- </script>
- <form name="myForm" ng-controller="ExampleController">
- List: <input name="namesInput" ng-model="names" ng-list required>
- <span class="error" ng-show="myForm.namesInput.$error.required">
- Required!</span>
- <br>
- <tt>names = {{names}}</tt><br/>
- <tt>myForm.namesInput.$valid = {{myForm.namesInput.$valid}}</tt><br/>
- <tt>myForm.namesInput.$error = {{myForm.namesInput.$error}}</tt><br/>
- <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
- <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
- </form>
- </file>
- <file name="protractor.js" type="protractor">
- var listInput = element(by.model('names'));
- var names = element(by.binding('{{names}}'));
- var valid = element(by.binding('myForm.namesInput.$valid'));
- var error = element(by.css('span.error'));
-
- it('should initialize to model', function() {
- expect(names.getText()).toContain('["igor","misko","vojta"]');
- expect(valid.getText()).toContain('true');
- expect(error.getCssValue('display')).toBe('none');
- });
-
- it('should be invalid if empty', function() {
- listInput.clear();
- listInput.sendKeys('');
-
- expect(names.getText()).toContain('');
- expect(valid.getText()).toContain('false');
- expect(error.getCssValue('display')).not.toBe('none'); });
- </file>
- </example>
- */
-var ngListDirective = function() {
- return {
- require: 'ngModel',
- link: function(scope, element, attr, ctrl) {
- var match = /\/(.*)\//.exec(attr.ngList),
- separator = match && new RegExp(match[1]) || attr.ngList || ',';
-
- var parse = function(viewValue) {
- // If the viewValue is invalid (say required but empty) it will be `undefined`
- if (isUndefined(viewValue)) return;
-
- var list = [];
-
- if (viewValue) {
- forEach(viewValue.split(separator), function(value) {
- if (value) list.push(trim(value));
- });
- }
-
- return list;
- };
-
- ctrl.$parsers.push(parse);
- ctrl.$formatters.push(function(value) {
- if (isArray(value)) {
- return value.join(', ');
- }
-
- return undefined;
- });
+}];
- // Override the standard $isEmpty because an empty array means the input is empty.
- ctrl.$isEmpty = function(value) {
- return !value || !value.length;
- };
- }
- };
-};
var CONSTANT_VALUE_REGEXP = /^(true|false|\d+)$/;
@@ -18226,12 +22017,17 @@ var CONSTANT_VALUE_REGEXP = /^(true|false|\d+)$/;
* @name ngValue
*
* @description
- * Binds the given expression to the value of `input[select]` or `input[radio]`, so
- * that when the element is selected, the `ngModel` of that element is set to the
- * bound value.
+ * Binds the given expression to the value of `<option>` or {@link input[radio] `input[radio]`},
+ * so that when the element is selected, the {@link ngModel `ngModel`} of that element is set to
+ * the bound value.
*
- * `ngValue` is useful when dynamically generating lists of radio buttons using `ng-repeat`, as
- * shown below.
+ * `ngValue` is useful when dynamically generating lists of radio buttons using
+ * {@link ngRepeat `ngRepeat`}, as shown below.
+ *
+ * Likewise, `ngValue` can be used to generate `<option>` elements for
+ * the {@link select `select`} element. In that case however, only strings are supported
+ * for the `value `attribute, so the resulting `ngModel` will always be a string.
+ * Support for `select` models with non-string values is available via `ngOptions`.
*
* @element input
* @param {string=} ngValue angular expression, whose value will be bound to the `value` attribute
@@ -18275,6 +22071,7 @@ var CONSTANT_VALUE_REGEXP = /^(true|false|\d+)$/;
*/
var ngValueDirective = function() {
return {
+ restrict: 'A',
priority: 100,
compile: function(tpl, tplAttr) {
if (CONSTANT_VALUE_REGEXP.test(tplAttr.ngValue)) {
@@ -18327,7 +22124,7 @@ var ngValueDirective = function() {
}]);
</script>
<div ng-controller="ExampleController">
- Enter name: <input type="text" ng-model="name"><br>
+ <label>Enter name: <input type="text" ng-model="name"></label><br>
Hello <span ng-bind="name"></span>!
</div>
</file>
@@ -18343,20 +22140,21 @@ var ngValueDirective = function() {
</file>
</example>
*/
-var ngBindDirective = ngDirective({
- compile: function(templateElement) {
- templateElement.addClass('ng-binding');
- return function (scope, element, attr) {
- element.data('$binding', attr.ngBind);
- scope.$watch(attr.ngBind, function ngBindWatchAction(value) {
- // We are purposefully using == here rather than === because we want to
- // catch when value is "null or undefined"
- // jshint -W041
- element.text(value == undefined ? '' : value);
- });
- };
- }
-});
+var ngBindDirective = ['$compile', function($compile) {
+ return {
+ restrict: 'AC',
+ compile: function ngBindCompile(templateElement) {
+ $compile.$$addBindingClass(templateElement);
+ return function ngBindLink(scope, element, attr) {
+ $compile.$$addBindingInfo(element, attr.ngBind);
+ element = element[0];
+ scope.$watch(attr.ngBind, function ngBindWatchAction(value) {
+ element.textContent = value === undefined ? '' : value;
+ });
+ };
+ }
+ };
+}];
/**
@@ -18381,14 +22179,14 @@ var ngBindDirective = ngDirective({
<file name="index.html">
<script>
angular.module('bindExample', [])
- .controller('ExampleController', ['$scope', function ($scope) {
+ .controller('ExampleController', ['$scope', function($scope) {
$scope.salutation = 'Hello';
$scope.name = 'World';
}]);
</script>
<div ng-controller="ExampleController">
- Salutation: <input type="text" ng-model="salutation"><br>
- Name: <input type="text" ng-model="name"><br>
+ <label>Salutation: <input type="text" ng-model="salutation"></label><br>
+ <label>Name: <input type="text" ng-model="name"></label><br>
<pre ng-bind-template="{{salutation}} {{name}}!"></pre>
</div>
</file>
@@ -18410,14 +22208,19 @@ var ngBindDirective = ngDirective({
</file>
</example>
*/
-var ngBindTemplateDirective = ['$interpolate', function($interpolate) {
- return function(scope, element, attr) {
- // TODO: move this to scenario runner
- var interpolateFn = $interpolate(element.attr(attr.$attr.ngBindTemplate));
- element.addClass('ng-binding').data('$binding', interpolateFn);
- attr.$observe('ngBindTemplate', function(value) {
- element.text(value);
- });
+var ngBindTemplateDirective = ['$interpolate', '$compile', function($interpolate, $compile) {
+ return {
+ compile: function ngBindTemplateCompile(templateElement) {
+ $compile.$$addBindingClass(templateElement);
+ return function ngBindTemplateLink(scope, element, attr) {
+ var interpolateFn = $interpolate(element.attr(attr.$attr.ngBindTemplate));
+ $compile.$$addBindingInfo(element, interpolateFn.expressions);
+ element = element[0];
+ attr.$observe('ngBindTemplate', function(value) {
+ element.textContent = value === undefined ? '' : value;
+ });
+ };
+ }
};
}];
@@ -18427,16 +22230,15 @@ var ngBindTemplateDirective = ['$interpolate', function($interpolate) {
* @name ngBindHtml
*
* @description
- * Creates a binding that will innerHTML the result of evaluating the `expression` into the current
- * element in a secure way. By default, the innerHTML-ed content will be sanitized using the {@link
- * ngSanitize.$sanitize $sanitize} service. To utilize this functionality, ensure that `$sanitize`
- * is available, for example, by including {@link ngSanitize} in your module's dependencies (not in
- * core Angular). In order to use {@link ngSanitize} in your module's dependencies, you need to
- * include "angular-sanitize.js" in your application.
+ * Evaluates the expression and inserts the resulting HTML into the element in a secure way. By default,
+ * the resulting HTML content will be sanitized using the {@link ngSanitize.$sanitize $sanitize} service.
+ * To utilize this functionality, ensure that `$sanitize` is available, for example, by including {@link
+ * ngSanitize} in your module's dependencies (not in core Angular). In order to use {@link ngSanitize}
+ * in your module's dependencies, you need to include "angular-sanitize.js" in your application.
*
* You may also bypass sanitization for values you know are safe. To do so, bind to
* an explicitly trusted value via {@link ng.$sce#trustAsHtml $sce.trustAsHtml}. See the example
- * under {@link ng.$sce#Example Strict Contextual Escaping (SCE)}.
+ * under {@link ng.$sce#show-me-an-example-using-sce- Strict Contextual Escaping (SCE)}.
*
* Note: If a `$sanitize` service is unavailable and the bound value isn't explicitly trusted, you
* will have an exception (instead of an exploit.)
@@ -18470,28 +22272,106 @@ var ngBindTemplateDirective = ['$interpolate', function($interpolate) {
</file>
</example>
*/
-var ngBindHtmlDirective = ['$sce', '$parse', function($sce, $parse) {
+var ngBindHtmlDirective = ['$sce', '$parse', '$compile', function($sce, $parse, $compile) {
return {
- compile: function (tElement) {
- tElement.addClass('ng-binding');
-
- return function (scope, element, attr) {
- element.data('$binding', attr.ngBindHtml);
+ restrict: 'A',
+ compile: function ngBindHtmlCompile(tElement, tAttrs) {
+ var ngBindHtmlGetter = $parse(tAttrs.ngBindHtml);
+ var ngBindHtmlWatch = $parse(tAttrs.ngBindHtml, function getStringValue(value) {
+ return (value || '').toString();
+ });
+ $compile.$$addBindingClass(tElement);
- var parsed = $parse(attr.ngBindHtml);
+ return function ngBindHtmlLink(scope, element, attr) {
+ $compile.$$addBindingInfo(element, attr.ngBindHtml);
- function getStringValue() {
- return (parsed(scope) || '').toString();
- }
-
- scope.$watch(getStringValue, function ngBindHtmlWatchAction(value) {
- element.html($sce.getTrustedHtml(parsed(scope)) || '');
+ scope.$watch(ngBindHtmlWatch, function ngBindHtmlWatchAction() {
+ // we re-evaluate the expr because we want a TrustedValueHolderType
+ // for $sce, not a string
+ element.html($sce.getTrustedHtml(ngBindHtmlGetter(scope)) || '');
});
};
}
};
}];
+/**
+ * @ngdoc directive
+ * @name ngChange
+ *
+ * @description
+ * Evaluate the given expression when the user changes the input.
+ * The expression is evaluated immediately, unlike the JavaScript onchange event
+ * which only triggers at the end of a change (usually, when the user leaves the
+ * form element or presses the return key).
+ *
+ * The `ngChange` expression is only evaluated when a change in the input value causes
+ * a new value to be committed to the model.
+ *
+ * It will not be evaluated:
+ * * if the value returned from the `$parsers` transformation pipeline has not changed
+ * * if the input has continued to be invalid since the model will stay `null`
+ * * if the model is changed programmatically and not by a change to the input value
+ *
+ *
+ * Note, this directive requires `ngModel` to be present.
+ *
+ * @element input
+ * @param {expression} ngChange {@link guide/expression Expression} to evaluate upon change
+ * in input value.
+ *
+ * @example
+ * <example name="ngChange-directive" module="changeExample">
+ * <file name="index.html">
+ * <script>
+ * angular.module('changeExample', [])
+ * .controller('ExampleController', ['$scope', function($scope) {
+ * $scope.counter = 0;
+ * $scope.change = function() {
+ * $scope.counter++;
+ * };
+ * }]);
+ * </script>
+ * <div ng-controller="ExampleController">
+ * <input type="checkbox" ng-model="confirmed" ng-change="change()" id="ng-change-example1" />
+ * <input type="checkbox" ng-model="confirmed" id="ng-change-example2" />
+ * <label for="ng-change-example2">Confirmed</label><br />
+ * <tt>debug = {{confirmed}}</tt><br/>
+ * <tt>counter = {{counter}}</tt><br/>
+ * </div>
+ * </file>
+ * <file name="protractor.js" type="protractor">
+ * var counter = element(by.binding('counter'));
+ * var debug = element(by.binding('confirmed'));
+ *
+ * it('should evaluate the expression if changing from view', function() {
+ * expect(counter.getText()).toContain('0');
+ *
+ * element(by.id('ng-change-example1')).click();
+ *
+ * expect(counter.getText()).toContain('1');
+ * expect(debug.getText()).toContain('true');
+ * });
+ *
+ * it('should not evaluate the expression if changing from model', function() {
+ * element(by.id('ng-change-example2')).click();
+
+ * expect(counter.getText()).toContain('0');
+ * expect(debug.getText()).toContain('true');
+ * });
+ * </file>
+ * </example>
+ */
+var ngChangeDirective = valueFn({
+ restrict: 'A',
+ require: 'ngModel',
+ link: function(scope, element, attr, ctrl) {
+ ctrl.$viewChangeListeners.push(function() {
+ scope.$eval(attr.ngChange);
+ });
+ }
+});
+
function classDirective(name, selector) {
name = 'ngClass' + name;
return ['$animate', function($animate) {
@@ -18530,10 +22410,12 @@ function classDirective(name, selector) {
attr.$removeClass(newClasses);
}
- function digestClassCounts (classes, count) {
- var classCounts = element.data('$classCounts') || {};
+ function digestClassCounts(classes, count) {
+ // Use createMap() to prevent class assumptions involving property
+ // names in Object.prototype
+ var classCounts = element.data('$classCounts') || createMap();
var classesToUpdate = [];
- forEach(classes, function (className) {
+ forEach(classes, function(className) {
if (count > 0 || classCounts[className]) {
classCounts[className] = (classCounts[className] || 0) + count;
if (classCounts[className] === +(count > 0)) {
@@ -18545,18 +22427,16 @@ function classDirective(name, selector) {
return classesToUpdate.join(' ');
}
- function updateClasses (oldClasses, newClasses) {
+ function updateClasses(oldClasses, newClasses) {
var toAdd = arrayDifference(newClasses, oldClasses);
var toRemove = arrayDifference(oldClasses, newClasses);
- toRemove = digestClassCounts(toRemove, -1);
toAdd = digestClassCounts(toAdd, 1);
-
- if (toAdd.length === 0) {
- $animate.removeClass(element, toRemove);
- } else if (toRemove.length === 0) {
+ toRemove = digestClassCounts(toRemove, -1);
+ if (toAdd && toAdd.length) {
$animate.addClass(element, toAdd);
- } else {
- $animate.setClass(element, toAdd, toRemove);
+ }
+ if (toRemove && toRemove.length) {
+ $animate.removeClass(element, toRemove);
}
}
@@ -18579,23 +22459,26 @@ function classDirective(name, selector) {
var values = [];
outer:
- for(var i = 0; i < tokens1.length; i++) {
+ for (var i = 0; i < tokens1.length; i++) {
var token = tokens1[i];
- for(var j = 0; j < tokens2.length; j++) {
- if(token == tokens2[j]) continue outer;
+ for (var j = 0; j < tokens2.length; j++) {
+ if (token == tokens2[j]) continue outer;
}
values.push(token);
}
return values;
}
- function arrayClasses (classVal) {
+ function arrayClasses(classVal) {
+ var classes = [];
if (isArray(classVal)) {
- return classVal;
+ forEach(classVal, function(v) {
+ classes = classes.concat(arrayClasses(v));
+ });
+ return classes;
} else if (isString(classVal)) {
return classVal.split(' ');
} else if (isObject(classVal)) {
- var classes = [], i = 0;
forEach(classVal, function(v, k) {
if (v) {
classes = classes.concat(k.split(' '));
@@ -18623,20 +22506,23 @@ function classDirective(name, selector) {
* 1. If the expression evaluates to a string, the string should be one or more space-delimited class
* names.
*
- * 2. If the expression evaluates to an array, each element of the array should be a string that is
- * one or more space-delimited class names.
- *
- * 3. If the expression evaluates to an object, then for each key-value pair of the
+ * 2. If the expression evaluates to an object, then for each key-value pair of the
* object with a truthy value the corresponding key is used as a class name.
*
+ * 3. If the expression evaluates to an array, each element of the array should either be a string as in
+ * type 1 or an object as in type 2. This means that you can mix strings and objects together in an array
+ * to give you more control over what CSS classes appear. See the code below for an example of this.
+ *
+ *
* The directive won't add duplicate classes if a particular class was already set.
*
- * When the expression changes, the previously added classes are removed and only then the
- * new classes are added.
+ * When the expression changes, the previously added classes are removed and only then are the
+ * new classes added.
*
* @animations
- * add - happens just before the class is applied to the element
- * remove - happens just before the class is removed from the element
+ * **add** - happens just before the class is applied to the elements
+ *
+ * **remove** - happens just before the class is removed from the element
*
* @element ANY
* @param {expression} ngClass {@link guide/expression Expression} to eval. The result
@@ -18648,22 +22534,39 @@ function classDirective(name, selector) {
* @example Example that demonstrates basic bindings via ngClass directive.
<example>
<file name="index.html">
- <p ng-class="{strike: deleted, bold: important, red: error}">Map Syntax Example</p>
- <input type="checkbox" ng-model="deleted"> deleted (apply "strike" class)<br>
- <input type="checkbox" ng-model="important"> important (apply "bold" class)<br>
- <input type="checkbox" ng-model="error"> error (apply "red" class)
+ <p ng-class="{strike: deleted, bold: important, 'has-error': error}">Map Syntax Example</p>
+ <label>
+ <input type="checkbox" ng-model="deleted">
+ deleted (apply "strike" class)
+ </label><br>
+ <label>
+ <input type="checkbox" ng-model="important">
+ important (apply "bold" class)
+ </label><br>
+ <label>
+ <input type="checkbox" ng-model="error">
+ error (apply "has-error" class)
+ </label>
<hr>
<p ng-class="style">Using String Syntax</p>
- <input type="text" ng-model="style" placeholder="Type: bold strike red">
+ <input type="text" ng-model="style"
+ placeholder="Type: bold strike red" aria-label="Type: bold strike red">
<hr>
<p ng-class="[style1, style2, style3]">Using Array Syntax</p>
- <input ng-model="style1" placeholder="Type: bold, strike or red"><br>
- <input ng-model="style2" placeholder="Type: bold, strike or red"><br>
- <input ng-model="style3" placeholder="Type: bold, strike or red"><br>
+ <input ng-model="style1"
+ placeholder="Type: bold, strike or red" aria-label="Type: bold, strike or red"><br>
+ <input ng-model="style2"
+ placeholder="Type: bold, strike or red" aria-label="Type: bold, strike or red 2"><br>
+ <input ng-model="style3"
+ placeholder="Type: bold, strike or red" aria-label="Type: bold, strike or red 3"><br>
+ <hr>
+ <p ng-class="[style4, {orange: warning}]">Using Array and Map Syntax</p>
+ <input ng-model="style4" placeholder="Type: bold, strike" aria-label="Type: bold, strike"><br>
+ <label><input type="checkbox" ng-model="warning"> warning (apply "orange" class)</label>
</file>
<file name="style.css">
.strike {
- text-decoration: line-through;
+ text-decoration: line-through;
}
.bold {
font-weight: bold;
@@ -18671,6 +22574,13 @@ function classDirective(name, selector) {
.red {
color: red;
}
+ .has-error {
+ color: red;
+ background-color: yellow;
+ }
+ .orange {
+ color: orange;
+ }
</file>
<file name="protractor.js" type="protractor">
var ps = element.all(by.css('p'));
@@ -18678,13 +22588,13 @@ function classDirective(name, selector) {
it('should let you toggle the class', function() {
expect(ps.first().getAttribute('class')).not.toMatch(/bold/);
- expect(ps.first().getAttribute('class')).not.toMatch(/red/);
+ expect(ps.first().getAttribute('class')).not.toMatch(/has-error/);
element(by.model('important')).click();
expect(ps.first().getAttribute('class')).toMatch(/bold/);
element(by.model('error')).click();
- expect(ps.first().getAttribute('class')).toMatch(/red/);
+ expect(ps.first().getAttribute('class')).toMatch(/has-error/);
});
it('should let you toggle string example', function() {
@@ -18695,11 +22605,18 @@ function classDirective(name, selector) {
});
it('array example should have 3 classes', function() {
- expect(ps.last().getAttribute('class')).toBe('');
+ expect(ps.get(2).getAttribute('class')).toBe('');
element(by.model('style1')).sendKeys('bold');
element(by.model('style2')).sendKeys('strike');
element(by.model('style3')).sendKeys('red');
- expect(ps.last().getAttribute('class')).toBe('bold strike red');
+ expect(ps.get(2).getAttribute('class')).toBe('bold strike red');
+ });
+
+ it('array with map example should have 2 classes', function() {
+ expect(ps.last().getAttribute('class')).toBe('');
+ element(by.model('style4')).sendKeys('bold');
+ element(by.model('warning')).click();
+ expect(ps.last().getAttribute('class')).toBe('bold orange');
});
</file>
</example>
@@ -18749,8 +22666,8 @@ function classDirective(name, selector) {
The ngClass directive still supports CSS3 Transitions/Animations even if they do not follow the ngAnimate CSS naming structure.
Upon animation ngAnimate will apply supplementary CSS classes to track the start and end of an animation, but this will not hinder
any pre-existing CSS transitions already on the element. To get an idea of what happens during a class-based animation, be sure
- to view the step by step details of {@link ngAnimate.$animate#addclass $animate.addClass} and
- {@link ngAnimate.$animate#removeclass $animate.removeClass}.
+ to view the step by step details of {@link $animate#addClass $animate.addClass} and
+ {@link $animate#removeClass $animate.removeClass}.
*/
var ngClassDirective = classDirective('', true);
@@ -18883,17 +22800,13 @@ var ngClassEvenDirective = classDirective('Even', 1);
* document; alternatively, the css rule above must be included in the external stylesheet of the
* application.
*
- * Legacy browsers, like IE7, do not provide attribute selector support (added in CSS 2.1) so they
- * cannot match the `[ng\:cloak]` selector. To work around this limitation, you must add the css
- * class `ng-cloak` in addition to the `ngCloak` directive as shown in the example below.
- *
* @element ANY
*
* @example
<example>
<file name="index.html">
<div id="template1" ng-cloak>{{ 'hello' }}</div>
- <div id="template2" ng-cloak class="ng-cloak">{{ 'hello IE7' }}</div>
+ <div id="template2" class="ng-cloak">{{ 'world' }}</div>
</file>
<file name="protractor.js" type="protractor">
it('should remove the template directive and css class', function() {
@@ -18937,10 +22850,16 @@ var ngCloakDirective = ngDirective({
* @element ANY
* @scope
* @priority 500
- * @param {expression} ngController Name of a globally accessible constructor function or an
- * {@link guide/expression expression} that on the current scope evaluates to a
- * constructor function. The controller instance can be published into a scope property
- * by specifying `as propertyName`.
+ * @param {expression} ngController Name of a constructor function registered with the current
+ * {@link ng.$controllerProvider $controllerProvider} or an {@link guide/expression expression}
+ * that on the current scope evaluates to a constructor function.
+ *
+ * The controller instance can be published into a scope property by specifying
+ * `ng-controller="as propertyName"`.
+ *
+ * If the current `$controllerProvider` is configured to use globals (via
+ * {@link ng.$controllerProvider#allowGlobals `$controllerProvider.allowGlobals()` }), this may
+ * also be the name of a globally accessible constructor function (not recommended).
*
* @example
* Here is a simple form for editing user contact information. Adding, removing, clearing, and
@@ -18971,20 +22890,20 @@ var ngCloakDirective = ngDirective({
* <example name="ngControllerAs" module="controllerAsExample">
* <file name="index.html">
* <div id="ctrl-as-exmpl" ng-controller="SettingsController1 as settings">
- * Name: <input type="text" ng-model="settings.name"/>
- * [ <a href="" ng-click="settings.greet()">greet</a> ]<br/>
+ * <label>Name: <input type="text" ng-model="settings.name"/></label>
+ * <button ng-click="settings.greet()">greet</button><br/>
* Contact:
* <ul>
* <li ng-repeat="contact in settings.contacts">
- * <select ng-model="contact.type">
+ * <select ng-model="contact.type" aria-label="Contact method" id="select_{{$index}}">
* <option>phone</option>
* <option>email</option>
* </select>
- * <input type="text" ng-model="contact.value"/>
- * [ <a href="" ng-click="settings.clearContact(contact)">clear</a>
- * | <a href="" ng-click="settings.removeContact(contact)">X</a> ]
+ * <input type="text" ng-model="contact.value" aria-labelledby="select_{{$index}}" />
+ * <button ng-click="settings.clearContact(contact)">clear</button>
+ * <button ng-click="settings.removeContact(contact)" aria-label="Remove">X</button>
* </li>
- * <li>[ <a href="" ng-click="settings.addContact()">add</a> ]</li>
+ * <li><button ng-click="settings.addContact()">add</button></li>
* </ul>
* </div>
* </file>
@@ -19034,12 +22953,12 @@ var ngCloakDirective = ngDirective({
* expect(secondRepeat.element(by.model('contact.value')).getAttribute('value'))
* .toBe('john.smith@example.org');
*
- * firstRepeat.element(by.linkText('clear')).click();
+ * firstRepeat.element(by.buttonText('clear')).click();
*
* expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
* .toBe('');
*
- * container.element(by.linkText('add')).click();
+ * container.element(by.buttonText('add')).click();
*
* expect(container.element(by.repeater('contact in settings.contacts').row(2))
* .element(by.model('contact.value'))
@@ -19054,20 +22973,20 @@ var ngCloakDirective = ngDirective({
* <example name="ngController" module="controllerExample">
* <file name="index.html">
* <div id="ctrl-exmpl" ng-controller="SettingsController2">
- * Name: <input type="text" ng-model="name"/>
- * [ <a href="" ng-click="greet()">greet</a> ]<br/>
+ * <label>Name: <input type="text" ng-model="name"/></label>
+ * <button ng-click="greet()">greet</button><br/>
* Contact:
* <ul>
* <li ng-repeat="contact in contacts">
- * <select ng-model="contact.type">
+ * <select ng-model="contact.type" id="select_{{$index}}">
* <option>phone</option>
* <option>email</option>
* </select>
- * <input type="text" ng-model="contact.value"/>
- * [ <a href="" ng-click="clearContact(contact)">clear</a>
- * | <a href="" ng-click="removeContact(contact)">X</a> ]
+ * <input type="text" ng-model="contact.value" aria-labelledby="select_{{$index}}" />
+ * <button ng-click="clearContact(contact)">clear</button>
+ * <button ng-click="removeContact(contact)">X</button>
* </li>
- * <li>[ <a href="" ng-click="addContact()">add</a> ]</li>
+ * <li>[ <button ng-click="addContact()">add</button> ]</li>
* </ul>
* </div>
* </file>
@@ -19117,12 +23036,12 @@ var ngCloakDirective = ngDirective({
* expect(secondRepeat.element(by.model('contact.value')).getAttribute('value'))
* .toBe('john.smith@example.org');
*
- * firstRepeat.element(by.linkText('clear')).click();
+ * firstRepeat.element(by.buttonText('clear')).click();
*
* expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
* .toBe('');
*
- * container.element(by.linkText('add')).click();
+ * container.element(by.buttonText('add')).click();
*
* expect(container.element(by.repeater('contact in contacts').row(2))
* .element(by.model('contact.value'))
@@ -19135,6 +23054,7 @@ var ngCloakDirective = ngDirective({
*/
var ngControllerDirective = [function() {
return {
+ restrict: 'A',
scope: true,
controller: '@',
priority: 500
@@ -19149,7 +23069,7 @@ var ngControllerDirective = [function() {
* @description
* Enables [CSP (Content Security Policy)](https://developer.mozilla.org/en/Security/CSP) support.
*
- * This is necessary when developing things like Google Chrome Extensions.
+ * This is necessary when developing things like Google Chrome Extensions or Universal Windows Apps.
*
* CSP forbids apps to use `eval` or `Function(string)` generated functions (among other things).
* For Angular to be CSP compatible there are only two things that we need to do differently:
@@ -19190,7 +23110,125 @@ var ngControllerDirective = [function() {
...
</html>
```
- */
+ * @example
+ // Note: the suffix `.csp` in the example name triggers
+ // csp mode in our http server!
+ <example name="example.csp" module="cspExample" ng-csp="true">
+ <file name="index.html">
+ <div ng-controller="MainController as ctrl">
+ <div>
+ <button ng-click="ctrl.inc()" id="inc">Increment</button>
+ <span id="counter">
+ {{ctrl.counter}}
+ </span>
+ </div>
+
+ <div>
+ <button ng-click="ctrl.evil()" id="evil">Evil</button>
+ <span id="evilError">
+ {{ctrl.evilError}}
+ </span>
+ </div>
+ </div>
+ </file>
+ <file name="script.js">
+ angular.module('cspExample', [])
+ .controller('MainController', function() {
+ this.counter = 0;
+ this.inc = function() {
+ this.counter++;
+ };
+ this.evil = function() {
+ // jshint evil:true
+ try {
+ eval('1+2');
+ } catch (e) {
+ this.evilError = e.message;
+ }
+ };
+ });
+ </file>
+ <file name="protractor.js" type="protractor">
+ var util, webdriver;
+
+ var incBtn = element(by.id('inc'));
+ var counter = element(by.id('counter'));
+ var evilBtn = element(by.id('evil'));
+ var evilError = element(by.id('evilError'));
+
+ function getAndClearSevereErrors() {
+ return browser.manage().logs().get('browser').then(function(browserLog) {
+ return browserLog.filter(function(logEntry) {
+ return logEntry.level.value > webdriver.logging.Level.WARNING.value;
+ });
+ });
+ }
+
+ function clearErrors() {
+ getAndClearSevereErrors();
+ }
+
+ function expectNoErrors() {
+ getAndClearSevereErrors().then(function(filteredLog) {
+ expect(filteredLog.length).toEqual(0);
+ if (filteredLog.length) {
+ console.log('browser console errors: ' + util.inspect(filteredLog));
+ }
+ });
+ }
+
+ function expectError(regex) {
+ getAndClearSevereErrors().then(function(filteredLog) {
+ var found = false;
+ filteredLog.forEach(function(log) {
+ if (log.message.match(regex)) {
+ found = true;
+ }
+ });
+ if (!found) {
+ throw new Error('expected an error that matches ' + regex);
+ }
+ });
+ }
+
+ beforeEach(function() {
+ util = require('util');
+ webdriver = require('protractor/node_modules/selenium-webdriver');
+ });
+
+ // For now, we only test on Chrome,
+ // as Safari does not load the page with Protractor's injected scripts,
+ // and Firefox webdriver always disables content security policy (#6358)
+ if (browser.params.browser !== 'chrome') {
+ return;
+ }
+
+ it('should not report errors when the page is loaded', function() {
+ // clear errors so we are not dependent on previous tests
+ clearErrors();
+ // Need to reload the page as the page is already loaded when
+ // we come here
+ browser.driver.getCurrentUrl().then(function(url) {
+ browser.get(url);
+ });
+ expectNoErrors();
+ });
+
+ it('should evaluate expressions', function() {
+ expect(counter.getText()).toEqual('0');
+ incBtn.click();
+ expect(counter.getText()).toEqual('1');
+ expectNoErrors();
+ });
+
+ it('should throw and report an error when using "eval"', function() {
+ evilBtn.click();
+ expect(evilError.getText()).toMatch(/Content Security Policy/);
+ expectError(/Content Security Policy/);
+ });
+ </file>
+ </example>
+ */
// ngCsp is not implemented as a proper directive any more, because we need it be processed while we
// bootstrap the system (before $parse is instantiated), for this reason we just have
@@ -19217,7 +23255,7 @@ var ngControllerDirective = [function() {
</button>
<span>
count: {{count}}
- <span>
+ </span>
</file>
<file name="protractor.js" type="protractor">
it('should check ng-click', function() {
@@ -19247,12 +23285,13 @@ forEach(
var directiveName = directiveNormalize('ng-' + eventName);
ngEventDirectives[directiveName] = ['$parse', '$rootScope', function($parse, $rootScope) {
return {
+ restrict: 'A',
compile: function($element, attr) {
// We expose the powerful $event object on the scope that provides access to the Window,
// etc. that isn't protected by the fast paths in $parse. We explicitly request better
// checks at the cost of speed since event handler expressions are not executed as
// frequently as regular change detection.
- var fn = $parse(attr[directiveName], /* expensiveChecks */ true);
+ var fn = $parse(attr[directiveName], /* interceptorFn */ null, /* expensiveChecks */ true);
return function ngEventHandler(scope, element) {
element.on(eventName, function(event) {
var callback = function() {
@@ -19683,6 +23722,7 @@ forEach(
* @ngdoc directive
* @name ngIf
* @restrict A
+ * @multiElement
*
* @description
* The `ngIf` directive removes or recreates a portion of the DOM tree based on an
@@ -19725,10 +23765,10 @@ forEach(
* @example
<example module="ngAnimate" deps="angular-animate.js" animations="true">
<file name="index.html">
- Click me: <input type="checkbox" ng-model="checked" ng-init="checked=true" /><br/>
+ <label>Click me: <input type="checkbox" ng-model="checked" ng-init="checked=true" /></label><br/>
Show when checked:
<span ng-if="checked" class="animate-if">
- I'm removed when the checkbox is unchecked.
+ This is removed when the checkbox is unchecked.
</span>
</file>
<file name="animations.css">
@@ -19757,19 +23797,20 @@ forEach(
*/
var ngIfDirective = ['$animate', function($animate) {
return {
+ multiElement: true,
transclude: 'element',
priority: 600,
terminal: true,
restrict: 'A',
$$tlb: true,
- link: function ($scope, $element, $attr, ctrl, $transclude) {
+ link: function($scope, $element, $attr, ctrl, $transclude) {
var block, childScope, previousElements;
$scope.$watch($attr.ngIf, function ngIfWatchAction(value) {
- if (toBoolean(value)) {
+ if (value) {
if (!childScope) {
- childScope = $scope.$new();
- $transclude(childScope, function (clone) {
+ $transclude(function(clone, newScope) {
+ childScope = newScope;
clone[clone.length++] = document.createComment(' end ngIf: ' + $attr.ngIf + ' ');
// Note: We only need the first/last node of the cloned nodes.
// However, we need to keep the reference to the jqlite wrapper as it might be changed later
@@ -19781,17 +23822,17 @@ var ngIfDirective = ['$animate', function($animate) {
});
}
} else {
- if(previousElements) {
+ if (previousElements) {
previousElements.remove();
previousElements = null;
}
- if(childScope) {
+ if (childScope) {
childScope.$destroy();
childScope = null;
}
- if(block) {
- previousElements = getBlockElements(block.clone);
- $animate.leave(previousElements, function() {
+ if (block) {
+ previousElements = getBlockNodes(block.clone);
+ $animate.leave(previousElements).then(function() {
previousElements = null;
});
block = null;
@@ -19811,10 +23852,10 @@ var ngIfDirective = ['$animate', function($animate) {
* Fetches, compiles and includes an external HTML fragment.
*
* By default, the template URL is restricted to the same domain and protocol as the
- * application document. This is done by calling {@link ng.$sce#getTrustedResourceUrl
+ * application document. This is done by calling {@link $sce#getTrustedResourceUrl
* $sce.getTrustedResourceUrl} on it. To load templates from other domains or protocols
* you may either {@link ng.$sceDelegateProvider#resourceUrlWhitelist whitelist them} or
- * [wrap them](ng.$sce#trustAsResourceUrl) as trusted values. Refer to Angular's {@link
+ * {@link $sce#trustAsResourceUrl wrap them} as trusted values. Refer to Angular's {@link
* ng.$sce Strict Contextual Escaping}.
*
* In addition, the browser's
@@ -19851,7 +23892,7 @@ var ngIfDirective = ['$animate', function($animate) {
<select ng-model="template" ng-options="t.name for t in templates">
<option value="">(blank)</option>
</select>
- url of the template: <tt>{{template.url}}</tt>
+ url of the template: <code>{{template.url}}</code>
<hr/>
<div class="slide-animate-container">
<div class="slide-animate" ng-include="template.url"></div>
@@ -19952,6 +23993,9 @@ var ngIfDirective = ['$animate', function($animate) {
* @eventType emit on the scope ngInclude was declared in
* @description
* Emitted every time the ngInclude content is requested.
+ *
+ * @param {Object} angularEvent Synthetic event object.
+ * @param {String} src URL of content to load.
*/
@@ -19961,9 +24005,24 @@ var ngIfDirective = ['$animate', function($animate) {
* @eventType emit on the current ngInclude scope
* @description
* Emitted every time the ngInclude content is reloaded.
+ *
+ * @param {Object} angularEvent Synthetic event object.
+ * @param {String} src URL of content to load.
+ */
+
+
+/**
+ * @ngdoc event
+ * @name ngInclude#$includeContentError
+ * @eventType emit on the scope ngInclude was declared in
+ * @description
+ * Emitted when a template HTTP request yields an erroneous response (status < 200 || status > 299)
+ *
+ * @param {Object} angularEvent Synthetic event object.
+ * @param {String} src URL of content to load.
*/
-var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$animate', '$sce',
- function($http, $templateCache, $anchorScroll, $animate, $sce) {
+var ngIncludeDirective = ['$templateRequest', '$anchorScroll', '$animate',
+ function($templateRequest, $anchorScroll, $animate) {
return {
restrict: 'ECA',
priority: 400,
@@ -19982,16 +24041,16 @@ var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$animate'
currentElement;
var cleanupLastIncludeContent = function() {
- if(previousElement) {
+ if (previousElement) {
previousElement.remove();
previousElement = null;
}
- if(currentScope) {
+ if (currentScope) {
currentScope.$destroy();
currentScope = null;
}
- if(currentElement) {
- $animate.leave(currentElement, function() {
+ if (currentElement) {
+ $animate.leave(currentElement).then(function() {
previousElement = null;
});
previousElement = currentElement;
@@ -19999,7 +24058,7 @@ var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$animate'
}
};
- scope.$watch($sce.parseAsResourceUrl(srcExp), function ngIncludeWatchAction(src) {
+ scope.$watch(srcExp, function ngIncludeWatchAction(src) {
var afterAnimation = function() {
if (isDefined(autoScrollExp) && (!autoScrollExp || scope.$eval(autoScrollExp))) {
$anchorScroll();
@@ -20008,7 +24067,9 @@ var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$animate'
var thisChangeId = ++changeCounter;
if (src) {
- $http.get(src, {cache: $templateCache}).success(function(response) {
+ //set the 2nd param to true to ignore the template request error so that the inner
+ //contents and scope can be cleaned up.
+ $templateRequest(src, true).then(function(response) {
if (thisChangeId !== changeCounter) return;
var newScope = scope.$new();
ctrl.template = response;
@@ -20021,18 +24082,21 @@ var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$animate'
// directives to non existing elements.
var clone = $transclude(newScope, function(clone) {
cleanupLastIncludeContent();
- $animate.enter(clone, null, $element, afterAnimation);
+ $animate.enter(clone, null, $element).then(afterAnimation);
});
currentScope = newScope;
currentElement = clone;
- currentScope.$emit('$includeContentLoaded');
+ currentScope.$emit('$includeContentLoaded', src);
scope.$eval(onloadExp);
- }).error(function() {
- if (thisChangeId === changeCounter) cleanupLastIncludeContent();
+ }, function() {
+ if (thisChangeId === changeCounter) {
+ cleanupLastIncludeContent();
+ scope.$emit('$includeContentError', src);
+ }
});
- scope.$emit('$includeContentRequested');
+ scope.$emit('$includeContentRequested', src);
} else {
cleanupLastIncludeContent();
ctrl.template = null;
@@ -20055,6 +24119,18 @@ var ngIncludeFillContentDirective = ['$compile',
priority: -400,
require: 'ngInclude',
link: function(scope, $element, $attr, ctrl) {
+ if (/SVG/.test($element[0].toString())) {
+ // WebKit: https://bugs.webkit.org/show_bug.cgi?id=135698 --- SVG elements do not
+ // support innerHTML, so detect this here and try to generate the contents
+ // specially.
+ $element.empty();
+ $compile(jqLiteBuildFragment(ctrl.template, document).childNodes)(scope,
+ function namespaceAdaptedClone(clone) {
+ $element.append(clone);
+ }, {futureParentElement: $element});
+ return;
+ }
+
$element.html(ctrl.template);
$compile($element.contents())(scope);
}
@@ -20070,7 +24146,7 @@ var ngIncludeFillContentDirective = ['$compile',
* The `ngInit` directive allows you to evaluate an expression in the
* current scope.
*
- * <div class="alert alert-error">
+ * <div class="alert alert-danger">
* The only appropriate use of `ngInit` is for aliasing special properties of
* {@link ng.directive:ngRepeat `ngRepeat`}, as seen in the demo below. Besides this case, you
* should use {@link guide/controller controllers} rather than `ngInit`
@@ -20080,7 +24156,7 @@ var ngIncludeFillContentDirective = ['$compile',
* **Note**: If you have assignment in `ngInit` along with {@link ng.$filter `$filter`}, make
* sure you have parenthesis for correct precedence:
* <pre class="prettyprint">
- * <div ng-init="test1 = (data | orderBy:'name')"></div>
+ * `<div ng-init="test1 = (data | orderBy:'name')"></div>`
* </pre>
* </div>
*
@@ -20130,6 +24206,1489 @@ var ngInitDirective = ngDirective({
/**
* @ngdoc directive
+ * @name ngList
+ *
+ * @description
+ * Text input that converts between a delimited string and an array of strings. The default
+ * delimiter is a comma followed by a space - equivalent to `ng-list=", "`. You can specify a custom
+ * delimiter as the value of the `ngList` attribute - for example, `ng-list=" | "`.
+ *
+ * The behaviour of the directive is affected by the use of the `ngTrim` attribute.
+ * * If `ngTrim` is set to `"false"` then whitespace around both the separator and each
+ * list item is respected. This implies that the user of the directive is responsible for
+ * dealing with whitespace but also allows you to use whitespace as a delimiter, such as a
+ * tab or newline character.
+ * * Otherwise whitespace around the delimiter is ignored when splitting (although it is respected
+ * when joining the list items back together) and whitespace around each list item is stripped
+ * before it is added to the model.
+ *
+ * ### Example with Validation
+ *
+ * <example name="ngList-directive" module="listExample">
+ * <file name="app.js">
+ * angular.module('listExample', [])
+ * .controller('ExampleController', ['$scope', function($scope) {
+ * $scope.names = ['morpheus', 'neo', 'trinity'];
+ * }]);
+ * </file>
+ * <file name="index.html">
+ * <form name="myForm" ng-controller="ExampleController">
+ * <label>List: <input name="namesInput" ng-model="names" ng-list required></label>
+ * <span role="alert">
+ * <span class="error" ng-show="myForm.namesInput.$error.required">
+ * Required!</span>
+ * </span>
+ * <br>
+ * <tt>names = {{names}}</tt><br/>
+ * <tt>myForm.namesInput.$valid = {{myForm.namesInput.$valid}}</tt><br/>
+ * <tt>myForm.namesInput.$error = {{myForm.namesInput.$error}}</tt><br/>
+ * <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
+ * <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
+ * </form>
+ * </file>
+ * <file name="protractor.js" type="protractor">
+ * var listInput = element(by.model('names'));
+ * var names = element(by.exactBinding('names'));
+ * var valid = element(by.binding('myForm.namesInput.$valid'));
+ * var error = element(by.css('span.error'));
+ *
+ * it('should initialize to model', function() {
+ * expect(names.getText()).toContain('["morpheus","neo","trinity"]');
+ * expect(valid.getText()).toContain('true');
+ * expect(error.getCssValue('display')).toBe('none');
+ * });
+ *
+ * it('should be invalid if empty', function() {
+ * listInput.clear();
+ * listInput.sendKeys('');
+ *
+ * expect(names.getText()).toContain('');
+ * expect(valid.getText()).toContain('false');
+ * expect(error.getCssValue('display')).not.toBe('none');
+ * });
+ * </file>
+ * </example>
+ *
+ * ### Example - splitting on whitespace
+ * <example name="ngList-directive-newlines">
+ * <file name="index.html">
+ * <textarea ng-model="list" ng-list="&#10;" ng-trim="false"></textarea>
+ * <pre>{{ list | json }}</pre>
+ * </file>
+ * <file name="protractor.js" type="protractor">
+ * it("should split the text by newlines", function() {
+ * var listInput = element(by.model('list'));
+ * var output = element(by.binding('list | json'));
+ * listInput.sendKeys('abc\ndef\nghi');
+ * expect(output.getText()).toContain('[\n "abc",\n "def",\n "ghi"\n]');
+ * });
+ * </file>
+ * </example>
+ *
+ * @element input
+ * @param {string=} ngList optional delimiter that should be used to split the value.
+ */
+var ngListDirective = function() {
+ return {
+ restrict: 'A',
+ priority: 100,
+ require: 'ngModel',
+ link: function(scope, element, attr, ctrl) {
+ // We want to control whitespace trimming so we use this convoluted approach
+ // to access the ngList attribute, which doesn't pre-trim the attribute
+ var ngList = element.attr(attr.$attr.ngList) || ', ';
+ var trimValues = attr.ngTrim !== 'false';
+ var separator = trimValues ? trim(ngList) : ngList;
+
+ var parse = function(viewValue) {
+ // If the viewValue is invalid (say required but empty) it will be `undefined`
+ if (isUndefined(viewValue)) return;
+
+ var list = [];
+
+ if (viewValue) {
+ forEach(viewValue.split(separator), function(value) {
+ if (value) list.push(trimValues ? trim(value) : value);
+ });
+ }
+
+ return list;
+ };
+
+ ctrl.$parsers.push(parse);
+ ctrl.$formatters.push(function(value) {
+ if (isArray(value)) {
+ return value.join(ngList);
+ }
+
+ return undefined;
+ });
+
+ // Override the standard $isEmpty because an empty array means the input is empty.
+ ctrl.$isEmpty = function(value) {
+ return !value || !value.length;
+ };
+ }
+ };
+};
+
+/* global VALID_CLASS: true,
+ INVALID_CLASS: true,
+ PRISTINE_CLASS: true,
+ DIRTY_CLASS: true,
+ UNTOUCHED_CLASS: true,
+ TOUCHED_CLASS: true,
+*/
+
+var VALID_CLASS = 'ng-valid',
+ INVALID_CLASS = 'ng-invalid',
+ PRISTINE_CLASS = 'ng-pristine',
+ DIRTY_CLASS = 'ng-dirty',
+ UNTOUCHED_CLASS = 'ng-untouched',
+ TOUCHED_CLASS = 'ng-touched',
+ PENDING_CLASS = 'ng-pending';
+
+
+var $ngModelMinErr = new minErr('ngModel');
+
+/**
+ * @ngdoc type
+ * @name ngModel.NgModelController
+ *
+ * @property {string} $viewValue Actual string value in the view.
+ * @property {*} $modelValue The value in the model that the control is bound to.
+ * @property {Array.<Function>} $parsers Array of functions to execute, as a pipeline, whenever
+ the control reads value from the DOM. The functions are called in array order, each passing
+ its return value through to the next. The last return value is forwarded to the
+ {@link ngModel.NgModelController#$validators `$validators`} collection.
+
+Parsers are used to sanitize / convert the {@link ngModel.NgModelController#$viewValue
+`$viewValue`}.
+
+Returning `undefined` from a parser means a parse error occurred. In that case,
+no {@link ngModel.NgModelController#$validators `$validators`} will run and the `ngModel`
+will be set to `undefined` unless {@link ngModelOptions `ngModelOptions.allowInvalid`}
+is set to `true`. The parse error is stored in `ngModel.$error.parse`.
+
+ *
+ * @property {Array.<Function>} $formatters Array of functions to execute, as a pipeline, whenever
+ the model value changes. The functions are called in reverse array order, each passing the value through to the
+ next. The last return value is used as the actual DOM value.
+ Used to format / convert values for display in the control.
+ * ```js
+ * function formatter(value) {
+ * if (value) {
+ * return value.toUpperCase();
+ * }
+ * }
+ * ngModel.$formatters.push(formatter);
+ * ```
+ *
+ * @property {Object.<string, function>} $validators A collection of validators that are applied
+ * whenever the model value changes. The key value within the object refers to the name of the
+ * validator while the function refers to the validation operation. The validation operation is
+ * provided with the model value as an argument and must return a true or false value depending
+ * on the response of that validation.
+ *
+ * ```js
+ * ngModel.$validators.validCharacters = function(modelValue, viewValue) {
+ * var value = modelValue || viewValue;
+ * return /[0-9]+/.test(value) &&
+ * /[a-z]+/.test(value) &&
+ * /[A-Z]+/.test(value) &&
+ * /\W+/.test(value);
+ * };
+ * ```
+ *
+ * @property {Object.<string, function>} $asyncValidators A collection of validations that are expected to
+ * perform an asynchronous validation (e.g. a HTTP request). The validation function that is provided
+ * is expected to return a promise when it is run during the model validation process. Once the promise
+ * is delivered then the validation status will be set to true when fulfilled and false when rejected.
+ * When the asynchronous validators are triggered, each of the validators will run in parallel and the model
+ * value will only be updated once all validators have been fulfilled. As long as an asynchronous validator
+ * is unfulfilled, its key will be added to the controllers `$pending` property. Also, all asynchronous validators
+ * will only run once all synchronous validators have passed.
+ *
+ * Please note that if $http is used then it is important that the server returns a success HTTP response code
+ * in order to fulfill the validation and a status level of `4xx` in order to reject the validation.
+ *
+ * ```js
+ * ngModel.$asyncValidators.uniqueUsername = function(modelValue, viewValue) {
+ * var value = modelValue || viewValue;
+ *
+ * // Lookup user by username
+ * return $http.get('/api/users/' + value).
+ * then(function resolved() {
+ * //username exists, this means validation fails
+ * return $q.reject('exists');
+ * }, function rejected() {
+ * //username does not exist, therefore this validation passes
+ * return true;
+ * });
+ * };
+ * ```
+ *
+ * @property {Array.<Function>} $viewChangeListeners Array of functions to execute whenever the
+ * view value has changed. It is called with no arguments, and its return value is ignored.
+ * This can be used in place of additional $watches against the model value.
+ *
+ * @property {Object} $error An object hash with all failing validator ids as keys.
+ * @property {Object} $pending An object hash with all pending validator ids as keys.
+ *
+ * @property {boolean} $untouched True if control has not lost focus yet.
+ * @property {boolean} $touched True if control has lost focus.
+ * @property {boolean} $pristine True if user has not interacted with the control yet.
+ * @property {boolean} $dirty True if user has already interacted with the control.
+ * @property {boolean} $valid True if there is no error.
+ * @property {boolean} $invalid True if at least one error on the control.
+ * @property {string} $name The name attribute of the control.
+ *
+ * @description
+ *
+ * `NgModelController` provides API for the {@link ngModel `ngModel`} directive.
+ * The controller contains services for data-binding, validation, CSS updates, and value formatting
+ * and parsing. It purposefully does not contain any logic which deals with DOM rendering or
+ * listening to DOM events.
+ * Such DOM related logic should be provided by other directives which make use of
+ * `NgModelController` for data-binding to control elements.
+ * Angular provides this DOM logic for most {@link input `input`} elements.
+ * At the end of this page you can find a {@link ngModel.NgModelController#custom-control-example
+ * custom control example} that uses `ngModelController` to bind to `contenteditable` elements.
+ *
+ * @example
+ * ### Custom Control Example
+ * This example shows how to use `NgModelController` with a custom control to achieve
+ * data-binding. Notice how different directives (`contenteditable`, `ng-model`, and `required`)
+ * collaborate together to achieve the desired result.
+ *
+ * `contenteditable` is an HTML5 attribute, which tells the browser to let the element
+ * contents be edited in place by the user.
+ *
+ * We are using the {@link ng.service:$sce $sce} service here and include the {@link ngSanitize $sanitize}
+ * module to automatically remove "bad" content like inline event listener (e.g. `<span onclick="...">`).
+ * However, as we are using `$sce` the model can still decide to provide unsafe content if it marks
+ * that content using the `$sce` service.
+ *
+ * <example name="NgModelController" module="customControl" deps="angular-sanitize.js">
+ <file name="style.css">
+ [contenteditable] {
+ border: 1px solid black;
+ background-color: white;
+ min-height: 20px;
+ }
+
+ .ng-invalid {
+ border: 1px solid red;
+ }
+
+ </file>
+ <file name="script.js">
+ angular.module('customControl', ['ngSanitize']).
+ directive('contenteditable', ['$sce', function($sce) {
+ return {
+ restrict: 'A', // only activate on element attribute
+ require: '?ngModel', // get a hold of NgModelController
+ link: function(scope, element, attrs, ngModel) {
+ if (!ngModel) return; // do nothing if no ng-model
+
+ // Specify how UI should be updated
+ ngModel.$render = function() {
+ element.html($sce.getTrustedHtml(ngModel.$viewValue || ''));
+ };
+
+ // Listen for change events to enable binding
+ element.on('blur keyup change', function() {
+ scope.$evalAsync(read);
+ });
+ read(); // initialize
+
+ // Write data to the model
+ function read() {
+ var html = element.html();
+ // When we clear the content editable the browser leaves a <br> behind
+ // If strip-br attribute is provided then we strip this out
+ if ( attrs.stripBr && html == '<br>' ) {
+ html = '';
+ }
+ ngModel.$setViewValue(html);
+ }
+ }
+ };
+ }]);
+ </file>
+ <file name="index.html">
+ <form name="myForm">
+ <div contenteditable
+ name="myWidget" ng-model="userContent"
+ strip-br="true"
+ required>Change me!</div>
+ <span ng-show="myForm.myWidget.$error.required">Required!</span>
+ <hr>
+ <textarea ng-model="userContent" aria-label="Dynamic textarea"></textarea>
+ </form>
+ </file>
+ <file name="protractor.js" type="protractor">
+ it('should data-bind and become invalid', function() {
+ if (browser.params.browser == 'safari' || browser.params.browser == 'firefox') {
+ // SafariDriver can't handle contenteditable
+ // and Firefox driver can't clear contenteditables very well
+ return;
+ }
+ var contentEditable = element(by.css('[contenteditable]'));
+ var content = 'Change me!';
+
+ expect(contentEditable.getText()).toEqual(content);
+
+ contentEditable.clear();
+ contentEditable.sendKeys(protractor.Key.BACK_SPACE);
+ expect(contentEditable.getText()).toEqual('');
+ expect(contentEditable.getAttribute('class')).toMatch(/ng-invalid-required/);
+ });
+ </file>
+ * </example>
+ *
+ *
+ */
+var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$parse', '$animate', '$timeout', '$rootScope', '$q', '$interpolate',
+ function($scope, $exceptionHandler, $attr, $element, $parse, $animate, $timeout, $rootScope, $q, $interpolate) {
+ this.$viewValue = Number.NaN;
+ this.$modelValue = Number.NaN;
+ this.$$rawModelValue = undefined; // stores the parsed modelValue / model set from scope regardless of validity.
+ this.$validators = {};
+ this.$asyncValidators = {};
+ this.$parsers = [];
+ this.$formatters = [];
+ this.$viewChangeListeners = [];
+ this.$untouched = true;
+ this.$touched = false;
+ this.$pristine = true;
+ this.$dirty = false;
+ this.$valid = true;
+ this.$invalid = false;
+ this.$error = {}; // keep invalid keys here
+ this.$$success = {}; // keep valid keys here
+ this.$pending = undefined; // keep pending keys here
+ this.$name = $interpolate($attr.name || '', false)($scope);
+
+
+ var parsedNgModel = $parse($attr.ngModel),
+ parsedNgModelAssign = parsedNgModel.assign,
+ ngModelGet = parsedNgModel,
+ ngModelSet = parsedNgModelAssign,
+ pendingDebounce = null,
+ parserValid,
+ ctrl = this;
+
+ this.$$setOptions = function(options) {
+ ctrl.$options = options;
+ if (options && options.getterSetter) {
+ var invokeModelGetter = $parse($attr.ngModel + '()'),
+ invokeModelSetter = $parse($attr.ngModel + '($$$p)');
+
+ ngModelGet = function($scope) {
+ var modelValue = parsedNgModel($scope);
+ if (isFunction(modelValue)) {
+ modelValue = invokeModelGetter($scope);
+ }
+ return modelValue;
+ };
+ ngModelSet = function($scope, newValue) {
+ if (isFunction(parsedNgModel($scope))) {
+ invokeModelSetter($scope, {$$$p: ctrl.$modelValue});
+ } else {
+ parsedNgModelAssign($scope, ctrl.$modelValue);
+ }
+ };
+ } else if (!parsedNgModel.assign) {
+ throw $ngModelMinErr('nonassign', "Expression '{0}' is non-assignable. Element: {1}",
+ $attr.ngModel, startingTag($element));
+ }
+ };
+
+ /**
+ * @ngdoc method
+ * @name ngModel.NgModelController#$render
+ *
+ * @description
+ * Called when the view needs to be updated. It is expected that the user of the ng-model
+ * directive will implement this method.
+ *
+ * The `$render()` method is invoked in the following situations:
+ *
+ * * `$rollbackViewValue()` is called. If we are rolling back the view value to the last
+ * committed value then `$render()` is called to update the input control.
+ * * The value referenced by `ng-model` is changed programmatically and both the `$modelValue` and
+ * the `$viewValue` are different from last time.
+ *
+ * Since `ng-model` does not do a deep watch, `$render()` is only invoked if the values of
+ * `$modelValue` and `$viewValue` are actually different from their previous value. If `$modelValue`
+ * or `$viewValue` are objects (rather than a string or number) then `$render()` will not be
+ * invoked if you only change a property on the objects.
+ */
+ this.$render = noop;
+
+ /**
+ * @ngdoc method
+ * @name ngModel.NgModelController#$isEmpty
+ *
+ * @description
+ * This is called when we need to determine if the value of an input is empty.
+ *
+ * For instance, the required directive does this to work out if the input has data or not.
+ *
+ * The default `$isEmpty` function checks whether the value is `undefined`, `''`, `null` or `NaN`.
+ *
+ * You can override this for input directives whose concept of being empty is different from the
+ * default. The `checkboxInputType` directive does this because in its case a value of `false`
+ * implies empty.
+ *
+ * @param {*} value The value of the input to check for emptiness.
+ * @returns {boolean} True if `value` is "empty".
+ */
+ this.$isEmpty = function(value) {
+ return isUndefined(value) || value === '' || value === null || value !== value;
+ };
+
+ var parentForm = $element.inheritedData('$formController') || nullFormCtrl,
+ currentValidationRunId = 0;
+
+ /**
+ * @ngdoc method
+ * @name ngModel.NgModelController#$setValidity
+ *
+ * @description
+ * Change the validity state, and notify the form.
+ *
+ * This method can be called within $parsers/$formatters or a custom validation implementation.
+ * However, in most cases it should be sufficient to use the `ngModel.$validators` and
+ * `ngModel.$asyncValidators` collections which will call `$setValidity` automatically.
+ *
+ * @param {string} validationErrorKey Name of the validator. The `validationErrorKey` will be assigned
+ * to either `$error[validationErrorKey]` or `$pending[validationErrorKey]`
+ * (for unfulfilled `$asyncValidators`), so that it is available for data-binding.
+ * The `validationErrorKey` should be in camelCase and will get converted into dash-case
+ * for class name. Example: `myError` will result in `ng-valid-my-error` and `ng-invalid-my-error`
+ * class and can be bound to as `{{someForm.someControl.$error.myError}}` .
+ * @param {boolean} isValid Whether the current state is valid (true), invalid (false), pending (undefined),
+ * or skipped (null). Pending is used for unfulfilled `$asyncValidators`.
+ * Skipped is used by Angular when validators do not run because of parse errors and
+ * when `$asyncValidators` do not run because any of the `$validators` failed.
+ */
+ addSetValidityMethod({
+ ctrl: this,
+ $element: $element,
+ set: function(object, property) {
+ object[property] = true;
+ },
+ unset: function(object, property) {
+ delete object[property];
+ },
+ parentForm: parentForm,
+ $animate: $animate
+ });
+
+ /**
+ * @ngdoc method
+ * @name ngModel.NgModelController#$setPristine
+ *
+ * @description
+ * Sets the control to its pristine state.
+ *
+ * This method can be called to remove the `ng-dirty` class and set the control to its pristine
+ * state (`ng-pristine` class). A model is considered to be pristine when the control
+ * has not been changed from when first compiled.
+ */
+ this.$setPristine = function() {
+ ctrl.$dirty = false;
+ ctrl.$pristine = true;
+ $animate.removeClass($element, DIRTY_CLASS);
+ $animate.addClass($element, PRISTINE_CLASS);
+ };
+
+ /**
+ * @ngdoc method
+ * @name ngModel.NgModelController#$setDirty
+ *
+ * @description
+ * Sets the control to its dirty state.
+ *
+ * This method can be called to remove the `ng-pristine` class and set the control to its dirty
+ * state (`ng-dirty` class). A model is considered to be dirty when the control has been changed
+ * from when first compiled.
+ */
+ this.$setDirty = function() {
+ ctrl.$dirty = true;
+ ctrl.$pristine = false;
+ $animate.removeClass($element, PRISTINE_CLASS);
+ $animate.addClass($element, DIRTY_CLASS);
+ parentForm.$setDirty();
+ };
+
+ /**
+ * @ngdoc method
+ * @name ngModel.NgModelController#$setUntouched
+ *
+ * @description
+ * Sets the control to its untouched state.
+ *
+ * This method can be called to remove the `ng-touched` class and set the control to its
+ * untouched state (`ng-untouched` class). Upon compilation, a model is set as untouched
+ * by default, however this function can be used to restore that state if the model has
+ * already been touched by the user.
+ */
+ this.$setUntouched = function() {
+ ctrl.$touched = false;
+ ctrl.$untouched = true;
+ $animate.setClass($element, UNTOUCHED_CLASS, TOUCHED_CLASS);
+ };
+
+ /**
+ * @ngdoc method
+ * @name ngModel.NgModelController#$setTouched
+ *
+ * @description
+ * Sets the control to its touched state.
+ *
+ * This method can be called to remove the `ng-untouched` class and set the control to its
+ * touched state (`ng-touched` class). A model is considered to be touched when the user has
+ * first focused the control element and then shifted focus away from the control (blur event).
+ */
+ this.$setTouched = function() {
+ ctrl.$touched = true;
+ ctrl.$untouched = false;
+ $animate.setClass($element, TOUCHED_CLASS, UNTOUCHED_CLASS);
+ };
+
+ /**
+ * @ngdoc method
+ * @name ngModel.NgModelController#$rollbackViewValue
+ *
+ * @description
+ * Cancel an update and reset the input element's value to prevent an update to the `$modelValue`,
+ * which may be caused by a pending debounced event or because the input is waiting for a some
+ * future event.
+ *
+ * If you have an input that uses `ng-model-options` to set up debounced events or events such
+ * as blur you can have a situation where there is a period when the `$viewValue`
+ * is out of synch with the ngModel's `$modelValue`.
+ *
+ * In this case, you can run into difficulties if you try to update the ngModel's `$modelValue`
+ * programmatically before these debounced/future events have resolved/occurred, because Angular's
+ * dirty checking mechanism is not able to tell whether the model has actually changed or not.
+ *
+ * The `$rollbackViewValue()` method should be called before programmatically changing the model of an
+ * input which may have such events pending. This is important in order to make sure that the
+ * input field will be updated with the new model value and any pending operations are cancelled.
+ *
+ * <example name="ng-model-cancel-update" module="cancel-update-example">
+ * <file name="app.js">
+ * angular.module('cancel-update-example', [])
+ *
+ * .controller('CancelUpdateController', ['$scope', function($scope) {
+ * $scope.resetWithCancel = function(e) {
+ * if (e.keyCode == 27) {
+ * $scope.myForm.myInput1.$rollbackViewValue();
+ * $scope.myValue = '';
+ * }
+ * };
+ * $scope.resetWithoutCancel = function(e) {
+ * if (e.keyCode == 27) {
+ * $scope.myValue = '';
+ * }
+ * };
+ * }]);
+ * </file>
+ * <file name="index.html">
+ * <div ng-controller="CancelUpdateController">
+ * <p>Try typing something in each input. See that the model only updates when you
+ * blur off the input.
+ * </p>
+ * <p>Now see what happens if you start typing then press the Escape key</p>
+ *
+ * <form name="myForm" ng-model-options="{ updateOn: 'blur' }">
+ * <p id="inputDescription1">With $rollbackViewValue()</p>
+ * <input name="myInput1" aria-describedby="inputDescription1" ng-model="myValue"
+ * ng-keydown="resetWithCancel($event)"><br/>
+ * myValue: "{{ myValue }}"
+ *
+ * <p id="inputDescription2">Without $rollbackViewValue()</p>
+ * <input name="myInput2" aria-describedby="inputDescription2" ng-model="myValue"
+ * ng-keydown="resetWithoutCancel($event)"><br/>
+ * myValue: "{{ myValue }}"
+ * </form>
+ * </div>
+ * </file>
+ * </example>
+ */
+ this.$rollbackViewValue = function() {
+ $timeout.cancel(pendingDebounce);
+ ctrl.$viewValue = ctrl.$$lastCommittedViewValue;
+ ctrl.$render();
+ };
+
+ /**
+ * @ngdoc method
+ * @name ngModel.NgModelController#$validate
+ *
+ * @description
+ * Runs each of the registered validators (first synchronous validators and then
+ * asynchronous validators).
+ * If the validity changes to invalid, the model will be set to `undefined`,
+ * unless {@link ngModelOptions `ngModelOptions.allowInvalid`} is `true`.
+ * If the validity changes to valid, it will set the model to the last available valid
+ * `$modelValue`, i.e. either the last parsed value or the last value set from the scope.
+ */
+ this.$validate = function() {
+ // ignore $validate before model is initialized
+ if (isNumber(ctrl.$modelValue) && isNaN(ctrl.$modelValue)) {
+ return;
+ }
+
+ var viewValue = ctrl.$$lastCommittedViewValue;
+ // Note: we use the $$rawModelValue as $modelValue might have been
+ // set to undefined during a view -> model update that found validation
+ // errors. We can't parse the view here, since that could change
+ // the model although neither viewValue nor the model on the scope changed
+ var modelValue = ctrl.$$rawModelValue;
+
+ var prevValid = ctrl.$valid;
+ var prevModelValue = ctrl.$modelValue;
+
+ var allowInvalid = ctrl.$options && ctrl.$options.allowInvalid;
+
+ ctrl.$$runValidators(modelValue, viewValue, function(allValid) {
+ // If there was no change in validity, don't update the model
+ // This prevents changing an invalid modelValue to undefined
+ if (!allowInvalid && prevValid !== allValid) {
+ // Note: Don't check ctrl.$valid here, as we could have
+ // external validators (e.g. calculated on the server),
+ // that just call $setValidity and need the model value
+ // to calculate their validity.
+ ctrl.$modelValue = allValid ? modelValue : undefined;
+
+ if (ctrl.$modelValue !== prevModelValue) {
+ ctrl.$$writeModelToScope();
+ }
+ }
+ });
+
+ };
+
+ this.$$runValidators = function(modelValue, viewValue, doneCallback) {
+ currentValidationRunId++;
+ var localValidationRunId = currentValidationRunId;
+
+ // check parser error
+ if (!processParseErrors()) {
+ validationDone(false);
+ return;
+ }
+ if (!processSyncValidators()) {
+ validationDone(false);
+ return;
+ }
+ processAsyncValidators();
+
+ function processParseErrors() {
+ var errorKey = ctrl.$$parserName || 'parse';
+ if (parserValid === undefined) {
+ setValidity(errorKey, null);
+ } else {
+ if (!parserValid) {
+ forEach(ctrl.$validators, function(v, name) {
+ setValidity(name, null);
+ });
+ forEach(ctrl.$asyncValidators, function(v, name) {
+ setValidity(name, null);
+ });
+ }
+ // Set the parse error last, to prevent unsetting it, should a $validators key == parserName
+ setValidity(errorKey, parserValid);
+ return parserValid;
+ }
+ return true;
+ }
+
+ function processSyncValidators() {
+ var syncValidatorsValid = true;
+ forEach(ctrl.$validators, function(validator, name) {
+ var result = validator(modelValue, viewValue);
+ syncValidatorsValid = syncValidatorsValid && result;
+ setValidity(name, result);
+ });
+ if (!syncValidatorsValid) {
+ forEach(ctrl.$asyncValidators, function(v, name) {
+ setValidity(name, null);
+ });
+ return false;
+ }
+ return true;
+ }
+
+ function processAsyncValidators() {
+ var validatorPromises = [];
+ var allValid = true;
+ forEach(ctrl.$asyncValidators, function(validator, name) {
+ var promise = validator(modelValue, viewValue);
+ if (!isPromiseLike(promise)) {
+ throw $ngModelMinErr("$asyncValidators",
+ "Expected asynchronous validator to return a promise but got '{0}' instead.", promise);
+ }
+ setValidity(name, undefined);
+ validatorPromises.push(promise.then(function() {
+ setValidity(name, true);
+ }, function(error) {
+ allValid = false;
+ setValidity(name, false);
+ }));
+ });
+ if (!validatorPromises.length) {
+ validationDone(true);
+ } else {
+ $q.all(validatorPromises).then(function() {
+ validationDone(allValid);
+ }, noop);
+ }
+ }
+
+ function setValidity(name, isValid) {
+ if (localValidationRunId === currentValidationRunId) {
+ ctrl.$setValidity(name, isValid);
+ }
+ }
+
+ function validationDone(allValid) {
+ if (localValidationRunId === currentValidationRunId) {
+
+ doneCallback(allValid);
+ }
+ }
+ };
+
+ /**
+ * @ngdoc method
+ * @name ngModel.NgModelController#$commitViewValue
+ *
+ * @description
+ * Commit a pending update to the `$modelValue`.
+ *
+ * Updates may be pending by a debounced event or because the input is waiting for a some future
+ * event defined in `ng-model-options`. this method is rarely needed as `NgModelController`
+ * usually handles calling this in response to input events.
+ */
+ this.$commitViewValue = function() {
+ var viewValue = ctrl.$viewValue;
+
+ $timeout.cancel(pendingDebounce);
+
+ // If the view value has not changed then we should just exit, except in the case where there is
+ // a native validator on the element. In this case the validation state may have changed even though
+ // the viewValue has stayed empty.
+ if (ctrl.$$lastCommittedViewValue === viewValue && (viewValue !== '' || !ctrl.$$hasNativeValidators)) {
+ return;
+ }
+ ctrl.$$lastCommittedViewValue = viewValue;
+
+ // change to dirty
+ if (ctrl.$pristine) {
+ this.$setDirty();
+ }
+ this.$$parseAndValidate();
+ };
+
+ this.$$parseAndValidate = function() {
+ var viewValue = ctrl.$$lastCommittedViewValue;
+ var modelValue = viewValue;
+ parserValid = isUndefined(modelValue) ? undefined : true;
+
+ if (parserValid) {
+ for (var i = 0; i < ctrl.$parsers.length; i++) {
+ modelValue = ctrl.$parsers[i](modelValue);
+ if (isUndefined(modelValue)) {
+ parserValid = false;
+ break;
+ }
+ }
+ }
+ if (isNumber(ctrl.$modelValue) && isNaN(ctrl.$modelValue)) {
+ // ctrl.$modelValue has not been touched yet...
+ ctrl.$modelValue = ngModelGet($scope);
+ }
+ var prevModelValue = ctrl.$modelValue;
+ var allowInvalid = ctrl.$options && ctrl.$options.allowInvalid;
+ ctrl.$$rawModelValue = modelValue;
+
+ if (allowInvalid) {
+ ctrl.$modelValue = modelValue;
+ writeToModelIfNeeded();
+ }
+
+ // Pass the $$lastCommittedViewValue here, because the cached viewValue might be out of date.
+ // This can happen if e.g. $setViewValue is called from inside a parser
+ ctrl.$$runValidators(modelValue, ctrl.$$lastCommittedViewValue, function(allValid) {
+ if (!allowInvalid) {
+ // Note: Don't check ctrl.$valid here, as we could have
+ // external validators (e.g. calculated on the server),
+ // that just call $setValidity and need the model value
+ // to calculate their validity.
+ ctrl.$modelValue = allValid ? modelValue : undefined;
+ writeToModelIfNeeded();
+ }
+ });
+
+ function writeToModelIfNeeded() {
+ if (ctrl.$modelValue !== prevModelValue) {
+ ctrl.$$writeModelToScope();
+ }
+ }
+ };
+
+ this.$$writeModelToScope = function() {
+ ngModelSet($scope, ctrl.$modelValue);
+ forEach(ctrl.$viewChangeListeners, function(listener) {
+ try {
+ listener();
+ } catch (e) {
+ $exceptionHandler(e);
+ }
+ });
+ };
+
+ /**
+ * @ngdoc method
+ * @name ngModel.NgModelController#$setViewValue
+ *
+ * @description
+ * Update the view value.
+ *
+ * This method should be called when an input directive want to change the view value; typically,
+ * this is done from within a DOM event handler.
+ *
+ * For example {@link ng.directive:input input} calls it when the value of the input changes and
+ * {@link ng.directive:select select} calls it when an option is selected.
+ *
+ * If the new `value` is an object (rather than a string or a number), we should make a copy of the
+ * object before passing it to `$setViewValue`. This is because `ngModel` does not perform a deep
+ * watch of objects, it only looks for a change of identity. If you only change the property of
+ * the object then ngModel will not realise that the object has changed and will not invoke the
+ * `$parsers` and `$validators` pipelines.
+ *
+ * For this reason, you should not change properties of the copy once it has been passed to
+ * `$setViewValue`. Otherwise you may cause the model value on the scope to change incorrectly.
+ *
+ * When this method is called, the new `value` will be staged for committing through the `$parsers`
+ * and `$validators` pipelines. If there are no special {@link ngModelOptions} specified then the staged
+ * value sent directly for processing, finally to be applied to `$modelValue` and then the
+ * **expression** specified in the `ng-model` attribute.
+ *
+ * Lastly, all the registered change listeners, in the `$viewChangeListeners` list, are called.
+ *
+ * In case the {@link ng.directive:ngModelOptions ngModelOptions} directive is used with `updateOn`
+ * and the `default` trigger is not listed, all those actions will remain pending until one of the
+ * `updateOn` events is triggered on the DOM element.
+ * All these actions will be debounced if the {@link ng.directive:ngModelOptions ngModelOptions}
+ * directive is used with a custom debounce for this particular event.
+ *
+ * Note that calling this function does not trigger a `$digest`.
+ *
+ * @param {string} value Value from the view.
+ * @param {string} trigger Event that triggered the update.
+ */
+ this.$setViewValue = function(value, trigger) {
+ ctrl.$viewValue = value;
+ if (!ctrl.$options || ctrl.$options.updateOnDefault) {
+ ctrl.$$debounceViewValueCommit(trigger);
+ }
+ };
+
+ this.$$debounceViewValueCommit = function(trigger) {
+ var debounceDelay = 0,
+ options = ctrl.$options,
+ debounce;
+
+ if (options && isDefined(options.debounce)) {
+ debounce = options.debounce;
+ if (isNumber(debounce)) {
+ debounceDelay = debounce;
+ } else if (isNumber(debounce[trigger])) {
+ debounceDelay = debounce[trigger];
+ } else if (isNumber(debounce['default'])) {
+ debounceDelay = debounce['default'];
+ }
+ }
+
+ $timeout.cancel(pendingDebounce);
+ if (debounceDelay) {
+ pendingDebounce = $timeout(function() {
+ ctrl.$commitViewValue();
+ }, debounceDelay);
+ } else if ($rootScope.$$phase) {
+ ctrl.$commitViewValue();
+ } else {
+ $scope.$apply(function() {
+ ctrl.$commitViewValue();
+ });
+ }
+ };
+
+ // model -> value
+ // Note: we cannot use a normal scope.$watch as we want to detect the following:
+ // 1. scope value is 'a'
+ // 2. user enters 'b'
+ // 3. ng-change kicks in and reverts scope value to 'a'
+ // -> scope value did not change since the last digest as
+ // ng-change executes in apply phase
+ // 4. view should be changed back to 'a'
+ $scope.$watch(function ngModelWatch() {
+ var modelValue = ngModelGet($scope);
+
+ // if scope model value and ngModel value are out of sync
+ // TODO(perf): why not move this to the action fn?
+ if (modelValue !== ctrl.$modelValue &&
+ // checks for NaN is needed to allow setting the model to NaN when there's an asyncValidator
+ (ctrl.$modelValue === ctrl.$modelValue || modelValue === modelValue)
+ ) {
+ ctrl.$modelValue = ctrl.$$rawModelValue = modelValue;
+ parserValid = undefined;
+
+ var formatters = ctrl.$formatters,
+ idx = formatters.length;
+
+ var viewValue = modelValue;
+ while (idx--) {
+ viewValue = formatters[idx](viewValue);
+ }
+ if (ctrl.$viewValue !== viewValue) {
+ ctrl.$viewValue = ctrl.$$lastCommittedViewValue = viewValue;
+ ctrl.$render();
+
+ ctrl.$$runValidators(modelValue, viewValue, noop);
+ }
+ }
+
+ return modelValue;
+ });
+}];
+
+
+/**
+ * @ngdoc directive
+ * @name ngModel
+ *
+ * @element input
+ * @priority 1
+ *
+ * @description
+ * The `ngModel` directive binds an `input`,`select`, `textarea` (or custom form control) to a
+ * property on the scope using {@link ngModel.NgModelController NgModelController},
+ * which is created and exposed by this directive.
+ *
+ * `ngModel` is responsible for:
+ *
+ * - Binding the view into the model, which other directives such as `input`, `textarea` or `select`
+ * require.
+ * - Providing validation behavior (i.e. required, number, email, url).
+ * - Keeping the state of the control (valid/invalid, dirty/pristine, touched/untouched, validation errors).
+ * - Setting related css classes on the element (`ng-valid`, `ng-invalid`, `ng-dirty`, `ng-pristine`, `ng-touched`, `ng-untouched`) including animations.
+ * - Registering the control with its parent {@link ng.directive:form form}.
+ *
+ * Note: `ngModel` will try to bind to the property given by evaluating the expression on the
+ * current scope. If the property doesn't already exist on this scope, it will be created
+ * implicitly and added to the scope.
+ *
+ * For best practices on using `ngModel`, see:
+ *
+ * - [Understanding Scopes](https://github.com/angular/angular.js/wiki/Understanding-Scopes)
+ *
+ * For basic examples, how to use `ngModel`, see:
+ *
+ * - {@link ng.directive:input input}
+ * - {@link input[text] text}
+ * - {@link input[checkbox] checkbox}
+ * - {@link input[radio] radio}
+ * - {@link input[number] number}
+ * - {@link input[email] email}
+ * - {@link input[url] url}
+ * - {@link input[date] date}
+ * - {@link input[datetime-local] datetime-local}
+ * - {@link input[time] time}
+ * - {@link input[month] month}
+ * - {@link input[week] week}
+ * - {@link ng.directive:select select}
+ * - {@link ng.directive:textarea textarea}
+ *
+ * # CSS classes
+ * The following CSS classes are added and removed on the associated input/select/textarea element
+ * depending on the validity of the model.
+ *
+ * - `ng-valid`: the model is valid
+ * - `ng-invalid`: the model is invalid
+ * - `ng-valid-[key]`: for each valid key added by `$setValidity`
+ * - `ng-invalid-[key]`: for each invalid key added by `$setValidity`
+ * - `ng-pristine`: the control hasn't been interacted with yet
+ * - `ng-dirty`: the control has been interacted with
+ * - `ng-touched`: the control has been blurred
+ * - `ng-untouched`: the control hasn't been blurred
+ * - `ng-pending`: any `$asyncValidators` are unfulfilled
+ *
+ * Keep in mind that ngAnimate can detect each of these classes when added and removed.
+ *
+ * ## Animation Hooks
+ *
+ * Animations within models are triggered when any of the associated CSS classes are added and removed
+ * on the input element which is attached to the model. These classes are: `.ng-pristine`, `.ng-dirty`,
+ * `.ng-invalid` and `.ng-valid` as well as any other validations that are performed on the model itself.
+ * The animations that are triggered within ngModel are similar to how they work in ngClass and
+ * animations can be hooked into using CSS transitions, keyframes as well as JS animations.
+ *
+ * The following example shows a simple way to utilize CSS transitions to style an input element
+ * that has been rendered as invalid after it has been validated:
+ *
+ * <pre>
+ * //be sure to include ngAnimate as a module to hook into more
+ * //advanced animations
+ * .my-input {
+ * transition:0.5s linear all;
+ * background: white;
+ * }
+ * .my-input.ng-invalid {
+ * background: red;
+ * color:white;
+ * }
+ * </pre>
+ *
+ * @example
+ * <example deps="angular-animate.js" animations="true" fixBase="true" module="inputExample">
+ <file name="index.html">
+ <script>
+ angular.module('inputExample', [])
+ .controller('ExampleController', ['$scope', function($scope) {
+ $scope.val = '1';
+ }]);
+ </script>
+ <style>
+ .my-input {
+ -webkit-transition:all linear 0.5s;
+ transition:all linear 0.5s;
+ background: transparent;
+ }
+ .my-input.ng-invalid {
+ color:white;
+ background: red;
+ }
+ </style>
+ <p id="inputDescription">
+ Update input to see transitions when valid/invalid.
+ Integer is a valid value.
+ </p>
+ <form name="testForm" ng-controller="ExampleController">
+ <input ng-model="val" ng-pattern="/^\d+$/" name="anim" class="my-input"
+ aria-describedby="inputDescription" />
+ </form>
+ </file>
+ * </example>
+ *
+ * ## Binding to a getter/setter
+ *
+ * Sometimes it's helpful to bind `ngModel` to a getter/setter function. A getter/setter is a
+ * function that returns a representation of the model when called with zero arguments, and sets
+ * the internal state of a model when called with an argument. It's sometimes useful to use this
+ * for models that have an internal representation that's different from what the model exposes
+ * to the view.
+ *
+ * <div class="alert alert-success">
+ * **Best Practice:** It's best to keep getters fast because Angular is likely to call them more
+ * frequently than other parts of your code.
+ * </div>
+ *
+ * You use this behavior by adding `ng-model-options="{ getterSetter: true }"` to an element that
+ * has `ng-model` attached to it. You can also add `ng-model-options="{ getterSetter: true }"` to
+ * a `<form>`, which will enable this behavior for all `<input>`s within it. See
+ * {@link ng.directive:ngModelOptions `ngModelOptions`} for more.
+ *
+ * The following example shows how to use `ngModel` with a getter/setter:
+ *
+ * @example
+ * <example name="ngModel-getter-setter" module="getterSetterExample">
+ <file name="index.html">
+ <div ng-controller="ExampleController">
+ <form name="userForm">
+ <label>Name:
+ <input type="text" name="userName"
+ ng-model="user.name"
+ ng-model-options="{ getterSetter: true }" />
+ </label>
+ </form>
+ <pre>user.name = <span ng-bind="user.name()"></span></pre>
+ </div>
+ </file>
+ <file name="app.js">
+ angular.module('getterSetterExample', [])
+ .controller('ExampleController', ['$scope', function($scope) {
+ var _name = 'Brian';
+ $scope.user = {
+ name: function(newName) {
+ // Note that newName can be undefined for two reasons:
+ // 1. Because it is called as a getter and thus called with no arguments
+ // 2. Because the property should actually be set to undefined. This happens e.g. if the
+ // input is invalid
+ return arguments.length ? (_name = newName) : _name;
+ }
+ };
+ }]);
+ </file>
+ * </example>
+ */
+var ngModelDirective = ['$rootScope', function($rootScope) {
+ return {
+ restrict: 'A',
+ require: ['ngModel', '^?form', '^?ngModelOptions'],
+ controller: NgModelController,
+ // Prelink needs to run before any input directive
+ // so that we can set the NgModelOptions in NgModelController
+ // before anyone else uses it.
+ priority: 1,
+ compile: function ngModelCompile(element) {
+ // Setup initial state of the control
+ element.addClass(PRISTINE_CLASS).addClass(UNTOUCHED_CLASS).addClass(VALID_CLASS);
+
+ return {
+ pre: function ngModelPreLink(scope, element, attr, ctrls) {
+ var modelCtrl = ctrls[0],
+ formCtrl = ctrls[1] || nullFormCtrl;
+
+ modelCtrl.$$setOptions(ctrls[2] && ctrls[2].$options);
+
+ // notify others, especially parent forms
+ formCtrl.$addControl(modelCtrl);
+
+ attr.$observe('name', function(newValue) {
+ if (modelCtrl.$name !== newValue) {
+ formCtrl.$$renameControl(modelCtrl, newValue);
+ }
+ });
+
+ scope.$on('$destroy', function() {
+ formCtrl.$removeControl(modelCtrl);
+ });
+ },
+ post: function ngModelPostLink(scope, element, attr, ctrls) {
+ var modelCtrl = ctrls[0];
+ if (modelCtrl.$options && modelCtrl.$options.updateOn) {
+ element.on(modelCtrl.$options.updateOn, function(ev) {
+ modelCtrl.$$debounceViewValueCommit(ev && ev.type);
+ });
+ }
+
+ element.on('blur', function(ev) {
+ if (modelCtrl.$touched) return;
+
+ if ($rootScope.$$phase) {
+ scope.$evalAsync(modelCtrl.$setTouched);
+ } else {
+ scope.$apply(modelCtrl.$setTouched);
+ }
+ });
+ }
+ };
+ }
+ };
+}];
+
+var DEFAULT_REGEXP = /(\s+|^)default(\s+|$)/;
+
+/**
+ * @ngdoc directive
+ * @name ngModelOptions
+ *
+ * @description
+ * Allows tuning how model updates are done. Using `ngModelOptions` you can specify a custom list of
+ * events that will trigger a model update and/or a debouncing delay so that the actual update only
+ * takes place when a timer expires; this timer will be reset after another change takes place.
+ *
+ * Given the nature of `ngModelOptions`, the value displayed inside input fields in the view might
+ * be different from the value in the actual model. This means that if you update the model you
+ * should also invoke {@link ngModel.NgModelController `$rollbackViewValue`} on the relevant input field in
+ * order to make sure it is synchronized with the model and that any debounced action is canceled.
+ *
+ * The easiest way to reference the control's {@link ngModel.NgModelController `$rollbackViewValue`}
+ * method is by making sure the input is placed inside a form that has a `name` attribute. This is
+ * important because `form` controllers are published to the related scope under the name in their
+ * `name` attribute.
+ *
+ * Any pending changes will take place immediately when an enclosing form is submitted via the
+ * `submit` event. Note that `ngClick` events will occur before the model is updated. Use `ngSubmit`
+ * to have access to the updated model.
+ *
+ * `ngModelOptions` has an effect on the element it's declared on and its descendants.
+ *
+ * @param {Object} ngModelOptions options to apply to the current model. Valid keys are:
+ * - `updateOn`: string specifying which event should the input be bound to. You can set several
+ * events using an space delimited list. There is a special event called `default` that
+ * matches the default events belonging of the control.
+ * - `debounce`: integer value which contains the debounce model update value in milliseconds. A
+ * value of 0 triggers an immediate update. If an object is supplied instead, you can specify a
+ * custom value for each event. For example:
+ * `ng-model-options="{ updateOn: 'default blur', debounce: { 'default': 500, 'blur': 0 } }"`
+ * - `allowInvalid`: boolean value which indicates that the model can be set with values that did
+ * not validate correctly instead of the default behavior of setting the model to undefined.
+ * - `getterSetter`: boolean value which determines whether or not to treat functions bound to
+ `ngModel` as getters/setters.
+ * - `timezone`: Defines the timezone to be used to read/write the `Date` instance in the model for
+ * `<input type="date">`, `<input type="time">`, ... . It understands UTC/GMT and the
+ * continental US time zone abbreviations, but for general use, use a time zone offset, for
+ * example, `'+0430'` (4 hours, 30 minutes east of the Greenwich meridian)
+ * If not specified, the timezone of the browser will be used.
+ *
+ * @example
+
+ The following example shows how to override immediate updates. Changes on the inputs within the
+ form will update the model only when the control loses focus (blur event). If `escape` key is
+ pressed while the input field is focused, the value is reset to the value in the current model.
+
+ <example name="ngModelOptions-directive-blur" module="optionsExample">
+ <file name="index.html">
+ <div ng-controller="ExampleController">
+ <form name="userForm">
+ <label>Name:
+ <input type="text" name="userName"
+ ng-model="user.name"
+ ng-model-options="{ updateOn: 'blur' }"
+ ng-keyup="cancel($event)" />
+ </label><br />
+ <label>Other data:
+ <input type="text" ng-model="user.data" />
+ </label><br />
+ </form>
+ <pre>user.name = <span ng-bind="user.name"></span></pre>
+ </div>
+ </file>
+ <file name="app.js">
+ angular.module('optionsExample', [])
+ .controller('ExampleController', ['$scope', function($scope) {
+ $scope.user = { name: 'say', data: '' };
+
+ $scope.cancel = function(e) {
+ if (e.keyCode == 27) {
+ $scope.userForm.userName.$rollbackViewValue();
+ }
+ };
+ }]);
+ </file>
+ <file name="protractor.js" type="protractor">
+ var model = element(by.binding('user.name'));
+ var input = element(by.model('user.name'));
+ var other = element(by.model('user.data'));
+
+ it('should allow custom events', function() {
+ input.sendKeys(' hello');
+ input.click();
+ expect(model.getText()).toEqual('say');
+ other.click();
+ expect(model.getText()).toEqual('say hello');
+ });
+
+ it('should $rollbackViewValue when model changes', function() {
+ input.sendKeys(' hello');
+ expect(input.getAttribute('value')).toEqual('say hello');
+ input.sendKeys(protractor.Key.ESCAPE);
+ expect(input.getAttribute('value')).toEqual('say');
+ other.click();
+ expect(model.getText()).toEqual('say');
+ });
+ </file>
+ </example>
+
+ This one shows how to debounce model changes. Model will be updated only 1 sec after last change.
+ If the `Clear` button is pressed, any debounced action is canceled and the value becomes empty.
+
+ <example name="ngModelOptions-directive-debounce" module="optionsExample">
+ <file name="index.html">
+ <div ng-controller="ExampleController">
+ <form name="userForm">
+ <label>Name:
+ <input type="text" name="userName"
+ ng-model="user.name"
+ ng-model-options="{ debounce: 1000 }" />
+ </label>
+ <button ng-click="userForm.userName.$rollbackViewValue(); user.name=''">Clear</button>
+ <br />
+ </form>
+ <pre>user.name = <span ng-bind="user.name"></span></pre>
+ </div>
+ </file>
+ <file name="app.js">
+ angular.module('optionsExample', [])
+ .controller('ExampleController', ['$scope', function($scope) {
+ $scope.user = { name: 'say' };
+ }]);
+ </file>
+ </example>
+
+ This one shows how to bind to getter/setters:
+
+ <example name="ngModelOptions-directive-getter-setter" module="getterSetterExample">
+ <file name="index.html">
+ <div ng-controller="ExampleController">
+ <form name="userForm">
+ <label>Name:
+ <input type="text" name="userName"
+ ng-model="user.name"
+ ng-model-options="{ getterSetter: true }" />
+ </label>
+ </form>
+ <pre>user.name = <span ng-bind="user.name()"></span></pre>
+ </div>
+ </file>
+ <file name="app.js">
+ angular.module('getterSetterExample', [])
+ .controller('ExampleController', ['$scope', function($scope) {
+ var _name = 'Brian';
+ $scope.user = {
+ name: function(newName) {
+ // Note that newName can be undefined for two reasons:
+ // 1. Because it is called as a getter and thus called with no arguments
+ // 2. Because the property should actually be set to undefined. This happens e.g. if the
+ // input is invalid
+ return arguments.length ? (_name = newName) : _name;
+ }
+ };
+ }]);
+ </file>
+ </example>
+ */
+var ngModelOptionsDirective = function() {
+ return {
+ restrict: 'A',
+ controller: ['$scope', '$attrs', function($scope, $attrs) {
+ var that = this;
+ this.$options = copy($scope.$eval($attrs.ngModelOptions));
+ // Allow adding/overriding bound events
+ if (this.$options.updateOn !== undefined) {
+ this.$options.updateOnDefault = false;
+ // extract "default" pseudo-event from list of events that can trigger a model update
+ this.$options.updateOn = trim(this.$options.updateOn.replace(DEFAULT_REGEXP, function() {
+ that.$options.updateOnDefault = true;
+ return ' ';
+ }));
+ } else {
+ this.$options.updateOnDefault = true;
+ }
+ }]
+ };
+};
+
+
+
+// helper methods
+function addSetValidityMethod(context) {
+ var ctrl = context.ctrl,
+ $element = context.$element,
+ classCache = {},
+ set = context.set,
+ unset = context.unset,
+ parentForm = context.parentForm,
+ $animate = context.$animate;
+
+ classCache[INVALID_CLASS] = !(classCache[VALID_CLASS] = $element.hasClass(VALID_CLASS));
+
+ ctrl.$setValidity = setValidity;
+
+ function setValidity(validationErrorKey, state, controller) {
+ if (state === undefined) {
+ createAndSet('$pending', validationErrorKey, controller);
+ } else {
+ unsetAndCleanup('$pending', validationErrorKey, controller);
+ }
+ if (!isBoolean(state)) {
+ unset(ctrl.$error, validationErrorKey, controller);
+ unset(ctrl.$$success, validationErrorKey, controller);
+ } else {
+ if (state) {
+ unset(ctrl.$error, validationErrorKey, controller);
+ set(ctrl.$$success, validationErrorKey, controller);
+ } else {
+ set(ctrl.$error, validationErrorKey, controller);
+ unset(ctrl.$$success, validationErrorKey, controller);
+ }
+ }
+ if (ctrl.$pending) {
+ cachedToggleClass(PENDING_CLASS, true);
+ ctrl.$valid = ctrl.$invalid = undefined;
+ toggleValidationCss('', null);
+ } else {
+ cachedToggleClass(PENDING_CLASS, false);
+ ctrl.$valid = isObjectEmpty(ctrl.$error);
+ ctrl.$invalid = !ctrl.$valid;
+ toggleValidationCss('', ctrl.$valid);
+ }
+
+ // re-read the state as the set/unset methods could have
+ // combined state in ctrl.$error[validationError] (used for forms),
+ // where setting/unsetting only increments/decrements the value,
+ // and does not replace it.
+ var combinedState;
+ if (ctrl.$pending && ctrl.$pending[validationErrorKey]) {
+ combinedState = undefined;
+ } else if (ctrl.$error[validationErrorKey]) {
+ combinedState = false;
+ } else if (ctrl.$$success[validationErrorKey]) {
+ combinedState = true;
+ } else {
+ combinedState = null;
+ }
+
+ toggleValidationCss(validationErrorKey, combinedState);
+ parentForm.$setValidity(validationErrorKey, combinedState, ctrl);
+ }
+
+ function createAndSet(name, value, controller) {
+ if (!ctrl[name]) {
+ ctrl[name] = {};
+ }
+ set(ctrl[name], value, controller);
+ }
+
+ function unsetAndCleanup(name, value, controller) {
+ if (ctrl[name]) {
+ unset(ctrl[name], value, controller);
+ }
+ if (isObjectEmpty(ctrl[name])) {
+ ctrl[name] = undefined;
+ }
+ }
+
+ function cachedToggleClass(className, switchValue) {
+ if (switchValue && !classCache[className]) {
+ $animate.addClass($element, className);
+ classCache[className] = true;
+ } else if (!switchValue && classCache[className]) {
+ $animate.removeClass($element, className);
+ classCache[className] = false;
+ }
+ }
+
+ function toggleValidationCss(validationErrorKey, isValid) {
+ validationErrorKey = validationErrorKey ? '-' + snake_case(validationErrorKey, '-') : '';
+
+ cachedToggleClass(VALID_CLASS + validationErrorKey, isValid === true);
+ cachedToggleClass(INVALID_CLASS + validationErrorKey, isValid === false);
+ }
+}
+
+function isObjectEmpty(obj) {
+ if (obj) {
+ for (var prop in obj) {
+ if (obj.hasOwnProperty(prop)) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+/**
+ * @ngdoc directive
* @name ngNonBindable
* @restrict AC
* @priority 1000
@@ -20162,6 +25721,732 @@ var ngInitDirective = ngDirective({
*/
var ngNonBindableDirective = ngDirective({ terminal: true, priority: 1000 });
+/* global jqLiteRemove */
+
+var ngOptionsMinErr = minErr('ngOptions');
+
+/**
+ * @ngdoc directive
+ * @name ngOptions
+ * @restrict A
+ *
+ * @description
+ *
+ * The `ngOptions` attribute can be used to dynamically generate a list of `<option>`
+ * elements for the `<select>` element using the array or object obtained by evaluating the
+ * `ngOptions` comprehension expression.
+ *
+ * In many cases, `ngRepeat` can be used on `<option>` elements instead of `ngOptions` to achieve a
+ * similar result. However, `ngOptions` provides some benefits such as reducing memory and
+ * increasing speed by not creating a new scope for each repeated instance, as well as providing
+ * more flexibility in how the `<select>`'s model is assigned via the `select` **`as`** part of the
+ * comprehension expression. `ngOptions` should be used when the `<select>` model needs to be bound
+ * to a non-string value. This is because an option element can only be bound to string values at
+ * present.
+ *
+ * When an item in the `<select>` menu is selected, the array element or object property
+ * represented by the selected option will be bound to the model identified by the `ngModel`
+ * directive.
+ *
+ * Optionally, a single hard-coded `<option>` element, with the value set to an empty string, can
+ * be nested into the `<select>` element. This element will then represent the `null` or "not selected"
+ * option. See example below for demonstration.
+ *
+ * ## Complex Models (objects or collections)
+ *
+ * **Note:** By default, `ngModel` watches the model by reference, not value. This is important when
+ * binding any input directive to a model that is an object or a collection.
+ *
+ * Since this is a common situation for `ngOptions` the directive additionally watches the model using
+ * `$watchCollection` when the select has the `multiple` attribute or when there is a `track by` clause in
+ * the options expression. This allows ngOptions to trigger a re-rendering of the options even if the actual
+ * object/collection has not changed identity but only a property on the object or an item in the collection
+ * changes.
+ *
+ * Note that `$watchCollection` does a shallow comparison of the properties of the object (or the items in the collection
+ * if the model is an array). This means that changing a property deeper inside the object/collection that the
+ * first level will not trigger a re-rendering.
+ *
+ *
+ * ## `select` **`as`**
+ *
+ * Using `select` **`as`** will bind the result of the `select` expression to the model, but
+ * the value of the `<select>` and `<option>` html elements will be either the index (for array data sources)
+ * or property name (for object data sources) of the value within the collection. If a **`track by`** expression
+ * is used, the result of that expression will be set as the value of the `option` and `select` elements.
+ *
+ *
+ * ### `select` **`as`** and **`track by`**
+ *
+ * <div class="alert alert-warning">
+ * Do not use `select` **`as`** and **`track by`** in the same expression. They are not designed to work together.
+ * </div>
+ *
+ * Consider the following example:
+ *
+ * ```html
+ * <select ng-options="item.subItem as item.label for item in values track by item.id" ng-model="selected">
+ * ```
+ *
+ * ```js
+ * $scope.values = [{
+ * id: 1,
+ * label: 'aLabel',
+ * subItem: { name: 'aSubItem' }
+ * }, {
+ * id: 2,
+ * label: 'bLabel',
+ * subItem: { name: 'bSubItem' }
+ * }];
+ *
+ * $scope.selected = { name: 'aSubItem' };
+ * ```
+ *
+ * With the purpose of preserving the selection, the **`track by`** expression is always applied to the element
+ * of the data source (to `item` in this example). To calculate whether an element is selected, we do the
+ * following:
+ *
+ * 1. Apply **`track by`** to the elements in the array. In the example: `[1, 2]`
+ * 2. Apply **`track by`** to the already selected value in `ngModel`.
+ * In the example: this is not possible as **`track by`** refers to `item.id`, but the selected
+ * value from `ngModel` is `{name: 'aSubItem'}`, so the **`track by`** expression is applied to
+ * a wrong object, the selected element can't be found, `<select>` is always reset to the "not
+ * selected" option.
+ *
+ *
+ * @param {string} ngModel Assignable angular expression to data-bind to.
+ * @param {string=} name Property name of the form under which the control is published.
+ * @param {string=} required The control is considered valid only if value is entered.
+ * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
+ * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
+ * `required` when you want to data-bind to the `required` attribute.
+ * @param {comprehension_expression=} ngOptions in one of the following forms:
+ *
+ * * for array data sources:
+ * * `label` **`for`** `value` **`in`** `array`
+ * * `select` **`as`** `label` **`for`** `value` **`in`** `array`
+ * * `label` **`group by`** `group` **`for`** `value` **`in`** `array`
+ * * `label` **`disable when`** `disable` **`for`** `value` **`in`** `array`
+ * * `label` **`group by`** `group` **`for`** `value` **`in`** `array` **`track by`** `trackexpr`
+ * * `label` **`disable when`** `disable` **`for`** `value` **`in`** `array` **`track by`** `trackexpr`
+ * * `label` **`for`** `value` **`in`** `array` | orderBy:`orderexpr` **`track by`** `trackexpr`
+ * (for including a filter with `track by`)
+ * * for object data sources:
+ * * `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
+ * * `select` **`as`** `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
+ * * `label` **`group by`** `group` **`for (`**`key`**`,`** `value`**`) in`** `object`
+ * * `label` **`disable when`** `disable` **`for (`**`key`**`,`** `value`**`) in`** `object`
+ * * `select` **`as`** `label` **`group by`** `group`
+ * **`for` `(`**`key`**`,`** `value`**`) in`** `object`
+ * * `select` **`as`** `label` **`disable when`** `disable`
+ * **`for` `(`**`key`**`,`** `value`**`) in`** `object`
+ *
+ * Where:
+ *
+ * * `array` / `object`: an expression which evaluates to an array / object to iterate over.
+ * * `value`: local variable which will refer to each item in the `array` or each property value
+ * of `object` during iteration.
+ * * `key`: local variable which will refer to a property name in `object` during iteration.
+ * * `label`: The result of this expression will be the label for `<option>` element. The
+ * `expression` will most likely refer to the `value` variable (e.g. `value.propertyName`).
+ * * `select`: The result of this expression will be bound to the model of the parent `<select>`
+ * element. If not specified, `select` expression will default to `value`.
+ * * `group`: The result of this expression will be used to group options using the `<optgroup>`
+ * DOM element.
+ * * `disable`: The result of this expression will be used to disable the rendered `<option>`
+ * element. Return `true` to disable.
+ * * `trackexpr`: Used when working with an array of objects. The result of this expression will be
+ * used to identify the objects in the array. The `trackexpr` will most likely refer to the
+ * `value` variable (e.g. `value.propertyName`). With this the selection is preserved
+ * even when the options are recreated (e.g. reloaded from the server).
+ *
+ * @example
+ <example module="selectExample">
+ <file name="index.html">
+ <script>
+ angular.module('selectExample', [])
+ .controller('ExampleController', ['$scope', function($scope) {
+ $scope.colors = [
+ {name:'black', shade:'dark'},
+ {name:'white', shade:'light', notAnOption: true},
+ {name:'red', shade:'dark'},
+ {name:'blue', shade:'dark', notAnOption: true},
+ {name:'yellow', shade:'light', notAnOption: false}
+ ];
+ $scope.myColor = $scope.colors[2]; // red
+ }]);
+ </script>
+ <div ng-controller="ExampleController">
+ <ul>
+ <li ng-repeat="color in colors">
+ <label>Name: <input ng-model="color.name"></label>
+ <label><input type="checkbox" ng-model="color.notAnOption"> Disabled?</label>
+ <button ng-click="colors.splice($index, 1)" aria-label="Remove">X</button>
+ </li>
+ <li>
+ <button ng-click="colors.push({})">add</button>
+ </li>
+ </ul>
+ <hr/>
+ <label>Color (null not allowed):
+ <select ng-model="myColor" ng-options="color.name for color in colors"></select>
+ </label><br/>
+ <label>Color (null allowed):
+ <span class="nullable">
+ <select ng-model="myColor" ng-options="color.name for color in colors">
+ <option value="">-- choose color --</option>
+ </select>
+ </span></label><br/>
+
+ <label>Color grouped by shade:
+ <select ng-model="myColor" ng-options="color.name group by color.shade for color in colors">
+ </select>
+ </label><br/>
+
+ <label>Color grouped by shade, with some disabled:
+ <select ng-model="myColor"
+ ng-options="color.name group by color.shade disable when color.notAnOption for color in colors">
+ </select>
+ </label><br/>
+
+
+
+ Select <button ng-click="myColor = { name:'not in list', shade: 'other' }">bogus</button>.
+ <br/>
+ <hr/>
+ Currently selected: {{ {selected_color:myColor} }}
+ <div style="border:solid 1px black; height:20px"
+ ng-style="{'background-color':myColor.name}">
+ </div>
+ </div>
+ </file>
+ <file name="protractor.js" type="protractor">
+ it('should check ng-options', function() {
+ expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('red');
+ element.all(by.model('myColor')).first().click();
+ element.all(by.css('select[ng-model="myColor"] option')).first().click();
+ expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('black');
+ element(by.css('.nullable select[ng-model="myColor"]')).click();
+ element.all(by.css('.nullable select[ng-model="myColor"] option')).first().click();
+ expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('null');
+ });
+ </file>
+ </example>
+ */
+
+// jshint maxlen: false
+// //00001111111111000000000002222222222000000000000000000000333333333300000000000000000000000004444444444400000000000005555555555555550000000006666666666666660000000777777777777777000000000000000888888888800000000000000000009999999999
+var NG_OPTIONS_REGEXP = /^\s*([\s\S]+?)(?:\s+as\s+([\s\S]+?))?(?:\s+group\s+by\s+([\s\S]+?))?(?:\s+disable\s+when\s+([\s\S]+?))?\s+for\s+(?:([\$\w][\$\w]*)|(?:\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)))\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?$/;
+ // 1: value expression (valueFn)
+ // 2: label expression (displayFn)
+ // 3: group by expression (groupByFn)
+ // 4: disable when expression (disableWhenFn)
+ // 5: array item variable name
+ // 6: object item key variable name
+ // 7: object item value variable name
+ // 8: collection expression
+ // 9: track by expression
+// jshint maxlen: 100
+
+
+var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
+
+ function parseOptionsExpression(optionsExp, selectElement, scope) {
+
+ var match = optionsExp.match(NG_OPTIONS_REGEXP);
+ if (!(match)) {
+ throw ngOptionsMinErr('iexp',
+ "Expected expression in form of " +
+ "'_select_ (as _label_)? for (_key_,)?_value_ in _collection_'" +
+ " but got '{0}'. Element: {1}",
+ optionsExp, startingTag(selectElement));
+ }
+
+ // Extract the parts from the ngOptions expression
+
+ // The variable name for the value of the item in the collection
+ var valueName = match[5] || match[7];
+ // The variable name for the key of the item in the collection
+ var keyName = match[6];
+
+ // An expression that generates the viewValue for an option if there is a label expression
+ var selectAs = / as /.test(match[0]) && match[1];
+ // An expression that is used to track the id of each object in the options collection
+ var trackBy = match[9];
+ // An expression that generates the viewValue for an option if there is no label expression
+ var valueFn = $parse(match[2] ? match[1] : valueName);
+ var selectAsFn = selectAs && $parse(selectAs);
+ var viewValueFn = selectAsFn || valueFn;
+ var trackByFn = trackBy && $parse(trackBy);
+
+ // Get the value by which we are going to track the option
+ // if we have a trackFn then use that (passing scope and locals)
+ // otherwise just hash the given viewValue
+ var getTrackByValueFn = trackBy ?
+ function(value, locals) { return trackByFn(scope, locals); } :
+ function getHashOfValue(value) { return hashKey(value); };
+ var getTrackByValue = function(value, key) {
+ return getTrackByValueFn(value, getLocals(value, key));
+ };
+
+ var displayFn = $parse(match[2] || match[1]);
+ var groupByFn = $parse(match[3] || '');
+ var disableWhenFn = $parse(match[4] || '');
+ var valuesFn = $parse(match[8]);
+
+ var locals = {};
+ var getLocals = keyName ? function(value, key) {
+ locals[keyName] = key;
+ locals[valueName] = value;
+ return locals;
+ } : function(value) {
+ locals[valueName] = value;
+ return locals;
+ };
+
+
+ function Option(selectValue, viewValue, label, group, disabled) {
+ this.selectValue = selectValue;
+ this.viewValue = viewValue;
+ this.label = label;
+ this.group = group;
+ this.disabled = disabled;
+ }
+
+ function getOptionValuesKeys(optionValues) {
+ var optionValuesKeys;
+
+ if (!keyName && isArrayLike(optionValues)) {
+ optionValuesKeys = optionValues;
+ } else {
+ // if object, extract keys, in enumeration order, unsorted
+ optionValuesKeys = [];
+ for (var itemKey in optionValues) {
+ if (optionValues.hasOwnProperty(itemKey) && itemKey.charAt(0) !== '$') {
+ optionValuesKeys.push(itemKey);
+ }
+ }
+ }
+ return optionValuesKeys;
+ }
+
+ return {
+ trackBy: trackBy,
+ getTrackByValue: getTrackByValue,
+ getWatchables: $parse(valuesFn, function(optionValues) {
+ // Create a collection of things that we would like to watch (watchedArray)
+ // so that they can all be watched using a single $watchCollection
+ // that only runs the handler once if anything changes
+ var watchedArray = [];
+ optionValues = optionValues || [];
+
+ var optionValuesKeys = getOptionValuesKeys(optionValues);
+ var optionValuesLength = optionValuesKeys.length;
+ for (var index = 0; index < optionValuesLength; index++) {
+ var key = (optionValues === optionValuesKeys) ? index : optionValuesKeys[index];
+ var value = optionValues[key];
+
+ var locals = getLocals(optionValues[key], key);
+ var selectValue = getTrackByValueFn(optionValues[key], locals);
+ watchedArray.push(selectValue);
+
+ // Only need to watch the displayFn if there is a specific label expression
+ if (match[2] || match[1]) {
+ var label = displayFn(scope, locals);
+ watchedArray.push(label);
+ }
+
+ // Only need to watch the disableWhenFn if there is a specific disable expression
+ if (match[4]) {
+ var disableWhen = disableWhenFn(scope, locals);
+ watchedArray.push(disableWhen);
+ }
+ }
+ return watchedArray;
+ }),
+
+ getOptions: function() {
+
+ var optionItems = [];
+ var selectValueMap = {};
+
+ // The option values were already computed in the `getWatchables` fn,
+ // which must have been called to trigger `getOptions`
+ var optionValues = valuesFn(scope) || [];
+ var optionValuesKeys = getOptionValuesKeys(optionValues);
+ var optionValuesLength = optionValuesKeys.length;
+
+ for (var index = 0; index < optionValuesLength; index++) {
+ var key = (optionValues === optionValuesKeys) ? index : optionValuesKeys[index];
+ var value = optionValues[key];
+ var locals = getLocals(value, key);
+ var viewValue = viewValueFn(scope, locals);
+ var selectValue = getTrackByValueFn(viewValue, locals);
+ var label = displayFn(scope, locals);
+ var group = groupByFn(scope, locals);
+ var disabled = disableWhenFn(scope, locals);
+ var optionItem = new Option(selectValue, viewValue, label, group, disabled);
+
+ optionItems.push(optionItem);
+ selectValueMap[selectValue] = optionItem;
+ }
+
+ return {
+ items: optionItems,
+ selectValueMap: selectValueMap,
+ getOptionFromViewValue: function(value) {
+ return selectValueMap[getTrackByValue(value)];
+ },
+ getViewValueFromOption: function(option) {
+ // If the viewValue could be an object that may be mutated by the application,
+ // we need to make a copy and not return the reference to the value on the option.
+ return trackBy ? angular.copy(option.viewValue) : option.viewValue;
+ }
+ };
+ }
+ };
+ }
+
+
+ // we can't just jqLite('<option>') since jqLite is not smart enough
+ // to create it in <select> and IE barfs otherwise.
+ var optionTemplate = document.createElement('option'),
+ optGroupTemplate = document.createElement('optgroup');
+
+ return {
+ restrict: 'A',
+ terminal: true,
+ require: ['select', '?ngModel'],
+ link: function(scope, selectElement, attr, ctrls) {
+
+ // if ngModel is not defined, we don't need to do anything
+ var ngModelCtrl = ctrls[1];
+ if (!ngModelCtrl) return;
+
+ var selectCtrl = ctrls[0];
+ var multiple = attr.multiple;
+
+ // The emptyOption allows the application developer to provide their own custom "empty"
+ // option when the viewValue does not match any of the option values.
+ var emptyOption;
+ for (var i = 0, children = selectElement.children(), ii = children.length; i < ii; i++) {
+ if (children[i].value === '') {
+ emptyOption = children.eq(i);
+ break;
+ }
+ }
+
+ var providedEmptyOption = !!emptyOption;
+
+ var unknownOption = jqLite(optionTemplate.cloneNode(false));
+ unknownOption.val('?');
+
+ var options;
+ var ngOptions = parseOptionsExpression(attr.ngOptions, selectElement, scope);
+
+
+ var renderEmptyOption = function() {
+ if (!providedEmptyOption) {
+ selectElement.prepend(emptyOption);
+ }
+ selectElement.val('');
+ emptyOption.prop('selected', true); // needed for IE
+ emptyOption.attr('selected', true);
+ };
+
+ var removeEmptyOption = function() {
+ if (!providedEmptyOption) {
+ emptyOption.remove();
+ }
+ };
+
+
+ var renderUnknownOption = function() {
+ selectElement.prepend(unknownOption);
+ selectElement.val('?');
+ unknownOption.prop('selected', true); // needed for IE
+ unknownOption.attr('selected', true);
+ };
+
+ var removeUnknownOption = function() {
+ unknownOption.remove();
+ };
+
+
+ // Update the controller methods for multiple selectable options
+ if (!multiple) {
+
+ selectCtrl.writeValue = function writeNgOptionsValue(value) {
+ var option = options.getOptionFromViewValue(value);
+
+ if (option && !option.disabled) {
+ if (selectElement[0].value !== option.selectValue) {
+ removeUnknownOption();
+ removeEmptyOption();
+
+ selectElement[0].value = option.selectValue;
+ option.element.selected = true;
+ option.element.setAttribute('selected', 'selected');
+ }
+ } else {
+ if (value === null || providedEmptyOption) {
+ removeUnknownOption();
+ renderEmptyOption();
+ } else {
+ removeEmptyOption();
+ renderUnknownOption();
+ }
+ }
+ };
+
+ selectCtrl.readValue = function readNgOptionsValue() {
+
+ var selectedOption = options.selectValueMap[selectElement.val()];
+
+ if (selectedOption && !selectedOption.disabled) {
+ removeEmptyOption();
+ removeUnknownOption();
+ return options.getViewValueFromOption(selectedOption);
+ }
+ return null;
+ };
+
+ // If we are using `track by` then we must watch the tracked value on the model
+ // since ngModel only watches for object identity change
+ if (ngOptions.trackBy) {
+ scope.$watch(
+ function() { return ngOptions.getTrackByValue(ngModelCtrl.$viewValue); },
+ function() { ngModelCtrl.$render(); }
+ );
+ }
+
+ } else {
+
+ ngModelCtrl.$isEmpty = function(value) {
+ return !value || value.length === 0;
+ };
+
+
+ selectCtrl.writeValue = function writeNgOptionsMultiple(value) {
+ options.items.forEach(function(option) {
+ option.element.selected = false;
+ });
+
+ if (value) {
+ value.forEach(function(item) {
+ var option = options.getOptionFromViewValue(item);
+ if (option && !option.disabled) option.element.selected = true;
+ });
+ }
+ };
+
+
+ selectCtrl.readValue = function readNgOptionsMultiple() {
+ var selectedValues = selectElement.val() || [],
+ selections = [];
+
+ forEach(selectedValues, function(value) {
+ var option = options.selectValueMap[value];
+ if (!option.disabled) selections.push(options.getViewValueFromOption(option));
+ });
+
+ return selections;
+ };
+
+ // If we are using `track by` then we must watch these tracked values on the model
+ // since ngModel only watches for object identity change
+ if (ngOptions.trackBy) {
+
+ scope.$watchCollection(function() {
+ if (isArray(ngModelCtrl.$viewValue)) {
+ return ngModelCtrl.$viewValue.map(function(value) {
+ return ngOptions.getTrackByValue(value);
+ });
+ }
+ }, function() {
+ ngModelCtrl.$render();
+ });
+
+ }
+ }
+
+
+ if (providedEmptyOption) {
+
+ // we need to remove it before calling selectElement.empty() because otherwise IE will
+ // remove the label from the element. wtf?
+ emptyOption.remove();
+
+ // compile the element since there might be bindings in it
+ $compile(emptyOption)(scope);
+
+ // remove the class, which is added automatically because we recompile the element and it
+ // becomes the compilation root
+ emptyOption.removeClass('ng-scope');
+ } else {
+ emptyOption = jqLite(optionTemplate.cloneNode(false));
+ }
+
+ // We need to do this here to ensure that the options object is defined
+ // when we first hit it in writeNgOptionsValue
+ updateOptions();
+
+ // We will re-render the option elements if the option values or labels change
+ scope.$watchCollection(ngOptions.getWatchables, updateOptions);
+
+ // ------------------------------------------------------------------ //
+
+
+ function updateOptionElement(option, element) {
+ option.element = element;
+ element.disabled = option.disabled;
+ if (option.value !== element.value) element.value = option.selectValue;
+ if (option.label !== element.label) {
+ element.label = option.label;
+ element.textContent = option.label;
+ }
+ }
+
+ function addOrReuseElement(parent, current, type, templateElement) {
+ var element;
+ // Check whether we can reuse the next element
+ if (current && lowercase(current.nodeName) === type) {
+ // The next element is the right type so reuse it
+ element = current;
+ } else {
+ // The next element is not the right type so create a new one
+ element = templateElement.cloneNode(false);
+ if (!current) {
+ // There are no more elements so just append it to the select
+ parent.appendChild(element);
+ } else {
+ // The next element is not a group so insert the new one
+ parent.insertBefore(element, current);
+ }
+ }
+ return element;
+ }
+
+
+ function removeExcessElements(current) {
+ var next;
+ while (current) {
+ next = current.nextSibling;
+ jqLiteRemove(current);
+ current = next;
+ }
+ }
+
+
+ function skipEmptyAndUnknownOptions(current) {
+ var emptyOption_ = emptyOption && emptyOption[0];
+ var unknownOption_ = unknownOption && unknownOption[0];
+
+ if (emptyOption_ || unknownOption_) {
+ while (current &&
+ (current === emptyOption_ ||
+ current === unknownOption_)) {
+ current = current.nextSibling;
+ }
+ }
+ return current;
+ }
+
+
+ function updateOptions() {
+
+ var previousValue = options && selectCtrl.readValue();
+
+ options = ngOptions.getOptions();
+
+ var groupMap = {};
+ var currentElement = selectElement[0].firstChild;
+
+ // Ensure that the empty option is always there if it was explicitly provided
+ if (providedEmptyOption) {
+ selectElement.prepend(emptyOption);
+ }
+
+ currentElement = skipEmptyAndUnknownOptions(currentElement);
+
+ options.items.forEach(function updateOption(option) {
+ var group;
+ var groupElement;
+ var optionElement;
+
+ if (option.group) {
+
+ // This option is to live in a group
+ // See if we have already created this group
+ group = groupMap[option.group];
+
+ if (!group) {
+
+ // We have not already created this group
+ groupElement = addOrReuseElement(selectElement[0],
+ currentElement,
+ 'optgroup',
+ optGroupTemplate);
+ // Move to the next element
+ currentElement = groupElement.nextSibling;
+
+ // Update the label on the group element
+ groupElement.label = option.group;
+
+ // Store it for use later
+ group = groupMap[option.group] = {
+ groupElement: groupElement,
+ currentOptionElement: groupElement.firstChild
+ };
+
+ }
+
+ // So now we have a group for this option we add the option to the group
+ optionElement = addOrReuseElement(group.groupElement,
+ group.currentOptionElement,
+ 'option',
+ optionTemplate);
+ updateOptionElement(option, optionElement);
+ // Move to the next element
+ group.currentOptionElement = optionElement.nextSibling;
+
+ } else {
+
+ // This option is not in a group
+ optionElement = addOrReuseElement(selectElement[0],
+ currentElement,
+ 'option',
+ optionTemplate);
+ updateOptionElement(option, optionElement);
+ // Move to the next element
+ currentElement = optionElement.nextSibling;
+ }
+ });
+
+
+ // Now remove all excess options and group
+ Object.keys(groupMap).forEach(function(key) {
+ removeExcessElements(groupMap[key].currentOptionElement);
+ });
+ removeExcessElements(currentElement);
+
+ ngModelCtrl.$render();
+
+ // Check to see if the value has changed due to the update to the options
+ if (!ngModelCtrl.$isEmpty(previousValue)) {
+ var nextValue = selectCtrl.readValue();
+ if (ngOptions.trackBy ? !equals(previousValue, nextValue) : previousValue !== nextValue) {
+ ngModelCtrl.$setViewValue(nextValue);
+ ngModelCtrl.$render();
+ }
+ }
+
+ }
+
+ }
+ };
+}];
+
/**
* @ngdoc directive
* @name ngPluralize
@@ -20216,6 +26501,9 @@ var ngNonBindableDirective = ngDirective({ terminal: true, priority: 1000 });
* <span ng-non-bindable>`{{personCount}}`</span>. The closed braces `{}` is a placeholder
* for <span ng-non-bindable>{{numberExpression}}</span>.
*
+ * If no rule is defined for a category, then an empty string is displayed and a warning is generated.
+ * Note that some locales define more categories than `one` and `other`. For example, fr-fr defines `few` and `many`.
+ *
* # Configuring ngPluralize with offset
* The `offset` attribute allows further customization of pluralized text, which can result in
* a better user experience. For example, instead of the message "4 people are viewing this document",
@@ -20262,9 +26550,9 @@ var ngNonBindableDirective = ngDirective({ terminal: true, priority: 1000 });
}]);
</script>
<div ng-controller="ExampleController">
- Person 1:<input type="text" ng-model="person1" value="Igor" /><br/>
- Person 2:<input type="text" ng-model="person2" value="Misko" /><br/>
- Number of People:<input type="text" ng-model="personCount" value="1" /><br/>
+ <label>Person 1:<input type="text" ng-model="person1" value="Igor" /></label><br/>
+ <label>Person 2:<input type="text" ng-model="person2" value="Misko" /></label><br/>
+ <label>Number of People:<input type="text" ng-model="personCount" value="1" /></label><br/>
<!--- Example with simple pluralization rules for en locale --->
Without Offset:
@@ -20334,10 +26622,11 @@ var ngNonBindableDirective = ngDirective({ terminal: true, priority: 1000 });
</file>
</example>
*/
-var ngPluralizeDirective = ['$locale', '$interpolate', function($locale, $interpolate) {
- var BRACE = /{}/g;
+var ngPluralizeDirective = ['$locale', '$interpolate', '$log', function($locale, $interpolate, $log) {
+ var BRACE = /{}/g,
+ IS_WHEN = /^when(Minus)?(.+)$/;
+
return {
- restrict: 'EA',
link: function(scope, element, attr) {
var numberExp = attr.count,
whenExp = attr.$attr.when && element.attr(attr.$attr.when), // we have {{}} in attrs
@@ -20346,34 +26635,53 @@ var ngPluralizeDirective = ['$locale', '$interpolate', function($locale, $interp
whensExpFns = {},
startSymbol = $interpolate.startSymbol(),
endSymbol = $interpolate.endSymbol(),
- isWhen = /^when(Minus)?(.+)$/;
+ braceReplacement = startSymbol + numberExp + '-' + offset + endSymbol,
+ watchRemover = angular.noop,
+ lastCount;
forEach(attr, function(expression, attributeName) {
- if (isWhen.test(attributeName)) {
- whens[lowercase(attributeName.replace('when', '').replace('Minus', '-'))] =
- element.attr(attr.$attr[attributeName]);
+ var tmpMatch = IS_WHEN.exec(attributeName);
+ if (tmpMatch) {
+ var whenKey = (tmpMatch[1] ? '-' : '') + lowercase(tmpMatch[2]);
+ whens[whenKey] = element.attr(attr.$attr[attributeName]);
}
});
forEach(whens, function(expression, key) {
- whensExpFns[key] =
- $interpolate(expression.replace(BRACE, startSymbol + numberExp + '-' +
- offset + endSymbol));
+ whensExpFns[key] = $interpolate(expression.replace(BRACE, braceReplacement));
+
});
- scope.$watch(function ngPluralizeWatch() {
- var value = parseFloat(scope.$eval(numberExp));
+ scope.$watch(numberExp, function ngPluralizeWatchAction(newVal) {
+ var count = parseFloat(newVal);
+ var countIsNaN = isNaN(count);
- if (!isNaN(value)) {
- //if explicit number rule such as 1, 2, 3... is defined, just use it. Otherwise,
- //check it against pluralization rules in $locale service
- if (!(value in whens)) value = $locale.pluralCat(value - offset);
- return whensExpFns[value](scope, element, true);
- } else {
- return '';
+ if (!countIsNaN && !(count in whens)) {
+ // If an explicit number rule such as 1, 2, 3... is defined, just use it.
+ // Otherwise, check it against pluralization rules in $locale service.
+ count = $locale.pluralCat(count - offset);
+ }
+
+ // If both `count` and `lastCount` are NaN, we don't need to re-register a watch.
+ // In JS `NaN !== NaN`, so we have to exlicitly check.
+ if ((count !== lastCount) && !(countIsNaN && isNumber(lastCount) && isNaN(lastCount))) {
+ watchRemover();
+ var whenExpFn = whensExpFns[count];
+ if (isUndefined(whenExpFn)) {
+ if (newVal != null) {
+ $log.debug("ngPluralize: no rule defined for '" + count + "' in " + whenExp);
+ }
+ watchRemover = noop;
+ updateElementText();
+ } else {
+ watchRemover = scope.$watch(whenExpFn, updateElementText);
+ }
+ lastCount = count;
}
- }, function ngPluralizeWatchAction(newVal) {
- element.text(newVal);
});
+
+ function updateElementText(newText) {
+ element.text(newText || '');
+ }
}
};
}];
@@ -20381,6 +26689,7 @@ var ngPluralizeDirective = ['$locale', '$interpolate', function($locale, $interp
/**
* @ngdoc directive
* @name ngRepeat
+ * @multiElement
*
* @description
* The `ngRepeat` directive instantiates a template once per item from a collection. Each template
@@ -20401,6 +26710,89 @@ var ngPluralizeDirective = ['$locale', '$interpolate', function($locale, $interp
* Creating aliases for these properties is possible with {@link ng.directive:ngInit `ngInit`}.
* This may be useful when, for instance, nesting ngRepeats.
*
+ *
+ * # Iterating over object properties
+ *
+ * It is possible to get `ngRepeat` to iterate over the properties of an object using the following
+ * syntax:
+ *
+ * ```js
+ * <div ng-repeat="(key, value) in myObj"> ... </div>
+ * ```
+ *
+ * You need to be aware that the JavaScript specification does not define the order of keys
+ * returned for an object. (To mitigate this in Angular 1.3 the `ngRepeat` directive
+ * used to sort the keys alphabetically.)
+ *
+ * Version 1.4 removed the alphabetic sorting. We now rely on the order returned by the browser
+ * when running `for key in myObj`. It seems that browsers generally follow the strategy of providing
+ * keys in the order in which they were defined, although there are exceptions when keys are deleted
+ * and reinstated. See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/delete#Cross-browser_issues
+ *
+ * If this is not desired, the recommended workaround is to convert your object into an array
+ * that is sorted into the order that you prefer before providing it to `ngRepeat`. You could
+ * do this with a filter such as [toArrayFilter](http://ngmodules.org/modules/angular-toArrayFilter)
+ * or implement a `$watch` on the object yourself.
+ *
+ *
+ * # Tracking and Duplicates
+ *
+ * When the contents of the collection change, `ngRepeat` makes the corresponding changes to the DOM:
+ *
+ * * When an item is added, a new instance of the template is added to the DOM.
+ * * When an item is removed, its template instance is removed from the DOM.
+ * * When items are reordered, their respective templates are reordered in the DOM.
+ *
+ * By default, `ngRepeat` does not allow duplicate items in arrays. This is because when
+ * there are duplicates, it is not possible to maintain a one-to-one mapping between collection
+ * items and DOM elements.
+ *
+ * If you do need to repeat duplicate items, you can substitute the default tracking behavior
+ * with your own using the `track by` expression.
+ *
+ * For example, you may track items by the index of each item in the collection, using the
+ * special scope property `$index`:
+ * ```html
+ * <div ng-repeat="n in [42, 42, 43, 43] track by $index">
+ * {{n}}
+ * </div>
+ * ```
+ *
+ * You may use arbitrary expressions in `track by`, including references to custom functions
+ * on the scope:
+ * ```html
+ * <div ng-repeat="n in [42, 42, 43, 43] track by myTrackingFunction(n)">
+ * {{n}}
+ * </div>
+ * ```
+ *
+ * If you are working with objects that have an identifier property, you can track
+ * by the identifier instead of the whole object. Should you reload your data later, `ngRepeat`
+ * will not have to rebuild the DOM elements for items it has already rendered, even if the
+ * JavaScript objects in the collection have been substituted for new ones:
+ * ```html
+ * <div ng-repeat="model in collection track by model.id">
+ * {{model.name}}
+ * </div>
+ * ```
+ *
+ * When no `track by` expression is provided, it is equivalent to tracking by the built-in
+ * `$id` function, which tracks items by their identity:
+ * ```html
+ * <div ng-repeat="obj in collection track by $id(obj)">
+ * {{obj.prop}}
+ * </div>
+ * ```
+ *
+ * <div class="alert alert-warning">
+ * **Note:** `track by` must always be the last expression:
+ * </div>
+ * ```
+ * <div ng-repeat="model in collection | orderBy: 'id' as filtered_result track by model.id">
+ * {{model.name}}
+ * </div>
+ * ```
+ *
* # Special repeat start and end points
* To repeat a series of elements instead of just one parent element, ngRepeat (as well as other ng directives) supports extending
* the range of the repeater by defining explicit start and end points by using **ng-repeat-start** and **ng-repeat-end** respectively.
@@ -20468,12 +26860,13 @@ var ngPluralizeDirective = ['$locale', '$interpolate', function($locale, $interp
*
* For example: `(name, age) in {'adam':10, 'amalie':12}`.
*
- * * `variable in expression track by tracking_expression` – You can also provide an optional tracking function
- * which can be used to associate the objects in the collection with the DOM elements. If no tracking function
- * is specified the ng-repeat associates elements by identity in the collection. It is an error to have
- * more than one tracking function to resolve to the same key. (This would mean that two distinct objects are
- * mapped to the same DOM element, which is not possible.) Filters should be applied to the expression,
- * before specifying a tracking expression.
+ * * `variable in expression track by tracking_expression` – You can also provide an optional tracking expression
+ * which can be used to associate the objects in the collection with the DOM elements. If no tracking expression
+ * is specified, ng-repeat associates elements by identity. It is an error to have
+ * more than one tracking expression value resolve to the same key. (This would mean that two distinct objects are
+ * mapped to the same DOM element, which is not possible.)
+ *
+ * Note that the tracking expression must come last, after any filters, and the alias expression.
*
* For example: `item in items` is equivalent to `item in items track by $id(item)`. This implies that the DOM elements
* will be associated by item identity in the array.
@@ -20490,6 +26883,18 @@ var ngPluralizeDirective = ['$locale', '$interpolate', function($locale, $interp
* For example: `item in items | filter:searchText track by item.id` is a pattern that might be used to apply a filter
* to items in conjunction with a tracking expression.
*
+ * * `variable in expression as alias_expression` – You can also provide an optional alias expression which will then store the
+ * intermediate results of the repeater after the filters have been applied. Typically this is used to render a special message
+ * when a filter is active on the repeater, but the filtered result set is empty.
+ *
+ * For example: `item in items | filter:x as results` will store the fragment of the repeated items as `results`, but only after
+ * the items have been processed through the filter.
+ *
+ * Please note that `as [variable name] is not an operator but rather a part of ngRepeat micro-syntax so it can be used only at the end
+ * (and not as operator, inside an expression).
+ *
+ * For example: `item in items | filter : x | orderBy : order | limitTo : limit as results` .
+ *
* @example
* This example initializes the scope to a list of names and
* then uses `ngRepeat` to display every person:
@@ -20508,11 +26913,14 @@ var ngPluralizeDirective = ['$locale', '$interpolate', function($locale, $interp
{name:'Samantha', age:60, gender:'girl'}
]">
I have {{friends.length}} friends. They are:
- <input type="search" ng-model="q" placeholder="filter friends..." />
+ <input type="search" ng-model="q" placeholder="filter friends..." aria-label="filter friends" />
<ul class="example-animate-container">
- <li class="animate-repeat" ng-repeat="friend in friends | filter:q">
+ <li class="animate-repeat" ng-repeat="friend in friends | filter:q as results">
[{{$index + 1}}] {{friend.name}} who is {{friend.age}} years old.
</li>
+ <li class="animate-repeat" ng-if="results.length == 0">
+ <strong>No results found...</strong>
+ </li>
</ul>
</div>
</file>
@@ -20579,29 +26987,84 @@ var ngPluralizeDirective = ['$locale', '$interpolate', function($locale, $interp
var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
var NG_REMOVED = '$$NG_REMOVED';
var ngRepeatMinErr = minErr('ngRepeat');
+
+ var updateScope = function(scope, index, valueIdentifier, value, keyIdentifier, key, arrayLength) {
+ // TODO(perf): generate setters to shave off ~40ms or 1-1.5%
+ scope[valueIdentifier] = value;
+ if (keyIdentifier) scope[keyIdentifier] = key;
+ scope.$index = index;
+ scope.$first = (index === 0);
+ scope.$last = (index === (arrayLength - 1));
+ scope.$middle = !(scope.$first || scope.$last);
+ // jshint bitwise: false
+ scope.$odd = !(scope.$even = (index&1) === 0);
+ // jshint bitwise: true
+ };
+
+ var getBlockStart = function(block) {
+ return block.clone[0];
+ };
+
+ var getBlockEnd = function(block) {
+ return block.clone[block.clone.length - 1];
+ };
+
+
return {
+ restrict: 'A',
+ multiElement: true,
transclude: 'element',
priority: 1000,
terminal: true,
$$tlb: true,
- link: function($scope, $element, $attr, ctrl, $transclude){
- var expression = $attr.ngRepeat;
- var match = expression.match(/^\s*([\s\S]+?)\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?\s*$/),
- trackByExp, trackByExpGetter, trackByIdExpFn, trackByIdArrayFn, trackByIdObjFn,
- lhs, rhs, valueIdentifier, keyIdentifier,
- hashFnLocals = {$id: hashKey};
+ compile: function ngRepeatCompile($element, $attr) {
+ var expression = $attr.ngRepeat;
+ var ngRepeatEndComment = document.createComment(' end ngRepeat: ' + expression + ' ');
- if (!match) {
- throw ngRepeatMinErr('iexp', "Expected expression in form of '_item_ in _collection_[ track by _id_]' but got '{0}'.",
+ var match = expression.match(/^\s*([\s\S]+?)\s+in\s+([\s\S]+?)(?:\s+as\s+([\s\S]+?))?(?:\s+track\s+by\s+([\s\S]+?))?\s*$/);
+
+ if (!match) {
+ throw ngRepeatMinErr('iexp', "Expected expression in form of '_item_ in _collection_[ track by _id_]' but got '{0}'.",
expression);
- }
+ }
+
+ var lhs = match[1];
+ var rhs = match[2];
+ var aliasAs = match[3];
+ var trackByExp = match[4];
+
+ match = lhs.match(/^(?:(\s*[\$\w]+)|\(\s*([\$\w]+)\s*,\s*([\$\w]+)\s*\))$/);
+
+ if (!match) {
+ throw ngRepeatMinErr('iidexp', "'_item_' in '_item_ in _collection_' should be an identifier or '(_key_, _value_)' expression, but got '{0}'.",
+ lhs);
+ }
+ var valueIdentifier = match[3] || match[1];
+ var keyIdentifier = match[2];
+
+ if (aliasAs && (!/^[$a-zA-Z_][$a-zA-Z0-9_]*$/.test(aliasAs) ||
+ /^(null|undefined|this|\$index|\$first|\$middle|\$last|\$even|\$odd|\$parent|\$root|\$id)$/.test(aliasAs))) {
+ throw ngRepeatMinErr('badident', "alias '{0}' is invalid --- must be a valid JS identifier which is not a reserved name.",
+ aliasAs);
+ }
- lhs = match[1];
- rhs = match[2];
- trackByExp = match[3];
+ var trackByExpGetter, trackByIdExpFn, trackByIdArrayFn, trackByIdObjFn;
+ var hashFnLocals = {$id: hashKey};
- if (trackByExp) {
- trackByExpGetter = $parse(trackByExp);
+ if (trackByExp) {
+ trackByExpGetter = $parse(trackByExp);
+ } else {
+ trackByIdArrayFn = function(key, value) {
+ return hashKey(value);
+ };
+ trackByIdObjFn = function(key) {
+ return key;
+ };
+ }
+
+ return function ngRepeatLink($scope, $element, $attr, ctrl, $transclude) {
+
+ if (trackByExpGetter) {
trackByIdExpFn = function(key, value, index) {
// assign key, value, and $index to the locals so that they can be used in hash functions
if (keyIdentifier) hashFnLocals[keyIdentifier] = key;
@@ -20609,174 +27072,154 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
hashFnLocals.$index = index;
return trackByExpGetter($scope, hashFnLocals);
};
- } else {
- trackByIdArrayFn = function(key, value) {
- return hashKey(value);
- };
- trackByIdObjFn = function(key) {
- return key;
- };
- }
-
- match = lhs.match(/^(?:([\$\w]+)|\(([\$\w]+)\s*,\s*([\$\w]+)\))$/);
- if (!match) {
- throw ngRepeatMinErr('iidexp', "'_item_' in '_item_ in _collection_' should be an identifier or '(_key_, _value_)' expression, but got '{0}'.",
- lhs);
}
- valueIdentifier = match[3] || match[1];
- keyIdentifier = match[2];
// Store a list of elements from previous run. This is a hash where key is the item from the
// iterator, and the value is objects with following properties.
// - scope: bound scope
// - element: previous element.
// - index: position
- var lastBlockMap = {};
+ //
+ // We are using no-proto object so that we don't need to guard against inherited props via
+ // hasOwnProperty.
+ var lastBlockMap = createMap();
//watch props
- $scope.$watchCollection(rhs, function ngRepeatAction(collection){
+ $scope.$watchCollection(rhs, function ngRepeatAction(collection) {
var index, length,
- previousNode = $element[0], // current position of the node
+ previousNode = $element[0], // node that cloned nodes should be inserted after
+ // initialized to the comment node anchor
nextNode,
// Same as lastBlockMap but it has the current state. It will become the
// lastBlockMap on the next iteration.
- nextBlockMap = {},
- arrayLength,
- childScope,
+ nextBlockMap = createMap(),
+ collectionLength,
key, value, // key/value of iteration
trackById,
trackByIdFn,
collectionKeys,
block, // last object information {scope, element, id}
- nextBlockOrder = [],
+ nextBlockOrder,
elementsToRemove;
+ if (aliasAs) {
+ $scope[aliasAs] = collection;
+ }
if (isArrayLike(collection)) {
collectionKeys = collection;
trackByIdFn = trackByIdExpFn || trackByIdArrayFn;
} else {
trackByIdFn = trackByIdExpFn || trackByIdObjFn;
- // if object, extract keys, sort them and use to determine order of iteration over obj props
+ // if object, extract keys, in enumeration order, unsorted
collectionKeys = [];
- for (key in collection) {
- if (collection.hasOwnProperty(key) && key.charAt(0) != '$') {
- collectionKeys.push(key);
+ for (var itemKey in collection) {
+ if (collection.hasOwnProperty(itemKey) && itemKey.charAt(0) !== '$') {
+ collectionKeys.push(itemKey);
}
}
- collectionKeys.sort();
}
- arrayLength = collectionKeys.length;
+ collectionLength = collectionKeys.length;
+ nextBlockOrder = new Array(collectionLength);
// locate existing items
- length = nextBlockOrder.length = collectionKeys.length;
- for(index = 0; index < length; index++) {
- key = (collection === collectionKeys) ? index : collectionKeys[index];
- value = collection[key];
- trackById = trackByIdFn(key, value, index);
- assertNotHasOwnProperty(trackById, '`track by` id');
- if(lastBlockMap.hasOwnProperty(trackById)) {
- block = lastBlockMap[trackById];
- delete lastBlockMap[trackById];
- nextBlockMap[trackById] = block;
- nextBlockOrder[index] = block;
- } else if (nextBlockMap.hasOwnProperty(trackById)) {
- // restore lastBlockMap
- forEach(nextBlockOrder, function(block) {
- if (block && block.scope) lastBlockMap[block.id] = block;
- });
- // This is a duplicate and we need to throw an error
- throw ngRepeatMinErr('dupes',
+ for (index = 0; index < collectionLength; index++) {
+ key = (collection === collectionKeys) ? index : collectionKeys[index];
+ value = collection[key];
+ trackById = trackByIdFn(key, value, index);
+ if (lastBlockMap[trackById]) {
+ // found previously seen block
+ block = lastBlockMap[trackById];
+ delete lastBlockMap[trackById];
+ nextBlockMap[trackById] = block;
+ nextBlockOrder[index] = block;
+ } else if (nextBlockMap[trackById]) {
+ // if collision detected. restore lastBlockMap and throw an error
+ forEach(nextBlockOrder, function(block) {
+ if (block && block.scope) lastBlockMap[block.id] = block;
+ });
+ throw ngRepeatMinErr('dupes',
"Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: {0}, Duplicate key: {1}, Duplicate value: {2}",
- expression, trackById, toJson(value));
- } else {
- // new never before seen block
- nextBlockOrder[index] = { id: trackById };
- nextBlockMap[trackById] = false;
- }
- }
+ expression, trackById, value);
+ } else {
+ // new never before seen block
+ nextBlockOrder[index] = {id: trackById, scope: undefined, clone: undefined};
+ nextBlockMap[trackById] = true;
+ }
+ }
- // remove existing items
- for (key in lastBlockMap) {
- // lastBlockMap is our own object so we don't need to use special hasOwnPropertyFn
- if (lastBlockMap.hasOwnProperty(key)) {
- block = lastBlockMap[key];
- elementsToRemove = getBlockElements(block.clone);
- $animate.leave(elementsToRemove);
- forEach(elementsToRemove, function(element) { element[NG_REMOVED] = true; });
- block.scope.$destroy();
+ // remove leftover items
+ for (var blockKey in lastBlockMap) {
+ block = lastBlockMap[blockKey];
+ elementsToRemove = getBlockNodes(block.clone);
+ $animate.leave(elementsToRemove);
+ if (elementsToRemove[0].parentNode) {
+ // if the element was not removed yet because of pending animation, mark it as deleted
+ // so that we can ignore it later
+ for (index = 0, length = elementsToRemove.length; index < length; index++) {
+ elementsToRemove[index][NG_REMOVED] = true;
+ }
}
+ block.scope.$destroy();
}
// we are not using forEach for perf reasons (trying to avoid #call)
- for (index = 0, length = collectionKeys.length; index < length; index++) {
+ for (index = 0; index < collectionLength; index++) {
key = (collection === collectionKeys) ? index : collectionKeys[index];
value = collection[key];
block = nextBlockOrder[index];
- if (nextBlockOrder[index - 1]) previousNode = getBlockEnd(nextBlockOrder[index - 1]);
if (block.scope) {
// if we have already seen this object, then we need to reuse the
// associated scope/element
- childScope = block.scope;
nextNode = previousNode;
+
+ // skip nodes that are already pending removal via leave animation
do {
nextNode = nextNode.nextSibling;
- } while(nextNode && nextNode[NG_REMOVED]);
+ } while (nextNode && nextNode[NG_REMOVED]);
if (getBlockStart(block) != nextNode) {
// existing item which got moved
- $animate.move(getBlockElements(block.clone), null, jqLite(previousNode));
+ $animate.move(getBlockNodes(block.clone), null, jqLite(previousNode));
}
previousNode = getBlockEnd(block);
+ updateScope(block.scope, index, valueIdentifier, value, keyIdentifier, key, collectionLength);
} else {
// new item which we don't know about
- childScope = $scope.$new();
- }
-
- childScope[valueIdentifier] = value;
- if (keyIdentifier) childScope[keyIdentifier] = key;
- childScope.$index = index;
- childScope.$first = (index === 0);
- childScope.$last = (index === (arrayLength - 1));
- childScope.$middle = !(childScope.$first || childScope.$last);
- // jshint bitwise: false
- childScope.$odd = !(childScope.$even = (index&1) === 0);
- // jshint bitwise: true
+ $transclude(function ngRepeatTransclude(clone, scope) {
+ block.scope = scope;
+ // http://jsperf.com/clone-vs-createcomment
+ var endNode = ngRepeatEndComment.cloneNode(false);
+ clone[clone.length++] = endNode;
- if (!block.scope) {
- $transclude(childScope, function(clone) {
- clone[clone.length++] = document.createComment(' end ngRepeat: ' + expression + ' ');
+ // TODO(perf): support naked previousNode in `enter` to avoid creation of jqLite wrapper?
$animate.enter(clone, null, jqLite(previousNode));
- previousNode = clone;
- block.scope = childScope;
+ previousNode = endNode;
// Note: We only need the first/last node of the cloned nodes.
// However, we need to keep the reference to the jqlite wrapper as it might be changed later
// by a directive with templateUrl when its template arrives.
block.clone = clone;
nextBlockMap[block.id] = block;
+ updateScope(block.scope, index, valueIdentifier, value, keyIdentifier, key, collectionLength);
});
}
}
lastBlockMap = nextBlockMap;
});
+ };
}
};
-
- function getBlockStart(block) {
- return block.clone[0];
- }
-
- function getBlockEnd(block) {
- return block.clone[block.clone.length - 1];
- }
}];
+var NG_HIDE_CLASS = 'ng-hide';
+var NG_HIDE_IN_PROGRESS_CLASS = 'ng-hide-animate';
/**
* @ngdoc directive
* @name ngShow
+ * @multiElement
*
* @description
* The `ngShow` directive shows or hides the given HTML element based on the expression
@@ -20793,15 +27236,10 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
* <div ng-show="myValue" class="ng-hide"></div>
* ```
*
- * When the `ngShow` expression evaluates to false then the `.ng-hide` CSS class is added to the class attribute
- * on the element causing it to become hidden. When true, the `.ng-hide` CSS class is removed
+ * When the `ngShow` expression evaluates to a falsy value then the `.ng-hide` CSS class is added to the class
+ * attribute on the element causing it to become hidden. When truthy, the `.ng-hide` CSS class is removed
* from the element causing the element not to appear hidden.
*
- * <div class="alert alert-warning">
- * **Note:** Here is a list of values that ngShow will consider as a falsy value (case insensitive):<br />
- * "f" / "0" / "false" / "no" / "n" / "[]"
- * </div>
- *
* ## Why is !important used?
*
* You may be wondering why !important is used for the `.ng-hide` CSS class. This is because the `.ng-hide` selector
@@ -20815,17 +27253,18 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
*
* ### Overriding `.ng-hide`
*
- * By default, the `.ng-hide` class will style the element with `display:none!important`. If you wish to change
+ * By default, the `.ng-hide` class will style the element with `display: none!important`. If you wish to change
* the hide behavior with ngShow/ngHide then this can be achieved by restating the styles for the `.ng-hide`
- * class in CSS:
+ * class CSS. Note that the selector that needs to be used is actually `.ng-hide:not(.ng-hide-animate)` to cope
+ * with extra animation classes that can be added.
*
* ```css
- * .ng-hide {
- * //this is just another form of hiding an element
- * display:block!important;
- * position:absolute;
- * top:-9999px;
- * left:-9999px;
+ * .ng-hide:not(.ng-hide-animate) {
+ * /&#42; this is just another form of hiding an element &#42;/
+ * display: block!important;
+ * position: absolute;
+ * top: -9999px;
+ * left: -9999px;
* }
* ```
*
@@ -20843,7 +27282,15 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
* //a working example can be found at the bottom of this page
* //
* .my-element.ng-hide-add, .my-element.ng-hide-remove {
- * transition:0.5s linear all;
+ * /&#42; this is required as of 1.3x to properly
+ * apply all styling in a show/hide animation &#42;/
+ * transition: 0s linear all;
+ * }
+ *
+ * .my-element.ng-hide-add-active,
+ * .my-element.ng-hide-remove-active {
+ * /&#42; the transition is defined in the active class &#42;/
+ * transition: 1s linear all;
* }
*
* .my-element.ng-hide-add { ... }
@@ -20852,7 +27299,7 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
* .my-element.ng-hide-remove.ng-hide-remove-active { ... }
* ```
*
- * Keep in mind that, as of AngularJS version 1.2.17 (and 1.3.0-beta.11), there is no need to change the display
+ * Keep in mind that, as of AngularJS version 1.3.0-beta.11, there is no need to change the display
* property to block during animation states--ngAnimate will handle the style toggling automatically for you.
*
* @animations
@@ -20866,7 +27313,7 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
* @example
<example module="ngAnimate" deps="angular-animate.js" animations="true">
<file name="index.html">
- Click me: <input type="checkbox" ng-model="checked"><br/>
+ Click me: <input type="checkbox" ng-model="checked" aria-label="Toggle ngHide"><br/>
<div>
Show:
<div class="check-element animate-show" ng-show="checked">
@@ -20881,29 +27328,33 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
</div>
</file>
<file name="glyphicons.css">
- @import url(//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap-glyphicons.css);
+ @import url(../../components/bootstrap-3.1.1/css/bootstrap.css);
</file>
<file name="animations.css">
.animate-show {
- -webkit-transition:all linear 0.5s;
- transition:all linear 0.5s;
- line-height:20px;
- opacity:1;
- padding:10px;
- border:1px solid black;
- background:white;
+ line-height: 20px;
+ opacity: 1;
+ padding: 10px;
+ border: 1px solid black;
+ background: white;
+ }
+
+ .animate-show.ng-hide-add.ng-hide-add-active,
+ .animate-show.ng-hide-remove.ng-hide-remove-active {
+ -webkit-transition: all linear 0.5s;
+ transition: all linear 0.5s;
}
.animate-show.ng-hide {
- line-height:0;
- opacity:0;
- padding:0 10px;
+ line-height: 0;
+ opacity: 0;
+ padding: 0 10px;
}
.check-element {
- padding:10px;
- border:1px solid black;
- background:white;
+ padding: 10px;
+ border: 1px solid black;
+ background: white;
}
</file>
<file name="protractor.js" type="protractor">
@@ -20923,10 +27374,20 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
</example>
*/
var ngShowDirective = ['$animate', function($animate) {
- return function(scope, element, attr) {
- scope.$watch(attr.ngShow, function ngShowWatchAction(value){
- $animate[toBoolean(value) ? 'removeClass' : 'addClass'](element, 'ng-hide');
- });
+ return {
+ restrict: 'A',
+ multiElement: true,
+ link: function(scope, element, attr) {
+ scope.$watch(attr.ngShow, function ngShowWatchAction(value) {
+ // we're adding a temporary, animation-specific class for ng-hide since this way
+ // we can control when the element is actually displayed on screen without having
+ // to have a global/greedy CSS selector that breaks when other animations are run.
+ // Read: https://github.com/angular/angular.js/issues/9103#issuecomment-58335845
+ $animate[value ? 'removeClass' : 'addClass'](element, NG_HIDE_CLASS, {
+ tempClasses: NG_HIDE_IN_PROGRESS_CLASS
+ });
+ });
+ }
};
}];
@@ -20934,6 +27395,7 @@ var ngShowDirective = ['$animate', function($animate) {
/**
* @ngdoc directive
* @name ngHide
+ * @multiElement
*
* @description
* The `ngHide` directive shows or hides the given HTML element based on the expression
@@ -20950,15 +27412,10 @@ var ngShowDirective = ['$animate', function($animate) {
* <div ng-hide="myValue"></div>
* ```
*
- * When the `.ngHide` expression evaluates to true then the `.ng-hide` CSS class is added to the class attribute
- * on the element causing it to become hidden. When false, the `.ng-hide` CSS class is removed
+ * When the `ngHide` expression evaluates to a truthy value then the `.ng-hide` CSS class is added to the class
+ * attribute on the element causing it to become hidden. When falsy, the `.ng-hide` CSS class is removed
* from the element causing the element not to appear hidden.
*
- * <div class="alert alert-warning">
- * **Note:** Here is a list of values that ngHide will consider as a falsy value (case insensitive):<br />
- * "f" / "0" / "false" / "no" / "n" / "[]"
- * </div>
- *
* ## Why is !important used?
*
* You may be wondering why !important is used for the `.ng-hide` CSS class. This is because the `.ng-hide` selector
@@ -20972,17 +27429,17 @@ var ngShowDirective = ['$animate', function($animate) {
*
* ### Overriding `.ng-hide`
*
- * By default, the `.ng-hide` class will style the element with `display:none!important`. If you wish to change
+ * By default, the `.ng-hide` class will style the element with `display: none!important`. If you wish to change
* the hide behavior with ngShow/ngHide then this can be achieved by restating the styles for the `.ng-hide`
* class in CSS:
*
* ```css
* .ng-hide {
- * //this is just another form of hiding an element
- * display:block!important;
- * position:absolute;
- * top:-9999px;
- * left:-9999px;
+ * /&#42; this is just another form of hiding an element &#42;/
+ * display: block!important;
+ * position: absolute;
+ * top: -9999px;
+ * left: -9999px;
* }
* ```
*
@@ -20999,7 +27456,7 @@ var ngShowDirective = ['$animate', function($animate) {
* //a working example can be found at the bottom of this page
* //
* .my-element.ng-hide-add, .my-element.ng-hide-remove {
- * transition:0.5s linear all;
+ * transition: 0.5s linear all;
* }
*
* .my-element.ng-hide-add { ... }
@@ -21008,7 +27465,7 @@ var ngShowDirective = ['$animate', function($animate) {
* .my-element.ng-hide-remove.ng-hide-remove-active { ... }
* ```
*
- * Keep in mind that, as of AngularJS version 1.2.17 (and 1.3.0-beta.11), there is no need to change the display
+ * Keep in mind that, as of AngularJS version 1.3.0-beta.11, there is no need to change the display
* property to block during animation states--ngAnimate will handle the style toggling automatically for you.
*
* @animations
@@ -21022,7 +27479,7 @@ var ngShowDirective = ['$animate', function($animate) {
* @example
<example module="ngAnimate" deps="angular-animate.js" animations="true">
<file name="index.html">
- Click me: <input type="checkbox" ng-model="checked"><br/>
+ Click me: <input type="checkbox" ng-model="checked" aria-label="Toggle ngShow"><br/>
<div>
Show:
<div class="check-element animate-hide" ng-show="checked">
@@ -21037,29 +27494,29 @@ var ngShowDirective = ['$animate', function($animate) {
</div>
</file>
<file name="glyphicons.css">
- @import url(//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap-glyphicons.css);
+ @import url(../../components/bootstrap-3.1.1/css/bootstrap.css);
</file>
<file name="animations.css">
.animate-hide {
- -webkit-transition:all linear 0.5s;
- transition:all linear 0.5s;
- line-height:20px;
- opacity:1;
- padding:10px;
- border:1px solid black;
- background:white;
+ -webkit-transition: all linear 0.5s;
+ transition: all linear 0.5s;
+ line-height: 20px;
+ opacity: 1;
+ padding: 10px;
+ border: 1px solid black;
+ background: white;
}
.animate-hide.ng-hide {
- line-height:0;
- opacity:0;
- padding:0 10px;
+ line-height: 0;
+ opacity: 0;
+ padding: 0 10px;
}
.check-element {
- padding:10px;
- border:1px solid black;
- background:white;
+ padding: 10px;
+ border: 1px solid black;
+ background: white;
}
</file>
<file name="protractor.js" type="protractor">
@@ -21079,10 +27536,18 @@ var ngShowDirective = ['$animate', function($animate) {
</example>
*/
var ngHideDirective = ['$animate', function($animate) {
- return function(scope, element, attr) {
- scope.$watch(attr.ngHide, function ngHideWatchAction(value){
- $animate[toBoolean(value) ? 'addClass' : 'removeClass'](element, 'ng-hide');
- });
+ return {
+ restrict: 'A',
+ multiElement: true,
+ link: function(scope, element, attr) {
+ scope.$watch(attr.ngHide, function ngHideWatchAction(value) {
+ // The comment inside of the ngShowDirective explains why we add and
+ // remove a temporary class for the show/hide animation
+ $animate[value ? 'addClass' : 'removeClass'](element,NG_HIDE_CLASS, {
+ tempClasses: NG_HIDE_IN_PROGRESS_CLASS
+ });
+ });
+ }
};
}];
@@ -21183,8 +27648,8 @@ var ngStyleDirective = ngDirective(function(scope, element, attr) {
*
*
* @scope
- * @priority 800
- * @param {*} ngSwitch|on expression to match against <tt>ng-switch-when</tt>.
+ * @priority 1200
+ * @param {*} ngSwitch|on expression to match against <code>ng-switch-when</code>.
* On child elements add:
*
* * `ngSwitchWhen`: the case statement to match against. If match then this
@@ -21201,7 +27666,7 @@ var ngStyleDirective = ngDirective(function(scope, element, attr) {
<div ng-controller="ExampleController">
<select ng-model="selection" ng-options="item for item in items">
</select>
- <tt>selection={{selection}}</tt>
+ <code>selection={{selection}}</code>
<hr/>
<div class="animate-switch-container"
ng-switch on="selection">
@@ -21271,7 +27736,6 @@ var ngStyleDirective = ngDirective(function(scope, element, attr) {
*/
var ngSwitchDirective = ['$animate', function($animate) {
return {
- restrict: 'EA',
require: 'ngSwitch',
// asks for $scope to fool the BC controller module
@@ -21282,37 +27746,39 @@ var ngSwitchDirective = ['$animate', function($animate) {
var watchExpr = attr.ngSwitch || attr.on,
selectedTranscludes = [],
selectedElements = [],
- previousElements = [],
+ previousLeaveAnimations = [],
selectedScopes = [];
+ var spliceFactory = function(array, index) {
+ return function() { array.splice(index, 1); };
+ };
+
scope.$watch(watchExpr, function ngSwitchWatchAction(value) {
var i, ii;
- for (i = 0, ii = previousElements.length; i < ii; ++i) {
- previousElements[i].remove();
+ for (i = 0, ii = previousLeaveAnimations.length; i < ii; ++i) {
+ $animate.cancel(previousLeaveAnimations[i]);
}
- previousElements.length = 0;
+ previousLeaveAnimations.length = 0;
for (i = 0, ii = selectedScopes.length; i < ii; ++i) {
- var selected = selectedElements[i];
+ var selected = getBlockNodes(selectedElements[i].clone);
selectedScopes[i].$destroy();
- previousElements[i] = selected;
- $animate.leave(selected, function() {
- previousElements.splice(i, 1);
- });
+ var promise = previousLeaveAnimations[i] = $animate.leave(selected);
+ promise.then(spliceFactory(previousLeaveAnimations, i));
}
selectedElements.length = 0;
selectedScopes.length = 0;
if ((selectedTranscludes = ngSwitchController.cases['!' + value] || ngSwitchController.cases['?'])) {
- scope.$eval(attr.change);
forEach(selectedTranscludes, function(selectedTransclude) {
- var selectedScope = scope.$new();
- selectedScopes.push(selectedScope);
- selectedTransclude.transclude(selectedScope, function(caseElement) {
+ selectedTransclude.transclude(function(caseElement, selectedScope) {
+ selectedScopes.push(selectedScope);
var anchor = selectedTransclude.element;
+ caseElement[caseElement.length++] = document.createComment(' end ngSwitchWhen: ');
+ var block = { clone: caseElement };
- selectedElements.push(caseElement);
+ selectedElements.push(block);
$animate.enter(caseElement, anchor.parent(), anchor);
});
});
@@ -21324,8 +27790,9 @@ var ngSwitchDirective = ['$animate', function($animate) {
var ngSwitchWhenDirective = ngDirective({
transclude: 'element',
- priority: 800,
+ priority: 1200,
require: '^ngSwitch',
+ multiElement: true,
link: function(scope, element, attrs, ctrl, $transclude) {
ctrl.cases['!' + attrs.ngSwitchWhen] = (ctrl.cases['!' + attrs.ngSwitchWhen] || []);
ctrl.cases['!' + attrs.ngSwitchWhen].push({ transclude: $transclude, element: element });
@@ -21334,8 +27801,9 @@ var ngSwitchWhenDirective = ngDirective({
var ngSwitchDefaultDirective = ngDirective({
transclude: 'element',
- priority: 800,
+ priority: 1200,
require: '^ngSwitch',
+ multiElement: true,
link: function(scope, element, attr, ctrl, $transclude) {
ctrl.cases['?'] = (ctrl.cases['?'] || []);
ctrl.cases['?'].push({ transclude: $transclude, element: element });
@@ -21345,7 +27813,7 @@ var ngSwitchDefaultDirective = ngDirective({
/**
* @ngdoc directive
* @name ngTransclude
- * @restrict AC
+ * @restrict EAC
*
* @description
* Directive that marks the insertion point for the transcluded DOM of the nearest parent directive that uses transclusion.
@@ -21366,7 +27834,7 @@ var ngSwitchDefaultDirective = ngDirective({
scope: { title:'@' },
template: '<div style="border: 1px solid black;">' +
'<div style="background-color: gray">{{title}}</div>' +
- '<div ng-transclude></div>' +
+ '<ng-transclude></ng-transclude>' +
'</div>'
};
})
@@ -21376,8 +27844,8 @@ var ngSwitchDefaultDirective = ngDirective({
}]);
</script>
<div ng-controller="ExampleController">
- <input ng-model="title"><br>
- <textarea ng-model="text"></textarea> <br/>
+ <input ng-model="title" aria-label="title"> <br/>
+ <textarea ng-model="text" aria-label="text"></textarea> <br/>
<pane title="{{title}}">{{text}}</pane>
</div>
</file>
@@ -21397,6 +27865,7 @@ var ngSwitchDefaultDirective = ngDirective({
*
*/
var ngTranscludeDirective = ngDirective({
+ restrict: 'EAC',
link: function($scope, $element, $attrs, controller, $transclude) {
if (!$transclude) {
throw minErr('ngTransclude')('orphan',
@@ -21461,7 +27930,106 @@ var scriptDirective = ['$templateCache', function($templateCache) {
};
}];
-var ngOptionsMinErr = minErr('ngOptions');
+var noopNgModelController = { $setViewValue: noop, $render: noop };
+
+/**
+ * @ngdoc type
+ * @name select.SelectController
+ * @description
+ * The controller for the `<select>` directive. This provides support for reading
+ * and writing the selected value(s) of the control and also coordinates dynamically
+ * added `<option>` elements, perhaps by an `ngRepeat` directive.
+ */
+var SelectController =
+ ['$element', '$scope', '$attrs', function($element, $scope, $attrs) {
+
+ var self = this,
+ optionsMap = new HashMap();
+
+ // If the ngModel doesn't get provided then provide a dummy noop version to prevent errors
+ self.ngModelCtrl = noopNgModelController;
+
+ // The "unknown" option is one that is prepended to the list if the viewValue
+ // does not match any of the options. When it is rendered the value of the unknown
+ // option is '? XXX ?' where XXX is the hashKey of the value that is not known.
+ //
+ // We can't just jqLite('<option>') since jqLite is not smart enough
+ // to create it in <select> and IE barfs otherwise.
+ self.unknownOption = jqLite(document.createElement('option'));
+ self.renderUnknownOption = function(val) {
+ var unknownVal = '? ' + hashKey(val) + ' ?';
+ self.unknownOption.val(unknownVal);
+ $element.prepend(self.unknownOption);
+ $element.val(unknownVal);
+ };
+
+ $scope.$on('$destroy', function() {
+ // disable unknown option so that we don't do work when the whole select is being destroyed
+ self.renderUnknownOption = noop;
+ });
+
+ self.removeUnknownOption = function() {
+ if (self.unknownOption.parent()) self.unknownOption.remove();
+ };
+
+
+ // Read the value of the select control, the implementation of this changes depending
+ // upon whether the select can have multiple values and whether ngOptions is at work.
+ self.readValue = function readSingleValue() {
+ self.removeUnknownOption();
+ return $element.val();
+ };
+
+
+ // Write the value to the select control, the implementation of this changes depending
+ // upon whether the select can have multiple values and whether ngOptions is at work.
+ self.writeValue = function writeSingleValue(value) {
+ if (self.hasOption(value)) {
+ self.removeUnknownOption();
+ $element.val(value);
+ if (value === '') self.emptyOption.prop('selected', true); // to make IE9 happy
+ } else {
+ if (value == null && self.emptyOption) {
+ self.removeUnknownOption();
+ $element.val('');
+ } else {
+ self.renderUnknownOption(value);
+ }
+ }
+ };
+
+
+ // Tell the select control that an option, with the given value, has been added
+ self.addOption = function(value, element) {
+ assertNotHasOwnProperty(value, '"option value"');
+ if (value === '') {
+ self.emptyOption = element;
+ }
+ var count = optionsMap.get(value) || 0;
+ optionsMap.put(value, count + 1);
+ };
+
+ // Tell the select control that an option, with the given value, has been removed
+ self.removeOption = function(value) {
+ var count = optionsMap.get(value);
+ if (count) {
+ if (count === 1) {
+ optionsMap.remove(value);
+ if (value === '') {
+ self.emptyOption = undefined;
+ }
+ } else {
+ optionsMap.put(value, count - 1);
+ }
+ }
+ };
+
+ // Check whether the select control has an option matching the given value
+ self.hasOption = function(value) {
+ return !!optionsMap.get(value);
+ };
+}];
+
/**
* @ngdoc directive
* @name select
@@ -21470,625 +28038,170 @@ var ngOptionsMinErr = minErr('ngOptions');
* @description
* HTML `SELECT` element with angular data-binding.
*
- * # `ngOptions`
- *
- * The `ngOptions` attribute can be used to dynamically generate a list of `<option>`
- * elements for the `<select>` element using the array or object obtained by evaluating the
- * `ngOptions` comprehension_expression.
+ * In many cases, `ngRepeat` can be used on `<option>` elements instead of {@link ng.directive:ngOptions
+ * ngOptions} to achieve a similar result. However, `ngOptions` provides some benefits such as reducing
+ * memory and increasing speed by not creating a new scope for each repeated instance, as well as providing
+ * more flexibility in how the `<select>`'s model is assigned via the `select` **`as`** part of the
+ * comprehension expression.
*
* When an item in the `<select>` menu is selected, the array element or object property
* represented by the selected option will be bound to the model identified by the `ngModel`
* directive.
*
- * <div class="alert alert-warning">
- * **Note:** `ngModel` compares by reference, not value. This is important when binding to an
- * array of objects. See an example [in this jsfiddle](http://jsfiddle.net/qWzTb/).
- * </div>
+ * If the viewValue contains a value that doesn't match any of the options then the control
+ * will automatically add an "unknown" option, which it then removes when this is resolved.
*
* Optionally, a single hard-coded `<option>` element, with the value set to an empty string, can
* be nested into the `<select>` element. This element will then represent the `null` or "not selected"
* option. See example below for demonstration.
*
- * <div class="alert alert-warning">
- * **Note:** `ngOptions` provides an iterator facility for the `<option>` element which should be used instead
- * of {@link ng.directive:ngRepeat ngRepeat} when you want the
- * `select` model to be bound to a non-string value. This is because an option element can only
- * be bound to string values at present.
+ * <div class="alert alert-info">
+ * The value of a `select` directive used without `ngOptions` is always a string.
+ * When the model needs to be bound to a non-string value, you must either explictly convert it
+ * using a directive (see example below) or use `ngOptions` to specify the set of options.
+ * This is because an option element can only be bound to string values at present.
* </div>
*
- * @param {string} ngModel Assignable angular expression to data-bind to.
- * @param {string=} name Property name of the form under which the control is published.
- * @param {string=} required The control is considered valid only if value is entered.
- * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
- * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
- * `required` when you want to data-bind to the `required` attribute.
- * @param {comprehension_expression=} ngOptions in one of the following forms:
+ * ### Example (binding `select` to a non-string value)
*
- * * for array data sources:
- * * `label` **`for`** `value` **`in`** `array`
- * * `select` **`as`** `label` **`for`** `value` **`in`** `array`
- * * `label` **`group by`** `group` **`for`** `value` **`in`** `array`
- * * `select` **`as`** `label` **`group by`** `group` **`for`** `value` **`in`** `array` **`track by`** `trackexpr`
- * * for object data sources:
- * * `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
- * * `select` **`as`** `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
- * * `label` **`group by`** `group` **`for (`**`key`**`,`** `value`**`) in`** `object`
- * * `select` **`as`** `label` **`group by`** `group`
- * **`for` `(`**`key`**`,`** `value`**`) in`** `object`
- *
- * Where:
- *
- * * `array` / `object`: an expression which evaluates to an array / object to iterate over.
- * * `value`: local variable which will refer to each item in the `array` or each property value
- * of `object` during iteration.
- * * `key`: local variable which will refer to a property name in `object` during iteration.
- * * `label`: The result of this expression will be the label for `<option>` element. The
- * `expression` will most likely refer to the `value` variable (e.g. `value.propertyName`).
- * * `select`: The result of this expression will be bound to the model of the parent `<select>`
- * element. If not specified, `select` expression will default to `value`.
- * * `group`: The result of this expression will be used to group options using the `<optgroup>`
- * DOM element.
- * * `trackexpr`: Used when working with an array of objects. The result of this expression will be
- * used to identify the objects in the array. The `trackexpr` will most likely refer to the
- * `value` variable (e.g. `value.propertyName`).
+ * <example name="select-with-non-string-options" module="nonStringSelect">
+ * <file name="index.html">
+ * <select ng-model="model.id" convert-to-number>
+ * <option value="0">Zero</option>
+ * <option value="1">One</option>
+ * <option value="2">Two</option>
+ * </select>
+ * {{ model }}
+ * </file>
+ * <file name="app.js">
+ * angular.module('nonStringSelect', [])
+ * .run(function($rootScope) {
+ * $rootScope.model = { id: 2 };
+ * })
+ * .directive('convertToNumber', function() {
+ * return {
+ * require: 'ngModel',
+ * link: function(scope, element, attrs, ngModel) {
+ * ngModel.$parsers.push(function(val) {
+ * return parseInt(val, 10);
+ * });
+ * ngModel.$formatters.push(function(val) {
+ * return '' + val;
+ * });
+ * }
+ * };
+ * });
+ * </file>
+ * <file name="protractor.js" type="protractor">
+ * it('should initialize to model', function() {
+ * var select = element(by.css('select'));
+ * expect(element(by.model('model.id')).$('option:checked').getText()).toEqual('Two');
+ * });
+ * </file>
+ * </example>
*
- * @example
- <example module="selectExample">
- <file name="index.html">
- <script>
- angular.module('selectExample', [])
- .controller('ExampleController', ['$scope', function($scope) {
- $scope.colors = [
- {name:'black', shade:'dark'},
- {name:'white', shade:'light'},
- {name:'red', shade:'dark'},
- {name:'blue', shade:'dark'},
- {name:'yellow', shade:'light'}
- ];
- $scope.myColor = $scope.colors[2]; // red
- }]);
- </script>
- <div ng-controller="ExampleController">
- <ul>
- <li ng-repeat="color in colors">
- Name: <input ng-model="color.name">
- [<a href ng-click="colors.splice($index, 1)">X</a>]
- </li>
- <li>
- [<a href ng-click="colors.push({})">add</a>]
- </li>
- </ul>
- <hr/>
- Color (null not allowed):
- <select ng-model="myColor" ng-options="color.name for color in colors"></select><br>
-
- Color (null allowed):
- <span class="nullable">
- <select ng-model="myColor" ng-options="color.name for color in colors">
- <option value="">-- choose color --</option>
- </select>
- </span><br/>
-
- Color grouped by shade:
- <select ng-model="myColor" ng-options="color.name group by color.shade for color in colors">
- </select><br/>
-
-
- Select <a href ng-click="myColor = { name:'not in list', shade: 'other' }">bogus</a>.<br>
- <hr/>
- Currently selected: {{ {selected_color:myColor} }}
- <div style="border:solid 1px black; height:20px"
- ng-style="{'background-color':myColor.name}">
- </div>
- </div>
- </file>
- <file name="protractor.js" type="protractor">
- it('should check ng-options', function() {
- expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('red');
- element.all(by.model('myColor')).first().click();
- element.all(by.css('select[ng-model="myColor"] option')).first().click();
- expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('black');
- element(by.css('.nullable select[ng-model="myColor"]')).click();
- element.all(by.css('.nullable select[ng-model="myColor"] option')).first().click();
- expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('null');
- });
- </file>
- </example>
*/
-
-var ngOptionsDirective = valueFn({ terminal: true });
-// jshint maxlen: false
-var selectDirective = ['$compile', '$parse', function($compile, $parse) {
- //000011111111110000000000022222222220000000000000000000003333333333000000000000004444444444444440000000005555555555555550000000666666666666666000000000000000777777777700000000000000000008888888888
- var NG_OPTIONS_REGEXP = /^\s*([\s\S]+?)(?:\s+as\s+([\s\S]+?))?(?:\s+group\s+by\s+([\s\S]+?))?\s+for\s+(?:([\$\w][\$\w]*)|(?:\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)))\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?$/,
- nullModelCtrl = {$setViewValue: noop};
-// jshint maxlen: 100
+var selectDirective = function() {
return {
restrict: 'E',
require: ['select', '?ngModel'],
- controller: ['$element', '$scope', '$attrs', function($element, $scope, $attrs) {
- var self = this,
- optionsMap = {},
- ngModelCtrl = nullModelCtrl,
- nullOption,
- unknownOption;
-
-
- self.databound = $attrs.ngModel;
-
-
- self.init = function(ngModelCtrl_, nullOption_, unknownOption_) {
- ngModelCtrl = ngModelCtrl_;
- nullOption = nullOption_;
- unknownOption = unknownOption_;
- };
-
-
- self.addOption = function(value) {
- assertNotHasOwnProperty(value, '"option value"');
- optionsMap[value] = true;
-
- if (ngModelCtrl.$viewValue == value) {
- $element.val(value);
- if (unknownOption.parent()) unknownOption.remove();
- }
- };
-
-
- self.removeOption = function(value) {
- if (this.hasOption(value)) {
- delete optionsMap[value];
- if (ngModelCtrl.$viewValue == value) {
- this.renderUnknownOption(value);
- }
- }
- };
+ controller: SelectController,
+ link: function(scope, element, attr, ctrls) {
+ // if ngModel is not defined, we don't need to do anything
+ var ngModelCtrl = ctrls[1];
+ if (!ngModelCtrl) return;
- self.renderUnknownOption = function(val) {
- var unknownVal = '? ' + hashKey(val) + ' ?';
- unknownOption.val(unknownVal);
- $element.prepend(unknownOption);
- $element.val(unknownVal);
- unknownOption.prop('selected', true); // needed for IE
- };
+ var selectCtrl = ctrls[0];
+ selectCtrl.ngModelCtrl = ngModelCtrl;
- self.hasOption = function(value) {
- return optionsMap.hasOwnProperty(value);
+ // We delegate rendering to the `writeValue` method, which can be changed
+ // if the select can have multiple selected values or if the options are being
+ // generated by `ngOptions`
+ ngModelCtrl.$render = function() {
+ selectCtrl.writeValue(ngModelCtrl.$viewValue);
};
- $scope.$on('$destroy', function() {
- // disable unknown option so that we don't do work when the whole select is being destroyed
- self.renderUnknownOption = noop;
+ // When the selected item(s) changes we delegate getting the value of the select control
+ // to the `readValue` method, which can be changed if the select can have multiple
+ // selected values or if the options are being generated by `ngOptions`
+ element.on('change', function() {
+ scope.$apply(function() {
+ ngModelCtrl.$setViewValue(selectCtrl.readValue());
+ });
});
- }],
-
- link: function(scope, element, attr, ctrls) {
- // if ngModel is not defined, we don't need to do anything
- if (!ctrls[1]) return;
-
- var selectCtrl = ctrls[0],
- ngModelCtrl = ctrls[1],
- multiple = attr.multiple,
- optionsExp = attr.ngOptions,
- nullOption = false, // if false, user will not be able to select it (used by ngOptions)
- emptyOption,
- // we can't just jqLite('<option>') since jqLite is not smart enough
- // to create it in <select> and IE barfs otherwise.
- optionTemplate = jqLite(document.createElement('option')),
- optGroupTemplate =jqLite(document.createElement('optgroup')),
- unknownOption = optionTemplate.clone();
-
- // find "null" option
- for(var i = 0, children = element.children(), ii = children.length; i < ii; i++) {
- if (children[i].value === '') {
- emptyOption = nullOption = children.eq(i);
- break;
- }
- }
-
- selectCtrl.init(ngModelCtrl, nullOption, unknownOption);
-
- // required validator
- if (multiple) {
- ngModelCtrl.$isEmpty = function(value) {
- return !value || value.length === 0;
- };
- }
-
- if (optionsExp) setupAsOptions(scope, element, ngModelCtrl);
- else if (multiple) setupAsMultiple(scope, element, ngModelCtrl);
- else setupAsSingle(scope, element, ngModelCtrl, selectCtrl);
-
- ////////////////////////////
-
-
-
- function setupAsSingle(scope, selectElement, ngModelCtrl, selectCtrl) {
- ngModelCtrl.$render = function() {
- var viewValue = ngModelCtrl.$viewValue;
-
- if (selectCtrl.hasOption(viewValue)) {
- if (unknownOption.parent()) unknownOption.remove();
- selectElement.val(viewValue);
- if (viewValue === '') emptyOption.prop('selected', true); // to make IE9 happy
- } else {
- if (isUndefined(viewValue) && emptyOption) {
- selectElement.val('');
- } else {
- selectCtrl.renderUnknownOption(viewValue);
+ // If the select allows multiple values then we need to modify how we read and write
+ // values from and to the control; also what it means for the value to be empty and
+ // we have to add an extra watch since ngModel doesn't work well with arrays - it
+ // doesn't trigger rendering if only an item in the array changes.
+ if (attr.multiple) {
+
+ // Read value now needs to check each option to see if it is selected
+ selectCtrl.readValue = function readMultipleValue() {
+ var array = [];
+ forEach(element.find('option'), function(option) {
+ if (option.selected) {
+ array.push(option.value);
}
- }
- };
-
- selectElement.on('change', function() {
- scope.$apply(function() {
- if (unknownOption.parent()) unknownOption.remove();
- ngModelCtrl.$setViewValue(selectElement.val());
});
- });
- }
+ return array;
+ };
- function setupAsMultiple(scope, selectElement, ctrl) {
- var lastView;
- ctrl.$render = function() {
- var items = new HashMap(ctrl.$viewValue);
- forEach(selectElement.find('option'), function(option) {
+ // Write value now needs to set the selected property of each matching option
+ selectCtrl.writeValue = function writeMultipleValue(value) {
+ var items = new HashMap(value);
+ forEach(element.find('option'), function(option) {
option.selected = isDefined(items.get(option.value));
});
};
// we have to do it on each watch since ngModel watches reference, but
// we need to work of an array, so we need to see if anything was inserted/removed
+ var lastView, lastViewRef = NaN;
scope.$watch(function selectMultipleWatch() {
- if (!equals(lastView, ctrl.$viewValue)) {
- lastView = shallowCopy(ctrl.$viewValue);
- ctrl.$render();
+ if (lastViewRef === ngModelCtrl.$viewValue && !equals(lastView, ngModelCtrl.$viewValue)) {
+ lastView = shallowCopy(ngModelCtrl.$viewValue);
+ ngModelCtrl.$render();
}
+ lastViewRef = ngModelCtrl.$viewValue;
});
- selectElement.on('change', function() {
- scope.$apply(function() {
- var array = [];
- forEach(selectElement.find('option'), function(option) {
- if (option.selected) {
- array.push(option.value);
- }
- });
- ctrl.$setViewValue(array);
- });
- });
- }
-
- function setupAsOptions(scope, selectElement, ctrl) {
- var match;
-
- if (!(match = optionsExp.match(NG_OPTIONS_REGEXP))) {
- throw ngOptionsMinErr('iexp',
- "Expected expression in form of " +
- "'_select_ (as _label_)? for (_key_,)?_value_ in _collection_'" +
- " but got '{0}'. Element: {1}",
- optionsExp, startingTag(selectElement));
- }
-
- var displayFn = $parse(match[2] || match[1]),
- valueName = match[4] || match[6],
- keyName = match[5],
- groupByFn = $parse(match[3] || ''),
- valueFn = $parse(match[2] ? match[1] : valueName),
- valuesFn = $parse(match[7]),
- track = match[8],
- trackFn = track ? $parse(match[8]) : null,
- // This is an array of array of existing option groups in DOM.
- // We try to reuse these if possible
- // - optionGroupsCache[0] is the options with no option group
- // - optionGroupsCache[?][0] is the parent: either the SELECT or OPTGROUP element
- optionGroupsCache = [[{element: selectElement, label:''}]];
-
- if (nullOption) {
- // compile the element since there might be bindings in it
- $compile(nullOption)(scope);
-
- // remove the class, which is added automatically because we recompile the element and it
- // becomes the compilation root
- nullOption.removeClass('ng-scope');
-
- // we need to remove it before calling selectElement.empty() because otherwise IE will
- // remove the label from the element. wtf?
- nullOption.remove();
- }
-
- // clear contents, we'll add what's needed based on the model
- selectElement.empty();
-
- selectElement.on('change', function() {
- scope.$apply(function() {
- var optionGroup,
- collection = valuesFn(scope) || [],
- locals = {},
- key, value, optionElement, index, groupIndex, length, groupLength, trackIndex;
-
- if (multiple) {
- value = [];
- for (groupIndex = 0, groupLength = optionGroupsCache.length;
- groupIndex < groupLength;
- groupIndex++) {
- // list of options for that group. (first item has the parent)
- optionGroup = optionGroupsCache[groupIndex];
-
- for(index = 1, length = optionGroup.length; index < length; index++) {
- if ((optionElement = optionGroup[index].element)[0].selected) {
- key = optionElement.val();
- if (keyName) locals[keyName] = key;
- if (trackFn) {
- for (trackIndex = 0; trackIndex < collection.length; trackIndex++) {
- locals[valueName] = collection[trackIndex];
- if (trackFn(scope, locals) == key) break;
- }
- } else {
- locals[valueName] = collection[key];
- }
- value.push(valueFn(scope, locals));
- }
- }
- }
- } else {
- key = selectElement.val();
- if (key == '?') {
- value = undefined;
- } else if (key === ''){
- value = null;
- } else {
- if (trackFn) {
- for (trackIndex = 0; trackIndex < collection.length; trackIndex++) {
- locals[valueName] = collection[trackIndex];
- if (trackFn(scope, locals) == key) {
- value = valueFn(scope, locals);
- break;
- }
- }
- } else {
- locals[valueName] = collection[key];
- if (keyName) locals[keyName] = key;
- value = valueFn(scope, locals);
- }
- }
- }
- ctrl.$setViewValue(value);
- render();
- });
- });
-
- ctrl.$render = render;
-
- scope.$watchCollection(valuesFn, render);
- scope.$watchCollection(function () {
- var locals = {},
- values = valuesFn(scope);
- if (values) {
- var toDisplay = new Array(values.length);
- for (var i = 0, ii = values.length; i < ii; i++) {
- locals[valueName] = values[i];
- toDisplay[i] = displayFn(scope, locals);
- }
- return toDisplay;
- }
- }, render);
-
- if ( multiple ) {
- scope.$watchCollection(function() { return ctrl.$modelValue; }, render);
- }
-
- function getSelectedSet() {
- var selectedSet = false;
- if (multiple) {
- var modelValue = ctrl.$modelValue;
- if (trackFn && isArray(modelValue)) {
- selectedSet = new HashMap([]);
- var locals = {};
- for (var trackIndex = 0; trackIndex < modelValue.length; trackIndex++) {
- locals[valueName] = modelValue[trackIndex];
- selectedSet.put(trackFn(scope, locals), modelValue[trackIndex]);
- }
- } else {
- selectedSet = new HashMap(modelValue);
- }
- }
- return selectedSet;
- }
-
-
- function render() {
- // Temporary location for the option groups before we render them
- var optionGroups = {'':[]},
- optionGroupNames = [''],
- optionGroupName,
- optionGroup,
- option,
- existingParent, existingOptions, existingOption,
- modelValue = ctrl.$modelValue,
- values = valuesFn(scope) || [],
- keys = keyName ? sortedKeys(values) : values,
- key,
- groupLength, length,
- groupIndex, index,
- locals = {},
- selected,
- selectedSet = getSelectedSet(),
- lastElement,
- element,
- label;
-
-
- // We now build up the list of options we need (we merge later)
- for (index = 0; length = keys.length, index < length; index++) {
-
- key = index;
- if (keyName) {
- key = keys[index];
- if ( key.charAt(0) === '$' ) continue;
- locals[keyName] = key;
- }
-
- locals[valueName] = values[key];
-
- optionGroupName = groupByFn(scope, locals) || '';
- if (!(optionGroup = optionGroups[optionGroupName])) {
- optionGroup = optionGroups[optionGroupName] = [];
- optionGroupNames.push(optionGroupName);
- }
- if (multiple) {
- selected = isDefined(
- selectedSet.remove(trackFn ? trackFn(scope, locals) : valueFn(scope, locals))
- );
- } else {
- if (trackFn) {
- var modelCast = {};
- modelCast[valueName] = modelValue;
- selected = trackFn(scope, modelCast) === trackFn(scope, locals);
- } else {
- selected = modelValue === valueFn(scope, locals);
- }
- selectedSet = selectedSet || selected; // see if at least one item is selected
- }
- label = displayFn(scope, locals); // what will be seen by the user
-
- // doing displayFn(scope, locals) || '' overwrites zero values
- label = isDefined(label) ? label : '';
- optionGroup.push({
- // either the index into array or key from object
- id: trackFn ? trackFn(scope, locals) : (keyName ? keys[index] : index),
- label: label,
- selected: selected // determine if we should be selected
- });
- }
- if (!multiple) {
- if (nullOption || modelValue === null) {
- // insert null option if we have a placeholder, or the model is null
- optionGroups[''].unshift({id:'', label:'', selected:!selectedSet});
- } else if (!selectedSet) {
- // option could not be found, we have to insert the undefined item
- optionGroups[''].unshift({id:'?', label:'', selected:true});
- }
- }
-
- // Now we need to update the list of DOM nodes to match the optionGroups we computed above
- for (groupIndex = 0, groupLength = optionGroupNames.length;
- groupIndex < groupLength;
- groupIndex++) {
- // current option group name or '' if no group
- optionGroupName = optionGroupNames[groupIndex];
-
- // list of options for that group. (first item has the parent)
- optionGroup = optionGroups[optionGroupName];
-
- if (optionGroupsCache.length <= groupIndex) {
- // we need to grow the optionGroups
- existingParent = {
- element: optGroupTemplate.clone().attr('label', optionGroupName),
- label: optionGroup.label
- };
- existingOptions = [existingParent];
- optionGroupsCache.push(existingOptions);
- selectElement.append(existingParent.element);
- } else {
- existingOptions = optionGroupsCache[groupIndex];
- existingParent = existingOptions[0]; // either SELECT (no group) or OPTGROUP element
-
- // update the OPTGROUP label if not the same.
- if (existingParent.label != optionGroupName) {
- existingParent.element.attr('label', existingParent.label = optionGroupName);
- }
- }
-
- lastElement = null; // start at the beginning
- for(index = 0, length = optionGroup.length; index < length; index++) {
- option = optionGroup[index];
- if ((existingOption = existingOptions[index+1])) {
- // reuse elements
- lastElement = existingOption.element;
- if (existingOption.label !== option.label) {
- lastElement.text(existingOption.label = option.label);
- lastElement.prop('label', existingOption.label);
- }
- if (existingOption.id !== option.id) {
- lastElement.val(existingOption.id = option.id);
- }
- // lastElement.prop('selected') provided by jQuery has side-effects
- if (lastElement[0].selected !== option.selected) {
- lastElement.prop('selected', (existingOption.selected = option.selected));
- if (msie) {
- // See #7692
- // The selected item wouldn't visually update on IE without this.
- // Tested on Win7: IE9, IE10 and IE11. Future IEs should be tested as well
- lastElement.prop('selected', existingOption.selected);
- }
- }
- } else {
- // grow elements
-
- // if it's a null option
- if (option.id === '' && nullOption) {
- // put back the pre-compiled element
- element = nullOption;
- } else {
- // jQuery(v1.4.2) Bug: We should be able to chain the method calls, but
- // in this version of jQuery on some browser the .text() returns a string
- // rather then the element.
- (element = optionTemplate.clone())
- .val(option.id)
- .prop('selected', option.selected)
- .attr('selected', option.selected)
- .prop('label', option.label)
- .text(option.label);
- }
+ // If we are a multiple select then value is now a collection
+ // so the meaning of $isEmpty changes
+ ngModelCtrl.$isEmpty = function(value) {
+ return !value || value.length === 0;
+ };
- existingOptions.push(existingOption = {
- element: element,
- label: option.label,
- id: option.id,
- selected: option.selected
- });
- selectCtrl.addOption(option.label, element);
- if (lastElement) {
- lastElement.after(element);
- } else {
- existingParent.element.append(element);
- }
- lastElement = element;
- }
- }
- // remove any excessive OPTIONs in a group
- index++; // increment since the existingOptions[0] is parent element not OPTION
- while(existingOptions.length > index) {
- option = existingOptions.pop();
- selectCtrl.removeOption(option.label);
- option.element.remove();
- }
- }
- // remove any excessive OPTGROUPs from select
- while(optionGroupsCache.length > groupIndex) {
- optionGroupsCache.pop()[0].element.remove();
- }
- }
}
}
};
-}];
+};
+
+// The option directive is purely designed to communicate the existence (or lack of)
+// of dynamically created (and destroyed) option elements to their containing select
+// directive via its controller.
var optionDirective = ['$interpolate', function($interpolate) {
- var nullSelectCtrl = {
- addOption: noop,
- removeOption: noop
- };
+
+ function chromeHack(optionElement) {
+ // Workaround for https://code.google.com/p/chromium/issues/detail?id=381459
+ // Adding an <option selected="selected"> element to a <select required="required"> should
+ // automatically select the new element
+ if (optionElement[0].hasAttribute('selected')) {
+ optionElement[0].selected = true;
+ }
+ }
return {
restrict: 'E',
priority: 100,
compile: function(element, attr) {
+
+ // If the value attribute is not defined then we fall back to the
+ // text content of the option element, which may be interpolated
if (isUndefined(attr.value)) {
var interpolateFn = $interpolate(element.text(), true);
if (!interpolateFn) {
@@ -22096,33 +28209,40 @@ var optionDirective = ['$interpolate', function($interpolate) {
}
}
- return function (scope, element, attr) {
+ return function(scope, element, attr) {
+
+ // This is an optimization over using ^^ since we don't want to have to search
+ // all the way to the root of the DOM for every single option element
var selectCtrlName = '$selectController',
parent = element.parent(),
selectCtrl = parent.data(selectCtrlName) ||
parent.parent().data(selectCtrlName); // in case we are in optgroup
- if (selectCtrl && selectCtrl.databound) {
- // For some reason Opera defaults to true and if not overridden this messes up the repeater.
- // We don't want the view to drive the initialization of the model anyway.
- element.prop('selected', false);
- } else {
- selectCtrl = nullSelectCtrl;
- }
+ // Only update trigger option updates if this is an option within a `select`
+ // that also has `ngModel` attached
+ if (selectCtrl && selectCtrl.ngModelCtrl) {
+
+ if (interpolateFn) {
+ scope.$watch(interpolateFn, function interpolateWatchAction(newVal, oldVal) {
+ attr.$set('value', newVal);
+ if (oldVal !== newVal) {
+ selectCtrl.removeOption(oldVal);
+ }
+ selectCtrl.addOption(newVal, element);
+ selectCtrl.ngModelCtrl.$render();
+ chromeHack(element);
+ });
+ } else {
+ selectCtrl.addOption(attr.value, element);
+ selectCtrl.ngModelCtrl.$render();
+ chromeHack(element);
+ }
- if (interpolateFn) {
- scope.$watch(interpolateFn, function interpolateWatchAction(newVal, oldVal) {
- attr.$set('value', newVal);
- if (newVal !== oldVal) selectCtrl.removeOption(oldVal);
- selectCtrl.addOption(newVal);
+ element.on('$destroy', function() {
+ selectCtrl.removeOption(attr.value);
+ selectCtrl.ngModelCtrl.$render();
});
- } else {
- selectCtrl.addOption(attr.value);
}
-
- element.on('$destroy', function() {
- selectCtrl.removeOption(attr.value);
- });
};
}
};
@@ -22130,16 +28250,106 @@ var optionDirective = ['$interpolate', function($interpolate) {
var styleDirective = valueFn({
restrict: 'E',
- terminal: true
+ terminal: false
});
+var requiredDirective = function() {
+ return {
+ restrict: 'A',
+ require: '?ngModel',
+ link: function(scope, elm, attr, ctrl) {
+ if (!ctrl) return;
+ attr.required = true; // force truthy in case we are on non input element
+
+ ctrl.$validators.required = function(modelValue, viewValue) {
+ return !attr.required || !ctrl.$isEmpty(viewValue);
+ };
+
+ attr.$observe('required', function() {
+ ctrl.$validate();
+ });
+ }
+ };
+};
+
+
+var patternDirective = function() {
+ return {
+ restrict: 'A',
+ require: '?ngModel',
+ link: function(scope, elm, attr, ctrl) {
+ if (!ctrl) return;
+
+ var regexp, patternExp = attr.ngPattern || attr.pattern;
+ attr.$observe('pattern', function(regex) {
+ if (isString(regex) && regex.length > 0) {
+ regex = new RegExp('^' + regex + '$');
+ }
+
+ if (regex && !regex.test) {
+ throw minErr('ngPattern')('noregexp',
+ 'Expected {0} to be a RegExp but was {1}. Element: {2}', patternExp,
+ regex, startingTag(elm));
+ }
+
+ regexp = regex || undefined;
+ ctrl.$validate();
+ });
+
+ ctrl.$validators.pattern = function(value) {
+ return ctrl.$isEmpty(value) || isUndefined(regexp) || regexp.test(value);
+ };
+ }
+ };
+};
+
+
+var maxlengthDirective = function() {
+ return {
+ restrict: 'A',
+ require: '?ngModel',
+ link: function(scope, elm, attr, ctrl) {
+ if (!ctrl) return;
+
+ var maxlength = -1;
+ attr.$observe('maxlength', function(value) {
+ var intVal = toInt(value);
+ maxlength = isNaN(intVal) ? -1 : intVal;
+ ctrl.$validate();
+ });
+ ctrl.$validators.maxlength = function(modelValue, viewValue) {
+ return (maxlength < 0) || ctrl.$isEmpty(viewValue) || (viewValue.length <= maxlength);
+ };
+ }
+ };
+};
+
+var minlengthDirective = function() {
+ return {
+ restrict: 'A',
+ require: '?ngModel',
+ link: function(scope, elm, attr, ctrl) {
+ if (!ctrl) return;
+
+ var minlength = 0;
+ attr.$observe('minlength', function(value) {
+ minlength = toInt(value) || 0;
+ ctrl.$validate();
+ });
+ ctrl.$validators.minlength = function(modelValue, viewValue) {
+ return ctrl.$isEmpty(viewValue) || viewValue.length >= minlength;
+ };
+ }
+ };
+};
+
if (window.angular.bootstrap) {
//AngularJS is already loaded, so we can return here...
console.log('WARNING: Tried to load angular more than once.');
return;
}
- //try to bind to jquery now so that one can write angular.element().read()
+ //try to bind to jquery now so that one can write jqLite(document).ready()
//but we will rebind on bootstrap again.
bindJQuery();
@@ -22151,4 +28361,4 @@ var styleDirective = valueFn({
})(window, document);
-!window.angular.$$csp() && window.angular.element(document).find('head').prepend('<style type="text/css">@charset "UTF-8";[ng\\:cloak],[ng-cloak],[data-ng-cloak],[x-ng-cloak],.ng-cloak,.x-ng-cloak,.ng-hide{display:none !important;}ng\\:form{display:block;}.ng-animate-block-transitions{transition:0s all!important;-webkit-transition:0s all!important;}.ng-hide-add-active,.ng-hide-remove{display:block!important;}</style>'); \ No newline at end of file
+!window.angular.$$csp() && window.angular.element(document.head).prepend('<style type="text/css">@charset "UTF-8";[ng\\:cloak],[ng-cloak],[data-ng-cloak],[x-ng-cloak],.ng-cloak,.x-ng-cloak,.ng-hide:not(.ng-hide-animate){display:none !important;}ng\\:form{display:block;}.ng-animate-shim{visibility:hidden;}.ng-anchor{position:absolute;}</style>');
diff --git a/libs/bower_components/angular/angular.min.js b/libs/bower_components/angular/angular.min.js
index e4f66c18bc..2c28ef96f2 100644
--- a/libs/bower_components/angular/angular.min.js
+++ b/libs/bower_components/angular/angular.min.js
@@ -1,217 +1,290 @@
/*
- AngularJS v1.2.28
- (c) 2010-2014 Google, Inc. http://angularjs.org
+ AngularJS v1.4.3
+ (c) 2010-2015 Google, Inc. http://angularjs.org
License: MIT
*/
-(function(W,X,u){'use strict';function z(b){return function(){var a=arguments[0],c,a="["+(b?b+":":"")+a+"] http://errors.angularjs.org/1.2.28/"+(b?b+"/":"")+a;for(c=1;c<arguments.length;c++)a=a+(1==c?"?":"&")+"p"+(c-1)+"="+encodeURIComponent("function"==typeof arguments[c]?arguments[c].toString().replace(/ \{[\s\S]*$/,""):"undefined"==typeof arguments[c]?"undefined":"string"!=typeof arguments[c]?JSON.stringify(arguments[c]):arguments[c]);return Error(a)}}function Sa(b){if(null==b||Ja(b))return!1;
-var a=b.length;return 1===b.nodeType&&a?!0:G(b)||L(b)||0===a||"number"===typeof a&&0<a&&a-1 in b}function r(b,a,c){var d;if(b)if(N(b))for(d in b)"prototype"==d||("length"==d||"name"==d||b.hasOwnProperty&&!b.hasOwnProperty(d))||a.call(c,b[d],d);else if(L(b)||Sa(b))for(d=0;d<b.length;d++)a.call(c,b[d],d);else if(b.forEach&&b.forEach!==r)b.forEach(a,c);else for(d in b)b.hasOwnProperty(d)&&a.call(c,b[d],d);return b}function Xb(b){var a=[],c;for(c in b)b.hasOwnProperty(c)&&a.push(c);return a.sort()}function Sc(b,
-a,c){for(var d=Xb(b),e=0;e<d.length;e++)a.call(c,b[d[e]],d[e]);return d}function Yb(b){return function(a,c){b(c,a)}}function ib(){for(var b=na.length,a;b;){b--;a=na[b].charCodeAt(0);if(57==a)return na[b]="A",na.join("");if(90==a)na[b]="0";else return na[b]=String.fromCharCode(a+1),na.join("")}na.unshift("0");return na.join("")}function Zb(b,a){a?b.$$hashKey=a:delete b.$$hashKey}function E(b){var a=b.$$hashKey;r(arguments,function(a){a!==b&&r(a,function(a,c){b[c]=a})});Zb(b,a);return b}function U(b){return parseInt(b,
-10)}function $b(b,a){return E(new (E(function(){},{prototype:b})),a)}function v(){}function ga(b){return b}function aa(b){return function(){return b}}function F(b){return"undefined"===typeof b}function D(b){return"undefined"!==typeof b}function T(b){return null!=b&&"object"===typeof b}function G(b){return"string"===typeof b}function jb(b){return"number"===typeof b}function va(b){return"[object Date]"===Ba.call(b)}function N(b){return"function"===typeof b}function kb(b){return"[object RegExp]"===Ba.call(b)}
-function Ja(b){return b&&b.document&&b.location&&b.alert&&b.setInterval}function Tc(b){return!(!b||!(b.nodeName||b.prop&&b.attr&&b.find))}function Uc(b,a,c){var d=[];r(b,function(b,f,g){d.push(a.call(c,b,f,g))});return d}function Ta(b,a){if(b.indexOf)return b.indexOf(a);for(var c=0;c<b.length;c++)if(a===b[c])return c;return-1}function Ua(b,a){var c=Ta(b,a);0<=c&&b.splice(c,1);return a}function Ka(b,a,c,d){if(Ja(b)||b&&b.$evalAsync&&b.$watch)throw Va("cpws");if(a){if(b===a)throw Va("cpi");c=c||[];
-d=d||[];if(T(b)){var e=Ta(c,b);if(-1!==e)return d[e];c.push(b);d.push(a)}if(L(b))for(var f=a.length=0;f<b.length;f++)e=Ka(b[f],null,c,d),T(b[f])&&(c.push(b[f]),d.push(e)),a.push(e);else{var g=a.$$hashKey;L(a)?a.length=0:r(a,function(b,c){delete a[c]});for(f in b)e=Ka(b[f],null,c,d),T(b[f])&&(c.push(b[f]),d.push(e)),a[f]=e;Zb(a,g)}}else if(a=b)L(b)?a=Ka(b,[],c,d):va(b)?a=new Date(b.getTime()):kb(b)?(a=RegExp(b.source,b.toString().match(/[^\/]*$/)[0]),a.lastIndex=b.lastIndex):T(b)&&(a=Ka(b,{},c,d));
-return a}function ha(b,a){if(L(b)){a=a||[];for(var c=0;c<b.length;c++)a[c]=b[c]}else if(T(b))for(c in a=a||{},b)!lb.call(b,c)||"$"===c.charAt(0)&&"$"===c.charAt(1)||(a[c]=b[c]);return a||b}function Ca(b,a){if(b===a)return!0;if(null===b||null===a)return!1;if(b!==b&&a!==a)return!0;var c=typeof b,d;if(c==typeof a&&"object"==c)if(L(b)){if(!L(a))return!1;if((c=b.length)==a.length){for(d=0;d<c;d++)if(!Ca(b[d],a[d]))return!1;return!0}}else{if(va(b))return va(a)?isNaN(b.getTime())&&isNaN(a.getTime())||b.getTime()===
-a.getTime():!1;if(kb(b)&&kb(a))return b.toString()==a.toString();if(b&&b.$evalAsync&&b.$watch||a&&a.$evalAsync&&a.$watch||Ja(b)||Ja(a)||L(a))return!1;c={};for(d in b)if("$"!==d.charAt(0)&&!N(b[d])){if(!Ca(b[d],a[d]))return!1;c[d]=!0}for(d in a)if(!c.hasOwnProperty(d)&&"$"!==d.charAt(0)&&a[d]!==u&&!N(a[d]))return!1;return!0}return!1}function Bb(b,a){var c=2<arguments.length?wa.call(arguments,2):[];return!N(a)||a instanceof RegExp?a:c.length?function(){return arguments.length?a.apply(b,c.concat(wa.call(arguments,
-0))):a.apply(b,c)}:function(){return arguments.length?a.apply(b,arguments):a.call(b)}}function Vc(b,a){var c=a;"string"===typeof b&&"$"===b.charAt(0)?c=u:Ja(a)?c="$WINDOW":a&&X===a?c="$DOCUMENT":a&&(a.$evalAsync&&a.$watch)&&(c="$SCOPE");return c}function oa(b,a){return"undefined"===typeof b?u:JSON.stringify(b,Vc,a?" ":null)}function ac(b){return G(b)?JSON.parse(b):b}function Wa(b){"function"===typeof b?b=!0:b&&0!==b.length?(b=x(""+b),b=!("f"==b||"0"==b||"false"==b||"no"==b||"n"==b||"[]"==b)):b=!1;
-return b}function ia(b){b=A(b).clone();try{b.empty()}catch(a){}var c=A("<div>").append(b).html();try{return 3===b[0].nodeType?x(c):c.match(/^(<[^>]+>)/)[1].replace(/^<([\w\-]+)/,function(a,b){return"<"+x(b)})}catch(d){return x(c)}}function bc(b){try{return decodeURIComponent(b)}catch(a){}}function cc(b){var a={},c,d;r((b||"").split("&"),function(b){b&&(c=b.replace(/\+/g,"%20").split("="),d=bc(c[0]),D(d)&&(b=D(c[1])?bc(c[1]):!0,lb.call(a,d)?L(a[d])?a[d].push(b):a[d]=[a[d],b]:a[d]=b))});return a}function Cb(b){var a=
-[];r(b,function(b,d){L(b)?r(b,function(b){a.push(Da(d,!0)+(!0===b?"":"="+Da(b,!0)))}):a.push(Da(d,!0)+(!0===b?"":"="+Da(b,!0)))});return a.length?a.join("&"):""}function mb(b){return Da(b,!0).replace(/%26/gi,"&").replace(/%3D/gi,"=").replace(/%2B/gi,"+")}function Da(b,a){return encodeURIComponent(b).replace(/%40/gi,"@").replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%20/g,a?"%20":"+")}function Wc(b,a){function c(a){a&&d.push(a)}var d=[b],e,f,g=["ng:app","ng-app","x-ng-app",
-"data-ng-app"],h=/\sng[:\-]app(:\s*([\w\d_]+);?)?\s/;r(g,function(a){g[a]=!0;c(X.getElementById(a));a=a.replace(":","\\:");b.querySelectorAll&&(r(b.querySelectorAll("."+a),c),r(b.querySelectorAll("."+a+"\\:"),c),r(b.querySelectorAll("["+a+"]"),c))});r(d,function(a){if(!e){var b=h.exec(" "+a.className+" ");b?(e=a,f=(b[2]||"").replace(/\s+/g,",")):r(a.attributes,function(b){!e&&g[b.name]&&(e=a,f=b.value)})}});e&&a(e,f?[f]:[])}function dc(b,a){var c=function(){b=A(b);if(b.injector()){var c=b[0]===X?
-"document":ia(b);throw Va("btstrpd",c.replace(/</,"&lt;").replace(/>/,"&gt;"));}a=a||[];a.unshift(["$provide",function(a){a.value("$rootElement",b)}]);a.unshift("ng");c=ec(a);c.invoke(["$rootScope","$rootElement","$compile","$injector","$animate",function(a,b,c,d,e){a.$apply(function(){b.data("$injector",d);c(b)(a)})}]);return c},d=/^NG_DEFER_BOOTSTRAP!/;if(W&&!d.test(W.name))return c();W.name=W.name.replace(d,"");Xa.resumeBootstrap=function(b){r(b,function(b){a.push(b)});c()}}function nb(b,a){a=
-a||"_";return b.replace(Xc,function(b,d){return(d?a:"")+b.toLowerCase()})}function Db(b,a,c){if(!b)throw Va("areq",a||"?",c||"required");return b}function Ya(b,a,c){c&&L(b)&&(b=b[b.length-1]);Db(N(b),a,"not a function, got "+(b&&"object"===typeof b?b.constructor.name||"Object":typeof b));return b}function Ea(b,a){if("hasOwnProperty"===b)throw Va("badname",a);}function fc(b,a,c){if(!a)return b;a=a.split(".");for(var d,e=b,f=a.length,g=0;g<f;g++)d=a[g],b&&(b=(e=b)[d]);return!c&&N(b)?Bb(e,b):b}function Eb(b){var a=
-b[0];b=b[b.length-1];if(a===b)return A(a);var c=[a];do{a=a.nextSibling;if(!a)break;c.push(a)}while(a!==b);return A(c)}function Yc(b){var a=z("$injector"),c=z("ng");b=b.angular||(b.angular={});b.$$minErr=b.$$minErr||z;return b.module||(b.module=function(){var b={};return function(e,f,g){if("hasOwnProperty"===e)throw c("badname","module");f&&b.hasOwnProperty(e)&&(b[e]=null);return b[e]||(b[e]=function(){function b(a,d,e){return function(){c[e||"push"]([a,d,arguments]);return n}}if(!f)throw a("nomod",
-e);var c=[],d=[],l=b("$injector","invoke"),n={_invokeQueue:c,_runBlocks:d,requires:f,name:e,provider:b("$provide","provider"),factory:b("$provide","factory"),service:b("$provide","service"),value:b("$provide","value"),constant:b("$provide","constant","unshift"),animation:b("$animateProvider","register"),filter:b("$filterProvider","register"),controller:b("$controllerProvider","register"),directive:b("$compileProvider","directive"),config:l,run:function(a){d.push(a);return this}};g&&l(g);return n}())}}())}
-function Zc(b){E(b,{bootstrap:dc,copy:Ka,extend:E,equals:Ca,element:A,forEach:r,injector:ec,noop:v,bind:Bb,toJson:oa,fromJson:ac,identity:ga,isUndefined:F,isDefined:D,isString:G,isFunction:N,isObject:T,isNumber:jb,isElement:Tc,isArray:L,version:$c,isDate:va,lowercase:x,uppercase:La,callbacks:{counter:0},$$minErr:z,$$csp:Za});$a=Yc(W);try{$a("ngLocale")}catch(a){$a("ngLocale",[]).provider("$locale",ad)}$a("ng",["ngLocale"],["$provide",function(a){a.provider({$$sanitizeUri:bd});a.provider("$compile",
-gc).directive({a:cd,input:hc,textarea:hc,form:dd,script:ed,select:fd,style:gd,option:hd,ngBind:id,ngBindHtml:jd,ngBindTemplate:kd,ngClass:ld,ngClassEven:md,ngClassOdd:nd,ngCloak:od,ngController:pd,ngForm:qd,ngHide:rd,ngIf:sd,ngInclude:td,ngInit:ud,ngNonBindable:vd,ngPluralize:wd,ngRepeat:xd,ngShow:yd,ngStyle:zd,ngSwitch:Ad,ngSwitchWhen:Bd,ngSwitchDefault:Cd,ngOptions:Dd,ngTransclude:Ed,ngModel:Fd,ngList:Gd,ngChange:Hd,required:ic,ngRequired:ic,ngValue:Id}).directive({ngInclude:Jd}).directive(Fb).directive(jc);
-a.provider({$anchorScroll:Kd,$animate:Ld,$browser:Md,$cacheFactory:Nd,$controller:Od,$document:Pd,$exceptionHandler:Qd,$filter:kc,$interpolate:Rd,$interval:Sd,$http:Td,$httpBackend:Ud,$location:Vd,$log:Wd,$parse:Xd,$rootScope:Yd,$q:Zd,$sce:$d,$sceDelegate:ae,$sniffer:be,$templateCache:ce,$timeout:de,$window:ee,$$rAF:fe,$$asyncCallback:ge})}])}function ab(b){return b.replace(he,function(a,b,d,e){return e?d.toUpperCase():d}).replace(ie,"Moz$1")}function Gb(b,a,c,d){function e(b){var e=c&&b?[this.filter(b)]:
-[this],k=a,m,l,n,q,p,s;if(!d||null!=b)for(;e.length;)for(m=e.shift(),l=0,n=m.length;l<n;l++)for(q=A(m[l]),k?q.triggerHandler("$destroy"):k=!k,p=0,q=(s=q.children()).length;p<q;p++)e.push(Fa(s[p]));return f.apply(this,arguments)}var f=Fa.fn[b],f=f.$original||f;e.$original=f;Fa.fn[b]=e}function S(b){if(b instanceof S)return b;G(b)&&(b=$(b));if(!(this instanceof S)){if(G(b)&&"<"!=b.charAt(0))throw Hb("nosel");return new S(b)}if(G(b)){var a=b;b=X;var c;if(c=je.exec(a))b=[b.createElement(c[1])];else{var d=
-b,e;b=d.createDocumentFragment();c=[];if(Ib.test(a)){d=b.appendChild(d.createElement("div"));e=(ke.exec(a)||["",""])[1].toLowerCase();e=da[e]||da._default;d.innerHTML="<div>&#160;</div>"+e[1]+a.replace(le,"<$1></$2>")+e[2];d.removeChild(d.firstChild);for(a=e[0];a--;)d=d.lastChild;a=0;for(e=d.childNodes.length;a<e;++a)c.push(d.childNodes[a]);d=b.firstChild;d.textContent=""}else c.push(d.createTextNode(a));b.textContent="";b.innerHTML="";b=c}Jb(this,b);A(X.createDocumentFragment()).append(this)}else Jb(this,
-b)}function Kb(b){return b.cloneNode(!0)}function Ma(b){Lb(b);var a=0;for(b=b.childNodes||[];a<b.length;a++)Ma(b[a])}function lc(b,a,c,d){if(D(d))throw Hb("offargs");var e=pa(b,"events");pa(b,"handle")&&(F(a)?r(e,function(a,c){bb(b,c,a);delete e[c]}):r(a.split(" "),function(a){F(c)?(bb(b,a,e[a]),delete e[a]):Ua(e[a]||[],c)}))}function Lb(b,a){var c=b.ng339,d=cb[c];d&&(a?delete cb[c].data[a]:(d.handle&&(d.events.$destroy&&d.handle({},"$destroy"),lc(b)),delete cb[c],b.ng339=u))}function pa(b,a,c){var d=
-b.ng339,d=cb[d||-1];if(D(c))d||(b.ng339=d=++me,d=cb[d]={}),d[a]=c;else return d&&d[a]}function Mb(b,a,c){var d=pa(b,"data"),e=D(c),f=!e&&D(a),g=f&&!T(a);d||g||pa(b,"data",d={});if(e)d[a]=c;else if(f){if(g)return d&&d[a];E(d,a)}else return d}function Nb(b,a){return b.getAttribute?-1<(" "+(b.getAttribute("class")||"")+" ").replace(/[\n\t]/g," ").indexOf(" "+a+" "):!1}function ob(b,a){a&&b.setAttribute&&r(a.split(" "),function(a){b.setAttribute("class",$((" "+(b.getAttribute("class")||"")+" ").replace(/[\n\t]/g,
-" ").replace(" "+$(a)+" "," ")))})}function pb(b,a){if(a&&b.setAttribute){var c=(" "+(b.getAttribute("class")||"")+" ").replace(/[\n\t]/g," ");r(a.split(" "),function(a){a=$(a);-1===c.indexOf(" "+a+" ")&&(c+=a+" ")});b.setAttribute("class",$(c))}}function Jb(b,a){if(a){a=a.nodeName||!D(a.length)||Ja(a)?[a]:a;for(var c=0;c<a.length;c++)b.push(a[c])}}function mc(b,a){return qb(b,"$"+(a||"ngController")+"Controller")}function qb(b,a,c){9==b.nodeType&&(b=b.documentElement);for(a=L(a)?a:[a];b;){for(var d=
-0,e=a.length;d<e;d++)if((c=A.data(b,a[d]))!==u)return c;b=b.parentNode||11===b.nodeType&&b.host}}function nc(b){for(var a=0,c=b.childNodes;a<c.length;a++)Ma(c[a]);for(;b.firstChild;)b.removeChild(b.firstChild)}function oc(b,a){var c=rb[a.toLowerCase()];return c&&pc[b.nodeName]&&c}function ne(b,a){var c=function(c,e){c.preventDefault||(c.preventDefault=function(){c.returnValue=!1});c.stopPropagation||(c.stopPropagation=function(){c.cancelBubble=!0});c.target||(c.target=c.srcElement||X);if(F(c.defaultPrevented)){var f=
-c.preventDefault;c.preventDefault=function(){c.defaultPrevented=!0;f.call(c)};c.defaultPrevented=!1}c.isDefaultPrevented=function(){return c.defaultPrevented||!1===c.returnValue};var g=ha(a[e||c.type]||[]);r(g,function(a){a.call(b,c)});8>=R?(c.preventDefault=null,c.stopPropagation=null,c.isDefaultPrevented=null):(delete c.preventDefault,delete c.stopPropagation,delete c.isDefaultPrevented)};c.elem=b;return c}function Na(b,a){var c=typeof b,d;"function"==c||"object"==c&&null!==b?"function"==typeof(d=
-b.$$hashKey)?d=b.$$hashKey():d===u&&(d=b.$$hashKey=(a||ib)()):d=b;return c+":"+d}function db(b,a){if(a){var c=0;this.nextUid=function(){return++c}}r(b,this.put,this)}function qc(b){var a,c;"function"===typeof b?(a=b.$inject)||(a=[],b.length&&(c=b.toString().replace(oe,""),c=c.match(pe),r(c[1].split(qe),function(b){b.replace(re,function(b,c,d){a.push(d)})})),b.$inject=a):L(b)?(c=b.length-1,Ya(b[c],"fn"),a=b.slice(0,c)):Ya(b,"fn",!0);return a}function ec(b){function a(a){return function(b,c){if(T(b))r(b,
-Yb(a));else return a(b,c)}}function c(a,b){Ea(a,"service");if(N(b)||L(b))b=n.instantiate(b);if(!b.$get)throw eb("pget",a);return l[a+h]=b}function d(a,b){return c(a,{$get:b})}function e(a){var b=[],c,d,f,h;r(a,function(a){if(!m.get(a)){m.put(a,!0);try{if(G(a))for(c=$a(a),b=b.concat(e(c.requires)).concat(c._runBlocks),d=c._invokeQueue,f=0,h=d.length;f<h;f++){var g=d[f],k=n.get(g[0]);k[g[1]].apply(k,g[2])}else N(a)?b.push(n.invoke(a)):L(a)?b.push(n.invoke(a)):Ya(a,"module")}catch(p){throw L(a)&&(a=
-a[a.length-1]),p.message&&(p.stack&&-1==p.stack.indexOf(p.message))&&(p=p.message+"\n"+p.stack),eb("modulerr",a,p.stack||p.message||p);}}});return b}function f(a,b){function c(d){if(a.hasOwnProperty(d)){if(a[d]===g)throw eb("cdep",d+" <- "+k.join(" <- "));return a[d]}try{return k.unshift(d),a[d]=g,a[d]=b(d)}catch(e){throw a[d]===g&&delete a[d],e;}finally{k.shift()}}function d(a,b,e){var f=[],h=qc(a),g,k,p;k=0;for(g=h.length;k<g;k++){p=h[k];if("string"!==typeof p)throw eb("itkn",p);f.push(e&&e.hasOwnProperty(p)?
-e[p]:c(p))}L(a)&&(a=a[g]);return a.apply(b,f)}return{invoke:d,instantiate:function(a,b){var c=function(){},e;c.prototype=(L(a)?a[a.length-1]:a).prototype;c=new c;e=d(a,c,b);return T(e)||N(e)?e:c},get:c,annotate:qc,has:function(b){return l.hasOwnProperty(b+h)||a.hasOwnProperty(b)}}}var g={},h="Provider",k=[],m=new db([],!0),l={$provide:{provider:a(c),factory:a(d),service:a(function(a,b){return d(a,["$injector",function(a){return a.instantiate(b)}])}),value:a(function(a,b){return d(a,aa(b))}),constant:a(function(a,
-b){Ea(a,"constant");l[a]=b;q[a]=b}),decorator:function(a,b){var c=n.get(a+h),d=c.$get;c.$get=function(){var a=p.invoke(d,c);return p.invoke(b,null,{$delegate:a})}}}},n=l.$injector=f(l,function(){throw eb("unpr",k.join(" <- "));}),q={},p=q.$injector=f(q,function(a){a=n.get(a+h);return p.invoke(a.$get,a)});r(e(b),function(a){p.invoke(a||v)});return p}function Kd(){var b=!0;this.disableAutoScrolling=function(){b=!1};this.$get=["$window","$location","$rootScope",function(a,c,d){function e(a){var b=null;
-r(a,function(a){b||"a"!==x(a.nodeName)||(b=a)});return b}function f(){var b=c.hash(),d;b?(d=g.getElementById(b))?d.scrollIntoView():(d=e(g.getElementsByName(b)))?d.scrollIntoView():"top"===b&&a.scrollTo(0,0):a.scrollTo(0,0)}var g=a.document;b&&d.$watch(function(){return c.hash()},function(){d.$evalAsync(f)});return f}]}function ge(){this.$get=["$$rAF","$timeout",function(b,a){return b.supported?function(a){return b(a)}:function(b){return a(b,0,!1)}}]}function se(b,a,c,d){function e(a){try{a.apply(null,
-wa.call(arguments,1))}finally{if(s--,0===s)for(;J.length;)try{J.pop()()}catch(b){c.error(b)}}}function f(a,b){(function ea(){r(w,function(a){a()});t=b(ea,a)})()}function g(){y!=h.url()&&(y=h.url(),r(ba,function(a){a(h.url())}))}var h=this,k=a[0],m=b.location,l=b.history,n=b.setTimeout,q=b.clearTimeout,p={};h.isMock=!1;var s=0,J=[];h.$$completeOutstandingRequest=e;h.$$incOutstandingRequestCount=function(){s++};h.notifyWhenNoOutstandingRequests=function(a){r(w,function(a){a()});0===s?a():J.push(a)};
-var w=[],t;h.addPollFn=function(a){F(t)&&f(100,n);w.push(a);return a};var y=m.href,K=a.find("base"),B=null;h.url=function(a,c){m!==b.location&&(m=b.location);l!==b.history&&(l=b.history);if(a){if(y!=a){var e=y&&Ga(y)===Ga(a);y=a;!e&&d.history?c?l.replaceState(null,"",a):(l.pushState(null,"",a),K.attr("href",K.attr("href"))):(e||(B=a),c?m.replace(a):m.href=a);return h}}else return B||m.href.replace(/%27/g,"'")};var ba=[],O=!1;h.onUrlChange=function(a){if(!O){if(d.history)A(b).on("popstate",g);if(d.hashchange)A(b).on("hashchange",
-g);else h.addPollFn(g);O=!0}ba.push(a);return a};h.$$checkUrlChange=g;h.baseHref=function(){var a=K.attr("href");return a?a.replace(/^(https?\:)?\/\/[^\/]*/,""):""};var M={},ca="",P=h.baseHref();h.cookies=function(a,b){var d,e,f,h;if(a)b===u?k.cookie=escape(a)+"=;path="+P+";expires=Thu, 01 Jan 1970 00:00:00 GMT":G(b)&&(d=(k.cookie=escape(a)+"="+escape(b)+";path="+P).length+1,4096<d&&c.warn("Cookie '"+a+"' possibly not set or overflowed because it was too large ("+d+" > 4096 bytes)!"));else{if(k.cookie!==
-ca)for(ca=k.cookie,d=ca.split("; "),M={},f=0;f<d.length;f++)e=d[f],h=e.indexOf("="),0<h&&(a=unescape(e.substring(0,h)),M[a]===u&&(M[a]=unescape(e.substring(h+1))));return M}};h.defer=function(a,b){var c;s++;c=n(function(){delete p[c];e(a)},b||0);p[c]=!0;return c};h.defer.cancel=function(a){return p[a]?(delete p[a],q(a),e(v),!0):!1}}function Md(){this.$get=["$window","$log","$sniffer","$document",function(b,a,c,d){return new se(b,d,a,c)}]}function Nd(){this.$get=function(){function b(b,d){function e(a){a!=
-n&&(q?q==a&&(q=a.n):q=a,f(a.n,a.p),f(a,n),n=a,n.n=null)}function f(a,b){a!=b&&(a&&(a.p=b),b&&(b.n=a))}if(b in a)throw z("$cacheFactory")("iid",b);var g=0,h=E({},d,{id:b}),k={},m=d&&d.capacity||Number.MAX_VALUE,l={},n=null,q=null;return a[b]={put:function(a,b){if(m<Number.MAX_VALUE){var c=l[a]||(l[a]={key:a});e(c)}if(!F(b))return a in k||g++,k[a]=b,g>m&&this.remove(q.key),b},get:function(a){if(m<Number.MAX_VALUE){var b=l[a];if(!b)return;e(b)}return k[a]},remove:function(a){if(m<Number.MAX_VALUE){var b=
-l[a];if(!b)return;b==n&&(n=b.p);b==q&&(q=b.n);f(b.n,b.p);delete l[a]}delete k[a];g--},removeAll:function(){k={};g=0;l={};n=q=null},destroy:function(){l=h=k=null;delete a[b]},info:function(){return E({},h,{size:g})}}}var a={};b.info=function(){var b={};r(a,function(a,e){b[e]=a.info()});return b};b.get=function(b){return a[b]};return b}}function ce(){this.$get=["$cacheFactory",function(b){return b("templates")}]}function gc(b,a){var c={},d="Directive",e=/^\s*directive\:\s*([\d\w_\-]+)\s+(.*)$/,f=/(([\d\w_\-]+)(?:\:([^;]+))?;?)/,
-g=/^(on[a-z]+|formaction)$/;this.directive=function k(a,e){Ea(a,"directive");G(a)?(Db(e,"directiveFactory"),c.hasOwnProperty(a)||(c[a]=[],b.factory(a+d,["$injector","$exceptionHandler",function(b,d){var e=[];r(c[a],function(c,f){try{var g=b.invoke(c);N(g)?g={compile:aa(g)}:!g.compile&&g.link&&(g.compile=aa(g.link));g.priority=g.priority||0;g.index=f;g.name=g.name||a;g.require=g.require||g.controller&&g.name;g.restrict=g.restrict||"A";e.push(g)}catch(k){d(k)}});return e}])),c[a].push(e)):r(a,Yb(k));
-return this};this.aHrefSanitizationWhitelist=function(b){return D(b)?(a.aHrefSanitizationWhitelist(b),this):a.aHrefSanitizationWhitelist()};this.imgSrcSanitizationWhitelist=function(b){return D(b)?(a.imgSrcSanitizationWhitelist(b),this):a.imgSrcSanitizationWhitelist()};this.$get=["$injector","$interpolate","$exceptionHandler","$http","$templateCache","$parse","$controller","$rootScope","$document","$sce","$animate","$$sanitizeUri",function(a,b,l,n,q,p,s,J,w,t,y,K){function B(a,b,c,d,e){a instanceof
-A||(a=A(a));r(a,function(b,c){3==b.nodeType&&b.nodeValue.match(/\S+/)&&(a[c]=A(b).wrap("<span></span>").parent()[0])});var f=O(a,b,a,c,d,e);ba(a,"ng-scope");return function(b,c,d,e){Db(b,"scope");var g=c?Oa.clone.call(a):a;r(d,function(a,b){g.data("$"+b+"Controller",a)});d=0;for(var k=g.length;d<k;d++){var p=g[d].nodeType;1!==p&&9!==p||g.eq(d).data("$scope",b)}c&&c(g,b);f&&f(b,g,g,e);return g}}function ba(a,b){try{a.addClass(b)}catch(c){}}function O(a,b,c,d,e,f){function g(a,c,d,e){var f,p,l,m,q,
-n,w;f=c.length;var s=Array(f);for(m=0;m<f;m++)s[m]=c[m];n=m=0;for(q=k.length;m<q;n++)p=s[n],c=k[m++],f=k[m++],c?(c.scope?(l=a.$new(),A.data(p,"$scope",l)):l=a,w=c.transcludeOnThisElement?M(a,c.transclude,e):!c.templateOnThisElement&&e?e:!e&&b?M(a,b):null,c(f,l,p,d,w)):f&&f(a,p.childNodes,u,e)}for(var k=[],p,l,m,q,n=0;n<a.length;n++)p=new Ob,l=ca(a[n],[],p,0===n?d:u,e),(f=l.length?I(l,a[n],p,b,c,null,[],[],f):null)&&f.scope&&ba(p.$$element,"ng-scope"),p=f&&f.terminal||!(m=a[n].childNodes)||!m.length?
-null:O(m,f?(f.transcludeOnThisElement||!f.templateOnThisElement)&&f.transclude:b),k.push(f,p),q=q||f||p,f=null;return q?g:null}function M(a,b,c){return function(d,e,f){var g=!1;d||(d=a.$new(),g=d.$$transcluded=!0);e=b(d,e,f,c);if(g)e.on("$destroy",function(){d.$destroy()});return e}}function ca(a,b,c,d,g){var k=c.$attr,p;switch(a.nodeType){case 1:ea(b,qa(Pa(a).toLowerCase()),"E",d,g);for(var l,m,q,n=a.attributes,w=0,s=n&&n.length;w<s;w++){var t=!1,J=!1;l=n[w];if(!R||8<=R||l.specified){p=l.name;m=
-$(l.value);l=qa(p);if(q=U.test(l))p=nb(l.substr(6),"-");var y=l.replace(/(Start|End)$/,"");l===y+"Start"&&(t=p,J=p.substr(0,p.length-5)+"end",p=p.substr(0,p.length-6));l=qa(p.toLowerCase());k[l]=p;if(q||!c.hasOwnProperty(l))c[l]=m,oc(a,l)&&(c[l]=!0);S(a,b,m,l);ea(b,l,"A",d,g,t,J)}}a=a.className;if(G(a)&&""!==a)for(;p=f.exec(a);)l=qa(p[2]),ea(b,l,"C",d,g)&&(c[l]=$(p[3])),a=a.substr(p.index+p[0].length);break;case 3:x(b,a.nodeValue);break;case 8:try{if(p=e.exec(a.nodeValue))l=qa(p[1]),ea(b,l,"M",d,
-g)&&(c[l]=$(p[2]))}catch(B){}}b.sort(F);return b}function P(a,b,c){var d=[],e=0;if(b&&a.hasAttribute&&a.hasAttribute(b)){do{if(!a)throw ja("uterdir",b,c);1==a.nodeType&&(a.hasAttribute(b)&&e++,a.hasAttribute(c)&&e--);d.push(a);a=a.nextSibling}while(0<e)}else d.push(a);return A(d)}function C(a,b,c){return function(d,e,f,g,k){e=P(e[0],b,c);return a(d,e,f,g,k)}}function I(a,c,d,e,f,g,k,q,n){function w(a,b,c,d){if(a){c&&(a=C(a,c,d));a.require=H.require;a.directiveName=z;if(K===H||H.$$isolateScope)a=rc(a,
-{isolateScope:!0});k.push(a)}if(b){c&&(b=C(b,c,d));b.require=H.require;b.directiveName=z;if(K===H||H.$$isolateScope)b=rc(b,{isolateScope:!0});q.push(b)}}function t(a,b,c,d){var e,f="data",g=!1;if(G(b)){for(;"^"==(e=b.charAt(0))||"?"==e;)b=b.substr(1),"^"==e&&(f="inheritedData"),g=g||"?"==e;e=null;d&&"data"===f&&(e=d[b]);e=e||c[f]("$"+b+"Controller");if(!e&&!g)throw ja("ctreq",b,a);}else L(b)&&(e=[],r(b,function(b){e.push(t(a,b,c,d))}));return e}function J(a,e,f,g,n){function w(a,b){var c;2>arguments.length&&
-(b=a,a=u);Ia&&(c=ca);return n(a,b,c)}var y,Q,B,M,C,P,ca={},ra;y=c===f?d:ha(d,new Ob(A(f),d.$attr));Q=y.$$element;if(K){var ue=/^\s*([@=&])(\??)\s*(\w*)\s*$/;P=e.$new(!0);!I||I!==K&&I!==K.$$originalDirective?Q.data("$isolateScopeNoTemplate",P):Q.data("$isolateScope",P);ba(Q,"ng-isolate-scope");r(K.scope,function(a,c){var d=a.match(ue)||[],f=d[3]||c,g="?"==d[2],d=d[1],k,l,n,q;P.$$isolateBindings[c]=d+f;switch(d){case "@":y.$observe(f,function(a){P[c]=a});y.$$observers[f].$$scope=e;y[f]&&(P[c]=b(y[f])(e));
-break;case "=":if(g&&!y[f])break;l=p(y[f]);q=l.literal?Ca:function(a,b){return a===b||a!==a&&b!==b};n=l.assign||function(){k=P[c]=l(e);throw ja("nonassign",y[f],K.name);};k=P[c]=l(e);P.$watch(function(){var a=l(e);q(a,P[c])||(q(a,k)?n(e,a=P[c]):P[c]=a);return k=a},null,l.literal);break;case "&":l=p(y[f]);P[c]=function(a){return l(e,a)};break;default:throw ja("iscp",K.name,c,a);}})}ra=n&&w;O&&r(O,function(a){var b={$scope:a===K||a.$$isolateScope?P:e,$element:Q,$attrs:y,$transclude:ra},c;C=a.controller;
-"@"==C&&(C=y[a.name]);c=s(C,b);ca[a.name]=c;Ia||Q.data("$"+a.name+"Controller",c);a.controllerAs&&(b.$scope[a.controllerAs]=c)});g=0;for(B=k.length;g<B;g++)try{M=k[g],M(M.isolateScope?P:e,Q,y,M.require&&t(M.directiveName,M.require,Q,ca),ra)}catch(H){l(H,ia(Q))}g=e;K&&(K.template||null===K.templateUrl)&&(g=P);a&&a(g,f.childNodes,u,n);for(g=q.length-1;0<=g;g--)try{M=q[g],M(M.isolateScope?P:e,Q,y,M.require&&t(M.directiveName,M.require,Q,ca),ra)}catch(D){l(D,ia(Q))}}n=n||{};for(var y=-Number.MAX_VALUE,
-M,O=n.controllerDirectives,K=n.newIsolateScopeDirective,I=n.templateDirective,ea=n.nonTlbTranscludeDirective,F=!1,E=!1,Ia=n.hasElementTranscludeDirective,x=d.$$element=A(c),H,z,V,S=e,R,Ha=0,sa=a.length;Ha<sa;Ha++){H=a[Ha];var U=H.$$start,Y=H.$$end;U&&(x=P(c,U,Y));V=u;if(y>H.priority)break;if(V=H.scope)M=M||H,H.templateUrl||(fb("new/isolated scope",K,H,x),T(V)&&(K=H));z=H.name;!H.templateUrl&&H.controller&&(V=H.controller,O=O||{},fb("'"+z+"' controller",O[z],H,x),O[z]=H);if(V=H.transclude)F=!0,H.$$tlb||
-(fb("transclusion",ea,H,x),ea=H),"element"==V?(Ia=!0,y=H.priority,V=x,x=d.$$element=A(X.createComment(" "+z+": "+d[z]+" ")),c=x[0],ra(f,wa.call(V,0),c),S=B(V,e,y,g&&g.name,{nonTlbTranscludeDirective:ea})):(V=A(Kb(c)).contents(),x.empty(),S=B(V,e));if(H.template)if(E=!0,fb("template",I,H,x),I=H,V=N(H.template)?H.template(x,d):H.template,V=W(V),H.replace){g=H;V=Ib.test(V)?A($(V)):[];c=V[0];if(1!=V.length||1!==c.nodeType)throw ja("tplrt",z,"");ra(f,x,c);sa={$attr:{}};V=ca(c,[],sa);var Z=a.splice(Ha+
-1,a.length-(Ha+1));K&&D(V);a=a.concat(V).concat(Z);v(d,sa);sa=a.length}else x.html(V);if(H.templateUrl)E=!0,fb("template",I,H,x),I=H,H.replace&&(g=H),J=te(a.splice(Ha,a.length-Ha),x,d,f,F&&S,k,q,{controllerDirectives:O,newIsolateScopeDirective:K,templateDirective:I,nonTlbTranscludeDirective:ea}),sa=a.length;else if(H.compile)try{R=H.compile(x,d,S),N(R)?w(null,R,U,Y):R&&w(R.pre,R.post,U,Y)}catch(ve){l(ve,ia(x))}H.terminal&&(J.terminal=!0,y=Math.max(y,H.priority))}J.scope=M&&!0===M.scope;J.transcludeOnThisElement=
-F;J.templateOnThisElement=E;J.transclude=S;n.hasElementTranscludeDirective=Ia;return J}function D(a){for(var b=0,c=a.length;b<c;b++)a[b]=$b(a[b],{$$isolateScope:!0})}function ea(b,e,f,g,p,m,n){if(e===p)return null;p=null;if(c.hasOwnProperty(e)){var q;e=a.get(e+d);for(var w=0,s=e.length;w<s;w++)try{q=e[w],(g===u||g>q.priority)&&-1!=q.restrict.indexOf(f)&&(m&&(q=$b(q,{$$start:m,$$end:n})),b.push(q),p=q)}catch(y){l(y)}}return p}function v(a,b){var c=b.$attr,d=a.$attr,e=a.$$element;r(a,function(d,e){"$"!=
-e.charAt(0)&&(b[e]&&b[e]!==d&&(d+=("style"===e?";":" ")+b[e]),a.$set(e,d,!0,c[e]))});r(b,function(b,f){"class"==f?(ba(e,b),a["class"]=(a["class"]?a["class"]+" ":"")+b):"style"==f?(e.attr("style",e.attr("style")+";"+b),a.style=(a.style?a.style+";":"")+b):"$"==f.charAt(0)||a.hasOwnProperty(f)||(a[f]=b,d[f]=c[f])})}function te(a,b,c,d,e,f,g,k){var p=[],l,m,w=b[0],s=a.shift(),y=E({},s,{templateUrl:null,transclude:null,replace:null,$$originalDirective:s}),J=N(s.templateUrl)?s.templateUrl(b,c):s.templateUrl;
-b.empty();n.get(t.getTrustedResourceUrl(J),{cache:q}).success(function(q){var n,t;q=W(q);if(s.replace){q=Ib.test(q)?A($(q)):[];n=q[0];if(1!=q.length||1!==n.nodeType)throw ja("tplrt",s.name,J);q={$attr:{}};ra(d,b,n);var B=ca(n,[],q);T(s.scope)&&D(B);a=B.concat(a);v(c,q)}else n=w,b.html(q);a.unshift(y);l=I(a,n,c,e,b,s,f,g,k);r(d,function(a,c){a==n&&(d[c]=b[0])});for(m=O(b[0].childNodes,e);p.length;){q=p.shift();t=p.shift();var K=p.shift(),C=p.shift(),B=b[0];if(t!==w){var P=t.className;k.hasElementTranscludeDirective&&
-s.replace||(B=Kb(n));ra(K,A(t),B);ba(A(B),P)}t=l.transcludeOnThisElement?M(q,l.transclude,C):C;l(m,q,B,d,t)}p=null}).error(function(a,b,c,d){throw ja("tpload",d.url);});return function(a,b,c,d,e){a=e;p?(p.push(b),p.push(c),p.push(d),p.push(a)):(l.transcludeOnThisElement&&(a=M(b,l.transclude,e)),l(m,b,c,d,a))}}function F(a,b){var c=b.priority-a.priority;return 0!==c?c:a.name!==b.name?a.name<b.name?-1:1:a.index-b.index}function fb(a,b,c,d){if(b)throw ja("multidir",b.name,c.name,a,ia(d));}function x(a,
-c){var d=b(c,!0);d&&a.push({priority:0,compile:function(a){var b=a.parent().length;b&&ba(a.parent(),"ng-binding");return function(a,c){var e=c.parent(),f=e.data("$binding")||[];f.push(d);e.data("$binding",f);b||ba(e,"ng-binding");a.$watch(d,function(a){c[0].nodeValue=a})}}})}function z(a,b){if("srcdoc"==b)return t.HTML;var c=Pa(a);if("xlinkHref"==b||"FORM"==c&&"action"==b||"IMG"!=c&&("src"==b||"ngSrc"==b))return t.RESOURCE_URL}function S(a,c,d,e){var f=b(d,!0);if(f){if("multiple"===e&&"SELECT"===
-Pa(a))throw ja("selmulti",ia(a));c.push({priority:100,compile:function(){return{pre:function(c,d,k){d=k.$$observers||(k.$$observers={});if(g.test(e))throw ja("nodomevents");if(f=b(k[e],!0,z(a,e)))k[e]=f(c),(d[e]||(d[e]=[])).$$inter=!0,(k.$$observers&&k.$$observers[e].$$scope||c).$watch(f,function(a,b){"class"===e&&a!=b?k.$updateClass(a,b):k.$set(e,a)})}}}})}}function ra(a,b,c){var d=b[0],e=b.length,f=d.parentNode,g,k;if(a)for(g=0,k=a.length;g<k;g++)if(a[g]==d){a[g++]=c;k=g+e-1;for(var p=a.length;g<
-p;g++,k++)k<p?a[g]=a[k]:delete a[g];a.length-=e-1;break}f&&f.replaceChild(c,d);a=X.createDocumentFragment();a.appendChild(d);c[A.expando]=d[A.expando];d=1;for(e=b.length;d<e;d++)f=b[d],A(f).remove(),a.appendChild(f),delete b[d];b[0]=c;b.length=1}function rc(a,b){return E(function(){return a.apply(null,arguments)},a,b)}var Ob=function(a,b){this.$$element=a;this.$attr=b||{}};Ob.prototype={$normalize:qa,$addClass:function(a){a&&0<a.length&&y.addClass(this.$$element,a)},$removeClass:function(a){a&&0<
-a.length&&y.removeClass(this.$$element,a)},$updateClass:function(a,b){var c=sc(a,b),d=sc(b,a);0===c.length?y.removeClass(this.$$element,d):0===d.length?y.addClass(this.$$element,c):y.setClass(this.$$element,c,d)},$set:function(a,b,c,d){var e=oc(this.$$element[0],a);e&&(this.$$element.prop(a,b),d=e);this[a]=b;d?this.$attr[a]=d:(d=this.$attr[a])||(this.$attr[a]=d=nb(a,"-"));e=Pa(this.$$element);if("A"===e&&"href"===a||"IMG"===e&&"src"===a)this[a]=b=K(b,"src"===a);!1!==c&&(null===b||b===u?this.$$element.removeAttr(d):
-this.$$element.attr(d,b));(c=this.$$observers)&&r(c[a],function(a){try{a(b)}catch(c){l(c)}})},$observe:function(a,b){var c=this,d=c.$$observers||(c.$$observers={}),e=d[a]||(d[a]=[]);e.push(b);J.$evalAsync(function(){e.$$inter||b(c[a])});return b}};var sa=b.startSymbol(),Ia=b.endSymbol(),W="{{"==sa||"}}"==Ia?ga:function(a){return a.replace(/\{\{/g,sa).replace(/}}/g,Ia)},U=/^ngAttr[A-Z]/;return B}]}function qa(b){return ab(b.replace(we,""))}function sc(b,a){var c="",d=b.split(/\s+/),e=a.split(/\s+/),
-f=0;a:for(;f<d.length;f++){for(var g=d[f],h=0;h<e.length;h++)if(g==e[h])continue a;c+=(0<c.length?" ":"")+g}return c}function Od(){var b={},a=/^(\S+)(\s+as\s+(\w+))?$/;this.register=function(a,d){Ea(a,"controller");T(a)?E(b,a):b[a]=d};this.$get=["$injector","$window",function(c,d){return function(e,f){var g,h,k;G(e)&&(g=e.match(a),h=g[1],k=g[3],e=b.hasOwnProperty(h)?b[h]:fc(f.$scope,h,!0)||fc(d,h,!0),Ya(e,h,!0));g=c.instantiate(e,f);if(k){if(!f||"object"!==typeof f.$scope)throw z("$controller")("noscp",
-h||e.name,k);f.$scope[k]=g}return g}}]}function Pd(){this.$get=["$window",function(b){return A(b.document)}]}function Qd(){this.$get=["$log",function(b){return function(a,c){b.error.apply(b,arguments)}}]}function tc(b){var a={},c,d,e;if(!b)return a;r(b.split("\n"),function(b){e=b.indexOf(":");c=x($(b.substr(0,e)));d=$(b.substr(e+1));c&&(a[c]=a[c]?a[c]+", "+d:d)});return a}function uc(b){var a=T(b)?b:u;return function(c){a||(a=tc(b));return c?a[x(c)]||null:a}}function vc(b,a,c){if(N(c))return c(b,
-a);r(c,function(c){b=c(b,a)});return b}function Td(){var b=/^\s*(\[|\{[^\{])/,a=/[\}\]]\s*$/,c=/^\)\]\}',?\n/,d={"Content-Type":"application/json;charset=utf-8"},e=this.defaults={transformResponse:[function(d){G(d)&&(d=d.replace(c,""),b.test(d)&&a.test(d)&&(d=ac(d)));return d}],transformRequest:[function(a){return T(a)&&"[object File]"!==Ba.call(a)&&"[object Blob]"!==Ba.call(a)?oa(a):a}],headers:{common:{Accept:"application/json, text/plain, */*"},post:ha(d),put:ha(d),patch:ha(d)},xsrfCookieName:"XSRF-TOKEN",
-xsrfHeaderName:"X-XSRF-TOKEN"},f=this.interceptors=[],g=this.responseInterceptors=[];this.$get=["$httpBackend","$browser","$cacheFactory","$rootScope","$q","$injector",function(a,b,c,d,n,q){function p(a){function b(a){var d=E({},a,{data:vc(a.data,a.headers,c.transformResponse)});return 200<=a.status&&300>a.status?d:n.reject(d)}var c={method:"get",transformRequest:e.transformRequest,transformResponse:e.transformResponse},d=function(a){var b=e.headers,c=E({},a.headers),d,f,b=E({},b.common,b[x(a.method)]);
-a:for(d in b){a=x(d);for(f in c)if(x(f)===a)continue a;c[d]=b[d]}(function(a){var b;r(a,function(c,d){N(c)&&(b=c(),null!=b?a[d]=b:delete a[d])})})(c);return c}(a);E(c,a);c.headers=d;c.method=La(c.method);var f=[function(a){d=a.headers;var c=vc(a.data,uc(d),a.transformRequest);F(c)&&r(d,function(a,b){"content-type"===x(b)&&delete d[b]});F(a.withCredentials)&&!F(e.withCredentials)&&(a.withCredentials=e.withCredentials);return s(a,c,d).then(b,b)},u],g=n.when(c);for(r(t,function(a){(a.request||a.requestError)&&
-f.unshift(a.request,a.requestError);(a.response||a.responseError)&&f.push(a.response,a.responseError)});f.length;){a=f.shift();var h=f.shift(),g=g.then(a,h)}g.success=function(a){g.then(function(b){a(b.data,b.status,b.headers,c)});return g};g.error=function(a){g.then(null,function(b){a(b.data,b.status,b.headers,c)});return g};return g}function s(c,f,g){function m(a,b,c,e){C&&(200<=a&&300>a?C.put(A,[a,b,tc(c),e]):C.remove(A));q(b,a,c,e);d.$$phase||d.$apply()}function q(a,b,d,e){b=Math.max(b,0);(200<=
-b&&300>b?t.resolve:t.reject)({data:a,status:b,headers:uc(d),config:c,statusText:e})}function s(){var a=Ta(p.pendingRequests,c);-1!==a&&p.pendingRequests.splice(a,1)}var t=n.defer(),r=t.promise,C,I,A=J(c.url,c.params);p.pendingRequests.push(c);r.then(s,s);!c.cache&&!e.cache||(!1===c.cache||"GET"!==c.method&&"JSONP"!==c.method)||(C=T(c.cache)?c.cache:T(e.cache)?e.cache:w);if(C)if(I=C.get(A),D(I)){if(I&&N(I.then))return I.then(s,s),I;L(I)?q(I[1],I[0],ha(I[2]),I[3]):q(I,200,{},"OK")}else C.put(A,r);F(I)&&
-((I=Pb(c.url)?b.cookies()[c.xsrfCookieName||e.xsrfCookieName]:u)&&(g[c.xsrfHeaderName||e.xsrfHeaderName]=I),a(c.method,A,f,m,g,c.timeout,c.withCredentials,c.responseType));return r}function J(a,b){if(!b)return a;var c=[];Sc(b,function(a,b){null===a||F(a)||(L(a)||(a=[a]),r(a,function(a){T(a)&&(a=va(a)?a.toISOString():oa(a));c.push(Da(b)+"="+Da(a))}))});0<c.length&&(a+=(-1==a.indexOf("?")?"?":"&")+c.join("&"));return a}var w=c("$http"),t=[];r(f,function(a){t.unshift(G(a)?q.get(a):q.invoke(a))});r(g,
-function(a,b){var c=G(a)?q.get(a):q.invoke(a);t.splice(b,0,{response:function(a){return c(n.when(a))},responseError:function(a){return c(n.reject(a))}})});p.pendingRequests=[];(function(a){r(arguments,function(a){p[a]=function(b,c){return p(E(c||{},{method:a,url:b}))}})})("get","delete","head","jsonp");(function(a){r(arguments,function(a){p[a]=function(b,c,d){return p(E(d||{},{method:a,url:b,data:c}))}})})("post","put","patch");p.defaults=e;return p}]}function xe(b){if(8>=R&&(!b.match(/^(get|post|head|put|delete|options)$/i)||
-!W.XMLHttpRequest))return new W.ActiveXObject("Microsoft.XMLHTTP");if(W.XMLHttpRequest)return new W.XMLHttpRequest;throw z("$httpBackend")("noxhr");}function Ud(){this.$get=["$browser","$window","$document",function(b,a,c){return ye(b,xe,b.defer,a.angular.callbacks,c[0])}]}function ye(b,a,c,d,e){function f(a,b,c){var f=e.createElement("script"),g=null;f.type="text/javascript";f.src=a;f.async=!0;g=function(a){bb(f,"load",g);bb(f,"error",g);e.body.removeChild(f);f=null;var h=-1,s="unknown";a&&("load"!==
-a.type||d[b].called||(a={type:"error"}),s=a.type,h="error"===a.type?404:200);c&&c(h,s)};sb(f,"load",g);sb(f,"error",g);8>=R&&(f.onreadystatechange=function(){G(f.readyState)&&/loaded|complete/.test(f.readyState)&&(f.onreadystatechange=null,g({type:"load"}))});e.body.appendChild(f);return g}var g=-1;return function(e,k,m,l,n,q,p,s){function J(){t=g;K&&K();B&&B.abort()}function w(a,d,e,f,g){O&&c.cancel(O);K=B=null;0===d&&(d=e?200:"file"==xa(k).protocol?404:0);a(1223===d?204:d,e,f,g||"");b.$$completeOutstandingRequest(v)}
-var t;b.$$incOutstandingRequestCount();k=k||b.url();if("jsonp"==x(e)){var y="_"+(d.counter++).toString(36);d[y]=function(a){d[y].data=a;d[y].called=!0};var K=f(k.replace("JSON_CALLBACK","angular.callbacks."+y),y,function(a,b){w(l,a,d[y].data,"",b);d[y]=v})}else{var B=a(e);B.open(e,k,!0);r(n,function(a,b){D(a)&&B.setRequestHeader(b,a)});B.onreadystatechange=function(){if(B&&4==B.readyState){var a=null,b=null,c="";t!==g&&(a=B.getAllResponseHeaders(),b="response"in B?B.response:B.responseText);t===g&&
-10>R||(c=B.statusText);w(l,t||B.status,b,a,c)}};p&&(B.withCredentials=!0);if(s)try{B.responseType=s}catch(ba){if("json"!==s)throw ba;}B.send(m||null)}if(0<q)var O=c(J,q);else q&&N(q.then)&&q.then(J)}}function Rd(){var b="{{",a="}}";this.startSymbol=function(a){return a?(b=a,this):b};this.endSymbol=function(b){return b?(a=b,this):a};this.$get=["$parse","$exceptionHandler","$sce",function(c,d,e){function f(f,m,l){for(var n,q,p=0,s=[],J=f.length,w=!1,t=[];p<J;)-1!=(n=f.indexOf(b,p))&&-1!=(q=f.indexOf(a,
-n+g))?(p!=n&&s.push(f.substring(p,n)),s.push(p=c(w=f.substring(n+g,q))),p.exp=w,p=q+h,w=!0):(p!=J&&s.push(f.substring(p)),p=J);(J=s.length)||(s.push(""),J=1);if(l&&1<s.length)throw wc("noconcat",f);if(!m||w)return t.length=J,p=function(a){try{for(var b=0,c=J,g;b<c;b++){if("function"==typeof(g=s[b]))if(g=g(a),g=l?e.getTrusted(l,g):e.valueOf(g),null==g)g="";else switch(typeof g){case "string":break;case "number":g=""+g;break;default:g=oa(g)}t[b]=g}return t.join("")}catch(h){a=wc("interr",f,h.toString()),
-d(a)}},p.exp=f,p.parts=s,p}var g=b.length,h=a.length;f.startSymbol=function(){return b};f.endSymbol=function(){return a};return f}]}function Sd(){this.$get=["$rootScope","$window","$q",function(b,a,c){function d(d,g,h,k){var m=a.setInterval,l=a.clearInterval,n=c.defer(),q=n.promise,p=0,s=D(k)&&!k;h=D(h)?h:0;q.then(null,null,d);q.$$intervalId=m(function(){n.notify(p++);0<h&&p>=h&&(n.resolve(p),l(q.$$intervalId),delete e[q.$$intervalId]);s||b.$apply()},g);e[q.$$intervalId]=n;return q}var e={};d.cancel=
-function(b){return b&&b.$$intervalId in e?(e[b.$$intervalId].reject("canceled"),a.clearInterval(b.$$intervalId),delete e[b.$$intervalId],!0):!1};return d}]}function ad(){this.$get=function(){return{id:"en-us",NUMBER_FORMATS:{DECIMAL_SEP:".",GROUP_SEP:",",PATTERNS:[{minInt:1,minFrac:0,maxFrac:3,posPre:"",posSuf:"",negPre:"-",negSuf:"",gSize:3,lgSize:3},{minInt:1,minFrac:2,maxFrac:2,posPre:"\u00a4",posSuf:"",negPre:"(\u00a4",negSuf:")",gSize:3,lgSize:3}],CURRENCY_SYM:"$"},DATETIME_FORMATS:{MONTH:"January February March April May June July August September October November December".split(" "),
-SHORTMONTH:"Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec".split(" "),DAY:"Sunday Monday Tuesday Wednesday Thursday Friday Saturday".split(" "),SHORTDAY:"Sun Mon Tue Wed Thu Fri Sat".split(" "),AMPMS:["AM","PM"],medium:"MMM d, y h:mm:ss a","short":"M/d/yy h:mm a",fullDate:"EEEE, MMMM d, y",longDate:"MMMM d, y",mediumDate:"MMM d, y",shortDate:"M/d/yy",mediumTime:"h:mm:ss a",shortTime:"h:mm a"},pluralCat:function(b){return 1===b?"one":"other"}}}}function Qb(b){b=b.split("/");for(var a=b.length;a--;)b[a]=
-mb(b[a]);return b.join("/")}function xc(b,a,c){b=xa(b,c);a.$$protocol=b.protocol;a.$$host=b.hostname;a.$$port=U(b.port)||ze[b.protocol]||null}function yc(b,a,c){var d="/"!==b.charAt(0);d&&(b="/"+b);b=xa(b,c);a.$$path=decodeURIComponent(d&&"/"===b.pathname.charAt(0)?b.pathname.substring(1):b.pathname);a.$$search=cc(b.search);a.$$hash=decodeURIComponent(b.hash);a.$$path&&"/"!=a.$$path.charAt(0)&&(a.$$path="/"+a.$$path)}function ta(b,a){if(0===a.indexOf(b))return a.substr(b.length)}function Ga(b){var a=
-b.indexOf("#");return-1==a?b:b.substr(0,a)}function Rb(b){return b.substr(0,Ga(b).lastIndexOf("/")+1)}function zc(b,a){this.$$html5=!0;a=a||"";var c=Rb(b);xc(b,this,b);this.$$parse=function(a){var e=ta(c,a);if(!G(e))throw Sb("ipthprfx",a,c);yc(e,this,b);this.$$path||(this.$$path="/");this.$$compose()};this.$$compose=function(){var a=Cb(this.$$search),b=this.$$hash?"#"+mb(this.$$hash):"";this.$$url=Qb(this.$$path)+(a?"?"+a:"")+b;this.$$absUrl=c+this.$$url.substr(1)};this.$$parseLinkUrl=function(d,
-e){var f,g;(f=ta(b,d))!==u?(g=f,g=(f=ta(a,f))!==u?c+(ta("/",f)||f):b+g):(f=ta(c,d))!==u?g=c+f:c==d+"/"&&(g=c);g&&this.$$parse(g);return!!g}}function Tb(b,a){var c=Rb(b);xc(b,this,b);this.$$parse=function(d){var e=ta(b,d)||ta(c,d),e="#"==e.charAt(0)?ta(a,e):this.$$html5?e:"";if(!G(e))throw Sb("ihshprfx",d,a);yc(e,this,b);d=this.$$path;var f=/^\/[A-Z]:(\/.*)/;0===e.indexOf(b)&&(e=e.replace(b,""));f.exec(e)||(d=(e=f.exec(d))?e[1]:d);this.$$path=d;this.$$compose()};this.$$compose=function(){var c=Cb(this.$$search),
-e=this.$$hash?"#"+mb(this.$$hash):"";this.$$url=Qb(this.$$path)+(c?"?"+c:"")+e;this.$$absUrl=b+(this.$$url?a+this.$$url:"")};this.$$parseLinkUrl=function(a,c){return Ga(b)==Ga(a)?(this.$$parse(a),!0):!1}}function Ac(b,a){this.$$html5=!0;Tb.apply(this,arguments);var c=Rb(b);this.$$parseLinkUrl=function(d,e){var f,g;b==Ga(d)?f=d:(g=ta(c,d))?f=b+a+g:c===d+"/"&&(f=c);f&&this.$$parse(f);return!!f};this.$$compose=function(){var c=Cb(this.$$search),e=this.$$hash?"#"+mb(this.$$hash):"";this.$$url=Qb(this.$$path)+
-(c?"?"+c:"")+e;this.$$absUrl=b+a+this.$$url}}function tb(b){return function(){return this[b]}}function Bc(b,a){return function(c){if(F(c))return this[b];this[b]=a(c);this.$$compose();return this}}function Vd(){var b="",a=!1;this.hashPrefix=function(a){return D(a)?(b=a,this):b};this.html5Mode=function(b){return D(b)?(a=b,this):a};this.$get=["$rootScope","$browser","$sniffer","$rootElement",function(c,d,e,f){function g(a){c.$broadcast("$locationChangeSuccess",h.absUrl(),a)}var h,k=d.baseHref(),m=d.url();
-a?(k=m.substring(0,m.indexOf("/",m.indexOf("//")+2))+(k||"/"),e=e.history?zc:Ac):(k=Ga(m),e=Tb);h=new e(k,"#"+b);h.$$parseLinkUrl(m,m);var l=/^\s*(javascript|mailto):/i;f.on("click",function(a){if(!a.ctrlKey&&!a.metaKey&&2!=a.which){for(var b=A(a.target);"a"!==x(b[0].nodeName);)if(b[0]===f[0]||!(b=b.parent())[0])return;var e=b.prop("href"),g=b.attr("href")||b.attr("xlink:href");T(e)&&"[object SVGAnimatedString]"===e.toString()&&(e=xa(e.animVal).href);l.test(e)||(!e||(b.attr("target")||a.isDefaultPrevented())||
-!h.$$parseLinkUrl(e,g))||(a.preventDefault(),h.absUrl()!=d.url()&&(c.$apply(),W.angular["ff-684208-preventDefault"]=!0))}});h.absUrl()!=m&&d.url(h.absUrl(),!0);d.onUrlChange(function(a){h.absUrl()!=a&&(c.$evalAsync(function(){var b=h.absUrl();h.$$parse(a);c.$broadcast("$locationChangeStart",a,b).defaultPrevented?(h.$$parse(b),d.url(b)):g(b)}),c.$$phase||c.$digest())});var n=0;c.$watch(function(){var a=d.url(),b=h.$$replace;n&&a==h.absUrl()||(n++,c.$evalAsync(function(){c.$broadcast("$locationChangeStart",
-h.absUrl(),a).defaultPrevented?h.$$parse(a):(d.url(h.absUrl(),b),g(a))}));h.$$replace=!1;return n});return h}]}function Wd(){var b=!0,a=this;this.debugEnabled=function(a){return D(a)?(b=a,this):b};this.$get=["$window",function(c){function d(a){a instanceof Error&&(a.stack?a=a.message&&-1===a.stack.indexOf(a.message)?"Error: "+a.message+"\n"+a.stack:a.stack:a.sourceURL&&(a=a.message+"\n"+a.sourceURL+":"+a.line));return a}function e(a){var b=c.console||{},e=b[a]||b.log||v;a=!1;try{a=!!e.apply}catch(k){}return a?
-function(){var a=[];r(arguments,function(b){a.push(d(b))});return e.apply(b,a)}:function(a,b){e(a,null==b?"":b)}}return{log:e("log"),info:e("info"),warn:e("warn"),error:e("error"),debug:function(){var c=e("debug");return function(){b&&c.apply(a,arguments)}}()}}]}function ka(b,a){if("__defineGetter__"===b||"__defineSetter__"===b||"__lookupGetter__"===b||"__lookupSetter__"===b||"__proto__"===b)throw la("isecfld",a);return b}function ma(b,a){if(b){if(b.constructor===b)throw la("isecfn",a);if(b.document&&
-b.location&&b.alert&&b.setInterval)throw la("isecwindow",a);if(b.children&&(b.nodeName||b.prop&&b.attr&&b.find))throw la("isecdom",a);if(b===Object)throw la("isecobj",a);}return b}function ub(b,a,c,d,e){ma(b,d);e=e||{};a=a.split(".");for(var f,g=0;1<a.length;g++){f=ka(a.shift(),d);var h=ma(b[f],d);h||(h={},b[f]=h);b=h;b.then&&e.unwrapPromises&&(ya(d),"$$v"in b||function(a){a.then(function(b){a.$$v=b})}(b),b.$$v===u&&(b.$$v={}),b=b.$$v)}f=ka(a.shift(),d);ma(b[f],d);return b[f]=c}function Qa(b){return"constructor"==
-b}function Cc(b,a,c,d,e,f,g){ka(b,f);ka(a,f);ka(c,f);ka(d,f);ka(e,f);var h=function(a){return ma(a,f)},k=g.expensiveChecks,m=k||Qa(b)?h:ga,l=k||Qa(a)?h:ga,n=k||Qa(c)?h:ga,q=k||Qa(d)?h:ga,p=k||Qa(e)?h:ga;return g.unwrapPromises?function(g,h){var k=h&&h.hasOwnProperty(b)?h:g,t;if(null==k)return k;(k=m(k[b]))&&k.then&&(ya(f),"$$v"in k||(t=k,t.$$v=u,t.then(function(a){t.$$v=m(a)})),k=m(k.$$v));if(!a)return k;if(null==k)return u;(k=l(k[a]))&&k.then&&(ya(f),"$$v"in k||(t=k,t.$$v=u,t.then(function(a){t.$$v=
-l(a)})),k=l(k.$$v));if(!c)return k;if(null==k)return u;(k=n(k[c]))&&k.then&&(ya(f),"$$v"in k||(t=k,t.$$v=u,t.then(function(a){t.$$v=n(a)})),k=n(k.$$v));if(!d)return k;if(null==k)return u;(k=q(k[d]))&&k.then&&(ya(f),"$$v"in k||(t=k,t.$$v=u,t.then(function(a){t.$$v=q(a)})),k=q(k.$$v));if(!e)return k;if(null==k)return u;(k=p(k[e]))&&k.then&&(ya(f),"$$v"in k||(t=k,t.$$v=u,t.then(function(a){t.$$v=p(a)})),k=p(k.$$v));return k}:function(f,g){var h=g&&g.hasOwnProperty(b)?g:f;if(null==h)return h;h=m(h[b]);
-if(!a)return h;if(null==h)return u;h=l(h[a]);if(!c)return h;if(null==h)return u;h=n(h[c]);if(!d)return h;if(null==h)return u;h=q(h[d]);return e?null==h?u:h=p(h[e]):h}}function Ae(b,a){return function(c,d){return b(c,d,ya,ma,a)}}function Dc(b,a,c){var d=a.expensiveChecks,e=d?Be:Ce;if(e.hasOwnProperty(b))return e[b];var f=b.split("."),g=f.length,h;if(a.csp)h=6>g?Cc(f[0],f[1],f[2],f[3],f[4],c,a):function(b,d){var e=0,h;do h=Cc(f[e++],f[e++],f[e++],f[e++],f[e++],c,a)(b,d),d=u,b=h;while(e<g);return h};
-else{var k="var p;\n";d&&(k+="s = eso(s, fe);\nl = eso(l, fe);\n");var m=d;r(f,function(b,e){ka(b,c);var f=(e?"s":'((l&&l.hasOwnProperty("'+b+'"))?l:s)')+'["'+b+'"]',g=d||Qa(b);g&&(f="eso("+f+", fe)",m=!0);k+="if(s == null) return undefined;\ns="+f+";\n";a.unwrapPromises&&(k+='if (s && s.then) {\n pw("'+c.replace(/(["\r\n])/g,"\\$1")+'");\n if (!("$$v" in s)) {\n p=s;\n p.$$v = undefined;\n p.then(function(v) {p.$$v='+(g?"eso(v)":"v")+";});\n}\n s="+(g?"eso(s.$$v)":"s.$$v")+"\n}\n")});k+="return s;";
-h=new Function("s","l","pw","eso","fe",k);h.toString=aa(k);if(m||a.unwrapPromises)h=Ae(h,c)}"hasOwnProperty"!==b&&(e[b]=h);return h}function Xd(){var b={},a={},c={csp:!1,unwrapPromises:!1,logPromiseWarnings:!0,expensiveChecks:!1};this.unwrapPromises=function(a){return D(a)?(c.unwrapPromises=!!a,this):c.unwrapPromises};this.logPromiseWarnings=function(a){return D(a)?(c.logPromiseWarnings=a,this):c.logPromiseWarnings};this.$get=["$filter","$sniffer","$log",function(d,e,f){c.csp=e.csp;var g={csp:c.csp,
-unwrapPromises:c.unwrapPromises,logPromiseWarnings:c.logPromiseWarnings,expensiveChecks:!0};ya=function(a){c.logPromiseWarnings&&!Ec.hasOwnProperty(a)&&(Ec[a]=!0,f.warn("[$parse] Promise found in the expression `"+a+"`. Automatic unwrapping of promises in Angular expressions is deprecated."))};return function(e,f){var m;switch(typeof e){case "string":var l=f?a:b;if(l.hasOwnProperty(e))return l[e];m=f?g:c;var n=new Ub(m);m=(new gb(n,d,m)).parse(e);"hasOwnProperty"!==e&&(l[e]=m);return m;case "function":return e;
-default:return v}}}]}function Zd(){this.$get=["$rootScope","$exceptionHandler",function(b,a){return De(function(a){b.$evalAsync(a)},a)}]}function De(b,a){function c(a){return a}function d(a){return g(a)}var e=function(){var g=[],m,l;return l={resolve:function(a){if(g){var c=g;g=u;m=f(a);c.length&&b(function(){for(var a,b=0,d=c.length;b<d;b++)a=c[b],m.then(a[0],a[1],a[2])})}},reject:function(a){l.resolve(h(a))},notify:function(a){if(g){var c=g;g.length&&b(function(){for(var b,d=0,e=c.length;d<e;d++)b=
-c[d],b[2](a)})}},promise:{then:function(b,f,h){var l=e(),J=function(d){try{l.resolve((N(b)?b:c)(d))}catch(e){l.reject(e),a(e)}},w=function(b){try{l.resolve((N(f)?f:d)(b))}catch(c){l.reject(c),a(c)}},t=function(b){try{l.notify((N(h)?h:c)(b))}catch(d){a(d)}};g?g.push([J,w,t]):m.then(J,w,t);return l.promise},"catch":function(a){return this.then(null,a)},"finally":function(a){function b(a,c){var d=e();c?d.resolve(a):d.reject(a);return d.promise}function d(e,f){var g=null;try{g=(a||c)()}catch(h){return b(h,
-!1)}return g&&N(g.then)?g.then(function(){return b(e,f)},function(a){return b(a,!1)}):b(e,f)}return this.then(function(a){return d(a,!0)},function(a){return d(a,!1)})}}}},f=function(a){return a&&N(a.then)?a:{then:function(c){var d=e();b(function(){d.resolve(c(a))});return d.promise}}},g=function(a){var b=e();b.reject(a);return b.promise},h=function(c){return{then:function(f,g){var h=e();b(function(){try{h.resolve((N(g)?g:d)(c))}catch(b){h.reject(b),a(b)}});return h.promise}}};return{defer:e,reject:g,
-when:function(h,m,l,n){var q=e(),p,s=function(b){try{return(N(m)?m:c)(b)}catch(d){return a(d),g(d)}},J=function(b){try{return(N(l)?l:d)(b)}catch(c){return a(c),g(c)}},w=function(b){try{return(N(n)?n:c)(b)}catch(d){a(d)}};b(function(){f(h).then(function(a){p||(p=!0,q.resolve(f(a).then(s,J,w)))},function(a){p||(p=!0,q.resolve(J(a)))},function(a){p||q.notify(w(a))})});return q.promise},all:function(a){var b=e(),c=0,d=L(a)?[]:{};r(a,function(a,e){c++;f(a).then(function(a){d.hasOwnProperty(e)||(d[e]=a,
---c||b.resolve(d))},function(a){d.hasOwnProperty(e)||b.reject(a)})});0===c&&b.resolve(d);return b.promise}}}function fe(){this.$get=["$window","$timeout",function(b,a){var c=b.requestAnimationFrame||b.webkitRequestAnimationFrame||b.mozRequestAnimationFrame,d=b.cancelAnimationFrame||b.webkitCancelAnimationFrame||b.mozCancelAnimationFrame||b.webkitCancelRequestAnimationFrame,e=!!c,f=e?function(a){var b=c(a);return function(){d(b)}}:function(b){var c=a(b,16.66,!1);return function(){a.cancel(c)}};f.supported=
-e;return f}]}function Yd(){var b=10,a=z("$rootScope"),c=null;this.digestTtl=function(a){arguments.length&&(b=a);return b};this.$get=["$injector","$exceptionHandler","$parse","$browser",function(d,e,f,g){function h(){this.$id=ib();this.$$phase=this.$parent=this.$$watchers=this.$$nextSibling=this.$$prevSibling=this.$$childHead=this.$$childTail=null;this["this"]=this.$root=this;this.$$destroyed=!1;this.$$asyncQueue=[];this.$$postDigestQueue=[];this.$$listeners={};this.$$listenerCount={};this.$$isolateBindings=
-{}}function k(b){if(q.$$phase)throw a("inprog",q.$$phase);q.$$phase=b}function m(a,b){var c=f(a);Ya(c,b);return c}function l(a,b,c){do a.$$listenerCount[c]-=b,0===a.$$listenerCount[c]&&delete a.$$listenerCount[c];while(a=a.$parent)}function n(){}h.prototype={constructor:h,$new:function(a){a?(a=new h,a.$root=this.$root,a.$$asyncQueue=this.$$asyncQueue,a.$$postDigestQueue=this.$$postDigestQueue):(this.$$childScopeClass||(this.$$childScopeClass=function(){this.$$watchers=this.$$nextSibling=this.$$childHead=
-this.$$childTail=null;this.$$listeners={};this.$$listenerCount={};this.$id=ib();this.$$childScopeClass=null},this.$$childScopeClass.prototype=this),a=new this.$$childScopeClass);a["this"]=a;a.$parent=this;a.$$prevSibling=this.$$childTail;this.$$childHead?this.$$childTail=this.$$childTail.$$nextSibling=a:this.$$childHead=this.$$childTail=a;return a},$watch:function(a,b,d){var e=m(a,"watch"),f=this.$$watchers,g={fn:b,last:n,get:e,exp:a,eq:!!d};c=null;if(!N(b)){var h=m(b||v,"listener");g.fn=function(a,
-b,c){h(c)}}if("string"==typeof a&&e.constant){var k=g.fn;g.fn=function(a,b,c){k.call(this,a,b,c);Ua(f,g)}}f||(f=this.$$watchers=[]);f.unshift(g);return function(){Ua(f,g);c=null}},$watchCollection:function(a,b){var c=this,d,e,g,h=1<b.length,k=0,l=f(a),m=[],n={},q=!0,r=0;return this.$watch(function(){d=l(c);var a,b,f;if(T(d))if(Sa(d))for(e!==m&&(e=m,r=e.length=0,k++),a=d.length,r!==a&&(k++,e.length=r=a),b=0;b<a;b++)f=e[b]!==e[b]&&d[b]!==d[b],f||e[b]===d[b]||(k++,e[b]=d[b]);else{e!==n&&(e=n={},r=0,
-k++);a=0;for(b in d)d.hasOwnProperty(b)&&(a++,e.hasOwnProperty(b)?(f=e[b]!==e[b]&&d[b]!==d[b],f||e[b]===d[b]||(k++,e[b]=d[b])):(r++,e[b]=d[b],k++));if(r>a)for(b in k++,e)e.hasOwnProperty(b)&&!d.hasOwnProperty(b)&&(r--,delete e[b])}else e!==d&&(e=d,k++);return k},function(){q?(q=!1,b(d,d,c)):b(d,g,c);if(h)if(T(d))if(Sa(d)){g=Array(d.length);for(var a=0;a<d.length;a++)g[a]=d[a]}else for(a in g={},d)lb.call(d,a)&&(g[a]=d[a]);else g=d})},$digest:function(){var d,f,h,l,m=this.$$asyncQueue,r=this.$$postDigestQueue,
-K,B,u=b,O,M=[],A,P,C;k("$digest");g.$$checkUrlChange();c=null;do{B=!1;for(O=this;m.length;){try{C=m.shift(),C.scope.$eval(C.expression)}catch(I){q.$$phase=null,e(I)}c=null}a:do{if(l=O.$$watchers)for(K=l.length;K--;)try{if(d=l[K])if((f=d.get(O))!==(h=d.last)&&!(d.eq?Ca(f,h):"number"===typeof f&&"number"===typeof h&&isNaN(f)&&isNaN(h)))B=!0,c=d,d.last=d.eq?Ka(f,null):f,d.fn(f,h===n?f:h,O),5>u&&(A=4-u,M[A]||(M[A]=[]),P=N(d.exp)?"fn: "+(d.exp.name||d.exp.toString()):d.exp,P+="; newVal: "+oa(f)+"; oldVal: "+
-oa(h),M[A].push(P));else if(d===c){B=!1;break a}}catch(D){q.$$phase=null,e(D)}if(!(l=O.$$childHead||O!==this&&O.$$nextSibling))for(;O!==this&&!(l=O.$$nextSibling);)O=O.$parent}while(O=l);if((B||m.length)&&!u--)throw q.$$phase=null,a("infdig",b,oa(M));}while(B||m.length);for(q.$$phase=null;r.length;)try{r.shift()()}catch(x){e(x)}},$destroy:function(){if(!this.$$destroyed){var a=this.$parent;this.$broadcast("$destroy");this.$$destroyed=!0;this!==q&&(r(this.$$listenerCount,Bb(null,l,this)),a.$$childHead==
-this&&(a.$$childHead=this.$$nextSibling),a.$$childTail==this&&(a.$$childTail=this.$$prevSibling),this.$$prevSibling&&(this.$$prevSibling.$$nextSibling=this.$$nextSibling),this.$$nextSibling&&(this.$$nextSibling.$$prevSibling=this.$$prevSibling),this.$parent=this.$$nextSibling=this.$$prevSibling=this.$$childHead=this.$$childTail=this.$root=null,this.$$listeners={},this.$$watchers=this.$$asyncQueue=this.$$postDigestQueue=[],this.$destroy=this.$digest=this.$apply=v,this.$on=this.$watch=function(){return v})}},
-$eval:function(a,b){return f(a)(this,b)},$evalAsync:function(a){q.$$phase||q.$$asyncQueue.length||g.defer(function(){q.$$asyncQueue.length&&q.$digest()});this.$$asyncQueue.push({scope:this,expression:a})},$$postDigest:function(a){this.$$postDigestQueue.push(a)},$apply:function(a){try{return k("$apply"),this.$eval(a)}catch(b){e(b)}finally{q.$$phase=null;try{q.$digest()}catch(c){throw e(c),c;}}},$on:function(a,b){var c=this.$$listeners[a];c||(this.$$listeners[a]=c=[]);c.push(b);var d=this;do d.$$listenerCount[a]||
-(d.$$listenerCount[a]=0),d.$$listenerCount[a]++;while(d=d.$parent);var e=this;return function(){var d=Ta(c,b);-1!==d&&(c[d]=null,l(e,1,a))}},$emit:function(a,b){var c=[],d,f=this,g=!1,h={name:a,targetScope:f,stopPropagation:function(){g=!0},preventDefault:function(){h.defaultPrevented=!0},defaultPrevented:!1},k=[h].concat(wa.call(arguments,1)),l,m;do{d=f.$$listeners[a]||c;h.currentScope=f;l=0;for(m=d.length;l<m;l++)if(d[l])try{d[l].apply(null,k)}catch(n){e(n)}else d.splice(l,1),l--,m--;if(g)break;
-f=f.$parent}while(f);return h},$broadcast:function(a,b){for(var c=this,d=this,f={name:a,targetScope:this,preventDefault:function(){f.defaultPrevented=!0},defaultPrevented:!1},g=[f].concat(wa.call(arguments,1)),h,k;c=d;){f.currentScope=c;d=c.$$listeners[a]||[];h=0;for(k=d.length;h<k;h++)if(d[h])try{d[h].apply(null,g)}catch(l){e(l)}else d.splice(h,1),h--,k--;if(!(d=c.$$listenerCount[a]&&c.$$childHead||c!==this&&c.$$nextSibling))for(;c!==this&&!(d=c.$$nextSibling);)c=c.$parent}return f}};var q=new h;
-return q}]}function bd(){var b=/^\s*(https?|ftp|mailto|tel|file):/,a=/^\s*((https?|ftp|file):|data:image\/)/;this.aHrefSanitizationWhitelist=function(a){return D(a)?(b=a,this):b};this.imgSrcSanitizationWhitelist=function(b){return D(b)?(a=b,this):a};this.$get=function(){return function(c,d){var e=d?a:b,f;if(!R||8<=R)if(f=xa(c).href,""!==f&&!f.match(e))return"unsafe:"+f;return c}}}function Ee(b){if("self"===b)return b;if(G(b)){if(-1<b.indexOf("***"))throw za("iwcard",b);b=b.replace(/([-()\[\]{}+?*.$\^|,:#<!\\])/g,
-"\\$1").replace(/\x08/g,"\\x08").replace("\\*\\*",".*").replace("\\*","[^:/.?&;]*");return RegExp("^"+b+"$")}if(kb(b))return RegExp("^"+b.source+"$");throw za("imatcher");}function Fc(b){var a=[];D(b)&&r(b,function(b){a.push(Ee(b))});return a}function ae(){this.SCE_CONTEXTS=fa;var b=["self"],a=[];this.resourceUrlWhitelist=function(a){arguments.length&&(b=Fc(a));return b};this.resourceUrlBlacklist=function(b){arguments.length&&(a=Fc(b));return a};this.$get=["$injector",function(c){function d(a){var b=
-function(a){this.$$unwrapTrustedValue=function(){return a}};a&&(b.prototype=new a);b.prototype.valueOf=function(){return this.$$unwrapTrustedValue()};b.prototype.toString=function(){return this.$$unwrapTrustedValue().toString()};return b}var e=function(a){throw za("unsafe");};c.has("$sanitize")&&(e=c.get("$sanitize"));var f=d(),g={};g[fa.HTML]=d(f);g[fa.CSS]=d(f);g[fa.URL]=d(f);g[fa.JS]=d(f);g[fa.RESOURCE_URL]=d(g[fa.URL]);return{trustAs:function(a,b){var c=g.hasOwnProperty(a)?g[a]:null;if(!c)throw za("icontext",
-a,b);if(null===b||b===u||""===b)return b;if("string"!==typeof b)throw za("itype",a);return new c(b)},getTrusted:function(c,d){if(null===d||d===u||""===d)return d;var f=g.hasOwnProperty(c)?g[c]:null;if(f&&d instanceof f)return d.$$unwrapTrustedValue();if(c===fa.RESOURCE_URL){var f=xa(d.toString()),l,n,q=!1;l=0;for(n=b.length;l<n;l++)if("self"===b[l]?Pb(f):b[l].exec(f.href)){q=!0;break}if(q)for(l=0,n=a.length;l<n;l++)if("self"===a[l]?Pb(f):a[l].exec(f.href)){q=!1;break}if(q)return d;throw za("insecurl",
-d.toString());}if(c===fa.HTML)return e(d);throw za("unsafe");},valueOf:function(a){return a instanceof f?a.$$unwrapTrustedValue():a}}}]}function $d(){var b=!0;this.enabled=function(a){arguments.length&&(b=!!a);return b};this.$get=["$parse","$sniffer","$sceDelegate",function(a,c,d){if(b&&c.msie&&8>c.msieDocumentMode)throw za("iequirks");var e=ha(fa);e.isEnabled=function(){return b};e.trustAs=d.trustAs;e.getTrusted=d.getTrusted;e.valueOf=d.valueOf;b||(e.trustAs=e.getTrusted=function(a,b){return b},
-e.valueOf=ga);e.parseAs=function(b,c){var d=a(c);return d.literal&&d.constant?d:function(a,c){return e.getTrusted(b,d(a,c))}};var f=e.parseAs,g=e.getTrusted,h=e.trustAs;r(fa,function(a,b){var c=x(b);e[ab("parse_as_"+c)]=function(b){return f(a,b)};e[ab("get_trusted_"+c)]=function(b){return g(a,b)};e[ab("trust_as_"+c)]=function(b){return h(a,b)}});return e}]}function be(){this.$get=["$window","$document",function(b,a){var c={},d=U((/android (\d+)/.exec(x((b.navigator||{}).userAgent))||[])[1]),e=/Boxee/i.test((b.navigator||
-{}).userAgent),f=a[0]||{},g=f.documentMode,h,k=/^(Moz|webkit|O|ms)(?=[A-Z])/,m=f.body&&f.body.style,l=!1,n=!1;if(m){for(var q in m)if(l=k.exec(q)){h=l[0];h=h.substr(0,1).toUpperCase()+h.substr(1);break}h||(h="WebkitOpacity"in m&&"webkit");l=!!("transition"in m||h+"Transition"in m);n=!!("animation"in m||h+"Animation"in m);!d||l&&n||(l=G(f.body.style.webkitTransition),n=G(f.body.style.webkitAnimation))}return{history:!(!b.history||!b.history.pushState||4>d||e),hashchange:"onhashchange"in b&&(!g||7<
-g),hasEvent:function(a){if("input"==a&&9==R)return!1;if(F(c[a])){var b=f.createElement("div");c[a]="on"+a in b}return c[a]},csp:Za(),vendorPrefix:h,transitions:l,animations:n,android:d,msie:R,msieDocumentMode:g}}]}function de(){this.$get=["$rootScope","$browser","$q","$exceptionHandler",function(b,a,c,d){function e(e,h,k){var m=c.defer(),l=m.promise,n=D(k)&&!k;h=a.defer(function(){try{m.resolve(e())}catch(a){m.reject(a),d(a)}finally{delete f[l.$$timeoutId]}n||b.$apply()},h);l.$$timeoutId=h;f[h]=m;
-return l}var f={};e.cancel=function(b){return b&&b.$$timeoutId in f?(f[b.$$timeoutId].reject("canceled"),delete f[b.$$timeoutId],a.defer.cancel(b.$$timeoutId)):!1};return e}]}function xa(b,a){var c=b;R&&(Y.setAttribute("href",c),c=Y.href);Y.setAttribute("href",c);return{href:Y.href,protocol:Y.protocol?Y.protocol.replace(/:$/,""):"",host:Y.host,search:Y.search?Y.search.replace(/^\?/,""):"",hash:Y.hash?Y.hash.replace(/^#/,""):"",hostname:Y.hostname,port:Y.port,pathname:"/"===Y.pathname.charAt(0)?Y.pathname:
-"/"+Y.pathname}}function Pb(b){b=G(b)?xa(b):b;return b.protocol===Gc.protocol&&b.host===Gc.host}function ee(){this.$get=aa(W)}function kc(b){function a(d,e){if(T(d)){var f={};r(d,function(b,c){f[c]=a(c,b)});return f}return b.factory(d+c,e)}var c="Filter";this.register=a;this.$get=["$injector",function(a){return function(b){return a.get(b+c)}}];a("currency",Hc);a("date",Ic);a("filter",Fe);a("json",Ge);a("limitTo",He);a("lowercase",Ie);a("number",Jc);a("orderBy",Kc);a("uppercase",Je)}function Fe(){return function(b,
-a,c){if(!L(b))return b;var d=typeof c,e=[];e.check=function(a){for(var b=0;b<e.length;b++)if(!e[b](a))return!1;return!0};"function"!==d&&(c="boolean"===d&&c?function(a,b){return Xa.equals(a,b)}:function(a,b){if(a&&b&&"object"===typeof a&&"object"===typeof b){for(var d in a)if("$"!==d.charAt(0)&&lb.call(a,d)&&c(a[d],b[d]))return!0;return!1}b=(""+b).toLowerCase();return-1<(""+a).toLowerCase().indexOf(b)});var f=function(a,b){if("string"===typeof b&&"!"===b.charAt(0))return!f(a,b.substr(1));switch(typeof a){case "boolean":case "number":case "string":return c(a,
-b);case "object":switch(typeof b){case "object":return c(a,b);default:for(var d in a)if("$"!==d.charAt(0)&&f(a[d],b))return!0}return!1;case "array":for(d=0;d<a.length;d++)if(f(a[d],b))return!0;return!1;default:return!1}};switch(typeof a){case "boolean":case "number":case "string":a={$:a};case "object":for(var g in a)(function(b){"undefined"!==typeof a[b]&&e.push(function(c){return f("$"==b?c:c&&c[b],a[b])})})(g);break;case "function":e.push(a);break;default:return b}d=[];for(g=0;g<b.length;g++){var h=
-b[g];e.check(h)&&d.push(h)}return d}}function Hc(b){var a=b.NUMBER_FORMATS;return function(b,d){F(d)&&(d=a.CURRENCY_SYM);return Lc(b,a.PATTERNS[1],a.GROUP_SEP,a.DECIMAL_SEP,2).replace(/\u00A4/g,d)}}function Jc(b){var a=b.NUMBER_FORMATS;return function(b,d){return Lc(b,a.PATTERNS[0],a.GROUP_SEP,a.DECIMAL_SEP,d)}}function Lc(b,a,c,d,e){if(null==b||!isFinite(b)||T(b))return"";var f=0>b;b=Math.abs(b);var g=b+"",h="",k=[],m=!1;if(-1!==g.indexOf("e")){var l=g.match(/([\d\.]+)e(-?)(\d+)/);l&&"-"==l[2]&&
-l[3]>e+1?(g="0",b=0):(h=g,m=!0)}if(m)0<e&&(-1<b&&1>b)&&(h=b.toFixed(e));else{g=(g.split(Mc)[1]||"").length;F(e)&&(e=Math.min(Math.max(a.minFrac,g),a.maxFrac));b=+(Math.round(+(b.toString()+"e"+e)).toString()+"e"+-e);0===b&&(f=!1);b=(""+b).split(Mc);g=b[0];b=b[1]||"";var l=0,n=a.lgSize,q=a.gSize;if(g.length>=n+q)for(l=g.length-n,m=0;m<l;m++)0===(l-m)%q&&0!==m&&(h+=c),h+=g.charAt(m);for(m=l;m<g.length;m++)0===(g.length-m)%n&&0!==m&&(h+=c),h+=g.charAt(m);for(;b.length<e;)b+="0";e&&"0"!==e&&(h+=d+b.substr(0,
-e))}k.push(f?a.negPre:a.posPre);k.push(h);k.push(f?a.negSuf:a.posSuf);return k.join("")}function Vb(b,a,c){var d="";0>b&&(d="-",b=-b);for(b=""+b;b.length<a;)b="0"+b;c&&(b=b.substr(b.length-a));return d+b}function Z(b,a,c,d){c=c||0;return function(e){e=e["get"+b]();if(0<c||e>-c)e+=c;0===e&&-12==c&&(e=12);return Vb(e,a,d)}}function vb(b,a){return function(c,d){var e=c["get"+b](),f=La(a?"SHORT"+b:b);return d[f][e]}}function Ic(b){function a(a){var b;if(b=a.match(c)){a=new Date(0);var f=0,g=0,h=b[8]?
-a.setUTCFullYear:a.setFullYear,k=b[8]?a.setUTCHours:a.setHours;b[9]&&(f=U(b[9]+b[10]),g=U(b[9]+b[11]));h.call(a,U(b[1]),U(b[2])-1,U(b[3]));f=U(b[4]||0)-f;g=U(b[5]||0)-g;h=U(b[6]||0);b=Math.round(1E3*parseFloat("0."+(b[7]||0)));k.call(a,f,g,h,b)}return a}var c=/^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/;return function(c,e){var f="",g=[],h,k;e=e||"mediumDate";e=b.DATETIME_FORMATS[e]||e;G(c)&&(c=Ke.test(c)?U(c):a(c));jb(c)&&(c=new Date(c));
-if(!va(c))return c;for(;e;)(k=Le.exec(e))?(g=g.concat(wa.call(k,1)),e=g.pop()):(g.push(e),e=null);r(g,function(a){h=Me[a];f+=h?h(c,b.DATETIME_FORMATS):a.replace(/(^'|'$)/g,"").replace(/''/g,"'")});return f}}function Ge(){return function(b){return oa(b,!0)}}function He(){return function(b,a){if(!L(b)&&!G(b))return b;a=Infinity===Math.abs(Number(a))?Number(a):U(a);if(G(b))return a?0<=a?b.slice(0,a):b.slice(a,b.length):"";var c=[],d,e;a>b.length?a=b.length:a<-b.length&&(a=-b.length);0<a?(d=0,e=a):(d=
-b.length+a,e=b.length);for(;d<e;d++)c.push(b[d]);return c}}function Kc(b){return function(a,c,d){function e(a,b){return Wa(b)?function(b,c){return a(c,b)}:a}function f(a,b){var c=typeof a,d=typeof b;return c==d?(va(a)&&va(b)&&(a=a.valueOf(),b=b.valueOf()),"string"==c&&(a=a.toLowerCase(),b=b.toLowerCase()),a===b?0:a<b?-1:1):c<d?-1:1}if(!Sa(a))return a;c=L(c)?c:[c];0===c.length&&(c=["+"]);c=Uc(c,function(a){var c=!1,d=a||ga;if(G(a)){if("+"==a.charAt(0)||"-"==a.charAt(0))c="-"==a.charAt(0),a=a.substring(1);
-if(""===a)return e(function(a,b){return f(a,b)},c);d=b(a);if(d.constant){var m=d();return e(function(a,b){return f(a[m],b[m])},c)}}return e(function(a,b){return f(d(a),d(b))},c)});return wa.call(a).sort(e(function(a,b){for(var d=0;d<c.length;d++){var e=c[d](a,b);if(0!==e)return e}return 0},d))}}function Aa(b){N(b)&&(b={link:b});b.restrict=b.restrict||"AC";return aa(b)}function Nc(b,a,c,d){function e(a,c){c=c?"-"+nb(c,"-"):"";d.setClass(b,(a?wb:xb)+c,(a?xb:wb)+c)}var f=this,g=b.parent().controller("form")||
-yb,h=0,k=f.$error={},m=[];f.$name=a.name||a.ngForm;f.$dirty=!1;f.$pristine=!0;f.$valid=!0;f.$invalid=!1;g.$addControl(f);b.addClass(Ra);e(!0);f.$addControl=function(a){Ea(a.$name,"input");m.push(a);a.$name&&(f[a.$name]=a)};f.$removeControl=function(a){a.$name&&f[a.$name]===a&&delete f[a.$name];r(k,function(b,c){f.$setValidity(c,!0,a)});Ua(m,a)};f.$setValidity=function(a,b,c){var d=k[a];if(b)d&&(Ua(d,c),d.length||(h--,h||(e(b),f.$valid=!0,f.$invalid=!1),k[a]=!1,e(!0,a),g.$setValidity(a,!0,f)));else{h||
-e(b);if(d){if(-1!=Ta(d,c))return}else k[a]=d=[],h++,e(!1,a),g.$setValidity(a,!1,f);d.push(c);f.$valid=!1;f.$invalid=!0}};f.$setDirty=function(){d.removeClass(b,Ra);d.addClass(b,zb);f.$dirty=!0;f.$pristine=!1;g.$setDirty()};f.$setPristine=function(){d.removeClass(b,zb);d.addClass(b,Ra);f.$dirty=!1;f.$pristine=!0;r(m,function(a){a.$setPristine()})}}function ua(b,a,c,d){b.$setValidity(a,c);return c?d:u}function Oc(b,a){var c,d;if(a)for(c=0;c<a.length;++c)if(d=a[c],b[d])return!0;return!1}function Ne(b,
-a,c,d,e){T(e)&&(b.$$hasNativeValidators=!0,b.$parsers.push(function(f){if(b.$error[a]||Oc(e,d)||!Oc(e,c))return f;b.$setValidity(a,!1)}))}function Ab(b,a,c,d,e,f){var g=a.prop(Oe),h=a[0].placeholder,k={},m=x(a[0].type);d.$$validityState=g;if(!e.android){var l=!1;a.on("compositionstart",function(a){l=!0});a.on("compositionend",function(){l=!1;n()})}var n=function(e){if(!l){var f=a.val();if(R&&"input"===(e||k).type&&a[0].placeholder!==h)h=a[0].placeholder;else if("password"!==m&&Wa(c.ngTrim||"T")&&
-(f=$(f)),e=g&&d.$$hasNativeValidators,d.$viewValue!==f||""===f&&e)b.$root.$$phase?d.$setViewValue(f):b.$apply(function(){d.$setViewValue(f)})}};if(e.hasEvent("input"))a.on("input",n);else{var q,p=function(){q||(q=f.defer(function(){n();q=null}))};a.on("keydown",function(a){a=a.keyCode;91===a||(15<a&&19>a||37<=a&&40>=a)||p()});if(e.hasEvent("paste"))a.on("paste cut",p)}a.on("change",n);d.$render=function(){a.val(d.$isEmpty(d.$viewValue)?"":d.$viewValue)};var s=c.ngPattern;s&&((e=s.match(/^\/(.*)\/([gim]*)$/))?
-(s=RegExp(e[1],e[2]),e=function(a){return ua(d,"pattern",d.$isEmpty(a)||s.test(a),a)}):e=function(c){var e=b.$eval(s);if(!e||!e.test)throw z("ngPattern")("noregexp",s,e,ia(a));return ua(d,"pattern",d.$isEmpty(c)||e.test(c),c)},d.$formatters.push(e),d.$parsers.push(e));if(c.ngMinlength){var r=U(c.ngMinlength);e=function(a){return ua(d,"minlength",d.$isEmpty(a)||a.length>=r,a)};d.$parsers.push(e);d.$formatters.push(e)}if(c.ngMaxlength){var w=U(c.ngMaxlength);e=function(a){return ua(d,"maxlength",d.$isEmpty(a)||
-a.length<=w,a)};d.$parsers.push(e);d.$formatters.push(e)}}function Wb(b,a){b="ngClass"+b;return["$animate",function(c){function d(a,b){var c=[],d=0;a:for(;d<a.length;d++){for(var e=a[d],l=0;l<b.length;l++)if(e==b[l])continue a;c.push(e)}return c}function e(a){if(!L(a)){if(G(a))return a.split(" ");if(T(a)){var b=[];r(a,function(a,c){a&&(b=b.concat(c.split(" ")))});return b}}return a}return{restrict:"AC",link:function(f,g,h){function k(a,b){var c=g.data("$classCounts")||{},d=[];r(a,function(a){if(0<
-b||c[a])c[a]=(c[a]||0)+b,c[a]===+(0<b)&&d.push(a)});g.data("$classCounts",c);return d.join(" ")}function m(b){if(!0===a||f.$index%2===a){var m=e(b||[]);if(!l){var p=k(m,1);h.$addClass(p)}else if(!Ca(b,l)){var s=e(l),p=d(m,s),m=d(s,m),m=k(m,-1),p=k(p,1);0===p.length?c.removeClass(g,m):0===m.length?c.addClass(g,p):c.setClass(g,p,m)}}l=ha(b)}var l;f.$watch(h[b],m,!0);h.$observe("class",function(a){m(f.$eval(h[b]))});"ngClass"!==b&&f.$watch("$index",function(c,d){var g=c&1;if(g!==(d&1)){var l=e(f.$eval(h[b]));
-g===a?(g=k(l,1),h.$addClass(g)):(g=k(l,-1),h.$removeClass(g))}})}}}]}var Oe="validity",x=function(b){return G(b)?b.toLowerCase():b},lb=Object.prototype.hasOwnProperty,La=function(b){return G(b)?b.toUpperCase():b},R,A,Fa,wa=[].slice,Pe=[].push,Ba=Object.prototype.toString,Va=z("ng"),Xa=W.angular||(W.angular={}),$a,Pa,na=["0","0","0"];R=U((/msie (\d+)/.exec(x(navigator.userAgent))||[])[1]);isNaN(R)&&(R=U((/trident\/.*; rv:(\d+)/.exec(x(navigator.userAgent))||[])[1]));v.$inject=[];ga.$inject=[];var L=
-function(){return N(Array.isArray)?Array.isArray:function(b){return"[object Array]"===Ba.call(b)}}(),$=function(){return String.prototype.trim?function(b){return G(b)?b.trim():b}:function(b){return G(b)?b.replace(/^\s\s*/,"").replace(/\s\s*$/,""):b}}();Pa=9>R?function(b){b=b.nodeName?b:b[0];return b.scopeName&&"HTML"!=b.scopeName?La(b.scopeName+":"+b.nodeName):b.nodeName}:function(b){return b.nodeName?b.nodeName:b[0].nodeName};var Za=function(){if(D(Za.isActive_))return Za.isActive_;var b=!(!X.querySelector("[ng-csp]")&&
-!X.querySelector("[data-ng-csp]"));if(!b)try{new Function("")}catch(a){b=!0}return Za.isActive_=b},Xc=/[A-Z]/g,$c={full:"1.2.28",major:1,minor:2,dot:28,codeName:"finnish-disembarkation"};S.expando="ng339";var cb=S.cache={},me=1,sb=W.document.addEventListener?function(b,a,c){b.addEventListener(a,c,!1)}:function(b,a,c){b.attachEvent("on"+a,c)},bb=W.document.removeEventListener?function(b,a,c){b.removeEventListener(a,c,!1)}:function(b,a,c){b.detachEvent("on"+a,c)};S._data=function(b){return this.cache[b[this.expando]]||
-{}};var he=/([\:\-\_]+(.))/g,ie=/^moz([A-Z])/,Hb=z("jqLite"),je=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,Ib=/<|&#?\w+;/,ke=/<([\w:]+)/,le=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,da={option:[1,'<select multiple="multiple">',"</select>"],thead:[1,"<table>","</table>"],col:[2,"<table><colgroup>","</colgroup></table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:[0,"",""]};da.optgroup=da.option;da.tbody=da.tfoot=da.colgroup=
-da.caption=da.thead;da.th=da.td;var Oa=S.prototype={ready:function(b){function a(){c||(c=!0,b())}var c=!1;"complete"===X.readyState?setTimeout(a):(this.on("DOMContentLoaded",a),S(W).on("load",a))},toString:function(){var b=[];r(this,function(a){b.push(""+a)});return"["+b.join(", ")+"]"},eq:function(b){return 0<=b?A(this[b]):A(this[this.length+b])},length:0,push:Pe,sort:[].sort,splice:[].splice},rb={};r("multiple selected checked disabled readOnly required open".split(" "),function(b){rb[x(b)]=b});
-var pc={};r("input select option textarea button form details".split(" "),function(b){pc[La(b)]=!0});r({data:Mb,removeData:Lb},function(b,a){S[a]=b});r({data:Mb,inheritedData:qb,scope:function(b){return A.data(b,"$scope")||qb(b.parentNode||b,["$isolateScope","$scope"])},isolateScope:function(b){return A.data(b,"$isolateScope")||A.data(b,"$isolateScopeNoTemplate")},controller:mc,injector:function(b){return qb(b,"$injector")},removeAttr:function(b,a){b.removeAttribute(a)},hasClass:Nb,css:function(b,
-a,c){a=ab(a);if(D(c))b.style[a]=c;else{var d;8>=R&&(d=b.currentStyle&&b.currentStyle[a],""===d&&(d="auto"));d=d||b.style[a];8>=R&&(d=""===d?u:d);return d}},attr:function(b,a,c){var d=x(a);if(rb[d])if(D(c))c?(b[a]=!0,b.setAttribute(a,d)):(b[a]=!1,b.removeAttribute(d));else return b[a]||(b.attributes.getNamedItem(a)||v).specified?d:u;else if(D(c))b.setAttribute(a,c);else if(b.getAttribute)return b=b.getAttribute(a,2),null===b?u:b},prop:function(b,a,c){if(D(c))b[a]=c;else return b[a]},text:function(){function b(b,
-d){var e=a[b.nodeType];if(F(d))return e?b[e]:"";b[e]=d}var a=[];9>R?(a[1]="innerText",a[3]="nodeValue"):a[1]=a[3]="textContent";b.$dv="";return b}(),val:function(b,a){if(F(a)){if("SELECT"===Pa(b)&&b.multiple){var c=[];r(b.options,function(a){a.selected&&c.push(a.value||a.text)});return 0===c.length?null:c}return b.value}b.value=a},html:function(b,a){if(F(a))return b.innerHTML;for(var c=0,d=b.childNodes;c<d.length;c++)Ma(d[c]);b.innerHTML=a},empty:nc},function(b,a){S.prototype[a]=function(a,d){var e,
-f,g=this.length;if(b!==nc&&(2==b.length&&b!==Nb&&b!==mc?a:d)===u){if(T(a)){for(e=0;e<g;e++)if(b===Mb)b(this[e],a);else for(f in a)b(this[e],f,a[f]);return this}e=b.$dv;g=e===u?Math.min(g,1):g;for(f=0;f<g;f++){var h=b(this[f],a,d);e=e?e+h:h}return e}for(e=0;e<g;e++)b(this[e],a,d);return this}});r({removeData:Lb,dealoc:Ma,on:function a(c,d,e,f){if(D(f))throw Hb("onargs");var g=pa(c,"events"),h=pa(c,"handle");g||pa(c,"events",g={});h||pa(c,"handle",h=ne(c,g));r(d.split(" "),function(d){var f=g[d];if(!f){if("mouseenter"==
-d||"mouseleave"==d){var l=X.body.contains||X.body.compareDocumentPosition?function(a,c){var d=9===a.nodeType?a.documentElement:a,e=c&&c.parentNode;return a===e||!!(e&&1===e.nodeType&&(d.contains?d.contains(e):a.compareDocumentPosition&&a.compareDocumentPosition(e)&16))}:function(a,c){if(c)for(;c=c.parentNode;)if(c===a)return!0;return!1};g[d]=[];a(c,{mouseleave:"mouseout",mouseenter:"mouseover"}[d],function(a){var c=a.relatedTarget;c&&(c===this||l(this,c))||h(a,d)})}else sb(c,d,h),g[d]=[];f=g[d]}f.push(e)})},
-off:lc,one:function(a,c,d){a=A(a);a.on(c,function f(){a.off(c,d);a.off(c,f)});a.on(c,d)},replaceWith:function(a,c){var d,e=a.parentNode;Ma(a);r(new S(c),function(c){d?e.insertBefore(c,d.nextSibling):e.replaceChild(c,a);d=c})},children:function(a){var c=[];r(a.childNodes,function(a){1===a.nodeType&&c.push(a)});return c},contents:function(a){return a.contentDocument||a.childNodes||[]},append:function(a,c){r(new S(c),function(c){1!==a.nodeType&&11!==a.nodeType||a.appendChild(c)})},prepend:function(a,
-c){if(1===a.nodeType){var d=a.firstChild;r(new S(c),function(c){a.insertBefore(c,d)})}},wrap:function(a,c){c=A(c)[0];var d=a.parentNode;d&&d.replaceChild(c,a);c.appendChild(a)},remove:function(a){Ma(a);var c=a.parentNode;c&&c.removeChild(a)},after:function(a,c){var d=a,e=a.parentNode;r(new S(c),function(a){e.insertBefore(a,d.nextSibling);d=a})},addClass:pb,removeClass:ob,toggleClass:function(a,c,d){c&&r(c.split(" "),function(c){var f=d;F(f)&&(f=!Nb(a,c));(f?pb:ob)(a,c)})},parent:function(a){return(a=
-a.parentNode)&&11!==a.nodeType?a:null},next:function(a){if(a.nextElementSibling)return a.nextElementSibling;for(a=a.nextSibling;null!=a&&1!==a.nodeType;)a=a.nextSibling;return a},find:function(a,c){return a.getElementsByTagName?a.getElementsByTagName(c):[]},clone:Kb,triggerHandler:function(a,c,d){var e,f;e=c.type||c;var g=(pa(a,"events")||{})[e];g&&(e={preventDefault:function(){this.defaultPrevented=!0},isDefaultPrevented:function(){return!0===this.defaultPrevented},stopPropagation:v,type:e,target:a},
-c.type&&(e=E(e,c)),c=ha(g),f=d?[e].concat(d):[e],r(c,function(c){c.apply(a,f)}))}},function(a,c){S.prototype[c]=function(c,e,f){for(var g,h=0;h<this.length;h++)F(g)?(g=a(this[h],c,e,f),D(g)&&(g=A(g))):Jb(g,a(this[h],c,e,f));return D(g)?g:this};S.prototype.bind=S.prototype.on;S.prototype.unbind=S.prototype.off});db.prototype={put:function(a,c){this[Na(a,this.nextUid)]=c},get:function(a){return this[Na(a,this.nextUid)]},remove:function(a){var c=this[a=Na(a,this.nextUid)];delete this[a];return c}};var pe=
-/^function\s*[^\(]*\(\s*([^\)]*)\)/m,qe=/,/,re=/^\s*(_?)(\S+?)\1\s*$/,oe=/((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg,eb=z("$injector"),Qe=z("$animate"),Ld=["$provide",function(a){this.$$selectors={};this.register=function(c,d){var e=c+"-animation";if(c&&"."!=c.charAt(0))throw Qe("notcsel",c);this.$$selectors[c.substr(1)]=e;a.factory(e,d)};this.classNameFilter=function(a){1===arguments.length&&(this.$$classNameFilter=a instanceof RegExp?a:null);return this.$$classNameFilter};this.$get=["$timeout","$$asyncCallback",
-function(a,d){return{enter:function(a,c,g,h){g?g.after(a):(c&&c[0]||(c=g.parent()),c.append(a));h&&d(h)},leave:function(a,c){a.remove();c&&d(c)},move:function(a,c,d,h){this.enter(a,c,d,h)},addClass:function(a,c,g){c=G(c)?c:L(c)?c.join(" "):"";r(a,function(a){pb(a,c)});g&&d(g)},removeClass:function(a,c,g){c=G(c)?c:L(c)?c.join(" "):"";r(a,function(a){ob(a,c)});g&&d(g)},setClass:function(a,c,g,h){r(a,function(a){pb(a,c);ob(a,g)});h&&d(h)},enabled:v}}]}],ja=z("$compile");gc.$inject=["$provide","$$sanitizeUriProvider"];
-var we=/^(x[\:\-_]|data[\:\-_])/i,wc=z("$interpolate"),Re=/^([^\?#]*)(\?([^#]*))?(#(.*))?$/,ze={http:80,https:443,ftp:21},Sb=z("$location");Ac.prototype=Tb.prototype=zc.prototype={$$html5:!1,$$replace:!1,absUrl:tb("$$absUrl"),url:function(a){if(F(a))return this.$$url;a=Re.exec(a);a[1]&&this.path(decodeURIComponent(a[1]));(a[2]||a[1])&&this.search(a[3]||"");this.hash(a[5]||"");return this},protocol:tb("$$protocol"),host:tb("$$host"),port:tb("$$port"),path:Bc("$$path",function(a){a=null!==a?a.toString():
-"";return"/"==a.charAt(0)?a:"/"+a}),search:function(a,c){switch(arguments.length){case 0:return this.$$search;case 1:if(G(a)||jb(a))a=a.toString(),this.$$search=cc(a);else if(T(a))r(a,function(c,e){null==c&&delete a[e]}),this.$$search=a;else throw Sb("isrcharg");break;default:F(c)||null===c?delete this.$$search[a]:this.$$search[a]=c}this.$$compose();return this},hash:Bc("$$hash",function(a){return null!==a?a.toString():""}),replace:function(){this.$$replace=!0;return this}};var la=z("$parse"),Ec=
-{},ya,Se=Function.prototype.call,Te=Function.prototype.apply,Pc=Function.prototype.bind,hb={"null":function(){return null},"true":function(){return!0},"false":function(){return!1},undefined:v,"+":function(a,c,d,e){d=d(a,c);e=e(a,c);return D(d)?D(e)?d+e:d:D(e)?e:u},"-":function(a,c,d,e){d=d(a,c);e=e(a,c);return(D(d)?d:0)-(D(e)?e:0)},"*":function(a,c,d,e){return d(a,c)*e(a,c)},"/":function(a,c,d,e){return d(a,c)/e(a,c)},"%":function(a,c,d,e){return d(a,c)%e(a,c)},"^":function(a,c,d,e){return d(a,c)^
-e(a,c)},"=":v,"===":function(a,c,d,e){return d(a,c)===e(a,c)},"!==":function(a,c,d,e){return d(a,c)!==e(a,c)},"==":function(a,c,d,e){return d(a,c)==e(a,c)},"!=":function(a,c,d,e){return d(a,c)!=e(a,c)},"<":function(a,c,d,e){return d(a,c)<e(a,c)},">":function(a,c,d,e){return d(a,c)>e(a,c)},"<=":function(a,c,d,e){return d(a,c)<=e(a,c)},">=":function(a,c,d,e){return d(a,c)>=e(a,c)},"&&":function(a,c,d,e){return d(a,c)&&e(a,c)},"||":function(a,c,d,e){return d(a,c)||e(a,c)},"&":function(a,c,d,e){return d(a,
-c)&e(a,c)},"|":function(a,c,d,e){return e(a,c)(a,c,d(a,c))},"!":function(a,c,d){return!d(a,c)}},Ue={n:"\n",f:"\f",r:"\r",t:"\t",v:"\v","'":"'",'"':'"'},Ub=function(a){this.options=a};Ub.prototype={constructor:Ub,lex:function(a){this.text=a;this.index=0;this.ch=u;this.lastCh=":";for(this.tokens=[];this.index<this.text.length;){this.ch=this.text.charAt(this.index);if(this.is("\"'"))this.readString(this.ch);else if(this.isNumber(this.ch)||this.is(".")&&this.isNumber(this.peek()))this.readNumber();else if(this.isIdent(this.ch))this.readIdent();
-else if(this.is("(){}[].,;:?"))this.tokens.push({index:this.index,text:this.ch}),this.index++;else if(this.isWhitespace(this.ch)){this.index++;continue}else{a=this.ch+this.peek();var c=a+this.peek(2),d=hb[this.ch],e=hb[a],f=hb[c];f?(this.tokens.push({index:this.index,text:c,fn:f}),this.index+=3):e?(this.tokens.push({index:this.index,text:a,fn:e}),this.index+=2):d?(this.tokens.push({index:this.index,text:this.ch,fn:d}),this.index+=1):this.throwError("Unexpected next character ",this.index,this.index+
-1)}this.lastCh=this.ch}return this.tokens},is:function(a){return-1!==a.indexOf(this.ch)},was:function(a){return-1!==a.indexOf(this.lastCh)},peek:function(a){a=a||1;return this.index+a<this.text.length?this.text.charAt(this.index+a):!1},isNumber:function(a){return"0"<=a&&"9">=a},isWhitespace:function(a){return" "===a||"\r"===a||"\t"===a||"\n"===a||"\v"===a||"\u00a0"===a},isIdent:function(a){return"a"<=a&&"z">=a||"A"<=a&&"Z">=a||"_"===a||"$"===a},isExpOperator:function(a){return"-"===a||"+"===a||this.isNumber(a)},
-throwError:function(a,c,d){d=d||this.index;c=D(c)?"s "+c+"-"+this.index+" ["+this.text.substring(c,d)+"]":" "+d;throw la("lexerr",a,c,this.text);},readNumber:function(){for(var a="",c=this.index;this.index<this.text.length;){var d=x(this.text.charAt(this.index));if("."==d||this.isNumber(d))a+=d;else{var e=this.peek();if("e"==d&&this.isExpOperator(e))a+=d;else if(this.isExpOperator(d)&&e&&this.isNumber(e)&&"e"==a.charAt(a.length-1))a+=d;else if(!this.isExpOperator(d)||e&&this.isNumber(e)||"e"!=a.charAt(a.length-
-1))break;else this.throwError("Invalid exponent")}this.index++}a*=1;this.tokens.push({index:c,text:a,literal:!0,constant:!0,fn:function(){return a}})},readIdent:function(){for(var a=this,c="",d=this.index,e,f,g,h;this.index<this.text.length;){h=this.text.charAt(this.index);if("."===h||this.isIdent(h)||this.isNumber(h))"."===h&&(e=this.index),c+=h;else break;this.index++}if(e)for(f=this.index;f<this.text.length;){h=this.text.charAt(f);if("("===h){g=c.substr(e-d+1);c=c.substr(0,e-d);this.index=f;break}if(this.isWhitespace(h))f++;
-else break}d={index:d,text:c};if(hb.hasOwnProperty(c))d.fn=hb[c],d.literal=!0,d.constant=!0;else{var k=Dc(c,this.options,this.text);d.fn=E(function(a,c){return k(a,c)},{assign:function(d,e){return ub(d,c,e,a.text,a.options)}})}this.tokens.push(d);g&&(this.tokens.push({index:e,text:"."}),this.tokens.push({index:e+1,text:g}))},readString:function(a){var c=this.index;this.index++;for(var d="",e=a,f=!1;this.index<this.text.length;){var g=this.text.charAt(this.index),e=e+g;if(f)"u"===g?(f=this.text.substring(this.index+
-1,this.index+5),f.match(/[\da-f]{4}/i)||this.throwError("Invalid unicode escape [\\u"+f+"]"),this.index+=4,d+=String.fromCharCode(parseInt(f,16))):d+=Ue[g]||g,f=!1;else if("\\"===g)f=!0;else{if(g===a){this.index++;this.tokens.push({index:c,text:e,string:d,literal:!0,constant:!0,fn:function(){return d}});return}d+=g}this.index++}this.throwError("Unterminated quote",c)}};var gb=function(a,c,d){this.lexer=a;this.$filter=c;this.options=d};gb.ZERO=E(function(){return 0},{constant:!0});gb.prototype={constructor:gb,
-parse:function(a){this.text=a;this.tokens=this.lexer.lex(a);a=this.statements();0!==this.tokens.length&&this.throwError("is an unexpected token",this.tokens[0]);a.literal=!!a.literal;a.constant=!!a.constant;return a},primary:function(){var a;if(this.expect("("))a=this.filterChain(),this.consume(")");else if(this.expect("["))a=this.arrayDeclaration();else if(this.expect("{"))a=this.object();else{var c=this.expect();(a=c.fn)||this.throwError("not a primary expression",c);a.literal=!!c.literal;a.constant=
-!!c.constant}for(var d;c=this.expect("(","[",".");)"("===c.text?(a=this.functionCall(a,d),d=null):"["===c.text?(d=a,a=this.objectIndex(a)):"."===c.text?(d=a,a=this.fieldAccess(a)):this.throwError("IMPOSSIBLE");return a},throwError:function(a,c){throw la("syntax",c.text,a,c.index+1,this.text,this.text.substring(c.index));},peekToken:function(){if(0===this.tokens.length)throw la("ueoe",this.text);return this.tokens[0]},peek:function(a,c,d,e){if(0<this.tokens.length){var f=this.tokens[0],g=f.text;if(g===
-a||g===c||g===d||g===e||!(a||c||d||e))return f}return!1},expect:function(a,c,d,e){return(a=this.peek(a,c,d,e))?(this.tokens.shift(),a):!1},consume:function(a){this.expect(a)||this.throwError("is unexpected, expecting ["+a+"]",this.peek())},unaryFn:function(a,c){return E(function(d,e){return a(d,e,c)},{constant:c.constant})},ternaryFn:function(a,c,d){return E(function(e,f){return a(e,f)?c(e,f):d(e,f)},{constant:a.constant&&c.constant&&d.constant})},binaryFn:function(a,c,d){return E(function(e,f){return c(e,
-f,a,d)},{constant:a.constant&&d.constant})},statements:function(){for(var a=[];;)if(0<this.tokens.length&&!this.peek("}",")",";","]")&&a.push(this.filterChain()),!this.expect(";"))return 1===a.length?a[0]:function(c,d){for(var e,f=0;f<a.length;f++){var g=a[f];g&&(e=g(c,d))}return e}},filterChain:function(){for(var a=this.expression(),c;;)if(c=this.expect("|"))a=this.binaryFn(a,c.fn,this.filter());else return a},filter:function(){for(var a=this.expect(),c=this.$filter(a.text),d=[];;)if(a=this.expect(":"))d.push(this.expression());
-else{var e=function(a,e,h){h=[h];for(var k=0;k<d.length;k++)h.push(d[k](a,e));return c.apply(a,h)};return function(){return e}}},expression:function(){return this.assignment()},assignment:function(){var a=this.ternary(),c,d;return(d=this.expect("="))?(a.assign||this.throwError("implies assignment but ["+this.text.substring(0,d.index)+"] can not be assigned to",d),c=this.ternary(),function(d,f){return a.assign(d,c(d,f),f)}):a},ternary:function(){var a=this.logicalOR(),c,d;if(this.expect("?")){c=this.assignment();
-if(d=this.expect(":"))return this.ternaryFn(a,c,this.assignment());this.throwError("expected :",d)}else return a},logicalOR:function(){for(var a=this.logicalAND(),c;;)if(c=this.expect("||"))a=this.binaryFn(a,c.fn,this.logicalAND());else return a},logicalAND:function(){var a=this.equality(),c;if(c=this.expect("&&"))a=this.binaryFn(a,c.fn,this.logicalAND());return a},equality:function(){var a=this.relational(),c;if(c=this.expect("==","!=","===","!=="))a=this.binaryFn(a,c.fn,this.equality());return a},
-relational:function(){var a=this.additive(),c;if(c=this.expect("<",">","<=",">="))a=this.binaryFn(a,c.fn,this.relational());return a},additive:function(){for(var a=this.multiplicative(),c;c=this.expect("+","-");)a=this.binaryFn(a,c.fn,this.multiplicative());return a},multiplicative:function(){for(var a=this.unary(),c;c=this.expect("*","/","%");)a=this.binaryFn(a,c.fn,this.unary());return a},unary:function(){var a;return this.expect("+")?this.primary():(a=this.expect("-"))?this.binaryFn(gb.ZERO,a.fn,
-this.unary()):(a=this.expect("!"))?this.unaryFn(a.fn,this.unary()):this.primary()},fieldAccess:function(a){var c=this,d=this.expect().text,e=Dc(d,this.options,this.text);return E(function(c,d,h){return e(h||a(c,d))},{assign:function(e,g,h){(h=a(e,h))||a.assign(e,h={});return ub(h,d,g,c.text,c.options)}})},objectIndex:function(a){var c=this,d=this.expression();this.consume("]");return E(function(e,f){var g=a(e,f),h=d(e,f),k;ka(h,c.text);if(!g)return u;(g=ma(g[h],c.text))&&(g.then&&c.options.unwrapPromises)&&
-(k=g,"$$v"in g||(k.$$v=u,k.then(function(a){k.$$v=a})),g=g.$$v);return g},{assign:function(e,f,g){var h=ka(d(e,g),c.text);(g=ma(a(e,g),c.text))||a.assign(e,g={});return g[h]=f}})},functionCall:function(a,c){var d=[];if(")"!==this.peekToken().text){do d.push(this.expression());while(this.expect(","))}this.consume(")");var e=this;return function(f,g){for(var h=[],k=c?c(f,g):f,m=0;m<d.length;m++)h.push(ma(d[m](f,g),e.text));m=a(f,g,k)||v;ma(k,e.text);var l=e.text;if(m){if(m.constructor===m)throw la("isecfn",
-l);if(m===Se||m===Te||Pc&&m===Pc)throw la("isecff",l);}h=m.apply?m.apply(k,h):m(h[0],h[1],h[2],h[3],h[4]);return ma(h,e.text)}},arrayDeclaration:function(){var a=[],c=!0;if("]"!==this.peekToken().text){do{if(this.peek("]"))break;var d=this.expression();a.push(d);d.constant||(c=!1)}while(this.expect(","))}this.consume("]");return E(function(c,d){for(var g=[],h=0;h<a.length;h++)g.push(a[h](c,d));return g},{literal:!0,constant:c})},object:function(){var a=[],c=!0;if("}"!==this.peekToken().text){do{if(this.peek("}"))break;
-var d=this.expect(),d=d.string||d.text;this.consume(":");var e=this.expression();a.push({key:d,value:e});e.constant||(c=!1)}while(this.expect(","))}this.consume("}");return E(function(c,d){for(var e={},k=0;k<a.length;k++){var m=a[k];e[m.key]=m.value(c,d)}return e},{literal:!0,constant:c})}};var Ce={},Be={},za=z("$sce"),fa={HTML:"html",CSS:"css",URL:"url",RESOURCE_URL:"resourceUrl",JS:"js"},Y=X.createElement("a"),Gc=xa(W.location.href,!0);kc.$inject=["$provide"];Hc.$inject=["$locale"];Jc.$inject=["$locale"];
-var Mc=".",Me={yyyy:Z("FullYear",4),yy:Z("FullYear",2,0,!0),y:Z("FullYear",1),MMMM:vb("Month"),MMM:vb("Month",!0),MM:Z("Month",2,1),M:Z("Month",1,1),dd:Z("Date",2),d:Z("Date",1),HH:Z("Hours",2),H:Z("Hours",1),hh:Z("Hours",2,-12),h:Z("Hours",1,-12),mm:Z("Minutes",2),m:Z("Minutes",1),ss:Z("Seconds",2),s:Z("Seconds",1),sss:Z("Milliseconds",3),EEEE:vb("Day"),EEE:vb("Day",!0),a:function(a,c){return 12>a.getHours()?c.AMPMS[0]:c.AMPMS[1]},Z:function(a){a=-1*a.getTimezoneOffset();return a=(0<=a?"+":"")+(Vb(Math[0<
-a?"floor":"ceil"](a/60),2)+Vb(Math.abs(a%60),2))}},Le=/((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+|H+|h+|m+|s+|a|Z))(.*)/,Ke=/^\-?\d+$/;Ic.$inject=["$locale"];var Ie=aa(x),Je=aa(La);Kc.$inject=["$parse"];var cd=aa({restrict:"E",compile:function(a,c){8>=R&&(c.href||c.name||c.$set("href",""),a.append(X.createComment("IE fix")));if(!c.href&&!c.xlinkHref&&!c.name)return function(a,c){var f="[object SVGAnimatedString]"===Ba.call(c.prop("href"))?"xlink:href":"href";c.on("click",function(a){c.attr(f)||
-a.preventDefault()})}}}),Fb={};r(rb,function(a,c){if("multiple"!=a){var d=qa("ng-"+c);Fb[d]=function(){return{priority:100,link:function(a,f,g){a.$watch(g[d],function(a){g.$set(c,!!a)})}}}}});r(["src","srcset","href"],function(a){var c=qa("ng-"+a);Fb[c]=function(){return{priority:99,link:function(d,e,f){var g=a,h=a;"href"===a&&"[object SVGAnimatedString]"===Ba.call(e.prop("href"))&&(h="xlinkHref",f.$attr[h]="xlink:href",g=null);f.$observe(c,function(c){c?(f.$set(h,c),R&&g&&e.prop(g,f[h])):"href"===
-a&&f.$set(h,null)})}}}});var yb={$addControl:v,$removeControl:v,$setValidity:v,$setDirty:v,$setPristine:v};Nc.$inject=["$element","$attrs","$scope","$animate"];var Qc=function(a){return["$timeout",function(c){return{name:"form",restrict:a?"EAC":"E",controller:Nc,compile:function(){return{pre:function(a,e,f,g){if(!f.action){var h=function(a){a.preventDefault?a.preventDefault():a.returnValue=!1};sb(e[0],"submit",h);e.on("$destroy",function(){c(function(){bb(e[0],"submit",h)},0,!1)})}var k=e.parent().controller("form"),
-m=f.name||f.ngForm;m&&ub(a,m,g,m);if(k)e.on("$destroy",function(){k.$removeControl(g);m&&ub(a,m,u,m);E(g,yb)})}}}}}]},dd=Qc(),qd=Qc(!0),Ve=/^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/,We=/^[a-z0-9!#$%&'*+\/=?^_`{|}~.-]+@[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i,Xe=/^\s*(\-|\+)?(\d+|(\d*(\.\d*)))\s*$/,Rc={text:Ab,number:function(a,c,d,e,f,g){Ab(a,c,d,e,f,g);e.$parsers.push(function(a){var c=e.$isEmpty(a);if(c||Xe.test(a))return e.$setValidity("number",
-!0),""===a?null:c?a:parseFloat(a);e.$setValidity("number",!1);return u});Ne(e,"number",Ye,null,e.$$validityState);e.$formatters.push(function(a){return e.$isEmpty(a)?"":""+a});d.min&&(a=function(a){var c=parseFloat(d.min);return ua(e,"min",e.$isEmpty(a)||a>=c,a)},e.$parsers.push(a),e.$formatters.push(a));d.max&&(a=function(a){var c=parseFloat(d.max);return ua(e,"max",e.$isEmpty(a)||a<=c,a)},e.$parsers.push(a),e.$formatters.push(a));e.$formatters.push(function(a){return ua(e,"number",e.$isEmpty(a)||
-jb(a),a)})},url:function(a,c,d,e,f,g){Ab(a,c,d,e,f,g);a=function(a){return ua(e,"url",e.$isEmpty(a)||Ve.test(a),a)};e.$formatters.push(a);e.$parsers.push(a)},email:function(a,c,d,e,f,g){Ab(a,c,d,e,f,g);a=function(a){return ua(e,"email",e.$isEmpty(a)||We.test(a),a)};e.$formatters.push(a);e.$parsers.push(a)},radio:function(a,c,d,e){F(d.name)&&c.attr("name",ib());c.on("click",function(){c[0].checked&&a.$apply(function(){e.$setViewValue(d.value)})});e.$render=function(){c[0].checked=d.value==e.$viewValue};
-d.$observe("value",e.$render)},checkbox:function(a,c,d,e){var f=d.ngTrueValue,g=d.ngFalseValue;G(f)||(f=!0);G(g)||(g=!1);c.on("click",function(){a.$apply(function(){e.$setViewValue(c[0].checked)})});e.$render=function(){c[0].checked=e.$viewValue};e.$isEmpty=function(a){return a!==f};e.$formatters.push(function(a){return a===f});e.$parsers.push(function(a){return a?f:g})},hidden:v,button:v,submit:v,reset:v,file:v},Ye=["badInput"],hc=["$browser","$sniffer",function(a,c){return{restrict:"E",require:"?ngModel",
-link:function(d,e,f,g){g&&(Rc[x(f.type)]||Rc.text)(d,e,f,g,c,a)}}}],wb="ng-valid",xb="ng-invalid",Ra="ng-pristine",zb="ng-dirty",Ze=["$scope","$exceptionHandler","$attrs","$element","$parse","$animate",function(a,c,d,e,f,g){function h(a,c){c=c?"-"+nb(c,"-"):"";g.removeClass(e,(a?xb:wb)+c);g.addClass(e,(a?wb:xb)+c)}this.$modelValue=this.$viewValue=Number.NaN;this.$parsers=[];this.$formatters=[];this.$viewChangeListeners=[];this.$pristine=!0;this.$dirty=!1;this.$valid=!0;this.$invalid=!1;this.$name=
-d.name;var k=f(d.ngModel),m=k.assign;if(!m)throw z("ngModel")("nonassign",d.ngModel,ia(e));this.$render=v;this.$isEmpty=function(a){return F(a)||""===a||null===a||a!==a};var l=e.inheritedData("$formController")||yb,n=0,q=this.$error={};e.addClass(Ra);h(!0);this.$setValidity=function(a,c){q[a]!==!c&&(c?(q[a]&&n--,n||(h(!0),this.$valid=!0,this.$invalid=!1)):(h(!1),this.$invalid=!0,this.$valid=!1,n++),q[a]=!c,h(c,a),l.$setValidity(a,c,this))};this.$setPristine=function(){this.$dirty=!1;this.$pristine=
-!0;g.removeClass(e,zb);g.addClass(e,Ra)};this.$setViewValue=function(d){this.$viewValue=d;this.$pristine&&(this.$dirty=!0,this.$pristine=!1,g.removeClass(e,Ra),g.addClass(e,zb),l.$setDirty());r(this.$parsers,function(a){d=a(d)});this.$modelValue!==d&&(this.$modelValue=d,m(a,d),r(this.$viewChangeListeners,function(a){try{a()}catch(d){c(d)}}))};var p=this;a.$watch(function(){var c=k(a);if(p.$modelValue!==c){var d=p.$formatters,e=d.length;for(p.$modelValue=c;e--;)c=d[e](c);p.$viewValue!==c&&(p.$viewValue=
-c,p.$render())}return c})}],Fd=function(){return{require:["ngModel","^?form"],controller:Ze,link:function(a,c,d,e){var f=e[0],g=e[1]||yb;g.$addControl(f);a.$on("$destroy",function(){g.$removeControl(f)})}}},Hd=aa({require:"ngModel",link:function(a,c,d,e){e.$viewChangeListeners.push(function(){a.$eval(d.ngChange)})}}),ic=function(){return{require:"?ngModel",link:function(a,c,d,e){if(e){d.required=!0;var f=function(a){if(d.required&&e.$isEmpty(a))e.$setValidity("required",!1);else return e.$setValidity("required",
-!0),a};e.$formatters.push(f);e.$parsers.unshift(f);d.$observe("required",function(){f(e.$viewValue)})}}}},Gd=function(){return{require:"ngModel",link:function(a,c,d,e){var f=(a=/\/(.*)\//.exec(d.ngList))&&RegExp(a[1])||d.ngList||",";e.$parsers.push(function(a){if(!F(a)){var c=[];a&&r(a.split(f),function(a){a&&c.push($(a))});return c}});e.$formatters.push(function(a){return L(a)?a.join(", "):u});e.$isEmpty=function(a){return!a||!a.length}}}},$e=/^(true|false|\d+)$/,Id=function(){return{priority:100,
-compile:function(a,c){return $e.test(c.ngValue)?function(a,c,f){f.$set("value",a.$eval(f.ngValue))}:function(a,c,f){a.$watch(f.ngValue,function(a){f.$set("value",a)})}}}},id=Aa({compile:function(a){a.addClass("ng-binding");return function(a,d,e){d.data("$binding",e.ngBind);a.$watch(e.ngBind,function(a){d.text(a==u?"":a)})}}}),kd=["$interpolate",function(a){return function(c,d,e){c=a(d.attr(e.$attr.ngBindTemplate));d.addClass("ng-binding").data("$binding",c);e.$observe("ngBindTemplate",function(a){d.text(a)})}}],
-jd=["$sce","$parse",function(a,c){return{compile:function(d){d.addClass("ng-binding");return function(d,f,g){f.data("$binding",g.ngBindHtml);var h=c(g.ngBindHtml);d.$watch(function(){return(h(d)||"").toString()},function(c){f.html(a.getTrustedHtml(h(d))||"")})}}}}],ld=Wb("",!0),nd=Wb("Odd",0),md=Wb("Even",1),od=Aa({compile:function(a,c){c.$set("ngCloak",u);a.removeClass("ng-cloak")}}),pd=[function(){return{scope:!0,controller:"@",priority:500}}],jc={},af={blur:!0,focus:!0};r("click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave keydown keyup keypress submit focus blur copy cut paste".split(" "),
-function(a){var c=qa("ng-"+a);jc[c]=["$parse","$rootScope",function(d,e){return{compile:function(f,g){var h=d(g[c],!0);return function(c,d){d.on(a,function(d){var f=function(){h(c,{$event:d})};af[a]&&e.$$phase?c.$evalAsync(f):c.$apply(f)})}}}}]});var sd=["$animate",function(a){return{transclude:"element",priority:600,terminal:!0,restrict:"A",$$tlb:!0,link:function(c,d,e,f,g){var h,k,m;c.$watch(e.ngIf,function(f){Wa(f)?k||(k=c.$new(),g(k,function(c){c[c.length++]=X.createComment(" end ngIf: "+e.ngIf+
-" ");h={clone:c};a.enter(c,d.parent(),d)})):(m&&(m.remove(),m=null),k&&(k.$destroy(),k=null),h&&(m=Eb(h.clone),a.leave(m,function(){m=null}),h=null))})}}}],td=["$http","$templateCache","$anchorScroll","$animate","$sce",function(a,c,d,e,f){return{restrict:"ECA",priority:400,terminal:!0,transclude:"element",controller:Xa.noop,compile:function(g,h){var k=h.ngInclude||h.src,m=h.onload||"",l=h.autoscroll;return function(g,h,p,r,J){var w=0,t,y,u,B=function(){y&&(y.remove(),y=null);t&&(t.$destroy(),t=null);
-u&&(e.leave(u,function(){y=null}),y=u,u=null)};g.$watch(f.parseAsResourceUrl(k),function(f){var k=function(){!D(l)||l&&!g.$eval(l)||d()},p=++w;f?(a.get(f,{cache:c}).success(function(a){if(p===w){var c=g.$new();r.template=a;a=J(c,function(a){B();e.enter(a,null,h,k)});t=c;u=a;t.$emit("$includeContentLoaded");g.$eval(m)}}).error(function(){p===w&&B()}),g.$emit("$includeContentRequested")):(B(),r.template=null)})}}}}],Jd=["$compile",function(a){return{restrict:"ECA",priority:-400,require:"ngInclude",
-link:function(c,d,e,f){d.html(f.template);a(d.contents())(c)}}}],ud=Aa({priority:450,compile:function(){return{pre:function(a,c,d){a.$eval(d.ngInit)}}}}),vd=Aa({terminal:!0,priority:1E3}),wd=["$locale","$interpolate",function(a,c){var d=/{}/g;return{restrict:"EA",link:function(e,f,g){var h=g.count,k=g.$attr.when&&f.attr(g.$attr.when),m=g.offset||0,l=e.$eval(k)||{},n={},q=c.startSymbol(),p=c.endSymbol(),s=/^when(Minus)?(.+)$/;r(g,function(a,c){s.test(c)&&(l[x(c.replace("when","").replace("Minus","-"))]=
-f.attr(g.$attr[c]))});r(l,function(a,e){n[e]=c(a.replace(d,q+h+"-"+m+p))});e.$watch(function(){var c=parseFloat(e.$eval(h));if(isNaN(c))return"";c in l||(c=a.pluralCat(c-m));return n[c](e,f,!0)},function(a){f.text(a)})}}}],xd=["$parse","$animate",function(a,c){var d=z("ngRepeat");return{transclude:"element",priority:1E3,terminal:!0,$$tlb:!0,link:function(e,f,g,h,k){var m=g.ngRepeat,l=m.match(/^\s*([\s\S]+?)\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?\s*$/),n,q,p,s,u,w,t={$id:Na};if(!l)throw d("iexp",
-m);g=l[1];h=l[2];(l=l[3])?(n=a(l),q=function(a,c,d){w&&(t[w]=a);t[u]=c;t.$index=d;return n(e,t)}):(p=function(a,c){return Na(c)},s=function(a){return a});l=g.match(/^(?:([\$\w]+)|\(([\$\w]+)\s*,\s*([\$\w]+)\))$/);if(!l)throw d("iidexp",g);u=l[3]||l[1];w=l[2];var y={};e.$watchCollection(h,function(a){var g,h,l=f[0],n,t={},D,C,I,x,G,v,z,F=[];if(Sa(a))v=a,G=q||p;else{G=q||s;v=[];for(I in a)a.hasOwnProperty(I)&&"$"!=I.charAt(0)&&v.push(I);v.sort()}D=v.length;h=F.length=v.length;for(g=0;g<h;g++)if(I=a===
-v?g:v[g],x=a[I],n=G(I,x,g),Ea(n,"`track by` id"),y.hasOwnProperty(n))z=y[n],delete y[n],t[n]=z,F[g]=z;else{if(t.hasOwnProperty(n))throw r(F,function(a){a&&a.scope&&(y[a.id]=a)}),d("dupes",m,n,oa(x));F[g]={id:n};t[n]=!1}for(I in y)y.hasOwnProperty(I)&&(z=y[I],g=Eb(z.clone),c.leave(g),r(g,function(a){a.$$NG_REMOVED=!0}),z.scope.$destroy());g=0;for(h=v.length;g<h;g++){I=a===v?g:v[g];x=a[I];z=F[g];F[g-1]&&(l=F[g-1].clone[F[g-1].clone.length-1]);if(z.scope){C=z.scope;n=l;do n=n.nextSibling;while(n&&n.$$NG_REMOVED);
-z.clone[0]!=n&&c.move(Eb(z.clone),null,A(l));l=z.clone[z.clone.length-1]}else C=e.$new();C[u]=x;w&&(C[w]=I);C.$index=g;C.$first=0===g;C.$last=g===D-1;C.$middle=!(C.$first||C.$last);C.$odd=!(C.$even=0===(g&1));z.scope||k(C,function(a){a[a.length++]=X.createComment(" end ngRepeat: "+m+" ");c.enter(a,null,A(l));l=a;z.scope=C;z.clone=a;t[z.id]=z})}y=t})}}}],yd=["$animate",function(a){return function(c,d,e){c.$watch(e.ngShow,function(c){a[Wa(c)?"removeClass":"addClass"](d,"ng-hide")})}}],rd=["$animate",
-function(a){return function(c,d,e){c.$watch(e.ngHide,function(c){a[Wa(c)?"addClass":"removeClass"](d,"ng-hide")})}}],zd=Aa(function(a,c,d){a.$watch(d.ngStyle,function(a,d){d&&a!==d&&r(d,function(a,d){c.css(d,"")});a&&c.css(a)},!0)}),Ad=["$animate",function(a){return{restrict:"EA",require:"ngSwitch",controller:["$scope",function(){this.cases={}}],link:function(c,d,e,f){var g=[],h=[],k=[],m=[];c.$watch(e.ngSwitch||e.on,function(d){var n,q;n=0;for(q=k.length;n<q;++n)k[n].remove();n=k.length=0;for(q=
-m.length;n<q;++n){var p=h[n];m[n].$destroy();k[n]=p;a.leave(p,function(){k.splice(n,1)})}h.length=0;m.length=0;if(g=f.cases["!"+d]||f.cases["?"])c.$eval(e.change),r(g,function(d){var e=c.$new();m.push(e);d.transclude(e,function(c){var e=d.element;h.push(c);a.enter(c,e.parent(),e)})})})}}}],Bd=Aa({transclude:"element",priority:800,require:"^ngSwitch",link:function(a,c,d,e,f){e.cases["!"+d.ngSwitchWhen]=e.cases["!"+d.ngSwitchWhen]||[];e.cases["!"+d.ngSwitchWhen].push({transclude:f,element:c})}}),Cd=
-Aa({transclude:"element",priority:800,require:"^ngSwitch",link:function(a,c,d,e,f){e.cases["?"]=e.cases["?"]||[];e.cases["?"].push({transclude:f,element:c})}}),Ed=Aa({link:function(a,c,d,e,f){if(!f)throw z("ngTransclude")("orphan",ia(c));f(function(a){c.empty();c.append(a)})}}),ed=["$templateCache",function(a){return{restrict:"E",terminal:!0,compile:function(c,d){"text/ng-template"==d.type&&a.put(d.id,c[0].text)}}}],bf=z("ngOptions"),Dd=aa({terminal:!0}),fd=["$compile","$parse",function(a,c){var d=
-/^\s*([\s\S]+?)(?:\s+as\s+([\s\S]+?))?(?:\s+group\s+by\s+([\s\S]+?))?\s+for\s+(?:([\$\w][\$\w]*)|(?:\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)))\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?$/,e={$setViewValue:v};return{restrict:"E",require:["select","?ngModel"],controller:["$element","$scope","$attrs",function(a,c,d){var k=this,m={},l=e,n;k.databound=d.ngModel;k.init=function(a,c,d){l=a;n=d};k.addOption=function(c){Ea(c,'"option value"');m[c]=!0;l.$viewValue==c&&(a.val(c),n.parent()&&n.remove())};
-k.removeOption=function(a){this.hasOption(a)&&(delete m[a],l.$viewValue==a&&this.renderUnknownOption(a))};k.renderUnknownOption=function(c){c="? "+Na(c)+" ?";n.val(c);a.prepend(n);a.val(c);n.prop("selected",!0)};k.hasOption=function(a){return m.hasOwnProperty(a)};c.$on("$destroy",function(){k.renderUnknownOption=v})}],link:function(e,g,h,k){function m(a,c,d,e){d.$render=function(){var a=d.$viewValue;e.hasOption(a)?(x.parent()&&x.remove(),c.val(a),""===a&&w.prop("selected",!0)):F(a)&&w?c.val(""):e.renderUnknownOption(a)};
-c.on("change",function(){a.$apply(function(){x.parent()&&x.remove();d.$setViewValue(c.val())})})}function l(a,c,d){var e;d.$render=function(){var a=new db(d.$viewValue);r(c.find("option"),function(c){c.selected=D(a.get(c.value))})};a.$watch(function(){Ca(e,d.$viewValue)||(e=ha(d.$viewValue),d.$render())});c.on("change",function(){a.$apply(function(){var a=[];r(c.find("option"),function(c){c.selected&&a.push(c.value)});d.$setViewValue(a)})})}function n(e,f,g){function h(){var a={"":[]},c=[""],d,k,
-s,u,v;s=g.$modelValue;u=A(e)||[];var F=n?Xb(u):u,G,Q,C;Q={};C=!1;if(p)if(k=g.$modelValue,w&&L(k))for(C=new db([]),d={},v=0;v<k.length;v++)d[m]=k[v],C.put(w(e,d),k[v]);else C=new db(k);v=C;var E,K;for(C=0;G=F.length,C<G;C++){k=C;if(n){k=F[C];if("$"===k.charAt(0))continue;Q[n]=k}Q[m]=u[k];d=r(e,Q)||"";(k=a[d])||(k=a[d]=[],c.push(d));p?d=D(v.remove(w?w(e,Q):x(e,Q))):(w?(d={},d[m]=s,d=w(e,d)===w(e,Q)):d=s===x(e,Q),v=v||d);E=l(e,Q);E=D(E)?E:"";k.push({id:w?w(e,Q):n?F[C]:C,label:E,selected:d})}p||(z||null===
-s?a[""].unshift({id:"",label:"",selected:!v}):v||a[""].unshift({id:"?",label:"",selected:!0}));Q=0;for(F=c.length;Q<F;Q++){d=c[Q];k=a[d];B.length<=Q?(s={element:y.clone().attr("label",d),label:k.label},u=[s],B.push(u),f.append(s.element)):(u=B[Q],s=u[0],s.label!=d&&s.element.attr("label",s.label=d));E=null;C=0;for(G=k.length;C<G;C++)d=k[C],(v=u[C+1])?(E=v.element,v.label!==d.label&&(E.text(v.label=d.label),E.prop("label",v.label)),v.id!==d.id&&E.val(v.id=d.id),E[0].selected!==d.selected&&(E.prop("selected",
-v.selected=d.selected),R&&E.prop("selected",v.selected))):(""===d.id&&z?K=z:(K=t.clone()).val(d.id).prop("selected",d.selected).attr("selected",d.selected).prop("label",d.label).text(d.label),u.push({element:K,label:d.label,id:d.id,selected:d.selected}),q.addOption(d.label,K),E?E.after(K):s.element.append(K),E=K);for(C++;u.length>C;)d=u.pop(),q.removeOption(d.label),d.element.remove()}for(;B.length>Q;)B.pop()[0].element.remove()}var k;if(!(k=s.match(d)))throw bf("iexp",s,ia(f));var l=c(k[2]||k[1]),
-m=k[4]||k[6],n=k[5],r=c(k[3]||""),x=c(k[2]?k[1]:m),A=c(k[7]),w=k[8]?c(k[8]):null,B=[[{element:f,label:""}]];z&&(a(z)(e),z.removeClass("ng-scope"),z.remove());f.empty();f.on("change",function(){e.$apply(function(){var a,c=A(e)||[],d={},k,l,q,r,s,t,v;if(p)for(l=[],r=0,t=B.length;r<t;r++)for(a=B[r],q=1,s=a.length;q<s;q++){if((k=a[q].element)[0].selected){k=k.val();n&&(d[n]=k);if(w)for(v=0;v<c.length&&(d[m]=c[v],w(e,d)!=k);v++);else d[m]=c[k];l.push(x(e,d))}}else if(k=f.val(),"?"==k)l=u;else if(""===
-k)l=null;else if(w)for(v=0;v<c.length;v++){if(d[m]=c[v],w(e,d)==k){l=x(e,d);break}}else d[m]=c[k],n&&(d[n]=k),l=x(e,d);g.$setViewValue(l);h()})});g.$render=h;e.$watchCollection(A,h);e.$watchCollection(function(){var a={},c=A(e);if(c){for(var d=Array(c.length),f=0,g=c.length;f<g;f++)a[m]=c[f],d[f]=l(e,a);return d}},h);p&&e.$watchCollection(function(){return g.$modelValue},h)}if(k[1]){var q=k[0];k=k[1];var p=h.multiple,s=h.ngOptions,z=!1,w,t=A(X.createElement("option")),y=A(X.createElement("optgroup")),
-x=t.clone();h=0;for(var B=g.children(),v=B.length;h<v;h++)if(""===B[h].value){w=z=B.eq(h);break}q.init(k,z,x);p&&(k.$isEmpty=function(a){return!a||0===a.length});s?n(e,g,k):p?l(e,g,k):m(e,g,k,q)}}}}],hd=["$interpolate",function(a){var c={addOption:v,removeOption:v};return{restrict:"E",priority:100,compile:function(d,e){if(F(e.value)){var f=a(d.text(),!0);f||e.$set("value",d.text())}return function(a,d,e){var m=d.parent(),l=m.data("$selectController")||m.parent().data("$selectController");l&&l.databound?
-d.prop("selected",!1):l=c;f?a.$watch(f,function(a,c){e.$set("value",a);a!==c&&l.removeOption(c);l.addOption(a)}):l.addOption(e.value);d.on("$destroy",function(){l.removeOption(e.value)})}}}}],gd=aa({restrict:"E",terminal:!0});W.angular.bootstrap?console.log("WARNING: Tried to load angular more than once."):((Fa=W.jQuery)&&Fa.fn.on?(A=Fa,E(Fa.fn,{scope:Oa.scope,isolateScope:Oa.isolateScope,controller:Oa.controller,injector:Oa.injector,inheritedData:Oa.inheritedData}),Gb("remove",!0,!0,!1),Gb("empty",
-!1,!1,!1),Gb("html",!1,!1,!0)):A=S,Xa.element=A,Zc(Xa),A(X).ready(function(){Wc(X,dc)}))})(window,document);!window.angular.$$csp()&&window.angular.element(document).find("head").prepend('<style type="text/css">@charset "UTF-8";[ng\\:cloak],[ng-cloak],[data-ng-cloak],[x-ng-cloak],.ng-cloak,.x-ng-cloak,.ng-hide{display:none !important;}ng\\:form{display:block;}.ng-animate-block-transitions{transition:0s all!important;-webkit-transition:0s all!important;}.ng-hide-add-active,.ng-hide-remove{display:block!important;}</style>');
+(function(O,U,t){'use strict';function J(b){return function(){var a=arguments[0],c;c="["+(b?b+":":"")+a+"] http://errors.angularjs.org/1.4.3/"+(b?b+"/":"")+a;for(a=1;a<arguments.length;a++){c=c+(1==a?"?":"&")+"p"+(a-1)+"=";var d=encodeURIComponent,e;e=arguments[a];e="function"==typeof e?e.toString().replace(/ \{[\s\S]*$/,""):"undefined"==typeof e?"undefined":"string"!=typeof e?JSON.stringify(e):e;c+=d(e)}return Error(c)}}function Ea(b){if(null==b||Wa(b))return!1;var a="length"in Object(b)&&b.length;
+return b.nodeType===qa&&a?!0:L(b)||G(b)||0===a||"number"===typeof a&&0<a&&a-1 in b}function m(b,a,c){var d,e;if(b)if(z(b))for(d in b)"prototype"==d||"length"==d||"name"==d||b.hasOwnProperty&&!b.hasOwnProperty(d)||a.call(c,b[d],d,b);else if(G(b)||Ea(b)){var f="object"!==typeof b;d=0;for(e=b.length;d<e;d++)(f||d in b)&&a.call(c,b[d],d,b)}else if(b.forEach&&b.forEach!==m)b.forEach(a,c,b);else if(nc(b))for(d in b)a.call(c,b[d],d,b);else if("function"===typeof b.hasOwnProperty)for(d in b)b.hasOwnProperty(d)&&
+a.call(c,b[d],d,b);else for(d in b)Xa.call(b,d)&&a.call(c,b[d],d,b);return b}function oc(b,a,c){for(var d=Object.keys(b).sort(),e=0;e<d.length;e++)a.call(c,b[d[e]],d[e]);return d}function pc(b){return function(a,c){b(c,a)}}function Ud(){return++nb}function qc(b,a){a?b.$$hashKey=a:delete b.$$hashKey}function Nb(b,a,c){for(var d=b.$$hashKey,e=0,f=a.length;e<f;++e){var g=a[e];if(H(g)||z(g))for(var h=Object.keys(g),l=0,k=h.length;l<k;l++){var n=h[l],r=g[n];c&&H(r)?aa(r)?b[n]=new Date(r.valueOf()):(H(b[n])||
+(b[n]=G(r)?[]:{}),Nb(b[n],[r],!0)):b[n]=r}}qc(b,d);return b}function P(b){return Nb(b,za.call(arguments,1),!1)}function Vd(b){return Nb(b,za.call(arguments,1),!0)}function W(b){return parseInt(b,10)}function Ob(b,a){return P(Object.create(b),a)}function v(){}function Ya(b){return b}function ra(b){return function(){return b}}function rc(b){return z(b.toString)&&b.toString!==Object.prototype.toString}function A(b){return"undefined"===typeof b}function w(b){return"undefined"!==typeof b}function H(b){return null!==
+b&&"object"===typeof b}function nc(b){return null!==b&&"object"===typeof b&&!sc(b)}function L(b){return"string"===typeof b}function V(b){return"number"===typeof b}function aa(b){return"[object Date]"===sa.call(b)}function z(b){return"function"===typeof b}function Za(b){return"[object RegExp]"===sa.call(b)}function Wa(b){return b&&b.window===b}function $a(b){return b&&b.$evalAsync&&b.$watch}function ab(b){return"boolean"===typeof b}function tc(b){return!(!b||!(b.nodeName||b.prop&&b.attr&&b.find))}
+function Wd(b){var a={};b=b.split(",");var c;for(c=0;c<b.length;c++)a[b[c]]=!0;return a}function ta(b){return M(b.nodeName||b[0]&&b[0].nodeName)}function bb(b,a){var c=b.indexOf(a);0<=c&&b.splice(c,1);return c}function fa(b,a,c,d){if(Wa(b)||$a(b))throw Fa("cpws");if(uc.test(sa.call(a)))throw Fa("cpta");if(a){if(b===a)throw Fa("cpi");c=c||[];d=d||[];H(b)&&(c.push(b),d.push(a));var e;if(G(b))for(e=a.length=0;e<b.length;e++)a.push(fa(b[e],null,c,d));else{var f=a.$$hashKey;G(a)?a.length=0:m(a,function(b,
+c){delete a[c]});if(nc(b))for(e in b)a[e]=fa(b[e],null,c,d);else if(b&&"function"===typeof b.hasOwnProperty)for(e in b)b.hasOwnProperty(e)&&(a[e]=fa(b[e],null,c,d));else for(e in b)Xa.call(b,e)&&(a[e]=fa(b[e],null,c,d));qc(a,f)}}else if(a=b,H(b)){if(c&&-1!==(f=c.indexOf(b)))return d[f];if(G(b))return fa(b,[],c,d);if(uc.test(sa.call(b)))a=new b.constructor(b);else if(aa(b))a=new Date(b.getTime());else if(Za(b))a=new RegExp(b.source,b.toString().match(/[^\/]*$/)[0]),a.lastIndex=b.lastIndex;else return e=
+Object.create(sc(b)),fa(b,e,c,d);d&&(c.push(b),d.push(a))}return a}function ia(b,a){if(G(b)){a=a||[];for(var c=0,d=b.length;c<d;c++)a[c]=b[c]}else if(H(b))for(c in a=a||{},b)if("$"!==c.charAt(0)||"$"!==c.charAt(1))a[c]=b[c];return a||b}function ka(b,a){if(b===a)return!0;if(null===b||null===a)return!1;if(b!==b&&a!==a)return!0;var c=typeof b,d;if(c==typeof a&&"object"==c)if(G(b)){if(!G(a))return!1;if((c=b.length)==a.length){for(d=0;d<c;d++)if(!ka(b[d],a[d]))return!1;return!0}}else{if(aa(b))return aa(a)?
+ka(b.getTime(),a.getTime()):!1;if(Za(b))return Za(a)?b.toString()==a.toString():!1;if($a(b)||$a(a)||Wa(b)||Wa(a)||G(a)||aa(a)||Za(a))return!1;c=ga();for(d in b)if("$"!==d.charAt(0)&&!z(b[d])){if(!ka(b[d],a[d]))return!1;c[d]=!0}for(d in a)if(!(d in c||"$"===d.charAt(0)||a[d]===t||z(a[d])))return!1;return!0}return!1}function cb(b,a,c){return b.concat(za.call(a,c))}function vc(b,a){var c=2<arguments.length?za.call(arguments,2):[];return!z(a)||a instanceof RegExp?a:c.length?function(){return arguments.length?
+a.apply(b,cb(c,arguments,0)):a.apply(b,c)}:function(){return arguments.length?a.apply(b,arguments):a.call(b)}}function Xd(b,a){var c=a;"string"===typeof b&&"$"===b.charAt(0)&&"$"===b.charAt(1)?c=t:Wa(a)?c="$WINDOW":a&&U===a?c="$DOCUMENT":$a(a)&&(c="$SCOPE");return c}function db(b,a){if("undefined"===typeof b)return t;V(a)||(a=a?2:null);return JSON.stringify(b,Xd,a)}function wc(b){return L(b)?JSON.parse(b):b}function xc(b,a){var c=Date.parse("Jan 01, 1970 00:00:00 "+b)/6E4;return isNaN(c)?a:c}function Pb(b,
+a,c){c=c?-1:1;var d=xc(a,b.getTimezoneOffset());a=b;b=c*(d-b.getTimezoneOffset());a=new Date(a.getTime());a.setMinutes(a.getMinutes()+b);return a}function ua(b){b=y(b).clone();try{b.empty()}catch(a){}var c=y("<div>").append(b).html();try{return b[0].nodeType===Na?M(c):c.match(/^(<[^>]+>)/)[1].replace(/^<([\w\-]+)/,function(a,b){return"<"+M(b)})}catch(d){return M(c)}}function yc(b){try{return decodeURIComponent(b)}catch(a){}}function zc(b){var a={},c,d;m((b||"").split("&"),function(b){b&&(c=b.replace(/\+/g,
+"%20").split("="),d=yc(c[0]),w(d)&&(b=w(c[1])?yc(c[1]):!0,Xa.call(a,d)?G(a[d])?a[d].push(b):a[d]=[a[d],b]:a[d]=b))});return a}function Qb(b){var a=[];m(b,function(b,d){G(b)?m(b,function(b){a.push(ma(d,!0)+(!0===b?"":"="+ma(b,!0)))}):a.push(ma(d,!0)+(!0===b?"":"="+ma(b,!0)))});return a.length?a.join("&"):""}function ob(b){return ma(b,!0).replace(/%26/gi,"&").replace(/%3D/gi,"=").replace(/%2B/gi,"+")}function ma(b,a){return encodeURIComponent(b).replace(/%40/gi,"@").replace(/%3A/gi,":").replace(/%24/g,
+"$").replace(/%2C/gi,",").replace(/%3B/gi,";").replace(/%20/g,a?"%20":"+")}function Yd(b,a){var c,d,e=Oa.length;for(d=0;d<e;++d)if(c=Oa[d]+a,L(c=b.getAttribute(c)))return c;return null}function Zd(b,a){var c,d,e={};m(Oa,function(a){a+="app";!c&&b.hasAttribute&&b.hasAttribute(a)&&(c=b,d=b.getAttribute(a))});m(Oa,function(a){a+="app";var e;!c&&(e=b.querySelector("["+a.replace(":","\\:")+"]"))&&(c=e,d=e.getAttribute(a))});c&&(e.strictDi=null!==Yd(c,"strict-di"),a(c,d?[d]:[],e))}function Ac(b,a,c){H(c)||
+(c={});c=P({strictDi:!1},c);var d=function(){b=y(b);if(b.injector()){var d=b[0]===U?"document":ua(b);throw Fa("btstrpd",d.replace(/</,"&lt;").replace(/>/,"&gt;"));}a=a||[];a.unshift(["$provide",function(a){a.value("$rootElement",b)}]);c.debugInfoEnabled&&a.push(["$compileProvider",function(a){a.debugInfoEnabled(!0)}]);a.unshift("ng");d=eb(a,c.strictDi);d.invoke(["$rootScope","$rootElement","$compile","$injector",function(a,b,c,d){a.$apply(function(){b.data("$injector",d);c(b)(a)})}]);return d},e=
+/^NG_ENABLE_DEBUG_INFO!/,f=/^NG_DEFER_BOOTSTRAP!/;O&&e.test(O.name)&&(c.debugInfoEnabled=!0,O.name=O.name.replace(e,""));if(O&&!f.test(O.name))return d();O.name=O.name.replace(f,"");ca.resumeBootstrap=function(b){m(b,function(b){a.push(b)});return d()};z(ca.resumeDeferredBootstrap)&&ca.resumeDeferredBootstrap()}function $d(){O.name="NG_ENABLE_DEBUG_INFO!"+O.name;O.location.reload()}function ae(b){b=ca.element(b).injector();if(!b)throw Fa("test");return b.get("$$testability")}function Bc(b,a){a=a||
+"_";return b.replace(be,function(b,d){return(d?a:"")+b.toLowerCase()})}function ce(){var b;if(!Cc){var a=pb();la=O.jQuery;w(a)&&(la=null===a?t:O[a]);la&&la.fn.on?(y=la,P(la.fn,{scope:Pa.scope,isolateScope:Pa.isolateScope,controller:Pa.controller,injector:Pa.injector,inheritedData:Pa.inheritedData}),b=la.cleanData,la.cleanData=function(a){var d;if(Rb)Rb=!1;else for(var e=0,f;null!=(f=a[e]);e++)(d=la._data(f,"events"))&&d.$destroy&&la(f).triggerHandler("$destroy");b(a)}):y=Q;ca.element=y;Cc=!0}}function Sb(b,
+a,c){if(!b)throw Fa("areq",a||"?",c||"required");return b}function Qa(b,a,c){c&&G(b)&&(b=b[b.length-1]);Sb(z(b),a,"not a function, got "+(b&&"object"===typeof b?b.constructor.name||"Object":typeof b));return b}function Ra(b,a){if("hasOwnProperty"===b)throw Fa("badname",a);}function Dc(b,a,c){if(!a)return b;a=a.split(".");for(var d,e=b,f=a.length,g=0;g<f;g++)d=a[g],b&&(b=(e=b)[d]);return!c&&z(b)?vc(e,b):b}function qb(b){var a=b[0];b=b[b.length-1];var c=[a];do{a=a.nextSibling;if(!a)break;c.push(a)}while(a!==
+b);return y(c)}function ga(){return Object.create(null)}function de(b){function a(a,b,c){return a[b]||(a[b]=c())}var c=J("$injector"),d=J("ng");b=a(b,"angular",Object);b.$$minErr=b.$$minErr||J;return a(b,"module",function(){var b={};return function(f,g,h){if("hasOwnProperty"===f)throw d("badname","module");g&&b.hasOwnProperty(f)&&(b[f]=null);return a(b,f,function(){function a(b,c,e,f){f||(f=d);return function(){f[e||"push"]([b,c,arguments]);return C}}function b(a,c){return function(b,e){e&&z(e)&&
+(e.$$moduleName=f);d.push([a,c,arguments]);return C}}if(!g)throw c("nomod",f);var d=[],e=[],s=[],x=a("$injector","invoke","push",e),C={_invokeQueue:d,_configBlocks:e,_runBlocks:s,requires:g,name:f,provider:b("$provide","provider"),factory:b("$provide","factory"),service:b("$provide","service"),value:a("$provide","value"),constant:a("$provide","constant","unshift"),decorator:b("$provide","decorator"),animation:b("$animateProvider","register"),filter:b("$filterProvider","register"),controller:b("$controllerProvider",
+"register"),directive:b("$compileProvider","directive"),config:x,run:function(a){s.push(a);return this}};h&&x(h);return C})}})}function ee(b){P(b,{bootstrap:Ac,copy:fa,extend:P,merge:Vd,equals:ka,element:y,forEach:m,injector:eb,noop:v,bind:vc,toJson:db,fromJson:wc,identity:Ya,isUndefined:A,isDefined:w,isString:L,isFunction:z,isObject:H,isNumber:V,isElement:tc,isArray:G,version:fe,isDate:aa,lowercase:M,uppercase:rb,callbacks:{counter:0},getTestability:ae,$$minErr:J,$$csp:fb,reloadWithDebugInfo:$d});
+gb=de(O);try{gb("ngLocale")}catch(a){gb("ngLocale",[]).provider("$locale",ge)}gb("ng",["ngLocale"],["$provide",function(a){a.provider({$$sanitizeUri:he});a.provider("$compile",Ec).directive({a:ie,input:Fc,textarea:Fc,form:je,script:ke,select:le,style:me,option:ne,ngBind:oe,ngBindHtml:pe,ngBindTemplate:qe,ngClass:re,ngClassEven:se,ngClassOdd:te,ngCloak:ue,ngController:ve,ngForm:we,ngHide:xe,ngIf:ye,ngInclude:ze,ngInit:Ae,ngNonBindable:Be,ngPluralize:Ce,ngRepeat:De,ngShow:Ee,ngStyle:Fe,ngSwitch:Ge,
+ngSwitchWhen:He,ngSwitchDefault:Ie,ngOptions:Je,ngTransclude:Ke,ngModel:Le,ngList:Me,ngChange:Ne,pattern:Gc,ngPattern:Gc,required:Hc,ngRequired:Hc,minlength:Ic,ngMinlength:Ic,maxlength:Jc,ngMaxlength:Jc,ngValue:Oe,ngModelOptions:Pe}).directive({ngInclude:Qe}).directive(sb).directive(Kc);a.provider({$anchorScroll:Re,$animate:Se,$$animateQueue:Te,$$AnimateRunner:Ue,$browser:Ve,$cacheFactory:We,$controller:Xe,$document:Ye,$exceptionHandler:Ze,$filter:Lc,$interpolate:$e,$interval:af,$http:bf,$httpParamSerializer:cf,
+$httpParamSerializerJQLike:df,$httpBackend:ef,$location:ff,$log:gf,$parse:hf,$rootScope:jf,$q:kf,$$q:lf,$sce:mf,$sceDelegate:nf,$sniffer:of,$templateCache:pf,$templateRequest:qf,$$testability:rf,$timeout:sf,$window:tf,$$rAF:uf,$$jqLite:vf,$$HashMap:wf,$$cookieReader:xf})}])}function hb(b){return b.replace(yf,function(a,b,d,e){return e?d.toUpperCase():d}).replace(zf,"Moz$1")}function Mc(b){b=b.nodeType;return b===qa||!b||9===b}function Nc(b,a){var c,d,e=a.createDocumentFragment(),f=[];if(Tb.test(b)){c=
+c||e.appendChild(a.createElement("div"));d=(Af.exec(b)||["",""])[1].toLowerCase();d=na[d]||na._default;c.innerHTML=d[1]+b.replace(Bf,"<$1></$2>")+d[2];for(d=d[0];d--;)c=c.lastChild;f=cb(f,c.childNodes);c=e.firstChild;c.textContent=""}else f.push(a.createTextNode(b));e.textContent="";e.innerHTML="";m(f,function(a){e.appendChild(a)});return e}function Q(b){if(b instanceof Q)return b;var a;L(b)&&(b=R(b),a=!0);if(!(this instanceof Q)){if(a&&"<"!=b.charAt(0))throw Ub("nosel");return new Q(b)}if(a){a=U;
+var c;b=(c=Cf.exec(b))?[a.createElement(c[1])]:(c=Nc(b,a))?c.childNodes:[]}Oc(this,b)}function Vb(b){return b.cloneNode(!0)}function tb(b,a){a||ub(b);if(b.querySelectorAll)for(var c=b.querySelectorAll("*"),d=0,e=c.length;d<e;d++)ub(c[d])}function Pc(b,a,c,d){if(w(d))throw Ub("offargs");var e=(d=vb(b))&&d.events,f=d&&d.handle;if(f)if(a)m(a.split(" "),function(a){if(w(c)){var d=e[a];bb(d||[],c);if(d&&0<d.length)return}b.removeEventListener(a,f,!1);delete e[a]});else for(a in e)"$destroy"!==a&&b.removeEventListener(a,
+f,!1),delete e[a]}function ub(b,a){var c=b.ng339,d=c&&ib[c];d&&(a?delete d.data[a]:(d.handle&&(d.events.$destroy&&d.handle({},"$destroy"),Pc(b)),delete ib[c],b.ng339=t))}function vb(b,a){var c=b.ng339,c=c&&ib[c];a&&!c&&(b.ng339=c=++Df,c=ib[c]={events:{},data:{},handle:t});return c}function Wb(b,a,c){if(Mc(b)){var d=w(c),e=!d&&a&&!H(a),f=!a;b=(b=vb(b,!e))&&b.data;if(d)b[a]=c;else{if(f)return b;if(e)return b&&b[a];P(b,a)}}}function wb(b,a){return b.getAttribute?-1<(" "+(b.getAttribute("class")||"")+
+" ").replace(/[\n\t]/g," ").indexOf(" "+a+" "):!1}function xb(b,a){a&&b.setAttribute&&m(a.split(" "),function(a){b.setAttribute("class",R((" "+(b.getAttribute("class")||"")+" ").replace(/[\n\t]/g," ").replace(" "+R(a)+" "," ")))})}function yb(b,a){if(a&&b.setAttribute){var c=(" "+(b.getAttribute("class")||"")+" ").replace(/[\n\t]/g," ");m(a.split(" "),function(a){a=R(a);-1===c.indexOf(" "+a+" ")&&(c+=a+" ")});b.setAttribute("class",R(c))}}function Oc(b,a){if(a)if(a.nodeType)b[b.length++]=a;else{var c=
+a.length;if("number"===typeof c&&a.window!==a){if(c)for(var d=0;d<c;d++)b[b.length++]=a[d]}else b[b.length++]=a}}function Qc(b,a){return zb(b,"$"+(a||"ngController")+"Controller")}function zb(b,a,c){9==b.nodeType&&(b=b.documentElement);for(a=G(a)?a:[a];b;){for(var d=0,e=a.length;d<e;d++)if((c=y.data(b,a[d]))!==t)return c;b=b.parentNode||11===b.nodeType&&b.host}}function Rc(b){for(tb(b,!0);b.firstChild;)b.removeChild(b.firstChild)}function Xb(b,a){a||tb(b);var c=b.parentNode;c&&c.removeChild(b)}function Ef(b,
+a){a=a||O;if("complete"===a.document.readyState)a.setTimeout(b);else y(a).on("load",b)}function Sc(b,a){var c=Ab[a.toLowerCase()];return c&&Tc[ta(b)]&&c}function Ff(b,a){var c=b.nodeName;return("INPUT"===c||"TEXTAREA"===c)&&Uc[a]}function Gf(b,a){var c=function(c,e){c.isDefaultPrevented=function(){return c.defaultPrevented};var f=a[e||c.type],g=f?f.length:0;if(g){if(A(c.immediatePropagationStopped)){var h=c.stopImmediatePropagation;c.stopImmediatePropagation=function(){c.immediatePropagationStopped=
+!0;c.stopPropagation&&c.stopPropagation();h&&h.call(c)}}c.isImmediatePropagationStopped=function(){return!0===c.immediatePropagationStopped};1<g&&(f=ia(f));for(var l=0;l<g;l++)c.isImmediatePropagationStopped()||f[l].call(b,c)}};c.elem=b;return c}function vf(){this.$get=function(){return P(Q,{hasClass:function(b,a){b.attr&&(b=b[0]);return wb(b,a)},addClass:function(b,a){b.attr&&(b=b[0]);return yb(b,a)},removeClass:function(b,a){b.attr&&(b=b[0]);return xb(b,a)}})}}function Ga(b,a){var c=b&&b.$$hashKey;
+if(c)return"function"===typeof c&&(c=b.$$hashKey()),c;c=typeof b;return c="function"==c||"object"==c&&null!==b?b.$$hashKey=c+":"+(a||Ud)():c+":"+b}function Sa(b,a){if(a){var c=0;this.nextUid=function(){return++c}}m(b,this.put,this)}function Hf(b){return(b=b.toString().replace(Vc,"").match(Wc))?"function("+(b[1]||"").replace(/[\s\r\n]+/," ")+")":"fn"}function eb(b,a){function c(a){return function(b,c){if(H(b))m(b,pc(a));else return a(b,c)}}function d(a,b){Ra(a,"service");if(z(b)||G(b))b=s.instantiate(b);
+if(!b.$get)throw Ha("pget",a);return r[a+"Provider"]=b}function e(a,b){return function(){var c=C.invoke(b,this);if(A(c))throw Ha("undef",a);return c}}function f(a,b,c){return d(a,{$get:!1!==c?e(a,b):b})}function g(a){var b=[],c;m(a,function(a){function d(a){var b,c;b=0;for(c=a.length;b<c;b++){var e=a[b],f=s.get(e[0]);f[e[1]].apply(f,e[2])}}if(!n.get(a)){n.put(a,!0);try{L(a)?(c=gb(a),b=b.concat(g(c.requires)).concat(c._runBlocks),d(c._invokeQueue),d(c._configBlocks)):z(a)?b.push(s.invoke(a)):G(a)?
+b.push(s.invoke(a)):Qa(a,"module")}catch(e){throw G(a)&&(a=a[a.length-1]),e.message&&e.stack&&-1==e.stack.indexOf(e.message)&&(e=e.message+"\n"+e.stack),Ha("modulerr",a,e.stack||e.message||e);}}});return b}function h(b,c){function d(a,e){if(b.hasOwnProperty(a)){if(b[a]===l)throw Ha("cdep",a+" <- "+k.join(" <- "));return b[a]}try{return k.unshift(a),b[a]=l,b[a]=c(a,e)}catch(f){throw b[a]===l&&delete b[a],f;}finally{k.shift()}}function e(b,c,f,g){"string"===typeof f&&(g=f,f=null);var h=[],k=eb.$$annotate(b,
+a,g),l,s,n;s=0;for(l=k.length;s<l;s++){n=k[s];if("string"!==typeof n)throw Ha("itkn",n);h.push(f&&f.hasOwnProperty(n)?f[n]:d(n,g))}G(b)&&(b=b[l]);return b.apply(c,h)}return{invoke:e,instantiate:function(a,b,c){var d=Object.create((G(a)?a[a.length-1]:a).prototype||null);a=e(a,d,b,c);return H(a)||z(a)?a:d},get:d,annotate:eb.$$annotate,has:function(a){return r.hasOwnProperty(a+"Provider")||b.hasOwnProperty(a)}}}a=!0===a;var l={},k=[],n=new Sa([],!0),r={$provide:{provider:c(d),factory:c(f),service:c(function(a,
+b){return f(a,["$injector",function(a){return a.instantiate(b)}])}),value:c(function(a,b){return f(a,ra(b),!1)}),constant:c(function(a,b){Ra(a,"constant");r[a]=b;x[a]=b}),decorator:function(a,b){var c=s.get(a+"Provider"),d=c.$get;c.$get=function(){var a=C.invoke(d,c);return C.invoke(b,null,{$delegate:a})}}}},s=r.$injector=h(r,function(a,b){ca.isString(b)&&k.push(b);throw Ha("unpr",k.join(" <- "));}),x={},C=x.$injector=h(x,function(a,b){var c=s.get(a+"Provider",b);return C.invoke(c.$get,c,t,a)});m(g(b),
+function(a){a&&C.invoke(a)});return C}function Re(){var b=!0;this.disableAutoScrolling=function(){b=!1};this.$get=["$window","$location","$rootScope",function(a,c,d){function e(a){var b=null;Array.prototype.some.call(a,function(a){if("a"===ta(a))return b=a,!0});return b}function f(b){if(b){b.scrollIntoView();var c;c=g.yOffset;z(c)?c=c():tc(c)?(c=c[0],c="fixed"!==a.getComputedStyle(c).position?0:c.getBoundingClientRect().bottom):V(c)||(c=0);c&&(b=b.getBoundingClientRect().top,a.scrollBy(0,b-c))}else a.scrollTo(0,
+0)}function g(a){a=L(a)?a:c.hash();var b;a?(b=h.getElementById(a))?f(b):(b=e(h.getElementsByName(a)))?f(b):"top"===a&&f(null):f(null)}var h=a.document;b&&d.$watch(function(){return c.hash()},function(a,b){a===b&&""===a||Ef(function(){d.$evalAsync(g)})});return g}]}function jb(b,a){if(!b&&!a)return"";if(!b)return a;if(!a)return b;G(b)&&(b=b.join(" "));G(a)&&(a=a.join(" "));return b+" "+a}function If(b){L(b)&&(b=b.split(" "));var a=ga();m(b,function(b){b.length&&(a[b]=!0)});return a}function Ia(b){return H(b)?
+b:{}}function Jf(b,a,c,d){function e(a){try{a.apply(null,za.call(arguments,1))}finally{if(C--,0===C)for(;F.length;)try{F.pop()()}catch(b){c.error(b)}}}function f(){g();h()}function g(){a:{try{u=n.state;break a}catch(a){}u=void 0}u=A(u)?null:u;ka(u,D)&&(u=D);D=u}function h(){if(K!==l.url()||p!==u)K=l.url(),p=u,m(B,function(a){a(l.url(),u)})}var l=this,k=b.location,n=b.history,r=b.setTimeout,s=b.clearTimeout,x={};l.isMock=!1;var C=0,F=[];l.$$completeOutstandingRequest=e;l.$$incOutstandingRequestCount=
+function(){C++};l.notifyWhenNoOutstandingRequests=function(a){0===C?a():F.push(a)};var u,p,K=k.href,q=a.find("base"),I=null;g();p=u;l.url=function(a,c,e){A(e)&&(e=null);k!==b.location&&(k=b.location);n!==b.history&&(n=b.history);if(a){var f=p===e;if(K===a&&(!d.history||f))return l;var h=K&&Ja(K)===Ja(a);K=a;p=e;if(!d.history||h&&f){if(!h||I)I=a;c?k.replace(a):h?(c=k,e=a.indexOf("#"),a=-1===e?"":a.substr(e),c.hash=a):k.href=a}else n[c?"replaceState":"pushState"](e,"",a),g(),p=u;return l}return I||
+k.href.replace(/%27/g,"'")};l.state=function(){return u};var B=[],N=!1,D=null;l.onUrlChange=function(a){if(!N){if(d.history)y(b).on("popstate",f);y(b).on("hashchange",f);N=!0}B.push(a);return a};l.$$applicationDestroyed=function(){y(b).off("hashchange popstate",f)};l.$$checkUrlChange=h;l.baseHref=function(){var a=q.attr("href");return a?a.replace(/^(https?\:)?\/\/[^\/]*/,""):""};l.defer=function(a,b){var c;C++;c=r(function(){delete x[c];e(a)},b||0);x[c]=!0;return c};l.defer.cancel=function(a){return x[a]?
+(delete x[a],s(a),e(v),!0):!1}}function Ve(){this.$get=["$window","$log","$sniffer","$document",function(b,a,c,d){return new Jf(b,d,a,c)}]}function We(){this.$get=function(){function b(b,d){function e(a){a!=r&&(s?s==a&&(s=a.n):s=a,f(a.n,a.p),f(a,r),r=a,r.n=null)}function f(a,b){a!=b&&(a&&(a.p=b),b&&(b.n=a))}if(b in a)throw J("$cacheFactory")("iid",b);var g=0,h=P({},d,{id:b}),l={},k=d&&d.capacity||Number.MAX_VALUE,n={},r=null,s=null;return a[b]={put:function(a,b){if(!A(b)){if(k<Number.MAX_VALUE){var c=
+n[a]||(n[a]={key:a});e(c)}a in l||g++;l[a]=b;g>k&&this.remove(s.key);return b}},get:function(a){if(k<Number.MAX_VALUE){var b=n[a];if(!b)return;e(b)}return l[a]},remove:function(a){if(k<Number.MAX_VALUE){var b=n[a];if(!b)return;b==r&&(r=b.p);b==s&&(s=b.n);f(b.n,b.p);delete n[a]}delete l[a];g--},removeAll:function(){l={};g=0;n={};r=s=null},destroy:function(){n=h=l=null;delete a[b]},info:function(){return P({},h,{size:g})}}}var a={};b.info=function(){var b={};m(a,function(a,e){b[e]=a.info()});return b};
+b.get=function(b){return a[b]};return b}}function pf(){this.$get=["$cacheFactory",function(b){return b("templates")}]}function Ec(b,a){function c(a,b,c){var d=/^\s*([@&]|=(\*?))(\??)\s*(\w*)\s*$/,e={};m(a,function(a,f){var g=a.match(d);if(!g)throw ea("iscp",b,f,a,c?"controller bindings definition":"isolate scope definition");e[f]={mode:g[1][0],collection:"*"===g[2],optional:"?"===g[3],attrName:g[4]||f}});return e}function d(a){var b=a.charAt(0);if(!b||b!==M(b))throw ea("baddir",a);if(a!==a.trim())throw ea("baddir",
+a);}var e={},f=/^\s*directive\:\s*([\w\-]+)\s+(.*)$/,g=/(([\w\-]+)(?:\:([^;]+))?;?)/,h=Wd("ngSrc,ngSrcset,src,srcset"),l=/^(?:(\^\^?)?(\?)?(\^\^?)?)?/,k=/^(on[a-z]+|formaction)$/;this.directive=function s(a,f){Ra(a,"directive");L(a)?(d(a),Sb(f,"directiveFactory"),e.hasOwnProperty(a)||(e[a]=[],b.factory(a+"Directive",["$injector","$exceptionHandler",function(b,d){var f=[];m(e[a],function(e,g){try{var h=b.invoke(e);z(h)?h={compile:ra(h)}:!h.compile&&h.link&&(h.compile=ra(h.link));h.priority=h.priority||
+0;h.index=g;h.name=h.name||a;h.require=h.require||h.controller&&h.name;h.restrict=h.restrict||"EA";var k=h,l=h,s=h.name,n={isolateScope:null,bindToController:null};H(l.scope)&&(!0===l.bindToController?(n.bindToController=c(l.scope,s,!0),n.isolateScope={}):n.isolateScope=c(l.scope,s,!1));H(l.bindToController)&&(n.bindToController=c(l.bindToController,s,!0));if(H(n.bindToController)){var C=l.controller,$=l.controllerAs;if(!C)throw ea("noctrl",s);var ha;a:if($&&L($))ha=$;else{if(L(C)){var m=Xc.exec(C);
+if(m){ha=m[3];break a}}ha=void 0}if(!ha)throw ea("noident",s);}var q=k.$$bindings=n;H(q.isolateScope)&&(h.$$isolateBindings=q.isolateScope);h.$$moduleName=e.$$moduleName;f.push(h)}catch(t){d(t)}});return f}])),e[a].push(f)):m(a,pc(s));return this};this.aHrefSanitizationWhitelist=function(b){return w(b)?(a.aHrefSanitizationWhitelist(b),this):a.aHrefSanitizationWhitelist()};this.imgSrcSanitizationWhitelist=function(b){return w(b)?(a.imgSrcSanitizationWhitelist(b),this):a.imgSrcSanitizationWhitelist()};
+var n=!0;this.debugInfoEnabled=function(a){return w(a)?(n=a,this):n};this.$get=["$injector","$interpolate","$exceptionHandler","$templateRequest","$parse","$controller","$rootScope","$document","$sce","$animate","$$sanitizeUri",function(a,b,c,d,u,p,K,q,I,B,N){function D(a,b){try{a.addClass(b)}catch(c){}}function Z(a,b,c,d,e){a instanceof y||(a=y(a));m(a,function(b,c){b.nodeType==Na&&b.nodeValue.match(/\S+/)&&(a[c]=y(b).wrap("<span></span>").parent()[0])});var f=S(a,b,a,c,d,e);Z.$$addScopeClass(a);
+var g=null;return function(b,c,d){Sb(b,"scope");d=d||{};var e=d.parentBoundTranscludeFn,h=d.transcludeControllers;d=d.futureParentElement;e&&e.$$boundTransclude&&(e=e.$$boundTransclude);g||(g=(d=d&&d[0])?"foreignobject"!==ta(d)&&d.toString().match(/SVG/)?"svg":"html":"html");d="html"!==g?y(Yb(g,y("<div>").append(a).html())):c?Pa.clone.call(a):a;if(h)for(var k in h)d.data("$"+k+"Controller",h[k].instance);Z.$$addScopeInfo(d,b);c&&c(d,b);f&&f(b,d,d,e);return d}}function S(a,b,c,d,e,f){function g(a,
+c,d,e){var f,k,l,s,n,B,C;if(p)for(C=Array(c.length),s=0;s<h.length;s+=3)f=h[s],C[f]=c[f];else C=c;s=0;for(n=h.length;s<n;)if(k=C[h[s++]],c=h[s++],f=h[s++],c){if(c.scope){if(l=a.$new(),Z.$$addScopeInfo(y(k),l),B=c.$$destroyBindings)c.$$destroyBindings=null,l.$on("$destroyed",B)}else l=a;B=c.transcludeOnThisElement?$(a,c.transclude,e):!c.templateOnThisElement&&e?e:!e&&b?$(a,b):null;c(f,l,k,d,B,c)}else f&&f(a,k.childNodes,t,e)}for(var h=[],k,l,s,n,p,B=0;B<a.length;B++){k=new aa;l=ha(a[B],[],k,0===B?
+d:t,e);(f=l.length?E(l,a[B],k,b,c,null,[],[],f):null)&&f.scope&&Z.$$addScopeClass(k.$$element);k=f&&f.terminal||!(s=a[B].childNodes)||!s.length?null:S(s,f?(f.transcludeOnThisElement||!f.templateOnThisElement)&&f.transclude:b);if(f||k)h.push(B,f,k),n=!0,p=p||f;f=null}return n?g:null}function $(a,b,c){return function(d,e,f,g,h){d||(d=a.$new(!1,h),d.$$transcluded=!0);return b(d,e,{parentBoundTranscludeFn:c,transcludeControllers:f,futureParentElement:g})}}function ha(a,b,c,d,e){var h=c.$attr,k;switch(a.nodeType){case qa:w(b,
+wa(ta(a)),"E",d,e);for(var l,s,n,p=a.attributes,B=0,C=p&&p.length;B<C;B++){var x=!1,S=!1;l=p[B];k=l.name;s=R(l.value);l=wa(k);if(n=ia.test(l))k=k.replace(Zc,"").substr(8).replace(/_(.)/g,function(a,b){return b.toUpperCase()});var F=l.replace(/(Start|End)$/,"");A(F)&&l===F+"Start"&&(x=k,S=k.substr(0,k.length-5)+"end",k=k.substr(0,k.length-6));l=wa(k.toLowerCase());h[l]=k;if(n||!c.hasOwnProperty(l))c[l]=s,Sc(a,l)&&(c[l]=!0);V(a,b,s,l,n);w(b,l,"A",d,e,x,S)}a=a.className;H(a)&&(a=a.animVal);if(L(a)&&
+""!==a)for(;k=g.exec(a);)l=wa(k[2]),w(b,l,"C",d,e)&&(c[l]=R(k[3])),a=a.substr(k.index+k[0].length);break;case Na:if(11===Ua)for(;a.parentNode&&a.nextSibling&&a.nextSibling.nodeType===Na;)a.nodeValue+=a.nextSibling.nodeValue,a.parentNode.removeChild(a.nextSibling);xa(b,a.nodeValue);break;case 8:try{if(k=f.exec(a.nodeValue))l=wa(k[1]),w(b,l,"M",d,e)&&(c[l]=R(k[2]))}catch($){}}b.sort(Aa);return b}function va(a,b,c){var d=[],e=0;if(b&&a.hasAttribute&&a.hasAttribute(b)){do{if(!a)throw ea("uterdir",b,c);
+a.nodeType==qa&&(a.hasAttribute(b)&&e++,a.hasAttribute(c)&&e--);d.push(a);a=a.nextSibling}while(0<e)}else d.push(a);return y(d)}function Yc(a,b,c){return function(d,e,f,g,h){e=va(e[0],b,c);return a(d,e,f,g,h)}}function E(a,b,d,e,f,g,h,k,s){function n(a,b,c,d){if(a){c&&(a=Yc(a,c,d));a.require=E.require;a.directiveName=w;if(u===E||E.$$isolateScope)a=X(a,{isolateScope:!0});h.push(a)}if(b){c&&(b=Yc(b,c,d));b.require=E.require;b.directiveName=w;if(u===E||E.$$isolateScope)b=X(b,{isolateScope:!0});k.push(b)}}
+function B(a,b,c,d){var e;if(L(b)){var f=b.match(l);b=b.substring(f[0].length);var g=f[1]||f[3],f="?"===f[2];"^^"===g?c=c.parent():e=(e=d&&d[b])&&e.instance;e||(d="$"+b+"Controller",e=g?c.inheritedData(d):c.data(d));if(!e&&!f)throw ea("ctreq",b,a);}else if(G(b))for(e=[],g=0,f=b.length;g<f;g++)e[g]=B(a,b[g],c,d);return e||null}function x(a,b,c,d,e,f){var g=ga(),h;for(h in d){var k=d[h],l={$scope:k===u||k.$$isolateScope?e:f,$element:a,$attrs:b,$transclude:c},s=k.controller;"@"==s&&(s=b[k.name]);l=p(s,
+l,!0,k.controllerAs);g[k.name]=l;q||a.data("$"+k.name+"Controller",l.instance)}return g}function S(a,c,e,f,g,l){function s(a,b,c){var d;$a(a)||(c=b,b=a,a=t);q&&(d=m);c||(c=q?ja.parent():ja);return g(a,b,d,c,va)}var n,p,C,F,m,ha,ja;b===e?(f=d,ja=d.$$element):(ja=y(e),f=new aa(ja,d));u&&(F=c.$new(!0));g&&(ha=s,ha.$$boundTransclude=g);N&&(m=x(ja,f,ha,N,F,c));u&&(Z.$$addScopeInfo(ja,F,!0,!(D&&(D===u||D===u.$$originalDirective))),Z.$$addScopeClass(ja,!0),F.$$isolateBindings=u.$$isolateBindings,W(c,f,F,
+F.$$isolateBindings,u,F));if(m){var K=u||$,I;K&&m[K.name]&&(p=K.$$bindings.bindToController,(C=m[K.name])&&C.identifier&&p&&(I=C,l.$$destroyBindings=W(c,f,C.instance,p,K)));for(n in m){C=m[n];var E=C();E!==C.instance&&(C.instance=E,ja.data("$"+n+"Controller",E),C===I&&(l.$$destroyBindings(),l.$$destroyBindings=W(c,f,E,p,K)))}}n=0;for(l=h.length;n<l;n++)p=h[n],Y(p,p.isolateScope?F:c,ja,f,p.require&&B(p.directiveName,p.require,ja,m),ha);var va=c;u&&(u.template||null===u.templateUrl)&&(va=F);a&&a(va,
+e.childNodes,t,g);for(n=k.length-1;0<=n;n--)p=k[n],Y(p,p.isolateScope?F:c,ja,f,p.require&&B(p.directiveName,p.require,ja,m),ha)}s=s||{};for(var F=-Number.MAX_VALUE,$=s.newScopeDirective,N=s.controllerDirectives,u=s.newIsolateScopeDirective,D=s.templateDirective,m=s.nonTlbTranscludeDirective,K=!1,I=!1,q=s.hasElementTranscludeDirective,ba=d.$$element=y(b),E,w,v,A=e,Aa,xa=0,Ta=a.length;xa<Ta;xa++){E=a[xa];var M=E.$$start,P=E.$$end;M&&(ba=va(b,M,P));v=t;if(F>E.priority)break;if(v=E.scope)E.templateUrl||
+(H(v)?(O("new/isolated scope",u||$,E,ba),u=E):O("new/isolated scope",u,E,ba)),$=$||E;w=E.name;!E.templateUrl&&E.controller&&(v=E.controller,N=N||ga(),O("'"+w+"' controller",N[w],E,ba),N[w]=E);if(v=E.transclude)K=!0,E.$$tlb||(O("transclusion",m,E,ba),m=E),"element"==v?(q=!0,F=E.priority,v=ba,ba=d.$$element=y(U.createComment(" "+w+": "+d[w]+" ")),b=ba[0],T(f,za.call(v,0),b),A=Z(v,e,F,g&&g.name,{nonTlbTranscludeDirective:m})):(v=y(Vb(b)).contents(),ba.empty(),A=Z(v,e));if(E.template)if(I=!0,O("template",
+D,E,ba),D=E,v=z(E.template)?E.template(ba,d):E.template,v=fa(v),E.replace){g=E;v=Tb.test(v)?$c(Yb(E.templateNamespace,R(v))):[];b=v[0];if(1!=v.length||b.nodeType!==qa)throw ea("tplrt",w,"");T(f,ba,b);Ta={$attr:{}};v=ha(b,[],Ta);var Q=a.splice(xa+1,a.length-(xa+1));u&&ad(v);a=a.concat(v).concat(Q);J(d,Ta);Ta=a.length}else ba.html(v);if(E.templateUrl)I=!0,O("template",D,E,ba),D=E,E.replace&&(g=E),S=Lf(a.splice(xa,a.length-xa),ba,d,f,K&&A,h,k,{controllerDirectives:N,newScopeDirective:$!==E&&$,newIsolateScopeDirective:u,
+templateDirective:D,nonTlbTranscludeDirective:m}),Ta=a.length;else if(E.compile)try{Aa=E.compile(ba,d,A),z(Aa)?n(null,Aa,M,P):Aa&&n(Aa.pre,Aa.post,M,P)}catch(Kf){c(Kf,ua(ba))}E.terminal&&(S.terminal=!0,F=Math.max(F,E.priority))}S.scope=$&&!0===$.scope;S.transcludeOnThisElement=K;S.templateOnThisElement=I;S.transclude=A;s.hasElementTranscludeDirective=q;return S}function ad(a){for(var b=0,c=a.length;b<c;b++)a[b]=Ob(a[b],{$$isolateScope:!0})}function w(b,d,f,g,h,k,l){if(d===h)return null;h=null;if(e.hasOwnProperty(d)){var n;
+d=a.get(d+"Directive");for(var p=0,B=d.length;p<B;p++)try{n=d[p],(g===t||g>n.priority)&&-1!=n.restrict.indexOf(f)&&(k&&(n=Ob(n,{$$start:k,$$end:l})),b.push(n),h=n)}catch(x){c(x)}}return h}function A(b){if(e.hasOwnProperty(b))for(var c=a.get(b+"Directive"),d=0,f=c.length;d<f;d++)if(b=c[d],b.multiElement)return!0;return!1}function J(a,b){var c=b.$attr,d=a.$attr,e=a.$$element;m(a,function(d,e){"$"!=e.charAt(0)&&(b[e]&&b[e]!==d&&(d+=("style"===e?";":" ")+b[e]),a.$set(e,d,!0,c[e]))});m(b,function(b,f){"class"==
+f?(D(e,b),a["class"]=(a["class"]?a["class"]+" ":"")+b):"style"==f?(e.attr("style",e.attr("style")+";"+b),a.style=(a.style?a.style+";":"")+b):"$"==f.charAt(0)||a.hasOwnProperty(f)||(a[f]=b,d[f]=c[f])})}function Lf(a,b,c,e,f,g,h,k){var l=[],s,n,p=b[0],B=a.shift(),C=Ob(B,{templateUrl:null,transclude:null,replace:null,$$originalDirective:B}),x=z(B.templateUrl)?B.templateUrl(b,c):B.templateUrl,N=B.templateNamespace;b.empty();d(x).then(function(d){var F,u;d=fa(d);if(B.replace){d=Tb.test(d)?$c(Yb(N,R(d))):
+[];F=d[0];if(1!=d.length||F.nodeType!==qa)throw ea("tplrt",B.name,x);d={$attr:{}};T(e,b,F);var K=ha(F,[],d);H(B.scope)&&ad(K);a=K.concat(a);J(c,d)}else F=p,b.html(d);a.unshift(C);s=E(a,F,c,f,b,B,g,h,k);m(e,function(a,c){a==F&&(e[c]=b[0])});for(n=S(b[0].childNodes,f);l.length;){d=l.shift();u=l.shift();var I=l.shift(),va=l.shift(),K=b[0];if(!d.$$destroyed){if(u!==p){var Z=u.className;k.hasElementTranscludeDirective&&B.replace||(K=Vb(F));T(I,y(u),K);D(y(K),Z)}u=s.transcludeOnThisElement?$(d,s.transclude,
+va):va;s(n,d,K,e,u,s)}}l=null});return function(a,b,c,d,e){a=e;b.$$destroyed||(l?l.push(b,c,d,a):(s.transcludeOnThisElement&&(a=$(b,s.transclude,e)),s(n,b,c,d,a,s)))}}function Aa(a,b){var c=b.priority-a.priority;return 0!==c?c:a.name!==b.name?a.name<b.name?-1:1:a.index-b.index}function O(a,b,c,d){function e(a){return a?" (module: "+a+")":""}if(b)throw ea("multidir",b.name,e(b.$$moduleName),c.name,e(c.$$moduleName),a,ua(d));}function xa(a,c){var d=b(c,!0);d&&a.push({priority:0,compile:function(a){a=
+a.parent();var b=!!a.length;b&&Z.$$addBindingClass(a);return function(a,c){var e=c.parent();b||Z.$$addBindingClass(e);Z.$$addBindingInfo(e,d.expressions);a.$watch(d,function(a){c[0].nodeValue=a})}}})}function Yb(a,b){a=M(a||"html");switch(a){case "svg":case "math":var c=U.createElement("div");c.innerHTML="<"+a+">"+b+"</"+a+">";return c.childNodes[0].childNodes;default:return b}}function Q(a,b){if("srcdoc"==b)return I.HTML;var c=ta(a);if("xlinkHref"==b||"form"==c&&"action"==b||"img"!=c&&("src"==b||
+"ngSrc"==b))return I.RESOURCE_URL}function V(a,c,d,e,f){var g=Q(a,e);f=h[e]||f;var l=b(d,!0,g,f);if(l){if("multiple"===e&&"select"===ta(a))throw ea("selmulti",ua(a));c.push({priority:100,compile:function(){return{pre:function(a,c,h){c=h.$$observers||(h.$$observers={});if(k.test(e))throw ea("nodomevents");var s=h[e];s!==d&&(l=s&&b(s,!0,g,f),d=s);l&&(h[e]=l(a),(c[e]||(c[e]=[])).$$inter=!0,(h.$$observers&&h.$$observers[e].$$scope||a).$watch(l,function(a,b){"class"===e&&a!=b?h.$updateClass(a,b):h.$set(e,
+a)}))}}}})}}function T(a,b,c){var d=b[0],e=b.length,f=d.parentNode,g,h;if(a)for(g=0,h=a.length;g<h;g++)if(a[g]==d){a[g++]=c;h=g+e-1;for(var k=a.length;g<k;g++,h++)h<k?a[g]=a[h]:delete a[g];a.length-=e-1;a.context===d&&(a.context=c);break}f&&f.replaceChild(c,d);a=U.createDocumentFragment();a.appendChild(d);y.hasData(d)&&(y(c).data(y(d).data()),la?(Rb=!0,la.cleanData([d])):delete y.cache[d[y.expando]]);d=1;for(e=b.length;d<e;d++)f=b[d],y(f).remove(),a.appendChild(f),delete b[d];b[0]=c;b.length=1}function X(a,
+b){return P(function(){return a.apply(null,arguments)},a,b)}function Y(a,b,d,e,f,g){try{a(b,d,e,f,g)}catch(h){c(h,ua(d))}}function W(a,c,d,e,f,g){var h;m(e,function(e,g){var k=e.attrName,l=e.optional,s=e.mode,n,p,B,C;Xa.call(c,k)||(c[k]=t);switch(s){case "@":c[k]||l||(d[g]=t);c.$observe(k,function(a){d[g]=a});c.$$observers[k].$$scope=a;c[k]&&(d[g]=b(c[k])(a));break;case "=":if(l&&!c[k])break;p=u(c[k]);C=p.literal?ka:function(a,b){return a===b||a!==a&&b!==b};B=p.assign||function(){n=d[g]=p(a);throw ea("nonassign",
+c[k],f.name);};n=d[g]=p(a);l=function(b){C(b,d[g])||(C(b,n)?B(a,b=d[g]):d[g]=b);return n=b};l.$stateful=!0;l=e.collection?a.$watchCollection(c[k],l):a.$watch(u(c[k],l),null,p.literal);h=h||[];h.push(l);break;case "&":p=u(c[k]);if(p===v&&l)break;d[g]=function(b){return p(a,b)}}});e=h?function(){for(var a=0,b=h.length;a<b;++a)h[a]()}:v;return g&&e!==v?(g.$on("$destroy",e),v):e}var aa=function(a,b){if(b){var c=Object.keys(b),d,e,f;d=0;for(e=c.length;d<e;d++)f=c[d],this[f]=b[f]}else this.$attr={};this.$$element=
+a};aa.prototype={$normalize:wa,$addClass:function(a){a&&0<a.length&&B.addClass(this.$$element,a)},$removeClass:function(a){a&&0<a.length&&B.removeClass(this.$$element,a)},$updateClass:function(a,b){var c=bd(a,b);c&&c.length&&B.addClass(this.$$element,c);(c=bd(b,a))&&c.length&&B.removeClass(this.$$element,c)},$set:function(a,b,d,e){var f=this.$$element[0],g=Sc(f,a),h=Ff(f,a),f=a;g?(this.$$element.prop(a,b),e=g):h&&(this[h]=b,f=h);this[a]=b;e?this.$attr[a]=e:(e=this.$attr[a])||(this.$attr[a]=e=Bc(a,
+"-"));g=ta(this.$$element);if("a"===g&&"href"===a||"img"===g&&"src"===a)this[a]=b=N(b,"src"===a);else if("img"===g&&"srcset"===a){for(var g="",h=R(b),k=/(\s+\d+x\s*,|\s+\d+w\s*,|\s+,|,\s+)/,k=/\s/.test(h)?k:/(,)/,h=h.split(k),k=Math.floor(h.length/2),l=0;l<k;l++)var s=2*l,g=g+N(R(h[s]),!0),g=g+(" "+R(h[s+1]));h=R(h[2*l]).split(/\s/);g+=N(R(h[0]),!0);2===h.length&&(g+=" "+R(h[1]));this[a]=b=g}!1!==d&&(null===b||b===t?this.$$element.removeAttr(e):this.$$element.attr(e,b));(a=this.$$observers)&&m(a[f],
+function(a){try{a(b)}catch(d){c(d)}})},$observe:function(a,b){var c=this,d=c.$$observers||(c.$$observers=ga()),e=d[a]||(d[a]=[]);e.push(b);K.$evalAsync(function(){!e.$$inter&&c.hasOwnProperty(a)&&b(c[a])});return function(){bb(e,b)}}};var ca=b.startSymbol(),da=b.endSymbol(),fa="{{"==ca||"}}"==da?Ya:function(a){return a.replace(/\{\{/g,ca).replace(/}}/g,da)},ia=/^ngAttr[A-Z]/;Z.$$addBindingInfo=n?function(a,b){var c=a.data("$binding")||[];G(b)?c=c.concat(b):c.push(b);a.data("$binding",c)}:v;Z.$$addBindingClass=
+n?function(a){D(a,"ng-binding")}:v;Z.$$addScopeInfo=n?function(a,b,c,d){a.data(c?d?"$isolateScopeNoTemplate":"$isolateScope":"$scope",b)}:v;Z.$$addScopeClass=n?function(a,b){D(a,b?"ng-isolate-scope":"ng-scope")}:v;return Z}]}function wa(b){return hb(b.replace(Zc,""))}function bd(b,a){var c="",d=b.split(/\s+/),e=a.split(/\s+/),f=0;a:for(;f<d.length;f++){for(var g=d[f],h=0;h<e.length;h++)if(g==e[h])continue a;c+=(0<c.length?" ":"")+g}return c}function $c(b){b=y(b);var a=b.length;if(1>=a)return b;for(;a--;)8===
+b[a].nodeType&&Mf.call(b,a,1);return b}function Xe(){var b={},a=!1;this.register=function(a,d){Ra(a,"controller");H(a)?P(b,a):b[a]=d};this.allowGlobals=function(){a=!0};this.$get=["$injector","$window",function(c,d){function e(a,b,c,d){if(!a||!H(a.$scope))throw J("$controller")("noscp",d,b);a.$scope[b]=c}return function(f,g,h,l){var k,n,r;h=!0===h;l&&L(l)&&(r=l);if(L(f)){l=f.match(Xc);if(!l)throw Nf("ctrlfmt",f);n=l[1];r=r||l[3];f=b.hasOwnProperty(n)?b[n]:Dc(g.$scope,n,!0)||(a?Dc(d,n,!0):t);Qa(f,
+n,!0)}if(h)return h=(G(f)?f[f.length-1]:f).prototype,k=Object.create(h||null),r&&e(g,r,k,n||f.name),P(function(){var a=c.invoke(f,k,g,n);a!==k&&(H(a)||z(a))&&(k=a,r&&e(g,r,k,n||f.name));return k},{instance:k,identifier:r});k=c.instantiate(f,g,n);r&&e(g,r,k,n||f.name);return k}}]}function Ye(){this.$get=["$window",function(b){return y(b.document)}]}function Ze(){this.$get=["$log",function(b){return function(a,c){b.error.apply(b,arguments)}}]}function Zb(b){return H(b)?aa(b)?b.toISOString():db(b):b}
+function cf(){this.$get=function(){return function(b){if(!b)return"";var a=[];oc(b,function(b,d){null===b||A(b)||(G(b)?m(b,function(b,c){a.push(ma(d)+"="+ma(Zb(b)))}):a.push(ma(d)+"="+ma(Zb(b))))});return a.join("&")}}}function df(){this.$get=function(){return function(b){function a(b,e,f){null===b||A(b)||(G(b)?m(b,function(b){a(b,e+"[]")}):H(b)&&!aa(b)?oc(b,function(b,c){a(b,e+(f?"":"[")+c+(f?"":"]"))}):c.push(ma(e)+"="+ma(Zb(b))))}if(!b)return"";var c=[];a(b,"",!0);return c.join("&")}}}function $b(b,
+a){if(L(b)){var c=b.replace(Of,"").trim();if(c){var d=a("Content-Type");(d=d&&0===d.indexOf(cd))||(d=(d=c.match(Pf))&&Qf[d[0]].test(c));d&&(b=wc(c))}}return b}function dd(b){var a=ga(),c;L(b)?m(b.split("\n"),function(b){c=b.indexOf(":");var e=M(R(b.substr(0,c)));b=R(b.substr(c+1));e&&(a[e]=a[e]?a[e]+", "+b:b)}):H(b)&&m(b,function(b,c){var f=M(c),g=R(b);f&&(a[f]=a[f]?a[f]+", "+g:g)});return a}function ed(b){var a;return function(c){a||(a=dd(b));return c?(c=a[M(c)],void 0===c&&(c=null),c):a}}function fd(b,
+a,c,d){if(z(d))return d(b,a,c);m(d,function(d){b=d(b,a,c)});return b}function bf(){var b=this.defaults={transformResponse:[$b],transformRequest:[function(a){return H(a)&&"[object File]"!==sa.call(a)&&"[object Blob]"!==sa.call(a)&&"[object FormData]"!==sa.call(a)?db(a):a}],headers:{common:{Accept:"application/json, text/plain, */*"},post:ia(ac),put:ia(ac),patch:ia(ac)},xsrfCookieName:"XSRF-TOKEN",xsrfHeaderName:"X-XSRF-TOKEN",paramSerializer:"$httpParamSerializer"},a=!1;this.useApplyAsync=function(b){return w(b)?
+(a=!!b,this):a};var c=this.interceptors=[];this.$get=["$httpBackend","$$cookieReader","$cacheFactory","$rootScope","$q","$injector",function(d,e,f,g,h,l){function k(a){function c(a){var b=P({},a);b.data=a.data?fd(a.data,a.headers,a.status,e.transformResponse):a.data;a=a.status;return 200<=a&&300>a?b:h.reject(b)}function d(a,b){var c,e={};m(a,function(a,d){z(a)?(c=a(b),null!=c&&(e[d]=c)):e[d]=a});return e}if(!ca.isObject(a))throw J("$http")("badreq",a);var e=P({method:"get",transformRequest:b.transformRequest,
+transformResponse:b.transformResponse,paramSerializer:b.paramSerializer},a);e.headers=function(a){var c=b.headers,e=P({},a.headers),f,g,h,c=P({},c.common,c[M(a.method)]);a:for(f in c){g=M(f);for(h in e)if(M(h)===g)continue a;e[f]=c[f]}return d(e,ia(a))}(a);e.method=rb(e.method);e.paramSerializer=L(e.paramSerializer)?l.get(e.paramSerializer):e.paramSerializer;var f=[function(a){var d=a.headers,e=fd(a.data,ed(d),t,a.transformRequest);A(e)&&m(d,function(a,b){"content-type"===M(b)&&delete d[b]});A(a.withCredentials)&&
+!A(b.withCredentials)&&(a.withCredentials=b.withCredentials);return n(a,e).then(c,c)},t],g=h.when(e);for(m(x,function(a){(a.request||a.requestError)&&f.unshift(a.request,a.requestError);(a.response||a.responseError)&&f.push(a.response,a.responseError)});f.length;){a=f.shift();var k=f.shift(),g=g.then(a,k)}g.success=function(a){Qa(a,"fn");g.then(function(b){a(b.data,b.status,b.headers,e)});return g};g.error=function(a){Qa(a,"fn");g.then(null,function(b){a(b.data,b.status,b.headers,e)});return g};return g}
+function n(c,f){function l(b,c,d,e){function f(){n(c,b,d,e)}N&&(200<=b&&300>b?N.put(S,[b,c,dd(d),e]):N.remove(S));a?g.$applyAsync(f):(f(),g.$$phase||g.$apply())}function n(a,b,d,e){b=Math.max(b,0);(200<=b&&300>b?I.resolve:I.reject)({data:a,status:b,headers:ed(d),config:c,statusText:e})}function x(a){n(a.data,a.status,ia(a.headers()),a.statusText)}function m(){var a=k.pendingRequests.indexOf(c);-1!==a&&k.pendingRequests.splice(a,1)}var I=h.defer(),B=I.promise,N,D,q=c.headers,S=r(c.url,c.paramSerializer(c.params));
+k.pendingRequests.push(c);B.then(m,m);!c.cache&&!b.cache||!1===c.cache||"GET"!==c.method&&"JSONP"!==c.method||(N=H(c.cache)?c.cache:H(b.cache)?b.cache:s);N&&(D=N.get(S),w(D)?D&&z(D.then)?D.then(x,x):G(D)?n(D[1],D[0],ia(D[2]),D[3]):n(D,200,{},"OK"):N.put(S,B));A(D)&&((D=gd(c.url)?e()[c.xsrfCookieName||b.xsrfCookieName]:t)&&(q[c.xsrfHeaderName||b.xsrfHeaderName]=D),d(c.method,S,f,l,q,c.timeout,c.withCredentials,c.responseType));return B}function r(a,b){0<b.length&&(a+=(-1==a.indexOf("?")?"?":"&")+b);
+return a}var s=f("$http");b.paramSerializer=L(b.paramSerializer)?l.get(b.paramSerializer):b.paramSerializer;var x=[];m(c,function(a){x.unshift(L(a)?l.get(a):l.invoke(a))});k.pendingRequests=[];(function(a){m(arguments,function(a){k[a]=function(b,c){return k(P({},c||{},{method:a,url:b}))}})})("get","delete","head","jsonp");(function(a){m(arguments,function(a){k[a]=function(b,c,d){return k(P({},d||{},{method:a,url:b,data:c}))}})})("post","put","patch");k.defaults=b;return k}]}function Rf(){return new O.XMLHttpRequest}
+function ef(){this.$get=["$browser","$window","$document",function(b,a,c){return Sf(b,Rf,b.defer,a.angular.callbacks,c[0])}]}function Sf(b,a,c,d,e){function f(a,b,c){var f=e.createElement("script"),n=null;f.type="text/javascript";f.src=a;f.async=!0;n=function(a){f.removeEventListener("load",n,!1);f.removeEventListener("error",n,!1);e.body.removeChild(f);f=null;var g=-1,x="unknown";a&&("load"!==a.type||d[b].called||(a={type:"error"}),x=a.type,g="error"===a.type?404:200);c&&c(g,x)};f.addEventListener("load",
+n,!1);f.addEventListener("error",n,!1);e.body.appendChild(f);return n}return function(e,h,l,k,n,r,s,x){function C(){p&&p();K&&K.abort()}function F(a,d,e,f,g){I!==t&&c.cancel(I);p=K=null;a(d,e,f,g);b.$$completeOutstandingRequest(v)}b.$$incOutstandingRequestCount();h=h||b.url();if("jsonp"==M(e)){var u="_"+(d.counter++).toString(36);d[u]=function(a){d[u].data=a;d[u].called=!0};var p=f(h.replace("JSON_CALLBACK","angular.callbacks."+u),u,function(a,b){F(k,a,d[u].data,"",b);d[u]=v})}else{var K=a();K.open(e,
+h,!0);m(n,function(a,b){w(a)&&K.setRequestHeader(b,a)});K.onload=function(){var a=K.statusText||"",b="response"in K?K.response:K.responseText,c=1223===K.status?204:K.status;0===c&&(c=b?200:"file"==Ba(h).protocol?404:0);F(k,c,b,K.getAllResponseHeaders(),a)};e=function(){F(k,-1,null,null,"")};K.onerror=e;K.onabort=e;s&&(K.withCredentials=!0);if(x)try{K.responseType=x}catch(q){if("json"!==x)throw q;}K.send(l)}if(0<r)var I=c(C,r);else r&&z(r.then)&&r.then(C)}}function $e(){var b="{{",a="}}";this.startSymbol=
+function(a){return a?(b=a,this):b};this.endSymbol=function(b){return b?(a=b,this):a};this.$get=["$parse","$exceptionHandler","$sce",function(c,d,e){function f(a){return"\\\\\\"+a}function g(c){return c.replace(n,b).replace(r,a)}function h(f,h,n,r){function u(a){try{var b=a;a=n?e.getTrusted(n,b):e.valueOf(b);var c;if(r&&!w(a))c=a;else if(null==a)c="";else{switch(typeof a){case "string":break;case "number":a=""+a;break;default:a=db(a)}c=a}return c}catch(g){d(Ka.interr(f,g))}}r=!!r;for(var p,m,q=0,I=
+[],B=[],N=f.length,D=[],t=[];q<N;)if(-1!=(p=f.indexOf(b,q))&&-1!=(m=f.indexOf(a,p+l)))q!==p&&D.push(g(f.substring(q,p))),q=f.substring(p+l,m),I.push(q),B.push(c(q,u)),q=m+k,t.push(D.length),D.push("");else{q!==N&&D.push(g(f.substring(q)));break}n&&1<D.length&&Ka.throwNoconcat(f);if(!h||I.length){var S=function(a){for(var b=0,c=I.length;b<c;b++){if(r&&A(a[b]))return;D[t[b]]=a[b]}return D.join("")};return P(function(a){var b=0,c=I.length,e=Array(c);try{for(;b<c;b++)e[b]=B[b](a);return S(e)}catch(g){d(Ka.interr(f,
+g))}},{exp:f,expressions:I,$$watchDelegate:function(a,b){var c;return a.$watchGroup(B,function(d,e){var f=S(d);z(b)&&b.call(this,f,d!==e?c:f,a);c=f})}})}}var l=b.length,k=a.length,n=new RegExp(b.replace(/./g,f),"g"),r=new RegExp(a.replace(/./g,f),"g");h.startSymbol=function(){return b};h.endSymbol=function(){return a};return h}]}function af(){this.$get=["$rootScope","$window","$q","$$q",function(b,a,c,d){function e(e,h,l,k){var n=4<arguments.length,r=n?za.call(arguments,4):[],s=a.setInterval,x=a.clearInterval,
+C=0,F=w(k)&&!k,u=(F?d:c).defer(),p=u.promise;l=w(l)?l:0;p.then(null,null,n?function(){e.apply(null,r)}:e);p.$$intervalId=s(function(){u.notify(C++);0<l&&C>=l&&(u.resolve(C),x(p.$$intervalId),delete f[p.$$intervalId]);F||b.$apply()},h);f[p.$$intervalId]=u;return p}var f={};e.cancel=function(b){return b&&b.$$intervalId in f?(f[b.$$intervalId].reject("canceled"),a.clearInterval(b.$$intervalId),delete f[b.$$intervalId],!0):!1};return e}]}function ge(){this.$get=function(){return{id:"en-us",NUMBER_FORMATS:{DECIMAL_SEP:".",
+GROUP_SEP:",",PATTERNS:[{minInt:1,minFrac:0,maxFrac:3,posPre:"",posSuf:"",negPre:"-",negSuf:"",gSize:3,lgSize:3},{minInt:1,minFrac:2,maxFrac:2,posPre:"\u00a4",posSuf:"",negPre:"(\u00a4",negSuf:")",gSize:3,lgSize:3}],CURRENCY_SYM:"$"},DATETIME_FORMATS:{MONTH:"January February March April May June July August September October November December".split(" "),SHORTMONTH:"Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec".split(" "),DAY:"Sunday Monday Tuesday Wednesday Thursday Friday Saturday".split(" "),
+SHORTDAY:"Sun Mon Tue Wed Thu Fri Sat".split(" "),AMPMS:["AM","PM"],medium:"MMM d, y h:mm:ss a","short":"M/d/yy h:mm a",fullDate:"EEEE, MMMM d, y",longDate:"MMMM d, y",mediumDate:"MMM d, y",shortDate:"M/d/yy",mediumTime:"h:mm:ss a",shortTime:"h:mm a",ERANAMES:["Before Christ","Anno Domini"],ERAS:["BC","AD"]},pluralCat:function(b){return 1===b?"one":"other"}}}}function bc(b){b=b.split("/");for(var a=b.length;a--;)b[a]=ob(b[a]);return b.join("/")}function hd(b,a){var c=Ba(b);a.$$protocol=c.protocol;
+a.$$host=c.hostname;a.$$port=W(c.port)||Tf[c.protocol]||null}function id(b,a){var c="/"!==b.charAt(0);c&&(b="/"+b);var d=Ba(b);a.$$path=decodeURIComponent(c&&"/"===d.pathname.charAt(0)?d.pathname.substring(1):d.pathname);a.$$search=zc(d.search);a.$$hash=decodeURIComponent(d.hash);a.$$path&&"/"!=a.$$path.charAt(0)&&(a.$$path="/"+a.$$path)}function ya(b,a){if(0===a.indexOf(b))return a.substr(b.length)}function Ja(b){var a=b.indexOf("#");return-1==a?b:b.substr(0,a)}function Bb(b){return b.replace(/(#.+)|#$/,
+"$1")}function cc(b){return b.substr(0,Ja(b).lastIndexOf("/")+1)}function dc(b,a){this.$$html5=!0;a=a||"";var c=cc(b);hd(b,this);this.$$parse=function(a){var b=ya(c,a);if(!L(b))throw Cb("ipthprfx",a,c);id(b,this);this.$$path||(this.$$path="/");this.$$compose()};this.$$compose=function(){var a=Qb(this.$$search),b=this.$$hash?"#"+ob(this.$$hash):"";this.$$url=bc(this.$$path)+(a?"?"+a:"")+b;this.$$absUrl=c+this.$$url.substr(1)};this.$$parseLinkUrl=function(d,e){if(e&&"#"===e[0])return this.hash(e.slice(1)),
+!0;var f,g;(f=ya(b,d))!==t?(g=f,g=(f=ya(a,f))!==t?c+(ya("/",f)||f):b+g):(f=ya(c,d))!==t?g=c+f:c==d+"/"&&(g=c);g&&this.$$parse(g);return!!g}}function ec(b,a){var c=cc(b);hd(b,this);this.$$parse=function(d){var e=ya(b,d)||ya(c,d),f;A(e)||"#"!==e.charAt(0)?this.$$html5?f=e:(f="",A(e)&&(b=d,this.replace())):(f=ya(a,e),A(f)&&(f=e));id(f,this);d=this.$$path;var e=b,g=/^\/[A-Z]:(\/.*)/;0===f.indexOf(e)&&(f=f.replace(e,""));g.exec(f)||(d=(f=g.exec(d))?f[1]:d);this.$$path=d;this.$$compose()};this.$$compose=
+function(){var c=Qb(this.$$search),e=this.$$hash?"#"+ob(this.$$hash):"";this.$$url=bc(this.$$path)+(c?"?"+c:"")+e;this.$$absUrl=b+(this.$$url?a+this.$$url:"")};this.$$parseLinkUrl=function(a,c){return Ja(b)==Ja(a)?(this.$$parse(a),!0):!1}}function jd(b,a){this.$$html5=!0;ec.apply(this,arguments);var c=cc(b);this.$$parseLinkUrl=function(d,e){if(e&&"#"===e[0])return this.hash(e.slice(1)),!0;var f,g;b==Ja(d)?f=d:(g=ya(c,d))?f=b+a+g:c===d+"/"&&(f=c);f&&this.$$parse(f);return!!f};this.$$compose=function(){var c=
+Qb(this.$$search),e=this.$$hash?"#"+ob(this.$$hash):"";this.$$url=bc(this.$$path)+(c?"?"+c:"")+e;this.$$absUrl=b+a+this.$$url}}function Db(b){return function(){return this[b]}}function kd(b,a){return function(c){if(A(c))return this[b];this[b]=a(c);this.$$compose();return this}}function ff(){var b="",a={enabled:!1,requireBase:!0,rewriteLinks:!0};this.hashPrefix=function(a){return w(a)?(b=a,this):b};this.html5Mode=function(b){return ab(b)?(a.enabled=b,this):H(b)?(ab(b.enabled)&&(a.enabled=b.enabled),
+ab(b.requireBase)&&(a.requireBase=b.requireBase),ab(b.rewriteLinks)&&(a.rewriteLinks=b.rewriteLinks),this):a};this.$get=["$rootScope","$browser","$sniffer","$rootElement","$window",function(c,d,e,f,g){function h(a,b,c){var e=k.url(),f=k.$$state;try{d.url(a,b,c),k.$$state=d.state()}catch(g){throw k.url(e),k.$$state=f,g;}}function l(a,b){c.$broadcast("$locationChangeSuccess",k.absUrl(),a,k.$$state,b)}var k,n;n=d.baseHref();var r=d.url(),s;if(a.enabled){if(!n&&a.requireBase)throw Cb("nobase");s=r.substring(0,
+r.indexOf("/",r.indexOf("//")+2))+(n||"/");n=e.history?dc:jd}else s=Ja(r),n=ec;k=new n(s,"#"+b);k.$$parseLinkUrl(r,r);k.$$state=d.state();var x=/^\s*(javascript|mailto):/i;f.on("click",function(b){if(a.rewriteLinks&&!b.ctrlKey&&!b.metaKey&&!b.shiftKey&&2!=b.which&&2!=b.button){for(var e=y(b.target);"a"!==ta(e[0]);)if(e[0]===f[0]||!(e=e.parent())[0])return;var h=e.prop("href"),l=e.attr("href")||e.attr("xlink:href");H(h)&&"[object SVGAnimatedString]"===h.toString()&&(h=Ba(h.animVal).href);x.test(h)||
+!h||e.attr("target")||b.isDefaultPrevented()||!k.$$parseLinkUrl(h,l)||(b.preventDefault(),k.absUrl()!=d.url()&&(c.$apply(),g.angular["ff-684208-preventDefault"]=!0))}});Bb(k.absUrl())!=Bb(r)&&d.url(k.absUrl(),!0);var C=!0;d.onUrlChange(function(a,b){c.$evalAsync(function(){var d=k.absUrl(),e=k.$$state,f;k.$$parse(a);k.$$state=b;f=c.$broadcast("$locationChangeStart",a,d,b,e).defaultPrevented;k.absUrl()===a&&(f?(k.$$parse(d),k.$$state=e,h(d,!1,e)):(C=!1,l(d,e)))});c.$$phase||c.$digest()});c.$watch(function(){var a=
+Bb(d.url()),b=Bb(k.absUrl()),f=d.state(),g=k.$$replace,n=a!==b||k.$$html5&&e.history&&f!==k.$$state;if(C||n)C=!1,c.$evalAsync(function(){var b=k.absUrl(),d=c.$broadcast("$locationChangeStart",b,a,k.$$state,f).defaultPrevented;k.absUrl()===b&&(d?(k.$$parse(a),k.$$state=f):(n&&h(b,g,f===k.$$state?null:k.$$state),l(a,f)))});k.$$replace=!1});return k}]}function gf(){var b=!0,a=this;this.debugEnabled=function(a){return w(a)?(b=a,this):b};this.$get=["$window",function(c){function d(a){a instanceof Error&&
+(a.stack?a=a.message&&-1===a.stack.indexOf(a.message)?"Error: "+a.message+"\n"+a.stack:a.stack:a.sourceURL&&(a=a.message+"\n"+a.sourceURL+":"+a.line));return a}function e(a){var b=c.console||{},e=b[a]||b.log||v;a=!1;try{a=!!e.apply}catch(l){}return a?function(){var a=[];m(arguments,function(b){a.push(d(b))});return e.apply(b,a)}:function(a,b){e(a,null==b?"":b)}}return{log:e("log"),info:e("info"),warn:e("warn"),error:e("error"),debug:function(){var c=e("debug");return function(){b&&c.apply(a,arguments)}}()}}]}
+function Ca(b,a){if("__defineGetter__"===b||"__defineSetter__"===b||"__lookupGetter__"===b||"__lookupSetter__"===b||"__proto__"===b)throw da("isecfld",a);return b}function oa(b,a){if(b){if(b.constructor===b)throw da("isecfn",a);if(b.window===b)throw da("isecwindow",a);if(b.children&&(b.nodeName||b.prop&&b.attr&&b.find))throw da("isecdom",a);if(b===Object)throw da("isecobj",a);}return b}function ld(b,a){if(b){if(b.constructor===b)throw da("isecfn",a);if(b===Uf||b===Vf||b===Wf)throw da("isecff",a);
+}}function Xf(b,a){return"undefined"!==typeof b?b:a}function md(b,a){return"undefined"===typeof b?a:"undefined"===typeof a?b:b+a}function T(b,a){var c,d;switch(b.type){case q.Program:c=!0;m(b.body,function(b){T(b.expression,a);c=c&&b.expression.constant});b.constant=c;break;case q.Literal:b.constant=!0;b.toWatch=[];break;case q.UnaryExpression:T(b.argument,a);b.constant=b.argument.constant;b.toWatch=b.argument.toWatch;break;case q.BinaryExpression:T(b.left,a);T(b.right,a);b.constant=b.left.constant&&
+b.right.constant;b.toWatch=b.left.toWatch.concat(b.right.toWatch);break;case q.LogicalExpression:T(b.left,a);T(b.right,a);b.constant=b.left.constant&&b.right.constant;b.toWatch=b.constant?[]:[b];break;case q.ConditionalExpression:T(b.test,a);T(b.alternate,a);T(b.consequent,a);b.constant=b.test.constant&&b.alternate.constant&&b.consequent.constant;b.toWatch=b.constant?[]:[b];break;case q.Identifier:b.constant=!1;b.toWatch=[b];break;case q.MemberExpression:T(b.object,a);b.computed&&T(b.property,a);
+b.constant=b.object.constant&&(!b.computed||b.property.constant);b.toWatch=[b];break;case q.CallExpression:c=b.filter?!a(b.callee.name).$stateful:!1;d=[];m(b.arguments,function(b){T(b,a);c=c&&b.constant;b.constant||d.push.apply(d,b.toWatch)});b.constant=c;b.toWatch=b.filter&&!a(b.callee.name).$stateful?d:[b];break;case q.AssignmentExpression:T(b.left,a);T(b.right,a);b.constant=b.left.constant&&b.right.constant;b.toWatch=[b];break;case q.ArrayExpression:c=!0;d=[];m(b.elements,function(b){T(b,a);c=
+c&&b.constant;b.constant||d.push.apply(d,b.toWatch)});b.constant=c;b.toWatch=d;break;case q.ObjectExpression:c=!0;d=[];m(b.properties,function(b){T(b.value,a);c=c&&b.value.constant;b.value.constant||d.push.apply(d,b.value.toWatch)});b.constant=c;b.toWatch=d;break;case q.ThisExpression:b.constant=!1,b.toWatch=[]}}function nd(b){if(1==b.length){b=b[0].expression;var a=b.toWatch;return 1!==a.length?a:a[0]!==b?a:t}}function od(b){return b.type===q.Identifier||b.type===q.MemberExpression}function pd(b){if(1===
+b.body.length&&od(b.body[0].expression))return{type:q.AssignmentExpression,left:b.body[0].expression,right:{type:q.NGValueParameter},operator:"="}}function qd(b){return 0===b.body.length||1===b.body.length&&(b.body[0].expression.type===q.Literal||b.body[0].expression.type===q.ArrayExpression||b.body[0].expression.type===q.ObjectExpression)}function rd(b,a){this.astBuilder=b;this.$filter=a}function sd(b,a){this.astBuilder=b;this.$filter=a}function Eb(b,a,c,d){oa(b,d);a=a.split(".");for(var e,f=0;1<
+a.length;f++){e=Ca(a.shift(),d);var g=oa(b[e],d);g||(g={},b[e]=g);b=g}e=Ca(a.shift(),d);oa(b[e],d);return b[e]=c}function Fb(b){return"constructor"==b}function fc(b){return z(b.valueOf)?b.valueOf():Yf.call(b)}function hf(){var b=ga(),a=ga();this.$get=["$filter","$sniffer",function(c,d){function e(a,b){return null==a||null==b?a===b:"object"===typeof a&&(a=fc(a),"object"===typeof a)?!1:a===b||a!==a&&b!==b}function f(a,b,c,d,f){var g=d.inputs,h;if(1===g.length){var k=e,g=g[0];return a.$watch(function(a){var b=
+g(a);e(b,k)||(h=d(a,t,t,[b]),k=b&&fc(b));return h},b,c,f)}for(var l=[],n=[],r=0,m=g.length;r<m;r++)l[r]=e,n[r]=null;return a.$watch(function(a){for(var b=!1,c=0,f=g.length;c<f;c++){var k=g[c](a);if(b||(b=!e(k,l[c])))n[c]=k,l[c]=k&&fc(k)}b&&(h=d(a,t,t,n));return h},b,c,f)}function g(a,b,c,d){var e,f;return e=a.$watch(function(a){return d(a)},function(a,c,d){f=a;z(b)&&b.apply(this,arguments);w(a)&&d.$$postDigest(function(){w(f)&&e()})},c)}function h(a,b,c,d){function e(a){var b=!0;m(a,function(a){w(a)||
+(b=!1)});return b}var f,g;return f=a.$watch(function(a){return d(a)},function(a,c,d){g=a;z(b)&&b.call(this,a,c,d);e(a)&&d.$$postDigest(function(){e(g)&&f()})},c)}function l(a,b,c,d){var e;return e=a.$watch(function(a){return d(a)},function(a,c,d){z(b)&&b.apply(this,arguments);e()},c)}function k(a,b){if(!b)return a;var c=a.$$watchDelegate,c=c!==h&&c!==g?function(c,d,e,f){e=a(c,d,e,f);return b(e,c,d)}:function(c,d,e,f){e=a(c,d,e,f);c=b(e,c,d);return w(e)?c:e};a.$$watchDelegate&&a.$$watchDelegate!==
+f?c.$$watchDelegate=a.$$watchDelegate:b.$stateful||(c.$$watchDelegate=f,c.inputs=a.inputs?a.inputs:[a]);return c}var n={csp:d.csp,expensiveChecks:!1},r={csp:d.csp,expensiveChecks:!0};return function(d,e,C){var m,u,p;switch(typeof d){case "string":p=d=d.trim();var q=C?a:b;m=q[p];m||(":"===d.charAt(0)&&":"===d.charAt(1)&&(u=!0,d=d.substring(2)),C=C?r:n,m=new gc(C),m=(new hc(m,c,C)).parse(d),m.constant?m.$$watchDelegate=l:u?m.$$watchDelegate=m.literal?h:g:m.inputs&&(m.$$watchDelegate=f),q[p]=m);return k(m,
+e);case "function":return k(d,e);default:return v}}}]}function kf(){this.$get=["$rootScope","$exceptionHandler",function(b,a){return td(function(a){b.$evalAsync(a)},a)}]}function lf(){this.$get=["$browser","$exceptionHandler",function(b,a){return td(function(a){b.defer(a)},a)}]}function td(b,a){function c(a,b,c){function d(b){return function(c){e||(e=!0,b.call(a,c))}}var e=!1;return[d(b),d(c)]}function d(){this.$$state={status:0}}function e(a,b){return function(c){b.call(a,c)}}function f(c){!c.processScheduled&&
+c.pending&&(c.processScheduled=!0,b(function(){var b,d,e;e=c.pending;c.processScheduled=!1;c.pending=t;for(var f=0,g=e.length;f<g;++f){d=e[f][0];b=e[f][c.status];try{z(b)?d.resolve(b(c.value)):1===c.status?d.resolve(c.value):d.reject(c.value)}catch(h){d.reject(h),a(h)}}}))}function g(){this.promise=new d;this.resolve=e(this,this.resolve);this.reject=e(this,this.reject);this.notify=e(this,this.notify)}var h=J("$q",TypeError);d.prototype={then:function(a,b,c){var d=new g;this.$$state.pending=this.$$state.pending||
+[];this.$$state.pending.push([d,a,b,c]);0<this.$$state.status&&f(this.$$state);return d.promise},"catch":function(a){return this.then(null,a)},"finally":function(a,b){return this.then(function(b){return k(b,!0,a)},function(b){return k(b,!1,a)},b)}};g.prototype={resolve:function(a){this.promise.$$state.status||(a===this.promise?this.$$reject(h("qcycle",a)):this.$$resolve(a))},$$resolve:function(b){var d,e;e=c(this,this.$$resolve,this.$$reject);try{if(H(b)||z(b))d=b&&b.then;z(d)?(this.promise.$$state.status=
+-1,d.call(b,e[0],e[1],this.notify)):(this.promise.$$state.value=b,this.promise.$$state.status=1,f(this.promise.$$state))}catch(g){e[1](g),a(g)}},reject:function(a){this.promise.$$state.status||this.$$reject(a)},$$reject:function(a){this.promise.$$state.value=a;this.promise.$$state.status=2;f(this.promise.$$state)},notify:function(c){var d=this.promise.$$state.pending;0>=this.promise.$$state.status&&d&&d.length&&b(function(){for(var b,e,f=0,g=d.length;f<g;f++){e=d[f][0];b=d[f][3];try{e.notify(z(b)?
+b(c):c)}catch(h){a(h)}}})}};var l=function(a,b){var c=new g;b?c.resolve(a):c.reject(a);return c.promise},k=function(a,b,c){var d=null;try{z(c)&&(d=c())}catch(e){return l(e,!1)}return d&&z(d.then)?d.then(function(){return l(a,b)},function(a){return l(a,!1)}):l(a,b)},n=function(a,b,c,d){var e=new g;e.resolve(a);return e.promise.then(b,c,d)},r=function x(a){if(!z(a))throw h("norslvr",a);if(!(this instanceof x))return new x(a);var b=new g;a(function(a){b.resolve(a)},function(a){b.reject(a)});return b.promise};
+r.defer=function(){return new g};r.reject=function(a){var b=new g;b.reject(a);return b.promise};r.when=n;r.resolve=n;r.all=function(a){var b=new g,c=0,d=G(a)?[]:{};m(a,function(a,e){c++;n(a).then(function(a){d.hasOwnProperty(e)||(d[e]=a,--c||b.resolve(d))},function(a){d.hasOwnProperty(e)||b.reject(a)})});0===c&&b.resolve(d);return b.promise};return r}function uf(){this.$get=["$window","$timeout",function(b,a){function c(){for(var a=0;a<n.length;a++){var b=n[a];b&&(n[a]=null,b())}k=n.length=0}function d(a){var b=
+n.length;k++;n.push(a);0===b&&(l=h(c));return function(){0<=b&&(b=n[b]=null,0===--k&&l&&(l(),l=null,n.length=0))}}var e=b.requestAnimationFrame||b.webkitRequestAnimationFrame,f=b.cancelAnimationFrame||b.webkitCancelAnimationFrame||b.webkitCancelRequestAnimationFrame,g=!!e,h=g?function(a){var b=e(a);return function(){f(b)}}:function(b){var c=a(b,16.66,!1);return function(){a.cancel(c)}};d.supported=g;var l,k=0,n=[];return d}]}function jf(){function b(a){function b(){this.$$watchers=this.$$nextSibling=
+this.$$childHead=this.$$childTail=null;this.$$listeners={};this.$$listenerCount={};this.$$watchersCount=0;this.$id=++nb;this.$$ChildScope=null}b.prototype=a;return b}var a=10,c=J("$rootScope"),d=null,e=null;this.digestTtl=function(b){arguments.length&&(a=b);return a};this.$get=["$injector","$exceptionHandler","$parse","$browser",function(f,g,h,l){function k(a){a.currentScope.$$destroyed=!0}function n(){this.$id=++nb;this.$$phase=this.$parent=this.$$watchers=this.$$nextSibling=this.$$prevSibling=this.$$childHead=
+this.$$childTail=null;this.$root=this;this.$$destroyed=!1;this.$$listeners={};this.$$listenerCount={};this.$$watchersCount=0;this.$$isolateBindings=null}function r(a){if(p.$$phase)throw c("inprog",p.$$phase);p.$$phase=a}function s(a,b){do a.$$watchersCount+=b;while(a=a.$parent)}function x(a,b,c){do a.$$listenerCount[c]-=b,0===a.$$listenerCount[c]&&delete a.$$listenerCount[c];while(a=a.$parent)}function q(){}function F(){for(;I.length;)try{I.shift()()}catch(a){g(a)}e=null}function u(){null===e&&(e=
+l.defer(function(){p.$apply(F)}))}n.prototype={constructor:n,$new:function(a,c){var d;c=c||this;a?(d=new n,d.$root=this.$root):(this.$$ChildScope||(this.$$ChildScope=b(this)),d=new this.$$ChildScope);d.$parent=c;d.$$prevSibling=c.$$childTail;c.$$childHead?(c.$$childTail.$$nextSibling=d,c.$$childTail=d):c.$$childHead=c.$$childTail=d;(a||c!=this)&&d.$on("$destroy",k);return d},$watch:function(a,b,c,e){var f=h(a);if(f.$$watchDelegate)return f.$$watchDelegate(this,b,c,f,a);var g=this,k=g.$$watchers,l=
+{fn:b,last:q,get:f,exp:e||a,eq:!!c};d=null;z(b)||(l.fn=v);k||(k=g.$$watchers=[]);k.unshift(l);s(this,1);return function(){0<=bb(k,l)&&s(g,-1);d=null}},$watchGroup:function(a,b){function c(){h=!1;k?(k=!1,b(e,e,g)):b(e,d,g)}var d=Array(a.length),e=Array(a.length),f=[],g=this,h=!1,k=!0;if(!a.length){var l=!0;g.$evalAsync(function(){l&&b(e,e,g)});return function(){l=!1}}if(1===a.length)return this.$watch(a[0],function(a,c,f){e[0]=a;d[0]=c;b(e,a===c?e:d,f)});m(a,function(a,b){var k=g.$watch(a,function(a,
+f){e[b]=a;d[b]=f;h||(h=!0,g.$evalAsync(c))});f.push(k)});return function(){for(;f.length;)f.shift()()}},$watchCollection:function(a,b){function c(a){e=a;var b,d,g,h;if(!A(e)){if(H(e))if(Ea(e))for(f!==r&&(f=r,m=f.length=0,l++),a=e.length,m!==a&&(l++,f.length=m=a),b=0;b<a;b++)h=f[b],g=e[b],d=h!==h&&g!==g,d||h===g||(l++,f[b]=g);else{f!==s&&(f=s={},m=0,l++);a=0;for(b in e)e.hasOwnProperty(b)&&(a++,g=e[b],h=f[b],b in f?(d=h!==h&&g!==g,d||h===g||(l++,f[b]=g)):(m++,f[b]=g,l++));if(m>a)for(b in l++,f)e.hasOwnProperty(b)||
+(m--,delete f[b])}else f!==e&&(f=e,l++);return l}}c.$stateful=!0;var d=this,e,f,g,k=1<b.length,l=0,n=h(a,c),r=[],s={},p=!0,m=0;return this.$watch(n,function(){p?(p=!1,b(e,e,d)):b(e,g,d);if(k)if(H(e))if(Ea(e)){g=Array(e.length);for(var a=0;a<e.length;a++)g[a]=e[a]}else for(a in g={},e)Xa.call(e,a)&&(g[a]=e[a]);else g=e})},$digest:function(){var b,f,h,k,n,s,m=a,x,u=[],E,I;r("$digest");l.$$checkUrlChange();this===p&&null!==e&&(l.defer.cancel(e),F());d=null;do{s=!1;for(x=this;t.length;){try{I=t.shift(),
+I.scope.$eval(I.expression,I.locals)}catch(v){g(v)}d=null}a:do{if(k=x.$$watchers)for(n=k.length;n--;)try{if(b=k[n])if((f=b.get(x))!==(h=b.last)&&!(b.eq?ka(f,h):"number"===typeof f&&"number"===typeof h&&isNaN(f)&&isNaN(h)))s=!0,d=b,b.last=b.eq?fa(f,null):f,b.fn(f,h===q?f:h,x),5>m&&(E=4-m,u[E]||(u[E]=[]),u[E].push({msg:z(b.exp)?"fn: "+(b.exp.name||b.exp.toString()):b.exp,newVal:f,oldVal:h}));else if(b===d){s=!1;break a}}catch(A){g(A)}if(!(k=x.$$watchersCount&&x.$$childHead||x!==this&&x.$$nextSibling))for(;x!==
+this&&!(k=x.$$nextSibling);)x=x.$parent}while(x=k);if((s||t.length)&&!m--)throw p.$$phase=null,c("infdig",a,u);}while(s||t.length);for(p.$$phase=null;w.length;)try{w.shift()()}catch(y){g(y)}},$destroy:function(){if(!this.$$destroyed){var a=this.$parent;this.$broadcast("$destroy");this.$$destroyed=!0;this===p&&l.$$applicationDestroyed();s(this,-this.$$watchersCount);for(var b in this.$$listenerCount)x(this,this.$$listenerCount[b],b);a&&a.$$childHead==this&&(a.$$childHead=this.$$nextSibling);a&&a.$$childTail==
+this&&(a.$$childTail=this.$$prevSibling);this.$$prevSibling&&(this.$$prevSibling.$$nextSibling=this.$$nextSibling);this.$$nextSibling&&(this.$$nextSibling.$$prevSibling=this.$$prevSibling);this.$destroy=this.$digest=this.$apply=this.$evalAsync=this.$applyAsync=v;this.$on=this.$watch=this.$watchGroup=function(){return v};this.$$listeners={};this.$parent=this.$$nextSibling=this.$$prevSibling=this.$$childHead=this.$$childTail=this.$root=this.$$watchers=null}},$eval:function(a,b){return h(a)(this,b)},
+$evalAsync:function(a,b){p.$$phase||t.length||l.defer(function(){t.length&&p.$digest()});t.push({scope:this,expression:a,locals:b})},$$postDigest:function(a){w.push(a)},$apply:function(a){try{return r("$apply"),this.$eval(a)}catch(b){g(b)}finally{p.$$phase=null;try{p.$digest()}catch(c){throw g(c),c;}}},$applyAsync:function(a){function b(){c.$eval(a)}var c=this;a&&I.push(b);u()},$on:function(a,b){var c=this.$$listeners[a];c||(this.$$listeners[a]=c=[]);c.push(b);var d=this;do d.$$listenerCount[a]||
+(d.$$listenerCount[a]=0),d.$$listenerCount[a]++;while(d=d.$parent);var e=this;return function(){var d=c.indexOf(b);-1!==d&&(c[d]=null,x(e,1,a))}},$emit:function(a,b){var c=[],d,e=this,f=!1,h={name:a,targetScope:e,stopPropagation:function(){f=!0},preventDefault:function(){h.defaultPrevented=!0},defaultPrevented:!1},k=cb([h],arguments,1),l,n;do{d=e.$$listeners[a]||c;h.currentScope=e;l=0;for(n=d.length;l<n;l++)if(d[l])try{d[l].apply(null,k)}catch(r){g(r)}else d.splice(l,1),l--,n--;if(f)return h.currentScope=
+null,h;e=e.$parent}while(e);h.currentScope=null;return h},$broadcast:function(a,b){var c=this,d=this,e={name:a,targetScope:this,preventDefault:function(){e.defaultPrevented=!0},defaultPrevented:!1};if(!this.$$listenerCount[a])return e;for(var f=cb([e],arguments,1),h,k;c=d;){e.currentScope=c;d=c.$$listeners[a]||[];h=0;for(k=d.length;h<k;h++)if(d[h])try{d[h].apply(null,f)}catch(l){g(l)}else d.splice(h,1),h--,k--;if(!(d=c.$$listenerCount[a]&&c.$$childHead||c!==this&&c.$$nextSibling))for(;c!==this&&!(d=
+c.$$nextSibling);)c=c.$parent}e.currentScope=null;return e}};var p=new n,t=p.$$asyncQueue=[],w=p.$$postDigestQueue=[],I=p.$$applyAsyncQueue=[];return p}]}function he(){var b=/^\s*(https?|ftp|mailto|tel|file):/,a=/^\s*((https?|ftp|file|blob):|data:image\/)/;this.aHrefSanitizationWhitelist=function(a){return w(a)?(b=a,this):b};this.imgSrcSanitizationWhitelist=function(b){return w(b)?(a=b,this):a};this.$get=function(){return function(c,d){var e=d?a:b,f;f=Ba(c).href;return""===f||f.match(e)?c:"unsafe:"+
+f}}}function Zf(b){if("self"===b)return b;if(L(b)){if(-1<b.indexOf("***"))throw Da("iwcard",b);b=ud(b).replace("\\*\\*",".*").replace("\\*","[^:/.?&;]*");return new RegExp("^"+b+"$")}if(Za(b))return new RegExp("^"+b.source+"$");throw Da("imatcher");}function vd(b){var a=[];w(b)&&m(b,function(b){a.push(Zf(b))});return a}function nf(){this.SCE_CONTEXTS=pa;var b=["self"],a=[];this.resourceUrlWhitelist=function(a){arguments.length&&(b=vd(a));return b};this.resourceUrlBlacklist=function(b){arguments.length&&
+(a=vd(b));return a};this.$get=["$injector",function(c){function d(a,b){return"self"===a?gd(b):!!a.exec(b.href)}function e(a){var b=function(a){this.$$unwrapTrustedValue=function(){return a}};a&&(b.prototype=new a);b.prototype.valueOf=function(){return this.$$unwrapTrustedValue()};b.prototype.toString=function(){return this.$$unwrapTrustedValue().toString()};return b}var f=function(a){throw Da("unsafe");};c.has("$sanitize")&&(f=c.get("$sanitize"));var g=e(),h={};h[pa.HTML]=e(g);h[pa.CSS]=e(g);h[pa.URL]=
+e(g);h[pa.JS]=e(g);h[pa.RESOURCE_URL]=e(h[pa.URL]);return{trustAs:function(a,b){var c=h.hasOwnProperty(a)?h[a]:null;if(!c)throw Da("icontext",a,b);if(null===b||b===t||""===b)return b;if("string"!==typeof b)throw Da("itype",a);return new c(b)},getTrusted:function(c,e){if(null===e||e===t||""===e)return e;var g=h.hasOwnProperty(c)?h[c]:null;if(g&&e instanceof g)return e.$$unwrapTrustedValue();if(c===pa.RESOURCE_URL){var g=Ba(e.toString()),r,s,m=!1;r=0;for(s=b.length;r<s;r++)if(d(b[r],g)){m=!0;break}if(m)for(r=
+0,s=a.length;r<s;r++)if(d(a[r],g)){m=!1;break}if(m)return e;throw Da("insecurl",e.toString());}if(c===pa.HTML)return f(e);throw Da("unsafe");},valueOf:function(a){return a instanceof g?a.$$unwrapTrustedValue():a}}}]}function mf(){var b=!0;this.enabled=function(a){arguments.length&&(b=!!a);return b};this.$get=["$parse","$sceDelegate",function(a,c){if(b&&8>Ua)throw Da("iequirks");var d=ia(pa);d.isEnabled=function(){return b};d.trustAs=c.trustAs;d.getTrusted=c.getTrusted;d.valueOf=c.valueOf;b||(d.trustAs=
+d.getTrusted=function(a,b){return b},d.valueOf=Ya);d.parseAs=function(b,c){var e=a(c);return e.literal&&e.constant?e:a(c,function(a){return d.getTrusted(b,a)})};var e=d.parseAs,f=d.getTrusted,g=d.trustAs;m(pa,function(a,b){var c=M(b);d[hb("parse_as_"+c)]=function(b){return e(a,b)};d[hb("get_trusted_"+c)]=function(b){return f(a,b)};d[hb("trust_as_"+c)]=function(b){return g(a,b)}});return d}]}function of(){this.$get=["$window","$document",function(b,a){var c={},d=W((/android (\d+)/.exec(M((b.navigator||
+{}).userAgent))||[])[1]),e=/Boxee/i.test((b.navigator||{}).userAgent),f=a[0]||{},g,h=/^(Moz|webkit|ms)(?=[A-Z])/,l=f.body&&f.body.style,k=!1,n=!1;if(l){for(var r in l)if(k=h.exec(r)){g=k[0];g=g.substr(0,1).toUpperCase()+g.substr(1);break}g||(g="WebkitOpacity"in l&&"webkit");k=!!("transition"in l||g+"Transition"in l);n=!!("animation"in l||g+"Animation"in l);!d||k&&n||(k=L(l.webkitTransition),n=L(l.webkitAnimation))}return{history:!(!b.history||!b.history.pushState||4>d||e),hasEvent:function(a){if("input"===
+a&&11>=Ua)return!1;if(A(c[a])){var b=f.createElement("div");c[a]="on"+a in b}return c[a]},csp:fb(),vendorPrefix:g,transitions:k,animations:n,android:d}}]}function qf(){this.$get=["$templateCache","$http","$q","$sce",function(b,a,c,d){function e(f,g){e.totalPendingRequests++;L(f)&&b.get(f)||(f=d.getTrustedResourceUrl(f));var h=a.defaults&&a.defaults.transformResponse;G(h)?h=h.filter(function(a){return a!==$b}):h===$b&&(h=null);return a.get(f,{cache:b,transformResponse:h})["finally"](function(){e.totalPendingRequests--}).then(function(a){b.put(f,
+a.data);return a.data},function(a){if(!g)throw ea("tpload",f,a.status,a.statusText);return c.reject(a)})}e.totalPendingRequests=0;return e}]}function rf(){this.$get=["$rootScope","$browser","$location",function(b,a,c){return{findBindings:function(a,b,c){a=a.getElementsByClassName("ng-binding");var g=[];m(a,function(a){var d=ca.element(a).data("$binding");d&&m(d,function(d){c?(new RegExp("(^|\\s)"+ud(b)+"(\\s|\\||$)")).test(d)&&g.push(a):-1!=d.indexOf(b)&&g.push(a)})});return g},findModels:function(a,
+b,c){for(var g=["ng-","data-ng-","ng\\:"],h=0;h<g.length;++h){var l=a.querySelectorAll("["+g[h]+"model"+(c?"=":"*=")+'"'+b+'"]');if(l.length)return l}},getLocation:function(){return c.url()},setLocation:function(a){a!==c.url()&&(c.url(a),b.$digest())},whenStable:function(b){a.notifyWhenNoOutstandingRequests(b)}}}]}function sf(){this.$get=["$rootScope","$browser","$q","$$q","$exceptionHandler",function(b,a,c,d,e){function f(f,l,k){z(f)||(k=l,l=f,f=v);var n=za.call(arguments,3),r=w(k)&&!k,s=(r?d:c).defer(),
+m=s.promise,q;q=a.defer(function(){try{s.resolve(f.apply(null,n))}catch(a){s.reject(a),e(a)}finally{delete g[m.$$timeoutId]}r||b.$apply()},l);m.$$timeoutId=q;g[q]=s;return m}var g={};f.cancel=function(b){return b&&b.$$timeoutId in g?(g[b.$$timeoutId].reject("canceled"),delete g[b.$$timeoutId],a.defer.cancel(b.$$timeoutId)):!1};return f}]}function Ba(b){Ua&&(X.setAttribute("href",b),b=X.href);X.setAttribute("href",b);return{href:X.href,protocol:X.protocol?X.protocol.replace(/:$/,""):"",host:X.host,
+search:X.search?X.search.replace(/^\?/,""):"",hash:X.hash?X.hash.replace(/^#/,""):"",hostname:X.hostname,port:X.port,pathname:"/"===X.pathname.charAt(0)?X.pathname:"/"+X.pathname}}function gd(b){b=L(b)?Ba(b):b;return b.protocol===wd.protocol&&b.host===wd.host}function tf(){this.$get=ra(O)}function xd(b){function a(a){try{return decodeURIComponent(a)}catch(b){return a}}var c=b[0]||{},d={},e="";return function(){var b,g,h,l,k;b=c.cookie||"";if(b!==e)for(e=b,b=e.split("; "),d={},h=0;h<b.length;h++)g=
+b[h],l=g.indexOf("="),0<l&&(k=a(g.substring(0,l)),d[k]===t&&(d[k]=a(g.substring(l+1))));return d}}function xf(){this.$get=xd}function Lc(b){function a(c,d){if(H(c)){var e={};m(c,function(b,c){e[c]=a(c,b)});return e}return b.factory(c+"Filter",d)}this.register=a;this.$get=["$injector",function(a){return function(b){return a.get(b+"Filter")}}];a("currency",yd);a("date",zd);a("filter",$f);a("json",ag);a("limitTo",bg);a("lowercase",cg);a("number",Ad);a("orderBy",Bd);a("uppercase",dg)}function $f(){return function(b,
+a,c){if(!Ea(b)){if(null==b)return b;throw J("filter")("notarray",b);}var d;switch(ic(a)){case "function":break;case "boolean":case "null":case "number":case "string":d=!0;case "object":a=eg(a,c,d);break;default:return b}return Array.prototype.filter.call(b,a)}}function eg(b,a,c){var d=H(b)&&"$"in b;!0===a?a=ka:z(a)||(a=function(a,b){if(A(a))return!1;if(null===a||null===b)return a===b;if(H(b)||H(a)&&!rc(a))return!1;a=M(""+a);b=M(""+b);return-1!==a.indexOf(b)});return function(e){return d&&!H(e)?La(e,
+b.$,a,!1):La(e,b,a,c)}}function La(b,a,c,d,e){var f=ic(b),g=ic(a);if("string"===g&&"!"===a.charAt(0))return!La(b,a.substring(1),c,d);if(G(b))return b.some(function(b){return La(b,a,c,d)});switch(f){case "object":var h;if(d){for(h in b)if("$"!==h.charAt(0)&&La(b[h],a,c,!0))return!0;return e?!1:La(b,a,c,!1)}if("object"===g){for(h in a)if(e=a[h],!z(e)&&!A(e)&&(f="$"===h,!La(f?b:b[h],e,c,f,f)))return!1;return!0}return c(b,a);case "function":return!1;default:return c(b,a)}}function ic(b){return null===
+b?"null":typeof b}function yd(b){var a=b.NUMBER_FORMATS;return function(b,d,e){A(d)&&(d=a.CURRENCY_SYM);A(e)&&(e=a.PATTERNS[1].maxFrac);return null==b?b:Cd(b,a.PATTERNS[1],a.GROUP_SEP,a.DECIMAL_SEP,e).replace(/\u00A4/g,d)}}function Ad(b){var a=b.NUMBER_FORMATS;return function(b,d){return null==b?b:Cd(b,a.PATTERNS[0],a.GROUP_SEP,a.DECIMAL_SEP,d)}}function Cd(b,a,c,d,e){if(H(b))return"";var f=0>b;b=Math.abs(b);var g=Infinity===b;if(!g&&!isFinite(b))return"";var h=b+"",l="",k=!1,n=[];g&&(l="\u221e");
+if(!g&&-1!==h.indexOf("e")){var r=h.match(/([\d\.]+)e(-?)(\d+)/);r&&"-"==r[2]&&r[3]>e+1?b=0:(l=h,k=!0)}if(g||k)0<e&&1>b&&(l=b.toFixed(e),b=parseFloat(l));else{g=(h.split(Dd)[1]||"").length;A(e)&&(e=Math.min(Math.max(a.minFrac,g),a.maxFrac));b=+(Math.round(+(b.toString()+"e"+e)).toString()+"e"+-e);var g=(""+b).split(Dd),h=g[0],g=g[1]||"",r=0,s=a.lgSize,m=a.gSize;if(h.length>=s+m)for(r=h.length-s,k=0;k<r;k++)0===(r-k)%m&&0!==k&&(l+=c),l+=h.charAt(k);for(k=r;k<h.length;k++)0===(h.length-k)%s&&0!==k&&
+(l+=c),l+=h.charAt(k);for(;g.length<e;)g+="0";e&&"0"!==e&&(l+=d+g.substr(0,e))}0===b&&(f=!1);n.push(f?a.negPre:a.posPre,l,f?a.negSuf:a.posSuf);return n.join("")}function Gb(b,a,c){var d="";0>b&&(d="-",b=-b);for(b=""+b;b.length<a;)b="0"+b;c&&(b=b.substr(b.length-a));return d+b}function Y(b,a,c,d){c=c||0;return function(e){e=e["get"+b]();if(0<c||e>-c)e+=c;0===e&&-12==c&&(e=12);return Gb(e,a,d)}}function Hb(b,a){return function(c,d){var e=c["get"+b](),f=rb(a?"SHORT"+b:b);return d[f][e]}}function Ed(b){var a=
+(new Date(b,0,1)).getDay();return new Date(b,0,(4>=a?5:12)-a)}function Fd(b){return function(a){var c=Ed(a.getFullYear());a=+new Date(a.getFullYear(),a.getMonth(),a.getDate()+(4-a.getDay()))-+c;a=1+Math.round(a/6048E5);return Gb(a,b)}}function jc(b,a){return 0>=b.getFullYear()?a.ERAS[0]:a.ERAS[1]}function zd(b){function a(a){var b;if(b=a.match(c)){a=new Date(0);var f=0,g=0,h=b[8]?a.setUTCFullYear:a.setFullYear,l=b[8]?a.setUTCHours:a.setHours;b[9]&&(f=W(b[9]+b[10]),g=W(b[9]+b[11]));h.call(a,W(b[1]),
+W(b[2])-1,W(b[3]));f=W(b[4]||0)-f;g=W(b[5]||0)-g;h=W(b[6]||0);b=Math.round(1E3*parseFloat("0."+(b[7]||0)));l.call(a,f,g,h,b)}return a}var c=/^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/;return function(c,e,f){var g="",h=[],l,k;e=e||"mediumDate";e=b.DATETIME_FORMATS[e]||e;L(c)&&(c=fg.test(c)?W(c):a(c));V(c)&&(c=new Date(c));if(!aa(c)||!isFinite(c.getTime()))return c;for(;e;)(k=gg.exec(e))?(h=cb(h,k,1),e=h.pop()):(h.push(e),e=null);var n=c.getTimezoneOffset();
+f&&(n=xc(f,c.getTimezoneOffset()),c=Pb(c,f,!0));m(h,function(a){l=hg[a];g+=l?l(c,b.DATETIME_FORMATS,n):a.replace(/(^'|'$)/g,"").replace(/''/g,"'")});return g}}function ag(){return function(b,a){A(a)&&(a=2);return db(b,a)}}function bg(){return function(b,a,c){a=Infinity===Math.abs(Number(a))?Number(a):W(a);if(isNaN(a))return b;V(b)&&(b=b.toString());if(!G(b)&&!L(b))return b;c=!c||isNaN(c)?0:W(c);c=0>c&&c>=-b.length?b.length+c:c;return 0<=a?b.slice(c,c+a):0===c?b.slice(a,b.length):b.slice(Math.max(0,
+c+a),c)}}function Bd(b){function a(a,c){c=c?-1:1;return a.map(function(a){var d=1,h=Ya;if(z(a))h=a;else if(L(a)){if("+"==a.charAt(0)||"-"==a.charAt(0))d="-"==a.charAt(0)?-1:1,a=a.substring(1);if(""!==a&&(h=b(a),h.constant))var l=h(),h=function(a){return a[l]}}return{get:h,descending:d*c}})}function c(a){switch(typeof a){case "number":case "boolean":case "string":return!0;default:return!1}}return function(b,e,f){if(!Ea(b))return b;G(e)||(e=[e]);0===e.length&&(e=["+"]);var g=a(e,f);b=Array.prototype.map.call(b,
+function(a,b){return{value:a,predicateValues:g.map(function(d){var e=d.get(a);d=typeof e;if(null===e)d="string",e="null";else if("string"===d)e=e.toLowerCase();else if("object"===d)a:{if("function"===typeof e.valueOf&&(e=e.valueOf(),c(e)))break a;if(rc(e)&&(e=e.toString(),c(e)))break a;e=b}return{value:e,type:d}})}});b.sort(function(a,b){for(var c=0,d=0,e=g.length;d<e;++d){var c=a.predicateValues[d],f=b.predicateValues[d],m=0;c.type===f.type?c.value!==f.value&&(m=c.value<f.value?-1:1):m=c.type<f.type?
+-1:1;if(c=m*g[d].descending)break}return c});return b=b.map(function(a){return a.value})}}function Ma(b){z(b)&&(b={link:b});b.restrict=b.restrict||"AC";return ra(b)}function Gd(b,a,c,d,e){var f=this,g=[],h=f.$$parentForm=b.parent().controller("form")||Ib;f.$error={};f.$$success={};f.$pending=t;f.$name=e(a.name||a.ngForm||"")(c);f.$dirty=!1;f.$pristine=!0;f.$valid=!0;f.$invalid=!1;f.$submitted=!1;h.$addControl(f);f.$rollbackViewValue=function(){m(g,function(a){a.$rollbackViewValue()})};f.$commitViewValue=
+function(){m(g,function(a){a.$commitViewValue()})};f.$addControl=function(a){Ra(a.$name,"input");g.push(a);a.$name&&(f[a.$name]=a)};f.$$renameControl=function(a,b){var c=a.$name;f[c]===a&&delete f[c];f[b]=a;a.$name=b};f.$removeControl=function(a){a.$name&&f[a.$name]===a&&delete f[a.$name];m(f.$pending,function(b,c){f.$setValidity(c,null,a)});m(f.$error,function(b,c){f.$setValidity(c,null,a)});m(f.$$success,function(b,c){f.$setValidity(c,null,a)});bb(g,a)};Hd({ctrl:this,$element:b,set:function(a,b,
+c){var d=a[b];d?-1===d.indexOf(c)&&d.push(c):a[b]=[c]},unset:function(a,b,c){var d=a[b];d&&(bb(d,c),0===d.length&&delete a[b])},parentForm:h,$animate:d});f.$setDirty=function(){d.removeClass(b,Va);d.addClass(b,Jb);f.$dirty=!0;f.$pristine=!1;h.$setDirty()};f.$setPristine=function(){d.setClass(b,Va,Jb+" ng-submitted");f.$dirty=!1;f.$pristine=!0;f.$submitted=!1;m(g,function(a){a.$setPristine()})};f.$setUntouched=function(){m(g,function(a){a.$setUntouched()})};f.$setSubmitted=function(){d.addClass(b,
+"ng-submitted");f.$submitted=!0;h.$setSubmitted()}}function kc(b){b.$formatters.push(function(a){return b.$isEmpty(a)?a:a.toString()})}function kb(b,a,c,d,e,f){var g=M(a[0].type);if(!e.android){var h=!1;a.on("compositionstart",function(a){h=!0});a.on("compositionend",function(){h=!1;l()})}var l=function(b){k&&(f.defer.cancel(k),k=null);if(!h){var e=a.val();b=b&&b.type;"password"===g||c.ngTrim&&"false"===c.ngTrim||(e=R(e));(d.$viewValue!==e||""===e&&d.$$hasNativeValidators)&&d.$setViewValue(e,b)}};
+if(e.hasEvent("input"))a.on("input",l);else{var k,n=function(a,b,c){k||(k=f.defer(function(){k=null;b&&b.value===c||l(a)}))};a.on("keydown",function(a){var b=a.keyCode;91===b||15<b&&19>b||37<=b&&40>=b||n(a,this,this.value)});if(e.hasEvent("paste"))a.on("paste cut",n)}a.on("change",l);d.$render=function(){a.val(d.$isEmpty(d.$viewValue)?"":d.$viewValue)}}function Kb(b,a){return function(c,d){var e,f;if(aa(c))return c;if(L(c)){'"'==c.charAt(0)&&'"'==c.charAt(c.length-1)&&(c=c.substring(1,c.length-1));
+if(ig.test(c))return new Date(c);b.lastIndex=0;if(e=b.exec(c))return e.shift(),f=d?{yyyy:d.getFullYear(),MM:d.getMonth()+1,dd:d.getDate(),HH:d.getHours(),mm:d.getMinutes(),ss:d.getSeconds(),sss:d.getMilliseconds()/1E3}:{yyyy:1970,MM:1,dd:1,HH:0,mm:0,ss:0,sss:0},m(e,function(b,c){c<a.length&&(f[a[c]]=+b)}),new Date(f.yyyy,f.MM-1,f.dd,f.HH,f.mm,f.ss||0,1E3*f.sss||0)}return NaN}}function lb(b,a,c,d){return function(e,f,g,h,l,k,n){function r(a){return a&&!(a.getTime&&a.getTime()!==a.getTime())}function s(a){return w(a)?
+aa(a)?a:c(a):t}Id(e,f,g,h);kb(e,f,g,h,l,k);var m=h&&h.$options&&h.$options.timezone,q;h.$$parserName=b;h.$parsers.push(function(b){return h.$isEmpty(b)?null:a.test(b)?(b=c(b,q),m&&(b=Pb(b,m)),b):t});h.$formatters.push(function(a){if(a&&!aa(a))throw Lb("datefmt",a);if(r(a))return(q=a)&&m&&(q=Pb(q,m,!0)),n("date")(a,d,m);q=null;return""});if(w(g.min)||g.ngMin){var F;h.$validators.min=function(a){return!r(a)||A(F)||c(a)>=F};g.$observe("min",function(a){F=s(a);h.$validate()})}if(w(g.max)||g.ngMax){var u;
+h.$validators.max=function(a){return!r(a)||A(u)||c(a)<=u};g.$observe("max",function(a){u=s(a);h.$validate()})}}}function Id(b,a,c,d){(d.$$hasNativeValidators=H(a[0].validity))&&d.$parsers.push(function(b){var c=a.prop("validity")||{};return c.badInput&&!c.typeMismatch?t:b})}function Jd(b,a,c,d,e){if(w(d)){b=b(d);if(!b.constant)throw J("ngModel")("constexpr",c,d);return b(a)}return e}function lc(b,a){b="ngClass"+b;return["$animate",function(c){function d(a,b){var c=[],d=0;a:for(;d<a.length;d++){for(var e=
+a[d],n=0;n<b.length;n++)if(e==b[n])continue a;c.push(e)}return c}function e(a){var b=[];return G(a)?(m(a,function(a){b=b.concat(e(a))}),b):L(a)?a.split(" "):H(a)?(m(a,function(a,c){a&&(b=b.concat(c.split(" ")))}),b):a}return{restrict:"AC",link:function(f,g,h){function l(a,b){var c=g.data("$classCounts")||ga(),d=[];m(a,function(a){if(0<b||c[a])c[a]=(c[a]||0)+b,c[a]===+(0<b)&&d.push(a)});g.data("$classCounts",c);return d.join(" ")}function k(b){if(!0===a||f.$index%2===a){var k=e(b||[]);if(!n){var m=
+l(k,1);h.$addClass(m)}else if(!ka(b,n)){var q=e(n),m=d(k,q),k=d(q,k),m=l(m,1),k=l(k,-1);m&&m.length&&c.addClass(g,m);k&&k.length&&c.removeClass(g,k)}}n=ia(b)}var n;f.$watch(h[b],k,!0);h.$observe("class",function(a){k(f.$eval(h[b]))});"ngClass"!==b&&f.$watch("$index",function(c,d){var g=c&1;if(g!==(d&1)){var k=e(f.$eval(h[b]));g===a?(g=l(k,1),h.$addClass(g)):(g=l(k,-1),h.$removeClass(g))}})}}}]}function Hd(b){function a(a,b){b&&!f[a]?(k.addClass(e,a),f[a]=!0):!b&&f[a]&&(k.removeClass(e,a),f[a]=!1)}
+function c(b,c){b=b?"-"+Bc(b,"-"):"";a(mb+b,!0===c);a(Kd+b,!1===c)}var d=b.ctrl,e=b.$element,f={},g=b.set,h=b.unset,l=b.parentForm,k=b.$animate;f[Kd]=!(f[mb]=e.hasClass(mb));d.$setValidity=function(b,e,f){e===t?(d.$pending||(d.$pending={}),g(d.$pending,b,f)):(d.$pending&&h(d.$pending,b,f),Ld(d.$pending)&&(d.$pending=t));ab(e)?e?(h(d.$error,b,f),g(d.$$success,b,f)):(g(d.$error,b,f),h(d.$$success,b,f)):(h(d.$error,b,f),h(d.$$success,b,f));d.$pending?(a(Md,!0),d.$valid=d.$invalid=t,c("",null)):(a(Md,
+!1),d.$valid=Ld(d.$error),d.$invalid=!d.$valid,c("",d.$valid));e=d.$pending&&d.$pending[b]?t:d.$error[b]?!1:d.$$success[b]?!0:null;c(b,e);l.$setValidity(b,e,d)}}function Ld(b){if(b)for(var a in b)if(b.hasOwnProperty(a))return!1;return!0}var jg=/^\/(.+)\/([a-z]*)$/,M=function(b){return L(b)?b.toLowerCase():b},Xa=Object.prototype.hasOwnProperty,rb=function(b){return L(b)?b.toUpperCase():b},Ua,y,la,za=[].slice,Mf=[].splice,kg=[].push,sa=Object.prototype.toString,sc=Object.getPrototypeOf,Fa=J("ng"),ca=
+O.angular||(O.angular={}),gb,nb=0;Ua=U.documentMode;v.$inject=[];Ya.$inject=[];var G=Array.isArray,uc=/^\[object (Uint8(Clamped)?)|(Uint16)|(Uint32)|(Int8)|(Int16)|(Int32)|(Float(32)|(64))Array\]$/,R=function(b){return L(b)?b.trim():b},ud=function(b){return b.replace(/([-()\[\]{}+?*.$\^|,:#<!\\])/g,"\\$1").replace(/\x08/g,"\\x08")},fb=function(){if(w(fb.isActive_))return fb.isActive_;var b=!(!U.querySelector("[ng-csp]")&&!U.querySelector("[data-ng-csp]"));if(!b)try{new Function("")}catch(a){b=!0}return fb.isActive_=
+b},pb=function(){if(w(pb.name_))return pb.name_;var b,a,c=Oa.length,d,e;for(a=0;a<c;++a)if(d=Oa[a],b=U.querySelector("["+d.replace(":","\\:")+"jq]")){e=b.getAttribute(d+"jq");break}return pb.name_=e},Oa=["ng-","data-ng-","ng:","x-ng-"],be=/[A-Z]/g,Cc=!1,Rb,qa=1,Na=3,fe={full:"1.4.3",major:1,minor:4,dot:3,codeName:"foam-acceleration"};Q.expando="ng339";var ib=Q.cache={},Df=1;Q._data=function(b){return this.cache[b[this.expando]]||{}};var yf=/([\:\-\_]+(.))/g,zf=/^moz([A-Z])/,lg={mouseleave:"mouseout",
+mouseenter:"mouseover"},Ub=J("jqLite"),Cf=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,Tb=/<|&#?\w+;/,Af=/<([\w:]+)/,Bf=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,na={option:[1,'<select multiple="multiple">',"</select>"],thead:[1,"<table>","</table>"],col:[2,"<table><colgroup>","</colgroup></table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:[0,"",""]};na.optgroup=na.option;na.tbody=na.tfoot=na.colgroup=na.caption=na.thead;
+na.th=na.td;var Pa=Q.prototype={ready:function(b){function a(){c||(c=!0,b())}var c=!1;"complete"===U.readyState?setTimeout(a):(this.on("DOMContentLoaded",a),Q(O).on("load",a))},toString:function(){var b=[];m(this,function(a){b.push(""+a)});return"["+b.join(", ")+"]"},eq:function(b){return 0<=b?y(this[b]):y(this[this.length+b])},length:0,push:kg,sort:[].sort,splice:[].splice},Ab={};m("multiple selected checked disabled readOnly required open".split(" "),function(b){Ab[M(b)]=b});var Tc={};m("input select option textarea button form details".split(" "),
+function(b){Tc[b]=!0});var Uc={ngMinlength:"minlength",ngMaxlength:"maxlength",ngMin:"min",ngMax:"max",ngPattern:"pattern"};m({data:Wb,removeData:ub,hasData:function(b){for(var a in ib[b.ng339])return!0;return!1}},function(b,a){Q[a]=b});m({data:Wb,inheritedData:zb,scope:function(b){return y.data(b,"$scope")||zb(b.parentNode||b,["$isolateScope","$scope"])},isolateScope:function(b){return y.data(b,"$isolateScope")||y.data(b,"$isolateScopeNoTemplate")},controller:Qc,injector:function(b){return zb(b,
+"$injector")},removeAttr:function(b,a){b.removeAttribute(a)},hasClass:wb,css:function(b,a,c){a=hb(a);if(w(c))b.style[a]=c;else return b.style[a]},attr:function(b,a,c){var d=b.nodeType;if(d!==Na&&2!==d&&8!==d)if(d=M(a),Ab[d])if(w(c))c?(b[a]=!0,b.setAttribute(a,d)):(b[a]=!1,b.removeAttribute(d));else return b[a]||(b.attributes.getNamedItem(a)||v).specified?d:t;else if(w(c))b.setAttribute(a,c);else if(b.getAttribute)return b=b.getAttribute(a,2),null===b?t:b},prop:function(b,a,c){if(w(c))b[a]=c;else return b[a]},
+text:function(){function b(a,b){if(A(b)){var d=a.nodeType;return d===qa||d===Na?a.textContent:""}a.textContent=b}b.$dv="";return b}(),val:function(b,a){if(A(a)){if(b.multiple&&"select"===ta(b)){var c=[];m(b.options,function(a){a.selected&&c.push(a.value||a.text)});return 0===c.length?null:c}return b.value}b.value=a},html:function(b,a){if(A(a))return b.innerHTML;tb(b,!0);b.innerHTML=a},empty:Rc},function(b,a){Q.prototype[a]=function(a,d){var e,f,g=this.length;if(b!==Rc&&(2==b.length&&b!==wb&&b!==Qc?
+a:d)===t){if(H(a)){for(e=0;e<g;e++)if(b===Wb)b(this[e],a);else for(f in a)b(this[e],f,a[f]);return this}e=b.$dv;g=e===t?Math.min(g,1):g;for(f=0;f<g;f++){var h=b(this[f],a,d);e=e?e+h:h}return e}for(e=0;e<g;e++)b(this[e],a,d);return this}});m({removeData:ub,on:function a(c,d,e,f){if(w(f))throw Ub("onargs");if(Mc(c)){var g=vb(c,!0);f=g.events;var h=g.handle;h||(h=g.handle=Gf(c,f));for(var g=0<=d.indexOf(" ")?d.split(" "):[d],l=g.length;l--;){d=g[l];var k=f[d];k||(f[d]=[],"mouseenter"===d||"mouseleave"===
+d?a(c,lg[d],function(a){var c=a.relatedTarget;c&&(c===this||this.contains(c))||h(a,d)}):"$destroy"!==d&&c.addEventListener(d,h,!1),k=f[d]);k.push(e)}}},off:Pc,one:function(a,c,d){a=y(a);a.on(c,function f(){a.off(c,d);a.off(c,f)});a.on(c,d)},replaceWith:function(a,c){var d,e=a.parentNode;tb(a);m(new Q(c),function(c){d?e.insertBefore(c,d.nextSibling):e.replaceChild(c,a);d=c})},children:function(a){var c=[];m(a.childNodes,function(a){a.nodeType===qa&&c.push(a)});return c},contents:function(a){return a.contentDocument||
+a.childNodes||[]},append:function(a,c){var d=a.nodeType;if(d===qa||11===d){c=new Q(c);for(var d=0,e=c.length;d<e;d++)a.appendChild(c[d])}},prepend:function(a,c){if(a.nodeType===qa){var d=a.firstChild;m(new Q(c),function(c){a.insertBefore(c,d)})}},wrap:function(a,c){c=y(c).eq(0).clone()[0];var d=a.parentNode;d&&d.replaceChild(c,a);c.appendChild(a)},remove:Xb,detach:function(a){Xb(a,!0)},after:function(a,c){var d=a,e=a.parentNode;c=new Q(c);for(var f=0,g=c.length;f<g;f++){var h=c[f];e.insertBefore(h,
+d.nextSibling);d=h}},addClass:yb,removeClass:xb,toggleClass:function(a,c,d){c&&m(c.split(" "),function(c){var f=d;A(f)&&(f=!wb(a,c));(f?yb:xb)(a,c)})},parent:function(a){return(a=a.parentNode)&&11!==a.nodeType?a:null},next:function(a){return a.nextElementSibling},find:function(a,c){return a.getElementsByTagName?a.getElementsByTagName(c):[]},clone:Vb,triggerHandler:function(a,c,d){var e,f,g=c.type||c,h=vb(a);if(h=(h=h&&h.events)&&h[g])e={preventDefault:function(){this.defaultPrevented=!0},isDefaultPrevented:function(){return!0===
+this.defaultPrevented},stopImmediatePropagation:function(){this.immediatePropagationStopped=!0},isImmediatePropagationStopped:function(){return!0===this.immediatePropagationStopped},stopPropagation:v,type:g,target:a},c.type&&(e=P(e,c)),c=ia(h),f=d?[e].concat(d):[e],m(c,function(c){e.isImmediatePropagationStopped()||c.apply(a,f)})}},function(a,c){Q.prototype[c]=function(c,e,f){for(var g,h=0,l=this.length;h<l;h++)A(g)?(g=a(this[h],c,e,f),w(g)&&(g=y(g))):Oc(g,a(this[h],c,e,f));return w(g)?g:this};Q.prototype.bind=
+Q.prototype.on;Q.prototype.unbind=Q.prototype.off});Sa.prototype={put:function(a,c){this[Ga(a,this.nextUid)]=c},get:function(a){return this[Ga(a,this.nextUid)]},remove:function(a){var c=this[a=Ga(a,this.nextUid)];delete this[a];return c}};var wf=[function(){this.$get=[function(){return Sa}]}],Wc=/^function\s*[^\(]*\(\s*([^\)]*)\)/m,mg=/,/,ng=/^\s*(_?)(\S+?)\1\s*$/,Vc=/((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg,Ha=J("$injector");eb.$$annotate=function(a,c,d){var e;if("function"===typeof a){if(!(e=a.$inject)){e=
+[];if(a.length){if(c)throw L(d)&&d||(d=a.name||Hf(a)),Ha("strictdi",d);c=a.toString().replace(Vc,"");c=c.match(Wc);m(c[1].split(mg),function(a){a.replace(ng,function(a,c,d){e.push(d)})})}a.$inject=e}}else G(a)?(c=a.length-1,Qa(a[c],"fn"),e=a.slice(0,c)):Qa(a,"fn",!0);return e};var Nd=J("$animate"),Ue=function(){this.$get=["$q","$$rAF",function(a,c){function d(){}d.all=v;d.chain=v;d.prototype={end:v,cancel:v,resume:v,pause:v,complete:v,then:function(d,f){return a(function(a){c(function(){a()})}).then(d,
+f)}};return d}]},Te=function(){var a=new Sa,c=[];this.$get=["$$AnimateRunner","$rootScope",function(d,e){function f(d,f,l){var k=a.get(d);k||(a.put(d,k={}),c.push(d));f&&m(f.split(" "),function(a){a&&(k[a]=!0)});l&&m(l.split(" "),function(a){a&&(k[a]=!1)});1<c.length||e.$$postDigest(function(){m(c,function(c){var d=a.get(c);if(d){var e=If(c.attr("class")),f="",g="";m(d,function(a,c){a!==!!e[c]&&(a?f+=(f.length?" ":"")+c:g+=(g.length?" ":"")+c)});m(c,function(a){f&&yb(a,f);g&&xb(a,g)});a.remove(c)}});
+c.length=0})}return{enabled:v,on:v,off:v,pin:v,push:function(a,c,e,k){k&&k();e=e||{};e.from&&a.css(e.from);e.to&&a.css(e.to);(e.addClass||e.removeClass)&&f(a,e.addClass,e.removeClass);return new d}}}]},Se=["$provide",function(a){var c=this;this.$$registeredAnimations=Object.create(null);this.register=function(d,e){if(d&&"."!==d.charAt(0))throw Nd("notcsel",d);var f=d+"-animation";c.$$registeredAnimations[d.substr(1)]=f;a.factory(f,e)};this.classNameFilter=function(a){if(1===arguments.length&&(this.$$classNameFilter=
+a instanceof RegExp?a:null)&&/(\s+|\/)ng-animate(\s+|\/)/.test(this.$$classNameFilter.toString()))throw Nd("nongcls","ng-animate");return this.$$classNameFilter};this.$get=["$$animateQueue",function(a){function c(a,d,e){if(e){var l;a:{for(l=0;l<e.length;l++){var k=e[l];if(1===k.nodeType){l=k;break a}}l=void 0}!l||l.parentNode||l.previousElementSibling||(e=null)}e?e.after(a):d.prepend(a)}return{on:a.on,off:a.off,pin:a.pin,enabled:a.enabled,cancel:function(a){a.end&&a.end()},enter:function(f,g,h,l){g=
+g&&y(g);h=h&&y(h);g=g||h.parent();c(f,g,h);return a.push(f,"enter",Ia(l))},move:function(f,g,h,l){g=g&&y(g);h=h&&y(h);g=g||h.parent();c(f,g,h);return a.push(f,"move",Ia(l))},leave:function(c,e){return a.push(c,"leave",Ia(e),function(){c.remove()})},addClass:function(c,e,h){h=Ia(h);h.addClass=jb(h.addclass,e);return a.push(c,"addClass",h)},removeClass:function(c,e,h){h=Ia(h);h.removeClass=jb(h.removeClass,e);return a.push(c,"removeClass",h)},setClass:function(c,e,h,l){l=Ia(l);l.addClass=jb(l.addClass,
+e);l.removeClass=jb(l.removeClass,h);return a.push(c,"setClass",l)},animate:function(c,e,h,l,k){k=Ia(k);k.from=k.from?P(k.from,e):e;k.to=k.to?P(k.to,h):h;k.tempClasses=jb(k.tempClasses,l||"ng-inline-animate");return a.push(c,"animate",k)}}}]}],ea=J("$compile");Ec.$inject=["$provide","$$sanitizeUriProvider"];var Zc=/^((?:x|data)[\:\-_])/i,Nf=J("$controller"),Xc=/^(\S+)(\s+as\s+(\w+))?$/,cd="application/json",ac={"Content-Type":cd+";charset=utf-8"},Pf=/^\[|^\{(?!\{)/,Qf={"[":/]$/,"{":/}$/},Of=/^\)\]\}',?\n/,
+Ka=ca.$interpolateMinErr=J("$interpolate");Ka.throwNoconcat=function(a){throw Ka("noconcat",a);};Ka.interr=function(a,c){return Ka("interr",a,c.toString())};var og=/^([^\?#]*)(\?([^#]*))?(#(.*))?$/,Tf={http:80,https:443,ftp:21},Cb=J("$location"),pg={$$html5:!1,$$replace:!1,absUrl:Db("$$absUrl"),url:function(a){if(A(a))return this.$$url;var c=og.exec(a);(c[1]||""===a)&&this.path(decodeURIComponent(c[1]));(c[2]||c[1]||""===a)&&this.search(c[3]||"");this.hash(c[5]||"");return this},protocol:Db("$$protocol"),
+host:Db("$$host"),port:Db("$$port"),path:kd("$$path",function(a){a=null!==a?a.toString():"";return"/"==a.charAt(0)?a:"/"+a}),search:function(a,c){switch(arguments.length){case 0:return this.$$search;case 1:if(L(a)||V(a))a=a.toString(),this.$$search=zc(a);else if(H(a))a=fa(a,{}),m(a,function(c,e){null==c&&delete a[e]}),this.$$search=a;else throw Cb("isrcharg");break;default:A(c)||null===c?delete this.$$search[a]:this.$$search[a]=c}this.$$compose();return this},hash:kd("$$hash",function(a){return null!==
+a?a.toString():""}),replace:function(){this.$$replace=!0;return this}};m([jd,ec,dc],function(a){a.prototype=Object.create(pg);a.prototype.state=function(c){if(!arguments.length)return this.$$state;if(a!==dc||!this.$$html5)throw Cb("nostate");this.$$state=A(c)?null:c;return this}});var da=J("$parse"),Uf=Function.prototype.call,Vf=Function.prototype.apply,Wf=Function.prototype.bind,Mb=ga();m("+ - * / % === !== == != < > <= >= && || ! = |".split(" "),function(a){Mb[a]=!0});var qg={n:"\n",f:"\f",r:"\r",
+t:"\t",v:"\v","'":"'",'"':'"'},gc=function(a){this.options=a};gc.prototype={constructor:gc,lex:function(a){this.text=a;this.index=0;for(this.tokens=[];this.index<this.text.length;)if(a=this.text.charAt(this.index),'"'===a||"'"===a)this.readString(a);else if(this.isNumber(a)||"."===a&&this.isNumber(this.peek()))this.readNumber();else if(this.isIdent(a))this.readIdent();else if(this.is(a,"(){}[].,;:?"))this.tokens.push({index:this.index,text:a}),this.index++;else if(this.isWhitespace(a))this.index++;
+else{var c=a+this.peek(),d=c+this.peek(2),e=Mb[c],f=Mb[d];Mb[a]||e||f?(a=f?d:e?c:a,this.tokens.push({index:this.index,text:a,operator:!0}),this.index+=a.length):this.throwError("Unexpected next character ",this.index,this.index+1)}return this.tokens},is:function(a,c){return-1!==c.indexOf(a)},peek:function(a){a=a||1;return this.index+a<this.text.length?this.text.charAt(this.index+a):!1},isNumber:function(a){return"0"<=a&&"9">=a&&"string"===typeof a},isWhitespace:function(a){return" "===a||"\r"===a||
+"\t"===a||"\n"===a||"\v"===a||"\u00a0"===a},isIdent:function(a){return"a"<=a&&"z">=a||"A"<=a&&"Z">=a||"_"===a||"$"===a},isExpOperator:function(a){return"-"===a||"+"===a||this.isNumber(a)},throwError:function(a,c,d){d=d||this.index;c=w(c)?"s "+c+"-"+this.index+" ["+this.text.substring(c,d)+"]":" "+d;throw da("lexerr",a,c,this.text);},readNumber:function(){for(var a="",c=this.index;this.index<this.text.length;){var d=M(this.text.charAt(this.index));if("."==d||this.isNumber(d))a+=d;else{var e=this.peek();
+if("e"==d&&this.isExpOperator(e))a+=d;else if(this.isExpOperator(d)&&e&&this.isNumber(e)&&"e"==a.charAt(a.length-1))a+=d;else if(!this.isExpOperator(d)||e&&this.isNumber(e)||"e"!=a.charAt(a.length-1))break;else this.throwError("Invalid exponent")}this.index++}this.tokens.push({index:c,text:a,constant:!0,value:Number(a)})},readIdent:function(){for(var a=this.index;this.index<this.text.length;){var c=this.text.charAt(this.index);if(!this.isIdent(c)&&!this.isNumber(c))break;this.index++}this.tokens.push({index:a,
+text:this.text.slice(a,this.index),identifier:!0})},readString:function(a){var c=this.index;this.index++;for(var d="",e=a,f=!1;this.index<this.text.length;){var g=this.text.charAt(this.index),e=e+g;if(f)"u"===g?(f=this.text.substring(this.index+1,this.index+5),f.match(/[\da-f]{4}/i)||this.throwError("Invalid unicode escape [\\u"+f+"]"),this.index+=4,d+=String.fromCharCode(parseInt(f,16))):d+=qg[g]||g,f=!1;else if("\\"===g)f=!0;else{if(g===a){this.index++;this.tokens.push({index:c,text:e,constant:!0,
+value:d});return}d+=g}this.index++}this.throwError("Unterminated quote",c)}};var q=function(a,c){this.lexer=a;this.options=c};q.Program="Program";q.ExpressionStatement="ExpressionStatement";q.AssignmentExpression="AssignmentExpression";q.ConditionalExpression="ConditionalExpression";q.LogicalExpression="LogicalExpression";q.BinaryExpression="BinaryExpression";q.UnaryExpression="UnaryExpression";q.CallExpression="CallExpression";q.MemberExpression="MemberExpression";q.Identifier="Identifier";q.Literal=
+"Literal";q.ArrayExpression="ArrayExpression";q.Property="Property";q.ObjectExpression="ObjectExpression";q.ThisExpression="ThisExpression";q.NGValueParameter="NGValueParameter";q.prototype={ast:function(a){this.text=a;this.tokens=this.lexer.lex(a);a=this.program();0!==this.tokens.length&&this.throwError("is an unexpected token",this.tokens[0]);return a},program:function(){for(var a=[];;)if(0<this.tokens.length&&!this.peek("}",")",";","]")&&a.push(this.expressionStatement()),!this.expect(";"))return{type:q.Program,
+body:a}},expressionStatement:function(){return{type:q.ExpressionStatement,expression:this.filterChain()}},filterChain:function(){for(var a=this.expression();this.expect("|");)a=this.filter(a);return a},expression:function(){return this.assignment()},assignment:function(){var a=this.ternary();this.expect("=")&&(a={type:q.AssignmentExpression,left:a,right:this.assignment(),operator:"="});return a},ternary:function(){var a=this.logicalOR(),c,d;return this.expect("?")&&(c=this.expression(),this.consume(":"))?
+(d=this.expression(),{type:q.ConditionalExpression,test:a,alternate:c,consequent:d}):a},logicalOR:function(){for(var a=this.logicalAND();this.expect("||");)a={type:q.LogicalExpression,operator:"||",left:a,right:this.logicalAND()};return a},logicalAND:function(){for(var a=this.equality();this.expect("&&");)a={type:q.LogicalExpression,operator:"&&",left:a,right:this.equality()};return a},equality:function(){for(var a=this.relational(),c;c=this.expect("==","!=","===","!==");)a={type:q.BinaryExpression,
+operator:c.text,left:a,right:this.relational()};return a},relational:function(){for(var a=this.additive(),c;c=this.expect("<",">","<=",">=");)a={type:q.BinaryExpression,operator:c.text,left:a,right:this.additive()};return a},additive:function(){for(var a=this.multiplicative(),c;c=this.expect("+","-");)a={type:q.BinaryExpression,operator:c.text,left:a,right:this.multiplicative()};return a},multiplicative:function(){for(var a=this.unary(),c;c=this.expect("*","/","%");)a={type:q.BinaryExpression,operator:c.text,
+left:a,right:this.unary()};return a},unary:function(){var a;return(a=this.expect("+","-","!"))?{type:q.UnaryExpression,operator:a.text,prefix:!0,argument:this.unary()}:this.primary()},primary:function(){var a;this.expect("(")?(a=this.filterChain(),this.consume(")")):this.expect("[")?a=this.arrayDeclaration():this.expect("{")?a=this.object():this.constants.hasOwnProperty(this.peek().text)?a=fa(this.constants[this.consume().text]):this.peek().identifier?a=this.identifier():this.peek().constant?a=this.constant():
+this.throwError("not a primary expression",this.peek());for(var c;c=this.expect("(","[",".");)"("===c.text?(a={type:q.CallExpression,callee:a,arguments:this.parseArguments()},this.consume(")")):"["===c.text?(a={type:q.MemberExpression,object:a,property:this.expression(),computed:!0},this.consume("]")):"."===c.text?a={type:q.MemberExpression,object:a,property:this.identifier(),computed:!1}:this.throwError("IMPOSSIBLE");return a},filter:function(a){a=[a];for(var c={type:q.CallExpression,callee:this.identifier(),
+arguments:a,filter:!0};this.expect(":");)a.push(this.expression());return c},parseArguments:function(){var a=[];if(")"!==this.peekToken().text){do a.push(this.expression());while(this.expect(","))}return a},identifier:function(){var a=this.consume();a.identifier||this.throwError("is not a valid identifier",a);return{type:q.Identifier,name:a.text}},constant:function(){return{type:q.Literal,value:this.consume().value}},arrayDeclaration:function(){var a=[];if("]"!==this.peekToken().text){do{if(this.peek("]"))break;
+a.push(this.expression())}while(this.expect(","))}this.consume("]");return{type:q.ArrayExpression,elements:a}},object:function(){var a=[],c;if("}"!==this.peekToken().text){do{if(this.peek("}"))break;c={type:q.Property,kind:"init"};this.peek().constant?c.key=this.constant():this.peek().identifier?c.key=this.identifier():this.throwError("invalid key",this.peek());this.consume(":");c.value=this.expression();a.push(c)}while(this.expect(","))}this.consume("}");return{type:q.ObjectExpression,properties:a}},
+throwError:function(a,c){throw da("syntax",c.text,a,c.index+1,this.text,this.text.substring(c.index));},consume:function(a){if(0===this.tokens.length)throw da("ueoe",this.text);var c=this.expect(a);c||this.throwError("is unexpected, expecting ["+a+"]",this.peek());return c},peekToken:function(){if(0===this.tokens.length)throw da("ueoe",this.text);return this.tokens[0]},peek:function(a,c,d,e){return this.peekAhead(0,a,c,d,e)},peekAhead:function(a,c,d,e,f){if(this.tokens.length>a){a=this.tokens[a];
+var g=a.text;if(g===c||g===d||g===e||g===f||!(c||d||e||f))return a}return!1},expect:function(a,c,d,e){return(a=this.peek(a,c,d,e))?(this.tokens.shift(),a):!1},constants:{"true":{type:q.Literal,value:!0},"false":{type:q.Literal,value:!1},"null":{type:q.Literal,value:null},undefined:{type:q.Literal,value:t},"this":{type:q.ThisExpression}}};rd.prototype={compile:function(a,c){var d=this,e=this.astBuilder.ast(a);this.state={nextId:0,filters:{},expensiveChecks:c,fn:{vars:[],body:[],own:{}},assign:{vars:[],
+body:[],own:{}},inputs:[]};T(e,d.$filter);var f="",g;this.stage="assign";if(g=pd(e))this.state.computing="assign",f=this.nextId(),this.recurse(g,f),f="fn.assign="+this.generateFunction("assign","s,v,l");g=nd(e.body);d.stage="inputs";m(g,function(a,c){var e="fn"+c;d.state[e]={vars:[],body:[],own:{}};d.state.computing=e;var f=d.nextId();d.recurse(a,f);d.return_(f);d.state.inputs.push(e);a.watchId=c});this.state.computing="fn";this.stage="main";this.recurse(e);f='"'+this.USE+" "+this.STRICT+'";\n'+this.filterPrefix()+
+"var fn="+this.generateFunction("fn","s,l,a,i")+f+this.watchFns()+"return fn;";f=(new Function("$filter","ensureSafeMemberName","ensureSafeObject","ensureSafeFunction","ifDefined","plus","text",f))(this.$filter,Ca,oa,ld,Xf,md,a);this.state=this.stage=t;f.literal=qd(e);f.constant=e.constant;return f},USE:"use",STRICT:"strict",watchFns:function(){var a=[],c=this.state.inputs,d=this;m(c,function(c){a.push("var "+c+"="+d.generateFunction(c,"s"))});c.length&&a.push("fn.inputs=["+c.join(",")+"];");return a.join("")},
+generateFunction:function(a,c){return"function("+c+"){"+this.varsPrefix(a)+this.body(a)+"};"},filterPrefix:function(){var a=[],c=this;m(this.state.filters,function(d,e){a.push(d+"=$filter("+c.escape(e)+")")});return a.length?"var "+a.join(",")+";":""},varsPrefix:function(a){return this.state[a].vars.length?"var "+this.state[a].vars.join(",")+";":""},body:function(a){return this.state[a].body.join("")},recurse:function(a,c,d,e,f,g){var h,l,k=this,n,r;e=e||v;if(!g&&w(a.watchId))c=c||this.nextId(),this.if_("i",
+this.lazyAssign(c,this.computedMember("i",a.watchId)),this.lazyRecurse(a,c,d,e,f,!0));else switch(a.type){case q.Program:m(a.body,function(c,d){k.recurse(c.expression,t,t,function(a){l=a});d!==a.body.length-1?k.current().body.push(l,";"):k.return_(l)});break;case q.Literal:r=this.escape(a.value);this.assign(c,r);e(r);break;case q.UnaryExpression:this.recurse(a.argument,t,t,function(a){l=a});r=a.operator+"("+this.ifDefined(l,0)+")";this.assign(c,r);e(r);break;case q.BinaryExpression:this.recurse(a.left,
+t,t,function(a){h=a});this.recurse(a.right,t,t,function(a){l=a});r="+"===a.operator?this.plus(h,l):"-"===a.operator?this.ifDefined(h,0)+a.operator+this.ifDefined(l,0):"("+h+")"+a.operator+"("+l+")";this.assign(c,r);e(r);break;case q.LogicalExpression:c=c||this.nextId();k.recurse(a.left,c);k.if_("&&"===a.operator?c:k.not(c),k.lazyRecurse(a.right,c));e(c);break;case q.ConditionalExpression:c=c||this.nextId();k.recurse(a.test,c);k.if_(c,k.lazyRecurse(a.alternate,c),k.lazyRecurse(a.consequent,c));e(c);
+break;case q.Identifier:c=c||this.nextId();d&&(d.context="inputs"===k.stage?"s":this.assign(this.nextId(),this.getHasOwnProperty("l",a.name)+"?l:s"),d.computed=!1,d.name=a.name);Ca(a.name);k.if_("inputs"===k.stage||k.not(k.getHasOwnProperty("l",a.name)),function(){k.if_("inputs"===k.stage||"s",function(){f&&1!==f&&k.if_(k.not(k.nonComputedMember("s",a.name)),k.lazyAssign(k.nonComputedMember("s",a.name),"{}"));k.assign(c,k.nonComputedMember("s",a.name))})},c&&k.lazyAssign(c,k.nonComputedMember("l",
+a.name)));(k.state.expensiveChecks||Fb(a.name))&&k.addEnsureSafeObject(c);e(c);break;case q.MemberExpression:h=d&&(d.context=this.nextId())||this.nextId();c=c||this.nextId();k.recurse(a.object,h,t,function(){k.if_(k.notNull(h),function(){if(a.computed)l=k.nextId(),k.recurse(a.property,l),k.addEnsureSafeMemberName(l),f&&1!==f&&k.if_(k.not(k.computedMember(h,l)),k.lazyAssign(k.computedMember(h,l),"{}")),r=k.ensureSafeObject(k.computedMember(h,l)),k.assign(c,r),d&&(d.computed=!0,d.name=l);else{Ca(a.property.name);
+f&&1!==f&&k.if_(k.not(k.nonComputedMember(h,a.property.name)),k.lazyAssign(k.nonComputedMember(h,a.property.name),"{}"));r=k.nonComputedMember(h,a.property.name);if(k.state.expensiveChecks||Fb(a.property.name))r=k.ensureSafeObject(r);k.assign(c,r);d&&(d.computed=!1,d.name=a.property.name)}},function(){k.assign(c,"undefined")});e(c)},!!f);break;case q.CallExpression:c=c||this.nextId();a.filter?(l=k.filter(a.callee.name),n=[],m(a.arguments,function(a){var c=k.nextId();k.recurse(a,c);n.push(c)}),r=l+
+"("+n.join(",")+")",k.assign(c,r),e(c)):(l=k.nextId(),h={},n=[],k.recurse(a.callee,l,h,function(){k.if_(k.notNull(l),function(){k.addEnsureSafeFunction(l);m(a.arguments,function(a){k.recurse(a,k.nextId(),t,function(a){n.push(k.ensureSafeObject(a))})});h.name?(k.state.expensiveChecks||k.addEnsureSafeObject(h.context),r=k.member(h.context,h.name,h.computed)+"("+n.join(",")+")"):r=l+"("+n.join(",")+")";r=k.ensureSafeObject(r);k.assign(c,r)},function(){k.assign(c,"undefined")});e(c)}));break;case q.AssignmentExpression:l=
+this.nextId();h={};if(!od(a.left))throw da("lval");this.recurse(a.left,t,h,function(){k.if_(k.notNull(h.context),function(){k.recurse(a.right,l);k.addEnsureSafeObject(k.member(h.context,h.name,h.computed));r=k.member(h.context,h.name,h.computed)+a.operator+l;k.assign(c,r);e(c||r)})},1);break;case q.ArrayExpression:n=[];m(a.elements,function(a){k.recurse(a,k.nextId(),t,function(a){n.push(a)})});r="["+n.join(",")+"]";this.assign(c,r);e(r);break;case q.ObjectExpression:n=[];m(a.properties,function(a){k.recurse(a.value,
+k.nextId(),t,function(c){n.push(k.escape(a.key.type===q.Identifier?a.key.name:""+a.key.value)+":"+c)})});r="{"+n.join(",")+"}";this.assign(c,r);e(r);break;case q.ThisExpression:this.assign(c,"s");e("s");break;case q.NGValueParameter:this.assign(c,"v"),e("v")}},getHasOwnProperty:function(a,c){var d=a+"."+c,e=this.current().own;e.hasOwnProperty(d)||(e[d]=this.nextId(!1,a+"&&("+this.escape(c)+" in "+a+")"));return e[d]},assign:function(a,c){if(a)return this.current().body.push(a,"=",c,";"),a},filter:function(a){this.state.filters.hasOwnProperty(a)||
+(this.state.filters[a]=this.nextId(!0));return this.state.filters[a]},ifDefined:function(a,c){return"ifDefined("+a+","+this.escape(c)+")"},plus:function(a,c){return"plus("+a+","+c+")"},return_:function(a){this.current().body.push("return ",a,";")},if_:function(a,c,d){if(!0===a)c();else{var e=this.current().body;e.push("if(",a,"){");c();e.push("}");d&&(e.push("else{"),d(),e.push("}"))}},not:function(a){return"!("+a+")"},notNull:function(a){return a+"!=null"},nonComputedMember:function(a,c){return a+
+"."+c},computedMember:function(a,c){return a+"["+c+"]"},member:function(a,c,d){return d?this.computedMember(a,c):this.nonComputedMember(a,c)},addEnsureSafeObject:function(a){this.current().body.push(this.ensureSafeObject(a),";")},addEnsureSafeMemberName:function(a){this.current().body.push(this.ensureSafeMemberName(a),";")},addEnsureSafeFunction:function(a){this.current().body.push(this.ensureSafeFunction(a),";")},ensureSafeObject:function(a){return"ensureSafeObject("+a+",text)"},ensureSafeMemberName:function(a){return"ensureSafeMemberName("+
+a+",text)"},ensureSafeFunction:function(a){return"ensureSafeFunction("+a+",text)"},lazyRecurse:function(a,c,d,e,f,g){var h=this;return function(){h.recurse(a,c,d,e,f,g)}},lazyAssign:function(a,c){var d=this;return function(){d.assign(a,c)}},stringEscapeRegex:/[^ a-zA-Z0-9]/g,stringEscapeFn:function(a){return"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)},escape:function(a){if(L(a))return"'"+a.replace(this.stringEscapeRegex,this.stringEscapeFn)+"'";if(V(a))return a.toString();if(!0===a)return"true";
+if(!1===a)return"false";if(null===a)return"null";if("undefined"===typeof a)return"undefined";throw da("esc");},nextId:function(a,c){var d="v"+this.state.nextId++;a||this.current().vars.push(d+(c?"="+c:""));return d},current:function(){return this.state[this.state.computing]}};sd.prototype={compile:function(a,c){var d=this,e=this.astBuilder.ast(a);this.expression=a;this.expensiveChecks=c;T(e,d.$filter);var f,g;if(f=pd(e))g=this.recurse(f);f=nd(e.body);var h;f&&(h=[],m(f,function(a,c){var e=d.recurse(a);
+a.input=e;h.push(e);a.watchId=c}));var l=[];m(e.body,function(a){l.push(d.recurse(a.expression))});f=0===e.body.length?function(){}:1===e.body.length?l[0]:function(a,c){var d;m(l,function(e){d=e(a,c)});return d};g&&(f.assign=function(a,c,d){return g(a,d,c)});h&&(f.inputs=h);f.literal=qd(e);f.constant=e.constant;return f},recurse:function(a,c,d){var e,f,g=this,h;if(a.input)return this.inputs(a.input,a.watchId);switch(a.type){case q.Literal:return this.value(a.value,c);case q.UnaryExpression:return f=
+this.recurse(a.argument),this["unary"+a.operator](f,c);case q.BinaryExpression:return e=this.recurse(a.left),f=this.recurse(a.right),this["binary"+a.operator](e,f,c);case q.LogicalExpression:return e=this.recurse(a.left),f=this.recurse(a.right),this["binary"+a.operator](e,f,c);case q.ConditionalExpression:return this["ternary?:"](this.recurse(a.test),this.recurse(a.alternate),this.recurse(a.consequent),c);case q.Identifier:return Ca(a.name,g.expression),g.identifier(a.name,g.expensiveChecks||Fb(a.name),
+c,d,g.expression);case q.MemberExpression:return e=this.recurse(a.object,!1,!!d),a.computed||(Ca(a.property.name,g.expression),f=a.property.name),a.computed&&(f=this.recurse(a.property)),a.computed?this.computedMember(e,f,c,d,g.expression):this.nonComputedMember(e,f,g.expensiveChecks,c,d,g.expression);case q.CallExpression:return h=[],m(a.arguments,function(a){h.push(g.recurse(a))}),a.filter&&(f=this.$filter(a.callee.name)),a.filter||(f=this.recurse(a.callee,!0)),a.filter?function(a,d,e,g){for(var m=
+[],q=0;q<h.length;++q)m.push(h[q](a,d,e,g));a=f.apply(t,m,g);return c?{context:t,name:t,value:a}:a}:function(a,d,e,r){var m=f(a,d,e,r),q;if(null!=m.value){oa(m.context,g.expression);ld(m.value,g.expression);q=[];for(var t=0;t<h.length;++t)q.push(oa(h[t](a,d,e,r),g.expression));q=oa(m.value.apply(m.context,q),g.expression)}return c?{value:q}:q};case q.AssignmentExpression:return e=this.recurse(a.left,!0,1),f=this.recurse(a.right),function(a,d,h,r){var m=e(a,d,h,r);a=f(a,d,h,r);oa(m.value,g.expression);
+m.context[m.name]=a;return c?{value:a}:a};case q.ArrayExpression:return h=[],m(a.elements,function(a){h.push(g.recurse(a))}),function(a,d,e,f){for(var g=[],m=0;m<h.length;++m)g.push(h[m](a,d,e,f));return c?{value:g}:g};case q.ObjectExpression:return h=[],m(a.properties,function(a){h.push({key:a.key.type===q.Identifier?a.key.name:""+a.key.value,value:g.recurse(a.value)})}),function(a,d,e,f){for(var g={},m=0;m<h.length;++m)g[h[m].key]=h[m].value(a,d,e,f);return c?{value:g}:g};case q.ThisExpression:return function(a){return c?
+{value:a}:a};case q.NGValueParameter:return function(a,d,e,f){return c?{value:e}:e}}},"unary+":function(a,c){return function(d,e,f,g){d=a(d,e,f,g);d=w(d)?+d:0;return c?{value:d}:d}},"unary-":function(a,c){return function(d,e,f,g){d=a(d,e,f,g);d=w(d)?-d:0;return c?{value:d}:d}},"unary!":function(a,c){return function(d,e,f,g){d=!a(d,e,f,g);return c?{value:d}:d}},"binary+":function(a,c,d){return function(e,f,g,h){var l=a(e,f,g,h);e=c(e,f,g,h);l=md(l,e);return d?{value:l}:l}},"binary-":function(a,c,d){return function(e,
+f,g,h){var l=a(e,f,g,h);e=c(e,f,g,h);l=(w(l)?l:0)-(w(e)?e:0);return d?{value:l}:l}},"binary*":function(a,c,d){return function(e,f,g,h){e=a(e,f,g,h)*c(e,f,g,h);return d?{value:e}:e}},"binary/":function(a,c,d){return function(e,f,g,h){e=a(e,f,g,h)/c(e,f,g,h);return d?{value:e}:e}},"binary%":function(a,c,d){return function(e,f,g,h){e=a(e,f,g,h)%c(e,f,g,h);return d?{value:e}:e}},"binary===":function(a,c,d){return function(e,f,g,h){e=a(e,f,g,h)===c(e,f,g,h);return d?{value:e}:e}},"binary!==":function(a,
+c,d){return function(e,f,g,h){e=a(e,f,g,h)!==c(e,f,g,h);return d?{value:e}:e}},"binary==":function(a,c,d){return function(e,f,g,h){e=a(e,f,g,h)==c(e,f,g,h);return d?{value:e}:e}},"binary!=":function(a,c,d){return function(e,f,g,h){e=a(e,f,g,h)!=c(e,f,g,h);return d?{value:e}:e}},"binary<":function(a,c,d){return function(e,f,g,h){e=a(e,f,g,h)<c(e,f,g,h);return d?{value:e}:e}},"binary>":function(a,c,d){return function(e,f,g,h){e=a(e,f,g,h)>c(e,f,g,h);return d?{value:e}:e}},"binary<=":function(a,c,d){return function(e,
+f,g,h){e=a(e,f,g,h)<=c(e,f,g,h);return d?{value:e}:e}},"binary>=":function(a,c,d){return function(e,f,g,h){e=a(e,f,g,h)>=c(e,f,g,h);return d?{value:e}:e}},"binary&&":function(a,c,d){return function(e,f,g,h){e=a(e,f,g,h)&&c(e,f,g,h);return d?{value:e}:e}},"binary||":function(a,c,d){return function(e,f,g,h){e=a(e,f,g,h)||c(e,f,g,h);return d?{value:e}:e}},"ternary?:":function(a,c,d,e){return function(f,g,h,l){f=a(f,g,h,l)?c(f,g,h,l):d(f,g,h,l);return e?{value:f}:f}},value:function(a,c){return function(){return c?
+{context:t,name:t,value:a}:a}},identifier:function(a,c,d,e,f){return function(g,h,l,k){g=h&&a in h?h:g;e&&1!==e&&g&&!g[a]&&(g[a]={});h=g?g[a]:t;c&&oa(h,f);return d?{context:g,name:a,value:h}:h}},computedMember:function(a,c,d,e,f){return function(g,h,l,k){var n=a(g,h,l,k),m,s;null!=n&&(m=c(g,h,l,k),Ca(m,f),e&&1!==e&&n&&!n[m]&&(n[m]={}),s=n[m],oa(s,f));return d?{context:n,name:m,value:s}:s}},nonComputedMember:function(a,c,d,e,f,g){return function(h,l,k,n){h=a(h,l,k,n);f&&1!==f&&h&&!h[c]&&(h[c]={});
+l=null!=h?h[c]:t;(d||Fb(c))&&oa(l,g);return e?{context:h,name:c,value:l}:l}},inputs:function(a,c){return function(d,e,f,g){return g?g[c]:a(d,e,f)}}};var hc=function(a,c,d){this.lexer=a;this.$filter=c;this.options=d;this.ast=new q(this.lexer);this.astCompiler=d.csp?new sd(this.ast,c):new rd(this.ast,c)};hc.prototype={constructor:hc,parse:function(a){return this.astCompiler.compile(a,this.options.expensiveChecks)}};ga();ga();var Yf=Object.prototype.valueOf,Da=J("$sce"),pa={HTML:"html",CSS:"css",URL:"url",
+RESOURCE_URL:"resourceUrl",JS:"js"},ea=J("$compile"),X=U.createElement("a"),wd=Ba(O.location.href);xd.$inject=["$document"];Lc.$inject=["$provide"];yd.$inject=["$locale"];Ad.$inject=["$locale"];var Dd=".",hg={yyyy:Y("FullYear",4),yy:Y("FullYear",2,0,!0),y:Y("FullYear",1),MMMM:Hb("Month"),MMM:Hb("Month",!0),MM:Y("Month",2,1),M:Y("Month",1,1),dd:Y("Date",2),d:Y("Date",1),HH:Y("Hours",2),H:Y("Hours",1),hh:Y("Hours",2,-12),h:Y("Hours",1,-12),mm:Y("Minutes",2),m:Y("Minutes",1),ss:Y("Seconds",2),s:Y("Seconds",
+1),sss:Y("Milliseconds",3),EEEE:Hb("Day"),EEE:Hb("Day",!0),a:function(a,c){return 12>a.getHours()?c.AMPMS[0]:c.AMPMS[1]},Z:function(a,c,d){a=-1*d;return a=(0<=a?"+":"")+(Gb(Math[0<a?"floor":"ceil"](a/60),2)+Gb(Math.abs(a%60),2))},ww:Fd(2),w:Fd(1),G:jc,GG:jc,GGG:jc,GGGG:function(a,c){return 0>=a.getFullYear()?c.ERANAMES[0]:c.ERANAMES[1]}},gg=/((?:[^yMdHhmsaZEwG']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+|H+|h+|m+|s+|a|Z|G+|w+))(.*)/,fg=/^\-?\d+$/;zd.$inject=["$locale"];var cg=ra(M),dg=ra(rb);Bd.$inject=
+["$parse"];var ie=ra({restrict:"E",compile:function(a,c){if(!c.href&&!c.xlinkHref)return function(a,c){if("a"===c[0].nodeName.toLowerCase()){var f="[object SVGAnimatedString]"===sa.call(c.prop("href"))?"xlink:href":"href";c.on("click",function(a){c.attr(f)||a.preventDefault()})}}}}),sb={};m(Ab,function(a,c){function d(a,d,f){a.$watch(f[e],function(a){f.$set(c,!!a)})}if("multiple"!=a){var e=wa("ng-"+c),f=d;"checked"===a&&(f=function(a,c,f){f.ngModel!==f[e]&&d(a,c,f)});sb[e]=function(){return{restrict:"A",
+priority:100,link:f}}}});m(Uc,function(a,c){sb[c]=function(){return{priority:100,link:function(a,e,f){if("ngPattern"===c&&"/"==f.ngPattern.charAt(0)&&(e=f.ngPattern.match(jg))){f.$set("ngPattern",new RegExp(e[1],e[2]));return}a.$watch(f[c],function(a){f.$set(c,a)})}}}});m(["src","srcset","href"],function(a){var c=wa("ng-"+a);sb[c]=function(){return{priority:99,link:function(d,e,f){var g=a,h=a;"href"===a&&"[object SVGAnimatedString]"===sa.call(e.prop("href"))&&(h="xlinkHref",f.$attr[h]="xlink:href",
+g=null);f.$observe(c,function(c){c?(f.$set(h,c),Ua&&g&&e.prop(g,f[h])):"href"===a&&f.$set(h,null)})}}}});var Ib={$addControl:v,$$renameControl:function(a,c){a.$name=c},$removeControl:v,$setValidity:v,$setDirty:v,$setPristine:v,$setSubmitted:v};Gd.$inject=["$element","$attrs","$scope","$animate","$interpolate"];var Od=function(a){return["$timeout",function(c){return{name:"form",restrict:a?"EAC":"E",controller:Gd,compile:function(d,e){d.addClass(Va).addClass(mb);var f=e.name?"name":a&&e.ngForm?"ngForm":
+!1;return{pre:function(a,d,e,k){if(!("action"in e)){var n=function(c){a.$apply(function(){k.$commitViewValue();k.$setSubmitted()});c.preventDefault()};d[0].addEventListener("submit",n,!1);d.on("$destroy",function(){c(function(){d[0].removeEventListener("submit",n,!1)},0,!1)})}var m=k.$$parentForm;f&&(Eb(a,k.$name,k,k.$name),e.$observe(f,function(c){k.$name!==c&&(Eb(a,k.$name,t,k.$name),m.$$renameControl(k,c),Eb(a,k.$name,k,k.$name))}));d.on("$destroy",function(){m.$removeControl(k);f&&Eb(a,e[f],t,
+k.$name);P(k,Ib)})}}}}}]},je=Od(),we=Od(!0),ig=/\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z)/,rg=/^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/,sg=/^[a-z0-9!#$%&'*+\/=?^_`{|}~.-]+@[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i,tg=/^\s*(\-|\+)?(\d+|(\d*(\.\d*)))([eE][+-]?\d+)?\s*$/,Pd=/^(\d{4})-(\d{2})-(\d{2})$/,Qd=/^(\d{4})-(\d\d)-(\d\d)T(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/,mc=/^(\d{4})-W(\d\d)$/,Rd=/^(\d{4})-(\d\d)$/,
+Sd=/^(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/,Td={text:function(a,c,d,e,f,g){kb(a,c,d,e,f,g);kc(e)},date:lb("date",Pd,Kb(Pd,["yyyy","MM","dd"]),"yyyy-MM-dd"),"datetime-local":lb("datetimelocal",Qd,Kb(Qd,"yyyy MM dd HH mm ss sss".split(" ")),"yyyy-MM-ddTHH:mm:ss.sss"),time:lb("time",Sd,Kb(Sd,["HH","mm","ss","sss"]),"HH:mm:ss.sss"),week:lb("week",mc,function(a,c){if(aa(a))return a;if(L(a)){mc.lastIndex=0;var d=mc.exec(a);if(d){var e=+d[1],f=+d[2],g=d=0,h=0,l=0,k=Ed(e),f=7*(f-1);c&&(d=c.getHours(),g=
+c.getMinutes(),h=c.getSeconds(),l=c.getMilliseconds());return new Date(e,0,k.getDate()+f,d,g,h,l)}}return NaN},"yyyy-Www"),month:lb("month",Rd,Kb(Rd,["yyyy","MM"]),"yyyy-MM"),number:function(a,c,d,e,f,g){Id(a,c,d,e);kb(a,c,d,e,f,g);e.$$parserName="number";e.$parsers.push(function(a){return e.$isEmpty(a)?null:tg.test(a)?parseFloat(a):t});e.$formatters.push(function(a){if(!e.$isEmpty(a)){if(!V(a))throw Lb("numfmt",a);a=a.toString()}return a});if(w(d.min)||d.ngMin){var h;e.$validators.min=function(a){return e.$isEmpty(a)||
+A(h)||a>=h};d.$observe("min",function(a){w(a)&&!V(a)&&(a=parseFloat(a,10));h=V(a)&&!isNaN(a)?a:t;e.$validate()})}if(w(d.max)||d.ngMax){var l;e.$validators.max=function(a){return e.$isEmpty(a)||A(l)||a<=l};d.$observe("max",function(a){w(a)&&!V(a)&&(a=parseFloat(a,10));l=V(a)&&!isNaN(a)?a:t;e.$validate()})}},url:function(a,c,d,e,f,g){kb(a,c,d,e,f,g);kc(e);e.$$parserName="url";e.$validators.url=function(a,c){var d=a||c;return e.$isEmpty(d)||rg.test(d)}},email:function(a,c,d,e,f,g){kb(a,c,d,e,f,g);kc(e);
+e.$$parserName="email";e.$validators.email=function(a,c){var d=a||c;return e.$isEmpty(d)||sg.test(d)}},radio:function(a,c,d,e){A(d.name)&&c.attr("name",++nb);c.on("click",function(a){c[0].checked&&e.$setViewValue(d.value,a&&a.type)});e.$render=function(){c[0].checked=d.value==e.$viewValue};d.$observe("value",e.$render)},checkbox:function(a,c,d,e,f,g,h,l){var k=Jd(l,a,"ngTrueValue",d.ngTrueValue,!0),n=Jd(l,a,"ngFalseValue",d.ngFalseValue,!1);c.on("click",function(a){e.$setViewValue(c[0].checked,a&&
+a.type)});e.$render=function(){c[0].checked=e.$viewValue};e.$isEmpty=function(a){return!1===a};e.$formatters.push(function(a){return ka(a,k)});e.$parsers.push(function(a){return a?k:n})},hidden:v,button:v,submit:v,reset:v,file:v},Fc=["$browser","$sniffer","$filter","$parse",function(a,c,d,e){return{restrict:"E",require:["?ngModel"],link:{pre:function(f,g,h,l){l[0]&&(Td[M(h.type)]||Td.text)(f,g,h,l[0],c,a,d,e)}}}}],ug=/^(true|false|\d+)$/,Oe=function(){return{restrict:"A",priority:100,compile:function(a,
+c){return ug.test(c.ngValue)?function(a,c,f){f.$set("value",a.$eval(f.ngValue))}:function(a,c,f){a.$watch(f.ngValue,function(a){f.$set("value",a)})}}}},oe=["$compile",function(a){return{restrict:"AC",compile:function(c){a.$$addBindingClass(c);return function(c,e,f){a.$$addBindingInfo(e,f.ngBind);e=e[0];c.$watch(f.ngBind,function(a){e.textContent=a===t?"":a})}}}}],qe=["$interpolate","$compile",function(a,c){return{compile:function(d){c.$$addBindingClass(d);return function(d,f,g){d=a(f.attr(g.$attr.ngBindTemplate));
+c.$$addBindingInfo(f,d.expressions);f=f[0];g.$observe("ngBindTemplate",function(a){f.textContent=a===t?"":a})}}}}],pe=["$sce","$parse","$compile",function(a,c,d){return{restrict:"A",compile:function(e,f){var g=c(f.ngBindHtml),h=c(f.ngBindHtml,function(a){return(a||"").toString()});d.$$addBindingClass(e);return function(c,e,f){d.$$addBindingInfo(e,f.ngBindHtml);c.$watch(h,function(){e.html(a.getTrustedHtml(g(c))||"")})}}}}],Ne=ra({restrict:"A",require:"ngModel",link:function(a,c,d,e){e.$viewChangeListeners.push(function(){a.$eval(d.ngChange)})}}),
+re=lc("",!0),te=lc("Odd",0),se=lc("Even",1),ue=Ma({compile:function(a,c){c.$set("ngCloak",t);a.removeClass("ng-cloak")}}),ve=[function(){return{restrict:"A",scope:!0,controller:"@",priority:500}}],Kc={},vg={blur:!0,focus:!0};m("click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave keydown keyup keypress submit focus blur copy cut paste".split(" "),function(a){var c=wa("ng-"+a);Kc[c]=["$parse","$rootScope",function(d,e){return{restrict:"A",compile:function(f,g){var h=
+d(g[c],null,!0);return function(c,d){d.on(a,function(d){var f=function(){h(c,{$event:d})};vg[a]&&e.$$phase?c.$evalAsync(f):c.$apply(f)})}}}}]});var ye=["$animate",function(a){return{multiElement:!0,transclude:"element",priority:600,terminal:!0,restrict:"A",$$tlb:!0,link:function(c,d,e,f,g){var h,l,k;c.$watch(e.ngIf,function(c){c?l||g(function(c,f){l=f;c[c.length++]=U.createComment(" end ngIf: "+e.ngIf+" ");h={clone:c};a.enter(c,d.parent(),d)}):(k&&(k.remove(),k=null),l&&(l.$destroy(),l=null),h&&(k=
+qb(h.clone),a.leave(k).then(function(){k=null}),h=null))})}}}],ze=["$templateRequest","$anchorScroll","$animate",function(a,c,d){return{restrict:"ECA",priority:400,terminal:!0,transclude:"element",controller:ca.noop,compile:function(e,f){var g=f.ngInclude||f.src,h=f.onload||"",l=f.autoscroll;return function(e,f,m,s,q){var t=0,F,u,p,v=function(){u&&(u.remove(),u=null);F&&(F.$destroy(),F=null);p&&(d.leave(p).then(function(){u=null}),u=p,p=null)};e.$watch(g,function(g){var m=function(){!w(l)||l&&!e.$eval(l)||
+c()},r=++t;g?(a(g,!0).then(function(a){if(r===t){var c=e.$new();s.template=a;a=q(c,function(a){v();d.enter(a,null,f).then(m)});F=c;p=a;F.$emit("$includeContentLoaded",g);e.$eval(h)}},function(){r===t&&(v(),e.$emit("$includeContentError",g))}),e.$emit("$includeContentRequested",g)):(v(),s.template=null)})}}}}],Qe=["$compile",function(a){return{restrict:"ECA",priority:-400,require:"ngInclude",link:function(c,d,e,f){/SVG/.test(d[0].toString())?(d.empty(),a(Nc(f.template,U).childNodes)(c,function(a){d.append(a)},
+{futureParentElement:d})):(d.html(f.template),a(d.contents())(c))}}}],Ae=Ma({priority:450,compile:function(){return{pre:function(a,c,d){a.$eval(d.ngInit)}}}}),Me=function(){return{restrict:"A",priority:100,require:"ngModel",link:function(a,c,d,e){var f=c.attr(d.$attr.ngList)||", ",g="false"!==d.ngTrim,h=g?R(f):f;e.$parsers.push(function(a){if(!A(a)){var c=[];a&&m(a.split(h),function(a){a&&c.push(g?R(a):a)});return c}});e.$formatters.push(function(a){return G(a)?a.join(f):t});e.$isEmpty=function(a){return!a||
+!a.length}}}},mb="ng-valid",Kd="ng-invalid",Va="ng-pristine",Jb="ng-dirty",Md="ng-pending",Lb=new J("ngModel"),wg=["$scope","$exceptionHandler","$attrs","$element","$parse","$animate","$timeout","$rootScope","$q","$interpolate",function(a,c,d,e,f,g,h,l,k,n){this.$modelValue=this.$viewValue=Number.NaN;this.$$rawModelValue=t;this.$validators={};this.$asyncValidators={};this.$parsers=[];this.$formatters=[];this.$viewChangeListeners=[];this.$untouched=!0;this.$touched=!1;this.$pristine=!0;this.$dirty=
+!1;this.$valid=!0;this.$invalid=!1;this.$error={};this.$$success={};this.$pending=t;this.$name=n(d.name||"",!1)(a);var r=f(d.ngModel),s=r.assign,q=r,C=s,F=null,u,p=this;this.$$setOptions=function(a){if((p.$options=a)&&a.getterSetter){var c=f(d.ngModel+"()"),g=f(d.ngModel+"($$$p)");q=function(a){var d=r(a);z(d)&&(d=c(a));return d};C=function(a,c){z(r(a))?g(a,{$$$p:p.$modelValue}):s(a,p.$modelValue)}}else if(!r.assign)throw Lb("nonassign",d.ngModel,ua(e));};this.$render=v;this.$isEmpty=function(a){return A(a)||
+""===a||null===a||a!==a};var K=e.inheritedData("$formController")||Ib,y=0;Hd({ctrl:this,$element:e,set:function(a,c){a[c]=!0},unset:function(a,c){delete a[c]},parentForm:K,$animate:g});this.$setPristine=function(){p.$dirty=!1;p.$pristine=!0;g.removeClass(e,Jb);g.addClass(e,Va)};this.$setDirty=function(){p.$dirty=!0;p.$pristine=!1;g.removeClass(e,Va);g.addClass(e,Jb);K.$setDirty()};this.$setUntouched=function(){p.$touched=!1;p.$untouched=!0;g.setClass(e,"ng-untouched","ng-touched")};this.$setTouched=
+function(){p.$touched=!0;p.$untouched=!1;g.setClass(e,"ng-touched","ng-untouched")};this.$rollbackViewValue=function(){h.cancel(F);p.$viewValue=p.$$lastCommittedViewValue;p.$render()};this.$validate=function(){if(!V(p.$modelValue)||!isNaN(p.$modelValue)){var a=p.$$rawModelValue,c=p.$valid,d=p.$modelValue,e=p.$options&&p.$options.allowInvalid;p.$$runValidators(a,p.$$lastCommittedViewValue,function(f){e||c===f||(p.$modelValue=f?a:t,p.$modelValue!==d&&p.$$writeModelToScope())})}};this.$$runValidators=
+function(a,c,d){function e(){var d=!0;m(p.$validators,function(e,f){var h=e(a,c);d=d&&h;g(f,h)});return d?!0:(m(p.$asyncValidators,function(a,c){g(c,null)}),!1)}function f(){var d=[],e=!0;m(p.$asyncValidators,function(f,h){var k=f(a,c);if(!k||!z(k.then))throw Lb("$asyncValidators",k);g(h,t);d.push(k.then(function(){g(h,!0)},function(a){e=!1;g(h,!1)}))});d.length?k.all(d).then(function(){h(e)},v):h(!0)}function g(a,c){l===y&&p.$setValidity(a,c)}function h(a){l===y&&d(a)}y++;var l=y;(function(){var a=
+p.$$parserName||"parse";if(u===t)g(a,null);else return u||(m(p.$validators,function(a,c){g(c,null)}),m(p.$asyncValidators,function(a,c){g(c,null)})),g(a,u),u;return!0})()?e()?f():h(!1):h(!1)};this.$commitViewValue=function(){var a=p.$viewValue;h.cancel(F);if(p.$$lastCommittedViewValue!==a||""===a&&p.$$hasNativeValidators)p.$$lastCommittedViewValue=a,p.$pristine&&this.$setDirty(),this.$$parseAndValidate()};this.$$parseAndValidate=function(){var c=p.$$lastCommittedViewValue;if(u=A(c)?t:!0)for(var d=
+0;d<p.$parsers.length;d++)if(c=p.$parsers[d](c),A(c)){u=!1;break}V(p.$modelValue)&&isNaN(p.$modelValue)&&(p.$modelValue=q(a));var e=p.$modelValue,f=p.$options&&p.$options.allowInvalid;p.$$rawModelValue=c;f&&(p.$modelValue=c,p.$modelValue!==e&&p.$$writeModelToScope());p.$$runValidators(c,p.$$lastCommittedViewValue,function(a){f||(p.$modelValue=a?c:t,p.$modelValue!==e&&p.$$writeModelToScope())})};this.$$writeModelToScope=function(){C(a,p.$modelValue);m(p.$viewChangeListeners,function(a){try{a()}catch(d){c(d)}})};
+this.$setViewValue=function(a,c){p.$viewValue=a;p.$options&&!p.$options.updateOnDefault||p.$$debounceViewValueCommit(c)};this.$$debounceViewValueCommit=function(c){var d=0,e=p.$options;e&&w(e.debounce)&&(e=e.debounce,V(e)?d=e:V(e[c])?d=e[c]:V(e["default"])&&(d=e["default"]));h.cancel(F);d?F=h(function(){p.$commitViewValue()},d):l.$$phase?p.$commitViewValue():a.$apply(function(){p.$commitViewValue()})};a.$watch(function(){var c=q(a);if(c!==p.$modelValue&&(p.$modelValue===p.$modelValue||c===c)){p.$modelValue=
+p.$$rawModelValue=c;u=t;for(var d=p.$formatters,e=d.length,f=c;e--;)f=d[e](f);p.$viewValue!==f&&(p.$viewValue=p.$$lastCommittedViewValue=f,p.$render(),p.$$runValidators(c,f,v))}return c})}],Le=["$rootScope",function(a){return{restrict:"A",require:["ngModel","^?form","^?ngModelOptions"],controller:wg,priority:1,compile:function(c){c.addClass(Va).addClass("ng-untouched").addClass(mb);return{pre:function(a,c,f,g){var h=g[0],l=g[1]||Ib;h.$$setOptions(g[2]&&g[2].$options);l.$addControl(h);f.$observe("name",
+function(a){h.$name!==a&&l.$$renameControl(h,a)});a.$on("$destroy",function(){l.$removeControl(h)})},post:function(c,e,f,g){var h=g[0];if(h.$options&&h.$options.updateOn)e.on(h.$options.updateOn,function(a){h.$$debounceViewValueCommit(a&&a.type)});e.on("blur",function(e){h.$touched||(a.$$phase?c.$evalAsync(h.$setTouched):c.$apply(h.$setTouched))})}}}}}],xg=/(\s+|^)default(\s+|$)/,Pe=function(){return{restrict:"A",controller:["$scope","$attrs",function(a,c){var d=this;this.$options=fa(a.$eval(c.ngModelOptions));
+this.$options.updateOn!==t?(this.$options.updateOnDefault=!1,this.$options.updateOn=R(this.$options.updateOn.replace(xg,function(){d.$options.updateOnDefault=!0;return" "}))):this.$options.updateOnDefault=!0}]}},Be=Ma({terminal:!0,priority:1E3}),yg=J("ngOptions"),zg=/^\s*([\s\S]+?)(?:\s+as\s+([\s\S]+?))?(?:\s+group\s+by\s+([\s\S]+?))?(?:\s+disable\s+when\s+([\s\S]+?))?\s+for\s+(?:([\$\w][\$\w]*)|(?:\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)))\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?$/,
+Je=["$compile","$parse",function(a,c){function d(a,d,e){function f(a,c,d,e,g){this.selectValue=a;this.viewValue=c;this.label=d;this.group=e;this.disabled=g}function n(a){var c;if(!q&&Ea(a))c=a;else{c=[];for(var d in a)a.hasOwnProperty(d)&&"$"!==d.charAt(0)&&c.push(d)}return c}var m=a.match(zg);if(!m)throw yg("iexp",a,ua(d));var s=m[5]||m[7],q=m[6];a=/ as /.test(m[0])&&m[1];var t=m[9];d=c(m[2]?m[1]:s);var v=a&&c(a)||d,u=t&&c(t),p=t?function(a,c){return u(e,c)}:function(a){return Ga(a)},w=function(a,
+c){return p(a,z(a,c))},y=c(m[2]||m[1]),A=c(m[3]||""),B=c(m[4]||""),N=c(m[8]),D={},z=q?function(a,c){D[q]=c;D[s]=a;return D}:function(a){D[s]=a;return D};return{trackBy:t,getTrackByValue:w,getWatchables:c(N,function(a){var c=[];a=a||[];for(var d=n(a),f=d.length,g=0;g<f;g++){var h=a===d?g:d[g],k=z(a[h],h),h=p(a[h],k);c.push(h);if(m[2]||m[1])h=y(e,k),c.push(h);m[4]&&(k=B(e,k),c.push(k))}return c}),getOptions:function(){for(var a=[],c={},d=N(e)||[],g=n(d),h=g.length,m=0;m<h;m++){var r=d===g?m:g[m],s=
+z(d[r],r),q=v(e,s),r=p(q,s),u=y(e,s),x=A(e,s),s=B(e,s),q=new f(r,q,u,x,s);a.push(q);c[r]=q}return{items:a,selectValueMap:c,getOptionFromViewValue:function(a){return c[w(a)]},getViewValueFromOption:function(a){return t?ca.copy(a.viewValue):a.viewValue}}}}}var e=U.createElement("option"),f=U.createElement("optgroup");return{restrict:"A",terminal:!0,require:["select","?ngModel"],link:function(c,h,l,k){function n(a,c){a.element=c;c.disabled=a.disabled;a.value!==c.value&&(c.value=a.selectValue);a.label!==
+c.label&&(c.label=a.label,c.textContent=a.label)}function r(a,c,d,e){c&&M(c.nodeName)===d?d=c:(d=e.cloneNode(!1),c?a.insertBefore(d,c):a.appendChild(d));return d}function s(a){for(var c;a;)c=a.nextSibling,Xb(a),a=c}function q(a){var c=p&&p[0],d=N&&N[0];if(c||d)for(;a&&(a===c||a===d);)a=a.nextSibling;return a}function t(){var a=D&&u.readValue();D=z.getOptions();var c={},d=h[0].firstChild;B&&h.prepend(p);d=q(d);D.items.forEach(function(a){var g,k;a.group?(g=c[a.group],g||(g=r(h[0],d,"optgroup",f),d=
+g.nextSibling,g.label=a.group,g=c[a.group]={groupElement:g,currentOptionElement:g.firstChild}),k=r(g.groupElement,g.currentOptionElement,"option",e),n(a,k),g.currentOptionElement=k.nextSibling):(k=r(h[0],d,"option",e),n(a,k),d=k.nextSibling)});Object.keys(c).forEach(function(a){s(c[a].currentOptionElement)});s(d);v.$render();if(!v.$isEmpty(a)){var g=u.readValue();(z.trackBy?ka(a,g):a===g)||(v.$setViewValue(g),v.$render())}}var v=k[1];if(v){var u=k[0];k=l.multiple;for(var p,w=0,A=h.children(),I=A.length;w<
+I;w++)if(""===A[w].value){p=A.eq(w);break}var B=!!p,N=y(e.cloneNode(!1));N.val("?");var D,z=d(l.ngOptions,h,c);k?(v.$isEmpty=function(a){return!a||0===a.length},u.writeValue=function(a){D.items.forEach(function(a){a.element.selected=!1});a&&a.forEach(function(a){(a=D.getOptionFromViewValue(a))&&!a.disabled&&(a.element.selected=!0)})},u.readValue=function(){var a=h.val()||[],c=[];m(a,function(a){a=D.selectValueMap[a];a.disabled||c.push(D.getViewValueFromOption(a))});return c},z.trackBy&&c.$watchCollection(function(){if(G(v.$viewValue))return v.$viewValue.map(function(a){return z.getTrackByValue(a)})},
+function(){v.$render()})):(u.writeValue=function(a){var c=D.getOptionFromViewValue(a);c&&!c.disabled?h[0].value!==c.selectValue&&(N.remove(),B||p.remove(),h[0].value=c.selectValue,c.element.selected=!0,c.element.setAttribute("selected","selected")):null===a||B?(N.remove(),B||h.prepend(p),h.val(""),p.prop("selected",!0),p.attr("selected",!0)):(B||p.remove(),h.prepend(N),h.val("?"),N.prop("selected",!0),N.attr("selected",!0))},u.readValue=function(){var a=D.selectValueMap[h.val()];return a&&!a.disabled?
+(B||p.remove(),N.remove(),D.getViewValueFromOption(a)):null},z.trackBy&&c.$watch(function(){return z.getTrackByValue(v.$viewValue)},function(){v.$render()}));B?(p.remove(),a(p)(c),p.removeClass("ng-scope")):p=y(e.cloneNode(!1));t();c.$watchCollection(z.getWatchables,t)}}}}],Ce=["$locale","$interpolate","$log",function(a,c,d){var e=/{}/g,f=/^when(Minus)?(.+)$/;return{link:function(g,h,l){function k(a){h.text(a||"")}var n=l.count,r=l.$attr.when&&h.attr(l.$attr.when),s=l.offset||0,q=g.$eval(r)||{},t=
+{},w=c.startSymbol(),u=c.endSymbol(),p=w+n+"-"+s+u,y=ca.noop,z;m(l,function(a,c){var d=f.exec(c);d&&(d=(d[1]?"-":"")+M(d[2]),q[d]=h.attr(l.$attr[c]))});m(q,function(a,d){t[d]=c(a.replace(e,p))});g.$watch(n,function(c){var e=parseFloat(c),f=isNaN(e);f||e in q||(e=a.pluralCat(e-s));e===z||f&&V(z)&&isNaN(z)||(y(),f=t[e],A(f)?(null!=c&&d.debug("ngPluralize: no rule defined for '"+e+"' in "+r),y=v,k()):y=g.$watch(f,k),z=e)})}}}],De=["$parse","$animate",function(a,c){var d=J("ngRepeat"),e=function(a,c,
+d,e,k,m,r){a[d]=e;k&&(a[k]=m);a.$index=c;a.$first=0===c;a.$last=c===r-1;a.$middle=!(a.$first||a.$last);a.$odd=!(a.$even=0===(c&1))};return{restrict:"A",multiElement:!0,transclude:"element",priority:1E3,terminal:!0,$$tlb:!0,compile:function(f,g){var h=g.ngRepeat,l=U.createComment(" end ngRepeat: "+h+" "),k=h.match(/^\s*([\s\S]+?)\s+in\s+([\s\S]+?)(?:\s+as\s+([\s\S]+?))?(?:\s+track\s+by\s+([\s\S]+?))?\s*$/);if(!k)throw d("iexp",h);var n=k[1],r=k[2],s=k[3],q=k[4],k=n.match(/^(?:(\s*[\$\w]+)|\(\s*([\$\w]+)\s*,\s*([\$\w]+)\s*\))$/);
+if(!k)throw d("iidexp",n);var v=k[3]||k[1],w=k[2];if(s&&(!/^[$a-zA-Z_][$a-zA-Z0-9_]*$/.test(s)||/^(null|undefined|this|\$index|\$first|\$middle|\$last|\$even|\$odd|\$parent|\$root|\$id)$/.test(s)))throw d("badident",s);var u,p,z,A,I={$id:Ga};q?u=a(q):(z=function(a,c){return Ga(c)},A=function(a){return a});return function(a,f,g,k,n){u&&(p=function(c,d,e){w&&(I[w]=c);I[v]=d;I.$index=e;return u(a,I)});var q=ga();a.$watchCollection(r,function(g){var k,r,u=f[0],x,D=ga(),I,H,L,G,M,J,O;s&&(a[s]=g);if(Ea(g))M=
+g,r=p||z;else for(O in r=p||A,M=[],g)g.hasOwnProperty(O)&&"$"!==O.charAt(0)&&M.push(O);I=M.length;O=Array(I);for(k=0;k<I;k++)if(H=g===M?k:M[k],L=g[H],G=r(H,L,k),q[G])J=q[G],delete q[G],D[G]=J,O[k]=J;else{if(D[G])throw m(O,function(a){a&&a.scope&&(q[a.id]=a)}),d("dupes",h,G,L);O[k]={id:G,scope:t,clone:t};D[G]=!0}for(x in q){J=q[x];G=qb(J.clone);c.leave(G);if(G[0].parentNode)for(k=0,r=G.length;k<r;k++)G[k].$$NG_REMOVED=!0;J.scope.$destroy()}for(k=0;k<I;k++)if(H=g===M?k:M[k],L=g[H],J=O[k],J.scope){x=
+u;do x=x.nextSibling;while(x&&x.$$NG_REMOVED);J.clone[0]!=x&&c.move(qb(J.clone),null,y(u));u=J.clone[J.clone.length-1];e(J.scope,k,v,L,w,H,I)}else n(function(a,d){J.scope=d;var f=l.cloneNode(!1);a[a.length++]=f;c.enter(a,null,y(u));u=f;J.clone=a;D[J.id]=J;e(J.scope,k,v,L,w,H,I)});q=D})}}}}],Ee=["$animate",function(a){return{restrict:"A",multiElement:!0,link:function(c,d,e){c.$watch(e.ngShow,function(c){a[c?"removeClass":"addClass"](d,"ng-hide",{tempClasses:"ng-hide-animate"})})}}}],xe=["$animate",
+function(a){return{restrict:"A",multiElement:!0,link:function(c,d,e){c.$watch(e.ngHide,function(c){a[c?"addClass":"removeClass"](d,"ng-hide",{tempClasses:"ng-hide-animate"})})}}}],Fe=Ma(function(a,c,d){a.$watch(d.ngStyle,function(a,d){d&&a!==d&&m(d,function(a,d){c.css(d,"")});a&&c.css(a)},!0)}),Ge=["$animate",function(a){return{require:"ngSwitch",controller:["$scope",function(){this.cases={}}],link:function(c,d,e,f){var g=[],h=[],l=[],k=[],n=function(a,c){return function(){a.splice(c,1)}};c.$watch(e.ngSwitch||
+e.on,function(c){var d,e;d=0;for(e=l.length;d<e;++d)a.cancel(l[d]);d=l.length=0;for(e=k.length;d<e;++d){var q=qb(h[d].clone);k[d].$destroy();(l[d]=a.leave(q)).then(n(l,d))}h.length=0;k.length=0;(g=f.cases["!"+c]||f.cases["?"])&&m(g,function(c){c.transclude(function(d,e){k.push(e);var f=c.element;d[d.length++]=U.createComment(" end ngSwitchWhen: ");h.push({clone:d});a.enter(d,f.parent(),f)})})})}}}],He=Ma({transclude:"element",priority:1200,require:"^ngSwitch",multiElement:!0,link:function(a,c,d,e,
+f){e.cases["!"+d.ngSwitchWhen]=e.cases["!"+d.ngSwitchWhen]||[];e.cases["!"+d.ngSwitchWhen].push({transclude:f,element:c})}}),Ie=Ma({transclude:"element",priority:1200,require:"^ngSwitch",multiElement:!0,link:function(a,c,d,e,f){e.cases["?"]=e.cases["?"]||[];e.cases["?"].push({transclude:f,element:c})}}),Ke=Ma({restrict:"EAC",link:function(a,c,d,e,f){if(!f)throw J("ngTransclude")("orphan",ua(c));f(function(a){c.empty();c.append(a)})}}),ke=["$templateCache",function(a){return{restrict:"E",terminal:!0,
+compile:function(c,d){"text/ng-template"==d.type&&a.put(d.id,c[0].text)}}}],Ag={$setViewValue:v,$render:v},Bg=["$element","$scope","$attrs",function(a,c,d){var e=this,f=new Sa;e.ngModelCtrl=Ag;e.unknownOption=y(U.createElement("option"));e.renderUnknownOption=function(c){c="? "+Ga(c)+" ?";e.unknownOption.val(c);a.prepend(e.unknownOption);a.val(c)};c.$on("$destroy",function(){e.renderUnknownOption=v});e.removeUnknownOption=function(){e.unknownOption.parent()&&e.unknownOption.remove()};e.readValue=
+function(){e.removeUnknownOption();return a.val()};e.writeValue=function(c){e.hasOption(c)?(e.removeUnknownOption(),a.val(c),""===c&&e.emptyOption.prop("selected",!0)):null==c&&e.emptyOption?(e.removeUnknownOption(),a.val("")):e.renderUnknownOption(c)};e.addOption=function(a,c){Ra(a,'"option value"');""===a&&(e.emptyOption=c);var d=f.get(a)||0;f.put(a,d+1)};e.removeOption=function(a){var c=f.get(a);c&&(1===c?(f.remove(a),""===a&&(e.emptyOption=t)):f.put(a,c-1))};e.hasOption=function(a){return!!f.get(a)}}],
+le=function(){return{restrict:"E",require:["select","?ngModel"],controller:Bg,link:function(a,c,d,e){var f=e[1];if(f){var g=e[0];g.ngModelCtrl=f;f.$render=function(){g.writeValue(f.$viewValue)};c.on("change",function(){a.$apply(function(){f.$setViewValue(g.readValue())})});if(d.multiple){g.readValue=function(){var a=[];m(c.find("option"),function(c){c.selected&&a.push(c.value)});return a};g.writeValue=function(a){var d=new Sa(a);m(c.find("option"),function(a){a.selected=w(d.get(a.value))})};var h,
+l=NaN;a.$watch(function(){l!==f.$viewValue||ka(h,f.$viewValue)||(h=ia(f.$viewValue),f.$render());l=f.$viewValue});f.$isEmpty=function(a){return!a||0===a.length}}}}}},ne=["$interpolate",function(a){function c(a){a[0].hasAttribute("selected")&&(a[0].selected=!0)}return{restrict:"E",priority:100,compile:function(d,e){if(A(e.value)){var f=a(d.text(),!0);f||e.$set("value",d.text())}return function(a,d,e){var k=d.parent(),m=k.data("$selectController")||k.parent().data("$selectController");m&&m.ngModelCtrl&&
+(f?a.$watch(f,function(a,f){e.$set("value",a);f!==a&&m.removeOption(f);m.addOption(a,d);m.ngModelCtrl.$render();c(d)}):(m.addOption(e.value,d),m.ngModelCtrl.$render(),c(d)),d.on("$destroy",function(){m.removeOption(e.value);m.ngModelCtrl.$render()}))}}}}],me=ra({restrict:"E",terminal:!1}),Hc=function(){return{restrict:"A",require:"?ngModel",link:function(a,c,d,e){e&&(d.required=!0,e.$validators.required=function(a,c){return!d.required||!e.$isEmpty(c)},d.$observe("required",function(){e.$validate()}))}}},
+Gc=function(){return{restrict:"A",require:"?ngModel",link:function(a,c,d,e){if(e){var f,g=d.ngPattern||d.pattern;d.$observe("pattern",function(a){L(a)&&0<a.length&&(a=new RegExp("^"+a+"$"));if(a&&!a.test)throw J("ngPattern")("noregexp",g,a,ua(c));f=a||t;e.$validate()});e.$validators.pattern=function(a){return e.$isEmpty(a)||A(f)||f.test(a)}}}}},Jc=function(){return{restrict:"A",require:"?ngModel",link:function(a,c,d,e){if(e){var f=-1;d.$observe("maxlength",function(a){a=W(a);f=isNaN(a)?-1:a;e.$validate()});
+e.$validators.maxlength=function(a,c){return 0>f||e.$isEmpty(c)||c.length<=f}}}}},Ic=function(){return{restrict:"A",require:"?ngModel",link:function(a,c,d,e){if(e){var f=0;d.$observe("minlength",function(a){f=W(a)||0;e.$validate()});e.$validators.minlength=function(a,c){return e.$isEmpty(c)||c.length>=f}}}}};O.angular.bootstrap?console.log("WARNING: Tried to load angular more than once."):(ce(),ee(ca),y(U).ready(function(){Zd(U,Ac)}))})(window,document);!window.angular.$$csp()&&window.angular.element(document.head).prepend('<style type="text/css">@charset "UTF-8";[ng\\:cloak],[ng-cloak],[data-ng-cloak],[x-ng-cloak],.ng-cloak,.x-ng-cloak,.ng-hide:not(.ng-hide-animate){display:none !important;}ng\\:form{display:block;}.ng-animate-shim{visibility:hidden;}.ng-anchor{position:absolute;}</style>');
//# sourceMappingURL=angular.min.js.map
diff --git a/libs/bower_components/angular/angular.min.js.gzip b/libs/bower_components/angular/angular.min.js.gzip
index 8f86428b97..64c240da57 100644
--- a/libs/bower_components/angular/angular.min.js.gzip
+++ b/libs/bower_components/angular/angular.min.js.gzip
Binary files differ
diff --git a/libs/bower_components/angular/angular.min.js.map b/libs/bower_components/angular/angular.min.js.map
index bf40d3e271..71ce90dcc5 100644
--- a/libs/bower_components/angular/angular.min.js.map
+++ b/libs/bower_components/angular/angular.min.js.map
@@ -1,8 +1,8 @@
{
"version":3,
"file":"angular.min.js",
-"lineCount":216,
-"mappings":"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",
+"lineCount":289,
+"mappings":"A;;;;;aAKC,SAAQ,CAACA,CAAD,CAASC,CAAT,CAAmBC,CAAnB,CAA8B,CAgCvCC,QAAAA,EAAAA,CAAAA,CAAAA,CAAAA,CAAAA,MAAAA,SAAAA,EAAAA,CAAAA,IAAAA,EAAAA,SAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,EAAAA,CAAAA,GAAAA,EAAAA,CAAAA,CAAAA,CAAAA,CAAAA,GAAAA,CAAAA,EAAAA,EAAAA,CAAAA,CAAAA,sCAAAA,EAAAA,CAAAA,CAAAA,CAAAA,CAAAA,GAAAA,CAAAA,EAAAA,EAAAA,CAAAA,KAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,SAAAA,OAAAA,CAAAA,CAAAA,EAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,EAAAA,CAAAA,EAAAA,CAAAA,CAAAA,GAAAA,CAAAA,GAAAA,EAAAA,GAAAA,EAAAA,CAAAA,CAAAA,CAAAA,EAAAA,GAAAA,KAAAA,EAAAA,kBAAAA,CAAAA,CAAAA,EAAAA,CAAAA,SAAAA,CAAAA,CAAAA,CAAAA,EAAAA,CAAAA,UAAAA,EAAAA,MAAAA,EAAAA,CAAAA,CAAAA,SAAAA,EAAAA,QAAAA,CAAAA,aAAAA,CAAAA,EAAAA,CAAAA,CAAAA,WAAAA,EAAAA,MAAAA,EAAAA,CAAAA,WAAAA,CAAAA,QAAAA,EAAAA,MAAAA,EAAAA,CAAAA,IAAAA,UAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,EAAAA,EAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,MAAAA,MAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAuOAC,QAASA,GAAW,CAACC,CAAD,CAAM,CACxB,GAAW,IAAX,EAAIA,CAAJ,EAAmBC,EAAA,CAASD,CAAT,CAAnB,CACE,MAAO,CAAA,CAKT,KAAIE,EAAS,QAATA,EAAqBC,OAAA,CAAOH,CAAP,CAArBE,EAAoCF,CAAAE,OAExC;MAAIF,EAAAI,SAAJ,GAAqBC,EAArB,EAA0CH,CAA1C,CACS,CAAA,CADT,CAIOI,CAAA,CAASN,CAAT,CAJP,EAIwBO,CAAA,CAAQP,CAAR,CAJxB,EAImD,CAJnD,GAIwCE,CAJxC,EAKyB,QALzB,GAKO,MAAOA,EALd,EAK8C,CAL9C,CAKqCA,CALrC,EAKoDA,CALpD,CAK6D,CAL7D,GAKmEF,EAd3C,CAoD1BQ,QAASA,EAAO,CAACR,CAAD,CAAMS,CAAN,CAAgBC,CAAhB,CAAyB,CAAA,IACnCC,CADmC,CAC9BT,CACT,IAAIF,CAAJ,CACE,GAAIY,CAAA,CAAWZ,CAAX,CAAJ,CACE,IAAKW,CAAL,GAAYX,EAAZ,CAGa,WAAX,EAAIW,CAAJ,EAAiC,QAAjC,EAA0BA,CAA1B,EAAoD,MAApD,EAA6CA,CAA7C,EAAgEX,CAAAa,eAAhE,EAAsF,CAAAb,CAAAa,eAAA,CAAmBF,CAAnB,CAAtF,EACEF,CAAAK,KAAA,CAAcJ,CAAd,CAAuBV,CAAA,CAAIW,CAAJ,CAAvB,CAAiCA,CAAjC,CAAsCX,CAAtC,CALN,KAQO,IAAIO,CAAA,CAAQP,CAAR,CAAJ,EAAoBD,EAAA,CAAYC,CAAZ,CAApB,CAAsC,CAC3C,IAAIe,EAA6B,QAA7BA,GAAc,MAAOf,EACpBW,EAAA,CAAM,CAAX,KAAcT,CAAd,CAAuBF,CAAAE,OAAvB,CAAmCS,CAAnC,CAAyCT,CAAzC,CAAiDS,CAAA,EAAjD,CACE,CAAII,CAAJ,EAAmBJ,CAAnB,GAA0BX,EAA1B,GACES,CAAAK,KAAA,CAAcJ,CAAd,CAAuBV,CAAA,CAAIW,CAAJ,CAAvB,CAAiCA,CAAjC,CAAsCX,CAAtC,CAJuC,CAAtC,IAOA,IAAIA,CAAAQ,QAAJ,EAAmBR,CAAAQ,QAAnB,GAAmCA,CAAnC,CACHR,CAAAQ,QAAA,CAAYC,CAAZ,CAAsBC,CAAtB,CAA+BV,CAA/B,CADG,KAEA,IAAIgB,EAAA,CAAchB,CAAd,CAAJ,CAEL,IAAKW,CAAL,GAAYX,EAAZ,CACES,CAAAK,KAAA,CAAcJ,CAAd,CAAuBV,CAAA,CAAIW,CAAJ,CAAvB,CAAiCA,CAAjC,CAAsCX,CAAtC,CAHG,KAKA,IAAkC,UAAlC,GAAI,MAAOA,EAAAa,eAAX,CAEL,IAAKF,CAAL,GAAYX,EAAZ,CACMA,CAAAa,eAAA,CAAmBF,CAAnB,CAAJ;AACEF,CAAAK,KAAA,CAAcJ,CAAd,CAAuBV,CAAA,CAAIW,CAAJ,CAAvB,CAAiCA,CAAjC,CAAsCX,CAAtC,CAJC,KASL,KAAKW,CAAL,GAAYX,EAAZ,CACMa,EAAAC,KAAA,CAAoBd,CAApB,CAAyBW,CAAzB,CAAJ,EACEF,CAAAK,KAAA,CAAcJ,CAAd,CAAuBV,CAAA,CAAIW,CAAJ,CAAvB,CAAiCA,CAAjC,CAAsCX,CAAtC,CAKR,OAAOA,EAzCgC,CA4CzCiB,QAASA,GAAa,CAACjB,CAAD,CAAMS,CAAN,CAAgBC,CAAhB,CAAyB,CAE7C,IADA,IAAIQ,EAAOf,MAAAe,KAAA,CAAYlB,CAAZ,CAAAmB,KAAA,EAAX,CACSC,EAAI,CAAb,CAAgBA,CAAhB,CAAoBF,CAAAhB,OAApB,CAAiCkB,CAAA,EAAjC,CACEX,CAAAK,KAAA,CAAcJ,CAAd,CAAuBV,CAAA,CAAIkB,CAAA,CAAKE,CAAL,CAAJ,CAAvB,CAAqCF,CAAA,CAAKE,CAAL,CAArC,CAEF,OAAOF,EALsC,CAc/CG,QAASA,GAAa,CAACC,CAAD,CAAa,CACjC,MAAO,SAAQ,CAACC,CAAD,CAAQZ,CAAR,CAAa,CAAEW,CAAA,CAAWX,CAAX,CAAgBY,CAAhB,CAAF,CADK,CAcnCC,QAASA,GAAO,EAAG,CACjB,MAAO,EAAEC,EADQ,CAUnBC,QAASA,GAAU,CAAC1B,CAAD,CAAM2B,CAAN,CAAS,CACtBA,CAAJ,CACE3B,CAAA4B,UADF,CACkBD,CADlB,CAGE,OAAO3B,CAAA4B,UAJiB,CAS5BC,QAASA,GAAU,CAACC,CAAD,CAAMC,CAAN,CAAYC,CAAZ,CAAkB,CAGnC,IAFA,IAAIL,EAAIG,CAAAF,UAAR,CAESR,EAAI,CAFb,CAEgBa,EAAKF,CAAA7B,OAArB,CAAkCkB,CAAlC,CAAsCa,CAAtC,CAA0C,EAAEb,CAA5C,CAA+C,CAC7C,IAAIpB,EAAM+B,CAAA,CAAKX,CAAL,CACV,IAAKc,CAAA,CAASlC,CAAT,CAAL,EAAuBY,CAAA,CAAWZ,CAAX,CAAvB,CAEA,IADA,IAAIkB,EAAOf,MAAAe,KAAA,CAAYlB,CAAZ,CAAX,CACSmC,EAAI,CADb,CACgBC,EAAKlB,CAAAhB,OAArB,CAAkCiC,CAAlC,CAAsCC,CAAtC,CAA0CD,CAAA,EAA1C,CAA+C,CAC7C,IAAIxB,EAAMO,CAAA,CAAKiB,CAAL,CAAV,CACIE,EAAMrC,CAAA,CAAIW,CAAJ,CAENqB,EAAJ,EAAYE,CAAA,CAASG,CAAT,CAAZ,CACMC,EAAA,CAAOD,CAAP,CAAJ,CACEP,CAAA,CAAInB,CAAJ,CADF,CACa,IAAI4B,IAAJ,CAASF,CAAAG,QAAA,EAAT,CADb,EAGON,CAAA,CAASJ,CAAA,CAAInB,CAAJ,CAAT,CACL;CADyBmB,CAAA,CAAInB,CAAJ,CACzB,CADoCJ,CAAA,CAAQ8B,CAAR,CAAA,CAAe,EAAf,CAAoB,EACxD,EAAAR,EAAA,CAAWC,CAAA,CAAInB,CAAJ,CAAX,CAAqB,CAAC0B,CAAD,CAArB,CAA4B,CAAA,CAA5B,CAJF,CADF,CAQEP,CAAA,CAAInB,CAAJ,CARF,CAQa0B,CAZgC,CAJF,CAqB/CX,EAAA,CAAWI,CAAX,CAAgBH,CAAhB,CACA,OAAOG,EAzB4B,CA8CrCW,QAASA,EAAM,CAACX,CAAD,CAAM,CACnB,MAAOD,GAAA,CAAWC,CAAX,CAAgBY,EAAA5B,KAAA,CAAW6B,SAAX,CAAsB,CAAtB,CAAhB,CAA0C,CAAA,CAA1C,CADY,CAuBrBC,QAASA,GAAK,CAACd,CAAD,CAAM,CAClB,MAAOD,GAAA,CAAWC,CAAX,CAAgBY,EAAA5B,KAAA,CAAW6B,SAAX,CAAsB,CAAtB,CAAhB,CAA0C,CAAA,CAA1C,CADW,CAMpBE,QAASA,EAAK,CAACC,CAAD,CAAM,CAClB,MAAOC,SAAA,CAASD,CAAT,CAAc,EAAd,CADW,CAKpBE,QAASA,GAAO,CAACC,CAAD,CAASC,CAAT,CAAgB,CAC9B,MAAOT,EAAA,CAAOtC,MAAAgD,OAAA,CAAcF,CAAd,CAAP,CAA8BC,CAA9B,CADuB,CAoBhCE,QAASA,EAAI,EAAG,EAsBhBC,QAASA,GAAQ,CAACC,CAAD,CAAI,CAAC,MAAOA,EAAR,CAIrBC,QAASA,GAAO,CAAChC,CAAD,CAAQ,CAAC,MAAO,SAAQ,EAAG,CAAC,MAAOA,EAAR,CAAnB,CAExBiC,QAASA,GAAiB,CAACxD,CAAD,CAAM,CAC9B,MAAOY,EAAA,CAAWZ,CAAAyD,SAAX,CAAP,EAAmCzD,CAAAyD,SAAnC,GAAoDtD,MAAAuD,UAAAD,SADtB,CAiBhCE,QAASA,EAAW,CAACpC,CAAD,CAAQ,CAAC,MAAwB,WAAxB,GAAO,MAAOA,EAAf,CAe5BqC,QAASA,EAAS,CAACrC,CAAD,CAAQ,CAAC,MAAwB,WAAxB,GAAO,MAAOA,EAAf,CAgB1BW,QAASA,EAAQ,CAACX,CAAD,CAAQ,CAEvB,MAAiB,KAAjB;AAAOA,CAAP,EAA0C,QAA1C,GAAyB,MAAOA,EAFT,CAWzBP,QAASA,GAAa,CAACO,CAAD,CAAQ,CAC5B,MAAiB,KAAjB,GAAOA,CAAP,EAA0C,QAA1C,GAAyB,MAAOA,EAAhC,EAAsD,CAACsC,EAAA,CAAetC,CAAf,CAD3B,CAiB9BjB,QAASA,EAAQ,CAACiB,CAAD,CAAQ,CAAC,MAAwB,QAAxB,GAAO,MAAOA,EAAf,CAqBzBuC,QAASA,EAAQ,CAACvC,CAAD,CAAQ,CAAC,MAAwB,QAAxB,GAAO,MAAOA,EAAf,CAezBe,QAASA,GAAM,CAACf,CAAD,CAAQ,CACrB,MAAgC,eAAhC,GAAOkC,EAAA3C,KAAA,CAAcS,CAAd,CADc,CA+BvBX,QAASA,EAAU,CAACW,CAAD,CAAQ,CAAC,MAAwB,UAAxB,GAAO,MAAOA,EAAf,CAU3BwC,QAASA,GAAQ,CAACxC,CAAD,CAAQ,CACvB,MAAgC,iBAAhC,GAAOkC,EAAA3C,KAAA,CAAcS,CAAd,CADgB,CAYzBtB,QAASA,GAAQ,CAACD,CAAD,CAAM,CACrB,MAAOA,EAAP,EAAcA,CAAAL,OAAd,GAA6BK,CADR,CAKvBgE,QAASA,GAAO,CAAChE,CAAD,CAAM,CACpB,MAAOA,EAAP,EAAcA,CAAAiE,WAAd,EAAgCjE,CAAAkE,OADZ,CAoBtBC,QAASA,GAAS,CAAC5C,CAAD,CAAQ,CACxB,MAAwB,SAAxB,GAAO,MAAOA,EADU,CAyC1B6C,QAASA,GAAS,CAACC,CAAD,CAAO,CACvB,MAAO,EAAGA,CAAAA,CAAH,EACJ,EAAAA,CAAAC,SAAA,EACGD,CAAAE,KADH,EACgBF,CAAAG,KADhB,EAC6BH,CAAAI,KAD7B,CADI,CADgB,CA7vBc;AAuwBvCC,QAASA,GAAO,CAAC5B,CAAD,CAAM,CAAA,IAChB9C,EAAM,EAAI2E,EAAAA,CAAQ7B,CAAA8B,MAAA,CAAU,GAAV,CAAtB,KAAsCxD,CACtC,KAAKA,CAAL,CAAS,CAAT,CAAYA,CAAZ,CAAgBuD,CAAAzE,OAAhB,CAA8BkB,CAAA,EAA9B,CACEpB,CAAA,CAAI2E,CAAA,CAAMvD,CAAN,CAAJ,CAAA,CAAgB,CAAA,CAElB,OAAOpB,EALa,CAStB6E,QAASA,GAAS,CAACC,CAAD,CAAU,CAC1B,MAAOC,EAAA,CAAUD,CAAAR,SAAV,EAA+BQ,CAAA,CAAQ,CAAR,CAA/B,EAA6CA,CAAA,CAAQ,CAAR,CAAAR,SAA7C,CADmB,CAQ5BU,QAASA,GAAW,CAACC,CAAD,CAAQ1D,CAAR,CAAe,CACjC,IAAI2D,EAAQD,CAAAE,QAAA,CAAc5D,CAAd,CACC,EAAb,EAAI2D,CAAJ,EACED,CAAAG,OAAA,CAAaF,CAAb,CAAoB,CAApB,CAEF,OAAOA,EAL0B,CAkEnCG,QAASA,GAAI,CAACC,CAAD,CAASC,CAAT,CAAsBC,CAAtB,CAAmCC,CAAnC,CAA8C,CACzD,GAAIxF,EAAA,CAASqF,CAAT,CAAJ,EAAwBtB,EAAA,CAAQsB,CAAR,CAAxB,CACE,KAAMI,GAAA,CAAS,MAAT,CAAN,CAGF,GA/HOC,EAAAC,KAAA,CAAwBnC,EAAA3C,KAAA,CA+HdyE,CA/Hc,CAAxB,CA+HP,CACE,KAAMG,GAAA,CAAS,MAAT,CAAN,CAIF,GAAKH,CAAL,CA+BO,CACL,GAAID,CAAJ,GAAeC,CAAf,CAA4B,KAAMG,GAAA,CAAS,KAAT,CAAN,CAG5BF,CAAA,CAAcA,CAAd,EAA6B,EAC7BC,EAAA,CAAYA,CAAZ,EAAyB,EAErBvD,EAAA,CAASoD,CAAT,CAAJ,GACEE,CAAAK,KAAA,CAAiBP,CAAjB,CACA,CAAAG,CAAAI,KAAA,CAAeN,CAAf,CAFF,CAKA,KAAY5E,CACZ,IAAIJ,CAAA,CAAQ+E,CAAR,CAAJ,CAEE,IAASlE,CAAT,CADAmE,CAAArF,OACA,CADqB,CACrB,CAAgBkB,CAAhB,CAAoBkE,CAAApF,OAApB,CAAmCkB,CAAA,EAAnC,CACEmE,CAAAM,KAAA,CAAiBR,EAAA,CAAKC,CAAA,CAAOlE,CAAP,CAAL,CAAgB,IAAhB,CAAsBoE,CAAtB,CAAmCC,CAAnC,CAAjB,CAHJ,KAKO,CACL,IAAI9D,EAAI4D,CAAA3D,UACJrB,EAAA,CAAQgF,CAAR,CAAJ,CACEA,CAAArF,OADF,CACuB,CADvB,CAGEM,CAAA,CAAQ+E,CAAR,CAAqB,QAAQ,CAAChE,CAAD;AAAQZ,CAAR,CAAa,CACxC,OAAO4E,CAAA,CAAY5E,CAAZ,CADiC,CAA1C,CAIF,IAAIK,EAAA,CAAcsE,CAAd,CAAJ,CAEE,IAAK3E,CAAL,GAAY2E,EAAZ,CACEC,CAAA,CAAY5E,CAAZ,CAAA,CAAmB0E,EAAA,CAAKC,CAAA,CAAO3E,CAAP,CAAL,CAAkB,IAAlB,CAAwB6E,CAAxB,CAAqCC,CAArC,CAHvB,KAKO,IAAIH,CAAJ,EAA+C,UAA/C,GAAc,MAAOA,EAAAzE,eAArB,CAEL,IAAKF,CAAL,GAAY2E,EAAZ,CACMA,CAAAzE,eAAA,CAAsBF,CAAtB,CAAJ,GACE4E,CAAA,CAAY5E,CAAZ,CADF,CACqB0E,EAAA,CAAKC,CAAA,CAAO3E,CAAP,CAAL,CAAkB,IAAlB,CAAwB6E,CAAxB,CAAqCC,CAArC,CADrB,CAHG,KASL,KAAK9E,CAAL,GAAY2E,EAAZ,CACMzE,EAAAC,KAAA,CAAoBwE,CAApB,CAA4B3E,CAA5B,CAAJ,GACE4E,CAAA,CAAY5E,CAAZ,CADF,CACqB0E,EAAA,CAAKC,CAAA,CAAO3E,CAAP,CAAL,CAAkB,IAAlB,CAAwB6E,CAAxB,CAAqCC,CAArC,CADrB,CAKJ/D,GAAA,CAAW6D,CAAX,CAAuB5D,CAAvB,CA7BK,CAlBF,CA/BP,IAEE,IADA4D,CACI,CADUD,CACV,CAAApD,CAAA,CAASoD,CAAT,CAAJ,CAAsB,CAEpB,GAAIE,CAAJ,EAA8D,EAA9D,IAAoBN,CAApB,CAA4BM,CAAAL,QAAA,CAAoBG,CAApB,CAA5B,EACE,MAAOG,EAAA,CAAUP,CAAV,CAOT,IAAI3E,CAAA,CAAQ+E,CAAR,CAAJ,CACE,MAAOD,GAAA,CAAKC,CAAL,CAAa,EAAb,CAAiBE,CAAjB,CAA8BC,CAA9B,CACF,IAlJJE,EAAAC,KAAA,CAAwBnC,EAAA3C,KAAA,CAkJHwE,CAlJG,CAAxB,CAkJI,CACLC,CAAA,CAAc,IAAID,CAAAQ,YAAJ,CAAuBR,CAAvB,CADT,KAEA,IAAIhD,EAAA,CAAOgD,CAAP,CAAJ,CACLC,CAAA,CAAc,IAAIhD,IAAJ,CAAS+C,CAAAS,QAAA,EAAT,CADT,KAEA,IAAIhC,EAAA,CAASuB,CAAT,CAAJ,CACLC,CACA,CADc,IAAIS,MAAJ,CAAWV,CAAAA,OAAX,CAA0BA,CAAA7B,SAAA,EAAAwC,MAAA,CAAwB,SAAxB,CAAA,CAAmC,CAAnC,CAA1B,CACd,CAAAV,CAAAW,UAAA,CAAwBZ,CAAAY,UAFnB,KAKL,OADIC,EACG;AADWhG,MAAAgD,OAAA,CAAcU,EAAA,CAAeyB,CAAf,CAAd,CACX,CAAAD,EAAA,CAAKC,CAAL,CAAaa,CAAb,CAA0BX,CAA1B,CAAuCC,CAAvC,CAGLA,EAAJ,GACED,CAAAK,KAAA,CAAiBP,CAAjB,CACA,CAAAG,CAAAI,KAAA,CAAeN,CAAf,CAFF,CAxBoB,CA+ExB,MAAOA,EA3FkD,CAmG3Da,QAASA,GAAW,CAAC/D,CAAD,CAAMP,CAAN,CAAW,CAC7B,GAAIvB,CAAA,CAAQ8B,CAAR,CAAJ,CAAkB,CAChBP,CAAA,CAAMA,CAAN,EAAa,EAEb,KAHgB,IAGPV,EAAI,CAHG,CAGAa,EAAKI,CAAAnC,OAArB,CAAiCkB,CAAjC,CAAqCa,CAArC,CAAyCb,CAAA,EAAzC,CACEU,CAAA,CAAIV,CAAJ,CAAA,CAASiB,CAAA,CAAIjB,CAAJ,CAJK,CAAlB,IAMO,IAAIc,CAAA,CAASG,CAAT,CAAJ,CAGL,IAAS1B,CAAT,GAFAmB,EAEgBO,CAFVP,CAEUO,EAFH,EAEGA,CAAAA,CAAhB,CACE,GAAwB,GAAxB,GAAM1B,CAAA0F,OAAA,CAAW,CAAX,CAAN,EAAiD,GAAjD,GAA+B1F,CAAA0F,OAAA,CAAW,CAAX,CAA/B,CACEvE,CAAA,CAAInB,CAAJ,CAAA,CAAW0B,CAAA,CAAI1B,CAAJ,CAKjB,OAAOmB,EAAP,EAAcO,CAjBe,CAkD/BiE,QAASA,GAAM,CAACC,CAAD,CAAKC,CAAL,CAAS,CACtB,GAAID,CAAJ,GAAWC,CAAX,CAAe,MAAO,CAAA,CACtB,IAAW,IAAX,GAAID,CAAJ,EAA0B,IAA1B,GAAmBC,CAAnB,CAAgC,MAAO,CAAA,CACvC,IAAID,CAAJ,GAAWA,CAAX,EAAiBC,CAAjB,GAAwBA,CAAxB,CAA4B,MAAO,CAAA,CAHb,KAIlBC,EAAK,MAAOF,EAJM,CAIsB5F,CAC5C,IAAI8F,CAAJ,EADyBC,MAAOF,EAChC,EACY,QADZ,EACMC,CADN,CAEI,GAAIlG,CAAA,CAAQgG,CAAR,CAAJ,CAAiB,CACf,GAAK,CAAAhG,CAAA,CAAQiG,CAAR,CAAL,CAAkB,MAAO,CAAA,CACzB,KAAKtG,CAAL,CAAcqG,CAAArG,OAAd,GAA4BsG,CAAAtG,OAA5B,CAAuC,CACrC,IAAKS,CAAL,CAAW,CAAX,CAAcA,CAAd,CAAoBT,CAApB,CAA4BS,CAAA,EAA5B,CACE,GAAK,CAAA2F,EAAA,CAAOC,CAAA,CAAG5F,CAAH,CAAP,CAAgB6F,CAAA,CAAG7F,CAAH,CAAhB,CAAL,CAA+B,MAAO,CAAA,CAExC,OAAO,CAAA,CAJ8B,CAFxB,CAAjB,IAQO,CAAA,GAAI2B,EAAA,CAAOiE,CAAP,CAAJ,CACL,MAAKjE,GAAA,CAAOkE,CAAP,CAAL;AACOF,EAAA,CAAOC,CAAAR,QAAA,EAAP,CAAqBS,CAAAT,QAAA,EAArB,CADP,CAAwB,CAAA,CAEnB,IAAIhC,EAAA,CAASwC,CAAT,CAAJ,CACL,MAAOxC,GAAA,CAASyC,CAAT,CAAA,CAAeD,CAAA9C,SAAA,EAAf,EAAgC+C,CAAA/C,SAAA,EAAhC,CAAgD,CAAA,CAEvD,IAAIO,EAAA,CAAQuC,CAAR,CAAJ,EAAmBvC,EAAA,CAAQwC,CAAR,CAAnB,EAAkCvG,EAAA,CAASsG,CAAT,CAAlC,EAAkDtG,EAAA,CAASuG,CAAT,CAAlD,EACEjG,CAAA,CAAQiG,CAAR,CADF,EACiBlE,EAAA,CAAOkE,CAAP,CADjB,EAC+BzC,EAAA,CAASyC,CAAT,CAD/B,CAC6C,MAAO,CAAA,CACpDG,EAAA,CAASC,EAAA,EACT,KAAKjG,CAAL,GAAY4F,EAAZ,CACE,GAAsB,GAAtB,GAAI5F,CAAA0F,OAAA,CAAW,CAAX,CAAJ,EAA6B,CAAAzF,CAAA,CAAW2F,CAAA,CAAG5F,CAAH,CAAX,CAA7B,CAAA,CACA,GAAK,CAAA2F,EAAA,CAAOC,CAAA,CAAG5F,CAAH,CAAP,CAAgB6F,CAAA,CAAG7F,CAAH,CAAhB,CAAL,CAA+B,MAAO,CAAA,CACtCgG,EAAA,CAAOhG,CAAP,CAAA,CAAc,CAAA,CAFd,CAIF,IAAKA,CAAL,GAAY6F,EAAZ,CACE,GAAI,EAAE7F,CAAF,GAASgG,EAAT,EACkB,GADlB,GACAhG,CAAA0F,OAAA,CAAW,CAAX,CADA,EAEAG,CAAA,CAAG7F,CAAH,CAFA,GAEYd,CAFZ,EAGCe,CAAA,CAAW4F,CAAA,CAAG7F,CAAH,CAAX,CAHD,CAAJ,CAG0B,MAAO,CAAA,CAEnC,OAAO,CAAA,CApBF,CAwBX,MAAO,CAAA,CAvCe,CAkHxBkG,QAASA,GAAM,CAACC,CAAD,CAASC,CAAT,CAAiB7B,CAAjB,CAAwB,CACrC,MAAO4B,EAAAD,OAAA,CAAcnE,EAAA5B,KAAA,CAAWiG,CAAX,CAAmB7B,CAAnB,CAAd,CAD8B,CA4BvC8B,QAASA,GAAI,CAACC,CAAD,CAAOC,CAAP,CAAW,CACtB,IAAIC,EAA+B,CAAnB,CAAAxE,SAAAzC,OAAA,CAxBTwC,EAAA5B,KAAA,CAwB0C6B,SAxB1C,CAwBqDyE,CAxBrD,CAwBS,CAAiD,EACjE,OAAI,CAAAxG,CAAA,CAAWsG,CAAX,CAAJ,EAAwBA,CAAxB,WAAsClB,OAAtC,CAcSkB,CAdT,CACSC,CAAAjH,OAAA,CACH,QAAQ,EAAG,CACT,MAAOyC,UAAAzC,OAAA;AACHgH,CAAAG,MAAA,CAASJ,CAAT,CAAeJ,EAAA,CAAOM,CAAP,CAAkBxE,SAAlB,CAA6B,CAA7B,CAAf,CADG,CAEHuE,CAAAG,MAAA,CAASJ,CAAT,CAAeE,CAAf,CAHK,CADR,CAMH,QAAQ,EAAG,CACT,MAAOxE,UAAAzC,OAAA,CACHgH,CAAAG,MAAA,CAASJ,CAAT,CAAetE,SAAf,CADG,CAEHuE,CAAApG,KAAA,CAAQmG,CAAR,CAHK,CATK,CAqBxBK,QAASA,GAAc,CAAC3G,CAAD,CAAMY,CAAN,CAAa,CAClC,IAAIgG,EAAMhG,CAES,SAAnB,GAAI,MAAOZ,EAAX,EAAiD,GAAjD,GAA+BA,CAAA0F,OAAA,CAAW,CAAX,CAA/B,EAA0E,GAA1E,GAAwD1F,CAAA0F,OAAA,CAAW,CAAX,CAAxD,CACEkB,CADF,CACQ1H,CADR,CAEWI,EAAA,CAASsB,CAAT,CAAJ,CACLgG,CADK,CACC,SADD,CAEIhG,CAAJ,EAAc3B,CAAd,GAA2B2B,CAA3B,CACLgG,CADK,CACC,WADD,CAEIvD,EAAA,CAAQzC,CAAR,CAFJ,GAGLgG,CAHK,CAGC,QAHD,CAMP,OAAOA,EAb2B,CAgCpCC,QAASA,GAAM,CAACxH,CAAD,CAAMyH,CAAN,CAAc,CAC3B,GAAmB,WAAnB,GAAI,MAAOzH,EAAX,CAAgC,MAAOH,EAClCiE,EAAA,CAAS2D,CAAT,CAAL,GACEA,CADF,CACWA,CAAA,CAAS,CAAT,CAAa,IADxB,CAGA,OAAOC,KAAAC,UAAA,CAAe3H,CAAf,CAAoBsH,EAApB,CAAoCG,CAApC,CALoB,CAqB7BG,QAASA,GAAQ,CAACC,CAAD,CAAO,CACtB,MAAOvH,EAAA,CAASuH,CAAT,CAAA,CACDH,IAAAI,MAAA,CAAWD,CAAX,CADC,CAEDA,CAHgB,CAOxBE,QAASA,GAAgB,CAACC,CAAD,CAAWC,CAAX,CAAqB,CAC5C,IAAIC,EAA0B3F,IAAAuF,MAAA,CAAW,wBAAX,CAAsCE,CAAtC,CAA1BE,CAA4E,GAChF,OAAOC,MAAA,CAAMD,CAAN,CAAA,CAAiCD,CAAjC,CAA4CC,CAFP,CAa9CE,QAASA,GAAsB,CAACC,CAAD;AAAOL,CAAP,CAAiBM,CAAjB,CAA0B,CACvDA,CAAA,CAAUA,CAAA,CAAW,EAAX,CAAe,CACzB,KAAIC,EAAiBR,EAAA,CAAiBC,CAAjB,CAA2BK,CAAAG,kBAAA,EAA3B,CACCH,EAAAA,CAAAA,CAAM,EAAA,CAAAC,CAAA,EAAWC,CAAX,CAA4BF,CAAAG,kBAAA,EAA5B,CAT5BH,EAAA,CAAO,IAAI9F,IAAJ,CAAS8F,CAAAtC,QAAA,EAAT,CACPsC,EAAAI,WAAA,CAAgBJ,CAAAK,WAAA,EAAhB,CAAoCC,CAApC,CAQA,OAPON,EAIgD,CAUzDO,QAASA,GAAW,CAAC9D,CAAD,CAAU,CAC5BA,CAAA,CAAU+D,CAAA,CAAO/D,CAAP,CAAAgE,MAAA,EACV,IAAI,CAGFhE,CAAAiE,MAAA,EAHE,CAIF,MAAOC,CAAP,CAAU,EACZ,IAAIC,EAAWJ,CAAA,CAAO,OAAP,CAAAK,OAAA,CAAuBpE,CAAvB,CAAAqE,KAAA,EACf,IAAI,CACF,MAAOrE,EAAA,CAAQ,CAAR,CAAA1E,SAAA,GAAwBgJ,EAAxB,CAAyCrE,CAAA,CAAUkE,CAAV,CAAzC,CACHA,CAAAhD,MAAA,CACQ,YADR,CAAA,CACsB,CADtB,CAAAoD,QAAA,CAEU,aAFV,CAEyB,QAAQ,CAACpD,CAAD,CAAQ3B,CAAR,CAAkB,CAAE,MAAO,GAAP,CAAaS,CAAA,CAAUT,CAAV,CAAf,CAFnD,CAFF,CAKF,MAAO0E,CAAP,CAAU,CACV,MAAOjE,EAAA,CAAUkE,CAAV,CADG,CAbgB,CA8B9BK,QAASA,GAAqB,CAAC/H,CAAD,CAAQ,CACpC,GAAI,CACF,MAAOgI,mBAAA,CAAmBhI,CAAnB,CADL,CAEF,MAAOyH,CAAP,CAAU,EAHwB,CAatCQ,QAASA,GAAa,CAAYC,CAAZ,CAAsB,CAAA,IACtCzJ,EAAM,EADgC,CAC5B0J,CAD4B,CACjB/I,CACzBH,EAAA,CAAQoE,CAAC6E,CAAD7E,EAAa,EAAbA,OAAA,CAAuB,GAAvB,CAAR,CAAqC,QAAQ,CAAC6E,CAAD,CAAW,CAClDA,CAAJ,GACEC,CAEA,CAFYD,CAAAJ,QAAA,CAAiB,KAAjB;AAAuB,KAAvB,CAAAzE,MAAA,CAAoC,GAApC,CAEZ,CADAjE,CACA,CADM2I,EAAA,CAAsBI,CAAA,CAAU,CAAV,CAAtB,CACN,CAAI9F,CAAA,CAAUjD,CAAV,CAAJ,GACM4G,CACJ,CADU3D,CAAA,CAAU8F,CAAA,CAAU,CAAV,CAAV,CAAA,CAA0BJ,EAAA,CAAsBI,CAAA,CAAU,CAAV,CAAtB,CAA1B,CAAgE,CAAA,CAC1E,CAAK7I,EAAAC,KAAA,CAAoBd,CAApB,CAAyBW,CAAzB,CAAL,CAEWJ,CAAA,CAAQP,CAAA,CAAIW,CAAJ,CAAR,CAAJ,CACLX,CAAA,CAAIW,CAAJ,CAAAkF,KAAA,CAAc0B,CAAd,CADK,CAGLvH,CAAA,CAAIW,CAAJ,CAHK,CAGM,CAACX,CAAA,CAAIW,CAAJ,CAAD,CAAU4G,CAAV,CALb,CACEvH,CAAA,CAAIW,CAAJ,CADF,CACa4G,CAHf,CAHF,CADsD,CAAxD,CAgBA,OAAOvH,EAlBmC,CAqB5C2J,QAASA,GAAU,CAAC3J,CAAD,CAAM,CACvB,IAAI4J,EAAQ,EACZpJ,EAAA,CAAQR,CAAR,CAAa,QAAQ,CAACuB,CAAD,CAAQZ,CAAR,CAAa,CAC5BJ,CAAA,CAAQgB,CAAR,CAAJ,CACEf,CAAA,CAAQe,CAAR,CAAe,QAAQ,CAACsI,CAAD,CAAa,CAClCD,CAAA/D,KAAA,CAAWiE,EAAA,CAAenJ,CAAf,CAAoB,CAAA,CAApB,CAAX,EAC2B,CAAA,CAAf,GAAAkJ,CAAA,CAAsB,EAAtB,CAA2B,GAA3B,CAAiCC,EAAA,CAAeD,CAAf,CAA2B,CAAA,CAA3B,CAD7C,EADkC,CAApC,CADF,CAMAD,CAAA/D,KAAA,CAAWiE,EAAA,CAAenJ,CAAf,CAAoB,CAAA,CAApB,CAAX,EACsB,CAAA,CAAV,GAAAY,CAAA,CAAiB,EAAjB,CAAsB,GAAtB,CAA4BuI,EAAA,CAAevI,CAAf,CAAsB,CAAA,CAAtB,CADxC,EAPgC,CAAlC,CAWA,OAAOqI,EAAA1J,OAAA,CAAe0J,CAAAG,KAAA,CAAW,GAAX,CAAf,CAAiC,EAbjB,CA4BzBC,QAASA,GAAgB,CAACzC,CAAD,CAAM,CAC7B,MAAOuC,GAAA,CAAevC,CAAf,CAAoB,CAAA,CAApB,CAAA8B,QAAA,CACY,OADZ,CACqB,GADrB,CAAAA,QAAA,CAEY,OAFZ,CAEqB,GAFrB,CAAAA,QAAA,CAGY,OAHZ,CAGqB,GAHrB,CADsB,CAmB/BS,QAASA,GAAc,CAACvC,CAAD,CAAM0C,CAAN,CAAuB,CAC5C,MAAOC,mBAAA,CAAmB3C,CAAnB,CAAA8B,QAAA,CACY,OADZ,CACqB,GADrB,CAAAA,QAAA,CAEY,OAFZ,CAEqB,GAFrB,CAAAA,QAAA,CAGY,MAHZ;AAGoB,GAHpB,CAAAA,QAAA,CAIY,OAJZ,CAIqB,GAJrB,CAAAA,QAAA,CAKY,OALZ,CAKqB,GALrB,CAAAA,QAAA,CAMY,MANZ,CAMqBY,CAAA,CAAkB,KAAlB,CAA0B,GAN/C,CADqC,CAY9CE,QAASA,GAAc,CAACrF,CAAD,CAAUsF,CAAV,CAAkB,CAAA,IACnC5F,CADmC,CAC7BpD,CAD6B,CAC1Ba,EAAKoI,EAAAnK,OAClB,KAAKkB,CAAL,CAAS,CAAT,CAAYA,CAAZ,CAAgBa,CAAhB,CAAoB,EAAEb,CAAtB,CAEE,GADAoD,CACI,CADG6F,EAAA,CAAejJ,CAAf,CACH,CADuBgJ,CACvB,CAAA9J,CAAA,CAASkE,CAAT,CAAgBM,CAAAwF,aAAA,CAAqB9F,CAArB,CAAhB,CAAJ,CACE,MAAOA,EAGX,OAAO,KARgC,CA0IzC+F,QAASA,GAAW,CAACzF,CAAD,CAAU0F,CAAV,CAAqB,CAAA,IACnCC,CADmC,CAEnCC,CAFmC,CAGnCC,EAAS,EAGbnK,EAAA,CAAQ6J,EAAR,CAAwB,QAAQ,CAACO,CAAD,CAAS,CACnCC,CAAAA,EAAgB,KAEfJ,EAAAA,CAAL,EAAmB3F,CAAAgG,aAAnB,EAA2ChG,CAAAgG,aAAA,CAAqBD,CAArB,CAA3C,GACEJ,CACA,CADa3F,CACb,CAAA4F,CAAA,CAAS5F,CAAAwF,aAAA,CAAqBO,CAArB,CAFX,CAHuC,CAAzC,CAQArK,EAAA,CAAQ6J,EAAR,CAAwB,QAAQ,CAACO,CAAD,CAAS,CACnCC,CAAAA,EAAgB,KACpB,KAAIE,CAECN,EAAAA,CAAL,GAAoBM,CAApB,CAAgCjG,CAAAkG,cAAA,CAAsB,GAAtB,CAA4BH,CAAAxB,QAAA,CAAa,GAAb,CAAkB,KAAlB,CAA5B,CAAuD,GAAvD,CAAhC,IACEoB,CACA,CADaM,CACb,CAAAL,CAAA,CAASK,CAAAT,aAAA,CAAuBO,CAAvB,CAFX,CAJuC,CAAzC,CASIJ,EAAJ,GACEE,CAAAM,SACA,CAD8D,IAC9D,GADkBd,EAAA,CAAeM,CAAf,CAA2B,WAA3B,CAClB,CAAAD,CAAA,CAAUC,CAAV,CAAsBC,CAAA,CAAS,CAACA,CAAD,CAAT,CAAoB,EAA1C,CAA8CC,CAA9C,CAFF,CAvBuC,CA+EzCH,QAASA,GAAS,CAAC1F,CAAD,CAAUoG,CAAV,CAAmBP,CAAnB,CAA2B,CACtCzI,CAAA,CAASyI,CAAT,CAAL;CAAuBA,CAAvB,CAAgC,EAAhC,CAIAA,EAAA,CAASlI,CAAA,CAHW0I,CAClBF,SAAU,CAAA,CADQE,CAGX,CAAsBR,CAAtB,CACT,KAAIS,EAAcA,QAAQ,EAAG,CAC3BtG,CAAA,CAAU+D,CAAA,CAAO/D,CAAP,CAEV,IAAIA,CAAAuG,SAAA,EAAJ,CAAwB,CACtB,IAAIC,EAAOxG,CAAA,CAAQ,CAAR,CAAD,GAAgBlF,CAAhB,CAA4B,UAA5B,CAAyCgJ,EAAA,CAAY9D,CAAZ,CAEnD,MAAMY,GAAA,CACF,SADE,CAGF4F,CAAAjC,QAAA,CAAY,GAAZ,CAAgB,MAAhB,CAAAA,QAAA,CAAgC,GAAhC,CAAoC,MAApC,CAHE,CAAN,CAHsB,CASxB6B,CAAA,CAAUA,CAAV,EAAqB,EACrBA,EAAAK,QAAA,CAAgB,CAAC,UAAD,CAAa,QAAQ,CAACC,CAAD,CAAW,CAC9CA,CAAAjK,MAAA,CAAe,cAAf,CAA+BuD,CAA/B,CAD8C,CAAhC,CAAhB,CAII6F,EAAAc,iBAAJ,EAEEP,CAAArF,KAAA,CAAa,CAAC,kBAAD,CAAqB,QAAQ,CAAC6F,CAAD,CAAmB,CAC3DA,CAAAD,iBAAA,CAAkC,CAAA,CAAlC,CAD2D,CAAhD,CAAb,CAKFP,EAAAK,QAAA,CAAgB,IAAhB,CACIF,EAAAA,CAAWM,EAAA,CAAeT,CAAf,CAAwBP,CAAAM,SAAxB,CACfI,EAAAO,OAAA,CAAgB,CAAC,YAAD,CAAe,cAAf,CAA+B,UAA/B,CAA2C,WAA3C,CACbC,QAAuB,CAACC,CAAD,CAAQhH,CAAR,CAAiBiH,CAAjB,CAA0BV,CAA1B,CAAoC,CAC1DS,CAAAE,OAAA,CAAa,QAAQ,EAAG,CACtBlH,CAAAmH,KAAA,CAAa,WAAb,CAA0BZ,CAA1B,CACAU,EAAA,CAAQjH,CAAR,CAAA,CAAiBgH,CAAjB,CAFsB,CAAxB,CAD0D,CAD9C,CAAhB,CAQA,OAAOT,EAlCoB,CAA7B,CAqCIa;AAAuB,wBArC3B,CAsCIC,EAAqB,sBAErBxM,EAAJ,EAAcuM,CAAAtG,KAAA,CAA0BjG,CAAAkL,KAA1B,CAAd,GACEF,CAAAc,iBACA,CAD0B,CAAA,CAC1B,CAAA9L,CAAAkL,KAAA,CAAclL,CAAAkL,KAAAxB,QAAA,CAAoB6C,CAApB,CAA0C,EAA1C,CAFhB,CAKA,IAAIvM,CAAJ,EAAe,CAAAwM,CAAAvG,KAAA,CAAwBjG,CAAAkL,KAAxB,CAAf,CACE,MAAOO,EAAA,EAGTzL,EAAAkL,KAAA,CAAclL,CAAAkL,KAAAxB,QAAA,CAAoB8C,CAApB,CAAwC,EAAxC,CACdC,GAAAC,gBAAA,CAA0BC,QAAQ,CAACC,CAAD,CAAe,CAC/C/L,CAAA,CAAQ+L,CAAR,CAAsB,QAAQ,CAAC7B,CAAD,CAAS,CACrCQ,CAAArF,KAAA,CAAa6E,CAAb,CADqC,CAAvC,CAGA,OAAOU,EAAA,EAJwC,CAO7CxK,EAAA,CAAWwL,EAAAI,wBAAX,CAAJ,EACEJ,EAAAI,wBAAA,EAhEyC,CA8E7CC,QAASA,GAAmB,EAAG,CAC7B9M,CAAAkL,KAAA,CAAc,uBAAd,CAAwClL,CAAAkL,KACxClL,EAAA+M,SAAAC,OAAA,EAF6B,CAa/BC,QAASA,GAAc,CAACC,CAAD,CAAc,CAC/BxB,CAAAA,CAAWe,EAAAtH,QAAA,CAAgB+H,CAAhB,CAAAxB,SAAA,EACf,IAAKA,CAAAA,CAAL,CACE,KAAM3F,GAAA,CAAS,MAAT,CAAN,CAGF,MAAO2F,EAAAyB,IAAA,CAAa,eAAb,CAN4B,CAUrCC,QAASA,GAAU,CAAClC,CAAD,CAAOmC,CAAP,CAAkB,CACnCA,CAAA,CAAYA,CAAZ;AAAyB,GACzB,OAAOnC,EAAAxB,QAAA,CAAa4D,EAAb,CAAgC,QAAQ,CAACC,CAAD,CAASC,CAAT,CAAc,CAC3D,OAAQA,CAAA,CAAMH,CAAN,CAAkB,EAA1B,EAAgCE,CAAAE,YAAA,EAD2B,CAAtD,CAF4B,CASrCC,QAASA,GAAU,EAAG,CACpB,IAAIC,CAEJ,IAAIC,CAAAA,EAAJ,CAAA,CAKA,IAAIC,EAASC,EAAA,EACbC,GAAA,CAAS/N,CAAA+N,OACL9J,EAAA,CAAU4J,CAAV,CAAJ,GACEE,EADF,CACsB,IAAX,GAAAF,CAAA,CAAkB3N,CAAlB,CAA8BF,CAAA,CAAO6N,CAAP,CADzC,CAQIE,GAAJ,EAAcA,EAAAxG,GAAAyG,GAAd,EACE9E,CAaA,CAbS6E,EAaT,CAZAjL,CAAA,CAAOiL,EAAAxG,GAAP,CAAkB,CAChB4E,MAAO8B,EAAA9B,MADS,CAEhB+B,aAAcD,EAAAC,aAFE,CAGhBC,WAAYF,EAAAE,WAHI,CAIhBzC,SAAUuC,EAAAvC,SAJM,CAKhB0C,cAAeH,EAAAG,cALC,CAAlB,CAYA,CADAT,CACA,CADoBI,EAAAM,UACpB,CAAAN,EAAAM,UAAA,CAAmBC,QAAQ,CAACC,CAAD,CAAQ,CACjC,IAAIC,CACJ,IAAKC,EAAL,CAQEA,EAAA,CAAmC,CAAA,CARrC,KACE,KADqC,IAC5BhN,EAAI,CADwB,CACrBiN,CAAhB,CAA2C,IAA3C,GAAuBA,CAAvB,CAA8BH,CAAA,CAAM9M,CAAN,CAA9B,EAAiDA,CAAA,EAAjD,CAEE,CADA+M,CACA,CADST,EAAAY,MAAA,CAAaD,CAAb,CAAmB,QAAnB,CACT,GAAcF,CAAAI,SAAd,EACEb,EAAA,CAAOW,CAAP,CAAAG,eAAA,CAA4B,UAA5B,CAMNlB,EAAA,CAAkBY,CAAlB,CAZiC,CAdrC,EA6BErF,CA7BF,CA6BW4F,CAGXrC,GAAAtH,QAAA,CAAkB+D,CAGlB0E,GAAA,CAAkB,CAAA,CAlDlB,CAHoB,CA2DtBmB,QAASA,GAAS,CAACC,CAAD;AAAM9D,CAAN,CAAY+D,CAAZ,CAAoB,CACpC,GAAKD,CAAAA,CAAL,CACE,KAAMjJ,GAAA,CAAS,MAAT,CAA2CmF,CAA3C,EAAmD,GAAnD,CAA0D+D,CAA1D,EAAoE,UAApE,CAAN,CAEF,MAAOD,EAJ6B,CAOtCE,QAASA,GAAW,CAACF,CAAD,CAAM9D,CAAN,CAAYiE,CAAZ,CAAmC,CACjDA,CAAJ,EAA6BvO,CAAA,CAAQoO,CAAR,CAA7B,GACIA,CADJ,CACUA,CAAA,CAAIA,CAAAzO,OAAJ,CAAiB,CAAjB,CADV,CAIAwO,GAAA,CAAU9N,CAAA,CAAW+N,CAAX,CAAV,CAA2B9D,CAA3B,CAAiC,sBAAjC,EACK8D,CAAA,EAAsB,QAAtB,GAAO,MAAOA,EAAd,CAAiCA,CAAA7I,YAAA+E,KAAjC,EAAyD,QAAzD,CAAoE,MAAO8D,EADhF,EAEA,OAAOA,EAP8C,CAevDI,QAASA,GAAuB,CAAClE,CAAD,CAAOnK,CAAP,CAAgB,CAC9C,GAAa,gBAAb,GAAImK,CAAJ,CACE,KAAMnF,GAAA,CAAS,SAAT,CAA8DhF,CAA9D,CAAN,CAF4C,CAchDsO,QAASA,GAAM,CAAChP,CAAD,CAAMiP,CAAN,CAAYC,CAAZ,CAA2B,CACxC,GAAKD,CAAAA,CAAL,CAAW,MAAOjP,EACdkB,EAAAA,CAAO+N,CAAArK,MAAA,CAAW,GAAX,CAKX,KAJA,IAAIjE,CAAJ,CACIwO,EAAenP,CADnB,CAEIoP,EAAMlO,CAAAhB,OAFV,CAISkB,EAAI,CAAb,CAAgBA,CAAhB,CAAoBgO,CAApB,CAAyBhO,CAAA,EAAzB,CACET,CACA,CADMO,CAAA,CAAKE,CAAL,CACN,CAAIpB,CAAJ,GACEA,CADF,CACQ,CAACmP,CAAD,CAAgBnP,CAAhB,EAAqBW,CAArB,CADR,CAIF,OAAKuO,CAAAA,CAAL,EAAsBtO,CAAA,CAAWZ,CAAX,CAAtB,CACSgH,EAAA,CAAKmI,CAAL,CAAmBnP,CAAnB,CADT,CAGOA,CAhBiC,CAwB1CqP,QAASA,GAAa,CAACC,CAAD,CAAQ,CAG5B,IAAIjL,EAAOiL,CAAA,CAAM,CAAN,CACPC,EAAAA,CAAUD,CAAA,CAAMA,CAAApP,OAAN,CAAqB,CAArB,CACd,KAAIsP,EAAa,CAACnL,CAAD,CAEjB,GAAG,CACDA,CAAA,CAAOA,CAAAoL,YACP,IAAKpL,CAAAA,CAAL,CAAW,KACXmL,EAAA3J,KAAA,CAAgBxB,CAAhB,CAHC,CAAH,MAISA,CAJT;AAIkBkL,CAJlB,CAMA,OAAO1G,EAAA,CAAO2G,CAAP,CAbqB,CA4B9B5I,QAASA,GAAS,EAAG,CACnB,MAAOzG,OAAAgD,OAAA,CAAc,IAAd,CADY,CAoBrBuM,QAASA,GAAiB,CAAC/P,CAAD,CAAS,CAKjCgQ,QAASA,EAAM,CAAC3P,CAAD,CAAM6K,CAAN,CAAY+E,CAAZ,CAAqB,CAClC,MAAO5P,EAAA,CAAI6K,CAAJ,CAAP,GAAqB7K,CAAA,CAAI6K,CAAJ,CAArB,CAAiC+E,CAAA,EAAjC,CADkC,CAHpC,IAAIC,EAAkB/P,CAAA,CAAO,WAAP,CAAtB,CACI4F,EAAW5F,CAAA,CAAO,IAAP,CAMXsM,EAAAA,CAAUuD,CAAA,CAAOhQ,CAAP,CAAe,SAAf,CAA0BQ,MAA1B,CAGdiM,EAAA0D,SAAA,CAAmB1D,CAAA0D,SAAnB,EAAuChQ,CAEvC,OAAO6P,EAAA,CAAOvD,CAAP,CAAgB,QAAhB,CAA0B,QAAQ,EAAG,CAE1C,IAAIlB,EAAU,EAqDd,OAAOR,SAAe,CAACG,CAAD,CAAOkF,CAAP,CAAiBC,CAAjB,CAA2B,CAE7C,GAAa,gBAAb,GAKsBnF,CALtB,CACE,KAAMnF,EAAA,CAAS,SAAT,CAIoBhF,QAJpB,CAAN,CAKAqP,CAAJ,EAAgB7E,CAAArK,eAAA,CAAuBgK,CAAvB,CAAhB,GACEK,CAAA,CAAQL,CAAR,CADF,CACkB,IADlB,CAGA,OAAO8E,EAAA,CAAOzE,CAAP,CAAgBL,CAAhB,CAAsB,QAAQ,EAAG,CA0OtCoF,QAASA,EAAW,CAACC,CAAD,CAAWC,CAAX,CAAmBC,CAAnB,CAAiCC,CAAjC,CAAwC,CACrDA,CAAL,GAAYA,CAAZ,CAAoBC,CAApB,CACA,OAAO,SAAQ,EAAG,CAChBD,CAAA,CAAMD,CAAN,EAAsB,MAAtB,CAAA,CAA8B,CAACF,CAAD,CAAWC,CAAX,CAAmBxN,SAAnB,CAA9B,CACA,OAAO4N,EAFS,CAFwC,CAa5DC,QAASA,EAA2B,CAACN,CAAD,CAAWC,CAAX,CAAmB,CACrD,MAAO,SAAQ,CAACM,CAAD,CAAaC,CAAb,CAA8B,CACvCA,CAAJ,EAAuB9P,CAAA,CAAW8P,CAAX,CAAvB;CAAoDA,CAAAC,aAApD,CAAmF9F,CAAnF,CACAyF,EAAAzK,KAAA,CAAiB,CAACqK,CAAD,CAAWC,CAAX,CAAmBxN,SAAnB,CAAjB,CACA,OAAO4N,EAHoC,CADQ,CAtPvD,GAAKR,CAAAA,CAAL,CACE,KAAMF,EAAA,CAAgB,OAAhB,CAEiDhF,CAFjD,CAAN,CAMF,IAAIyF,EAAc,EAAlB,CAGIM,EAAe,EAHnB,CAMIC,EAAY,EANhB,CAQIlG,EAASsF,CAAA,CAAY,WAAZ,CAAyB,QAAzB,CAAmC,MAAnC,CAA2CW,CAA3C,CARb,CAWIL,EAAiB,CAEnBO,aAAcR,CAFK,CAGnBS,cAAeH,CAHI,CAInBI,WAAYH,CAJO,CAenBd,SAAUA,CAfS,CAyBnBlF,KAAMA,CAzBa,CAsCnBqF,SAAUM,CAAA,CAA4B,UAA5B,CAAwC,UAAxC,CAtCS,CAiDnBZ,QAASY,CAAA,CAA4B,UAA5B,CAAwC,SAAxC,CAjDU,CA4DnBS,QAAST,CAAA,CAA4B,UAA5B,CAAwC,SAAxC,CA5DU,CAuEnBjP,MAAO0O,CAAA,CAAY,UAAZ,CAAwB,OAAxB,CAvEY,CAmFnBiB,SAAUjB,CAAA,CAAY,UAAZ,CAAwB,UAAxB,CAAoC,SAApC,CAnFS,CA+FnBkB,UAAWX,CAAA,CAA4B,UAA5B,CAAwC,WAAxC,CA/FQ,CAiInBY,UAAWZ,CAAA,CAA4B,kBAA5B,CAAgD,UAAhD,CAjIQ,CAmJnBa,OAAQb,CAAA,CAA4B,iBAA5B,CAA+C,UAA/C,CAnJW,CA+JnB1C,WAAY0C,CAAA,CAA4B,qBAA5B;AAAmD,UAAnD,CA/JO,CA4KnBc,UAAWd,CAAA,CAA4B,kBAA5B,CAAgD,WAAhD,CA5KQ,CAyLnB7F,OAAQA,CAzLW,CAqMnB4G,IAAKA,QAAQ,CAACC,CAAD,CAAQ,CACnBX,CAAAhL,KAAA,CAAe2L,CAAf,CACA,OAAO,KAFY,CArMF,CA2MjBxB,EAAJ,EACErF,CAAA,CAAOqF,CAAP,CAGF,OAAOO,EAlO+B,CAAjC,CAXwC,CAvDP,CAArC,CAd0B,CAoenCkB,QAASA,GAAkB,CAACrF,CAAD,CAAU,CACnC3J,CAAA,CAAO2J,CAAP,CAAgB,CACd,UAAa5B,EADC,CAEd,KAAQnF,EAFM,CAGd,OAAU5C,CAHI,CAId,MAASG,EAJK,CAKd,OAAU0D,EALI,CAMd,QAAWuC,CANG,CAOd,QAAWrI,CAPG,CAQd,SAAYmL,EARE,CASd,KAAQvI,CATM,CAUd,KAAQ4D,EAVM,CAWd,OAAUQ,EAXI,CAYd,SAAYI,EAZE,CAad,SAAYvE,EAbE,CAcd,YAAeM,CAdD,CAed,UAAaC,CAfC,CAgBd,SAAYtD,CAhBE,CAiBd,WAAcM,CAjBA,CAkBd,SAAYsB,CAlBE,CAmBd,SAAY4B,CAnBE,CAoBd,UAAaM,EApBC,CAqBd,QAAW7D,CArBG,CAsBd,QAAWmR,EAtBG,CAuBd,OAAUpP,EAvBI,CAwBd,UAAayC,CAxBC,CAyBd,UAAa4M,EAzBC,CA0Bd,UAAa,CAACC,QAAS,CAAV,CA1BC,CA2Bd,eAAkBhF,EA3BJ,CA4Bd,SAAY9M,CA5BE,CA6Bd,MAAS+R,EA7BK,CA8Bd,oBAAuBpF,EA9BT,CAAhB,CAiCAqF;EAAA,CAAgBpC,EAAA,CAAkB/P,CAAlB,CAChB,IAAI,CACFmS,EAAA,CAAc,UAAd,CADE,CAEF,MAAO9I,CAAP,CAAU,CACV8I,EAAA,CAAc,UAAd,CAA0B,EAA1B,CAAA5B,SAAA,CAAuC,SAAvC,CAAkD6B,EAAlD,CADU,CAIZD,EAAA,CAAc,IAAd,CAAoB,CAAC,UAAD,CAApB,CAAkC,CAAC,UAAD,CAChCE,QAAiB,CAACxG,CAAD,CAAW,CAE1BA,CAAA0E,SAAA,CAAkB,CAChB+B,cAAeC,EADC,CAAlB,CAGA1G,EAAA0E,SAAA,CAAkB,UAAlB,CAA8BiC,EAA9B,CAAAb,UAAA,CACY,CACNc,EAAGC,EADG,CAENC,MAAOC,EAFD,CAGNC,SAAUD,EAHJ,CAINE,KAAMC,EAJA,CAKNC,OAAQC,EALF,CAMNC,OAAQC,EANF,CAONC,MAAOC,EAPD,CAQNC,OAAQC,EARF,CASNC,OAAQC,EATF,CAUNC,WAAYC,EAVN,CAWNC,eAAgBC,EAXV,CAYNC,QAASC,EAZH,CAaNC,YAAaC,EAbP,CAcNC,WAAYC,EAdN,CAeNC,QAASC,EAfH,CAgBNC,aAAcC,EAhBR,CAiBNC,OAAQC,EAjBF,CAkBNC,OAAQC,EAlBF,CAmBNC,KAAMC,EAnBA,CAoBNC,UAAWC,EApBL,CAqBNC,OAAQC,EArBF,CAsBNC,cAAeC,EAtBT,CAuBNC,YAAaC,EAvBP,CAwBNC,SAAUC,EAxBJ,CAyBNC,OAAQC,EAzBF,CA0BNC,QAASC,EA1BH,CA2BNC,SAAUC,EA3BJ;AA4BNC,aAAcC,EA5BR,CA6BNC,gBAAiBC,EA7BX,CA8BNC,UAAWC,EA9BL,CA+BNC,aAAcC,EA/BR,CAgCNC,QAASC,EAhCH,CAiCNC,OAAQC,EAjCF,CAkCNC,SAAUC,EAlCJ,CAmCNC,QAASC,EAnCH,CAoCNC,UAAWD,EApCL,CAqCNE,SAAUC,EArCJ,CAsCNC,WAAYD,EAtCN,CAuCNE,UAAWC,EAvCL,CAwCNC,YAAaD,EAxCP,CAyCNE,UAAWC,EAzCL,CA0CNC,YAAaD,EA1CP,CA2CNE,QAASC,EA3CH,CA4CNC,eAAgBC,EA5CV,CADZ,CAAAhG,UAAA,CA+CY,CACRmD,UAAW8C,EADH,CA/CZ,CAAAjG,UAAA,CAkDYkG,EAlDZ,CAAAlG,UAAA,CAmDYmG,EAnDZ,CAoDAjM,EAAA0E,SAAA,CAAkB,CAChBwH,cAAeC,EADC,CAEhBC,SAAUC,EAFM,CAGhBC,eAAgBC,EAHA,CAIhBC,gBAAiBC,EAJD,CAKhBC,SAAUC,EALM,CAMhBC,cAAeC,EANC,CAOhBC,YAAaC,EAPG,CAQhBC,UAAWC,EARK,CAShBC,kBAAmBC,EATH,CAUhBC,QAASC,EAVO,CAWhBC,aAAcC,EAXE,CAYhBC,UAAWC,EAZK,CAahBC,MAAOC,EAbS,CAchBC,qBAAsBC,EAdN;AAehBC,2BAA4BC,EAfZ,CAgBhBC,aAAcC,EAhBE,CAiBhBC,UAAWC,EAjBK,CAkBhBC,KAAMC,EAlBU,CAmBhBC,OAAQC,EAnBQ,CAoBhBC,WAAYC,EApBI,CAqBhBC,GAAIC,EArBY,CAsBhBC,IAAKC,EAtBW,CAuBhBC,KAAMC,EAvBU,CAwBhBC,aAAcC,EAxBE,CAyBhBC,SAAUC,EAzBM,CA0BhBC,eAAgBC,EA1BA,CA2BhBC,iBAAkBC,EA3BF,CA4BhBC,cAAeC,EA5BC,CA6BhBC,SAAUC,EA7BM,CA8BhBC,QAASC,EA9BO,CA+BhBC,MAAOC,EA/BS,CAgChBC,SAAUC,EAhCM,CAiChBC,UAAWC,EAjCK,CAkChBC,eAAgBC,EAlCA,CAAlB,CAzD0B,CADI,CAAlC,CAzCmC,CA0RrCC,QAASA,GAAS,CAACjR,CAAD,CAAO,CACvB,MAAOA,EAAAxB,QAAA,CACG0S,EADH,CACyB,QAAQ,CAACC,CAAD,CAAIhP,CAAJ,CAAeE,CAAf,CAAuB+O,CAAvB,CAA+B,CACnE,MAAOA,EAAA,CAAS/O,CAAAgP,YAAA,EAAT,CAAgChP,CAD4B,CADhE,CAAA7D,QAAA,CAIG8S,EAJH,CAIoB,OAJpB,CADgB,CAgCzBC,QAASA,GAAiB,CAAC/X,CAAD,CAAO,CAG3BjE,CAAAA,CAAWiE,CAAAjE,SACf,OAAOA,EAAP,GAAoBC,EAApB,EAAyC,CAACD,CAA1C,EA9yBuBic,CA8yBvB,GAAsDjc,CAJvB,CAcjCkc,QAASA,GAAmB,CAACnT,CAAD,CAAOzI,CAAP,CAAgB,CAAA,IACtC6b,CADsC,CACjCjR,CADiC,CAEtCkR,EAAW9b,CAAA+b,uBAAA,EAF2B,CAGtCnN,EAAQ,EAEZ,IAtBQoN,EAAA9W,KAAA,CAsBauD,CAtBb,CAsBR,CAGO,CAELoT,CAAA;AAAMA,CAAN,EAAaC,CAAAG,YAAA,CAAqBjc,CAAAkc,cAAA,CAAsB,KAAtB,CAArB,CACbtR,EAAA,CAAM,CAACuR,EAAAC,KAAA,CAAqB3T,CAArB,CAAD,EAA+B,CAAC,EAAD,CAAK,EAAL,CAA/B,EAAyC,CAAzC,CAAAiE,YAAA,EACN2P,EAAA,CAAOC,EAAA,CAAQ1R,CAAR,CAAP,EAAuB0R,EAAAC,SACvBV,EAAAW,UAAA,CAAgBH,CAAA,CAAK,CAAL,CAAhB,CAA0B5T,CAAAE,QAAA,CAAa8T,EAAb,CAA+B,WAA/B,CAA1B,CAAwEJ,CAAA,CAAK,CAAL,CAIxE,KADA3b,CACA,CADI2b,CAAA,CAAK,CAAL,CACJ,CAAO3b,CAAA,EAAP,CAAA,CACEmb,CAAA,CAAMA,CAAAa,UAGR9N,EAAA,CAAQzI,EAAA,CAAOyI,CAAP,CAAciN,CAAAc,WAAd,CAERd,EAAA,CAAMC,CAAAc,WACNf,EAAAgB,YAAA,CAAkB,EAhBb,CAHP,IAEEjO,EAAAzJ,KAAA,CAAWnF,CAAA8c,eAAA,CAAuBrU,CAAvB,CAAX,CAqBFqT,EAAAe,YAAA,CAAuB,EACvBf,EAAAU,UAAA,CAAqB,EACrB1c,EAAA,CAAQ8O,CAAR,CAAe,QAAQ,CAACjL,CAAD,CAAO,CAC5BmY,CAAAG,YAAA,CAAqBtY,CAArB,CAD4B,CAA9B,CAIA,OAAOmY,EAlCmC,CAqD5C/N,QAASA,EAAM,CAAC3J,CAAD,CAAU,CACvB,GAAIA,CAAJ,WAAuB2J,EAAvB,CACE,MAAO3J,EAGT,KAAI2Y,CAEAnd,EAAA,CAASwE,CAAT,CAAJ,GACEA,CACA,CADU4Y,CAAA,CAAK5Y,CAAL,CACV,CAAA2Y,CAAA,CAAc,CAAA,CAFhB,CAIA,IAAM,EAAA,IAAA,WAAgBhP,EAAhB,CAAN,CAA+B,CAC7B,GAAIgP,CAAJ,EAAwC,GAAxC,EAAmB3Y,CAAAuB,OAAA,CAAe,CAAf,CAAnB,CACE,KAAMsX,GAAA,CAAa,OAAb,CAAN,CAEF,MAAO,KAAIlP,CAAJ,CAAW3J,CAAX,CAJsB,CAO/B,GAAI2Y,CAAJ,CAAiB,CAjCjB/c,CAAA,CAAqBd,CACrB;IAAIge,CAGF,EAAA,CADF,CAAKA,CAAL,CAAcC,EAAAf,KAAA,CAAuB3T,CAAvB,CAAd,EACS,CAACzI,CAAAkc,cAAA,CAAsBgB,CAAA,CAAO,CAAP,CAAtB,CAAD,CADT,CAIA,CAAKA,CAAL,CAActB,EAAA,CAAoBnT,CAApB,CAA0BzI,CAA1B,CAAd,EACSkd,CAAAP,WADT,CAIO,EAsBU,CACfS,EAAA,CAAe,IAAf,CAAqB,CAArB,CAnBqB,CAyBzBC,QAASA,GAAW,CAACjZ,CAAD,CAAU,CAC5B,MAAOA,EAAAkZ,UAAA,CAAkB,CAAA,CAAlB,CADqB,CAI9BC,QAASA,GAAY,CAACnZ,CAAD,CAAUoZ,CAAV,CAA2B,CACzCA,CAAL,EAAsBC,EAAA,CAAiBrZ,CAAjB,CAEtB,IAAIA,CAAAsZ,iBAAJ,CAEE,IADA,IAAIC,EAAcvZ,CAAAsZ,iBAAA,CAAyB,GAAzB,CAAlB,CACShd,EAAI,CADb,CACgBkd,EAAID,CAAAne,OAApB,CAAwCkB,CAAxC,CAA4Ckd,CAA5C,CAA+Cld,CAAA,EAA/C,CACE+c,EAAA,CAAiBE,CAAA,CAAYjd,CAAZ,CAAjB,CAN0C,CAWhDmd,QAASA,GAAS,CAACzZ,CAAD,CAAU0Z,CAAV,CAAgBtX,CAAhB,CAAoBuX,CAApB,CAAiC,CACjD,GAAI7a,CAAA,CAAU6a,CAAV,CAAJ,CAA4B,KAAMd,GAAA,CAAa,SAAb,CAAN,CAG5B,IAAIxP,GADAuQ,CACAvQ,CADewQ,EAAA,CAAmB7Z,CAAnB,CACfqJ,GAAyBuQ,CAAAvQ,OAA7B,CACIyQ,EAASF,CAATE,EAAyBF,CAAAE,OAE7B,IAAKA,CAAL,CAEA,GAAKJ,CAAL,CAQEhe,CAAA,CAAQge,CAAA5Z,MAAA,CAAW,GAAX,CAAR,CAAyB,QAAQ,CAAC4Z,CAAD,CAAO,CACtC,GAAI5a,CAAA,CAAUsD,CAAV,CAAJ,CAAmB,CACjB,IAAI2X,EAAc1Q,CAAA,CAAOqQ,CAAP,CAClBxZ,GAAA,CAAY6Z,CAAZ,EAA2B,EAA3B,CAA+B3X,CAA/B,CACA,IAAI2X,CAAJ,EAAwC,CAAxC,CAAmBA,CAAA3e,OAAnB,CACE,MAJe,CAQG4E,CA7LtBga,oBAAA,CA6L+BN,CA7L/B,CA6LqCI,CA7LrC,CAAsC,CAAA,CAAtC,CA8LA,QAAOzQ,CAAA,CAAOqQ,CAAP,CAV+B,CAAxC,CARF,KACE,KAAKA,CAAL,GAAarQ,EAAb,CACe,UAGb,GAHIqQ,CAGJ,EAFwB1Z,CA/KxBga,oBAAA,CA+KiCN,CA/KjC;AA+KuCI,CA/KvC,CAAsC,CAAA,CAAtC,CAiLA,CAAA,OAAOzQ,CAAA,CAAOqQ,CAAP,CAdsC,CAgCnDL,QAASA,GAAgB,CAACrZ,CAAD,CAAU+F,CAAV,CAAgB,CACvC,IAAIkU,EAAYja,CAAAka,MAAhB,CACIN,EAAeK,CAAfL,EAA4BO,EAAA,CAAQF,CAAR,CAE5BL,EAAJ,GACM7T,CAAJ,CACE,OAAO6T,CAAAzS,KAAA,CAAkBpB,CAAlB,CADT,EAKI6T,CAAAE,OAOJ,GANMF,CAAAvQ,OAAAI,SAGJ,EAFEmQ,CAAAE,OAAA,CAAoB,EAApB,CAAwB,UAAxB,CAEF,CAAAL,EAAA,CAAUzZ,CAAV,CAGF,EADA,OAAOma,EAAA,CAAQF,CAAR,CACP,CAAAja,CAAAka,MAAA,CAAgBnf,CAZhB,CADF,CAJuC,CAsBzC8e,QAASA,GAAkB,CAAC7Z,CAAD,CAAUoa,CAAV,CAA6B,CAAA,IAClDH,EAAYja,CAAAka,MADsC,CAElDN,EAAeK,CAAfL,EAA4BO,EAAA,CAAQF,CAAR,CAE5BG,EAAJ,EAA0BR,CAAAA,CAA1B,GACE5Z,CAAAka,MACA,CADgBD,CAChB,CApNyB,EAAEI,EAoN3B,CAAAT,CAAA,CAAeO,EAAA,CAAQF,CAAR,CAAf,CAAoC,CAAC5Q,OAAQ,EAAT,CAAalC,KAAM,EAAnB,CAAuB2S,OAAQ/e,CAA/B,CAFtC,CAKA,OAAO6e,EAT+C,CAaxDU,QAASA,GAAU,CAACta,CAAD,CAAUnE,CAAV,CAAeY,CAAf,CAAsB,CACvC,GAAI6a,EAAA,CAAkBtX,CAAlB,CAAJ,CAAgC,CAE9B,IAAIua,EAAiBzb,CAAA,CAAUrC,CAAV,CAArB,CACI+d,EAAiB,CAACD,CAAlBC,EAAoC3e,CAApC2e,EAA2C,CAACpd,CAAA,CAASvB,CAAT,CADhD,CAEI4e,EAAa,CAAC5e,CAEdsL,EAAAA,EADAyS,CACAzS,CADe0S,EAAA,CAAmB7Z,CAAnB,CAA4B,CAACwa,CAA7B,CACfrT,GAAuByS,CAAAzS,KAE3B,IAAIoT,CAAJ,CACEpT,CAAA,CAAKtL,CAAL,CAAA,CAAYY,CADd,KAEO,CACL,GAAIge,CAAJ,CACE,MAAOtT,EAEP,IAAIqT,CAAJ,CAEE,MAAOrT,EAAP,EAAeA,CAAA,CAAKtL,CAAL,CAEf8B,EAAA,CAAOwJ,CAAP,CAAatL,CAAb,CARC,CAVuB,CADO,CA0BzC6e,QAASA,GAAc,CAAC1a,CAAD,CAAU2a,CAAV,CAAoB,CACzC,MAAK3a,EAAAwF,aAAL,CAEqC,EAFrC,CACQjB,CAAC,GAADA,EAAQvE,CAAAwF,aAAA,CAAqB,OAArB,CAARjB,EAAyC,EAAzCA;AAA+C,GAA/CA,SAAA,CAA4D,SAA5D,CAAuE,GAAvE,CAAAlE,QAAA,CACI,GADJ,CACUsa,CADV,CACqB,GADrB,CADR,CAAkC,CAAA,CADO,CAM3CC,QAASA,GAAiB,CAAC5a,CAAD,CAAU6a,CAAV,CAAsB,CAC1CA,CAAJ,EAAkB7a,CAAA8a,aAAlB,EACEpf,CAAA,CAAQmf,CAAA/a,MAAA,CAAiB,GAAjB,CAAR,CAA+B,QAAQ,CAACib,CAAD,CAAW,CAChD/a,CAAA8a,aAAA,CAAqB,OAArB,CAA8BlC,CAAA,CAC1BrU,CAAC,GAADA,EAAQvE,CAAAwF,aAAA,CAAqB,OAArB,CAARjB,EAAyC,EAAzCA,EAA+C,GAA/CA,SAAA,CACS,SADT,CACoB,GADpB,CAAAA,QAAA,CAES,GAFT,CAEeqU,CAAA,CAAKmC,CAAL,CAFf,CAEgC,GAFhC,CAEqC,GAFrC,CAD0B,CAA9B,CADgD,CAAlD,CAF4C,CAYhDC,QAASA,GAAc,CAAChb,CAAD,CAAU6a,CAAV,CAAsB,CAC3C,GAAIA,CAAJ,EAAkB7a,CAAA8a,aAAlB,CAAwC,CACtC,IAAIG,EAAkB1W,CAAC,GAADA,EAAQvE,CAAAwF,aAAA,CAAqB,OAArB,CAARjB,EAAyC,EAAzCA,EAA+C,GAA/CA,SAAA,CACW,SADX,CACsB,GADtB,CAGtB7I,EAAA,CAAQmf,CAAA/a,MAAA,CAAiB,GAAjB,CAAR,CAA+B,QAAQ,CAACib,CAAD,CAAW,CAChDA,CAAA,CAAWnC,CAAA,CAAKmC,CAAL,CAC4C,GAAvD,GAAIE,CAAA5a,QAAA,CAAwB,GAAxB,CAA8B0a,CAA9B,CAAyC,GAAzC,CAAJ,GACEE,CADF,EACqBF,CADrB,CACgC,GADhC,CAFgD,CAAlD,CAOA/a,EAAA8a,aAAA,CAAqB,OAArB,CAA8BlC,CAAA,CAAKqC,CAAL,CAA9B,CAXsC,CADG,CAiB7CjC,QAASA,GAAc,CAACkC,CAAD,CAAOC,CAAP,CAAiB,CAGtC,GAAIA,CAAJ,CAGE,GAAIA,CAAA7f,SAAJ,CACE4f,CAAA,CAAKA,CAAA9f,OAAA,EAAL,CAAA,CAAsB+f,CADxB,KAEO,CACL,IAAI/f;AAAS+f,CAAA/f,OAGb,IAAsB,QAAtB,GAAI,MAAOA,EAAX,EAAkC+f,CAAAtgB,OAAlC,GAAsDsgB,CAAtD,CACE,IAAI/f,CAAJ,CACE,IAAS,IAAAkB,EAAI,CAAb,CAAgBA,CAAhB,CAAoBlB,CAApB,CAA4BkB,CAAA,EAA5B,CACE4e,CAAA,CAAKA,CAAA9f,OAAA,EAAL,CAAA,CAAsB+f,CAAA,CAAS7e,CAAT,CAF1B,CADF,IAOE4e,EAAA,CAAKA,CAAA9f,OAAA,EAAL,CAAA,CAAsB+f,CAXnB,CAR6B,CA0BxCC,QAASA,GAAgB,CAACpb,CAAD,CAAU+F,CAAV,CAAgB,CACvC,MAAOsV,GAAA,CAAoBrb,CAApB,CAA6B,GAA7B,EAAoC+F,CAApC,EAA4C,cAA5C,EAA8D,YAA9D,CADgC,CAIzCsV,QAASA,GAAmB,CAACrb,CAAD,CAAU+F,CAAV,CAAgBtJ,CAAhB,CAAuB,CAnjC1B8a,CAsjCvB,EAAIvX,CAAA1E,SAAJ,GACE0E,CADF,CACYA,CAAAsb,gBADZ,CAKA,KAFIC,CAEJ,CAFY9f,CAAA,CAAQsK,CAAR,CAAA,CAAgBA,CAAhB,CAAuB,CAACA,CAAD,CAEnC,CAAO/F,CAAP,CAAA,CAAgB,CACd,IADc,IACL1D,EAAI,CADC,CACEa,EAAKoe,CAAAngB,OAArB,CAAmCkB,CAAnC,CAAuCa,CAAvC,CAA2Cb,CAAA,EAA3C,CACE,IAAKG,CAAL,CAAasH,CAAAoD,KAAA,CAAYnH,CAAZ,CAAqBub,CAAA,CAAMjf,CAAN,CAArB,CAAb,IAAiDvB,CAAjD,CAA4D,MAAO0B,EAMrEuD,EAAA,CAAUA,CAAAwb,WAAV,EAlkC8BC,EAkkC9B,GAAiCzb,CAAA1E,SAAjC,EAAqF0E,CAAA0b,KARvE,CARiC,CAoBnDC,QAASA,GAAW,CAAC3b,CAAD,CAAU,CAE5B,IADAmZ,EAAA,CAAanZ,CAAb,CAAsB,CAAA,CAAtB,CACA,CAAOA,CAAAwY,WAAP,CAAA,CACExY,CAAA4b,YAAA,CAAoB5b,CAAAwY,WAApB,CAH0B,CAO9BqD,QAASA,GAAY,CAAC7b,CAAD,CAAU8b,CAAV,CAAoB,CAClCA,CAAL,EAAe3C,EAAA,CAAanZ,CAAb,CACf,KAAI7B,EAAS6B,CAAAwb,WACTrd,EAAJ,EAAYA,CAAAyd,YAAA,CAAmB5b,CAAnB,CAH2B,CAOzC+b,QAASA,GAAoB,CAACC,CAAD;AAASC,CAAT,CAAc,CACzCA,CAAA,CAAMA,CAAN,EAAaphB,CACb,IAAgC,UAAhC,GAAIohB,CAAAnhB,SAAAohB,WAAJ,CAIED,CAAAE,WAAA,CAAeH,CAAf,CAJF,KAOEjY,EAAA,CAAOkY,CAAP,CAAApT,GAAA,CAAe,MAAf,CAAuBmT,CAAvB,CATuC,CA0E3CI,QAASA,GAAkB,CAACpc,CAAD,CAAU+F,CAAV,CAAgB,CAEzC,IAAIsW,EAAcC,EAAA,CAAavW,CAAAuC,YAAA,EAAb,CAGlB,OAAO+T,EAAP,EAAsBE,EAAA,CAAiBxc,EAAA,CAAUC,CAAV,CAAjB,CAAtB,EAA8Dqc,CALrB,CAQ3CG,QAASA,GAAkB,CAACxc,CAAD,CAAU+F,CAAV,CAAgB,CACzC,IAAIvG,EAAWQ,CAAAR,SACf,QAAqB,OAArB,GAAQA,CAAR,EAA6C,UAA7C,GAAgCA,CAAhC,GAA4Did,EAAA,CAAa1W,CAAb,CAFnB,CAkL3C2W,QAASA,GAAkB,CAAC1c,CAAD,CAAUqJ,CAAV,CAAkB,CAC3C,IAAIsT,EAAeA,QAAQ,CAACC,CAAD,CAAQlD,CAAR,CAAc,CAEvCkD,CAAAC,mBAAA,CAA2BC,QAAQ,EAAG,CACpC,MAAOF,EAAAG,iBAD6B,CAItC,KAAIC,EAAW3T,CAAA,CAAOqQ,CAAP,EAAekD,CAAAlD,KAAf,CAAf,CACIuD,EAAiBD,CAAA,CAAWA,CAAA5hB,OAAX,CAA6B,CAElD,IAAK6hB,CAAL,CAAA,CAEA,GAAIpe,CAAA,CAAY+d,CAAAM,4BAAZ,CAAJ,CAAoD,CAClD,IAAIC,EAAmCP,CAAAQ,yBACvCR,EAAAQ,yBAAA,CAAiCC,QAAQ,EAAG,CAC1CT,CAAAM,4BAAA;AAAoC,CAAA,CAEhCN,EAAAU,gBAAJ,EACEV,CAAAU,gBAAA,EAGEH,EAAJ,EACEA,CAAAnhB,KAAA,CAAsC4gB,CAAtC,CARwC,CAFM,CAepDA,CAAAW,8BAAA,CAAsCC,QAAQ,EAAG,CAC/C,MAA6C,CAAA,CAA7C,GAAOZ,CAAAM,4BADwC,CAK3B,EAAtB,CAAKD,CAAL,GACED,CADF,CACa1b,EAAA,CAAY0b,CAAZ,CADb,CAIA,KAAS,IAAA1gB,EAAI,CAAb,CAAgBA,CAAhB,CAAoB2gB,CAApB,CAAoC3gB,CAAA,EAApC,CACOsgB,CAAAW,8BAAA,EAAL,EACEP,CAAA,CAAS1gB,CAAT,CAAAN,KAAA,CAAiBgE,CAAjB,CAA0B4c,CAA1B,CA5BJ,CATuC,CA4CzCD,EAAApT,KAAA,CAAoBvJ,CACpB,OAAO2c,EA9CoC,CAwS7ChG,QAASA,GAAgB,EAAG,CAC1B,IAAA8G,KAAA,CAAYC,QAAiB,EAAG,CAC9B,MAAO/f,EAAA,CAAOgM,CAAP,CAAe,CACpBgU,SAAUA,QAAQ,CAACpe,CAAD,CAAOqe,CAAP,CAAgB,CAC5Bre,CAAAG,KAAJ,GAAeH,CAAf,CAAsBA,CAAA,CAAK,CAAL,CAAtB,CACA,OAAOmb,GAAA,CAAenb,CAAf,CAAqBqe,CAArB,CAFyB,CADd,CAKpBC,SAAUA,QAAQ,CAACte,CAAD,CAAOqe,CAAP,CAAgB,CAC5Bre,CAAAG,KAAJ,GAAeH,CAAf,CAAsBA,CAAA,CAAK,CAAL,CAAtB,CACA,OAAOyb,GAAA,CAAezb,CAAf,CAAqBqe,CAArB,CAFyB,CALd,CASpBE,YAAaA,QAAQ,CAACve,CAAD,CAAOqe,CAAP,CAAgB,CAC/Bre,CAAAG,KAAJ,GAAeH,CAAf,CAAsBA,CAAA,CAAK,CAAL,CAAtB,CACA,OAAOqb,GAAA,CAAkBrb,CAAlB,CAAwBqe,CAAxB,CAF4B,CATjB,CAAf,CADuB,CADN,CA+B5BG,QAASA,GAAO,CAAC7iB,CAAD,CAAM8iB,CAAN,CAAiB,CAC/B,IAAIniB,EAAMX,CAANW,EAAaX,CAAA4B,UAEjB;GAAIjB,CAAJ,CAIE,MAHmB,UAGZA,GAHH,MAAOA,EAGJA,GAFLA,CAEKA,CAFCX,CAAA4B,UAAA,EAEDjB,EAAAA,CAGLoiB,EAAAA,CAAU,MAAO/iB,EAOrB,OALEW,EAKF,CANe,UAAf,EAAIoiB,CAAJ,EAAyC,QAAzC,EAA8BA,CAA9B,EAA6D,IAA7D,GAAqD/iB,CAArD,CACQA,CAAA4B,UADR,CACwBmhB,CADxB,CACkC,GADlC,CACwC,CAACD,CAAD,EAActhB,EAAd,GADxC,CAGQuhB,CAHR,CAGkB,GAHlB,CAGwB/iB,CAdO,CAuBjCgjB,QAASA,GAAO,CAAC/d,CAAD,CAAQge,CAAR,CAAqB,CACnC,GAAIA,CAAJ,CAAiB,CACf,IAAIxhB,EAAM,CACV,KAAAD,QAAA,CAAe0hB,QAAQ,EAAG,CACxB,MAAO,EAAEzhB,CADe,CAFX,CAMjBjB,CAAA,CAAQyE,CAAR,CAAe,IAAAke,IAAf,CAAyB,IAAzB,CAPmC,CAgHrCC,QAASA,GAAM,CAAClc,CAAD,CAAK,CAKlB,MAAA,CADImc,CACJ,CAFanc,CAAAzD,SAAA,EAAA4F,QAAAia,CAAsBC,EAAtBD,CAAsC,EAAtCA,CACFrd,MAAA,CAAaud,EAAb,CACX,EACS,WADT,CACuBna,CAACga,CAAA,CAAK,CAAL,CAADha,EAAY,EAAZA,SAAA,CAAwB,WAAxB,CAAqC,GAArC,CADvB,CACmE,GADnE,CAGO,IARW,CAkiBpBsC,QAASA,GAAc,CAAC8X,CAAD,CAAgBxY,CAAhB,CAA0B,CAuC/CyY,QAASA,EAAa,CAACC,CAAD,CAAW,CAC/B,MAAO,SAAQ,CAAChjB,CAAD,CAAMY,CAAN,CAAa,CAC1B,GAAIW,CAAA,CAASvB,CAAT,CAAJ,CACEH,CAAA,CAAQG,CAAR,CAAaU,EAAA,CAAcsiB,CAAd,CAAb,CADF,KAGE,OAAOA,EAAA,CAAShjB,CAAT,CAAcY,CAAd,CAJiB,CADG,CAUjC2O,QAASA,EAAQ,CAACrF,CAAD,CAAO+Y,CAAP,CAAkB,CACjC7U,EAAA,CAAwBlE,CAAxB,CAA8B,SAA9B,CACA,IAAIjK,CAAA,CAAWgjB,CAAX,CAAJ,EAA6BrjB,CAAA,CAAQqjB,CAAR,CAA7B,CACEA,CAAA,CAAYC,CAAAC,YAAA,CAA6BF,CAA7B,CAEd;GAAKrB,CAAAqB,CAAArB,KAAL,CACE,KAAM1S,GAAA,CAAgB,MAAhB,CAA2EhF,CAA3E,CAAN,CAEF,MAAOkZ,EAAA,CAAclZ,CAAd,CAtDYmZ,UAsDZ,CAAP,CAA8CJ,CARb,CAWnCK,QAASA,EAAkB,CAACpZ,CAAD,CAAO+E,CAAP,CAAgB,CACzC,MAAOsU,SAA4B,EAAG,CACpC,IAAIC,EAASC,CAAAxY,OAAA,CAAwBgE,CAAxB,CAAiC,IAAjC,CACb,IAAIjM,CAAA,CAAYwgB,CAAZ,CAAJ,CACE,KAAMtU,GAAA,CAAgB,OAAhB,CAAyFhF,CAAzF,CAAN,CAEF,MAAOsZ,EAL6B,CADG,CAU3CvU,QAASA,EAAO,CAAC/E,CAAD,CAAOwZ,CAAP,CAAkBC,CAAlB,CAA2B,CACzC,MAAOpU,EAAA,CAASrF,CAAT,CAAe,CACpB0X,KAAkB,CAAA,CAAZ,GAAA+B,CAAA,CAAoBL,CAAA,CAAmBpZ,CAAnB,CAAyBwZ,CAAzB,CAApB,CAA0DA,CAD5C,CAAf,CADkC,CAiC3CE,QAASA,EAAW,CAACd,CAAD,CAAgB,CAAA,IAC9B5S,EAAY,EADkB,CACd2T,CACpBhkB,EAAA,CAAQijB,CAAR,CAAuB,QAAQ,CAAC/Y,CAAD,CAAS,CAItC+Z,QAASA,EAAc,CAACpU,CAAD,CAAQ,CAAA,IACzBjP,CADyB,CACtBa,CACFb,EAAA,CAAI,CAAT,KAAYa,CAAZ,CAAiBoO,CAAAnQ,OAAjB,CAA+BkB,CAA/B,CAAmCa,CAAnC,CAAuCb,CAAA,EAAvC,CAA4C,CAAA,IACtCsjB,EAAarU,CAAA,CAAMjP,CAAN,CADyB,CAEtC8O,EAAW2T,CAAA/W,IAAA,CAAqB4X,CAAA,CAAW,CAAX,CAArB,CAEfxU,EAAA,CAASwU,CAAA,CAAW,CAAX,CAAT,CAAArd,MAAA,CAA8B6I,CAA9B,CAAwCwU,CAAA,CAAW,CAAX,CAAxC,CAJ0C,CAFf,CAH/B,GAAI,CAAAC,CAAA7X,IAAA,CAAkBpC,CAAlB,CAAJ,CAAA,CACAia,CAAAxB,IAAA,CAAkBzY,CAAlB,CAA0B,CAAA,CAA1B,CAYA,IAAI,CACEpK,CAAA,CAASoK,CAAT,CAAJ,EACE8Z,CAGA,CAHW1S,EAAA,CAAcpH,CAAd,CAGX,CAFAmG,CAEA,CAFYA,CAAAhK,OAAA,CAAiB0d,CAAA,CAAYC,CAAAzU,SAAZ,CAAjB,CAAAlJ,OAAA,CAAwD2d,CAAAxT,WAAxD,CAEZ,CADAyT,CAAA,CAAeD,CAAA1T,aAAf,CACA,CAAA2T,CAAA,CAAeD,CAAAzT,cAAf,CAJF,EAKWnQ,CAAA,CAAW8J,CAAX,CAAJ,CACHmG,CAAAhL,KAAA,CAAege,CAAAjY,OAAA,CAAwBlB,CAAxB,CAAf,CADG,CAEInK,CAAA,CAAQmK,CAAR,CAAJ;AACHmG,CAAAhL,KAAA,CAAege,CAAAjY,OAAA,CAAwBlB,CAAxB,CAAf,CADG,CAGLmE,EAAA,CAAYnE,CAAZ,CAAoB,QAApB,CAXA,CAaF,MAAO1B,CAAP,CAAU,CAYV,KAXIzI,EAAA,CAAQmK,CAAR,CAWE,GAVJA,CAUI,CAVKA,CAAA,CAAOA,CAAAxK,OAAP,CAAuB,CAAvB,CAUL,EARF8I,CAAA4b,QAQE,EARW5b,CAAA6b,MAQX,EARqD,EAQrD,EARsB7b,CAAA6b,MAAA1f,QAAA,CAAgB6D,CAAA4b,QAAhB,CAQtB,GAFJ5b,CAEI,CAFAA,CAAA4b,QAEA,CAFY,IAEZ,CAFmB5b,CAAA6b,MAEnB,EAAAhV,EAAA,CAAgB,UAAhB,CACInF,CADJ,CACY1B,CAAA6b,MADZ,EACuB7b,CAAA4b,QADvB,EACoC5b,CADpC,CAAN,CAZU,CA1BZ,CADsC,CAAxC,CA2CA,OAAO6H,EA7C2B,CAoDpCiU,QAASA,EAAsB,CAACC,CAAD,CAAQnV,CAAR,CAAiB,CAE9CoV,QAASA,EAAU,CAACC,CAAD,CAAcC,CAAd,CAAsB,CACvC,GAAIH,CAAAlkB,eAAA,CAAqBokB,CAArB,CAAJ,CAAuC,CACrC,GAAIF,CAAA,CAAME,CAAN,CAAJ,GAA2BE,CAA3B,CACE,KAAMtV,GAAA,CAAgB,MAAhB,CACIoV,CADJ,CACkB,MADlB,CAC2BhW,CAAAlF,KAAA,CAAU,MAAV,CAD3B,CAAN,CAGF,MAAOgb,EAAA,CAAME,CAAN,CAL8B,CAOrC,GAAI,CAGF,MAFAhW,EAAA1D,QAAA,CAAa0Z,CAAb,CAEO,CADPF,CAAA,CAAME,CAAN,CACO,CADcE,CACd,CAAAJ,CAAA,CAAME,CAAN,CAAA,CAAqBrV,CAAA,CAAQqV,CAAR,CAAqBC,CAArB,CAH1B,CAIF,MAAOE,CAAP,CAAY,CAIZ,KAHIL,EAAA,CAAME,CAAN,CAGEG,GAHqBD,CAGrBC,EAFJ,OAAOL,CAAA,CAAME,CAAN,CAEHG,CAAAA,CAAN,CAJY,CAJd,OASU,CACRnW,CAAAoW,MAAA,EADQ,CAjB2B,CAuBzCzZ,QAASA,EAAM,CAAC1E,CAAD,CAAKD,CAAL,CAAWqe,CAAX,CAAmBL,CAAnB,CAAgC,CACvB,QAAtB,GAAI,MAAOK,EAAX,GACEL,CACA,CADcK,CACd,CAAAA,CAAA,CAAS,IAFX,CAD6C,KAMzCjC,EAAO,EANkC,CAOzCkC,EAAU5Z,EAAA6Z,WAAA,CAA0Bte,CAA1B;AAA8B+D,CAA9B,CAAwCga,CAAxC,CAP+B,CAQzC/kB,CARyC,CAQjCkB,CARiC,CASzCT,CAECS,EAAA,CAAI,CAAT,KAAYlB,CAAZ,CAAqBqlB,CAAArlB,OAArB,CAAqCkB,CAArC,CAAyClB,CAAzC,CAAiDkB,CAAA,EAAjD,CAAsD,CACpDT,CAAA,CAAM4kB,CAAA,CAAQnkB,CAAR,CACN,IAAmB,QAAnB,GAAI,MAAOT,EAAX,CACE,KAAMkP,GAAA,CAAgB,MAAhB,CACyElP,CADzE,CAAN,CAGF0iB,CAAAxd,KAAA,CACEyf,CAAA,EAAUA,CAAAzkB,eAAA,CAAsBF,CAAtB,CAAV,CACE2kB,CAAA,CAAO3kB,CAAP,CADF,CAEEqkB,CAAA,CAAWrkB,CAAX,CAAgBskB,CAAhB,CAHJ,CANoD,CAYlD1kB,CAAA,CAAQ2G,CAAR,CAAJ,GACEA,CADF,CACOA,CAAA,CAAGhH,CAAH,CADP,CAMA,OAAOgH,EAAAG,MAAA,CAASJ,CAAT,CAAeoc,CAAf,CA7BsC,CA0C/C,MAAO,CACLzX,OAAQA,CADH,CAELkY,YAZFA,QAAoB,CAAC2B,CAAD,CAAOH,CAAP,CAAeL,CAAf,CAA4B,CAI9C,IAAIS,EAAWvlB,MAAAgD,OAAA,CAAcO,CAACnD,CAAA,CAAQklB,CAAR,CAAA,CAAgBA,CAAA,CAAKA,CAAAvlB,OAAL,CAAmB,CAAnB,CAAhB,CAAwCulB,CAAzC/hB,WAAd,EAA0E,IAA1E,CACXiiB,EAAAA,CAAgB/Z,CAAA,CAAO6Z,CAAP,CAAaC,CAAb,CAAuBJ,CAAvB,CAA+BL,CAA/B,CAEpB,OAAO/iB,EAAA,CAASyjB,CAAT,CAAA,EAA2B/kB,CAAA,CAAW+kB,CAAX,CAA3B,CAAuDA,CAAvD,CAAuED,CAPhC,CAUzC,CAGL5Y,IAAKkY,CAHA,CAILY,SAAUja,EAAA6Z,WAJL,CAKLK,IAAKA,QAAQ,CAAChb,CAAD,CAAO,CAClB,MAAOkZ,EAAAljB,eAAA,CAA6BgK,CAA7B,CAjOQmZ,UAiOR,CAAP,EAA8De,CAAAlkB,eAAA,CAAqBgK,CAArB,CAD5C,CALf,CAnEuC,CA1JhDI,CAAA,CAAyB,CAAA,CAAzB,GAAYA,CADmC,KAE3Cka,EAAgB,EAF2B,CAI3ClW,EAAO,EAJoC,CAK3C0V,EAAgB,IAAI3B,EAAJ,CAAY,EAAZ,CAAgB,CAAA,CAAhB,CAL2B,CAM3Ce,EAAgB,CACdvY,SAAU,CACN0E,SAAUwT,CAAA,CAAcxT,CAAd,CADJ,CAENN,QAAS8T,CAAA,CAAc9T,CAAd,CAFH,CAGNqB,QAASyS,CAAA,CAkEnBzS,QAAgB,CAACpG,CAAD;AAAO/E,CAAP,CAAoB,CAClC,MAAO8J,EAAA,CAAQ/E,CAAR,CAAc,CAAC,WAAD,CAAc,QAAQ,CAACib,CAAD,CAAY,CACrD,MAAOA,EAAAhC,YAAA,CAAsBhe,CAAtB,CAD8C,CAAlC,CAAd,CAD2B,CAlEjB,CAHH,CAINvE,MAAOmiB,CAAA,CAuEjBniB,QAAc,CAACsJ,CAAD,CAAOtD,CAAP,CAAY,CAAE,MAAOqI,EAAA,CAAQ/E,CAAR,CAActH,EAAA,CAAQgE,CAAR,CAAd,CAA4B,CAAA,CAA5B,CAAT,CAvET,CAJD,CAKN2J,SAAUwS,CAAA,CAwEpBxS,QAAiB,CAACrG,CAAD,CAAOtJ,CAAP,CAAc,CAC7BwN,EAAA,CAAwBlE,CAAxB,CAA8B,UAA9B,CACAkZ,EAAA,CAAclZ,CAAd,CAAA,CAAsBtJ,CACtBwkB,EAAA,CAAclb,CAAd,CAAA,CAAsBtJ,CAHO,CAxEX,CALJ,CAMN4P,UA6EVA,QAAkB,CAAC8T,CAAD,CAAce,CAAd,CAAuB,CAAA,IACnCC,EAAepC,CAAA/W,IAAA,CAAqBmY,CAArB,CAxFAjB,UAwFA,CADoB,CAEnCkC,EAAWD,CAAA1D,KAEf0D,EAAA1D,KAAA,CAAoB4D,QAAQ,EAAG,CAC7B,IAAIC,EAAehC,CAAAxY,OAAA,CAAwBsa,CAAxB,CAAkCD,CAAlC,CACnB,OAAO7B,EAAAxY,OAAA,CAAwBoa,CAAxB,CAAiC,IAAjC,CAAuC,CAACK,UAAWD,CAAZ,CAAvC,CAFsB,CAJQ,CAnFzB,CADI,CAN2B,CAgB3CvC,EAAoBE,CAAA+B,UAApBjC,CACIiB,CAAA,CAAuBf,CAAvB,CAAsC,QAAQ,CAACkB,CAAD,CAAcC,CAAd,CAAsB,CAC9D9Y,EAAA9L,SAAA,CAAiB4kB,CAAjB,CAAJ,EACEjW,CAAApJ,KAAA,CAAUqf,CAAV,CAEF,MAAMrV,GAAA,CAAgB,MAAhB,CAAiDZ,CAAAlF,KAAA,CAAU,MAAV,CAAjD,CAAN,CAJkE,CAApE,CAjBuC,CAuB3Cgc,EAAgB,EAvB2B,CAwB3C3B,EAAoB2B,CAAAD,UAApB1B,CACIU,CAAA,CAAuBiB,CAAvB,CAAsC,QAAQ,CAACd,CAAD,CAAcC,CAAd,CAAsB,CAClE,IAAIhV,EAAW2T,CAAA/W,IAAA,CAAqBmY,CAArB,CAvBJjB,UAuBI,CAAmDkB,CAAnD,CACf,OAAOd,EAAAxY,OAAA,CAAwBsE,CAAAqS,KAAxB,CAAuCrS,CAAvC,CAAiDrQ,CAAjD,CAA4DolB,CAA5D,CAF2D,CAApE,CAMRzkB,EAAA,CAAQ+jB,CAAA,CAAYd,CAAZ,CAAR;AAAoC,QAAQ,CAACvc,CAAD,CAAK,CAAMA,CAAJ,EAAQkd,CAAAxY,OAAA,CAAwB1E,CAAxB,CAAV,CAAjD,CAEA,OAAOkd,EAjCwC,CAoPjDzM,QAASA,GAAqB,EAAG,CAE/B,IAAI2O,EAAuB,CAAA,CAe3B,KAAAC,qBAAA,CAA4BC,QAAQ,EAAG,CACrCF,CAAA,CAAuB,CAAA,CADc,CAiJvC,KAAA/D,KAAA,CAAY,CAAC,SAAD,CAAY,WAAZ,CAAyB,YAAzB,CAAuC,QAAQ,CAACnH,CAAD,CAAU1B,CAAV,CAAqBM,CAArB,CAAiC,CAM1FyM,QAASA,EAAc,CAACC,CAAD,CAAO,CAC5B,IAAIvC,EAAS,IACbwC,MAAAjjB,UAAAkjB,KAAA9lB,KAAA,CAA0B4lB,CAA1B,CAAgC,QAAQ,CAAC5hB,CAAD,CAAU,CAChD,GAA2B,GAA3B,GAAID,EAAA,CAAUC,CAAV,CAAJ,CAEE,MADAqf,EACO,CADErf,CACF,CAAA,CAAA,CAHuC,CAAlD,CAMA,OAAOqf,EARqB,CAgC9B0C,QAASA,EAAQ,CAACxY,CAAD,CAAO,CACtB,GAAIA,CAAJ,CAAU,CACRA,CAAAyY,eAAA,EAEA,KAAI7K,CAvBFA,EAAAA,CAAS8K,CAAAC,QAETpmB,EAAA,CAAWqb,CAAX,CAAJ,CACEA,CADF,CACWA,CAAA,EADX,CAEW7X,EAAA,CAAU6X,CAAV,CAAJ,EACD5N,CAGF,CAHS4N,CAAA,CAAO,CAAP,CAGT,CAAAA,CAAA,CADqB,OAAvB,GADYb,CAAA6L,iBAAAlU,CAAyB1E,CAAzB0E,CACRmU,SAAJ,CACW,CADX,CAGW7Y,CAAA8Y,sBAAA,EAAAC,OANN,EAQKtjB,CAAA,CAASmY,CAAT,CARL,GASLA,CATK,CASI,CATJ,CAqBDA,EAAJ,GAcMoL,CACJ,CADchZ,CAAA8Y,sBAAA,EAAAG,IACd,CAAAlM,CAAAmM,SAAA,CAAiB,CAAjB,CAAoBF,CAApB,CAA8BpL,CAA9B,CAfF,CALQ,CAAV,IAuBEb,EAAAyL,SAAA,CAAiB,CAAjB;AAAoB,CAApB,CAxBoB,CA4BxBE,QAASA,EAAM,CAACS,CAAD,CAAO,CACpBA,CAAA,CAAOlnB,CAAA,CAASknB,CAAT,CAAA,CAAiBA,CAAjB,CAAwB9N,CAAA8N,KAAA,EAC/B,KAAIC,CAGCD,EAAL,CAGK,CAAKC,CAAL,CAAW7nB,CAAA8nB,eAAA,CAAwBF,CAAxB,CAAX,EAA2CX,CAAA,CAASY,CAAT,CAA3C,CAGA,CAAKA,CAAL,CAAWhB,CAAA,CAAe7mB,CAAA+nB,kBAAA,CAA2BH,CAA3B,CAAf,CAAX,EAA8DX,CAAA,CAASY,CAAT,CAA9D,CAGa,KAHb,GAGID,CAHJ,EAGoBX,CAAA,CAAS,IAAT,CATzB,CAAWA,CAAA,CAAS,IAAT,CALS,CAjEtB,IAAIjnB,EAAWwb,CAAAxb,SAoFX0mB,EAAJ,EACEtM,CAAA9V,OAAA,CAAkB0jB,QAAwB,EAAG,CAAC,MAAOlO,EAAA8N,KAAA,EAAR,CAA7C,CACEK,QAA8B,CAACC,CAAD,CAASC,CAAT,CAAiB,CAEzCD,CAAJ,GAAeC,CAAf,EAAoC,EAApC,GAAyBD,CAAzB,EAEAjH,EAAA,CAAqB,QAAQ,EAAG,CAC9B7G,CAAA/V,WAAA,CAAsB8iB,CAAtB,CAD8B,CAAhC,CAJ6C,CADjD,CAWF,OAAOA,EAjGmF,CAAhF,CAlKmB,CA2QjCiB,QAASA,GAAY,CAAC5V,CAAD,CAAG6V,CAAH,CAAM,CACzB,GAAK7V,CAAAA,CAAL,EAAW6V,CAAAA,CAAX,CAAc,MAAO,EACrB,IAAK7V,CAAAA,CAAL,CAAQ,MAAO6V,EACf,IAAKA,CAAAA,CAAL,CAAQ,MAAO7V,EACX7R,EAAA,CAAQ6R,CAAR,CAAJ,GAAgBA,CAAhB,CAAoBA,CAAArI,KAAA,CAAO,GAAP,CAApB,CACIxJ,EAAA,CAAQ0nB,CAAR,CAAJ,GAAgBA,CAAhB,CAAoBA,CAAAle,KAAA,CAAO,GAAP,CAApB,CACA,OAAOqI,EAAP,CAAW,GAAX,CAAiB6V,CANQ,CAkB3BC,QAASA,GAAY,CAACxF,CAAD,CAAU,CACzBpiB,CAAA,CAASoiB,CAAT,CAAJ,GACEA,CADF,CACYA,CAAA9d,MAAA,CAAc,GAAd,CADZ,CAMA,KAAI5E,EAAM4G,EAAA,EACVpG,EAAA,CAAQkiB,CAAR,CAAiB,QAAQ,CAACyF,CAAD,CAAQ,CAG3BA,CAAAjoB,OAAJ,GACEF,CAAA,CAAImoB,CAAJ,CADF,CACe,CAAA,CADf,CAH+B,CAAjC,CAOA,OAAOnoB,EAfsB,CAyB/BooB,QAASA,GAAqB,CAACC,CAAD,CAAU,CACtC,MAAOnmB,EAAA,CAASmmB,CAAT,CAAA;AACDA,CADC,CAED,EAHgC,CA+jBxCC,QAASA,GAAO,CAAC3oB,CAAD,CAASC,CAAT,CAAmBga,CAAnB,CAAyBc,CAAzB,CAAmC,CAsBjD6N,QAASA,EAA0B,CAACrhB,CAAD,CAAK,CACtC,GAAI,CACFA,CAAAG,MAAA,CAAS,IAAT,CAtqIG3E,EAAA5B,KAAA,CAsqIsB6B,SAtqItB,CAsqIiCyE,CAtqIjC,CAsqIH,CADE,CAAJ,OAEU,CAER,GADAohB,CAAA,EACI,CAA4B,CAA5B,GAAAA,CAAJ,CACE,IAAA,CAAOC,CAAAvoB,OAAP,CAAA,CACE,GAAI,CACFuoB,CAAAC,IAAA,EAAA,EADE,CAEF,MAAO1f,CAAP,CAAU,CACV4Q,CAAA+O,MAAA,CAAW3f,CAAX,CADU,CANR,CAH4B,CA6IxC4f,QAASA,EAA0B,EAAG,CACpCC,CAAA,EACAC,EAAA,EAFoC,CAetCD,QAASA,EAAU,EAAG,CAVK,CAAA,CAAA,CACzB,GAAI,CACF,CAAA,CAAOE,CAAAC,MAAP,OAAA,CADE,CAEF,MAAOhgB,CAAP,CAAU,EAHa,CAAA,CAAA,IAAA,EAAA,CAazBigB,CAAA,CAActlB,CAAA,CAAYslB,CAAZ,CAAA,CAA2B,IAA3B,CAAkCA,CAG5C3iB,GAAA,CAAO2iB,CAAP,CAAoBC,CAApB,CAAJ,GACED,CADF,CACgBC,CADhB,CAGAA,EAAA,CAAkBD,CATE,CAYtBH,QAASA,EAAa,EAAG,CACvB,GAAIK,CAAJ,GAAuBliB,CAAAmiB,IAAA,EAAvB,EAAqCC,CAArC,GAA0DJ,CAA1D,CAIAE,CAEA,CAFiBliB,CAAAmiB,IAAA,EAEjB,CADAC,CACA,CADmBJ,CACnB,CAAAzoB,CAAA,CAAQ8oB,CAAR,CAA4B,QAAQ,CAACC,CAAD,CAAW,CAC7CA,CAAA,CAAStiB,CAAAmiB,IAAA,EAAT,CAAqBH,CAArB,CAD6C,CAA/C,CAPuB,CA9LwB,IAC7ChiB,EAAO,IADsC,CAG7CyF,EAAW/M,CAAA+M,SAHkC,CAI7Cqc,EAAUppB,CAAAopB,QAJmC,CAK7C9H,EAAathB,CAAAshB,WALgC,CAM7CuI,EAAe7pB,CAAA6pB,aAN8B,CAO7CC,EAAkB,EAEtBxiB,EAAAyiB,OAAA,CAAc,CAAA,CAEd,KAAIlB,EAA0B,CAA9B,CACIC,EAA8B,EAGlCxhB,EAAA0iB,6BAAA,CAAoCpB,CACpCthB,EAAA2iB,6BAAA;AAAoCC,QAAQ,EAAG,CAAErB,CAAA,EAAF,CAkC/CvhB,EAAA6iB,gCAAA,CAAuCC,QAAQ,CAACC,CAAD,CAAW,CACxB,CAAhC,GAAIxB,CAAJ,CACEwB,CAAA,EADF,CAGEvB,CAAA5iB,KAAA,CAAiCmkB,CAAjC,CAJsD,CAlDT,KA8D7Cf,CA9D6C,CA8DhCI,CA9DgC,CA+D7CF,EAAiBzc,CAAAud,KA/D4B,CAgE7CC,EAActqB,CAAA6E,KAAA,CAAc,MAAd,CAhE+B,CAiE7C0lB,EAAiB,IAErBtB,EAAA,EACAQ,EAAA,CAAmBJ,CAsBnBhiB,EAAAmiB,IAAA,CAAWgB,QAAQ,CAAChB,CAAD,CAAM/f,CAAN,CAAe2f,CAAf,CAAsB,CAInCrlB,CAAA,CAAYqlB,CAAZ,CAAJ,GACEA,CADF,CACU,IADV,CAKItc,EAAJ,GAAiB/M,CAAA+M,SAAjB,GAAkCA,CAAlC,CAA6C/M,CAAA+M,SAA7C,CACIqc,EAAJ,GAAgBppB,CAAAopB,QAAhB,GAAgCA,CAAhC,CAA0CppB,CAAAopB,QAA1C,CAGA,IAAIK,CAAJ,CAAS,CACP,IAAIiB,EAAYhB,CAAZgB,GAAiCrB,CAKrC,IAAIG,CAAJ,GAAuBC,CAAvB,GAAgCL,CAAArO,CAAAqO,QAAhC,EAAoDsB,CAApD,EACE,MAAOpjB,EAET,KAAIqjB,EAAWnB,CAAXmB,EAA6BC,EAAA,CAAUpB,CAAV,CAA7BmB,GAA2DC,EAAA,CAAUnB,CAAV,CAC/DD,EAAA,CAAiBC,CACjBC,EAAA,CAAmBL,CAKnB,IAAID,CAAArO,CAAAqO,QAAJ,EAA0BuB,CAA1B,EAAuCD,CAAvC,CAKO,CACL,GAAKC,CAAAA,CAAL,EAAiBH,CAAjB,CACEA,CAAA,CAAiBf,CAEf/f,EAAJ,CACEqD,CAAArD,QAAA,CAAiB+f,CAAjB,CADF,CAEYkB,CAAL,EAGL5d,CAAA,CAAAA,CAAA,CA7FFxH,CA6FE,CAAwBkkB,CA7FlBjkB,QAAA,CAAY,GAAZ,CA6FN,CA5FN,CA4FM,CA5FY,EAAX,GAAAD,CAAA,CAAe,EAAf,CA4FuBkkB,CA5FHoB,OAAA,CAAWtlB,CAAX,CA4FrB,CAAAwH,CAAA8a,KAAA,CAAgB,CAHX,EACL9a,CAAAud,KADK,CACWb,CAPb,CALP,IACEL,EAAA,CAAQ1f,CAAA,CAAU,cAAV,CAA2B,WAAnC,CAAA,CAAgD2f,CAAhD,CAAuD,EAAvD,CAA2DI,CAA3D,CAGA,CAFAP,CAAA,EAEA,CAAAQ,CAAA,CAAmBJ,CAarB,OAAOhiB,EAjCA,CAuCP,MAAOkjB,EAAP;AAAyBzd,CAAAud,KAAA5gB,QAAA,CAAsB,MAAtB,CAA6B,GAA7B,CApDY,CAkEzCpC,EAAA+hB,MAAA,CAAayB,QAAQ,EAAG,CACtB,MAAOxB,EADe,CA5JyB,KAgK7CK,EAAqB,EAhKwB,CAiK7CoB,EAAgB,CAAA,CAjK6B,CAiL7CxB,EAAkB,IA8CtBjiB,EAAA0jB,YAAA,CAAmBC,QAAQ,CAACZ,CAAD,CAAW,CAEpC,GAAKU,CAAAA,CAAL,CAAoB,CAMlB,GAAIhQ,CAAAqO,QAAJ,CAAsBlgB,CAAA,CAAOlJ,CAAP,CAAAgO,GAAA,CAAkB,UAAlB,CAA8Bib,CAA9B,CAEtB/f,EAAA,CAAOlJ,CAAP,CAAAgO,GAAA,CAAkB,YAAlB,CAAgCib,CAAhC,CAEA8B,EAAA,CAAgB,CAAA,CAVE,CAapBpB,CAAAzjB,KAAA,CAAwBmkB,CAAxB,CACA,OAAOA,EAhB6B,CAyBtC/iB,EAAA4jB,uBAAA,CAA8BC,QAAQ,EAAG,CACvCjiB,CAAA,CAAOlJ,CAAP,CAAAorB,IAAA,CAAmB,qBAAnB,CAA0CnC,CAA1C,CADuC,CASzC3hB,EAAA+jB,iBAAA,CAAwBlC,CAexB7hB,EAAAgkB,SAAA,CAAgBC,QAAQ,EAAG,CACzB,IAAIjB,EAAOC,CAAA1lB,KAAA,CAAiB,MAAjB,CACX,OAAOylB,EAAA,CAAOA,CAAA5gB,QAAA,CAAa,wBAAb,CAAuC,EAAvC,CAAP,CAAoD,EAFlC,CAmB3BpC,EAAAkkB,MAAA,CAAaC,QAAQ,CAAClkB,CAAD,CAAKmkB,CAAL,CAAY,CAC/B,IAAIC,CACJ9C,EAAA,EACA8C,EAAA,CAAYrK,CAAA,CAAW,QAAQ,EAAG,CAChC,OAAOwI,CAAA,CAAgB6B,CAAhB,CACP/C,EAAA,CAA2BrhB,CAA3B,CAFgC,CAAtB,CAGTmkB,CAHS,EAGA,CAHA,CAIZ5B,EAAA,CAAgB6B,CAAhB,CAAA,CAA6B,CAAA,CAC7B,OAAOA,EARwB,CAsBjCrkB,EAAAkkB,MAAAI,OAAA,CAAoBC,QAAQ,CAACC,CAAD,CAAU,CACpC,MAAIhC,EAAA,CAAgBgC,CAAhB,CAAJ;CACE,OAAOhC,CAAA,CAAgBgC,CAAhB,CAGA,CAFPjC,CAAA,CAAaiC,CAAb,CAEO,CADPlD,CAAA,CAA2BnlB,CAA3B,CACO,CAAA,CAAA,CAJT,EAMO,CAAA,CAP6B,CAzTW,CAqUnD+U,QAASA,GAAgB,EAAG,CAC1B,IAAAoK,KAAA,CAAY,CAAC,SAAD,CAAY,MAAZ,CAAoB,UAApB,CAAgC,WAAhC,CACR,QAAQ,CAACnH,CAAD,CAAUxB,CAAV,CAAgBc,CAAhB,CAA0BlC,CAA1B,CAAqC,CAC3C,MAAO,KAAI8P,EAAJ,CAAYlN,CAAZ,CAAqB5C,CAArB,CAAgCoB,CAAhC,CAAsCc,CAAtC,CADoC,CADrC,CADc,CAwF5BrC,QAASA,GAAqB,EAAG,CAE/B,IAAAkK,KAAA,CAAYC,QAAQ,EAAG,CAGrBkJ,QAASA,EAAY,CAACC,CAAD,CAAUtD,CAAV,CAAmB,CAwMtCuD,QAASA,EAAO,CAACC,CAAD,CAAQ,CAClBA,CAAJ,EAAaC,CAAb,GACOC,CAAL,CAEWA,CAFX,EAEuBF,CAFvB,GAGEE,CAHF,CAGaF,CAAAG,EAHb,EACED,CADF,CACaF,CAQb,CAHAI,CAAA,CAAKJ,CAAAG,EAAL,CAAcH,CAAAK,EAAd,CAGA,CAFAD,CAAA,CAAKJ,CAAL,CAAYC,CAAZ,CAEA,CADAA,CACA,CADWD,CACX,CAAAC,CAAAE,EAAA,CAAa,IAVf,CADsB,CAmBxBC,QAASA,EAAI,CAACE,CAAD,CAAYC,CAAZ,CAAuB,CAC9BD,CAAJ,EAAiBC,CAAjB,GACMD,CACJ,GADeA,CAAAD,EACf,CAD6BE,CAC7B,EAAIA,CAAJ,GAAeA,CAAAJ,EAAf,CAA6BG,CAA7B,CAFF,CADkC,CA1NpC,GAAIR,CAAJ,GAAeU,EAAf,CACE,KAAMvsB,EAAA,CAAO,eAAP,CAAA,CAAwB,KAAxB,CAAkE6rB,CAAlE,CAAN,CAFoC,IAKlCW,EAAO,CAL2B,CAMlCC,EAAQ9pB,CAAA,CAAO,EAAP,CAAW4lB,CAAX,CAAoB,CAACmE,GAAIb,CAAL,CAApB,CAN0B,CAOlC1f,EAAO,EAP2B,CAQlCwgB,EAAYpE,CAAZoE,EAAuBpE,CAAAoE,SAAvBA,EAA4CC,MAAAC,UARV,CASlCC,EAAU,EATwB,CAUlCd,EAAW,IAVuB,CAWlCC,EAAW,IAyCf,OAAOM,EAAA,CAAOV,CAAP,CAAP,CAAyB,CAoBvBxI,IAAKA,QAAQ,CAACxiB,CAAD,CAAMY,CAAN,CAAa,CACxB,GAAI,CAAAoC,CAAA,CAAYpC,CAAZ,CAAJ,CAAA,CACA,GAAIkrB,CAAJ,CAAeC,MAAAC,UAAf,CAAiC,CAC/B,IAAIE;AAAWD,CAAA,CAAQjsB,CAAR,CAAXksB,GAA4BD,CAAA,CAAQjsB,CAAR,CAA5BksB,CAA2C,CAAClsB,IAAKA,CAAN,CAA3CksB,CAEJjB,EAAA,CAAQiB,CAAR,CAH+B,CAM3BlsB,CAAN,GAAasL,EAAb,EAAoBqgB,CAAA,EACpBrgB,EAAA,CAAKtL,CAAL,CAAA,CAAYY,CAER+qB,EAAJ,CAAWG,CAAX,EACE,IAAAK,OAAA,CAAYf,CAAAprB,IAAZ,CAGF,OAAOY,EAdP,CADwB,CApBH,CAiDvBuL,IAAKA,QAAQ,CAACnM,CAAD,CAAM,CACjB,GAAI8rB,CAAJ,CAAeC,MAAAC,UAAf,CAAiC,CAC/B,IAAIE,EAAWD,CAAA,CAAQjsB,CAAR,CAEf,IAAKksB,CAAAA,CAAL,CAAe,MAEfjB,EAAA,CAAQiB,CAAR,CAL+B,CAQjC,MAAO5gB,EAAA,CAAKtL,CAAL,CATU,CAjDI,CAwEvBmsB,OAAQA,QAAQ,CAACnsB,CAAD,CAAM,CACpB,GAAI8rB,CAAJ,CAAeC,MAAAC,UAAf,CAAiC,CAC/B,IAAIE,EAAWD,CAAA,CAAQjsB,CAAR,CAEf,IAAKksB,CAAAA,CAAL,CAAe,MAEXA,EAAJ,EAAgBf,CAAhB,GAA0BA,CAA1B,CAAqCe,CAAAX,EAArC,CACIW,EAAJ,EAAgBd,CAAhB,GAA0BA,CAA1B,CAAqCc,CAAAb,EAArC,CACAC,EAAA,CAAKY,CAAAb,EAAL,CAAgBa,CAAAX,EAAhB,CAEA,QAAOU,CAAA,CAAQjsB,CAAR,CATwB,CAYjC,OAAOsL,CAAA,CAAKtL,CAAL,CACP2rB,EAAA,EAdoB,CAxEC,CAkGvBS,UAAWA,QAAQ,EAAG,CACpB9gB,CAAA,CAAO,EACPqgB,EAAA,CAAO,CACPM,EAAA,CAAU,EACVd,EAAA,CAAWC,CAAX,CAAsB,IAJF,CAlGC,CAmHvBiB,QAASA,QAAQ,EAAG,CAGlBJ,CAAA,CADAL,CACA,CAFAtgB,CAEA,CAFO,IAGP,QAAOogB,CAAA,CAAOV,CAAP,CAJW,CAnHG,CA2IvBsB,KAAMA,QAAQ,EAAG,CACf,MAAOxqB,EAAA,CAAO,EAAP,CAAW8pB,CAAX,CAAkB,CAACD,KAAMA,CAAP,CAAlB,CADQ,CA3IM,CApDa,CAFxC,IAAID,EAAS,EA+ObX,EAAAuB,KAAA,CAAoBC,QAAQ,EAAG,CAC7B,IAAID,EAAO,EACXzsB,EAAA,CAAQ6rB,CAAR,CAAgB,QAAQ,CAACtH,CAAD,CAAQ4G,CAAR,CAAiB,CACvCsB,CAAA,CAAKtB,CAAL,CAAA,CAAgB5G,CAAAkI,KAAA,EADuB,CAAzC,CAGA,OAAOA,EALsB,CAmB/BvB;CAAA5e,IAAA,CAAmBqgB,QAAQ,CAACxB,CAAD,CAAU,CACnC,MAAOU,EAAA,CAAOV,CAAP,CAD4B,CAKrC,OAAOD,EAxQc,CAFQ,CAyTjC7Q,QAASA,GAAsB,EAAG,CAChC,IAAA0H,KAAA,CAAY,CAAC,eAAD,CAAkB,QAAQ,CAACnK,CAAD,CAAgB,CACpD,MAAOA,EAAA,CAAc,WAAd,CAD6C,CAA1C,CADoB,CAwtBlCjG,QAASA,GAAgB,CAAC3G,CAAD,CAAW4hB,CAAX,CAAkC,CAazDC,QAASA,EAAoB,CAACvhB,CAAD,CAAQwhB,CAAR,CAAuBC,CAAvB,CAAqC,CAChE,IAAIC,EAAe,oCAAnB,CAEIC,EAAW,EAEfjtB,EAAA,CAAQsL,CAAR,CAAe,QAAQ,CAAC4hB,CAAD,CAAaC,CAAb,CAAwB,CAC7C,IAAI1nB,EAAQynB,CAAAznB,MAAA,CAAiBunB,CAAjB,CAEZ,IAAKvnB,CAAAA,CAAL,CACE,KAAM2nB,GAAA,CAAe,MAAf,CAGFN,CAHE,CAGaK,CAHb,CAGwBD,CAHxB,CAIDH,CAAA,CAAe,gCAAf,CACD,0BALE,CAAN,CAQFE,CAAA,CAASE,CAAT,CAAA,CAAsB,CACpBE,KAAM5nB,CAAA,CAAM,CAAN,CAAA,CAAS,CAAT,CADc,CAEpB6nB,WAAyB,GAAzBA,GAAY7nB,CAAA,CAAM,CAAN,CAFQ,CAGpB8nB,SAAuB,GAAvBA,GAAU9nB,CAAA,CAAM,CAAN,CAHU,CAIpB+nB,SAAU/nB,CAAA,CAAM,CAAN,CAAV+nB,EAAsBL,CAJF,CAZuB,CAA/C,CAoBA,OAAOF,EAzByD,CAiElEQ,QAASA,EAAwB,CAACpjB,CAAD,CAAO,CACtC,IAAIqC,EAASrC,CAAAxE,OAAA,CAAY,CAAZ,CACb,IAAK6G,CAAAA,CAAL,EAAeA,CAAf,GAA0BnI,CAAA,CAAUmI,CAAV,CAA1B,CACE,KAAM0gB,GAAA,CAAe,QAAf,CAA4G/iB,CAA5G,CAAN,CAEF,GAAIA,CAAJ,GAAaA,CAAA6S,KAAA,EAAb,CACE,KAAMkQ,GAAA,CAAe,QAAf;AAEA/iB,CAFA,CAAN,CANoC,CA9EiB,IACrDqjB,EAAgB,EADqC,CAGrDC,EAA2B,qCAH0B,CAIrDC,EAAyB,6BAJ4B,CAKrDC,EAAuB3pB,EAAA,CAAQ,2BAAR,CAL8B,CAMrD4pB,EAAwB,6BAN6B,CAWrDC,EAA4B,yBA8F/B,KAAAjd,UAAA,CAAiBkd,QAASC,EAAiB,CAAC5jB,CAAD,CAAO6jB,CAAP,CAAyB,CACnE3f,EAAA,CAAwBlE,CAAxB,CAA8B,WAA9B,CACIvK,EAAA,CAASuK,CAAT,CAAJ,EACEojB,CAAA,CAAyBpjB,CAAzB,CAkCA,CAjCA6D,EAAA,CAAUggB,CAAV,CAA4B,kBAA5B,CAiCA,CAhCKR,CAAArtB,eAAA,CAA6BgK,CAA7B,CAgCL,GA/BEqjB,CAAA,CAAcrjB,CAAd,CACA,CADsB,EACtB,CAAAW,CAAAoE,QAAA,CAAiB/E,CAAjB,CA9GO8jB,WA8GP,CAAgC,CAAC,WAAD,CAAc,mBAAd,CAC9B,QAAQ,CAAC7I,CAAD,CAAYpN,CAAZ,CAA+B,CACrC,IAAIkW,EAAa,EACjBpuB,EAAA,CAAQ0tB,CAAA,CAAcrjB,CAAd,CAAR,CAA6B,QAAQ,CAAC6jB,CAAD,CAAmBxpB,CAAnB,CAA0B,CAC7D,GAAI,CACF,IAAIoM,EAAYwU,CAAAla,OAAA,CAAiB8iB,CAAjB,CACZ9tB,EAAA,CAAW0Q,CAAX,CAAJ,CACEA,CADF,CACc,CAAEvF,QAASxI,EAAA,CAAQ+N,CAAR,CAAX,CADd,CAEYvF,CAAAuF,CAAAvF,QAFZ,EAEiCuF,CAAA2a,KAFjC,GAGE3a,CAAAvF,QAHF,CAGsBxI,EAAA,CAAQ+N,CAAA2a,KAAR,CAHtB,CAKA3a,EAAAud,SAAA,CAAqBvd,CAAAud,SAArB;AAA2C,CAC3Cvd,EAAApM,MAAA,CAAkBA,CAClBoM,EAAAzG,KAAA,CAAiByG,CAAAzG,KAAjB,EAAmCA,CACnCyG,EAAAwd,QAAA,CAAoBxd,CAAAwd,QAApB,EAA0Cxd,CAAAxD,WAA1C,EAAkEwD,CAAAzG,KAClEyG,EAAAyd,SAAA,CAAqBzd,CAAAyd,SAArB,EAA2C,IAC5Bzd,KAAAA,EAAAA,CAAAA,CACYA,EAAAA,CADZA,CACuBzG,EAAAyG,CAAAzG,KADvByG,CAtFvBmc,EAAW,CACb5f,aAAc,IADD,CAEbmhB,iBAAkB,IAFL,CAIX9sB,EAAA,CAASoP,CAAAxF,MAAT,CAAJ,GACqC,CAAA,CAAnC,GAAIwF,CAAA0d,iBAAJ,EACEvB,CAAAuB,iBAEA,CAF4B3B,CAAA,CAAqB/b,CAAAxF,MAArB,CACqBwhB,CADrB,CACoC,CAAA,CADpC,CAE5B,CAAAG,CAAA5f,aAAA,CAAwB,EAH1B,EAKE4f,CAAA5f,aALF,CAK0Bwf,CAAA,CAAqB/b,CAAAxF,MAArB,CACqBwhB,CADrB,CACoC,CAAA,CADpC,CAN5B,CAUIprB,EAAA,CAASoP,CAAA0d,iBAAT,CAAJ,GACEvB,CAAAuB,iBADF,CAEM3B,CAAA,CAAqB/b,CAAA0d,iBAArB,CAAiD1B,CAAjD,CAAgE,CAAA,CAAhE,CAFN,CAIA,IAAIprB,CAAA,CAASurB,CAAAuB,iBAAT,CAAJ,CAAyC,CACvC,IAAIlhB,EAAawD,CAAAxD,WAAjB,CACImhB,EAAe3d,CAAA2d,aACnB,IAAKnhB,CAAAA,CAAL,CAEE,KAAM8f,GAAA,CAAe,QAAf,CAEAN,CAFA,CAAN,CAGU,IAAA,EAw7DkC,EAAA,CAClD,GAz7DoD2B,CAy7DpD,EAAa3uB,CAAA,CAz7DuC2uB,CAy7DvC,CAAb,CAA8B,EAAA,CAz7DsBA,CAy7DpD,KAAA,CACA,GAAI3uB,CAAA,CA17DoCwN,CA07DpC,CAAJ,CAA0B,CACxB,IAAI7H,EAAQipB,EAAApS,KAAA,CA37D0BhP,CA27D1B,CACZ;GAAI7H,CAAJ,CAAW,CAAA,EAAA,CAAOA,CAAA,CAAM,CAAN,CAAP,OAAA,CAAA,CAFa,CAFwB,EAAA,CAAA,IAAA,EAClD,CAz7DW,GAAK,CAAA,EAAL,CAEL,KAAM2nB,GAAA,CAAe,SAAf,CAEAN,CAFA,CAAN,CAVqC,CAoE7B,IAAIG,EAAWnc,CAAA6d,WAAX1B,CArDTA,CAuDSvrB,EAAA,CAASurB,CAAA5f,aAAT,CAAJ,GACEyD,CAAA8d,kBADF,CACgC3B,CAAA5f,aADhC,CAGAyD,EAAAX,aAAA,CAAyB+d,CAAA/d,aACzBie,EAAA/oB,KAAA,CAAgByL,CAAhB,CAlBE,CAmBF,MAAOtI,CAAP,CAAU,CACV0P,CAAA,CAAkB1P,CAAlB,CADU,CApBiD,CAA/D,CAwBA,OAAO4lB,EA1B8B,CADT,CAAhC,CA8BF,EAAAV,CAAA,CAAcrjB,CAAd,CAAAhF,KAAA,CAAyB6oB,CAAzB,CAnCF,EAqCEluB,CAAA,CAAQqK,CAAR,CAAcxJ,EAAA,CAAcotB,CAAd,CAAd,CAEF,OAAO,KAzC4D,CAiErE,KAAAY,2BAAA,CAAkCC,QAAQ,CAACC,CAAD,CAAS,CACjD,MAAI3rB,EAAA,CAAU2rB,CAAV,CAAJ,EACEnC,CAAAiC,2BAAA,CAAiDE,CAAjD,CACO,CAAA,IAFT,EAISnC,CAAAiC,2BAAA,EALwC,CA8BnD,KAAAG,4BAAA,CAAmCC,QAAQ,CAACF,CAAD,CAAS,CAClD,MAAI3rB,EAAA,CAAU2rB,CAAV,CAAJ,EACEnC,CAAAoC,4BAAA,CAAkDD,CAAlD,CACO,CAAA,IAFT,EAISnC,CAAAoC,4BAAA,EALyC,CA+BpD;IAAI/jB,EAAmB,CAAA,CACvB,KAAAA,iBAAA,CAAwBikB,QAAQ,CAACC,CAAD,CAAU,CACxC,MAAI/rB,EAAA,CAAU+rB,CAAV,CAAJ,EACElkB,CACO,CADYkkB,CACZ,CAAA,IAFT,EAIOlkB,CALiC,CAQ1C,KAAA8W,KAAA,CAAY,CACF,WADE,CACW,cADX,CAC2B,mBAD3B,CACgD,kBADhD,CACoE,QADpE,CAEF,aAFE,CAEa,YAFb,CAE2B,WAF3B,CAEwC,MAFxC,CAEgD,UAFhD,CAE4D,eAF5D,CAGV,QAAQ,CAACuD,CAAD,CAAchN,CAAd,CAA8BJ,CAA9B,CAAmDoC,CAAnD,CAAuEhB,CAAvE,CACCxB,CADD,CACgB0B,CADhB,CAC8BxB,CAD9B,CAC2C8B,CAD3C,CACmD1C,CADnD,CAC+D3F,CAD/D,CAC8E,CA2OtF2d,QAASA,EAAY,CAACC,CAAD,CAAWC,CAAX,CAAsB,CACzC,GAAI,CACFD,CAAAlN,SAAA,CAAkBmN,CAAlB,CADE,CAEF,MAAO9mB,CAAP,CAAU,EAH6B,CAgD3C+C,QAASA,EAAO,CAACgkB,CAAD,CAAgBC,CAAhB,CAA8BC,CAA9B,CAA2CC,CAA3C,CACIC,CADJ,CAC4B,CACpCJ,CAAN,WAA+BlnB,EAA/B,GAGEknB,CAHF,CAGkBlnB,CAAA,CAAOknB,CAAP,CAHlB,CAOAvvB,EAAA,CAAQuvB,CAAR,CAAuB,QAAQ,CAAC1rB,CAAD,CAAOa,CAAP,CAAc,CACvCb,CAAAjE,SAAJ,EAAqBgJ,EAArB,EAAuC/E,CAAA+rB,UAAAnqB,MAAA,CAAqB,KAArB,CAAvC,GACE8pB,CAAA,CAAc7qB,CAAd,CADF,CACyB2D,CAAA,CAAOxE,CAAP,CAAA0Y,KAAA,CAAkB,eAAlB,CAAA9Z,OAAA,EAAA,CAA4C,CAA5C,CADzB,CAD2C,CAA7C,CAKA,KAAIotB,EACIC,CAAA,CAAaP,CAAb,CAA4BC,CAA5B,CAA0CD,CAA1C,CACaE,CADb,CAC0BC,CAD1B,CAC2CC,CAD3C,CAERpkB,EAAAwkB,gBAAA,CAAwBR,CAAxB,CACA;IAAIS,EAAY,IAChB,OAAOC,SAAqB,CAAC3kB,CAAD,CAAQ4kB,CAAR,CAAwBrI,CAAxB,CAAiC,CAC3D3Z,EAAA,CAAU5C,CAAV,CAAiB,OAAjB,CAEAuc,EAAA,CAAUA,CAAV,EAAqB,EAHsC,KAIvDsI,EAA0BtI,CAAAsI,wBAJ6B,CAKzDC,EAAwBvI,CAAAuI,sBACxBC,EAAAA,CAAsBxI,CAAAwI,oBAMpBF,EAAJ,EAA+BA,CAAAG,kBAA/B,GACEH,CADF,CAC4BA,CAAAG,kBAD5B,CAIKN,EAAL,GAyCA,CAzCA,CAsCF,CADInsB,CACJ,CArCgDwsB,CAqChD,EArCgDA,CAoCpB,CAAc,CAAd,CAC5B,EAG6B,eAApB,GAAAhsB,EAAA,CAAUR,CAAV,CAAA,EAAuCA,CAAAZ,SAAA,EAAAwC,MAAA,CAAsB,KAAtB,CAAvC,CAAsE,KAAtE,CAA8E,MAHvF,CACS,MAvCP,CAUE8qB,EAAA,CANgB,MAAlB,GAAIP,CAAJ,CAMc3nB,CAAA,CACVmoB,EAAA,CAAaR,CAAb,CAAwB3nB,CAAA,CAAO,OAAP,CAAAK,OAAA,CAAuB6mB,CAAvB,CAAA5mB,KAAA,EAAxB,CADU,CANd,CASWunB,CAAJ,CAGO9iB,EAAA9E,MAAAhI,KAAA,CAA2BivB,CAA3B,CAHP,CAKOA,CAGd,IAAIa,CAAJ,CACE,IAASK,IAAAA,CAAT,GAA2BL,EAA3B,CACEG,CAAA9kB,KAAA,CAAe,GAAf,CAAqBglB,CAArB,CAAsC,YAAtC,CAAoDL,CAAA,CAAsBK,CAAtB,CAAAvL,SAApD,CAIJ3Z,EAAAmlB,eAAA,CAAuBH,CAAvB,CAAkCjlB,CAAlC,CAEI4kB,EAAJ,EAAoBA,CAAA,CAAeK,CAAf,CAA0BjlB,CAA1B,CAChBukB,EAAJ,EAAqBA,CAAA,CAAgBvkB,CAAhB,CAAuBilB,CAAvB,CAAkCA,CAAlC,CAA6CJ,CAA7C,CACrB,OAAOI,EA/CoD,CAlBnB,CA8F5CT,QAASA,EAAY,CAACa,CAAD,CAAWnB,CAAX,CAAyBoB,CAAzB,CAAuCnB,CAAvC,CAAoDC,CAApD,CACGC,CADH,CAC2B,CA0C9CE,QAASA,EAAe,CAACvkB,CAAD;AAAQqlB,CAAR,CAAkBC,CAAlB,CAAgCT,CAAhC,CAAyD,CAAA,IAC/DU,CAD+D,CAClDhtB,CADkD,CAC5CitB,CAD4C,CAChClwB,CADgC,CAC7Ba,CAD6B,CACpBsvB,CADoB,CAE3EC,CAGJ,IAAIC,CAAJ,CAOE,IAHAD,CAGK,CAHgB7K,KAAJ,CADIwK,CAAAjxB,OACJ,CAGZ,CAAAkB,CAAA,CAAI,CAAT,CAAYA,CAAZ,CAAgBswB,CAAAxxB,OAAhB,CAAgCkB,CAAhC,EAAmC,CAAnC,CACEuwB,CACA,CADMD,CAAA,CAAQtwB,CAAR,CACN,CAAAowB,CAAA,CAAeG,CAAf,CAAA,CAAsBR,CAAA,CAASQ,CAAT,CAT1B,KAYEH,EAAA,CAAiBL,CAGd/vB,EAAA,CAAI,CAAT,KAAYa,CAAZ,CAAiByvB,CAAAxxB,OAAjB,CAAiCkB,CAAjC,CAAqCa,CAArC,CAAA,CAKE,GAJAoC,CAIIutB,CAJGJ,CAAA,CAAeE,CAAA,CAAQtwB,CAAA,EAAR,CAAf,CAIHwwB,CAHJA,CAGIA,CAHSF,CAAA,CAAQtwB,CAAA,EAAR,CAGTwwB,CAFJP,CAEIO,CAFUF,CAAA,CAAQtwB,CAAA,EAAR,CAEVwwB,CAAAA,CAAJ,CAAgB,CACd,GAAIA,CAAA9lB,MAAJ,CAIE,IAHAwlB,CAEIO,CAFS/lB,CAAAgmB,KAAA,EAETD,CADJ9lB,CAAAmlB,eAAA,CAAuBroB,CAAA,CAAOxE,CAAP,CAAvB,CAAqCitB,CAArC,CACIO,CAAAA,CAAAA,CAAkBD,CAAAG,kBACtB,CACEH,CAAAG,kBACA,CAD+B,IAC/B,CAAAT,CAAAU,IAAA,CAAe,YAAf,CAA6BH,CAA7B,CAFF,CAJF,IASEP,EAAA,CAAaxlB,CAIbylB,EAAA,CADEK,CAAAK,wBAAJ,CAC2BC,CAAA,CACrBpmB,CADqB,CACd8lB,CAAAO,WADc,CACSxB,CADT,CAD3B,CAIYyB,CAAAR,CAAAQ,sBAAL,EAAyCzB,CAAzC,CACoBA,CADpB,CAGKA,CAAAA,CAAL,EAAgCX,CAAhC,CACoBkC,CAAA,CAAwBpmB,CAAxB,CAA+BkkB,CAA/B,CADpB,CAIoB,IAG3B4B,EAAA,CAAWP,CAAX,CAAwBC,CAAxB,CAAoCjtB,CAApC,CAA0C+sB,CAA1C,CAAwDG,CAAxD,CACWK,CADX,CA3Bc,CAAhB,IA8BWP,EAAJ,EACLA,CAAA,CAAYvlB,CAAZ,CAAmBzH,CAAAgZ,WAAnB,CAAoCxd,CAApC,CAA+C8wB,CAA/C,CAxD2E,CAtCjF,IAJ8C,IAC1Ce,EAAU,EADgC,CAE1CW,CAF0C,CAEnCzD,CAFmC,CAEXvR,CAFW,CAEciV,CAFd,CAE2Bb,CAF3B,CAIrCrwB,EAAI,CAAb,CAAgBA,CAAhB,CAAoB+vB,CAAAjxB,OAApB,CAAqCkB,CAAA,EAArC,CAA0C,CACxCixB,CAAA,CAAQ,IAAIE,EAGZ3D,EAAA,CAAa4D,EAAA,CAAkBrB,CAAA,CAAS/vB,CAAT,CAAlB,CAA+B,EAA/B,CAAmCixB,CAAnC,CAAgD,CAAN,GAAAjxB,CAAA;AAAU6uB,CAAV,CAAwBpwB,CAAlE,CACmBqwB,CADnB,CAQb,EALA0B,CAKA,CALchD,CAAA1uB,OAAD,CACPuyB,CAAA,CAAsB7D,CAAtB,CAAkCuC,CAAA,CAAS/vB,CAAT,CAAlC,CAA+CixB,CAA/C,CAAsDrC,CAAtD,CAAoEoB,CAApE,CACwB,IADxB,CAC8B,EAD9B,CACkC,EADlC,CACsCjB,CADtC,CADO,CAGP,IAEN,GAAkByB,CAAA9lB,MAAlB,EACEC,CAAAwkB,gBAAA,CAAwB8B,CAAAK,UAAxB,CAGFrB,EAAA,CAAeO,CAAD,EAAeA,CAAAe,SAAf,EACE,EAAAtV,CAAA,CAAa8T,CAAA,CAAS/vB,CAAT,CAAAic,WAAb,CADF,EAECnd,CAAAmd,CAAAnd,OAFD,CAGR,IAHQ,CAIRowB,CAAA,CAAajT,CAAb,CACGuU,CAAA,EACEA,CAAAK,wBADF,EACwC,CAACL,CAAAQ,sBADzC,GAEOR,CAAAO,WAFP,CAEgCnC,CAHnC,CAKN,IAAI4B,CAAJ,EAAkBP,CAAlB,CACEK,CAAA7rB,KAAA,CAAazE,CAAb,CAAgBwwB,CAAhB,CAA4BP,CAA5B,CAEA,CADAiB,CACA,CADc,CAAA,CACd,CAAAb,CAAA,CAAkBA,CAAlB,EAAqCG,CAIvCzB,EAAA,CAAyB,IAhCe,CAoC1C,MAAOmC,EAAA,CAAcjC,CAAd,CAAgC,IAxCO,CAwGhD6B,QAASA,EAAuB,CAACpmB,CAAD,CAAQkkB,CAAR,CAAsB4C,CAAtB,CAAiD,CAgB/E,MAdwBC,SAAQ,CAACC,CAAD,CAAmBC,CAAnB,CAA4BC,CAA5B,CAAyCnC,CAAzC,CAA8DoC,CAA9D,CAA+E,CAExGH,CAAL,GACEA,CACA,CADmBhnB,CAAAgmB,KAAA,CAAW,CAAA,CAAX,CAAkBmB,CAAlB,CACnB,CAAAH,CAAAI,cAAA,CAAiC,CAAA,CAFnC,CAKA,OAAOlD,EAAA,CAAa8C,CAAb,CAA+BC,CAA/B,CAAwC,CAC7CpC,wBAAyBiC,CADoB,CAE7ChC,sBAAuBoC,CAFsB,CAG7CnC,oBAAqBA,CAHwB,CAAxC,CAPsG,CAFhC,CA6BjF2B,QAASA,GAAiB,CAACnuB,CAAD,CAAOuqB,CAAP,CAAmByD,CAAnB,CAA0BpC,CAA1B,CAAuCC,CAAvC,CAAwD,CAAA,IAE5EiD,EAAWd,CAAAe,MAFiE,CAG5EntB,CAGJ,QALe5B,CAAAjE,SAKf,EACE,KAAKC,EAAL,CAEEgzB,CAAA,CAAazE,CAAb;AACI0E,EAAA,CAAmBzuB,EAAA,CAAUR,CAAV,CAAnB,CADJ,CACyC,GADzC,CAC8C4rB,CAD9C,CAC2DC,CAD3D,CAIA,KANF,IAMW1rB,CANX,CAM0CjD,CAN1C,CAMiDgyB,CANjD,CAM2DC,EAASnvB,CAAAovB,WANpE,CAOWtxB,EAAI,CAPf,CAOkBC,EAAKoxB,CAALpxB,EAAeoxB,CAAAtzB,OAD/B,CAC8CiC,CAD9C,CACkDC,CADlD,CACsDD,CAAA,EADtD,CAC2D,CACzD,IAAIuxB,EAAgB,CAAA,CAApB,CACIC,EAAc,CAAA,CAElBnvB,EAAA,CAAOgvB,CAAA,CAAOrxB,CAAP,CACP0I,EAAA,CAAOrG,CAAAqG,KACPtJ,EAAA,CAAQmc,CAAA,CAAKlZ,CAAAjD,MAAL,CAGRqyB,EAAA,CAAaN,EAAA,CAAmBzoB,CAAnB,CACb,IAAI0oB,CAAJ,CAAeM,EAAAjuB,KAAA,CAAqBguB,CAArB,CAAf,CACE/oB,CAAA,CAAOA,CAAAxB,QAAA,CAAayqB,EAAb,CAA4B,EAA5B,CAAAtJ,OAAA,CACG,CADH,CAAAnhB,QAAA,CACc,OADd,CACuB,QAAQ,CAACpD,CAAD,CAAQiH,CAAR,CAAgB,CAClD,MAAOA,EAAAgP,YAAA,EAD2C,CAD/C,CAMT,KAAI6X,EAAiBH,CAAAvqB,QAAA,CAAmB,cAAnB,CAAmC,EAAnC,CACjB2qB,EAAA,CAAwBD,CAAxB,CAAJ,EACMH,CADN,GACqBG,CADrB,CACsC,OADtC,GAEIL,CAEA,CAFgB7oB,CAEhB,CADA8oB,CACA,CADc9oB,CAAA2f,OAAA,CAAY,CAAZ,CAAe3f,CAAA3K,OAAf,CAA6B,CAA7B,CACd,CADgD,KAChD,CAAA2K,CAAA,CAAOA,CAAA2f,OAAA,CAAY,CAAZ,CAAe3f,CAAA3K,OAAf,CAA6B,CAA7B,CAJX,CAQA+zB,EAAA,CAAQX,EAAA,CAAmBzoB,CAAAuC,YAAA,EAAnB,CACR+lB,EAAA,CAASc,CAAT,CAAA,CAAkBppB,CAClB,IAAI0oB,CAAJ,EAAiB,CAAAlB,CAAAxxB,eAAA,CAAqBozB,CAArB,CAAjB,CACI5B,CAAA,CAAM4B,CAAN,CACA,CADe1yB,CACf,CAAI2f,EAAA,CAAmB7c,CAAnB,CAAyB4vB,CAAzB,CAAJ,GACE5B,CAAA,CAAM4B,CAAN,CADF,CACiB,CAAA,CADjB,CAIJC,EAAA,CAA4B7vB,CAA5B,CAAkCuqB,CAAlC,CAA8CrtB,CAA9C,CAAqD0yB,CAArD,CAA4DV,CAA5D,CACAF,EAAA,CAAazE,CAAb,CAAyBqF,CAAzB,CAAgC,GAAhC,CAAqChE,CAArC,CAAkDC,CAAlD,CAAmEwD,CAAnE,CACcC,CADd,CAnCyD,CAwC3D7D,CAAA,CAAYzrB,CAAAyrB,UACR5tB,EAAA,CAAS4tB,CAAT,CAAJ,GAEIA,CAFJ,CAEgBA,CAAAqE,QAFhB,CAIA,IAAI7zB,CAAA,CAASwvB,CAAT,CAAJ;AAAyC,EAAzC,GAA2BA,CAA3B,CACE,IAAA,CAAO7pB,CAAP,CAAemoB,CAAAtR,KAAA,CAA4BgT,CAA5B,CAAf,CAAA,CACEmE,CAIA,CAJQX,EAAA,CAAmBrtB,CAAA,CAAM,CAAN,CAAnB,CAIR,CAHIotB,CAAA,CAAazE,CAAb,CAAyBqF,CAAzB,CAAgC,GAAhC,CAAqChE,CAArC,CAAkDC,CAAlD,CAGJ,GAFEmC,CAAA,CAAM4B,CAAN,CAEF,CAFiBvW,CAAA,CAAKzX,CAAA,CAAM,CAAN,CAAL,CAEjB,EAAA6pB,CAAA,CAAYA,CAAAtF,OAAA,CAAiBvkB,CAAAf,MAAjB,CAA+Be,CAAA,CAAM,CAAN,CAAA/F,OAA/B,CAGhB,MACF,MAAKkJ,EAAL,CACE,GAAa,EAAb,GAAIgrB,EAAJ,CAEE,IAAA,CAAO/vB,CAAAic,WAAP,EAA0Bjc,CAAAoL,YAA1B,EAA8CpL,CAAAoL,YAAArP,SAA9C,GAA4EgJ,EAA5E,CAAA,CACE/E,CAAA+rB,UACA,EADkC/rB,CAAAoL,YAAA2gB,UAClC,CAAA/rB,CAAAic,WAAAI,YAAA,CAA4Brc,CAAAoL,YAA5B,CAGJ4kB,GAAA,CAA4BzF,CAA5B,CAAwCvqB,CAAA+rB,UAAxC,CACA,MACF,MApqLgBkE,CAoqLhB,CACE,GAAI,CAEF,GADAruB,CACA,CADQkoB,CAAArR,KAAA,CAA8BzY,CAAA+rB,UAA9B,CACR,CACE6D,CACA,CADQX,EAAA,CAAmBrtB,CAAA,CAAM,CAAN,CAAnB,CACR,CAAIotB,CAAA,CAAazE,CAAb,CAAyBqF,CAAzB,CAAgC,GAAhC,CAAqChE,CAArC,CAAkDC,CAAlD,CAAJ,GACEmC,CAAA,CAAM4B,CAAN,CADF,CACiBvW,CAAA,CAAKzX,CAAA,CAAM,CAAN,CAAL,CADjB,CAJA,CAQF,MAAO+C,CAAP,CAAU,EAlFhB,CA0FA4lB,CAAAztB,KAAA,CAAgBozB,EAAhB,CACA,OAAO3F,EAjGyE,CA4GlF4F,QAASA,GAAS,CAACnwB,CAAD,CAAOowB,CAAP,CAAkBC,CAAlB,CAA2B,CAC3C,IAAIplB,EAAQ,EAAZ,CACIqlB,EAAQ,CACZ,IAAIF,CAAJ,EAAiBpwB,CAAAyG,aAAjB,EAAsCzG,CAAAyG,aAAA,CAAkB2pB,CAAlB,CAAtC,EACE,EAAG,CACD,GAAKpwB,CAAAA,CAAL,CACE,KAAMupB,GAAA,CAAe,SAAf,CAEI6G,CAFJ,CAEeC,CAFf,CAAN;AAIErwB,CAAAjE,SAAJ,EAAqBC,EAArB,GACMgE,CAAAyG,aAAA,CAAkB2pB,CAAlB,CACJ,EADkCE,CAAA,EAClC,CAAItwB,CAAAyG,aAAA,CAAkB4pB,CAAlB,CAAJ,EAAgCC,CAAA,EAFlC,CAIArlB,EAAAzJ,KAAA,CAAWxB,CAAX,CACAA,EAAA,CAAOA,CAAAoL,YAXN,CAAH,MAYiB,CAZjB,CAYSklB,CAZT,CADF,KAeErlB,EAAAzJ,KAAA,CAAWxB,CAAX,CAGF,OAAOwE,EAAA,CAAOyG,CAAP,CArBoC,CAgC7CslB,QAASA,GAA0B,CAACC,CAAD,CAASJ,CAAT,CAAoBC,CAApB,CAA6B,CAC9D,MAAO,SAAQ,CAAC5oB,CAAD,CAAQhH,CAAR,CAAiButB,CAAjB,CAAwBW,CAAxB,CAAqChD,CAArC,CAAmD,CAChElrB,CAAA,CAAU0vB,EAAA,CAAU1vB,CAAA,CAAQ,CAAR,CAAV,CAAsB2vB,CAAtB,CAAiCC,CAAjC,CACV,OAAOG,EAAA,CAAO/oB,CAAP,CAAchH,CAAd,CAAuButB,CAAvB,CAA8BW,CAA9B,CAA2ChD,CAA3C,CAFyD,CADJ,CA8BhEyC,QAASA,EAAqB,CAAC7D,CAAD,CAAakG,CAAb,CAA0BC,CAA1B,CAAyC/E,CAAzC,CACCgF,CADD,CACeC,CADf,CACyCC,CADzC,CACqDC,CADrD,CAEChF,CAFD,CAEyB,CAgNrDiF,QAASA,EAAU,CAACC,CAAD,CAAMC,CAAN,CAAYb,CAAZ,CAAuBC,CAAvB,CAAgC,CACjD,GAAIW,CAAJ,CAAS,CACHZ,CAAJ,GAAeY,CAAf,CAAqBT,EAAA,CAA2BS,CAA3B,CAAgCZ,CAAhC,CAA2CC,CAA3C,CAArB,CACAW,EAAAvG,QAAA,CAAcxd,CAAAwd,QACduG,EAAA/H,cAAA,CAAoBA,CACpB,IAAIiI,CAAJ,GAAiCjkB,CAAjC,EAA8CA,CAAAkkB,eAA9C,CACEH,CAAA,CAAMI,CAAA,CAAmBJ,CAAnB,CAAwB,CAACxnB,aAAc,CAAA,CAAf,CAAxB,CAERqnB,EAAArvB,KAAA,CAAgBwvB,CAAhB,CAPO,CAST,GAAIC,CAAJ,CAAU,CACJb,CAAJ,GAAea,CAAf,CAAsBV,EAAA,CAA2BU,CAA3B,CAAiCb,CAAjC,CAA4CC,CAA5C,CAAtB,CACAY,EAAAxG,QAAA,CAAexd,CAAAwd,QACfwG,EAAAhI,cAAA,CAAqBA,CACrB,IAAIiI,CAAJ,GAAiCjkB,CAAjC,EAA8CA,CAAAkkB,eAA9C,CACEF,CAAA,CAAOG,CAAA,CAAmBH,CAAnB,CAAyB,CAACznB,aAAc,CAAA,CAAf,CAAzB,CAETsnB,EAAAtvB,KAAA,CAAiByvB,CAAjB,CAPQ,CAVuC,CAhNE;AAsOrDI,QAASA,EAAc,CAACpI,CAAD,CAAgBwB,CAAhB,CAAyBe,CAAzB,CAAmC8F,CAAnC,CAAuD,CAC5E,IAAIp0B,CAEJ,IAAIjB,CAAA,CAASwuB,CAAT,CAAJ,CAAuB,CACrB,IAAI7oB,EAAQ6oB,CAAA7oB,MAAA,CAAcqoB,CAAd,CACRzjB,EAAAA,CAAOikB,CAAA8G,UAAA,CAAkB3vB,CAAA,CAAM,CAAN,CAAA/F,OAAlB,CACX,KAAI21B,EAAc5vB,CAAA,CAAM,CAAN,CAAd4vB,EAA0B5vB,CAAA,CAAM,CAAN,CAA9B,CACI8nB,EAAwB,GAAxBA,GAAW9nB,CAAA,CAAM,CAAN,CAGK,KAApB,GAAI4vB,CAAJ,CACEhG,CADF,CACaA,CAAA5sB,OAAA,EADb,CAME1B,CANF,EAKEA,CALF,CAKUo0B,CALV,EAKgCA,CAAA,CAAmB9qB,CAAnB,CALhC,GAMmBtJ,CAAAmkB,SAGdnkB,EAAL,GACMu0B,CACJ,CADe,GACf,CADqBjrB,CACrB,CAD4B,YAC5B,CAAAtJ,CAAA,CAAQs0B,CAAA,CAAchG,CAAA9hB,cAAA,CAAuB+nB,CAAvB,CAAd,CAAiDjG,CAAA5jB,KAAA,CAAc6pB,CAAd,CAF3D,CAKA,IAAKv0B,CAAAA,CAAL,EAAewsB,CAAAA,CAAf,CACE,KAAMH,GAAA,CAAe,OAAf,CAEF/iB,CAFE,CAEIyiB,CAFJ,CAAN,CAtBmB,CAAvB,IA0BO,IAAI/sB,CAAA,CAAQuuB,CAAR,CAAJ,CAEL,IADAvtB,CACgBU,CADR,EACQA,CAAPb,CAAOa,CAAH,CAAGA,CAAAA,CAAAA,CAAK6sB,CAAA5uB,OAArB,CAAqCkB,CAArC,CAAyCa,CAAzC,CAA6Cb,CAAA,EAA7C,CACEG,CAAA,CAAMH,CAAN,CAAA,CAAWs0B,CAAA,CAAepI,CAAf,CAA8BwB,CAAA,CAAQ1tB,CAAR,CAA9B,CAA0CyuB,CAA1C,CAAoD8F,CAApD,CAIf,OAAOp0B,EAAP,EAAgB,IApC4D,CAuC9Ew0B,QAASA,EAAgB,CAAClG,CAAD,CAAWwC,CAAX,CAAkBrC,CAAlB,CAAgCgG,CAAhC,CAAsDnoB,CAAtD,CAAoE/B,CAApE,CAA2E,CAClG,IAAI6pB,EAAqB/uB,EAAA,EAAzB,CACSqvB,CAAT,KAASA,CAAT,GAA0BD,EAA1B,CAAgD,CAC9C,IAAI1kB,EAAY0kB,CAAA,CAAqBC,CAArB,CAAhB,CACI3Q,EAAS,CACX4Q,OAAQ5kB,CAAA,GAAcikB,CAAd,EAA0CjkB,CAAAkkB,eAA1C,CAAqE3nB,CAArE,CAAoF/B,CADjF,CAEX+jB,SAAUA,CAFC,CAGXsG,OAAQ9D,CAHG,CAIX+D,YAAapG,CAJF,CADb,CAQIliB,EAAawD,CAAAxD,WACC,IAAlB,EAAIA,CAAJ,GACEA,CADF,CACeukB,CAAA,CAAM/gB,CAAAzG,KAAN,CADf,CAIIwrB,EAAAA,CAAqB/d,CAAA,CAAYxK,CAAZ;AAAwBwX,CAAxB,CAAgC,CAAA,CAAhC,CAAsChU,CAAA2d,aAAtC,CAOzB0G,EAAA,CAAmBrkB,CAAAzG,KAAnB,CAAA,CAAqCwrB,CAChCC,EAAL,EACEzG,CAAA5jB,KAAA,CAAc,GAAd,CAAoBqF,CAAAzG,KAApB,CAAqC,YAArC,CAAmDwrB,CAAA3Q,SAAnD,CAvB4C,CA0BhD,MAAOiQ,EA5B2F,CA+BpG/D,QAASA,EAAU,CAACP,CAAD,CAAcvlB,CAAd,CAAqByqB,CAArB,CAA+BnF,CAA/B,CAA6CyB,CAA7C,CACC2D,CADD,CACa,CA4G9BC,QAASA,EAA0B,CAAC3qB,CAAD,CAAQ4qB,CAAR,CAAuB7F,CAAvB,CAA4C,CAC7E,IAAID,CAGC5sB,GAAA,CAAQ8H,CAAR,CAAL,GACE+kB,CAEA,CAFsB6F,CAEtB,CADAA,CACA,CADgB5qB,CAChB,CAAAA,CAAA,CAAQjM,CAHV,CAMIy2B,EAAJ,GACE1F,CADF,CAC0B+E,CAD1B,CAGK9E,EAAL,GACEA,CADF,CACwByF,CAAA,CAAgCzG,EAAA5sB,OAAA,EAAhC,CAAoD4sB,EAD5E,CAGA,OAAOgD,EAAA,CAAkB/mB,CAAlB,CAAyB4qB,CAAzB,CAAwC9F,CAAxC,CAA+DC,CAA/D,CAAoF8F,EAApF,CAhBsE,CA5GjD,IAC1Bv1B,CAD0B,CACnByzB,CADmB,CACX/mB,CADW,CACCD,CADD,CACe8nB,CADf,CACmC3F,EADnC,CACiDH,EAG3EiF,EAAJ,GAAoByB,CAApB,EACElE,CACA,CADQ0C,CACR,CAAAlF,EAAA,CAAWkF,CAAArC,UAFb,GAIE7C,EACA,CADWhnB,CAAA,CAAO0tB,CAAP,CACX,CAAAlE,CAAA,CAAQ,IAAIE,EAAJ,CAAe1C,EAAf,CAAyBkF,CAAzB,CALV,CAQIQ,EAAJ,GACE1nB,CADF,CACiB/B,CAAAgmB,KAAA,CAAW,CAAA,CAAX,CADjB,CAIIe,EAAJ,GAGE7C,EACA,CADeyG,CACf,CAAAzG,EAAAc,kBAAA,CAAiC+B,CAJnC,CAOImD,EAAJ,GACEL,CADF,CACuBI,CAAA,CAAiBlG,EAAjB,CAA2BwC,CAA3B,CAAkCrC,EAAlC,CAAgDgG,CAAhD,CAAsEnoB,CAAtE,CAAoF/B,CAApF,CADvB,CAIIypB,EAAJ,GAEExpB,CAAAmlB,eAAA,CAAuBrB,EAAvB,CAAiChiB,CAAjC,CAA+C,CAAA,CAA/C,CAAqD,EAAE+oB,CAAF,GAAwBA,CAAxB,GAA8CrB,CAA9C,EACjDqB,CADiD,GAC3BrB,CAAAsB,oBAD2B,EAArD,CAKA,CAHA9qB,CAAAwkB,gBAAA,CAAwBV,EAAxB,CAAkC,CAAA,CAAlC,CAGA,CAFAhiB,CAAAuhB,kBAEA,CADImG,CAAAnG,kBACJ,CAAA0H,CAAA,CAA4BhrB,CAA5B,CAAmCumB,CAAnC,CAA0CxkB,CAA1C;AAC4BA,CAAAuhB,kBAD5B,CAE4BmG,CAF5B,CAEsD1nB,CAFtD,CAPF,CAWA,IAAI8nB,CAAJ,CAAwB,CAEtB,IAAIoB,EAAiBxB,CAAjBwB,EAA6CC,CAAjD,CAEIC,CACAF,EAAJ,EAAsBpB,CAAA,CAAmBoB,CAAAlsB,KAAnB,CAAtB,GACE4iB,CAGA,CAHWsJ,CAAA5H,WAAAH,iBAGX,EAFAlhB,CAEA,CAFa6nB,CAAA,CAAmBoB,CAAAlsB,KAAnB,CAEb,GAAkBiD,CAAAopB,WAAlB,EAA2CzJ,CAA3C,GACEwJ,CACA,CADwBnpB,CACxB,CAAA0oB,CAAAzE,kBAAA,CACI+E,CAAA,CAA4BhrB,CAA5B,CAAmCumB,CAAnC,CAA0CvkB,CAAA4X,SAA1C,CAC4B+H,CAD5B,CACsCsJ,CADtC,CAHN,CAJF,CAWA,KAAK31B,CAAL,GAAUu0B,EAAV,CAA8B,CAC5B7nB,CAAA,CAAa6nB,CAAA,CAAmBv0B,CAAnB,CACb,KAAI+1B,EAAmBrpB,CAAA,EAEnBqpB,EAAJ,GAAyBrpB,CAAA4X,SAAzB,GAGE5X,CAAA4X,SAEA,CAFsByR,CAEtB,CADAtH,EAAA5jB,KAAA,CAAc,GAAd,CAAoB7K,CAApB,CAAwB,YAAxB,CAAsC+1B,CAAtC,CACA,CAAIrpB,CAAJ,GAAmBmpB,CAAnB,GAEET,CAAAzE,kBAAA,EACA,CAAAyE,CAAAzE,kBAAA,CACE+E,CAAA,CAA4BhrB,CAA5B,CAAmCumB,CAAnC,CAA0C8E,CAA1C,CAA4D1J,CAA5D,CAAsEsJ,CAAtE,CAJJ,CALF,CAJ4B,CAhBR,CAoCnB31B,CAAA,CAAI,CAAT,KAAYa,CAAZ,CAAiBizB,CAAAh1B,OAAjB,CAAoCkB,CAApC,CAAwCa,CAAxC,CAA4Cb,CAAA,EAA5C,CACEyzB,CACA,CADSK,CAAA,CAAW9zB,CAAX,CACT,CAAAg2B,CAAA,CAAavC,CAAb,CACIA,CAAAhnB,aAAA,CAAsBA,CAAtB,CAAqC/B,CADzC,CAEI+jB,EAFJ,CAGIwC,CAHJ,CAIIwC,CAAA/F,QAJJ,EAIsB4G,CAAA,CAAeb,CAAAvH,cAAf,CAAqCuH,CAAA/F,QAArC,CAAqDe,EAArD,CAA+D8F,CAA/D,CAJtB,CAKI3F,EALJ,CAYF,KAAI2G,GAAe7qB,CACfypB,EAAJ,GAAiCA,CAAA8B,SAAjC,EAA+G,IAA/G,GAAsE9B,CAAA+B,YAAtE,IACEX,EADF,CACiB9oB,CADjB,CAGAwjB,EAAA,EAAeA,CAAA,CAAYsF,EAAZ;AAA0BJ,CAAAlZ,WAA1B,CAA+Cxd,CAA/C,CAA0DgzB,CAA1D,CAGf,KAAKzxB,CAAL,CAAS+zB,CAAAj1B,OAAT,CAA8B,CAA9B,CAAsC,CAAtC,EAAiCkB,CAAjC,CAAyCA,CAAA,EAAzC,CACEyzB,CACA,CADSM,CAAA,CAAY/zB,CAAZ,CACT,CAAAg2B,CAAA,CAAavC,CAAb,CACIA,CAAAhnB,aAAA,CAAsBA,CAAtB,CAAqC/B,CADzC,CAEI+jB,EAFJ,CAGIwC,CAHJ,CAIIwC,CAAA/F,QAJJ,EAIsB4G,CAAA,CAAeb,CAAAvH,cAAf,CAAqCuH,CAAA/F,QAArC,CAAqDe,EAArD,CAA+D8F,CAA/D,CAJtB,CAKI3F,EALJ,CAjG4B,CA5ShCG,CAAA,CAAyBA,CAAzB,EAAmD,EAqBnD,KAtBqD,IAGjDoH,EAAmB,CAAC7K,MAAAC,UAH6B,CAIjDqK,EAAoB7G,CAAA6G,kBAJ6B,CAKjDhB,EAAuB7F,CAAA6F,qBAL0B,CAMjDT,EAA2BpF,CAAAoF,yBANsB,CAOjDqB,EAAoBzG,CAAAyG,kBAP6B,CAQjDY,EAA4BrH,CAAAqH,0BARqB,CASjDC,EAAyB,CAAA,CATwB,CAUjDC,EAAc,CAAA,CAVmC,CAWjDpB,EAAgCnG,CAAAmG,8BAXiB,CAYjDqB,GAAe5C,CAAArC,UAAfiF,CAAyC9uB,CAAA,CAAOisB,CAAP,CAZQ,CAajDxjB,CAbiD,CAcjDgc,CAdiD,CAejDsK,CAfiD,CAiBjDC,EAAoB7H,CAjB6B,CAkBjD6E,EAlBiD,CAsB5CzzB,GAAI,CAtBwC,CAsBrCa,GAAK2sB,CAAA1uB,OAArB,CAAwCkB,EAAxC,CAA4Ca,EAA5C,CAAgDb,EAAA,EAAhD,CAAqD,CACnDkQ,CAAA,CAAYsd,CAAA,CAAWxtB,EAAX,CACZ,KAAIqzB,EAAYnjB,CAAAwmB,QAAhB,CACIpD,EAAUpjB,CAAAymB,MAGVtD,EAAJ,GACEkD,EADF,CACiBnD,EAAA,CAAUM,CAAV,CAAuBL,CAAvB,CAAkCC,CAAlC,CADjB,CAGAkD,EAAA,CAAY/3B,CAEZ,IAAI03B,CAAJ,CAAuBjmB,CAAAud,SAAvB,CACE,KAGF,IAAImJ,CAAJ,CAAqB1mB,CAAAxF,MAArB,CAIOwF,CAAAgmB,YAeL;CAdMp1B,CAAA,CAAS81B,CAAT,CAAJ,EAGEC,CAAA,CAAkB,oBAAlB,CAAwC1C,CAAxC,EAAoEyB,CAApE,CACkB1lB,CADlB,CAC6BqmB,EAD7B,CAEA,CAAApC,CAAA,CAA2BjkB,CAL7B,EASE2mB,CAAA,CAAkB,oBAAlB,CAAwC1C,CAAxC,CAAkEjkB,CAAlE,CACkBqmB,EADlB,CAKJ,EAAAX,CAAA,CAAoBA,CAApB,EAAyC1lB,CAG3Cgc,EAAA,CAAgBhc,CAAAzG,KAEXysB,EAAAhmB,CAAAgmB,YAAL,EAA8BhmB,CAAAxD,WAA9B,GACEkqB,CAIA,CAJiB1mB,CAAAxD,WAIjB,CAHAkoB,CAGA,CAHuBA,CAGvB,EAH+CpvB,EAAA,EAG/C,CAFAqxB,CAAA,CAAkB,GAAlB,CAAwB3K,CAAxB,CAAwC,cAAxC,CACI0I,CAAA,CAAqB1I,CAArB,CADJ,CACyChc,CADzC,CACoDqmB,EADpD,CAEA,CAAA3B,CAAA,CAAqB1I,CAArB,CAAA,CAAsChc,CALxC,CAQA,IAAI0mB,CAAJ,CAAqB1mB,CAAA6gB,WAArB,CACEsF,CAUA,CAVyB,CAAA,CAUzB,CALKnmB,CAAA4mB,MAKL,GAJED,CAAA,CAAkB,cAAlB,CAAkCT,CAAlC,CAA6DlmB,CAA7D,CAAwEqmB,EAAxE,CACA,CAAAH,CAAA,CAA4BlmB,CAG9B,EAAsB,SAAtB,EAAI0mB,CAAJ,EACE1B,CASA,CATgC,CAAA,CAShC,CARAiB,CAQA,CARmBjmB,CAAAud,SAQnB,CAPA+I,CAOA,CAPYD,EAOZ,CANAA,EAMA,CANe5C,CAAArC,UAMf,CALI7pB,CAAA,CAAOjJ,CAAAu4B,cAAA,CAAuB,GAAvB,CAA6B7K,CAA7B,CAA6C,IAA7C,CACuByH,CAAA,CAAczH,CAAd,CADvB,CACsD,GADtD,CAAP,CAKJ,CAHAwH,CAGA,CAHc6C,EAAA,CAAa,CAAb,CAGd,CAFAS,CAAA,CAAYpD,CAAZ,CApjNHtyB,EAAA5B,KAAA,CAojNuC82B,CApjNvC,CAA+B,CAA/B,CAojNG,CAAgD9C,CAAhD,CAEA,CAAA+C,CAAA,CAAoB9rB,CAAA,CAAQ6rB,CAAR,CAAmB5H,CAAnB,CAAiCuH,CAAjC,CACQc,CADR,EAC4BA,CAAAxtB,KAD5B,CACmD,CAQzC2sB,0BAA2BA,CARc,CADnD,CAVtB,GAsBEI,CAEA,CAFY/uB,CAAA,CAAOkV,EAAA,CAAY+W,CAAZ,CAAP,CAAAwD,SAAA,EAEZ,CADAX,EAAA5uB,MAAA,EACA,CAAA8uB,CAAA,CAAoB9rB,CAAA,CAAQ6rB,CAAR,CAAmB5H,CAAnB,CAxBtB,CA4BF,IAAI1e,CAAA+lB,SAAJ,CAWE,GAVAK,CAUIruB,CAVU,CAAA,CAUVA,CATJ4uB,CAAA,CAAkB,UAAlB;AAA8BrB,CAA9B,CAAiDtlB,CAAjD,CAA4DqmB,EAA5D,CASItuB,CARJutB,CAQIvtB,CARgBiI,CAQhBjI,CANJ2uB,CAMI3uB,CANczI,CAAA,CAAW0Q,CAAA+lB,SAAX,CAAD,CACX/lB,CAAA+lB,SAAA,CAAmBM,EAAnB,CAAiC5C,CAAjC,CADW,CAEXzjB,CAAA+lB,SAIFhuB,CAFJ2uB,CAEI3uB,CAFakvB,EAAA,CAAoBP,CAApB,CAEb3uB,CAAAiI,CAAAjI,QAAJ,CAAuB,CACrBgvB,CAAA,CAAmB/mB,CAIjBsmB,EAAA,CArlKJlb,EAAA9W,KAAA,CAklKuBoyB,CAllKvB,CAklKE,CAGcQ,EAAA,CAAexH,EAAA,CAAa1f,CAAAmnB,kBAAb,CAA0C/a,CAAA,CAAKsa,CAAL,CAA1C,CAAf,CAHd,CACc,EAIdlD,EAAA,CAAc8C,CAAA,CAAU,CAAV,CAEd,IAAwB,CAAxB,EAAIA,CAAA13B,OAAJ,EAA6B40B,CAAA10B,SAA7B,GAAsDC,EAAtD,CACE,KAAMutB,GAAA,CAAe,OAAf,CAEFN,CAFE,CAEa,EAFb,CAAN,CAKF8K,CAAA,CAAYpD,CAAZ,CAA0B2C,EAA1B,CAAwC7C,CAAxC,CAEI4D,GAAAA,CAAmB,CAACtF,MAAO,EAAR,CAOnBuF,EAAAA,CAAqBnG,EAAA,CAAkBsC,CAAlB,CAA+B,EAA/B,CAAmC4D,EAAnC,CACzB,KAAIE,EAAwBhK,CAAAxpB,OAAA,CAAkBhE,EAAlB,CAAsB,CAAtB,CAAyBwtB,CAAA1uB,OAAzB,EAA8CkB,EAA9C,CAAkD,CAAlD,EAExBm0B,EAAJ,EACEsD,EAAA,CAAwBF,CAAxB,CAEF/J,EAAA,CAAaA,CAAA/nB,OAAA,CAAkB8xB,CAAlB,CAAA9xB,OAAA,CAA6C+xB,CAA7C,CACbE,EAAA,CAAwB/D,CAAxB,CAAuC2D,EAAvC,CAEAz2B,GAAA,CAAK2sB,CAAA1uB,OAjCgB,CAAvB,IAmCEy3B,GAAAxuB,KAAA,CAAkB6uB,CAAlB,CAIJ,IAAI1mB,CAAAgmB,YAAJ,CACEI,CAgBA,CAhBc,CAAA,CAgBd,CAfAO,CAAA,CAAkB,UAAlB,CAA8BrB,CAA9B,CAAiDtlB,CAAjD,CAA4DqmB,EAA5D,CAeA,CAdAf,CAcA,CAdoBtlB,CAcpB,CAZIA,CAAAjI,QAYJ,GAXEgvB,CAWF,CAXqB/mB,CAWrB,EARAsgB,CAQA,CARamH,EAAA,CAAmBnK,CAAAxpB,OAAA,CAAkBhE,EAAlB,CAAqBwtB,CAAA1uB,OAArB,CAAyCkB,EAAzC,CAAnB,CAAgEu2B,EAAhE,CACT5C,CADS,CACMC,CADN,CACoByC,CADpB,EAC8CI,CAD9C,CACiE3C,CADjE,CAC6EC,CAD7E,CAC0F,CACjGa,qBAAsBA,CAD2E,CAEjGgB,kBAAoBA,CAApBA,GAA0C1lB,CAA1C0lB,EAAwDA,CAFyC,CAGjGzB,yBAA0BA,CAHuE;AAIjGqB,kBAAmBA,CAJ8E,CAKjGY,0BAA2BA,CALsE,CAD1F,CAQb,CAAAv1B,EAAA,CAAK2sB,CAAA1uB,OAjBP,KAkBO,IAAIoR,CAAAvF,QAAJ,CACL,GAAI,CACF8oB,EACA,CADSvjB,CAAAvF,QAAA,CAAkB4rB,EAAlB,CAAgC5C,CAAhC,CAA+C8C,CAA/C,CACT,CAAIj3B,CAAA,CAAWi0B,EAAX,CAAJ,CACEO,CAAA,CAAW,IAAX,CAAiBP,EAAjB,CAAyBJ,CAAzB,CAAoCC,CAApC,CADF,CAEWG,EAFX,EAGEO,CAAA,CAAWP,EAAAQ,IAAX,CAAuBR,EAAAS,KAAvB,CAAoCb,CAApC,CAA+CC,CAA/C,CALA,CAOF,MAAO1rB,EAAP,CAAU,CACV0P,CAAA,CAAkB1P,EAAlB,CAAqBJ,EAAA,CAAY+uB,EAAZ,CAArB,CADU,CAKVrmB,CAAAqhB,SAAJ,GACEf,CAAAe,SACA,CADsB,CAAA,CACtB,CAAA4E,CAAA,CAAmByB,IAAAC,IAAA,CAAS1B,CAAT,CAA2BjmB,CAAAud,SAA3B,CAFrB,CAvKmD,CA8KrD+C,CAAA9lB,MAAA,CAAmBkrB,CAAnB,EAAoE,CAAA,CAApE,GAAwCA,CAAAlrB,MACxC8lB,EAAAK,wBAAA,CAAqCwF,CACrC7F,EAAAQ,sBAAA,CAAmCsF,CACnC9F,EAAAO,WAAA,CAAwB0F,CAExB1H,EAAAmG,8BAAA,CAAuDA,CAGvD,OAAO1E,EA5M8C,CA8avDiH,QAASA,GAAuB,CAACjK,CAAD,CAAa,CAE3C,IAF2C,IAElCzsB,EAAI,CAF8B,CAE3BC,EAAKwsB,CAAA1uB,OAArB,CAAwCiC,CAAxC,CAA4CC,CAA5C,CAAgDD,CAAA,EAAhD,CACEysB,CAAA,CAAWzsB,CAAX,CAAA,CAAgBa,EAAA,CAAQ4rB,CAAA,CAAWzsB,CAAX,CAAR,CAAuB,CAACqzB,eAAgB,CAAA,CAAjB,CAAvB,CAHyB,CAqB7CnC,QAASA,EAAY,CAAC6F,CAAD,CAAcruB,CAAd,CAAoB6B,CAApB,CAA8BujB,CAA9B,CAA2CC,CAA3C,CAA4DiJ,CAA5D,CACCC,CADD,CACc,CACjC,GAAIvuB,CAAJ,GAAaqlB,CAAb,CAA8B,MAAO,KACjCjqB,EAAAA,CAAQ,IACZ,IAAIioB,CAAArtB,eAAA,CAA6BgK,CAA7B,CAAJ,CAAwC,CAAA,IAC7ByG,CAAWsd;CAAAA,CAAa9I,CAAAhZ,IAAA,CAAcjC,CAAd,CAt2C1B8jB,WAs2C0B,CAAjC,KADsC,IAElCvtB,EAAI,CAF8B,CAE3Ba,EAAK2sB,CAAA1uB,OADhB,CACmCkB,CADnC,CACuCa,CADvC,CAC2Cb,CAAA,EAD3C,CAEE,GAAI,CACFkQ,CACA,CADYsd,CAAA,CAAWxtB,CAAX,CACZ,EAAK6uB,CAAL,GAAqBpwB,CAArB,EAAkCowB,CAAlC,CAAgD3e,CAAAud,SAAhD,GAC8C,EAD9C,EACKvd,CAAAyd,SAAA5pB,QAAA,CAA2BuH,CAA3B,CADL,GAEMysB,CAIJ,GAHE7nB,CAGF,CAHctO,EAAA,CAAQsO,CAAR,CAAmB,CAACwmB,QAASqB,CAAV,CAAyBpB,MAAOqB,CAAhC,CAAnB,CAGd,EADAF,CAAArzB,KAAA,CAAiByL,CAAjB,CACA,CAAArL,CAAA,CAAQqL,CANV,CAFE,CAUF,MAAOtI,CAAP,CAAU,CAAE0P,CAAA,CAAkB1P,CAAlB,CAAF,CAbwB,CAgBxC,MAAO/C,EAnB0B,CA+BnC+tB,QAASA,EAAuB,CAACnpB,CAAD,CAAO,CACrC,GAAIqjB,CAAArtB,eAAA,CAA6BgK,CAA7B,CAAJ,CACE,IADsC,IAClB+jB,EAAa9I,CAAAhZ,IAAA,CAAcjC,CAAd,CAn4C1B8jB,WAm4C0B,CADK,CAElCvtB,EAAI,CAF8B,CAE3Ba,EAAK2sB,CAAA1uB,OADhB,CACmCkB,CADnC,CACuCa,CADvC,CAC2Cb,CAAA,EAD3C,CAGE,GADAkQ,CACI+nB,CADQzK,CAAA,CAAWxtB,CAAX,CACRi4B,CAAA/nB,CAAA+nB,aAAJ,CACE,MAAO,CAAA,CAIb,OAAO,CAAA,CAV8B,CAqBvCP,QAASA,EAAuB,CAACh3B,CAAD,CAAMO,CAAN,CAAW,CAAA,IACrCi3B,EAAUj3B,CAAA+wB,MAD2B,CAErCmG,EAAUz3B,CAAAsxB,MAF2B,CAGrCvD,EAAW/tB,CAAA4wB,UAGflyB,EAAA,CAAQsB,CAAR,CAAa,QAAQ,CAACP,CAAD,CAAQZ,CAAR,CAAa,CACX,GAArB,EAAIA,CAAA0F,OAAA,CAAW,CAAX,CAAJ,GACMhE,CAAA,CAAI1B,CAAJ,CAGJ,EAHgB0B,CAAA,CAAI1B,CAAJ,CAGhB,GAH6BY,CAG7B,GAFEA,CAEF,GAFoB,OAAR,GAAAZ,CAAA,CAAkB,GAAlB,CAAwB,GAEpC,EAF2C0B,CAAA,CAAI1B,CAAJ,CAE3C,EAAAmB,CAAA03B,KAAA,CAAS74B,CAAT,CAAcY,CAAd,CAAqB,CAAA,CAArB,CAA2B+3B,CAAA,CAAQ34B,CAAR,CAA3B,CAJF,CADgC,CAAlC,CAUAH,EAAA,CAAQ6B,CAAR,CAAa,QAAQ,CAACd,CAAD,CAAQZ,CAAR,CAAa,CACrB,OAAX;AAAIA,CAAJ,EACEivB,CAAA,CAAaC,CAAb,CAAuBtuB,CAAvB,CACA,CAAAO,CAAA,CAAI,OAAJ,CAAA,EAAgBA,CAAA,CAAI,OAAJ,CAAA,CAAeA,CAAA,CAAI,OAAJ,CAAf,CAA8B,GAA9B,CAAoC,EAApD,EAA0DP,CAF5D,EAGkB,OAAX,EAAIZ,CAAJ,EACLkvB,CAAArrB,KAAA,CAAc,OAAd,CAAuBqrB,CAAArrB,KAAA,CAAc,OAAd,CAAvB,CAAgD,GAAhD,CAAsDjD,CAAtD,CACA,CAAAO,CAAA,MAAA,EAAgBA,CAAA,MAAA,CAAeA,CAAA,MAAf,CAA8B,GAA9B,CAAoC,EAApD,EAA0DP,CAFrD,EAMqB,GANrB,EAMIZ,CAAA0F,OAAA,CAAW,CAAX,CANJ,EAM6BvE,CAAAjB,eAAA,CAAmBF,CAAnB,CAN7B,GAOLmB,CAAA,CAAInB,CAAJ,CACA,CADWY,CACX,CAAAg4B,CAAA,CAAQ54B,CAAR,CAAA,CAAe24B,CAAA,CAAQ34B,CAAR,CARV,CAJyB,CAAlC,CAhByC,CAkC3Co4B,QAASA,GAAkB,CAACnK,CAAD,CAAa+I,CAAb,CAA2B8B,CAA3B,CACvBrI,CADuB,CACTyG,CADS,CACU3C,CADV,CACsBC,CADtB,CACmChF,CADnC,CAC2D,CAAA,IAChFuJ,EAAY,EADoE,CAEhFC,CAFgF,CAGhFC,CAHgF,CAIhFC,EAA4BlC,CAAA,CAAa,CAAb,CAJoD,CAKhFmC,EAAqBlL,CAAAvJ,MAAA,EAL2D,CAMhF0U,EAAuB/2B,EAAA,CAAQ82B,CAAR,CAA4B,CACjDxC,YAAa,IADoC,CAC9BnF,WAAY,IADkB,CACZ9oB,QAAS,IADG,CACGwtB,oBAAqBiD,CADxB,CAA5B,CANyD,CAShFxC,EAAe12B,CAAA,CAAWk5B,CAAAxC,YAAX,CAAD,CACRwC,CAAAxC,YAAA,CAA+BK,CAA/B,CAA6C8B,CAA7C,CADQ,CAERK,CAAAxC,YAX0E,CAYhFmB,EAAoBqB,CAAArB,kBAExBd,EAAA5uB,MAAA,EAEA+R,EAAA,CAAiBwc,CAAjB,CAAA0C,KAAA,CACQ,QAAQ,CAACC,CAAD,CAAU,CAAA,IAClBnF,CADkB,CACyBvD,CAE/C0I,EAAA,CAAU1B,EAAA,CAAoB0B,CAApB,CAEV,IAAIH,CAAAzwB,QAAJ,CAAgC,CAI5BuuB,CAAA,CA9gLJlb,EAAA9W,KAAA,CA2gLuBq0B,CA3gLvB,CA2gLE,CAGczB,EAAA,CAAexH,EAAA,CAAayH,CAAb,CAAgC/a,CAAA,CAAKuc,CAAL,CAAhC,CAAf,CAHd;AACc,EAIdnF,EAAA,CAAc8C,CAAA,CAAU,CAAV,CAEd,IAAwB,CAAxB,EAAIA,CAAA13B,OAAJ,EAA6B40B,CAAA10B,SAA7B,GAAsDC,EAAtD,CACE,KAAMutB,GAAA,CAAe,OAAf,CAEFkM,CAAAjvB,KAFE,CAEuBysB,CAFvB,CAAN,CAKF4C,CAAA,CAAoB,CAAC9G,MAAO,EAAR,CACpBgF,EAAA,CAAYhH,CAAZ,CAA0BuG,CAA1B,CAAwC7C,CAAxC,CACA,KAAI6D,EAAqBnG,EAAA,CAAkBsC,CAAlB,CAA+B,EAA/B,CAAmCoF,CAAnC,CAErBh4B,EAAA,CAAS43B,CAAAhuB,MAAT,CAAJ,EACE+sB,EAAA,CAAwBF,CAAxB,CAEF/J,EAAA,CAAa+J,CAAA9xB,OAAA,CAA0B+nB,CAA1B,CACbkK,EAAA,CAAwBW,CAAxB,CAAgCS,CAAhC,CAtB8B,CAAhC,IAwBEpF,EACA,CADc+E,CACd,CAAAlC,CAAAxuB,KAAA,CAAkB8wB,CAAlB,CAGFrL,EAAArjB,QAAA,CAAmBwuB,CAAnB,CAEAJ,EAAA,CAA0BlH,CAAA,CAAsB7D,CAAtB,CAAkCkG,CAAlC,CAA+C2E,CAA/C,CACtB5B,CADsB,CACHF,CADG,CACWmC,CADX,CAC+B5E,CAD/B,CAC2CC,CAD3C,CAEtBhF,CAFsB,CAG1B3vB,EAAA,CAAQ4wB,CAAR,CAAsB,QAAQ,CAAC/sB,CAAD,CAAOjD,CAAP,CAAU,CAClCiD,CAAJ,EAAYywB,CAAZ,GACE1D,CAAA,CAAahwB,CAAb,CADF,CACoBu2B,CAAA,CAAa,CAAb,CADpB,CADsC,CAAxC,CAOA,KAFAiC,CAEA,CAF2BtJ,CAAA,CAAaqH,CAAA,CAAa,CAAb,CAAAta,WAAb,CAAyCwa,CAAzC,CAE3B,CAAO6B,CAAAx5B,OAAP,CAAA,CAAyB,CACnB4L,CAAAA,CAAQ4tB,CAAArU,MAAA,EACR8U,EAAAA,CAAyBT,CAAArU,MAAA,EAFN,KAGnB+U,EAAkBV,CAAArU,MAAA,EAHC,CAInBwN,GAAoB6G,CAAArU,MAAA,EAJD,CAKnBkR,EAAWoB,CAAA,CAAa,CAAb,CAEf,IAAI0C,CAAAvuB,CAAAuuB,YAAJ,CAAA,CAEA,GAAIF,CAAJ,GAA+BN,CAA/B,CAA0D,CACxD,IAAIS,EAAaH,CAAArK,UAEXK,EAAAmG,8BAAN,EACIwD,CAAAzwB,QADJ,GAGEktB,CAHF,CAGaxY,EAAA,CAAY+W,CAAZ,CAHb,CAKAsD,EAAA,CAAYgC,CAAZ,CAA6BvxB,CAAA,CAAOsxB,CAAP,CAA7B,CAA6D5D,CAA7D,CAGA3G,EAAA,CAAa/mB,CAAA,CAAO0tB,CAAP,CAAb,CAA+B+D,CAA/B,CAXwD,CAcxD/I,CAAA,CADEoI,CAAA1H,wBAAJ,CAC2BC,CAAA,CAAwBpmB,CAAxB,CAA+B6tB,CAAAxH,WAA/B;AAAmEU,EAAnE,CAD3B,CAG2BA,EAE3B8G,EAAA,CAAwBC,CAAxB,CAAkD9tB,CAAlD,CAAyDyqB,CAAzD,CAAmEnF,CAAnE,CACEG,CADF,CAC0BoI,CAD1B,CApBA,CAPuB,CA8BzBD,CAAA,CAAY,IA3EU,CAD1B,CA+EA,OAAOa,SAA0B,CAACC,CAAD,CAAoB1uB,CAApB,CAA2BzH,CAA3B,CAAiCwI,CAAjC,CAA8CgmB,CAA9C,CAAiE,CAC5FtB,CAAAA,CAAyBsB,CACzB/mB,EAAAuuB,YAAJ,GACIX,CAAJ,CACEA,CAAA7zB,KAAA,CAAeiG,CAAf,CACezH,CADf,CAEewI,CAFf,CAGe0kB,CAHf,CADF,EAMMoI,CAAA1H,wBAGJ,GAFEV,CAEF,CAF2BW,CAAA,CAAwBpmB,CAAxB,CAA+B6tB,CAAAxH,WAA/B,CAAmEU,CAAnE,CAE3B,EAAA8G,CAAA,CAAwBC,CAAxB,CAAkD9tB,CAAlD,CAAyDzH,CAAzD,CAA+DwI,CAA/D,CAA4E0kB,CAA5E,CACwBoI,CADxB,CATF,CADA,CAFgG,CA/Fd,CAqHtFpF,QAASA,GAAU,CAACniB,CAAD,CAAI6V,CAAJ,CAAO,CACxB,IAAIwS,EAAOxS,CAAA4G,SAAP4L,CAAoBroB,CAAAyc,SACxB,OAAa,EAAb,GAAI4L,CAAJ,CAAuBA,CAAvB,CACIroB,CAAAvH,KAAJ,GAAeod,CAAApd,KAAf,CAA+BuH,CAAAvH,KAAD,CAAUod,CAAApd,KAAV,CAAqB,EAArB,CAAyB,CAAvD,CACOuH,CAAAlN,MADP,CACiB+iB,CAAA/iB,MAJO,CAO1B+yB,QAASA,EAAiB,CAACyC,CAAD,CAAOC,CAAP,CAA0BrpB,CAA1B,CAAqCxM,CAArC,CAA8C,CAEtE81B,QAASA,EAAuB,CAACC,CAAD,CAAa,CAC3C,MAAOA,EAAA,CACJ,YADI,CACWA,CADX,CACwB,GADxB,CAEL,EAHyC,CAM7C,GAAIF,CAAJ,CACE,KAAM/M,GAAA,CAAe,UAAf,CACF+M,CAAA9vB,KADE,CACsB+vB,CAAA,CAAwBD,CAAAhqB,aAAxB,CADtB,CAEFW,CAAAzG,KAFE,CAEc+vB,CAAA,CAAwBtpB,CAAAX,aAAxB,CAFd,CAE+D+pB,CAF/D,CAEqE9xB,EAAA,CAAY9D,CAAZ,CAFrE,CAAN,CAToE,CAgBxEuvB,QAASA,GAA2B,CAACzF,CAAD,CAAakM,CAAb,CAAmB,CACrD,IAAIC,EAAgBjiB,CAAA,CAAagiB,CAAb,CAAmB,CAAA,CAAnB,CAChBC,EAAJ,EACEnM,CAAA/oB,KAAA,CAAgB,CACdgpB,SAAU,CADI,CAEd9iB,QAASivB,QAAiC,CAACC,CAAD,CAAe,CACnDC,CAAAA;AAAqBD,CAAAh4B,OAAA,EAAzB,KACIk4B,EAAmB,CAAEj7B,CAAAg7B,CAAAh7B,OAIrBi7B,EAAJ,EAAsBpvB,CAAAqvB,kBAAA,CAA0BF,CAA1B,CAEtB,OAAOG,SAA8B,CAACvvB,CAAD,CAAQzH,CAAR,CAAc,CACjD,IAAIpB,EAASoB,CAAApB,OAAA,EACRk4B,EAAL,EAAuBpvB,CAAAqvB,kBAAA,CAA0Bn4B,CAA1B,CACvB8I,EAAAuvB,iBAAA,CAAyBr4B,CAAzB,CAAiC83B,CAAAQ,YAAjC,CACAzvB,EAAA5H,OAAA,CAAa62B,CAAb,CAA4BS,QAAiC,CAACj6B,CAAD,CAAQ,CACnE8C,CAAA,CAAK,CAAL,CAAA+rB,UAAA,CAAoB7uB,CAD+C,CAArE,CAJiD,CARI,CAF3C,CAAhB,CAHmD,CA2BvDyvB,QAASA,GAAY,CAACxS,CAAD,CAAO6Y,CAAP,CAAiB,CACpC7Y,CAAA,CAAOzZ,CAAA,CAAUyZ,CAAV,EAAkB,MAAlB,CACP,QAAQA,CAAR,EACA,KAAK,KAAL,CACA,KAAK,MAAL,CACE,IAAIid,EAAU77B,CAAAgd,cAAA,CAAuB,KAAvB,CACd6e,EAAAve,UAAA,CAAoB,GAApB,CAA0BsB,CAA1B,CAAiC,GAAjC,CAAuC6Y,CAAvC,CAAkD,IAAlD,CAAyD7Y,CAAzD,CAAgE,GAChE,OAAOid,EAAApe,WAAA,CAAmB,CAAnB,CAAAA,WACT,SACE,MAAOga,EAPT,CAFoC,CActCqE,QAASA,EAAiB,CAACr3B,CAAD,CAAOs3B,CAAP,CAA2B,CACnD,GAA0B,QAA1B,EAAIA,CAAJ,CACE,MAAOrhB,EAAAshB,KAET,KAAItwB,EAAMzG,EAAA,CAAUR,CAAV,CAEV,IAA0B,WAA1B,EAAIs3B,CAAJ,EACY,MADZ,EACKrwB,CADL,EAC4C,QAD5C,EACsBqwB,CADtB,EAEY,KAFZ,EAEKrwB,CAFL,GAE4C,KAF5C,EAEsBqwB,CAFtB;AAG4C,OAH5C,EAGsBA,CAHtB,EAIE,MAAOrhB,EAAAuhB,aAV0C,CAerD3H,QAASA,EAA2B,CAAC7vB,CAAD,CAAOuqB,CAAP,CAAmBrtB,CAAnB,CAA0BsJ,CAA1B,CAAgCixB,CAAhC,CAA8C,CAChF,IAAIC,EAAiBL,CAAA,CAAkBr3B,CAAlB,CAAwBwG,CAAxB,CACrBixB,EAAA,CAAezN,CAAA,CAAqBxjB,CAArB,CAAf,EAA6CixB,CAE7C,KAAIf,EAAgBjiB,CAAA,CAAavX,CAAb,CAAoB,CAAA,CAApB,CAA0Bw6B,CAA1B,CAA0CD,CAA1C,CAGpB,IAAKf,CAAL,CAAA,CAGA,GAAa,UAAb,GAAIlwB,CAAJ,EAA+C,QAA/C,GAA2BhG,EAAA,CAAUR,CAAV,CAA3B,CACE,KAAMupB,GAAA,CAAe,UAAf,CAEFhlB,EAAA,CAAYvE,CAAZ,CAFE,CAAN,CAKFuqB,CAAA/oB,KAAA,CAAgB,CACdgpB,SAAU,GADI,CAEd9iB,QAASA,QAAQ,EAAG,CAChB,MAAO,CACLspB,IAAK2G,QAAiC,CAAClwB,CAAD,CAAQhH,CAAR,CAAiBN,CAAjB,CAAuB,CACvDy3B,CAAAA,CAAez3B,CAAAy3B,YAAfA,GAAoCz3B,CAAAy3B,YAApCA,CAAuD,EAAvDA,CAEJ,IAAI1N,CAAA3oB,KAAA,CAA+BiF,CAA/B,CAAJ,CACE,KAAM+iB,GAAA,CAAe,aAAf,CAAN,CAMF,IAAIsO,EAAW13B,CAAA,CAAKqG,CAAL,CACXqxB,EAAJ,GAAiB36B,CAAjB,GAIEw5B,CACA,CADgBmB,CAChB,EAD4BpjB,CAAA,CAAaojB,CAAb,CAAuB,CAAA,CAAvB,CAA6BH,CAA7B,CAA6CD,CAA7C,CAC5B,CAAAv6B,CAAA,CAAQ26B,CALV,CAUKnB,EAAL,GAKAv2B,CAAA,CAAKqG,CAAL,CAGA,CAHakwB,CAAA,CAAcjvB,CAAd,CAGb,CADAqwB,CAACF,CAAA,CAAYpxB,CAAZ,CAADsxB,GAAuBF,CAAA,CAAYpxB,CAAZ,CAAvBsxB,CAA2C,EAA3CA,UACA,CAD0D,CAAA,CAC1D,CAAAj4B,CAACM,CAAAy3B,YAAD/3B,EAAqBM,CAAAy3B,YAAA,CAAiBpxB,CAAjB,CAAAuxB,QAArBl4B,EAAuD4H,CAAvD5H,QAAA,CACS62B,CADT,CACwBS,QAAiC,CAACU,CAAD,CAAWG,CAAX,CAAqB,CAO7D,OAAb,GAAIxxB,CAAJ,EAAwBqxB,CAAxB,EAAoCG,CAApC,CACE73B,CAAA83B,aAAA,CAAkBJ,CAAlB,CAA4BG,CAA5B,CADF,CAGE73B,CAAAg1B,KAAA,CAAU3uB,CAAV;AAAgBqxB,CAAhB,CAVwE,CAD9E,CARA,CArB2D,CADxD,CADS,CAFN,CAAhB,CATA,CAPgF,CAgFlF9D,QAASA,EAAW,CAAChH,CAAD,CAAemL,CAAf,CAAiCC,CAAjC,CAA0C,CAAA,IACxDC,EAAuBF,CAAA,CAAiB,CAAjB,CADiC,CAExDG,EAAcH,CAAAr8B,OAF0C,CAGxD+C,EAASw5B,CAAAnc,WAH+C,CAIxDlf,CAJwD,CAIrDa,CAEP,IAAImvB,CAAJ,CACE,IAAKhwB,CAAO,CAAH,CAAG,CAAAa,CAAA,CAAKmvB,CAAAlxB,OAAjB,CAAsCkB,CAAtC,CAA0Ca,CAA1C,CAA8Cb,CAAA,EAA9C,CACE,GAAIgwB,CAAA,CAAahwB,CAAb,CAAJ,EAAuBq7B,CAAvB,CAA6C,CAC3CrL,CAAA,CAAahwB,CAAA,EAAb,CAAA,CAAoBo7B,CACJG,EAAAA,CAAKx6B,CAALw6B,CAASD,CAATC,CAAuB,CAAvC,KAAS,IACAv6B,EAAKgvB,CAAAlxB,OADd,CAEKiC,CAFL,CAESC,CAFT,CAEaD,CAAA,EAAA,CAAKw6B,CAAA,EAFlB,CAGMA,CAAJ,CAASv6B,CAAT,CACEgvB,CAAA,CAAajvB,CAAb,CADF,CACoBivB,CAAA,CAAauL,CAAb,CADpB,CAGE,OAAOvL,CAAA,CAAajvB,CAAb,CAGXivB,EAAAlxB,OAAA,EAAuBw8B,CAAvB,CAAqC,CAKjCtL,EAAA1wB,QAAJ,GAA6B+7B,CAA7B,GACErL,CAAA1wB,QADF,CACyB87B,CADzB,CAGA,MAnB2C,CAwB7Cv5B,CAAJ,EACEA,CAAA25B,aAAA,CAAoBJ,CAApB,CAA6BC,CAA7B,CAIEjgB,EAAAA,CAAW5c,CAAA6c,uBAAA,EACfD,EAAAG,YAAA,CAAqB8f,CAArB,CAEI5zB,EAAAg0B,QAAA,CAAeJ,CAAf,CAAJ,GAIE5zB,CAAA,CAAO2zB,CAAP,CAAAvwB,KAAA,CAAqBpD,CAAA,CAAO4zB,CAAP,CAAAxwB,KAAA,EAArB,CAKA,CAAKyB,EAAL,EAUEU,EACA,CADmC,CAAA,CACnC,CAAAV,EAAAM,UAAA,CAAiB,CAACyuB,CAAD,CAAjB,CAXF,EACE,OAAO5zB,CAAAkc,MAAA,CAAa0X,CAAA,CAAqB5zB,CAAAi0B,QAArB,CAAb,CAVX,CAwBSC,EAAAA,CAAI,CAAb,KAAgBC,CAAhB,CAAqBT,CAAAr8B,OAArB,CAA8C68B,CAA9C,CAAkDC,CAAlD,CAAsDD,CAAA,EAAtD,CACMj4B,CAGJ,CAHcy3B,CAAA,CAAiBQ,CAAjB,CAGd,CAFAl0B,CAAA,CAAO/D,CAAP,CAAAgoB,OAAA,EAEA,CADAtQ,CAAAG,YAAA,CAAqB7X,CAArB,CACA,CAAA,OAAOy3B,CAAA,CAAiBQ,CAAjB,CAGTR,EAAA,CAAiB,CAAjB,CAAA,CAAsBC,CACtBD,EAAAr8B,OAAA,CAA0B,CAxEkC,CA4E9Du1B,QAASA,EAAkB,CAACvuB,CAAD;AAAK+1B,CAAL,CAAiB,CAC1C,MAAOx6B,EAAA,CAAO,QAAQ,EAAG,CAAE,MAAOyE,EAAAG,MAAA,CAAS,IAAT,CAAe1E,SAAf,CAAT,CAAlB,CAAyDuE,CAAzD,CAA6D+1B,CAA7D,CADmC,CAK5C7F,QAASA,EAAY,CAACvC,CAAD,CAAS/oB,CAAT,CAAgB+jB,CAAhB,CAA0BwC,CAA1B,CAAiCW,CAAjC,CAA8ChD,CAA9C,CAA4D,CAC/E,GAAI,CACF6E,CAAA,CAAO/oB,CAAP,CAAc+jB,CAAd,CAAwBwC,CAAxB,CAA+BW,CAA/B,CAA4ChD,CAA5C,CADE,CAEF,MAAOhnB,CAAP,CAAU,CACV0P,CAAA,CAAkB1P,CAAlB,CAAqBJ,EAAA,CAAYinB,CAAZ,CAArB,CADU,CAHmE,CAWjFiH,QAASA,EAA2B,CAAChrB,CAAD,CAAQumB,CAAR,CAAe9sB,CAAf,CAA4BkoB,CAA5B,CACCnc,CADD,CACY4rB,CADZ,CACsB,CACxD,IAAIC,CACJ38B,EAAA,CAAQitB,CAAR,CAAkB,QAAQ,CAACC,CAAD,CAAaC,CAAb,CAAwB,CAAA,IAC5CK,EAAWN,CAAAM,SADiC,CAEhDD,EAAWL,CAAAK,SAFqC,CAGhDF,EAAOH,CAAAG,KAHyC,CAIhDuP,CAJgD,CAKhDC,CALgD,CAKrCC,CALqC,CAK1BC,CAEjB18B,GAAAC,KAAA,CAAoBuxB,CAApB,CAA2BrE,CAA3B,CAAL,GAGEqE,CAAA,CAAMrE,CAAN,CAHF,CAGoBnuB,CAHpB,CAMA,QAAQguB,CAAR,EAEE,KAAK,GAAL,CACOwE,CAAA,CAAMrE,CAAN,CAAL,EAAyBD,CAAzB,GACExoB,CAAA,CAAYooB,CAAZ,CADF,CAC2B9tB,CAD3B,CAIAwyB,EAAAmL,SAAA,CAAexP,CAAf,CAAyB,QAAQ,CAACzsB,CAAD,CAAQ,CACvCgE,CAAA,CAAYooB,CAAZ,CAAA,CAAyBpsB,CADc,CAAzC,CAGA8wB,EAAA4J,YAAA,CAAkBjO,CAAlB,CAAAoO,QAAA,CAAsCtwB,CAClCumB,EAAA,CAAMrE,CAAN,CAAJ,GAGEzoB,CAAA,CAAYooB,CAAZ,CAHF,CAG2B7U,CAAA,CAAauZ,CAAA,CAAMrE,CAAN,CAAb,CAAA,CAA8BliB,CAA9B,CAH3B,CAKA,MAEF,MAAK,GAAL,CACE,GAAIiiB,CAAJ,EAAiB,CAAAsE,CAAA,CAAMrE,CAAN,CAAjB,CACE,KAEFqP,EAAA,CAAYvjB,CAAA,CAAOuY,CAAA,CAAMrE,CAAN,CAAP,CAGVuP,EAAA,CADEF,CAAAI,QAAJ,CACYn3B,EADZ,CAGYi3B,QAAQ,CAACnrB,CAAD,CAAI6V,CAAJ,CAAO,CAAE,MAAO7V,EAAP,GAAa6V,CAAb,EAAmB7V,CAAnB,GAAyBA,CAAzB,EAA8B6V,CAA9B,GAAoCA,CAAtC,CAE3BqV,EAAA,CAAYD,CAAAK,OAAZ,EAAgC,QAAQ,EAAG,CAEzCN,CAAA,CAAY73B,CAAA,CAAYooB,CAAZ,CAAZ,CAAqC0P,CAAA,CAAUvxB,CAAV,CACrC,MAAM8hB,GAAA,CAAe,WAAf;AAEFyE,CAAA,CAAMrE,CAAN,CAFE,CAEe1c,CAAAzG,KAFf,CAAN,CAHyC,CAO3CuyB,EAAA,CAAY73B,CAAA,CAAYooB,CAAZ,CAAZ,CAAqC0P,CAAA,CAAUvxB,CAAV,CACjC6xB,EAAAA,CAAmBA,QAAyB,CAACC,CAAD,CAAc,CACvDL,CAAA,CAAQK,CAAR,CAAqBr4B,CAAA,CAAYooB,CAAZ,CAArB,CAAL,GAEO4P,CAAA,CAAQK,CAAR,CAAqBR,CAArB,CAAL,CAKEE,CAAA,CAAUxxB,CAAV,CAAiB8xB,CAAjB,CAA+Br4B,CAAA,CAAYooB,CAAZ,CAA/B,CALF,CAEEpoB,CAAA,CAAYooB,CAAZ,CAFF,CAE2BiQ,CAJ7B,CAUA,OAAOR,EAAP,CAAmBQ,CAXyC,CAa9DD,EAAAE,UAAA,CAA6B,CAAA,CAG3BC,EAAA,CADEpQ,CAAAI,WAAJ,CACYhiB,CAAAiyB,iBAAA,CAAuB1L,CAAA,CAAMrE,CAAN,CAAvB,CAAwC2P,CAAxC,CADZ,CAGY7xB,CAAA5H,OAAA,CAAa4V,CAAA,CAAOuY,CAAA,CAAMrE,CAAN,CAAP,CAAwB2P,CAAxB,CAAb,CAAwD,IAAxD,CAA8DN,CAAAI,QAA9D,CAEZN,EAAA,CAAuBA,CAAvB,EAA8C,EAC9CA,EAAAt3B,KAAA,CAAyBi4B,CAAzB,CACA,MAEF,MAAK,GAAL,CACET,CAAA,CAAYvjB,CAAA,CAAOuY,CAAA,CAAMrE,CAAN,CAAP,CAGZ,IAAIqP,CAAJ,GAAkBj6B,CAAlB,EAA0B2qB,CAA1B,CAAoC,KAEpCxoB,EAAA,CAAYooB,CAAZ,CAAA,CAAyB,QAAQ,CAACrI,CAAD,CAAS,CACxC,MAAO+X,EAAA,CAAUvxB,CAAV,CAAiBwZ,CAAjB,CADiC,CAnE9C,CAbgD,CAAlD,CAsFIuM,EAAAA,CAAkBsL,CAAA,CAAsBtL,QAAwB,EAAG,CACrE,IADqE,IAC5DzwB,EAAI,CADwD,CACrDa,EAAKk7B,CAAAj9B,OAArB,CAAiDkB,CAAjD,CAAqDa,CAArD,CAAyD,EAAEb,CAA3D,CACE+7B,CAAA,CAAoB/7B,CAApB,CAAA,EAFmE,CAAjD,CAIlBgC,CACJ,OAAI85B,EAAJ,EAAgBrL,CAAhB,GAAoCzuB,CAApC,EACE85B,CAAAlL,IAAA,CAAa,UAAb,CAAyBH,CAAzB,CACOzuB,CAAAA,CAFT,EAIOyuB,CAjGiD,CAtjD1D,IAAIU,GAAaA,QAAQ,CAACztB,CAAD,CAAUk5B,CAAV,CAA4B,CACnD,GAAIA,CAAJ,CAAsB,CACpB,IAAI98B,EAAOf,MAAAe,KAAA,CAAY88B,CAAZ,CAAX,CACI58B,CADJ,CACOkd,CADP,CACU3d,CAELS,EAAA,CAAI,CAAT,KAAYkd,CAAZ,CAAgBpd,CAAAhB,OAAhB,CAA6BkB,CAA7B,CAAiCkd,CAAjC,CAAoCld,CAAA,EAApC,CACET,CACA,CADMO,CAAA,CAAKE,CAAL,CACN,CAAA,IAAA,CAAKT,CAAL,CAAA,CAAYq9B,CAAA,CAAiBr9B,CAAjB,CANM,CAAtB,IASE,KAAAyyB,MAAA,CAAa,EAGf,KAAAV,UAAA;AAAiB5tB,CAbkC,CAgBrDytB,GAAA7uB,UAAA,CAAuB,CAgBrBu6B,WAAY3K,EAhBS,CA8BrB4K,UAAWA,QAAQ,CAACC,CAAD,CAAW,CACxBA,CAAJ,EAAkC,CAAlC,CAAgBA,CAAAj+B,OAAhB,EACE0X,CAAA+K,SAAA,CAAkB,IAAA+P,UAAlB,CAAkCyL,CAAlC,CAF0B,CA9BT,CA+CrBC,aAAcA,QAAQ,CAACD,CAAD,CAAW,CAC3BA,CAAJ,EAAkC,CAAlC,CAAgBA,CAAAj+B,OAAhB,EACE0X,CAAAgL,YAAA,CAAqB,IAAA8P,UAArB,CAAqCyL,CAArC,CAF6B,CA/CZ,CAiErB7B,aAAcA,QAAQ,CAAC+B,CAAD,CAAa/D,CAAb,CAAyB,CAC7C,IAAIgE,EAAQC,EAAA,CAAgBF,CAAhB,CAA4B/D,CAA5B,CACRgE,EAAJ,EAAaA,CAAAp+B,OAAb,EACE0X,CAAA+K,SAAA,CAAkB,IAAA+P,UAAlB,CAAkC4L,CAAlC,CAIF,EADIE,CACJ,CADeD,EAAA,CAAgBjE,CAAhB,CAA4B+D,CAA5B,CACf,GAAgBG,CAAAt+B,OAAhB,EACE0X,CAAAgL,YAAA,CAAqB,IAAA8P,UAArB,CAAqC8L,CAArC,CAR2C,CAjE1B,CAsFrBhF,KAAMA,QAAQ,CAAC74B,CAAD,CAAMY,CAAN,CAAak9B,CAAb,CAAwBzQ,CAAxB,CAAkC,CAAA,IAK1C3pB,EAAO,IAAAquB,UAAA,CAAe,CAAf,CALmC,CAM1CgM,EAAaxd,EAAA,CAAmB7c,CAAnB,CAAyB1D,CAAzB,CAN6B,CAO1Cg+B,EAAard,EAAA,CAAmBjd,CAAnB,CAAyB1D,CAAzB,CAP6B,CAQ1Ci+B,EAAWj+B,CAGX+9B,EAAJ,EACE,IAAAhM,UAAAnuB,KAAA,CAAoB5D,CAApB,CAAyBY,CAAzB,CACA,CAAAysB,CAAA,CAAW0Q,CAFb,EAGWC,CAHX,GAIE,IAAA,CAAKA,CAAL,CACA,CADmBp9B,CACnB,CAAAq9B,CAAA,CAAWD,CALb,CAQA,KAAA,CAAKh+B,CAAL,CAAA,CAAYY,CAGRysB,EAAJ,CACE,IAAAoF,MAAA,CAAWzyB,CAAX,CADF,CACoBqtB,CADpB,EAGEA,CAHF,CAGa,IAAAoF,MAAA,CAAWzyB,CAAX,CAHb,IAKI,IAAAyyB,MAAA,CAAWzyB,CAAX,CALJ,CAKsBqtB,CALtB,CAKiCjhB,EAAA,CAAWpM,CAAX;AAAgB,GAAhB,CALjC,CASA2D,EAAA,CAAWO,EAAA,CAAU,IAAA6tB,UAAV,CAEX,IAAkB,GAAlB,GAAKpuB,CAAL,EAAiC,MAAjC,GAAyB3D,CAAzB,EACkB,KADlB,GACK2D,CADL,EACmC,KADnC,GAC2B3D,CAD3B,CAGE,IAAA,CAAKA,CAAL,CAAA,CAAYY,CAAZ,CAAoB0Q,CAAA,CAAc1Q,CAAd,CAA6B,KAA7B,GAAqBZ,CAArB,CAHtB,KAIO,IAAiB,KAAjB,GAAI2D,CAAJ,EAAkC,QAAlC,GAA0B3D,CAA1B,CAA4C,CAejD,IAbIwjB,IAAAA,EAAS,EAATA,CAGA0a,EAAgBnhB,CAAA,CAAKnc,CAAL,CAHhB4iB,CAKA2a,EAAa,qCALb3a,CAMA5N,EAAU,IAAA3Q,KAAA,CAAUi5B,CAAV,CAAA,CAA2BC,CAA3B,CAAwC,KANlD3a,CASA4a,EAAUF,CAAAj6B,MAAA,CAAoB2R,CAApB,CATV4N,CAYA6a,EAAoBhG,IAAAiG,MAAA,CAAWF,CAAA7+B,OAAX,CAA4B,CAA5B,CAZpBikB,CAaK/iB,EAAI,CAAb,CAAgBA,CAAhB,CAAoB49B,CAApB,CAAuC59B,CAAA,EAAvC,CACE,IAAI89B,EAAe,CAAfA,CAAW99B,CAAf,CAEA+iB,EAAAA,CAAAA,CAAUlS,CAAA,CAAcyL,CAAA,CAAKqhB,CAAA,CAAQG,CAAR,CAAL,CAAd,CAAuC,CAAA,CAAvC,CAFV,CAIA/a,EAAAA,CAAAA,EAAW,GAAXA,CAAiBzG,CAAA,CAAKqhB,CAAA,CAAQG,CAAR,CAAmB,CAAnB,CAAL,CAAjB/a,CAIEgb,EAAAA,CAAYzhB,CAAA,CAAKqhB,CAAA,CAAY,CAAZ,CAAQ39B,CAAR,CAAL,CAAAwD,MAAA,CAA2B,IAA3B,CAGhBuf,EAAA,EAAUlS,CAAA,CAAcyL,CAAA,CAAKyhB,CAAA,CAAU,CAAV,CAAL,CAAd,CAAkC,CAAA,CAAlC,CAGe,EAAzB,GAAIA,CAAAj/B,OAAJ,GACEikB,CADF,EACa,GADb,CACmBzG,CAAA,CAAKyhB,CAAA,CAAU,CAAV,CAAL,CADnB,CAGA,KAAA,CAAKx+B,CAAL,CAAA,CAAYY,CAAZ,CAAoB4iB,CAjC6B,CAoCjC,CAAA,CAAlB,GAAIsa,CAAJ,GACgB,IAAd,GAAIl9B,CAAJ,EAAsBA,CAAtB,GAAgC1B,CAAhC,CACE,IAAA6yB,UAAA0M,WAAA,CAA0BpR,CAA1B,CADF,CAGE,IAAA0E,UAAAluB,KAAA,CAAoBwpB,CAApB,CAA8BzsB,CAA9B,CAJJ,CAUA,EADI06B,CACJ,CADkB,IAAAA,YAClB,GAAez7B,CAAA,CAAQy7B,CAAA,CAAY2C,CAAZ,CAAR;AAA+B,QAAQ,CAAC13B,CAAD,CAAK,CACzD,GAAI,CACFA,CAAA,CAAG3F,CAAH,CADE,CAEF,MAAOyH,CAAP,CAAU,CACV0P,CAAA,CAAkB1P,CAAlB,CADU,CAH6C,CAA5C,CAnF+B,CAtF3B,CAqMrBw0B,SAAUA,QAAQ,CAAC78B,CAAD,CAAMuG,CAAN,CAAU,CAAA,IACtBmrB,EAAQ,IADc,CAEtB4J,EAAe5J,CAAA4J,YAAfA,GAAqC5J,CAAA4J,YAArCA,CAAyDr1B,EAAA,EAAzDq1B,CAFsB,CAGtBoD,EAAapD,CAAA,CAAYt7B,CAAZ,CAAb0+B,GAAkCpD,CAAA,CAAYt7B,CAAZ,CAAlC0+B,CAAqD,EAArDA,CAEJA,EAAAx5B,KAAA,CAAeqB,CAAf,CACA8S,EAAA/V,WAAA,CAAsB,QAAQ,EAAG,CAC1Bk4B,CAAAkD,CAAAlD,QAAL,EAA0B9J,CAAAxxB,eAAA,CAAqBF,CAArB,CAA1B,EAEEuG,CAAA,CAAGmrB,CAAA,CAAM1xB,CAAN,CAAH,CAH6B,CAAjC,CAOA,OAAO,SAAQ,EAAG,CAChBqE,EAAA,CAAYq6B,CAAZ,CAAuBn4B,CAAvB,CADgB,CAbQ,CArMP,CAlB+D,KAqPlFo4B,GAAcxmB,CAAAwmB,YAAA,EArPoE,CAsPlFC,GAAYzmB,CAAAymB,UAAA,EAtPsE,CAuPlFhH,GAAsC,IAAhB,EAAC+G,EAAD,EAAsC,IAAtC,EAAwBC,EAAxB,CAChBl8B,EADgB,CAEhBk1B,QAA4B,CAAClB,CAAD,CAAW,CACvC,MAAOA,EAAAhuB,QAAA,CAAiB,OAAjB,CAA0Bi2B,EAA1B,CAAAj2B,QAAA,CAA+C,KAA/C,CAAsDk2B,EAAtD,CADgC,CAzPqC,CA4PlF1L,GAAkB,cAEtB9nB,EAAAuvB,iBAAA,CAA2B7vB,CAAA,CAAmB6vB,QAAyB,CAACzL,CAAD,CAAW2P,CAAX,CAAoB,CACzF,IAAI/R,EAAWoC,CAAA5jB,KAAA,CAAc,UAAd,CAAXwhB,EAAwC,EAExCltB,EAAA,CAAQi/B,CAAR,CAAJ,CACE/R,CADF,CACaA,CAAA5mB,OAAA,CAAgB24B,CAAhB,CADb,CAGE/R,CAAA5nB,KAAA,CAAc25B,CAAd,CAGF3P,EAAA5jB,KAAA,CAAc,UAAd,CAA0BwhB,CAA1B,CATyF,CAAhE,CAUvBrqB,CAEJ2I,EAAAqvB,kBAAA;AAA4B3vB,CAAA,CAAmB2vB,QAA0B,CAACvL,CAAD,CAAW,CAClFD,CAAA,CAAaC,CAAb,CAAuB,YAAvB,CADkF,CAAxD,CAExBzsB,CAEJ2I,EAAAmlB,eAAA,CAAyBzlB,CAAA,CAAmBylB,QAAuB,CAACrB,CAAD,CAAW/jB,CAAX,CAAkB2zB,CAAlB,CAA4BC,CAA5B,CAAwC,CAEzG7P,CAAA5jB,KAAA,CADewzB,CAAA3J,CAAY4J,CAAA,CAAa,yBAAb,CAAyC,eAArD5J,CAAwE,QACvF,CAAwBhqB,CAAxB,CAFyG,CAAlF,CAGrB1I,CAEJ2I,EAAAwkB,gBAAA,CAA0B9kB,CAAA,CAAmB8kB,QAAwB,CAACV,CAAD,CAAW4P,CAAX,CAAqB,CACxF7P,CAAA,CAAaC,CAAb,CAAuB4P,CAAA,CAAW,kBAAX,CAAgC,UAAvD,CADwF,CAAhE,CAEtBr8B,CAEJ,OAAO2I,EAvR+E,CAJ5E,CAhP6C,CAu5D3DunB,QAASA,GAAkB,CAACzoB,CAAD,CAAO,CAChC,MAAOiR,GAAA,CAAUjR,CAAAxB,QAAA,CAAayqB,EAAb,CAA4B,EAA5B,CAAV,CADyB,CAgElCyK,QAASA,GAAe,CAACoB,CAAD,CAAOC,CAAP,CAAa,CAAA,IAC/BC,EAAS,EADsB,CAE/BC,EAAUH,CAAA/6B,MAAA,CAAW,KAAX,CAFqB,CAG/Bm7B,EAAUH,CAAAh7B,MAAA,CAAW,KAAX,CAHqB,CAM1BxD,EAAI,CADb,EAAA,CACA,IAAA,CAAgBA,CAAhB,CAAoB0+B,CAAA5/B,OAApB,CAAoCkB,CAAA,EAApC,CAAyC,CAEvC,IADA,IAAI4+B,EAAQF,CAAA,CAAQ1+B,CAAR,CAAZ,CACSe,EAAI,CAAb,CAAgBA,CAAhB,CAAoB49B,CAAA7/B,OAApB,CAAoCiC,CAAA,EAApC,CACE,GAAI69B,CAAJ,EAAaD,CAAA,CAAQ59B,CAAR,CAAb,CAAyB,SAAS,CAEpC09B,EAAA,GAA2B,CAAhB,CAAAA,CAAA3/B,OAAA,CAAoB,GAApB,CAA0B,EAArC,EAA2C8/B,CALJ,CAOzC,MAAOH,EAb4B,CAgBrCrH,QAASA,GAAc,CAACyH,CAAD,CAAU,CAC/BA,CAAA,CAAUp3B,CAAA,CAAOo3B,CAAP,CACV,KAAI7+B,EAAI6+B,CAAA//B,OAER,IAAS,CAAT,EAAIkB,CAAJ,CACE,MAAO6+B,EAGT,KAAA,CAAO7+B,CAAA,EAAP,CAAA,CAh1NsBkzB,CAk1NpB;AADW2L,CAAA57B,CAAQjD,CAARiD,CACPjE,SAAJ,EACEgF,EAAAtE,KAAA,CAAYm/B,CAAZ,CAAqB7+B,CAArB,CAAwB,CAAxB,CAGJ,OAAO6+B,EAdwB,CAwCjC1nB,QAASA,GAAmB,EAAG,CAAA,IACzBya,EAAc,EADW,CAEzBkN,EAAU,CAAA,CAUd,KAAAC,SAAA,CAAgBC,QAAQ,CAACv1B,CAAD,CAAO/E,CAAP,CAAoB,CAC1CiJ,EAAA,CAAwBlE,CAAxB,CAA8B,YAA9B,CACI3I,EAAA,CAAS2I,CAAT,CAAJ,CACEpI,CAAA,CAAOuwB,CAAP,CAAoBnoB,CAApB,CADF,CAGEmoB,CAAA,CAAYnoB,CAAZ,CAHF,CAGsB/E,CALoB,CAc5C,KAAAu6B,aAAA,CAAoBC,QAAQ,EAAG,CAC7BJ,CAAA,CAAU,CAAA,CADmB,CAK/B,KAAA3d,KAAA,CAAY,CAAC,WAAD,CAAc,SAAd,CAAyB,QAAQ,CAACuD,CAAD,CAAY1K,CAAZ,CAAqB,CAyGhEmlB,QAASA,EAAa,CAACjb,CAAD,CAAS4R,CAAT,CAAqBxR,CAArB,CAA+B7a,CAA/B,CAAqC,CACzD,GAAMya,CAAAA,CAAN,EAAgB,CAAApjB,CAAA,CAASojB,CAAA4Q,OAAT,CAAhB,CACE,KAAMp2B,EAAA,CAAO,aAAP,CAAA,CAAsB,OAAtB,CAEJ+K,CAFI,CAEEqsB,CAFF,CAAN,CAKF5R,CAAA4Q,OAAA,CAAcgB,CAAd,CAAA,CAA4BxR,CAP6B,CA5E3D,MAAO,SAAQ,CAAC8a,CAAD,CAAalb,CAAb,CAAqBmb,CAArB,CAA4BC,CAA5B,CAAmC,CAAA,IAQ5Chb,CAR4C,CAQ3B5f,CAR2B,CAQdoxB,CAClCuJ,EAAA,CAAkB,CAAA,CAAlB,GAAQA,CACJC,EAAJ,EAAapgC,CAAA,CAASogC,CAAT,CAAb,GACExJ,CADF,CACewJ,CADf,CAIA,IAAIpgC,CAAA,CAASkgC,CAAT,CAAJ,CAA0B,CACxBv6B,CAAA,CAAQu6B,CAAAv6B,MAAA,CAAiBipB,EAAjB,CACR,IAAKjpB,CAAAA,CAAL,CACE,KAAM06B,GAAA,CAAkB,SAAlB,CAE8CH,CAF9C,CAAN,CAIF16B,CAAA,CAAcG,CAAA,CAAM,CAAN,CACdixB,EADA,CACaA,CADb,EAC2BjxB,CAAA,CAAM,CAAN,CAC3Bu6B,EAAA,CAAaxN,CAAAnyB,eAAA,CAA2BiF,CAA3B,CAAA,CACPktB,CAAA,CAAYltB,CAAZ,CADO,CAEPkJ,EAAA,CAAOsW,CAAA4Q,OAAP,CAAsBpwB,CAAtB,CAAmC,CAAA,CAAnC,CAFO,GAGJo6B,CAAA,CAAUlxB,EAAA,CAAOoM,CAAP,CAAgBtV,CAAhB,CAA6B,CAAA,CAA7B,CAAV,CAA+CjG,CAH3C,CAKbgP,GAAA,CAAY2xB,CAAZ;AAAwB16B,CAAxB,CAAqC,CAAA,CAArC,CAdwB,CAiB1B,GAAI26B,CAAJ,CAoBE,MATIG,EASiB,CATKl9B,CAACnD,CAAA,CAAQigC,CAAR,CAAA,CACzBA,CAAA,CAAWA,CAAAtgC,OAAX,CAA+B,CAA/B,CADyB,CACWsgC,CADZ98B,WASL,CAPrBgiB,CAOqB,CAPVvlB,MAAAgD,OAAA,CAAcy9B,CAAd,EAAqC,IAArC,CAOU,CALjB1J,CAKiB,EAJnBqJ,CAAA,CAAcjb,CAAd,CAAsB4R,CAAtB,CAAkCxR,CAAlC,CAA4C5f,CAA5C,EAA2D06B,CAAA31B,KAA3D,CAImB,CAAApI,CAAA,CAAO,QAAQ,EAAG,CACrC,IAAI0hB,EAAS2B,CAAAla,OAAA,CAAiB40B,CAAjB,CAA6B9a,CAA7B,CAAuCJ,CAAvC,CAA+Cxf,CAA/C,CACTqe,EAAJ,GAAeuB,CAAf,GAA4BxjB,CAAA,CAASiiB,CAAT,CAA5B,EAAgDvjB,CAAA,CAAWujB,CAAX,CAAhD,IACEuB,CACA,CADWvB,CACX,CAAI+S,CAAJ,EAEEqJ,CAAA,CAAcjb,CAAd,CAAsB4R,CAAtB,CAAkCxR,CAAlC,CAA4C5f,CAA5C,EAA2D06B,CAAA31B,KAA3D,CAJJ,CAOA,OAAO6a,EAT8B,CAAlB,CAUlB,CACDA,SAAUA,CADT,CAEDwR,WAAYA,CAFX,CAVkB,CAgBvBxR,EAAA,CAAWI,CAAAhC,YAAA,CAAsB0c,CAAtB,CAAkClb,CAAlC,CAA0Cxf,CAA1C,CAEPoxB,EAAJ,EACEqJ,CAAA,CAAcjb,CAAd,CAAsB4R,CAAtB,CAAkCxR,CAAlC,CAA4C5f,CAA5C,EAA2D06B,CAAA31B,KAA3D,CAGF,OAAO6a,EAzEyC,CA7Bc,CAAtD,CA/BiB,CA6K/BjN,QAASA,GAAiB,EAAG,CAC3B,IAAA8J,KAAA,CAAY,CAAC,SAAD,CAAY,QAAQ,CAAC5iB,CAAD,CAAS,CACvC,MAAOkJ,EAAA,CAAOlJ,CAAAC,SAAP,CADgC,CAA7B,CADe,CA8C7B+Y,QAASA,GAAyB,EAAG,CACnC,IAAA4J,KAAA,CAAY,CAAC,MAAD,CAAS,QAAQ,CAAC3I,CAAD,CAAO,CAClC,MAAO,SAAQ,CAACinB,CAAD,CAAYC,CAAZ,CAAmB,CAChClnB,CAAA+O,MAAAthB,MAAA,CAAiBuS,CAAjB,CAAuBjX,SAAvB,CADgC,CADA,CAAxB,CADuB,CAiBrCo+B,QAASA,GAAc,CAACC,CAAD,CAAI,CACzB,MAAI9+B,EAAA,CAAS8+B,CAAT,CAAJ,CACS1+B,EAAA,CAAO0+B,CAAP,CAAA,CAAYA,CAAAC,YAAA,EAAZ,CAA8Bz5B,EAAA,CAAOw5B,CAAP,CADvC,CAGOA,CAJkB,CA75RY;AAq6RvC3nB,QAASA,GAA4B,EAAG,CAiBtC,IAAAkJ,KAAA,CAAYC,QAAQ,EAAG,CACrB,MAAO0e,SAA0B,CAACC,CAAD,CAAS,CACxC,GAAKA,CAAAA,CAAL,CAAa,MAAO,EACpB,KAAIv3B,EAAQ,EACZ3I,GAAA,CAAckgC,CAAd,CAAsB,QAAQ,CAAC5/B,CAAD,CAAQZ,CAAR,CAAa,CAC3B,IAAd,GAAIY,CAAJ,EAAsBoC,CAAA,CAAYpC,CAAZ,CAAtB,GACIhB,CAAA,CAAQgB,CAAR,CAAJ,CACEf,CAAA,CAAQe,CAAR,CAAe,QAAQ,CAACy/B,CAAD,CAAIjE,CAAJ,CAAO,CAC5BnzB,CAAA/D,KAAA,CAAWiE,EAAA,CAAenJ,CAAf,CAAX,CAAkC,GAAlC,CAAwCmJ,EAAA,CAAei3B,EAAA,CAAeC,CAAf,CAAf,CAAxC,CAD4B,CAA9B,CADF,CAKEp3B,CAAA/D,KAAA,CAAWiE,EAAA,CAAenJ,CAAf,CAAX,CAAiC,GAAjC,CAAuCmJ,EAAA,CAAei3B,EAAA,CAAex/B,CAAf,CAAf,CAAvC,CANF,CADyC,CAA3C,CAWA,OAAOqI,EAAAG,KAAA,CAAW,GAAX,CAdiC,CADrB,CAjBe,CAqCxCwP,QAASA,GAAkC,EAAG,CA4C5C,IAAAgJ,KAAA,CAAYC,QAAQ,EAAG,CACrB,MAAO4e,SAAkC,CAACD,CAAD,CAAS,CAMhDE,QAASA,EAAS,CAACC,CAAD,CAAc12B,CAAd,CAAsB22B,CAAtB,CAAgC,CAC5B,IAApB,GAAID,CAAJ,EAA4B39B,CAAA,CAAY29B,CAAZ,CAA5B,GACI/gC,CAAA,CAAQ+gC,CAAR,CAAJ,CACE9gC,CAAA,CAAQ8gC,CAAR,CAAqB,QAAQ,CAAC//B,CAAD,CAAQ,CACnC8/B,CAAA,CAAU9/B,CAAV,CAAiBqJ,CAAjB,CAA0B,IAA1B,CADmC,CAArC,CADF,CAIW1I,CAAA,CAASo/B,CAAT,CAAJ,EAA8B,CAAAh/B,EAAA,CAAOg/B,CAAP,CAA9B,CACLrgC,EAAA,CAAcqgC,CAAd,CAA2B,QAAQ,CAAC//B,CAAD,CAAQZ,CAAR,CAAa,CAC9C0gC,CAAA,CAAU9/B,CAAV,CAAiBqJ,CAAjB,EACK22B,CAAA,CAAW,EAAX,CAAgB,GADrB,EAEI5gC,CAFJ,EAGK4gC,CAAA,CAAW,EAAX,CAAgB,GAHrB,EAD8C,CAAhD,CADK,CAQL33B,CAAA/D,KAAA,CAAWiE,EAAA,CAAec,CAAf,CAAX,CAAoC,GAApC,CAA0Cd,EAAA,CAAei3B,EAAA,CAAeO,CAAf,CAAf,CAA1C,CAbF,CADgD,CALlD,GAAKH,CAAAA,CAAL,CAAa,MAAO,EACpB,KAAIv3B,EAAQ,EACZy3B,EAAA,CAAUF,CAAV,CAAkB,EAAlB,CAAsB,CAAA,CAAtB,CACA,OAAOv3B,EAAAG,KAAA,CAAW,GAAX,CAJyC,CAD7B,CA5CqB,CAwE9Cy3B,QAASA,GAA4B,CAACv1B,CAAD;AAAOw1B,CAAP,CAAgB,CACnD,GAAInhC,CAAA,CAAS2L,CAAT,CAAJ,CAAoB,CAElB,IAAIy1B,EAAWz1B,CAAA5C,QAAA,CAAas4B,EAAb,CAAqC,EAArC,CAAAjkB,KAAA,EAEf,IAAIgkB,CAAJ,CAAc,CACZ,IAAIE,EAAcH,CAAA,CAAQ,cAAR,CACd,EAAC,CAAD,CAAC,CAAD,EAAC,CAAD,GAAC,CAAA,QAAA,CAAA,EAAA,CAAD,IAWN,CAXM,EAUFI,CAVE,CAAkE/+B,CAUxDmD,MAAA,CAAU67B,EAAV,CAVV,GAWcC,EAAA,CAAUF,CAAA,CAAU,CAAV,CAAV,CAAAj8B,KAAA,CAXoD9C,CAWpD,CAXd,CAAA,EAAJ,GACEmJ,CADF,CACSrE,EAAA,CAAS85B,CAAT,CADT,CAFY,CAJI,CAYpB,MAAOz1B,EAb4C,CA2BrD+1B,QAASA,GAAY,CAACP,CAAD,CAAU,CAAA,IACzB7jB,EAAShX,EAAA,EADgB,CACHxF,CAQtBd,EAAA,CAASmhC,CAAT,CAAJ,CACEjhC,CAAA,CAAQihC,CAAA78B,MAAA,CAAc,IAAd,CAAR,CAA6B,QAAQ,CAACq9B,CAAD,CAAO,CAC1C7gC,CAAA,CAAI6gC,CAAA98B,QAAA,CAAa,GAAb,CACS,KAAA,EAAAJ,CAAA,CAAU2Y,CAAA,CAAKukB,CAAAzX,OAAA,CAAY,CAAZ,CAAeppB,CAAf,CAAL,CAAV,CAAoC,EAAA,CAAAsc,CAAA,CAAKukB,CAAAzX,OAAA,CAAYppB,CAAZ,CAAgB,CAAhB,CAAL,CAR/CT,EAAJ,GACEid,CAAA,CAAOjd,CAAP,CADF,CACgBid,CAAA,CAAOjd,CAAP,CAAA,CAAcid,CAAA,CAAOjd,CAAP,CAAd,CAA4B,IAA5B,CAAmC4G,CAAnC,CAAyCA,CADzD,CAM4C,CAA5C,CADF,CAKWrF,CAAA,CAASu/B,CAAT,CALX,EAMEjhC,CAAA,CAAQihC,CAAR,CAAiB,QAAQ,CAACS,CAAD,CAAYC,CAAZ,CAAuB,CACjC,IAAA,EAAAp9B,CAAA,CAAUo9B,CAAV,CAAA,CAAsB,EAAAzkB,CAAA,CAAKwkB,CAAL,CAZjCvhC,EAAJ,GACEid,CAAA,CAAOjd,CAAP,CADF,CACgBid,CAAA,CAAOjd,CAAP,CAAA,CAAcid,CAAA,CAAOjd,CAAP,CAAd,CAA4B,IAA5B,CAAmC4G,CAAnC,CAAyCA,CADzD,CAWgD,CAAhD,CAKF,OAAOqW,EApBsB,CAoC/BwkB,QAASA,GAAa,CAACX,CAAD,CAAU,CAC9B,IAAIY,CAEJ,OAAO,SAAQ,CAACx3B,CAAD,CAAO,CACfw3B,CAAL,GAAiBA,CAAjB,CAA+BL,EAAA,CAAaP,CAAb,CAA/B,CAEA,OAAI52B,EAAJ,EACMtJ,CAIGA,CAJK8gC,CAAA,CAAWt9B,CAAA,CAAU8F,CAAV,CAAX,CAILtJ,CAHO,IAAK,EAGZA,GAHHA,CAGGA,GAFLA,CAEKA,CAFG,IAEHA,EAAAA,CALT,EAQO8gC,CAXa,CAHQ,CA8BhCC,QAASA,GAAa,CAACr2B,CAAD;AAAOw1B,CAAP,CAAgBc,CAAhB,CAAwBC,CAAxB,CAA6B,CACjD,GAAI5hC,CAAA,CAAW4hC,CAAX,CAAJ,CACE,MAAOA,EAAA,CAAIv2B,CAAJ,CAAUw1B,CAAV,CAAmBc,CAAnB,CAGT/hC,EAAA,CAAQgiC,CAAR,CAAa,QAAQ,CAACt7B,CAAD,CAAK,CACxB+E,CAAA,CAAO/E,CAAA,CAAG+E,CAAH,CAASw1B,CAAT,CAAkBc,CAAlB,CADiB,CAA1B,CAIA,OAAOt2B,EAT0C,CAwBnDkN,QAASA,GAAa,EAAG,CAkCvB,IAAIspB,EAAW,IAAAA,SAAXA,CAA2B,CAE7BC,kBAAmB,CAAClB,EAAD,CAFU,CAK7BmB,iBAAkB,CAAC,QAAQ,CAACC,CAAD,CAAI,CAC7B,MAAO1gC,EAAA,CAAS0gC,CAAT,CAAA,EAz+QmB,eAy+QnB,GAz+QJn/B,EAAA3C,KAAA,CAy+Q2B8hC,CAz+Q3B,CAy+QI,EA/9QmB,eA+9QnB,GA/9QJn/B,EAAA3C,KAAA,CA+9QyC8hC,CA/9QzC,CA+9QI,EAp+QmB,mBAo+QnB,GAp+QJn/B,EAAA3C,KAAA,CAo+Q2D8hC,CAp+Q3D,CAo+QI,CAA4Dp7B,EAAA,CAAOo7B,CAAP,CAA5D,CAAwEA,CADlD,CAAb,CALW,CAU7BnB,QAAS,CACPoB,OAAQ,CACN,OAAU,mCADJ,CADD,CAIPvN,KAAQlvB,EAAA,CAAY08B,EAAZ,CAJD,CAKP3f,IAAQ/c,EAAA,CAAY08B,EAAZ,CALD,CAMPC,MAAQ38B,EAAA,CAAY08B,EAAZ,CAND,CAVoB,CAmB7BE,eAAgB,YAnBa,CAoB7BC,eAAgB,cApBa,CAsB7BC,gBAAiB,sBAtBY,CAA/B,CAyBIC,EAAgB,CAAA,CAoBpB,KAAAA,cAAA,CAAqBC,QAAQ,CAAC7hC,CAAD,CAAQ,CACnC,MAAIqC,EAAA,CAAUrC,CAAV,CAAJ;CACE4hC,CACO,CADS,CAAE5hC,CAAAA,CACX,CAAA,IAFT,EAIO4hC,CAL4B,CAqBrC,KAAIE,EAAuB,IAAAC,aAAvBD,CAA2C,EAE/C,KAAA9gB,KAAA,CAAY,CAAC,cAAD,CAAiB,gBAAjB,CAAmC,eAAnC,CAAoD,YAApD,CAAkE,IAAlE,CAAwE,WAAxE,CACR,QAAQ,CAAC/I,CAAD,CAAeoC,CAAf,CAA+BxD,CAA/B,CAA8C4B,CAA9C,CAA0DE,CAA1D,CAA8D4L,CAA9D,CAAyE,CAqiBnF5M,QAASA,EAAK,CAACqqB,CAAD,CAAgB,CA+E5Bb,QAASA,EAAiB,CAACc,CAAD,CAAW,CAEnC,IAAIC,EAAOhhC,CAAA,CAAO,EAAP,CAAW+gC,CAAX,CAITC,EAAAx3B,KAAA,CAHGu3B,CAAAv3B,KAAL,CAGcq2B,EAAA,CAAckB,CAAAv3B,KAAd,CAA6Bu3B,CAAA/B,QAA7B,CAA+C+B,CAAAjB,OAA/C,CAAgE53B,CAAA+3B,kBAAhE,CAHd,CACcc,CAAAv3B,KAIIs2B,EAAAA,CAAAiB,CAAAjB,OAAlB,OA7uBC,IA6uBM,EA7uBCA,CA6uBD,EA7uBoB,GA6uBpB,CA7uBWA,CA6uBX,CACHkB,CADG,CAEHvpB,CAAAwpB,OAAA,CAAUD,CAAV,CAV+B,CAarCE,QAASA,EAAgB,CAAClC,CAAD,CAAU92B,CAAV,CAAkB,CAAA,IACrCi5B,CADqC,CACtBC,EAAmB,EAEtCrjC,EAAA,CAAQihC,CAAR,CAAiB,QAAQ,CAACqC,CAAD,CAAWC,CAAX,CAAmB,CACtCnjC,CAAA,CAAWkjC,CAAX,CAAJ,EACEF,CACA,CADgBE,CAAA,CAASn5B,CAAT,CAChB,CAAqB,IAArB,EAAIi5B,CAAJ,GACEC,CAAA,CAAiBE,CAAjB,CADF,CAC6BH,CAD7B,CAFF,EAMEC,CAAA,CAAiBE,CAAjB,CANF,CAM6BD,CAPa,CAA5C,CAWA,OAAOD,EAdkC,CA1F3C,GAAK,CAAAz3B,EAAAlK,SAAA,CAAiBqhC,CAAjB,CAAL,CACE,KAAMzjC,EAAA,CAAO,OAAP,CAAA,CAAgB,QAAhB,CAA0FyjC,CAA1F,CAAN,CAGF,IAAI54B,EAASlI,CAAA,CAAO,CAClB0N,OAAQ,KADU,CAElBwyB,iBAAkBF,CAAAE,iBAFA;AAGlBD,kBAAmBD,CAAAC,kBAHD,CAIlBQ,gBAAiBT,CAAAS,gBAJC,CAAP,CAKVK,CALU,CAOb54B,EAAA82B,QAAA,CAgGAuC,QAAqB,CAACr5B,CAAD,CAAS,CAAA,IACxBs5B,EAAaxB,CAAAhB,QADW,CAExByC,EAAazhC,CAAA,CAAO,EAAP,CAAWkI,CAAA82B,QAAX,CAFW,CAGxB0C,CAHwB,CAGTC,CAHS,CAGeC,CAHf,CAK5BJ,EAAaxhC,CAAA,CAAO,EAAP,CAAWwhC,CAAApB,OAAX,CAA8BoB,CAAA,CAAWl/B,CAAA,CAAU4F,CAAAwF,OAAV,CAAX,CAA9B,CAGb,EAAA,CACA,IAAKg0B,CAAL,GAAsBF,EAAtB,CAAkC,CAChCG,CAAA,CAAyBr/B,CAAA,CAAUo/B,CAAV,CAEzB,KAAKE,CAAL,GAAsBH,EAAtB,CACE,GAAIn/B,CAAA,CAAUs/B,CAAV,CAAJ,GAAiCD,CAAjC,CACE,SAAS,CAIbF,EAAA,CAAWC,CAAX,CAAA,CAA4BF,CAAA,CAAWE,CAAX,CATI,CAalC,MAAOR,EAAA,CAAiBO,CAAjB,CAA6B99B,EAAA,CAAYuE,CAAZ,CAA7B,CAtBqB,CAhGb,CAAa44B,CAAb,CACjB54B,EAAAwF,OAAA,CAAgBwB,EAAA,CAAUhH,CAAAwF,OAAV,CAChBxF,EAAAu4B,gBAAA,CAAyB5iC,CAAA,CAASqK,CAAAu4B,gBAAT,CAAA,CACvBpd,CAAAhZ,IAAA,CAAcnC,CAAAu4B,gBAAd,CADuB,CACiBv4B,CAAAu4B,gBAuB1C,KAAIoB,EAAQ,CArBQC,QAAQ,CAAC55B,CAAD,CAAS,CACnC,IAAI82B,EAAU92B,CAAA82B,QAAd,CACI+C,EAAUlC,EAAA,CAAc33B,CAAAsB,KAAd,CAA2Bm2B,EAAA,CAAcX,CAAd,CAA3B,CAAmD5hC,CAAnD,CAA8D8K,CAAAg4B,iBAA9D,CAGVh/B,EAAA,CAAY6gC,CAAZ,CAAJ,EACEhkC,CAAA,CAAQihC,CAAR,CAAiB,QAAQ,CAAClgC,CAAD,CAAQwiC,CAAR,CAAgB,CACb,cAA1B,GAAIh/B,CAAA,CAAUg/B,CAAV,CAAJ,EACI,OAAOtC,CAAA,CAAQsC,CAAR,CAF4B,CAAzC,CAOEpgC,EAAA,CAAYgH,CAAA85B,gBAAZ,CAAJ;AAA4C,CAAA9gC,CAAA,CAAY8+B,CAAAgC,gBAAZ,CAA5C,GACE95B,CAAA85B,gBADF,CAC2BhC,CAAAgC,gBAD3B,CAKA,OAAOC,EAAA,CAAQ/5B,CAAR,CAAgB65B,CAAhB,CAAAxK,KAAA,CAA8B0I,CAA9B,CAAiDA,CAAjD,CAlB4B,CAqBzB,CAAgB7iC,CAAhB,CAAZ,CACI8kC,EAAUzqB,CAAA0qB,KAAA,CAAQj6B,CAAR,CAYd,KATAnK,CAAA,CAAQqkC,CAAR,CAA8B,QAAQ,CAACC,CAAD,CAAc,CAClD,CAAIA,CAAAC,QAAJ,EAA2BD,CAAAE,aAA3B,GACEV,CAAA/4B,QAAA,CAAcu5B,CAAAC,QAAd,CAAmCD,CAAAE,aAAnC,CAEF,EAAIF,CAAAtB,SAAJ,EAA4BsB,CAAAG,cAA5B,GACEX,CAAAz+B,KAAA,CAAWi/B,CAAAtB,SAAX,CAAiCsB,CAAAG,cAAjC,CALgD,CAApD,CASA,CAAOX,CAAApkC,OAAP,CAAA,CAAqB,CACfglC,CAAAA,CAASZ,CAAAjf,MAAA,EACb,KAAI8f,EAAWb,CAAAjf,MAAA,EAAf,CAEAsf,EAAUA,CAAA3K,KAAA,CAAakL,CAAb,CAAqBC,CAArB,CAJS,CAOrBR,CAAAS,QAAA,CAAkBC,QAAQ,CAACn+B,CAAD,CAAK,CAC7B2H,EAAA,CAAY3H,CAAZ,CAAgB,IAAhB,CAEAy9B,EAAA3K,KAAA,CAAa,QAAQ,CAACwJ,CAAD,CAAW,CAC9Bt8B,CAAA,CAAGs8B,CAAAv3B,KAAH,CAAkBu3B,CAAAjB,OAAlB,CAAmCiB,CAAA/B,QAAnC,CAAqD92B,CAArD,CAD8B,CAAhC,CAGA,OAAOg6B,EANsB,CAS/BA,EAAAhc,MAAA,CAAgB2c,QAAQ,CAACp+B,CAAD,CAAK,CAC3B2H,EAAA,CAAY3H,CAAZ,CAAgB,IAAhB,CAEAy9B,EAAA3K,KAAA,CAAa,IAAb,CAAmB,QAAQ,CAACwJ,CAAD,CAAW,CACpCt8B,CAAA,CAAGs8B,CAAAv3B,KAAH,CAAkBu3B,CAAAjB,OAAlB,CAAmCiB,CAAA/B,QAAnC,CAAqD92B,CAArD,CADoC,CAAtC,CAGA,OAAOg6B,EANoB,CAS7B,OAAOA,EA7EqB,CAriBqD;AAuzBnFD,QAASA,EAAO,CAAC/5B,CAAD,CAAS65B,CAAT,CAAkB,CA+DhCe,QAASA,EAAI,CAAChD,CAAD,CAASiB,CAAT,CAAmBgC,CAAnB,CAAkCC,CAAlC,CAA8C,CAUzDC,QAASA,EAAkB,EAAG,CAC5BC,CAAA,CAAenC,CAAf,CAAyBjB,CAAzB,CAAiCiD,CAAjC,CAAgDC,CAAhD,CAD4B,CAT1B1gB,CAAJ,GAx+BC,GAy+BC,EAAcwd,CAAd,EAz+ByB,GAy+BzB,CAAcA,CAAd,CACExd,CAAA5B,IAAA,CAAUiG,CAAV,CAAe,CAACmZ,CAAD,CAASiB,CAAT,CAAmBxB,EAAA,CAAawD,CAAb,CAAnB,CAAgDC,CAAhD,CAAf,CADF,CAIE1gB,CAAA+H,OAAA,CAAa1D,CAAb,CALJ,CAaI+Z,EAAJ,CACEnpB,CAAA4rB,YAAA,CAAuBF,CAAvB,CADF,EAGEA,CAAA,EACA,CAAK1rB,CAAA6rB,QAAL,EAAyB7rB,CAAAhO,OAAA,EAJ3B,CAdyD,CA0B3D25B,QAASA,EAAc,CAACnC,CAAD,CAAWjB,CAAX,CAAmBd,CAAnB,CAA4BgE,CAA5B,CAAwC,CAE7DlD,CAAA,CAASvJ,IAAAC,IAAA,CAASsJ,CAAT,CAAiB,CAAjB,CAET,EArgCC,GAqgCA,EAAUA,CAAV,EArgC0B,GAqgC1B,CAAUA,CAAV,CAAoBuD,CAAAC,QAApB,CAAuCD,CAAApC,OAAxC,EAAyD,CACvDz3B,KAAMu3B,CADiD,CAEvDjB,OAAQA,CAF+C,CAGvDd,QAASW,EAAA,CAAcX,CAAd,CAH8C,CAIvD92B,OAAQA,CAJ+C,CAKvD86B,WAAYA,CAL2C,CAAzD,CAJ6D,CAa/DO,QAASA,EAAwB,CAAC7hB,CAAD,CAAS,CACxCwhB,CAAA,CAAexhB,CAAAlY,KAAf,CAA4BkY,CAAAoe,OAA5B,CAA2Cn8B,EAAA,CAAY+d,CAAAsd,QAAA,EAAZ,CAA3C,CAA0Etd,CAAAshB,WAA1E,CADwC,CAI1CQ,QAASA,EAAgB,EAAG,CAC1B,IAAItU,EAAMzY,CAAAgtB,gBAAA/gC,QAAA,CAA8BwF,CAA9B,CACG,GAAb,GAAIgnB,CAAJ,EAAgBzY,CAAAgtB,gBAAA9gC,OAAA,CAA6BusB,CAA7B,CAAkC,CAAlC,CAFU,CA1GI,IAC5BmU,EAAW5rB,CAAAiR,MAAA,EADiB,CAE5BwZ,EAAUmB,CAAAnB,QAFkB,CAG5B5f,CAH4B,CAI5BohB,CAJ4B,CAK5BjC,EAAav5B,CAAA82B,QALe,CAM5BrY,EAAMgd,CAAA,CAASz7B,CAAAye,IAAT,CAAqBze,CAAAu4B,gBAAA,CAAuBv4B,CAAAw2B,OAAvB,CAArB,CAEVjoB;CAAAgtB,gBAAArgC,KAAA,CAA2B8E,CAA3B,CACAg6B,EAAA3K,KAAA,CAAaiM,CAAb,CAA+BA,CAA/B,CAGKlhB,EAAApa,CAAAoa,MAAL,EAAqBA,CAAA0d,CAAA1d,MAArB,EAAyD,CAAA,CAAzD,GAAwCpa,CAAAoa,MAAxC,EACuB,KADvB,GACKpa,CAAAwF,OADL,EACkD,OADlD,GACgCxF,CAAAwF,OADhC,GAEE4U,CAFF,CAEU7iB,CAAA,CAASyI,CAAAoa,MAAT,CAAA,CAAyBpa,CAAAoa,MAAzB,CACA7iB,CAAA,CAASugC,CAAA1d,MAAT,CAAA,CAA2B0d,CAAA1d,MAA3B,CACAshB,CAJV,CAOIthB,EAAJ,GACEohB,CACA,CADaphB,CAAAjY,IAAA,CAAUsc,CAAV,CACb,CAAIxlB,CAAA,CAAUuiC,CAAV,CAAJ,CACoBA,CAAlB,EAj2SMvlC,CAAA,CAi2SYulC,CAj2SDnM,KAAX,CAi2SN,CAEEmM,CAAAnM,KAAA,CAAgBgM,CAAhB,CAA0CA,CAA1C,CAFF,CAKMzlC,CAAA,CAAQ4lC,CAAR,CAAJ,CACER,CAAA,CAAeQ,CAAA,CAAW,CAAX,CAAf,CAA8BA,CAAA,CAAW,CAAX,CAA9B,CAA6C//B,EAAA,CAAY+/B,CAAA,CAAW,CAAX,CAAZ,CAA7C,CAAyEA,CAAA,CAAW,CAAX,CAAzE,CADF,CAGER,CAAA,CAAeQ,CAAf,CAA2B,GAA3B,CAAgC,EAAhC,CAAoC,IAApC,CATN,CAcEphB,CAAA5B,IAAA,CAAUiG,CAAV,CAAeub,CAAf,CAhBJ,CAuBIhhC,EAAA,CAAYwiC,CAAZ,CAAJ,GAQE,CAPIG,CAOJ,CAPgBC,EAAA,CAAgB57B,CAAAye,IAAhB,CAAA,CACVxN,CAAA,EAAA,CAAiBjR,CAAAq4B,eAAjB,EAA0CP,CAAAO,eAA1C,CADU,CAEVnjC,CAKN,IAHEqkC,CAAA,CAAYv5B,CAAAs4B,eAAZ,EAAqCR,CAAAQ,eAArC,CAGF,CAHmEqD,CAGnE,EAAA9sB,CAAA,CAAa7O,CAAAwF,OAAb,CAA4BiZ,CAA5B,CAAiCob,CAAjC,CAA0Ce,CAA1C,CAAgDrB,CAAhD,CAA4Dv5B,CAAA67B,QAA5D,CACI77B,CAAA85B,gBADJ,CAC4B95B,CAAA87B,aAD5B,CARF,CAYA,OAAO9B,EAtDyB,CAiHlCyB,QAASA,EAAQ,CAAChd,CAAD,CAAMsd,CAAN,CAAwB,CACT,CAA9B,CAAIA,CAAAxmC,OAAJ,GACEkpB,CADF,GACgC,EAAtB,EAACA,CAAAjkB,QAAA,CAAY,GAAZ,CAAD,CAA2B,GAA3B,CAAiC,GAD3C,EACkDuhC,CADlD,CAGA;MAAOtd,EAJgC,CAt6BzC,IAAIid,EAAejuB,CAAA,CAAc,OAAd,CAKnBqqB,EAAAS,gBAAA,CAA2B5iC,CAAA,CAASmiC,CAAAS,gBAAT,CAAA,CACzBpd,CAAAhZ,IAAA,CAAc21B,CAAAS,gBAAd,CADyB,CACiBT,CAAAS,gBAO5C,KAAI2B,EAAuB,EAE3BrkC,EAAA,CAAQ6iC,CAAR,CAA8B,QAAQ,CAACsD,CAAD,CAAqB,CACzD9B,CAAAt5B,QAAA,CAA6BjL,CAAA,CAASqmC,CAAT,CAAA,CACvB7gB,CAAAhZ,IAAA,CAAc65B,CAAd,CADuB,CACa7gB,CAAAla,OAAA,CAAiB+6B,CAAjB,CAD1C,CADyD,CAA3D,CA2pBAztB,EAAAgtB,gBAAA,CAAwB,EA4GxBU,UAA2B,CAACvmB,CAAD,CAAQ,CACjC7f,CAAA,CAAQmC,SAAR,CAAmB,QAAQ,CAACkI,CAAD,CAAO,CAChCqO,CAAA,CAAMrO,CAAN,CAAA,CAAc,QAAQ,CAACue,CAAD,CAAMze,CAAN,CAAc,CAClC,MAAOuO,EAAA,CAAMzW,CAAA,CAAO,EAAP,CAAWkI,CAAX,EAAqB,EAArB,CAAyB,CACpCwF,OAAQtF,CAD4B,CAEpCue,IAAKA,CAF+B,CAAzB,CAAN,CAD2B,CADJ,CAAlC,CADiC,CAAnCwd,CA1DA,CAAmB,KAAnB,CAA0B,QAA1B,CAAoC,MAApC,CAA4C,OAA5C,CAsEAC,UAAmC,CAACh8B,CAAD,CAAO,CACxCrK,CAAA,CAAQmC,SAAR,CAAmB,QAAQ,CAACkI,CAAD,CAAO,CAChCqO,CAAA,CAAMrO,CAAN,CAAA,CAAc,QAAQ,CAACue,CAAD,CAAMnd,CAAN,CAAYtB,CAAZ,CAAoB,CACxC,MAAOuO,EAAA,CAAMzW,CAAA,CAAO,EAAP,CAAWkI,CAAX,EAAqB,EAArB,CAAyB,CACpCwF,OAAQtF,CAD4B,CAEpCue,IAAKA,CAF+B,CAGpCnd,KAAMA,CAH8B,CAAzB,CAAN,CADiC,CADV,CAAlC,CADwC,CAA1C46B,CA9BA,CAA2B,MAA3B,CAAmC,KAAnC,CAA0C,OAA1C,CAYA3tB,EAAAupB,SAAA,CAAiBA,CAGjB,OAAOvpB,EArxB4E,CADzE,CAtGW,CAwhCzB4tB,QAASA,GAAS,EAAG,CACjB,MAAO,KAAInnC,CAAAonC,eADM,CA/pUkB;AAmrUvCttB,QAASA,GAAoB,EAAG,CAC9B,IAAA8I,KAAA,CAAY,CAAC,UAAD,CAAa,SAAb,CAAwB,WAAxB,CAAqC,QAAQ,CAACrK,CAAD,CAAWkD,CAAX,CAAoB5C,CAApB,CAA+B,CACtF,MAAOwuB,GAAA,CAAkB9uB,CAAlB,CAA4B4uB,EAA5B,CAAuC5uB,CAAAiT,MAAvC,CAAuD/P,CAAAhP,QAAA66B,UAAvD,CAAkFzuB,CAAA,CAAU,CAAV,CAAlF,CAD+E,CAA5E,CADkB,CAMhCwuB,QAASA,GAAiB,CAAC9uB,CAAD,CAAW4uB,CAAX,CAAsBI,CAAtB,CAAqCD,CAArC,CAAgDE,CAAhD,CAA6D,CA8GrFC,QAASA,EAAQ,CAAChe,CAAD,CAAMie,CAAN,CAAkB9B,CAAlB,CAAwB,CAAA,IAInC5yB,EAASw0B,CAAAvqB,cAAA,CAA0B,QAA1B,CAJ0B,CAIWoN,EAAW,IAC7DrX,EAAA6L,KAAA,CAAc,iBACd7L,EAAAtQ,IAAA,CAAa+mB,CACbzW,EAAA20B,MAAA,CAAe,CAAA,CAEftd,EAAA,CAAWA,QAAQ,CAACtI,CAAD,CAAQ,CACH/O,CA7vPtBmM,oBAAA,CA6vP8BN,MA7vP9B,CA6vPsCwL,CA7vPtC,CAAsC,CAAA,CAAtC,CA8vPsBrX,EA9vPtBmM,oBAAA,CA8vP8BN,OA9vP9B,CA8vPuCwL,CA9vPvC,CAAsC,CAAA,CAAtC,CA+vPAmd,EAAAI,KAAA7mB,YAAA,CAA6B/N,CAA7B,CACAA,EAAA,CAAS,IACT,KAAI4vB,EAAU,EAAd,CACIzH,EAAO,SAEPpZ,EAAJ,GACqB,MAInB,GAJIA,CAAAlD,KAIJ,EAJ8ByoB,CAAA,CAAUI,CAAV,CAAAG,OAI9B,GAHE9lB,CAGF,CAHU,CAAElD,KAAM,OAAR,CAGV,EADAsc,CACA,CADOpZ,CAAAlD,KACP,CAAA+jB,CAAA,CAAwB,OAAf,GAAA7gB,CAAAlD,KAAA,CAAyB,GAAzB,CAA+B,GAL1C,CAQI+mB,EAAJ,EACEA,CAAA,CAAKhD,CAAL,CAAazH,CAAb,CAjBuB,CAqBRnoB,EApxPjB80B,iBAAA,CAoxPyBjpB,MApxPzB;AAoxPiCwL,CApxPjC,CAAmC,CAAA,CAAnC,CAqxPiBrX,EArxPjB80B,iBAAA,CAqxPyBjpB,OArxPzB,CAqxPkCwL,CArxPlC,CAAmC,CAAA,CAAnC,CAsxPFmd,EAAAI,KAAA5qB,YAAA,CAA6BhK,CAA7B,CACA,OAAOqX,EAjCgC,CA5GzC,MAAO,SAAQ,CAAC7Z,CAAD,CAASiZ,CAAT,CAAckM,CAAd,CAAoBtL,CAApB,CAA8ByX,CAA9B,CAAuC+E,CAAvC,CAAgD/B,CAAhD,CAAiEgC,CAAjE,CAA+E,CA2F5FiB,QAASA,EAAc,EAAG,CACxBC,CAAA,EAAaA,CAAA,EACbC,EAAA,EAAOA,CAAAC,MAAA,EAFiB,CAK1BC,QAASA,EAAe,CAAC9d,CAAD,CAAWuY,CAAX,CAAmBiB,CAAnB,CAA6BgC,CAA7B,CAA4CC,CAA5C,CAAwD,CAE1Ena,CAAJ,GAAkBzrB,CAAlB,EACEqnC,CAAA3b,OAAA,CAAqBD,CAArB,CAEFqc,EAAA,CAAYC,CAAZ,CAAkB,IAElB5d,EAAA,CAASuY,CAAT,CAAiBiB,CAAjB,CAA2BgC,CAA3B,CAA0CC,CAA1C,CACAvtB,EAAAyR,6BAAA,CAAsCvmB,CAAtC,CAR8E,CA/FhF8U,CAAA0R,6BAAA,EACAR,EAAA,CAAMA,CAAN,EAAalR,CAAAkR,IAAA,EAEb,IAAyB,OAAzB,EAAIrkB,CAAA,CAAUoL,CAAV,CAAJ,CAAkC,CAChC,IAAIk3B,EAAa,GAAbA,CAAmB5jC,CAACwjC,CAAAr1B,QAAA,EAADnO,UAAA,CAA+B,EAA/B,CACvBwjC,EAAA,CAAUI,CAAV,CAAA,CAAwB,QAAQ,CAACp7B,CAAD,CAAO,CACrCg7B,CAAA,CAAUI,CAAV,CAAAp7B,KAAA,CAA6BA,CAC7Bg7B,EAAA,CAAUI,CAAV,CAAAG,OAAA,CAA+B,CAAA,CAFM,CAKvC,KAAIG,EAAYP,CAAA,CAAShe,CAAA/f,QAAA,CAAY,eAAZ,CAA6B,oBAA7B,CAAoDg+B,CAApD,CAAT,CACZA,CADY,CACA,QAAQ,CAAC9E,CAAD,CAASzH,CAAT,CAAe,CACrCgN,CAAA,CAAgB9d,CAAhB,CAA0BuY,CAA1B,CAAkC0E,CAAA,CAAUI,CAAV,CAAAp7B,KAAlC,CAA8D,EAA9D,CAAkE6uB,CAAlE,CACAmM,EAAA,CAAUI,CAAV,CAAA,CAAwBjkC,CAFa,CADvB,CAPgB,CAAlC,IAYO,CAEL,IAAIwkC,EAAMd,CAAA,EAEVc,EAAAG,KAAA,CAAS53B,CAAT;AAAiBiZ,CAAjB,CAAsB,CAAA,CAAtB,CACA5oB,EAAA,CAAQihC,CAAR,CAAiB,QAAQ,CAAClgC,CAAD,CAAQZ,CAAR,CAAa,CAChCiD,CAAA,CAAUrC,CAAV,CAAJ,EACIqmC,CAAAI,iBAAA,CAAqBrnC,CAArB,CAA0BY,CAA1B,CAFgC,CAAtC,CAMAqmC,EAAAK,OAAA,CAAaC,QAAsB,EAAG,CACpC,IAAIzC,EAAamC,CAAAnC,WAAbA,EAA+B,EAAnC,CAIIjC,EAAY,UAAD,EAAeoE,EAAf,CAAsBA,CAAApE,SAAtB,CAAqCoE,CAAAO,aAJpD,CAOI5F,EAAwB,IAAf,GAAAqF,CAAArF,OAAA,CAAsB,GAAtB,CAA4BqF,CAAArF,OAK1B,EAAf,GAAIA,CAAJ,GACEA,CADF,CACWiB,CAAA,CAAW,GAAX,CAA6C,MAA5B,EAAA4E,EAAA,CAAWhf,CAAX,CAAAif,SAAA,CAAqC,GAArC,CAA2C,CADvE,CAIAP,EAAA,CAAgB9d,CAAhB,CACIuY,CADJ,CAEIiB,CAFJ,CAGIoE,CAAAU,sBAAA,EAHJ,CAII7C,CAJJ,CAjBoC,CAwBlCT,EAAAA,CAAeA,QAAQ,EAAG,CAG5B8C,CAAA,CAAgB9d,CAAhB,CAA2B,EAA3B,CAA8B,IAA9B,CAAoC,IAApC,CAA0C,EAA1C,CAH4B,CAM9B4d,EAAAW,QAAA,CAAcvD,CACd4C,EAAAY,QAAA,CAAcxD,CAEVP,EAAJ,GACEmD,CAAAnD,gBADF,CACwB,CAAA,CADxB,CAIA,IAAIgC,CAAJ,CACE,GAAI,CACFmB,CAAAnB,aAAA,CAAmBA,CADjB,CAEF,MAAOz9B,CAAP,CAAU,CAQV,GAAqB,MAArB,GAAIy9B,CAAJ,CACE,KAAMz9B,EAAN,CATQ,CAcd4+B,CAAAa,KAAA,CAASnT,CAAT,CAjEK,CAoEP,GAAc,CAAd,CAAIkR,CAAJ,CACE,IAAIlb,EAAY4b,CAAA,CAAcQ,CAAd,CAA8BlB,CAA9B,CADlB,KAEyBA,EAAlB,EAvjTK5lC,CAAA,CAujTa4lC,CAvjTFxM,KAAX,CAujTL,EACLwM,CAAAxM,KAAA,CAAa0N,CAAb,CAvF0F,CAFT,CAkMvF3uB,QAASA,GAAoB,EAAG,CAC9B,IAAIumB,EAAc,IAAlB,CACIC,EAAY,IAWhB,KAAAD,YAAA;AAAmBoJ,QAAQ,CAACnnC,CAAD,CAAQ,CACjC,MAAIA,EAAJ,EACE+9B,CACO,CADO/9B,CACP,CAAA,IAFT,EAIS+9B,CALwB,CAkBnC,KAAAC,UAAA,CAAiBoJ,QAAQ,CAACpnC,CAAD,CAAQ,CAC/B,MAAIA,EAAJ,EACEg+B,CACO,CADKh+B,CACL,CAAA,IAFT,EAISg+B,CALsB,CAUjC,KAAAhd,KAAA,CAAY,CAAC,QAAD,CAAW,mBAAX,CAAgC,MAAhC,CAAwC,QAAQ,CAACzI,CAAD,CAASpB,CAAT,CAA4B4B,CAA5B,CAAkC,CAM5FsuB,QAASA,EAAM,CAACC,CAAD,CAAK,CAClB,MAAO,QAAP,CAAkBA,CADA,CAIpBC,QAASA,EAAY,CAAChO,CAAD,CAAO,CAC1B,MAAOA,EAAAzxB,QAAA,CAAa0/B,CAAb,CAAiCzJ,CAAjC,CAAAj2B,QAAA,CACG2/B,CADH,CACqBzJ,CADrB,CADmB,CAoH5BzmB,QAASA,EAAY,CAACgiB,CAAD,CAAOmO,CAAP,CAA2BlN,CAA3B,CAA2CD,CAA3C,CAAyD,CA0F5EoN,QAASA,EAAyB,CAAC3nC,CAAD,CAAQ,CACxC,GAAI,CACeA,IAAAA,EAAAA,CAvCjB,EAAA,CAAOw6B,CAAA,CACLzhB,CAAA6uB,WAAA,CAAgBpN,CAAhB,CAAgCx6B,CAAhC,CADK,CAEL+Y,CAAA9X,QAAA,CAAajB,CAAb,CAsCK,KAAA,CAAA,IAAAu6B,CAAA,EAAiB,CAAAl4B,CAAA,CAAUrC,CAAV,CAAjB,CAAoCA,CAAAA,CAAAA,CAApC,KA3MX,IAAa,IAAb,EAAIA,CAAJ,CACE,CAAA,CAAO,EADT,KAAA,CAGA,OAAQ,MAAOA,EAAf,EACE,KAAK,QAAL,CACE,KACF,MAAK,QAAL,CACEA,CAAA,CAAQ,EAAR,CAAaA,CACb,MACF,SACEA,CAAA,CAAQiG,EAAA,CAAOjG,CAAP,CAPZ,CAUA,CAAA,CAAOA,CAbP,CA2MI,MAAO,EAFL,CAGF,MAAO6jB,CAAP,CAAY,CACZ1M,CAAA,CAAkB0wB,EAAAC,OAAA,CAA0BvO,CAA1B,CAAgC1V,CAAhC,CAAlB,CADY,CAJ0B,CAzF1C0W,CAAA,CAAe,CAAEA,CAAAA,CAWjB,KAZ4E,IAExE10B,CAFwE,CAGxEkiC,CAHwE,CAIxEpkC,EAAQ,CAJgE,CAKxEq2B;AAAc,EAL0D,CAMxEgO,EAAW,EAN6D,CAOxEC,EAAa1O,CAAA56B,OAP2D,CASxE2G,EAAS,EAT+D,CAUxE4iC,EAAsB,EAE1B,CAAOvkC,CAAP,CAAeskC,CAAf,CAAA,CACE,GAAyD,EAAzD,GAAMpiC,CAAN,CAAmB0zB,CAAA31B,QAAA,CAAam6B,CAAb,CAA0Bp6B,CAA1B,CAAnB,GAC+E,EAD/E,GACOokC,CADP,CACkBxO,CAAA31B,QAAA,CAAao6B,CAAb,CAAwBn4B,CAAxB,CAAqCsiC,CAArC,CADlB,EAEMxkC,CAQJ,GARckC,CAQd,EAPEP,CAAAhB,KAAA,CAAYijC,CAAA,CAAahO,CAAAlF,UAAA,CAAe1wB,CAAf,CAAsBkC,CAAtB,CAAb,CAAZ,CAOF,CALAuiC,CAKA,CALM7O,CAAAlF,UAAA,CAAexuB,CAAf,CAA4BsiC,CAA5B,CAA+CJ,CAA/C,CAKN,CAJA/N,CAAA11B,KAAA,CAAiB8jC,CAAjB,CAIA,CAHAJ,CAAA1jC,KAAA,CAAciU,CAAA,CAAO6vB,CAAP,CAAYT,CAAZ,CAAd,CAGA,CAFAhkC,CAEA,CAFQokC,CAER,CAFmBM,CAEnB,CADAH,CAAA5jC,KAAA,CAAyBgB,CAAA3G,OAAzB,CACA,CAAA2G,CAAAhB,KAAA,CAAY,EAAZ,CAVF,KAWO,CAEDX,CAAJ,GAAcskC,CAAd,EACE3iC,CAAAhB,KAAA,CAAYijC,CAAA,CAAahO,CAAAlF,UAAA,CAAe1wB,CAAf,CAAb,CAAZ,CAEF,MALK,CAeL62B,CAAJ,EAAsC,CAAtC,CAAsBl1B,CAAA3G,OAAtB,EACIkpC,EAAAS,cAAA,CAAiC/O,CAAjC,CAGJ,IAAKmO,CAAAA,CAAL,EAA2B1N,CAAAr7B,OAA3B,CAA+C,CAC7C,IAAI4pC,EAAUA,QAAQ,CAACjK,CAAD,CAAS,CAC7B,IAD6B,IACpBz+B,EAAI,CADgB,CACba,EAAKs5B,CAAAr7B,OAArB,CAAyCkB,CAAzC,CAA6Ca,CAA7C,CAAiDb,CAAA,EAAjD,CAAsD,CACpD,GAAI06B,CAAJ,EAAoBn4B,CAAA,CAAYk8B,CAAA,CAAOz+B,CAAP,CAAZ,CAApB,CAA4C,MAC5CyF,EAAA,CAAO4iC,CAAA,CAAoBroC,CAApB,CAAP,CAAA,CAAiCy+B,CAAA,CAAOz+B,CAAP,CAFmB,CAItD,MAAOyF,EAAAkD,KAAA,CAAY,EAAZ,CALsB,CAc/B,OAAOtH,EAAA,CAAOsnC,QAAwB,CAACrpC,CAAD,CAAU,CAC5C,IAAIU,EAAI,CAAR,CACIa,EAAKs5B,CAAAr7B,OADT,CAEI2/B,EAAalZ,KAAJ,CAAU1kB,CAAV,CAEb,IAAI,CACF,IAAA,CAAOb,CAAP,CAAWa,CAAX,CAAeb,CAAA,EAAf,CACEy+B,CAAA,CAAOz+B,CAAP,CAAA,CAAYmoC,CAAA,CAASnoC,CAAT,CAAA,CAAYV,CAAZ,CAGd,OAAOopC,EAAA,CAAQjK,CAAR,CALL,CAMF,MAAOza,CAAP,CAAY,CACZ1M,CAAA,CAAkB0wB,EAAAC,OAAA,CAA0BvO,CAA1B;AAAgC1V,CAAhC,CAAlB,CADY,CAX8B,CAAzC,CAeF,CAEHukB,IAAK7O,CAFF,CAGHS,YAAaA,CAHV,CAIHyO,gBAAiBA,QAAQ,CAACl+B,CAAD,CAAQyd,CAAR,CAAkB,CACzC,IAAI6T,CACJ,OAAOtxB,EAAAm+B,YAAA,CAAkBV,CAAlB,CAA4BW,QAA6B,CAACrK,CAAD,CAASsK,CAAT,CAAoB,CAClF,IAAIC,EAAYN,CAAA,CAAQjK,CAAR,CACZj/B,EAAA,CAAW2oB,CAAX,CAAJ,EACEA,CAAAzoB,KAAA,CAAc,IAAd,CAAoBspC,CAApB,CAA+BvK,CAAA,GAAWsK,CAAX,CAAuB/M,CAAvB,CAAmCgN,CAAlE,CAA6Et+B,CAA7E,CAEFsxB,EAAA,CAAYgN,CALsE,CAA7E,CAFkC,CAJxC,CAfE,CAfsC,CA3C6B,CA9Hc,IACxFV,EAAoBpK,CAAAp/B,OADoE,CAExF0pC,EAAkBrK,CAAAr/B,OAFsE,CAGxF6oC,EAAqB,IAAI/iC,MAAJ,CAAWs5B,CAAAj2B,QAAA,CAAoB,IAApB,CAA0Bu/B,CAA1B,CAAX,CAA8C,GAA9C,CAHmE,CAIxFI,EAAmB,IAAIhjC,MAAJ,CAAWu5B,CAAAl2B,QAAA,CAAkB,IAAlB,CAAwBu/B,CAAxB,CAAX,CAA4C,GAA5C,CA0OvB9vB,EAAAwmB,YAAA,CAA2B+K,QAAQ,EAAG,CACpC,MAAO/K,EAD6B,CAgBtCxmB,EAAAymB,UAAA,CAAyB+K,QAAQ,EAAG,CAClC,MAAO/K,EAD2B,CAIpC,OAAOzmB,EAlQqF,CAAlF,CAzCkB,CA+ShCG,QAASA,GAAiB,EAAG,CAC3B,IAAAsJ,KAAA,CAAY,CAAC,YAAD,CAAe,SAAf,CAA0B,IAA1B,CAAgC,KAAhC,CACP,QAAQ,CAACvI,CAAD,CAAeoB,CAAf,CAA0BlB,CAA1B,CAAgCE,CAAhC,CAAqC,CAiIhDmwB,QAASA,EAAQ,CAACrjC,CAAD,CAAKmkB,CAAL,CAAYmf,CAAZ,CAAmBC,CAAnB,CAAgC,CAAA,IAC3CC,EAA+B,CAA/BA,CAAY/nC,SAAAzC,OAD+B,CAE3CmjB,EAAOqnB,CAAA,CAzsTRhoC,EAAA5B,KAAA,CAysT8B6B,SAzsT9B,CAysTyCyE,CAzsTzC,CAysTQ,CAAsC,EAFF,CAG3CujC,EAAcvvB,CAAAuvB,YAH6B,CAI3CC,EAAgBxvB,CAAAwvB,cAJ2B;AAK3CC,EAAY,CAL+B,CAM3CC,EAAalnC,CAAA,CAAU6mC,CAAV,CAAbK,EAAuC,CAACL,CANG,CAO3C3E,EAAW3a,CAAC2f,CAAA,CAAY1wB,CAAZ,CAAkBF,CAAnBiR,OAAA,EAPgC,CAQ3CwZ,EAAUmB,CAAAnB,QAEd6F,EAAA,CAAQ5mC,CAAA,CAAU4mC,CAAV,CAAA,CAAmBA,CAAnB,CAA2B,CAEnC7F,EAAA3K,KAAA,CAAa,IAAb,CAAmB,IAAnB,CAA2B0Q,CAAF,CAAoB,QAAQ,EAAG,CACtDxjC,CAAAG,MAAA,CAAS,IAAT,CAAegc,CAAf,CADsD,CAA/B,CAAenc,CAAxC,CAIAy9B,EAAAoG,aAAA,CAAuBJ,CAAA,CAAYK,QAAa,EAAG,CACjDlF,CAAAmF,OAAA,CAAgBJ,CAAA,EAAhB,CAEY,EAAZ,CAAIL,CAAJ,EAAiBK,CAAjB,EAA8BL,CAA9B,GACE1E,CAAAC,QAAA,CAAiB8E,CAAjB,CAEA,CADAD,CAAA,CAAcjG,CAAAoG,aAAd,CACA,CAAA,OAAOG,CAAA,CAAUvG,CAAAoG,aAAV,CAHT,CAMKD,EAAL,EAAgB9wB,CAAAhO,OAAA,EATiC,CAA5B,CAWpBqf,CAXoB,CAavB6f,EAAA,CAAUvG,CAAAoG,aAAV,CAAA,CAAkCjF,CAElC,OAAOnB,EA/BwC,CAhIjD,IAAIuG,EAAY,EA6KhBX,EAAAhf,OAAA,CAAkB4f,QAAQ,CAACxG,CAAD,CAAU,CAClC,MAAIA,EAAJ,EAAeA,CAAAoG,aAAf,GAAuCG,EAAvC,EACEA,CAAA,CAAUvG,CAAAoG,aAAV,CAAArH,OAAA,CAAuC,UAAvC,CAGO,CAFPtoB,CAAAwvB,cAAA,CAAsBjG,CAAAoG,aAAtB,CAEO,CADP,OAAOG,CAAA,CAAUvG,CAAAoG,aAAV,CACA,CAAA,CAAA,CAJT,EAMO,CAAA,CAP2B,CAUpC,OAAOR,EAxLyC,CADtC,CADe,CAwM7Bx4B,QAASA,GAAe,EAAG,CACzB,IAAAwQ,KAAA,CAAYC,QAAQ,EAAG,CACrB,MAAO,CACLgK,GAAI,OADC,CAGL4e,eAAgB,CACdC,YAAa,GADC;AAEdC,UAAW,GAFG,CAGdC,SAAU,CACR,CACEC,OAAQ,CADV,CAEEC,QAAS,CAFX,CAGEC,QAAS,CAHX,CAIEC,OAAQ,EAJV,CAKEC,OAAQ,EALV,CAMEC,OAAQ,GANV,CAOEC,OAAQ,EAPV,CAQEC,MAAO,CART,CASEC,OAAQ,CATV,CADQ,CAWN,CACAR,OAAQ,CADR,CAEAC,QAAS,CAFT,CAGAC,QAAS,CAHT,CAIAC,OAAQ,QAJR,CAKAC,OAAQ,EALR,CAMAC,OAAQ,SANR,CAOAC,OAAQ,GAPR,CAQAC,MAAO,CARP,CASAC,OAAQ,CATR,CAXM,CAHI,CA0BdC,aAAc,GA1BA,CAHX,CAgCLC,iBAAkB,CAChBC,MACI,uFAAA,MAAA,CAAA,GAAA,CAFY,CAIhBC,WAAa,iDAAA,MAAA,CAAA,GAAA,CAJG,CAKhBC,IAAK,0DAAA,MAAA,CAAA,GAAA,CALW;AAMhBC,SAAU,6BAAA,MAAA,CAAA,GAAA,CANM,CAOhBC,MAAO,CAAC,IAAD,CAAM,IAAN,CAPS,CAQhBC,OAAQ,oBARQ,CAShB,QAAS,eATO,CAUhBC,SAAU,iBAVM,CAWhBC,SAAU,WAXM,CAYhBC,WAAY,UAZI,CAahBC,UAAW,QAbK,CAchBC,WAAY,WAdI,CAehBC,UAAW,QAfK,CAgBhBC,SAAU,CACR,eADQ,CAER,aAFQ,CAhBM,CAoBhBC,KAAM,CACJ,IADI,CAEJ,IAFI,CApBU,CAhCb,CA0DLC,UAAWA,QAAQ,CAACC,CAAD,CAAM,CACvB,MAAY,EAAZ,GAAIA,CAAJ,CACS,KADT,CAGO,OAJgB,CA1DpB,CADc,CADE,CAiF3BC,QAASA,GAAU,CAACl+B,CAAD,CAAO,CACpBm+B,CAAAA,CAAWn+B,CAAArK,MAAA,CAAW,GAAX,CAGf,KAHA,IACIxD,EAAIgsC,CAAAltC,OAER,CAAOkB,CAAA,EAAP,CAAA,CACEgsC,CAAA,CAAShsC,CAAT,CAAA,CAAc4I,EAAA,CAAiBojC,CAAA,CAAShsC,CAAT,CAAjB,CAGhB,OAAOgsC,EAAArjC,KAAA,CAAc,GAAd,CARiB,CAW1BsjC,QAASA,GAAgB,CAACC,CAAD,CAAcC,CAAd,CAA2B,CAClD,IAAIC,EAAYpF,EAAA,CAAWkF,CAAX,CAEhBC,EAAAE,WAAA,CAAyBD,CAAAnF,SACzBkF;CAAAG,OAAA,CAAqBF,CAAAG,SACrBJ,EAAAK,OAAA,CAAqB/qC,CAAA,CAAM2qC,CAAAK,KAAN,CAArB,EAA8CC,EAAA,CAAcN,CAAAnF,SAAd,CAA9C,EAAmF,IALjC,CASpD0F,QAASA,GAAW,CAACC,CAAD,CAAcT,CAAd,CAA2B,CAC7C,IAAIU,EAAsC,GAAtCA,GAAYD,CAAA3nC,OAAA,CAAmB,CAAnB,CACZ4nC,EAAJ,GACED,CADF,CACgB,GADhB,CACsBA,CADtB,CAGA,KAAI/nC,EAAQmiC,EAAA,CAAW4F,CAAX,CACZT,EAAAW,OAAA,CAAqB3kC,kBAAA,CAAmB0kC,CAAA,EAAyC,GAAzC,GAAYhoC,CAAAkoC,SAAA9nC,OAAA,CAAsB,CAAtB,CAAZ,CACpCJ,CAAAkoC,SAAAvY,UAAA,CAAyB,CAAzB,CADoC,CACN3vB,CAAAkoC,SADb,CAErBZ,EAAAa,SAAA,CAAuB5kC,EAAA,CAAcvD,CAAAooC,OAAd,CACvBd,EAAAe,OAAA,CAAqB/kC,kBAAA,CAAmBtD,CAAAuhB,KAAnB,CAGjB+lB,EAAAW,OAAJ,EAA0D,GAA1D,EAA0BX,CAAAW,OAAA7nC,OAAA,CAA0B,CAA1B,CAA1B,GACEknC,CAAAW,OADF,CACuB,GADvB,CAC6BX,CAAAW,OAD7B,CAZ6C,CAyB/CK,QAASA,GAAU,CAACC,CAAD,CAAQC,CAAR,CAAe,CAChC,GAA6B,CAA7B,GAAIA,CAAAtpC,QAAA,CAAcqpC,CAAd,CAAJ,CACE,MAAOC,EAAAjkB,OAAA,CAAagkB,CAAAtuC,OAAb,CAFuB,CAOlCqqB,QAASA,GAAS,CAACnB,CAAD,CAAM,CACtB,IAAIlkB,EAAQkkB,CAAAjkB,QAAA,CAAY,GAAZ,CACZ,OAAiB,EAAV,EAAAD,CAAA,CAAckkB,CAAd,CAAoBA,CAAAoB,OAAA,CAAW,CAAX,CAActlB,CAAd,CAFL,CAKxBwpC,QAASA,GAAa,CAACtlB,CAAD,CAAM,CAC1B,MAAOA,EAAA/f,QAAA,CAAY,UAAZ;AAAwB,IAAxB,CADmB,CAK5BslC,QAASA,GAAS,CAACvlB,CAAD,CAAM,CACtB,MAAOA,EAAAoB,OAAA,CAAW,CAAX,CAAcD,EAAA,CAAUnB,CAAV,CAAAwlB,YAAA,CAA2B,GAA3B,CAAd,CAAgD,CAAhD,CADe,CAkBxBC,QAASA,GAAgB,CAACC,CAAD,CAAUC,CAAV,CAAsB,CAC7C,IAAAC,QAAA,CAAe,CAAA,CACfD,EAAA,CAAaA,CAAb,EAA2B,EAC3B,KAAIE,EAAgBN,EAAA,CAAUG,CAAV,CACpBzB,GAAA,CAAiByB,CAAjB,CAA0B,IAA1B,CAQA,KAAAI,QAAA,CAAeC,QAAQ,CAAC/lB,CAAD,CAAM,CAC3B,IAAIgmB,EAAUb,EAAA,CAAWU,CAAX,CAA0B7lB,CAA1B,CACd,IAAK,CAAA9oB,CAAA,CAAS8uC,CAAT,CAAL,CACE,KAAMC,GAAA,CAAgB,UAAhB,CAA6EjmB,CAA7E,CACF6lB,CADE,CAAN,CAIFlB,EAAA,CAAYqB,CAAZ,CAAqB,IAArB,CAEK,KAAAlB,OAAL,GACE,IAAAA,OADF,CACgB,GADhB,CAIA,KAAAoB,UAAA,EAb2B,CAoB7B,KAAAA,UAAA,CAAiBC,QAAQ,EAAG,CAAA,IACtBlB,EAAS1kC,EAAA,CAAW,IAAAykC,SAAX,CADa,CAEtB5mB,EAAO,IAAA8mB,OAAA,CAAc,GAAd,CAAoBtkC,EAAA,CAAiB,IAAAskC,OAAjB,CAApB,CAAoD,EAE/D,KAAAkB,MAAA,CAAarC,EAAA,CAAW,IAAAe,OAAX,CAAb,EAAwCG,CAAA,CAAS,GAAT,CAAeA,CAAf,CAAwB,EAAhE,EAAsE7mB,CACtE,KAAAioB,SAAA,CAAgBR,CAAhB,CAAgC,IAAAO,MAAAhlB,OAAA,CAAkB,CAAlB,CALN,CAQ5B,KAAAklB,eAAA,CAAsBC,QAAQ,CAACvmB,CAAD,CAAMwmB,CAAN,CAAe,CAC3C,GAAIA,CAAJ,EAA8B,GAA9B,GAAeA,CAAA,CAAQ,CAAR,CAAf,CAIE,MADA,KAAApoB,KAAA,CAAUooB,CAAAltC,MAAA,CAAc,CAAd,CAAV,CACO;AAAA,CAAA,CALkC,KAOvCmtC,CAPuC,CAO/BC,CAGZ,EAAKD,CAAL,CAActB,EAAA,CAAWO,CAAX,CAAoB1lB,CAApB,CAAd,IAA4CvpB,CAA5C,EACEiwC,CAEE,CAFWD,CAEX,CAAAE,CAAA,CADF,CAAKF,CAAL,CAActB,EAAA,CAAWQ,CAAX,CAAuBc,CAAvB,CAAd,IAAkDhwC,CAAlD,CACiBovC,CADjB,EACkCV,EAAA,CAAW,GAAX,CAAgBsB,CAAhB,CADlC,EAC6DA,CAD7D,EAGiBf,CAHjB,CAG2BgB,CAL7B,EAOO,CAAKD,CAAL,CAActB,EAAA,CAAWU,CAAX,CAA0B7lB,CAA1B,CAAd,IAAkDvpB,CAAlD,CACLkwC,CADK,CACUd,CADV,CAC0BY,CAD1B,CAEIZ,CAFJ,EAEqB7lB,CAFrB,CAE2B,GAF3B,GAGL2mB,CAHK,CAGUd,CAHV,CAKHc,EAAJ,EACE,IAAAb,QAAA,CAAaa,CAAb,CAEF,OAAO,CAAEA,CAAAA,CAzBkC,CAxCA,CA+E/CC,QAASA,GAAmB,CAAClB,CAAD,CAAUmB,CAAV,CAAsB,CAChD,IAAIhB,EAAgBN,EAAA,CAAUG,CAAV,CAEpBzB,GAAA,CAAiByB,CAAjB,CAA0B,IAA1B,CAQA,KAAAI,QAAA,CAAeC,QAAQ,CAAC/lB,CAAD,CAAM,CAC3B,IAAI8mB,EAAiB3B,EAAA,CAAWO,CAAX,CAAoB1lB,CAApB,CAAjB8mB,EAA6C3B,EAAA,CAAWU,CAAX,CAA0B7lB,CAA1B,CAAjD,CACI+mB,CAECxsC,EAAA,CAAYusC,CAAZ,CAAL,EAAiE,GAAjE,GAAoCA,CAAA7pC,OAAA,CAAsB,CAAtB,CAApC,CAcM,IAAA2oC,QAAJ,CACEmB,CADF,CACmBD,CADnB,EAGEC,CACA,CADiB,EACjB,CAAIxsC,CAAA,CAAYusC,CAAZ,CAAJ,GACEpB,CACA,CADU1lB,CACV,CAAA,IAAA/f,QAAA,EAFF,CAJF,CAdF,EAIE8mC,CACA,CADiB5B,EAAA,CAAW0B,CAAX,CAAuBC,CAAvB,CACjB,CAAIvsC,CAAA,CAAYwsC,CAAZ,CAAJ,GAEEA,CAFF,CAEmBD,CAFnB,CALF,CAyBAnC,GAAA,CAAYoC,CAAZ,CAA4B,IAA5B,CAEqCjC,EAAAA,CAAAA,IAAAA,OAA6BY,KAAAA,EAAAA,CAAAA,CAoB5DsB,EAAqB,iBAKC,EAA1B,GAAIhnB,CAAAjkB,QAAA,CAAYkrC,CAAZ,CAAJ,GACEjnB,CADF,CACQA,CAAA/f,QAAA,CAAYgnC,CAAZ,CAAkB,EAAlB,CADR,CAKID,EAAAtzB,KAAA,CAAwBsM,CAAxB,CAAJ,GAKA,CALA,CAKO,CADPknB,CACO,CADiBF,CAAAtzB,KAAA,CAAwB7N,CAAxB,CACjB,EAAwBqhC,CAAA,CAAsB,CAAtB,CAAxB,CAAmDrhC,CAL1D,CA9BF,KAAAi/B,OAAA,CAAc,CAEd,KAAAoB,UAAA,EAjC2B,CA0E7B,KAAAA,UAAA;AAAiBC,QAAQ,EAAG,CAAA,IACtBlB,EAAS1kC,EAAA,CAAW,IAAAykC,SAAX,CADa,CAEtB5mB,EAAO,IAAA8mB,OAAA,CAAc,GAAd,CAAoBtkC,EAAA,CAAiB,IAAAskC,OAAjB,CAApB,CAAoD,EAE/D,KAAAkB,MAAA,CAAarC,EAAA,CAAW,IAAAe,OAAX,CAAb,EAAwCG,CAAA,CAAS,GAAT,CAAeA,CAAf,CAAwB,EAAhE,EAAsE7mB,CACtE,KAAAioB,SAAA,CAAgBX,CAAhB,EAA2B,IAAAU,MAAA,CAAaS,CAAb,CAA0B,IAAAT,MAA1B,CAAuC,EAAlE,CAL0B,CAQ5B,KAAAE,eAAA,CAAsBC,QAAQ,CAACvmB,CAAD,CAAMwmB,CAAN,CAAe,CAC3C,MAAIrlB,GAAA,CAAUukB,CAAV,CAAJ,EAA0BvkB,EAAA,CAAUnB,CAAV,CAA1B,EACE,IAAA8lB,QAAA,CAAa9lB,CAAb,CACO,CAAA,CAAA,CAFT,EAIO,CAAA,CALoC,CA7FG,CAgHlDmnB,QAASA,GAA0B,CAACzB,CAAD,CAAUmB,CAAV,CAAsB,CACvD,IAAAjB,QAAA,CAAe,CAAA,CACfgB,GAAA3oC,MAAA,CAA0B,IAA1B,CAAgC1E,SAAhC,CAEA,KAAIssC,EAAgBN,EAAA,CAAUG,CAAV,CAEpB,KAAAY,eAAA,CAAsBC,QAAQ,CAACvmB,CAAD,CAAMwmB,CAAN,CAAe,CAC3C,GAAIA,CAAJ,EAA8B,GAA9B,GAAeA,CAAA,CAAQ,CAAR,CAAf,CAIE,MADA,KAAApoB,KAAA,CAAUooB,CAAAltC,MAAA,CAAc,CAAd,CAAV,CACO,CAAA,CAAA,CAGT,KAAIqtC,CAAJ,CACIF,CAEAf,EAAJ,EAAevkB,EAAA,CAAUnB,CAAV,CAAf,CACE2mB,CADF,CACiB3mB,CADjB,CAEO,CAAKymB,CAAL,CAActB,EAAA,CAAWU,CAAX,CAA0B7lB,CAA1B,CAAd,EACL2mB,CADK,CACUjB,CADV,CACoBmB,CADpB,CACiCJ,CADjC,CAEIZ,CAFJ,GAEsB7lB,CAFtB,CAE4B,GAF5B,GAGL2mB,CAHK,CAGUd,CAHV,CAKHc,EAAJ,EACE,IAAAb,QAAA,CAAaa,CAAb,CAEF,OAAO,CAAEA,CAAAA,CArBkC,CAwB7C,KAAAT,UAAA,CAAiBC,QAAQ,EAAG,CAAA,IACtBlB;AAAS1kC,EAAA,CAAW,IAAAykC,SAAX,CADa,CAEtB5mB,EAAO,IAAA8mB,OAAA,CAAc,GAAd,CAAoBtkC,EAAA,CAAiB,IAAAskC,OAAjB,CAApB,CAAoD,EAE/D,KAAAkB,MAAA,CAAarC,EAAA,CAAW,IAAAe,OAAX,CAAb,EAAwCG,CAAA,CAAS,GAAT,CAAeA,CAAf,CAAwB,EAAhE,EAAsE7mB,CAEtE,KAAAioB,SAAA,CAAgBX,CAAhB,CAA0BmB,CAA1B,CAAuC,IAAAT,MANb,CA9B2B,CA8WzDgB,QAASA,GAAc,CAACC,CAAD,CAAW,CAChC,MAAO,SAAQ,EAAG,CAChB,MAAO,KAAA,CAAKA,CAAL,CADS,CADc,CAOlCC,QAASA,GAAoB,CAACD,CAAD,CAAWE,CAAX,CAAuB,CAClD,MAAO,SAAQ,CAACpvC,CAAD,CAAQ,CACrB,GAAIoC,CAAA,CAAYpC,CAAZ,CAAJ,CACE,MAAO,KAAA,CAAKkvC,CAAL,CAGT,KAAA,CAAKA,CAAL,CAAA,CAAiBE,CAAA,CAAWpvC,CAAX,CACjB,KAAA+tC,UAAA,EAEA,OAAO,KARc,CAD2B,CA8CpD31B,QAASA,GAAiB,EAAG,CAAA,IACvBs2B,EAAa,EADU,CAEvBW,EAAY,CACVjhB,QAAS,CAAA,CADC,CAEVkhB,YAAa,CAAA,CAFH,CAGVC,aAAc,CAAA,CAHJ,CAahB,KAAAb,WAAA,CAAkBc,QAAQ,CAACnmC,CAAD,CAAS,CACjC,MAAIhH,EAAA,CAAUgH,CAAV,CAAJ,EACEqlC,CACO,CADMrlC,CACN,CAAA,IAFT,EAISqlC,CALwB,CA4BnC,KAAAW,UAAA,CAAiBI,QAAQ,CAACnjB,CAAD,CAAO,CAC9B,MAAI1pB,GAAA,CAAU0pB,CAAV,CAAJ,EACE+iB,CAAAjhB,QACO,CADa9B,CACb,CAAA,IAFT,EAGW3rB,CAAA,CAAS2rB,CAAT,CAAJ,EAED1pB,EAAA,CAAU0pB,CAAA8B,QAAV,CAYG,GAXLihB,CAAAjhB,QAWK,CAXe9B,CAAA8B,QAWf;AARHxrB,EAAA,CAAU0pB,CAAAgjB,YAAV,CAQG,GAPLD,CAAAC,YAOK,CAPmBhjB,CAAAgjB,YAOnB,EAJH1sC,EAAA,CAAU0pB,CAAAijB,aAAV,CAIG,GAHLF,CAAAE,aAGK,CAHoBjjB,CAAAijB,aAGpB,EAAA,IAdF,EAgBEF,CApBqB,CA+DhC,KAAAruB,KAAA,CAAY,CAAC,YAAD,CAAe,UAAf,CAA2B,UAA3B,CAAuC,cAAvC,CAAuD,SAAvD,CACR,QAAQ,CAACvI,CAAD,CAAa9B,CAAb,CAAuBwC,CAAvB,CAAiC0W,CAAjC,CAA+ChW,CAA/C,CAAwD,CAyBlE61B,QAASA,EAAyB,CAAC7nB,CAAD,CAAM/f,CAAN,CAAe2f,CAAf,CAAsB,CACtD,IAAIkoB,EAASx3B,CAAA0P,IAAA,EAAb,CACI+nB,EAAWz3B,CAAA03B,QACf,IAAI,CACFl5B,CAAAkR,IAAA,CAAaA,CAAb,CAAkB/f,CAAlB,CAA2B2f,CAA3B,CAKA,CAAAtP,CAAA03B,QAAA,CAAoBl5B,CAAA8Q,MAAA,EANlB,CAOF,MAAOhgB,CAAP,CAAU,CAKV,KAHA0Q,EAAA0P,IAAA,CAAc8nB,CAAd,CAGMloC,CAFN0Q,CAAA03B,QAEMpoC,CAFcmoC,CAEdnoC,CAAAA,CAAN,CALU,CAV0C,CA8IxDqoC,QAASA,EAAmB,CAACH,CAAD,CAASC,CAAT,CAAmB,CAC7Cn3B,CAAAs3B,WAAA,CAAsB,wBAAtB,CAAgD53B,CAAA63B,OAAA,EAAhD,CAAoEL,CAApE,CACEx3B,CAAA03B,QADF,CACqBD,CADrB,CAD6C,CAvKmB,IAC9Dz3B,CAD8D,CAE9D83B,CACAvmB,EAAAA,CAAW/S,CAAA+S,SAAA,EAHmD,KAI9DwmB,EAAav5B,CAAAkR,IAAA,EAJiD,CAK9D0lB,CAEJ,IAAI8B,CAAAjhB,QAAJ,CAAuB,CACrB,GAAK1E,CAAAA,CAAL,EAAiB2lB,CAAAC,YAAjB,CACE,KAAMxB,GAAA,CAAgB,QAAhB,CAAN,CAGFP,CAAA,CAAqB2C,CAruBlB7b,UAAA,CAAc,CAAd;AAquBkB6b,CAruBDtsC,QAAA,CAAY,GAAZ,CAquBCssC,CAruBgBtsC,QAAA,CAAY,IAAZ,CAAjB,CAAqC,CAArC,CAAjB,CAquBH,EAAoC8lB,CAApC,EAAgD,GAAhD,CACAumB,EAAA,CAAe92B,CAAAqO,QAAA,CAAmB8lB,EAAnB,CAAsC0B,EANhC,CAAvB,IAQEzB,EACA,CADUvkB,EAAA,CAAUknB,CAAV,CACV,CAAAD,CAAA,CAAexB,EAEjBt2B,EAAA,CAAY,IAAI83B,CAAJ,CAAiB1C,CAAjB,CAA0B,GAA1B,CAAgCmB,CAAhC,CACZv2B,EAAAg2B,eAAA,CAAyB+B,CAAzB,CAAqCA,CAArC,CAEA/3B,EAAA03B,QAAA,CAAoBl5B,CAAA8Q,MAAA,EAEpB,KAAI0oB,EAAoB,2BAqBxBtgB,EAAAzjB,GAAA,CAAgB,OAAhB,CAAyB,QAAQ,CAAC+T,CAAD,CAAQ,CAIvC,GAAKkvB,CAAAE,aAAL,EAA+Ba,CAAAjwB,CAAAiwB,QAA/B,EAAgDC,CAAAlwB,CAAAkwB,QAAhD,EAAiEC,CAAAnwB,CAAAmwB,SAAjE,EAAkG,CAAlG,EAAmFnwB,CAAAowB,MAAnF,EAAuH,CAAvH,EAAuGpwB,CAAAqwB,OAAvG,CAAA,CAKA,IAHA,IAAItqB,EAAM5e,CAAA,CAAO6Y,CAAAswB,OAAP,CAGV,CAA6B,GAA7B,GAAOntC,EAAA,CAAU4iB,CAAA,CAAI,CAAJ,CAAV,CAAP,CAAA,CAEE,GAAIA,CAAA,CAAI,CAAJ,CAAJ,GAAe2J,CAAA,CAAa,CAAb,CAAf,EAAmC,CAAA,CAAC3J,CAAD,CAAOA,CAAAxkB,OAAA,EAAP,EAAqB,CAArB,CAAnC,CAA4D,MAG9D,KAAIgvC,EAAUxqB,CAAAljB,KAAA,CAAS,MAAT,CAAd,CAGIqrC,EAAUnoB,CAAAjjB,KAAA,CAAS,MAAT,CAAVorC,EAA8BnoB,CAAAjjB,KAAA,CAAS,YAAT,CAE9BtC,EAAA,CAAS+vC,CAAT,CAAJ,EAAgD,4BAAhD,GAAyBA,CAAAxuC,SAAA,EAAzB,GAGEwuC,CAHF,CAGY7J,EAAA,CAAW6J,CAAA9d,QAAX,CAAAlK,KAHZ,CAOIynB,EAAA9rC,KAAA,CAAuBqsC,CAAvB,CAAJ;AAEIA,CAAAA,CAFJ,EAEgBxqB,CAAAjjB,KAAA,CAAS,QAAT,CAFhB,EAEuCkd,CAAAC,mBAAA,EAFvC,EAGM,CAAAjI,CAAAg2B,eAAA,CAAyBuC,CAAzB,CAAkCrC,CAAlC,CAHN,GAOIluB,CAAAwwB,eAAA,EAEA,CAAIx4B,CAAA63B,OAAA,EAAJ,EAA0Br5B,CAAAkR,IAAA,EAA1B,GACEpP,CAAAhO,OAAA,EAEA,CAAAoP,CAAAhP,QAAA,CAAgB,0BAAhB,CAAA,CAA8C,CAAA,CAHhD,CATJ,CAtBA,CAJuC,CAAzC,CA8CIsiC,GAAA,CAAch1B,CAAA63B,OAAA,EAAd,CAAJ,EAAyC7C,EAAA,CAAc+C,CAAd,CAAzC,EACEv5B,CAAAkR,IAAA,CAAa1P,CAAA63B,OAAA,EAAb,CAAiC,CAAA,CAAjC,CAGF,KAAIY,EAAe,CAAA,CAGnBj6B,EAAAyS,YAAA,CAAqB,QAAQ,CAACynB,CAAD,CAASC,CAAT,CAAmB,CAC9Cr4B,CAAA/V,WAAA,CAAsB,QAAQ,EAAG,CAC/B,IAAIitC,EAASx3B,CAAA63B,OAAA,EAAb,CACIJ,EAAWz3B,CAAA03B,QADf,CAEIvvB,CAEJnI,EAAAw1B,QAAA,CAAkBkD,CAAlB,CACA14B,EAAA03B,QAAA,CAAoBiB,CAEpBxwB,EAAA,CAAmB7H,CAAAs3B,WAAA,CAAsB,sBAAtB,CAA8Cc,CAA9C,CAAsDlB,CAAtD,CACfmB,CADe,CACLlB,CADK,CAAAtvB,iBAKfnI,EAAA63B,OAAA,EAAJ,GAA2Ba,CAA3B,GAEIvwB,CAAJ,EACEnI,CAAAw1B,QAAA,CAAkBgC,CAAlB,CAEA,CADAx3B,CAAA03B,QACA,CADoBD,CACpB,CAAAF,CAAA,CAA0BC,CAA1B,CAAkC,CAAA,CAAlC,CAAyCC,CAAzC,CAHF,GAKEgB,CACA,CADe,CAAA,CACf,CAAAd,CAAA,CAAoBH,CAApB,CAA4BC,CAA5B,CANF,CAFA,CAb+B,CAAjC,CAwBKn3B,EAAA6rB,QAAL,EAAyB7rB,CAAAs4B,QAAA,EAzBqB,CAAhD,CA6BAt4B,EAAA9V,OAAA,CAAkBquC,QAAuB,EAAG,CAC1C,IAAIrB;AAASxC,EAAA,CAAcx2B,CAAAkR,IAAA,EAAd,CAAb,CACIgpB,EAAS1D,EAAA,CAAch1B,CAAA63B,OAAA,EAAd,CADb,CAEIJ,EAAWj5B,CAAA8Q,MAAA,EAFf,CAGIwpB,EAAiB94B,CAAA+4B,UAHrB,CAIIC,EAAoBxB,CAApBwB,GAA+BN,CAA/BM,EACDh5B,CAAAs1B,QADC0D,EACoBh4B,CAAAqO,QADpB2pB,EACwCvB,CADxCuB,GACqDh5B,CAAA03B,QAEzD,IAAIe,CAAJ,EAAoBO,CAApB,CACEP,CAEA,CAFe,CAAA,CAEf,CAAAn4B,CAAA/V,WAAA,CAAsB,QAAQ,EAAG,CAC/B,IAAImuC,EAAS14B,CAAA63B,OAAA,EAAb,CACI1vB,EAAmB7H,CAAAs3B,WAAA,CAAsB,sBAAtB,CAA8Cc,CAA9C,CAAsDlB,CAAtD,CACnBx3B,CAAA03B,QADmB,CACAD,CADA,CAAAtvB,iBAKnBnI,EAAA63B,OAAA,EAAJ,GAA2Ba,CAA3B,GAEIvwB,CAAJ,EACEnI,CAAAw1B,QAAA,CAAkBgC,CAAlB,CACA,CAAAx3B,CAAA03B,QAAA,CAAoBD,CAFtB,GAIMuB,CAIJ,EAHEzB,CAAA,CAA0BmB,CAA1B,CAAkCI,CAAlC,CAC0BrB,CAAA,GAAaz3B,CAAA03B,QAAb,CAAiC,IAAjC,CAAwC13B,CAAA03B,QADlE,CAGF,CAAAC,CAAA,CAAoBH,CAApB,CAA4BC,CAA5B,CARF,CAFA,CAP+B,CAAjC,CAsBFz3B,EAAA+4B,UAAA,CAAsB,CAAA,CAjCoB,CAA5C,CAuCA,OAAO/4B,EArK2D,CADxD,CA1Ge,CAqU7BG,QAASA,GAAY,EAAG,CAAA,IAClB84B,EAAQ,CAAA,CADU,CAElB1rC,EAAO,IASX,KAAA2rC,aAAA,CAAoBC,QAAQ,CAACC,CAAD,CAAO,CACjC,MAAIlvC,EAAA,CAAUkvC,CAAV,CAAJ,EACEH,CACK,CADGG,CACH,CAAA,IAFP,EAISH,CALwB,CASnC,KAAApwB,KAAA,CAAY,CAAC,SAAD,CAAY,QAAQ,CAACnH,CAAD,CAAU,CAwDxC23B,QAASA,EAAW,CAACpkC,CAAD,CAAM,CACpBA,CAAJ,WAAmBqkC,MAAnB;CACMrkC,CAAAkW,MAAJ,CACElW,CADF,CACSA,CAAAiW,QAAD,EAAoD,EAApD,GAAgBjW,CAAAkW,MAAA1f,QAAA,CAAkBwJ,CAAAiW,QAAlB,CAAhB,CACA,SADA,CACYjW,CAAAiW,QADZ,CAC0B,IAD1B,CACiCjW,CAAAkW,MADjC,CAEAlW,CAAAkW,MAHR,CAIWlW,CAAAskC,UAJX,GAKEtkC,CALF,CAKQA,CAAAiW,QALR,CAKsB,IALtB,CAK6BjW,CAAAskC,UAL7B,CAK6C,GAL7C,CAKmDtkC,CAAAszB,KALnD,CADF,CASA,OAAOtzB,EAViB,CAa1BukC,QAASA,EAAU,CAAC10B,CAAD,CAAO,CAAA,IACpB20B,EAAU/3B,CAAA+3B,QAAVA,EAA6B,EADT,CAEpBC,EAAQD,CAAA,CAAQ30B,CAAR,CAAR40B,EAAyBD,CAAAE,IAAzBD,EAAwChwC,CACxCkwC,EAAAA,CAAW,CAAA,CAIf,IAAI,CACFA,CAAA,CAAW,CAAEjsC,CAAA+rC,CAAA/rC,MADX,CAEF,MAAO2B,CAAP,CAAU,EAEZ,MAAIsqC,EAAJ,CACS,QAAQ,EAAG,CAChB,IAAIjwB,EAAO,EACX7iB,EAAA,CAAQmC,SAAR,CAAmB,QAAQ,CAACgM,CAAD,CAAM,CAC/B0U,CAAAxd,KAAA,CAAUktC,CAAA,CAAYpkC,CAAZ,CAAV,CAD+B,CAAjC,CAGA,OAAOykC,EAAA/rC,MAAA,CAAY8rC,CAAZ,CAAqB9vB,CAArB,CALS,CADpB,CAYO,QAAQ,CAACkwB,CAAD,CAAOC,CAAP,CAAa,CAC1BJ,CAAA,CAAMG,CAAN,CAAoB,IAAR,EAAAC,CAAA,CAAe,EAAf,CAAoBA,CAAhC,CAD0B,CAvBJ,CApE1B,MAAO,CAQLH,IAAKH,CAAA,CAAW,KAAX,CARA,CAiBLjmB,KAAMimB,CAAA,CAAW,MAAX,CAjBD,CA0BLO,KAAMP,CAAA,CAAW,MAAX,CA1BD,CAmCLvqB,MAAOuqB,CAAA,CAAW,OAAX,CAnCF,CA4CLP,MAAQ,QAAQ,EAAG,CACjB,IAAIzrC,EAAKgsC,CAAA,CAAW,OAAX,CAET,OAAO,SAAQ,EAAG,CACZP,CAAJ,EACEzrC,CAAAG,MAAA,CAASJ,CAAT,CAAetE,SAAf,CAFc,CAHD,CAAX,EA5CH,CADiC,CAA9B,CApBU,CA17Xe;AAslYvC+wC,QAASA,GAAoB,CAAC7oC,CAAD,CAAO8oC,CAAP,CAAuB,CAClD,GAAa,kBAAb,GAAI9oC,CAAJ,EAA4C,kBAA5C,GAAmCA,CAAnC,EACgB,kBADhB,GACOA,CADP,EAC+C,kBAD/C,GACsCA,CADtC,EAEgB,WAFhB,GAEOA,CAFP,CAGE,KAAM+oC,GAAA,CAAa,SAAb,CAEmBD,CAFnB,CAAN,CAIF,MAAO9oC,EAR2C,CAWpDgpC,QAASA,GAAgB,CAAC7zC,CAAD,CAAM2zC,CAAN,CAAsB,CAE7C,GAAI3zC,CAAJ,CAAS,CACP,GAAIA,CAAA8F,YAAJ,GAAwB9F,CAAxB,CACE,KAAM4zC,GAAA,CAAa,QAAb,CAEFD,CAFE,CAAN,CAGK,GACH3zC,CAAAL,OADG,GACYK,CADZ,CAEL,KAAM4zC,GAAA,CAAa,YAAb,CAEFD,CAFE,CAAN,CAGK,GACH3zC,CAAA8zC,SADG,GACc9zC,CAAAsE,SADd,EAC+BtE,CAAAuE,KAD/B,EAC2CvE,CAAAwE,KAD3C,EACuDxE,CAAAyE,KADvD,EAEL,KAAMmvC,GAAA,CAAa,SAAb,CAEFD,CAFE,CAAN,CAGK,GACH3zC,CADG,GACKG,MADL,CAEL,KAAMyzC,GAAA,CAAa,SAAb,CAEFD,CAFE,CAAN,CAjBK,CAsBT,MAAO3zC,EAxBsC,CA+B/C+zC,QAASA,GAAkB,CAAC/zC,CAAD,CAAM2zC,CAAN,CAAsB,CAC/C,GAAI3zC,CAAJ,CAAS,CACP,GAAIA,CAAA8F,YAAJ,GAAwB9F,CAAxB,CACE,KAAM4zC,GAAA,CAAa,QAAb,CAEJD,CAFI,CAAN,CAGK,GAAI3zC,CAAJ,GAAYg0C,EAAZ,EAAoBh0C,CAApB,GAA4Bi0C,EAA5B,EAAqCj0C,CAArC,GAA6Ck0C,EAA7C,CACL,KAAMN,GAAA,CAAa,QAAb,CAEJD,CAFI,CAAN;AANK,CADsC,CAygBjDQ,QAASA,GAAS,CAACnT,CAAD,CAAI4B,CAAJ,CAAO,CACvB,MAAoB,WAAb,GAAA,MAAO5B,EAAP,CAA2BA,CAA3B,CAA+B4B,CADf,CAIzBwR,QAASA,GAAM,CAAC91B,CAAD,CAAI+1B,CAAJ,CAAO,CACpB,MAAiB,WAAjB,GAAI,MAAO/1B,EAAX,CAAqC+1B,CAArC,CACiB,WAAjB,GAAI,MAAOA,EAAX,CAAqC/1B,CAArC,CACOA,CADP,CACW+1B,CAHS,CAWtBC,QAASA,EAA+B,CAACC,CAAD,CAAM37B,CAAN,CAAe,CACrD,IAAI47B,CAAJ,CACIC,CACJ,QAAQF,CAAA/1B,KAAR,EACA,KAAKk2B,CAAAC,QAAL,CACEH,CAAA,CAAe,CAAA,CACfh0C,EAAA,CAAQ+zC,CAAAhN,KAAR,CAAkB,QAAQ,CAACqN,CAAD,CAAO,CAC/BN,CAAA,CAAgCM,CAAApU,WAAhC,CAAiD5nB,CAAjD,CACA47B,EAAA,CAAeA,CAAf,EAA+BI,CAAApU,WAAAtvB,SAFA,CAAjC,CAIAqjC,EAAArjC,SAAA,CAAesjC,CACf,MACF,MAAKE,CAAAG,QAAL,CACEN,CAAArjC,SAAA,CAAe,CAAA,CACfqjC,EAAAO,QAAA,CAAc,EACd,MACF,MAAKJ,CAAAK,gBAAL,CACET,CAAA,CAAgCC,CAAAS,SAAhC,CAA8Cp8B,CAA9C,CACA27B,EAAArjC,SAAA,CAAeqjC,CAAAS,SAAA9jC,SACfqjC,EAAAO,QAAA,CAAcP,CAAAS,SAAAF,QACd,MACF,MAAKJ,CAAAO,iBAAL,CACEX,CAAA,CAAgCC,CAAAW,KAAhC,CAA0Ct8B,CAA1C,CACA07B,EAAA,CAAgCC,CAAAY,MAAhC,CAA2Cv8B,CAA3C,CACA27B,EAAArjC,SAAA,CAAeqjC,CAAAW,KAAAhkC,SAAf;AAAoCqjC,CAAAY,MAAAjkC,SACpCqjC,EAAAO,QAAA,CAAcP,CAAAW,KAAAJ,QAAAjuC,OAAA,CAAwB0tC,CAAAY,MAAAL,QAAxB,CACd,MACF,MAAKJ,CAAAU,kBAAL,CACEd,CAAA,CAAgCC,CAAAW,KAAhC,CAA0Ct8B,CAA1C,CACA07B,EAAA,CAAgCC,CAAAY,MAAhC,CAA2Cv8B,CAA3C,CACA27B,EAAArjC,SAAA,CAAeqjC,CAAAW,KAAAhkC,SAAf,EAAoCqjC,CAAAY,MAAAjkC,SACpCqjC,EAAAO,QAAA,CAAcP,CAAArjC,SAAA,CAAe,EAAf,CAAoB,CAACqjC,CAAD,CAClC,MACF,MAAKG,CAAAW,sBAAL,CACEf,CAAA,CAAgCC,CAAA3uC,KAAhC,CAA0CgT,CAA1C,CACA07B,EAAA,CAAgCC,CAAAe,UAAhC,CAA+C18B,CAA/C,CACA07B,EAAA,CAAgCC,CAAAgB,WAAhC,CAAgD38B,CAAhD,CACA27B,EAAArjC,SAAA,CAAeqjC,CAAA3uC,KAAAsL,SAAf,EAAoCqjC,CAAAe,UAAApkC,SAApC,EAA8DqjC,CAAAgB,WAAArkC,SAC9DqjC,EAAAO,QAAA,CAAcP,CAAArjC,SAAA,CAAe,EAAf,CAAoB,CAACqjC,CAAD,CAClC,MACF,MAAKG,CAAAc,WAAL,CACEjB,CAAArjC,SAAA,CAAe,CAAA,CACfqjC,EAAAO,QAAA,CAAc,CAACP,CAAD,CACd,MACF,MAAKG,CAAAe,iBAAL,CACEnB,CAAA,CAAgCC,CAAAmB,OAAhC,CAA4C98B,CAA5C,CACI27B,EAAAoB,SAAJ,EACErB,CAAA,CAAgCC,CAAA9D,SAAhC,CAA8C73B,CAA9C,CAEF27B;CAAArjC,SAAA,CAAeqjC,CAAAmB,OAAAxkC,SAAf,GAAuC,CAACqjC,CAAAoB,SAAxC,EAAwDpB,CAAA9D,SAAAv/B,SAAxD,CACAqjC,EAAAO,QAAA,CAAc,CAACP,CAAD,CACd,MACF,MAAKG,CAAAkB,eAAL,CACEpB,CAAA,CAAeD,CAAAljC,OAAA,CAxDV,CAwDmCuH,CAzDjC1R,CAyD0CqtC,CAAAsB,OAAAhrC,KAzD1C3D,CACD22B,UAwDS,CAAqD,CAAA,CACpE4W,EAAA,CAAc,EACdj0C,EAAA,CAAQ+zC,CAAA5xC,UAAR,CAAuB,QAAQ,CAACiyC,CAAD,CAAO,CACpCN,CAAA,CAAgCM,CAAhC,CAAsCh8B,CAAtC,CACA47B,EAAA,CAAeA,CAAf,EAA+BI,CAAA1jC,SAC1B0jC,EAAA1jC,SAAL,EACEujC,CAAA5uC,KAAAwB,MAAA,CAAuBotC,CAAvB,CAAoCG,CAAAE,QAApC,CAJkC,CAAtC,CAOAP,EAAArjC,SAAA,CAAesjC,CACfD,EAAAO,QAAA,CAAcP,CAAAljC,OAAA,EAlERwsB,CAkEkCjlB,CAnEjC1R,CAmE0CqtC,CAAAsB,OAAAhrC,KAnE1C3D,CACD22B,UAkEQ,CAAsD4W,CAAtD,CAAoE,CAACF,CAAD,CAClF,MACF,MAAKG,CAAAoB,qBAAL,CACExB,CAAA,CAAgCC,CAAAW,KAAhC,CAA0Ct8B,CAA1C,CACA07B,EAAA,CAAgCC,CAAAY,MAAhC,CAA2Cv8B,CAA3C,CACA27B,EAAArjC,SAAA,CAAeqjC,CAAAW,KAAAhkC,SAAf,EAAoCqjC,CAAAY,MAAAjkC,SACpCqjC,EAAAO,QAAA,CAAc,CAACP,CAAD,CACd,MACF,MAAKG,CAAAqB,gBAAL,CACEvB,CAAA,CAAe,CAAA,CACfC,EAAA,CAAc,EACdj0C,EAAA,CAAQ+zC,CAAAt0B,SAAR,CAAsB,QAAQ,CAAC20B,CAAD,CAAO,CACnCN,CAAA,CAAgCM,CAAhC,CAAsCh8B,CAAtC,CACA47B,EAAA;AAAeA,CAAf,EAA+BI,CAAA1jC,SAC1B0jC,EAAA1jC,SAAL,EACEujC,CAAA5uC,KAAAwB,MAAA,CAAuBotC,CAAvB,CAAoCG,CAAAE,QAApC,CAJiC,CAArC,CAOAP,EAAArjC,SAAA,CAAesjC,CACfD,EAAAO,QAAA,CAAcL,CACd,MACF,MAAKC,CAAAsB,iBAAL,CACExB,CAAA,CAAe,CAAA,CACfC,EAAA,CAAc,EACdj0C,EAAA,CAAQ+zC,CAAA0B,WAAR,CAAwB,QAAQ,CAACxF,CAAD,CAAW,CACzC6D,CAAA,CAAgC7D,CAAAlvC,MAAhC,CAAgDqX,CAAhD,CACA47B,EAAA,CAAeA,CAAf,EAA+B/D,CAAAlvC,MAAA2P,SAC1Bu/B,EAAAlvC,MAAA2P,SAAL,EACEujC,CAAA5uC,KAAAwB,MAAA,CAAuBotC,CAAvB,CAAoChE,CAAAlvC,MAAAuzC,QAApC,CAJuC,CAA3C,CAOAP,EAAArjC,SAAA,CAAesjC,CACfD,EAAAO,QAAA,CAAcL,CACd,MACF,MAAKC,CAAAwB,eAAL,CACE3B,CAAArjC,SACA,CADe,CAAA,CACf,CAAAqjC,CAAAO,QAAA,CAAc,EAhGhB,CAHqD,CAwGvDqB,QAASA,GAAS,CAAC5O,CAAD,CAAO,CACvB,GAAmB,CAAnB,EAAIA,CAAArnC,OAAJ,CAAA,CACIk2C,CAAAA,CAAiB7O,CAAA,CAAK,CAAL,CAAA/G,WACrB,KAAIz1B,EAAYqrC,CAAAtB,QAChB,OAAyB,EAAzB,GAAI/pC,CAAA7K,OAAJ,CAAmC6K,CAAnC,CACOA,CAAA,CAAU,CAAV,CAAA,GAAiBqrC,CAAjB,CAAkCrrC,CAAlC,CAA8ClL,CAJrD,CADuB,CAQzBw2C,QAASA,GAAY,CAAC9B,CAAD,CAAM,CACzB,MAAOA,EAAA/1B,KAAP,GAAoBk2B,CAAAc,WAApB,EAAsCjB,CAAA/1B,KAAtC,GAAmDk2B,CAAAe,iBAD1B,CAI3Ba,QAASA,GAAa,CAAC/B,CAAD,CAAM,CAC1B,GAAwB,CAAxB;AAAIA,CAAAhN,KAAArnC,OAAJ,EAA6Bm2C,EAAA,CAAa9B,CAAAhN,KAAA,CAAS,CAAT,CAAA/G,WAAb,CAA7B,CACE,MAAO,CAAChiB,KAAMk2B,CAAAoB,qBAAP,CAAiCZ,KAAMX,CAAAhN,KAAA,CAAS,CAAT,CAAA/G,WAAvC,CAA+D2U,MAAO,CAAC32B,KAAMk2B,CAAA6B,iBAAP,CAAtE,CAAoGC,SAAU,GAA9G,CAFiB,CAM5BC,QAASA,GAAS,CAAClC,CAAD,CAAM,CACtB,MAA2B,EAA3B,GAAOA,CAAAhN,KAAArnC,OAAP,EACwB,CADxB,GACIq0C,CAAAhN,KAAArnC,OADJ,GAEIq0C,CAAAhN,KAAA,CAAS,CAAT,CAAA/G,WAAAhiB,KAFJ,GAEoCk2B,CAAAG,QAFpC,EAGIN,CAAAhN,KAAA,CAAS,CAAT,CAAA/G,WAAAhiB,KAHJ,GAGoCk2B,CAAAqB,gBAHpC,EAIIxB,CAAAhN,KAAA,CAAS,CAAT,CAAA/G,WAAAhiB,KAJJ,GAIoCk2B,CAAAsB,iBAJpC,CADsB,CAYxBU,QAASA,GAAW,CAACC,CAAD,CAAa/9B,CAAb,CAAsB,CACxC,IAAA+9B,WAAA,CAAkBA,CAClB,KAAA/9B,QAAA,CAAeA,CAFyB,CAyd1Cg+B,QAASA,GAAc,CAACD,CAAD,CAAa/9B,CAAb,CAAsB,CAC3C,IAAA+9B,WAAA,CAAkBA,CAClB,KAAA/9B,QAAA,CAAeA,CAF4B,CAwY7Ci+B,QAASA,GAAM,CAAC72C,CAAD,CAAMiP,CAAN,CAAY6nC,CAAZ,CAAsBC,CAAtB,CAA+B,CAC5ClD,EAAA,CAAiB7zC,CAAjB,CAAsB+2C,CAAtB,CAEIjyC,EAAAA,CAAUmK,CAAArK,MAAA,CAAW,GAAX,CACd,KADA,IAA+BjE,CAA/B,CACSS,EAAI,CAAb,CAAiC,CAAjC;AAAgB0D,CAAA5E,OAAhB,CAAoCkB,CAAA,EAApC,CAAyC,CACvCT,CAAA,CAAM+yC,EAAA,CAAqB5uC,CAAAugB,MAAA,EAArB,CAAsC0xB,CAAtC,CACN,KAAIC,EAAcnD,EAAA,CAAiB7zC,CAAA,CAAIW,CAAJ,CAAjB,CAA2Bo2C,CAA3B,CACbC,EAAL,GACEA,CACA,CADc,EACd,CAAAh3C,CAAA,CAAIW,CAAJ,CAAA,CAAWq2C,CAFb,CAIAh3C,EAAA,CAAMg3C,CAPiC,CASzCr2C,CAAA,CAAM+yC,EAAA,CAAqB5uC,CAAAugB,MAAA,EAArB,CAAsC0xB,CAAtC,CACNlD,GAAA,CAAiB7zC,CAAA,CAAIW,CAAJ,CAAjB,CAA2Bo2C,CAA3B,CAEA,OADA/2C,EAAA,CAAIW,CAAJ,CACA,CADWm2C,CAfiC,CAsB9CG,QAASA,GAA6B,CAACpsC,CAAD,CAAO,CAC3C,MAAe,aAAf,EAAOA,CADoC,CAM7CqsC,QAASA,GAAU,CAAC31C,CAAD,CAAQ,CACzB,MAAOX,EAAA,CAAWW,CAAAiB,QAAX,CAAA,CAA4BjB,CAAAiB,QAAA,EAA5B,CAA8C20C,EAAAr2C,KAAA,CAAmBS,CAAnB,CAD5B,CAuD3BwY,QAASA,GAAc,EAAG,CACxB,IAAIq9B,EAAexwC,EAAA,EAAnB,CACIywC,EAAiBzwC,EAAA,EAErB,KAAA2b,KAAA,CAAY,CAAC,SAAD,CAAY,UAAZ,CAAwB,QAAQ,CAAC3J,CAAD,CAAU8B,CAAV,CAAoB,CAkD9D48B,QAASA,EAAyB,CAACpb,CAAD,CAAWqb,CAAX,CAA4B,CAE5D,MAAgB,KAAhB,EAAIrb,CAAJ,EAA2C,IAA3C,EAAwBqb,CAAxB,CACSrb,CADT,GACsBqb,CADtB,CAIwB,QAAxB,GAAI,MAAOrb,EAAX,GAKEA,CAEI,CAFOgb,EAAA,CAAWhb,CAAX,CAEP,CAAoB,QAApB,GAAA,MAAOA,EAPb,EASW,CAAA,CATX,CAgBOA,CAhBP,GAgBoBqb,CAhBpB,EAgBwCrb,CAhBxC,GAgBqDA,CAhBrD,EAgBiEqb,CAhBjE,GAgBqFA,CAtBzB,CAyB9DC,QAASA,EAAmB,CAAC1rC,CAAD,CAAQyd,CAAR,CAAkBkuB,CAAlB,CAAkCC,CAAlC,CAAoDC,CAApD,CAA2E,CACrG,IAAIC,EAAmBF,CAAAG,OAAvB,CACIC,CAEJ,IAAgC,CAAhC,GAAIF,CAAA13C,OAAJ,CAAmC,CACjC,IAAI63C,EAAkBT,CAAtB,CACAM,EAAmBA,CAAA,CAAiB,CAAjB,CACnB,OAAO9rC,EAAA5H,OAAA,CAAa8zC,QAA6B,CAAClsC,CAAD,CAAQ,CACvD,IAAImsC;AAAgBL,CAAA,CAAiB9rC,CAAjB,CACfwrC,EAAA,CAA0BW,CAA1B,CAAyCF,CAAzC,CAAL,GACED,CACA,CADaJ,CAAA,CAAiB5rC,CAAjB,CAAwBjM,CAAxB,CAAmCA,CAAnC,CAA8C,CAACo4C,CAAD,CAA9C,CACb,CAAAF,CAAA,CAAkBE,CAAlB,EAAmCf,EAAA,CAAWe,CAAX,CAFrC,CAIA,OAAOH,EANgD,CAAlD,CAOJvuB,CAPI,CAOMkuB,CAPN,CAOsBE,CAPtB,CAH0B,CAenC,IAFA,IAAIO,EAAwB,EAA5B,CACIC,EAAiB,EADrB,CAES/2C,EAAI,CAFb,CAEgBa,EAAK21C,CAAA13C,OAArB,CAA8CkB,CAA9C,CAAkDa,CAAlD,CAAsDb,CAAA,EAAtD,CACE82C,CAAA,CAAsB92C,CAAtB,CACA,CAD2Bk2C,CAC3B,CAAAa,CAAA,CAAe/2C,CAAf,CAAA,CAAoB,IAGtB,OAAO0K,EAAA5H,OAAA,CAAak0C,QAA8B,CAACtsC,CAAD,CAAQ,CAGxD,IAFA,IAAIusC,EAAU,CAAA,CAAd,CAESj3C,EAAI,CAFb,CAEgBa,EAAK21C,CAAA13C,OAArB,CAA8CkB,CAA9C,CAAkDa,CAAlD,CAAsDb,CAAA,EAAtD,CAA2D,CACzD,IAAI62C,EAAgBL,CAAA,CAAiBx2C,CAAjB,CAAA,CAAoB0K,CAApB,CACpB,IAAIusC,CAAJ,GAAgBA,CAAhB,CAA0B,CAACf,CAAA,CAA0BW,CAA1B,CAAyCC,CAAA,CAAsB92C,CAAtB,CAAzC,CAA3B,EACE+2C,CAAA,CAAe/2C,CAAf,CACA,CADoB62C,CACpB,CAAAC,CAAA,CAAsB92C,CAAtB,CAAA,CAA2B62C,CAA3B,EAA4Cf,EAAA,CAAWe,CAAX,CAJW,CAQvDI,CAAJ,GACEP,CADF,CACeJ,CAAA,CAAiB5rC,CAAjB,CAAwBjM,CAAxB,CAAmCA,CAAnC,CAA8Cs4C,CAA9C,CADf,CAIA,OAAOL,EAfiD,CAAnD,CAgBJvuB,CAhBI,CAgBMkuB,CAhBN,CAgBsBE,CAhBtB,CAxB8F,CA2CvGW,QAASA,EAAoB,CAACxsC,CAAD,CAAQyd,CAAR,CAAkBkuB,CAAlB,CAAkCC,CAAlC,CAAoD,CAAA,IAC3E5Z,CAD2E,CAClEV,CACb,OAAOU,EAAP,CAAiBhyB,CAAA5H,OAAA,CAAaq0C,QAAqB,CAACzsC,CAAD,CAAQ,CACzD,MAAO4rC,EAAA,CAAiB5rC,CAAjB,CADkD,CAA1C,CAEd0sC,QAAwB,CAACj3C,CAAD,CAAQk3C,CAAR,CAAa3sC,CAAb,CAAoB,CAC7CsxB,CAAA,CAAY77B,CACRX,EAAA,CAAW2oB,CAAX,CAAJ,EACEA,CAAAliB,MAAA,CAAe,IAAf,CAAqB1E,SAArB,CAEEiB,EAAA,CAAUrC,CAAV,CAAJ,EACEuK,CAAA4sC,aAAA,CAAmB,QAAQ,EAAG,CACxB90C,CAAA,CAAUw5B,CAAV,CAAJ,EACEU,CAAA,EAF0B,CAA9B,CAN2C,CAF9B,CAcd2Z,CAdc,CAF8D,CAmBjFkB,QAASA,EAA2B,CAAC7sC,CAAD,CAAQyd,CAAR,CAAkBkuB,CAAlB,CAAkCC,CAAlC,CAAoD,CAgBtFkB,QAASA,EAAY,CAACr3C,CAAD,CAAQ,CAC3B,IAAIs3C,EAAa,CAAA,CACjBr4C,EAAA,CAAQe,CAAR,CAAe,QAAQ,CAACgG,CAAD,CAAM,CACtB3D,CAAA,CAAU2D,CAAV,CAAL;CAAqBsxC,CAArB,CAAkC,CAAA,CAAlC,CAD2B,CAA7B,CAGA,OAAOA,EALoB,CAhByD,IAClF/a,CADkF,CACzEV,CACb,OAAOU,EAAP,CAAiBhyB,CAAA5H,OAAA,CAAaq0C,QAAqB,CAACzsC,CAAD,CAAQ,CACzD,MAAO4rC,EAAA,CAAiB5rC,CAAjB,CADkD,CAA1C,CAEd0sC,QAAwB,CAACj3C,CAAD,CAAQk3C,CAAR,CAAa3sC,CAAb,CAAoB,CAC7CsxB,CAAA,CAAY77B,CACRX,EAAA,CAAW2oB,CAAX,CAAJ,EACEA,CAAAzoB,KAAA,CAAc,IAAd,CAAoBS,CAApB,CAA2Bk3C,CAA3B,CAAgC3sC,CAAhC,CAEE8sC,EAAA,CAAar3C,CAAb,CAAJ,EACEuK,CAAA4sC,aAAA,CAAmB,QAAQ,EAAG,CACxBE,CAAA,CAAaxb,CAAb,CAAJ,EAA6BU,CAAA,EADD,CAA9B,CAN2C,CAF9B,CAYd2Z,CAZc,CAFqE,CAyBxFqB,QAASA,EAAqB,CAAChtC,CAAD,CAAQyd,CAAR,CAAkBkuB,CAAlB,CAAkCC,CAAlC,CAAoD,CAChF,IAAI5Z,CACJ,OAAOA,EAAP,CAAiBhyB,CAAA5H,OAAA,CAAa60C,QAAsB,CAACjtC,CAAD,CAAQ,CAC1D,MAAO4rC,EAAA,CAAiB5rC,CAAjB,CADmD,CAA3C,CAEdktC,QAAyB,CAACz3C,CAAD,CAAQk3C,CAAR,CAAa3sC,CAAb,CAAoB,CAC1ClL,CAAA,CAAW2oB,CAAX,CAAJ,EACEA,CAAAliB,MAAA,CAAe,IAAf,CAAqB1E,SAArB,CAEFm7B,EAAA,EAJ8C,CAF/B,CAOd2Z,CAPc,CAF+D,CAYlFwB,QAASA,EAAc,CAACvB,CAAD,CAAmBwB,CAAnB,CAAkC,CACvD,GAAKA,CAAAA,CAAL,CAAoB,MAAOxB,EAC3B,KAAIyB,EAAgBzB,CAAA1N,gBAApB,CAMI9iC,EAHAiyC,CAGK,GAHaR,CAGb,EAFLQ,CAEK,GAFab,CAEb,CAAec,QAAqC,CAACttC,CAAD,CAAQwZ,CAAR,CAAgBoY,CAAhB,CAAwBma,CAAxB,CAAgC,CACvFt2C,CAAAA,CAAQm2C,CAAA,CAAiB5rC,CAAjB,CAAwBwZ,CAAxB,CAAgCoY,CAAhC,CAAwCma,CAAxC,CACZ,OAAOqB,EAAA,CAAc33C,CAAd,CAAqBuK,CAArB,CAA4BwZ,CAA5B,CAFoF,CAApF,CAGL+zB,QAAqC,CAACvtC,CAAD,CAAQwZ,CAAR,CAAgBoY,CAAhB,CAAwBma,CAAxB,CAAgC,CACnEt2C,CAAAA,CAAQm2C,CAAA,CAAiB5rC,CAAjB,CAAwBwZ,CAAxB,CAAgCoY,CAAhC,CAAwCma,CAAxC,CACR1zB,EAAAA,CAAS+0B,CAAA,CAAc33C,CAAd,CAAqBuK,CAArB,CAA4BwZ,CAA5B,CAGb,OAAO1hB,EAAA,CAAUrC,CAAV,CAAA,CAAmB4iB,CAAnB,CAA4B5iB,CALoC,CASrEm2C,EAAA1N,gBAAJ,EACI0N,CAAA1N,gBADJ;AACyCwN,CADzC,CAEEtwC,CAAA8iC,gBAFF,CAEuB0N,CAAA1N,gBAFvB,CAGYkP,CAAArb,UAHZ,GAME32B,CAAA8iC,gBACA,CADqBwN,CACrB,CAAAtwC,CAAA2wC,OAAA,CAAYH,CAAAG,OAAA,CAA0BH,CAAAG,OAA1B,CAAoD,CAACH,CAAD,CAPlE,CAUA,OAAOxwC,EA9BgD,CA9KK,IAC1DoyC,EAAgB,CACdznC,IAAK6I,CAAA7I,IADS,CAEd0nC,gBAAiB,CAAA,CAFH,CAD0C,CAK1DC,EAAyB,CACvB3nC,IAAK6I,CAAA7I,IADkB,CAEvB0nC,gBAAiB,CAAA,CAFM,CAK7B,OAAOz/B,SAAe,CAAC6vB,CAAD,CAAMuP,CAAN,CAAqBK,CAArB,CAAsC,CAAA,IACtD7B,CADsD,CACpC+B,CADoC,CAC3BC,CAE/B,QAAQ,MAAO/P,EAAf,EACE,KAAK,QAAL,CAEE+P,CAAA,CADA/P,CACA,CADMA,CAAAjsB,KAAA,EAGN,KAAIqH,EAASw0B,CAAA,CAAkBlC,CAAlB,CAAmCD,CAChDM,EAAA,CAAmB3yB,CAAA,CAAM20B,CAAN,CAEdhC,EAAL,GACwB,GAgBtB,GAhBI/N,CAAAtjC,OAAA,CAAW,CAAX,CAgBJ,EAhB+C,GAgB/C,GAhB6BsjC,CAAAtjC,OAAA,CAAW,CAAX,CAgB7B,GAfEozC,CACA,CADU,CAAA,CACV,CAAA9P,CAAA,CAAMA,CAAA/T,UAAA,CAAc,CAAd,CAcR,EAZI+jB,CAYJ,CAZmBJ,CAAA,CAAkBC,CAAlB,CAA2CF,CAY9D,CAXIM,CAWJ,CAXY,IAAIC,EAAJ,CAAUF,CAAV,CAWZ,CATAjC,CASA,CATmB5vC,CADNgyC,IAAIC,EAAJD,CAAWF,CAAXE,CAAkBlhC,CAAlBkhC,CAA2BH,CAA3BG,CACMhyC,OAAA,CAAa6hC,CAAb,CASnB,CARI+N,CAAAxmC,SAAJ,CACEwmC,CAAA1N,gBADF,CACqC8O,CADrC,CAEWW,CAAJ,CACL/B,CAAA1N,gBADK,CAC8B0N,CAAAja,QAAA,CAC/Bkb,CAD+B,CACDL,CAF7B,CAGIZ,CAAAG,OAHJ,GAILH,CAAA1N,gBAJK,CAI8BwN,CAJ9B,CAMP,CAAAzyB,CAAA,CAAM20B,CAAN,CAAA,CAAkBhC,CAjBpB,CAmBA,OAAOuB,EAAA,CAAevB,CAAf;AAAiCwB,CAAjC,CAET,MAAK,UAAL,CACE,MAAOD,EAAA,CAAetP,CAAf,CAAoBuP,CAApB,CAET,SACE,MAAO91C,EAjCX,CAH0D,CAVE,CAApD,CAJY,CA2a1B+W,QAASA,GAAU,EAAG,CAEpB,IAAAoI,KAAA,CAAY,CAAC,YAAD,CAAe,mBAAf,CAAoC,QAAQ,CAACvI,CAAD,CAAatB,CAAb,CAAgC,CACtF,MAAOshC,GAAA,CAAS,QAAQ,CAAChwB,CAAD,CAAW,CACjChQ,CAAA/V,WAAA,CAAsB+lB,CAAtB,CADiC,CAA5B,CAEJtR,CAFI,CAD+E,CAA5E,CAFQ,CAStB2B,QAASA,GAAW,EAAG,CACrB,IAAAkI,KAAA,CAAY,CAAC,UAAD,CAAa,mBAAb,CAAkC,QAAQ,CAACrK,CAAD,CAAWQ,CAAX,CAA8B,CAClF,MAAOshC,GAAA,CAAS,QAAQ,CAAChwB,CAAD,CAAW,CACjC9R,CAAAiT,MAAA,CAAenB,CAAf,CADiC,CAA5B,CAEJtR,CAFI,CAD2E,CAAxE,CADS,CAgBvBshC,QAASA,GAAQ,CAACC,CAAD,CAAWC,CAAX,CAA6B,CAE5CC,QAASA,EAAQ,CAAClzC,CAAD,CAAOmzC,CAAP,CAAkBjV,CAAlB,CAA4B,CAE3CpoB,QAASA,EAAI,CAAC7V,CAAD,CAAK,CAChB,MAAO,SAAQ,CAAC3F,CAAD,CAAQ,CACjBimC,CAAJ,GACAA,CACA,CADS,CAAA,CACT,CAAAtgC,CAAApG,KAAA,CAAQmG,CAAR,CAAc1F,CAAd,CAFA,CADqB,CADP,CADlB,IAAIimC,EAAS,CAAA,CASb,OAAO,CAACzqB,CAAA,CAAKq9B,CAAL,CAAD,CAAkBr9B,CAAA,CAAKooB,CAAL,CAAlB,CAVoC,CA2B7CkV,QAASA,EAAO,EAAG,CACjB,IAAAjJ,QAAA,CAAe,CAAE7O,OAAQ,CAAV,CADE,CA6BnB+X,QAASA,EAAU,CAAC55C,CAAD,CAAUwG,CAAV,CAAc,CAC/B,MAAO,SAAQ,CAAC3F,CAAD,CAAQ,CACrB2F,CAAApG,KAAA,CAAQJ,CAAR,CAAiBa,CAAjB,CADqB,CADQ,CA8BjCg5C,QAASA,EAAoB,CAACvxB,CAAD,CAAQ,CAC/BwxB,CAAAxxB,CAAAwxB,iBAAJ;AAA+BxxB,CAAAyxB,QAA/B,GACAzxB,CAAAwxB,iBACA,CADyB,CAAA,CACzB,CAAAP,CAAA,CAAS,QAAQ,EAAG,CA3BO,IACvB/yC,CADuB,CACnB4+B,CADmB,CACT2U,CAElBA,EAAA,CAwBmCzxB,CAxBzByxB,QAwByBzxB,EAvBnCwxB,iBAAA,CAAyB,CAAA,CAuBUxxB,EAtBnCyxB,QAAA,CAAgB56C,CAChB,KAN2B,IAMlBuB,EAAI,CANc,CAMXa,EAAKw4C,CAAAv6C,OAArB,CAAqCkB,CAArC,CAAyCa,CAAzC,CAA6C,EAAEb,CAA/C,CAAkD,CAChD0kC,CAAA,CAAW2U,CAAA,CAAQr5C,CAAR,CAAA,CAAW,CAAX,CACX8F,EAAA,CAAKuzC,CAAA,CAAQr5C,CAAR,CAAA,CAmB4B4nB,CAnBjBuZ,OAAX,CACL,IAAI,CACE3hC,CAAA,CAAWsG,CAAX,CAAJ,CACE4+B,CAAAC,QAAA,CAAiB7+B,CAAA,CAgBY8hB,CAhBTznB,MAAH,CAAjB,CADF,CAE4B,CAArB,GAewBynB,CAfpBuZ,OAAJ,CACLuD,CAAAC,QAAA,CAc6B/c,CAdZznB,MAAjB,CADK,CAGLukC,CAAApC,OAAA,CAY6B1a,CAZbznB,MAAhB,CANA,CAQF,MAAOyH,CAAP,CAAU,CACV88B,CAAApC,OAAA,CAAgB16B,CAAhB,CACA,CAAAkxC,CAAA,CAAiBlxC,CAAjB,CAFU,CAXoC,CAqB9B,CAApB,CAFA,CADmC,CAMrC0xC,QAASA,EAAQ,EAAG,CAClB,IAAA/V,QAAA,CAAe,IAAI0V,CAEnB,KAAAtU,QAAA,CAAeuU,CAAA,CAAW,IAAX,CAAiB,IAAAvU,QAAjB,CACf,KAAArC,OAAA,CAAc4W,CAAA,CAAW,IAAX,CAAiB,IAAA5W,OAAjB,CACd,KAAAuH,OAAA,CAAcqP,CAAA,CAAW,IAAX,CAAiB,IAAArP,OAAjB,CALI,CA7FpB,IAAI0P,EAAW76C,CAAA,CAAO,IAAP,CAAa86C,SAAb,CAgCfP,EAAA32C,UAAA,CAAoB,CAClBs2B,KAAMA,QAAQ,CAAC6gB,CAAD,CAAcC,CAAd,CAA0BC,CAA1B,CAAwC,CACpD,IAAI52B,EAAS,IAAIu2B,CAEjB,KAAAtJ,QAAAqJ,QAAA,CAAuB,IAAArJ,QAAAqJ,QAAvB;AAA+C,EAC/C,KAAArJ,QAAAqJ,QAAA50C,KAAA,CAA0B,CAACse,CAAD,CAAS02B,CAAT,CAAsBC,CAAtB,CAAkCC,CAAlC,CAA1B,CAC0B,EAA1B,CAAI,IAAA3J,QAAA7O,OAAJ,EAA6BgY,CAAA,CAAqB,IAAAnJ,QAArB,CAE7B,OAAOjtB,EAAAwgB,QAP6C,CADpC,CAWlB,QAASqW,QAAQ,CAAChxB,CAAD,CAAW,CAC1B,MAAO,KAAAgQ,KAAA,CAAU,IAAV,CAAgBhQ,CAAhB,CADmB,CAXV,CAelB,UAAWixB,QAAQ,CAACjxB,CAAD,CAAW+wB,CAAX,CAAyB,CAC1C,MAAO,KAAA/gB,KAAA,CAAU,QAAQ,CAACz4B,CAAD,CAAQ,CAC/B,MAAO25C,EAAA,CAAe35C,CAAf,CAAsB,CAAA,CAAtB,CAA4ByoB,CAA5B,CADwB,CAA1B,CAEJ,QAAQ,CAACrB,CAAD,CAAQ,CACjB,MAAOuyB,EAAA,CAAevyB,CAAf,CAAsB,CAAA,CAAtB,CAA6BqB,CAA7B,CADU,CAFZ,CAIJ+wB,CAJI,CADmC,CAf1B,CAqEpBL,EAAAh3C,UAAA,CAAqB,CACnBqiC,QAASA,QAAQ,CAACx+B,CAAD,CAAM,CACjB,IAAAo9B,QAAAyM,QAAA7O,OAAJ,GACIh7B,CAAJ,GAAY,IAAAo9B,QAAZ,CACE,IAAAwW,SAAA,CAAcR,CAAA,CACZ,QADY,CAGZpzC,CAHY,CAAd,CADF,CAME,IAAA6zC,UAAA,CAAe7zC,CAAf,CAPF,CADqB,CADJ,CAcnB6zC,UAAWA,QAAQ,CAAC7zC,CAAD,CAAM,CAAA,IACnByyB,CADmB,CACbwI,CAEVA,EAAA,CAAM2X,CAAA,CAAS,IAAT,CAAe,IAAAiB,UAAf,CAA+B,IAAAD,SAA/B,CACN,IAAI,CACF,GAAKj5C,CAAA,CAASqF,CAAT,CAAL,EAAsB3G,CAAA,CAAW2G,CAAX,CAAtB,CAAwCyyB,CAAA,CAAOzyB,CAAP,EAAcA,CAAAyyB,KAClDp5B,EAAA,CAAWo5B,CAAX,CAAJ,EACE,IAAA2K,QAAAyM,QAAA7O,OACA;AAD+B,EAC/B,CAAAvI,CAAAl5B,KAAA,CAAUyG,CAAV,CAAei7B,CAAA,CAAI,CAAJ,CAAf,CAAuBA,CAAA,CAAI,CAAJ,CAAvB,CAA+B,IAAAyI,OAA/B,CAFF,GAIE,IAAAtG,QAAAyM,QAAA7vC,MAEA,CAF6BgG,CAE7B,CADA,IAAAo9B,QAAAyM,QAAA7O,OACA,CAD8B,CAC9B,CAAAgY,CAAA,CAAqB,IAAA5V,QAAAyM,QAArB,CANF,CAFE,CAUF,MAAOpoC,CAAP,CAAU,CACVw5B,CAAA,CAAI,CAAJ,CAAA,CAAOx5B,CAAP,CACA,CAAAkxC,CAAA,CAAiBlxC,CAAjB,CAFU,CAdW,CAdN,CAkCnB06B,OAAQA,QAAQ,CAAC90B,CAAD,CAAS,CACnB,IAAA+1B,QAAAyM,QAAA7O,OAAJ,EACA,IAAA4Y,SAAA,CAAcvsC,CAAd,CAFuB,CAlCN,CAuCnBusC,SAAUA,QAAQ,CAACvsC,CAAD,CAAS,CACzB,IAAA+1B,QAAAyM,QAAA7vC,MAAA,CAA6BqN,CAC7B,KAAA+1B,QAAAyM,QAAA7O,OAAA,CAA8B,CAC9BgY,EAAA,CAAqB,IAAA5V,QAAAyM,QAArB,CAHyB,CAvCR,CA6CnBnG,OAAQA,QAAQ,CAACoQ,CAAD,CAAW,CACzB,IAAIpU,EAAY,IAAAtC,QAAAyM,QAAAqJ,QAEoB,EAApC,EAAK,IAAA9V,QAAAyM,QAAA7O,OAAL,EAA0C0E,CAA1C,EAAuDA,CAAA/mC,OAAvD,EACE+5C,CAAA,CAAS,QAAQ,EAAG,CAElB,IAFkB,IACdjwB,CADc,CACJ7F,CADI,CAET/iB,EAAI,CAFK,CAEFa,EAAKglC,CAAA/mC,OAArB,CAAuCkB,CAAvC,CAA2Ca,CAA3C,CAA+Cb,CAAA,EAA/C,CAAoD,CAClD+iB,CAAA,CAAS8iB,CAAA,CAAU7lC,CAAV,CAAA,CAAa,CAAb,CACT4oB,EAAA,CAAWid,CAAA,CAAU7lC,CAAV,CAAA,CAAa,CAAb,CACX,IAAI,CACF+iB,CAAA8mB,OAAA,CAAcrqC,CAAA,CAAWopB,CAAX,CAAA;AAAuBA,CAAA,CAASqxB,CAAT,CAAvB,CAA4CA,CAA1D,CADE,CAEF,MAAOryC,CAAP,CAAU,CACVkxC,CAAA,CAAiBlxC,CAAjB,CADU,CALsC,CAFlC,CAApB,CAJuB,CA7CR,CA2GrB,KAAIsyC,EAAcA,QAAoB,CAAC/5C,CAAD,CAAQg6C,CAAR,CAAkB,CACtD,IAAIp3B,EAAS,IAAIu2B,CACba,EAAJ,CACEp3B,CAAA4hB,QAAA,CAAexkC,CAAf,CADF,CAGE4iB,CAAAuf,OAAA,CAAcniC,CAAd,CAEF,OAAO4iB,EAAAwgB,QAP+C,CAAxD,CAUIuW,EAAiBA,QAAuB,CAAC35C,CAAD,CAAQi6C,CAAR,CAAoBxxB,CAApB,CAA8B,CACxE,IAAIyxB,EAAiB,IACrB,IAAI,CACE76C,CAAA,CAAWopB,CAAX,CAAJ,GAA0ByxB,CAA1B,CAA2CzxB,CAAA,EAA3C,CADE,CAEF,MAAOhhB,CAAP,CAAU,CACV,MAAOsyC,EAAA,CAAYtyC,CAAZ,CAAe,CAAA,CAAf,CADG,CAGZ,MAAkByyC,EAAlB,EA9pbY76C,CAAA,CA8pbM66C,CA9pbKzhB,KAAX,CA8pbZ,CACSyhB,CAAAzhB,KAAA,CAAoB,QAAQ,EAAG,CACpC,MAAOshB,EAAA,CAAY/5C,CAAZ,CAAmBi6C,CAAnB,CAD6B,CAA/B,CAEJ,QAAQ,CAAC7yB,CAAD,CAAQ,CACjB,MAAO2yB,EAAA,CAAY3yB,CAAZ,CAAmB,CAAA,CAAnB,CADU,CAFZ,CADT,CAOS2yB,CAAA,CAAY/5C,CAAZ,CAAmBi6C,CAAnB,CAd+D,CAV1E,CA2CI5W,EAAOA,QAAQ,CAACrjC,CAAD,CAAQyoB,CAAR,CAAkB0xB,CAAlB,CAA2BX,CAA3B,CAAyC,CAC1D,IAAI52B,EAAS,IAAIu2B,CACjBv2B,EAAA4hB,QAAA,CAAexkC,CAAf,CACA,OAAO4iB,EAAAwgB,QAAA3K,KAAA,CAAoBhQ,CAApB,CAA8B0xB,CAA9B,CAAuCX,CAAvC,CAHmD,CA3C5D,CAsGIY,EAAKA,QAASC,EAAC,CAACC,CAAD,CAAW,CAC5B,GAAK,CAAAj7C,CAAA,CAAWi7C,CAAX,CAAL,CACE,KAAMlB,EAAA,CAAS,SAAT,CAAsDkB,CAAtD,CAAN,CAGF,GAAM,EAAA,IAAA,WAAgBD,EAAhB,CAAN,CAEE,MAAO,KAAIA,CAAJ,CAAMC,CAAN,CAGT,KAAI/V,EAAW,IAAI4U,CAUnBmB,EAAA,CARAzB,QAAkB,CAAC74C,CAAD,CAAQ,CACxBukC,CAAAC,QAAA,CAAiBxkC,CAAjB,CADwB,CAQ1B,CAJA4jC,QAAiB,CAACv2B,CAAD,CAAS,CACxBk3B,CAAApC,OAAA,CAAgB90B,CAAhB,CADwB,CAI1B,CAEA,OAAOk3B,EAAAnB,QAtBqB,CAyB9BgX;CAAAxwB,MAAA,CAvTYA,QAAQ,EAAG,CACrB,MAAO,KAAIuvB,CADU,CAwTvBiB,EAAAjY,OAAA,CAtIaA,QAAQ,CAAC90B,CAAD,CAAS,CAC5B,IAAIuV,EAAS,IAAIu2B,CACjBv2B,EAAAuf,OAAA,CAAc90B,CAAd,CACA,OAAOuV,EAAAwgB,QAHqB,CAuI9BgX,EAAA/W,KAAA,CAAUA,CACV+W,EAAA5V,QAAA,CAtEcnB,CAuEd+W,EAAAG,IAAA,CArDAA,QAAY,CAACC,CAAD,CAAW,CAAA,IACjBjW,EAAW,IAAI4U,CADE,CAEjB9oC,EAAU,CAFO,CAGjBoqC,EAAUz7C,CAAA,CAAQw7C,CAAR,CAAA,CAAoB,EAApB,CAAyB,EAEvCv7C,EAAA,CAAQu7C,CAAR,CAAkB,QAAQ,CAACpX,CAAD,CAAUhkC,CAAV,CAAe,CACvCiR,CAAA,EACAgzB,EAAA,CAAKD,CAAL,CAAA3K,KAAA,CAAmB,QAAQ,CAACz4B,CAAD,CAAQ,CAC7By6C,CAAAn7C,eAAA,CAAuBF,CAAvB,CAAJ,GACAq7C,CAAA,CAAQr7C,CAAR,CACA,CADeY,CACf,CAAM,EAAEqQ,CAAR,EAAkBk0B,CAAAC,QAAA,CAAiBiW,CAAjB,CAFlB,CADiC,CAAnC,CAIG,QAAQ,CAACptC,CAAD,CAAS,CACdotC,CAAAn7C,eAAA,CAAuBF,CAAvB,CAAJ,EACAmlC,CAAApC,OAAA,CAAgB90B,CAAhB,CAFkB,CAJpB,CAFuC,CAAzC,CAYgB,EAAhB,GAAIgD,CAAJ,EACEk0B,CAAAC,QAAA,CAAiBiW,CAAjB,CAGF,OAAOlW,EAAAnB,QArBc,CAuDvB,OAAOgX,EAtVqC,CAyV9CpgC,QAASA,GAAa,EAAG,CACvB,IAAAgH,KAAA,CAAY,CAAC,SAAD,CAAY,UAAZ,CAAwB,QAAQ,CAACnH,CAAD,CAAUF,CAAV,CAAoB,CA8B9D+gC,QAASA,EAAK,EAAG,CACf,IAAS,IAAA76C,EAAI,CAAb,CAAgBA,CAAhB,CAAoB86C,CAAAh8C,OAApB,CAAsCkB,CAAA,EAAtC,CAA2C,CACzC,IAAI+6C,EAAOD,CAAA,CAAU96C,CAAV,CACP+6C,EAAJ,GACED,CAAA,CAAU96C,CAAV,CACA,CADe,IACf,CAAA+6C,CAAA,EAFF,CAFyC,CAO3CC,CAAA,CAAYF,CAAAh8C,OAAZ,CAA+B,CARhB,CAWjBm8C,QAASA,EAAO,CAACC,CAAD,CAAU,CACxB,IAAIp3C;AAAQg3C,CAAAh8C,OAEZk8C,EAAA,EACAF,EAAAr2C,KAAA,CAAey2C,CAAf,CAEc,EAAd,GAAIp3C,CAAJ,GACEq3C,CADF,CACkBC,CAAA,CAAMP,CAAN,CADlB,CAIA,OAAOQ,SAAsB,EAAG,CACjB,CAAb,EAAIv3C,CAAJ,GAEEA,CAEA,CAHAg3C,CAAA,CAAUh3C,CAAV,CAGA,CAHmB,IAGnB,CAAoB,CAApB,GAAI,EAAEk3C,CAAN,EAAyBG,CAAzB,GACEA,CAAA,EAEA,CADAA,CACA,CADgB,IAChB,CAAAL,CAAAh8C,OAAA,CAAmB,CAHrB,CAJF,CAD8B,CAVR,CAxC1B,IAAIw8C,EAAwBthC,CAAAshC,sBAAxBA,EACwBthC,CAAAuhC,4BAD5B,CAGIC,EAAuBxhC,CAAAwhC,qBAAvBA,EACuBxhC,CAAAyhC,2BADvBD,EAEuBxhC,CAAA0hC,kCAL3B,CAOIC,EAAe,CAAEL,CAAAA,CAPrB,CAQIF,EAAQO,CAAA,CACR,QAAQ,CAAC71C,CAAD,CAAK,CACX,IAAIslB,EAAKkwB,CAAA,CAAsBx1C,CAAtB,CACT,OAAO,SAAQ,EAAG,CAChB01C,CAAA,CAAqBpwB,CAArB,CADgB,CAFP,CADL,CAOR,QAAQ,CAACtlB,CAAD,CAAK,CACX,IAAI81C,EAAQ9hC,CAAA,CAAShU,CAAT,CAAa,KAAb,CAAoB,CAAA,CAApB,CACZ,OAAO,SAAQ,EAAG,CAChBgU,CAAAqQ,OAAA,CAAgByxB,CAAhB,CADgB,CAFP,CAOjBX,EAAAY,UAAA,CAAoBF,CAEpB,KAAIR,CAAJ,CACIH,EAAY,CADhB,CAEIF,EAAY,EAChB,OAAOG,EA5BuD,CAApD,CADW,CAuIzBpiC,QAASA,GAAkB,EAAG,CAa5BijC,QAASA,EAAqB,CAACj6C,CAAD,CAAS,CACrCk6C,QAASA,EAAU,EAAG,CACpB,IAAAC,WAAA,CAAkB,IAAAC,cAAlB;AACI,IAAAC,YADJ,CACuB,IAAAC,YADvB,CAC0C,IAC1C,KAAAC,YAAA,CAAmB,EACnB,KAAAC,gBAAA,CAAuB,EACvB,KAAAC,gBAAA,CAAuB,CACvB,KAAAC,IAAA,CAtwcG,EAAEl8C,EAuwcL,KAAAm8C,aAAA,CAAoB,IAPA,CAStBT,CAAAz5C,UAAA,CAAuBT,CACvB,OAAOk6C,EAX8B,CAZvC,IAAIU,EAAM,EAAV,CACIC,EAAmBh+C,CAAA,CAAO,YAAP,CADvB,CAEIi+C,EAAiB,IAFrB,CAGIC,EAAe,IAEnB,KAAAC,UAAA,CAAiBC,QAAQ,CAAC38C,CAAD,CAAQ,CAC3BoB,SAAAzC,OAAJ,GACE29C,CADF,CACQt8C,CADR,CAGA,OAAOs8C,EAJwB,CAqBjC,KAAAt7B,KAAA,CAAY,CAAC,WAAD,CAAc,mBAAd,CAAmC,QAAnC,CAA6C,UAA7C,CACR,QAAQ,CAACuD,CAAD,CAAYpN,CAAZ,CAA+BoB,CAA/B,CAAuC5B,CAAvC,CAAiD,CAE3DimC,QAASA,EAAiB,CAACC,CAAD,CAAS,CAC/BA,CAAAC,aAAAhkB,YAAA,CAAkC,CAAA,CADH,CA+CnCikB,QAASA,EAAK,EAAG,CACf,IAAAX,IAAA,CAh0cG,EAAEl8C,EAi0cL,KAAAokC,QAAA,CAAe,IAAA0Y,QAAf,CAA8B,IAAAnB,WAA9B,CACe,IAAAC,cADf,CACoC,IAAAmB,cADpC,CAEe,IAAAlB,YAFf;AAEkC,IAAAC,YAFlC,CAEqD,IACrD,KAAAkB,MAAA,CAAa,IACb,KAAApkB,YAAA,CAAmB,CAAA,CACnB,KAAAmjB,YAAA,CAAmB,EACnB,KAAAC,gBAAA,CAAuB,EACvB,KAAAC,gBAAA,CAAuB,CACvB,KAAAtuB,kBAAA,CAAyB,IAVV,CA6nCjBsvB,QAASA,EAAU,CAACC,CAAD,CAAQ,CACzB,GAAI3kC,CAAA6rB,QAAJ,CACE,KAAMiY,EAAA,CAAiB,QAAjB,CAAsD9jC,CAAA6rB,QAAtD,CAAN,CAGF7rB,CAAA6rB,QAAA,CAAqB8Y,CALI,CAY3BC,QAASA,EAAsB,CAACC,CAAD,CAAUrU,CAAV,CAAiB,CAC9C,EACEqU,EAAAnB,gBAAA,EAA2BlT,CAD7B,OAEUqU,CAFV,CAEoBA,CAAAN,QAFpB,CAD8C,CAMhDO,QAASA,EAAsB,CAACD,CAAD,CAAUrU,CAAV,CAAiB3/B,CAAjB,CAAuB,CACpD,EACEg0C,EAAApB,gBAAA,CAAwB5yC,CAAxB,CAEA,EAFiC2/B,CAEjC,CAAsC,CAAtC,GAAIqU,CAAApB,gBAAA,CAAwB5yC,CAAxB,CAAJ,EACE,OAAOg0C,CAAApB,gBAAA,CAAwB5yC,CAAxB,CAJX,OAMUg0C,CANV,CAMoBA,CAAAN,QANpB,CADoD,CActDQ,QAASA,EAAY,EAAG,EAExBC,QAASA,EAAe,EAAG,CACzB,IAAA,CAAOC,CAAA/+C,OAAP,CAAA,CACE,GAAI,CACF++C,CAAA55B,MAAA,EAAA,EADE,CAEF,MAAOrc,CAAP,CAAU,CACV0P,CAAA,CAAkB1P,CAAlB,CADU,CAIdg1C,CAAA,CAAe,IARU,CAW3BkB,QAASA,EAAkB,EAAG,CACP,IAArB,GAAIlB,CAAJ,GACEA,CADF;AACiB9lC,CAAAiT,MAAA,CAAe,QAAQ,EAAG,CACvCnR,CAAAhO,OAAA,CAAkBgzC,CAAlB,CADuC,CAA1B,CADjB,CAD4B,CAroC9BV,CAAA56C,UAAA,CAAkB,CAChBoC,YAAaw4C,CADG,CA+BhBxsB,KAAMA,QAAQ,CAACqtB,CAAD,CAAUl8C,CAAV,CAAkB,CAC9B,IAAIm8C,CAEJn8C,EAAA,CAASA,CAAT,EAAmB,IAEfk8C,EAAJ,EACEC,CACA,CADQ,IAAId,CACZ,CAAAc,CAAAX,MAAA,CAAc,IAAAA,MAFhB,GAMO,IAAAb,aAGL,GAFE,IAAAA,aAEF,CAFsBV,CAAA,CAAsB,IAAtB,CAEtB,EAAAkC,CAAA,CAAQ,IAAI,IAAAxB,aATd,CAWAwB,EAAAb,QAAA,CAAgBt7C,CAChBm8C,EAAAZ,cAAA,CAAsBv7C,CAAAs6C,YAClBt6C,EAAAq6C,YAAJ,EACEr6C,CAAAs6C,YAAAF,cACA,CADmC+B,CACnC,CAAAn8C,CAAAs6C,YAAA,CAAqB6B,CAFvB,EAIEn8C,CAAAq6C,YAJF,CAIuBr6C,CAAAs6C,YAJvB,CAI4C6B,CAQ5C,EAAID,CAAJ,EAAel8C,CAAf,EAAyB,IAAzB,GAA+Bm8C,CAAAptB,IAAA,CAAU,UAAV,CAAsBmsB,CAAtB,CAE/B,OAAOiB,EAhCuB,CA/BhB,CAsLhBl7C,OAAQA,QAAQ,CAACm7C,CAAD,CAAW91B,CAAX,CAAqBkuB,CAArB,CAAqCE,CAArC,CAA4D,CAC1E,IAAI7qC,EAAMgN,CAAA,CAAOulC,CAAP,CAEV,IAAIvyC,CAAAk9B,gBAAJ,CACE,MAAOl9B,EAAAk9B,gBAAA,CAAoB,IAApB,CAA0BzgB,CAA1B,CAAoCkuB,CAApC,CAAoD3qC,CAApD,CAAyDuyC,CAAzD,CAJiE,KAMtEvzC,EAAQ,IAN8D,CAOtE7G,EAAQ6G,CAAAsxC,WAP8D,CAQtEkC;AAAU,CACRp4C,GAAIqiB,CADI,CAERg2B,KAAMR,CAFE,CAGRjyC,IAAKA,CAHG,CAIR68B,IAAKgO,CAALhO,EAA8B0V,CAJtB,CAKRG,GAAI,CAAE/H,CAAAA,CALE,CAQdsG,EAAA,CAAiB,IAEZn9C,EAAA,CAAW2oB,CAAX,CAAL,GACE+1B,CAAAp4C,GADF,CACe9D,CADf,CAIK6B,EAAL,GACEA,CADF,CACU6G,CAAAsxC,WADV,CAC6B,EAD7B,CAKAn4C,EAAAsG,QAAA,CAAc+zC,CAAd,CACAV,EAAA,CAAuB,IAAvB,CAA6B,CAA7B,CAEA,OAAOa,SAAwB,EAAG,CACG,CAAnC,EAAIz6C,EAAA,CAAYC,CAAZ,CAAmBq6C,CAAnB,CAAJ,EACEV,CAAA,CAAuB9yC,CAAvB,CAA+B,EAA/B,CAEFiyC,EAAA,CAAiB,IAJe,CA9BwC,CAtL5D,CAqPhB9T,YAAaA,QAAQ,CAACyV,CAAD,CAAmBn2B,CAAnB,CAA6B,CAwChDo2B,QAASA,EAAgB,EAAG,CAC1BC,CAAA,CAA0B,CAAA,CAEtBC,EAAJ,EACEA,CACA,CADW,CAAA,CACX,CAAAt2B,CAAA,CAASu2B,CAAT,CAAoBA,CAApB,CAA+B74C,CAA/B,CAFF,EAIEsiB,CAAA,CAASu2B,CAAT,CAAoB3V,CAApB,CAA+BljC,CAA/B,CAPwB,CAvC5B,IAAIkjC,EAAgBxjB,KAAJ,CAAU+4B,CAAAx/C,OAAV,CAAhB,CACI4/C,EAAgBn5B,KAAJ,CAAU+4B,CAAAx/C,OAAV,CADhB,CAEI6/C,EAAgB,EAFpB,CAGI94C,EAAO,IAHX,CAII24C,EAA0B,CAAA,CAJ9B,CAKIC,EAAW,CAAA,CAEf,IAAK3/C,CAAAw/C,CAAAx/C,OAAL,CAA8B,CAE5B,IAAI8/C,EAAa,CAAA,CACjB/4C,EAAAhD,WAAA,CAAgB,QAAQ,EAAG,CACrB+7C,CAAJ,EAAgBz2B,CAAA,CAASu2B,CAAT,CAAoBA,CAApB,CAA+B74C,CAA/B,CADS,CAA3B,CAGA,OAAOg5C,SAA6B,EAAG,CACrCD,CAAA,CAAa,CAAA,CADwB,CANX,CAW9B,GAAgC,CAAhC,GAAIN,CAAAx/C,OAAJ,CAEE,MAAO,KAAAgE,OAAA,CAAYw7C,CAAA,CAAiB,CAAjB,CAAZ,CAAiCC,QAAyB,CAACp+C,CAAD,CAAQ86B,CAAR,CAAkBvwB,CAAlB,CAAyB,CACxFg0C,CAAA,CAAU,CAAV,CAAA,CAAev+C,CACf4oC,EAAA,CAAU,CAAV,CAAA,CAAe9N,CACf9S,EAAA,CAASu2B,CAAT,CAAqBv+C,CAAD,GAAW86B,CAAX,CAAuByjB,CAAvB,CAAmC3V,CAAvD,CAAkEr+B,CAAlE,CAHwF,CAAnF,CAOTtL,EAAA,CAAQk/C,CAAR,CAA0B,QAAQ,CAAC9K,CAAD,CAAOxzC,CAAP,CAAU,CAC1C,IAAI8+C,EAAYj5C,CAAA/C,OAAA,CAAY0wC,CAAZ,CAAkBuL,QAA4B,CAAC5+C,CAAD;AAAQ86B,CAAR,CAAkB,CAC9EyjB,CAAA,CAAU1+C,CAAV,CAAA,CAAeG,CACf4oC,EAAA,CAAU/oC,CAAV,CAAA,CAAei7B,CACVujB,EAAL,GACEA,CACA,CAD0B,CAAA,CAC1B,CAAA34C,CAAAhD,WAAA,CAAgB07C,CAAhB,CAFF,CAH8E,CAAhE,CAQhBI,EAAAl6C,KAAA,CAAmBq6C,CAAnB,CAT0C,CAA5C,CAuBA,OAAOD,SAA6B,EAAG,CACrC,IAAA,CAAOF,CAAA7/C,OAAP,CAAA,CACE6/C,CAAA16B,MAAA,EAAA,EAFmC,CAnDS,CArPlC,CAuWhB0Y,iBAAkBA,QAAQ,CAAC/9B,CAAD,CAAMupB,CAAN,CAAgB,CAoBxC62B,QAASA,EAA2B,CAACC,CAAD,CAAS,CAC3CnkB,CAAA,CAAWmkB,CADgC,KAE5B1/C,CAF4B,CAEvB2/C,CAFuB,CAEdC,CAFc,CAELC,CAGtC,IAAI,CAAA78C,CAAA,CAAYu4B,CAAZ,CAAJ,CAAA,CAEA,GAAKh6B,CAAA,CAASg6B,CAAT,CAAL,CAKO,GAAIn8B,EAAA,CAAYm8B,CAAZ,CAAJ,CAgBL,IAfIG,CAeKj7B,GAfQq/C,CAeRr/C,GAbPi7B,CAEA,CAFWokB,CAEX,CADAC,CACA,CADYrkB,CAAAn8B,OACZ,CAD8B,CAC9B,CAAAygD,CAAA,EAWOv/C,EARTw/C,CAQSx/C,CARG86B,CAAAh8B,OAQHkB,CANLs/C,CAMKt/C,GANSw/C,CAMTx/C,GAJPu/C,CAAA,EACA,CAAAtkB,CAAAn8B,OAAA,CAAkBwgD,CAAlB,CAA8BE,CAGvBx/C,EAAAA,CAAAA,CAAI,CAAb,CAAgBA,CAAhB,CAAoBw/C,CAApB,CAA+Bx/C,CAAA,EAA/B,CACEo/C,CAIA,CAJUnkB,CAAA,CAASj7B,CAAT,CAIV,CAHAm/C,CAGA,CAHUrkB,CAAA,CAAS96B,CAAT,CAGV,CADAk/C,CACA,CADWE,CACX,GADuBA,CACvB,EADoCD,CACpC,GADgDA,CAChD,CAAKD,CAAL,EAAiBE,CAAjB,GAA6BD,CAA7B,GACEI,CAAA,EACA,CAAAtkB,CAAA,CAASj7B,CAAT,CAAA,CAAcm/C,CAFhB,CArBG,KA0BA,CACDlkB,CAAJ,GAAiBwkB,CAAjB,GAEExkB,CAEA,CAFWwkB,CAEX,CAF4B,EAE5B,CADAH,CACA,CADY,CACZ,CAAAC,CAAA,EAJF,CAOAC,EAAA,CAAY,CACZ,KAAKjgD,CAAL,GAAYu7B,EAAZ,CACMA,CAAAr7B,eAAA,CAAwBF,CAAxB,CAAJ,GACEigD,CAAA,EAIA,CAHAL,CAGA,CAHUrkB,CAAA,CAASv7B,CAAT,CAGV,CAFA6/C,CAEA,CAFUnkB,CAAA,CAAS17B,CAAT,CAEV,CAAIA,CAAJ,GAAW07B,EAAX,EACEikB,CACA,CADWE,CACX,GADuBA,CACvB,EADoCD,CACpC,GADgDA,CAChD,CAAKD,CAAL,EAAiBE,CAAjB,GAA6BD,CAA7B,GACEI,CAAA,EACA,CAAAtkB,CAAA,CAAS17B,CAAT,CAAA,CAAgB4/C,CAFlB,CAFF,GAOEG,CAAA,EAEA,CADArkB,CAAA,CAAS17B,CAAT,CACA,CADgB4/C,CAChB,CAAAI,CAAA,EATF,CALF,CAkBF,IAAID,CAAJ,CAAgBE,CAAhB,CAGE,IAAKjgD,CAAL,GADAggD,EAAA,EACYtkB,CAAAA,CAAZ,CACOH,CAAAr7B,eAAA,CAAwBF,CAAxB,CAAL;CACE+/C,CAAA,EACA,CAAA,OAAOrkB,CAAA,CAAS17B,CAAT,CAFT,CAhCC,CA/BP,IACM07B,EAAJ,GAAiBH,CAAjB,GACEG,CACA,CADWH,CACX,CAAAykB,CAAA,EAFF,CAqEF,OAAOA,EAxEP,CAL2C,CAnB7CP,CAAAviB,UAAA,CAAwC,CAAA,CAExC,KAAI52B,EAAO,IAAX,CAEIi1B,CAFJ,CAKIG,CALJ,CAOIykB,CAPJ,CASIC,EAAuC,CAAvCA,CAAqBx3B,CAAArpB,OATzB,CAUIygD,EAAiB,CAVrB,CAWIK,EAAiBlnC,CAAA,CAAO9Z,CAAP,CAAYogD,CAAZ,CAXrB,CAYIK,EAAgB,EAZpB,CAaII,EAAiB,EAbrB,CAcII,EAAU,CAAA,CAdd,CAeIP,EAAY,CA+GhB,OAAO,KAAAx8C,OAAA,CAAY88C,CAAZ,CA7BPE,QAA+B,EAAG,CAC5BD,CAAJ,EACEA,CACA,CADU,CAAA,CACV,CAAA13B,CAAA,CAAS2S,CAAT,CAAmBA,CAAnB,CAA6Bj1B,CAA7B,CAFF,EAIEsiB,CAAA,CAAS2S,CAAT,CAAmB4kB,CAAnB,CAAiC75C,CAAjC,CAIF,IAAI85C,CAAJ,CACE,GAAK7+C,CAAA,CAASg6B,CAAT,CAAL,CAGO,GAAIn8B,EAAA,CAAYm8B,CAAZ,CAAJ,CAA2B,CAChC4kB,CAAA,CAAmBn6B,KAAJ,CAAUuV,CAAAh8B,OAAV,CACf,KAAS,IAAAkB,EAAI,CAAb,CAAgBA,CAAhB,CAAoB86B,CAAAh8B,OAApB,CAAqCkB,CAAA,EAArC,CACE0/C,CAAA,CAAa1/C,CAAb,CAAA,CAAkB86B,CAAA,CAAS96B,CAAT,CAHY,CAA3B,IAOL,KAAST,CAAT,GADAmgD,EACgB5kB,CADD,EACCA,CAAAA,CAAhB,CACMr7B,EAAAC,KAAA,CAAoBo7B,CAApB,CAA8Bv7B,CAA9B,CAAJ,GACEmgD,CAAA,CAAangD,CAAb,CADF,CACsBu7B,CAAA,CAASv7B,CAAT,CADtB,CAXJ,KAEEmgD,EAAA,CAAe5kB,CAZa,CA6B3B,CAjIiC,CAvW1B,CA8hBhBoW,QAASA,QAAQ,EAAG,CAAA,IACd6O,CADc,CACP5/C,CADO,CACAg+C,CADA,CAEd6B,CAFc,CAGdlhD,CAHc,CAIdmhD,CAJc,CAIPC,EAAMzD,CAJC,CAKRgB,CALQ,CAMd0C,EAAW,EANG,CAOdC,CAPc,CAOEC,CAEpB/C,EAAA,CAAW,SAAX,CAEAxmC,EAAA8S,iBAAA,EAEI,KAAJ,GAAahR,CAAb,EAA4C,IAA5C,GAA2BgkC,CAA3B,GAGE9lC,CAAAiT,MAAAI,OAAA,CAAsByyB,CAAtB,CACA,CAAAgB,CAAA,EAJF,CAOAjB,EAAA,CAAiB,IAEjB,GAAG,CACDsD,CAAA,CAAQ,CAAA,CAGR,KAFAxC,CAEA,CArB0B7M,IAqB1B,CAAO0P,CAAAxhD,OAAP,CAAA,CAA0B,CACxB,GAAI,CACFuhD,CACA,CADYC,CAAAr8B,MAAA,EACZ;AAAAo8B,CAAA31C,MAAA61C,MAAA,CAAsBF,CAAAjhB,WAAtB,CAA4CihB,CAAAn8B,OAA5C,CAFE,CAGF,MAAOtc,CAAP,CAAU,CACV0P,CAAA,CAAkB1P,CAAlB,CADU,CAGZ+0C,CAAA,CAAiB,IAPO,CAU1B,CAAA,CACA,EAAG,CACD,GAAKqD,CAAL,CAAgBvC,CAAAzB,WAAhB,CAGE,IADAl9C,CACA,CADSkhD,CAAAlhD,OACT,CAAOA,CAAA,EAAP,CAAA,CACE,GAAI,CAIF,GAHAihD,CAGA,CAHQC,CAAA,CAASlhD,CAAT,CAGR,CACE,IAAKqB,CAAL,CAAa4/C,CAAAr0C,IAAA,CAAU+xC,CAAV,CAAb,KAAsCU,CAAtC,CAA6C4B,CAAA5B,KAA7C,GACM,EAAA4B,CAAA3B,GAAA,CACIl5C,EAAA,CAAO/E,CAAP,CAAcg+C,CAAd,CADJ,CAEsB,QAFtB,GAEK,MAAOh+C,EAFZ,EAEkD,QAFlD,GAEkC,MAAOg+C,EAFzC,EAGQp3C,KAAA,CAAM5G,CAAN,CAHR,EAGwB4G,KAAA,CAAMo3C,CAAN,CAHxB,CADN,CAKE8B,CAIA,CAJQ,CAAA,CAIR,CAHAtD,CAGA,CAHiBoD,CAGjB,CAFAA,CAAA5B,KAEA,CAFa4B,CAAA3B,GAAA,CAAWn6C,EAAA,CAAK9D,CAAL,CAAY,IAAZ,CAAX,CAA+BA,CAE5C,CADA4/C,CAAAj6C,GAAA,CAAS3F,CAAT,CAAkBg+C,CAAD,GAAUR,CAAV,CAA0Bx9C,CAA1B,CAAkCg+C,CAAnD,CAA0DV,CAA1D,CACA,CAAU,CAAV,CAAIyC,CAAJ,GACEE,CAEA,CAFS,CAET,CAFaF,CAEb,CADKC,CAAA,CAASC,CAAT,CACL,GADuBD,CAAA,CAASC,CAAT,CACvB,CAD0C,EAC1C,EAAAD,CAAA,CAASC,CAAT,CAAA37C,KAAA,CAAsB,CACpB+7C,IAAKhhD,CAAA,CAAWugD,CAAAxX,IAAX,CAAA,CAAwB,MAAxB,EAAkCwX,CAAAxX,IAAA9+B,KAAlC,EAAoDs2C,CAAAxX,IAAAlmC,SAAA,EAApD,EAA4E09C,CAAAxX,IAD7D,CAEpB7hB,OAAQvmB,CAFY,CAGpBwmB,OAAQw3B,CAHY,CAAtB,CAHF,CATF,KAkBO,IAAI4B,CAAJ,GAAcpD,CAAd,CAA8B,CAGnCsD,CAAA,CAAQ,CAAA,CACR,OAAM,CAJ6B,CAvBrC,CA8BF,MAAOr4C,CAAP,CAAU,CACV0P,CAAA,CAAkB1P,CAAlB,CADU,CAShB,GAAM,EAAA64C,CAAA,CAAShD,CAAAnB,gBAAT,EAAoCmB,CAAAvB,YAApC,EACDuB,CADC,GA5EkB7M,IA4ElB,EACqB6M,CAAAxB,cADrB,CAAN,CAEE,IAAA,CAAOwB,CAAP;AA9EsB7M,IA8EtB,EAA+B,EAAA6P,CAAA,CAAOhD,CAAAxB,cAAP,CAA/B,CAAA,CACEwB,CAAA,CAAUA,CAAAN,QA/Cb,CAAH,MAkDUM,CAlDV,CAkDoBgD,CAlDpB,CAsDA,KAAKR,CAAL,EAAcK,CAAAxhD,OAAd,GAAsC,CAAAohD,CAAA,EAAtC,CAEE,KAseNtnC,EAAA6rB,QAteY,CAseS,IAteT,CAAAiY,CAAA,CAAiB,QAAjB,CAGFD,CAHE,CAGG0D,CAHH,CAAN,CAvED,CAAH,MA6ESF,CA7ET,EA6EkBK,CAAAxhD,OA7ElB,CAiFA,KA4dF8Z,CAAA6rB,QA5dE,CA4dmB,IA5dnB,CAAOic,CAAA5hD,OAAP,CAAA,CACE,GAAI,CACF4hD,CAAAz8B,MAAA,EAAA,EADE,CAEF,MAAOrc,CAAP,CAAU,CACV0P,CAAA,CAAkB1P,CAAlB,CADU,CA1GI,CA9hBJ,CAirBhBuF,SAAUA,QAAQ,EAAG,CAEnB,GAAI8rB,CAAA,IAAAA,YAAJ,CAAA,CACA,IAAIp3B,EAAS,IAAAs7C,QAEb,KAAAjN,WAAA,CAAgB,UAAhB,CACA,KAAAjX,YAAA,CAAmB,CAAA,CAEf,KAAJ,GAAargB,CAAb,EAEE9B,CAAA2S,uBAAA,EAGF+zB,EAAA,CAAuB,IAAvB,CAA6B,CAAC,IAAAlB,gBAA9B,CACA,KAASqE,IAAAA,CAAT,GAAsB,KAAAtE,gBAAtB,CACEqB,CAAA,CAAuB,IAAvB,CAA6B,IAAArB,gBAAA,CAAqBsE,CAArB,CAA7B,CAA8DA,CAA9D,CAKE9+C,EAAJ,EAAcA,CAAAq6C,YAAd,EAAoC,IAApC,GAA0Cr6C,CAAAq6C,YAA1C,CAA+D,IAAAD,cAA/D,CACIp6C,EAAJ,EAAcA,CAAAs6C,YAAd;AAAoC,IAApC,GAA0Ct6C,CAAAs6C,YAA1C,CAA+D,IAAAiB,cAA/D,CACI,KAAAA,cAAJ,GAAwB,IAAAA,cAAAnB,cAAxB,CAA2D,IAAAA,cAA3D,CACI,KAAAA,cAAJ,GAAwB,IAAAA,cAAAmB,cAAxB,CAA2D,IAAAA,cAA3D,CAGA,KAAAjwC,SAAA,CAAgB,IAAA+jC,QAAhB,CAA+B,IAAAtmC,OAA/B,CAA6C,IAAA/H,WAA7C,CAA+D,IAAA2hC,YAA/D,CAAkFxiC,CAClF,KAAA4uB,IAAA,CAAW,IAAA9tB,OAAX,CAAyB,IAAA+lC,YAAzB,CAA4C+X,QAAQ,EAAG,CAAE,MAAO5+C,EAAT,CACvD,KAAAo6C,YAAA,CAAmB,EAUnB,KAAAe,QAAA,CAAe,IAAAlB,cAAf,CAAoC,IAAAmB,cAApC,CAAyD,IAAAlB,YAAzD,CACI,IAAAC,YADJ,CACuB,IAAAkB,MADvB,CACoC,IAAArB,WADpC,CACsD,IArCtD,CAFmB,CAjrBL,CAuvBhBuE,MAAOA,QAAQ,CAAC/M,CAAD,CAAOtvB,CAAP,CAAe,CAC5B,MAAOxL,EAAA,CAAO86B,CAAP,CAAA,CAAa,IAAb,CAAmBtvB,CAAnB,CADqB,CAvvBd;AAyxBhBrhB,WAAYA,QAAQ,CAAC2wC,CAAD,CAAOtvB,CAAP,CAAe,CAG5BtL,CAAA6rB,QAAL,EAA4B6b,CAAAxhD,OAA5B,EACEgY,CAAAiT,MAAA,CAAe,QAAQ,EAAG,CACpBu2B,CAAAxhD,OAAJ,EACE8Z,CAAAs4B,QAAA,EAFsB,CAA1B,CAOFoP,EAAA77C,KAAA,CAAgB,CAACiG,MAAO,IAAR,CAAc00B,WAAYoU,CAA1B,CAAgCtvB,OAAQA,CAAxC,CAAhB,CAXiC,CAzxBnB,CAuyBhBozB,aAAcA,QAAQ,CAACxxC,CAAD,CAAK,CACzB46C,CAAAj8C,KAAA,CAAqBqB,CAArB,CADyB,CAvyBX,CAw1BhB8E,OAAQA,QAAQ,CAAC4oC,CAAD,CAAO,CACrB,GAAI,CAEF,MADA8J,EAAA,CAAW,QAAX,CACO,CAAA,IAAAiD,MAAA,CAAW/M,CAAX,CAFL,CAGF,MAAO5rC,CAAP,CAAU,CACV0P,CAAA,CAAkB1P,CAAlB,CADU,CAHZ,OAKU,CAmQZgR,CAAA6rB,QAAA,CAAqB,IAjQjB,IAAI,CACF7rB,CAAAs4B,QAAA,EADE,CAEF,MAAOtpC,CAAP,CAAU,CAEV,KADA0P,EAAA,CAAkB1P,CAAlB,CACMA,CAAAA,CAAN,CAFU,CAJJ,CANW,CAx1BP,CA03BhB48B,YAAaA,QAAQ,CAACgP,CAAD,CAAO,CAK1BqN,QAASA,EAAqB,EAAG,CAC/Bn2C,CAAA61C,MAAA,CAAY/M,CAAZ,CAD+B,CAJjC,IAAI9oC,EAAQ,IACZ8oC,EAAA,EAAQqK,CAAAp5C,KAAA,CAAqBo8C,CAArB,CACR/C,EAAA,EAH0B,CA13BZ,CA+5BhBltB,IAAKA,QAAQ,CAACnnB,CAAD,CAAO0e,CAAP,CAAiB,CAC5B,IAAI24B,EAAiB,IAAA1E,YAAA,CAAiB3yC,CAAjB,CAChBq3C,EAAL,GACE,IAAA1E,YAAA,CAAiB3yC,CAAjB,CADF,CAC2Bq3C,CAD3B,CAC4C,EAD5C,CAGAA,EAAAr8C,KAAA,CAAoB0jB,CAApB,CAEA,KAAIs1B,EAAU,IACd,GACOA,EAAApB,gBAAA,CAAwB5yC,CAAxB,CAGL;CAFEg0C,CAAApB,gBAAA,CAAwB5yC,CAAxB,CAEF,CAFkC,CAElC,EAAAg0C,CAAApB,gBAAA,CAAwB5yC,CAAxB,CAAA,EAJF,OAKUg0C,CALV,CAKoBA,CAAAN,QALpB,CAOA,KAAIt3C,EAAO,IACX,OAAO,SAAQ,EAAG,CAChB,IAAIk7C,EAAkBD,CAAA/8C,QAAA,CAAuBokB,CAAvB,CACG,GAAzB,GAAI44B,CAAJ,GACED,CAAA,CAAeC,CAAf,CACA,CADkC,IAClC,CAAArD,CAAA,CAAuB73C,CAAvB,CAA6B,CAA7B,CAAgC4D,CAAhC,CAFF,CAFgB,CAhBU,CA/5Bd,CA+8BhBu3C,MAAOA,QAAQ,CAACv3C,CAAD,CAAOwY,CAAP,CAAa,CAAA,IACtBta,EAAQ,EADc,CAEtBm5C,CAFsB,CAGtBp2C,EAAQ,IAHc,CAItBsW,EAAkB,CAAA,CAJI,CAKtBV,EAAQ,CACN7W,KAAMA,CADA,CAENw3C,YAAav2C,CAFP,CAGNsW,gBAAiBA,QAAQ,EAAG,CAACA,CAAA,CAAkB,CAAA,CAAnB,CAHtB,CAIN8vB,eAAgBA,QAAQ,EAAG,CACzBxwB,CAAAG,iBAAA,CAAyB,CAAA,CADA,CAJrB,CAONA,iBAAkB,CAAA,CAPZ,CALc,CActBygC,EAAez7C,EAAA,CAAO,CAAC6a,CAAD,CAAP,CAAgB/e,SAAhB,CAA2B,CAA3B,CAdO,CAetBvB,CAfsB,CAenBlB,CAEP,GAAG,CACDgiD,CAAA,CAAiBp2C,CAAA0xC,YAAA,CAAkB3yC,CAAlB,CAAjB,EAA4C9B,CAC5C2Y,EAAA28B,aAAA,CAAqBvyC,CAChB1K,EAAA,CAAI,CAAT,KAAYlB,CAAZ,CAAqBgiD,CAAAhiD,OAArB,CAA4CkB,CAA5C,CAAgDlB,CAAhD,CAAwDkB,CAAA,EAAxD,CAGE,GAAK8gD,CAAA,CAAe9gD,CAAf,CAAL,CAMA,GAAI,CAEF8gD,CAAA,CAAe9gD,CAAf,CAAAiG,MAAA,CAAwB,IAAxB,CAA8Bi7C,CAA9B,CAFE,CAGF,MAAOt5C,CAAP,CAAU,CACV0P,CAAA,CAAkB1P,CAAlB,CADU,CATZ,IACEk5C,EAAA98C,OAAA,CAAsBhE,CAAtB,CAAyB,CAAzB,CAEA,CADAA,CAAA,EACA,CAAAlB,CAAA,EAWJ,IAAIkiB,CAAJ,CAEE,MADAV,EAAA28B,aACO38B;AADc,IACdA,CAAAA,CAGT5V,EAAA,CAAQA,CAAAyyC,QAzBP,CAAH,MA0BSzyC,CA1BT,CA4BA4V,EAAA28B,aAAA,CAAqB,IAErB,OAAO38B,EA/CmB,CA/8BZ,CAuhChB4vB,WAAYA,QAAQ,CAACzmC,CAAD,CAAOwY,CAAP,CAAa,CAAA,IAE3Bw7B,EADS7M,IADkB,CAG3B6P,EAFS7P,IADkB,CAI3BtwB,EAAQ,CACN7W,KAAMA,CADA,CAENw3C,YALOrQ,IAGD,CAGNE,eAAgBA,QAAQ,EAAG,CACzBxwB,CAAAG,iBAAA,CAAyB,CAAA,CADA,CAHrB,CAMNA,iBAAkB,CAAA,CANZ,CASZ,IAAK,CAZQmwB,IAYRyL,gBAAA,CAAuB5yC,CAAvB,CAAL,CAAmC,MAAO6W,EAM1C,KAnB+B,IAe3B4gC,EAAez7C,EAAA,CAAO,CAAC6a,CAAD,CAAP,CAAgB/e,SAAhB,CAA2B,CAA3B,CAfY,CAgBhBvB,CAhBgB,CAgBblB,CAGlB,CAAQ2+C,CAAR,CAAkBgD,CAAlB,CAAA,CAAyB,CACvBngC,CAAA28B,aAAA,CAAqBQ,CACrBxf,EAAA,CAAYwf,CAAArB,YAAA,CAAoB3yC,CAApB,CAAZ,EAAyC,EACpCzJ,EAAA,CAAI,CAAT,KAAYlB,CAAZ,CAAqBm/B,CAAAn/B,OAArB,CAAuCkB,CAAvC,CAA2ClB,CAA3C,CAAmDkB,CAAA,EAAnD,CAEE,GAAKi+B,CAAA,CAAUj+B,CAAV,CAAL,CAOA,GAAI,CACFi+B,CAAA,CAAUj+B,CAAV,CAAAiG,MAAA,CAAmB,IAAnB,CAAyBi7C,CAAzB,CADE,CAEF,MAAOt5C,CAAP,CAAU,CACV0P,CAAA,CAAkB1P,CAAlB,CADU,CATZ,IACEq2B,EAAAj6B,OAAA,CAAiBhE,CAAjB,CAAoB,CAApB,CAEA,CADAA,CAAA,EACA,CAAAlB,CAAA,EAeJ,IAAM,EAAA2hD,CAAA,CAAShD,CAAApB,gBAAA,CAAwB5yC,CAAxB,CAAT,EAA0Cg0C,CAAAvB,YAA1C,EACDuB,CADC,GAzCK7M,IAyCL,EACqB6M,CAAAxB,cADrB,CAAN,CAEE,IAAA,CAAOwB,CAAP,GA3CS7M,IA2CT,EAA+B,EAAA6P,CAAA;AAAOhD,CAAAxB,cAAP,CAA/B,CAAA,CACEwB,CAAA,CAAUA,CAAAN,QA1BS,CA+BzB78B,CAAA28B,aAAA,CAAqB,IACrB,OAAO38B,EAnDwB,CAvhCjB,CA8kClB,KAAI1H,EAAa,IAAIskC,CAArB,CAGIoD,EAAa1nC,CAAAuoC,aAAbb,CAAuC,EAH3C,CAIII,EAAkB9nC,CAAAwoC,kBAAlBV,CAAiD,EAJrD,CAKI7C,EAAkBjlC,CAAAyoC,kBAAlBxD,CAAiD,EAErD,OAAOjlC,EA3qCoD,CADjD,CA3BgB,CAqwC9B9H,QAASA,GAAqB,EAAG,CAAA,IAC3Bmd,EAA6B,mCADF,CAE7BG,EAA8B,4CAkBhC,KAAAH,2BAAA,CAAkCC,QAAQ,CAACC,CAAD,CAAS,CACjD,MAAI3rB,EAAA,CAAU2rB,CAAV,CAAJ,EACEF,CACO,CADsBE,CACtB,CAAA,IAFT,EAIOF,CAL0C,CAyBnD,KAAAG,4BAAA,CAAmCC,QAAQ,CAACF,CAAD,CAAS,CAClD,MAAI3rB,EAAA,CAAU2rB,CAAV,CAAJ,EACEC,CACO,CADuBD,CACvB,CAAA,IAFT,EAIOC,CAL2C,CAQpD,KAAAjN,KAAA,CAAYC,QAAQ,EAAG,CACrB,MAAOkgC,SAAoB,CAACC,CAAD,CAAMC,CAAN,CAAe,CACxC,IAAIC,EAAQD,CAAA,CAAUpzB,CAAV,CAAwCH,CAApD,CACIyzB,CACJA,EAAA,CAAgB1a,EAAA,CAAWua,CAAX,CAAA14B,KAChB,OAAsB,EAAtB,GAAI64B,CAAJ,EAA6BA,CAAA78C,MAAA,CAAoB48C,CAApB,CAA7B,CAGOF,CAHP,CACS,SADT;AACqBG,CALmB,CADrB,CArDQ,CA2FjCC,QAASA,GAAa,CAACC,CAAD,CAAU,CAC9B,GAAgB,MAAhB,GAAIA,CAAJ,CACE,MAAOA,EACF,IAAI1iD,CAAA,CAAS0iD,CAAT,CAAJ,CAAuB,CAK5B,GAA8B,EAA9B,CAAIA,CAAA79C,QAAA,CAAgB,KAAhB,CAAJ,CACE,KAAM89C,GAAA,CAAW,QAAX,CACsDD,CADtD,CAAN,CAGFA,CAAA,CAAUE,EAAA,CAAgBF,CAAhB,CAAA35C,QAAA,CACY,QADZ,CACsB,IADtB,CAAAA,QAAA,CAEY,KAFZ,CAEmB,YAFnB,CAGV,OAAO,KAAIrD,MAAJ,CAAW,GAAX,CAAiBg9C,CAAjB,CAA2B,GAA3B,CAZqB,CAavB,GAAIj/C,EAAA,CAASi/C,CAAT,CAAJ,CAIL,MAAO,KAAIh9C,MAAJ,CAAW,GAAX,CAAiBg9C,CAAA19C,OAAjB,CAAkC,GAAlC,CAEP,MAAM29C,GAAA,CAAW,UAAX,CAAN,CAtB4B,CA4BhCE,QAASA,GAAc,CAACC,CAAD,CAAW,CAChC,IAAIC,EAAmB,EACnBz/C,EAAA,CAAUw/C,CAAV,CAAJ,EACE5iD,CAAA,CAAQ4iD,CAAR,CAAkB,QAAQ,CAACJ,CAAD,CAAU,CAClCK,CAAAx9C,KAAA,CAAsBk9C,EAAA,CAAcC,CAAd,CAAtB,CADkC,CAApC,CAIF,OAAOK,EAPyB,CA8ElC5oC,QAASA,GAAoB,EAAG,CAC9B,IAAA6oC,aAAA,CAAoBA,EADU,KAI1BC,EAAuB,CAAC,MAAD,CAJG,CAK1BC,EAAuB,EAwB3B,KAAAD,qBAAA,CAA4BE,QAAQ,CAACliD,CAAD,CAAQ,CACtCoB,SAAAzC,OAAJ,GACEqjD,CADF,CACyBJ,EAAA,CAAe5hD,CAAf,CADzB,CAGA,OAAOgiD,EAJmC,CAkC5C,KAAAC,qBAAA,CAA4BE,QAAQ,CAACniD,CAAD,CAAQ,CACtCoB,SAAAzC,OAAJ;CACEsjD,CADF,CACyBL,EAAA,CAAe5hD,CAAf,CADzB,CAGA,OAAOiiD,EAJmC,CAO5C,KAAAjhC,KAAA,CAAY,CAAC,WAAD,CAAc,QAAQ,CAACuD,CAAD,CAAY,CAW5C69B,QAASA,EAAQ,CAACX,CAAD,CAAUxV,CAAV,CAAqB,CACpC,MAAgB,MAAhB,GAAIwV,CAAJ,CACSzc,EAAA,CAAgBiH,CAAhB,CADT,CAIS,CAAE,CAAAwV,CAAAlmC,KAAA,CAAa0wB,CAAAvjB,KAAb,CALyB,CA+BtC25B,QAASA,EAAkB,CAACC,CAAD,CAAO,CAChC,IAAIC,EAAaA,QAA+B,CAACC,CAAD,CAAe,CAC7D,IAAAC,qBAAA,CAA4BC,QAAQ,EAAG,CACrC,MAAOF,EAD8B,CADsB,CAK3DF,EAAJ,GACEC,CAAApgD,UADF,CACyB,IAAImgD,CAD7B,CAGAC,EAAApgD,UAAAlB,QAAA,CAA+B0hD,QAAmB,EAAG,CACnD,MAAO,KAAAF,qBAAA,EAD4C,CAGrDF,EAAApgD,UAAAD,SAAA,CAAgC0gD,QAAoB,EAAG,CACrD,MAAO,KAAAH,qBAAA,EAAAvgD,SAAA,EAD8C,CAGvD,OAAOqgD,EAfyB,CAxClC,IAAIM,EAAgBA,QAAsB,CAACj7C,CAAD,CAAO,CAC/C,KAAM85C,GAAA,CAAW,QAAX,CAAN,CAD+C,CAI7Cn9B,EAAAD,IAAA,CAAc,WAAd,CAAJ,GACEu+B,CADF,CACkBt+B,CAAAhZ,IAAA,CAAc,WAAd,CADlB,CAN4C,KA4DxCu3C,EAAyBT,CAAA,EA5De,CA6DxCU,EAAS,EAEbA,EAAA,CAAOhB,EAAA1nB,KAAP,CAAA,CAA4BgoB,CAAA,CAAmBS,CAAnB,CAC5BC,EAAA,CAAOhB,EAAAiB,IAAP,CAAA,CAA2BX,CAAA,CAAmBS,CAAnB,CAC3BC,EAAA,CAAOhB,EAAAkB,IAAP,CAAA;AAA2BZ,CAAA,CAAmBS,CAAnB,CAC3BC,EAAA,CAAOhB,EAAAmB,GAAP,CAAA,CAA0Bb,CAAA,CAAmBS,CAAnB,CAC1BC,EAAA,CAAOhB,EAAAznB,aAAP,CAAA,CAAoC+nB,CAAA,CAAmBU,CAAA,CAAOhB,EAAAkB,IAAP,CAAnB,CAyGpC,OAAO,CAAEE,QAtFTA,QAAgB,CAAClmC,CAAD,CAAOulC,CAAP,CAAqB,CACnC,IAAIY,EAAeL,CAAAzjD,eAAA,CAAsB2d,CAAtB,CAAA,CAA8B8lC,CAAA,CAAO9lC,CAAP,CAA9B,CAA6C,IAChE,IAAKmmC,CAAAA,CAAL,CACE,KAAM1B,GAAA,CAAW,UAAX,CAEFzkC,CAFE,CAEIulC,CAFJ,CAAN,CAIF,GAAqB,IAArB,GAAIA,CAAJ,EAA6BA,CAA7B,GAA8ClkD,CAA9C,EAA4E,EAA5E,GAA2DkkD,CAA3D,CACE,MAAOA,EAIT,IAA4B,QAA5B,GAAI,MAAOA,EAAX,CACE,KAAMd,GAAA,CAAW,OAAX,CAEFzkC,CAFE,CAAN,CAIF,MAAO,KAAImmC,CAAJ,CAAgBZ,CAAhB,CAjB4B,CAsF9B,CACE5a,WA1BTA,QAAmB,CAAC3qB,CAAD,CAAOomC,CAAP,CAAqB,CACtC,GAAqB,IAArB,GAAIA,CAAJ,EAA6BA,CAA7B,GAA8C/kD,CAA9C,EAA4E,EAA5E,GAA2D+kD,CAA3D,CACE,MAAOA,EAET,KAAI9+C,EAAew+C,CAAAzjD,eAAA,CAAsB2d,CAAtB,CAAA,CAA8B8lC,CAAA,CAAO9lC,CAAP,CAA9B,CAA6C,IAChE,IAAI1Y,CAAJ,EAAmB8+C,CAAnB,WAA2C9+C,EAA3C,CACE,MAAO8+C,EAAAZ,qBAAA,EAKT,IAAIxlC,CAAJ,GAAa8kC,EAAAznB,aAAb,CAAwC,CAzIpC2R,IAAAA,EAAYpF,EAAA,CA0ImBwc,CA1IRnhD,SAAA,EAAX,CAAZ+pC,CACApsC,CADAosC,CACGxhB,CADHwhB,CACMqX,EAAU,CAAA,CAEfzjD,EAAA,CAAI,CAAT,KAAY4qB,CAAZ,CAAgBu3B,CAAArjD,OAAhB,CAA6CkB,CAA7C,CAAiD4qB,CAAjD,CAAoD5qB,CAAA,EAApD,CACE,GAAIuiD,CAAA,CAASJ,CAAA,CAAqBniD,CAArB,CAAT,CAAkCosC,CAAlC,CAAJ,CAAkD,CAChDqX,CAAA,CAAU,CAAA,CACV,MAFgD,CAKpD,GAAIA,CAAJ,CAEE,IAAKzjD,CAAO;AAAH,CAAG,CAAA4qB,CAAA,CAAIw3B,CAAAtjD,OAAhB,CAA6CkB,CAA7C,CAAiD4qB,CAAjD,CAAoD5qB,CAAA,EAApD,CACE,GAAIuiD,CAAA,CAASH,CAAA,CAAqBpiD,CAArB,CAAT,CAAkCosC,CAAlC,CAAJ,CAAkD,CAChDqX,CAAA,CAAU,CAAA,CACV,MAFgD,CA8HpD,GAxHKA,CAwHL,CACE,MAAOD,EAEP,MAAM3B,GAAA,CAAW,UAAX,CAEF2B,CAAAnhD,SAAA,EAFE,CAAN,CAJoC,CAQjC,GAAI+a,CAAJ,GAAa8kC,EAAA1nB,KAAb,CACL,MAAOwoB,EAAA,CAAcQ,CAAd,CAET,MAAM3B,GAAA,CAAW,QAAX,CAAN,CAtBsC,CAyBjC,CAEEzgD,QAlDTA,QAAgB,CAACoiD,CAAD,CAAe,CAC7B,MAAIA,EAAJ,WAA4BP,EAA5B,CACSO,CAAAZ,qBAAA,EADT,CAGSY,CAJoB,CAgDxB,CA5KqC,CAAlC,CAtEkB,CAkhBhCrqC,QAASA,GAAY,EAAG,CACtB,IAAIoV,EAAU,CAAA,CAad,KAAAA,QAAA,CAAem1B,QAAQ,CAACvjD,CAAD,CAAQ,CACzBoB,SAAAzC,OAAJ,GACEyvB,CADF,CACY,CAAEpuB,CAAAA,CADd,CAGA,OAAOouB,EAJsB,CAsD/B,KAAApN,KAAA,CAAY,CAAC,QAAD,CAAW,cAAX,CAA2B,QAAQ,CACjCzI,CADiC,CACvBU,CADuB,CACT,CAGpC,GAAImV,CAAJ,EAAsB,CAAtB,CAAeyE,EAAf,CACE,KAAM6uB,GAAA,CAAW,UAAX,CAAN,CAMF,IAAI8B,EAAM3+C,EAAA,CAAYk9C,EAAZ,CAaVyB,EAAAC,UAAA,CAAgBC,QAAQ,EAAG,CACzB,MAAOt1B,EADkB,CAG3Bo1B,EAAAL,QAAA,CAAclqC,CAAAkqC,QACdK,EAAA5b,WAAA,CAAiB3uB,CAAA2uB,WACjB4b,EAAAviD,QAAA,CAAcgY,CAAAhY,QAETmtB,EAAL,GACEo1B,CAAAL,QACA;AADcK,CAAA5b,WACd,CAD+B+b,QAAQ,CAAC1mC,CAAD,CAAOjd,CAAP,CAAc,CAAE,MAAOA,EAAT,CACrD,CAAAwjD,CAAAviD,QAAA,CAAca,EAFhB,CAwBA0hD,EAAAI,QAAA,CAAcC,QAAmB,CAAC5mC,CAAD,CAAOo2B,CAAP,CAAa,CAC5C,IAAIh3B,EAAS9D,CAAA,CAAO86B,CAAP,CACb,OAAIh3B,EAAA6f,QAAJ,EAAsB7f,CAAA1M,SAAtB,CACS0M,CADT,CAGS9D,CAAA,CAAO86B,CAAP,CAAa,QAAQ,CAACrzC,CAAD,CAAQ,CAClC,MAAOwjD,EAAA5b,WAAA,CAAe3qB,CAAf,CAAqBjd,CAArB,CAD2B,CAA7B,CALmC,CAtDV,KAoThCuG,EAAQi9C,CAAAI,QApTwB,CAqThChc,EAAa4b,CAAA5b,WArTmB,CAsThCub,EAAUK,CAAAL,QAEdlkD,EAAA,CAAQ8iD,EAAR,CAAsB,QAAQ,CAAC+B,CAAD,CAAYx6C,CAAZ,CAAkB,CAC9C,IAAIy6C,EAAQvgD,CAAA,CAAU8F,CAAV,CACZk6C,EAAA,CAAIjpC,EAAA,CAAU,WAAV,CAAwBwpC,CAAxB,CAAJ,CAAA,CAAsC,QAAQ,CAAC1Q,CAAD,CAAO,CACnD,MAAO9sC,EAAA,CAAMu9C,CAAN,CAAiBzQ,CAAjB,CAD4C,CAGrDmQ,EAAA,CAAIjpC,EAAA,CAAU,cAAV,CAA2BwpC,CAA3B,CAAJ,CAAA,CAAyC,QAAQ,CAAC/jD,CAAD,CAAQ,CACvD,MAAO4nC,EAAA,CAAWkc,CAAX,CAAsB9jD,CAAtB,CADgD,CAGzDwjD,EAAA,CAAIjpC,EAAA,CAAU,WAAV,CAAwBwpC,CAAxB,CAAJ,CAAA,CAAsC,QAAQ,CAAC/jD,CAAD,CAAQ,CACpD,MAAOmjD,EAAA,CAAQW,CAAR,CAAmB9jD,CAAnB,CAD6C,CARR,CAAhD,CAaA,OAAOwjD,EArU6B,CAD1B,CApEU,CA4ZxBpqC,QAASA,GAAgB,EAAG,CAC1B,IAAA4H,KAAA,CAAY,CAAC,SAAD,CAAY,WAAZ,CAAyB,QAAQ,CAACnH,CAAD,CAAU5C,CAAV,CAAqB,CAAA,IAC5D+sC,EAAe,EAD6C,CAE5DC,EACE3iD,CAAA,CAAM,CAAC,eAAAia,KAAA,CAAqB/X,CAAA,CAAU0gD,CAACrqC,CAAAsqC,UAADD;AAAsB,EAAtBA,WAAV,CAArB,CAAD,EAAyE,EAAzE,EAA6E,CAA7E,CAAN,CAH0D,CAI5DE,EAAQ,QAAA//C,KAAA,CAAc6/C,CAACrqC,CAAAsqC,UAADD,EAAsB,EAAtBA,WAAd,CAJoD,CAK5D7lD,EAAW4Y,CAAA,CAAU,CAAV,CAAX5Y,EAA2B,EALiC,CAM5DgmD,CAN4D,CAO5DC,EAAc,2BAP8C,CAQ5DC,EAAYlmD,CAAA2nC,KAAZue,EAA6BlmD,CAAA2nC,KAAAx0B,MAR+B,CAS5DgzC,EAAc,CAAA,CAT8C,CAU5DC,EAAa,CAAA,CAGjB,IAAIF,CAAJ,CAAe,CACb,IAASvhD,IAAAA,CAAT,GAAiBuhD,EAAjB,CACE,GAAI7/C,CAAJ,CAAY4/C,CAAA/oC,KAAA,CAAiBvY,CAAjB,CAAZ,CAAoC,CAClCqhD,CAAA,CAAe3/C,CAAA,CAAM,CAAN,CACf2/C,EAAA,CAAeA,CAAAp7B,OAAA,CAAoB,CAApB,CAAuB,CAAvB,CAAAtO,YAAA,EAAf,CAAyD0pC,CAAAp7B,OAAA,CAAoB,CAApB,CACzD,MAHkC,CAOjCo7B,CAAL,GACEA,CADF,CACkB,eADlB,EACqCE,EADrC,EACmD,QADnD,CAIAC,EAAA,CAAc,CAAG,EAAC,YAAD,EAAiBD,EAAjB,EAAgCF,CAAhC,CAA+C,YAA/C,EAA+DE,EAA/D,CACjBE,EAAA,CAAc,CAAG,EAAC,WAAD,EAAgBF,EAAhB,EAA+BF,CAA/B,CAA8C,WAA9C,EAA6DE,EAA7D,CAEbN,EAAAA,CAAJ,EAAiBO,CAAjB,EAAkCC,CAAlC,GACED,CACA,CADczlD,CAAA,CAASwlD,CAAAG,iBAAT,CACd,CAAAD,CAAA,CAAa1lD,CAAA,CAASwlD,CAAAI,gBAAT,CAFf,CAhBa,CAuBf,MAAO,CAULn9B,QAAS,EAAGA,CAAA3N,CAAA2N,QAAH,EAAsBo9B,CAAA/qC,CAAA2N,QAAAo9B,UAAtB,EAA+D,CAA/D,CAAqDX,CAArD,EAAsEG,CAAtE,CAVJ,CAYLS,SAAUA,QAAQ,CAAC1kC,CAAD,CAAQ,CAMxB,GAAc,OAAd;AAAIA,CAAJ,EAAiC,EAAjC,EAAyB0S,EAAzB,CAAqC,MAAO,CAAA,CAE5C,IAAIzwB,CAAA,CAAY4hD,CAAA,CAAa7jC,CAAb,CAAZ,CAAJ,CAAsC,CACpC,IAAI2kC,EAASzmD,CAAAgd,cAAA,CAAuB,KAAvB,CACb2oC,EAAA,CAAa7jC,CAAb,CAAA,CAAsB,IAAtB,CAA6BA,CAA7B,GAAsC2kC,EAFF,CAKtC,MAAOd,EAAA,CAAa7jC,CAAb,CAbiB,CAZrB,CA2BL7P,IAAKA,EAAA,EA3BA,CA4BL+zC,aAAcA,CA5BT,CA6BLG,YAAaA,CA7BR,CA8BLC,WAAYA,CA9BP,CA+BLR,QAASA,CA/BJ,CApCyD,CAAtD,CADc,CA8F5BzqC,QAASA,GAAwB,EAAG,CAClC,IAAAwH,KAAA,CAAY,CAAC,gBAAD,CAAmB,OAAnB,CAA4B,IAA5B,CAAkC,MAAlC,CAA0C,QAAQ,CAAC3H,CAAD,CAAiB1B,CAAjB,CAAwBgB,CAAxB,CAA4BI,CAA5B,CAAkC,CAC9FgsC,QAASA,EAAe,CAACC,CAAD,CAAMC,CAAN,CAA0B,CAChDF,CAAAG,qBAAA,EAOKnmD,EAAA,CAASimD,CAAT,CAAL,EAAuB3rC,CAAA9N,IAAA,CAAmBy5C,CAAnB,CAAvB,GACEA,CADF,CACQjsC,CAAAosC,sBAAA,CAA2BH,CAA3B,CADR,CAIA,KAAI7jB,EAAoBxpB,CAAAupB,SAApBC,EAAsCxpB,CAAAupB,SAAAC,kBAEtCniC,EAAA,CAAQmiC,CAAR,CAAJ,CACEA,CADF,CACsBA,CAAArxB,OAAA,CAAyB,QAAQ,CAACs1C,CAAD,CAAc,CACjE,MAAOA,EAAP,GAAuBnlB,EAD0C,CAA/C,CADtB,CAIWkB,CAJX,GAIiClB,EAJjC,GAKEkB,CALF,CAKsB,IALtB,CAaA,OAAOxpB,EAAApM,IAAA,CAAUy5C,CAAV,CALWK,CAChB7hC,MAAOnK,CADSgsC,CAEhBlkB,kBAAmBA,CAFHkkB,CAKX,CAAA,CACJ,SADI,CAAA,CACO,QAAQ,EAAG,CACrBN,CAAAG,qBAAA,EADqB,CADlB,CAAAzsB,KAAA,CAIC,QAAQ,CAACwJ,CAAD,CAAW,CACvB5oB,CAAAuI,IAAA,CAAmBojC,CAAnB;AAAwB/iB,CAAAv3B,KAAxB,CACA,OAAOu3B,EAAAv3B,KAFgB,CAJpB,CASP46C,QAAoB,CAACpjB,CAAD,CAAO,CACzB,GAAK+iB,CAAAA,CAAL,CACE,KAAM54B,GAAA,CAAe,QAAf,CACJ24B,CADI,CACC9iB,CAAAlB,OADD,CACckB,CAAAgC,WADd,CAAN,CAGF,MAAOvrB,EAAAwpB,OAAA,CAAUD,CAAV,CALkB,CATpB,CA3ByC,CA6ClD6iB,CAAAG,qBAAA,CAAuC,CAEvC,OAAOH,EAhDuF,CAApF,CADsB,CAqDpCrrC,QAASA,GAAqB,EAAG,CAC/B,IAAAsH,KAAA,CAAY,CAAC,YAAD,CAAe,UAAf,CAA2B,WAA3B,CACP,QAAQ,CAACvI,CAAD,CAAe9B,CAAf,CAA2BwB,CAA3B,CAAsC,CA6GjD,MApGkBotC,CAcN,aAAeC,QAAQ,CAACjiD,CAAD,CAAU07B,CAAV,CAAsBwmB,CAAtB,CAAsC,CACnEv5B,CAAAA,CAAW3oB,CAAAmiD,uBAAA,CAA+B,YAA/B,CACf,KAAIC,EAAU,EACd1mD,EAAA,CAAQitB,CAAR,CAAkB,QAAQ,CAAC+R,CAAD,CAAU,CAClC,IAAI2nB,EAAc/6C,EAAAtH,QAAA,CAAgB06B,CAAhB,CAAAvzB,KAAA,CAA8B,UAA9B,CACdk7C,EAAJ,EACE3mD,CAAA,CAAQ2mD,CAAR,CAAqB,QAAQ,CAACC,CAAD,CAAc,CACrCJ,CAAJ,CAEMphD,CADUo9C,IAAIh9C,MAAJg9C,CAAW,SAAXA,CAAuBE,EAAA,CAAgB1iB,CAAhB,CAAvBwiB,CAAqD,aAArDA,CACVp9C,MAAA,CAAawhD,CAAb,CAFN,EAGIF,CAAArhD,KAAA,CAAa25B,CAAb,CAHJ,CAM0C,EAN1C,EAMM4nB,CAAAjiD,QAAA,CAAoBq7B,CAApB,CANN,EAOI0mB,CAAArhD,KAAA,CAAa25B,CAAb,CARqC,CAA3C,CAHgC,CAApC,CAiBA,OAAO0nB,EApBgE,CAdvDJ,CAiDN,WAAaO,QAAQ,CAACviD,CAAD;AAAU07B,CAAV,CAAsBwmB,CAAtB,CAAsC,CAErE,IADA,IAAIM,EAAW,CAAC,KAAD,CAAQ,UAAR,CAAoB,OAApB,CAAf,CACSp7B,EAAI,CAAb,CAAgBA,CAAhB,CAAoBo7B,CAAApnD,OAApB,CAAqC,EAAEgsB,CAAvC,CAA0C,CAGxC,IAAIjM,EAAWnb,CAAAsZ,iBAAA,CADA,GACA,CADMkpC,CAAA,CAASp7B,CAAT,CACN,CADoB,OACpB,EAFO86B,CAAAO,CAAiB,GAAjBA,CAAuB,IAE9B,EADgD,GAChD,CADsD/mB,CACtD,CADmE,IACnE,CACf,IAAIvgB,CAAA/f,OAAJ,CACE,MAAO+f,EAL+B,CAF2B,CAjDrD6mC,CAoEN,YAAcU,QAAQ,EAAG,CACnC,MAAO9tC,EAAA0P,IAAA,EAD4B,CApEnB09B,CAiFN,YAAcW,QAAQ,CAACr+B,CAAD,CAAM,CAClCA,CAAJ,GAAY1P,CAAA0P,IAAA,EAAZ,GACE1P,CAAA0P,IAAA,CAAcA,CAAd,CACA,CAAApP,CAAAs4B,QAAA,EAFF,CADsC,CAjFtBwU,CAgGN,WAAaY,QAAQ,CAAC19B,CAAD,CAAW,CAC1C9R,CAAA4R,gCAAA,CAAyCE,CAAzC,CAD0C,CAhG1B88B,CAT+B,CADvC,CADmB,CAmHjC3rC,QAASA,GAAgB,EAAG,CAC1B,IAAAoH,KAAA,CAAY,CAAC,YAAD,CAAe,UAAf,CAA2B,IAA3B,CAAiC,KAAjC,CAAwC,mBAAxC,CACP,QAAQ,CAACvI,CAAD,CAAe9B,CAAf,CAA2BgC,CAA3B,CAAiCE,CAAjC,CAAwC1B,CAAxC,CAA2D,CAkCtE8tB,QAASA,EAAO,CAACt/B,CAAD,CAAKmkB,CAAL,CAAYof,CAAZ,CAAyB,CAClC7pC,CAAA,CAAWsG,CAAX,CAAL,GACEujC,CAEA,CAFcpf,CAEd,CADAA,CACA,CADQnkB,CACR,CAAAA,CAAA,CAAK9D,CAHP,CADuC,KAOnCigB,EAzrgBD3gB,EAAA5B,KAAA,CAyrgBkB6B,SAzrgBlB,CAyrgB6ByE,CAzrgB7B,CAkrgBoC,CAQnC0jC,EAAalnC,CAAA,CAAU6mC,CAAV,CAAbK,EAAuC,CAACL,CARL,CASnC3E,EAAW3a,CAAC2f,CAAA,CAAY1wB,CAAZ,CAAkBF,CAAnBiR,OAAA,EATwB;AAUnCwZ,EAAUmB,CAAAnB,QAVyB,CAWnCrZ,CAEJA,EAAA,CAAYpT,CAAAiT,MAAA,CAAe,QAAQ,EAAG,CACpC,GAAI,CACF2a,CAAAC,QAAA,CAAiB7+B,CAAAG,MAAA,CAAS,IAAT,CAAegc,CAAf,CAAjB,CADE,CAEF,MAAOra,CAAP,CAAU,CACV88B,CAAApC,OAAA,CAAgB16B,CAAhB,CACA,CAAA0P,CAAA,CAAkB1P,CAAlB,CAFU,CAFZ,OAMQ,CACN,OAAO2+C,CAAA,CAAUhjB,CAAAijB,YAAV,CADD,CAIH9c,CAAL,EAAgB9wB,CAAAhO,OAAA,EAXoB,CAA1B,CAYTqf,CAZS,CAcZsZ,EAAAijB,YAAA,CAAsBt8B,CACtBq8B,EAAA,CAAUr8B,CAAV,CAAA,CAAuBwa,CAEvB,OAAOnB,EA9BgC,CAhCzC,IAAIgjB,EAAY,EA8EhBnhB,EAAAjb,OAAA,CAAiBs8B,QAAQ,CAACljB,CAAD,CAAU,CACjC,MAAIA,EAAJ,EAAeA,CAAAijB,YAAf,GAAsCD,EAAtC,EACEA,CAAA,CAAUhjB,CAAAijB,YAAV,CAAAlkB,OAAA,CAAsC,UAAtC,CAEO,CADP,OAAOikB,CAAA,CAAUhjB,CAAAijB,YAAV,CACA,CAAA1vC,CAAAiT,MAAAI,OAAA,CAAsBoZ,CAAAijB,YAAtB,CAHT,EAKO,CAAA,CAN0B,CASnC,OAAOphB,EAzF+D,CAD5D,CADc,CA8J5B4B,QAASA,GAAU,CAAChf,CAAD,CAAM,CAGnBgL,EAAJ,GAGE0zB,CAAAloC,aAAA,CAA4B,MAA5B,CAAoCqK,CAApC,CACA,CAAAA,CAAA,CAAO69B,CAAA79B,KAJT,CAOA69B,EAAAloC,aAAA,CAA4B,MAA5B,CAAoCqK,CAApC,CAGA,OAAO,CACLA,KAAM69B,CAAA79B,KADD,CAELoe,SAAUyf,CAAAzf,SAAA,CAA0Byf,CAAAzf,SAAAh/B,QAAA,CAAgC,IAAhC,CAAsC,EAAtC,CAA1B,CAAsE,EAF3E,CAGLmX,KAAMsnC,CAAAtnC,KAHD;AAIL6tB,OAAQyZ,CAAAzZ,OAAA,CAAwByZ,CAAAzZ,OAAAhlC,QAAA,CAA8B,KAA9B,CAAqC,EAArC,CAAxB,CAAmE,EAJtE,CAKLme,KAAMsgC,CAAAtgC,KAAA,CAAsBsgC,CAAAtgC,KAAAne,QAAA,CAA4B,IAA5B,CAAkC,EAAlC,CAAtB,CAA8D,EAL/D,CAMLskC,SAAUma,CAAAna,SANL,CAOLE,KAAMia,CAAAja,KAPD,CAQLM,SAAiD,GAAvC,GAAC2Z,CAAA3Z,SAAA9nC,OAAA,CAA+B,CAA/B,CAAD,CACNyhD,CAAA3Z,SADM,CAEN,GAFM,CAEA2Z,CAAA3Z,SAVL,CAbgB,CAkCzB5H,QAASA,GAAe,CAACwhB,CAAD,CAAa,CAC/BnqC,CAAAA,CAAUtd,CAAA,CAASynD,CAAT,CAAD,CAAyB3f,EAAA,CAAW2f,CAAX,CAAzB,CAAkDA,CAC/D,OAAQnqC,EAAAyqB,SAAR,GAA4B2f,EAAA3f,SAA5B,EACQzqB,CAAA4C,KADR,GACwBwnC,EAAAxnC,KAHW,CA+CrCnF,QAASA,GAAe,EAAG,CACzB,IAAAkH,KAAA,CAAYhf,EAAA,CAAQ5D,CAAR,CADa,CAa3BsoD,QAASA,GAAc,CAACzvC,CAAD,CAAY,CAKjC0vC,QAASA,EAAsB,CAACplD,CAAD,CAAM,CACnC,GAAI,CACF,MAAOyG,mBAAA,CAAmBzG,CAAnB,CADL,CAEF,MAAOkG,CAAP,CAAU,CACV,MAAOlG,EADG,CAHuB,CAJrC,IAAIqkC,EAAc3uB,CAAA,CAAU,CAAV,CAAd2uB,EAA8B,EAAlC,CACIghB,EAAc,EADlB,CAEIC,EAAmB,EAUvB,OAAO,SAAQ,EAAG,CAAA,IACZC,CADY,CACCC,CADD,CACSlnD,CADT,CACY8D,CADZ,CACmB2F,CAC/B09C,EAAAA,CAAsBphB,CAAAmhB,OAAtBC,EAA4C,EAEhD,IAAIA,CAAJ,GAA4BH,CAA5B,CAKE,IAJAA,CAIK,CAJcG,CAId,CAHLF,CAGK,CAHSD,CAAAxjD,MAAA,CAAuB,IAAvB,CAGT,CAFLujD,CAEK,CAFS,EAET,CAAA/mD,CAAA,CAAI,CAAT,CAAYA,CAAZ,CAAgBinD,CAAAnoD,OAAhB,CAAoCkB,CAAA,EAApC,CACEknD,CAEA;AAFSD,CAAA,CAAYjnD,CAAZ,CAET,CADA8D,CACA,CADQojD,CAAAnjD,QAAA,CAAe,GAAf,CACR,CAAY,CAAZ,CAAID,CAAJ,GACE2F,CAIA,CAJOq9C,CAAA,CAAuBI,CAAA1yB,UAAA,CAAiB,CAAjB,CAAoB1wB,CAApB,CAAvB,CAIP,CAAIijD,CAAA,CAAYt9C,CAAZ,CAAJ,GAA0BhL,CAA1B,GACEsoD,CAAA,CAAYt9C,CAAZ,CADF,CACsBq9C,CAAA,CAAuBI,CAAA1yB,UAAA,CAAiB1wB,CAAjB,CAAyB,CAAzB,CAAvB,CADtB,CALF,CAWJ,OAAOijD,EAvBS,CAbe,CA0CnCtsC,QAASA,GAAsB,EAAG,CAChC,IAAA0G,KAAA,CAAY0lC,EADoB,CAwGlCpvC,QAASA,GAAe,CAACrN,CAAD,CAAW,CAkBjC20B,QAASA,EAAQ,CAACt1B,CAAD,CAAO+E,CAAP,CAAgB,CAC/B,GAAI1N,CAAA,CAAS2I,CAAT,CAAJ,CAAoB,CAClB,IAAI29C,EAAU,EACdhoD,EAAA,CAAQqK,CAAR,CAAc,QAAQ,CAACwG,CAAD,CAAS1Q,CAAT,CAAc,CAClC6nD,CAAA,CAAQ7nD,CAAR,CAAA,CAAew/B,CAAA,CAASx/B,CAAT,CAAc0Q,CAAd,CADmB,CAApC,CAGA,OAAOm3C,EALW,CAOlB,MAAOh9C,EAAAoE,QAAA,CAAiB/E,CAAjB,CAzBE49C,QAyBF,CAAgC74C,CAAhC,CARsB,CAWjC,IAAAuwB,SAAA,CAAgBA,CAEhB,KAAA5d,KAAA,CAAY,CAAC,WAAD,CAAc,QAAQ,CAACuD,CAAD,CAAY,CAC5C,MAAO,SAAQ,CAACjb,CAAD,CAAO,CACpB,MAAOib,EAAAhZ,IAAA,CAAcjC,CAAd,CAhCE49C,QAgCF,CADa,CADsB,CAAlC,CAoBZtoB,EAAA,CAAS,UAAT,CAAqBuoB,EAArB,CACAvoB,EAAA,CAAS,MAAT,CAAiBwoB,EAAjB,CACAxoB,EAAA,CAAS,QAAT,CAAmByoB,EAAnB,CACAzoB,EAAA,CAAS,MAAT,CAAiB0oB,EAAjB,CACA1oB,EAAA,CAAS,SAAT,CAAoB2oB,EAApB,CACA3oB,EAAA,CAAS,WAAT,CAAsB4oB,EAAtB,CACA5oB,EAAA,CAAS,QAAT,CAAmB6oB,EAAnB,CACA7oB,EAAA,CAAS,SAAT,CAAoB8oB,EAApB,CACA9oB,EAAA,CAAS,WAAT,CAAsB+oB,EAAtB,CA3DiC,CA6LnCN,QAASA,GAAY,EAAG,CACtB,MAAO,SAAQ,CAAC3jD,CAAD;AAAQu7B,CAAR,CAAoB2oB,CAApB,CAAgC,CAC7C,GAAK,CAAAppD,EAAA,CAAYkF,CAAZ,CAAL,CAAyB,CACvB,GAAa,IAAb,EAAIA,CAAJ,CACE,MAAOA,EAEP,MAAMnF,EAAA,CAAO,QAAP,CAAA,CAAiB,UAAjB,CAAiEmF,CAAjE,CAAN,CAJqB,CAUzB,IAAImkD,CAEJ,QAJqBC,EAAAC,CAAiB9oB,CAAjB8oB,CAIrB,EACE,KAAK,UAAL,CAEE,KACF,MAAK,SAAL,CACA,KAAK,MAAL,CACA,KAAK,QAAL,CACA,KAAK,QAAL,CACEF,CAAA,CAAsB,CAAA,CAExB,MAAK,QAAL,CAEEG,CAAA,CAAcC,EAAA,CAAkBhpB,CAAlB,CAA8B2oB,CAA9B,CAA0CC,CAA1C,CACd,MACF,SACE,MAAOnkD,EAfX,CAkBA,MAAO0hB,MAAAjjB,UAAA2N,OAAAvQ,KAAA,CAA4BmE,CAA5B,CAAmCskD,CAAnC,CA/BsC,CADzB,CAqCxBC,QAASA,GAAiB,CAAChpB,CAAD,CAAa2oB,CAAb,CAAyBC,CAAzB,CAA8C,CACtE,IAAIK,EAAwBvnD,CAAA,CAASs+B,CAAT,CAAxBipB,EAAiD,GAAjDA,EAAwDjpB,EAGzC,EAAA,CAAnB,GAAI2oB,CAAJ,CACEA,CADF,CACe7iD,EADf,CAEY1F,CAAA,CAAWuoD,CAAX,CAFZ,GAGEA,CAHF,CAGeA,QAAQ,CAACO,CAAD,CAASC,CAAT,CAAmB,CACtC,GAAIhmD,CAAA,CAAY+lD,CAAZ,CAAJ,CAEE,MAAO,CAAA,CAET,IAAgB,IAAhB,GAAKA,CAAL,EAAuC,IAAvC,GAA0BC,CAA1B,CAEE,MAAOD,EAAP,GAAkBC,CAEpB,IAAIznD,CAAA,CAASynD,CAAT,CAAJ,EAA2BznD,CAAA,CAASwnD,CAAT,CAA3B,EAAgD,CAAAlmD,EAAA,CAAkBkmD,CAAlB,CAAhD,CAEE,MAAO,CAAA,CAGTA,EAAA,CAAS3kD,CAAA,CAAU,EAAV,CAAe2kD,CAAf,CACTC,EAAA,CAAW5kD,CAAA,CAAU,EAAV,CAAe4kD,CAAf,CACX,OAAqC,EAArC,GAAOD,CAAAvkD,QAAA,CAAewkD,CAAf,CAhB+B,CAH1C,CA8BA,OAPcJ,SAAQ,CAACK,CAAD,CAAO,CAC3B,MAAIH,EAAJ,EAA8B,CAAAvnD,CAAA,CAAS0nD,CAAT,CAA9B,CACSC,EAAA,CAAYD,CAAZ;AAAkBppB,CAAAl9B,EAAlB,CAAgC6lD,CAAhC,CAA4C,CAAA,CAA5C,CADT,CAGOU,EAAA,CAAYD,CAAZ,CAAkBppB,CAAlB,CAA8B2oB,CAA9B,CAA0CC,CAA1C,CAJoB,CA3ByC,CAqCxES,QAASA,GAAW,CAACH,CAAD,CAASC,CAAT,CAAmBR,CAAnB,CAA+BC,CAA/B,CAAoDU,CAApD,CAA0E,CAC5F,IAAIC,EAAaV,EAAA,CAAiBK,CAAjB,CAAjB,CACIM,EAAeX,EAAA,CAAiBM,CAAjB,CAEnB,IAAsB,QAAtB,GAAKK,CAAL,EAA2D,GAA3D,GAAoCL,CAAAtjD,OAAA,CAAgB,CAAhB,CAApC,CACE,MAAO,CAACwjD,EAAA,CAAYH,CAAZ,CAAoBC,CAAA/zB,UAAA,CAAmB,CAAnB,CAApB,CAA2CuzB,CAA3C,CAAuDC,CAAvD,CACH,IAAI7oD,CAAA,CAAQmpD,CAAR,CAAJ,CAGL,MAAOA,EAAA9iC,KAAA,CAAY,QAAQ,CAACgjC,CAAD,CAAO,CAChC,MAAOC,GAAA,CAAYD,CAAZ,CAAkBD,CAAlB,CAA4BR,CAA5B,CAAwCC,CAAxC,CADyB,CAA3B,CAKT,QAAQW,CAAR,EACE,KAAK,QAAL,CACE,IAAIppD,CACJ,IAAIyoD,CAAJ,CAAyB,CACvB,IAAKzoD,CAAL,GAAY+oD,EAAZ,CACE,GAAuB,GAAvB,GAAK/oD,CAAA0F,OAAA,CAAW,CAAX,CAAL,EAA+BwjD,EAAA,CAAYH,CAAA,CAAO/oD,CAAP,CAAZ,CAAyBgpD,CAAzB,CAAmCR,CAAnC,CAA+C,CAAA,CAA/C,CAA/B,CACE,MAAO,CAAA,CAGX,OAAOW,EAAA,CAAuB,CAAA,CAAvB,CAA+BD,EAAA,CAAYH,CAAZ,CAAoBC,CAApB,CAA8BR,CAA9B,CAA0C,CAAA,CAA1C,CANf,CAOlB,GAAqB,QAArB,GAAIa,CAAJ,CAA+B,CACpC,IAAKrpD,CAAL,GAAYgpD,EAAZ,CAEE,GADIM,CACA,CADcN,CAAA,CAAShpD,CAAT,CACd,CAAA,CAAAC,CAAA,CAAWqpD,CAAX,CAAA,EAA2B,CAAAtmD,CAAA,CAAYsmD,CAAZ,CAA3B,GAIAC,CAEC,CAF0B,GAE1B,GAFkBvpD,CAElB,CAAA,CAAAkpD,EAAA,CADWK,CAAAC,CAAmBT,CAAnBS,CAA4BT,CAAA,CAAO/oD,CAAP,CACvC,CAAuBspD,CAAvB,CAAoCd,CAApC,CAAgDe,CAAhD,CAAkEA,CAAlE,CAND,CAAJ,CAOE,MAAO,CAAA,CAGX,OAAO,CAAA,CAb6B,CAepC,MAAOf,EAAA,CAAWO,CAAX,CAAmBC,CAAnB,CAGX,MAAK,UAAL,CACE,MAAO,CAAA,CACT,SACE,MAAOR,EAAA,CAAWO,CAAX,CAAmBC,CAAnB,CA/BX,CAd4F,CAkD9FN,QAASA,GAAgB,CAAC9hD,CAAD,CAAM,CAC7B,MAAgB,KAAT;AAACA,CAAD,CAAiB,MAAjB,CAA0B,MAAOA,EADX,CAyD/BmhD,QAASA,GAAc,CAAC0B,CAAD,CAAU,CAC/B,IAAIC,EAAUD,CAAAhf,eACd,OAAO,SAAQ,CAACkf,CAAD,CAASC,CAAT,CAAyBC,CAAzB,CAAuC,CAChD7mD,CAAA,CAAY4mD,CAAZ,CAAJ,GACEA,CADF,CACmBF,CAAApe,aADnB,CAIItoC,EAAA,CAAY6mD,CAAZ,CAAJ,GACEA,CADF,CACiBH,CAAA9e,SAAA,CAAiB,CAAjB,CAAAG,QADjB,CAKA,OAAkB,KAAX,EAAC4e,CAAD,CACDA,CADC,CAEDG,EAAA,CAAaH,CAAb,CAAqBD,CAAA9e,SAAA,CAAiB,CAAjB,CAArB,CAA0C8e,CAAA/e,UAA1C,CAA6D+e,CAAAhf,YAA7D,CAAkFmf,CAAlF,CAAAnhD,QAAA,CACU,SADV,CACqBkhD,CADrB,CAZ8C,CAFvB,CA0EjCvB,QAASA,GAAY,CAACoB,CAAD,CAAU,CAC7B,IAAIC,EAAUD,CAAAhf,eACd,OAAO,SAAQ,CAACsf,CAAD,CAASF,CAAT,CAAuB,CAGpC,MAAkB,KAAX,EAACE,CAAD,CACDA,CADC,CAEDD,EAAA,CAAaC,CAAb,CAAqBL,CAAA9e,SAAA,CAAiB,CAAjB,CAArB,CAA0C8e,CAAA/e,UAA1C,CAA6D+e,CAAAhf,YAA7D,CACamf,CADb,CAL8B,CAFT,CAa/BC,QAASA,GAAY,CAACC,CAAD,CAASn0C,CAAT,CAAkBo0C,CAAlB,CAA4BC,CAA5B,CAAwCJ,CAAxC,CAAsD,CACzE,GAAItoD,CAAA,CAASwoD,CAAT,CAAJ,CAAsB,MAAO,EAE7B,KAAIG,EAAsB,CAAtBA,CAAaH,CACjBA,EAAA,CAAS1xB,IAAA8xB,IAAA,CAASJ,CAAT,CAET,KAAIK,EAAwBC,QAAxBD,GAAaL,CACjB,IAAKK,CAAAA,CAAL,EAAoB,CAAAE,QAAA,CAASP,CAAT,CAApB,CAAsC,MAAO,EAP4B,KASrEQ,EAASR,CAATQ,CAAkB,EATmD,CAUrEC,EAAe,EAVsD,CAWrEC,EAAc,CAAA,CAXuD,CAYrExhD,EAAQ,EAERmhD,EAAJ,GAAgBI,CAAhB,CAA+B,QAA/B,CAEA;GAAKJ,CAAAA,CAAL,EAA4C,EAA5C,GAAmBG,CAAA/lD,QAAA,CAAe,GAAf,CAAnB,CAA+C,CAC7C,IAAIc,EAAQilD,CAAAjlD,MAAA,CAAa,qBAAb,CACRA,EAAJ,EAAyB,GAAzB,EAAaA,CAAA,CAAM,CAAN,CAAb,EAAgCA,CAAA,CAAM,CAAN,CAAhC,CAA2CukD,CAA3C,CAA0D,CAA1D,CACEE,CADF,CACW,CADX,EAGES,CACA,CADeD,CACf,CAAAE,CAAA,CAAc,CAAA,CAJhB,CAF6C,CAU/C,GAAKL,CAAL,EAAoBK,CAApB,CA6CqB,CAAnB,CAAIZ,CAAJ,EAAiC,CAAjC,CAAwBE,CAAxB,GACES,CACA,CADeT,CAAAW,QAAA,CAAeb,CAAf,CACf,CAAAE,CAAA,CAASY,UAAA,CAAWH,CAAX,CAFX,CA7CF,KAAiC,CAC3BI,CAAAA,CAAcrrD,CAACgrD,CAAAtmD,MAAA,CAAaymC,EAAb,CAAA,CAA0B,CAA1B,CAADnrC,EAAiC,EAAjCA,QAGdyD,EAAA,CAAY6mD,CAAZ,CAAJ,GACEA,CADF,CACiBxxB,IAAAwyB,IAAA,CAASxyB,IAAAC,IAAA,CAAS1iB,CAAAk1B,QAAT,CAA0B8f,CAA1B,CAAT,CAAiDh1C,CAAAm1B,QAAjD,CADjB,CAOAgf,EAAA,CAAS,EAAE1xB,IAAAyyB,MAAA,CAAW,EAAEf,CAAAjnD,SAAA,EAAF,CAAsB,GAAtB,CAA4B+mD,CAA5B,CAAX,CAAA/mD,SAAA,EAAF,CAAqE,GAArE,CAA2E,CAAC+mD,CAA5E,CAELkB,KAAAA,EAAW9mD,CAAC,EAADA,CAAM8lD,CAAN9lD,OAAA,CAAoBymC,EAApB,CAAXqgB,CACAjd,EAAQid,CAAA,CAAS,CAAT,CADRA,CAEJA,EAAWA,CAAA,CAAS,CAAT,CAAXA,EAA0B,EAFtBA,CAIGv+C,EAAM,CAJTu+C,CAKAC,EAASp1C,CAAAy1B,OALT0f,CAMAE,EAAQr1C,CAAAw1B,MAEZ,IAAI0C,CAAAvuC,OAAJ,EAAqByrD,CAArB,CAA8BC,CAA9B,CAEE,IADAz+C,CACK,CADCshC,CAAAvuC,OACD,CADgByrD,CAChB,CAAAvqD,CAAA,CAAI,CAAT,CAAYA,CAAZ,CAAgB+L,CAAhB,CAAqB/L,CAAA,EAArB,CAC4B,CAG1B,IAHK+L,CAGL,CAHW/L,CAGX,EAHgBwqD,CAGhB,EAHqC,CAGrC,GAH+BxqD,CAG/B,GAFE+pD,CAEF,EAFkBR,CAElB,EAAAQ,CAAA,EAAgB1c,CAAApoC,OAAA,CAAajF,CAAb,CAIpB,KAAKA,CAAL,CAAS+L,CAAT,CAAc/L,CAAd,CAAkBqtC,CAAAvuC,OAAlB,CAAgCkB,CAAA,EAAhC,CACsC,CAGpC,IAHKqtC,CAAAvuC,OAGL,CAHoBkB,CAGpB,EAHyBuqD,CAGzB,EAH+C,CAG/C,GAHyCvqD,CAGzC;CAFE+pD,CAEF,EAFkBR,CAElB,EAAAQ,CAAA,EAAgB1c,CAAApoC,OAAA,CAAajF,CAAb,CAIlB,KAAA,CAAOsqD,CAAAxrD,OAAP,CAAyBsqD,CAAzB,CAAA,CACEkB,CAAA,EAAY,GAGVlB,EAAJ,EAAqC,GAArC,GAAoBA,CAApB,GAA0CW,CAA1C,EAA0DP,CAA1D,CAAuEc,CAAAlhC,OAAA,CAAgB,CAAhB,CAAmBggC,CAAnB,CAAvE,CA3C+B,CAmDlB,CAAf,GAAIE,CAAJ,GACEG,CADF,CACe,CAAA,CADf,CAIAjhD,EAAA/D,KAAA,CAAWglD,CAAA,CAAat0C,CAAAs1B,OAAb,CAA8Bt1B,CAAAo1B,OAAzC,CACWwf,CADX,CAEWN,CAAA,CAAat0C,CAAAu1B,OAAb,CAA8Bv1B,CAAAq1B,OAFzC,CAGA,OAAOhiC,EAAAG,KAAA,CAAW,EAAX,CApFkE,CAuF3E8hD,QAASA,GAAS,CAAC3e,CAAD,CAAM4e,CAAN,CAAcpuC,CAAd,CAAoB,CACpC,IAAIquC,EAAM,EACA,EAAV,CAAI7e,CAAJ,GACE6e,CACA,CADO,GACP,CAAA7e,CAAA,CAAM,CAACA,CAFT,CAKA,KADAA,CACA,CADM,EACN,CADWA,CACX,CAAOA,CAAAhtC,OAAP,CAAoB4rD,CAApB,CAAA,CAA4B5e,CAAA,CAAM,GAAN,CAAYA,CACpCxvB,EAAJ,GACEwvB,CADF,CACQA,CAAA1iB,OAAA,CAAW0iB,CAAAhtC,OAAX,CAAwB4rD,CAAxB,CADR,CAGA,OAAOC,EAAP,CAAa7e,CAXuB,CAetC8e,QAASA,EAAU,CAACnhD,CAAD,CAAOyhB,CAAP,CAAarQ,CAAb,CAAqByB,CAArB,CAA2B,CAC5CzB,CAAA,CAASA,CAAT,EAAmB,CACnB,OAAO,SAAQ,CAAC5T,CAAD,CAAO,CAChB9G,CAAAA,CAAQ8G,CAAA,CAAK,KAAL,CAAawC,CAAb,CAAA,EACZ,IAAa,CAAb,CAAIoR,CAAJ,EAAkB1a,CAAlB,CAA0B,CAAC0a,CAA3B,CACE1a,CAAA,EAAS0a,CAEG,EAAd,GAAI1a,CAAJ,EAA8B,GAA9B,EAAmB0a,CAAnB,GAAkC1a,CAAlC,CAA0C,EAA1C,CACA,OAAOsqD,GAAA,CAAUtqD,CAAV,CAAiB+qB,CAAjB,CAAuB5O,CAAvB,CANa,CAFsB,CAY9CuuC,QAASA,GAAa,CAACphD,CAAD,CAAOqhD,CAAP,CAAkB,CACtC,MAAO,SAAQ,CAAC7jD,CAAD,CAAOgiD,CAAP,CAAgB,CAC7B,IAAI9oD,EAAQ8G,CAAA,CAAK,KAAL,CAAawC,CAAb,CAAA,EAAZ,CACIiC,EAAM6E,EAAA,CAAUu6C,CAAA,CAAa,OAAb,CAAuBrhD,CAAvB,CAA+BA,CAAzC,CAEV,OAAOw/C,EAAA,CAAQv9C,CAAR,CAAA,CAAavL,CAAb,CAJsB,CADO,CAmBxC4qD,QAASA,GAAsB,CAACC,CAAD,CAAO,CAElC,IAAIC;AAAmBC,CAAC,IAAI/pD,IAAJ,CAAS6pD,CAAT,CAAe,CAAf,CAAkB,CAAlB,CAADE,QAAA,EAGvB,OAAO,KAAI/pD,IAAJ,CAAS6pD,CAAT,CAAe,CAAf,EAAwC,CAArB,EAACC,CAAD,CAA0B,CAA1B,CAA8B,EAAjD,EAAuDA,CAAvD,CAL2B,CActCE,QAASA,GAAU,CAACjgC,CAAD,CAAO,CACvB,MAAO,SAAQ,CAACjkB,CAAD,CAAO,CAAA,IACfmkD,EAAaL,EAAA,CAAuB9jD,CAAAokD,YAAA,EAAvB,CAGbhyB,EAAAA,CAAO,CAVNiyB,IAAInqD,IAAJmqD,CAQ8BrkD,CARrBokD,YAAA,EAATC,CAQ8BrkD,CARGskD,SAAA,EAAjCD,CAQ8BrkD,CANnCukD,QAAA,EAFKF,EAEiB,CAFjBA,CAQ8BrkD,CANTikD,OAAA,EAFrBI,EAUDjyB,CAAoB,CAAC+xB,CACtBroC,EAAAA,CAAS,CAATA,CAAa6U,IAAAyyB,MAAA,CAAWhxB,CAAX,CAAkB,MAAlB,CAEhB,OAAOoxB,GAAA,CAAU1nC,CAAV,CAAkBmI,CAAlB,CAPY,CADC,CAgB1BugC,QAASA,GAAS,CAACxkD,CAAD,CAAOgiD,CAAP,CAAgB,CAChC,MAA6B,EAAtB,EAAAhiD,CAAAokD,YAAA,EAAA,CAA0BpC,CAAArd,KAAA,CAAa,CAAb,CAA1B,CAA4Cqd,CAAArd,KAAA,CAAa,CAAb,CADnB,CA0IlC2b,QAASA,GAAU,CAACyB,CAAD,CAAU,CAK3B0C,QAASA,EAAgB,CAACC,CAAD,CAAS,CAChC,IAAI9mD,CACJ,IAAIA,CAAJ,CAAY8mD,CAAA9mD,MAAA,CAAa+mD,CAAb,CAAZ,CAAyC,CACnC3kD,CAAAA,CAAO,IAAI9F,IAAJ,CAAS,CAAT,CAD4B,KAEnC0qD,EAAS,CAF0B,CAGnCC,EAAS,CAH0B,CAInCC,EAAalnD,CAAA,CAAM,CAAN,CAAA,CAAWoC,CAAA+kD,eAAX,CAAiC/kD,CAAAglD,YAJX,CAKnCC,EAAarnD,CAAA,CAAM,CAAN,CAAA,CAAWoC,CAAAklD,YAAX,CAA8BllD,CAAAmlD,SAE3CvnD,EAAA,CAAM,CAAN,CAAJ,GACEgnD,CACA,CADSpqD,CAAA,CAAMoD,CAAA,CAAM,CAAN,CAAN,CAAiBA,CAAA,CAAM,EAAN,CAAjB,CACT,CAAAinD,CAAA,CAAQrqD,CAAA,CAAMoD,CAAA,CAAM,CAAN,CAAN,CAAiBA,CAAA,CAAM,EAAN,CAAjB,CAFV,CAIAknD,EAAArsD,KAAA,CAAgBuH,CAAhB,CAAsBxF,CAAA,CAAMoD,CAAA,CAAM,CAAN,CAAN,CAAtB;AAAuCpD,CAAA,CAAMoD,CAAA,CAAM,CAAN,CAAN,CAAvC,CAAyD,CAAzD,CAA4DpD,CAAA,CAAMoD,CAAA,CAAM,CAAN,CAAN,CAA5D,CACItE,EAAAA,CAAIkB,CAAA,CAAMoD,CAAA,CAAM,CAAN,CAAN,EAAkB,CAAlB,CAAJtE,CAA2BsrD,CAC3BQ,EAAAA,CAAI5qD,CAAA,CAAMoD,CAAA,CAAM,CAAN,CAAN,EAAkB,CAAlB,CAAJwnD,CAA2BP,CAC3BQ,EAAAA,CAAI7qD,CAAA,CAAMoD,CAAA,CAAM,CAAN,CAAN,EAAkB,CAAlB,CACJ0nD,EAAAA,CAAK30B,IAAAyyB,MAAA,CAAgD,GAAhD,CAAWH,UAAA,CAAW,IAAX,EAAmBrlD,CAAA,CAAM,CAAN,CAAnB,EAA+B,CAA/B,EAAX,CACTqnD,EAAAxsD,KAAA,CAAgBuH,CAAhB,CAAsB1G,CAAtB,CAAyB8rD,CAAzB,CAA4BC,CAA5B,CAA+BC,CAA/B,CAhBuC,CAmBzC,MAAOZ,EArByB,CAFlC,IAAIC,EAAgB,sGA2BpB,OAAO,SAAQ,CAAC3kD,CAAD,CAAOulD,CAAP,CAAe5lD,CAAf,CAAyB,CAAA,IAClC8yB,EAAO,EAD2B,CAElClxB,EAAQ,EAF0B,CAGlC1C,CAHkC,CAG9BjB,CAER2nD,EAAA,CAASA,CAAT,EAAmB,YACnBA,EAAA,CAASxD,CAAAle,iBAAA,CAAyB0hB,CAAzB,CAAT,EAA6CA,CACzCttD,EAAA,CAAS+H,CAAT,CAAJ,GACEA,CADF,CACSwlD,EAAAjoD,KAAA,CAAmByC,CAAnB,CAAA,CAA2BxF,CAAA,CAAMwF,CAAN,CAA3B,CAAyCykD,CAAA,CAAiBzkD,CAAjB,CADlD,CAIIvE,EAAA,CAASuE,CAAT,CAAJ,GACEA,CADF,CACS,IAAI9F,IAAJ,CAAS8F,CAAT,CADT,CAIA,IAAK,CAAA/F,EAAA,CAAO+F,CAAP,CAAL,EAAsB,CAAA4iD,QAAA,CAAS5iD,CAAAtC,QAAA,EAAT,CAAtB,CACE,MAAOsC,EAGT,KAAA,CAAOulD,CAAP,CAAA,CAEE,CADA3nD,CACA,CADQ6nD,EAAAhxC,KAAA,CAAwB8wC,CAAxB,CACR,GACEhkD,CACA,CADQ/C,EAAA,CAAO+C,CAAP,CAAc3D,CAAd,CAAqB,CAArB,CACR,CAAA2nD,CAAA,CAAShkD,CAAA8e,IAAA,EAFX,GAIE9e,CAAA/D,KAAA,CAAW+nD,CAAX,CACA,CAAAA,CAAA,CAAS,IALX,CASF,KAAIG,EAAqB1lD,CAAAG,kBAAA,EACrBR;CAAJ,GACE+lD,CACA,CADqBhmD,EAAA,CAAiBC,CAAjB,CAA2BK,CAAAG,kBAAA,EAA3B,CACrB,CAAAH,CAAA,CAAOD,EAAA,CAAuBC,CAAvB,CAA6BL,CAA7B,CAAuC,CAAA,CAAvC,CAFT,CAIAxH,EAAA,CAAQoJ,CAAR,CAAe,QAAQ,CAACrI,CAAD,CAAQ,CAC7B2F,CAAA,CAAK8mD,EAAA,CAAazsD,CAAb,CACLu5B,EAAA,EAAQ5zB,CAAA,CAAKA,CAAA,CAAGmB,CAAH,CAAS+hD,CAAAle,iBAAT,CAAmC6hB,CAAnC,CAAL,CACKxsD,CAAA8H,QAAA,CAAc,UAAd,CAA0B,EAA1B,CAAAA,QAAA,CAAsC,KAAtC,CAA6C,GAA7C,CAHgB,CAA/B,CAMA,OAAOyxB,EAzC+B,CA9Bb,CA2G7B+tB,QAASA,GAAU,EAAG,CACpB,MAAO,SAAQ,CAACnT,CAAD,CAASuY,CAAT,CAAkB,CAC3BtqD,CAAA,CAAYsqD,CAAZ,CAAJ,GACIA,CADJ,CACc,CADd,CAGA,OAAOzmD,GAAA,CAAOkuC,CAAP,CAAeuY,CAAf,CAJwB,CADb,CAiItBnF,QAASA,GAAa,EAAG,CACvB,MAAO,SAAQ,CAACx2C,CAAD,CAAQ47C,CAAR,CAAe1f,CAAf,CAAsB,CAEjC0f,CAAA,CAD8BlD,QAAhC,GAAIhyB,IAAA8xB,IAAA,CAASp+B,MAAA,CAAOwhC,CAAP,CAAT,CAAJ,CACUxhC,MAAA,CAAOwhC,CAAP,CADV,CAGUrrD,CAAA,CAAMqrD,CAAN,CAEV,IAAI/lD,KAAA,CAAM+lD,CAAN,CAAJ,CAAkB,MAAO57C,EAErBxO,EAAA,CAASwO,CAAT,CAAJ,GAAqBA,CAArB,CAA6BA,CAAA7O,SAAA,EAA7B,CACA,IAAK,CAAAlD,CAAA,CAAQ+R,CAAR,CAAL,EAAwB,CAAAhS,CAAA,CAASgS,CAAT,CAAxB,CAAyC,MAAOA,EAEhDk8B,EAAA,CAAUA,CAAAA,CAAF,EAAWrmC,KAAA,CAAMqmC,CAAN,CAAX,CAA2B,CAA3B,CAA+B3rC,CAAA,CAAM2rC,CAAN,CACvCA,EAAA,CAAiB,CAAT,CAACA,CAAD,EAAcA,CAAd,EAAuB,CAACl8B,CAAApS,OAAxB,CAAwCoS,CAAApS,OAAxC,CAAuDsuC,CAAvD,CAA+DA,CAEvE,OAAa,EAAb,EAAI0f,CAAJ,CACS57C,CAAA5P,MAAA,CAAY8rC,CAAZ,CAAmBA,CAAnB,CAA2B0f,CAA3B,CADT,CAGgB,CAAd,GAAI1f,CAAJ,CACSl8B,CAAA5P,MAAA,CAAYwrD,CAAZ,CAAmB57C,CAAApS,OAAnB,CADT,CAGSoS,CAAA5P,MAAA,CAAYs2B,IAAAC,IAAA,CAAS,CAAT;AAAYuV,CAAZ,CAAoB0f,CAApB,CAAZ,CAAwC1f,CAAxC,CApBwB,CADd,CAyMzBya,QAASA,GAAa,CAACnvC,CAAD,CAAS,CAsC7Bq0C,QAASA,EAAiB,CAACC,CAAD,CAAgBC,CAAhB,CAA8B,CACtDA,CAAA,CAAeA,CAAA,CAAgB,EAAhB,CAAoB,CACnC,OAAOD,EAAAE,IAAA,CAAkB,QAAQ,CAACC,CAAD,CAAY,CAAA,IACvCC,EAAa,CAD0B,CACvB1hD,EAAMzJ,EAE1B,IAAIzC,CAAA,CAAW2tD,CAAX,CAAJ,CACEzhD,CAAA,CAAMyhD,CADR,KAEO,IAAIjuD,CAAA,CAASiuD,CAAT,CAAJ,CAAyB,CAC9B,GAA4B,GAA5B,EAAKA,CAAAloD,OAAA,CAAiB,CAAjB,CAAL,EAA0D,GAA1D,EAAmCkoD,CAAAloD,OAAA,CAAiB,CAAjB,CAAnC,CACEmoD,CACA,CADoC,GAAvB,EAAAD,CAAAloD,OAAA,CAAiB,CAAjB,CAAA,CAA8B,EAA9B,CAAkC,CAC/C,CAAAkoD,CAAA,CAAYA,CAAA34B,UAAA,CAAoB,CAApB,CAEd,IAAkB,EAAlB,GAAI24B,CAAJ,GACEzhD,CACIoE,CADE4I,CAAA,CAAOy0C,CAAP,CACFr9C,CAAApE,CAAAoE,SAFN,EAGI,IAAIvQ,EAAMmM,CAAA,EAAV,CACAA,EAAMA,QAAQ,CAACvL,CAAD,CAAQ,CAAE,MAAOA,EAAA,CAAMZ,CAAN,CAAT,CATI,CAahC,MAAO,CAAEmM,IAAKA,CAAP,CAAY0hD,WAAYA,CAAZA,CAAyBH,CAArC,CAlBoC,CAAtC,CAF+C,CAwBxDttD,QAASA,EAAW,CAACQ,CAAD,CAAQ,CAC1B,OAAQ,MAAOA,EAAf,EACE,KAAK,QAAL,CACA,KAAK,SAAL,CACA,KAAK,QAAL,CACE,MAAO,CAAA,CACT,SACE,MAAO,CAAA,CANX,CAD0B,CA7D5B,MAAO,SAAQ,CAAC0D,CAAD,CAAQmpD,CAAR,CAAuBC,CAAvB,CAAqC,CAElD,GAAM,CAAAtuD,EAAA,CAAYkF,CAAZ,CAAN,CAA2B,MAAOA,EAE7B1E,EAAA,CAAQ6tD,CAAR,CAAL,GAA+BA,CAA/B,CAA+C,CAACA,CAAD,CAA/C,CAC6B,EAA7B,GAAIA,CAAAluD,OAAJ,GAAkCkuD,CAAlC,CAAkD,CAAC,GAAD,CAAlD,CAEA,KAAIK,EAAaN,CAAA,CAAkBC,CAAlB,CAAiCC,CAAjC,CAKbK,EAAAA,CAAgB/nC,KAAAjjB,UAAA4qD,IAAAxtD,KAAA,CAAyBmE,CAAzB;AAMpB0pD,QAA4B,CAACptD,CAAD,CAAQ2D,CAAR,CAAe,CACzC,MAAO,CACL3D,MAAOA,CADF,CAELqtD,gBAAiBH,CAAAH,IAAA,CAAe,QAAQ,CAACC,CAAD,CAAY,CACzB,IAAA,EAAAA,CAAAzhD,IAAA,CAAcvL,CAAd,CAkE3Bid,EAAAA,CAAO,MAAOjd,EAClB,IAAc,IAAd,GAAIA,CAAJ,CACEid,CACA,CADO,QACP,CAAAjd,CAAA,CAAQ,MAFV,KAGO,IAAa,QAAb,GAAIid,CAAJ,CACLjd,CAAA,CAAQA,CAAA6L,YAAA,EADH,KAEA,IAAa,QAAb,GAAIoR,CAAJ,CAtB0B,CAAA,CAAA,CAEjC,GAA6B,UAA7B,GAAI,MAAOjd,EAAAiB,QAAX,GACEjB,CACI,CADIA,CAAAiB,QAAA,EACJ,CAAAzB,CAAA,CAAYQ,CAAZ,CAFN,EAE0B,MAAA,CAG1B,IAAIiC,EAAA,CAAkBjC,CAAlB,CAAJ,GACEA,CACI,CADIA,CAAAkC,SAAA,EACJ,CAAA1C,CAAA,CAAYQ,CAAZ,CAFN,EAE0B,MAAA,CAG1B,EAAA,CA9DqD2D,CAkDpB,CAlD3B,MA2EC,CAAE3D,MAAOA,CAAT,CAAgBid,KAAMA,CAAtB,CA5EiD,CAAnC,CAFZ,CADkC,CANvB,CACpBkwC,EAAAvtD,KAAA,CAcA0tD,QAAqB,CAACC,CAAD,CAAKC,CAAL,CAAS,CAE5B,IADA,IAAI5qC,EAAS,CAAb,CACSjf,EAAM,CADf,CACkBhF,EAASuuD,CAAAvuD,OAA3B,CAA8CgF,CAA9C,CAAsDhF,CAAtD,CAA8D,EAAEgF,CAAhE,CAAuE,CACpD,IAAA,EAAA4pD,CAAAF,gBAAA,CAAmB1pD,CAAnB,CAAA,CAA2B,EAAA6pD,CAAAH,gBAAA,CAAmB1pD,CAAnB,CAA3B,CAuEjBif,EAAS,CACT2qC,EAAAtwC,KAAJ,GAAgBuwC,CAAAvwC,KAAhB,CACMswC,CAAAvtD,MADN,GACmBwtD,CAAAxtD,MADnB,GAEI4iB,CAFJ,CAEa2qC,CAAAvtD,MAAA,CAAWwtD,CAAAxtD,MAAX,CAAuB,EAAvB,CAA2B,CAFxC,EAKE4iB,CALF,CAKW2qC,CAAAtwC,KAAA,CAAUuwC,CAAAvwC,KAAV;AAAqB,EAArB,CAAyB,CA5EhC,IADA2F,CACA,CA8EGA,CA9EH,CADyEsqC,CAAA,CAAWvpD,CAAX,CAAAspD,WACzE,CAAY,KAFyD,CAIvE,MAAOrqC,EANqB,CAd9B,CAGA,OAFAlf,EAEA,CAFQypD,CAAAJ,IAAA,CAAkB,QAAQ,CAAC1E,CAAD,CAAO,CAAE,MAAOA,EAAAroD,MAAT,CAAjC,CAd0C,CADvB,CAkH/BytD,QAASA,GAAW,CAAC19C,CAAD,CAAY,CAC1B1Q,CAAA,CAAW0Q,CAAX,CAAJ,GACEA,CADF,CACc,CACV2a,KAAM3a,CADI,CADd,CAKAA,EAAAyd,SAAA,CAAqBzd,CAAAyd,SAArB,EAA2C,IAC3C,OAAOxrB,GAAA,CAAQ+N,CAAR,CAPuB,CAuiBhC29C,QAASA,GAAc,CAACnqD,CAAD,CAAUutB,CAAV,CAAiB6D,CAAjB,CAAyBte,CAAzB,CAAmCkB,CAAnC,CAAiD,CAAA,IAClErG,EAAO,IAD2D,CAElEy8C,EAAW,EAFuD,CAIlEC,EAAa18C,CAAA28C,aAAbD,CAAiCrqD,CAAA7B,OAAA,EAAA6K,WAAA,CAA4B,MAA5B,CAAjCqhD,EAAwEE,EAG5E58C,EAAA68C,OAAA,CAAc,EACd78C,EAAA88C,UAAA,CAAiB,EACjB98C,EAAA+8C,SAAA,CAAgB3vD,CAChB4S,EAAAg9C,MAAA,CAAa32C,CAAA,CAAauZ,CAAAxnB,KAAb,EAA2BwnB,CAAAle,OAA3B,EAA2C,EAA3C,CAAA,CAA+C+hB,CAA/C,CACbzjB,EAAAi9C,OAAA,CAAc,CAAA,CACdj9C,EAAAk9C,UAAA,CAAiB,CAAA,CACjBl9C,EAAAm9C,OAAA,CAAc,CAAA,CACdn9C,EAAAo9C,SAAA,CAAgB,CAAA,CAChBp9C,EAAAq9C,WAAA,CAAkB,CAAA,CAElBX,EAAAY,YAAA,CAAuBt9C,CAAvB,CAaAA,EAAAu9C,mBAAA,CAA0BC,QAAQ,EAAG,CACnCzvD,CAAA,CAAQ0uD,CAAR,CAAkB,QAAQ,CAACgB,CAAD,CAAU,CAClCA,CAAAF,mBAAA,EADkC,CAApC,CADmC,CAiBrCv9C,EAAA09C,iBAAA;AAAwBC,QAAQ,EAAG,CACjC5vD,CAAA,CAAQ0uD,CAAR,CAAkB,QAAQ,CAACgB,CAAD,CAAU,CAClCA,CAAAC,iBAAA,EADkC,CAApC,CADiC,CAenC19C,EAAAs9C,YAAA,CAAmBM,QAAQ,CAACH,CAAD,CAAU,CAGnCnhD,EAAA,CAAwBmhD,CAAAT,MAAxB,CAAuC,OAAvC,CACAP,EAAArpD,KAAA,CAAcqqD,CAAd,CAEIA,EAAAT,MAAJ,GACEh9C,CAAA,CAAKy9C,CAAAT,MAAL,CADF,CACwBS,CADxB,CANmC,CAYrCz9C,EAAA69C,gBAAA,CAAuBC,QAAQ,CAACL,CAAD,CAAUM,CAAV,CAAmB,CAChD,IAAIC,EAAUP,CAAAT,MAEVh9C,EAAA,CAAKg+C,CAAL,CAAJ,GAAsBP,CAAtB,EACE,OAAOz9C,CAAA,CAAKg+C,CAAL,CAETh+C,EAAA,CAAK+9C,CAAL,CAAA,CAAgBN,CAChBA,EAAAT,MAAA,CAAgBe,CAPgC,CAmBlD/9C,EAAAi+C,eAAA,CAAsBC,QAAQ,CAACT,CAAD,CAAU,CAClCA,CAAAT,MAAJ,EAAqBh9C,CAAA,CAAKy9C,CAAAT,MAAL,CAArB,GAA6CS,CAA7C,EACE,OAAOz9C,CAAA,CAAKy9C,CAAAT,MAAL,CAETjvD,EAAA,CAAQiS,CAAA+8C,SAAR,CAAuB,QAAQ,CAACjuD,CAAD,CAAQsJ,CAAR,CAAc,CAC3C4H,CAAAm+C,aAAA,CAAkB/lD,CAAlB,CAAwB,IAAxB,CAA8BqlD,CAA9B,CAD2C,CAA7C,CAGA1vD,EAAA,CAAQiS,CAAA68C,OAAR,CAAqB,QAAQ,CAAC/tD,CAAD,CAAQsJ,CAAR,CAAc,CACzC4H,CAAAm+C,aAAA,CAAkB/lD,CAAlB,CAAwB,IAAxB,CAA8BqlD,CAA9B,CADyC,CAA3C,CAGA1vD,EAAA,CAAQiS,CAAA88C,UAAR,CAAwB,QAAQ,CAAChuD,CAAD,CAAQsJ,CAAR,CAAc,CAC5C4H,CAAAm+C,aAAA,CAAkB/lD,CAAlB,CAAwB,IAAxB,CAA8BqlD,CAA9B,CAD4C,CAA9C,CAIAlrD,GAAA,CAAYkqD,CAAZ,CAAsBgB,CAAtB,CAdsC,CA2BxCW,GAAA,CAAqB,CACnBC,KAAM,IADa,CAEnBjhC,SAAU/qB,CAFS,CAGnBisD,IAAKA,QAAQ,CAACrb,CAAD,CAASjF,CAAT;AAAmB3iC,CAAnB,CAA+B,CAC1C,IAAI4Y,EAAOgvB,CAAA,CAAOjF,CAAP,CACN/pB,EAAL,CAIiB,EAJjB,GAGcA,CAAAvhB,QAAAD,CAAa4I,CAAb5I,CAHd,EAKIwhB,CAAA7gB,KAAA,CAAUiI,CAAV,CALJ,CACE4nC,CAAA,CAAOjF,CAAP,CADF,CACqB,CAAC3iC,CAAD,CAHqB,CAHzB,CAcnBkjD,MAAOA,QAAQ,CAACtb,CAAD,CAASjF,CAAT,CAAmB3iC,CAAnB,CAA+B,CAC5C,IAAI4Y,EAAOgvB,CAAA,CAAOjF,CAAP,CACN/pB,EAAL,GAGA1hB,EAAA,CAAY0hB,CAAZ,CAAkB5Y,CAAlB,CACA,CAAoB,CAApB,GAAI4Y,CAAAxmB,OAAJ,EACE,OAAOw1C,CAAA,CAAOjF,CAAP,CALT,CAF4C,CAd3B,CAwBnB0e,WAAYA,CAxBO,CAyBnBv3C,SAAUA,CAzBS,CAArB,CAsCAnF,EAAAw+C,UAAA,CAAiBC,QAAQ,EAAG,CAC1Bt5C,CAAAgL,YAAA,CAAqB9d,CAArB,CAA8BqsD,EAA9B,CACAv5C,EAAA+K,SAAA,CAAkB7d,CAAlB,CAA2BssD,EAA3B,CACA3+C,EAAAi9C,OAAA,CAAc,CAAA,CACdj9C,EAAAk9C,UAAA,CAAiB,CAAA,CACjBR,EAAA8B,UAAA,EAL0B,CAsB5Bx+C,EAAA4+C,aAAA,CAAoBC,QAAQ,EAAG,CAC7B15C,CAAA25C,SAAA,CAAkBzsD,CAAlB,CAA2BqsD,EAA3B,CAA2CC,EAA3C,CAtOcI,eAsOd,CACA/+C,EAAAi9C,OAAA,CAAc,CAAA,CACdj9C,EAAAk9C,UAAA,CAAiB,CAAA,CACjBl9C,EAAAq9C,WAAA,CAAkB,CAAA,CAClBtvD,EAAA,CAAQ0uD,CAAR,CAAkB,QAAQ,CAACgB,CAAD,CAAU,CAClCA,CAAAmB,aAAA,EADkC,CAApC,CAL6B,CAuB/B5+C,EAAAg/C,cAAA,CAAqBC,QAAQ,EAAG,CAC9BlxD,CAAA,CAAQ0uD,CAAR,CAAkB,QAAQ,CAACgB,CAAD,CAAU,CAClCA,CAAAuB,cAAA,EADkC,CAApC,CAD8B,CAahCh/C,EAAAk/C,cAAA,CAAqBC,QAAQ,EAAG,CAC9Bh6C,CAAA+K,SAAA,CAAkB7d,CAAlB;AA1Qc0sD,cA0Qd,CACA/+C,EAAAq9C,WAAA,CAAkB,CAAA,CAClBX,EAAAwC,cAAA,EAH8B,CAxNsC,CAu9CxEE,QAASA,GAAoB,CAACf,CAAD,CAAO,CAClCA,CAAAgB,YAAAjsD,KAAA,CAAsB,QAAQ,CAACtE,CAAD,CAAQ,CACpC,MAAOuvD,EAAAiB,SAAA,CAAcxwD,CAAd,CAAA,CAAuBA,CAAvB,CAA+BA,CAAAkC,SAAA,EADF,CAAtC,CADkC,CAWpCuuD,QAASA,GAAa,CAAClmD,CAAD,CAAQhH,CAAR,CAAiBN,CAAjB,CAAuBssD,CAAvB,CAA6Bp2C,CAA7B,CAAuCxC,CAAvC,CAAiD,CACrE,IAAIsG,EAAOzZ,CAAA,CAAUD,CAAA,CAAQ,CAAR,CAAA0Z,KAAV,CAKX,IAAKgnC,CAAA9qC,CAAA8qC,QAAL,CAAuB,CACrB,IAAIyM,EAAY,CAAA,CAEhBntD,EAAA6I,GAAA,CAAW,kBAAX,CAA+B,QAAQ,CAAC1B,CAAD,CAAO,CAC5CgmD,CAAA,CAAY,CAAA,CADgC,CAA9C,CAIAntD,EAAA6I,GAAA,CAAW,gBAAX,CAA6B,QAAQ,EAAG,CACtCskD,CAAA,CAAY,CAAA,CACZ1oC,EAAA,EAFsC,CAAxC,CAPqB,CAavB,IAAIA,EAAWA,QAAQ,CAAC2oC,CAAD,CAAK,CACtB1rB,CAAJ,GACEtuB,CAAAiT,MAAAI,OAAA,CAAsBib,CAAtB,CACA,CAAAA,CAAA,CAAU,IAFZ,CAIA,IAAIyrB,CAAAA,CAAJ,CAAA,CAL0B,IAMtB1wD,EAAQuD,CAAAyC,IAAA,EACRma,EAAAA,CAAQwwC,CAARxwC,EAAcwwC,CAAA1zC,KAKL,WAAb,GAAIA,CAAJ,EAA6Bha,CAAA2tD,OAA7B,EAA4D,OAA5D,GAA4C3tD,CAAA2tD,OAA5C,GACE5wD,CADF,CACUmc,CAAA,CAAKnc,CAAL,CADV,CAOA,EAAIuvD,CAAAsB,WAAJ,GAAwB7wD,CAAxB,EAA4C,EAA5C,GAAkCA,CAAlC,EAAkDuvD,CAAAuB,sBAAlD,GACEvB,CAAAwB,cAAA,CAAmB/wD,CAAnB,CAA0BmgB,CAA1B,CAfF,CAL0B,CA0B5B;GAAIhH,CAAA0rC,SAAA,CAAkB,OAAlB,CAAJ,CACEthD,CAAA6I,GAAA,CAAW,OAAX,CAAoB4b,CAApB,CADF,KAEO,CACL,IAAIid,CAAJ,CAEI+rB,EAAgBA,QAAQ,CAACL,CAAD,CAAK5/C,CAAL,CAAYkgD,CAAZ,CAAuB,CAC5ChsB,CAAL,GACEA,CADF,CACYtuB,CAAAiT,MAAA,CAAe,QAAQ,EAAG,CAClCqb,CAAA,CAAU,IACLl0B,EAAL,EAAcA,CAAA/Q,MAAd,GAA8BixD,CAA9B,EACEjpC,CAAA,CAAS2oC,CAAT,CAHgC,CAA1B,CADZ,CADiD,CAWnDptD,EAAA6I,GAAA,CAAW,SAAX,CAAsB,QAAQ,CAAC+T,CAAD,CAAQ,CACpC,IAAI/gB,EAAM+gB,CAAA+wC,QAIE,GAAZ,GAAI9xD,CAAJ,EAAmB,EAAnB,CAAwBA,CAAxB,EAAqC,EAArC,CAA+BA,CAA/B,EAA6C,EAA7C,EAAmDA,CAAnD,EAAiE,EAAjE,EAA0DA,CAA1D,EAEA4xD,CAAA,CAAc7wC,CAAd,CAAqB,IAArB,CAA2B,IAAAngB,MAA3B,CAPoC,CAAtC,CAWA,IAAImZ,CAAA0rC,SAAA,CAAkB,OAAlB,CAAJ,CACEthD,CAAA6I,GAAA,CAAW,WAAX,CAAwB4kD,CAAxB,CA1BG,CAgCPztD,CAAA6I,GAAA,CAAW,QAAX,CAAqB4b,CAArB,CAEAunC,EAAA4B,QAAA,CAAeC,QAAQ,EAAG,CACxB7tD,CAAAyC,IAAA,CAAYupD,CAAAiB,SAAA,CAAcjB,CAAAsB,WAAd,CAAA,CAAiC,EAAjC,CAAsCtB,CAAAsB,WAAlD,CADwB,CAjF2C,CAsHvEQ,QAASA,GAAgB,CAACrjC,CAAD,CAASsjC,CAAT,CAAkB,CACzC,MAAO,SAAQ,CAACC,CAAD,CAAMzqD,CAAN,CAAY,CAAA,IACrBuB,CADqB,CACd0kD,CAEX,IAAIhsD,EAAA,CAAOwwD,CAAP,CAAJ,CACE,MAAOA,EAGT,IAAIxyD,CAAA,CAASwyD,CAAT,CAAJ,CAAmB,CAII,GAArB,EAAIA,CAAAzsD,OAAA,CAAW,CAAX,CAAJ,EAA0D,GAA1D,EAA4BysD,CAAAzsD,OAAA,CAAWysD,CAAA5yD,OAAX,CAAwB,CAAxB,CAA5B,GACE4yD,CADF,CACQA,CAAAl9B,UAAA,CAAc,CAAd,CAAiBk9B,CAAA5yD,OAAjB,CAA8B,CAA9B,CADR,CAGA;GAAI6yD,EAAAntD,KAAA,CAAqBktD,CAArB,CAAJ,CACE,MAAO,KAAIvwD,IAAJ,CAASuwD,CAAT,CAETvjC,EAAArpB,UAAA,CAAmB,CAGnB,IAFA0D,CAEA,CAFQ2lB,CAAAzS,KAAA,CAAYg2C,CAAZ,CAER,CAqBE,MApBAlpD,EAAAyb,MAAA,EAoBO,CAlBLipC,CAkBK,CAnBHjmD,CAAJ,CACQ,CACJ2qD,KAAM3qD,CAAAokD,YAAA,EADF,CAEJwG,GAAI5qD,CAAAskD,SAAA,EAAJsG,CAAsB,CAFlB,CAGJC,GAAI7qD,CAAAukD,QAAA,EAHA,CAIJuG,GAAI9qD,CAAA+qD,SAAA,EAJA,CAKJC,GAAIhrD,CAAAK,WAAA,EALA,CAMJ4qD,GAAIjrD,CAAAkrD,WAAA,EANA,CAOJC,IAAKnrD,CAAAorD,gBAAA,EAALD,CAA8B,GAP1B,CADR,CAWQ,CAAER,KAAM,IAAR,CAAcC,GAAI,CAAlB,CAAqBC,GAAI,CAAzB,CAA4BC,GAAI,CAAhC,CAAmCE,GAAI,CAAvC,CAA0CC,GAAI,CAA9C,CAAiDE,IAAK,CAAtD,CAQD,CALPhzD,CAAA,CAAQoJ,CAAR,CAAe,QAAQ,CAAC8pD,CAAD,CAAOxuD,CAAP,CAAc,CAC/BA,CAAJ,CAAY2tD,CAAA3yD,OAAZ,GACEouD,CAAA,CAAIuE,CAAA,CAAQ3tD,CAAR,CAAJ,CADF,CACwB,CAACwuD,CADzB,CADmC,CAArC,CAKO,CAAA,IAAInxD,IAAJ,CAAS+rD,CAAA0E,KAAT,CAAmB1E,CAAA2E,GAAnB,CAA4B,CAA5B,CAA+B3E,CAAA4E,GAA/B,CAAuC5E,CAAA6E,GAAvC,CAA+C7E,CAAA+E,GAA/C,CAAuD/E,CAAAgF,GAAvD,EAAiE,CAAjE,CAA8E,GAA9E,CAAoEhF,CAAAkF,IAApE,EAAsF,CAAtF,CAlCQ,CAsCnB,MAAOG,IA7CkB,CADc,CAkD3CC,QAASA,GAAmB,CAACp1C,CAAD,CAAO+Q,CAAP,CAAeskC,CAAf,CAA0BjG,CAA1B,CAAkC,CAC5D,MAAOkG,SAA6B,CAAChoD,CAAD,CAAQhH,CAAR,CAAiBN,CAAjB,CAAuBssD,CAAvB,CAA6Bp2C,CAA7B,CAAuCxC,CAAvC,CAAiDU,CAAjD,CAA0D,CA4D5Fm7C,QAASA,EAAW,CAACxyD,CAAD,CAAQ,CAE1B,MAAOA,EAAP,EAAgB,EAAEA,CAAAwE,QAAF,EAAmBxE,CAAAwE,QAAA,EAAnB,GAAuCxE,CAAAwE,QAAA,EAAvC,CAFU,CAK5BiuD,QAASA,EAAsB,CAACzsD,CAAD,CAAM,CACnC,MAAO3D,EAAA,CAAU2D,CAAV,CAAA;AAAkBjF,EAAA,CAAOiF,CAAP,CAAA,CAAcA,CAAd,CAAoBssD,CAAA,CAAUtsD,CAAV,CAAtC,CAAwD1H,CAD5B,CAhErCo0D,EAAA,CAAgBnoD,CAAhB,CAAuBhH,CAAvB,CAAgCN,CAAhC,CAAsCssD,CAAtC,CACAkB,GAAA,CAAclmD,CAAd,CAAqBhH,CAArB,CAA8BN,CAA9B,CAAoCssD,CAApC,CAA0Cp2C,CAA1C,CAAoDxC,CAApD,CACA,KAAIlQ,EAAW8oD,CAAX9oD,EAAmB8oD,CAAAoD,SAAnBlsD,EAAoC8oD,CAAAoD,SAAAlsD,SAAxC,CACImsD,CAEJrD,EAAAsD,aAAA,CAAoB51C,CACpBsyC,EAAAuD,SAAAxuD,KAAA,CAAmB,QAAQ,CAACtE,CAAD,CAAQ,CACjC,MAAIuvD,EAAAiB,SAAA,CAAcxwD,CAAd,CAAJ,CAAiC,IAAjC,CACIguB,CAAA3pB,KAAA,CAAYrE,CAAZ,CAAJ,EAIM+yD,CAIGA,CAJUT,CAAA,CAAUtyD,CAAV,CAAiB4yD,CAAjB,CAIVG,CAHHtsD,CAGGssD,GAFLA,CAEKA,CAFQlsD,EAAA,CAAuBksD,CAAvB,CAAmCtsD,CAAnC,CAERssD,EAAAA,CART,EAUOz0D,CAZ0B,CAAnC,CAeAixD,EAAAgB,YAAAjsD,KAAA,CAAsB,QAAQ,CAACtE,CAAD,CAAQ,CACpC,GAAIA,CAAJ,EAAc,CAAAe,EAAA,CAAOf,CAAP,CAAd,CACE,KAAMgzD,GAAA,CAAe,SAAf,CAAyDhzD,CAAzD,CAAN,CAEF,GAAIwyD,CAAA,CAAYxyD,CAAZ,CAAJ,CAKE,MAAO,CAJP4yD,CAIO,CAJQ5yD,CAIR,GAHayG,CAGb,GAFLmsD,CAEK,CAFU/rD,EAAA,CAAuB+rD,CAAvB,CAAqCnsD,CAArC,CAA+C,CAAA,CAA/C,CAEV,EAAA4Q,CAAA,CAAQ,MAAR,CAAA,CAAgBrX,CAAhB,CAAuBqsD,CAAvB,CAA+B5lD,CAA/B,CAEPmsD,EAAA,CAAe,IACf,OAAO,EAZ2B,CAAtC,CAgBA,IAAIvwD,CAAA,CAAUY,CAAAgnD,IAAV,CAAJ,EAA2BhnD,CAAAgwD,MAA3B,CAAuC,CACrC,IAAIC,CACJ3D,EAAA4D,YAAAlJ,IAAA,CAAuBmJ,QAAQ,CAACpzD,CAAD,CAAQ,CACrC,MAAO,CAACwyD,CAAA,CAAYxyD,CAAZ,CAAR,EAA8BoC,CAAA,CAAY8wD,CAAZ,CAA9B,EAAqDZ,CAAA,CAAUtyD,CAAV,CAArD,EAAyEkzD,CADpC,CAGvCjwD,EAAAg5B,SAAA,CAAc,KAAd,CAAqB,QAAQ,CAACj2B,CAAD,CAAM,CACjCktD,CAAA,CAAST,CAAA,CAAuBzsD,CAAvB,CACTupD,EAAA8D,UAAA,EAFiC,CAAnC,CALqC,CAWvC,GAAIhxD,CAAA,CAAUY,CAAAy0B,IAAV,CAAJ,EAA2Bz0B,CAAAqwD,MAA3B,CAAuC,CACrC,IAAIC,CACJhE;CAAA4D,YAAAz7B,IAAA,CAAuB87B,QAAQ,CAACxzD,CAAD,CAAQ,CACrC,MAAO,CAACwyD,CAAA,CAAYxyD,CAAZ,CAAR,EAA8BoC,CAAA,CAAYmxD,CAAZ,CAA9B,EAAqDjB,CAAA,CAAUtyD,CAAV,CAArD,EAAyEuzD,CADpC,CAGvCtwD,EAAAg5B,SAAA,CAAc,KAAd,CAAqB,QAAQ,CAACj2B,CAAD,CAAM,CACjCutD,CAAA,CAASd,CAAA,CAAuBzsD,CAAvB,CACTupD,EAAA8D,UAAA,EAFiC,CAAnC,CALqC,CAjDqD,CADlC,CAwE9DX,QAASA,GAAe,CAACnoD,CAAD,CAAQhH,CAAR,CAAiBN,CAAjB,CAAuBssD,CAAvB,CAA6B,CAGnD,CADuBA,CAAAuB,sBACvB,CADoDnwD,CAAA,CADzC4C,CAAAT,CAAQ,CAARA,CACkD2wD,SAAT,CACpD,GACElE,CAAAuD,SAAAxuD,KAAA,CAAmB,QAAQ,CAACtE,CAAD,CAAQ,CACjC,IAAIyzD,EAAWlwD,CAAAP,KAAA,CAt+pBS0wD,UAs+pBT,CAAXD,EAAoD,EAKxD,OAAOA,EAAAE,SAAA,EAAsBC,CAAAH,CAAAG,aAAtB,CAA8Ct1D,CAA9C,CAA0D0B,CANhC,CAAnC,CAJiD,CAqHrD6zD,QAASA,GAAiB,CAACt7C,CAAD,CAASpZ,CAAT,CAAkBmK,CAAlB,CAAwB21B,CAAxB,CAAoCv4B,CAApC,CAA8C,CAEtE,GAAIrE,CAAA,CAAU48B,CAAV,CAAJ,CAA2B,CACzB60B,CAAA,CAAUv7C,CAAA,CAAO0mB,CAAP,CACV,IAAKtvB,CAAAmkD,CAAAnkD,SAAL,CACE,KAAMpR,EAAA,CAAO,SAAP,CAAA,CAAkB,WAAlB,CACiC+K,CADjC,CACuC21B,CADvC,CAAN,CAGF,MAAO60B,EAAA,CAAQ30D,CAAR,CANkB,CAQ3B,MAAOuH,EAV+D,CAolBxEqtD,QAASA,GAAc,CAACzqD,CAAD,CAAO4U,CAAP,CAAiB,CACtC5U,CAAA,CAAO,SAAP,CAAmBA,CACnB,OAAO,CAAC,UAAD,CAAa,QAAQ,CAAC+M,CAAD,CAAW,CAiFrC29C,QAASA,EAAe,CAACz1B,CAAD,CAAUC,CAAV,CAAmB,CACzC,IAAIF,EAAS,EAAb,CAGSz+B,EAAI,CADb,EAAA,CACA,IAAA,CAAgBA,CAAhB,CAAoB0+B,CAAA5/B,OAApB,CAAoCkB,CAAA,EAApC,CAAyC,CAEvC,IADA,IAAI4+B;AAAQF,CAAA,CAAQ1+B,CAAR,CAAZ,CACSe,EAAI,CAAb,CAAgBA,CAAhB,CAAoB49B,CAAA7/B,OAApB,CAAoCiC,CAAA,EAApC,CACE,GAAI69B,CAAJ,EAAaD,CAAA,CAAQ59B,CAAR,CAAb,CAAyB,SAAS,CAEpC09B,EAAAh6B,KAAA,CAAYm6B,CAAZ,CALuC,CAOzC,MAAOH,EAXkC,CAc3C21B,QAASA,EAAY,CAACr3B,CAAD,CAAW,CAC9B,IAAIzb,EAAU,EACd,OAAIniB,EAAA,CAAQ49B,CAAR,CAAJ,EACE39B,CAAA,CAAQ29B,CAAR,CAAkB,QAAQ,CAAC6C,CAAD,CAAI,CAC5Bte,CAAA,CAAUA,CAAA7b,OAAA,CAAe2uD,CAAA,CAAax0B,CAAb,CAAf,CADkB,CAA9B,CAGOte,CAAAA,CAJT,EAKWpiB,CAAA,CAAS69B,CAAT,CAAJ,CACEA,CAAAv5B,MAAA,CAAe,GAAf,CADF,CAEI1C,CAAA,CAASi8B,CAAT,CAAJ,EACL39B,CAAA,CAAQ29B,CAAR,CAAkB,QAAQ,CAAC6C,CAAD,CAAIjE,CAAJ,CAAO,CAC3BiE,CAAJ,GACEte,CADF,CACYA,CAAA7b,OAAA,CAAek2B,CAAAn4B,MAAA,CAAQ,GAAR,CAAf,CADZ,CAD+B,CAAjC,CAKO8d,CAAAA,CANF,EAQAyb,CAjBuB,CA9FhC,MAAO,CACLpP,SAAU,IADL,CAEL9C,KAAMA,QAAQ,CAACngB,CAAD,CAAQhH,CAAR,CAAiBN,CAAjB,CAAuB,CAiCnCixD,QAASA,EAAiB,CAAC/yC,CAAD,CAAU8nB,CAAV,CAAiB,CAGzC,IAAIkrB,EAAc5wD,CAAAmH,KAAA,CAAa,cAAb,CAAdypD,EAA8C9uD,EAAA,EAAlD,CACI+uD,EAAkB,EACtBn1D,EAAA,CAAQkiB,CAAR,CAAiB,QAAQ,CAACoN,CAAD,CAAY,CACnC,GAAY,CAAZ,CAAI0a,CAAJ,EAAiBkrB,CAAA,CAAY5lC,CAAZ,CAAjB,CACE4lC,CAAA,CAAY5lC,CAAZ,CACA,EAD0B4lC,CAAA,CAAY5lC,CAAZ,CAC1B,EADoD,CACpD,EADyD0a,CACzD,CAAIkrB,CAAA,CAAY5lC,CAAZ,CAAJ,GAA+B,EAAU,CAAV,CAAE0a,CAAF,CAA/B,EACEmrB,CAAA9vD,KAAA,CAAqBiqB,CAArB,CAJ+B,CAArC,CAQAhrB,EAAAmH,KAAA,CAAa,cAAb,CAA6BypD,CAA7B,CACA,OAAOC,EAAA5rD,KAAA,CAAqB,GAArB,CAdkC,CA8B3C6rD,QAASA,EAAkB,CAAC9tC,CAAD,CAAS,CAClC,GAAiB,CAAA,CAAjB,GAAIrI,CAAJ,EAAyB3T,CAAA+pD,OAAzB,CAAwC,CAAxC,GAA8Cp2C,CAA9C,CAAwD,CACtD,IAAI4e,EAAam3B,CAAA,CAAa1tC,CAAb,EAAuB,EAAvB,CACjB,IAAKC,CAAAA,CAAL,CAAa,CA1Cf,IAAIsW;AAAao3B,CAAA,CA2CFp3B,CA3CE,CAA2B,CAA3B,CACjB75B,EAAA05B,UAAA,CAAeG,CAAf,CAyCe,CAAb,IAEO,IAAK,CAAA/3B,EAAA,CAAOwhB,CAAP,CAAcC,CAAd,CAAL,CAA4B,CAEnBuS,IAAAA,EADGk7B,CAAAl7B,CAAavS,CAAbuS,CACHA,CAnBdgE,EAAQi3B,CAAA,CAmBkBl3B,CAnBlB,CAA4B/D,CAA5B,CAmBMA,CAlBdkE,EAAW+2B,CAAA,CAAgBj7B,CAAhB,CAkBe+D,CAlBf,CAkBG/D,CAjBlBgE,EAAQm3B,CAAA,CAAkBn3B,CAAlB,CAAyB,CAAzB,CAiBUhE,CAhBlBkE,EAAWi3B,CAAA,CAAkBj3B,CAAlB,CAA6B,EAA7B,CACPF,EAAJ,EAAaA,CAAAp+B,OAAb,EACE0X,CAAA+K,SAAA,CAAkB7d,CAAlB,CAA2Bw5B,CAA3B,CAEEE,EAAJ,EAAgBA,CAAAt+B,OAAhB,EACE0X,CAAAgL,YAAA,CAAqB9d,CAArB,CAA8B05B,CAA9B,CASmC,CAJmB,CASxDzW,CAAA,CAAS3hB,EAAA,CAAY0hB,CAAZ,CAVyB,CA9DpC,IAAIC,CAEJjc,EAAA5H,OAAA,CAAaM,CAAA,CAAKqG,CAAL,CAAb,CAAyB+qD,CAAzB,CAA6C,CAAA,CAA7C,CAEApxD,EAAAg5B,SAAA,CAAc,OAAd,CAAuB,QAAQ,CAACj8B,CAAD,CAAQ,CACrCq0D,CAAA,CAAmB9pD,CAAA61C,MAAA,CAAYn9C,CAAA,CAAKqG,CAAL,CAAZ,CAAnB,CADqC,CAAvC,CAKa,UAAb,GAAIA,CAAJ,EACEiB,CAAA5H,OAAA,CAAa,QAAb,CAAuB,QAAQ,CAAC2xD,CAAD,CAASC,CAAT,CAAoB,CAEjD,IAAIC,EAAMF,CAANE,CAAe,CACnB,IAAIA,CAAJ,IAAaD,CAAb,CAAyB,CAAzB,EAA6B,CAC3B,IAAIpzC,EAAU8yC,CAAA,CAAa1pD,CAAA61C,MAAA,CAAYn9C,CAAA,CAAKqG,CAAL,CAAZ,CAAb,CACdkrD,EAAA,GAAQt2C,CAAR,EAQA4e,CACJ,CADiBo3B,CAAA,CAPA/yC,CAOA,CAA2B,CAA3B,CACjB,CAAAle,CAAA05B,UAAA,CAAeG,CAAf,CATI,GAaAA,CACJ,CADiBo3B,CAAA,CAXG/yC,CAWH,CAA4B,EAA5B,CACjB,CAAAle,CAAA45B,aAAA,CAAkBC,CAAlB,CAdI,CAF2B,CAHoB,CAAnD,CAXiC,CAFhC,CAD8B,CAAhC,CAF+B,CAyoGxCwyB,QAASA,GAAoB,CAACnwD,CAAD,CAAU,CA6ErCs1D,QAASA,EAAiB,CAAClmC,CAAD,CAAYmmC,CAAZ,CAAyB,CAC7CA,CAAJ,EAAoB,CAAAC,CAAA,CAAWpmC,CAAX,CAApB,EACElY,CAAA+K,SAAA,CAAkBkN,CAAlB,CAA4BC,CAA5B,CACA,CAAAomC,CAAA,CAAWpmC,CAAX,CAAA,CAAwB,CAAA,CAF1B,EAGYmmC,CAAAA,CAHZ,EAG2BC,CAAA,CAAWpmC,CAAX,CAH3B,GAIElY,CAAAgL,YAAA,CAAqBiN,CAArB,CAA+BC,CAA/B,CACA,CAAAomC,CAAA,CAAWpmC,CAAX,CAAA,CAAwB,CAAA,CAL1B,CADiD,CA7Ed;AAuFrCqmC,QAASA,EAAmB,CAACC,CAAD,CAAqBC,CAArB,CAA8B,CACxDD,CAAA,CAAqBA,CAAA,CAAqB,GAArB,CAA2BrpD,EAAA,CAAWqpD,CAAX,CAA+B,GAA/B,CAA3B,CAAiE,EAEtFJ,EAAA,CAAkBM,EAAlB,CAAgCF,CAAhC,CAAgE,CAAA,CAAhE,GAAoDC,CAApD,CACAL,EAAA,CAAkBO,EAAlB,CAAkCH,CAAlC,CAAkE,CAAA,CAAlE,GAAsDC,CAAtD,CAJwD,CAvFrB,IACjCvF,EAAOpwD,CAAAowD,KAD0B,CAEjCjhC,EAAWnvB,CAAAmvB,SAFsB,CAGjCqmC,EAAa,EAHoB,CAIjCnF,EAAMrwD,CAAAqwD,IAJ2B,CAKjCC,EAAQtwD,CAAAswD,MALyB,CAMjC7B,EAAazuD,CAAAyuD,WANoB,CAOjCv3C,EAAWlX,CAAAkX,SAEfs+C,EAAA,CAAWK,EAAX,CAAA,CAA4B,EAAEL,CAAA,CAAWI,EAAX,CAAF,CAA4BzmC,CAAApN,SAAA,CAAkB6zC,EAAlB,CAA5B,CAE5BxF,EAAAF,aAAA,CAEA4F,QAAoB,CAACJ,CAAD,CAAqBptC,CAArB,CAA4Blb,CAA5B,CAAwC,CACtDkb,CAAJ,GAAcnpB,CAAd,EAgDKixD,CAAA,SAGL,GAFEA,CAAA,SAEF,CAFe,EAEf,EAAAC,CAAA,CAAID,CAAA,SAAJ,CAlD2BsF,CAkD3B,CAlD+CtoD,CAkD/C,CAnDA,GAuDIgjD,CAAA,SAGJ,EAFEE,CAAA,CAAMF,CAAA,SAAN,CArD4BsF,CAqD5B,CArDgDtoD,CAqDhD,CAEF,CAAI2oD,EAAA,CAAc3F,CAAA,SAAd,CAAJ,GACEA,CAAA,SADF,CACejxD,CADf,CA1DA,CAKKsE,GAAA,CAAU6kB,CAAV,CAAL,CAIMA,CAAJ,EACEgoC,CAAA,CAAMF,CAAAxB,OAAN,CAAmB8G,CAAnB,CAAuCtoD,CAAvC,CACA,CAAAijD,CAAA,CAAID,CAAAvB,UAAJ,CAAoB6G,CAApB,CAAwCtoD,CAAxC,CAFF,GAIEijD,CAAA,CAAID,CAAAxB,OAAJ,CAAiB8G,CAAjB,CAAqCtoD,CAArC,CACA,CAAAkjD,CAAA,CAAMF,CAAAvB,UAAN,CAAsB6G,CAAtB,CAA0CtoD,CAA1C,CALF,CAJF,EACEkjD,CAAA,CAAMF,CAAAxB,OAAN,CAAmB8G,CAAnB,CAAuCtoD,CAAvC,CACA,CAAAkjD,CAAA,CAAMF,CAAAvB,UAAN,CAAsB6G,CAAtB,CAA0CtoD,CAA1C,CAFF,CAYIgjD,EAAAtB,SAAJ,EACEwG,CAAA,CAAkBU,EAAlB,CAAiC,CAAA,CAAjC,CAEA,CADA5F,CAAAlB,OACA,CADckB,CAAAjB,SACd,CAD8BhwD,CAC9B,CAAAs2D,CAAA,CAAoB,EAApB,CAAwB,IAAxB,CAHF,GAKEH,CAAA,CAAkBU,EAAlB;AAAiC,CAAA,CAAjC,CAGA,CAFA5F,CAAAlB,OAEA,CAFc6G,EAAA,CAAc3F,CAAAxB,OAAd,CAEd,CADAwB,CAAAjB,SACA,CADgB,CAACiB,CAAAlB,OACjB,CAAAuG,CAAA,CAAoB,EAApB,CAAwBrF,CAAAlB,OAAxB,CARF,CAiBE+G,EAAA,CADE7F,CAAAtB,SAAJ,EAAqBsB,CAAAtB,SAAA,CAAc4G,CAAd,CAArB,CACkBv2D,CADlB,CAEWixD,CAAAxB,OAAA,CAAY8G,CAAZ,CAAJ,CACW,CAAA,CADX,CAEItF,CAAAvB,UAAA,CAAe6G,CAAf,CAAJ,CACW,CAAA,CADX,CAGW,IAGlBD,EAAA,CAAoBC,CAApB,CAAwCO,CAAxC,CACAxH,EAAAyB,aAAA,CAAwBwF,CAAxB,CAA4CO,CAA5C,CAA2D7F,CAA3D,CA7C0D,CAbvB,CA+FvC2F,QAASA,GAAa,CAACz2D,CAAD,CAAM,CAC1B,GAAIA,CAAJ,CACE,IAASuE,IAAAA,CAAT,GAAiBvE,EAAjB,CACE,GAAIA,CAAAa,eAAA,CAAmB0D,CAAnB,CAAJ,CACE,MAAO,CAAA,CAIb,OAAO,CAAA,CARmB,CAt5xB5B,IAAIqyD,GAAsB,oBAA1B,CAgBI7xD,EAAYA,QAAQ,CAACgoD,CAAD,CAAS,CAAC,MAAOzsD,EAAA,CAASysD,CAAT,CAAA,CAAmBA,CAAA3/C,YAAA,EAAnB,CAA0C2/C,CAAlD,CAhBjC,CAiBIlsD,GAAiBV,MAAAuD,UAAA7C,eAjBrB,CA6BI8Q,GAAYA,QAAQ,CAACo7C,CAAD,CAAS,CAAC,MAAOzsD,EAAA,CAASysD,CAAT,CAAA,CAAmBA,CAAA7wC,YAAA,EAAnB,CAA0C6wC,CAAlD,CA7BjC,CAwDI34B,EAxDJ,CAyDIvrB,CAzDJ,CA0DI6E,EA1DJ,CA2DIhL,GAAoB,EAAAA,MA3DxB,CA4DI0C,GAAoB,EAAAA,OA5DxB,CA6DIS,GAAoB,EAAAA,KA7DxB,CA8DIpC,GAAoBtD,MAAAuD,UAAAD,SA9DxB,CA+DII,GAAoB1D,MAAA0D,eA/DxB,CAgEI6B,GAAoB5F,CAAA,CAAO,IAAP,CAhExB,CAmEIsM;AAAoBzM,CAAAyM,QAApBA,GAAuCzM,CAAAyM,QAAvCA,CAAwD,EAAxDA,CAnEJ,CAoEI0F,EApEJ,CAqEIrQ,GAAoB,CAMxB2yB,GAAA,CAAOx0B,CAAAi3D,aA6PPzzD,EAAAmiB,QAAA,CAAe,EAsBfliB,GAAAkiB,QAAA,CAAmB,EAsInB,KAAIhlB,EAAUomB,KAAApmB,QAAd,CAuEIoF,GAAqB,+FAvEzB,CA6EI+X,EAAOA,QAAQ,CAACnc,CAAD,CAAQ,CACzB,MAAOjB,EAAA,CAASiB,CAAT,CAAA,CAAkBA,CAAAmc,KAAA,EAAlB,CAAiCnc,CADf,CA7E3B,CAoFI2hD,GAAkBA,QAAQ,CAACwK,CAAD,CAAI,CAChC,MAAOA,EAAArkD,QAAA,CAAU,+BAAV,CAA2C,MAA3C,CAAAA,QAAA,CACU,OADV,CACmB,OADnB,CADyB,CApFlC,CAkYIwI,GAAMA,QAAQ,EAAG,CACnB,GAAIjO,CAAA,CAAUiO,EAAAilD,UAAV,CAAJ,CAA8B,MAAOjlD,GAAAilD,UAErC,KAAIC,EAAS,EAAG,CAAAn3D,CAAAoL,cAAA,CAAuB,UAAvB,CAAH,EACG,CAAApL,CAAAoL,cAAA,CAAuB,eAAvB,CADH,CAGb,IAAK+rD,CAAAA,CAAL,CACE,GAAI,CAEF,IAAIC,QAAJ,CAAa,EAAb,CAFE,CAIF,MAAOhuD,CAAP,CAAU,CACV+tD,CAAA,CAAS,CAAA,CADC,CAKd,MAAQllD,GAAAilD,UAAR;AAAwBC,CAhBL,CAlYrB,CA2bItpD,GAAKA,QAAQ,EAAG,CAClB,GAAI7J,CAAA,CAAU6J,EAAAwpD,MAAV,CAAJ,CAAyB,MAAOxpD,GAAAwpD,MAChC,KAAIC,CAAJ,CACI91D,CADJ,CACOa,EAAKoI,EAAAnK,OADZ,CACmC0K,CADnC,CAC2CC,CAC3C,KAAKzJ,CAAL,CAAS,CAAT,CAAYA,CAAZ,CAAgBa,CAAhB,CAAoB,EAAEb,CAAtB,CAEE,GADAwJ,CACI,CADKP,EAAA,CAAejJ,CAAf,CACL,CAAA81D,CAAA,CAAKt3D,CAAAoL,cAAA,CAAuB,GAAvB,CAA6BJ,CAAAvB,QAAA,CAAe,GAAf,CAAoB,KAApB,CAA7B,CAA0D,KAA1D,CAAT,CAA2E,CACzEwB,CAAA,CAAOqsD,CAAA5sD,aAAA,CAAgBM,CAAhB,CAAyB,IAAzB,CACP,MAFyE,CAM7E,MAAQ6C,GAAAwpD,MAAR,CAAmBpsD,CAZD,CA3bpB,CAusBIR,GAAiB,CAAC,KAAD,CAAQ,UAAR,CAAoB,KAApB,CAA2B,OAA3B,CAvsBrB,CAsgCI4C,GAAoB,QAtgCxB,CA8gCIM,GAAkB,CAAA,CA9gCtB,CA+gCIa,EA/gCJ,CAuqCI/N,GAAoB,CAvqCxB,CAyqCI+I,GAAiB,CAzqCrB,CAkpDIsI,GAAU,CACZylD,KAAM,OADM,CAEZC,MAAO,CAFK,CAGZC,MAAO,CAHK,CAIZC,IAAK,CAJO,CAKZC,SAAU,mBALE,CAmQd9oD,EAAAquB,QAAA,CAAiB,OA5iFsB,KA8iFnC7d,GAAUxQ,CAAAsW,MAAV9F,CAAyB,EA9iFU,CA+iFnCE,GAAO,CAWX1Q,EAAAH,MAAA,CAAekpD,QAAQ,CAACnzD,CAAD,CAAO,CAE5B,MAAO,KAAA0gB,MAAA,CAAW1gB,CAAA,CAAK,IAAAy4B,QAAL,CAAX,CAAP,EAAyC,EAFb,CAQ9B,KAAI/gB,GAAuB,iBAA3B,CACII,GAAkB,aADtB,CAEIs7C,GAAiB,CAAEC,WAAY,UAAd;AAA0BC,WAAY,WAAtC,CAFrB,CAGIh6C,GAAe7d,CAAA,CAAO,QAAP,CAHnB,CAkBI+d,GAAoB,4BAlBxB,CAmBInB,GAAc,WAnBlB,CAoBIG,GAAkB,WApBtB,CAqBIM,GAAmB,yEArBvB,CAuBIH,GAAU,CACZ,OAAU,CAAC,CAAD,CAAI,8BAAJ,CAAoC,WAApC,CADE,CAGZ,MAAS,CAAC,CAAD,CAAI,SAAJ,CAAe,UAAf,CAHG,CAIZ,IAAO,CAAC,CAAD,CAAI,mBAAJ,CAAyB,qBAAzB,CAJK,CAKZ,GAAM,CAAC,CAAD,CAAI,gBAAJ,CAAsB,kBAAtB,CALM,CAMZ,GAAM,CAAC,CAAD,CAAI,oBAAJ,CAA0B,uBAA1B,CANM,CAOZ,SAAY,CAAC,CAAD,CAAI,EAAJ,CAAQ,EAAR,CAPA,CAUdA,GAAA46C,SAAA,CAAmB56C,EAAA/J,OACnB+J,GAAA66C,MAAA,CAAgB76C,EAAA86C,MAAhB,CAAgC96C,EAAA+6C,SAAhC,CAAmD/6C,EAAAg7C,QAAnD,CAAqEh7C,EAAAi7C,MACrEj7C;EAAAk7C,GAAA,CAAal7C,EAAAm7C,GAkUb,KAAIvqD,GAAkBa,CAAA/K,UAAlBkK,CAAqC,CACvCwqD,MAAOA,QAAQ,CAAClxD,CAAD,CAAK,CAGlBmxD,QAASA,EAAO,EAAG,CACbC,CAAJ,GACAA,CACA,CADQ,CAAA,CACR,CAAApxD,CAAA,EAFA,CADiB,CAFnB,IAAIoxD,EAAQ,CAAA,CASgB,WAA5B,GAAI14D,CAAAohB,WAAJ,CACEC,UAAA,CAAWo3C,CAAX,CADF,EAGE,IAAA1qD,GAAA,CAAQ,kBAAR,CAA4B0qD,CAA5B,CAGA,CAAA5pD,CAAA,CAAO9O,CAAP,CAAAgO,GAAA,CAAkB,MAAlB,CAA0B0qD,CAA1B,CANF,CAVkB,CADmB,CAqBvC50D,SAAUA,QAAQ,EAAG,CACnB,IAAIlC,EAAQ,EACZf,EAAA,CAAQ,IAAR,CAAc,QAAQ,CAACwI,CAAD,CAAI,CAAEzH,CAAAsE,KAAA,CAAW,EAAX,CAAgBmD,CAAhB,CAAF,CAA1B,CACA,OAAO,GAAP,CAAazH,CAAAwI,KAAA,CAAW,IAAX,CAAb,CAAgC,GAHb,CArBkB,CA2BvCy1C,GAAIA,QAAQ,CAACt6C,CAAD,CAAQ,CAChB,MAAiB,EAAV,EAACA,CAAD,CAAe2D,CAAA,CAAO,IAAA,CAAK3D,CAAL,CAAP,CAAf,CAAqC2D,CAAA,CAAO,IAAA,CAAK,IAAA3I,OAAL,CAAmBgF,CAAnB,CAAP,CAD5B,CA3BmB,CA+BvChF,OAAQ,CA/B+B,CAgCvC2F,KAAMA,EAhCiC,CAiCvC1E,KAAM,EAAAA,KAjCiC,CAkCvCiE,OAAQ,EAAAA,OAlC+B,CAAzC,CA0CIgc,GAAe,EACnB5gB,EAAA,CAAQ,2DAAA,MAAA,CAAA,GAAA,CAAR,CAAgF,QAAQ,CAACe,CAAD,CAAQ,CAC9F6f,EAAA,CAAarc,CAAA,CAAUxD,CAAV,CAAb,CAAA,CAAiCA,CAD6D,CAAhG,CAGA,KAAI8f,GAAmB,EACvB7gB,EAAA,CAAQ,kDAAA,MAAA,CAAA,GAAA,CAAR;AAAuE,QAAQ,CAACe,CAAD,CAAQ,CACrF8f,EAAA,CAAiB9f,CAAjB,CAAA,CAA0B,CAAA,CAD2D,CAAvF,CAGA,KAAIggB,GAAe,CACjB,YAAe,WADE,CAEjB,YAAe,WAFE,CAGjB,MAAS,KAHQ,CAIjB,MAAS,KAJQ,CAKjB,UAAa,SALI,CAqBnB/gB,EAAA,CAAQ,CACNyL,KAAMmT,EADA,CAENm5C,WAAYp6C,EAFN,CAGN0e,QA9XF27B,QAAsB,CAACn0D,CAAD,CAAO,CAC3B,IAAS1D,IAAAA,CAAT,GAAgBse,GAAA,CAAQ5a,CAAA2a,MAAR,CAAhB,CACE,MAAO,CAAA,CAET,OAAO,CAAA,CAJoB,CA2XrB,CAAR,CAIG,QAAQ,CAAC9X,CAAD,CAAK2D,CAAL,CAAW,CACpB4D,CAAA,CAAO5D,CAAP,CAAA,CAAe3D,CADK,CAJtB,CAQA1G,EAAA,CAAQ,CACNyL,KAAMmT,EADA,CAENrR,cAAeoS,EAFT,CAINrU,MAAOA,QAAQ,CAAChH,CAAD,CAAU,CAEvB,MAAO+D,EAAAoD,KAAA,CAAYnH,CAAZ,CAAqB,QAArB,CAAP,EAAyCqb,EAAA,CAAoBrb,CAAAwb,WAApB,EAA0Cxb,CAA1C,CAAmD,CAAC,eAAD,CAAkB,QAAlB,CAAnD,CAFlB,CAJnB,CASN+I,aAAcA,QAAQ,CAAC/I,CAAD,CAAU,CAE9B,MAAO+D,EAAAoD,KAAA,CAAYnH,CAAZ,CAAqB,eAArB,CAAP,EAAgD+D,CAAAoD,KAAA,CAAYnH,CAAZ,CAAqB,yBAArB,CAFlB,CAT1B,CAcNgJ,WAAYoS,EAdN,CAgBN7U,SAAUA,QAAQ,CAACvG,CAAD,CAAU,CAC1B,MAAOqb,GAAA,CAAoBrb,CAApB;AAA6B,WAA7B,CADmB,CAhBtB,CAoBNs6B,WAAYA,QAAQ,CAACt6B,CAAD,CAAU+F,CAAV,CAAgB,CAClC/F,CAAA2zD,gBAAA,CAAwB5tD,CAAxB,CADkC,CApB9B,CAwBN4X,SAAUjD,EAxBJ,CA0BNk5C,IAAKA,QAAQ,CAAC5zD,CAAD,CAAU+F,CAAV,CAAgBtJ,CAAhB,CAAuB,CAClCsJ,CAAA,CAAOiR,EAAA,CAAUjR,CAAV,CAEP,IAAIjH,CAAA,CAAUrC,CAAV,CAAJ,CACEuD,CAAAiO,MAAA,CAAclI,CAAd,CAAA,CAAsBtJ,CADxB,KAGE,OAAOuD,EAAAiO,MAAA,CAAclI,CAAd,CANyB,CA1B9B,CAoCNrG,KAAMA,QAAQ,CAACM,CAAD,CAAU+F,CAAV,CAAgBtJ,CAAhB,CAAuB,CACnC,IAAInB,EAAW0E,CAAA1E,SACf,IAAIA,CAAJ,GAAiBgJ,EAAjB,EA7tCsBuvD,CA6tCtB,GAAmCv4D,CAAnC,EA3tCoBk0B,CA2tCpB,GAAuEl0B,CAAvE,CAIA,GADIw4D,CACA,CADiB7zD,CAAA,CAAU8F,CAAV,CACjB,CAAAuW,EAAA,CAAaw3C,CAAb,CAAJ,CACE,GAAIh1D,CAAA,CAAUrC,CAAV,CAAJ,CACQA,CAAN,EACEuD,CAAA,CAAQ+F,CAAR,CACA,CADgB,CAAA,CAChB,CAAA/F,CAAA8a,aAAA,CAAqB/U,CAArB,CAA2B+tD,CAA3B,CAFF,GAIE9zD,CAAA,CAAQ+F,CAAR,CACA,CADgB,CAAA,CAChB,CAAA/F,CAAA2zD,gBAAA,CAAwBG,CAAxB,CALF,CADF,KASE,OAAQ9zD,EAAA,CAAQ+F,CAAR,CAAD,EACEguD,CAAC/zD,CAAA2uB,WAAAqlC,aAAA,CAAgCjuD,CAAhC,CAADguD,EAA0Cz1D,CAA1Cy1D,WADF,CAEED,CAFF,CAGE/4D,CAbb,KAeO,IAAI+D,CAAA,CAAUrC,CAAV,CAAJ,CACLuD,CAAA8a,aAAA,CAAqB/U,CAArB,CAA2BtJ,CAA3B,CADK,KAEA,IAAIuD,CAAAwF,aAAJ,CAKL,MAFIyuD,EAEG,CAFGj0D,CAAAwF,aAAA,CAAqBO,CAArB,CAA2B,CAA3B,CAEH,CAAQ,IAAR,GAAAkuD,CAAA,CAAel5D,CAAf,CAA2Bk5D,CA5BD,CApC/B,CAoENx0D,KAAMA,QAAQ,CAACO,CAAD,CAAU+F,CAAV,CAAgBtJ,CAAhB,CAAuB,CACnC,GAAIqC,CAAA,CAAUrC,CAAV,CAAJ,CACEuD,CAAA,CAAQ+F,CAAR,CAAA,CAAgBtJ,CADlB,KAGE,OAAOuD,EAAA,CAAQ+F,CAAR,CAJ0B,CApE/B;AA4ENiwB,KAAO,QAAQ,EAAG,CAIhBk+B,QAASA,EAAO,CAACl0D,CAAD,CAAUvD,CAAV,CAAiB,CAC/B,GAAIoC,CAAA,CAAYpC,CAAZ,CAAJ,CAAwB,CACtB,IAAInB,EAAW0E,CAAA1E,SACf,OAAQA,EAAD,GAAcC,EAAd,EAAmCD,CAAnC,GAAgDgJ,EAAhD,CAAkEtE,CAAAyY,YAAlE,CAAwF,EAFzE,CAIxBzY,CAAAyY,YAAA,CAAsBhc,CALS,CAHjCy3D,CAAAC,IAAA,CAAc,EACd,OAAOD,EAFS,CAAZ,EA5EA,CAyFNzxD,IAAKA,QAAQ,CAACzC,CAAD,CAAUvD,CAAV,CAAiB,CAC5B,GAAIoC,CAAA,CAAYpC,CAAZ,CAAJ,CAAwB,CACtB,GAAIuD,CAAAo0D,SAAJ,EAA+C,QAA/C,GAAwBr0D,EAAA,CAAUC,CAAV,CAAxB,CAAyD,CACvD,IAAIqf,EAAS,EACb3jB,EAAA,CAAQsE,CAAAujB,QAAR,CAAyB,QAAQ,CAACpV,CAAD,CAAS,CACpCA,CAAAkmD,SAAJ,EACEh1C,CAAAte,KAAA,CAAYoN,CAAA1R,MAAZ,EAA4B0R,CAAA6nB,KAA5B,CAFsC,CAA1C,CAKA,OAAyB,EAAlB,GAAA3W,CAAAjkB,OAAA,CAAsB,IAAtB,CAA6BikB,CAPmB,CASzD,MAAOrf,EAAAvD,MAVe,CAYxBuD,CAAAvD,MAAA,CAAgBA,CAbY,CAzFxB,CAyGN4H,KAAMA,QAAQ,CAACrE,CAAD,CAAUvD,CAAV,CAAiB,CAC7B,GAAIoC,CAAA,CAAYpC,CAAZ,CAAJ,CACE,MAAOuD,EAAAoY,UAETe,GAAA,CAAanZ,CAAb,CAAsB,CAAA,CAAtB,CACAA,EAAAoY,UAAA,CAAoB3b,CALS,CAzGzB,CAiHNwH,MAAO0X,EAjHD,CAAR,CAkHG,QAAQ,CAACvZ,CAAD,CAAK2D,CAAL,CAAW,CAIpB4D,CAAA/K,UAAA,CAAiBmH,CAAjB,CAAA,CAAyB,QAAQ,CAAC0oC,CAAD,CAAOC,CAAP,CAAa,CAAA,IACxCpyC,CADwC,CACrCT,CADqC,CAExCy4D,EAAY,IAAAl5D,OAKhB,IAAIgH,CAAJ,GAAWuZ,EAAX,GACoB,CAAd,EAACvZ,CAAAhH,OAAD,EAAoBgH,CAApB,GAA2BsY,EAA3B,EAA6CtY,CAA7C,GAAoDgZ,EAApD;AAAyEqzB,CAAzE,CAAgFC,CADtF,IACgG3zC,CADhG,CAC4G,CAC1G,GAAIqC,CAAA,CAASqxC,CAAT,CAAJ,CAAoB,CAGlB,IAAKnyC,CAAL,CAAS,CAAT,CAAYA,CAAZ,CAAgBg4D,CAAhB,CAA2Bh4D,CAAA,EAA3B,CACE,GAAI8F,CAAJ,GAAWkY,EAAX,CAEElY,CAAA,CAAG,IAAA,CAAK9F,CAAL,CAAH,CAAYmyC,CAAZ,CAFF,KAIE,KAAK5yC,CAAL,GAAY4yC,EAAZ,CACErsC,CAAA,CAAG,IAAA,CAAK9F,CAAL,CAAH,CAAYT,CAAZ,CAAiB4yC,CAAA,CAAK5yC,CAAL,CAAjB,CAKN,OAAO,KAdW,CAkBdY,CAAAA,CAAQ2F,CAAA+xD,IAER72D,EAAAA,CAAMb,CAAD,GAAW1B,CAAX,CAAwBm5B,IAAAwyB,IAAA,CAAS4N,CAAT,CAAoB,CAApB,CAAxB,CAAiDA,CAC1D,KAASj3D,CAAT,CAAa,CAAb,CAAgBA,CAAhB,CAAoBC,CAApB,CAAwBD,CAAA,EAAxB,CAA6B,CAC3B,IAAIiuB,EAAYlpB,CAAA,CAAG,IAAA,CAAK/E,CAAL,CAAH,CAAYoxC,CAAZ,CAAkBC,CAAlB,CAChBjyC,EAAA,CAAQA,CAAA,CAAQA,CAAR,CAAgB6uB,CAAhB,CAA4BA,CAFT,CAI7B,MAAO7uB,EA1BiG,CA8B1G,IAAKH,CAAL,CAAS,CAAT,CAAYA,CAAZ,CAAgBg4D,CAAhB,CAA2Bh4D,CAAA,EAA3B,CACE8F,CAAA,CAAG,IAAA,CAAK9F,CAAL,CAAH,CAAYmyC,CAAZ,CAAkBC,CAAlB,CAGF,OAAO,KA1CmC,CAJ1B,CAlHtB,CA2NAhzC,EAAA,CAAQ,CACN+3D,WAAYp6C,EADN,CAGNxQ,GAAI0rD,QAASA,EAAQ,CAACv0D,CAAD,CAAU0Z,CAAV,CAAgBtX,CAAhB,CAAoBuX,CAApB,CAAiC,CACpD,GAAI7a,CAAA,CAAU6a,CAAV,CAAJ,CAA4B,KAAMd,GAAA,CAAa,QAAb,CAAN,CAG5B,GAAKvB,EAAA,CAAkBtX,CAAlB,CAAL,CAAA,CAIA,IAAI4Z,EAAeC,EAAA,CAAmB7Z,CAAnB,CAA4B,CAAA,CAA5B,CACfqJ,EAAAA,CAASuQ,CAAAvQ,OACb,KAAIyQ,EAASF,CAAAE,OAERA,EAAL,GACEA,CADF,CACWF,CAAAE,OADX,CACiC4C,EAAA,CAAmB1c,CAAnB,CAA4BqJ,CAA5B,CADjC,CAQA,KAHImrD,IAAAA,EAA6B,CAArB,EAAA96C,CAAArZ,QAAA,CAAa,GAAb,CAAA,CAAyBqZ,CAAA5Z,MAAA,CAAW,GAAX,CAAzB,CAA2C,CAAC4Z,CAAD,CAAnD86C,CACAl4D,EAAIk4D,CAAAp5D,OAER,CAAOkB,CAAA,EAAP,CAAA,CAAY,CACVod,CAAA,CAAO86C,CAAA,CAAMl4D,CAAN,CACP,KAAI0gB,EAAW3T,CAAA,CAAOqQ,CAAP,CAEVsD,EAAL,GACE3T,CAAA,CAAOqQ,CAAP,CAqBA,CArBe,EAqBf,CAnBa,YAAb,GAAIA,CAAJ,EAAsC,YAAtC;AAA6BA,CAA7B,CAKE66C,CAAA,CAASv0D,CAAT,CAAkB2yD,EAAA,CAAgBj5C,CAAhB,CAAlB,CAAyC,QAAQ,CAACkD,CAAD,CAAQ,CACvD,IAAmB63C,EAAU73C,CAAA83C,cAGxBD,EAAL,GAAiBA,CAAjB,GAHavnB,IAGb,EAHaA,IAG2BynB,SAAA,CAAgBF,CAAhB,CAAxC,GACE36C,CAAA,CAAO8C,CAAP,CAAclD,CAAd,CALqD,CAAzD,CALF,CAee,UAff,GAeMA,CAfN,EAgBuB1Z,CA9sBzB2iC,iBAAA,CA8sBkCjpB,CA9sBlC,CA8sBwCI,CA9sBxC,CAAmC,CAAA,CAAnC,CAitBE,CAAAkD,CAAA,CAAW3T,CAAA,CAAOqQ,CAAP,CAtBb,CAwBAsD,EAAAjc,KAAA,CAAcqB,CAAd,CA5BU,CAhBZ,CAJoD,CAHhD,CAuDN6jB,IAAKxM,EAvDC,CAyDNm7C,IAAKA,QAAQ,CAAC50D,CAAD,CAAU0Z,CAAV,CAAgBtX,CAAhB,CAAoB,CAC/BpC,CAAA,CAAU+D,CAAA,CAAO/D,CAAP,CAKVA,EAAA6I,GAAA,CAAW6Q,CAAX,CAAiBm7C,QAASA,EAAI,EAAG,CAC/B70D,CAAAimB,IAAA,CAAYvM,CAAZ,CAAkBtX,CAAlB,CACApC,EAAAimB,IAAA,CAAYvM,CAAZ,CAAkBm7C,CAAlB,CAF+B,CAAjC,CAIA70D,EAAA6I,GAAA,CAAW6Q,CAAX,CAAiBtX,CAAjB,CAV+B,CAzD3B,CAsENkxB,YAAaA,QAAQ,CAACtzB,CAAD,CAAU80D,CAAV,CAAuB,CAAA,IACtC10D,CADsC,CAC/BjC,EAAS6B,CAAAwb,WACpBrC,GAAA,CAAanZ,CAAb,CACAtE,EAAA,CAAQ,IAAIiO,CAAJ,CAAWmrD,CAAX,CAAR,CAAiC,QAAQ,CAACv1D,CAAD,CAAO,CAC1Ca,CAAJ,CACEjC,CAAA42D,aAAA,CAAoBx1D,CAApB,CAA0Ba,CAAAuK,YAA1B,CADF,CAGExM,CAAA25B,aAAA,CAAoBv4B,CAApB,CAA0BS,CAA1B,CAEFI,EAAA,CAAQb,CANsC,CAAhD,CAH0C,CAtEtC,CAmFNyvC,SAAUA,QAAQ,CAAChvC,CAAD,CAAU,CAC1B,IAAIgvC,EAAW,EACftzC,EAAA,CAAQsE,CAAAuY,WAAR,CAA4B,QAAQ,CAACvY,CAAD,CAAU,CACxCA,CAAA1E,SAAJ,GAAyBC,EAAzB,EACEyzC,CAAAjuC,KAAA,CAAcf,CAAd,CAF0C,CAA9C,CAKA,OAAOgvC,EAPmB,CAnFtB,CA6FNxb,SAAUA,QAAQ,CAACxzB,CAAD,CAAU,CAC1B,MAAOA,EAAAg1D,gBAAP;AAAkCh1D,CAAAuY,WAAlC,EAAwD,EAD9B,CA7FtB,CAiGNnU,OAAQA,QAAQ,CAACpE,CAAD,CAAUT,CAAV,CAAgB,CAC9B,IAAIjE,EAAW0E,CAAA1E,SACf,IAAIA,CAAJ,GAAiBC,EAAjB,EAj/C8BkgB,EAi/C9B,GAAsCngB,CAAtC,CAAA,CAEAiE,CAAA,CAAO,IAAIoK,CAAJ,CAAWpK,CAAX,CAEP,KAASjD,IAAAA,EAAI,CAAJA,CAAOa,EAAKoC,CAAAnE,OAArB,CAAkCkB,CAAlC,CAAsCa,CAAtC,CAA0Cb,CAAA,EAA1C,CAEE0D,CAAA6X,YAAA,CADYtY,CAAA+6C,CAAKh+C,CAALg+C,CACZ,CANF,CAF8B,CAjG1B,CA6GN2a,QAASA,QAAQ,CAACj1D,CAAD,CAAUT,CAAV,CAAgB,CAC/B,GAAIS,CAAA1E,SAAJ,GAAyBC,EAAzB,CAA4C,CAC1C,IAAI6E,EAAQJ,CAAAwY,WACZ9c,EAAA,CAAQ,IAAIiO,CAAJ,CAAWpK,CAAX,CAAR,CAA0B,QAAQ,CAAC+6C,CAAD,CAAQ,CACxCt6C,CAAA+0D,aAAA,CAAqBza,CAArB,CAA4Bl6C,CAA5B,CADwC,CAA1C,CAF0C,CADb,CA7G3B,CAsHN6X,KAAMA,QAAQ,CAACjY,CAAD,CAAUk1D,CAAV,CAAoB,CAChCA,CAAA,CAAWnxD,CAAA,CAAOmxD,CAAP,CAAAxa,GAAA,CAAoB,CAApB,CAAA12C,MAAA,EAAA,CAA+B,CAA/B,CACX,KAAI7F,EAAS6B,CAAAwb,WACTrd,EAAJ,EACEA,CAAA25B,aAAA,CAAoBo9B,CAApB,CAA8Bl1D,CAA9B,CAEFk1D,EAAAr9C,YAAA,CAAqB7X,CAArB,CANgC,CAtH5B,CA+HNgoB,OAAQnM,EA/HF,CAiINs5C,OAAQA,QAAQ,CAACn1D,CAAD,CAAU,CACxB6b,EAAA,CAAa7b,CAAb,CAAsB,CAAA,CAAtB,CADwB,CAjIpB,CAqINo1D,MAAOA,QAAQ,CAACp1D,CAAD,CAAUq1D,CAAV,CAAsB,CAAA,IAC/Bj1D,EAAQJ,CADuB,CACd7B,EAAS6B,CAAAwb,WAC9B65C,EAAA,CAAa,IAAI1rD,CAAJ,CAAW0rD,CAAX,CAEb,KAJmC,IAI1B/4D,EAAI,CAJsB,CAInBa,EAAKk4D,CAAAj6D,OAArB,CAAwCkB,CAAxC,CAA4Ca,CAA5C,CAAgDb,CAAA,EAAhD,CAAqD,CACnD,IAAIiD,EAAO81D,CAAA,CAAW/4D,CAAX,CACX6B,EAAA42D,aAAA,CAAoBx1D,CAApB;AAA0Ba,CAAAuK,YAA1B,CACAvK,EAAA,CAAQb,CAH2C,CAJlB,CArI/B,CAgJNse,SAAU7C,EAhJJ,CAiJN8C,YAAalD,EAjJP,CAmJN06C,YAAaA,QAAQ,CAACt1D,CAAD,CAAU2a,CAAV,CAAoB46C,CAApB,CAA+B,CAC9C56C,CAAJ,EACEjf,CAAA,CAAQif,CAAA7a,MAAA,CAAe,GAAf,CAAR,CAA6B,QAAQ,CAACkrB,CAAD,CAAY,CAC/C,IAAIwqC,EAAiBD,CACjB12D,EAAA,CAAY22D,CAAZ,CAAJ,GACEA,CADF,CACmB,CAAC96C,EAAA,CAAe1a,CAAf,CAAwBgrB,CAAxB,CADpB,CAGA,EAACwqC,CAAA,CAAiBx6C,EAAjB,CAAkCJ,EAAnC,EAAsD5a,CAAtD,CAA+DgrB,CAA/D,CAL+C,CAAjD,CAFgD,CAnJ9C,CA+JN7sB,OAAQA,QAAQ,CAAC6B,CAAD,CAAU,CAExB,MAAO,CADH7B,CACG,CADM6B,CAAAwb,WACN,GA/iDuBC,EA+iDvB,GAAUtd,CAAA7C,SAAV,CAA4D6C,CAA5D,CAAqE,IAFpD,CA/JpB,CAoKN4+C,KAAMA,QAAQ,CAAC/8C,CAAD,CAAU,CACtB,MAAOA,EAAAy1D,mBADe,CApKlB,CAwKN91D,KAAMA,QAAQ,CAACK,CAAD,CAAU2a,CAAV,CAAoB,CAChC,MAAI3a,EAAA01D,qBAAJ,CACS11D,CAAA01D,qBAAA,CAA6B/6C,CAA7B,CADT,CAGS,EAJuB,CAxK5B,CAgLN3W,MAAOiV,EAhLD,CAkLNvP,eAAgBA,QAAQ,CAAC1J,CAAD,CAAU4c,CAAV,CAAiB+4C,CAAjB,CAAkC,CAAA,IAEpDC,CAFoD,CAE1BC,CAF0B,CAGpD5Y,EAAYrgC,CAAAlD,KAAZujC,EAA0BrgC,CAH0B,CAIpDhD,EAAeC,EAAA,CAAmB7Z,CAAnB,CAInB,IAFIgd,CAEJ,EAHI3T,CAGJ,CAHauQ,CAGb,EAH6BA,CAAAvQ,OAG7B,GAFyBA,CAAA,CAAO4zC,CAAP,CAEzB,CAEE2Y,CAmBA,CAnBa,CACXxoB,eAAgBA,QAAQ,EAAG,CAAE,IAAArwB,iBAAA,CAAwB,CAAA,CAA1B,CADhB,CAEXF,mBAAoBA,QAAQ,EAAG,CAAE,MAAiC,CAAA,CAAjC;AAAO,IAAAE,iBAAT,CAFpB,CAGXK,yBAA0BA,QAAQ,EAAG,CAAE,IAAAF,4BAAA,CAAmC,CAAA,CAArC,CAH1B,CAIXK,8BAA+BA,QAAQ,EAAG,CAAE,MAA4C,CAAA,CAA5C,GAAO,IAAAL,4BAAT,CAJ/B,CAKXI,gBAAiBhf,CALN,CAMXob,KAAMujC,CANK,CAOX/P,OAAQltC,CAPG,CAmBb,CARI4c,CAAAlD,KAQJ,GAPEk8C,CAOF,CAPej4D,CAAA,CAAOi4D,CAAP,CAAmBh5C,CAAnB,CAOf,EAHAk5C,CAGA,CAHex0D,EAAA,CAAY0b,CAAZ,CAGf,CAFA64C,CAEA,CAFcF,CAAA,CAAkB,CAACC,CAAD,CAAA7zD,OAAA,CAAoB4zD,CAApB,CAAlB,CAAyD,CAACC,CAAD,CAEvE,CAAAl6D,CAAA,CAAQo6D,CAAR,CAAsB,QAAQ,CAAC1zD,CAAD,CAAK,CAC5BwzD,CAAAr4C,8BAAA,EAAL,EACEnb,CAAAG,MAAA,CAASvC,CAAT,CAAkB61D,CAAlB,CAF+B,CAAnC,CA7BsD,CAlLpD,CAAR,CAsNG,QAAQ,CAACzzD,CAAD,CAAK2D,CAAL,CAAW,CAIpB4D,CAAA/K,UAAA,CAAiBmH,CAAjB,CAAA,CAAyB,QAAQ,CAAC0oC,CAAD,CAAOC,CAAP,CAAaqnB,CAAb,CAAmB,CAGlD,IAFA,IAAIt5D,CAAJ,CAESH,EAAI,CAFb,CAEgBa,EAAK,IAAA/B,OAArB,CAAkCkB,CAAlC,CAAsCa,CAAtC,CAA0Cb,CAAA,EAA1C,CACMuC,CAAA,CAAYpC,CAAZ,CAAJ,EACEA,CACA,CADQ2F,CAAA,CAAG,IAAA,CAAK9F,CAAL,CAAH,CAAYmyC,CAAZ,CAAkBC,CAAlB,CAAwBqnB,CAAxB,CACR,CAAIj3D,CAAA,CAAUrC,CAAV,CAAJ,GAEEA,CAFF,CAEUsH,CAAA,CAAOtH,CAAP,CAFV,CAFF,EAOEuc,EAAA,CAAevc,CAAf,CAAsB2F,CAAA,CAAG,IAAA,CAAK9F,CAAL,CAAH,CAAYmyC,CAAZ,CAAkBC,CAAlB,CAAwBqnB,CAAxB,CAAtB,CAGJ,OAAOj3D,EAAA,CAAUrC,CAAV,CAAA,CAAmBA,CAAnB,CAA2B,IAdgB,CAkBpDkN,EAAA/K,UAAAsD,KAAA;AAAwByH,CAAA/K,UAAAiK,GACxBc,EAAA/K,UAAAo3D,OAAA,CAA0BrsD,CAAA/K,UAAAqnB,IAvBN,CAtNtB,CAiTA/H,GAAAtf,UAAA,CAAoB,CAMlByf,IAAKA,QAAQ,CAACxiB,CAAD,CAAMY,CAAN,CAAa,CACxB,IAAA,CAAKshB,EAAA,CAAQliB,CAAR,CAAa,IAAAa,QAAb,CAAL,CAAA,CAAmCD,CADX,CANR,CAclBuL,IAAKA,QAAQ,CAACnM,CAAD,CAAM,CACjB,MAAO,KAAA,CAAKkiB,EAAA,CAAQliB,CAAR,CAAa,IAAAa,QAAb,CAAL,CADU,CAdD,CAsBlBsrB,OAAQA,QAAQ,CAACnsB,CAAD,CAAM,CACpB,IAAIY,EAAQ,IAAA,CAAKZ,CAAL,CAAWkiB,EAAA,CAAQliB,CAAR,CAAa,IAAAa,QAAb,CAAX,CACZ,QAAO,IAAA,CAAKb,CAAL,CACP,OAAOY,EAHa,CAtBJ,CA6BpB,KAAIoa,GAAoB,CAAC,QAAQ,EAAG,CAClC,IAAA4G,KAAA,CAAY,CAAC,QAAQ,EAAG,CACtB,MAAOS,GADe,CAAZ,CADsB,CAAZ,CAAxB,CAoEIQ,GAAU,oCApEd,CAqEIu3C,GAAe,GArEnB,CAsEIC,GAAS,sBAtEb,CAuEIz3C,GAAiB,kCAvErB,CAwEI1T,GAAkB/P,CAAA,CAAO,WAAP,CA8wBtB6L,GAAA6Z,WAAA,CAjwBAI,QAAiB,CAAC1e,CAAD,CAAK+D,CAAL,CAAeJ,CAAf,CAAqB,CAAA,IAChC0a,CAKJ,IAAkB,UAAlB,GAAI,MAAOre,EAAX,CACE,IAAM,EAAAqe,CAAA,CAAUre,CAAAqe,QAAV,CAAN,CAA6B,CAC3BA,CAAA;AAAU,EACV,IAAIre,CAAAhH,OAAJ,CAAe,CACb,GAAI+K,CAAJ,CAIE,KAHK3K,EAAA,CAASuK,CAAT,CAGC,EAHkBA,CAGlB,GAFJA,CAEI,CAFG3D,CAAA2D,KAEH,EAFcuY,EAAA,CAAOlc,CAAP,CAEd,EAAA2I,EAAA,CAAgB,UAAhB,CACyEhF,CADzE,CAAN,CAGFyY,CAAA,CAASpc,CAAAzD,SAAA,EAAA4F,QAAA,CAAsBka,EAAtB,CAAsC,EAAtC,CACT03C,EAAA,CAAU33C,CAAArd,MAAA,CAAaud,EAAb,CACVhjB,EAAA,CAAQy6D,CAAA,CAAQ,CAAR,CAAAr2D,MAAA,CAAiBm2D,EAAjB,CAAR,CAAwC,QAAQ,CAACpsD,CAAD,CAAM,CACpDA,CAAAtF,QAAA,CAAY2xD,EAAZ,CAAoB,QAAQ,CAAClf,CAAD,CAAMof,CAAN,CAAkBrwD,CAAlB,CAAwB,CAClD0a,CAAA1f,KAAA,CAAagF,CAAb,CADkD,CAApD,CADoD,CAAtD,CAVa,CAgBf3D,CAAAqe,QAAA,CAAaA,CAlBc,CAA7B,CADF,IAqBWhlB,EAAA,CAAQ2G,CAAR,CAAJ,EACLq4C,CAEA,CAFOr4C,CAAAhH,OAEP,CAFmB,CAEnB,CADA2O,EAAA,CAAY3H,CAAA,CAAGq4C,CAAH,CAAZ,CAAsB,IAAtB,CACA,CAAAh6B,CAAA,CAAUre,CAAAxE,MAAA,CAAS,CAAT,CAAY68C,CAAZ,CAHL,EAKL1wC,EAAA,CAAY3H,CAAZ,CAAgB,IAAhB,CAAsB,CAAA,CAAtB,CAEF,OAAOqe,EAlC6B,CAkhCtC,KAAI41C,GAAiBr7D,CAAA,CAAO,UAAP,CAArB,CAqDImY,GAA8BA,QAAQ,EAAG,CAC3C,IAAAsK,KAAA,CAAY,CAAC,IAAD,CAAO,OAAP,CAAgB,QAAQ,CAACrI,CAAD,CAAKoB,CAAL,CAAY,CAC9C8/C,QAASA,EAAa,EAAG,EACzBA,CAAAtf,IAAA,CAAoB14C,CACpBg4D,EAAA92B,MAAA,CAAsBlhC,CACtBg4D,EAAA13D,UAAA,CAA0B,CACxB23D,IAAKj4D,CADmB,CAExBmoB,OAAQnoB,CAFgB,CAGxBk4D,OAAQl4D,CAHgB,CAIxBm4D,MAAOn4D,CAJiB,CAKxBo4D,SAAUp4D,CALc,CAMxB42B,KAAMA,QAAQ,CAACyhC,CAAD,CAAOC,CAAP,CAAa,CACzB,MAAOxhD,EAAA,CAAG,QAAQ,CAAC6rB,CAAD,CAAU,CAC1BzqB,CAAA,CAAM,QAAQ,EAAG,CACfyqB,CAAA,EADe,CAAjB,CAD0B,CAArB,CAAA/L,KAAA,CAICyhC,CAJD;AAIOC,CAJP,CADkB,CANH,CAc1B,OAAON,EAlBuC,CAApC,CAD+B,CArD7C,CA8EIrjD,GAA6BA,QAAQ,EAAG,CAC1C,IAAI+pC,EAAkB,IAAI9+B,EAA1B,CACI24C,EAAqB,EAEzB,KAAAp5C,KAAA,CAAY,CAAC,iBAAD,CAAoB,YAApB,CACP,QAAQ,CAACvK,CAAD,CAAoBgC,CAApB,CAAgC,CAsB3C4hD,QAASA,EAA0B,CAAC92D,CAAD,CAAU+2D,CAAV,CAAe/uC,CAAf,CAAuB,CACxD,IAAI7gB,EAAO61C,CAAAh1C,IAAA,CAAoBhI,CAApB,CAGNmH,EAAL,GACE61C,CAAA3+B,IAAA,CAAoBre,CAApB,CAA6BmH,CAA7B,CAAoC,EAApC,CACA,CAAA0vD,CAAA91D,KAAA,CAAwBf,CAAxB,CAFF,CAKI+2D,EAAJ,EACEr7D,CAAA,CAAQq7D,CAAAj3D,MAAA,CAAU,GAAV,CAAR,CAAwB,QAAQ,CAACkrB,CAAD,CAAY,CACtCA,CAAJ,GACE7jB,CAAA,CAAK6jB,CAAL,CADF,CACoB,CAAA,CADpB,CAD0C,CAA5C,CAOEhD,EAAJ,EACEtsB,CAAA,CAAQssB,CAAAloB,MAAA,CAAa,GAAb,CAAR,CAA2B,QAAQ,CAACkrB,CAAD,CAAY,CACzCA,CAAJ,GACE7jB,CAAA,CAAK6jB,CAAL,CADF,CACoB,CAAA,CADpB,CAD6C,CAA/C,CAO8B,EAAhC,CAAI6rC,CAAAz7D,OAAJ,EAEA8Z,CAAA0+B,aAAA,CAAwB,QAAQ,EAAG,CACjCl4C,CAAA,CAAQm7D,CAAR,CAA4B,QAAQ,CAAC72D,CAAD,CAAU,CAC5C,IAAImH,EAAO61C,CAAAh1C,IAAA,CAAoBhI,CAApB,CACX,IAAImH,CAAJ,CAAU,CACR,IAAI6vD,EAAW5zC,EAAA,CAAapjB,CAAAN,KAAA,CAAa,OAAb,CAAb,CAAf,CACI85B,EAAQ,EADZ,CAEIE,EAAW,EACfh+B,EAAA,CAAQyL,CAAR,CAAc,QAAQ,CAACs2B,CAAD,CAASzS,CAAT,CAAoB,CAEpCyS,CAAJ,GADe9f,CAAE,CAAAq5C,CAAA,CAAShsC,CAAT,CACjB,GACMyS,CAAJ,CACEjE,CADF,GACYA,CAAAp+B,OAAA,CAAe,GAAf,CAAqB,EADjC,EACuC4vB,CADvC,CAGE0O,CAHF,GAGeA,CAAAt+B,OAAA,CAAkB,GAAlB,CAAwB,EAHvC,EAG6C4vB,CAJ/C,CAFwC,CAA1C,CAWAtvB,EAAA,CAAQsE,CAAR,CAAiB,QAAQ,CAAC2iB,CAAD,CAAM,CAC7B6W,CAAA,EAAYxe,EAAA,CAAe2H,CAAf,CAAoB6W,CAApB,CACZE,EAAA,EAAY9e,EAAA,CAAkB+H,CAAlB,CAAuB+W,CAAvB,CAFiB,CAA/B,CAIAsjB,EAAAh1B,OAAA,CAAuBhoB,CAAvB,CAnBQ,CAFkC,CAA9C,CAyBA62D;CAAAz7D,OAAA,CAA4B,CA1BK,CAAnC,CA3BwD,CArB1D,MAAO,CACLyvB,QAASvsB,CADJ,CAELuK,GAAIvK,CAFC,CAGL2nB,IAAK3nB,CAHA,CAIL24D,IAAK34D,CAJA,CAMLyC,KAAMA,QAAQ,CAACf,CAAD,CAAU4c,CAAV,CAAiB2G,CAAjB,CAA0B2zC,CAA1B,CAAwC,CACpDA,CAAA,EAAuBA,CAAA,EAEvB3zC,EAAA,CAAUA,CAAV,EAAqB,EACrBA,EAAA4zC,KAAA,EAAuBn3D,CAAA4zD,IAAA,CAAYrwC,CAAA4zC,KAAZ,CACvB5zC,EAAA6zC,GAAA,EAAuBp3D,CAAA4zD,IAAA,CAAYrwC,CAAA6zC,GAAZ,CAEvB,EAAI7zC,CAAA1F,SAAJ,EAAwB0F,CAAAzF,YAAxB,GACEg5C,CAAA,CAA2B92D,CAA3B,CAAoCujB,CAAA1F,SAApC,CAAsD0F,CAAAzF,YAAtD,CAGF,OAAO,KAAI5K,CAXyC,CANjD,CADoC,CADjC,CAJ8B,CA9E5C,CAgLIH,GAAmB,CAAC,UAAD,CAAa,QAAQ,CAACrM,CAAD,CAAW,CACrD,IAAI0E,EAAW,IAEf,KAAAisD,uBAAA,CAA8Bh8D,MAAAgD,OAAA,CAAc,IAAd,CAyC9B,KAAAg9B,SAAA,CAAgBC,QAAQ,CAACv1B,CAAD,CAAO+E,CAAP,CAAgB,CACtC,GAAI/E,CAAJ,EAA+B,GAA/B,GAAYA,CAAAxE,OAAA,CAAY,CAAZ,CAAZ,CACE,KAAM80D,GAAA,CAAe,SAAf,CAAmFtwD,CAAnF,CAAN,CAGF,IAAIlK,EAAMkK,CAANlK,CAAa,YACjBuP,EAAAisD,uBAAA,CAAgCtxD,CAAA2f,OAAA,CAAY,CAAZ,CAAhC,CAAA,CAAkD7pB,CAClD6K,EAAAoE,QAAA,CAAiBjP,CAAjB,CAAsBiP,CAAtB,CAPsC,CAwBxC,KAAAwsD,gBAAA,CAAuBC,QAAQ,CAAC77B,CAAD,CAAa,CAC1C,GAAyB,CAAzB,GAAI79B,SAAAzC,OAAJ,GACE,IAAAo8D,kBADF;AAC4B97B,CAAD,WAAuBx6B,OAAvB,CAAiCw6B,CAAjC,CAA8C,IADzE,GAGwB+7B,4BAChB32D,KAAA,CAAmB,IAAA02D,kBAAA74D,SAAA,EAAnB,CAJR,CAKM,KAAM03D,GAAA,CAAe,SAAf,CAxPWqB,YAwPX,CAAN,CAKN,MAAO,KAAAF,kBAXmC,CAc5C,KAAA/5C,KAAA,CAAY,CAAC,gBAAD,CAAmB,QAAQ,CAACzK,CAAD,CAAiB,CACtD2kD,QAASA,EAAS,CAAC33D,CAAD,CAAU43D,CAAV,CAAyBC,CAAzB,CAAuC,CAIvD,GAAIA,CAAJ,CAAkB,CAChB,IAAIC,CA3PyB,EAAA,CAAA,CACnC,IAASx7D,CAAT,CAAa,CAAb,CAAgBA,CAAhB,CA0PyCu7D,CA1PrBz8D,OAApB,CAAoCkB,CAAA,EAApC,CAAyC,CACvC,IAAIqmB,EAyPmCk1C,CAzP7B,CAAQv7D,CAAR,CACV,IAfey7D,CAef,GAAIp1C,CAAArnB,SAAJ,CAAmC,CACjC,CAAA,CAAOqnB,CAAP,OAAA,CADiC,CAFI,CADN,CAAA,CAAA,IAAA,EAAA,CA4PzBm1C,CAAAA,CAAJ,EAAkBA,CAAAt8C,WAAlB,EAA2Cs8C,CAAAE,uBAA3C,GACEH,CADF,CACiB,IADjB,CAFgB,CAMlBA,CAAA,CAAeA,CAAAzC,MAAA,CAAmBp1D,CAAnB,CAAf,CAA6C43D,CAAA3C,QAAA,CAAsBj1D,CAAtB,CAVU,CAgCzD,MAAO,CA8BL6I,GAAImK,CAAAnK,GA9BC,CAwDLod,IAAKjT,CAAAiT,IAxDA,CA0ELgxC,IAAKjkD,CAAAikD,IA1EA,CAyGLpsC,QAAS7X,CAAA6X,QAzGJ,CAmHLpE,OAAQA,QAAQ,CAACwxC,CAAD,CAAS,CACvBA,CAAA1B,IAAA,EAAc0B,CAAA1B,IAAA,EADS,CAnHpB,CAyIL2B,MAAOA,QAAQ,CAACl4D,CAAD,CAAU7B,CAAV,CAAkBi3D,CAAlB,CAAyB7xC,CAAzB,CAAkC,CAC/CplB,CAAA;AAASA,CAAT,EAAmB4F,CAAA,CAAO5F,CAAP,CACnBi3D,EAAA,CAAQA,CAAR,EAAiBrxD,CAAA,CAAOqxD,CAAP,CACjBj3D,EAAA,CAASA,CAAT,EAAmBi3D,CAAAj3D,OAAA,EACnBw5D,EAAA,CAAU33D,CAAV,CAAmB7B,CAAnB,CAA2Bi3D,CAA3B,CACA,OAAOpiD,EAAAjS,KAAA,CAAoBf,CAApB,CAA6B,OAA7B,CAAsCsjB,EAAA,CAAsBC,CAAtB,CAAtC,CALwC,CAzI5C,CAmKL40C,KAAMA,QAAQ,CAACn4D,CAAD,CAAU7B,CAAV,CAAkBi3D,CAAlB,CAAyB7xC,CAAzB,CAAkC,CAC9CplB,CAAA,CAASA,CAAT,EAAmB4F,CAAA,CAAO5F,CAAP,CACnBi3D,EAAA,CAAQA,CAAR,EAAiBrxD,CAAA,CAAOqxD,CAAP,CACjBj3D,EAAA,CAASA,CAAT,EAAmBi3D,CAAAj3D,OAAA,EACnBw5D,EAAA,CAAU33D,CAAV,CAAmB7B,CAAnB,CAA2Bi3D,CAA3B,CACA,OAAOpiD,EAAAjS,KAAA,CAAoBf,CAApB,CAA6B,MAA7B,CAAqCsjB,EAAA,CAAsBC,CAAtB,CAArC,CALuC,CAnK3C,CAwLL60C,MAAOA,QAAQ,CAACp4D,CAAD,CAAUujB,CAAV,CAAmB,CAChC,MAAOvQ,EAAAjS,KAAA,CAAoBf,CAApB,CAA6B,OAA7B,CAAsCsjB,EAAA,CAAsBC,CAAtB,CAAtC,CAAsE,QAAQ,EAAG,CACtFvjB,CAAAgoB,OAAA,EADsF,CAAjF,CADyB,CAxL7B,CAgNLnK,SAAUA,QAAQ,CAAC7d,CAAD,CAAUgrB,CAAV,CAAqBzH,CAArB,CAA8B,CAC9CA,CAAA,CAAUD,EAAA,CAAsBC,CAAtB,CACVA,EAAA1F,SAAA,CAAmBqF,EAAA,CAAaK,CAAA80C,SAAb,CAA+BrtC,CAA/B,CACnB,OAAOhY,EAAAjS,KAAA,CAAoBf,CAApB,CAA6B,UAA7B,CAAyCujB,CAAzC,CAHuC,CAhN3C,CAwOLzF,YAAaA,QAAQ,CAAC9d,CAAD,CAAUgrB,CAAV,CAAqBzH,CAArB,CAA8B,CACjDA,CAAA,CAAUD,EAAA,CAAsBC,CAAtB,CACVA,EAAAzF,YAAA,CAAsBoF,EAAA,CAAaK,CAAAzF,YAAb,CAAkCkN,CAAlC,CACtB,OAAOhY,EAAAjS,KAAA,CAAoBf,CAApB,CAA6B,aAA7B,CAA4CujB,CAA5C,CAH0C,CAxO9C,CAiQLkpC,SAAUA,QAAQ,CAACzsD,CAAD,CAAU+2D,CAAV,CAAe/uC,CAAf,CAAuBzE,CAAvB,CAAgC,CAChDA,CAAA,CAAUD,EAAA,CAAsBC,CAAtB,CACVA,EAAA1F,SAAA,CAAmBqF,EAAA,CAAaK,CAAA1F,SAAb;AAA+Bk5C,CAA/B,CACnBxzC,EAAAzF,YAAA,CAAsBoF,EAAA,CAAaK,CAAAzF,YAAb,CAAkCkK,CAAlC,CACtB,OAAOhV,EAAAjS,KAAA,CAAoBf,CAApB,CAA6B,UAA7B,CAAyCujB,CAAzC,CAJyC,CAjQ7C,CA6RL+0C,QAASA,QAAQ,CAACt4D,CAAD,CAAUm3D,CAAV,CAAgBC,CAAhB,CAAoBpsC,CAApB,CAA+BzH,CAA/B,CAAwC,CACvDA,CAAA,CAAUD,EAAA,CAAsBC,CAAtB,CACVA,EAAA4zC,KAAA,CAAe5zC,CAAA4zC,KAAA,CAAex5D,CAAA,CAAO4lB,CAAA4zC,KAAP,CAAqBA,CAArB,CAAf,CAA4CA,CAC3D5zC,EAAA6zC,GAAA,CAAe7zC,CAAA6zC,GAAA,CAAez5D,CAAA,CAAO4lB,CAAA6zC,GAAP,CAAmBA,CAAnB,CAAf,CAA4CA,CAG3D7zC,EAAAg1C,YAAA,CAAsBr1C,EAAA,CAAaK,CAAAg1C,YAAb,CADVvtC,CACU,EADG,mBACH,CACtB,OAAOhY,EAAAjS,KAAA,CAAoBf,CAApB,CAA6B,SAA7B,CAAwCujB,CAAxC,CAPgD,CA7RpD,CAjC+C,CAA5C,CAlFyC,CAAhC,CAhLvB,CAmhEIuF,GAAiB9tB,CAAA,CAAO,UAAP,CAQrBqS,GAAAoT,QAAA,CAA2B,CAAC,UAAD,CAAa,uBAAb,CAm5D3B,KAAIuO,GAAgB,uBAApB,CAsGI6M,GAAoB7gC,CAAA,CAAO,aAAP,CAtGxB,CAyGIovB,GAAY,yBAzGhB,CAgWIouC,GAAmB,kBAhWvB,CAiWIx6B,GAAgC,CAAC,eAAgBw6B,EAAhB,CAAmC,gBAApC,CAjWpC,CAkWIx7B,GAAa,eAlWjB,CAmWIC,GAAY,CACd,IAAK,IADS,CAEd,IAAK,IAFS,CAnWhB,CAuWIJ,GAAyB,cAvW7B;AAwxDIyH,GAAqBh9B,EAAAg9B,mBAArBA,CAAkDtpC,CAAA,CAAO,cAAP,CACtDspC,GAAAS,cAAA,CAAmC0zB,QAAQ,CAACziC,CAAD,CAAO,CAChD,KAAMsO,GAAA,CAAmB,UAAnB,CAGsDtO,CAHtD,CAAN,CADgD,CAOlDsO,GAAAC,OAAA,CAA4Bm0B,QAAQ,CAAC1iC,CAAD,CAAO1V,CAAP,CAAY,CAC9C,MAAOgkB,GAAA,CAAmB,QAAnB,CAA4DtO,CAA5D,CAAkE1V,CAAA3hB,SAAA,EAAlE,CADuC,CAp1UT,KAw7VnCg6D,GAAa,iCAx7VsB,CAy7VnC3vB,GAAgB,CAAC,KAAQ,EAAT,CAAa,MAAS,GAAtB,CAA2B,IAAO,EAAlC,CAz7VmB,CA07VnCuB,GAAkBvvC,CAAA,CAAO,WAAP,CA17ViB,CA4vWnC49D,GAAoB,CAMtB1uB,QAAS,CAAA,CANa,CAYtByD,UAAW,CAAA,CAZW,CAiCtBlB,OAAQf,EAAA,CAAe,UAAf,CAjCc,CAwDtBpnB,IAAKA,QAAQ,CAACA,CAAD,CAAM,CACjB,GAAIzlB,CAAA,CAAYylB,CAAZ,CAAJ,CACE,MAAO,KAAAomB,MAGT,KAAIvpC,EAAQw3D,EAAA3gD,KAAA,CAAgBsM,CAAhB,CACZ,EAAInjB,CAAA,CAAM,CAAN,CAAJ,EAAwB,EAAxB,GAAgBmjB,CAAhB,GAA4B,IAAAna,KAAA,CAAU1F,kBAAA,CAAmBtD,CAAA,CAAM,CAAN,CAAnB,CAAV,CAC5B,EAAIA,CAAA,CAAM,CAAN,CAAJ,EAAgBA,CAAA,CAAM,CAAN,CAAhB,EAAoC,EAApC,GAA4BmjB,CAA5B,GAAwC,IAAAilB,OAAA,CAAYpoC,CAAA,CAAM,CAAN,CAAZ,EAAwB,EAAxB,CACxC,KAAAuhB,KAAA,CAAUvhB,CAAA,CAAM,CAAN,CAAV,EAAsB,EAAtB,CAEA,OAAO,KAVU,CAxDG,CAuFtBoiC,SAAUmI,EAAA,CAAe,YAAf,CAvFY;AAmHtBhwB,KAAMgwB,EAAA,CAAe,QAAf,CAnHgB,CAuItB3C,KAAM2C,EAAA,CAAe,QAAf,CAvIgB,CAiKtBvhC,KAAMyhC,EAAA,CAAqB,QAArB,CAA+B,QAAQ,CAACzhC,CAAD,CAAO,CAClDA,CAAA,CAAgB,IAAT,GAAAA,CAAA,CAAgBA,CAAAxL,SAAA,EAAhB,CAAkC,EACzC,OAAyB,GAAlB,EAAAwL,CAAA5I,OAAA,CAAY,CAAZ,CAAA,CAAwB4I,CAAxB,CAA+B,GAA/B,CAAqCA,CAFM,CAA9C,CAjKgB,CAmNtBo/B,OAAQA,QAAQ,CAACA,CAAD,CAASsvB,CAAT,CAAqB,CACnC,OAAQh7D,SAAAzC,OAAR,EACE,KAAK,CAAL,CACE,MAAO,KAAAkuC,SACT,MAAK,CAAL,CACE,GAAI9tC,CAAA,CAAS+tC,CAAT,CAAJ,EAAwBvqC,CAAA,CAASuqC,CAAT,CAAxB,CACEA,CACA,CADSA,CAAA5qC,SAAA,EACT,CAAA,IAAA2qC,SAAA,CAAgB5kC,EAAA,CAAc6kC,CAAd,CAFlB,KAGO,IAAInsC,CAAA,CAASmsC,CAAT,CAAJ,CACLA,CAMA,CANShpC,EAAA,CAAKgpC,CAAL,CAAa,EAAb,CAMT,CAJA7tC,CAAA,CAAQ6tC,CAAR,CAAgB,QAAQ,CAAC9sC,CAAD,CAAQZ,CAAR,CAAa,CACtB,IAAb,EAAIY,CAAJ,EAAmB,OAAO8sC,CAAA,CAAO1tC,CAAP,CADS,CAArC,CAIA,CAAA,IAAAytC,SAAA,CAAgBC,CAPX,KASL,MAAMgB,GAAA,CAAgB,UAAhB,CAAN,CAGF,KACF,SACM1rC,CAAA,CAAYg6D,CAAZ,CAAJ,EAA8C,IAA9C,GAA+BA,CAA/B,CACE,OAAO,IAAAvvB,SAAA,CAAcC,CAAd,CADT,CAGE,IAAAD,SAAA,CAAcC,CAAd,CAHF,CAG0BsvB,CAxB9B,CA4BA,IAAAruB,UAAA,EACA,OAAO,KA9B4B,CAnNf,CAyQtB9nB,KAAMkpB,EAAA,CAAqB,QAArB,CAA+B,QAAQ,CAAClpB,CAAD,CAAO,CAClD,MAAgB,KAAT;AAAAA,CAAA,CAAgBA,CAAA/jB,SAAA,EAAhB,CAAkC,EADS,CAA9C,CAzQgB,CAqRtB4F,QAASA,QAAQ,EAAG,CAClB,IAAAopC,UAAA,CAAiB,CAAA,CACjB,OAAO,KAFW,CArRE,CA2RxBjyC,EAAA,CAAQ,CAAC+vC,EAAD,CAA6BP,EAA7B,CAAkDnB,EAAlD,CAAR,CAA6E,QAAQ,CAAC+uB,CAAD,CAAW,CAC9FA,CAAAl6D,UAAA,CAAqBvD,MAAAgD,OAAA,CAAcu6D,EAAd,CAqBrBE,EAAAl6D,UAAAslB,MAAA,CAA2B60C,QAAQ,CAAC70C,CAAD,CAAQ,CACzC,GAAK9oB,CAAAyC,SAAAzC,OAAL,CACE,MAAO,KAAAkxC,QAGT,IAAIwsB,CAAJ,GAAiB/uB,EAAjB,EAAsCG,CAAA,IAAAA,QAAtC,CACE,KAAMK,GAAA,CAAgB,SAAhB,CAAN,CAMF,IAAA+B,QAAA,CAAeztC,CAAA,CAAYqlB,CAAZ,CAAA,CAAqB,IAArB,CAA4BA,CAE3C,OAAO,KAdkC,CAtBmD,CAAhG,CAqiBA,KAAI4qB,GAAe9zC,CAAA,CAAO,QAAP,CAAnB,CAgEIk0C,GAAOgjB,QAAAtzD,UAAA5C,KAhEX,CAiEImzC,GAAQ+iB,QAAAtzD,UAAA2D,MAjEZ,CAkEI6sC,GAAO8iB,QAAAtzD,UAAAsD,KAlEX,CAkFI82D,GAAYl3D,EAAA,EAChBpG,EAAA,CAAQ,+CAAA,MAAA,CAAA,GAAA,CAAR,CAAoE,QAAQ,CAACg2C,CAAD,CAAW,CAAEsnB,EAAA,CAAUtnB,CAAV,CAAA,CAAsB,CAAA,CAAxB,CAAvF,CACA,KAAIunB,GAAS,CAAC,EAAI,IAAL,CAAW,EAAI,IAAf,CAAqB,EAAI,IAAzB;AAA+B,EAAI,IAAnC,CAAyC,EAAI,IAA7C,CAAmD,IAAI,GAAvD,CAA4D,IAAI,GAAhE,CAAb,CASIlkB,GAAQA,QAAQ,CAACxxB,CAAD,CAAU,CAC5B,IAAAA,QAAA,CAAeA,CADa,CAI9BwxB,GAAAn2C,UAAA,CAAkB,CAChBoC,YAAa+zC,EADG,CAGhBmkB,IAAKA,QAAQ,CAACljC,CAAD,CAAO,CAClB,IAAAA,KAAA,CAAYA,CACZ,KAAA51B,MAAA,CAAa,CAGb,KAFA,IAAA+4D,OAEA,CAFc,EAEd,CAAO,IAAA/4D,MAAP,CAAoB,IAAA41B,KAAA56B,OAApB,CAAA,CAEE,GADI2oC,CACA,CADK,IAAA/N,KAAAz0B,OAAA,CAAiB,IAAAnB,MAAjB,CACL,CAAO,GAAP,GAAA2jC,CAAA,EAAqB,GAArB,GAAcA,CAAlB,CACE,IAAAq1B,WAAA,CAAgBr1B,CAAhB,CADF,KAEO,IAAI,IAAA/kC,SAAA,CAAc+kC,CAAd,CAAJ,EAAgC,GAAhC,GAAyBA,CAAzB,EAAuC,IAAA/kC,SAAA,CAAc,IAAAq6D,KAAA,EAAd,CAAvC,CACL,IAAAC,WAAA,EADK,KAEA,IAAI,IAAAC,QAAA,CAAax1B,CAAb,CAAJ,CACL,IAAAy1B,UAAA,EADK,KAEA,IAAI,IAAAC,GAAA,CAAQ11B,CAAR,CAAY,aAAZ,CAAJ,CACL,IAAAo1B,OAAAp4D,KAAA,CAAiB,CAACX,MAAO,IAAAA,MAAR,CAAoB41B,KAAM+N,CAA1B,CAAjB,CACA,CAAA,IAAA3jC,MAAA,EAFK,KAGA,IAAI,IAAAs5D,aAAA,CAAkB31B,CAAlB,CAAJ,CACL,IAAA3jC,MAAA,EADK;IAEA,CACL,IAAIu5D,EAAM51B,CAAN41B,CAAW,IAAAN,KAAA,EAAf,CACIO,EAAMD,CAANC,CAAY,IAAAP,KAAA,CAAU,CAAV,CADhB,CAGIQ,EAAMb,EAAA,CAAUW,CAAV,CAHV,CAIIG,EAAMd,EAAA,CAAUY,CAAV,CAFAZ,GAAAe,CAAUh2B,CAAVg2B,CAGV,EAAWF,CAAX,EAAkBC,CAAlB,EACM5+B,CAEJ,CAFY4+B,CAAA,CAAMF,CAAN,CAAaC,CAAA,CAAMF,CAAN,CAAY51B,CAErC,CADA,IAAAo1B,OAAAp4D,KAAA,CAAiB,CAACX,MAAO,IAAAA,MAAR,CAAoB41B,KAAMkF,CAA1B,CAAiCwW,SAAU,CAAA,CAA3C,CAAjB,CACA,CAAA,IAAAtxC,MAAA,EAAc86B,CAAA9/B,OAHhB,EAKE,IAAA4+D,WAAA,CAAgB,4BAAhB,CAA8C,IAAA55D,MAA9C,CAA0D,IAAAA,MAA1D,CAAuE,CAAvE,CAXG,CAeT,MAAO,KAAA+4D,OAjCW,CAHJ,CAuChBM,GAAIA,QAAQ,CAAC11B,CAAD,CAAKk2B,CAAL,CAAY,CACtB,MAA8B,EAA9B,GAAOA,CAAA55D,QAAA,CAAc0jC,CAAd,CADe,CAvCR,CA2ChBs1B,KAAMA,QAAQ,CAAC/8D,CAAD,CAAI,CACZ8rC,CAAAA,CAAM9rC,CAAN8rC,EAAW,CACf,OAAQ,KAAAhoC,MAAD,CAAcgoC,CAAd,CAAoB,IAAApS,KAAA56B,OAApB,CAAwC,IAAA46B,KAAAz0B,OAAA,CAAiB,IAAAnB,MAAjB,CAA8BgoC,CAA9B,CAAxC,CAA6E,CAAA,CAFpE,CA3CF,CAgDhBppC,SAAUA,QAAQ,CAAC+kC,CAAD,CAAK,CACrB,MAAQ,GAAR,EAAeA,CAAf,EAA2B,GAA3B,EAAqBA,CAArB,EAAiD,QAAjD,GAAmC,MAAOA,EADrB,CAhDP,CAoDhB21B,aAAcA,QAAQ,CAAC31B,CAAD,CAAK,CAEzB,MAAe,GAAf,GAAQA,CAAR,EAA6B,IAA7B,GAAsBA,CAAtB;AAA4C,IAA5C,GAAqCA,CAArC,EACe,IADf,GACQA,CADR,EAC8B,IAD9B,GACuBA,CADvB,EAC6C,QAD7C,GACsCA,CAHb,CApDX,CA0DhBw1B,QAASA,QAAQ,CAACx1B,CAAD,CAAK,CACpB,MAAQ,GAAR,EAAeA,CAAf,EAA2B,GAA3B,EAAqBA,CAArB,EACQ,GADR,EACeA,CADf,EAC2B,GAD3B,EACqBA,CADrB,EAEQ,GAFR,GAEgBA,CAFhB,EAE6B,GAF7B,GAEsBA,CAHF,CA1DN,CAgEhBm2B,cAAeA,QAAQ,CAACn2B,CAAD,CAAK,CAC1B,MAAe,GAAf,GAAQA,CAAR,EAA6B,GAA7B,GAAsBA,CAAtB,EAAoC,IAAA/kC,SAAA,CAAc+kC,CAAd,CADV,CAhEZ,CAoEhBi2B,WAAYA,QAAQ,CAACn2C,CAAD,CAAQs2C,CAAR,CAAe5D,CAAf,CAAoB,CACtCA,CAAA,CAAMA,CAAN,EAAa,IAAAn2D,MACTg6D,EAAAA,CAAUt7D,CAAA,CAAUq7D,CAAV,CAAA,CACJ,IADI,CACGA,CADH,CACY,GADZ,CACkB,IAAA/5D,MADlB,CAC+B,IAD/B,CACsC,IAAA41B,KAAAlF,UAAA,CAAoBqpC,CAApB,CAA2B5D,CAA3B,CADtC,CACwE,GADxE,CAEJ,GAFI,CAEEA,CAChB,MAAMznB,GAAA,CAAa,QAAb,CACFjrB,CADE,CACKu2C,CADL,CACa,IAAApkC,KADb,CAAN,CALsC,CApExB,CA6EhBsjC,WAAYA,QAAQ,EAAG,CAGrB,IAFA,IAAI1T,EAAS,EAAb,CACIuU,EAAQ,IAAA/5D,MACZ,CAAO,IAAAA,MAAP,CAAoB,IAAA41B,KAAA56B,OAApB,CAAA,CAAsC,CACpC,IAAI2oC,EAAK9jC,CAAA,CAAU,IAAA+1B,KAAAz0B,OAAA,CAAiB,IAAAnB,MAAjB,CAAV,CACT,IAAU,GAAV,EAAI2jC,CAAJ,EAAiB,IAAA/kC,SAAA,CAAc+kC,CAAd,CAAjB,CACE6hB,CAAA,EAAU7hB,CADZ,KAEO,CACL,IAAIs2B,EAAS,IAAAhB,KAAA,EACb;GAAU,GAAV,EAAIt1B,CAAJ,EAAiB,IAAAm2B,cAAA,CAAmBG,CAAnB,CAAjB,CACEzU,CAAA,EAAU7hB,CADZ,KAEO,IAAI,IAAAm2B,cAAA,CAAmBn2B,CAAnB,CAAJ,EACHs2B,CADG,EACO,IAAAr7D,SAAA,CAAcq7D,CAAd,CADP,EAEiC,GAFjC,EAEHzU,CAAArkD,OAAA,CAAcqkD,CAAAxqD,OAAd,CAA8B,CAA9B,CAFG,CAGLwqD,CAAA,EAAU7hB,CAHL,KAIA,IAAI,CAAA,IAAAm2B,cAAA,CAAmBn2B,CAAnB,CAAJ,EACDs2B,CADC,EACU,IAAAr7D,SAAA,CAAcq7D,CAAd,CADV,EAEiC,GAFjC,EAEHzU,CAAArkD,OAAA,CAAcqkD,CAAAxqD,OAAd,CAA8B,CAA9B,CAFG,CAKL,KALK,KAGL,KAAA4+D,WAAA,CAAgB,kBAAhB,CAXG,CAgBP,IAAA55D,MAAA,EApBoC,CAsBtC,IAAA+4D,OAAAp4D,KAAA,CAAiB,CACfX,MAAO+5D,CADQ,CAEfnkC,KAAM4vB,CAFS,CAGfx5C,SAAU,CAAA,CAHK,CAIf3P,MAAOmrB,MAAA,CAAOg+B,CAAP,CAJQ,CAAjB,CAzBqB,CA7EP,CA8GhB4T,UAAWA,QAAQ,EAAG,CAEpB,IADA,IAAIW,EAAQ,IAAA/5D,MACZ,CAAO,IAAAA,MAAP,CAAoB,IAAA41B,KAAA56B,OAApB,CAAA,CAAsC,CACpC,IAAI2oC,EAAK,IAAA/N,KAAAz0B,OAAA,CAAiB,IAAAnB,MAAjB,CACT,IAAM,CAAA,IAAAm5D,QAAA,CAAax1B,CAAb,CAAN,EAA0B,CAAA,IAAA/kC,SAAA,CAAc+kC,CAAd,CAA1B,CACE,KAEF,KAAA3jC,MAAA,EALoC,CAOtC,IAAA+4D,OAAAp4D,KAAA,CAAiB,CACfX,MAAO+5D,CADQ;AAEfnkC,KAAM,IAAAA,KAAAp4B,MAAA,CAAgBu8D,CAAhB,CAAuB,IAAA/5D,MAAvB,CAFS,CAGfgyB,WAAY,CAAA,CAHG,CAAjB,CAToB,CA9GN,CA8HhBgnC,WAAYA,QAAQ,CAACkB,CAAD,CAAQ,CAC1B,IAAIH,EAAQ,IAAA/5D,MACZ,KAAAA,MAAA,EAIA,KAHA,IAAI6nD,EAAS,EAAb,CACIsS,EAAYD,CADhB,CAEIx2B,EAAS,CAAA,CACb,CAAO,IAAA1jC,MAAP,CAAoB,IAAA41B,KAAA56B,OAApB,CAAA,CAAsC,CACpC,IAAI2oC,EAAK,IAAA/N,KAAAz0B,OAAA,CAAiB,IAAAnB,MAAjB,CAAT,CACAm6D,EAAAA,CAAAA,CAAax2B,CACb,IAAID,CAAJ,CACa,GAAX,GAAIC,CAAJ,EACMy2B,CAKJ,CALU,IAAAxkC,KAAAlF,UAAA,CAAoB,IAAA1wB,MAApB,CAAiC,CAAjC,CAAoC,IAAAA,MAApC,CAAiD,CAAjD,CAKV,CAJKo6D,CAAAr5D,MAAA,CAAU,aAAV,CAIL,EAHE,IAAA64D,WAAA,CAAgB,6BAAhB,CAAgDQ,CAAhD,CAAsD,GAAtD,CAGF,CADA,IAAAp6D,MACA,EADc,CACd,CAAA6nD,CAAA,EAAUwS,MAAAC,aAAA,CAAoBz8D,QAAA,CAASu8D,CAAT,CAAc,EAAd,CAApB,CANZ,EASEvS,CATF,EAQYgR,EAAA0B,CAAO52B,CAAP42B,CARZ,EAS4B52B,CAE5B,CAAAD,CAAA,CAAS,CAAA,CAZX,KAaO,IAAW,IAAX,GAAIC,CAAJ,CACLD,CAAA,CAAS,CAAA,CADJ,KAEA,CAAA,GAAIC,CAAJ,GAAWu2B,CAAX,CAAkB,CACvB,IAAAl6D,MAAA,EACA,KAAA+4D,OAAAp4D,KAAA,CAAiB,CACfX,MAAO+5D,CADQ,CAEfnkC,KAAMukC,CAFS,CAGfnuD,SAAU,CAAA,CAHK;AAIf3P,MAAOwrD,CAJQ,CAAjB,CAMA,OARuB,CAUvBA,CAAA,EAAUlkB,CAVL,CAYP,IAAA3jC,MAAA,EA9BoC,CAgCtC,IAAA45D,WAAA,CAAgB,oBAAhB,CAAsCG,CAAtC,CAtC0B,CA9HZ,CAwKlB,KAAIvqB,EAAMA,QAAQ,CAACkF,CAAD,CAAQvxB,CAAR,CAAiB,CACjC,IAAAuxB,MAAA,CAAaA,CACb,KAAAvxB,QAAA,CAAeA,CAFkB,CAKnCqsB,EAAAC,QAAA,CAAc,SACdD,EAAAgrB,oBAAA,CAA0B,qBAC1BhrB,EAAAoB,qBAAA,CAA2B,sBAC3BpB,EAAAW,sBAAA,CAA4B,uBAC5BX,EAAAU,kBAAA,CAAwB,mBACxBV,EAAAO,iBAAA,CAAuB,kBACvBP,EAAAK,gBAAA,CAAsB,iBACtBL,EAAAkB,eAAA,CAAqB,gBACrBlB,EAAAe,iBAAA,CAAuB,kBACvBf,EAAAc,WAAA,CAAiB,YACjBd,EAAAG,QAAA;AAAc,SACdH,EAAAqB,gBAAA,CAAsB,iBACtBrB,EAAAirB,SAAA,CAAe,UACfjrB,EAAAsB,iBAAA,CAAuB,kBACvBtB,EAAAwB,eAAA,CAAqB,gBAGrBxB,EAAA6B,iBAAA,CAAuB,kBAEvB7B,EAAAhxC,UAAA,CAAgB,CACd6wC,IAAKA,QAAQ,CAACzZ,CAAD,CAAO,CAClB,IAAAA,KAAA,CAAYA,CACZ,KAAAmjC,OAAA,CAAc,IAAArkB,MAAAokB,IAAA,CAAeljC,CAAf,CAEVv5B,EAAAA,CAAQ,IAAAq+D,QAAA,EAEe,EAA3B,GAAI,IAAA3B,OAAA/9D,OAAJ,EACE,IAAA4+D,WAAA,CAAgB,wBAAhB,CAA0C,IAAAb,OAAA,CAAY,CAAZ,CAA1C,CAGF,OAAO18D,EAVW,CADN,CAcdq+D,QAASA,QAAQ,EAAG,CAElB,IADA,IAAIr4B,EAAO,EACX,CAAA,CAAA,CAGE,GAFyB,CAEpB,CAFD,IAAA02B,OAAA/9D,OAEC,EAF0B,CAAA,IAAAi+D,KAAA,CAAU,GAAV,CAAe,GAAf,CAAoB,GAApB,CAAyB,GAAzB,CAE1B,EADH52B,CAAA1hC,KAAA,CAAU,IAAAg6D,oBAAA,EAAV,CACG,CAAA,CAAA,IAAAC,OAAA,CAAY,GAAZ,CAAL,CACE,MAAO,CAAEthD,KAAMk2B,CAAAC,QAAR;AAAqBpN,KAAMA,CAA3B,CANO,CAdN,CAyBds4B,oBAAqBA,QAAQ,EAAG,CAC9B,MAAO,CAAErhD,KAAMk2B,CAAAgrB,oBAAR,CAAiCl/B,WAAY,IAAAu/B,YAAA,EAA7C,CADuB,CAzBlB,CA6BdA,YAAaA,QAAQ,EAAG,CAGtB,IAFA,IAAI7qB,EAAO,IAAA1U,WAAA,EAEX,CAAgB,IAAAs/B,OAAA,CAAY,GAAZ,CAAhB,CAAA,CACE5qB,CAAA,CAAO,IAAA7jC,OAAA,CAAY6jC,CAAZ,CAET,OAAOA,EANe,CA7BV,CAsCd1U,WAAYA,QAAQ,EAAG,CACrB,MAAO,KAAAw/B,WAAA,EADc,CAtCT,CA0CdA,WAAYA,QAAQ,EAAG,CACrB,IAAI77C,EAAS,IAAA87C,QAAA,EACT,KAAAH,OAAA,CAAY,GAAZ,CAAJ,GACE37C,CADF,CACW,CAAE3F,KAAMk2B,CAAAoB,qBAAR,CAAkCZ,KAAM/wB,CAAxC,CAAgDgxB,MAAO,IAAA6qB,WAAA,EAAvD,CAA0ExpB,SAAU,GAApF,CADX,CAGA,OAAOryB,EALc,CA1CT,CAkDd87C,QAASA,QAAQ,EAAG,CAClB,IAAIr6D,EAAO,IAAAs6D,UAAA,EAAX,CACI5qB,CADJ,CAEIC,CACJ,OAAI,KAAAuqB,OAAA,CAAY,GAAZ,CAAJ,GACExqB,CACI,CADQ,IAAA9U,WAAA,EACR,CAAA,IAAA2/B,QAAA,CAAa,GAAb,CAFN;CAGI5qB,CACO,CADM,IAAA/U,WAAA,EACN,CAAA,CAAEhiB,KAAMk2B,CAAAW,sBAAR,CAAmCzvC,KAAMA,CAAzC,CAA+C0vC,UAAWA,CAA1D,CAAqEC,WAAYA,CAAjF,CAJX,EAOO3vC,CAXW,CAlDN,CAgEds6D,UAAWA,QAAQ,EAAG,CAEpB,IADA,IAAIhrB,EAAO,IAAAkrB,WAAA,EACX,CAAO,IAAAN,OAAA,CAAY,IAAZ,CAAP,CAAA,CACE5qB,CAAA,CAAO,CAAE12B,KAAMk2B,CAAAU,kBAAR,CAA+BoB,SAAU,IAAzC,CAA+CtB,KAAMA,CAArD,CAA2DC,MAAO,IAAAirB,WAAA,EAAlE,CAET,OAAOlrB,EALa,CAhER,CAwEdkrB,WAAYA,QAAQ,EAAG,CAErB,IADA,IAAIlrB,EAAO,IAAAmrB,SAAA,EACX,CAAO,IAAAP,OAAA,CAAY,IAAZ,CAAP,CAAA,CACE5qB,CAAA,CAAO,CAAE12B,KAAMk2B,CAAAU,kBAAR,CAA+BoB,SAAU,IAAzC,CAA+CtB,KAAMA,CAArD,CAA2DC,MAAO,IAAAkrB,SAAA,EAAlE,CAET,OAAOnrB,EALc,CAxET,CAgFdmrB,SAAUA,QAAQ,EAAG,CAGnB,IAFA,IAAInrB,EAAO,IAAAorB,WAAA,EAAX,CACItgC,CACJ,CAAQA,CAAR,CAAgB,IAAA8/B,OAAA,CAAY,IAAZ,CAAiB,IAAjB,CAAsB,KAAtB,CAA4B,KAA5B,CAAhB,CAAA,CACE5qB,CAAA,CAAO,CAAE12B,KAAMk2B,CAAAO,iBAAR;AAA8BuB,SAAUxW,CAAAlF,KAAxC,CAAoDoa,KAAMA,CAA1D,CAAgEC,MAAO,IAAAmrB,WAAA,EAAvE,CAET,OAAOprB,EANY,CAhFP,CAyFdorB,WAAYA,QAAQ,EAAG,CAGrB,IAFA,IAAIprB,EAAO,IAAAqrB,SAAA,EAAX,CACIvgC,CACJ,CAAQA,CAAR,CAAgB,IAAA8/B,OAAA,CAAY,GAAZ,CAAiB,GAAjB,CAAsB,IAAtB,CAA4B,IAA5B,CAAhB,CAAA,CACE5qB,CAAA,CAAO,CAAE12B,KAAMk2B,CAAAO,iBAAR,CAA8BuB,SAAUxW,CAAAlF,KAAxC,CAAoDoa,KAAMA,CAA1D,CAAgEC,MAAO,IAAAorB,SAAA,EAAvE,CAET,OAAOrrB,EANc,CAzFT,CAkGdqrB,SAAUA,QAAQ,EAAG,CAGnB,IAFA,IAAIrrB,EAAO,IAAAsrB,eAAA,EAAX,CACIxgC,CACJ,CAAQA,CAAR,CAAgB,IAAA8/B,OAAA,CAAY,GAAZ,CAAgB,GAAhB,CAAhB,CAAA,CACE5qB,CAAA,CAAO,CAAE12B,KAAMk2B,CAAAO,iBAAR,CAA8BuB,SAAUxW,CAAAlF,KAAxC,CAAoDoa,KAAMA,CAA1D,CAAgEC,MAAO,IAAAqrB,eAAA,EAAvE,CAET,OAAOtrB,EANY,CAlGP,CA2GdsrB,eAAgBA,QAAQ,EAAG,CAGzB,IAFA,IAAItrB,EAAO,IAAAurB,MAAA,EAAX,CACIzgC,CACJ,CAAQA,CAAR,CAAgB,IAAA8/B,OAAA,CAAY,GAAZ,CAAgB,GAAhB,CAAoB,GAApB,CAAhB,CAAA,CACE5qB,CAAA,CAAO,CAAE12B,KAAMk2B,CAAAO,iBAAR,CAA8BuB,SAAUxW,CAAAlF,KAAxC;AAAoDoa,KAAMA,CAA1D,CAAgEC,MAAO,IAAAsrB,MAAA,EAAvE,CAET,OAAOvrB,EANkB,CA3Gb,CAoHdurB,MAAOA,QAAQ,EAAG,CAChB,IAAIzgC,CACJ,OAAA,CAAKA,CAAL,CAAa,IAAA8/B,OAAA,CAAY,GAAZ,CAAiB,GAAjB,CAAsB,GAAtB,CAAb,EACS,CAAEthD,KAAMk2B,CAAAK,gBAAR,CAA6ByB,SAAUxW,CAAAlF,KAAvC,CAAmDlwB,OAAQ,CAAA,CAA3D,CAAiEoqC,SAAU,IAAAyrB,MAAA,EAA3E,CADT,CAGS,IAAAC,QAAA,EALO,CApHJ,CA6HdA,QAASA,QAAQ,EAAG,CAClB,IAAIA,CACA,KAAAZ,OAAA,CAAY,GAAZ,CAAJ,EACEY,CACA,CADU,IAAAX,YAAA,EACV,CAAA,IAAAI,QAAA,CAAa,GAAb,CAFF,EAGW,IAAAL,OAAA,CAAY,GAAZ,CAAJ,CACLY,CADK,CACK,IAAAC,iBAAA,EADL,CAEI,IAAAb,OAAA,CAAY,GAAZ,CAAJ,CACLY,CADK,CACK,IAAAhrB,OAAA,EADL,CAEI,IAAAkrB,UAAA//D,eAAA,CAA8B,IAAAs9D,KAAA,EAAArjC,KAA9B,CAAJ,CACL4lC,CADK,CACKr7D,EAAA,CAAK,IAAAu7D,UAAA,CAAe,IAAAT,QAAA,EAAArlC,KAAf,CAAL,CADL,CAEI,IAAAqjC,KAAA,EAAAjnC,WAAJ,CACLwpC,CADK,CACK,IAAAxpC,WAAA,EADL,CAEI,IAAAinC,KAAA,EAAAjtD,SAAJ,CACLwvD,CADK,CACK,IAAAxvD,SAAA,EADL;AAGL,IAAA4tD,WAAA,CAAgB,0BAAhB,CAA4C,IAAAX,KAAA,EAA5C,CAIF,KADA,IAAItc,CACJ,CAAQA,CAAR,CAAe,IAAAie,OAAA,CAAY,GAAZ,CAAiB,GAAjB,CAAsB,GAAtB,CAAf,CAAA,CACoB,GAAlB,GAAIje,CAAA/mB,KAAJ,EACE4lC,CACA,CADU,CAACliD,KAAMk2B,CAAAkB,eAAP,CAA2BC,OAAQ6qB,CAAnC,CAA4C/9D,UAAW,IAAAk+D,eAAA,EAAvD,CACV,CAAA,IAAAV,QAAA,CAAa,GAAb,CAFF,EAGyB,GAAlB,GAAIte,CAAA/mB,KAAJ,EACL4lC,CACA,CADU,CAAEliD,KAAMk2B,CAAAe,iBAAR,CAA8BC,OAAQgrB,CAAtC,CAA+CjwB,SAAU,IAAAjQ,WAAA,EAAzD,CAA4EmV,SAAU,CAAA,CAAtF,CACV,CAAA,IAAAwqB,QAAA,CAAa,GAAb,CAFK,EAGkB,GAAlB,GAAIte,CAAA/mB,KAAJ,CACL4lC,CADK,CACK,CAAEliD,KAAMk2B,CAAAe,iBAAR,CAA8BC,OAAQgrB,CAAtC,CAA+CjwB,SAAU,IAAAvZ,WAAA,EAAzD,CAA4Eye,SAAU,CAAA,CAAtF,CADL,CAGL,IAAAmpB,WAAA,CAAgB,YAAhB,CAGJ,OAAO4B,EAjCW,CA7HN,CAiKdrvD,OAAQA,QAAQ,CAACyvD,CAAD,CAAiB,CAC3Bz9C,CAAAA,CAAO,CAACy9C,CAAD,CAGX,KAFA,IAAI38C,EAAS,CAAC3F,KAAMk2B,CAAAkB,eAAP,CAA2BC,OAAQ,IAAA3e,WAAA,EAAnC;AAAsDv0B,UAAW0gB,CAAjE,CAAuEhS,OAAQ,CAAA,CAA/E,CAEb,CAAO,IAAAyuD,OAAA,CAAY,GAAZ,CAAP,CAAA,CACEz8C,CAAAxd,KAAA,CAAU,IAAA26B,WAAA,EAAV,CAGF,OAAOrc,EARwB,CAjKnB,CA4Kd08C,eAAgBA,QAAQ,EAAG,CACzB,IAAIx9C,EAAO,EACX,IAA8B,GAA9B,GAAI,IAAA09C,UAAA,EAAAjmC,KAAJ,EACE,EACEzX,EAAAxd,KAAA,CAAU,IAAA26B,WAAA,EAAV,CADF,OAES,IAAAs/B,OAAA,CAAY,GAAZ,CAFT,CADF,CAKA,MAAOz8C,EAPkB,CA5Kb,CAsLd6T,WAAYA,QAAQ,EAAG,CACrB,IAAI8I,EAAQ,IAAAmgC,QAAA,EACPngC,EAAA9I,WAAL,EACE,IAAA4nC,WAAA,CAAgB,2BAAhB,CAA6C9+B,CAA7C,CAEF,OAAO,CAAExhB,KAAMk2B,CAAAc,WAAR,CAAwB3qC,KAAMm1B,CAAAlF,KAA9B,CALc,CAtLT,CA8Ld5pB,SAAUA,QAAQ,EAAG,CAEnB,MAAO,CAAEsN,KAAMk2B,CAAAG,QAAR,CAAqBtzC,MAAO,IAAA4+D,QAAA,EAAA5+D,MAA5B,CAFY,CA9LP,CAmMdo/D,iBAAkBA,QAAQ,EAAG,CAC3B,IAAI1gD,EAAW,EACf,IAA8B,GAA9B,GAAI,IAAA8gD,UAAA,EAAAjmC,KAAJ,EACE,EAAG,CACD,GAAI,IAAAqjC,KAAA,CAAU,GAAV,CAAJ,CAEE,KAEFl+C;CAAApa,KAAA,CAAc,IAAA26B,WAAA,EAAd,CALC,CAAH,MAMS,IAAAs/B,OAAA,CAAY,GAAZ,CANT,CADF,CASA,IAAAK,QAAA,CAAa,GAAb,CAEA,OAAO,CAAE3hD,KAAMk2B,CAAAqB,gBAAR,CAA6B91B,SAAUA,CAAvC,CAboB,CAnMf,CAmNdy1B,OAAQA,QAAQ,EAAG,CAAA,IACbO,EAAa,EADA,CACIxF,CACrB,IAA8B,GAA9B,GAAI,IAAAswB,UAAA,EAAAjmC,KAAJ,EACE,EAAG,CACD,GAAI,IAAAqjC,KAAA,CAAU,GAAV,CAAJ,CAEE,KAEF1tB,EAAA,CAAW,CAACjyB,KAAMk2B,CAAAirB,SAAP,CAAqBqB,KAAM,MAA3B,CACP,KAAA7C,KAAA,EAAAjtD,SAAJ,CACEu/B,CAAA9vC,IADF,CACiB,IAAAuQ,SAAA,EADjB,CAEW,IAAAitD,KAAA,EAAAjnC,WAAJ,CACLuZ,CAAA9vC,IADK,CACU,IAAAu2B,WAAA,EADV,CAGL,IAAA4nC,WAAA,CAAgB,aAAhB,CAA+B,IAAAX,KAAA,EAA/B,CAEF,KAAAgC,QAAA,CAAa,GAAb,CACA1vB,EAAAlvC,MAAA,CAAiB,IAAAi/B,WAAA,EACjByV,EAAApwC,KAAA,CAAgB4qC,CAAhB,CAfC,CAAH,MAgBS,IAAAqvB,OAAA,CAAY,GAAZ,CAhBT,CADF,CAmBA,IAAAK,QAAA,CAAa,GAAb,CAEA,OAAO,CAAC3hD,KAAMk2B,CAAAsB,iBAAP,CAA6BC,WAAYA,CAAzC,CAvBU,CAnNL;AA6Od6oB,WAAYA,QAAQ,CAACld,CAAD,CAAM5hB,CAAN,CAAa,CAC/B,KAAM4T,GAAA,CAAa,QAAb,CAEA5T,CAAAlF,KAFA,CAEY8mB,CAFZ,CAEkB5hB,CAAA96B,MAFlB,CAEgC,CAFhC,CAEoC,IAAA41B,KAFpC,CAE+C,IAAAA,KAAAlF,UAAA,CAAoBoK,CAAA96B,MAApB,CAF/C,CAAN,CAD+B,CA7OnB,CAmPdi7D,QAASA,QAAQ,CAACc,CAAD,CAAK,CACpB,GAA2B,CAA3B,GAAI,IAAAhD,OAAA/9D,OAAJ,CACE,KAAM0zC,GAAA,CAAa,MAAb,CAA0D,IAAA9Y,KAA1D,CAAN,CAGF,IAAIkF,EAAQ,IAAA8/B,OAAA,CAAYmB,CAAZ,CACPjhC,EAAL,EACE,IAAA8+B,WAAA,CAAgB,4BAAhB,CAA+CmC,CAA/C,CAAoD,GAApD,CAAyD,IAAA9C,KAAA,EAAzD,CAEF,OAAOn+B,EATa,CAnPR,CA+Pd+gC,UAAWA,QAAQ,EAAG,CACpB,GAA2B,CAA3B,GAAI,IAAA9C,OAAA/9D,OAAJ,CACE,KAAM0zC,GAAA,CAAa,MAAb,CAA0D,IAAA9Y,KAA1D,CAAN,CAEF,MAAO,KAAAmjC,OAAA,CAAY,CAAZ,CAJa,CA/PR,CAsQdE,KAAMA,QAAQ,CAAC8C,CAAD,CAAKC,CAAL,CAASC,CAAT,CAAaC,CAAb,CAAiB,CAC7B,MAAO,KAAAC,UAAA,CAAe,CAAf,CAAkBJ,CAAlB,CAAsBC,CAAtB,CAA0BC,CAA1B,CAA8BC,CAA9B,CADsB,CAtQjB,CA0QdC,UAAWA,QAAQ,CAACjgE,CAAD,CAAI6/D,CAAJ,CAAQC,CAAR,CAAYC,CAAZ,CAAgBC,CAAhB,CAAoB,CACrC,GAAI,IAAAnD,OAAA/9D,OAAJ,CAAyBkB,CAAzB,CAA4B,CACtB4+B,CAAAA,CAAQ,IAAAi+B,OAAA,CAAY78D,CAAZ,CACZ;IAAIkgE,EAAIthC,CAAAlF,KACR,IAAIwmC,CAAJ,GAAUL,CAAV,EAAgBK,CAAhB,GAAsBJ,CAAtB,EAA4BI,CAA5B,GAAkCH,CAAlC,EAAwCG,CAAxC,GAA8CF,CAA9C,EACK,EAACH,CAAD,EAAQC,CAAR,EAAeC,CAAf,EAAsBC,CAAtB,CADL,CAEE,MAAOphC,EALiB,CAQ5B,MAAO,CAAA,CAT8B,CA1QzB,CAsRd8/B,OAAQA,QAAQ,CAACmB,CAAD,CAAKC,CAAL,CAASC,CAAT,CAAaC,CAAb,CAAiB,CAE/B,MAAA,CADIphC,CACJ,CADY,IAAAm+B,KAAA,CAAU8C,CAAV,CAAcC,CAAd,CAAkBC,CAAlB,CAAsBC,CAAtB,CACZ,GACE,IAAAnD,OAAA54C,MAAA,EACO2a,CAAAA,CAFT,EAIO,CAAA,CANwB,CAtRnB,CAmSd4gC,UAAW,CACT,OAAQ,CAAEpiD,KAAMk2B,CAAAG,QAAR,CAAqBtzC,MAAO,CAAA,CAA5B,CADC,CAET,QAAS,CAAEid,KAAMk2B,CAAAG,QAAR,CAAqBtzC,MAAO,CAAA,CAA5B,CAFA,CAGT,OAAQ,CAAEid,KAAMk2B,CAAAG,QAAR,CAAqBtzC,MAAO,IAA5B,CAHC,CAIT,UAAa,CAACid,KAAMk2B,CAAAG,QAAP,CAAoBtzC,MAAO1B,CAA3B,CAJJ,CAKT,OAAQ,CAAC2e,KAAMk2B,CAAAwB,eAAP,CALC,CAnSG,CAschBQ,GAAAhzC,UAAA,CAAwB,CACtBqI,QAASA,QAAQ,CAACy0B,CAAD,CAAa+Y,CAAb,CAA8B,CAC7C,IAAItyC,EAAO,IAAX,CACIstC,EAAM,IAAAoC,WAAApC,IAAA,CAAoB/T,CAApB,CACV,KAAAxX,MAAA,CAAa,CACXu4C,OAAQ,CADG,CAEX/Y,QAAS,EAFE,CAGXjP,gBAAiBA,CAHN,CAIXryC,GAAI,CAACs6D,KAAM,EAAP,CAAWj6B,KAAM,EAAjB,CAAqBk6B,IAAK,EAA1B,CAJO,CAKX/jC,OAAQ,CAAC8jC,KAAM,EAAP;AAAWj6B,KAAM,EAAjB,CAAqBk6B,IAAK,EAA1B,CALG,CAMX5pB,OAAQ,EANG,CAQbvD,EAAA,CAAgCC,CAAhC,CAAqCttC,CAAA2R,QAArC,CACA,KAAI1V,EAAQ,EAAZ,CACIw+D,CACJ,KAAAC,MAAA,CAAa,QACb,IAAKD,CAAL,CAAkBprB,EAAA,CAAc/B,CAAd,CAAlB,CACE,IAAAvrB,MAAA44C,UAGA,CAHuB,QAGvB,CAFIz9C,CAEJ,CAFa,IAAAo9C,OAAA,EAEb,CADA,IAAAM,QAAA,CAAaH,CAAb,CAAyBv9C,CAAzB,CACA,CAAAjhB,CAAA,CAAQ,YAAR,CAAuB,IAAA4+D,iBAAA,CAAsB,QAAtB,CAAgC,OAAhC,CAErBhtB,EAAAA,CAAUqB,EAAA,CAAU5B,CAAAhN,KAAV,CACdtgC,EAAA06D,MAAA,CAAa,QACbnhE,EAAA,CAAQs0C,CAAR,CAAiB,QAAQ,CAACqM,CAAD,CAAQxgD,CAAR,CAAa,CACpC,IAAIohE,EAAQ,IAARA,CAAephE,CACnBsG,EAAA+hB,MAAA,CAAW+4C,CAAX,CAAA,CAAoB,CAACP,KAAM,EAAP,CAAWj6B,KAAM,EAAjB,CAAqBk6B,IAAK,EAA1B,CACpBx6D,EAAA+hB,MAAA44C,UAAA,CAAuBG,CACvB,KAAIC,EAAS/6D,CAAAs6D,OAAA,EACbt6D,EAAA46D,QAAA,CAAa1gB,CAAb,CAAoB6gB,CAApB,CACA/6D,EAAAg7D,QAAA,CAAaD,CAAb,CACA/6D,EAAA+hB,MAAA6uB,OAAAhyC,KAAA,CAAuBk8D,CAAvB,CACA5gB,EAAA+gB,QAAA,CAAgBvhE,CARoB,CAAtC,CAUA,KAAAqoB,MAAA44C,UAAA,CAAuB,IACvB,KAAAD,MAAA,CAAa,MACb,KAAAE,QAAA,CAAattB,CAAb,CACI4tB,EAAAA,CAGF,GAHEA,CAGI,IAAAC,IAHJD,CAGe,GAHfA,CAGqB,IAAAE,OAHrBF,CAGmC,MAHnCA,CAIF,IAAAG,aAAA,EAJEH;AAKF,SALEA,CAKU,IAAAL,iBAAA,CAAsB,IAAtB,CAA4B,SAA5B,CALVK,CAMFj/D,CANEi/D,CAOF,IAAAI,SAAA,EAPEJ,CAQF,YAGEj7D,EAAAA,CAAK,CAAC,IAAI8vD,QAAJ,CAAa,SAAb,CACN,sBADM,CAEN,kBAFM,CAGN,oBAHM,CAIN,WAJM,CAKN,MALM,CAMN,MANM,CAONmL,CAPM,CAAD,EAQH,IAAAvpD,QARG,CASH86B,EATG,CAUHG,EAVG,CAWHE,EAXG,CAYHI,EAZG,CAaHC,EAbG,CAcH5T,CAdG,CAgBT,KAAAxX,MAAA,CAAa,IAAA24C,MAAb,CAA0B9hE,CAC1BqH,EAAAu2B,QAAA,CAAagZ,EAAA,CAAUlC,CAAV,CACbrtC,EAAAgK,SAAA,CAAyBqjC,CA1EpBrjC,SA2EL,OAAOhK,EAlEsC,CADzB,CAsEtBk7D,IAAK,KAtEiB,CAwEtBC,OAAQ,QAxEc,CA0EtBE,SAAUA,QAAQ,EAAG,CACnB,IAAIp+C,EAAS,EAAb,CACIqe,EAAM,IAAAxZ,MAAA6uB,OADV,CAEI5wC,EAAO,IACXzG,EAAA,CAAQgiC,CAAR,CAAa,QAAQ,CAAC33B,CAAD,CAAO,CAC1BsZ,CAAAte,KAAA,CAAY,MAAZ,CAAqBgF,CAArB,CAA4B,GAA5B,CAAkC5D,CAAA66D,iBAAA,CAAsBj3D,CAAtB,CAA4B,GAA5B,CAAlC,CAD0B,CAA5B,CAGI23B,EAAAtiC,OAAJ,EACEikB,CAAAte,KAAA,CAAY,aAAZ,CAA4B28B,CAAAz4B,KAAA,CAAS,GAAT,CAA5B,CAA4C,IAA5C,CAEF,OAAOoa,EAAApa,KAAA,CAAY,EAAZ,CAVY,CA1EC;AAuFtB+3D,iBAAkBA,QAAQ,CAACj3D,CAAD,CAAOs2B,CAAP,CAAe,CACvC,MAAO,WAAP,CAAqBA,CAArB,CAA8B,IAA9B,CACI,IAAAqhC,WAAA,CAAgB33D,CAAhB,CADJ,CAEI,IAAA08B,KAAA,CAAU18B,CAAV,CAFJ,CAGI,IAJmC,CAvFnB,CA8FtBy3D,aAAcA,QAAQ,EAAG,CACvB,IAAI14D,EAAQ,EAAZ,CACI3C,EAAO,IACXzG,EAAA,CAAQ,IAAAwoB,MAAAw/B,QAAR,CAA4B,QAAQ,CAACh8B,CAAD,CAAKnb,CAAL,CAAa,CAC/CzH,CAAA/D,KAAA,CAAW2mB,CAAX,CAAgB,WAAhB,CAA8BvlB,CAAA2hC,OAAA,CAAYv3B,CAAZ,CAA9B,CAAoD,GAApD,CAD+C,CAAjD,CAGA,OAAIzH,EAAA1J,OAAJ,CAAyB,MAAzB,CAAkC0J,CAAAG,KAAA,CAAW,GAAX,CAAlC,CAAoD,GAApD,CACO,EAPgB,CA9FH,CAwGtBy4D,WAAYA,QAAQ,CAACC,CAAD,CAAU,CAC5B,MAAO,KAAAz5C,MAAA,CAAWy5C,CAAX,CAAAjB,KAAAthE,OAAA,CAAkC,MAAlC,CAA2C,IAAA8oB,MAAA,CAAWy5C,CAAX,CAAAjB,KAAAz3D,KAAA,CAA8B,GAA9B,CAA3C,CAAgF,GAAhF,CAAsF,EADjE,CAxGR,CA4GtBw9B,KAAMA,QAAQ,CAACk7B,CAAD,CAAU,CACtB,MAAO,KAAAz5C,MAAA,CAAWy5C,CAAX,CAAAl7B,KAAAx9B,KAAA,CAA8B,EAA9B,CADe,CA5GF,CAgHtB83D,QAASA,QAAQ,CAACttB,CAAD,CAAMytB,CAAN,CAAcU,CAAd,CAAsBC,CAAtB,CAAmCx/D,CAAnC,CAA2Cy/D,CAA3C,CAA6D,CAAA,IACxE1tB,CADwE,CAClEC,CADkE,CAC3DluC,EAAO,IADoD,CAC9Coc,CAD8C,CACxCmd,CACpCmiC,EAAA,CAAcA,CAAd,EAA6Bv/D,CAC7B,IAAKw/D,CAAAA,CAAL,EAAyBh/D,CAAA,CAAU2wC,CAAA2tB,QAAV,CAAzB,CACEF,CACA,CADSA,CACT,EADmB,IAAAT,OAAA,EACnB,CAAA,IAAAsB,IAAA,CAAS,GAAT;AACE,IAAAC,WAAA,CAAgBd,CAAhB,CAAwB,IAAAe,eAAA,CAAoB,GAApB,CAAyBxuB,CAAA2tB,QAAzB,CAAxB,CADF,CAEE,IAAAc,YAAA,CAAiBzuB,CAAjB,CAAsBytB,CAAtB,CAA8BU,CAA9B,CAAsCC,CAAtC,CAAmDx/D,CAAnD,CAA2D,CAAA,CAA3D,CAFF,CAFF,KAQA,QAAQoxC,CAAA/1B,KAAR,EACA,KAAKk2B,CAAAC,QAAL,CACEn0C,CAAA,CAAQ+zC,CAAAhN,KAAR,CAAkB,QAAQ,CAAC/G,CAAD,CAAarzB,CAAb,CAAkB,CAC1ClG,CAAA46D,QAAA,CAAarhC,CAAAA,WAAb,CAAoC3gC,CAApC,CAA+CA,CAA/C,CAA0D,QAAQ,CAAC+0C,CAAD,CAAO,CAAEO,CAAA,CAAQP,CAAV,CAAzE,CACIznC,EAAJ,GAAYonC,CAAAhN,KAAArnC,OAAZ,CAA8B,CAA9B,CACE+G,CAAA43C,QAAA,EAAAtX,KAAA1hC,KAAA,CAAyBsvC,CAAzB,CAAgC,GAAhC,CADF,CAGEluC,CAAAg7D,QAAA,CAAa9sB,CAAb,CALwC,CAA5C,CAQA,MACF,MAAKT,CAAAG,QAAL,CACErU,CAAA,CAAa,IAAAoI,OAAA,CAAY2L,CAAAhzC,MAAZ,CACb,KAAAm8B,OAAA,CAAYskC,CAAZ,CAAoBxhC,CAApB,CACAmiC,EAAA,CAAYniC,CAAZ,CACA,MACF,MAAKkU,CAAAK,gBAAL,CACE,IAAA8sB,QAAA,CAAattB,CAAAS,SAAb,CAA2Bn1C,CAA3B,CAAsCA,CAAtC,CAAiD,QAAQ,CAAC+0C,CAAD,CAAO,CAAEO,CAAA,CAAQP,CAAV,CAAhE,CACApU,EAAA,CAAa+T,CAAAiC,SAAb,CAA4B,GAA5B,CAAkC,IAAArC,UAAA,CAAegB,CAAf,CAAsB,CAAtB,CAAlC,CAA6D,GAC7D,KAAAzX,OAAA,CAAYskC,CAAZ,CAAoBxhC,CAApB,CACAmiC,EAAA,CAAYniC,CAAZ,CACA,MACF,MAAKkU,CAAAO,iBAAL,CACE,IAAA4sB,QAAA,CAAattB,CAAAW,KAAb;AAAuBr1C,CAAvB,CAAkCA,CAAlC,CAA6C,QAAQ,CAAC+0C,CAAD,CAAO,CAAEM,CAAA,CAAON,CAAT,CAA5D,CACA,KAAAitB,QAAA,CAAattB,CAAAY,MAAb,CAAwBt1C,CAAxB,CAAmCA,CAAnC,CAA8C,QAAQ,CAAC+0C,CAAD,CAAO,CAAEO,CAAA,CAAQP,CAAV,CAA7D,CAEEpU,EAAA,CADmB,GAArB,GAAI+T,CAAAiC,SAAJ,CACe,IAAAysB,KAAA,CAAU/tB,CAAV,CAAgBC,CAAhB,CADf,CAE4B,GAArB,GAAIZ,CAAAiC,SAAJ,CACQ,IAAArC,UAAA,CAAee,CAAf,CAAqB,CAArB,CADR,CACkCX,CAAAiC,SADlC,CACiD,IAAArC,UAAA,CAAegB,CAAf,CAAsB,CAAtB,CADjD,CAGQ,GAHR,CAGcD,CAHd,CAGqB,GAHrB,CAG2BX,CAAAiC,SAH3B,CAG0C,GAH1C,CAGgDrB,CAHhD,CAGwD,GAE/D,KAAAzX,OAAA,CAAYskC,CAAZ,CAAoBxhC,CAApB,CACAmiC,EAAA,CAAYniC,CAAZ,CACA,MACF,MAAKkU,CAAAU,kBAAL,CACE4sB,CAAA,CAASA,CAAT,EAAmB,IAAAT,OAAA,EACnBt6D,EAAA46D,QAAA,CAAattB,CAAAW,KAAb,CAAuB8sB,CAAvB,CACA/6D,EAAA47D,IAAA,CAA0B,IAAjB,GAAAtuB,CAAAiC,SAAA,CAAwBwrB,CAAxB,CAAiC/6D,CAAAi8D,IAAA,CAASlB,CAAT,CAA1C,CAA4D/6D,CAAA+7D,YAAA,CAAiBzuB,CAAAY,MAAjB,CAA4B6sB,CAA5B,CAA5D,CACAW,EAAA,CAAYX,CAAZ,CACA,MACF,MAAKttB,CAAAW,sBAAL,CACE2sB,CAAA,CAASA,CAAT,EAAmB,IAAAT,OAAA,EACnBt6D,EAAA46D,QAAA,CAAattB,CAAA3uC,KAAb,CAAuBo8D,CAAvB,CACA/6D,EAAA47D,IAAA,CAASb,CAAT,CAAiB/6D,CAAA+7D,YAAA,CAAiBzuB,CAAAe,UAAjB,CAAgC0sB,CAAhC,CAAjB,CAA0D/6D,CAAA+7D,YAAA,CAAiBzuB,CAAAgB,WAAjB,CAAiCysB,CAAjC,CAA1D,CACAW,EAAA,CAAYX,CAAZ,CACA;KACF,MAAKttB,CAAAc,WAAL,CACEwsB,CAAA,CAASA,CAAT,EAAmB,IAAAT,OAAA,EACfmB,EAAJ,GACEA,CAAAhiE,QAEA,CAFgC,QAAf,GAAAuG,CAAA06D,MAAA,CAA0B,GAA1B,CAAgC,IAAAjkC,OAAA,CAAY,IAAA6jC,OAAA,EAAZ,CAA2B,IAAA4B,kBAAA,CAAuB,GAAvB,CAA4B5uB,CAAA1pC,KAA5B,CAA3B,CAAmE,MAAnE,CAEjD,CADA63D,CAAA/sB,SACA,CADkB,CAAA,CAClB,CAAA+sB,CAAA73D,KAAA,CAAc0pC,CAAA1pC,KAHhB,CAKA6oC,GAAA,CAAqBa,CAAA1pC,KAArB,CACA5D,EAAA47D,IAAA,CAAwB,QAAxB,GAAS57D,CAAA06D,MAAT,EAAoC16D,CAAAi8D,IAAA,CAASj8D,CAAAk8D,kBAAA,CAAuB,GAAvB,CAA4B5uB,CAAA1pC,KAA5B,CAAT,CAApC,CACE,QAAQ,EAAG,CACT5D,CAAA47D,IAAA,CAAwB,QAAxB,GAAS57D,CAAA06D,MAAT,EAAoC,GAApC,CAAyC,QAAQ,EAAG,CAC9Cx+D,CAAJ,EAAyB,CAAzB,GAAcA,CAAd,EACE8D,CAAA47D,IAAA,CACE57D,CAAAi8D,IAAA,CAASj8D,CAAAm8D,kBAAA,CAAuB,GAAvB,CAA4B7uB,CAAA1pC,KAA5B,CAAT,CADF,CAEE5D,CAAA67D,WAAA,CAAgB77D,CAAAm8D,kBAAA,CAAuB,GAAvB,CAA4B7uB,CAAA1pC,KAA5B,CAAhB,CAAuD,IAAvD,CAFF,CAIF5D,EAAAy2B,OAAA,CAAYskC,CAAZ,CAAoB/6D,CAAAm8D,kBAAA,CAAuB,GAAvB,CAA4B7uB,CAAA1pC,KAA5B,CAApB,CANkD,CAApD,CADS,CADb,CAUKm3D,CAVL,EAUe/6D,CAAA67D,WAAA,CAAgBd,CAAhB,CAAwB/6D,CAAAm8D,kBAAA,CAAuB,GAAvB;AAA4B7uB,CAAA1pC,KAA5B,CAAxB,CAVf,CAYA,EAAI5D,CAAA+hB,MAAAuwB,gBAAJ,EAAkCtC,EAAA,CAA8B1C,CAAA1pC,KAA9B,CAAlC,GACE5D,CAAAo8D,oBAAA,CAAyBrB,CAAzB,CAEFW,EAAA,CAAYX,CAAZ,CACA,MACF,MAAKttB,CAAAe,iBAAL,CACEP,CAAA,CAAOwtB,CAAP,GAAkBA,CAAAhiE,QAAlB,CAAmC,IAAA6gE,OAAA,EAAnC,GAAqD,IAAAA,OAAA,EACrDS,EAAA,CAASA,CAAT,EAAmB,IAAAT,OAAA,EACnBt6D,EAAA46D,QAAA,CAAattB,CAAAmB,OAAb,CAAyBR,CAAzB,CAA+Br1C,CAA/B,CAA0C,QAAQ,EAAG,CACnDoH,CAAA47D,IAAA,CAAS57D,CAAAq8D,QAAA,CAAapuB,CAAb,CAAT,CAA6B,QAAQ,EAAG,CACtC,GAAIX,CAAAoB,SAAJ,CACER,CAQA,CARQluC,CAAAs6D,OAAA,EAQR,CAPAt6D,CAAA46D,QAAA,CAAattB,CAAA9D,SAAb,CAA2B0E,CAA3B,CAOA,CANAluC,CAAAs8D,wBAAA,CAA6BpuB,CAA7B,CAMA,CALIhyC,CAKJ,EALyB,CAKzB,GALcA,CAKd,EAJE8D,CAAA47D,IAAA,CAAS57D,CAAAi8D,IAAA,CAASj8D,CAAA87D,eAAA,CAAoB7tB,CAApB,CAA0BC,CAA1B,CAAT,CAAT,CAAqDluC,CAAA67D,WAAA,CAAgB77D,CAAA87D,eAAA,CAAoB7tB,CAApB,CAA0BC,CAA1B,CAAhB,CAAkD,IAAlD,CAArD,CAIF,CAFA3U,CAEA,CAFav5B,CAAA4sC,iBAAA,CAAsB5sC,CAAA87D,eAAA,CAAoB7tB,CAApB,CAA0BC,CAA1B,CAAtB,CAEb,CADAluC,CAAAy2B,OAAA,CAAYskC,CAAZ,CAAoBxhC,CAApB,CACA,CAAIkiC,CAAJ,GACEA,CAAA/sB,SACA,CADkB,CAAA,CAClB,CAAA+sB,CAAA73D,KAAA,CAAcsqC,CAFhB,CATF,KAaO,CACLzB,EAAA,CAAqBa,CAAA9D,SAAA5lC,KAArB,CACI1H;CAAJ,EAAyB,CAAzB,GAAcA,CAAd,EACE8D,CAAA47D,IAAA,CAAS57D,CAAAi8D,IAAA,CAASj8D,CAAAm8D,kBAAA,CAAuBluB,CAAvB,CAA6BX,CAAA9D,SAAA5lC,KAA7B,CAAT,CAAT,CAAoE5D,CAAA67D,WAAA,CAAgB77D,CAAAm8D,kBAAA,CAAuBluB,CAAvB,CAA6BX,CAAA9D,SAAA5lC,KAA7B,CAAhB,CAAiE,IAAjE,CAApE,CAEF21B,EAAA,CAAav5B,CAAAm8D,kBAAA,CAAuBluB,CAAvB,CAA6BX,CAAA9D,SAAA5lC,KAA7B,CACb,IAAI5D,CAAA+hB,MAAAuwB,gBAAJ,EAAkCtC,EAAA,CAA8B1C,CAAA9D,SAAA5lC,KAA9B,CAAlC,CACE21B,CAAA,CAAav5B,CAAA4sC,iBAAA,CAAsBrT,CAAtB,CAEfv5B,EAAAy2B,OAAA,CAAYskC,CAAZ,CAAoBxhC,CAApB,CACIkiC,EAAJ,GACEA,CAAA/sB,SACA,CADkB,CAAA,CAClB,CAAA+sB,CAAA73D,KAAA,CAAc0pC,CAAA9D,SAAA5lC,KAFhB,CAVK,CAd+B,CAAxC,CA6BG,QAAQ,EAAG,CACZ5D,CAAAy2B,OAAA,CAAYskC,CAAZ,CAAoB,WAApB,CADY,CA7Bd,CAgCAW,EAAA,CAAYX,CAAZ,CAjCmD,CAArD,CAkCG,CAAE7+D,CAAAA,CAlCL,CAmCA,MACF,MAAKuxC,CAAAkB,eAAL,CACEosB,CAAA,CAASA,CAAT,EAAmB,IAAAT,OAAA,EACfhtB,EAAAljC,OAAJ,EACE8jC,CASA,CATQluC,CAAAoK,OAAA,CAAYkjC,CAAAsB,OAAAhrC,KAAZ,CASR,CARAwY,CAQA,CARO,EAQP,CAPA7iB,CAAA,CAAQ+zC,CAAA5xC,UAAR,CAAuB,QAAQ,CAACiyC,CAAD,CAAO,CACpC,IAAII,EAAW/tC,CAAAs6D,OAAA,EACft6D,EAAA46D,QAAA,CAAajtB,CAAb,CAAmBI,CAAnB,CACA3xB,EAAAxd,KAAA,CAAUmvC,CAAV,CAHoC,CAAtC,CAOA,CAFAxU,CAEA,CAFa2U,CAEb;AAFqB,GAErB,CAF2B9xB,CAAAtZ,KAAA,CAAU,GAAV,CAE3B,CAF4C,GAE5C,CADA9C,CAAAy2B,OAAA,CAAYskC,CAAZ,CAAoBxhC,CAApB,CACA,CAAAmiC,CAAA,CAAYX,CAAZ,CAVF,GAYE7sB,CAGA,CAHQluC,CAAAs6D,OAAA,EAGR,CAFArsB,CAEA,CAFO,EAEP,CADA7xB,CACA,CADO,EACP,CAAApc,CAAA46D,QAAA,CAAattB,CAAAsB,OAAb,CAAyBV,CAAzB,CAAgCD,CAAhC,CAAsC,QAAQ,EAAG,CAC/CjuC,CAAA47D,IAAA,CAAS57D,CAAAq8D,QAAA,CAAanuB,CAAb,CAAT,CAA8B,QAAQ,EAAG,CACvCluC,CAAAu8D,sBAAA,CAA2BruB,CAA3B,CACA30C,EAAA,CAAQ+zC,CAAA5xC,UAAR,CAAuB,QAAQ,CAACiyC,CAAD,CAAO,CACpC3tC,CAAA46D,QAAA,CAAajtB,CAAb,CAAmB3tC,CAAAs6D,OAAA,EAAnB,CAAkC1hE,CAAlC,CAA6C,QAAQ,CAACm1C,CAAD,CAAW,CAC9D3xB,CAAAxd,KAAA,CAAUoB,CAAA4sC,iBAAA,CAAsBmB,CAAtB,CAAV,CAD8D,CAAhE,CADoC,CAAtC,CAKIE,EAAArqC,KAAJ,EACO5D,CAAA+hB,MAAAuwB,gBAGL,EAFEtyC,CAAAo8D,oBAAA,CAAyBnuB,CAAAx0C,QAAzB,CAEF,CAAA8/B,CAAA,CAAav5B,CAAAw8D,OAAA,CAAYvuB,CAAAx0C,QAAZ,CAA0Bw0C,CAAArqC,KAA1B,CAAqCqqC,CAAAS,SAArC,CAAb,CAAmE,GAAnE,CAAyEtyB,CAAAtZ,KAAA,CAAU,GAAV,CAAzE,CAA0F,GAJ5F,EAMEy2B,CANF,CAMe2U,CANf,CAMuB,GANvB,CAM6B9xB,CAAAtZ,KAAA,CAAU,GAAV,CAN7B,CAM8C,GAE9Cy2B,EAAA,CAAav5B,CAAA4sC,iBAAA,CAAsBrT,CAAtB,CACbv5B,EAAAy2B,OAAA,CAAYskC,CAAZ,CAAoBxhC,CAApB,CAhBuC,CAAzC,CAiBG,QAAQ,EAAG,CACZv5B,CAAAy2B,OAAA,CAAYskC,CAAZ,CAAoB,WAApB,CADY,CAjBd,CAoBAW,EAAA,CAAYX,CAAZ,CArB+C,CAAjD,CAfF,CAuCA,MACF,MAAKttB,CAAAoB,qBAAL,CACEX,CAAA;AAAQ,IAAAosB,OAAA,EACRrsB,EAAA,CAAO,EACP,IAAK,CAAAmB,EAAA,CAAa9B,CAAAW,KAAb,CAAL,CACE,KAAMtB,GAAA,CAAa,MAAb,CAAN,CAEF,IAAAiuB,QAAA,CAAattB,CAAAW,KAAb,CAAuBr1C,CAAvB,CAAkCq1C,CAAlC,CAAwC,QAAQ,EAAG,CACjDjuC,CAAA47D,IAAA,CAAS57D,CAAAq8D,QAAA,CAAapuB,CAAAx0C,QAAb,CAAT,CAAqC,QAAQ,EAAG,CAC9CuG,CAAA46D,QAAA,CAAattB,CAAAY,MAAb,CAAwBA,CAAxB,CACAluC,EAAAo8D,oBAAA,CAAyBp8D,CAAAw8D,OAAA,CAAYvuB,CAAAx0C,QAAZ,CAA0Bw0C,CAAArqC,KAA1B,CAAqCqqC,CAAAS,SAArC,CAAzB,CACAnV,EAAA,CAAav5B,CAAAw8D,OAAA,CAAYvuB,CAAAx0C,QAAZ,CAA0Bw0C,CAAArqC,KAA1B,CAAqCqqC,CAAAS,SAArC,CAAb,CAAmEpB,CAAAiC,SAAnE,CAAkFrB,CAClFluC,EAAAy2B,OAAA,CAAYskC,CAAZ,CAAoBxhC,CAApB,CACAmiC,EAAA,CAAYX,CAAZ,EAAsBxhC,CAAtB,CAL8C,CAAhD,CADiD,CAAnD,CAQG,CARH,CASA,MACF,MAAKkU,CAAAqB,gBAAL,CACE1yB,CAAA,CAAO,EACP7iB,EAAA,CAAQ+zC,CAAAt0B,SAAR,CAAsB,QAAQ,CAAC20B,CAAD,CAAO,CACnC3tC,CAAA46D,QAAA,CAAajtB,CAAb,CAAmB3tC,CAAAs6D,OAAA,EAAnB,CAAkC1hE,CAAlC,CAA6C,QAAQ,CAACm1C,CAAD,CAAW,CAC9D3xB,CAAAxd,KAAA,CAAUmvC,CAAV,CAD8D,CAAhE,CADmC,CAArC,CAKAxU,EAAA,CAAa,GAAb,CAAmBnd,CAAAtZ,KAAA,CAAU,GAAV,CAAnB,CAAoC,GACpC,KAAA2zB,OAAA,CAAYskC,CAAZ,CAAoBxhC,CAApB,CACAmiC,EAAA,CAAYniC,CAAZ,CACA,MACF,MAAKkU,CAAAsB,iBAAL,CACE3yB,CAAA,CAAO,EACP7iB,EAAA,CAAQ+zC,CAAA0B,WAAR,CAAwB,QAAQ,CAACxF,CAAD,CAAW,CACzCxpC,CAAA46D,QAAA,CAAapxB,CAAAlvC,MAAb;AAA6B0F,CAAAs6D,OAAA,EAA7B,CAA4C1hE,CAA5C,CAAuD,QAAQ,CAAC+0C,CAAD,CAAO,CACpEvxB,CAAAxd,KAAA,CAAUoB,CAAA2hC,OAAA,CACN6H,CAAA9vC,IAAA6d,KAAA,GAAsBk2B,CAAAc,WAAtB,CAAuC/E,CAAA9vC,IAAAkK,KAAvC,CACG,EADH,CACQ4lC,CAAA9vC,IAAAY,MAFF,CAAV,CAGI,GAHJ,CAGUqzC,CAHV,CADoE,CAAtE,CADyC,CAA3C,CAQApU,EAAA,CAAa,GAAb,CAAmBnd,CAAAtZ,KAAA,CAAU,GAAV,CAAnB,CAAoC,GACpC,KAAA2zB,OAAA,CAAYskC,CAAZ,CAAoBxhC,CAApB,CACAmiC,EAAA,CAAYniC,CAAZ,CACA,MACF,MAAKkU,CAAAwB,eAAL,CACE,IAAAxY,OAAA,CAAYskC,CAAZ,CAAoB,GAApB,CACAW,EAAA,CAAY,GAAZ,CACA,MACF,MAAKjuB,CAAA6B,iBAAL,CACE,IAAA7Y,OAAA,CAAYskC,CAAZ,CAAoB,GAApB,CACA,CAAAW,CAAA,CAAY,GAAZ,CAxMF,CAX4E,CAhHxD,CAwUtBQ,kBAAmBA,QAAQ,CAACr+D,CAAD,CAAU2rC,CAAV,CAAoB,CAC7C,IAAI9vC,EAAMmE,CAANnE,CAAgB,GAAhBA,CAAsB8vC,CAA1B,CACIgxB,EAAM,IAAA5iB,QAAA,EAAA4iB,IACLA,EAAA5gE,eAAA,CAAmBF,CAAnB,CAAL,GACE8gE,CAAA,CAAI9gE,CAAJ,CADF,CACa,IAAA4gE,OAAA,CAAY,CAAA,CAAZ,CAAmBz8D,CAAnB,CAA6B,KAA7B,CAAqC,IAAA8jC,OAAA,CAAY6H,CAAZ,CAArC,CAA6D,MAA7D,CAAsE3rC,CAAtE,CAAgF,GAAhF,CADb,CAGA,OAAO28D,EAAA,CAAI9gE,CAAJ,CANsC,CAxUzB,CAiVtB+8B,OAAQA,QAAQ,CAAClR,CAAD,CAAKjrB,CAAL,CAAY,CAC1B,GAAKirB,CAAL,CAEA,MADA,KAAAqyB,QAAA,EAAAtX,KAAA1hC,KAAA,CAAyB2mB,CAAzB,CAA6B,GAA7B,CAAkCjrB,CAAlC,CAAyC,GAAzC,CACOirB,CAAAA,CAHmB,CAjVN,CAuVtBnb,OAAQA,QAAQ,CAACqyD,CAAD,CAAa,CACtB,IAAA16C,MAAAw/B,QAAA3nD,eAAA,CAAkC6iE,CAAlC,CAAL;CACE,IAAA16C,MAAAw/B,QAAA,CAAmBkb,CAAnB,CADF,CACmC,IAAAnC,OAAA,CAAY,CAAA,CAAZ,CADnC,CAGA,OAAO,KAAAv4C,MAAAw/B,QAAA,CAAmBkb,CAAnB,CAJoB,CAvVP,CA8VtBvvB,UAAWA,QAAQ,CAAC3nB,CAAD,CAAKm3C,CAAL,CAAmB,CACpC,MAAO,YAAP,CAAsBn3C,CAAtB,CAA2B,GAA3B,CAAiC,IAAAoc,OAAA,CAAY+6B,CAAZ,CAAjC,CAA6D,GADzB,CA9VhB,CAkWtBV,KAAMA,QAAQ,CAAC/tB,CAAD,CAAOC,CAAP,CAAc,CAC1B,MAAO,OAAP,CAAiBD,CAAjB,CAAwB,GAAxB,CAA8BC,CAA9B,CAAsC,GADZ,CAlWN,CAsWtB8sB,QAASA,QAAQ,CAACz1C,CAAD,CAAK,CACpB,IAAAqyB,QAAA,EAAAtX,KAAA1hC,KAAA,CAAyB,SAAzB,CAAoC2mB,CAApC,CAAwC,GAAxC,CADoB,CAtWA,CA0WtBq2C,IAAKA,QAAQ,CAACj9D,CAAD,CAAO0vC,CAAP,CAAkBC,CAAlB,CAA8B,CACzC,GAAa,CAAA,CAAb,GAAI3vC,CAAJ,CACE0vC,CAAA,EADF,KAEO,CACL,IAAI/N,EAAO,IAAAsX,QAAA,EAAAtX,KACXA,EAAA1hC,KAAA,CAAU,KAAV,CAAiBD,CAAjB,CAAuB,IAAvB,CACA0vC,EAAA,EACA/N,EAAA1hC,KAAA,CAAU,GAAV,CACI0vC,EAAJ,GACEhO,CAAA1hC,KAAA,CAAU,OAAV,CAEA,CADA0vC,CAAA,EACA,CAAAhO,CAAA1hC,KAAA,CAAU,GAAV,CAHF,CALK,CAHkC,CA1WrB,CA0XtBq9D,IAAKA,QAAQ,CAAC1iC,CAAD,CAAa,CACxB,MAAO,IAAP,CAAcA,CAAd,CAA2B,GADH,CA1XJ,CA8XtB8iC,QAASA,QAAQ,CAAC9iC,CAAD,CAAa,CAC5B,MAAOA,EAAP,CAAoB,QADQ,CA9XR,CAkYtB4iC,kBAAmBA,QAAQ,CAACluB,CAAD,CAAOC,CAAP,CAAc,CACvC,MAAOD,EAAP;AAAc,GAAd,CAAoBC,CADmB,CAlYnB,CAsYtB4tB,eAAgBA,QAAQ,CAAC7tB,CAAD,CAAOC,CAAP,CAAc,CACpC,MAAOD,EAAP,CAAc,GAAd,CAAoBC,CAApB,CAA4B,GADQ,CAtYhB,CA0YtBsuB,OAAQA,QAAQ,CAACvuB,CAAD,CAAOC,CAAP,CAAcQ,CAAd,CAAwB,CACtC,MAAIA,EAAJ,CAAqB,IAAAotB,eAAA,CAAoB7tB,CAApB,CAA0BC,CAA1B,CAArB,CACO,IAAAiuB,kBAAA,CAAuBluB,CAAvB,CAA6BC,CAA7B,CAF+B,CA1YlB,CA+YtBkuB,oBAAqBA,QAAQ,CAACzZ,CAAD,CAAO,CAClC,IAAA/K,QAAA,EAAAtX,KAAA1hC,KAAA,CAAyB,IAAAguC,iBAAA,CAAsB+V,CAAtB,CAAzB,CAAsD,GAAtD,CADkC,CA/Yd,CAmZtB2Z,wBAAyBA,QAAQ,CAAC3Z,CAAD,CAAO,CACtC,IAAA/K,QAAA,EAAAtX,KAAA1hC,KAAA,CAAyB,IAAA6tC,qBAAA,CAA0BkW,CAA1B,CAAzB,CAA0D,GAA1D,CADsC,CAnZlB,CAuZtB4Z,sBAAuBA,QAAQ,CAAC5Z,CAAD,CAAO,CACpC,IAAA/K,QAAA,EAAAtX,KAAA1hC,KAAA,CAAyB,IAAAkuC,mBAAA,CAAwB6V,CAAxB,CAAzB,CAAwD,GAAxD,CADoC,CAvZhB,CA2ZtB/V,iBAAkBA,QAAQ,CAAC+V,CAAD,CAAO,CAC/B,MAAO,mBAAP,CAA6BA,CAA7B,CAAoC,QADL,CA3ZX,CA+ZtBlW,qBAAsBA,QAAQ,CAACkW,CAAD,CAAO,CACnC,MAAO,uBAAP;AAAiCA,CAAjC,CAAwC,QADL,CA/Zf,CAmatB7V,mBAAoBA,QAAQ,CAAC6V,CAAD,CAAO,CACjC,MAAO,qBAAP,CAA+BA,CAA/B,CAAsC,QADL,CAnab,CAuatBoZ,YAAaA,QAAQ,CAACzuB,CAAD,CAAMytB,CAAN,CAAcU,CAAd,CAAsBC,CAAtB,CAAmCx/D,CAAnC,CAA2Cy/D,CAA3C,CAA6D,CAChF,IAAI37D,EAAO,IACX,OAAO,SAAQ,EAAG,CAChBA,CAAA46D,QAAA,CAAattB,CAAb,CAAkBytB,CAAlB,CAA0BU,CAA1B,CAAkCC,CAAlC,CAA+Cx/D,CAA/C,CAAuDy/D,CAAvD,CADgB,CAF8D,CAva5D,CA8atBE,WAAYA,QAAQ,CAACt2C,CAAD,CAAKjrB,CAAL,CAAY,CAC9B,IAAI0F,EAAO,IACX,OAAO,SAAQ,EAAG,CAChBA,CAAAy2B,OAAA,CAAYlR,CAAZ,CAAgBjrB,CAAhB,CADgB,CAFY,CA9aV,CAqbtBqiE,kBAAmB,gBArbG,CAubtBC,eAAgBA,QAAQ,CAACC,CAAD,CAAI,CAC1B,MAAO,KAAP,CAAephE,CAAC,MAADA,CAAUohE,CAAAC,WAAA,CAAa,CAAb,CAAAtgE,SAAA,CAAyB,EAAzB,CAAVf,OAAA,CAA+C,EAA/C,CADW,CAvbN,CA2btBkmC,OAAQA,QAAQ,CAACrnC,CAAD,CAAQ,CACtB,GAAIjB,CAAA,CAASiB,CAAT,CAAJ,CAAqB,MAAO,GAAP,CAAaA,CAAA8H,QAAA,CAAc,IAAAu6D,kBAAd,CAAsC,IAAAC,eAAtC,CAAb,CAA0E,GAC/F,IAAI//D,CAAA,CAASvC,CAAT,CAAJ,CAAqB,MAAOA,EAAAkC,SAAA,EAC5B,IAAc,CAAA,CAAd,GAAIlC,CAAJ,CAAoB,MAAO,MAC3B;GAAc,CAAA,CAAd,GAAIA,CAAJ,CAAqB,MAAO,OAC5B,IAAc,IAAd,GAAIA,CAAJ,CAAoB,MAAO,MAC3B,IAAqB,WAArB,GAAI,MAAOA,EAAX,CAAkC,MAAO,WAEzC,MAAMqyC,GAAA,CAAa,KAAb,CAAN,CARsB,CA3bF,CAsctB2tB,OAAQA,QAAQ,CAACyC,CAAD,CAAOC,CAAP,CAAa,CAC3B,IAAIz3C,EAAK,GAALA,CAAY,IAAAxD,MAAAu4C,OAAA,EACXyC,EAAL,EACE,IAAAnlB,QAAA,EAAA2iB,KAAA37D,KAAA,CAAyB2mB,CAAzB,EAA+By3C,CAAA,CAAO,GAAP,CAAaA,CAAb,CAAoB,EAAnD,EAEF,OAAOz3C,EALoB,CAtcP,CA8ctBqyB,QAASA,QAAQ,EAAG,CAClB,MAAO,KAAA71B,MAAA,CAAW,IAAAA,MAAA44C,UAAX,CADW,CA9cE,CAydxBhrB,GAAAlzC,UAAA,CAA2B,CACzBqI,QAASA,QAAQ,CAACy0B,CAAD,CAAa+Y,CAAb,CAA8B,CAC7C,IAAItyC,EAAO,IAAX,CACIstC,EAAM,IAAAoC,WAAApC,IAAA,CAAoB/T,CAApB,CACV,KAAAA,WAAA,CAAkBA,CAClB,KAAA+Y,gBAAA,CAAuBA,CACvBjF,EAAA,CAAgCC,CAAhC,CAAqCttC,CAAA2R,QAArC,CACA,KAAI8oD,CAAJ,CACIhkC,CACJ,IAAKgkC,CAAL,CAAkBprB,EAAA,CAAc/B,CAAd,CAAlB,CACE7W,CAAA,CAAS,IAAAmkC,QAAA,CAAaH,CAAb,CAEP5sB,EAAAA,CAAUqB,EAAA,CAAU5B,CAAAhN,KAAV,CACd,KAAIsQ,CACA/C,EAAJ,GACE+C,CACA,CADS,EACT,CAAAr3C,CAAA,CAAQs0C,CAAR,CAAiB,QAAQ,CAACqM,CAAD,CAAQxgD,CAAR,CAAa,CACpC,IAAI2R,EAAQrL,CAAA46D,QAAA,CAAa1gB,CAAb,CACZA;CAAA7uC,MAAA,CAAcA,CACdulC,EAAAhyC,KAAA,CAAYyM,CAAZ,CACA6uC,EAAA+gB,QAAA,CAAgBvhE,CAJoB,CAAtC,CAFF,CASA,KAAI46B,EAAc,EAClB/6B,EAAA,CAAQ+zC,CAAAhN,KAAR,CAAkB,QAAQ,CAAC/G,CAAD,CAAa,CACrCjF,CAAA11B,KAAA,CAAiBoB,CAAA46D,QAAA,CAAarhC,CAAAA,WAAb,CAAjB,CADqC,CAAvC,CAGIt5B,EAAAA,CAAyB,CAApB,GAAAqtC,CAAAhN,KAAArnC,OAAA,CAAwB,QAAQ,EAAG,EAAnC,CACoB,CAApB,GAAAq0C,CAAAhN,KAAArnC,OAAA,CAAwBq7B,CAAA,CAAY,CAAZ,CAAxB,CACA,QAAQ,CAACzvB,CAAD,CAAQwZ,CAAR,CAAgB,CACtB,IAAI8X,CACJ58B,EAAA,CAAQ+6B,CAAR,CAAqB,QAAQ,CAACoO,CAAD,CAAM,CACjCvM,CAAA,CAAYuM,CAAA,CAAI79B,CAAJ,CAAWwZ,CAAX,CADqB,CAAnC,CAGA,OAAO8X,EALe,CAO7BM,EAAJ,GACEx2B,CAAAw2B,OADF,CACcwmC,QAAQ,CAACp4D,CAAD,CAAQvK,CAAR,CAAe+jB,CAAf,CAAuB,CACzC,MAAOoY,EAAA,CAAO5xB,CAAP,CAAcwZ,CAAd,CAAsB/jB,CAAtB,CADkC,CAD7C,CAKIs2C,EAAJ,GACE3wC,CAAA2wC,OADF,CACcA,CADd,CAGA3wC,EAAAu2B,QAAA,CAAagZ,EAAA,CAAUlC,CAAV,CACbrtC,EAAAgK,SAAA,CAAyBqjC,CA9gBpBrjC,SA+gBL,OAAOhK,EA7CsC,CADtB,CAiDzB26D,QAASA,QAAQ,CAACttB,CAAD,CAAM7zC,CAAN,CAAeyC,CAAf,CAAuB,CAAA,IAClC+xC,CADkC,CAC5BC,CAD4B,CACrBluC,EAAO,IADc,CACRoc,CAC9B,IAAIkxB,CAAAjiC,MAAJ,CACE,MAAO,KAAAulC,OAAA,CAAYtD,CAAAjiC,MAAZ,CAAuBiiC,CAAA2tB,QAAvB,CAET,QAAQ3tB,CAAA/1B,KAAR,EACA,KAAKk2B,CAAAG,QAAL,CACE,MAAO,KAAAtzC,MAAA,CAAWgzC,CAAAhzC,MAAX,CAAsBb,CAAtB,CACT,MAAKg0C,CAAAK,gBAAL,CAEE,MADAI,EACO;AADC,IAAA0sB,QAAA,CAAattB,CAAAS,SAAb,CACD,CAAA,IAAA,CAAK,OAAL,CAAeT,CAAAiC,SAAf,CAAA,CAA6BrB,CAA7B,CAAoCz0C,CAApC,CACT,MAAKg0C,CAAAO,iBAAL,CAGE,MAFAC,EAEO,CAFA,IAAA2sB,QAAA,CAAattB,CAAAW,KAAb,CAEA,CADPC,CACO,CADC,IAAA0sB,QAAA,CAAattB,CAAAY,MAAb,CACD,CAAA,IAAA,CAAK,QAAL,CAAgBZ,CAAAiC,SAAhB,CAAA,CAA8BtB,CAA9B,CAAoCC,CAApC,CAA2Cz0C,CAA3C,CACT,MAAKg0C,CAAAU,kBAAL,CAGE,MAFAF,EAEO,CAFA,IAAA2sB,QAAA,CAAattB,CAAAW,KAAb,CAEA,CADPC,CACO,CADC,IAAA0sB,QAAA,CAAattB,CAAAY,MAAb,CACD,CAAA,IAAA,CAAK,QAAL,CAAgBZ,CAAAiC,SAAhB,CAAA,CAA8BtB,CAA9B,CAAoCC,CAApC,CAA2Cz0C,CAA3C,CACT,MAAKg0C,CAAAW,sBAAL,CACE,MAAO,KAAA,CAAK,WAAL,CAAA,CACL,IAAAwsB,QAAA,CAAattB,CAAA3uC,KAAb,CADK,CAEL,IAAAi8D,QAAA,CAAattB,CAAAe,UAAb,CAFK,CAGL,IAAAusB,QAAA,CAAattB,CAAAgB,WAAb,CAHK,CAIL70C,CAJK,CAMT,MAAKg0C,CAAAc,WAAL,CAEE,MADA9B,GAAA,CAAqBa,CAAA1pC,KAArB,CAA+B5D,CAAAu5B,WAA/B,CACO,CAAAv5B,CAAAiwB,WAAA,CAAgBqd,CAAA1pC,KAAhB,CACgB5D,CAAAsyC,gBADhB,EACwCtC,EAAA,CAA8B1C,CAAA1pC,KAA9B,CADxC;AAEgBnK,CAFhB,CAEyByC,CAFzB,CAEiC8D,CAAAu5B,WAFjC,CAGT,MAAKkU,CAAAe,iBAAL,CAOE,MANAP,EAMO,CANA,IAAA2sB,QAAA,CAAattB,CAAAmB,OAAb,CAAyB,CAAA,CAAzB,CAAgC,CAAEvyC,CAAAA,CAAlC,CAMA,CALFoxC,CAAAoB,SAKE,GAJLjC,EAAA,CAAqBa,CAAA9D,SAAA5lC,KAArB,CAAwC5D,CAAAu5B,WAAxC,CACA,CAAA2U,CAAA,CAAQZ,CAAA9D,SAAA5lC,KAGH,EADH0pC,CAAAoB,SACG,GADWR,CACX,CADmB,IAAA0sB,QAAA,CAAattB,CAAA9D,SAAb,CACnB,EAAA8D,CAAAoB,SAAA,CACL,IAAAotB,eAAA,CAAoB7tB,CAApB,CAA0BC,CAA1B,CAAiCz0C,CAAjC,CAA0CyC,CAA1C,CAAkD8D,CAAAu5B,WAAlD,CADK,CAEL,IAAA4iC,kBAAA,CAAuBluB,CAAvB,CAA6BC,CAA7B,CAAoCluC,CAAAsyC,gBAApC,CAA0D74C,CAA1D,CAAmEyC,CAAnE,CAA2E8D,CAAAu5B,WAA3E,CACJ,MAAKkU,CAAAkB,eAAL,CAOE,MANAvyB,EAMO,CANA,EAMA,CALP7iB,CAAA,CAAQ+zC,CAAA5xC,UAAR,CAAuB,QAAQ,CAACiyC,CAAD,CAAO,CACpCvxB,CAAAxd,KAAA,CAAUoB,CAAA46D,QAAA,CAAajtB,CAAb,CAAV,CADoC,CAAtC,CAKO,CAFHL,CAAAljC,OAEG,GAFS8jC,CAET,CAFiB,IAAAv8B,QAAA,CAAa27B,CAAAsB,OAAAhrC,KAAb,CAEjB,EADF0pC,CAAAljC,OACE,GADU8jC,CACV,CADkB,IAAA0sB,QAAA,CAAattB,CAAAsB,OAAb,CAAyB,CAAA,CAAzB,CAClB,EAAAtB,CAAAljC,OAAA,CACL,QAAQ,CAACvF,CAAD,CAAQwZ,CAAR,CAAgBoY,CAAhB,CAAwBma,CAAxB,CAAgC,CAEtC,IADA,IAAIhY;AAAS,EAAb,CACSz+B,EAAI,CAAb,CAAgBA,CAAhB,CAAoBiiB,CAAAnjB,OAApB,CAAiC,EAAEkB,CAAnC,CACEy+B,CAAAh6B,KAAA,CAAYwd,CAAA,CAAKjiB,CAAL,CAAA,CAAQ0K,CAAR,CAAewZ,CAAf,CAAuBoY,CAAvB,CAA+Bma,CAA/B,CAAZ,CAEEt2C,EAAAA,CAAQ4zC,CAAA9tC,MAAA,CAAYxH,CAAZ,CAAuBggC,CAAvB,CAA+BgY,CAA/B,CACZ,OAAOn3C,EAAA,CAAU,CAACA,QAASb,CAAV,CAAqBgL,KAAMhL,CAA3B,CAAsC0B,MAAOA,CAA7C,CAAV,CAAgEA,CANjC,CADnC,CASL,QAAQ,CAACuK,CAAD,CAAQwZ,CAAR,CAAgBoY,CAAhB,CAAwBma,CAAxB,CAAgC,CACtC,IAAIssB,EAAMhvB,CAAA,CAAMrpC,CAAN,CAAawZ,CAAb,CAAqBoY,CAArB,CAA6Bma,CAA7B,CAAV,CACIt2C,CACJ,IAAiB,IAAjB,EAAI4iE,CAAA5iE,MAAJ,CAAuB,CACrBsyC,EAAA,CAAiBswB,CAAAzjE,QAAjB,CAA8BuG,CAAAu5B,WAA9B,CACAuT,GAAA,CAAmBowB,CAAA5iE,MAAnB,CAA8B0F,CAAAu5B,WAA9B,CACIX,EAAAA,CAAS,EACb,KAAS,IAAAz+B,EAAI,CAAb,CAAgBA,CAAhB,CAAoBiiB,CAAAnjB,OAApB,CAAiC,EAAEkB,CAAnC,CACEy+B,CAAAh6B,KAAA,CAAYguC,EAAA,CAAiBxwB,CAAA,CAAKjiB,CAAL,CAAA,CAAQ0K,CAAR,CAAewZ,CAAf,CAAuBoY,CAAvB,CAA+Bma,CAA/B,CAAjB,CAAyD5wC,CAAAu5B,WAAzD,CAAZ,CAEFj/B,EAAA,CAAQsyC,EAAA,CAAiBswB,CAAA5iE,MAAA8F,MAAA,CAAgB88D,CAAAzjE,QAAhB,CAA6Bm/B,CAA7B,CAAjB,CAAuD54B,CAAAu5B,WAAvD,CAPa,CASvB,MAAO9/B,EAAA,CAAU,CAACa,MAAOA,CAAR,CAAV,CAA2BA,CAZI,CAc5C,MAAKmzC,CAAAoB,qBAAL,CAGE,MAFAZ,EAEO,CAFA,IAAA2sB,QAAA,CAAattB,CAAAW,KAAb,CAAuB,CAAA,CAAvB,CAA6B,CAA7B,CAEA,CADPC,CACO,CADC,IAAA0sB,QAAA,CAAattB,CAAAY,MAAb,CACD,CAAA,QAAQ,CAACrpC,CAAD,CAAQwZ,CAAR,CAAgBoY,CAAhB,CAAwBma,CAAxB,CAAgC,CAC7C,IAAIusB,EAAMlvB,CAAA,CAAKppC,CAAL,CAAYwZ,CAAZ,CAAoBoY,CAApB,CAA4Bma,CAA5B,CACNssB,EAAAA,CAAMhvB,CAAA,CAAMrpC,CAAN,CAAawZ,CAAb,CAAqBoY,CAArB,CAA6Bma,CAA7B,CACVhE,GAAA,CAAiBuwB,CAAA7iE,MAAjB,CAA4B0F,CAAAu5B,WAA5B,CACA4jC;CAAA1jE,QAAA,CAAY0jE,CAAAv5D,KAAZ,CAAA,CAAwBs5D,CACxB,OAAOzjE,EAAA,CAAU,CAACa,MAAO4iE,CAAR,CAAV,CAAyBA,CALa,CAOjD,MAAKzvB,CAAAqB,gBAAL,CAKE,MAJA1yB,EAIO,CAJA,EAIA,CAHP7iB,CAAA,CAAQ+zC,CAAAt0B,SAAR,CAAsB,QAAQ,CAAC20B,CAAD,CAAO,CACnCvxB,CAAAxd,KAAA,CAAUoB,CAAA46D,QAAA,CAAajtB,CAAb,CAAV,CADmC,CAArC,CAGO,CAAA,QAAQ,CAAC9oC,CAAD,CAAQwZ,CAAR,CAAgBoY,CAAhB,CAAwBma,CAAxB,CAAgC,CAE7C,IADA,IAAIt2C,EAAQ,EAAZ,CACSH,EAAI,CAAb,CAAgBA,CAAhB,CAAoBiiB,CAAAnjB,OAApB,CAAiC,EAAEkB,CAAnC,CACEG,CAAAsE,KAAA,CAAWwd,CAAA,CAAKjiB,CAAL,CAAA,CAAQ0K,CAAR,CAAewZ,CAAf,CAAuBoY,CAAvB,CAA+Bma,CAA/B,CAAX,CAEF,OAAOn3C,EAAA,CAAU,CAACa,MAAOA,CAAR,CAAV,CAA2BA,CALW,CAOjD,MAAKmzC,CAAAsB,iBAAL,CASE,MARA3yB,EAQO,CARA,EAQA,CAPP7iB,CAAA,CAAQ+zC,CAAA0B,WAAR,CAAwB,QAAQ,CAACxF,CAAD,CAAW,CACzCptB,CAAAxd,KAAA,CAAU,CAAClF,IAAK8vC,CAAA9vC,IAAA6d,KAAA,GAAsBk2B,CAAAc,WAAtB,CACA/E,CAAA9vC,IAAAkK,KADA,CAEC,EAFD,CAEM4lC,CAAA9vC,IAAAY,MAFZ,CAGCA,MAAO0F,CAAA46D,QAAA,CAAapxB,CAAAlvC,MAAb,CAHR,CAAV,CADyC,CAA3C,CAOO,CAAA,QAAQ,CAACuK,CAAD,CAAQwZ,CAAR,CAAgBoY,CAAhB,CAAwBma,CAAxB,CAAgC,CAE7C,IADA,IAAIt2C,EAAQ,EAAZ,CACSH,EAAI,CAAb,CAAgBA,CAAhB,CAAoBiiB,CAAAnjB,OAApB,CAAiC,EAAEkB,CAAnC,CACEG,CAAA,CAAM8hB,CAAA,CAAKjiB,CAAL,CAAAT,IAAN,CAAA,CAAqB0iB,CAAA,CAAKjiB,CAAL,CAAAG,MAAA,CAAcuK,CAAd,CAAqBwZ,CAArB,CAA6BoY,CAA7B,CAAqCma,CAArC,CAEvB,OAAOn3C,EAAA,CAAU,CAACa,MAAOA,CAAR,CAAV,CAA2BA,CALW,CAOjD,MAAKmzC,CAAAwB,eAAL,CACE,MAAO,SAAQ,CAACpqC,CAAD,CAAQ,CACrB,MAAOpL,EAAA;AAAU,CAACa,MAAOuK,CAAR,CAAV,CAA2BA,CADb,CAGzB,MAAK4oC,CAAA6B,iBAAL,CACE,MAAO,SAAQ,CAACzqC,CAAD,CAAQwZ,CAAR,CAAgBoY,CAAhB,CAAwBma,CAAxB,CAAgC,CAC7C,MAAOn3C,EAAA,CAAU,CAACa,MAAOm8B,CAAR,CAAV,CAA4BA,CADU,CA7GjD,CALsC,CAjDf,CAyKzB,SAAU2mC,QAAQ,CAACrvB,CAAD,CAAWt0C,CAAX,CAAoB,CACpC,MAAO,SAAQ,CAACoL,CAAD,CAAQwZ,CAAR,CAAgBoY,CAAhB,CAAwBma,CAAxB,CAAgC,CACzClpC,CAAAA,CAAMqmC,CAAA,CAASlpC,CAAT,CAAgBwZ,CAAhB,CAAwBoY,CAAxB,CAAgCma,CAAhC,CAERlpC,EAAA,CADE/K,CAAA,CAAU+K,CAAV,CAAJ,CACQ,CAACA,CADT,CAGQ,CAER,OAAOjO,EAAA,CAAU,CAACa,MAAOoN,CAAR,CAAV,CAAyBA,CAPa,CADX,CAzKb,CAoLzB,SAAU21D,QAAQ,CAACtvB,CAAD,CAAWt0C,CAAX,CAAoB,CACpC,MAAO,SAAQ,CAACoL,CAAD,CAAQwZ,CAAR,CAAgBoY,CAAhB,CAAwBma,CAAxB,CAAgC,CACzClpC,CAAAA,CAAMqmC,CAAA,CAASlpC,CAAT,CAAgBwZ,CAAhB,CAAwBoY,CAAxB,CAAgCma,CAAhC,CAERlpC,EAAA,CADE/K,CAAA,CAAU+K,CAAV,CAAJ,CACQ,CAACA,CADT,CAGQ,CAER,OAAOjO,EAAA,CAAU,CAACa,MAAOoN,CAAR,CAAV,CAAyBA,CAPa,CADX,CApLb,CA+LzB,SAAU41D,QAAQ,CAACvvB,CAAD,CAAWt0C,CAAX,CAAoB,CACpC,MAAO,SAAQ,CAACoL,CAAD,CAAQwZ,CAAR,CAAgBoY,CAAhB,CAAwBma,CAAxB,CAAgC,CACzClpC,CAAAA,CAAM,CAACqmC,CAAA,CAASlpC,CAAT,CAAgBwZ,CAAhB,CAAwBoY,CAAxB,CAAgCma,CAAhC,CACX,OAAOn3C,EAAA,CAAU,CAACa,MAAOoN,CAAR,CAAV,CAAyBA,CAFa,CADX,CA/Lb,CAqMzB,UAAW61D,QAAQ,CAACtvB,CAAD,CAAOC,CAAP,CAAcz0C,CAAd,CAAuB,CACxC,MAAO,SAAQ,CAACoL,CAAD,CAAQwZ,CAAR,CAAgBoY,CAAhB,CAAwBma,CAAxB,CAAgC,CAC7C,IAAIusB,EAAMlvB,CAAA,CAAKppC,CAAL,CAAYwZ,CAAZ,CAAoBoY,CAApB,CAA4Bma,CAA5B,CACNssB,EAAAA,CAAMhvB,CAAA,CAAMrpC,CAAN,CAAawZ,CAAb,CAAqBoY,CAArB,CAA6Bma,CAA7B,CACNlpC,EAAAA,CAAMylC,EAAA,CAAOgwB,CAAP,CAAYD,CAAZ,CACV,OAAOzjE,EAAA,CAAU,CAACa,MAAOoN,CAAR,CAAV,CAAyBA,CAJa,CADP,CArMjB,CA6MzB,UAAW81D,QAAQ,CAACvvB,CAAD,CAAOC,CAAP,CAAcz0C,CAAd,CAAuB,CACxC,MAAO,SAAQ,CAACoL,CAAD;AAAQwZ,CAAR,CAAgBoY,CAAhB,CAAwBma,CAAxB,CAAgC,CAC7C,IAAIusB,EAAMlvB,CAAA,CAAKppC,CAAL,CAAYwZ,CAAZ,CAAoBoY,CAApB,CAA4Bma,CAA5B,CACNssB,EAAAA,CAAMhvB,CAAA,CAAMrpC,CAAN,CAAawZ,CAAb,CAAqBoY,CAArB,CAA6Bma,CAA7B,CACNlpC,EAAAA,EAAO/K,CAAA,CAAUwgE,CAAV,CAAA,CAAiBA,CAAjB,CAAuB,CAA9Bz1D,GAAoC/K,CAAA,CAAUugE,CAAV,CAAA,CAAiBA,CAAjB,CAAuB,CAA3Dx1D,CACJ,OAAOjO,EAAA,CAAU,CAACa,MAAOoN,CAAR,CAAV,CAAyBA,CAJa,CADP,CA7MjB,CAqNzB,UAAW+1D,QAAQ,CAACxvB,CAAD,CAAOC,CAAP,CAAcz0C,CAAd,CAAuB,CACxC,MAAO,SAAQ,CAACoL,CAAD,CAAQwZ,CAAR,CAAgBoY,CAAhB,CAAwBma,CAAxB,CAAgC,CACzClpC,CAAAA,CAAMumC,CAAA,CAAKppC,CAAL,CAAYwZ,CAAZ,CAAoBoY,CAApB,CAA4Bma,CAA5B,CAANlpC,CAA4CwmC,CAAA,CAAMrpC,CAAN,CAAawZ,CAAb,CAAqBoY,CAArB,CAA6Bma,CAA7B,CAChD,OAAOn3C,EAAA,CAAU,CAACa,MAAOoN,CAAR,CAAV,CAAyBA,CAFa,CADP,CArNjB,CA2NzB,UAAWg2D,QAAQ,CAACzvB,CAAD,CAAOC,CAAP,CAAcz0C,CAAd,CAAuB,CACxC,MAAO,SAAQ,CAACoL,CAAD,CAAQwZ,CAAR,CAAgBoY,CAAhB,CAAwBma,CAAxB,CAAgC,CACzClpC,CAAAA,CAAMumC,CAAA,CAAKppC,CAAL,CAAYwZ,CAAZ,CAAoBoY,CAApB,CAA4Bma,CAA5B,CAANlpC,CAA4CwmC,CAAA,CAAMrpC,CAAN,CAAawZ,CAAb,CAAqBoY,CAArB,CAA6Bma,CAA7B,CAChD,OAAOn3C,EAAA,CAAU,CAACa,MAAOoN,CAAR,CAAV,CAAyBA,CAFa,CADP,CA3NjB,CAiOzB,UAAWi2D,QAAQ,CAAC1vB,CAAD,CAAOC,CAAP,CAAcz0C,CAAd,CAAuB,CACxC,MAAO,SAAQ,CAACoL,CAAD,CAAQwZ,CAAR,CAAgBoY,CAAhB,CAAwBma,CAAxB,CAAgC,CACzClpC,CAAAA,CAAMumC,CAAA,CAAKppC,CAAL,CAAYwZ,CAAZ,CAAoBoY,CAApB,CAA4Bma,CAA5B,CAANlpC,CAA4CwmC,CAAA,CAAMrpC,CAAN,CAAawZ,CAAb,CAAqBoY,CAArB,CAA6Bma,CAA7B,CAChD,OAAOn3C,EAAA,CAAU,CAACa,MAAOoN,CAAR,CAAV,CAAyBA,CAFa,CADP,CAjOjB,CAuOzB,YAAak2D,QAAQ,CAAC3vB,CAAD,CAAOC,CAAP,CAAcz0C,CAAd,CAAuB,CAC1C,MAAO,SAAQ,CAACoL,CAAD,CAAQwZ,CAAR,CAAgBoY,CAAhB,CAAwBma,CAAxB,CAAgC,CACzClpC,CAAAA,CAAMumC,CAAA,CAAKppC,CAAL,CAAYwZ,CAAZ,CAAoBoY,CAApB,CAA4Bma,CAA5B,CAANlpC,GAA8CwmC,CAAA,CAAMrpC,CAAN,CAAawZ,CAAb,CAAqBoY,CAArB,CAA6Bma,CAA7B,CAClD,OAAOn3C,EAAA,CAAU,CAACa,MAAOoN,CAAR,CAAV,CAAyBA,CAFa,CADL,CAvOnB,CA6OzB,YAAam2D,QAAQ,CAAC5vB,CAAD;AAAOC,CAAP,CAAcz0C,CAAd,CAAuB,CAC1C,MAAO,SAAQ,CAACoL,CAAD,CAAQwZ,CAAR,CAAgBoY,CAAhB,CAAwBma,CAAxB,CAAgC,CACzClpC,CAAAA,CAAMumC,CAAA,CAAKppC,CAAL,CAAYwZ,CAAZ,CAAoBoY,CAApB,CAA4Bma,CAA5B,CAANlpC,GAA8CwmC,CAAA,CAAMrpC,CAAN,CAAawZ,CAAb,CAAqBoY,CAArB,CAA6Bma,CAA7B,CAClD,OAAOn3C,EAAA,CAAU,CAACa,MAAOoN,CAAR,CAAV,CAAyBA,CAFa,CADL,CA7OnB,CAmPzB,WAAYo2D,QAAQ,CAAC7vB,CAAD,CAAOC,CAAP,CAAcz0C,CAAd,CAAuB,CACzC,MAAO,SAAQ,CAACoL,CAAD,CAAQwZ,CAAR,CAAgBoY,CAAhB,CAAwBma,CAAxB,CAAgC,CACzClpC,CAAAA,CAAMumC,CAAA,CAAKppC,CAAL,CAAYwZ,CAAZ,CAAoBoY,CAApB,CAA4Bma,CAA5B,CAANlpC,EAA6CwmC,CAAA,CAAMrpC,CAAN,CAAawZ,CAAb,CAAqBoY,CAArB,CAA6Bma,CAA7B,CACjD,OAAOn3C,EAAA,CAAU,CAACa,MAAOoN,CAAR,CAAV,CAAyBA,CAFa,CADN,CAnPlB,CAyPzB,WAAYq2D,QAAQ,CAAC9vB,CAAD,CAAOC,CAAP,CAAcz0C,CAAd,CAAuB,CACzC,MAAO,SAAQ,CAACoL,CAAD,CAAQwZ,CAAR,CAAgBoY,CAAhB,CAAwBma,CAAxB,CAAgC,CACzClpC,CAAAA,CAAMumC,CAAA,CAAKppC,CAAL,CAAYwZ,CAAZ,CAAoBoY,CAApB,CAA4Bma,CAA5B,CAANlpC,EAA6CwmC,CAAA,CAAMrpC,CAAN,CAAawZ,CAAb,CAAqBoY,CAArB,CAA6Bma,CAA7B,CACjD,OAAOn3C,EAAA,CAAU,CAACa,MAAOoN,CAAR,CAAV,CAAyBA,CAFa,CADN,CAzPlB,CA+PzB,UAAWs2D,QAAQ,CAAC/vB,CAAD,CAAOC,CAAP,CAAcz0C,CAAd,CAAuB,CACxC,MAAO,SAAQ,CAACoL,CAAD,CAAQwZ,CAAR,CAAgBoY,CAAhB,CAAwBma,CAAxB,CAAgC,CACzClpC,CAAAA,CAAMumC,CAAA,CAAKppC,CAAL,CAAYwZ,CAAZ,CAAoBoY,CAApB,CAA4Bma,CAA5B,CAANlpC,CAA4CwmC,CAAA,CAAMrpC,CAAN,CAAawZ,CAAb,CAAqBoY,CAArB,CAA6Bma,CAA7B,CAChD,OAAOn3C,EAAA,CAAU,CAACa,MAAOoN,CAAR,CAAV,CAAyBA,CAFa,CADP,CA/PjB,CAqQzB,UAAWu2D,QAAQ,CAAChwB,CAAD,CAAOC,CAAP,CAAcz0C,CAAd,CAAuB,CACxC,MAAO,SAAQ,CAACoL,CAAD,CAAQwZ,CAAR,CAAgBoY,CAAhB,CAAwBma,CAAxB,CAAgC,CACzClpC,CAAAA,CAAMumC,CAAA,CAAKppC,CAAL,CAAYwZ,CAAZ,CAAoBoY,CAApB,CAA4Bma,CAA5B,CAANlpC,CAA4CwmC,CAAA,CAAMrpC,CAAN,CAAawZ,CAAb,CAAqBoY,CAArB,CAA6Bma,CAA7B,CAChD,OAAOn3C,EAAA,CAAU,CAACa,MAAOoN,CAAR,CAAV,CAAyBA,CAFa,CADP,CArQjB,CA2QzB,WAAYw2D,QAAQ,CAACjwB,CAAD,CAAOC,CAAP,CAAcz0C,CAAd,CAAuB,CACzC,MAAO,SAAQ,CAACoL,CAAD;AAAQwZ,CAAR,CAAgBoY,CAAhB,CAAwBma,CAAxB,CAAgC,CACzClpC,CAAAA,CAAMumC,CAAA,CAAKppC,CAAL,CAAYwZ,CAAZ,CAAoBoY,CAApB,CAA4Bma,CAA5B,CAANlpC,EAA6CwmC,CAAA,CAAMrpC,CAAN,CAAawZ,CAAb,CAAqBoY,CAArB,CAA6Bma,CAA7B,CACjD,OAAOn3C,EAAA,CAAU,CAACa,MAAOoN,CAAR,CAAV,CAAyBA,CAFa,CADN,CA3QlB,CAiRzB,WAAYy2D,QAAQ,CAAClwB,CAAD,CAAOC,CAAP,CAAcz0C,CAAd,CAAuB,CACzC,MAAO,SAAQ,CAACoL,CAAD,CAAQwZ,CAAR,CAAgBoY,CAAhB,CAAwBma,CAAxB,CAAgC,CACzClpC,CAAAA,CAAMumC,CAAA,CAAKppC,CAAL,CAAYwZ,CAAZ,CAAoBoY,CAApB,CAA4Bma,CAA5B,CAANlpC,EAA6CwmC,CAAA,CAAMrpC,CAAN,CAAawZ,CAAb,CAAqBoY,CAArB,CAA6Bma,CAA7B,CACjD,OAAOn3C,EAAA,CAAU,CAACa,MAAOoN,CAAR,CAAV,CAAyBA,CAFa,CADN,CAjRlB,CAuRzB,WAAY02D,QAAQ,CAACnwB,CAAD,CAAOC,CAAP,CAAcz0C,CAAd,CAAuB,CACzC,MAAO,SAAQ,CAACoL,CAAD,CAAQwZ,CAAR,CAAgBoY,CAAhB,CAAwBma,CAAxB,CAAgC,CACzClpC,CAAAA,CAAMumC,CAAA,CAAKppC,CAAL,CAAYwZ,CAAZ,CAAoBoY,CAApB,CAA4Bma,CAA5B,CAANlpC,EAA6CwmC,CAAA,CAAMrpC,CAAN,CAAawZ,CAAb,CAAqBoY,CAArB,CAA6Bma,CAA7B,CACjD,OAAOn3C,EAAA,CAAU,CAACa,MAAOoN,CAAR,CAAV,CAAyBA,CAFa,CADN,CAvRlB,CA6RzB,WAAY22D,QAAQ,CAACpwB,CAAD,CAAOC,CAAP,CAAcz0C,CAAd,CAAuB,CACzC,MAAO,SAAQ,CAACoL,CAAD,CAAQwZ,CAAR,CAAgBoY,CAAhB,CAAwBma,CAAxB,CAAgC,CACzClpC,CAAAA,CAAMumC,CAAA,CAAKppC,CAAL,CAAYwZ,CAAZ,CAAoBoY,CAApB,CAA4Bma,CAA5B,CAANlpC,EAA6CwmC,CAAA,CAAMrpC,CAAN,CAAawZ,CAAb,CAAqBoY,CAArB,CAA6Bma,CAA7B,CACjD,OAAOn3C,EAAA,CAAU,CAACa,MAAOoN,CAAR,CAAV,CAAyBA,CAFa,CADN,CA7RlB,CAmSzB,YAAa42D,QAAQ,CAAC3/D,CAAD,CAAO0vC,CAAP,CAAkBC,CAAlB,CAA8B70C,CAA9B,CAAuC,CAC1D,MAAO,SAAQ,CAACoL,CAAD,CAAQwZ,CAAR,CAAgBoY,CAAhB,CAAwBma,CAAxB,CAAgC,CACzClpC,CAAAA,CAAM/I,CAAA,CAAKkG,CAAL,CAAYwZ,CAAZ,CAAoBoY,CAApB,CAA4Bma,CAA5B,CAAA,CAAsCvC,CAAA,CAAUxpC,CAAV,CAAiBwZ,CAAjB,CAAyBoY,CAAzB,CAAiCma,CAAjC,CAAtC,CAAiFtC,CAAA,CAAWzpC,CAAX,CAAkBwZ,CAAlB,CAA0BoY,CAA1B,CAAkCma,CAAlC,CAC3F,OAAOn3C,EAAA,CAAU,CAACa,MAAOoN,CAAR,CAAV,CAAyBA,CAFa,CADW,CAnSnC,CAySzBpN,MAAOA,QAAQ,CAACA,CAAD,CAAQb,CAAR,CAAiB,CAC9B,MAAO,SAAQ,EAAG,CAAE,MAAOA,EAAA;AAAU,CAACA,QAASb,CAAV,CAAqBgL,KAAMhL,CAA3B,CAAsC0B,MAAOA,CAA7C,CAAV,CAAgEA,CAAzE,CADY,CAzSP,CA4SzB21B,WAAYA,QAAQ,CAACrsB,CAAD,CAAO0uC,CAAP,CAAwB74C,CAAxB,CAAiCyC,CAAjC,CAAyCq9B,CAAzC,CAAqD,CACvE,MAAO,SAAQ,CAAC10B,CAAD,CAAQwZ,CAAR,CAAgBoY,CAAhB,CAAwBma,CAAxB,CAAgC,CACzCxH,CAAAA,CAAO/qB,CAAA,EAAWza,CAAX,GAAmBya,EAAnB,CAA6BA,CAA7B,CAAsCxZ,CAC7C3I,EAAJ,EAAyB,CAAzB,GAAcA,CAAd,EAA8BktC,CAA9B,EAAwC,CAAAA,CAAA,CAAKxlC,CAAL,CAAxC,GACEwlC,CAAA,CAAKxlC,CAAL,CADF,CACe,EADf,CAGItJ,EAAAA,CAAQ8uC,CAAA,CAAOA,CAAA,CAAKxlC,CAAL,CAAP,CAAoBhL,CAC5B05C,EAAJ,EACE1F,EAAA,CAAiBtyC,CAAjB,CAAwBi/B,CAAxB,CAEF,OAAI9/B,EAAJ,CACS,CAACA,QAAS2vC,CAAV,CAAgBxlC,KAAMA,CAAtB,CAA4BtJ,MAAOA,CAAnC,CADT,CAGSA,CAZoC,CADwB,CA5ShD,CA6TzBwhE,eAAgBA,QAAQ,CAAC7tB,CAAD,CAAOC,CAAP,CAAcz0C,CAAd,CAAuByC,CAAvB,CAA+Bq9B,CAA/B,CAA2C,CACjE,MAAO,SAAQ,CAAC10B,CAAD,CAAQwZ,CAAR,CAAgBoY,CAAhB,CAAwBma,CAAxB,CAAgC,CAC7C,IAAIusB,EAAMlvB,CAAA,CAAKppC,CAAL,CAAYwZ,CAAZ,CAAoBoY,CAApB,CAA4Bma,CAA5B,CAAV,CACIssB,CADJ,CAEI5iE,CACO,KAAX,EAAI6iE,CAAJ,GACED,CAMA,CANMhvB,CAAA,CAAMrpC,CAAN,CAAawZ,CAAb,CAAqBoY,CAArB,CAA6Bma,CAA7B,CAMN,CALAnE,EAAA,CAAqBywB,CAArB,CAA0B3jC,CAA1B,CAKA,CAJIr9B,CAIJ,EAJyB,CAIzB,GAJcA,CAId,EAJ8BihE,CAI9B,EAJuC,CAAAA,CAAA,CAAID,CAAJ,CAIvC,GAHEC,CAAA,CAAID,CAAJ,CAGF,CAHa,EAGb,EADA5iE,CACA,CADQ6iE,CAAA,CAAID,CAAJ,CACR,CAAAtwB,EAAA,CAAiBtyC,CAAjB,CAAwBi/B,CAAxB,CAPF,CASA,OAAI9/B,EAAJ,CACS,CAACA,QAAS0jE,CAAV,CAAev5D,KAAMs5D,CAArB,CAA0B5iE,MAAOA,CAAjC,CADT,CAGSA,CAhBoC,CADkB,CA7T1C,CAkVzB6hE,kBAAmBA,QAAQ,CAACluB,CAAD,CAAOC,CAAP,CAAcoE,CAAd,CAA+B74C,CAA/B,CAAwCyC,CAAxC,CAAgDq9B,CAAhD,CAA4D,CACrF,MAAO,SAAQ,CAAC10B,CAAD,CAAQwZ,CAAR,CAAgBoY,CAAhB,CAAwBma,CAAxB,CAAgC,CACzCusB,CAAAA,CAAMlvB,CAAA,CAAKppC,CAAL,CAAYwZ,CAAZ,CAAoBoY,CAApB,CAA4Bma,CAA5B,CACN10C,EAAJ,EAAyB,CAAzB,GAAcA,CAAd,EAA8BihE,CAA9B,EAAuC,CAAAA,CAAA,CAAIjvB,CAAJ,CAAvC,GACEivB,CAAA,CAAIjvB,CAAJ,CADF,CACe,EADf,CAGI5zC;CAAAA,CAAe,IAAP,EAAA6iE,CAAA,CAAcA,CAAA,CAAIjvB,CAAJ,CAAd,CAA2Bt1C,CACvC,EAAI05C,CAAJ,EAAuBtC,EAAA,CAA8B9B,CAA9B,CAAvB,GACEtB,EAAA,CAAiBtyC,CAAjB,CAAwBi/B,CAAxB,CAEF,OAAI9/B,EAAJ,CACS,CAACA,QAAS0jE,CAAV,CAAev5D,KAAMsqC,CAArB,CAA4B5zC,MAAOA,CAAnC,CADT,CAGSA,CAZoC,CADsC,CAlV9D,CAmWzBs2C,OAAQA,QAAQ,CAACvlC,CAAD,CAAQ4vD,CAAR,CAAiB,CAC/B,MAAO,SAAQ,CAACp2D,CAAD,CAAQvK,CAAR,CAAe+jB,CAAf,CAAuBuyB,CAAvB,CAA+B,CAC5C,MAAIA,EAAJ,CAAmBA,CAAA,CAAOqqB,CAAP,CAAnB,CACO5vD,CAAA,CAAMxG,CAAN,CAAavK,CAAb,CAAoB+jB,CAApB,CAFqC,CADf,CAnWR,CA8W3B,KAAIy0B,GAASA,QAAQ,CAACH,CAAD,CAAQhhC,CAAR,CAAiByP,CAAjB,CAA0B,CAC7C,IAAAuxB,MAAA,CAAaA,CACb,KAAAhhC,QAAA,CAAeA,CACf,KAAAyP,QAAA,CAAeA,CACf,KAAAksB,IAAA,CAAW,IAAIG,CAAJ,CAAQ,IAAAkF,MAAR,CACX,KAAA4rB,YAAA,CAAmBn9C,CAAAxW,IAAA,CAAc,IAAI+kC,EAAJ,CAAmB,IAAArC,IAAnB,CAA6B37B,CAA7B,CAAd,CACc,IAAI89B,EAAJ,CAAgB,IAAAnC,IAAhB,CAA0B37B,CAA1B,CANY,CAS/CmhC,GAAAr2C,UAAA,CAAmB,CACjBoC,YAAai0C,EADI,CAGjBjyC,MAAOA,QAAQ,CAACgzB,CAAD,CAAO,CACpB,MAAO,KAAA0qC,YAAAz5D,QAAA,CAAyB+uB,CAAzB,CAA+B,IAAAzS,QAAAkxB,gBAA/B,CADa,CAHL,CA+BQ3yC,GAAA,EACEA,GAAA,EAM7B,KAAIuwC,GAAgBh3C,MAAAuD,UAAAlB,QAApB,CA+yEIygD,GAAanjD,CAAA,CAAO,MAAP,CA/yEjB,CAizEIwjD,GAAe,CACjB1nB,KAAM,MADW,CAEjB2oB,IAAK,KAFY,CAGjBC,IAAK,KAHY;AAMjB3oB,aAAc,aANG,CAOjB4oB,GAAI,IAPa,CAjzEnB,CA85GI72B,GAAiB9tB,CAAA,CAAO,UAAP,CA95GrB,CAisHIgoD,EAAiBloD,CAAAgd,cAAA,CAAuB,GAAvB,CAjsHrB,CAksHIorC,GAAY5f,EAAA,CAAWzoC,CAAA+M,SAAAud,KAAX,CA6LhBg+B,GAAA1iC,QAAA,CAAyB,CAAC,WAAD,CAyGzB1M,GAAA0M,QAAA,CAA0B,CAAC,UAAD,CAkX1BmjC,GAAAnjC,QAAA,CAAyB,CAAC,SAAD,CA0EzByjC,GAAAzjC,QAAA,CAAuB,CAAC,SAAD,CAavB,KAAI8lB,GAAc,GAAlB,CA4KI2iB,GAAe,CACjBgF,KAAMhH,CAAA,CAAW,UAAX,CAAuB,CAAvB,CADW,CAEfyZ,GAAIzZ,CAAA,CAAW,UAAX,CAAuB,CAAvB,CAA0B,CAA1B,CAA6B,CAAA,CAA7B,CAFW,CAGd0Z,EAAG1Z,CAAA,CAAW,UAAX,CAAuB,CAAvB,CAHW,CAIjB2Z,KAAM1Z,EAAA,CAAc,OAAd,CAJW,CAKhB2Z,IAAK3Z,EAAA,CAAc,OAAd,CAAuB,CAAA,CAAvB,CALW,CAMfgH,GAAIjH,CAAA,CAAW,OAAX,CAAoB,CAApB,CAAuB,CAAvB,CANW,CAOd6Z,EAAG7Z,CAAA,CAAW,OAAX,CAAoB,CAApB,CAAuB,CAAvB,CAPW,CAQfkH,GAAIlH,CAAA,CAAW,MAAX,CAAmB,CAAnB,CARW,CASdppB,EAAGopB,CAAA,CAAW,MAAX,CAAmB,CAAnB,CATW,CAUfmH,GAAInH,CAAA,CAAW,OAAX,CAAoB,CAApB,CAVW,CAWd8Z,EAAG9Z,CAAA,CAAW,OAAX,CAAoB,CAApB,CAXW,CAYf+Z,GAAI/Z,CAAA,CAAW,OAAX,CAAoB,CAApB,CAAwB,GAAxB,CAZW,CAadrqD,EAAGqqD,CAAA,CAAW,OAAX,CAAoB,CAApB,CAAwB,GAAxB,CAbW,CAcfqH,GAAIrH,CAAA,CAAW,SAAX,CAAsB,CAAtB,CAdW,CAedyB,EAAGzB,CAAA,CAAW,SAAX,CAAsB,CAAtB,CAfW,CAgBfsH,GAAItH,CAAA,CAAW,SAAX,CAAsB,CAAtB,CAhBW,CAiBd0B,EAAG1B,CAAA,CAAW,SAAX;AAAsB,CAAtB,CAjBW,CAoBhBwH,IAAKxH,CAAA,CAAW,cAAX,CAA2B,CAA3B,CApBW,CAqBjBga,KAAM/Z,EAAA,CAAc,KAAd,CArBW,CAsBhBga,IAAKha,EAAA,CAAc,KAAd,CAAqB,CAAA,CAArB,CAtBW,CAuBd75C,EAnCL8zD,QAAmB,CAAC79D,CAAD,CAAOgiD,CAAP,CAAgB,CACjC,MAAyB,GAAlB,CAAAhiD,CAAA+qD,SAAA,EAAA,CAAuB/I,CAAA9d,MAAA,CAAc,CAAd,CAAvB,CAA0C8d,CAAA9d,MAAA,CAAc,CAAd,CADhB,CAYhB,CAwBd45B,EAxELC,QAAuB,CAAC/9D,CAAD,CAAOgiD,CAAP,CAAgBpuC,CAAhB,CAAwB,CACzCoqD,CAAAA,CAAQ,EAARA,CAAYpqD,CAMhB,OAHAqqD,EAGA,EAL0B,CAATA,EAACD,CAADC,CAAc,GAAdA,CAAoB,EAKrC,GAHcza,EAAA,CAAU7yB,IAAA,CAAY,CAAP,CAAAqtC,CAAA,CAAW,OAAX,CAAqB,MAA1B,CAAA,CAAkCA,CAAlC,CAAyC,EAAzC,CAAV,CAAwD,CAAxD,CAGd,CAFcxa,EAAA,CAAU7yB,IAAA8xB,IAAA,CAASub,CAAT,CAAgB,EAAhB,CAAV,CAA+B,CAA/B,CAEd,CAP6C,CAgD5B,CAyBfE,GAAIha,EAAA,CAAW,CAAX,CAzBW,CA0Bdia,EAAGja,EAAA,CAAW,CAAX,CA1BW,CA2Bdka,EAAG5Z,EA3BW,CA4Bd6Z,GAAI7Z,EA5BU,CA6Bd8Z,IAAK9Z,EA7BS,CA8Bd+Z,KAlCLC,QAAsB,CAACx+D,CAAD,CAAOgiD,CAAP,CAAgB,CACpC,MAA6B,EAAtB,EAAAhiD,CAAAokD,YAAA,EAAA,CAA0BpC,CAAAtd,SAAA,CAAiB,CAAjB,CAA1B,CAAgDsd,CAAAtd,SAAA,CAAiB,CAAjB,CADnB,CAInB,CA5KnB,CA6MI+gB,GAAqB,sFA7MzB,CA8MID,GAAgB,UA+FpBlF,GAAApjC,QAAA,CAAqB,CAAC,SAAD,CA8HrB,KAAIwjC,GAAkBxlD,EAAA,CAAQwB,CAAR,CAAtB,CAWImkD,GAAkB3lD,EAAA,CAAQoO,EAAR,CA4StBs3C,GAAA1jC,QAAA;AAAwB,CAAC,QAAD,CA0IxB,KAAIlT,GAAsB9O,EAAA,CAAQ,CAChCwrB,SAAU,GADsB,CAEhChjB,QAASA,QAAQ,CAACjH,CAAD,CAAUN,CAAV,CAAgB,CAC/B,GAAKylB,CAAAzlB,CAAAylB,KAAL,EAAmB68C,CAAAtiE,CAAAsiE,UAAnB,CACE,MAAO,SAAQ,CAACh7D,CAAD,CAAQhH,CAAR,CAAiB,CAE9B,GAA0C,GAA1C,GAAIA,CAAA,CAAQ,CAAR,CAAAR,SAAA8I,YAAA,EAAJ,CAAA,CAGA,IAAI6c,EAA+C,4BAAxC,GAAAxmB,EAAA3C,KAAA,CAAcgE,CAAAP,KAAA,CAAa,MAAb,CAAd,CAAA,CACA,YADA,CACe,MAC1BO,EAAA6I,GAAA,CAAW,OAAX,CAAoB,QAAQ,CAAC+T,CAAD,CAAQ,CAE7B5c,CAAAN,KAAA,CAAaylB,CAAb,CAAL,EACEvI,CAAAwwB,eAAA,EAHgC,CAApC,CALA,CAF8B,CAFH,CAFD,CAAR,CAA1B,CAoXI16B,GAA6B,EAGjChX,EAAA,CAAQ4gB,EAAR,CAAsB,QAAQ,CAAC2lD,CAAD,CAAW/4C,CAAX,CAAqB,CAIjDg5C,QAASA,EAAa,CAACl7D,CAAD,CAAQhH,CAAR,CAAiBN,CAAjB,CAAuB,CAC3CsH,CAAA5H,OAAA,CAAaM,CAAA,CAAKyiE,CAAL,CAAb,CAA+BC,QAAiC,CAAC3lE,CAAD,CAAQ,CACtEiD,CAAAg1B,KAAA,CAAUxL,CAAV,CAAoB,CAAEzsB,CAAAA,CAAtB,CADsE,CAAxE,CAD2C,CAF7C,GAAgB,UAAhB,EAAIwlE,CAAJ,CAAA,CAQA,IAAIE,EAAa3zC,EAAA,CAAmB,KAAnB,CAA2BtF,CAA3B,CAAjB,CACI6G,EAASmyC,CAEI,UAAjB,GAAID,CAAJ,GACElyC,CADF,CACWA,QAAQ,CAAC/oB,CAAD,CAAQhH,CAAR,CAAiBN,CAAjB,CAAuB,CAElCA,CAAAyR,QAAJ,GAAqBzR,CAAA,CAAKyiE,CAAL,CAArB,EACED,CAAA,CAAcl7D,CAAd,CAAqBhH,CAArB,CAA8BN,CAA9B,CAHoC,CAD1C,CASAgT,GAAA,CAA2ByvD,CAA3B,CAAA,CAAyC,QAAQ,EAAG,CAClD,MAAO,CACLl4C,SAAU,GADL;AAELF,SAAU,GAFL,CAGL5C,KAAM4I,CAHD,CAD2C,CApBpD,CAFiD,CAAnD,CAgCAr0B,EAAA,CAAQ+gB,EAAR,CAAsB,QAAQ,CAAC4lD,CAAD,CAAW/8D,CAAX,CAAmB,CAC/CoN,EAAA,CAA2BpN,CAA3B,CAAA,CAAqC,QAAQ,EAAG,CAC9C,MAAO,CACLykB,SAAU,GADL,CAEL5C,KAAMA,QAAQ,CAACngB,CAAD,CAAQhH,CAAR,CAAiBN,CAAjB,CAAuB,CAGnC,GAAe,WAAf,GAAI4F,CAAJ,EAA0D,GAA1D,EAA8B5F,CAAAiS,UAAApQ,OAAA,CAAsB,CAAtB,CAA9B,GACMJ,CADN,CACczB,CAAAiS,UAAAxQ,MAAA,CAAqB2wD,EAArB,CADd,EAEa,CACTpyD,CAAAg1B,KAAA,CAAU,WAAV,CAAuB,IAAIxzB,MAAJ,CAAWC,CAAA,CAAM,CAAN,CAAX,CAAqBA,CAAA,CAAM,CAAN,CAArB,CAAvB,CACA,OAFS,CAMb6F,CAAA5H,OAAA,CAAaM,CAAA,CAAK4F,CAAL,CAAb,CAA2Bg9D,QAA+B,CAAC7lE,CAAD,CAAQ,CAChEiD,CAAAg1B,KAAA,CAAUpvB,CAAV,CAAkB7I,CAAlB,CADgE,CAAlE,CAXmC,CAFhC,CADuC,CADD,CAAjD,CAwBAf,EAAA,CAAQ,CAAC,KAAD,CAAQ,QAAR,CAAkB,MAAlB,CAAR,CAAmC,QAAQ,CAACwtB,CAAD,CAAW,CACpD,IAAIi5C,EAAa3zC,EAAA,CAAmB,KAAnB,CAA2BtF,CAA3B,CACjBxW,GAAA,CAA2ByvD,CAA3B,CAAA,CAAyC,QAAQ,EAAG,CAClD,MAAO,CACLp4C,SAAU,EADL,CAEL5C,KAAMA,QAAQ,CAACngB,CAAD,CAAQhH,CAAR,CAAiBN,CAAjB,CAAuB,CAAA,IAC/BuiE,EAAW/4C,CADoB,CAE/BnjB,EAAOmjB,CAEM,OAAjB,GAAIA,CAAJ,EAC4C,4BAD5C,GACIvqB,EAAA3C,KAAA,CAAcgE,CAAAP,KAAA,CAAa,MAAb,CAAd,CADJ,GAEEsG,CAEA,CAFO,WAEP,CADArG,CAAA4uB,MAAA,CAAWvoB,CAAX,CACA,CADmB,YACnB;AAAAk8D,CAAA,CAAW,IAJb,CAOAviE,EAAAg5B,SAAA,CAAcypC,CAAd,CAA0B,QAAQ,CAAC1lE,CAAD,CAAQ,CACnCA,CAAL,EAOAiD,CAAAg1B,KAAA,CAAU3uB,CAAV,CAAgBtJ,CAAhB,CAMA,CAAI6yB,EAAJ,EAAY2yC,CAAZ,EAAsBjiE,CAAAP,KAAA,CAAawiE,CAAb,CAAuBviE,CAAA,CAAKqG,CAAL,CAAvB,CAbtB,EACmB,MADnB,GACMmjB,CADN,EAEIxpB,CAAAg1B,KAAA,CAAU3uB,CAAV,CAAgB,IAAhB,CAHoC,CAA1C,CAXmC,CAFhC,CAD2C,CAFA,CAAtD,CAr2mBuC,KA44mBnCwkD,GAAe,CACjBU,YAAa3sD,CADI,CAEjBktD,gBASF+W,QAA8B,CAACnX,CAAD,CAAUrlD,CAAV,CAAgB,CAC5CqlD,CAAAT,MAAA,CAAgB5kD,CAD4B,CAX3B,CAGjB6lD,eAAgBttD,CAHC,CAIjBwtD,aAAcxtD,CAJG,CAKjB6tD,UAAW7tD,CALM,CAMjBiuD,aAAcjuD,CANG,CAOjBuuD,cAAevuD,CAPE,CAyDnB6rD,GAAA1pC,QAAA,CAAyB,CAAC,UAAD,CAAa,QAAb,CAAuB,QAAvB,CAAiC,UAAjC,CAA6C,cAA7C,CAqYzB,KAAI+hD,GAAuBA,QAAQ,CAACC,CAAD,CAAW,CAC5C,MAAO,CAAC,UAAD,CAAa,QAAQ,CAACrsD,CAAD,CAAW,CAgErC,MA/DoBxI,CAClB7H,KAAM,MADY6H,CAElBqc,SAAUw4C,CAAA,CAAW,KAAX,CAAmB,GAFX70D,CAGlB5E,WAAYmhD,EAHMv8C,CAIlB3G,QAASy7D,QAAsB,CAACC,CAAD,CAAcjjE,CAAd,CAAoB,CAEjDijE,CAAA9kD,SAAA,CAAqBwuC,EAArB,CAAAxuC,SAAA,CAA8C2zC,EAA9C,CAEA,KAAIoR,EAAWljE,CAAAqG,KAAA,CAAY,MAAZ,CAAsB08D,CAAA,EAAY/iE,CAAA2P,OAAZ,CAA0B,QAA1B;AAAqC,CAAA,CAE1E,OAAO,CACLkhB,IAAKsyC,QAAsB,CAAC77D,CAAD,CAAQ27D,CAAR,CAAqBjjE,CAArB,CAA2BsJ,CAA3B,CAAuC,CAEhE,GAAM,EAAA,QAAA,EAAYtJ,EAAZ,CAAN,CAAyB,CAOvB,IAAIojE,EAAuBA,QAAQ,CAAClmD,CAAD,CAAQ,CACzC5V,CAAAE,OAAA,CAAa,QAAQ,EAAG,CACtB8B,CAAAqiD,iBAAA,EACAriD,EAAA6jD,cAAA,EAFsB,CAAxB,CAKAjwC,EAAAwwB,eAAA,EANyC,CASxBu1B,EAAA3iE,CAAY,CAAZA,CAxziB3B2iC,iBAAA,CAwziB2CjpB,QAxziB3C,CAwziBqDopD,CAxziBrD,CAAmC,CAAA,CAAnC,CA4ziBQH,EAAA95D,GAAA,CAAe,UAAf,CAA2B,QAAQ,EAAG,CACpCuN,CAAA,CAAS,QAAQ,EAAG,CACIusD,CAAA3iE,CAAY,CAAZA,CA3ziBlCga,oBAAA,CA2ziBkDN,QA3ziBlD,CA2ziB4DopD,CA3ziB5D,CAAsC,CAAA,CAAtC,CA0ziB8B,CAApB,CAEG,CAFH,CAEM,CAAA,CAFN,CADoC,CAAtC,CApBuB,CA2BzB,IAAIC,EAAiB/5D,CAAAshD,aAEjBsY,EAAJ,GACE7wB,EAAA,CAAO/qC,CAAP,CAAcgC,CAAA2hD,MAAd,CAAgC3hD,CAAhC,CAA4CA,CAAA2hD,MAA5C,CACA,CAAAjrD,CAAAg5B,SAAA,CAAckqC,CAAd,CAAwB,QAAQ,CAACxrC,CAAD,CAAW,CACrCpuB,CAAA2hD,MAAJ,GAAyBvzB,CAAzB,GACA2a,EAAA,CAAO/qC,CAAP,CAAcgC,CAAA2hD,MAAd,CAAgC5vD,CAAhC,CAA2CiO,CAAA2hD,MAA3C,CAEA,CADAoY,CAAAvX,gBAAA,CAA+BxiD,CAA/B,CAA2CouB,CAA3C,CACA,CAAA2a,EAAA,CAAO/qC,CAAP,CAAcgC,CAAA2hD,MAAd,CAAgC3hD,CAAhC,CAA4CA,CAAA2hD,MAA5C,CAHA,CADyC,CAA3C,CAFF,CASAgY,EAAA95D,GAAA,CAAe,UAAf,CAA2B,QAAQ,EAAG,CACpCk6D,CAAAnX,eAAA,CAA8B5iD,CAA9B,CACI45D,EAAJ,EACE7wB,EAAA,CAAO/qC,CAAP,CAActH,CAAA,CAAKkjE,CAAL,CAAd,CAA8B7nE,CAA9B;AAAyCiO,CAAA2hD,MAAzC,CAEFhtD,EAAA,CAAOqL,CAAP,CAAmBuhD,EAAnB,CALoC,CAAtC,CAxCgE,CAD7D,CAN0C,CAJjC38C,CADiB,CAAhC,CADqC,CAA9C,CAqEIA,GAAgB40D,EAAA,EArEpB,CAsEIlzD,GAAkBkzD,EAAA,CAAqB,CAAA,CAArB,CAtEtB,CAkFIvU,GAAkB,0EAlFtB,CAmFI+U,GAAa,qFAnFjB,CAoFIC,GAAe,mGApFnB,CAqFIC,GAAgB,mDArFpB,CAsFIC,GAAc,2BAtFlB,CAuFIC,GAAuB,+DAvF3B,CAwFIC,GAAc,mBAxFlB,CAyFIC,GAAe,kBAzFnB;AA0FIC,GAAc,yCA1FlB,CA4FIC,GAAY,CAgGd,KA65BFC,QAAsB,CAACz8D,CAAD,CAAQhH,CAAR,CAAiBN,CAAjB,CAAuBssD,CAAvB,CAA6Bp2C,CAA7B,CAAuCxC,CAAvC,CAAiD,CACrE85C,EAAA,CAAclmD,CAAd,CAAqBhH,CAArB,CAA8BN,CAA9B,CAAoCssD,CAApC,CAA0Cp2C,CAA1C,CAAoDxC,CAApD,CACA25C,GAAA,CAAqBf,CAArB,CAFqE,CA7/BvD,CA+Ld,KAAQ8C,EAAA,CAAoB,MAApB,CAA4BqU,EAA5B,CACDrV,EAAA,CAAiBqV,EAAjB,CAA8B,CAAC,MAAD,CAAS,IAAT,CAAe,IAAf,CAA9B,CADC,CAED,YAFC,CA/LM,CA8Rd,iBAAkBrU,EAAA,CAAoB,eAApB,CAAqCsU,EAArC,CACdtV,EAAA,CAAiBsV,EAAjB,CAAuC,yBAAA,MAAA,CAAA,GAAA,CAAvC,CADc,CAEd,yBAFc,CA9RJ,CA8Xd,KAAQtU,EAAA,CAAoB,MAApB,CAA4ByU,EAA5B,CACJzV,EAAA,CAAiByV,EAAjB,CAA8B,CAAC,IAAD,CAAO,IAAP,CAAa,IAAb,CAAmB,KAAnB,CAA9B,CADI,CAEL,cAFK,CA9XM,CA+dd,KAAQzU,EAAA,CAAoB,MAApB,CAA4BuU,EAA5B,CAynBVK,QAAmB,CAACC,CAAD,CAAUC,CAAV,CAAwB,CACzC,GAAIpmE,EAAA,CAAOmmE,CAAP,CAAJ,CACE,MAAOA,EAGT,IAAInoE,CAAA,CAASmoE,CAAT,CAAJ,CAAuB,CACrBN,EAAAjiE,UAAA,CAAwB,CACxB,KAAI0D,EAAQu+D,EAAArrD,KAAA,CAAiB2rD,CAAjB,CACZ,IAAI7+D,CAAJ,CAAW,CAAA,IACLwiD,EAAO,CAACxiD,CAAA,CAAM,CAAN,CADH,CAEL++D,EAAO,CAAC/+D,CAAA,CAAM,CAAN,CAFH,CAILjB,EADAigE,CACAjgE,CADQ,CAHH,CAKLkgE,EAAU,CALL,CAMLC,EAAe,CANV,CAOLtc,EAAaL,EAAA,CAAuBC,CAAvB,CAPR,CAQL2c,EAAuB,CAAvBA,EAAWJ,CAAXI,CAAkB,CAAlBA,CAEAL,EAAJ,GACEE,CAGA,CAHQF,CAAAtV,SAAA,EAGR,CAFAzqD,CAEA;AAFU+/D,CAAAhgE,WAAA,EAEV,CADAmgE,CACA,CADUH,CAAAnV,WAAA,EACV,CAAAuV,CAAA,CAAeJ,CAAAjV,gBAAA,EAJjB,CAOA,OAAO,KAAIlxD,IAAJ,CAAS6pD,CAAT,CAAe,CAAf,CAAkBI,CAAAI,QAAA,EAAlB,CAAyCmc,CAAzC,CAAkDH,CAAlD,CAAyDjgE,CAAzD,CAAkEkgE,CAAlE,CAA2EC,CAA3E,CAjBE,CAHU,CAwBvB,MAAOnV,IA7BkC,CAznBjC,CAAqD,UAArD,CA/dM,CA8jBd,MAASC,EAAA,CAAoB,OAApB,CAA6BwU,EAA7B,CACNxV,EAAA,CAAiBwV,EAAjB,CAA+B,CAAC,MAAD,CAAS,IAAT,CAA/B,CADM,CAEN,SAFM,CA9jBK,CA6qBd,OAolBFY,QAAwB,CAACl9D,CAAD,CAAQhH,CAAR,CAAiBN,CAAjB,CAAuBssD,CAAvB,CAA6Bp2C,CAA7B,CAAuCxC,CAAvC,CAAiD,CACvE+7C,EAAA,CAAgBnoD,CAAhB,CAAuBhH,CAAvB,CAAgCN,CAAhC,CAAsCssD,CAAtC,CACAkB,GAAA,CAAclmD,CAAd,CAAqBhH,CAArB,CAA8BN,CAA9B,CAAoCssD,CAApC,CAA0Cp2C,CAA1C,CAAoDxC,CAApD,CAEA44C,EAAAsD,aAAA,CAAoB,QACpBtD,EAAAuD,SAAAxuD,KAAA,CAAmB,QAAQ,CAACtE,CAAD,CAAQ,CACjC,MAAIuvD,EAAAiB,SAAA,CAAcxwD,CAAd,CAAJ,CAAsC,IAAtC,CACIymE,EAAApiE,KAAA,CAAmBrE,CAAnB,CAAJ,CAAsC+pD,UAAA,CAAW/pD,CAAX,CAAtC,CACO1B,CAH0B,CAAnC,CAMAixD,EAAAgB,YAAAjsD,KAAA,CAAsB,QAAQ,CAACtE,CAAD,CAAQ,CACpC,GAAK,CAAAuvD,CAAAiB,SAAA,CAAcxwD,CAAd,CAAL,CAA2B,CACzB,GAAK,CAAAuC,CAAA,CAASvC,CAAT,CAAL,CACE,KAAMgzD,GAAA,CAAe,QAAf,CAA0DhzD,CAA1D,CAAN,CAEFA,CAAA,CAAQA,CAAAkC,SAAA,EAJiB,CAM3B,MAAOlC,EAP6B,CAAtC,CAUA,IAAIqC,CAAA,CAAUY,CAAAgnD,IAAV,CAAJ,EAA2BhnD,CAAAgwD,MAA3B,CAAuC,CACrC,IAAIC,CACJ3D,EAAA4D,YAAAlJ,IAAA,CAAuBmJ,QAAQ,CAACpzD,CAAD,CAAQ,CACrC,MAAOuvD,EAAAiB,SAAA,CAAcxwD,CAAd,CAAP;AAA+BoC,CAAA,CAAY8wD,CAAZ,CAA/B,EAAsDlzD,CAAtD,EAA+DkzD,CAD1B,CAIvCjwD,EAAAg5B,SAAA,CAAc,KAAd,CAAqB,QAAQ,CAACj2B,CAAD,CAAM,CAC7B3D,CAAA,CAAU2D,CAAV,CAAJ,EAAuB,CAAAzD,CAAA,CAASyD,CAAT,CAAvB,GACEA,CADF,CACQ+jD,UAAA,CAAW/jD,CAAX,CAAgB,EAAhB,CADR,CAGAktD,EAAA,CAAS3wD,CAAA,CAASyD,CAAT,CAAA,EAAkB,CAAAY,KAAA,CAAMZ,CAAN,CAAlB,CAA+BA,CAA/B,CAAqC1H,CAE9CixD,EAAA8D,UAAA,EANiC,CAAnC,CANqC,CAgBvC,GAAIhxD,CAAA,CAAUY,CAAAy0B,IAAV,CAAJ,EAA2Bz0B,CAAAqwD,MAA3B,CAAuC,CACrC,IAAIC,CACJhE,EAAA4D,YAAAz7B,IAAA,CAAuB87B,QAAQ,CAACxzD,CAAD,CAAQ,CACrC,MAAOuvD,EAAAiB,SAAA,CAAcxwD,CAAd,CAAP,EAA+BoC,CAAA,CAAYmxD,CAAZ,CAA/B,EAAsDvzD,CAAtD,EAA+DuzD,CAD1B,CAIvCtwD,EAAAg5B,SAAA,CAAc,KAAd,CAAqB,QAAQ,CAACj2B,CAAD,CAAM,CAC7B3D,CAAA,CAAU2D,CAAV,CAAJ,EAAuB,CAAAzD,CAAA,CAASyD,CAAT,CAAvB,GACEA,CADF,CACQ+jD,UAAA,CAAW/jD,CAAX,CAAgB,EAAhB,CADR,CAGAutD,EAAA,CAAShxD,CAAA,CAASyD,CAAT,CAAA,EAAkB,CAAAY,KAAA,CAAMZ,CAAN,CAAlB,CAA+BA,CAA/B,CAAqC1H,CAE9CixD,EAAA8D,UAAA,EANiC,CAAnC,CANqC,CArCgC,CAjwCzD,CAgxBd,IAuiBFqU,QAAqB,CAACn9D,CAAD,CAAQhH,CAAR,CAAiBN,CAAjB,CAAuBssD,CAAvB,CAA6Bp2C,CAA7B,CAAuCxC,CAAvC,CAAiD,CAGpE85C,EAAA,CAAclmD,CAAd,CAAqBhH,CAArB,CAA8BN,CAA9B,CAAoCssD,CAApC,CAA0Cp2C,CAA1C,CAAoDxC,CAApD,CACA25C,GAAA,CAAqBf,CAArB,CAEAA,EAAAsD,aAAA,CAAoB,KACpBtD,EAAA4D,YAAAtrC,IAAA,CAAuB8/C,QAAQ,CAACC,CAAD,CAAaC,CAAb,CAAwB,CACrD,IAAI7nE,EAAQ4nE,CAAR5nE,EAAsB6nE,CAC1B,OAAOtY,EAAAiB,SAAA,CAAcxwD,CAAd,CAAP,EAA+BumE,EAAAliE,KAAA,CAAgBrE,CAAhB,CAFsB,CAPa,CAvzCtD,CAk3Bd,MAkdF8nE,QAAuB,CAACv9D,CAAD,CAAQhH,CAAR,CAAiBN,CAAjB,CAAuBssD,CAAvB,CAA6Bp2C,CAA7B,CAAuCxC,CAAvC,CAAiD,CAGtE85C,EAAA,CAAclmD,CAAd,CAAqBhH,CAArB,CAA8BN,CAA9B,CAAoCssD,CAApC,CAA0Cp2C,CAA1C,CAAoDxC,CAApD,CACA25C,GAAA,CAAqBf,CAArB,CAEAA;CAAAsD,aAAA,CAAoB,OACpBtD,EAAA4D,YAAA4U,MAAA,CAAyBC,QAAQ,CAACJ,CAAD,CAAaC,CAAb,CAAwB,CACvD,IAAI7nE,EAAQ4nE,CAAR5nE,EAAsB6nE,CAC1B,OAAOtY,EAAAiB,SAAA,CAAcxwD,CAAd,CAAP,EAA+BwmE,EAAAniE,KAAA,CAAkBrE,CAAlB,CAFwB,CAPa,CAp0CxD,CAo7Bd,MA6ZFioE,QAAuB,CAAC19D,CAAD,CAAQhH,CAAR,CAAiBN,CAAjB,CAAuBssD,CAAvB,CAA6B,CAE9CntD,CAAA,CAAYa,CAAAqG,KAAZ,CAAJ,EACE/F,CAAAN,KAAA,CAAa,MAAb,CAt3pBK,EAAE/C,EAs3pBP,CASFqD,EAAA6I,GAAA,CAAW,OAAX,CANe4b,QAAQ,CAAC2oC,CAAD,CAAK,CACtBptD,CAAA,CAAQ,CAAR,CAAA2kE,QAAJ,EACE3Y,CAAAwB,cAAA,CAAmB9tD,CAAAjD,MAAnB,CAA+B2wD,CAA/B,EAAqCA,CAAA1zC,KAArC,CAFwB,CAM5B,CAEAsyC,EAAA4B,QAAA,CAAeC,QAAQ,EAAG,CAExB7tD,CAAA,CAAQ,CAAR,CAAA2kE,QAAA,CADYjlE,CAAAjD,MACZ,EAA+BuvD,CAAAsB,WAFP,CAK1B5tD,EAAAg5B,SAAA,CAAc,OAAd,CAAuBszB,CAAA4B,QAAvB,CAnBkD,CAj1CpC,CA8+Bd,SAsYFgX,QAA0B,CAAC59D,CAAD,CAAQhH,CAAR,CAAiBN,CAAjB,CAAuBssD,CAAvB,CAA6Bp2C,CAA7B,CAAuCxC,CAAvC,CAAiDU,CAAjD,CAA0DkB,CAA1D,CAAkE,CAC1F,IAAI6vD,EAAYvU,EAAA,CAAkBt7C,CAAlB,CAA0BhO,CAA1B,CAAiC,aAAjC,CAAgDtH,CAAAolE,YAAhD,CAAkE,CAAA,CAAlE,CAAhB,CACIC,EAAazU,EAAA,CAAkBt7C,CAAlB,CAA0BhO,CAA1B,CAAiC,cAAjC,CAAiDtH,CAAAslE,aAAjD,CAAoE,CAAA,CAApE,CAMjBhlE,EAAA6I,GAAA,CAAW,OAAX,CAJe4b,QAAQ,CAAC2oC,CAAD,CAAK,CAC1BpB,CAAAwB,cAAA,CAAmBxtD,CAAA,CAAQ,CAAR,CAAA2kE,QAAnB,CAAuCvX,CAAvC;AAA6CA,CAAA1zC,KAA7C,CAD0B,CAI5B,CAEAsyC,EAAA4B,QAAA,CAAeC,QAAQ,EAAG,CACxB7tD,CAAA,CAAQ,CAAR,CAAA2kE,QAAA,CAAqB3Y,CAAAsB,WADG,CAO1BtB,EAAAiB,SAAA,CAAgBgY,QAAQ,CAACxoE,CAAD,CAAQ,CAC9B,MAAiB,CAAA,CAAjB,GAAOA,CADuB,CAIhCuvD,EAAAgB,YAAAjsD,KAAA,CAAsB,QAAQ,CAACtE,CAAD,CAAQ,CACpC,MAAO+E,GAAA,CAAO/E,CAAP,CAAcooE,CAAd,CAD6B,CAAtC,CAIA7Y,EAAAuD,SAAAxuD,KAAA,CAAmB,QAAQ,CAACtE,CAAD,CAAQ,CACjC,MAAOA,EAAA,CAAQooE,CAAR,CAAoBE,CADM,CAAnC,CAzB0F,CAp3C5E,CAg/Bd,OAAUzmE,CAh/BI,CAi/Bd,OAAUA,CAj/BI,CAk/Bd,OAAUA,CAl/BI,CAm/Bd,MAASA,CAn/BK,CAo/Bd,KAAQA,CAp/BM,CA5FhB,CA4pDImP,GAAiB,CAAC,UAAD,CAAa,UAAb,CAAyB,SAAzB,CAAoC,QAApC,CACjB,QAAQ,CAAC2F,CAAD,CAAWwC,CAAX,CAAqB9B,CAArB,CAA8BkB,CAA9B,CAAsC,CAChD,MAAO,CACLiV,SAAU,GADL,CAELD,QAAS,CAAC,UAAD,CAFJ,CAGL7C,KAAM,CACJoJ,IAAKA,QAAQ,CAACvpB,CAAD,CAAQhH,CAAR,CAAiBN,CAAjB,CAAuBwlE,CAAvB,CAA8B,CACrCA,CAAA,CAAM,CAAN,CAAJ,EACE,CAAC1B,EAAA,CAAUvjE,CAAA,CAAUP,CAAAga,KAAV,CAAV,CAAD,EAAoC8pD,EAAAxtC,KAApC,EAAoDhvB,CAApD,CAA2DhH,CAA3D,CAAoEN,CAApE,CAA0EwlE,CAAA,CAAM,CAAN,CAA1E,CAAoFtvD,CAApF,CACoDxC,CADpD,CAC8DU,CAD9D,CACuEkB,CADvE,CAFuC,CADvC,CAHD,CADyC,CAD7B,CA5pDrB,CA8qDImwD,GAAwB,oBA9qD5B,CAwuDI7yD,GAAmBA,QAAQ,EAAG,CAChC,MAAO,CACL2X,SAAU,GADL,CAELF,SAAU,GAFL,CAGL9iB,QAASA,QAAQ,CAACw6C,CAAD;AAAM2jB,CAAN,CAAe,CAC9B,MAAID,GAAArkE,KAAA,CAA2BskE,CAAA/yD,QAA3B,CAAJ,CACSgzD,QAA4B,CAACr+D,CAAD,CAAQ2b,CAAR,CAAajjB,CAAb,CAAmB,CACpDA,CAAAg1B,KAAA,CAAU,OAAV,CAAmB1tB,CAAA61C,MAAA,CAAYn9C,CAAA2S,QAAZ,CAAnB,CADoD,CADxD,CAKSizD,QAAoB,CAACt+D,CAAD,CAAQ2b,CAAR,CAAajjB,CAAb,CAAmB,CAC5CsH,CAAA5H,OAAA,CAAaM,CAAA2S,QAAb,CAA2BkzD,QAAyB,CAAC9oE,CAAD,CAAQ,CAC1DiD,CAAAg1B,KAAA,CAAU,OAAV,CAAmBj4B,CAAnB,CAD0D,CAA5D,CAD4C,CANlB,CAH3B,CADyB,CAxuDlC,CA+yDI6R,GAAkB,CAAC,UAAD,CAAa,QAAQ,CAACk3D,CAAD,CAAW,CACpD,MAAO,CACLv7C,SAAU,IADL,CAELhjB,QAASw+D,QAAsB,CAACC,CAAD,CAAkB,CAC/CF,CAAAlvC,kBAAA,CAA2BovC,CAA3B,CACA,OAAOC,SAAmB,CAAC3+D,CAAD,CAAQhH,CAAR,CAAiBN,CAAjB,CAAuB,CAC/C8lE,CAAAhvC,iBAAA,CAA0Bx2B,CAA1B,CAAmCN,CAAA2O,OAAnC,CACArO,EAAA,CAAUA,CAAA,CAAQ,CAAR,CACVgH,EAAA5H,OAAA,CAAaM,CAAA2O,OAAb,CAA0Bu3D,QAA0B,CAACnpE,CAAD,CAAQ,CAC1DuD,CAAAyY,YAAA,CAAsBhc,CAAA,GAAU1B,CAAV,CAAsB,EAAtB,CAA2B0B,CADS,CAA5D,CAH+C,CAFF,CAF5C,CAD6C,CAAhC,CA/yDtB,CAm3DIiS,GAA0B,CAAC,cAAD,CAAiB,UAAjB,CAA6B,QAAQ,CAACsF,CAAD,CAAewxD,CAAf,CAAyB,CAC1F,MAAO,CACLv+D,QAAS4+D,QAA8B,CAACH,CAAD,CAAkB,CACvDF,CAAAlvC,kBAAA,CAA2BovC,CAA3B,CACA,OAAOI,SAA2B,CAAC9+D,CAAD,CAAQhH,CAAR,CAAiBN,CAAjB,CAAuB,CACnDu2B,CAAAA,CAAgBjiB,CAAA,CAAahU,CAAAN,KAAA,CAAaA,CAAA4uB,MAAA7f,eAAb,CAAb,CACpB+2D;CAAAhvC,iBAAA,CAA0Bx2B,CAA1B,CAAmCi2B,CAAAQ,YAAnC,CACAz2B,EAAA,CAAUA,CAAA,CAAQ,CAAR,CACVN,EAAAg5B,SAAA,CAAc,gBAAd,CAAgC,QAAQ,CAACj8B,CAAD,CAAQ,CAC9CuD,CAAAyY,YAAA,CAAsBhc,CAAA,GAAU1B,CAAV,CAAsB,EAAtB,CAA2B0B,CADH,CAAhD,CAJuD,CAFF,CADpD,CADmF,CAA9D,CAn3D9B,CAm7DI+R,GAAsB,CAAC,MAAD,CAAS,QAAT,CAAmB,UAAnB,CAA+B,QAAQ,CAACgH,CAAD,CAAOR,CAAP,CAAewwD,CAAf,CAAyB,CACxF,MAAO,CACLv7C,SAAU,GADL,CAELhjB,QAAS8+D,QAA0B,CAACC,CAAD,CAAWrxC,CAAX,CAAmB,CACpD,IAAIsxC,EAAmBjxD,CAAA,CAAO2f,CAAApmB,WAAP,CAAvB,CACI23D,EAAkBlxD,CAAA,CAAO2f,CAAApmB,WAAP,CAA0B43D,QAAuB,CAAC1pE,CAAD,CAAQ,CAC7E,MAAOkC,CAAClC,CAADkC,EAAU,EAAVA,UAAA,EADsE,CAAzD,CAGtB6mE,EAAAlvC,kBAAA,CAA2B0vC,CAA3B,CAEA,OAAOI,SAAuB,CAACp/D,CAAD,CAAQhH,CAAR,CAAiBN,CAAjB,CAAuB,CACnD8lE,CAAAhvC,iBAAA,CAA0Bx2B,CAA1B,CAAmCN,CAAA6O,WAAnC,CAEAvH,EAAA5H,OAAA,CAAa8mE,CAAb,CAA8BG,QAA8B,EAAG,CAG7DrmE,CAAAqE,KAAA,CAAamR,CAAA8wD,eAAA,CAAoBL,CAAA,CAAiBj/D,CAAjB,CAApB,CAAb,EAA6D,EAA7D,CAH6D,CAA/D,CAHmD,CAPD,CAFjD,CADiF,CAAhE,CAn7D1B,CA6gEIwK,GAAoB/S,EAAA,CAAQ,CAC9BwrB,SAAU,GADoB,CAE9BD,QAAS,SAFqB,CAG9B7C,KAAMA,QAAQ,CAACngB,CAAD,CAAQhH,CAAR,CAAiBN,CAAjB,CAAuBssD,CAAvB,CAA6B,CACzCA,CAAAua,qBAAAxlE,KAAA,CAA+B,QAAQ,EAAG,CACxCiG,CAAA61C,MAAA,CAAYn9C,CAAA6R,SAAZ,CADwC,CAA1C,CADyC,CAHb,CAAR,CA7gExB;AAg0EI3C,GAAmB4hD,EAAA,CAAe,EAAf,CAAmB,CAAA,CAAnB,CAh0EvB,CAg3EIxhD,GAAsBwhD,EAAA,CAAe,KAAf,CAAsB,CAAtB,CAh3E1B,CAg6EI1hD,GAAuB0hD,EAAA,CAAe,MAAf,CAAuB,CAAvB,CAh6E3B,CAs9EIthD,GAAmBg7C,EAAA,CAAY,CACjCjjD,QAASA,QAAQ,CAACjH,CAAD,CAAUN,CAAV,CAAgB,CAC/BA,CAAAg1B,KAAA,CAAU,SAAV,CAAqB35B,CAArB,CACAiF,EAAA8d,YAAA,CAAoB,UAApB,CAF+B,CADA,CAAZ,CAt9EvB,CA+rFI1O,GAAwB,CAAC,QAAQ,EAAG,CACtC,MAAO,CACL6a,SAAU,GADL,CAELjjB,MAAO,CAAA,CAFF,CAGLgC,WAAY,GAHP,CAIL+gB,SAAU,GAJL,CAD+B,CAAZ,CA/rF5B,CAy5FIpX,GAAoB,EAz5FxB,CA85FI6zD,GAAmB,CACrB,KAAQ,CAAA,CADa,CAErB,MAAS,CAAA,CAFY,CAIvB9qE,EAAA,CACE,6IAAA,MAAA,CAAA,GAAA,CADF,CAEE,QAAQ,CAACuhD,CAAD,CAAY,CAClB,IAAIz0B,EAAgBgG,EAAA,CAAmB,KAAnB,CAA2ByuB,CAA3B,CACpBtqC,GAAA,CAAkB6V,CAAlB,CAAA,CAAmC,CAAC,QAAD,CAAW,YAAX,CAAyB,QAAQ,CAACxT,CAAD,CAASE,CAAT,CAAqB,CACvF,MAAO,CACL+U,SAAU,GADL,CAELhjB,QAASA,QAAQ,CAAC8jB,CAAD,CAAWrrB,CAAX,CAAiB,CAKhC,IAAI0C;AAAK4S,CAAA,CAAOtV,CAAA,CAAK8oB,CAAL,CAAP,CAAgD,IAAhD,CAA4E,CAAA,CAA5E,CACT,OAAOi+C,SAAuB,CAACz/D,CAAD,CAAQhH,CAAR,CAAiB,CAC7CA,CAAA6I,GAAA,CAAWo0C,CAAX,CAAsB,QAAQ,CAACrgC,CAAD,CAAQ,CACpC,IAAIsI,EAAWA,QAAQ,EAAG,CACxB9iB,CAAA,CAAG4E,CAAH,CAAU,CAACsyC,OAAO18B,CAAR,CAAV,CADwB,CAGtB4pD,GAAA,CAAiBvpB,CAAjB,CAAJ,EAAmC/nC,CAAA6rB,QAAnC,CACE/5B,CAAA7H,WAAA,CAAiB+lB,CAAjB,CADF,CAGEle,CAAAE,OAAA,CAAage,CAAb,CAPkC,CAAtC,CAD6C,CANf,CAF7B,CADgF,CAAtD,CAFjB,CAFtB,CAogBA,KAAIxV,GAAgB,CAAC,UAAD,CAAa,QAAQ,CAACoD,CAAD,CAAW,CAClD,MAAO,CACLyhB,aAAc,CAAA,CADT,CAELlH,WAAY,SAFP,CAGLtD,SAAU,GAHL,CAIL8D,SAAU,CAAA,CAJL,CAKL5D,SAAU,GALL,CAMLmJ,MAAO,CAAA,CANF,CAOLjM,KAAMA,QAAQ,CAACiK,CAAD,CAASrG,CAAT,CAAmBuD,CAAnB,CAA0B09B,CAA1B,CAAgC16B,CAAhC,CAA6C,CAAA,IACnD5kB,CADmD,CAC5C8f,CAD4C,CAChCk6C,CACvBt1C,EAAAhyB,OAAA,CAAckvB,CAAA7e,KAAd,CAA0Bk3D,QAAwB,CAAClqE,CAAD,CAAQ,CAEpDA,CAAJ,CACO+vB,CADP,EAEI8E,CAAA,CAAY,QAAQ,CAACttB,CAAD,CAAQo0B,CAAR,CAAkB,CACpC5L,CAAA,CAAa4L,CACbp0B,EAAA,CAAMA,CAAA5I,OAAA,EAAN,CAAA,CAAwBN,CAAAu4B,cAAA,CAAuB,aAAvB,CAAuC/E,CAAA7e,KAAvC,CAAoD,GAApD,CAIxB/C,EAAA,CAAQ,CACN1I,MAAOA,CADD,CAGR8O,EAAAolD,MAAA,CAAel0D,CAAf,CAAsB+mB,CAAA5sB,OAAA,EAAtB,CAAyC4sB,CAAzC,CAToC,CAAtC,CAFJ,EAeM27C,CAQJ,GAPEA,CAAA1+C,OAAA,EACA,CAAA0+C,CAAA,CAAmB,IAMrB,EAJIl6C,CAIJ,GAHEA,CAAA/iB,SAAA,EACA,CAAA+iB,CAAA,CAAa,IAEf,EAAI9f,CAAJ,GACEg6D,CAIA;AAJmBn8D,EAAA,CAAcmC,CAAA1I,MAAd,CAInB,CAHA8O,CAAAslD,MAAA,CAAesO,CAAf,CAAAxxC,KAAA,CAAsC,QAAQ,EAAG,CAC/CwxC,CAAA,CAAmB,IAD4B,CAAjD,CAGA,CAAAh6D,CAAA,CAAQ,IALV,CAvBF,CAFwD,CAA1D,CAFuD,CAPtD,CAD2C,CAAhC,CAApB,CAkOIkD,GAAqB,CAAC,kBAAD,CAAqB,eAArB,CAAsC,UAAtC,CACP,QAAQ,CAACoG,CAAD,CAAqBpD,CAArB,CAAsCE,CAAtC,CAAgD,CACxE,MAAO,CACLmX,SAAU,KADL,CAELF,SAAU,GAFL,CAGL8D,SAAU,CAAA,CAHL,CAILR,WAAY,SAJP,CAKLrkB,WAAY1B,EAAAhJ,KALP,CAML2I,QAASA,QAAQ,CAACjH,CAAD,CAAUN,CAAV,CAAgB,CAAA,IAC3BknE,EAASlnE,CAAAiQ,UAATi3D,EAA2BlnE,CAAAnC,IADA,CAE3BspE,EAAYnnE,CAAAyjC,OAAZ0jC,EAA2B,EAFA,CAG3BC,EAAgBpnE,CAAAqnE,WAEpB,OAAO,SAAQ,CAAC//D,CAAD,CAAQ+jB,CAAR,CAAkBuD,CAAlB,CAAyB09B,CAAzB,CAA+B16B,CAA/B,CAA4C,CAAA,IACrD01C,EAAgB,CADqC,CAErDztB,CAFqD,CAGrD0tB,CAHqD,CAIrDC,CAJqD,CAMrDC,EAA4BA,QAAQ,EAAG,CACrCF,CAAJ,GACEA,CAAAj/C,OAAA,EACA,CAAAi/C,CAAA,CAAkB,IAFpB,CAII1tB,EAAJ,GACEA,CAAA9vC,SAAA,EACA,CAAA8vC,CAAA,CAAe,IAFjB,CAII2tB,EAAJ,GACEp0D,CAAAslD,MAAA,CAAe8O,CAAf,CAAAhyC,KAAA,CAAoC,QAAQ,EAAG,CAC7C+xC,CAAA,CAAkB,IAD2B,CAA/C,CAIA,CADAA,CACA,CADkBC,CAClB,CAAAA,CAAA,CAAiB,IALnB,CATyC,CAkB3ClgE,EAAA5H,OAAA,CAAawnE,CAAb,CAAqBQ,QAA6B,CAAC7pE,CAAD,CAAM,CACtD,IAAI8pE,EAAiBA,QAAQ,EAAG,CAC1B,CAAAvoE,CAAA,CAAUgoE,CAAV,CAAJ,EAAkCA,CAAlC,EAAmD,CAAA9/D,CAAA61C,MAAA,CAAYiqB,CAAZ,CAAnD;AACEl0D,CAAA,EAF4B,CAAhC,CAKI00D,EAAe,EAAEN,CAEjBzpE,EAAJ,EAGEyY,CAAA,CAAiBzY,CAAjB,CAAsB,CAAA,CAAtB,CAAA23B,KAAA,CAAiC,QAAQ,CAACwJ,CAAD,CAAW,CAClD,GAAI4oC,CAAJ,GAAqBN,CAArB,CAAA,CACA,IAAI5uC,EAAWpxB,CAAAgmB,KAAA,EACfg/B,EAAAz5B,SAAA,CAAgBmM,CAQZ16B,EAAAA,CAAQstB,CAAA,CAAY8G,CAAZ,CAAsB,QAAQ,CAACp0B,CAAD,CAAQ,CAChDmjE,CAAA,EACAr0D,EAAAolD,MAAA,CAAel0D,CAAf,CAAsB,IAAtB,CAA4B+mB,CAA5B,CAAAmK,KAAA,CAA2CmyC,CAA3C,CAFgD,CAAtC,CAKZ9tB,EAAA,CAAenhB,CACf8uC,EAAA,CAAiBljE,CAEjBu1C,EAAA+D,MAAA,CAAmB,uBAAnB,CAA4C//C,CAA5C,CACAyJ,EAAA61C,MAAA,CAAYgqB,CAAZ,CAnBA,CADkD,CAApD,CAqBG,QAAQ,EAAG,CACRS,CAAJ,GAAqBN,CAArB,GACEG,CAAA,EACA,CAAAngE,CAAAs2C,MAAA,CAAY,sBAAZ,CAAoC//C,CAApC,CAFF,CADY,CArBd,CA2BA,CAAAyJ,CAAAs2C,MAAA,CAAY,0BAAZ,CAAwC//C,CAAxC,CA9BF,GAgCE4pE,CAAA,EACA,CAAAnb,CAAAz5B,SAAA,CAAgB,IAjClB,CARsD,CAAxD,CAxByD,CAL5B,CAN5B,CADiE,CADjD,CAlOzB,CA6TI9f,GAAgC,CAAC,UAAD,CAClC,QAAQ,CAAC+yD,CAAD,CAAW,CACjB,MAAO,CACLv7C,SAAU,KADL,CAELF,SAAW,IAFN,CAGLC,QAAS,WAHJ,CAIL7C,KAAMA,QAAQ,CAACngB,CAAD,CAAQ+jB,CAAR,CAAkBuD,CAAlB,CAAyB09B,CAAzB,CAA+B,CACvC,KAAAlrD,KAAA,CAAWiqB,CAAA,CAAS,CAAT,CAAApsB,SAAA,EAAX,CAAJ,EAIEosB,CAAA9mB,MAAA,EACA,CAAAuhE,CAAA,CAAShuD,EAAA,CAAoBw0C,CAAAz5B,SAApB,CAAmCz3B,CAAnC,CAAAyd,WAAT,CAAA,CAAkEvR,CAAlE,CACIugE,QAA8B,CAACvjE,CAAD,CAAQ,CACxC+mB,CAAA3mB,OAAA,CAAgBJ,CAAhB,CADwC,CAD1C;AAGG,CAAC+nB,oBAAqBhB,CAAtB,CAHH,CALF,GAYAA,CAAA1mB,KAAA,CAAc2nD,CAAAz5B,SAAd,CACA,CAAAizC,CAAA,CAASz6C,CAAAyI,SAAA,EAAT,CAAA,CAA8BxsB,CAA9B,CAbA,CAD2C,CAJxC,CADU,CADe,CA7TpC,CA8YI8I,GAAkBo6C,EAAA,CAAY,CAChCngC,SAAU,GADsB,CAEhC9iB,QAASA,QAAQ,EAAG,CAClB,MAAO,CACLspB,IAAKA,QAAQ,CAACvpB,CAAD,CAAQhH,CAAR,CAAiButB,CAAjB,CAAwB,CACnCvmB,CAAA61C,MAAA,CAAYtvB,CAAA1d,OAAZ,CADmC,CADhC,CADW,CAFY,CAAZ,CA9YtB,CA6eIyB,GAAkBA,QAAQ,EAAG,CAC/B,MAAO,CACL2Y,SAAU,GADL,CAELF,SAAU,GAFL,CAGLC,QAAS,SAHJ,CAIL7C,KAAMA,QAAQ,CAACngB,CAAD,CAAQhH,CAAR,CAAiBN,CAAjB,CAAuBssD,CAAvB,CAA6B,CAGzC,IAAI36C,EAASrR,CAAAN,KAAA,CAAaA,CAAA4uB,MAAAjd,OAAb,CAATA,EAA4C,IAAhD,CACIm2D,EAA6B,OAA7BA,GAAa9nE,CAAA2tD,OADjB,CAEInlD,EAAYs/D,CAAA,CAAa5uD,CAAA,CAAKvH,CAAL,CAAb,CAA4BA,CAiB5C26C,EAAAuD,SAAAxuD,KAAA,CAfYiC,QAAQ,CAACshE,CAAD,CAAY,CAE9B,GAAI,CAAAzlE,CAAA,CAAYylE,CAAZ,CAAJ,CAAA,CAEA,IAAI1iD,EAAO,EAEP0iD,EAAJ,EACE5oE,CAAA,CAAQ4oE,CAAAxkE,MAAA,CAAgBoI,CAAhB,CAAR,CAAoC,QAAQ,CAACzL,CAAD,CAAQ,CAC9CA,CAAJ,EAAWmlB,CAAA7gB,KAAA,CAAUymE,CAAA,CAAa5uD,CAAA,CAAKnc,CAAL,CAAb,CAA2BA,CAArC,CADuC,CAApD,CAKF,OAAOmlB,EAVP,CAF8B,CAehC,CACAoqC,EAAAgB,YAAAjsD,KAAA,CAAsB,QAAQ,CAACtE,CAAD,CAAQ,CACpC,MAAIhB,EAAA,CAAQgB,CAAR,CAAJ,CACSA,CAAAwI,KAAA,CAAWoM,CAAX,CADT,CAIOtW,CAL6B,CAAtC,CASAixD,EAAAiB,SAAA,CAAgBgY,QAAQ,CAACxoE,CAAD,CAAQ,CAC9B,MAAO,CAACA,CAAR;AAAiB,CAACA,CAAArB,OADY,CAhCS,CAJtC,CADwB,CA7ejC,CAiiBIo2D,GAAc,UAjiBlB,CAkiBIC,GAAgB,YAliBpB,CAmiBIpF,GAAiB,aAniBrB,CAoiBIC,GAAc,UApiBlB,CAuiBIsF,GAAgB,YAviBpB,CA0iBInC,GAAiB,IAAIz0D,CAAJ,CAAW,SAAX,CA1iBrB,CAkvBIysE,GAAoB,CAAC,QAAD,CAAW,mBAAX,CAAgC,QAAhC,CAA0C,UAA1C,CAAsD,QAAtD,CAAgE,UAAhE,CAA4E,UAA5E,CAAwF,YAAxF,CAAsG,IAAtG,CAA4G,cAA5G,CACpB,QAAQ,CAACr2C,CAAD,CAASxd,CAAT,CAA4B0a,CAA5B,CAAmCvD,CAAnC,CAA6C/V,CAA7C,CAAqDlC,CAArD,CAA+DsD,CAA/D,CAAyElB,CAAzE,CAAqFE,CAArF,CAAyFpB,CAAzF,CAAuG,CAEjH,IAAA0zD,YAAA,CADA,IAAApa,WACA,CADkB1lC,MAAAinC,IAElB,KAAA8Y,gBAAA,CAAuB5sE,CACvB,KAAA60D,YAAA,CAAmB,EACnB,KAAAgY,iBAAA,CAAwB,EACxB,KAAArY,SAAA,CAAgB,EAChB,KAAAvC,YAAA,CAAmB,EACnB,KAAAuZ,qBAAA,CAA4B,EAC5B,KAAAsB,WAAA,CAAkB,CAAA,CAClB,KAAAC,SAAA,CAAgB,CAAA,CAChB,KAAAjd,UAAA,CAAiB,CAAA,CACjB,KAAAD,OAAA;AAAc,CAAA,CACd,KAAAE,OAAA,CAAc,CAAA,CACd,KAAAC,SAAA,CAAgB,CAAA,CAChB,KAAAP,OAAA,CAAc,EACd,KAAAC,UAAA,CAAiB,EACjB,KAAAC,SAAA,CAAgB3vD,CAChB,KAAA4vD,MAAA,CAAa32C,CAAA,CAAasa,CAAAvoB,KAAb,EAA2B,EAA3B,CAA+B,CAAA,CAA/B,CAAA,CAAsCqrB,CAAtC,CAlBoG,KAqB7G22C,EAAgB/yD,CAAA,CAAOsZ,CAAAnd,QAAP,CArB6F,CAsB7G62D,EAAsBD,CAAAnvC,OAtBuF,CAuB7GqvC,EAAaF,CAvBgG,CAwB7GG,EAAaF,CAxBgG,CAyB7GG,EAAkB,IAzB2F,CA0B7GC,CA1B6G,CA2B7Gpc,EAAO,IAEX,KAAAqc,aAAA,CAAoBC,QAAQ,CAAC/kD,CAAD,CAAU,CAEpC,IADAyoC,CAAAoD,SACA,CADgB7rC,CAChB,GAAeA,CAAAglD,aAAf,CAAqC,CAAA,IAC/BC,EAAoBxzD,CAAA,CAAOsZ,CAAAnd,QAAP,CAAuB,IAAvB,CADW,CAE/Bs3D,EAAoBzzD,CAAA,CAAOsZ,CAAAnd,QAAP,CAAuB,QAAvB,CAExB82D,EAAA,CAAaA,QAAQ,CAAC72C,CAAD,CAAS,CAC5B,IAAIizC,EAAa0D,CAAA,CAAc32C,CAAd,CACbt1B,EAAA,CAAWuoE,CAAX,CAAJ,GACEA,CADF,CACemE,CAAA,CAAkBp3C,CAAlB,CADf,CAGA,OAAOizC,EALqB,CAO9B6D,EAAA,CAAaA,QAAQ,CAAC92C,CAAD,CAASgG,CAAT,CAAmB,CAClCt7B,CAAA,CAAWisE,CAAA,CAAc32C,CAAd,CAAX,CAAJ,CACEq3C,CAAA,CAAkBr3C,CAAlB,CAA0B,CAACs3C,KAAM1c,CAAA0b,YAAP,CAA1B,CADF,CAGEM,CAAA,CAAoB52C,CAApB,CAA4B46B,CAAA0b,YAA5B,CAJoC,CAXL,CAArC,IAkBO,IAAK9uC,CAAAmvC,CAAAnvC,OAAL,CACL,KAAM62B,GAAA,CAAe,WAAf,CACFnhC,CAAAnd,QADE,CACarN,EAAA,CAAYinB,CAAZ,CADb,CAAN,CArBkC,CA8CtC,KAAA6iC,QAAA,CAAetvD,CAoBf,KAAA2uD,SAAA,CAAgB0b,QAAQ,CAAClsE,CAAD,CAAQ,CAC9B,MAAOoC,EAAA,CAAYpC,CAAZ,CAAP;AAAuC,EAAvC,GAA6BA,CAA7B,EAAuD,IAAvD,GAA6CA,CAA7C,EAA+DA,CAA/D,GAAyEA,CAD3C,CA/FiF,KAmG7G4tD,EAAat/B,CAAA9hB,cAAA,CAAuB,iBAAvB,CAAbohD,EAA0DE,EAnGmD,CAoG7Gqe,EAAyB,CAwB7B7c,GAAA,CAAqB,CACnBC,KAAM,IADa,CAEnBjhC,SAAUA,CAFS,CAGnBkhC,IAAKA,QAAQ,CAACrb,CAAD,CAASjF,CAAT,CAAmB,CAC9BiF,CAAA,CAAOjF,CAAP,CAAA,CAAmB,CAAA,CADW,CAHb,CAMnBugB,MAAOA,QAAQ,CAACtb,CAAD,CAASjF,CAAT,CAAmB,CAChC,OAAOiF,CAAA,CAAOjF,CAAP,CADyB,CANf,CASnB0e,WAAYA,CATO,CAUnBv3C,SAAUA,CAVS,CAArB,CAwBA,KAAAy5C,aAAA,CAAoBsc,QAAQ,EAAG,CAC7B7c,CAAApB,OAAA,CAAc,CAAA,CACdoB,EAAAnB,UAAA,CAAiB,CAAA,CACjB/3C,EAAAgL,YAAA,CAAqBiN,CAArB,CAA+BuhC,EAA/B,CACAx5C,EAAA+K,SAAA,CAAkBkN,CAAlB,CAA4BshC,EAA5B,CAJ6B,CAkB/B,KAAAF,UAAA,CAAiB2c,QAAQ,EAAG,CAC1B9c,CAAApB,OAAA,CAAc,CAAA,CACdoB,EAAAnB,UAAA,CAAiB,CAAA,CACjB/3C,EAAAgL,YAAA,CAAqBiN,CAArB,CAA+BshC,EAA/B,CACAv5C,EAAA+K,SAAA,CAAkBkN,CAAlB,CAA4BuhC,EAA5B,CACAjC,EAAA8B,UAAA,EAL0B,CAoB5B,KAAAQ,cAAA,CAAqBoc,QAAQ,EAAG,CAC9B/c,CAAA8b,SAAA,CAAgB,CAAA,CAChB9b,EAAA6b,WAAA,CAAkB,CAAA,CAClB/0D,EAAA25C,SAAA,CAAkB1hC,CAAlB,CA3YkBi+C,cA2YlB,CA1YgBC,YA0YhB,CAH8B,CAiBhC,KAAAC,YAAA;AAAmBC,QAAQ,EAAG,CAC5Bnd,CAAA8b,SAAA,CAAgB,CAAA,CAChB9b,EAAA6b,WAAA,CAAkB,CAAA,CAClB/0D,EAAA25C,SAAA,CAAkB1hC,CAAlB,CA3ZgBk+C,YA2ZhB,CA5ZkBD,cA4ZlB,CAH4B,CAmE9B,KAAA9d,mBAAA,CAA0Bke,QAAQ,EAAG,CACnChzD,CAAAqQ,OAAA,CAAgB0hD,CAAhB,CACAnc,EAAAsB,WAAA,CAAkBtB,CAAAqd,yBAClBrd,EAAA4B,QAAA,EAHmC,CAkBrC,KAAAkC,UAAA,CAAiBwZ,QAAQ,EAAG,CAE1B,GAAI,CAAAtqE,CAAA,CAASgtD,CAAA0b,YAAT,CAAJ,EAAkC,CAAArkE,KAAA,CAAM2oD,CAAA0b,YAAN,CAAlC,CAAA,CASA,IAAIrD,EAAarY,CAAA2b,gBAAjB,CAEI4B,EAAYvd,CAAAlB,OAFhB,CAGI0e,EAAiBxd,CAAA0b,YAHrB,CAKI+B,EAAezd,CAAAoD,SAAfqa,EAAgCzd,CAAAoD,SAAAqa,aAEpCzd,EAAA0d,gBAAA,CAAqBrF,CAArB,CAZgBrY,CAAAqd,yBAYhB,CAA4C,QAAQ,CAACM,CAAD,CAAW,CAGxDF,CAAL,EAAqBF,CAArB,GAAmCI,CAAnC,GAKE3d,CAAA0b,YAEA,CAFmBiC,CAAA,CAAWtF,CAAX,CAAwBtpE,CAE3C,CAAIixD,CAAA0b,YAAJ,GAAyB8B,CAAzB,EACExd,CAAA4d,oBAAA,EARJ,CAH6D,CAA/D,CAhBA,CAF0B,CAoC5B,KAAAF,gBAAA;AAAuBG,QAAQ,CAACxF,CAAD,CAAaC,CAAb,CAAwBwF,CAAxB,CAAsC,CAmCnEC,QAASA,EAAqB,EAAG,CAC/B,IAAIC,EAAsB,CAAA,CAC1BtuE,EAAA,CAAQswD,CAAA4D,YAAR,CAA0B,QAAQ,CAACqa,CAAD,CAAYlkE,CAAZ,CAAkB,CAClD,IAAIsZ,EAAS4qD,CAAA,CAAU5F,CAAV,CAAsBC,CAAtB,CACb0F,EAAA,CAAsBA,CAAtB,EAA6C3qD,CAC7CqyC,EAAA,CAAY3rD,CAAZ,CAAkBsZ,CAAlB,CAHkD,CAApD,CAKA,OAAK2qD,EAAL,CAMO,CAAA,CANP,EACEtuE,CAAA,CAAQswD,CAAA4b,iBAAR,CAA+B,QAAQ,CAAC1rC,CAAD,CAAIn2B,CAAJ,CAAU,CAC/C2rD,CAAA,CAAY3rD,CAAZ,CAAkB,IAAlB,CAD+C,CAAjD,CAGO,CAAA,CAAA,CAJT,CAP+B,CAgBjCmkE,QAASA,EAAsB,EAAG,CAChC,IAAIC,EAAoB,EAAxB,CACIR,EAAW,CAAA,CACfjuE,EAAA,CAAQswD,CAAA4b,iBAAR,CAA+B,QAAQ,CAACqC,CAAD,CAAYlkE,CAAZ,CAAkB,CACvD,IAAI85B,EAAUoqC,CAAA,CAAU5F,CAAV,CAAsBC,CAAtB,CACd,IAAmBzkC,CAAAA,CAAnB,EArovBQ,CAAA/jC,CAAA,CAqovBW+jC,CArovBA3K,KAAX,CAqovBR,CACE,KAAMu6B,GAAA,CAAe,kBAAf,CAC0E5vB,CAD1E,CAAN,CAGF6xB,CAAA,CAAY3rD,CAAZ,CAAkBhL,CAAlB,CACAovE,EAAAppE,KAAA,CAAuB8+B,CAAA3K,KAAA,CAAa,QAAQ,EAAG,CAC7Cw8B,CAAA,CAAY3rD,CAAZ,CAAkB,CAAA,CAAlB,CAD6C,CAAxB,CAEpB,QAAQ,CAAC8d,CAAD,CAAQ,CACjB8lD,CAAA,CAAW,CAAA,CACXjY,EAAA,CAAY3rD,CAAZ,CAAkB,CAAA,CAAlB,CAFiB,CAFI,CAAvB,CAPuD,CAAzD,CAcKokE,EAAA/uE,OAAL,CAGEga,CAAA4hC,IAAA,CAAOmzB,CAAP,CAAAj1C,KAAA,CAA+B,QAAQ,EAAG,CACxCk1C,CAAA,CAAeT,CAAf,CADwC,CAA1C,CAEGrrE,CAFH,CAHF,CACE8rE,CAAA,CAAe,CAAA,CAAf,CAlB8B,CA0BlC1Y,QAASA,EAAW,CAAC3rD,CAAD,CAAOwrD,CAAP,CAAgB,CAC9B8Y,CAAJ,GAA6BzB,CAA7B,EACE5c,CAAAF,aAAA,CAAkB/lD,CAAlB,CAAwBwrD,CAAxB,CAFgC,CAMpC6Y,QAASA,EAAc,CAACT,CAAD,CAAW,CAC5BU,CAAJ,GAA6BzB,CAA7B,EAEEkB,CAAA,CAAaH,CAAb,CAH8B,CAlFlCf,CAAA,EACA,KAAIyB,EAAuBzB,CAa3B0B,UAA2B,EAAG,CAC5B,IAAIC;AAAWve,CAAAsD,aAAXib,EAAgC,OACpC,IAAInC,CAAJ,GAAoBrtE,CAApB,CACE22D,CAAA,CAAY6Y,CAAZ,CAAsB,IAAtB,CADF,KAaE,OAVKnC,EAUEA,GATL1sE,CAAA,CAAQswD,CAAA4D,YAAR,CAA0B,QAAQ,CAAC1zB,CAAD,CAAIn2B,CAAJ,CAAU,CAC1C2rD,CAAA,CAAY3rD,CAAZ,CAAkB,IAAlB,CAD0C,CAA5C,CAGA,CAAArK,CAAA,CAAQswD,CAAA4b,iBAAR,CAA+B,QAAQ,CAAC1rC,CAAD,CAAIn2B,CAAJ,CAAU,CAC/C2rD,CAAA,CAAY3rD,CAAZ,CAAkB,IAAlB,CAD+C,CAAjD,CAMKqiE,EADP1W,CAAA,CAAY6Y,CAAZ,CAAsBnC,CAAtB,CACOA,CAAAA,CAET,OAAO,CAAA,CAjBqB,CAA9BkC,CAVK,EAAL,CAIKP,CAAA,EAAL,CAIAG,CAAA,EAJA,CACEE,CAAA,CAAe,CAAA,CAAf,CALF,CACEA,CAAA,CAAe,CAAA,CAAf,CANiE,CAsGrE,KAAA/e,iBAAA,CAAwBmf,QAAQ,EAAG,CACjC,IAAIlG,EAAYtY,CAAAsB,WAEhBl3C,EAAAqQ,OAAA,CAAgB0hD,CAAhB,CAKA,IAAInc,CAAAqd,yBAAJ,GAAsC/E,CAAtC,EAAkE,EAAlE,GAAoDA,CAApD,EAAyEtY,CAAAuB,sBAAzE,CAGAvB,CAAAqd,yBAMA,CANgC/E,CAMhC,CAHItY,CAAAnB,UAGJ,EAFE,IAAAsB,UAAA,EAEF,CAAA,IAAAse,mBAAA,EAjBiC,CAoBnC,KAAAA,mBAAA,CAA0BC,QAAQ,EAAG,CAEnC,IAAIrG,EADYrY,CAAAqd,yBAIhB,IAFAjB,CAEA,CAFcvpE,CAAA,CAAYwlE,CAAZ,CAAA,CAA0BtpE,CAA1B,CAAsC,CAAA,CAEpD,CACE,IAAS,IAAAuB;AAAI,CAAb,CAAgBA,CAAhB,CAAoB0vD,CAAAuD,SAAAn0D,OAApB,CAA0CkB,CAAA,EAA1C,CAEE,GADA+nE,CACI,CADSrY,CAAAuD,SAAA,CAAcjzD,CAAd,CAAA,CAAiB+nE,CAAjB,CACT,CAAAxlE,CAAA,CAAYwlE,CAAZ,CAAJ,CAA6B,CAC3B+D,CAAA,CAAc,CAAA,CACd,MAF2B,CAM7BppE,CAAA,CAASgtD,CAAA0b,YAAT,CAAJ,EAAkCrkE,KAAA,CAAM2oD,CAAA0b,YAAN,CAAlC,GAEE1b,CAAA0b,YAFF,CAEqBO,CAAA,CAAW72C,CAAX,CAFrB,CAIA,KAAIo4C,EAAiBxd,CAAA0b,YAArB,CACI+B,EAAezd,CAAAoD,SAAfqa,EAAgCzd,CAAAoD,SAAAqa,aACpCzd,EAAA2b,gBAAA,CAAuBtD,CAEnBoF,EAAJ,GACEzd,CAAA0b,YAkBA,CAlBmBrD,CAkBnB,CAAIrY,CAAA0b,YAAJ,GAAyB8B,CAAzB,EACExd,CAAA4d,oBAAA,EApBJ,CAOA5d,EAAA0d,gBAAA,CAAqBrF,CAArB,CAAiCrY,CAAAqd,yBAAjC,CAAgE,QAAQ,CAACM,CAAD,CAAW,CAC5EF,CAAL,GAKEzd,CAAA0b,YAMF,CANqBiC,CAAA,CAAWtF,CAAX,CAAwBtpE,CAM7C,CAAIixD,CAAA0b,YAAJ,GAAyB8B,CAAzB,EACExd,CAAA4d,oBAAA,EAZF,CADiF,CAAnF,CA7BmC,CA+CrC,KAAAA,oBAAA,CAA2Be,QAAQ,EAAG,CACpCzC,CAAA,CAAW92C,CAAX,CAAmB46B,CAAA0b,YAAnB,CACAhsE,EAAA,CAAQswD,CAAAua,qBAAR,CAAmC,QAAQ,CAAC9hD,CAAD,CAAW,CACpD,GAAI,CACFA,CAAA,EADE,CAEF,MAAOvgB,CAAP,CAAU,CACV0P,CAAA,CAAkB1P,CAAlB,CADU,CAHwC,CAAtD,CAFoC,CAmDtC;IAAAspD,cAAA,CAAqBod,QAAQ,CAACnuE,CAAD,CAAQ82D,CAAR,CAAiB,CAC5CvH,CAAAsB,WAAA,CAAkB7wD,CACbuvD,EAAAoD,SAAL,EAAsByb,CAAA7e,CAAAoD,SAAAyb,gBAAtB,EACE7e,CAAA8e,0BAAA,CAA+BvX,CAA/B,CAH0C,CAO9C,KAAAuX,0BAAA,CAAiCC,QAAQ,CAACxX,CAAD,CAAU,CAAA,IAC7CyX,EAAgB,CAD6B,CAE7CznD,EAAUyoC,CAAAoD,SAGV7rC,EAAJ,EAAezkB,CAAA,CAAUykB,CAAA0nD,SAAV,CAAf,GACEA,CACA,CADW1nD,CAAA0nD,SACX,CAAIjsE,CAAA,CAASisE,CAAT,CAAJ,CACED,CADF,CACkBC,CADlB,CAEWjsE,CAAA,CAASisE,CAAA,CAAS1X,CAAT,CAAT,CAAJ,CACLyX,CADK,CACWC,CAAA,CAAS1X,CAAT,CADX,CAEIv0D,CAAA,CAASisE,CAAA,CAAS,SAAT,CAAT,CAFJ,GAGLD,CAHK,CAGWC,CAAA,CAAS,SAAT,CAHX,CAJT,CAWA70D,EAAAqQ,OAAA,CAAgB0hD,CAAhB,CACI6C,EAAJ,CACE7C,CADF,CACoB/xD,CAAA,CAAS,QAAQ,EAAG,CACpC41C,CAAAX,iBAAA,EADoC,CAApB,CAEf2f,CAFe,CADpB,CAIW91D,CAAA6rB,QAAJ,CACLirB,CAAAX,iBAAA,EADK,CAGLj6B,CAAAlqB,OAAA,CAAc,QAAQ,EAAG,CACvB8kD,CAAAX,iBAAA,EADuB,CAAzB,CAxB+C,CAsCnDj6B,EAAAhyB,OAAA,CAAc8rE,QAAqB,EAAG,CACpC,IAAI7G,EAAa4D,CAAA,CAAW72C,CAAX,CAIjB,IAAIizC,CAAJ,GAAmBrY,CAAA0b,YAAnB,GAEI1b,CAAA0b,YAFJ,GAEyB1b,CAAA0b,YAFzB,EAE6CrD,CAF7C,GAE4DA,CAF5D,EAGE,CACArY,CAAA0b,YAAA;AAAmB1b,CAAA2b,gBAAnB,CAA0CtD,CAC1C+D,EAAA,CAAcrtE,CAMd,KARA,IAIIowE,EAAanf,CAAAgB,YAJjB,CAKIngC,EAAMs+C,CAAA/vE,OALV,CAOIkpE,EAAYD,CAChB,CAAOx3C,CAAA,EAAP,CAAA,CACEy3C,CAAA,CAAY6G,CAAA,CAAWt+C,CAAX,CAAA,CAAgBy3C,CAAhB,CAEVtY,EAAAsB,WAAJ,GAAwBgX,CAAxB,GACEtY,CAAAsB,WAGA,CAHkBtB,CAAAqd,yBAGlB,CAHkD/E,CAGlD,CAFAtY,CAAA4B,QAAA,EAEA,CAAA5B,CAAA0d,gBAAA,CAAqBrF,CAArB,CAAiCC,CAAjC,CAA4ChmE,CAA5C,CAJF,CAXA,CAmBF,MAAO+lE,EA3B6B,CAAtC,CA7kBiH,CAD3F,CAlvBxB,CAwgDIjzD,GAAmB,CAAC,YAAD,CAAe,QAAQ,CAAC8D,CAAD,CAAa,CACzD,MAAO,CACL+U,SAAU,GADL,CAELD,QAAS,CAAC,SAAD,CAAY,QAAZ,CAAsB,kBAAtB,CAFJ,CAGLhhB,WAAYy+D,EAHP,CAOL19C,SAAU,CAPL,CAQL9iB,QAASmkE,QAAuB,CAACprE,CAAD,CAAU,CAExCA,CAAA6d,SAAA,CAAiBwuC,EAAjB,CAAAxuC,SAAA,CA9+BgBmrD,cA8+BhB,CAAAnrD,SAAA,CAAoE2zC,EAApE,CAEA,OAAO,CACLjhC,IAAK86C,QAAuB,CAACrkE,CAAD,CAAQhH,CAAR,CAAiBN,CAAjB,CAAuBwlE,CAAvB,CAA8B,CAAA,IACpDoG,EAAYpG,CAAA,CAAM,CAAN,CADwC,CAEpDqG,EAAWrG,CAAA,CAAM,CAAN,CAAXqG,EAAuBhhB,EAE3B+gB,EAAAjD,aAAA,CAAuBnD,CAAA,CAAM,CAAN,CAAvB,EAAmCA,CAAA,CAAM,CAAN,CAAA9V,SAAnC,CAGAmc,EAAAtgB,YAAA,CAAqBqgB,CAArB,CAEA5rE,EAAAg5B,SAAA,CAAc,MAAd;AAAsB,QAAQ,CAACtB,CAAD,CAAW,CACnCk0C,CAAA3gB,MAAJ,GAAwBvzB,CAAxB,EACEm0C,CAAA/f,gBAAA,CAAyB8f,CAAzB,CAAoCl0C,CAApC,CAFqC,CAAzC,CAMApwB,EAAAkmB,IAAA,CAAU,UAAV,CAAsB,QAAQ,EAAG,CAC/Bq+C,CAAA3f,eAAA,CAAwB0f,CAAxB,CAD+B,CAAjC,CAfwD,CADrD,CAoBL96C,KAAMg7C,QAAwB,CAACxkE,CAAD,CAAQhH,CAAR,CAAiBN,CAAjB,CAAuBwlE,CAAvB,CAA8B,CAC1D,IAAIoG,EAAYpG,CAAA,CAAM,CAAN,CAChB,IAAIoG,CAAAlc,SAAJ,EAA0Bkc,CAAAlc,SAAAqc,SAA1B,CACEzrE,CAAA6I,GAAA,CAAWyiE,CAAAlc,SAAAqc,SAAX,CAAwC,QAAQ,CAACre,CAAD,CAAK,CACnDke,CAAAR,0BAAA,CAAoC1d,CAApC,EAA0CA,CAAA1zC,KAA1C,CADmD,CAArD,CAKF1Z,EAAA6I,GAAA,CAAW,MAAX,CAAmB,QAAQ,CAACukD,CAAD,CAAK,CAC1Bke,CAAAxD,SAAJ,GAEI5yD,CAAA6rB,QAAJ,CACE/5B,CAAA7H,WAAA,CAAiBmsE,CAAApC,YAAjB,CADF,CAGEliE,CAAAE,OAAA,CAAaokE,CAAApC,YAAb,CALF,CAD8B,CAAhC,CAR0D,CApBvD,CAJiC,CARrC,CADkD,CAApC,CAxgDvB,CAgkDIwC,GAAiB,uBAhkDrB,CAkuDIl5D,GAA0BA,QAAQ,EAAG,CACvC,MAAO,CACLyX,SAAU,GADL,CAELjhB,WAAY,CAAC,QAAD,CAAW,QAAX,CAAqB,QAAQ,CAACooB,CAAD,CAASC,CAAT,CAAiB,CACxD,IAAIs6C,EAAO,IACX,KAAAvc,SAAA,CAAgB7uD,EAAA,CAAK6wB,CAAAyrB,MAAA,CAAaxrB,CAAA9e,eAAb,CAAL,CAEZ;IAAA68C,SAAAqc,SAAJ,GAA+B1wE,CAA/B,EACE,IAAAq0D,SAAAyb,gBAEA,CAFgC,CAAA,CAEhC,CAAA,IAAAzb,SAAAqc,SAAA,CAAyB7yD,CAAA,CAAK,IAAAw2C,SAAAqc,SAAAlnE,QAAA,CAA+BmnE,EAA/B,CAA+C,QAAQ,EAAG,CACtFC,CAAAvc,SAAAyb,gBAAA,CAAgC,CAAA,CAChC,OAAO,GAF+E,CAA1D,CAAL,CAH3B,EAQE,IAAAzb,SAAAyb,gBARF,CAQkC,CAAA,CAZsB,CAA9C,CAFP,CADgC,CAluDzC,CAo4DI76D,GAAyBk6C,EAAA,CAAY,CAAEr8B,SAAU,CAAA,CAAZ,CAAkB9D,SAAU,GAA5B,CAAZ,CAp4D7B,CAw4DI6hD,GAAkB5wE,CAAA,CAAO,WAAP,CAx4DtB,CA6lEI6wE,GAAoB,2OA7lExB;AA0mEI76D,GAAqB,CAAC,UAAD,CAAa,QAAb,CAAuB,QAAQ,CAACw0D,CAAD,CAAWxwD,CAAX,CAAmB,CAEzE82D,QAASA,EAAsB,CAACC,CAAD,CAAaC,CAAb,CAA4BhlE,CAA5B,CAAmC,CAsDhEilE,QAASA,EAAM,CAACC,CAAD,CAAc5H,CAAd,CAAyB6H,CAAzB,CAAgCrlB,CAAhC,CAAuCslB,CAAvC,CAAiD,CAC9D,IAAAF,YAAA,CAAmBA,CACnB,KAAA5H,UAAA,CAAiBA,CACjB,KAAA6H,MAAA,CAAaA,CACb,KAAArlB,MAAA,CAAaA,CACb,KAAAslB,SAAA,CAAgBA,CAL8C,CAQhEC,QAASA,EAAmB,CAACC,CAAD,CAAe,CACzC,IAAIC,CAEJ,IAAKC,CAAAA,CAAL,EAAgBvxE,EAAA,CAAYqxE,CAAZ,CAAhB,CACEC,CAAA,CAAmBD,CADrB,KAEO,CAELC,CAAA,CAAmB,EACnB,KAASE,IAAAA,CAAT,GAAoBH,EAApB,CACMA,CAAAvwE,eAAA,CAA4B0wE,CAA5B,CAAJ,EAAkE,GAAlE,GAA4CA,CAAAlrE,OAAA,CAAe,CAAf,CAA5C,EACEgrE,CAAAxrE,KAAA,CAAsB0rE,CAAtB,CALC,CASP,MAAOF,EAdkC,CA5D3C,IAAIprE,EAAQ4qE,CAAA5qE,MAAA,CAAiB0qE,EAAjB,CACZ,IAAM1qE,CAAAA,CAAN,CACE,KAAMyqE,GAAA,CAAgB,MAAhB,CAIJG,CAJI,CAIQjoE,EAAA,CAAYkoE,CAAZ,CAJR,CAAN,CAUF,IAAIU,EAAYvrE,CAAA,CAAM,CAAN,CAAZurE,EAAwBvrE,CAAA,CAAM,CAAN,CAA5B,CAEIqrE,EAAUrrE,CAAA,CAAM,CAAN,CAGVwrE,EAAAA,CAAW,MAAA7rE,KAAA,CAAYK,CAAA,CAAM,CAAN,CAAZ,CAAXwrE,EAAoCxrE,CAAA,CAAM,CAAN,CAExC,KAAIyrE,EAAUzrE,CAAA,CAAM,CAAN,CAEV1C,EAAAA,CAAUuW,CAAA,CAAO7T,CAAA,CAAM,CAAN,CAAA,CAAWA,CAAA,CAAM,CAAN,CAAX,CAAsBurE,CAA7B,CAEd,KAAIG,EADaF,CACbE,EADyB73D,CAAA,CAAO23D,CAAP,CACzBE,EAA4BpuE,CAAhC,CACIquE,EAAYF,CAAZE,EAAuB93D,CAAA,CAAO43D,CAAP,CAD3B,CAMIG,EAAoBH,CAAA,CACE,QAAQ,CAACnwE,CAAD,CAAQ+jB,CAAR,CAAgB,CAAE,MAAOssD,EAAA,CAAU9lE,CAAV,CAAiBwZ,CAAjB,CAAT,CAD1B,CAEEwsD,QAAuB,CAACvwE,CAAD,CAAQ,CAAE,MAAOshB,GAAA,CAAQthB,CAAR,CAAT,CARzD,CASIwwE,EAAkBA,QAAQ,CAACxwE,CAAD;AAAQZ,CAAR,CAAa,CACzC,MAAOkxE,EAAA,CAAkBtwE,CAAlB,CAAyBywE,CAAA,CAAUzwE,CAAV,CAAiBZ,CAAjB,CAAzB,CADkC,CAT3C,CAaIsxE,EAAYn4D,CAAA,CAAO7T,CAAA,CAAM,CAAN,CAAP,EAAmBA,CAAA,CAAM,CAAN,CAAnB,CAbhB,CAcIisE,EAAYp4D,CAAA,CAAO7T,CAAA,CAAM,CAAN,CAAP,EAAmB,EAAnB,CAdhB,CAeIksE,EAAgBr4D,CAAA,CAAO7T,CAAA,CAAM,CAAN,CAAP,EAAmB,EAAnB,CAfpB,CAgBImsE,EAAWt4D,CAAA,CAAO7T,CAAA,CAAM,CAAN,CAAP,CAhBf,CAkBIqf,EAAS,EAlBb,CAmBI0sD,EAAYV,CAAA,CAAU,QAAQ,CAAC/vE,CAAD,CAAQZ,CAAR,CAAa,CAC7C2kB,CAAA,CAAOgsD,CAAP,CAAA,CAAkB3wE,CAClB2kB,EAAA,CAAOksD,CAAP,CAAA,CAAoBjwE,CACpB,OAAO+jB,EAHsC,CAA/B,CAIZ,QAAQ,CAAC/jB,CAAD,CAAQ,CAClB+jB,CAAA,CAAOksD,CAAP,CAAA,CAAoBjwE,CACpB,OAAO+jB,EAFW,CA+BpB,OAAO,CACLosD,QAASA,CADJ,CAELK,gBAAiBA,CAFZ,CAGLM,cAAev4D,CAAA,CAAOs4D,CAAP,CAAiB,QAAQ,CAAChB,CAAD,CAAe,CAIrD,IAAIkB,EAAe,EACnBlB,EAAA,CAAeA,CAAf,EAA+B,EAI/B,KAFA,IAAIC,EAAmBF,CAAA,CAAoBC,CAApB,CAAvB,CACImB,EAAqBlB,CAAAnxE,OADzB,CAESgF,EAAQ,CAAjB,CAAoBA,CAApB,CAA4BqtE,CAA5B,CAAgDrtE,CAAA,EAAhD,CAAyD,CACvD,IAAIvE,EAAOywE,CAAD,GAAkBC,CAAlB,CAAsCnsE,CAAtC,CAA8CmsE,CAAA,CAAiBnsE,CAAjB,CAAxD,CAGIogB,EAAS0sD,CAAA,CAAUZ,CAAA,CAAazwE,CAAb,CAAV,CAA6BA,CAA7B,CAHb,CAIIqwE,EAAca,CAAA,CAAkBT,CAAA,CAAazwE,CAAb,CAAlB,CAAqC2kB,CAArC,CAClBgtD,EAAAzsE,KAAA,CAAkBmrE,CAAlB,CAGA,IAAI/qE,CAAA,CAAM,CAAN,CAAJ,EAAgBA,CAAA,CAAM,CAAN,CAAhB,CACMgrE,CACJ,CADYgB,CAAA,CAAUnmE,CAAV,CAAiBwZ,CAAjB,CACZ,CAAAgtD,CAAAzsE,KAAA,CAAkBorE,CAAlB,CAIEhrE,EAAA,CAAM,CAAN,CAAJ,GACMusE,CACJ,CADkBL,CAAA,CAAcrmE,CAAd,CAAqBwZ,CAArB,CAClB,CAAAgtD,CAAAzsE,KAAA,CAAkB2sE,CAAlB,CAFF,CAfuD,CAoBzD,MAAOF,EA7B8C,CAAxC,CAHV,CAmCLG,WAAYA,QAAQ,EAAG,CAWrB,IATA,IAAIC,EAAc,EAAlB,CACIC,EAAiB,EADrB,CAKIvB,EAAegB,CAAA,CAAStmE,CAAT,CAAfslE,EAAkC,EALtC,CAMIC,EAAmBF,CAAA,CAAoBC,CAApB,CANvB,CAOImB,EAAqBlB,CAAAnxE,OAPzB,CASSgF,EAAQ,CAAjB,CAAoBA,CAApB,CAA4BqtE,CAA5B,CAAgDrtE,CAAA,EAAhD,CAAyD,CACvD,IAAIvE,EAAOywE,CAAD,GAAkBC,CAAlB,CAAsCnsE,CAAtC,CAA8CmsE,CAAA,CAAiBnsE,CAAjB,CAAxD,CAEIogB;AAAS0sD,CAAA,CADDZ,CAAA7vE,CAAaZ,CAAbY,CACC,CAAiBZ,CAAjB,CAFb,CAGIyoE,EAAYuI,CAAA,CAAY7lE,CAAZ,CAAmBwZ,CAAnB,CAHhB,CAII0rD,EAAca,CAAA,CAAkBzI,CAAlB,CAA6B9jD,CAA7B,CAJlB,CAKI2rD,EAAQgB,CAAA,CAAUnmE,CAAV,CAAiBwZ,CAAjB,CALZ,CAMIsmC,EAAQsmB,CAAA,CAAUpmE,CAAV,CAAiBwZ,CAAjB,CANZ,CAOI4rD,EAAWiB,CAAA,CAAcrmE,CAAd,CAAqBwZ,CAArB,CAPf,CAQIstD,EAAa,IAAI7B,CAAJ,CAAWC,CAAX,CAAwB5H,CAAxB,CAAmC6H,CAAnC,CAA0CrlB,CAA1C,CAAiDslB,CAAjD,CAEjBwB,EAAA7sE,KAAA,CAAiB+sE,CAAjB,CACAD,EAAA,CAAe3B,CAAf,CAAA,CAA8B4B,CAZyB,CAezD,MAAO,CACLjuE,MAAO+tE,CADF,CAELC,eAAgBA,CAFX,CAGLE,uBAAwBA,QAAQ,CAACtxE,CAAD,CAAQ,CACtC,MAAOoxE,EAAA,CAAeZ,CAAA,CAAgBxwE,CAAhB,CAAf,CAD+B,CAHnC,CAMLuxE,uBAAwBA,QAAQ,CAAC7/D,CAAD,CAAS,CAGvC,MAAOy+D,EAAA,CAAUtlE,EAAA/G,KAAA,CAAa4N,CAAAm2D,UAAb,CAAV,CAA2Cn2D,CAAAm2D,UAHX,CANpC,CA1Bc,CAnClB,CA/EyD,CAFO,IAiKrE2J,EAAiBnzE,CAAAgd,cAAA,CAAuB,QAAvB,CAjKoD,CAkKrEo2D,EAAmBpzE,CAAAgd,cAAA,CAAuB,UAAvB,CAEvB,OAAO,CACLmS,SAAU,GADL,CAEL4D,SAAU,CAAA,CAFL,CAGL7D,QAAS,CAAC,QAAD,CAAW,UAAX,CAHJ,CAIL7C,KAAMA,QAAQ,CAACngB,CAAD,CAAQglE,CAAR,CAAuBtsE,CAAvB,CAA6BwlE,CAA7B,CAAoC,CAoLhDiJ,QAASA,EAAmB,CAAChgE,CAAD,CAASnO,CAAT,CAAkB,CAC5CmO,CAAAnO,QAAA,CAAiBA,CACjBA,EAAAosE,SAAA,CAAmBj+D,CAAAi+D,SACfj+D,EAAA1R,MAAJ,GAAqBuD,CAAAvD,MAArB,GAAoCuD,CAAAvD,MAApC,CAAoD0R,CAAA+9D,YAApD,CACI/9D,EAAAg+D,MAAJ;AAAqBnsE,CAAAmsE,MAArB,GACEnsE,CAAAmsE,MACA,CADgBh+D,CAAAg+D,MAChB,CAAAnsE,CAAAyY,YAAA,CAAsBtK,CAAAg+D,MAFxB,CAJ4C,CAU9CiC,QAASA,EAAiB,CAACjwE,CAAD,CAAS47C,CAAT,CAAkBrgC,CAAlB,CAAwBgsD,CAAxB,CAAyC,CAG7D3rB,CAAJ,EAAe95C,CAAA,CAAU85C,CAAAv6C,SAAV,CAAf,GAA+Cka,CAA/C,CAEE1Z,CAFF,CAEY+5C,CAFZ,EAKE/5C,CACA,CADU0lE,CAAAxsD,UAAA,CAA0B,CAAA,CAA1B,CACV,CAAK6gC,CAAL,CAKE57C,CAAA42D,aAAA,CAAoB/0D,CAApB,CAA6B+5C,CAA7B,CALF,CAEE57C,CAAA0Z,YAAA,CAAmB7X,CAAnB,CARJ,CAcA,OAAOA,EAjB0D,CAqBnEquE,QAASA,EAAoB,CAACt0B,CAAD,CAAU,CAErC,IADA,IAAIgD,CACJ,CAAOhD,CAAP,CAAA,CACEgD,CAEA,CAFOhD,CAAApvC,YAEP,CADAkR,EAAA,CAAak+B,CAAb,CACA,CAAAA,CAAA,CAAUgD,CALyB,CAUvCuxB,QAASA,EAA0B,CAACv0B,CAAD,CAAU,CAC3C,IAAIw0B,EAAeC,CAAfD,EAA8BC,CAAA,CAAY,CAAZ,CAAlC,CACIC,EAAiBC,CAAjBD,EAAkCC,CAAA,CAAc,CAAd,CAEtC,IAAIH,CAAJ,EAAoBE,CAApB,CACE,IAAA,CAAO10B,CAAP,GACOA,CADP,GACmBw0B,CADnB,EAEMx0B,CAFN,GAEkB00B,CAFlB,EAAA,CAGE10B,CAAA,CAAUA,CAAApvC,YAGd,OAAOovC,EAXoC,CAe7C40B,QAASA,EAAa,EAAG,CAEvB,IAAIC,EAAgBrrD,CAAhBqrD,EAA2BC,CAAAC,UAAA,EAE/BvrD,EAAA,CAAUxS,CAAA48D,WAAA,EAEV,KAAIoB,EAAW,EAAf,CACI7H,EAAiB8E,CAAA,CAAc,CAAd,CAAAxzD,WAGjBw2D,EAAJ,EACEhD,CAAA/W,QAAA,CAAsBuZ,CAAtB,CAGFtH,EAAA,CAAiBoH,CAAA,CAA2BpH,CAA3B,CAEjB3jD,EAAA1jB,MAAAnE,QAAA,CAAsBuzE,QAAqB,CAAC9gE,CAAD,CAAS,CAClD,IAAI24C,CAAJ,CAEIooB,CAEA/gE,EAAA24C,MAAJ,EAIEA,CA8BA,CA9BQioB,CAAA,CAAS5gE,CAAA24C,MAAT,CA8BR,CA5BKA,CA4BL,GAzBEqoB,CAWA,CAXef,CAAA,CAAkBpC,CAAA,CAAc,CAAd,CAAlB,CACkB9E,CADlB,CAEkB,UAFlB,CAGkBgH,CAHlB,CAWf,CANAhH,CAMA;AANiBiI,CAAAxkE,YAMjB,CAHAwkE,CAAAhD,MAGA,CAHqBh+D,CAAA24C,MAGrB,CAAAA,CAAA,CAAQioB,CAAA,CAAS5gE,CAAA24C,MAAT,CAAR,CAAiC,CAC/BqoB,aAAcA,CADiB,CAE/BC,qBAAsBD,CAAA32D,WAFS,CAcnC,EANA02D,CAMA,CANgBd,CAAA,CAAkBtnB,CAAAqoB,aAAlB,CACkBroB,CAAAsoB,qBADlB,CAEkB,QAFlB,CAGkBnB,CAHlB,CAMhB,CAFAE,CAAA,CAAoBhgE,CAApB,CAA4B+gE,CAA5B,CAEA,CAAApoB,CAAAsoB,qBAAA,CAA6BF,CAAAvkE,YAlC/B,GAuCEukE,CAMA,CANgBd,CAAA,CAAkBpC,CAAA,CAAc,CAAd,CAAlB,CACkB9E,CADlB,CAEkB,QAFlB,CAGkB+G,CAHlB,CAMhB,CAFAE,CAAA,CAAoBhgE,CAApB,CAA4B+gE,CAA5B,CAEA,CAAAhI,CAAA,CAAiBgI,CAAAvkE,YA7CnB,CALkD,CAApD,CAwDAtP,OAAAe,KAAA,CAAY2yE,CAAZ,CAAArzE,QAAA,CAA8B,QAAQ,CAACG,CAAD,CAAM,CAC1CwyE,CAAA,CAAqBU,CAAA,CAASlzE,CAAT,CAAAuzE,qBAArB,CAD0C,CAA5C,CAGAf,EAAA,CAAqBnH,CAArB,CAEAmI,EAAAzhB,QAAA,EAGA,IAAK,CAAAyhB,CAAApiB,SAAA,CAAqB2hB,CAArB,CAAL,CAA0C,CACxC,IAAIU,EAAYT,CAAAC,UAAA,EAChB,EAAI/9D,CAAA67D,QAAA,CAAqBprE,EAAA,CAAOotE,CAAP,CAAsBU,CAAtB,CAArB,CAAwDV,CAAxD,GAA0EU,CAA9E,IACED,CAAA7hB,cAAA,CAA0B8hB,CAA1B,CACA,CAAAD,CAAAzhB,QAAA,EAFF,CAFwC,CAhFnB,CAzOzB,IAAIyhB,EAAcnK,CAAA,CAAM,CAAN,CAClB,IAAKmK,CAAL,CAAA,CAEA,IAAIR,EAAa3J,CAAA,CAAM,CAAN,CACb9Q,EAAAA,CAAW10D,CAAA00D,SAKf,KADA,IAAIoa,CAAJ,CACSlyE,EAAI,CADb,CACgB0yC,EAAWg9B,CAAAh9B,SAAA,EAD3B,CACqD7xC,EAAK6xC,CAAA5zC,OAA1D,CAA2EkB,CAA3E;AAA+Ea,CAA/E,CAAmFb,CAAA,EAAnF,CACE,GAA0B,EAA1B,GAAI0yC,CAAA,CAAS1yC,CAAT,CAAAG,MAAJ,CAA8B,CAC5B+xE,CAAA,CAAcx/B,CAAA0L,GAAA,CAAYp+C,CAAZ,CACd,MAF4B,CAMhC,IAAI0yE,EAAsB,CAAER,CAAAA,CAA5B,CAEIE,EAAgB3qE,CAAA,CAAOkqE,CAAA/0D,UAAA,CAAyB,CAAA,CAAzB,CAAP,CACpBw1D,EAAAjsE,IAAA,CAAkB,GAAlB,CAEA,KAAI8gB,CAAJ,CACIxS,EAAY+6D,CAAA,CAAuBpsE,CAAAqR,UAAvB,CAAuCi7D,CAAvC,CAAsDhlE,CAAtD,CAgCXotD,EAAL,EAgDEib,CAAApiB,SAiCA,CAjCuBsiB,QAAQ,CAAC9yE,CAAD,CAAQ,CACrC,MAAO,CAACA,CAAR,EAAkC,CAAlC,GAAiBA,CAAArB,OADoB,CAiCvC,CA5BAyzE,CAAAW,WA4BA,CA5BwBC,QAA+B,CAAChzE,CAAD,CAAQ,CAC7D8mB,CAAA1jB,MAAAnE,QAAA,CAAsB,QAAQ,CAACyS,CAAD,CAAS,CACrCA,CAAAnO,QAAAq0D,SAAA,CAA0B,CAAA,CADW,CAAvC,CAII53D,EAAJ,EACEA,CAAAf,QAAA,CAAc,QAAQ,CAACopD,CAAD,CAAO,CAE3B,CADI32C,CACJ,CADaoV,CAAAwqD,uBAAA,CAA+BjpB,CAA/B,CACb,GAAesnB,CAAAj+D,CAAAi+D,SAAf,GAAgCj+D,CAAAnO,QAAAq0D,SAAhC,CAA0D,CAAA,CAA1D,CAF2B,CAA7B,CAN2D,CA4B/D,CAdAwa,CAAAC,UAcA,CAduBY,QAA8B,EAAG,CAAA,IAClDC,EAAiB3D,CAAAvpE,IAAA,EAAjBktE,EAAwC,EADU,CAElDC,EAAa,EAEjBl0E,EAAA,CAAQi0E,CAAR,CAAwB,QAAQ,CAAClzE,CAAD,CAAQ,CAClC0R,CAAAA,CAASoV,CAAAsqD,eAAA,CAAuBpxE,CAAvB,CACR0R,EAAAi+D,SAAL,EAAsBwD,CAAA7uE,KAAA,CAAgBwiB,CAAAyqD,uBAAA,CAA+B7/D,CAA/B,CAAhB,CAFgB,CAAxC,CAKA,OAAOyhE,EAT+C,CAcxD,CAAI7+D,CAAA67D,QAAJ,EAEE5lE,CAAAiyB,iBAAA,CAAuB,QAAQ,EAAG,CAChC,GAAIx9B,CAAA,CAAQ4zE,CAAA/hB,WAAR,CAAJ,CACE,MAAO+hB,EAAA/hB,WAAA9D,IAAA,CAA2B,QAAQ,CAAC/sD,CAAD,CAAQ,CAChD,MAAOsU,EAAAk8D,gBAAA,CAA0BxwE,CAA1B,CADyC,CAA3C,CAFuB,CAAlC;AAMG,QAAQ,EAAG,CACZ4yE,CAAAzhB,QAAA,EADY,CANd,CAnFJ,GAEEihB,CAAAW,WAqCA,CArCwBC,QAA4B,CAAChzE,CAAD,CAAQ,CAC1D,IAAI0R,EAASoV,CAAAwqD,uBAAA,CAA+BtxE,CAA/B,CAET0R,EAAJ,EAAei+D,CAAAj+D,CAAAi+D,SAAf,CACMJ,CAAA,CAAc,CAAd,CAAAvvE,MADN,GACiC0R,CAAA+9D,YADjC,GAVFwC,CAAA1mD,OAAA,EAiBM,CA/BDgnD,CA+BC,EA9BJR,CAAAxmD,OAAA,EA8BI,CAFAgkD,CAAA,CAAc,CAAd,CAAAvvE,MAEA,CAFyB0R,CAAA+9D,YAEzB,CADA/9D,CAAAnO,QAAAq0D,SACA,CAD0B,CAAA,CAC1B,CAAAlmD,CAAAnO,QAAA8a,aAAA,CAA4B,UAA5B,CAAwC,UAAxC,CAPJ,EAUgB,IAAd,GAAIre,CAAJ,EAAsBuyE,CAAtB,EApBJN,CAAA1mD,OAAA,EAlBA,CALKgnD,CAKL,EAJEhD,CAAA/W,QAAA,CAAsBuZ,CAAtB,CAIF,CAFAxC,CAAAvpE,IAAA,CAAkB,EAAlB,CAEA,CADA+rE,CAAA/uE,KAAA,CAAiB,UAAjB,CAA6B,CAAA,CAA7B,CACA,CAAA+uE,CAAA9uE,KAAA,CAAiB,UAAjB,CAA6B,CAAA,CAA7B,CAsCI,GAlCCsvE,CAUL,EATER,CAAAxmD,OAAA,EASF,CAHAgkD,CAAA/W,QAAA,CAAsByZ,CAAtB,CAGA,CAFA1C,CAAAvpE,IAAA,CAAkB,GAAlB,CAEA,CADAisE,CAAAjvE,KAAA,CAAmB,UAAnB,CAA+B,CAAA,CAA/B,CACA,CAAAivE,CAAAhvE,KAAA,CAAmB,UAAnB,CAA+B,CAAA,CAA/B,CAwBI,CAbwD,CAqC5D,CAdAmvE,CAAAC,UAcA,CAduBY,QAA2B,EAAG,CAEnD,IAAIG,EAAiBtsD,CAAAsqD,eAAA,CAAuB7B,CAAAvpE,IAAA,EAAvB,CAErB,OAAIotE,EAAJ,EAAuBzD,CAAAyD,CAAAzD,SAAvB;CAhDG4C,CAmDM,EAlDTR,CAAAxmD,OAAA,EAkDS,CArCX0mD,CAAA1mD,OAAA,EAqCW,CAAAzE,CAAAyqD,uBAAA,CAA+B6B,CAA/B,CAHT,EAKO,IAT4C,CAcrD,CAAI9+D,CAAA67D,QAAJ,EACE5lE,CAAA5H,OAAA,CACE,QAAQ,EAAG,CAAE,MAAO2R,EAAAk8D,gBAAA,CAA0BoC,CAAA/hB,WAA1B,CAAT,CADb,CAEE,QAAQ,EAAG,CAAE+hB,CAAAzhB,QAAA,EAAF,CAFb,CAxCJ,CAiGIohB,EAAJ,EAIER,CAAAxmD,OAAA,EAOA,CAJAw9C,CAAA,CAASgJ,CAAT,CAAA,CAAsBxnE,CAAtB,CAIA,CAAAwnE,CAAA1wD,YAAA,CAAwB,UAAxB,CAXF,EAaE0wD,CAbF,CAagBzqE,CAAA,CAAOkqE,CAAA/0D,UAAA,CAAyB,CAAA,CAAzB,CAAP,CAKhBy1D,EAAA,EAGA3nE,EAAAiyB,iBAAA,CAAuBloB,CAAAw8D,cAAvB,CAAgDoB,CAAhD,CA3KA,CAJgD,CAJ7C,CApKkE,CAAlD,CA1mEzB,CA2wFIz+D,GAAuB,CAAC,SAAD,CAAY,cAAZ,CAA4B,MAA5B,CAAoC,QAAQ,CAACo1C,CAAD,CAAUtxC,CAAV,CAAwBc,CAAxB,CAA8B,CAAA,IAC/Fg7D,EAAQ,KADuF,CAE/FC,EAAU,oBAEd,OAAO,CACL5oD,KAAMA,QAAQ,CAACngB,CAAD,CAAQhH,CAAR,CAAiBN,CAAjB,CAAuB,CAoDnCswE,QAASA,EAAiB,CAACC,CAAD,CAAU,CAClCjwE,CAAAg2B,KAAA,CAAai6C,CAAb,EAAwB,EAAxB,CADkC,CApDD,IAC/BC,EAAYxwE,CAAAgmC,MADmB,CAE/ByqC,EAAUzwE,CAAA4uB,MAAAwR,KAAVqwC,EAA6BnwE,CAAAN,KAAA,CAAaA,CAAA4uB,MAAAwR,KAAb,CAFE,CAG/B3oB,EAASzX,CAAAyX,OAATA,EAAwB,CAHO,CAI/Bi5D,EAAQppE,CAAA61C,MAAA,CAAYszB,CAAZ,CAARC,EAAgC,EAJD,CAK/BC;AAAc,EALiB,CAM/B71C,EAAcxmB,CAAAwmB,YAAA,EANiB,CAO/BC,EAAYzmB,CAAAymB,UAAA,EAPmB,CAQ/B61C,EAAmB91C,CAAnB81C,CAAiCJ,CAAjCI,CAA6C,GAA7CA,CAAmDn5D,CAAnDm5D,CAA4D71C,CAR7B,CAS/B81C,EAAejpE,EAAAhJ,KATgB,CAU/BkyE,CAEJ90E,EAAA,CAAQgE,CAAR,CAAc,QAAQ,CAACg8B,CAAD,CAAa+0C,CAAb,CAA4B,CAChD,IAAIC,EAAWX,CAAA/3D,KAAA,CAAay4D,CAAb,CACXC,EAAJ,GACMC,CACJ,EADeD,CAAA,CAAS,CAAT,CAAA,CAAc,GAAd,CAAoB,EACnC,EADyCzwE,CAAA,CAAUywE,CAAA,CAAS,CAAT,CAAV,CACzC,CAAAN,CAAA,CAAMO,CAAN,CAAA,CAAiB3wE,CAAAN,KAAA,CAAaA,CAAA4uB,MAAA,CAAWmiD,CAAX,CAAb,CAFnB,CAFgD,CAAlD,CAOA/0E,EAAA,CAAQ00E,CAAR,CAAe,QAAQ,CAAC10C,CAAD,CAAa7/B,CAAb,CAAkB,CACvCw0E,CAAA,CAAYx0E,CAAZ,CAAA,CAAmBmY,CAAA,CAAa0nB,CAAAn3B,QAAA,CAAmBurE,CAAnB,CAA0BQ,CAA1B,CAAb,CADoB,CAAzC,CAKAtpE,EAAA5H,OAAA,CAAa8wE,CAAb,CAAwBU,QAA+B,CAAC5tD,CAAD,CAAS,CAC9D,IAAI0iB,EAAQ8gB,UAAA,CAAWxjC,CAAX,CAAZ,CACI6tD,EAAaxtE,KAAA,CAAMqiC,CAAN,CAEZmrC,EAAL,EAAqBnrC,CAArB,GAA8B0qC,EAA9B,GAGE1qC,CAHF,CAGU4f,CAAAnd,UAAA,CAAkBzC,CAAlB,CAA0BvuB,CAA1B,CAHV,CAQKuuB,EAAL,GAAe8qC,CAAf,EAA+BK,CAA/B,EAA6C7xE,CAAA,CAASwxE,CAAT,CAA7C,EAAoEntE,KAAA,CAAMmtE,CAAN,CAApE,GACED,CAAA,EAWA,CAVIO,CAUJ,CAVgBT,CAAA,CAAY3qC,CAAZ,CAUhB,CATI7mC,CAAA,CAAYiyE,CAAZ,CAAJ,EACgB,IAId,EAJI9tD,CAIJ,EAHElO,CAAA+4B,MAAA,CAAW,oCAAX,CAAkDnI,CAAlD,CAA0D,OAA1D,CAAoEyqC,CAApE,CAGF,CADAI,CACA,CADejyE,CACf,CAAA0xE,CAAA,EALF,EAOEO,CAPF,CAOiBvpE,CAAA5H,OAAA,CAAa0xE,CAAb,CAAwBd,CAAxB,CAEjB,CAAAQ,CAAA,CAAY9qC,CAZd,CAZ8D,CAAhE,CAxBmC,CADhC,CAJ4F,CAA1E,CA3wF3B,CAqnGIt1B,GAAoB,CAAC,QAAD,CAAW,UAAX,CAAuB,QAAQ,CAAC4E,CAAD,CAASlC,CAAT,CAAmB,CAExE,IAAIi+D,EAAiB/1E,CAAA,CAAO,UAAP,CAArB,CAEIg2E,EAAcA,QAAQ,CAAChqE,CAAD,CAAQ5G,CAAR;AAAe6wE,CAAf,CAAgCx0E,CAAhC,CAAuCy0E,CAAvC,CAAsDr1E,CAAtD,CAA2Ds1E,CAA3D,CAAwE,CAEhGnqE,CAAA,CAAMiqE,CAAN,CAAA,CAAyBx0E,CACrBy0E,EAAJ,GAAmBlqE,CAAA,CAAMkqE,CAAN,CAAnB,CAA0Cr1E,CAA1C,CACAmL,EAAA+pD,OAAA,CAAe3wD,CACf4G,EAAAoqE,OAAA,CAA0B,CAA1B,GAAgBhxE,CAChB4G,EAAAqqE,MAAA,CAAejxE,CAAf,GAA0B+wE,CAA1B,CAAwC,CACxCnqE,EAAAsqE,QAAA,CAAgB,EAAEtqE,CAAAoqE,OAAF,EAAkBpqE,CAAAqqE,MAAlB,CAEhBrqE,EAAAuqE,KAAA,CAAa,EAAEvqE,CAAAwqE,MAAF,CAA8B,CAA9B,IAAiBpxE,CAAjB,CAAuB,CAAvB,EATmF,CAsBlG,OAAO,CACL6pB,SAAU,GADL,CAELsK,aAAc,CAAA,CAFT,CAGLlH,WAAY,SAHP,CAILtD,SAAU,GAJL,CAKL8D,SAAU,CAAA,CALL,CAMLuF,MAAO,CAAA,CANF,CAOLnsB,QAASwqE,QAAwB,CAAC1mD,CAAD,CAAWuD,CAAX,CAAkB,CACjD,IAAIoN,EAAapN,CAAAne,SAAjB,CACIuhE,EAAqB52E,CAAAu4B,cAAA,CAAuB,iBAAvB,CAA2CqI,CAA3C,CAAwD,GAAxD,CADzB,CAGIv6B,EAAQu6B,CAAAv6B,MAAA,CAAiB,4FAAjB,CAEZ,IAAKA,CAAAA,CAAL,CACE,KAAM4vE,EAAA,CAAe,MAAf,CACFr1C,CADE,CAAN,CAIF,IAAI4jC,EAAMn+D,CAAA,CAAM,CAAN,CAAV,CACIk+D,EAAMl+D,CAAA,CAAM,CAAN,CADV,CAEIwwE,EAAUxwE,CAAA,CAAM,CAAN,CAFd,CAGIywE,EAAazwE,CAAA,CAAM,CAAN,CAHjB,CAKAA,EAAQm+D,CAAAn+D,MAAA,CAAU,wDAAV,CAER;GAAKA,CAAAA,CAAL,CACE,KAAM4vE,EAAA,CAAe,QAAf,CACFzR,CADE,CAAN,CAGF,IAAI2R,EAAkB9vE,CAAA,CAAM,CAAN,CAAlB8vE,EAA8B9vE,CAAA,CAAM,CAAN,CAAlC,CACI+vE,EAAgB/vE,CAAA,CAAM,CAAN,CAEpB,IAAIwwE,CAAJ,GAAiB,CAAA,4BAAA7wE,KAAA,CAAkC6wE,CAAlC,CAAjB,EACI,2FAAA7wE,KAAA,CAAiG6wE,CAAjG,CADJ,EAEE,KAAMZ,EAAA,CAAe,UAAf,CACJY,CADI,CAAN,CA3B+C,IA+B7CE,CA/B6C,CA+B3BC,CA/B2B,CA+BXC,CA/BW,CA+BOC,CA/BP,CAgC7CC,EAAe,CAACp5B,IAAK96B,EAAN,CAEf6zD,EAAJ,CACEC,CADF,CACqB78D,CAAA,CAAO48D,CAAP,CADrB,EAGEG,CAGA,CAHmBA,QAAQ,CAACl2E,CAAD,CAAMY,CAAN,CAAa,CACtC,MAAOshB,GAAA,CAAQthB,CAAR,CAD+B,CAGxC,CAAAu1E,CAAA,CAAiBA,QAAQ,CAACn2E,CAAD,CAAM,CAC7B,MAAOA,EADsB,CANjC,CAWA,OAAOq2E,SAAqB,CAAC9gD,CAAD,CAASrG,CAAT,CAAmBuD,CAAnB,CAA0B09B,CAA1B,CAAgC16B,CAAhC,CAA6C,CAEnEugD,CAAJ,GACEC,CADF,CACmBA,QAAQ,CAACj2E,CAAD,CAAMY,CAAN,CAAa2D,CAAb,CAAoB,CAEvC8wE,CAAJ,GAAmBe,CAAA,CAAaf,CAAb,CAAnB,CAAiDr1E,CAAjD,CACAo2E,EAAA,CAAahB,CAAb,CAAA,CAAgCx0E,CAChCw1E,EAAAlhB,OAAA,CAAsB3wD,CACtB,OAAOyxE,EAAA,CAAiBzgD,CAAjB,CAAyB6gD,CAAzB,CALoC,CAD/C,CAkBA,KAAIE,EAAerwE,EAAA,EAGnBsvB,EAAA6H,iBAAA,CAAwBomC,CAAxB,CAA6B+S,QAAuB,CAACppD,CAAD,CAAa,CAAA,IAC3D5oB,CAD2D,CACpDhF,CADoD,CAE3Di3E,EAAetnD,CAAA,CAAS,CAAT,CAF4C,CAI3DunD,CAJ2D,CAO3DC,EAAezwE,EAAA,EAP4C,CAQ3D0wE,CAR2D,CAS3D32E,CAT2D,CAStDY,CATsD,CAU3Dg2E,CAV2D,CAY3DC,CAZ2D,CAa3DhmE,CAb2D,CAc3DimE,CAGAhB,EAAJ,GACEvgD,CAAA,CAAOugD,CAAP,CADF,CACoB3oD,CADpB,CAIA,IAAI/tB,EAAA,CAAY+tB,CAAZ,CAAJ,CACE0pD,CACA;AADiB1pD,CACjB,CAAA4pD,CAAA,CAAcd,CAAd,EAAgCC,CAFlC,KAOE,KAAStF,CAAT,GAHAmG,EAGoB5pD,CAHN8oD,CAGM9oD,EAHYgpD,CAGZhpD,CADpB0pD,CACoB1pD,CADH,EACGA,CAAAA,CAApB,CACMA,CAAAjtB,eAAA,CAA0B0wE,CAA1B,CAAJ,EAAgE,GAAhE,GAA0CA,CAAAlrE,OAAA,CAAe,CAAf,CAA1C,EACEmxE,CAAA3xE,KAAA,CAAoB0rE,CAApB,CAKN+F,EAAA,CAAmBE,CAAAt3E,OACnBu3E,EAAA,CAAqB9wD,KAAJ,CAAU2wD,CAAV,CAGjB,KAAKpyE,CAAL,CAAa,CAAb,CAAgBA,CAAhB,CAAwBoyE,CAAxB,CAA0CpyE,CAAA,EAA1C,CAIE,GAHAvE,CAGI,CAHGmtB,CAAD,GAAgB0pD,CAAhB,CAAkCtyE,CAAlC,CAA0CsyE,CAAA,CAAetyE,CAAf,CAG5C,CAFJ3D,CAEI,CAFIusB,CAAA,CAAWntB,CAAX,CAEJ,CADJ42E,CACI,CADQG,CAAA,CAAY/2E,CAAZ,CAAiBY,CAAjB,CAAwB2D,CAAxB,CACR,CAAA+xE,CAAA,CAAaM,CAAb,CAAJ,CAEE/lE,CAGA,CAHQylE,CAAA,CAAaM,CAAb,CAGR,CAFA,OAAON,CAAA,CAAaM,CAAb,CAEP,CADAF,CAAA,CAAaE,CAAb,CACA,CAD0B/lE,CAC1B,CAAAimE,CAAA,CAAevyE,CAAf,CAAA,CAAwBsM,CAL1B,KAMO,CAAA,GAAI6lE,CAAA,CAAaE,CAAb,CAAJ,CAKL,KAHA/2E,EAAA,CAAQi3E,CAAR,CAAwB,QAAQ,CAACjmE,CAAD,CAAQ,CAClCA,CAAJ,EAAaA,CAAA1F,MAAb,GAA0BmrE,CAAA,CAAazlE,CAAAgb,GAAb,CAA1B,CAAmDhb,CAAnD,CADsC,CAAxC,CAGM,CAAAqkE,CAAA,CAAe,OAAf,CAEFr1C,CAFE,CAEU+2C,CAFV,CAEqBh2E,CAFrB,CAAN,CAKAk2E,CAAA,CAAevyE,CAAf,CAAA,CAAwB,CAACsnB,GAAI+qD,CAAL,CAAgBzrE,MAAOjM,CAAvB,CAAkCiJ,MAAOjJ,CAAzC,CACxBw3E,EAAA,CAAaE,CAAb,CAAA,CAA0B,CAAA,CAXrB,CAgBT,IAASI,CAAT,GAAqBV,EAArB,CAAmC,CACjCzlE,CAAA,CAAQylE,CAAA,CAAaU,CAAb,CACRp7C,EAAA,CAAmBltB,EAAA,CAAcmC,CAAA1I,MAAd,CACnB8O,EAAAslD,MAAA,CAAe3gC,CAAf,CACA,IAAIA,CAAA,CAAiB,CAAjB,CAAAjc,WAAJ,CAGE,IAAKpb,CAAW,CAAH,CAAG,CAAAhF,CAAA,CAASq8B,CAAAr8B,OAAzB,CAAkDgF,CAAlD,CAA0DhF,CAA1D,CAAkEgF,CAAA,EAAlE,CACEq3B,CAAA,CAAiBr3B,CAAjB,CAAA,aAAA,CAAsC,CAAA,CAG1CsM,EAAA1F,MAAAyC,SAAA,EAXiC,CAenC,IAAKrJ,CAAL,CAAa,CAAb,CAAgBA,CAAhB,CAAwBoyE,CAAxB,CAA0CpyE,CAAA,EAA1C,CAKE,GAJAvE,CAIImL,CAJGgiB,CAAD,GAAgB0pD,CAAhB,CAAkCtyE,CAAlC,CAA0CsyE,CAAA,CAAetyE,CAAf,CAI5C4G,CAHJvK,CAGIuK,CAHIgiB,CAAA,CAAWntB,CAAX,CAGJmL,CAFJ0F,CAEI1F,CAFI2rE,CAAA,CAAevyE,CAAf,CAEJ4G,CAAA0F,CAAA1F,MAAJ,CAAiB,CAIfsrE,CAAA;AAAWD,CAGX,GACEC,EAAA,CAAWA,CAAA3nE,YADb,OAES2nE,CAFT,EAEqBA,CAAA,aAFrB,CAIkB5lE,EAnLrB1I,MAAA,CAAY,CAAZ,CAmLG,EAA4BsuE,CAA5B,EAEEx/D,CAAAqlD,KAAA,CAAc5tD,EAAA,CAAcmC,CAAA1I,MAAd,CAAd,CAA0C,IAA1C,CAAgDD,CAAA,CAAOsuE,CAAP,CAAhD,CAEFA,EAAA,CAA2B3lE,CAnL9B1I,MAAA,CAmL8B0I,CAnLlB1I,MAAA5I,OAAZ,CAAiC,CAAjC,CAoLG41E,EAAA,CAAYtkE,CAAA1F,MAAZ,CAAyB5G,CAAzB,CAAgC6wE,CAAhC,CAAiDx0E,CAAjD,CAAwDy0E,CAAxD,CAAuEr1E,CAAvE,CAA4E22E,CAA5E,CAhBe,CAAjB,IAmBElhD,EAAA,CAAYwhD,QAA2B,CAAC9uE,CAAD,CAAQgD,CAAR,CAAe,CACpD0F,CAAA1F,MAAA,CAAcA,CAEd,KAAIyD,EAAUinE,CAAAx4D,UAAA,CAA6B,CAAA,CAA7B,CACdlV,EAAA,CAAMA,CAAA5I,OAAA,EAAN,CAAA,CAAwBqP,CAGxBqI,EAAAolD,MAAA,CAAel0D,CAAf,CAAsB,IAAtB,CAA4BD,CAAA,CAAOsuE,CAAP,CAA5B,CACAA,EAAA,CAAe5nE,CAIfiC,EAAA1I,MAAA,CAAcA,CACduuE,EAAA,CAAa7lE,CAAAgb,GAAb,CAAA,CAAyBhb,CACzBskE,EAAA,CAAYtkE,CAAA1F,MAAZ,CAAyB5G,CAAzB,CAAgC6wE,CAAhC,CAAiDx0E,CAAjD,CAAwDy0E,CAAxD,CAAuEr1E,CAAvE,CAA4E22E,CAA5E,CAdoD,CAAtD,CAkBJL,EAAA,CAAeI,CA1HgD,CAAjE,CAvBuE,CA7CxB,CAP9C,CA1BiE,CAAlD,CArnGxB,CA0/GIjiE,GAAkB,CAAC,UAAD,CAAa,QAAQ,CAACwC,CAAD,CAAW,CACpD,MAAO,CACLmX,SAAU,GADL,CAELsK,aAAc,CAAA,CAFT,CAGLpN,KAAMA,QAAQ,CAACngB,CAAD,CAAQhH,CAAR,CAAiBN,CAAjB,CAAuB,CACnCsH,CAAA5H,OAAA,CAAaM,CAAA2Q,OAAb,CAA0B0iE,QAA0B,CAACt2E,CAAD,CAAQ,CAK1DqW,CAAA,CAASrW,CAAA,CAAQ,aAAR,CAAwB,UAAjC,CAAA,CAA6CuD,CAA7C,CAzKYgzE,SAyKZ,CAAqE,CACnEza,YAzKsB0a,iBAwK6C,CAArE,CAL0D,CAA5D,CADmC,CAHhC,CAD6C,CAAhC,CA1/GtB,CA4pHIzjE,GAAkB,CAAC,UAAD;AAAa,QAAQ,CAACsD,CAAD,CAAW,CACpD,MAAO,CACLmX,SAAU,GADL,CAELsK,aAAc,CAAA,CAFT,CAGLpN,KAAMA,QAAQ,CAACngB,CAAD,CAAQhH,CAAR,CAAiBN,CAAjB,CAAuB,CACnCsH,CAAA5H,OAAA,CAAaM,CAAA6P,OAAb,CAA0B2jE,QAA0B,CAACz2E,CAAD,CAAQ,CAG1DqW,CAAA,CAASrW,CAAA,CAAQ,UAAR,CAAqB,aAA9B,CAAA,CAA6CuD,CAA7C,CAzUYgzE,SAyUZ,CAAoE,CAClEza,YAzUsB0a,iBAwU4C,CAApE,CAH0D,CAA5D,CADmC,CAHhC,CAD6C,CAAhC,CA5pHtB,CA0tHIziE,GAAmB05C,EAAA,CAAY,QAAQ,CAACljD,CAAD,CAAQhH,CAAR,CAAiBN,CAAjB,CAAuB,CAChEsH,CAAA5H,OAAA,CAAaM,CAAA6Q,QAAb,CAA2B4iE,QAA2B,CAACC,CAAD,CAAYC,CAAZ,CAAuB,CACvEA,CAAJ,EAAkBD,CAAlB,GAAgCC,CAAhC,EACE33E,CAAA,CAAQ23E,CAAR,CAAmB,QAAQ,CAAC5wE,CAAD,CAAMwL,CAAN,CAAa,CAAEjO,CAAA4zD,IAAA,CAAY3lD,CAAZ,CAAmB,EAAnB,CAAF,CAAxC,CAEEmlE,EAAJ,EAAepzE,CAAA4zD,IAAA,CAAYwf,CAAZ,CAJ4D,CAA7E,CAKG,CAAA,CALH,CADgE,CAA3C,CA1tHvB,CAm2HI1iE,GAAoB,CAAC,UAAD,CAAa,QAAQ,CAACoC,CAAD,CAAW,CACtD,MAAO,CACLkX,QAAS,UADJ,CAILhhB,WAAY,CAAC,QAAD,CAAWsqE,QAA2B,EAAG,CACpD,IAAAC,MAAA,CAAa,EADuC,CAAzC,CAJP,CAOLpsD,KAAMA,QAAQ,CAACngB,CAAD,CAAQhH,CAAR,CAAiBN,CAAjB,CAAuB4zE,CAAvB,CAA2C,CAAA,IAEnDE,EAAsB,EAF6B,CAGnDC,EAAmB,EAHgC,CAInDC,EAA0B,EAJyB,CAKnDC,EAAiB,EALkC,CAOnDC,EAAgBA,QAAQ,CAACzzE,CAAD,CAAQC,CAAR,CAAe,CACvC,MAAO,SAAQ,EAAG,CAAED,CAAAG,OAAA,CAAaF,CAAb,CAAoB,CAApB,CAAF,CADqB,CAI3C4G,EAAA5H,OAAA,CAVgBM,CAAA+Q,SAUhB;AAViC/Q,CAAAmJ,GAUjC,CAAwBgrE,QAA4B,CAACp3E,CAAD,CAAQ,CAAA,IACtDH,CADsD,CACnDa,CACFb,EAAA,CAAI,CAAT,KAAYa,CAAZ,CAAiBu2E,CAAAt4E,OAAjB,CAAiDkB,CAAjD,CAAqDa,CAArD,CAAyD,EAAEb,CAA3D,CACEwW,CAAA2T,OAAA,CAAgBitD,CAAA,CAAwBp3E,CAAxB,CAAhB,CAIGA,EAAA,CAFLo3E,CAAAt4E,OAEK,CAF4B,CAEjC,KAAY+B,CAAZ,CAAiBw2E,CAAAv4E,OAAjB,CAAwCkB,CAAxC,CAA4Ca,CAA5C,CAAgD,EAAEb,CAAlD,CAAqD,CACnD,IAAI+3D,EAAW9pD,EAAA,CAAckpE,CAAA,CAAiBn3E,CAAjB,CAAA0H,MAAd,CACf2vE,EAAA,CAAer3E,CAAf,CAAAmN,SAAA,EAEAyrB,EADcw+C,CAAA,CAAwBp3E,CAAxB,CACd44B,CAD2CpiB,CAAAslD,MAAA,CAAe/D,CAAf,CAC3Cn/B,MAAA,CAAa0+C,CAAA,CAAcF,CAAd,CAAuCp3E,CAAvC,CAAb,CAJmD,CAOrDm3E,CAAAr4E,OAAA,CAA0B,CAC1Bu4E,EAAAv4E,OAAA,CAAwB,CAExB,EAAKo4E,CAAL,CAA2BF,CAAAC,MAAA,CAAyB,GAAzB,CAA+B92E,CAA/B,CAA3B,EAAoE62E,CAAAC,MAAA,CAAyB,GAAzB,CAApE,GACE73E,CAAA,CAAQ83E,CAAR,CAA6B,QAAQ,CAACM,CAAD,CAAqB,CACxDA,CAAAzmD,WAAA,CAA8B,QAAQ,CAAC0mD,CAAD,CAAcC,CAAd,CAA6B,CACjEL,CAAA5yE,KAAA,CAAoBizE,CAApB,CACA,KAAIC,EAASH,CAAA9zE,QACb+zE,EAAA,CAAYA,CAAA34E,OAAA,EAAZ,CAAA,CAAoCN,CAAAu4B,cAAA,CAAuB,qBAAvB,CAGpCogD,EAAA1yE,KAAA,CAFY2L,CAAE1I,MAAO+vE,CAATrnE,CAEZ,CACAoG,EAAAolD,MAAA,CAAe6b,CAAf,CAA4BE,CAAA91E,OAAA,EAA5B,CAA6C81E,CAA7C,CAPiE,CAAnE,CADwD,CAA1D,CAlBwD,CAA5D,CAXuD,CAPpD,CAD+C,CAAhC,CAn2HxB,CAy5HIrjE,GAAwBs5C,EAAA,CAAY,CACtC78B,WAAY,SAD0B,CAEtCtD,SAAU,IAF4B,CAGtCC,QAAS,WAH6B,CAItCuK,aAAc,CAAA,CAJwB,CAKtCpN,KAAMA,QAAQ,CAACngB,CAAD,CAAQhH,CAAR,CAAiButB,CAAjB,CAAwBy+B,CAAxB;AAA8B16B,CAA9B,CAA2C,CACvD06B,CAAAunB,MAAA,CAAW,GAAX,CAAiBhmD,CAAA5c,aAAjB,CAAA,CAAwCq7C,CAAAunB,MAAA,CAAW,GAAX,CAAiBhmD,CAAA5c,aAAjB,CAAxC,EAAgF,EAChFq7C,EAAAunB,MAAA,CAAW,GAAX,CAAiBhmD,CAAA5c,aAAjB,CAAA5P,KAAA,CAA0C,CAAEssB,WAAYiE,CAAd,CAA2BtxB,QAASA,CAApC,CAA1C,CAFuD,CALnB,CAAZ,CAz5H5B,CAo6HI8Q,GAA2Bo5C,EAAA,CAAY,CACzC78B,WAAY,SAD6B,CAEzCtD,SAAU,IAF+B,CAGzCC,QAAS,WAHgC,CAIzCuK,aAAc,CAAA,CAJ2B,CAKzCpN,KAAMA,QAAQ,CAACngB,CAAD,CAAQhH,CAAR,CAAiBN,CAAjB,CAAuBssD,CAAvB,CAA6B16B,CAA7B,CAA0C,CACtD06B,CAAAunB,MAAA,CAAW,GAAX,CAAA,CAAmBvnB,CAAAunB,MAAA,CAAW,GAAX,CAAnB,EAAsC,EACtCvnB,EAAAunB,MAAA,CAAW,GAAX,CAAAxyE,KAAA,CAAqB,CAAEssB,WAAYiE,CAAd,CAA2BtxB,QAASA,CAApC,CAArB,CAFsD,CALf,CAAZ,CAp6H/B,CAq+HIkR,GAAwBg5C,EAAA,CAAY,CACtCjgC,SAAU,KAD4B,CAEtC9C,KAAMA,QAAQ,CAACiK,CAAD,CAASrG,CAAT,CAAmBsG,CAAnB,CAA2BroB,CAA3B,CAAuCsoB,CAAvC,CAAoD,CAChE,GAAKA,CAAAA,CAAL,CACE,KAAMt2B,EAAA,CAAO,cAAP,CAAA,CAAuB,QAAvB,CAIL8I,EAAA,CAAYinB,CAAZ,CAJK,CAAN,CAOFuG,CAAA,CAAY,QAAQ,CAACttB,CAAD,CAAQ,CAC1B+mB,CAAA9mB,MAAA,EACA8mB,EAAA3mB,OAAA,CAAgBJ,CAAhB,CAF0B,CAA5B,CATgE,CAF5B,CAAZ,CAr+H5B,CAwhII8J,GAAkB,CAAC,gBAAD,CAAmB,QAAQ,CAACgI,CAAD,CAAiB,CAChE,MAAO,CACLmU,SAAU,GADL,CAEL4D,SAAU,CAAA,CAFL;AAGL5mB,QAASA,QAAQ,CAACjH,CAAD,CAAUN,CAAV,CAAgB,CACd,kBAAjB,EAAIA,CAAAga,KAAJ,EAIE5D,CAAAuI,IAAA,CAHkB3e,CAAAgoB,GAGlB,CAFW1nB,CAAA,CAAQ,CAAR,CAAAg2B,KAEX,CAL6B,CAH5B,CADyD,CAA5C,CAxhItB,CAuiIIk+C,GAAwB,CAAE1mB,cAAelvD,CAAjB,CAAuBsvD,QAAStvD,CAAhC,CAviI5B,CAijII61E,GACI,CAAC,UAAD,CAAa,QAAb,CAAuB,QAAvB,CAAiC,QAAQ,CAACppD,CAAD,CAAWqG,CAAX,CAAmBC,CAAnB,CAA2B,CAAA,IAEtElvB,EAAO,IAF+D,CAGtEiyE,EAAa,IAAIl2D,EAGrB/b,EAAAktE,YAAA,CAAmB6E,EAQnB/xE,EAAAusE,cAAA,CAAqB3qE,CAAA,CAAOjJ,CAAAgd,cAAA,CAAuB,QAAvB,CAAP,CACrB3V,EAAAkyE,oBAAA,CAA2BC,QAAQ,CAAC7xE,CAAD,CAAM,CACnC8xE,CAAAA,CAAa,IAAbA,CAAoBx2D,EAAA,CAAQtb,CAAR,CAApB8xE,CAAmC,IACvCpyE,EAAAusE,cAAAjsE,IAAA,CAAuB8xE,CAAvB,CACAxpD,EAAAkqC,QAAA,CAAiB9yD,CAAAusE,cAAjB,CACA3jD,EAAAtoB,IAAA,CAAa8xE,CAAb,CAJuC,CAOzCnjD,EAAAlE,IAAA,CAAW,UAAX,CAAuB,QAAQ,EAAG,CAEhC/qB,CAAAkyE,oBAAA,CAA2B/1E,CAFK,CAAlC,CAKA6D,EAAAqyE,oBAAA,CAA2BC,QAAQ,EAAG,CAChCtyE,CAAAusE,cAAAvwE,OAAA,EAAJ,EAAiCgE,CAAAusE,cAAA1mD,OAAA,EADG,CAOtC7lB,EAAA2sE,UAAA;AAAiB4F,QAAwB,EAAG,CAC1CvyE,CAAAqyE,oBAAA,EACA,OAAOzpD,EAAAtoB,IAAA,EAFmC,CAQ5CN,EAAAqtE,WAAA,CAAkBmF,QAAyB,CAACl4E,CAAD,CAAQ,CAC7C0F,CAAAyyE,UAAA,CAAen4E,CAAf,CAAJ,EACE0F,CAAAqyE,oBAAA,EAEA,CADAzpD,CAAAtoB,IAAA,CAAahG,CAAb,CACA,CAAc,EAAd,GAAIA,CAAJ,EAAkB0F,CAAAqsE,YAAA/uE,KAAA,CAAsB,UAAtB,CAAkC,CAAA,CAAlC,CAHpB,EAKe,IAAb,EAAIhD,CAAJ,EAAqB0F,CAAAqsE,YAArB,EACErsE,CAAAqyE,oBAAA,EACA,CAAAzpD,CAAAtoB,IAAA,CAAa,EAAb,CAFF,EAIEN,CAAAkyE,oBAAA,CAAyB53E,CAAzB,CAV6C,CAiBnD0F,EAAA0yE,UAAA,CAAiBC,QAAQ,CAACr4E,CAAD,CAAQuD,CAAR,CAAiB,CACxCiK,EAAA,CAAwBxN,CAAxB,CAA+B,gBAA/B,CACc,GAAd,GAAIA,CAAJ,GACE0F,CAAAqsE,YADF,CACqBxuE,CADrB,CAGA,KAAI0lC,EAAQ0uC,CAAApsE,IAAA,CAAevL,CAAf,CAARipC,EAAiC,CACrC0uC,EAAA/1D,IAAA,CAAe5hB,CAAf,CAAsBipC,CAAtB,CAA8B,CAA9B,CANwC,CAU1CvjC,EAAA4yE,aAAA,CAAoBC,QAAQ,CAACv4E,CAAD,CAAQ,CAClC,IAAIipC,EAAQ0uC,CAAApsE,IAAA,CAAevL,CAAf,CACRipC,EAAJ,GACgB,CAAd,GAAIA,CAAJ,EACE0uC,CAAApsD,OAAA,CAAkBvrB,CAAlB,CACA,CAAc,EAAd,GAAIA,CAAJ,GACE0F,CAAAqsE,YADF,CACqBzzE,CADrB,CAFF,EAMEq5E,CAAA/1D,IAAA,CAAe5hB,CAAf,CAAsBipC,CAAtB,CAA8B,CAA9B,CAPJ,CAFkC,CAepCvjC,EAAAyyE,UAAA,CAAiBK,QAAQ,CAACx4E,CAAD,CAAQ,CAC/B,MAAO,CAAE,CAAA23E,CAAApsE,IAAA,CAAevL,CAAf,CADsB,CApFyC,CAApE,CAljIR;AAktIIuR,GAAkBA,QAAQ,EAAG,CAE/B,MAAO,CACLic,SAAU,GADL,CAELD,QAAS,CAAC,QAAD,CAAW,UAAX,CAFJ,CAGLhhB,WAAYmrE,EAHP,CAILhtD,KAAMA,QAAQ,CAACngB,CAAD,CAAQhH,CAAR,CAAiBN,CAAjB,CAAuBwlE,CAAvB,CAA8B,CAG1C,IAAImK,EAAcnK,CAAA,CAAM,CAAN,CAClB,IAAKmK,CAAL,CAAA,CAEA,IAAIR,EAAa3J,CAAA,CAAM,CAAN,CAEjB2J,EAAAQ,YAAA,CAAyBA,CAKzBA,EAAAzhB,QAAA,CAAsBsnB,QAAQ,EAAG,CAC/BrG,CAAAW,WAAA,CAAsBH,CAAA/hB,WAAtB,CAD+B,CAOjCttD,EAAA6I,GAAA,CAAW,QAAX,CAAqB,QAAQ,EAAG,CAC9B7B,CAAAE,OAAA,CAAa,QAAQ,EAAG,CACtBmoE,CAAA7hB,cAAA,CAA0BqhB,CAAAC,UAAA,EAA1B,CADsB,CAAxB,CAD8B,CAAhC,CAUA,IAAIpvE,CAAA00D,SAAJ,CAAmB,CAGjBya,CAAAC,UAAA,CAAuBY,QAA0B,EAAG,CAClD,IAAIvvE,EAAQ,EACZzE,EAAA,CAAQsE,CAAAL,KAAA,CAAa,QAAb,CAAR,CAAgC,QAAQ,CAACwO,CAAD,CAAS,CAC3CA,CAAAkmD,SAAJ,EACEl0D,CAAAY,KAAA,CAAWoN,CAAA1R,MAAX,CAF6C,CAAjD,CAKA,OAAO0D,EAP2C,CAWpD0uE,EAAAW,WAAA,CAAwBC,QAA2B,CAAChzE,CAAD,CAAQ,CACzD,IAAIoD,EAAQ,IAAIqe,EAAJ,CAAYzhB,CAAZ,CACZf,EAAA,CAAQsE,CAAAL,KAAA,CAAa,QAAb,CAAR,CAAgC,QAAQ,CAACwO,CAAD,CAAS,CAC/CA,CAAAkmD,SAAA,CAAkBv1D,CAAA,CAAUe,CAAAmI,IAAA,CAAUmG,CAAA1R,MAAV,CAAV,CAD6B,CAAjD,CAFyD,CAd1C,KAuBb04E,CAvBa;AAuBHC,EAAcvmB,GAC5B7nD,EAAA5H,OAAA,CAAai2E,QAA4B,EAAG,CACtCD,CAAJ,GAAoB/F,CAAA/hB,WAApB,EAA+C9rD,EAAA,CAAO2zE,CAAP,CAAiB9F,CAAA/hB,WAAjB,CAA/C,GACE6nB,CACA,CADW7zE,EAAA,CAAY+tE,CAAA/hB,WAAZ,CACX,CAAA+hB,CAAAzhB,QAAA,EAFF,CAIAwnB,EAAA,CAAc/F,CAAA/hB,WAL4B,CAA5C,CAUA+hB,EAAApiB,SAAA,CAAuBsiB,QAAQ,CAAC9yE,CAAD,CAAQ,CACrC,MAAO,CAACA,CAAR,EAAkC,CAAlC,GAAiBA,CAAArB,OADoB,CAlCtB,CA1BnB,CAJ0C,CAJvC,CAFwB,CAltIjC,CAqyIIgT,GAAkB,CAAC,cAAD,CAAiB,QAAQ,CAAC4F,CAAD,CAAe,CAE5DshE,QAASA,EAAU,CAACpG,CAAD,CAAgB,CAI7BA,CAAA,CAAc,CAAd,CAAAlpE,aAAA,CAA8B,UAA9B,CAAJ,GACEkpE,CAAA,CAAc,CAAd,CAAA7a,SADF,CAC8B,CAAA,CAD9B,CAJiC,CASnC,MAAO,CACLpqC,SAAU,GADL,CAELF,SAAU,GAFL,CAGL9iB,QAASA,QAAQ,CAACjH,CAAD,CAAUN,CAAV,CAAgB,CAI/B,GAAIb,CAAA,CAAYa,CAAAjD,MAAZ,CAAJ,CAA6B,CAC3B,IAAIw5B,EAAgBjiB,CAAA,CAAahU,CAAAg2B,KAAA,EAAb,CAA6B,CAAA,CAA7B,CACfC,EAAL,EACEv2B,CAAAg1B,KAAA,CAAU,OAAV,CAAmB10B,CAAAg2B,KAAA,EAAnB,CAHyB,CAO7B,MAAO,SAAQ,CAAChvB,CAAD,CAAQhH,CAAR,CAAiBN,CAAjB,CAAuB,CAAA,IAKhCvB,EAAS6B,CAAA7B,OAAA,EALuB,CAMhC0wE,EAAa1wE,CAAAgJ,KAAA,CAFIouE,mBAEJ,CAAb1G,EACE1wE,CAAAA,OAAA,EAAAgJ,KAAA,CAHeouE,mBAGf,CAIF1G,EAAJ,EAAkBA,CAAAQ,YAAlB;CAEMp5C,CAAJ,CACEjvB,CAAA5H,OAAA,CAAa62B,CAAb,CAA4Bu/C,QAA+B,CAACxyD,CAAD,CAASC,CAAT,CAAiB,CAC1EvjB,CAAAg1B,KAAA,CAAU,OAAV,CAAmB1R,CAAnB,CACIC,EAAJ,GAAeD,CAAf,EACE6rD,CAAAkG,aAAA,CAAwB9xD,CAAxB,CAEF4rD,EAAAgG,UAAA,CAAqB7xD,CAArB,CAA6BhjB,CAA7B,CACA6uE,EAAAQ,YAAAzhB,QAAA,EACA0nB,EAAA,CAAWt1E,CAAX,CAP0E,CAA5E,CADF,EAWE6uE,CAAAgG,UAAA,CAAqBn1E,CAAAjD,MAArB,CAAiCuD,CAAjC,CAEA,CADA6uE,CAAAQ,YAAAzhB,QAAA,EACA,CAAA0nB,CAAA,CAAWt1E,CAAX,CAbF,CAgBA,CAAAA,CAAA6I,GAAA,CAAW,UAAX,CAAuB,QAAQ,EAAG,CAChCgmE,CAAAkG,aAAA,CAAwBr1E,CAAAjD,MAAxB,CACAoyE,EAAAQ,YAAAzhB,QAAA,EAFgC,CAAlC,CAlBF,CAXoC,CAXP,CAH5B,CAXqD,CAAxC,CAryItB,CAq2II1/C,GAAiBzP,EAAA,CAAQ,CAC3BwrB,SAAU,GADiB,CAE3B4D,SAAU,CAAA,CAFiB,CAAR,CAr2IrB,CA02IIhc,GAAoBA,QAAQ,EAAG,CACjC,MAAO,CACLoY,SAAU,GADL,CAELD,QAAS,UAFJ,CAGL7C,KAAMA,QAAQ,CAACngB,CAAD,CAAQ2b,CAAR,CAAajjB,CAAb,CAAmBssD,CAAnB,CAAyB,CAChCA,CAAL,GACAtsD,CAAAkS,SAMA,CANgB,CAAA,CAMhB,CAJAo6C,CAAA4D,YAAAh+C,SAIA,CAJ4B6jE,QAAQ,CAACpR,CAAD,CAAaC,CAAb,CAAwB,CAC1D,MAAO,CAAC5kE,CAAAkS,SAAR,EAAyB,CAACo6C,CAAAiB,SAAA,CAAcqX,CAAd,CADgC,CAI5D,CAAA5kE,CAAAg5B,SAAA,CAAc,UAAd,CAA0B,QAAQ,EAAG,CACnCszB,CAAA8D,UAAA,EADmC,CAArC,CAPA,CADqC,CAHlC,CAD0B,CA12InC;AA83IIp+C,GAAmBA,QAAQ,EAAG,CAChC,MAAO,CACLuY,SAAU,GADL,CAELD,QAAS,UAFJ,CAGL7C,KAAMA,QAAQ,CAACngB,CAAD,CAAQ2b,CAAR,CAAajjB,CAAb,CAAmBssD,CAAnB,CAAyB,CACrC,GAAKA,CAAL,CAAA,CADqC,IAGjCvhC,CAHiC,CAGzBirD,EAAah2E,CAAAiS,UAAb+jE,EAA+Bh2E,CAAA+R,QAC3C/R,EAAAg5B,SAAA,CAAc,SAAd,CAAyB,QAAQ,CAACqlB,CAAD,CAAQ,CACnCviD,CAAA,CAASuiD,CAAT,CAAJ,EAAsC,CAAtC,CAAuBA,CAAA3iD,OAAvB,GACE2iD,CADF,CACU,IAAI78C,MAAJ,CAAW,GAAX,CAAiB68C,CAAjB,CAAyB,GAAzB,CADV,CAIA,IAAIA,CAAJ,EAAcj9C,CAAAi9C,CAAAj9C,KAAd,CACE,KAAM9F,EAAA,CAAO,WAAP,CAAA,CAAoB,UAApB,CACqD06E,CADrD,CAEJ33B,CAFI,CAEGj6C,EAAA,CAAY6e,CAAZ,CAFH,CAAN,CAKF8H,CAAA,CAASszB,CAAT,EAAkBhjD,CAClBixD,EAAA8D,UAAA,EAZuC,CAAzC,CAeA9D,EAAA4D,YAAAn+C,QAAA,CAA2BkkE,QAAQ,CAACl5E,CAAD,CAAQ,CACzC,MAAOuvD,EAAAiB,SAAA,CAAcxwD,CAAd,CAAP,EAA+BoC,CAAA,CAAY4rB,CAAZ,CAA/B,EAAsDA,CAAA3pB,KAAA,CAAYrE,CAAZ,CADb,CAlB3C,CADqC,CAHlC,CADyB,CA93IlC,CA65II0V,GAAqBA,QAAQ,EAAG,CAClC,MAAO,CACL8X,SAAU,GADL,CAELD,QAAS,UAFJ,CAGL7C,KAAMA,QAAQ,CAACngB,CAAD,CAAQ2b,CAAR,CAAajjB,CAAb,CAAmBssD,CAAnB,CAAyB,CACrC,GAAKA,CAAL,CAAA,CAEA,IAAI95C,EAAa,EACjBxS,EAAAg5B,SAAA,CAAc,WAAd,CAA2B,QAAQ,CAACj8B,CAAD,CAAQ,CACrCm5E,CAAAA,CAAS73E,CAAA,CAAMtB,CAAN,CACbyV,EAAA,CAAY7O,KAAA,CAAMuyE,CAAN,CAAA,CAAiB,EAAjB,CAAqBA,CACjC5pB,EAAA8D,UAAA,EAHyC,CAA3C,CAKA9D;CAAA4D,YAAA19C,UAAA,CAA6B2jE,QAAQ,CAACxR,CAAD,CAAaC,CAAb,CAAwB,CAC3D,MAAoB,EAApB,CAAQpyD,CAAR,EAA0B85C,CAAAiB,SAAA,CAAcqX,CAAd,CAA1B,EAAuDA,CAAAlpE,OAAvD,EAA2E8W,CADhB,CAR7D,CADqC,CAHlC,CAD2B,CA75IpC,CAi7IIF,GAAqBA,QAAQ,EAAG,CAClC,MAAO,CACLiY,SAAU,GADL,CAELD,QAAS,UAFJ,CAGL7C,KAAMA,QAAQ,CAACngB,CAAD,CAAQ2b,CAAR,CAAajjB,CAAb,CAAmBssD,CAAnB,CAAyB,CACrC,GAAKA,CAAL,CAAA,CAEA,IAAIj6C,EAAY,CAChBrS,EAAAg5B,SAAA,CAAc,WAAd,CAA2B,QAAQ,CAACj8B,CAAD,CAAQ,CACzCsV,CAAA,CAAYhU,CAAA,CAAMtB,CAAN,CAAZ,EAA4B,CAC5BuvD,EAAA8D,UAAA,EAFyC,CAA3C,CAIA9D,EAAA4D,YAAA79C,UAAA,CAA6B+jE,QAAQ,CAACzR,CAAD,CAAaC,CAAb,CAAwB,CAC3D,MAAOtY,EAAAiB,SAAA,CAAcqX,CAAd,CAAP,EAAmCA,CAAAlpE,OAAnC,EAAuD2W,CADI,CAP7D,CADqC,CAHlC,CAD2B,CAmB9BlX,EAAAyM,QAAA5B,UAAJ,CAEE2oC,OAAAE,IAAA,CAAY,gDAAZ,CAFF,EAQAhmC,EAAA,EAIA,CAFAoE,EAAA,CAAmBrF,EAAnB,CAEA,CAAAvD,CAAA,CAAOjJ,CAAP,CAAAw4D,MAAA,CAAuB,QAAQ,EAAG,CAChC7tD,EAAA,CAAY3K,CAAZ,CAAsB4K,EAAtB,CADgC,CAAlC,CAZA,CApr3BqC,CAAtC,CAAD,CAos3BG7K,MAps3BH,CAos3BWC,QAps3BX,CAss3BC,EAAAD,MAAAyM,QAAAyuE,MAAA,EAAD,EAA2Bl7E,MAAAyM,QAAAtH,QAAA,CAAuBlF,QAAAk7E,KAAvB,CAAA/gB,QAAA,CAA8C,gRAA9C;",
"sources":["angular.js"],
-"names":["window","document","undefined","minErr","isArrayLike","obj","isWindow","length","nodeType","isString","isArray","forEach","iterator","context","key","isFunction","hasOwnProperty","call","sortedKeys","keys","push","sort","forEachSorted","i","reverseParams","iteratorFn","value","nextUid","index","uid","digit","charCodeAt","join","String","fromCharCode","unshift","setHashKey","h","$$hashKey","extend","dst","arguments","int","str","parseInt","inherit","parent","extra","noop","identity","$","valueFn","isUndefined","isDefined","isObject","isNumber","isDate","toString","isRegExp","location","alert","setInterval","isElement","node","nodeName","prop","attr","find","map","results","list","indexOf","array","arrayRemove","splice","copy","source","destination","stackSource","stackDest","$evalAsync","$watch","ngMinErr","result","Date","getTime","RegExp","match","lastIndex","shallowCopy","src","charAt","equals","o1","o2","t1","t2","isNaN","keySet","bind","self","fn","curryArgs","slice","startIndex","apply","concat","toJsonReplacer","val","toJson","pretty","JSON","stringify","fromJson","json","parse","toBoolean","v","lowercase","startingTag","element","jqLite","clone","empty","e","elemHtml","append","html","TEXT_NODE","replace","tryDecodeURIComponent","decodeURIComponent","parseKeyValue","keyValue","key_value","split","toKeyValue","parts","arrayValue","encodeUriQuery","encodeUriSegment","pctEncodeSpaces","encodeURIComponent","angularInit","bootstrap","elements","appElement","module","names","NG_APP_CLASS_REGEXP","name","getElementById","querySelectorAll","exec","className","attributes","modules","doBootstrap","injector","tag","$provide","createInjector","invoke","scope","compile","animate","$apply","data","NG_DEFER_BOOTSTRAP","test","angular","resumeBootstrap","angular.resumeBootstrap","extraModules","snake_case","separator","SNAKE_CASE_REGEXP","letter","pos","toLowerCase","assertArg","arg","reason","assertArgFn","acceptArrayAnnotation","constructor","assertNotHasOwnProperty","getter","path","bindFnToScope","lastInstance","len","getBlockElements","nodes","startNode","endNode","nextSibling","setupModuleLoader","$injectorMinErr","$$minErr","factory","requires","configFn","invokeLater","provider","method","insertMethod","invokeQueue","moduleInstance","runBlocks","config","run","block","publishExternalAPI","version","uppercase","csp","angularModule","$LocaleProvider","ngModule","$$SanitizeUriProvider","$CompileProvider","directive","htmlAnchorDirective","inputDirective","formDirective","scriptDirective","selectDirective","styleDirective","optionDirective","ngBindDirective","ngBindHtmlDirective","ngBindTemplateDirective","ngClassDirective","ngClassEvenDirective","ngClassOddDirective","ngCloakDirective","ngControllerDirective","ngFormDirective","ngHideDirective","ngIfDirective","ngIncludeDirective","ngInitDirective","ngNonBindableDirective","ngPluralizeDirective","ngRepeatDirective","ngShowDirective","ngStyleDirective","ngSwitchDirective","ngSwitchWhenDirective","ngSwitchDefaultDirective","ngOptionsDirective","ngTranscludeDirective","ngModelDirective","ngListDirective","ngChangeDirective","requiredDirective","ngValueDirective","ngIncludeFillContentDirective","ngAttributeAliasDirectives","ngEventDirectives","$AnchorScrollProvider","$AnimateProvider","$BrowserProvider","$CacheFactoryProvider","$ControllerProvider","$DocumentProvider","$ExceptionHandlerProvider","$FilterProvider","$InterpolateProvider","$IntervalProvider","$HttpProvider","$HttpBackendProvider","$LocationProvider","$LogProvider","$ParseProvider","$RootScopeProvider","$QProvider","$SceProvider","$SceDelegateProvider","$SnifferProvider","$TemplateCacheProvider","$TimeoutProvider","$WindowProvider","$$RAFProvider","$$AsyncCallbackProvider","camelCase","SPECIAL_CHARS_REGEXP","_","offset","toUpperCase","MOZ_HACK_REGEXP","jqLitePatchJQueryRemove","dispatchThis","filterElems","getterIfNoArguments","removePatch","param","filter","fireEvent","set","setIndex","setLength","childIndex","children","shift","triggerHandler","childLength","jQuery","originalJqFn","$original","JQLite","trim","jqLiteMinErr","parsed","SINGLE_TAG_REGEXP","fragment","createDocumentFragment","HTML_REGEXP","tmp","appendChild","createElement","TAG_NAME_REGEXP","wrap","wrapMap","_default","innerHTML","XHTML_TAG_REGEXP","removeChild","firstChild","lastChild","j","jj","childNodes","textContent","createTextNode","jqLiteAddNodes","jqLiteClone","cloneNode","jqLiteDealoc","jqLiteRemoveData","jqLiteOff","type","unsupported","events","jqLiteExpandoStore","handle","eventHandler","removeEventListenerFn","expandoId","ng339","expandoStore","jqCache","$destroy","jqId","jqLiteData","isSetter","keyDefined","isSimpleGetter","jqLiteHasClass","selector","getAttribute","jqLiteRemoveClass","cssClasses","setAttribute","cssClass","jqLiteAddClass","existingClasses","root","jqLiteController","jqLiteInheritedData","documentElement","ii","parentNode","host","jqLiteEmpty","getBooleanAttrName","booleanAttr","BOOLEAN_ATTR","BOOLEAN_ELEMENTS","createEventHandler","event","preventDefault","event.preventDefault","returnValue","stopPropagation","event.stopPropagation","cancelBubble","target","srcElement","defaultPrevented","prevent","isDefaultPrevented","event.isDefaultPrevented","eventHandlersCopy","msie","elem","hashKey","nextUidFn","objType","HashMap","isolatedUid","this.nextUid","put","annotate","$inject","fnText","STRIP_COMMENTS","argDecl","FN_ARGS","FN_ARG_SPLIT","FN_ARG","all","underscore","last","modulesToLoad","supportObject","delegate","provider_","providerInjector","instantiate","$get","providerCache","providerSuffix","factoryFn","loadModules","moduleFn","loadedModules","get","_runBlocks","_invokeQueue","invokeArgs","message","stack","createInternalInjector","cache","getService","serviceName","INSTANTIATING","err","locals","args","Type","Constructor","returnedValue","prototype","instance","has","service","$injector","constant","instanceCache","decorator","decorFn","origProvider","orig$get","origProvider.$get","origInstance","instanceInjector","servicename","autoScrollingEnabled","disableAutoScrolling","this.disableAutoScrolling","$window","$location","$rootScope","getFirstAnchor","scroll","hash","elm","scrollIntoView","getElementsByName","scrollTo","autoScrollWatch","autoScrollWatchAction","$$rAF","$timeout","supported","Browser","$log","$sniffer","completeOutstandingRequest","outstandingRequestCount","outstandingRequestCallbacks","pop","error","startPoller","interval","setTimeout","check","pollFns","pollFn","pollTimeout","fireUrlChange","lastBrowserUrl","url","urlChangeListeners","listener","rawDocument","history","clearTimeout","pendingDeferIds","isMock","$$completeOutstandingRequest","$$incOutstandingRequestCount","self.$$incOutstandingRequestCount","notifyWhenNoOutstandingRequests","self.notifyWhenNoOutstandingRequests","callback","addPollFn","self.addPollFn","href","baseElement","reloadLocation","self.url","sameBase","stripHash","replaceState","pushState","urlChangeInit","onUrlChange","self.onUrlChange","on","hashchange","$$checkUrlChange","baseHref","self.baseHref","lastCookies","lastCookieString","cookiePath","cookies","self.cookies","cookieLength","cookie","escape","warn","cookieArray","unescape","substring","defer","self.defer","delay","timeoutId","cancel","self.defer.cancel","deferId","$document","this.$get","cacheFactory","cacheId","options","refresh","entry","freshEnd","staleEnd","n","link","p","nextEntry","prevEntry","caches","size","stats","capacity","Number","MAX_VALUE","lruHash","lruEntry","remove","removeAll","destroy","info","cacheFactory.info","cacheFactory.get","$cacheFactory","$$sanitizeUriProvider","hasDirectives","Suffix","COMMENT_DIRECTIVE_REGEXP","CLASS_DIRECTIVE_REGEXP","EVENT_HANDLER_ATTR_REGEXP","this.directive","registerDirective","directiveFactory","$exceptionHandler","directives","priority","require","controller","restrict","aHrefSanitizationWhitelist","this.aHrefSanitizationWhitelist","regexp","imgSrcSanitizationWhitelist","this.imgSrcSanitizationWhitelist","$interpolate","$http","$templateCache","$parse","$controller","$sce","$animate","$$sanitizeUri","$compileNodes","transcludeFn","maxPriority","ignoreDirective","previousCompileContext","nodeValue","compositeLinkFn","compileNodes","safeAddClass","publicLinkFn","cloneConnectFn","transcludeControllers","parentBoundTranscludeFn","$linkNode","JQLitePrototype","eq","$element","addClass","nodeList","$rootElement","childLinkFn","childScope","childBoundTranscludeFn","nodeListLength","stableNodeList","Array","linkFns","nodeLinkFn","$new","transcludeOnThisElement","createBoundTranscludeFn","transclude","templateOnThisElement","attrs","linkFnFound","Attributes","collectDirectives","applyDirectivesToNode","$$element","terminal","previousBoundTranscludeFn","boundTranscludeFn","transcludedScope","cloneFn","controllers","scopeCreated","$$transcluded","attrsMap","$attr","addDirective","directiveNormalize","nodeName_","isNgAttr","nAttrs","attrStartName","attrEndName","specified","ngAttrName","NG_ATTR_BINDING","substr","directiveNName","nName","addAttrInterpolateDirective","addTextInterpolateDirective","byPriority","groupScan","attrStart","attrEnd","depth","hasAttribute","$compileMinErr","groupElementsLinkFnWrapper","linkFn","compileNode","templateAttrs","jqCollection","originalReplaceDirective","preLinkFns","postLinkFns","addLinkFns","pre","post","directiveName","newIsolateScopeDirective","$$isolateScope","cloneAndAnnotateFn","getControllers","elementControllers","retrievalMethod","optional","linkNode","controllersBoundTransclude","cloneAttachFn","hasElementTranscludeDirective","isolateScope","LOCAL_REGEXP","templateDirective","$$originalDirective","definition","scopeName","attrName","mode","lastValue","parentGet","parentSet","compare","$$isolateBindings","$observe","$$observers","$$scope","literal","a","b","assign","parentValueWatch","parentValue","controllerDirectives","controllerInstance","controllerAs","$scope","scopeToChild","template","templateUrl","terminalPriority","newScopeDirective","nonTlbTranscludeDirective","hasTranscludeDirective","hasTemplate","$compileNode","$template","childTranscludeFn","$$start","$$end","directiveValue","assertNoDuplicate","$$tlb","createComment","replaceWith","replaceDirective","contents","denormalizeTemplate","newTemplateAttrs","templateDirectives","unprocessedDirectives","markDirectivesAsIsolate","mergeTemplateAttributes","compileTemplateUrl","Math","max","tDirectives","startAttrName","endAttrName","srcAttr","dstAttr","$set","tAttrs","linkQueue","afterTemplateNodeLinkFn","afterTemplateChildLinkFn","beforeTemplateCompileNode","origAsyncDirective","derivedSyncDirective","getTrustedResourceUrl","success","content","tempTemplateAttrs","beforeTemplateLinkNode","linkRootElement","oldClasses","response","code","headers","delayedNodeLinkFn","ignoreChildLinkFn","rootElement","diff","what","previousDirective","text","interpolateFn","textInterpolateCompileFn","templateNode","hasCompileParent","textInterpolateLinkFn","bindings","interpolateFnWatchAction","getTrustedContext","attrNormalizedName","HTML","RESOURCE_URL","attrInterpolatePreLinkFn","$$inter","newValue","oldValue","$updateClass","elementsToRemove","newNode","firstElementToRemove","removeCount","j2","replaceChild","expando","k","kk","annotation","$addClass","classVal","$removeClass","removeClass","newClasses","toAdd","tokenDifference","toRemove","setClass","writeAttr","booleanKey","removeAttr","listeners","startSymbol","endSymbol","PREFIX_REGEXP","str1","str2","values","tokens1","tokens2","token","CNTRL_REG","register","this.register","expression","identifier","exception","cause","parseHeaders","line","headersGetter","headersObj","transformData","fns","JSON_START","JSON_END","PROTECTION_PREFIX","CONTENT_TYPE_APPLICATION_JSON","defaults","d","interceptorFactories","interceptors","responseInterceptorFactories","responseInterceptors","$httpBackend","$browser","$q","requestConfig","transformResponse","resp","status","reject","transformRequest","mergeHeaders","defHeaders","reqHeaders","defHeaderName","reqHeaderName","common","lowercaseDefHeaderName","execHeaders","headerContent","headerFn","header","chain","serverRequest","reqData","withCredentials","sendReq","then","promise","when","reversedInterceptors","interceptor","request","requestError","responseError","thenFn","rejectFn","promise.success","promise.error","done","headersString","statusText","resolvePromise","$$phase","deferred","resolve","removePendingReq","idx","pendingRequests","cachedResp","buildUrl","params","defaultCache","xsrfValue","urlIsSameOrigin","xsrfCookieName","xsrfHeaderName","timeout","responseType","toISOString","interceptorFactory","responseFn","createShortMethods","createShortMethodsWithData","createXhr","XMLHttpRequest","ActiveXObject","createHttpBackend","callbacks","$browserDefer","jsonpReq","callbackId","script","async","body","called","addEventListenerFn","onreadystatechange","script.onreadystatechange","readyState","ABORTED","timeoutRequest","jsonpDone","xhr","abort","completeRequest","urlResolve","protocol","counter","open","setRequestHeader","xhr.onreadystatechange","responseHeaders","getAllResponseHeaders","responseText","send","this.startSymbol","this.endSymbol","mustHaveExpression","trustedContext","endIndex","hasInterpolation","startSymbolLength","exp","endSymbolLength","$interpolateMinErr","part","getTrusted","valueOf","newErr","$interpolate.startSymbol","$interpolate.endSymbol","count","invokeApply","clearInterval","iteration","skipApply","$$intervalId","tick","notify","intervals","interval.cancel","short","pluralCat","num","encodePath","segments","parseAbsoluteUrl","absoluteUrl","locationObj","appBase","parsedUrl","$$protocol","$$host","hostname","$$port","port","DEFAULT_PORTS","parseAppUrl","relativeUrl","prefixed","$$path","pathname","$$search","search","$$hash","beginsWith","begin","whole","stripFile","lastIndexOf","LocationHtml5Url","basePrefix","$$html5","appBaseNoFile","$$parse","this.$$parse","pathUrl","$locationMinErr","$$compose","this.$$compose","$$url","$$absUrl","$$parseLinkUrl","this.$$parseLinkUrl","relHref","appUrl","prevAppUrl","rewrittenUrl","LocationHashbangUrl","hashPrefix","withoutBaseUrl","withoutHashUrl","windowsFilePathExp","firstPathSegmentMatch","LocationHashbangInHtml5Url","locationGetter","property","locationGetterSetter","preprocess","html5Mode","this.hashPrefix","prefix","this.html5Mode","afterLocationChange","oldUrl","$broadcast","absUrl","initialUrl","LocationMode","IGNORE_URI_REGEXP","ctrlKey","metaKey","which","absHref","animVal","newUrl","$digest","changeCounter","$locationWatch","currentReplace","$$replace","debug","debugEnabled","this.debugEnabled","flag","formatError","Error","sourceURL","consoleLog","console","logFn","log","hasApply","arg1","arg2","ensureSafeMemberName","fullExpression","$parseMinErr","ensureSafeObject","Object","setter","setValue","fullExp","propertyObj","unwrapPromises","promiseWarning","$$v","isPossiblyDangerousMemberName","cspSafeGetterFn","key0","key1","key2","key3","key4","eso","o","expensiveChecks","eso0","eso1","eso2","eso3","eso4","cspSafePromiseEnabledGetter","pathVal","cspSafeGetter","getterFnWithExtraArgs","s","l","getterFn","getterFnCache","getterFnCacheExpensive","getterFnCacheDefault","pathKeys","pathKeysLength","needsEnsureSafeObject","lookupJs","wrapWithEso","evaledFnGetter","Function","cacheDefault","cacheExpensive","$parseOptions","this.unwrapPromises","logPromiseWarnings","this.logPromiseWarnings","$filter","$parseOptionsExpensive","promiseWarningCache","parsedExpression","parseOptions","lexer","Lexer","parser","Parser","qFactory","nextTick","exceptionHandler","defaultCallback","defaultErrback","pending","ref","createInternalRejectedPromise","progress","errback","progressback","wrappedCallback","wrappedErrback","wrappedProgressback","catch","finally","makePromise","resolved","handleCallback","isResolved","callbackOutput","promises","requestAnimationFrame","webkitRequestAnimationFrame","mozRequestAnimationFrame","cancelAnimationFrame","webkitCancelAnimationFrame","mozCancelAnimationFrame","webkitCancelRequestAnimationFrame","rafSupported","raf","id","timer","TTL","$rootScopeMinErr","lastDirtyWatch","digestTtl","this.digestTtl","Scope","$id","$parent","$$watchers","$$nextSibling","$$prevSibling","$$childHead","$$childTail","$root","$$destroyed","$$asyncQueue","$$postDigestQueue","$$listeners","$$listenerCount","beginPhase","phase","compileToFn","decrementListenerCount","current","initWatchVal","isolate","child","$$childScopeClass","this.$$childScopeClass","watchExp","objectEquality","watcher","listenFn","watcher.fn","newVal","oldVal","originalFn","deregisterWatch","$watchCollection","veryOldValue","trackVeryOldValue","changeDetected","objGetter","internalArray","internalObject","initRun","oldLength","$watchCollectionWatch","newLength","bothNaN","$watchCollectionAction","watch","watchers","asyncQueue","postDigestQueue","dirty","ttl","watchLog","logIdx","logMsg","asyncTask","$eval","next","$on","this.$watch","expr","$$postDigest","namedListeners","indexOfListener","$emit","listenerArgs","array1","currentScope","sanitizeUri","uri","isImage","regex","normalizedVal","adjustMatcher","matcher","$sceMinErr","adjustMatchers","matchers","adjustedMatchers","SCE_CONTEXTS","resourceUrlWhitelist","resourceUrlBlacklist","this.resourceUrlWhitelist","this.resourceUrlBlacklist","generateHolderType","Base","holderType","trustedValue","$$unwrapTrustedValue","this.$$unwrapTrustedValue","holderType.prototype.valueOf","holderType.prototype.toString","htmlSanitizer","trustedValueHolderBase","byType","CSS","URL","JS","trustAs","maybeTrusted","allowed","enabled","this.enabled","$sceDelegate","msieDocumentMode","sce","isEnabled","sce.isEnabled","sce.getTrusted","parseAs","sce.parseAs","sceParseAsTrusted","enumValue","lName","eventSupport","android","userAgent","navigator","boxee","documentMode","vendorPrefix","vendorRegex","bodyStyle","style","transitions","animations","webkitTransition","webkitAnimation","hasEvent","divElm","deferreds","$$timeoutId","timeout.cancel","base","urlParsingNode","requestUrl","originUrl","filters","suffix","currencyFilter","dateFilter","filterFilter","jsonFilter","limitToFilter","lowercaseFilter","numberFilter","orderByFilter","uppercaseFilter","comparator","comparatorType","predicates","predicates.check","objKey","filtered","$locale","formats","NUMBER_FORMATS","amount","currencySymbol","CURRENCY_SYM","formatNumber","PATTERNS","GROUP_SEP","DECIMAL_SEP","number","fractionSize","pattern","groupSep","decimalSep","isFinite","isNegative","abs","numStr","formatedText","hasExponent","toFixed","fractionLen","min","minFrac","maxFrac","round","fraction","lgroup","lgSize","group","gSize","negPre","posPre","negSuf","posSuf","padNumber","digits","neg","dateGetter","date","dateStrGetter","shortForm","jsonStringToDate","string","R_ISO8601_STR","tzHour","tzMin","dateSetter","setUTCFullYear","setFullYear","timeSetter","setUTCHours","setHours","m","ms","parseFloat","format","DATETIME_FORMATS","NUMBER_STRING","DATE_FORMATS_SPLIT","DATE_FORMATS","object","input","limit","Infinity","out","sortPredicate","reverseOrder","reverseComparator","comp","descending","v1","v2","predicate","ngDirective","FormController","toggleValidCss","isValid","validationErrorKey","VALID_CLASS","INVALID_CLASS","form","parentForm","nullFormCtrl","invalidCount","errors","$error","controls","$name","ngForm","$dirty","$pristine","$valid","$invalid","$addControl","PRISTINE_CLASS","form.$addControl","control","$removeControl","form.$removeControl","queue","validationToken","$setValidity","form.$setValidity","$setDirty","form.$setDirty","DIRTY_CLASS","$setPristine","form.$setPristine","validate","ctrl","validatorName","validity","testFlags","flags","addNativeHtml5Validators","badFlags","ignoreFlags","$$hasNativeValidators","$parsers","validator","textInputType","VALIDITY_STATE_PROPERTY","placeholder","noevent","$$validityState","composing","ev","ngTrim","revalidate","$viewValue","$setViewValue","deferListener","keyCode","$render","ctrl.$render","$isEmpty","ngPattern","patternValidator","patternObj","$formatters","ngMinlength","minlength","minLengthValidator","ngMaxlength","maxlength","maxLengthValidator","classDirective","arrayDifference","arrayClasses","classes","digestClassCounts","classCounts","classesToUpdate","ngClassWatchAction","$index","old$index","mod","isActive_","active","querySelector","addEventListener","attachEvent","removeEventListener","detachEvent","_data","JQLite._data","optgroup","option","tbody","tfoot","colgroup","caption","thead","th","td","ready","trigger","fired","removeAttribute","css","currentStyle","lowercasedName","getNamedItem","ret","getText","textProp","NODE_TYPE_TEXT_PROPERTY","$dv","multiple","selected","nodeCount","onFn","eventFns","contains","compareDocumentPosition","adown","bup","eventmap","related","relatedTarget","one","off","replaceNode","insertBefore","contentDocument","prepend","wrapNode","after","newElement","toggleClass","condition","classCondition","nextElementSibling","getElementsByTagName","extraParameters","dummyEvent","handlerArgs","eventName","eventFnsCopy","arg3","unbind","$animateMinErr","$$selectors","classNameFilter","this.classNameFilter","$$classNameFilter","$$asyncCallback","enter","leave","move","add","PATH_MATCH","paramValue","CALL","APPLY","BIND","OPERATORS","null","true","false","+","-","*","/","%","^","===","!==","==","!=","<",">","<=",">=","&&","||","&","|","!","ESCAPE","lex","ch","lastCh","tokens","is","readString","peek","readNumber","isIdent","readIdent","isWhitespace","ch2","ch3","fn2","fn3","throwError","chars","was","isExpOperator","start","end","colStr","peekCh","ident","lastDot","peekIndex","methodName","quote","rawString","hex","rep","ZERO","statements","primary","expect","filterChain","consume","arrayDeclaration","functionCall","objectIndex","fieldAccess","msg","peekToken","e1","e2","e3","e4","t","unaryFn","right","ternaryFn","left","middle","binaryFn","statement","argsFn","fnInvoke","assignment","ternary","logicalOR","logicalAND","equality","relational","additive","multiplicative","unary","field","indexFn","contextGetter","fnPtr","elementFns","allConstant","elementFn","keyValues","ampmGetter","getHours","AMPMS","timeZoneGetter","zone","getTimezoneOffset","paddedZone","xlinkHref","propName","normalized","ngBooleanAttrWatchAction","formDirectiveFactory","isNgForm","formElement","action","preventDefaultListener","parentFormCtrl","alias","URL_REGEXP","EMAIL_REGEXP","NUMBER_REGEXP","inputType","numberInputType","numberBadFlags","minValidator","maxValidator","urlInputType","urlValidator","emailInputType","emailValidator","radioInputType","checked","checkboxInputType","trueValue","ngTrueValue","falseValue","ngFalseValue","ctrl.$isEmpty","NgModelController","$modelValue","NaN","$viewChangeListeners","ngModelGet","ngModel","ngModelSet","this.$isEmpty","inheritedData","this.$setValidity","this.$setPristine","this.$setViewValue","ngModelWatch","formatters","ctrls","modelCtrl","formCtrl","ngChange","required","ngList","viewValue","CONSTANT_VALUE_REGEXP","tpl","tplAttr","ngValue","ngValueConstantLink","ngValueLink","valueWatchAction","templateElement","ngBind","ngBindWatchAction","ngBindTemplate","tElement","ngBindHtml","getStringValue","ngBindHtmlWatchAction","getTrustedHtml","forceAsyncEvents","ngEventHandler","$transclude","previousElements","ngIf","ngIfWatchAction","$anchorScroll","srcExp","ngInclude","onloadExp","onload","autoScrollExp","autoscroll","previousElement","currentElement","cleanupLastIncludeContent","parseAsResourceUrl","ngIncludeWatchAction","afterAnimation","thisChangeId","newScope","$compile","ngInit","BRACE","numberExp","whenExp","whens","whensExpFns","isWhen","attributeName","ngPluralizeWatch","ngPluralizeWatchAction","ngRepeatMinErr","ngRepeat","trackByExpGetter","trackByIdExpFn","trackByIdArrayFn","trackByIdObjFn","valueIdentifier","keyIdentifier","hashFnLocals","lhs","rhs","trackByExp","lastBlockMap","ngRepeatAction","collection","previousNode","nextNode","nextBlockMap","arrayLength","trackByIdFn","collectionKeys","nextBlockOrder","trackById","$first","$last","$middle","$odd","$even","ngShow","ngShowWatchAction","ngHide","ngHideWatchAction","ngStyle","ngStyleWatchAction","newStyles","oldStyles","ngSwitchController","cases","selectedTranscludes","selectedElements","selectedScopes","ngSwitch","ngSwitchWatchAction","change","selectedTransclude","selectedScope","caseElement","anchor","ngSwitchWhen","$attrs","ngOptionsMinErr","NG_OPTIONS_REGEXP","nullModelCtrl","optionsMap","ngModelCtrl","unknownOption","databound","init","self.init","ngModelCtrl_","nullOption_","unknownOption_","addOption","self.addOption","removeOption","self.removeOption","hasOption","renderUnknownOption","self.renderUnknownOption","unknownVal","self.hasOption","setupAsSingle","selectElement","selectCtrl","ngModelCtrl.$render","emptyOption","setupAsMultiple","lastView","items","selectMultipleWatch","setupAsOptions","render","optionGroups","optionGroupNames","optionGroupName","optionGroup","existingParent","existingOptions","existingOption","modelValue","valuesFn","keyName","groupIndex","selectedSet","trackFn","trackIndex","valueName","lastElement","groupByFn","modelCast","label","displayFn","nullOption","groupLength","optionGroupsCache","optGroupTemplate","optionTemplate","optionsExp","track","optionElement","toDisplay","ngOptions","ngModelCtrl.$isEmpty","nullSelectCtrl","selectCtrlName","interpolateWatchAction","$$csp"]
+"names":["window","document","undefined","minErr","isArrayLike","obj","isWindow","length","Object","nodeType","NODE_TYPE_ELEMENT","isString","isArray","forEach","iterator","context","key","isFunction","hasOwnProperty","call","isPrimitive","isBlankObject","forEachSorted","keys","sort","i","reverseParams","iteratorFn","value","nextUid","uid","setHashKey","h","$$hashKey","baseExtend","dst","objs","deep","ii","isObject","j","jj","src","isDate","Date","valueOf","extend","slice","arguments","merge","toInt","str","parseInt","inherit","parent","extra","create","noop","identity","$","valueFn","hasCustomToString","toString","prototype","isUndefined","isDefined","getPrototypeOf","isNumber","isRegExp","isScope","$evalAsync","$watch","isBoolean","isElement","node","nodeName","prop","attr","find","makeMap","items","split","nodeName_","element","lowercase","arrayRemove","array","index","indexOf","splice","copy","source","destination","stackSource","stackDest","ngMinErr","TYPED_ARRAY_REGEXP","test","push","constructor","getTime","RegExp","match","lastIndex","emptyObject","shallowCopy","charAt","equals","o1","o2","t1","t2","keySet","createMap","concat","array1","array2","bind","self","fn","curryArgs","startIndex","apply","toJsonReplacer","val","toJson","pretty","JSON","stringify","fromJson","json","parse","timezoneToOffset","timezone","fallback","requestedTimezoneOffset","isNaN","convertTimezoneToLocal","date","reverse","timezoneOffset","getTimezoneOffset","setMinutes","getMinutes","minutes","startingTag","jqLite","clone","empty","e","elemHtml","append","html","NODE_TYPE_TEXT","replace","tryDecodeURIComponent","decodeURIComponent","parseKeyValue","keyValue","key_value","toKeyValue","parts","arrayValue","encodeUriQuery","join","encodeUriSegment","pctEncodeSpaces","encodeURIComponent","getNgAttribute","ngAttr","ngAttrPrefixes","getAttribute","angularInit","bootstrap","appElement","module","config","prefix","name","hasAttribute","candidate","querySelector","strictDi","modules","defaultConfig","doBootstrap","injector","tag","unshift","$provide","debugInfoEnabled","$compileProvider","createInjector","invoke","bootstrapApply","scope","compile","$apply","data","NG_ENABLE_DEBUG_INFO","NG_DEFER_BOOTSTRAP","angular","resumeBootstrap","angular.resumeBootstrap","extraModules","resumeDeferredBootstrap","reloadWithDebugInfo","location","reload","getTestability","rootElement","get","snake_case","separator","SNAKE_CASE_REGEXP","letter","pos","toLowerCase","bindJQuery","originalCleanData","bindJQueryFired","jqName","jq","jQuery","on","JQLitePrototype","isolateScope","controller","inheritedData","cleanData","jQuery.cleanData","elems","events","skipDestroyOnNextJQueryCleanData","elem","_data","$destroy","triggerHandler","JQLite","assertArg","arg","reason","assertArgFn","acceptArrayAnnotation","assertNotHasOwnProperty","getter","path","bindFnToScope","lastInstance","len","getBlockNodes","nodes","endNode","blockNodes","nextSibling","setupModuleLoader","ensure","factory","$injectorMinErr","$$minErr","requires","configFn","invokeLater","provider","method","insertMethod","queue","invokeQueue","moduleInstance","invokeLaterAndSetModuleName","recipeName","factoryFunction","$$moduleName","configBlocks","runBlocks","_invokeQueue","_configBlocks","_runBlocks","service","constant","decorator","animation","filter","directive","run","block","publishExternalAPI","version","uppercase","counter","csp","angularModule","$LocaleProvider","ngModule","$$sanitizeUri","$$SanitizeUriProvider","$CompileProvider","a","htmlAnchorDirective","input","inputDirective","textarea","form","formDirective","script","scriptDirective","select","selectDirective","style","styleDirective","option","optionDirective","ngBind","ngBindDirective","ngBindHtml","ngBindHtmlDirective","ngBindTemplate","ngBindTemplateDirective","ngClass","ngClassDirective","ngClassEven","ngClassEvenDirective","ngClassOdd","ngClassOddDirective","ngCloak","ngCloakDirective","ngController","ngControllerDirective","ngForm","ngFormDirective","ngHide","ngHideDirective","ngIf","ngIfDirective","ngInclude","ngIncludeDirective","ngInit","ngInitDirective","ngNonBindable","ngNonBindableDirective","ngPluralize","ngPluralizeDirective","ngRepeat","ngRepeatDirective","ngShow","ngShowDirective","ngStyle","ngStyleDirective","ngSwitch","ngSwitchDirective","ngSwitchWhen","ngSwitchWhenDirective","ngSwitchDefault","ngSwitchDefaultDirective","ngOptions","ngOptionsDirective","ngTransclude","ngTranscludeDirective","ngModel","ngModelDirective","ngList","ngListDirective","ngChange","ngChangeDirective","pattern","patternDirective","ngPattern","required","requiredDirective","ngRequired","minlength","minlengthDirective","ngMinlength","maxlength","maxlengthDirective","ngMaxlength","ngValue","ngValueDirective","ngModelOptions","ngModelOptionsDirective","ngIncludeFillContentDirective","ngAttributeAliasDirectives","ngEventDirectives","$anchorScroll","$AnchorScrollProvider","$animate","$AnimateProvider","$$animateQueue","$$CoreAnimateQueueProvider","$$AnimateRunner","$$CoreAnimateRunnerProvider","$browser","$BrowserProvider","$cacheFactory","$CacheFactoryProvider","$controller","$ControllerProvider","$document","$DocumentProvider","$exceptionHandler","$ExceptionHandlerProvider","$filter","$FilterProvider","$interpolate","$InterpolateProvider","$interval","$IntervalProvider","$http","$HttpProvider","$httpParamSerializer","$HttpParamSerializerProvider","$httpParamSerializerJQLike","$HttpParamSerializerJQLikeProvider","$httpBackend","$HttpBackendProvider","$location","$LocationProvider","$log","$LogProvider","$parse","$ParseProvider","$rootScope","$RootScopeProvider","$q","$QProvider","$$q","$$QProvider","$sce","$SceProvider","$sceDelegate","$SceDelegateProvider","$sniffer","$SnifferProvider","$templateCache","$TemplateCacheProvider","$templateRequest","$TemplateRequestProvider","$$testability","$$TestabilityProvider","$timeout","$TimeoutProvider","$window","$WindowProvider","$$rAF","$$RAFProvider","$$jqLite","$$jqLiteProvider","$$HashMap","$$HashMapProvider","$$cookieReader","$$CookieReaderProvider","camelCase","SPECIAL_CHARS_REGEXP","_","offset","toUpperCase","MOZ_HACK_REGEXP","jqLiteAcceptsData","NODE_TYPE_DOCUMENT","jqLiteBuildFragment","tmp","fragment","createDocumentFragment","HTML_REGEXP","appendChild","createElement","TAG_NAME_REGEXP","exec","wrap","wrapMap","_default","innerHTML","XHTML_TAG_REGEXP","lastChild","childNodes","firstChild","textContent","createTextNode","argIsString","trim","jqLiteMinErr","parsed","SINGLE_TAG_REGEXP","jqLiteAddNodes","jqLiteClone","cloneNode","jqLiteDealoc","onlyDescendants","jqLiteRemoveData","querySelectorAll","descendants","l","jqLiteOff","type","unsupported","expandoStore","jqLiteExpandoStore","handle","listenerFns","removeEventListener","expandoId","ng339","jqCache","createIfNecessary","jqId","jqLiteData","isSimpleSetter","isSimpleGetter","massGetter","jqLiteHasClass","selector","jqLiteRemoveClass","cssClasses","setAttribute","cssClass","jqLiteAddClass","existingClasses","root","elements","jqLiteController","jqLiteInheritedData","documentElement","names","parentNode","NODE_TYPE_DOCUMENT_FRAGMENT","host","jqLiteEmpty","removeChild","jqLiteRemove","keepData","jqLiteDocumentLoaded","action","win","readyState","setTimeout","getBooleanAttrName","booleanAttr","BOOLEAN_ATTR","BOOLEAN_ELEMENTS","getAliasedAttrName","ALIASED_ATTR","createEventHandler","eventHandler","event","isDefaultPrevented","event.isDefaultPrevented","defaultPrevented","eventFns","eventFnsLength","immediatePropagationStopped","originalStopImmediatePropagation","stopImmediatePropagation","event.stopImmediatePropagation","stopPropagation","isImmediatePropagationStopped","event.isImmediatePropagationStopped","$get","this.$get","hasClass","classes","addClass","removeClass","hashKey","nextUidFn","objType","HashMap","isolatedUid","this.nextUid","put","anonFn","args","fnText","STRIP_COMMENTS","FN_ARGS","modulesToLoad","supportObject","delegate","provider_","providerInjector","instantiate","providerCache","providerSuffix","enforceReturnValue","enforcedReturnValue","result","instanceInjector","factoryFn","enforce","loadModules","moduleFn","runInvokeQueue","invokeArgs","loadedModules","message","stack","createInternalInjector","cache","getService","serviceName","caller","INSTANTIATING","err","shift","locals","$inject","$$annotate","Type","instance","returnedValue","annotate","has","$injector","instanceCache","decorFn","origProvider","orig$get","origProvider.$get","origInstance","$delegate","autoScrollingEnabled","disableAutoScrolling","this.disableAutoScrolling","getFirstAnchor","list","Array","some","scrollTo","scrollIntoView","scroll","yOffset","getComputedStyle","position","getBoundingClientRect","bottom","elemTop","top","scrollBy","hash","elm","getElementById","getElementsByName","autoScrollWatch","autoScrollWatchAction","newVal","oldVal","mergeClasses","b","splitClasses","klass","prepareAnimateOptions","options","Browser","completeOutstandingRequest","outstandingRequestCount","outstandingRequestCallbacks","pop","error","cacheStateAndFireUrlChange","cacheState","fireUrlChange","history","state","cachedState","lastCachedState","lastBrowserUrl","url","lastHistoryState","urlChangeListeners","listener","clearTimeout","pendingDeferIds","isMock","$$completeOutstandingRequest","$$incOutstandingRequestCount","self.$$incOutstandingRequestCount","notifyWhenNoOutstandingRequests","self.notifyWhenNoOutstandingRequests","callback","href","baseElement","reloadLocation","self.url","sameState","sameBase","stripHash","substr","self.state","urlChangeInit","onUrlChange","self.onUrlChange","$$applicationDestroyed","self.$$applicationDestroyed","off","$$checkUrlChange","baseHref","self.baseHref","defer","self.defer","delay","timeoutId","cancel","self.defer.cancel","deferId","cacheFactory","cacheId","refresh","entry","freshEnd","staleEnd","n","link","p","nextEntry","prevEntry","caches","size","stats","id","capacity","Number","MAX_VALUE","lruHash","lruEntry","remove","removeAll","destroy","info","cacheFactory.info","cacheFactory.get","$$sanitizeUriProvider","parseIsolateBindings","directiveName","isController","LOCAL_REGEXP","bindings","definition","scopeName","$compileMinErr","mode","collection","optional","attrName","assertValidDirectiveName","hasDirectives","COMMENT_DIRECTIVE_REGEXP","CLASS_DIRECTIVE_REGEXP","ALL_OR_NOTHING_ATTRS","REQUIRE_PREFIX_REGEXP","EVENT_HANDLER_ATTR_REGEXP","this.directive","registerDirective","directiveFactory","Suffix","directives","priority","require","restrict","bindToController","controllerAs","CNTRL_REG","$$bindings","$$isolateBindings","aHrefSanitizationWhitelist","this.aHrefSanitizationWhitelist","regexp","imgSrcSanitizationWhitelist","this.imgSrcSanitizationWhitelist","this.debugInfoEnabled","enabled","safeAddClass","$element","className","$compileNodes","transcludeFn","maxPriority","ignoreDirective","previousCompileContext","nodeValue","compositeLinkFn","compileNodes","$$addScopeClass","namespace","publicLinkFn","cloneConnectFn","parentBoundTranscludeFn","transcludeControllers","futureParentElement","$$boundTransclude","$linkNode","wrapTemplate","controllerName","$$addScopeInfo","nodeList","$rootElement","childLinkFn","childScope","childBoundTranscludeFn","stableNodeList","nodeLinkFnFound","linkFns","idx","nodeLinkFn","destroyBindings","$new","$$destroyBindings","$on","transcludeOnThisElement","createBoundTranscludeFn","transclude","templateOnThisElement","attrs","linkFnFound","Attributes","collectDirectives","applyDirectivesToNode","$$element","terminal","previousBoundTranscludeFn","boundTranscludeFn","transcludedScope","cloneFn","controllers","containingScope","$$transcluded","attrsMap","$attr","addDirective","directiveNormalize","isNgAttr","nAttrs","attributes","attrStartName","attrEndName","ngAttrName","NG_ATTR_BINDING","PREFIX_REGEXP","directiveNName","directiveIsMultiElement","nName","addAttrInterpolateDirective","animVal","msie","addTextInterpolateDirective","NODE_TYPE_COMMENT","byPriority","groupScan","attrStart","attrEnd","depth","groupElementsLinkFnWrapper","linkFn","compileNode","templateAttrs","jqCollection","originalReplaceDirective","preLinkFns","postLinkFns","addLinkFns","pre","post","newIsolateScopeDirective","$$isolateScope","cloneAndAnnotateFn","getControllers","elementControllers","substring","inheritType","dataName","setupControllers","controllerDirectives","controllerKey","$scope","$attrs","$transclude","controllerInstance","hasElementTranscludeDirective","linkNode","thisLinkFn","controllersBoundTransclude","cloneAttachFn","scopeToChild","templateDirective","$$originalDirective","initializeDirectiveBindings","scopeDirective","newScopeDirective","controllerForBindings","identifier","controllerResult","invokeLinkFn","template","templateUrl","terminalPriority","nonTlbTranscludeDirective","hasTranscludeDirective","hasTemplate","$compileNode","$template","childTranscludeFn","$$start","$$end","directiveValue","assertNoDuplicate","$$tlb","createComment","replaceWith","replaceDirective","contents","denormalizeTemplate","removeComments","templateNamespace","newTemplateAttrs","templateDirectives","unprocessedDirectives","markDirectivesAsIsolate","mergeTemplateAttributes","compileTemplateUrl","Math","max","tDirectives","startAttrName","endAttrName","multiElement","srcAttr","dstAttr","$set","tAttrs","linkQueue","afterTemplateNodeLinkFn","afterTemplateChildLinkFn","beforeTemplateCompileNode","origAsyncDirective","derivedSyncDirective","then","content","tempTemplateAttrs","beforeTemplateLinkNode","linkRootElement","$$destroyed","oldClasses","delayedNodeLinkFn","ignoreChildLinkFn","diff","what","previousDirective","wrapModuleNameIfDefined","moduleName","text","interpolateFn","textInterpolateCompileFn","templateNode","templateNodeParent","hasCompileParent","$$addBindingClass","textInterpolateLinkFn","$$addBindingInfo","expressions","interpolateFnWatchAction","wrapper","getTrustedContext","attrNormalizedName","HTML","RESOURCE_URL","allOrNothing","trustedContext","attrInterpolatePreLinkFn","$$observers","newValue","$$inter","$$scope","oldValue","$updateClass","elementsToRemove","newNode","firstElementToRemove","removeCount","j2","replaceChild","hasData","expando","k","kk","annotation","newScope","onNewScopeDestroyed","lastValue","parentGet","parentSet","compare","$observe","literal","assign","parentValueWatch","parentValue","$stateful","unwatch","$watchCollection","attributesToCopy","$normalize","$addClass","classVal","$removeClass","newClasses","toAdd","tokenDifference","toRemove","writeAttr","booleanKey","aliasedKey","observer","trimmedSrcset","srcPattern","rawUris","nbrUrisWith2parts","floor","innerIdx","lastTuple","removeAttr","listeners","startSymbol","endSymbol","binding","isolated","noTemplate","str1","str2","values","tokens1","tokens2","token","jqNodes","globals","register","this.register","allowGlobals","this.allowGlobals","addIdentifier","expression","later","ident","$controllerMinErr","controllerPrototype","exception","cause","serializeValue","v","toISOString","ngParamSerializer","params","jQueryLikeParamSerializer","serialize","toSerialize","topLevel","defaultHttpResponseTransform","headers","tempData","JSON_PROTECTION_PREFIX","contentType","jsonStart","JSON_START","JSON_ENDS","parseHeaders","line","headerVal","headerKey","headersGetter","headersObj","transformData","status","fns","defaults","transformResponse","transformRequest","d","common","CONTENT_TYPE_APPLICATION_JSON","patch","xsrfCookieName","xsrfHeaderName","paramSerializer","useApplyAsync","this.useApplyAsync","interceptorFactories","interceptors","requestConfig","response","resp","reject","executeHeaderFns","headerContent","processedHeaders","headerFn","header","mergeHeaders","defHeaders","reqHeaders","defHeaderName","lowercaseDefHeaderName","reqHeaderName","chain","serverRequest","reqData","withCredentials","sendReq","promise","when","reversedInterceptors","interceptor","request","requestError","responseError","thenFn","rejectFn","success","promise.success","promise.error","done","headersString","statusText","resolveHttpPromise","resolvePromise","$applyAsync","$$phase","deferred","resolve","resolvePromiseWithResult","removePendingReq","pendingRequests","cachedResp","buildUrl","defaultCache","xsrfValue","urlIsSameOrigin","timeout","responseType","serializedParams","interceptorFactory","createShortMethods","createShortMethodsWithData","createXhr","XMLHttpRequest","createHttpBackend","callbacks","$browserDefer","rawDocument","jsonpReq","callbackId","async","body","called","addEventListener","timeoutRequest","jsonpDone","xhr","abort","completeRequest","open","setRequestHeader","onload","xhr.onload","responseText","urlResolve","protocol","getAllResponseHeaders","onerror","onabort","send","this.startSymbol","this.endSymbol","escape","ch","unescapeText","escapedStartRegexp","escapedEndRegexp","mustHaveExpression","parseStringifyInterceptor","getTrusted","$interpolateMinErr","interr","endIndex","parseFns","textLength","expressionPositions","startSymbolLength","exp","endSymbolLength","throwNoconcat","compute","interpolationFn","$$watchDelegate","$watchGroup","interpolateFnWatcher","oldValues","currValue","$interpolate.startSymbol","$interpolate.endSymbol","interval","count","invokeApply","hasParams","setInterval","clearInterval","iteration","skipApply","$$intervalId","tick","notify","intervals","interval.cancel","NUMBER_FORMATS","DECIMAL_SEP","GROUP_SEP","PATTERNS","minInt","minFrac","maxFrac","posPre","posSuf","negPre","negSuf","gSize","lgSize","CURRENCY_SYM","DATETIME_FORMATS","MONTH","SHORTMONTH","DAY","SHORTDAY","AMPMS","medium","fullDate","longDate","mediumDate","shortDate","mediumTime","shortTime","ERANAMES","ERAS","pluralCat","num","encodePath","segments","parseAbsoluteUrl","absoluteUrl","locationObj","parsedUrl","$$protocol","$$host","hostname","$$port","port","DEFAULT_PORTS","parseAppUrl","relativeUrl","prefixed","$$path","pathname","$$search","search","$$hash","beginsWith","begin","whole","trimEmptyHash","stripFile","lastIndexOf","LocationHtml5Url","appBase","basePrefix","$$html5","appBaseNoFile","$$parse","this.$$parse","pathUrl","$locationMinErr","$$compose","this.$$compose","$$url","$$absUrl","$$parseLinkUrl","this.$$parseLinkUrl","relHref","appUrl","prevAppUrl","rewrittenUrl","LocationHashbangUrl","hashPrefix","withoutBaseUrl","withoutHashUrl","windowsFilePathExp","base","firstPathSegmentMatch","LocationHashbangInHtml5Url","locationGetter","property","locationGetterSetter","preprocess","html5Mode","requireBase","rewriteLinks","this.hashPrefix","this.html5Mode","setBrowserUrlWithFallback","oldUrl","oldState","$$state","afterLocationChange","$broadcast","absUrl","LocationMode","initialUrl","IGNORE_URI_REGEXP","ctrlKey","metaKey","shiftKey","which","button","target","absHref","preventDefault","initializing","newUrl","newState","$digest","$locationWatch","currentReplace","$$replace","urlOrStateChanged","debug","debugEnabled","this.debugEnabled","flag","formatError","Error","sourceURL","consoleLog","console","logFn","log","hasApply","arg1","arg2","warn","ensureSafeMemberName","fullExpression","$parseMinErr","ensureSafeObject","children","ensureSafeFunction","CALL","APPLY","BIND","ifDefined","plusFn","r","findConstantAndWatchExpressions","ast","allConstants","argsToWatch","AST","Program","expr","Literal","toWatch","UnaryExpression","argument","BinaryExpression","left","right","LogicalExpression","ConditionalExpression","alternate","consequent","Identifier","MemberExpression","object","computed","CallExpression","callee","AssignmentExpression","ArrayExpression","ObjectExpression","properties","ThisExpression","getInputs","lastExpression","isAssignable","assignableAST","NGValueParameter","operator","isLiteral","ASTCompiler","astBuilder","ASTInterpreter","setter","setValue","fullExp","propertyObj","isPossiblyDangerousMemberName","getValueOf","objectValueOf","cacheDefault","cacheExpensive","expressionInputDirtyCheck","oldValueOfValue","inputsWatchDelegate","objectEquality","parsedExpression","prettyPrintExpression","inputExpressions","inputs","lastResult","oldInputValueOf","expressionInputWatch","newInputValue","oldInputValueOfValues","oldInputValues","expressionInputsWatch","changed","oneTimeWatchDelegate","oneTimeWatch","oneTimeListener","old","$$postDigest","oneTimeLiteralWatchDelegate","isAllDefined","allDefined","constantWatchDelegate","constantWatch","constantListener","addInterceptor","interceptorFn","watchDelegate","regularInterceptedExpression","oneTimeInterceptedExpression","$parseOptions","expensiveChecks","$parseOptionsExpensive","oneTime","cacheKey","parseOptions","lexer","Lexer","parser","Parser","qFactory","nextTick","exceptionHandler","callOnce","resolveFn","Promise","simpleBind","scheduleProcessQueue","processScheduled","pending","Deferred","$qMinErr","TypeError","onFulfilled","onRejected","progressBack","catch","finally","handleCallback","$$reject","$$resolve","progress","makePromise","resolved","isResolved","callbackOutput","errback","$Q","Q","resolver","all","promises","results","flush","taskQueue","task","taskCount","queueFn","asyncFn","cancelLastRAF","rafFn","cancelQueueFn","requestAnimationFrame","webkitRequestAnimationFrame","cancelAnimationFrame","webkitCancelAnimationFrame","webkitCancelRequestAnimationFrame","rafSupported","timer","supported","createChildScopeClass","ChildScope","$$watchers","$$nextSibling","$$childHead","$$childTail","$$listeners","$$listenerCount","$$watchersCount","$id","$$ChildScope","TTL","$rootScopeMinErr","lastDirtyWatch","applyAsyncId","digestTtl","this.digestTtl","destroyChildScope","$event","currentScope","Scope","$parent","$$prevSibling","$root","beginPhase","phase","incrementWatchersCount","current","decrementListenerCount","initWatchVal","flushApplyAsync","applyAsyncQueue","scheduleApplyAsync","isolate","child","watchExp","watcher","last","eq","deregisterWatch","watchExpressions","watchGroupAction","changeReactionScheduled","firstRun","newValues","deregisterFns","shouldCall","deregisterWatchGroup","unwatchFn","watchGroupSubAction","$watchCollectionInterceptor","_value","bothNaN","newItem","oldItem","internalArray","oldLength","changeDetected","newLength","internalObject","veryOldValue","trackVeryOldValue","changeDetector","initRun","$watchCollectionAction","watch","watchers","dirty","ttl","watchLog","logIdx","asyncTask","asyncQueue","$eval","msg","next","postDigestQueue","eventName","this.$watchGroup","$applyAsyncExpression","namedListeners","indexOfListener","$emit","targetScope","listenerArgs","$$asyncQueue","$$postDigestQueue","$$applyAsyncQueue","sanitizeUri","uri","isImage","regex","normalizedVal","adjustMatcher","matcher","$sceMinErr","escapeForRegexp","adjustMatchers","matchers","adjustedMatchers","SCE_CONTEXTS","resourceUrlWhitelist","resourceUrlBlacklist","this.resourceUrlWhitelist","this.resourceUrlBlacklist","matchUrl","generateHolderType","Base","holderType","trustedValue","$$unwrapTrustedValue","this.$$unwrapTrustedValue","holderType.prototype.valueOf","holderType.prototype.toString","htmlSanitizer","trustedValueHolderBase","byType","CSS","URL","JS","trustAs","Constructor","maybeTrusted","allowed","this.enabled","sce","isEnabled","sce.isEnabled","sce.getTrusted","parseAs","sce.parseAs","enumValue","lName","eventSupport","android","userAgent","navigator","boxee","vendorPrefix","vendorRegex","bodyStyle","transitions","animations","webkitTransition","webkitAnimation","pushState","hasEvent","divElm","handleRequestFn","tpl","ignoreRequestError","totalPendingRequests","getTrustedResourceUrl","transformer","httpOptions","handleError","testability","testability.findBindings","opt_exactMatch","getElementsByClassName","matches","dataBinding","bindingName","testability.findModels","prefixes","attributeEquals","testability.getLocation","testability.setLocation","testability.whenStable","deferreds","$$timeoutId","timeout.cancel","urlParsingNode","requestUrl","originUrl","$$CookieReader","safeDecodeURIComponent","lastCookies","lastCookieString","cookieArray","cookie","currentCookieString","filters","suffix","currencyFilter","dateFilter","filterFilter","jsonFilter","limitToFilter","lowercaseFilter","numberFilter","orderByFilter","uppercaseFilter","comparator","matchAgainstAnyProp","getTypeForFilter","expressionType","predicateFn","createPredicateFn","shouldMatchPrimitives","actual","expected","item","deepCompare","dontMatchWholeObject","actualType","expectedType","expectedVal","matchAnyProperty","actualVal","$locale","formats","amount","currencySymbol","fractionSize","formatNumber","number","groupSep","decimalSep","isNegative","abs","isInfinity","Infinity","isFinite","numStr","formatedText","hasExponent","toFixed","parseFloat","fractionLen","min","round","fraction","lgroup","group","padNumber","digits","neg","dateGetter","dateStrGetter","shortForm","getFirstThursdayOfYear","year","dayOfWeekOnFirst","getDay","weekGetter","firstThurs","getFullYear","thisThurs","getMonth","getDate","eraGetter","jsonStringToDate","string","R_ISO8601_STR","tzHour","tzMin","dateSetter","setUTCFullYear","setFullYear","timeSetter","setUTCHours","setHours","m","s","ms","format","NUMBER_STRING","DATE_FORMATS_SPLIT","dateTimezoneOffset","DATE_FORMATS","spacing","limit","processPredicates","sortPredicate","reverseOrder","map","predicate","descending","predicates","compareValues","getComparisonObject","predicateValues","doComparison","v1","v2","ngDirective","FormController","controls","parentForm","$$parentForm","nullFormCtrl","$error","$$success","$pending","$name","$dirty","$pristine","$valid","$invalid","$submitted","$addControl","$rollbackViewValue","form.$rollbackViewValue","control","$commitViewValue","form.$commitViewValue","form.$addControl","$$renameControl","form.$$renameControl","newName","oldName","$removeControl","form.$removeControl","$setValidity","addSetValidityMethod","ctrl","set","unset","$setDirty","form.$setDirty","PRISTINE_CLASS","DIRTY_CLASS","$setPristine","form.$setPristine","setClass","SUBMITTED_CLASS","$setUntouched","form.$setUntouched","$setSubmitted","form.$setSubmitted","stringBasedInputType","$formatters","$isEmpty","baseInputType","composing","ev","ngTrim","$viewValue","$$hasNativeValidators","$setViewValue","deferListener","origValue","keyCode","$render","ctrl.$render","createDateParser","mapping","iso","ISO_DATE_REGEXP","yyyy","MM","dd","HH","getHours","mm","ss","getSeconds","sss","getMilliseconds","part","NaN","createDateInputType","parseDate","dynamicDateInputType","isValidDate","parseObservedDateValue","badInputChecker","$options","previousDate","$$parserName","$parsers","parsedDate","$ngModelMinErr","ngMin","minVal","$validators","ctrl.$validators.min","$validate","ngMax","maxVal","ctrl.$validators.max","validity","VALIDITY_STATE_PROPERTY","badInput","typeMismatch","parseConstantExpr","parseFn","classDirective","arrayDifference","arrayClasses","digestClassCounts","classCounts","classesToUpdate","ngClassWatchAction","$index","old$index","mod","cachedToggleClass","switchValue","classCache","toggleValidationCss","validationErrorKey","isValid","VALID_CLASS","INVALID_CLASS","setValidity","isObjectEmpty","PENDING_CLASS","combinedState","REGEX_STRING_REGEXP","documentMode","isActive_","active","Function","name_","el","full","major","minor","dot","codeName","JQLite._data","MOUSE_EVENT_MAP","mouseleave","mouseenter","optgroup","tbody","tfoot","colgroup","caption","thead","th","td","ready","trigger","fired","removeData","jqLiteHasData","removeAttribute","css","NODE_TYPE_ATTRIBUTE","lowercasedName","specified","getNamedItem","ret","getText","$dv","multiple","selected","nodeCount","jqLiteOn","types","related","relatedTarget","contains","one","onFn","replaceNode","insertBefore","contentDocument","prepend","wrapNode","detach","after","newElement","toggleClass","condition","classCondition","nextElementSibling","getElementsByTagName","extraParameters","dummyEvent","handlerArgs","eventFnsCopy","arg3","unbind","FN_ARG_SPLIT","FN_ARG","argDecl","underscore","$animateMinErr","AnimateRunner","end","resume","pause","complete","pass","fail","postDigestElements","addRemoveClassesPostDigest","add","existing","pin","domOperation","from","to","$$registeredAnimations","classNameFilter","this.classNameFilter","$$classNameFilter","reservedRegex","NG_ANIMATE_CLASSNAME","domInsert","parentElement","afterElement","afterNode","ELEMENT_NODE","previousElementSibling","runner","enter","move","leave","addclass","animate","tempClasses","APPLICATION_JSON","$interpolateMinErr.throwNoconcat","$interpolateMinErr.interr","PATH_MATCH","locationPrototype","paramValue","Location","Location.prototype.state","OPERATORS","ESCAPE","lex","tokens","readString","peek","readNumber","isIdent","readIdent","is","isWhitespace","ch2","ch3","op2","op3","op1","throwError","chars","isExpOperator","start","colStr","peekCh","quote","rawString","hex","String","fromCharCode","rep","ExpressionStatement","Property","program","expressionStatement","expect","filterChain","assignment","ternary","logicalOR","consume","logicalAND","equality","relational","additive","multiplicative","unary","primary","arrayDeclaration","constants","parseArguments","baseExpression","peekToken","kind","e1","e2","e3","e4","peekAhead","t","nextId","vars","own","assignable","stage","computing","recurse","generateFunction","fnKey","intoId","return_","watchId","fnString","USE","STRICT","filterPrefix","watchFns","varsPrefix","section","nameId","recursionFn","skipWatchIdCheck","if_","lazyAssign","computedMember","lazyRecurse","plus","not","getHasOwnProperty","nonComputedMember","addEnsureSafeObject","notNull","addEnsureSafeMemberName","addEnsureSafeFunction","member","filterName","defaultValue","stringEscapeRegex","stringEscapeFn","c","charCodeAt","skip","init","fn.assign","rhs","lhs","unary+","unary-","unary!","binary+","binary-","binary*","binary/","binary%","binary===","binary!==","binary==","binary!=","binary<","binary>","binary<=","binary>=","binary&&","binary||","ternary?:","astCompiler","yy","y","MMMM","MMM","M","H","hh","EEEE","EEE","ampmGetter","Z","timeZoneGetter","zone","paddedZone","ww","w","G","GG","GGG","GGGG","longEraGetter","xlinkHref","propName","defaultLinkFn","normalized","ngBooleanAttrWatchAction","htmlAttr","ngAttrAliasWatchAction","nullFormRenameControl","formDirectiveFactory","isNgForm","ngFormCompile","formElement","nameAttr","ngFormPreLink","handleFormSubmission","parentFormCtrl","URL_REGEXP","EMAIL_REGEXP","NUMBER_REGEXP","DATE_REGEXP","DATETIMELOCAL_REGEXP","WEEK_REGEXP","MONTH_REGEXP","TIME_REGEXP","inputType","textInputType","weekParser","isoWeek","existingDate","week","hours","seconds","milliseconds","addDays","numberInputType","urlInputType","ctrl.$validators.url","modelValue","viewValue","emailInputType","email","ctrl.$validators.email","radioInputType","checked","checkboxInputType","trueValue","ngTrueValue","falseValue","ngFalseValue","ctrl.$isEmpty","ctrls","CONSTANT_VALUE_REGEXP","tplAttr","ngValueConstantLink","ngValueLink","valueWatchAction","$compile","ngBindCompile","templateElement","ngBindLink","ngBindWatchAction","ngBindTemplateCompile","ngBindTemplateLink","ngBindHtmlCompile","tElement","ngBindHtmlGetter","ngBindHtmlWatch","getStringValue","ngBindHtmlLink","ngBindHtmlWatchAction","getTrustedHtml","$viewChangeListeners","forceAsyncEvents","ngEventHandler","previousElements","ngIfWatchAction","srcExp","onloadExp","autoScrollExp","autoscroll","changeCounter","previousElement","currentElement","cleanupLastIncludeContent","ngIncludeWatchAction","afterAnimation","thisChangeId","namespaceAdaptedClone","trimValues","NgModelController","$modelValue","$$rawModelValue","$asyncValidators","$untouched","$touched","parsedNgModel","parsedNgModelAssign","ngModelGet","ngModelSet","pendingDebounce","parserValid","$$setOptions","this.$$setOptions","getterSetter","invokeModelGetter","invokeModelSetter","$$$p","this.$isEmpty","currentValidationRunId","this.$setPristine","this.$setDirty","this.$setUntouched","UNTOUCHED_CLASS","TOUCHED_CLASS","$setTouched","this.$setTouched","this.$rollbackViewValue","$$lastCommittedViewValue","this.$validate","prevValid","prevModelValue","allowInvalid","$$runValidators","allValid","$$writeModelToScope","this.$$runValidators","doneCallback","processSyncValidators","syncValidatorsValid","validator","processAsyncValidators","validatorPromises","validationDone","localValidationRunId","processParseErrors","errorKey","this.$commitViewValue","$$parseAndValidate","this.$$parseAndValidate","this.$$writeModelToScope","this.$setViewValue","updateOnDefault","$$debounceViewValueCommit","this.$$debounceViewValueCommit","debounceDelay","debounce","ngModelWatch","formatters","ngModelCompile","ngModelPreLink","modelCtrl","formCtrl","ngModelPostLink","updateOn","DEFAULT_REGEXP","that","ngOptionsMinErr","NG_OPTIONS_REGEXP","parseOptionsExpression","optionsExp","selectElement","Option","selectValue","label","disabled","getOptionValuesKeys","optionValues","optionValuesKeys","keyName","itemKey","valueName","selectAs","trackBy","viewValueFn","trackByFn","getTrackByValueFn","getHashOfValue","getTrackByValue","getLocals","displayFn","groupByFn","disableWhenFn","valuesFn","getWatchables","watchedArray","optionValuesLength","disableWhen","getOptions","optionItems","selectValueMap","optionItem","getOptionFromViewValue","getViewValueFromOption","optionTemplate","optGroupTemplate","updateOptionElement","addOrReuseElement","removeExcessElements","skipEmptyAndUnknownOptions","emptyOption_","emptyOption","unknownOption_","unknownOption","updateOptions","previousValue","selectCtrl","readValue","groupMap","providedEmptyOption","updateOption","optionElement","groupElement","currentOptionElement","ngModelCtrl","nextValue","ngModelCtrl.$isEmpty","writeValue","selectCtrl.writeValue","selectCtrl.readValue","selectedValues","selections","selectedOption","BRACE","IS_WHEN","updateElementText","newText","numberExp","whenExp","whens","whensExpFns","braceReplacement","watchRemover","lastCount","attributeName","tmpMatch","whenKey","ngPluralizeWatchAction","countIsNaN","whenExpFn","ngRepeatMinErr","updateScope","valueIdentifier","keyIdentifier","arrayLength","$first","$last","$middle","$odd","$even","ngRepeatCompile","ngRepeatEndComment","aliasAs","trackByExp","trackByExpGetter","trackByIdExpFn","trackByIdArrayFn","trackByIdObjFn","hashFnLocals","ngRepeatLink","lastBlockMap","ngRepeatAction","previousNode","nextNode","nextBlockMap","collectionLength","trackById","collectionKeys","nextBlockOrder","trackByIdFn","blockKey","ngRepeatTransclude","ngShowWatchAction","NG_HIDE_CLASS","NG_HIDE_IN_PROGRESS_CLASS","ngHideWatchAction","ngStyleWatchAction","newStyles","oldStyles","ngSwitchController","cases","selectedTranscludes","selectedElements","previousLeaveAnimations","selectedScopes","spliceFactory","ngSwitchWatchAction","selectedTransclude","caseElement","selectedScope","anchor","noopNgModelController","SelectController","optionsMap","renderUnknownOption","self.renderUnknownOption","unknownVal","removeUnknownOption","self.removeUnknownOption","self.readValue","self.writeValue","hasOption","addOption","self.addOption","removeOption","self.removeOption","self.hasOption","ngModelCtrl.$render","lastView","lastViewRef","selectMultipleWatch","chromeHack","selectCtrlName","interpolateWatchAction","ctrl.$validators.required","patternExp","ctrl.$validators.pattern","intVal","ctrl.$validators.maxlength","ctrl.$validators.minlength","$$csp","head"]
}
diff --git a/libs/bower_components/angular/bower.json b/libs/bower_components/angular/bower.json
index 4689d923d1..25dbde948b 100644
--- a/libs/bower_components/angular/bower.json
+++ b/libs/bower_components/angular/bower.json
@@ -1,6 +1,6 @@
{
"name": "angular",
- "version": "1.2.28",
+ "version": "1.4.3",
"main": "./angular.js",
"ignore": [],
"dependencies": {
diff --git a/libs/bower_components/angular/index.js b/libs/bower_components/angular/index.js
new file mode 100644
index 0000000000..5c1aafcca2
--- /dev/null
+++ b/libs/bower_components/angular/index.js
@@ -0,0 +1,2 @@
+require('./angular');
+module.exports = angular;
diff --git a/libs/bower_components/angular/package.json b/libs/bower_components/angular/package.json
index 40cf22288c..28ac057ca6 100644
--- a/libs/bower_components/angular/package.json
+++ b/libs/bower_components/angular/package.json
@@ -1,8 +1,8 @@
{
"name": "angular",
- "version": "1.2.28",
+ "version": "1.4.3",
"description": "HTML enhanced for web apps",
- "main": "angular.js",
+ "main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
diff --git a/misc/others/iframeWidget_localhost.php b/misc/others/iframeWidget_localhost.php
index 73bfc5c59b..a124b9767a 100644
--- a/misc/others/iframeWidget_localhost.php
+++ b/misc/others/iframeWidget_localhost.php
@@ -2,7 +2,7 @@
use Piwik\FrontController;
use Piwik\Url;
use Piwik\UrlHelper;
-use Piwik\WidgetsList;
+use Piwik\Widget\WidgetsList;
exit;
$date = date('Y-m-d');
@@ -34,15 +34,28 @@ require_once PIWIK_INCLUDE_PATH . "/index.php";
require_once PIWIK_INCLUDE_PATH . "/core/API/Request.php";
FrontController::getInstance()->init();
-$widgets = WidgetsList::get();
-foreach ($widgets as $category => $widgetsInCategory) {
+$widgets = WidgetsList::get()->getWidgetConfigs();
+$widgetCategoriesHandled = array();
+foreach ($widgets as $widgetConfig) {
+ $category = $widgetConfig->getCategoryId();
+
+ if (!empty($widgetCategoriesHandled[$category])) {
+ continue;
+ }
+ $widgetCategoriesHandled[$category] = true;
+
echo '<h2>' . $category . '</h2>';
- foreach ($widgetsInCategory as $widget) {
- echo '<h3>' . $widget['name'] . '</h3>';
+
+ foreach ($widgets as $widget) {
+ if ($category !== $widget->getCategoryId()) {
+ continue;
+ }
+
+ echo '<h3>' . \Piwik\Piwik::translate($widget->getName()) . '</h3>';
$widgetUrl = UrlHelper::getArrayFromQueryString($url);
- $widgetUrl['moduleToWidgetize'] = $widget['parameters']['module'];
- $widgetUrl['actionToWidgetize'] = $widget['parameters']['action'];
- $parameters = $widget['parameters'];
+ $widgetUrl['moduleToWidgetize'] = $widget->getModule();
+ $widgetUrl['actionToWidgetize'] = $widget->getAction();
+ $parameters = $widget->getParameters();
unset($parameters['module']);
unset($parameters['action']);
foreach ($parameters as $name => $value) {
@@ -54,7 +67,7 @@ foreach ($widgets as $category => $widgetsInCategory) {
$widgetUrl = Url::getQueryStringFromParameters($widgetUrl);
echo '<div id="widgetIframe"><iframe width="500" height="350"
- src="' . $widgetUrl . '" scrolling="no" frameborder="0" marginheight="0" marginwidth="0"></iframe></div>';
+ src="' . $widgetUrl . '" scrolling="no" frameborder="0" marginheight="0" marginwidth="0"></iframe></div>';
}
}
diff --git a/plugins/API/API.php b/plugins/API/API.php
index bb287f9b7a..528d17e8cf 100644
--- a/plugins/API/API.php
+++ b/plugins/API/API.php
@@ -10,7 +10,9 @@ namespace Piwik\Plugins\API;
use Piwik\API\Proxy;
use Piwik\API\Request;
-use Piwik\Columns\Dimension;
+use Piwik\Cache;
+use Piwik\CacheId;
+use Piwik\Category\CategoryList;
use Piwik\Common;
use Piwik\Config;
use Piwik\Container\StaticContainer;
@@ -28,6 +30,7 @@ use Piwik\Plugins\CoreAdminHome\CustomLogo;
use Piwik\Translation\Translator;
use Piwik\Measurable\Type\TypeManager;
use Piwik\Version;
+use Piwik\Widget\WidgetsList;
require_once PIWIK_INCLUDE_PATH . '/core/Config.php';
@@ -131,83 +134,20 @@ class API extends \Piwik\Plugin\API
$isNotAnonymous = !Piwik::isUserIsAnonymous();
- $segments = array();
- foreach (Dimension::getAllDimensions() as $dimension) {
- foreach ($dimension->getSegments() as $segment) {
- if ($segment->isRequiresAtLeastViewAccess()) {
- $segment->setPermission($isNotAnonymous);
- }
+ $sites = (is_array($idSites) ? implode('.', $idSites) : (int) $idSites);
+ $cache = Cache::getTransientCache();
+ $cachKey = 'API.getSegmentsMetadata' . $sites . '_' . (int) $_hideImplementationData . '_' . (int) $isNotAnonymous;
+ $cachKey = CacheId::pluginAware($cachKey);
- $segments[] = $segment->toArray();
- }
+ if ($cache->contains($cachKey)) {
+ return $cache->fetch($cachKey);
}
- /**
- * Triggered when gathering all available segment dimensions.
- *
- * This event can be used to make new segment dimensions available.
- *
- * **Example**
- *
- * public function getSegmentsMetadata(&$segments, $idSites)
- * {
- * $segments[] = array(
- * 'type' => 'dimension',
- * 'category' => Piwik::translate('General_Visit'),
- * 'name' => 'General_VisitorIP',
- * 'segment' => 'visitIp',
- * 'acceptedValues' => '13.54.122.1, etc.',
- * 'sqlSegment' => 'log_visit.location_ip',
- * 'sqlFilter' => array('Piwik\IP', 'P2N'),
- * 'permission' => $isAuthenticatedWithViewAccess,
- * );
- * }
- *
- * @param array &$dimensions The list of available segment dimensions. Append to this list to add
- * new segments. Each element in this list must contain the
- * following information:
- *
- * - **type**: Either `'metric'` or `'dimension'`. `'metric'` means
- * the value is a numeric and `'dimension'` means it is
- * a string. Also, `'metric'` values will be displayed
- * under **Visit (metrics)** in the Segment Editor.
- * - **category**: The segment category name. This can be an existing
- * segment category visible in the segment editor.
- * - **name**: The pretty name of the segment. Can be a translation token.
- * - **segment**: The segment name, eg, `'visitIp'` or `'searches'`.
- * - **acceptedValues**: A string describing one or two exacmple values, eg
- * `'13.54.122.1, etc.'`.
- * - **sqlSegment**: The table column this segment will segment by.
- * For example, `'log_visit.location_ip'` for the
- * **visitIp** segment.
- * - **sqlFilter**: A PHP callback to apply to segment values before
- * they are used in SQL.
- * - **permission**: True if the current user has view access to this
- * segment, false if otherwise.
- * @param array $idSites The list of site IDs we're getting the available segments
- * for. Some segments (such as Goal segments) depend on the
- * site.
- */
- Piwik::postEvent('API.getSegmentDimensionMetadata', array(&$segments, $idSites));
-
- foreach ($segments as &$segment) {
- $segment['name'] = Piwik::translate($segment['name']);
- $segment['category'] = Piwik::translate($segment['category']);
-
- if ($_hideImplementationData) {
- unset($segment['sqlFilter']);
- unset($segment['sqlFilterValue']);
- unset($segment['sqlSegment']);
-
- if (isset($segment['suggestedValuesCallback'])
- && !is_string($segment['suggestedValuesCallback'])
- ) {
- unset($segment['suggestedValuesCallback']);
- }
- }
- }
+ $metadata = new SegmentMetadata();
+ $segments = $metadata->getSegmentsMetadata($idSites, $_hideImplementationData, $isNotAnonymous);
+
+ $cache->save($cachKey, $segments);
- usort($segments, array($this, 'sortSegments'));
return $segments;
}
@@ -228,32 +168,6 @@ class API extends \Piwik\Plugin\API
return $values;
}
- private function sortSegments($row1, $row2)
- {
- $customVarCategory = Piwik::translate('CustomVariables_CustomVariables');
-
- $columns = array('type', 'category', 'name', 'segment');
- foreach ($columns as $column) {
- // Keep segments ordered alphabetically inside categories..
- $type = -1;
- if ($column == 'name') $type = 1;
-
- $compare = $type * strcmp($row1[$column], $row2[$column]);
-
- // hack so that custom variables "page" are grouped together in the doc
- if ($row1['category'] == $customVarCategory
- && $row1['category'] == $row2['category']
- ) {
- $compare = strcmp($row1['segment'], $row2['segment']);
- return $compare;
- }
- if ($compare != 0) {
- return $compare;
- }
- }
- return $compare;
- }
-
/**
* Returns the url to application logo (~280x110px)
*
@@ -360,6 +274,41 @@ class API extends \Piwik\Plugin\API
}
/**
+ * Get a list of all pages that shall be shown in a Piwik UI including a list of all widgets that shall
+ * be shown within each page.
+ *
+ * @param int $idSite
+ * @return array
+ */
+ public function getReportPagesMetadata($idSite)
+ {
+ Piwik::checkUserHasViewAccess($idSite);
+
+ $widgetsList = WidgetsList::get();
+ $categoryList = CategoryList::get();
+ $metadata = new WidgetMetadata();
+
+ return $metadata->getPagesMetadata($categoryList, $widgetsList);
+ }
+
+ /**
+ * Get a list of all widgetizable widgets.
+ *
+ * @param int $idSite
+ * @return array
+ */
+ public function getWidgetMetadata($idSite)
+ {
+ Piwik::checkUserHasViewAccess($idSite);
+
+ $widgetsList = WidgetsList::get();
+ $categoryList = CategoryList::get();
+ $metadata = new WidgetMetadata();
+
+ return $metadata->getWidgetMetadata($categoryList, $widgetsList);
+ }
+
+ /**
* Get a combined report of the *.get API methods.
*/
public function get($idSite, $period, $date, $segment = false, $columns = false)
@@ -674,9 +623,9 @@ class API extends \Piwik\Plugin\API
{
// If you update this, also update flattenVisitorDetailsArray
$segmentsNeedActionsInfo = array('visitConvertedGoalId',
- 'pageUrl', 'pageTitle', 'siteSearchKeyword',
- 'entryPageTitle', 'entryPageUrl', 'exitPageTitle', 'exitPageUrl',
- 'outlinkUrl', 'downloadUrl'
+ 'pageUrl', 'pageTitle', 'siteSearchKeyword',
+ 'entryPageTitle', 'entryPageUrl', 'exitPageTitle', 'exitPageUrl',
+ 'outlinkUrl', 'downloadUrl'
);
$isCustomVariablePage = stripos($segmentName, 'customVariablePage') !== false;
$isEventSegment = stripos($segmentName, 'event') !== false;
diff --git a/plugins/API/ProcessedReport.php b/plugins/API/ProcessedReport.php
index 9c6893057d..8a9a96b537 100644
--- a/plugins/API/ProcessedReport.php
+++ b/plugins/API/ProcessedReport.php
@@ -23,9 +23,11 @@ use Piwik\Metrics\Formatter;
use Piwik\Period;
use Piwik\Piwik;
use Piwik\Plugin\Report;
+use Piwik\Plugin\Reports;
use Piwik\Site;
use Piwik\Timer;
use Piwik\Url;
+use Piwik\Category\Category;
class ProcessedReport
{
@@ -166,77 +168,14 @@ class ProcessedReport
$availableReports = array();
- foreach (Report::getAllReports() as $report) {
+ $reports = new Reports();
+ foreach ($reports->getAllReports() as $report) {
$report->configureReportMetadata($availableReports, $parameters);
}
- /**
- * Triggered when gathering metadata for all available reports.
- *
- * Plugins that define new reports should use this event to make them available in via
- * the metadata API. By doing so, the report will become available in scheduled reports
- * as well as in the Piwik Mobile App. In fact, any third party app that uses the metadata
- * API will automatically have access to the new report.
- *
- * @param string &$availableReports The list of available reports. Append to this list
- * to make a report available.
- *
- * Every element of this array must contain the following
- * information:
- *
- * - **category**: A translated string describing the report's category.
- * - **name**: The translated display title of the report.
- * - **module**: The plugin of the report.
- * - **action**: The API method that serves the report.
- *
- * The following information is optional:
- *
- * - **dimension**: The report's [dimension](/guides/all-about-analytics-data#dimensions) if any.
- * - **metrics**: An array mapping metric names with their display names.
- * - **metricsDocumentation**: An array mapping metric names with their
- * translated documentation.
- * - **processedMetrics**: The array of metrics in the report that are
- * calculated using existing metrics. Can be set to
- * `false` if the report contains no processed
- * metrics.
- * - **order**: The order of the report in the list of reports
- * with the same category.
- *
- * @param array $parameters Contains the values of the sites and period we are
- * getting reports for. Some reports depend on this data.
- * For example, Goals reports depend on the site IDs being
- * requested. Contains the following information:
- *
- * - **idSites**: The array of site IDs we are getting reports for.
- * - **period**: The period type, eg, `'day'`, `'week'`, `'month'`,
- * `'year'`, `'range'`.
- * - **date**: A string date within the period or a date range, eg,
- * `'2013-01-01'` or `'2012-01-01,2013-01-01'`.
- *
- * TODO: put dimensions section in all about analytics data
- * @deprecated since 2.5.0 Use Report Classes instead.
- * @ignore
- */
- Piwik::postEvent('API.getReportMetadata', array(&$availableReports, $parameters));
-
- // TODO we can remove this one once we remove API.getReportMetadata event (except hideMetricsDoc)
foreach ($availableReports as &$availableReport) {
- // can be removed once we remove hook API.getReportMetadata
- if (!isset($availableReport['metrics'])) {
- $availableReport['metrics'] = Metrics::getDefaultMetrics();
- }
- // can be removed once we remove hook API.getReportMetadata
- if (!isset($availableReport['processedMetrics'])) {
- $availableReport['processedMetrics'] = Metrics::getDefaultProcessedMetrics();
- }
-
- if ($hideMetricsDoc) // remove metric documentation if it's not wanted
- {
+ if ($hideMetricsDoc) {
unset($availableReport['metricsDocumentation']);
- } else if (!isset($availableReport['metricsDocumentation'])) {
- // set metric documentation to default if it's not set
- // can be removed once we remove hook API.getReportMetadata
- $availableReport['metricsDocumentation'] = Metrics::getDefaultMetricsDocumentation();
}
}
@@ -270,6 +209,9 @@ class ProcessedReport
$columnsToRemove = $this->getColumnsToRemove();
foreach ($availableReports as &$availableReport) {
+ $availableReport['category'] = Piwik::translate($availableReport['category']);
+ $availableReport['subcategory'] = Piwik::translate($availableReport['subcategory']);
+
// Ensure all metrics have a translation
$metrics = $availableReport['metrics'];
$cleanedMetrics = array();
@@ -349,32 +291,8 @@ class ProcessedReport
*/
private static function sortReports($a, $b)
{
- static $order = null;
- if (is_null($order)) {
- $order = array();
- foreach (Report::$orderOfReports as $category) {
- $order[] = Piwik::translate($category);
- }
- }
-
- $posA = array_search($a['category'], $order);
- $posB = array_search($b['category'], $order);
-
- if ($posA === false && $posB === false) {
- return strcmp($a['category'], $b['category']);
- } elseif ($posA === false) {
- return 1;
- } elseif ($posB === false) {
- return -1;
- }
-
- $category = strcmp($posA, $posB);
-
- if ($category == 0) {
- return (@$a['order'] < @$b['order'] ? -1 : 1);
- }
-
- return $category;
+ $reports = new Reports();
+ return $reports->compareCategories($a['category'], $a['subcategory'], $a['order'], $b['category'], $b['subcategory'], $b['order']);
}
public function getProcessedReport($idSite, $period, $date, $apiModule, $apiAction, $segment = false,
diff --git a/plugins/API/Reports/Get.php b/plugins/API/Reports/Get.php
index de087d0a86..61cded3856 100644
--- a/plugins/API/Reports/Get.php
+++ b/plugins/API/Reports/Get.php
@@ -10,6 +10,7 @@ namespace Piwik\Plugins\API\Reports;
use Piwik\Piwik;
use Piwik\Plugin\Report;
+use Piwik\Plugin\Reports;
class Get extends Report
{
@@ -29,7 +30,7 @@ class Get extends Report
$this->module = 'API';
$this->action = 'get';
- $this->category = 'API';
+ $this->categoryId = 'API';
$this->name = Piwik::translate('General_MainMetrics');
$this->documentation = '';
@@ -80,8 +81,9 @@ class Get extends Report
*/
private function getReportsToMerge()
{
+ $reports = new Reports();
$result = array();
- foreach (Report::getAllReportClasses() as $reportClass) {
+ foreach ($reports->getAllReportClasses() as $reportClass) {
if ($reportClass == 'Piwik\\Plugins\\API\\Reports\\Get') {
continue;
}
diff --git a/plugins/API/SegmentMetadata.php b/plugins/API/SegmentMetadata.php
new file mode 100644
index 0000000000..4be514978c
--- /dev/null
+++ b/plugins/API/SegmentMetadata.php
@@ -0,0 +1,171 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\API;
+
+use Piwik\Columns\Dimension;
+use Piwik\Piwik;
+
+class SegmentMetadata
+{
+ public function getSegmentsMetadata($idSites = array(), $_hideImplementationData = true, $isAuthenticatedWithViewAccess)
+ {
+ $segments = array();
+
+ foreach (Dimension::getAllDimensions() as $dimension) {
+ foreach ($dimension->getSegments() as $segment) {
+ if ($segment->isRequiresAtLeastViewAccess()) {
+ $segment->setPermission($isAuthenticatedWithViewAccess);
+ }
+
+ $segments[] = $segment->toArray();
+ }
+ }
+
+ /**
+ * Triggered when gathering all available segment dimensions.
+ *
+ * This event can be used to make new segment dimensions available.
+ *
+ * **Example**
+ *
+ * public function getSegmentsMetadata(&$segments, $idSites)
+ * {
+ * $segments[] = array(
+ * 'type' => 'dimension',
+ * 'category' => Piwik::translate('General_Visit'),
+ * 'name' => 'General_VisitorIP',
+ * 'segment' => 'visitIp',
+ * 'acceptedValues' => '13.54.122.1, etc.',
+ * 'sqlSegment' => 'log_visit.location_ip',
+ * 'sqlFilter' => array('Piwik\IP', 'P2N'),
+ * 'permission' => $isAuthenticatedWithViewAccess,
+ * );
+ * }
+ *
+ * @param array &$dimensions The list of available segment dimensions. Append to this list to add
+ * new segments. Each element in this list must contain the
+ * following information:
+ *
+ * - **type**: Either `'metric'` or `'dimension'`. `'metric'` means
+ * the value is a numeric and `'dimension'` means it is
+ * a string. Also, `'metric'` values will be displayed
+ * under **Visit (metrics)** in the Segment Editor.
+ * - **category**: The segment category name. This can be an existing
+ * segment category visible in the segment editor.
+ * - **name**: The pretty name of the segment. Can be a translation token.
+ * - **segment**: The segment name, eg, `'visitIp'` or `'searches'`.
+ * - **acceptedValues**: A string describing one or two exacmple values, eg
+ * `'13.54.122.1, etc.'`.
+ * - **sqlSegment**: The table column this segment will segment by.
+ * For example, `'log_visit.location_ip'` for the
+ * **visitIp** segment.
+ * - **sqlFilter**: A PHP callback to apply to segment values before
+ * they are used in SQL.
+ * - **permission**: True if the current user has view access to this
+ * segment, false if otherwise.
+ * @param array $idSites The list of site IDs we're getting the available segments
+ * for. Some segments (such as Goal segments) depend on the
+ * site.
+ */
+ Piwik::postEvent('API.getSegmentDimensionMetadata', array(&$segments, $idSites));
+
+ $segments[] = array(
+ 'type' => 'dimension',
+ 'category' => Piwik::translate('General_Visit'),
+ 'name' => 'General_UserId',
+ 'segment' => 'userId',
+ 'acceptedValues' => 'any non empty unique string identifying the user (such as an email address or a username).',
+ 'sqlSegment' => 'log_visit.user_id',
+ 'permission' => $isAuthenticatedWithViewAccess,
+ );
+
+ $segments[] = array(
+ 'type' => 'dimension',
+ 'category' => Piwik::translate('General_Visit'),
+ 'name' => 'General_VisitorID',
+ 'segment' => 'visitorId',
+ 'acceptedValues' => '34c31e04394bdc63 - any 16 Hexadecimal chars ID, which can be fetched using the Tracking API function getVisitorId()',
+ 'sqlSegment' => 'log_visit.idvisitor',
+ 'sqlFilterValue' => array('Piwik\Common', 'convertVisitorIdToBin'),
+ 'permission' => $isAuthenticatedWithViewAccess,
+ );
+
+ $segments[] = array(
+ 'type' => 'dimension',
+ 'category' => Piwik::translate('General_Visit'),
+ 'name' => Piwik::translate('General_Visit') . " ID",
+ 'segment' => 'visitId',
+ 'acceptedValues' => 'Any integer.',
+ 'sqlSegment' => 'log_visit.idvisit',
+ 'permission' => $isAuthenticatedWithViewAccess,
+ );
+
+ $segments[] = array(
+ 'type' => 'metric',
+ 'category' => Piwik::translate('General_Visit'),
+ 'name' => 'General_VisitorIP',
+ 'segment' => 'visitIp',
+ 'acceptedValues' => '13.54.122.1. </code>Select IP ranges with notation: <code>visitIp>13.54.122.0;visitIp<13.54.122.255',
+ 'sqlSegment' => 'log_visit.location_ip',
+ 'sqlFilterValue' => array('Piwik\Network\IPUtils', 'stringToBinaryIP'),
+ 'permission' => $isAuthenticatedWithViewAccess,
+ );
+
+ foreach ($segments as &$segment) {
+ $segment['name'] = Piwik::translate($segment['name']);
+ $segment['category'] = Piwik::translate($segment['category']);
+
+ if ($_hideImplementationData) {
+ unset($segment['sqlFilter']);
+ unset($segment['sqlFilterValue']);
+ unset($segment['sqlSegment']);
+
+ if (isset($segment['suggestedValuesCallback'])
+ && !is_string($segment['suggestedValuesCallback'])
+ ) {
+ unset($segment['suggestedValuesCallback']);
+ }
+ }
+ }
+
+ usort($segments, array($this, 'sortSegments'));
+
+ return $segments;
+ }
+
+ private function sortSegments($row1, $row2)
+ {
+ $customVarCategory = Piwik::translate('CustomVariables_CustomVariables');
+
+ $columns = array('type', 'category', 'name', 'segment');
+
+ foreach ($columns as $column) {
+ // Keep segments ordered alphabetically inside categories..
+ $type = -1;
+ if ($column == 'name') $type = 1;
+
+ $compare = $type * strcmp($row1[$column], $row2[$column]);
+
+ // hack so that custom variables "page" are grouped together in the doc
+ if ($row1['category'] == $customVarCategory
+ && $row1['category'] == $row2['category']
+ ) {
+ $compare = strcmp($row1['segment'], $row2['segment']);
+ return $compare;
+ }
+
+ if ($compare != 0) {
+ return $compare;
+ }
+ }
+
+ return $compare;
+ }
+
+} \ No newline at end of file
diff --git a/plugins/API/WidgetMetadata.php b/plugins/API/WidgetMetadata.php
new file mode 100644
index 0000000000..8f0fb0330f
--- /dev/null
+++ b/plugins/API/WidgetMetadata.php
@@ -0,0 +1,283 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\API;
+
+use Piwik\Category\CategoryList;
+use Piwik\Piwik;
+use Piwik\Report\ReportWidgetConfig;
+use Piwik\Category\Category;
+use Piwik\Category\Subcategory;
+use Piwik\Widget\WidgetContainerConfig;
+use Piwik\Widget\WidgetConfig;
+use Piwik\Widget\WidgetsList;
+
+class WidgetMetadata
+{
+ public function getPagesMetadata(CategoryList $categoryList, WidgetsList $widgetsList)
+ {
+ $this->createMissingCategoriesAndSubcategories($categoryList, $widgetsList->getWidgetConfigs());
+
+ return $this->buildPagesMetadata($categoryList, $widgetsList);
+ }
+
+ public function getWidgetMetadata(CategoryList $categoryList, WidgetsList $widgetsList)
+ {
+ $this->createMissingCategoriesAndSubcategories($categoryList, $widgetsList->getWidgetConfigs());
+
+ $flat = array();
+
+ foreach ($widgetsList->getWidgetConfigs() as $widgetConfig) {
+
+ /** @var WidgetConfig[] $widgets */
+ $widgets = array($widgetConfig);
+ if ($widgetConfig instanceof WidgetContainerConfig) {
+ // so far we go only one level down, in theory these widgetConfigs could have again containers containing configs
+ $widgets = array_merge($widgets, $widgetConfig->getWidgetConfigs());
+ }
+
+ foreach ($widgets as $widget) {
+ // make sure to include only widgetizable widgets
+ if (!$widget->isWidgetizeable() || !$widget->getName()) {
+ continue;
+ }
+
+ $flat[] = $this->buildWidgetMetadata($widget, $categoryList);
+ }
+ }
+
+ usort($flat, array($this, 'sortWidgets'));
+
+ return $flat;
+ }
+
+ /**
+ * @param WidgetConfig $widget
+ * @param CategoryList|null $categoryList If null, no category information will be added to the widgets in first
+ * level (they will be added to nested widgets as potentially needed eg for
+ * widgets in ByDimensionView where they are needed to build the left menu)
+ * @return array
+ */
+ public function buildWidgetMetadata(WidgetConfig $widget, $categoryList = null)
+ {
+ $item = array(
+ 'name' => Piwik::translate($widget->getName())
+ );
+
+ if (isset($categoryList)) {
+ $category = $categoryList->getCategory($widget->getCategoryId());
+ $subcategory = $category ? $category->getSubcategory($widget->getSubcategoryId()) : null;
+
+ $item['category'] = $this->buildCategoryMetadata($category);
+ $item['subcategory'] = $this->buildSubcategoryMetadata($subcategory);
+ }
+
+ $item['module'] = $widget->getModule();
+ $item['action'] = $widget->getAction();
+ $item['order'] = $widget->getOrder();
+ $item['parameters'] = $widget->getParameters();
+ $item['uniqueId'] = $widget->getUniqueId();
+
+ $middleware = $widget->getMiddlewareParameters();
+
+ if (!empty($middleware)) {
+ $item['middlewareParameters'] = $middleware;
+ }
+
+ if ($widget instanceof ReportWidgetConfig) {
+ $item['viewDataTable'] = $widget->getViewDataTable();
+ $item['isReport'] = true;
+ }
+
+ if ($widget instanceof WidgetContainerConfig) {
+ $item['layout'] = $widget->getLayout();
+ $item['isContainer'] = true;
+
+ // we do not want to create categories to the inital categoryList. Otherwise we'd maybe display more pages
+ // etc.
+ $subCategoryList = new CategoryList();
+ $this->createMissingCategoriesAndSubcategories($subCategoryList, $widget->getWidgetConfigs());
+
+ $children = array();
+ foreach ($widget->getWidgetConfigs() as $widgetConfig) {
+ $children[] = $this->buildWidgetMetadata($widgetConfig, $subCategoryList);
+ }
+ $item['widgets'] = $children;
+ }
+
+ return $item;
+ }
+
+ private function sortWidgets($widgetA, $widgetB) {
+ $orderA = $widgetA['category']['order'];
+ $orderB = $widgetB['category']['order'];
+
+ if ($orderA === $orderB) {
+ if (!empty($widgetA['subcategory']['order']) && !empty($widgetB['subcategory']['order'])) {
+
+ $subOrderA = $widgetA['subcategory']['order'];
+ $subOrderB = $widgetB['subcategory']['order'];
+
+ if ($subOrderA === $subOrderB) {
+ return 0;
+ }
+
+ return $subOrderA > $subOrderB ? 1 : -1;
+
+ } elseif (!empty($orderA)) {
+
+ return 1;
+ }
+
+ return -1;
+ }
+
+ return $orderA > $orderB ? 1 : -1;
+ }
+
+ /**
+ * @param Category|null $category
+ * @return array
+ */
+ private function buildCategoryMetadata($category)
+ {
+ if (!isset($category)) {
+ return null;
+ }
+
+ return array(
+ 'id' => (string) $category->getId(),
+ 'name' => Piwik::translate($category->getId()),
+ 'order' => $category->getOrder(),
+ 'icon' => $category->getIcon(),
+ );
+ }
+
+ /**
+ * @param Subcategory|null $subcategory
+ * @return array
+ */
+ private function buildSubcategoryMetadata($subcategory)
+ {
+ if (!isset($subcategory)) {
+ return null;
+ }
+
+ return array(
+ 'id' => (string) $subcategory->getId(),
+ 'name' => Piwik::translate($subcategory->getName()),
+ 'order' => $subcategory->getOrder(),
+ );
+ }
+
+ /**
+ * @param CategoryList $categoryList
+ * @param WidgetConfig[] $widgetConfigs
+ */
+ private function createMissingCategoriesAndSubcategories($categoryList, $widgetConfigs)
+ {
+ // move reports into categories/subcategories and create missing ones if needed
+ foreach ($widgetConfigs as $widgetConfig) {
+ $categoryId = $widgetConfig->getCategoryId();
+ $subcategoryId = $widgetConfig->getSubcategoryId();
+
+ if (!$categoryId) {
+ continue;
+ }
+
+ if ($widgetConfig instanceof WidgetContainerConfig && !$widgetConfig->getWidgetConfigs()) {
+ // if a container does not contain any widgets, ignore it
+ continue;
+ }
+
+ if (!$categoryList->hasCategory($categoryId)) {
+ $categoryList->addCategory($this->createCategory($categoryId));
+ }
+
+ if (!$subcategoryId) {
+ continue;
+ }
+
+ $category = $categoryList->getCategory($categoryId);
+
+ if (!$category->hasSubcategory($subcategoryId)) {
+ $category->addSubcategory($this->createSubcategory($categoryId, $subcategoryId));
+ }
+ }
+ }
+
+ private function createCategory($categoryId)
+ {
+ $category = new Category();
+ $category->setId($categoryId);
+ return $category;
+ }
+
+ private function createSubcategory($categoryId, $subcategoryId)
+ {
+ $subcategory = new Subcategory();
+ $subcategory->setCategoryId($categoryId);
+ $subcategory->setId($subcategoryId);
+ return $subcategory;
+ }
+
+ /**
+ * @param CategoryList $categoryList
+ * @param WidgetsList $widgetsList
+ * @return array
+ */
+ private function buildPagesMetadata(CategoryList $categoryList, WidgetsList $widgetsList)
+ {
+ $pages = array();
+
+ $widgets = array();
+ foreach ($widgetsList->getWidgetConfigs() as $config) {
+ $pageId = $this->buildPageId($config->getCategoryId(), $config->getSubcategoryId());
+
+ if (!isset($widgets[$pageId])) {
+ $widgets[$pageId] = array();
+ }
+
+ $widgets[$pageId][] = $config;
+ }
+
+ foreach ($categoryList->getCategories() as $category) {
+ foreach ($category->getSubcategories() as $subcategory) {
+ $pageId = $this->buildPageId($category->getId(), $subcategory->getId());
+
+ if (!empty($widgets[$pageId])) {
+ $pages[] = $this->buildPageMetadata($category, $subcategory, $widgets[$pageId]);
+ }
+ }
+ }
+
+ return $pages;
+ }
+
+ private function buildPageId($categoryId, $subcategoryId)
+ {
+ return $categoryId . '.' . $subcategoryId;
+ }
+
+ public function buildPageMetadata(Category $category, Subcategory $subcategory, $widgetConfigs)
+ {
+ $ca = array(
+ 'uniqueId' => $this->buildPageId($category->getId(), $subcategory->getId()),
+ 'category' => $this->buildCategoryMetadata($category),
+ 'subcategory' => $this->buildSubcategoryMetadata($subcategory),
+ 'widgets' => array()
+ );
+
+ foreach ($widgetConfigs as $config) {
+ $ca['widgets'][] = $this->buildWidgetMetadata($config);
+ }
+
+ return $ca;
+ }
+
+} \ No newline at end of file
diff --git a/plugins/API/tests/Unit/WidgetMetadataTest.php b/plugins/API/tests/Unit/WidgetMetadataTest.php
new file mode 100644
index 0000000000..340a0fb6ea
--- /dev/null
+++ b/plugins/API/tests/Unit/WidgetMetadataTest.php
@@ -0,0 +1,283 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+
+namespace Piwik\Plugins\API\tests\Unit;
+
+use Piwik\Category\Category;
+use Piwik\Category\CategoryList;
+use Piwik\Category\Subcategory;
+use Piwik\DataTable;
+use Piwik\Plugins\API\Renderer\Console;
+use Piwik\Plugins\API\WidgetMetadata;
+use Piwik\Plugins\CoreHome\CoreHome;
+use Piwik\Report\ReportWidgetConfig;
+use Piwik\Widget\WidgetConfig;
+use Piwik\Widget\WidgetContainerConfig;
+
+/**
+ * @group Widget
+ * @group Widgets
+ * @group WidgetMetadata
+ * @group WidgetMetadataTest
+ */
+class WidgetMetadataTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * @var WidgetMetadata
+ */
+ private $metadata;
+
+ public function setUp()
+ {
+ $this->metadata = new WidgetMetadata();
+ }
+
+ public function test_buildWidgetMetadata_ShouldGenerateMetadata()
+ {
+ $config = $this->createWidgetConfig('Test', 'CategoryId', 'SubcategoryId');
+ $list = $this->createCategoryList(array('CategoryId' => array('SubcategoryId')));
+ $metadata = $this->metadata->buildWidgetMetadata($config, $list);
+
+ $this->assertEquals(array(
+ 'name' => 'Test',
+ 'category' => array(
+ 'id' => 'CategoryId',
+ 'name' => 'CategoryId',
+ 'order' => 99,
+ 'icon' => ''
+ ),
+ 'subcategory' => array(
+ 'id' => 'SubcategoryId',
+ 'name' => 'SubcategoryIdName',
+ 'order' => 99,
+ ),
+ 'module' => 'CoreHome',
+ 'action' => 'render',
+ 'order' => 99,
+ 'parameters' => array (
+ 'module' => 'CoreHome',
+ 'action' => 'render'
+ ),
+ 'uniqueId' => 'widgetCoreHomerender'
+ ), $metadata);
+ }
+
+ public function test_buildWidgetMetadata_ShouldSetCategoryAndSubcategoryToNull_IfBothGivenButNotExistInList()
+ {
+ $config = $this->createWidgetConfig('Test', 'CategoryId', 'SubcategoryId');
+ $list = $this->createCategoryList();
+ $metadata = $this->metadata->buildWidgetMetadata($config, $list);
+
+ $this->assertNull($metadata['category']);
+ $this->assertNull($metadata['subcategory']);
+ }
+
+ public function test_buildWidgetMetadata_ShouldSetSubcategoryToNull_IfCategoryGivenInListButSubcategoryNot()
+ {
+ $config = $this->createWidgetConfig('Test', 'CategoryId', 'SubcategoryId');
+ $list = $this->createCategoryList(array('CategoryId' => array()));
+ $metadata = $this->metadata->buildWidgetMetadata($config, $list);
+
+ $this->assertSame(array(
+ 'id' => 'CategoryId',
+ 'name' => 'CategoryId',
+ 'order' => 99,
+ 'icon' => '',
+ ), $metadata['category']);
+ $this->assertNull($metadata['subcategory']);
+ }
+
+ public function test_buildWidgetMetadata_ShouldNotAddCategoryAndSubcategoryToNull_IfNoCategoryListGiven()
+ {
+ $config = $this->createWidgetConfig('Test', 'CategoryId', 'SubcategoryId');
+ $metadata = $this->metadata->buildWidgetMetadata($config);
+
+ $this->assertArrayNotHasKey('category', $metadata);
+ $this->assertArrayNotHasKey('subcategory', $metadata);
+ }
+
+ public function test_buildWidgetMetadata_ShouldAddOptionalMiddlewareParameters()
+ {
+ $config = $this->createWidgetConfig('Test', 'CategoryId', 'SubcategoryId');
+ $config->setMiddlewareParameters(array('module' => 'Goals', 'action' => 'hasAnyConversions'));
+ $metadata = $this->metadata->buildWidgetMetadata($config);
+
+ $this->assertSame(array('module' => 'Goals', 'action' => 'hasAnyConversions'), $metadata['middlewareParameters']);
+ }
+
+ public function test_buildWidgetMetadata_ShouldAddReportInformtion_IfReportWidgetConfigGiven()
+ {
+ $config = new ReportWidgetConfig();
+ $config->setDefaultViewDataTable('graph');
+ $metadata = $this->metadata->buildWidgetMetadata($config);
+
+ $this->assertSame('graph', $metadata['viewDataTable']);
+ $this->assertTrue($metadata['isReport']);
+ }
+
+ public function test_buildWidgetMetadata_ShouldAddContainerInformtion_IfWidgetContainerConfigGiven()
+ {
+ $config = new WidgetContainerConfig();
+ $config->setLayout('ByDimension');
+ $config->addWidgetConfig($this->createWidgetConfig('NestedName1', 'NestedCategory1', 'NestedSubcategory1'));
+ $config->addWidgetConfig($this->createWidgetConfig('NestedName2', 'NestedCategory2', 'NestedSubcategory2'));
+ $metadata = $this->metadata->buildWidgetMetadata($config);
+
+ $this->assertSame('ByDimension', $metadata['layout']);
+ $this->assertTrue($metadata['isContainer']);
+ $this->assertCount(2, $metadata['widgets']);
+
+ $widget1 = $metadata['widgets'][0];
+ $widget2 = $metadata['widgets'][1];
+ $this->assertSame(array(
+ 'name' => 'NestedName1',
+ 'category' => array (
+ 'id' => 'NestedCategory1',
+ 'name' => 'NestedCategory1',
+ 'order' => 99,
+ 'icon' => ''
+ ),
+ 'subcategory' => array (
+ 'id' => 'NestedSubcategory1',
+ 'name' => 'NestedSubcategory1',
+ 'order' => 99
+ ),
+ 'module' => 'CoreHome',
+ 'action' => 'render',
+ 'order' => 99,
+ 'parameters' => array (
+ 'module' => 'CoreHome',
+ 'action' => 'render',
+ ),
+ 'uniqueId' => 'widgetCoreHomerender'
+ ), $widget1);
+ $this->assertSame(array(
+ 'name' => 'NestedName2',
+ 'category' => array (
+ 'id' => 'NestedCategory2',
+ 'name' => 'NestedCategory2',
+ 'order' => 99,
+ 'icon' => ''
+ ),
+ 'subcategory' => array (
+ 'id' => 'NestedSubcategory2',
+ 'name' => 'NestedSubcategory2',
+ 'order' => 99
+ ),
+ 'module' => 'CoreHome',
+ 'action' => 'render',
+ 'order' => 99,
+ 'parameters' => array (
+ 'module' => 'CoreHome',
+ 'action' => 'render',
+ ),
+ 'uniqueId' => 'widgetCoreHomerender'
+ ), $widget2);
+ }
+
+ public function test_buildPageMetadata_ShouldAddContainerInformtion_IfWidgetContainerConfigGiven()
+ {
+ $config = new WidgetContainerConfig();
+ $config->setLayout('ByDimension');
+
+ $widgets = array(
+ $this->createWidgetConfig('NestedName1', 'NestedCategory1', 'NestedSubcategory1'),
+ $this->createWidgetConfig('NestedName2', 'NestedCategory2', 'NestedSubcategory1'),
+ );
+
+ $category = $this->createCategory('NestedCategory1');
+ $subcategory = $this->createSubcategory('NestedCategory1' ,'NestedSubcategory1');
+
+ $metadata = $this->metadata->buildPageMetadata($category, $subcategory, $widgets);
+
+ $this->assertSame(array(
+ 'uniqueId' => 'NestedCategory1.NestedSubcategory1',
+ 'category' => array (
+ 'id' => 'NestedCategory1',
+ 'name' => 'NestedCategory1',
+ 'order' => 99,
+ 'icon' => '',
+ ),
+ 'subcategory' => array (
+ 'id' => 'NestedSubcategory1',
+ 'name' => 'NestedSubcategory1Name',
+ 'order' => 99,
+ ),
+ 'widgets' => array (
+ 0 => array ( // widgets should not have category / subcategory again, it's already present above
+ 'name' => 'NestedName1',
+ 'module' => 'CoreHome',
+ 'action' => 'render',
+ 'order' => 99,
+ 'parameters' => array (
+ 'module' => 'CoreHome',
+ 'action' => 'render',
+ ),
+ 'uniqueId' => 'widgetCoreHomerender',
+ ), array (
+ 'name' => 'NestedName2',
+ 'module' => 'CoreHome',
+ 'action' => 'render',
+ 'order' => 99,
+ 'parameters' => array (
+ 'module' => 'CoreHome',
+ 'action' => 'render',
+ ),
+ 'uniqueId' => 'widgetCoreHomerender'
+ )
+ )
+ ), $metadata);
+ }
+
+ private function createWidgetConfig($name, $categoryId, $subcategoryId = '')
+ {
+ $widgetConfig = new WidgetConfig();
+ $widgetConfig->setName($name);
+ $widgetConfig->setCategoryId($categoryId);
+ $widgetConfig->setSubcategoryId($subcategoryId);
+ $widgetConfig->setModule('CoreHome');
+ $widgetConfig->setAction('render');
+
+ return $widgetConfig;
+ }
+
+ private function createCategoryList($categories = array())
+ {
+ $list = new CategoryList();
+
+ foreach ($categories as $categoryId => $subcategoryIds) {
+ $category = $this->createCategory($categoryId);
+ $list->addCategory($category);
+
+ foreach ($subcategoryIds as $subcategoryId) {
+ $subcategory = $this->createSubcategory($categoryId, $subcategoryId);
+ $category->addSubcategory($subcategory);
+ }
+ }
+
+ return $list;
+ }
+
+ private function createSubcategory($categoryId, $subcategoryId)
+ {
+ $subcategory = new Subcategory();
+ $subcategory->setCategoryId($categoryId);
+ $subcategory->setId($subcategoryId);
+ $subcategory->setName($subcategoryId . 'Name');
+
+ return $subcategory;
+ }
+
+ private function createCategory($categoryId)
+ {
+ $category = new Category();
+ $category->setId($categoryId);
+ return $category;
+ }
+
+}
diff --git a/plugins/Actions/API.php b/plugins/Actions/API.php
index 891400e122..e475f4240c 100644
--- a/plugins/Actions/API.php
+++ b/plugins/Actions/API.php
@@ -22,6 +22,7 @@ use Piwik\Plugins\Actions\Columns\Metrics\BounceRate;
use Piwik\Plugins\Actions\Columns\Metrics\ExitRate;
use Piwik\Plugins\CustomVariables\API as APICustomVariables;
use Piwik\Plugins\Actions\Actions\ActionSiteSearch;
+use Piwik\Plugin\Reports;
use Piwik\Tracker\Action;
use Piwik\Tracker\PageUrl;
@@ -55,7 +56,7 @@ class API extends \Piwik\Plugin\API
{
Piwik::checkUserHasViewAccess($idSite);
- $report = Report::factory("Actions", "get");
+ $report = Reports::factory("Actions", "get");
$archive = Archive::build($idSite, $period, $date, $segment);
$requestedColumns = Piwik::getArrayFromApiParameter($columns);
diff --git a/plugins/Actions/Actions.php b/plugins/Actions/Actions.php
index bf47a6b9fa..38ccbc229c 100644
--- a/plugins/Actions/Actions.php
+++ b/plugins/Actions/Actions.php
@@ -10,6 +10,7 @@ namespace Piwik\Plugins\Actions;
use Piwik\ArchiveProcessor;
use Piwik\Db;
+use Piwik\Plugins\CoreVisualizations\Visualizations\Sparklines;
use Piwik\Site;
use Piwik\Plugin\ViewDataTable;
use Piwik\Plugins\CoreVisualizations\Visualizations\HtmlTable;
diff --git a/plugins/Actions/Categories/DownloadsSubcategory.php b/plugins/Actions/Categories/DownloadsSubcategory.php
new file mode 100644
index 0000000000..ac432b11d1
--- /dev/null
+++ b/plugins/Actions/Categories/DownloadsSubcategory.php
@@ -0,0 +1,19 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\Actions\Categories;
+
+use Piwik\Category\Subcategory;
+
+class DownloadsSubcategory extends Subcategory
+{
+ protected $categoryId = 'General_Actions';
+ protected $id = 'General_Downloads';
+ protected $order = 35;
+
+}
diff --git a/plugins/Actions/Categories/EntryPagesSubcategory.php b/plugins/Actions/Categories/EntryPagesSubcategory.php
new file mode 100644
index 0000000000..d4ee657b79
--- /dev/null
+++ b/plugins/Actions/Categories/EntryPagesSubcategory.php
@@ -0,0 +1,19 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\Actions\Categories;
+
+use Piwik\Category\Subcategory;
+
+class EntryPagesSubcategory extends Subcategory
+{
+ protected $categoryId = 'General_Actions';
+ protected $id = 'Actions_SubmenuPagesEntry';
+ protected $order = 10;
+
+}
diff --git a/plugins/Actions/Categories/ExitPagesSubcategory.php b/plugins/Actions/Categories/ExitPagesSubcategory.php
new file mode 100644
index 0000000000..b1a5a636c6
--- /dev/null
+++ b/plugins/Actions/Categories/ExitPagesSubcategory.php
@@ -0,0 +1,19 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\Actions\Categories;
+
+use Piwik\Category\Subcategory;
+
+class ExitPagesSubcategory extends Subcategory
+{
+ protected $categoryId = 'General_Actions';
+ protected $id = 'Actions_SubmenuPagesExit';
+ protected $order = 15;
+
+}
diff --git a/plugins/Actions/Categories/OutlinksSubcategory.php b/plugins/Actions/Categories/OutlinksSubcategory.php
new file mode 100644
index 0000000000..975ca9003e
--- /dev/null
+++ b/plugins/Actions/Categories/OutlinksSubcategory.php
@@ -0,0 +1,19 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\Actions\Categories;
+
+use Piwik\Category\Subcategory;
+
+class OutlinksSubcategory extends Subcategory
+{
+ protected $categoryId = 'General_Actions';
+ protected $id = 'General_Outlinks';
+ protected $order = 30;
+
+}
diff --git a/plugins/Actions/Categories/PageTitlesSubcategory.php b/plugins/Actions/Categories/PageTitlesSubcategory.php
new file mode 100644
index 0000000000..1a88b6dbd2
--- /dev/null
+++ b/plugins/Actions/Categories/PageTitlesSubcategory.php
@@ -0,0 +1,19 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\Actions\Categories;
+
+use Piwik\Category\Subcategory;
+
+class PageTitlesSubcategory extends Subcategory
+{
+ protected $categoryId = 'General_Actions';
+ protected $id = 'Actions_SubmenuPageTitles';
+ protected $order = 20;
+
+}
diff --git a/plugins/Actions/Categories/PagesSubcategory.php b/plugins/Actions/Categories/PagesSubcategory.php
new file mode 100644
index 0000000000..5d407859b1
--- /dev/null
+++ b/plugins/Actions/Categories/PagesSubcategory.php
@@ -0,0 +1,19 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\Actions\Categories;
+
+use Piwik\Category\Subcategory;
+
+class PagesSubcategory extends Subcategory
+{
+ protected $categoryId = 'General_Actions';
+ protected $id = 'General_Pages';
+ protected $order = 5;
+
+}
diff --git a/plugins/Actions/Categories/SiteSearchSubcategory.php b/plugins/Actions/Categories/SiteSearchSubcategory.php
new file mode 100644
index 0000000000..e915803679
--- /dev/null
+++ b/plugins/Actions/Categories/SiteSearchSubcategory.php
@@ -0,0 +1,19 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\Actions\Categories;
+
+use Piwik\Category\Subcategory;
+
+class SiteSearchSubcategory extends Subcategory
+{
+ protected $categoryId = 'General_Actions';
+ protected $id = 'Actions_SubmenuSitesearch';
+ protected $order = 25;
+
+}
diff --git a/plugins/Actions/Controller.php b/plugins/Actions/Controller.php
deleted file mode 100644
index 51c7d7ba3a..0000000000
--- a/plugins/Actions/Controller.php
+++ /dev/null
@@ -1,45 +0,0 @@
-<?php
-/**
- * Piwik - free/libre analytics platform
- *
- * @link http://piwik.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- *
- */
-namespace Piwik\Plugins\Actions;
-
-use Piwik\Plugin\Report;
-use Piwik\View;
-
-/**
- * Actions controller
- *
- */
-class Controller extends \Piwik\Plugin\Controller
-{
- //
- // Actions that render whole pages
- //
-
- public function indexSiteSearch()
- {
- $view = new View('@Actions/indexSiteSearch');
-
- $keyword = Report::factory($this->pluginName, 'getSiteSearchKeywords');
- $noResult = Report::factory($this->pluginName, 'getSiteSearchNoResultKeywords');
- $pageUrls = Report::factory($this->pluginName, 'getPageUrlsFollowingSiteSearch');
-
- $view->keywords = $keyword->render();
- $view->noResultKeywords = $noResult->render();
- $view->pagesUrlsFollowingSiteSearch = $pageUrls->render();
-
- $categoryTrackingEnabled = Actions::isCustomVariablesPluginsEnabled();
- if ($categoryTrackingEnabled) {
- $categories = Report::factory($this->pluginName, 'getSiteSearchCategories');
- $view->categories = $categories->render();
- }
-
- return $view->render();
- }
-
-}
diff --git a/plugins/Actions/Menu.php b/plugins/Actions/Menu.php
deleted file mode 100644
index 9063be50a3..0000000000
--- a/plugins/Actions/Menu.php
+++ /dev/null
@@ -1,29 +0,0 @@
-<?php
-/**
- * Piwik - free/libre analytics platform
- *
- * @link http://piwik.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- *
- */
-namespace Piwik\Plugins\Actions;
-
-use Piwik\Common;
-use Piwik\Menu\MenuReporting;
-
-class Menu extends \Piwik\Plugin\Menu
-{
- public function configureReportingMenu(MenuReporting $menu)
- {
- $menu->addActionsItem('', array(), 15);
-
- $idSite = Common::getRequestVar('idSite', 0, 'int');
- $idSites = Common::getRequestVar('idSites', '', 'string');
-
- $actions = new Actions();
- if ($actions->isSiteSearchEnabled($idSites, $idSite)) {
- $menu->addActionsItem('Actions_SubmenuSitesearch', $this->urlForAction('indexSiteSearch'), 5);
- }
- }
-
-}
diff --git a/plugins/Actions/Reports/Base.php b/plugins/Actions/Reports/Base.php
index 45c9c0af9c..20e35593d8 100644
--- a/plugins/Actions/Reports/Base.php
+++ b/plugins/Actions/Reports/Base.php
@@ -21,7 +21,7 @@ abstract class Base extends \Piwik\Plugin\Report
{
protected function init()
{
- $this->category = 'General_Actions';
+ $this->categoryId = 'General_Actions';
$this->processedMetrics = false;
$this->recursiveLabelSeparator = '/';
}
diff --git a/plugins/Actions/Reports/GetDownloads.php b/plugins/Actions/Reports/GetDownloads.php
index f168cba878..92975b969e 100644
--- a/plugins/Actions/Reports/GetDownloads.php
+++ b/plugins/Actions/Reports/GetDownloads.php
@@ -26,8 +26,7 @@ class GetDownloads extends Base
$this->actionToLoadSubTables = $this->action;
$this->order = 9;
- $this->menuTitle = 'General_Downloads';
- $this->widgetTitle = 'General_Downloads';
+ $this->subcategoryId = 'General_Downloads';
}
public function getMetrics()
diff --git a/plugins/Actions/Reports/GetEntryPageTitles.php b/plugins/Actions/Reports/GetEntryPageTitles.php
index 7c029f4b02..9df1d74450 100644
--- a/plugins/Actions/Reports/GetEntryPageTitles.php
+++ b/plugins/Actions/Reports/GetEntryPageTitles.php
@@ -15,6 +15,9 @@ use Piwik\Plugins\Actions\Columns\Metrics\AveragePageGenerationTime;
use Piwik\Plugins\Actions\Columns\Metrics\AverageTimeOnPage;
use Piwik\Plugins\Actions\Columns\Metrics\BounceRate;
use Piwik\Plugins\Actions\Columns\Metrics\ExitRate;
+use Piwik\Plugin\Reports;
+use Piwik\Report\ReportWidgetFactory;
+use Piwik\Widget\WidgetsList;
class GetEntryPageTitles extends Base
{
@@ -35,8 +38,11 @@ class GetEntryPageTitles extends Base
);
$this->order = 6;
$this->actionToLoadSubTables = $this->action;
+ }
- $this->widgetTitle = 'Actions_WidgetEntryPageTitles';
+ public function configureWidgets(WidgetsList $widgetsList, ReportWidgetFactory $factory)
+ {
+ $widgetsList->addWidgetConfig($factory->createWidget()->setName('Actions_WidgetEntryPageTitles'));
}
public function getProcessedMetrics()
@@ -79,8 +85,8 @@ class GetEntryPageTitles extends Base
public function getRelatedReports()
{
return array(
- self::factory('Actions', 'getPageTitles'),
- self::factory('Actions', 'getEntryPageUrls')
+ Reports::factory('Actions', 'getPageTitles'),
+ Reports::factory('Actions', 'getEntryPageUrls')
);
}
}
diff --git a/plugins/Actions/Reports/GetEntryPageUrls.php b/plugins/Actions/Reports/GetEntryPageUrls.php
index 838bb414d0..dfeeb8cf04 100644
--- a/plugins/Actions/Reports/GetEntryPageUrls.php
+++ b/plugins/Actions/Reports/GetEntryPageUrls.php
@@ -15,6 +15,9 @@ use Piwik\Plugins\Actions\Columns\Metrics\AveragePageGenerationTime;
use Piwik\Plugins\Actions\Columns\Metrics\AverageTimeOnPage;
use Piwik\Plugins\Actions\Columns\Metrics\BounceRate;
use Piwik\Plugins\Actions\Columns\Metrics\ExitRate;
+use Piwik\Plugin\Reports;
+use Piwik\Report\ReportWidgetFactory;
+use Piwik\Widget\WidgetsList;
class GetEntryPageUrls extends Base
{
@@ -38,8 +41,7 @@ class GetEntryPageUrls extends Base
$this->actionToLoadSubTables = $this->action;
- $this->menuTitle = 'Actions_SubmenuPagesEntry';
- $this->widgetTitle = 'Actions_WidgetPagesEntry';
+ $this->subcategoryId = 'Actions_SubmenuPagesEntry';
}
public function getProcessedMetrics()
@@ -81,7 +83,7 @@ class GetEntryPageUrls extends Base
public function getRelatedReports()
{
return array(
- self::factory('Actions', 'getEntryPageTitles'),
+ Reports::factory('Actions', 'getEntryPageTitles'),
);
}
}
diff --git a/plugins/Actions/Reports/GetExitPageTitles.php b/plugins/Actions/Reports/GetExitPageTitles.php
index 6cc5b1f320..53f235209d 100644
--- a/plugins/Actions/Reports/GetExitPageTitles.php
+++ b/plugins/Actions/Reports/GetExitPageTitles.php
@@ -15,6 +15,9 @@ use Piwik\Plugins\Actions\Columns\Metrics\AveragePageGenerationTime;
use Piwik\Plugins\Actions\Columns\Metrics\AverageTimeOnPage;
use Piwik\Plugins\Actions\Columns\Metrics\BounceRate;
use Piwik\Plugins\Actions\Columns\Metrics\ExitRate;
+use Piwik\Plugin\Reports;
+use Piwik\Report\ReportWidgetFactory;
+use Piwik\Widget\WidgetsList;
class GetExitPageTitles extends Base
{
@@ -37,8 +40,13 @@ class GetExitPageTitles extends Base
$this->order = 7;
$this->actionToLoadSubTables = $this->action;
+ }
- $this->widgetTitle = 'Actions_WidgetExitPageTitles';
+ public function configureWidgets(WidgetsList $widgetsList, ReportWidgetFactory $factory)
+ {
+ // we have to do it manually since it's only done automatically if a subcategoryId is specified,
+ // we do not set a subcategoryId since this report is not supposed to be shown in the UI
+ $widgetsList->addWidgetConfig($factory->createWidget());
}
public function getProcessedMetrics()
@@ -86,8 +94,8 @@ class GetExitPageTitles extends Base
public function getRelatedReports()
{
return array(
- self::factory('Actions', 'getPageTitles'),
- self::factory('Actions', 'getExitPageUrls'),
+ Reports::factory('Actions', 'getPageTitles'),
+ Reports::factory('Actions', 'getExitPageUrls'),
);
}
}
diff --git a/plugins/Actions/Reports/GetExitPageUrls.php b/plugins/Actions/Reports/GetExitPageUrls.php
index 092a54adfe..bc4d29782d 100644
--- a/plugins/Actions/Reports/GetExitPageUrls.php
+++ b/plugins/Actions/Reports/GetExitPageUrls.php
@@ -16,6 +16,9 @@ use Piwik\Plugins\Actions\Columns\Metrics\AveragePageGenerationTime;
use Piwik\Plugins\Actions\Columns\Metrics\AverageTimeOnPage;
use Piwik\Plugins\Actions\Columns\Metrics\BounceRate;
use Piwik\Plugins\Actions\Columns\Metrics\ExitRate;
+use Piwik\Plugin\Reports;
+use Piwik\Report\ReportWidgetFactory;
+use Piwik\Widget\WidgetsList;
class GetExitPageUrls extends Base
{
@@ -39,8 +42,7 @@ class GetExitPageUrls extends Base
$this->order = 4;
- $this->menuTitle = 'Actions_SubmenuPagesExit';
- $this->widgetTitle = 'Actions_WidgetPagesExit';
+ $this->subcategoryId = 'Actions_SubmenuPagesExit';
}
public function getProcessedMetrics()
@@ -96,7 +98,7 @@ class GetExitPageUrls extends Base
public function getRelatedReports()
{
return array(
- self::factory('Actions', 'getExitPageTitles'),
+ Reports::factory('Actions', 'getExitPageTitles'),
);
}
diff --git a/plugins/Actions/Reports/GetOutlinks.php b/plugins/Actions/Reports/GetOutlinks.php
index adf21c572c..fb5e13e831 100644
--- a/plugins/Actions/Reports/GetOutlinks.php
+++ b/plugins/Actions/Reports/GetOutlinks.php
@@ -29,8 +29,7 @@ class GetOutlinks extends Base
$this->actionToLoadSubTables = $this->action;
- $this->menuTitle = 'General_Outlinks';
- $this->widgetTitle = 'General_Outlinks';
+ $this->subcategoryId = 'General_Outlinks';
}
public function getMetrics()
diff --git a/plugins/Actions/Reports/GetPageTitles.php b/plugins/Actions/Reports/GetPageTitles.php
index 1466efce8a..ed1846ddd6 100644
--- a/plugins/Actions/Reports/GetPageTitles.php
+++ b/plugins/Actions/Reports/GetPageTitles.php
@@ -16,6 +16,9 @@ use Piwik\Plugins\Actions\Columns\Metrics\AveragePageGenerationTime;
use Piwik\Plugins\Actions\Columns\Metrics\AverageTimeOnPage;
use Piwik\Plugins\Actions\Columns\Metrics\BounceRate;
use Piwik\Plugins\Actions\Columns\Metrics\ExitRate;
+use Piwik\Plugin\Reports;
+use Piwik\Report\ReportWidgetFactory;
+use Piwik\Widget\WidgetsList;
class GetPageTitles extends Base
{
@@ -39,8 +42,7 @@ class GetPageTitles extends Base
$this->actionToLoadSubTables = $this->action;
- $this->menuTitle = 'Actions_SubmenuPageTitles';
- $this->widgetTitle = 'Actions_WidgetPageTitles';
+ $this->subcategoryId = 'Actions_SubmenuPageTitles';
}
public function getMetrics()
@@ -80,8 +82,8 @@ class GetPageTitles extends Base
public function getRelatedReports()
{
return array(
- self::factory('Actions', 'getEntryPageTitles'),
- self::factory('Actions', 'getExitPageTitles'),
+ Reports::factory('Actions', 'getEntryPageTitles'),
+ Reports::factory('Actions', 'getExitPageTitles'),
);
}
}
diff --git a/plugins/Actions/Reports/GetPageTitlesFollowingSiteSearch.php b/plugins/Actions/Reports/GetPageTitlesFollowingSiteSearch.php
index 657e88211d..3d50ba4f95 100644
--- a/plugins/Actions/Reports/GetPageTitlesFollowingSiteSearch.php
+++ b/plugins/Actions/Reports/GetPageTitlesFollowingSiteSearch.php
@@ -15,6 +15,7 @@ use Piwik\Plugins\Actions\Columns\Metrics\AveragePageGenerationTime;
use Piwik\Plugins\Actions\Columns\Metrics\AverageTimeOnPage;
use Piwik\Plugins\Actions\Columns\Metrics\BounceRate;
use Piwik\Plugins\Actions\Columns\Metrics\ExitRate;
+use Piwik\Plugin\Reports;
class GetPageTitlesFollowingSiteSearch extends SiteSearchBase
{
@@ -32,7 +33,8 @@ class GetPageTitlesFollowingSiteSearch extends SiteSearchBase
new AveragePageGenerationTime()
);
$this->order = 19;
- $this->widgetTitle = 'Actions_WidgetPageTitlesFollowingSearch';
+
+ $this->subcategoryId = 'Actions_SubmenuSitesearch';
}
public function configureView(ViewDataTable $view)
@@ -80,7 +82,7 @@ class GetPageTitlesFollowingSiteSearch extends SiteSearchBase
public function getRelatedReports()
{
return array(
- self::factory('Actions', 'getPageUrlsFollowingSiteSearch'),
+ Reports::factory('Actions', 'getPageUrlsFollowingSiteSearch'),
);
}
}
diff --git a/plugins/Actions/Reports/GetPageUrls.php b/plugins/Actions/Reports/GetPageUrls.php
index e1cda77a48..004d11ba88 100644
--- a/plugins/Actions/Reports/GetPageUrls.php
+++ b/plugins/Actions/Reports/GetPageUrls.php
@@ -15,6 +15,8 @@ use Piwik\Plugins\Actions\Columns\Metrics\BounceRate;
use Piwik\Plugins\Actions\Columns\PageUrl;
use Piwik\Plugins\Actions\Columns\Metrics\ExitRate;
use Piwik\Plugins\Actions\Columns\Metrics\AverageTimeOnPage;
+use Piwik\Report\ReportWidgetFactory;
+use Piwik\Widget\WidgetsList;
class GetPageUrls extends Base
{
@@ -37,8 +39,12 @@ class GetPageUrls extends Base
new AveragePageGenerationTime()
);
- $this->menuTitle = 'General_Pages';
- $this->widgetTitle = 'General_Pages';
+ $this->subcategoryId = 'General_Pages';
+ }
+
+ public function configureWidgets(WidgetsList $widgetsList, ReportWidgetFactory $factory)
+ {
+ $widgetsList->addWidgetConfig($factory->createWidget()->setName($this->subcategoryId));
}
public function getMetrics()
diff --git a/plugins/Actions/Reports/GetPageUrlsFollowingSiteSearch.php b/plugins/Actions/Reports/GetPageUrlsFollowingSiteSearch.php
index 2d8ba1a3a2..063d3855b5 100644
--- a/plugins/Actions/Reports/GetPageUrlsFollowingSiteSearch.php
+++ b/plugins/Actions/Reports/GetPageUrlsFollowingSiteSearch.php
@@ -11,6 +11,7 @@ namespace Piwik\Plugins\Actions\Reports;
use Piwik\Piwik;
use Piwik\Plugin\ViewDataTable;
use Piwik\Plugins\Actions\Columns\DestinationPage;
+use Piwik\Plugin\Reports;
class GetPageUrlsFollowingSiteSearch extends GetPageTitlesFollowingSiteSearch
{
@@ -20,8 +21,9 @@ class GetPageUrlsFollowingSiteSearch extends GetPageTitlesFollowingSiteSearch
$this->dimension = new DestinationPage();
$this->name = Piwik::translate('Actions_WidgetPageUrlsFollowingSearch');
$this->documentation = Piwik::translate('Actions_SiteSearchFollowingPagesDoc') . '<br/>' . Piwik::translate('General_UsePlusMinusIconsDocumentation');
- $this->order = 18;
- $this->widgetTitle = 'Actions_WidgetPageUrlsFollowingSearch';
+ $this->order = 16;
+
+ $this->subcategoryId = 'Actions_SubmenuSitesearch';
}
public function configureView(ViewDataTable $view)
@@ -34,7 +36,7 @@ class GetPageUrlsFollowingSiteSearch extends GetPageTitlesFollowingSiteSearch
public function getRelatedReports()
{
return array(
- self::factory('Actions', 'getPageTitlesFollowingSiteSearch'),
+ Reports::factory('Actions', 'getPageTitlesFollowingSiteSearch'),
);
}
}
diff --git a/plugins/Actions/Reports/GetSiteSearchCategories.php b/plugins/Actions/Reports/GetSiteSearchCategories.php
index 6d41e3c334..5388ff9198 100644
--- a/plugins/Actions/Reports/GetSiteSearchCategories.php
+++ b/plugins/Actions/Reports/GetSiteSearchCategories.php
@@ -23,8 +23,9 @@ class GetSiteSearchCategories extends SiteSearchBase
$this->name = Piwik::translate('Actions_WidgetSearchCategories');
$this->documentation = Piwik::translate('Actions_SiteSearchCategories1') . '<br/>' . Piwik::translate('Actions_SiteSearchCategories2');
$this->metrics = array('nb_visits', 'nb_pages_per_search', 'exit_rate');
- $this->order = 17;
- $this->widgetTitle = 'Actions_WidgetSearchCategories';
+ $this->order = 20;
+
+ $this->subcategoryId = 'Actions_SubmenuSitesearch';
}
protected function isEnabledForIdSites($idSites, $idSite)
diff --git a/plugins/Actions/Reports/GetSiteSearchKeywords.php b/plugins/Actions/Reports/GetSiteSearchKeywords.php
index d88684cd15..dc4b5e2d16 100644
--- a/plugins/Actions/Reports/GetSiteSearchKeywords.php
+++ b/plugins/Actions/Reports/GetSiteSearchKeywords.php
@@ -33,7 +33,7 @@ class GetSiteSearchKeywords extends SiteSearchBase
new AveragePageGenerationTime()
);
$this->order = 15;
- $this->widgetTitle = 'Actions_WidgetSearchKeywords';
+ $this->subcategoryId = 'Actions_SubmenuSitesearch';
}
public function getMetrics()
diff --git a/plugins/Actions/Reports/GetSiteSearchNoResultKeywords.php b/plugins/Actions/Reports/GetSiteSearchNoResultKeywords.php
index 94b19e8566..c1c01ca504 100644
--- a/plugins/Actions/Reports/GetSiteSearchNoResultKeywords.php
+++ b/plugins/Actions/Reports/GetSiteSearchNoResultKeywords.php
@@ -31,8 +31,9 @@ class GetSiteSearchNoResultKeywords extends SiteSearchBase
new ExitRate(),
new AveragePageGenerationTime()
);
- $this->order = 16;
- $this->widgetTitle = 'Actions_WidgetSearchNoResultKeywords';
+ $this->order = 18;
+
+ $this->subcategoryId = 'Actions_SubmenuSitesearch';
}
public function getMetrics()
diff --git a/plugins/Actions/Reports/SiteSearchBase.php b/plugins/Actions/Reports/SiteSearchBase.php
index e30a2243d8..d4715e04e6 100644
--- a/plugins/Actions/Reports/SiteSearchBase.php
+++ b/plugins/Actions/Reports/SiteSearchBase.php
@@ -18,7 +18,7 @@ abstract class SiteSearchBase extends Base
protected function init()
{
parent::init();
- $this->category = 'Actions_SubmenuSitesearch';
+ $this->categoryId = 'General_Actions';
}
public function isEnabled()
diff --git a/plugins/Actions/templates/indexSiteSearch.twig b/plugins/Actions/templates/indexSiteSearch.twig
deleted file mode 100644
index 8d9eaa0909..0000000000
--- a/plugins/Actions/templates/indexSiteSearch.twig
+++ /dev/null
@@ -1,21 +0,0 @@
-<div class="row">
-
- <div class="col-md-6">
- <h2 piwik-enriched-headline>{{ 'Actions_WidgetSearchKeywords'|translate }}</h2>
- {{ keywords|raw }}
-
- <h2 piwik-enriched-headline>{{ 'Actions_WidgetSearchNoResultKeywords'|translate }}</h2>
- {{ noResultKeywords|raw }}
-
- {% if categories is defined %}
- <h2 piwik-enriched-headline>{{ 'Actions_WidgetSearchCategories'|translate }}</h2>
- {{ categories|raw }}
- {% endif %}
- </div>
-
- <div class="col-md-6">
- <h2 piwik-enriched-headline>{{ 'Actions_WidgetPageUrlsFollowingSearch'|translate }}</h2>
- {{ pagesUrlsFollowingSiteSearch|raw }}
- </div>
-
-</div>
diff --git a/plugins/Annotations/javascripts/annotations.js b/plugins/Annotations/javascripts/annotations.js
index 28adbc126b..90ebee273c 100755
--- a/plugins/Annotations/javascripts/annotations.js
+++ b/plugins/Annotations/javascripts/annotations.js
@@ -45,6 +45,7 @@
var ajaxRequest = new ajaxHelper();
ajaxRequest.addParams(ajaxParams, 'get');
+ ajaxRequest.withTokenInUrl();
ajaxRequest.setCallback(callback);
ajaxRequest.setFormat('html');
ajaxRequest.send(false);
@@ -67,6 +68,7 @@
var ajaxRequest = new ajaxHelper();
ajaxRequest.addParams(ajaxParams, 'get');
+ ajaxRequest.withTokenInUrl();
ajaxRequest.setCallback(callback);
ajaxRequest.setFormat('html');
ajaxRequest.send(false);
@@ -86,6 +88,7 @@
var ajaxRequest = new ajaxHelper();
ajaxRequest.addParams(ajaxParams, 'get');
+ ajaxRequest.withTokenInUrl();
ajaxRequest.setCallback(callback);
ajaxRequest.setFormat('html');
ajaxRequest.send(false);
diff --git a/plugins/Contents/Categories/ContentsSubcategory.php b/plugins/Contents/Categories/ContentsSubcategory.php
new file mode 100644
index 0000000000..735d376e4f
--- /dev/null
+++ b/plugins/Contents/Categories/ContentsSubcategory.php
@@ -0,0 +1,19 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\Contents\Categories;
+
+use Piwik\Category\Subcategory;
+
+class ContentsSubcategory extends Subcategory
+{
+ protected $categoryId = 'General_Actions';
+ protected $id = 'Contents_Contents';
+ protected $order = 45;
+
+}
diff --git a/plugins/Contents/Contents.php b/plugins/Contents/Contents.php
index 8bd0fe8042..df42522cb3 100644
--- a/plugins/Contents/Contents.php
+++ b/plugins/Contents/Contents.php
@@ -21,7 +21,7 @@ class Contents extends \Piwik\Plugin
'Metrics.getDefaultMetricTranslations' => 'addMetricTranslations',
'Metrics.getDefaultMetricDocumentationTranslations' => 'addMetricDocumentationTranslations',
'AssetManager.getJavaScriptFiles' => 'getJsFiles',
- 'AssetManager.getStylesheetFiles' => 'getStylesheetFiles',
+ 'AssetManager.getStylesheetFiles' => 'getStylesheetFiles'
);
}
diff --git a/plugins/Contents/Controller.php b/plugins/Contents/Controller.php
deleted file mode 100644
index a17ec3fdce..0000000000
--- a/plugins/Contents/Controller.php
+++ /dev/null
@@ -1,51 +0,0 @@
-<?php
-/**
- * Piwik - free/libre analytics platform
- *
- * @link http://piwik.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- *
- */
-namespace Piwik\Plugins\Contents;
-
-use Piwik\Plugin\Report;
-use Piwik\View;
-
-class Controller extends \Piwik\Plugin\Controller
-{
-
- public function index()
- {
- $reportsView = new View\ReportsByDimension('Contents');
-
- /** @var \Piwik\Plugin\Report[] $reports */
- $contentNames = Report::factory($this->pluginName, 'getContentNames');
- $contentPieces = Report::factory($this->pluginName, 'getContentPieces');
- $reports = array($contentNames, $contentPieces);
-
- foreach($reports as $report) {
- $reportsView->addReport(
- $report->getCategory(),
- $report->getName(),
- 'Contents.' . Report::PREFIX_ACTION_IN_MENU . ucfirst($report->getAction())
- );
- }
-
- return $reportsView->render();
- }
-
- public function menuGetContentNames()
- {
- $report = Report::factory($this->pluginName, 'getContentNames');
-
- return View::singleReport($report->getName(), $report->render());
- }
-
- public function menuGetContentPieces()
- {
- $report = Report::factory($this->pluginName, 'getContentPieces');
-
- return View::singleReport($report->getName(), $report->render());
- }
-
-}
diff --git a/plugins/Contents/Menu.php b/plugins/Contents/Menu.php
deleted file mode 100644
index 2e0d25bb7f..0000000000
--- a/plugins/Contents/Menu.php
+++ /dev/null
@@ -1,24 +0,0 @@
-<?php
-/**
- * Piwik - free/libre analytics platform
- *
- * @link http://piwik.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- *
- */
-namespace Piwik\Plugins\Contents;
-
-use Piwik\Menu\MenuReporting;
-
-/**
- * This class allows you to add, remove or rename menu items.
- * To configure a menu (such as Admin Menu, Reporting Menu, User Menu...) simply call the corresponding methods as
- * described in the API-Reference http://developer.piwik.org/api-reference/Piwik/Menu/MenuAbstract
- */
-class Menu extends \Piwik\Plugin\Menu
-{
- public function configureReportingMenu(MenuReporting $menu)
- {
- $menu->addActionsItem('Contents_Contents', array('module' => 'Contents', 'action' => 'index'), $orderId = 40);
- }
-}
diff --git a/plugins/Contents/Reports/Base.php b/plugins/Contents/Reports/Base.php
index b1ea92d075..e323bebdbe 100644
--- a/plugins/Contents/Reports/Base.php
+++ b/plugins/Contents/Reports/Base.php
@@ -13,12 +13,22 @@ use Piwik\Piwik;
use Piwik\Plugin\Report;
use Piwik\Plugin\ViewDataTable;
use Piwik\Plugins\Contents\Dimensions;
+use Piwik\Report\ReportWidgetFactory;
+use Piwik\Widget\WidgetsList;
abstract class Base extends Report
{
protected function init()
{
- $this->category = 'General_Actions';
+ $this->categoryId = 'General_Actions';
+ $this->subcategoryId = 'Contents_Contents';
+ }
+
+ public function configureWidgets(WidgetsList $widgetsList, ReportWidgetFactory $factory)
+ {
+ $widget = $factory->createWidget();
+
+ $widgetsList->addToContainerWidget('Contents', $widget);
}
/**
diff --git a/plugins/Contents/Reports/GetContentNames.php b/plugins/Contents/Reports/GetContentNames.php
index d217af5d71..6afb8e071e 100644
--- a/plugins/Contents/Reports/GetContentNames.php
+++ b/plugins/Contents/Reports/GetContentNames.php
@@ -32,7 +32,6 @@ class GetContentNames extends Base
$this->order = 35;
$this->actionToLoadSubTables = 'getContentNames';
- $this->widgetTitle = 'Contents_ContentName';
$this->metrics = array('nb_impressions', 'nb_interactions');
$this->processedMetrics = array(new InteractionRate());
}
diff --git a/plugins/Contents/Reports/GetContentPieces.php b/plugins/Contents/Reports/GetContentPieces.php
index 7ab3f1ed1c..ede8da9405 100644
--- a/plugins/Contents/Reports/GetContentPieces.php
+++ b/plugins/Contents/Reports/GetContentPieces.php
@@ -32,8 +32,6 @@ class GetContentPieces extends Base
$this->order = 36;
$this->actionToLoadSubTables = 'getContentPieces';
- $this->widgetTitle = 'Contents_ContentPiece';
-
$this->metrics = array('nb_impressions', 'nb_interactions');
$this->processedMetrics = array(new InteractionRate());
}
diff --git a/plugins/Contents/Widgets/ContentsByDimension.php b/plugins/Contents/Widgets/ContentsByDimension.php
new file mode 100644
index 0000000000..3f2291e8d8
--- /dev/null
+++ b/plugins/Contents/Widgets/ContentsByDimension.php
@@ -0,0 +1,21 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\Contents\Widgets;
+
+use Piwik\Plugins\CoreHome\CoreHome;
+use Piwik\Widget\WidgetContainerConfig;
+
+class ContentsByDimension extends WidgetContainerConfig
+{
+ protected $layout = CoreHome::WIDGET_CONTAINER_LAYOUT_BY_DIMENSION;
+ protected $id = 'Contents';
+ protected $categoryId = 'General_Actions';
+ protected $subcategoryId = 'Contents_Contents';
+
+}
diff --git a/plugins/Contents/tests/System/expected/.gitkeep b/plugins/Contents/tests/System/expected/.gitkeep
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/plugins/Contents/tests/System/expected/.gitkeep
diff --git a/plugins/Contents/tests/System/expected/test_Contents_Contents.getContentNames_lastN__API.getProcessedReport_day.xml b/plugins/Contents/tests/System/expected/test_Contents_Contents.getContentNames_lastN__API.getProcessedReport_day.xml
index 17f90f27bc..35ee103b17 100644
--- a/plugins/Contents/tests/System/expected/test_Contents_Contents.getContentNames_lastN__API.getProcessedReport_day.xml
+++ b/plugins/Contents/tests/System/expected/test_Contents_Contents.getContentNames_lastN__API.getProcessedReport_day.xml
@@ -4,6 +4,7 @@
<prettyDate>January 3 – 9, 2010</prettyDate>
<metadata>
<category>Actions</category>
+ <subcategory>Contents</subcategory>
<name>Content Name</name>
<module>Contents</module>
<action>getContentNames</action>
diff --git a/plugins/Contents/tests/System/expected/test_Contents_Contents.getContentPieces_lastN__API.getProcessedReport_day.xml b/plugins/Contents/tests/System/expected/test_Contents_Contents.getContentPieces_lastN__API.getProcessedReport_day.xml
index b1e6277b3d..d7e5a543f8 100644
--- a/plugins/Contents/tests/System/expected/test_Contents_Contents.getContentPieces_lastN__API.getProcessedReport_day.xml
+++ b/plugins/Contents/tests/System/expected/test_Contents_Contents.getContentPieces_lastN__API.getProcessedReport_day.xml
@@ -4,6 +4,7 @@
<prettyDate>January 3 – 9, 2010</prettyDate>
<metadata>
<category>Actions</category>
+ <subcategory>Contents</subcategory>
<name>Content Piece</name>
<module>Contents</module>
<action>getContentPieces</action>
diff --git a/plugins/CoreAdminHome/javascripts/generalSettings.js b/plugins/CoreAdminHome/javascripts/generalSettings.js
index 5ac87afb57..e691ce72b9 100644
--- a/plugins/CoreAdminHome/javascripts/generalSettings.js
+++ b/plugins/CoreAdminHome/javascripts/generalSettings.js
@@ -38,6 +38,7 @@ function sendGeneralSettingsAJAX() {
module: 'CoreAdminHome',
action: 'setGeneralSettings'
}, 'GET');
+ ajaxHandler.withTokenInUrl();
ajaxHandler.redirectOnSuccess();
ajaxHandler.send(true);
}
diff --git a/plugins/CoreConsole/Commands/GenerateReport.php b/plugins/CoreConsole/Commands/GenerateReport.php
index 9eb7313400..3f9fda4939 100644
--- a/plugins/CoreConsole/Commands/GenerateReport.php
+++ b/plugins/CoreConsole/Commands/GenerateReport.php
@@ -10,8 +10,10 @@
namespace Piwik\Plugins\CoreConsole\Commands;
use Piwik\Columns\Dimension;
+use Piwik\Piwik;
use Piwik\Plugin\Manager;
use Piwik\Plugin\Report;
+use Piwik\Plugin\Reports;
use Piwik\Translate;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
@@ -67,8 +69,8 @@ class GenerateReport extends GeneratePluginBase
$this->copyTemplateToPlugin($exampleFolder, $pluginName, $replace, $whitelistFiles);
$this->writeSuccessMessage($output, array(
- sprintf('Reports/%s.php for %s generated.', ucfirst($apiName), $pluginName),
- 'You should now implement the method called "' . lcfirst($apiName) . '" in API.php',
+ sprintf('plugins/%s/Reports/%s.php for %s generated.', $pluginName, ucfirst($apiName)),
+ 'You should now implement the method called <comment>"' . lcfirst($apiName) . '()"</comment> in API.php',
// 'Read more about this here: link to developer guide',
'Enjoy!'
));
@@ -78,8 +80,10 @@ class GenerateReport extends GeneratePluginBase
{
$order = 1;
- foreach (Report::getAllReports() as $report) {
- if ($report->getCategory() === $category) {
+ $reports = new Reports();
+
+ foreach ($reports->getAllReports() as $report) {
+ if ($report->getCategoryId() === $category) {
if ($report->getOrder() > $order) {
$order = $report->getOrder() + 1;
}
@@ -189,10 +193,12 @@ class GenerateReport extends GeneratePluginBase
$category = $input->getOption('category');
+ $reports = new Reports();
+
$categories = array();
- foreach (Report::getAllReports() as $report) {
- if ($report->getCategory()) {
- $categories[] = $report->getCategory();
+ foreach ($reports->getAllReports() as $report) {
+ if ($report->getCategoryId()) {
+ $categories[] = Piwik::translate($report->getCategoryId());
}
}
$categories = array_values(array_unique($categories));
@@ -226,7 +232,9 @@ class GenerateReport extends GeneratePluginBase
$dimensions = array();
$dimensionNames = array();
- foreach (Report::getAllReports() as $report) {
+ $reports = new Reports();
+
+ foreach ($reports->getAllReports() as $report) {
$dimension = $report->getDimension();
if (is_object($dimension)) {
$name = $dimension->getName();
diff --git a/plugins/CoreConsole/Commands/GenerateWidget.php b/plugins/CoreConsole/Commands/GenerateWidget.php
index da4f8e349d..c04c30cd55 100644
--- a/plugins/CoreConsole/Commands/GenerateWidget.php
+++ b/plugins/CoreConsole/Commands/GenerateWidget.php
@@ -10,8 +10,8 @@
namespace Piwik\Plugins\CoreConsole\Commands;
use Piwik\Piwik;
-use Piwik\Plugin\Widgets;
use Piwik\Translate;
+use Piwik\Widget\WidgetsList;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
@@ -25,6 +25,7 @@ class GenerateWidget extends GeneratePluginBase
$this->setName('generate:widget')
->setDescription('Adds a plugin widget class to an existing plugin')
->addOption('pluginname', null, InputOption::VALUE_REQUIRED, 'The name of an existing plugin which does not have any widgets defined yet')
+ ->addOption('widgetname', null, InputOption::VALUE_REQUIRED, 'The name of the widget you want to create')
->addOption('category', null, InputOption::VALUE_REQUIRED, 'The name of the category the widget should belong to');
}
@@ -33,6 +34,7 @@ class GenerateWidget extends GeneratePluginBase
$pluginName = $this->getPluginName($input, $output);
$this->checkAndUpdateRequiredPiwikVersion($pluginName, $output);
+ $widgetName = $this->getWidgetName($input, $output);
$category = $this->getCategory($input, $output);
if ($category === Piwik::translate($category)) {
@@ -40,26 +42,78 @@ class GenerateWidget extends GeneratePluginBase
$category = $this->makeTranslationIfPossible($pluginName, $category);
}
+ $widgetMethod = $this->getWidgetMethodName($widgetName);
+ $widgetClass = ucfirst($widgetMethod);
+
$exampleFolder = PIWIK_INCLUDE_PATH . '/plugins/ExamplePlugin';
- $replace = array('ExamplePlugin' => $pluginName,
- 'Example Category' => $category);
- $whitelistFiles = array('/Widgets.php');
+ $replace = array('ExamplePlugin' => $pluginName,
+ 'MyExampleWidget' => $widgetClass,
+ 'Example Widget Name' => $this->makeTranslationIfPossible($pluginName, $widgetName),
+ 'About Piwik' => $category);
+ $whitelistFiles = array('/Widgets', '/Widgets/MyExampleWidget.php');
$this->copyTemplateToPlugin($exampleFolder, $pluginName, $replace, $whitelistFiles);
$this->writeSuccessMessage($output, array(
- sprintf('Widgets.php for %s generated.', $pluginName),
- 'You can now start defining your plugin widgets',
+ sprintf('plugins/%s/Widgets/%s.php generated.', $pluginName, $widgetClass),
+ 'You can now start implementing the <comment>render()</comment> method.',
'Enjoy!'
));
}
+ private function getWidgetMethodName($methodName)
+ {
+ $methodName = trim($methodName);
+ $methodName = str_replace(' ', '', $methodName);
+ $methodName = preg_replace("/[^A-Za-z0-9]/", '', $methodName);
+
+ if (0 !== strpos(strtolower($methodName), 'get')) {
+ $methodName = 'get' . ucfirst($methodName);
+ }
+
+ return lcfirst($methodName);
+ }
+
+ /**
+ * @param InputInterface $input
+ * @param OutputInterface $output
+ * @return array
+ * @throws \RuntimeException
+ */
+ protected function getWidgetName(InputInterface $input, OutputInterface $output)
+ {
+ $validate = function ($widgetName) {
+ if (empty($widgetName)) {
+ throw new \InvalidArgumentException('Please enter the name of your widget');
+ }
+
+ if (preg_match("/[^A-Za-z0-9 ]/", $widgetName)) {
+ throw new \InvalidArgumentException('Only alpha numerical characters and whitespaces are allowed');
+ }
+
+ return $widgetName;
+ };
+
+ $widgetName = $input->getOption('widgetname');
+
+ if (empty($widgetName)) {
+ $dialog = $this->getHelperSet()->get('dialog');
+ $widgetName = $dialog->askAndValidate($output, 'Enter the name of your Widget, for instance "Browser Families": ', $validate);
+ } else {
+ $validate($widgetName);
+ }
+
+ $widgetName = ucfirst($widgetName);
+
+ return $widgetName;
+ }
+
protected function getExistingCategories()
{
$categories = array();
- foreach (Widgets::getAllWidgets() as $widget) {
- if ($widget->getCategory()) {
- $categories[] = Piwik::translate($widget->getCategory());
+ foreach (WidgetsList::get()->getWidgetConfigs() as $widget) {
+ if ($widget->getCategoryId()) {
+ $categories[] = Piwik::translate($widget->getCategoryId());
}
}
$categories = array_values(array_unique($categories));
@@ -111,8 +165,8 @@ class GenerateWidget extends GeneratePluginBase
*/
protected function getPluginName(InputInterface $input, OutputInterface $output)
{
- $pluginNames = $this->getPluginNamesHavingNotSpecificFile('Widgets.php');
- $invalidName = 'You have to enter the name of an existing plugin which does not already have any widgets defined';
+ $pluginNames = $this->getPluginNames();
+ $invalidName = 'You have to enter a name of an existing plugin.';
return $this->askPluginNameAndValidate($input, $output, $pluginNames, $invalidName);
}
diff --git a/plugins/CoreConsole/Commands/ManagePlugin.php b/plugins/CoreConsole/Commands/ManagePlugin.php
deleted file mode 100644
index 3f07918f7c..0000000000
--- a/plugins/CoreConsole/Commands/ManagePlugin.php
+++ /dev/null
@@ -1,108 +0,0 @@
-<?php
-/**
- * Piwik - free/libre analytics platform
- *
- * @link http://piwik.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- */
-
-namespace Piwik\Plugins\CoreConsole\Commands;
-
-use Piwik\Plugin\ConsoleCommand;
-use Piwik\Plugins\CorePluginsAdmin\Commands\ActivatePlugin;
-use Piwik\Plugins\CorePluginsAdmin\Commands\DeactivatePlugin;
-use Piwik\Plugins\CorePluginsAdmin\Commands\ListPlugins;
-use Symfony\Component\Console\Input\ArrayInput;
-use Symfony\Component\Console\Input\InputArgument;
-use Symfony\Component\Console\Input\InputInterface;
-use Symfony\Component\Console\Input\InputOption;
-use Symfony\Component\Console\Output\OutputInterface;
-
-/**
- * core:plugin console command.
- *
- * @deprecated This command has been replaced with `plugin:*` commands.
- */
-class ManagePlugin extends ConsoleCommand
-{
- private $operations = array();
-
- protected function configure()
- {
- $this->setName('core:plugin');
- $this->setDescription("Perform various actions regarding one or more plugins.");
- $this->addArgument("operation", InputArgument::REQUIRED, "Operation to apply (can be 'activate' or 'deactivate' or 'list').");
- $this->addArgument("plugins", InputArgument::OPTIONAL | InputArgument::IS_ARRAY, 'Plugin name(s) to activate.');
- $this->addOption('domain', null, InputOption::VALUE_REQUIRED, "The domain to activate the plugin for.");
-
- $this->operations['activate'] = 'activatePlugin';
- $this->operations['deactivate'] = 'deactivatePlugin';
- $this->operations['list'] = 'listPlugins';
- }
-
- /**
- * Execute command like: ./console core:plugin activate CustomAlerts --piwik-domain=testcustomer.piwik.pro
- */
- protected function execute(InputInterface $input, OutputInterface $output)
- {
- $operation = $input->getArgument("operation");
- $plugins = $input->getArgument('plugins');
-
- if (empty($this->operations[$operation])) {
- throw new \Exception("Invalid operation '$operation'.");
- }
-
- $fn = $this->operations[$operation];
-
-
- if($fn == 'listPlugins') {
- call_user_func(array($this, $fn), $input, $output);
- } else {
- $this->applyOperationToEachPlugin($input, $output, $plugins, $fn);
- }
- }
-
- /**
- * @param InputInterface $input
- * @param OutputInterface $output
- * @param $plugins
- * @param $fn
- */
- protected function applyOperationToEachPlugin(InputInterface $input, OutputInterface $output, $plugins, $fn)
- {
- foreach ($plugins as $plugin) {
- call_user_func(array($this, $fn), $input, $output, $plugin);
- }
- }
-
- private function activatePlugin(InputInterface $input, OutputInterface $output, $plugin)
- {
- $output->writeln('<comment>Warning: the command core:plugin is deprecated, use plugin:activate instead.</comment>');
-
- $command = new ActivatePlugin();
- $input = new ArrayInput(array(
- 'plugin' => $plugin,
- ));
- return $command->run($input, $output);
- }
-
- private function deactivatePlugin(InputInterface $input, OutputInterface $output, $plugin)
- {
- $output->writeln('<comment>Warning: the command core:plugin is deprecated, use plugin:deactivate instead.</comment>');
-
- $command = new DeactivatePlugin();
- $input = new ArrayInput(array(
- 'plugin' => $plugin,
- ));
- return $command->run($input, $output);
- }
-
- private function listPlugins(InputInterface $input, OutputInterface $output)
- {
- $output->writeln('<comment>Warning: the command core:plugin is deprecated, use plugin:list instead.</comment>');
-
- $command = new ListPlugins();
- $input = new ArrayInput(array());
- return $command->run($input, $output);
- }
-} \ No newline at end of file
diff --git a/plugins/CoreHome/Categories/ActionsCategory.php b/plugins/CoreHome/Categories/ActionsCategory.php
new file mode 100644
index 0000000000..a7f1c57276
--- /dev/null
+++ b/plugins/CoreHome/Categories/ActionsCategory.php
@@ -0,0 +1,18 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\CoreHome\Categories;
+
+use Piwik\Category\Category;
+
+class ActionsCategory extends Category
+{
+ protected $id = 'General_Actions';
+ protected $order = 10;
+ protected $icon = 'icon-reporting-actions';
+}
diff --git a/plugins/CoreHome/Categories/DevicesSubcategory.php b/plugins/CoreHome/Categories/DevicesSubcategory.php
new file mode 100644
index 0000000000..9d68e5b30c
--- /dev/null
+++ b/plugins/CoreHome/Categories/DevicesSubcategory.php
@@ -0,0 +1,19 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\CoreHome\Categories;
+
+use Piwik\Category\Subcategory;
+
+class DevicesSubcategory extends Subcategory
+{
+ protected $categoryId = 'General_Visitors';
+ protected $id = 'DevicesDetection_Devices';
+ protected $order = 15;
+
+}
diff --git a/plugins/CoreHome/Categories/EngagementSubcategory.php b/plugins/CoreHome/Categories/EngagementSubcategory.php
new file mode 100644
index 0000000000..1a4f4b1d40
--- /dev/null
+++ b/plugins/CoreHome/Categories/EngagementSubcategory.php
@@ -0,0 +1,19 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\CoreHome\Categories;
+
+use Piwik\Category\Subcategory;
+
+class EngagementSubcategory extends Subcategory
+{
+ protected $categoryId = 'General_Visitors';
+ protected $id = 'VisitorInterest_Engagement';
+ protected $order = 30;
+
+}
diff --git a/plugins/CoreHome/Categories/SoftwareSubcategory.php b/plugins/CoreHome/Categories/SoftwareSubcategory.php
new file mode 100644
index 0000000000..34188afe97
--- /dev/null
+++ b/plugins/CoreHome/Categories/SoftwareSubcategory.php
@@ -0,0 +1,19 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\CoreHome\Categories;
+
+use Piwik\Category\Subcategory;
+
+class SoftwareSubcategory extends Subcategory
+{
+ protected $categoryId = 'General_Visitors';
+ protected $id = 'DevicesDetection_Software';
+ protected $order = 20;
+
+}
diff --git a/plugins/CoreHome/Categories/VisitorsCategory.php b/plugins/CoreHome/Categories/VisitorsCategory.php
new file mode 100644
index 0000000000..1327c7b955
--- /dev/null
+++ b/plugins/CoreHome/Categories/VisitorsCategory.php
@@ -0,0 +1,18 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\CoreHome\Categories;
+
+use Piwik\Category\Category;
+
+class VisitorsCategory extends Category
+{
+ protected $id = 'General_Visitors';
+ protected $order = 5;
+ protected $icon = 'icon-reporting-visitors';
+}
diff --git a/plugins/CoreHome/Categories/VisitorsOverviewSubcategory.php b/plugins/CoreHome/Categories/VisitorsOverviewSubcategory.php
new file mode 100644
index 0000000000..3db3e260d2
--- /dev/null
+++ b/plugins/CoreHome/Categories/VisitorsOverviewSubcategory.php
@@ -0,0 +1,19 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\CoreHome\Categories;
+
+use Piwik\Category\Subcategory;
+
+class VisitorsOverviewSubcategory extends Subcategory
+{
+ protected $categoryId = 'General_Visitors';
+ protected $id = 'General_Overview';
+ protected $order = 2;
+
+}
diff --git a/plugins/CoreHome/Columns/Metrics/AverageTimeOnSite.php b/plugins/CoreHome/Columns/Metrics/AverageTimeOnSite.php
index e590e19871..b56364aa7f 100644
--- a/plugins/CoreHome/Columns/Metrics/AverageTimeOnSite.php
+++ b/plugins/CoreHome/Columns/Metrics/AverageTimeOnSite.php
@@ -38,7 +38,7 @@ class AverageTimeOnSite extends ProcessedMetric
public function format($value, Formatter $formatter)
{
- return $formatter->getPrettyTimeFromSeconds($value);
+ return $formatter->getPrettyTimeFromSeconds($value, true);
}
public function getTranslatedName()
diff --git a/plugins/CoreHome/Controller.php b/plugins/CoreHome/Controller.php
index a61419e5fb..cf4be9b446 100644
--- a/plugins/CoreHome/Controller.php
+++ b/plugins/CoreHome/Controller.php
@@ -11,12 +11,13 @@ namespace Piwik\Plugins\CoreHome;
use Exception;
use Piwik\API\Request;
use Piwik\Common;
+use Piwik\DataTable\Renderer\Json;
use Piwik\Date;
use Piwik\FrontController;
-use Piwik\Menu\MenuReporting;
use Piwik\Notification\Manager as NotificationManager;
use Piwik\Piwik;
use Piwik\Plugin\Report;
+use Piwik\Widget\Widget;
use Piwik\Plugins\CoreHome\DataTableRowAction\MultiRowEvolution;
use Piwik\Plugins\CoreHome\DataTableRowAction\RowEvolution;
use Piwik\Plugins\CorePluginsAdmin\MarketplaceApiClient;
@@ -28,7 +29,6 @@ use Piwik\UpdateCheck;
use Piwik\Url;
use Piwik\View;
use Piwik\ViewDataTable\Manager as ViewDataTableManager;
-use Piwik\Plugin\Widgets as PluginWidgets;
class Controller extends \Piwik\Plugin\Controller
{
@@ -49,40 +49,38 @@ class Controller extends \Piwik\Plugin\Controller
return 'redirectToCoreHomeIndex';
}
- public function renderReportMenu(Report $report)
+ public function renderReportWidget(Report $report)
{
Piwik::checkUserHasSomeViewAccess();
$this->checkSitePermission();
$report->checkIsEnabled();
- $menuTitle = $report->getMenuTitle();
-
- if (empty($menuTitle)) {
- throw new Exception('This report is not supposed to be displayed in the menu, please define a $menuTitle in your report.');
- }
-
- $menuTitle = $this->translator->translate($menuTitle);
- $content = $this->renderReportWidget($report);
-
- return View::singleReport($menuTitle, $content);
+ return $report->render();
}
- public function renderReportWidget(Report $report)
+ public function renderWidgetContainer()
{
Piwik::checkUserHasSomeViewAccess();
$this->checkSitePermission();
- $report->checkIsEnabled();
+ $view = new View('@CoreHome/widgetContainer');
+ $view->isWidgetized = (bool) Common::getRequestVar('widget', 0, 'int');
+ $view->containerId = Common::getRequestVar('containerId', null, 'string');
- return $report->render();
+ return $view->render();
}
- public function renderWidget(PluginWidgets $widget, $method)
+ /**
+ * @param Widget $widget
+ * @return mixed
+ * @throws Exception
+ */
+ public function renderWidget($widget)
{
Piwik::checkUserHasSomeViewAccess();
- return $widget->$method();
+ return $widget->render();
}
function redirectToCoreHomeIndex()
@@ -133,7 +131,7 @@ class Controller extends \Piwik\Plugin\Controller
{
$view = new View('@CoreHome/getDefaultIndexView');
$this->setGeneralVariablesView($view);
- $view->menu = MenuReporting::getInstance()->getMenu();
+ $view->showMenu = true;
$view->dashboardSettingsControl = new DashboardManagerControl();
$view->content = '';
return $view;
diff --git a/plugins/CoreHome/CoreHome.php b/plugins/CoreHome/CoreHome.php
index 52cfa2de5d..9e6afdb107 100644
--- a/plugins/CoreHome/CoreHome.php
+++ b/plugins/CoreHome/CoreHome.php
@@ -14,6 +14,13 @@ namespace Piwik\Plugins\CoreHome;
class CoreHome extends \Piwik\Plugin
{
/**
+ * Defines a widget container layout that will display all widgets within a container inside a "tab" menu
+ * where on the left side a link is shown for each widget and on the right side the selected widget.
+ * @api
+ */
+ const WIDGET_CONTAINER_LAYOUT_BY_DIMENSION = 'ByDimension';
+
+ /**
* @see Piwik\Plugin::registerEvents
*/
public function registerEvents()
@@ -107,8 +114,6 @@ class CoreHome extends \Piwik\Plugin
$jsFiles[] = "plugins/CoreHome/javascripts/dataTable_rowactions.js";
$jsFiles[] = "plugins/CoreHome/javascripts/popover.js";
$jsFiles[] = "plugins/CoreHome/javascripts/broadcast.js";
- $jsFiles[] = "plugins/CoreHome/javascripts/menu.js";
- $jsFiles[] = "plugins/CoreHome/javascripts/menu_init.js";
$jsFiles[] = "plugins/CoreHome/javascripts/calendar.js";
$jsFiles[] = "plugins/CoreHome/javascripts/sparkline.js";
$jsFiles[] = "plugins/CoreHome/javascripts/corehome.js";
@@ -123,8 +128,12 @@ class CoreHome extends \Piwik\Plugin
$jsFiles[] = "plugins/CoreHome/angularjs/piwikApp.config.js";
$jsFiles[] = "plugins/CoreHome/angularjs/common/services/service.module.js";
+ $jsFiles[] = "plugins/CoreHome/angularjs/common/services/global-ajax-queue.js";
$jsFiles[] = "plugins/CoreHome/angularjs/common/services/piwik.js";
$jsFiles[] = "plugins/CoreHome/angularjs/common/services/piwik-api.js";
+ $jsFiles[] = "plugins/CoreHome/angularjs/common/services/piwik-url.js";
+ $jsFiles[] = "plugins/CoreHome/angularjs/common/services/report-metadata-model.js";
+ $jsFiles[] = "plugins/CoreHome/angularjs/common/services/reporting-pages-model.js";
$jsFiles[] = "plugins/CoreHome/angularjs/common/filters/filter.module.js";
$jsFiles[] = "plugins/CoreHome/angularjs/common/filters/translate.js";
@@ -133,6 +142,7 @@ class CoreHome extends \Piwik\Plugin
$jsFiles[] = "plugins/CoreHome/angularjs/common/filters/length.js";
$jsFiles[] = "plugins/CoreHome/angularjs/common/filters/trim.js";
$jsFiles[] = "plugins/CoreHome/angularjs/common/filters/pretty-url.js";
+ $jsFiles[] = "plugins/CoreHome/angularjs/common/filters/escape.js";
$jsFiles[] = "plugins/CoreHome/angularjs/common/filters/htmldecode.js";
$jsFiles[] = "plugins/CoreHome/angularjs/common/filters/ucfirst.js";
@@ -151,6 +161,8 @@ class CoreHome extends \Piwik\Plugin
$jsFiles[] = "plugins/CoreHome/angularjs/history/history.service.js";
+ $jsFiles[] = "plugins/CoreHome/angularjs/activity-indicator/activityindicator.directive.js";
+
$jsFiles[] = "plugins/CoreHome/angularjs/siteselector/siteselector-model.service.js";
$jsFiles[] = "plugins/CoreHome/angularjs/siteselector/siteselector.controller.js";
$jsFiles[] = "plugins/CoreHome/angularjs/siteselector/siteselector.directive.js";
@@ -169,6 +181,21 @@ class CoreHome extends \Piwik\Plugin
$jsFiles[] = "plugins/CoreHome/angularjs/ajax-form/ajax-form.controller.js";
$jsFiles[] = "plugins/CoreHome/angularjs/ajax-form/ajax-form.directive.js";
+ $jsFiles[] = "plugins/CoreHome/angularjs/widget-loader/widgetloader.directive.js";
+ $jsFiles[] = "plugins/CoreHome/angularjs/widget-bydimension-container/widget-bydimension-container.directive.js";
+ $jsFiles[] = "plugins/CoreHome/angularjs/widget-container/widgetcontainer.directive.js";
+ $jsFiles[] = "plugins/CoreHome/angularjs/widget/widget.directive.js";
+
+ $jsFiles[] = "plugins/CoreHome/angularjs/popover-handler/popover-handler.directive.js";
+
+ $jsFiles[] = "plugins/CoreHome/angularjs/reporting-page/reportingpage.controller.js";
+ $jsFiles[] = "plugins/CoreHome/angularjs/reporting-page/reportingpage-model.js";
+ $jsFiles[] = "plugins/CoreHome/angularjs/reporting-page/reportingpage.directive.js";
+
+ $jsFiles[] = "plugins/CoreHome/angularjs/reporting-menu/reportingmenu.controller.js";
+ $jsFiles[] = "plugins/CoreHome/angularjs/reporting-menu/reportingmenu-model.js";
+ $jsFiles[] = "plugins/CoreHome/angularjs/reporting-menu/reportingmenu.directive.js";
+
$jsFiles[] = "plugins/CoreHome/angularjs/quick-access/quick-access.controller.js";
$jsFiles[] = "plugins/CoreHome/angularjs/quick-access/quick-access.directive.js";
@@ -273,10 +300,13 @@ class CoreHome extends \Piwik\Plugin
$translationKeys[] = 'General_LearnMore';
$translationKeys[] = 'CoreHome_UndoPivotBySubtable';
$translationKeys[] = 'CoreHome_PivotBySubtable';
+ $translationKeys[] = 'General_LearnMore';
+ $translationKeys[] = 'CoreHome_NoSuchPage';
$translationKeys[] = 'CoreHome_QuickAccessTitle';
$translationKeys[] = 'CoreHome_Segments';
$translationKeys[] = 'CoreHome_MenuEntries';
$translationKeys[] = 'SitesManager_Sites';
+ $translationKeys[] = 'CoreHome_MainNavigation';
$translationKeys[] = 'CoreHome_ChangeCurrentWebsite';
$translationKeys[] = 'General_CreatedByUser';
}
diff --git a/plugins/CoreHome/Widgets.php b/plugins/CoreHome/Widgets.php
deleted file mode 100644
index 1a2c945bff..0000000000
--- a/plugins/CoreHome/Widgets.php
+++ /dev/null
@@ -1,63 +0,0 @@
-<?php
-/**
- * Piwik - free/libre analytics platform
- *
- * @link http://piwik.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- *
- */
-namespace Piwik\Plugins\CoreHome;
-
-use Piwik\Common;
-use Piwik\Piwik;
-use Piwik\Translation\Translator;
-use Piwik\View;
-
-class Widgets extends \Piwik\Plugin\Widgets
-{
- protected $category = 'About Piwik';
-
- /**
- * @var Translator
- */
- private $translator;
-
- public function __construct(Translator $translator)
- {
- $this->translator = $translator;
- }
-
- protected function init()
- {
- $this->addWidget('CoreHome_SupportPiwik', 'getDonateForm');
- $this->addWidget('Installation_Welcome', 'getPromoVideo');
- }
-
- /**
- * Renders and echo's the in-app donate form w/ slider.
- */
- public function getDonateForm()
- {
- $view = new View('@CoreHome/getDonateForm');
-
- if (Common::getRequestVar('widget', false)
- && Piwik::hasUserSuperUserAccess()) {
- $view->footerMessage = $this->translator->translate('CoreHome_OnlyForSuperUserAccess');
- }
-
- return $view->render();
- }
-
- /**
- * Renders and echo's HTML that displays the Piwik promo video.
- */
- public function getPromoVideo()
- {
- $view = new View('@CoreHome/getPromoVideo');
- $view->shareText = $this->translator->translate('CoreHome_SharePiwikShort');
- $view->shareTextLong = $this->translator->translate('CoreHome_SharePiwikLong');
- $view->promoVideoUrl = 'https://www.youtube.com/watch?v=OslfF_EH81g';
-
- return $view->render();
- }
-}
diff --git a/plugins/CoreHome/Widgets/GetDonateForm.php b/plugins/CoreHome/Widgets/GetDonateForm.php
new file mode 100644
index 0000000000..081afd9c03
--- /dev/null
+++ b/plugins/CoreHome/Widgets/GetDonateForm.php
@@ -0,0 +1,48 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\CoreHome\Widgets;
+
+use Piwik\Common;
+use Piwik\Piwik;
+use Piwik\Widget\Widget;
+use Piwik\Widget\WidgetConfig;
+use Piwik\Translation\Translator;
+use Piwik\View;
+
+class GetDonateForm extends Widget
+{
+ /**
+ * @var Translator
+ */
+ private $translator;
+
+ public function __construct(Translator $translator)
+ {
+ $this->translator = $translator;
+ }
+
+ public static function configure(WidgetConfig $config)
+ {
+ $config->setCategoryId('About Piwik');
+ $config->setName('CoreHome_SupportPiwik');
+ $config->setOrder(5);
+ }
+
+ public function render()
+ {
+ $view = new View('@CoreHome/getDonateForm');
+
+ if (Common::getRequestVar('widget', false)
+ && Piwik::hasUserSuperUserAccess()) {
+ $view->footerMessage = $this->translator->translate('CoreHome_OnlyForSuperUserAccess');
+ }
+
+ return $view->render();
+ }
+} \ No newline at end of file
diff --git a/plugins/CoreHome/Widgets/GetPromoVideo.php b/plugins/CoreHome/Widgets/GetPromoVideo.php
new file mode 100644
index 0000000000..5ceef91f84
--- /dev/null
+++ b/plugins/CoreHome/Widgets/GetPromoVideo.php
@@ -0,0 +1,44 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\CoreHome\Widgets;
+
+use Piwik\Widget\Widget;
+use Piwik\Widget\WidgetConfig;
+use Piwik\Translation\Translator;
+use Piwik\View;
+
+class GetPromoVideo extends Widget
+{
+ /**
+ * @var Translator
+ */
+ private $translator;
+
+ public function __construct(Translator $translator)
+ {
+ $this->translator = $translator;
+ }
+
+ public static function configure(WidgetConfig $config)
+ {
+ $config->setCategoryId('About Piwik');
+ $config->setName('Installation_Welcome');
+ $config->setOrder(10);
+ }
+
+ public function render()
+ {
+ $view = new View('@CoreHome/getPromoVideo');
+ $view->shareText = $this->translator->translate('CoreHome_SharePiwikShort');
+ $view->shareTextLong = $this->translator->translate('CoreHome_SharePiwikLong');
+ $view->promoVideoUrl = 'https://www.youtube.com/watch?v=OslfF_EH81g';
+
+ return $view->render();
+ }
+} \ No newline at end of file
diff --git a/plugins/CoreHome/angularjs/activity-indicator/activityindicator.directive.js b/plugins/CoreHome/angularjs/activity-indicator/activityindicator.directive.js
new file mode 100644
index 0000000000..4417cea7ac
--- /dev/null
+++ b/plugins/CoreHome/angularjs/activity-indicator/activityindicator.directive.js
@@ -0,0 +1,31 @@
+/*!
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+
+/**
+ * Shows a general loading message while [loading] is set to true.
+ *
+ * @param {Boolean} loading If true, the activity indicator is shown, otherwise the indicator is hidden.
+ *
+ * Example:
+ * <div piwik-activity-indicator loading="true|false"></div>
+ */
+(function () {
+ angular.module('piwikApp').directive('piwikActivityIndicator', piwikActivityIndicator);
+
+ piwikActivityIndicator.$inject = ['piwik'];
+
+ function piwikActivityIndicator(piwik){
+ return {
+ restrict: 'A',
+ transclude: true,
+ scope: {
+ loading: '='
+ },
+ templateUrl: 'plugins/CoreHome/angularjs/activity-indicator/activityindicator.html?cb=' + piwik.cacheBuster
+ };
+ }
+})(); \ No newline at end of file
diff --git a/plugins/CoreHome/angularjs/activity-indicator/activityindicator.html b/plugins/CoreHome/angularjs/activity-indicator/activityindicator.html
new file mode 100644
index 0000000000..f6080ae817
--- /dev/null
+++ b/plugins/CoreHome/angularjs/activity-indicator/activityindicator.html
@@ -0,0 +1,3 @@
+<div ng-show="loading" class="loadingPiwik">
+ <img src="plugins/Morpheus/images/loading-blue.gif" alt=""/>{{ 'General_LoadingData'|translate }}
+</div> \ No newline at end of file
diff --git a/plugins/CoreHome/angularjs/ajax-form/ajax-form.controller.js b/plugins/CoreHome/angularjs/ajax-form/ajax-form.controller.js
index 8a1f3b529c..e1c60b0550 100644
--- a/plugins/CoreHome/angularjs/ajax-form/ajax-form.controller.js
+++ b/plugins/CoreHome/angularjs/ajax-form/ajax-form.controller.js
@@ -75,9 +75,9 @@
});
notification.scrollToNotification();
}
- })['catch'](function (errorMessage) {
+ }).catch(function (errorMessage) {
vm.errorPostResponse = errorMessage;
- })['finally'](function () {
+ }).finally(function () {
vm.isSubmitting = false;
});
}
diff --git a/plugins/CoreHome/angularjs/ajax-form/ajax-form.directive.js b/plugins/CoreHome/angularjs/ajax-form/ajax-form.directive.js
index 89d572cedf..2eef346ec6 100644
--- a/plugins/CoreHome/angularjs/ajax-form/ajax-form.directive.js
+++ b/plugins/CoreHome/angularjs/ajax-form/ajax-form.directive.js
@@ -132,7 +132,9 @@
scope.ajaxForm.data[name] = val;
if (!skipScopeApply) {
- scope.$apply();
+ setTimeout(function () {
+ scope.$apply();
+ }, 0);
}
}
};
diff --git a/plugins/CoreHome/angularjs/common/directives/focus-anywhere-but-here.js b/plugins/CoreHome/angularjs/common/directives/focus-anywhere-but-here.js
index 0617c5df88..ee1a2cf219 100644
--- a/plugins/CoreHome/angularjs/common/directives/focus-anywhere-but-here.js
+++ b/plugins/CoreHome/angularjs/common/directives/focus-anywhere-but-here.js
@@ -24,13 +24,17 @@
function onClickOutsideElement (event) {
if (element.has(event.target).length === 0) {
- scope.$apply(attr.piwikFocusAnywhereButHere);
+ setTimeout(function () {
+ scope.$apply(attr.piwikFocusAnywhereButHere);
+ }, 0);
}
}
function onEscapeHandler (event) {
if (event.which === 27) {
- scope.$apply(attr.piwikFocusAnywhereButHere);
+ setTimeout(function () {
+ scope.$apply(attr.piwikFocusAnywhereButHere);
+ }, 0);
}
}
diff --git a/plugins/CoreHome/angularjs/common/filters/escape.js b/plugins/CoreHome/angularjs/common/filters/escape.js
new file mode 100644
index 0000000000..382e84b5ac
--- /dev/null
+++ b/plugins/CoreHome/angularjs/common/filters/escape.js
@@ -0,0 +1,16 @@
+/*!
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+(function () {
+ angular.module('piwikApp.filter').filter('escape', escape);
+
+ function escape() {
+
+ return function(value) {
+ return piwikHelper.escape(piwikHelper.htmlEntities(value));
+ };
+ }
+})(); \ No newline at end of file
diff --git a/plugins/CoreHome/angularjs/common/services/global-ajax-queue.js b/plugins/CoreHome/angularjs/common/services/global-ajax-queue.js
new file mode 100644
index 0000000000..f831995810
--- /dev/null
+++ b/plugins/CoreHome/angularjs/common/services/global-ajax-queue.js
@@ -0,0 +1,14 @@
+/*!
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+(function () {
+ angular.module('piwikApp.service').service('globalAjaxQueue', ajaxQueue);
+
+ function ajaxQueue() {
+
+ return globalAjaxQueue;
+ }
+})(); \ No newline at end of file
diff --git a/plugins/CoreHome/angularjs/common/services/piwik-api.js b/plugins/CoreHome/angularjs/common/services/piwik-api.js
index f9e5b225a3..8bb14808c5 100644
--- a/plugins/CoreHome/angularjs/common/services/piwik-api.js
+++ b/plugins/CoreHome/angularjs/common/services/piwik-api.js
@@ -38,6 +38,15 @@ var hasBlockedContent = false;
}
}
+ function withTokenInUrl()
+ {
+ postParams['token_auth'] = piwik.token_auth;
+ }
+
+ function isRequestToApiMethod() {
+ return getParams && getParams['module'] === 'API' && getParams['method'];
+ }
+
function reset () {
getParams = {};
postParams = {};
@@ -133,11 +142,11 @@ var hasBlockedContent = false;
},
'finally': function () {
- return addAbortMethod(to['finally'].apply(to, arguments), deferred);
+ return addAbortMethod(to.finally.apply(to, arguments), deferred);
},
'catch': function () {
- return addAbortMethod(to['catch'].apply(to, arguments), deferred);
+ return addAbortMethod(to.catch.apply(to, arguments), deferred);
},
abort: function () {
@@ -162,7 +171,10 @@ var hasBlockedContent = false;
* @private
*/
function getPostParams (params) {
- params.token_auth = piwik.token_auth;
+ if (isRequestToApiMethod()) {
+ params.token_auth = piwik.token_auth;
+ }
+
return params;
}
@@ -284,7 +296,7 @@ var hasBlockedContent = false;
}
deferred.resolve(response);
- })['catch'](function () {
+ }).catch(function () {
deferred.reject.apply(deferred, arguments);
});
@@ -292,6 +304,7 @@ var hasBlockedContent = false;
}
return {
+ withTokenInUrl: withTokenInUrl,
bulkFetch: bulkFetch,
post: post,
fetch: fetch,
diff --git a/plugins/CoreHome/angularjs/common/services/piwik-url.js b/plugins/CoreHome/angularjs/common/services/piwik-url.js
new file mode 100644
index 0000000000..f2d6e9bb0c
--- /dev/null
+++ b/plugins/CoreHome/angularjs/common/services/piwik-url.js
@@ -0,0 +1,54 @@
+/*!
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+(function () {
+ angular.module('piwikApp.service').service('piwikUrl', piwikUrl);
+
+ piwikUrl.$inject = ['$location', 'piwik'];
+
+ /**
+ * Similar to angulars $location but works around some limitation. Use it if you need to access search params
+ */
+ function piwikUrl($location, piwik) {
+
+ var model = {
+ getSearchParam: getSearchParam
+ }
+
+ return model;
+
+ function getSearchParam(paramName)
+ {
+ if (paramName === 'segment') {
+ var hash = window.location.href.split('#');
+ if (hash && hash[1]) {
+ return piwik.broadcast.getValueFromHash(paramName, hash[1]);
+ }
+
+ return broadcast.getValueFromUrl(paramName);
+ }
+
+ // available in global scope
+ var search = $location.search();
+
+ if (!search[paramName]) {
+ // see https://github.com/angular/angular.js/issues/7239 (issue is resolved but problem still exists)
+ search[paramName] = piwik.broadcast.getValueFromUrl(paramName);
+ }
+
+ if (search[paramName]) {
+ var value = search[paramName];
+
+ if (angular.isArray(search[paramName])) {
+ // use last one. Eg when having period=day&period=year angular would otherwise return ['day', 'year']
+ return value[value.length - 1];
+ }
+
+ return value;
+ }
+ }
+ }
+})(); \ No newline at end of file
diff --git a/plugins/CoreHome/angularjs/common/services/report-metadata-model.js b/plugins/CoreHome/angularjs/common/services/report-metadata-model.js
new file mode 100644
index 0000000000..f158861423
--- /dev/null
+++ b/plugins/CoreHome/angularjs/common/services/report-metadata-model.js
@@ -0,0 +1,52 @@
+/*!
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+(function () {
+ angular.module('piwikApp.service').factory('reportMetadataModel', reportMetadataModel);
+
+ reportMetadataModel.$inject = ['piwik', 'piwikApi'];
+
+ function reportMetadataModel (piwik, piwikApi) {
+
+ var reportsPromise = null;
+
+ var model = {
+ reports: [],
+ fetchReportMetadata: fetchReportMetadata,
+ findReport: findReport
+ };
+
+ return model;
+
+ function findReport(module, action)
+ {
+ var found = [];
+
+ angular.forEach(model.reports, function (report) {
+ if (report.module === module && report.action === action) {
+ found = report;
+ }
+ });
+
+ return found;
+ }
+
+ function fetchReportMetadata()
+ {
+ if (!reportsPromise) {
+ reportsPromise = piwikApi.fetch({
+ method: 'API.getReportMetadata',
+ idSites: piwik.idSite || piwik.broadcast.getValueFromUrl('idSite'),
+ }).then(function (response) {
+ model.reports = response;
+ return response;
+ });
+ }
+
+ return reportsPromise;
+ }
+ }
+})(); \ No newline at end of file
diff --git a/plugins/CoreHome/angularjs/common/services/reporting-pages-model.js b/plugins/CoreHome/angularjs/common/services/reporting-pages-model.js
new file mode 100644
index 0000000000..1b1e406c95
--- /dev/null
+++ b/plugins/CoreHome/angularjs/common/services/reporting-pages-model.js
@@ -0,0 +1,58 @@
+/*!
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+(function () {
+ angular.module('piwikApp.service').factory('reportingPagesModel', reportingPagesModelService);
+
+ reportingPagesModelService.$inject = ['piwikApi'];
+
+ function reportingPagesModelService (piwikApi) {
+ var fetchAllPagesPromise = false;
+
+ // those sites are going to be displayed
+ var model = {
+ pages : [],
+ findPage: findPage,
+ reloadAllPages : reloadAllPages,
+ getAllPages : getAllPages
+ };
+
+ return model;
+
+ function findPage(categoryId, subcategoryId)
+ {
+ var found = null;
+
+ angular.forEach(model.pages, function (page) {
+ if (page &&
+ page.category && page.subcategory &&
+ page.category.id === categoryId && ('' + page.subcategory.id) === subcategoryId) {
+ found = page;
+ }
+ });
+
+ return found;
+ }
+
+ function reloadAllPages()
+ {
+ fetchAllPagesPromise = null;
+ return getAllPages();
+ }
+
+ function getAllPages()
+ {
+ if (!fetchAllPagesPromise) {
+ fetchAllPagesPromise = piwikApi.fetch({method: 'API.getReportPagesMetadata'}).then(function (response) {
+ model.pages = response;
+ return response;
+ });
+ }
+
+ return fetchAllPagesPromise;
+ }
+ }
+})(); \ No newline at end of file
diff --git a/plugins/CoreHome/angularjs/enrichedheadline/enrichedheadline.directive.js b/plugins/CoreHome/angularjs/enrichedheadline/enrichedheadline.directive.js
index 79e1da49bf..ea248e1360 100644
--- a/plugins/CoreHome/angularjs/enrichedheadline/enrichedheadline.directive.js
+++ b/plugins/CoreHome/angularjs/enrichedheadline/enrichedheadline.directive.js
@@ -20,9 +20,13 @@
* <h2 piwik-enriched-headline edit-url="index.php?module=Foo&action=bar&id=4">All Websites Dashboard</h2>
* -> makes the headline clickable linking to the specified url
*
+ * <h2 piwik-enriched-headline inline-help="inlineHelp">Pages report</h2>
+ * -> inlineHelp specified via a attribute shows help icon on headline hover
+ *
* <h2 piwik-enriched-headline>All Websites Dashboard
* <div class="inlineHelp">My <strong>inline help</strong></div>
* </h2>
+ * -> alternative definition for inline help
* -> shows help icon to display inline help on click. Note: You can combine inlinehelp and help-url
*/
(function () {
@@ -33,7 +37,8 @@
function piwikEnrichedHeadline($document, piwik, $filter){
var defaults = {
helpUrl: '',
- editUrl: ''
+ editUrl: '',
+ inlineHelp: ''
};
return {
@@ -42,7 +47,8 @@
scope: {
helpUrl: '@',
editUrl: '@',
- featureName: '@'
+ featureName: '@',
+ inlineHelp: '@'
},
templateUrl: 'plugins/CoreHome/angularjs/enrichedheadline/enrichedheadline.directive.html?cb=' + piwik.cacheBuster,
compile: function (element, attrs) {
@@ -52,19 +58,16 @@
}
return function (scope, element, attrs) {
+ if (!scope.inlineHelp) {
- var helpNode = $('[ng-transclude] .inlineHelp', element);
-
- if ((!helpNode || !helpNode.length) && element.next()) {
- // hack for reports :(
- helpNode = element.next().find('.reportDocumentation');
- }
+ var helpNode = $('[ng-transclude] .inlineHelp', element);
- if (helpNode && helpNode.length) {
- if ($.trim(helpNode.text())) {
- scope.inlineHelp = $.trim(helpNode.html());
+ if (helpNode && helpNode.length) {
+ if ($.trim(helpNode.text())) {
+ scope.inlineHelp = $.trim(helpNode.html());
+ }
+ helpNode.remove();
}
- helpNode.remove();
}
if (!attrs.featureName) {
diff --git a/plugins/CoreHome/angularjs/http404check.js b/plugins/CoreHome/angularjs/http404check.js
index f2e2a86edf..5b720c9472 100644
--- a/plugins/CoreHome/angularjs/http404check.js
+++ b/plugins/CoreHome/angularjs/http404check.js
@@ -1,9 +1,9 @@
(function () {
angular.module('piwikApp').factory('http404CheckInterceptor', http404CheckInterceptor);
- http404CheckInterceptor.$inject = ['$q'];
+ http404CheckInterceptor.$inject = ['$q', 'globalAjaxQueue'];
- function http404CheckInterceptor($q) {
+ function http404CheckInterceptor($q, globalAjaxQueue) {
function isClientError(rejection)
{
@@ -15,8 +15,8 @@
}
return {
-
'responseError': function(rejection) {
+
if (rejection &&
isClientError(rejection) &&
rejection.config &&
diff --git a/plugins/CoreHome/angularjs/menudropdown/menudropdown.directive.html b/plugins/CoreHome/angularjs/menudropdown/menudropdown.directive.html
index 5da730a2e2..b9084dbe10 100644
--- a/plugins/CoreHome/angularjs/menudropdown/menudropdown.directive.html
+++ b/plugins/CoreHome/angularjs/menudropdown/menudropdown.directive.html
@@ -23,7 +23,7 @@
class="reset"
src="plugins/CoreHome/images/reset_search.png"/>
</div>
- <div ng-transclude>
+ <div ng-transclude ng-click="selectItem($event)">
</div>
</div>
diff --git a/plugins/CoreHome/angularjs/menudropdown/menudropdown.directive.js b/plugins/CoreHome/angularjs/menudropdown/menudropdown.directive.js
index 00fbf87d7b..313ef00d6c 100644
--- a/plugins/CoreHome/angularjs/menudropdown/menudropdown.directive.js
+++ b/plugins/CoreHome/angularjs/menudropdown/menudropdown.directive.js
@@ -34,10 +34,10 @@
templateUrl: 'plugins/CoreHome/angularjs/menudropdown/menudropdown.directive.html?cb=' + piwik.cacheBuster,
link: function(scope, element, attrs) {
- element.find('.item').on('click', function () {
- var $self = angular.element(this);
+ scope.selectItem = function (event) {
+ var $self = angular.element(event.target);
- if ($self.hasClass('disabled') || $self.hasClass('separator')) {
+ if (!$self.hasClass('item') || $self.hasClass('disabled') || $self.hasClass('separator')) {
return;
}
@@ -47,11 +47,14 @@
});
}
scope.$eval('view.showItems = false');
- scope.$apply();
+
+ setTimeout(function () {
+ scope.$apply();
+ }, 0);
element.find('.item').removeClass('active');
$self.addClass('active');
- });
+ };
scope.searchItems = function (searchTerm)
{
diff --git a/plugins/CoreHome/angularjs/popover-handler/popover-handler.directive.js b/plugins/CoreHome/angularjs/popover-handler/popover-handler.directive.js
new file mode 100644
index 0000000000..ea15f025b0
--- /dev/null
+++ b/plugins/CoreHome/angularjs/popover-handler/popover-handler.directive.js
@@ -0,0 +1,74 @@
+/*!
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+
+/**
+ * When present in the page it listens to a popover URL parameter.
+ *
+ * If present it will try to load the related content in a popover or if the URL is empty it will close an
+ * opened popover.
+ *
+ * Example:
+ * <div piwik-popover-handler></div>
+ */
+(function () {
+ angular.module('piwikApp').directive('piwikPopoverHandler', piwikPopoverHandler);
+
+ piwikPopoverHandler.$inject = ['$location', '$rootScope', 'piwik'];
+
+ function piwikPopoverHandler($location, $rootScope, piwik){
+
+ return {
+ restrict: 'A',
+ scope: {},
+ controller: function () {
+
+ function close()
+ {
+ Piwik_Popover.close();
+ }
+
+ function open(popoverParam)
+ {
+ // in case the $ was encoded (e.g. when using copy&paste on urls in some browsers)
+ popoverParam = decodeURIComponent(popoverParam);
+ // revert special encoding from broadcast.propagateNewPopoverParameter()
+ popoverParam = popoverParam.replace(/\$/g, '%');
+ popoverParam = decodeURIComponent(popoverParam);
+
+ var popoverParamParts = popoverParam.split(':');
+ var handlerName = popoverParamParts[0];
+ popoverParamParts.shift();
+ var param = popoverParamParts.join(':');
+ if (typeof piwik.broadcast.popoverHandlers[handlerName] != 'undefined'
+ && !piwik.broadcast.isLoginPage()) {
+ piwik.broadcast.popoverHandlers[handlerName](param);
+ }
+ }
+
+ function openOrClose()
+ {
+ // should be rather done by routing
+ var popoverParam = $location.search().popover;
+ if (popoverParam) {
+ open(popoverParam);
+ } else {
+ close();
+ }
+ }
+
+ $rootScope.$on('$locationChangeSuccess', function () {
+ // should be rather done by routing
+ $(function () {
+ // make sure all popover handles were registered
+ openOrClose();
+ });
+ });
+
+ }
+ };
+ }
+})(); \ No newline at end of file
diff --git a/plugins/CoreHome/angularjs/reporting-menu/reportingmenu-model.js b/plugins/CoreHome/angularjs/reporting-menu/reportingmenu-model.js
new file mode 100644
index 0000000000..7b999aab08
--- /dev/null
+++ b/plugins/CoreHome/angularjs/reporting-menu/reportingmenu-model.js
@@ -0,0 +1,164 @@
+/*!
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+(function () {
+ angular.module('piwikApp').factory('reportingMenuModel', reportingMenuModelService);
+
+ reportingMenuModelService.$inject = ['$filter', '$q', 'piwikApi', 'reportingPagesModel', '$location'];
+
+ function reportingMenuModelService ($filter, $q, piwikApi, reportingPagesModel, $location) {
+
+ // those sites are going to be displayed
+ var model = {
+ menu: [],
+ selected: [],
+ fetchMenuItems: fetchMenuItems,
+ reloadMenuItems: reloadMenuItems,
+ findSubcategory: findSubcategory
+ };
+
+ return model;
+
+ function isNumeric(text) {
+ return !isNaN(parseFloat(text)) && isFinite(text);
+ }
+
+ function findSubcategory(categoryId, subcategoryId)
+ {
+ var foundCategory = null;
+ var foundSubcategory = null;
+ var foundSubSubcategory = null;
+
+ angular.forEach(model.menu, function (category) {
+ if (category.id !== categoryId) {
+ return;
+ }
+ angular.forEach(category.subcategories, function (subcategory) {
+ if (subcategory.id === subcategoryId) {
+ foundCategory = category;
+ foundSubcategory = subcategory;
+ }
+
+ if (subcategory.isGroup) {
+ angular.forEach(subcategory.subcategories, function (subcat) {
+ if (subcat.id === subcategoryId) {
+ foundCategory = category;
+ foundSubcategory = subcategory;
+ foundSubSubcategory = subcat;
+ }
+ });
+ }
+ });
+ });
+
+ return {category: foundCategory, subcategory: foundSubcategory, subsubcategory: foundSubSubcategory};
+ }
+
+ function buildMenuFromPages(pages)
+ {
+ var menu = [];
+
+ var activeCategory = $location.search().category;
+ var activeSubcategory = $location.search().subcategory;
+
+ var categoriesHandled = {};
+ angular.forEach(pages, function (page, key) {
+ var category = page.category;
+ var categoryId = category.id;
+
+ if (categoriesHandled[categoryId]) {
+ return;
+ }
+
+ categoriesHandled[categoryId] = true;
+
+ if (activeCategory && category.id === activeCategory) {
+ // this doesn't really belong here but placed it here for convenience
+ category.active = true;
+ }
+
+ category.subcategories = [];
+
+ var goalsGroup = false;
+
+ angular.forEach(pages, function (page, key) {
+ if (page.category.id === categoryId) {
+ var subcategory = page.subcategory;
+
+ if (subcategory.id === activeSubcategory && categoryId === activeCategory) {
+ subcategory.active = true;
+ }
+
+ if (page.widgets && page.widgets[0] && page.category.id === 'Goals_Goals' && isNumeric(page.subcategory.id)) {
+ // we handle a goal
+ if (!goalsGroup) {
+ goalsGroup = angular.copy(subcategory);
+ goalsGroup.name = $filter('translate')('Goals_ChooseGoal');
+ goalsGroup.isGroup = true;
+ goalsGroup.subcategories = [];
+ goalsGroup.order = 10;
+ }
+
+ if (subcategory.active) {
+ goalsGroup.name = subcategory.name;
+ goalsGroup.active = true;
+ }
+
+ var goalId = page.subcategory.id;
+ subcategory.tooltip = subcategory.name + ' (id = ' + goalId + ' )';
+
+ goalsGroup.subcategories.push(subcategory);
+ return;
+ }
+
+ category.subcategories.push(subcategory);
+ }
+ });
+
+ if (goalsGroup && goalsGroup.subcategories && goalsGroup.subcategories.length <= 3) {
+ angular.forEach(goalsGroup.subcategories, function (subcategory) {
+ category.subcategories.push(subcategory);
+ });
+ } else if(goalsGroup) {
+ category.subcategories.push(goalsGroup);
+ }
+
+ category.subcategories = sortMenuItems(category.subcategories);
+
+ menu.push(category);
+
+ return menu;
+ });
+
+ menu = sortMenuItems(menu);
+
+ return menu;
+ }
+
+ function sortMenuItems(menu) {
+ return $filter('orderBy')(menu, 'order');
+ };
+
+ function reloadMenuItems()
+ {
+ var pagesPromise = reportingPagesModel.reloadAllPages();
+ return pagesPromise.then(function (pages) {
+ model.menu = buildMenuFromPages(pages);
+ });
+ }
+
+ function fetchMenuItems()
+ {
+ var pagesPromise = reportingPagesModel.getAllPages();
+
+ return pagesPromise.then(function (pages) {
+ model.menu = buildMenuFromPages(pages);
+
+ return model.menu;
+ });
+ }
+ }
+})(); \ No newline at end of file
diff --git a/plugins/CoreHome/angularjs/reporting-menu/reportingmenu.controller.js b/plugins/CoreHome/angularjs/reporting-menu/reportingmenu.controller.js
new file mode 100644
index 0000000000..add0b3fc8b
--- /dev/null
+++ b/plugins/CoreHome/angularjs/reporting-menu/reportingmenu.controller.js
@@ -0,0 +1,135 @@
+/*!
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+(function () {
+ angular.module('piwikApp').controller('ReportingMenuController', ReportingMenuController);
+
+ ReportingMenuController.$inject = ['$scope', 'piwik', '$location', '$timeout', 'reportingMenuModel', '$rootScope'];
+
+ function ReportingMenuController($scope, piwik, $location, $timeout, menuModel, $rootScope) {
+
+ function markAllCategoriesAsInactive()
+ {
+ angular.forEach(menuModel.menu, function (cat) {
+ cat.active = false;
+ });
+ }
+
+ function markAllCategoriesAndChildrenInactive()
+ {
+ angular.forEach(menuModel.menu, function (cat) {
+ cat.active = false;
+ angular.forEach(cat.subcategories, function (subcat) {
+ subcat.active = false;
+
+ if (subcat.isGroup && subcat.subcategories) {
+ angular.forEach(subcat.subcategories, function (sub) {
+ sub.active = false;
+ });
+
+ }
+ });
+ });
+ }
+
+ function getUrlParam(param)
+ {
+ var value = piwik.broadcast.getValueFromHash(param);
+ if (!value) {
+ value = piwik.broadcast.getValueFromUrl(param);
+ }
+ return value;
+ }
+
+ $scope.menuModel = menuModel;
+
+ // highlight the currently hovered subcategory (and category)
+ function enterSubcategory(category, subcategory, subsubcategory) {
+ if (!category || !subcategory) {
+ return;
+ }
+
+ markAllCategoriesAndChildrenInactive();
+
+ category.active = true;
+ subcategory.active = true;
+
+ if (subsubcategory) {
+ subsubcategory.active = true;
+ }
+ };
+
+ var idSite = getUrlParam('idSite');
+ var period = getUrlParam('period');
+ var date = getUrlParam('date');
+ var segment = getUrlParam('segment');
+
+ $scope.makeUrl = function (category, subcategory) {
+
+ var url = 'idSite=' + encodeURIComponent(idSite);
+ url += '&period=' + encodeURIComponent(period);
+ url += '&date=' + encodeURIComponent(date);
+ url += '&category=' + encodeURIComponent(category.id);
+ url += '&subcategory=' + encodeURIComponent(subcategory.id);
+
+ if (segment) {
+ url+= '&segment='+ segment;
+ }
+ return url;
+ }
+
+ $scope.loadCategory = function (category) {
+ if (category.active) {
+ category.active = false;
+ } else {
+ markAllCategoriesAsInactive();
+ category.active = true;
+ }
+
+ if (category.active && category.subcategories && category.subcategories.length === 1) {
+ var subcategory = category.subcategories[0];
+
+ if (subcategory.active) {
+ // we need to manually trigger change as URL would not change and therefore page would not be
+ // reloaded
+ $scope.loadSubcategory(category, subcategory);
+ } else {
+ var url = $scope.makeUrl(category, subcategory);
+ $location.search(url);
+ }
+ }
+ };
+
+ $scope.loadSubcategory = function (category, subcategory) {
+ if (subcategory && subcategory.active) {
+ // this menu item is already active, a location change success would not be triggered,
+ // instead trigger an event
+ $rootScope.$emit('loadPage', category.id, subcategory.id);
+ }
+ };
+
+ menuModel.fetchMenuItems().then(function (menu) {
+ if (!$location.search().subcategory) {
+ // load first, initial page if no subcategory is present
+ enterSubcategory(menu[0], menu[0].subcategories[0]);
+ $location.search($scope.makeUrl(menu[0], menu[0].subcategories[0]));
+ }
+ });
+
+ $rootScope.$on('$locationChangeSuccess', function () {
+ var category = $location.search().category;
+ var subcategory = $location.search().subcategory;
+
+ if (!category || !subcategory) {
+ return;
+ }
+
+ var found = menuModel.findSubcategory(category, subcategory);
+ enterSubcategory(found.category, found.subcategory, found.subsubcategory);
+ });
+
+ }
+})();
diff --git a/plugins/CoreHome/angularjs/reporting-menu/reportingmenu.directive.html b/plugins/CoreHome/angularjs/reporting-menu/reportingmenu.directive.html
new file mode 100644
index 0000000000..0e32b23d7f
--- /dev/null
+++ b/plugins/CoreHome/angularjs/reporting-menu/reportingmenu.directive.html
@@ -0,0 +1,38 @@
+<ul class="navbar" role="menu" aria-label="{{ 'CoreHome_MainNavigation'|translate }}">
+ <li ng-repeat="category in menuModel.menu"
+ class="menuTab"
+ role="menuitem"
+ ng-class="{'active': category.active}">
+ <a class="item" tabindex="5"
+ href=""
+ ng-click="loadCategory(category)">
+ <span class="menu-icon {{ category.icon ? category.icon : 'icon-arrow-right' }}"></span>{{ category.name }}
+ <span class="hidden">
+ {{ 'CoreHome_Menu'|translate }}
+ </span>
+ </a>
+ <ul role="menu">
+ <li ng-repeat="subcategory in category.subcategories"
+ role="menuitem"
+ ng-class="{'active': subcategory.active}">
+ <div ng-if="subcategory.isGroup" piwik-menudropdown show-search="true" menu-title="{{ subcategory.name|escape }}">
+ <a class="item" tabindex="5"
+ ng-repeat="subcat in subcategory.subcategories"
+ title="{{ subcat.tooltip }}"
+ ng-class="{'active': subcat.active}"
+ ng-href="#?{{ makeUrl(category,subcat) }}"
+ ng-click='loadSubcategory(category, subcat)'>
+ {{ subcat.name }}
+ </a>
+ </div>
+
+ <a ng-if="!subcategory.isGroup"
+ ng-href="#?{{ makeUrl(category,subcategory) }}"
+ class="item"
+ ng-click='loadSubcategory(category, subcategory)'>
+ {{ subcategory.name }}
+ </a>
+ </li>
+ </ul>
+ </li>
+</ul> \ No newline at end of file
diff --git a/plugins/CoreHome/angularjs/reporting-menu/reportingmenu.directive.js b/plugins/CoreHome/angularjs/reporting-menu/reportingmenu.directive.js
new file mode 100644
index 0000000000..1b524d3e9b
--- /dev/null
+++ b/plugins/CoreHome/angularjs/reporting-menu/reportingmenu.directive.js
@@ -0,0 +1,32 @@
+/*!
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+
+/**
+ * Shows the Piwik reporting menu.
+ *
+ * It automatically calls the API to fetch all data.
+ *
+ * Example:
+ * <div piwik-reporting-menu></div>
+ */
+
+(function () {
+ angular.module('piwikApp').directive('piwikReportingMenu', piwikReportingMenu);
+
+ piwikReportingMenu.$inject = ['piwik'];
+
+ function piwikReportingMenu(piwik){
+
+ return {
+ restrict: 'A',
+ replace: true,
+ scope: {},
+ templateUrl: 'plugins/CoreHome/angularjs/reporting-menu/reportingmenu.directive.html?cb=' + piwik.cacheBuster,
+ controller: 'ReportingMenuController'
+ };
+ }
+})(); \ No newline at end of file
diff --git a/plugins/CoreHome/angularjs/reporting-page/reportingpage-model.js b/plugins/CoreHome/angularjs/reporting-page/reportingpage-model.js
new file mode 100644
index 0000000000..4018fcee8c
--- /dev/null
+++ b/plugins/CoreHome/angularjs/reporting-page/reportingpage-model.js
@@ -0,0 +1,196 @@
+/*!
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+(function () {
+ angular.module('piwikApp').factory('reportingPageModel', reportingPageModelService);
+
+ reportingPageModelService.$inject = ['$filter', 'piwikApi', 'reportingPagesModel', 'reportMetadataModel'];
+
+ function reportingPageModelService ($filter, piwikApi, reportingPagesModel, reportMetadataModel) {
+ var init = false;
+
+ // those sites are going to be displayed
+ var model = {
+ fetchPage: fetchPage,
+ resetPage: resetPage,
+ widgets: [],
+ page: null,
+ pageContentUrl: '',
+ evolutionReports: [],
+ sparklineReports: []
+ };
+
+ return model;
+
+ function resetPage()
+ {
+ model.page = null;
+ model.widgets = [];
+ model.pageContentUrl = '';
+ model.evolutionReports = [];
+ model.sparklineReports = [];
+ }
+
+ function sortWidgets(widgets)
+ {
+ return $filter('orderBy')(widgets, 'order');
+ }
+
+ function shouldBeRenderedWithFullWidth(widget)
+ {
+ // rather controller logic
+ if ((widget.isContainer && widget.layout && widget.layout === 'ByDimension')
+ || widget.viewDataTable === 'bydimension') {
+ return true;
+ }
+
+ return widget.viewDataTable && widget.viewDataTable === 'tableAllColumns';
+ }
+
+ function buildPage(page)
+ {
+ if (!page) {
+ return;
+ }
+
+ var widgets = [];
+ var evolutionReports = [];
+ var sparklineReports = [];
+ var reportsToIgnore = [];
+
+ angular.forEach(page.widgets, function (widget) {
+
+ if (isIgnoredReport(reportsToIgnore, widget)) {
+ return;
+ }
+
+ reportsToIgnore = reportsToIgnore.concat(getRelatedReports(widget));
+
+ if (widget.viewDataTable && widget.viewDataTable === 'graphEvolution') {
+ evolutionReports.push(widget);
+ } else if (widget.viewDataTable && widget.viewDataTable === 'sparklines') {
+ sparklineReports.push(widget);
+ } else {
+ widgets.push(widget);
+ }
+ });
+
+ widgets = sortWidgets(widgets);
+
+ var groupedWidgets = [];
+
+ if (widgets.length === 1) {
+ // if there is only one widget, we always display it full width
+ groupedWidgets = widgets;
+ } else {
+ for (var i = 0; i < widgets.length; i++) {
+ var widget = widgets[i];
+
+ if (shouldBeRenderedWithFullWidth(widget) || (widgets[i+1] && shouldBeRenderedWithFullWidth(widgets[i+1]))) {
+ widget.widgets = sortWidgets(widget.widgets);
+
+ groupedWidgets.push(widget);
+ } else {
+
+ var counter = 0;
+ var left = [widget];
+ var right = [];
+
+ while (widgets[i+1] && !shouldBeRenderedWithFullWidth(widgets[i+1])) {
+ i++;
+ counter++;
+ if (counter % 2 === 0) {
+ left.push(widgets[i]);
+ } else {
+ right.push(widgets[i]);
+ }
+ }
+
+ groupedWidgets.push({group: true, left: left, right: right});
+ }
+ }
+ }
+
+ var copyWidgets = angular.copy(groupedWidgets);
+ var copyEvolution = angular.copy(evolutionReports);
+ var copySparklines = angular.copy(sparklineReports);
+
+ if (copyEvolution.length) {
+ copyEvolution = markWidgetsInFirstRowOfPage(copyEvolution);
+ } else if (copySparklines.length) {
+ copySparklines = markWidgetsInFirstRowOfPage(copySparklines);
+ } else {
+ copyWidgets = markWidgetsInFirstRowOfPage(copyWidgets);
+ }
+
+ // angular.copy forces the page to re-render. Otherwise it won't reload some pages
+ model.evolutionReports = copyEvolution;
+ model.sparklineReports = copySparklines;
+ model.widgets = copyWidgets;
+ }
+
+ function markWidgetsInFirstRowOfPage(widgets)
+ {
+ if (widgets && widgets[0]) {
+ if (widgets[0].group) {
+ markWidgetsInFirstRowOfPage(widgets[0].left);
+ markWidgetsInFirstRowOfPage(widgets[0].right);
+ } else {
+ widgets[0].isFirstInPage = true;
+ }
+ }
+
+ return widgets;
+ }
+
+ function getRelatedReports(widget)
+ {
+ if (widget.isReport) {
+ var report = reportMetadataModel.findReport(widget.module, widget.action);
+
+ if (report && report.relatedReports) {
+ return report.relatedReports;
+ }
+ }
+
+ return [];
+ }
+
+ function isIgnoredReport(reportsToIgnore, widget)
+ {
+ var found = false;
+
+ if (widget.isReport) {
+ angular.forEach(reportsToIgnore, function (report) {
+ if (report.module === widget.module &&
+ report.action === widget.action) {
+ found = true;
+ }
+ });
+ }
+
+ return found;
+ }
+
+ function fetchPage(category, subcategory)
+ {
+ resetPage();
+
+ var pagesPromise = reportingPagesModel.getAllPages();
+ var reportsPromise = reportMetadataModel.fetchReportMetadata();
+
+ return pagesPromise.then(function () {
+ model.page = reportingPagesModel.findPage(category, subcategory);
+
+ reportsPromise.then(function () {
+ buildPage(model.page);
+ });
+
+ return model.page;
+ });
+ }
+ }
+})(); \ No newline at end of file
diff --git a/plugins/CoreHome/angularjs/reporting-page/reportingpage.controller.js b/plugins/CoreHome/angularjs/reporting-page/reportingpage.controller.js
new file mode 100644
index 0000000000..3fe5955dc7
--- /dev/null
+++ b/plugins/CoreHome/angularjs/reporting-page/reportingpage.controller.js
@@ -0,0 +1,68 @@
+/*!
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+(function () {
+ angular.module('piwikApp').controller('ReportingPageController', ReportingPageController);
+
+ ReportingPageController.$inject = ['$scope', 'piwik', '$rootScope', '$location', 'reportingPageModel'];
+
+ function ReportingPageController($scope, piwik, $rootScope, $location, pageModel) {
+ pageModel.resetPage();
+ $scope.pageModel = pageModel;
+
+ var currentCategory = null;
+ var currentSubcategory = null;
+
+ $scope.renderPage = function (category, subcategory) {
+ if (!category || !subcategory) {
+ pageModel.resetPage();
+ $scope.loading = false;
+ return;
+ }
+
+ currentCategory = category;
+ currentSubcategory = subcategory;
+
+ if (category === 'Dashboard_Dashboard' && $.isNumeric(subcategory) && $('[piwik-dashboard]').length) {
+ // hack to make loading of dashboards faster since all the information is already there in the
+ // piwik-dashboard widget, we can let the piwik-dashboard widget render the page. We need to find
+ // a proper solution for this. A workaround for now could be an event or something to let other
+ // components render a specific page.
+ $scope.loading = false;
+ var element = $('[piwik-dashboard]');
+ var scope = angular.element(element).scope();
+ scope.fetchDashboard(parseInt(subcategory, 10));
+ return;
+ }
+
+ pageModel.fetchPage(category, subcategory).then(function () {
+ $scope.hasNoPage = !pageModel.page;
+ $scope.loading = false;
+ });
+ }
+
+ $scope.loading = true; // we only set loading on initial load
+
+ $scope.renderPage($location.search().category, $location.search().subcategory);
+
+ $rootScope.$on('$locationChangeSuccess', function () {
+ // should be handled by $route
+ var category = $location.search().category;
+ var subcategory = $location.search().subcategory;
+
+ if (category === currentCategory && subcategory === currentSubcategory) {
+ // this page is already loaded
+ return;
+ }
+
+ $scope.renderPage(category, subcategory);
+ });
+
+ $rootScope.$on('loadPage', function (event, category, subcategory) {
+ $scope.renderPage(category, subcategory);
+ });
+ }
+})();
diff --git a/plugins/CoreHome/angularjs/reporting-page/reportingpage.directive.html b/plugins/CoreHome/angularjs/reporting-page/reportingpage.directive.html
new file mode 100644
index 0000000000..9a8974e313
--- /dev/null
+++ b/plugins/CoreHome/angularjs/reporting-page/reportingpage.directive.html
@@ -0,0 +1,25 @@
+<div class="reporting-page">
+
+ <div piwik-activity-indicator loading="loading"/>
+
+ <div ng-show="hasNoPage">{{ 'CoreHome_NoSuchPage'|translate }}</div>
+
+ <div class="row" ng-repeat="evolutionReport in pageModel.evolutionReports">
+ <div class="col-md-12" piwik-widget="evolutionReport"></div>
+ </div>
+
+ <div class="row" ng-repeat="sparklineReport in pageModel.sparklineReports">
+ <div class="col-md-12" piwik-widget="sparklineReport"></div>
+ </div>
+
+ <div class="row" ng-repeat="widget in pageModel.widgets">
+ <div class="col-md-12" ng-if="!widget.group" piwik-widget="widget"></div>
+
+ <div ng-if="widget.group" class="col-md-6">
+ <div ng-repeat="widgetInGroup in widget.left" piwik-widget="widgetInGroup"></div>
+ </div>
+ <div ng-if="widget.group" class="col-md-6">
+ <div ng-repeat="widgetInGroup in widget.right" piwik-widget="widgetInGroup"></div>
+ </div>
+ </div>
+</div> \ No newline at end of file
diff --git a/plugins/CoreHome/angularjs/reporting-page/reportingpage.directive.js b/plugins/CoreHome/angularjs/reporting-page/reportingpage.directive.js
new file mode 100644
index 0000000000..a146ed3112
--- /dev/null
+++ b/plugins/CoreHome/angularjs/reporting-page/reportingpage.directive.js
@@ -0,0 +1,31 @@
+/*!
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+
+/**
+ * Shows a piwik reporting page.
+ *
+ * The content to be displayed is automatically loaded via API based on the current URL. The URL parameters
+ * 'category' and 'subcategory' need to be present in the URL in order to see something in the reporting page.
+ *
+ * Example:
+ * <div piwik-reporting-page></div>
+ */
+(function () {
+ angular.module('piwikApp').directive('piwikReportingPage', piwikReportingPage);
+
+ piwikReportingPage.$inject = ['piwik'];
+
+ function piwikReportingPage(piwik){
+
+ return {
+ restrict: 'A',
+ scope: {},
+ templateUrl: 'plugins/CoreHome/angularjs/reporting-page/reportingpage.directive.html?cb=' + piwik.cacheBuster,
+ controller: 'ReportingPageController'
+ };
+ }
+})(); \ No newline at end of file
diff --git a/plugins/CoreHome/angularjs/siteselector/siteselector-model.service.js b/plugins/CoreHome/angularjs/siteselector/siteselector-model.service.js
index 6688057579..48f7bf2419 100644
--- a/plugins/CoreHome/angularjs/siteselector/siteselector-model.service.js
+++ b/plugins/CoreHome/angularjs/siteselector/siteselector-model.service.js
@@ -98,7 +98,7 @@
if (angular.isDefined(response)) {
return updateWebsitesList(response);
}
- })['finally'](function () { // .finally() is not IE8 compatible see https://github.com/angular/angular.js/commit/f078762d48d0d5d9796dcdf2cb0241198677582c
+ }).finally(function () {
model.isLoading = false;
model.currentRequest = null;
});
diff --git a/plugins/CoreHome/angularjs/siteselector/siteselector.directive.js b/plugins/CoreHome/angularjs/siteselector/siteselector.directive.js
index a445f4de6b..06033fbd30 100644
--- a/plugins/CoreHome/angularjs/siteselector/siteselector.directive.js
+++ b/plugins/CoreHome/angularjs/siteselector/siteselector.directive.js
@@ -66,7 +66,6 @@
return function (scope, element, attrs, ngModel) {
scope.selectedSite = {id: attrs.siteid, name: attrs.sitename};
scope.model.onlySitesWithAdminAccess = scope.onlySitesWithAdminAccess;
- scope.model.loadInitialSites();
if (ngModel) {
ngModel.$setViewValue(scope.selectedSite);
diff --git a/plugins/CoreHome/angularjs/widget-bydimension-container/widget-bydimension-container.directive.html b/plugins/CoreHome/angularjs/widget-bydimension-container/widget-bydimension-container.directive.html
new file mode 100644
index 0000000000..32bb13331e
--- /dev/null
+++ b/plugins/CoreHome/angularjs/widget-bydimension-container/widget-bydimension-container.directive.html
@@ -0,0 +1,25 @@
+<div class="reportsByDimensionView">
+
+ <div class="entityList">
+ <div class='dimensionCategory' ng-repeat="category in widgetsByCategory">
+ {{ category.name }}
+ <ul class='listCircle'>
+ <li ng-repeat="widget in category.widgets"
+ class="reportDimension"
+ ng-class="{activeDimension: (selectedWidget.uniqueId===widget.uniqueId)}"
+ ng-click="selectWidget(widget)">
+ <span class='dimension'>{{widget.name}}</span>
+ </li>
+ </ul>
+ </div>
+ </div>
+
+ <div style="float:left;max-width:730px;">
+ <h2 ng-if="selectedWidget.name" class="noTopMargin">{{ selectedWidget.name }}</h2>
+
+ <div ng-if="selectedWidget.parameters" class="dimensionReport"
+ piwik-widget-loader="selectedWidget.parameters"></div>
+ </div>
+ <div class="clear"></div>
+
+</div> \ No newline at end of file
diff --git a/plugins/CoreHome/angularjs/widget-bydimension-container/widget-bydimension-container.directive.js b/plugins/CoreHome/angularjs/widget-bydimension-container/widget-bydimension-container.directive.js
new file mode 100644
index 0000000000..f3693be97e
--- /dev/null
+++ b/plugins/CoreHome/angularjs/widget-bydimension-container/widget-bydimension-container.directive.js
@@ -0,0 +1,67 @@
+/*!
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+
+/**
+ * Renders a widget that is a container widget having the layout "ByDimension".
+ *
+ * The "ByDimension" layout shows a menu on the left letting you choose any widgets within this container. The
+ * currently selected widget is shown on the right.
+ *
+ * @param {Object} piwikWidgetByDimensionContainer a widget object as returned by the WidgetMetadata API.
+ *
+ * Example:
+ * <div piwik-widget-by-dimension-container="containerWidget"></div>
+ */
+(function () {
+ angular.module('piwikApp').directive('piwikWidgetByDimensionContainer', piwikWidgetContainer);
+
+ piwikWidgetContainer.$inject = ['piwik', '$filter'];
+
+ function piwikWidgetContainer(piwik, $filter){
+ return {
+ restrict: 'A',
+ scope: {
+ container: '=piwikWidgetByDimensionContainer'
+ },
+ templateUrl: 'plugins/CoreHome/angularjs/widget-bydimension-container/widget-bydimension-container.directive.html?cb=' + piwik.cacheBuster,
+ compile: function (element, attrs) {
+
+ return function (scope, element, attrs, ngModel) {
+
+ var widgetsSorted = $filter('orderBy')(scope.container.widgets, 'order');
+ var widgetsByCategory = {};
+
+ angular.forEach(widgetsSorted, function (widget) {
+ var category = widget.subcategory.name;
+
+ if (!widgetsByCategory[category]) {
+ widgetsByCategory[category] = {name: category, order: widget.order, widgets: []};
+ }
+
+ widgetsByCategory[category].widgets.push(widget);
+ });
+
+ // only an array can be sorted
+ var finalWidgetsByCategory = [];
+ angular.forEach(widgetsByCategory, function (category) {
+ finalWidgetsByCategory.push(category);
+ });
+
+ scope.widgetsByCategory = $filter('orderBy')(finalWidgetsByCategory, 'order');
+
+ scope.selectWidget = function (widget) {
+ scope.selectedWidget = angular.copy(widget); // we copy to force rerender
+ }
+
+ if (widgetsSorted && widgetsSorted.length) {
+ scope.selectWidget(widgetsSorted[0]);
+ }
+ };
+ }
+ };
+ }
+})(); \ No newline at end of file
diff --git a/plugins/CoreHome/angularjs/widget-container/widgetcontainer.directive.html b/plugins/CoreHome/angularjs/widget-container/widgetcontainer.directive.html
new file mode 100644
index 0000000000..21ebd3d0cd
--- /dev/null
+++ b/plugins/CoreHome/angularjs/widget-container/widgetcontainer.directive.html
@@ -0,0 +1,10 @@
+<div>
+ <!-- custom template prevents recursion -->
+ <script id="mywidget.html" type="text/ng-template">
+ <div piwik-widget="widget"></div>
+ </script>
+
+ <div ng-repeat="widget in container.widgets">
+ <div ng-include src="'mywidget.html'"/>
+ </div>
+</div> \ No newline at end of file
diff --git a/plugins/CoreHome/angularjs/widget-container/widgetcontainer.directive.js b/plugins/CoreHome/angularjs/widget-container/widgetcontainer.directive.js
new file mode 100644
index 0000000000..c378637c71
--- /dev/null
+++ b/plugins/CoreHome/angularjs/widget-container/widgetcontainer.directive.js
@@ -0,0 +1,32 @@
+/*!
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+
+/**
+ * Renders a widget that is a container widget having no specific layout (which is the default).
+ *
+ * It shows all widgets vertically aligned one widget after another.
+ *
+ * @param {Object} piwikWidgetContainer a widget object as returned by the WidgetMetadata API.
+ *
+ * Example:
+ * <div piwik-widget-container="containerWidget"></div>
+ */
+(function () {
+ angular.module('piwikApp').directive('piwikWidgetContainer', piwikWidgetContainer);
+
+ piwikWidgetContainer.$inject = ['piwik'];
+
+ function piwikWidgetContainer(piwik){
+ return {
+ restrict: 'A',
+ scope: {
+ container: '=piwikWidgetContainer'
+ },
+ templateUrl: 'plugins/CoreHome/angularjs/widget-container/widgetcontainer.directive.html?cb=' + piwik.cacheBuster
+ };
+ }
+})(); \ No newline at end of file
diff --git a/plugins/CoreHome/angularjs/widget-loader/widgetloader.directive.html b/plugins/CoreHome/angularjs/widget-loader/widgetloader.directive.html
new file mode 100644
index 0000000000..d1f0cb51f1
--- /dev/null
+++ b/plugins/CoreHome/angularjs/widget-loader/widgetloader.directive.html
@@ -0,0 +1,13 @@
+<div>
+
+ <div piwik-activity-indicator loading="loading"/>
+
+ <div ng-show="loadingFailed">
+ <div class="notification system notification-error">
+ {{ 'General_ErrorRequest'|translate:(''):('') }}
+ </div>
+ </div>
+
+ <div class="theWidgetContent"></div>
+
+</div> \ No newline at end of file
diff --git a/plugins/CoreHome/angularjs/widget-loader/widgetloader.directive.js b/plugins/CoreHome/angularjs/widget-loader/widgetloader.directive.js
new file mode 100644
index 0000000000..b1d49579fc
--- /dev/null
+++ b/plugins/CoreHome/angularjs/widget-loader/widgetloader.directive.js
@@ -0,0 +1,135 @@
+/*!
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+
+/**
+ * Loads any custom widget or URL based on the given parameters.
+ *
+ * The currently active idSite, period, date and segment (if needed) is automatically appended to the parameters. If
+ * this widget is removed from the DOM and requests are in progress, these requests will be aborted. A loading message
+ * or an error message on failure is shown as well. It's kinda similar to ng-include but there it is not possible to
+ * listen to HTTP errors etc.
+ *
+ * Example:
+ * <div piwik-widget-loader="{module: '', action: '', ...}"></div>
+ */
+(function () {
+ angular.module('piwikApp').directive('piwikWidgetLoader', piwikWidgetLoader);
+
+ piwikWidgetLoader.$inject = ['piwik', 'piwikUrl', '$http', '$compile', '$q', '$location'];
+
+ function piwikWidgetLoader(piwik, piwikUrl, $http, $compile, $q, $location){
+ return {
+ restrict: 'A',
+ transclude: true,
+ scope: {
+ piwikWidgetLoader: '='
+ },
+ templateUrl: 'plugins/CoreHome/angularjs/widget-loader/widgetloader.directive.html?cb=' + piwik.cacheBuster,
+ compile: function (element, attrs) {
+
+ return function (scope, element, attrs, ngModel) {
+ var changeCounter = 0,
+ currentScope,
+ currentElement,
+ httpCanceler,
+ contentNode = element.find('.theWidgetContent');
+
+ var cleanupLastWidgetContent = function() {
+ if (currentElement) {
+ currentElement.remove();
+ currentElement = null;
+ }
+ if (currentScope) {
+ currentScope.$destroy();
+ currentScope = null;
+ }
+ };
+
+ var abortHttpRequestIfNeeded = function () {
+ if (httpCanceler) {
+ httpCanceler.resolve();
+ httpCanceler = null;
+ }
+ }
+
+ function getFullWidgetUrl(parameters) {
+
+ var url = $.param(parameters);
+
+ var $urlParams = $location.search();
+ $urlParams = angular.copy($urlParams);
+ delete $urlParams['category'];
+ delete $urlParams['subcategory'];
+
+ angular.forEach($urlParams, function (value, key) {
+ if (!(key in parameters)) {
+ url += '&' + key + '=' + piwikUrl.getSearchParam(key);
+ }
+ });
+
+ url += '&random=' + parseInt(Math.random() * 10000);
+
+ return '?' + url;
+ }
+
+ function loadWidgetUrl(parameters, thisChangeId)
+ {
+ scope.loading = true;
+
+ var url = getFullWidgetUrl(parameters);
+
+ abortHttpRequestIfNeeded();
+ cleanupLastWidgetContent();
+
+ httpCanceler = $q.defer();
+
+ $http.get(url, {timeout: httpCanceler.promise}).success(function(response) {
+ if (thisChangeId !== changeCounter || !response) {
+ // another widget was requested meanwhile, ignore this response
+ return;
+ }
+
+ httpCanceler = null;
+
+ var newScope = scope.$new();
+ currentScope = newScope;
+
+ scope.loading = false;
+ scope.loadingFailed = false;
+
+ currentElement = contentNode.html(response).children();
+ $compile(currentElement)(newScope);
+
+ }).error(function () {
+ if (thisChangeId !== changeCounter) {
+ // another widget was requested meanwhile, ignore this response
+ return;
+ }
+
+ httpCanceler = null;
+
+ cleanupLastWidgetContent();
+
+ scope.loading = false;
+ scope.loadingFailed = true;
+ });
+ }
+
+ scope.$watch('piwikWidgetLoader', function (parameters, oldUrl) {
+ if (parameters) {
+ loadWidgetUrl(parameters, ++changeCounter);
+ }
+ });
+
+ element.on('$destroy', function() {
+ abortHttpRequestIfNeeded();
+ });
+ };
+ }
+ };
+ }
+})(); \ No newline at end of file
diff --git a/plugins/CoreHome/angularjs/widget/widget.directive.html b/plugins/CoreHome/angularjs/widget/widget.directive.html
new file mode 100644
index 0000000000..d75b273d9d
--- /dev/null
+++ b/plugins/CoreHome/angularjs/widget/widget.directive.html
@@ -0,0 +1,24 @@
+<div id="{{ widget.uniqueId }}"
+ ng-show="view.showWidget"
+ class="{{widget.viewDataTable}}"
+ ng-class="{'smallTopMargin': (!widget.isFirstInPage && (!widget.name || widgetized))}"
+ >
+ <!--smallTopMargin: we display small margin if it's not the first widget on the page and if there's no headline -->
+ <h2 ng-if="!widget.parameters.widget && widget.name && !widgetized"
+ piwik-enriched-headline
+ ng-class="{'noTopMargin': widget.isFirstInPage}"
+ inline-help="{{widget.documentation}}"
+ feature-name="{{widget.name}}">{{widget.name}}</h2>
+ <h2 ng-if="widget.parameters.widget && widget.name && !widgetized">{{widget.name}}</h2>
+
+ <div ng-if="!widget.isContainer && widget.parameters"
+ piwik-widget-loader="widget.parameters"></div>
+
+ <div ng-if="widget.isContainer && widget.layout!='ByDimension'">
+ <div piwik-widget-container="widget"></div>
+ </div>
+
+ <div ng-if="widget.isContainer && widget.layout=='ByDimension'">
+ <div piwik-widget-by-dimension-container="widget"></div>
+ </div>
+</div> \ No newline at end of file
diff --git a/plugins/CoreHome/angularjs/widget/widget.directive.js b/plugins/CoreHome/angularjs/widget/widget.directive.js
new file mode 100644
index 0000000000..8f2bd2e25d
--- /dev/null
+++ b/plugins/CoreHome/angularjs/widget/widget.directive.js
@@ -0,0 +1,103 @@
+/*!
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+
+/**
+ * Renders any kind of widget. If you have a widget and you want to have it rendered, use this directive. It will
+ * display a name on top and the actual widget below. It can handle any kind of widget, no matter whether it is a
+ * regular widget or a container.
+ *
+ * @param {Object} piwikWidget A widget object as returned by the WidgetMetadata API.
+ * @param {Object} piwikWidget.middlewareParameters If present, we will request a URL using the given parameters and
+ * only if this URL returns a JSON `true` the widget will be shown.
+ * Otherwise the widget won't be shown.
+ * @param {String} containerId If you do not have a widget object but a containerId we will find the correct widget
+ * object based on the given containerId. Be aware that we might not find the widget if
+ * it is for example not available for the current user or period/date.
+ * @param {Boolean} widgetized true if the widget is widgetized (eg in Dashboard or exported). In this case we will add
+ * a URL parameter widget=1 to all widgets. Eg sparklines will be then displayed one after
+ * another (vertically aligned) instead of two next to each other.
+ *
+ * Example:
+ * <div piwik-widget="widget"></div>
+ * <div piwik-widget containerid="widgetGoalsOverview"></div> // in this case we will find the correct widget automatically
+ * <div piwik-widget="widget" widetized="true"></div> // disables rating feature, no initial headline
+ */
+(function () {
+ angular.module('piwikApp').directive('piwikWidget', piwikWidget);
+
+ piwikWidget.$inject = ['piwik', 'piwikApi', 'reportMetadataModel'];
+
+ function piwikWidget(piwik, piwikApi, reportMetadataModel){
+
+ function findContainerWidget(containerId, scope) {
+ widgetsHelper.getAvailableWidgets(function (categorizedWidgets) {
+
+ angular.forEach(categorizedWidgets, function (widgets) {
+ angular.forEach(widgets, function (widget) {
+ if (widget && widget.isContainer && widget.parameters.containerId === containerId) {
+ widget = angular.copy(widget);
+ if (scope.widgetized) {
+ widget.isFirstInPage = '1';
+ widget.parameters.widget = '1';
+ angular.forEach(widget.widgets, function (widget) {
+ widget.parameters.widget = '1';
+ });
+ }
+ scope.widget = widget;
+ applyMiddleware(scope);
+ }
+ });
+ });
+
+ });
+ }
+
+ function addReportDocumentationIfPossible(widget)
+ {
+ if (widget && widget.isReport && !widget.documentation) {
+ var report = reportMetadataModel.findReport(widget.module, widget.action);
+ if (report && report.documentation) {
+ widget.documentation = report.documentation;
+ }
+ }
+ }
+
+ function applyMiddleware(scope)
+ {
+ if (!scope.widget.middlewareParameters) {
+ scope.$eval('view.showWidget = true');
+ } else {
+ var params = angular.copy(scope.widget.middlewareParameters);
+ piwikApi.fetch(params).then(function (response) {
+ var enabled = response ? 'true' : 'false';
+ scope.$eval('view.showWidget = ' + enabled);
+ });
+ }
+ }
+
+ return {
+ restrict: 'A',
+ scope: {
+ widget: '=?piwikWidget',
+ widgetized: '=?',
+ containerid: '='
+ },
+ templateUrl: 'plugins/CoreHome/angularjs/widget/widget.directive.html?cb=' + piwik.cacheBuster,
+ compile: function (element, attrs) {
+
+ return function (scope, element, attrs, ngModel) {
+ if (scope.widget) {
+ addReportDocumentationIfPossible(scope.widget);
+ applyMiddleware(scope);
+ } else if (attrs.containerid) {
+ findContainerWidget(attrs.containerid, scope);
+ }
+ }
+ }
+ };
+ }
+})(); \ No newline at end of file
diff --git a/plugins/CoreHome/javascripts/broadcast.js b/plugins/CoreHome/javascripts/broadcast.js
index c0cc7d81c4..30b21f46af 100644
--- a/plugins/CoreHome/javascripts/broadcast.js
+++ b/plugins/CoreHome/javascripts/broadcast.js
@@ -159,7 +159,6 @@ var broadcast = {
} else {
// start page
Piwik_Popover.close();
-
$('.pageWrap #content:not(.admin)').empty();
}
},
@@ -173,6 +172,7 @@ var broadcast = {
},
/**
+ * ONLY USED BY OVERLAY
* propagateAjax -- update hash values then make ajax calls.
* example :
* 1) <a href="javascript:broadcast.propagateAjax('module=Referrers&action=getKeywords')">View keywords report</a>
@@ -233,6 +233,47 @@ var broadcast = {
},
/**
+ * propagateAjax -- update hash values then make ajax calls.
+ * example :
+ * 1) <a href="javascript:broadcast.propagateAjax('module=Referrers&action=getKeywords')">View keywords report</a>
+ * 2) Main menu li also goes through this function.
+ *
+ * Will propagate your new value into the current hash string and make ajax calls.
+ *
+ * NOTE: this method will only make ajax call and replacing main content.
+ *
+ * @param {string} ajaxUrl querystring with parameters to be updated
+ * @param {boolean} [disableHistory] the hash change won't be available in the browser history
+ * @return {void}
+ */
+ buildReportingUrl: function (ajaxUrl, disableHistory) {
+
+ // available in global scope
+ var currentHashStr = broadcast.getHash();
+
+ ajaxUrl = ajaxUrl.replace(/^\?|&#/, '');
+
+ var params_vals = ajaxUrl.split("&");
+ for (var i = 0; i < params_vals.length; i++) {
+ currentHashStr = broadcast.updateParamValue(params_vals[i], currentHashStr);
+ }
+
+ // if the module is not 'Goals', we specifically unset the 'idGoal' parameter
+ // this is to ensure that the URLs are clean (and that clicks on graphs work as expected - they are broken with the extra parameter)
+ var action = broadcast.getParamValue('action', currentHashStr);
+ if (action != 'goalReport' && action != 'ecommerceReport' && action != 'products' && action != 'sales') {
+ currentHashStr = broadcast.updateParamValue('idGoal=', currentHashStr);
+ }
+ // unset idDashboard if use doesn't display a dashboard
+ var module = broadcast.getParamValue('module', currentHashStr);
+ if (module != 'Dashboard') {
+ currentHashStr = broadcast.updateParamValue('idDashboard=', currentHashStr);
+ }
+
+ return '#' + currentHashStr;
+ },
+
+ /**
* propagateNewPage() -- update url value and load new page,
* Example:
* 1) We want to update idSite to both search query and hash then reload the page,
@@ -353,9 +394,9 @@ var broadcast = {
*/
propagateNewPopoverParameter: function (handlerName, value) {
// init broadcast if not already done (it is required to make popovers work in widgetize mode)
- broadcast.init(true);
+ //broadcast.init(true);
- var hash = broadcast.getHashFromUrl(window.location.href);
+ var $location = angular.element(document).injector().get('$location');
var popover = '';
if (handlerName) {
@@ -369,24 +410,14 @@ var broadcast = {
}
if ('' == value || 'undefined' == typeof value) {
- var newHash = hash.replace(/(&?popover=.*)/, '');
- } else if (broadcast.getParamValue('popover', hash)) {
- var newHash = broadcast.updateParamValue('popover='+popover, hash);
- } else if (hash && hash != '#') {
- var newHash = hash + '&popover=' + popover
+ $location.search('popover', '');
} else {
- var newHash = '#popover='+popover;
- }
-
- // never use an empty hash, as that might reload the page
- if ('' == newHash) {
- newHash = '#';
+ $location.search('popover', popover);
}
- broadcast.forceReload = false;
- angular.element(document).injector().invoke(function (historyService) {
- historyService.load(newHash);
- });
+ setTimeout(function () {
+ angular.element(document).injector().get('$rootScope').$apply();
+ }, 1);
},
/**
diff --git a/plugins/CoreHome/javascripts/calendar.js b/plugins/CoreHome/javascripts/calendar.js
index e1c68f851b..004c15e0aa 100644
--- a/plugins/CoreHome/javascripts/calendar.js
+++ b/plugins/CoreHome/javascripts/calendar.js
@@ -547,6 +547,8 @@
if (piwik.period == 'range') {
$("#period_id_range").click();
}
+
+ initTopControls();
});
}(jQuery));
diff --git a/plugins/CoreHome/javascripts/corehome.js b/plugins/CoreHome/javascripts/corehome.js
index fd8c1632a7..b0ac486b10 100755
--- a/plugins/CoreHome/javascripts/corehome.js
+++ b/plugins/CoreHome/javascripts/corehome.js
@@ -15,6 +15,8 @@
var headerMessageParent = $('#header_message').parent();
+ initTopControls();
+
// when 'check for updates...' link is clicked, force a check & display the result
headerMessageParent.on('click', '#updateCheckLinkContainer', function (e) {
e.preventDefault();
@@ -28,8 +30,11 @@
action: 'checkForUpdates'
}, 'get');
+ ajaxRequest.withTokenInUrl();
+
var $titleElement = $(this);
$titleElement.addClass('activityIndicator');
+
ajaxRequest.setCallback(function (response) {
headerMessage.fadeOut('slow', function () {
response = $(response);
@@ -121,67 +126,8 @@
handleSectionToggle(this, 'inline', !$(this).is(':checked'));
});
- //
- // reports by dimension list behavior
- //
-
- // when a report dimension is clicked, load the appropriate report
- var currentWidgetLoading = null;
- $('body').on('click', '.reportDimension', function (e) {
- var view = $(this).closest('.reportsByDimensionView'),
- report = $('.dimensionReport', view),
- loading = $('.loadingPiwik', view);
-
- // make this dimension the active one
- $('.activeDimension', view).removeClass('activeDimension');
- $(this).addClass('activeDimension');
-
- // hide the visible report & show the loading elem
- report.hide();
- loading.show();
-
- // load the report using the data-url attribute (which holds the URL to the report)
- var widgetParams = broadcast.getValuesFromUrl($(this).attr('data-url'));
- for (var key in widgetParams) {
- widgetParams[key] = decodeURIComponent(widgetParams[key]);
- }
-
- var widgetUniqueId = widgetParams.module + widgetParams.action;
- currentWidgetLoading = widgetUniqueId;
-
- var ajaxRequest = new ajaxHelper();
- ajaxRequest.addParams(widgetParams, 'get');
- ajaxRequest.setCallback(function (response) {
- // if the widget that was loaded was not for the latest clicked link, do nothing w/ the response
- if (widgetUniqueId != currentWidgetLoading) {
- return;
- }
-
- loading.hide();
- report.css('display', 'inline-block').html($(response));
-
- // scroll to report
- piwikHelper.lazyScrollTo(report, 400);
- });
- ajaxRequest.setErrorCallback(function (deferred, status) {
- if (status == 'abort' || !deferred || deferred.status < 400 || deferred.status >= 600) {
- return;
- }
-
- loading.hide();
-
- var errorMessage = _pk_translate('General_ErrorRequest', ['', '']);
- if ($('#loadingError').html()) {
- errorMessage = $('#loadingError').html();
- }
-
- report.css('display', 'inline-block').html('<div class="dimensionLoadingError">' + errorMessage + '</div>');
- });
- ajaxRequest.setFormat('html');
- ajaxRequest.send(false);
- });
});
-
+
@@ -192,5 +138,4 @@ $( document ).ready(function() {
$('a[name="main"]').attr('tabindex', -1).focus();
$(window).scrollTo($('a[name="main"]'));
});
-
}); \ No newline at end of file
diff --git a/plugins/CoreHome/javascripts/dataTable.js b/plugins/CoreHome/javascripts/dataTable.js
index 3a19e6dc86..4386a4bf7b 100644
--- a/plugins/CoreHome/javascripts/dataTable.js
+++ b/plugins/CoreHome/javascripts/dataTable.js
@@ -1,3 +1,4 @@
+
/*!
* Piwik - free/libre analytics platform
*
@@ -236,6 +237,7 @@ $.extend(DataTable.prototype, UIControl.prototype, {
var ajaxRequest = new ajaxHelper();
ajaxRequest.addParams(params, 'get');
+ ajaxRequest.withTokenInUrl();
ajaxRequest.setCallback(
function (response) {
@@ -1383,6 +1385,7 @@ $.extend(DataTable.prototype, UIControl.prototype, {
action: 'saveViewDataTableParameters',
report_id: reportId
}, 'get');
+ ajaxRequest.withTokenInUrl();
ajaxRequest.addParams({
parameters: JSON.stringify(parameters)
}, 'post');
diff --git a/plugins/CoreHome/javascripts/menu.js b/plugins/CoreHome/javascripts/menu.js
deleted file mode 100644
index d968b757aa..0000000000
--- a/plugins/CoreHome/javascripts/menu.js
+++ /dev/null
@@ -1,176 +0,0 @@
-/*!
- * Piwik - free/libre analytics platform
- *
- * @link http://piwik.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- */
-
-/**
- * @constructor
- */
-function menu() {
- this.param = {};
-}
-
-menu.prototype =
-{
- resetTimer: null,
-
- onItemClick: function (e) {
- if (e.which === 2) {
- return;
- }
-
- $('#secondNavBar').removeClass('open fadeInLeft');
-
- var $link = $(this);
- var href = $link.attr('href');
-
- if (!$('#content.admin').size()) {
- if (!href && $link.parent().is('.menuTab')) {
- var $li = $link.parents('li').first();
-
- if ($li.hasClass('sfActive')) {
- $li.removeClass('sfActive');
- } else {
- $li.siblings().removeClass('sfActive');
- $li.addClass('sfActive');
- }
-
- var $children = $li.find('ul li > .item');
- if ($children.length === 1) {
- $children.first().click();
- }
-
-
- } else if (href) {
- $('#secondNavBar').trigger('piwikSwitchPage', this);
-
- broadcast.propagateAjax(href.substr(1));
- }
-
- return false;
- }
-
- return !!href;
- },
-
- isAdmin: function () {
- return !!$('#content.admin').size();
- },
-
- init: function () {
- this.menuNode = $('#secondNavBar');
-
- // add id to all li menu to support menu identification.
- // for all sub menu we want to have a unique id based on their module and action
- // for main menu we want to add just the module as its id.
- this.menuNode.find('li').each(function () {
- var $this = $(this);
- var link = $this.find('a');
-
- var main_menu = $this.parent().hasClass('navbar') ? true : false;
-
- if (!link) {
- return;
- }
-
- var href = link.attr('href');
- if (!href) {
- return;
- }
- var url = href.substr(1);
-
- var module = broadcast.getValueFromUrl('module', url);
- var action = broadcast.getValueFromUrl('action', url);
-
- var moduleId = broadcast.getValueFromUrl("idGoal", url) || broadcast.getValueFromUrl("idDashboard", url);
-
- if (main_menu) {
- $this.attr({id: module});
- }
- // if there's a idGoal or idDashboard, use this in the ID
- else if (moduleId != '') {
- $(this).attr({id: module + '_' + action + '_' + moduleId});
- }
- else {
- $(this).attr({id: module + '_' + action});
- }
- });
-
- this.menuNode.find('a.item').click(this.onItemClick);
-
- var self = this;
- $('#header .toggle-second-menu').click(function () {
- self.menuNode.toggleClass('open fadeInLeft');
- });
- },
-
- activateMenu: function (module, action, params) {
- params = params || {};
- params.module = module;
- params.action = action;
-
- this.menuNode.find('li').removeClass('sfActive');
-
- var isAdmin = this.isAdmin();
-
- var $activeLink = this.menuNode.find('a').filter(function () {
- var url = $(this).attr('href');
- if (!url) {
- return false;
- }
-
- var found = false;
- for (var key in params) {
- if (!params.hasOwnProperty(key)
- || !params[key]
- ) {
- continue;
- }
-
- var actual;
-
- if (isAdmin) {
- actual = broadcast.getValueFromUrl(key, url);
- } else {
- actual = broadcast.getValueFromHash(key, url);
- }
-
- if (actual != params[key]) {
- return false;
- }
-
- found = true;
- // at least one param must match. Otherwise all menu items might be highlighted if params[key] = null;
- }
-
- return found;
- });
-
- $activeLink.closest('li').addClass('sfActive');
- $activeLink.closest('li.menuTab').addClass('sfActive');
- },
-
- // getting the right li is a little tricky since goals uses idGoal, and overview is index.
- getSubmenuID: function (module, id, action) {
- var $li = '';
- // So, if module is Goals, id is present, and action is not Index, must be one of the goals
- if ((module == 'Goals' || module == 'Ecommerce') && id != '' && (action != 'index')) {
- $li = $("#" + module + "_" + action + "_" + id);
- // if module is Dashboard and id is present, must be one of the dashboards
- } else if (module == 'Dashboard') {
- if (!id) id = 1;
- $li = $("#" + module + "_" + action + "_" + id);
- } else {
- $li = $("#" + module + "_" + action);
- }
- return $li;
- },
-
- loadFirstSection: function () {
- if (broadcast.isHashExists() == false) {
- $('.navbar li:first ul a:first', this.menuNode).click().addClass('sfActive');
- }
- }
-}; \ No newline at end of file
diff --git a/plugins/CoreHome/javascripts/menu_init.js b/plugins/CoreHome/javascripts/menu_init.js
deleted file mode 100644
index 099721185c..0000000000
--- a/plugins/CoreHome/javascripts/menu_init.js
+++ /dev/null
@@ -1,40 +0,0 @@
-$(function () {
- var isPageHasMenu = $('#secondNavBar').size();
- var isPageIsAdmin = $('#content.admin').size();
-
- if (isPageHasMenu) {
- piwikMenu = new menu();
- piwikMenu.init();
- if (isPageIsAdmin) {
- piwikMenu.activateMenu(broadcast.getValueFromUrl('module'), broadcast.getValueFromUrl('action'), '');
- } else {
- piwikMenu.loadFirstSection();
- }
- } else if (!isPageIsAdmin) {
- // eg multisites
- initTopControls();
- }
-
- if (isPageIsAdmin) {
- // don't use broadcast in admin page
- initTopControls();
- return;
- }
-
- if (isPageHasMenu) {
- broadcast.init();
- } else {
- broadcast.init(true);
- }
-
- $('.menuTab').keydown(function(e){
- if(e.which==27){
- var isFocusedInSubmenu = !$(':focus').parent().hasClass('menuTab')
- if(isFocusedInSubmenu){
- $(this).closest('.menuTab').attr('tabindex', -1).focus();
- $('body').scrollTop(0);
- }
- $('.sfActive').removeClass('sfActive');
- }
- })
-});
diff --git a/plugins/CoreHome/javascripts/popover.js b/plugins/CoreHome/javascripts/popover.js
index bdde52e0d8..28cad1f3f9 100644
--- a/plugins/CoreHome/javascripts/popover.js
+++ b/plugins/CoreHome/javascripts/popover.js
@@ -39,7 +39,7 @@ var Piwik_Popover = (function () {
},
close: function (event, ui) {
container.find('div.jqplot-target').trigger('piwikDestroyPlot');
- container[0].innerHTML = ''; // IE8 fix
+ container[0].innerHTML = '';
container.dialog('destroy').remove();
globalAjaxQueue.abort();
$('.ui-widget-overlay').off('click.popover');
diff --git a/plugins/CoreHome/javascripts/sparkline.js b/plugins/CoreHome/javascripts/sparkline.js
index fc3b74f692..256e6f1589 100644
--- a/plugins/CoreHome/javascripts/sparkline.js
+++ b/plugins/CoreHome/javascripts/sparkline.js
@@ -35,14 +35,30 @@ piwik.initSparklines = function() {
};
window.initializeSparklines = function () {
- var sparklineUrlParamsToIgnore = ['module', 'action', 'idSite', 'period', 'date', 'viewDataTable'];
+ var sparklineUrlParamsToIgnore = ['module', 'action', 'idSite', 'period', 'date', 'viewDataTable', 'forceView', 'random'];
- $("[data-graph-id]").each(function () {
+ $('.graphEvolution [data-report]').each(function () {
var graph = $(this);
- // try to find sparklines and add them clickable behaviour
- graph.parent().find('div.sparkline').each(function () {
+ // we search for .widget to make sure eg in the Dashboard to not update any graph of another report
+ var selectorsToFindParent = ['.widget', '.reporting-page', 'body'];
+ var index = 0, selector, parent;
+ for (index; index < selectorsToFindParent.length; index++) {
+ selector = selectorsToFindParent[index];
+ parent = graph.parents(selector).first();
+ if (parent && parent.length) {
+ break;
+ }
+ }
+
+ if (!parent || !parent.length) {
+ return;
+ }
+ var sparklines = parent.find('div.sparkline');
+
+ // try to find sparklines and add them clickable behaviour
+ sparklines.each(function () {
// find the sparkline and get it's src attribute
var sparklineUrl = $('img', this).attr('data-src');
@@ -66,8 +82,8 @@ window.initializeSparklines = function () {
// on click, reload the graph with the new url
$(this).off('click.sparkline');
$(this).on('click.sparkline', function () {
- var reportId = graph.attr('data-graph-id'),
- dataTable = $(require('piwik/UI').DataTable.getDataTableByReport(reportId));
+ var reportId = graph.attr('data-report'),
+ dataTable = graph;
// when the metrics picker is used, the id of the data table might be updated (which is correct behavior).
// for example, in goal reports it might change from GoalsgetEvolutionGraph to GoalsgetEvolutionGraph1.
diff --git a/plugins/CoreHome/javascripts/top_controls.js b/plugins/CoreHome/javascripts/top_controls.js
index 73d0edf109..dbaa81622f 100644
--- a/plugins/CoreHome/javascripts/top_controls.js
+++ b/plugins/CoreHome/javascripts/top_controls.js
@@ -62,7 +62,6 @@ function initTopControls() {
header.css('right', (Math.abs(overlap) + 18) * -1);
}
}
-
}
}
@@ -82,6 +81,22 @@ $( document ).ready(function() {
})
});
+//Keyboard controls for Top Controls Calendar through tab and enter.
+$( document ).ready(function() {
+ $('.periodSelector').keydown(function(e){
+ toggleCalendar(e);
+ })
+
+ blockPropegation();
+
+ $('.periodSelector .form-radio').keydown(function(e){
+ e.stopPropagation();
+ if(e.which==13){
+ selectPeriodRadioButton($(this));
+ }
+ })
+});
+
function toggleCalendar(e){
var calendarOpen = $('.periodSelector').hasClass('expanded');
diff --git a/plugins/CoreHome/lang/en.json b/plugins/CoreHome/lang/en.json
index 1de5049893..cbc0300282 100644
--- a/plugins/CoreHome/lang/en.json
+++ b/plugins/CoreHome/lang/en.json
@@ -49,6 +49,7 @@
"YouAreUsingTheLatestVersion": "You are using the latest version of Piwik!",
"ClickRowToExpandOrContract": "Click this row to expand or contract the subtable.",
"UndoPivotBySubtable": "This report has been pivoted %s Undo pivot",
+ "NoSuchPage": "This page does not exist",
"PivotBySubtable": "This report is not pivoted %1$s Pivot by %2$s",
"QuickAccessTitle": "Search for %s. Use the arrow keys to navigate through search results. Shortcut: Press 'f' to search.",
"MenuEntries": "Menu entries",
@@ -56,4 +57,4 @@
"AdblockIsMaybeUsed": "In case you are using an ad blocker, please disable it for this site to make sure Piwik works without any issues.",
"ChangeCurrentWebsite": "Choose a website, currently selected website: %s"
}
-} \ No newline at end of file
+}
diff --git a/plugins/CoreHome/stylesheets/coreHome.less b/plugins/CoreHome/stylesheets/coreHome.less
index 38b2ad8ba5..ab4b749b02 100644
--- a/plugins/CoreHome/stylesheets/coreHome.less
+++ b/plugins/CoreHome/stylesheets/coreHome.less
@@ -115,6 +115,12 @@ div.ui-datepicker {
display: none;
}
+.reporting-page {
+ .sparklines {
+ max-width: 1250px;
+ }
+}
+
div .sparkline {
float: left;
clear: both;
diff --git a/plugins/CoreHome/stylesheets/layout.less b/plugins/CoreHome/stylesheets/layout.less
index 5776c1a97e..03ef1c2959 100644
--- a/plugins/CoreHome/stylesheets/layout.less
+++ b/plugins/CoreHome/stylesheets/layout.less
@@ -264,8 +264,9 @@
}
}
- &.sfActive {
- .item {
+ &.active {
+ > .menuDropdown,
+ > .item {
color: @theme-color-menu-contrast-textSelected;
background-color: @theme-color-background-base;
decoration: none;
@@ -277,6 +278,7 @@
.menuDropdown {
+ width: 100%;
.items {
width: 224px;
@@ -330,7 +332,7 @@
}
}
- &.sfActive {
+ &.active {
ul {
display: block;
}
diff --git a/plugins/CoreHome/stylesheets/zen-mode.less b/plugins/CoreHome/stylesheets/zen-mode.less
index 0b9f619ea7..520d501d32 100644
--- a/plugins/CoreHome/stylesheets/zen-mode.less
+++ b/plugins/CoreHome/stylesheets/zen-mode.less
@@ -77,14 +77,26 @@
#content:not(.admin), .widget {
- h2:nth-of-type(n+2) {
- margin-top: 40px;
+ .reporting-page {
+ .smallTopMargin:not(.graphEvolution) {
+ margin-top: 20px;
+ }
}
h2 {
- padding-left: 0;
- font-size: 21px;
+ margin-top: 40px;
padding: 16px 0 12px 0;
+ font-size: 21px;
+
+ &.noTopMargin {
+ margin-top: 0;
+ padding-top: 7px;
+ }
+ }
+
+ .widget [piwik-widget-container] [piwik-widget]:first-child h2 {
+ // eg Visits Overview with Graph should not have a margin-top
+ margin-top: 0px;
}
}
diff --git a/plugins/CoreHome/templates/ReportsByDimension/_reportsByDimension.twig b/plugins/CoreHome/templates/ReportsByDimension/_reportsByDimension.twig
deleted file mode 100644
index 6ce760af1d..0000000000
--- a/plugins/CoreHome/templates/ReportsByDimension/_reportsByDimension.twig
+++ /dev/null
@@ -1,29 +0,0 @@
-<div class="reportsByDimensionView">
-
- <div class="entityList">
- {% for category, dimensions in dimensionCategories %}
- {% set firstCategory = (loop.index0 == 0) %}
- <div class='dimensionCategory'>
- {{ category|translate }}
- <ul class='listCircle'>
- {% for idx, dimension in dimensions %}
- <li class="reportDimension {% if idx == 0 and firstCategory %}activeDimension{% endif %}"
- data-url="{{ dimension.url }}">
- <span class='dimension'>{{ dimension.title|translate }}</span>
- </li>
- {% endfor %}
- </ul>
- </div>
- {% endfor %}
- </div>
-
- <div style="float:left;max-width:730px;">
- <div class="loadingPiwik" style="display:none;">
- <img src="plugins/Morpheus/images/loading-blue.gif" alt=""/>{{ 'General_LoadingData'|translate }}
- </div>
-
- <div class="dimensionReport">{{ firstReport|raw }}</div>
- </div>
- <div class="clear"></div>
-
-</div>
diff --git a/plugins/CoreHome/templates/_indexContent.twig b/plugins/CoreHome/templates/_indexContent.twig
new file mode 100644
index 0000000000..671c26e782
--- /dev/null
+++ b/plugins/CoreHome/templates/_indexContent.twig
@@ -0,0 +1,22 @@
+{% import 'ajaxMacros.twig' as ajax %}
+<div class="pageWrap container-fluid">
+<a name="main"></a>
+ {% include "@CoreHome/_notifications.twig" %}
+ <div class="top_controls">
+ {% include "@CoreHome/_periodSelect.twig" %}
+ {{ postEvent("Template.nextToCalendar") }}
+ {% render dashboardSettingsControl %}
+ {% include "@CoreHome/_headerMessage.twig" %}
+ {{ ajax.requestErrorDiv(emailSuperUser|default('')) }}
+ </div>
+
+ {{ ajax.loadingDiv() }}
+
+ <div piwik-popover></div>
+
+ <div id="content" class="home">
+ {% if content %}{{ content }}{% endif %}
+ <div piwik-reporting-page ng-cloak></div>
+ </div>
+ <div class="clear"></div>
+</div>
diff --git a/plugins/CoreHome/templates/_menu.twig b/plugins/CoreHome/templates/_menu.twig
index bf51ecf6bb..673c2ba1c8 100644
--- a/plugins/CoreHome/templates/_menu.twig
+++ b/plugins/CoreHome/templates/_menu.twig
@@ -1,61 +1,39 @@
-{% macro submenuItem(name, url, anchorlink, tooltip) %}
- {% if name|slice(0,1) != '_' %}
- <li role="menuitem" title="{{ tooltip|default("")|translate|e('html_attr') }}">
- <a class="item" href="{% if anchorlink %}#{% else %}index.php?{% endif %}{{ url|urlRewriteWithParameters|slice(1) }}" tabindex="5">
- {{ name|translate }}
- </a>
- </li>
- {% endif %}
-{% endmacro %}
-
-{% macro groupedItem(name, group, anchorlink) %}
- <li role="menuitem" title="{{ name|translate|e('html_attr') }}">
- <div piwik-menudropdown show-search="true" menu-title="{{ name|translate|e('html_attr') }}">
- {% for item in group.getItems %}
- <a class="item menuItem"
- href='{% if anchorlink %}#?{% else %}index.php?{% endif %}{{ item.url|urlRewriteWithParameters|slice(1) }}'
- title="{% if item.tooltip %}{{ item.tooltip|e('html_attr') }}{% endif %}">
- {{ item.name|translate }}
- </a>
- {% endfor %}
- </div>
- </li>
-{% endmacro %}
-
-{% macro getId(urlParameters) -%}
- {% if urlParameters is iterable -%}
- {{ urlParameters|urlRewriteWithParameters }}
- {%- endif %}
-{%- endmacro %}
-
-{% macro menu(menu, anchorlink, cssClass) %}
+{% macro menu(menu, anchorlink, cssClass, currentModule, currentAction) %}
<div id="secondNavBar" class="{{ cssClass }}">
<div id="search" ng-cloak>
<div piwik-quick-access class="borderedControl"></div>
</div>
- <ul role="menu" aria-label="{{ 'CoreHome_MainNavigation'|translate|e('html_attr') }}" class="navbar">
+ <ul class="navbar" aria-label="{{ 'CoreHome_MainNavigation'|translate|e('html_attr') }}" role="menu">
{% for level1,level2 in menu %}
+
{% set hasSubmenuItem = false %}
{% for name,urlParameters in level2 %}
- {% if urlParameters._url is defined and urlParameters._url is not iterable %}
- {% set hasSubmenuItem = true %}
- {% elseif name|slice(0,1) != '_' %}
+ {% if name|slice(0,1) != '_' %}
{% set hasSubmenuItem = true %}
{% endif %}
{% endfor %}
{% if hasSubmenuItem %}
- <li role="menuitem" class="menuTab" id="{% if level2._url is defined and level2._url is not empty %}{{ _self.getId(level2._url) }}{% endif %}">
- <a class="item" href="" tabindex="5">
+ <li class="menuTab" role="menuitem">
+
+ <a class="item" tabindex="5">
<span class="menu-icon {{ level2._icon|default('icon-arrow-right') }}"></span>{{ level1|translate }}
+ <span class="hidden">
+ {{ 'CoreHome_Menu'|translate }}
+ </span>
</a>
-
- <ul role="menu" title="{{ level1|translate|e('html_attr') }}">
+ <ul role="menu">
{% for name,urlParameters in level2 %}
- {% if urlParameters._url is defined and urlParameters._url is not iterable %}
- {{ _self.groupedItem(name,urlParameters._url, anchorlink) }}
- {% elseif name|slice(0,1) != '_' %}
- {{ _self.submenuItem(name,urlParameters._url, anchorlink, urlParameters._tooltip) }}
+ {% if name|slice(0,1) != '_' %}
+ <li {% if urlParameters._url.module is defined and urlParameters._url.module == currentModule and urlParameters._url.action is defined and urlParameters._url.action == currentAction %}class="active"{% endif %}
+ role="menuitem"
+ >
+ <a class="item" tabindex="5"
+ title="{{ urlParameters._tooltip|default('')|translate|e('html_attr') }}"
+ href="index.php?{{ urlParameters._url|urlRewriteWithParameters|slice(1) }}">
+ {{ name|translate }}
+ </a>
+ </li>
{% endif %}
{% endfor %}
</ul>
diff --git a/plugins/CoreHome/templates/getDefaultIndexView.twig b/plugins/CoreHome/templates/getDefaultIndexView.twig
index 62e8d8ffe7..97fae5e996 100644
--- a/plugins/CoreHome/templates/getDefaultIndexView.twig
+++ b/plugins/CoreHome/templates/getDefaultIndexView.twig
@@ -15,6 +15,9 @@
<div id="content" class="home">
{% if content %}{{ content }}{% endif %}
+ <div piwik-reporting-page ng-cloak></div>
</div>
+ <div class="clear"></div>
+
{% endblock %}
diff --git a/plugins/CoreHome/templates/widgetContainer.twig b/plugins/CoreHome/templates/widgetContainer.twig
new file mode 100755
index 0000000000..b3eda12997
--- /dev/null
+++ b/plugins/CoreHome/templates/widgetContainer.twig
@@ -0,0 +1,18 @@
+<div>
+ <div piwik-widget
+ containerid="{{ containerId|e('html_attr') }}"
+ widgetized="{% if isWidgetized %}true{% else %}false{% endif %}"></div>
+
+ <script type="text/javascript">
+ $(function () {
+
+ var piwikWidget = $('[piwik-widget][containerid={{ containerId|e('js') }}]');
+
+ angular.element(document).injector().invoke(function($compile) {
+ var scope = angular.element(piwikWidget).scope();
+ $compile(piwikWidget)(scope.$new());
+ });
+
+ });
+ </script>
+</div> \ No newline at end of file
diff --git a/plugins/CoreUpdater/templates/layout.twig b/plugins/CoreUpdater/templates/layout.twig
index 142a36015e..bb9f33c12b 100644
--- a/plugins/CoreUpdater/templates/layout.twig
+++ b/plugins/CoreUpdater/templates/layout.twig
@@ -36,8 +36,6 @@
{% include "@CoreHome/_favicon.twig" %}
</head>
-<!--[if lt IE 9 ]>
-<body id="simple" ng-app="app" class="old-ie"> <![endif]-->
<!--[if (gte IE 9)|!(IE)]><!-->
<body id="simple" ng-app="app"><!--<![endif]-->
diff --git a/plugins/CoreVisualizations/JqplotDataGenerator/Evolution.php b/plugins/CoreVisualizations/JqplotDataGenerator/Evolution.php
index 5675153c34..5114167364 100644
--- a/plugins/CoreVisualizations/JqplotDataGenerator/Evolution.php
+++ b/plugins/CoreVisualizations/JqplotDataGenerator/Evolution.php
@@ -12,7 +12,6 @@ use Piwik\Archive\DataTableFactory;
use Piwik\Common;
use Piwik\DataTable;
use Piwik\DataTable\Row;
-use Piwik\Menu\MenuMain;
use Piwik\Plugins\CoreVisualizations\JqplotDataGenerator;
use Piwik\Url;
@@ -76,7 +75,6 @@ class Evolution extends JqplotDataGenerator
$periodLabel = reset($dataTables)->getMetadata(DataTableFactory::TABLE_METADATA_PERIOD_INDEX)->getLabel();
$axisXOnClick = array();
- $queryStringAsHash = $this->getQueryStringAsHash();
foreach ($dataTable->getDataTables() as $metadataDataTable) {
$dateInUrl = $metadataDataTable->getMetadata(DataTableFactory::TABLE_METADATA_PERIOD_INDEX)->getDateStart();
$parameters = array(
@@ -85,16 +83,7 @@ class Evolution extends JqplotDataGenerator
'date' => $dateInUrl->toString(),
'segment' => \Piwik\API\Request::getRawSegmentFromRequest()
);
- $hash = '';
- if (!empty($queryStringAsHash)) {
- $hash = '#' . Url::getQueryStringFromParameters($queryStringAsHash + $parameters);
- }
- $link = 'index.php?' .
- Url::getQueryStringFromParameters(array(
- 'module' => 'CoreHome',
- 'action' => 'index',
- ) + $parameters)
- . $hash;
+ $link = Url::getQueryStringFromParameters($parameters);
$axisXOnClick[] = $link;
}
$visualization->setAxisXOnClick($axisXOnClick);
@@ -144,34 +133,6 @@ class Evolution extends JqplotDataGenerator
return $label;
}
- /**
- * We link the graph dots to the same report as currently being displayed (only the date would change).
- *
- * In some cases the widget is loaded within a report that doesn't exist as such.
- * For example, the dashboards loads the 'Last visits graph' widget which can't be directly linked to.
- * Instead, the graph must link back to the dashboard.
- *
- * In other cases, like Visitors>Overview or the Goals graphs, we can link the graph clicks to the same report.
- *
- * To detect whether or not we can link to a report, we simply check if the current URL from which it was loaded
- * belongs to the menu or not. If it doesn't belong to the menu, we do not append the hash to the URL,
- * which results in loading the dashboard.
- *
- * @return array Query string array to append to the URL hash or false if the dashboard should be displayed
- */
- private function getQueryStringAsHash()
- {
- $queryString = Url::getArrayFromCurrentQueryString();
- $piwikParameters = array('idSite', 'date', 'period', 'XDEBUG_SESSION_START', 'KEY');
- foreach ($piwikParameters as $parameter) {
- unset($queryString[$parameter]);
- }
- if (MenuMain::getInstance()->isUrlFound($queryString)) {
- return $queryString;
- }
- return false;
- }
-
private function isLinkEnabled()
{
static $linkEnabled;
diff --git a/plugins/CoreVisualizations/Visualizations/Sparkline.php b/plugins/CoreVisualizations/Visualizations/Sparkline.php
index 2ca75bbcfe..3c1dbf5a56 100644
--- a/plugins/CoreVisualizations/Visualizations/Sparkline.php
+++ b/plugins/CoreVisualizations/Visualizations/Sparkline.php
@@ -25,7 +25,7 @@ class Sparkline extends ViewDataTable
* @see ViewDataTable::main()
* @return mixed
*/
- protected function buildView()
+ public function render()
{
// If period=range, we force the sparkline to draw daily data points
$period = Common::getRequestVar('period');
@@ -58,7 +58,7 @@ class Sparkline extends ViewDataTable
$graph->main();
- return $graph;
+ return $graph->render();
}
/**
diff --git a/plugins/CoreVisualizations/Visualizations/Sparklines.php b/plugins/CoreVisualizations/Visualizations/Sparklines.php
new file mode 100644
index 0000000000..3b576c885e
--- /dev/null
+++ b/plugins/CoreVisualizations/Visualizations/Sparklines.php
@@ -0,0 +1,147 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\CoreVisualizations\Visualizations;
+
+use Piwik\DataTable;
+use Piwik\Metrics;
+use Piwik\Plugin\ViewDataTable;
+use Piwik\Url;
+use Piwik\View;
+
+/**
+ * Reads the requested DataTable from the API and prepares data for the Sparklines view. It can display any amount
+ * of sparklines. Within a reporting page sparklines are shown in 2 columns, in a dashboard or when exported as a widget
+ * the sparklines are shown in one column.
+ *
+ * The sparklines view currently only supports requesting columns from the same API (the API method of the defining
+ * report) via {Sparklines\Config::addSparklineMetric($columns = array('nb_visits', 'nb_unique_visitors'))}.
+ *
+ * Example:
+ * $view->config->addSparklineMetric('nb_visits'); // if an array of metrics given, they will be displayed comma separated
+ * $view->config->addTranslation('nb_visits', 'Visits');
+ * Results in: [sparkline image] X visits
+ * Data is fetched from the configured $view->requestConfig->apiMethodToRequestDataTable.
+ *
+ * In case you want to add any custom sparklines from any other API method you can call
+ * {@link Sparklines\Config::addSparkline()}.
+ *
+ * Example:
+ * $sparklineUrlParams = array('columns' => array('nb_visits));
+ * $evolution = array('currentValue' => 5, 'pastValue' => 10, 'tooltip' => 'Foo bar');
+ * $view->config->addSparkline($sparklineUrlParams, $value = 5, $description = 'Visits', $evolution);
+ *
+ * @property Sparklines\Config $config
+ */
+class Sparklines extends ViewDataTable
+{
+ const ID = 'sparklines';
+
+ public static function getDefaultConfig()
+ {
+ return new Sparklines\Config();
+ }
+
+ /**
+ * @see ViewDataTable::main()
+ * @return mixed
+ */
+ public function render()
+ {
+ $view = new View('@CoreVisualizations/_dataTableViz_sparklines.twig');
+
+ $columnsList = array();
+ if ($this->config->hasSparklineMetrics()) {
+ foreach ($this->config->getSparklineMetrics() as $cols) {
+ $columnsList = array_merge($cols['columns'], $columnsList);
+ }
+ }
+
+ $this->requestConfig->request_parameters_to_modify['columns'] = $columnsList;
+ $this->requestConfig->request_parameters_to_modify['format_metrics'] = '1';
+
+ if (!empty($this->requestConfig->apiMethodToRequestDataTable)) {
+ $this->fetchConfiguredSparklines();
+ }
+
+ $view->sparklines = $this->config->getSortedSparklines();
+
+ return $view->render();
+ }
+
+ private function fetchConfiguredSparklines()
+ {
+ $data = $this->loadDataTableFromAPI();
+
+ $this->applyFilters($data);
+
+ if (!$this->config->hasSparklineMetrics()) {
+ foreach ($data->getColumns() as $column) {
+ $this->config->addSparklineMetric($column);
+ }
+ }
+
+ $translations = $this->config->translations;
+
+ $firstRow = $data->getFirstRow();
+
+ foreach ($this->config->getSparklineMetrics() as $sparklineMetric) {
+ $column = $sparklineMetric['columns'];
+ $order = $sparklineMetric['order'];
+
+ if ($column === 'label') {
+ continue;
+ }
+
+ if (empty($column)) {
+ $this->config->addPlaceholder($order);
+ continue;
+ }
+
+ if (!is_array($column)) {
+ $column = array($column);
+ }
+
+ $values = array();
+ $descriptions = array();
+
+ foreach ($column as $col) {
+ $value = $firstRow->getColumn($col);
+
+ if ($value === false) {
+ $value = 0;
+ }
+
+ $values[] = $value;
+ $descriptions[] = isset($translations[$col]) ? $translations[$col] : $col;
+ }
+
+ $sparklineUrlParams = array(
+ 'columns' => $column,
+ 'module' => $this->requestConfig->getApiModuleToRequest(),
+ 'action' => $this->requestConfig->getApiMethodToRequest()
+ );
+
+ $this->config->addSparkline($sparklineUrlParams, $values, $descriptions, null, $order);
+ }
+ }
+
+ private function applyFilters(DataTable\DataTableInterface $table)
+ {
+ foreach ($this->config->getPriorityFilters() as $filter) {
+ $table->filter($filter[0], $filter[1]);
+ }
+
+ // queue other filters so they can be applied later if queued filters are disabled
+ foreach ($this->config->getPresentationFilters() as $filter) {
+ $table->queueFilter($filter[0], $filter[1]);
+ }
+
+ $table->applyQueuedFilters();
+ }
+}
diff --git a/plugins/CoreVisualizations/Visualizations/Sparklines/Config.php b/plugins/CoreVisualizations/Visualizations/Sparklines/Config.php
new file mode 100644
index 0000000000..ca54a6d564
--- /dev/null
+++ b/plugins/CoreVisualizations/Visualizations/Sparklines/Config.php
@@ -0,0 +1,354 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+
+namespace Piwik\Plugins\CoreVisualizations\Visualizations\Sparklines;
+use Piwik\Common;
+use Piwik\DataTable\Filter\CalculateEvolutionFilter;
+use Piwik\Metrics;
+use Piwik\NoAccessException;
+use Piwik\Period\Range;
+use Piwik\Site;
+use Piwik\Url;
+
+/**
+ * DataTable Visualization that derives from Sparklines.
+ */
+class Config extends \Piwik\ViewDataTable\Config
+{
+ /**
+ * Holds metrics / column names that will be used to fetch data from the configured $requestConfig API.
+ * Default value: array
+ */
+ private $sparkline_metrics = array();
+
+ /**
+ * Holds the actual sparkline entries based on fetched data that will be used in the template.
+ * @var array
+ */
+ private $sparklines = array();
+
+ public function __construct()
+ {
+ parent::__construct();
+
+ $this->translations = Metrics::getDefaultMetricTranslations();
+ }
+
+ /**
+ * @ignore
+ * @return array
+ */
+ public function getSparklineMetrics()
+ {
+ return $this->sparkline_metrics;
+ }
+
+ /**
+ * @ignore
+ * @return bool
+ */
+ public function hasSparklineMetrics()
+ {
+ return !empty($this->sparkline_metrics);
+ }
+
+ /**
+ * Removes an existing sparkline entry. Especially useful in dataTable filters in case sparklines should be not
+ * displayed depending on the fetched data.
+ *
+ * Example:
+ * $config->addSparklineMetric('nb_users');
+ * $config->filters[] = function ($dataTable) use ($config) {
+ * if ($dataTable->getFirstRow()->getColumn('nb_users') == 0) {
+ * // do not show a sparkline if there are no recorded users
+ * $config->removeSparklineMetric('nb_users');
+ * }
+ * }
+ *
+ * @param array|string $metricNames The name of the metrics in the same format they were used when added via
+ * {@link addSparklineMetric}
+ */
+ public function removeSparklineMetric($metricNames)
+ {
+ foreach ($this->sparkline_metrics as $index => $metric) {
+ if ($metric['columns'] === $metricNames) {
+ array_splice($this->sparkline_metrics, $index, 1);
+
+ break;
+ }
+ }
+ }
+
+ /**
+ * Replaces an existing sparkline entry with different columns. Especially useful in dataTable filters in case
+ * sparklines should be not displayed depending on the fetched data.
+ *
+ * Example:
+ * $config->addSparklineMetric('nb_users');
+ * $config->filters[] = function ($dataTable) use ($config) {
+ * if ($dataTable->getFirstRow()->getColumn('nb_users') == 0) {
+ * // instead of showing the sparklines for users, show a placeholder if there are no recorded users
+ * $config->replaceSparklineMetric(array('nb_users'), '');
+ * }
+ * }
+ *
+ * @param array|string $metricNames The name of the metrics in the same format they were used when added via
+ * {@link addSparklineMetric}
+ * @param array|string $replacementColumns The removed columns will be replaced with these columns
+ */
+ public function replaceSparklineMetric($metricNames, $replacementColumns)
+ {
+ foreach ($this->sparkline_metrics as $index => $metric) {
+ if ($metric['columns'] === $metricNames) {
+ $this->sparkline_metrics[$index]['columns'] = $replacementColumns;
+ }
+ }
+ }
+
+ /**
+ * Adds a new sparkline.
+ *
+ * It will show a sparkline image, the value of the resolved metric name and a descrption. Optionally, multiple
+ * values can be shown after a sparkline image by passing multiple metric names
+ * (eg array('nb_visits', 'nb_actions')). The data will be requested from the configured api method see
+ * {@link Piwik\ViewDataTable\RequestConfig::$apiMethodToRequestDataTable}.
+ *
+ * Example:
+ * $config->addSparklineMetric('nb_visits');
+ * $config->addTranslation('nb_visits', 'Visits');
+ * Results in: [sparkline image] X visits
+ *
+ * Example:
+ * $config->addSparklineMetric(array('nb_visits', 'nb_actions'));
+ * $config->addTranslations(array('nb_visits' => 'Visits', 'nb_actions' => 'Actions'));
+ * Results in: [sparkline image] X visits, Y actions
+ *
+ * @param string|array $metricName Either one metric name (eg 'nb_visits') or an array of metric names
+ * @param int|null $order Defines the order. The lower the order the earlier the sparkline will be displayed.
+ * By default the sparkline will be appended to the end.
+ */
+ public function addSparklineMetric($metricName, $order = null)
+ {
+ $this->sparkline_metrics[] = array(
+ 'columns' => $metricName,
+ 'order' => $order
+ );
+ }
+
+ /**
+ * Adds a placeholder. In this case nothing will be shown, neither a sparkline nor any description. This can be
+ * useful if you want to have some kind of separator. Eg if you want to have a sparkline on the left side but
+ * not sparkline on the right side.
+ *
+ * @param int|null $order Defines the order. The lower the order the earlier the sparkline will be displayed.
+ * By default the sparkline will be appended to the end.
+ */
+ public function addPlaceholder($order = null)
+ {
+ $this->sparklines[] = array(
+ 'url' => '',
+ 'metrics' => array(),
+ 'order' => $this->getSparklineOrder($order)
+ );
+ }
+
+ /**
+ * Add a new sparkline to be displayed to the view.
+ *
+ * Each sparkline can consist of one or multiple metrics. One metric consists of a value and a description. By
+ * default the value is shown first, then the description. The description can optionally contain a '%s' in case
+ * the value shall be displayed within the description. If multiple metrics are given, they will be separated by
+ * a comma.
+ *
+ * @param array $requestParamsForSparkline You need to at least set a module / action eg
+ * array('columns' => array('nb_visit'), 'module' => '', 'action' => '')
+ * @param int|float|string|array $value Either the metric value or an array of values.
+ * @param string|array $description Either one description or an array of descriptions. If an array, both
+ * $value and $description need the same amount of array entries.
+ * $description[0] should be the description for $value[0].
+ * $description should be already translated. If $value should appear
+ * somewhere within the text a `%s` can be used in the translation.
+ * @param array|null $evolution Optional array containing at least the array keys 'currentValue' and
+ * 'pastValue' which are needed to calculate the correct percentage.
+ * An optional 'tooltip' can be set as well. Eg
+ * array('currentValue' => 10, 'pastValue' => 20,
+ * 'tooltip' => '10 visits in 2015-07-26 compared to 20 visits in 2015-07-25')
+ * @param int $order Defines the order. The lower the order the earlier the sparkline will be
+ * displayed. By default the sparkline will be appended to the end.
+ * @throws \Exception In case an evolution parameter is set but has wrong data structure
+ */
+ public function addSparkline($requestParamsForSparkline, $value, $description, $evolution = null, $order = null)
+ {
+ $metrics = array();
+
+ if (is_array($value)) {
+ $values = $value;
+ } else {
+ $values = array($value);
+ }
+
+ if (!is_array($description)) {
+ $description = array($description);
+ }
+
+ if (count($values) === count($description)) {
+ foreach ($values as $index => $value) {
+ $metrics[] = array(
+ 'value' => $value,
+ 'description' => $description[$index]
+ );
+ }
+ } else {
+ $msg = 'The number of values and descriptions need to be the same to add a sparkline. ';
+ $msg .= 'Values: ' . implode(', ', $values). ' Descriptions: ' . implode(', ', $description);
+ throw new \Exception($msg);
+ }
+
+ if (empty($metrics)) {
+ return;
+ }
+
+ $sparkline = array(
+ 'url' => $this->getUrlSparkline($requestParamsForSparkline),
+ 'metrics' => $metrics,
+ 'order' => $this->getSparklineOrder($order)
+ );
+
+ if (!empty($evolution)) {
+ if (!is_array($evolution) ||
+ !array_key_exists('currentValue', $evolution) ||
+ !array_key_exists('pastValue', $evolution)) {
+ throw new \Exception('In order to show an evolution in the sparklines view a currentValue and pastValue array key needs to be present');
+ }
+
+ $evolutionPercent = CalculateEvolutionFilter::calculate($evolution['currentValue'], $evolution['pastValue'], $precision = 1);
+
+ // do not display evolution if evolution percent is 0 and current value is 0
+ if ($evolutionPercent != 0 || $evolution['currentValue'] != 0) {
+ $sparkline['evolution'] = array(
+ 'percent' => $evolutionPercent,
+ 'tooltip' => !empty($evolution['tooltip']) ? $evolution['tooltip'] : null
+ );
+ }
+
+ }
+
+ $this->sparklines[] = $sparkline;
+ }
+
+ /**
+ * @return array
+ * @ignore
+ */
+ public function getSortedSparklines()
+ {
+ usort($this->sparklines, function ($a, $b) {
+ if ($a['order'] == $b['order']) {
+ return 0;
+ }
+ return ($a['order'] < $b['order']) ? -1 : 1;
+ });
+
+ return $this->sparklines;
+ }
+
+ private function getSparklineOrder($order)
+ {
+ if (!isset($order)) {
+ // make sure to append to the end if nothing set (in the order they are added)
+ $order = 999 + count($this->sparklines);
+ }
+
+ return (int) $order;
+ }
+
+ /**
+ * Returns a URL to a sparkline image for a report served by the current plugin.
+ *
+ * The result of this URL should be used with the [sparkline()](/api-reference/Piwik/View#twig) twig function.
+ *
+ * The current site ID and period will be used.
+ *
+ * @param array $customParameters The array of query parameter name/value pairs that
+ * should be set in result URL.
+ * @return string The generated URL.
+ */
+ private function getUrlSparkline($customParameters = array())
+ {
+ $customParameters['viewDataTable'] = 'sparkline';
+
+ $params = $this->getGraphParamsModified($customParameters);
+
+ // convert array values to comma separated
+ foreach ($params as &$value) {
+ if (is_array($value)) {
+ $value = rawurlencode(implode(',', $value));
+ }
+ }
+ $url = Url::getCurrentQueryStringWithParametersModified($params);
+ return $url;
+ }
+
+ /**
+ * Returns the array of new processed parameters once the parameters are applied.
+ * For example: if you set range=last30 and date=2008-03-10,
+ * the date element of the returned array will be "2008-02-10,2008-03-10"
+ *
+ * Parameters you can set:
+ * - range: last30, previous10, etc.
+ * - date: YYYY-MM-DD, today, yesterday
+ * - period: day, week, month, year
+ *
+ * @param array $paramsToSet array( 'date' => 'last50', 'viewDataTable' =>'sparkline' )
+ * @throws \Piwik\NoAccessException
+ * @return array
+ */
+ private function getGraphParamsModified($paramsToSet = array())
+ {
+ if (!isset($paramsToSet['period'])) {
+ $period = Common::getRequestVar('period');
+ } else {
+ $period = $paramsToSet['period'];
+ }
+
+ if ($period == 'range') {
+ return $paramsToSet;
+ }
+
+ if (!isset($paramsToSet['range'])) {
+ $range = 'last30';
+ } else {
+ $range = $paramsToSet['range'];
+ }
+
+ if (!isset($paramsToSet['idSite'])) {
+ $idSite = Common::getRequestVar('idSite');
+ } else {
+ $idSite = $paramsToSet['idSite'];
+ }
+
+ if (!isset($paramsToSet['date'])) {
+ $endDate = Common::getRequestVar('date', 'yesterday', 'string');
+ } else {
+ $endDate = $paramsToSet['date'];
+ }
+
+ $site = new Site($idSite);
+
+ if (is_null($site)) {
+ throw new NoAccessException("Website not initialized, check that you are logged in and/or using the correct token_auth.");
+ }
+
+ $paramDate = Range::getRelativeToEndDate($period, $range, $endDate, $site);
+
+ $params = array_merge($paramsToSet, array('date' => $paramDate));
+ return $params;
+ }
+
+}
diff --git a/plugins/CoreVisualizations/javascripts/jqplotEvolutionGraph.js b/plugins/CoreVisualizations/javascripts/jqplotEvolutionGraph.js
index 2fa3cee126..b77add4962 100644
--- a/plugins/CoreVisualizations/javascripts/jqplotEvolutionGraph.js
+++ b/plugins/CoreVisualizations/javascripts/jqplotEvolutionGraph.js
@@ -90,41 +90,7 @@
&& typeof self.jqplotParams.axes.xaxis.onclick[lastTick] == 'string') {
var url = self.jqplotParams.axes.xaxis.onclick[lastTick];
- if (url && -1 === url.indexOf('#')) {
- var module = broadcast.getValueFromHash('module');
- var action = broadcast.getValueFromHash('action');
- var idGoal = broadcast.getValueFromHash('idGoal');
- var idDimension = broadcast.getValueFromHash('idDimension');
- var idSite = broadcast.getValueFromUrl('idSite', url);
- var period = broadcast.getValueFromUrl('period', url);
- var date = broadcast.getValueFromUrl('date', url);
-
- if (module && action) {
- url += '#module=' + module + '&action=' + action;
-
- if (idSite) {
- url += '&idSite=' + idSite;
- }
-
- if (idGoal) {
- url += '&idGoal=' + idGoal;
- }
-
- if (idDimension) {
- url += '&idDimension=' + idDimension;
- }
-
- if (period) {
- url += '&period=' + period;
- }
-
- if (period) {
- url += '&date=' + date;
- }
- }
- }
-
- piwikHelper.redirectToUrl(url);
+ broadcast.propagateNewPage(url);
}
})
.on('jqplotPiwikTickOver', function (e, tick) {
@@ -166,6 +132,10 @@
render: function () {
JqplotGraphDataTablePrototype.render.call(this);
+
+ if (initializeSparklines) {
+ initializeSparklines();
+ }
}
});
diff --git a/plugins/CoreVisualizations/templates/_dataTableViz_sparklines.twig b/plugins/CoreVisualizations/templates/_dataTableViz_sparklines.twig
new file mode 100644
index 0000000000..38a0b9d97e
--- /dev/null
+++ b/plugins/CoreVisualizations/templates/_dataTableViz_sparklines.twig
@@ -0,0 +1,34 @@
+{% import '@CoreVisualizations/macros.twig' as macros %}
+
+{% if not isWidget %}
+<div class="row">
+ <div class="col-md-6">
+{% endif %}
+
+ {% for key, sparkline in sparklines %}
+ {% if key is even %}
+ {{ macros.singleSparkline(sparkline) }}
+ {% endif %}
+ {% endfor %}
+
+{% if not isWidget %}
+ <br style="clear:left"/>
+ </div>
+ <div class="col-md-6">
+{% endif %}
+
+ {% for key, sparkline in sparklines %}
+ {% if key is odd %}
+ {{ macros.singleSparkline(sparkline) }}
+ {% endif %}
+ {% endfor %}
+
+ <br style="clear:left"/>
+
+{% if not isWidget %}
+ </div>
+</div>
+{% endif %}
+
+{% include "_sparklineFooter.twig" %}
+
diff --git a/plugins/CoreVisualizations/templates/macros.twig b/plugins/CoreVisualizations/templates/macros.twig
new file mode 100644
index 0000000000..ffd1885be1
--- /dev/null
+++ b/plugins/CoreVisualizations/templates/macros.twig
@@ -0,0 +1,32 @@
+{% macro singleSparkline(sparkline) %}
+ <div class="sparkline">
+ {% if sparkline.url %}{{ sparkline(sparkline.url)|raw }}{% endif %}
+ {% for metric in sparkline.metrics %}
+ {% if '%s' in metric.description -%}
+ {{ metric.description|translate("<strong>"~metric.value~"</strong>")|raw }}
+ {%- else %}
+ <strong>{{ metric.value }}</strong> {{ metric.description }}
+ {%- endif %}{% if not loop.last %}, {% endif %}
+ {% endfor %}
+ {% if sparkline.evolution is defined %}
+
+ {% set evolutionPretty = sparkline.evolution.percent %}
+
+ {% if sparkline.evolution.percent < 0 %}
+ {% set evolutionClass = 'negative-evolution' %}
+ {% set evolutionIcon = 'arrow_down.png' %}
+ {% elseif sparkline.evolution.percent == 0 %}
+ {% set evolutionClass = 'neutral-evolution' %}
+ {% set evolutionIcon = 'stop.png' %}
+ {% else %}
+ {% set evolutionClass = 'positive-evolution' %}
+ {% set evolutionIcon = 'arrow_up.png' %}
+ {% set evolutionPretty = '+' ~ sparkline.evolution.percent %}
+ {% endif %}
+
+ <span class="metricEvolution" title="{{ sparkline.evolution.tooltip }}"><img
+ style="padding-right:4px" src="plugins/MultiSites/images/{{ evolutionIcon }}"/>
+ <strong class="{{ evolutionClass }}">{{ evolutionPretty }}</strong></span>
+ {% endif %}
+ </div>
+{% endmacro %}
diff --git a/plugins/CoreVisualizations/tests/Integration/SparklinesConfigTest.php b/plugins/CoreVisualizations/tests/Integration/SparklinesConfigTest.php
new file mode 100644
index 0000000000..45f4876ea4
--- /dev/null
+++ b/plugins/CoreVisualizations/tests/Integration/SparklinesConfigTest.php
@@ -0,0 +1,138 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+
+namespace Piwik\Plugins\CoreVisualizations\tests\Integration;
+
+use Piwik\Plugins\CoreVisualizations\Visualizations\Sparklines\Config;
+use Piwik\Tests\Framework\Fixture;
+use Piwik\Tests\Framework\Mock\FakeAccess;
+use Piwik\Tests\Framework\TestCase\IntegrationTestCase;
+use Piwik\Translate;
+
+/**
+ * @group CoreVisualizations
+ * @group SparklinesConfigTest
+ * @group Plugins
+ */
+class SparklinesConfigTest extends IntegrationTestCase
+{
+ /**
+ * @var Config
+ */
+ private $config;
+
+ public function setUp()
+ {
+ parent::setUp();
+ FakeAccess::$superUser = true;
+
+ if (!Fixture::siteCreated(1)) {
+ Fixture::createWebsite('2014-01-01 00:00:00');
+ }
+
+ $this->config = new Config();
+
+ Translate::loadAllTranslations();
+ }
+
+ public function tearDown()
+ {
+ Translate::reset();
+
+ parent::tearDown();
+ }
+
+ public function test_addSparkline_shouldAddAMinimalSparklineWithOneValueAndUseDefaultOrder()
+ {
+ $this->config->addSparkline($this->sparklineParams(), $value = 10, $description = 'Visits');
+
+ $expectedSparkline = array(
+ 'url' => '?period=day&date=2012-03-06,2012-04-04&idSite=1&module=CoreHome&action=renderMe&viewDataTable=sparkline',
+ 'metrics' => array (
+ array ('value' => 10, 'description' => 'Visits'),
+ ),
+ 'order' => 999
+ );
+
+ $this->assertSame(array($expectedSparkline), $this->config->getSortedSparklines());
+ }
+
+ public function test_addSparkline_shouldAddSparklineWithMultipleValues()
+ {
+ $this->config->addSparkline($this->sparklineParams(), $values = array(10, 20), $description = array('Visits', 'Actions'));
+
+ $sparklines = $this->config->getSortedSparklines();
+
+ $this->assertSame(array (
+ array ('value' => 10, 'description' => 'Visits'),
+ array ('value' => 20, 'description' => 'Actions'),
+ ), $sparklines[0]['metrics']);
+ }
+
+ /**
+ * @expectedException \Exception
+ * @expectedExceptionMessage Values: 10, 20, 30 Descriptions: Visits, Actions
+ */
+ public function test_addSparkline_shouldThrowAnException_IfValuesDoesNotMatchAmountOfDescriptions()
+ {
+ $this->config->addSparkline($this->sparklineParams(), $values = array(10, 20, 30), $description = array('Visits', 'Actions'));
+ }
+
+ public function test_addSparkline_shouldAddEvolution()
+ {
+ $evolution = array('currentValue' => 10, 'pastValue' => 21,
+ 'tooltip' => '1 visit compared to 2 visits');
+ $this->config->addSparkline($this->sparklineParams(), $value = 10, $description = 'Visits', $evolution);
+
+ $sparklines = $this->config->getSortedSparklines();
+
+ $this->assertSame(array (
+ 'percent' => '-52.4%',
+ 'tooltip' => '1 visit compared to 2 visits'
+ ), $sparklines[0]['evolution']);
+ }
+
+ public function test_addSparkline_shouldAddOrder()
+ {
+ $this->config->addSparkline($this->sparklineParams(), $value = 10, $description = 'Visits', $evolution = null, $order = '42');
+
+ $sparklines = $this->config->getSortedSparklines();
+
+ $this->assertSame(42, $sparklines[0]['order']);
+ }
+
+ public function test_addSparkline_shouldBeAbleToBuildSparklineUrlBasedOnGETparams()
+ {
+ $oldGet = $_GET;
+ $_GET = $this->sparklineParams();
+ $this->config->addSparkline(array('columns' => 'nb_visits'), $value = 10, $description = 'Visits');
+ $_GET = $oldGet;
+
+ $sparklines = $this->config->getSortedSparklines();
+
+ $this->assertSame('?columns=nb_visits&viewDataTable=sparkline&date=2012-03-06,2012-04-04', $sparklines[0]['url']);
+ }
+
+ private function sparklineParams($params = array())
+ {
+ $params['period'] = 'day';
+ $params['date'] = '2012-04-04';
+ $params['idSite'] = '1';
+ $params['module'] = 'CoreHome';
+ $params['action'] = 'renderMe';
+
+ return $params;
+ }
+
+ public function provideContainerConfig()
+ {
+ return array(
+ 'Piwik\Access' => new FakeAccess()
+ );
+ }
+}
diff --git a/plugins/CoreVisualizations/tests/Unit/SparklinesConfigTest.php b/plugins/CoreVisualizations/tests/Unit/SparklinesConfigTest.php
new file mode 100644
index 0000000000..516f19f8e1
--- /dev/null
+++ b/plugins/CoreVisualizations/tests/Unit/SparklinesConfigTest.php
@@ -0,0 +1,130 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+
+namespace Piwik\Plugins\CoreVisualizations\tests\Unit;
+use Piwik\Plugins\CoreVisualizations\Visualizations\Sparklines\Config;
+
+/**
+ * @group CoreVisualizations
+ * @group SparklinesConfigTest
+ * @group Sparklines
+ * @group Plugins
+ */
+class SparklinesConfigTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * @var Config
+ */
+ private $config;
+
+ public function setUp()
+ {
+ $this->config = new Config();
+ }
+
+ public function test_hasSparklineMetrics_shouldNotHaveSparklineMetrics_ByDefault()
+ {
+ $this->assertFalse($this->config->hasSparklineMetrics());
+ }
+
+ public function test_hasSparklineMetrics_shouldHaveSparklineMetrics_IfAtLeastOneWasAdded()
+ {
+ $this->config->addSparklineMetric('nb_visits');
+
+ $this->assertTrue($this->config->hasSparklineMetrics());
+ }
+
+ public function test_getSparklineMetrics_shouldNotHaveSparklineMetrics_ByDefault()
+ {
+ $this->assertSame(array(), $this->config->getSparklineMetrics());
+ }
+
+ public function test_addSparklineMetric_getSparklineMetrics_shouldReturnAllAddedSparklineMetrics()
+ {
+ $this->addFewSparklines();
+
+ $this->assertSame(array(
+ array('columns' => 'nb_visits', 'order' => null),
+ array('columns' => 'nb_unique_visitors', 'order' => 99),
+ array('columns' => array('nb_downloads', 'nb_outlinks'), 'order' => null),
+ ), $this->config->getSparklineMetrics());
+ }
+
+ public function test_removeSparklineMetric_shouldRemoveMetric_IfOnlySingleMetricIsGiven()
+ {
+ $this->addFewSparklines();
+
+ $this->config->removeSparklineMetric('nb_unique_visitors');
+
+ $this->assertSame(array(
+ array('columns' => 'nb_visits', 'order' => null),
+ array('columns' => array('nb_downloads', 'nb_outlinks'), 'order' => null),
+ ), $this->config->getSparklineMetrics());
+ }
+
+ public function test_removeSparklineMetric_shouldRemoveMetric_IfMultipleMetricsAreGiven()
+ {
+ $this->addFewSparklines();
+
+ $this->config->removeSparklineMetric(array('nb_downloads', 'nb_outlinks'));
+
+ $this->assertSame(array(
+ array('columns' => 'nb_visits', 'order' => null),
+ array('columns' => 'nb_unique_visitors', 'order' => 99),
+ ), $this->config->getSparklineMetrics());
+ }
+
+ public function test_replaceSparklineMetric_shouldBeAbleToReplaceColumns_IfSingleMetricIsGiven()
+ {
+ $this->addFewSparklines();
+
+ $this->config->replaceSparklineMetric('nb_unique_visitors', '');
+
+ $this->assertSame(array(
+ array('columns' => 'nb_visits', 'order' => null),
+ array('columns' => '', 'order' => 99),
+ array('columns' => array('nb_downloads', 'nb_outlinks'), 'order' => null),
+ ), $this->config->getSparklineMetrics());
+ }
+
+ public function test_replaceSparklineMetric_shouldBeAbleToReplaceColumns_IfMultipleMetricsAreGiven()
+ {
+ $this->addFewSparklines();
+
+ $this->config->replaceSparklineMetric(array('nb_downloads', 'nb_outlinks'), '');
+
+ $this->assertSame(array(
+ array('columns' => 'nb_visits', 'order' => null),
+ array('columns' => 'nb_unique_visitors', 'order' => 99),
+ array('columns' => '', 'order' => null),
+ ), $this->config->getSparklineMetrics());
+ }
+
+ public function test_addPlaceholder_getSortedSparklines()
+ {
+ $this->config->addPlaceholder();
+ $this->config->addPlaceholder($order = 10);
+ $this->config->addPlaceholder();
+ $this->config->addPlaceholder($order = 3);
+
+ $this->assertSame(array(
+ array('url' => '', 'metrics' => array(), 'order' => 3),
+ array('url' => '', 'metrics' => array(), 'order' => 10),
+ array('url' => '', 'metrics' => array(), 'order' => 999),
+ array('url' => '', 'metrics' => array(), 'order' => 1001),
+ ), $this->config->getSortedSparklines());
+ }
+
+ private function addFewSparklines()
+ {
+ $this->config->addSparklineMetric('nb_visits');
+ $this->config->addSparklineMetric('nb_unique_visitors', 99);
+ $this->config->addSparklineMetric(array('nb_downloads', 'nb_outlinks'));
+ }
+
+}
diff --git a/plugins/CustomDimensions b/plugins/CustomDimensions
-Subproject aab8e5a7246135a1d6b3ca00e665aea4adf8035
+Subproject cef5a9d43f7e26e98a33a003eb283431dfacf6d
diff --git a/plugins/CustomVariables/Categories/CustomVariablesSubcategory.php b/plugins/CustomVariables/Categories/CustomVariablesSubcategory.php
new file mode 100644
index 0000000000..d81b56568c
--- /dev/null
+++ b/plugins/CustomVariables/Categories/CustomVariablesSubcategory.php
@@ -0,0 +1,19 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\CustomVariables\Categories;
+
+use Piwik\Category\Subcategory;
+
+class CustomVariablesSubcategory extends Subcategory
+{
+ protected $categoryId = 'General_Visitors';
+ protected $id = 'CustomVariables_CustomVariables';
+ protected $order = 10;
+
+}
diff --git a/plugins/CustomVariables/Reports/Base.php b/plugins/CustomVariables/Reports/Base.php
index be48bf4d44..0c6bcbec0b 100644
--- a/plugins/CustomVariables/Reports/Base.php
+++ b/plugins/CustomVariables/Reports/Base.php
@@ -14,7 +14,7 @@ abstract class Base extends \Piwik\Plugin\Report
protected function init()
{
- $this->category = 'General_Visitors';
+ $this->categoryId = 'General_Visitors';
}
}
diff --git a/plugins/CustomVariables/Reports/GetCustomVariables.php b/plugins/CustomVariables/Reports/GetCustomVariables.php
index b4e133c7e3..b460c8b836 100644
--- a/plugins/CustomVariables/Reports/GetCustomVariables.php
+++ b/plugins/CustomVariables/Reports/GetCustomVariables.php
@@ -24,8 +24,8 @@ class GetCustomVariables extends Base
array('<br />', '<a href="http://piwik.org/docs/custom-variables/" rel="noreferrer" target="_blank">', '</a>'));
$this->actionToLoadSubTables = 'getCustomVariablesValuesFromNameId';
$this->order = 10;
- $this->widgetTitle = 'CustomVariables_CustomVariables';
- $this->menuTitle = 'CustomVariables_CustomVariables';
+
+ $this->subcategoryId = 'CustomVariables_CustomVariables';
$this->hasGoalMetrics = true;
}
diff --git a/plugins/CustomVariables/tests/System/expected/test_CustomVariablesSystemTest__CustomVariables.getCustomVariables_day.xml b/plugins/CustomVariables/tests/System/expected/test_CustomVariablesSystemTest__CustomVariables.getCustomVariables_day.xml
index 054f9b1e31..766be4e97d 100644
--- a/plugins/CustomVariables/tests/System/expected/test_CustomVariablesSystemTest__CustomVariables.getCustomVariables_day.xml
+++ b/plugins/CustomVariables/tests/System/expected/test_CustomVariablesSystemTest__CustomVariables.getCustomVariables_day.xml
@@ -1,150 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<result>
<row>
- <label>Name_PAGE_1</label>
- <nb_actions>1</nb_actions>
- <slots>
- <row>
- <scope>page</scope>
- <index>1</index>
- </row>
- </slots>
- <segment>customVariableName==Name_PAGE_1</segment>
- <subtable>
- <row>
- <label>Val_PAGE1</label>
- <nb_visits>1</nb_visits>
- <nb_actions>1</nb_actions>
- </row>
- </subtable>
- </row>
- <row>
- <label>Name_PAGE_2</label>
- <nb_actions>1</nb_actions>
- <slots>
- <row>
- <scope>page</scope>
- <index>2</index>
- </row>
- </slots>
- <segment>customVariableName==Name_PAGE_2</segment>
- <subtable>
- <row>
- <label>Val_PAGE2</label>
- <nb_visits>1</nb_visits>
- <nb_actions>1</nb_actions>
- </row>
- </subtable>
- </row>
- <row>
- <label>Name_PAGE_3</label>
- <nb_actions>1</nb_actions>
- <slots>
- <row>
- <scope>page</scope>
- <index>3</index>
- </row>
- </slots>
- <segment>customVariableName==Name_PAGE_3</segment>
- <subtable>
- <row>
- <label>Val_PAGE3</label>
- <nb_visits>1</nb_visits>
- <nb_actions>1</nb_actions>
- </row>
- </subtable>
- </row>
- <row>
- <label>Name_PAGE_4</label>
- <nb_actions>1</nb_actions>
- <slots>
- <row>
- <scope>page</scope>
- <index>4</index>
- </row>
- </slots>
- <segment>customVariableName==Name_PAGE_4</segment>
- <subtable>
- <row>
- <label>Val_PAGE4</label>
- <nb_visits>1</nb_visits>
- <nb_actions>1</nb_actions>
- </row>
- </subtable>
- </row>
- <row>
- <label>Name_PAGE_5</label>
- <nb_actions>1</nb_actions>
- <slots>
- <row>
- <scope>page</scope>
- <index>5</index>
- </row>
- </slots>
- <segment>customVariableName==Name_PAGE_5</segment>
- <subtable>
- <row>
- <label>Val_PAGE5</label>
- <nb_visits>1</nb_visits>
- <nb_actions>1</nb_actions>
- </row>
- </subtable>
- </row>
- <row>
- <label>Name_PAGE_6</label>
- <nb_actions>1</nb_actions>
- <slots>
- <row>
- <scope>page</scope>
- <index>6</index>
- </row>
- </slots>
- <segment>customVariableName==Name_PAGE_6</segment>
- <subtable>
- <row>
- <label>Val_PAGE6</label>
- <nb_visits>1</nb_visits>
- <nb_actions>1</nb_actions>
- </row>
- </subtable>
- </row>
- <row>
- <label>Name_PAGE_7</label>
- <nb_actions>1</nb_actions>
- <slots>
- <row>
- <scope>page</scope>
- <index>7</index>
- </row>
- </slots>
- <segment>customVariableName==Name_PAGE_7</segment>
- <subtable>
- <row>
- <label>Val_PAGE7</label>
- <nb_visits>1</nb_visits>
- <nb_actions>1</nb_actions>
- </row>
- </subtable>
- </row>
- <row>
- <label>Name_PAGE_8</label>
- <nb_actions>1</nb_actions>
- <slots>
- <row>
- <scope>page</scope>
- <index>8</index>
- </row>
- </slots>
- <segment>customVariableName==Name_PAGE_8</segment>
- <subtable>
- <row>
- <label>Val_PAGE8</label>
- <nb_visits>1</nb_visits>
- <nb_actions>1</nb_actions>
- </row>
- </subtable>
- </row>
- <row>
<label>Name_VISIT_1</label>
<nb_visits>1</nb_visits>
<nb_actions>1</nb_actions>
@@ -504,4 +360,148 @@
</row>
</subtable>
</row>
+ <row>
+ <label>Name_PAGE_1</label>
+ <nb_actions>1</nb_actions>
+ <slots>
+ <row>
+ <scope>page</scope>
+ <index>1</index>
+ </row>
+ </slots>
+ <segment>customVariableName==Name_PAGE_1</segment>
+ <subtable>
+ <row>
+ <label>Val_PAGE1</label>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ </row>
+ </subtable>
+ </row>
+ <row>
+ <label>Name_PAGE_2</label>
+ <nb_actions>1</nb_actions>
+ <slots>
+ <row>
+ <scope>page</scope>
+ <index>2</index>
+ </row>
+ </slots>
+ <segment>customVariableName==Name_PAGE_2</segment>
+ <subtable>
+ <row>
+ <label>Val_PAGE2</label>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ </row>
+ </subtable>
+ </row>
+ <row>
+ <label>Name_PAGE_3</label>
+ <nb_actions>1</nb_actions>
+ <slots>
+ <row>
+ <scope>page</scope>
+ <index>3</index>
+ </row>
+ </slots>
+ <segment>customVariableName==Name_PAGE_3</segment>
+ <subtable>
+ <row>
+ <label>Val_PAGE3</label>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ </row>
+ </subtable>
+ </row>
+ <row>
+ <label>Name_PAGE_4</label>
+ <nb_actions>1</nb_actions>
+ <slots>
+ <row>
+ <scope>page</scope>
+ <index>4</index>
+ </row>
+ </slots>
+ <segment>customVariableName==Name_PAGE_4</segment>
+ <subtable>
+ <row>
+ <label>Val_PAGE4</label>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ </row>
+ </subtable>
+ </row>
+ <row>
+ <label>Name_PAGE_5</label>
+ <nb_actions>1</nb_actions>
+ <slots>
+ <row>
+ <scope>page</scope>
+ <index>5</index>
+ </row>
+ </slots>
+ <segment>customVariableName==Name_PAGE_5</segment>
+ <subtable>
+ <row>
+ <label>Val_PAGE5</label>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ </row>
+ </subtable>
+ </row>
+ <row>
+ <label>Name_PAGE_6</label>
+ <nb_actions>1</nb_actions>
+ <slots>
+ <row>
+ <scope>page</scope>
+ <index>6</index>
+ </row>
+ </slots>
+ <segment>customVariableName==Name_PAGE_6</segment>
+ <subtable>
+ <row>
+ <label>Val_PAGE6</label>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ </row>
+ </subtable>
+ </row>
+ <row>
+ <label>Name_PAGE_7</label>
+ <nb_actions>1</nb_actions>
+ <slots>
+ <row>
+ <scope>page</scope>
+ <index>7</index>
+ </row>
+ </slots>
+ <segment>customVariableName==Name_PAGE_7</segment>
+ <subtable>
+ <row>
+ <label>Val_PAGE7</label>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ </row>
+ </subtable>
+ </row>
+ <row>
+ <label>Name_PAGE_8</label>
+ <nb_actions>1</nb_actions>
+ <slots>
+ <row>
+ <scope>page</scope>
+ <index>8</index>
+ </row>
+ </slots>
+ <segment>customVariableName==Name_PAGE_8</segment>
+ <subtable>
+ <row>
+ <label>Val_PAGE8</label>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ </row>
+ </subtable>
+ </row>
</result> \ No newline at end of file
diff --git a/plugins/CustomVariables/tests/UI/expected-ui-screenshots/CustomVariables_manage.png b/plugins/CustomVariables/tests/UI/expected-ui-screenshots/CustomVariables_manage.png
index c03b7e3795..6a3b0341f5 100644
--- a/plugins/CustomVariables/tests/UI/expected-ui-screenshots/CustomVariables_manage.png
+++ b/plugins/CustomVariables/tests/UI/expected-ui-screenshots/CustomVariables_manage.png
Binary files differ
diff --git a/plugins/DBStats/Reports/GetMetricDataSummary.php b/plugins/DBStats/Reports/GetMetricDataSummary.php
index 92b93fce9b..94735c4e03 100644
--- a/plugins/DBStats/Reports/GetMetricDataSummary.php
+++ b/plugins/DBStats/Reports/GetMetricDataSummary.php
@@ -11,6 +11,7 @@ namespace Piwik\Plugins\DBStats\Reports;
use Piwik\Piwik;
use Piwik\Plugin\ViewDataTable;
use Piwik\Plugins\CoreVisualizations\Visualizations\Graph;
+use Piwik\Plugin\Reports;
/**
* Shows a datatable that displays the amount of space each numeric archive table
@@ -34,7 +35,7 @@ class GetMetricDataSummary extends Base
public function getRelatedReports()
{
return array(
- self::factory('DBStats', 'getMetricDataSummaryByYear'),
+ Reports::factory('DBStats', 'getMetricDataSummaryByYear'),
);
}
diff --git a/plugins/DBStats/Reports/GetMetricDataSummaryByYear.php b/plugins/DBStats/Reports/GetMetricDataSummaryByYear.php
index bc5e8e5c3c..81b89d5d99 100644
--- a/plugins/DBStats/Reports/GetMetricDataSummaryByYear.php
+++ b/plugins/DBStats/Reports/GetMetricDataSummaryByYear.php
@@ -11,6 +11,7 @@ namespace Piwik\Plugins\DBStats\Reports;
use Piwik\Piwik;
use Piwik\Plugin\ViewDataTable;
use Piwik\Plugins\CoreVisualizations\Visualizations\Graph;
+use Piwik\Plugin\Reports;
/**
* Shows a datatable that displays the amount of space each numeric archive table
@@ -35,7 +36,7 @@ class GetMetricDataSummaryByYear extends Base
public function getRelatedReports()
{
return array(
- self::factory('DBStats', 'getMetricDataSummary'),
+ Reports::factory('DBStats', 'getMetricDataSummary'),
);
}
diff --git a/plugins/DBStats/Reports/GetReportDataSummary.php b/plugins/DBStats/Reports/GetReportDataSummary.php
index d38f3ee717..58c1b065c5 100644
--- a/plugins/DBStats/Reports/GetReportDataSummary.php
+++ b/plugins/DBStats/Reports/GetReportDataSummary.php
@@ -11,6 +11,7 @@ namespace Piwik\Plugins\DBStats\Reports;
use Piwik\Piwik;
use Piwik\Plugin\ViewDataTable;
use Piwik\Plugins\CoreVisualizations\Visualizations\Graph;
+use Piwik\Plugin\Reports;
/**
* Shows a datatable that displays the amount of space each blob archive table
@@ -34,7 +35,7 @@ class GetReportDataSummary extends Base
public function getRelatedReports()
{
return array(
- self::factory('DBStats', 'getReportDataSummaryByYear'),
+ Reports::factory('DBStats', 'getReportDataSummaryByYear'),
);
}
}
diff --git a/plugins/DBStats/Reports/GetReportDataSummaryByYear.php b/plugins/DBStats/Reports/GetReportDataSummaryByYear.php
index 1bbe67e467..7ff78a638b 100644
--- a/plugins/DBStats/Reports/GetReportDataSummaryByYear.php
+++ b/plugins/DBStats/Reports/GetReportDataSummaryByYear.php
@@ -11,6 +11,7 @@ namespace Piwik\Plugins\DBStats\Reports;
use Piwik\Piwik;
use Piwik\Plugin\ViewDataTable;
use Piwik\Plugins\CoreVisualizations\Visualizations\Graph;
+use Piwik\Plugin\Reports;
/**
* Shows a datatable that displays the amount of space each blob archive table
@@ -35,7 +36,7 @@ class GetReportDataSummaryByYear extends Base
public function getRelatedReports()
{
return array(
- self::factory('DBStats', 'getReportDataSummary'),
+ Reports::factory('DBStats', 'getReportDataSummary'),
);
}
diff --git a/plugins/Dashboard/API.php b/plugins/Dashboard/API.php
index f4637e862a..7bd5bd73a5 100644
--- a/plugins/Dashboard/API.php
+++ b/plugins/Dashboard/API.php
@@ -8,7 +8,6 @@
namespace Piwik\Plugins\Dashboard;
use Piwik\Piwik;
-use Piwik\WidgetsList;
/**
* This API is the <a href='http://piwik.org/docs/analytics-api/reference/' rel='noreferrer' target='_blank'>Dashboard API</a>: it gives information about dashboards.
@@ -43,25 +42,22 @@ class API extends \Piwik\Plugin\API
/**
* Get the default dashboard.
- *
- * @return array[]
+ * @return \array[]
*/
private function getDefaultDashboard()
{
$defaultLayout = $this->dashboard->getDefaultLayout();
$defaultLayout = $this->dashboard->decodeLayout($defaultLayout);
+ $defaultDashboard = array('name' => Piwik::translate('Dashboard_Dashboard'), 'layout' => $defaultLayout, 'iddashboard' => 1);
- $defaultDashboard = array('name' => Piwik::translate('Dashboard_Dashboard'), 'layout' => $defaultLayout);
-
- $widgets = $this->getExistingWidgetsWithinDashboard($defaultDashboard);
+ $widgets = $this->getVisibleWidgetsWithinDashboard($defaultDashboard);
return $this->buildDashboard($defaultDashboard, $widgets);
}
/**
* Get all dashboards which a user has created.
- *
- * @return array[]
+ * @return \array[]
*/
private function getUserDashboards()
{
@@ -71,17 +67,14 @@ class API extends \Piwik\Plugin\API
$dashboards = array();
foreach ($userDashboards as $userDashboard) {
-
- if ($this->hasDashboardColumns($userDashboard)) {
- $widgets = $this->getExistingWidgetsWithinDashboard($userDashboard);
- $dashboards[] = $this->buildDashboard($userDashboard, $widgets);
- }
+ $widgets = $this->getVisibleWidgetsWithinDashboard($userDashboard);
+ $dashboards[] = $this->buildDashboard($userDashboard, $widgets);
}
return $dashboards;
}
- private function getExistingWidgetsWithinDashboard($dashboard)
+ private function getVisibleWidgetsWithinDashboard($dashboard)
{
$columns = $this->getColumnsFromDashboard($dashboard);
@@ -91,7 +84,7 @@ class API extends \Piwik\Plugin\API
foreach ($columns as $column) {
foreach ($column as $widget) {
- if ($this->widgetIsNotHidden($widget) && $this->widgetExists($widget)) {
+ if ($this->widgetIsNotHidden($widget) && !empty($widget->parameters->module)) {
$module = $widget->parameters->module;
$action = $widget->parameters->action;
@@ -105,39 +98,24 @@ class API extends \Piwik\Plugin\API
private function getColumnsFromDashboard($dashboard)
{
- if (is_array($dashboard['layout'])) {
-
- return $dashboard['layout'];
+ if (empty($dashboard['layout'])) {
+ return array();
}
- return $dashboard['layout']->columns;
- }
-
- private function hasDashboardColumns($dashboard)
- {
if (is_array($dashboard['layout'])) {
+ return $dashboard['layout'];
+ }
- return !empty($dashboard['layout']);
+ if (!empty($dashboard['layout']->columns)) {
+ return $dashboard['layout']->columns;
}
- return !empty($dashboard['layout']->columns);
+ return array();
}
private function buildDashboard($dashboard, $widgets)
{
- return array('name' => $dashboard['name'], 'widgets' => $widgets);
- }
-
- private function widgetExists($widget)
- {
- if (empty($widget->parameters->module)) {
- return false;
- }
-
- $module = $widget->parameters->module;
- $action = $widget->parameters->action;
-
- return WidgetsList::isDefined($module, $action);
+ return array('name' => $dashboard['name'], 'id' => $dashboard['iddashboard'], 'widgets' => $widgets);
}
private function widgetIsNotHidden($widget)
diff --git a/plugins/Dashboard/Categories/DashboardCategory.php b/plugins/Dashboard/Categories/DashboardCategory.php
new file mode 100644
index 0000000000..4fb9952385
--- /dev/null
+++ b/plugins/Dashboard/Categories/DashboardCategory.php
@@ -0,0 +1,18 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\Dashboard\Categories;
+
+use Piwik\Category\Category;
+
+class DashboardCategory extends Category
+{
+ protected $id = 'Dashboard_Dashboard';
+ protected $order = 0;
+ protected $icon = 'icon-reporting-dashboard';
+}
diff --git a/plugins/Dashboard/Controller.php b/plugins/Dashboard/Controller.php
index d77c283273..bef5a89237 100644
--- a/plugins/Dashboard/Controller.php
+++ b/plugins/Dashboard/Controller.php
@@ -13,8 +13,6 @@ use Piwik\Db;
use Piwik\Piwik;
use Piwik\Session\SessionNamespace;
use Piwik\View;
-use Piwik\WidgetsList;
-use Piwik\FrontController;
/**
* Dashboard Controller
@@ -39,24 +37,21 @@ class Controller extends \Piwik\Plugin\Controller
$view = new View($template);
$this->setGeneralVariablesView($view);
- $view->availableWidgets = json_encode(WidgetsList::get());
$view->availableLayouts = $this->getAvailableLayouts();
$view->dashboardId = Common::getRequestVar('idDashboard', 1, 'int');
- // get the layout via FrontController so controller events are posted
- $view->dashboardLayout = FrontController::getInstance()->dispatch('Dashboard', 'getDashboardLayout',
- array($checkToken = false));
-
return $view;
}
+ // this
public function embeddedIndex()
{
$view = $this->_getDashboardView('@Dashboard/embeddedIndex');
return $view->render();
}
+ // this is the exported widget
public function index()
{
$view = $this->_getDashboardView('@Dashboard/index');
@@ -70,14 +65,6 @@ class Controller extends \Piwik\Plugin\Controller
return $view->render();
}
- public function getAvailableWidgets()
- {
- $this->checkTokenInUrl();
-
- Json::sendHeaderJSON();
- return json_encode(WidgetsList::get());
- }
-
public function getDashboardLayout($checkToken = true)
{
if ($checkToken) {
diff --git a/plugins/Dashboard/Dashboard.php b/plugins/Dashboard/Dashboard.php
index 729f845c70..44814f6800 100644
--- a/plugins/Dashboard/Dashboard.php
+++ b/plugins/Dashboard/Dashboard.php
@@ -12,8 +12,9 @@ use Piwik\Common;
use Piwik\Container\StaticContainer;
use Piwik\Db;
use Piwik\Piwik;
+use Piwik\Category\Subcategory;
+use Piwik\Widget\WidgetConfig;
use Piwik\Plugin;
-use Piwik\WidgetsList;
/**
*/
@@ -28,10 +29,81 @@ class Dashboard extends \Piwik\Plugin
'AssetManager.getJavaScriptFiles' => 'getJsFiles',
'AssetManager.getStylesheetFiles' => 'getStylesheetFiles',
'UsersManager.deleteUser' => 'deleteDashboardLayout',
- 'Translate.getClientSideTranslationKeys' => 'getClientSideTranslationKeys'
+ 'Translate.getClientSideTranslationKeys' => 'getClientSideTranslationKeys',
+ 'Widget.addWidgetConfigs' => 'addWidgetConfigs',
+ 'Category.addSubcategories' => 'addSubcategories'
);
}
+ public function addWidgetConfigs(&$widgets)
+ {
+ if (Piwik::isUserIsAnonymous()) {
+ $this->addDefaultDashboard($widgets);
+ } else {
+ $dashboards = API::getInstance()->getDashboards();
+
+ if (empty($dashboards)) {
+ $this->addDefaultDashboard($widgets);
+ } else {
+ foreach ($dashboards as $dashboard) {
+ $config = new WidgetConfig();
+ $config->setIsNotWidgetizable();
+ $config->setModule('Dashboard');
+ $config->setAction('embeddedIndex');
+ $config->setCategoryId('Dashboard_Dashboard');
+ $config->setSubcategoryId($dashboard['id']);
+ $config->setParameters(array('idDashboard' => $dashboard['id']));
+ $widgets[] = $config;
+ }
+ }
+ }
+ }
+
+ private function addDefaultDashboard(&$widgets)
+ {
+ $config = new WidgetConfig();
+ $config->setIsNotWidgetizable();
+ $config->setModule('Dashboard');
+ $config->setAction('embeddedIndex');
+ $config->setCategoryId('Dashboard_Dashboard');
+ $config->setSubcategoryId('1');
+ $config->setParameters(array('idDashboard' => 1));
+ $widgets[] = $config;
+ }
+
+ public function addSubcategories(&$subcategories)
+ {
+ if (Piwik::isUserIsAnonymous()) {
+ $this->addDefaultSubcategory($subcategories);
+ } else {
+ $dashboards = API::getInstance()->getDashboards();
+
+ if (empty($dashboards)) {
+ $this->addDefaultSubcategory($subcategories);
+ } else {
+ $order = 0;
+ foreach ($dashboards as $dashboard) {
+ $subcategory = new Subcategory();
+ $subcategory->setName($dashboard['name']);
+ $subcategory->setCategoryId('Dashboard_Dashboard');
+ $subcategory->setId($dashboard['id']);
+ $subcategory->setOrder($order++);
+ $subcategories[] = $subcategory;
+ }
+ }
+ }
+ }
+
+ private function addDefaultSubcategory(&$subcategories)
+ {
+ $subcategory = new Subcategory();
+ $subcategory->setName('Dashboard_Dashboard');
+ $subcategory->setCategoryId('Dashboard_Dashboard');
+ $subcategory->setId('1');
+ $subcategory->setOrder(1);
+ $subcategories[] = $subcategory;
+ }
+
/**
* Returns the layout in the DB for the given user, or false if the layout has not been set yet.
* Parameters must be checked BEFORE this function call
@@ -80,14 +152,14 @@ class Dashboard extends \Piwik\Plugin
$defaultLayout = '[
[
- {"uniqueId":"widgetVisitsSummarygetEvolutionGraphcolumnsArray","parameters":{"module":"VisitsSummary","action":"getEvolutionGraph","columns":"nb_visits"}},
+ {"uniqueId":"widgetVisitsSummarygetEvolutionGraphforceView1viewDataTablegraphEvolution","parameters":{"forceView":"1","viewDataTable":"graphEvolution","module":"VisitsSummary","action":"getEvolutionGraph"}},
{"uniqueId":"widgetLivewidget","parameters":{"module":"Live","action":"widget"}},
- {"uniqueId":"widgetVisitorInterestgetNumberOfVisitsPerVisitDuration","parameters":{"module":"VisitorInterest","action":"getNumberOfVisitsPerVisitDuration"}}
+ {"uniqueId":"widgetVisitorInterestgetNumberOfVisitsPerVisitDurationviewDataTablecloud","parameters":{"viewDataTable":"cloud","module":"VisitorInterest","action":"getNumberOfVisitsPerVisitDuration"}}
],
[
' . $topWidget . '
{"uniqueId":"widgetReferrersgetWebsites","parameters":{"module":"Referrers","action":"getWebsites"}},
- {"uniqueId":"widgetVisitTimegetVisitInformationPerServerTime","parameters":{"module":"VisitTime","action":"getVisitInformationPerServerTime"}}
+ {"uniqueId":"widgetVisitTimegetVisitInformationPerServerTimeviewDataTablegraphVerticalBar","parameters":{"viewDataTable": "graphVerticalBar","module":"VisitTime","action":"getVisitInformationPerServerTime"}}
],
[
{"uniqueId":"widgetUserCountryMapvisitorMap","parameters":{"module":"UserCountryMap","action":"visitorMap"}},
@@ -170,24 +242,6 @@ class Dashboard extends \Piwik\Plugin
);
}
- foreach ($layoutObject->columns as &$row) {
- if (!is_array($row)) {
- $row = array();
- continue;
- }
-
- foreach ($row as $widgetId => $widget) {
- if (isset($widget->parameters->module)) {
- $controllerName = $widget->parameters->module;
- $controllerAction = $widget->parameters->action;
- if (!WidgetsList::isDefined($controllerName, $controllerAction)) {
- unset($row[$widgetId]);
- }
- } else {
- unset($row[$widgetId]);
- }
- }
- }
$layout = $this->encodeLayout($layoutObject);
return $layout;
}
@@ -212,11 +266,13 @@ class Dashboard extends \Piwik\Plugin
public function getJsFiles(&$jsFiles)
{
+ $jsFiles[] = "plugins/Dashboard/angularjs/common/services/dashboards-model.js";
$jsFiles[] = "plugins/Dashboard/javascripts/widgetMenu.js";
$jsFiles[] = "libs/javascript/json2.js";
$jsFiles[] = "plugins/Dashboard/javascripts/dashboardObject.js";
$jsFiles[] = "plugins/Dashboard/javascripts/dashboardWidget.js";
$jsFiles[] = "plugins/Dashboard/javascripts/dashboard.js";
+ $jsFiles[] = "plugins/Dashboard/angularjs/dashboard/dashboard.directive.js";
}
public function getStylesheetFiles(&$stylesheets)
diff --git a/plugins/Dashboard/Menu.php b/plugins/Dashboard/Menu.php
index 9baa8c8a6d..7967635f97 100644
--- a/plugins/Dashboard/Menu.php
+++ b/plugins/Dashboard/Menu.php
@@ -9,7 +9,6 @@
namespace Piwik\Plugins\Dashboard;
use Piwik\Db;
-use Piwik\Menu\MenuReporting;
use Piwik\Menu\MenuTop;
use Piwik\Piwik;
use Piwik\Plugins\UsersManager\UserPreferences;
@@ -19,35 +18,6 @@ use Piwik\Site;
*/
class Menu extends \Piwik\Plugin\Menu
{
- public function configureReportingMenu(MenuReporting $menu)
- {
- $menu->addItem('Dashboard_Dashboard', '', array(), 5);
-
- if (Piwik::isUserIsAnonymous()) {
- $this->addDefaultDashboard($menu);
- } else {
- $login = Piwik::getCurrentUserLogin();
-
- $dashboard = new Dashboard();
- $dashboards = $dashboard->getAllDashboards($login);
-
- if (empty($dashboards)) {
- $this->addDefaultDashboard($menu);
- } else {
- $pos = 0;
- foreach ($dashboards as $dashboard) {
- $menu->addItem('Dashboard_Dashboard', $dashboard['name'], $this->urlForAction('embeddedIndex', array('idDashboard' => $dashboard['iddashboard'])), $pos);
- $pos++;
- }
- }
- }
- }
-
- private function addDefaultDashboard(MenuReporting $menu)
- {
- $menu->addItem('Dashboard_Dashboard', 'Dashboard_Dashboard', $this->urlForAction('embeddedIndex', array('idDashboard' => 1)));
- }
-
public function configureTopMenu(MenuTop $menu)
{
$userPreferences = new UserPreferences();
diff --git a/plugins/Dashboard/Model.php b/plugins/Dashboard/Model.php
index 790076c1a9..0ef02aeea9 100644
--- a/plugins/Dashboard/Model.php
+++ b/plugins/Dashboard/Model.php
@@ -10,7 +10,7 @@ namespace Piwik\Plugins\Dashboard;
use Piwik\Common;
use Piwik\Db;
use Piwik\DbHelper;
-use Piwik\WidgetsList;
+use Piwik\Widget\WidgetsList;
class Model
{
@@ -189,7 +189,11 @@ class Model
if ($widget->uniqueId == $oldWidgetId) {
- $newWidgetId = WidgetsList::getWidgetUniqueId($newWidget['module'], $newWidget['action'], $newWidget['params']);
+ if (!empty($newWidget['uniqueId'])) {
+ $newWidgetId = $newWidget['uniqueId'];
+ } else {
+ $newWidgetId = WidgetsList::getWidgetUniqueId($newWidget['module'], $newWidget['action'], $newWidget['params']);
+ }
// is new widget already is on dashboard just remove the old one
if (self::layoutContainsWidget($dashboardLayout, $newWidgetId)) {
diff --git a/plugins/Dashboard/angularjs/common/services/dashboards-model.js b/plugins/Dashboard/angularjs/common/services/dashboards-model.js
new file mode 100644
index 0000000000..8cdfbec772
--- /dev/null
+++ b/plugins/Dashboard/angularjs/common/services/dashboards-model.js
@@ -0,0 +1,70 @@
+/*!
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+(function () {
+ angular.module('piwikApp.service').factory('dashboardsModel', dashboardsModel);
+
+ dashboardsModel.$inject = ['piwikApi'];
+
+ function dashboardsModel (piwikApi) {
+
+ var dashboardsPromise = null;
+
+ var model = {
+ dashboards: [],
+ getAllDashboards: getAllDashboards,
+ reloadAllDashboards: reloadAllDashboards,
+ getDashboard: getDashboard,
+ getDashboardLayout: getDashboardLayout
+ };
+
+ return model;
+
+ function getDashboard(dashboardId)
+ {
+ return getAllDashboards().then(function (dashboards) {
+ var dashboard = null;
+ angular.forEach(dashboards, function (board) {
+ if (parseInt(board.id, 10) === parseInt(dashboardId, 10)) {
+ dashboard = board;
+ }
+ });
+ return dashboard;
+ });
+ }
+
+ function getDashboardLayout(dashboardId)
+ {
+ piwikApi.withTokenInUrl();
+
+ return piwikApi.fetch({module: 'Dashboard', action: 'getDashboardLayout', idDashboard: dashboardId});
+ }
+
+ function reloadAllDashboards()
+ {
+ if (dashboardsPromise) {
+ dashboardsPromise = null;
+ }
+
+ return getAllDashboards();
+ }
+
+ function getAllDashboards()
+ {
+ if (!dashboardsPromise) {
+ dashboardsPromise = piwikApi.fetch({method: 'Dashboard.getDashboards'}).then(function (response) {
+ if (response) {
+ model.dashboards = response;
+ }
+
+ return response;
+ });
+ }
+
+ return dashboardsPromise;
+ }
+ }
+})(); \ No newline at end of file
diff --git a/plugins/Dashboard/angularjs/dashboard/dashboard.directive.js b/plugins/Dashboard/angularjs/dashboard/dashboard.directive.js
new file mode 100644
index 0000000000..60031e80d3
--- /dev/null
+++ b/plugins/Dashboard/angularjs/dashboard/dashboard.directive.js
@@ -0,0 +1,108 @@
+/*!
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+
+/**
+ * <div piwik-dashboard dashboard-id="5"></div>
+ */
+(function () {
+ angular.module('piwikApp').directive('piwikDashboard', piwikDashboard);
+
+ piwikDashboard.$inject = ['dashboardsModel', '$rootScope', '$q'];
+
+ function piwikDashboard(dashboardsModel, $rootScope, $q) {
+
+ function renderDashboard(dashboardId, dashboard, layout)
+ {
+ $('.dashboardSettings').show();
+ initTopControls();
+
+ // Embed dashboard / exported as widget
+ if (!$('#topBars').length) {
+ $('.dashboardSettings').after($('#Dashboard'));
+ $('#Dashboard ul li').removeClass('active');
+ $('#Dashboard_embeddedIndex_' + dashboardId).addClass('active');
+ }
+
+ widgetsHelper.getAvailableWidgets();
+
+ $('#dashboardWidgetsArea')
+ .on('dashboardempty', showEmptyDashboardNotification)
+ .dashboard({
+ idDashboard: dashboardId,
+ layout: layout,
+ name: dashboard ? dashboard.name : ''
+ });
+
+ $('#columnPreview').find('>div').each(function () {
+ var width = [];
+ $('div', this).each(function () {
+ width.push(this.className.replace(/width-/, ''));
+ });
+ $(this).attr('layout', width.join('-'));
+ });
+
+ $('#columnPreview').find('>div').on('click', function () {
+ $('#columnPreview').find('>div').removeClass('choosen');
+ $(this).addClass('choosen');
+ });
+ }
+
+ function fetchDashboard(dashboardId) {
+ var dashboardElement = $('#dashboardWidgetsArea');
+ dashboardElement.dashboard('destroyWidgets');
+ dashboardElement.empty();
+ globalAjaxQueue.abort();
+
+ var getDashboard = dashboardsModel.getDashboard(dashboardId);
+ var getLayout = dashboardsModel.getDashboardLayout(dashboardId);
+
+ $q.all([getDashboard, getLayout]).then(function (response) {
+ var dashboard = response[0];
+ var layout = response[1];
+
+ $(function() {
+ renderDashboard(dashboardId, dashboard, layout);
+ });
+ });
+ }
+
+ function clearDashboard () {
+ $('.top_controls .dashboard-manager').hide();
+ $('#dashboardWidgetsArea').dashboard('destroy');
+ }
+
+ return {
+ restrict: 'A',
+ scope: {
+ dashboardid: '=',
+ layout: '='
+ },
+ link: function (scope, element, attrs) {
+
+ scope.$parent.fetchDashboard = function (dashboardId) {
+ scope.dashboardId = dashboardId;
+ fetchDashboard(dashboardId)
+ };
+
+ fetchDashboard(scope.dashboardid);
+
+ function onLocationChange(event, newUrl, oldUrl)
+ {
+ if (newUrl !== oldUrl && newUrl.indexOf('category=Dashboard_Dashboard') === -1) {
+ // we remove the dashboard only if we no longer show a dashboard.
+ clearDashboard();
+ }
+ }
+
+ // should be rather handled in route or so.
+ var unbind = $rootScope.$on('$locationChangeSuccess', onLocationChange);
+ scope.$on('$destroy', onLocationChange);
+ scope.$on('$destroy', unbind);
+ }
+ };
+ }
+})(); \ No newline at end of file
diff --git a/plugins/Dashboard/javascripts/dashboard.js b/plugins/Dashboard/javascripts/dashboard.js
index bdd248682a..582ad1b79a 100644
--- a/plugins/Dashboard/javascripts/dashboard.js
+++ b/plugins/Dashboard/javascripts/dashboard.js
@@ -5,48 +5,16 @@
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*/
-function initDashboard(dashboardId, dashboardLayout) {
-
- $('.dashboardSettings').show();
- initTopControls();
-
- // Embed dashboard
- if (!$('#header .navbar-right').length) {
- $('.dashboardSettings').after($('#Dashboard'));
- $('#Dashboard_embeddedIndex_' + dashboardId).addClass('sfActive');
- }
-
- widgetsHelper.getAvailableWidgets();
-
- $('#dashboardWidgetsArea')
- .on('dashboardempty', showEmptyDashboardNotification)
- .dashboard({
- idDashboard: dashboardId,
- layout: dashboardLayout
- });
-
- $('#columnPreview').find('>div').each(function () {
- var width = [];
- $('div', this).each(function () {
- width.push(this.className.replace(/width-/, ''));
- });
- $(this).attr('layout', width.join('-'));
- });
-
- $('#columnPreview').find('>div').on('click', function () {
- $('#columnPreview').find('>div').removeClass('choosen');
- $(this).addClass('choosen');
- });
-}
-
function createDashboard() {
- $('#createDashboardName').val('');
- piwikHelper.modalConfirm('#createDashboardConfirm', {yes: function () {
- var dashboardName = $('#createDashboardName').val();
- var type = ($('#dashboard_type_empty:checked').length > 0) ? 'empty' : 'default';
+ $(makeSelectorLastId('createDashboardName')).val('');
+
+ piwikHelper.modalConfirm(makeSelectorLastId('createDashboardConfirm'), {yes: function () {
+ var dashboardName = $(makeSelectorLastId('createDashboardName')).val();
+ var type = ($('[id=dashboard_type_empty]:last:checked').length > 0) ? 'empty' : 'default';
var ajaxRequest = new ajaxHelper();
ajaxRequest.setLoadingElement();
+ ajaxRequest.withTokenInUrl();
ajaxRequest.addParams({
module: 'Dashboard',
action: 'createNewDashboard'
@@ -57,50 +25,75 @@ function createDashboard() {
}, 'post');
ajaxRequest.setCallback(
function (id) {
- $('#dashboardWidgetsArea').dashboard('loadDashboard', id);
+ angular.element(document).injector().invoke(function ($location, reportingMenuModel, dashboardsModel) {
+ dashboardsModel.reloadAllDashboards().then(function () {
+
+ $('#dashboardWidgetsArea').dashboard('loadDashboard', id);
+ $('#dashboardWidgetsArea').dashboard('rebuildMenu');
+ });
+ });
}
);
ajaxRequest.send(true);
}});
}
+function makeSelectorLastId(domElementId)
+{
+ // there can be many elements with this id, we prefer the last one
+ return '[id=' + domElementId + ']:last';
+}
+
function resetDashboard() {
- piwikHelper.modalConfirm('#resetDashboardConfirm', {yes: function () { $('#dashboardWidgetsArea').dashboard('resetLayout'); }});
+ piwikHelper.modalConfirm(makeSelectorLastId('resetDashboardConfirm'), {yes:
+ function () { $('#dashboardWidgetsArea').dashboard('resetLayout');
+ }});
}
function renameDashboard() {
- $('#newDashboardName').val($('#dashboardWidgetsArea').dashboard('getDashboardName'));
- piwikHelper.modalConfirm('#renameDashboardConfirm', {yes: function () { $('#dashboardWidgetsArea').dashboard('setDashboardName', $('#newDashboardName').val()); }});
+ $(makeSelectorLastId('newDashboardName')).val($('#dashboardWidgetsArea').dashboard('getDashboardName'));
+
+ piwikHelper.modalConfirm(makeSelectorLastId('renameDashboardConfirm'), {yes: function () {
+ var newDashboardName = $(makeSelectorLastId('newDashboardName')).val();
+ $('#dashboardWidgetsArea').dashboard('setDashboardName', newDashboardName);
+ }});
}
function removeDashboard() {
- $('#removeDashboardConfirm').find('h2 span').text($('#dashboardWidgetsArea').dashboard('getDashboardName'));
- piwikHelper.modalConfirm('#removeDashboardConfirm', {yes: function () { $('#dashboardWidgetsArea').dashboard('removeDashboard'); }});
+ $(makeSelectorLastId('removeDashboardConfirm')).find('h2 span').text($('#dashboardWidgetsArea').dashboard('getDashboardName'));
+
+ piwikHelper.modalConfirm(makeSelectorLastId('removeDashboardConfirm'), {yes: function () {
+ $('#dashboardWidgetsArea').dashboard('removeDashboard');
+ }});
}
function showChangeDashboardLayoutDialog() {
$('#columnPreview').find('>div').removeClass('choosen');
$('#columnPreview').find('>div[layout=' + $('#dashboardWidgetsArea').dashboard('getColumnLayout') + ']').addClass('choosen');
- piwikHelper.modalConfirm('#changeDashboardLayout', {yes: function () {
- $('#dashboardWidgetsArea').dashboard('setColumnLayout', $('#changeDashboardLayout').find('.choosen').attr('layout'));
+
+ var id = makeSelectorLastId('changeDashboardLayout');
+ piwikHelper.modalConfirm(id, {yes: function () {
+ $('#dashboardWidgetsArea').dashboard('setColumnLayout', $(id).find('.choosen').attr('layout'));
}});
}
function showEmptyDashboardNotification() {
- piwikHelper.modalConfirm('#dashboardEmptyNotification', {
+ piwikHelper.modalConfirm(makeSelectorLastId('dashboardEmptyNotification'), {
resetDashboard: function () { $('#dashboardWidgetsArea').dashboard('resetLayout'); },
addWidget: function () { $('.dashboardSettings > a').trigger('click'); }
});
}
function setAsDefaultWidgets() {
- piwikHelper.modalConfirm('#setAsDefaultWidgetsConfirm', {
- yes: function () { $('#dashboardWidgetsArea').dashboard('saveLayoutAsDefaultWidgetLayout'); }
+ piwikHelper.modalConfirm(makeSelectorLastId('setAsDefaultWidgetsConfirm'), {
+ yes: function () {
+ $('#dashboardWidgetsArea').dashboard('saveLayoutAsDefaultWidgetLayout');
+ }
});
}
function copyDashboardToUser() {
- $('#copyDashboardName').val($('#dashboardWidgetsArea').dashboard('getDashboardName'));
+ $(makeSelectorLastId('copyDashboardName')).val($('#dashboardWidgetsArea').dashboard('getDashboardName'));
var ajaxRequest = new ajaxHelper();
ajaxRequest.addParams({
module: 'API',
@@ -109,13 +102,13 @@ function copyDashboardToUser() {
}, 'get');
ajaxRequest.setCallback(
function (availableUsers) {
- $('#copyDashboardUser').empty();
- $('#copyDashboardUser').append(
+ $(makeSelectorLastId('copyDashboardUser')).empty();
+ $(makeSelectorLastId('copyDashboardUser')).append(
$('<option></option>').val(piwik.userLogin).text(piwik.userLogin)
);
$.each(availableUsers, function (index, user) {
if (user.login != 'anonymous' && user.login != piwik.userLogin) {
- $('#copyDashboardUser').append(
+ $(makeSelectorLastId('copyDashboardUser')).append(
$('<option></option>').val(user.login).text(user.login + ' (' + user.alias + ')')
);
}
@@ -124,10 +117,10 @@ function copyDashboardToUser() {
);
ajaxRequest.send(true);
- piwikHelper.modalConfirm('#copyDashboardToUserConfirm', {
+ piwikHelper.modalConfirm(makeSelectorLastId('copyDashboardToUserConfirm'), {
yes: function () {
- var copyDashboardName = $('#copyDashboardName').val();
- var copyDashboardUser = $('#copyDashboardUser').val();
+ var copyDashboardName = $(makeSelectorLastId('copyDashboardName')).val();
+ var copyDashboardUser = $(makeSelectorLastId('copyDashboardUser')).val();
var ajaxRequest = new ajaxHelper();
ajaxRequest.addParams({
@@ -145,6 +138,7 @@ function copyDashboardToUser() {
piwikHelper.modalConfirm('#alert', {});
}
);
+ ajaxRequest.withTokenInUrl();
ajaxRequest.send(true);
}
});
@@ -299,7 +293,7 @@ function copyDashboardToUser() {
},
isWidgetAvailable: function (widgetUniqueId) {
- return !$('#dashboardWidgetsArea').find('[widgetId=' + widgetUniqueId + ']').length;
+ return !$('#dashboardWidgetsArea').find('[widgetId="' + widgetUniqueId + '"]').length;
},
widgetSelected: function (widget) {
@@ -309,6 +303,7 @@ function copyDashboardToUser() {
DashboardManagerControl.initElements = function () {
UIControl.initElements(this, '.dashboard-manager');
+ $('.top_controls .dashboard-manager').hide(); // initially hide the manager
};
exports.DashboardManagerControl = DashboardManagerControl;
diff --git a/plugins/Dashboard/javascripts/dashboardObject.js b/plugins/Dashboard/javascripts/dashboardObject.js
index 4bb4bbcb91..3bdd50662c 100644
--- a/plugins/Dashboard/javascripts/dashboardObject.js
+++ b/plugins/Dashboard/javascripts/dashboardObject.js
@@ -57,9 +57,6 @@
if (options.layout) {
generateLayout(options.layout);
- buildMenu();
- } else {
- methods.loadDashboard.apply(this, [dashboardId]);
}
return this;
@@ -73,27 +70,33 @@
destroy: function () {
$(dashboardElement).remove();
dashboardElement = null;
- var widgets = $('[widgetId]');
- for (var i = 0; i < widgets.length; i++) {
- $(widgets[i]).dashboardWidget('destroy');
- }
+ destroyWidgets();
},
+ destroyWidgets: destroyWidgets,
+
/**
* Load dashboard with the given id
*
* @param {int} dashboardIdToLoad
*/
loadDashboard: function (dashboardIdToLoad) {
+
$(dashboardElement).empty();
dashboardName = '';
dashboardLayout = null;
dashboardId = dashboardIdToLoad;
- piwikHelper.showAjaxLoading();
- broadcast.updateHashOnly = true;
- broadcast.propagateAjax('?idDashboard=' + dashboardIdToLoad);
- fetchLayout(generateLayout);
- buildMenu();
+
+ if (piwikHelper.isAngularRenderingThePage()) {
+ angular.element(document).injector().invoke(function ($location) {
+ $location.search('subcategory', '' + dashboardIdToLoad);
+ });
+ } else {
+ var element = $('[piwik-dashboard]');
+ var scope = angular.element(element).scope();
+ scope.fetchDashboard(dashboardIdToLoad);
+ }
+
return this;
},
@@ -169,6 +172,7 @@
action: 'resetLayout',
idDashboard: dashboardId
}, 'get');
+ ajaxRequest.withTokenInUrl();
ajaxRequest.setCallback(
function () {
methods.loadDashboard.apply(this, [dashboardId])
@@ -179,11 +183,31 @@
ajaxRequest.send(true);
},
+ rebuildMenu: rebuildMenu,
/**
* Removes the current dashboard
*/
removeDashboard: function () {
- removeDashboard();
+ if (dashboardId == 1) {
+ return; // dashboard with id 1 should never be deleted, as it is the default
+ }
+
+ var ajaxRequest = new ajaxHelper();
+ ajaxRequest.setLoadingElement();
+ ajaxRequest.addParams({
+ module: 'Dashboard',
+ action: 'removeDashboard',
+ idDashboard: dashboardId
+ }, 'get');
+ ajaxRequest.setCallback(
+ function () {
+ methods.loadDashboard.apply(this, [1]);
+ rebuildMenu();
+ }
+ );
+ ajaxRequest.withTokenInUrl();
+ ajaxRequest.setFormat('html');
+ ajaxRequest.send(true);
},
/**
@@ -201,6 +225,47 @@
}
};
+ function destroyWidgets()
+ {
+ var widgets = $('[widgetId]');
+ for (var i = 0; i < widgets.length; i++) {
+ $(widgets[i]).dashboardWidget('destroy');
+ }
+ }
+
+ function removeNonExistingWidgets(availableWidgets, layout)
+ {
+ var existingModuleAction = {};
+ $.each(availableWidgets, function (category, widgets) {
+ $.each(widgets, function (index, widget) {
+ existingModuleAction[widget.module + '.' + widget.action] = true;
+ });
+ });
+
+ var columns = [];
+ $.each(layout.columns, function (i, column) {
+ var widgets = [];
+
+ $.each(column, function (j, widget) {
+ if (!widget.parameters || !widget.parameters.module) {
+ return;
+ }
+
+ var method = widget.parameters.module + '.' + widget.parameters.action
+ if (existingModuleAction[method]) {
+ widgets.push(widget);
+ }
+
+ });
+
+ columns[i] = widgets;
+ });
+
+ layout.columns = columns;
+
+ return layout;
+ }
+
/**
* Generates the dashboard out of the given layout
*
@@ -209,46 +274,33 @@
function generateLayout(layout) {
dashboardLayout = parseLayout(layout);
- piwikHelper.hideAjaxLoading();
- adjustDashboardColumns(dashboardLayout.config.layout);
-
- var dashboardContainsWidgets = false;
- for (var column = 0; column < dashboardLayout.columns.length; column++) {
- for (var i in dashboardLayout.columns[column]) {
- if (typeof dashboardLayout.columns[column][i] != 'object') {
- // Fix IE8 bug: the "i in" loop contains i="indexOf", which would yield type function.
- // If we would continue with i="indexOf", an invalid widget would be created.
- continue;
+
+ widgetsHelper.getAvailableWidgets(function (availableWidgets) {
+ dashboardLayout = removeNonExistingWidgets(availableWidgets, dashboardLayout);
+
+ piwikHelper.hideAjaxLoading();
+ adjustDashboardColumns(dashboardLayout.config.layout);
+
+ var dashboardContainsWidgets = false;
+ for (var column = 0; column < dashboardLayout.columns.length; column++) {
+ for (var i in dashboardLayout.columns[column]) {
+ if (typeof dashboardLayout.columns[column][i] != 'object') {
+ // Fix IE8 bug: the "i in" loop contains i="indexOf", which would yield type function.
+ // If we would continue with i="indexOf", an invalid widget would be created.
+ continue;
+ }
+ var widget = dashboardLayout.columns[column][i];
+ dashboardContainsWidgets = true;
+ addWidgetTemplate(widget.uniqueId, column + 1, widget.parameters, false, widget.isHidden)
}
- var widget = dashboardLayout.columns[column][i];
- dashboardContainsWidgets = true;
- addWidgetTemplate(widget.uniqueId, column + 1, widget.parameters, false, widget.isHidden)
}
- }
- if (!dashboardContainsWidgets) {
- $(dashboardElement).trigger('dashboardempty');
- }
-
- makeWidgetsSortable();
- }
+ if (!dashboardContainsWidgets) {
+ $(dashboardElement).trigger('dashboardempty');
+ }
- /**
- * Fetches the layout for the currently set dashboard id
- * and passes the response to given callback function
- *
- * @param {function} callback
- */
- function fetchLayout(callback) {
- globalAjaxQueue.abort();
- var ajaxRequest = new ajaxHelper();
- ajaxRequest.addParams({
- module: 'Dashboard',
- action: 'getDashboardLayout',
- idDashboard: dashboardId
- }, 'get');
- ajaxRequest.setCallback(callback);
- ajaxRequest.send(false);
+ makeWidgetsSortable();
+ });
}
/**
@@ -388,7 +440,7 @@
* @param {String} uniqueId
*/
function reloadWidget(uniqueId) {
- $('[widgetId=' + uniqueId + ']', dashboardElement).dashboardWidget('reload', false, true);
+ $('[widgetId="' + uniqueId + '"]', dashboardElement).dashboardWidget('reload', false, true);
}
/**
@@ -417,7 +469,7 @@
$('.col:nth-child(' + columnNumber + ')', dashboardElement).append(widgetContent);
}
- $('[widgetId=' + uniqueId + ']', dashboardElement).dashboardWidget({
+ $('[widgetId="' + uniqueId + '"]', dashboardElement).dashboardWidget({
uniqueId: uniqueId,
widgetParameters: widgetParameters,
onChange: function () {
@@ -468,7 +520,19 @@
/**
* Handle clicks for menu items for choosing between available dashboards
*/
- function buildMenu() {
+ function rebuildMenu() {
+
+ if (piwikHelper.isAngularRenderingThePage()) {
+ // dashboard in reporting page (regular Piwik UI)
+ angular.element(document).injector().invoke(function (reportingMenuModel) {
+ reportingMenuModel.reloadMenuItems();
+ });
+ return;
+ }
+
+ var _self = this;
+
+ // widgetized
var success = function (dashboards) {
var dashboardMenuList = $('#Dashboard_embeddedIndex_1').closest('ul');
var dashboardMenuListItems = dashboardMenuList.find('>li');
@@ -487,13 +551,13 @@
var items = [];
for (var i = 0; i < dashboards.length; i++) {
var $link = $('<a/>').attr('data-iddashboard', dashboards[i].iddashboard).text(dashboards[i].name).addClass('item');
- var $li = $('<li/>').attr('id', 'Dashboard_embeddedIndex_' + dashboards[i].iddashboard)
- .attr('role', 'menuitem').append($link);
+ var $li = $('<li/>').attr('id', 'Dashboard_embeddedIndex_' + dashboards[i].iddashboard).addClass('dashboardMenuItem').attr('role', 'menuitem').append($link);
+
items.push($li);
if (dashboards[i].iddashboard == dashboardId) {
dashboardName = dashboards[i].name;
- $li.addClass('sfActive');
+ $li.addClass('active');
}
}
dashboardMenuList.prepend(items);
@@ -504,13 +568,11 @@
var idDashboard = $(this).attr('data-iddashboard');
- $('li', dashboardMenuList).removeClass('sfActive');
- if ($(dashboardElement).length) {
- $(dashboardElement).dashboard('loadDashboard', idDashboard);
- } else {
- broadcast.propagateAjax('module=Dashboard&action=embeddedIndex&idDashboard=' + idDashboard);
- }
- $(this).closest('li').addClass('sfActive');
+ $('#Dashboard ul li').removeClass('active');
+
+ methods.loadDashboard.apply(_self, [idDashboard]);
+
+ $(this).closest('li').addClass('active');
});
};
@@ -519,8 +581,9 @@
module: 'Dashboard',
action: 'getAllDashboards'
}, 'get');
+ ajaxRequest.withTokenInUrl();
ajaxRequest.setCallback(success);
- ajaxRequest.send(false);
+ ajaxRequest.send();
}
/**
@@ -567,40 +630,18 @@
function () {
if (dashboardChanged) {
dashboardChanged = false;
- buildMenu();
+ rebuildMenu();
}
}
);
+
+ ajaxRequest.withTokenInUrl();
ajaxRequest.setFormat('html');
ajaxRequest.send(false);
}
}
/**
- * Removes the current dashboard
- */
- function removeDashboard() {
- if (dashboardId == 1) {
- return; // dashboard with id 1 should never be deleted, as it is the default
- }
-
- var ajaxRequest = new ajaxHelper();
- ajaxRequest.setLoadingElement();
- ajaxRequest.addParams({
- module: 'Dashboard',
- action: 'removeDashboard',
- idDashboard: dashboardId
- }, 'get');
- ajaxRequest.setCallback(
- function () {
- methods.loadDashboard.apply(this, [1]);
- }
- );
- ajaxRequest.setFormat('html');
- ajaxRequest.send(true);
- }
-
- /**
* Make plugin methods available
*/
$.fn.dashboard = function (method) {
diff --git a/plugins/Dashboard/javascripts/dashboardWidget.js b/plugins/Dashboard/javascripts/dashboardWidget.js
index 728593715f..b3e78dcea3 100755
--- a/plugins/Dashboard/javascripts/dashboardWidget.js
+++ b/plugins/Dashboard/javascripts/dashboardWidget.js
@@ -70,7 +70,7 @@
*/
destroy: function () {
if (this.isMaximised) {
- $('[widgetId=' + this.uniqueId + ']').dialog('destroy');
+ $('[widgetId="' + this.uniqueId + '"]').dialog('destroy');
}
$('*', this.element).off('.dashboardWidget'); // unbind all events
$('.widgetContent', this.element).trigger('widget:destroy');
@@ -121,7 +121,12 @@
var $widgetContent = $('.widgetContent', currentWidget);
$widgetContent.html(loadedContent);
- piwikHelper.compileAngularComponents($widgetContent);
+
+ if (currentWidget.parents('body').size()) {
+ // there might be race conditions, eg widget might be just refreshed while whole dashboard is also
+ // removed from DOM
+ piwikHelper.compileAngularComponents($widgetContent);
+ }
$widgetContent.removeClass('loading');
$widgetContent.trigger('widget:create', [self]);
}
@@ -200,7 +205,7 @@
var emptyWidgetContent = require('piwik/UI/Dashboard').WidgetFactory.make(uniqueId, title);
this.element.html(emptyWidgetContent);
- var widgetElement = $('#' + uniqueId, this.element);
+ var widgetElement = $('[id="' + uniqueId + '"]', this.element);
var self = this;
widgetElement
.on('mouseenter.dashboardWidget', function () {
@@ -315,7 +320,7 @@
}
$('body').off('.dashboardWidget');
$(this).dialog("destroy");
- $('#' + self.uniqueId + '-placeholder').replaceWith(this);
+ $('[id="' + self.uniqueId + '-placeholder"]').replaceWith(this);
$(this).removeAttr('style');
self.options.onChange();
$(this).find('div.piwik-graph').trigger('resizeGraph');
@@ -342,6 +347,9 @@
*/
detachWidget: function () {
this.element.before('<div id="' + this.uniqueId + '-placeholder" class="widgetPlaceholder widget"> </div>');
+ var placeholder = $('[id="' + self.uniqueId + '-placeholder"]')
+
+
$('#' + this.uniqueId + '-placeholder').height(this.element.height());
$('#' + this.uniqueId + '-placeholder').width(this.element.width() - 16);
diff --git a/plugins/Dashboard/javascripts/widgetMenu.js b/plugins/Dashboard/javascripts/widgetMenu.js
index 66e033cf8e..7190f342a5 100644
--- a/plugins/Dashboard/javascripts/widgetMenu.js
+++ b/plugins/Dashboard/javascripts/widgetMenu.js
@@ -13,21 +13,82 @@ function widgetsHelper() {
*
* @return {object} object containing available widgets
*/
-widgetsHelper.getAvailableWidgets = function () {
+widgetsHelper.getAvailableWidgets = function (callback) {
+
+ function mergeCategoriesAndSubCategories(availableWidgets)
+ {
+ var categorized = {};
+
+ $.each(availableWidgets, function (index, widget) {
+ var category = widget.category.name;
+
+ if (!categorized[category]) {
+ categorized[category] = {'-': []};
+ }
+
+ var subcategory = '-';
+ if (widget.subcategory && widget.subcategory.name) {
+ subcategory = widget.subcategory.name;
+ }
+
+ if (!categorized[category][subcategory]) {
+ categorized[category][subcategory] = [];
+ }
+
+ categorized[category][subcategory].push(widget);
+ });
+
+ var moved = {};
+
+ $.each(categorized, function (category, widgets) {
+ $.each(widgets, function (subcategory, subwidgets) {
+
+ var categoryToUse = category;
+ if (subwidgets.length >= 3 && subcategory !== '-') {
+ categoryToUse = category + ' - ' + subcategory;
+ }
+
+ if (!moved[categoryToUse]) {
+ moved[categoryToUse] = [];
+ }
+
+ $.each(subwidgets, function (index, widget) {
+ moved[categoryToUse].push(widget);
+ });
+ });
+ });
+
+ return moved;
+ }
+
if (!widgetsHelper.availableWidgets) {
var ajaxRequest = new ajaxHelper();
+ ajaxRequest._mixinDefaultGetParams = function (params) {
+ return params;
+ };
ajaxRequest.addParams({
- module: 'Dashboard',
- action: 'getAvailableWidgets'
+ module: 'API',
+ method: 'API.getWidgetMetadata',
+ format: 'JSON',
+ deep: '1',
+ idSite: piwik.idSite || broadcast.getValueFromUrl('idSite')
}, 'get');
ajaxRequest.setCallback(
function (data) {
- widgetsHelper.availableWidgets = data;
+ widgetsHelper.availableWidgets = mergeCategoriesAndSubCategories(data);
+
+ if (callback) {
+ callback(widgetsHelper.availableWidgets);
+ }
}
);
ajaxRequest.send(true);
}
+ if (callback) {
+ callback(widgetsHelper.availableWidgets);
+ }
+
return widgetsHelper.availableWidgets;
};
@@ -191,6 +252,7 @@ widgetsHelper.loadWidgetAjax = function (widgetUniqueId, widgetParameters, onWid
* @return {$} category list element
*/
function createWidgetCategoryList(widgetPreview, availableWidgets) {
+
var settings = widgetPreview.settings;
if (!$('.' + settings.categorylistClass, widgetPreview).length) {
@@ -200,7 +262,6 @@ widgetsHelper.loadWidgetAjax = function (widgetUniqueId, widgetParameters, onWid
}
for (var widgetCategory in availableWidgets) {
-
$('.' + settings.categorylistClass, widgetPreview).append('<li>' + widgetCategory + '</li>');
}
@@ -262,6 +323,8 @@ widgetsHelper.loadWidgetAjax = function (widgetUniqueId, widgetParameters, onWid
widgetClass += ' ' + settings.unavailableClass;
}
+ widgetName = piwikHelper.escape(piwikHelper.htmlEntities(widgetName));
+
widgetList.append('<li class="' + widgetClass + '" uniqueid="' + widgetUniqueId + '">' + widgetName + '</li>');
}
@@ -283,7 +346,7 @@ widgetsHelper.loadWidgetAjax = function (widgetUniqueId, widgetParameters, onWid
clearTimeout(widgetPreview);
});
- $('li:not(.' + settings.unavailableClass + ')', widgetList).on('click', function () {
+ $('li', widgetList).on('click', function () {
if (!$('.widgetLoading', widgetPreview).length) {
settings.onSelect($(this).attr('uniqueid'));
$(widgetPreview).closest('.dashboard-manager').removeClass('expanded');
@@ -323,7 +386,7 @@ widgetsHelper.loadWidgetAjax = function (widgetUniqueId, widgetParameters, onWid
*/
function showPreview(widgetUniqueId, widgetPreview) {
// do not reload id widget already displayed
- if ($('#' + widgetUniqueId, widgetPreview).length) return;
+ if ($('[id="' + widgetUniqueId + '"]', widgetPreview).length) return;
var settings = widgetPreview.settings;
@@ -341,7 +404,8 @@ widgetsHelper.loadWidgetAjax = function (widgetUniqueId, widgetParameters, onWid
previewElement.html(emptyWidgetHtml);
var onWidgetLoadedCallback = function (response) {
- var widgetElement = $('#' + widgetUniqueId);
+ var widgetElement = $(document.getElementById(widgetUniqueId));
+ // document.getElementById needed for widgets with uniqueid like widgetOpens+Contact+Form
$('.widgetContent', widgetElement).html($(response));
$('.widgetContent', widgetElement).trigger('widget:create');
settings.onPreviewLoaded(widgetUniqueId, widgetElement);
@@ -405,19 +469,21 @@ widgetsHelper.loadWidgetAjax = function (widgetUniqueId, widgetParameters, onWid
this.onPreviewLoaded = this.settings.onPreviewLoaded;
}
- availableWidgets = widgetsHelper.getAvailableWidgets();
+ var self = this;
+ widgetsHelper.getAvailableWidgets(function (availableWidgets) {
- var categoryList = createWidgetCategoryList(this, availableWidgets);
+ var categoryList = createWidgetCategoryList(self, availableWidgets);
- var self = this;
- $('li', categoryList).on('mouseover', function () {
- var category = $(this).text();
- var widgets = availableWidgets[category];
- $('li', categoryList).removeClass(self.settings.choosenClass);
- $(this).addClass(self.settings.choosenClass);
- showWidgetList(widgets, self);
- createPreviewElement(self); // empty preview
+ $('li', categoryList).on('mouseover', function () {
+ var category = $(this).text();
+ var widgets = availableWidgets[category];
+ $('li', categoryList).removeClass(self.settings.choosenClass);
+ $(this).addClass(self.settings.choosenClass);
+ showWidgetList(widgets, self);
+ createPreviewElement(self); // empty preview
+ });
});
+
};
}
});
diff --git a/plugins/Dashboard/templates/embeddedIndex.twig b/plugins/Dashboard/templates/embeddedIndex.twig
index af1dbeb887..a7633ca193 100644
--- a/plugins/Dashboard/templates/embeddedIndex.twig
+++ b/plugins/Dashboard/templates/embeddedIndex.twig
@@ -1,10 +1,4 @@
-<script type="text/javascript">
- widgetsHelper.availableWidgets = {{ availableWidgets|raw }};
- $(function() {
- initDashboard({{ dashboardId }}, {{ dashboardLayout|raw }});
- });
-</script>
-<div id="dashboard">
+<div id="dashboard" piwik-dashboard dashboardid="{{ dashboardId }}">
<div class="ui-confirm" id="confirm">
<h2>{{ 'Dashboard_DeleteWidgetConfirm'|translate }}</h2>
<input role="yes" type="button" value="{{ 'General_Yes'|translate }}"/>
diff --git a/plugins/DevicePlugins/Reports/Base.php b/plugins/DevicePlugins/Reports/Base.php
index 81116f4d1d..b6f8755b13 100644
--- a/plugins/DevicePlugins/Reports/Base.php
+++ b/plugins/DevicePlugins/Reports/Base.php
@@ -15,7 +15,7 @@ abstract class Base extends \Piwik\Plugin\Report
{
protected function init()
{
- $this->category = 'General_VisitorSettings';
+ $this->categoryId = 'General_Visitors';
}
protected function getBasicDevicePluginsDisplayProperties(ViewDataTable $view)
diff --git a/plugins/DevicePlugins/Reports/GetPlugin.php b/plugins/DevicePlugins/Reports/GetPlugin.php
index 151bf3e1a6..42fef1cb89 100644
--- a/plugins/DevicePlugins/Reports/GetPlugin.php
+++ b/plugins/DevicePlugins/Reports/GetPlugin.php
@@ -23,8 +23,9 @@ class GetPlugin extends Base
$this->metrics = array('nb_visits');
$this->constantRowsCount = true;
$this->processedMetrics = array('nb_visits_percentage');
- $this->order = 4;
- $this->widgetTitle = 'DevicePlugins_WidgetPlugins';
+ $this->order = 13;
+
+ $this->subcategoryId = 'DevicesDetection_Software';
}
public function configureView(ViewDataTable $view)
diff --git a/plugins/DevicePlugins/tests/System/expected/test_UserSettingsBCTestUserSettings_UserSettings.getPlugin___API.getMetadata_day.xml b/plugins/DevicePlugins/tests/System/expected/test_UserSettingsBCTestUserSettings_UserSettings.getPlugin___API.getMetadata_day.xml
index 9a4f403963..a1ab29592e 100644
--- a/plugins/DevicePlugins/tests/System/expected/test_UserSettingsBCTestUserSettings_UserSettings.getPlugin___API.getMetadata_day.xml
+++ b/plugins/DevicePlugins/tests/System/expected/test_UserSettingsBCTestUserSettings_UserSettings.getPlugin___API.getMetadata_day.xml
@@ -1,7 +1,8 @@
<?xml version="1.0" encoding="utf-8" ?>
<result>
<row>
- <category>Visitor Settings</category>
+ <category>Visitors</category>
+ <subcategory>Software</subcategory>
<name>Browser Plugins</name>
<module>DevicePlugins</module>
<action>getPlugin</action>
diff --git a/plugins/DevicesDetection/Controller.php b/plugins/DevicesDetection/Controller.php
index 10c55a8a96..d19d0cf403 100644
--- a/plugins/DevicesDetection/Controller.php
+++ b/plugins/DevicesDetection/Controller.php
@@ -13,52 +13,11 @@ use Piwik\Common;
use Piwik\Db;
use Piwik\Piwik;
use Piwik\Plugin\ControllerAdmin;
-use Piwik\Plugin\Manager AS PluginManager;
use Piwik\Plugin\Report;
use Piwik\View;
class Controller extends \Piwik\Plugin\Controller
{
- public function index()
- {
- return $this->devices();
- }
-
- public function devices()
- {
- $view = new View('@DevicesDetection/devices');
- $view->deviceTypes = $this->renderReport('getType');
- $view->deviceBrands = $this->renderReport('getBrand');
- $view->deviceModels = $this->renderReport('getModel');
-
- $isResolutionEnabled = PluginManager::getInstance()->isPluginActivated('Resolution');
- if ($isResolutionEnabled) {
- $view->resolutions = $this->renderReport(Report::factory('Resolution', 'getResolution'));
- }
-
- return $view->render();
- }
-
- public function software()
- {
- $view = new View('@DevicesDetection/software');
- $view->osReport = $this->renderReport('getOsVersions');
- $view->browserReport = $this->renderReport('getBrowsers');
- $view->browserEngineReport = $this->renderReport('getBrowserEngines');
-
- $isResolutionEnabled = PluginManager::getInstance()->isPluginActivated('Resolution');
- if ($isResolutionEnabled) {
- $view->configurations = $this->renderReport(Report::factory('Resolution', 'getConfiguration'));
- }
-
- $isDevicePluginsEnabled = PluginManager::getInstance()->isPluginActivated('DevicePlugins');
- if ($isDevicePluginsEnabled) {
- $view->browserPlugins = $this->renderReport(Report::factory('DevicePlugins', 'getPlugin'));
- }
-
- return $view->render();
- }
-
public function detection()
{
Piwik::checkUserHasSomeAdminAccess();
diff --git a/plugins/DevicesDetection/Menu.php b/plugins/DevicesDetection/Menu.php
index 7ddb1dc668..067f8b9afa 100644
--- a/plugins/DevicesDetection/Menu.php
+++ b/plugins/DevicesDetection/Menu.php
@@ -9,7 +9,6 @@
namespace Piwik\Plugins\DevicesDetection;
use Piwik\Menu\MenuAdmin;
-use Piwik\Menu\MenuReporting;
use Piwik\Piwik;
/**
@@ -24,10 +23,4 @@ class Menu extends \Piwik\Plugin\Menu
$order = 40);
}
}
-
- public function configureReportingMenu(MenuReporting $menu)
- {
- $menu->addVisitorsItem('DevicesDetection_Devices', $this->urlForAction('devices'));
- $menu->addVisitorsItem('DevicesDetection_Software', $this->urlForAction('software'));
- }
}
diff --git a/plugins/DevicesDetection/Reports/Base.php b/plugins/DevicesDetection/Reports/Base.php
index 15eac96a4a..cb24a376e4 100644
--- a/plugins/DevicesDetection/Reports/Base.php
+++ b/plugins/DevicesDetection/Reports/Base.php
@@ -14,6 +14,6 @@ abstract class Base extends \Piwik\Plugin\Report
{
protected function init()
{
- $this->category = 'DevicesDetection_DevicesDetection';
+ $this->categoryId = 'General_Visitors';
}
}
diff --git a/plugins/DevicesDetection/Reports/GetBrand.php b/plugins/DevicesDetection/Reports/GetBrand.php
index 070b2d8918..41b9fd5366 100644
--- a/plugins/DevicesDetection/Reports/GetBrand.php
+++ b/plugins/DevicesDetection/Reports/GetBrand.php
@@ -20,8 +20,9 @@ class GetBrand extends Base
$this->dimension = new DeviceBrand();
$this->name = Piwik::translate('DevicesDetection_DeviceBrand');
$this->documentation = ''; // TODO
- $this->order = 1;
- $this->widgetTitle = 'DevicesDetection_DeviceBrand';
+ $this->order = 4;
+
+ $this->subcategoryId = 'DevicesDetection_Devices';
}
public function configureView(ViewDataTable $view)
diff --git a/plugins/DevicesDetection/Reports/GetBrowserEngines.php b/plugins/DevicesDetection/Reports/GetBrowserEngines.php
index 7c47ffca63..403955c66c 100644
--- a/plugins/DevicesDetection/Reports/GetBrowserEngines.php
+++ b/plugins/DevicesDetection/Reports/GetBrowserEngines.php
@@ -21,8 +21,9 @@ class GetBrowserEngines extends Base
$this->dimension = new BrowserEngine();
$this->name = Piwik::translate('DevicesDetection_BrowserEngines');
$this->documentation = Piwik::translate('DevicesDetection_BrowserEngineDocumentation', '<br />');
- $this->order = 7;
- $this->widgetTitle = 'DevicesDetection_BrowserEngines';
+ $this->order = 10;
+
+ $this->subcategoryId = 'DevicesDetection_Software';
}
public function getDefaultTypeViewDataTable()
diff --git a/plugins/DevicesDetection/Reports/GetBrowserVersions.php b/plugins/DevicesDetection/Reports/GetBrowserVersions.php
index 4f5875199a..66c7f91f55 100644
--- a/plugins/DevicesDetection/Reports/GetBrowserVersions.php
+++ b/plugins/DevicesDetection/Reports/GetBrowserVersions.php
@@ -11,6 +11,7 @@ namespace Piwik\Plugins\DevicesDetection\Reports;
use Piwik\Piwik;
use Piwik\Plugin\ViewDataTable;
use Piwik\Plugins\DevicesDetection\Columns\BrowserVersion;
+use Piwik\Plugin\Reports;
class GetBrowserVersions extends Base
{
@@ -20,8 +21,9 @@ class GetBrowserVersions extends Base
$this->dimension = new BrowserVersion();
$this->name = Piwik::translate('DevicesDetection_BrowserVersion');
$this->documentation = ''; // TODO
- $this->order = 2;
- $this->widgetTitle = 'DevicesDetection_BrowserVersion';
+ $this->order = 6;
+
+ $this->subcategoryId = 'DevicesDetection_Software';
}
public function configureView(ViewDataTable $view)
@@ -34,7 +36,7 @@ class GetBrowserVersions extends Base
public function getRelatedReports()
{
return array(
- self::factory('DevicesDetection', 'getBrowsers'),
+ Reports::factory('DevicesDetection', 'getBrowsers'),
);
}
}
diff --git a/plugins/DevicesDetection/Reports/GetBrowsers.php b/plugins/DevicesDetection/Reports/GetBrowsers.php
index 7d08a51ce5..5c39a275ee 100644
--- a/plugins/DevicesDetection/Reports/GetBrowsers.php
+++ b/plugins/DevicesDetection/Reports/GetBrowsers.php
@@ -11,6 +11,7 @@ namespace Piwik\Plugins\DevicesDetection\Reports;
use Piwik\Piwik;
use Piwik\Plugin\ViewDataTable;
use Piwik\Plugins\DevicesDetection\Columns\BrowserName;
+use Piwik\Plugin\Reports;
class GetBrowsers extends Base
{
@@ -18,10 +19,11 @@ class GetBrowsers extends Base
{
parent::init();
$this->dimension = new BrowserName();
- $this->name = Piwik::translate('DevicesDetection_WidgetBrowsers');
+ $this->name = Piwik::translate('DevicesDetection_Browsers');
$this->documentation = Piwik::translate('DevicesDetection_WidgetBrowsersDocumentation', '<br />');
- $this->order = 1;
- $this->widgetTitle = 'DevicesDetection_WidgetBrowsers';
+ $this->order = 5;
+
+ $this->subcategoryId = 'DevicesDetection_Software';
}
public function configureView(ViewDataTable $view)
@@ -35,7 +37,7 @@ class GetBrowsers extends Base
public function getRelatedReports()
{
return array(
- self::factory('DevicesDetection', 'getBrowserVersions'),
+ Reports::factory('DevicesDetection', 'getBrowserVersions'),
);
}
}
diff --git a/plugins/DevicesDetection/Reports/GetModel.php b/plugins/DevicesDetection/Reports/GetModel.php
index e2241e1ad4..154464691c 100644
--- a/plugins/DevicesDetection/Reports/GetModel.php
+++ b/plugins/DevicesDetection/Reports/GetModel.php
@@ -21,7 +21,8 @@ class GetModel extends Base
$this->name = Piwik::translate('DevicesDetection_DeviceModel');
$this->documentation = ''; // TODO
$this->order = 2;
- $this->widgetTitle = 'DevicesDetection_DeviceModel';
+
+ $this->subcategoryId = 'DevicesDetection_Devices';
}
public function configureView(ViewDataTable $view)
diff --git a/plugins/DevicesDetection/Reports/GetOsFamilies.php b/plugins/DevicesDetection/Reports/GetOsFamilies.php
index 61b393cb44..a283a83f7b 100644
--- a/plugins/DevicesDetection/Reports/GetOsFamilies.php
+++ b/plugins/DevicesDetection/Reports/GetOsFamilies.php
@@ -11,6 +11,7 @@ namespace Piwik\Plugins\DevicesDetection\Reports;
use Piwik\Piwik;
use Piwik\Plugin\ViewDataTable;
use Piwik\Plugins\DevicesDetection\Columns\Os;
+use Piwik\Plugin\Reports;
class GetOsFamilies extends Base
{
@@ -20,8 +21,9 @@ class GetOsFamilies extends Base
$this->dimension = new Os();
$this->name = Piwik::translate('DevicesDetection_OperatingSystemFamilies');
$this->documentation = ''; // TODO
- $this->order = 3;
- $this->widgetTitle = 'DevicesDetection_OperatingSystemFamilies';
+ $this->order = 8;
+
+ $this->subcategoryId = 'DevicesDetection_Software';
}
public function configureView(ViewDataTable $view)
@@ -35,7 +37,7 @@ class GetOsFamilies extends Base
public function getRelatedReports()
{
return array(
- self::factory('DevicesDetection', 'getOsVersions'),
+ Reports::factory('DevicesDetection', 'getOsVersions'),
);
}
diff --git a/plugins/DevicesDetection/Reports/GetOsVersions.php b/plugins/DevicesDetection/Reports/GetOsVersions.php
index 8676f38776..b330054c6f 100644
--- a/plugins/DevicesDetection/Reports/GetOsVersions.php
+++ b/plugins/DevicesDetection/Reports/GetOsVersions.php
@@ -11,6 +11,7 @@ namespace Piwik\Plugins\DevicesDetection\Reports;
use Piwik\Piwik;
use Piwik\Plugin\ViewDataTable;
use Piwik\Plugins\DevicesDetection\Columns\OsVersion;
+use Piwik\Plugin\Reports;
class GetOsVersions extends Base
{
@@ -20,8 +21,9 @@ class GetOsVersions extends Base
$this->dimension = new OsVersion();
$this->name = Piwik::translate('DevicesDetection_OperatingSystemVersions');
$this->documentation = ''; // TODO
- $this->order = 4;
- $this->widgetTitle = 'DevicesDetection_OperatingSystemVersions';
+ $this->order = 2;
+
+ $this->subcategoryId = 'DevicesDetection_Software';
}
public function configureView(ViewDataTable $view)
@@ -35,7 +37,7 @@ class GetOsVersions extends Base
public function getRelatedReports()
{
return array(
- self::factory('DevicesDetection', 'getOsFamilies'),
+ Reports::factory('DevicesDetection', 'getOsFamilies'),
);
}
}
diff --git a/plugins/DevicesDetection/Reports/GetType.php b/plugins/DevicesDetection/Reports/GetType.php
index cbfa69db3d..b12f19f319 100644
--- a/plugins/DevicesDetection/Reports/GetType.php
+++ b/plugins/DevicesDetection/Reports/GetType.php
@@ -22,7 +22,8 @@ class GetType extends Base
$this->name = Piwik::translate('DevicesDetection_DeviceType');
$this->documentation = ''; // TODO
$this->order = 0;
- $this->widgetTitle = 'DevicesDetection_DeviceType';
+
+ $this->subcategoryId = 'DevicesDetection_Devices';
}
public function configureView(ViewDataTable $view)
diff --git a/plugins/DevicesDetection/templates/devices.twig b/plugins/DevicesDetection/templates/devices.twig
deleted file mode 100644
index a37079c9fd..0000000000
--- a/plugins/DevicesDetection/templates/devices.twig
+++ /dev/null
@@ -1,19 +0,0 @@
-<div class="row">
-
- <div class="col-md-6">
- <h2 piwik-enriched-headline>{{ "DevicesDetection_DeviceType"|translate }}</h2>
- {{ deviceTypes | raw}}
- <h2 piwik-enriched-headline>{{ "DevicesDetection_DeviceBrand"|translate }}</h2>
- {{ deviceBrands | raw }}
- </div>
-
- <div class="col-md-6">
- <h2 piwik-enriched-headline>{{ "DevicesDetection_DeviceModel"|translate }}</h2>
- {{ deviceModels | raw }}
- {% if resolutions|default is not empty %}
- <h2 piwik-enriched-headline>{{ 'Resolution_Resolutions'|translate }}</h2>
- {{ resolutions|raw }}
- {% endif %}
- </div>
-
-</div>
diff --git a/plugins/DevicesDetection/templates/software.twig b/plugins/DevicesDetection/templates/software.twig
deleted file mode 100644
index 8b0dab0631..0000000000
--- a/plugins/DevicesDetection/templates/software.twig
+++ /dev/null
@@ -1,23 +0,0 @@
-<div class="row">
-
- <div class="col-md-6">
- <h2 piwik-enriched-headline>{{ "DevicesDetection_OperatingSystems"|translate }}</h2>
- {{ osReport | raw}}
- {% if configurations|default is not empty %}
- <h2 piwik-enriched-headline>{{ 'Resolution_Configurations'|translate }}</h2>
- {{ configurations|raw }}
- {% endif %}
- </div>
-
- <div class="col-md-6">
- <h2 piwik-enriched-headline>{{ "DevicesDetection_Browsers"|translate }}</h2>
- {{ browserReport | raw }}
- <h2 piwik-enriched-headline>{{ "DevicesDetection_BrowserEngines"|translate }}</h2>
- {{ browserEngineReport | raw }}
- {% if browserPlugins|default is not empty %}
- <h2 piwik-enriched-headline>{{ 'General_Plugins'|translate }}</h2>
- {{ browserPlugins|raw }}
- {% endif %}
- </div>
-
-</div>
diff --git a/plugins/DevicesDetection/tests/System/expected/test_UserSettingsBCTestUserSettings_UserSettings.getBrowserType___API.getMetadata_day.xml b/plugins/DevicesDetection/tests/System/expected/test_UserSettingsBCTestUserSettings_UserSettings.getBrowserType___API.getMetadata_day.xml
index 59301a5809..00bd3aad0a 100644
--- a/plugins/DevicesDetection/tests/System/expected/test_UserSettingsBCTestUserSettings_UserSettings.getBrowserType___API.getMetadata_day.xml
+++ b/plugins/DevicesDetection/tests/System/expected/test_UserSettingsBCTestUserSettings_UserSettings.getBrowserType___API.getMetadata_day.xml
@@ -1,7 +1,8 @@
<?xml version="1.0" encoding="utf-8" ?>
<result>
<row>
- <category>Visitor Devices</category>
+ <category>Visitors</category>
+ <subcategory>Software</subcategory>
<name>Browser engines</name>
<module>DevicesDetection</module>
<action>getBrowserEngines</action>
diff --git a/plugins/DevicesDetection/tests/System/expected/test_UserSettingsBCTestUserSettings_UserSettings.getBrowserVersion___API.getMetadata_day.xml b/plugins/DevicesDetection/tests/System/expected/test_UserSettingsBCTestUserSettings_UserSettings.getBrowserVersion___API.getMetadata_day.xml
index ae5eedde52..8c027b0207 100644
--- a/plugins/DevicesDetection/tests/System/expected/test_UserSettingsBCTestUserSettings_UserSettings.getBrowserVersion___API.getMetadata_day.xml
+++ b/plugins/DevicesDetection/tests/System/expected/test_UserSettingsBCTestUserSettings_UserSettings.getBrowserVersion___API.getMetadata_day.xml
@@ -1,7 +1,8 @@
<?xml version="1.0" encoding="utf-8" ?>
<result>
<row>
- <category>Visitor Devices</category>
+ <category>Visitors</category>
+ <subcategory>Software</subcategory>
<name>Browser version</name>
<module>DevicesDetection</module>
<action>getBrowserVersions</action>
@@ -28,6 +29,13 @@
<bounce_rate>Bounce Rate</bounce_rate>
<conversion_rate>Conversion Rate</conversion_rate>
</processedMetrics>
+ <relatedReports>
+ <row>
+ <name>Browsers</name>
+ <module>DevicesDetection</module>
+ <action>getBrowsers</action>
+ </row>
+ </relatedReports>
<imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=DevicesDetection&amp;apiAction=getBrowserVersions&amp;period=day&amp;date=2010-03-06</imageGraphUrl>
<imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=DevicesDetection&amp;apiAction=getBrowserVersions&amp;period=day&amp;date=2010-02-05,2010-03-06</imageGraphEvolutionUrl>
<uniqueId>DevicesDetection_getBrowserVersions</uniqueId>
diff --git a/plugins/DevicesDetection/tests/System/expected/test_UserSettingsBCTestUserSettings_UserSettings.getBrowser___API.getMetadata_day.xml b/plugins/DevicesDetection/tests/System/expected/test_UserSettingsBCTestUserSettings_UserSettings.getBrowser___API.getMetadata_day.xml
index 5c5b2df10a..fa0ddd6acf 100644
--- a/plugins/DevicesDetection/tests/System/expected/test_UserSettingsBCTestUserSettings_UserSettings.getBrowser___API.getMetadata_day.xml
+++ b/plugins/DevicesDetection/tests/System/expected/test_UserSettingsBCTestUserSettings_UserSettings.getBrowser___API.getMetadata_day.xml
@@ -1,8 +1,9 @@
<?xml version="1.0" encoding="utf-8" ?>
<result>
<row>
- <category>Visitor Devices</category>
- <name>Visitor Browser</name>
+ <category>Visitors</category>
+ <subcategory>Software</subcategory>
+ <name>Browsers</name>
<module>DevicesDetection</module>
<action>getBrowsers</action>
<dimension>Browser</dimension>
@@ -29,6 +30,13 @@
<bounce_rate>Bounce Rate</bounce_rate>
<conversion_rate>Conversion Rate</conversion_rate>
</processedMetrics>
+ <relatedReports>
+ <row>
+ <name>Browser version</name>
+ <module>DevicesDetection</module>
+ <action>getBrowserVersions</action>
+ </row>
+ </relatedReports>
<imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=DevicesDetection&amp;apiAction=getBrowsers&amp;period=day&amp;date=2010-03-06</imageGraphUrl>
<imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=DevicesDetection&amp;apiAction=getBrowsers&amp;period=day&amp;date=2010-02-05,2010-03-06</imageGraphEvolutionUrl>
<uniqueId>DevicesDetection_getBrowsers</uniqueId>
diff --git a/plugins/DevicesDetection/tests/System/expected/test_UserSettingsBCTestUserSettings_UserSettings.getMobileVsDesktop___API.getMetadata_day.xml b/plugins/DevicesDetection/tests/System/expected/test_UserSettingsBCTestUserSettings_UserSettings.getMobileVsDesktop___API.getMetadata_day.xml
index 377949b52e..17b74553d8 100644
--- a/plugins/DevicesDetection/tests/System/expected/test_UserSettingsBCTestUserSettings_UserSettings.getMobileVsDesktop___API.getMetadata_day.xml
+++ b/plugins/DevicesDetection/tests/System/expected/test_UserSettingsBCTestUserSettings_UserSettings.getMobileVsDesktop___API.getMetadata_day.xml
@@ -1,7 +1,8 @@
<?xml version="1.0" encoding="utf-8" ?>
<result>
<row>
- <category>Visitor Devices</category>
+ <category>Visitors</category>
+ <subcategory>Devices</subcategory>
<name>Device type</name>
<module>DevicesDetection</module>
<action>getType</action>
diff --git a/plugins/DevicesDetection/tests/System/expected/test_UserSettingsBCTestUserSettings_UserSettings.getOSFamily___API.getMetadata_day.xml b/plugins/DevicesDetection/tests/System/expected/test_UserSettingsBCTestUserSettings_UserSettings.getOSFamily___API.getMetadata_day.xml
index 23934c7263..ac3c2586dc 100644
--- a/plugins/DevicesDetection/tests/System/expected/test_UserSettingsBCTestUserSettings_UserSettings.getOSFamily___API.getMetadata_day.xml
+++ b/plugins/DevicesDetection/tests/System/expected/test_UserSettingsBCTestUserSettings_UserSettings.getOSFamily___API.getMetadata_day.xml
@@ -1,7 +1,8 @@
<?xml version="1.0" encoding="utf-8" ?>
<result>
<row>
- <category>Visitor Devices</category>
+ <category>Visitors</category>
+ <subcategory>Software</subcategory>
<name>Operating System families</name>
<module>DevicesDetection</module>
<action>getOsFamilies</action>
@@ -28,6 +29,13 @@
<bounce_rate>Bounce Rate</bounce_rate>
<conversion_rate>Conversion Rate</conversion_rate>
</processedMetrics>
+ <relatedReports>
+ <row>
+ <name>Operating System versions</name>
+ <module>DevicesDetection</module>
+ <action>getOsVersions</action>
+ </row>
+ </relatedReports>
<imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=DevicesDetection&amp;apiAction=getOsFamilies&amp;period=day&amp;date=2010-03-06</imageGraphUrl>
<imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=DevicesDetection&amp;apiAction=getOsFamilies&amp;period=day&amp;date=2010-02-05,2010-03-06</imageGraphEvolutionUrl>
<uniqueId>DevicesDetection_getOsFamilies</uniqueId>
diff --git a/plugins/DevicesDetection/tests/System/expected/test_UserSettingsBCTestUserSettings_UserSettings.getOS___API.getMetadata_day.xml b/plugins/DevicesDetection/tests/System/expected/test_UserSettingsBCTestUserSettings_UserSettings.getOS___API.getMetadata_day.xml
index 7d6d669f04..957d9b88cc 100644
--- a/plugins/DevicesDetection/tests/System/expected/test_UserSettingsBCTestUserSettings_UserSettings.getOS___API.getMetadata_day.xml
+++ b/plugins/DevicesDetection/tests/System/expected/test_UserSettingsBCTestUserSettings_UserSettings.getOS___API.getMetadata_day.xml
@@ -1,7 +1,8 @@
<?xml version="1.0" encoding="utf-8" ?>
<result>
<row>
- <category>Visitor Devices</category>
+ <category>Visitors</category>
+ <subcategory>Software</subcategory>
<name>Operating System versions</name>
<module>DevicesDetection</module>
<action>getOsVersions</action>
@@ -28,6 +29,13 @@
<bounce_rate>Bounce Rate</bounce_rate>
<conversion_rate>Conversion Rate</conversion_rate>
</processedMetrics>
+ <relatedReports>
+ <row>
+ <name>Operating System families</name>
+ <module>DevicesDetection</module>
+ <action>getOsFamilies</action>
+ </row>
+ </relatedReports>
<imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=DevicesDetection&amp;apiAction=getOsVersions&amp;period=day&amp;date=2010-03-06</imageGraphUrl>
<imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=DevicesDetection&amp;apiAction=getOsVersions&amp;period=day&amp;date=2010-02-05,2010-03-06</imageGraphEvolutionUrl>
<uniqueId>DevicesDetection_getOsVersions</uniqueId>
diff --git a/plugins/Ecommerce/Categories/EcommerceCategory.php b/plugins/Ecommerce/Categories/EcommerceCategory.php
new file mode 100644
index 0000000000..0e14470cfb
--- /dev/null
+++ b/plugins/Ecommerce/Categories/EcommerceCategory.php
@@ -0,0 +1,18 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\Ecommerce\Categories;
+
+use Piwik\Category\Category;
+
+class EcommerceCategory extends Category
+{
+ protected $id = 'Goals_Ecommerce';
+ protected $order = 20;
+ protected $icon = 'icon-reporting-ecommerce';
+}
diff --git a/plugins/Ecommerce/Categories/EcommerceLogSubcategory.php b/plugins/Ecommerce/Categories/EcommerceLogSubcategory.php
new file mode 100644
index 0000000000..f3999fda02
--- /dev/null
+++ b/plugins/Ecommerce/Categories/EcommerceLogSubcategory.php
@@ -0,0 +1,19 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\Ecommerce\Categories;
+
+use Piwik\Category\Subcategory;
+
+class EcommerceLogSubcategory extends Subcategory
+{
+ protected $categoryId = 'Goals_Ecommerce';
+ protected $id = 'Goals_EcommerceLog';
+ protected $order = 5;
+
+}
diff --git a/plugins/Ecommerce/Categories/EcommerceOverviewSubcategory.php b/plugins/Ecommerce/Categories/EcommerceOverviewSubcategory.php
new file mode 100644
index 0000000000..b8560a8072
--- /dev/null
+++ b/plugins/Ecommerce/Categories/EcommerceOverviewSubcategory.php
@@ -0,0 +1,19 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\Ecommerce\Categories;
+
+use Piwik\Category\Subcategory;
+
+class EcommerceOverviewSubcategory extends Subcategory
+{
+ protected $categoryId = 'Goals_Ecommerce';
+ protected $id = 'General_Overview';
+ protected $order = 2;
+
+}
diff --git a/plugins/Ecommerce/Categories/ProductSubcategory.php b/plugins/Ecommerce/Categories/ProductSubcategory.php
new file mode 100644
index 0000000000..d7d8e9a810
--- /dev/null
+++ b/plugins/Ecommerce/Categories/ProductSubcategory.php
@@ -0,0 +1,19 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\Ecommerce\Categories;
+
+use Piwik\Category\Subcategory;
+
+class ProductSubcategory extends Subcategory
+{
+ protected $categoryId = 'Goals_Ecommerce';
+ protected $id = 'Goals_Products';
+ protected $order = 10;
+
+}
diff --git a/plugins/Ecommerce/Categories/SalesSubcategory.php b/plugins/Ecommerce/Categories/SalesSubcategory.php
new file mode 100644
index 0000000000..0cb68d3d1c
--- /dev/null
+++ b/plugins/Ecommerce/Categories/SalesSubcategory.php
@@ -0,0 +1,19 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\Ecommerce\Categories;
+
+use Piwik\Category\Subcategory;
+
+class SalesSubcategory extends Subcategory
+{
+ protected $categoryId = 'Goals_Ecommerce';
+ protected $id = 'Ecommerce_Sales';
+ protected $order = 15;
+
+}
diff --git a/plugins/Ecommerce/Controller.php b/plugins/Ecommerce/Controller.php
index 7cfb955184..16d324ab0d 100644
--- a/plugins/Ecommerce/Controller.php
+++ b/plugins/Ecommerce/Controller.php
@@ -8,7 +8,8 @@
*/
namespace Piwik\Plugins\Ecommerce;
-use Exception;
+use Piwik\API\Request;
+use Piwik\Common;
use Piwik\DataTable;
use Piwik\FrontController;
use Piwik\Piwik;
@@ -30,95 +31,76 @@ class Controller extends \Piwik\Plugins\Goals\Controller
parent::__construct($translator, $translationHelper);
}
- public function ecommerceReport()
+ public function getSparklines()
{
- if (!\Piwik\Plugin\Manager::getInstance()->isPluginActivated('CustomVariables')) {
- throw new Exception("Ecommerce Tracking requires that the plugin Custom Variables is enabled. Please enable the plugin CustomVariables (or ask your admin).");
- }
+ $idGoal = Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_ORDER;
- $view = $this->getGoalReportView($idGoal = Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_ORDER);
- $view->displayFullReport = false;
- $view->headline = $this->translator->translate('General_EvolutionOverPeriod');
+ $view = new View('@Ecommerce/getSparklines');
+ $view->onlyConversionOverview = false;
+ $view->conversionsOverViewEnabled = true;
- return $view->render();
- }
+ if ($idGoal == Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_ORDER) {
+ $goalDefinition['name'] = $this->translator->translate('Goals_Ecommerce');
+ $goalDefinition['allow_multiple'] = true;
+ } else {
+ if (!isset($this->goals[$idGoal])) {
+ Piwik::redirectToModule('Goals', 'index', array('idGoal' => null));
+ }
+ $goalDefinition = $this->goals[$idGoal];
+ }
- public function ecommerceLogReport($fetch = false)
- {
- $view = new View('@Ecommerce/ecommerceLog');
$this->setGeneralVariablesView($view);
- $view->ecommerceLog = $this->getEcommerceLog($fetch);
-
- return $view->render();
- }
+ $goal = $this->getMetricsForGoal($idGoal);
+ foreach ($goal as $name => $value) {
+ $view->$name = $value;
+ }
- public function getEcommerceLog($fetch = false)
- {
- $saveGET = $_GET;
- $_GET['segment'] = urlencode('visitEcommerceStatus!=none');
- $_GET['widget'] = 1;
- $output = FrontController::getInstance()->dispatch('Live', 'getVisitorLog', array($fetch));
- $_GET = $saveGET;
+ if ($idGoal == Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_ORDER) {
+ $goal = $this->getMetricsForGoal(Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_CART);
+ foreach ($goal as $name => $value) {
+ $name = 'cart_' . $name;
+ $view->$name = $value;
+ }
+ }
- return $output;
- }
+ $view->idGoal = $idGoal;
+ $view->goalAllowMultipleConversionsPerVisit = $goalDefinition['allow_multiple'];
- public function index()
- {
- return $this->ecommerceReport();
+ return $view->render();
}
- public function products()
+ public function getConversionsOverview()
{
- $goal = $this->getMetricsForGoal(Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_ORDER);
- $conversions = 0;
- if (!empty($goal['nb_conversions'])) {
- $conversions = $goal['nb_conversions'];
- }
-
- $goal = $this->getMetricsForGoal(Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_CART);
-
- $cartNbConversions = 0;
- if (!empty($goal) && array_key_exists('nb_conversions', $goal)) {
- $cartNbConversions = $goal['nb_conversions'];
- }
+ $view = new View('@Ecommerce/conversionOverview');
+ $idGoal = Common::getRequestVar('idGoal', null, 'string');
- $preloadAbandonedCart = $cartNbConversions !== false && $conversions == 0;
+ $goalMetrics = Request::processRequest('Goals.get', array('idGoal' => $idGoal));
+ $dataRow = $goalMetrics->getFirstRow();
- $goalReportsByDimension = new View\ReportsByDimension('Goals');
+ $view->idSite = Common::getRequestVar('idSite', null, 'int');
+ $view->idGoal = $idGoal;
- $ecommerceCustomParams = array();
- if ($preloadAbandonedCart) {
- $ecommerceCustomParams['abandonedCarts'] = '1';
- } else {
- $ecommerceCustomParams['abandonedCarts'] = '0';
+ if ($dataRow) {
+ $view->revenue = $dataRow->getColumn('revenue');
+ $view->revenue_subtotal = $dataRow->getColumn('revenue_subtotal');
+ $view->revenue_tax = $dataRow->getColumn('revenue_tax');
+ $view->revenue_shipping = $dataRow->getColumn('revenue_shipping');
+ $view->revenue_discount = $dataRow->getColumn('revenue_discount');
}
- $goalReportsByDimension->addReport(
- 'Goals_Products', 'Goals_ProductSKU', 'Goals.getItemsSku', $ecommerceCustomParams);
- $goalReportsByDimension->addReport(
- 'Goals_Products', 'Goals_ProductName', 'Goals.getItemsName', $ecommerceCustomParams);
- $goalReportsByDimension->addReport(
- 'Goals_Products', 'Goals_ProductCategory', 'Goals.getItemsCategory', $ecommerceCustomParams);
-
- $view = new View('@Ecommerce/products');
- $this->setGeneralVariablesView($view);
-
- $view->productsByDimension = $goalReportsByDimension->render();
return $view->render();
}
- public function sales()
+ public function getEcommerceLog($fetch = false)
{
- $viewOverview = $this->getGoalReportView(Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_ORDER);
- $reportsByDimension = $viewOverview->goalReportsByDimension;
-
- $view = new View('@Ecommerce/sales');
- $this->setGeneralVariablesView($view);
+ $saveGET = $_GET;
+ $_GET['segment'] = urlencode('visitEcommerceStatus!=none');
+ $_GET['widget'] = 1;
+ $output = FrontController::getInstance()->dispatch('Live', 'getVisitorLog', array($fetch));
+ $_GET = $saveGET;
- $view->goalReportsByDimension = $reportsByDimension;
- return $view->render();
+ return $output;
}
}
diff --git a/plugins/Ecommerce/Menu.php b/plugins/Ecommerce/Menu.php
deleted file mode 100644
index 069ab48cb8..0000000000
--- a/plugins/Ecommerce/Menu.php
+++ /dev/null
@@ -1,39 +0,0 @@
-<?php
-/**
- * Piwik - free/libre analytics platform
- *
- * @link http://piwik.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- *
- */
-namespace Piwik\Plugins\Ecommerce;
-
-use Piwik\Common;
-use Piwik\Menu\MenuReporting;
-use Piwik\Piwik;
-use Piwik\Site;
-use Piwik\Url;
-
-/**
- */
-class Menu extends \Piwik\Plugin\Menu
-{
-
- public function configureReportingMenu(MenuReporting $menu)
- {
- $idSite = Common::getRequestVar('idSite', null, 'int');
-
- $site = new Site($idSite);
-
- if ($site->isEcommerceEnabled()) {
- $ecommerceParams = array('idGoal' => Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_ORDER);
-
- $menu->addItem('Goals_Ecommerce', '', array(), 24);
- $menu->addItem('Goals_Ecommerce', 'General_Overview', $this->urlForAction('ecommerceReport', $ecommerceParams), 1);
- $menu->addItem('Goals_Ecommerce', 'Goals_EcommerceLog', $this->urlForAction('ecommerceLogReport'), 2);
- $menu->addItem('Goals_Ecommerce', 'Goals_Products', $this->urlForAction('products', $ecommerceParams), 3);
- $menu->addItem('Goals_Ecommerce', 'Ecommerce_Sales', $this->urlForAction('sales', $ecommerceParams), 4);
- }
-
- }
-}
diff --git a/plugins/Ecommerce/Reports/Base.php b/plugins/Ecommerce/Reports/Base.php
index b4ec63c9a5..28a3a4a36f 100644
--- a/plugins/Ecommerce/Reports/Base.php
+++ b/plugins/Ecommerce/Reports/Base.php
@@ -18,7 +18,7 @@ abstract class Base extends Report
protected function init()
{
$this->module = 'Goals';
- $this->category = 'Goals_Ecommerce';
+ $this->categoryId = 'Goals_Ecommerce';
}
public function isEnabled()
diff --git a/plugins/Ecommerce/Reports/BaseItem.php b/plugins/Ecommerce/Reports/BaseItem.php
index 5caf770a6b..5896710dc2 100644
--- a/plugins/Ecommerce/Reports/BaseItem.php
+++ b/plugins/Ecommerce/Reports/BaseItem.php
@@ -9,15 +9,18 @@
namespace Piwik\Plugins\Ecommerce\Reports;
use Piwik\Common;
+use Piwik\DataTable;
use Piwik\Metrics\Formatter;
use Piwik\Piwik;
-use Piwik\Plugin\Report;
use Piwik\Plugin\ViewDataTable;
use Piwik\Plugins\CoreVisualizations\Visualizations\JqplotGraph\Evolution;
-use Piwik\Plugins\Goals\Goals;
use Piwik\Plugins\Goals\Columns\Metrics\AveragePrice;
use Piwik\Plugins\Goals\Columns\Metrics\AverageQuantity;
use Piwik\Plugins\Goals\Columns\Metrics\ProductConversionRate;
+use Piwik\Plugins\Goals\Conversions;
+use Piwik\Plugins\Goals\Model;
+use Piwik\Report\ReportWidgetFactory;
+use Piwik\Widget\WidgetsList;
abstract class BaseItem extends Base
{
@@ -46,7 +49,8 @@ abstract class BaseItem extends Base
public function getMetricsDocumentation()
{
- if ($this->isAbandonedCart()) {
+ // we do not check whether it is abondon carts if not set re performance improvements
+ if ($this->isAbandonedCart($fetchIfNotSet = false)) {
return array(
'revenue' => Piwik::translate('Goals_ColumnRevenueDocumentation',
Piwik::translate('Goals_DocumentationRevenueGeneratedByProductSales')),
@@ -62,6 +66,11 @@ abstract class BaseItem extends Base
return array();
}
+ public function configureWidgets(WidgetsList $widgetsList, ReportWidgetFactory $factory)
+ {
+ $widgetsList->addToContainerWidget('Products', $factory->createWidget());
+ }
+
public function configureView(ViewDataTable $view)
{
$idSite = Common::getRequestVar('idSite');
@@ -100,7 +109,7 @@ abstract class BaseItem extends Base
$view->config->custom_parameters['viewDataTable'] = 'table';
$abandonedCart = true;
} else {
- $abandonedCart = $this->isAbandonedCart();
+ $abandonedCart = $this->isAbandonedCart($fetchIfNotSet = true);
}
if ($abandonedCart) {
@@ -127,8 +136,32 @@ abstract class BaseItem extends Base
$view->config->columns_to_display = $columnsOrdered;
}
- private function isAbandonedCart()
+ private function isAbandonedCart($fetchIfNotSet)
{
- return Common::getRequestVar('abandonedCarts', '0', 'string') == 1;
+ $abandonedCarts = Common::getRequestVar('abandonedCarts', '', 'string');
+
+ if ($abandonedCarts === '') {
+ if ($fetchIfNotSet) {
+
+ $idSite = Common::getRequestVar('idSite', 0, 'int');
+ $period = Common::getRequestVar('period', '', 'string');
+ $date = Common::getRequestVar('date', '', 'string');
+
+ $conversion = new Conversions();
+ $conversions = $conversion->getConversionForGoal(Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_ORDER, $idSite, $period, $date);
+ $cartNbConversions = $conversion->getConversionForGoal(Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_CART, $idSite, $period, $date);
+ $preloadAbandonedCart = $cartNbConversions !== false && $conversions == 0;
+
+ if ($preloadAbandonedCart) {
+ $abandonedCarts = '1';
+ } else {
+ $abandonedCarts = '0';
+ }
+ } else {
+ $abandonedCarts = '0';
+ }
+ }
+
+ return $abandonedCarts == '1';
}
}
diff --git a/plugins/Ecommerce/Reports/GetItemsCategory.php b/plugins/Ecommerce/Reports/GetItemsCategory.php
index bf652ca10d..efd4a9489a 100644
--- a/plugins/Ecommerce/Reports/GetItemsCategory.php
+++ b/plugins/Ecommerce/Reports/GetItemsCategory.php
@@ -20,6 +20,7 @@ class GetItemsCategory extends BaseItem
$this->name = Piwik::translate('Goals_ProductCategory');
$this->dimension = new ProductCategory();
$this->order = 32;
- $this->widgetTitle = 'Goals_ProductCategory';
+
+ $this->subcategoryId = 'Goals_Products';
}
}
diff --git a/plugins/Ecommerce/Reports/GetItemsName.php b/plugins/Ecommerce/Reports/GetItemsName.php
index a320b760e4..db8c7f5d3d 100644
--- a/plugins/Ecommerce/Reports/GetItemsName.php
+++ b/plugins/Ecommerce/Reports/GetItemsName.php
@@ -20,6 +20,7 @@ class GetItemsName extends BaseItem
$this->name = Piwik::translate('Goals_ProductName');
$this->dimension = new ProductName();
$this->order = 31;
- $this->widgetTitle = 'Goals_ProductName';
+
+ $this->subcategoryId = 'Goals_Products';
}
}
diff --git a/plugins/Ecommerce/Reports/GetItemsSku.php b/plugins/Ecommerce/Reports/GetItemsSku.php
index a2b20eb3f9..9056b2ff6c 100644
--- a/plugins/Ecommerce/Reports/GetItemsSku.php
+++ b/plugins/Ecommerce/Reports/GetItemsSku.php
@@ -21,7 +21,8 @@ class GetItemsSku extends BaseItem
$this->name = Piwik::translate('Goals_ProductSKU');
$this->dimension = new ProductSku();
$this->order = 30;
- $this->widgetTitle = 'Goals_ProductSKU';
+
+ $this->subcategoryId = 'Goals_Products';
}
}
diff --git a/plugins/Ecommerce/Widgets.php b/plugins/Ecommerce/Widgets.php
deleted file mode 100644
index e20a73850e..0000000000
--- a/plugins/Ecommerce/Widgets.php
+++ /dev/null
@@ -1,35 +0,0 @@
-<?php
-/**
- * Piwik - free/libre analytics platform
- *
- * @link http://piwik.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- *
- */
-namespace Piwik\Plugins\Ecommerce;
-
-use Piwik\Common;
-use Piwik\Site;
-use Piwik\Piwik;
-
-class Widgets extends \Piwik\Plugin\Widgets
-{
- protected $category = 'Goals_Ecommerce';
-
- protected function init()
- {
- $idSite = $this->getIdSite();
-
- $site = new Site($idSite);
- if ($site->isEcommerceEnabled()) {
- $this->addWidget('General_Overview', 'widgetGoalReport', array('idGoal' => Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_ORDER));
- $this->addWidget('Goals_EcommerceLog', 'getEcommerceLog');
- }
- }
-
- private function getIdSite()
- {
- return Common::getRequestVar('idSite', null, 'int');
- }
-
-}
diff --git a/plugins/Ecommerce/Widgets/GetEcommerceLog.php b/plugins/Ecommerce/Widgets/GetEcommerceLog.php
new file mode 100644
index 0000000000..d1a68a435a
--- /dev/null
+++ b/plugins/Ecommerce/Widgets/GetEcommerceLog.php
@@ -0,0 +1,28 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\Ecommerce\Widgets;
+
+use Piwik\Common;
+use Piwik\Widget\WidgetConfig;
+use Piwik\Site;
+
+class GetEcommerceLog extends \Piwik\Widget\Widget
+{
+ public static function configure(WidgetConfig $config)
+ {
+ $config->setCategoryId('Goals_Ecommerce');
+ $config->setSubcategoryId('Goals_EcommerceLog');
+ $config->setName('Goals_EcommerceLog');
+
+ $idSite = Common::getRequestVar('idSite', null, 'int');
+ $site = new Site($idSite);
+ $config->setIsEnabled($site->isEcommerceEnabled());
+ }
+
+}
diff --git a/plugins/Ecommerce/Widgets/ProductsByDimension.php b/plugins/Ecommerce/Widgets/ProductsByDimension.php
new file mode 100644
index 0000000000..2f25e23b76
--- /dev/null
+++ b/plugins/Ecommerce/Widgets/ProductsByDimension.php
@@ -0,0 +1,34 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\Ecommerce\Widgets;
+
+use Piwik\Common;
+use Piwik\Plugins\CoreHome\CoreHome;
+use Piwik\Site;
+use Piwik\Widget\WidgetContainerConfig;
+
+class ProductsByDimension extends WidgetContainerConfig
+{
+ protected $layout = CoreHome::WIDGET_CONTAINER_LAYOUT_BY_DIMENSION;
+ protected $id = 'Products';
+ protected $categoryId = 'Goals_Ecommerce';
+ protected $subcategoryId = 'Goals_Products';
+
+ public function isEnabled()
+ {
+ $idSite = Common::getRequestVar('idSite', false, 'int');
+
+ if (empty($idSite)) {
+ return false;
+ }
+
+ $site = new Site($idSite);
+ return $site->isEcommerceEnabled();
+ }
+}
diff --git a/plugins/Ecommerce/templates/conversionOverview.twig b/plugins/Ecommerce/templates/conversionOverview.twig
new file mode 100644
index 0000000000..1da5c3a926
--- /dev/null
+++ b/plugins/Ecommerce/templates/conversionOverview.twig
@@ -0,0 +1,19 @@
+<ul class="ulGoalTopElements">
+ {{ 'General_ColumnRevenue'|translate }}: {{ revenue|money(idSite)|raw -}}
+ {% if revenue_subtotal is not empty %},
+ {{ 'General_Subtotal'|translate }}: {{ revenue_subtotal|money(idSite)|raw -}}
+ {% endif %}
+ {%- if revenue_tax is not empty -%},
+ {{ 'General_Tax'|translate }}: {{ revenue_tax|money(idSite)|raw -}}
+ {% endif %}
+ {%- if revenue_shipping is not empty -%},
+ {{ 'General_Shipping'|translate }}: {{ revenue_shipping|money(idSite)|raw -}}
+ {% endif %}
+ {%- if revenue_discount is not empty -%},
+ {{ 'General_Discount'|translate }}: {{ revenue_discount|money(idSite)|raw -}}
+ {% endif %}
+</ul>
+<a href="javascript:;" class="segmentedlog" onclick="SegmentedVisitorLog.show('Goals.getMetrics', 'visitConvertedGoalId=={{ idGoal }}', {})">
+ {{ 'Live_RowActionTooltipWithDimension'|translate('General_Goal'|translate) }}
+</a>
+<br style="clear:left"/> \ No newline at end of file
diff --git a/plugins/Ecommerce/templates/ecommerceLog.twig b/plugins/Ecommerce/templates/ecommerceLog.twig
deleted file mode 100644
index 4c40a94d99..0000000000
--- a/plugins/Ecommerce/templates/ecommerceLog.twig
+++ /dev/null
@@ -1,3 +0,0 @@
-<h2 piwik-enriched-headline>{{ 'Goals_EcommerceLog'|translate }}</h2>
-
-{{ ecommerceLog|raw }}
diff --git a/plugins/Ecommerce/templates/getSparklines.twig b/plugins/Ecommerce/templates/getSparklines.twig
new file mode 100644
index 0000000000..5e56ad868f
--- /dev/null
+++ b/plugins/Ecommerce/templates/getSparklines.twig
@@ -0,0 +1,56 @@
+<div id='leftcolumn' style="clear:both;{% if not isWidget %}width:33%;'{% endif %}">
+ <div class="sparkline">{{ sparkline(urlSparklineConversions) }}
+ <strong>{{ nb_conversions|number }}</strong>
+ {{ 'General_EcommerceOrders'|translate }}
+ <img src='plugins/Morpheus/images/ecommerceOrder.gif'>
+
+ {% if goalAllowMultipleConversionsPerVisit is defined and goalAllowMultipleConversionsPerVisit %}
+ ({{ 'General_NVisits'|translate("<strong>"~nb_visits_converted~"</strong>")|raw }})
+ {% endif %}
+ </div>
+
+ <div class="sparkline">
+ {{ sparkline(urlSparklineRevenue) }}
+ {% set revenue=revenue|money(idSite) %}
+ <strong>{{ revenue|raw }}</strong> {{ 'General_TotalRevenue'|translate }}
+ </div>
+
+ <div class="sparkline">{{ sparkline(urlSparklineAverageOrderValue) }}
+ <strong>{{ avg_order_revenue|money(idSite)|raw }}</strong>
+ {{ 'General_AverageOrderValue'|translate }}
+ </div>
+</div>
+<div id='leftcolumn' {% if not isWidget %}style='width:33%;'{% endif %}>
+ <div class="sparkline">{{ sparkline(urlSparklineConversionRate) }}
+ {% set ecommerceOrdersText %}{{ 'General_EcommerceOrders'|translate }}{% endset %}
+ {{ 'Goals_ConversionRate'|translate("<strong>"~conversion_rate|percent~"</strong> "~ecommerceOrdersText)|raw }}
+ </div>
+ <div class="sparkline">{{ sparkline(urlSparklinePurchasedProducts) }}
+ <strong>{{ items|number }}</strong> {{ 'General_PurchasedProducts'|translate }}</div>
+</div>
+<div id='rightcolumn' {% if not isWidget %}style='width:30%;'{% endif %}>
+ <div>
+ <img src='plugins/Morpheus/images/ecommerceAbandonedCart.gif'> <em>{{ 'General_AbandonedCarts'|translate }}</em>
+ </div>
+
+ <div class="sparkline">
+ {{ sparkline(cart_urlSparklineConversions) }}
+ {% set ecommerceAbandonedCartsText %}{{ 'Goals_AbandonedCart'|translate }}{% endset %}
+ <strong>{{ cart_nb_conversions|number }}</strong> {{ 'General_VisitsWith'|translate(ecommerceAbandonedCartsText) }}
+ </div>
+
+ <div class="sparkline">
+ {{ sparkline(cart_urlSparklineRevenue) }}
+ {% set revenue %}{{ cart_revenue|money(idSite)|raw }}{% endset %}
+ {% set revenueText %}{{ 'General_ColumnRevenue'|translate }}{% endset %}
+ <strong>{{ revenue }}</strong> {{ 'Goals_LeftInCart'|translate(revenueText) }}
+ </div>
+
+ <div class="sparkline">
+ {{ sparkline(cart_urlSparklineConversionRate) }}
+ <strong>{{ cart_conversion_rate|percent }}</strong>
+ {{ 'General_VisitsWith'|translate(ecommerceAbandonedCartsText) }}
+ </div>
+</div>
+<div style="clear: left;"></div>
+{% include "_sparklineFooter.twig" %}
diff --git a/plugins/Events/Categories/EventsSubcategory.php b/plugins/Events/Categories/EventsSubcategory.php
new file mode 100644
index 0000000000..e969029e13
--- /dev/null
+++ b/plugins/Events/Categories/EventsSubcategory.php
@@ -0,0 +1,19 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\Events\Categories;
+
+use Piwik\Category\Subcategory;
+
+class EventsSubcategory extends Subcategory
+{
+ protected $categoryId = 'General_Actions';
+ protected $id = 'Events_Events';
+ protected $order = 40;
+
+}
diff --git a/plugins/Events/Controller.php b/plugins/Events/Controller.php
deleted file mode 100644
index 3429443b88..0000000000
--- a/plugins/Events/Controller.php
+++ /dev/null
@@ -1,104 +0,0 @@
-<?php
-/**
- * Piwik - free/libre analytics platform
- *
- * @link http://piwik.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- *
- */
-namespace Piwik\Plugins\Events;
-
-use Piwik\View;
-
-/**
- * Events controller
- *
- */
-class Controller extends \Piwik\Plugin\Controller
-{
- public function index()
- {
- $view = new View('@Events/index');
- $view->leftMenuReports = $this->getLeftMenuReports();
- return $view->render();
- }
-
- private function getLeftMenuReports()
- {
- $reports = new View\ReportsByDimension('Events');
- foreach(Events::getLabelTranslations() as $apiAction => $translations) {
- // 'getCategory' is the API method, but we are loading 'indexCategory' which displays <h2>
- $count = 1;
- $controllerAction = str_replace("get", "index", $apiAction, $count);
- $params = array(
- 'secondaryDimension' => API::getInstance()->getDefaultSecondaryDimension($apiAction)
- );
- $reports->addReport('Events_TopEvents', $translations[0], 'Events.' . $controllerAction, $params);
- }
- return $reports->render();
- }
-
- public function indexCategory()
- {
- return $this->indexEvent(__FUNCTION__);
- }
-
- public function indexAction()
- {
- return $this->indexEvent(__FUNCTION__);
- }
-
- public function indexName()
- {
- return $this->indexEvent(__FUNCTION__);
- }
-
- public function getActionFromCategoryId()
- {
- return $this->renderReport(__FUNCTION__);
- }
-
- public function getNameFromCategoryId()
- {
- return $this->renderReport(__FUNCTION__);
- }
-
- public function getCategoryFromActionId()
- {
- return $this->renderReport(__FUNCTION__);
- }
-
- public function getNameFromActionId()
- {
- return $this->renderReport(__FUNCTION__);
- }
-
- public function getActionFromNameId()
- {
- return $this->renderReport(__FUNCTION__);
- }
-
- public function getCategoryFromNameId()
- {
- return $this->renderReport(__FUNCTION__);
- }
-
- protected function indexEvent($controllerMethod)
- {
- $count = 1;
- $apiMethod = str_replace('index', 'get', $controllerMethod, $count);
- $events = new Events;
- $title = $events->getReportTitleTranslation($apiMethod);
-
- if (method_exists($this, $apiMethod)) {
- $content = $this->$apiMethod();
- } else {
- $content = $this->renderReport($apiMethod);
- }
-
- return View::singleReport(
- $title,
- $content
- );
- }
-}
diff --git a/plugins/Events/Events.php b/plugins/Events/Events.php
index e178dc197b..06a7b5b081 100644
--- a/plugins/Events/Events.php
+++ b/plugins/Events/Events.php
@@ -13,6 +13,7 @@ use Piwik\DataTable;
use Piwik\Piwik;
use Piwik\Plugin\Report;
use Piwik\Plugin\ViewDataTable;
+use Piwik\Plugin\Reports;
use Piwik\Plugins\CoreVisualizations\Visualizations\HtmlTable\AllColumns;
class Events extends \Piwik\Plugin
@@ -178,7 +179,7 @@ class Events extends \Piwik\Plugin
$this->addRelatedReports($view, $secondaryDimension);
$this->addTooltipEventValue($view);
- $subtableReport = Report::factory('Events', $view->config->subtable_controller_action);
+ $subtableReport = Reports::factory('Events', $view->config->subtable_controller_action);
$view->config->pivot_by_dimension = $subtableReport->getDimension()->getId();
$view->config->pivot_by_column = 'nb_events';
}
diff --git a/plugins/Events/Menu.php b/plugins/Events/Menu.php
deleted file mode 100644
index 440a35978e..0000000000
--- a/plugins/Events/Menu.php
+++ /dev/null
@@ -1,21 +0,0 @@
-<?php
-/**
- * Piwik - free/libre analytics platform
- *
- * @link http://piwik.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- *
- */
-namespace Piwik\Plugins\Events;
-
-use Piwik\Menu\MenuReporting;
-
-/**
- */
-class Menu extends \Piwik\Plugin\Menu
-{
- public function configureReportingMenu(MenuReporting $menu)
- {
- $menu->addActionsItem('Events_Events', $this->urlForAction('index'), 30);
- }
-}
diff --git a/plugins/Events/Reports/Base.php b/plugins/Events/Reports/Base.php
index 4430b31407..a43ba0dbfa 100644
--- a/plugins/Events/Reports/Base.php
+++ b/plugins/Events/Reports/Base.php
@@ -10,19 +10,31 @@ namespace Piwik\Plugins\Events\Reports;
use Piwik\Plugins\Events\API;
use Piwik\Plugins\Events\Columns\Metrics\AverageEventValue;
+use Piwik\Report\ReportWidgetFactory;
+use Piwik\Widget\WidgetsList;
abstract class Base extends \Piwik\Plugin\Report
{
protected function init()
{
- $this->category = 'Events_Events';
+ $this->categoryId = 'General_Actions';
+ $this->subcategoryId = 'Events_Events';
+
$this->processedMetrics = array(
new AverageEventValue()
);
+ }
- $this->widgetParams = array(
- 'secondaryDimension' => API::getInstance()->getDefaultSecondaryDimension($this->action)
- );
+ public function configureWidgets(WidgetsList $widgetsList, ReportWidgetFactory $factory)
+ {
+ if (!$this->isSubtableReport) {
+ $widget = $factory->createWidget()->setParameters(array(
+ 'secondaryDimension' => API::getInstance()->getDefaultSecondaryDimension($this->action)
+ ));
+
+ $widgetsList->addToContainerWidget('Events', $widget);
+ }
}
+
}
diff --git a/plugins/Events/Reports/GetAction.php b/plugins/Events/Reports/GetAction.php
index 84f750e264..bbdadd7ed4 100644
--- a/plugins/Events/Reports/GetAction.php
+++ b/plugins/Events/Reports/GetAction.php
@@ -27,6 +27,5 @@ class GetAction extends Base
$this->actionToLoadSubTables = 'getNameFromActionId';
}
$this->order = 1;
- $this->widgetTitle = 'Events_EventActions';
}
}
diff --git a/plugins/Events/Reports/GetActionFromCategoryId.php b/plugins/Events/Reports/GetActionFromCategoryId.php
index c6fc362f6d..842e5e10b8 100644
--- a/plugins/Events/Reports/GetActionFromCategoryId.php
+++ b/plugins/Events/Reports/GetActionFromCategoryId.php
@@ -9,7 +9,6 @@
namespace Piwik\Plugins\Events\Reports;
use Piwik\Piwik;
-use Piwik\Plugin\Report;
use Piwik\Plugins\Events\Columns\EventAction;
/**
@@ -24,6 +23,5 @@ class GetActionFromCategoryId extends Base
$this->dimension = new EventAction();
$this->name = Piwik::translate('Events_EventActions');
$this->isSubtableReport = true;
- $this->widgetParams = array();
}
} \ No newline at end of file
diff --git a/plugins/Events/Reports/GetActionFromNameId.php b/plugins/Events/Reports/GetActionFromNameId.php
index 3b4882ee39..d82be65fb0 100644
--- a/plugins/Events/Reports/GetActionFromNameId.php
+++ b/plugins/Events/Reports/GetActionFromNameId.php
@@ -9,7 +9,6 @@
namespace Piwik\Plugins\Events\Reports;
use Piwik\Piwik;
-use Piwik\Plugin\Report;
use Piwik\Plugins\Events\Columns\EventAction;
/**
@@ -24,6 +23,5 @@ class GetActionFromNameId extends Base
$this->dimension = new EventAction();
$this->name = Piwik::translate('Events_EventActions');
$this->isSubtableReport = true;
- $this->widgetParams = array();
}
} \ No newline at end of file
diff --git a/plugins/Events/Reports/GetCategory.php b/plugins/Events/Reports/GetCategory.php
index be867705ea..2049868e7c 100644
--- a/plugins/Events/Reports/GetCategory.php
+++ b/plugins/Events/Reports/GetCategory.php
@@ -27,6 +27,5 @@ class GetCategory extends Base
$this->actionToLoadSubTables = 'getActionFromCategoryId';
}
$this->order = 0;
- $this->widgetTitle = 'Events_EventCategories';
}
}
diff --git a/plugins/Events/Reports/GetCategoryFromActionId.php b/plugins/Events/Reports/GetCategoryFromActionId.php
index a592ab24e0..efa1607a15 100644
--- a/plugins/Events/Reports/GetCategoryFromActionId.php
+++ b/plugins/Events/Reports/GetCategoryFromActionId.php
@@ -9,7 +9,6 @@
namespace Piwik\Plugins\Events\Reports;
use Piwik\Piwik;
-use Piwik\Plugin\Report;
use Piwik\Plugins\Events\Columns\EventCategory;
/**
@@ -24,6 +23,5 @@ class GetCategoryFromActionId extends Base
$this->dimension = new EventCategory();
$this->name = Piwik::translate('Events_EventCategories');
$this->isSubtableReport = true;
- $this->widgetParams = array();
}
} \ No newline at end of file
diff --git a/plugins/Events/Reports/GetCategoryFromNameId.php b/plugins/Events/Reports/GetCategoryFromNameId.php
index caf7119a54..b5a93009d8 100644
--- a/plugins/Events/Reports/GetCategoryFromNameId.php
+++ b/plugins/Events/Reports/GetCategoryFromNameId.php
@@ -9,7 +9,6 @@
namespace Piwik\Plugins\Events\Reports;
use Piwik\Piwik;
-use Piwik\Plugin\Report;
use Piwik\Plugins\Events\Columns\EventCategory;
/**
@@ -24,6 +23,5 @@ class GetCategoryFromNameId extends Base
$this->dimension = new EventCategory();
$this->name = Piwik::translate('Events_EventCategories');
$this->isSubtableReport = true;
- $this->widgetParams = array();
}
} \ No newline at end of file
diff --git a/plugins/Events/Reports/GetName.php b/plugins/Events/Reports/GetName.php
index aa21f968be..08d97b6ac4 100644
--- a/plugins/Events/Reports/GetName.php
+++ b/plugins/Events/Reports/GetName.php
@@ -27,6 +27,5 @@ class GetName extends Base
$this->actionToLoadSubTables = 'getActionFromNameId';
}
$this->order = 2;
- $this->widgetTitle = 'Events_EventNames';
}
}
diff --git a/plugins/Events/Reports/GetNameFromActionId.php b/plugins/Events/Reports/GetNameFromActionId.php
index 403d252b65..e9a171a5c7 100644
--- a/plugins/Events/Reports/GetNameFromActionId.php
+++ b/plugins/Events/Reports/GetNameFromActionId.php
@@ -9,7 +9,6 @@
namespace Piwik\Plugins\Events\Reports;
use Piwik\Piwik;
-use Piwik\Plugin\Report;
use Piwik\Plugins\Events\Columns\EventName;
/**
@@ -24,6 +23,5 @@ class GetNameFromActionId extends Base
$this->dimension = new EventName();
$this->name = Piwik::translate('Events_Names');
$this->isSubtableReport = true;
- $this->widgetParams = array();
}
} \ No newline at end of file
diff --git a/plugins/Events/Reports/GetNameFromCategoryId.php b/plugins/Events/Reports/GetNameFromCategoryId.php
index ee951e03bf..1f9e1b3318 100644
--- a/plugins/Events/Reports/GetNameFromCategoryId.php
+++ b/plugins/Events/Reports/GetNameFromCategoryId.php
@@ -9,7 +9,6 @@
namespace Piwik\Plugins\Events\Reports;
use Piwik\Piwik;
-use Piwik\Plugin\Report;
use Piwik\Plugins\Events\Columns\EventName;
/**
@@ -19,11 +18,11 @@ class GetNameFromCategoryId extends Base
{
protected function init()
{
- parent::init();
+ $this->categoryId = 'Events_Events';
+ $this->processedMetrics = false;
$this->dimension = new EventName();
$this->name = Piwik::translate('Events_EventNames');
$this->isSubtableReport = true;
- $this->widgetParams = array();
}
} \ No newline at end of file
diff --git a/plugins/Events/Widgets/EventsByDimension.php b/plugins/Events/Widgets/EventsByDimension.php
new file mode 100644
index 0000000000..ef04e0d761
--- /dev/null
+++ b/plugins/Events/Widgets/EventsByDimension.php
@@ -0,0 +1,22 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\Events\Widgets;
+
+use Piwik\Plugins\CoreHome\CoreHome;
+use Piwik\Translation\Translator;
+use Piwik\Widget\WidgetContainerConfig;
+
+class EventsByDimension extends WidgetContainerConfig
+{
+ protected $layout = CoreHome::WIDGET_CONTAINER_LAYOUT_BY_DIMENSION;
+ protected $id = 'Events';
+ protected $categoryId = 'General_Actions';
+ protected $subcategoryId = 'Events_Events';
+
+}
diff --git a/plugins/Events/templates/index.twig b/plugins/Events/templates/index.twig
deleted file mode 100644
index a12afb651a..0000000000
--- a/plugins/Events/templates/index.twig
+++ /dev/null
@@ -1,2 +0,0 @@
-{{ leftMenuReports|raw }}
-
diff --git a/plugins/ExamplePlugin/Menu.php b/plugins/ExamplePlugin/Menu.php
index f890587fea..7c9acb90f6 100644
--- a/plugins/ExamplePlugin/Menu.php
+++ b/plugins/ExamplePlugin/Menu.php
@@ -9,27 +9,16 @@
namespace Piwik\Plugins\ExamplePlugin;
use Piwik\Menu\MenuAdmin;
-use Piwik\Menu\MenuReporting;
use Piwik\Menu\MenuTop;
use Piwik\Menu\MenuUser;
/**
* This class allows you to add, remove or rename menu items.
- * To configure a menu (such as Admin Menu, Reporting Menu, User Menu...) simply call the corresponding methods as
+ * To configure a menu (such as Admin Menu, Top Menu, User Menu...) simply call the corresponding methods as
* described in the API-Reference http://developer.piwik.org/api-reference/Piwik/Menu/MenuAbstract
*/
class Menu extends \Piwik\Plugin\Menu
{
- public function configureReportingMenu(MenuReporting $menu)
- {
- // reuse an existing category. Execute the showList() method within the controller when menu item was clicked
- // $menu->addVisitorsItem('Report 1', $this->urlForAction('showList'), $orderId = 30);
- // $menu->addActionsItem('Report 1', $this->urlForAction('showList'), $orderId = 30);
-
- // or create a custom category 'UI Framework'
- // $menu->addItem('UI Framework', '', $this->urlForDefaultAction(), $orderId = 30);
- // $menu->addItem('UI Framework', 'Report 1', $this->urlForAction('showList'), $orderId = 30);
- }
public function configureAdminMenu(MenuAdmin $menu)
{
diff --git a/plugins/ExamplePlugin/Widgets.php b/plugins/ExamplePlugin/Widgets.php
deleted file mode 100644
index a5670902ef..0000000000
--- a/plugins/ExamplePlugin/Widgets.php
+++ /dev/null
@@ -1,67 +0,0 @@
-<?php
-/**
- * Piwik - free/libre analytics platform
- *
- * @link http://piwik.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- */
-
-namespace Piwik\Plugins\ExamplePlugin;
-
-use Piwik\View;
-use Piwik\WidgetsList;
-
-/**
- * This class allows you to add your own widgets to the Piwik platform. In case you want to remove widgets from another
- * plugin please have a look at the "configureWidgetsList()" method.
- * To configure a widget simply call the corresponding methods as described in the API-Reference:
- * http://developer.piwik.org/api-reference/Piwik/Plugin\Widgets
- */
-class Widgets extends \Piwik\Plugin\Widgets
-{
- /**
- * Here you can define the category the widget belongs to. You can reuse any existing widget category or define
- * your own category.
- * @var string
- */
- protected $category = 'Example Category';
-
- /**
- * Here you can add one or multiple widgets. You can add a widget by calling the method "addWidget()" and pass the
- * name of the widget as well as a method name that should be called to render the widget. The method can be
- * defined either directly here in this widget class or in the controller in case you want to reuse the same action
- * for instance in the menu etc.
- */
- protected function init()
- {
- // $this->addWidget('Example Widget Name', $method = 'myExampleWidget');
- // $this->addWidget('Example Widget 2', $method = 'myExampleWidget', $params = array('myparam' => 'myvalue'));
- }
-
- /**
- * This method renders a widget as defined in "init()". It's on you how to generate the content of the
- * widget. As long as you return a string everything is fine. You can use for instance a "Piwik\View" to render a
- * twig template. In such a case don't forget to create a twig template (eg. myViewTemplate.twig) in the
- * "templates" directory of your plugin.
- *
- * @return string
- */
- public function myExampleWidget()
- {
- // $view = new View('@ExamplePlugin/myViewTemplate');
- // return $view->render();
-
- return 'My Widget Text';
- }
-
- /**
- * Here you can remove any widgets defined by any plugin.
- *
- * @param WidgetsList $widgetsList
- */
- public function configureWidgetsList(WidgetsList $widgetsList)
- {
- // $widgetsList->remove('NameOfWidgetCategory'); // will remove all widgets having this category
- // $widgetsList->remove('NameOfWidgetCategory', 'Widget name'); // will only remove a specific widget
- }
-}
diff --git a/plugins/ExamplePlugin/Widgets/MyExampleWidget.php b/plugins/ExamplePlugin/Widgets/MyExampleWidget.php
new file mode 100644
index 0000000000..3434a3aac9
--- /dev/null
+++ b/plugins/ExamplePlugin/Widgets/MyExampleWidget.php
@@ -0,0 +1,80 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\ExamplePlugin\Widgets;
+
+use Piwik\Widget\Widget;
+use Piwik\Widget\WidgetConfig;
+use Piwik\View;
+
+/**
+ * This class allows you to add your own widget to the Piwik platform. In case you want to remove widgets from another
+ * plugin please have a look at the "configureWidgetsList()" method.
+ * To configure a widget simply call the corresponding methods as described in the API-Reference:
+ * http://developer.piwik.org/api-reference/Piwik/Plugin\Widget
+ */
+class MyExampleWidget extends Widget
+{
+ public static function configure(WidgetConfig $config)
+ {
+ /**
+ * Set the category the widget belongs to. You can reuse any existing widget category or define
+ * your own category.
+ */
+ $config->setCategoryId('About Piwik');
+
+ /**
+ * Set the subcategory the widget belongs to. If a subcategory is set, the widget will be shown in the UI.
+ */
+ // $config->setSubcategoryId('General_Overview');
+
+ /**
+ * Set the name of the widget belongs to.
+ */
+ $config->setName('Example Widget Name');
+
+ /**
+ * Set the order of the widget. The lower the number, the earlier the widget will be listed within a category.
+ */
+ $config->setOrder(99);
+
+ /**
+ * Optionally set URL parameters that will be used when this widget is requested.
+ * $config->setParameters(array('myparam' => 'myvalue'));
+ */
+
+ /**
+ * Define whether a widget is enabled or not. For instance some widgets might not be available to every user or
+ * might depend on a setting (such as Ecommerce) of a site. In such a case you can perform any checks and then
+ * set `true` or `false`. If your widget is only available to users having super user access you can do the
+ * following:
+ *
+ * $config->setIsEnabled(\Piwik\Piwik::hasUserSuperUserAccess());
+ * or
+ * if (!\Piwik\Piwik::hasUserSuperUserAccess())
+ * $config->disable();
+ */
+ }
+
+ /**
+ * This method renders the widget. It's on you how to generate the content of the widget.
+ * As long as you return a string everything is fine. You can use for instance a "Piwik\View" to render a
+ * twig template. In such a case don't forget to create a twig template (eg. myViewTemplate.twig) in the
+ * "templates" directory of your plugin.
+ *
+ * @return string
+ */
+ public function render()
+ {
+ // $view = new View('@ExamplePlugin/myViewTemplate');
+ // return $view->render();
+
+ return '<div>My Widget Text</div>';
+ }
+
+} \ No newline at end of file
diff --git a/plugins/ExamplePlugin/javascripts/plugin.js b/plugins/ExamplePlugin/javascripts/plugin.js
index 1a0d0dee7a..1f14f0afb7 100644
--- a/plugins/ExamplePlugin/javascripts/plugin.js
+++ b/plugins/ExamplePlugin/javascripts/plugin.js
@@ -14,7 +14,7 @@ $(document).ready(function () {
* disable_merged_assets = 1
*/
- if('undefined' != (typeof console)) { /* IE8 has no console */
+ if('undefined' != (typeof console)) { /* IE9 has no console */
console.log('Plugin file loaded');
}
});
diff --git a/plugins/ExampleReport/Reports/Base.php b/plugins/ExampleReport/Reports/Base.php
index c09da78e4b..35af935d9e 100644
--- a/plugins/ExampleReport/Reports/Base.php
+++ b/plugins/ExampleReport/Reports/Base.php
@@ -14,6 +14,6 @@ abstract class Base extends Report
{
protected function init()
{
- $this->category = 'ExampleCategory';
+ $this->categoryId = 'ExampleCategory';
}
}
diff --git a/plugins/ExampleReport/Reports/GetExampleReport.php b/plugins/ExampleReport/Reports/GetExampleReport.php
index 42af54d04a..9e0980f050 100644
--- a/plugins/ExampleReport/Reports/GetExampleReport.php
+++ b/plugins/ExampleReport/Reports/GetExampleReport.php
@@ -49,12 +49,8 @@ class GetExampleReport extends Base
// 24 rows for 1-24hours
// $this->constantRowsCount = true;
- // If a menu title is specified, the report will be displayed in the menu
- // $this->menuTitle = 'ExampleReportName';
-
- // If a widget title is specified, the report will be displayed in the list of widgets and the report can be
- // exported as a widget
- // $this->widgetTitle = 'ExampleReportName';
+ // If a subcategory is specified, the report will be displayed in the menu under this menu item
+ // $this->subCategory = 'ExampleReportName';
}
/**
diff --git a/plugins/ExampleRssWidget/Widgets.php b/plugins/ExampleRssWidget/Widgets/RssChangelog.php
index 41d316323c..d42737b3fa 100644
--- a/plugins/ExampleRssWidget/Widgets.php
+++ b/plugins/ExampleRssWidget/Widgets/RssChangelog.php
@@ -6,36 +6,21 @@
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
*/
-namespace Piwik\Plugins\ExampleRssWidget;
+namespace Piwik\Plugins\ExampleRssWidget\Widgets;
-use Piwik\Common;
use Piwik\Piwik;
+use Piwik\Widget\WidgetConfig;
+use Piwik\Plugins\ExampleRssWidget\RssRenderer;
-class Widgets extends \Piwik\Plugin\Widgets
+class RssChangelog extends \Piwik\Widget\Widget
{
- protected $category = 'About Piwik';
-
- protected function init()
- {
- $this->addWidget('Piwik.org Blog', 'rssPiwik');
- $this->addWidget('Piwik Changelog', 'rssChangelog');
- }
-
- public function rssPiwik()
+ public static function configure(WidgetConfig $config)
{
- try {
- $rss = new RssRenderer('http://feeds.feedburner.com/Piwik');
- $rss->showDescription(true);
-
- return $rss->get();
-
- } catch (\Exception $e) {
-
- return $this->error($e);
- }
+ $config->setCategoryId('About Piwik');
+ $config->setName('Piwik Changelog');
}
- public function rssChangelog()
+ public function render()
{
try {
$rss = new RssRenderer('http://feeds.feedburner.com/PiwikReleases');
diff --git a/plugins/ExampleRssWidget/Widgets/RssPiwik.php b/plugins/ExampleRssWidget/Widgets/RssPiwik.php
new file mode 100644
index 0000000000..489b703656
--- /dev/null
+++ b/plugins/ExampleRssWidget/Widgets/RssPiwik.php
@@ -0,0 +1,47 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\ExampleRssWidget\Widgets;
+
+use Piwik\Piwik;
+use Piwik\Widget\WidgetConfig;
+use Piwik\Plugins\ExampleRssWidget\RssRenderer;
+
+class RssPiwik extends \Piwik\Widget\Widget
+{
+ public static function configure(WidgetConfig $config)
+ {
+ $config->setCategoryId('About Piwik');
+ $config->setName('Piwik.org Blog');
+ }
+
+ public function render()
+ {
+ try {
+ $rss = new RssRenderer('http://feeds.feedburner.com/Piwik');
+ $rss->showDescription(true);
+
+ return $rss->get();
+
+ } catch (\Exception $e) {
+
+ return $this->error($e);
+ }
+ }
+
+ /**
+ * @param \Exception $e
+ * @return string
+ */
+ private function error($e)
+ {
+ return '<div class="pk-emptyDataTable">'
+ . Piwik::translate('General_ErrorRequest', array('', ''))
+ . ' - ' . $e->getMessage() . '</div>';
+ }
+}
diff --git a/plugins/ExampleUI/API.php b/plugins/ExampleUI/API.php
index 7b6e0c508a..ae9beae05f 100644
--- a/plugins/ExampleUI/API.php
+++ b/plugins/ExampleUI/API.php
@@ -99,4 +99,5 @@ class API extends \Piwik\Plugin\API
return $planetsDataTable;
}
+
}
diff --git a/plugins/ExampleUI/Categories/ExampleUiCategory.php b/plugins/ExampleUI/Categories/ExampleUiCategory.php
new file mode 100644
index 0000000000..cc7d2fd219
--- /dev/null
+++ b/plugins/ExampleUI/Categories/ExampleUiCategory.php
@@ -0,0 +1,17 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\ExampleUI\Categories;
+
+use Piwik\Category\Category;
+
+class ExampleUiCategory extends Category
+{
+ protected $id = 'ExampleUI_UiFramework';
+ protected $order = 90;
+}
diff --git a/plugins/ExampleUI/Controller.php b/plugins/ExampleUI/Controller.php
index 210093c8b5..c032d449fa 100644
--- a/plugins/ExampleUI/Controller.php
+++ b/plugins/ExampleUI/Controller.php
@@ -18,38 +18,6 @@ use Piwik\ViewDataTable\Factory as ViewDataTableFactory;
*/
class Controller extends \Piwik\Plugin\Controller
{
- public function dataTables()
- {
- $controllerAction = $this->pluginName . '.' . __FUNCTION__;
- $apiAction = 'ExampleUI.getTemperatures';
-
- $view = ViewDataTableFactory::build('table', $apiAction, $controllerAction);
-
- $view->config->translations['value'] = 'Temperature in °C';
- $view->config->translations['label'] = 'Hour of day';
- $view->requestConfig->filter_sort_column = 'label';
- $view->requestConfig->filter_sort_order = 'asc';
- $view->requestConfig->filter_limit = 24;
- $view->config->columns_to_display = array('label', 'value');
- $view->config->y_axis_unit = '°C'; // useful if the user requests the bar graph
- $view->config->show_exclude_low_population = false;
- $view->config->show_table_all_columns = false;
- $view->config->disable_row_evolution = true;
- $view->config->max_graph_elements = 24;
- $view->config->metrics_documentation = array('value' => 'Documentation for temperature metric');
-
- return $view->render();
- }
-
- public function evolutionGraph()
- {
- $view = new View('@ExampleUI/evolutiongraph');
-
- $this->setPeriodVariablesView($view);
- $view->evolutionGraph = $this->getEvolutionGraph(array(), array('server1', 'server2'));
-
- return $view->render();
- }
public function notifications()
{
@@ -78,126 +46,4 @@ class Controller extends \Piwik\Plugin\Controller
return $view->render();
}
- public function getEvolutionGraph(array $columns = array(), array $defaultColumns = array())
- {
- if (empty($columns)) {
- $columns = Common::getRequestVar('columns', false);
- if (false !== $columns) {
- $columns = Piwik::getArrayFromApiParameter($columns);
- }
- }
-
- $view = $this->getLastUnitGraphAcrossPlugins($this->pluginName, __FUNCTION__, $columns,
- $selectableColumns = array('server1', 'server2'), 'My documentation', 'ExampleUI.getTemperaturesEvolution');
- $view->requestConfig->filter_sort_column = 'label';
- $view->requestConfig->filter_sort_order = 'asc';
-
- if (empty($view->config->columns_to_display) && !empty($defaultColumns)) {
- $view->config->columns_to_display = $defaultColumns;
- }
-
- return $this->renderView($view);
- }
-
- public function barGraph()
- {
- $view = ViewDataTableFactory::build(
- 'graphVerticalBar', 'ExampleUI.getTemperatures', $controllerAction = 'ExampleUI.barGraph');
-
- $view->config->y_axis_unit = '°C';
- $view->config->show_footer = false;
- $view->config->translations['value'] = "Temperature";
- $view->config->selectable_columns = array("value");
- $view->config->max_graph_elements = 24;
-
- return $view->render();
- }
-
- public function pieGraph()
- {
- $view = ViewDataTableFactory::build(
- 'graphPie', 'ExampleUI.getPlanetRatios', $controllerAction = 'ExampleUI.pieGraph');
-
- $view->config->columns_to_display = array('value');
- $view->config->translations['value'] = "times the diameter of Earth";
- $view->config->show_footer_icons = false;
- $view->config->selectable_columns = array("value");
- $view->config->max_graph_elements = 10;
-
- return $view->render();
- }
-
- public function tagClouds()
- {
- $output = "<h2>Simple tag cloud</h2>";
- $output .= $this->echoSimpleTagClouds();
-
- $output .= "<br /><br /><h2>Advanced tag cloud: with logos and links</h2>
- <ul style='list-style-type:disc;margin-left:50px'>
- <li>The logo size is proportional to the value returned by the API</li>
- <li>The logo is linked to a specific URL</li>
- </ul><br /><br />";
- $output .= $this->echoAdvancedTagClouds();
-
- return $output;
- }
-
- public function echoSimpleTagClouds()
- {
- $view = ViewDataTableFactory::build(
- 'cloud', 'ExampleUI.getPlanetRatios', $controllerAction = 'ExampleUI.echoSimpleTagClouds');
-
- $view->config->columns_to_display = array('label', 'value');
- $view->config->translations['value'] = "times the diameter of Earth";
- $view->config->show_footer = false;
-
- return $view->render();
- }
-
- public function echoAdvancedTagClouds()
- {
- $view = ViewDataTableFactory::build(
- 'cloud', 'ExampleUI.getPlanetRatiosWithLogos', $controllerAction = 'ExampleUI.echoAdvancedTagClouds');
-
- $view->config->display_logo_instead_of_label = true;
- $view->config->columns_to_display = array('label', 'value');
- $view->config->translations['value'] = "times the diameter of Earth";
-
- return $view->render();
- }
-
- public function sparklines()
- {
- $view = new View('@ExampleUI/sparklines');
- $view->urlSparkline1 = $this->getUrlSparkline('generateSparkline', array('server' => 'server1', 'rand' => mt_rand()));
- $view->urlSparkline2 = $this->getUrlSparkline('generateSparkline', array('server' => 'server2', 'rand' => mt_rand()));
-
- return $view->render();
- }
-
- public function generateSparkline()
- {
- $view = ViewDataTableFactory::build(
- 'sparkline', 'ExampleUI.getTemperaturesEvolution', $controllerAction = 'ExampleUI.generateSparkline');
-
- $serverRequested = Common::getRequestVar('server', false);
- if (false !== $serverRequested) {
- $view->config->columns_to_display = array($serverRequested);
- }
-
- return $view->render();
- }
-
- public function treemap()
- {
- $view = ViewDataTableFactory::build(
- 'infoviz-treemap', 'ExampleUI.getTemperatures', $controllerAction = 'ExampleUI.treemap');
-
- $view->config->translations['value'] = "Temperature";
- $view->config->columns_to_display = array("label", "value");
- $view->config->selectable_columns = array("value");
- $view->config->show_evolution_values = 0;
-
- return $view->render();
- }
}
diff --git a/plugins/ExampleUI/Menu.php b/plugins/ExampleUI/Menu.php
index fe41612847..35cf0d70b5 100644
--- a/plugins/ExampleUI/Menu.php
+++ b/plugins/ExampleUI/Menu.php
@@ -8,37 +8,12 @@
*/
namespace Piwik\Plugins\ExampleUI;
-use Piwik\Menu\MenuReporting;
use Piwik\Menu\MenuUser;
-use Piwik\Plugin\Manager as PluginManager;
-/**
- */
class Menu extends \Piwik\Plugin\Menu
{
- public function configureReportingMenu(MenuReporting $menu)
- {
- $menu->addItem('UI Framework', '', array(), 30);
-
- $this->addSubMenu($menu, 'Data tables', 'dataTables', 1);
- $this->addSubMenu($menu, 'Bar graph', 'barGraph', 2);
- $this->addSubMenu($menu, 'Pie graph', 'pieGraph', 3);
- $this->addSubMenu($menu, 'Tag clouds', 'tagClouds', 4);
- $this->addSubMenu($menu, 'Sparklines', 'sparklines', 5);
- $this->addSubMenu($menu, 'Evolution Graph', 'evolutionGraph', 6);
-
- if (PluginManager::getInstance()->isPluginActivated('TreemapVisualization')) {
- $this->addSubMenu($menu, 'Treemap', 'treemap', 7);
- }
- }
-
public function configureUserMenu(MenuUser $menu)
{
$menu->addPlatformItem('UI Notifications', $this->urlForAction('notifications'), $order = 10);
}
-
- private function addSubMenu(MenuReporting $menu, $subMenu, $action, $order)
- {
- $menu->addItem('UI Framework', $subMenu, $this->urlForAction($action), $order);
- }
}
diff --git a/plugins/ExampleUI/Reports/Base.php b/plugins/ExampleUI/Reports/Base.php
new file mode 100644
index 0000000000..88fa676754
--- /dev/null
+++ b/plugins/ExampleUI/Reports/Base.php
@@ -0,0 +1,19 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\ExampleUI\Reports;
+
+use Piwik\Plugin\Report;
+
+abstract class Base extends Report
+{
+ protected function init()
+ {
+ $this->categoryId = 'ExampleUI_UiFramework';
+ }
+}
diff --git a/plugins/ExampleUI/Reports/GetPlanetRatios.php b/plugins/ExampleUI/Reports/GetPlanetRatios.php
new file mode 100644
index 0000000000..244e8f79c8
--- /dev/null
+++ b/plugins/ExampleUI/Reports/GetPlanetRatios.php
@@ -0,0 +1,74 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+
+namespace Piwik\Plugins\ExampleUI\Reports;
+
+use Piwik\Plugin\Report;
+use Piwik\Plugin\ViewDataTable;
+use Piwik\Plugins\CoreVisualizations\Visualizations\Cloud;
+use Piwik\Plugins\CoreVisualizations\Visualizations\JqplotGraph\Pie;
+use Piwik\Report\ReportWidgetFactory;
+use Piwik\Widget\WidgetsList;
+
+/**
+ * This class defines a new report.
+ *
+ * See {@link http://developer.piwik.org/api-reference/Piwik/Plugin/Report} for more information.
+ */
+class GetPlanetRatios extends Base
+{
+ protected function init()
+ {
+ parent::init();
+
+ $this->name = 'Pie graph';
+ $this->subcategoryId = $this->name;
+ $this->order = 112;
+ }
+
+ public function getDefaultTypeViewDataTable()
+ {
+ return PIE::ID;
+ }
+
+ public function configureWidgets(WidgetsList $widgetsList, ReportWidgetFactory $factory)
+ {
+ $widgetsList->addWidgetConfig(
+ // in this case it will render PIE as configured as default
+ $factory->createWidget()
+ );
+
+ $widgetsList->addWidgetConfig(
+ $factory->createWidget()
+ ->setName('Simple tag cloud')
+ ->setSubcategoryId('Tag clouds')
+ ->forceViewDataTable(Cloud::ID)
+ ->setOrder(5)
+ );
+ }
+
+ public function configureView(ViewDataTable $view)
+ {
+ $view->config->addTranslation('value', 'times the diameter of Earth');
+
+ if ($view->isViewDataTableId(PIE::ID)) {
+
+ $view->config->columns_to_display = array('value');
+ $view->config->selectable_columns = array('value');
+ $view->config->show_footer_icons = false;
+ $view->config->max_graph_elements = 10;
+
+ } else if ($view->isViewDataTableId(Cloud::ID)) {
+
+ $view->config->columns_to_display = array('label', 'value');
+ $view->config->show_footer = false;
+
+ }
+ }
+
+}
diff --git a/plugins/ExampleUI/Reports/GetPlanetRatiosWithLogos.php b/plugins/ExampleUI/Reports/GetPlanetRatiosWithLogos.php
new file mode 100644
index 0000000000..d4d205e6c9
--- /dev/null
+++ b/plugins/ExampleUI/Reports/GetPlanetRatiosWithLogos.php
@@ -0,0 +1,44 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+
+namespace Piwik\Plugins\ExampleUI\Reports;
+
+use Piwik\Piwik;
+use Piwik\Plugin\Report;
+use Piwik\Plugin\ViewDataTable;
+use Piwik\Plugins\CoreVisualizations\Visualizations\Cloud;
+
+/**
+ * This class defines a new report.
+ *
+ * See {@link http://developer.piwik.org/api-reference/Piwik/Plugin/Report} for more information.
+ */
+class GetPlanetRatiosWithLogos extends Base
+{
+ protected function init()
+ {
+ parent::init();
+
+ $this->name = Piwik::translate('Advanced tag cloud: with logos and links');
+ $this->subcategoryId = 'Tag clouds';
+ $this->order = 113;
+ }
+
+ public function getDefaultTypeViewDataTable()
+ {
+ return Cloud::ID;
+ }
+
+ public function configureView(ViewDataTable $view)
+ {
+ $view->config->display_logo_instead_of_label = true;
+ $view->config->columns_to_display = array('label', 'value');
+ $view->config->addTranslation('value', 'times the diameter of Earth');
+ }
+
+}
diff --git a/plugins/ExampleUI/Reports/GetTemperatures.php b/plugins/ExampleUI/Reports/GetTemperatures.php
new file mode 100644
index 0000000000..0449e8b3e2
--- /dev/null
+++ b/plugins/ExampleUI/Reports/GetTemperatures.php
@@ -0,0 +1,93 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+
+namespace Piwik\Plugins\ExampleUI\Reports;
+
+use Piwik\Piwik;
+use Piwik\Plugin\Report;
+use Piwik\Plugin\ViewDataTable;
+use Piwik\Plugins\CoreVisualizations\Visualizations\JqplotGraph\Bar;
+use Piwik\Plugin\Manager as PluginManager;
+use Piwik\Report\ReportWidgetFactory;
+use Piwik\View;
+use Piwik\Widget\WidgetsList;
+
+/**
+ * This class defines a new report.
+ *
+ * See {@link http://developer.piwik.org/api-reference/Piwik/Plugin/Report} for more information.
+ */
+class GetTemperatures extends Base
+{
+ protected function init()
+ {
+ parent::init();
+
+ $this->name = Piwik::translate('ExampleUI_GetTemperaturesDataTable');
+ $this->subcategoryId = 'ExampleUI_GetTemperaturesDataTable';
+ $this->order = 110;
+ }
+
+ public function configureWidgets(WidgetsList $widgetsList, ReportWidgetFactory $factory)
+ {
+ // this will render the default view, in this case an Html Table
+ $widgetsList->addWidgetConfig($factory->createWidget());
+
+ $widgetsList->addWidgetConfig(
+ $factory->createWidget()
+ ->forceViewDataTable(Bar::ID)
+ ->setSubcategoryId('Bar graph')
+ );
+
+ if (PluginManager::getInstance()->isPluginActivated('TreemapVisualization')) {
+ $widgetsList->addWidgetConfig(
+ $factory->createWidget()
+ ->setName('Treemap example')
+ ->setSubcategoryId('Treemap')
+ ->forceViewDataTable('infoviz-treemap')
+ );
+
+ }
+ }
+
+ public function configureView(ViewDataTable $view)
+ {
+ if ($view->isViewDataTableId(BAR::ID)) {
+
+ $view->config->y_axis_unit = '°C';
+ $view->config->show_footer = false;
+ $view->config->translations['value'] = "Temperature";
+ $view->config->selectable_columns = array("value");
+ $view->config->max_graph_elements = 24;
+
+ } elseif ($view->isViewDataTableId('infoviz-treemap')) {
+
+ $view->config->translations['value'] = "Temperature";
+ $view->config->columns_to_display = array("label", "value");
+ $view->config->selectable_columns = array("value");
+ $view->config->show_evolution_values = 0;
+
+ } else {
+ // for default view datatable, eg HtmlTable
+
+ $view->config->translations['value'] = 'Temperature in °C';
+ $view->config->translations['label'] = 'Hour of day';
+ $view->requestConfig->filter_sort_column = 'label';
+ $view->requestConfig->filter_sort_order = 'asc';
+ $view->requestConfig->filter_limit = 24;
+ $view->config->columns_to_display = array('label', 'value');
+ $view->config->y_axis_unit = '°C'; // useful if the user requests the bar graph
+ $view->config->show_exclude_low_population = false;
+ $view->config->show_table_all_columns = false;
+ $view->config->disable_row_evolution = true;
+ $view->config->max_graph_elements = 24;
+ $view->config->metrics_documentation = array('value' => 'Documentation for temperature metric');
+ }
+ }
+
+}
diff --git a/plugins/ExampleUI/Reports/GetTemperaturesEvolution.php b/plugins/ExampleUI/Reports/GetTemperaturesEvolution.php
new file mode 100644
index 0000000000..ff8ea66e10
--- /dev/null
+++ b/plugins/ExampleUI/Reports/GetTemperaturesEvolution.php
@@ -0,0 +1,95 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+
+namespace Piwik\Plugins\ExampleUI\Reports;
+
+use Piwik\Common;
+use Piwik\Piwik;
+use Piwik\Plugin\Report;
+use Piwik\Plugin\ViewDataTable;
+
+use Piwik\Plugins\CoreVisualizations\Visualizations\JqplotGraph\Bar;
+use Piwik\Plugins\CoreVisualizations\Visualizations\JqplotGraph\Evolution;
+use Piwik\Plugins\CoreVisualizations\Visualizations\JqplotGraph\Pie;
+use Piwik\Plugins\CoreVisualizations\Visualizations\Sparklines;
+use Piwik\Report\ReportWidgetFactory;
+use Piwik\View;
+use Piwik\Widget\WidgetsList;
+
+/**
+ * This class defines a new report.
+ *
+ * See {@link http://developer.piwik.org/api-reference/Piwik/Plugin/Report} for more information.
+ */
+class GetTemperaturesEvolution extends Base
+{
+ protected function init()
+ {
+ parent::init();
+
+ $this->name = Piwik::translate('ExampleUI_GetTemperaturesEvolution');
+ $this->order = 111;
+ }
+
+ public function configureWidgets(WidgetsList $widgetsList, ReportWidgetFactory $factory)
+ {
+ $widgetsList->addWidgetConfig(
+ $factory->createWidget()
+ ->setSubcategoryId('Sparklines')
+ ->forceViewDataTable(Sparklines::ID)
+ );
+
+ $widgetsList->addWidgetConfig(
+ $factory->createWidget()
+ ->setName('ExampleUI_TemperaturesEvolution')
+ ->setSubcategoryId('Evolution Graph')
+ ->forceViewDataTable(Evolution::ID)
+ ->setParameters(array('columns' => array('server1', 'server2')))
+ );
+
+ }
+
+ /**
+ * Here you can configure how your report should be displayed. For instance whether your report supports a search
+ * etc. You can also change the default request config. For instance change how many rows are displayed by default.
+ *
+ * @param ViewDataTable $view
+ */
+ public function configureView(ViewDataTable $view)
+ {
+ if ($view->isViewDataTableId(Sparklines::ID)) {
+
+ /** @var Sparklines $view */
+ $view->config->addSparklineMetric(array('server1'));
+ $view->config->addSparklineMetric(array('server2'));
+ $view->config->addTranslations(array('server1' => 'Evolution of temperature for server piwik.org'));
+ $view->config->addTranslations(array('server2' => 'Evolution of temperature for server dev.piwik.org'));
+
+ } elseif ($view->isViewDataTableId(Evolution::ID)) {
+
+ /** @var Evolution $view */
+ $selectableColumns = array('server1', 'server2');
+
+ $columns = Common::getRequestVar('columns', false);
+ if (!empty($columns)) {
+ $columns = Piwik::getArrayFromApiParameter($columns);
+ }
+
+ $columns = array_merge($columns ? $columns : array(), $selectableColumns);
+ $view->config->columns_to_display = $columns;
+
+ $view->config->addTranslations(array_combine($columns, $columns));
+ $view->config->selectable_columns = $selectableColumns;
+ $view->requestConfig->filter_sort_column = 'label';
+ $view->requestConfig->filter_sort_order = 'asc';
+ $view->config->documentation = 'My documentation';
+ $view->config->show_goals = false;
+ }
+ }
+
+}
diff --git a/plugins/ExampleUI/lang/en.json b/plugins/ExampleUI/lang/en.json
new file mode 100644
index 0000000000..e0c05c5411
--- /dev/null
+++ b/plugins/ExampleUI/lang/en.json
@@ -0,0 +1,8 @@
+{
+ "ExampleUI": {
+ "UiFramework": "UI Framework",
+ "GetTemperaturesDataTable": "Data tables",
+ "GetTemperaturesEvolution": "Temperatures evolution over time",
+ "TemperaturesEvolution": "Evolution of server temperatures over the last few days"
+ }
+} \ No newline at end of file
diff --git a/plugins/ExampleUI/plugin.json b/plugins/ExampleUI/plugin.json
index ec2fcfe025..8a39e0a2a2 100644
--- a/plugins/ExampleUI/plugin.json
+++ b/plugins/ExampleUI/plugin.json
@@ -2,14 +2,23 @@
"name": "ExampleUI",
"description": "Piwik Platform showcase: how to display data tables, graphs, and the UI framework.",
"version": "1.0.1",
- "keywords": ["example", "framework", "platform", "ui", "visualization"],
- "homepage": "http://piwik.org",
+ "keywords": [
+ "example",
+ "framework",
+ "platform",
+ "ui",
+ "visualization"
+ ],
+ "homepage": "http:\/\/piwik.org",
"license": "GPL v3+",
"authors": [
{
"name": "Piwik",
"email": "hello@piwik.org",
- "homepage": "http://piwik.org"
+ "homepage": "http:\/\/piwik.org"
}
- ]
+ ],
+ "require": {
+ "piwik": ">=2.13.1"
+ }
} \ No newline at end of file
diff --git a/plugins/Goals/API.php b/plugins/Goals/API.php
index 113bea5ec9..89af85f9c0 100644
--- a/plugins/Goals/API.php
+++ b/plugins/Goals/API.php
@@ -22,6 +22,7 @@ use Piwik\Plugin\Report;
use Piwik\Plugins\API\DataTable\MergeDataTables;
use Piwik\Plugins\CoreHome\Columns\Metrics\ConversionRate;
use Piwik\Plugins\Goals\Columns\Metrics\AverageOrderRevenue;
+use Piwik\Plugin\Reports;
use Piwik\Segment\SegmentExpression;
use Piwik\Site;
use Piwik\Tracker\Cache;
@@ -413,7 +414,7 @@ class API extends \Piwik\Plugin\API
$requestedColumns = array_unique(array_merge($requestedColumns, $metricsToAdd));
}
- $report = Report::factory('Goals', 'getMetrics');
+ $report = Reports::factory('Goals', 'getMetrics');
$columnsToGet = $report->getMetricsRequiredForReport($allMetrics, $requestedColumns);
$inDbMetricNames = array_map(function ($name) use ($idGoal) {
diff --git a/plugins/Goals/Categories/AddANewGoalSubcategory.php b/plugins/Goals/Categories/AddANewGoalSubcategory.php
new file mode 100644
index 0000000000..9b613f2e55
--- /dev/null
+++ b/plugins/Goals/Categories/AddANewGoalSubcategory.php
@@ -0,0 +1,19 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\Goals\Categories;
+
+use Piwik\Category\Subcategory;
+
+class AddANewGoalSubcategory extends Subcategory
+{
+ protected $categoryId = 'Goals_Goals';
+ protected $id = 'Goals_AddNewGoal';
+ protected $order = 9999;
+
+}
diff --git a/plugins/Goals/Categories/GoalsCategory.php b/plugins/Goals/Categories/GoalsCategory.php
new file mode 100644
index 0000000000..043a51fd0b
--- /dev/null
+++ b/plugins/Goals/Categories/GoalsCategory.php
@@ -0,0 +1,18 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\Goals\Categories;
+
+use Piwik\Category\Category;
+
+class GoalsCategory extends Category
+{
+ protected $id = 'Goals_Goals';
+ protected $order = 25;
+ protected $icon = 'icon-reporting-goal';
+}
diff --git a/plugins/Goals/Categories/GoalsOverviewSubcategory.php b/plugins/Goals/Categories/GoalsOverviewSubcategory.php
new file mode 100644
index 0000000000..95f2d815c9
--- /dev/null
+++ b/plugins/Goals/Categories/GoalsOverviewSubcategory.php
@@ -0,0 +1,19 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\Goals\Categories;
+
+use Piwik\Category\Subcategory;
+
+class GoalsOverviewSubcategory extends Subcategory
+{
+ protected $categoryId = 'Goals_Goals';
+ protected $id = 'General_Overview';
+ protected $order = 2;
+
+}
diff --git a/plugins/Goals/Categories/ManageGoalsSubcategory.php b/plugins/Goals/Categories/ManageGoalsSubcategory.php
new file mode 100644
index 0000000000..ef71697981
--- /dev/null
+++ b/plugins/Goals/Categories/ManageGoalsSubcategory.php
@@ -0,0 +1,19 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\Goals\Categories;
+
+use Piwik\Category\Subcategory;
+
+class ManageGoalsSubcategory extends Subcategory
+{
+ protected $categoryId = 'Goals_Goals';
+ protected $id = 'Goals_ManageGoals';
+ protected $order = 9999;
+
+}
diff --git a/plugins/Goals/Controller.php b/plugins/Goals/Controller.php
index 4aac0eb736..5d7a5168e2 100644
--- a/plugins/Goals/Controller.php
+++ b/plugins/Goals/Controller.php
@@ -11,12 +11,13 @@ namespace Piwik\Plugins\Goals;
use Piwik\API\Request;
use Piwik\Common;
use Piwik\DataTable;
+use Piwik\DataTable\Renderer\Json;
use Piwik\DataTable\Filter\AddColumnsProcessedMetricsGoal;
+use Piwik\FrontController;
use Piwik\Piwik;
use Piwik\Plugins\Referrers\API as APIReferrers;
use Piwik\Translation\Translator;
use Piwik\View;
-use Piwik\View\ReportsByDimension;
/**
*
@@ -47,11 +48,6 @@ class Controller extends \Piwik\Plugin\Controller
*/
private $translator;
- /**
- * @var TranslationHelper
- */
- private $translationHelper;
-
private function formatConversionRate($conversionRate, $columnName = 'conversion_rate')
{
if ($conversionRate instanceof DataTable) {
@@ -69,89 +65,16 @@ class Controller extends \Piwik\Plugin\Controller
return $conversionRate;
}
- public function __construct(Translator $translator, TranslationHelper $translationHelper)
+ public function __construct(Translator $translator)
{
parent::__construct();
$this->translator = $translator;
- $this->translationHelper = $translationHelper;
$this->idSite = Common::getRequestVar('idSite', null, 'int');
$this->goals = API::getInstance()->getGoals($this->idSite);
}
- public function widgetGoalReport()
- {
- $view = $this->getGoalReportView($idGoal = Common::getRequestVar('idGoal', null, 'string'));
- $view->displayFullReport = false;
- return $view->render();
- }
-
- public function goalReport()
- {
- $view = $this->getGoalReportView($idGoal = Common::getRequestVar('idGoal', null, 'string'));
- $view->displayFullReport = true;
- return $view->render();
- }
-
- protected function getGoalReportView($idGoal = false)
- {
- $view = new View('@Goals/getGoalReportView');
- if ($idGoal == Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_ORDER) {
- $goalDefinition['name'] = $this->translator->translate('Goals_Ecommerce');
- $goalDefinition['allow_multiple'] = true;
- $ecommerce = $view->ecommerce = true;
- } else {
- if (!isset($this->goals[$idGoal])) {
- Piwik::redirectToModule('Goals', 'index', array('idGoal' => null));
- }
- $goalDefinition = $this->goals[$idGoal];
- }
- $this->setGeneralVariablesView($view);
- $goal = $this->getMetricsForGoal($idGoal);
- foreach ($goal as $name => $value) {
- $view->$name = $value;
- }
- if ($idGoal == Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_ORDER) {
- $goal = $this->getMetricsForGoal(Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_CART);
- foreach ($goal as $name => $value) {
- $name = 'cart_' . $name;
- $view->$name = $value;
- }
- }
- $view->showHeadline = false;
- $view->idGoal = $idGoal;
- $view->goalName = $goalDefinition['name'];
- $view->goalAllowMultipleConversionsPerVisit = $goalDefinition['allow_multiple'];
- $view->graphEvolution = $this->getEvolutionGraph(array(), $idGoal, array('nb_conversions'));
- $view->nameGraphEvolution = 'Goals.getEvolutionGraph' . $idGoal;
- $view->topDimensions = $this->getTopDimensions($idGoal);
-
- $goalMetrics = Request::processRequest('Goals.get', array('idGoal' => $idGoal));
-
- // conversion rate for new and returning visitors
- $view->conversion_rate_returning = $this->formatConversionRate($goalMetrics, 'conversion_rate_returning_visit');
- $view->conversion_rate_new = $this->formatConversionRate($goalMetrics, 'conversion_rate_new_visit');
-
- $view->goalReportsByDimension = $this->getGoalReportsByDimensionTable(
- $view->nb_conversions, isset($ecommerce), !empty($view->cart_nb_conversions));
- return $view;
- }
-
- public function index()
- {
- $view = $this->getOverviewView();
-
- // unsanitize goal names and other text data (not done in API so as not to break
- // any other code/cause security issues)
- $goals = $this->goals;
- $view->goalsJSON = json_encode($goals);
-
- $view->ecommerceEnabled = $this->site->isEcommerceEnabled();
- $view->displayFullReport = true;
- return $view->render();
- }
-
public function manage()
{
Piwik::checkUserHasAdminAccess($this->idSite);
@@ -163,48 +86,21 @@ class Controller extends \Piwik\Plugin\Controller
return $view->render();
}
- public function widgetGoalsOverview()
+ public function goalConversionsOverview()
{
- $view = $this->getOverviewView();
- $view->displayFullReport = false;
- return $view->render();
- }
+ $view = new View('@Goals/conversionOverview');
+ $idGoal = Common::getRequestVar('idGoal', null, 'string');
- protected function getOverviewView()
- {
- $view = new View('@Goals/getOverviewView');
- $this->setGeneralVariablesView($view);
-
- $view->graphEvolution = $this->getEvolutionGraph(array(), false, array('nb_conversions'));
- $view->nameGraphEvolution = 'GoalsgetEvolutionGraph';
-
- // sparkline for the historical data of the above values
- $view->urlSparklineConversions = $this->getUrlSparkline('getEvolutionGraph', array('columns' => array('nb_conversions'), 'idGoal' => ''));
- $view->urlSparklineConversionRate = $this->getUrlSparkline('getEvolutionGraph', array('columns' => array('conversion_rate'), 'idGoal' => ''));
- $view->urlSparklineRevenue = $this->getUrlSparkline('getEvolutionGraph', array('columns' => array('revenue'), 'idGoal' => ''));
-
- // Pass empty idGoal will return Goal overview
- $request = new Request("method=Goals.get&format=original&idGoal=");
- $datatable = $request->process();
- $dataRow = $datatable->getFirstRow();
+ $view->topDimensions = $this->getTopDimensions($idGoal);
- $view->nb_conversions = $dataRow->getColumn('nb_conversions');
- $view->nb_visits_converted = $dataRow->getColumn('nb_visits_converted');
- $view->conversion_rate = $this->formatConversionRate($dataRow->getColumn('conversion_rate'));
- $view->revenue = $dataRow->getColumn('revenue');
+ $goalMetrics = Request::processRequest('Goals.get', array('idGoal' => $idGoal));
- $goalMetrics = array();
- foreach ($this->goals as $idGoal => $goal) {
- $goalMetrics[$idGoal] = $this->getMetricsForGoal($idGoal);
- $goalMetrics[$idGoal]['name'] = $goal['name'];
- $goalMetrics[$idGoal]['goalAllowMultipleConversionsPerVisit'] = $goal['allow_multiple'];
- }
+ // conversion rate for new and returning visitors
+ $view->conversion_rate_returning = $this->formatConversionRate($goalMetrics, 'conversion_rate_returning_visit');
+ $view->conversion_rate_new = $this->formatConversionRate($goalMetrics, 'conversion_rate_new_visit');
+ $view->idGoal = $idGoal;
- $view->goalMetrics = $goalMetrics;
- $view->goals = $this->goals;
- $view->goalReportsByDimension = $this->getGoalReportsByDimensionTable(
- $view->nb_conversions, $ecommerce = false, !empty($view->cart_nb_conversions));
- return $view;
+ return $view->render();
}
public function getLastNbConversionsGraph()
@@ -243,6 +139,26 @@ class Controller extends \Piwik\Plugin\Controller
return $view->render();
}
+ public function hasConversions()
+ {
+ $this->checkSitePermission();
+
+ $idGoal = Common::getRequestVar('idGoal', '', 'string');
+ $idSite = Common::getRequestVar('idSite', null, 'int');
+ $period = Common::getRequestVar('period', null, 'string');
+ $date = Common::getRequestVar('date', null, 'string');
+
+ Piwik::checkUserHasViewAccess($idSite);
+
+ $conversions = new Conversions();
+
+ Json::sendHeaderJSON();
+
+ $numConversions = $conversions->getConversionForGoal($idGoal, $idSite, $period, $date);
+
+ return json_encode($numConversions > 0);
+ }
+
public function getEvolutionGraph(array $columns = array(), $idGoal = false, array $defaultColumns = array())
{
if (empty($columns)) {
@@ -333,11 +249,11 @@ class Controller extends \Piwik\Plugin\Controller
$topDimensions = array();
foreach ($topDimensionsToLoad as $dimensionName => $apiMethod) {
$request = new Request("method=$apiMethod
- &format=original
- &filter_update_columns_when_show_all_goals=1
- &idGoal=" . AddColumnsProcessedMetricsGoal::GOALS_FULL_TABLE . "
- &filter_sort_order=desc
- &filter_sort_column=$columnNbConversions" .
+ &format=original
+ &filter_update_columns_when_show_all_goals=1
+ &idGoal=" . AddColumnsProcessedMetricsGoal::GOALS_FULL_TABLE . "
+ &filter_sort_order=desc
+ &filter_sort_column=$columnNbConversions" .
// select a couple more in case some are not valid (ie. conversions==0 or they are "Keyword not defined")
"&filter_limit=" . (self::COUNT_TOP_ROWS_TO_DISPLAY + 2));
$datatable = $request->process();
@@ -401,78 +317,11 @@ class Controller extends \Piwik\Plugin\Controller
'avg_order_revenue' => $aov ? $aov : 0,
'urlSparklinePurchasedProducts' => $this->getUrlSparkline('getEvolutionGraph', array('columns' => array('items'), 'idGoal' => $idGoal)),
'urlSparklineAverageOrderValue' => $this->getUrlSparkline('getEvolutionGraph', array('columns' => array('avg_order_revenue'), 'idGoal' => $idGoal)),
- ));
+ ));
}
return $return;
}
- /**
- * Utility function that returns HTML that displays Goal information for reports. This
- * is the HTML that is at the bottom of every goals page.
- *
- * @param int $conversions The number of conversions for this goal (or all goals
- * in case of the overview).
- * @param bool $ecommerce Whether to show ecommerce reports or not.
- * @param bool $cartNbConversions Whether there are cart conversions or not for this
- * goal.
- * @return string
- */
- private function getGoalReportsByDimensionTable($conversions, $ecommerce = false, $cartNbConversions = false)
- {
- $preloadAbandonedCart = $cartNbConversions !== false && $conversions == 0;
-
- $goalReportsByDimension = new ReportsByDimension('Goals');
-
- // add ecommerce reports
- $ecommerceCustomParams = array();
- if ($ecommerce) {
- if ($preloadAbandonedCart) {
- $ecommerceCustomParams['abandonedCarts'] = '1';
- } else {
- $ecommerceCustomParams['abandonedCarts'] = '0';
- }
- }
-
- if ($conversions > 0 || $ecommerce) {
- // for non-Goals reports, we show the goals table
- $customParams = $ecommerceCustomParams + array('documentationForGoalsPage' => '1');
-
- if (Common::getRequestVar('idGoal', '') === '') // if no idGoal, use 0 for overview
- {
- $customParams['idGoal'] = '0'; // NOTE: Must be string! Otherwise Piwik_View_HtmlTable_Goals fails.
- }
-
- $allReports = Goals::getReportsWithGoalMetrics();
- foreach ($allReports as $category => $reports) {
- if ($ecommerce) {
- $categoryText = $this->translationHelper->translateEcommerceMetricCategory($category);
- } else {
- $categoryText = $this->translationHelper->translateGoalMetricCategory($category);
- }
-
- foreach ($reports as $report) {
- if (empty($report['viewDataTable'])
- && empty($report['abandonedCarts'])
- ) {
- $report['viewDataTable'] = 'tableGoals';
- }
- $customParams['viewDataTable'] = $report['viewDataTable'];
-
- if (!empty($report['parameters'])) {
- $params = array_merge($customParams, $report['parameters']);
- } else {
- $params = $customParams;
- }
-
- $goalReportsByDimension->addReport(
- $categoryText, $report['name'], $report['module'] . '.' . $report['action'], $params);
- }
- }
- }
-
- return $goalReportsByDimension->render();
- }
-
private function setEditGoalsViewVariables($view)
{
$goals = $this->goals;
@@ -501,4 +350,32 @@ class Controller extends \Piwik\Plugin\Controller
{
$view->userCanEditGoals = Piwik::isUserHasAdminAccess($this->idSite);
}
+
+ /**
+ * @deprecated used to be a widgetized URL. There to not break widget URLs
+ */
+ public function widgetGoalReport()
+ {
+ $idGoal = Common::getRequestVar('idGoal', '', 'string');
+
+ if ($idGoal === Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_ORDER) {
+ $_GET['containerId'] = 'EcommerceOverview';
+ } elseif (!empty($idGoal)) {
+ $_GET['containerId'] = 'Goal_' . (int) $idGoal;
+ } else {
+ return '';
+ }
+
+ return FrontController::getInstance()->fetchDispatch('CoreHome', 'renderWidgetContainer');
+ }
+
+ /**
+ * @deprecated used to be a widgetized URL. There to not break widget URLs
+ */
+ public function widgetGoalsOverview()
+ {
+ $_GET['containerId'] = 'GoalsOverview';
+
+ return FrontController::getInstance()->fetchDispatch('CoreHome', 'renderWidgetContainer');
+ }
}
diff --git a/plugins/Goals/Conversions.php b/plugins/Goals/Conversions.php
new file mode 100644
index 0000000000..fbbbef0078
--- /dev/null
+++ b/plugins/Goals/Conversions.php
@@ -0,0 +1,45 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\Goals;
+
+use Piwik\API\Request;
+use Piwik\Cache;
+use Piwik\Common;
+use Piwik\Db;
+
+class Conversions
+{
+
+ public function getConversionForGoal($idGoal, $idSite, $period, $date)
+ {
+ if (!$period || !$date || !$idSite) {
+ return false;
+ }
+
+ $datatable = Request::processRequest('Goals.get', array(
+ 'idGoal' => $idGoal,
+ 'period' => $period,
+ 'date' => $date,
+ 'idSite' => $idSite,
+ 'serialize' => 0,
+ 'segment' => false
+ ));
+
+ // we ignore the segment even if there is one set. We still want to show conversion overview if there are conversions
+ // in general but not for this segment
+
+ $dataRow = $datatable->getFirstRow();
+
+ if (!$dataRow) {
+ return false;
+ }
+
+ return $dataRow->getColumn('nb_conversions');
+ }
+}
diff --git a/plugins/Goals/Goals.php b/plugins/Goals/Goals.php
index 223f05a212..03420aa8d7 100644
--- a/plugins/Goals/Goals.php
+++ b/plugins/Goals/Goals.php
@@ -9,10 +9,12 @@
namespace Piwik\Plugins\Goals;
use Piwik\ArchiveProcessor;
+use Piwik\Common;
use Piwik\Db;
use Piwik\Piwik;
-use Piwik\Plugin\Report;
+use Piwik\Plugin\Reports;
use Piwik\Tracker\GoalManager;
+use Piwik\Category\Subcategory;
/**
*
@@ -27,36 +29,17 @@ class Goals extends \Piwik\Plugin
foreach ($dimensions as $dimension) {
$group = $dimension['category'];
// move "Custom Variables" report to the "Goals/Sales by User attribute" category
- if ($dimension['module'] === 'CustomVariables') {
+ if ($dimension['module'] === 'CustomVariables'
+ || $dimension['action'] == 'getVisitInformationPerServerTime') {
$group = 'VisitsSummary_VisitsSummary';
}
unset($dimension['category']);
$dimensionsByGroup[$group][] = $dimension;
}
- uksort($dimensionsByGroup, array('self', 'sortGoalDimensionsByModule'));
return $dimensionsByGroup;
}
- public static function sortGoalDimensionsByModule($a, $b)
- {
- static $order = null;
-
- if (is_null($order)) {
- $order = array(
- 'Referrers_Referrers',
- 'General_Visit',
- 'General_Visitors',
- 'VisitsSummary_VisitsSummary',
- 'VisitTime_ColumnServerTime',
- );
- }
-
- $orderA = array_search($a, $order);
- $orderB = array_search($b, $order);
- return $orderA > $orderB;
- }
-
public static function getGoalColumns($idGoal)
{
$columns = array(
@@ -96,11 +79,34 @@ class Goals extends \Piwik\Plugin
'SitesManager.deleteSite.end' => 'deleteSiteGoals',
'Goals.getReportsWithGoalMetrics' => 'getActualReportsWithGoalMetrics',
'Translate.getClientSideTranslationKeys' => 'getClientSideTranslationKeys',
- 'Metrics.getDefaultMetricTranslations' => 'addMetricTranslations'
+ 'Metrics.getDefaultMetricTranslations' => 'addMetricTranslations',
+ 'Category.addSubcategories' => 'addSubcategories'
);
return $hooks;
}
+ public function addSubcategories(&$subcategories)
+ {
+ $idSite = Common::getRequestVar('idSite', 0, 'int');
+
+ if (!$idSite) {
+ return;
+ }
+
+ $goals = API::getInstance()->getGoals($idSite);
+
+ $order = 900;
+ foreach ($goals as $goal) {
+ $category = new Subcategory();
+ $category->setName($goal['name']);
+ $category->setCategoryId('Goals_Goals');
+ $category->setId($goal['idgoal']);
+ $category->setOrder($order++);
+ $subcategories[] = $category;
+ }
+ }
+
+
public function addMetricTranslations(&$translations)
{
$metrics = array(
@@ -174,10 +180,12 @@ class Goals extends \Piwik\Plugin
{
$reportsWithGoals = array();
- foreach (Report::getAllReports() as $report) {
+ $reports = new Reports();
+
+ foreach ($reports->getAllReports() as $report) {
if ($report->hasGoalMetrics()) {
$reportsWithGoals[] = array(
- 'category' => $report->getCategoryKey(),
+ 'category' => $report->getCategoryId(),
'name' => $report->getName(),
'module' => $report->getModule(),
'action' => $report->getAction(),
@@ -269,5 +277,6 @@ class Goals extends \Piwik\Plugin
$translationKeys[] = 'Goals_DeleteGoalConfirm';
$translationKeys[] = 'Goals_Ecommerce';
$translationKeys[] = 'Goals_Optional';
+ $translationKeys[] = 'Goals_ChooseGoal';
}
}
diff --git a/plugins/Goals/Menu.php b/plugins/Goals/Menu.php
index d032aea4a2..258a0677e2 100644
--- a/plugins/Goals/Menu.php
+++ b/plugins/Goals/Menu.php
@@ -9,57 +9,12 @@
namespace Piwik\Plugins\Goals;
use Piwik\Common;
-use Piwik\Menu\Group;
-use Piwik\Menu\MenuReporting;
use Piwik\Menu\MenuUser;
use Piwik\Piwik;
use Piwik\Plugins\UsersManager\UserPreferences;
-use Piwik\Translate;
class Menu extends \Piwik\Plugin\Menu
{
- public function configureReportingMenu(MenuReporting $menu)
- {
- $idSite = $this->getIdSite();
- $goals = API::getInstance()->getGoals($idSite);
- $mainGoalMenu = 'Goals_Goals';
-
- if (count($goals) == 0) {
- $linkToAddNewGoal = $this->urlForAction('addNewGoal', array(
- 'idGoal' => null,
- ));
- $menu->addItem($mainGoalMenu, '', array(), 25);
- $menu->addItem($mainGoalMenu, 'Goals_AddNewGoal', $linkToAddNewGoal, 1);
- return;
- }
-
- $order = 1;
-
- $url = $this->urlForAction('index', array('idGoal' => null));
-
- $menu->addItem($mainGoalMenu, '', $url, 25);
- $menu->addItem($mainGoalMenu, 'General_Overview', $url, ++$order);
-
- $group = new Group();
- foreach ($goals as $goal) {
- $subMenuName = str_replace('%', '%%', Translate::clean($goal['name']));
- $params = $this->urlForAction('goalReport', array('idGoal' => $goal['idgoal']));
- $tooltip = sprintf('%s (id = %d)', $subMenuName, $goal['idgoal']);
-
- if (count($goals) > 3) {
- $group->add($subMenuName, $params, $tooltip);
- } else {
- $menu->addItem($mainGoalMenu, $subMenuName, $params, ++$order, $tooltip);
- }
- }
-
- if (count($goals) > 3) {
- $menu->addGroup($mainGoalMenu, 'Goals_ChooseGoal', $group, ++$order, $tooltip = false);
- }
-
- $menu->addItem($mainGoalMenu, 'Goals_ManageGoals', $this->urlForAction('editGoals'), ++$order);
- }
-
public function configureUserMenu(MenuUser $menu)
{
$userPreferences = new UserPreferences();
@@ -68,7 +23,6 @@ class Menu extends \Piwik\Plugin\Menu
if (Piwik::isUserHasAdminAccess($idSite)) {
$menu->addManageItem('Goals_Goals', $this->urlForAction('manage', array('idSite' => $idSite)), 1);
}
-
}
private function getIdSite($default = null)
diff --git a/plugins/Goals/Pages.php b/plugins/Goals/Pages.php
new file mode 100644
index 0000000000..72db6cc21b
--- /dev/null
+++ b/plugins/Goals/Pages.php
@@ -0,0 +1,346 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\Goals;
+
+
+use Piwik\API\Request;
+use Piwik\Cache;
+use Piwik\Common;
+use Piwik\Piwik;
+use Piwik\Plugin\Report;
+use Piwik\Plugins\CoreVisualizations\Visualizations\JqplotGraph\Evolution;
+use Piwik\Plugins\CoreVisualizations\Visualizations\Sparklines;
+use Piwik\Plugin\Reports;
+use Piwik\Widget\WidgetContainerConfig;
+use Piwik\Widget\WidgetConfig;
+use Piwik\Report\ReportWidgetFactory;
+
+class Pages
+{
+ private $orderId = 0;
+ private $allReports = array();
+ private $factory = array();
+ private $conversions;
+
+ public function __construct(ReportWidgetFactory $reportFactory, $reportsWithGoalMetrics)
+ {
+ $this->factory = $reportFactory;
+ $this->allReports = $reportsWithGoalMetrics;
+ $this->conversions = new Conversions();
+ }
+
+ /**
+ * @param array $goals
+ * @return WidgetConfig[]
+ */
+ public function createGoalsOverviewPage($goals)
+ {
+ $subcategory = 'General_Overview';
+
+ $widgets = array();
+
+ $config = $this->factory->createWidget();
+ $config->forceViewDataTable(Evolution::ID);
+ $config->setSubcategoryId($subcategory);
+ $config->setAction('getEvolutionGraph');
+ $config->setOrder(++$this->orderId);
+ $config->setIsNotWidgetizable();
+ $widgets[] = $config;
+
+ $config = $this->factory->createWidget();
+ $config->forceViewDataTable(Sparklines::ID);
+ $config->setSubcategoryId($subcategory);
+ $config->setName('');
+ $config->setOrder(++$this->orderId);
+ $config->setIsNotWidgetizable();
+ $widgets[] = $config;
+
+ foreach ($goals as $goal) {
+ $name = Common::sanitizeInputValue($goal['name']);
+ $goalTranslated = Piwik::translate('Goals_GoalX', array($name));
+
+ $config = $this->factory->createWidget();
+ $config->setName($goalTranslated);
+ $config->setSubcategoryId($subcategory);
+ $config->forceViewDataTable(Sparklines::ID);
+ $config->setParameters(array('idGoal' => $goal['idgoal']));
+ $config->setOrder(++$this->orderId);
+ $config->setIsNotWidgetizable();
+ $config->addParameters(array('allow_multiple' => (int) $goal['allow_multiple'], 'only_summary' => '1'));
+ $widgets[] = $config;
+ }
+
+ $container = $this->createWidgetizableWidgetContainer('GoalsOverview', $subcategory, $widgets);
+
+ $config = $this->factory->createContainerWidget('Goals');
+ $config->setSubcategoryId($subcategory);
+ $config->setName('Goals_ConversionsOverviewBy');
+ $config->setOrder(++$this->orderId);
+ $config->setIsNotWidgetizable();
+ $this->buildGoalByDimensionView('', $config);
+ $config->setMiddlewareParameters(array(
+ 'module' => 'Goals',
+ 'action' => 'hasConversions'
+ ));
+
+ return array($container, $config);
+ }
+
+ /**
+ * @return WidgetConfig[]
+ */
+ public function createEcommerceOverviewPage()
+ {
+ $category = 'Goals_Ecommerce';
+ $subcategory = 'General_Overview';
+ $idGoal = Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_ORDER;
+
+ $widgets = array();
+ $config = $this->factory->createWidget();
+ $config->forceViewDataTable(Evolution::ID);
+ $config->setCategoryId($category);
+ $config->setSubcategoryId($subcategory);
+ $config->setAction('getEvolutionGraph');
+ $config->setOrder(++$this->orderId);
+ $config->setIsNotWidgetizable();
+ $config->setParameters(array('idGoal' => $idGoal));
+ $widgets[] = $config;
+
+ $config = $this->factory->createWidget();
+ $config->setCategoryId($category);
+ $config->forceViewDataTable(Sparklines::ID);
+ $config->setSubcategoryId($subcategory);
+ $config->setName('');
+ $config->setModule('Ecommerce');
+ $config->setAction('getSparklines');
+ $config->setParameters(array('idGoal' => $idGoal));
+ $config->setOrder(++$this->orderId);
+ $config->setIsNotWidgetizable();
+ $widgets[] = $config;
+
+ $config = $this->factory->createWidget();
+ $config->setModule('Ecommerce');
+ $config->setAction('getConversionsOverview');
+ $config->setSubcategoryId($idGoal);
+ $config->setName('Goals_ConversionsOverview');
+ $config->setParameters(array('idGoal' => $idGoal));
+ $config->setOrder(++$this->orderId);
+ $config->setIsNotWidgetizable();
+ $config->setMiddlewareParameters(array(
+ 'module' => 'Goals',
+ 'action' => 'hasConversions',
+ 'idGoal' => $idGoal
+ ));
+
+ $widgets[] = $config;
+
+ $container = $this->createWidgetizableWidgetContainer('EcommerceOverview', $subcategory, $widgets);
+ return array($container);
+ }
+
+ /**
+ * @return WidgetConfig[]
+ */
+ public function createEcommerceSalesPage()
+ {
+ $category = 'Goals_Ecommerce';
+ $subcategory = 'Ecommerce_Sales';
+
+ $config = $this->factory->createContainerWidget('GoalsOrder');
+ $config->setCategoryId($category);
+ $config->setSubcategoryId($subcategory);
+ $config->setName('');
+ $config->setParameters(array('idGoal' => Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_ORDER));
+ $config->setOrder(++$this->orderId);
+ $config->setIsNotWidgetizable();
+ $this->buildGoalByDimensionView(Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_ORDER, $config);
+
+ return array($config);
+ }
+
+ /**
+ * @param array $goal
+ * @return WidgetConfig[]
+ */
+ public function createGoalDetailPage($goal)
+ {
+ $widgets = array();
+
+ $idGoal = (int) $goal['idgoal'];
+ $name = Common::sanitizeInputValue($goal['name']);
+ $params = array('idGoal' => $idGoal);
+
+ $config = $this->factory->createWidget();
+ $config->setSubcategoryId($idGoal);
+ $config->forceViewDataTable(Evolution::ID);
+ $config->setAction('getEvolutionGraph');
+ $config->setParameters($params);
+ $config->setOrder(++$this->orderId);
+ $config->setIsNotWidgetizable();
+ $widgets[] = $config;
+
+ $config = $this->factory->createWidget();
+ $config->setSubcategoryId($idGoal);
+ $config->setName('');
+ $config->forceViewDataTable(Sparklines::ID);
+ $config->setParameters($params);
+ $config->addParameters(array('allow_multiple' => (int) $goal['allow_multiple']));
+ $config->setOrder(++$this->orderId);
+ $config->setIsNotWidgetizable();
+ $config->setIsNotWidgetizable();
+ $widgets[] = $config;
+
+ $config = $this->factory->createWidget();
+ $config->setAction('goalConversionsOverview');
+ $config->setSubcategoryId($idGoal);
+ $config->setName('Goals_ConversionsOverview');
+ $config->setParameters($params);
+ $config->setOrder(++$this->orderId);
+ $config->setIsNotWidgetizable();
+ $config->setMiddlewareParameters(array(
+ 'module' => 'Goals',
+ 'action' => 'hasConversions',
+ 'idGoal' => $idGoal
+ ));
+ $widgets[] = $config;
+
+ $container = $this->createWidgetizableWidgetContainer('Goal_' . $idGoal, $name, $widgets);
+
+ $configs = array($container);
+
+ $config = $this->factory->createContainerWidget('Goals' . $idGoal);
+ $config->setName(Piwik::translate('Goals_GoalConversionsBy', array($name)));
+ $config->setSubcategoryId($idGoal);
+ $config->setParameters(array());
+ $config->setOrder(++$this->orderId);
+ $config->setIsNotWidgetizable();
+ $config->setMiddlewareParameters(array(
+ 'module' => 'Goals',
+ 'action' => 'hasConversions',
+ 'idGoal' => $idGoal
+ ));
+ $this->buildGoalByDimensionView($idGoal, $config);
+
+ $configs[] = $config;
+
+ return $configs;
+ }
+
+ private function createWidgetizableWidgetContainer($containerId, $pageName, $widgets)
+ {
+ /** @var \Piwik\Widget\WidgetConfig[] $widgets */
+ $firstWidget = reset($widgets);
+ /** @var \Piwik\Report\ReportWidgetConfig $firstWidget */
+
+ if (!empty($pageName)) {
+ // make sure to not show two titles (one for this container and one for the first widget)
+ $firstWidget->setName('');
+ }
+
+ $config = $this->factory->createContainerWidget($containerId);
+ $config->setName($pageName);
+ $config->setCategoryId($firstWidget->getCategoryId());
+ $config->setSubcategoryId($firstWidget->getSubcategoryId());
+ $config->setIsWidgetizable();
+ $config->setOrder($this->orderId++);
+
+ foreach ($widgets as $widget) {
+ $config->addWidgetConfig($widget);
+ }
+
+ return $config;
+ }
+
+ private function buildGoalByDimensionView($idGoal, WidgetContainerConfig $container)
+ {
+ $container->setLayout('ByDimension');
+ $ecommerce = ($idGoal == Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_ORDER);
+
+ // for non-Goals reports, we show the goals table
+ $customParams = array('documentationForGoalsPage' => '1');
+
+ if ($idGoal === '') {
+ // if no idGoal, use 0 for overview. Must be string! Otherwise Piwik_View_HtmlTable_Goals fails.
+ $customParams['idGoal'] = '0';
+ } else {
+ $customParams['idGoal'] = $idGoal;
+ }
+
+ $translationHelper = new TranslationHelper();
+
+ foreach ($this->allReports as $category => $reports) {
+ $order = ($this->getSortOrderOfCategory($category) * 100);
+
+ if ($ecommerce) {
+ $categoryText = $translationHelper->translateEcommerceMetricCategory($category);
+ } else {
+ $categoryText = $translationHelper->translateGoalMetricCategory($category);
+ }
+
+ foreach ($reports as $report) {
+ $order++;
+
+ if (empty($report['viewDataTable'])
+ && empty($report['abandonedCarts'])
+ ) {
+ $report['viewDataTable'] = 'tableGoals';
+ }
+
+ if (!empty($report['parameters'])) {
+ $params = array_merge($customParams, $report['parameters']);
+ } else {
+ $params = $customParams;
+ }
+
+ $widget = $this->createWidgetForReport($report['module'], $report['action']);
+ $widget->setParameters($params);
+ $widget->setCategoryId($categoryText);
+ $widget->setSubcategoryId($categoryText);
+ $widget->setOrder($order);
+ $widget->setIsNotWidgetizable();
+
+ if (!empty($report['viewDataTable'])) {
+ $widget->setDefaultViewDataTable($report['viewDataTable']);
+ }
+
+ $container->addWidgetConfig($widget);
+ }
+ }
+ }
+
+ private function getSortOrderOfCategory($category)
+ {
+ static $order = null;
+
+ if (is_null($order)) {
+ $order = array(
+ 'Referrers_Referrers',
+ 'General_Visit',
+ 'General_Visitors',
+ 'VisitsSummary_VisitsSummary',
+ );
+ }
+
+ $value = array_search($category, $order);
+
+ if (false === $value) {
+ $value = count($order) + 1;
+ }
+
+ return $value;
+ }
+
+ private function createWidgetForReport($module, $action)
+ {
+ $report = Reports::factory($module, $action);
+ $factory = new ReportWidgetFactory($report);
+ return $factory->createWidget();
+ }
+
+}
diff --git a/plugins/Goals/Reports/Base.php b/plugins/Goals/Reports/Base.php
index 3db8c4446b..f9e36d6787 100644
--- a/plugins/Goals/Reports/Base.php
+++ b/plugins/Goals/Reports/Base.php
@@ -18,7 +18,7 @@ abstract class Base extends \Piwik\Plugin\Report
protected function init()
{
- $this->category = 'Goals_Goals';
+ $this->categoryId = 'Goals_Goals';
}
protected function addReportMetadataForEachGoal(&$availableReports, $infos, $goalNameFormatter)
diff --git a/plugins/Goals/Reports/Get.php b/plugins/Goals/Reports/Get.php
index bccecda146..d7180547f0 100644
--- a/plugins/Goals/Reports/Get.php
+++ b/plugins/Goals/Reports/Get.php
@@ -8,7 +8,22 @@
*/
namespace Piwik\Plugins\Goals\Reports;
+use Piwik\Common;
+use Piwik\DataTable;
+use Piwik\Metrics\Formatter;
+use Piwik\NumberFormatter;
use Piwik\Piwik;
+use Piwik\Plugin;
+use Piwik\Plugin\ViewDataTable;
+use Piwik\Plugins\CoreVisualizations\Visualizations\JqplotGraph\Evolution;
+use Piwik\Plugins\CoreVisualizations\Visualizations\Sparklines;
+use Piwik\Plugins\Goals\API;
+use Piwik\Plugins\Goals\Goals;
+use Piwik\Plugins\Goals\Pages;
+use Piwik\Report\ReportWidgetFactory;
+use Piwik\Site;
+use Piwik\Tracker\GoalManager;
+use Piwik\Widget\WidgetsList;
class Get extends Base
{
@@ -25,6 +40,122 @@ class Get extends Base
$this->parameters = null;
}
+ public function configureWidgets(WidgetsList $widgetsList, ReportWidgetFactory $factory)
+ {
+ $idSite = $this->getIdSite();
+ $goals = API::getInstance()->getGoals($idSite);
+ $reports = Goals::getReportsWithGoalMetrics();
+
+ $page = new Pages($factory, $reports);
+
+ $widgetsList->addWidgetConfigs($page->createGoalsOverviewPage($goals));
+
+ if ($this->isEcommerceEnabled($idSite)) {
+ $widgetsList->addWidgetConfigs($page->createEcommerceOverviewPage());
+ $widgetsList->addWidgetConfigs($page->createEcommerceSalesPage());
+ }
+
+ foreach ($goals as $goal) {
+ $widgetsList->addWidgetConfigs($page->createGoalDetailPage($goal));
+ }
+ }
+
+ private function getIdSite()
+ {
+ return Common::getRequestVar('idSite', null, 'int');
+ }
+
+ private function isEcommerceEnabled($idSite)
+ {
+ if (!Plugin\Manager::getInstance()->isPluginActivated('Ecommerce')) {
+ return false;
+ }
+
+ $site = new Site($idSite);
+ return $site->isEcommerceEnabled();
+ }
+
+ public function configureView(ViewDataTable $view)
+ {
+ if ($view->isViewDataTableId(Sparklines::ID)) {
+ /** @var Sparklines $view */
+ $idSite = $this->getIdSite();
+ $isEcommerceEnabled = $this->isEcommerceEnabled($idSite);
+
+ $idGoal = Common::getRequestVar('idGoal', 0, 'int');
+
+ $numberFormatter = NumberFormatter::getInstance();
+ $view->config->filters[] = function (DataTable $table) use ($numberFormatter, $idSite) {
+ $firstRow = $table->getFirstRow();
+ if ($firstRow) {
+
+ $revenue = $firstRow->getColumn('revenue');
+ $currencySymbol = Site::getCurrencySymbolFor($idSite);
+ $revenue = $numberFormatter->formatCurrency($revenue, $currencySymbol, GoalManager::REVENUE_PRECISION);
+ $firstRow->setColumn('revenue', $revenue);
+
+ $conversionRate = $firstRow->getColumn('conversion_rate');
+ if (false !== $conversionRate) {
+ $firstRow->setColumn('conversion_rate', $numberFormatter->formatPercent($conversionRate, $precision = 1));
+ }
+
+ $conversions = $firstRow->getColumn('nb_conversions');
+ if (false !== $conversions) {
+ $firstRow->setColumn('nb_conversions', $numberFormatter->formatNumber($conversions));
+ }
+
+ $visitsConverted = $firstRow->getColumn('nb_visits_converted');
+ if (false !== $visitsConverted) {
+ $firstRow->setColumn('nb_visits_converted', $numberFormatter->formatNumber($visitsConverted));
+ }
+ }
+ };
+
+ $view->config->addTranslations(array(
+ 'nb_visits' => Piwik::translate('VisitsSummary_NbVisitsDescription'),
+ 'nb_conversions' => Piwik::translate('Goals_ConversionsDescription'),
+ 'nb_visits_converted' => Piwik::translate('General_NVisits'),
+ 'conversion_rate' => Piwik::translate('Goals_OverallConversionRate'),
+ 'revenue' => Piwik::translate('Goals_OverallRevenue'),
+ ));
+
+ $allowMultiple = Common::getRequestVar('allow_multiple', 0, 'int');
+
+ if ($allowMultiple) {
+ $view->config->addSparklineMetric(array('nb_conversions', 'nb_visits_converted'), $order = 10);
+ } else {
+ $view->config->addSparklineMetric(array('nb_conversions'), $order = 10);
+ }
+
+ $view->config->addSparklineMetric(array('conversion_rate'), $order = 20);
+
+ if (empty($idGoal)) {
+ // goals overview sparklines below evolution graph
+
+ if ($isEcommerceEnabled) {
+ // this would be ideally done in Ecommerce plugin but then it is hard to keep same order
+ $view->config->addSparklineMetric(array('revenue'), $order = 30);
+ }
+
+ } else {
+ $onlySummary = Common::getRequestVar('only_summary', 0, 'int');
+
+ if ($onlySummary) {
+ // in Goals Overview we list an overview for each goal....
+ $view->config->addTranslation('conversion_rate', Piwik::translate('Goals_ConversionRate'));
+
+ } elseif ($isEcommerceEnabled) {
+ // in Goals detail page...
+ $view->config->addSparklineMetric(array('revenue'), $order = 30);
+ }
+ }
+ } else if ($view->isViewDataTableId(Evolution::ID)) {
+ if (empty($view->config->columns_to_display)) {
+ $view->config->columns_to_display = array('nb_conversions');
+ }
+ }
+ }
+
public function configureReportMetadata(&$availableReports, $infos)
{
if (!$this->isEnabled()) {
diff --git a/plugins/Goals/Widgets.php b/plugins/Goals/Widgets.php
deleted file mode 100644
index 94d91bda5c..0000000000
--- a/plugins/Goals/Widgets.php
+++ /dev/null
@@ -1,39 +0,0 @@
-<?php
-/**
- * Piwik - free/libre analytics platform
- *
- * @link http://piwik.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- *
- */
-namespace Piwik\Plugins\Goals;
-
-use Piwik\Common;
-
-class Widgets extends \Piwik\Plugin\Widgets
-{
- protected $category = 'Goals_Goals';
-
- protected function init()
- {
- $this->addWidget('Goals_GoalsOverview', 'widgetGoalsOverview');
-
- $idSite = $this->getIdSite();
- $goals = API::getInstance()->getGoals($idSite);
-
- if (count($goals) > 0) {
- foreach ($goals as $goal) {
- $name = Common::sanitizeInputValue($goal['name']);
- $params = array('idGoal' => $goal['idgoal']);
-
- $this->addWidget($name, 'widgetGoalReport', $params);
- }
- }
- }
-
- private function getIdSite()
- {
- return Common::getRequestVar('idSite', null, 'int');
- }
-
-}
diff --git a/plugins/Goals/Widgets/AddNewGoal.php b/plugins/Goals/Widgets/AddNewGoal.php
new file mode 100644
index 0000000000..b692309b9d
--- /dev/null
+++ b/plugins/Goals/Widgets/AddNewGoal.php
@@ -0,0 +1,38 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\Goals\Widgets;
+
+use Piwik\Common;
+use Piwik\Piwik;
+use Piwik\Plugins\Goals\API;
+use Piwik\Widget\WidgetConfig;
+
+class AddNewGoal extends \Piwik\Widget\Widget
+{
+ public static function configure(WidgetConfig $config)
+ {
+ $idSite = Common::getRequestVar('idSite', null, 'int');
+ $goals = API::getInstance()->getGoals($idSite);
+
+ $config->setCategoryId('Goals_Goals');
+ $config->setSubcategoryId('Goals_AddNewGoal');
+ $config->setParameters(array('idGoal' => ''));
+ $config->setIsNotWidgetizable();
+
+ if (Piwik::isUserHasAdminAccess($idSite)) {
+ $config->setName('Goals_AddNewGoal');
+ } else {
+ $config->setName('Goals_CreateNewGOal');
+ }
+
+ if (count($goals) !== 0) {
+ $config->disable();
+ }
+ }
+}
diff --git a/plugins/Goals/Widgets/EditGoals.php b/plugins/Goals/Widgets/EditGoals.php
new file mode 100644
index 0000000000..d0bb52667c
--- /dev/null
+++ b/plugins/Goals/Widgets/EditGoals.php
@@ -0,0 +1,37 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\Goals\Widgets;
+
+use Piwik\Common;
+use Piwik\Piwik;
+use Piwik\Plugins\Goals\API;
+use Piwik\Widget\WidgetConfig;
+
+class EditGoals extends \Piwik\Widget\Widget
+{
+ public static function configure(WidgetConfig $config)
+ {
+ $idSite = Common::getRequestVar('idSite', null, 'int');
+ $goals = API::getInstance()->getGoals($idSite);
+
+ $config->setCategoryId('Goals_Goals');
+ $config->setSubcategoryId('Goals_ManageGoals');
+ $config->setIsNotWidgetizable();
+
+ if (Piwik::isUserHasAdminAccess($idSite)) {
+ $config->setName('Goals_ManageGoals');
+ } else {
+ $config->setName('Goals_CreateNewGOal');
+ }
+
+ if (count($goals) === 0) {
+ $config->disable();
+ }
+ }
+}
diff --git a/plugins/Goals/lang/en.json b/plugins/Goals/lang/en.json
index dc485c94d8..d5b221a3fc 100644
--- a/plugins/Goals/lang/en.json
+++ b/plugins/Goals/lang/en.json
@@ -36,6 +36,7 @@
"ConversionByTypeReportDocumentation": "This report provides detailed information about the goal performance (conversions, conversion rates and revenue per visit) for each of the categories available in the left panel. %1$s Please click on one of the categories to view the report. %2$s For more information, read the %3$sTracking Goals documentation%4$s",
"ConversionRate": "%s conversion rate",
"Conversions": "%s conversions",
+ "ConversionsDescription": "conversions",
"ConversionsOverview": "Conversions Overview",
"ConversionsOverviewBy": "Conversions overview by type of visit",
"DaysToConv": "Days to Conversion",
@@ -79,8 +80,8 @@
"NoGoalsNeedAccess": "Only an Administrator or a user with Super User access can manage Goals for a given website. Please ask your Piwik administrator to set up a Goal for your website. <br>Tracking Goals is a great way to help understand and maximize your website performance!",
"NeedAccess": "Only an Administrator or a user with Super User access can manage Goals for a given website.",
"Optional": "(optional)",
- "OverallConversionRate": "%s overall conversion rate (visits with a completed goal)",
- "OverallRevenue": "%s overall revenue",
+ "OverallConversionRate": "overall conversion rate (visits with a completed goal)",
+ "OverallRevenue": "overall revenue",
"PageTitle": "Page Title",
"Pattern": "Pattern",
"PluginDescription": "Create Goals and see detailed reports about your goal conversions: evolution over time, revenue per visit, conversions per referrer, per keyword, and more.",
@@ -104,4 +105,4 @@
"WhereVisitedPageManuallyCallsJavascriptTrackerLearnMore": "where the visited page contains a call to the JavaScript 'trackGoal' method (%1$slearn more%2$s)",
"YouCanEnableEcommerceReports": "You can enable %1$s for this website in the %2$s page."
}
-} \ No newline at end of file
+}
diff --git a/plugins/Goals/templates/_titleAndEvolutionGraph.twig b/plugins/Goals/templates/_titleAndEvolutionGraph.twig
deleted file mode 100644
index 59657778a6..0000000000
--- a/plugins/Goals/templates/_titleAndEvolutionGraph.twig
+++ /dev/null
@@ -1,86 +0,0 @@
-<span data-graph-id="{{ nameGraphEvolution }}"></span>
-
-{% if displayFullReport or headline is defined %}
- <h2 piwik-enriched-headline
- {% if idGoal is defined and idGoal and goalName is defined and not ecommerce is defined %}
- edit-url="{{ linkTo({'module': 'Goals', 'action': 'manage', 'idGoal': idGoal})|e('html_attr') }}"
- feature-name="{{ 'Goals_Details'|translate|e('html_attr') }}"
- {% endif %}
- >{% if headline is defined %}{{ headline }}{% elseif goalName is defined %}{{ 'Goals_GoalX'|translate(goalName) }}{% else %}{{ 'General_EvolutionOverPeriod'|translate }}{% endif %}</h2>
-{% endif %}
-{{ graphEvolution|raw }}
-
-<div id='leftcolumn' style="clear:both;{% if not isWidget and ecommerce is defined %}width:33%;'{% endif %}">
- <div class="sparkline">{{ sparkline(urlSparklineConversions) }}
- {% if ecommerce is defined %}
- <strong>{{ nb_conversions|number }}</strong>
- {{ 'General_EcommerceOrders'|translate }}
- <img src='plugins/Morpheus/images/ecommerceOrder.gif'>
- {% else %}
- {{ 'Goals_Conversions'|translate("<strong>"~nb_conversions|number~"</strong>")|raw }}
- {% endif %}
- {% if goalAllowMultipleConversionsPerVisit is defined and goalAllowMultipleConversionsPerVisit %}
- ({{ 'General_NVisits'|translate("<strong>"~nb_visits_converted|number~"</strong>")|raw }})
- {% endif %}
- </div>
- {% if revenue != 0 or ecommerce is defined %}
- <div class="sparkline">
- {{ sparkline(urlSparklineRevenue) }}
- {% set revenue=revenue|money(idSite) %}
- {% if ecommerce is defined %}
- <strong>{{ revenue|raw }}</strong> {{ 'General_TotalRevenue'|translate }}
- {% else %}
- {{ 'Goals_OverallRevenue'|translate("<strong>"~revenue~"</strong>")|raw }}
- {% endif %}
- </div>
- {% endif %}
- {% if ecommerce is defined %}
- <div class="sparkline">{{ sparkline(urlSparklineAverageOrderValue) }}
- <strong>{{ avg_order_revenue|money(idSite)|raw }}</strong>
- {{ 'General_AverageOrderValue'|translate }}
- </div>
- {% endif %}
-
-</div>
-<div id='leftcolumn' {% if not isWidget and ecommerce is defined %}style='width:33%;'{% endif %}>
- <div class="sparkline">{{ sparkline(urlSparklineConversionRate) }}
- {% if ecommerce is defined %}
- {% set ecommerceOrdersText %}{{ 'General_EcommerceOrders'|translate }}{% endset %}
- {{ 'Goals_ConversionRate'|translate("<strong>"~conversion_rate|percent~"</strong> "~ecommerceOrdersText)|raw }}
- {% else %}
- {{ 'Goals_OverallConversionRate'|translate("<strong>"~conversion_rate|percent~"</strong>")|raw }}
- {% endif %}
- </div>
- {% if ecommerce is defined %}
- <div class="sparkline">{{ sparkline(urlSparklinePurchasedProducts) }}
- <strong>{{ items|number }}</strong> {{ 'General_PurchasedProducts'|translate }}</div>
- {% endif %}
-</div>
-{% if ecommerce is defined %}
- <div id='rightcolumn' {% if not isWidget %}style='width:30%;'{% endif %}>
- <div>
- <img src='plugins/Morpheus/images/ecommerceAbandonedCart.gif'> <em>{{ 'General_AbandonedCarts'|translate }}</em>
- </div>
-
- <div class="sparkline">
- {{ sparkline(cart_urlSparklineConversions) }}
- {% set ecommerceAbandonedCartsText %}{{ 'Goals_AbandonedCart'|translate }}{% endset %}
- <strong>{{ cart_nb_conversions|number }}</strong> {{ 'General_VisitsWith'|translate(ecommerceAbandonedCartsText) }}
- </div>
-
- <div class="sparkline">
- {{ sparkline(cart_urlSparklineRevenue) }}
- {% set revenue %}{{ cart_revenue|money(idSite)|raw }}{% endset %}
- {% set revenueText %}{{ 'General_ColumnRevenue'|translate }}{% endset %}
- <strong>{{ revenue }}</strong> {{ 'Goals_LeftInCart'|translate(revenueText) }}
- </div>
-
- <div class="sparkline">
- {{ sparkline(cart_urlSparklineConversionRate) }}
- <strong>{{ cart_conversion_rate|percent }}</strong>
- {{ 'General_VisitsWith'|translate(ecommerceAbandonedCartsText) }}
- </div>
- </div>
-{% endif %}
-{% include "_sparklineFooter.twig" %}
-
diff --git a/plugins/Goals/templates/addNewGoal.twig b/plugins/Goals/templates/addNewGoal.twig
index a2b44b88e9..844892ecbc 100644
--- a/plugins/Goals/templates/addNewGoal.twig
+++ b/plugins/Goals/templates/addNewGoal.twig
@@ -1,5 +1,4 @@
{% if userCanEditGoals %}
- <h2 piwik-enriched-headline>{{ 'Goals_AddNewGoal'|translate }}</h2>
<p>{{ 'Goals_NewGoalIntro'|translate }}</p>
<p>{{ 'Goals_LearnMoreAboutGoalTrackingDocumentation'|translate("<a href='?module=Proxy&action=redirect&url=http://piwik.org/docs/tracking-goals-web-analytics/' target='_blank'>","</a>")|raw }}
{{ 'Goals_ManageGoalsOrCreateANewGoal'|translate("<a href='#module=Goals&action=editGoals'>","</a>")|raw }}
diff --git a/plugins/Goals/templates/conversionOverview.twig b/plugins/Goals/templates/conversionOverview.twig
new file mode 100644
index 0000000000..a810c464aa
--- /dev/null
+++ b/plugins/Goals/templates/conversionOverview.twig
@@ -0,0 +1,19 @@
+<ul class="ulGoalTopElements">
+ {% if topDimensions.country is defined %}
+ <li>{{ 'Goals_BestCountries'|translate }} {% include '@Goals/_listTopDimension.twig' with {'topDimension':topDimensions.country} %}</li>
+ {% endif %}
+ {% if topDimensions.keyword is defined and topDimensions.keyword|length > 0 %}
+ <li>{{ 'Goals_BestKeywords'|translate }} {% include '@Goals/_listTopDimension.twig' with {'topDimension':topDimensions.keyword} %}</li>
+ {% endif %}
+ {% if topDimensions.website is defined and topDimensions.website|length > 0 %}
+ <li>{{ 'Goals_BestReferrers'|translate }} {% include '@Goals/_listTopDimension.twig' with {'topDimension':topDimensions.website} %}</li>
+ {% endif %}
+ <li>
+ {{ 'Goals_ReturningVisitorsConversionRateIs'|translate("<strong>"~conversion_rate_returning~"</strong>")|raw }}
+ , {{ 'Goals_NewVisitorsConversionRateIs'|translate("<strong>"~conversion_rate_new~"</strong>")|raw }}
+ </li>
+</ul>
+<a href="javascript:;" class="segmentedlog" onclick="SegmentedVisitorLog.show('Goals.getMetrics', 'visitConvertedGoalId=={{ idGoal }}', {})">
+ {{ 'Live_RowActionTooltipWithDimension'|translate('General_Goal'|translate) }}
+</a>
+<br style="clear:left"/> \ No newline at end of file
diff --git a/plugins/Goals/templates/editGoals.twig b/plugins/Goals/templates/editGoals.twig
index 76b64b9918..1bc8956511 100644
--- a/plugins/Goals/templates/editGoals.twig
+++ b/plugins/Goals/templates/editGoals.twig
@@ -1,7 +1,5 @@
{% if userCanEditGoals %}
- <h2 piwik-enriched-headline>{{ 'Goals_ManageGoals'|translate }}</h2>
-
{% include "@Goals/_addEditGoal.twig" %}
{% else %}
diff --git a/plugins/Goals/templates/getGoalReportView.twig b/plugins/Goals/templates/getGoalReportView.twig
deleted file mode 100644
index 3d69cb3f5b..0000000000
--- a/plugins/Goals/templates/getGoalReportView.twig
+++ /dev/null
@@ -1,70 +0,0 @@
-<link rel="stylesheet" type="text/css" href="plugins/Goals/stylesheets/goals.css"/>
-{% include "@Goals/_titleAndEvolutionGraph.twig" | raw %}
-
-<div class="clear"></div>
-{% if nb_conversions > 0 %}
- <h2>{{ 'Goals_ConversionsOverview'|translate }}</h2>
- <ul class="ulGoalTopElements">
- {% if ecommerce is not defined %}
- {% if topDimensions.country is defined %}
- <li>{{ 'Goals_BestCountries'|translate }} {% include '@Goals/_listTopDimension.twig' with {'topDimension':topDimensions.country} %}</li>
- {% endif %}
- {% if topDimensions.keyword is defined and topDimensions.keyword|length > 0 %}
- <li>{{ 'Goals_BestKeywords'|translate }} {% include '@Goals/_listTopDimension.twig' with {'topDimension':topDimensions.keyword} %}</li>
- {% endif %}
- {% if topDimensions.website is defined and topDimensions.website|length > 0 %}
- <li>{{ 'Goals_BestReferrers'|translate }} {% include '@Goals/_listTopDimension.twig' with {'topDimension':topDimensions.website} %}</li>
- {% endif %}
- <li>
- {{ 'Goals_ReturningVisitorsConversionRateIs'|translate("<strong>"~conversion_rate_returning~"</strong>")|raw }}
- , {{ 'Goals_NewVisitorsConversionRateIs'|translate("<strong>"~conversion_rate_new~"</strong>")|raw }}
- </li>
- {% else %}
- <li>
- {{ 'General_ColumnRevenue'|translate }}: {{ revenue|money(idSite)|raw -}}
- {% if revenue_subtotal is not empty %},
- {{ 'General_Subtotal'|translate }}: {{ revenue_subtotal|money(idSite)|raw -}}
- {% endif %}
- {%- if revenue_tax is not empty -%},
- {{ 'General_Tax'|translate }}: {{ revenue_tax|money(idSite)|raw -}}
- {% endif %}
- {%- if revenue_shipping is not empty -%},
- {{ 'General_Shipping'|translate }}: {{ revenue_shipping|money(idSite)|raw -}}
- {% endif %}
- {%- if revenue_discount is not empty -%},
- {{ 'General_Discount'|translate }}: {{ revenue_discount|money(idSite)|raw -}}
- {% endif %}
- </li>
- {% endif %}
- </ul>
-
- <a href="javascript:;" class="segmentedlog" onclick="SegmentedVisitorLog.show('Goals.getMetrics', 'visitConvertedGoalId=={{ idGoal }}', {})">
- {{ 'Live_RowActionTooltipWithDimension'|translate('General_Goal'|translate) }}
- </a>
-{% endif %}
-
-<script type="text/javascript">
- $(document).ready(function () {
- $('.goalTopElement').tooltip({
- track: true,
- content: function () {
- return $(this).attr("title");
- },
- show: false,
- hide: false
- });
- });
-</script>
-
-{% if displayFullReport %}
- {% if nb_conversions > 0 or cart_nb_conversions is defined %}
- <h2 id='titleGoalsByDimension'>
- {% if idGoal is defined %}
- {{ 'Goals_GoalConversionsBy'|translate(goalName) }}
- {% else %}
- {{ 'Goals_ConversionsOverviewBy'|translate }}
- {% endif %}
- </h2>
- {{ goalReportsByDimension|raw }}
- {% endif %}
-{% endif %}
diff --git a/plugins/Goals/templates/getOverviewView.twig b/plugins/Goals/templates/getOverviewView.twig
deleted file mode 100644
index ce828a8b54..0000000000
--- a/plugins/Goals/templates/getOverviewView.twig
+++ /dev/null
@@ -1,58 +0,0 @@
-<link rel="stylesheet" type="text/css" href="plugins/Goals/stylesheets/goals.css"/>
-
-{% include "@Goals/_titleAndEvolutionGraph.twig" %}
-{% set sum_nb_conversions=nb_conversions %}
-
-{% for goal in goalMetrics %}
- {% set nb_conversions=goal.nb_conversions %}
- {% set nb_visits_converted=goal.nb_visits_converted %}
- {% set conversion_rate=goal.conversion_rate %}
- {% set name=goal.name %}
- <div class="goalEntry" style="clear:both">
- <h2>
- <a href="javascript:broadcast.propagateAjax('module=Goals&action=goalReport&idGoal={{ goal.id }}')">
- {{ 'Goals_GoalX'|translate("'"~name~"'") }}
- </a>
- </h2>
-
- {% if not isWidget %}
- <div class="row">
- <div class="col-md-6">
- {% endif %}
-
- <div class="sparkline">{{ sparkline(goal.urlSparklineConversions) }}
- {{ 'Goals_Conversions'|translate("<strong>"~nb_conversions|number~"</strong>")|raw }}
- {% if goal.goalAllowMultipleConversionsPerVisit %}
- ({{ 'General_NVisits'|translate("<strong>"~nb_visits_converted|number~"</strong>") | raw }})
- {% endif %}
- </div>
-
- {% if not isWidget %}
- </div>
- <div class="col-md-6">
- {% endif %}
-
- <div class="sparkline">{{ sparkline(goal.urlSparklineConversionRate) }}
- {{ 'Goals_ConversionRate'|translate("<strong>"~conversion_rate|percent~"</strong>")|raw }}
- </div>
-
- {% if not isWidget %}
- </div>
- </div>
- {% endif %}
-
- </div>
-{% endfor %}
-
-{% if displayFullReport %}
- {% if sum_nb_conversions != 0 %}
- <h2 id='titleGoalsByDimension'>
- {% if idGoal is defined %}
- {{ 'Goals_GoalConversionsBy'|translate(goalName) }}
- {% else %}
- {{ 'Goals_ConversionsOverviewBy'|translate }}
- {% endif %}
- </h2>
- {{ goalReportsByDimension|raw }}
- {% endif %}
-{% endif %}
diff --git a/plugins/Insights/Widgets.php b/plugins/Insights/Widgets.php
deleted file mode 100644
index 799662deb5..0000000000
--- a/plugins/Insights/Widgets.php
+++ /dev/null
@@ -1,20 +0,0 @@
-<?php
-/**
- * Piwik - free/libre analytics platform
- *
- * @link http://piwik.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- *
- */
-namespace Piwik\Plugins\Insights;
-
-class Widgets extends \Piwik\Plugin\Widgets
-{
- protected $category = 'Insights_WidgetCategory';
-
- public function init()
- {
- $this->addWidget('Insights_OverviewWidgetTitle', 'getInsightsOverview');
- $this->addWidget('Insights_MoversAndShakersWidgetTitle', 'getOverallMoversAndShakers');
- }
-}
diff --git a/plugins/Insights/Widgets/GetInsightsOverview.php b/plugins/Insights/Widgets/GetInsightsOverview.php
new file mode 100644
index 0000000000..e715865a41
--- /dev/null
+++ b/plugins/Insights/Widgets/GetInsightsOverview.php
@@ -0,0 +1,20 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\Insights\Widgets;
+
+use Piwik\Widget\WidgetConfig;
+
+class GetInsightsOverview extends \Piwik\Widget\Widget
+{
+ public static function configure(WidgetConfig $config)
+ {
+ $config->setCategoryId('Insights_WidgetCategory');
+ $config->setName('Insights_OverviewWidgetTitle');
+ }
+}
diff --git a/plugins/Insights/Widgets/GetOverallMoversAndShakers.php b/plugins/Insights/Widgets/GetOverallMoversAndShakers.php
new file mode 100644
index 0000000000..e175e76519
--- /dev/null
+++ b/plugins/Insights/Widgets/GetOverallMoversAndShakers.php
@@ -0,0 +1,20 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\Insights\Widgets;
+
+use Piwik\Widget\WidgetConfig;
+
+class GetOverallMoversAndShakers extends \Piwik\Widget\Widget
+{
+ public static function configure(WidgetConfig $config)
+ {
+ $config->setCategoryId('Insights_WidgetCategory');
+ $config->setName('Insights_MoversAndShakersWidgetTitle');
+ }
+}
diff --git a/plugins/Installation/templates/layout.twig b/plugins/Installation/templates/layout.twig
index 438ebec820..ba331db0a7 100644
--- a/plugins/Installation/templates/layout.twig
+++ b/plugins/Installation/templates/layout.twig
@@ -27,8 +27,6 @@
<script type="text/javascript" src="plugins/CoreHome/angularjs/piwikApp.js"></script>
<script type="text/javascript" src="plugins/Installation/javascripts/installation.js"></script>
</head>
-<!--[if lt IE 9 ]>
-<body ng-app="app" class="old-ie"> <![endif]-->
<!--[if (gte IE 9)|!(IE)]><!-->
<body ng-app="app"><!--<![endif]-->
diff --git a/plugins/Live/Categories/LiveCategory.php b/plugins/Live/Categories/LiveCategory.php
new file mode 100644
index 0000000000..c3b1a52c91
--- /dev/null
+++ b/plugins/Live/Categories/LiveCategory.php
@@ -0,0 +1,17 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\Live\Categories;
+
+use Piwik\Category\Category;
+
+class LiveCategory extends Category
+{
+ protected $id = 'Live!';
+ protected $order = 2;
+}
diff --git a/plugins/Live/Categories/VisitorLogSubcategory.php b/plugins/Live/Categories/VisitorLogSubcategory.php
new file mode 100644
index 0000000000..2ed65cc4ed
--- /dev/null
+++ b/plugins/Live/Categories/VisitorLogSubcategory.php
@@ -0,0 +1,19 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\Live\Categories;
+
+use Piwik\Category\Subcategory;
+
+class VisitorLogSubcategory extends Subcategory
+{
+ protected $categoryId = 'General_Visitors';
+ protected $id = 'Live_VisitorLog';
+ protected $order = 5;
+
+}
diff --git a/plugins/Live/Reports/Base.php b/plugins/Live/Reports/Base.php
index e64ed55f96..3a9a00945a 100644
--- a/plugins/Live/Reports/Base.php
+++ b/plugins/Live/Reports/Base.php
@@ -12,7 +12,7 @@ abstract class Base extends \Piwik\Plugin\Report
{
protected function init()
{
- $this->category = 'Live!';
+ $this->categoryId = 'Live!';
}
public function configureReportMetadata(&$availableReports, $infos)
diff --git a/plugins/Live/Reports/GetLastVisitsDetails.php b/plugins/Live/Reports/GetLastVisitsDetails.php
index 8cf2268d28..f714989b75 100644
--- a/plugins/Live/Reports/GetLastVisitsDetails.php
+++ b/plugins/Live/Reports/GetLastVisitsDetails.php
@@ -8,10 +8,10 @@
*/
namespace Piwik\Plugins\Live\Reports;
-use Piwik\Menu\MenuReporting;
use Piwik\Plugin\Report;
use Piwik\Plugins\Live\Visualizations\VisitorLog;
-use Piwik\WidgetsList;
+use Piwik\Report\ReportWidgetFactory;
+use Piwik\Widget\WidgetsList;
class GetLastVisitsDetails extends Base
{
@@ -20,8 +20,9 @@ class GetLastVisitsDetails extends Base
protected function init()
{
parent::init();
- $this->widgetTitle = 'Live_VisitorLog';
$this->order = 2;
+ $this->categoryId = 'General_Visitors';
+ $this->subcategoryId = 'Live_VisitorLog';
}
public function getDefaultTypeViewDataTable()
@@ -34,17 +35,14 @@ class GetLastVisitsDetails extends Base
return true;
}
- public function configureReportingMenu(MenuReporting $menu)
+ public function configureWidgets(WidgetsList $widgetsList, ReportWidgetFactory $factory)
{
- if ($this->isEnabled()) {
- $url = array('module' => $this->module, 'action' => 'indexVisitorLog');
- $menu->addVisitorsItem($this->widgetTitle, $url, $order = 5);
- }
- }
-
- public function configureWidget(WidgetsList $widget)
- {
- $widget->add($this->category, $this->widgetTitle, $this->module, 'getVisitorLog', array('small' => 1));
+ $widget = $factory->createWidget()
+ ->forceViewDataTable(VisitorLog::ID)
+ ->setName('Live_VisitorLog')
+ ->setOrder(10)
+ ->setParameters(array('small' => 1));
+ $widgetsList->addWidgetConfig($widget);
}
}
diff --git a/plugins/Live/Reports/GetSimpleLastVisitCount.php b/plugins/Live/Reports/GetSimpleLastVisitCount.php
index 9b0db30769..d2f535ff4e 100644
--- a/plugins/Live/Reports/GetSimpleLastVisitCount.php
+++ b/plugins/Live/Reports/GetSimpleLastVisitCount.php
@@ -14,17 +14,24 @@ use Piwik\Piwik;
use Piwik\Plugin\Report;
use Piwik\Plugins\Live\Controller;
use Piwik\API\Request;
+use Piwik\Report\ReportWidgetFactory;
use Piwik\View;
+use Piwik\Widget\WidgetsList;
class GetSimpleLastVisitCount extends Base
{
protected function init()
{
parent::init();
- $this->widgetTitle = 'Live_RealTimeVisitorCount';
$this->order = 3;
}
+ public function configureWidgets(WidgetsList $widgetsList, ReportWidgetFactory $factory)
+ {
+ $widget = $factory->createWidget()->setName('Live_RealTimeVisitorCount')->setOrder(15);
+ $widgetsList->addWidgetConfig($widget);
+ }
+
public function render()
{
$lastMinutes = Config::getInstance()->General[Controller::SIMPLE_VISIT_COUNT_WIDGET_LAST_MINUTES_CONFIG_KEY];
diff --git a/plugins/Live/Widgets.php b/plugins/Live/Widgets.php
deleted file mode 100644
index c4c96c53e9..0000000000
--- a/plugins/Live/Widgets.php
+++ /dev/null
@@ -1,27 +0,0 @@
-<?php
-/**
- * Piwik - free/libre analytics platform
- *
- * @link http://piwik.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- *
- */
-namespace Piwik\Plugins\Live;
-
-use Piwik\Piwik;
-
-class Widgets extends \Piwik\Plugin\Widgets
-{
- protected $category = 'Live!';
-
- public function init()
- {
- $this->addWidget('Live_VisitorsInRealTime', 'widget');
-
- // the visitor profile uses a segment that is not accessible to the anonymous user, so don't bother showing this widget
- if (!Piwik::isUserIsAnonymous()) {
- $this->addWidget('Live_VisitorProfile', 'getVisitorProfilePopup');
- }
- }
-
-}
diff --git a/plugins/Live/Widgets/GetVisitorProfilePopup.php b/plugins/Live/Widgets/GetVisitorProfilePopup.php
new file mode 100644
index 0000000000..0d01a7abca
--- /dev/null
+++ b/plugins/Live/Widgets/GetVisitorProfilePopup.php
@@ -0,0 +1,33 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\Live\Widgets;
+
+use Piwik\Piwik;
+use Piwik\Widget\WidgetConfig;
+
+class GetVisitorProfilePopup extends \Piwik\Widget\Widget
+{
+
+ public static function configure(WidgetConfig $config)
+ {
+ $config->setCategoryId('General_Visitors');
+ $config->setName('Live_VisitorProfile');
+ $config->setOrder(25);
+
+ if (Piwik::isUserIsAnonymous()) {
+ $config->disable();
+ }
+ }
+
+ public function render()
+ {
+
+ }
+
+}
diff --git a/plugins/Live/Widgets/Widget.php b/plugins/Live/Widgets/Widget.php
new file mode 100644
index 0000000000..e058423b66
--- /dev/null
+++ b/plugins/Live/Widgets/Widget.php
@@ -0,0 +1,21 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\Live\Widgets;
+
+use Piwik\Widget\WidgetConfig;
+
+class Widget extends \Piwik\Widget\Widget
+{
+ public static function configure(WidgetConfig $config)
+ {
+ $config->setCategoryId('Live!');
+ $config->setName('Live_VisitorsInRealTime');
+ $config->setOrder(20);
+ }
+}
diff --git a/plugins/Live/templates/index.twig b/plugins/Live/templates/index.twig
index 3504e5178a..b0a9382b65 100644
--- a/plugins/Live/templates/index.twig
+++ b/plugins/Live/templates/index.twig
@@ -43,7 +43,7 @@
</a>
{% if not disableLink %}
&nbsp;
- <a class="rightLink" href="javascript:broadcast.propagateAjax('module=Live&action=indexVisitorLog')">{{ 'Live_LinkVisitorLog'|translate }}</a>
+ <a class="rightLink" href="#" onclick="this.href=broadcast.buildReportingUrl('category=General_Visitors&subcategory=Live_VisitorLog')">{{ 'Live_LinkVisitorLog'|translate }}</a>
{% endif %}
</div>
{% endspaceless %}
diff --git a/plugins/Login/Controller.php b/plugins/Login/Controller.php
index 1b18bcbef6..707f9a2c9f 100644
--- a/plugins/Login/Controller.php
+++ b/plugins/Login/Controller.php
@@ -30,17 +30,17 @@ class Controller extends \Piwik\Plugin\Controller
/**
* @var PasswordResetter
*/
- private $passwordResetter;
+ protected $passwordResetter;
/**
* @var Auth
*/
- private $auth;
+ protected $auth;
/**
* @var SessionInitializer
*/
- private $sessionInitializer;
+ protected $sessionInitializer;
/**
* Constructor.
@@ -123,7 +123,7 @@ class Controller extends \Piwik\Plugin\Controller
*
* @param View $view
*/
- private function configureView($view)
+ protected function configureView($view)
{
$this->setBasicVariablesView($view);
@@ -285,7 +285,7 @@ class Controller extends \Piwik\Plugin\Controller
* @param QuickForm2 $form
* @return array Error message(s) if an error occurs.
*/
- private function resetPasswordFirstStep($form)
+ protected function resetPasswordFirstStep($form)
{
$loginMail = $form->getSubmitValue('form_login');
$password = $form->getSubmitValue('form_password');
diff --git a/plugins/Login/stylesheets/login.less b/plugins/Login/stylesheets/login.less
index 3941342f31..ae35e24efd 100644
--- a/plugins/Login/stylesheets/login.less
+++ b/plugins/Login/stylesheets/login.less
@@ -182,9 +182,4 @@
#piwik a {
color: #CDCDCD;
}
-
- /* IE < 9 will use this */
- body.old-ie .ie-hide {
- display: none;
- }
}
diff --git a/plugins/Morpheus/Menu.php b/plugins/Morpheus/Menu.php
index 2ba349a302..c2bd081cdf 100644
--- a/plugins/Morpheus/Menu.php
+++ b/plugins/Morpheus/Menu.php
@@ -10,7 +10,6 @@ namespace Piwik\Plugins\Morpheus;
use Piwik\Development;
use Piwik\Menu\MenuAdmin;
-use Piwik\Menu\MenuReporting;
use Piwik\Menu\MenuUser;
use Piwik\Piwik;
@@ -39,14 +38,4 @@ class Menu extends \Piwik\Plugin\Menu
$menu->addPlatformItem('UI Demo', $this->urlForAction('demo'), $order = 15);
}
}
-
- public function configureReportingMenu(MenuReporting $menu)
- {
- $menu->registerMenuIcon('General_Visitors', 'icon-reporting-visitors');
- $menu->registerMenuIcon('General_Actions', 'icon-reporting-actions');
- $menu->registerMenuIcon('Referrers_Referrers', 'icon-reporting-referer');
- $menu->registerMenuIcon('Goals_Goals', 'icon-reporting-goal');
- $menu->registerMenuIcon('Goals_Ecommerce', 'icon-reporting-ecommerce');
- $menu->registerMenuIcon('Dashboard_Dashboard', 'icon-reporting-dashboard');
- }
}
diff --git a/plugins/Morpheus/javascripts/ajaxHelper.js b/plugins/Morpheus/javascripts/ajaxHelper.js
index 8050539192..0f0e60259d 100644
--- a/plugins/Morpheus/javascripts/ajaxHelper.js
+++ b/plugins/Morpheus/javascripts/ajaxHelper.js
@@ -99,6 +99,8 @@ function ajaxHelper() {
*/
this.errorCallback = this.defaultErrorCallback;
+ this.withToken = false;
+
/**
* Callback function to be executed on complete (after error or success)
*/
@@ -171,6 +173,10 @@ function ajaxHelper() {
}
};
+ this.withTokenInUrl = function () {
+ this.withToken = true;
+ };
+
/**
* Sets the base URL to use in the AJAX request.
*
@@ -432,11 +438,19 @@ function ajaxHelper() {
return $.ajax(ajaxCall);
};
+ this._isRequestToApiMethod = function () {
+ return this.getParams && this.getParams['module'] === 'API' && this.getParams['method'];
+ };
+
this._getDefaultPostParams = function () {
- return {
- token_auth: piwik.token_auth
- };
- }
+ if (this.withToken || this._isRequestToApiMethod()) {
+ return {
+ token_auth: piwik.token_auth
+ };
+ }
+
+ return {};
+ };
/**
* Mixin the default parameters to send as POST
diff --git a/plugins/Morpheus/javascripts/piwikHelper.js b/plugins/Morpheus/javascripts/piwikHelper.js
index 22c4c092e7..48c1bb8eba 100644
--- a/plugins/Morpheus/javascripts/piwikHelper.js
+++ b/plugins/Morpheus/javascripts/piwikHelper.js
@@ -109,6 +109,7 @@ var piwikHelper = {
var $element = $(selector);
if (!$element.length) {
+
return;
}
@@ -131,6 +132,17 @@ var piwikHelper = {
},
/**
+ * Detects whether angular is rendering the page. If so, the page will be reloaded automatically
+ * via angular as soon as it detects a $locationChange
+ *
+ * @returns {number|jQuery}
+ */
+ isAngularRenderingThePage: function ()
+ {
+ return $('[piwik-reporting-page]').length;
+ },
+
+ /**
* Displays a Modal dialog. Text will be taken from the DOM node domSelector.
* Given callback handles will be mapped to the buttons having a role attriute
*
@@ -154,9 +166,9 @@ var piwikHelper = {
var button = {text: text};
if(typeof handles[role] == 'function') {
- button.click = function(){$(this).dialog("close"); handles[role].apply()};
+ button.click = function(){ $(this).dialog("close"); handles[role].apply()};
} else {
- button.click = function(){$(this).dialog("close");};
+ button.click = function(){ $(this).dialog("close");};
}
if (title) {
@@ -421,49 +433,6 @@ try {
oldArc.call(this, x, y, r, sAngle, eAngle, clockwise);
};
- //--------------------------------------
- //
- // Array.reduce is not available in IE8 but used in Jqplot
- //
- //--------------------------------------
- if ('function' !== typeof Array.prototype.reduce) {
- Array.prototype.reduce = function(callback, opt_initialValue){
- 'use strict';
- if (null === this || 'undefined' === typeof this) {
- // At the moment all modern browsers, that support strict mode, have
- // native implementation of Array.prototype.reduce. For instance, IE8
- // does not support strict mode, so this check is actually useless.
- throw new TypeError(
- 'Array.prototype.reduce called on null or undefined');
- }
- if ('function' !== typeof callback) {
- throw new TypeError(callback + ' is not a function');
- }
- var index, value,
- length = this.length >>> 0,
- isValueSet = false;
- if (1 < arguments.length) {
- value = opt_initialValue;
- isValueSet = true;
- }
- for (index = 0; length > index; ++index) {
- if (this.hasOwnProperty(index)) {
- if (isValueSet) {
- value = callback(value, this[index], index, this);
- }
- else {
- value = this[index];
- isValueSet = true;
- }
- }
- }
- if (!isValueSet) {
- throw new TypeError('Reduce of empty array with no initial value');
- }
- return value;
- };
- }
-
// Fix jQuery UI dialogs scrolling when click on links with tooltips
jQuery.ui.dialog.prototype._focusTabbable = $.noop;
diff --git a/plugins/Morpheus/stylesheets/base/mixins.less b/plugins/Morpheus/stylesheets/base/mixins.less
index f772e6f2aa..2558a14469 100644
--- a/plugins/Morpheus/stylesheets/base/mixins.less
+++ b/plugins/Morpheus/stylesheets/base/mixins.less
@@ -56,7 +56,4 @@
.opacity(@opacity) {
opacity: @opacity;
- // IE8 filter
- @opacity-ie: (@opacity * 100);
- filter: ~"alpha(opacity=@{opacity-ie})";
} \ No newline at end of file
diff --git a/plugins/Morpheus/stylesheets/general/_utils.less b/plugins/Morpheus/stylesheets/general/_utils.less
index 804012cb21..58a9579eff 100644
--- a/plugins/Morpheus/stylesheets/general/_utils.less
+++ b/plugins/Morpheus/stylesheets/general/_utils.less
@@ -13,11 +13,6 @@ div.clear {
overflow: hidden;
}
-/* IE < 9 will use this */
-body.old-ie .ie-hide {
- display: none;
-}
-
.centerLargeDiv {
width: 850px;
margin: auto;
diff --git a/plugins/Morpheus/stylesheets/main.less b/plugins/Morpheus/stylesheets/main.less
index 85ed5f957c..94e08389f9 100644
--- a/plugins/Morpheus/stylesheets/main.less
+++ b/plugins/Morpheus/stylesheets/main.less
@@ -209,7 +209,7 @@ table.entityTable tr td a:hover {
cursor: pointer;
text-transform: uppercase;
}
- &.sfActive {
+ &.active {
a {
color: @theme-color-menu-contrast-textActive;
}
diff --git a/plugins/Morpheus/stylesheets/ui/_map.less b/plugins/Morpheus/stylesheets/ui/_map.less
index 0446610c2d..731f4e369b 100644
--- a/plugins/Morpheus/stylesheets/ui/_map.less
+++ b/plugins/Morpheus/stylesheets/ui/_map.less
@@ -56,6 +56,10 @@
font-size: 14px;
}
+.uiTest .realTimeMap_datetime {
+ visibility: hidden;
+}
+
.realtime-map[data-name=white-fill] {
color: #f2f2f2 !important;
}
diff --git a/plugins/Morpheus/templates/admin.twig b/plugins/Morpheus/templates/admin.twig
index 143d5a9f07..bb669acf51 100644
--- a/plugins/Morpheus/templates/admin.twig
+++ b/plugins/Morpheus/templates/admin.twig
@@ -26,7 +26,7 @@
{% if showMenu is not defined or showMenu %}
{% import '@CoreHome/_menu.twig' as menu %}
- {{ menu.menu(adminMenu, false, 'Menu--admin') }}
+ {{ menu.menu(adminMenu, false, 'Menu--admin', currentModule, currentAction) }}
{% endif %}
<div class="pageWrap">
diff --git a/plugins/Morpheus/templates/dashboard.twig b/plugins/Morpheus/templates/dashboard.twig
index a1a3ed95e6..8adf020f2c 100644
--- a/plugins/Morpheus/templates/dashboard.twig
+++ b/plugins/Morpheus/templates/dashboard.twig
@@ -32,9 +32,13 @@
<div class="page">
- {% if (menu is defined and menu) %}
- {% import '@CoreHome/_menu.twig' as menuMacro %}
- {{ menuMacro.menu(menu, true, 'Menu--dashboard') }}
+ {% if showMenu is defined and showMenu %}
+ <div id="secondNavBar" class="Menu--dashboard">
+ <div id="search">
+ <div piwik-quick-access class="borderedControl"></div>
+ </div>
+ <div piwik-reporting-menu></div>
+ </div>
{% endif %}
<div class="pageWrap">
@@ -50,6 +54,8 @@
{% include "@CoreHome/_notifications.twig" %}
{% endblock %}
+ <div piwik-popover></div>
+
{% block content %}
{% endblock %}
diff --git a/plugins/Morpheus/templates/layout.twig b/plugins/Morpheus/templates/layout.twig
index fa2f480df5..2229ba2ac7 100644
--- a/plugins/Morpheus/templates/layout.twig
+++ b/plugins/Morpheus/templates/layout.twig
@@ -29,9 +29,6 @@
<![endif]-->
{% endblock %}
</head>
- <!--[if lt IE 9 ]>
- <body id="{{ bodyId|default('') }}" ng-app="app" class="old-ie {{ bodyClass|default('') }}">
- <![endif]-->
<!--[if (gte IE 9)|!(IE)]><!-->
<body id="{{ bodyId|default('') }}" ng-app="app" class="{{ bodyClass|default('') }}">
<!--<![endif]-->
@@ -46,6 +43,8 @@
{% endblock %}
</div>
+ <div piwik-popover-handler></div>
+
{% endblock %}
{% include "@CoreHome/_adblockDetect.twig" %}
diff --git a/plugins/Morpheus/templates/user.twig b/plugins/Morpheus/templates/user.twig
index b343961eae..f1fed83d2e 100644
--- a/plugins/Morpheus/templates/user.twig
+++ b/plugins/Morpheus/templates/user.twig
@@ -28,7 +28,7 @@
{% if showMenu is not defined or showMenu %}
{% import '@CoreHome/_menu.twig' as menu %}
- {{ menu.menu(userMenu, false, 'Menu--admin') }}
+ {{ menu.menu(userMenu, false, 'Menu--admin', currentModule, currentAction) }}
{% endif %}
<div class="pageWrap">
diff --git a/plugins/MultiSites/Categories/MultiSitesCategory.php b/plugins/MultiSites/Categories/MultiSitesCategory.php
new file mode 100644
index 0000000000..0e884d3cfb
--- /dev/null
+++ b/plugins/MultiSites/Categories/MultiSitesCategory.php
@@ -0,0 +1,17 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\MultiSites\Categories;
+
+use Piwik\Category\Category;
+
+class MultiSitesCategory extends Category
+{
+ protected $id = 'General_MultiSitesSummary';
+ protected $order = 3;
+}
diff --git a/plugins/MultiSites/Reports/Base.php b/plugins/MultiSites/Reports/Base.php
index 7b72df674b..fbc85200b3 100644
--- a/plugins/MultiSites/Reports/Base.php
+++ b/plugins/MultiSites/Reports/Base.php
@@ -15,7 +15,7 @@ abstract class Base extends \Piwik\Plugin\Report
{
protected function init()
{
- $this->category = 'General_MultiSitesSummary';
+ $this->categoryId = 'General_MultiSitesSummary';
$allMetricsInfo = API::getApiMetrics($enhanced = true);
diff --git a/plugins/MultiSites/angularjs/dashboard/dashboard-model.service.js b/plugins/MultiSites/angularjs/dashboard/dashboard-model.service.js
index 105ac32304..d90d0f0aec 100644
--- a/plugins/MultiSites/angularjs/dashboard/dashboard-model.service.js
+++ b/plugins/MultiSites/angularjs/dashboard/dashboard-model.service.js
@@ -162,7 +162,7 @@
return piwikApi.fetch(params).then(function (response) {
updateWebsitesList(response);
- }, onError)['finally'](function () {
+ }, onError).finally(function () {
model.isLoading = false;
if (model.refreshInterval && model.refreshInterval > 0) {
diff --git a/plugins/MultiSites/templates/getSitesInfo.twig b/plugins/MultiSites/templates/getSitesInfo.twig
index cca348dfec..94d13ee702 100644
--- a/plugins/MultiSites/templates/getSitesInfo.twig
+++ b/plugins/MultiSites/templates/getSitesInfo.twig
@@ -2,10 +2,8 @@
{% block topcontrols %}
{% if not isWidgetized %}
- <div class="top_controls">
- {% include "@CoreHome/_periodSelect.twig" %}
- {% include "@CoreHome/_headerMessage.twig" %}
- </div>
+ {% include "@CoreHome/_periodSelect.twig" %}
+ {% include "@CoreHome/_headerMessage.twig" %}
{% endif %}
{% endblock %}
diff --git a/plugins/Overlay/client/client.js b/plugins/Overlay/client/client.js
index f37b9a0cd3..5fd99c466b 100644
--- a/plugins/Overlay/client/client.js
+++ b/plugins/Overlay/client/client.js
@@ -54,10 +54,7 @@ var Piwik_Overlay_Client = (function () {
src: piwikRoot + 'index.php?module=Overlay&action=notifyParentIframe#' + window.location.href
}).css({width: 0, height: 0, border: 0});
- // in some cases, calling append right away doesn't work in IE8
- $(document).ready(function () {
- $('body').append(iframe);
- });
+ $('body').append(iframe);
}
}
@@ -84,50 +81,6 @@ var Piwik_Overlay_Client = (function () {
return el;
}
- /** Special treatment for some internet explorers */
- var ieStatusBarEventsBound = false;
-
- function handleIEStatusBar() {
- if (navigator.appVersion.indexOf("MSIE 7.") == -1
- && navigator.appVersion.indexOf("MSIE 8.") == -1) {
- // this is not IE8 or lower
- return;
- }
-
- // IE7/8 can't handle position:fixed so we need to do it by hand
- statusBar.css({
- position: 'absolute',
- right: 'auto',
- bottom: 'auto',
- left: 0,
- top: 0
- });
-
- var position = function () {
- var scrollY = document.body.parentElement.scrollTop;
- var scrollX = document.body.parentElement.scrollLeft;
- statusBar.css({
- top: (scrollY + $(window).height() - statusBar.outerHeight()) + 'px',
- left: (scrollX + $(window).width() - statusBar.outerWidth()) + 'px'
- });
- };
-
- position();
-
- statusBar.css({width: 'auto'});
- if (statusBar.width() < 350) {
- statusBar.width(350);
- } else {
- statusBar.width(statusBar.width());
- }
-
- if (!ieStatusBarEventsBound) {
- ieStatusBarEventsBound = true;
- $(window).resize(position);
- $(window).scroll(position);
- }
- }
-
return {
/** Initialize in-site analytics */
@@ -230,15 +183,10 @@ var Piwik_Overlay_Client = (function () {
statusBar.show().append(item);
- handleIEStatusBar();
- window.setTimeout(handleIEStatusBar, 100);
-
return function () {
item.remove();
if (statusBar.children().size() == 0) {
statusBar.hide();
- } else {
- handleIEStatusBar();
}
};
},
@@ -248,8 +196,6 @@ var Piwik_Overlay_Client = (function () {
statusBar.find('.PIS_' + className).remove();
if (statusBar.children().size() == 0) {
statusBar.hide();
- } else {
- handleIEStatusBar();
}
},
diff --git a/plugins/PiwikPro/Widgets/PromoPiwikPro.php b/plugins/PiwikPro/Widgets/PromoPiwikPro.php
new file mode 100644
index 0000000000..a9203d417f
--- /dev/null
+++ b/plugins/PiwikPro/Widgets/PromoPiwikPro.php
@@ -0,0 +1,55 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\PiwikPro\Widgets;
+
+use Piwik\Container\StaticContainer;
+use Piwik\Piwik;
+use Piwik\PiwikPro\Advertising;
+use Piwik\Plugins\PiwikPro\Promo;
+use Piwik\View;
+use Piwik\Widget\WidgetConfig;
+
+class PromoPiwikPro extends \Piwik\Widget\Widget
+{
+ /**
+ * @var Advertising
+ */
+ private $advertising;
+
+ /**
+ * @var Promo
+ */
+ private $promo;
+
+ public function __construct(Advertising $advertising, Promo $promo)
+ {
+ $this->advertising = $advertising;
+ $this->promo = $promo;
+ }
+
+ public static function configure(WidgetConfig $config)
+ {
+ $config->setCategoryId('About Piwik');
+ $config->setName('PiwikPro_WidgetPiwikProAd');
+ $config->setIsEnabled(StaticContainer::get('Piwik\PiwikPro\Advertising')->arePiwikProAdsEnabled());
+ }
+
+ public function render()
+ {
+ $view = new View('@PiwikPro/promoPiwikProWidget');
+
+ $promo = $this->promo->getContent();
+
+ $view->ctaLinkUrl = $this->advertising->getPromoUrlForOnPremises('PromoWidget', $promo['campaignContent']);
+ $view->ctaText = $promo['text'];
+ $view->ctaLinkTitle = $this->promo->getLinkTitle();
+
+ return $view->render();
+ }
+}
diff --git a/plugins/PiwikPro/Widgets/RssPiwikPro.php b/plugins/PiwikPro/Widgets/RssPiwikPro.php
new file mode 100644
index 0000000000..26e87f92be
--- /dev/null
+++ b/plugins/PiwikPro/Widgets/RssPiwikPro.php
@@ -0,0 +1,49 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\PiwikPro\Widgets;
+
+use Piwik\Container\StaticContainer;
+use Piwik\Piwik;
+use Piwik\Widget\WidgetConfig;
+use Piwik\Plugins\ExampleRssWidget\RssRenderer;
+
+class RssPiwikPro extends \Piwik\Widget\Widget
+{
+ public static function configure(WidgetConfig $config)
+ {
+ $config->setCategoryId('About Piwik');
+ $config->setName('PiwikPro_WidgetBlogTitle');
+ $config->setIsEnabled(StaticContainer::get('Piwik\PiwikPro\Advertising')->arePiwikProAdsEnabled());
+ }
+
+ public function render()
+ {
+ try {
+ $rss = new RssRenderer('https://piwik.pro/feed/');
+ $rss->showDescription(true);
+
+ return $rss->get();
+
+ } catch (\Exception $e) {
+
+ return $this->error($e);
+ }
+ }
+
+ /**
+ * @param \Exception $e
+ * @return string
+ */
+ private function error($e)
+ {
+ return '<div class="pk-emptyDataTable">'
+ . Piwik::translate('General_ErrorRequest', array('', ''))
+ . ' - ' . $e->getMessage() . '</div>';
+ }
+}
diff --git a/plugins/PrivacyManager/javascripts/privacySettings.js b/plugins/PrivacyManager/javascripts/privacySettings.js
index 92d0437636..b50ed40563 100644
--- a/plugins/PrivacyManager/javascripts/privacySettings.js
+++ b/plugins/PrivacyManager/javascripts/privacySettings.js
@@ -178,6 +178,7 @@ $(document).ready(function () {
module: 'PrivacyManager',
action: 'executeDataPurge'
}, 'get');
+ ajaxRequest.withTokenInUrl();
ajaxRequest.setCallback(
function () {
// force reload
diff --git a/plugins/Provider/Reports/GetProvider.php b/plugins/Provider/Reports/GetProvider.php
index e7cfcfa753..adf03cd26f 100644
--- a/plugins/Provider/Reports/GetProvider.php
+++ b/plugins/Provider/Reports/GetProvider.php
@@ -13,17 +13,26 @@ use Piwik\Piwik;
use Piwik\Plugin\Report;
use Piwik\Plugin\ViewDataTable;
use Piwik\Plugins\Provider\Columns\Provider;
+use Piwik\Report\ReportWidgetFactory;
+use Piwik\Widget\WidgetsList;
class GetProvider extends Report
{
protected function init()
{
- $this->category = 'General_Visitors';
+ $this->categoryId = 'General_Visitors';
$this->dimension = new Provider();
$this->name = Piwik::translate('Provider_ColumnProvider');
$this->documentation = Piwik::translate('Provider_ProviderReportDocumentation', '<br />');
$this->order = 50;
- $this->widgetTitle = 'Provider_WidgetProviders';
+
+ $this->subcategoryId = 'UserCountry_SubmenuLocations';
+ }
+
+ public function configureWidgets(WidgetsList $widgetsList, ReportWidgetFactory $factory)
+ {
+ $widget = $factory->createWidget()->setName('Provider_WidgetProviders');
+ $widgetsList->addWidgetConfig($widget);
}
public function configureView(ViewDataTable $view)
diff --git a/plugins/Referrers/Categories/AllReferrersSubcategory.php b/plugins/Referrers/Categories/AllReferrersSubcategory.php
new file mode 100644
index 0000000000..277fc762dd
--- /dev/null
+++ b/plugins/Referrers/Categories/AllReferrersSubcategory.php
@@ -0,0 +1,19 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\Referrers\Categories;
+
+use Piwik\Category\Subcategory;
+
+class AllReferrersSubcategory extends Subcategory
+{
+ protected $categoryId = 'Referrers_Referrers';
+ protected $id = 'Referrers_WidgetGetAll';
+ protected $order = 5;
+
+}
diff --git a/plugins/Referrers/Categories/CampaignsSubcategory.php b/plugins/Referrers/Categories/CampaignsSubcategory.php
new file mode 100644
index 0000000000..5878a0a9e2
--- /dev/null
+++ b/plugins/Referrers/Categories/CampaignsSubcategory.php
@@ -0,0 +1,19 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\Referrers\Categories;
+
+use Piwik\Category\Subcategory;
+
+class CampaignsSubcategory extends Subcategory
+{
+ protected $categoryId = 'Referrers_Referrers';
+ protected $id = 'Referrers_Campaigns';
+ protected $order = 20;
+
+}
diff --git a/plugins/Referrers/Categories/ReferrersCategory.php b/plugins/Referrers/Categories/ReferrersCategory.php
new file mode 100644
index 0000000000..bde0c76699
--- /dev/null
+++ b/plugins/Referrers/Categories/ReferrersCategory.php
@@ -0,0 +1,18 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\Referrers\Categories;
+
+use Piwik\Category\Category;
+
+class ReferrersCategory extends Category
+{
+ protected $id = 'Referrers_Referrers';
+ protected $order = 15;
+ protected $icon = 'icon-reporting-referer';
+}
diff --git a/plugins/Referrers/Categories/ReferrersOverviewSubcategory.php b/plugins/Referrers/Categories/ReferrersOverviewSubcategory.php
new file mode 100644
index 0000000000..9cd6dafbdc
--- /dev/null
+++ b/plugins/Referrers/Categories/ReferrersOverviewSubcategory.php
@@ -0,0 +1,19 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\Referrers\Categories;
+
+use Piwik\Category\Subcategory;
+
+class ReferrersOverviewSubcategory extends Subcategory
+{
+ protected $categoryId = 'Referrers_Referrers';
+ protected $id = 'General_Overview';
+ protected $order = 2;
+
+}
diff --git a/plugins/Referrers/Categories/SearchEnginesSubcategory.php b/plugins/Referrers/Categories/SearchEnginesSubcategory.php
new file mode 100644
index 0000000000..c8bfc478e6
--- /dev/null
+++ b/plugins/Referrers/Categories/SearchEnginesSubcategory.php
@@ -0,0 +1,19 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\Referrers\Categories;
+
+use Piwik\Category\Subcategory;
+
+class SearchEnginesSubcategory extends Subcategory
+{
+ protected $categoryId = 'Referrers_Referrers';
+ protected $id = 'Referrers_SubmenuSearchEngines';
+ protected $order = 10;
+
+}
diff --git a/plugins/Referrers/Categories/WebsitesSubcategory.php b/plugins/Referrers/Categories/WebsitesSubcategory.php
new file mode 100644
index 0000000000..8b045bd5d4
--- /dev/null
+++ b/plugins/Referrers/Categories/WebsitesSubcategory.php
@@ -0,0 +1,19 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\Referrers\Categories;
+
+use Piwik\Category\Subcategory;
+
+class WebsitesSubcategory extends Subcategory
+{
+ protected $categoryId = 'Referrers_Referrers';
+ protected $id = 'Referrers_SubmenuWebsites';
+ protected $order = 15;
+
+}
diff --git a/plugins/Referrers/Controller.php b/plugins/Referrers/Controller.php
index c628af7a83..1b258f4c6a 100644
--- a/plugins/Referrers/Controller.php
+++ b/plugins/Referrers/Controller.php
@@ -10,10 +10,14 @@ namespace Piwik\Plugins\Referrers;
use Piwik\API\Request;
use Piwik\Common;
+use Piwik\DataTable\Filter\CalculateEvolutionFilter;
use Piwik\DataTable\Map;
use Piwik\Metrics;
+use Piwik\NumberFormatter;
use Piwik\Period\Range;
use Piwik\Piwik;
+use Piwik\Plugins\CoreVisualizations\Visualizations\Sparklines;
+use Piwik\ViewDataTable;
use Piwik\SettingsPiwik;
use Piwik\Translation\Translator;
use Piwik\View;
@@ -35,34 +39,23 @@ class Controller extends \Piwik\Plugin\Controller
parent::__construct();
}
- public function index()
+ public function getSparklines()
{
- $view = new View('@Referrers/index');
-
- $view->graphEvolutionReferrers = $this->getEvolutionGraph(Common::REFERRER_TYPE_DIRECT_ENTRY, array(), array('nb_visits'));
- $view->nameGraphEvolutionReferrers = 'Referrers.getEvolutionGraph';
+ $metrics = $this->getReferrersVisitorsByType();
+ $distinctMetrics = $this->getDistinctReferrersMetrics();
- $nameValues = $this->getReferrersVisitorsByType();
+ $numberFormatter = NumberFormatter::getInstance();
- $totalVisits = array_sum($nameValues);
- foreach ($nameValues as $name => $value) {
- $view->$name = $value;
+ $totalVisits = array_sum($metrics);
+ foreach ($metrics as $name => $value) {
// calculate percent of total, if there were any visits
- if ($value != 0
- && $totalVisits != 0
- ) {
+ if ($value != 0 && $totalVisits != 0) {
$percentName = $name . 'Percent';
- $view->$percentName = round(($value / $totalVisits) * 100, 0);
+ $metrics[$percentName] = round(($value / $totalVisits) * 100, 0);
}
}
- // set distinct metrics
- $distinctMetrics = $this->getDistinctReferrersMetrics();
- foreach ($distinctMetrics as $name => $value) {
- $view->$name = $value;
- }
-
// calculate evolution for visit metrics & distinct metrics
list($lastPeriodDate, $ignore) = Range::getLastDate();
if ($lastPeriodDate !== false) {
@@ -74,71 +67,124 @@ class Controller extends \Piwik\Plugin\Controller
// visit metrics
$previousValues = $this->getReferrersVisitorsByType($lastPeriodDate);
- $this->addEvolutionPropertiesToView($view, $prettyDate, $nameValues, $prettyLastPeriodDate, $previousValues);
+ $metrics = $this->addEvolutionPropertiesToView($prettyDate, $metrics, $prettyLastPeriodDate, $previousValues);
// distinct metrics
$previousValues = $this->getDistinctReferrersMetrics($lastPeriodDate);
- $this->addEvolutionPropertiesToView($view, $prettyDate, $distinctMetrics, $prettyLastPeriodDate, $previousValues);
+ $distinctMetrics = $this->addEvolutionPropertiesToView($prettyDate, $distinctMetrics, $prettyLastPeriodDate, $previousValues);
}
- // sparkline for the historical data of the above values
- $view->urlSparklineSearchEngines = $this->getReferrerUrlSparkline(Common::REFERRER_TYPE_SEARCH_ENGINE);
- $view->urlSparklineDirectEntry = $this->getReferrerUrlSparkline(Common::REFERRER_TYPE_DIRECT_ENTRY);
- $view->urlSparklineWebsites = $this->getReferrerUrlSparkline(Common::REFERRER_TYPE_WEBSITE);
- $view->urlSparklineCampaigns = $this->getReferrerUrlSparkline(Common::REFERRER_TYPE_CAMPAIGN);
- // sparklines for the evolution of the distinct keywords count/websites count/ etc
- $view->urlSparklineDistinctSearchEngines = $this->getUrlSparkline('getLastDistinctSearchEnginesGraph');
- $view->urlSparklineDistinctKeywords = $this->getUrlSparkline('getLastDistinctKeywordsGraph');
- $view->urlSparklineDistinctWebsites = $this->getUrlSparkline('getLastDistinctWebsitesGraph');
- $view->urlSparklineDistinctCampaigns = $this->getUrlSparkline('getLastDistinctCampaignsGraph');
+ /** @var Sparklines $view */
+ $view = ViewDataTable\Factory::build(Sparklines::ID, $api = false, $controller = false, $force = true, $loadUserParams = false);
- return $view->render();
- }
+ // DIRECT ENTRY
+ $metrics['visitorsFromDirectEntry'] = $numberFormatter->formatNumber($metrics['visitorsFromDirectEntry']);
+ $values = array($metrics['visitorsFromDirectEntry']);
+ $descriptions = array(Piwik::translate('Referrers_TypeDirectEntries'));
- public function allReferrers()
- {
- $view = new View('@Referrers/allReferrers');
+ if (!empty($metrics['visitorsFromDirectEntryPercent'])) {
+ $metrics['visitorsFromDirectEntryPercent'] = $numberFormatter->formatPercent($metrics['visitorsFromDirectEntryPercent'], $precision = 1);
+ $values[] = $metrics['visitorsFromDirectEntryPercent'];
+ $descriptions[] = Piwik::translate('Referrers_XPercentOfVisits');
+ }
- // building the referrers summary report
- $view->dataTableReferrerType = $this->renderReport('getReferrerType');
+ $directEntryParams = $this->getReferrerSparklineParams(Common::REFERRER_TYPE_DIRECT_ENTRY);
- $nameValues = $this->getReferrersVisitorsByType();
+ $view->config->addSparkline($directEntryParams, $values, $descriptions, @$metrics['visitorsFromDirectEntryEvolution']);
- $totalVisits = array_sum($nameValues);
- foreach ($nameValues as $name => $value) {
- $view->$name = $value;
- // calculate percent of total, if there were any visits
- if ($value != 0
- && $totalVisits != 0
- ) {
- $percentName = $name . 'Percent';
- $view->$percentName = round(($value / $totalVisits) * 100, 0);
- }
+ // WEBSITES
+ $metrics['visitorsFromWebsites'] = $numberFormatter->formatNumber($metrics['visitorsFromWebsites']);
+ $values = array($metrics['visitorsFromWebsites']);
+ $descriptions = array(Piwik::translate('Referrers_TypeWebsites'));
+
+ if (!empty($metrics['visitorsFromWebsitesPercent'])) {
+ $metrics['visitorsFromWebsitesPercent'] = $numberFormatter->formatPercent($metrics['visitorsFromWebsitesPercent'], $precision = 1);
+ $values[] = $metrics['visitorsFromWebsitesPercent'];
+ $descriptions[] = Piwik::translate('Referrers_XPercentOfVisits');
}
- $view->totalVisits = $totalVisits;
- $view->referrersReportsByDimension = $this->renderReport('getAll');
+ $searchEngineParams = $this->getReferrerSparklineParams(Common::REFERRER_TYPE_WEBSITE);
- return $view->render();
- }
+ $view->config->addSparkline($searchEngineParams, $values, $descriptions, @$metrics['visitorsFromWebsitesEvolution']);
+
+
+ // SEARCH ENGINES
+ $metrics['visitorsFromSearchEngines'] = $numberFormatter->formatNumber($metrics['visitorsFromSearchEngines']);
+ $values = array($metrics['visitorsFromSearchEngines']);
+ $descriptions = array(Piwik::translate('Referrers_TypeSearchEngines'));
+
+ if (!empty($metrics['visitorsFromSearchEnginesPercent'])) {
+ $metrics['visitorsFromSearchEnginesPercent'] = $numberFormatter->formatPercent($metrics['visitorsFromSearchEnginesPercent'], $precision = 1);
+ $values[] = $metrics['visitorsFromSearchEnginesPercent'];
+ $descriptions[] = Piwik::translate('Referrers_XPercentOfVisits');
+ }
+ $searchEngineParams = $this->getReferrerSparklineParams(Common::REFERRER_TYPE_SEARCH_ENGINE);
+
+ $view->config->addSparkline($searchEngineParams, $values, $descriptions, @$metrics['visitorsFromSearchEnginesEvolution']);
+
+
+ // CAMPAIGNS
+ $metrics['visitorsFromCampaigns'] = $numberFormatter->formatNumber($metrics['visitorsFromCampaigns']);
+ $values = array($metrics['visitorsFromCampaigns']);
+ $descriptions = array(Piwik::translate('Referrers_TypeCampaigns'));
+
+ if (!empty($metrics['visitorsFromCampaignsPercent'])) {
+ $metrics['visitorsFromCampaignsPercent'] = $numberFormatter->formatPercent($metrics['visitorsFromCampaignsPercent'], $precision = 1);
+ $values[] = $metrics['visitorsFromCampaignsPercent'];
+ $descriptions[] = Piwik::translate('Referrers_XPercentOfVisits');
+ }
+
+ $searchEngineParams = $this->getReferrerSparklineParams(Common::REFERRER_TYPE_CAMPAIGN);
+
+ $view->config->addSparkline($searchEngineParams, $values, $descriptions, @$metrics['visitorsFromCampaignsEvolution']);
+
+
+ // DISTINCT SEARCH ENGINES
+ $sparklineParams = $this->getDistinctSparklineUrlParams('getLastDistinctSearchEnginesGraph');
+ $value = $distinctMetrics['numberDistinctSearchEngines'];
+ $value = $numberFormatter->formatNumber($value);
+ $description = Piwik::translate('Referrers_DistinctSearchEngines');
+
+ $view->config->addSparkline($sparklineParams, $value, $description, @$distinctMetrics['numberDistinctSearchEnginesEvolution']);
+
+
+ // DISTINCT WEBSITES
+ $sparklineParams = $this->getDistinctSparklineUrlParams('getLastDistinctWebsitesGraph');
+
+ $distinctMetrics['numberDistinctWebsites'] = $numberFormatter->formatNumber($distinctMetrics['numberDistinctWebsites']);
+ $distinctMetrics['numberDistinctWebsitesUrls'] = $numberFormatter->formatNumber($distinctMetrics['numberDistinctWebsitesUrls']);
+
+ $values = array($distinctMetrics['numberDistinctWebsites'], $distinctMetrics['numberDistinctWebsitesUrls']);
+ $descriptions = array(Piwik::translate('Referrers_DistinctWebsites'), Piwik::translate('Referrers_UsingNDistinctUrls'));
+
+ $view->config->addSparkline($sparklineParams, $values, $descriptions, @$distinctMetrics['numberDistinctWebsitesEvolution']);
+
+
+ // DISTINCT KEYWORDS
+ $sparklineParams = $this->getDistinctSparklineUrlParams('getLastDistinctKeywordsGraph');
+ $value = $distinctMetrics['numberDistinctKeywords'];
+ $value = $numberFormatter->formatNumber($value);
+ $description = Piwik::translate('Referrers_DistinctKeywords');
+
+ $view->config->addSparkline($sparklineParams, $value, $description, @$distinctMetrics['numberDistinctKeywordsEvolution']);
+
+
+ // DISTINCT CAMPAIGNS
+ $sparklineParams = $this->getDistinctSparklineUrlParams('getLastDistinctCampaignsGraph');
+ $value = $distinctMetrics['numberDistinctCampaigns'];
+ $value = $numberFormatter->formatNumber($value);
+ $description = Piwik::translate('Referrers_DistinctCampaigns');
+
+ $view->config->addSparkline($sparklineParams, $value, $description, @$distinctMetrics['numberDistinctCampaignsEvolution']);
- public function getSearchEnginesAndKeywords()
- {
- $view = new View('@Referrers/getSearchEnginesAndKeywords');
- $view->searchEngines = $this->renderReport('getSearchEngines');
- $view->keywords = $this->renderReport('getKeywords');
return $view->render();
}
- public function indexWebsites()
+ private function getDistinctSparklineUrlParams($action)
{
- $view = new View('@Referrers/indexWebsites');
- $view->websites = $this->renderReport('getWebsites');
- $view->socials = $this->renderReport('getSocials');
-
- return $view->render();
+ return array('module' => $this->pluginName, 'action' => $action);
}
protected function getReferrersVisitorsByType($date = false)
@@ -221,7 +267,7 @@ class Controller extends \Piwik\Plugin\Controller
} else {
// use $typeReferrer as default
if ($typeReferrer === false) {
- $typeReferrer = Common::getRequestVar('typeReferrer', false);
+ $typeReferrer = Common::getRequestVar('typeReferrer', Common::REFERRER_TYPE_DIRECT_ENTRY);
}
$label = self::getTranslatedReferrerTypeLabel($typeReferrer);
$total = $this->translator->translate('General_Total');
@@ -416,14 +462,16 @@ function DisplayTopKeywords($url = "")
* @param int $referrerType The referrer type. Referrer types are defined in Common class.
* @return string The URL that can be used to get a sparkline image.
*/
- private function getReferrerUrlSparkline($referrerType)
+ private function getReferrerSparklineParams($referrerType)
{
$totalRow = $this->translator->translate('General_Total');
- return $this->getUrlSparkline(
- 'getEvolutionGraph',
- array('columns' => array('nb_visits'),
- 'rows' => array(self::getTranslatedReferrerTypeLabel($referrerType), $totalRow),
- 'typeReferrer' => $referrerType)
+
+ return array(
+ 'columns' => array('nb_visits'),
+ 'rows' => array(self::getTranslatedReferrerTypeLabel($referrerType), $totalRow),
+ 'typeReferrer' => $referrerType,
+ 'module' => $this->pluginName,
+ 'action' => 'getReferrerType'
);
}
@@ -456,20 +504,35 @@ function DisplayTopKeywords($url = "")
* Utility method that calculates evolution values for a set of current & past values
* and sets properties on a View w/ HTML that displays the evolution percents.
*
- * @param View $view The view to set properties on.
* @param string $date The date of the current values.
* @param array $currentValues Array mapping view property names w/ present values.
* @param string $lastPeriodDate The date of the period in the past.
* @param array $previousValues Array mapping view property names w/ past values. Keys
* in this array should be the same as keys in $currentValues.
+ * @return array Added current values
*/
- private function addEvolutionPropertiesToView($view, $date, $currentValues, $lastPeriodDate, $previousValues)
+ private function addEvolutionPropertiesToView($date, $currentValues, $lastPeriodDate, $previousValues)
{
foreach ($previousValues as $name => $pastValue) {
$currentValue = $currentValues[$name];
$evolutionName = $name . 'Evolution';
- $view->$evolutionName = $this->getEvolutionHtml($date, $currentValue, $lastPeriodDate, $pastValue);
+ $currentValueFormatted = NumberFormatter::getInstance()->format($currentValue);
+ $pastValueFormatted = NumberFormatter::getInstance()->format($pastValue);
+
+ $currentValues[$evolutionName] = array(
+ 'currentValue' => $currentValue,
+ 'pastValue' => $pastValue,
+ 'tooltip' => Piwik::translate('General_EvolutionSummaryGeneric', array(
+ Piwik::translate('General_NVisits', $currentValueFormatted),
+ $date,
+ Piwik::translate('General_NVisits', $pastValueFormatted),
+ $lastPeriodDate,
+ CalculateEvolutionFilter::calculate($currentValue, $pastValue, $precision = 1)
+ ))
+ );
}
+
+ return $currentValues;
}
}
diff --git a/plugins/Referrers/Menu.php b/plugins/Referrers/Menu.php
deleted file mode 100644
index 1088cb738e..0000000000
--- a/plugins/Referrers/Menu.php
+++ /dev/null
@@ -1,23 +0,0 @@
-<?php
-/**
- * Piwik - free/libre analytics platform
- *
- * @link http://piwik.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- *
- */
-namespace Piwik\Plugins\Referrers;
-
-use Piwik\Menu\MenuReporting;
-
-class Menu extends \Piwik\Plugin\Menu
-{
- public function configureReportingMenu(MenuReporting $menu)
- {
- $menu->addReferrersItem('', array(), 20);
- $menu->addReferrersItem('General_Overview', $this->urlForAction('index'), 1);
- $menu->addReferrersItem('Referrers_WidgetGetAll', $this->urlForAction('allReferrers'), 2);
- $menu->addReferrersItem('Referrers_SubmenuSearchEngines', $this->urlForAction('getSearchEnginesAndKeywords'), 3);
- $menu->addReferrersItem('Referrers_SubmenuWebsites', $this->urlForAction('indexWebsites'), 4);
- }
-}
diff --git a/plugins/Referrers/Reports/Base.php b/plugins/Referrers/Reports/Base.php
index e4a6394c00..2bd240d191 100644
--- a/plugins/Referrers/Reports/Base.php
+++ b/plugins/Referrers/Reports/Base.php
@@ -12,7 +12,7 @@ abstract class Base extends \Piwik\Plugin\Report
{
protected function init()
{
- $this->category = 'Referrers_Referrers';
+ $this->categoryId = 'Referrers_Referrers';
}
}
diff --git a/plugins/Referrers/Reports/GetAll.php b/plugins/Referrers/Reports/GetAll.php
index 2079dd414d..cb5f17ee41 100644
--- a/plugins/Referrers/Reports/GetAll.php
+++ b/plugins/Referrers/Reports/GetAll.php
@@ -13,6 +13,8 @@ use Piwik\Plugin\ViewDataTable;
use Piwik\Plugins\CoreVisualizations\Visualizations\HtmlTable;
use Piwik\Plugins\Referrers\Columns\Referrer;
use Piwik\Plugins\Referrers\Referrers;
+use Piwik\Report\ReportWidgetFactory;
+use Piwik\Widget\WidgetsList;
class GetAll extends Base
{
@@ -23,7 +25,15 @@ class GetAll extends Base
$this->name = Piwik::translate('Referrers_WidgetGetAll');
$this->documentation = Piwik::translate('Referrers_AllReferrersReportDocumentation', '<br />');
$this->order = 2;
- $this->widgetTitle = 'Referrers_WidgetGetAll';
+
+ $this->subcategoryId = 'Referrers_WidgetGetAll';
+ }
+
+ public function configureWidgets(WidgetsList $widgetsList, ReportWidgetFactory $factory)
+ {
+ $widgetsList->addWidgetConfig(
+ $factory->createWidget()->setName('Referrers_Referrers')
+ );
}
public function getDefaultTypeViewDataTable()
diff --git a/plugins/Referrers/Reports/GetCampaigns.php b/plugins/Referrers/Reports/GetCampaigns.php
index a09affa70c..1d375423d8 100644
--- a/plugins/Referrers/Reports/GetCampaigns.php
+++ b/plugins/Referrers/Reports/GetCampaigns.php
@@ -24,8 +24,8 @@ class GetCampaigns extends Base
$this->actionToLoadSubTables = 'getKeywordsFromCampaignId';
$this->hasGoalMetrics = true;
$this->order = 9;
- $this->widgetTitle = 'Referrers_Campaigns';
- $this->menuTitle = 'Referrers_Campaigns';
+
+ $this->subcategoryId = 'Referrers_Campaigns';
}
public function configureView(ViewDataTable $view)
diff --git a/plugins/Referrers/Reports/GetKeywords.php b/plugins/Referrers/Reports/GetKeywords.php
index be8e8d3f4c..3239fefde0 100644
--- a/plugins/Referrers/Reports/GetKeywords.php
+++ b/plugins/Referrers/Reports/GetKeywords.php
@@ -11,7 +11,9 @@ namespace Piwik\Plugins\Referrers\Reports;
use Piwik\Piwik;
use Piwik\Plugin\ViewDataTable;
use Piwik\Plugins\CoreVisualizations\Visualizations\HtmlTable;
+use Piwik\Plugins\CoreVisualizations\Visualizations\JqplotGraph\Evolution;
use Piwik\Plugins\Referrers\Columns\Keyword;
+use Piwik\Tracker\Visit;
class GetKeywords extends Base
{
@@ -24,7 +26,7 @@ class GetKeywords extends Base
$this->actionToLoadSubTables = 'getSearchEnginesFromKeywordId';
$this->hasGoalMetrics = true;
$this->order = 3;
- $this->widgetTitle = 'Referrers_Keywords';
+ $this->subcategoryId = 'Referrers_SubmenuSearchEngines';
}
public function configureView(ViewDataTable $view)
diff --git a/plugins/Referrers/Reports/GetReferrerType.php b/plugins/Referrers/Reports/GetReferrerType.php
index f5656bfa7f..c09f8c6d17 100644
--- a/plugins/Referrers/Reports/GetReferrerType.php
+++ b/plugins/Referrers/Reports/GetReferrerType.php
@@ -12,7 +12,11 @@ use Piwik\Common;
use Piwik\Piwik;
use Piwik\Plugin\ViewDataTable;
use Piwik\Plugins\CoreVisualizations\Visualizations\HtmlTable;
+use Piwik\Plugins\CoreVisualizations\Visualizations\JqplotGraph\Evolution;
+use Piwik\Plugins\CoreVisualizations\Visualizations\Sparklines;
use Piwik\Plugins\Referrers\Columns\ReferrerType;
+use Piwik\Widget\WidgetsList;
+use Piwik\Report\ReportWidgetFactory;
class GetReferrerType extends Base
{
@@ -32,7 +36,7 @@ class GetReferrerType extends Base
$this->constantRowsCount = true;
$this->hasGoalMetrics = true;
$this->order = 1;
- $this->widgetTitle = 'General_Overview';
+ $this->subcategoryId = 'Referrers_WidgetGetAll';
}
public function getDefaultTypeViewDataTable()
@@ -40,6 +44,36 @@ class GetReferrerType extends Base
return HtmlTable\AllColumns::ID;
}
+ public function configureWidgets(WidgetsList $widgetsList, ReportWidgetFactory $factory)
+ {
+ $widgetsList->addWidgetConfig(
+ $factory->createWidget()
+ ->setName('Referrers_ReferrerTypes')
+ ->setSubcategoryId('Referrers_WidgetGetAll')
+ );
+
+ $widgetsList->addWidgetConfig(
+ $factory->createWidget()
+ ->setName('General_EvolutionOverPeriod')
+ ->setSubcategoryId('General_Overview')
+ ->setAction('getEvolutionGraph')
+ ->setIsNotWidgetizable()
+ ->forceViewDataTable(Evolution::ID)
+ ->addParameters(array(
+ 'columns' => $defaultColumns = array('nb_visits'),
+ ))
+ );
+
+ $widgetsList->addWidgetConfig(
+ $factory->createCustomWidget('getSparklines')
+ ->forceViewDataTable(Sparklines::ID)
+ ->setIsNotWidgetizable()
+ ->setName('Referrers_Type')
+ ->setSubcategoryId('General_Overview')
+ ->setOrder(10)
+ );
+ }
+
public function configureView(ViewDataTable $view)
{
$idSubtable = Common::getRequestVar('idSubtable', false);
diff --git a/plugins/Referrers/Reports/GetSearchEngines.php b/plugins/Referrers/Reports/GetSearchEngines.php
index 3b66cd0784..0a17cd132e 100644
--- a/plugins/Referrers/Reports/GetSearchEngines.php
+++ b/plugins/Referrers/Reports/GetSearchEngines.php
@@ -24,7 +24,8 @@ class GetSearchEngines extends Base
$this->actionToLoadSubTables = 'getKeywordsFromSearchEngineId';
$this->hasGoalMetrics = true;
$this->order = 7;
- $this->widgetTitle = 'Referrers_SearchEngines';
+
+ $this->subcategoryId = 'Referrers_SubmenuSearchEngines';
}
public function configureView(ViewDataTable $view)
diff --git a/plugins/Referrers/Reports/GetSocials.php b/plugins/Referrers/Reports/GetSocials.php
index b49fac623a..7429ddd48f 100644
--- a/plugins/Referrers/Reports/GetSocials.php
+++ b/plugins/Referrers/Reports/GetSocials.php
@@ -14,6 +14,8 @@ use Piwik\Plugin\ViewDataTable;
use Piwik\Plugins\CoreVisualizations\Visualizations\HtmlTable;
use Piwik\Plugins\CoreVisualizations\Visualizations\JqplotGraph\Pie;
use Piwik\Plugins\Referrers\Columns\SocialNetwork;
+use Piwik\Report\ReportWidgetFactory;
+use Piwik\Widget\WidgetsList;
class GetSocials extends Base
{
@@ -25,7 +27,14 @@ class GetSocials extends Base
$this->documentation = Piwik::translate('Referrers_WebsitesReportDocumentation', '<br />');
$this->actionToLoadSubTables = 'getUrlsForSocial';
$this->order = 11;
- $this->widgetTitle = 'Referrers_WidgetSocials';
+
+ $this->subcategoryId = 'Referrers_SubmenuWebsites';
+ }
+
+ public function configureWidgets(WidgetsList $widgetsList, ReportWidgetFactory $factory)
+ {
+ $widget = $factory->createWidget()->setName('Referrers_Socials');
+ $widgetsList->addWidgetConfig($widget);
}
public function getDefaultTypeViewDataTable()
diff --git a/plugins/Referrers/Reports/GetWebsites.php b/plugins/Referrers/Reports/GetWebsites.php
index 18f9336a63..f5be3ca375 100644
--- a/plugins/Referrers/Reports/GetWebsites.php
+++ b/plugins/Referrers/Reports/GetWebsites.php
@@ -12,6 +12,8 @@ use Piwik\Piwik;
use Piwik\Plugin\ViewDataTable;
use Piwik\Plugins\CoreVisualizations\Visualizations\HtmlTable;
use Piwik\Plugins\Referrers\Columns\Website;
+use Piwik\Report\ReportWidgetFactory;
+use Piwik\Widget\WidgetsList;
class GetWebsites extends Base
{
@@ -25,7 +27,8 @@ class GetWebsites extends Base
$this->actionToLoadSubTables = 'getUrlsFromWebsiteId';
$this->hasGoalMetrics = true;
$this->order = 5;
- $this->widgetTitle = 'Referrers_WidgetExternalWebsites';
+
+ $this->subcategoryId = 'Referrers_SubmenuWebsites';
}
public function configureView(ViewDataTable $view)
diff --git a/plugins/Referrers/Widgets.php b/plugins/Referrers/Widgets.php
deleted file mode 100644
index 4e23c9f746..0000000000
--- a/plugins/Referrers/Widgets.php
+++ /dev/null
@@ -1,24 +0,0 @@
-<?php
-/**
- * Piwik - free/libre analytics platform
- *
- * @link http://piwik.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- *
- */
-namespace Piwik\Plugins\Referrers;
-
-use Piwik\SettingsPiwik;
-
-class Widgets extends \Piwik\Plugin\Widgets
-{
- protected $category = 'SEO';
-
- public function init()
- {
- if (SettingsPiwik::isSegmentationEnabled()) {
- $this->addWidget('Referrers_WidgetTopKeywordsForPages', 'getKeywordsForPage');
- }
- }
-
-}
diff --git a/plugins/Referrers/Widgets/GetKeywordsForPage.php b/plugins/Referrers/Widgets/GetKeywordsForPage.php
new file mode 100644
index 0000000000..165bb18f68
--- /dev/null
+++ b/plugins/Referrers/Widgets/GetKeywordsForPage.php
@@ -0,0 +1,23 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\Referrers\Widgets;
+
+use Piwik\Widget\WidgetConfig;
+use Piwik\SettingsPiwik;
+
+class GetKeywordsForPage extends \Piwik\Widget\Widget
+{
+ public static function configure(WidgetConfig $config)
+ {
+ $config->setCategoryId('SEO');
+ $config->setName('Referrers_WidgetTopKeywordsForPages');
+ $config->setIsEnabled(SettingsPiwik::isSegmentationEnabled());
+ }
+
+}
diff --git a/plugins/Referrers/templates/allReferrers.twig b/plugins/Referrers/templates/allReferrers.twig
deleted file mode 100644
index bf8c7c431c..0000000000
--- a/plugins/Referrers/templates/allReferrers.twig
+++ /dev/null
@@ -1,11 +0,0 @@
-<h2 piwik-enriched-headline>{{ 'Referrers_ReferrerTypes'|translate }}</h2>
-{{ dataTableReferrerType|raw }}
-
-<div style="clear:both;"></div>
-
-{% if totalVisits > 0 %}
- <h2 piwik-enriched-headline>{{ 'Referrers_Referrers'|translate }}</h2>
- {{ referrersReportsByDimension|raw }}
-{% endif %}
-
-{% include "_sparklineFooter.twig" %}
diff --git a/plugins/Referrers/templates/getSearchEnginesAndKeywords.twig b/plugins/Referrers/templates/getSearchEnginesAndKeywords.twig
deleted file mode 100644
index 29b2b3f0af..0000000000
--- a/plugins/Referrers/templates/getSearchEnginesAndKeywords.twig
+++ /dev/null
@@ -1,13 +0,0 @@
-<div class="row">
-
- <div class="col-md-6">
- <h2 piwik-enriched-headline>{{ 'Referrers_Keywords'|translate }}</h2>
- {{ keywords|raw }}
- </div>
-
- <div class="col-md-6">
- <h2 piwik-enriched-headline>{{ 'Referrers_SearchEngines'|translate }}</h2>
- {{ searchEngines|raw }}
- </div>
-
-</div>
diff --git a/plugins/Referrers/templates/index.twig b/plugins/Referrers/templates/index.twig
deleted file mode 100644
index 74851c3b37..0000000000
--- a/plugins/Referrers/templates/index.twig
+++ /dev/null
@@ -1,89 +0,0 @@
-<h2 piwik-enriched-headline
- data-graph-id="{{ nameGraphEvolutionReferrers }}">{{ 'General_EvolutionOverPeriod'|translate }}</h2>
-{{ graphEvolutionReferrers|raw }}
-
-<h2 piwik-enriched-headline>{{ 'Referrers_Type'|translate }}</h2>
-
-<div class="row">
- <div class="col-md-6">
- <div class="sparkline" style="padding-left: 12px;">{{ sparkline(urlSparklineDirectEntry) }}
- {{ 'Referrers_TypeDirectEntries'|translate("<strong>"~visitorsFromDirectEntry|number~"</strong>")|raw }}
- {% if visitorsFromDirectEntryPercent|default is not empty %},
- {{ 'Referrers_XPercentOfVisits'|translate("<strong>"~visitorsFromDirectEntryPercent|percent~"</strong>")|raw }}
- {% endif %}
- {% if visitorsFromDirectEntryEvolution|default is not empty %}
- {{ visitorsFromDirectEntryEvolution|raw }}
- {% endif %}
- </div>
- <div class="sparkline" style="padding-left: 12px;">{{ sparkline(urlSparklineSearchEngines) }}
- {{ 'Referrers_TypeSearchEngines'|translate("<strong>"~visitorsFromSearchEngines|number~"</strong>")|raw }}
- {% if visitorsFromSearchEnginesPercent|default is not empty %},
- {{ 'Referrers_XPercentOfVisits'|translate("<strong>"~visitorsFromSearchEnginesPercent|percent~"</strong>")|raw }}
- {% endif %}
- {% if visitorsFromSearchEnginesEvolution|default is not empty %}
- {{ visitorsFromSearchEnginesEvolution|raw }}
- {% endif %}
- </div>
- </div>
- <div class="col-md-6">
- <div class="sparkline">{{ sparkline(urlSparklineWebsites) }}
- {{ 'Referrers_TypeWebsites'|translate("<strong>"~visitorsFromWebsites|number~"</strong>")|raw }}
- {% if visitorsFromWebsitesPercent|default is not empty %},
- {{ 'Referrers_XPercentOfVisits'|translate("<strong>"~visitorsFromWebsitesPercent|percent~"</strong>")|raw }}
- {% endif %}
- {% if visitorsFromWebsitesEvolution|default is not empty %}
- {{ visitorsFromWebsitesEvolution|raw }}
- {% endif %}
- </div>
- <div class="sparkline">{{ sparkline(urlSparklineCampaigns) }}
- {{ 'Referrers_TypeCampaigns'|translate("<strong>"~visitorsFromCampaigns|number~"</strong>")|raw }}
- {% if visitorsFromCampaignsPercent|default is not empty %},
- {{ 'Referrers_XPercentOfVisits'|translate("<strong>"~visitorsFromCampaignsPercent|percent~"</strong>")|raw }}
- {% endif %}
- {% if visitorsFromCampaignsEvolution|default is not empty %}
- {{ visitorsFromCampaignsEvolution|raw }}
- {% endif %}
- </div>
- </div>
-</div>
-
-<div id="distinctReferrersByType" class="row">
- <div class="col-md-6">
- <div class="sparkline" style="padding-left: 12px;">{{ sparkline(urlSparklineDistinctSearchEngines) }}
- <strong>{{ numberDistinctSearchEngines|number }}</strong> {{ 'Referrers_DistinctSearchEngines'|translate }}
- {% if numberDistinctSearchEnginesEvolution|default is not empty %}
- {{ numberDistinctSearchEnginesEvolution|raw }}
- {% endif %}
- </div>
- <div class="sparkline" style="padding-left: 12px;">{{ sparkline(urlSparklineDistinctKeywords) }}
- <strong>{{ numberDistinctKeywords|number }}</strong> {{ 'Referrers_DistinctKeywords'|translate }}
- {% if numberDistinctKeywordsEvolution|default is not empty %}
- {{ numberDistinctKeywordsEvolution|raw }}
- {% endif %}
- </div>
- </div>
- <div class="col-md-6">
- <div class="sparkline">{{ sparkline(urlSparklineDistinctWebsites) }}
- <strong>{{ numberDistinctWebsites|number }}</strong> {{ 'Referrers_DistinctWebsites'|translate }}
- {{ 'Referrers_UsingNDistinctUrls'|translate("<strong>"~numberDistinctWebsitesUrls|number~"</strong>")|raw }}
- {% if numberDistinctWebsitesEvolution|default is not empty %}
- {{ numberDistinctWebsitesEvolution|raw }}
- {% endif %}
- </div>
- <div class="sparkline">{{ sparkline(urlSparklineDistinctCampaigns) }}
- <strong>{{ numberDistinctCampaigns|number }}</strong> {{ 'Referrers_DistinctCampaigns'|translate }}
- {% if numberDistinctCampaignsEvolution|default is not empty %}
- {{ numberDistinctCampaignsEvolution|raw }}
- {% endif %}
- </div>
- </div>
- <br/>
-</div>
-
-<div style="float:left;" class="relatedReferrerReports">{{ 'General_View'|translate }}
- <a href="javascript:broadcast.propagateAjax('module=Referrers&action=getSearchEnginesAndKeywords')">{{ 'Referrers_SubmenuSearchEngines'|translate }}</a>,
- <a href="javascript:broadcast.propagateAjax('module=Referrers&action=indexWebsites')">{{ 'Referrers_SubmenuWebsites'|translate }}</a>,
- <a href="javascript:broadcast.propagateAjax('module=Referrers&action=indexCampaigns')">{{ 'Referrers_Campaigns'|translate }}</a>.
-</div>
-
-{% include "_sparklineFooter.twig" %}
diff --git a/plugins/Referrers/templates/indexWebsites.twig b/plugins/Referrers/templates/indexWebsites.twig
deleted file mode 100644
index cdfa6efe01..0000000000
--- a/plugins/Referrers/templates/indexWebsites.twig
+++ /dev/null
@@ -1,13 +0,0 @@
-<div class="row">
-
- <div class="col-md-6">
- <h2 piwik-enriched-headline>{{ 'Referrers_Websites'|translate }}</h2>
- {{ websites|raw }}
- </div>
-
- <div class="col-md-6">
- <h2 piwik-enriched-headline>{{ 'Referrers_Socials'|translate }}</h2>
- {{ socials|raw }}
- </div>
-
-</div>
diff --git a/plugins/Referrers/tests/System/expected/test_Referrers_getReferrerType__API.getProcessedReport_day.xml b/plugins/Referrers/tests/System/expected/test_Referrers_getReferrerType__API.getProcessedReport_day.xml
index 52de949c82..52262c275a 100644
--- a/plugins/Referrers/tests/System/expected/test_Referrers_getReferrerType__API.getProcessedReport_day.xml
+++ b/plugins/Referrers/tests/System/expected/test_Referrers_getReferrerType__API.getProcessedReport_day.xml
@@ -4,6 +4,7 @@
<prettyDate>January 1 &#x2013; March 10, 2010</prettyDate>
<metadata>
<category>Referrers</category>
+ <subcategory>All Referrers</subcategory>
<name>Referrer Type</name>
<module>Referrers</module>
<action>getReferrerType</action>
diff --git a/plugins/Resolution/Reports/Base.php b/plugins/Resolution/Reports/Base.php
index 259a164113..0ef3f0d631 100644
--- a/plugins/Resolution/Reports/Base.php
+++ b/plugins/Resolution/Reports/Base.php
@@ -15,7 +15,7 @@ abstract class Base extends \Piwik\Plugin\Report
{
protected function init()
{
- $this->category = 'General_VisitorSettings';
+ $this->categoryId = 'General_Visitors';
}
protected function getBasicResolutionDisplayProperties(ViewDataTable $view)
diff --git a/plugins/Resolution/Reports/GetConfiguration.php b/plugins/Resolution/Reports/GetConfiguration.php
index c01c4f3b07..600f07edd9 100644
--- a/plugins/Resolution/Reports/GetConfiguration.php
+++ b/plugins/Resolution/Reports/GetConfiguration.php
@@ -11,6 +11,7 @@ namespace Piwik\Plugins\Resolution\Reports;
use Piwik\Piwik;
use Piwik\Plugin\ViewDataTable;
use Piwik\Plugins\Resolution\Columns\Configuration;
+use Piwik\Plugin\Reports;
class GetConfiguration extends Base
{
@@ -18,10 +19,11 @@ class GetConfiguration extends Base
{
parent::init();
$this->dimension = new Configuration();
- $this->name = Piwik::translate('Resolution_WidgetGlobalVisitors');
+ $this->name = Piwik::translate('Resolution_Configurations');
$this->documentation = Piwik::translate('Resolution_WidgetGlobalVisitorsDocumentation', '<br />');
$this->order = 7;
- $this->widgetTitle = 'Resolution_WidgetGlobalVisitors';
+
+ $this->subcategoryId = 'DevicesDetection_Software';
}
public function configureView(ViewDataTable $view)
@@ -36,7 +38,7 @@ class GetConfiguration extends Base
public function getRelatedReports()
{
return array(
- self::factory('Resolution', 'getResolution'),
+ Reports::factory('Resolution', 'getResolution'),
);
}
}
diff --git a/plugins/Resolution/Reports/GetResolution.php b/plugins/Resolution/Reports/GetResolution.php
index f9066ce19c..3b27236a86 100644
--- a/plugins/Resolution/Reports/GetResolution.php
+++ b/plugins/Resolution/Reports/GetResolution.php
@@ -11,6 +11,7 @@ namespace Piwik\Plugins\Resolution\Reports;
use Piwik\Piwik;
use Piwik\Plugin\ViewDataTable;
use Piwik\Plugins\Resolution\Columns\Resolution;
+use Piwik\Plugin\Reports;
class GetResolution extends Base
{
@@ -20,8 +21,9 @@ class GetResolution extends Base
$this->dimension = new Resolution();
$this->name = Piwik::translate('Resolution_WidgetResolutions');
$this->documentation = ''; // TODO
- $this->order = 0;
- $this->widgetTitle = 'Resolution_WidgetResolutions';
+ $this->order = 8;
+
+ $this->subcategoryId = 'DevicesDetection_Devices';
}
public function configureView(ViewDataTable $view)
@@ -34,7 +36,7 @@ class GetResolution extends Base
public function getRelatedReports()
{
return array(
- self::factory('Resolution', 'getConfiguration'),
+ Reports::factory('Resolution', 'getConfiguration'),
);
}
}
diff --git a/plugins/Resolution/tests/System/expected/test_UserSettingsBCTestUserSettings_UserSettings.getConfiguration___API.getMetadata_day.xml b/plugins/Resolution/tests/System/expected/test_UserSettingsBCTestUserSettings_UserSettings.getConfiguration___API.getMetadata_day.xml
index 01fee59915..991d2dbc51 100644
--- a/plugins/Resolution/tests/System/expected/test_UserSettingsBCTestUserSettings_UserSettings.getConfiguration___API.getMetadata_day.xml
+++ b/plugins/Resolution/tests/System/expected/test_UserSettingsBCTestUserSettings_UserSettings.getConfiguration___API.getMetadata_day.xml
@@ -1,8 +1,9 @@
<?xml version="1.0" encoding="utf-8" ?>
<result>
<row>
- <category>Visitor Settings</category>
- <name>Visitor Configuration</name>
+ <category>Visitors</category>
+ <subcategory>Software</subcategory>
+ <name>Configurations</name>
<module>Resolution</module>
<action>getConfiguration</action>
<dimension>Configuration</dimension>
@@ -29,6 +30,13 @@
<bounce_rate>Bounce Rate</bounce_rate>
<conversion_rate>Conversion Rate</conversion_rate>
</processedMetrics>
+ <relatedReports>
+ <row>
+ <name>Screen Resolution</name>
+ <module>Resolution</module>
+ <action>getResolution</action>
+ </row>
+ </relatedReports>
<imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Resolution&amp;apiAction=getConfiguration&amp;period=day&amp;date=2010-03-06</imageGraphUrl>
<imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Resolution&amp;apiAction=getConfiguration&amp;period=day&amp;date=2010-02-05,2010-03-06</imageGraphEvolutionUrl>
<uniqueId>Resolution_getConfiguration</uniqueId>
diff --git a/plugins/Resolution/tests/System/expected/test_UserSettingsBCTestUserSettings_UserSettings.getResolution___API.getMetadata_day.xml b/plugins/Resolution/tests/System/expected/test_UserSettingsBCTestUserSettings_UserSettings.getResolution___API.getMetadata_day.xml
index b99815c557..c0f6929125 100644
--- a/plugins/Resolution/tests/System/expected/test_UserSettingsBCTestUserSettings_UserSettings.getResolution___API.getMetadata_day.xml
+++ b/plugins/Resolution/tests/System/expected/test_UserSettingsBCTestUserSettings_UserSettings.getResolution___API.getMetadata_day.xml
@@ -1,7 +1,8 @@
<?xml version="1.0" encoding="utf-8" ?>
<result>
<row>
- <category>Visitor Settings</category>
+ <category>Visitors</category>
+ <subcategory>Devices</subcategory>
<name>Screen Resolution</name>
<module>Resolution</module>
<action>getResolution</action>
@@ -28,6 +29,13 @@
<bounce_rate>Bounce Rate</bounce_rate>
<conversion_rate>Conversion Rate</conversion_rate>
</processedMetrics>
+ <relatedReports>
+ <row>
+ <name>Configurations</name>
+ <module>Resolution</module>
+ <action>getConfiguration</action>
+ </row>
+ </relatedReports>
<imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Resolution&amp;apiAction=getResolution&amp;period=day&amp;date=2010-03-06</imageGraphUrl>
<imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Resolution&amp;apiAction=getResolution&amp;period=day&amp;date=2010-02-05,2010-03-06</imageGraphEvolutionUrl>
<uniqueId>Resolution_getResolution</uniqueId>
diff --git a/plugins/SEO/Widgets.php b/plugins/SEO/Widgets/GetRank.php
index 1f06c2ec8b..521bf1859c 100644
--- a/plugins/SEO/Widgets.php
+++ b/plugins/SEO/Widgets/GetRank.php
@@ -6,25 +6,26 @@
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
*/
-namespace Piwik\Plugins\SEO;
+namespace Piwik\Plugins\SEO\Widgets;
use Piwik\Common;
use Piwik\DataTable\Renderer;
+use Piwik\Widget\WidgetConfig;
use Piwik\Site;
use Piwik\Url;
use Piwik\UrlHelper;
use Piwik\View;
+use Piwik\Plugins\SEO\API;
-class Widgets extends \Piwik\Plugin\Widgets
+class GetRank extends \Piwik\Widget\Widget
{
- protected $category = 'SEO';
-
- public function init()
+ public static function configure(WidgetConfig $config)
{
- $this->addWidget('SEO_SeoRankings', 'getRank');
+ $config->setCategoryId('SEO');
+ $config->setName('SEO_SeoRankings');
}
- public function getRank()
+ public function render()
{
$idSite = Common::getRequestVar('idSite');
$site = new Site($idSite);
diff --git a/plugins/ScheduledReports/ScheduledReports.php b/plugins/ScheduledReports/ScheduledReports.php
index c66a6ad0d6..f306dd8d05 100644
--- a/plugins/ScheduledReports/ScheduledReports.php
+++ b/plugins/ScheduledReports/ScheduledReports.php
@@ -191,6 +191,9 @@ class ScheduledReports extends \Piwik\Plugin
$filteredReportMetadata = array();
foreach ($availableReportMetadata as $reportMetadata) {
// removing reports from the API category and MultiSites.getOne
+ if (empty($reportMetadata['category'])) {
+ var_dump($reportMetadata);exit;
+ }
if (
$reportMetadata['category'] == 'API' ||
$reportMetadata['category'] == Piwik::translate('General_MultiSitesSummary') && $reportMetadata['name'] == Piwik::translate('General_SingleWebsitesDashboard')
diff --git a/plugins/SitesManager/angularjs/sites-manager/sites-manager-admin-sites-model.js b/plugins/SitesManager/angularjs/sites-manager/sites-manager-admin-sites-model.js
index ddfb3e53e3..628de72e73 100644
--- a/plugins/SitesManager/angularjs/sites-manager/sites-manager-admin-sites-model.js
+++ b/plugins/SitesManager/angularjs/sites-manager/sites-manager-admin-sites-model.js
@@ -102,7 +102,7 @@
setSites(sites);
- }, onError)['finally'](function () {
+ }, onError).finally(function () {
if (callback) {
callback();
}
diff --git a/plugins/SitesManager/angularjs/sites-manager/sites-manager.controller.js b/plugins/SitesManager/angularjs/sites-manager/sites-manager.controller.js
index 100e75bbf7..b5d7ec0213 100644
--- a/plugins/SitesManager/angularjs/sites-manager/sites-manager.controller.js
+++ b/plugins/SitesManager/angularjs/sites-manager/sites-manager.controller.js
@@ -243,7 +243,7 @@
searchKeywordParameters: $scope.globalSettings.searchKeywordParametersGlobal.join(','),
searchCategoryParameters: $scope.globalSettings.searchCategoryParametersGlobal.join(',')
}, 'POST');
-
+ ajaxHandler.withTokenInUrl();
ajaxHandler.redirectOnSuccess($scope.redirectParams);
ajaxHandler.setLoadingElement();
ajaxHandler.send(true);
diff --git a/plugins/TestRunner/Commands/TestsRun.php b/plugins/TestRunner/Commands/TestsRun.php
index 08e456da19..8a12c07e3b 100644
--- a/plugins/TestRunner/Commands/TestsRun.php
+++ b/plugins/TestRunner/Commands/TestsRun.php
@@ -47,10 +47,6 @@ class TestsRun extends ConsoleCommand
// bin is the composer executeable directory, where all vendors (should) place their executables
$command = PIWIK_VENDOR_PATH . '/bin/phpunit';
- if (version_compare(PHP_VERSION, '5.4.0', '<')) {
- $command = 'php -dzend.enable_gc=0 ' . $command;
- }
-
if (!$this->isCoverageEnabled($options) && $this->isXdebugLoaded()) {
$message = 'Did you know? You can run tests faster by disabling xdebug';
if($this->isXdebugCodeCoverageEnabled()) {
diff --git a/plugins/Transitions/Controller.php b/plugins/Transitions/Controller.php
index dbd782f08c..fb7bb5de2b 100644
--- a/plugins/Transitions/Controller.php
+++ b/plugins/Transitions/Controller.php
@@ -22,7 +22,7 @@ class Controller extends \Piwik\Plugin\Controller
* translation keys.
*/
private static $metricTranslations = array(
- 'pageviewsInline' => 'VisitsSummary_NbPageviewsDescription',
+ 'pageviewsInline' => 'Transitions_NumPageviews',
'loopsInline' => 'Transitions_LoopsInline',
'fromPreviousPages' => 'Transitions_FromPreviousPages',
'fromPreviousPagesInline' => 'Transitions_FromPreviousPagesInline',
@@ -41,9 +41,9 @@ class Controller extends \Piwik\Plugin\Controller
'toFollowingSiteSearches' => 'Transitions_ToFollowingSiteSearches',
'toFollowingSiteSearchesInline' => 'Transitions_ToFollowingSiteSearchesInline',
'downloads' => 'General_Downloads',
- 'downloadsInline' => 'VisitsSummary_NbDownloadsDescription',
+ 'downloadsInline' => 'Transitions_NumDownloads',
'outlinks' => 'General_Outlinks',
- 'outlinksInline' => 'VisitsSummary_NbOutlinksDescription',
+ 'outlinksInline' => 'Transitions_NumOutlinks',
'exits' => 'General_ColumnExits',
'exitsInline' => 'Transitions_ExitsInline',
'bouncesInline' => 'Transitions_BouncesInline'
diff --git a/plugins/Transitions/lang/en.json b/plugins/Transitions/lang/en.json
index a161a89e6d..1b0c7fc9ba 100644
--- a/plugins/Transitions/lang/en.json
+++ b/plugins/Transitions/lang/en.json
@@ -4,6 +4,9 @@
"DirectEntries": "Direct Entries",
"ErrorBack": "Go back to the previous action",
"ExitsInline": "%s exits",
+ "NumPageviews": "%s pageviews",
+ "NumDownloads": "%s downloads",
+ "NumOutlinks": "%s outlinks",
"FromCampaigns": "From Campaigns",
"FromPreviousPages": "From Internal Pages",
"FromPreviousPagesInline": "%s from internal pages",
diff --git a/plugins/UserCountry/Categories/LocationsSubcategory.php b/plugins/UserCountry/Categories/LocationsSubcategory.php
new file mode 100644
index 0000000000..22be202abd
--- /dev/null
+++ b/plugins/UserCountry/Categories/LocationsSubcategory.php
@@ -0,0 +1,19 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\UserCountry\Categories;
+
+use Piwik\Category\Subcategory;
+
+class LocationsSubcategory extends Subcategory
+{
+ protected $categoryId = 'General_Visitors';
+ protected $id = 'UserCountry_SubmenuLocations';
+ protected $order = 25;
+
+}
diff --git a/plugins/UserCountry/Controller.php b/plugins/UserCountry/Controller.php
index a241968cbd..0ed417e421 100644
--- a/plugins/UserCountry/Controller.php
+++ b/plugins/UserCountry/Controller.php
@@ -26,18 +26,13 @@ use Piwik\View;
*/
class Controller extends \Piwik\Plugin\ControllerAdmin
{
- public function index()
+ public function getDistinctCountries()
{
- $view = new View('@UserCountry/index');
+ $view = new View('@UserCountry/getDistinctCountries');
$view->urlSparklineCountries = $this->getUrlSparkline('getLastDistinctCountriesGraph');
$view->numberDistinctCountries = $this->getNumberOfDistinctCountries(true);
- $view->dataTableCountry = $this->renderReport('getCountry');
- $view->dataTableContinent = $this->renderReport('getContinent');
- $view->dataTableRegion = $this->renderReport('getRegion');
- $view->dataTableCity = $this->renderReport('getCity');
-
return $view->render();
}
diff --git a/plugins/UserCountry/Menu.php b/plugins/UserCountry/Menu.php
index fa90e258db..92f88a7f14 100644
--- a/plugins/UserCountry/Menu.php
+++ b/plugins/UserCountry/Menu.php
@@ -9,7 +9,6 @@
namespace Piwik\Plugins\UserCountry;
use Piwik\Menu\MenuAdmin;
-use Piwik\Menu\MenuReporting;
use Piwik\Piwik;
class Menu extends \Piwik\Plugin\Menu
@@ -22,9 +21,4 @@ class Menu extends \Piwik\Plugin\Menu
$order = 9);
}
}
-
- public function configureReportingMenu(MenuReporting $menu)
- {
- $menu->addVisitorsItem('UserCountry_SubmenuLocations', $this->urlForAction('index'));
- }
}
diff --git a/plugins/UserCountry/Reports/Base.php b/plugins/UserCountry/Reports/Base.php
index f7a4f34203..c24ec82d24 100644
--- a/plugins/UserCountry/Reports/Base.php
+++ b/plugins/UserCountry/Reports/Base.php
@@ -17,7 +17,7 @@ abstract class Base extends \Piwik\Plugin\Report
{
protected function init()
{
- $this->category = 'General_Visitors';
+ $this->categoryId = 'General_Visitors';
}
protected function getGeoIPReportDocSuffix()
diff --git a/plugins/UserCountry/Reports/GetCity.php b/plugins/UserCountry/Reports/GetCity.php
index ce087c3f3c..e492d12ee2 100644
--- a/plugins/UserCountry/Reports/GetCity.php
+++ b/plugins/UserCountry/Reports/GetCity.php
@@ -22,9 +22,8 @@ class GetCity extends Base
$this->documentation = Piwik::translate('UserCountry_getCityDocumentation') . '<br/>' . $this->getGeoIPReportDocSuffix();
$this->metrics = array('nb_visits', 'nb_uniq_visitors', 'nb_actions');
$this->hasGoalMetrics = true;
- $this->order = 8;
- $this->widgetTitle = Piwik::translate('UserCountry_WidgetLocation')
- . ' (' . Piwik::translate('UserCountry_City') . ')';
+ $this->order = 10;
+ $this->subcategoryId = 'UserCountry_SubmenuLocations';
}
public function configureView(ViewDataTable $view)
diff --git a/plugins/UserCountry/Reports/GetContinent.php b/plugins/UserCountry/Reports/GetContinent.php
index 7ba6d2ca1c..b524c4f048 100644
--- a/plugins/UserCountry/Reports/GetContinent.php
+++ b/plugins/UserCountry/Reports/GetContinent.php
@@ -11,6 +11,9 @@ namespace Piwik\Plugins\UserCountry\Reports;
use Piwik\Piwik;
use Piwik\Plugin\ViewDataTable;
use Piwik\Plugins\UserCountry\Columns\Continent;
+use Piwik\Report\ReportWidgetFactory;
+use Piwik\Widget\WidgetContainerConfig;
+use Piwik\Widget\WidgetsList;
class GetContinent extends Base
{
@@ -23,8 +26,18 @@ class GetContinent extends Base
$this->metrics = array('nb_visits', 'nb_uniq_visitors', 'nb_actions');
$this->hasGoalMetrics = true;
$this->order = 6;
- $this->widgetTitle = Piwik::translate('UserCountry_WidgetLocation')
- . ' (' . Piwik::translate('UserCountry_Continent') . ')';
+
+ $this->subcategoryId = 'UserCountry_SubmenuLocations';
+ }
+
+ public function configureWidgets(WidgetsList $widgetsList, ReportWidgetFactory $factory)
+ {
+ $widgetsList->addWidgetConfig($factory->createContainerWidget('Continent'));
+
+ $widgetsList->addToContainerWidget('Continent', $factory->createWidget());
+
+ $widget = $factory->createWidget()->setAction('getDistinctCountries')->setName('');
+ $widgetsList->addToContainerWidget('Continent', $widget);
}
public function configureView(ViewDataTable $view)
diff --git a/plugins/UserCountry/Reports/GetCountry.php b/plugins/UserCountry/Reports/GetCountry.php
index 88363e1efa..5b038f7e49 100644
--- a/plugins/UserCountry/Reports/GetCountry.php
+++ b/plugins/UserCountry/Reports/GetCountry.php
@@ -24,8 +24,7 @@ class GetCountry extends Base
$this->metrics = array('nb_visits', 'nb_uniq_visitors', 'nb_actions');
$this->hasGoalMetrics = true;
$this->order = 5;
- $this->widgetTitle = Piwik::translate('UserCountry_WidgetLocation')
- . ' (' . Piwik::translate('UserCountry_Country') . ')';
+ $this->subcategoryId = 'UserCountry_SubmenuLocations';
}
public function configureView(ViewDataTable $view)
diff --git a/plugins/UserCountry/Reports/GetRegion.php b/plugins/UserCountry/Reports/GetRegion.php
index 648b78967b..7e418ebef2 100644
--- a/plugins/UserCountry/Reports/GetRegion.php
+++ b/plugins/UserCountry/Reports/GetRegion.php
@@ -23,8 +23,8 @@ class GetRegion extends Base
$this->metrics = array('nb_visits', 'nb_uniq_visitors', 'nb_actions');
$this->hasGoalMetrics = true;
$this->order = 7;
- $this->widgetTitle = Piwik::translate('UserCountry_WidgetLocation')
- . ' (' . Piwik::translate('UserCountry_Region') . ')';
+
+ $this->subcategoryId = 'UserCountry_SubmenuLocations';
}
public function configureView(ViewDataTable $view)
diff --git a/plugins/UserCountry/javascripts/userCountry.js b/plugins/UserCountry/javascripts/userCountry.js
index 7cdaf9a640..68a74adb7a 100755
--- a/plugins/UserCountry/javascripts/userCountry.js
+++ b/plugins/UserCountry/javascripts/userCountry.js
@@ -23,6 +23,7 @@ $(document).ready(function () {
action: 'setCurrentLocationProvider',
id: $(this).val()
}, 'get');
+ ajaxRequest.withTokenInUrl();
ajaxRequest.setCallback(
function () {
var UI = require('piwik/UI');
@@ -81,6 +82,7 @@ $(document).ready(function () {
var ajaxRequest = new ajaxHelper();
ajaxRequest.addParams(data, 'post');
+ ajaxRequest.withTokenInUrl();
ajaxRequest.setCallback(function (response) {
if (!response || response.error) {
callback(response);
@@ -204,6 +206,7 @@ $(document).ready(function () {
isp_db: $('#geoip-isp-db').val(),
org_db: $('#geoip-org-db').val()
}, 'post');
+ ajaxRequest.withTokenInUrl();
ajaxRequest.setCallback(updateGeoIPSuccess);
ajaxRequest.send(false);
}
diff --git a/plugins/UserCountry/templates/getDistinctCountries.twig b/plugins/UserCountry/templates/getDistinctCountries.twig
new file mode 100644
index 0000000000..ce78d5ca68
--- /dev/null
+++ b/plugins/UserCountry/templates/getDistinctCountries.twig
@@ -0,0 +1,5 @@
+<div class="sparkline">
+ {{ sparkline(urlSparklineCountries) }}
+ {{ 'UserCountry_DistinctCountries'|translate("<strong>"~numberDistinctCountries|number~"</strong>")|raw }}
+</div>
+<br style="clear:left"/> \ No newline at end of file
diff --git a/plugins/UserCountry/templates/index.twig b/plugins/UserCountry/templates/index.twig
deleted file mode 100644
index 01708f5bce..0000000000
--- a/plugins/UserCountry/templates/index.twig
+++ /dev/null
@@ -1,29 +0,0 @@
-<div class="row">
-
- <div class="col-md-6">
- {{ postEvent("Template.leftColumnUserCountry") }}
-
- <h2 piwik-enriched-headline>{{ 'UserCountry_Continent'|translate }}</h2>
- {{ dataTableContinent|raw }}
-
- <div class="sparkline">
- {{ sparkline(urlSparklineCountries) }}
- {{ 'UserCountry_DistinctCountries'|translate("<strong>"~numberDistinctCountries|number~"</strong>")|raw }}
- </div>
- <div style="clear:left"></div>
-
- {{ postEvent("Template.footerUserCountry") }}
- </div>
-
- <div class="col-md-6">
- <h2 piwik-enriched-headline>{{ 'UserCountry_Country'|translate }}</h2>
- {{ dataTableCountry|raw }}
-
- <h2 piwik-enriched-headline>{{ 'UserCountry_Region'|translate }}</h2>
- {{ dataTableRegion|raw }}
-
- <h2 piwik-enriched-headline>{{ 'UserCountry_City'|translate }}</h2>
- {{ dataTableCity|raw }}
- </div>
-
-</div>
diff --git a/plugins/UserCountryMap/Categories/RealTimeMapSubcategory.php b/plugins/UserCountryMap/Categories/RealTimeMapSubcategory.php
new file mode 100644
index 0000000000..d8f482327f
--- /dev/null
+++ b/plugins/UserCountryMap/Categories/RealTimeMapSubcategory.php
@@ -0,0 +1,19 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\UserCountryMap\Categories;
+
+use Piwik\Category\Subcategory;
+
+class RealTimeMapSubcategory extends Subcategory
+{
+ protected $categoryId = 'General_Visitors';
+ protected $id = 'UserCountryMap_RealTimeMap';
+ protected $order = 40;
+
+}
diff --git a/plugins/UserCountryMap/Controller.php b/plugins/UserCountryMap/Controller.php
index e38bf73113..b86d45f1f8 100644
--- a/plugins/UserCountryMap/Controller.php
+++ b/plugins/UserCountryMap/Controller.php
@@ -155,7 +155,7 @@ class Controller extends \Piwik\Plugin\Controller
$token_auth = Piwik::getCurrentUserTokenAuth();
$view = new View('@UserCountryMap/realtimeMap');
- $view->mapIsStandaloneNotWidget = $standalone;
+ $view->mapIsStandaloneNotWidget = !(bool) Common::getRequestVar('widget', $standalone, 'int');
$view->metrics = $this->getMetrics($idSite, 'range', self::REAL_TIME_WINDOW, $token_auth);
$view->defaultMetric = 'nb_visits';
diff --git a/plugins/UserCountryMap/Menu.php b/plugins/UserCountryMap/Menu.php
deleted file mode 100644
index 88108e3f4d..0000000000
--- a/plugins/UserCountryMap/Menu.php
+++ /dev/null
@@ -1,24 +0,0 @@
-<?php
-/**
- * Piwik - free/libre analytics platform
- *
- * @link http://piwik.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- *
- */
-namespace Piwik\Plugins\UserCountryMap;
-
-use Piwik\Menu\MenuReporting;
-use Piwik\Plugin\Manager as PluginManager;
-
-class Menu extends \Piwik\Plugin\Menu
-{
- public function configureReportingMenu(MenuReporting $menu)
- {
- if (PluginManager::getInstance()->isPluginActivated('UserCountry')) {
- $menu->addVisitorsItem('UserCountryMap_RealTimeMap',
- $this->urlForAction('realtimeWorldMap'),
- $order = 70);
- }
- }
-}
diff --git a/plugins/UserCountryMap/UserCountryMap.php b/plugins/UserCountryMap/UserCountryMap.php
index bf49c36a63..e5e9f041ab 100644
--- a/plugins/UserCountryMap/UserCountryMap.php
+++ b/plugins/UserCountryMap/UserCountryMap.php
@@ -10,8 +10,6 @@ namespace Piwik\Plugins\UserCountryMap;
use Piwik\FrontController;
use Piwik\Piwik;
-use Piwik\WidgetsList;
-use Piwik\Plugin\Manager as PluginManager;
/**
*/
@@ -33,23 +31,11 @@ class UserCountryMap extends \Piwik\Plugin
$hooks = array(
'AssetManager.getJavaScriptFiles' => 'getJsFiles',
'AssetManager.getStylesheetFiles' => 'getStylesheetFiles',
- 'Translate.getClientSideTranslationKeys' => 'getClientSideTranslationKeys',
- 'Platform.initialized' => array(
- 'after' => true,
- 'function' => 'registerWidgets'
- )
+ 'Translate.getClientSideTranslationKeys' => 'getClientSideTranslationKeys'
);
return $hooks;
}
- public function registerWidgets()
- {
- if (PluginManager::getInstance()->isPluginActivated('UserCountry')) {
- WidgetsList::add('General_Visitors', Piwik::translate('UserCountryMap_VisitorMap'), 'UserCountryMap', 'visitorMap');
- WidgetsList::add('Live!', Piwik::translate('UserCountryMap_RealTimeMap'), 'UserCountryMap', 'realtimeMap');
- }
- }
-
public function getJsFiles(&$jsFiles)
{
$jsFiles[] = "libs/bower_components/visibilityjs/lib/visibility.core.js";
diff --git a/plugins/UserCountryMap/Widgets/GetRealtimeMap.php b/plugins/UserCountryMap/Widgets/GetRealtimeMap.php
new file mode 100644
index 0000000000..d6476bfe2d
--- /dev/null
+++ b/plugins/UserCountryMap/Widgets/GetRealtimeMap.php
@@ -0,0 +1,29 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\UserCountryMap\Widgets;
+
+use Piwik\Widget\WidgetConfig;
+use Piwik\Plugin\Manager as PluginManager;
+
+class GetRealtimeMap extends \Piwik\Widget\Widget
+{
+ public static function configure(WidgetConfig $config)
+ {
+ $config->setCategoryId('General_Visitors');
+ $config->setSubcategoryId('UserCountryMap_RealTimeMap');
+ $config->setName('UserCountryMap_RealTimeMap');
+ $config->setModule('UserCountryMap');
+ $config->setAction('realtimeMap');
+ $config->setOrder(5);
+
+ if (!PluginManager::getInstance()->isPluginActivated('UserCountry')) {
+ $config->disable();
+ }
+ }
+}
diff --git a/plugins/UserCountryMap/Widgets/GetVisitorMap.php b/plugins/UserCountryMap/Widgets/GetVisitorMap.php
new file mode 100644
index 0000000000..930630df55
--- /dev/null
+++ b/plugins/UserCountryMap/Widgets/GetVisitorMap.php
@@ -0,0 +1,23 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\UserCountryMap\Widgets;
+
+use Piwik\Widget\WidgetConfig;
+
+class GetVisitorMap extends \Piwik\Widget\Widget
+{
+ public static function configure(WidgetConfig $config)
+ {
+ $config->setCategoryId('General_Visitors');
+ $config->setSubcategoryId('UserCountry_SubmenuLocations');
+ $config->setName('UserCountryMap_VisitorMap');
+ $config->setAction('visitorMap');
+ $config->setOrder(1);
+ }
+}
diff --git a/plugins/UserCountryMap/templates/visitorMap.twig b/plugins/UserCountryMap/templates/visitorMap.twig
index 7873200c9f..b5445a2cc6 100644
--- a/plugins/UserCountryMap/templates/visitorMap.twig
+++ b/plugins/UserCountryMap/templates/visitorMap.twig
@@ -86,7 +86,7 @@
if ($('#dashboardWidgetsArea').length) {
// dashboard mode
- var $widgetContent = $('.UserCountryMap').parents('.widgetContent');
+ var $widgetContent = $('.UserCountryMap').parents('.widgetContent').first();
$widgetContent.on('widget:create',function (evt, widget) {
visitorMap = new UserCountryMap.VisitorMap(config, widget);
diff --git a/plugins/UserLanguage/Reports/Base.php b/plugins/UserLanguage/Reports/Base.php
index b6bcc40222..9aa6a6ab35 100644
--- a/plugins/UserLanguage/Reports/Base.php
+++ b/plugins/UserLanguage/Reports/Base.php
@@ -14,6 +14,7 @@ abstract class Base extends \Piwik\Plugin\Report
{
protected function init()
{
- $this->category = 'General_VisitorSettings';
+ $this->categoryId = 'General_Visitors';
+ $this->subcategoryId = 'UserCountry_SubmenuLocations';
}
}
diff --git a/plugins/UserLanguage/Reports/GetLanguage.php b/plugins/UserLanguage/Reports/GetLanguage.php
index f5babd65b8..8db3629134 100644
--- a/plugins/UserLanguage/Reports/GetLanguage.php
+++ b/plugins/UserLanguage/Reports/GetLanguage.php
@@ -11,6 +11,7 @@ namespace Piwik\Plugins\UserLanguage\Reports;
use Piwik\Piwik;
use Piwik\Plugin\ViewDataTable;
use Piwik\Plugins\UserLanguage\Columns\Language;
+use Piwik\Plugin\Reports;
class GetLanguage extends Base
{
@@ -20,8 +21,7 @@ class GetLanguage extends Base
$this->dimension = new Language();
$this->name = Piwik::translate('UserLanguage_BrowserLanguage');
$this->documentation = ''; // TODO
- $this->order = 10;
- $this->widgetTitle = 'UserLanguage_BrowserLanguage';
+ $this->order = 8;
}
public function configureView(ViewDataTable $view)
@@ -37,7 +37,7 @@ class GetLanguage extends Base
public function getRelatedReports() {
return array(
- self::factory('UserLanguage', 'getLanguageCode'),
+ Reports::factory('UserLanguage', 'getLanguageCode'),
);
}
diff --git a/plugins/UserLanguage/Reports/GetLanguageCode.php b/plugins/UserLanguage/Reports/GetLanguageCode.php
index 0ca2c64bb2..9d9a46f201 100644
--- a/plugins/UserLanguage/Reports/GetLanguageCode.php
+++ b/plugins/UserLanguage/Reports/GetLanguageCode.php
@@ -10,6 +10,7 @@ namespace Piwik\Plugins\UserLanguage\Reports;
use Piwik\Piwik;
use Piwik\Plugins\UserLanguage\Columns\Language;
+use Piwik\Plugin\Reports;
class GetLanguageCode extends GetLanguage
{
@@ -20,13 +21,12 @@ class GetLanguageCode extends GetLanguage
$this->name = Piwik::translate('UserLanguage_LanguageCode');
$this->documentation = '';
$this->order = 11;
- $this->widgetTitle = 'UserLanguage_LanguageCode';
}
public function getRelatedReports()
{
return array(
- self::factory('UserLanguage', 'getLanguage'),
+ Reports::factory('UserLanguage', 'getLanguage'),
);
}
diff --git a/plugins/UserLanguage/tests/System/expected/test_UserSettingsBCTestUserSettings_UserSettings.getLanguageCode___API.getMetadata_day.xml b/plugins/UserLanguage/tests/System/expected/test_UserSettingsBCTestUserSettings_UserSettings.getLanguageCode___API.getMetadata_day.xml
index 9bf598e68f..609bf27f42 100644
--- a/plugins/UserLanguage/tests/System/expected/test_UserSettingsBCTestUserSettings_UserSettings.getLanguageCode___API.getMetadata_day.xml
+++ b/plugins/UserLanguage/tests/System/expected/test_UserSettingsBCTestUserSettings_UserSettings.getLanguageCode___API.getMetadata_day.xml
@@ -1,7 +1,8 @@
<?xml version="1.0" encoding="utf-8" ?>
<result>
<row>
- <category>Visitor Settings</category>
+ <category>Visitors</category>
+ <subcategory>Locations</subcategory>
<name>Language code</name>
<module>UserLanguage</module>
<action>getLanguageCode</action>
@@ -28,6 +29,13 @@
<bounce_rate>Bounce Rate</bounce_rate>
<conversion_rate>Conversion Rate</conversion_rate>
</processedMetrics>
+ <relatedReports>
+ <row>
+ <name>Browser language</name>
+ <module>UserLanguage</module>
+ <action>getLanguage</action>
+ </row>
+ </relatedReports>
<imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=UserLanguage&amp;apiAction=getLanguageCode&amp;period=day&amp;date=2010-03-06</imageGraphUrl>
<imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=UserLanguage&amp;apiAction=getLanguageCode&amp;period=day&amp;date=2010-02-05,2010-03-06</imageGraphEvolutionUrl>
<uniqueId>UserLanguage_getLanguageCode</uniqueId>
diff --git a/plugins/UserLanguage/tests/System/expected/test_UserSettingsBCTestUserSettings_UserSettings.getLanguage___API.getMetadata_day.xml b/plugins/UserLanguage/tests/System/expected/test_UserSettingsBCTestUserSettings_UserSettings.getLanguage___API.getMetadata_day.xml
index 9e886e4c3f..5dd35140ad 100644
--- a/plugins/UserLanguage/tests/System/expected/test_UserSettingsBCTestUserSettings_UserSettings.getLanguage___API.getMetadata_day.xml
+++ b/plugins/UserLanguage/tests/System/expected/test_UserSettingsBCTestUserSettings_UserSettings.getLanguage___API.getMetadata_day.xml
@@ -1,7 +1,8 @@
<?xml version="1.0" encoding="utf-8" ?>
<result>
<row>
- <category>Visitor Settings</category>
+ <category>Visitors</category>
+ <subcategory>Locations</subcategory>
<name>Browser language</name>
<module>UserLanguage</module>
<action>getLanguage</action>
@@ -28,6 +29,13 @@
<bounce_rate>Bounce Rate</bounce_rate>
<conversion_rate>Conversion Rate</conversion_rate>
</processedMetrics>
+ <relatedReports>
+ <row>
+ <name>Language code</name>
+ <module>UserLanguage</module>
+ <action>getLanguageCode</action>
+ </row>
+ </relatedReports>
<imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=UserLanguage&amp;apiAction=getLanguage&amp;period=day&amp;date=2010-03-06</imageGraphUrl>
<imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=UserLanguage&amp;apiAction=getLanguage&amp;period=day&amp;date=2010-02-05,2010-03-06</imageGraphEvolutionUrl>
<uniqueId>UserLanguage_getLanguage</uniqueId>
diff --git a/plugins/UsersManager/javascripts/usersSettings.js b/plugins/UsersManager/javascripts/usersSettings.js
index c6c909ea6b..1708e64bf7 100644
--- a/plugins/UsersManager/javascripts/usersSettings.js
+++ b/plugins/UsersManager/javascripts/usersSettings.js
@@ -46,6 +46,7 @@ function sendUserSettingsAJAX() {
format: 'json',
action: 'recordUserSettings'
}, 'GET');
+ ajaxHandler.withTokenInUrl();
ajaxHandler.addParams(postParams, 'POST');
ajaxHandler.redirectOnSuccess(params);
ajaxHandler.setLoadingElement('#ajaxLoadingUserSettings');
@@ -65,6 +66,7 @@ function sendAnonymousUserSettingsAJAX() {
format: 'json',
action: 'recordAnonymousUserSettings'
}, 'GET');
+ ajaxHandler.withTokenInUrl();
ajaxHandler.addParams({
anonymousDefaultReport: anonymousDefaultReport,
anonymousDefaultDate: anonymousDefaultDate
diff --git a/plugins/UsersManager/stylesheets/usersManager.less b/plugins/UsersManager/stylesheets/usersManager.less
index 330e8569d7..f8f0f9de92 100644
--- a/plugins/UsersManager/stylesheets/usersManager.less
+++ b/plugins/UsersManager/stylesheets/usersManager.less
@@ -55,4 +55,4 @@
#user_invite {
min-width: 300px;
}
-}
+} \ No newline at end of file
diff --git a/plugins/VisitFrequency/Controller.php b/plugins/VisitFrequency/Controller.php
index e1279206fd..8e6af9cffd 100644
--- a/plugins/VisitFrequency/Controller.php
+++ b/plugins/VisitFrequency/Controller.php
@@ -8,9 +8,10 @@
*/
namespace Piwik\Plugins\VisitFrequency;
-use Piwik\API\Request;
use Piwik\Common;
+use Piwik\FrontController;
use Piwik\Piwik;
+use Piwik\Plugins\CoreVisualizations\Visualizations\Sparklines;
use Piwik\Translation\Translator;
use Piwik\View;
@@ -28,31 +29,22 @@ class Controller extends \Piwik\Plugin\Controller
parent::__construct();
}
- public function index()
- {
- $view = new View('@VisitFrequency/index');
- $this->setGeneralVariablesView($view);
-
- $view->graphEvolutionVisitFrequency = $this->getEvolutionGraph(array(), array('nb_visits_returning'));
- $this->setSparklinesAndNumbers($view);
-
- return $view->render();
- }
-
+ /**
+ * @deprecated used to be a widgetized URL. There to not break widget URLs
+ */
public function getSparklines()
{
- $view = new View('@VisitFrequency/getSparklines');
- $this->setSparklinesAndNumbers($view);
- return $view->render();
+ $_GET['forceView'] = '1';
+ $_GET['viewDataTable'] = Sparklines::ID;
+
+ return FrontController::getInstance()->fetchDispatch('VisitFrequency', 'get');
}
- public function getEvolutionGraph(array $columns = array(), array $defaultColumns = array())
+ public function getEvolutionGraph()
{
- if (empty($columns)) {
- $columns = Common::getRequestVar('columns', false);
- if (false !== $columns) {
- $columns = Piwik::getArrayFromApiParameter($columns);
- }
+ $columns = Common::getRequestVar('columns', false);
+ if (false !== $columns) {
+ $columns = Piwik::getArrayFromApiParameter($columns);
}
$documentation = $this->translator->translate('VisitFrequency_ReturningVisitsDocumentation') . '<br />'
@@ -89,35 +81,10 @@ class Controller extends \Piwik\Plugin\Controller
$view = $this->getLastUnitGraphAcrossPlugins($this->pluginName, __FUNCTION__, $columns,
$selectableColumns, $documentation);
- if (empty($view->config->columns_to_display) && !empty($defaultColumns)) {
- $view->config->columns_to_display = $defaultColumns;
+ if (empty($view->config->columns_to_display)) {
+ $view->config->columns_to_display = array('nb_visits_returning');
}
return $this->renderView($view);
}
-
- protected function setSparklinesAndNumbers($view)
- {
- $view->urlSparklineNbVisitsReturning = $this->getUrlSparkline('getEvolutionGraph', array('columns' => array('nb_visits_returning')));
- $view->urlSparklineNbActionsReturning = $this->getUrlSparkline('getEvolutionGraph', array('columns' => array('nb_actions_returning')));
- $view->urlSparklineActionsPerVisitReturning = $this->getUrlSparkline('getEvolutionGraph', array('columns' => array('nb_actions_per_visit_returning')));
- $view->urlSparklineAvgVisitDurationReturning = $this->getUrlSparkline('getEvolutionGraph', array('columns' => array('avg_time_on_site_returning')));
- $view->urlSparklineBounceRateReturning = $this->getUrlSparkline('getEvolutionGraph', array('columns' => array('bounce_rate_returning')));
-
- $dataTableFrequency = $this->getSummary();
- $dataRow = $dataTableFrequency->getFirstRow();
- $nbVisitsReturning = $dataRow->getColumn('nb_visits_returning');
- $view->nbVisitsReturning = $nbVisitsReturning;
- $view->nbActionsReturning = $dataRow->getColumn('nb_actions_returning');
- $view->nbActionsPerVisitReturning = $dataRow->getColumn('nb_actions_per_visit_returning');
- $view->avgVisitDurationReturning = $dataRow->getColumn('avg_time_on_site_returning');
- $view->bounceRateReturning = $dataRow->getColumn('bounce_rate_returning');
- }
-
- protected function getSummary()
- {
- $requestString = "method=VisitFrequency.get&format=original";
- $request = new Request($requestString);
- return $request->process();
- }
}
diff --git a/plugins/VisitFrequency/Menu.php b/plugins/VisitFrequency/Menu.php
deleted file mode 100644
index e858bd2f76..0000000000
--- a/plugins/VisitFrequency/Menu.php
+++ /dev/null
@@ -1,19 +0,0 @@
-<?php
-/**
- * Piwik - free/libre analytics platform
- *
- * @link http://piwik.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- *
- */
-namespace Piwik\Plugins\VisitFrequency;
-
-use Piwik\Menu\MenuReporting;
-
-class Menu extends \Piwik\Plugin\Menu
-{
- public function configureReportingMenu(MenuReporting $menu)
- {
- $menu->addVisitorsItem('VisitFrequency_SubmenuFrequency', $this->urlForAction('index'), $order = 55);
- }
-}
diff --git a/plugins/VisitFrequency/Reports/Get.php b/plugins/VisitFrequency/Reports/Get.php
index eb4c7ddfbe..9904c9ddd4 100644
--- a/plugins/VisitFrequency/Reports/Get.php
+++ b/plugins/VisitFrequency/Reports/Get.php
@@ -8,18 +8,25 @@
*/
namespace Piwik\Plugins\VisitFrequency\Reports;
+use Piwik\DataTable;
+use Piwik\NumberFormatter;
use Piwik\Piwik;
+use Piwik\Plugin\ViewDataTable;
use Piwik\Plugins\CoreHome\Columns\Metrics\ActionsPerVisit;
use Piwik\Plugins\CoreHome\Columns\Metrics\AverageTimeOnSite;
use Piwik\Plugins\CoreHome\Columns\Metrics\BounceRate;
+use Piwik\Plugins\CoreVisualizations\Visualizations\JqplotGraph\Evolution;
+use Piwik\Plugins\CoreVisualizations\Visualizations\Sparklines;
use Piwik\Plugins\VisitFrequency\Columns\Metrics\ReturningMetric;
+use Piwik\Report\ReportWidgetFactory;
+use Piwik\Widget\WidgetsList;
class Get extends \Piwik\Plugin\Report
{
protected function init()
{
parent::init();
- $this->category = 'General_Visitors';
+ $this->categoryId = 'General_Visitors';
$this->name = Piwik::translate('VisitFrequency_ColumnReturningVisits');
$this->documentation = ''; // TODO
$this->processedMetrics = array(
@@ -35,5 +42,86 @@ class Get extends \Piwik\Plugin\Report
'max_actions_returning'
);
$this->order = 40;
+ $this->subcategoryId = 'VisitorInterest_Engagement';
}
+
+ public function configureWidgets(WidgetsList $widgetsList, ReportWidgetFactory $factory)
+ {
+ $widgetsList->addWidgetConfig(
+ $factory->createWidget()
+ ->setName('VisitFrequency_WidgetGraphReturning')
+ ->forceViewDataTable(Evolution::ID)
+ ->setAction('getEvolutionGraph')
+ ->setOrder(1)
+ );
+
+ $widgetsList->addWidgetConfig(
+ $factory->createWidget()
+ ->forceViewDataTable(Sparklines::ID)
+ ->setName('VisitFrequency_WidgetOverview')
+ ->setOrder(2)
+ );
+ }
+
+ public function configureView(ViewDataTable $view)
+ {
+ if ($view->isViewDataTableId(Sparklines::ID)) {
+ $view->requestConfig->apiMethodToRequestDataTable = 'VisitFrequency.get';
+ $this->addSparklineColumns($view);
+ $view->config->addTranslations($this->getSparklineTranslations());
+
+ $numberFormatter = NumberFormatter::getInstance();
+ $view->config->filters[] = function (DataTable $table) use ($numberFormatter) {
+ $firstRow = $table->getFirstRow();
+ if ($firstRow) {
+ $value = $firstRow->getColumn('nb_visits_returning');
+ if (false !== $value) {
+ $firstRow->setColumn('nb_visits_returning', $numberFormatter->formatNumber($value));
+ }
+
+ $value = $firstRow->getColumn('nb_actions_returning');
+ if (false !== $value) {
+ $firstRow->setColumn('nb_actions_returning', $numberFormatter->formatNumber($value));
+ }
+
+ $value = $firstRow->getColumn('nb_actions_per_visit_returning');
+ if (false !== $value) {
+ $firstRow->setColumn('nb_actions_per_visit_returning', $numberFormatter->formatNumber($value, 1));
+ }
+
+ $value = $firstRow->getColumn('bounce_rate_returning');
+ if (false !== $value) {
+ $firstRow->setColumn('bounce_rate_returning', $numberFormatter->formatNumber($value, $precision = 1));
+ }
+ }
+ };
+ }
+ }
+
+ private function getSparklineTranslations()
+ {
+ $translations = array(
+ 'nb_visits_returning' => 'ReturnVisits',
+ 'nb_actions_returning' => 'ReturnActions',
+ 'nb_actions_per_visit_returning' => 'ReturnAvgActions',
+ 'avg_time_on_site_returning' => 'ReturnAverageVisitDuration',
+ 'bounce_rate_returning' => 'ReturnBounceRate',
+ );
+
+ foreach ($translations as $metric => $key) {
+ $translations[$metric] = Piwik::translate('VisitFrequency_' . $key);
+ }
+
+ return $translations;
+ }
+
+ private function addSparklineColumns(Sparklines $view)
+ {
+ $view->config->addSparklineMetric(array('nb_visits_returning'));
+ $view->config->addSparklineMetric(array('avg_time_on_site_returning'));
+ $view->config->addSparklineMetric(array('nb_actions_per_visit_returning'));
+ $view->config->addSparklineMetric(array('bounce_rate_returning'));
+ $view->config->addSparklineMetric(array('nb_actions_returning'));
+ }
+
}
diff --git a/plugins/VisitFrequency/Widgets.php b/plugins/VisitFrequency/Widgets.php
deleted file mode 100644
index 53a5ddcd47..0000000000
--- a/plugins/VisitFrequency/Widgets.php
+++ /dev/null
@@ -1,23 +0,0 @@
-<?php
-/**
- * Piwik - free/libre analytics platform
- *
- * @link http://piwik.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- *
- */
-namespace Piwik\Plugins\VisitFrequency;
-
-class Widgets extends \Piwik\Plugin\Widgets
-{
- protected $category = 'General_Visitors';
-
- public function init()
- {
- $this->addWidget('VisitFrequency_WidgetOverview', 'getSparklines');
- $this->addWidget('VisitFrequency_WidgetGraphReturning',
- 'getEvolutionGraph',
- array('columns' => array('nb_visits_returning')));
- }
-
-}
diff --git a/plugins/VisitFrequency/lang/en.json b/plugins/VisitFrequency/lang/en.json
index d157e0a88c..39b1879852 100644
--- a/plugins/VisitFrequency/lang/en.json
+++ b/plugins/VisitFrequency/lang/en.json
@@ -12,13 +12,13 @@
"ColumnUniqueReturningVisitors": "Unique returning visitors",
"ColumnReturningUsers": "Returning Users",
"PluginDescription": "Reports metrics about your first time new visitors and returning visitors.",
- "ReturnActions": "%s actions by the returning visits",
- "ReturnAverageVisitDuration": "%s average visit duration for returning visitors",
- "ReturnAvgActions": "%s actions per returning visit",
- "ReturnBounceRate": "%s returning visits have bounced (left the website after one page)",
+ "ReturnActions": "actions by the returning visits",
+ "ReturnAverageVisitDuration": "average visit duration for returning visitors",
+ "ReturnAvgActions": "actions per returning visit",
+ "ReturnBounceRate": "returning visits have bounced (left the website after one page)",
"ReturningVisitDocumentation": "A returning visit is (as opposed to a new visit) made by someone who has visited the website at least once before.",
"ReturningVisitsDocumentation": "This is an overview of the returning visits.",
- "ReturnVisits": "%s returning visits",
+ "ReturnVisits": "returning visits",
"SubmenuFrequency": "Frequency",
"WidgetGraphReturning": "Returning Visits Over Time",
"WidgetOverview": "Frequency Overview"
diff --git a/plugins/VisitFrequency/templates/_sparklines.twig b/plugins/VisitFrequency/templates/_sparklines.twig
deleted file mode 100644
index 9c59efb811..0000000000
--- a/plugins/VisitFrequency/templates/_sparklines.twig
+++ /dev/null
@@ -1,39 +0,0 @@
-
-{% if not isWidget %}
-<div class="row">
- <div class="col-md-6">
-{% endif %}
-
- <div class="sparkline">
- {{ sparkline(urlSparklineNbVisitsReturning) }}
- {{ 'VisitFrequency_ReturnVisits'|translate("<strong>"~nbVisitsReturning|number~"</strong>")|raw }}
- </div>
- <div class="sparkline">
- {{ sparkline(urlSparklineNbActionsReturning) }}
- {{ 'VisitFrequency_ReturnActions'|translate("<strong>"~nbActionsReturning|number~"</strong>")|raw }}
- </div>
- <div class="sparkline">
- {{ sparkline(urlSparklineActionsPerVisitReturning) }}
- {{ 'VisitFrequency_ReturnAvgActions'|translate("<strong>"~nbActionsPerVisitReturning|number(1)~"</strong>")|raw }}
- </div>
-
- {% if not isWidget %}
- </div>
- <div class="col-md-6">
- {% endif %}
-
- <div class="sparkline">
- {{ sparkline(urlSparklineAvgVisitDurationReturning) }}
- {% set avgVisitDurationReturning=avgVisitDurationReturning|sumtime %}
- {{ 'VisitFrequency_ReturnAverageVisitDuration'|translate("<strong>"~avgVisitDurationReturning~"</strong>")|raw }}
- </div>
- <div class="sparkline">
- {{ sparkline(urlSparklineBounceRateReturning) }}
- {{ 'VisitFrequency_ReturnBounceRate'|translate("<strong>"~bounceRateReturning|percent~"</strong>")|raw }}
- </div>
- {% include "_sparklineFooter.twig" %}
-
-{% if not isWidget %}
- </div>
-</div>
-{% endif %}
diff --git a/plugins/VisitFrequency/templates/getSparklines.twig b/plugins/VisitFrequency/templates/getSparklines.twig
deleted file mode 100644
index fd158c8329..0000000000
--- a/plugins/VisitFrequency/templates/getSparklines.twig
+++ /dev/null
@@ -1 +0,0 @@
-{% include "@VisitFrequency/_sparklines.twig" %} \ No newline at end of file
diff --git a/plugins/VisitFrequency/templates/index.twig b/plugins/VisitFrequency/templates/index.twig
deleted file mode 100644
index 6abd255b17..0000000000
--- a/plugins/VisitFrequency/templates/index.twig
+++ /dev/null
@@ -1,9 +0,0 @@
-{{ postEvent("Template.headerVisitsFrequency") }}
-
-<h2 piwik-enriched-headline data-graph-id="VisitFrequency.getEvolutionGraph">{{ 'VisitFrequency_ColumnReturningVisits'|translate }}</h2>
- {{ graphEvolutionVisitFrequency|raw }}
-<br/>
-
-{% include "@VisitFrequency/_sparklines.twig" %}
-
-{{ postEvent("Template.footerVisitsFrequency") }}
diff --git a/plugins/VisitTime/Categories/TimesSubcategory.php b/plugins/VisitTime/Categories/TimesSubcategory.php
new file mode 100644
index 0000000000..220a568ad3
--- /dev/null
+++ b/plugins/VisitTime/Categories/TimesSubcategory.php
@@ -0,0 +1,19 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\VisitTime\Categories;
+
+use Piwik\Category\Subcategory;
+
+class TimesSubcategory extends Subcategory
+{
+ protected $categoryId = 'General_Visitors';
+ protected $id = 'VisitTime_SubmenuTimes';
+ protected $order = 35;
+
+}
diff --git a/plugins/VisitTime/Controller.php b/plugins/VisitTime/Controller.php
deleted file mode 100644
index 08af238213..0000000000
--- a/plugins/VisitTime/Controller.php
+++ /dev/null
@@ -1,25 +0,0 @@
-<?php
-/**
- * Piwik - free/libre analytics platform
- *
- * @link http://piwik.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- *
- */
-namespace Piwik\Plugins\VisitTime;
-
-use Piwik\View;
-
-/**
- *
- */
-class Controller extends \Piwik\Plugin\Controller
-{
- public function index()
- {
- $view = new View('@VisitTime/index');
- $view->dataTableVisitInformationPerLocalTime = $this->renderReport('getVisitInformationPerLocalTime');
- $view->dataTableVisitInformationPerServerTime = $this->renderReport('getVisitInformationPerServerTime');
- return $view->render();
- }
-}
diff --git a/plugins/VisitTime/Menu.php b/plugins/VisitTime/Menu.php
deleted file mode 100644
index ffa3a5b015..0000000000
--- a/plugins/VisitTime/Menu.php
+++ /dev/null
@@ -1,19 +0,0 @@
-<?php
-/**
- * Piwik - free/libre analytics platform
- *
- * @link http://piwik.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- *
- */
-namespace Piwik\Plugins\VisitTime;
-
-use Piwik\Menu\MenuReporting;
-
-class Menu extends \Piwik\Plugin\Menu
-{
- public function configureReportingMenu(MenuReporting $menu)
- {
- $menu->addVisitorsItem('VisitTime_SubmenuTimes', $this->urlForAction('index'), $order = 65);
- }
-}
diff --git a/plugins/VisitTime/Reports/Base.php b/plugins/VisitTime/Reports/Base.php
index 89b553cd44..2dfbf0e169 100644
--- a/plugins/VisitTime/Reports/Base.php
+++ b/plugins/VisitTime/Reports/Base.php
@@ -15,7 +15,7 @@ abstract class Base extends \Piwik\Plugin\Report
{
protected function init()
{
- $this->category = 'VisitsSummary_VisitsSummary';
+ $this->categoryId = 'General_Visitors';
}
public function getDefaultTypeViewDataTable()
diff --git a/plugins/VisitTime/Reports/GetByDayOfWeek.php b/plugins/VisitTime/Reports/GetByDayOfWeek.php
index d9a3a58ee8..a93c6f21ee 100644
--- a/plugins/VisitTime/Reports/GetByDayOfWeek.php
+++ b/plugins/VisitTime/Reports/GetByDayOfWeek.php
@@ -14,6 +14,7 @@ use Piwik\Plugin\ViewDataTable;
use Piwik\Plugins\CoreVisualizations\Visualizations\Graph;
use Piwik\Plugins\VisitTime\Columns\DayOfTheWeek;
use Piwik\Period;
+use Piwik\Plugin\Reports;
use Piwik\Site;
class GetByDayOfWeek extends Base
@@ -28,7 +29,7 @@ class GetByDayOfWeek extends Base
$this->documentation = Piwik::translate('VisitTime_WidgetByDayOfWeekDocumentation');
$this->constantRowsCount = true;
$this->order = 25;
- $this->widgetTitle = 'VisitTime_VisitsByDayOfWeek';
+ $this->subcategoryId = 'VisitTime_SubmenuTimes';
}
public function configureView(ViewDataTable $view)
@@ -73,4 +74,11 @@ class GetByDayOfWeek extends Base
}
return $dateRange;
}
+
+ public function getRelatedReports()
+ {
+ return array(
+ Reports::factory('VisitTime', 'getVisitInformationPerLocalTime')
+ );
+ }
}
diff --git a/plugins/VisitTime/Reports/GetVisitInformationPerLocalTime.php b/plugins/VisitTime/Reports/GetVisitInformationPerLocalTime.php
index 6546463cd1..9372875619 100644
--- a/plugins/VisitTime/Reports/GetVisitInformationPerLocalTime.php
+++ b/plugins/VisitTime/Reports/GetVisitInformationPerLocalTime.php
@@ -13,6 +13,7 @@ use Piwik\Piwik;
use Piwik\Plugin\ViewDataTable;
use Piwik\Plugins\CoreVisualizations\Visualizations\Graph;
use Piwik\Plugins\VisitTime\Columns\LocalTime;
+use Piwik\Plugin\Reports;
class GetVisitInformationPerLocalTime extends Base
{
@@ -23,11 +24,12 @@ class GetVisitInformationPerLocalTime extends Base
{
parent::init();
$this->dimension = new LocalTime();
- $this->name = Piwik::translate('VisitTime_WidgetLocalTime');
+ $this->name = Piwik::translate('VisitTime_LocalTime');
$this->documentation = Piwik::translate('VisitTime_WidgetLocalTimeDocumentation', array('<strong>', '</strong>'));
$this->constantRowsCount = true;
- $this->order = 20;
- $this->widgetTitle = 'VisitTime_WidgetLocalTime';
+ $this->order = 15;
+
+ $this->subcategoryId = 'VisitTime_SubmenuTimes';
}
public function configureView(ViewDataTable $view)
@@ -42,10 +44,12 @@ class GetVisitInformationPerLocalTime extends Base
if ($view->isViewDataTableId(Graph::ID)) {
$view->config->max_graph_elements = false;
}
+ }
- // add the visits by day of week as a related report, if the current period is not 'day'
- if (Common::getRequestVar('period', 'day') != 'day') {
- $view->config->addRelatedReport('VisitTime.getByDayOfWeek', Piwik::translate('VisitTime_VisitsByDayOfWeek'));
- }
+ public function getRelatedReports()
+ {
+ return array(
+ Reports::factory('VisitTime', 'getByDayOfWeek')
+ );
}
}
diff --git a/plugins/VisitTime/Reports/GetVisitInformationPerServerTime.php b/plugins/VisitTime/Reports/GetVisitInformationPerServerTime.php
index ce213fb211..871f760046 100644
--- a/plugins/VisitTime/Reports/GetVisitInformationPerServerTime.php
+++ b/plugins/VisitTime/Reports/GetVisitInformationPerServerTime.php
@@ -22,12 +22,13 @@ class GetVisitInformationPerServerTime extends Base
{
parent::init();
$this->dimension = new ServerTime();
- $this->name = Piwik::translate('VisitTime_WidgetServerTime');
+ $this->name = Piwik::translate('VisitTime_ServerTime');
$this->documentation = Piwik::translate('VisitTime_WidgetServerTimeDocumentation', array('<strong>', '</strong>'));
$this->constantRowsCount = true;
$this->hasGoalMetrics = true;
- $this->order = 15;
- $this->widgetTitle = 'VisitTime_WidgetServerTime';
+ $this->order = 20;
+
+ $this->subcategoryId = 'VisitTime_SubmenuTimes';
}
public function configureView(ViewDataTable $view)
diff --git a/plugins/VisitTime/templates/index.twig b/plugins/VisitTime/templates/index.twig
deleted file mode 100644
index 688cde0338..0000000000
--- a/plugins/VisitTime/templates/index.twig
+++ /dev/null
@@ -1,13 +0,0 @@
-<div class="row">
-
- <div class="col-md-6">
- <h2 piwik-enriched-headline>{{ 'VisitTime_LocalTime'|translate }}</h2>
- {{ dataTableVisitInformationPerLocalTime|raw }}
- </div>
-
- <div class="col-md-6">
- <h2 piwik-enriched-headline>{{ 'VisitTime_ServerTime'|translate }}</h2>
- {{ dataTableVisitInformationPerServerTime|raw }}
- </div>
-
-</div>
diff --git a/plugins/VisitorInterest/Controller.php b/plugins/VisitorInterest/Controller.php
deleted file mode 100644
index 8cb5200c4d..0000000000
--- a/plugins/VisitorInterest/Controller.php
+++ /dev/null
@@ -1,24 +0,0 @@
-<?php
-/**
- * Piwik - free/libre analytics platform
- *
- * @link http://piwik.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- *
- */
-namespace Piwik\Plugins\VisitorInterest;
-
-use Piwik\View;
-
-class Controller extends \Piwik\Plugin\Controller
-{
- public function index()
- {
- $view = new View('@VisitorInterest/index');
- $view->dataTableNumberOfVisitsPerVisitDuration = $this->renderReport('getNumberOfVisitsPerVisitDuration');
- $view->dataTableNumberOfVisitsPerPage = $this->renderReport('getNumberOfVisitsPerPage');
- $view->dataTableNumberOfVisitsByVisitNum = $this->renderReport('getNumberOfVisitsByVisitCount');
- $view->dataTableNumberOfVisitsByDaysSinceLast = $this->renderReport('getNumberOfVisitsByDaysSinceLast');
- return $view->render();
- }
-} \ No newline at end of file
diff --git a/plugins/VisitorInterest/Menu.php b/plugins/VisitorInterest/Menu.php
deleted file mode 100644
index 17de395000..0000000000
--- a/plugins/VisitorInterest/Menu.php
+++ /dev/null
@@ -1,20 +0,0 @@
-<?php
-/**
- * Piwik - free/libre analytics platform
- *
- * @link http://piwik.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- *
- */
-namespace Piwik\Plugins\VisitorInterest;
-
-use Piwik\Menu\MenuReporting;
-
-class Menu extends \Piwik\Plugin\Menu
-{
- public function configureReportingMenu(MenuReporting $menu)
- {
- $menu->rename('General_Visitors', 'VisitFrequency_SubmenuFrequency',
- 'General_Visitors', 'VisitorInterest_Engagement');
- }
-}
diff --git a/plugins/VisitorInterest/Reports/Base.php b/plugins/VisitorInterest/Reports/Base.php
index fb3f0b4a42..3381a8e805 100644
--- a/plugins/VisitorInterest/Reports/Base.php
+++ b/plugins/VisitorInterest/Reports/Base.php
@@ -12,7 +12,8 @@ abstract class Base extends \Piwik\Plugin\Report
{
protected function init()
{
- $this->category = 'General_Visitors';
+ $this->categoryId = 'General_Visitors';
+ $this->subcategoryId = 'VisitorInterest_Engagement';
}
}
diff --git a/plugins/VisitorInterest/Reports/GetNumberOfVisitsByDaysSinceLast.php b/plugins/VisitorInterest/Reports/GetNumberOfVisitsByDaysSinceLast.php
index fd935d47c6..b7b7302842 100644
--- a/plugins/VisitorInterest/Reports/GetNumberOfVisitsByDaysSinceLast.php
+++ b/plugins/VisitorInterest/Reports/GetNumberOfVisitsByDaysSinceLast.php
@@ -11,6 +11,8 @@ namespace Piwik\Plugins\VisitorInterest\Reports;
use Piwik\Piwik;
use Piwik\Plugin\ViewDataTable;
use Piwik\Plugins\VisitorInterest\Columns\VisitsByDaysSinceLastVisit;
+use Piwik\Report\ReportWidgetFactory;
+use Piwik\Widget\WidgetsList;
class GetNumberOfVisitsByDaysSinceLast extends Base
{
@@ -26,7 +28,14 @@ class GetNumberOfVisitsByDaysSinceLast extends Base
$this->processedMetrics = false;
$this->constantRowsCount = true;
$this->order = 30;
- $this->widgetTitle = 'VisitorInterest_WidgetVisitsByDaysSinceLast';
+
+ $this->subcategoryId = 'VisitorInterest_Engagement';
+ }
+
+ public function configureWidgets(WidgetsList $widgetsList, ReportWidgetFactory $factory)
+ {
+ $widget = $factory->createWidget()->setName('VisitorInterest_WidgetVisitsByDaysSinceLast');
+ $widgetsList->addWidgetConfig($widget);
}
public function configureView(ViewDataTable $view)
diff --git a/plugins/VisitorInterest/Reports/GetNumberOfVisitsByVisitCount.php b/plugins/VisitorInterest/Reports/GetNumberOfVisitsByVisitCount.php
index 74dbf69c14..d7c2a7b7e8 100644
--- a/plugins/VisitorInterest/Reports/GetNumberOfVisitsByVisitCount.php
+++ b/plugins/VisitorInterest/Reports/GetNumberOfVisitsByVisitCount.php
@@ -31,7 +31,6 @@ class GetNumberOfVisitsByVisitCount extends Base
);
$this->constantRowsCount = true;
$this->order = 25;
- $this->widgetTitle = 'VisitorInterest_visitsByVisitCount';
}
public function configureView(ViewDataTable $view)
diff --git a/plugins/VisitorInterest/Reports/GetNumberOfVisitsPerPage.php b/plugins/VisitorInterest/Reports/GetNumberOfVisitsPerPage.php
index de15ed5f5f..395c70da2b 100644
--- a/plugins/VisitorInterest/Reports/GetNumberOfVisitsPerPage.php
+++ b/plugins/VisitorInterest/Reports/GetNumberOfVisitsPerPage.php
@@ -13,6 +13,8 @@ use Piwik\Plugin\ViewDataTable;
use Piwik\Plugins\CoreVisualizations\Visualizations\Cloud;
use Piwik\Plugins\CoreVisualizations\Visualizations\Graph;
use Piwik\Plugins\VisitorInterest\Columns\PagesPerVisit;
+use Piwik\Report\ReportWidgetFactory;
+use Piwik\Widget\WidgetsList;
class GetNumberOfVisitsPerPage extends Base
{
@@ -29,7 +31,13 @@ class GetNumberOfVisitsPerPage extends Base
$this->processedMetrics = false;
$this->constantRowsCount = true;
$this->order = 20;
- $this->widgetTitle = 'VisitorInterest_WidgetPages';
+ }
+
+ public function configureWidgets(WidgetsList $widgetsList, ReportWidgetFactory $factory)
+ {
+ $widgetsList->addWidgetConfig(
+ $factory->createWidget()->setName('VisitorInterest_VisitsPerNbOfPages')
+ );
}
public function getDefaultTypeViewDataTable()
diff --git a/plugins/VisitorInterest/Reports/GetNumberOfVisitsPerVisitDuration.php b/plugins/VisitorInterest/Reports/GetNumberOfVisitsPerVisitDuration.php
index ead1849b7f..8ca31b560c 100644
--- a/plugins/VisitorInterest/Reports/GetNumberOfVisitsPerVisitDuration.php
+++ b/plugins/VisitorInterest/Reports/GetNumberOfVisitsPerVisitDuration.php
@@ -13,6 +13,8 @@ use Piwik\Plugin\ViewDataTable;
use Piwik\Plugins\CoreVisualizations\Visualizations\Cloud;
use Piwik\Plugins\CoreVisualizations\Visualizations\Graph;
use Piwik\Plugins\VisitorInterest\Columns\VisitDuration;
+use Piwik\Report\ReportWidgetFactory;
+use Piwik\Widget\WidgetsList;
class GetNumberOfVisitsPerVisitDuration extends Base
{
@@ -29,7 +31,13 @@ class GetNumberOfVisitsPerVisitDuration extends Base
$this->processedMetrics = false;
$this->constantRowsCount = true;
$this->order = 15;
- $this->widgetTitle = 'VisitorInterest_WidgetLengths';
+ }
+
+ public function configureWidgets(WidgetsList $widgetsList, ReportWidgetFactory $factory)
+ {
+ $widgetsList->addWidgetConfig(
+ $factory->createWidget()->setName('VisitorInterest_VisitsPerDuration')
+ );
}
public function getDefaultTypeViewDataTable()
diff --git a/plugins/VisitorInterest/templates/index.twig b/plugins/VisitorInterest/templates/index.twig
deleted file mode 100644
index 332289e106..0000000000
--- a/plugins/VisitorInterest/templates/index.twig
+++ /dev/null
@@ -1,21 +0,0 @@
-<div class="row">
- <div class="col-md-6">
- <h2 piwik-enriched-headline>{{ 'VisitorInterest_VisitsPerDuration'|translate }}</h2>
- {{ dataTableNumberOfVisitsPerVisitDuration|raw }}
- </div>
- <div class="col-md-6">
- <h2 piwik-enriched-headline>{{ 'VisitorInterest_VisitsPerNbOfPages'|translate }}</h2>
- {{ dataTableNumberOfVisitsPerPage|raw }}
- </div>
-</div>
-
-<div class="row">
- <div class="col-md-6">
- <h2 piwik-enriched-headline>{{ 'VisitorInterest_visitsByVisitCount'|translate }}</h2>
- {{ dataTableNumberOfVisitsByVisitNum|raw }}
- </div>
- <div class="col-md-6">
- <h2 piwik-enriched-headline>{{ 'VisitorInterest_VisitsByDaysSinceLast'|translate }}</h2>
- {{ dataTableNumberOfVisitsByDaysSinceLast|raw }}
- </div>
-</div>
diff --git a/plugins/VisitsSummary/API.php b/plugins/VisitsSummary/API.php
index b80c505fbb..c46bd93b7b 100644
--- a/plugins/VisitsSummary/API.php
+++ b/plugins/VisitsSummary/API.php
@@ -12,6 +12,7 @@ use Piwik\Archive;
use Piwik\Metrics\Formatter;
use Piwik\Piwik;
use Piwik\Plugin\Report;
+use Piwik\Plugin\Reports;
use Piwik\SettingsPiwik;
/**
@@ -29,7 +30,7 @@ class API extends \Piwik\Plugin\API
$requestedColumns = Piwik::getArrayFromApiParameter($columns);
- $report = Report::factory("VisitsSummary", "get");
+ $report = Reports::factory("VisitsSummary", "get");
$columns = $report->getMetricsRequiredForReport($this->getCoreColumns($period), $requestedColumns);
$dataTable = $archive->getDataTableFromNumeric($columns);
diff --git a/plugins/VisitsSummary/Controller.php b/plugins/VisitsSummary/Controller.php
index bc28ca0dde..ca141b7ed8 100644
--- a/plugins/VisitsSummary/Controller.php
+++ b/plugins/VisitsSummary/Controller.php
@@ -12,7 +12,9 @@ use Piwik\API\Request;
use Piwik\Common;
use Piwik\DataTable;
use Piwik\DataTable\Row;
+use Piwik\FrontController;
use Piwik\Piwik;
+use Piwik\Plugins\CoreVisualizations\Visualizations\Sparklines;
use Piwik\Site;
use Piwik\Translation\Translator;
use Piwik\View;
@@ -34,38 +36,32 @@ class Controller extends \Piwik\Plugin\Controller
parent::__construct();
}
- public function index()
+ /**
+ * @deprecated used to be a widgetized URL. There to not break widget URLs
+ */
+ public function getSparklines()
{
- $view = new View('@VisitsSummary/index');
- $this->setPeriodVariablesView($view);
- $view->graphEvolutionVisitsSummary = $this->getEvolutionGraph(array(), array('nb_visits'), 'getIndexGraph');
- $this->setSparklinesAndNumbers($view);
- return $view->render();
- }
+ $_GET['forceView'] = '1';
+ $_GET['viewDataTable'] = Sparklines::ID;
- // sparkline.js:81 dataTable.trigger('reload', …); does not remove the old headline,
- // so when updating this graph (such as when selecting a different metric)
- // ONLY the graph should be returned
- public function getIndexGraph()
- {
- return $this->getEvolutionGraph(array(), array(), __FUNCTION__);
+ return FrontController::getInstance()->fetchDispatch('VisitsSummary', 'get');
}
- public function getSparklines()
+ /**
+ * @deprecated used to be a widgetized URL. There to not break widget URLs
+ */
+ public function index()
{
- $view = new View('@VisitsSummary/getSparklines');
- $this->setPeriodVariablesView($view);
- $this->setSparklinesAndNumbers($view);
- return $view->render();
+ $_GET['containerId'] = 'VisitOverviewWithGraph';
+
+ return FrontController::getInstance()->fetchDispatch('CoreHome', 'renderWidgetContainer');
}
- public function getEvolutionGraph(array $columns = array(), array $defaultColumns = array(), $callingAction = __FUNCTION__)
+ public function getEvolutionGraph()
{
- if (empty($columns)) {
- $columns = Common::getRequestVar('columns', false);
- if (false !== $columns) {
- $columns = Piwik::getArrayFromApiParameter($columns);
- }
+ $columns = Common::getRequestVar('columns', false);
+ if (false !== $columns) {
+ $columns = Piwik::getArrayFromApiParameter($columns);
}
$documentation = $this->translator->translate('VisitsSummary_VisitsSummaryDocumentation') . '<br />'
@@ -115,11 +111,11 @@ class Controller extends \Piwik\Plugin\Controller
}
// $callingAction may be specified to distinguish between
// "VisitsSummary_WidgetLastVisits" and "VisitsSummary_WidgetOverviewGraph"
- $view = $this->getLastUnitGraphAcrossPlugins($this->pluginName, $callingAction, $columns,
+ $view = $this->getLastUnitGraphAcrossPlugins($this->pluginName, __FUNCTION__, $columns,
$selectableColumns, $documentation);
- if (empty($view->config->columns_to_display) && !empty($defaultColumns)) {
- $view->config->columns_to_display = $defaultColumns;
+ if (empty($view->config->columns_to_display)) {
+ $view->config->columns_to_display = array('nb_visits');
}
return $this->renderView($view);
@@ -136,87 +132,4 @@ class Controller extends \Piwik\Plugin\Controller
return empty($result) ? new DataTable() : $result;
}
-
- public static function getVisits()
- {
- $requestString = "method=VisitsSummary.getVisits" .
- "&format=original" .
- "&disable_generic_filters=1";
- $request = new Request($requestString);
- return $request->process();
- }
-
- protected function setSparklinesAndNumbers($view)
- {
- $view->urlSparklineNbVisits = $this->getUrlSparkline('getEvolutionGraph', array('columns' => $view->displayUniqueVisitors ? array('nb_visits', 'nb_uniq_visitors') : array('nb_visits')));
- $view->urlSparklineNbUsers = $this->getUrlSparkline('getEvolutionGraph', array('columns' => array('nb_users')));
- $view->urlSparklineNbPageviews = $this->getUrlSparkline('getEvolutionGraph', array('columns' => array('nb_pageviews', 'nb_uniq_pageviews')));
- $view->urlSparklineNbDownloads = $this->getUrlSparkline('getEvolutionGraph', array('columns' => array('nb_downloads', 'nb_uniq_downloads')));
- $view->urlSparklineNbOutlinks = $this->getUrlSparkline('getEvolutionGraph', array('columns' => array('nb_outlinks', 'nb_uniq_outlinks')));
- $view->urlSparklineAvgVisitDuration = $this->getUrlSparkline('getEvolutionGraph', array('columns' => array('avg_time_on_site')));
- $view->urlSparklineMaxActions = $this->getUrlSparkline('getEvolutionGraph', array('columns' => array('max_actions')));
- $view->urlSparklineActionsPerVisit = $this->getUrlSparkline('getEvolutionGraph', array('columns' => array('nb_actions_per_visit')));
- $view->urlSparklineBounceRate = $this->getUrlSparkline('getEvolutionGraph', array('columns' => array('bounce_rate')));
- $view->urlSparklineAvgGenerationTime = $this->getUrlSparkline('getEvolutionGraph', array('columns' => array('avg_time_generation')));
-
- $idSite = Common::getRequestVar('idSite');
- $displaySiteSearch = Site::isSiteSearchEnabledFor($idSite);
- if ($displaySiteSearch) {
- $view->urlSparklineNbSearches = $this->getUrlSparkline('getEvolutionGraph', array('columns' => array('nb_searches', 'nb_keywords')));
- }
- $view->displaySiteSearch = $displaySiteSearch;
-
- $dataTableVisit = self::getVisitsSummary();
- $dataRow = $dataTableVisit->getRowsCount() == 0 ? new Row() : $dataTableVisit->getFirstRow();
- $view->nbUniqVisitors = (int)$dataRow->getColumn('nb_uniq_visitors');
- $view->nbUsers = (int)$dataRow->getColumn('nb_users');
- $nbVisits = (int)$dataRow->getColumn('nb_visits');
- $view->nbVisits = $nbVisits;
-
- $view->averageVisitDuration = $dataRow->getColumn('avg_time_on_site');
- $view->bounceRate = $dataRow->getColumn('bounce_rate');
- $view->maxActions = (int)$dataRow->getColumn('max_actions');
- $view->nbActionsPerVisit = $dataRow->getColumn('nb_actions_per_visit');
-
- if (Common::isActionsPluginEnabled()) {
- $view->showActionsPluginReports = true;
-
- $dataTableActions = Request::processRequest("Actions.get", array(
- 'idSite' => $idSite,
- 'period' => Common::getRequestVar('period'),
- 'date' => Common::getRequestVar('date'),
- 'segment' => Request::getRawSegmentFromRequest()
- ), $defaultParams = array());
-
- $dataActionsRow =
- $dataTableActions->getRowsCount() == 0 ? new Row() : $dataTableActions->getFirstRow();
-
- $view->nbPageviews = (int)$dataActionsRow->getColumn('nb_pageviews');
- $view->nbUniquePageviews = (int)$dataActionsRow->getColumn('nb_uniq_pageviews');
- $view->nbDownloads = (int)$dataActionsRow->getColumn('nb_downloads');
- $view->nbUniqueDownloads = (int)$dataActionsRow->getColumn('nb_uniq_downloads');
- $view->nbOutlinks = (int)$dataActionsRow->getColumn('nb_outlinks');
- $view->nbUniqueOutlinks = (int)$dataActionsRow->getColumn('nb_uniq_outlinks');
- $view->averageGenerationTime = $dataActionsRow->getColumn('avg_time_generation');
-
- if ($displaySiteSearch) {
- $view->nbSearches = (int)$dataActionsRow->getColumn('nb_searches');
- $view->nbKeywords = (int)$dataActionsRow->getColumn('nb_keywords');
- }
-
- // backward compatibility:
- // show actions if the finer metrics are not archived
- $view->showOnlyActions = false;
- if ($dataActionsRow->getColumn('nb_pageviews')
- + $dataActionsRow->getColumn('nb_downloads')
- + $dataActionsRow->getColumn('nb_outlinks') == 0
- && $dataRow->getColumn('nb_actions') > 0
- ) {
- $view->showOnlyActions = true;
- $view->nbActions = $dataRow->getColumn('nb_actions');
- $view->urlSparklineNbActions = $this->getUrlSparkline('getEvolutionGraph', array('columns' => array('nb_actions')));
- }
- }
-
- }
}
diff --git a/plugins/VisitsSummary/Menu.php b/plugins/VisitsSummary/Menu.php
deleted file mode 100644
index be7fc7ed09..0000000000
--- a/plugins/VisitsSummary/Menu.php
+++ /dev/null
@@ -1,20 +0,0 @@
-<?php
-/**
- * Piwik - free/libre analytics platform
- *
- * @link http://piwik.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- *
- */
-namespace Piwik\Plugins\VisitsSummary;
-
-use Piwik\Menu\MenuReporting;
-
-class Menu extends \Piwik\Plugin\Menu
-{
- public function configureReportingMenu(MenuReporting $menu)
- {
- $menu->addVisitorsItem('', array(), 10);
- $menu->addVisitorsItem('General_Overview', array('module' => 'VisitsSummary', 'action' => 'index'), 1);
- }
-}
diff --git a/plugins/VisitsSummary/Reports/Get.php b/plugins/VisitsSummary/Reports/Get.php
index 665ae17009..c74a82566f 100644
--- a/plugins/VisitsSummary/Reports/Get.php
+++ b/plugins/VisitsSummary/Reports/Get.php
@@ -8,10 +8,23 @@
*/
namespace Piwik\Plugins\VisitsSummary\Reports;
+use Piwik\Common;
+use Piwik\Container\StaticContainer;
+use Piwik\DataTable;
+use Piwik\Metrics\Formatter;
+use Piwik\NumberFormatter;
use Piwik\Piwik;
+use Piwik\Plugin\ViewDataTable;
use Piwik\Plugins\CoreHome\Columns\Metrics\ActionsPerVisit;
use Piwik\Plugins\CoreHome\Columns\Metrics\AverageTimeOnSite;
use Piwik\Plugins\CoreHome\Columns\Metrics\BounceRate;
+use Piwik\Plugins\CoreHome\Columns\UserId;
+use Piwik\Plugins\CoreVisualizations\Visualizations\JqplotGraph\Evolution;
+use Piwik\Plugins\CoreVisualizations\Visualizations\Sparklines;
+use Piwik\Report\ReportWidgetFactory;
+use Piwik\SettingsPiwik;
+use Piwik\Site;
+use Piwik\Widget\WidgetsList;
class Get extends \Piwik\Plugin\Report
{
@@ -20,7 +33,7 @@ class Get extends \Piwik\Plugin\Report
protected function init()
{
parent::init();
- $this->category = 'VisitsSummary_VisitsSummary';
+ $this->categoryId = 'General_Visitors';
$this->name = Piwik::translate('VisitsSummary_VisitsSummary');
$this->documentation = ''; // TODO
$this->processedMetrics = array(
@@ -35,12 +48,165 @@ class Get extends \Piwik\Plugin\Report
'nb_actions',
'max_actions'
);
+ $this->subcategoryId = 'General_Overview';
// Used to process metrics, not displayed/used directly
// 'sum_visit_length',
// 'nb_visits_converted',
$this->order = 1;
}
+ public function configureWidgets(WidgetsList $widgetsList, ReportWidgetFactory $factory)
+ {
+ $widgetsList->addWidgetConfig(
+ $factory->createWidget()
+ ->setName('VisitsSummary_WidgetLastVisits')
+ ->forceViewDataTable(Evolution::ID)
+ ->setAction('getEvolutionGraph')
+ ->setOrder(5)
+ );
+
+ $widgetsList->addWidgetConfig(
+ $factory->createWidget()
+ ->setName('VisitsSummary_WidgetVisits')
+ ->forceViewDataTable(Sparklines::ID)
+ ->setOrder(10)
+ );
+ }
+
+ public function configureView(ViewDataTable $view)
+ {
+ if ($view->isViewDataTableId(Sparklines::ID)) {
+ /** @var Sparklines $view */
+ $view->requestConfig->apiMethodToRequestDataTable = 'API.get';
+ $this->addSparklineColumns($view);
+ $view->config->addTranslations($this->getSparklineTranslations());
+
+ $numberFormatter = NumberFormatter::getInstance();
+ $view->config->filters[] = function (DataTable $table) use ($view, $numberFormatter) {
+ $firstRow = $table->getFirstRow();
+
+ if (($firstRow->getColumn('nb_pageviews')
+ + $firstRow->getColumn('nb_downloads')
+ + $firstRow->getColumn('nb_outlinks')) == 0
+ && $firstRow->getColumn('nb_actions') > 0) {
+ $view->config->removeSparklineMetric(array('nb_downloads', 'nb_uniq_downloads'));
+ $view->config->removeSparklineMetric(array('nb_outlinks', 'nb_uniq_outlinks'));
+ $view->config->removeSparklineMetric(array('nb_pageviews', 'nb_uniq_pageviews'));
+ $view->config->removeSparklineMetric(array('nb_searches', 'nb_keywords'));
+ } else {
+ $view->config->removeSparklineMetric(array('nb_actions'));
+ }
+
+ $nbUsers = $firstRow->getColumn('nb_users');
+ if (!is_numeric($nbUsers) || 0 >= $nbUsers) {
+ $view->config->replaceSparklineMetric(array('nb_users'), '');
+ }
+
+ $avgGenerationTime = $firstRow->getColumn('avg_time_generation');
+ if (false === $avgGenerationTime) {
+ // fix avgGenerationTime is not formatted if value is false
+ /** @var Formatter $formatter */
+ $formatter = StaticContainer::get('Piwik\Metrics\Formatter');
+ $avgGenerationTime = $formatter->getPrettyTimeFromSeconds($avgGenerationTime, true);
+ $firstRow->setColumn('avg_time_generation', $avgGenerationTime);
+ }
+
+ $numberMetrics = array('nb_visits', 'nb_uniq_visitors', 'nb_uniq_visitors', 'nb_users', 'nb_actions',
+ 'nb_pageviews', 'nb_uniq_pageviews', 'nb_searches', 'nb_keywords', 'nb_downloads',
+ 'nb_uniq_downloads', 'nb_outlinks', 'nb_uniq_outlinks', 'max_actions');
+ foreach ($numberMetrics as $metric) {
+ $value = $firstRow->getColumn($metric);
+ if (false !== $value) {
+ $firstRow->setColumn($metric, $numberFormatter->formatNumber($value));
+ }
+ }
+ $value = $firstRow->getColumn('bounce_rate');
+ if (false !== $value) {
+ $firstRow->setColumn('bounce_rate', $numberFormatter->formatPercent($value, $precision = 1));
+ }
+ $value = $firstRow->getColumn('nb_actions_per_visit');
+ if (false !== $value) {
+ $firstRow->setColumn('nb_actions_per_visit', $numberFormatter->formatNumber($value, $maxFraction = 1));
+ }
+ };
+ }
+ }
+
+ private function getSparklineTranslations()
+ {
+ $translations = array(
+ 'nb_actions' => 'NbActionsDescription',
+ 'nb_visits' => 'NbVisitsDescription',
+ 'nb_users' => 'NbUsersDescription',
+ 'nb_uniq_visitors' => 'NbUniqueVisitors',
+ 'avg_time_generation' => 'AverageGenerationTime',
+ 'avg_time_on_site' => 'AverageVisitDuration',
+ 'max_actions' => 'MaxNbActions',
+ 'nb_actions_per_visit' => 'NbActionsPerVisit',
+ 'nb_downloads' => 'NbDownloadsDescription',
+ 'nb_uniq_downloads' => 'NbUniqueDownloadsDescription',
+ 'nb_outlinks' => 'NbOutlinksDescription',
+ 'nb_uniq_outlinks' => 'NbUniqueOutlinksDescription',
+ 'nb_keywords' => 'NbKeywordsDescription',
+ 'nb_searches' => 'NbSearchesDescription',
+ 'nb_pageviews' => 'NbPageviewsDescription',
+ 'nb_uniq_pageviews' => 'NbUniquePageviewsDescription',
+ 'bounce_rate' => 'NbVisitsBounced',
+ );
+
+ foreach ($translations as $metric => $key) {
+ $translations[$metric] = Piwik::translate('VisitsSummary_' . $key);
+ }
+
+ return $translations;
+ }
+
+ private function addSparklineColumns(Sparklines $view)
+ {
+ $currentPeriod = Common::getRequestVar('period');
+ $currentIdSite = Common::getRequestVar('idSite');
+ $currentDate = Common::getRequestVar('date');
+ $displayUniqueVisitors = SettingsPiwik::isUniqueVisitorsEnabled($currentPeriod);
+
+ $isActionPluginEnabled = Common::isActionsPluginEnabled();
+
+ $view->config->addSparklineMetric($displayUniqueVisitors ? array('nb_visits', 'nb_uniq_visitors') : array('nb_visits'), 5);
+
+ if ($isActionPluginEnabled) {
+ $view->config->addSparklineMetric(array('nb_actions'), 10); // either actions or pageviews will be displayed
+ $view->config->addSparklineMetric(array('nb_pageviews', 'nb_uniq_pageviews'), 20);
+ } else {
+ // make sure to still create a div on the right side for this, just leave it empty
+ $view->config->addPlaceholder(10);
+ }
+
+ $userId = new UserId();
+ if ($userId->isUsedInAtLeastOneSite($currentIdSite, $currentPeriod, $currentDate)) {
+ $view->config->addSparklineMetric(array('nb_users'), 30);
+ $view->config->addPlaceholder(31);
+ }
+
+ $view->config->addSparklineMetric(array('avg_time_on_site'), 40);
+
+ $idSite = Common::getRequestVar('idSite');
+ if ($isActionPluginEnabled && Site::isSiteSearchEnabledFor($idSite)) {
+ $view->config->addSparklineMetric(array('nb_searches', 'nb_keywords'), 50);
+ } else {
+ // make sure to still create a div on the right side for this, just leave it empty
+ $view->config->addPlaceholder(50);
+ }
+
+ $view->config->addSparklineMetric(array('bounce_rate'), 60);
+
+ if ($isActionPluginEnabled) {
+ $view->config->addSparklineMetric(array('nb_downloads', 'nb_uniq_downloads'), 70);
+ $view->config->addSparklineMetric(array('nb_actions_per_visit'), 71);
+ $view->config->addSparklineMetric(array('nb_outlinks', 'nb_uniq_outlinks'), 72);
+ $view->config->addSparklineMetric(array('avg_time_generation'), 73);
+ $view->config->addSparklineMetric(array('max_actions'), 74);
+ }
+ }
+
public function getMetrics()
{
$metrics = parent::getMetrics();
diff --git a/plugins/VisitsSummary/Widgets.php b/plugins/VisitsSummary/Widgets.php
deleted file mode 100644
index 5ec7eef56e..0000000000
--- a/plugins/VisitsSummary/Widgets.php
+++ /dev/null
@@ -1,22 +0,0 @@
-<?php
-/**
- * Piwik - free/libre analytics platform
- *
- * @link http://piwik.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- *
- */
-namespace Piwik\Plugins\VisitsSummary;
-
-class Widgets extends \Piwik\Plugin\Widgets
-{
- protected $category = 'VisitsSummary_VisitsSummary';
-
- public function init()
- {
- $this->addWidget('VisitsSummary_WidgetLastVisits', 'getEvolutionGraph', array('columns' => array('nb_visits')));
- $this->addWidget('VisitsSummary_WidgetVisits', 'getSparklines');
- $this->addWidget('VisitsSummary_WidgetOverviewGraph', 'index');
- }
-
-}
diff --git a/plugins/VisitsSummary/Widgets/Index.php b/plugins/VisitsSummary/Widgets/Index.php
new file mode 100644
index 0000000000..1b39fad7c6
--- /dev/null
+++ b/plugins/VisitsSummary/Widgets/Index.php
@@ -0,0 +1,47 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\VisitsSummary\Widgets;
+
+use Piwik\Plugin\Report;
+use Piwik\Plugins\CoreVisualizations\Visualizations\JqplotGraph\Evolution;
+use Piwik\Plugins\CoreVisualizations\Visualizations\Sparklines;
+use Piwik\Plugin\Reports;
+use Piwik\Report\ReportWidgetFactory;
+use Piwik\Widget\WidgetsList;
+
+class Index extends \Piwik\Widget\WidgetContainerConfig
+{
+ protected $categoryId = 'General_Visitors';
+ protected $name = 'VisitsSummary_WidgetOverviewGraph';
+ protected $id = 'VisitOverviewWithGraph';
+ protected $isWidgetizable = true;
+
+ public function isEnabled()
+ {
+ return Reports::factory('VisitsSummary', 'get')->isEnabled();
+ }
+
+ public function getWidgetConfigs()
+ {
+ $report = Reports::factory('VisitsSummary', 'get');
+
+ $factory = new ReportWidgetFactory($report);
+ $widgets = array();
+
+ $list = new WidgetsList();
+ $report->configureWidgets($list, $factory);
+
+ foreach ($list->getWidgetConfigs() as $config) {
+ $config->setIsNotWidgetizable();
+ $widgets[] = $config;
+ }
+
+ return $widgets;
+ }
+}
diff --git a/plugins/VisitsSummary/lang/en.json b/plugins/VisitsSummary/lang/en.json
index e4a46bc5ae..fc9d3c4777 100644
--- a/plugins/VisitsSummary/lang/en.json
+++ b/plugins/VisitsSummary/lang/en.json
@@ -1,22 +1,24 @@
{
"VisitsSummary": {
- "AverageGenerationTime": "%s average generation time",
- "AverageVisitDuration": "%s average visit duration",
+ "AverageGenerationTime": "average generation time",
+ "AverageVisitDuration": "average visit duration",
"GenerateQueries": "%s queries executed",
"GenerateTime": "%s seconds to generate the page",
- "MaxNbActions": "%s max actions in one visit",
+ "MaxNbActions": "max actions in one visit",
"NbActionsDescription": "%s actions",
- "NbActionsPerVisit": "%s actions (page views, downloads, outlinks and internal site searches) per visit",
- "NbDownloadsDescription": "%s downloads",
- "NbKeywordsDescription": "%s unique keywords",
- "NbOutlinksDescription": "%s outlinks",
- "NbPageviewsDescription": "%s pageviews",
- "NbSearchesDescription": "%s total searches on your website",
- "NbUniqueDownloadsDescription": "%s unique downloads",
- "NbUniqueOutlinksDescription": "%s unique outlinks",
- "NbUniquePageviewsDescription": "%s unique pageviews",
- "NbUniqueVisitors": "%s unique visitors",
- "NbVisitsBounced": "%s visits have bounced (left the website after one page)",
+ "NbActionsPerVisit": "actions (page views, downloads, outlinks and internal site searches) per visit",
+ "NbDownloadsDescription": "downloads",
+ "NbKeywordsDescription": "unique keywords",
+ "NbOutlinksDescription": "outlinks",
+ "NbPageviewsDescription": "pageviews",
+ "NbSearchesDescription": "total searches on your website",
+ "NbUniqueDownloadsDescription": "unique downloads",
+ "NbUniqueOutlinksDescription": "unique outlinks",
+ "NbUniquePageviewsDescription": "unique pageviews",
+ "NbUniqueVisitors": "unique visitors",
+ "NbUsersDescription": "users",
+ "NbVisitsDescription": "visits",
+ "NbVisitsBounced": "visits have bounced (left the website after one page)",
"PluginDescription": "Reports general analytics metrics: visits, unique visitors, number of actions, bounce rate, etc.",
"VisitsSummary": "Visits Summary",
"VisitsSummaryDocumentation": "This is an overview of the visit evolution.",
diff --git a/plugins/Widgetize/Controller.php b/plugins/Widgetize/Controller.php
index 2e2e5bf8cb..cf6cb5114a 100644
--- a/plugins/Widgetize/Controller.php
+++ b/plugins/Widgetize/Controller.php
@@ -12,7 +12,6 @@ use Piwik\API\Request;
use Piwik\Common;
use Piwik\FrontController;
use Piwik\View;
-use Piwik\WidgetsList;
/**
*
@@ -22,7 +21,6 @@ class Controller extends \Piwik\Plugin\Controller
public function index()
{
$view = new View('@Widgetize/index');
- $view->availableWidgets = json_encode(WidgetsList::get());
$this->setGeneralVariablesView($view);
return $view->render();
}
@@ -35,7 +33,7 @@ class Controller extends \Piwik\Plugin\Controller
$controllerName = Common::getRequestVar('moduleToWidgetize');
$actionName = Common::getRequestVar('actionToWidgetize');
- if($controllerName == 'API') {
+ if ($controllerName == 'API') {
throw new \Exception("Widgetizing API requests is not supported for security reasons. Please change query parameter 'moduleToWidgetize'.");
}
diff --git a/plugins/Widgetize/templates/iframe.twig b/plugins/Widgetize/templates/iframe.twig
index ce40bdb940..66556262b5 100644
--- a/plugins/Widgetize/templates/iframe.twig
+++ b/plugins/Widgetize/templates/iframe.twig
@@ -12,11 +12,10 @@
<link rel="stylesheet" type="text/css" href="plugins/Morpheus/stylesheets/ieonly.css"/>
<![endif]-->
</head>
- <!--[if lt IE 9 ]>
- <body ng-app="app" class="old-ie"> <![endif]-->
<!--[if (gte IE 9)|!(IE)]><!-->
<body ng-app="app">
<![endif]-->
+ <div piwik-popover-handler></div>
<div class="widget">
{{ content|raw }}
</div>
diff --git a/plugins/Widgetize/templates/index.twig b/plugins/Widgetize/templates/index.twig
index 800c5cafd7..8ada9906cf 100644
--- a/plugins/Widgetize/templates/index.twig
+++ b/plugins/Widgetize/templates/index.twig
@@ -29,7 +29,6 @@
$('#widgetPreview').widgetPreview({
onPreviewLoaded: widgetized.callbackAddExportButtonsUnderWidget
});
- broadcast.init();
});
</script>
diff --git a/plugins/Widgetize/tests/System/WidgetTest.php b/plugins/Widgetize/tests/System/WidgetTest.php
index fe126b0b08..72861e6faf 100644
--- a/plugins/Widgetize/tests/System/WidgetTest.php
+++ b/plugins/Widgetize/tests/System/WidgetTest.php
@@ -11,10 +11,11 @@ namespace Piwik\Plugins\Widgetize\tests\Integration;
use Piwik\Container\StaticContainer;
use Piwik\Http\ControllerResolver;
use Piwik\Piwik;
+use Piwik\Plugins\API;
use Piwik\Plugins\Goals;
use Piwik\Plugins\Widgetize\tests\Fixtures\WidgetizeFixture;
use Piwik\Tests\Framework\TestCase\SystemTestCase;
-use Piwik\WidgetsList;
+use Piwik\Widget\WidgetsList;
/**
* @group Widgetize
@@ -35,7 +36,7 @@ class WidgetTest extends SystemTestCase
$_GET = array();
$_GET['idSite'] = self::$fixture->idSite;
$_GET['period'] = 'year';
- $_GET['date'] = 'today';
+ $_GET['date'] = '2013-01-23';
}
public function tearDown()
@@ -44,28 +45,35 @@ class WidgetTest extends SystemTestCase
parent::tearDown();
}
+ public function test_allWidgetUniqueIdsAreActuallyUnique()
+ {
+ $uniqueIds = array();
+ foreach (WidgetsList::get()->getWidgetConfigs() as $widget) {
+ $uniqueIds[] = $widget->getUniqueId();
+ }
+
+ $this->assertEquals(array_unique($uniqueIds), $uniqueIds);
+ }
+
public function test_AvailableWidgetListIsUpToDate()
{
- $namesOfWidgetsThatAreAPI = $this->getWidgetNames($this->getWidgetsThatAreAPI());
+ $namesOfWidgetsThatAreAPI = array_map(function ($widget) {
+ return $widget['uniqueId'];
+ }, $this->getWidgetsThatAreAPICurrently());
Piwik::postEvent('Platform.initialized'); // userCountryMap defines it's Widgets via this event currently
- $currentWidgetNames = array();
- foreach (WidgetsList::get() as $widgets) {
- $currentWidgetNames = array_merge($this->getWidgetNames($widgets), $currentWidgetNames);
- }
+ $widgets = API\API::getInstance()->getWidgetMetadata($_GET['idSite']);
- $allWidgetNames = array_merge($namesOfWidgetsThatAreAPI, $currentWidgetNames);
- $regressedWidgetNames = array_diff($allWidgetNames, $currentWidgetNames);
+ $currentUniqueIds = array();
+ foreach ($widgets as $widget) {
+ $currentUniqueIds[] = $widget['uniqueId'];
+ }
- $this->assertEmpty($regressedWidgetNames, 'The widgets list is no longer up to date. If you added, removed or renamed a widget please update `getAvailableWidgets()` otherwise you will need to fix it. Different names: ' . var_export($regressedWidgetNames, 1));
- }
+ $allWidgetNames = array_merge($namesOfWidgetsThatAreAPI, $currentUniqueIds);
+ $regressedWidgetIds = array_diff($allWidgetNames, $currentUniqueIds);
- private function getWidgetNames($widgets)
- {
- return array_map(function ($widget) {
- return $widget['name'];
- }, $widgets);
+ $this->assertEmpty($regressedWidgetIds, 'The widgets list is no longer up to date. If you added or changed a widget please update `getWidgetsThatAreAPICurrently()`, if you removed a widget please add it to `getWidgetsThatAreDeprecatedButStillAPI()`. If the uniqueId changed you might need to create an update for Dashboards and Scheduled Reports! Different names: ' . var_export($regressedWidgetIds, 1));
}
/**
@@ -78,7 +86,8 @@ class WidgetTest extends SystemTestCase
$params = $widget['parameters'];
$parameters = array();
- $resolver = new ControllerResolver(StaticContainer::getContainer());
+ /** @var ControllerResolver $resolver */
+ $resolver = StaticContainer::get('Piwik\Http\ControllerResolver');
$controller = $resolver->getController($params['module'], $params['action'], $parameters);
$this->assertNotEmpty($controller, $widget['name'] . ' is not renderable with following params: ' . json_encode($params) . '. This breaks the API, please make sure to keep the URL working');
@@ -86,11 +95,15 @@ class WidgetTest extends SystemTestCase
public function availableWidgetsProvider()
{
- $widgets = $this->getWidgetsThatAreAPI();
-
$data = array();
- foreach ($widgets as $widget) {
+ foreach ($this->getWidgetsThatAreAPICurrently() as $widget) {
+ if (!empty($widget)) {
+ $data[] = array($widget);
+ }
+ }
+
+ foreach ($this->getWidgetsThatAreDeprecatedButStillAPI() as $widget) {
if (!empty($widget)) {
$data[] = array($widget);
}
@@ -99,661 +112,1159 @@ class WidgetTest extends SystemTestCase
return $data;
}
+ public function getWidgetsThatAreAPICurrently()
+ {
+ return array(
+ array (
+ 'name' => 'Visits Overview (with graph)',
+ 'uniqueId' => 'widgetVisitOverviewWithGraph',
+ 'parameters' =>
+ array (
+ 'module' => 'CoreHome',
+ 'action' => 'renderWidgetContainer',
+ 'containerId' => 'VisitOverviewWithGraph',
+ ),
+ ),array (
+ 'name' => 'Support Piwik!',
+ 'uniqueId' => 'widgetCoreHomegetDonateForm',
+ 'parameters' =>
+ array (
+ 'module' => 'CoreHome',
+ 'action' => 'getDonateForm',
+ ),
+ ),array (
+ 'name' => 'Welcome!',
+ 'uniqueId' => 'widgetCoreHomegetPromoVideo',
+ 'parameters' =>
+ array (
+ 'module' => 'CoreHome',
+ 'action' => 'getPromoVideo',
+ ),
+ ),array (
+ 'name' => 'Example Widget Name',
+ 'uniqueId' => 'widgetExamplePluginmyExampleWidget',
+ 'parameters' =>
+ array (
+ 'module' => 'ExamplePlugin',
+ 'action' => 'myExampleWidget',
+ ),
+ ),array (
+ 'name' => 'Top Keywords for Page URL',
+ 'uniqueId' => 'widgetReferrersgetKeywordsForPage',
+ 'parameters' =>
+ array (
+ 'module' => 'Referrers',
+ 'action' => 'getKeywordsForPage',
+ ),
+ ),array (
+ 'name' => 'Ecommerce Log',
+ 'uniqueId' => 'widgetEcommercegetEcommerceLog',
+ 'parameters' =>
+ array (
+ 'module' => 'Ecommerce',
+ 'action' => 'getEcommerceLog',
+ ),
+ ),array (
+ 'name' => 'SEO Rankings',
+ 'uniqueId' => 'widgetSEOgetRank',
+ 'parameters' =>
+ array (
+ 'module' => 'SEO',
+ 'action' => 'getRank',
+ ),
+ ),array (
+ 'name' => 'Piwik Changelog',
+ 'uniqueId' => 'widgetExampleRssWidgetrssChangelog',
+ 'parameters' =>
+ array (
+ 'module' => 'ExampleRssWidget',
+ 'action' => 'rssChangelog',
+ ),
+ ),array (
+ 'name' => 'Piwik.org Blog',
+ 'uniqueId' => 'widgetExampleRssWidgetrssPiwik',
+ 'parameters' =>
+ array (
+ 'module' => 'ExampleRssWidget',
+ 'action' => 'rssPiwik',
+ ),
+ ),array (
+ 'name' => 'Real-time Map',
+ 'uniqueId' => 'widgetUserCountryMaprealtimeMap',
+ 'parameters' =>
+ array (
+ 'module' => 'UserCountryMap',
+ 'action' => 'realtimeMap',
+ ),
+ ),array (
+ 'name' => 'Visitor Map',
+ 'uniqueId' => 'widgetUserCountryMapvisitorMap',
+ 'parameters' =>
+ array (
+ 'module' => 'UserCountryMap',
+ 'action' => 'visitorMap',
+ ),
+ ),array (
+ 'name' => 'Visitor profile',
+ 'uniqueId' => 'widgetLivegetVisitorProfilePopup',
+ 'parameters' =>
+ array (
+ 'module' => 'Live',
+ 'action' => 'getVisitorProfilePopup',
+ ),
+ ),array (
+ 'name' => 'Visitors in Real-time',
+ 'uniqueId' => 'widgetLivewidget',
+ 'parameters' =>
+ array (
+ 'module' => 'Live',
+ 'action' => 'widget',
+ ),
+ ),array (
+ 'name' => 'Insights Overview',
+ 'uniqueId' => 'widgetInsightsgetInsightsOverview',
+ 'parameters' =>
+ array (
+ 'module' => 'Insights',
+ 'action' => 'getInsightsOverview',
+ ),
+ ),array (
+ 'name' => 'Movers and Shakers',
+ 'uniqueId' => 'widgetInsightsgetOverallMoversAndShakers',
+ 'parameters' =>
+ array (
+ 'module' => 'Insights',
+ 'action' => 'getOverallMoversAndShakers',
+ ),
+ ),array (
+ 'name' => 'Real Time Visitor Count',
+ 'uniqueId' => 'widgetLivegetSimpleLastVisitCount',
+ 'parameters' =>
+ array (
+ 'module' => 'Live',
+ 'action' => 'getSimpleLastVisitCount',
+ ),
+ ),array (
+ 'name' => 'Visits Over Time',
+ 'uniqueId' => 'widgetVisitsSummarygetEvolutionGraphforceView1viewDataTablegraphEvolution',
+ 'parameters' =>
+ array (
+ 'forceView' => 1,
+ 'viewDataTable' => 'graphEvolution',
+ 'module' => 'VisitsSummary',
+ 'action' => 'getEvolutionGraph',
+ ),
+ ),array (
+ 'name' => 'Visits Overview',
+ 'uniqueId' => 'widgetVisitsSummarygetforceView1viewDataTablesparklines',
+ 'parameters' =>
+ array (
+ 'forceView' => 1,
+ 'viewDataTable' => 'sparklines',
+ 'module' => 'VisitsSummary',
+ 'action' => 'get',
+ ),
+ ),array (
+ 'name' => 'Visitor Log',
+ 'uniqueId' => 'widgetLivegetLastVisitsDetailsforceView1viewDataTableVisitorLogsmall1',
+ 'parameters' =>
+ array (
+ 'forceView' => 1,
+ 'viewDataTable' => 'VisitorLog',
+ 'module' => 'Live',
+ 'action' => 'getLastVisitsDetails',
+ 'small' => 1,
+ ),
+ ),array (
+ 'name' => 'Custom Variables',
+ 'uniqueId' => 'widgetCustomVariablesgetCustomVariables',
+ 'parameters' =>
+ array (
+ 'module' => 'CustomVariables',
+ 'action' => 'getCustomVariables',
+ ),
+ ),array (
+ 'name' => 'Device type',
+ 'uniqueId' => 'widgetDevicesDetectiongetType',
+ 'parameters' =>
+ array (
+ 'module' => 'DevicesDetection',
+ 'action' => 'getType',
+ ),
+ ),array (
+ 'name' => 'Device model',
+ 'uniqueId' => 'widgetDevicesDetectiongetModel',
+ 'parameters' =>
+ array (
+ 'module' => 'DevicesDetection',
+ 'action' => 'getModel',
+ ),
+ ),array (
+ 'name' => 'Device brand',
+ 'uniqueId' => 'widgetDevicesDetectiongetBrand',
+ 'parameters' =>
+ array (
+ 'module' => 'DevicesDetection',
+ 'action' => 'getBrand',
+ ),
+ ),array (
+ 'name' => 'Screen Resolution',
+ 'uniqueId' => 'widgetResolutiongetResolution',
+ 'parameters' =>
+ array (
+ 'module' => 'Resolution',
+ 'action' => 'getResolution',
+ ),
+ ),array (
+ 'name' => 'Operating System versions',
+ 'uniqueId' => 'widgetDevicesDetectiongetOsVersions',
+ 'parameters' =>
+ array (
+ 'module' => 'DevicesDetection',
+ 'action' => 'getOsVersions',
+ ),
+ ),array (
+ 'name' => 'Browsers',
+ 'uniqueId' => 'widgetDevicesDetectiongetBrowsers',
+ 'parameters' =>
+ array (
+ 'module' => 'DevicesDetection',
+ 'action' => 'getBrowsers',
+ ),
+ ),array (
+ 'name' => 'Browser version',
+ 'uniqueId' => 'widgetDevicesDetectiongetBrowserVersions',
+ 'parameters' =>
+ array (
+ 'module' => 'DevicesDetection',
+ 'action' => 'getBrowserVersions',
+ ),
+ ),array (
+ 'name' => 'Configurations',
+ 'uniqueId' => 'widgetResolutiongetConfiguration',
+ 'parameters' =>
+ array (
+ 'module' => 'Resolution',
+ 'action' => 'getConfiguration',
+ ),
+ ),array (
+ 'name' => 'Operating System families',
+ 'uniqueId' => 'widgetDevicesDetectiongetOsFamilies',
+ 'parameters' =>
+ array (
+ 'module' => 'DevicesDetection',
+ 'action' => 'getOsFamilies',
+ ),
+ ),array (
+ 'name' => 'Browser engines',
+ 'uniqueId' => 'widgetDevicesDetectiongetBrowserEnginesviewDataTablegraphPie',
+ 'parameters' =>
+ array (
+ 'viewDataTable' => 'graphPie',
+ 'module' => 'DevicesDetection',
+ 'action' => 'getBrowserEngines',
+ ),
+ ),array (
+ 'name' => 'Browser Plugins',
+ 'uniqueId' => 'widgetDevicePluginsgetPlugin',
+ 'parameters' =>
+ array (
+ 'module' => 'DevicePlugins',
+ 'action' => 'getPlugin',
+ ),
+ ),array (
+ 'name' => 'Country',
+ 'uniqueId' => 'widgetUserCountrygetCountry',
+ 'parameters' =>
+ array (
+ 'module' => 'UserCountry',
+ 'action' => 'getCountry',
+ ),
+ ),array (
+ 'name' => 'Region',
+ 'uniqueId' => 'widgetUserCountrygetRegion',
+ 'parameters' =>
+ array (
+ 'module' => 'UserCountry',
+ 'action' => 'getRegion',
+ ),
+ ),array (
+ 'name' => 'Browser language',
+ 'uniqueId' => 'widgetUserLanguagegetLanguage',
+ 'parameters' =>
+ array (
+ 'module' => 'UserLanguage',
+ 'action' => 'getLanguage',
+ ),
+ ),array (
+ 'name' => 'City',
+ 'uniqueId' => 'widgetUserCountrygetCity',
+ 'parameters' =>
+ array (
+ 'module' => 'UserCountry',
+ 'action' => 'getCity',
+ ),
+ ),array (
+ 'name' => 'Language code',
+ 'uniqueId' => 'widgetUserLanguagegetLanguageCode',
+ 'parameters' =>
+ array (
+ 'module' => 'UserLanguage',
+ 'action' => 'getLanguageCode',
+ ),
+ ),array (
+ 'name' => 'Visits per visit duration',
+ 'uniqueId' => 'widgetVisitorInterestgetNumberOfVisitsPerVisitDurationviewDataTablecloud',
+ 'parameters' =>
+ array (
+ 'viewDataTable' => 'cloud',
+ 'module' => 'VisitorInterest',
+ 'action' => 'getNumberOfVisitsPerVisitDuration',
+ ),
+ ),array (
+ 'name' => 'Visits per number of pages',
+ 'uniqueId' => 'widgetVisitorInterestgetNumberOfVisitsPerPageviewDataTablecloud',
+ 'parameters' =>
+ array (
+ 'viewDataTable' => 'cloud',
+ 'module' => 'VisitorInterest',
+ 'action' => 'getNumberOfVisitsPerPage',
+ ),
+ ),array (
+ 'name' => 'Visits by Visit Number',
+ 'uniqueId' => 'widgetVisitorInterestgetNumberOfVisitsByVisitCount',
+ 'parameters' =>
+ array (
+ 'module' => 'VisitorInterest',
+ 'action' => 'getNumberOfVisitsByVisitCount',
+ ),
+ ),array (
+ 'name' => 'Visits by Days Since Last Visit',
+ 'uniqueId' => 'widgetVisitorInterestgetNumberOfVisitsByDaysSinceLast',
+ 'parameters' =>
+ array (
+ 'module' => 'VisitorInterest',
+ 'action' => 'getNumberOfVisitsByDaysSinceLast',
+ ),
+ ),array (
+ 'name' => 'Returning Visits Over Time',
+ 'uniqueId' => 'widgetVisitFrequencygetEvolutionGraphforceView1viewDataTablegraphEvolution',
+ 'parameters' =>
+ array (
+ 'forceView' => 1,
+ 'viewDataTable' => 'graphEvolution',
+ 'module' => 'VisitFrequency',
+ 'action' => 'getEvolutionGraph',
+ ),
+ ),array (
+ 'name' => 'Frequency Overview',
+ 'uniqueId' => 'widgetVisitFrequencygetforceView1viewDataTablesparklines',
+ 'parameters' =>
+ array (
+ 'forceView' => 1,
+ 'viewDataTable' => 'sparklines',
+ 'module' => 'VisitFrequency',
+ 'action' => 'get',
+ ),
+ ),array (
+ 'name' => 'Visits per local time',
+ 'uniqueId' => 'widgetVisitTimegetVisitInformationPerLocalTimeviewDataTablegraphVerticalBar',
+ 'parameters' =>
+ array (
+ 'viewDataTable' => 'graphVerticalBar',
+ 'module' => 'VisitTime',
+ 'action' => 'getVisitInformationPerLocalTime',
+ ),
+ ),array (
+ 'name' => 'Visits per server time',
+ 'uniqueId' => 'widgetVisitTimegetVisitInformationPerServerTimeviewDataTablegraphVerticalBar',
+ 'parameters' =>
+ array (
+ 'viewDataTable' => 'graphVerticalBar',
+ 'module' => 'VisitTime',
+ 'action' => 'getVisitInformationPerServerTime',
+ ),
+ ),array (
+ 'name' => 'Visits by Day of Week',
+ 'uniqueId' => 'widgetVisitTimegetByDayOfWeekviewDataTablegraphVerticalBar',
+ 'parameters' =>
+ array (
+ 'viewDataTable' => 'graphVerticalBar',
+ 'module' => 'VisitTime',
+ 'action' => 'getByDayOfWeek',
+ ),
+ ),array (
+ 'name' => 'Pages',
+ 'uniqueId' => 'widgetActionsgetPageUrls',
+ 'parameters' =>
+ array (
+ 'module' => 'Actions',
+ 'action' => 'getPageUrls',
+ ),
+ ),array (
+ 'name' => 'Entry pages',
+ 'uniqueId' => 'widgetActionsgetEntryPageUrls',
+ 'parameters' =>
+ array (
+ 'module' => 'Actions',
+ 'action' => 'getEntryPageUrls',
+ ),
+ ),array (
+ 'name' => 'Exit pages',
+ 'uniqueId' => 'widgetActionsgetExitPageUrls',
+ 'parameters' =>
+ array (
+ 'module' => 'Actions',
+ 'action' => 'getExitPageUrls',
+ ),
+ ),array (
+ 'name' => 'Page titles',
+ 'uniqueId' => 'widgetActionsgetPageTitles',
+ 'parameters' =>
+ array (
+ 'module' => 'Actions',
+ 'action' => 'getPageTitles',
+ ),
+ ),array (
+ 'name' => 'Site Search Keywords',
+ 'uniqueId' => 'widgetActionsgetSiteSearchKeywords',
+ 'parameters' =>
+ array (
+ 'module' => 'Actions',
+ 'action' => 'getSiteSearchKeywords',
+ ),
+ ),array (
+ 'name' => 'Pages Following a Site Search',
+ 'uniqueId' => 'widgetActionsgetPageUrlsFollowingSiteSearch',
+ 'parameters' =>
+ array (
+ 'module' => 'Actions',
+ 'action' => 'getPageUrlsFollowingSiteSearch',
+ ),
+ ),array (
+ 'name' => 'Search Keywords with No Results',
+ 'uniqueId' => 'widgetActionsgetSiteSearchNoResultKeywords',
+ 'parameters' =>
+ array (
+ 'module' => 'Actions',
+ 'action' => 'getSiteSearchNoResultKeywords',
+ ),
+ ),array (
+ 'name' => 'Page Titles Following a Site Search',
+ 'uniqueId' => 'widgetActionsgetPageTitlesFollowingSiteSearch',
+ 'parameters' =>
+ array (
+ 'module' => 'Actions',
+ 'action' => 'getPageTitlesFollowingSiteSearch',
+ ),
+ ),array (
+ 'name' => 'Search Categories',
+ 'uniqueId' => 'widgetActionsgetSiteSearchCategories',
+ 'parameters' =>
+ array (
+ 'module' => 'Actions',
+ 'action' => 'getSiteSearchCategories',
+ ),
+ ),array (
+ 'name' => 'Outlinks',
+ 'uniqueId' => 'widgetActionsgetOutlinks',
+ 'parameters' =>
+ array (
+ 'module' => 'Actions',
+ 'action' => 'getOutlinks',
+ ),
+ ),array (
+ 'name' => 'Downloads',
+ 'uniqueId' => 'widgetActionsgetDownloads',
+ 'parameters' =>
+ array (
+ 'module' => 'Actions',
+ 'action' => 'getDownloads',
+ ),
+ ),array (
+ 'name' => 'Entry Page Titles',
+ 'uniqueId' => 'widgetActionsgetEntryPageTitles',
+ 'parameters' =>
+ array (
+ 'module' => 'Actions',
+ 'action' => 'getEntryPageTitles',
+ ),
+ ),array (
+ 'name' => 'Exit page titles',
+ 'uniqueId' => 'widgetActionsgetExitPageTitles',
+ 'parameters' =>
+ array (
+ 'module' => 'Actions',
+ 'action' => 'getExitPageTitles',
+ ),
+ ),array (
+ 'name' => 'Referrer Types',
+ 'uniqueId' => 'widgetReferrersgetReferrerTypeviewDataTabletableAllColumns',
+ 'parameters' =>
+ array (
+ 'viewDataTable' => 'tableAllColumns',
+ 'module' => 'Referrers',
+ 'action' => 'getReferrerType',
+ ),
+ ),array (
+ 'name' => 'Referrers',
+ 'uniqueId' => 'widgetReferrersgetAllviewDataTabletableAllColumns',
+ 'parameters' =>
+ array (
+ 'viewDataTable' => 'tableAllColumns',
+ 'module' => 'Referrers',
+ 'action' => 'getAll',
+ ),
+ ),array (
+ 'name' => 'Keywords',
+ 'uniqueId' => 'widgetReferrersgetKeywords',
+ 'parameters' =>
+ array (
+ 'module' => 'Referrers',
+ 'action' => 'getKeywords',
+ ),
+ ),array (
+ 'name' => 'Search Engines',
+ 'uniqueId' => 'widgetReferrersgetSearchEngines',
+ 'parameters' =>
+ array (
+ 'module' => 'Referrers',
+ 'action' => 'getSearchEngines',
+ ),
+ ),array (
+ 'name' => 'Websites',
+ 'uniqueId' => 'widgetReferrersgetWebsites',
+ 'parameters' =>
+ array (
+ 'module' => 'Referrers',
+ 'action' => 'getWebsites',
+ ),
+ ),array (
+ 'name' => 'Social Networks',
+ 'uniqueId' => 'widgetReferrersgetSocialsviewDataTablegraphPie',
+ 'parameters' =>
+ array (
+ 'viewDataTable' => 'graphPie',
+ 'module' => 'Referrers',
+ 'action' => 'getSocials',
+ ),
+ ),array (
+ 'name' => 'Campaigns',
+ 'uniqueId' => 'widgetReferrersgetCampaigns',
+ 'parameters' =>
+ array (
+ 'module' => 'Referrers',
+ 'action' => 'getCampaigns',
+ ),
+ ),array (
+ 'name' => 'Overview',
+ 'uniqueId' => 'widgetGoalsOverview',
+ 'parameters' =>
+ array (
+ 'module' => 'CoreHome',
+ 'action' => 'renderWidgetContainer',
+ 'containerId' => 'GoalsOverview',
+ ),
+ ),array (
+ 'name' => 'Overview',
+ 'uniqueId' => 'widgetEcommerceOverview',
+ 'parameters' =>
+ array (
+ 'module' => 'CoreHome',
+ 'action' => 'renderWidgetContainer',
+ 'containerId' => 'EcommerceOverview',
+ ),
+ ),array (
+ 'name' => 'Download Software',
+ 'uniqueId' => 'widgetGoal_1',
+ 'parameters' =>
+ array (
+ 'module' => 'CoreHome',
+ 'action' => 'renderWidgetContainer',
+ 'containerId' => 'Goal_1',
+ ),
+ ),array (
+ 'name' => 'Download Software2',
+ 'uniqueId' => 'widgetGoal_2',
+ 'parameters' =>
+ array (
+ 'module' => 'CoreHome',
+ 'action' => 'renderWidgetContainer',
+ 'containerId' => 'Goal_2',
+ ),
+ ),array (
+ 'name' => 'Opens Contact Form',
+ 'uniqueId' => 'widgetGoal_3',
+ 'parameters' =>
+ array (
+ 'module' => 'CoreHome',
+ 'action' => 'renderWidgetContainer',
+ 'containerId' => 'Goal_3',
+ ),
+ ),array (
+ 'name' => 'Visit Docs',
+ 'uniqueId' => 'widgetGoal_4',
+ 'parameters' =>
+ array (
+ 'module' => 'CoreHome',
+ 'action' => 'renderWidgetContainer',
+ 'containerId' => 'Goal_4',
+ ),
+ ),array (
+ 'name' => 'Data tables',
+ 'uniqueId' => 'widgetExampleUIgetTemperatures',
+ 'parameters' =>
+ array (
+ 'module' => 'ExampleUI',
+ 'action' => 'getTemperatures',
+ ),
+ ),array (
+ 'name' => 'Data tables',
+ 'uniqueId' => 'widgetExampleUIgetTemperaturesforceView1viewDataTablegraphVerticalBar',
+ 'parameters' =>
+ array (
+ 'forceView' => 1,
+ 'viewDataTable' => 'graphVerticalBar',
+ 'module' => 'ExampleUI',
+ 'action' => 'getTemperatures',
+ ),
+ ),array (
+ 'name' => 'Treemap example',
+ 'uniqueId' => 'widgetExampleUIgetTemperaturesforceView1viewDataTableinfoviz-treemap',
+ 'parameters' =>
+ array (
+ 'forceView' => 1,
+ 'viewDataTable' => 'infoviz-treemap',
+ 'module' => 'ExampleUI',
+ 'action' => 'getTemperatures',
+ ),
+ ),array (
+ 'name' => 'Temperatures evolution over time',
+ 'uniqueId' => 'widgetExampleUIgetTemperaturesEvolutionforceView1viewDataTablesparklines',
+ 'parameters' =>
+ array (
+ 'forceView' => 1,
+ 'viewDataTable' => 'sparklines',
+ 'module' => 'ExampleUI',
+ 'action' => 'getTemperaturesEvolution',
+ ),
+ ),array (
+ 'name' => 'Evolution of server temperatures over the last few days',
+ 'uniqueId' => 'widgetExampleUIgetTemperaturesEvolutionforceView1viewDataTablegraphEvolutioncolumnsArray',
+ 'parameters' =>
+ array (
+ 'forceView' => 1,
+ 'viewDataTable' => 'graphEvolution',
+ 'module' => 'ExampleUI',
+ 'action' => 'getTemperaturesEvolution',
+ 'columns' =>
+ array (
+ 0 => 'server1',
+ 1 => 'server2',
+ ),
+ ),
+ ),array (
+ 'name' => 'Pie graph',
+ 'uniqueId' => 'widgetExampleUIgetPlanetRatiosviewDataTablegraphPie',
+ 'parameters' =>
+ array (
+ 'viewDataTable' => 'graphPie',
+ 'module' => 'ExampleUI',
+ 'action' => 'getPlanetRatios',
+ ),
+ ),array (
+ 'name' => 'Simple tag cloud',
+ 'uniqueId' => 'widgetExampleUIgetPlanetRatiosforceView1viewDataTablecloud',
+ 'parameters' =>
+ array (
+ 'forceView' => 1,
+ 'viewDataTable' => 'cloud',
+ 'module' => 'ExampleUI',
+ 'action' => 'getPlanetRatios',
+ ),
+ ),array (
+ 'name' => 'Advanced tag cloud: with logos and links',
+ 'uniqueId' => 'widgetExampleUIgetPlanetRatiosWithLogosviewDataTablecloud',
+ 'parameters' =>
+ array (
+ 'viewDataTable' => 'cloud',
+ 'module' => 'ExampleUI',
+ 'action' => 'getPlanetRatiosWithLogos',
+ )
+ ),array (
+ 'name' => 'Continent',
+ 'uniqueId' => 'widgetUserCountrygetContinent',
+ 'parameters' =>
+ array (
+ 'module' => 'UserCountry',
+ 'action' => 'getContinent',
+ ),
+ ), array (
+ 'name' => 'Event Categories',
+ 'uniqueId' => 'widgetEventsgetCategorysecondaryDimensioneventAction',
+ 'parameters' =>
+ array (
+ 'module' => 'Events',
+ 'action' => 'getCategory',
+ 'secondaryDimension' => 'eventAction',
+ ),
+ ), array (
+ 'name' => 'Event Categories',
+ 'uniqueId' => 'widgetEventsgetCategorysecondaryDimensioneventAction',
+ 'parameters' =>
+ array (
+ 'module' => 'Events',
+ 'action' => 'getCategory',
+ 'secondaryDimension' => 'eventAction',
+ ),
+ ), array (
+ 'name' => 'Event Actions',
+ 'uniqueId' => 'widgetEventsgetActionsecondaryDimensioneventName',
+ 'parameters' =>
+ array (
+ 'module' => 'Events',
+ 'action' => 'getAction',
+ 'secondaryDimension' => 'eventName',
+ ),
+ ), array (
+ 'name' => 'Event Actions',
+ 'uniqueId' => 'widgetEventsgetActionsecondaryDimensioneventName',
+ 'parameters' =>
+ array (
+ 'module' => 'Events',
+ 'action' => 'getAction',
+ 'secondaryDimension' => 'eventName',
+ ),
+ ), array (
+ 'name' => 'Event Actions',
+ 'uniqueId' => 'widgetEventsgetActionsecondaryDimensioneventName',
+ 'parameters' =>
+ array (
+ 'module' => 'Events',
+ 'action' => 'getAction',
+ 'secondaryDimension' => 'eventName',
+ ),
+ ), array (
+ 'name' => 'Event Actions',
+ 'uniqueId' => 'widgetEventsgetActionsecondaryDimensioneventName',
+ 'parameters' =>
+ array (
+ 'module' => 'Events',
+ 'action' => 'getAction',
+ 'secondaryDimension' => 'eventName',
+ ),
+ ), array (
+ 'name' => 'Event Names',
+ 'uniqueId' => 'widgetEventsgetNamesecondaryDimensioneventAction',
+ 'parameters' =>
+ array (
+ 'module' => 'Events',
+ 'action' => 'getName',
+ 'secondaryDimension' => 'eventAction',
+ ),
+ ), array (
+ 'name' => 'Event Names',
+ 'uniqueId' => 'widgetEventsgetNamesecondaryDimensioneventAction',
+ 'parameters' =>
+ array (
+ 'module' => 'Events',
+ 'action' => 'getName',
+ 'secondaryDimension' => 'eventAction',
+ ),
+ ), array (
+ 'name' => 'Event Names',
+ 'uniqueId' => 'widgetEventsgetNamesecondaryDimensioneventAction',
+ 'parameters' =>
+ array (
+ 'module' => 'Events',
+ 'action' => 'getName',
+ 'secondaryDimension' => 'eventAction',
+ ),
+ ), array (
+ 'name' => 'Event Names',
+ 'uniqueId' => 'widgetEventsgetNamesecondaryDimensioneventAction',
+ 'parameters' =>
+ array (
+ 'module' => 'Events',
+ 'action' => 'getName',
+ 'secondaryDimension' => 'eventAction',
+ ),
+ ), array (
+ 'name' => 'Event Categories',
+ 'uniqueId' => 'widgetEventsgetCategorysecondaryDimensioneventAction',
+ 'parameters' =>
+ array (
+ 'module' => 'Events',
+ 'action' => 'getCategory',
+ 'secondaryDimension' => 'eventAction',
+ ),
+ ), array (
+ 'name' => 'Event Categories',
+ 'uniqueId' => 'widgetEventsgetCategorysecondaryDimensioneventAction',
+ 'parameters' =>
+ array (
+ 'module' => 'Events',
+ 'action' => 'getCategory',
+ 'secondaryDimension' => 'eventAction',
+ ),
+ ), array (
+ 'name' => 'Content Piece',
+ 'uniqueId' => 'widgetContentsgetContentPieces',
+ 'parameters' =>
+ array (
+ 'module' => 'Contents',
+ 'action' => 'getContentPieces',
+ ),
+ ), array (
+ 'name' => 'Content Piece',
+ 'uniqueId' => 'widgetContentsgetContentPieces',
+ 'parameters' =>
+ array (
+ 'module' => 'Contents',
+ 'action' => 'getContentPieces',
+ ),
+ ), array (
+ 'name' => 'Content Name',
+ 'uniqueId' => 'widgetContentsgetContentNames',
+ 'parameters' =>
+ array (
+ 'module' => 'Contents',
+ 'action' => 'getContentNames',
+ ),
+ ), array (
+ 'name' => 'Content Name',
+ 'uniqueId' => 'widgetContentsgetContentNames',
+ 'parameters' =>
+ array (
+ 'module' => 'Contents',
+ 'action' => 'getContentNames',
+ ),
+ ), array (
+ 'name' => 'Content Name',
+ 'uniqueId' => 'widgetContentsgetContentNames',
+ 'parameters' =>
+ array (
+ 'module' => 'Contents',
+ 'action' => 'getContentNames',
+ ),
+ ), array (
+ 'name' => 'Content Name',
+ 'uniqueId' => 'widgetContentsgetContentNames',
+ 'parameters' =>
+ array (
+ 'module' => 'Contents',
+ 'action' => 'getContentNames',
+ ),
+ ), array (
+ 'name' => 'Content Piece',
+ 'uniqueId' => 'widgetContentsgetContentPieces',
+ 'parameters' =>
+ array (
+ 'module' => 'Contents',
+ 'action' => 'getContentPieces',
+ ),
+ ), array (
+ 'name' => 'Content Piece',
+ 'uniqueId' => 'widgetContentsgetContentPieces',
+ 'parameters' =>
+ array (
+ 'module' => 'Contents',
+ 'action' => 'getContentPieces',
+ ),
+ ), array (
+ 'name' => 'Product SKU',
+ 'uniqueId' => 'widgetGoalsgetItemsSku',
+ 'parameters' =>
+ array (
+ 'module' => 'Goals',
+ 'action' => 'getItemsSku',
+ ),
+ ), array (
+ 'name' => 'Product SKU',
+ 'uniqueId' => 'widgetGoalsgetItemsSku',
+ 'parameters' =>
+ array (
+ 'module' => 'Goals',
+ 'action' => 'getItemsSku',
+ ),
+ ), array (
+ 'name' => 'Product Category',
+ 'uniqueId' => 'widgetGoalsgetItemsCategory',
+ 'parameters' =>
+ array (
+ 'module' => 'Goals',
+ 'action' => 'getItemsCategory',
+ ),
+ ),
+ );
+ }
+
/**
* This is a list of all widgets that we consider API. We need to make sure the widgets will be still renderable
* etc.
* @return array
*/
- public function getWidgetsThatAreAPI()
+ public function getWidgetsThatAreDeprecatedButStillAPI()
{
- return array (
- array (
- 'name' => 'Visits by Server Time',
- 'uniqueId' => 'widgetVisitTimegetVisitInformationPerServerTime',
- 'parameters' =>
- array (
- 'module' => 'VisitTime',
- 'action' => 'getVisitInformationPerServerTime',
- ),
- ),
- array (
- 'name' => 'Visits by Local Time',
- 'uniqueId' => 'widgetVisitTimegetVisitInformationPerLocalTime',
- 'parameters' =>
- array (
- 'module' => 'VisitTime',
- 'action' => 'getVisitInformationPerLocalTime',
- ),
- ),
- array (
- 'name' => 'Visits by Day of Week',
- 'uniqueId' => 'widgetVisitTimegetByDayOfWeek',
- 'parameters' =>
- array (
- 'module' => 'VisitTime',
- 'action' => 'getByDayOfWeek',
- ),
- ),
- array (
- 'name' => 'Visits Over Time',
- 'uniqueId' => 'widgetVisitsSummarygetEvolutionGraphcolumnsArray',
- 'parameters' =>
- array (
- 'module' => 'VisitsSummary',
- 'action' => 'getEvolutionGraph',
- 'columns' =>
- array (
- 0 => 'nb_visits',
- ),
- ),
- ),
- array (
- 'name' => 'Visits Overview',
- 'uniqueId' => 'widgetVisitsSummarygetSparklines',
- 'parameters' =>
- array (
- 'module' => 'VisitsSummary',
- 'action' => 'getSparklines',
- ),
- ),
- array (
- 'name' => 'Visits Overview (with graph)',
- 'uniqueId' => 'widgetVisitsSummaryindex',
- 'parameters' =>
- array (
- 'module' => 'VisitsSummary',
- 'action' => 'index',
- ),
- ),
- array (
- 'name' => 'Real-time Map',
- 'uniqueId' => 'widgetUserCountryMaprealtimeMap',
- 'parameters' =>
- array (
- 'module' => 'UserCountryMap',
- 'action' => 'realtimeMap',
- ),
- ),
- array (
- 'name' => 'Visitor Log',
- 'uniqueId' => 'widgetLivegetVisitorLogsmall1',
- 'parameters' =>
- array (
- 'module' => 'Live',
- 'action' => 'getVisitorLog',
- 'small' => 1,
- ),
- ),
- array (
- 'name' => 'Real Time Visitor Count',
- 'uniqueId' => 'widgetLivegetSimpleLastVisitCount',
- 'parameters' =>
- array (
- 'module' => 'Live',
- 'action' => 'getSimpleLastVisitCount',
- ),
- ),
- array (
- 'name' => 'Visitors in Real-time',
- 'uniqueId' => 'widgetLivewidget',
- 'parameters' =>
- array (
- 'module' => 'Live',
- 'action' => 'widget',
- ),
- ),
- array (
- 'name' => 'Visitor profile',
- 'uniqueId' => 'widgetLivegetVisitorProfilePopup',
- 'parameters' =>
- array (
- 'module' => 'Live',
- 'action' => 'getVisitorProfilePopup',
- ),
- ),
- array (
- 'name' => 'Visitor Map',
- 'uniqueId' => 'widgetUserCountryMapvisitorMap',
- 'parameters' =>
- array (
- 'module' => 'UserCountryMap',
- 'action' => 'visitorMap',
- ),
- ),
- array (
- 'name' => 'Visitor Location (Country)',
- 'uniqueId' => 'widgetUserCountrygetCountry',
- 'parameters' =>
- array (
- 'module' => 'UserCountry',
- 'action' => 'getCountry',
- ),
- ),
- array (
- 'name' => 'Visitor Location (Continent)',
- 'uniqueId' => 'widgetUserCountrygetContinent',
- 'parameters' =>
- array (
- 'module' => 'UserCountry',
- 'action' => 'getContinent',
- ),
- ),
- array (
- 'name' => 'Visitor Location (Region)',
- 'uniqueId' => 'widgetUserCountrygetRegion',
- 'parameters' =>
- array (
- 'module' => 'UserCountry',
- 'action' => 'getRegion',
- ),
- ),
- array (
- 'name' => 'Visitor Location (City)',
- 'uniqueId' => 'widgetUserCountrygetCity',
- 'parameters' =>
- array (
- 'module' => 'UserCountry',
- 'action' => 'getCity',
- ),
- ),
- array (
- 'name' => 'Custom Variables',
- 'uniqueId' => 'widgetCustomVariablesgetCustomVariables',
- 'parameters' =>
- array (
- 'module' => 'CustomVariables',
- 'action' => 'getCustomVariables',
- ),
- ),
- array (
- 'name' => 'Length of Visits',
- 'uniqueId' => 'widgetVisitorInterestgetNumberOfVisitsPerVisitDuration',
- 'parameters' =>
- array (
- 'module' => 'VisitorInterest',
- 'action' => 'getNumberOfVisitsPerVisitDuration',
- ),
- ),
- array (
- 'name' => 'Pages per Visit',
- 'uniqueId' => 'widgetVisitorInterestgetNumberOfVisitsPerPage',
- 'parameters' =>
- array (
- 'module' => 'VisitorInterest',
- 'action' => 'getNumberOfVisitsPerPage',
- ),
- ),
- array (
- 'name' => 'Visits by Visit Number',
- 'uniqueId' => 'widgetVisitorInterestgetNumberOfVisitsByVisitCount',
- 'parameters' =>
- array (
- 'module' => 'VisitorInterest',
- 'action' => 'getNumberOfVisitsByVisitCount',
- ),
- ),
- array (
- 'name' => 'Visits by Days Since Last Visit',
- 'uniqueId' => 'widgetVisitorInterestgetNumberOfVisitsByDaysSinceLast',
- 'parameters' =>
- array (
- 'module' => 'VisitorInterest',
- 'action' => 'getNumberOfVisitsByDaysSinceLast',
- ),
- ),
- array (
- 'name' => 'Frequency Overview',
- 'uniqueId' => 'widgetVisitFrequencygetSparklines',
- 'parameters' =>
- array (
- 'module' => 'VisitFrequency',
- 'action' => 'getSparklines',
- ),
- ),
- array (
- 'name' => 'Returning Visits Over Time',
- 'uniqueId' => 'widgetVisitFrequencygetEvolutionGraphcolumnsArray',
- 'parameters' =>
- array (
- 'module' => 'VisitFrequency',
- 'action' => 'getEvolutionGraph',
- 'columns' =>
- array (
- 0 => 'nb_visits_returning',
- ),
- ),
- ),
- array (
- 'name' => 'Screen Resolution',
- 'uniqueId' => 'widgetResolutiongetResolution',
- 'parameters' =>
- array (
- 'module' => 'Resolution',
- 'action' => 'getResolution',
- ),
- ),
- array (
- 'name' => 'Browser Plugins',
- 'uniqueId' => 'widgetDevicePluginsgetPlugin',
- 'parameters' =>
- array (
- 'module' => 'DevicePlugins',
- 'action' => 'getPlugin',
- ),
- ),
- array (
- 'name' => 'Visitor Configuration',
- 'uniqueId' => 'widgetResolutiongetConfiguration',
- 'parameters' =>
- array (
- 'module' => 'Resolution',
- 'action' => 'getConfiguration',
- ),
- ),
- array (
- 'name' => 'Browser language',
- 'uniqueId' => 'widgetUserLanguagegetLanguage',
- 'parameters' =>
- array (
- 'module' => 'UserLanguage',
- 'action' => 'getLanguage',
- ),
- ),
- array (
- 'name' => 'Language code',
- 'uniqueId' => 'widgetUserLanguagegetLanguageCode',
- 'parameters' =>
- array (
- 'module' => 'UserLanguage',
- 'action' => 'getLanguageCode',
- ),
- ),
- array (
- 'name' => 'Device type',
- 'uniqueId' => 'widgetDevicesDetectiongetType',
- 'parameters' =>
- array (
- 'module' => 'DevicesDetection',
- 'action' => 'getType',
- ),
- ),
- array (
- 'name' => 'Device brand',
- 'uniqueId' => 'widgetDevicesDetectiongetBrand',
- 'parameters' =>
- array (
- 'module' => 'DevicesDetection',
- 'action' => 'getBrand',
- ),
- ),
- array (
- 'name' => 'Visitor Browser',
- 'uniqueId' => 'widgetDevicesDetectiongetBrowsers',
- 'parameters' =>
- array (
- 'module' => 'DevicesDetection',
- 'action' => 'getBrowsers',
- ),
- ),
- array (
- 'name' => 'Device model',
- 'uniqueId' => 'widgetDevicesDetectiongetModel',
- 'parameters' =>
- array (
- 'module' => 'DevicesDetection',
- 'action' => 'getModel',
- ),
- ),
- array (
- 'name' => 'Browser version',
- 'uniqueId' => 'widgetDevicesDetectiongetBrowserVersions',
- 'parameters' =>
- array (
- 'module' => 'DevicesDetection',
- 'action' => 'getBrowserVersions',
- ),
- ),
- array (
- 'name' => 'Operating System families',
- 'uniqueId' => 'widgetDevicesDetectiongetOsFamilies',
- 'parameters' =>
- array (
- 'module' => 'DevicesDetection',
- 'action' => 'getOsFamilies',
- ),
- ),
- array (
- 'name' => 'Operating System versions',
- 'uniqueId' => 'widgetDevicesDetectiongetOsVersions',
- 'parameters' =>
- array (
- 'module' => 'DevicesDetection',
- 'action' => 'getOsVersions',
- ),
- ),
- array (
- 'name' => 'Browser engines',
- 'uniqueId' => 'widgetDevicesDetectiongetBrowserEngines',
- 'parameters' =>
- array (
- 'module' => 'DevicesDetection',
- 'action' => 'getBrowserEngines',
- ),
- ),
- array (
- 'name' => 'Pages',
- 'uniqueId' => 'widgetActionsgetPageUrls',
- 'parameters' =>
- array (
- 'module' => 'Actions',
- 'action' => 'getPageUrls',
- ),
- ),
- array (
- 'name' => 'Entry Pages',
- 'uniqueId' => 'widgetActionsgetEntryPageUrls',
- 'parameters' =>
- array (
- 'module' => 'Actions',
- 'action' => 'getEntryPageUrls',
- ),
- ),
- array (
- 'name' => 'Exit Pages',
- 'uniqueId' => 'widgetActionsgetExitPageUrls',
- 'parameters' =>
- array (
- 'module' => 'Actions',
- 'action' => 'getExitPageUrls',
- ),
- ),
- array (
- 'name' => 'Page Titles',
- 'uniqueId' => 'widgetActionsgetPageTitles',
- 'parameters' =>
- array (
- 'module' => 'Actions',
- 'action' => 'getPageTitles',
- ),
- ),
- array (
- 'name' => 'Entry Page Titles',
- 'uniqueId' => 'widgetActionsgetEntryPageTitles',
- 'parameters' =>
- array (
- 'module' => 'Actions',
- 'action' => 'getEntryPageTitles',
- ),
- ),
- array (
- 'name' => 'Exit Page Titles',
- 'uniqueId' => 'widgetActionsgetExitPageTitles',
- 'parameters' =>
- array (
- 'module' => 'Actions',
- 'action' => 'getExitPageTitles',
- ),
- ),
- array (
- 'name' => 'Outlinks',
- 'uniqueId' => 'widgetActionsgetOutlinks',
- 'parameters' =>
- array (
- 'module' => 'Actions',
- 'action' => 'getOutlinks',
- ),
- ),
- array (
- 'name' => 'Downloads',
- 'uniqueId' => 'widgetActionsgetDownloads',
- 'parameters' =>
- array (
- 'module' => 'Actions',
- 'action' => 'getDownloads',
- ),
- ),
- array (
- 'name' => 'Content Name',
- 'uniqueId' => 'widgetContentsgetContentNames',
- 'parameters' =>
- array (
- 'module' => 'Contents',
- 'action' => 'getContentNames',
- ),
- ),
- array (
- 'name' => 'Content Piece',
- 'uniqueId' => 'widgetContentsgetContentPieces',
- 'parameters' =>
- array (
- 'module' => 'Contents',
- 'action' => 'getContentPieces',
- ),
- ),
- array (
- 'name' => 'Event Categories',
- 'uniqueId' => 'widgetEventsgetCategorysecondaryDimensioneventAction',
- 'parameters' =>
- array (
- 'module' => 'Events',
- 'action' => 'getCategory',
- 'secondaryDimension' => 'eventAction',
- ),
- ),
- array (
- 'name' => 'Event Actions',
- 'uniqueId' => 'widgetEventsgetActionsecondaryDimensioneventName',
- 'parameters' =>
- array (
- 'module' => 'Events',
- 'action' => 'getAction',
- 'secondaryDimension' => 'eventName',
- ),
- ),
- array (
- 'name' => 'Event Names',
- 'uniqueId' => 'widgetEventsgetNamesecondaryDimensioneventAction',
- 'parameters' =>
- array (
- 'module' => 'Events',
- 'action' => 'getName',
- 'secondaryDimension' => 'eventAction',
- ),
- ),
- array (
- 'name' => 'Site Search Keywords',
- 'uniqueId' => 'widgetActionsgetSiteSearchKeywords',
- 'parameters' =>
- array (
- 'module' => 'Actions',
- 'action' => 'getSiteSearchKeywords',
- ),
- ),
- array (
- 'name' => 'Search Keywords with No Results',
- 'uniqueId' => 'widgetActionsgetSiteSearchNoResultKeywords',
- 'parameters' =>
- array (
- 'module' => 'Actions',
- 'action' => 'getSiteSearchNoResultKeywords',
- ),
- ),
- array (
- 'name' => 'Search Categories',
- 'uniqueId' => 'widgetActionsgetSiteSearchCategories',
- 'parameters' =>
- array (
- 'module' => 'Actions',
- 'action' => 'getSiteSearchCategories',
- ),
- ),
- array (
- 'name' => 'Pages Following a Site Search',
- 'uniqueId' => 'widgetActionsgetPageUrlsFollowingSiteSearch',
- 'parameters' =>
- array (
- 'module' => 'Actions',
- 'action' => 'getPageUrlsFollowingSiteSearch',
- ),
- ),
- array (
- 'name' => 'Page Titles Following a Site Search',
- 'uniqueId' => 'widgetActionsgetPageTitlesFollowingSiteSearch',
- 'parameters' =>
- array (
- 'module' => 'Actions',
- 'action' => 'getPageTitlesFollowingSiteSearch',
- ),
- ),
- array (
- 'name' => 'Overview',
- 'uniqueId' => 'widgetReferrersgetReferrerType',
- 'parameters' =>
- array (
- 'module' => 'Referrers',
- 'action' => 'getReferrerType',
- ),
- ),
- array (
- 'name' => 'All Referrers',
- 'uniqueId' => 'widgetReferrersgetAll',
- 'parameters' =>
- array (
- 'module' => 'Referrers',
- 'action' => 'getAll',
- ),
- ),
- array (
- 'name' => 'Keywords',
- 'uniqueId' => 'widgetReferrersgetKeywords',
- 'parameters' =>
- array (
- 'module' => 'Referrers',
- 'action' => 'getKeywords',
- ),
- ),
- array (
- 'name' => 'Referrer Websites',
- 'uniqueId' => 'widgetReferrersgetWebsites',
- 'parameters' =>
- array (
- 'module' => 'Referrers',
- 'action' => 'getWebsites',
- ),
- ),
- array (
- 'name' => 'Search Engines',
- 'uniqueId' => 'widgetReferrersgetSearchEngines',
- 'parameters' =>
- array (
- 'module' => 'Referrers',
- 'action' => 'getSearchEngines',
- ),
- ),
- array (
- 'name' => 'Campaigns',
- 'uniqueId' => 'widgetReferrersgetCampaigns',
- 'parameters' =>
- array (
- 'module' => 'Referrers',
- 'action' => 'getCampaigns',
- ),
- ),
- array (
- 'name' => 'List of social networks',
- 'uniqueId' => 'widgetReferrersgetSocials',
- 'parameters' =>
- array (
- 'module' => 'Referrers',
- 'action' => 'getSocials',
- ),
- ),
- array (
- 'name' => 'Goals Overview',
- 'uniqueId' => 'widgetGoalswidgetGoalsOverview',
- 'parameters' =>
- array (
- 'module' => 'Goals',
- 'action' => 'widgetGoalsOverview',
- ),
- ),
- array (
- 'name' => 'Download Software',
- 'uniqueId' => 'widgetGoalswidgetGoalReportidGoal1',
- 'parameters' =>
- array (
- 'module' => 'Goals',
- 'action' => 'widgetGoalReport',
- 'idGoal' => '1',
- ),
- ),
- array (
- 'name' => 'Download Software2',
- 'uniqueId' => 'widgetGoalswidgetGoalReportidGoal2',
- 'parameters' =>
- array (
- 'module' => 'Goals',
- 'action' => 'widgetGoalReport',
- 'idGoal' => '2',
- ),
- ),
- array (
- 'name' => 'Opens Contact Form',
- 'uniqueId' => 'widgetGoalswidgetGoalReportidGoal3',
- 'parameters' =>
- array (
- 'module' => 'Goals',
- 'action' => 'widgetGoalReport',
- 'idGoal' => '3',
- ),
- ),
- array (
- 'name' => 'Visit Docs',
- 'uniqueId' => 'widgetGoalswidgetGoalReportidGoal4',
- 'parameters' =>
- array (
- 'module' => 'Goals',
- 'action' => 'widgetGoalReport',
- 'idGoal' => '4',
- ),
- ),
- array (
- 'name' => 'Product SKU',
- 'uniqueId' => 'widgetGoalsgetItemsSku',
- 'parameters' =>
- array (
- 'module' => 'Goals',
- 'action' => 'getItemsSku',
- ),
- ),
- array (
- 'name' => 'Product Name',
- 'uniqueId' => 'widgetGoalsgetItemsName',
- 'parameters' =>
- array (
- 'module' => 'Goals',
- 'action' => 'getItemsName',
- ),
- ),
- array (
- 'name' => 'Product Category',
- 'uniqueId' => 'widgetGoalsgetItemsCategory',
- 'parameters' =>
- array (
- 'module' => 'Goals',
- 'action' => 'getItemsCategory',
- ),
- ),
- array (
- 'name' => 'Overview',
- 'uniqueId' => 'widgetEcommercewidgetGoalReportidGoalecommerceOrder',
- 'parameters' =>
- array (
- 'module' => 'Ecommerce',
- 'action' => 'widgetGoalReport',
- 'idGoal' => 'ecommerceOrder',
- ),
- ),
+ return array(
+ array (
+ 'name' => 'Visits per server time',
+ 'uniqueId' => 'widgetVisitTimegetVisitInformationPerServerTime',
+ 'parameters' =>
+ array (
+ 'module' => 'VisitTime',
+ 'action' => 'getVisitInformationPerServerTime',
+ ),
+ ), array (
+ 'name' => 'Visits per local time',
+ 'uniqueId' => 'widgetVisitTimegetVisitInformationPerLocalTime',
+ 'parameters' =>
+ array (
+ 'module' => 'VisitTime',
+ 'action' => 'getVisitInformationPerLocalTime',
+ ),
+ ), array (
+ 'name' => 'Visits by Day of Week',
+ 'uniqueId' => 'widgetVisitTimegetByDayOfWeek',
+ 'parameters' =>
+ array (
+ 'module' => 'VisitTime',
+ 'action' => 'getByDayOfWeek',
+ ),
+ ), array (
+ 'name' => 'Visits Over Time',
+ 'uniqueId' => 'widgetVisitsSummarygetEvolutionGraphcolumnsArray',
+ 'parameters' =>
+ array (
+ 'module' => 'VisitsSummary',
+ 'action' => 'getEvolutionGraph',
+ 'columns' =>
+ array (
+ 0 => 'nb_visits',
+ ),
+ ),
+ ), array (
+ 'name' => 'Visits Overview',
+ 'uniqueId' => 'widgetVisitsSummarygetSparklines',
+ 'parameters' =>
+ array (
+ 'module' => 'VisitsSummary',
+ 'action' => 'getSparklines',
+ ),
+ ), array (
+ 'name' => 'Visits Overview (with graph)',
+ 'uniqueId' => 'widgetVisitsSummaryindex',
+ 'parameters' =>
+ array (
+ 'module' => 'VisitsSummary',
+ 'action' => 'index',
+ ),
+ ), array (
+ 'name' => 'Visitor Log',
+ 'uniqueId' => 'widgetLivegetVisitorLogsmall1',
+ 'parameters' =>
+ array (
+ 'module' => 'Live',
+ 'action' => 'getVisitorLog',
+ 'small' => 1,
+ ),
+ ), array (
+ 'name' => 'Continent',
+ 'uniqueId' => 'widgetUserCountrygetContinent',
+ 'parameters' =>
+ array (
+ 'module' => 'UserCountry',
+ 'action' => 'getContinent',
+ ),
+ ), array (
+ 'name' => 'Visits per visit duration',
+ 'uniqueId' => 'widgetVisitorInterestgetNumberOfVisitsPerVisitDuration',
+ 'parameters' =>
+ array (
+ 'module' => 'VisitorInterest',
+ 'action' => 'getNumberOfVisitsPerVisitDuration',
+ ),
+ ), array (
+ 'name' => 'Pages per Visit',
+ 'uniqueId' => 'widgetVisitorInterestgetNumberOfVisitsPerPage',
+ 'parameters' =>
+ array (
+ 'module' => 'VisitorInterest',
+ 'action' => 'getNumberOfVisitsPerPage',
+ ),
+ ), array (
+ 'name' => 'Frequency Overview',
+ 'uniqueId' => 'widgetVisitFrequencygetSparklines',
+ 'parameters' =>
+ array (
+ 'module' => 'VisitFrequency',
+ 'action' => 'getSparklines',
+ ),
+ ), array (
+ 'name' => 'Returning Visits Over Time',
+ 'uniqueId' => 'widgetVisitFrequencygetEvolutionGraphcolumnsArray',
+ 'parameters' =>
+ array (
+ 'module' => 'VisitFrequency',
+ 'action' => 'getEvolutionGraph',
+ 'columns' =>
+ array (
+ 0 => 'nb_visits_returning',
+ ),
+ ),
+ ), array (
+ 'name' => 'Browser engines',
+ 'uniqueId' => 'widgetDevicesDetectiongetBrowserEngines',
+ 'parameters' =>
+ array (
+ 'module' => 'DevicesDetection',
+ 'action' => 'getBrowserEngines',
+ ),
+ ), array (
+ 'name' => 'Content Name',
+ 'uniqueId' => 'widgetContentsgetContentNames',
+ 'parameters' =>
+ array (
+ 'module' => 'Contents',
+ 'action' => 'getContentNames',
+ ),
+ ), array (
+ 'name' => 'Content Piece',
+ 'uniqueId' => 'widgetContentsgetContentPieces',
+ 'parameters' =>
+ array (
+ 'module' => 'Contents',
+ 'action' => 'getContentPieces',
+ ),
+ ), array (
+ 'name' => 'Event Categories',
+ 'uniqueId' => 'widgetEventsgetCategorysecondaryDimensioneventAction',
+ 'parameters' =>
+ array (
+ 'module' => 'Events',
+ 'action' => 'getCategory',
+ 'secondaryDimension' => 'eventAction',
+ ),
+ ), array (
+ 'name' => 'Event Actions',
+ 'uniqueId' => 'widgetEventsgetActionsecondaryDimensioneventName',
+ 'parameters' =>
+ array (
+ 'module' => 'Events',
+ 'action' => 'getAction',
+ 'secondaryDimension' => 'eventName',
+ ),
+ ), array (
+ 'name' => 'Event Names',
+ 'uniqueId' => 'widgetEventsgetNamesecondaryDimensioneventAction',
+ 'parameters' =>
+ array (
+ 'module' => 'Events',
+ 'action' => 'getName',
+ 'secondaryDimension' => 'eventAction',
+ ),
+ ), array (
+ 'name' => 'Overview',
+ 'uniqueId' => 'widgetReferrersgetReferrerType',
+ 'parameters' =>
+ array (
+ 'module' => 'Referrers',
+ 'action' => 'getReferrerType',
+ ),
+ ), array (
+ 'name' => 'All Referrers',
+ 'uniqueId' => 'widgetReferrersgetAll',
+ 'parameters' =>
+ array (
+ 'module' => 'Referrers',
+ 'action' => 'getAll',
+ ),
+ ), array (
+ 'name' => 'List of social networks',
+ 'uniqueId' => 'widgetReferrersgetSocials',
+ 'parameters' =>
+ array (
+ 'module' => 'Referrers',
+ 'action' => 'getSocials',
+ ),
+ ), array (
+ 'name' => 'Goals Overview',
+ 'uniqueId' => 'widgetGoalswidgetGoalsOverview',
+ 'parameters' =>
+ array (
+ 'module' => 'Goals',
+ 'action' => 'widgetGoalsOverview',
+ ),
+ ), array (
+ 'name' => 'Download Software',
+ 'uniqueId' => 'widgetGoalswidgetGoalReportidGoal1',
+ 'parameters' =>
+ array (
+ 'module' => 'Goals',
+ 'action' => 'widgetGoalReport',
+ 'idGoal' => '1',
+ ),
+ ), array (
+ 'name' => 'Download Software2',
+ 'uniqueId' => 'widgetGoalswidgetGoalReportidGoal2',
+ 'parameters' =>
+ array (
+ 'module' => 'Goals',
+ 'action' => 'widgetGoalReport',
+ 'idGoal' => '2',
+ ),
+ ), array (
+ 'name' => 'Opens Contact Form',
+ 'uniqueId' => 'widgetGoalswidgetGoalReportidGoal3',
+ 'parameters' =>
+ array (
+ 'module' => 'Goals',
+ 'action' => 'widgetGoalReport',
+ 'idGoal' => '3',
+ ),
+ ), array (
+ 'name' => 'Visit Docs',
+ 'uniqueId' => 'widgetGoalswidgetGoalReportidGoal4',
+ 'parameters' =>
+ array (
+ 'module' => 'Goals',
+ 'action' => 'widgetGoalReport',
+ 'idGoal' => '4',
+ ),
+ ), array (
+ 'name' => 'Product SKU',
+ 'uniqueId' => 'widgetGoalsgetItemsSku',
+ 'parameters' =>
+ array (
+ 'module' => 'Goals',
+ 'action' => 'getItemsSku',
+ ),
+ ), array (
+ 'name' => 'Product Name',
+ 'uniqueId' => 'widgetGoalsgetItemsName',
+ 'parameters' =>
+ array (
+ 'module' => 'Goals',
+ 'action' => 'getItemsName',
+ ),
+ ), array (
+ 'name' => 'Product Category',
+ 'uniqueId' => 'widgetGoalsgetItemsCategory',
+ 'parameters' =>
+ array (
+ 'module' => 'Goals',
+ 'action' => 'getItemsCategory',
+ ),
+ ), array (
+ 'name' => 'Overview',
+ 'uniqueId' => 'widgetEcommercewidgetGoalReportidGoalecommerceOrder',
+ 'parameters' =>
+ array (
+ 'module' => 'Ecommerce',
+ 'action' => 'widgetGoalReport',
+ 'idGoal' => 'ecommerceOrder',
+ ),
+ ),
array (
'name' => 'Ecommerce Log',
'uniqueId' => 'widgetEcommercegetEcommerceLog',
@@ -858,4 +1369,4 @@ class WidgetTest extends SystemTestCase
}
-WidgetTest::$fixture = new WidgetizeFixture(); \ No newline at end of file
+WidgetTest::$fixture = new WidgetizeFixture();
diff --git a/tests/PHPUnit/Fixtures/OmniFixture.php b/tests/PHPUnit/Fixtures/OmniFixture.php
index 800a4e48bf..e37afea8db 100644
--- a/tests/PHPUnit/Fixtures/OmniFixture.php
+++ b/tests/PHPUnit/Fixtures/OmniFixture.php
@@ -99,12 +99,15 @@ class OmniFixture extends Fixture
}
}
- $this->now = $this->fixtures['Piwik\\Tests\\Fixtures\\ManySitesImportedLogsWithXssAttempts']->now;
- // make sure ManySitesImportedLogsWithXssAttempts is the first fixture
- $fixture = $this->fixtures['Piwik\\Tests\\Fixtures\\ManySitesImportedLogsWithXssAttempts'];
- unset($this->fixtures['Piwik\\Tests\\Fixtures\\ManySitesImportedLogsWithXssAttempts']);
- $this->fixtures = array_merge(array('Piwik\\Tests\\Fixtures\\ManySitesImportedLogsWithXssAttempts' => $fixture), $this->fixtures);
+ if (!empty($this->fixtures['Piwik\\Tests\\Fixtures\\ManySitesImportedLogsWithXssAttempts'])) {
+ $this->now = $this->fixtures['Piwik\\Tests\\Fixtures\\ManySitesImportedLogsWithXssAttempts']->now;
+
+ // make sure ManySitesImportedLogsWithXssAttempts is the first fixture
+ $fixture = $this->fixtures['Piwik\\Tests\\Fixtures\\ManySitesImportedLogsWithXssAttempts'];
+ unset($this->fixtures['Piwik\\Tests\\Fixtures\\ManySitesImportedLogsWithXssAttempts']);
+ $this->fixtures = array_merge(array('Piwik\\Tests\\Fixtures\\ManySitesImportedLogsWithXssAttempts' => $fixture), $this->fixtures);
+ }
}
private function adjustDateTime($dateTime, $adjustToDate)
diff --git a/tests/PHPUnit/Fixtures/UITestFixture.php b/tests/PHPUnit/Fixtures/UITestFixture.php
index 0f6f749b85..0792a4e448 100644
--- a/tests/PHPUnit/Fixtures/UITestFixture.php
+++ b/tests/PHPUnit/Fixtures/UITestFixture.php
@@ -8,6 +8,7 @@
namespace Piwik\Tests\Fixtures;
use Exception;
+use Piwik\API\Request;
use Piwik\AssetManager;
use Piwik\Access;
use Piwik\Common;
@@ -22,9 +23,6 @@ use Piwik\Plugins\UserCountry\LocationProvider;
use Piwik\Plugins\UsersManager\API as UsersManagerAPI;
use Piwik\Plugins\SitesManager\API as SitesManagerAPI;
use Piwik\Tests\Framework\Fixture;
-use Piwik\WidgetsList;
-use Piwik\Tests\Framework\OverrideLogin;
-use Piwik\Tests\Framework\TestCase\SystemTestCase;
use Piwik\Plugins\VisitsSummary\API as VisitsSummaryAPI;
use Piwik\Config as PiwikConfig;
@@ -236,10 +234,10 @@ class UITestFixture extends SqlDump
$_GET['token_auth'] = Fixture::getTokenAuth();
// collect widgets & sort them so widget order is not important
- $allWidgets = array();
- foreach (WidgetsList::get() as $category => $widgets) {
- $allWidgets = array_merge($allWidgets, $widgets);
- }
+ $allWidgets = Request::processRequest('API.getWidgetMetadata', array(
+ 'idSite' => 1
+ ));
+
usort($allWidgets, function ($lhs, $rhs) {
return strcmp($lhs['uniqueId'], $rhs['uniqueId']);
});
@@ -305,11 +303,12 @@ class UITestFixture extends SqlDump
$dashboard = array(
array(
array(
- 'uniqueId' => "widgetVisitsSummarygetEvolutionGraphcolumnsArray",
+ 'uniqueId' => "widgetVisitsSummarygetEvolutionGraphforceView1viewDataTablegraphEvolution",
'parameters' => array(
'module' => 'VisitsSummary',
'action' => 'getEvolutionGraph',
- 'columns' => 'nb_visits'
+ 'forceView' => '1',
+ 'viewDataTable' => 'graphEvolution'
)
)
),
diff --git a/tests/PHPUnit/Framework/Mock/Category/Categeories.php b/tests/PHPUnit/Framework/Mock/Category/Categeories.php
new file mode 100644
index 0000000000..a7e7f0ce01
--- /dev/null
+++ b/tests/PHPUnit/Framework/Mock/Category/Categeories.php
@@ -0,0 +1,63 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+namespace Piwik\Tests\Framework\Mock\Category;
+
+use Piwik\Category\Category;
+use Piwik\Category\Subcategory;
+use Piwik\Plugin;
+
+/**
+ * FakeCategories for UnitTests
+ * @since 3.0.0
+ */
+class Categories extends Plugin\Categories
+{
+ private $categories;
+ private $subcategories;
+
+ /**
+ * @param Category[] $categories
+ */
+ public function setCategories($categories)
+ {
+ $cats = array();
+
+ foreach ($categories as $category) {
+ $cats[$category->getId()] = $category;
+ }
+
+ $this->categories = $cats;
+ }
+
+ /**
+ * @param Subcategory[] $subcategories
+ */
+ public function setSubcategories($subcategories)
+ {
+ $this->subcategories = $subcategories;
+ }
+
+ public function getAllCategories()
+ {
+ if ($this->categories) {
+ return $this->categories;
+ }
+
+ return parent::getAllCategories();
+ }
+
+ public function getAllSubcategories()
+ {
+ if ($this->subcategories) {
+ return $this->subcategories;
+ }
+
+ return parent::getAllSubcategories();
+ }
+
+} \ No newline at end of file
diff --git a/tests/PHPUnit/Framework/TestCase/SystemTestCase.php b/tests/PHPUnit/Framework/TestCase/SystemTestCase.php
index 0dd79873ab..dbcd3671ef 100755
--- a/tests/PHPUnit/Framework/TestCase/SystemTestCase.php
+++ b/tests/PHPUnit/Framework/TestCase/SystemTestCase.php
@@ -667,13 +667,6 @@ abstract class SystemTestCase extends PHPUnit_Framework_TestCase
DbHelper::deleteArchiveTables();
}
- protected function skipWhenPhp53()
- {
- if(self::isPhpVersion53()) {
- $this->markTestSkipped('Sometimes fail on php 5.3');
- }
- }
-
public function assertHttpResponseText($expectedResponseText, $url, $message = '')
{
self::assertThat($url, new HttpResponseText($expectedResponseText), $message);
diff --git a/tests/PHPUnit/Framework/TestRequest/Response.php b/tests/PHPUnit/Framework/TestRequest/Response.php
index 0f09a25b04..b67b7d8092 100644
--- a/tests/PHPUnit/Framework/TestRequest/Response.php
+++ b/tests/PHPUnit/Framework/TestRequest/Response.php
@@ -122,10 +122,6 @@ class Response
private function normalizeEncodingPhp533($apiResponse)
{
- if (!SystemTestCase::isPhpVersion53()
- || strpos($apiResponse, '<result') === false) {
- return $apiResponse;
- }
return str_replace('&amp;#039;', "'", $apiResponse);
}
diff --git a/tests/PHPUnit/Integration/Category/CategoryListTest.php b/tests/PHPUnit/Integration/Category/CategoryListTest.php
new file mode 100644
index 0000000000..4c8cc4ec57
--- /dev/null
+++ b/tests/PHPUnit/Integration/Category/CategoryListTest.php
@@ -0,0 +1,133 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+
+namespace Piwik\Tests\Integration\Category;
+
+use Piwik\Category\Category;
+use Piwik\Category\CategoryList;
+use Piwik\Category\Subcategory;
+use Piwik\Container\StaticContainer;
+use Piwik\Db;
+use Piwik\Tests\Framework\Mock\Category\Categories;
+use Piwik\Tests\Framework\TestCase\IntegrationTestCase;
+
+require_once PIWIK_INCLUDE_PATH . '/tests/PHPUnit/Framework/Mock/Category/Categeories.php';
+
+/**
+ * @group Category
+ * @group CategoryList
+ * @group CategoryListTest
+ */
+class CategoryListTest extends IntegrationTestCase
+{
+ /**
+ * @var Categories
+ */
+ private $categories;
+
+ public function testGetAllCategoriesWithSubcategories_shouldFindCategories()
+ {
+ $list = CategoryList::get();
+
+ $this->assertSame(array(
+ 'General_Actions',
+ 'General_Visitors',
+ 'Dashboard_Dashboard',
+ 'General_MultiSitesSummary',
+ 'Referrers_Referrers',
+ 'Goals_Goals',
+ 'Goals_Ecommerce',
+ 'Live!',
+ 'ExampleUI_UiFramework'
+ ), array_keys($list->getCategories()));
+ }
+
+ public function testGetAllCategoriesWithSubcategories_shouldFindSubcategories()
+ {
+ $list = CategoryList::get();
+
+ $this->assertTrue(5 < count($list->getCategory('General_Actions')->getSubcategories()));
+ $this->assertTrue(5 < count($list->getCategory('General_Visitors')->getSubcategories()));
+ $this->assertTrue($list->getCategory('General_Actions')->hasSubcategory('General_Pages'));
+ }
+
+ public function test_getAllCategoriesWithSubcategories_shouldMergeCategoriesAndSubcategories()
+ {
+ $this->categories->setCategories(array(
+ $this->createCategory('General_Visits'),
+ $this->createCategory('General_Actions'),
+ $this->createCategory('Goals_Goals'),
+ $this->createCategory('Goals_Ecommerce'),
+ $this->createCategory('Referrers_Referrers'),
+ ));
+ $this->categories->setSubcategories(array(
+ $subcat1 = $this->createSubcategory('General_Actions', 'General_Pages'),
+ $subcat2 = $this->createSubcategory('Goals_Goals', 'General_Overview'),
+ $subcat3 = $this->createSubcategory('General_Actions', 'Actions_Downloads'),
+ $subcat4 = $this->createSubcategory('General_AnyThingNotExist', 'General_MySubcategoryId'),
+ $subcat5 = $this->createSubcategory('General_Visits', 'Visits'),
+ $subcat6 = $this->createSubcategory('Goals_Goals', '4'),
+ $subcat7 = $this->createSubcategory('General_Visits', 'General_Engagement'),
+ $subcat8 = $this->createSubcategory('Goals_Ecommerce', 'General_Overview'),
+ ));
+
+ /** @var CategoryList $list */
+ $list = CategoryList::get();
+
+ $categoryNames = array(
+ 'General_Visits',
+ 'General_Actions',
+ 'Goals_Goals',
+ 'Goals_Ecommerce',
+ 'Referrers_Referrers',
+ 'General_AnyThingNotExist' // should be created dynamically as none exists
+ );
+ $this->assertSame($categoryNames, array_keys($list->getCategories()));
+
+ $this->assertSubcategoriesInCategoryEquals(array($subcat5, $subcat7), 'General_Visits', $list);
+ $this->assertSubcategoriesInCategoryEquals(array($subcat1, $subcat3), 'General_Actions', $list);
+ $this->assertSubcategoriesInCategoryEquals(array($subcat2, $subcat6), 'Goals_Goals', $list);
+ $this->assertSubcategoriesInCategoryEquals(array($subcat8), 'Goals_Ecommerce', $list);
+ $this->assertSubcategoriesInCategoryEquals(array(), 'Referrers_Referrers', $list);
+ $this->assertSubcategoriesInCategoryEquals(array($subcat4), 'General_AnyThingNotExist', $list);
+
+ // make sure id was actually set
+ $this->assertSame('General_AnyThingNotExist', $list->getCategory('General_AnyThingNotExist')->getId());
+ }
+
+ private function assertSubcategoriesInCategoryEquals($expectedSubcategories, $categoryId, CategoryList $list)
+ {
+ $this->assertSame($expectedSubcategories, $list->getCategory($categoryId)->getSubcategories());
+ }
+
+ private function createCategory($categoryId)
+ {
+ $config = new Category();
+ $config->setId($categoryId);
+
+ return $config;
+ }
+
+ private function createSubcategory($categoryId, $subcategoryId)
+ {
+ $config = new Subcategory();
+ $config->setId($subcategoryId);
+ $config->setCategoryId($categoryId);
+
+ return $config;
+ }
+
+ public function provideContainerConfig()
+ {
+ $this->categories = new Categories(StaticContainer::get('Piwik\Plugin\Manager'));
+
+ return array(
+ 'Piwik\Plugin\Categories' => $this->categories
+ );
+ }
+}
diff --git a/tests/PHPUnit/Integration/DataTable/Filter/PivotByDimensionTest.php b/tests/PHPUnit/Integration/DataTable/Filter/PivotByDimensionTest.php
index 64ee7dac1c..dea1e7d7e9 100644
--- a/tests/PHPUnit/Integration/DataTable/Filter/PivotByDimensionTest.php
+++ b/tests/PHPUnit/Integration/DataTable/Filter/PivotByDimensionTest.php
@@ -91,7 +91,7 @@ class PivotByDimensionTest extends IntegrationTestCase
/**
* @expectedException Exception
- * @expectedExceptionMessage Unsupported pivot: No segment for dimension of report 'Resolution.Resolution_WidgetGlobalVisitors'
+ * @expectedExceptionMessage Unsupported pivot: No segment for dimension of report 'Resolution.Resolution_Configurations'
*/
public function test_construction_ShouldFail_WhenDimensionIsNotSubtableAndSegmentFetchingIsEnabledButThereIsNoSegment()
{
diff --git a/tests/PHPUnit/Integration/Menu/MenuReportingTest.php b/tests/PHPUnit/Integration/Menu/MenuReportingTest.php
deleted file mode 100644
index a9d06afa13..0000000000
--- a/tests/PHPUnit/Integration/Menu/MenuReportingTest.php
+++ /dev/null
@@ -1,80 +0,0 @@
-<?php
-/**
- * Piwik - free/libre analytics platform
- *
- * @link http://piwik.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
- */
-
-namespace Piwik\Tests\Integration\Menu;
-
-use Piwik\Plugin\Report;
-use Piwik\Piwik;
-use Piwik\Metrics;
-use Piwik\Menu\MenuReporting;
-use Piwik\Plugin\Manager as PluginManager;
-use Piwik\Tests\Framework\TestCase\IntegrationTestCase;
-
-/**
- * @group Core
- */
-class ReportingTest extends IntegrationTestCase
-{
- /**
- * @var MenuReporting
- */
- private $menu;
-
- public function setUp()
- {
- parent::setUp();
-
- PluginManager::getInstance()->unloadPlugins();
- $this->menu = MenuReporting::getInstance();
- }
-
- public function tearDown()
- {
- MenuReporting::getInstance()->unsetInstance();
- parent::tearDown();
- }
-
- public function test_getMenu_shouldBeNull_IfNoItems()
- {
- $this->assertNull($this->menu->getMenu());
- }
-
- public function test_getMenu_shouldTriggerAddItemsEvent_toBeBackwardsCompatible()
- {
- $this->loadSomePlugins();
-
- $triggered = false;
- Piwik::addAction('Menu.Reporting.addItems', function () use (&$triggered) {
- $triggered = true;
- });
-
- $this->menu->getMenu();
-
- $this->assertTrue($triggered);
- }
-
- public function test_getMenu_shouldAddMenuItemsOfReports()
- {
- $this->loadSomePlugins();
-
- $items = $this->menu->getMenu();
-
- $this->assertNotEmpty($items);
- $this->assertGreaterThan(20, $items);
- $this->assertEquals(array('General_Actions', 'General_Visitors'), array_keys($items));
- $this->assertNotEmpty($items['General_Actions']['General_Pages']);
- $this->assertEquals('menuGetPageUrls', $items['General_Actions']['General_Pages']['_url']['action']);
- }
-
- private function loadSomePlugins()
- {
- PluginManager::getInstance()->loadPlugins(array(
- 'Actions', 'DevicesDetection', 'CoreVisualizations', 'API', 'Morpheus'
- ));
- }
-}
diff --git a/tests/PHPUnit/Integration/Plugin/CategoriesTest.php b/tests/PHPUnit/Integration/Plugin/CategoriesTest.php
new file mode 100644
index 0000000000..925abc81b8
--- /dev/null
+++ b/tests/PHPUnit/Integration/Plugin/CategoriesTest.php
@@ -0,0 +1,89 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+
+namespace Piwik\Tests\Integration\Plugin;
+
+use Piwik\Category\Category;
+use Piwik\Category\Subcategory;
+use Piwik\Container\StaticContainer;
+use Piwik\Plugin\Categories;
+use Piwik\Settings\Storage;
+use Piwik\Tests\Framework\Fixture;
+use Piwik\Tests\Framework\TestCase\IntegrationTestCase;
+
+/**
+ * @group Categories
+ * @group CategoriesTest
+ */
+class CategoriesTest extends IntegrationTestCase
+{
+ /**
+ * @var Categories
+ */
+ private $categories;
+
+ public function setUp()
+ {
+ parent::setUp();
+
+ $_GET['idSite'] = 1;
+ if (!Fixture::siteCreated(1)) {
+ Fixture::createWebsite('2015-01-01 00:00:00');
+ }
+
+ $this->categories = new Categories(StaticContainer::get('Piwik\Plugin\Manager'));
+ }
+
+ public function tearDown()
+ {
+ parent::tearDown();
+ unset($_GET['idSite']);
+ }
+
+ public function test_getAllCategories_shouldOnlyFindCategories()
+ {
+ $categories = $this->categories->getAllCategories();
+
+ $this->assertGreaterThanOrEqual(4, count($categories));
+
+ foreach ($categories as $category) {
+ $this->assertTrue($category instanceof Category);
+ }
+ }
+
+ public function test_getAllCategories_shouldHaveACategoryIdDefined()
+ {
+ $categories = $this->categories->getAllCategories();
+
+ foreach ($categories as $category) {
+ $this->assertNotEmpty($category->getId());
+ }
+ }
+
+ public function test_getAllSubcategories_shouldOnlyFindSubcategories()
+ {
+ $subcategories = $this->categories->getAllSubcategories();
+
+ $this->assertGreaterThanOrEqual(10, count($subcategories));
+
+ foreach ($subcategories as $subcategory) {
+ $this->assertTrue($subcategory instanceof Subcategory);
+ $this->assertNotEmpty($subcategory->getId());
+ }
+ }
+
+ public function test_getAllSubcategories_shouldHaveACategoryIdAndSubcategoryIdDefined()
+ {
+ $subcategories = $this->categories->getAllSubcategories();
+
+ foreach ($subcategories as $subcategory) {
+ $this->assertNotEmpty($subcategory->getId());
+ $this->assertNotEmpty($subcategory->getCategoryId());
+ }
+ }
+}
diff --git a/tests/PHPUnit/Integration/Plugin/ManagerTest.php b/tests/PHPUnit/Integration/Plugin/ManagerTest.php
index 2a36d3462c..e05e3a021e 100644
--- a/tests/PHPUnit/Integration/Plugin/ManagerTest.php
+++ b/tests/PHPUnit/Integration/Plugin/ManagerTest.php
@@ -8,11 +8,14 @@
namespace Piwik\Tests\Integration\Plugin;
+use Piwik\Container\StaticContainer;
use Piwik\Db;
+use Piwik\Http\ControllerResolver;
use Piwik\Plugin;
use Piwik\Settings\Storage;
use Piwik\Cache as PiwikCache;
use Piwik\Tests\Integration\Settings\IntegrationTestCase;
+use Piwik\Widget\WidgetsList;
/**
* @group Plugin
@@ -84,6 +87,29 @@ class ManagerTest extends IntegrationTestCase
$this->assertFalse($this->manager->isPluginActivated('ExampleTheme'));
}
+ /** @see Issue https://github.com/piwik/piwik/issues/8422 */
+ public function test_ListenNotToControllerMethodEventsThatDoesNotExists()
+ {
+ foreach ($this->manager->getLoadedPlugins() as $plugin) {
+ $hooks = $plugin->getListHooksRegistered();
+ foreach ($hooks as $hook => $callback) {
+ if (0 === strpos($hook, 'Controller.')) {
+ list($controller, $module, $action) = explode('.', $hook);
+
+ try {
+ $resolver = new ControllerResolver(StaticContainer::getContainer(), new Plugin\Widgets($this->manager));
+ $params = array();
+ $controller = $resolver->getController($module, $action, $params);
+ } catch (\Exception $e) {
+ $this->fail("$hook is listening to a controller method that does not exist");
+ }
+
+ $this->assertNotEmpty($controller);
+ }
+ }
+ }
+ }
+
/**
* @dataProvider getPluginNameProvider
*/
diff --git a/tests/PHPUnit/Integration/Plugin/SettingsTest.php b/tests/PHPUnit/Integration/Plugin/SettingsTest.php
index f5ac688d31..679b84ccba 100644
--- a/tests/PHPUnit/Integration/Plugin/SettingsTest.php
+++ b/tests/PHPUnit/Integration/Plugin/SettingsTest.php
@@ -189,7 +189,6 @@ class SettingsTest extends IntegrationTestCase
public function test_getSettingsForCurrentUser_shouldReturnAllSettingsIfEnoughPermissionsAndSortThemBySettingOrder()
{
- $this->skipWhenPhp53();
$this->setSuperUser();
$this->addSystemSetting('mysystemsetting1', 'mytitle1');
diff --git a/tests/PHPUnit/Integration/Plugin/WidgetsTest.php b/tests/PHPUnit/Integration/Plugin/WidgetsTest.php
new file mode 100644
index 0000000000..185faba064
--- /dev/null
+++ b/tests/PHPUnit/Integration/Plugin/WidgetsTest.php
@@ -0,0 +1,81 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+
+namespace Piwik\Tests\Integration\Plugin;
+
+use Piwik\Container\StaticContainer;
+use Piwik\Db;
+use Piwik\Plugin\Widgets;
+use Piwik\Settings\Storage;
+use Piwik\Tests\Framework\Fixture;
+use Piwik\Tests\Framework\TestCase\IntegrationTestCase;
+use Piwik\Widget\WidgetConfig;
+use Piwik\Widget\WidgetContainerConfig;
+
+/**
+ * @group Widgets
+ * @group WidgetsTest
+ */
+class WidgetsTest extends IntegrationTestCase
+{
+ /**
+ * @var Widgets
+ */
+ private $widgets;
+
+ public function setUp()
+ {
+ parent::setUp();
+
+ $_GET['idSite'] = 1;
+ if (!Fixture::siteCreated(1)) {
+ Fixture::createWebsite('2015-01-01 00:00:00');
+ }
+
+ $this->widgets = new Widgets(StaticContainer::get('Piwik\Plugin\Manager'));
+ }
+
+ public function tearDown()
+ {
+ parent::tearDown();
+ unset($_GET['idSite']);
+ }
+
+ public function test_getWidgetContainerConfigs_shouldOnlyFindWidgetContainerConfigs()
+ {
+ $configs = $this->widgets->getWidgetContainerConfigs();
+
+ $this->assertGreaterThanOrEqual(3, count($configs));
+
+ foreach ($configs as $config) {
+ $this->assertTrue($config instanceof WidgetContainerConfig);
+ }
+ }
+
+ public function test_getWidgetConfigs_shouldFindWidgetConfigs()
+ {
+ $configs = $this->widgets->getWidgetConfigs();
+
+ $this->assertGreaterThanOrEqual(10, count($configs));
+
+ foreach ($configs as $config) {
+ $this->assertTrue($config instanceof WidgetConfig);
+ $this->assertFalse($config instanceof WidgetContainerConfig);
+ }
+ }
+
+ public function test_getWidgetConfigs_shouldSetModuleAndActionForEachConfig()
+ {
+ $configs = $this->widgets->getWidgetConfigs();
+
+ foreach ($configs as $config) {
+ $this->assertNotEmpty($config->getModule());
+ $this->assertNotEmpty($config->getAction());
+ }
+ }
+}
diff --git a/tests/PHPUnit/Integration/Report/ReportsTest.php b/tests/PHPUnit/Integration/Report/ReportsTest.php
new file mode 100644
index 0000000000..9681d73e64
--- /dev/null
+++ b/tests/PHPUnit/Integration/Report/ReportsTest.php
@@ -0,0 +1,72 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+
+namespace Piwik\Tests\Integration\Report;
+
+use Piwik\API\Proxy;
+use Piwik\Plugin\Report;
+use Piwik\Plugins\ExampleReport\Reports\GetExampleReport;
+use Piwik\Plugins\Actions\Columns\ExitPageUrl;
+use Piwik\Piwik;
+use Piwik\Metrics;
+use Piwik\Plugins\ExampleTracker\Columns\ExampleDimension;
+use Piwik\Plugins\Referrers\Columns\Keyword;
+use Piwik\Plugin\Reports;
+use Piwik\Report\ReportWidgetFactory;
+use Piwik\Translate;
+use Piwik\Plugin\Manager as PluginManager;
+use Piwik\Tests\Framework\Fixture;
+use Piwik\Tests\Framework\TestCase\IntegrationTestCase;
+use Piwik\Widget\WidgetsList;
+
+
+/**
+ * @group Core
+ */
+class ReportTest extends IntegrationTestCase
+{
+ public function test_getAllReports_shouldNotFindAReport_IfNoPluginLoaded()
+ {
+ $this->unloadAllPlugins();
+
+ $reports = new Reports();
+ $report = $reports->getAllReports();
+
+ $this->assertEquals(array(), $report);
+ }
+
+ public function test_getAllReports_ShouldFindAllAvailableReports()
+ {
+ $this->loadExampleReportPlugin();
+ $this->loadMorePlugins();
+
+ $reports = new Reports();
+ $reports = $reports->getAllReports();
+
+ $this->assertGreaterThan(20, count($reports));
+
+ foreach ($reports as $report) {
+ $this->assertInstanceOf('Piwik\Plugin\Report', $report);
+ }
+ }
+
+ private function loadExampleReportPlugin()
+ {
+ PluginManager::getInstance()->loadPlugins(array('ExampleReport'));
+ }
+
+ private function loadMorePlugins()
+ {
+ PluginManager::getInstance()->loadPlugins(array('Actions', 'DevicesDetection', 'CoreVisualizations', 'API', 'Morpheus'));
+ }
+
+ private function unloadAllPlugins()
+ {
+ PluginManager::getInstance()->unloadPlugins();
+ }
+}
diff --git a/tests/PHPUnit/Integration/ReportTest.php b/tests/PHPUnit/Integration/ReportTest.php
index b71246d36c..036516bd91 100644
--- a/tests/PHPUnit/Integration/ReportTest.php
+++ b/tests/PHPUnit/Integration/ReportTest.php
@@ -16,12 +16,13 @@ use Piwik\Piwik;
use Piwik\Metrics;
use Piwik\Plugins\ExampleTracker\Columns\ExampleDimension;
use Piwik\Plugins\Referrers\Columns\Keyword;
-use Piwik\WidgetsList;
+use Piwik\Plugin\Reports;
+use Piwik\Report\ReportWidgetFactory;
use Piwik\Translate;
-use Piwik\Menu\MenuReporting;
use Piwik\Plugin\Manager as PluginManager;
use Piwik\Tests\Framework\Fixture;
use Piwik\Tests\Framework\TestCase\IntegrationTestCase;
+use Piwik\Widget\WidgetsList;
class GetBasicReport extends Report
{
@@ -33,7 +34,7 @@ class GetBasicReport extends Report
$this->order = 20;
$this->module = 'TestPlugin';
$this->action = 'getBasicReport';
- $this->category = 'Goals_Goals';
+ $this->categoryId = 'Goals_Goals';
$this->actionToLoadSubTables = 'invalidReport';
}
}
@@ -45,8 +46,7 @@ class GetAdvancedReport extends GetBasicReport
parent::init();
$this->action = 'getAdvancedReport';
- $this->widgetTitle = 'Actions_WidgetPageTitlesFollowingSearch';
- $this->menuTitle = 'Actions_SubmenuPageTitles';
+ $this->subcategoryId = 'Actions_SubmenuPageTitles';
$this->documentation = Piwik::translate('ExampleReportDocumentation');
$this->dimension = new ExitPageUrl();
$this->metrics = array('nb_actions', 'nb_visits');
@@ -57,6 +57,12 @@ class GetAdvancedReport extends GetBasicReport
$this->constantRowsCount = true;
}
+ public function configureWidgets(WidgetsList $widgetsList, ReportWidgetFactory $factory)
+ {
+ $widget = $factory->createWidget()->setName('Actions_WidgetPageTitlesFollowingSearch');
+ $widgetsList->addWidgetConfig($widget);
+ }
+
public function set($param, $value)
{
$this->$param = $value;
@@ -114,8 +120,6 @@ class ReportTest extends IntegrationTestCase
public function tearDown()
{
- WidgetsList::getInstance()->_reset();
- MenuReporting::getInstance()->unsetInstance();
unset($_GET['idSite']);
parent::tearDown();
}
@@ -149,106 +153,13 @@ class ReportTest extends IntegrationTestCase
$this->disabledReport->checkIsEnabled();
}
- public function test_getWidgetTitle_shouldReturnNullIfNoTitleIsSet()
- {
- $this->assertNull($this->basicReport->getWidgetTitle());
- }
-
- public function test_getWidgetTitle_shouldReturnTranslatedTitleIfSet()
- {
- Translate::loadAllTranslations();
- $this->assertEquals('Page Titles Following a Site Search', $this->advancedReport->getWidgetTitle());
- Translate::reset();
- }
-
public function test_getCategory_shouldReturnTranslatedCategory()
{
Translate::loadAllTranslations();
- $this->assertEquals('Goals', $this->advancedReport->getCategory());
+ $this->assertEquals('Goals_Goals', $this->advancedReport->getCategoryId());
Translate::reset();
}
- public function test_configureWidget_shouldNotAddAWidgetIfNoWidgetTitleIsSet()
- {
- $widgets = WidgetsList::get();
- $this->assertCount(0, $widgets);
-
- $this->basicReport->configureWidget(WidgetsList::getInstance());
-
- $widgets = WidgetsList::get();
- $this->assertCount(0, $widgets);
- }
-
- public function test_configureWidget_shouldAddAWidgetIfAWidgetTitleIsSet()
- {
- $widgets = WidgetsList::get();
- $this->assertCount(0, $widgets);
-
- $this->advancedReport->configureWidget(WidgetsList::getInstance());
-
- $widgets = WidgetsList::get();
- $this->assertCount(1, $widgets);
- $this->assertEquals(array(array(
- 'name' => 'Actions_WidgetPageTitlesFollowingSearch',
- 'uniqueId' => 'widgetTestPlugingetAdvancedReport',
- 'parameters' => array('module' => 'TestPlugin', 'action' => 'getAdvancedReport')
- )), $widgets['Goals_Goals']);
- }
-
- public function test_configureWidget_shouldMixinWidgetParametersIfSet()
- {
- $widgets = WidgetsList::get();
- $this->assertCount(0, $widgets);
-
- $this->advancedReport->set('widgetParams', array('foo' => 'bar'));
- $this->advancedReport->configureWidget(WidgetsList::getInstance());
-
- $widgets = WidgetsList::get();
- $this->assertCount(1, $widgets);
- $this->assertEquals(array('module' => 'TestPlugin', 'action' => 'getAdvancedReport', 'foo' => 'bar'),
- $widgets['Goals_Goals'][0]['parameters']);
- }
-
- public function test_configureReportingMenu_shouldNotAddAMenuIfNoWidgetTitleIsSet()
- {
- $menu = MenuReporting::getInstance();
- $menuItems = $menu->getMenu();
- $this->assertNull($menuItems);
-
- $this->basicReport->configureReportingMenu($menu);
-
- $menuItems = $menu->getMenu();
- $this->assertNull($menuItems);
- }
-
- public function test_configureReportingMenu_shouldAddAMenuIfATitleIsSet()
- {
- $menu = MenuReporting::getInstance();
- $menuItems = $menu->getMenu();
- $this->assertNull($menuItems);
-
- $this->advancedReport->configureReportingMenu($menu);
-
- $menuItems = $menu->getMenu();
-
- $expected = array(
- '_tooltip' => false,
- '_order' => 20,
- '_hasSubmenu' => true,
- 'Actions_SubmenuPageTitles' => array(
- '_url' => array(
- 'module' => 'TestPlugin',
- 'action' => 'menuGetAdvancedReport'
- ),
- '_order' => 20,
- '_name' => 'Actions_SubmenuPageTitles',
- '_tooltip' => false,
- ));
-
- $this->assertCount(1, $menuItems);
- $this->assertEquals($expected, $menuItems['Goals_Goals']);
- }
-
public function test_getMetrics_shouldUseDefaultMetrics()
{
$this->assertEquals(Metrics::getDefaultMetrics(), $this->basicReport->getMetrics());
@@ -353,7 +264,8 @@ class ReportTest extends IntegrationTestCase
'conversion_rate' => 'General_ColumnConversionRate',
),
'actionToLoadSubTables' => 'invalidReport',
- 'order' => 20
+ 'order' => 20,
+ 'subcategory' => null
)
), $reports);
}
@@ -390,7 +302,8 @@ class ReportTest extends IntegrationTestCase
),
'actionToLoadSubTables' => 'GetBasicReport',
'constantRowsCount' => true,
- 'order' => '20'
+ 'order' => '20',
+ 'subcategory' => 'Actions_SubmenuPageTitles'
)
), $reports);
}
@@ -402,43 +315,20 @@ class ReportTest extends IntegrationTestCase
$module = 'ExampleReport';
$action = 'getExampleReport';
- $report = Report::factory($module, $action);
+ $report = Reports::factory($module, $action);
$this->assertInstanceOf('Piwik\Plugins\ExampleReport\Reports\GetExampleReport', $report);
$this->assertEquals($module, $report->getModule());
$this->assertEquals($action, $report->getAction());
// action ucfirst should work as well
- $report = Report::factory($module, ucfirst($action));
+ $report = Reports::factory($module, ucfirst($action));
$this->assertInstanceOf('Piwik\Plugins\ExampleReport\Reports\GetExampleReport', $report);
$this->assertEquals($module, $report->getModule());
$this->assertEquals($action, $report->getAction());
}
- public function test_getAllReports_shouldNotFindAReport_IfNoPluginLoaded()
- {
- $this->unloadAllPlugins();
-
- $report = Report::getAllReports();
-
- $this->assertEquals(array(), $report);
- }
-
- public function test_getAllReports_ShouldFindAllAvailableReports()
- {
- $this->loadExampleReportPlugin();
- $this->loadMorePlugins();
-
- $reports = Report::getAllReports();
-
- $this->assertGreaterThan(20, count($reports));
-
- foreach ($reports as $report) {
- $this->assertInstanceOf('Piwik\Plugin\Report', $report);
- }
- }
-
public function test_getSubtableDimension_ShouldReturnNullIfNoSubtableActionExists()
{
$report = new GetExampleReport();
@@ -455,7 +345,7 @@ class ReportTest extends IntegrationTestCase
{
PluginManager::getInstance()->loadPlugins(array('Referrers'));
- $report = Report::factory('Referrers', 'getSearchEngines');
+ $report = Reports::factory('Referrers', 'getSearchEngines');
$subtableDimension = $report->getSubtableDimension();
$this->assertNotNull($subtableDimension);
diff --git a/tests/PHPUnit/Integration/WidgetsListTest.php b/tests/PHPUnit/Integration/WidgetsListTest.php
index 075de8ff6a..3cafbe67a1 100644
--- a/tests/PHPUnit/Integration/WidgetsListTest.php
+++ b/tests/PHPUnit/Integration/WidgetsListTest.php
@@ -8,163 +8,164 @@
namespace Piwik\Tests\Integration;
+use Piwik\Widget\WidgetConfig;
use Piwik\Plugins\Goals\API;
use Piwik\Tests\Framework\Mock\FakeAccess;
use Piwik\Translate;
-use Piwik\WidgetsList;
+use Piwik\Widget\WidgetsList;
use Piwik\Tests\Framework\Fixture;
use Piwik\Tests\Framework\TestCase\IntegrationTestCase;
/**
- * @group WidgetsListTest
* @group Core
*/
class WidgetsListTest extends IntegrationTestCase
{
- public function testGet()
+ public function setIp()
{
- // setup the access layer
+ parent::setUp();
+
FakeAccess::$superUser = true;
+ }
+ public function testGet()
+ {
Fixture::createWebsite('2009-01-04 00:11:42');
$_GET['idSite'] = 1;
- WidgetsList::_reset();
$widgets = WidgetsList::get();
- WidgetsList::_reset();
+
+ $widgetsPerCategory = $this->getWidgetsPerCategory($widgets);
// check if each category has the right number of widgets
$numberOfWidgets = array(
- 'VisitsSummary_VisitsSummary' => 6,
- 'Live!' => 4,
- 'General_Visitors' => 11,
- 'General_VisitorSettings' => 5,
- 'General_Actions' => 10,
- 'Events_Events' => 3,
- 'Actions_SubmenuSitesearch' => 5,
- 'Referrers_Referrers' => 7,
- 'Goals_Goals' => 1,
- 'SEO' => 2,
- 'About Piwik' => 6,
- 'DevicesDetection_DevicesDetection' => 8,
- 'Insights_WidgetCategory' => 2
+ 'Dashboard_Dashboard' => 1,
+ 'General_Actions' => 15,
+ 'General_Visitors' => 34,
+ 'SEO' => 2,
+ 'Goals_Goals' => 3,
+ 'Live!' => 2,
+ 'Insights_WidgetCategory' => 2,
+ 'ExampleUI_UiFramework' => 8,
+ 'Referrers_Referrers' => 9,
+ 'About Piwik' => 7,
);
-
// number of main categories
- $this->assertEquals(count($numberOfWidgets), count($widgets));
+ $this->assertEquals(count($numberOfWidgets), count($widgetsPerCategory));
foreach ($numberOfWidgets as $category => $widgetCount) {
- $this->assertEquals($widgetCount, count($widgets[$category]), sprintf("Widget: %s", $category));
+ $this->assertEquals($widgetCount, count($widgetsPerCategory[$category]), sprintf("Widget: %s", $category));
}
}
- public function testGetWithGoals()
+ private function getWidgetsPerCategory(WidgetsList $list)
{
- // setup the access layer
- FakeAccess::$superUser = true;
+ $widgetsPerCategory = array();
+ foreach ($list->getWidgetConfigs() as $widgetConfig) {
+ $category = $widgetConfig->getCategoryId();
+ if (!isset($widgetsPerCategory[$category])) {
+ $widgetsPerCategory[$category] = array();
+ }
+
+ $widgetsPerCategory[$category][] = $widgetConfig;
+ }
+
+ return $widgetsPerCategory;
+ }
+ public function testGetWithGoals()
+ {
Fixture::createWebsite('2009-01-04 00:11:42');
- API::getInstance()->addGoal(1, 'Goal 1 - Thank you', 'title', 'Thank you', 'contains', $caseSensitive = false, $revenue = 10, $allowMultipleConversions = 1);
+
+ $initialGoalsWidgets = 3;
$_GET['idSite'] = 1;
- WidgetsList::_reset();
- $widgets = WidgetsList::get();
- WidgetsList::_reset();
+ $perCategory = $this->getWidgetsPerCategory(WidgetsList::get());
+ $this->assertEquals($initialGoalsWidgets, count($perCategory['Goals_Goals']));
- // number of main categories
- $this->assertEquals(13, count($widgets));
- // check that the goal widget was added
- $numberOfWidgets = array(
- 'Goals_Goals' => 2,
- );
+ API::getInstance()->addGoal(1, 'Goal 1 - Thank you', 'title', 'Thank you', 'contains', $caseSensitive = false, $revenue = 10, $allowMultipleConversions = 1);
- foreach ($numberOfWidgets as $category => $widgetCount) {
- $this->assertEquals($widgetCount, count($widgets[$category]));
- }
+ $perCategory = $this->getWidgetsPerCategory(WidgetsList::get());
+
+ // number of main categories
+ $this->assertEquals(10, count($perCategory));
+ $this->assertEquals($initialGoalsWidgets + 2, count($perCategory['Goals_Goals'])); // make sure widgets for that goal were added
}
public function testGetWithGoalsAndEcommerce()
{
- // setup the access layer
- FakeAccess::$superUser = true;
-
Fixture::createWebsite('2009-01-04 00:11:42', true);
API::getInstance()->addGoal(1, 'Goal 1 - Thank you', 'title', 'Thank you', 'contains', $caseSensitive = false, $revenue = 10, $allowMultipleConversions = 1);
$_GET['idSite'] = 1;
- WidgetsList::_reset();
- $widgets = WidgetsList::get();
- WidgetsList::_reset();
+ $perCategory = $this->getWidgetsPerCategory(WidgetsList::get());
// number of main categories
- $this->assertEquals(14, count($widgets));
+ $this->assertEquals(11, count($perCategory));
// check if each category has the right number of widgets
$numberOfWidgets = array(
- 'Goals_Goals' => 2,
- 'Goals_Ecommerce' => 5,
+ 'Goals_Goals' => 5,
+ 'Goals_Ecommerce' => 4,
);
foreach ($numberOfWidgets as $category => $widgetCount) {
- $this->assertEquals($widgetCount, count($widgets[$category]));
+ $this->assertEquals($widgetCount, count($perCategory[$category]));
}
}
public function testRemove()
{
- // setup the access layer
- FakeAccess::$superUser = true;
-
Fixture::createWebsite('2009-01-04 00:11:42', true);
API::getInstance()->addGoal(1, 'Goal 1 - Thank you', 'title', 'Thank you', 'contains', $caseSensitive = false, $revenue = 10, $allowMultipleConversions = 1);
$_GET['idSite'] = 1;
- WidgetsList::_reset();
- $widgets = WidgetsList::get();
+ $list = WidgetsList::get();
- $this->assertCount(14, $widgets);
- WidgetsList::remove('SEO', 'NoTeXiStInG');
+ $this->assertCount(11, $this->getWidgetsPerCategory($list));
- $widgets = WidgetsList::get();
- $this->assertCount(14, $widgets);
+ $list->remove('SEO', 'NoTeXiStInG');
- $this->assertArrayHasKey('SEO', $widgets);
- $this->assertCount(2, $widgets['SEO']);
+ $perCategory = $this->getWidgetsPerCategory($list);
+ $this->assertCount(11, $perCategory);
- WidgetsList::remove('SEO', 'SEO_SeoRankings');
- $widgets = WidgetsList::get();
+ $this->assertArrayHasKey('SEO', $perCategory);
+ $this->assertCount(2, $perCategory['SEO']);
- $this->assertCount(1, $widgets['SEO']);
+ $list->remove('SEO', 'SEO_SeoRankings');
- WidgetsList::remove('SEO');
- $widgets = WidgetsList::get();
+ $perCategory = $this->getWidgetsPerCategory($list);
+ $this->assertCount(1, $perCategory['SEO']);
- $this->assertArrayNotHasKey('SEO', $widgets);
+ $list->remove('SEO');
- WidgetsList::_reset();
+ $perCategory = $this->getWidgetsPerCategory($list);
+ $this->assertArrayNotHasKey('SEO', $perCategory);
}
public function testIsDefined()
{
- // setup the access layer
- FakeAccess::$superUser = true;
-
Translate::loadAllTranslations();
Fixture::createWebsite('2009-01-04 00:11:42', true);
$_GET['idSite'] = 1;
- WidgetsList::_reset();
- WidgetsList::add('Actions', 'Pages', 'Actions', 'getPageUrls');
+ $config = new WidgetConfig();
+ $config->setCategoryId('Actions');
+ $config->setName('Pages');
+ $config->setModule('Actions');
+ $config->setAction('getPageUrls');
+ $list = WidgetsList::get();
+ $list->addWidgetConfig($config);
- $this->assertTrue(WidgetsList::isDefined('Actions', 'getPageUrls'));
- $this->assertFalse(WidgetsList::isDefined('Actions', 'inValiD'));
+ $this->assertTrue($list->isDefined('Actions', 'getPageUrls'));
+ $this->assertFalse($list->isDefined('Actions', 'inValiD'));
Translate::reset();
}
diff --git a/tests/PHPUnit/System/ApiGetReportMetadataTest.php b/tests/PHPUnit/System/ApiGetReportMetadataTest.php
index 1270361c39..6b20309230 100755
--- a/tests/PHPUnit/System/ApiGetReportMetadataTest.php
+++ b/tests/PHPUnit/System/ApiGetReportMetadataTest.php
@@ -8,6 +8,7 @@
namespace Piwik\Tests\System;
use Piwik\API\Proxy;
+use Piwik\Cache;
use Piwik\Tests\Framework\TestCase\SystemTestCase;
use Piwik\Tests\Fixtures\ThreeGoalsOnePageview;
diff --git a/tests/PHPUnit/System/ArchiveCronTest.php b/tests/PHPUnit/System/ArchiveCronTest.php
index db722f9266..dcdf8ca5e1 100644
--- a/tests/PHPUnit/System/ArchiveCronTest.php
+++ b/tests/PHPUnit/System/ArchiveCronTest.php
@@ -78,10 +78,6 @@ class ArchiveCronTest extends SystemTestCase
public function testArchivePhpCron()
{
- if(self::isPhpVersion53()) {
- $this->markTestSkipped('Fails on PHP 5.3 once in a blue moon.');
- }
-
$this->setLastRunArchiveOptions();
$output = $this->runArchivePhpCron();
diff --git a/tests/PHPUnit/System/AutoSuggestAPITest.php b/tests/PHPUnit/System/AutoSuggestAPITest.php
index 9ab0023c2f..c1404e5757 100644
--- a/tests/PHPUnit/System/AutoSuggestAPITest.php
+++ b/tests/PHPUnit/System/AutoSuggestAPITest.php
@@ -18,6 +18,7 @@ use Piwik\Plugins\CustomVariables\Model;
use Piwik\Tests\Framework\TestCase\SystemTestCase;
use Piwik\Tests\Fixtures\ManyVisitsWithGeoIP;
use Piwik\Tracker\Cache;
+use Piwik\Cache as PiwikCache;
/**
* testing a the auto suggest API for all known segments
@@ -40,10 +41,6 @@ class AutoSuggestAPITest extends SystemTestCase
// Refresh cache for CustomVariables\Model
Cache::clearCacheGeneral();
- if(self::isPhpVersion53() && self::isTravisCI()) {
- $this->markTestSkipped("Skipping this test as it seg faults on php 5.3 (bug triggered on travis)");
- }
-
$this->runApiTests($api, $params);
}
@@ -158,6 +155,7 @@ class AutoSuggestAPITest extends SystemTestCase
{
// Refresh cache for CustomVariables\Model
Cache::clearCacheGeneral();
+ PiwikCache::getTransientCache()->flushAll();
$segments = array();
diff --git a/tests/PHPUnit/System/CliMultiTest.php b/tests/PHPUnit/System/CliMultiTest.php
index 55e95e0066..23ea2e68a3 100644
--- a/tests/PHPUnit/System/CliMultiTest.php
+++ b/tests/PHPUnit/System/CliMultiTest.php
@@ -83,7 +83,6 @@ class CliMultiTest extends SystemTestCase
public function test_request_shouldRunAsync()
{
- $this->skipWhenPhp53();
$this->assertTrue($this->cliMulti->supportsAsync);
}
@@ -143,7 +142,6 @@ class CliMultiTest extends SystemTestCase
*/
public function test_request_shouldDetectFinishOfRequest_IfNoParamsAreGiven()
{
- $this->skipWhenPhp53();
$this->cliMulti->runAsSuperUser();
$response = $this->cliMulti->request(array($this->completeUrl('')));
$this->assertStringStartsWith('Error in Piwik: Error: no website was found', $response[0]);
@@ -151,7 +149,6 @@ class CliMultiTest extends SystemTestCase
public function test_request_shouldBeAbleToRenderARegularPageInPiwik()
{
- $this->skipWhenPhp53();
Fixture::createWebsite('2014-01-01 00:00:00');
$urls = array($this->completeUrl('/?module=Widgetize&idSite=1&period=day&date=today'));
diff --git a/tests/PHPUnit/System/ManyVisitorsOneWebsiteTest.php b/tests/PHPUnit/System/ManyVisitorsOneWebsiteTest.php
index 35daba0b5d..d1301d728a 100755
--- a/tests/PHPUnit/System/ManyVisitorsOneWebsiteTest.php
+++ b/tests/PHPUnit/System/ManyVisitorsOneWebsiteTest.php
@@ -115,54 +115,48 @@ class ManyVisitorsOneWebsiteTest extends SystemTestCase
)),
);
- // Randomly fails on 5.3
- if(!self::isPhpVersion53()) {
-
- $apiToTest[] = array('Live.getLastVisitsDetails', array(
- 'idSite' => $idSite,
- 'date' => $dateString,
- 'periods' => 'month',
- 'testSuffix' => '_Live.getLastVisitsDetails_sortDesc',
- 'otherRequestParameters' => array('filter_sort_order' => 'desc', 'filter_limit' => 7)
- ));
-
- // #5950
- $apiToTest[] = array('Live.getLastVisitsDetails', array(
- 'idSite' => $idSite,
- 'date' => $dateString,
- 'periods' => 'month',
- 'testSuffix' => '_Live.getLastVisitsDetails_sortByIdVisit',
- 'otherRequestParameters' => array('filter_sort_order' => 'desc', 'filter_sort_column' => 'idVisit', 'filter_limit' => 7)
- ));
-
- // #7458
- $apiToTest[] = array('Live.getLastVisitsDetails', array(
- 'idSite' => $idSite,
- 'date' => $dateString,
- 'periods' => 'month',
- 'testSuffix' => '_Live.getLastVisitsDetails_offsetAndLimit_1',
- 'otherRequestParameters' => array('filter_offset' => '1', 'filter_limit' => 3)
- ));
- $apiToTest[] = array('Live.getLastVisitsDetails', array(
- 'idSite' => $idSite,
- 'date' => $dateString,
- 'periods' => 'month',
- 'testSuffix' => '_Live.getLastVisitsDetails_offsetAndLimit_2',
- 'otherRequestParameters' => array('filter_offset' => '4', 'filter_limit' => 3)
- ));
-
- // #8324
- // testing filter_excludelowpop and filter_excludelowpop_value
- $apiToTest[] = array('UserCountry.getCountry', array(
- 'idSite' => $idSite,
- 'date' => $dateString,
- 'periods' => 'month',
- 'testSuffix' => '_getCountry_with_filter_excludelowpop',
- 'otherRequestParameters' => array('filter_excludelowpop' => 'nb_visits', 'filter_excludelowpop_value' => 5)
- ));
-
-
- }
+ $apiToTest[] = array('Live.getLastVisitsDetails', array(
+ 'idSite' => $idSite,
+ 'date' => $dateString,
+ 'periods' => 'month',
+ 'testSuffix' => '_Live.getLastVisitsDetails_sortDesc',
+ 'otherRequestParameters' => array('filter_sort_order' => 'desc', 'filter_limit' => 7)
+ ));
+
+ // #5950
+ $apiToTest[] = array('Live.getLastVisitsDetails', array(
+ 'idSite' => $idSite,
+ 'date' => $dateString,
+ 'periods' => 'month',
+ 'testSuffix' => '_Live.getLastVisitsDetails_sortByIdVisit',
+ 'otherRequestParameters' => array('filter_sort_order' => 'desc', 'filter_sort_column' => 'idVisit', 'filter_limit' => 7)
+ ));
+
+ // #7458
+ $apiToTest[] = array('Live.getLastVisitsDetails', array(
+ 'idSite' => $idSite,
+ 'date' => $dateString,
+ 'periods' => 'month',
+ 'testSuffix' => '_Live.getLastVisitsDetails_offsetAndLimit_1',
+ 'otherRequestParameters' => array('filter_offset' => '1', 'filter_limit' => 3)
+ ));
+ $apiToTest[] = array('Live.getLastVisitsDetails', array(
+ 'idSite' => $idSite,
+ 'date' => $dateString,
+ 'periods' => 'month',
+ 'testSuffix' => '_Live.getLastVisitsDetails_offsetAndLimit_2',
+ 'otherRequestParameters' => array('filter_offset' => '4', 'filter_limit' => 3)
+ ));
+
+ // #8324
+ // testing filter_excludelowpop and filter_excludelowpop_value
+ $apiToTest[] = array('UserCountry.getCountry', array(
+ 'idSite' => $idSite,
+ 'date' => $dateString,
+ 'periods' => 'month',
+ 'testSuffix' => '_getCountry_with_filter_excludelowpop',
+ 'otherRequestParameters' => array('filter_excludelowpop' => 'nb_visits', 'filter_excludelowpop_value' => 5)
+ ));
// this also fails on all PHP versions, it seems randomly.
// $apiToTest[] = array('Live.getLastVisitsDetails', array(
diff --git a/tests/PHPUnit/System/PivotByQueryParamTest.php b/tests/PHPUnit/System/PivotByQueryParamTest.php
index 099f82fcf6..f30fd5c555 100644
--- a/tests/PHPUnit/System/PivotByQueryParamTest.php
+++ b/tests/PHPUnit/System/PivotByQueryParamTest.php
@@ -198,10 +198,6 @@ class PivotByQueryParamTest extends SystemTestCase
}
public function assertApiResponseEqualsExpected($apiMethod, $queryParams)
{
- if(self::isPhpVersion53()) {
- // 5.3.3 space encoding fail eg. https://travis-ci.org/piwik/piwik/jobs/35920420
- $this->markTestSkipped();
- }
parent::assertApiResponseEqualsExpected($apiMethod, $queryParams);
}
}
diff --git a/tests/PHPUnit/System/TwoVisitorsTwoWebsitesDifferentDaysArchivingDisabledTest.php b/tests/PHPUnit/System/TwoVisitorsTwoWebsitesDifferentDaysArchivingDisabledTest.php
index 5e4c04a7d8..ae4c167010 100755
--- a/tests/PHPUnit/System/TwoVisitorsTwoWebsitesDifferentDaysArchivingDisabledTest.php
+++ b/tests/PHPUnit/System/TwoVisitorsTwoWebsitesDifferentDaysArchivingDisabledTest.php
@@ -26,9 +26,6 @@ class TwoVisitorsTwoWebsitesDifferentDaysArchivingDisabledTest extends SystemTes
*/
public function testApi($api, $params)
{
- if (self::isPhpVersion53() && self::isTravisCI()) {
- $this->markTestSkipped("Skipping this test as it often fails on travis)");
- }
$this->runApiTests($api, $params);
}
diff --git a/tests/PHPUnit/System/TwoVisitorsTwoWebsitesDifferentDaysConversionsTest.php b/tests/PHPUnit/System/TwoVisitorsTwoWebsitesDifferentDaysConversionsTest.php
index c02023d7cb..cf22ba95cb 100755
--- a/tests/PHPUnit/System/TwoVisitorsTwoWebsitesDifferentDaysConversionsTest.php
+++ b/tests/PHPUnit/System/TwoVisitorsTwoWebsitesDifferentDaysConversionsTest.php
@@ -36,8 +36,6 @@ class TwoVisitorsTwoWebsitesDifferentDaysConversionsTest extends SystemTestCase
*/
public function testApi($api, $params)
{
- $this->markTestSkippedOnPhp53();
-
$this->runApiTests($api, $params);
}
@@ -124,8 +122,6 @@ class TwoVisitorsTwoWebsitesDifferentDaysConversionsTest extends SystemTestCase
// plugins is non-trivial, so not done now.
public function test_Archive_getNumeric_ReturnsMetricsFromDifferentPlugins_WhenThoseMetricsAreRequested()
{
- $this->markTestSkippedOnPhp53();
-
// Tests that getting a visits summary metric (nb_visits) & a Goal's metric (Goal_revenue)
// at the same time works.
$dateTimeRange = '2010-01-03,2010-01-06';
@@ -147,8 +143,6 @@ class TwoVisitorsTwoWebsitesDifferentDaysConversionsTest extends SystemTestCase
// plugins is non-trivial, so not done now.
public function test_Archive_getNumeric_shouldInvalidateRememberedReportsOncePerRequestIfNeeded()
{
- $this->markTestSkippedOnPhp53();
-
// Tests that getting a visits summary metric (nb_visits) & a Goal's metric (Goal_revenue)
// at the same time works.
$dateTimeRange = '2010-01-03,2010-01-06';
@@ -217,13 +211,6 @@ class TwoVisitorsTwoWebsitesDifferentDaysConversionsTest extends SystemTestCase
{
return 'TwoVisitors_twoWebsites_differentDays_Conversions';
}
-
- private function markTestSkippedOnPhp53()
- {
- if (self::isPhpVersion53() && self::isTravisCI()) {
- $this->markTestSkipped("Skipping this test as it often fails on travis)");
- }
- }
}
TwoVisitorsTwoWebsitesDifferentDaysConversionsTest::$fixture = new TwoSitesTwoVisitorsDifferentDays();
diff --git a/tests/PHPUnit/System/TwoVisitorsTwoWebsitesDifferentDaysTest.php b/tests/PHPUnit/System/TwoVisitorsTwoWebsitesDifferentDaysTest.php
index 9e0d567e6b..43335c0e81 100755
--- a/tests/PHPUnit/System/TwoVisitorsTwoWebsitesDifferentDaysTest.php
+++ b/tests/PHPUnit/System/TwoVisitorsTwoWebsitesDifferentDaysTest.php
@@ -37,9 +37,6 @@ class TwoVisitorsTwoWebsitesDifferentDaysTest extends SystemTestCase
*/
public function testApi($api, $params)
{
- if(self::isTravisCI() && self::isPhpVersion53()) {
- $this->markTestSkipped('This test fails on travis eg. https://travis-ci.org/piwik/piwik/jobs/46944264');
- }
$this->runApiTests($api, $params);
}
diff --git a/tests/PHPUnit/System/TwoVisitsWithCustomVariablesSegmentMatchVisitorTypeTest.php b/tests/PHPUnit/System/TwoVisitsWithCustomVariablesSegmentMatchVisitorTypeTest.php
index 3a11d10668..c6e9023727 100755
--- a/tests/PHPUnit/System/TwoVisitsWithCustomVariablesSegmentMatchVisitorTypeTest.php
+++ b/tests/PHPUnit/System/TwoVisitsWithCustomVariablesSegmentMatchVisitorTypeTest.php
@@ -10,9 +10,7 @@ namespace Piwik\Tests\System;
use Piwik\Archive\Chunk;
use Piwik\Common;
use Piwik\Archive\ArchiveInvalidator;
-use Piwik\CronArchive\SitesToReprocessDistributedList;
use Piwik\Db;
-use Piwik\Piwik;
use Piwik\Tests\Framework\TestCase\SystemTestCase;
use Piwik\Tests\Fixtures\TwoVisitsWithCustomVariables;
diff --git a/tests/PHPUnit/System/expected/test_ArchiveCronTest_archive_php_cron_output.txt b/tests/PHPUnit/System/expected/test_ArchiveCronTest_archive_php_cron_output.txt
index 6bfd8b0c09..937d7d2f86 100644
--- a/tests/PHPUnit/System/expected/test_ArchiveCronTest_archive_php_cron_output.txt
+++ b/tests/PHPUnit/System/expected/test_ArchiveCronTest_archive_php_cron_output.txt
@@ -10,95 +10,79 @@ try 'php archive.php --url=http://your.piwik/path'
-------------------------------------------------------
-INFO [2015-09-21 23:00:55] ---------------------------
-INFO [2015-09-21 23:00:55] INIT
-INFO [2015-09-21 23:00:55] Running Piwik 2.15.0-b8 as Super User
-INFO [2015-09-21 23:00:55] ---------------------------
-INFO [2015-09-21 23:00:55] NOTES
-INFO [2015-09-21 23:00:55] - If you execute this script at least once per hour (or more often) in a crontab, you may disable 'Browser trigger archiving' in Piwik UI > Settings > General Settings.
-INFO [2015-09-21 23:00:55] See the doc at: http://piwik.org/docs/setup-auto-archiving/
-INFO [2015-09-21 23:00:55] - Reports for today will be processed at most every 150 seconds. You can change this value in Piwik UI > Settings > General Settings.
-INFO [2015-09-21 23:00:55] - Reports for the current week/month/year will be refreshed at most every 3600 seconds.
-INFO [2015-09-21 23:00:55] Will invalidate archived reports for 2012-08-09 for following websites ids: 1
-INFO [2015-09-21 23:00:55] Will invalidate archived reports for 2012-08-10 for following websites ids: 1
-INFO [2015-09-21 23:00:55] Will invalidate archived reports for 2012-08-11 for following websites ids: 1
-INFO [2015-09-21 23:00:55] Will invalidate archived reports for 2012-08-15 for following websites ids: 1,2,3
-INFO [2015-09-21 23:00:55] Will invalidate archived reports for 2012-09-30 for following websites ids: 1
-INFO [2015-09-21 23:00:55] Will invalidate archived reports for 2014-03-12 for following websites ids: 1,3
-INFO [2015-09-21 23:00:55] Will invalidate archived reports for 2014-03-13 for following websites ids: 1,3
-INFO [2015-09-21 23:00:55] - Will process 3 other websites because some old data reports have been invalidated (eg. using the Log Import script) , IDs: 1, 2, 3
-INFO [2015-09-21 23:00:55] ---------------------------
-INFO [2015-09-21 23:00:55] START
-INFO [2015-09-21 23:00:55] Starting Piwik reports archiving...
-INFO [2015-09-21 23:00:55] Old report was invalidated for website id 1
-INFO [2015-09-21 23:00:55] Will pre-process for website id = 1, period = day, date = last52
-INFO [2015-09-21 23:00:55] - pre-processing all visits
-INFO [2015-09-21 23:00:57] - pre-processing segment 1/3 browserCode==IE
-INFO [2015-09-21 23:00:57] - pre-processing segment 2/3 visitCount<=5;visitorType!=non-existing-type;daysSinceFirstVisit<=50
-INFO [2015-09-21 23:00:57] - pre-processing segment 3/3 visitCount<=5;visitorType!=re%2C%3Btest%20is%20encoded;daysSinceFirstVisit<=50
-INFO [2015-09-21 23:01:00] Archived website id = 1, period = day, 3 segments, 0 visits in last 52 days, 0 visits today, Time elapsed: 5.119s
-INFO [2015-09-21 23:01:00] Will pre-process for website id = 1, period = week, date = last260
-INFO [2015-09-21 23:01:00] - pre-processing all visits
-INFO [2015-09-21 23:01:00] - pre-processing segment 1/3 browserCode==IE
-INFO [2015-09-21 23:01:00] - pre-processing segment 2/3 visitCount<=5;visitorType!=non-existing-type;daysSinceFirstVisit<=50
-INFO [2015-09-21 23:01:32] - pre-processing segment 3/3 visitCount<=5;visitorType!=re%2C%3Btest%20is%20encoded;daysSinceFirstVisit<=50
-INFO [2015-09-21 23:02:02] Archived website id = 1, period = week, 3 segments, 40 visits in last 260 weeks, 0 visits this week, Time elapsed: 61.934s
-INFO [2015-09-21 23:02:02] Will pre-process for website id = 1, period = month, date = last52
-INFO [2015-09-21 23:02:02] - pre-processing all visits
-INFO [2015-09-21 23:02:02] - pre-processing segment 1/3 browserCode==IE
-INFO [2015-09-21 23:02:02] - pre-processing segment 2/3 visitCount<=5;visitorType!=non-existing-type;daysSinceFirstVisit<=50
-INFO [2015-09-21 23:02:10] - pre-processing segment 3/3 visitCount<=5;visitorType!=re%2C%3Btest%20is%20encoded;daysSinceFirstVisit<=50
-INFO [2015-09-21 23:02:17] Archived website id = 1, period = month, 3 segments, 40 visits in last 52 months, 0 visits this month, Time elapsed: 15.041s
-INFO [2015-09-21 23:02:17] Will pre-process for website id = 1, period = year, date = last7
-INFO [2015-09-21 23:02:17] - pre-processing all visits
-INFO [2015-09-21 23:02:17] - pre-processing segment 1/3 browserCode==IE
-INFO [2015-09-21 23:02:17] - pre-processing segment 2/3 visitCount<=5;visitorType!=non-existing-type;daysSinceFirstVisit<=50
-INFO [2015-09-21 23:02:20] - pre-processing segment 3/3 visitCount<=5;visitorType!=re%2C%3Btest%20is%20encoded;daysSinceFirstVisit<=50
-INFO [2015-09-21 23:02:23] Archived website id = 1, period = year, 3 segments, 40 visits in last 7 years, 0 visits this year, Time elapsed: 6.248s
-INFO [2015-09-21 23:02:23] Archived website id = 1, 16 API requests, Time elapsed: 88.352s [1/3 done]
-INFO [2015-09-21 23:02:24] Old report was invalidated for website id 2
-INFO [2015-09-21 23:02:24] Will pre-process for website id = 2, period = day, date = last52
-INFO [2015-09-21 23:02:24] - pre-processing all visits
-INFO [2015-09-21 23:02:26] Archived website id = 2, period = day, 0 segments, 0 visits in last 52 days, 0 visits today, Time elapsed: 2.241s
-INFO [2015-09-21 23:02:26] Will pre-process for website id = 2, period = week, date = last260
-INFO [2015-09-21 23:02:26] - pre-processing all visits
-INFO [2015-09-21 23:02:46] Archived website id = 2, period = week, 0 segments, 1 visits in last 260 weeks, 0 visits this week, Time elapsed: 20.727s
-INFO [2015-09-21 23:02:46] Will pre-process for website id = 2, period = month, date = last52
-INFO [2015-09-21 23:02:46] - pre-processing all visits
-INFO [2015-09-21 23:02:51] Archived website id = 2, period = month, 0 segments, 1 visits in last 52 months, 0 visits this month, Time elapsed: 4.933s
-INFO [2015-09-21 23:02:51] Will pre-process for website id = 2, period = year, date = last7
-INFO [2015-09-21 23:02:51] - pre-processing all visits
-INFO [2015-09-21 23:02:53] Archived website id = 2, period = year, 0 segments, 1 visits in last 7 years, 0 visits this year, Time elapsed: 1.760s
-INFO [2015-09-21 23:02:53] Archived website id = 2, 4 API requests, Time elapsed: 29.666s [2/3 done]
-INFO [2015-09-21 23:02:53] Old report was invalidated for website id 3
-INFO [2015-09-21 23:02:53] Will pre-process for website id = 3, period = day, date = last52
-INFO [2015-09-21 23:02:53] - pre-processing all visits
-INFO [2015-09-21 23:02:56] Archived website id = 3, period = day, 0 segments, 0 visits in last 52 days, 0 visits today, Time elapsed: 2.356s
-INFO [2015-09-21 23:02:56] Will pre-process for website id = 3, period = week, date = last260
-INFO [2015-09-21 23:02:56] - pre-processing all visits
-INFO [2015-09-21 23:03:18] Archived website id = 3, period = week, 0 segments, 15 visits in last 260 weeks, 0 visits this week, Time elapsed: 22.395s
-INFO [2015-09-21 23:03:18] Will pre-process for website id = 3, period = month, date = last52
-INFO [2015-09-21 23:03:18] - pre-processing all visits
-INFO [2015-09-21 23:03:24] Archived website id = 3, period = month, 0 segments, 15 visits in last 52 months, 0 visits this month, Time elapsed: 5.837s
-INFO [2015-09-21 23:03:24] Will pre-process for website id = 3, period = year, date = last7
-INFO [2015-09-21 23:03:24] - pre-processing all visits
-INFO [2015-09-21 23:03:27] Archived website id = 3, period = year, 0 segments, 15 visits in last 7 years, 0 visits this year, Time elapsed: 2.929s
-INFO [2015-09-21 23:03:27] Archived website id = 3, 4 API requests, Time elapsed: 33.525s [3/3 done]
-INFO [2015-09-21 23:03:27] Done archiving!
-INFO [2015-09-21 23:03:27] ---------------------------
-INFO [2015-09-21 23:03:27] SUMMARY
-INFO [2015-09-21 23:03:27] Total visits for today across archived websites: 0
-INFO [2015-09-21 23:03:27] Archived today's reports for 3 websites
-INFO [2015-09-21 23:03:27] Archived week/month/year for 3 websites
-INFO [2015-09-21 23:03:27] Skipped 0 websites
-INFO [2015-09-21 23:03:27] - 0 skipped because no new visit since the last script execution
-INFO [2015-09-21 23:03:27] - 0 skipped because existing daily reports are less than 150 seconds old
-INFO [2015-09-21 23:03:27] - 0 skipped because existing week/month/year periods reports are less than 3600 seconds old
-INFO [2015-09-21 23:03:27] Total API requests: 24
-INFO [2015-09-21 23:03:27] done: 3/3 100%, 0 vtoday, 3 wtoday, 3 wperiods, 24 req, 151815 ms, no error
-INFO [2015-09-21 23:03:27] Time elapsed: 151.815s
-INFO [2015-09-21 23:03:27] ---------------------------
-INFO [2015-09-21 23:03:27] SCHEDULED TASKS
-INFO [2015-09-21 23:03:27] Starting Scheduled tasks...
-INFO [2015-09-21 23:03:27] done
-INFO [2015-09-21 23:03:27] --------------------------- \ No newline at end of file
+INFO [2015-08-20 13:41:26] ---------------------------
+INFO [2015-08-20 13:41:26] INIT
+INFO [2015-08-20 13:41:26] Running Piwik 3.0.0-b1 as Super User
+INFO [2015-08-20 13:41:26] ---------------------------
+INFO [2015-08-20 13:41:26] NOTES
+INFO [2015-08-20 13:41:26] - If you execute this script at least once per hour (or more often) in a crontab, you may disable 'Browser trigger archiving' in Piwik UI > Settings > General Settings.
+INFO [2015-08-20 13:41:26] See the doc at: http://piwik.org/docs/setup-auto-archiving/
+INFO [2015-08-20 13:41:26] - Reports for today will be processed at most every 150 seconds. You can change this value in Piwik UI > Settings > General Settings.
+INFO [2015-08-20 13:41:26] - Reports for the current week/month/year will be refreshed at most every 3600 seconds.
+INFO [2015-08-20 13:41:26] Will invalidate archived reports for 2012-08-09 for following siteIds: 1
+INFO [2015-08-20 13:41:27] Will invalidate archived reports for 2012-08-10 for following siteIds: 1
+INFO [2015-08-20 13:41:27] Will invalidate archived reports for 2012-08-11 for following siteIds: 1
+INFO [2015-08-20 13:41:27] Will invalidate archived reports for 2012-08-15 for following siteIds: 1,2
+INFO [2015-08-20 13:41:27] Will invalidate archived reports for 2012-09-30 for following siteIds: 1
+INFO [2015-08-20 13:41:27] Will invalidate archived reports for 2014-03-12 for following siteIds: 1
+INFO [2015-08-20 13:41:27] Will invalidate archived reports for 2014-03-13 for following siteIds: 1
+INFO [2015-08-20 13:41:27] - Will process 0 websites with new visits since 7 days 0 hours
+INFO [2015-08-20 13:41:27] - Will process 2 other websites because some old data reports have been invalidated (eg. using the Log Import script) , IDs: 1, 2
+INFO [2015-08-20 13:41:27] ---------------------------
+INFO [2015-08-20 13:41:27] START
+INFO [2015-08-20 13:41:27] Starting Piwik reports archiving...
+INFO [2015-08-20 13:41:27] Will pre-process for website id = 1, period = day, date = last52
+INFO [2015-08-20 13:41:27] - pre-processing all visits
+INFO [2015-08-20 13:41:29] - pre-processing segment 1/3 browserCode==IE
+INFO [2015-08-20 13:41:29] - pre-processing segment 2/3 visitCount<=5;visitorType!=non-existing-type;daysSinceFirstVisit<=50
+INFO [2015-08-20 13:41:29] - pre-processing segment 3/3 visitCount<=5;visitorType!=re%2C%3Btest%20is%20encoded;daysSinceFirstVisit<=50
+INFO [2015-08-20 13:41:31] Archived website id = 1, period = day, 3 segments, 0 visits in last last52 days, 0 visits today, Time elapsed: 2.207s
+INFO [2015-08-20 13:41:31] Will pre-process for website id = 1, period = week, date = last260
+INFO [2015-08-20 13:41:31] - pre-processing all visits
+INFO [2015-08-20 13:41:31] - pre-processing segment 1/3 browserCode==IE
+INFO [2015-08-20 13:41:31] - pre-processing segment 2/3 visitCount<=5;visitorType!=non-existing-type;daysSinceFirstVisit<=50
+INFO [2015-08-20 13:41:56] - pre-processing segment 3/3 visitCount<=5;visitorType!=re%2C%3Btest%20is%20encoded;daysSinceFirstVisit<=50
+INFO [2015-08-20 13:42:18] Archived website id = 1, period = week, 3 segments, 40 visits in last last260 weeks, 0 visits this week, Time elapsed: 47.002s
+INFO [2015-08-20 13:42:18] Will pre-process for website id = 1, period = month, date = last52
+INFO [2015-08-20 13:42:18] - pre-processing all visits
+INFO [2015-08-20 13:42:18] - pre-processing segment 1/3 browserCode==IE
+INFO [2015-08-20 13:42:18] - pre-processing segment 2/3 visitCount<=5;visitorType!=non-existing-type;daysSinceFirstVisit<=50
+INFO [2015-08-20 13:42:24] - pre-processing segment 3/3 visitCount<=5;visitorType!=re%2C%3Btest%20is%20encoded;daysSinceFirstVisit<=50
+INFO [2015-08-20 13:42:29] Archived website id = 1, period = month, 3 segments, 40 visits in last last52 months, 0 visits this month, Time elapsed: 11.370s
+INFO [2015-08-20 13:42:29] Will pre-process for website id = 1, period = year, date = last7
+INFO [2015-08-20 13:42:29] - pre-processing all visits
+INFO [2015-08-20 13:42:29] - pre-processing segment 1/3 browserCode==IE
+INFO [2015-08-20 13:42:29] - pre-processing segment 2/3 visitCount<=5;visitorType!=non-existing-type;daysSinceFirstVisit<=50
+INFO [2015-08-20 13:42:32] - pre-processing segment 3/3 visitCount<=5;visitorType!=re%2C%3Btest%20is%20encoded;daysSinceFirstVisit<=50
+INFO [2015-08-20 13:42:34] Archived website id = 1, period = year, 3 segments, 40 visits in last last7 years, 0 visits this year, Time elapsed: 4.820s
+INFO [2015-08-20 13:42:34] Archived website id = 1, 16 API requests, Time elapsed: 67.301s [1/2 done]
+INFO [2015-08-20 13:42:34] Will pre-process for website id = 2, period = day, date = last52
+INFO [2015-08-20 13:42:34] - pre-processing all visits
+INFO [2015-08-20 13:42:36] Archived website id = 2, period = day, 0 segments, 0 visits in last last52 days, 0 visits today, Time elapsed: 0.001s
+INFO [2015-08-20 13:42:36] Will pre-process for website id = 2, period = week, date = last260
+INFO [2015-08-20 13:42:36] - pre-processing all visits
+INFO [2015-08-20 13:42:51] Archived website id = 2, period = week, 0 segments, 1 visits in last last260 weeks, 0 visits this week, Time elapsed: 15.229s
+INFO [2015-08-20 13:42:51] Will pre-process for website id = 2, period = month, date = last52
+INFO [2015-08-20 13:42:51] - pre-processing all visits
+INFO [2015-08-20 13:42:55] Archived website id = 2, period = month, 0 segments, 1 visits in last last52 months, 0 visits this month, Time elapsed: 3.790s
+INFO [2015-08-20 13:42:55] Will pre-process for website id = 2, period = year, date = last7
+INFO [2015-08-20 13:42:55] - pre-processing all visits
+INFO [2015-08-20 13:42:56] Archived website id = 2, period = year, 0 segments, 1 visits in last last7 years, 0 visits this year, Time elapsed: 1.380s
+INFO [2015-08-20 13:42:56] Archived website id = 2, 4 API requests, Time elapsed: 22.132s [2/2 done]
+INFO [2015-08-20 13:42:56] Done archiving!
+INFO [2015-08-20 13:42:56] ---------------------------
+INFO [2015-08-20 13:42:56] SUMMARY
+INFO [2015-08-20 13:42:56] Total visits for today across archived websites: 0
+INFO [2015-08-20 13:42:56] Archived today's reports for 2 websites
+INFO [2015-08-20 13:42:56] Archived week/month/year for 2 websites
+INFO [2015-08-20 13:42:56] Skipped 0 websites: no new visit since the last script execution
+INFO [2015-08-20 13:42:56] Skipped 0 websites day archiving: existing daily reports are less than 150 seconds old
+INFO [2015-08-20 13:42:56] Skipped 0 websites week/month/year archiving: existing periods reports are less than 3600 seconds old
+INFO [2015-08-20 13:42:56] Total API requests: 20
+INFO [2015-08-20 13:42:56] done: 2/2 100%, 0 vtoday, 2 wtoday, 2 wperiods, 20 req, 89599 ms, no error
+INFO [2015-08-20 13:42:56] Time elapsed: 89.600s
+INFO [2015-08-20 13:42:56] ---------------------------
+INFO [2015-08-20 13:42:56] SCHEDULED TASKS
+INFO [2015-08-20 13:42:56] Starting Scheduled tasks...
+INFO [2015-08-20 13:42:56] done
+INFO [2015-08-20 13:42:56] --------------------------- \ No newline at end of file
diff --git a/tests/PHPUnit/System/expected/test_CustomEvents_Events.getAction_flat__API.getProcessedReport_day.xml b/tests/PHPUnit/System/expected/test_CustomEvents_Events.getAction_flat__API.getProcessedReport_day.xml
index 235eb8744e..bd56600c6b 100644
--- a/tests/PHPUnit/System/expected/test_CustomEvents_Events.getAction_flat__API.getProcessedReport_day.xml
+++ b/tests/PHPUnit/System/expected/test_CustomEvents_Events.getAction_flat__API.getProcessedReport_day.xml
@@ -3,7 +3,8 @@
<website>Piwik test</website>
<prettyDate>January 3 – 9, 2010</prettyDate>
<metadata>
- <category>Events</category>
+ <category>Actions</category>
+ <subcategory>Events</subcategory>
<name>Event Actions</name>
<module>Events</module>
<action>getAction</action>
@@ -61,7 +62,7 @@
<avg_event_value>9.66</avg_event_value>
</row>
<row>
- <label>play - La fiancée de l&amp;#039;eau</label>
+ <label>play - La fiancée de l'eau</label>
<nb_events>2</nb_events>
<nb_events_with_value>0</nb_events_with_value>
<sum_event_value>0</sum_event_value>
@@ -70,7 +71,7 @@
<avg_event_value>0</avg_event_value>
</row>
<row>
- <label>play25% - La fiancée de l&amp;#039;eau</label>
+ <label>play25% - La fiancée de l'eau</label>
<nb_events>2</nb_events>
<nb_events_with_value>0</nb_events_with_value>
<sum_event_value>0</sum_event_value>
@@ -88,7 +89,7 @@
<avg_event_value>0</avg_event_value>
</row>
<row>
- <label>play50% - La fiancée de l&amp;#039;eau</label>
+ <label>play50% - La fiancée de l'eau</label>
<nb_events>2</nb_events>
<nb_events_with_value>0</nb_events_with_value>
<sum_event_value>0</sum_event_value>
@@ -106,7 +107,7 @@
<avg_event_value>0</avg_event_value>
</row>
<row>
- <label>play75% - La fiancée de l&amp;#039;eau</label>
+ <label>play75% - La fiancée de l'eau</label>
<nb_events>2</nb_events>
<nb_events_with_value>0</nb_events_with_value>
<sum_event_value>0</sum_event_value>
@@ -124,7 +125,7 @@
<avg_event_value>0</avg_event_value>
</row>
<row>
- <label>playEnd - La fiancée de l&amp;#039;eau</label>
+ <label>playEnd - La fiancée de l'eau</label>
<nb_events>2</nb_events>
<nb_events_with_value>0</nb_events_with_value>
<sum_event_value>0</sum_event_value>
@@ -187,7 +188,7 @@
<avg_event_value>0</avg_event_value>
</row>
<row>
- <label>rating - La fiancée de l&amp;#039;eau</label>
+ <label>rating - La fiancée de l'eau</label>
<nb_events>4</nb_events>
<nb_events_with_value>4</nb_events_with_value>
<sum_event_value>38</sum_event_value>
diff --git a/tests/PHPUnit/System/expected/test_CustomEvents_Events.getAction_lastN__API.getProcessedReport_day.xml b/tests/PHPUnit/System/expected/test_CustomEvents_Events.getAction_lastN__API.getProcessedReport_day.xml
index 9554b5beca..bea242a734 100644
--- a/tests/PHPUnit/System/expected/test_CustomEvents_Events.getAction_lastN__API.getProcessedReport_day.xml
+++ b/tests/PHPUnit/System/expected/test_CustomEvents_Events.getAction_lastN__API.getProcessedReport_day.xml
@@ -3,7 +3,8 @@
<website>Piwik test</website>
<prettyDate>January 3 – 9, 2010</prettyDate>
<metadata>
- <category>Events</category>
+ <category>Actions</category>
+ <subcategory>Events</subcategory>
<name>Event Actions</name>
<module>Events</module>
<action>getAction</action>
diff --git a/tests/PHPUnit/System/expected/test_CustomEvents_Events.getCategory_flat__API.getProcessedReport_day.xml b/tests/PHPUnit/System/expected/test_CustomEvents_Events.getCategory_flat__API.getProcessedReport_day.xml
index 97ac365384..98d6c9c102 100644
--- a/tests/PHPUnit/System/expected/test_CustomEvents_Events.getCategory_flat__API.getProcessedReport_day.xml
+++ b/tests/PHPUnit/System/expected/test_CustomEvents_Events.getCategory_flat__API.getProcessedReport_day.xml
@@ -3,7 +3,8 @@
<website>Piwik test</website>
<prettyDate>January 3 – 9, 2010</prettyDate>
<metadata>
- <category>Events</category>
+ <category>Actions</category>
+ <subcategory>Events</subcategory>
<name>Event Categories</name>
<module>Events</module>
<action>getCategory</action>
diff --git a/tests/PHPUnit/System/expected/test_CustomEvents_Events.getCategory_lastN__API.getProcessedReport_day.xml b/tests/PHPUnit/System/expected/test_CustomEvents_Events.getCategory_lastN__API.getProcessedReport_day.xml
index c541958923..e8f56874f1 100644
--- a/tests/PHPUnit/System/expected/test_CustomEvents_Events.getCategory_lastN__API.getProcessedReport_day.xml
+++ b/tests/PHPUnit/System/expected/test_CustomEvents_Events.getCategory_lastN__API.getProcessedReport_day.xml
@@ -3,7 +3,8 @@
<website>Piwik test</website>
<prettyDate>January 3 – 9, 2010</prettyDate>
<metadata>
- <category>Events</category>
+ <category>Actions</category>
+ <subcategory>Events</subcategory>
<name>Event Categories</name>
<module>Events</module>
<action>getCategory</action>
diff --git a/tests/PHPUnit/System/expected/test_CustomEvents_Events.getName_flat__API.getProcessedReport_day.xml b/tests/PHPUnit/System/expected/test_CustomEvents_Events.getName_flat__API.getProcessedReport_day.xml
index 6cdeaabe5a..7e7115220c 100644
--- a/tests/PHPUnit/System/expected/test_CustomEvents_Events.getName_flat__API.getProcessedReport_day.xml
+++ b/tests/PHPUnit/System/expected/test_CustomEvents_Events.getName_flat__API.getProcessedReport_day.xml
@@ -3,7 +3,8 @@
<website>Piwik test</website>
<prettyDate>January 3 – 9, 2010</prettyDate>
<metadata>
- <category>Events</category>
+ <category>Actions</category>
+ <subcategory>Events</subcategory>
<name>Event Names</name>
<module>Events</module>
<action>getName</action>
@@ -70,7 +71,7 @@
<avg_event_value>0</avg_event_value>
</row>
<row>
- <label>La fiancée de l&amp;#039;eau - play</label>
+ <label>La fiancée de l'eau - play</label>
<nb_events>2</nb_events>
<nb_events_with_value>0</nb_events_with_value>
<sum_event_value>0</sum_event_value>
@@ -79,7 +80,7 @@
<avg_event_value>0</avg_event_value>
</row>
<row>
- <label>La fiancée de l&amp;#039;eau - play25%</label>
+ <label>La fiancée de l'eau - play25%</label>
<nb_events>2</nb_events>
<nb_events_with_value>0</nb_events_with_value>
<sum_event_value>0</sum_event_value>
@@ -88,7 +89,7 @@
<avg_event_value>0</avg_event_value>
</row>
<row>
- <label>La fiancée de l&amp;#039;eau - play50%</label>
+ <label>La fiancée de l'eau - play50%</label>
<nb_events>2</nb_events>
<nb_events_with_value>0</nb_events_with_value>
<sum_event_value>0</sum_event_value>
@@ -97,7 +98,7 @@
<avg_event_value>0</avg_event_value>
</row>
<row>
- <label>La fiancée de l&amp;#039;eau - play75%</label>
+ <label>La fiancée de l'eau - play75%</label>
<nb_events>2</nb_events>
<nb_events_with_value>0</nb_events_with_value>
<sum_event_value>0</sum_event_value>
@@ -106,7 +107,7 @@
<avg_event_value>0</avg_event_value>
</row>
<row>
- <label>La fiancée de l&amp;#039;eau - playEnd</label>
+ <label>La fiancée de l'eau - playEnd</label>
<nb_events>2</nb_events>
<nb_events_with_value>0</nb_events_with_value>
<sum_event_value>0</sum_event_value>
@@ -115,7 +116,7 @@
<avg_event_value>0</avg_event_value>
</row>
<row>
- <label>La fiancée de l&amp;#039;eau - rating</label>
+ <label>La fiancée de l'eau - rating</label>
<nb_events>4</nb_events>
<nb_events_with_value>4</nb_events_with_value>
<sum_event_value>38</sum_event_value>
diff --git a/tests/PHPUnit/System/expected/test_CustomEvents_Events.getName_lastN__API.getProcessedReport_day.xml b/tests/PHPUnit/System/expected/test_CustomEvents_Events.getName_lastN__API.getProcessedReport_day.xml
index cd0dfb593d..8abd14891c 100644
--- a/tests/PHPUnit/System/expected/test_CustomEvents_Events.getName_lastN__API.getProcessedReport_day.xml
+++ b/tests/PHPUnit/System/expected/test_CustomEvents_Events.getName_lastN__API.getProcessedReport_day.xml
@@ -3,7 +3,8 @@
<website>Piwik test</website>
<prettyDate>January 3 – 9, 2010</prettyDate>
<metadata>
- <category>Events</category>
+ <category>Actions</category>
+ <subcategory>Events</subcategory>
<name>Event Names</name>
<module>Events</module>
<action>getName</action>
@@ -52,7 +53,7 @@
<avg_event_value>9.66</avg_event_value>
</row>
<row>
- <label>La fiancée de l&amp;#039;eau</label>
+ <label>La fiancée de l'eau</label>
<nb_events>14</nb_events>
<nb_events_with_value>4</nb_events_with_value>
<sum_event_value>38</sum_event_value>
diff --git a/tests/PHPUnit/System/expected/test_CustomEvents__Events.getAction_day.xml b/tests/PHPUnit/System/expected/test_CustomEvents__Events.getAction_day.xml
index 529442b5c2..67343d25f6 100644
--- a/tests/PHPUnit/System/expected/test_CustomEvents__Events.getAction_day.xml
+++ b/tests/PHPUnit/System/expected/test_CustomEvents__Events.getAction_day.xml
@@ -85,7 +85,7 @@
<segment>eventAction==play25%25</segment>
<subtable>
<row>
- <label>La fiancée de l&amp;#039;eau</label>
+ <label>La fiancée de l'eau</label>
<nb_uniq_visitors>2</nb_uniq_visitors>
<nb_visits>2</nb_visits>
<nb_events>2</nb_events>
@@ -121,7 +121,7 @@
<segment>eventAction==play50%25</segment>
<subtable>
<row>
- <label>La fiancée de l&amp;#039;eau</label>
+ <label>La fiancée de l'eau</label>
<nb_uniq_visitors>2</nb_uniq_visitors>
<nb_visits>2</nb_visits>
<nb_events>2</nb_events>
@@ -157,7 +157,7 @@
<segment>eventAction==play75%25</segment>
<subtable>
<row>
- <label>La fiancée de l&amp;#039;eau</label>
+ <label>La fiancée de l'eau</label>
<nb_uniq_visitors>2</nb_uniq_visitors>
<nb_visits>2</nb_visits>
<nb_events>2</nb_events>
@@ -193,7 +193,7 @@
<segment>eventAction==playEnd</segment>
<subtable>
<row>
- <label>La fiancée de l&amp;#039;eau</label>
+ <label>La fiancée de l'eau</label>
<nb_uniq_visitors>2</nb_uniq_visitors>
<nb_visits>2</nb_visits>
<nb_events>2</nb_events>
@@ -229,7 +229,7 @@
<segment>eventAction==rating</segment>
<subtable>
<row>
- <label>La fiancée de l&amp;#039;eau</label>
+ <label>La fiancée de l'eau</label>
<nb_uniq_visitors>2</nb_uniq_visitors>
<nb_visits>2</nb_visits>
<nb_events>4</nb_events>
@@ -315,7 +315,7 @@
<segment>eventAction==play</segment>
<subtable>
<row>
- <label>La fiancée de l&amp;#039;eau</label>
+ <label>La fiancée de l'eau</label>
<nb_uniq_visitors>2</nb_uniq_visitors>
<nb_visits>2</nb_visits>
<nb_events>2</nb_events>
diff --git a/tests/PHPUnit/System/expected/test_CustomEvents__Events.getAction_month.xml b/tests/PHPUnit/System/expected/test_CustomEvents__Events.getAction_month.xml
index 3c9792b64e..8f96e9b8f8 100644
--- a/tests/PHPUnit/System/expected/test_CustomEvents__Events.getAction_month.xml
+++ b/tests/PHPUnit/System/expected/test_CustomEvents__Events.getAction_month.xml
@@ -85,7 +85,7 @@
<segment>eventAction==play25%25</segment>
<subtable>
<row>
- <label>La fiancée de l&amp;#039;eau</label>
+ <label>La fiancée de l'eau</label>
<nb_visits>2</nb_visits>
<nb_events>2</nb_events>
<nb_events_with_value>0</nb_events_with_value>
@@ -121,7 +121,7 @@
<segment>eventAction==play50%25</segment>
<subtable>
<row>
- <label>La fiancée de l&amp;#039;eau</label>
+ <label>La fiancée de l'eau</label>
<nb_visits>2</nb_visits>
<nb_events>2</nb_events>
<nb_events_with_value>0</nb_events_with_value>
@@ -157,7 +157,7 @@
<segment>eventAction==play75%25</segment>
<subtable>
<row>
- <label>La fiancée de l&amp;#039;eau</label>
+ <label>La fiancée de l'eau</label>
<nb_visits>2</nb_visits>
<nb_events>2</nb_events>
<nb_events_with_value>0</nb_events_with_value>
@@ -193,7 +193,7 @@
<segment>eventAction==playEnd</segment>
<subtable>
<row>
- <label>La fiancée de l&amp;#039;eau</label>
+ <label>La fiancée de l'eau</label>
<nb_visits>2</nb_visits>
<nb_events>2</nb_events>
<nb_events_with_value>0</nb_events_with_value>
@@ -229,7 +229,7 @@
<segment>eventAction==rating</segment>
<subtable>
<row>
- <label>La fiancée de l&amp;#039;eau</label>
+ <label>La fiancée de l'eau</label>
<nb_visits>2</nb_visits>
<nb_events>4</nb_events>
<nb_events_with_value>4</nb_events_with_value>
@@ -315,7 +315,7 @@
<segment>eventAction==play</segment>
<subtable>
<row>
- <label>La fiancée de l&amp;#039;eau</label>
+ <label>La fiancée de l'eau</label>
<nb_visits>2</nb_visits>
<nb_events>2</nb_events>
<nb_events_with_value>0</nb_events_with_value>
diff --git a/tests/PHPUnit/System/expected/test_CustomEvents__Events.getName_day.xml b/tests/PHPUnit/System/expected/test_CustomEvents__Events.getName_day.xml
index 83e54f1311..84c1b47507 100644
--- a/tests/PHPUnit/System/expected/test_CustomEvents__Events.getName_day.xml
+++ b/tests/PHPUnit/System/expected/test_CustomEvents__Events.getName_day.xml
@@ -103,7 +103,7 @@
</subtable>
</row>
<row>
- <label>La fiancée de l&amp;#039;eau</label>
+ <label>La fiancée de l'eau</label>
<nb_uniq_visitors>12</nb_uniq_visitors>
<nb_visits>12</nb_visits>
<nb_events>14</nb_events>
diff --git a/tests/PHPUnit/System/expected/test_CustomEvents__Events.getName_month.xml b/tests/PHPUnit/System/expected/test_CustomEvents__Events.getName_month.xml
index 98c7fa3bad..141ccc652e 100644
--- a/tests/PHPUnit/System/expected/test_CustomEvents__Events.getName_month.xml
+++ b/tests/PHPUnit/System/expected/test_CustomEvents__Events.getName_month.xml
@@ -103,7 +103,7 @@
</subtable>
</row>
<row>
- <label>La fiancée de l&amp;#039;eau</label>
+ <label>La fiancée de l'eau</label>
<nb_visits>12</nb_visits>
<nb_events>14</nb_events>
<nb_events_with_value>4</nb_events_with_value>
diff --git a/tests/PHPUnit/System/expected/test_CustomEvents__Live.getLastVisitsDetails_day.xml b/tests/PHPUnit/System/expected/test_CustomEvents__Live.getLastVisitsDetails_day.xml
index 81d8899dcf..c2c4ac7f78 100644
--- a/tests/PHPUnit/System/expected/test_CustomEvents__Live.getLastVisitsDetails_day.xml
+++ b/tests/PHPUnit/System/expected/test_CustomEvents__Live.getLastVisitsDetails_day.xml
@@ -537,7 +537,7 @@
<customVariablePageValue1>should not appear in events report</customVariablePageValue1>
</row>
</customVariables>
- <eventName>La fiancée de l&amp;#039;eau</eventName>
+ <eventName>La fiancée de l'eau</eventName>
<timeSpent>60</timeSpent>
<timeSpentPretty>1 min 0s</timeSpentPretty>
<icon>plugins/Morpheus/images/event.png</icon>
@@ -557,7 +557,7 @@
<customVariablePageValue1>should not appear in events report</customVariablePageValue1>
</row>
</customVariables>
- <eventName>La fiancée de l&amp;#039;eau</eventName>
+ <eventName>La fiancée de l'eau</eventName>
<timeSpent>60</timeSpent>
<timeSpentPretty>1 min 0s</timeSpentPretty>
<icon>plugins/Morpheus/images/event.png</icon>
@@ -577,7 +577,7 @@
<customVariablePageValue1>should not appear in events report</customVariablePageValue1>
</row>
</customVariables>
- <eventName>La fiancée de l&amp;#039;eau</eventName>
+ <eventName>La fiancée de l'eau</eventName>
<timeSpent>60</timeSpent>
<timeSpentPretty>1 min 0s</timeSpentPretty>
<icon>plugins/Morpheus/images/event.png</icon>
@@ -597,7 +597,7 @@
<customVariablePageValue1>should not appear in events report</customVariablePageValue1>
</row>
</customVariables>
- <eventName>La fiancée de l&amp;#039;eau</eventName>
+ <eventName>La fiancée de l'eau</eventName>
<timeSpent>30</timeSpent>
<timeSpentPretty>30s</timeSpentPretty>
<icon>plugins/Morpheus/images/event.png</icon>
@@ -617,7 +617,7 @@
<customVariablePageValue1>should not appear in events report</customVariablePageValue1>
</row>
</customVariables>
- <eventName>La fiancée de l&amp;#039;eau</eventName>
+ <eventName>La fiancée de l'eau</eventName>
<timeSpent>30</timeSpent>
<timeSpentPretty>30s</timeSpentPretty>
<icon>plugins/Morpheus/images/event.png</icon>
@@ -637,7 +637,7 @@
<customVariablePageValue1>should not appear in events report</customVariablePageValue1>
</row>
</customVariables>
- <eventName>La fiancée de l&amp;#039;eau</eventName>
+ <eventName>La fiancée de l'eau</eventName>
<eventValue>9</eventValue>
<timeSpent>1</timeSpent>
<timeSpentPretty>1s</timeSpentPretty>
@@ -658,7 +658,7 @@
<customVariablePageValue1>should not appear in events report</customVariablePageValue1>
</row>
</customVariables>
- <eventName>La fiancée de l&amp;#039;eau</eventName>
+ <eventName>La fiancée de l'eau</eventName>
<eventValue>10</eventValue>
<timeSpent>1499</timeSpent>
<timeSpentPretty>24 min 59s</timeSpentPretty>
@@ -1369,7 +1369,7 @@
<customVariablePageValue1>should not appear in events report</customVariablePageValue1>
</row>
</customVariables>
- <eventName>La fiancée de l&amp;#039;eau</eventName>
+ <eventName>La fiancée de l'eau</eventName>
<timeSpent>60</timeSpent>
<timeSpentPretty>1 min 0s</timeSpentPretty>
<icon>plugins/Morpheus/images/event.png</icon>
@@ -1389,7 +1389,7 @@
<customVariablePageValue1>should not appear in events report</customVariablePageValue1>
</row>
</customVariables>
- <eventName>La fiancée de l&amp;#039;eau</eventName>
+ <eventName>La fiancée de l'eau</eventName>
<timeSpent>60</timeSpent>
<timeSpentPretty>1 min 0s</timeSpentPretty>
<icon>plugins/Morpheus/images/event.png</icon>
@@ -1409,7 +1409,7 @@
<customVariablePageValue1>should not appear in events report</customVariablePageValue1>
</row>
</customVariables>
- <eventName>La fiancée de l&amp;#039;eau</eventName>
+ <eventName>La fiancée de l'eau</eventName>
<timeSpent>60</timeSpent>
<timeSpentPretty>1 min 0s</timeSpentPretty>
<icon>plugins/Morpheus/images/event.png</icon>
@@ -1429,7 +1429,7 @@
<customVariablePageValue1>should not appear in events report</customVariablePageValue1>
</row>
</customVariables>
- <eventName>La fiancée de l&amp;#039;eau</eventName>
+ <eventName>La fiancée de l'eau</eventName>
<timeSpent>30</timeSpent>
<timeSpentPretty>30s</timeSpentPretty>
<icon>plugins/Morpheus/images/event.png</icon>
@@ -1449,7 +1449,7 @@
<customVariablePageValue1>should not appear in events report</customVariablePageValue1>
</row>
</customVariables>
- <eventName>La fiancée de l&amp;#039;eau</eventName>
+ <eventName>La fiancée de l'eau</eventName>
<timeSpent>30</timeSpent>
<timeSpentPretty>30s</timeSpentPretty>
<icon>plugins/Morpheus/images/event.png</icon>
@@ -1469,7 +1469,7 @@
<customVariablePageValue1>should not appear in events report</customVariablePageValue1>
</row>
</customVariables>
- <eventName>La fiancée de l&amp;#039;eau</eventName>
+ <eventName>La fiancée de l'eau</eventName>
<eventValue>9</eventValue>
<timeSpent>1</timeSpent>
<timeSpentPretty>1s</timeSpentPretty>
@@ -1490,7 +1490,7 @@
<customVariablePageValue1>should not appear in events report</customVariablePageValue1>
</row>
</customVariables>
- <eventName>La fiancée de l&amp;#039;eau</eventName>
+ <eventName>La fiancée de l'eau</eventName>
<eventValue>10</eventValue>
<timeSpent>1499</timeSpent>
<timeSpentPretty>24 min 59s</timeSpentPretty>
diff --git a/tests/PHPUnit/System/expected/test_CustomEvents__Live.getLastVisitsDetails_month.xml b/tests/PHPUnit/System/expected/test_CustomEvents__Live.getLastVisitsDetails_month.xml
index 81d8899dcf..c2c4ac7f78 100644
--- a/tests/PHPUnit/System/expected/test_CustomEvents__Live.getLastVisitsDetails_month.xml
+++ b/tests/PHPUnit/System/expected/test_CustomEvents__Live.getLastVisitsDetails_month.xml
@@ -537,7 +537,7 @@
<customVariablePageValue1>should not appear in events report</customVariablePageValue1>
</row>
</customVariables>
- <eventName>La fiancée de l&amp;#039;eau</eventName>
+ <eventName>La fiancée de l'eau</eventName>
<timeSpent>60</timeSpent>
<timeSpentPretty>1 min 0s</timeSpentPretty>
<icon>plugins/Morpheus/images/event.png</icon>
@@ -557,7 +557,7 @@
<customVariablePageValue1>should not appear in events report</customVariablePageValue1>
</row>
</customVariables>
- <eventName>La fiancée de l&amp;#039;eau</eventName>
+ <eventName>La fiancée de l'eau</eventName>
<timeSpent>60</timeSpent>
<timeSpentPretty>1 min 0s</timeSpentPretty>
<icon>plugins/Morpheus/images/event.png</icon>
@@ -577,7 +577,7 @@
<customVariablePageValue1>should not appear in events report</customVariablePageValue1>
</row>
</customVariables>
- <eventName>La fiancée de l&amp;#039;eau</eventName>
+ <eventName>La fiancée de l'eau</eventName>
<timeSpent>60</timeSpent>
<timeSpentPretty>1 min 0s</timeSpentPretty>
<icon>plugins/Morpheus/images/event.png</icon>
@@ -597,7 +597,7 @@
<customVariablePageValue1>should not appear in events report</customVariablePageValue1>
</row>
</customVariables>
- <eventName>La fiancée de l&amp;#039;eau</eventName>
+ <eventName>La fiancée de l'eau</eventName>
<timeSpent>30</timeSpent>
<timeSpentPretty>30s</timeSpentPretty>
<icon>plugins/Morpheus/images/event.png</icon>
@@ -617,7 +617,7 @@
<customVariablePageValue1>should not appear in events report</customVariablePageValue1>
</row>
</customVariables>
- <eventName>La fiancée de l&amp;#039;eau</eventName>
+ <eventName>La fiancée de l'eau</eventName>
<timeSpent>30</timeSpent>
<timeSpentPretty>30s</timeSpentPretty>
<icon>plugins/Morpheus/images/event.png</icon>
@@ -637,7 +637,7 @@
<customVariablePageValue1>should not appear in events report</customVariablePageValue1>
</row>
</customVariables>
- <eventName>La fiancée de l&amp;#039;eau</eventName>
+ <eventName>La fiancée de l'eau</eventName>
<eventValue>9</eventValue>
<timeSpent>1</timeSpent>
<timeSpentPretty>1s</timeSpentPretty>
@@ -658,7 +658,7 @@
<customVariablePageValue1>should not appear in events report</customVariablePageValue1>
</row>
</customVariables>
- <eventName>La fiancée de l&amp;#039;eau</eventName>
+ <eventName>La fiancée de l'eau</eventName>
<eventValue>10</eventValue>
<timeSpent>1499</timeSpent>
<timeSpentPretty>24 min 59s</timeSpentPretty>
@@ -1369,7 +1369,7 @@
<customVariablePageValue1>should not appear in events report</customVariablePageValue1>
</row>
</customVariables>
- <eventName>La fiancée de l&amp;#039;eau</eventName>
+ <eventName>La fiancée de l'eau</eventName>
<timeSpent>60</timeSpent>
<timeSpentPretty>1 min 0s</timeSpentPretty>
<icon>plugins/Morpheus/images/event.png</icon>
@@ -1389,7 +1389,7 @@
<customVariablePageValue1>should not appear in events report</customVariablePageValue1>
</row>
</customVariables>
- <eventName>La fiancée de l&amp;#039;eau</eventName>
+ <eventName>La fiancée de l'eau</eventName>
<timeSpent>60</timeSpent>
<timeSpentPretty>1 min 0s</timeSpentPretty>
<icon>plugins/Morpheus/images/event.png</icon>
@@ -1409,7 +1409,7 @@
<customVariablePageValue1>should not appear in events report</customVariablePageValue1>
</row>
</customVariables>
- <eventName>La fiancée de l&amp;#039;eau</eventName>
+ <eventName>La fiancée de l'eau</eventName>
<timeSpent>60</timeSpent>
<timeSpentPretty>1 min 0s</timeSpentPretty>
<icon>plugins/Morpheus/images/event.png</icon>
@@ -1429,7 +1429,7 @@
<customVariablePageValue1>should not appear in events report</customVariablePageValue1>
</row>
</customVariables>
- <eventName>La fiancée de l&amp;#039;eau</eventName>
+ <eventName>La fiancée de l'eau</eventName>
<timeSpent>30</timeSpent>
<timeSpentPretty>30s</timeSpentPretty>
<icon>plugins/Morpheus/images/event.png</icon>
@@ -1449,7 +1449,7 @@
<customVariablePageValue1>should not appear in events report</customVariablePageValue1>
</row>
</customVariables>
- <eventName>La fiancée de l&amp;#039;eau</eventName>
+ <eventName>La fiancée de l'eau</eventName>
<timeSpent>30</timeSpent>
<timeSpentPretty>30s</timeSpentPretty>
<icon>plugins/Morpheus/images/event.png</icon>
@@ -1469,7 +1469,7 @@
<customVariablePageValue1>should not appear in events report</customVariablePageValue1>
</row>
</customVariables>
- <eventName>La fiancée de l&amp;#039;eau</eventName>
+ <eventName>La fiancée de l'eau</eventName>
<eventValue>9</eventValue>
<timeSpent>1</timeSpent>
<timeSpentPretty>1s</timeSpentPretty>
@@ -1490,7 +1490,7 @@
<customVariablePageValue1>should not appear in events report</customVariablePageValue1>
</row>
</customVariables>
- <eventName>La fiancée de l&amp;#039;eau</eventName>
+ <eventName>La fiancée de l'eau</eventName>
<eventValue>10</eventValue>
<timeSpent>1499</timeSpent>
<timeSpentPretty>24 min 59s</timeSpentPretty>
diff --git a/tests/PHPUnit/System/expected/test_CustomEvents_eventCategoryOrNameMatch__Events.getAction_day.xml b/tests/PHPUnit/System/expected/test_CustomEvents_eventCategoryOrNameMatch__Events.getAction_day.xml
index beb7e00c22..1ae34d2b69 100644
--- a/tests/PHPUnit/System/expected/test_CustomEvents_eventCategoryOrNameMatch__Events.getAction_day.xml
+++ b/tests/PHPUnit/System/expected/test_CustomEvents_eventCategoryOrNameMatch__Events.getAction_day.xml
@@ -85,7 +85,7 @@
<segment>eventAction==play25%25</segment>
<subtable>
<row>
- <label>La fiancée de l&amp;#039;eau</label>
+ <label>La fiancée de l'eau</label>
<nb_uniq_visitors>2</nb_uniq_visitors>
<nb_visits>2</nb_visits>
<nb_events>2</nb_events>
@@ -121,7 +121,7 @@
<segment>eventAction==play50%25</segment>
<subtable>
<row>
- <label>La fiancée de l&amp;#039;eau</label>
+ <label>La fiancée de l'eau</label>
<nb_uniq_visitors>2</nb_uniq_visitors>
<nb_visits>2</nb_visits>
<nb_events>2</nb_events>
@@ -157,7 +157,7 @@
<segment>eventAction==play75%25</segment>
<subtable>
<row>
- <label>La fiancée de l&amp;#039;eau</label>
+ <label>La fiancée de l'eau</label>
<nb_uniq_visitors>2</nb_uniq_visitors>
<nb_visits>2</nb_visits>
<nb_events>2</nb_events>
@@ -193,7 +193,7 @@
<segment>eventAction==playEnd</segment>
<subtable>
<row>
- <label>La fiancée de l&amp;#039;eau</label>
+ <label>La fiancée de l'eau</label>
<nb_uniq_visitors>2</nb_uniq_visitors>
<nb_visits>2</nb_visits>
<nb_events>2</nb_events>
@@ -229,7 +229,7 @@
<segment>eventAction==rating</segment>
<subtable>
<row>
- <label>La fiancée de l&amp;#039;eau</label>
+ <label>La fiancée de l'eau</label>
<nb_uniq_visitors>2</nb_uniq_visitors>
<nb_visits>2</nb_visits>
<nb_events>4</nb_events>
@@ -290,7 +290,7 @@
<segment>eventAction==play</segment>
<subtable>
<row>
- <label>La fiancée de l&amp;#039;eau</label>
+ <label>La fiancée de l'eau</label>
<nb_uniq_visitors>2</nb_uniq_visitors>
<nb_visits>2</nb_visits>
<nb_events>2</nb_events>
diff --git a/tests/PHPUnit/System/expected/test_CustomEvents_eventCategoryOrNameMatch__Events.getName_day.xml b/tests/PHPUnit/System/expected/test_CustomEvents_eventCategoryOrNameMatch__Events.getName_day.xml
index ba1b7c0cb4..5b4b604c43 100644
--- a/tests/PHPUnit/System/expected/test_CustomEvents_eventCategoryOrNameMatch__Events.getName_day.xml
+++ b/tests/PHPUnit/System/expected/test_CustomEvents_eventCategoryOrNameMatch__Events.getName_day.xml
@@ -103,7 +103,7 @@
</subtable>
</row>
<row>
- <label>La fiancée de l&amp;#039;eau</label>
+ <label>La fiancée de l'eau</label>
<nb_uniq_visitors>12</nb_uniq_visitors>
<nb_visits>12</nb_visits>
<nb_events>14</nb_events>
diff --git a/tests/PHPUnit/System/expected/test_CustomEvents_secondaryDimensionIsEventAction__Events.getName_day.xml b/tests/PHPUnit/System/expected/test_CustomEvents_secondaryDimensionIsEventAction__Events.getName_day.xml
index 83e54f1311..84c1b47507 100644
--- a/tests/PHPUnit/System/expected/test_CustomEvents_secondaryDimensionIsEventAction__Events.getName_day.xml
+++ b/tests/PHPUnit/System/expected/test_CustomEvents_secondaryDimensionIsEventAction__Events.getName_day.xml
@@ -103,7 +103,7 @@
</subtable>
</row>
<row>
- <label>La fiancée de l&amp;#039;eau</label>
+ <label>La fiancée de l'eau</label>
<nb_uniq_visitors>12</nb_uniq_visitors>
<nb_visits>12</nb_visits>
<nb_events>14</nb_events>
diff --git a/tests/PHPUnit/System/expected/test_CustomEvents_secondaryDimensionIsEventAction__Events.getName_month.xml b/tests/PHPUnit/System/expected/test_CustomEvents_secondaryDimensionIsEventAction__Events.getName_month.xml
index 98c7fa3bad..141ccc652e 100644
--- a/tests/PHPUnit/System/expected/test_CustomEvents_secondaryDimensionIsEventAction__Events.getName_month.xml
+++ b/tests/PHPUnit/System/expected/test_CustomEvents_secondaryDimensionIsEventAction__Events.getName_month.xml
@@ -103,7 +103,7 @@
</subtable>
</row>
<row>
- <label>La fiancée de l&amp;#039;eau</label>
+ <label>La fiancée de l'eau</label>
<nb_visits>12</nb_visits>
<nb_events>14</nb_events>
<nb_events_with_value>4</nb_events_with_value>
diff --git a/tests/PHPUnit/System/expected/test_CustomEvents_secondaryDimensionIsEventCategory__Events.getName_day.xml b/tests/PHPUnit/System/expected/test_CustomEvents_secondaryDimensionIsEventCategory__Events.getName_day.xml
index 2945259531..194453a8db 100644
--- a/tests/PHPUnit/System/expected/test_CustomEvents_secondaryDimensionIsEventCategory__Events.getName_day.xml
+++ b/tests/PHPUnit/System/expected/test_CustomEvents_secondaryDimensionIsEventCategory__Events.getName_day.xml
@@ -26,7 +26,7 @@
</subtable>
</row>
<row>
- <label>La fiancée de l&amp;#039;eau</label>
+ <label>La fiancée de l'eau</label>
<nb_uniq_visitors>12</nb_uniq_visitors>
<nb_visits>12</nb_visits>
<nb_events>14</nb_events>
diff --git a/tests/PHPUnit/System/expected/test_CustomEvents_secondaryDimensionIsEventCategory__Events.getName_month.xml b/tests/PHPUnit/System/expected/test_CustomEvents_secondaryDimensionIsEventCategory__Events.getName_month.xml
index bfa292b1ec..e27153830c 100644
--- a/tests/PHPUnit/System/expected/test_CustomEvents_secondaryDimensionIsEventCategory__Events.getName_month.xml
+++ b/tests/PHPUnit/System/expected/test_CustomEvents_secondaryDimensionIsEventCategory__Events.getName_month.xml
@@ -26,7 +26,7 @@
</subtable>
</row>
<row>
- <label>La fiancée de l&amp;#039;eau</label>
+ <label>La fiancée de l'eau</label>
<nb_visits>12</nb_visits>
<nb_events>14</nb_events>
<nb_events_with_value>4</nb_events_with_value>
diff --git a/tests/PHPUnit/System/expected/test_CustomEvents_secondaryDimensionIsEventName__Events.getAction_day.xml b/tests/PHPUnit/System/expected/test_CustomEvents_secondaryDimensionIsEventName__Events.getAction_day.xml
index 529442b5c2..67343d25f6 100644
--- a/tests/PHPUnit/System/expected/test_CustomEvents_secondaryDimensionIsEventName__Events.getAction_day.xml
+++ b/tests/PHPUnit/System/expected/test_CustomEvents_secondaryDimensionIsEventName__Events.getAction_day.xml
@@ -85,7 +85,7 @@
<segment>eventAction==play25%25</segment>
<subtable>
<row>
- <label>La fiancée de l&amp;#039;eau</label>
+ <label>La fiancée de l'eau</label>
<nb_uniq_visitors>2</nb_uniq_visitors>
<nb_visits>2</nb_visits>
<nb_events>2</nb_events>
@@ -121,7 +121,7 @@
<segment>eventAction==play50%25</segment>
<subtable>
<row>
- <label>La fiancée de l&amp;#039;eau</label>
+ <label>La fiancée de l'eau</label>
<nb_uniq_visitors>2</nb_uniq_visitors>
<nb_visits>2</nb_visits>
<nb_events>2</nb_events>
@@ -157,7 +157,7 @@
<segment>eventAction==play75%25</segment>
<subtable>
<row>
- <label>La fiancée de l&amp;#039;eau</label>
+ <label>La fiancée de l'eau</label>
<nb_uniq_visitors>2</nb_uniq_visitors>
<nb_visits>2</nb_visits>
<nb_events>2</nb_events>
@@ -193,7 +193,7 @@
<segment>eventAction==playEnd</segment>
<subtable>
<row>
- <label>La fiancée de l&amp;#039;eau</label>
+ <label>La fiancée de l'eau</label>
<nb_uniq_visitors>2</nb_uniq_visitors>
<nb_visits>2</nb_visits>
<nb_events>2</nb_events>
@@ -229,7 +229,7 @@
<segment>eventAction==rating</segment>
<subtable>
<row>
- <label>La fiancée de l&amp;#039;eau</label>
+ <label>La fiancée de l'eau</label>
<nb_uniq_visitors>2</nb_uniq_visitors>
<nb_visits>2</nb_visits>
<nb_events>4</nb_events>
@@ -315,7 +315,7 @@
<segment>eventAction==play</segment>
<subtable>
<row>
- <label>La fiancée de l&amp;#039;eau</label>
+ <label>La fiancée de l'eau</label>
<nb_uniq_visitors>2</nb_uniq_visitors>
<nb_visits>2</nb_visits>
<nb_events>2</nb_events>
diff --git a/tests/PHPUnit/System/expected/test_CustomEvents_secondaryDimensionIsEventName__Events.getAction_month.xml b/tests/PHPUnit/System/expected/test_CustomEvents_secondaryDimensionIsEventName__Events.getAction_month.xml
index 3c9792b64e..8f96e9b8f8 100644
--- a/tests/PHPUnit/System/expected/test_CustomEvents_secondaryDimensionIsEventName__Events.getAction_month.xml
+++ b/tests/PHPUnit/System/expected/test_CustomEvents_secondaryDimensionIsEventName__Events.getAction_month.xml
@@ -85,7 +85,7 @@
<segment>eventAction==play25%25</segment>
<subtable>
<row>
- <label>La fiancée de l&amp;#039;eau</label>
+ <label>La fiancée de l'eau</label>
<nb_visits>2</nb_visits>
<nb_events>2</nb_events>
<nb_events_with_value>0</nb_events_with_value>
@@ -121,7 +121,7 @@
<segment>eventAction==play50%25</segment>
<subtable>
<row>
- <label>La fiancée de l&amp;#039;eau</label>
+ <label>La fiancée de l'eau</label>
<nb_visits>2</nb_visits>
<nb_events>2</nb_events>
<nb_events_with_value>0</nb_events_with_value>
@@ -157,7 +157,7 @@
<segment>eventAction==play75%25</segment>
<subtable>
<row>
- <label>La fiancée de l&amp;#039;eau</label>
+ <label>La fiancée de l'eau</label>
<nb_visits>2</nb_visits>
<nb_events>2</nb_events>
<nb_events_with_value>0</nb_events_with_value>
@@ -193,7 +193,7 @@
<segment>eventAction==playEnd</segment>
<subtable>
<row>
- <label>La fiancée de l&amp;#039;eau</label>
+ <label>La fiancée de l'eau</label>
<nb_visits>2</nb_visits>
<nb_events>2</nb_events>
<nb_events_with_value>0</nb_events_with_value>
@@ -229,7 +229,7 @@
<segment>eventAction==rating</segment>
<subtable>
<row>
- <label>La fiancée de l&amp;#039;eau</label>
+ <label>La fiancée de l'eau</label>
<nb_visits>2</nb_visits>
<nb_events>4</nb_events>
<nb_events_with_value>4</nb_events_with_value>
@@ -315,7 +315,7 @@
<segment>eventAction==play</segment>
<subtable>
<row>
- <label>La fiancée de l&amp;#039;eau</label>
+ <label>La fiancée de l'eau</label>
<nb_visits>2</nb_visits>
<nb_events>2</nb_events>
<nb_events_with_value>0</nb_events_with_value>
diff --git a/tests/PHPUnit/System/expected/test_CustomEvents_secondaryDimensionIsEventName__Events.getCategory_day.xml b/tests/PHPUnit/System/expected/test_CustomEvents_secondaryDimensionIsEventName__Events.getCategory_day.xml
index 9d0c930867..ab1e9a0af0 100644
--- a/tests/PHPUnit/System/expected/test_CustomEvents_secondaryDimensionIsEventName__Events.getCategory_day.xml
+++ b/tests/PHPUnit/System/expected/test_CustomEvents_secondaryDimensionIsEventName__Events.getCategory_day.xml
@@ -71,7 +71,7 @@
<segment>eventCategory==Music</segment>
<subtable>
<row>
- <label>La fiancée de l&amp;#039;eau</label>
+ <label>La fiancée de l'eau</label>
<nb_uniq_visitors>12</nb_uniq_visitors>
<nb_visits>12</nb_visits>
<nb_events>14</nb_events>
diff --git a/tests/PHPUnit/System/expected/test_CustomEvents_secondaryDimensionIsEventName__Events.getCategory_month.xml b/tests/PHPUnit/System/expected/test_CustomEvents_secondaryDimensionIsEventName__Events.getCategory_month.xml
index 96f053cf19..2e1a51f476 100644
--- a/tests/PHPUnit/System/expected/test_CustomEvents_secondaryDimensionIsEventName__Events.getCategory_month.xml
+++ b/tests/PHPUnit/System/expected/test_CustomEvents_secondaryDimensionIsEventName__Events.getCategory_month.xml
@@ -71,7 +71,7 @@
<segment>eventCategory==Music</segment>
<subtable>
<row>
- <label>La fiancée de l&amp;#039;eau</label>
+ <label>La fiancée de l'eau</label>
<nb_visits>12</nb_visits>
<nb_events>14</nb_events>
<nb_events_with_value>4</nb_events_with_value>
diff --git a/tests/PHPUnit/System/expected/test_CustomEvents_segmentMatchesEventActionPlay__Events.getAction_day.xml b/tests/PHPUnit/System/expected/test_CustomEvents_segmentMatchesEventActionPlay__Events.getAction_day.xml
index 49170578d6..390de64329 100644
--- a/tests/PHPUnit/System/expected/test_CustomEvents_segmentMatchesEventActionPlay__Events.getAction_day.xml
+++ b/tests/PHPUnit/System/expected/test_CustomEvents_segmentMatchesEventActionPlay__Events.getAction_day.xml
@@ -60,7 +60,7 @@
<segment>eventAction==play25%25</segment>
<subtable>
<row>
- <label>La fiancée de l&amp;#039;eau</label>
+ <label>La fiancée de l'eau</label>
<nb_uniq_visitors>2</nb_uniq_visitors>
<nb_visits>2</nb_visits>
<nb_events>2</nb_events>
@@ -96,7 +96,7 @@
<segment>eventAction==play50%25</segment>
<subtable>
<row>
- <label>La fiancée de l&amp;#039;eau</label>
+ <label>La fiancée de l'eau</label>
<nb_uniq_visitors>2</nb_uniq_visitors>
<nb_visits>2</nb_visits>
<nb_events>2</nb_events>
@@ -132,7 +132,7 @@
<segment>eventAction==play75%25</segment>
<subtable>
<row>
- <label>La fiancée de l&amp;#039;eau</label>
+ <label>La fiancée de l'eau</label>
<nb_uniq_visitors>2</nb_uniq_visitors>
<nb_visits>2</nb_visits>
<nb_events>2</nb_events>
@@ -168,7 +168,7 @@
<segment>eventAction==playEnd</segment>
<subtable>
<row>
- <label>La fiancée de l&amp;#039;eau</label>
+ <label>La fiancée de l'eau</label>
<nb_uniq_visitors>2</nb_uniq_visitors>
<nb_visits>2</nb_visits>
<nb_events>2</nb_events>
@@ -204,7 +204,7 @@
<segment>eventAction==play</segment>
<subtable>
<row>
- <label>La fiancée de l&amp;#039;eau</label>
+ <label>La fiancée de l'eau</label>
<nb_uniq_visitors>2</nb_uniq_visitors>
<nb_visits>2</nb_visits>
<nb_events>2</nb_events>
diff --git a/tests/PHPUnit/System/expected/test_CustomEvents_segmentMatchesEventActionPlay__Events.getName_day.xml b/tests/PHPUnit/System/expected/test_CustomEvents_segmentMatchesEventActionPlay__Events.getName_day.xml
index 11f30a6954..73eb523352 100644
--- a/tests/PHPUnit/System/expected/test_CustomEvents_segmentMatchesEventActionPlay__Events.getName_day.xml
+++ b/tests/PHPUnit/System/expected/test_CustomEvents_segmentMatchesEventActionPlay__Events.getName_day.xml
@@ -81,7 +81,7 @@
</subtable>
</row>
<row>
- <label>La fiancée de l&amp;#039;eau</label>
+ <label>La fiancée de l'eau</label>
<nb_uniq_visitors>10</nb_uniq_visitors>
<nb_visits>10</nb_visits>
<nb_events>10</nb_events>
diff --git a/tests/PHPUnit/System/expected/test_FlattenReports__CustomVariables.getCustomVariables_day.xml b/tests/PHPUnit/System/expected/test_FlattenReports__CustomVariables.getCustomVariables_day.xml
index cb25516ca4..6d6e6128de 100644
--- a/tests/PHPUnit/System/expected/test_FlattenReports__CustomVariables.getCustomVariables_day.xml
+++ b/tests/PHPUnit/System/expected/test_FlattenReports__CustomVariables.getCustomVariables_day.xml
@@ -2,28 +2,28 @@
<results>
<result date="2010-03-05">
<row>
- <label>CustomVarPage</label>
+ <label>CustomVarVisit</label>
+ <nb_visits>6</nb_visits>
<nb_actions>18</nb_actions>
+ <nb_users>0</nb_users>
+ <max_actions>3</max_actions>
+ <sum_visit_length>6</sum_visit_length>
+ <bounce_count>0</bounce_count>
+ <nb_visits_converted>0</nb_visits_converted>
<slots>
<row>
- <scope>page</scope>
+ <scope>visit</scope>
<index>1</index>
</row>
</slots>
<is_aggregate>1</is_aggregate>
</row>
<row>
- <label>CustomVarVisit</label>
- <nb_visits>6</nb_visits>
+ <label>CustomVarPage</label>
<nb_actions>18</nb_actions>
- <nb_users>0</nb_users>
- <max_actions>3</max_actions>
- <sum_visit_length>6</sum_visit_length>
- <bounce_count>0</bounce_count>
- <nb_visits_converted>0</nb_visits_converted>
<slots>
<row>
- <scope>visit</scope>
+ <scope>page</scope>
<index>1</index>
</row>
</slots>
@@ -100,6 +100,12 @@
<is_aggregate>0</is_aggregate>
</row>
<row>
+ <label>CustomVarPage - CustomVarValue1</label>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ <is_aggregate>0</is_aggregate>
+ </row>
+ <row>
<label>CustomVarPage</label>
<nb_actions>1</nb_actions>
<slots>
@@ -110,12 +116,6 @@
</slots>
<is_aggregate>1</is_aggregate>
</row>
- <row>
- <label>CustomVarPage - CustomVarValue1</label>
- <nb_visits>1</nb_visits>
- <nb_actions>1</nb_actions>
- <is_aggregate>0</is_aggregate>
- </row>
</result>
<result date="2010-03-07" />
<result date="2010-03-08" />
diff --git a/tests/PHPUnit/System/expected/test_LabelFilter_thisiscool__Actions.getPageUrls_day.xml b/tests/PHPUnit/System/expected/test_LabelFilter_thisiscool__Actions.getPageUrls_day.xml
index 65c519b014..16c1e673c8 100644
--- a/tests/PHPUnit/System/expected/test_LabelFilter_thisiscool__Actions.getPageUrls_day.xml
+++ b/tests/PHPUnit/System/expected/test_LabelFilter_thisiscool__Actions.getPageUrls_day.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8" ?>
<result>
<row>
- <label>/ééé&quot;&amp;#039;... &lt;this is cool&gt;!</label>
+ <label>/ééé&quot;'... &lt;this is cool&gt;!</label>
<nb_visits>1</nb_visits>
<nb_uniq_visitors>1</nb_uniq_visitors>
<nb_hits>1</nb_hits>
diff --git a/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_Live.getLastVisitsDetails_offsetAndLimit_1__Live.getLastVisitsDetails_month.xml b/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_Live.getLastVisitsDetails_offsetAndLimit_1__Live.getLastVisitsDetails_month.xml
index 8e249fd8e8..23daf4bf06 100644
--- a/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_Live.getLastVisitsDetails_offsetAndLimit_1__Live.getLastVisitsDetails_month.xml
+++ b/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_Live.getLastVisitsDetails_offsetAndLimit_1__Live.getLastVisitsDetails_month.xml
@@ -207,7 +207,7 @@
<row>
<type>action</type>
<url>http://piwik.net/grue/lair</url>
- <pageTitle>It&amp;#039;s &lt;script&gt; pitch black...</pageTitle>
+ <pageTitle>It's &lt;script&gt; pitch black...</pageTitle>
<pageIdAction>2</pageIdAction>
<pageId>45</pageId>
diff --git a/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_Live.getLastVisitsDetails_offsetAndLimit_2__Live.getLastVisitsDetails_month.xml b/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_Live.getLastVisitsDetails_offsetAndLimit_2__Live.getLastVisitsDetails_month.xml
index 7f6a3282d9..69d9272531 100644
--- a/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_Live.getLastVisitsDetails_offsetAndLimit_2__Live.getLastVisitsDetails_month.xml
+++ b/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_Live.getLastVisitsDetails_offsetAndLimit_2__Live.getLastVisitsDetails_month.xml
@@ -20,7 +20,7 @@
<row>
<type>action</type>
<url>http://piwik.net/grue/lair</url>
- <pageTitle>It&amp;#039;s &lt;script&gt; pitch black...</pageTitle>
+ <pageTitle>It's &lt;script&gt; pitch black...</pageTitle>
<pageIdAction>2</pageIdAction>
<pageId>40</pageId>
@@ -336,7 +336,7 @@
<row>
<type>action</type>
<url>http://piwik.net/grue/lair</url>
- <pageTitle>It&amp;#039;s &lt;script&gt; pitch black...</pageTitle>
+ <pageTitle>It's &lt;script&gt; pitch black...</pageTitle>
<pageIdAction>2</pageIdAction>
<pageId>34</pageId>
diff --git a/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_Live.getLastVisitsDetails_sortByIdVisit__Live.getLastVisitsDetails_month.xml b/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_Live.getLastVisitsDetails_sortByIdVisit__Live.getLastVisitsDetails_month.xml
index 582ef94413..0323bd788c 100644
--- a/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_Live.getLastVisitsDetails_sortByIdVisit__Live.getLastVisitsDetails_month.xml
+++ b/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_Live.getLastVisitsDetails_sortByIdVisit__Live.getLastVisitsDetails_month.xml
@@ -20,7 +20,7 @@
<row>
<type>action</type>
<url>http://piwik.net/grue/lair</url>
- <pageTitle>It&amp;#039;s pitch black...</pageTitle>
+ <pageTitle>It's pitch black...</pageTitle>
<pageIdAction>2</pageIdAction>
<pageId>95</pageId>
@@ -318,7 +318,7 @@
<row>
<type>action</type>
<url>http://piwik.net/grue/lair</url>
- <pageTitle>It&amp;#039;s &lt;script&gt; pitch black...</pageTitle>
+ <pageTitle>It's &lt;script&gt; pitch black...</pageTitle>
<pageIdAction>2</pageIdAction>
<pageId>45</pageId>
@@ -616,7 +616,7 @@
<row>
<type>action</type>
<url>http://piwik.net/grue/lair</url>
- <pageTitle>It&amp;#039;s &lt;script&gt; pitch black...</pageTitle>
+ <pageTitle>It's &lt;script&gt; pitch black...</pageTitle>
<pageIdAction>2</pageIdAction>
<pageId>40</pageId>
@@ -932,7 +932,7 @@
<row>
<type>action</type>
<url>http://piwik.net/grue/lair</url>
- <pageTitle>It&amp;#039;s &lt;script&gt; pitch black...</pageTitle>
+ <pageTitle>It's &lt;script&gt; pitch black...</pageTitle>
<pageIdAction>2</pageIdAction>
<pageId>34</pageId>
diff --git a/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_Live.getLastVisitsDetails_sortDesc__Live.getLastVisitsDetails_month.xml b/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_Live.getLastVisitsDetails_sortDesc__Live.getLastVisitsDetails_month.xml
index 582ef94413..0323bd788c 100644
--- a/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_Live.getLastVisitsDetails_sortDesc__Live.getLastVisitsDetails_month.xml
+++ b/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_Live.getLastVisitsDetails_sortDesc__Live.getLastVisitsDetails_month.xml
@@ -20,7 +20,7 @@
<row>
<type>action</type>
<url>http://piwik.net/grue/lair</url>
- <pageTitle>It&amp;#039;s pitch black...</pageTitle>
+ <pageTitle>It's pitch black...</pageTitle>
<pageIdAction>2</pageIdAction>
<pageId>95</pageId>
@@ -318,7 +318,7 @@
<row>
<type>action</type>
<url>http://piwik.net/grue/lair</url>
- <pageTitle>It&amp;#039;s &lt;script&gt; pitch black...</pageTitle>
+ <pageTitle>It's &lt;script&gt; pitch black...</pageTitle>
<pageIdAction>2</pageIdAction>
<pageId>45</pageId>
@@ -616,7 +616,7 @@
<row>
<type>action</type>
<url>http://piwik.net/grue/lair</url>
- <pageTitle>It&amp;#039;s &lt;script&gt; pitch black...</pageTitle>
+ <pageTitle>It's &lt;script&gt; pitch black...</pageTitle>
<pageIdAction>2</pageIdAction>
<pageId>40</pageId>
@@ -932,7 +932,7 @@
<row>
<type>action</type>
<url>http://piwik.net/grue/lair</url>
- <pageTitle>It&amp;#039;s &lt;script&gt; pitch black...</pageTitle>
+ <pageTitle>It's &lt;script&gt; pitch black...</pageTitle>
<pageIdAction>2</pageIdAction>
<pageId>34</pageId>
diff --git a/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest__Live.getLastVisitsDetails_month.xml b/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest__Live.getLastVisitsDetails_month.xml
index 0ca5df1e81..4665c485f0 100644
--- a/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest__Live.getLastVisitsDetails_month.xml
+++ b/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest__Live.getLastVisitsDetails_month.xml
@@ -20,7 +20,7 @@
<row>
<type>action</type>
<url>http://piwik.net/grue/lair</url>
- <pageTitle>It&amp;#039;s pitch black...</pageTitle>
+ <pageTitle>It's pitch black...</pageTitle>
<pageIdAction>2</pageIdAction>
<pageId>95</pageId>
@@ -318,7 +318,7 @@
<row>
<type>action</type>
<url>http://piwik.net/grue/lair</url>
- <pageTitle>It&amp;#039;s &lt;script&gt; pitch black...</pageTitle>
+ <pageTitle>It's &lt;script&gt; pitch black...</pageTitle>
<pageIdAction>2</pageIdAction>
<pageId>45</pageId>
@@ -616,7 +616,7 @@
<row>
<type>action</type>
<url>http://piwik.net/grue/lair</url>
- <pageTitle>It&amp;#039;s &lt;script&gt; pitch black...</pageTitle>
+ <pageTitle>It's &lt;script&gt; pitch black...</pageTitle>
<pageIdAction>2</pageIdAction>
<pageId>40</pageId>
@@ -932,7 +932,7 @@
<row>
<type>action</type>
<url>http://piwik.net/grue/lair</url>
- <pageTitle>It&amp;#039;s &lt;script&gt; pitch black...</pageTitle>
+ <pageTitle>It's &lt;script&gt; pitch black...</pageTitle>
<pageIdAction>2</pageIdAction>
<pageId>34</pageId>
@@ -1230,7 +1230,7 @@
<row>
<type>action</type>
<url>http://piwik.net/grue/lair</url>
- <pageTitle>It&amp;#039;s &lt;script&gt; pitch black...</pageTitle>
+ <pageTitle>It's &lt;script&gt; pitch black...</pageTitle>
<pageIdAction>2</pageIdAction>
<pageId>29</pageId>
diff --git a/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_sortByProcessedMetric__API.getProcessedReport_day.xml b/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_sortByProcessedMetric__API.getProcessedReport_day.xml
index 8ba7f648bd..a2dc2171b4 100644
--- a/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_sortByProcessedMetric__API.getProcessedReport_day.xml
+++ b/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_sortByProcessedMetric__API.getProcessedReport_day.xml
@@ -4,6 +4,7 @@
<prettyDate>Sunday, January 3, 2010</prettyDate>
<metadata>
<category>Actions</category>
+ <subcategory>Pages</subcategory>
<name>Page URLs</name>
<module>Actions</module>
<action>getPageUrls</action>
@@ -41,14 +42,6 @@
</columns>
<reportData>
<row>
- <label>grue</label>
- <nb_visits>4</nb_visits>
- <nb_hits>4</nb_hits>
- <bounce_rate>100%</bounce_rate>
- <avg_time_on_page>00:00:00</avg_time_on_page>
- <exit_rate>100%</exit_rate>
- </row>
- <row>
<label>space</label>
<nb_visits>4</nb_visits>
<nb_hits>4</nb_hits>
@@ -56,15 +49,23 @@
<avg_time_on_page>00:06:00</avg_time_on_page>
<exit_rate>0%</exit_rate>
</row>
+ <row>
+ <label>grue</label>
+ <nb_visits>4</nb_visits>
+ <nb_hits>4</nb_hits>
+ <bounce_rate>100%</bounce_rate>
+ <avg_time_on_page>00:00:00</avg_time_on_page>
+ <exit_rate>100%</exit_rate>
+ </row>
</reportData>
<reportMetadata>
<row>
- <idsubdatatable>2711</idsubdatatable>
+ <idsubdatatable>2712</idsubdatatable>
</row>
<row>
- <idsubdatatable>2712</idsubdatatable>
+ <idsubdatatable>2711</idsubdatatable>
</row>
</reportMetadata>
<reportTotal>
diff --git a/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_sortByProcessedMetric_constantRowsCountShouldKeepEmptyRows__API.getProcessedReport_day.xml b/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_sortByProcessedMetric_constantRowsCountShouldKeepEmptyRows__API.getProcessedReport_day.xml
index 02d9471f31..c2998323f3 100644
--- a/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_sortByProcessedMetric_constantRowsCountShouldKeepEmptyRows__API.getProcessedReport_day.xml
+++ b/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_sortByProcessedMetric_constantRowsCountShouldKeepEmptyRows__API.getProcessedReport_day.xml
@@ -3,8 +3,9 @@
<website>Site 1</website>
<prettyDate>Sunday, January 3, 2010</prettyDate>
<metadata>
- <category>Visits Summary</category>
- <name>Visits by Server Time</name>
+ <category>Visitors</category>
+ <subcategory>Times</subcategory>
+ <name>Visits per server time</name>
<module>VisitTime</module>
<action>getVisitInformationPerServerTime</action>
<dimension>Server time</dimension>
diff --git a/tests/PHPUnit/System/expected/test_OneVisitorTwoVisits__subtable__API.getProcessedReport_week.xml b/tests/PHPUnit/System/expected/test_OneVisitorTwoVisits__subtable__API.getProcessedReport_week.xml
index bfcd3f626d..d13ec92745 100644
--- a/tests/PHPUnit/System/expected/test_OneVisitorTwoVisits__subtable__API.getProcessedReport_week.xml
+++ b/tests/PHPUnit/System/expected/test_OneVisitorTwoVisits__subtable__API.getProcessedReport_week.xml
@@ -4,6 +4,7 @@
<prettyDate>week March 1 – 7, 2010</prettyDate>
<metadata>
<category>Actions</category>
+ <subcategory>Pages</subcategory>
<name>Page URLs</name>
<module>Actions</module>
<action>getPageUrls</action>
diff --git a/tests/PHPUnit/System/expected/test_OneVisitorTwoVisits_hideColumns___API.getProcessedReport_day.xml b/tests/PHPUnit/System/expected/test_OneVisitorTwoVisits_hideColumns___API.getProcessedReport_day.xml
index 52aca7f701..3ecc645c62 100644
--- a/tests/PHPUnit/System/expected/test_OneVisitorTwoVisits_hideColumns___API.getProcessedReport_day.xml
+++ b/tests/PHPUnit/System/expected/test_OneVisitorTwoVisits_hideColumns___API.getProcessedReport_day.xml
@@ -4,6 +4,7 @@
<prettyDate>Saturday, March 6, 2010</prettyDate>
<metadata>
<category>Actions</category>
+ <subcategory>Page titles</subcategory>
<name>Page titles</name>
<module>Actions</module>
<action>getPageTitles</action>
@@ -16,6 +17,18 @@
<exit_rate>Exit rate</exit_rate>
</processedMetrics>
<actionToLoadSubTables>getPageTitles</actionToLoadSubTables>
+ <relatedReports>
+ <row>
+ <name>Entry page titles</name>
+ <module>Actions</module>
+ <action>getEntryPageTitles</action>
+ </row>
+ <row>
+ <name>Exit page titles</name>
+ <module>Actions</module>
+ <action>getExitPageTitles</action>
+ </row>
+ </relatedReports>
<imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Actions&amp;apiAction=getPageTitles&amp;period=day&amp;date=2010-03-06</imageGraphUrl>
<imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Actions&amp;apiAction=getPageTitles&amp;period=day&amp;date=2010-02-05,2010-03-06</imageGraphEvolutionUrl>
<uniqueId>Actions_getPageTitles</uniqueId>
diff --git a/tests/PHPUnit/System/expected/test_OneVisitorTwoVisits_showColumnsWithProcessedMetrics___API.getProcessedReport_day.xml b/tests/PHPUnit/System/expected/test_OneVisitorTwoVisits_showColumnsWithProcessedMetrics___API.getProcessedReport_day.xml
index 208b546983..90c254ce80 100644
--- a/tests/PHPUnit/System/expected/test_OneVisitorTwoVisits_showColumnsWithProcessedMetrics___API.getProcessedReport_day.xml
+++ b/tests/PHPUnit/System/expected/test_OneVisitorTwoVisits_showColumnsWithProcessedMetrics___API.getProcessedReport_day.xml
@@ -3,8 +3,9 @@
<website>new name</website>
<prettyDate>Saturday, March 6, 2010</prettyDate>
<metadata>
- <category>Visits Summary</category>
- <name>Visits by Server Time</name>
+ <category>Visitors</category>
+ <subcategory>Times</subcategory>
+ <name>Visits per server time</name>
<module>VisitTime</module>
<action>getVisitInformationPerServerTime</action>
<dimension>Server time</dimension>
diff --git a/tests/PHPUnit/System/expected/test_OneVisitorTwoVisits_showColumns___API.getProcessedReport_day.xml b/tests/PHPUnit/System/expected/test_OneVisitorTwoVisits_showColumns___API.getProcessedReport_day.xml
index c5f4f6b6a5..96248d9ba3 100644
--- a/tests/PHPUnit/System/expected/test_OneVisitorTwoVisits_showColumns___API.getProcessedReport_day.xml
+++ b/tests/PHPUnit/System/expected/test_OneVisitorTwoVisits_showColumns___API.getProcessedReport_day.xml
@@ -4,6 +4,7 @@
<prettyDate>Saturday, March 6, 2010</prettyDate>
<metadata>
<category>Actions</category>
+ <subcategory>Page titles</subcategory>
<name>Page titles</name>
<module>Actions</module>
<action>getPageTitles</action>
@@ -20,6 +21,18 @@
<bounce_rate>Bounce Rate</bounce_rate>
</processedMetrics>
<actionToLoadSubTables>getPageTitles</actionToLoadSubTables>
+ <relatedReports>
+ <row>
+ <name>Entry page titles</name>
+ <module>Actions</module>
+ <action>getEntryPageTitles</action>
+ </row>
+ <row>
+ <name>Exit page titles</name>
+ <module>Actions</module>
+ <action>getExitPageTitles</action>
+ </row>
+ </relatedReports>
<imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Actions&amp;apiAction=getPageTitles&amp;period=day&amp;date=2010-03-06</imageGraphUrl>
<imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Actions&amp;apiAction=getPageTitles&amp;period=day&amp;date=2010-02-05,2010-03-06</imageGraphEvolutionUrl>
<uniqueId>Actions_getPageTitles</uniqueId>
diff --git a/tests/PHPUnit/System/expected/test_OneVisitorTwoVisits_showColumns_onlyOne__API.getProcessedReport_day.xml b/tests/PHPUnit/System/expected/test_OneVisitorTwoVisits_showColumns_onlyOne__API.getProcessedReport_day.xml
index 1d07653623..9bdbd47c3e 100644
--- a/tests/PHPUnit/System/expected/test_OneVisitorTwoVisits_showColumns_onlyOne__API.getProcessedReport_day.xml
+++ b/tests/PHPUnit/System/expected/test_OneVisitorTwoVisits_showColumns_onlyOne__API.getProcessedReport_day.xml
@@ -3,7 +3,8 @@
<website>new name</website>
<prettyDate>Saturday, March 6, 2010</prettyDate>
<metadata>
- <category>Visits Summary</category>
+ <category>Visitors</category>
+ <subcategory>Overview</subcategory>
<name>Visits Summary</name>
<module>VisitsSummary</module>
<action>get</action>
diff --git a/tests/PHPUnit/System/expected/test_PivotByQueryParamTest_test_PivotByParam_PlaysNiceWithDataTableMaps__Referrers.getKeywords_day.xml b/tests/PHPUnit/System/expected/test_PivotByQueryParamTest_test_PivotByParam_PlaysNiceWithDataTableMaps__Referrers.getKeywords_day.xml
index 6cb480f284..3703da3a45 100644
--- a/tests/PHPUnit/System/expected/test_PivotByQueryParamTest_test_PivotByParam_PlaysNiceWithDataTableMaps__Referrers.getKeywords_day.xml
+++ b/tests/PHPUnit/System/expected/test_PivotByQueryParamTest_test_PivotByParam_PlaysNiceWithDataTableMaps__Referrers.getKeywords_day.xml
@@ -5,28 +5,16 @@
<result date="2010-01-02" />
<result date="2010-01-03">
<row>
- <col name="label">search term 4</col>
- <col name="1. Melbourne, Victoria, Australia">0</col>
- <col name="2. Toronto, Ontario, Canada">2</col>
- <col name="3. Yokohama, Kanagawa, Japan">0</col>
- </row>
- <row>
- <col name="label">that search term</col>
- <col name="1. Melbourne, Victoria, Australia">2</col>
- <col name="2. Toronto, Ontario, Canada">0</col>
- <col name="3. Yokohama, Kanagawa, Japan">0</col>
- </row>
- <row>
<col name="label">search term 1</col>
<col name="1. Melbourne, Victoria, Australia">0</col>
<col name="2. Toronto, Ontario, Canada">0</col>
<col name="3. Yokohama, Kanagawa, Japan">1</col>
</row>
<row>
- <col name="label">this search term</col>
- <col name="1. Melbourne, Victoria, Australia">2</col>
+ <col name="label">search term 2</col>
+ <col name="1. Melbourne, Victoria, Australia">0</col>
<col name="2. Toronto, Ontario, Canada">0</col>
- <col name="3. Yokohama, Kanagawa, Japan">1</col>
+ <col name="3. Yokohama, Kanagawa, Japan">2</col>
</row>
<row>
<col name="label">search term 3</col>
@@ -35,10 +23,22 @@
<col name="3. Yokohama, Kanagawa, Japan">0</col>
</row>
<row>
- <col name="label">search term 2</col>
+ <col name="label">search term 4</col>
<col name="1. Melbourne, Victoria, Australia">0</col>
+ <col name="2. Toronto, Ontario, Canada">2</col>
+ <col name="3. Yokohama, Kanagawa, Japan">0</col>
+ </row>
+ <row>
+ <col name="label">that search term</col>
+ <col name="1. Melbourne, Victoria, Australia">2</col>
<col name="2. Toronto, Ontario, Canada">0</col>
- <col name="3. Yokohama, Kanagawa, Japan">2</col>
+ <col name="3. Yokohama, Kanagawa, Japan">0</col>
+ </row>
+ <row>
+ <col name="label">this search term</col>
+ <col name="1. Melbourne, Victoria, Australia">2</col>
+ <col name="2. Toronto, Ontario, Canada">0</col>
+ <col name="3. Yokohama, Kanagawa, Japan">1</col>
</row>
</result>
<result date="2010-01-04" />
diff --git a/tests/PHPUnit/System/expected/test_PivotByQueryParamTest_test_PivotByParam_WorksWithColumnLimiting__Referrers.getKeywords_week.xml b/tests/PHPUnit/System/expected/test_PivotByQueryParamTest_test_PivotByParam_WorksWithColumnLimiting__Referrers.getKeywords_week.xml
index b5613d0dbd..b03831fa61 100644
--- a/tests/PHPUnit/System/expected/test_PivotByQueryParamTest_test_PivotByParam_WorksWithColumnLimiting__Referrers.getKeywords_week.xml
+++ b/tests/PHPUnit/System/expected/test_PivotByQueryParamTest_test_PivotByParam_WorksWithColumnLimiting__Referrers.getKeywords_week.xml
@@ -1,24 +1,14 @@
<?xml version="1.0" encoding="utf-8" ?>
<result>
<row>
- <col name="label">search term 4</col>
- <col name="1. Melbourne, Victoria, Australia">0</col>
- <col name="Others">2</col>
- </row>
- <row>
- <col name="label">that search term</col>
- <col name="1. Melbourne, Victoria, Australia">2</col>
- <col name="Others">0</col>
- </row>
- <row>
<col name="label">search term 1</col>
<col name="1. Melbourne, Victoria, Australia">0</col>
<col name="Others">1</col>
</row>
<row>
- <col name="label">this search term</col>
- <col name="1. Melbourne, Victoria, Australia">2</col>
- <col name="Others">1</col>
+ <col name="label">search term 2</col>
+ <col name="1. Melbourne, Victoria, Australia">0</col>
+ <col name="Others">2</col>
</row>
<row>
<col name="label">search term 3</col>
@@ -26,8 +16,18 @@
<col name="Others">2</col>
</row>
<row>
- <col name="label">search term 2</col>
+ <col name="label">search term 4</col>
<col name="1. Melbourne, Victoria, Australia">0</col>
<col name="Others">2</col>
</row>
+ <row>
+ <col name="label">that search term</col>
+ <col name="1. Melbourne, Victoria, Australia">2</col>
+ <col name="Others">0</col>
+ </row>
+ <row>
+ <col name="label">this search term</col>
+ <col name="1. Melbourne, Victoria, Australia">2</col>
+ <col name="Others">1</col>
+ </row>
</result> \ No newline at end of file
diff --git a/tests/PHPUnit/System/expected/test_PivotByQueryParamTest_test_PivotByParam_WorksWithCsvOutput__Referrers.getKeywords_week.csv b/tests/PHPUnit/System/expected/test_PivotByQueryParamTest_test_PivotByParam_WorksWithCsvOutput__Referrers.getKeywords_week.csv
index 83cabc249a..ab0c4340e4 100644
--- a/tests/PHPUnit/System/expected/test_PivotByQueryParamTest_test_PivotByParam_WorksWithCsvOutput__Referrers.getKeywords_week.csv
+++ b/tests/PHPUnit/System/expected/test_PivotByQueryParamTest_test_PivotByParam_WorksWithCsvOutput__Referrers.getKeywords_week.csv
Binary files differ
diff --git a/tests/PHPUnit/System/expected/test_PivotByQueryParamTest_test_PivotByParam_WorksWithJsonOutput__Referrers.getKeywords_week.json b/tests/PHPUnit/System/expected/test_PivotByQueryParamTest_test_PivotByParam_WorksWithJsonOutput__Referrers.getKeywords_week.json
index 1b48052924..0343b12be5 100644
--- a/tests/PHPUnit/System/expected/test_PivotByQueryParamTest_test_PivotByParam_WorksWithJsonOutput__Referrers.getKeywords_week.json
+++ b/tests/PHPUnit/System/expected/test_PivotByQueryParamTest_test_PivotByParam_WorksWithJsonOutput__Referrers.getKeywords_week.json
@@ -1 +1 @@
-[{"label":"search term 4","1.\u00a0Melbourne, Victoria, Australia":false,"2.\u00a0Toronto, Ontario, Canada":2,"3.\u00a0Yokohama, Kanagawa, Japan":false},{"label":"that search term","1.\u00a0Melbourne, Victoria, Australia":2,"2.\u00a0Toronto, Ontario, Canada":false,"3.\u00a0Yokohama, Kanagawa, Japan":false},{"label":"search term 1","1.\u00a0Melbourne, Victoria, Australia":false,"2.\u00a0Toronto, Ontario, Canada":false,"3.\u00a0Yokohama, Kanagawa, Japan":1},{"label":"this search term","1.\u00a0Melbourne, Victoria, Australia":2,"2.\u00a0Toronto, Ontario, Canada":false,"3.\u00a0Yokohama, Kanagawa, Japan":1},{"label":"search term 3","1.\u00a0Melbourne, Victoria, Australia":false,"2.\u00a0Toronto, Ontario, Canada":2,"3.\u00a0Yokohama, Kanagawa, Japan":false},{"label":"search term 2","1.\u00a0Melbourne, Victoria, Australia":false,"2.\u00a0Toronto, Ontario, Canada":false,"3.\u00a0Yokohama, Kanagawa, Japan":2}] \ No newline at end of file
+[{"label":"search term 1","1.\u00a0Melbourne, Victoria, Australia":false,"2.\u00a0Toronto, Ontario, Canada":false,"3.\u00a0Yokohama, Kanagawa, Japan":1},{"label":"search term 2","1.\u00a0Melbourne, Victoria, Australia":false,"2.\u00a0Toronto, Ontario, Canada":false,"3.\u00a0Yokohama, Kanagawa, Japan":2},{"label":"search term 3","1.\u00a0Melbourne, Victoria, Australia":false,"2.\u00a0Toronto, Ontario, Canada":2,"3.\u00a0Yokohama, Kanagawa, Japan":false},{"label":"search term 4","1.\u00a0Melbourne, Victoria, Australia":false,"2.\u00a0Toronto, Ontario, Canada":2,"3.\u00a0Yokohama, Kanagawa, Japan":false},{"label":"that search term","1.\u00a0Melbourne, Victoria, Australia":2,"2.\u00a0Toronto, Ontario, Canada":false,"3.\u00a0Yokohama, Kanagawa, Japan":false},{"label":"this search term","1.\u00a0Melbourne, Victoria, Australia":2,"2.\u00a0Toronto, Ontario, Canada":false,"3.\u00a0Yokohama, Kanagawa, Japan":1}] \ No newline at end of file
diff --git a/tests/PHPUnit/System/expected/test_PivotByQueryParamTest_test_PivotByParam_WorksWithReportWhoseSubtableIsSelf__Actions.getPageUrls_week.xml b/tests/PHPUnit/System/expected/test_PivotByQueryParamTest_test_PivotByParam_WorksWithReportWhoseSubtableIsSelf__Actions.getPageUrls_week.xml
index f1c47c508d..99f7f60110 100644
--- a/tests/PHPUnit/System/expected/test_PivotByQueryParamTest_test_PivotByParam_WorksWithReportWhoseSubtableIsSelf__Actions.getPageUrls_week.xml
+++ b/tests/PHPUnit/System/expected/test_PivotByQueryParamTest_test_PivotByParam_WorksWithReportWhoseSubtableIsSelf__Actions.getPageUrls_week.xml
@@ -1,23 +1,23 @@
<?xml version="1.0" encoding="utf-8" ?>
<result>
<row>
- <col name="label">4</col>
+ <col name="label">0</col>
<col name="1. /index">1</col>
<col name="2. /13">0</col>
<col name="3. /12">0</col>
<col name="4. /9">0</col>
<col name="5. /14">0</col>
<col name="6. /15">0</col>
- <col name="7. /19">1</col>
- <col name="8. /18">1</col>
- <col name="9. /17">1</col>
- <col name="10. /16">1</col>
+ <col name="7. /19">0</col>
+ <col name="8. /18">0</col>
+ <col name="9. /17">0</col>
+ <col name="10. /16">0</col>
<col name="11. /8">0</col>
<col name="12. /11">0</col>
- <col name="13. /2">0</col>
- <col name="14. /1">0</col>
- <col name="15. /0">0</col>
- <col name="16. /3">0</col>
+ <col name="13. /2">1</col>
+ <col name="14. /1">1</col>
+ <col name="15. /0">1</col>
+ <col name="16. /3">1</col>
<col name="17. /4">0</col>
<col name="18. /7">0</col>
<col name="19. /6">0</col>
@@ -25,13 +25,13 @@
<col name="21. /10">0</col>
</row>
<row>
- <col name="label">3</col>
+ <col name="label">1</col>
<col name="1. /index">1</col>
- <col name="2. /13">1</col>
- <col name="3. /12">1</col>
+ <col name="2. /13">0</col>
+ <col name="3. /12">0</col>
<col name="4. /9">0</col>
- <col name="5. /14">1</col>
- <col name="6. /15">1</col>
+ <col name="5. /14">0</col>
+ <col name="6. /15">0</col>
<col name="7. /19">0</col>
<col name="8. /18">0</col>
<col name="9. /17">0</col>
@@ -42,10 +42,10 @@
<col name="14. /1">0</col>
<col name="15. /0">0</col>
<col name="16. /3">0</col>
- <col name="17. /4">0</col>
- <col name="18. /7">0</col>
- <col name="19. /6">0</col>
- <col name="20. /5">0</col>
+ <col name="17. /4">1</col>
+ <col name="18. /7">1</col>
+ <col name="19. /6">1</col>
+ <col name="20. /5">1</col>
<col name="21. /10">0</col>
</row>
<row>
@@ -73,13 +73,13 @@
<col name="21. /10">1</col>
</row>
<row>
- <col name="label">1</col>
+ <col name="label">3</col>
<col name="1. /index">1</col>
- <col name="2. /13">0</col>
- <col name="3. /12">0</col>
+ <col name="2. /13">1</col>
+ <col name="3. /12">1</col>
<col name="4. /9">0</col>
- <col name="5. /14">0</col>
- <col name="6. /15">0</col>
+ <col name="5. /14">1</col>
+ <col name="6. /15">1</col>
<col name="7. /19">0</col>
<col name="8. /18">0</col>
<col name="9. /17">0</col>
@@ -90,30 +90,30 @@
<col name="14. /1">0</col>
<col name="15. /0">0</col>
<col name="16. /3">0</col>
- <col name="17. /4">1</col>
- <col name="18. /7">1</col>
- <col name="19. /6">1</col>
- <col name="20. /5">1</col>
+ <col name="17. /4">0</col>
+ <col name="18. /7">0</col>
+ <col name="19. /6">0</col>
+ <col name="20. /5">0</col>
<col name="21. /10">0</col>
</row>
<row>
- <col name="label">0</col>
+ <col name="label">4</col>
<col name="1. /index">1</col>
<col name="2. /13">0</col>
<col name="3. /12">0</col>
<col name="4. /9">0</col>
<col name="5. /14">0</col>
<col name="6. /15">0</col>
- <col name="7. /19">0</col>
- <col name="8. /18">0</col>
- <col name="9. /17">0</col>
- <col name="10. /16">0</col>
+ <col name="7. /19">1</col>
+ <col name="8. /18">1</col>
+ <col name="9. /17">1</col>
+ <col name="10. /16">1</col>
<col name="11. /8">0</col>
<col name="12. /11">0</col>
- <col name="13. /2">1</col>
- <col name="14. /1">1</col>
- <col name="15. /0">1</col>
- <col name="16. /3">1</col>
+ <col name="13. /2">0</col>
+ <col name="14. /1">0</col>
+ <col name="15. /0">0</col>
+ <col name="16. /3">0</col>
<col name="17. /4">0</col>
<col name="18. /7">0</col>
<col name="19. /6">0</col>
diff --git a/tests/PHPUnit/System/expected/test_PivotByQueryParamTest_test_PivotBySegment_CreatesCorrectPivotTable_WhenPeriodIsRange__Referrers.getKeywords_range.xml b/tests/PHPUnit/System/expected/test_PivotByQueryParamTest_test_PivotBySegment_CreatesCorrectPivotTable_WhenPeriodIsRange__Referrers.getKeywords_range.xml
index 0ce7cf1276..29c2baa5d6 100644
--- a/tests/PHPUnit/System/expected/test_PivotByQueryParamTest_test_PivotBySegment_CreatesCorrectPivotTable_WhenPeriodIsRange__Referrers.getKeywords_range.xml
+++ b/tests/PHPUnit/System/expected/test_PivotByQueryParamTest_test_PivotBySegment_CreatesCorrectPivotTable_WhenPeriodIsRange__Referrers.getKeywords_range.xml
@@ -1,28 +1,16 @@
<?xml version="1.0" encoding="utf-8" ?>
<result>
<row>
- <col name="label">search term 4</col>
- <col name="1. Melbourne, Victoria, Australia">0</col>
- <col name="2. Toronto, Ontario, Canada">2</col>
- <col name="3. Yokohama, Kanagawa, Japan">0</col>
- </row>
- <row>
- <col name="label">that search term</col>
- <col name="1. Melbourne, Victoria, Australia">2</col>
- <col name="2. Toronto, Ontario, Canada">0</col>
- <col name="3. Yokohama, Kanagawa, Japan">0</col>
- </row>
- <row>
<col name="label">search term 1</col>
<col name="1. Melbourne, Victoria, Australia">0</col>
<col name="2. Toronto, Ontario, Canada">0</col>
<col name="3. Yokohama, Kanagawa, Japan">1</col>
</row>
<row>
- <col name="label">this search term</col>
- <col name="1. Melbourne, Victoria, Australia">2</col>
+ <col name="label">search term 2</col>
+ <col name="1. Melbourne, Victoria, Australia">0</col>
<col name="2. Toronto, Ontario, Canada">0</col>
- <col name="3. Yokohama, Kanagawa, Japan">1</col>
+ <col name="3. Yokohama, Kanagawa, Japan">2</col>
</row>
<row>
<col name="label">search term 3</col>
@@ -31,9 +19,21 @@
<col name="3. Yokohama, Kanagawa, Japan">0</col>
</row>
<row>
- <col name="label">search term 2</col>
+ <col name="label">search term 4</col>
<col name="1. Melbourne, Victoria, Australia">0</col>
+ <col name="2. Toronto, Ontario, Canada">2</col>
+ <col name="3. Yokohama, Kanagawa, Japan">0</col>
+ </row>
+ <row>
+ <col name="label">that search term</col>
+ <col name="1. Melbourne, Victoria, Australia">2</col>
<col name="2. Toronto, Ontario, Canada">0</col>
- <col name="3. Yokohama, Kanagawa, Japan">2</col>
+ <col name="3. Yokohama, Kanagawa, Japan">0</col>
+ </row>
+ <row>
+ <col name="label">this search term</col>
+ <col name="1. Melbourne, Victoria, Australia">2</col>
+ <col name="2. Toronto, Ontario, Canada">0</col>
+ <col name="3. Yokohama, Kanagawa, Japan">1</col>
</row>
</result> \ No newline at end of file
diff --git a/tests/PHPUnit/System/expected/test_PivotByQueryParamTest_test_PivotBySegment_CreatesCorrectPivotTable_WhenSegmentUsedInRequest__Referrers.getKeywords_week.xml b/tests/PHPUnit/System/expected/test_PivotByQueryParamTest_test_PivotBySegment_CreatesCorrectPivotTable_WhenSegmentUsedInRequest__Referrers.getKeywords_week.xml
index 04769de105..52686d6610 100644
--- a/tests/PHPUnit/System/expected/test_PivotByQueryParamTest_test_PivotBySegment_CreatesCorrectPivotTable_WhenSegmentUsedInRequest__Referrers.getKeywords_week.xml
+++ b/tests/PHPUnit/System/expected/test_PivotByQueryParamTest_test_PivotBySegment_CreatesCorrectPivotTable_WhenSegmentUsedInRequest__Referrers.getKeywords_week.xml
@@ -1,11 +1,11 @@
<?xml version="1.0" encoding="utf-8" ?>
<result>
<row>
- <col name="label">this search term</col>
+ <col name="label">that search term</col>
<col name="1. Melbourne, Victoria, Australia">2</col>
</row>
<row>
- <col name="label">that search term</col>
+ <col name="label">this search term</col>
<col name="1. Melbourne, Victoria, Australia">2</col>
</row>
</result> \ No newline at end of file
diff --git a/tests/PHPUnit/System/expected/test_PivotByQueryParamTest_test_PivotBySegment_CreatesCorrectPivotTable__Referrers.getKeywords_week.xml b/tests/PHPUnit/System/expected/test_PivotByQueryParamTest_test_PivotBySegment_CreatesCorrectPivotTable__Referrers.getKeywords_week.xml
index 0ce7cf1276..29c2baa5d6 100644
--- a/tests/PHPUnit/System/expected/test_PivotByQueryParamTest_test_PivotBySegment_CreatesCorrectPivotTable__Referrers.getKeywords_week.xml
+++ b/tests/PHPUnit/System/expected/test_PivotByQueryParamTest_test_PivotBySegment_CreatesCorrectPivotTable__Referrers.getKeywords_week.xml
@@ -1,28 +1,16 @@
<?xml version="1.0" encoding="utf-8" ?>
<result>
<row>
- <col name="label">search term 4</col>
- <col name="1. Melbourne, Victoria, Australia">0</col>
- <col name="2. Toronto, Ontario, Canada">2</col>
- <col name="3. Yokohama, Kanagawa, Japan">0</col>
- </row>
- <row>
- <col name="label">that search term</col>
- <col name="1. Melbourne, Victoria, Australia">2</col>
- <col name="2. Toronto, Ontario, Canada">0</col>
- <col name="3. Yokohama, Kanagawa, Japan">0</col>
- </row>
- <row>
<col name="label">search term 1</col>
<col name="1. Melbourne, Victoria, Australia">0</col>
<col name="2. Toronto, Ontario, Canada">0</col>
<col name="3. Yokohama, Kanagawa, Japan">1</col>
</row>
<row>
- <col name="label">this search term</col>
- <col name="1. Melbourne, Victoria, Australia">2</col>
+ <col name="label">search term 2</col>
+ <col name="1. Melbourne, Victoria, Australia">0</col>
<col name="2. Toronto, Ontario, Canada">0</col>
- <col name="3. Yokohama, Kanagawa, Japan">1</col>
+ <col name="3. Yokohama, Kanagawa, Japan">2</col>
</row>
<row>
<col name="label">search term 3</col>
@@ -31,9 +19,21 @@
<col name="3. Yokohama, Kanagawa, Japan">0</col>
</row>
<row>
- <col name="label">search term 2</col>
+ <col name="label">search term 4</col>
<col name="1. Melbourne, Victoria, Australia">0</col>
+ <col name="2. Toronto, Ontario, Canada">2</col>
+ <col name="3. Yokohama, Kanagawa, Japan">0</col>
+ </row>
+ <row>
+ <col name="label">that search term</col>
+ <col name="1. Melbourne, Victoria, Australia">2</col>
<col name="2. Toronto, Ontario, Canada">0</col>
- <col name="3. Yokohama, Kanagawa, Japan">2</col>
+ <col name="3. Yokohama, Kanagawa, Japan">0</col>
+ </row>
+ <row>
+ <col name="label">this search term</col>
+ <col name="1. Melbourne, Victoria, Australia">2</col>
+ <col name="2. Toronto, Ontario, Canada">0</col>
+ <col name="3. Yokohama, Kanagawa, Japan">1</col>
</row>
</result> \ No newline at end of file
diff --git a/tests/PHPUnit/System/expected/test_PivotByQueryParamTest_test_PivotBySubtableDimension_CreatesCorrectPivotTable_WhenPeriodIsDateRange__Referrers.getKeywords_range.xml b/tests/PHPUnit/System/expected/test_PivotByQueryParamTest_test_PivotBySubtableDimension_CreatesCorrectPivotTable_WhenPeriodIsDateRange__Referrers.getKeywords_range.xml
index 3da9704733..59e74a92f1 100644
--- a/tests/PHPUnit/System/expected/test_PivotByQueryParamTest_test_PivotBySubtableDimension_CreatesCorrectPivotTable_WhenPeriodIsDateRange__Referrers.getKeywords_range.xml
+++ b/tests/PHPUnit/System/expected/test_PivotByQueryParamTest_test_PivotBySubtableDimension_CreatesCorrectPivotTable_WhenPeriodIsDateRange__Referrers.getKeywords_range.xml
@@ -1,57 +1,57 @@
<?xml version="1.0" encoding="utf-8" ?>
<result>
<row>
- <col name="label">search term 4</col>
+ <col name="label">search term 1</col>
<col name="1. Google">0</col>
- <col name="2. Yahoo!">1</col>
+ <col name="2. Yahoo!">0</col>
<col name="3. Bing">1</col>
<col name="4. Ask">0</col>
<col name="5. Babylon">0</col>
<col name="6. Alexa">0</col>
</row>
<row>
- <col name="label">that search term</col>
- <col name="1. Google">1</col>
- <col name="2. Yahoo!">1</col>
+ <col name="label">search term 2</col>
+ <col name="1. Google">0</col>
+ <col name="2. Yahoo!">0</col>
<col name="3. Bing">0</col>
<col name="4. Ask">0</col>
+ <col name="5. Babylon">1</col>
+ <col name="6. Alexa">1</col>
+ </row>
+ <row>
+ <col name="label">search term 3</col>
+ <col name="1. Google">1</col>
+ <col name="2. Yahoo!">0</col>
+ <col name="3. Bing">0</col>
+ <col name="4. Ask">1</col>
<col name="5. Babylon">0</col>
<col name="6. Alexa">0</col>
</row>
<row>
- <col name="label">search term 1</col>
+ <col name="label">search term 4</col>
<col name="1. Google">0</col>
- <col name="2. Yahoo!">0</col>
+ <col name="2. Yahoo!">1</col>
<col name="3. Bing">1</col>
<col name="4. Ask">0</col>
<col name="5. Babylon">0</col>
<col name="6. Alexa">0</col>
</row>
<row>
- <col name="label">this search term</col>
+ <col name="label">that search term</col>
<col name="1. Google">1</col>
<col name="2. Yahoo!">1</col>
<col name="3. Bing">0</col>
- <col name="4. Ask">1</col>
+ <col name="4. Ask">0</col>
<col name="5. Babylon">0</col>
<col name="6. Alexa">0</col>
</row>
<row>
- <col name="label">search term 3</col>
+ <col name="label">this search term</col>
<col name="1. Google">1</col>
- <col name="2. Yahoo!">0</col>
+ <col name="2. Yahoo!">1</col>
<col name="3. Bing">0</col>
<col name="4. Ask">1</col>
<col name="5. Babylon">0</col>
<col name="6. Alexa">0</col>
</row>
- <row>
- <col name="label">search term 2</col>
- <col name="1. Google">0</col>
- <col name="2. Yahoo!">0</col>
- <col name="3. Bing">0</col>
- <col name="4. Ask">0</col>
- <col name="5. Babylon">1</col>
- <col name="6. Alexa">1</col>
- </row>
</result> \ No newline at end of file
diff --git a/tests/PHPUnit/System/expected/test_PivotByQueryParamTest_test_PivotBySubtableDimension_CreatesCorrectPivotTable__Referrers.getKeywords_week.xml b/tests/PHPUnit/System/expected/test_PivotByQueryParamTest_test_PivotBySubtableDimension_CreatesCorrectPivotTable__Referrers.getKeywords_week.xml
index 7b18166f59..86ae6c16be 100644
--- a/tests/PHPUnit/System/expected/test_PivotByQueryParamTest_test_PivotBySubtableDimension_CreatesCorrectPivotTable__Referrers.getKeywords_week.xml
+++ b/tests/PHPUnit/System/expected/test_PivotByQueryParamTest_test_PivotBySubtableDimension_CreatesCorrectPivotTable__Referrers.getKeywords_week.xml
@@ -1,57 +1,57 @@
<?xml version="1.0" encoding="utf-8" ?>
<result>
<row>
- <col name="label">search term 4</col>
+ <col name="label">search term 1</col>
<col name="Google">0</col>
- <col name="Yahoo!">1</col>
+ <col name="Yahoo!">0</col>
<col name="Bing">1</col>
<col name="Ask">0</col>
<col name="Babylon">0</col>
<col name="Alexa">0</col>
</row>
<row>
- <col name="label">that search term</col>
- <col name="Google">1</col>
- <col name="Yahoo!">1</col>
+ <col name="label">search term 2</col>
+ <col name="Google">0</col>
+ <col name="Yahoo!">0</col>
<col name="Bing">0</col>
<col name="Ask">0</col>
+ <col name="Babylon">1</col>
+ <col name="Alexa">1</col>
+ </row>
+ <row>
+ <col name="label">search term 3</col>
+ <col name="Google">1</col>
+ <col name="Yahoo!">0</col>
+ <col name="Bing">0</col>
+ <col name="Ask">1</col>
<col name="Babylon">0</col>
<col name="Alexa">0</col>
</row>
<row>
- <col name="label">search term 1</col>
+ <col name="label">search term 4</col>
<col name="Google">0</col>
- <col name="Yahoo!">0</col>
+ <col name="Yahoo!">1</col>
<col name="Bing">1</col>
<col name="Ask">0</col>
<col name="Babylon">0</col>
<col name="Alexa">0</col>
</row>
<row>
- <col name="label">this search term</col>
+ <col name="label">that search term</col>
<col name="Google">1</col>
<col name="Yahoo!">1</col>
<col name="Bing">0</col>
- <col name="Ask">1</col>
+ <col name="Ask">0</col>
<col name="Babylon">0</col>
<col name="Alexa">0</col>
</row>
<row>
- <col name="label">search term 3</col>
+ <col name="label">this search term</col>
<col name="Google">1</col>
- <col name="Yahoo!">0</col>
+ <col name="Yahoo!">1</col>
<col name="Bing">0</col>
<col name="Ask">1</col>
<col name="Babylon">0</col>
<col name="Alexa">0</col>
</row>
- <row>
- <col name="label">search term 2</col>
- <col name="Google">0</col>
- <col name="Yahoo!">0</col>
- <col name="Bing">0</col>
- <col name="Ask">0</col>
- <col name="Babylon">1</col>
- <col name="Alexa">1</col>
- </row>
</result> \ No newline at end of file
diff --git a/tests/PHPUnit/System/expected/test_PivotByQueryParamTest_test_PivotBySubtableDimension_WhenEntireHirearchyIsNotLoaded__Referrers.getKeywords_week.xml b/tests/PHPUnit/System/expected/test_PivotByQueryParamTest_test_PivotBySubtableDimension_WhenEntireHirearchyIsNotLoaded__Referrers.getKeywords_week.xml
index 3da9704733..59e74a92f1 100644
--- a/tests/PHPUnit/System/expected/test_PivotByQueryParamTest_test_PivotBySubtableDimension_WhenEntireHirearchyIsNotLoaded__Referrers.getKeywords_week.xml
+++ b/tests/PHPUnit/System/expected/test_PivotByQueryParamTest_test_PivotBySubtableDimension_WhenEntireHirearchyIsNotLoaded__Referrers.getKeywords_week.xml
@@ -1,57 +1,57 @@
<?xml version="1.0" encoding="utf-8" ?>
<result>
<row>
- <col name="label">search term 4</col>
+ <col name="label">search term 1</col>
<col name="1. Google">0</col>
- <col name="2. Yahoo!">1</col>
+ <col name="2. Yahoo!">0</col>
<col name="3. Bing">1</col>
<col name="4. Ask">0</col>
<col name="5. Babylon">0</col>
<col name="6. Alexa">0</col>
</row>
<row>
- <col name="label">that search term</col>
- <col name="1. Google">1</col>
- <col name="2. Yahoo!">1</col>
+ <col name="label">search term 2</col>
+ <col name="1. Google">0</col>
+ <col name="2. Yahoo!">0</col>
<col name="3. Bing">0</col>
<col name="4. Ask">0</col>
+ <col name="5. Babylon">1</col>
+ <col name="6. Alexa">1</col>
+ </row>
+ <row>
+ <col name="label">search term 3</col>
+ <col name="1. Google">1</col>
+ <col name="2. Yahoo!">0</col>
+ <col name="3. Bing">0</col>
+ <col name="4. Ask">1</col>
<col name="5. Babylon">0</col>
<col name="6. Alexa">0</col>
</row>
<row>
- <col name="label">search term 1</col>
+ <col name="label">search term 4</col>
<col name="1. Google">0</col>
- <col name="2. Yahoo!">0</col>
+ <col name="2. Yahoo!">1</col>
<col name="3. Bing">1</col>
<col name="4. Ask">0</col>
<col name="5. Babylon">0</col>
<col name="6. Alexa">0</col>
</row>
<row>
- <col name="label">this search term</col>
+ <col name="label">that search term</col>
<col name="1. Google">1</col>
<col name="2. Yahoo!">1</col>
<col name="3. Bing">0</col>
- <col name="4. Ask">1</col>
+ <col name="4. Ask">0</col>
<col name="5. Babylon">0</col>
<col name="6. Alexa">0</col>
</row>
<row>
- <col name="label">search term 3</col>
+ <col name="label">this search term</col>
<col name="1. Google">1</col>
- <col name="2. Yahoo!">0</col>
+ <col name="2. Yahoo!">1</col>
<col name="3. Bing">0</col>
<col name="4. Ask">1</col>
<col name="5. Babylon">0</col>
<col name="6. Alexa">0</col>
</row>
- <row>
- <col name="label">search term 2</col>
- <col name="1. Google">0</col>
- <col name="2. Yahoo!">0</col>
- <col name="3. Bing">0</col>
- <col name="4. Ask">0</col>
- <col name="5. Babylon">1</col>
- <col name="6. Alexa">1</col>
- </row>
</result> \ No newline at end of file
diff --git a/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getPageTitlesFollowingSiteSearch_firstSite_lastN__API.getProcessedReport_day.xml b/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getPageTitlesFollowingSiteSearch_firstSite_lastN__API.getProcessedReport_day.xml
index 1b2cdaa4b1..f6a279a41a 100644
--- a/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getPageTitlesFollowingSiteSearch_firstSite_lastN__API.getProcessedReport_day.xml
+++ b/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getPageTitlesFollowingSiteSearch_firstSite_lastN__API.getProcessedReport_day.xml
@@ -3,7 +3,8 @@
<website>Site 1 - Site search</website>
<prettyDate>January 3 – 9, 2010</prettyDate>
<metadata>
- <category>Site Search</category>
+ <category>Actions</category>
+ <subcategory>Site Search</subcategory>
<name>Page Titles Following a Site Search</name>
<module>Actions</module>
<action>getPageTitlesFollowingSiteSearch</action>
@@ -17,6 +18,13 @@
<nb_hits_following_search>The number of times this Page was visited after a visitor did a search on your website, and clicked on this page in the search results.</nb_hits_following_search>
<nb_hits>The number of times this page was visited.</nb_hits>
</metricsDocumentation>
+ <relatedReports>
+ <row>
+ <name>Pages Following a Site Search</name>
+ <module>Actions</module>
+ <action>getPageUrlsFollowingSiteSearch</action>
+ </row>
+ </relatedReports>
<imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Actions&amp;apiAction=getPageTitlesFollowingSiteSearch&amp;period=range&amp;date=2010-01-03,2010-01-09</imageGraphUrl>
<imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Actions&amp;apiAction=getPageTitlesFollowingSiteSearch&amp;period=day&amp;date=2010-01-03,2010-01-09</imageGraphEvolutionUrl>
<uniqueId>Actions_getPageTitlesFollowingSiteSearch</uniqueId>
diff --git a/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getPageTitlesFollowingSiteSearch_firstSite_lastN__API.getProcessedReport_month.xml b/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getPageTitlesFollowingSiteSearch_firstSite_lastN__API.getProcessedReport_month.xml
index 34b9d68415..cad4b436dd 100644
--- a/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getPageTitlesFollowingSiteSearch_firstSite_lastN__API.getProcessedReport_month.xml
+++ b/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getPageTitlesFollowingSiteSearch_firstSite_lastN__API.getProcessedReport_month.xml
@@ -3,7 +3,8 @@
<website>Site 1 - Site search</website>
<prettyDate>January 1 – July 31, 2010</prettyDate>
<metadata>
- <category>Site Search</category>
+ <category>Actions</category>
+ <subcategory>Site Search</subcategory>
<name>Page Titles Following a Site Search</name>
<module>Actions</module>
<action>getPageTitlesFollowingSiteSearch</action>
@@ -17,6 +18,13 @@
<nb_hits_following_search>The number of times this Page was visited after a visitor did a search on your website, and clicked on this page in the search results.</nb_hits_following_search>
<nb_hits>The number of times this page was visited.</nb_hits>
</metricsDocumentation>
+ <relatedReports>
+ <row>
+ <name>Pages Following a Site Search</name>
+ <module>Actions</module>
+ <action>getPageUrlsFollowingSiteSearch</action>
+ </row>
+ </relatedReports>
<imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Actions&amp;apiAction=getPageTitlesFollowingSiteSearch&amp;period=range&amp;date=2010-01-03,2010-07-03</imageGraphUrl>
<imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Actions&amp;apiAction=getPageTitlesFollowingSiteSearch&amp;period=month&amp;date=2010-01-03,2010-07-03</imageGraphEvolutionUrl>
<uniqueId>Actions_getPageTitlesFollowingSiteSearch</uniqueId>
diff --git a/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getPageTitles_firstSite_lastN__API.getProcessedReport_day.xml b/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getPageTitles_firstSite_lastN__API.getProcessedReport_day.xml
index 3d9d61741c..3808a4f5b5 100644
--- a/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getPageTitles_firstSite_lastN__API.getProcessedReport_day.xml
+++ b/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getPageTitles_firstSite_lastN__API.getProcessedReport_day.xml
@@ -4,6 +4,7 @@
<prettyDate>January 3 – 9, 2010</prettyDate>
<metadata>
<category>Actions</category>
+ <subcategory>Page titles</subcategory>
<name>Page titles</name>
<module>Actions</module>
<action>getPageTitles</action>
@@ -27,6 +28,18 @@
<avg_time_generation>Avg. generation time</avg_time_generation>
</processedMetrics>
<actionToLoadSubTables>getPageTitles</actionToLoadSubTables>
+ <relatedReports>
+ <row>
+ <name>Entry page titles</name>
+ <module>Actions</module>
+ <action>getEntryPageTitles</action>
+ </row>
+ <row>
+ <name>Exit page titles</name>
+ <module>Actions</module>
+ <action>getExitPageTitles</action>
+ </row>
+ </relatedReports>
<imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Actions&amp;apiAction=getPageTitles&amp;period=range&amp;date=2010-01-03,2010-01-09</imageGraphUrl>
<imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Actions&amp;apiAction=getPageTitles&amp;period=day&amp;date=2010-01-03,2010-01-09</imageGraphEvolutionUrl>
<uniqueId>Actions_getPageTitles</uniqueId>
diff --git a/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getPageTitles_firstSite_lastN__API.getProcessedReport_month.xml b/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getPageTitles_firstSite_lastN__API.getProcessedReport_month.xml
index 950fa43511..f88c7b0657 100644
--- a/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getPageTitles_firstSite_lastN__API.getProcessedReport_month.xml
+++ b/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getPageTitles_firstSite_lastN__API.getProcessedReport_month.xml
@@ -4,6 +4,7 @@
<prettyDate>January 1 – July 31, 2010</prettyDate>
<metadata>
<category>Actions</category>
+ <subcategory>Page titles</subcategory>
<name>Page titles</name>
<module>Actions</module>
<action>getPageTitles</action>
@@ -27,6 +28,18 @@
<avg_time_generation>Avg. generation time</avg_time_generation>
</processedMetrics>
<actionToLoadSubTables>getPageTitles</actionToLoadSubTables>
+ <relatedReports>
+ <row>
+ <name>Entry page titles</name>
+ <module>Actions</module>
+ <action>getEntryPageTitles</action>
+ </row>
+ <row>
+ <name>Exit page titles</name>
+ <module>Actions</module>
+ <action>getExitPageTitles</action>
+ </row>
+ </relatedReports>
<imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Actions&amp;apiAction=getPageTitles&amp;period=range&amp;date=2010-01-03,2010-07-03</imageGraphUrl>
<imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Actions&amp;apiAction=getPageTitles&amp;period=month&amp;date=2010-01-03,2010-07-03</imageGraphEvolutionUrl>
<uniqueId>Actions_getPageTitles</uniqueId>
diff --git a/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getPageUrlsFollowingSiteSearch_firstSite_lastN__API.getProcessedReport_day.xml b/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getPageUrlsFollowingSiteSearch_firstSite_lastN__API.getProcessedReport_day.xml
index f8732be73a..31080e4eab 100644
--- a/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getPageUrlsFollowingSiteSearch_firstSite_lastN__API.getProcessedReport_day.xml
+++ b/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getPageUrlsFollowingSiteSearch_firstSite_lastN__API.getProcessedReport_day.xml
@@ -3,7 +3,8 @@
<website>Site 1 - Site search</website>
<prettyDate>January 3 – 9, 2010</prettyDate>
<metadata>
- <category>Site Search</category>
+ <category>Actions</category>
+ <subcategory>Site Search</subcategory>
<name>Pages Following a Site Search</name>
<module>Actions</module>
<action>getPageUrlsFollowingSiteSearch</action>
@@ -17,6 +18,13 @@
<nb_hits_following_search>The number of times this Page was visited after a visitor did a search on your website, and clicked on this page in the search results.</nb_hits_following_search>
<nb_hits>The number of times this page was visited.</nb_hits>
</metricsDocumentation>
+ <relatedReports>
+ <row>
+ <name>Page Titles Following a Site Search</name>
+ <module>Actions</module>
+ <action>getPageTitlesFollowingSiteSearch</action>
+ </row>
+ </relatedReports>
<imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Actions&amp;apiAction=getPageUrlsFollowingSiteSearch&amp;period=range&amp;date=2010-01-03,2010-01-09</imageGraphUrl>
<imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Actions&amp;apiAction=getPageUrlsFollowingSiteSearch&amp;period=day&amp;date=2010-01-03,2010-01-09</imageGraphEvolutionUrl>
<uniqueId>Actions_getPageUrlsFollowingSiteSearch</uniqueId>
diff --git a/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getPageUrlsFollowingSiteSearch_firstSite_lastN__API.getProcessedReport_month.xml b/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getPageUrlsFollowingSiteSearch_firstSite_lastN__API.getProcessedReport_month.xml
index 6439b7eb6a..00824b40d8 100644
--- a/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getPageUrlsFollowingSiteSearch_firstSite_lastN__API.getProcessedReport_month.xml
+++ b/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getPageUrlsFollowingSiteSearch_firstSite_lastN__API.getProcessedReport_month.xml
@@ -3,7 +3,8 @@
<website>Site 1 - Site search</website>
<prettyDate>January 1 – July 31, 2010</prettyDate>
<metadata>
- <category>Site Search</category>
+ <category>Actions</category>
+ <subcategory>Site Search</subcategory>
<name>Pages Following a Site Search</name>
<module>Actions</module>
<action>getPageUrlsFollowingSiteSearch</action>
@@ -17,6 +18,13 @@
<nb_hits_following_search>The number of times this Page was visited after a visitor did a search on your website, and clicked on this page in the search results.</nb_hits_following_search>
<nb_hits>The number of times this page was visited.</nb_hits>
</metricsDocumentation>
+ <relatedReports>
+ <row>
+ <name>Page Titles Following a Site Search</name>
+ <module>Actions</module>
+ <action>getPageTitlesFollowingSiteSearch</action>
+ </row>
+ </relatedReports>
<imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Actions&amp;apiAction=getPageUrlsFollowingSiteSearch&amp;period=range&amp;date=2010-01-03,2010-07-03</imageGraphUrl>
<imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Actions&amp;apiAction=getPageUrlsFollowingSiteSearch&amp;period=month&amp;date=2010-01-03,2010-07-03</imageGraphEvolutionUrl>
<uniqueId>Actions_getPageUrlsFollowingSiteSearch</uniqueId>
diff --git a/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getPageUrls_firstSite_lastN__API.getProcessedReport_day.xml b/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getPageUrls_firstSite_lastN__API.getProcessedReport_day.xml
index f31d90446f..9987853e36 100644
--- a/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getPageUrls_firstSite_lastN__API.getProcessedReport_day.xml
+++ b/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getPageUrls_firstSite_lastN__API.getProcessedReport_day.xml
@@ -4,6 +4,7 @@
<prettyDate>January 3 – 9, 2010</prettyDate>
<metadata>
<category>Actions</category>
+ <subcategory>Pages</subcategory>
<name>Page URLs</name>
<module>Actions</module>
<action>getPageUrls</action>
diff --git a/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getPageUrls_firstSite_lastN__API.getProcessedReport_month.xml b/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getPageUrls_firstSite_lastN__API.getProcessedReport_month.xml
index 2db5ec8b59..062f55e0fd 100644
--- a/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getPageUrls_firstSite_lastN__API.getProcessedReport_month.xml
+++ b/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getPageUrls_firstSite_lastN__API.getProcessedReport_month.xml
@@ -4,6 +4,7 @@
<prettyDate>January 1 – July 31, 2010</prettyDate>
<metadata>
<category>Actions</category>
+ <subcategory>Pages</subcategory>
<name>Page URLs</name>
<module>Actions</module>
<action>getPageUrls</action>
diff --git a/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getSiteSearchCategories_firstSite_lastN__API.getProcessedReport_day.xml b/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getSiteSearchCategories_firstSite_lastN__API.getProcessedReport_day.xml
index 286a9043ba..cc02efba3e 100644
--- a/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getSiteSearchCategories_firstSite_lastN__API.getProcessedReport_day.xml
+++ b/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getSiteSearchCategories_firstSite_lastN__API.getProcessedReport_day.xml
@@ -3,7 +3,8 @@
<website>Site 1 - Site search</website>
<prettyDate>January 3 – 9, 2010</prettyDate>
<metadata>
- <category>Site Search</category>
+ <category>Actions</category>
+ <subcategory>Site Search</subcategory>
<name>Search Categories</name>
<module>Actions</module>
<action>getSiteSearchCategories</action>
diff --git a/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getSiteSearchCategories_firstSite_lastN__API.getProcessedReport_month.xml b/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getSiteSearchCategories_firstSite_lastN__API.getProcessedReport_month.xml
index 3a532fac04..d43e4fca7c 100644
--- a/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getSiteSearchCategories_firstSite_lastN__API.getProcessedReport_month.xml
+++ b/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getSiteSearchCategories_firstSite_lastN__API.getProcessedReport_month.xml
@@ -3,7 +3,8 @@
<website>Site 1 - Site search</website>
<prettyDate>January 1 – July 31, 2010</prettyDate>
<metadata>
- <category>Site Search</category>
+ <category>Actions</category>
+ <subcategory>Site Search</subcategory>
<name>Search Categories</name>
<module>Actions</module>
<action>getSiteSearchCategories</action>
diff --git a/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getSiteSearchKeywords_firstSite_lastN__API.getProcessedReport_day.xml b/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getSiteSearchKeywords_firstSite_lastN__API.getProcessedReport_day.xml
index 4e9e2a50a4..6b0247d330 100644
--- a/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getSiteSearchKeywords_firstSite_lastN__API.getProcessedReport_day.xml
+++ b/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getSiteSearchKeywords_firstSite_lastN__API.getProcessedReport_day.xml
@@ -3,7 +3,8 @@
<website>Site 1 - Site search</website>
<prettyDate>January 3 – 9, 2010</prettyDate>
<metadata>
- <category>Site Search</category>
+ <category>Actions</category>
+ <subcategory>Site Search</subcategory>
<name>Site Search Keywords</name>
<module>Actions</module>
<action>getSiteSearchKeywords</action>
diff --git a/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getSiteSearchKeywords_firstSite_lastN__API.getProcessedReport_month.xml b/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getSiteSearchKeywords_firstSite_lastN__API.getProcessedReport_month.xml
index b9f052a1eb..b6b731c93f 100644
--- a/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getSiteSearchKeywords_firstSite_lastN__API.getProcessedReport_month.xml
+++ b/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getSiteSearchKeywords_firstSite_lastN__API.getProcessedReport_month.xml
@@ -3,7 +3,8 @@
<website>Site 1 - Site search</website>
<prettyDate>January 1 – July 31, 2010</prettyDate>
<metadata>
- <category>Site Search</category>
+ <category>Actions</category>
+ <subcategory>Site Search</subcategory>
<name>Site Search Keywords</name>
<module>Actions</module>
<action>getSiteSearchKeywords</action>
diff --git a/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getSiteSearchNoResultKeywords_firstSite_lastN__API.getProcessedReport_day.xml b/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getSiteSearchNoResultKeywords_firstSite_lastN__API.getProcessedReport_day.xml
index f5a25a2e1c..916fcf2306 100644
--- a/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getSiteSearchNoResultKeywords_firstSite_lastN__API.getProcessedReport_day.xml
+++ b/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getSiteSearchNoResultKeywords_firstSite_lastN__API.getProcessedReport_day.xml
@@ -3,7 +3,8 @@
<website>Site 1 - Site search</website>
<prettyDate>January 3 – 9, 2010</prettyDate>
<metadata>
- <category>Site Search</category>
+ <category>Actions</category>
+ <subcategory>Site Search</subcategory>
<name>Search Keywords with No Results</name>
<module>Actions</module>
<action>getSiteSearchNoResultKeywords</action>
diff --git a/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getSiteSearchNoResultKeywords_firstSite_lastN__API.getProcessedReport_month.xml b/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getSiteSearchNoResultKeywords_firstSite_lastN__API.getProcessedReport_month.xml
index f82dde07dc..5037355b29 100644
--- a/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getSiteSearchNoResultKeywords_firstSite_lastN__API.getProcessedReport_month.xml
+++ b/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getSiteSearchNoResultKeywords_firstSite_lastN__API.getProcessedReport_month.xml
@@ -3,7 +3,8 @@
<website>Site 1 - Site search</website>
<prettyDate>January 1 – July 31, 2010</prettyDate>
<metadata>
- <category>Site Search</category>
+ <category>Actions</category>
+ <subcategory>Site Search</subcategory>
<name>Search Keywords with No Results</name>
<module>Actions</module>
<action>getSiteSearchNoResultKeywords</action>
diff --git a/tests/PHPUnit/System/expected/test_SiteSearch_CustomVariables.getCustomVariables_firstSite_lastN__API.getProcessedReport_day.xml b/tests/PHPUnit/System/expected/test_SiteSearch_CustomVariables.getCustomVariables_firstSite_lastN__API.getProcessedReport_day.xml
index 04b14932b5..bd42dba25a 100644
--- a/tests/PHPUnit/System/expected/test_SiteSearch_CustomVariables.getCustomVariables_firstSite_lastN__API.getProcessedReport_day.xml
+++ b/tests/PHPUnit/System/expected/test_SiteSearch_CustomVariables.getCustomVariables_firstSite_lastN__API.getProcessedReport_day.xml
@@ -4,6 +4,7 @@
<prettyDate>January 3 – 9, 2010</prettyDate>
<metadata>
<category>Visitors</category>
+ <subcategory>Custom Variables</subcategory>
<name>Custom Variables</name>
<module>CustomVariables</module>
<action>getCustomVariables</action>
diff --git a/tests/PHPUnit/System/expected/test_SiteSearch_CustomVariables.getCustomVariables_firstSite_lastN__API.getProcessedReport_month.xml b/tests/PHPUnit/System/expected/test_SiteSearch_CustomVariables.getCustomVariables_firstSite_lastN__API.getProcessedReport_month.xml
index 0d9935f4ed..4d86dedf9b 100644
--- a/tests/PHPUnit/System/expected/test_SiteSearch_CustomVariables.getCustomVariables_firstSite_lastN__API.getProcessedReport_month.xml
+++ b/tests/PHPUnit/System/expected/test_SiteSearch_CustomVariables.getCustomVariables_firstSite_lastN__API.getProcessedReport_month.xml
@@ -4,6 +4,7 @@
<prettyDate>January 1 – July 31, 2010</prettyDate>
<metadata>
<category>Visitors</category>
+ <subcategory>Custom Variables</subcategory>
<name>Custom Variables</name>
<module>CustomVariables</module>
<action>getCustomVariables</action>
diff --git a/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_Actions.getOutlinks_firstSite_lastN__API.getProcessedReport_day.xml b/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_Actions.getOutlinks_firstSite_lastN__API.getProcessedReport_day.xml
index 66783fa4df..fd119b430b 100644
--- a/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_Actions.getOutlinks_firstSite_lastN__API.getProcessedReport_day.xml
+++ b/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_Actions.getOutlinks_firstSite_lastN__API.getProcessedReport_day.xml
@@ -4,6 +4,7 @@
<prettyDate>January 3 – 9, 2010</prettyDate>
<metadata>
<category>Actions</category>
+ <subcategory>Outlinks</subcategory>
<name>Outlinks</name>
<module>Actions</module>
<action>getOutlinks</action>
diff --git a/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_Actions.getPageTitles_firstSite_lastN__API.getProcessedReport_day.xml b/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_Actions.getPageTitles_firstSite_lastN__API.getProcessedReport_day.xml
index 1dcf5c1e94..3391cb2597 100644
--- a/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_Actions.getPageTitles_firstSite_lastN__API.getProcessedReport_day.xml
+++ b/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_Actions.getPageTitles_firstSite_lastN__API.getProcessedReport_day.xml
@@ -4,6 +4,7 @@
<prettyDate>January 3 – 9, 2010</prettyDate>
<metadata>
<category>Actions</category>
+ <subcategory>Page titles</subcategory>
<name>Page titles</name>
<module>Actions</module>
<action>getPageTitles</action>
@@ -28,6 +29,18 @@
<avg_time_generation>Avg. generation time</avg_time_generation>
</processedMetrics>
<actionToLoadSubTables>getPageTitles</actionToLoadSubTables>
+ <relatedReports>
+ <row>
+ <name>Entry page titles</name>
+ <module>Actions</module>
+ <action>getEntryPageTitles</action>
+ </row>
+ <row>
+ <name>Exit page titles</name>
+ <module>Actions</module>
+ <action>getExitPageTitles</action>
+ </row>
+ </relatedReports>
<imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Actions&amp;apiAction=getPageTitles&amp;period=range&amp;date=2010-01-03,2010-01-09</imageGraphUrl>
<imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Actions&amp;apiAction=getPageTitles&amp;period=day&amp;date=2010-01-03,2010-01-09</imageGraphEvolutionUrl>
<uniqueId>Actions_getPageTitles</uniqueId>
diff --git a/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_Actions.getPageUrls_firstSite_lastN__API.getProcessedReport_day.xml b/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_Actions.getPageUrls_firstSite_lastN__API.getProcessedReport_day.xml
index c7078bf12d..207e2159fc 100644
--- a/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_Actions.getPageUrls_firstSite_lastN__API.getProcessedReport_day.xml
+++ b/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_Actions.getPageUrls_firstSite_lastN__API.getProcessedReport_day.xml
@@ -4,6 +4,7 @@
<prettyDate>January 3 – 9, 2010</prettyDate>
<metadata>
<category>Actions</category>
+ <subcategory>Pages</subcategory>
<name>Page URLs</name>
<module>Actions</module>
<action>getPageUrls</action>
diff --git a/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_Referrers.getWebsites_firstSite_lastN__API.getProcessedReport_day.xml b/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_Referrers.getWebsites_firstSite_lastN__API.getProcessedReport_day.xml
index 21f4942fd1..50478b59fc 100644
--- a/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_Referrers.getWebsites_firstSite_lastN__API.getProcessedReport_day.xml
+++ b/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_Referrers.getWebsites_firstSite_lastN__API.getProcessedReport_day.xml
@@ -4,6 +4,7 @@
<prettyDate>January 3 – 9, 2010</prettyDate>
<metadata>
<category>Referrers</category>
+ <subcategory>Websites &amp; Social</subcategory>
<name>Websites</name>
<module>Referrers</module>
<action>getWebsites</action>
diff --git a/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_VisitFrequency.get_firstSite_lastN__API.getProcessedReport_day.xml b/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_VisitFrequency.get_firstSite_lastN__API.getProcessedReport_day.xml
index 77da393895..1b132d45ae 100644
--- a/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_VisitFrequency.get_firstSite_lastN__API.getProcessedReport_day.xml
+++ b/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_VisitFrequency.get_firstSite_lastN__API.getProcessedReport_day.xml
@@ -4,6 +4,7 @@
<prettyDate>January 3 – 9, 2010</prettyDate>
<metadata>
<category>Visitors</category>
+ <subcategory>Engagement</subcategory>
<name>Returning Visits</name>
<module>VisitFrequency</module>
<action>get</action>
diff --git a/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_VisitorInterest.getNumberOfVisitsByDaysSinceLast_firstSite_lastN__API.getProcessedReport_day.xml b/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_VisitorInterest.getNumberOfVisitsByDaysSinceLast_firstSite_lastN__API.getProcessedReport_day.xml
index 94b167ab2b..78a7a0c724 100644
--- a/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_VisitorInterest.getNumberOfVisitsByDaysSinceLast_firstSite_lastN__API.getProcessedReport_day.xml
+++ b/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_VisitorInterest.getNumberOfVisitsByDaysSinceLast_firstSite_lastN__API.getProcessedReport_day.xml
@@ -4,6 +4,7 @@
<prettyDate>January 3 – 9, 2010</prettyDate>
<metadata>
<category>Visitors</category>
+ <subcategory>Engagement</subcategory>
<name>Visits by days since last visit</name>
<module>VisitorInterest</module>
<action>getNumberOfVisitsByDaysSinceLast</action>
diff --git a/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_VisitsSummary.get_firstSite_lastN__API.getProcessedReport_day.xml b/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_VisitsSummary.get_firstSite_lastN__API.getProcessedReport_day.xml
index a611557fea..2eaea47bc6 100644
--- a/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_VisitsSummary.get_firstSite_lastN__API.getProcessedReport_day.xml
+++ b/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_VisitsSummary.get_firstSite_lastN__API.getProcessedReport_day.xml
@@ -3,7 +3,8 @@
<website>Site 1</website>
<prettyDate>January 3 – 9, 2010</prettyDate>
<metadata>
- <category>Visits Summary</category>
+ <category>Visitors</category>
+ <subcategory>Overview</subcategory>
<name>Visits Summary</name>
<module>VisitsSummary</module>
<action>get</action>
diff --git a/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_scheduled_report_in_csv__ScheduledReports.generateReport_month.original.csv b/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_scheduled_report_in_csv__ScheduledReports.generateReport_month.original.csv
index 440caf0135..94a3e0f6fb 100644
--- a/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_scheduled_report_in_csv__ScheduledReports.generateReport_month.original.csv
+++ b/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_scheduled_report_in_csv__ScheduledReports.generateReport_month.original.csv
@@ -7,34 +7,168 @@ Visits Summary
nb_uniq_visitors,nb_visits,nb_actions,max_actions,nb_actions_per_visit,avg_time_on_site,bounce_rate
2,11,43,5,3.9,00:10:55,27%
-Visits by Server Time
+Custom Variables
+No data available
+
+Device type
+label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate
+Unknown,8,40,0%,5,00:15:01,0%
+Desktop,3,3,0%,1,00:00:00,100%
+
+Device model
+label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate
+Unknown,11,43,0%,3.9,00:10:55,27%
+
+Device brand
+label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate
+Unknown,11,43,0%,3.9,00:10:55,27%
+
+Screen Resolution
+label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate
+800x300,9,41,0%,4.6,00:13:21,11%
+1024x768,2,2,0%,1,00:00:00,100%
+
+Operating System versions
+label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate
+Unknown,8,40,0%,5,00:15:01,0%
+Windows XP,3,3,0%,1,00:00:00,100%
+
+Browsers
+label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate
+Unknown,8,40,0%,5,00:15:01,0%
+Firefox,2,2,0%,1,00:00:00,100%
+Opera,1,1,0%,1,00:00:00,100%
+
+Browser version
+label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate
+Unknown,8,40,0%,5,00:15:01,0%
+Firefox 3.6,2,2,0%,1,00:00:00,100%
+Opera 9.63,1,1,0%,1,00:00:00,100%
+
+Configurations
+label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate
+Unknown / Unknown / 800x300,8,40,0%,5,00:15:01,0%
+Windows / Firefox / 1024x768,2,2,0%,1,00:00:00,100%
+Windows / Opera / 800x300,1,1,0%,1,00:00:00,100%
+
+Operating System families
+label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate
+Unknown,8,40,0%,5,00:15:01,0%
+Windows,3,3,0%,1,00:00:00,100%
+
+Browser engines
+label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate
+Unknown,8,40,0%,5,00:15:01,0%
+Gecko (Firefox),2,2,0%,1,00:00:00,100%
+Presto (Opera),1,1,0%,1,00:00:00,100%
+
+Browser Plugins
+label,nb_visits,nb_visits_percentage
+Cookie,11,100%
+Flash,11,100%
+Java,11,100%
+Director,0,0%
+Gears,0,0%
+Pdf,0,0%
+Quicktime,0,0%
+Realplayer,0,0%
+Silverlight,0,0%
+Windowsmedia,0,0%
+
+Country
label,nb_visits,nb_actions,nb_actions_per_visit,avg_time_on_site,bounce_rate,revenue
-0h,1,1,1,00:00:00,100%,$ 0
-1h,0,0,0,00:00:00,0%,$ 0
-2h,0,0,0,00:00:00,0%,$ 0
-3h,0,0,0,00:00:00,0%,$ 0
-4h,0,0,0,00:00:00,0%,$ 0
-5h,0,0,0,00:00:00,0%,$ 0
-6h,0,0,0,00:00:00,0%,$ 0
-7h,0,0,0,00:00:00,0%,$ 0
-8h,0,0,0,00:00:00,0%,$ 0
-9h,0,0,0,00:00:00,0%,$ 0
-10h,0,0,0,00:00:00,0%,$ 0
-11h,8,40,5,00:15:01,0%,$ 0
-12h,1,1,1,00:00:00,100%,$ 0
-13h,0,0,0,00:00:00,0%,$ 0
-14h,0,0,0,00:00:00,0%,$ 0
-15h,0,0,0,00:00:00,0%,$ 0
-16h,0,0,0,00:00:00,0%,$ 0
-17h,0,0,0,00:00:00,0%,$ 0
-18h,0,0,0,00:00:00,0%,$ 0
-19h,0,0,0,00:00:00,0%,$ 0
-20h,0,0,0,00:00:00,0%,$ 0
-21h,0,0,0,00:00:00,0%,$ 0
-22h,0,0,0,00:00:00,0%,$ 0
-23h,1,1,1,00:00:00,100%,$ 0
+Unknown,8,40,5,00:15:01,0%,$ 0
+France,3,3,1,00:00:00,100%,$ 0
+
+Continent
+label,nb_visits,nb_actions,nb_actions_per_visit,avg_time_on_site,bounce_rate,revenue
+Unknown,8,40,5,00:15:01,0%,$ 0
+Europe,3,3,1,00:00:00,100%,$ 0
+
+Region
+label,nb_visits,nb_actions,nb_actions_per_visit,avg_time_on_site,bounce_rate,revenue
+Unknown,11,43,3.9,00:10:55,27%,$ 0
+
+Browser language
+label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate
+Unknown,8,40,0%,5,00:15:01,0%
+French,3,3,0%,1,00:00:00,100%
-Visits by Local Time
+City
+label,nb_visits,nb_actions,nb_actions_per_visit,avg_time_on_site,bounce_rate,revenue
+Unknown,11,43,3.9,00:10:55,27%,$ 0
+
+Language code
+label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate
+Unknown (xx),8,40,0%,5,00:15:01,0%
+French (fr),3,3,0%,1,00:00:00,100%
+
+Length of Visits
+label,nb_visits
+0-10s,3
+11-30s,0
+31-60s,0
+1-2 min,0
+2-4 min,0
+4-7 min,0
+7-10 min,0
+10-15 min,0
+15-30 min,8
+30+ min,0
+
+Pages per Visit
+label,nb_visits
+1 page,3
+2 pages,0
+3 pages,0
+4 pages,0
+5 pages,8
+6-7 pages,0
+8-10 pages,0
+11-14 pages,0
+15-20 pages,0
+21+ pages,0
+
+Visits by Visit Number
+label,nb_visits,nb_visits_percentage
+1 visit,3,27%
+2 visits,8,73%
+3 visits,0,0%
+4 visits,0,0%
+5 visits,0,0%
+6 visits,0,0%
+7 visits,0,0%
+8 visits,0,0%
+9-14 visits,0,0%
+15-25 visits,0,0%
+26-50 visits,0,0%
+51-100 visits,0,0%
+101-200 visits,0,0%
+201+ visits,0,0%
+
+Visits by days since last visit
+label,nb_visits
+New visits,2
+0 days,1
+1 day,0
+2 days,1
+3 days,1
+4 days,1
+5 days,1
+6 days,1
+7 days,1
+8-14 days,2
+15-30 days,0
+31-60 days,0
+61-120 days,0
+121-364 days,0
+365+ days,0
+
+Returning Visits
+nb_uniq_visitors_returning,nb_users_returning,nb_visits_returning,nb_actions_returning,max_actions_returning,bounce_rate_returning,nb_actions_per_visit_returning,avg_time_on_site_returning
+2,0,9,41,5,11%,4.6,00:13:21
+
+Visits per local time
label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate
0h,0,0,0%,0,00:00:00,0%
1h,0,0,0%,0,00:00:00,0%
@@ -61,6 +195,33 @@ label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site
22h,0,0,0%,0,00:00:00,0%
23h,0,0,0%,0,00:00:00,0%
+Visits per server time
+label,nb_visits,nb_actions,nb_actions_per_visit,avg_time_on_site,bounce_rate,revenue
+0h,1,1,1,00:00:00,100%,$ 0
+1h,0,0,0,00:00:00,0%,$ 0
+2h,0,0,0,00:00:00,0%,$ 0
+3h,0,0,0,00:00:00,0%,$ 0
+4h,0,0,0,00:00:00,0%,$ 0
+5h,0,0,0,00:00:00,0%,$ 0
+6h,0,0,0,00:00:00,0%,$ 0
+7h,0,0,0,00:00:00,0%,$ 0
+8h,0,0,0,00:00:00,0%,$ 0
+9h,0,0,0,00:00:00,0%,$ 0
+10h,0,0,0,00:00:00,0%,$ 0
+11h,8,40,5,00:15:01,0%,$ 0
+12h,1,1,1,00:00:00,100%,$ 0
+13h,0,0,0,00:00:00,0%,$ 0
+14h,0,0,0,00:00:00,0%,$ 0
+15h,0,0,0,00:00:00,0%,$ 0
+16h,0,0,0,00:00:00,0%,$ 0
+17h,0,0,0,00:00:00,0%,$ 0
+18h,0,0,0,00:00:00,0%,$ 0
+19h,0,0,0,00:00:00,0%,$ 0
+20h,0,0,0,00:00:00,0%,$ 0
+21h,0,0,0,00:00:00,0%,$ 0
+22h,0,0,0,00:00:00,0%,$ 0
+23h,1,1,1,00:00:00,100%,$ 0
+
Visits by Day of Week
label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate
Monday,2,6,0%,3,00:07:31,50%
@@ -71,44 +232,6 @@ Friday,1,5,0%,5,00:15:01,0%
Saturday,1,5,0%,5,00:15:01,0%
Sunday,3,7,0%,2.3,00:05:00,67%
-Screen Resolution
-label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate
-800x300,9,41,0%,4.6,00:13:21,11%
-1024x768,2,2,0%,1,00:00:00,100%
-
-Browser Plugins
-label,nb_visits,nb_visits_percentage
-Cookie,11,100%
-Flash,11,100%
-Java,11,100%
-Director,0,0%
-Gears,0,0%
-Pdf,0,0%
-Quicktime,0,0%
-Realplayer,0,0%
-Silverlight,0,0%
-Windowsmedia,0,0%
-
-Visitor Configuration
-label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate
-Unknown / Unknown / 800x300,8,40,0%,5,00:15:01,0%
-Windows / Firefox / 1024x768,2,2,0%,1,00:00:00,100%
-Windows / Opera / 800x300,1,1,0%,1,00:00:00,100%
-
-Browser language
-label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate
-Unknown,8,40,0%,5,00:15:01,0%
-French,3,3,0%,1,00:00:00,100%
-
-Language code
-label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate
-Unknown (xx),8,40,0%,5,00:15:01,0%
-French (fr),3,3,0%,1,00:00:00,100%
-
-Actions - Main metrics
-nb_pageviews,nb_uniq_pageviews,nb_downloads,nb_uniq_downloads,nb_outlinks,nb_uniq_outlinks,nb_searches,nb_keywords,avg_time_generation
-43,27,0,0,0,0,0,0,0.3s
-
Page URLs
label,nb_visits,nb_hits,bounce_rate,avg_time_on_page,exit_rate,avg_time_generation
/index.htm,9,9,11%,00:05:20,11%,0.3s
@@ -134,26 +257,25 @@ Checkout,8,8,0%,00:00:00,100%,0.45s
first page view,2,2,100%,00:00:00,100%,0.14s
Page Name not defined,1,1,0%,00:00:00,0%,0.22s
-Entry page titles
-label,entry_nb_visits,entry_bounce_count,bounce_rate,avg_time_generation
-second visitor,8,0,0%,0.25s
- first page view,2,2,100%,0.14s
+Site Search Keywords
+No data available
-Exit page titles
-label,nb_visits,exit_nb_visits,exit_rate,avg_time_generation
-Checkout,8,8,100%,0.45s
- first page view,2,2,100%,0.14s
+Pages Following a Site Search
+No data available
-Outlinks
+Search Keywords with No Results
No data available
-Downloads
+Page Titles Following a Site Search
No data available
-Content Name
+Search Categories
No data available
-Content Piece
+Outlinks
+No data available
+
+Downloads
No data available
Event Categories
@@ -165,20 +287,25 @@ No data available
Event Names
No data available
-Site Search Keywords
+Content Name
No data available
-Search Keywords with No Results
+Content Piece
No data available
-Search Categories
-No data available
+Actions - Main metrics
+nb_pageviews,nb_uniq_pageviews,nb_downloads,nb_uniq_downloads,nb_outlinks,nb_uniq_outlinks,nb_searches,nb_keywords,avg_time_generation
+43,27,0,0,0,0,0,0,0.3s
-Pages Following a Site Search
-No data available
+Entry page titles
+label,entry_nb_visits,entry_bounce_count,bounce_rate,avg_time_generation
+second visitor,8,0,0%,0.25s
+ first page view,2,2,100%,0.14s
-Page Titles Following a Site Search
-No data available
+Exit page titles
+label,nb_visits,exit_nb_visits,exit_rate,avg_time_generation
+Checkout,8,8,100%,0.45s
+ first page view,2,2,100%,0.14s
Referrer Type
label,nb_visits,nb_actions,nb_actions_per_visit,avg_time_on_site,bounce_rate,revenue
@@ -194,20 +321,20 @@ goal-matching-url-parameter,4,20,0%,5,00:15:01,0%
Keywords
No data available
+Search Engines
+No data available
+
Websites
label,nb_visits,nb_actions,nb_actions_per_visit,avg_time_on_site,bounce_rate,revenue
referrer.com,6,22,3.7,00:10:01,33%,$ 0
-Search Engines
+Social Networks
No data available
Campaigns
label,nb_visits,nb_actions,nb_actions_per_visit,avg_time_on_site,bounce_rate,revenue
goal-matching-url-parameter,4,20,5,00:15:01,0%,$ 0
-Social Networks
-No data available
-
Goals
nb_conversions,nb_visits_converted,revenue,conversion_rate
0,0,$ 0,0%
@@ -218,130 +345,15 @@ No data available
Days to Conversion
No data available
-Country
-label,nb_visits,nb_actions,nb_actions_per_visit,avg_time_on_site,bounce_rate,revenue
-Unknown,8,40,5,00:15:01,0%,$ 0
-France,3,3,1,00:00:00,100%,$ 0
-
-Continent
-label,nb_visits,nb_actions,nb_actions_per_visit,avg_time_on_site,bounce_rate,revenue
-Unknown,8,40,5,00:15:01,0%,$ 0
-Europe,3,3,1,00:00:00,100%,$ 0
-
-Region
-label,nb_visits,nb_actions,nb_actions_per_visit,avg_time_on_site,bounce_rate,revenue
-Unknown,11,43,3.9,00:10:55,27%,$ 0
-
-City
-label,nb_visits,nb_actions,nb_actions_per_visit,avg_time_on_site,bounce_rate,revenue
-Unknown,11,43,3.9,00:10:55,27%,$ 0
-
-Custom Variables
+Data tables
No data available
-Length of Visits
-label,nb_visits
-0-10s,3
-11-30s,0
-31-60s,0
-1-2 min,0
-2-4 min,0
-4-7 min,0
-7-10 min,0
-10-15 min,0
-15-30 min,8
-30+ min,0
-
-Pages per Visit
-label,nb_visits
-1 page,3
-2 pages,0
-3 pages,0
-4 pages,0
-5 pages,8
-6-7 pages,0
-8-10 pages,0
-11-14 pages,0
-15-20 pages,0
-21+ pages,0
-
-Visits by Visit Number
-label,nb_visits,nb_visits_percentage
-1 visit,3,27%
-2 visits,8,73%
-3 visits,0,0%
-4 visits,0,0%
-5 visits,0,0%
-6 visits,0,0%
-7 visits,0,0%
-8 visits,0,0%
-9-14 visits,0,0%
-15-25 visits,0,0%
-26-50 visits,0,0%
-51-100 visits,0,0%
-101-200 visits,0,0%
-201+ visits,0,0%
-
-Visits by days since last visit
-label,nb_visits
-New visits,2
-0 days,1
-1 day,0
-2 days,1
-3 days,1
-4 days,1
-5 days,1
-6 days,1
-7 days,1
-8-14 days,2
-15-30 days,0
-31-60 days,0
-61-120 days,0
-121-364 days,0
-365+ days,0
-
-Returning Visits
-nb_uniq_visitors_returning,nb_users_returning,nb_visits_returning,nb_actions_returning,max_actions_returning,bounce_rate_returning,nb_actions_per_visit_returning,avg_time_on_site_returning
-2,0,9,41,5,11%,4.6,00:13:21
-
-Device type
-label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate
-Unknown,8,40,0%,5,00:15:01,0%
-Desktop,3,3,0%,1,00:00:00,100%
-
-Visitor Browser
-label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate
-Unknown,8,40,0%,5,00:15:01,0%
-Firefox,2,2,0%,1,00:00:00,100%
-Opera,1,1,0%,1,00:00:00,100%
-
-Device brand
-label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate
-Unknown,11,43,0%,3.9,00:10:55,27%
-
-Device model
-label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate
-Unknown,11,43,0%,3.9,00:10:55,27%
-
-Browser version
-label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate
-Unknown,8,40,0%,5,00:15:01,0%
-Firefox 3.6,2,2,0%,1,00:00:00,100%
-Opera 9.63,1,1,0%,1,00:00:00,100%
-
-Operating System families
-label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate
-Unknown,8,40,0%,5,00:15:01,0%
-Windows,3,3,0%,1,00:00:00,100%
+Temperatures evolution over time
+No data available
-Operating System versions
-label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate
-Unknown,8,40,0%,5,00:15:01,0%
-Windows XP,3,3,0%,1,00:00:00,100%
+Pie graph
+No data available
-Browser engines
-label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate
-Unknown,8,40,0%,5,00:15:01,0%
-Gecko (Firefox),2,2,0%,1,00:00:00,100%
-Presto (Opera),1,1,0%,1,00:00:00,100%
+Advanced tag cloud: with logos and links
+No data available
diff --git a/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_scheduled_report_in_html_tables_only__ScheduledReports.generateReport_month.original.html b/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_scheduled_report_in_html_tables_only__ScheduledReports.generateReport_month.original.html
index 9038446a12..95c67bf1c7 100644
--- a/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_scheduled_report_in_html_tables_only__ScheduledReports.generateReport_month.original.html
+++ b/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_scheduled_report_in_html_tables_only__ScheduledReports.generateReport_month.original.html
@@ -31,18 +31,23 @@
</a>
</li>
<li>
- <a href="#VisitTime_getVisitInformationPerServerTime" style="text-decoration:none; color: rgb(13,13,13);">
- Visits by Server Time
+ <a href="#CustomVariables_getCustomVariables" style="text-decoration:none; color: rgb(13,13,13);">
+ Custom Variables
</a>
</li>
<li>
- <a href="#VisitTime_getVisitInformationPerLocalTime" style="text-decoration:none; color: rgb(13,13,13);">
- Visits by Local Time
+ <a href="#DevicesDetection_getType" style="text-decoration:none; color: rgb(13,13,13);">
+ Device type
</a>
</li>
<li>
- <a href="#VisitTime_getByDayOfWeek" style="text-decoration:none; color: rgb(13,13,13);">
- Visits by Day of Week
+ <a href="#DevicesDetection_getModel" style="text-decoration:none; color: rgb(13,13,13);">
+ Device model
+ </a>
+ </li>
+ <li>
+ <a href="#DevicesDetection_getBrand" style="text-decoration:none; color: rgb(13,13,13);">
+ Device brand
</a>
</li>
<li>
@@ -51,258 +56,273 @@
</a>
</li>
<li>
- <a href="#DevicePlugins_getPlugin" style="text-decoration:none; color: rgb(13,13,13);">
- Browser Plugins
+ <a href="#DevicesDetection_getOsVersions" style="text-decoration:none; color: rgb(13,13,13);">
+ Operating System versions
+ </a>
+ </li>
+ <li>
+ <a href="#DevicesDetection_getBrowsers" style="text-decoration:none; color: rgb(13,13,13);">
+ Browsers
+ </a>
+ </li>
+ <li>
+ <a href="#DevicesDetection_getBrowserVersions" style="text-decoration:none; color: rgb(13,13,13);">
+ Browser version
</a>
</li>
<li>
<a href="#Resolution_getConfiguration" style="text-decoration:none; color: rgb(13,13,13);">
- Visitor Configuration
+ Configurations
</a>
</li>
<li>
- <a href="#UserLanguage_getLanguage" style="text-decoration:none; color: rgb(13,13,13);">
- Browser language
+ <a href="#DevicesDetection_getOsFamilies" style="text-decoration:none; color: rgb(13,13,13);">
+ Operating System families
</a>
</li>
<li>
- <a href="#UserLanguage_getLanguageCode" style="text-decoration:none; color: rgb(13,13,13);">
- Language code
+ <a href="#DevicesDetection_getBrowserEngines" style="text-decoration:none; color: rgb(13,13,13);">
+ Browser engines
</a>
</li>
<li>
- <a href="#Actions_get" style="text-decoration:none; color: rgb(13,13,13);">
- Actions - Main metrics
+ <a href="#DevicePlugins_getPlugin" style="text-decoration:none; color: rgb(13,13,13);">
+ Browser Plugins
</a>
</li>
<li>
- <a href="#Actions_getPageUrls" style="text-decoration:none; color: rgb(13,13,13);">
- Page URLs
+ <a href="#UserCountry_getCountry" style="text-decoration:none; color: rgb(13,13,13);">
+ Country
</a>
</li>
<li>
- <a href="#Actions_getEntryPageUrls" style="text-decoration:none; color: rgb(13,13,13);">
- Entry pages
+ <a href="#UserCountry_getContinent" style="text-decoration:none; color: rgb(13,13,13);">
+ Continent
</a>
</li>
<li>
- <a href="#Actions_getExitPageUrls" style="text-decoration:none; color: rgb(13,13,13);">
- Exit pages
+ <a href="#UserCountry_getRegion" style="text-decoration:none; color: rgb(13,13,13);">
+ Region
</a>
</li>
<li>
- <a href="#Actions_getPageTitles" style="text-decoration:none; color: rgb(13,13,13);">
- Page titles
+ <a href="#UserLanguage_getLanguage" style="text-decoration:none; color: rgb(13,13,13);">
+ Browser language
</a>
</li>
<li>
- <a href="#Actions_getEntryPageTitles" style="text-decoration:none; color: rgb(13,13,13);">
- Entry page titles
+ <a href="#UserCountry_getCity" style="text-decoration:none; color: rgb(13,13,13);">
+ City
</a>
</li>
<li>
- <a href="#Actions_getExitPageTitles" style="text-decoration:none; color: rgb(13,13,13);">
- Exit page titles
+ <a href="#UserLanguage_getLanguageCode" style="text-decoration:none; color: rgb(13,13,13);">
+ Language code
</a>
</li>
<li>
- <a href="#Actions_getOutlinks" style="text-decoration:none; color: rgb(13,13,13);">
- Outlinks
+ <a href="#VisitorInterest_getNumberOfVisitsPerVisitDuration" style="text-decoration:none; color: rgb(13,13,13);">
+ Length of Visits
</a>
</li>
<li>
- <a href="#Actions_getDownloads" style="text-decoration:none; color: rgb(13,13,13);">
- Downloads
+ <a href="#VisitorInterest_getNumberOfVisitsPerPage" style="text-decoration:none; color: rgb(13,13,13);">
+ Pages per Visit
</a>
</li>
<li>
- <a href="#Contents_getContentNames" style="text-decoration:none; color: rgb(13,13,13);">
- Content Name
+ <a href="#VisitorInterest_getNumberOfVisitsByVisitCount" style="text-decoration:none; color: rgb(13,13,13);">
+ Visits by Visit Number
</a>
</li>
<li>
- <a href="#Contents_getContentPieces" style="text-decoration:none; color: rgb(13,13,13);">
- Content Piece
+ <a href="#VisitorInterest_getNumberOfVisitsByDaysSinceLast" style="text-decoration:none; color: rgb(13,13,13);">
+ Visits by days since last visit
</a>
</li>
<li>
- <a href="#Events_getCategory" style="text-decoration:none; color: rgb(13,13,13);">
- Event Categories
+ <a href="#VisitFrequency_get" style="text-decoration:none; color: rgb(13,13,13);">
+ Returning Visits
</a>
</li>
<li>
- <a href="#Events_getAction" style="text-decoration:none; color: rgb(13,13,13);">
- Event Actions
+ <a href="#VisitTime_getVisitInformationPerLocalTime" style="text-decoration:none; color: rgb(13,13,13);">
+ Visits per local time
</a>
</li>
<li>
- <a href="#Events_getName" style="text-decoration:none; color: rgb(13,13,13);">
- Event Names
+ <a href="#VisitTime_getVisitInformationPerServerTime" style="text-decoration:none; color: rgb(13,13,13);">
+ Visits per server time
</a>
</li>
<li>
- <a href="#Actions_getSiteSearchKeywords" style="text-decoration:none; color: rgb(13,13,13);">
- Site Search Keywords
+ <a href="#VisitTime_getByDayOfWeek" style="text-decoration:none; color: rgb(13,13,13);">
+ Visits by Day of Week
</a>
</li>
<li>
- <a href="#Actions_getSiteSearchNoResultKeywords" style="text-decoration:none; color: rgb(13,13,13);">
- Search Keywords with No Results
+ <a href="#Actions_getPageUrls" style="text-decoration:none; color: rgb(13,13,13);">
+ Page URLs
</a>
</li>
<li>
- <a href="#Actions_getSiteSearchCategories" style="text-decoration:none; color: rgb(13,13,13);">
- Search Categories
+ <a href="#Actions_getEntryPageUrls" style="text-decoration:none; color: rgb(13,13,13);">
+ Entry pages
</a>
</li>
<li>
- <a href="#Actions_getPageUrlsFollowingSiteSearch" style="text-decoration:none; color: rgb(13,13,13);">
- Pages Following a Site Search
+ <a href="#Actions_getExitPageUrls" style="text-decoration:none; color: rgb(13,13,13);">
+ Exit pages
</a>
</li>
<li>
- <a href="#Actions_getPageTitlesFollowingSiteSearch" style="text-decoration:none; color: rgb(13,13,13);">
- Page Titles Following a Site Search
+ <a href="#Actions_getPageTitles" style="text-decoration:none; color: rgb(13,13,13);">
+ Page titles
</a>
</li>
<li>
- <a href="#Referrers_getReferrerType" style="text-decoration:none; color: rgb(13,13,13);">
- Referrer Type
+ <a href="#Actions_getSiteSearchKeywords" style="text-decoration:none; color: rgb(13,13,13);">
+ Site Search Keywords
</a>
</li>
<li>
- <a href="#Referrers_getAll" style="text-decoration:none; color: rgb(13,13,13);">
- All Referrers
+ <a href="#Actions_getPageUrlsFollowingSiteSearch" style="text-decoration:none; color: rgb(13,13,13);">
+ Pages Following a Site Search
</a>
</li>
<li>
- <a href="#Referrers_getKeywords" style="text-decoration:none; color: rgb(13,13,13);">
- Keywords
+ <a href="#Actions_getSiteSearchNoResultKeywords" style="text-decoration:none; color: rgb(13,13,13);">
+ Search Keywords with No Results
</a>
</li>
<li>
- <a href="#Referrers_getWebsites" style="text-decoration:none; color: rgb(13,13,13);">
- Websites
+ <a href="#Actions_getPageTitlesFollowingSiteSearch" style="text-decoration:none; color: rgb(13,13,13);">
+ Page Titles Following a Site Search
</a>
</li>
<li>
- <a href="#Referrers_getSearchEngines" style="text-decoration:none; color: rgb(13,13,13);">
- Search Engines
+ <a href="#Actions_getSiteSearchCategories" style="text-decoration:none; color: rgb(13,13,13);">
+ Search Categories
</a>
</li>
<li>
- <a href="#Referrers_getCampaigns" style="text-decoration:none; color: rgb(13,13,13);">
- Campaigns
+ <a href="#Actions_getOutlinks" style="text-decoration:none; color: rgb(13,13,13);">
+ Outlinks
</a>
</li>
<li>
- <a href="#Referrers_getSocials" style="text-decoration:none; color: rgb(13,13,13);">
- Social Networks
+ <a href="#Actions_getDownloads" style="text-decoration:none; color: rgb(13,13,13);">
+ Downloads
</a>
</li>
<li>
- <a href="#Goals_get" style="text-decoration:none; color: rgb(13,13,13);">
- Goals
+ <a href="#Events_getCategory" style="text-decoration:none; color: rgb(13,13,13);">
+ Event Categories
</a>
</li>
<li>
- <a href="#Goals_getVisitsUntilConversion" style="text-decoration:none; color: rgb(13,13,13);">
- Visits to Conversion
+ <a href="#Events_getAction" style="text-decoration:none; color: rgb(13,13,13);">
+ Event Actions
</a>
</li>
<li>
- <a href="#Goals_getDaysToConversion" style="text-decoration:none; color: rgb(13,13,13);">
- Days to Conversion
+ <a href="#Events_getName" style="text-decoration:none; color: rgb(13,13,13);">
+ Event Names
</a>
</li>
<li>
- <a href="#UserCountry_getCountry" style="text-decoration:none; color: rgb(13,13,13);">
- Country
+ <a href="#Contents_getContentNames" style="text-decoration:none; color: rgb(13,13,13);">
+ Content Name
</a>
</li>
<li>
- <a href="#UserCountry_getContinent" style="text-decoration:none; color: rgb(13,13,13);">
- Continent
+ <a href="#Contents_getContentPieces" style="text-decoration:none; color: rgb(13,13,13);">
+ Content Piece
</a>
</li>
<li>
- <a href="#UserCountry_getRegion" style="text-decoration:none; color: rgb(13,13,13);">
- Region
+ <a href="#Actions_get" style="text-decoration:none; color: rgb(13,13,13);">
+ Actions - Main metrics
</a>
</li>
<li>
- <a href="#UserCountry_getCity" style="text-decoration:none; color: rgb(13,13,13);">
- City
+ <a href="#Actions_getEntryPageTitles" style="text-decoration:none; color: rgb(13,13,13);">
+ Entry page titles
</a>
</li>
<li>
- <a href="#CustomVariables_getCustomVariables" style="text-decoration:none; color: rgb(13,13,13);">
- Custom Variables
+ <a href="#Actions_getExitPageTitles" style="text-decoration:none; color: rgb(13,13,13);">
+ Exit page titles
</a>
</li>
<li>
- <a href="#VisitorInterest_getNumberOfVisitsPerVisitDuration" style="text-decoration:none; color: rgb(13,13,13);">
- Length of Visits
+ <a href="#Referrers_getReferrerType" style="text-decoration:none; color: rgb(13,13,13);">
+ Referrer Type
</a>
</li>
<li>
- <a href="#VisitorInterest_getNumberOfVisitsPerPage" style="text-decoration:none; color: rgb(13,13,13);">
- Pages per Visit
+ <a href="#Referrers_getAll" style="text-decoration:none; color: rgb(13,13,13);">
+ All Referrers
</a>
</li>
<li>
- <a href="#VisitorInterest_getNumberOfVisitsByVisitCount" style="text-decoration:none; color: rgb(13,13,13);">
- Visits by Visit Number
+ <a href="#Referrers_getKeywords" style="text-decoration:none; color: rgb(13,13,13);">
+ Keywords
</a>
</li>
<li>
- <a href="#VisitorInterest_getNumberOfVisitsByDaysSinceLast" style="text-decoration:none; color: rgb(13,13,13);">
- Visits by days since last visit
+ <a href="#Referrers_getSearchEngines" style="text-decoration:none; color: rgb(13,13,13);">
+ Search Engines
</a>
</li>
<li>
- <a href="#VisitFrequency_get" style="text-decoration:none; color: rgb(13,13,13);">
- Returning Visits
+ <a href="#Referrers_getWebsites" style="text-decoration:none; color: rgb(13,13,13);">
+ Websites
</a>
</li>
<li>
- <a href="#DevicesDetection_getType" style="text-decoration:none; color: rgb(13,13,13);">
- Device type
+ <a href="#Referrers_getSocials" style="text-decoration:none; color: rgb(13,13,13);">
+ Social Networks
</a>
</li>
<li>
- <a href="#DevicesDetection_getBrowsers" style="text-decoration:none; color: rgb(13,13,13);">
- Visitor Browser
+ <a href="#Referrers_getCampaigns" style="text-decoration:none; color: rgb(13,13,13);">
+ Campaigns
</a>
</li>
<li>
- <a href="#DevicesDetection_getBrand" style="text-decoration:none; color: rgb(13,13,13);">
- Device brand
+ <a href="#Goals_get" style="text-decoration:none; color: rgb(13,13,13);">
+ Goals
</a>
</li>
<li>
- <a href="#DevicesDetection_getModel" style="text-decoration:none; color: rgb(13,13,13);">
- Device model
+ <a href="#Goals_getVisitsUntilConversion" style="text-decoration:none; color: rgb(13,13,13);">
+ Visits to Conversion
</a>
</li>
<li>
- <a href="#DevicesDetection_getBrowserVersions" style="text-decoration:none; color: rgb(13,13,13);">
- Browser version
+ <a href="#Goals_getDaysToConversion" style="text-decoration:none; color: rgb(13,13,13);">
+ Days to Conversion
</a>
</li>
<li>
- <a href="#DevicesDetection_getOsFamilies" style="text-decoration:none; color: rgb(13,13,13);">
- Operating System families
+ <a href="#ExampleUI_getTemperatures" style="text-decoration:none; color: rgb(13,13,13);">
+ Data tables
</a>
</li>
<li>
- <a href="#DevicesDetection_getOsVersions" style="text-decoration:none; color: rgb(13,13,13);">
- Operating System versions
+ <a href="#ExampleUI_getTemperaturesEvolution" style="text-decoration:none; color: rgb(13,13,13);">
+ Temperatures evolution over time
</a>
</li>
<li>
- <a href="#DevicesDetection_getBrowserEngines" style="text-decoration:none; color: rgb(13,13,13);">
- Browser engines
+ <a href="#ExampleUI_getPlanetRatios" style="text-decoration:none; color: rgb(13,13,13);">
+ Pie graph
+ </a>
+ </li>
+ <li>
+ <a href="#ExampleUI_getPlanetRatiosWithLogos" style="text-decoration:none; color: rgb(13,13,13);">
+ Advanced tag cloud: with logos and links
</a>
</li>
</ul>
@@ -476,8 +496,13 @@
<a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
Back to top
</a>
-<h2 id="VisitTime_getVisitInformationPerServerTime" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Visits by Server Time
+<h2 id="CustomVariables_getCustomVariables" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Custom Variables
+</h2>
+
+ There is no data for this report.
+<h2 id="DevicesDetection_getType" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Device type
</h2>
@@ -485,7 +510,7 @@
<table style="border-collapse:collapse; margin-left: 5px;">
<thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
<th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Server time&nbsp;&nbsp;
+ &nbsp;Device type&nbsp;&nbsp;
</th>
<th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
&nbsp;Visits&nbsp;&nbsp;
@@ -503,267 +528,617 @@
&nbsp;Bounce Rate&nbsp;&nbsp;
</th>
<th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Revenue&nbsp;&nbsp;
+ &nbsp;Conversion Rate&nbsp;&nbsp;
</th>
</thead>
<tbody>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0h </td>
+ <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicesDetection/images/screens/unknown.gif'>
+ &nbsp;
+ Unknown </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
+ 8
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
+ 40
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
+ 5
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:00:00
+ 00:15:01
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 100%
+ 0%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
+ 0%
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1h </td>
+ <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicesDetection/images/screens/normal.gif'>
+ &nbsp;
+ Desktop </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 3
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 3
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 1
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
00:00:00
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 100%
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0%
</td>
+ </tr>
+ </tbody>
+ </table>
+ <br/>
+ <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
+ Back to top
+ </a>
+<h2 id="DevicesDetection_getModel" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Device model
+</h2>
+
+
+
+ <table style="border-collapse:collapse; margin-left: 5px;">
+ <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Device model&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Visits&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Actions&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Actions per Visit&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Avg. Time on Website&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Bounce Rate&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Conversion Rate&nbsp;&nbsp;
+ </th>
+ </thead>
+ <tbody>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ Unknown </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 11
+ </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
+ 43
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 3.9
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 00:10:55
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 27%
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0%
</td>
</tr>
-
+ </tbody>
+ </table>
+ <br/>
+ <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
+ Back to top
+ </a>
+<h2 id="DevicesDetection_getBrand" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Device brand
+</h2>
+
+
+
+ <table style="border-collapse:collapse; margin-left: 5px;">
+ <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Device brand&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Visits&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Actions&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Actions per Visit&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Avg. Time on Website&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Bounce Rate&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Conversion Rate&nbsp;&nbsp;
+ </th>
+ </thead>
+ <tbody>
+
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 2h </td>
+ <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicesDetection/images/brand/Unknown.ico'>
+ &nbsp;
+ Unknown </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 11
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 43
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 3.9
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:00:00
+ 00:10:55
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 27%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0%
</td>
+ </tr>
+ </tbody>
+ </table>
+ <br/>
+ <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
+ Back to top
+ </a>
+<h2 id="Resolution_getResolution" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Screen Resolution
+</h2>
+
+
+
+ <table style="border-collapse:collapse; margin-left: 5px;">
+ <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Resolution&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Visits&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Actions&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Actions per Visit&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Avg. Time on Website&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Bounce Rate&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Conversion Rate&nbsp;&nbsp;
+ </th>
+ </thead>
+ <tbody>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 800x300 </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
+ 9
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 41
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 4.6
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 00:13:21
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 11%
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0%
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 3h </td>
+ 1024x768 </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 2
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 2
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 1
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
00:00:00
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ 100%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
+ 0%
</td>
</tr>
-
+ </tbody>
+ </table>
+ <br/>
+ <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
+ Back to top
+ </a>
+<h2 id="DevicesDetection_getOsVersions" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Operating System versions
+</h2>
+
+
+
+ <table style="border-collapse:collapse; margin-left: 5px;">
+ <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Operating System versions&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Visits&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Actions&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Actions per Visit&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Avg. Time on Website&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Bounce Rate&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Conversion Rate&nbsp;&nbsp;
+ </th>
+ </thead>
+ <tbody>
+
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 4h </td>
+ <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicesDetection/images/os/UNK.gif'>
+ &nbsp;
+ Unknown </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 8
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 40
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 5
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:00:00
+ 00:15:01
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
+ 0%
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 5h </td>
+ <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicesDetection/images/os/WIN.gif'>
+ &nbsp;
+ Windows XP </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 3
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 3
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 1
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
00:00:00
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ 100%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
+ 0%
</td>
</tr>
-
+ </tbody>
+ </table>
+ <br/>
+ <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
+ Back to top
+ </a>
+<h2 id="DevicesDetection_getBrowsers" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Browsers
+</h2>
+
+
+
+ <table style="border-collapse:collapse; margin-left: 5px;">
+ <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Browser&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Visits&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Actions&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Actions per Visit&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Avg. Time on Website&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Bounce Rate&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Conversion Rate&nbsp;&nbsp;
+ </th>
+ </thead>
+ <tbody>
+
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 6h </td>
+ <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicesDetection/images/browsers/UNK.gif'>
+ &nbsp;
+ Unknown </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 8
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 40
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 5
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:00:00
+ 00:15:01
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
+ 0%
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 7h </td>
+ <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicesDetection/images/browsers/FF.gif'>
+ &nbsp;
+ Firefox </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 2
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 2
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 1
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
00:00:00
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ 100%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
+ 0%
</td>
</tr>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 8h </td>
+ <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicesDetection/images/browsers/OP.gif'>
+ &nbsp;
+ Opera </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 1
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 1
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 1
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
00:00:00
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 100%
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0%
</td>
+ </tr>
+ </tbody>
+ </table>
+ <br/>
+ <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
+ Back to top
+ </a>
+<h2 id="DevicesDetection_getBrowserVersions" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Browser version
+</h2>
+
+
+
+ <table style="border-collapse:collapse; margin-left: 5px;">
+ <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Browser version&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Visits&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Actions&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Actions per Visit&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Avg. Time on Website&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Bounce Rate&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Conversion Rate&nbsp;&nbsp;
+ </th>
+ </thead>
+ <tbody>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicesDetection/images/browsers/UNK.gif'>
+ &nbsp;
+ Unknown </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
+ 8
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 40
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 5
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 00:15:01
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0%
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0%
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 9h </td>
+ <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicesDetection/images/browsers/FF.gif'>
+ &nbsp;
+ Firefox 3.6 </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 2
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 2
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 1
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
00:00:00
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ 100%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
+ 0%
</td>
</tr>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 10h </td>
+ <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicesDetection/images/browsers/OP.gif'>
+ &nbsp;
+ Opera 9.63 </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 1
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 1
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 1
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
00:00:00
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ 100%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
+ 0%
</td>
</tr>
-
- <tr style=";line-height: 22px;">
+ </tbody>
+ </table>
+ <br/>
+ <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
+ Back to top
+ </a>
+<h2 id="Resolution_getConfiguration" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Configurations
+</h2>
+
+
+
+ <table style="border-collapse:collapse; margin-left: 5px;">
+ <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Configuration&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Visits&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Actions&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Actions per Visit&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Avg. Time on Website&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Bounce Rate&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Conversion Rate&nbsp;&nbsp;
+ </th>
+ </thead>
+ <tbody>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 11h </td>
+ Unknown / Unknown / 800x300 </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
8
</td>
@@ -780,18 +1155,18 @@
0%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
+ 0%
</td>
</tr>
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 12h </td>
+ Windows / Firefox / 1024x768 </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
+ 2
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
+ 2
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
1
@@ -803,231 +1178,434 @@
100%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
+ 0%
</td>
</tr>
- <tr style=";line-height: 22px;">
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 13h </td>
+ Windows / Opera / 800x300 </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 1
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 1
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 1
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
00:00:00
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ 100%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
+ 0%
</td>
</tr>
-
+ </tbody>
+ </table>
+ <br/>
+ <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
+ Back to top
+ </a>
+<h2 id="DevicesDetection_getOsFamilies" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Operating System families
+</h2>
+
+
+
+ <table style="border-collapse:collapse; margin-left: 5px;">
+ <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Operating system family&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Visits&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Actions&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Actions per Visit&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Avg. Time on Website&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Bounce Rate&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Conversion Rate&nbsp;&nbsp;
+ </th>
+ </thead>
+ <tbody>
+
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 14h </td>
+ <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicesDetection/images/os/UNK.gif'>
+ &nbsp;
+ Unknown </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 8
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 40
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 5
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:00:00
+ 00:15:01
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
+ 0%
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 15h </td>
+ <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicesDetection/images/os/WIN.gif'>
+ &nbsp;
+ Windows </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 3
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 3
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 1
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
00:00:00
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ 100%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
+ 0%
</td>
</tr>
-
+ </tbody>
+ </table>
+ <br/>
+ <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
+ Back to top
+ </a>
+<h2 id="DevicesDetection_getBrowserEngines" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Browser engines
+</h2>
+
+
+
+ <table style="border-collapse:collapse; margin-left: 5px;">
+ <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Browser engine&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Visits&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Actions&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Actions per Visit&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Avg. Time on Website&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Bounce Rate&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Conversion Rate&nbsp;&nbsp;
+ </th>
+ </thead>
+ <tbody>
+
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 16h </td>
+ Unknown </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 8
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 40
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 5
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:00:00
+ 00:15:01
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
+ 0%
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 17h </td>
+ Gecko (Firefox) </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 2
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 2
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 1
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
00:00:00
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ 100%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
+ 0%
</td>
</tr>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 18h </td>
+ Presto (Opera) </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 1
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 1
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 1
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
00:00:00
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 100%
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0%
</td>
+ </tr>
+ </tbody>
+ </table>
+ <br/>
+ <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
+ Back to top
+ </a>
+<h2 id="DevicePlugins_getPlugin" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Browser Plugins
+</h2>
+
+
+
+ <table style="border-collapse:collapse; margin-left: 5px;">
+ <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Plugin&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Visits&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;% Visits&nbsp;&nbsp;
+ </th>
+ </thead>
+ <tbody>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicePlugins/images/plugins/cookie.gif'>
+ &nbsp;
+ Cookie </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
+ 11
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 100%
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 19h </td>
+ <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicePlugins/images/plugins/flash.gif'>
+ &nbsp;
+ Flash </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 11
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 100%
</td>
+ </tr>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicePlugins/images/plugins/java.gif'>
+ &nbsp;
+ Java </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 11
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:00:00
+ 100%
</td>
+ </tr>
+
+ <tr style=";line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicePlugins/images/plugins/director.gif'>
+ &nbsp;
+ Director </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
+ 0%
</td>
</tr>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 20h </td>
+ <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicePlugins/images/plugins/gears.gif'>
+ &nbsp;
+ Gears </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 0%
</td>
+ </tr>
+
+ <tr style=";line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicePlugins/images/plugins/pdf.gif'>
+ &nbsp;
+ Pdf </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:00:00
+ 0%
</td>
+ </tr>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicePlugins/images/plugins/quicktime.gif'>
+ &nbsp;
+ Quicktime </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
+ 0%
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 21h </td>
+ <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicePlugins/images/plugins/realplayer.gif'>
+ &nbsp;
+ Realplayer </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 0%
</td>
+ </tr>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicePlugins/images/plugins/silverlight.gif'>
+ &nbsp;
+ Silverlight </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:00:00
+ 0%
</td>
+ </tr>
+
+ <tr style=";line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicePlugins/images/plugins/windowsmedia.gif'>
+ &nbsp;
+ Windowsmedia </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
+ 0%
</td>
</tr>
-
+ </tbody>
+ </table>
+ <br/>
+ <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
+ Back to top
+ </a>
+<h2 id="UserCountry_getCountry" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Country
+</h2>
+
+
+
+ <table style="border-collapse:collapse; margin-left: 5px;">
+ <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Country&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Visits&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Actions&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Actions per Visit&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Avg. Time on Website&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Bounce Rate&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Revenue&nbsp;&nbsp;
+ </th>
+ </thead>
+ <tbody>
+
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 22h </td>
+ <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/UserCountry/images/flags/xx.png'>
+ &nbsp;
+ Unknown </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 8
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 40
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 5
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:00:00
+ 00:15:01
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0%
@@ -1039,12 +1617,14 @@
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 23h </td>
+ <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/UserCountry/images/flags/fr.png'>
+ &nbsp;
+ France </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
+ 3
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
+ 3
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
1
@@ -1065,8 +1645,8 @@
<a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
Back to top
</a>
-<h2 id="VisitTime_getVisitInformationPerLocalTime" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Visits by Local Time
+<h2 id="UserCountry_getContinent" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Continent
</h2>
@@ -1074,7 +1654,7 @@
<table style="border-collapse:collapse; margin-left: 5px;">
<thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
<th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Local time&nbsp;&nbsp;
+ &nbsp;Continent&nbsp;&nbsp;
</th>
<th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
&nbsp;Visits&nbsp;&nbsp;
@@ -1092,71 +1672,170 @@
&nbsp;Bounce Rate&nbsp;&nbsp;
</th>
<th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Conversion Rate&nbsp;&nbsp;
+ &nbsp;Revenue&nbsp;&nbsp;
</th>
</thead>
<tbody>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0h </td>
+ Unknown </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 8
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 40
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 5
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:00:00
+ 00:15:01
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ $ 0
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1h </td>
+ Europe </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 3
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 3
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 1
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
00:00:00
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ 100%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ $ 0
</td>
</tr>
-
+ </tbody>
+ </table>
+ <br/>
+ <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
+ Back to top
+ </a>
+<h2 id="UserCountry_getRegion" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Region
+</h2>
+
+
+
+ <table style="border-collapse:collapse; margin-left: 5px;">
+ <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Region&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Visits&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Actions&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Actions per Visit&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Avg. Time on Website&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Bounce Rate&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Revenue&nbsp;&nbsp;
+ </th>
+ </thead>
+ <tbody>
+
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 2h </td>
+ <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/UserCountry/images/flags/xx.png'>
+ &nbsp;
+ Unknown </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 11
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 43
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 3.9
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:00:00
+ 00:10:55
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 27%
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ $ 0
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ <br/>
+ <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
+ Back to top
+ </a>
+<h2 id="UserLanguage_getLanguage" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Browser language
+</h2>
+
+
+
+ <table style="border-collapse:collapse; margin-left: 5px;">
+ <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Language&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Visits&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Actions&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Actions per Visit&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Avg. Time on Website&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Bounce Rate&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Conversion Rate&nbsp;&nbsp;
+ </th>
+ </thead>
+ <tbody>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ Unknown </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 8
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 40
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 5
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 00:15:01
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0%
@@ -1168,41 +1847,140 @@
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 3h </td>
+ French </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 3
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 3
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 1
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
00:00:00
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ 100%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0%
</td>
</tr>
-
+ </tbody>
+ </table>
+ <br/>
+ <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
+ Back to top
+ </a>
+<h2 id="UserCountry_getCity" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ City
+</h2>
+
+
+
+ <table style="border-collapse:collapse; margin-left: 5px;">
+ <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;City&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Visits&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Actions&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Actions per Visit&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Avg. Time on Website&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Bounce Rate&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Revenue&nbsp;&nbsp;
+ </th>
+ </thead>
+ <tbody>
+
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 4h </td>
+ <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/UserCountry/images/flags/xx.png'>
+ &nbsp;
+ Unknown </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 11
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 43
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 3.9
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:00:00
+ 00:10:55
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 27%
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ $ 0
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ <br/>
+ <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
+ Back to top
+ </a>
+<h2 id="UserLanguage_getLanguageCode" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Language code
+</h2>
+
+
+
+ <table style="border-collapse:collapse; margin-left: 5px;">
+ <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Language&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Visits&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Actions&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Actions per Visit&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Avg. Time on Website&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Bounce Rate&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Conversion Rate&nbsp;&nbsp;
+ </th>
+ </thead>
+ <tbody>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ Unknown (xx) </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 8
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 40
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 5
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 00:15:01
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0%
@@ -1214,113 +1992,294 @@
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 5h </td>
+ French (fr) </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 3
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 3
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 1
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
00:00:00
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ 100%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0%
</td>
</tr>
+ </tbody>
+ </table>
+ <br/>
+ <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
+ Back to top
+ </a>
+<h2 id="VisitorInterest_getNumberOfVisitsPerVisitDuration" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Length of Visits
+</h2>
+
+
+
+ <table style="border-collapse:collapse; margin-left: 5px;">
+ <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Visit duration&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Visits&nbsp;&nbsp;
+ </th>
+ </thead>
+ <tbody>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0-10s </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 3
+ </td>
+ </tr>
+
+ <tr style=";line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 11-30s </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0
+ </td>
+ </tr>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 6h </td>
+ 31-60s </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
+ </tr>
+
+ <tr style=";line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 1-2 min </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0
+ </td>
+ </tr>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 2-4 min </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
+ </tr>
+
+ <tr style=";line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 4-7 min </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
+ </tr>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 7-10 min </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:00:00
+ 0
</td>
+ </tr>
+
+ <tr style=";line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 10-15 min </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ 0
</td>
+ </tr>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 15-30 min </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ 8
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 7h </td>
+ 30+ min </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
+ </tr>
+ </tbody>
+ </table>
+ <br/>
+ <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
+ Back to top
+ </a>
+<h2 id="VisitorInterest_getNumberOfVisitsPerPage" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Pages per Visit
+</h2>
+
+
+
+ <table style="border-collapse:collapse; margin-left: 5px;">
+ <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Pages per visit&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Visits&nbsp;&nbsp;
+ </th>
+ </thead>
+ <tbody>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 1 page </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 3
+ </td>
+ </tr>
+
+ <tr style=";line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 2 pages </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
+ </tr>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 3 pages </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
+ </tr>
+
+ <tr style=";line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 4 pages </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:00:00
+ 0
</td>
+ </tr>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 5 pages </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ 8
</td>
+ </tr>
+
+ <tr style=";line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 6-7 pages </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ 0
</td>
</tr>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 8h </td>
+ 8-10 pages </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
+ </tr>
+
+ <tr style=";line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 11-14 pages </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
+ </tr>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 15-20 pages </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
+ </tr>
+
+ <tr style=";line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 21+ pages </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:00:00
+ 0
</td>
+ </tr>
+ </tbody>
+ </table>
+ <br/>
+ <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
+ Back to top
+ </a>
+<h2 id="VisitorInterest_getNumberOfVisitsByVisitCount" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Visits by Visit Number
+</h2>
+
+
+
+ <table style="border-collapse:collapse; margin-left: 5px;">
+ <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Visits by Visit Number&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Visits&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;% Visits&nbsp;&nbsp;
+ </th>
+ </thead>
+ <tbody>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 1 visit </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ 3
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ 27%
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 9h </td>
+ 2 visits </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 8
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 73%
</td>
+ </tr>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 3 visits </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:00:00
+ 0%
</td>
+ </tr>
+
+ <tr style=";line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 4 visits </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0%
@@ -1329,21 +2288,31 @@
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 10h </td>
+ 5 visits </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 0%
</td>
+ </tr>
+
+ <tr style=";line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 6 visits </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:00:00
+ 0%
</td>
+ </tr>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 7 visits </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0%
@@ -1352,21 +2321,31 @@
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 11h </td>
+ 8 visits </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 0%
</td>
+ </tr>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 9-14 visits </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:00:00
+ 0%
</td>
+ </tr>
+
+ <tr style=";line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 15-25 visits </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0%
@@ -1375,21 +2354,31 @@
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 12h </td>
+ 26-50 visits </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 11
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 43
+ 0%
</td>
+ </tr>
+
+ <tr style=";line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 51-100 visits </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 3.9
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:10:55
+ 0%
</td>
+ </tr>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 101-200 visits </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 27%
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0%
@@ -1398,76 +2387,283 @@
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 13h </td>
+ 201+ visits </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 0%
</td>
+ </tr>
+ </tbody>
+ </table>
+ <br/>
+ <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
+ Back to top
+ </a>
+<h2 id="VisitorInterest_getNumberOfVisitsByDaysSinceLast" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Visits by days since last visit
+</h2>
+
+
+
+ <table style="border-collapse:collapse; margin-left: 5px;">
+ <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Visits by days since last visit&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Visits&nbsp;&nbsp;
+ </th>
+ </thead>
+ <tbody>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ New visits </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 2
+ </td>
+ </tr>
+
+ <tr style=";line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0 days </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 1
+ </td>
+ </tr>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 1 day </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
+ </tr>
+
+ <tr style=";line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 2 days </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:00:00
+ 1
+ </td>
+ </tr>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 3 days </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 1
</td>
+ </tr>
+
+ <tr style=";line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 4 days </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ 1
</td>
+ </tr>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 5 days </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ 1
+ </td>
+ </tr>
+
+ <tr style=";line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 6 days </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 1
</td>
</tr>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 14h </td>
+ 7 days </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 1
+ </td>
+ </tr>
+
+ <tr style=";line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 8-14 days </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 2
+ </td>
+ </tr>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 15-30 days </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
+ </tr>
+
+ <tr style=";line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 31-60 days </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
+ </tr>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 61-120 days </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
+ </tr>
+
+ <tr style=";line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 121-364 days </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:00:00
+ 0
</td>
+ </tr>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 365+ days </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ 0
</td>
+ </tr>
+ </tbody>
+ </table>
+ <br/>
+ <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
+ Back to top
+ </a>
+<h2 id="VisitFrequency_get" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Returning Visits
+</h2>
+
+
+
+ <table style="border-collapse:collapse; margin-left: 5px;">
+ <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Name&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Value&nbsp;&nbsp;
+ </th>
+ </thead>
+ <tbody>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ Unique returning visitors </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ 2
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 15h </td>
+ Returning Users </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
+ </tr>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ Returning Visits </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 9
</td>
+ </tr>
+
+ <tr style=";line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ Actions by Returning Visits </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 41
</td>
+ </tr>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ Maximum actions in one returning visit </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:00:00
+ 5
</td>
+ </tr>
+
+ <tr style=";line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ Bounce Rate for Returning Visits </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ 11%
</td>
+ </tr>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ Avg. Actions per Returning Visit </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ 4.6
</td>
</tr>
+ <tr style=";line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ Avg. Duration of a Returning Visit (in sec) </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 00:13:21
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ <br/>
+ <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
+ Back to top
+ </a>
+<h2 id="VisitTime_getVisitInformationPerLocalTime" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Visits per local time
+</h2>
+
+
+
+ <table style="border-collapse:collapse; margin-left: 5px;">
+ <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Local time&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Visits&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Actions&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Actions per Visit&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Avg. Time on Website&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Bounce Rate&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Conversion Rate&nbsp;&nbsp;
+ </th>
+ </thead>
+ <tbody>
+
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 16h </td>
+ 0h </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
@@ -1490,7 +2686,7 @@
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 17h </td>
+ 1h </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
@@ -1513,7 +2709,7 @@
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 18h </td>
+ 2h </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
@@ -1536,7 +2732,7 @@
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 19h </td>
+ 3h </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
@@ -1559,7 +2755,7 @@
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 20h </td>
+ 4h </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
@@ -1582,7 +2778,7 @@
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 21h </td>
+ 5h </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
@@ -1605,7 +2801,7 @@
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 22h </td>
+ 6h </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
@@ -1628,7 +2824,7 @@
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 23h </td>
+ 7h </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
@@ -1648,61 +2844,24 @@
0%
</td>
</tr>
- </tbody>
- </table>
- <br/>
- <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
- Back to top
- </a>
-<h2 id="VisitTime_getByDayOfWeek" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Visits by Day of Week
-</h2>
-
-
-
- <table style="border-collapse:collapse; margin-left: 5px;">
- <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Day of the week&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Visits&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Actions&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Actions per Visit&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Avg. Time on Website&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Bounce Rate&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Conversion Rate&nbsp;&nbsp;
- </th>
- </thead>
- <tbody>
-
+
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Monday </td>
+ 8h </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 2
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 6
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 3
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:07:31
+ 00:00:00
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 50%
+ 0%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0%
@@ -1711,18 +2870,18 @@
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Tuesday </td>
+ 9h </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 2
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 10
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 5
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:15:01
+ 00:00:00
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0%
@@ -1734,18 +2893,18 @@
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Wednesday </td>
+ 10h </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 5
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 5
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:15:01
+ 00:00:00
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0%
@@ -1757,18 +2916,18 @@
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Thursday </td>
+ 11h </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 5
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 5
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:15:01
+ 00:00:00
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0%
@@ -1780,21 +2939,21 @@
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Friday </td>
+ 12h </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
+ 11
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 5
+ 43
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 5
+ 3.9
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:15:01
+ 00:10:55
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ 27%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0%
@@ -1803,18 +2962,18 @@
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Saturday </td>
+ 13h </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 5
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 5
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:15:01
+ 00:00:00
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0%
@@ -1826,233 +2985,136 @@
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Sunday </td>
+ 14h </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 3
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 7
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 2.3
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:05:00
+ 00:00:00
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 67%
+ 0%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0%
</td>
</tr>
- </tbody>
- </table>
- <br/>
- <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
- Back to top
- </a>
-<h2 id="Resolution_getResolution" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Screen Resolution
-</h2>
-
-
-
- <table style="border-collapse:collapse; margin-left: 5px;">
- <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Resolution&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Visits&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Actions&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Actions per Visit&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Avg. Time on Website&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Bounce Rate&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Conversion Rate&nbsp;&nbsp;
- </th>
- </thead>
- <tbody>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+
+ <tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 800x300 </td>
+ 15h </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 9
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 41
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 4.6
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:13:21
+ 00:00:00
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 11%
+ 0%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0%
</td>
</tr>
- <tr style=";line-height: 22px;">
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1024x768 </td>
+ 16h </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 2
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 2
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
00:00:00
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 100%
+ 0%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0%
</td>
</tr>
- </tbody>
- </table>
- <br/>
- <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
- Back to top
- </a>
-<h2 id="DevicePlugins_getPlugin" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Browser Plugins
-</h2>
-
-
-
- <table style="border-collapse:collapse; margin-left: 5px;">
- <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Plugin&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Visits&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;% Visits&nbsp;&nbsp;
- </th>
- </thead>
- <tbody>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+
+ <tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicePlugins/images/plugins/cookie.gif'>
- &nbsp;
- Cookie </td>
+ 17h </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 11
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 100%
+ 0
</td>
- </tr>
-
- <tr style=";line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicePlugins/images/plugins/flash.gif'>
- &nbsp;
- Flash </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 11
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 100%
+ 00:00:00
</td>
- </tr>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicePlugins/images/plugins/java.gif'>
- &nbsp;
- Java </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 11
+ 0%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 100%
+ 0%
</td>
</tr>
- <tr style=";line-height: 22px;">
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicePlugins/images/plugins/director.gif'>
- &nbsp;
- Director </td>
+ 18h </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ 0
</td>
- </tr>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicePlugins/images/plugins/gears.gif'>
- &nbsp;
- Gears </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 00:00:00
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0%
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0%
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicePlugins/images/plugins/pdf.gif'>
- &nbsp;
- Pdf </td>
+ 19h </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ 0
</td>
- </tr>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicePlugins/images/plugins/quicktime.gif'>
- &nbsp;
- Quicktime </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ 00:00:00
</td>
- </tr>
-
- <tr style=";line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicePlugins/images/plugins/realplayer.gif'>
- &nbsp;
- Realplayer </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 0%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0%
@@ -2061,81 +3123,41 @@
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicePlugins/images/plugins/silverlight.gif'>
- &nbsp;
- Silverlight </td>
+ 20h </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ 0
</td>
- </tr>
-
- <tr style=";line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicePlugins/images/plugins/windowsmedia.gif'>
- &nbsp;
- Windowsmedia </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 00:00:00
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0%
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0%
</td>
</tr>
- </tbody>
- </table>
- <br/>
- <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
- Back to top
- </a>
-<h2 id="Resolution_getConfiguration" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Visitor Configuration
-</h2>
-
-
-
- <table style="border-collapse:collapse; margin-left: 5px;">
- <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Configuration&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Visits&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Actions&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Actions per Visit&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Avg. Time on Website&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Bounce Rate&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Conversion Rate&nbsp;&nbsp;
- </th>
- </thead>
- <tbody>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+
+ <tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Unknown / Unknown / 800x300 </td>
+ 21h </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 8
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 40
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 5
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:15:01
+ 00:00:00
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0%
@@ -2145,46 +3167,46 @@
</td>
</tr>
- <tr style=";line-height: 22px;">
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Windows / Firefox / 1024x768 </td>
+ 22h </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 2
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 2
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
00:00:00
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 100%
+ 0%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0%
</td>
</tr>
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Windows / Opera / 800x300 </td>
+ 23h </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
00:00:00
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 100%
+ 0%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0%
@@ -2196,8 +3218,8 @@
<a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
Back to top
</a>
-<h2 id="UserLanguage_getLanguage" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Browser language
+<h2 id="VisitTime_getVisitInformationPerServerTime" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Visits per server time
</h2>
@@ -2205,7 +3227,7 @@
<table style="border-collapse:collapse; margin-left: 5px;">
<thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
<th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Language&nbsp;&nbsp;
+ &nbsp;Server time&nbsp;&nbsp;
</th>
<th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
&nbsp;Visits&nbsp;&nbsp;
@@ -2223,921 +3245,531 @@
&nbsp;Bounce Rate&nbsp;&nbsp;
</th>
<th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Conversion Rate&nbsp;&nbsp;
+ &nbsp;Revenue&nbsp;&nbsp;
</th>
</thead>
<tbody>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Unknown </td>
+ 0h </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 8
+ 1
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 40
+ 1
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 5
+ 1
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:15:01
+ 00:00:00
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ 100%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ $ 0
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- French </td>
+ 1h </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 3
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 3
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
00:00:00
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 100%
+ 0%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ $ 0
</td>
</tr>
- </tbody>
- </table>
- <br/>
- <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
- Back to top
- </a>
-<h2 id="UserLanguage_getLanguageCode" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Language code
-</h2>
-
-
-
- <table style="border-collapse:collapse; margin-left: 5px;">
- <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Language&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Visits&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Actions&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Actions per Visit&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Avg. Time on Website&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Bounce Rate&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Conversion Rate&nbsp;&nbsp;
- </th>
- </thead>
- <tbody>
-
+
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Unknown (xx) </td>
+ 2h </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 8
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 40
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 5
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:15:01
+ 00:00:00
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ $ 0
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- French (fr) </td>
+ 3h </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 3
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 3
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
00:00:00
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 100%
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0%
</td>
- </tr>
- </tbody>
- </table>
- <br/>
- <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
- Back to top
- </a>
-<h2 id="Actions_get" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Actions - Main metrics
-</h2>
-
-
-
- <table style="border-collapse:collapse; margin-left: 5px;">
- <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Name&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Value&nbsp;&nbsp;
- </th>
- </thead>
- <tbody>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Pageviews </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 43
- </td>
- </tr>
-
- <tr style=";line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Unique Pageviews </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 27
+ $ 0
</td>
</tr>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Downloads </td>
+ 4h </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
- </tr>
-
- <tr style=";line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Unique Downloads </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
- </tr>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Outlinks </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 00:00:00
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0%
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ $ 0
+ </td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Unique Outlinks </td>
+ 5h </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
- </tr>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Searches </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
- </tr>
-
- <tr style=";line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Unique Keywords </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
- </tr>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Avg. generation time </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0.3s
+ 00:00:00
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0%
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ $ 0
</td>
</tr>
- </tbody>
- </table>
- <br/>
- <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
- Back to top
- </a>
-<h2 id="Actions_getPageUrls" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Page URLs
-</h2>
-
-
-
- <table style="border-collapse:collapse; margin-left: 5px;">
- <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Page URL&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Pageviews&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Unique Pageviews&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Avg. time on page&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Bounce Rate&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Exit rate&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Avg. generation time&nbsp;&nbsp;
- </th>
- </thead>
- <tbody>
-
+
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- <a style="color: rgb(13,13,13);" href='http://example.org/index.htm'>
- /index.htm </a>
- </td>
+ 6h </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 9
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 9
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:05:20
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 11%
+ 00:00:00
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 11%
+ 0%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0.3s
+ $ 0
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- <a style="color: rgb(13,13,13);" href='http://'>
- Page URL not defined </a>
- </td>
+ 7h </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 17
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 9
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:00:00
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ 00:00:00
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0.22s
+ $ 0
</td>
</tr>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- <a style="color: rgb(13,13,13);" href='http://example.org/thankyou'>
- /thankyou </a>
- </td>
+ 8h </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 16
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 8
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:03:00
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ 00:00:00
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 100%
+ 0%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0.31s
+ $ 0
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- <a style="color: rgb(13,13,13);" href='http://example.org/products'>
- /products </a>
- </td>
+ 9h </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:00:00
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 100%
+ 00:00:00
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 100%
+ 0%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0.15s
+ $ 0
</td>
</tr>
- </tbody>
- </table>
- <br/>
- <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
- Back to top
- </a>
-<h2 id="Actions_getEntryPageUrls" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Entry pages
-</h2>
-
-
-
- <table style="border-collapse:collapse; margin-left: 5px;">
- <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Entry Page URL&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Entrances&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Bounces&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Bounce Rate&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Avg. generation time&nbsp;&nbsp;
- </th>
- </thead>
- <tbody>
-
+
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- <a style="color: rgb(13,13,13);" href='http://example.org/index.htm'>
- /index.htm </a>
- </td>
+ 10h </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 9
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 11%
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0.3s
+ 00:00:00
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0%
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ $ 0
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- <a style="color: rgb(13,13,13);" href='http://example.org/products'>
- /products </a>
- </td>
+ 11h </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
+ 8
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
+ 40
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 100%
+ 5
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0.15s
+ 00:15:01
</td>
- </tr>
- </tbody>
- </table>
- <br/>
- <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
- Back to top
- </a>
-<h2 id="Actions_getExitPageUrls" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Exit pages
-</h2>
-
-
-
- <table style="border-collapse:collapse; margin-left: 5px;">
- <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Exit Page URL&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Exits&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Unique Pageviews&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Exit rate&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Avg. generation time&nbsp;&nbsp;
- </th>
- </thead>
- <tbody>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- <a style="color: rgb(13,13,13);" href='http://example.org/index.htm'>
- /index.htm </a>
- </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
+ 0%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 9
+ $ 0
</td>
+ </tr>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 12h </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 11%
+ 1
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0.3s
+ 1
</td>
- </tr>
-
- <tr style=";line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- <a style="color: rgb(13,13,13);" href='http://example.org/thankyou'>
- /thankyou </a>
- </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 8
+ 1
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 8
+ 00:00:00
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
100%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0.31s
+ $ 0
</td>
</tr>
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- <a style="color: rgb(13,13,13);" href='http://example.org/products'>
- /products </a>
- </td>
+ 13h </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 100%
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0.15s
+ 00:00:00
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0%
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ $ 0
</td>
</tr>
- </tbody>
- </table>
- <br/>
- <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
- Back to top
- </a>
-<h2 id="Actions_getPageTitles" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Page titles
-</h2>
-
-
-
- <table style="border-collapse:collapse; margin-left: 5px;">
- <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Page Name&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Pageviews&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Unique Pageviews&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Avg. time on page&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Bounce Rate&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Exit rate&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Avg. generation time&nbsp;&nbsp;
- </th>
- </thead>
- <tbody>
-
+
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- second visitor </td>
+ 14h </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 16
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 16
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:07:30
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ 00:00:00
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0.25s
+ $ 0
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Checkout </td>
+ 15h </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 8
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 8
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:00:00
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ 00:00:00
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 100%
+ 0%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0.45s
+ $ 0
</td>
</tr>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- first page view </td>
+ 16h </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 2
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 2
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:00:00
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 100%
+ 00:00:00
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 100%
+ 0%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0.14s
+ $ 0
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Page Name not defined </td>
+ 17h </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:00:00
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ 00:00:00
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0.22s
+ $ 0
</td>
</tr>
- </tbody>
- </table>
- <br/>
- <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
- Back to top
- </a>
-<h2 id="Actions_getEntryPageTitles" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Entry page titles
-</h2>
-
-
-
- <table style="border-collapse:collapse; margin-left: 5px;">
- <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Entry Page title&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Entrances&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Bounces&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Bounce Rate&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Avg. generation time&nbsp;&nbsp;
- </th>
- </thead>
- <tbody>
-
+
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- second visitor </td>
+ 18h </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 8
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 00:00:00
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0.25s
+ $ 0
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- first page view </td>
+ 19h </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 2
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 2
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 100%
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0.14s
+ 00:00:00
</td>
- </tr>
- </tbody>
- </table>
- <br/>
- <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
- Back to top
- </a>
-<h2 id="Actions_getExitPageTitles" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Exit page titles
-</h2>
-
-
-
- <table style="border-collapse:collapse; margin-left: 5px;">
- <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Exit Page Title&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Exits&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Unique Pageviews&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Exit rate&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Avg. generation time&nbsp;&nbsp;
- </th>
- </thead>
- <tbody>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Checkout </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 8
+ 0%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 8
+ $ 0
</td>
+ </tr>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 20h </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 100%
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0.45s
+ 0
</td>
- </tr>
-
- <tr style=";line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- first page view </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 2
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 2
+ 00:00:00
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 100%
+ 0%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0.14s
+ $ 0
</td>
</tr>
- </tbody>
- </table>
- <br/>
- <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
- Back to top
- </a>
-<h2 id="Actions_getOutlinks" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Outlinks
-</h2>
-
- There is no data for this report.
-<h2 id="Actions_getDownloads" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Downloads
-</h2>
-
- There is no data for this report.
-<h2 id="Contents_getContentNames" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Content Name
-</h2>
-
- There is no data for this report.
-<h2 id="Contents_getContentPieces" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Content Piece
-</h2>
-
- There is no data for this report.
-<h2 id="Events_getCategory" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Event Categories
-</h2>
-
- There is no data for this report.
-<h2 id="Events_getAction" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Event Actions
-</h2>
-
- There is no data for this report.
-<h2 id="Events_getName" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Event Names
-</h2>
-
- There is no data for this report.
-<h2 id="Actions_getSiteSearchKeywords" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Site Search Keywords
-</h2>
-
- There is no data for this report.
-<h2 id="Actions_getSiteSearchNoResultKeywords" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Search Keywords with No Results
-</h2>
-
- There is no data for this report.
-<h2 id="Actions_getSiteSearchCategories" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Search Categories
-</h2>
-
- There is no data for this report.
-<h2 id="Actions_getPageUrlsFollowingSiteSearch" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Pages Following a Site Search
-</h2>
-
- There is no data for this report.
-<h2 id="Actions_getPageTitlesFollowingSiteSearch" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Page Titles Following a Site Search
-</h2>
-
- There is no data for this report.
-<h2 id="Referrers_getReferrerType" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Referrer Type
-</h2>
-
-
-
- <table style="border-collapse:collapse; margin-left: 5px;">
- <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Referrer Type&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Visits&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Actions&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Actions per Visit&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Avg. Time on Website&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Bounce Rate&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Revenue&nbsp;&nbsp;
- </th>
- </thead>
- <tbody>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+
+ <tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Websites </td>
+ 21h </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 6
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 22
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 3.7
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:10:01
+ 00:00:00
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 33%
+ 0%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
$ 0
</td>
</tr>
- <tr style=";line-height: 22px;">
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Campaigns </td>
+ 22h </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 4
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 20
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 5
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:15:01
+ 00:00:00
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0%
@@ -3147,9 +3779,9 @@
</td>
</tr>
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Direct Entry </td>
+ 23h </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
1
</td>
@@ -3175,8 +3807,8 @@
<a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
Back to top
</a>
-<h2 id="Referrers_getAll" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- All Referrers
+<h2 id="VisitTime_getByDayOfWeek" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Visits by Day of Week
</h2>
@@ -3184,7 +3816,7 @@
<table style="border-collapse:collapse; margin-left: 5px;">
<thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
<th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Referrer&nbsp;&nbsp;
+ &nbsp;Day of the week&nbsp;&nbsp;
</th>
<th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
&nbsp;Visits&nbsp;&nbsp;
@@ -3209,21 +3841,21 @@
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- referrer.com </td>
+ Monday </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 6
+ 2
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 22
+ 6
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 3.7
+ 3
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:10:01
+ 00:07:31
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 33%
+ 50%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0%
@@ -3232,12 +3864,12 @@
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- goal-matching-url-parameter </td>
+ Tuesday </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 4
+ 2
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 20
+ 10
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
5
@@ -3252,122 +3884,38 @@
0%
</td>
</tr>
- </tbody>
- </table>
- <br/>
- <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
- Back to top
- </a>
-<h2 id="Referrers_getKeywords" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Keywords
-</h2>
-
- There is no data for this report.
-<h2 id="Referrers_getWebsites" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Websites
-</h2>
-
-
-
- <table style="border-collapse:collapse; margin-left: 5px;">
- <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Website&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Visits&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Actions&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Actions per Visit&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Avg. Time on Website&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Bounce Rate&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Revenue&nbsp;&nbsp;
- </th>
- </thead>
- <tbody>
-
+
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- referrer.com </td>
+ Wednesday </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 6
+ 1
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 22
+ 5
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 3.7
+ 5
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:10:01
+ 00:15:01
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 33%
+ 0%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
+ 0%
</td>
</tr>
- </tbody>
- </table>
- <br/>
- <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
- Back to top
- </a>
-<h2 id="Referrers_getSearchEngines" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Search Engines
-</h2>
-
- There is no data for this report.
-<h2 id="Referrers_getCampaigns" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Campaigns
-</h2>
-
-
-
- <table style="border-collapse:collapse; margin-left: 5px;">
- <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Campaign&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Visits&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Actions&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Actions per Visit&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Avg. Time on Website&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Bounce Rate&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Revenue&nbsp;&nbsp;
- </th>
- </thead>
- <tbody>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+
+ <tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- goal-matching-url-parameter </td>
+ Thursday </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 4
+ 1
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 20
+ 5
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
5
@@ -3379,126 +3927,41 @@
0%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
+ 0%
</td>
</tr>
- </tbody>
- </table>
- <br/>
- <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
- Back to top
- </a>
-<h2 id="Referrers_getSocials" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Social Networks
-</h2>
-
- There is no data for this report.
-<h2 id="Goals_get" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Goals
-</h2>
-
-
-
- <table style="border-collapse:collapse; margin-left: 5px;">
- <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Name&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Value&nbsp;&nbsp;
- </th>
- </thead>
- <tbody>
-
+
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Conversions </td>
+ Friday </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 1
</td>
- </tr>
-
- <tr style=";line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Visits with Conversions </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 5
</td>
- </tr>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Revenue </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
+ 5
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 00:15:01
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0%
</td>
- </tr>
-
- <tr style=";line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Conversion Rate </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0%
</td>
</tr>
- </tbody>
- </table>
- <br/>
- <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
- Back to top
- </a>
-<h2 id="Goals_getVisitsUntilConversion" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Visits to Conversion
-</h2>
-
- There is no data for this report.
-<h2 id="Goals_getDaysToConversion" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Days to Conversion
-</h2>
-
- There is no data for this report.
-<h2 id="UserCountry_getCountry" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Country
-</h2>
-
-
-
- <table style="border-collapse:collapse; margin-left: 5px;">
- <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Country&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Visits&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Actions&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Actions per Visit&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Avg. Time on Website&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Bounce Rate&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Revenue&nbsp;&nbsp;
- </th>
- </thead>
- <tbody>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+
+ <tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/UserCountry/images/flags/xx.png'>
- &nbsp;
- Unknown </td>
+ Saturday </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 8
+ 1
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 40
+ 5
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
5
@@ -3510,32 +3973,30 @@
0%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
+ 0%
</td>
</tr>
- <tr style=";line-height: 22px;">
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/UserCountry/images/flags/fr.png'>
- &nbsp;
- France </td>
+ Sunday </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
3
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 3
+ 7
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
+ 2.3
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:00:00
+ 00:05:00
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 100%
+ 67%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
+ 0%
</td>
</tr>
</tbody>
@@ -3544,8 +4005,8 @@
<a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
Back to top
</a>
-<h2 id="UserCountry_getContinent" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Continent
+<h2 id="Actions_getPageUrls" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Page URLs
</h2>
@@ -3553,196 +4014,126 @@
<table style="border-collapse:collapse; margin-left: 5px;">
<thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
<th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Continent&nbsp;&nbsp;
+ &nbsp;Page URL&nbsp;&nbsp;
</th>
<th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Visits&nbsp;&nbsp;
+ &nbsp;Pageviews&nbsp;&nbsp;
</th>
<th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Actions&nbsp;&nbsp;
+ &nbsp;Unique Pageviews&nbsp;&nbsp;
</th>
<th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Actions per Visit&nbsp;&nbsp;
+ &nbsp;Avg. time on page&nbsp;&nbsp;
</th>
<th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Avg. Time on Website&nbsp;&nbsp;
+ &nbsp;Bounce Rate&nbsp;&nbsp;
</th>
<th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Bounce Rate&nbsp;&nbsp;
+ &nbsp;Exit rate&nbsp;&nbsp;
</th>
<th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Revenue&nbsp;&nbsp;
+ &nbsp;Avg. generation time&nbsp;&nbsp;
</th>
</thead>
<tbody>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Unknown </td>
+ <a style="color: rgb(13,13,13);" href='http://example.org/index.htm'>
+ /index.htm </a>
+ </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 8
+ 9
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 40
+ 9
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 5
+ 00:05:20
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:15:01
+ 11%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ 11%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
+ 0.3s
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Europe </td>
+ <a style="color: rgb(13,13,13);" href='http://'>
+ Page URL not defined </a>
+ </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 3
+ 17
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 3
+ 9
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
+ 00:00:00
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:00:00
+ 0%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 100%
+ 0%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
+ 0.22s
</td>
</tr>
- </tbody>
- </table>
- <br/>
- <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
- Back to top
- </a>
-<h2 id="UserCountry_getRegion" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Region
-</h2>
-
-
-
- <table style="border-collapse:collapse; margin-left: 5px;">
- <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Region&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Visits&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Actions&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Actions per Visit&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Avg. Time on Website&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Bounce Rate&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Revenue&nbsp;&nbsp;
- </th>
- </thead>
- <tbody>
-
+
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/UserCountry/images/flags/xx.png'>
- &nbsp;
- Unknown </td>
+ <a style="color: rgb(13,13,13);" href='http://example.org/thankyou'>
+ /thankyou </a>
+ </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 11
+ 16
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 43
+ 8
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 3.9
+ 00:03:00
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:10:55
+ 0%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 27%
+ 100%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
+ 0.31s
</td>
</tr>
- </tbody>
- </table>
- <br/>
- <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
- Back to top
- </a>
-<h2 id="UserCountry_getCity" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- City
-</h2>
-
-
-
- <table style="border-collapse:collapse; margin-left: 5px;">
- <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;City&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Visits&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Actions&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Actions per Visit&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Avg. Time on Website&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Bounce Rate&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Revenue&nbsp;&nbsp;
- </th>
- </thead>
- <tbody>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+
+ <tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/UserCountry/images/flags/xx.png'>
- &nbsp;
- Unknown </td>
+ <a style="color: rgb(13,13,13);" href='http://example.org/products'>
+ /products </a>
+ </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 11
+ 1
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 43
+ 1
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 3.9
+ 00:00:00
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:10:55
+ 100%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 27%
+ 100%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
+ 0.15s
</td>
</tr>
</tbody>
@@ -3751,13 +4142,8 @@
<a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
Back to top
</a>
-<h2 id="CustomVariables_getCustomVariables" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Custom Variables
-</h2>
-
- There is no data for this report.
-<h2 id="VisitorInterest_getNumberOfVisitsPerVisitDuration" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Length of Visits
+<h2 id="Actions_getEntryPageUrls" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Entry pages
</h2>
@@ -3765,91 +4151,58 @@
<table style="border-collapse:collapse; margin-left: 5px;">
<thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
<th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Visit duration&nbsp;&nbsp;
+ &nbsp;Entry Page URL&nbsp;&nbsp;
</th>
<th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Visits&nbsp;&nbsp;
+ &nbsp;Entrances&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Bounces&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Bounce Rate&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Avg. generation time&nbsp;&nbsp;
</th>
</thead>
<tbody>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0-10s </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 3
- </td>
- </tr>
-
- <tr style=";line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 11-30s </td>
+ <a style="color: rgb(13,13,13);" href='http://example.org/index.htm'>
+ /index.htm </a>
+ </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 9
</td>
- </tr>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 31-60s </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 1
</td>
- </tr>
-
- <tr style=";line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1-2 min </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 11%
</td>
- </tr>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 2-4 min </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 0.3s
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 4-7 min </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
- </td>
- </tr>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 7-10 min </td>
+ <a style="color: rgb(13,13,13);" href='http://example.org/products'>
+ /products </a>
+ </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 1
</td>
- </tr>
-
- <tr style=";line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 10-15 min </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 1
</td>
- </tr>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 15-30 min </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 8
+ 100%
</td>
- </tr>
-
- <tr style=";line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 30+ min </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 0.15s
</td>
</tr>
</tbody>
@@ -3858,8 +4211,8 @@
<a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
Back to top
</a>
-<h2 id="VisitorInterest_getNumberOfVisitsPerPage" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Pages per Visit
+<h2 id="Actions_getExitPageUrls" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Exit pages
</h2>
@@ -3867,91 +4220,77 @@
<table style="border-collapse:collapse; margin-left: 5px;">
<thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
<th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Pages per visit&nbsp;&nbsp;
+ &nbsp;Exit Page URL&nbsp;&nbsp;
</th>
<th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Visits&nbsp;&nbsp;
+ &nbsp;Exits&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Unique Pageviews&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Exit rate&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Avg. generation time&nbsp;&nbsp;
</th>
</thead>
<tbody>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1 page </td>
+ <a style="color: rgb(13,13,13);" href='http://example.org/index.htm'>
+ /index.htm </a>
+ </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 3
+ 1
</td>
- </tr>
-
- <tr style=";line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 2 pages </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 9
</td>
- </tr>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 3 pages </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 11%
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0.3s
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 4 pages </td>
+ <a style="color: rgb(13,13,13);" href='http://example.org/thankyou'>
+ /thankyou </a>
+ </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 8
</td>
- </tr>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 5 pages </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
8
</td>
- </tr>
-
- <tr style=";line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 6-7 pages </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 100%
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0.31s
</td>
</tr>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 8-10 pages </td>
+ <a style="color: rgb(13,13,13);" href='http://example.org/products'>
+ /products </a>
+ </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 1
</td>
- </tr>
-
- <tr style=";line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 11-14 pages </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 1
</td>
- </tr>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 15-20 pages </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 100%
</td>
- </tr>
-
- <tr style=";line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 21+ pages </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 0.15s
</td>
</tr>
</tbody>
@@ -3960,8 +4299,8 @@
<a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
Back to top
</a>
-<h2 id="VisitorInterest_getNumberOfVisitsByVisitCount" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Visits by Visit Number
+<h2 id="Actions_getPageTitles" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Page titles
</h2>
@@ -3969,168 +4308,118 @@
<table style="border-collapse:collapse; margin-left: 5px;">
<thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
<th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Visits by Visit Number&nbsp;&nbsp;
+ &nbsp;Page Name&nbsp;&nbsp;
</th>
<th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Visits&nbsp;&nbsp;
+ &nbsp;Pageviews&nbsp;&nbsp;
</th>
<th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;% Visits&nbsp;&nbsp;
+ &nbsp;Unique Pageviews&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Avg. time on page&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Bounce Rate&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Exit rate&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Avg. generation time&nbsp;&nbsp;
</th>
</thead>
<tbody>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1 visit </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 3
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 27%
- </td>
- </tr>
-
- <tr style=";line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 2 visits </td>
+ second visitor </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 8
+ 16
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 73%
+ 16
</td>
- </tr>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 3 visits </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 00:07:30
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0%
</td>
- </tr>
-
- <tr style=";line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 4 visits </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
- </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0%
</td>
- </tr>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 5 visits </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
- </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ 0.25s
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 6 visits </td>
+ Checkout </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 8
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ 8
</td>
- </tr>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 7 visits </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 00:00:00
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0%
</td>
- </tr>
-
- <tr style=";line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 8 visits </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 100%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ 0.45s
</td>
</tr>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 9-14 visits </td>
+ first page view </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 2
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ 2
</td>
- </tr>
-
- <tr style=";line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 15-25 visits </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 00:00:00
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ 100%
</td>
- </tr>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 26-50 visits </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 100%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ 0.14s
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 51-100 visits </td>
+ Page Name not defined </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 1
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ 1
</td>
- </tr>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 101-200 visits </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 00:00:00
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0%
</td>
- </tr>
-
- <tr style=";line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 201+ visits </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 0%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ 0.22s
</td>
</tr>
</tbody>
@@ -4139,8 +4428,68 @@
<a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
Back to top
</a>
-<h2 id="VisitorInterest_getNumberOfVisitsByDaysSinceLast" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Visits by days since last visit
+<h2 id="Actions_getSiteSearchKeywords" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Site Search Keywords
+</h2>
+
+ There is no data for this report.
+<h2 id="Actions_getPageUrlsFollowingSiteSearch" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Pages Following a Site Search
+</h2>
+
+ There is no data for this report.
+<h2 id="Actions_getSiteSearchNoResultKeywords" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Search Keywords with No Results
+</h2>
+
+ There is no data for this report.
+<h2 id="Actions_getPageTitlesFollowingSiteSearch" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Page Titles Following a Site Search
+</h2>
+
+ There is no data for this report.
+<h2 id="Actions_getSiteSearchCategories" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Search Categories
+</h2>
+
+ There is no data for this report.
+<h2 id="Actions_getOutlinks" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Outlinks
+</h2>
+
+ There is no data for this report.
+<h2 id="Actions_getDownloads" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Downloads
+</h2>
+
+ There is no data for this report.
+<h2 id="Events_getCategory" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Event Categories
+</h2>
+
+ There is no data for this report.
+<h2 id="Events_getAction" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Event Actions
+</h2>
+
+ There is no data for this report.
+<h2 id="Events_getName" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Event Names
+</h2>
+
+ There is no data for this report.
+<h2 id="Contents_getContentNames" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Content Name
+</h2>
+
+ There is no data for this report.
+<h2 id="Contents_getContentPieces" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Content Piece
+</h2>
+
+ There is no data for this report.
+<h2 id="Actions_get" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Actions - Main metrics
</h2>
@@ -4148,33 +4497,33 @@
<table style="border-collapse:collapse; margin-left: 5px;">
<thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
<th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Visits by days since last visit&nbsp;&nbsp;
+ &nbsp;Name&nbsp;&nbsp;
</th>
<th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Visits&nbsp;&nbsp;
+ &nbsp;Value&nbsp;&nbsp;
</th>
</thead>
<tbody>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- New visits </td>
+ Pageviews </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 2
+ 43
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0 days </td>
+ Unique Pageviews </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
+ 27
</td>
</tr>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1 day </td>
+ Downloads </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
@@ -4182,63 +4531,15 @@
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 2 days </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
- </td>
- </tr>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 3 days </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
- </td>
- </tr>
-
- <tr style=";line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 4 days </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
- </td>
- </tr>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 5 days </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
- </td>
- </tr>
-
- <tr style=";line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 6 days </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
- </td>
- </tr>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 7 days </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
- </td>
- </tr>
-
- <tr style=";line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 8-14 days </td>
+ Unique Downloads </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 2
+ 0
</td>
</tr>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 15-30 days </td>
+ Outlinks </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
@@ -4246,7 +4547,7 @@
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 31-60 days </td>
+ Unique Outlinks </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
@@ -4254,7 +4555,7 @@
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 61-120 days </td>
+ Searches </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
@@ -4262,7 +4563,7 @@
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 121-364 days </td>
+ Unique Keywords </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
@@ -4270,9 +4571,9 @@
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 365+ days </td>
+ Avg. generation time </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 0.3s
</td>
</tr>
</tbody>
@@ -4281,8 +4582,8 @@
<a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
Back to top
</a>
-<h2 id="VisitFrequency_get" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Returning Visits
+<h2 id="Actions_getEntryPageTitles" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Entry page titles
</h2>
@@ -4290,75 +4591,54 @@
<table style="border-collapse:collapse; margin-left: 5px;">
<thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
<th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Name&nbsp;&nbsp;
+ &nbsp;Entry Page title&nbsp;&nbsp;
</th>
<th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Value&nbsp;&nbsp;
+ &nbsp;Entrances&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Bounces&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Bounce Rate&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Avg. generation time&nbsp;&nbsp;
</th>
</thead>
<tbody>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Unique returning visitors </td>
+ second visitor </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 2
+ 8
</td>
- </tr>
-
- <tr style=";line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Returning Users </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
- </tr>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Returning Visits </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 9
+ 0%
</td>
- </tr>
-
- <tr style=";line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Actions by Returning Visits </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 41
+ 0.25s
</td>
</tr>
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Maximum actions in one returning visit </td>
+ first page view </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 5
+ 2
</td>
- </tr>
-
- <tr style=";line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Bounce Rate for Returning Visits </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 11%
+ 2
</td>
- </tr>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Avg. Actions per Returning Visit </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 4.6
+ 100%
</td>
- </tr>
-
- <tr style=";line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Avg. Duration of a Returning Visit (in sec) </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:13:21
+ 0.14s
</td>
</tr>
</tbody>
@@ -4367,8 +4647,8 @@
<a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
Back to top
</a>
-<h2 id="DevicesDetection_getType" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Device type
+<h2 id="Actions_getExitPageTitles" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Exit page titles
</h2>
@@ -4376,76 +4656,54 @@
<table style="border-collapse:collapse; margin-left: 5px;">
<thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
<th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Device type&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Visits&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Actions&nbsp;&nbsp;
+ &nbsp;Exit Page Title&nbsp;&nbsp;
</th>
<th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Actions per Visit&nbsp;&nbsp;
+ &nbsp;Exits&nbsp;&nbsp;
</th>
<th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Avg. Time on Website&nbsp;&nbsp;
+ &nbsp;Unique Pageviews&nbsp;&nbsp;
</th>
<th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Bounce Rate&nbsp;&nbsp;
+ &nbsp;Exit rate&nbsp;&nbsp;
</th>
<th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Conversion Rate&nbsp;&nbsp;
+ &nbsp;Avg. generation time&nbsp;&nbsp;
</th>
</thead>
<tbody>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicesDetection/images/screens/unknown.gif'>
- &nbsp;
- Unknown </td>
+ Checkout </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
8
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 40
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 5
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:15:01
+ 8
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ 100%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ 0.45s
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicesDetection/images/screens/normal.gif'>
- &nbsp;
- Desktop </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 3
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 3
- </td>
+ first page view </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
+ 2
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:00:00
+ 2
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
100%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ 0.14s
</td>
</tr>
</tbody>
@@ -4454,8 +4712,8 @@
<a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
Back to top
</a>
-<h2 id="DevicesDetection_getBrowsers" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Visitor Browser
+<h2 id="Referrers_getReferrerType" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Referrer Type
</h2>
@@ -4463,7 +4721,7 @@
<table style="border-collapse:collapse; margin-left: 5px;">
<thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
<th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Browser&nbsp;&nbsp;
+ &nbsp;Referrer Type&nbsp;&nbsp;
</th>
<th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
&nbsp;Visits&nbsp;&nbsp;
@@ -4481,66 +4739,60 @@
&nbsp;Bounce Rate&nbsp;&nbsp;
</th>
<th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Conversion Rate&nbsp;&nbsp;
+ &nbsp;Revenue&nbsp;&nbsp;
</th>
</thead>
<tbody>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicesDetection/images/browsers/UNK.gif'>
- &nbsp;
- Unknown </td>
+ Websites </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 8
+ 6
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 40
+ 22
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 5
+ 3.7
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:15:01
+ 00:10:01
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ 33%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ $ 0
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicesDetection/images/browsers/FF.gif'>
- &nbsp;
- Firefox </td>
+ Campaigns </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 2
+ 4
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 2
+ 20
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
+ 5
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:00:00
+ 00:15:01
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 100%
+ 0%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ $ 0
</td>
</tr>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicesDetection/images/browsers/OP.gif'>
- &nbsp;
- Opera </td>
+ Direct Entry </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
1
</td>
@@ -4557,129 +4809,7 @@
100%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
- </td>
- </tr>
- </tbody>
- </table>
- <br/>
- <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
- Back to top
- </a>
-<h2 id="DevicesDetection_getBrand" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Device brand
-</h2>
-
-
-
- <table style="border-collapse:collapse; margin-left: 5px;">
- <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Device brand&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Visits&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Actions&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Actions per Visit&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Avg. Time on Website&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Bounce Rate&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Conversion Rate&nbsp;&nbsp;
- </th>
- </thead>
- <tbody>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicesDetection/images/brand/Unknown.ico'>
- &nbsp;
- Unknown </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 11
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 43
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 3.9
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:10:55
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 27%
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
- </td>
- </tr>
- </tbody>
- </table>
- <br/>
- <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
- Back to top
- </a>
-<h2 id="DevicesDetection_getModel" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Device model
-</h2>
-
-
-
- <table style="border-collapse:collapse; margin-left: 5px;">
- <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Device model&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Visits&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Actions&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Actions per Visit&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Avg. Time on Website&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Bounce Rate&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Conversion Rate&nbsp;&nbsp;
- </th>
- </thead>
- <tbody>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Unknown </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 11
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 43
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 3.9
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:10:55
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 27%
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ $ 0
</td>
</tr>
</tbody>
@@ -4688,8 +4818,8 @@
<a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
Back to top
</a>
-<h2 id="DevicesDetection_getBrowserVersions" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Browser version
+<h2 id="Referrers_getAll" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ All Referrers
</h2>
@@ -4697,7 +4827,7 @@
<table style="border-collapse:collapse; margin-left: 5px;">
<thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
<th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Browser version&nbsp;&nbsp;
+ &nbsp;Referrer&nbsp;&nbsp;
</th>
<th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
&nbsp;Visits&nbsp;&nbsp;
@@ -4722,23 +4852,21 @@
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicesDetection/images/browsers/UNK.gif'>
- &nbsp;
- Unknown </td>
+ referrer.com </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 8
+ 6
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 40
+ 22
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 5
+ 3.7
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:15:01
+ 00:10:01
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ 33%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0%
@@ -4747,49 +4875,22 @@
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicesDetection/images/browsers/FF.gif'>
- &nbsp;
- Firefox 3.6 </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 2
- </td>
+ goal-matching-url-parameter </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 2
+ 4
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
+ 20
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:00:00
+ 5
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 100%
+ 00:15:01
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0%
</td>
- </tr>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicesDetection/images/browsers/OP.gif'>
- &nbsp;
- Opera 9.63 </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:00:00
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 100%
- </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0%
</td>
@@ -4800,8 +4901,18 @@
<a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
Back to top
</a>
-<h2 id="DevicesDetection_getOsFamilies" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Operating System families
+<h2 id="Referrers_getKeywords" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Keywords
+</h2>
+
+ There is no data for this report.
+<h2 id="Referrers_getSearchEngines" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Search Engines
+</h2>
+
+ There is no data for this report.
+<h2 id="Referrers_getWebsites" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Websites
</h2>
@@ -4809,7 +4920,7 @@
<table style="border-collapse:collapse; margin-left: 5px;">
<thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
<th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Operating system family&nbsp;&nbsp;
+ &nbsp;Website&nbsp;&nbsp;
</th>
<th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
&nbsp;Visits&nbsp;&nbsp;
@@ -4827,58 +4938,31 @@
&nbsp;Bounce Rate&nbsp;&nbsp;
</th>
<th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Conversion Rate&nbsp;&nbsp;
+ &nbsp;Revenue&nbsp;&nbsp;
</th>
</thead>
<tbody>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicesDetection/images/os/UNK.gif'>
- &nbsp;
- Unknown </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 8
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 40
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 5
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:15:01
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
- </td>
- </tr>
-
- <tr style=";line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicesDetection/images/os/WIN.gif'>
- &nbsp;
- Windows </td>
+ referrer.com </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 3
+ 6
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 3
+ 22
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
+ 3.7
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:00:00
+ 00:10:01
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 100%
+ 33%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ $ 0
</td>
</tr>
</tbody>
@@ -4887,8 +4971,13 @@
<a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
Back to top
</a>
-<h2 id="DevicesDetection_getOsVersions" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Operating System versions
+<h2 id="Referrers_getSocials" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Social Networks
+</h2>
+
+ There is no data for this report.
+<h2 id="Referrers_getCampaigns" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Campaigns
</h2>
@@ -4896,7 +4985,7 @@
<table style="border-collapse:collapse; margin-left: 5px;">
<thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
<th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Operating System versions&nbsp;&nbsp;
+ &nbsp;Campaign&nbsp;&nbsp;
</th>
<th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
&nbsp;Visits&nbsp;&nbsp;
@@ -4914,21 +5003,19 @@
&nbsp;Bounce Rate&nbsp;&nbsp;
</th>
<th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Conversion Rate&nbsp;&nbsp;
+ &nbsp;Revenue&nbsp;&nbsp;
</th>
</thead>
<tbody>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicesDetection/images/os/UNK.gif'>
- &nbsp;
- Unknown </td>
+ goal-matching-url-parameter </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 8
+ 4
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 40
+ 20
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
5
@@ -4940,32 +5027,7 @@
0%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
- </td>
- </tr>
-
- <tr style=";line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicesDetection/images/os/WIN.gif'>
- &nbsp;
- Windows XP </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 3
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 3
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:00:00
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 100%
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ $ 0
</td>
</tr>
</tbody>
@@ -4974,8 +5036,8 @@
<a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
Back to top
</a>
-<h2 id="DevicesDetection_getBrowserEngines" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Browser engines
+<h2 id="Goals_get" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Goals
</h2>
@@ -4983,93 +5045,41 @@
<table style="border-collapse:collapse; margin-left: 5px;">
<thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
<th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Browser engine&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Visits&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Actions&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Actions per Visit&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Avg. Time on Website&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Bounce Rate&nbsp;&nbsp;
+ &nbsp;Name&nbsp;&nbsp;
</th>
<th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Conversion Rate&nbsp;&nbsp;
+ &nbsp;Value&nbsp;&nbsp;
</th>
</thead>
<tbody>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Unknown </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 8
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 40
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 5
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:15:01
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
- </td>
+ Conversions </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ 0
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Gecko (Firefox) </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 2
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 2
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:00:00
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 100%
- </td>
+ Visits with Conversions </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ 0
</td>
</tr>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Presto (Opera) </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:00:00
- </td>
+ Revenue </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 100%
+ $ 0
</td>
+ </tr>
+
+ <tr style=";line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ Conversion Rate </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0%
</td>
@@ -5080,5 +5090,35 @@
<a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
Back to top
</a>
+<h2 id="Goals_getVisitsUntilConversion" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Visits to Conversion
+</h2>
+
+ There is no data for this report.
+<h2 id="Goals_getDaysToConversion" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Days to Conversion
+</h2>
+
+ There is no data for this report.
+<h2 id="ExampleUI_getTemperatures" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Data tables
+</h2>
+
+ There is no data for this report.
+<h2 id="ExampleUI_getTemperaturesEvolution" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Temperatures evolution over time
+</h2>
+
+ There is no data for this report.
+<h2 id="ExampleUI_getPlanetRatios" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Pie graph
+</h2>
+
+ There is no data for this report.
+<h2 id="ExampleUI_getPlanetRatiosWithLogos" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Advanced tag cloud: with logos and links
+</h2>
+
+ There is no data for this report.
</body>
</html> \ No newline at end of file
diff --git a/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_scheduled_report_in_pdf_tables_only__ScheduledReports.generateReport_month.original.pdf b/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_scheduled_report_in_pdf_tables_only__ScheduledReports.generateReport_month.original.pdf
index ffc46593bf..f04618be41 100644
--- a/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_scheduled_report_in_pdf_tables_only__ScheduledReports.generateReport_month.original.pdf
+++ b/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_scheduled_report_in_pdf_tables_only__ScheduledReports.generateReport_month.original.pdf
Binary files differ
diff --git a/tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getGlossaryMetrics.xml b/tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getGlossaryMetrics.xml
index 5499dca4d3..097ddcd4c4 100644
--- a/tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getGlossaryMetrics.xml
+++ b/tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getGlossaryMetrics.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8" ?>
<result>
<row>
- <name>% Search Exits (Site Search)</name>
+ <name>% Search Exits (Actions)</name>
<id>exit_rate</id>
<documentation>The percentage of visits that left the website after searching for this Keyword on your Site Search engine.</documentation>
</row>
@@ -16,7 +16,7 @@
<documentation>The average number of actions (page views, site searches, downloads or outlinks) that were performed during the visits.</documentation>
</row>
<row>
- <name>Avg. Time on Website</name>
+ <name>Avg. Visit Duration (in seconds)</name>
<id>avg_time_on_site</id>
<documentation>The average duration of a visit.</documentation>
</row>
@@ -126,7 +126,7 @@
<documentation>The number of visits that searched for this keyword on your website's search engine.</documentation>
</row>
<row>
- <name>Searches (Site Search)</name>
+ <name>Searches (Actions)</name>
<id>nb_visits</id>
<documentation>The number of visits that searched for this keyword on your website's search engine.</documentation>
</row>
diff --git a/tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getGlossaryReports.xml b/tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getGlossaryReports.xml
index 5b802dbc6c..190aeeea80 100644
--- a/tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getGlossaryReports.xml
+++ b/tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getGlossaryReports.xml
@@ -5,14 +5,18 @@
<documentation>This report shows all your Referrers in one unified report, listing all Websites, Search keywords and Campaigns used by your visitors to find your website.</documentation>
</row>
<row>
- <name>Browser Plugins (Visitor Settings)</name>
+ <name>Browser Plugins (Visitors)</name>
<documentation>This report shows which browser plugins your visitors had enabled. This information might be important for choosing the right way to deliver your content.</documentation>
</row>
<row>
- <name>Browser engines (Visitor Devices)</name>
+ <name>Browser engines (Visitors)</name>
<documentation>This report shows your visitors' browsers broken down into browser engines. &lt;br /&gt; The most important information for web developers is what kind of rendering engine their visitors are using. The labels contain the names of the engines followed by the most common browser using that engine in brackets.</documentation>
</row>
<row>
+ <name>Browsers (Visitors)</name>
+ <documentation>This report contains information about what kind of browser your visitors were using. Each browser version is listed separately.</documentation>
+ </row>
+ <row>
<name>Campaigns (Referrers)</name>
<documentation>This report shows which campaigns led visitors to your website. &lt;br /&gt; For more information about tracking campaigns, read the &lt;a href=&quot;http://piwik.org/docs/tracking-campaigns/&quot; rel=&quot;noreferrer&quot; target=&quot;_blank&quot;&gt;campaigns documentation on piwik.org&lt;/a&gt;</documentation>
</row>
@@ -21,6 +25,10 @@
<documentation>This report shows the cities your visitors were in when they accessed your website.&lt;br/&gt;In order to see data for this report, you must setup GeoIP in the Geolocation admin tab. The commercial &lt;a rel=&quot;noreferrer&quot; target=&quot;_blank&quot; href=&quot;http://www.maxmind.com/?rId=piwik&quot;&gt;Maxmind&lt;/a&gt; GeoIP databases are more accurate than the free ones. To see how accurate they are, click &lt;a rel=&quot;noreferrer&quot; target=&quot;_blank&quot; href=&quot;http://www.maxmind.com/en/city_accuracy?rId=piwik&quot;&gt;here&lt;/a&gt;.</documentation>
</row>
<row>
+ <name>Configurations (Visitors)</name>
+ <documentation>This report shows the most common overall configurations that your visitors had. A configuration is the combination of an operating system, a browser type and a screen resolution.</documentation>
+ </row>
+ <row>
<name>Continent (Visitors)</name>
<documentation>This report shows which continent your visitors were in when they accessed your website.</documentation>
</row>
@@ -65,7 +73,7 @@
<documentation>This report shows a hierarchical list of outlink URLs that were clicked by your visitors. An outlink is a link that leads the visitor away from your website (to another domain).&lt;br /&gt;Use the plus and minus icons on the left to navigate.</documentation>
</row>
<row>
- <name>Page Titles Following a Site Search (Site Search)</name>
+ <name>Page Titles Following a Site Search (Actions)</name>
<documentation>When visitors search on your website, they are looking for a particular page, content, product, or service. This report lists the pages that were clicked the most after an internal search. In other words, the list of pages the most searched for by visitors already on your website.&lt;br/&gt;Use the plus and minus icons on the left to navigate.</documentation>
</row>
<row>
@@ -77,7 +85,7 @@
<documentation>This report contains information about the titles of the pages that have been visited. &lt;br /&gt; The page title is the HTML &lt;title&gt; Tag that most browsers show in their window title.</documentation>
</row>
<row>
- <name>Pages Following a Site Search (Site Search)</name>
+ <name>Pages Following a Site Search (Actions)</name>
<documentation>When visitors search on your website, they are looking for a particular page, content, product, or service. This report lists the pages that were clicked the most after an internal search. In other words, the list of pages the most searched for by visitors already on your website.&lt;br/&gt;Use the plus and minus icons on the left to navigate.</documentation>
</row>
<row>
@@ -93,7 +101,7 @@
<documentation>This report shows which region your visitors were in when they accessed your website.&lt;br/&gt;In order to see data for this report, you must setup GeoIP in the Geolocation admin tab. The commercial &lt;a rel=&quot;noreferrer&quot; target=&quot;_blank&quot; href=&quot;http://www.maxmind.com/?rId=piwik&quot;&gt;Maxmind&lt;/a&gt; GeoIP databases are more accurate than the free ones. To see how accurate they are, click &lt;a rel=&quot;noreferrer&quot; target=&quot;_blank&quot; href=&quot;http://www.maxmind.com/en/city_accuracy?rId=piwik&quot;&gt;here&lt;/a&gt;.</documentation>
</row>
<row>
- <name>Search Categories (Site Search)</name>
+ <name>Search Categories (Actions)</name>
<documentation>This report lists the Categories that visitors selected when they made a Search on your website.&lt;br/&gt;For example, Ecommerce websites typically have a &quot;Category&quot; selector so that visitors can restrict their searches to all products in a specific Category.</documentation>
</row>
<row>
@@ -101,11 +109,11 @@
<documentation>This report shows which search engines referred users to your website. &lt;br /&gt; By clicking on a row in the table, you can see what users were searching for using a specific search engine.</documentation>
</row>
<row>
- <name>Search Keywords with No Results (Site Search)</name>
+ <name>Search Keywords with No Results (Actions)</name>
<documentation>Tracking searches that visitors make on your website is a very effective way to learn more about what your audience is looking for, it can help find ideas for new content, new Ecommerce products that potential customers might be searching for, and generally improve the visitors' experience on your website.&lt;br /&gt;&lt;br /&gt;This report lists the Search Keywords that did not return any Search result: maybe the search engine algorithm can be improved, or maybe your visitors are looking for content that is not (yet) on your website?</documentation>
</row>
<row>
- <name>Site Search Keywords (Site Search)</name>
+ <name>Site Search Keywords (Actions)</name>
<documentation>This report lists the Search Keywords that visitors searched for on your internal Search Engine.&lt;br/&gt;&lt;br/&gt;Tracking searches that visitors make on your website is a very effective way to learn more about what your audience is looking for, it can help find ideas for new content, new Ecommerce products that potential customers might be searching for, and generally improve the visitors' experience on your website.&lt;br/&gt;&lt;br/&gt;&lt;a href=&quot;http://piwik.org/docs/site-search/&quot; rel=&quot;noreferrer&quot; target=&quot;_blank&quot;&gt;Learn more about Tracking how your visitors use your Search engine.&lt;/a&gt;</documentation>
</row>
<row>
@@ -113,34 +121,26 @@
<documentation>In this table, you can see which websites referred visitors to your site. &lt;br /&gt; By clicking on a row in the table, you can see which URLs the links to your website were on.</documentation>
</row>
<row>
- <name>Visitor Browser (Visitor Devices)</name>
- <documentation>This report contains information about what kind of browser your visitors were using. Each browser version is listed separately.</documentation>
+ <name>Visits by Day of Week (Visitors)</name>
+ <documentation>This graph shows the number of visits your website received on each day of the week.</documentation>
</row>
<row>
- <name>Visitor Configuration (Visitor Settings)</name>
- <documentation>This report shows the most common overall configurations that your visitors had. A configuration is the combination of an operating system, a browser type and a screen resolution.</documentation>
+ <name>Visits by Visit Number (Visitors)</name>
+ <documentation>In this report, you can see the number of visits who were the Nth visit, ie. visitors who visited your website at least N times.&lt;br /&gt;Please note, that you can view the report in other ways than as a tag cloud. Use the controls at the bottom of the report to do so.</documentation>
</row>
<row>
- <name>Visits by Day of Week (Visits Summary)</name>
- <documentation>This graph shows the number of visits your website received on each day of the week.</documentation>
+ <name>Visits by days since last visit (Visitors)</name>
+ <documentation>In this report, you can see how many visits were from visitors whose last visit was a certain number of days ago.</documentation>
</row>
<row>
- <name>Visits by Local Time (Visits Summary)</name>
+ <name>Visits per local time (Visitors)</name>
<documentation>This graph shows what time it was in the &lt;strong&gt; visitors' time zones &lt;/strong&gt; during their visits.</documentation>
</row>
<row>
- <name>Visits by Server Time (Visits Summary)</name>
+ <name>Visits per server time (Visitors)</name>
<documentation>This graph shows what time it was in the &lt;strong&gt; server's time zone &lt;/strong&gt; during the visits.</documentation>
</row>
<row>
- <name>Visits by Visit Number (Visitors)</name>
- <documentation>In this report, you can see the number of visits who were the Nth visit, ie. visitors who visited your website at least N times.&lt;br /&gt;Please note, that you can view the report in other ways than as a tag cloud. Use the controls at the bottom of the report to do so.</documentation>
- </row>
- <row>
- <name>Visits by days since last visit (Visitors)</name>
- <documentation>In this report, you can see how many visits were from visitors whose last visit was a certain number of days ago.</documentation>
- </row>
- <row>
<name>Websites (Referrers)</name>
<documentation>In this table, you can see which websites referred visitors to your site. &lt;br /&gt; By clicking on a row in the table, you can see which URLs the links to your website were on.</documentation>
</row>
diff --git a/tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getMetadata_day.xml b/tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getMetadata_day.xml
index 813c7c3279..439a50b51d 100644
--- a/tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getMetadata_day.xml
+++ b/tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getMetadata_day.xml
@@ -2,6 +2,7 @@
<result>
<row>
<category>Visitors</category>
+ <subcategory>Locations</subcategory>
<name>Country</name>
<module>UserCountry</module>
<action>getCountry</action>
diff --git a/tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getProcessedReport_day.xml b/tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getProcessedReport_day.xml
index 7173518fff..4fad658db9 100644
--- a/tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getProcessedReport_day.xml
+++ b/tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getProcessedReport_day.xml
@@ -4,6 +4,7 @@
<prettyDate>Sunday, January 4, 2009</prettyDate>
<metadata>
<category>Visitors</category>
+ <subcategory>Locations</subcategory>
<name>Country</name>
<module>UserCountry</module>
<action>getCountry</action>
diff --git a/tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getReportMetadata_day.xml b/tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getReportMetadata_day.xml
index df6c40e9c4..b9c8e51c20 100644
--- a/tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getReportMetadata_day.xml
+++ b/tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getReportMetadata_day.xml
@@ -67,7 +67,8 @@
<uniqueId>MultiSites_getOne</uniqueId>
</row>
<row>
- <category>Visits Summary</category>
+ <category>Visitors</category>
+ <subcategory>Overview</subcategory>
<name>Visits Summary</name>
<module>VisitsSummary</module>
<action>get</action>
@@ -97,12 +98,13 @@
<uniqueId>VisitsSummary_get</uniqueId>
</row>
<row>
- <category>Visits Summary</category>
- <name>Visits by Server Time</name>
- <module>VisitTime</module>
- <action>getVisitInformationPerServerTime</action>
- <dimension>Server time</dimension>
- <documentation>This graph shows what time it was in the &lt;strong&gt; server's time zone &lt;/strong&gt; during the visits.</documentation>
+ <category>Visitors</category>
+ <subcategory>Custom Variables</subcategory>
+ <name>Custom Variables</name>
+ <module>CustomVariables</module>
+ <action>getCustomVariables</action>
+ <dimension>Custom Variable name</dimension>
+ <documentation>This report contains information about your Custom Variables. Click on a variable name to see the distribution of the values. &lt;br /&gt; For more information about Custom Variables in general, read the &lt;a href=&quot;http://piwik.org/docs/custom-variables/&quot; rel=&quot;noreferrer&quot; target=&quot;_blank&quot;&gt;Custom Variables documentation on piwik.org&lt;/a&gt;</documentation>
<metrics>
<nb_visits>Visits</nb_visits>
<nb_uniq_visitors>Unique visitors</nb_uniq_visitors>
@@ -124,7 +126,7 @@
<avg_time_on_site>Avg. Time on Website</avg_time_on_site>
<bounce_rate>Bounce Rate</bounce_rate>
</processedMetrics>
- <constantRowsCount>1</constantRowsCount>
+ <actionToLoadSubTables>getCustomVariablesValuesFromNameId</actionToLoadSubTables>
<metricsGoal>
<nb_conversions>Conversions</nb_conversions>
<revenue>Revenue</revenue>
@@ -132,16 +134,17 @@
<processedMetricsGoal>
<revenue_per_visit>Revenue per Visit</revenue_per_visit>
</processedMetricsGoal>
- <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=VisitTime&amp;apiAction=getVisitInformationPerServerTime&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
- <uniqueId>VisitTime_getVisitInformationPerServerTime</uniqueId>
+ <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=CustomVariables&amp;apiAction=getCustomVariables&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
+ <imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=CustomVariables&amp;apiAction=getCustomVariables&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
+ <uniqueId>CustomVariables_getCustomVariables</uniqueId>
</row>
<row>
- <category>Visits Summary</category>
- <name>Visits by Local Time</name>
- <module>VisitTime</module>
- <action>getVisitInformationPerLocalTime</action>
- <dimension>Local time</dimension>
- <documentation>This graph shows what time it was in the &lt;strong&gt; visitors' time zones &lt;/strong&gt; during their visits.</documentation>
+ <category>Visitors</category>
+ <subcategory>Devices</subcategory>
+ <name>Device type</name>
+ <module>DevicesDetection</module>
+ <action>getType</action>
+ <dimension>Device type</dimension>
<metrics>
<nb_visits>Visits</nb_visits>
<nb_uniq_visitors>Unique visitors</nb_uniq_visitors>
@@ -164,17 +167,17 @@
<bounce_rate>Bounce Rate</bounce_rate>
<conversion_rate>Conversion Rate</conversion_rate>
</processedMetrics>
- <constantRowsCount>1</constantRowsCount>
- <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=VisitTime&amp;apiAction=getVisitInformationPerLocalTime&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
- <uniqueId>VisitTime_getVisitInformationPerLocalTime</uniqueId>
+ <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=DevicesDetection&amp;apiAction=getType&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
+ <imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=DevicesDetection&amp;apiAction=getType&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
+ <uniqueId>DevicesDetection_getType</uniqueId>
</row>
<row>
- <category>Visits Summary</category>
- <name>Visits by Day of Week</name>
- <module>VisitTime</module>
- <action>getByDayOfWeek</action>
- <dimension>Day of the week</dimension>
- <documentation>This graph shows the number of visits your website received on each day of the week.</documentation>
+ <category>Visitors</category>
+ <subcategory>Devices</subcategory>
+ <name>Device model</name>
+ <module>DevicesDetection</module>
+ <action>getModel</action>
+ <dimension>Device model</dimension>
<metrics>
<nb_visits>Visits</nb_visits>
<nb_uniq_visitors>Unique visitors</nb_uniq_visitors>
@@ -197,12 +200,46 @@
<bounce_rate>Bounce Rate</bounce_rate>
<conversion_rate>Conversion Rate</conversion_rate>
</processedMetrics>
- <constantRowsCount>1</constantRowsCount>
- <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=VisitTime&amp;apiAction=getByDayOfWeek&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
- <uniqueId>VisitTime_getByDayOfWeek</uniqueId>
+ <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=DevicesDetection&amp;apiAction=getModel&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
+ <imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=DevicesDetection&amp;apiAction=getModel&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
+ <uniqueId>DevicesDetection_getModel</uniqueId>
</row>
<row>
- <category>Visitor Settings</category>
+ <category>Visitors</category>
+ <subcategory>Devices</subcategory>
+ <name>Device brand</name>
+ <module>DevicesDetection</module>
+ <action>getBrand</action>
+ <dimension>Device brand</dimension>
+ <metrics>
+ <nb_visits>Visits</nb_visits>
+ <nb_uniq_visitors>Unique visitors</nb_uniq_visitors>
+ <nb_actions>Actions</nb_actions>
+ <nb_users>Users</nb_users>
+ </metrics>
+ <metricsDocumentation>
+ <nb_visits>If a visitor comes to your website for the first time or if he visits a page more than 30 minutes after his last page view, this will be recorded as a new visit.</nb_visits>
+ <nb_uniq_visitors>The number of unduplicated visitors coming to your website. Every user is only counted once, even if he visits the website multiple times a day.</nb_uniq_visitors>
+ <nb_actions>The number of actions performed by your visitors. Actions can be page views, internal site searches, downloads or outlinks.</nb_actions>
+ <nb_users>The number of users logged in your website. It is the number of unique active users that have a User ID set (via the Tracking code function 'setUserId').</nb_users>
+ <nb_actions_per_visit>The average number of actions (page views, site searches, downloads or outlinks) that were performed during the visits.</nb_actions_per_visit>
+ <avg_time_on_site>The average duration of a visit.</avg_time_on_site>
+ <bounce_rate>The percentage of visits that only had a single pageview. This means, that the visitor left the website directly from the entrance page.</bounce_rate>
+ <conversion_rate>The percentage of visits that triggered a goal conversion.</conversion_rate>
+ </metricsDocumentation>
+ <processedMetrics>
+ <nb_actions_per_visit>Actions per Visit</nb_actions_per_visit>
+ <avg_time_on_site>Avg. Time on Website</avg_time_on_site>
+ <bounce_rate>Bounce Rate</bounce_rate>
+ <conversion_rate>Conversion Rate</conversion_rate>
+ </processedMetrics>
+ <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=DevicesDetection&amp;apiAction=getBrand&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
+ <imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=DevicesDetection&amp;apiAction=getBrand&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
+ <uniqueId>DevicesDetection_getBrand</uniqueId>
+ </row>
+ <row>
+ <category>Visitors</category>
+ <subcategory>Devices</subcategory>
<name>Screen Resolution</name>
<module>Resolution</module>
<action>getResolution</action>
@@ -229,33 +266,142 @@
<bounce_rate>Bounce Rate</bounce_rate>
<conversion_rate>Conversion Rate</conversion_rate>
</processedMetrics>
+ <relatedReports>
+ <row>
+ <name>Configurations</name>
+ <module>Resolution</module>
+ <action>getConfiguration</action>
+ </row>
+ </relatedReports>
<imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Resolution&amp;apiAction=getResolution&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
<imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Resolution&amp;apiAction=getResolution&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
<uniqueId>Resolution_getResolution</uniqueId>
</row>
<row>
- <category>Visitor Settings</category>
- <name>Browser Plugins</name>
- <module>DevicePlugins</module>
- <action>getPlugin</action>
- <dimension>Plugin</dimension>
- <documentation>This report shows which browser plugins your visitors had enabled. This information might be important for choosing the right way to deliver your content.</documentation>
+ <category>Visitors</category>
+ <subcategory>Software</subcategory>
+ <name>Operating System versions</name>
+ <module>DevicesDetection</module>
+ <action>getOsVersions</action>
+ <dimension>Operating System versions</dimension>
<metrics>
<nb_visits>Visits</nb_visits>
+ <nb_uniq_visitors>Unique visitors</nb_uniq_visitors>
+ <nb_actions>Actions</nb_actions>
+ <nb_users>Users</nb_users>
</metrics>
<metricsDocumentation>
<nb_visits>If a visitor comes to your website for the first time or if he visits a page more than 30 minutes after his last page view, this will be recorded as a new visit.</nb_visits>
+ <nb_uniq_visitors>The number of unduplicated visitors coming to your website. Every user is only counted once, even if he visits the website multiple times a day.</nb_uniq_visitors>
+ <nb_actions>The number of actions performed by your visitors. Actions can be page views, internal site searches, downloads or outlinks.</nb_actions>
+ <nb_users>The number of users logged in your website. It is the number of unique active users that have a User ID set (via the Tracking code function 'setUserId').</nb_users>
+ <nb_actions_per_visit>The average number of actions (page views, site searches, downloads or outlinks) that were performed during the visits.</nb_actions_per_visit>
+ <avg_time_on_site>The average duration of a visit.</avg_time_on_site>
+ <bounce_rate>The percentage of visits that only had a single pageview. This means, that the visitor left the website directly from the entrance page.</bounce_rate>
+ <conversion_rate>The percentage of visits that triggered a goal conversion.</conversion_rate>
</metricsDocumentation>
<processedMetrics>
- <nb_visits_percentage>% Visits</nb_visits_percentage>
+ <nb_actions_per_visit>Actions per Visit</nb_actions_per_visit>
+ <avg_time_on_site>Avg. Time on Website</avg_time_on_site>
+ <bounce_rate>Bounce Rate</bounce_rate>
+ <conversion_rate>Conversion Rate</conversion_rate>
</processedMetrics>
- <constantRowsCount>1</constantRowsCount>
- <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=DevicePlugins&amp;apiAction=getPlugin&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
- <uniqueId>DevicePlugins_getPlugin</uniqueId>
+ <relatedReports>
+ <row>
+ <name>Operating System families</name>
+ <module>DevicesDetection</module>
+ <action>getOsFamilies</action>
+ </row>
+ </relatedReports>
+ <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=DevicesDetection&amp;apiAction=getOsVersions&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
+ <imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=DevicesDetection&amp;apiAction=getOsVersions&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
+ <uniqueId>DevicesDetection_getOsVersions</uniqueId>
+ </row>
+ <row>
+ <category>Visitors</category>
+ <subcategory>Software</subcategory>
+ <name>Browsers</name>
+ <module>DevicesDetection</module>
+ <action>getBrowsers</action>
+ <dimension>Browser</dimension>
+ <documentation>This report contains information about what kind of browser your visitors were using. Each browser version is listed separately.</documentation>
+ <metrics>
+ <nb_visits>Visits</nb_visits>
+ <nb_uniq_visitors>Unique visitors</nb_uniq_visitors>
+ <nb_actions>Actions</nb_actions>
+ <nb_users>Users</nb_users>
+ </metrics>
+ <metricsDocumentation>
+ <nb_visits>If a visitor comes to your website for the first time or if he visits a page more than 30 minutes after his last page view, this will be recorded as a new visit.</nb_visits>
+ <nb_uniq_visitors>The number of unduplicated visitors coming to your website. Every user is only counted once, even if he visits the website multiple times a day.</nb_uniq_visitors>
+ <nb_actions>The number of actions performed by your visitors. Actions can be page views, internal site searches, downloads or outlinks.</nb_actions>
+ <nb_users>The number of users logged in your website. It is the number of unique active users that have a User ID set (via the Tracking code function 'setUserId').</nb_users>
+ <nb_actions_per_visit>The average number of actions (page views, site searches, downloads or outlinks) that were performed during the visits.</nb_actions_per_visit>
+ <avg_time_on_site>The average duration of a visit.</avg_time_on_site>
+ <bounce_rate>The percentage of visits that only had a single pageview. This means, that the visitor left the website directly from the entrance page.</bounce_rate>
+ <conversion_rate>The percentage of visits that triggered a goal conversion.</conversion_rate>
+ </metricsDocumentation>
+ <processedMetrics>
+ <nb_actions_per_visit>Actions per Visit</nb_actions_per_visit>
+ <avg_time_on_site>Avg. Time on Website</avg_time_on_site>
+ <bounce_rate>Bounce Rate</bounce_rate>
+ <conversion_rate>Conversion Rate</conversion_rate>
+ </processedMetrics>
+ <relatedReports>
+ <row>
+ <name>Browser version</name>
+ <module>DevicesDetection</module>
+ <action>getBrowserVersions</action>
+ </row>
+ </relatedReports>
+ <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=DevicesDetection&amp;apiAction=getBrowsers&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
+ <imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=DevicesDetection&amp;apiAction=getBrowsers&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
+ <uniqueId>DevicesDetection_getBrowsers</uniqueId>
</row>
<row>
- <category>Visitor Settings</category>
- <name>Visitor Configuration</name>
+ <category>Visitors</category>
+ <subcategory>Software</subcategory>
+ <name>Browser version</name>
+ <module>DevicesDetection</module>
+ <action>getBrowserVersions</action>
+ <dimension>Browser version</dimension>
+ <metrics>
+ <nb_visits>Visits</nb_visits>
+ <nb_uniq_visitors>Unique visitors</nb_uniq_visitors>
+ <nb_actions>Actions</nb_actions>
+ <nb_users>Users</nb_users>
+ </metrics>
+ <metricsDocumentation>
+ <nb_visits>If a visitor comes to your website for the first time or if he visits a page more than 30 minutes after his last page view, this will be recorded as a new visit.</nb_visits>
+ <nb_uniq_visitors>The number of unduplicated visitors coming to your website. Every user is only counted once, even if he visits the website multiple times a day.</nb_uniq_visitors>
+ <nb_actions>The number of actions performed by your visitors. Actions can be page views, internal site searches, downloads or outlinks.</nb_actions>
+ <nb_users>The number of users logged in your website. It is the number of unique active users that have a User ID set (via the Tracking code function 'setUserId').</nb_users>
+ <nb_actions_per_visit>The average number of actions (page views, site searches, downloads or outlinks) that were performed during the visits.</nb_actions_per_visit>
+ <avg_time_on_site>The average duration of a visit.</avg_time_on_site>
+ <bounce_rate>The percentage of visits that only had a single pageview. This means, that the visitor left the website directly from the entrance page.</bounce_rate>
+ <conversion_rate>The percentage of visits that triggered a goal conversion.</conversion_rate>
+ </metricsDocumentation>
+ <processedMetrics>
+ <nb_actions_per_visit>Actions per Visit</nb_actions_per_visit>
+ <avg_time_on_site>Avg. Time on Website</avg_time_on_site>
+ <bounce_rate>Bounce Rate</bounce_rate>
+ <conversion_rate>Conversion Rate</conversion_rate>
+ </processedMetrics>
+ <relatedReports>
+ <row>
+ <name>Browsers</name>
+ <module>DevicesDetection</module>
+ <action>getBrowsers</action>
+ </row>
+ </relatedReports>
+ <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=DevicesDetection&amp;apiAction=getBrowserVersions&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
+ <imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=DevicesDetection&amp;apiAction=getBrowserVersions&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
+ <uniqueId>DevicesDetection_getBrowserVersions</uniqueId>
+ </row>
+ <row>
+ <category>Visitors</category>
+ <subcategory>Software</subcategory>
+ <name>Configurations</name>
<module>Resolution</module>
<action>getConfiguration</action>
<dimension>Configuration</dimension>
@@ -282,16 +428,24 @@
<bounce_rate>Bounce Rate</bounce_rate>
<conversion_rate>Conversion Rate</conversion_rate>
</processedMetrics>
+ <relatedReports>
+ <row>
+ <name>Screen Resolution</name>
+ <module>Resolution</module>
+ <action>getResolution</action>
+ </row>
+ </relatedReports>
<imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Resolution&amp;apiAction=getConfiguration&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
<imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Resolution&amp;apiAction=getConfiguration&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
<uniqueId>Resolution_getConfiguration</uniqueId>
</row>
<row>
- <category>Visitor Settings</category>
- <name>Browser language</name>
- <module>UserLanguage</module>
- <action>getLanguage</action>
- <dimension>Language</dimension>
+ <category>Visitors</category>
+ <subcategory>Software</subcategory>
+ <name>Operating System families</name>
+ <module>DevicesDetection</module>
+ <action>getOsFamilies</action>
+ <dimension>Operating system family</dimension>
<metrics>
<nb_visits>Visits</nb_visits>
<nb_uniq_visitors>Unique visitors</nb_uniq_visitors>
@@ -314,16 +468,25 @@
<bounce_rate>Bounce Rate</bounce_rate>
<conversion_rate>Conversion Rate</conversion_rate>
</processedMetrics>
- <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=UserLanguage&amp;apiAction=getLanguage&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
- <imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=UserLanguage&amp;apiAction=getLanguage&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
- <uniqueId>UserLanguage_getLanguage</uniqueId>
+ <relatedReports>
+ <row>
+ <name>Operating System versions</name>
+ <module>DevicesDetection</module>
+ <action>getOsVersions</action>
+ </row>
+ </relatedReports>
+ <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=DevicesDetection&amp;apiAction=getOsFamilies&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
+ <imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=DevicesDetection&amp;apiAction=getOsFamilies&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
+ <uniqueId>DevicesDetection_getOsFamilies</uniqueId>
</row>
<row>
- <category>Visitor Settings</category>
- <name>Language code</name>
- <module>UserLanguage</module>
- <action>getLanguageCode</action>
- <dimension>Language</dimension>
+ <category>Visitors</category>
+ <subcategory>Software</subcategory>
+ <name>Browser engines</name>
+ <module>DevicesDetection</module>
+ <action>getBrowserEngines</action>
+ <dimension>Browser engine</dimension>
+ <documentation>This report shows your visitors' browsers broken down into browser engines. &lt;br /&gt; The most important information for web developers is what kind of rendering engine their visitors are using. The labels contain the names of the engines followed by the most common browser using that engine in brackets.</documentation>
<metrics>
<nb_visits>Visits</nb_visits>
<nb_uniq_visitors>Unique visitors</nb_uniq_visitors>
@@ -346,284 +509,485 @@
<bounce_rate>Bounce Rate</bounce_rate>
<conversion_rate>Conversion Rate</conversion_rate>
</processedMetrics>
- <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=UserLanguage&amp;apiAction=getLanguageCode&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
- <imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=UserLanguage&amp;apiAction=getLanguageCode&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
- <uniqueId>UserLanguage_getLanguageCode</uniqueId>
+ <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=DevicesDetection&amp;apiAction=getBrowserEngines&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
+ <imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=DevicesDetection&amp;apiAction=getBrowserEngines&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
+ <uniqueId>DevicesDetection_getBrowserEngines</uniqueId>
</row>
<row>
- <category>API</category>
- <name>Main metrics</name>
- <module>API</module>
- <action>get</action>
+ <category>Visitors</category>
+ <subcategory>Software</subcategory>
+ <name>Browser Plugins</name>
+ <module>DevicePlugins</module>
+ <action>getPlugin</action>
+ <dimension>Plugin</dimension>
+ <documentation>This report shows which browser plugins your visitors had enabled. This information might be important for choosing the right way to deliver your content.</documentation>
<metrics>
- <nb_pageviews>Pageviews</nb_pageviews>
- <nb_uniq_pageviews>Unique Pageviews</nb_uniq_pageviews>
- <nb_downloads>Downloads</nb_downloads>
- <nb_uniq_downloads>Unique Downloads</nb_uniq_downloads>
- <nb_outlinks>Outlinks</nb_outlinks>
- <nb_uniq_outlinks>Unique Outlinks</nb_uniq_outlinks>
- <nb_searches>Searches</nb_searches>
- <nb_keywords>Unique Keywords</nb_keywords>
+ <nb_visits>Visits</nb_visits>
+ </metrics>
+ <metricsDocumentation>
+ <nb_visits>If a visitor comes to your website for the first time or if he visits a page more than 30 minutes after his last page view, this will be recorded as a new visit.</nb_visits>
+ </metricsDocumentation>
+ <processedMetrics>
+ <nb_visits_percentage>% Visits</nb_visits_percentage>
+ </processedMetrics>
+ <constantRowsCount>1</constantRowsCount>
+ <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=DevicePlugins&amp;apiAction=getPlugin&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
+ <uniqueId>DevicePlugins_getPlugin</uniqueId>
+ </row>
+ <row>
+ <category>Visitors</category>
+ <subcategory>Locations</subcategory>
+ <name>Country</name>
+ <module>UserCountry</module>
+ <action>getCountry</action>
+ <dimension>Country</dimension>
+ <documentation>This report shows which country your visitors were in when they accessed your website.</documentation>
+ <metrics>
+ <nb_visits>Visits</nb_visits>
+ <nb_uniq_visitors>Unique visitors</nb_uniq_visitors>
+ <nb_actions>Actions</nb_actions>
+ </metrics>
+ <metricsDocumentation>
+ <nb_visits>If a visitor comes to your website for the first time or if he visits a page more than 30 minutes after his last page view, this will be recorded as a new visit.</nb_visits>
+ <nb_uniq_visitors>The number of unduplicated visitors coming to your website. Every user is only counted once, even if he visits the website multiple times a day.</nb_uniq_visitors>
+ <nb_actions>The number of actions performed by your visitors. Actions can be page views, internal site searches, downloads or outlinks.</nb_actions>
+ <nb_actions_per_visit>The average number of actions (page views, site searches, downloads or outlinks) that were performed during the visits.</nb_actions_per_visit>
+ <avg_time_on_site>The average duration of a visit.</avg_time_on_site>
+ <bounce_rate>The percentage of visits that only had a single pageview. This means, that the visitor left the website directly from the entrance page.</bounce_rate>
+ <conversion_rate>The percentage of visits that triggered a goal conversion.</conversion_rate>
+ </metricsDocumentation>
+ <processedMetrics>
+ <nb_actions_per_visit>Actions per Visit</nb_actions_per_visit>
+ <avg_time_on_site>Avg. Time on Website</avg_time_on_site>
+ <bounce_rate>Bounce Rate</bounce_rate>
+ </processedMetrics>
+ <metricsGoal>
<nb_conversions>Conversions</nb_conversions>
- <nb_visits_converted>Visits with Conversions</nb_visits_converted>
<revenue>Revenue</revenue>
- <nb_uniq_visitors>Unique visitors</nb_uniq_visitors>
+ </metricsGoal>
+ <processedMetricsGoal>
+ <revenue_per_visit>Revenue per Visit</revenue_per_visit>
+ </processedMetricsGoal>
+ <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=UserCountry&amp;apiAction=getCountry&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
+ <imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=UserCountry&amp;apiAction=getCountry&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
+ <uniqueId>UserCountry_getCountry</uniqueId>
+ </row>
+ <row>
+ <category>Visitors</category>
+ <subcategory>Locations</subcategory>
+ <name>Continent</name>
+ <module>UserCountry</module>
+ <action>getContinent</action>
+ <dimension>Continent</dimension>
+ <documentation>This report shows which continent your visitors were in when they accessed your website.</documentation>
+ <metrics>
<nb_visits>Visits</nb_visits>
- <nb_users>Users</nb_users>
+ <nb_uniq_visitors>Unique visitors</nb_uniq_visitors>
<nb_actions>Actions</nb_actions>
- <max_actions>Maximum actions in one visit</max_actions>
- <nb_visits_returning>Returning Visits</nb_visits_returning>
- <nb_actions_returning>Actions by Returning Visits</nb_actions_returning>
- <nb_uniq_visitors_returning>Unique returning visitors</nb_uniq_visitors_returning>
- <nb_users_returning>Returning Users</nb_users_returning>
- <max_actions_returning>Maximum actions in one returning visit</max_actions_returning>
</metrics>
<metricsDocumentation>
- <nb_pageviews>The number of times this page was visited.</nb_pageviews>
- <nb_uniq_pageviews>The number of visits that included this page. If a page was viewed multiple times during one visit, it is only counted once.</nb_uniq_pageviews>
- <nb_downloads>The number of times this link was clicked.</nb_downloads>
- <nb_uniq_downloads>The number of visits that involved a click on this link. If a link was clicked multiple times during one visit, it is only counted once.</nb_uniq_downloads>
- <nb_outlinks>The number of times this link was clicked.</nb_outlinks>
- <nb_uniq_outlinks>The number of visits that involved a click on this link. If a link was clicked multiple times during one visit, it is only counted once.</nb_uniq_outlinks>
- <nb_searches>The number of visits that searched for this keyword on your website's search engine.</nb_searches>
- <nb_uniq_visitors>The number of unduplicated visitors coming to your website. Every user is only counted once, even if he visits the website multiple times a day.</nb_uniq_visitors>
<nb_visits>If a visitor comes to your website for the first time or if he visits a page more than 30 minutes after his last page view, this will be recorded as a new visit.</nb_visits>
- <nb_users>The number of users logged in your website. It is the number of unique active users that have a User ID set (via the Tracking code function 'setUserId').</nb_users>
+ <nb_uniq_visitors>The number of unduplicated visitors coming to your website. Every user is only counted once, even if he visits the website multiple times a day.</nb_uniq_visitors>
<nb_actions>The number of actions performed by your visitors. Actions can be page views, internal site searches, downloads or outlinks.</nb_actions>
- <avg_time_generation>The average time it took to generate the page. This metric includes the time it took the server to generate the web page, plus the time it took for the visitor to download the response from the server. A lower 'Avg. generation time' means a faster website for your visitors!</avg_time_generation>
- <conversion_rate>The percentage of visits that triggered a goal conversion.</conversion_rate>
- <bounce_rate>The percentage of visits that only had a single pageview. This means, that the visitor left the website directly from the entrance page.</bounce_rate>
<nb_actions_per_visit>The average number of actions (page views, site searches, downloads or outlinks) that were performed during the visits.</nb_actions_per_visit>
<avg_time_on_site>The average duration of a visit.</avg_time_on_site>
+ <bounce_rate>The percentage of visits that only had a single pageview. This means, that the visitor left the website directly from the entrance page.</bounce_rate>
+ <conversion_rate>The percentage of visits that triggered a goal conversion.</conversion_rate>
</metricsDocumentation>
<processedMetrics>
- <avg_time_generation>Avg. generation time</avg_time_generation>
- <conversion_rate>Conversion Rate</conversion_rate>
- <bounce_rate>Bounce Rate</bounce_rate>
<nb_actions_per_visit>Actions per Visit</nb_actions_per_visit>
- <avg_time_on_site>Avg. Visit Duration (in seconds)</avg_time_on_site>
- <avg_time_on_site_returning>Avg. Duration of a Returning Visit (in sec)</avg_time_on_site_returning>
- <nb_actions_per_visit_returning>Avg. Actions per Returning Visit</nb_actions_per_visit_returning>
- <bounce_rate_returning>Bounce Rate for Returning Visits</bounce_rate_returning>
+ <avg_time_on_site>Avg. Time on Website</avg_time_on_site>
+ <bounce_rate>Bounce Rate</bounce_rate>
</processedMetrics>
- <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=API&amp;apiAction=get&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphUrl>
- <imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=API&amp;apiAction=get&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
- <uniqueId>API_get</uniqueId>
+ <metricsGoal>
+ <nb_conversions>Conversions</nb_conversions>
+ <revenue>Revenue</revenue>
+ </metricsGoal>
+ <processedMetricsGoal>
+ <revenue_per_visit>Revenue per Visit</revenue_per_visit>
+ </processedMetricsGoal>
+ <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=UserCountry&amp;apiAction=getContinent&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
+ <imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=UserCountry&amp;apiAction=getContinent&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
+ <uniqueId>UserCountry_getContinent</uniqueId>
</row>
<row>
- <category>Ecommerce</category>
- <name>Ecommerce Orders</name>
- <module>Goals</module>
- <action>get</action>
- <parameters>
- <idGoal>ecommerceOrder</idGoal>
- </parameters>
+ <category>Visitors</category>
+ <subcategory>Locations</subcategory>
+ <name>Region</name>
+ <module>UserCountry</module>
+ <action>getRegion</action>
+ <dimension>Region</dimension>
+ <documentation>This report shows which region your visitors were in when they accessed your website.&lt;br/&gt;In order to see data for this report, you must setup GeoIP in the Geolocation admin tab. The commercial &lt;a rel=&quot;noreferrer&quot; target=&quot;_blank&quot; href=&quot;http://www.maxmind.com/?rId=piwik&quot;&gt;Maxmind&lt;/a&gt; GeoIP databases are more accurate than the free ones. To see how accurate they are, click &lt;a rel=&quot;noreferrer&quot; target=&quot;_blank&quot; href=&quot;http://www.maxmind.com/en/city_accuracy?rId=piwik&quot;&gt;here&lt;/a&gt;.</documentation>
<metrics>
- <nb_conversions>Ecommerce Orders</nb_conversions>
- <nb_visits_converted>Visits with Conversions</nb_visits_converted>
- <conversion_rate>Conversion Rate</conversion_rate>
- <revenue>Revenue</revenue>
- <revenue_subtotal>Subtotal</revenue_subtotal>
- <revenue_tax>Tax</revenue_tax>
- <revenue_shipping>Shipping</revenue_shipping>
- <revenue_discount>Discount</revenue_discount>
- <items>Purchased Products</items>
+ <nb_visits>Visits</nb_visits>
+ <nb_uniq_visitors>Unique visitors</nb_uniq_visitors>
+ <nb_actions>Actions</nb_actions>
</metrics>
<metricsDocumentation>
+ <nb_visits>If a visitor comes to your website for the first time or if he visits a page more than 30 minutes after his last page view, this will be recorded as a new visit.</nb_visits>
+ <nb_uniq_visitors>The number of unduplicated visitors coming to your website. Every user is only counted once, even if he visits the website multiple times a day.</nb_uniq_visitors>
+ <nb_actions>The number of actions performed by your visitors. Actions can be page views, internal site searches, downloads or outlinks.</nb_actions>
+ <nb_actions_per_visit>The average number of actions (page views, site searches, downloads or outlinks) that were performed during the visits.</nb_actions_per_visit>
+ <avg_time_on_site>The average duration of a visit.</avg_time_on_site>
+ <bounce_rate>The percentage of visits that only had a single pageview. This means, that the visitor left the website directly from the entrance page.</bounce_rate>
<conversion_rate>The percentage of visits that triggered a goal conversion.</conversion_rate>
</metricsDocumentation>
<processedMetrics>
- <avg_order_revenue>Average Order Value</avg_order_revenue>
+ <nb_actions_per_visit>Actions per Visit</nb_actions_per_visit>
+ <avg_time_on_site>Avg. Time on Website</avg_time_on_site>
+ <bounce_rate>Bounce Rate</bounce_rate>
</processedMetrics>
- <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Goals&amp;apiAction=get&amp;idGoal=ecommerceOrder&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphUrl>
- <imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Goals&amp;apiAction=get&amp;idGoal=ecommerceOrder&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
- <uniqueId>Goals_get_idGoal--ecommerceOrder</uniqueId>
+ <metricsGoal>
+ <nb_conversions>Conversions</nb_conversions>
+ <revenue>Revenue</revenue>
+ </metricsGoal>
+ <processedMetricsGoal>
+ <revenue_per_visit>Revenue per Visit</revenue_per_visit>
+ </processedMetricsGoal>
+ <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=UserCountry&amp;apiAction=getRegion&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
+ <imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=UserCountry&amp;apiAction=getRegion&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
+ <uniqueId>UserCountry_getRegion</uniqueId>
</row>
<row>
- <category>Ecommerce</category>
- <name>Ecommerce Orders - Visits to Conversion</name>
- <module>Goals</module>
- <action>getVisitsUntilConversion</action>
- <parameters>
- <idGoal>ecommerceOrder</idGoal>
- </parameters>
- <dimension>Visits to Conversion</dimension>
+ <category>Visitors</category>
+ <subcategory>Locations</subcategory>
+ <name>Browser language</name>
+ <module>UserLanguage</module>
+ <action>getLanguage</action>
+ <dimension>Language</dimension>
<metrics>
- <nb_conversions>Conversions</nb_conversions>
+ <nb_visits>Visits</nb_visits>
+ <nb_uniq_visitors>Unique visitors</nb_uniq_visitors>
+ <nb_actions>Actions</nb_actions>
+ <nb_users>Users</nb_users>
</metrics>
- <constantRowsCount>1</constantRowsCount>
- <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Goals&amp;apiAction=getVisitsUntilConversion&amp;idGoal=ecommerceOrder&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
- <uniqueId>Goals_getVisitsUntilConversion_idGoal--ecommerceOrder</uniqueId>
+ <metricsDocumentation>
+ <nb_visits>If a visitor comes to your website for the first time or if he visits a page more than 30 minutes after his last page view, this will be recorded as a new visit.</nb_visits>
+ <nb_uniq_visitors>The number of unduplicated visitors coming to your website. Every user is only counted once, even if he visits the website multiple times a day.</nb_uniq_visitors>
+ <nb_actions>The number of actions performed by your visitors. Actions can be page views, internal site searches, downloads or outlinks.</nb_actions>
+ <nb_users>The number of users logged in your website. It is the number of unique active users that have a User ID set (via the Tracking code function 'setUserId').</nb_users>
+ <nb_actions_per_visit>The average number of actions (page views, site searches, downloads or outlinks) that were performed during the visits.</nb_actions_per_visit>
+ <avg_time_on_site>The average duration of a visit.</avg_time_on_site>
+ <bounce_rate>The percentage of visits that only had a single pageview. This means, that the visitor left the website directly from the entrance page.</bounce_rate>
+ <conversion_rate>The percentage of visits that triggered a goal conversion.</conversion_rate>
+ </metricsDocumentation>
+ <processedMetrics>
+ <nb_actions_per_visit>Actions per Visit</nb_actions_per_visit>
+ <avg_time_on_site>Avg. Time on Website</avg_time_on_site>
+ <bounce_rate>Bounce Rate</bounce_rate>
+ <conversion_rate>Conversion Rate</conversion_rate>
+ </processedMetrics>
+ <relatedReports>
+ <row>
+ <name>Language code</name>
+ <module>UserLanguage</module>
+ <action>getLanguageCode</action>
+ </row>
+ </relatedReports>
+ <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=UserLanguage&amp;apiAction=getLanguage&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
+ <imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=UserLanguage&amp;apiAction=getLanguage&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
+ <uniqueId>UserLanguage_getLanguage</uniqueId>
</row>
<row>
- <category>Ecommerce</category>
- <name>Ecommerce Orders - Days to Conversion</name>
- <module>Goals</module>
- <action>getDaysToConversion</action>
- <parameters>
- <idGoal>ecommerceOrder</idGoal>
- </parameters>
- <dimension>Days to Conversion</dimension>
+ <category>Visitors</category>
+ <subcategory>Locations</subcategory>
+ <name>City</name>
+ <module>UserCountry</module>
+ <action>getCity</action>
+ <dimension>City</dimension>
+ <documentation>This report shows the cities your visitors were in when they accessed your website.&lt;br/&gt;In order to see data for this report, you must setup GeoIP in the Geolocation admin tab. The commercial &lt;a rel=&quot;noreferrer&quot; target=&quot;_blank&quot; href=&quot;http://www.maxmind.com/?rId=piwik&quot;&gt;Maxmind&lt;/a&gt; GeoIP databases are more accurate than the free ones. To see how accurate they are, click &lt;a rel=&quot;noreferrer&quot; target=&quot;_blank&quot; href=&quot;http://www.maxmind.com/en/city_accuracy?rId=piwik&quot;&gt;here&lt;/a&gt;.</documentation>
<metrics>
- <nb_conversions>Conversions</nb_conversions>
+ <nb_visits>Visits</nb_visits>
+ <nb_uniq_visitors>Unique visitors</nb_uniq_visitors>
+ <nb_actions>Actions</nb_actions>
</metrics>
- <constantRowsCount>1</constantRowsCount>
- <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Goals&amp;apiAction=getDaysToConversion&amp;idGoal=ecommerceOrder&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
- <uniqueId>Goals_getDaysToConversion_idGoal--ecommerceOrder</uniqueId>
+ <metricsDocumentation>
+ <nb_visits>If a visitor comes to your website for the first time or if he visits a page more than 30 minutes after his last page view, this will be recorded as a new visit.</nb_visits>
+ <nb_uniq_visitors>The number of unduplicated visitors coming to your website. Every user is only counted once, even if he visits the website multiple times a day.</nb_uniq_visitors>
+ <nb_actions>The number of actions performed by your visitors. Actions can be page views, internal site searches, downloads or outlinks.</nb_actions>
+ <nb_actions_per_visit>The average number of actions (page views, site searches, downloads or outlinks) that were performed during the visits.</nb_actions_per_visit>
+ <avg_time_on_site>The average duration of a visit.</avg_time_on_site>
+ <bounce_rate>The percentage of visits that only had a single pageview. This means, that the visitor left the website directly from the entrance page.</bounce_rate>
+ <conversion_rate>The percentage of visits that triggered a goal conversion.</conversion_rate>
+ </metricsDocumentation>
+ <processedMetrics>
+ <nb_actions_per_visit>Actions per Visit</nb_actions_per_visit>
+ <avg_time_on_site>Avg. Time on Website</avg_time_on_site>
+ <bounce_rate>Bounce Rate</bounce_rate>
+ </processedMetrics>
+ <metricsGoal>
+ <nb_conversions>Conversions</nb_conversions>
+ <revenue>Revenue</revenue>
+ </metricsGoal>
+ <processedMetricsGoal>
+ <revenue_per_visit>Revenue per Visit</revenue_per_visit>
+ </processedMetricsGoal>
+ <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=UserCountry&amp;apiAction=getCity&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
+ <imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=UserCountry&amp;apiAction=getCity&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
+ <uniqueId>UserCountry_getCity</uniqueId>
</row>
<row>
- <category>Ecommerce</category>
- <name>Abandoned Carts</name>
- <module>Goals</module>
- <action>get</action>
- <parameters>
- <idGoal>ecommerceAbandonedCart</idGoal>
- </parameters>
+ <category>Visitors</category>
+ <subcategory>Locations</subcategory>
+ <name>Language code</name>
+ <module>UserLanguage</module>
+ <action>getLanguageCode</action>
+ <dimension>Language</dimension>
<metrics>
- <nb_conversions>Abandoned Carts</nb_conversions>
- <conversion_rate>Conversion Rate</conversion_rate>
- <revenue>Revenue left in cart</revenue>
- <items>Products left in cart</items>
+ <nb_visits>Visits</nb_visits>
+ <nb_uniq_visitors>Unique visitors</nb_uniq_visitors>
+ <nb_actions>Actions</nb_actions>
+ <nb_users>Users</nb_users>
</metrics>
<metricsDocumentation>
+ <nb_visits>If a visitor comes to your website for the first time or if he visits a page more than 30 minutes after his last page view, this will be recorded as a new visit.</nb_visits>
+ <nb_uniq_visitors>The number of unduplicated visitors coming to your website. Every user is only counted once, even if he visits the website multiple times a day.</nb_uniq_visitors>
+ <nb_actions>The number of actions performed by your visitors. Actions can be page views, internal site searches, downloads or outlinks.</nb_actions>
+ <nb_users>The number of users logged in your website. It is the number of unique active users that have a User ID set (via the Tracking code function 'setUserId').</nb_users>
+ <nb_actions_per_visit>The average number of actions (page views, site searches, downloads or outlinks) that were performed during the visits.</nb_actions_per_visit>
+ <avg_time_on_site>The average duration of a visit.</avg_time_on_site>
+ <bounce_rate>The percentage of visits that only had a single pageview. This means, that the visitor left the website directly from the entrance page.</bounce_rate>
<conversion_rate>The percentage of visits that triggered a goal conversion.</conversion_rate>
</metricsDocumentation>
<processedMetrics>
- <avg_order_revenue>Average Order Value</avg_order_revenue>
+ <nb_actions_per_visit>Actions per Visit</nb_actions_per_visit>
+ <avg_time_on_site>Avg. Time on Website</avg_time_on_site>
+ <bounce_rate>Bounce Rate</bounce_rate>
+ <conversion_rate>Conversion Rate</conversion_rate>
</processedMetrics>
- <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Goals&amp;apiAction=get&amp;idGoal=ecommerceAbandonedCart&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphUrl>
- <imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Goals&amp;apiAction=get&amp;idGoal=ecommerceAbandonedCart&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
- <uniqueId>Goals_get_idGoal--ecommerceAbandonedCart</uniqueId>
+ <relatedReports>
+ <row>
+ <name>Browser language</name>
+ <module>UserLanguage</module>
+ <action>getLanguage</action>
+ </row>
+ </relatedReports>
+ <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=UserLanguage&amp;apiAction=getLanguageCode&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
+ <imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=UserLanguage&amp;apiAction=getLanguageCode&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
+ <uniqueId>UserLanguage_getLanguageCode</uniqueId>
</row>
<row>
- <category>Ecommerce</category>
- <name>Abandoned Carts - Visits to Conversion</name>
- <module>Goals</module>
- <action>getVisitsUntilConversion</action>
- <parameters>
- <idGoal>ecommerceAbandonedCart</idGoal>
- </parameters>
- <dimension>Visits to Conversion</dimension>
+ <category>Visitors</category>
+ <subcategory>Engagement</subcategory>
+ <name>Length of Visits</name>
+ <module>VisitorInterest</module>
+ <action>getNumberOfVisitsPerVisitDuration</action>
+ <dimension>Visit duration</dimension>
+ <documentation>In this report, you can see how many visits had a certain total duration. Initially, the report is shown as a tag cloud, more common durations are displayed in a larger font.&lt;br /&gt;Please note, that you can view the report in other ways than as a tag cloud. Use the controls at the bottom of the report to do so.</documentation>
<metrics>
- <nb_conversions>Conversions</nb_conversions>
+ <nb_visits>Visits</nb_visits>
</metrics>
+ <metricsDocumentation>
+ <nb_visits>If a visitor comes to your website for the first time or if he visits a page more than 30 minutes after his last page view, this will be recorded as a new visit.</nb_visits>
+ </metricsDocumentation>
<constantRowsCount>1</constantRowsCount>
- <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Goals&amp;apiAction=getVisitsUntilConversion&amp;idGoal=ecommerceAbandonedCart&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
- <uniqueId>Goals_getVisitsUntilConversion_idGoal--ecommerceAbandonedCart</uniqueId>
+ <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=VisitorInterest&amp;apiAction=getNumberOfVisitsPerVisitDuration&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
+ <uniqueId>VisitorInterest_getNumberOfVisitsPerVisitDuration</uniqueId>
</row>
<row>
- <category>Ecommerce</category>
- <name>Abandoned Carts - Days to Conversion</name>
- <module>Goals</module>
- <action>getDaysToConversion</action>
- <parameters>
- <idGoal>ecommerceAbandonedCart</idGoal>
- </parameters>
- <dimension>Days to Conversion</dimension>
+ <category>Visitors</category>
+ <subcategory>Engagement</subcategory>
+ <name>Pages per Visit</name>
+ <module>VisitorInterest</module>
+ <action>getNumberOfVisitsPerPage</action>
+ <dimension>Pages per visit</dimension>
+ <documentation>In this report, you can see how many visits involved a certain number of pageviews. Initially, the report is shown as a tag cloud, more common numbers of pages are displayed in a larger font.&lt;br /&gt;Please note, that you can view the report in other ways than as a tag cloud. Use the controls at the bottom of the report to do so.</documentation>
<metrics>
- <nb_conversions>Conversions</nb_conversions>
+ <nb_visits>Visits</nb_visits>
</metrics>
+ <metricsDocumentation>
+ <nb_visits>If a visitor comes to your website for the first time or if he visits a page more than 30 minutes after his last page view, this will be recorded as a new visit.</nb_visits>
+ </metricsDocumentation>
<constantRowsCount>1</constantRowsCount>
- <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Goals&amp;apiAction=getDaysToConversion&amp;idGoal=ecommerceAbandonedCart&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
- <uniqueId>Goals_getDaysToConversion_idGoal--ecommerceAbandonedCart</uniqueId>
+ <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=VisitorInterest&amp;apiAction=getNumberOfVisitsPerPage&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
+ <uniqueId>VisitorInterest_getNumberOfVisitsPerPage</uniqueId>
</row>
<row>
- <category>Ecommerce</category>
- <name>Product SKU</name>
- <module>Goals</module>
- <action>getItemsSku</action>
- <dimension>Product SKU</dimension>
+ <category>Visitors</category>
+ <subcategory>Engagement</subcategory>
+ <name>Visits by Visit Number</name>
+ <module>VisitorInterest</module>
+ <action>getNumberOfVisitsByVisitCount</action>
+ <dimension>Visits by Visit Number</dimension>
+ <documentation>In this report, you can see the number of visits who were the Nth visit, ie. visitors who visited your website at least N times.&lt;br /&gt;Please note, that you can view the report in other ways than as a tag cloud. Use the controls at the bottom of the report to do so.</documentation>
<metrics>
- <revenue>Product Revenue</revenue>
- <quantity>Quantity</quantity>
- <orders>Unique Purchases</orders>
<nb_visits>Visits</nb_visits>
</metrics>
+ <metricsDocumentation>
+ <nb_visits>If a visitor comes to your website for the first time or if he visits a page more than 30 minutes after his last page view, this will be recorded as a new visit.</nb_visits>
+ </metricsDocumentation>
<processedMetrics>
- <avg_price>Average Price</avg_price>
- <avg_quantity>Average Quantity</avg_quantity>
- <conversion_rate>Product Conversion Rate</conversion_rate>
+ <nb_visits_percentage>% Visits</nb_visits_percentage>
</processedMetrics>
- <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Goals&amp;apiAction=getItemsSku&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
- <imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Goals&amp;apiAction=getItemsSku&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
- <uniqueId>Goals_getItemsSku</uniqueId>
+ <constantRowsCount>1</constantRowsCount>
+ <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=VisitorInterest&amp;apiAction=getNumberOfVisitsByVisitCount&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
+ <uniqueId>VisitorInterest_getNumberOfVisitsByVisitCount</uniqueId>
</row>
<row>
- <category>Ecommerce</category>
- <name>Product Name</name>
- <module>Goals</module>
- <action>getItemsName</action>
- <dimension>Product Name</dimension>
+ <category>Visitors</category>
+ <subcategory>Engagement</subcategory>
+ <name>Visits by days since last visit</name>
+ <module>VisitorInterest</module>
+ <action>getNumberOfVisitsByDaysSinceLast</action>
+ <dimension>Visits by days since last visit</dimension>
+ <documentation>In this report, you can see how many visits were from visitors whose last visit was a certain number of days ago.</documentation>
<metrics>
- <revenue>Product Revenue</revenue>
- <quantity>Quantity</quantity>
- <orders>Unique Purchases</orders>
<nb_visits>Visits</nb_visits>
</metrics>
+ <metricsDocumentation>
+ <nb_visits>If a visitor comes to your website for the first time or if he visits a page more than 30 minutes after his last page view, this will be recorded as a new visit.</nb_visits>
+ </metricsDocumentation>
+ <constantRowsCount>1</constantRowsCount>
+ <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=VisitorInterest&amp;apiAction=getNumberOfVisitsByDaysSinceLast&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
+ <uniqueId>VisitorInterest_getNumberOfVisitsByDaysSinceLast</uniqueId>
+ </row>
+ <row>
+ <category>Visitors</category>
+ <subcategory>Engagement</subcategory>
+ <name>Returning Visits</name>
+ <module>VisitFrequency</module>
+ <action>get</action>
+ <metrics>
+ <nb_visits_returning>Returning Visits</nb_visits_returning>
+ <nb_actions_returning>Actions by Returning Visits</nb_actions_returning>
+ <nb_uniq_visitors_returning>Unique returning visitors</nb_uniq_visitors_returning>
+ <nb_users_returning>Returning Users</nb_users_returning>
+ <max_actions_returning>Maximum actions in one returning visit</max_actions_returning>
+ </metrics>
<processedMetrics>
- <avg_price>Average Price</avg_price>
- <avg_quantity>Average Quantity</avg_quantity>
- <conversion_rate>Product Conversion Rate</conversion_rate>
+ <avg_time_on_site_returning>Avg. Duration of a Returning Visit (in sec)</avg_time_on_site_returning>
+ <nb_actions_per_visit_returning>Avg. Actions per Returning Visit</nb_actions_per_visit_returning>
+ <bounce_rate_returning>Bounce Rate for Returning Visits</bounce_rate_returning>
</processedMetrics>
- <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Goals&amp;apiAction=getItemsName&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
- <imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Goals&amp;apiAction=getItemsName&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
- <uniqueId>Goals_getItemsName</uniqueId>
+ <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=VisitFrequency&amp;apiAction=get&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphUrl>
+ <imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=VisitFrequency&amp;apiAction=get&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
+ <uniqueId>VisitFrequency_get</uniqueId>
</row>
<row>
- <category>Ecommerce</category>
- <name>Product Category</name>
- <module>Goals</module>
- <action>getItemsCategory</action>
- <dimension>Product Category</dimension>
+ <category>Visitors</category>
+ <subcategory>Times</subcategory>
+ <name>Visits per local time</name>
+ <module>VisitTime</module>
+ <action>getVisitInformationPerLocalTime</action>
+ <dimension>Local time</dimension>
+ <documentation>This graph shows what time it was in the &lt;strong&gt; visitors' time zones &lt;/strong&gt; during their visits.</documentation>
<metrics>
- <revenue>Product Revenue</revenue>
- <quantity>Quantity</quantity>
- <orders>Unique Purchases</orders>
<nb_visits>Visits</nb_visits>
+ <nb_uniq_visitors>Unique visitors</nb_uniq_visitors>
+ <nb_actions>Actions</nb_actions>
+ <nb_users>Users</nb_users>
</metrics>
+ <metricsDocumentation>
+ <nb_visits>If a visitor comes to your website for the first time or if he visits a page more than 30 minutes after his last page view, this will be recorded as a new visit.</nb_visits>
+ <nb_uniq_visitors>The number of unduplicated visitors coming to your website. Every user is only counted once, even if he visits the website multiple times a day.</nb_uniq_visitors>
+ <nb_actions>The number of actions performed by your visitors. Actions can be page views, internal site searches, downloads or outlinks.</nb_actions>
+ <nb_users>The number of users logged in your website. It is the number of unique active users that have a User ID set (via the Tracking code function 'setUserId').</nb_users>
+ <nb_actions_per_visit>The average number of actions (page views, site searches, downloads or outlinks) that were performed during the visits.</nb_actions_per_visit>
+ <avg_time_on_site>The average duration of a visit.</avg_time_on_site>
+ <bounce_rate>The percentage of visits that only had a single pageview. This means, that the visitor left the website directly from the entrance page.</bounce_rate>
+ <conversion_rate>The percentage of visits that triggered a goal conversion.</conversion_rate>
+ </metricsDocumentation>
<processedMetrics>
- <avg_price>Average Price</avg_price>
- <avg_quantity>Average Quantity</avg_quantity>
- <conversion_rate>Product Conversion Rate</conversion_rate>
+ <nb_actions_per_visit>Actions per Visit</nb_actions_per_visit>
+ <avg_time_on_site>Avg. Time on Website</avg_time_on_site>
+ <bounce_rate>Bounce Rate</bounce_rate>
+ <conversion_rate>Conversion Rate</conversion_rate>
</processedMetrics>
- <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Goals&amp;apiAction=getItemsCategory&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
- <imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Goals&amp;apiAction=getItemsCategory&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
- <uniqueId>Goals_getItemsCategory</uniqueId>
+ <constantRowsCount>1</constantRowsCount>
+ <relatedReports>
+ <row>
+ <name>Visits by Day of Week</name>
+ <module>VisitTime</module>
+ <action>getByDayOfWeek</action>
+ </row>
+ </relatedReports>
+ <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=VisitTime&amp;apiAction=getVisitInformationPerLocalTime&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
+ <uniqueId>VisitTime_getVisitInformationPerLocalTime</uniqueId>
</row>
<row>
- <category>Actions</category>
- <name>Actions - Main metrics</name>
- <module>Actions</module>
- <action>get</action>
+ <category>Visitors</category>
+ <subcategory>Times</subcategory>
+ <name>Visits per server time</name>
+ <module>VisitTime</module>
+ <action>getVisitInformationPerServerTime</action>
+ <dimension>Server time</dimension>
+ <documentation>This graph shows what time it was in the &lt;strong&gt; server's time zone &lt;/strong&gt; during the visits.</documentation>
<metrics>
- <nb_pageviews>Pageviews</nb_pageviews>
- <nb_uniq_pageviews>Unique Pageviews</nb_uniq_pageviews>
- <nb_downloads>Downloads</nb_downloads>
- <nb_uniq_downloads>Unique Downloads</nb_uniq_downloads>
- <nb_outlinks>Outlinks</nb_outlinks>
- <nb_uniq_outlinks>Unique Outlinks</nb_uniq_outlinks>
- <nb_searches>Searches</nb_searches>
- <nb_keywords>Unique Keywords</nb_keywords>
+ <nb_visits>Visits</nb_visits>
+ <nb_uniq_visitors>Unique visitors</nb_uniq_visitors>
+ <nb_actions>Actions</nb_actions>
+ <nb_users>Users</nb_users>
</metrics>
<metricsDocumentation>
- <nb_pageviews>The number of times this page was visited.</nb_pageviews>
- <nb_uniq_pageviews>The number of visits that included this page. If a page was viewed multiple times during one visit, it is only counted once.</nb_uniq_pageviews>
- <nb_downloads>The number of times this link was clicked.</nb_downloads>
- <nb_uniq_downloads>The number of visits that involved a click on this link. If a link was clicked multiple times during one visit, it is only counted once.</nb_uniq_downloads>
- <nb_outlinks>The number of times this link was clicked.</nb_outlinks>
- <nb_uniq_outlinks>The number of visits that involved a click on this link. If a link was clicked multiple times during one visit, it is only counted once.</nb_uniq_outlinks>
- <nb_searches>The number of visits that searched for this keyword on your website's search engine.</nb_searches>
- <avg_time_generation>The average time it took to generate the page. This metric includes the time it took the server to generate the web page, plus the time it took for the visitor to download the response from the server. A lower 'Avg. generation time' means a faster website for your visitors!</avg_time_generation>
+ <nb_visits>If a visitor comes to your website for the first time or if he visits a page more than 30 minutes after his last page view, this will be recorded as a new visit.</nb_visits>
+ <nb_uniq_visitors>The number of unduplicated visitors coming to your website. Every user is only counted once, even if he visits the website multiple times a day.</nb_uniq_visitors>
+ <nb_actions>The number of actions performed by your visitors. Actions can be page views, internal site searches, downloads or outlinks.</nb_actions>
+ <nb_users>The number of users logged in your website. It is the number of unique active users that have a User ID set (via the Tracking code function 'setUserId').</nb_users>
+ <nb_actions_per_visit>The average number of actions (page views, site searches, downloads or outlinks) that were performed during the visits.</nb_actions_per_visit>
+ <avg_time_on_site>The average duration of a visit.</avg_time_on_site>
+ <bounce_rate>The percentage of visits that only had a single pageview. This means, that the visitor left the website directly from the entrance page.</bounce_rate>
+ <conversion_rate>The percentage of visits that triggered a goal conversion.</conversion_rate>
</metricsDocumentation>
<processedMetrics>
- <avg_time_generation>Avg. generation time</avg_time_generation>
+ <nb_actions_per_visit>Actions per Visit</nb_actions_per_visit>
+ <avg_time_on_site>Avg. Time on Website</avg_time_on_site>
+ <bounce_rate>Bounce Rate</bounce_rate>
</processedMetrics>
- <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Actions&amp;apiAction=get&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphUrl>
- <imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Actions&amp;apiAction=get&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
- <uniqueId>Actions_get</uniqueId>
+ <constantRowsCount>1</constantRowsCount>
+ <metricsGoal>
+ <nb_conversions>Conversions</nb_conversions>
+ <revenue>Revenue</revenue>
+ </metricsGoal>
+ <processedMetricsGoal>
+ <revenue_per_visit>Revenue per Visit</revenue_per_visit>
+ </processedMetricsGoal>
+ <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=VisitTime&amp;apiAction=getVisitInformationPerServerTime&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
+ <uniqueId>VisitTime_getVisitInformationPerServerTime</uniqueId>
+ </row>
+ <row>
+ <category>Visitors</category>
+ <subcategory>Times</subcategory>
+ <name>Visits by Day of Week</name>
+ <module>VisitTime</module>
+ <action>getByDayOfWeek</action>
+ <dimension>Day of the week</dimension>
+ <documentation>This graph shows the number of visits your website received on each day of the week.</documentation>
+ <metrics>
+ <nb_visits>Visits</nb_visits>
+ <nb_uniq_visitors>Unique visitors</nb_uniq_visitors>
+ <nb_actions>Actions</nb_actions>
+ <nb_users>Users</nb_users>
+ </metrics>
+ <metricsDocumentation>
+ <nb_visits>If a visitor comes to your website for the first time or if he visits a page more than 30 minutes after his last page view, this will be recorded as a new visit.</nb_visits>
+ <nb_uniq_visitors>The number of unduplicated visitors coming to your website. Every user is only counted once, even if he visits the website multiple times a day.</nb_uniq_visitors>
+ <nb_actions>The number of actions performed by your visitors. Actions can be page views, internal site searches, downloads or outlinks.</nb_actions>
+ <nb_users>The number of users logged in your website. It is the number of unique active users that have a User ID set (via the Tracking code function 'setUserId').</nb_users>
+ <nb_actions_per_visit>The average number of actions (page views, site searches, downloads or outlinks) that were performed during the visits.</nb_actions_per_visit>
+ <avg_time_on_site>The average duration of a visit.</avg_time_on_site>
+ <bounce_rate>The percentage of visits that only had a single pageview. This means, that the visitor left the website directly from the entrance page.</bounce_rate>
+ <conversion_rate>The percentage of visits that triggered a goal conversion.</conversion_rate>
+ </metricsDocumentation>
+ <processedMetrics>
+ <nb_actions_per_visit>Actions per Visit</nb_actions_per_visit>
+ <avg_time_on_site>Avg. Time on Website</avg_time_on_site>
+ <bounce_rate>Bounce Rate</bounce_rate>
+ <conversion_rate>Conversion Rate</conversion_rate>
+ </processedMetrics>
+ <constantRowsCount>1</constantRowsCount>
+ <relatedReports>
+ <row>
+ <name>Visits per local time</name>
+ <module>VisitTime</module>
+ <action>getVisitInformationPerLocalTime</action>
+ </row>
+ </relatedReports>
+ <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=VisitTime&amp;apiAction=getByDayOfWeek&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
+ <uniqueId>VisitTime_getByDayOfWeek</uniqueId>
</row>
<row>
<category>Actions</category>
+ <subcategory>Pages</subcategory>
<name>Page URLs</name>
<module>Actions</module>
<action>getPageUrls</action>
@@ -654,6 +1018,7 @@
</row>
<row>
<category>Actions</category>
+ <subcategory>Entry pages</subcategory>
<name>Entry pages</name>
<module>Actions</module>
<action>getEntryPageUrls</action>
@@ -674,12 +1039,20 @@
<avg_time_generation>Avg. generation time</avg_time_generation>
</processedMetrics>
<actionToLoadSubTables>getEntryPageUrls</actionToLoadSubTables>
+ <relatedReports>
+ <row>
+ <name>Entry page titles</name>
+ <module>Actions</module>
+ <action>getEntryPageTitles</action>
+ </row>
+ </relatedReports>
<imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Actions&amp;apiAction=getEntryPageUrls&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
<imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Actions&amp;apiAction=getEntryPageUrls&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
<uniqueId>Actions_getEntryPageUrls</uniqueId>
</row>
<row>
<category>Actions</category>
+ <subcategory>Exit pages</subcategory>
<name>Exit pages</name>
<module>Actions</module>
<action>getExitPageUrls</action>
@@ -702,12 +1075,20 @@
<avg_time_generation>Avg. generation time</avg_time_generation>
</processedMetrics>
<actionToLoadSubTables>getExitPageUrls</actionToLoadSubTables>
+ <relatedReports>
+ <row>
+ <name>Exit page titles</name>
+ <module>Actions</module>
+ <action>getExitPageTitles</action>
+ </row>
+ </relatedReports>
<imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Actions&amp;apiAction=getExitPageUrls&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
<imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Actions&amp;apiAction=getExitPageUrls&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
<uniqueId>Actions_getExitPageUrls</uniqueId>
</row>
<row>
<category>Actions</category>
+ <subcategory>Page titles</subcategory>
<name>Page titles</name>
<module>Actions</module>
<action>getPageTitles</action>
@@ -732,64 +1113,147 @@
<avg_time_generation>Avg. generation time</avg_time_generation>
</processedMetrics>
<actionToLoadSubTables>getPageTitles</actionToLoadSubTables>
+ <relatedReports>
+ <row>
+ <name>Entry page titles</name>
+ <module>Actions</module>
+ <action>getEntryPageTitles</action>
+ </row>
+ <row>
+ <name>Exit page titles</name>
+ <module>Actions</module>
+ <action>getExitPageTitles</action>
+ </row>
+ </relatedReports>
<imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Actions&amp;apiAction=getPageTitles&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
<imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Actions&amp;apiAction=getPageTitles&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
<uniqueId>Actions_getPageTitles</uniqueId>
</row>
<row>
<category>Actions</category>
- <name>Entry page titles</name>
+ <subcategory>Site Search</subcategory>
+ <name>Site Search Keywords</name>
<module>Actions</module>
- <action>getEntryPageTitles</action>
- <dimension>Entry Page title</dimension>
- <documentation>This report contains information about the titles of entry pages that were used during the specified period. Use the plus and minus icons on the left to navigate.</documentation>
+ <action>getSiteSearchKeywords</action>
+ <dimension>Keyword</dimension>
+ <documentation>This report lists the Search Keywords that visitors searched for on your internal Search Engine.&lt;br/&gt;&lt;br/&gt;Tracking searches that visitors make on your website is a very effective way to learn more about what your audience is looking for, it can help find ideas for new content, new Ecommerce products that potential customers might be searching for, and generally improve the visitors' experience on your website.&lt;br/&gt;&lt;br/&gt;&lt;a href=&quot;http://piwik.org/docs/site-search/&quot; rel=&quot;noreferrer&quot; target=&quot;_blank&quot;&gt;Learn more about Tracking how your visitors use your Search engine.&lt;/a&gt;</documentation>
<metrics>
- <entry_nb_visits>Entrances</entry_nb_visits>
- <entry_bounce_count>Bounces</entry_bounce_count>
+ <nb_visits>Searches</nb_visits>
+ <nb_pages_per_search>Search Results pages</nb_pages_per_search>
</metrics>
<metricsDocumentation>
- <entry_nb_visits>Number of visits that started on this page.</entry_nb_visits>
- <entry_bounce_count>Number of visits that started and ended on this page. This means that the visitor left the website after viewing only this page.</entry_bounce_count>
- <bounce_rate>The percentage of visits that started on this page and left the website straight away.</bounce_rate>
- <avg_time_generation>The average time it took to generate the page. This metric includes the time it took the server to generate the web page, plus the time it took for the visitor to download the response from the server. A lower 'Avg. generation time' means a faster website for your visitors!</avg_time_generation>
+ <nb_visits>The number of visits that searched for this keyword on your website's search engine.</nb_visits>
+ <nb_pages_per_search>Visitors will search on your website, and sometimes click &quot;next&quot; to view more results. This is the average number of search results pages viewed for this keyword.</nb_pages_per_search>
+ <exit_rate>The percentage of visits that left the website after searching for this Keyword on your Site Search engine.</exit_rate>
</metricsDocumentation>
<processedMetrics>
- <bounce_rate>Bounce Rate</bounce_rate>
- <avg_time_generation>Avg. generation time</avg_time_generation>
+ <exit_rate>% Search Exits</exit_rate>
</processedMetrics>
- <actionToLoadSubTables>getEntryPageTitles</actionToLoadSubTables>
- <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Actions&amp;apiAction=getEntryPageTitles&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
- <imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Actions&amp;apiAction=getEntryPageTitles&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
- <uniqueId>Actions_getEntryPageTitles</uniqueId>
+ <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Actions&amp;apiAction=getSiteSearchKeywords&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
+ <imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Actions&amp;apiAction=getSiteSearchKeywords&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
+ <uniqueId>Actions_getSiteSearchKeywords</uniqueId>
</row>
<row>
<category>Actions</category>
- <name>Exit page titles</name>
+ <subcategory>Site Search</subcategory>
+ <name>Pages Following a Site Search</name>
<module>Actions</module>
- <action>getExitPageTitles</action>
- <dimension>Exit Page Title</dimension>
- <documentation>This report contains information about the titles of exit pages that occurred during the specified period. Use the plus and minus icons on the left to navigate.</documentation>
+ <action>getPageUrlsFollowingSiteSearch</action>
+ <dimension>Destination Page</dimension>
+ <documentation>When visitors search on your website, they are looking for a particular page, content, product, or service. This report lists the pages that were clicked the most after an internal search. In other words, the list of pages the most searched for by visitors already on your website.&lt;br/&gt;Use the plus and minus icons on the left to navigate.</documentation>
<metrics>
- <exit_nb_visits>Exits</exit_nb_visits>
- <nb_visits>Unique Pageviews</nb_visits>
+ <nb_hits_following_search>Clicked in search results</nb_hits_following_search>
+ <nb_hits>Total Pageviews</nb_hits>
</metrics>
<metricsDocumentation>
- <exit_nb_visits>Number of visits that ended on this page.</exit_nb_visits>
- <nb_visits>The number of visits that included this page. If a page was viewed multiple times during one visit, it is only counted once.</nb_visits>
- <exit_rate>The percentage of visits that left the website after viewing this page.</exit_rate>
- <avg_time_generation>The average time it took to generate the page. This metric includes the time it took the server to generate the web page, plus the time it took for the visitor to download the response from the server. A lower 'Avg. generation time' means a faster website for your visitors!</avg_time_generation>
+ <nb_hits_following_search>The number of times this Page was visited after a visitor did a search on your website, and clicked on this page in the search results.</nb_hits_following_search>
+ <nb_hits>The number of times this page was visited.</nb_hits>
+ </metricsDocumentation>
+ <relatedReports>
+ <row>
+ <name>Page Titles Following a Site Search</name>
+ <module>Actions</module>
+ <action>getPageTitlesFollowingSiteSearch</action>
+ </row>
+ </relatedReports>
+ <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Actions&amp;apiAction=getPageUrlsFollowingSiteSearch&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
+ <imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Actions&amp;apiAction=getPageUrlsFollowingSiteSearch&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
+ <uniqueId>Actions_getPageUrlsFollowingSiteSearch</uniqueId>
+ </row>
+ <row>
+ <category>Actions</category>
+ <subcategory>Site Search</subcategory>
+ <name>Search Keywords with No Results</name>
+ <module>Actions</module>
+ <action>getSiteSearchNoResultKeywords</action>
+ <dimension>Keyword with No Search Result</dimension>
+ <documentation>Tracking searches that visitors make on your website is a very effective way to learn more about what your audience is looking for, it can help find ideas for new content, new Ecommerce products that potential customers might be searching for, and generally improve the visitors' experience on your website.&lt;br /&gt;&lt;br /&gt;This report lists the Search Keywords that did not return any Search result: maybe the search engine algorithm can be improved, or maybe your visitors are looking for content that is not (yet) on your website?</documentation>
+ <metrics>
+ <nb_visits>Searches</nb_visits>
+ </metrics>
+ <metricsDocumentation>
+ <nb_visits>The number of visits that searched for this keyword on your website's search engine.</nb_visits>
+ <exit_rate>The percentage of visits that left the website after searching for this Keyword on your Site Search engine.</exit_rate>
</metricsDocumentation>
<processedMetrics>
- <exit_rate>Exit rate</exit_rate>
- <avg_time_generation>Avg. generation time</avg_time_generation>
+ <exit_rate>% Search Exits</exit_rate>
</processedMetrics>
- <actionToLoadSubTables>getExitPageTitles</actionToLoadSubTables>
- <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Actions&amp;apiAction=getExitPageTitles&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
- <imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Actions&amp;apiAction=getExitPageTitles&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
- <uniqueId>Actions_getExitPageTitles</uniqueId>
+ <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Actions&amp;apiAction=getSiteSearchNoResultKeywords&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
+ <imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Actions&amp;apiAction=getSiteSearchNoResultKeywords&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
+ <uniqueId>Actions_getSiteSearchNoResultKeywords</uniqueId>
+ </row>
+ <row>
+ <category>Actions</category>
+ <subcategory>Site Search</subcategory>
+ <name>Page Titles Following a Site Search</name>
+ <module>Actions</module>
+ <action>getPageTitlesFollowingSiteSearch</action>
+ <dimension>Destination Page</dimension>
+ <documentation>When visitors search on your website, they are looking for a particular page, content, product, or service. This report lists the pages that were clicked the most after an internal search. In other words, the list of pages the most searched for by visitors already on your website.&lt;br/&gt;Use the plus and minus icons on the left to navigate.</documentation>
+ <metrics>
+ <nb_hits_following_search>Clicked in search results</nb_hits_following_search>
+ <nb_hits>Total Pageviews</nb_hits>
+ </metrics>
+ <metricsDocumentation>
+ <nb_hits_following_search>The number of times this Page was visited after a visitor did a search on your website, and clicked on this page in the search results.</nb_hits_following_search>
+ <nb_hits>The number of times this page was visited.</nb_hits>
+ </metricsDocumentation>
+ <relatedReports>
+ <row>
+ <name>Pages Following a Site Search</name>
+ <module>Actions</module>
+ <action>getPageUrlsFollowingSiteSearch</action>
+ </row>
+ </relatedReports>
+ <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Actions&amp;apiAction=getPageTitlesFollowingSiteSearch&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
+ <imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Actions&amp;apiAction=getPageTitlesFollowingSiteSearch&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
+ <uniqueId>Actions_getPageTitlesFollowingSiteSearch</uniqueId>
+ </row>
+ <row>
+ <category>Actions</category>
+ <subcategory>Site Search</subcategory>
+ <name>Search Categories</name>
+ <module>Actions</module>
+ <action>getSiteSearchCategories</action>
+ <dimension>Search Category</dimension>
+ <documentation>This report lists the Categories that visitors selected when they made a Search on your website.&lt;br/&gt;For example, Ecommerce websites typically have a &quot;Category&quot; selector so that visitors can restrict their searches to all products in a specific Category.</documentation>
+ <metrics>
+ <nb_visits>Searches</nb_visits>
+ <nb_pages_per_search>Search Results pages</nb_pages_per_search>
+ <exit_rate>% Search Exits</exit_rate>
+ </metrics>
+ <metricsDocumentation>
+ <nb_visits>The number of visits that searched for this keyword on your website's search engine.</nb_visits>
+ <nb_pages_per_search>Visitors will search on your website, and sometimes click &quot;next&quot; to view more results. This is the average number of search results pages viewed for this keyword.</nb_pages_per_search>
+ <exit_rate>The percentage of visits that left the website after searching for this Keyword on your Site Search engine.</exit_rate>
+ </metricsDocumentation>
+ <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Actions&amp;apiAction=getSiteSearchCategories&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
+ <imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Actions&amp;apiAction=getSiteSearchCategories&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
+ <uniqueId>Actions_getSiteSearchCategories</uniqueId>
</row>
<row>
<category>Actions</category>
+ <subcategory>Outlinks</subcategory>
<name>Outlinks</name>
<module>Actions</module>
<action>getOutlinks</action>
@@ -810,6 +1274,7 @@
</row>
<row>
<category>Actions</category>
+ <subcategory>Downloads</subcategory>
<name>Downloads</name>
<module>Actions</module>
<action>getDownloads</action>
@@ -830,52 +1295,7 @@
</row>
<row>
<category>Actions</category>
- <name>Content Name</name>
- <module>Contents</module>
- <action>getContentNames</action>
- <dimension>Content Name</dimension>
- <metrics>
- <nb_impressions>Impressions</nb_impressions>
- <nb_interactions>Interactions</nb_interactions>
- </metrics>
- <metricsDocumentation>
- <nb_impressions>The number of times a content block, such as a banner or an ad, was displayed on a page.</nb_impressions>
- <nb_interactions>The number of times a content block was interacted with (eg, a 'click' on a banner or ad).</nb_interactions>
- <interaction_rate>The ratio of content impressions to interactions.</interaction_rate>
- </metricsDocumentation>
- <processedMetrics>
- <interaction_rate>Interaction Rate</interaction_rate>
- </processedMetrics>
- <actionToLoadSubTables>getContentNames</actionToLoadSubTables>
- <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Contents&amp;apiAction=getContentNames&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
- <imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Contents&amp;apiAction=getContentNames&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
- <uniqueId>Contents_getContentNames</uniqueId>
- </row>
- <row>
- <category>Actions</category>
- <name>Content Piece</name>
- <module>Contents</module>
- <action>getContentPieces</action>
- <dimension>Content Piece</dimension>
- <metrics>
- <nb_impressions>Impressions</nb_impressions>
- <nb_interactions>Interactions</nb_interactions>
- </metrics>
- <metricsDocumentation>
- <nb_impressions>The number of times a content block, such as a banner or an ad, was displayed on a page.</nb_impressions>
- <nb_interactions>The number of times a content block was interacted with (eg, a 'click' on a banner or ad).</nb_interactions>
- <interaction_rate>The ratio of content impressions to interactions.</interaction_rate>
- </metricsDocumentation>
- <processedMetrics>
- <interaction_rate>Interaction Rate</interaction_rate>
- </processedMetrics>
- <actionToLoadSubTables>getContentPieces</actionToLoadSubTables>
- <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Contents&amp;apiAction=getContentPieces&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
- <imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Contents&amp;apiAction=getContentPieces&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
- <uniqueId>Contents_getContentPieces</uniqueId>
- </row>
- <row>
- <category>Events</category>
+ <subcategory>Events</subcategory>
<name>Event Categories</name>
<module>Events</module>
<action>getCategory</action>
@@ -904,7 +1324,8 @@
<uniqueId>Events_getCategory</uniqueId>
</row>
<row>
- <category>Events</category>
+ <category>Actions</category>
+ <subcategory>Events</subcategory>
<name>Event Actions</name>
<module>Events</module>
<action>getAction</action>
@@ -933,7 +1354,8 @@
<uniqueId>Events_getAction</uniqueId>
</row>
<row>
- <category>Events</category>
+ <category>Actions</category>
+ <subcategory>Events</subcategory>
<name>Event Names</name>
<module>Events</module>
<action>getName</action>
@@ -962,110 +1384,164 @@
<uniqueId>Events_getName</uniqueId>
</row>
<row>
- <category>Site Search</category>
- <name>Site Search Keywords</name>
- <module>Actions</module>
- <action>getSiteSearchKeywords</action>
- <dimension>Keyword</dimension>
- <documentation>This report lists the Search Keywords that visitors searched for on your internal Search Engine.&lt;br/&gt;&lt;br/&gt;Tracking searches that visitors make on your website is a very effective way to learn more about what your audience is looking for, it can help find ideas for new content, new Ecommerce products that potential customers might be searching for, and generally improve the visitors' experience on your website.&lt;br/&gt;&lt;br/&gt;&lt;a href=&quot;http://piwik.org/docs/site-search/&quot; rel=&quot;noreferrer&quot; target=&quot;_blank&quot;&gt;Learn more about Tracking how your visitors use your Search engine.&lt;/a&gt;</documentation>
+ <category>Actions</category>
+ <subcategory>Contents</subcategory>
+ <name>Content Name</name>
+ <module>Contents</module>
+ <action>getContentNames</action>
+ <dimension>Content Name</dimension>
<metrics>
- <nb_visits>Searches</nb_visits>
- <nb_pages_per_search>Search Results pages</nb_pages_per_search>
+ <nb_impressions>Impressions</nb_impressions>
+ <nb_interactions>Interactions</nb_interactions>
</metrics>
<metricsDocumentation>
- <nb_visits>The number of visits that searched for this keyword on your website's search engine.</nb_visits>
- <nb_pages_per_search>Visitors will search on your website, and sometimes click &quot;next&quot; to view more results. This is the average number of search results pages viewed for this keyword.</nb_pages_per_search>
- <exit_rate>The percentage of visits that left the website after searching for this Keyword on your Site Search engine.</exit_rate>
+ <nb_impressions>The number of times a content block, such as a banner or an ad, was displayed on a page.</nb_impressions>
+ <nb_interactions>The number of times a content block was interacted with (eg, a 'click' on a banner or ad).</nb_interactions>
+ <interaction_rate>The ratio of content impressions to interactions.</interaction_rate>
</metricsDocumentation>
<processedMetrics>
- <exit_rate>% Search Exits</exit_rate>
+ <interaction_rate>Interaction Rate</interaction_rate>
</processedMetrics>
- <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Actions&amp;apiAction=getSiteSearchKeywords&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
- <imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Actions&amp;apiAction=getSiteSearchKeywords&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
- <uniqueId>Actions_getSiteSearchKeywords</uniqueId>
+ <actionToLoadSubTables>getContentNames</actionToLoadSubTables>
+ <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Contents&amp;apiAction=getContentNames&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
+ <imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Contents&amp;apiAction=getContentNames&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
+ <uniqueId>Contents_getContentNames</uniqueId>
</row>
<row>
- <category>Site Search</category>
- <name>Search Keywords with No Results</name>
- <module>Actions</module>
- <action>getSiteSearchNoResultKeywords</action>
- <dimension>Keyword with No Search Result</dimension>
- <documentation>Tracking searches that visitors make on your website is a very effective way to learn more about what your audience is looking for, it can help find ideas for new content, new Ecommerce products that potential customers might be searching for, and generally improve the visitors' experience on your website.&lt;br /&gt;&lt;br /&gt;This report lists the Search Keywords that did not return any Search result: maybe the search engine algorithm can be improved, or maybe your visitors are looking for content that is not (yet) on your website?</documentation>
+ <category>Actions</category>
+ <subcategory>Contents</subcategory>
+ <name>Content Piece</name>
+ <module>Contents</module>
+ <action>getContentPieces</action>
+ <dimension>Content Piece</dimension>
<metrics>
- <nb_visits>Searches</nb_visits>
+ <nb_impressions>Impressions</nb_impressions>
+ <nb_interactions>Interactions</nb_interactions>
</metrics>
<metricsDocumentation>
- <nb_visits>The number of visits that searched for this keyword on your website's search engine.</nb_visits>
- <exit_rate>The percentage of visits that left the website after searching for this Keyword on your Site Search engine.</exit_rate>
+ <nb_impressions>The number of times a content block, such as a banner or an ad, was displayed on a page.</nb_impressions>
+ <nb_interactions>The number of times a content block was interacted with (eg, a 'click' on a banner or ad).</nb_interactions>
+ <interaction_rate>The ratio of content impressions to interactions.</interaction_rate>
</metricsDocumentation>
<processedMetrics>
- <exit_rate>% Search Exits</exit_rate>
+ <interaction_rate>Interaction Rate</interaction_rate>
</processedMetrics>
- <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Actions&amp;apiAction=getSiteSearchNoResultKeywords&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
- <imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Actions&amp;apiAction=getSiteSearchNoResultKeywords&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
- <uniqueId>Actions_getSiteSearchNoResultKeywords</uniqueId>
+ <actionToLoadSubTables>getContentPieces</actionToLoadSubTables>
+ <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Contents&amp;apiAction=getContentPieces&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
+ <imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Contents&amp;apiAction=getContentPieces&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
+ <uniqueId>Contents_getContentPieces</uniqueId>
</row>
<row>
- <category>Site Search</category>
- <name>Search Categories</name>
+ <category>Actions</category>
+ <name>Actions - Main metrics</name>
<module>Actions</module>
- <action>getSiteSearchCategories</action>
- <dimension>Search Category</dimension>
- <documentation>This report lists the Categories that visitors selected when they made a Search on your website.&lt;br/&gt;For example, Ecommerce websites typically have a &quot;Category&quot; selector so that visitors can restrict their searches to all products in a specific Category.</documentation>
+ <action>get</action>
<metrics>
- <nb_visits>Searches</nb_visits>
- <nb_pages_per_search>Search Results pages</nb_pages_per_search>
- <exit_rate>% Search Exits</exit_rate>
+ <nb_pageviews>Pageviews</nb_pageviews>
+ <nb_uniq_pageviews>Unique Pageviews</nb_uniq_pageviews>
+ <nb_downloads>Downloads</nb_downloads>
+ <nb_uniq_downloads>Unique Downloads</nb_uniq_downloads>
+ <nb_outlinks>Outlinks</nb_outlinks>
+ <nb_uniq_outlinks>Unique Outlinks</nb_uniq_outlinks>
+ <nb_searches>Searches</nb_searches>
+ <nb_keywords>Unique Keywords</nb_keywords>
</metrics>
<metricsDocumentation>
- <nb_visits>The number of visits that searched for this keyword on your website's search engine.</nb_visits>
- <nb_pages_per_search>Visitors will search on your website, and sometimes click &quot;next&quot; to view more results. This is the average number of search results pages viewed for this keyword.</nb_pages_per_search>
- <exit_rate>The percentage of visits that left the website after searching for this Keyword on your Site Search engine.</exit_rate>
+ <nb_pageviews>The number of times this page was visited.</nb_pageviews>
+ <nb_uniq_pageviews>The number of visits that included this page. If a page was viewed multiple times during one visit, it is only counted once.</nb_uniq_pageviews>
+ <nb_downloads>The number of times this link was clicked.</nb_downloads>
+ <nb_uniq_downloads>The number of visits that involved a click on this link. If a link was clicked multiple times during one visit, it is only counted once.</nb_uniq_downloads>
+ <nb_outlinks>The number of times this link was clicked.</nb_outlinks>
+ <nb_uniq_outlinks>The number of visits that involved a click on this link. If a link was clicked multiple times during one visit, it is only counted once.</nb_uniq_outlinks>
+ <nb_searches>The number of visits that searched for this keyword on your website's search engine.</nb_searches>
+ <avg_time_generation>The average time it took to generate the page. This metric includes the time it took the server to generate the web page, plus the time it took for the visitor to download the response from the server. A lower 'Avg. generation time' means a faster website for your visitors!</avg_time_generation>
</metricsDocumentation>
- <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Actions&amp;apiAction=getSiteSearchCategories&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
- <imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Actions&amp;apiAction=getSiteSearchCategories&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
- <uniqueId>Actions_getSiteSearchCategories</uniqueId>
+ <processedMetrics>
+ <avg_time_generation>Avg. generation time</avg_time_generation>
+ </processedMetrics>
+ <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Actions&amp;apiAction=get&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphUrl>
+ <imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Actions&amp;apiAction=get&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
+ <uniqueId>Actions_get</uniqueId>
</row>
<row>
- <category>Site Search</category>
- <name>Pages Following a Site Search</name>
+ <category>Actions</category>
+ <name>Entry page titles</name>
<module>Actions</module>
- <action>getPageUrlsFollowingSiteSearch</action>
- <dimension>Destination Page</dimension>
- <documentation>When visitors search on your website, they are looking for a particular page, content, product, or service. This report lists the pages that were clicked the most after an internal search. In other words, the list of pages the most searched for by visitors already on your website.&lt;br/&gt;Use the plus and minus icons on the left to navigate.</documentation>
+ <action>getEntryPageTitles</action>
+ <dimension>Entry Page title</dimension>
+ <documentation>This report contains information about the titles of entry pages that were used during the specified period. Use the plus and minus icons on the left to navigate.</documentation>
<metrics>
- <nb_hits_following_search>Clicked in search results</nb_hits_following_search>
- <nb_hits>Total Pageviews</nb_hits>
+ <entry_nb_visits>Entrances</entry_nb_visits>
+ <entry_bounce_count>Bounces</entry_bounce_count>
</metrics>
<metricsDocumentation>
- <nb_hits_following_search>The number of times this Page was visited after a visitor did a search on your website, and clicked on this page in the search results.</nb_hits_following_search>
- <nb_hits>The number of times this page was visited.</nb_hits>
+ <entry_nb_visits>Number of visits that started on this page.</entry_nb_visits>
+ <entry_bounce_count>Number of visits that started and ended on this page. This means that the visitor left the website after viewing only this page.</entry_bounce_count>
+ <bounce_rate>The percentage of visits that started on this page and left the website straight away.</bounce_rate>
+ <avg_time_generation>The average time it took to generate the page. This metric includes the time it took the server to generate the web page, plus the time it took for the visitor to download the response from the server. A lower 'Avg. generation time' means a faster website for your visitors!</avg_time_generation>
</metricsDocumentation>
- <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Actions&amp;apiAction=getPageUrlsFollowingSiteSearch&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
- <imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Actions&amp;apiAction=getPageUrlsFollowingSiteSearch&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
- <uniqueId>Actions_getPageUrlsFollowingSiteSearch</uniqueId>
+ <processedMetrics>
+ <bounce_rate>Bounce Rate</bounce_rate>
+ <avg_time_generation>Avg. generation time</avg_time_generation>
+ </processedMetrics>
+ <actionToLoadSubTables>getEntryPageTitles</actionToLoadSubTables>
+ <relatedReports>
+ <row>
+ <name>Page titles</name>
+ <module>Actions</module>
+ <action>getPageTitles</action>
+ </row>
+ <row>
+ <name>Entry pages</name>
+ <module>Actions</module>
+ <action>getEntryPageUrls</action>
+ </row>
+ </relatedReports>
+ <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Actions&amp;apiAction=getEntryPageTitles&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
+ <imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Actions&amp;apiAction=getEntryPageTitles&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
+ <uniqueId>Actions_getEntryPageTitles</uniqueId>
</row>
<row>
- <category>Site Search</category>
- <name>Page Titles Following a Site Search</name>
+ <category>Actions</category>
+ <name>Exit page titles</name>
<module>Actions</module>
- <action>getPageTitlesFollowingSiteSearch</action>
- <dimension>Destination Page</dimension>
- <documentation>When visitors search on your website, they are looking for a particular page, content, product, or service. This report lists the pages that were clicked the most after an internal search. In other words, the list of pages the most searched for by visitors already on your website.&lt;br/&gt;Use the plus and minus icons on the left to navigate.</documentation>
+ <action>getExitPageTitles</action>
+ <dimension>Exit Page Title</dimension>
+ <documentation>This report contains information about the titles of exit pages that occurred during the specified period. Use the plus and minus icons on the left to navigate.</documentation>
<metrics>
- <nb_hits_following_search>Clicked in search results</nb_hits_following_search>
- <nb_hits>Total Pageviews</nb_hits>
+ <exit_nb_visits>Exits</exit_nb_visits>
+ <nb_visits>Unique Pageviews</nb_visits>
</metrics>
<metricsDocumentation>
- <nb_hits_following_search>The number of times this Page was visited after a visitor did a search on your website, and clicked on this page in the search results.</nb_hits_following_search>
- <nb_hits>The number of times this page was visited.</nb_hits>
+ <exit_nb_visits>Number of visits that ended on this page.</exit_nb_visits>
+ <nb_visits>The number of visits that included this page. If a page was viewed multiple times during one visit, it is only counted once.</nb_visits>
+ <exit_rate>The percentage of visits that left the website after viewing this page.</exit_rate>
+ <avg_time_generation>The average time it took to generate the page. This metric includes the time it took the server to generate the web page, plus the time it took for the visitor to download the response from the server. A lower 'Avg. generation time' means a faster website for your visitors!</avg_time_generation>
</metricsDocumentation>
- <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Actions&amp;apiAction=getPageTitlesFollowingSiteSearch&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
- <imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Actions&amp;apiAction=getPageTitlesFollowingSiteSearch&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
- <uniqueId>Actions_getPageTitlesFollowingSiteSearch</uniqueId>
+ <processedMetrics>
+ <exit_rate>Exit rate</exit_rate>
+ <avg_time_generation>Avg. generation time</avg_time_generation>
+ </processedMetrics>
+ <actionToLoadSubTables>getExitPageTitles</actionToLoadSubTables>
+ <relatedReports>
+ <row>
+ <name>Page titles</name>
+ <module>Actions</module>
+ <action>getPageTitles</action>
+ </row>
+ <row>
+ <name>Exit pages</name>
+ <module>Actions</module>
+ <action>getExitPageUrls</action>
+ </row>
+ </relatedReports>
+ <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Actions&amp;apiAction=getExitPageTitles&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
+ <imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Actions&amp;apiAction=getExitPageTitles&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
+ <uniqueId>Actions_getExitPageTitles</uniqueId>
</row>
<row>
<category>Referrers</category>
+ <subcategory>All Referrers</subcategory>
<name>Referrer Type</name>
<module>Referrers</module>
<action>getReferrerType</action>
@@ -1106,6 +1582,7 @@
</row>
<row>
<category>Referrers</category>
+ <subcategory>All Referrers</subcategory>
<name>All Referrers</name>
<module>Referrers</module>
<action>getAll</action>
@@ -1138,6 +1615,7 @@
</row>
<row>
<category>Referrers</category>
+ <subcategory>Search Engines &amp; Keywords</subcategory>
<name>Keywords</name>
<module>Referrers</module>
<action>getKeywords</action>
@@ -1178,6 +1656,48 @@
</row>
<row>
<category>Referrers</category>
+ <subcategory>Search Engines &amp; Keywords</subcategory>
+ <name>Search Engines</name>
+ <module>Referrers</module>
+ <action>getSearchEngines</action>
+ <dimension>Search Engine</dimension>
+ <documentation>This report shows which search engines referred users to your website. &lt;br /&gt; By clicking on a row in the table, you can see what users were searching for using a specific search engine.</documentation>
+ <metrics>
+ <nb_visits>Visits</nb_visits>
+ <nb_uniq_visitors>Unique visitors</nb_uniq_visitors>
+ <nb_actions>Actions</nb_actions>
+ <nb_users>Users</nb_users>
+ </metrics>
+ <metricsDocumentation>
+ <nb_visits>If a visitor comes to your website for the first time or if he visits a page more than 30 minutes after his last page view, this will be recorded as a new visit.</nb_visits>
+ <nb_uniq_visitors>The number of unduplicated visitors coming to your website. Every user is only counted once, even if he visits the website multiple times a day.</nb_uniq_visitors>
+ <nb_actions>The number of actions performed by your visitors. Actions can be page views, internal site searches, downloads or outlinks.</nb_actions>
+ <nb_users>The number of users logged in your website. It is the number of unique active users that have a User ID set (via the Tracking code function 'setUserId').</nb_users>
+ <nb_actions_per_visit>The average number of actions (page views, site searches, downloads or outlinks) that were performed during the visits.</nb_actions_per_visit>
+ <avg_time_on_site>The average duration of a visit.</avg_time_on_site>
+ <bounce_rate>The percentage of visits that only had a single pageview. This means, that the visitor left the website directly from the entrance page.</bounce_rate>
+ <conversion_rate>The percentage of visits that triggered a goal conversion.</conversion_rate>
+ </metricsDocumentation>
+ <processedMetrics>
+ <nb_actions_per_visit>Actions per Visit</nb_actions_per_visit>
+ <avg_time_on_site>Avg. Time on Website</avg_time_on_site>
+ <bounce_rate>Bounce Rate</bounce_rate>
+ </processedMetrics>
+ <actionToLoadSubTables>getKeywordsFromSearchEngineId</actionToLoadSubTables>
+ <metricsGoal>
+ <nb_conversions>Conversions</nb_conversions>
+ <revenue>Revenue</revenue>
+ </metricsGoal>
+ <processedMetricsGoal>
+ <revenue_per_visit>Revenue per Visit</revenue_per_visit>
+ </processedMetricsGoal>
+ <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Referrers&amp;apiAction=getSearchEngines&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
+ <imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Referrers&amp;apiAction=getSearchEngines&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
+ <uniqueId>Referrers_getSearchEngines</uniqueId>
+ </row>
+ <row>
+ <category>Referrers</category>
+ <subcategory>Websites &amp; Social</subcategory>
<name>Websites</name>
<module>Referrers</module>
<action>getWebsites</action>
@@ -1218,11 +1738,12 @@
</row>
<row>
<category>Referrers</category>
- <name>Search Engines</name>
+ <subcategory>Websites &amp; Social</subcategory>
+ <name>Social Networks</name>
<module>Referrers</module>
- <action>getSearchEngines</action>
- <dimension>Search Engine</dimension>
- <documentation>This report shows which search engines referred users to your website. &lt;br /&gt; By clicking on a row in the table, you can see what users were searching for using a specific search engine.</documentation>
+ <action>getSocials</action>
+ <dimension>Social network</dimension>
+ <documentation>In this table, you can see which websites referred visitors to your site. &lt;br /&gt; By clicking on a row in the table, you can see which URLs the links to your website were on.</documentation>
<metrics>
<nb_visits>Visits</nb_visits>
<nb_uniq_visitors>Unique visitors</nb_uniq_visitors>
@@ -1243,21 +1764,16 @@
<nb_actions_per_visit>Actions per Visit</nb_actions_per_visit>
<avg_time_on_site>Avg. Time on Website</avg_time_on_site>
<bounce_rate>Bounce Rate</bounce_rate>
+ <conversion_rate>Conversion Rate</conversion_rate>
</processedMetrics>
- <actionToLoadSubTables>getKeywordsFromSearchEngineId</actionToLoadSubTables>
- <metricsGoal>
- <nb_conversions>Conversions</nb_conversions>
- <revenue>Revenue</revenue>
- </metricsGoal>
- <processedMetricsGoal>
- <revenue_per_visit>Revenue per Visit</revenue_per_visit>
- </processedMetricsGoal>
- <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Referrers&amp;apiAction=getSearchEngines&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
- <imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Referrers&amp;apiAction=getSearchEngines&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
- <uniqueId>Referrers_getSearchEngines</uniqueId>
+ <actionToLoadSubTables>getUrlsForSocial</actionToLoadSubTables>
+ <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Referrers&amp;apiAction=getSocials&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
+ <imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Referrers&amp;apiAction=getSocials&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
+ <uniqueId>Referrers_getSocials</uniqueId>
</row>
<row>
<category>Referrers</category>
+ <subcategory>Campaigns</subcategory>
<name>Campaigns</name>
<module>Referrers</module>
<action>getCampaigns</action>
@@ -1297,38 +1813,187 @@
<uniqueId>Referrers_getCampaigns</uniqueId>
</row>
<row>
- <category>Referrers</category>
- <name>Social Networks</name>
- <module>Referrers</module>
- <action>getSocials</action>
- <dimension>Social network</dimension>
- <documentation>In this table, you can see which websites referred visitors to your site. &lt;br /&gt; By clicking on a row in the table, you can see which URLs the links to your website were on.</documentation>
+ <category>Ecommerce</category>
+ <subcategory>Products</subcategory>
+ <name>Product SKU</name>
+ <module>Goals</module>
+ <action>getItemsSku</action>
+ <dimension>Product SKU</dimension>
+ <metrics>
+ <revenue>Product Revenue</revenue>
+ <quantity>Quantity</quantity>
+ <orders>Unique Purchases</orders>
+ <nb_visits>Visits</nb_visits>
+ </metrics>
+ <processedMetrics>
+ <avg_price>Average Price</avg_price>
+ <avg_quantity>Average Quantity</avg_quantity>
+ <conversion_rate>Product Conversion Rate</conversion_rate>
+ </processedMetrics>
+ <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Goals&amp;apiAction=getItemsSku&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
+ <imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Goals&amp;apiAction=getItemsSku&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
+ <uniqueId>Goals_getItemsSku</uniqueId>
+ </row>
+ <row>
+ <category>Ecommerce</category>
+ <subcategory>Products</subcategory>
+ <name>Product Name</name>
+ <module>Goals</module>
+ <action>getItemsName</action>
+ <dimension>Product Name</dimension>
<metrics>
+ <revenue>Product Revenue</revenue>
+ <quantity>Quantity</quantity>
+ <orders>Unique Purchases</orders>
<nb_visits>Visits</nb_visits>
- <nb_uniq_visitors>Unique visitors</nb_uniq_visitors>
- <nb_actions>Actions</nb_actions>
- <nb_users>Users</nb_users>
+ </metrics>
+ <processedMetrics>
+ <avg_price>Average Price</avg_price>
+ <avg_quantity>Average Quantity</avg_quantity>
+ <conversion_rate>Product Conversion Rate</conversion_rate>
+ </processedMetrics>
+ <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Goals&amp;apiAction=getItemsName&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
+ <imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Goals&amp;apiAction=getItemsName&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
+ <uniqueId>Goals_getItemsName</uniqueId>
+ </row>
+ <row>
+ <category>Ecommerce</category>
+ <subcategory>Products</subcategory>
+ <name>Product Category</name>
+ <module>Goals</module>
+ <action>getItemsCategory</action>
+ <dimension>Product Category</dimension>
+ <metrics>
+ <revenue>Product Revenue</revenue>
+ <quantity>Quantity</quantity>
+ <orders>Unique Purchases</orders>
+ <nb_visits>Visits</nb_visits>
+ </metrics>
+ <processedMetrics>
+ <avg_price>Average Price</avg_price>
+ <avg_quantity>Average Quantity</avg_quantity>
+ <conversion_rate>Product Conversion Rate</conversion_rate>
+ </processedMetrics>
+ <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Goals&amp;apiAction=getItemsCategory&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
+ <imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Goals&amp;apiAction=getItemsCategory&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
+ <uniqueId>Goals_getItemsCategory</uniqueId>
+ </row>
+ <row>
+ <category>Ecommerce</category>
+ <name>Ecommerce Orders</name>
+ <module>Goals</module>
+ <action>get</action>
+ <parameters>
+ <idGoal>ecommerceOrder</idGoal>
+ </parameters>
+ <metrics>
+ <nb_conversions>Ecommerce Orders</nb_conversions>
+ <nb_visits_converted>Visits with Conversions</nb_visits_converted>
+ <conversion_rate>Conversion Rate</conversion_rate>
+ <revenue>Revenue</revenue>
+ <revenue_subtotal>Subtotal</revenue_subtotal>
+ <revenue_tax>Tax</revenue_tax>
+ <revenue_shipping>Shipping</revenue_shipping>
+ <revenue_discount>Discount</revenue_discount>
+ <items>Purchased Products</items>
</metrics>
<metricsDocumentation>
- <nb_visits>If a visitor comes to your website for the first time or if he visits a page more than 30 minutes after his last page view, this will be recorded as a new visit.</nb_visits>
- <nb_uniq_visitors>The number of unduplicated visitors coming to your website. Every user is only counted once, even if he visits the website multiple times a day.</nb_uniq_visitors>
- <nb_actions>The number of actions performed by your visitors. Actions can be page views, internal site searches, downloads or outlinks.</nb_actions>
- <nb_users>The number of users logged in your website. It is the number of unique active users that have a User ID set (via the Tracking code function 'setUserId').</nb_users>
- <nb_actions_per_visit>The average number of actions (page views, site searches, downloads or outlinks) that were performed during the visits.</nb_actions_per_visit>
- <avg_time_on_site>The average duration of a visit.</avg_time_on_site>
- <bounce_rate>The percentage of visits that only had a single pageview. This means, that the visitor left the website directly from the entrance page.</bounce_rate>
<conversion_rate>The percentage of visits that triggered a goal conversion.</conversion_rate>
</metricsDocumentation>
<processedMetrics>
- <nb_actions_per_visit>Actions per Visit</nb_actions_per_visit>
- <avg_time_on_site>Avg. Time on Website</avg_time_on_site>
- <bounce_rate>Bounce Rate</bounce_rate>
+ <avg_order_revenue>Average Order Value</avg_order_revenue>
+ </processedMetrics>
+ <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Goals&amp;apiAction=get&amp;idGoal=ecommerceOrder&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphUrl>
+ <imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Goals&amp;apiAction=get&amp;idGoal=ecommerceOrder&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
+ <uniqueId>Goals_get_idGoal--ecommerceOrder</uniqueId>
+ </row>
+ <row>
+ <category>Ecommerce</category>
+ <name>Ecommerce Orders - Visits to Conversion</name>
+ <module>Goals</module>
+ <action>getVisitsUntilConversion</action>
+ <parameters>
+ <idGoal>ecommerceOrder</idGoal>
+ </parameters>
+ <dimension>Visits to Conversion</dimension>
+ <metrics>
+ <nb_conversions>Conversions</nb_conversions>
+ </metrics>
+ <constantRowsCount>1</constantRowsCount>
+ <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Goals&amp;apiAction=getVisitsUntilConversion&amp;idGoal=ecommerceOrder&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
+ <uniqueId>Goals_getVisitsUntilConversion_idGoal--ecommerceOrder</uniqueId>
+ </row>
+ <row>
+ <category>Ecommerce</category>
+ <name>Ecommerce Orders - Days to Conversion</name>
+ <module>Goals</module>
+ <action>getDaysToConversion</action>
+ <parameters>
+ <idGoal>ecommerceOrder</idGoal>
+ </parameters>
+ <dimension>Days to Conversion</dimension>
+ <metrics>
+ <nb_conversions>Conversions</nb_conversions>
+ </metrics>
+ <constantRowsCount>1</constantRowsCount>
+ <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Goals&amp;apiAction=getDaysToConversion&amp;idGoal=ecommerceOrder&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
+ <uniqueId>Goals_getDaysToConversion_idGoal--ecommerceOrder</uniqueId>
+ </row>
+ <row>
+ <category>Ecommerce</category>
+ <name>Abandoned Carts</name>
+ <module>Goals</module>
+ <action>get</action>
+ <parameters>
+ <idGoal>ecommerceAbandonedCart</idGoal>
+ </parameters>
+ <metrics>
+ <nb_conversions>Abandoned Carts</nb_conversions>
<conversion_rate>Conversion Rate</conversion_rate>
+ <revenue>Revenue left in cart</revenue>
+ <items>Products left in cart</items>
+ </metrics>
+ <metricsDocumentation>
+ <conversion_rate>The percentage of visits that triggered a goal conversion.</conversion_rate>
+ </metricsDocumentation>
+ <processedMetrics>
+ <avg_order_revenue>Average Order Value</avg_order_revenue>
</processedMetrics>
- <actionToLoadSubTables>getUrlsForSocial</actionToLoadSubTables>
- <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Referrers&amp;apiAction=getSocials&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
- <imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Referrers&amp;apiAction=getSocials&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
- <uniqueId>Referrers_getSocials</uniqueId>
+ <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Goals&amp;apiAction=get&amp;idGoal=ecommerceAbandonedCart&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphUrl>
+ <imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Goals&amp;apiAction=get&amp;idGoal=ecommerceAbandonedCart&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
+ <uniqueId>Goals_get_idGoal--ecommerceAbandonedCart</uniqueId>
+ </row>
+ <row>
+ <category>Ecommerce</category>
+ <name>Abandoned Carts - Visits to Conversion</name>
+ <module>Goals</module>
+ <action>getVisitsUntilConversion</action>
+ <parameters>
+ <idGoal>ecommerceAbandonedCart</idGoal>
+ </parameters>
+ <dimension>Visits to Conversion</dimension>
+ <metrics>
+ <nb_conversions>Conversions</nb_conversions>
+ </metrics>
+ <constantRowsCount>1</constantRowsCount>
+ <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Goals&amp;apiAction=getVisitsUntilConversion&amp;idGoal=ecommerceAbandonedCart&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
+ <uniqueId>Goals_getVisitsUntilConversion_idGoal--ecommerceAbandonedCart</uniqueId>
+ </row>
+ <row>
+ <category>Ecommerce</category>
+ <name>Abandoned Carts - Days to Conversion</name>
+ <module>Goals</module>
+ <action>getDaysToConversion</action>
+ <parameters>
+ <idGoal>ecommerceAbandonedCart</idGoal>
+ </parameters>
+ <dimension>Days to Conversion</dimension>
+ <metrics>
+ <nb_conversions>Conversions</nb_conversions>
+ </metrics>
+ <constantRowsCount>1</constantRowsCount>
+ <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Goals&amp;apiAction=getDaysToConversion&amp;idGoal=ecommerceAbandonedCart&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
+ <uniqueId>Goals_getDaysToConversion_idGoal--ecommerceAbandonedCart</uniqueId>
</row>
<row>
<category>Goals</category>
@@ -1556,291 +2221,11 @@
<uniqueId>Goals_getDaysToConversion_idGoal--3</uniqueId>
</row>
<row>
- <category>Visitors</category>
- <name>Country</name>
- <module>UserCountry</module>
- <action>getCountry</action>
- <dimension>Country</dimension>
- <documentation>This report shows which country your visitors were in when they accessed your website.</documentation>
- <metrics>
- <nb_visits>Visits</nb_visits>
- <nb_uniq_visitors>Unique visitors</nb_uniq_visitors>
- <nb_actions>Actions</nb_actions>
- </metrics>
- <metricsDocumentation>
- <nb_visits>If a visitor comes to your website for the first time or if he visits a page more than 30 minutes after his last page view, this will be recorded as a new visit.</nb_visits>
- <nb_uniq_visitors>The number of unduplicated visitors coming to your website. Every user is only counted once, even if he visits the website multiple times a day.</nb_uniq_visitors>
- <nb_actions>The number of actions performed by your visitors. Actions can be page views, internal site searches, downloads or outlinks.</nb_actions>
- <nb_actions_per_visit>The average number of actions (page views, site searches, downloads or outlinks) that were performed during the visits.</nb_actions_per_visit>
- <avg_time_on_site>The average duration of a visit.</avg_time_on_site>
- <bounce_rate>The percentage of visits that only had a single pageview. This means, that the visitor left the website directly from the entrance page.</bounce_rate>
- <conversion_rate>The percentage of visits that triggered a goal conversion.</conversion_rate>
- </metricsDocumentation>
- <processedMetrics>
- <nb_actions_per_visit>Actions per Visit</nb_actions_per_visit>
- <avg_time_on_site>Avg. Time on Website</avg_time_on_site>
- <bounce_rate>Bounce Rate</bounce_rate>
- </processedMetrics>
- <metricsGoal>
- <nb_conversions>Conversions</nb_conversions>
- <revenue>Revenue</revenue>
- </metricsGoal>
- <processedMetricsGoal>
- <revenue_per_visit>Revenue per Visit</revenue_per_visit>
- </processedMetricsGoal>
- <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=UserCountry&amp;apiAction=getCountry&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
- <imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=UserCountry&amp;apiAction=getCountry&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
- <uniqueId>UserCountry_getCountry</uniqueId>
- </row>
- <row>
- <category>Visitors</category>
- <name>Continent</name>
- <module>UserCountry</module>
- <action>getContinent</action>
- <dimension>Continent</dimension>
- <documentation>This report shows which continent your visitors were in when they accessed your website.</documentation>
- <metrics>
- <nb_visits>Visits</nb_visits>
- <nb_uniq_visitors>Unique visitors</nb_uniq_visitors>
- <nb_actions>Actions</nb_actions>
- </metrics>
- <metricsDocumentation>
- <nb_visits>If a visitor comes to your website for the first time or if he visits a page more than 30 minutes after his last page view, this will be recorded as a new visit.</nb_visits>
- <nb_uniq_visitors>The number of unduplicated visitors coming to your website. Every user is only counted once, even if he visits the website multiple times a day.</nb_uniq_visitors>
- <nb_actions>The number of actions performed by your visitors. Actions can be page views, internal site searches, downloads or outlinks.</nb_actions>
- <nb_actions_per_visit>The average number of actions (page views, site searches, downloads or outlinks) that were performed during the visits.</nb_actions_per_visit>
- <avg_time_on_site>The average duration of a visit.</avg_time_on_site>
- <bounce_rate>The percentage of visits that only had a single pageview. This means, that the visitor left the website directly from the entrance page.</bounce_rate>
- <conversion_rate>The percentage of visits that triggered a goal conversion.</conversion_rate>
- </metricsDocumentation>
- <processedMetrics>
- <nb_actions_per_visit>Actions per Visit</nb_actions_per_visit>
- <avg_time_on_site>Avg. Time on Website</avg_time_on_site>
- <bounce_rate>Bounce Rate</bounce_rate>
- </processedMetrics>
- <metricsGoal>
- <nb_conversions>Conversions</nb_conversions>
- <revenue>Revenue</revenue>
- </metricsGoal>
- <processedMetricsGoal>
- <revenue_per_visit>Revenue per Visit</revenue_per_visit>
- </processedMetricsGoal>
- <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=UserCountry&amp;apiAction=getContinent&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
- <imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=UserCountry&amp;apiAction=getContinent&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
- <uniqueId>UserCountry_getContinent</uniqueId>
- </row>
- <row>
- <category>Visitors</category>
- <name>Region</name>
- <module>UserCountry</module>
- <action>getRegion</action>
- <dimension>Region</dimension>
- <documentation>This report shows which region your visitors were in when they accessed your website.&lt;br/&gt;In order to see data for this report, you must setup GeoIP in the Geolocation admin tab. The commercial &lt;a rel=&quot;noreferrer&quot; target=&quot;_blank&quot; href=&quot;http://www.maxmind.com/?rId=piwik&quot;&gt;Maxmind&lt;/a&gt; GeoIP databases are more accurate than the free ones. To see how accurate they are, click &lt;a rel=&quot;noreferrer&quot; target=&quot;_blank&quot; href=&quot;http://www.maxmind.com/en/city_accuracy?rId=piwik&quot;&gt;here&lt;/a&gt;.</documentation>
- <metrics>
- <nb_visits>Visits</nb_visits>
- <nb_uniq_visitors>Unique visitors</nb_uniq_visitors>
- <nb_actions>Actions</nb_actions>
- </metrics>
- <metricsDocumentation>
- <nb_visits>If a visitor comes to your website for the first time or if he visits a page more than 30 minutes after his last page view, this will be recorded as a new visit.</nb_visits>
- <nb_uniq_visitors>The number of unduplicated visitors coming to your website. Every user is only counted once, even if he visits the website multiple times a day.</nb_uniq_visitors>
- <nb_actions>The number of actions performed by your visitors. Actions can be page views, internal site searches, downloads or outlinks.</nb_actions>
- <nb_actions_per_visit>The average number of actions (page views, site searches, downloads or outlinks) that were performed during the visits.</nb_actions_per_visit>
- <avg_time_on_site>The average duration of a visit.</avg_time_on_site>
- <bounce_rate>The percentage of visits that only had a single pageview. This means, that the visitor left the website directly from the entrance page.</bounce_rate>
- <conversion_rate>The percentage of visits that triggered a goal conversion.</conversion_rate>
- </metricsDocumentation>
- <processedMetrics>
- <nb_actions_per_visit>Actions per Visit</nb_actions_per_visit>
- <avg_time_on_site>Avg. Time on Website</avg_time_on_site>
- <bounce_rate>Bounce Rate</bounce_rate>
- </processedMetrics>
- <metricsGoal>
- <nb_conversions>Conversions</nb_conversions>
- <revenue>Revenue</revenue>
- </metricsGoal>
- <processedMetricsGoal>
- <revenue_per_visit>Revenue per Visit</revenue_per_visit>
- </processedMetricsGoal>
- <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=UserCountry&amp;apiAction=getRegion&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
- <imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=UserCountry&amp;apiAction=getRegion&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
- <uniqueId>UserCountry_getRegion</uniqueId>
- </row>
- <row>
- <category>Visitors</category>
- <name>City</name>
- <module>UserCountry</module>
- <action>getCity</action>
- <dimension>City</dimension>
- <documentation>This report shows the cities your visitors were in when they accessed your website.&lt;br/&gt;In order to see data for this report, you must setup GeoIP in the Geolocation admin tab. The commercial &lt;a rel=&quot;noreferrer&quot; target=&quot;_blank&quot; href=&quot;http://www.maxmind.com/?rId=piwik&quot;&gt;Maxmind&lt;/a&gt; GeoIP databases are more accurate than the free ones. To see how accurate they are, click &lt;a rel=&quot;noreferrer&quot; target=&quot;_blank&quot; href=&quot;http://www.maxmind.com/en/city_accuracy?rId=piwik&quot;&gt;here&lt;/a&gt;.</documentation>
- <metrics>
- <nb_visits>Visits</nb_visits>
- <nb_uniq_visitors>Unique visitors</nb_uniq_visitors>
- <nb_actions>Actions</nb_actions>
- </metrics>
- <metricsDocumentation>
- <nb_visits>If a visitor comes to your website for the first time or if he visits a page more than 30 minutes after his last page view, this will be recorded as a new visit.</nb_visits>
- <nb_uniq_visitors>The number of unduplicated visitors coming to your website. Every user is only counted once, even if he visits the website multiple times a day.</nb_uniq_visitors>
- <nb_actions>The number of actions performed by your visitors. Actions can be page views, internal site searches, downloads or outlinks.</nb_actions>
- <nb_actions_per_visit>The average number of actions (page views, site searches, downloads or outlinks) that were performed during the visits.</nb_actions_per_visit>
- <avg_time_on_site>The average duration of a visit.</avg_time_on_site>
- <bounce_rate>The percentage of visits that only had a single pageview. This means, that the visitor left the website directly from the entrance page.</bounce_rate>
- <conversion_rate>The percentage of visits that triggered a goal conversion.</conversion_rate>
- </metricsDocumentation>
- <processedMetrics>
- <nb_actions_per_visit>Actions per Visit</nb_actions_per_visit>
- <avg_time_on_site>Avg. Time on Website</avg_time_on_site>
- <bounce_rate>Bounce Rate</bounce_rate>
- </processedMetrics>
- <metricsGoal>
- <nb_conversions>Conversions</nb_conversions>
- <revenue>Revenue</revenue>
- </metricsGoal>
- <processedMetricsGoal>
- <revenue_per_visit>Revenue per Visit</revenue_per_visit>
- </processedMetricsGoal>
- <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=UserCountry&amp;apiAction=getCity&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
- <imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=UserCountry&amp;apiAction=getCity&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
- <uniqueId>UserCountry_getCity</uniqueId>
- </row>
- <row>
- <category>Visitors</category>
- <name>Custom Variables</name>
- <module>CustomVariables</module>
- <action>getCustomVariables</action>
- <dimension>Custom Variable name</dimension>
- <documentation>This report contains information about your Custom Variables. Click on a variable name to see the distribution of the values. &lt;br /&gt; For more information about Custom Variables in general, read the &lt;a href=&quot;http://piwik.org/docs/custom-variables/&quot; rel=&quot;noreferrer&quot; target=&quot;_blank&quot;&gt;Custom Variables documentation on piwik.org&lt;/a&gt;</documentation>
- <metrics>
- <nb_visits>Visits</nb_visits>
- <nb_uniq_visitors>Unique visitors</nb_uniq_visitors>
- <nb_actions>Actions</nb_actions>
- <nb_users>Users</nb_users>
- </metrics>
- <metricsDocumentation>
- <nb_visits>If a visitor comes to your website for the first time or if he visits a page more than 30 minutes after his last page view, this will be recorded as a new visit.</nb_visits>
- <nb_uniq_visitors>The number of unduplicated visitors coming to your website. Every user is only counted once, even if he visits the website multiple times a day.</nb_uniq_visitors>
- <nb_actions>The number of actions performed by your visitors. Actions can be page views, internal site searches, downloads or outlinks.</nb_actions>
- <nb_users>The number of users logged in your website. It is the number of unique active users that have a User ID set (via the Tracking code function 'setUserId').</nb_users>
- <nb_actions_per_visit>The average number of actions (page views, site searches, downloads or outlinks) that were performed during the visits.</nb_actions_per_visit>
- <avg_time_on_site>The average duration of a visit.</avg_time_on_site>
- <bounce_rate>The percentage of visits that only had a single pageview. This means, that the visitor left the website directly from the entrance page.</bounce_rate>
- <conversion_rate>The percentage of visits that triggered a goal conversion.</conversion_rate>
- </metricsDocumentation>
- <processedMetrics>
- <nb_actions_per_visit>Actions per Visit</nb_actions_per_visit>
- <avg_time_on_site>Avg. Time on Website</avg_time_on_site>
- <bounce_rate>Bounce Rate</bounce_rate>
- </processedMetrics>
- <actionToLoadSubTables>getCustomVariablesValuesFromNameId</actionToLoadSubTables>
- <metricsGoal>
- <nb_conversions>Conversions</nb_conversions>
- <revenue>Revenue</revenue>
- </metricsGoal>
- <processedMetricsGoal>
- <revenue_per_visit>Revenue per Visit</revenue_per_visit>
- </processedMetricsGoal>
- <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=CustomVariables&amp;apiAction=getCustomVariables&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
- <imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=CustomVariables&amp;apiAction=getCustomVariables&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
- <uniqueId>CustomVariables_getCustomVariables</uniqueId>
- </row>
- <row>
- <category>Visitors</category>
- <name>Length of Visits</name>
- <module>VisitorInterest</module>
- <action>getNumberOfVisitsPerVisitDuration</action>
- <dimension>Visit duration</dimension>
- <documentation>In this report, you can see how many visits had a certain total duration. Initially, the report is shown as a tag cloud, more common durations are displayed in a larger font.&lt;br /&gt;Please note, that you can view the report in other ways than as a tag cloud. Use the controls at the bottom of the report to do so.</documentation>
- <metrics>
- <nb_visits>Visits</nb_visits>
- </metrics>
- <metricsDocumentation>
- <nb_visits>If a visitor comes to your website for the first time or if he visits a page more than 30 minutes after his last page view, this will be recorded as a new visit.</nb_visits>
- </metricsDocumentation>
- <constantRowsCount>1</constantRowsCount>
- <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=VisitorInterest&amp;apiAction=getNumberOfVisitsPerVisitDuration&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
- <uniqueId>VisitorInterest_getNumberOfVisitsPerVisitDuration</uniqueId>
- </row>
- <row>
- <category>Visitors</category>
- <name>Pages per Visit</name>
- <module>VisitorInterest</module>
- <action>getNumberOfVisitsPerPage</action>
- <dimension>Pages per visit</dimension>
- <documentation>In this report, you can see how many visits involved a certain number of pageviews. Initially, the report is shown as a tag cloud, more common numbers of pages are displayed in a larger font.&lt;br /&gt;Please note, that you can view the report in other ways than as a tag cloud. Use the controls at the bottom of the report to do so.</documentation>
- <metrics>
- <nb_visits>Visits</nb_visits>
- </metrics>
- <metricsDocumentation>
- <nb_visits>If a visitor comes to your website for the first time or if he visits a page more than 30 minutes after his last page view, this will be recorded as a new visit.</nb_visits>
- </metricsDocumentation>
- <constantRowsCount>1</constantRowsCount>
- <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=VisitorInterest&amp;apiAction=getNumberOfVisitsPerPage&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
- <uniqueId>VisitorInterest_getNumberOfVisitsPerPage</uniqueId>
- </row>
- <row>
- <category>Visitors</category>
- <name>Visits by Visit Number</name>
- <module>VisitorInterest</module>
- <action>getNumberOfVisitsByVisitCount</action>
- <dimension>Visits by Visit Number</dimension>
- <documentation>In this report, you can see the number of visits who were the Nth visit, ie. visitors who visited your website at least N times.&lt;br /&gt;Please note, that you can view the report in other ways than as a tag cloud. Use the controls at the bottom of the report to do so.</documentation>
- <metrics>
- <nb_visits>Visits</nb_visits>
- </metrics>
- <metricsDocumentation>
- <nb_visits>If a visitor comes to your website for the first time or if he visits a page more than 30 minutes after his last page view, this will be recorded as a new visit.</nb_visits>
- </metricsDocumentation>
- <processedMetrics>
- <nb_visits_percentage>% Visits</nb_visits_percentage>
- </processedMetrics>
- <constantRowsCount>1</constantRowsCount>
- <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=VisitorInterest&amp;apiAction=getNumberOfVisitsByVisitCount&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
- <uniqueId>VisitorInterest_getNumberOfVisitsByVisitCount</uniqueId>
- </row>
- <row>
- <category>Visitors</category>
- <name>Visits by days since last visit</name>
- <module>VisitorInterest</module>
- <action>getNumberOfVisitsByDaysSinceLast</action>
- <dimension>Visits by days since last visit</dimension>
- <documentation>In this report, you can see how many visits were from visitors whose last visit was a certain number of days ago.</documentation>
- <metrics>
- <nb_visits>Visits</nb_visits>
- </metrics>
- <metricsDocumentation>
- <nb_visits>If a visitor comes to your website for the first time or if he visits a page more than 30 minutes after his last page view, this will be recorded as a new visit.</nb_visits>
- </metricsDocumentation>
- <constantRowsCount>1</constantRowsCount>
- <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=VisitorInterest&amp;apiAction=getNumberOfVisitsByDaysSinceLast&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
- <uniqueId>VisitorInterest_getNumberOfVisitsByDaysSinceLast</uniqueId>
- </row>
- <row>
- <category>Visitors</category>
- <name>Returning Visits</name>
- <module>VisitFrequency</module>
- <action>get</action>
- <metrics>
- <nb_visits_returning>Returning Visits</nb_visits_returning>
- <nb_actions_returning>Actions by Returning Visits</nb_actions_returning>
- <nb_uniq_visitors_returning>Unique returning visitors</nb_uniq_visitors_returning>
- <nb_users_returning>Returning Users</nb_users_returning>
- <max_actions_returning>Maximum actions in one returning visit</max_actions_returning>
- </metrics>
- <processedMetrics>
- <avg_time_on_site_returning>Avg. Duration of a Returning Visit (in sec)</avg_time_on_site_returning>
- <nb_actions_per_visit_returning>Avg. Actions per Returning Visit</nb_actions_per_visit_returning>
- <bounce_rate_returning>Bounce Rate for Returning Visits</bounce_rate_returning>
- </processedMetrics>
- <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=VisitFrequency&amp;apiAction=get&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphUrl>
- <imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=VisitFrequency&amp;apiAction=get&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
- <uniqueId>VisitFrequency_get</uniqueId>
- </row>
- <row>
- <category>Visitor Devices</category>
- <name>Device type</name>
- <module>DevicesDetection</module>
- <action>getType</action>
- <dimension>Device type</dimension>
+ <category>UI Framework</category>
+ <subcategory>Data tables</subcategory>
+ <name>Data tables</name>
+ <module>ExampleUI</module>
+ <action>getTemperatures</action>
<metrics>
<nb_visits>Visits</nb_visits>
<nb_uniq_visitors>Unique visitors</nb_uniq_visitors>
@@ -1863,17 +2248,15 @@
<bounce_rate>Bounce Rate</bounce_rate>
<conversion_rate>Conversion Rate</conversion_rate>
</processedMetrics>
- <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=DevicesDetection&amp;apiAction=getType&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
- <imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=DevicesDetection&amp;apiAction=getType&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
- <uniqueId>DevicesDetection_getType</uniqueId>
+ <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=ExampleUI&amp;apiAction=getTemperatures&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphUrl>
+ <imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=ExampleUI&amp;apiAction=getTemperatures&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
+ <uniqueId>ExampleUI_getTemperatures</uniqueId>
</row>
<row>
- <category>Visitor Devices</category>
- <name>Visitor Browser</name>
- <module>DevicesDetection</module>
- <action>getBrowsers</action>
- <dimension>Browser</dimension>
- <documentation>This report contains information about what kind of browser your visitors were using. Each browser version is listed separately.</documentation>
+ <category>UI Framework</category>
+ <name>Temperatures evolution over time</name>
+ <module>ExampleUI</module>
+ <action>getTemperaturesEvolution</action>
<metrics>
<nb_visits>Visits</nb_visits>
<nb_uniq_visitors>Unique visitors</nb_uniq_visitors>
@@ -1896,16 +2279,16 @@
<bounce_rate>Bounce Rate</bounce_rate>
<conversion_rate>Conversion Rate</conversion_rate>
</processedMetrics>
- <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=DevicesDetection&amp;apiAction=getBrowsers&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
- <imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=DevicesDetection&amp;apiAction=getBrowsers&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
- <uniqueId>DevicesDetection_getBrowsers</uniqueId>
+ <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=ExampleUI&amp;apiAction=getTemperaturesEvolution&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphUrl>
+ <imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=ExampleUI&amp;apiAction=getTemperaturesEvolution&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
+ <uniqueId>ExampleUI_getTemperaturesEvolution</uniqueId>
</row>
<row>
- <category>Visitor Devices</category>
- <name>Device brand</name>
- <module>DevicesDetection</module>
- <action>getBrand</action>
- <dimension>Device brand</dimension>
+ <category>UI Framework</category>
+ <subcategory>Pie graph</subcategory>
+ <name>Pie graph</name>
+ <module>ExampleUI</module>
+ <action>getPlanetRatios</action>
<metrics>
<nb_visits>Visits</nb_visits>
<nb_uniq_visitors>Unique visitors</nb_uniq_visitors>
@@ -1928,16 +2311,16 @@
<bounce_rate>Bounce Rate</bounce_rate>
<conversion_rate>Conversion Rate</conversion_rate>
</processedMetrics>
- <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=DevicesDetection&amp;apiAction=getBrand&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
- <imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=DevicesDetection&amp;apiAction=getBrand&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
- <uniqueId>DevicesDetection_getBrand</uniqueId>
+ <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=ExampleUI&amp;apiAction=getPlanetRatios&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphUrl>
+ <imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=ExampleUI&amp;apiAction=getPlanetRatios&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
+ <uniqueId>ExampleUI_getPlanetRatios</uniqueId>
</row>
<row>
- <category>Visitor Devices</category>
- <name>Browser version</name>
- <module>DevicesDetection</module>
- <action>getBrowserVersions</action>
- <dimension>Browser version</dimension>
+ <category>UI Framework</category>
+ <subcategory>Tag clouds</subcategory>
+ <name>Advanced tag cloud: with logos and links</name>
+ <module>ExampleUI</module>
+ <action>getPlanetRatiosWithLogos</action>
<metrics>
<nb_visits>Visits</nb_visits>
<nb_uniq_visitors>Unique visitors</nb_uniq_visitors>
@@ -1960,137 +2343,68 @@
<bounce_rate>Bounce Rate</bounce_rate>
<conversion_rate>Conversion Rate</conversion_rate>
</processedMetrics>
- <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=DevicesDetection&amp;apiAction=getBrowserVersions&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
- <imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=DevicesDetection&amp;apiAction=getBrowserVersions&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
- <uniqueId>DevicesDetection_getBrowserVersions</uniqueId>
+ <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=ExampleUI&amp;apiAction=getPlanetRatiosWithLogos&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphUrl>
+ <imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=ExampleUI&amp;apiAction=getPlanetRatiosWithLogos&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
+ <uniqueId>ExampleUI_getPlanetRatiosWithLogos</uniqueId>
</row>
<row>
- <category>Visitor Devices</category>
- <name>Device model</name>
- <module>DevicesDetection</module>
- <action>getModel</action>
- <dimension>Device model</dimension>
+ <category>API</category>
+ <name>Main metrics</name>
+ <module>API</module>
+ <action>get</action>
<metrics>
- <nb_visits>Visits</nb_visits>
+ <nb_pageviews>Pageviews</nb_pageviews>
+ <nb_uniq_pageviews>Unique Pageviews</nb_uniq_pageviews>
+ <nb_downloads>Downloads</nb_downloads>
+ <nb_uniq_downloads>Unique Downloads</nb_uniq_downloads>
+ <nb_outlinks>Outlinks</nb_outlinks>
+ <nb_uniq_outlinks>Unique Outlinks</nb_uniq_outlinks>
+ <nb_searches>Searches</nb_searches>
+ <nb_keywords>Unique Keywords</nb_keywords>
+ <nb_conversions>Conversions</nb_conversions>
+ <nb_visits_converted>Visits with Conversions</nb_visits_converted>
+ <revenue>Revenue</revenue>
<nb_uniq_visitors>Unique visitors</nb_uniq_visitors>
- <nb_actions>Actions</nb_actions>
- <nb_users>Users</nb_users>
- </metrics>
- <metricsDocumentation>
- <nb_visits>If a visitor comes to your website for the first time or if he visits a page more than 30 minutes after his last page view, this will be recorded as a new visit.</nb_visits>
- <nb_uniq_visitors>The number of unduplicated visitors coming to your website. Every user is only counted once, even if he visits the website multiple times a day.</nb_uniq_visitors>
- <nb_actions>The number of actions performed by your visitors. Actions can be page views, internal site searches, downloads or outlinks.</nb_actions>
- <nb_users>The number of users logged in your website. It is the number of unique active users that have a User ID set (via the Tracking code function 'setUserId').</nb_users>
- <nb_actions_per_visit>The average number of actions (page views, site searches, downloads or outlinks) that were performed during the visits.</nb_actions_per_visit>
- <avg_time_on_site>The average duration of a visit.</avg_time_on_site>
- <bounce_rate>The percentage of visits that only had a single pageview. This means, that the visitor left the website directly from the entrance page.</bounce_rate>
- <conversion_rate>The percentage of visits that triggered a goal conversion.</conversion_rate>
- </metricsDocumentation>
- <processedMetrics>
- <nb_actions_per_visit>Actions per Visit</nb_actions_per_visit>
- <avg_time_on_site>Avg. Time on Website</avg_time_on_site>
- <bounce_rate>Bounce Rate</bounce_rate>
- <conversion_rate>Conversion Rate</conversion_rate>
- </processedMetrics>
- <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=DevicesDetection&amp;apiAction=getModel&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
- <imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=DevicesDetection&amp;apiAction=getModel&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
- <uniqueId>DevicesDetection_getModel</uniqueId>
- </row>
- <row>
- <category>Visitor Devices</category>
- <name>Operating System families</name>
- <module>DevicesDetection</module>
- <action>getOsFamilies</action>
- <dimension>Operating system family</dimension>
- <metrics>
<nb_visits>Visits</nb_visits>
- <nb_uniq_visitors>Unique visitors</nb_uniq_visitors>
- <nb_actions>Actions</nb_actions>
<nb_users>Users</nb_users>
- </metrics>
- <metricsDocumentation>
- <nb_visits>If a visitor comes to your website for the first time or if he visits a page more than 30 minutes after his last page view, this will be recorded as a new visit.</nb_visits>
- <nb_uniq_visitors>The number of unduplicated visitors coming to your website. Every user is only counted once, even if he visits the website multiple times a day.</nb_uniq_visitors>
- <nb_actions>The number of actions performed by your visitors. Actions can be page views, internal site searches, downloads or outlinks.</nb_actions>
- <nb_users>The number of users logged in your website. It is the number of unique active users that have a User ID set (via the Tracking code function 'setUserId').</nb_users>
- <nb_actions_per_visit>The average number of actions (page views, site searches, downloads or outlinks) that were performed during the visits.</nb_actions_per_visit>
- <avg_time_on_site>The average duration of a visit.</avg_time_on_site>
- <bounce_rate>The percentage of visits that only had a single pageview. This means, that the visitor left the website directly from the entrance page.</bounce_rate>
- <conversion_rate>The percentage of visits that triggered a goal conversion.</conversion_rate>
- </metricsDocumentation>
- <processedMetrics>
- <nb_actions_per_visit>Actions per Visit</nb_actions_per_visit>
- <avg_time_on_site>Avg. Time on Website</avg_time_on_site>
- <bounce_rate>Bounce Rate</bounce_rate>
- <conversion_rate>Conversion Rate</conversion_rate>
- </processedMetrics>
- <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=DevicesDetection&amp;apiAction=getOsFamilies&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
- <imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=DevicesDetection&amp;apiAction=getOsFamilies&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
- <uniqueId>DevicesDetection_getOsFamilies</uniqueId>
- </row>
- <row>
- <category>Visitor Devices</category>
- <name>Operating System versions</name>
- <module>DevicesDetection</module>
- <action>getOsVersions</action>
- <dimension>Operating System versions</dimension>
- <metrics>
- <nb_visits>Visits</nb_visits>
- <nb_uniq_visitors>Unique visitors</nb_uniq_visitors>
<nb_actions>Actions</nb_actions>
- <nb_users>Users</nb_users>
+ <max_actions>Maximum actions in one visit</max_actions>
+ <nb_visits_returning>Returning Visits</nb_visits_returning>
+ <nb_actions_returning>Actions by Returning Visits</nb_actions_returning>
+ <nb_uniq_visitors_returning>Unique returning visitors</nb_uniq_visitors_returning>
+ <nb_users_returning>Returning Users</nb_users_returning>
+ <max_actions_returning>Maximum actions in one returning visit</max_actions_returning>
</metrics>
<metricsDocumentation>
- <nb_visits>If a visitor comes to your website for the first time or if he visits a page more than 30 minutes after his last page view, this will be recorded as a new visit.</nb_visits>
+ <nb_pageviews>The number of times this page was visited.</nb_pageviews>
+ <nb_uniq_pageviews>The number of visits that included this page. If a page was viewed multiple times during one visit, it is only counted once.</nb_uniq_pageviews>
+ <nb_downloads>The number of times this link was clicked.</nb_downloads>
+ <nb_uniq_downloads>The number of visits that involved a click on this link. If a link was clicked multiple times during one visit, it is only counted once.</nb_uniq_downloads>
+ <nb_outlinks>The number of times this link was clicked.</nb_outlinks>
+ <nb_uniq_outlinks>The number of visits that involved a click on this link. If a link was clicked multiple times during one visit, it is only counted once.</nb_uniq_outlinks>
+ <nb_searches>The number of visits that searched for this keyword on your website's search engine.</nb_searches>
<nb_uniq_visitors>The number of unduplicated visitors coming to your website. Every user is only counted once, even if he visits the website multiple times a day.</nb_uniq_visitors>
- <nb_actions>The number of actions performed by your visitors. Actions can be page views, internal site searches, downloads or outlinks.</nb_actions>
- <nb_users>The number of users logged in your website. It is the number of unique active users that have a User ID set (via the Tracking code function 'setUserId').</nb_users>
- <nb_actions_per_visit>The average number of actions (page views, site searches, downloads or outlinks) that were performed during the visits.</nb_actions_per_visit>
- <avg_time_on_site>The average duration of a visit.</avg_time_on_site>
- <bounce_rate>The percentage of visits that only had a single pageview. This means, that the visitor left the website directly from the entrance page.</bounce_rate>
- <conversion_rate>The percentage of visits that triggered a goal conversion.</conversion_rate>
- </metricsDocumentation>
- <processedMetrics>
- <nb_actions_per_visit>Actions per Visit</nb_actions_per_visit>
- <avg_time_on_site>Avg. Time on Website</avg_time_on_site>
- <bounce_rate>Bounce Rate</bounce_rate>
- <conversion_rate>Conversion Rate</conversion_rate>
- </processedMetrics>
- <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=DevicesDetection&amp;apiAction=getOsVersions&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
- <imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=DevicesDetection&amp;apiAction=getOsVersions&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
- <uniqueId>DevicesDetection_getOsVersions</uniqueId>
- </row>
- <row>
- <category>Visitor Devices</category>
- <name>Browser engines</name>
- <module>DevicesDetection</module>
- <action>getBrowserEngines</action>
- <dimension>Browser engine</dimension>
- <documentation>This report shows your visitors' browsers broken down into browser engines. &lt;br /&gt; The most important information for web developers is what kind of rendering engine their visitors are using. The labels contain the names of the engines followed by the most common browser using that engine in brackets.</documentation>
- <metrics>
- <nb_visits>Visits</nb_visits>
- <nb_uniq_visitors>Unique visitors</nb_uniq_visitors>
- <nb_actions>Actions</nb_actions>
- <nb_users>Users</nb_users>
- </metrics>
- <metricsDocumentation>
<nb_visits>If a visitor comes to your website for the first time or if he visits a page more than 30 minutes after his last page view, this will be recorded as a new visit.</nb_visits>
- <nb_uniq_visitors>The number of unduplicated visitors coming to your website. Every user is only counted once, even if he visits the website multiple times a day.</nb_uniq_visitors>
- <nb_actions>The number of actions performed by your visitors. Actions can be page views, internal site searches, downloads or outlinks.</nb_actions>
<nb_users>The number of users logged in your website. It is the number of unique active users that have a User ID set (via the Tracking code function 'setUserId').</nb_users>
+ <nb_actions>The number of actions performed by your visitors. Actions can be page views, internal site searches, downloads or outlinks.</nb_actions>
+ <avg_time_generation>The average time it took to generate the page. This metric includes the time it took the server to generate the web page, plus the time it took for the visitor to download the response from the server. A lower 'Avg. generation time' means a faster website for your visitors!</avg_time_generation>
+ <conversion_rate>The percentage of visits that triggered a goal conversion.</conversion_rate>
+ <bounce_rate>The percentage of visits that only had a single pageview. This means, that the visitor left the website directly from the entrance page.</bounce_rate>
<nb_actions_per_visit>The average number of actions (page views, site searches, downloads or outlinks) that were performed during the visits.</nb_actions_per_visit>
<avg_time_on_site>The average duration of a visit.</avg_time_on_site>
- <bounce_rate>The percentage of visits that only had a single pageview. This means, that the visitor left the website directly from the entrance page.</bounce_rate>
- <conversion_rate>The percentage of visits that triggered a goal conversion.</conversion_rate>
</metricsDocumentation>
<processedMetrics>
- <nb_actions_per_visit>Actions per Visit</nb_actions_per_visit>
- <avg_time_on_site>Avg. Time on Website</avg_time_on_site>
- <bounce_rate>Bounce Rate</bounce_rate>
+ <avg_time_generation>Avg. generation time</avg_time_generation>
<conversion_rate>Conversion Rate</conversion_rate>
+ <bounce_rate>Bounce Rate</bounce_rate>
+ <nb_actions_per_visit>Actions per Visit</nb_actions_per_visit>
+ <avg_time_on_site>Avg. Visit Duration (in seconds)</avg_time_on_site>
+ <avg_time_on_site_returning>Avg. Duration of a Returning Visit (in sec)</avg_time_on_site_returning>
+ <nb_actions_per_visit_returning>Avg. Actions per Returning Visit</nb_actions_per_visit_returning>
+ <bounce_rate_returning>Bounce Rate for Returning Visits</bounce_rate_returning>
</processedMetrics>
- <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=DevicesDetection&amp;apiAction=getBrowserEngines&amp;period=day&amp;date=2009-01-04</imageGraphUrl>
- <imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=DevicesDetection&amp;apiAction=getBrowserEngines&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
- <uniqueId>DevicesDetection_getBrowserEngines</uniqueId>
+ <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=API&amp;apiAction=get&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphUrl>
+ <imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=API&amp;apiAction=get&amp;period=day&amp;date=2008-12-06,2009-01-04</imageGraphEvolutionUrl>
+ <uniqueId>API_get</uniqueId>
</row>
</result> \ No newline at end of file
diff --git a/tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getReportPagesMetadata.xml b/tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getReportPagesMetadata.xml
new file mode 100644
index 0000000000..0346619db3
--- /dev/null
+++ b/tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getReportPagesMetadata.xml
@@ -0,0 +1,4193 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<result>
+ <row>
+ <uniqueId>General_Actions.General_Downloads</uniqueId>
+ <category>
+ <id>General_Actions</id>
+ <name>Actions</name>
+ <order>10</order>
+ <icon>icon-reporting-actions</icon>
+ </category>
+ <subcategory>
+ <id>General_Downloads</id>
+ <name>Downloads</name>
+ <order>35</order>
+ </subcategory>
+ <widgets>
+ <row>
+ <name>Downloads</name>
+ <module>Actions</module>
+ <action>getDownloads</action>
+ <order>109</order>
+ <parameters>
+ <module>Actions</module>
+ <action>getDownloads</action>
+ </parameters>
+ <uniqueId>widgetActionsgetDownloads</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ </widgets>
+ </row>
+ <row>
+ <uniqueId>General_Actions.Actions_SubmenuPagesEntry</uniqueId>
+ <category>
+ <id>General_Actions</id>
+ <name>Actions</name>
+ <order>10</order>
+ <icon>icon-reporting-actions</icon>
+ </category>
+ <subcategory>
+ <id>Actions_SubmenuPagesEntry</id>
+ <name>Entry pages</name>
+ <order>10</order>
+ </subcategory>
+ <widgets>
+ <row>
+ <name>Entry pages</name>
+ <module>Actions</module>
+ <action>getEntryPageUrls</action>
+ <order>103</order>
+ <parameters>
+ <module>Actions</module>
+ <action>getEntryPageUrls</action>
+ </parameters>
+ <uniqueId>widgetActionsgetEntryPageUrls</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ </widgets>
+ </row>
+ <row>
+ <uniqueId>General_Actions.Actions_SubmenuPagesExit</uniqueId>
+ <category>
+ <id>General_Actions</id>
+ <name>Actions</name>
+ <order>10</order>
+ <icon>icon-reporting-actions</icon>
+ </category>
+ <subcategory>
+ <id>Actions_SubmenuPagesExit</id>
+ <name>Exit pages</name>
+ <order>15</order>
+ </subcategory>
+ <widgets>
+ <row>
+ <name>Exit pages</name>
+ <module>Actions</module>
+ <action>getExitPageUrls</action>
+ <order>104</order>
+ <parameters>
+ <module>Actions</module>
+ <action>getExitPageUrls</action>
+ </parameters>
+ <uniqueId>widgetActionsgetExitPageUrls</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ </widgets>
+ </row>
+ <row>
+ <uniqueId>General_Actions.General_Outlinks</uniqueId>
+ <category>
+ <id>General_Actions</id>
+ <name>Actions</name>
+ <order>10</order>
+ <icon>icon-reporting-actions</icon>
+ </category>
+ <subcategory>
+ <id>General_Outlinks</id>
+ <name>Outlinks</name>
+ <order>30</order>
+ </subcategory>
+ <widgets>
+ <row>
+ <name>Outlinks</name>
+ <module>Actions</module>
+ <action>getOutlinks</action>
+ <order>108</order>
+ <parameters>
+ <module>Actions</module>
+ <action>getOutlinks</action>
+ </parameters>
+ <uniqueId>widgetActionsgetOutlinks</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ </widgets>
+ </row>
+ <row>
+ <uniqueId>General_Actions.General_Pages</uniqueId>
+ <category>
+ <id>General_Actions</id>
+ <name>Actions</name>
+ <order>10</order>
+ <icon>icon-reporting-actions</icon>
+ </category>
+ <subcategory>
+ <id>General_Pages</id>
+ <name>Pages</name>
+ <order>5</order>
+ </subcategory>
+ <widgets>
+ <row>
+ <name>Pages</name>
+ <module>Actions</module>
+ <action>getPageUrls</action>
+ <order>102</order>
+ <parameters>
+ <module>Actions</module>
+ <action>getPageUrls</action>
+ </parameters>
+ <uniqueId>widgetActionsgetPageUrls</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ </widgets>
+ </row>
+ <row>
+ <uniqueId>General_Actions.Actions_SubmenuPageTitles</uniqueId>
+ <category>
+ <id>General_Actions</id>
+ <name>Actions</name>
+ <order>10</order>
+ <icon>icon-reporting-actions</icon>
+ </category>
+ <subcategory>
+ <id>Actions_SubmenuPageTitles</id>
+ <name>Page titles</name>
+ <order>20</order>
+ </subcategory>
+ <widgets>
+ <row>
+ <name>Page titles</name>
+ <module>Actions</module>
+ <action>getPageTitles</action>
+ <order>105</order>
+ <parameters>
+ <module>Actions</module>
+ <action>getPageTitles</action>
+ </parameters>
+ <uniqueId>widgetActionsgetPageTitles</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ </widgets>
+ </row>
+ <row>
+ <uniqueId>General_Actions.Actions_SubmenuSitesearch</uniqueId>
+ <category>
+ <id>General_Actions</id>
+ <name>Actions</name>
+ <order>10</order>
+ <icon>icon-reporting-actions</icon>
+ </category>
+ <subcategory>
+ <id>Actions_SubmenuSitesearch</id>
+ <name>Site Search</name>
+ <order>25</order>
+ </subcategory>
+ <widgets>
+ <row>
+ <name>Site Search Keywords</name>
+ <module>Actions</module>
+ <action>getSiteSearchKeywords</action>
+ <order>115</order>
+ <parameters>
+ <module>Actions</module>
+ <action>getSiteSearchKeywords</action>
+ </parameters>
+ <uniqueId>widgetActionsgetSiteSearchKeywords</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Pages Following a Site Search</name>
+ <module>Actions</module>
+ <action>getPageUrlsFollowingSiteSearch</action>
+ <order>116</order>
+ <parameters>
+ <module>Actions</module>
+ <action>getPageUrlsFollowingSiteSearch</action>
+ </parameters>
+ <uniqueId>widgetActionsgetPageUrlsFollowingSiteSearch</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Search Keywords with No Results</name>
+ <module>Actions</module>
+ <action>getSiteSearchNoResultKeywords</action>
+ <order>118</order>
+ <parameters>
+ <module>Actions</module>
+ <action>getSiteSearchNoResultKeywords</action>
+ </parameters>
+ <uniqueId>widgetActionsgetSiteSearchNoResultKeywords</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Page Titles Following a Site Search</name>
+ <module>Actions</module>
+ <action>getPageTitlesFollowingSiteSearch</action>
+ <order>119</order>
+ <parameters>
+ <module>Actions</module>
+ <action>getPageTitlesFollowingSiteSearch</action>
+ </parameters>
+ <uniqueId>widgetActionsgetPageTitlesFollowingSiteSearch</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Search Categories</name>
+ <module>Actions</module>
+ <action>getSiteSearchCategories</action>
+ <order>120</order>
+ <parameters>
+ <module>Actions</module>
+ <action>getSiteSearchCategories</action>
+ </parameters>
+ <uniqueId>widgetActionsgetSiteSearchCategories</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ </widgets>
+ </row>
+ <row>
+ <uniqueId>General_Actions.Events_Events</uniqueId>
+ <category>
+ <id>General_Actions</id>
+ <name>Actions</name>
+ <order>10</order>
+ <icon>icon-reporting-actions</icon>
+ </category>
+ <subcategory>
+ <id>Events_Events</id>
+ <name>Events</name>
+ <order>40</order>
+ </subcategory>
+ <widgets>
+ <row>
+ <name />
+ <module>CoreHome</module>
+ <action>renderWidgetContainer</action>
+ <order>99</order>
+ <parameters>
+ <module>CoreHome</module>
+ <action>renderWidgetContainer</action>
+ <containerId>Events</containerId>
+ </parameters>
+ <uniqueId>widgetEvents</uniqueId>
+ <layout>ByDimension</layout>
+ <isContainer>1</isContainer>
+ <widgets>
+ <row>
+ <name>Event Categories</name>
+ <category>
+ <id>General_Actions</id>
+ <name>Actions</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Events_Events</id>
+ <name>Events</name>
+ <order>99</order>
+ </subcategory>
+ <module>Events</module>
+ <action>getCategory</action>
+ <order>100</order>
+ <parameters>
+ <module>Events</module>
+ <action>getCategory</action>
+ <secondaryDimension>eventAction</secondaryDimension>
+ </parameters>
+ <uniqueId>widgetEventsgetCategorysecondaryDimensioneventAction</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Event Actions</name>
+ <category>
+ <id>General_Actions</id>
+ <name>Actions</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Events_Events</id>
+ <name>Events</name>
+ <order>99</order>
+ </subcategory>
+ <module>Events</module>
+ <action>getAction</action>
+ <order>101</order>
+ <parameters>
+ <module>Events</module>
+ <action>getAction</action>
+ <secondaryDimension>eventName</secondaryDimension>
+ </parameters>
+ <uniqueId>widgetEventsgetActionsecondaryDimensioneventName</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Event Names</name>
+ <category>
+ <id>General_Actions</id>
+ <name>Actions</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Events_Events</id>
+ <name>Events</name>
+ <order>99</order>
+ </subcategory>
+ <module>Events</module>
+ <action>getName</action>
+ <order>102</order>
+ <parameters>
+ <module>Events</module>
+ <action>getName</action>
+ <secondaryDimension>eventAction</secondaryDimension>
+ </parameters>
+ <uniqueId>widgetEventsgetNamesecondaryDimensioneventAction</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ </widgets>
+ </row>
+ </widgets>
+ </row>
+ <row>
+ <uniqueId>General_Actions.Contents_Contents</uniqueId>
+ <category>
+ <id>General_Actions</id>
+ <name>Actions</name>
+ <order>10</order>
+ <icon>icon-reporting-actions</icon>
+ </category>
+ <subcategory>
+ <id>Contents_Contents</id>
+ <name>Contents</name>
+ <order>45</order>
+ </subcategory>
+ <widgets>
+ <row>
+ <name />
+ <module>CoreHome</module>
+ <action>renderWidgetContainer</action>
+ <order>99</order>
+ <parameters>
+ <module>CoreHome</module>
+ <action>renderWidgetContainer</action>
+ <containerId>Contents</containerId>
+ </parameters>
+ <uniqueId>widgetContents</uniqueId>
+ <layout>ByDimension</layout>
+ <isContainer>1</isContainer>
+ <widgets>
+ <row>
+ <name>Content Name</name>
+ <category>
+ <id>General_Actions</id>
+ <name>Actions</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Contents_Contents</id>
+ <name>Contents</name>
+ <order>99</order>
+ </subcategory>
+ <module>Contents</module>
+ <action>getContentNames</action>
+ <order>135</order>
+ <parameters>
+ <module>Contents</module>
+ <action>getContentNames</action>
+ </parameters>
+ <uniqueId>widgetContentsgetContentNames</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Content Piece</name>
+ <category>
+ <id>General_Actions</id>
+ <name>Actions</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Contents_Contents</id>
+ <name>Contents</name>
+ <order>99</order>
+ </subcategory>
+ <module>Contents</module>
+ <action>getContentPieces</action>
+ <order>136</order>
+ <parameters>
+ <module>Contents</module>
+ <action>getContentPieces</action>
+ </parameters>
+ <uniqueId>widgetContentsgetContentPieces</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ </widgets>
+ </row>
+ </widgets>
+ </row>
+ <row>
+ <uniqueId>General_Visitors.DevicesDetection_Devices</uniqueId>
+ <category>
+ <id>General_Visitors</id>
+ <name>Visitors</name>
+ <order>5</order>
+ <icon>icon-reporting-visitors</icon>
+ </category>
+ <subcategory>
+ <id>DevicesDetection_Devices</id>
+ <name>Devices</name>
+ <order>15</order>
+ </subcategory>
+ <widgets>
+ <row>
+ <name>Device type</name>
+ <module>DevicesDetection</module>
+ <action>getType</action>
+ <order>100</order>
+ <parameters>
+ <module>DevicesDetection</module>
+ <action>getType</action>
+ </parameters>
+ <uniqueId>widgetDevicesDetectiongetType</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Device model</name>
+ <module>DevicesDetection</module>
+ <action>getModel</action>
+ <order>102</order>
+ <parameters>
+ <module>DevicesDetection</module>
+ <action>getModel</action>
+ </parameters>
+ <uniqueId>widgetDevicesDetectiongetModel</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Device brand</name>
+ <module>DevicesDetection</module>
+ <action>getBrand</action>
+ <order>104</order>
+ <parameters>
+ <module>DevicesDetection</module>
+ <action>getBrand</action>
+ </parameters>
+ <uniqueId>widgetDevicesDetectiongetBrand</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Screen Resolution</name>
+ <module>Resolution</module>
+ <action>getResolution</action>
+ <order>108</order>
+ <parameters>
+ <module>Resolution</module>
+ <action>getResolution</action>
+ </parameters>
+ <uniqueId>widgetResolutiongetResolution</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ </widgets>
+ </row>
+ <row>
+ <uniqueId>General_Visitors.VisitorInterest_Engagement</uniqueId>
+ <category>
+ <id>General_Visitors</id>
+ <name>Visitors</name>
+ <order>5</order>
+ <icon>icon-reporting-visitors</icon>
+ </category>
+ <subcategory>
+ <id>VisitorInterest_Engagement</id>
+ <name>Engagement</name>
+ <order>30</order>
+ </subcategory>
+ <widgets>
+ <row>
+ <name>Visits per visit duration</name>
+ <module>VisitorInterest</module>
+ <action>getNumberOfVisitsPerVisitDuration</action>
+ <order>115</order>
+ <parameters>
+ <viewDataTable>cloud</viewDataTable>
+ <module>VisitorInterest</module>
+ <action>getNumberOfVisitsPerVisitDuration</action>
+ </parameters>
+ <uniqueId>widgetVisitorInterestgetNumberOfVisitsPerVisitDurationviewDataTablecloud</uniqueId>
+ <viewDataTable>cloud</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Visits per number of pages</name>
+ <module>VisitorInterest</module>
+ <action>getNumberOfVisitsPerPage</action>
+ <order>120</order>
+ <parameters>
+ <viewDataTable>cloud</viewDataTable>
+ <module>VisitorInterest</module>
+ <action>getNumberOfVisitsPerPage</action>
+ </parameters>
+ <uniqueId>widgetVisitorInterestgetNumberOfVisitsPerPageviewDataTablecloud</uniqueId>
+ <viewDataTable>cloud</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Visits by Visit Number</name>
+ <module>VisitorInterest</module>
+ <action>getNumberOfVisitsByVisitCount</action>
+ <order>125</order>
+ <parameters>
+ <module>VisitorInterest</module>
+ <action>getNumberOfVisitsByVisitCount</action>
+ </parameters>
+ <uniqueId>widgetVisitorInterestgetNumberOfVisitsByVisitCount</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Visits by Days Since Last Visit</name>
+ <module>VisitorInterest</module>
+ <action>getNumberOfVisitsByDaysSinceLast</action>
+ <order>130</order>
+ <parameters>
+ <module>VisitorInterest</module>
+ <action>getNumberOfVisitsByDaysSinceLast</action>
+ </parameters>
+ <uniqueId>widgetVisitorInterestgetNumberOfVisitsByDaysSinceLast</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Returning Visits Over Time</name>
+ <module>VisitFrequency</module>
+ <action>getEvolutionGraph</action>
+ <order>1</order>
+ <parameters>
+ <forceView>1</forceView>
+ <viewDataTable>graphEvolution</viewDataTable>
+ <module>VisitFrequency</module>
+ <action>getEvolutionGraph</action>
+ </parameters>
+ <uniqueId>widgetVisitFrequencygetEvolutionGraphforceView1viewDataTablegraphEvolution</uniqueId>
+ <viewDataTable>graphEvolution</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Frequency Overview</name>
+ <module>VisitFrequency</module>
+ <action>get</action>
+ <order>2</order>
+ <parameters>
+ <forceView>1</forceView>
+ <viewDataTable>sparklines</viewDataTable>
+ <module>VisitFrequency</module>
+ <action>get</action>
+ </parameters>
+ <uniqueId>widgetVisitFrequencygetforceView1viewDataTablesparklines</uniqueId>
+ <viewDataTable>sparklines</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ </widgets>
+ </row>
+ <row>
+ <uniqueId>General_Visitors.DevicesDetection_Software</uniqueId>
+ <category>
+ <id>General_Visitors</id>
+ <name>Visitors</name>
+ <order>5</order>
+ <icon>icon-reporting-visitors</icon>
+ </category>
+ <subcategory>
+ <id>DevicesDetection_Software</id>
+ <name>Software</name>
+ <order>20</order>
+ </subcategory>
+ <widgets>
+ <row>
+ <name>Operating System versions</name>
+ <module>DevicesDetection</module>
+ <action>getOsVersions</action>
+ <order>102</order>
+ <parameters>
+ <module>DevicesDetection</module>
+ <action>getOsVersions</action>
+ </parameters>
+ <uniqueId>widgetDevicesDetectiongetOsVersions</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Browsers</name>
+ <module>DevicesDetection</module>
+ <action>getBrowsers</action>
+ <order>105</order>
+ <parameters>
+ <module>DevicesDetection</module>
+ <action>getBrowsers</action>
+ </parameters>
+ <uniqueId>widgetDevicesDetectiongetBrowsers</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Browser version</name>
+ <module>DevicesDetection</module>
+ <action>getBrowserVersions</action>
+ <order>106</order>
+ <parameters>
+ <module>DevicesDetection</module>
+ <action>getBrowserVersions</action>
+ </parameters>
+ <uniqueId>widgetDevicesDetectiongetBrowserVersions</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Configurations</name>
+ <module>Resolution</module>
+ <action>getConfiguration</action>
+ <order>107</order>
+ <parameters>
+ <module>Resolution</module>
+ <action>getConfiguration</action>
+ </parameters>
+ <uniqueId>widgetResolutiongetConfiguration</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Operating System families</name>
+ <module>DevicesDetection</module>
+ <action>getOsFamilies</action>
+ <order>108</order>
+ <parameters>
+ <module>DevicesDetection</module>
+ <action>getOsFamilies</action>
+ </parameters>
+ <uniqueId>widgetDevicesDetectiongetOsFamilies</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Browser engines</name>
+ <module>DevicesDetection</module>
+ <action>getBrowserEngines</action>
+ <order>110</order>
+ <parameters>
+ <viewDataTable>graphPie</viewDataTable>
+ <module>DevicesDetection</module>
+ <action>getBrowserEngines</action>
+ </parameters>
+ <uniqueId>widgetDevicesDetectiongetBrowserEnginesviewDataTablegraphPie</uniqueId>
+ <viewDataTable>graphPie</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Browser Plugins</name>
+ <module>DevicePlugins</module>
+ <action>getPlugin</action>
+ <order>113</order>
+ <parameters>
+ <module>DevicePlugins</module>
+ <action>getPlugin</action>
+ </parameters>
+ <uniqueId>widgetDevicePluginsgetPlugin</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ </widgets>
+ </row>
+ <row>
+ <uniqueId>General_Visitors.General_Overview</uniqueId>
+ <category>
+ <id>General_Visitors</id>
+ <name>Visitors</name>
+ <order>5</order>
+ <icon>icon-reporting-visitors</icon>
+ </category>
+ <subcategory>
+ <id>General_Overview</id>
+ <name>Overview</name>
+ <order>2</order>
+ </subcategory>
+ <widgets>
+ <row>
+ <name>Visits Over Time</name>
+ <module>VisitsSummary</module>
+ <action>getEvolutionGraph</action>
+ <order>5</order>
+ <parameters>
+ <forceView>1</forceView>
+ <viewDataTable>graphEvolution</viewDataTable>
+ <module>VisitsSummary</module>
+ <action>getEvolutionGraph</action>
+ </parameters>
+ <uniqueId>widgetVisitsSummarygetEvolutionGraphforceView1viewDataTablegraphEvolution</uniqueId>
+ <viewDataTable>graphEvolution</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Visits Overview</name>
+ <module>VisitsSummary</module>
+ <action>get</action>
+ <order>10</order>
+ <parameters>
+ <forceView>1</forceView>
+ <viewDataTable>sparklines</viewDataTable>
+ <module>VisitsSummary</module>
+ <action>get</action>
+ </parameters>
+ <uniqueId>widgetVisitsSummarygetforceView1viewDataTablesparklines</uniqueId>
+ <viewDataTable>sparklines</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ </widgets>
+ </row>
+ <row>
+ <uniqueId>General_Visitors.UserCountry_SubmenuLocations</uniqueId>
+ <category>
+ <id>General_Visitors</id>
+ <name>Visitors</name>
+ <order>5</order>
+ <icon>icon-reporting-visitors</icon>
+ </category>
+ <subcategory>
+ <id>UserCountry_SubmenuLocations</id>
+ <name>Locations</name>
+ <order>25</order>
+ </subcategory>
+ <widgets>
+ <row>
+ <name>Visitor Map</name>
+ <module>UserCountryMap</module>
+ <action>visitorMap</action>
+ <order>1</order>
+ <parameters>
+ <module>UserCountryMap</module>
+ <action>visitorMap</action>
+ </parameters>
+ <uniqueId>widgetUserCountryMapvisitorMap</uniqueId>
+ </row>
+ <row>
+ <name>Country</name>
+ <module>UserCountry</module>
+ <action>getCountry</action>
+ <order>105</order>
+ <parameters>
+ <module>UserCountry</module>
+ <action>getCountry</action>
+ </parameters>
+ <uniqueId>widgetUserCountrygetCountry</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name />
+ <module>CoreHome</module>
+ <action>renderWidgetContainer</action>
+ <order>106</order>
+ <parameters>
+ <module>CoreHome</module>
+ <action>renderWidgetContainer</action>
+ <containerId>Continent</containerId>
+ </parameters>
+ <uniqueId>widgetContinent</uniqueId>
+ <layout />
+ <isContainer>1</isContainer>
+ <widgets>
+ <row>
+ <name>Continent</name>
+ <category>
+ <id>General_Visitors</id>
+ <name>Visitors</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>UserCountry_SubmenuLocations</id>
+ <name>Locations</name>
+ <order>99</order>
+ </subcategory>
+ <module>UserCountry</module>
+ <action>getContinent</action>
+ <order>106</order>
+ <parameters>
+ <module>UserCountry</module>
+ <action>getContinent</action>
+ </parameters>
+ <uniqueId>widgetUserCountrygetContinent</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name />
+ <category>
+ <id>General_Visitors</id>
+ <name>Visitors</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>UserCountry_SubmenuLocations</id>
+ <name>Locations</name>
+ <order>99</order>
+ </subcategory>
+ <module>UserCountry</module>
+ <action>getDistinctCountries</action>
+ <order>106</order>
+ <parameters>
+ <module>UserCountry</module>
+ <action>getDistinctCountries</action>
+ </parameters>
+ <uniqueId>widgetUserCountrygetDistinctCountries</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ </widgets>
+ </row>
+ <row>
+ <name>Region</name>
+ <module>UserCountry</module>
+ <action>getRegion</action>
+ <order>107</order>
+ <parameters>
+ <module>UserCountry</module>
+ <action>getRegion</action>
+ </parameters>
+ <uniqueId>widgetUserCountrygetRegion</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Browser language</name>
+ <module>UserLanguage</module>
+ <action>getLanguage</action>
+ <order>108</order>
+ <parameters>
+ <module>UserLanguage</module>
+ <action>getLanguage</action>
+ </parameters>
+ <uniqueId>widgetUserLanguagegetLanguage</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>City</name>
+ <module>UserCountry</module>
+ <action>getCity</action>
+ <order>110</order>
+ <parameters>
+ <module>UserCountry</module>
+ <action>getCity</action>
+ </parameters>
+ <uniqueId>widgetUserCountrygetCity</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Language code</name>
+ <module>UserLanguage</module>
+ <action>getLanguageCode</action>
+ <order>111</order>
+ <parameters>
+ <module>UserLanguage</module>
+ <action>getLanguageCode</action>
+ </parameters>
+ <uniqueId>widgetUserLanguagegetLanguageCode</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ </widgets>
+ </row>
+ <row>
+ <uniqueId>General_Visitors.VisitTime_SubmenuTimes</uniqueId>
+ <category>
+ <id>General_Visitors</id>
+ <name>Visitors</name>
+ <order>5</order>
+ <icon>icon-reporting-visitors</icon>
+ </category>
+ <subcategory>
+ <id>VisitTime_SubmenuTimes</id>
+ <name>Times</name>
+ <order>35</order>
+ </subcategory>
+ <widgets>
+ <row>
+ <name>Visits per local time</name>
+ <module>VisitTime</module>
+ <action>getVisitInformationPerLocalTime</action>
+ <order>115</order>
+ <parameters>
+ <viewDataTable>graphVerticalBar</viewDataTable>
+ <module>VisitTime</module>
+ <action>getVisitInformationPerLocalTime</action>
+ </parameters>
+ <uniqueId>widgetVisitTimegetVisitInformationPerLocalTimeviewDataTablegraphVerticalBar</uniqueId>
+ <viewDataTable>graphVerticalBar</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Visits per server time</name>
+ <module>VisitTime</module>
+ <action>getVisitInformationPerServerTime</action>
+ <order>120</order>
+ <parameters>
+ <viewDataTable>graphVerticalBar</viewDataTable>
+ <module>VisitTime</module>
+ <action>getVisitInformationPerServerTime</action>
+ </parameters>
+ <uniqueId>widgetVisitTimegetVisitInformationPerServerTimeviewDataTablegraphVerticalBar</uniqueId>
+ <viewDataTable>graphVerticalBar</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Visits by Day of Week</name>
+ <module>VisitTime</module>
+ <action>getByDayOfWeek</action>
+ <order>125</order>
+ <parameters>
+ <viewDataTable>graphVerticalBar</viewDataTable>
+ <module>VisitTime</module>
+ <action>getByDayOfWeek</action>
+ </parameters>
+ <uniqueId>widgetVisitTimegetByDayOfWeekviewDataTablegraphVerticalBar</uniqueId>
+ <viewDataTable>graphVerticalBar</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ </widgets>
+ </row>
+ <row>
+ <uniqueId>General_Visitors.UserCountryMap_RealTimeMap</uniqueId>
+ <category>
+ <id>General_Visitors</id>
+ <name>Visitors</name>
+ <order>5</order>
+ <icon>icon-reporting-visitors</icon>
+ </category>
+ <subcategory>
+ <id>UserCountryMap_RealTimeMap</id>
+ <name>Real-time Map</name>
+ <order>40</order>
+ </subcategory>
+ <widgets>
+ <row>
+ <name>Real-time Map</name>
+ <module>UserCountryMap</module>
+ <action>realtimeMap</action>
+ <order>5</order>
+ <parameters>
+ <module>UserCountryMap</module>
+ <action>realtimeMap</action>
+ </parameters>
+ <uniqueId>widgetUserCountryMaprealtimeMap</uniqueId>
+ </row>
+ </widgets>
+ </row>
+ <row>
+ <uniqueId>General_Visitors.Live_VisitorLog</uniqueId>
+ <category>
+ <id>General_Visitors</id>
+ <name>Visitors</name>
+ <order>5</order>
+ <icon>icon-reporting-visitors</icon>
+ </category>
+ <subcategory>
+ <id>Live_VisitorLog</id>
+ <name>Visitor Log</name>
+ <order>5</order>
+ </subcategory>
+ <widgets>
+ <row>
+ <name>Visitor Log</name>
+ <module>Live</module>
+ <action>getLastVisitsDetails</action>
+ <order>10</order>
+ <parameters>
+ <forceView>1</forceView>
+ <viewDataTable>VisitorLog</viewDataTable>
+ <module>Live</module>
+ <action>getLastVisitsDetails</action>
+ <small>1</small>
+ </parameters>
+ <uniqueId>widgetLivegetLastVisitsDetailsforceView1viewDataTableVisitorLogsmall1</uniqueId>
+ <viewDataTable>VisitorLog</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ </widgets>
+ </row>
+ <row>
+ <uniqueId>General_Visitors.CustomVariables_CustomVariables</uniqueId>
+ <category>
+ <id>General_Visitors</id>
+ <name>Visitors</name>
+ <order>5</order>
+ <icon>icon-reporting-visitors</icon>
+ </category>
+ <subcategory>
+ <id>CustomVariables_CustomVariables</id>
+ <name>Custom Variables</name>
+ <order>10</order>
+ </subcategory>
+ <widgets>
+ <row>
+ <name>Custom Variables</name>
+ <module>CustomVariables</module>
+ <action>getCustomVariables</action>
+ <order>110</order>
+ <parameters>
+ <module>CustomVariables</module>
+ <action>getCustomVariables</action>
+ </parameters>
+ <uniqueId>widgetCustomVariablesgetCustomVariables</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ </widgets>
+ </row>
+ <row>
+ <uniqueId>Dashboard_Dashboard.1</uniqueId>
+ <category>
+ <id>Dashboard_Dashboard</id>
+ <name>Dashboard</name>
+ <order>0</order>
+ <icon>icon-reporting-dashboard</icon>
+ </category>
+ <subcategory>
+ <id>1</id>
+ <name>Dashboard</name>
+ <order>0</order>
+ </subcategory>
+ <widgets>
+ <row>
+ <name />
+ <module>Dashboard</module>
+ <action>embeddedIndex</action>
+ <order>99</order>
+ <parameters>
+ <module>Dashboard</module>
+ <action>embeddedIndex</action>
+ <idDashboard>1</idDashboard>
+ </parameters>
+ <uniqueId>widgetDashboardembeddedIndexidDashboard1</uniqueId>
+ </row>
+ </widgets>
+ </row>
+ <row>
+ <uniqueId>Referrers_Referrers.Referrers_WidgetGetAll</uniqueId>
+ <category>
+ <id>Referrers_Referrers</id>
+ <name>Referrers</name>
+ <order>15</order>
+ <icon>icon-reporting-referer</icon>
+ </category>
+ <subcategory>
+ <id>Referrers_WidgetGetAll</id>
+ <name>All Referrers</name>
+ <order>5</order>
+ </subcategory>
+ <widgets>
+ <row>
+ <name>Referrer Types</name>
+ <module>Referrers</module>
+ <action>getReferrerType</action>
+ <order>101</order>
+ <parameters>
+ <viewDataTable>tableAllColumns</viewDataTable>
+ <module>Referrers</module>
+ <action>getReferrerType</action>
+ </parameters>
+ <uniqueId>widgetReferrersgetReferrerTypeviewDataTabletableAllColumns</uniqueId>
+ <viewDataTable>tableAllColumns</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Referrers</name>
+ <module>Referrers</module>
+ <action>getAll</action>
+ <order>102</order>
+ <parameters>
+ <viewDataTable>tableAllColumns</viewDataTable>
+ <module>Referrers</module>
+ <action>getAll</action>
+ </parameters>
+ <uniqueId>widgetReferrersgetAllviewDataTabletableAllColumns</uniqueId>
+ <viewDataTable>tableAllColumns</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ </widgets>
+ </row>
+ <row>
+ <uniqueId>Referrers_Referrers.Referrers_Campaigns</uniqueId>
+ <category>
+ <id>Referrers_Referrers</id>
+ <name>Referrers</name>
+ <order>15</order>
+ <icon>icon-reporting-referer</icon>
+ </category>
+ <subcategory>
+ <id>Referrers_Campaigns</id>
+ <name>Campaigns</name>
+ <order>20</order>
+ </subcategory>
+ <widgets>
+ <row>
+ <name>Campaigns</name>
+ <module>Referrers</module>
+ <action>getCampaigns</action>
+ <order>109</order>
+ <parameters>
+ <module>Referrers</module>
+ <action>getCampaigns</action>
+ </parameters>
+ <uniqueId>widgetReferrersgetCampaigns</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ </widgets>
+ </row>
+ <row>
+ <uniqueId>Referrers_Referrers.General_Overview</uniqueId>
+ <category>
+ <id>Referrers_Referrers</id>
+ <name>Referrers</name>
+ <order>15</order>
+ <icon>icon-reporting-referer</icon>
+ </category>
+ <subcategory>
+ <id>General_Overview</id>
+ <name>Overview</name>
+ <order>2</order>
+ </subcategory>
+ <widgets>
+ <row>
+ <name>Evolution over the period</name>
+ <module>Referrers</module>
+ <action>getEvolutionGraph</action>
+ <order>101</order>
+ <parameters>
+ <forceView>1</forceView>
+ <viewDataTable>graphEvolution</viewDataTable>
+ <module>Referrers</module>
+ <action>getEvolutionGraph</action>
+ <columns>
+ <row>nb_visits</row>
+ </columns>
+ </parameters>
+ <uniqueId>widgetReferrersgetEvolutionGraphforceView1viewDataTablegraphEvolutioncolumnsArray</uniqueId>
+ <viewDataTable>graphEvolution</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Referrer Type</name>
+ <module>Referrers</module>
+ <action>getSparklines</action>
+ <order>10</order>
+ <parameters>
+ <forceView>1</forceView>
+ <viewDataTable>sparklines</viewDataTable>
+ <module>Referrers</module>
+ <action>getSparklines</action>
+ </parameters>
+ <uniqueId>widgetReferrersgetSparklinesforceView1viewDataTablesparklines</uniqueId>
+ <viewDataTable>sparklines</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ </widgets>
+ </row>
+ <row>
+ <uniqueId>Referrers_Referrers.Referrers_SubmenuSearchEngines</uniqueId>
+ <category>
+ <id>Referrers_Referrers</id>
+ <name>Referrers</name>
+ <order>15</order>
+ <icon>icon-reporting-referer</icon>
+ </category>
+ <subcategory>
+ <id>Referrers_SubmenuSearchEngines</id>
+ <name>Search Engines &amp; Keywords</name>
+ <order>10</order>
+ </subcategory>
+ <widgets>
+ <row>
+ <name>Keywords</name>
+ <module>Referrers</module>
+ <action>getKeywords</action>
+ <order>103</order>
+ <parameters>
+ <module>Referrers</module>
+ <action>getKeywords</action>
+ </parameters>
+ <uniqueId>widgetReferrersgetKeywords</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Search Engines</name>
+ <module>Referrers</module>
+ <action>getSearchEngines</action>
+ <order>107</order>
+ <parameters>
+ <module>Referrers</module>
+ <action>getSearchEngines</action>
+ </parameters>
+ <uniqueId>widgetReferrersgetSearchEngines</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ </widgets>
+ </row>
+ <row>
+ <uniqueId>Referrers_Referrers.Referrers_SubmenuWebsites</uniqueId>
+ <category>
+ <id>Referrers_Referrers</id>
+ <name>Referrers</name>
+ <order>15</order>
+ <icon>icon-reporting-referer</icon>
+ </category>
+ <subcategory>
+ <id>Referrers_SubmenuWebsites</id>
+ <name>Websites &amp; Social</name>
+ <order>15</order>
+ </subcategory>
+ <widgets>
+ <row>
+ <name>Websites</name>
+ <module>Referrers</module>
+ <action>getWebsites</action>
+ <order>105</order>
+ <parameters>
+ <module>Referrers</module>
+ <action>getWebsites</action>
+ </parameters>
+ <uniqueId>widgetReferrersgetWebsites</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Social Networks</name>
+ <module>Referrers</module>
+ <action>getSocials</action>
+ <order>111</order>
+ <parameters>
+ <viewDataTable>graphPie</viewDataTable>
+ <module>Referrers</module>
+ <action>getSocials</action>
+ </parameters>
+ <uniqueId>widgetReferrersgetSocialsviewDataTablegraphPie</uniqueId>
+ <viewDataTable>graphPie</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ </widgets>
+ </row>
+ <row>
+ <uniqueId>Goals_Goals.1</uniqueId>
+ <category>
+ <id>Goals_Goals</id>
+ <name>Goals</name>
+ <order>25</order>
+ <icon>icon-reporting-goal</icon>
+ </category>
+ <subcategory>
+ <id>1</id>
+ <name>Goal 1 - Thank you</name>
+ <order>900</order>
+ </subcategory>
+ <widgets>
+ <row>
+ <name>Goal 1 - Thank you</name>
+ <module>CoreHome</module>
+ <action>renderWidgetContainer</action>
+ <order>15</order>
+ <parameters>
+ <module>CoreHome</module>
+ <action>renderWidgetContainer</action>
+ <containerId>Goal_1</containerId>
+ </parameters>
+ <uniqueId>widgetGoal_1</uniqueId>
+ <layout />
+ <isContainer>1</isContainer>
+ <widgets>
+ <row>
+ <name />
+ <category>
+ <id>Goals_Goals</id>
+ <name>Goals</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>1</id>
+ <name>1</name>
+ <order>99</order>
+ </subcategory>
+ <module>Goals</module>
+ <action>getEvolutionGraph</action>
+ <order>13</order>
+ <parameters>
+ <forceView>1</forceView>
+ <viewDataTable>graphEvolution</viewDataTable>
+ <module>Goals</module>
+ <action>getEvolutionGraph</action>
+ <idGoal>1</idGoal>
+ </parameters>
+ <uniqueId>widgetGoalsgetEvolutionGraphforceView1viewDataTablegraphEvolutionidGoal1</uniqueId>
+ <viewDataTable>graphEvolution</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name />
+ <category>
+ <id>Goals_Goals</id>
+ <name>Goals</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>1</id>
+ <name>1</name>
+ <order>99</order>
+ </subcategory>
+ <module>Goals</module>
+ <action>get</action>
+ <order>14</order>
+ <parameters>
+ <forceView>1</forceView>
+ <viewDataTable>sparklines</viewDataTable>
+ <module>Goals</module>
+ <action>get</action>
+ <idGoal>1</idGoal>
+ <allow_multiple>1</allow_multiple>
+ </parameters>
+ <uniqueId>widgetGoalsgetforceView1viewDataTablesparklinesidGoal1allow_multiple1</uniqueId>
+ <viewDataTable>sparklines</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Conversions Overview</name>
+ <category>
+ <id>Goals_Goals</id>
+ <name>Goals</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>1</id>
+ <name>1</name>
+ <order>99</order>
+ </subcategory>
+ <module>Goals</module>
+ <action>goalConversionsOverview</action>
+ <order>15</order>
+ <parameters>
+ <module>Goals</module>
+ <action>goalConversionsOverview</action>
+ <idGoal>1</idGoal>
+ </parameters>
+ <uniqueId>widgetGoalsgoalConversionsOverviewidGoal1</uniqueId>
+ <middlewareParameters>
+ <module>Goals</module>
+ <action>hasConversions</action>
+ <idGoal>1</idGoal>
+ </middlewareParameters>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ </widgets>
+ </row>
+ <row>
+ <name>Goal Goal 1 - Thank you conversions by type of visit</name>
+ <module>CoreHome</module>
+ <action>renderWidgetContainer</action>
+ <order>17</order>
+ <parameters>
+ <module>CoreHome</module>
+ <action>renderWidgetContainer</action>
+ <containerId>Goals1</containerId>
+ </parameters>
+ <uniqueId>widgetGoals1</uniqueId>
+ <middlewareParameters>
+ <module>Goals</module>
+ <action>hasConversions</action>
+ <idGoal>1</idGoal>
+ </middlewareParameters>
+ <layout>ByDimension</layout>
+ <isContainer>1</isContainer>
+ <widgets>
+ <row>
+ <name>Custom Variables</name>
+ <category>
+ <id>Goals by User attribute</id>
+ <name>Goals by User attribute</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Goals by User attribute</id>
+ <name>Goals by User attribute</name>
+ <order>99</order>
+ </subcategory>
+ <module>CustomVariables</module>
+ <action>getCustomVariables</action>
+ <order>301</order>
+ <parameters>
+ <viewDataTable>tableGoals</viewDataTable>
+ <module>CustomVariables</module>
+ <action>getCustomVariables</action>
+ <documentationForGoalsPage>1</documentationForGoalsPage>
+ <idGoal>1</idGoal>
+ </parameters>
+ <uniqueId>widgetCustomVariablesgetCustomVariablesviewDataTabletableGoalsdocumentationForGoalsPage1idGoal1</uniqueId>
+ <viewDataTable>tableGoals</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Visits per server time</name>
+ <category>
+ <id>Goals by User attribute</id>
+ <name>Goals by User attribute</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Goals by User attribute</id>
+ <name>Goals by User attribute</name>
+ <order>99</order>
+ </subcategory>
+ <module>VisitTime</module>
+ <action>getVisitInformationPerServerTime</action>
+ <order>302</order>
+ <parameters>
+ <viewDataTable>tableGoals</viewDataTable>
+ <module>VisitTime</module>
+ <action>getVisitInformationPerServerTime</action>
+ <documentationForGoalsPage>1</documentationForGoalsPage>
+ <idGoal>1</idGoal>
+ </parameters>
+ <uniqueId>widgetVisitTimegetVisitInformationPerServerTimeviewDataTabletableGoalsdocumentationForGoalsPage1idGoal1</uniqueId>
+ <viewDataTable>tableGoals</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Country</name>
+ <category>
+ <id>Goals by User location</id>
+ <name>Goals by User location</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Goals by User location</id>
+ <name>Goals by User location</name>
+ <order>99</order>
+ </subcategory>
+ <module>UserCountry</module>
+ <action>getCountry</action>
+ <order>201</order>
+ <parameters>
+ <viewDataTable>tableGoals</viewDataTable>
+ <module>UserCountry</module>
+ <action>getCountry</action>
+ <documentationForGoalsPage>1</documentationForGoalsPage>
+ <idGoal>1</idGoal>
+ </parameters>
+ <uniqueId>widgetUserCountrygetCountryviewDataTabletableGoalsdocumentationForGoalsPage1idGoal1</uniqueId>
+ <viewDataTable>tableGoals</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Continent</name>
+ <category>
+ <id>Goals by User location</id>
+ <name>Goals by User location</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Goals by User location</id>
+ <name>Goals by User location</name>
+ <order>99</order>
+ </subcategory>
+ <module>UserCountry</module>
+ <action>getContinent</action>
+ <order>202</order>
+ <parameters>
+ <viewDataTable>tableGoals</viewDataTable>
+ <module>UserCountry</module>
+ <action>getContinent</action>
+ <documentationForGoalsPage>1</documentationForGoalsPage>
+ <idGoal>1</idGoal>
+ </parameters>
+ <uniqueId>widgetUserCountrygetContinentviewDataTabletableGoalsdocumentationForGoalsPage1idGoal1</uniqueId>
+ <viewDataTable>tableGoals</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Region</name>
+ <category>
+ <id>Goals by User location</id>
+ <name>Goals by User location</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Goals by User location</id>
+ <name>Goals by User location</name>
+ <order>99</order>
+ </subcategory>
+ <module>UserCountry</module>
+ <action>getRegion</action>
+ <order>203</order>
+ <parameters>
+ <viewDataTable>tableGoals</viewDataTable>
+ <module>UserCountry</module>
+ <action>getRegion</action>
+ <documentationForGoalsPage>1</documentationForGoalsPage>
+ <idGoal>1</idGoal>
+ </parameters>
+ <uniqueId>widgetUserCountrygetRegionviewDataTabletableGoalsdocumentationForGoalsPage1idGoal1</uniqueId>
+ <viewDataTable>tableGoals</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>City</name>
+ <category>
+ <id>Goals by User location</id>
+ <name>Goals by User location</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Goals by User location</id>
+ <name>Goals by User location</name>
+ <order>99</order>
+ </subcategory>
+ <module>UserCountry</module>
+ <action>getCity</action>
+ <order>204</order>
+ <parameters>
+ <viewDataTable>tableGoals</viewDataTable>
+ <module>UserCountry</module>
+ <action>getCity</action>
+ <documentationForGoalsPage>1</documentationForGoalsPage>
+ <idGoal>1</idGoal>
+ </parameters>
+ <uniqueId>widgetUserCountrygetCityviewDataTabletableGoalsdocumentationForGoalsPage1idGoal1</uniqueId>
+ <viewDataTable>tableGoals</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Referrer Type</name>
+ <category>
+ <id>Goals by Referrers</id>
+ <name>Goals by Referrers</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Goals by Referrers</id>
+ <name>Goals by Referrers</name>
+ <order>99</order>
+ </subcategory>
+ <module>Referrers</module>
+ <action>getReferrerType</action>
+ <order>1</order>
+ <parameters>
+ <viewDataTable>tableGoals</viewDataTable>
+ <module>Referrers</module>
+ <action>getReferrerType</action>
+ <documentationForGoalsPage>1</documentationForGoalsPage>
+ <idGoal>1</idGoal>
+ </parameters>
+ <uniqueId>widgetReferrersgetReferrerTypeviewDataTabletableGoalsdocumentationForGoalsPage1idGoal1</uniqueId>
+ <viewDataTable>tableGoals</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Keywords</name>
+ <category>
+ <id>Goals by Referrers</id>
+ <name>Goals by Referrers</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Goals by Referrers</id>
+ <name>Goals by Referrers</name>
+ <order>99</order>
+ </subcategory>
+ <module>Referrers</module>
+ <action>getKeywords</action>
+ <order>2</order>
+ <parameters>
+ <viewDataTable>tableGoals</viewDataTable>
+ <module>Referrers</module>
+ <action>getKeywords</action>
+ <documentationForGoalsPage>1</documentationForGoalsPage>
+ <idGoal>1</idGoal>
+ </parameters>
+ <uniqueId>widgetReferrersgetKeywordsviewDataTabletableGoalsdocumentationForGoalsPage1idGoal1</uniqueId>
+ <viewDataTable>tableGoals</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Search Engines</name>
+ <category>
+ <id>Goals by Referrers</id>
+ <name>Goals by Referrers</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Goals by Referrers</id>
+ <name>Goals by Referrers</name>
+ <order>99</order>
+ </subcategory>
+ <module>Referrers</module>
+ <action>getSearchEngines</action>
+ <order>3</order>
+ <parameters>
+ <viewDataTable>tableGoals</viewDataTable>
+ <module>Referrers</module>
+ <action>getSearchEngines</action>
+ <documentationForGoalsPage>1</documentationForGoalsPage>
+ <idGoal>1</idGoal>
+ </parameters>
+ <uniqueId>widgetReferrersgetSearchEnginesviewDataTabletableGoalsdocumentationForGoalsPage1idGoal1</uniqueId>
+ <viewDataTable>tableGoals</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Websites</name>
+ <category>
+ <id>Goals by Referrers</id>
+ <name>Goals by Referrers</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Goals by Referrers</id>
+ <name>Goals by Referrers</name>
+ <order>99</order>
+ </subcategory>
+ <module>Referrers</module>
+ <action>getWebsites</action>
+ <order>4</order>
+ <parameters>
+ <viewDataTable>tableGoals</viewDataTable>
+ <module>Referrers</module>
+ <action>getWebsites</action>
+ <documentationForGoalsPage>1</documentationForGoalsPage>
+ <idGoal>1</idGoal>
+ </parameters>
+ <uniqueId>widgetReferrersgetWebsitesviewDataTabletableGoalsdocumentationForGoalsPage1idGoal1</uniqueId>
+ <viewDataTable>tableGoals</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Campaigns</name>
+ <category>
+ <id>Goals by Referrers</id>
+ <name>Goals by Referrers</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Goals by Referrers</id>
+ <name>Goals by Referrers</name>
+ <order>99</order>
+ </subcategory>
+ <module>Referrers</module>
+ <action>getCampaigns</action>
+ <order>5</order>
+ <parameters>
+ <viewDataTable>tableGoals</viewDataTable>
+ <module>Referrers</module>
+ <action>getCampaigns</action>
+ <documentationForGoalsPage>1</documentationForGoalsPage>
+ <idGoal>1</idGoal>
+ </parameters>
+ <uniqueId>widgetReferrersgetCampaignsviewDataTabletableGoalsdocumentationForGoalsPage1idGoal1</uniqueId>
+ <viewDataTable>tableGoals</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Visits to Conversion</name>
+ <category>
+ <id>Goals engagement</id>
+ <name>Goals engagement</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Goals engagement</id>
+ <name>Goals engagement</name>
+ <order>99</order>
+ </subcategory>
+ <module>Goals</module>
+ <action>getVisitsUntilConversion</action>
+ <order>101</order>
+ <parameters>
+ <module>Goals</module>
+ <action>getVisitsUntilConversion</action>
+ <documentationForGoalsPage>1</documentationForGoalsPage>
+ <idGoal>1</idGoal>
+ </parameters>
+ <uniqueId>widgetGoalsgetVisitsUntilConversiondocumentationForGoalsPage1idGoal1</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Days to Conversion</name>
+ <category>
+ <id>Goals engagement</id>
+ <name>Goals engagement</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Goals engagement</id>
+ <name>Goals engagement</name>
+ <order>99</order>
+ </subcategory>
+ <module>Goals</module>
+ <action>getDaysToConversion</action>
+ <order>102</order>
+ <parameters>
+ <module>Goals</module>
+ <action>getDaysToConversion</action>
+ <documentationForGoalsPage>1</documentationForGoalsPage>
+ <idGoal>1</idGoal>
+ </parameters>
+ <uniqueId>widgetGoalsgetDaysToConversiondocumentationForGoalsPage1idGoal1</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ </widgets>
+ </row>
+ </widgets>
+ </row>
+ <row>
+ <uniqueId>Goals_Goals.2</uniqueId>
+ <category>
+ <id>Goals_Goals</id>
+ <name>Goals</name>
+ <order>25</order>
+ <icon>icon-reporting-goal</icon>
+ </category>
+ <subcategory>
+ <id>2</id>
+ <name>Goal 2 - Hello</name>
+ <order>901</order>
+ </subcategory>
+ <widgets>
+ <row>
+ <name>Goal 2 - Hello</name>
+ <module>CoreHome</module>
+ <action>renderWidgetContainer</action>
+ <order>20</order>
+ <parameters>
+ <module>CoreHome</module>
+ <action>renderWidgetContainer</action>
+ <containerId>Goal_2</containerId>
+ </parameters>
+ <uniqueId>widgetGoal_2</uniqueId>
+ <layout />
+ <isContainer>1</isContainer>
+ <widgets>
+ <row>
+ <name />
+ <category>
+ <id>Goals_Goals</id>
+ <name>Goals</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>2</id>
+ <name>2</name>
+ <order>99</order>
+ </subcategory>
+ <module>Goals</module>
+ <action>getEvolutionGraph</action>
+ <order>18</order>
+ <parameters>
+ <forceView>1</forceView>
+ <viewDataTable>graphEvolution</viewDataTable>
+ <module>Goals</module>
+ <action>getEvolutionGraph</action>
+ <idGoal>2</idGoal>
+ </parameters>
+ <uniqueId>widgetGoalsgetEvolutionGraphforceView1viewDataTablegraphEvolutionidGoal2</uniqueId>
+ <viewDataTable>graphEvolution</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name />
+ <category>
+ <id>Goals_Goals</id>
+ <name>Goals</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>2</id>
+ <name>2</name>
+ <order>99</order>
+ </subcategory>
+ <module>Goals</module>
+ <action>get</action>
+ <order>19</order>
+ <parameters>
+ <forceView>1</forceView>
+ <viewDataTable>sparklines</viewDataTable>
+ <module>Goals</module>
+ <action>get</action>
+ <idGoal>2</idGoal>
+ <allow_multiple>0</allow_multiple>
+ </parameters>
+ <uniqueId>widgetGoalsgetforceView1viewDataTablesparklinesidGoal2allow_multiple0</uniqueId>
+ <viewDataTable>sparklines</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Conversions Overview</name>
+ <category>
+ <id>Goals_Goals</id>
+ <name>Goals</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>2</id>
+ <name>2</name>
+ <order>99</order>
+ </subcategory>
+ <module>Goals</module>
+ <action>goalConversionsOverview</action>
+ <order>20</order>
+ <parameters>
+ <module>Goals</module>
+ <action>goalConversionsOverview</action>
+ <idGoal>2</idGoal>
+ </parameters>
+ <uniqueId>widgetGoalsgoalConversionsOverviewidGoal2</uniqueId>
+ <middlewareParameters>
+ <module>Goals</module>
+ <action>hasConversions</action>
+ <idGoal>2</idGoal>
+ </middlewareParameters>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ </widgets>
+ </row>
+ <row>
+ <name>Goal Goal 2 - Hello conversions by type of visit</name>
+ <module>CoreHome</module>
+ <action>renderWidgetContainer</action>
+ <order>22</order>
+ <parameters>
+ <module>CoreHome</module>
+ <action>renderWidgetContainer</action>
+ <containerId>Goals2</containerId>
+ </parameters>
+ <uniqueId>widgetGoals2</uniqueId>
+ <middlewareParameters>
+ <module>Goals</module>
+ <action>hasConversions</action>
+ <idGoal>2</idGoal>
+ </middlewareParameters>
+ <layout>ByDimension</layout>
+ <isContainer>1</isContainer>
+ <widgets>
+ <row>
+ <name>Custom Variables</name>
+ <category>
+ <id>Goals by User attribute</id>
+ <name>Goals by User attribute</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Goals by User attribute</id>
+ <name>Goals by User attribute</name>
+ <order>99</order>
+ </subcategory>
+ <module>CustomVariables</module>
+ <action>getCustomVariables</action>
+ <order>301</order>
+ <parameters>
+ <viewDataTable>tableGoals</viewDataTable>
+ <module>CustomVariables</module>
+ <action>getCustomVariables</action>
+ <documentationForGoalsPage>1</documentationForGoalsPage>
+ <idGoal>2</idGoal>
+ </parameters>
+ <uniqueId>widgetCustomVariablesgetCustomVariablesviewDataTabletableGoalsdocumentationForGoalsPage1idGoal2</uniqueId>
+ <viewDataTable>tableGoals</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Visits per server time</name>
+ <category>
+ <id>Goals by User attribute</id>
+ <name>Goals by User attribute</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Goals by User attribute</id>
+ <name>Goals by User attribute</name>
+ <order>99</order>
+ </subcategory>
+ <module>VisitTime</module>
+ <action>getVisitInformationPerServerTime</action>
+ <order>302</order>
+ <parameters>
+ <viewDataTable>tableGoals</viewDataTable>
+ <module>VisitTime</module>
+ <action>getVisitInformationPerServerTime</action>
+ <documentationForGoalsPage>1</documentationForGoalsPage>
+ <idGoal>2</idGoal>
+ </parameters>
+ <uniqueId>widgetVisitTimegetVisitInformationPerServerTimeviewDataTabletableGoalsdocumentationForGoalsPage1idGoal2</uniqueId>
+ <viewDataTable>tableGoals</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Country</name>
+ <category>
+ <id>Goals by User location</id>
+ <name>Goals by User location</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Goals by User location</id>
+ <name>Goals by User location</name>
+ <order>99</order>
+ </subcategory>
+ <module>UserCountry</module>
+ <action>getCountry</action>
+ <order>201</order>
+ <parameters>
+ <viewDataTable>tableGoals</viewDataTable>
+ <module>UserCountry</module>
+ <action>getCountry</action>
+ <documentationForGoalsPage>1</documentationForGoalsPage>
+ <idGoal>2</idGoal>
+ </parameters>
+ <uniqueId>widgetUserCountrygetCountryviewDataTabletableGoalsdocumentationForGoalsPage1idGoal2</uniqueId>
+ <viewDataTable>tableGoals</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Continent</name>
+ <category>
+ <id>Goals by User location</id>
+ <name>Goals by User location</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Goals by User location</id>
+ <name>Goals by User location</name>
+ <order>99</order>
+ </subcategory>
+ <module>UserCountry</module>
+ <action>getContinent</action>
+ <order>202</order>
+ <parameters>
+ <viewDataTable>tableGoals</viewDataTable>
+ <module>UserCountry</module>
+ <action>getContinent</action>
+ <documentationForGoalsPage>1</documentationForGoalsPage>
+ <idGoal>2</idGoal>
+ </parameters>
+ <uniqueId>widgetUserCountrygetContinentviewDataTabletableGoalsdocumentationForGoalsPage1idGoal2</uniqueId>
+ <viewDataTable>tableGoals</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Region</name>
+ <category>
+ <id>Goals by User location</id>
+ <name>Goals by User location</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Goals by User location</id>
+ <name>Goals by User location</name>
+ <order>99</order>
+ </subcategory>
+ <module>UserCountry</module>
+ <action>getRegion</action>
+ <order>203</order>
+ <parameters>
+ <viewDataTable>tableGoals</viewDataTable>
+ <module>UserCountry</module>
+ <action>getRegion</action>
+ <documentationForGoalsPage>1</documentationForGoalsPage>
+ <idGoal>2</idGoal>
+ </parameters>
+ <uniqueId>widgetUserCountrygetRegionviewDataTabletableGoalsdocumentationForGoalsPage1idGoal2</uniqueId>
+ <viewDataTable>tableGoals</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>City</name>
+ <category>
+ <id>Goals by User location</id>
+ <name>Goals by User location</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Goals by User location</id>
+ <name>Goals by User location</name>
+ <order>99</order>
+ </subcategory>
+ <module>UserCountry</module>
+ <action>getCity</action>
+ <order>204</order>
+ <parameters>
+ <viewDataTable>tableGoals</viewDataTable>
+ <module>UserCountry</module>
+ <action>getCity</action>
+ <documentationForGoalsPage>1</documentationForGoalsPage>
+ <idGoal>2</idGoal>
+ </parameters>
+ <uniqueId>widgetUserCountrygetCityviewDataTabletableGoalsdocumentationForGoalsPage1idGoal2</uniqueId>
+ <viewDataTable>tableGoals</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Referrer Type</name>
+ <category>
+ <id>Goals by Referrers</id>
+ <name>Goals by Referrers</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Goals by Referrers</id>
+ <name>Goals by Referrers</name>
+ <order>99</order>
+ </subcategory>
+ <module>Referrers</module>
+ <action>getReferrerType</action>
+ <order>1</order>
+ <parameters>
+ <viewDataTable>tableGoals</viewDataTable>
+ <module>Referrers</module>
+ <action>getReferrerType</action>
+ <documentationForGoalsPage>1</documentationForGoalsPage>
+ <idGoal>2</idGoal>
+ </parameters>
+ <uniqueId>widgetReferrersgetReferrerTypeviewDataTabletableGoalsdocumentationForGoalsPage1idGoal2</uniqueId>
+ <viewDataTable>tableGoals</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Keywords</name>
+ <category>
+ <id>Goals by Referrers</id>
+ <name>Goals by Referrers</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Goals by Referrers</id>
+ <name>Goals by Referrers</name>
+ <order>99</order>
+ </subcategory>
+ <module>Referrers</module>
+ <action>getKeywords</action>
+ <order>2</order>
+ <parameters>
+ <viewDataTable>tableGoals</viewDataTable>
+ <module>Referrers</module>
+ <action>getKeywords</action>
+ <documentationForGoalsPage>1</documentationForGoalsPage>
+ <idGoal>2</idGoal>
+ </parameters>
+ <uniqueId>widgetReferrersgetKeywordsviewDataTabletableGoalsdocumentationForGoalsPage1idGoal2</uniqueId>
+ <viewDataTable>tableGoals</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Search Engines</name>
+ <category>
+ <id>Goals by Referrers</id>
+ <name>Goals by Referrers</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Goals by Referrers</id>
+ <name>Goals by Referrers</name>
+ <order>99</order>
+ </subcategory>
+ <module>Referrers</module>
+ <action>getSearchEngines</action>
+ <order>3</order>
+ <parameters>
+ <viewDataTable>tableGoals</viewDataTable>
+ <module>Referrers</module>
+ <action>getSearchEngines</action>
+ <documentationForGoalsPage>1</documentationForGoalsPage>
+ <idGoal>2</idGoal>
+ </parameters>
+ <uniqueId>widgetReferrersgetSearchEnginesviewDataTabletableGoalsdocumentationForGoalsPage1idGoal2</uniqueId>
+ <viewDataTable>tableGoals</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Websites</name>
+ <category>
+ <id>Goals by Referrers</id>
+ <name>Goals by Referrers</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Goals by Referrers</id>
+ <name>Goals by Referrers</name>
+ <order>99</order>
+ </subcategory>
+ <module>Referrers</module>
+ <action>getWebsites</action>
+ <order>4</order>
+ <parameters>
+ <viewDataTable>tableGoals</viewDataTable>
+ <module>Referrers</module>
+ <action>getWebsites</action>
+ <documentationForGoalsPage>1</documentationForGoalsPage>
+ <idGoal>2</idGoal>
+ </parameters>
+ <uniqueId>widgetReferrersgetWebsitesviewDataTabletableGoalsdocumentationForGoalsPage1idGoal2</uniqueId>
+ <viewDataTable>tableGoals</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Campaigns</name>
+ <category>
+ <id>Goals by Referrers</id>
+ <name>Goals by Referrers</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Goals by Referrers</id>
+ <name>Goals by Referrers</name>
+ <order>99</order>
+ </subcategory>
+ <module>Referrers</module>
+ <action>getCampaigns</action>
+ <order>5</order>
+ <parameters>
+ <viewDataTable>tableGoals</viewDataTable>
+ <module>Referrers</module>
+ <action>getCampaigns</action>
+ <documentationForGoalsPage>1</documentationForGoalsPage>
+ <idGoal>2</idGoal>
+ </parameters>
+ <uniqueId>widgetReferrersgetCampaignsviewDataTabletableGoalsdocumentationForGoalsPage1idGoal2</uniqueId>
+ <viewDataTable>tableGoals</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Visits to Conversion</name>
+ <category>
+ <id>Goals engagement</id>
+ <name>Goals engagement</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Goals engagement</id>
+ <name>Goals engagement</name>
+ <order>99</order>
+ </subcategory>
+ <module>Goals</module>
+ <action>getVisitsUntilConversion</action>
+ <order>101</order>
+ <parameters>
+ <module>Goals</module>
+ <action>getVisitsUntilConversion</action>
+ <documentationForGoalsPage>1</documentationForGoalsPage>
+ <idGoal>2</idGoal>
+ </parameters>
+ <uniqueId>widgetGoalsgetVisitsUntilConversiondocumentationForGoalsPage1idGoal2</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Days to Conversion</name>
+ <category>
+ <id>Goals engagement</id>
+ <name>Goals engagement</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Goals engagement</id>
+ <name>Goals engagement</name>
+ <order>99</order>
+ </subcategory>
+ <module>Goals</module>
+ <action>getDaysToConversion</action>
+ <order>102</order>
+ <parameters>
+ <module>Goals</module>
+ <action>getDaysToConversion</action>
+ <documentationForGoalsPage>1</documentationForGoalsPage>
+ <idGoal>2</idGoal>
+ </parameters>
+ <uniqueId>widgetGoalsgetDaysToConversiondocumentationForGoalsPage1idGoal2</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ </widgets>
+ </row>
+ </widgets>
+ </row>
+ <row>
+ <uniqueId>Goals_Goals.3</uniqueId>
+ <category>
+ <id>Goals_Goals</id>
+ <name>Goals</name>
+ <order>25</order>
+ <icon>icon-reporting-goal</icon>
+ </category>
+ <subcategory>
+ <id>3</id>
+ <name>triggered js</name>
+ <order>902</order>
+ </subcategory>
+ <widgets>
+ <row>
+ <name>triggered js</name>
+ <module>CoreHome</module>
+ <action>renderWidgetContainer</action>
+ <order>25</order>
+ <parameters>
+ <module>CoreHome</module>
+ <action>renderWidgetContainer</action>
+ <containerId>Goal_3</containerId>
+ </parameters>
+ <uniqueId>widgetGoal_3</uniqueId>
+ <layout />
+ <isContainer>1</isContainer>
+ <widgets>
+ <row>
+ <name />
+ <category>
+ <id>Goals_Goals</id>
+ <name>Goals</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>3</id>
+ <name>3</name>
+ <order>99</order>
+ </subcategory>
+ <module>Goals</module>
+ <action>getEvolutionGraph</action>
+ <order>23</order>
+ <parameters>
+ <forceView>1</forceView>
+ <viewDataTable>graphEvolution</viewDataTable>
+ <module>Goals</module>
+ <action>getEvolutionGraph</action>
+ <idGoal>3</idGoal>
+ </parameters>
+ <uniqueId>widgetGoalsgetEvolutionGraphforceView1viewDataTablegraphEvolutionidGoal3</uniqueId>
+ <viewDataTable>graphEvolution</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name />
+ <category>
+ <id>Goals_Goals</id>
+ <name>Goals</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>3</id>
+ <name>3</name>
+ <order>99</order>
+ </subcategory>
+ <module>Goals</module>
+ <action>get</action>
+ <order>24</order>
+ <parameters>
+ <forceView>1</forceView>
+ <viewDataTable>sparklines</viewDataTable>
+ <module>Goals</module>
+ <action>get</action>
+ <idGoal>3</idGoal>
+ <allow_multiple>0</allow_multiple>
+ </parameters>
+ <uniqueId>widgetGoalsgetforceView1viewDataTablesparklinesidGoal3allow_multiple0</uniqueId>
+ <viewDataTable>sparklines</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Conversions Overview</name>
+ <category>
+ <id>Goals_Goals</id>
+ <name>Goals</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>3</id>
+ <name>3</name>
+ <order>99</order>
+ </subcategory>
+ <module>Goals</module>
+ <action>goalConversionsOverview</action>
+ <order>25</order>
+ <parameters>
+ <module>Goals</module>
+ <action>goalConversionsOverview</action>
+ <idGoal>3</idGoal>
+ </parameters>
+ <uniqueId>widgetGoalsgoalConversionsOverviewidGoal3</uniqueId>
+ <middlewareParameters>
+ <module>Goals</module>
+ <action>hasConversions</action>
+ <idGoal>3</idGoal>
+ </middlewareParameters>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ </widgets>
+ </row>
+ <row>
+ <name>Goal triggered js conversions by type of visit</name>
+ <module>CoreHome</module>
+ <action>renderWidgetContainer</action>
+ <order>27</order>
+ <parameters>
+ <module>CoreHome</module>
+ <action>renderWidgetContainer</action>
+ <containerId>Goals3</containerId>
+ </parameters>
+ <uniqueId>widgetGoals3</uniqueId>
+ <middlewareParameters>
+ <module>Goals</module>
+ <action>hasConversions</action>
+ <idGoal>3</idGoal>
+ </middlewareParameters>
+ <layout>ByDimension</layout>
+ <isContainer>1</isContainer>
+ <widgets>
+ <row>
+ <name>Custom Variables</name>
+ <category>
+ <id>Goals by User attribute</id>
+ <name>Goals by User attribute</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Goals by User attribute</id>
+ <name>Goals by User attribute</name>
+ <order>99</order>
+ </subcategory>
+ <module>CustomVariables</module>
+ <action>getCustomVariables</action>
+ <order>301</order>
+ <parameters>
+ <viewDataTable>tableGoals</viewDataTable>
+ <module>CustomVariables</module>
+ <action>getCustomVariables</action>
+ <documentationForGoalsPage>1</documentationForGoalsPage>
+ <idGoal>3</idGoal>
+ </parameters>
+ <uniqueId>widgetCustomVariablesgetCustomVariablesviewDataTabletableGoalsdocumentationForGoalsPage1idGoal3</uniqueId>
+ <viewDataTable>tableGoals</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Visits per server time</name>
+ <category>
+ <id>Goals by User attribute</id>
+ <name>Goals by User attribute</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Goals by User attribute</id>
+ <name>Goals by User attribute</name>
+ <order>99</order>
+ </subcategory>
+ <module>VisitTime</module>
+ <action>getVisitInformationPerServerTime</action>
+ <order>302</order>
+ <parameters>
+ <viewDataTable>tableGoals</viewDataTable>
+ <module>VisitTime</module>
+ <action>getVisitInformationPerServerTime</action>
+ <documentationForGoalsPage>1</documentationForGoalsPage>
+ <idGoal>3</idGoal>
+ </parameters>
+ <uniqueId>widgetVisitTimegetVisitInformationPerServerTimeviewDataTabletableGoalsdocumentationForGoalsPage1idGoal3</uniqueId>
+ <viewDataTable>tableGoals</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Country</name>
+ <category>
+ <id>Goals by User location</id>
+ <name>Goals by User location</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Goals by User location</id>
+ <name>Goals by User location</name>
+ <order>99</order>
+ </subcategory>
+ <module>UserCountry</module>
+ <action>getCountry</action>
+ <order>201</order>
+ <parameters>
+ <viewDataTable>tableGoals</viewDataTable>
+ <module>UserCountry</module>
+ <action>getCountry</action>
+ <documentationForGoalsPage>1</documentationForGoalsPage>
+ <idGoal>3</idGoal>
+ </parameters>
+ <uniqueId>widgetUserCountrygetCountryviewDataTabletableGoalsdocumentationForGoalsPage1idGoal3</uniqueId>
+ <viewDataTable>tableGoals</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Continent</name>
+ <category>
+ <id>Goals by User location</id>
+ <name>Goals by User location</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Goals by User location</id>
+ <name>Goals by User location</name>
+ <order>99</order>
+ </subcategory>
+ <module>UserCountry</module>
+ <action>getContinent</action>
+ <order>202</order>
+ <parameters>
+ <viewDataTable>tableGoals</viewDataTable>
+ <module>UserCountry</module>
+ <action>getContinent</action>
+ <documentationForGoalsPage>1</documentationForGoalsPage>
+ <idGoal>3</idGoal>
+ </parameters>
+ <uniqueId>widgetUserCountrygetContinentviewDataTabletableGoalsdocumentationForGoalsPage1idGoal3</uniqueId>
+ <viewDataTable>tableGoals</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Region</name>
+ <category>
+ <id>Goals by User location</id>
+ <name>Goals by User location</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Goals by User location</id>
+ <name>Goals by User location</name>
+ <order>99</order>
+ </subcategory>
+ <module>UserCountry</module>
+ <action>getRegion</action>
+ <order>203</order>
+ <parameters>
+ <viewDataTable>tableGoals</viewDataTable>
+ <module>UserCountry</module>
+ <action>getRegion</action>
+ <documentationForGoalsPage>1</documentationForGoalsPage>
+ <idGoal>3</idGoal>
+ </parameters>
+ <uniqueId>widgetUserCountrygetRegionviewDataTabletableGoalsdocumentationForGoalsPage1idGoal3</uniqueId>
+ <viewDataTable>tableGoals</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>City</name>
+ <category>
+ <id>Goals by User location</id>
+ <name>Goals by User location</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Goals by User location</id>
+ <name>Goals by User location</name>
+ <order>99</order>
+ </subcategory>
+ <module>UserCountry</module>
+ <action>getCity</action>
+ <order>204</order>
+ <parameters>
+ <viewDataTable>tableGoals</viewDataTable>
+ <module>UserCountry</module>
+ <action>getCity</action>
+ <documentationForGoalsPage>1</documentationForGoalsPage>
+ <idGoal>3</idGoal>
+ </parameters>
+ <uniqueId>widgetUserCountrygetCityviewDataTabletableGoalsdocumentationForGoalsPage1idGoal3</uniqueId>
+ <viewDataTable>tableGoals</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Referrer Type</name>
+ <category>
+ <id>Goals by Referrers</id>
+ <name>Goals by Referrers</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Goals by Referrers</id>
+ <name>Goals by Referrers</name>
+ <order>99</order>
+ </subcategory>
+ <module>Referrers</module>
+ <action>getReferrerType</action>
+ <order>1</order>
+ <parameters>
+ <viewDataTable>tableGoals</viewDataTable>
+ <module>Referrers</module>
+ <action>getReferrerType</action>
+ <documentationForGoalsPage>1</documentationForGoalsPage>
+ <idGoal>3</idGoal>
+ </parameters>
+ <uniqueId>widgetReferrersgetReferrerTypeviewDataTabletableGoalsdocumentationForGoalsPage1idGoal3</uniqueId>
+ <viewDataTable>tableGoals</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Keywords</name>
+ <category>
+ <id>Goals by Referrers</id>
+ <name>Goals by Referrers</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Goals by Referrers</id>
+ <name>Goals by Referrers</name>
+ <order>99</order>
+ </subcategory>
+ <module>Referrers</module>
+ <action>getKeywords</action>
+ <order>2</order>
+ <parameters>
+ <viewDataTable>tableGoals</viewDataTable>
+ <module>Referrers</module>
+ <action>getKeywords</action>
+ <documentationForGoalsPage>1</documentationForGoalsPage>
+ <idGoal>3</idGoal>
+ </parameters>
+ <uniqueId>widgetReferrersgetKeywordsviewDataTabletableGoalsdocumentationForGoalsPage1idGoal3</uniqueId>
+ <viewDataTable>tableGoals</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Search Engines</name>
+ <category>
+ <id>Goals by Referrers</id>
+ <name>Goals by Referrers</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Goals by Referrers</id>
+ <name>Goals by Referrers</name>
+ <order>99</order>
+ </subcategory>
+ <module>Referrers</module>
+ <action>getSearchEngines</action>
+ <order>3</order>
+ <parameters>
+ <viewDataTable>tableGoals</viewDataTable>
+ <module>Referrers</module>
+ <action>getSearchEngines</action>
+ <documentationForGoalsPage>1</documentationForGoalsPage>
+ <idGoal>3</idGoal>
+ </parameters>
+ <uniqueId>widgetReferrersgetSearchEnginesviewDataTabletableGoalsdocumentationForGoalsPage1idGoal3</uniqueId>
+ <viewDataTable>tableGoals</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Websites</name>
+ <category>
+ <id>Goals by Referrers</id>
+ <name>Goals by Referrers</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Goals by Referrers</id>
+ <name>Goals by Referrers</name>
+ <order>99</order>
+ </subcategory>
+ <module>Referrers</module>
+ <action>getWebsites</action>
+ <order>4</order>
+ <parameters>
+ <viewDataTable>tableGoals</viewDataTable>
+ <module>Referrers</module>
+ <action>getWebsites</action>
+ <documentationForGoalsPage>1</documentationForGoalsPage>
+ <idGoal>3</idGoal>
+ </parameters>
+ <uniqueId>widgetReferrersgetWebsitesviewDataTabletableGoalsdocumentationForGoalsPage1idGoal3</uniqueId>
+ <viewDataTable>tableGoals</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Campaigns</name>
+ <category>
+ <id>Goals by Referrers</id>
+ <name>Goals by Referrers</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Goals by Referrers</id>
+ <name>Goals by Referrers</name>
+ <order>99</order>
+ </subcategory>
+ <module>Referrers</module>
+ <action>getCampaigns</action>
+ <order>5</order>
+ <parameters>
+ <viewDataTable>tableGoals</viewDataTable>
+ <module>Referrers</module>
+ <action>getCampaigns</action>
+ <documentationForGoalsPage>1</documentationForGoalsPage>
+ <idGoal>3</idGoal>
+ </parameters>
+ <uniqueId>widgetReferrersgetCampaignsviewDataTabletableGoalsdocumentationForGoalsPage1idGoal3</uniqueId>
+ <viewDataTable>tableGoals</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Visits to Conversion</name>
+ <category>
+ <id>Goals engagement</id>
+ <name>Goals engagement</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Goals engagement</id>
+ <name>Goals engagement</name>
+ <order>99</order>
+ </subcategory>
+ <module>Goals</module>
+ <action>getVisitsUntilConversion</action>
+ <order>101</order>
+ <parameters>
+ <module>Goals</module>
+ <action>getVisitsUntilConversion</action>
+ <documentationForGoalsPage>1</documentationForGoalsPage>
+ <idGoal>3</idGoal>
+ </parameters>
+ <uniqueId>widgetGoalsgetVisitsUntilConversiondocumentationForGoalsPage1idGoal3</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Days to Conversion</name>
+ <category>
+ <id>Goals engagement</id>
+ <name>Goals engagement</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Goals engagement</id>
+ <name>Goals engagement</name>
+ <order>99</order>
+ </subcategory>
+ <module>Goals</module>
+ <action>getDaysToConversion</action>
+ <order>102</order>
+ <parameters>
+ <module>Goals</module>
+ <action>getDaysToConversion</action>
+ <documentationForGoalsPage>1</documentationForGoalsPage>
+ <idGoal>3</idGoal>
+ </parameters>
+ <uniqueId>widgetGoalsgetDaysToConversiondocumentationForGoalsPage1idGoal3</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ </widgets>
+ </row>
+ </widgets>
+ </row>
+ <row>
+ <uniqueId>Goals_Goals.General_Overview</uniqueId>
+ <category>
+ <id>Goals_Goals</id>
+ <name>Goals</name>
+ <order>25</order>
+ <icon>icon-reporting-goal</icon>
+ </category>
+ <subcategory>
+ <id>General_Overview</id>
+ <name>Overview</name>
+ <order>2</order>
+ </subcategory>
+ <widgets>
+ <row>
+ <name>Overview</name>
+ <module>CoreHome</module>
+ <action>renderWidgetContainer</action>
+ <order>5</order>
+ <parameters>
+ <module>CoreHome</module>
+ <action>renderWidgetContainer</action>
+ <containerId>GoalsOverview</containerId>
+ </parameters>
+ <uniqueId>widgetGoalsOverview</uniqueId>
+ <layout />
+ <isContainer>1</isContainer>
+ <widgets>
+ <row>
+ <name />
+ <category>
+ <id>Goals_Goals</id>
+ <name>Goals</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>General_Overview</id>
+ <name>Overview</name>
+ <order>99</order>
+ </subcategory>
+ <module>Goals</module>
+ <action>getEvolutionGraph</action>
+ <order>1</order>
+ <parameters>
+ <forceView>1</forceView>
+ <viewDataTable>graphEvolution</viewDataTable>
+ <module>Goals</module>
+ <action>getEvolutionGraph</action>
+ </parameters>
+ <uniqueId>widgetGoalsgetEvolutionGraphforceView1viewDataTablegraphEvolution</uniqueId>
+ <viewDataTable>graphEvolution</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name />
+ <category>
+ <id>Goals_Goals</id>
+ <name>Goals</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>General_Overview</id>
+ <name>Overview</name>
+ <order>99</order>
+ </subcategory>
+ <module>Goals</module>
+ <action>get</action>
+ <order>2</order>
+ <parameters>
+ <forceView>1</forceView>
+ <viewDataTable>sparklines</viewDataTable>
+ <module>Goals</module>
+ <action>get</action>
+ </parameters>
+ <uniqueId>widgetGoalsgetforceView1viewDataTablesparklines</uniqueId>
+ <viewDataTable>sparklines</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Goal Goal 1 - Thank you</name>
+ <category>
+ <id>Goals_Goals</id>
+ <name>Goals</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>General_Overview</id>
+ <name>Overview</name>
+ <order>99</order>
+ </subcategory>
+ <module>Goals</module>
+ <action>get</action>
+ <order>3</order>
+ <parameters>
+ <forceView>1</forceView>
+ <viewDataTable>sparklines</viewDataTable>
+ <module>Goals</module>
+ <action>get</action>
+ <idGoal>1</idGoal>
+ <allow_multiple>1</allow_multiple>
+ <only_summary>1</only_summary>
+ </parameters>
+ <uniqueId>widgetGoalsgetforceView1viewDataTablesparklinesidGoal1allow_multiple1only_summary1</uniqueId>
+ <viewDataTable>sparklines</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Goal Goal 2 - Hello</name>
+ <category>
+ <id>Goals_Goals</id>
+ <name>Goals</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>General_Overview</id>
+ <name>Overview</name>
+ <order>99</order>
+ </subcategory>
+ <module>Goals</module>
+ <action>get</action>
+ <order>4</order>
+ <parameters>
+ <forceView>1</forceView>
+ <viewDataTable>sparklines</viewDataTable>
+ <module>Goals</module>
+ <action>get</action>
+ <idGoal>2</idGoal>
+ <allow_multiple>0</allow_multiple>
+ <only_summary>1</only_summary>
+ </parameters>
+ <uniqueId>widgetGoalsgetforceView1viewDataTablesparklinesidGoal2allow_multiple0only_summary1</uniqueId>
+ <viewDataTable>sparklines</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Goal triggered js</name>
+ <category>
+ <id>Goals_Goals</id>
+ <name>Goals</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>General_Overview</id>
+ <name>Overview</name>
+ <order>99</order>
+ </subcategory>
+ <module>Goals</module>
+ <action>get</action>
+ <order>5</order>
+ <parameters>
+ <forceView>1</forceView>
+ <viewDataTable>sparklines</viewDataTable>
+ <module>Goals</module>
+ <action>get</action>
+ <idGoal>3</idGoal>
+ <allow_multiple>0</allow_multiple>
+ <only_summary>1</only_summary>
+ </parameters>
+ <uniqueId>widgetGoalsgetforceView1viewDataTablesparklinesidGoal3allow_multiple0only_summary1</uniqueId>
+ <viewDataTable>sparklines</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ </widgets>
+ </row>
+ <row>
+ <name>Conversions overview by type of visit</name>
+ <module>CoreHome</module>
+ <action>renderWidgetContainer</action>
+ <order>7</order>
+ <parameters>
+ <module>CoreHome</module>
+ <action>renderWidgetContainer</action>
+ <containerId>Goals</containerId>
+ </parameters>
+ <uniqueId>widgetGoals</uniqueId>
+ <middlewareParameters>
+ <module>Goals</module>
+ <action>hasConversions</action>
+ </middlewareParameters>
+ <layout>ByDimension</layout>
+ <isContainer>1</isContainer>
+ <widgets>
+ <row>
+ <name>Custom Variables</name>
+ <category>
+ <id>Goals by User attribute</id>
+ <name>Goals by User attribute</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Goals by User attribute</id>
+ <name>Goals by User attribute</name>
+ <order>99</order>
+ </subcategory>
+ <module>CustomVariables</module>
+ <action>getCustomVariables</action>
+ <order>301</order>
+ <parameters>
+ <viewDataTable>tableGoals</viewDataTable>
+ <module>CustomVariables</module>
+ <action>getCustomVariables</action>
+ <documentationForGoalsPage>1</documentationForGoalsPage>
+ <idGoal>0</idGoal>
+ </parameters>
+ <uniqueId>widgetCustomVariablesgetCustomVariablesviewDataTabletableGoalsdocumentationForGoalsPage1idGoal0</uniqueId>
+ <viewDataTable>tableGoals</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Visits per server time</name>
+ <category>
+ <id>Goals by User attribute</id>
+ <name>Goals by User attribute</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Goals by User attribute</id>
+ <name>Goals by User attribute</name>
+ <order>99</order>
+ </subcategory>
+ <module>VisitTime</module>
+ <action>getVisitInformationPerServerTime</action>
+ <order>302</order>
+ <parameters>
+ <viewDataTable>tableGoals</viewDataTable>
+ <module>VisitTime</module>
+ <action>getVisitInformationPerServerTime</action>
+ <documentationForGoalsPage>1</documentationForGoalsPage>
+ <idGoal>0</idGoal>
+ </parameters>
+ <uniqueId>widgetVisitTimegetVisitInformationPerServerTimeviewDataTabletableGoalsdocumentationForGoalsPage1idGoal0</uniqueId>
+ <viewDataTable>tableGoals</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Country</name>
+ <category>
+ <id>Goals by User location</id>
+ <name>Goals by User location</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Goals by User location</id>
+ <name>Goals by User location</name>
+ <order>99</order>
+ </subcategory>
+ <module>UserCountry</module>
+ <action>getCountry</action>
+ <order>201</order>
+ <parameters>
+ <viewDataTable>tableGoals</viewDataTable>
+ <module>UserCountry</module>
+ <action>getCountry</action>
+ <documentationForGoalsPage>1</documentationForGoalsPage>
+ <idGoal>0</idGoal>
+ </parameters>
+ <uniqueId>widgetUserCountrygetCountryviewDataTabletableGoalsdocumentationForGoalsPage1idGoal0</uniqueId>
+ <viewDataTable>tableGoals</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Continent</name>
+ <category>
+ <id>Goals by User location</id>
+ <name>Goals by User location</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Goals by User location</id>
+ <name>Goals by User location</name>
+ <order>99</order>
+ </subcategory>
+ <module>UserCountry</module>
+ <action>getContinent</action>
+ <order>202</order>
+ <parameters>
+ <viewDataTable>tableGoals</viewDataTable>
+ <module>UserCountry</module>
+ <action>getContinent</action>
+ <documentationForGoalsPage>1</documentationForGoalsPage>
+ <idGoal>0</idGoal>
+ </parameters>
+ <uniqueId>widgetUserCountrygetContinentviewDataTabletableGoalsdocumentationForGoalsPage1idGoal0</uniqueId>
+ <viewDataTable>tableGoals</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Region</name>
+ <category>
+ <id>Goals by User location</id>
+ <name>Goals by User location</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Goals by User location</id>
+ <name>Goals by User location</name>
+ <order>99</order>
+ </subcategory>
+ <module>UserCountry</module>
+ <action>getRegion</action>
+ <order>203</order>
+ <parameters>
+ <viewDataTable>tableGoals</viewDataTable>
+ <module>UserCountry</module>
+ <action>getRegion</action>
+ <documentationForGoalsPage>1</documentationForGoalsPage>
+ <idGoal>0</idGoal>
+ </parameters>
+ <uniqueId>widgetUserCountrygetRegionviewDataTabletableGoalsdocumentationForGoalsPage1idGoal0</uniqueId>
+ <viewDataTable>tableGoals</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>City</name>
+ <category>
+ <id>Goals by User location</id>
+ <name>Goals by User location</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Goals by User location</id>
+ <name>Goals by User location</name>
+ <order>99</order>
+ </subcategory>
+ <module>UserCountry</module>
+ <action>getCity</action>
+ <order>204</order>
+ <parameters>
+ <viewDataTable>tableGoals</viewDataTable>
+ <module>UserCountry</module>
+ <action>getCity</action>
+ <documentationForGoalsPage>1</documentationForGoalsPage>
+ <idGoal>0</idGoal>
+ </parameters>
+ <uniqueId>widgetUserCountrygetCityviewDataTabletableGoalsdocumentationForGoalsPage1idGoal0</uniqueId>
+ <viewDataTable>tableGoals</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Referrer Type</name>
+ <category>
+ <id>Goals by Referrers</id>
+ <name>Goals by Referrers</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Goals by Referrers</id>
+ <name>Goals by Referrers</name>
+ <order>99</order>
+ </subcategory>
+ <module>Referrers</module>
+ <action>getReferrerType</action>
+ <order>1</order>
+ <parameters>
+ <viewDataTable>tableGoals</viewDataTable>
+ <module>Referrers</module>
+ <action>getReferrerType</action>
+ <documentationForGoalsPage>1</documentationForGoalsPage>
+ <idGoal>0</idGoal>
+ </parameters>
+ <uniqueId>widgetReferrersgetReferrerTypeviewDataTabletableGoalsdocumentationForGoalsPage1idGoal0</uniqueId>
+ <viewDataTable>tableGoals</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Keywords</name>
+ <category>
+ <id>Goals by Referrers</id>
+ <name>Goals by Referrers</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Goals by Referrers</id>
+ <name>Goals by Referrers</name>
+ <order>99</order>
+ </subcategory>
+ <module>Referrers</module>
+ <action>getKeywords</action>
+ <order>2</order>
+ <parameters>
+ <viewDataTable>tableGoals</viewDataTable>
+ <module>Referrers</module>
+ <action>getKeywords</action>
+ <documentationForGoalsPage>1</documentationForGoalsPage>
+ <idGoal>0</idGoal>
+ </parameters>
+ <uniqueId>widgetReferrersgetKeywordsviewDataTabletableGoalsdocumentationForGoalsPage1idGoal0</uniqueId>
+ <viewDataTable>tableGoals</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Search Engines</name>
+ <category>
+ <id>Goals by Referrers</id>
+ <name>Goals by Referrers</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Goals by Referrers</id>
+ <name>Goals by Referrers</name>
+ <order>99</order>
+ </subcategory>
+ <module>Referrers</module>
+ <action>getSearchEngines</action>
+ <order>3</order>
+ <parameters>
+ <viewDataTable>tableGoals</viewDataTable>
+ <module>Referrers</module>
+ <action>getSearchEngines</action>
+ <documentationForGoalsPage>1</documentationForGoalsPage>
+ <idGoal>0</idGoal>
+ </parameters>
+ <uniqueId>widgetReferrersgetSearchEnginesviewDataTabletableGoalsdocumentationForGoalsPage1idGoal0</uniqueId>
+ <viewDataTable>tableGoals</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Websites</name>
+ <category>
+ <id>Goals by Referrers</id>
+ <name>Goals by Referrers</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Goals by Referrers</id>
+ <name>Goals by Referrers</name>
+ <order>99</order>
+ </subcategory>
+ <module>Referrers</module>
+ <action>getWebsites</action>
+ <order>4</order>
+ <parameters>
+ <viewDataTable>tableGoals</viewDataTable>
+ <module>Referrers</module>
+ <action>getWebsites</action>
+ <documentationForGoalsPage>1</documentationForGoalsPage>
+ <idGoal>0</idGoal>
+ </parameters>
+ <uniqueId>widgetReferrersgetWebsitesviewDataTabletableGoalsdocumentationForGoalsPage1idGoal0</uniqueId>
+ <viewDataTable>tableGoals</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Campaigns</name>
+ <category>
+ <id>Goals by Referrers</id>
+ <name>Goals by Referrers</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Goals by Referrers</id>
+ <name>Goals by Referrers</name>
+ <order>99</order>
+ </subcategory>
+ <module>Referrers</module>
+ <action>getCampaigns</action>
+ <order>5</order>
+ <parameters>
+ <viewDataTable>tableGoals</viewDataTable>
+ <module>Referrers</module>
+ <action>getCampaigns</action>
+ <documentationForGoalsPage>1</documentationForGoalsPage>
+ <idGoal>0</idGoal>
+ </parameters>
+ <uniqueId>widgetReferrersgetCampaignsviewDataTabletableGoalsdocumentationForGoalsPage1idGoal0</uniqueId>
+ <viewDataTable>tableGoals</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Visits to Conversion</name>
+ <category>
+ <id>Goals engagement</id>
+ <name>Goals engagement</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Goals engagement</id>
+ <name>Goals engagement</name>
+ <order>99</order>
+ </subcategory>
+ <module>Goals</module>
+ <action>getVisitsUntilConversion</action>
+ <order>101</order>
+ <parameters>
+ <module>Goals</module>
+ <action>getVisitsUntilConversion</action>
+ <documentationForGoalsPage>1</documentationForGoalsPage>
+ <idGoal>0</idGoal>
+ </parameters>
+ <uniqueId>widgetGoalsgetVisitsUntilConversiondocumentationForGoalsPage1idGoal0</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Days to Conversion</name>
+ <category>
+ <id>Goals engagement</id>
+ <name>Goals engagement</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Goals engagement</id>
+ <name>Goals engagement</name>
+ <order>99</order>
+ </subcategory>
+ <module>Goals</module>
+ <action>getDaysToConversion</action>
+ <order>102</order>
+ <parameters>
+ <module>Goals</module>
+ <action>getDaysToConversion</action>
+ <documentationForGoalsPage>1</documentationForGoalsPage>
+ <idGoal>0</idGoal>
+ </parameters>
+ <uniqueId>widgetGoalsgetDaysToConversiondocumentationForGoalsPage1idGoal0</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ </widgets>
+ </row>
+ </widgets>
+ </row>
+ <row>
+ <uniqueId>Goals_Goals.Goals_ManageGoals</uniqueId>
+ <category>
+ <id>Goals_Goals</id>
+ <name>Goals</name>
+ <order>25</order>
+ <icon>icon-reporting-goal</icon>
+ </category>
+ <subcategory>
+ <id>Goals_ManageGoals</id>
+ <name>Manage Goals</name>
+ <order>9999</order>
+ </subcategory>
+ <widgets>
+ <row>
+ <name>Manage Goals</name>
+ <module>Goals</module>
+ <action>editGoals</action>
+ <order>99</order>
+ <parameters>
+ <module>Goals</module>
+ <action>editGoals</action>
+ </parameters>
+ <uniqueId>widgetGoalseditGoals</uniqueId>
+ </row>
+ </widgets>
+ </row>
+ <row>
+ <uniqueId>Goals_Ecommerce.Goals_EcommerceLog</uniqueId>
+ <category>
+ <id>Goals_Ecommerce</id>
+ <name>Ecommerce</name>
+ <order>20</order>
+ <icon>icon-reporting-ecommerce</icon>
+ </category>
+ <subcategory>
+ <id>Goals_EcommerceLog</id>
+ <name>Ecommerce Log</name>
+ <order>5</order>
+ </subcategory>
+ <widgets>
+ <row>
+ <name>Ecommerce Log</name>
+ <module>Ecommerce</module>
+ <action>getEcommerceLog</action>
+ <order>99</order>
+ <parameters>
+ <module>Ecommerce</module>
+ <action>getEcommerceLog</action>
+ </parameters>
+ <uniqueId>widgetEcommercegetEcommerceLog</uniqueId>
+ </row>
+ </widgets>
+ </row>
+ <row>
+ <uniqueId>Goals_Ecommerce.General_Overview</uniqueId>
+ <category>
+ <id>Goals_Ecommerce</id>
+ <name>Ecommerce</name>
+ <order>20</order>
+ <icon>icon-reporting-ecommerce</icon>
+ </category>
+ <subcategory>
+ <id>General_Overview</id>
+ <name>Overview</name>
+ <order>2</order>
+ </subcategory>
+ <widgets>
+ <row>
+ <name>Overview</name>
+ <module>CoreHome</module>
+ <action>renderWidgetContainer</action>
+ <order>10</order>
+ <parameters>
+ <module>CoreHome</module>
+ <action>renderWidgetContainer</action>
+ <containerId>EcommerceOverview</containerId>
+ </parameters>
+ <uniqueId>widgetEcommerceOverview</uniqueId>
+ <layout />
+ <isContainer>1</isContainer>
+ <widgets>
+ <row>
+ <name />
+ <category>
+ <id>Goals_Ecommerce</id>
+ <name>Ecommerce</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>General_Overview</id>
+ <name>Overview</name>
+ <order>99</order>
+ </subcategory>
+ <module>Goals</module>
+ <action>getEvolutionGraph</action>
+ <order>8</order>
+ <parameters>
+ <forceView>1</forceView>
+ <viewDataTable>graphEvolution</viewDataTable>
+ <module>Goals</module>
+ <action>getEvolutionGraph</action>
+ <idGoal>ecommerceOrder</idGoal>
+ </parameters>
+ <uniqueId>widgetGoalsgetEvolutionGraphforceView1viewDataTablegraphEvolutionidGoalecommerceOrder</uniqueId>
+ <viewDataTable>graphEvolution</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name />
+ <category>
+ <id>Goals_Ecommerce</id>
+ <name>Ecommerce</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>General_Overview</id>
+ <name>Overview</name>
+ <order>99</order>
+ </subcategory>
+ <module>Ecommerce</module>
+ <action>getSparklines</action>
+ <order>9</order>
+ <parameters>
+ <forceView>1</forceView>
+ <viewDataTable>sparklines</viewDataTable>
+ <module>Ecommerce</module>
+ <action>getSparklines</action>
+ <idGoal>ecommerceOrder</idGoal>
+ </parameters>
+ <uniqueId>widgetEcommercegetSparklinesforceView1viewDataTablesparklinesidGoalecommerceOrder</uniqueId>
+ <viewDataTable>sparklines</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Conversions Overview</name>
+ <category>
+ <id>Goals_Goals</id>
+ <name>Goals</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>ecommerceOrder</id>
+ <name>ecommerceOrder</name>
+ <order>99</order>
+ </subcategory>
+ <module>Ecommerce</module>
+ <action>getConversionsOverview</action>
+ <order>10</order>
+ <parameters>
+ <module>Ecommerce</module>
+ <action>getConversionsOverview</action>
+ <idGoal>ecommerceOrder</idGoal>
+ </parameters>
+ <uniqueId>widgetEcommercegetConversionsOverviewidGoalecommerceOrder</uniqueId>
+ <middlewareParameters>
+ <module>Goals</module>
+ <action>hasConversions</action>
+ <idGoal>ecommerceOrder</idGoal>
+ </middlewareParameters>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ </widgets>
+ </row>
+ </widgets>
+ </row>
+ <row>
+ <uniqueId>Goals_Ecommerce.Goals_Products</uniqueId>
+ <category>
+ <id>Goals_Ecommerce</id>
+ <name>Ecommerce</name>
+ <order>20</order>
+ <icon>icon-reporting-ecommerce</icon>
+ </category>
+ <subcategory>
+ <id>Goals_Products</id>
+ <name>Products</name>
+ <order>10</order>
+ </subcategory>
+ <widgets>
+ <row>
+ <name />
+ <module>CoreHome</module>
+ <action>renderWidgetContainer</action>
+ <order>99</order>
+ <parameters>
+ <module>CoreHome</module>
+ <action>renderWidgetContainer</action>
+ <containerId>Products</containerId>
+ </parameters>
+ <uniqueId>widgetProducts</uniqueId>
+ <layout>ByDimension</layout>
+ <isContainer>1</isContainer>
+ <widgets>
+ <row>
+ <name>Product SKU</name>
+ <category>
+ <id>Goals_Ecommerce</id>
+ <name>Ecommerce</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Goals_Products</id>
+ <name>Products</name>
+ <order>99</order>
+ </subcategory>
+ <module>Goals</module>
+ <action>getItemsSku</action>
+ <order>130</order>
+ <parameters>
+ <module>Goals</module>
+ <action>getItemsSku</action>
+ </parameters>
+ <uniqueId>widgetGoalsgetItemsSku</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Product Name</name>
+ <category>
+ <id>Goals_Ecommerce</id>
+ <name>Ecommerce</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Goals_Products</id>
+ <name>Products</name>
+ <order>99</order>
+ </subcategory>
+ <module>Goals</module>
+ <action>getItemsName</action>
+ <order>131</order>
+ <parameters>
+ <module>Goals</module>
+ <action>getItemsName</action>
+ </parameters>
+ <uniqueId>widgetGoalsgetItemsName</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Product Category</name>
+ <category>
+ <id>Goals_Ecommerce</id>
+ <name>Ecommerce</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Goals_Products</id>
+ <name>Products</name>
+ <order>99</order>
+ </subcategory>
+ <module>Goals</module>
+ <action>getItemsCategory</action>
+ <order>132</order>
+ <parameters>
+ <module>Goals</module>
+ <action>getItemsCategory</action>
+ </parameters>
+ <uniqueId>widgetGoalsgetItemsCategory</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ </widgets>
+ </row>
+ </widgets>
+ </row>
+ <row>
+ <uniqueId>Goals_Ecommerce.Ecommerce_Sales</uniqueId>
+ <category>
+ <id>Goals_Ecommerce</id>
+ <name>Ecommerce</name>
+ <order>20</order>
+ <icon>icon-reporting-ecommerce</icon>
+ </category>
+ <subcategory>
+ <id>Ecommerce_Sales</id>
+ <name>Sales</name>
+ <order>15</order>
+ </subcategory>
+ <widgets>
+ <row>
+ <name />
+ <module>CoreHome</module>
+ <action>renderWidgetContainer</action>
+ <order>12</order>
+ <parameters>
+ <module>CoreHome</module>
+ <action>renderWidgetContainer</action>
+ <idGoal>ecommerceOrder</idGoal>
+ <containerId>GoalsOrder</containerId>
+ </parameters>
+ <uniqueId>widgetGoalsOrderidGoalecommerceOrder</uniqueId>
+ <layout>ByDimension</layout>
+ <isContainer>1</isContainer>
+ <widgets>
+ <row>
+ <name>Custom Variables</name>
+ <category>
+ <id>Sales by User attribute</id>
+ <name>Sales by User attribute</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Sales by User attribute</id>
+ <name>Sales by User attribute</name>
+ <order>99</order>
+ </subcategory>
+ <module>CustomVariables</module>
+ <action>getCustomVariables</action>
+ <order>301</order>
+ <parameters>
+ <viewDataTable>tableGoals</viewDataTable>
+ <module>CustomVariables</module>
+ <action>getCustomVariables</action>
+ <documentationForGoalsPage>1</documentationForGoalsPage>
+ <idGoal>ecommerceOrder</idGoal>
+ </parameters>
+ <uniqueId>widgetCustomVariablesgetCustomVariablesviewDataTabletableGoalsdocumentationForGoalsPage1idGoalecommerceOrder</uniqueId>
+ <viewDataTable>tableGoals</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Visits per server time</name>
+ <category>
+ <id>Sales by User attribute</id>
+ <name>Sales by User attribute</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Sales by User attribute</id>
+ <name>Sales by User attribute</name>
+ <order>99</order>
+ </subcategory>
+ <module>VisitTime</module>
+ <action>getVisitInformationPerServerTime</action>
+ <order>302</order>
+ <parameters>
+ <viewDataTable>tableGoals</viewDataTable>
+ <module>VisitTime</module>
+ <action>getVisitInformationPerServerTime</action>
+ <documentationForGoalsPage>1</documentationForGoalsPage>
+ <idGoal>ecommerceOrder</idGoal>
+ </parameters>
+ <uniqueId>widgetVisitTimegetVisitInformationPerServerTimeviewDataTabletableGoalsdocumentationForGoalsPage1idGoalecommerceOrder</uniqueId>
+ <viewDataTable>tableGoals</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Country</name>
+ <category>
+ <id>Sales by User location</id>
+ <name>Sales by User location</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Sales by User location</id>
+ <name>Sales by User location</name>
+ <order>99</order>
+ </subcategory>
+ <module>UserCountry</module>
+ <action>getCountry</action>
+ <order>201</order>
+ <parameters>
+ <viewDataTable>tableGoals</viewDataTable>
+ <module>UserCountry</module>
+ <action>getCountry</action>
+ <documentationForGoalsPage>1</documentationForGoalsPage>
+ <idGoal>ecommerceOrder</idGoal>
+ </parameters>
+ <uniqueId>widgetUserCountrygetCountryviewDataTabletableGoalsdocumentationForGoalsPage1idGoalecommerceOrder</uniqueId>
+ <viewDataTable>tableGoals</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Continent</name>
+ <category>
+ <id>Sales by User location</id>
+ <name>Sales by User location</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Sales by User location</id>
+ <name>Sales by User location</name>
+ <order>99</order>
+ </subcategory>
+ <module>UserCountry</module>
+ <action>getContinent</action>
+ <order>202</order>
+ <parameters>
+ <viewDataTable>tableGoals</viewDataTable>
+ <module>UserCountry</module>
+ <action>getContinent</action>
+ <documentationForGoalsPage>1</documentationForGoalsPage>
+ <idGoal>ecommerceOrder</idGoal>
+ </parameters>
+ <uniqueId>widgetUserCountrygetContinentviewDataTabletableGoalsdocumentationForGoalsPage1idGoalecommerceOrder</uniqueId>
+ <viewDataTable>tableGoals</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Region</name>
+ <category>
+ <id>Sales by User location</id>
+ <name>Sales by User location</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Sales by User location</id>
+ <name>Sales by User location</name>
+ <order>99</order>
+ </subcategory>
+ <module>UserCountry</module>
+ <action>getRegion</action>
+ <order>203</order>
+ <parameters>
+ <viewDataTable>tableGoals</viewDataTable>
+ <module>UserCountry</module>
+ <action>getRegion</action>
+ <documentationForGoalsPage>1</documentationForGoalsPage>
+ <idGoal>ecommerceOrder</idGoal>
+ </parameters>
+ <uniqueId>widgetUserCountrygetRegionviewDataTabletableGoalsdocumentationForGoalsPage1idGoalecommerceOrder</uniqueId>
+ <viewDataTable>tableGoals</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>City</name>
+ <category>
+ <id>Sales by User location</id>
+ <name>Sales by User location</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Sales by User location</id>
+ <name>Sales by User location</name>
+ <order>99</order>
+ </subcategory>
+ <module>UserCountry</module>
+ <action>getCity</action>
+ <order>204</order>
+ <parameters>
+ <viewDataTable>tableGoals</viewDataTable>
+ <module>UserCountry</module>
+ <action>getCity</action>
+ <documentationForGoalsPage>1</documentationForGoalsPage>
+ <idGoal>ecommerceOrder</idGoal>
+ </parameters>
+ <uniqueId>widgetUserCountrygetCityviewDataTabletableGoalsdocumentationForGoalsPage1idGoalecommerceOrder</uniqueId>
+ <viewDataTable>tableGoals</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Referrer Type</name>
+ <category>
+ <id>Sales by Referrers</id>
+ <name>Sales by Referrers</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Sales by Referrers</id>
+ <name>Sales by Referrers</name>
+ <order>99</order>
+ </subcategory>
+ <module>Referrers</module>
+ <action>getReferrerType</action>
+ <order>1</order>
+ <parameters>
+ <viewDataTable>tableGoals</viewDataTable>
+ <module>Referrers</module>
+ <action>getReferrerType</action>
+ <documentationForGoalsPage>1</documentationForGoalsPage>
+ <idGoal>ecommerceOrder</idGoal>
+ </parameters>
+ <uniqueId>widgetReferrersgetReferrerTypeviewDataTabletableGoalsdocumentationForGoalsPage1idGoalecommerceOrder</uniqueId>
+ <viewDataTable>tableGoals</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Keywords</name>
+ <category>
+ <id>Sales by Referrers</id>
+ <name>Sales by Referrers</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Sales by Referrers</id>
+ <name>Sales by Referrers</name>
+ <order>99</order>
+ </subcategory>
+ <module>Referrers</module>
+ <action>getKeywords</action>
+ <order>2</order>
+ <parameters>
+ <viewDataTable>tableGoals</viewDataTable>
+ <module>Referrers</module>
+ <action>getKeywords</action>
+ <documentationForGoalsPage>1</documentationForGoalsPage>
+ <idGoal>ecommerceOrder</idGoal>
+ </parameters>
+ <uniqueId>widgetReferrersgetKeywordsviewDataTabletableGoalsdocumentationForGoalsPage1idGoalecommerceOrder</uniqueId>
+ <viewDataTable>tableGoals</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Search Engines</name>
+ <category>
+ <id>Sales by Referrers</id>
+ <name>Sales by Referrers</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Sales by Referrers</id>
+ <name>Sales by Referrers</name>
+ <order>99</order>
+ </subcategory>
+ <module>Referrers</module>
+ <action>getSearchEngines</action>
+ <order>3</order>
+ <parameters>
+ <viewDataTable>tableGoals</viewDataTable>
+ <module>Referrers</module>
+ <action>getSearchEngines</action>
+ <documentationForGoalsPage>1</documentationForGoalsPage>
+ <idGoal>ecommerceOrder</idGoal>
+ </parameters>
+ <uniqueId>widgetReferrersgetSearchEnginesviewDataTabletableGoalsdocumentationForGoalsPage1idGoalecommerceOrder</uniqueId>
+ <viewDataTable>tableGoals</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Websites</name>
+ <category>
+ <id>Sales by Referrers</id>
+ <name>Sales by Referrers</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Sales by Referrers</id>
+ <name>Sales by Referrers</name>
+ <order>99</order>
+ </subcategory>
+ <module>Referrers</module>
+ <action>getWebsites</action>
+ <order>4</order>
+ <parameters>
+ <viewDataTable>tableGoals</viewDataTable>
+ <module>Referrers</module>
+ <action>getWebsites</action>
+ <documentationForGoalsPage>1</documentationForGoalsPage>
+ <idGoal>ecommerceOrder</idGoal>
+ </parameters>
+ <uniqueId>widgetReferrersgetWebsitesviewDataTabletableGoalsdocumentationForGoalsPage1idGoalecommerceOrder</uniqueId>
+ <viewDataTable>tableGoals</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Campaigns</name>
+ <category>
+ <id>Sales by Referrers</id>
+ <name>Sales by Referrers</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Sales by Referrers</id>
+ <name>Sales by Referrers</name>
+ <order>99</order>
+ </subcategory>
+ <module>Referrers</module>
+ <action>getCampaigns</action>
+ <order>5</order>
+ <parameters>
+ <viewDataTable>tableGoals</viewDataTable>
+ <module>Referrers</module>
+ <action>getCampaigns</action>
+ <documentationForGoalsPage>1</documentationForGoalsPage>
+ <idGoal>ecommerceOrder</idGoal>
+ </parameters>
+ <uniqueId>widgetReferrersgetCampaignsviewDataTabletableGoalsdocumentationForGoalsPage1idGoalecommerceOrder</uniqueId>
+ <viewDataTable>tableGoals</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Visits to Conversion</name>
+ <category>
+ <id>Sales engagement</id>
+ <name>Sales engagement</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Sales engagement</id>
+ <name>Sales engagement</name>
+ <order>99</order>
+ </subcategory>
+ <module>Goals</module>
+ <action>getVisitsUntilConversion</action>
+ <order>101</order>
+ <parameters>
+ <module>Goals</module>
+ <action>getVisitsUntilConversion</action>
+ <documentationForGoalsPage>1</documentationForGoalsPage>
+ <idGoal>ecommerceOrder</idGoal>
+ </parameters>
+ <uniqueId>widgetGoalsgetVisitsUntilConversiondocumentationForGoalsPage1idGoalecommerceOrder</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Days to Conversion</name>
+ <category>
+ <id>Sales engagement</id>
+ <name>Sales engagement</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Sales engagement</id>
+ <name>Sales engagement</name>
+ <order>99</order>
+ </subcategory>
+ <module>Goals</module>
+ <action>getDaysToConversion</action>
+ <order>102</order>
+ <parameters>
+ <module>Goals</module>
+ <action>getDaysToConversion</action>
+ <documentationForGoalsPage>1</documentationForGoalsPage>
+ <idGoal>ecommerceOrder</idGoal>
+ </parameters>
+ <uniqueId>widgetGoalsgetDaysToConversiondocumentationForGoalsPage1idGoalecommerceOrder</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ </widgets>
+ </row>
+ </widgets>
+ </row>
+ <row>
+ <uniqueId>ExampleUI_UiFramework.ExampleUI_GetTemperaturesDataTable</uniqueId>
+ <category>
+ <id>ExampleUI_UiFramework</id>
+ <name>UI Framework</name>
+ <order>90</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>ExampleUI_GetTemperaturesDataTable</id>
+ <name>Data tables</name>
+ <order>99</order>
+ </subcategory>
+ <widgets>
+ <row>
+ <name>Data tables</name>
+ <module>ExampleUI</module>
+ <action>getTemperatures</action>
+ <order>210</order>
+ <parameters>
+ <module>ExampleUI</module>
+ <action>getTemperatures</action>
+ </parameters>
+ <uniqueId>widgetExampleUIgetTemperatures</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ </widgets>
+ </row>
+ <row>
+ <uniqueId>ExampleUI_UiFramework.Bar graph</uniqueId>
+ <category>
+ <id>ExampleUI_UiFramework</id>
+ <name>UI Framework</name>
+ <order>90</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Bar graph</id>
+ <name>Bar graph</name>
+ <order>99</order>
+ </subcategory>
+ <widgets>
+ <row>
+ <name>Data tables</name>
+ <module>ExampleUI</module>
+ <action>getTemperatures</action>
+ <order>210</order>
+ <parameters>
+ <forceView>1</forceView>
+ <viewDataTable>graphVerticalBar</viewDataTable>
+ <module>ExampleUI</module>
+ <action>getTemperatures</action>
+ </parameters>
+ <uniqueId>widgetExampleUIgetTemperaturesforceView1viewDataTablegraphVerticalBar</uniqueId>
+ <viewDataTable>graphVerticalBar</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ </widgets>
+ </row>
+ <row>
+ <uniqueId>ExampleUI_UiFramework.Treemap</uniqueId>
+ <category>
+ <id>ExampleUI_UiFramework</id>
+ <name>UI Framework</name>
+ <order>90</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Treemap</id>
+ <name>Treemap</name>
+ <order>99</order>
+ </subcategory>
+ <widgets>
+ <row>
+ <name>Treemap example</name>
+ <module>ExampleUI</module>
+ <action>getTemperatures</action>
+ <order>210</order>
+ <parameters>
+ <forceView>1</forceView>
+ <viewDataTable>infoviz-treemap</viewDataTable>
+ <module>ExampleUI</module>
+ <action>getTemperatures</action>
+ </parameters>
+ <uniqueId>widgetExampleUIgetTemperaturesforceView1viewDataTableinfoviz-treemap</uniqueId>
+ <viewDataTable>infoviz-treemap</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ </widgets>
+ </row>
+ <row>
+ <uniqueId>ExampleUI_UiFramework.Sparklines</uniqueId>
+ <category>
+ <id>ExampleUI_UiFramework</id>
+ <name>UI Framework</name>
+ <order>90</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Sparklines</id>
+ <name>Sparklines</name>
+ <order>99</order>
+ </subcategory>
+ <widgets>
+ <row>
+ <name>Temperatures evolution over time</name>
+ <module>ExampleUI</module>
+ <action>getTemperaturesEvolution</action>
+ <order>211</order>
+ <parameters>
+ <forceView>1</forceView>
+ <viewDataTable>sparklines</viewDataTable>
+ <module>ExampleUI</module>
+ <action>getTemperaturesEvolution</action>
+ </parameters>
+ <uniqueId>widgetExampleUIgetTemperaturesEvolutionforceView1viewDataTablesparklines</uniqueId>
+ <viewDataTable>sparklines</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ </widgets>
+ </row>
+ <row>
+ <uniqueId>ExampleUI_UiFramework.Evolution Graph</uniqueId>
+ <category>
+ <id>ExampleUI_UiFramework</id>
+ <name>UI Framework</name>
+ <order>90</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Evolution Graph</id>
+ <name>Evolution Graph</name>
+ <order>99</order>
+ </subcategory>
+ <widgets>
+ <row>
+ <name>Evolution of server temperatures over the last few days</name>
+ <module>ExampleUI</module>
+ <action>getTemperaturesEvolution</action>
+ <order>211</order>
+ <parameters>
+ <forceView>1</forceView>
+ <viewDataTable>graphEvolution</viewDataTable>
+ <module>ExampleUI</module>
+ <action>getTemperaturesEvolution</action>
+ <columns>
+ <row>server1</row>
+ <row>server2</row>
+ </columns>
+ </parameters>
+ <uniqueId>widgetExampleUIgetTemperaturesEvolutionforceView1viewDataTablegraphEvolutioncolumnsArray</uniqueId>
+ <viewDataTable>graphEvolution</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ </widgets>
+ </row>
+ <row>
+ <uniqueId>ExampleUI_UiFramework.Pie graph</uniqueId>
+ <category>
+ <id>ExampleUI_UiFramework</id>
+ <name>UI Framework</name>
+ <order>90</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Pie graph</id>
+ <name>Pie graph</name>
+ <order>99</order>
+ </subcategory>
+ <widgets>
+ <row>
+ <name>Pie graph</name>
+ <module>ExampleUI</module>
+ <action>getPlanetRatios</action>
+ <order>212</order>
+ <parameters>
+ <viewDataTable>graphPie</viewDataTable>
+ <module>ExampleUI</module>
+ <action>getPlanetRatios</action>
+ </parameters>
+ <uniqueId>widgetExampleUIgetPlanetRatiosviewDataTablegraphPie</uniqueId>
+ <viewDataTable>graphPie</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ </widgets>
+ </row>
+ <row>
+ <uniqueId>ExampleUI_UiFramework.Tag clouds</uniqueId>
+ <category>
+ <id>ExampleUI_UiFramework</id>
+ <name>UI Framework</name>
+ <order>90</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Tag clouds</id>
+ <name>Tag clouds</name>
+ <order>99</order>
+ </subcategory>
+ <widgets>
+ <row>
+ <name>Simple tag cloud</name>
+ <module>ExampleUI</module>
+ <action>getPlanetRatios</action>
+ <order>5</order>
+ <parameters>
+ <forceView>1</forceView>
+ <viewDataTable>cloud</viewDataTable>
+ <module>ExampleUI</module>
+ <action>getPlanetRatios</action>
+ </parameters>
+ <uniqueId>widgetExampleUIgetPlanetRatiosforceView1viewDataTablecloud</uniqueId>
+ <viewDataTable>cloud</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Advanced tag cloud: with logos and links</name>
+ <module>ExampleUI</module>
+ <action>getPlanetRatiosWithLogos</action>
+ <order>213</order>
+ <parameters>
+ <viewDataTable>cloud</viewDataTable>
+ <module>ExampleUI</module>
+ <action>getPlanetRatiosWithLogos</action>
+ </parameters>
+ <uniqueId>widgetExampleUIgetPlanetRatiosWithLogosviewDataTablecloud</uniqueId>
+ <viewDataTable>cloud</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ </widgets>
+ </row>
+</result> \ No newline at end of file
diff --git a/tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getSegmentsMetadata.xml b/tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getSegmentsMetadata.xml
index 0c213a04ab..0afffa1863 100644
--- a/tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getSegmentsMetadata.xml
+++ b/tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getSegmentsMetadata.xml
@@ -59,6 +59,14 @@
<permission>1</permission>
</row>
<row>
+ <type>metric</type>
+ <category>Visit</category>
+ <name>Visitor IP</name>
+ <segment>visitIp</segment>
+ <acceptedValues>13.54.122.1. &lt;/code&gt;Select IP ranges with notation: &lt;code&gt;visitIp&gt;13.54.122.0;visitIp&lt;13.54.122.255</acceptedValues>
+ <permission>1</permission>
+ </row>
+ <row>
<type>dimension</type>
<category>Visit Location</category>
<name>City</name>
@@ -189,6 +197,14 @@
<row>
<type>dimension</type>
<category>Visit</category>
+ <name>User ID</name>
+ <segment>userId</segment>
+ <acceptedValues>any non empty unique string identifying the user (such as an email address or a username).</acceptedValues>
+ <permission>1</permission>
+ </row>
+ <row>
+ <type>dimension</type>
+ <category>Visit</category>
<name>Visit Ecommerce status at the end of the visit</name>
<segment>visitEcommerceStatus</segment>
<acceptedValues>none, ordered, abandonedCart, orderedThenAbandonedCart. For example, to select all visits that have made an Ecommerce order, the API request would contain &quot;&amp;segment=visitEcommerceStatus==ordered,visitEcommerceStatus==orderedThenAbandonedCart&quot;</acceptedValues>
@@ -204,6 +220,14 @@
<row>
<type>dimension</type>
<category>Visit</category>
+ <name>Visit ID</name>
+ <segment>visitId</segment>
+ <acceptedValues>Any integer.</acceptedValues>
+ <permission>1</permission>
+ </row>
+ <row>
+ <type>dimension</type>
+ <category>Visit</category>
<name>Visit converted a specific Goal Id</name>
<segment>visitConvertedGoalId</segment>
<acceptedValues>1, 2, 3, etc.</acceptedValues>
@@ -232,6 +256,14 @@
</row>
<row>
<type>dimension</type>
+ <category>Visit</category>
+ <name>Visitor ID</name>
+ <segment>visitorId</segment>
+ <acceptedValues>34c31e04394bdc63 - any 16 Hexadecimal chars ID, which can be fetched using the Tracking API function getVisitorId()</acceptedValues>
+ <permission>1</permission>
+ </row>
+ <row>
+ <type>dimension</type>
<category>Referrers</category>
<name>Keyword</name>
<segment>referrerKeyword</segment>
diff --git a/tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getWidgetMetadata.xml b/tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getWidgetMetadata.xml
new file mode 100644
index 0000000000..f6499f1062
--- /dev/null
+++ b/tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getWidgetMetadata.xml
@@ -0,0 +1,2821 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<result>
+ <row>
+ <name>Visitors in Real-time</name>
+ <category>
+ <id>Live!</id>
+ <name>Live!</name>
+ <order>2</order>
+ <icon />
+ </category>
+ <subcategory />
+ <module>Live</module>
+ <action>widget</action>
+ <order>20</order>
+ <parameters>
+ <module>Live</module>
+ <action>widget</action>
+ </parameters>
+ <uniqueId>widgetLivewidget</uniqueId>
+ </row>
+ <row>
+ <name>Real Time Visitor Count</name>
+ <category>
+ <id>Live!</id>
+ <name>Live!</name>
+ <order>2</order>
+ <icon />
+ </category>
+ <subcategory />
+ <module>Live</module>
+ <action>getSimpleLastVisitCount</action>
+ <order>15</order>
+ <parameters>
+ <module>Live</module>
+ <action>getSimpleLastVisitCount</action>
+ </parameters>
+ <uniqueId>widgetLivegetSimpleLastVisitCount</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Visits Overview</name>
+ <category>
+ <id>General_Visitors</id>
+ <name>Visitors</name>
+ <order>5</order>
+ <icon>icon-reporting-visitors</icon>
+ </category>
+ <subcategory>
+ <id>General_Overview</id>
+ <name>Overview</name>
+ <order>2</order>
+ </subcategory>
+ <module>VisitsSummary</module>
+ <action>get</action>
+ <order>10</order>
+ <parameters>
+ <forceView>1</forceView>
+ <viewDataTable>sparklines</viewDataTable>
+ <module>VisitsSummary</module>
+ <action>get</action>
+ </parameters>
+ <uniqueId>widgetVisitsSummarygetforceView1viewDataTablesparklines</uniqueId>
+ <viewDataTable>sparklines</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Visits Over Time</name>
+ <category>
+ <id>General_Visitors</id>
+ <name>Visitors</name>
+ <order>5</order>
+ <icon>icon-reporting-visitors</icon>
+ </category>
+ <subcategory>
+ <id>General_Overview</id>
+ <name>Overview</name>
+ <order>2</order>
+ </subcategory>
+ <module>VisitsSummary</module>
+ <action>getEvolutionGraph</action>
+ <order>5</order>
+ <parameters>
+ <forceView>1</forceView>
+ <viewDataTable>graphEvolution</viewDataTable>
+ <module>VisitsSummary</module>
+ <action>getEvolutionGraph</action>
+ </parameters>
+ <uniqueId>widgetVisitsSummarygetEvolutionGraphforceView1viewDataTablegraphEvolution</uniqueId>
+ <viewDataTable>graphEvolution</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Visitor Log</name>
+ <category>
+ <id>General_Visitors</id>
+ <name>Visitors</name>
+ <order>5</order>
+ <icon>icon-reporting-visitors</icon>
+ </category>
+ <subcategory>
+ <id>Live_VisitorLog</id>
+ <name>Visitor Log</name>
+ <order>5</order>
+ </subcategory>
+ <module>Live</module>
+ <action>getLastVisitsDetails</action>
+ <order>10</order>
+ <parameters>
+ <forceView>1</forceView>
+ <viewDataTable>VisitorLog</viewDataTable>
+ <module>Live</module>
+ <action>getLastVisitsDetails</action>
+ <small>1</small>
+ </parameters>
+ <uniqueId>widgetLivegetLastVisitsDetailsforceView1viewDataTableVisitorLogsmall1</uniqueId>
+ <viewDataTable>VisitorLog</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Custom Variables</name>
+ <category>
+ <id>General_Visitors</id>
+ <name>Visitors</name>
+ <order>5</order>
+ <icon>icon-reporting-visitors</icon>
+ </category>
+ <subcategory>
+ <id>CustomVariables_CustomVariables</id>
+ <name>Custom Variables</name>
+ <order>10</order>
+ </subcategory>
+ <module>CustomVariables</module>
+ <action>getCustomVariables</action>
+ <order>110</order>
+ <parameters>
+ <module>CustomVariables</module>
+ <action>getCustomVariables</action>
+ </parameters>
+ <uniqueId>widgetCustomVariablesgetCustomVariables</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Device model</name>
+ <category>
+ <id>General_Visitors</id>
+ <name>Visitors</name>
+ <order>5</order>
+ <icon>icon-reporting-visitors</icon>
+ </category>
+ <subcategory>
+ <id>DevicesDetection_Devices</id>
+ <name>Devices</name>
+ <order>15</order>
+ </subcategory>
+ <module>DevicesDetection</module>
+ <action>getModel</action>
+ <order>102</order>
+ <parameters>
+ <module>DevicesDetection</module>
+ <action>getModel</action>
+ </parameters>
+ <uniqueId>widgetDevicesDetectiongetModel</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Device type</name>
+ <category>
+ <id>General_Visitors</id>
+ <name>Visitors</name>
+ <order>5</order>
+ <icon>icon-reporting-visitors</icon>
+ </category>
+ <subcategory>
+ <id>DevicesDetection_Devices</id>
+ <name>Devices</name>
+ <order>15</order>
+ </subcategory>
+ <module>DevicesDetection</module>
+ <action>getType</action>
+ <order>100</order>
+ <parameters>
+ <module>DevicesDetection</module>
+ <action>getType</action>
+ </parameters>
+ <uniqueId>widgetDevicesDetectiongetType</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Device brand</name>
+ <category>
+ <id>General_Visitors</id>
+ <name>Visitors</name>
+ <order>5</order>
+ <icon>icon-reporting-visitors</icon>
+ </category>
+ <subcategory>
+ <id>DevicesDetection_Devices</id>
+ <name>Devices</name>
+ <order>15</order>
+ </subcategory>
+ <module>DevicesDetection</module>
+ <action>getBrand</action>
+ <order>104</order>
+ <parameters>
+ <module>DevicesDetection</module>
+ <action>getBrand</action>
+ </parameters>
+ <uniqueId>widgetDevicesDetectiongetBrand</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Screen Resolution</name>
+ <category>
+ <id>General_Visitors</id>
+ <name>Visitors</name>
+ <order>5</order>
+ <icon>icon-reporting-visitors</icon>
+ </category>
+ <subcategory>
+ <id>DevicesDetection_Devices</id>
+ <name>Devices</name>
+ <order>15</order>
+ </subcategory>
+ <module>Resolution</module>
+ <action>getResolution</action>
+ <order>108</order>
+ <parameters>
+ <module>Resolution</module>
+ <action>getResolution</action>
+ </parameters>
+ <uniqueId>widgetResolutiongetResolution</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Browser version</name>
+ <category>
+ <id>General_Visitors</id>
+ <name>Visitors</name>
+ <order>5</order>
+ <icon>icon-reporting-visitors</icon>
+ </category>
+ <subcategory>
+ <id>DevicesDetection_Software</id>
+ <name>Software</name>
+ <order>20</order>
+ </subcategory>
+ <module>DevicesDetection</module>
+ <action>getBrowserVersions</action>
+ <order>106</order>
+ <parameters>
+ <module>DevicesDetection</module>
+ <action>getBrowserVersions</action>
+ </parameters>
+ <uniqueId>widgetDevicesDetectiongetBrowserVersions</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Configurations</name>
+ <category>
+ <id>General_Visitors</id>
+ <name>Visitors</name>
+ <order>5</order>
+ <icon>icon-reporting-visitors</icon>
+ </category>
+ <subcategory>
+ <id>DevicesDetection_Software</id>
+ <name>Software</name>
+ <order>20</order>
+ </subcategory>
+ <module>Resolution</module>
+ <action>getConfiguration</action>
+ <order>107</order>
+ <parameters>
+ <module>Resolution</module>
+ <action>getConfiguration</action>
+ </parameters>
+ <uniqueId>widgetResolutiongetConfiguration</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Browsers</name>
+ <category>
+ <id>General_Visitors</id>
+ <name>Visitors</name>
+ <order>5</order>
+ <icon>icon-reporting-visitors</icon>
+ </category>
+ <subcategory>
+ <id>DevicesDetection_Software</id>
+ <name>Software</name>
+ <order>20</order>
+ </subcategory>
+ <module>DevicesDetection</module>
+ <action>getBrowsers</action>
+ <order>105</order>
+ <parameters>
+ <module>DevicesDetection</module>
+ <action>getBrowsers</action>
+ </parameters>
+ <uniqueId>widgetDevicesDetectiongetBrowsers</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Operating System versions</name>
+ <category>
+ <id>General_Visitors</id>
+ <name>Visitors</name>
+ <order>5</order>
+ <icon>icon-reporting-visitors</icon>
+ </category>
+ <subcategory>
+ <id>DevicesDetection_Software</id>
+ <name>Software</name>
+ <order>20</order>
+ </subcategory>
+ <module>DevicesDetection</module>
+ <action>getOsVersions</action>
+ <order>102</order>
+ <parameters>
+ <module>DevicesDetection</module>
+ <action>getOsVersions</action>
+ </parameters>
+ <uniqueId>widgetDevicesDetectiongetOsVersions</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Operating System families</name>
+ <category>
+ <id>General_Visitors</id>
+ <name>Visitors</name>
+ <order>5</order>
+ <icon>icon-reporting-visitors</icon>
+ </category>
+ <subcategory>
+ <id>DevicesDetection_Software</id>
+ <name>Software</name>
+ <order>20</order>
+ </subcategory>
+ <module>DevicesDetection</module>
+ <action>getOsFamilies</action>
+ <order>108</order>
+ <parameters>
+ <module>DevicesDetection</module>
+ <action>getOsFamilies</action>
+ </parameters>
+ <uniqueId>widgetDevicesDetectiongetOsFamilies</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Visits Overview (with graph)</name>
+ <category>
+ <id>General_Visitors</id>
+ <name>Visitors</name>
+ <order>5</order>
+ <icon>icon-reporting-visitors</icon>
+ </category>
+ <subcategory />
+ <module>CoreHome</module>
+ <action>renderWidgetContainer</action>
+ <order>99</order>
+ <parameters>
+ <module>CoreHome</module>
+ <action>renderWidgetContainer</action>
+ <containerId>VisitOverviewWithGraph</containerId>
+ </parameters>
+ <uniqueId>widgetVisitOverviewWithGraph</uniqueId>
+ <layout />
+ <isContainer>1</isContainer>
+ <widgets>
+ <row>
+ <name>Visits Over Time</name>
+ <category>
+ <id>General_Visitors</id>
+ <name>Visitors</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>General_Overview</id>
+ <name>Overview</name>
+ <order>99</order>
+ </subcategory>
+ <module>VisitsSummary</module>
+ <action>getEvolutionGraph</action>
+ <order>5</order>
+ <parameters>
+ <forceView>1</forceView>
+ <viewDataTable>graphEvolution</viewDataTable>
+ <module>VisitsSummary</module>
+ <action>getEvolutionGraph</action>
+ </parameters>
+ <uniqueId>widgetVisitsSummarygetEvolutionGraphforceView1viewDataTablegraphEvolution</uniqueId>
+ <viewDataTable>graphEvolution</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Visits Overview</name>
+ <category>
+ <id>General_Visitors</id>
+ <name>Visitors</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>General_Overview</id>
+ <name>Overview</name>
+ <order>99</order>
+ </subcategory>
+ <module>VisitsSummary</module>
+ <action>get</action>
+ <order>10</order>
+ <parameters>
+ <forceView>1</forceView>
+ <viewDataTable>sparklines</viewDataTable>
+ <module>VisitsSummary</module>
+ <action>get</action>
+ </parameters>
+ <uniqueId>widgetVisitsSummarygetforceView1viewDataTablesparklines</uniqueId>
+ <viewDataTable>sparklines</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ </widgets>
+ </row>
+ <row>
+ <name>Browser engines</name>
+ <category>
+ <id>General_Visitors</id>
+ <name>Visitors</name>
+ <order>5</order>
+ <icon>icon-reporting-visitors</icon>
+ </category>
+ <subcategory>
+ <id>DevicesDetection_Software</id>
+ <name>Software</name>
+ <order>20</order>
+ </subcategory>
+ <module>DevicesDetection</module>
+ <action>getBrowserEngines</action>
+ <order>110</order>
+ <parameters>
+ <viewDataTable>graphPie</viewDataTable>
+ <module>DevicesDetection</module>
+ <action>getBrowserEngines</action>
+ </parameters>
+ <uniqueId>widgetDevicesDetectiongetBrowserEnginesviewDataTablegraphPie</uniqueId>
+ <viewDataTable>graphPie</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Browser Plugins</name>
+ <category>
+ <id>General_Visitors</id>
+ <name>Visitors</name>
+ <order>5</order>
+ <icon>icon-reporting-visitors</icon>
+ </category>
+ <subcategory>
+ <id>DevicesDetection_Software</id>
+ <name>Software</name>
+ <order>20</order>
+ </subcategory>
+ <module>DevicePlugins</module>
+ <action>getPlugin</action>
+ <order>113</order>
+ <parameters>
+ <module>DevicePlugins</module>
+ <action>getPlugin</action>
+ </parameters>
+ <uniqueId>widgetDevicePluginsgetPlugin</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Visitor Map</name>
+ <category>
+ <id>General_Visitors</id>
+ <name>Visitors</name>
+ <order>5</order>
+ <icon>icon-reporting-visitors</icon>
+ </category>
+ <subcategory>
+ <id>UserCountry_SubmenuLocations</id>
+ <name>Locations</name>
+ <order>25</order>
+ </subcategory>
+ <module>UserCountryMap</module>
+ <action>visitorMap</action>
+ <order>1</order>
+ <parameters>
+ <module>UserCountryMap</module>
+ <action>visitorMap</action>
+ </parameters>
+ <uniqueId>widgetUserCountryMapvisitorMap</uniqueId>
+ </row>
+ <row>
+ <name>City</name>
+ <category>
+ <id>General_Visitors</id>
+ <name>Visitors</name>
+ <order>5</order>
+ <icon>icon-reporting-visitors</icon>
+ </category>
+ <subcategory>
+ <id>UserCountry_SubmenuLocations</id>
+ <name>Locations</name>
+ <order>25</order>
+ </subcategory>
+ <module>UserCountry</module>
+ <action>getCity</action>
+ <order>110</order>
+ <parameters>
+ <module>UserCountry</module>
+ <action>getCity</action>
+ </parameters>
+ <uniqueId>widgetUserCountrygetCity</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Browser language</name>
+ <category>
+ <id>General_Visitors</id>
+ <name>Visitors</name>
+ <order>5</order>
+ <icon>icon-reporting-visitors</icon>
+ </category>
+ <subcategory>
+ <id>UserCountry_SubmenuLocations</id>
+ <name>Locations</name>
+ <order>25</order>
+ </subcategory>
+ <module>UserLanguage</module>
+ <action>getLanguage</action>
+ <order>108</order>
+ <parameters>
+ <module>UserLanguage</module>
+ <action>getLanguage</action>
+ </parameters>
+ <uniqueId>widgetUserLanguagegetLanguage</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Region</name>
+ <category>
+ <id>General_Visitors</id>
+ <name>Visitors</name>
+ <order>5</order>
+ <icon>icon-reporting-visitors</icon>
+ </category>
+ <subcategory>
+ <id>UserCountry_SubmenuLocations</id>
+ <name>Locations</name>
+ <order>25</order>
+ </subcategory>
+ <module>UserCountry</module>
+ <action>getRegion</action>
+ <order>107</order>
+ <parameters>
+ <module>UserCountry</module>
+ <action>getRegion</action>
+ </parameters>
+ <uniqueId>widgetUserCountrygetRegion</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Continent</name>
+ <category>
+ <id>General_Visitors</id>
+ <name>Visitors</name>
+ <order>5</order>
+ <icon>icon-reporting-visitors</icon>
+ </category>
+ <subcategory>
+ <id>UserCountry_SubmenuLocations</id>
+ <name>Locations</name>
+ <order>25</order>
+ </subcategory>
+ <module>UserCountry</module>
+ <action>getContinent</action>
+ <order>106</order>
+ <parameters>
+ <module>UserCountry</module>
+ <action>getContinent</action>
+ </parameters>
+ <uniqueId>widgetUserCountrygetContinent</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Country</name>
+ <category>
+ <id>General_Visitors</id>
+ <name>Visitors</name>
+ <order>5</order>
+ <icon>icon-reporting-visitors</icon>
+ </category>
+ <subcategory>
+ <id>UserCountry_SubmenuLocations</id>
+ <name>Locations</name>
+ <order>25</order>
+ </subcategory>
+ <module>UserCountry</module>
+ <action>getCountry</action>
+ <order>105</order>
+ <parameters>
+ <module>UserCountry</module>
+ <action>getCountry</action>
+ </parameters>
+ <uniqueId>widgetUserCountrygetCountry</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Language code</name>
+ <category>
+ <id>General_Visitors</id>
+ <name>Visitors</name>
+ <order>5</order>
+ <icon>icon-reporting-visitors</icon>
+ </category>
+ <subcategory>
+ <id>UserCountry_SubmenuLocations</id>
+ <name>Locations</name>
+ <order>25</order>
+ </subcategory>
+ <module>UserLanguage</module>
+ <action>getLanguageCode</action>
+ <order>111</order>
+ <parameters>
+ <module>UserLanguage</module>
+ <action>getLanguageCode</action>
+ </parameters>
+ <uniqueId>widgetUserLanguagegetLanguageCode</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Visits by Days Since Last Visit</name>
+ <category>
+ <id>General_Visitors</id>
+ <name>Visitors</name>
+ <order>5</order>
+ <icon>icon-reporting-visitors</icon>
+ </category>
+ <subcategory>
+ <id>VisitorInterest_Engagement</id>
+ <name>Engagement</name>
+ <order>30</order>
+ </subcategory>
+ <module>VisitorInterest</module>
+ <action>getNumberOfVisitsByDaysSinceLast</action>
+ <order>130</order>
+ <parameters>
+ <module>VisitorInterest</module>
+ <action>getNumberOfVisitsByDaysSinceLast</action>
+ </parameters>
+ <uniqueId>widgetVisitorInterestgetNumberOfVisitsByDaysSinceLast</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Visits per visit duration</name>
+ <category>
+ <id>General_Visitors</id>
+ <name>Visitors</name>
+ <order>5</order>
+ <icon>icon-reporting-visitors</icon>
+ </category>
+ <subcategory>
+ <id>VisitorInterest_Engagement</id>
+ <name>Engagement</name>
+ <order>30</order>
+ </subcategory>
+ <module>VisitorInterest</module>
+ <action>getNumberOfVisitsPerVisitDuration</action>
+ <order>115</order>
+ <parameters>
+ <viewDataTable>cloud</viewDataTable>
+ <module>VisitorInterest</module>
+ <action>getNumberOfVisitsPerVisitDuration</action>
+ </parameters>
+ <uniqueId>widgetVisitorInterestgetNumberOfVisitsPerVisitDurationviewDataTablecloud</uniqueId>
+ <viewDataTable>cloud</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Visits per number of pages</name>
+ <category>
+ <id>General_Visitors</id>
+ <name>Visitors</name>
+ <order>5</order>
+ <icon>icon-reporting-visitors</icon>
+ </category>
+ <subcategory>
+ <id>VisitorInterest_Engagement</id>
+ <name>Engagement</name>
+ <order>30</order>
+ </subcategory>
+ <module>VisitorInterest</module>
+ <action>getNumberOfVisitsPerPage</action>
+ <order>120</order>
+ <parameters>
+ <viewDataTable>cloud</viewDataTable>
+ <module>VisitorInterest</module>
+ <action>getNumberOfVisitsPerPage</action>
+ </parameters>
+ <uniqueId>widgetVisitorInterestgetNumberOfVisitsPerPageviewDataTablecloud</uniqueId>
+ <viewDataTable>cloud</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Returning Visits Over Time</name>
+ <category>
+ <id>General_Visitors</id>
+ <name>Visitors</name>
+ <order>5</order>
+ <icon>icon-reporting-visitors</icon>
+ </category>
+ <subcategory>
+ <id>VisitorInterest_Engagement</id>
+ <name>Engagement</name>
+ <order>30</order>
+ </subcategory>
+ <module>VisitFrequency</module>
+ <action>getEvolutionGraph</action>
+ <order>1</order>
+ <parameters>
+ <forceView>1</forceView>
+ <viewDataTable>graphEvolution</viewDataTable>
+ <module>VisitFrequency</module>
+ <action>getEvolutionGraph</action>
+ </parameters>
+ <uniqueId>widgetVisitFrequencygetEvolutionGraphforceView1viewDataTablegraphEvolution</uniqueId>
+ <viewDataTable>graphEvolution</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Visitor profile</name>
+ <category>
+ <id>General_Visitors</id>
+ <name>Visitors</name>
+ <order>5</order>
+ <icon>icon-reporting-visitors</icon>
+ </category>
+ <subcategory />
+ <module>Live</module>
+ <action>getVisitorProfilePopup</action>
+ <order>25</order>
+ <parameters>
+ <module>Live</module>
+ <action>getVisitorProfilePopup</action>
+ </parameters>
+ <uniqueId>widgetLivegetVisitorProfilePopup</uniqueId>
+ </row>
+ <row>
+ <name>Frequency Overview</name>
+ <category>
+ <id>General_Visitors</id>
+ <name>Visitors</name>
+ <order>5</order>
+ <icon>icon-reporting-visitors</icon>
+ </category>
+ <subcategory>
+ <id>VisitorInterest_Engagement</id>
+ <name>Engagement</name>
+ <order>30</order>
+ </subcategory>
+ <module>VisitFrequency</module>
+ <action>get</action>
+ <order>2</order>
+ <parameters>
+ <forceView>1</forceView>
+ <viewDataTable>sparklines</viewDataTable>
+ <module>VisitFrequency</module>
+ <action>get</action>
+ </parameters>
+ <uniqueId>widgetVisitFrequencygetforceView1viewDataTablesparklines</uniqueId>
+ <viewDataTable>sparklines</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Visits by Visit Number</name>
+ <category>
+ <id>General_Visitors</id>
+ <name>Visitors</name>
+ <order>5</order>
+ <icon>icon-reporting-visitors</icon>
+ </category>
+ <subcategory>
+ <id>VisitorInterest_Engagement</id>
+ <name>Engagement</name>
+ <order>30</order>
+ </subcategory>
+ <module>VisitorInterest</module>
+ <action>getNumberOfVisitsByVisitCount</action>
+ <order>125</order>
+ <parameters>
+ <module>VisitorInterest</module>
+ <action>getNumberOfVisitsByVisitCount</action>
+ </parameters>
+ <uniqueId>widgetVisitorInterestgetNumberOfVisitsByVisitCount</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Visits per local time</name>
+ <category>
+ <id>General_Visitors</id>
+ <name>Visitors</name>
+ <order>5</order>
+ <icon>icon-reporting-visitors</icon>
+ </category>
+ <subcategory>
+ <id>VisitTime_SubmenuTimes</id>
+ <name>Times</name>
+ <order>35</order>
+ </subcategory>
+ <module>VisitTime</module>
+ <action>getVisitInformationPerLocalTime</action>
+ <order>115</order>
+ <parameters>
+ <viewDataTable>graphVerticalBar</viewDataTable>
+ <module>VisitTime</module>
+ <action>getVisitInformationPerLocalTime</action>
+ </parameters>
+ <uniqueId>widgetVisitTimegetVisitInformationPerLocalTimeviewDataTablegraphVerticalBar</uniqueId>
+ <viewDataTable>graphVerticalBar</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Visits per server time</name>
+ <category>
+ <id>General_Visitors</id>
+ <name>Visitors</name>
+ <order>5</order>
+ <icon>icon-reporting-visitors</icon>
+ </category>
+ <subcategory>
+ <id>VisitTime_SubmenuTimes</id>
+ <name>Times</name>
+ <order>35</order>
+ </subcategory>
+ <module>VisitTime</module>
+ <action>getVisitInformationPerServerTime</action>
+ <order>120</order>
+ <parameters>
+ <viewDataTable>graphVerticalBar</viewDataTable>
+ <module>VisitTime</module>
+ <action>getVisitInformationPerServerTime</action>
+ </parameters>
+ <uniqueId>widgetVisitTimegetVisitInformationPerServerTimeviewDataTablegraphVerticalBar</uniqueId>
+ <viewDataTable>graphVerticalBar</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Visits by Day of Week</name>
+ <category>
+ <id>General_Visitors</id>
+ <name>Visitors</name>
+ <order>5</order>
+ <icon>icon-reporting-visitors</icon>
+ </category>
+ <subcategory>
+ <id>VisitTime_SubmenuTimes</id>
+ <name>Times</name>
+ <order>35</order>
+ </subcategory>
+ <module>VisitTime</module>
+ <action>getByDayOfWeek</action>
+ <order>125</order>
+ <parameters>
+ <viewDataTable>graphVerticalBar</viewDataTable>
+ <module>VisitTime</module>
+ <action>getByDayOfWeek</action>
+ </parameters>
+ <uniqueId>widgetVisitTimegetByDayOfWeekviewDataTablegraphVerticalBar</uniqueId>
+ <viewDataTable>graphVerticalBar</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Real-time Map</name>
+ <category>
+ <id>General_Visitors</id>
+ <name>Visitors</name>
+ <order>5</order>
+ <icon>icon-reporting-visitors</icon>
+ </category>
+ <subcategory>
+ <id>UserCountryMap_RealTimeMap</id>
+ <name>Real-time Map</name>
+ <order>40</order>
+ </subcategory>
+ <module>UserCountryMap</module>
+ <action>realtimeMap</action>
+ <order>5</order>
+ <parameters>
+ <module>UserCountryMap</module>
+ <action>realtimeMap</action>
+ </parameters>
+ <uniqueId>widgetUserCountryMaprealtimeMap</uniqueId>
+ </row>
+ <row>
+ <name>Pages</name>
+ <category>
+ <id>General_Actions</id>
+ <name>Actions</name>
+ <order>10</order>
+ <icon>icon-reporting-actions</icon>
+ </category>
+ <subcategory>
+ <id>General_Pages</id>
+ <name>Pages</name>
+ <order>5</order>
+ </subcategory>
+ <module>Actions</module>
+ <action>getPageUrls</action>
+ <order>102</order>
+ <parameters>
+ <module>Actions</module>
+ <action>getPageUrls</action>
+ </parameters>
+ <uniqueId>widgetActionsgetPageUrls</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Entry pages</name>
+ <category>
+ <id>General_Actions</id>
+ <name>Actions</name>
+ <order>10</order>
+ <icon>icon-reporting-actions</icon>
+ </category>
+ <subcategory>
+ <id>Actions_SubmenuPagesEntry</id>
+ <name>Entry pages</name>
+ <order>10</order>
+ </subcategory>
+ <module>Actions</module>
+ <action>getEntryPageUrls</action>
+ <order>103</order>
+ <parameters>
+ <module>Actions</module>
+ <action>getEntryPageUrls</action>
+ </parameters>
+ <uniqueId>widgetActionsgetEntryPageUrls</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Exit pages</name>
+ <category>
+ <id>General_Actions</id>
+ <name>Actions</name>
+ <order>10</order>
+ <icon>icon-reporting-actions</icon>
+ </category>
+ <subcategory>
+ <id>Actions_SubmenuPagesExit</id>
+ <name>Exit pages</name>
+ <order>15</order>
+ </subcategory>
+ <module>Actions</module>
+ <action>getExitPageUrls</action>
+ <order>104</order>
+ <parameters>
+ <module>Actions</module>
+ <action>getExitPageUrls</action>
+ </parameters>
+ <uniqueId>widgetActionsgetExitPageUrls</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Page titles</name>
+ <category>
+ <id>General_Actions</id>
+ <name>Actions</name>
+ <order>10</order>
+ <icon>icon-reporting-actions</icon>
+ </category>
+ <subcategory>
+ <id>Actions_SubmenuPageTitles</id>
+ <name>Page titles</name>
+ <order>20</order>
+ </subcategory>
+ <module>Actions</module>
+ <action>getPageTitles</action>
+ <order>105</order>
+ <parameters>
+ <module>Actions</module>
+ <action>getPageTitles</action>
+ </parameters>
+ <uniqueId>widgetActionsgetPageTitles</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Search Keywords with No Results</name>
+ <category>
+ <id>General_Actions</id>
+ <name>Actions</name>
+ <order>10</order>
+ <icon>icon-reporting-actions</icon>
+ </category>
+ <subcategory>
+ <id>Actions_SubmenuSitesearch</id>
+ <name>Site Search</name>
+ <order>25</order>
+ </subcategory>
+ <module>Actions</module>
+ <action>getSiteSearchNoResultKeywords</action>
+ <order>118</order>
+ <parameters>
+ <module>Actions</module>
+ <action>getSiteSearchNoResultKeywords</action>
+ </parameters>
+ <uniqueId>widgetActionsgetSiteSearchNoResultKeywords</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Page Titles Following a Site Search</name>
+ <category>
+ <id>General_Actions</id>
+ <name>Actions</name>
+ <order>10</order>
+ <icon>icon-reporting-actions</icon>
+ </category>
+ <subcategory>
+ <id>Actions_SubmenuSitesearch</id>
+ <name>Site Search</name>
+ <order>25</order>
+ </subcategory>
+ <module>Actions</module>
+ <action>getPageTitlesFollowingSiteSearch</action>
+ <order>119</order>
+ <parameters>
+ <module>Actions</module>
+ <action>getPageTitlesFollowingSiteSearch</action>
+ </parameters>
+ <uniqueId>widgetActionsgetPageTitlesFollowingSiteSearch</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Search Categories</name>
+ <category>
+ <id>General_Actions</id>
+ <name>Actions</name>
+ <order>10</order>
+ <icon>icon-reporting-actions</icon>
+ </category>
+ <subcategory>
+ <id>Actions_SubmenuSitesearch</id>
+ <name>Site Search</name>
+ <order>25</order>
+ </subcategory>
+ <module>Actions</module>
+ <action>getSiteSearchCategories</action>
+ <order>120</order>
+ <parameters>
+ <module>Actions</module>
+ <action>getSiteSearchCategories</action>
+ </parameters>
+ <uniqueId>widgetActionsgetSiteSearchCategories</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Pages Following a Site Search</name>
+ <category>
+ <id>General_Actions</id>
+ <name>Actions</name>
+ <order>10</order>
+ <icon>icon-reporting-actions</icon>
+ </category>
+ <subcategory>
+ <id>Actions_SubmenuSitesearch</id>
+ <name>Site Search</name>
+ <order>25</order>
+ </subcategory>
+ <module>Actions</module>
+ <action>getPageUrlsFollowingSiteSearch</action>
+ <order>116</order>
+ <parameters>
+ <module>Actions</module>
+ <action>getPageUrlsFollowingSiteSearch</action>
+ </parameters>
+ <uniqueId>widgetActionsgetPageUrlsFollowingSiteSearch</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Site Search Keywords</name>
+ <category>
+ <id>General_Actions</id>
+ <name>Actions</name>
+ <order>10</order>
+ <icon>icon-reporting-actions</icon>
+ </category>
+ <subcategory>
+ <id>Actions_SubmenuSitesearch</id>
+ <name>Site Search</name>
+ <order>25</order>
+ </subcategory>
+ <module>Actions</module>
+ <action>getSiteSearchKeywords</action>
+ <order>115</order>
+ <parameters>
+ <module>Actions</module>
+ <action>getSiteSearchKeywords</action>
+ </parameters>
+ <uniqueId>widgetActionsgetSiteSearchKeywords</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Entry Page Titles</name>
+ <category>
+ <id>General_Actions</id>
+ <name>Actions</name>
+ <order>10</order>
+ <icon>icon-reporting-actions</icon>
+ </category>
+ <subcategory />
+ <module>Actions</module>
+ <action>getEntryPageTitles</action>
+ <order>106</order>
+ <parameters>
+ <module>Actions</module>
+ <action>getEntryPageTitles</action>
+ </parameters>
+ <uniqueId>widgetActionsgetEntryPageTitles</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Outlinks</name>
+ <category>
+ <id>General_Actions</id>
+ <name>Actions</name>
+ <order>10</order>
+ <icon>icon-reporting-actions</icon>
+ </category>
+ <subcategory>
+ <id>General_Outlinks</id>
+ <name>Outlinks</name>
+ <order>30</order>
+ </subcategory>
+ <module>Actions</module>
+ <action>getOutlinks</action>
+ <order>108</order>
+ <parameters>
+ <module>Actions</module>
+ <action>getOutlinks</action>
+ </parameters>
+ <uniqueId>widgetActionsgetOutlinks</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Downloads</name>
+ <category>
+ <id>General_Actions</id>
+ <name>Actions</name>
+ <order>10</order>
+ <icon>icon-reporting-actions</icon>
+ </category>
+ <subcategory>
+ <id>General_Downloads</id>
+ <name>Downloads</name>
+ <order>35</order>
+ </subcategory>
+ <module>Actions</module>
+ <action>getDownloads</action>
+ <order>109</order>
+ <parameters>
+ <module>Actions</module>
+ <action>getDownloads</action>
+ </parameters>
+ <uniqueId>widgetActionsgetDownloads</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Event Categories</name>
+ <category>
+ <id>General_Actions</id>
+ <name>Actions</name>
+ <order>10</order>
+ <icon>icon-reporting-actions</icon>
+ </category>
+ <subcategory>
+ <id>Events_Events</id>
+ <name>Events</name>
+ <order>40</order>
+ </subcategory>
+ <module>Events</module>
+ <action>getCategory</action>
+ <order>100</order>
+ <parameters>
+ <module>Events</module>
+ <action>getCategory</action>
+ <secondaryDimension>eventAction</secondaryDimension>
+ </parameters>
+ <uniqueId>widgetEventsgetCategorysecondaryDimensioneventAction</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Event Actions</name>
+ <category>
+ <id>General_Actions</id>
+ <name>Actions</name>
+ <order>10</order>
+ <icon>icon-reporting-actions</icon>
+ </category>
+ <subcategory>
+ <id>Events_Events</id>
+ <name>Events</name>
+ <order>40</order>
+ </subcategory>
+ <module>Events</module>
+ <action>getAction</action>
+ <order>101</order>
+ <parameters>
+ <module>Events</module>
+ <action>getAction</action>
+ <secondaryDimension>eventName</secondaryDimension>
+ </parameters>
+ <uniqueId>widgetEventsgetActionsecondaryDimensioneventName</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Event Categories</name>
+ <category>
+ <id>General_Actions</id>
+ <name>Actions</name>
+ <order>10</order>
+ <icon>icon-reporting-actions</icon>
+ </category>
+ <subcategory>
+ <id>Events_Events</id>
+ <name>Events</name>
+ <order>40</order>
+ </subcategory>
+ <module>Events</module>
+ <action>getCategory</action>
+ <order>100</order>
+ <parameters>
+ <module>Events</module>
+ <action>getCategory</action>
+ <secondaryDimension>eventAction</secondaryDimension>
+ </parameters>
+ <uniqueId>widgetEventsgetCategorysecondaryDimensioneventAction</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Event Actions</name>
+ <category>
+ <id>General_Actions</id>
+ <name>Actions</name>
+ <order>10</order>
+ <icon>icon-reporting-actions</icon>
+ </category>
+ <subcategory>
+ <id>Events_Events</id>
+ <name>Events</name>
+ <order>40</order>
+ </subcategory>
+ <module>Events</module>
+ <action>getAction</action>
+ <order>101</order>
+ <parameters>
+ <module>Events</module>
+ <action>getAction</action>
+ <secondaryDimension>eventName</secondaryDimension>
+ </parameters>
+ <uniqueId>widgetEventsgetActionsecondaryDimensioneventName</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Event Names</name>
+ <category>
+ <id>General_Actions</id>
+ <name>Actions</name>
+ <order>10</order>
+ <icon>icon-reporting-actions</icon>
+ </category>
+ <subcategory>
+ <id>Events_Events</id>
+ <name>Events</name>
+ <order>40</order>
+ </subcategory>
+ <module>Events</module>
+ <action>getName</action>
+ <order>102</order>
+ <parameters>
+ <module>Events</module>
+ <action>getName</action>
+ <secondaryDimension>eventAction</secondaryDimension>
+ </parameters>
+ <uniqueId>widgetEventsgetNamesecondaryDimensioneventAction</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Event Names</name>
+ <category>
+ <id>General_Actions</id>
+ <name>Actions</name>
+ <order>10</order>
+ <icon>icon-reporting-actions</icon>
+ </category>
+ <subcategory>
+ <id>Events_Events</id>
+ <name>Events</name>
+ <order>40</order>
+ </subcategory>
+ <module>Events</module>
+ <action>getName</action>
+ <order>102</order>
+ <parameters>
+ <module>Events</module>
+ <action>getName</action>
+ <secondaryDimension>eventAction</secondaryDimension>
+ </parameters>
+ <uniqueId>widgetEventsgetNamesecondaryDimensioneventAction</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Content Piece</name>
+ <category>
+ <id>General_Actions</id>
+ <name>Actions</name>
+ <order>10</order>
+ <icon>icon-reporting-actions</icon>
+ </category>
+ <subcategory>
+ <id>Contents_Contents</id>
+ <name>Contents</name>
+ <order>45</order>
+ </subcategory>
+ <module>Contents</module>
+ <action>getContentPieces</action>
+ <order>136</order>
+ <parameters>
+ <module>Contents</module>
+ <action>getContentPieces</action>
+ </parameters>
+ <uniqueId>widgetContentsgetContentPieces</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Exit page titles</name>
+ <category>
+ <id>General_Actions</id>
+ <name>Actions</name>
+ <order>10</order>
+ <icon>icon-reporting-actions</icon>
+ </category>
+ <subcategory />
+ <module>Actions</module>
+ <action>getExitPageTitles</action>
+ <order>107</order>
+ <parameters>
+ <module>Actions</module>
+ <action>getExitPageTitles</action>
+ </parameters>
+ <uniqueId>widgetActionsgetExitPageTitles</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Content Name</name>
+ <category>
+ <id>General_Actions</id>
+ <name>Actions</name>
+ <order>10</order>
+ <icon>icon-reporting-actions</icon>
+ </category>
+ <subcategory>
+ <id>Contents_Contents</id>
+ <name>Contents</name>
+ <order>45</order>
+ </subcategory>
+ <module>Contents</module>
+ <action>getContentNames</action>
+ <order>135</order>
+ <parameters>
+ <module>Contents</module>
+ <action>getContentNames</action>
+ </parameters>
+ <uniqueId>widgetContentsgetContentNames</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Content Name</name>
+ <category>
+ <id>General_Actions</id>
+ <name>Actions</name>
+ <order>10</order>
+ <icon>icon-reporting-actions</icon>
+ </category>
+ <subcategory>
+ <id>Contents_Contents</id>
+ <name>Contents</name>
+ <order>45</order>
+ </subcategory>
+ <module>Contents</module>
+ <action>getContentNames</action>
+ <order>135</order>
+ <parameters>
+ <module>Contents</module>
+ <action>getContentNames</action>
+ </parameters>
+ <uniqueId>widgetContentsgetContentNames</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Content Piece</name>
+ <category>
+ <id>General_Actions</id>
+ <name>Actions</name>
+ <order>10</order>
+ <icon>icon-reporting-actions</icon>
+ </category>
+ <subcategory>
+ <id>Contents_Contents</id>
+ <name>Contents</name>
+ <order>45</order>
+ </subcategory>
+ <module>Contents</module>
+ <action>getContentPieces</action>
+ <order>136</order>
+ <parameters>
+ <module>Contents</module>
+ <action>getContentPieces</action>
+ </parameters>
+ <uniqueId>widgetContentsgetContentPieces</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Referrer Types</name>
+ <category>
+ <id>Referrers_Referrers</id>
+ <name>Referrers</name>
+ <order>15</order>
+ <icon>icon-reporting-referer</icon>
+ </category>
+ <subcategory>
+ <id>Referrers_WidgetGetAll</id>
+ <name>All Referrers</name>
+ <order>5</order>
+ </subcategory>
+ <module>Referrers</module>
+ <action>getReferrerType</action>
+ <order>101</order>
+ <parameters>
+ <viewDataTable>tableAllColumns</viewDataTable>
+ <module>Referrers</module>
+ <action>getReferrerType</action>
+ </parameters>
+ <uniqueId>widgetReferrersgetReferrerTypeviewDataTabletableAllColumns</uniqueId>
+ <viewDataTable>tableAllColumns</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Referrers</name>
+ <category>
+ <id>Referrers_Referrers</id>
+ <name>Referrers</name>
+ <order>15</order>
+ <icon>icon-reporting-referer</icon>
+ </category>
+ <subcategory>
+ <id>Referrers_WidgetGetAll</id>
+ <name>All Referrers</name>
+ <order>5</order>
+ </subcategory>
+ <module>Referrers</module>
+ <action>getAll</action>
+ <order>102</order>
+ <parameters>
+ <viewDataTable>tableAllColumns</viewDataTable>
+ <module>Referrers</module>
+ <action>getAll</action>
+ </parameters>
+ <uniqueId>widgetReferrersgetAllviewDataTabletableAllColumns</uniqueId>
+ <viewDataTable>tableAllColumns</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Keywords</name>
+ <category>
+ <id>Referrers_Referrers</id>
+ <name>Referrers</name>
+ <order>15</order>
+ <icon>icon-reporting-referer</icon>
+ </category>
+ <subcategory>
+ <id>Referrers_SubmenuSearchEngines</id>
+ <name>Search Engines &amp; Keywords</name>
+ <order>10</order>
+ </subcategory>
+ <module>Referrers</module>
+ <action>getKeywords</action>
+ <order>103</order>
+ <parameters>
+ <module>Referrers</module>
+ <action>getKeywords</action>
+ </parameters>
+ <uniqueId>widgetReferrersgetKeywords</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Search Engines</name>
+ <category>
+ <id>Referrers_Referrers</id>
+ <name>Referrers</name>
+ <order>15</order>
+ <icon>icon-reporting-referer</icon>
+ </category>
+ <subcategory>
+ <id>Referrers_SubmenuSearchEngines</id>
+ <name>Search Engines &amp; Keywords</name>
+ <order>10</order>
+ </subcategory>
+ <module>Referrers</module>
+ <action>getSearchEngines</action>
+ <order>107</order>
+ <parameters>
+ <module>Referrers</module>
+ <action>getSearchEngines</action>
+ </parameters>
+ <uniqueId>widgetReferrersgetSearchEngines</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Social Networks</name>
+ <category>
+ <id>Referrers_Referrers</id>
+ <name>Referrers</name>
+ <order>15</order>
+ <icon>icon-reporting-referer</icon>
+ </category>
+ <subcategory>
+ <id>Referrers_SubmenuWebsites</id>
+ <name>Websites &amp; Social</name>
+ <order>15</order>
+ </subcategory>
+ <module>Referrers</module>
+ <action>getSocials</action>
+ <order>111</order>
+ <parameters>
+ <viewDataTable>graphPie</viewDataTable>
+ <module>Referrers</module>
+ <action>getSocials</action>
+ </parameters>
+ <uniqueId>widgetReferrersgetSocialsviewDataTablegraphPie</uniqueId>
+ <viewDataTable>graphPie</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Websites</name>
+ <category>
+ <id>Referrers_Referrers</id>
+ <name>Referrers</name>
+ <order>15</order>
+ <icon>icon-reporting-referer</icon>
+ </category>
+ <subcategory>
+ <id>Referrers_SubmenuWebsites</id>
+ <name>Websites &amp; Social</name>
+ <order>15</order>
+ </subcategory>
+ <module>Referrers</module>
+ <action>getWebsites</action>
+ <order>105</order>
+ <parameters>
+ <module>Referrers</module>
+ <action>getWebsites</action>
+ </parameters>
+ <uniqueId>widgetReferrersgetWebsites</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Campaigns</name>
+ <category>
+ <id>Referrers_Referrers</id>
+ <name>Referrers</name>
+ <order>15</order>
+ <icon>icon-reporting-referer</icon>
+ </category>
+ <subcategory>
+ <id>Referrers_Campaigns</id>
+ <name>Campaigns</name>
+ <order>20</order>
+ </subcategory>
+ <module>Referrers</module>
+ <action>getCampaigns</action>
+ <order>109</order>
+ <parameters>
+ <module>Referrers</module>
+ <action>getCampaigns</action>
+ </parameters>
+ <uniqueId>widgetReferrersgetCampaigns</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Overview</name>
+ <category>
+ <id>Goals_Ecommerce</id>
+ <name>Ecommerce</name>
+ <order>20</order>
+ <icon>icon-reporting-ecommerce</icon>
+ </category>
+ <subcategory>
+ <id>General_Overview</id>
+ <name>Overview</name>
+ <order>2</order>
+ </subcategory>
+ <module>CoreHome</module>
+ <action>renderWidgetContainer</action>
+ <order>10</order>
+ <parameters>
+ <module>CoreHome</module>
+ <action>renderWidgetContainer</action>
+ <containerId>EcommerceOverview</containerId>
+ </parameters>
+ <uniqueId>widgetEcommerceOverview</uniqueId>
+ <layout />
+ <isContainer>1</isContainer>
+ <widgets>
+ <row>
+ <name />
+ <category>
+ <id>Goals_Ecommerce</id>
+ <name>Ecommerce</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>General_Overview</id>
+ <name>Overview</name>
+ <order>99</order>
+ </subcategory>
+ <module>Goals</module>
+ <action>getEvolutionGraph</action>
+ <order>8</order>
+ <parameters>
+ <forceView>1</forceView>
+ <viewDataTable>graphEvolution</viewDataTable>
+ <module>Goals</module>
+ <action>getEvolutionGraph</action>
+ <idGoal>ecommerceOrder</idGoal>
+ </parameters>
+ <uniqueId>widgetGoalsgetEvolutionGraphforceView1viewDataTablegraphEvolutionidGoalecommerceOrder</uniqueId>
+ <viewDataTable>graphEvolution</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name />
+ <category>
+ <id>Goals_Ecommerce</id>
+ <name>Ecommerce</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>General_Overview</id>
+ <name>Overview</name>
+ <order>99</order>
+ </subcategory>
+ <module>Ecommerce</module>
+ <action>getSparklines</action>
+ <order>9</order>
+ <parameters>
+ <forceView>1</forceView>
+ <viewDataTable>sparklines</viewDataTable>
+ <module>Ecommerce</module>
+ <action>getSparklines</action>
+ <idGoal>ecommerceOrder</idGoal>
+ </parameters>
+ <uniqueId>widgetEcommercegetSparklinesforceView1viewDataTablesparklinesidGoalecommerceOrder</uniqueId>
+ <viewDataTable>sparklines</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Conversions Overview</name>
+ <category>
+ <id>Goals_Goals</id>
+ <name>Goals</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>ecommerceOrder</id>
+ <name>ecommerceOrder</name>
+ <order>99</order>
+ </subcategory>
+ <module>Ecommerce</module>
+ <action>getConversionsOverview</action>
+ <order>10</order>
+ <parameters>
+ <module>Ecommerce</module>
+ <action>getConversionsOverview</action>
+ <idGoal>ecommerceOrder</idGoal>
+ </parameters>
+ <uniqueId>widgetEcommercegetConversionsOverviewidGoalecommerceOrder</uniqueId>
+ <middlewareParameters>
+ <module>Goals</module>
+ <action>hasConversions</action>
+ <idGoal>ecommerceOrder</idGoal>
+ </middlewareParameters>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ </widgets>
+ </row>
+ <row>
+ <name>Ecommerce Log</name>
+ <category>
+ <id>Goals_Ecommerce</id>
+ <name>Ecommerce</name>
+ <order>20</order>
+ <icon>icon-reporting-ecommerce</icon>
+ </category>
+ <subcategory>
+ <id>Goals_EcommerceLog</id>
+ <name>Ecommerce Log</name>
+ <order>5</order>
+ </subcategory>
+ <module>Ecommerce</module>
+ <action>getEcommerceLog</action>
+ <order>99</order>
+ <parameters>
+ <module>Ecommerce</module>
+ <action>getEcommerceLog</action>
+ </parameters>
+ <uniqueId>widgetEcommercegetEcommerceLog</uniqueId>
+ </row>
+ <row>
+ <name>Product SKU</name>
+ <category>
+ <id>Goals_Ecommerce</id>
+ <name>Ecommerce</name>
+ <order>20</order>
+ <icon>icon-reporting-ecommerce</icon>
+ </category>
+ <subcategory>
+ <id>Goals_Products</id>
+ <name>Products</name>
+ <order>10</order>
+ </subcategory>
+ <module>Goals</module>
+ <action>getItemsSku</action>
+ <order>130</order>
+ <parameters>
+ <module>Goals</module>
+ <action>getItemsSku</action>
+ </parameters>
+ <uniqueId>widgetGoalsgetItemsSku</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Product Category</name>
+ <category>
+ <id>Goals_Ecommerce</id>
+ <name>Ecommerce</name>
+ <order>20</order>
+ <icon>icon-reporting-ecommerce</icon>
+ </category>
+ <subcategory>
+ <id>Goals_Products</id>
+ <name>Products</name>
+ <order>10</order>
+ </subcategory>
+ <module>Goals</module>
+ <action>getItemsCategory</action>
+ <order>132</order>
+ <parameters>
+ <module>Goals</module>
+ <action>getItemsCategory</action>
+ </parameters>
+ <uniqueId>widgetGoalsgetItemsCategory</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Product Name</name>
+ <category>
+ <id>Goals_Ecommerce</id>
+ <name>Ecommerce</name>
+ <order>20</order>
+ <icon>icon-reporting-ecommerce</icon>
+ </category>
+ <subcategory>
+ <id>Goals_Products</id>
+ <name>Products</name>
+ <order>10</order>
+ </subcategory>
+ <module>Goals</module>
+ <action>getItemsName</action>
+ <order>131</order>
+ <parameters>
+ <module>Goals</module>
+ <action>getItemsName</action>
+ </parameters>
+ <uniqueId>widgetGoalsgetItemsName</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Product Category</name>
+ <category>
+ <id>Goals_Ecommerce</id>
+ <name>Ecommerce</name>
+ <order>20</order>
+ <icon>icon-reporting-ecommerce</icon>
+ </category>
+ <subcategory>
+ <id>Goals_Products</id>
+ <name>Products</name>
+ <order>10</order>
+ </subcategory>
+ <module>Goals</module>
+ <action>getItemsCategory</action>
+ <order>132</order>
+ <parameters>
+ <module>Goals</module>
+ <action>getItemsCategory</action>
+ </parameters>
+ <uniqueId>widgetGoalsgetItemsCategory</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Product SKU</name>
+ <category>
+ <id>Goals_Ecommerce</id>
+ <name>Ecommerce</name>
+ <order>20</order>
+ <icon>icon-reporting-ecommerce</icon>
+ </category>
+ <subcategory>
+ <id>Goals_Products</id>
+ <name>Products</name>
+ <order>10</order>
+ </subcategory>
+ <module>Goals</module>
+ <action>getItemsSku</action>
+ <order>130</order>
+ <parameters>
+ <module>Goals</module>
+ <action>getItemsSku</action>
+ </parameters>
+ <uniqueId>widgetGoalsgetItemsSku</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Product Name</name>
+ <category>
+ <id>Goals_Ecommerce</id>
+ <name>Ecommerce</name>
+ <order>20</order>
+ <icon>icon-reporting-ecommerce</icon>
+ </category>
+ <subcategory>
+ <id>Goals_Products</id>
+ <name>Products</name>
+ <order>10</order>
+ </subcategory>
+ <module>Goals</module>
+ <action>getItemsName</action>
+ <order>131</order>
+ <parameters>
+ <module>Goals</module>
+ <action>getItemsName</action>
+ </parameters>
+ <uniqueId>widgetGoalsgetItemsName</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Overview</name>
+ <category>
+ <id>Goals_Goals</id>
+ <name>Goals</name>
+ <order>25</order>
+ <icon>icon-reporting-goal</icon>
+ </category>
+ <subcategory>
+ <id>General_Overview</id>
+ <name>Overview</name>
+ <order>2</order>
+ </subcategory>
+ <module>CoreHome</module>
+ <action>renderWidgetContainer</action>
+ <order>5</order>
+ <parameters>
+ <module>CoreHome</module>
+ <action>renderWidgetContainer</action>
+ <containerId>GoalsOverview</containerId>
+ </parameters>
+ <uniqueId>widgetGoalsOverview</uniqueId>
+ <layout />
+ <isContainer>1</isContainer>
+ <widgets>
+ <row>
+ <name />
+ <category>
+ <id>Goals_Goals</id>
+ <name>Goals</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>General_Overview</id>
+ <name>Overview</name>
+ <order>99</order>
+ </subcategory>
+ <module>Goals</module>
+ <action>getEvolutionGraph</action>
+ <order>1</order>
+ <parameters>
+ <forceView>1</forceView>
+ <viewDataTable>graphEvolution</viewDataTable>
+ <module>Goals</module>
+ <action>getEvolutionGraph</action>
+ </parameters>
+ <uniqueId>widgetGoalsgetEvolutionGraphforceView1viewDataTablegraphEvolution</uniqueId>
+ <viewDataTable>graphEvolution</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name />
+ <category>
+ <id>Goals_Goals</id>
+ <name>Goals</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>General_Overview</id>
+ <name>Overview</name>
+ <order>99</order>
+ </subcategory>
+ <module>Goals</module>
+ <action>get</action>
+ <order>2</order>
+ <parameters>
+ <forceView>1</forceView>
+ <viewDataTable>sparklines</viewDataTable>
+ <module>Goals</module>
+ <action>get</action>
+ </parameters>
+ <uniqueId>widgetGoalsgetforceView1viewDataTablesparklines</uniqueId>
+ <viewDataTable>sparklines</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Goal Goal 1 - Thank you</name>
+ <category>
+ <id>Goals_Goals</id>
+ <name>Goals</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>General_Overview</id>
+ <name>Overview</name>
+ <order>99</order>
+ </subcategory>
+ <module>Goals</module>
+ <action>get</action>
+ <order>3</order>
+ <parameters>
+ <forceView>1</forceView>
+ <viewDataTable>sparklines</viewDataTable>
+ <module>Goals</module>
+ <action>get</action>
+ <idGoal>1</idGoal>
+ <allow_multiple>1</allow_multiple>
+ <only_summary>1</only_summary>
+ </parameters>
+ <uniqueId>widgetGoalsgetforceView1viewDataTablesparklinesidGoal1allow_multiple1only_summary1</uniqueId>
+ <viewDataTable>sparklines</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Goal Goal 2 - Hello</name>
+ <category>
+ <id>Goals_Goals</id>
+ <name>Goals</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>General_Overview</id>
+ <name>Overview</name>
+ <order>99</order>
+ </subcategory>
+ <module>Goals</module>
+ <action>get</action>
+ <order>4</order>
+ <parameters>
+ <forceView>1</forceView>
+ <viewDataTable>sparklines</viewDataTable>
+ <module>Goals</module>
+ <action>get</action>
+ <idGoal>2</idGoal>
+ <allow_multiple>0</allow_multiple>
+ <only_summary>1</only_summary>
+ </parameters>
+ <uniqueId>widgetGoalsgetforceView1viewDataTablesparklinesidGoal2allow_multiple0only_summary1</uniqueId>
+ <viewDataTable>sparklines</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Goal triggered js</name>
+ <category>
+ <id>Goals_Goals</id>
+ <name>Goals</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>General_Overview</id>
+ <name>Overview</name>
+ <order>99</order>
+ </subcategory>
+ <module>Goals</module>
+ <action>get</action>
+ <order>5</order>
+ <parameters>
+ <forceView>1</forceView>
+ <viewDataTable>sparklines</viewDataTable>
+ <module>Goals</module>
+ <action>get</action>
+ <idGoal>3</idGoal>
+ <allow_multiple>0</allow_multiple>
+ <only_summary>1</only_summary>
+ </parameters>
+ <uniqueId>widgetGoalsgetforceView1viewDataTablesparklinesidGoal3allow_multiple0only_summary1</uniqueId>
+ <viewDataTable>sparklines</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ </widgets>
+ </row>
+ <row>
+ <name>Goal 1 - Thank you</name>
+ <category>
+ <id>Goals_Goals</id>
+ <name>Goals</name>
+ <order>25</order>
+ <icon>icon-reporting-goal</icon>
+ </category>
+ <subcategory>
+ <id>1</id>
+ <name>Goal 1 - Thank you</name>
+ <order>900</order>
+ </subcategory>
+ <module>CoreHome</module>
+ <action>renderWidgetContainer</action>
+ <order>15</order>
+ <parameters>
+ <module>CoreHome</module>
+ <action>renderWidgetContainer</action>
+ <containerId>Goal_1</containerId>
+ </parameters>
+ <uniqueId>widgetGoal_1</uniqueId>
+ <layout />
+ <isContainer>1</isContainer>
+ <widgets>
+ <row>
+ <name />
+ <category>
+ <id>Goals_Goals</id>
+ <name>Goals</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>1</id>
+ <name>1</name>
+ <order>99</order>
+ </subcategory>
+ <module>Goals</module>
+ <action>getEvolutionGraph</action>
+ <order>13</order>
+ <parameters>
+ <forceView>1</forceView>
+ <viewDataTable>graphEvolution</viewDataTable>
+ <module>Goals</module>
+ <action>getEvolutionGraph</action>
+ <idGoal>1</idGoal>
+ </parameters>
+ <uniqueId>widgetGoalsgetEvolutionGraphforceView1viewDataTablegraphEvolutionidGoal1</uniqueId>
+ <viewDataTable>graphEvolution</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name />
+ <category>
+ <id>Goals_Goals</id>
+ <name>Goals</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>1</id>
+ <name>1</name>
+ <order>99</order>
+ </subcategory>
+ <module>Goals</module>
+ <action>get</action>
+ <order>14</order>
+ <parameters>
+ <forceView>1</forceView>
+ <viewDataTable>sparklines</viewDataTable>
+ <module>Goals</module>
+ <action>get</action>
+ <idGoal>1</idGoal>
+ <allow_multiple>1</allow_multiple>
+ </parameters>
+ <uniqueId>widgetGoalsgetforceView1viewDataTablesparklinesidGoal1allow_multiple1</uniqueId>
+ <viewDataTable>sparklines</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Conversions Overview</name>
+ <category>
+ <id>Goals_Goals</id>
+ <name>Goals</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>1</id>
+ <name>1</name>
+ <order>99</order>
+ </subcategory>
+ <module>Goals</module>
+ <action>goalConversionsOverview</action>
+ <order>15</order>
+ <parameters>
+ <module>Goals</module>
+ <action>goalConversionsOverview</action>
+ <idGoal>1</idGoal>
+ </parameters>
+ <uniqueId>widgetGoalsgoalConversionsOverviewidGoal1</uniqueId>
+ <middlewareParameters>
+ <module>Goals</module>
+ <action>hasConversions</action>
+ <idGoal>1</idGoal>
+ </middlewareParameters>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ </widgets>
+ </row>
+ <row>
+ <name>Goal 2 - Hello</name>
+ <category>
+ <id>Goals_Goals</id>
+ <name>Goals</name>
+ <order>25</order>
+ <icon>icon-reporting-goal</icon>
+ </category>
+ <subcategory>
+ <id>2</id>
+ <name>Goal 2 - Hello</name>
+ <order>901</order>
+ </subcategory>
+ <module>CoreHome</module>
+ <action>renderWidgetContainer</action>
+ <order>20</order>
+ <parameters>
+ <module>CoreHome</module>
+ <action>renderWidgetContainer</action>
+ <containerId>Goal_2</containerId>
+ </parameters>
+ <uniqueId>widgetGoal_2</uniqueId>
+ <layout />
+ <isContainer>1</isContainer>
+ <widgets>
+ <row>
+ <name />
+ <category>
+ <id>Goals_Goals</id>
+ <name>Goals</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>2</id>
+ <name>2</name>
+ <order>99</order>
+ </subcategory>
+ <module>Goals</module>
+ <action>getEvolutionGraph</action>
+ <order>18</order>
+ <parameters>
+ <forceView>1</forceView>
+ <viewDataTable>graphEvolution</viewDataTable>
+ <module>Goals</module>
+ <action>getEvolutionGraph</action>
+ <idGoal>2</idGoal>
+ </parameters>
+ <uniqueId>widgetGoalsgetEvolutionGraphforceView1viewDataTablegraphEvolutionidGoal2</uniqueId>
+ <viewDataTable>graphEvolution</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name />
+ <category>
+ <id>Goals_Goals</id>
+ <name>Goals</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>2</id>
+ <name>2</name>
+ <order>99</order>
+ </subcategory>
+ <module>Goals</module>
+ <action>get</action>
+ <order>19</order>
+ <parameters>
+ <forceView>1</forceView>
+ <viewDataTable>sparklines</viewDataTable>
+ <module>Goals</module>
+ <action>get</action>
+ <idGoal>2</idGoal>
+ <allow_multiple>0</allow_multiple>
+ </parameters>
+ <uniqueId>widgetGoalsgetforceView1viewDataTablesparklinesidGoal2allow_multiple0</uniqueId>
+ <viewDataTable>sparklines</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Conversions Overview</name>
+ <category>
+ <id>Goals_Goals</id>
+ <name>Goals</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>2</id>
+ <name>2</name>
+ <order>99</order>
+ </subcategory>
+ <module>Goals</module>
+ <action>goalConversionsOverview</action>
+ <order>20</order>
+ <parameters>
+ <module>Goals</module>
+ <action>goalConversionsOverview</action>
+ <idGoal>2</idGoal>
+ </parameters>
+ <uniqueId>widgetGoalsgoalConversionsOverviewidGoal2</uniqueId>
+ <middlewareParameters>
+ <module>Goals</module>
+ <action>hasConversions</action>
+ <idGoal>2</idGoal>
+ </middlewareParameters>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ </widgets>
+ </row>
+ <row>
+ <name>triggered js</name>
+ <category>
+ <id>Goals_Goals</id>
+ <name>Goals</name>
+ <order>25</order>
+ <icon>icon-reporting-goal</icon>
+ </category>
+ <subcategory>
+ <id>3</id>
+ <name>triggered js</name>
+ <order>902</order>
+ </subcategory>
+ <module>CoreHome</module>
+ <action>renderWidgetContainer</action>
+ <order>25</order>
+ <parameters>
+ <module>CoreHome</module>
+ <action>renderWidgetContainer</action>
+ <containerId>Goal_3</containerId>
+ </parameters>
+ <uniqueId>widgetGoal_3</uniqueId>
+ <layout />
+ <isContainer>1</isContainer>
+ <widgets>
+ <row>
+ <name />
+ <category>
+ <id>Goals_Goals</id>
+ <name>Goals</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>3</id>
+ <name>3</name>
+ <order>99</order>
+ </subcategory>
+ <module>Goals</module>
+ <action>getEvolutionGraph</action>
+ <order>23</order>
+ <parameters>
+ <forceView>1</forceView>
+ <viewDataTable>graphEvolution</viewDataTable>
+ <module>Goals</module>
+ <action>getEvolutionGraph</action>
+ <idGoal>3</idGoal>
+ </parameters>
+ <uniqueId>widgetGoalsgetEvolutionGraphforceView1viewDataTablegraphEvolutionidGoal3</uniqueId>
+ <viewDataTable>graphEvolution</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name />
+ <category>
+ <id>Goals_Goals</id>
+ <name>Goals</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>3</id>
+ <name>3</name>
+ <order>99</order>
+ </subcategory>
+ <module>Goals</module>
+ <action>get</action>
+ <order>24</order>
+ <parameters>
+ <forceView>1</forceView>
+ <viewDataTable>sparklines</viewDataTable>
+ <module>Goals</module>
+ <action>get</action>
+ <idGoal>3</idGoal>
+ <allow_multiple>0</allow_multiple>
+ </parameters>
+ <uniqueId>widgetGoalsgetforceView1viewDataTablesparklinesidGoal3allow_multiple0</uniqueId>
+ <viewDataTable>sparklines</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Conversions Overview</name>
+ <category>
+ <id>Goals_Goals</id>
+ <name>Goals</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>3</id>
+ <name>3</name>
+ <order>99</order>
+ </subcategory>
+ <module>Goals</module>
+ <action>goalConversionsOverview</action>
+ <order>25</order>
+ <parameters>
+ <module>Goals</module>
+ <action>goalConversionsOverview</action>
+ <idGoal>3</idGoal>
+ </parameters>
+ <uniqueId>widgetGoalsgoalConversionsOverviewidGoal3</uniqueId>
+ <middlewareParameters>
+ <module>Goals</module>
+ <action>hasConversions</action>
+ <idGoal>3</idGoal>
+ </middlewareParameters>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ </widgets>
+ </row>
+ <row>
+ <name>Data tables</name>
+ <category>
+ <id>ExampleUI_UiFramework</id>
+ <name>UI Framework</name>
+ <order>90</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Bar graph</id>
+ <name>Bar graph</name>
+ <order>99</order>
+ </subcategory>
+ <module>ExampleUI</module>
+ <action>getTemperatures</action>
+ <order>210</order>
+ <parameters>
+ <forceView>1</forceView>
+ <viewDataTable>graphVerticalBar</viewDataTable>
+ <module>ExampleUI</module>
+ <action>getTemperatures</action>
+ </parameters>
+ <uniqueId>widgetExampleUIgetTemperaturesforceView1viewDataTablegraphVerticalBar</uniqueId>
+ <viewDataTable>graphVerticalBar</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Data tables</name>
+ <category>
+ <id>ExampleUI_UiFramework</id>
+ <name>UI Framework</name>
+ <order>90</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>ExampleUI_GetTemperaturesDataTable</id>
+ <name>Data tables</name>
+ <order>99</order>
+ </subcategory>
+ <module>ExampleUI</module>
+ <action>getTemperatures</action>
+ <order>210</order>
+ <parameters>
+ <module>ExampleUI</module>
+ <action>getTemperatures</action>
+ </parameters>
+ <uniqueId>widgetExampleUIgetTemperatures</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Treemap example</name>
+ <category>
+ <id>ExampleUI_UiFramework</id>
+ <name>UI Framework</name>
+ <order>90</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Treemap</id>
+ <name>Treemap</name>
+ <order>99</order>
+ </subcategory>
+ <module>ExampleUI</module>
+ <action>getTemperatures</action>
+ <order>210</order>
+ <parameters>
+ <forceView>1</forceView>
+ <viewDataTable>infoviz-treemap</viewDataTable>
+ <module>ExampleUI</module>
+ <action>getTemperatures</action>
+ </parameters>
+ <uniqueId>widgetExampleUIgetTemperaturesforceView1viewDataTableinfoviz-treemap</uniqueId>
+ <viewDataTable>infoviz-treemap</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Pie graph</name>
+ <category>
+ <id>ExampleUI_UiFramework</id>
+ <name>UI Framework</name>
+ <order>90</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Pie graph</id>
+ <name>Pie graph</name>
+ <order>99</order>
+ </subcategory>
+ <module>ExampleUI</module>
+ <action>getPlanetRatios</action>
+ <order>212</order>
+ <parameters>
+ <viewDataTable>graphPie</viewDataTable>
+ <module>ExampleUI</module>
+ <action>getPlanetRatios</action>
+ </parameters>
+ <uniqueId>widgetExampleUIgetPlanetRatiosviewDataTablegraphPie</uniqueId>
+ <viewDataTable>graphPie</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Evolution of server temperatures over the last few days</name>
+ <category>
+ <id>ExampleUI_UiFramework</id>
+ <name>UI Framework</name>
+ <order>90</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Evolution Graph</id>
+ <name>Evolution Graph</name>
+ <order>99</order>
+ </subcategory>
+ <module>ExampleUI</module>
+ <action>getTemperaturesEvolution</action>
+ <order>211</order>
+ <parameters>
+ <forceView>1</forceView>
+ <viewDataTable>graphEvolution</viewDataTable>
+ <module>ExampleUI</module>
+ <action>getTemperaturesEvolution</action>
+ <columns>
+ <row>server1</row>
+ <row>server2</row>
+ </columns>
+ </parameters>
+ <uniqueId>widgetExampleUIgetTemperaturesEvolutionforceView1viewDataTablegraphEvolutioncolumnsArray</uniqueId>
+ <viewDataTable>graphEvolution</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Temperatures evolution over time</name>
+ <category>
+ <id>ExampleUI_UiFramework</id>
+ <name>UI Framework</name>
+ <order>90</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Sparklines</id>
+ <name>Sparklines</name>
+ <order>99</order>
+ </subcategory>
+ <module>ExampleUI</module>
+ <action>getTemperaturesEvolution</action>
+ <order>211</order>
+ <parameters>
+ <forceView>1</forceView>
+ <viewDataTable>sparklines</viewDataTable>
+ <module>ExampleUI</module>
+ <action>getTemperaturesEvolution</action>
+ </parameters>
+ <uniqueId>widgetExampleUIgetTemperaturesEvolutionforceView1viewDataTablesparklines</uniqueId>
+ <viewDataTable>sparklines</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Advanced tag cloud: with logos and links</name>
+ <category>
+ <id>ExampleUI_UiFramework</id>
+ <name>UI Framework</name>
+ <order>90</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Tag clouds</id>
+ <name>Tag clouds</name>
+ <order>99</order>
+ </subcategory>
+ <module>ExampleUI</module>
+ <action>getPlanetRatiosWithLogos</action>
+ <order>213</order>
+ <parameters>
+ <viewDataTable>cloud</viewDataTable>
+ <module>ExampleUI</module>
+ <action>getPlanetRatiosWithLogos</action>
+ </parameters>
+ <uniqueId>widgetExampleUIgetPlanetRatiosWithLogosviewDataTablecloud</uniqueId>
+ <viewDataTable>cloud</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Simple tag cloud</name>
+ <category>
+ <id>ExampleUI_UiFramework</id>
+ <name>UI Framework</name>
+ <order>90</order>
+ <icon />
+ </category>
+ <subcategory>
+ <id>Tag clouds</id>
+ <name>Tag clouds</name>
+ <order>99</order>
+ </subcategory>
+ <module>ExampleUI</module>
+ <action>getPlanetRatios</action>
+ <order>5</order>
+ <parameters>
+ <forceView>1</forceView>
+ <viewDataTable>cloud</viewDataTable>
+ <module>ExampleUI</module>
+ <action>getPlanetRatios</action>
+ </parameters>
+ <uniqueId>widgetExampleUIgetPlanetRatiosforceView1viewDataTablecloud</uniqueId>
+ <viewDataTable>cloud</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>SEO Rankings</name>
+ <category>
+ <id>SEO</id>
+ <name>SEO</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory />
+ <module>SEO</module>
+ <action>getRank</action>
+ <order>99</order>
+ <parameters>
+ <module>SEO</module>
+ <action>getRank</action>
+ </parameters>
+ <uniqueId>widgetSEOgetRank</uniqueId>
+ </row>
+ <row>
+ <name>Insights Overview</name>
+ <category>
+ <id>Insights_WidgetCategory</id>
+ <name>Insights</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory />
+ <module>Insights</module>
+ <action>getInsightsOverview</action>
+ <order>99</order>
+ <parameters>
+ <module>Insights</module>
+ <action>getInsightsOverview</action>
+ </parameters>
+ <uniqueId>widgetInsightsgetInsightsOverview</uniqueId>
+ </row>
+ <row>
+ <name>Piwik.org Blog</name>
+ <category>
+ <id>About Piwik</id>
+ <name>About Piwik</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory />
+ <module>ExampleRssWidget</module>
+ <action>rssPiwik</action>
+ <order>99</order>
+ <parameters>
+ <module>ExampleRssWidget</module>
+ <action>rssPiwik</action>
+ </parameters>
+ <uniqueId>widgetExampleRssWidgetrssPiwik</uniqueId>
+ </row>
+ <row>
+ <name>Example Widget Name</name>
+ <category>
+ <id>About Piwik</id>
+ <name>About Piwik</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory />
+ <module>ExamplePlugin</module>
+ <action>myExampleWidget</action>
+ <order>99</order>
+ <parameters>
+ <module>ExamplePlugin</module>
+ <action>myExampleWidget</action>
+ </parameters>
+ <uniqueId>widgetExamplePluginmyExampleWidget</uniqueId>
+ </row>
+ <row>
+ <name>Movers and Shakers</name>
+ <category>
+ <id>Insights_WidgetCategory</id>
+ <name>Insights</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory />
+ <module>Insights</module>
+ <action>getOverallMoversAndShakers</action>
+ <order>99</order>
+ <parameters>
+ <module>Insights</module>
+ <action>getOverallMoversAndShakers</action>
+ </parameters>
+ <uniqueId>widgetInsightsgetOverallMoversAndShakers</uniqueId>
+ </row>
+ <row>
+ <name>Top Keywords for Page URL</name>
+ <category>
+ <id>SEO</id>
+ <name>SEO</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory />
+ <module>Referrers</module>
+ <action>getKeywordsForPage</action>
+ <order>99</order>
+ <parameters>
+ <module>Referrers</module>
+ <action>getKeywordsForPage</action>
+ </parameters>
+ <uniqueId>widgetReferrersgetKeywordsForPage</uniqueId>
+ </row>
+ <row>
+ <name>Support Piwik!</name>
+ <category>
+ <id>About Piwik</id>
+ <name>About Piwik</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory />
+ <module>CoreHome</module>
+ <action>getDonateForm</action>
+ <order>5</order>
+ <parameters>
+ <module>CoreHome</module>
+ <action>getDonateForm</action>
+ </parameters>
+ <uniqueId>widgetCoreHomegetDonateForm</uniqueId>
+ </row>
+ <row>
+ <name>Piwik PRO: Advanced Analytics &amp; Services</name>
+ <category>
+ <id>About Piwik</id>
+ <name>About Piwik</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory />
+ <module>PiwikPro</module>
+ <action>promoPiwikPro</action>
+ <order>99</order>
+ <parameters>
+ <module>PiwikPro</module>
+ <action>promoPiwikPro</action>
+ </parameters>
+ <uniqueId>widgetPiwikPropromoPiwikPro</uniqueId>
+ </row>
+ <row>
+ <name>Piwik Changelog</name>
+ <category>
+ <id>About Piwik</id>
+ <name>About Piwik</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory />
+ <module>ExampleRssWidget</module>
+ <action>rssChangelog</action>
+ <order>99</order>
+ <parameters>
+ <module>ExampleRssWidget</module>
+ <action>rssChangelog</action>
+ </parameters>
+ <uniqueId>widgetExampleRssWidgetrssChangelog</uniqueId>
+ </row>
+ <row>
+ <name>Welcome!</name>
+ <category>
+ <id>About Piwik</id>
+ <name>About Piwik</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory />
+ <module>CoreHome</module>
+ <action>getPromoVideo</action>
+ <order>10</order>
+ <parameters>
+ <module>CoreHome</module>
+ <action>getPromoVideo</action>
+ </parameters>
+ <uniqueId>widgetCoreHomegetPromoVideo</uniqueId>
+ </row>
+ <row>
+ <name>Piwik PRO Blog</name>
+ <category>
+ <id>About Piwik</id>
+ <name>About Piwik</name>
+ <order>99</order>
+ <icon />
+ </category>
+ <subcategory />
+ <module>PiwikPro</module>
+ <action>rssPiwikPro</action>
+ <order>99</order>
+ <parameters>
+ <module>PiwikPro</module>
+ <action>rssPiwikPro</action>
+ </parameters>
+ <uniqueId>widgetPiwikProrssPiwikPro</uniqueId>
+ </row>
+</result> \ No newline at end of file
diff --git a/tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getWidgetMetadata_day.xml b/tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getWidgetMetadata_day.xml
new file mode 100644
index 0000000000..fa3b20ac00
--- /dev/null
+++ b/tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getWidgetMetadata_day.xml
@@ -0,0 +1,1987 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<result>
+ <row>
+ <name>Visitors in Real-time</name>
+ <category>
+ <name>Live!</name>
+ <order>2</order>
+ <id>Live!</id>
+ </category>
+ <subcategory />
+ <module>Live</module>
+ <action>widget</action>
+ <order>20</order>
+ <parameters>
+ <module>Live</module>
+ <action>widget</action>
+ </parameters>
+ <uniqueId>widgetLivewidget</uniqueId>
+ </row>
+ <row>
+ <name>Real Time Visitor Count</name>
+ <category>
+ <name>Live!</name>
+ <order>2</order>
+ <id>Live!</id>
+ </category>
+ <subcategory />
+ <module>Live</module>
+ <action>getSimpleLastVisitCount</action>
+ <order>15</order>
+ <parameters>
+ <module>Live</module>
+ <action>getSimpleLastVisitCount</action>
+ </parameters>
+ <uniqueId>widgetLivegetSimpleLastVisitCount</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Visits Over Time</name>
+ <category>
+ <name>Visitors</name>
+ <order>5</order>
+ <id>General_Visitors</id>
+ </category>
+ <subcategory>
+ <name>Overview</name>
+ <order>2</order>
+ <id>General_Overview</id>
+ </subcategory>
+ <module>VisitsSummary</module>
+ <action>getEvolutionGraph</action>
+ <order>5</order>
+ <parameters>
+ <forceView>1</forceView>
+ <viewDataTable>graphEvolution</viewDataTable>
+ <module>VisitsSummary</module>
+ <action>getEvolutionGraph</action>
+ </parameters>
+ <uniqueId>widgetVisitsSummarygetEvolutionGraphforceView1viewDataTablegraphEvolution</uniqueId>
+ <viewDataTable>graphEvolution</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Visitor Log</name>
+ <category>
+ <name>Visitors</name>
+ <order>5</order>
+ <id>General_Visitors</id>
+ </category>
+ <subcategory>
+ <name>Visitor Log</name>
+ <order>5</order>
+ <id>Live_VisitorLog</id>
+ </subcategory>
+ <module>Live</module>
+ <action>getLastVisitsDetails</action>
+ <order>10</order>
+ <parameters>
+ <forceView>1</forceView>
+ <viewDataTable>Piwik\Plugins\Live\VisitorLog</viewDataTable>
+ <module>Live</module>
+ <action>getLastVisitsDetails</action>
+ <small>1</small>
+ </parameters>
+ <uniqueId>widgetLivegetLastVisitsDetailsforceView1viewDataTablePiwik%5CPlugins%5CLive%5CVisitorLogsmall1</uniqueId>
+ <viewDataTable>Piwik\Plugins\Live\VisitorLog</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Custom Variables</name>
+ <category>
+ <name>Visitors</name>
+ <order>5</order>
+ <id>General_Visitors</id>
+ </category>
+ <subcategory>
+ <name>Custom Variables</name>
+ <order>10</order>
+ <id>CustomVariables_CustomVariables</id>
+ </subcategory>
+ <module>CustomVariables</module>
+ <action>getCustomVariables</action>
+ <order>110</order>
+ <parameters>
+ <module>CustomVariables</module>
+ <action>getCustomVariables</action>
+ </parameters>
+ <uniqueId>widgetCustomVariablesgetCustomVariables</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Device model</name>
+ <category>
+ <name>Visitors</name>
+ <order>5</order>
+ <id>General_Visitors</id>
+ </category>
+ <subcategory>
+ <name>Devices</name>
+ <order>15</order>
+ <id>DevicesDetection_Devices</id>
+ </subcategory>
+ <module>DevicesDetection</module>
+ <action>getModel</action>
+ <order>102</order>
+ <parameters>
+ <module>DevicesDetection</module>
+ <action>getModel</action>
+ </parameters>
+ <uniqueId>widgetDevicesDetectiongetModel</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Device type</name>
+ <category>
+ <name>Visitors</name>
+ <order>5</order>
+ <id>General_Visitors</id>
+ </category>
+ <subcategory>
+ <name>Devices</name>
+ <order>15</order>
+ <id>DevicesDetection_Devices</id>
+ </subcategory>
+ <module>DevicesDetection</module>
+ <action>getType</action>
+ <order>100</order>
+ <parameters>
+ <module>DevicesDetection</module>
+ <action>getType</action>
+ </parameters>
+ <uniqueId>widgetDevicesDetectiongetType</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Screen Resolution</name>
+ <category>
+ <name>Visitors</name>
+ <order>5</order>
+ <id>General_Visitors</id>
+ </category>
+ <subcategory>
+ <name>Devices</name>
+ <order>15</order>
+ <id>DevicesDetection_Devices</id>
+ </subcategory>
+ <module>Resolution</module>
+ <action>getResolution</action>
+ <order>108</order>
+ <parameters>
+ <module>Resolution</module>
+ <action>getResolution</action>
+ </parameters>
+ <uniqueId>widgetResolutiongetResolution</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Device brand</name>
+ <category>
+ <name>Visitors</name>
+ <order>5</order>
+ <id>General_Visitors</id>
+ </category>
+ <subcategory>
+ <name>Devices</name>
+ <order>15</order>
+ <id>DevicesDetection_Devices</id>
+ </subcategory>
+ <module>DevicesDetection</module>
+ <action>getBrand</action>
+ <order>104</order>
+ <parameters>
+ <module>DevicesDetection</module>
+ <action>getBrand</action>
+ </parameters>
+ <uniqueId>widgetDevicesDetectiongetBrand</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Operating System versions</name>
+ <category>
+ <name>Visitors</name>
+ <order>5</order>
+ <id>General_Visitors</id>
+ </category>
+ <subcategory>
+ <name>Software</name>
+ <order>20</order>
+ <id>DevicesDetection_Software</id>
+ </subcategory>
+ <module>DevicesDetection</module>
+ <action>getOsVersions</action>
+ <order>102</order>
+ <parameters>
+ <module>DevicesDetection</module>
+ <action>getOsVersions</action>
+ </parameters>
+ <uniqueId>widgetDevicesDetectiongetOsVersions</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Browsers</name>
+ <category>
+ <name>Visitors</name>
+ <order>5</order>
+ <id>General_Visitors</id>
+ </category>
+ <subcategory>
+ <name>Software</name>
+ <order>20</order>
+ <id>DevicesDetection_Software</id>
+ </subcategory>
+ <module>DevicesDetection</module>
+ <action>getBrowsers</action>
+ <order>105</order>
+ <parameters>
+ <module>DevicesDetection</module>
+ <action>getBrowsers</action>
+ </parameters>
+ <uniqueId>widgetDevicesDetectiongetBrowsers</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Visits Overview (with graph)</name>
+ <category>
+ <name>Visitors</name>
+ <order>5</order>
+ <id>General_Visitors</id>
+ </category>
+ <subcategory />
+ <module>CoreHome</module>
+ <action>renderWidgetContainer</action>
+ <order>99</order>
+ <parameters>
+ <module>CoreHome</module>
+ <action>renderWidgetContainer</action>
+ <containerId>VisitOverviewWithGraph</containerId>
+ </parameters>
+ <uniqueId>widgetVisitOverviewWithGraph</uniqueId>
+ <layout />
+ <isContainer>1</isContainer>
+ </row>
+ <row>
+ <name>Visits Overview</name>
+ <category>
+ <name>Visitors</name>
+ <order>5</order>
+ <id>General_Visitors</id>
+ </category>
+ <subcategory>
+ <name>Overview</name>
+ <order>2</order>
+ <id>General_Overview</id>
+ </subcategory>
+ <module>VisitsSummary</module>
+ <action>get</action>
+ <order>10</order>
+ <parameters>
+ <forceView>1</forceView>
+ <viewDataTable>sparklines</viewDataTable>
+ <module>VisitsSummary</module>
+ <action>get</action>
+ </parameters>
+ <uniqueId>widgetVisitsSummarygetforceView1viewDataTablesparklines</uniqueId>
+ <viewDataTable>sparklines</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Browser version</name>
+ <category>
+ <name>Visitors</name>
+ <order>5</order>
+ <id>General_Visitors</id>
+ </category>
+ <subcategory>
+ <name>Software</name>
+ <order>20</order>
+ <id>DevicesDetection_Software</id>
+ </subcategory>
+ <module>DevicesDetection</module>
+ <action>getBrowserVersions</action>
+ <order>106</order>
+ <parameters>
+ <module>DevicesDetection</module>
+ <action>getBrowserVersions</action>
+ </parameters>
+ <uniqueId>widgetDevicesDetectiongetBrowserVersions</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Configurations</name>
+ <category>
+ <name>Visitors</name>
+ <order>5</order>
+ <id>General_Visitors</id>
+ </category>
+ <subcategory>
+ <name>Software</name>
+ <order>20</order>
+ <id>DevicesDetection_Software</id>
+ </subcategory>
+ <module>Resolution</module>
+ <action>getConfiguration</action>
+ <order>107</order>
+ <parameters>
+ <module>Resolution</module>
+ <action>getConfiguration</action>
+ </parameters>
+ <uniqueId>widgetResolutiongetConfiguration</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Browser Plugins</name>
+ <category>
+ <name>Visitors</name>
+ <order>5</order>
+ <id>General_Visitors</id>
+ </category>
+ <subcategory>
+ <name>Software</name>
+ <order>20</order>
+ <id>DevicesDetection_Software</id>
+ </subcategory>
+ <module>DevicePlugins</module>
+ <action>getPlugin</action>
+ <order>113</order>
+ <parameters>
+ <module>DevicePlugins</module>
+ <action>getPlugin</action>
+ </parameters>
+ <uniqueId>widgetDevicePluginsgetPlugin</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Browser engines</name>
+ <category>
+ <name>Visitors</name>
+ <order>5</order>
+ <id>General_Visitors</id>
+ </category>
+ <subcategory>
+ <name>Software</name>
+ <order>20</order>
+ <id>DevicesDetection_Software</id>
+ </subcategory>
+ <module>DevicesDetection</module>
+ <action>getBrowserEngines</action>
+ <order>110</order>
+ <parameters>
+ <viewDataTable>graphPie</viewDataTable>
+ <module>DevicesDetection</module>
+ <action>getBrowserEngines</action>
+ </parameters>
+ <uniqueId>widgetDevicesDetectiongetBrowserEnginesviewDataTablegraphPie</uniqueId>
+ <viewDataTable>graphPie</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Operating System families</name>
+ <category>
+ <name>Visitors</name>
+ <order>5</order>
+ <id>General_Visitors</id>
+ </category>
+ <subcategory>
+ <name>Software</name>
+ <order>20</order>
+ <id>DevicesDetection_Software</id>
+ </subcategory>
+ <module>DevicesDetection</module>
+ <action>getOsFamilies</action>
+ <order>108</order>
+ <parameters>
+ <module>DevicesDetection</module>
+ <action>getOsFamilies</action>
+ </parameters>
+ <uniqueId>widgetDevicesDetectiongetOsFamilies</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Browser language</name>
+ <category>
+ <name>Visitors</name>
+ <order>5</order>
+ <id>General_Visitors</id>
+ </category>
+ <subcategory>
+ <name>Locations</name>
+ <order>25</order>
+ <id>UserCountry_SubmenuLocations</id>
+ </subcategory>
+ <module>UserLanguage</module>
+ <action>getLanguage</action>
+ <order>108</order>
+ <parameters>
+ <module>UserLanguage</module>
+ <action>getLanguage</action>
+ </parameters>
+ <uniqueId>widgetUserLanguagegetLanguage</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Region</name>
+ <category>
+ <name>Visitors</name>
+ <order>5</order>
+ <id>General_Visitors</id>
+ </category>
+ <subcategory>
+ <name>Locations</name>
+ <order>25</order>
+ <id>UserCountry_SubmenuLocations</id>
+ </subcategory>
+ <module>UserCountry</module>
+ <action>getRegion</action>
+ <order>107</order>
+ <parameters>
+ <module>UserCountry</module>
+ <action>getRegion</action>
+ </parameters>
+ <uniqueId>widgetUserCountrygetRegion</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Country</name>
+ <category>
+ <name>Visitors</name>
+ <order>5</order>
+ <id>General_Visitors</id>
+ </category>
+ <subcategory>
+ <name>Locations</name>
+ <order>25</order>
+ <id>UserCountry_SubmenuLocations</id>
+ </subcategory>
+ <module>UserCountry</module>
+ <action>getCountry</action>
+ <order>105</order>
+ <parameters>
+ <module>UserCountry</module>
+ <action>getCountry</action>
+ </parameters>
+ <uniqueId>widgetUserCountrygetCountry</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Language code</name>
+ <category>
+ <name>Visitors</name>
+ <order>5</order>
+ <id>General_Visitors</id>
+ </category>
+ <subcategory>
+ <name>Locations</name>
+ <order>25</order>
+ <id>UserCountry_SubmenuLocations</id>
+ </subcategory>
+ <module>UserLanguage</module>
+ <action>getLanguageCode</action>
+ <order>111</order>
+ <parameters>
+ <module>UserLanguage</module>
+ <action>getLanguageCode</action>
+ </parameters>
+ <uniqueId>widgetUserLanguagegetLanguageCode</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Continent</name>
+ <category>
+ <name>Visitors</name>
+ <order>5</order>
+ <id>General_Visitors</id>
+ </category>
+ <subcategory>
+ <name>Locations</name>
+ <order>25</order>
+ <id>UserCountry_SubmenuLocations</id>
+ </subcategory>
+ <module>UserCountry</module>
+ <action>getContinent</action>
+ <order>106</order>
+ <parameters>
+ <module>UserCountry</module>
+ <action>getContinent</action>
+ </parameters>
+ <uniqueId>widgetUserCountrygetContinent</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Visitor profile</name>
+ <category>
+ <name>Visitors</name>
+ <order>5</order>
+ <id>General_Visitors</id>
+ </category>
+ <subcategory />
+ <module>Live</module>
+ <action>getVisitorProfilePopup</action>
+ <order>25</order>
+ <parameters>
+ <module>Live</module>
+ <action>getVisitorProfilePopup</action>
+ </parameters>
+ <uniqueId>widgetLivegetVisitorProfilePopup</uniqueId>
+ </row>
+ <row>
+ <name>Providers</name>
+ <category>
+ <name>Visitors</name>
+ <order>5</order>
+ <id>General_Visitors</id>
+ </category>
+ <subcategory>
+ <name>Locations</name>
+ <order>25</order>
+ <id>UserCountry_SubmenuLocations</id>
+ </subcategory>
+ <module>Provider</module>
+ <action>getProvider</action>
+ <order>150</order>
+ <parameters>
+ <module>Provider</module>
+ <action>getProvider</action>
+ </parameters>
+ <uniqueId>widgetProvidergetProvider</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>City</name>
+ <category>
+ <name>Visitors</name>
+ <order>5</order>
+ <id>General_Visitors</id>
+ </category>
+ <subcategory>
+ <name>Locations</name>
+ <order>25</order>
+ <id>UserCountry_SubmenuLocations</id>
+ </subcategory>
+ <module>UserCountry</module>
+ <action>getCity</action>
+ <order>110</order>
+ <parameters>
+ <module>UserCountry</module>
+ <action>getCity</action>
+ </parameters>
+ <uniqueId>widgetUserCountrygetCity</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Visitor Map</name>
+ <category>
+ <name>Visitors</name>
+ <order>5</order>
+ <id>General_Visitors</id>
+ </category>
+ <subcategory>
+ <name>Locations</name>
+ <order>25</order>
+ <id>UserCountry_SubmenuLocations</id>
+ </subcategory>
+ <module>UserCountryMap</module>
+ <action>visitorMap</action>
+ <order>1</order>
+ <parameters>
+ <module>UserCountryMap</module>
+ <action>visitorMap</action>
+ </parameters>
+ <uniqueId>widgetUserCountryMapvisitorMap</uniqueId>
+ </row>
+ <row>
+ <name>Visits per visit duration</name>
+ <category>
+ <name>Visitors</name>
+ <order>5</order>
+ <id>General_Visitors</id>
+ </category>
+ <subcategory>
+ <name>Engagement</name>
+ <order>30</order>
+ <id>VisitorInterest_Engagement</id>
+ </subcategory>
+ <module>VisitorInterest</module>
+ <action>getNumberOfVisitsPerVisitDuration</action>
+ <order>115</order>
+ <parameters>
+ <viewDataTable>cloud</viewDataTable>
+ <module>VisitorInterest</module>
+ <action>getNumberOfVisitsPerVisitDuration</action>
+ </parameters>
+ <uniqueId>widgetVisitorInterestgetNumberOfVisitsPerVisitDurationviewDataTablecloud</uniqueId>
+ <viewDataTable>cloud</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Returning Visits Over Time</name>
+ <category>
+ <name>Visitors</name>
+ <order>5</order>
+ <id>General_Visitors</id>
+ </category>
+ <subcategory>
+ <name>Engagement</name>
+ <order>30</order>
+ <id>VisitorInterest_Engagement</id>
+ </subcategory>
+ <module>VisitFrequency</module>
+ <action>getEvolutionGraph</action>
+ <order>1</order>
+ <parameters>
+ <forceView>1</forceView>
+ <viewDataTable>graphEvolution</viewDataTable>
+ <module>VisitFrequency</module>
+ <action>getEvolutionGraph</action>
+ </parameters>
+ <uniqueId>widgetVisitFrequencygetEvolutionGraphforceView1viewDataTablegraphEvolution</uniqueId>
+ <viewDataTable>graphEvolution</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Visits by Days Since Last Visit</name>
+ <category>
+ <name>Visitors</name>
+ <order>5</order>
+ <id>General_Visitors</id>
+ </category>
+ <subcategory>
+ <name>Engagement</name>
+ <order>30</order>
+ <id>VisitorInterest_Engagement</id>
+ </subcategory>
+ <module>VisitorInterest</module>
+ <action>getNumberOfVisitsByDaysSinceLast</action>
+ <order>130</order>
+ <parameters>
+ <module>VisitorInterest</module>
+ <action>getNumberOfVisitsByDaysSinceLast</action>
+ </parameters>
+ <uniqueId>widgetVisitorInterestgetNumberOfVisitsByDaysSinceLast</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Visits by Visit Number</name>
+ <category>
+ <name>Visitors</name>
+ <order>5</order>
+ <id>General_Visitors</id>
+ </category>
+ <subcategory>
+ <name>Engagement</name>
+ <order>30</order>
+ <id>VisitorInterest_Engagement</id>
+ </subcategory>
+ <module>VisitorInterest</module>
+ <action>getNumberOfVisitsByVisitCount</action>
+ <order>125</order>
+ <parameters>
+ <module>VisitorInterest</module>
+ <action>getNumberOfVisitsByVisitCount</action>
+ </parameters>
+ <uniqueId>widgetVisitorInterestgetNumberOfVisitsByVisitCount</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Visits per number of pages</name>
+ <category>
+ <name>Visitors</name>
+ <order>5</order>
+ <id>General_Visitors</id>
+ </category>
+ <subcategory>
+ <name>Engagement</name>
+ <order>30</order>
+ <id>VisitorInterest_Engagement</id>
+ </subcategory>
+ <module>VisitorInterest</module>
+ <action>getNumberOfVisitsPerPage</action>
+ <order>120</order>
+ <parameters>
+ <viewDataTable>cloud</viewDataTable>
+ <module>VisitorInterest</module>
+ <action>getNumberOfVisitsPerPage</action>
+ </parameters>
+ <uniqueId>widgetVisitorInterestgetNumberOfVisitsPerPageviewDataTablecloud</uniqueId>
+ <viewDataTable>cloud</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Frequency Overview</name>
+ <category>
+ <name>Visitors</name>
+ <order>5</order>
+ <id>General_Visitors</id>
+ </category>
+ <subcategory>
+ <name>Engagement</name>
+ <order>30</order>
+ <id>VisitorInterest_Engagement</id>
+ </subcategory>
+ <module>VisitFrequency</module>
+ <action>get</action>
+ <order>2</order>
+ <parameters>
+ <forceView>1</forceView>
+ <viewDataTable>sparklines</viewDataTable>
+ <module>VisitFrequency</module>
+ <action>get</action>
+ </parameters>
+ <uniqueId>widgetVisitFrequencygetforceView1viewDataTablesparklines</uniqueId>
+ <viewDataTable>sparklines</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Visits per server time</name>
+ <category>
+ <name>Visitors</name>
+ <order>5</order>
+ <id>General_Visitors</id>
+ </category>
+ <subcategory>
+ <name>Times</name>
+ <order>35</order>
+ <id>VisitTime_SubmenuTimes</id>
+ </subcategory>
+ <module>VisitTime</module>
+ <action>getVisitInformationPerServerTime</action>
+ <order>120</order>
+ <parameters>
+ <viewDataTable>graphVerticalBar</viewDataTable>
+ <module>VisitTime</module>
+ <action>getVisitInformationPerServerTime</action>
+ </parameters>
+ <uniqueId>widgetVisitTimegetVisitInformationPerServerTimeviewDataTablegraphVerticalBar</uniqueId>
+ <viewDataTable>graphVerticalBar</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Visits per local time</name>
+ <category>
+ <name>Visitors</name>
+ <order>5</order>
+ <id>General_Visitors</id>
+ </category>
+ <subcategory>
+ <name>Times</name>
+ <order>35</order>
+ <id>VisitTime_SubmenuTimes</id>
+ </subcategory>
+ <module>VisitTime</module>
+ <action>getVisitInformationPerLocalTime</action>
+ <order>115</order>
+ <parameters>
+ <viewDataTable>graphVerticalBar</viewDataTable>
+ <module>VisitTime</module>
+ <action>getVisitInformationPerLocalTime</action>
+ </parameters>
+ <uniqueId>widgetVisitTimegetVisitInformationPerLocalTimeviewDataTablegraphVerticalBar</uniqueId>
+ <viewDataTable>graphVerticalBar</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Visits by Day of Week</name>
+ <category>
+ <name>Visitors</name>
+ <order>5</order>
+ <id>General_Visitors</id>
+ </category>
+ <subcategory>
+ <name>Times</name>
+ <order>35</order>
+ <id>VisitTime_SubmenuTimes</id>
+ </subcategory>
+ <module>VisitTime</module>
+ <action>getByDayOfWeek</action>
+ <order>125</order>
+ <parameters>
+ <viewDataTable>graphVerticalBar</viewDataTable>
+ <module>VisitTime</module>
+ <action>getByDayOfWeek</action>
+ </parameters>
+ <uniqueId>widgetVisitTimegetByDayOfWeekviewDataTablegraphVerticalBar</uniqueId>
+ <viewDataTable>graphVerticalBar</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Real-time Map</name>
+ <category>
+ <name>Visitors</name>
+ <order>5</order>
+ <id>General_Visitors</id>
+ </category>
+ <subcategory>
+ <name>Real-time Map</name>
+ <order>40</order>
+ <id>UserCountryMap_RealTimeMap</id>
+ </subcategory>
+ <module>UserCountryMap</module>
+ <action>realtimeMap</action>
+ <order>5</order>
+ <parameters>
+ <module>UserCountryMap</module>
+ <action>realtimeMap</action>
+ </parameters>
+ <uniqueId>widgetUserCountryMaprealtimeMap</uniqueId>
+ </row>
+ <row>
+ <name>Pages</name>
+ <category>
+ <name>Actions</name>
+ <order>10</order>
+ <id>General_Actions</id>
+ </category>
+ <subcategory>
+ <name>Pages</name>
+ <order>5</order>
+ <id>General_Pages</id>
+ </subcategory>
+ <module>Actions</module>
+ <action>getPageUrls</action>
+ <order>102</order>
+ <parameters>
+ <module>Actions</module>
+ <action>getPageUrls</action>
+ </parameters>
+ <uniqueId>widgetActionsgetPageUrls</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Entry pages</name>
+ <category>
+ <name>Actions</name>
+ <order>10</order>
+ <id>General_Actions</id>
+ </category>
+ <subcategory>
+ <name>Entry pages</name>
+ <order>10</order>
+ <id>Actions_SubmenuPagesEntry</id>
+ </subcategory>
+ <module>Actions</module>
+ <action>getEntryPageUrls</action>
+ <order>103</order>
+ <parameters>
+ <module>Actions</module>
+ <action>getEntryPageUrls</action>
+ </parameters>
+ <uniqueId>widgetActionsgetEntryPageUrls</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Exit pages</name>
+ <category>
+ <name>Actions</name>
+ <order>10</order>
+ <id>General_Actions</id>
+ </category>
+ <subcategory>
+ <name>Exit pages</name>
+ <order>15</order>
+ <id>Actions_SubmenuPagesExit</id>
+ </subcategory>
+ <module>Actions</module>
+ <action>getExitPageUrls</action>
+ <order>104</order>
+ <parameters>
+ <module>Actions</module>
+ <action>getExitPageUrls</action>
+ </parameters>
+ <uniqueId>widgetActionsgetExitPageUrls</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Page titles</name>
+ <category>
+ <name>Actions</name>
+ <order>10</order>
+ <id>General_Actions</id>
+ </category>
+ <subcategory>
+ <name>Page titles</name>
+ <order>20</order>
+ <id>Actions_SubmenuPageTitles</id>
+ </subcategory>
+ <module>Actions</module>
+ <action>getPageTitles</action>
+ <order>105</order>
+ <parameters>
+ <module>Actions</module>
+ <action>getPageTitles</action>
+ </parameters>
+ <uniqueId>widgetActionsgetPageTitles</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Site Search Keywords</name>
+ <category>
+ <name>Actions</name>
+ <order>10</order>
+ <id>General_Actions</id>
+ </category>
+ <subcategory>
+ <name>Site Search</name>
+ <order>25</order>
+ <id>Actions_SubmenuSitesearch</id>
+ </subcategory>
+ <module>Actions</module>
+ <action>getSiteSearchKeywords</action>
+ <order>115</order>
+ <parameters>
+ <module>Actions</module>
+ <action>getSiteSearchKeywords</action>
+ </parameters>
+ <uniqueId>widgetActionsgetSiteSearchKeywords</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Search Keywords with No Results</name>
+ <category>
+ <name>Actions</name>
+ <order>10</order>
+ <id>General_Actions</id>
+ </category>
+ <subcategory>
+ <name>Site Search</name>
+ <order>25</order>
+ <id>Actions_SubmenuSitesearch</id>
+ </subcategory>
+ <module>Actions</module>
+ <action>getSiteSearchNoResultKeywords</action>
+ <order>118</order>
+ <parameters>
+ <module>Actions</module>
+ <action>getSiteSearchNoResultKeywords</action>
+ </parameters>
+ <uniqueId>widgetActionsgetSiteSearchNoResultKeywords</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Page Titles Following a Site Search</name>
+ <category>
+ <name>Actions</name>
+ <order>10</order>
+ <id>General_Actions</id>
+ </category>
+ <subcategory>
+ <name>Site Search</name>
+ <order>25</order>
+ <id>Actions_SubmenuSitesearch</id>
+ </subcategory>
+ <module>Actions</module>
+ <action>getPageTitlesFollowingSiteSearch</action>
+ <order>119</order>
+ <parameters>
+ <module>Actions</module>
+ <action>getPageTitlesFollowingSiteSearch</action>
+ </parameters>
+ <uniqueId>widgetActionsgetPageTitlesFollowingSiteSearch</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Pages Following a Site Search</name>
+ <category>
+ <name>Actions</name>
+ <order>10</order>
+ <id>General_Actions</id>
+ </category>
+ <subcategory>
+ <name>Site Search</name>
+ <order>25</order>
+ <id>Actions_SubmenuSitesearch</id>
+ </subcategory>
+ <module>Actions</module>
+ <action>getPageUrlsFollowingSiteSearch</action>
+ <order>116</order>
+ <parameters>
+ <module>Actions</module>
+ <action>getPageUrlsFollowingSiteSearch</action>
+ </parameters>
+ <uniqueId>widgetActionsgetPageUrlsFollowingSiteSearch</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Search Categories</name>
+ <category>
+ <name>Actions</name>
+ <order>10</order>
+ <id>General_Actions</id>
+ </category>
+ <subcategory>
+ <name>Site Search</name>
+ <order>25</order>
+ <id>Actions_SubmenuSitesearch</id>
+ </subcategory>
+ <module>Actions</module>
+ <action>getSiteSearchCategories</action>
+ <order>120</order>
+ <parameters>
+ <module>Actions</module>
+ <action>getSiteSearchCategories</action>
+ </parameters>
+ <uniqueId>widgetActionsgetSiteSearchCategories</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Entry Page Titles</name>
+ <category>
+ <name>Actions</name>
+ <order>10</order>
+ <id>General_Actions</id>
+ </category>
+ <subcategory />
+ <module>Actions</module>
+ <action>getEntryPageTitles</action>
+ <order>106</order>
+ <parameters>
+ <module>Actions</module>
+ <action>getEntryPageTitles</action>
+ </parameters>
+ <uniqueId>widgetActionsgetEntryPageTitles</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Exit page titles</name>
+ <category>
+ <name>Actions</name>
+ <order>10</order>
+ <id>General_Actions</id>
+ </category>
+ <subcategory />
+ <module>Actions</module>
+ <action>getExitPageTitles</action>
+ <order>107</order>
+ <parameters>
+ <module>Actions</module>
+ <action>getExitPageTitles</action>
+ </parameters>
+ <uniqueId>widgetActionsgetExitPageTitles</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Outlinks</name>
+ <category>
+ <name>Actions</name>
+ <order>10</order>
+ <id>General_Actions</id>
+ </category>
+ <subcategory>
+ <name>Outlinks</name>
+ <order>30</order>
+ <id>General_Outlinks</id>
+ </subcategory>
+ <module>Actions</module>
+ <action>getOutlinks</action>
+ <order>108</order>
+ <parameters>
+ <module>Actions</module>
+ <action>getOutlinks</action>
+ </parameters>
+ <uniqueId>widgetActionsgetOutlinks</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Downloads</name>
+ <category>
+ <name>Actions</name>
+ <order>10</order>
+ <id>General_Actions</id>
+ </category>
+ <subcategory>
+ <name>Downloads</name>
+ <order>35</order>
+ <id>General_Downloads</id>
+ </subcategory>
+ <module>Actions</module>
+ <action>getDownloads</action>
+ <order>109</order>
+ <parameters>
+ <module>Actions</module>
+ <action>getDownloads</action>
+ </parameters>
+ <uniqueId>widgetActionsgetDownloads</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Event Names</name>
+ <category>
+ <name>Actions</name>
+ <order>10</order>
+ <id>General_Actions</id>
+ </category>
+ <subcategory>
+ <name>Events</name>
+ <order>40</order>
+ <id>Events_Events</id>
+ </subcategory>
+ <module>Events</module>
+ <action>getName</action>
+ <order>102</order>
+ <parameters>
+ <module>Events</module>
+ <action>getName</action>
+ <secondaryDimension>eventAction</secondaryDimension>
+ </parameters>
+ <uniqueId>widgetEventsgetNamesecondaryDimensioneventAction</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Event Categories</name>
+ <category>
+ <name>Actions</name>
+ <order>10</order>
+ <id>General_Actions</id>
+ </category>
+ <subcategory>
+ <name>Events</name>
+ <order>40</order>
+ <id>Events_Events</id>
+ </subcategory>
+ <module>Events</module>
+ <action>getCategory</action>
+ <order>100</order>
+ <parameters>
+ <module>Events</module>
+ <action>getCategory</action>
+ <secondaryDimension>eventAction</secondaryDimension>
+ </parameters>
+ <uniqueId>widgetEventsgetCategorysecondaryDimensioneventAction</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Event Actions</name>
+ <category>
+ <name>Actions</name>
+ <order>10</order>
+ <id>General_Actions</id>
+ </category>
+ <subcategory>
+ <name>Events</name>
+ <order>40</order>
+ <id>Events_Events</id>
+ </subcategory>
+ <module>Events</module>
+ <action>getAction</action>
+ <order>101</order>
+ <parameters>
+ <module>Events</module>
+ <action>getAction</action>
+ <secondaryDimension>eventName</secondaryDimension>
+ </parameters>
+ <uniqueId>widgetEventsgetActionsecondaryDimensioneventName</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Content Name</name>
+ <category>
+ <name>Actions</name>
+ <order>10</order>
+ <id>General_Actions</id>
+ </category>
+ <subcategory>
+ <name>Contents</name>
+ <order>45</order>
+ <id>Contents_Contents</id>
+ </subcategory>
+ <module>Contents</module>
+ <action>getContentNames</action>
+ <order>135</order>
+ <parameters>
+ <module>Contents</module>
+ <action>getContentNames</action>
+ </parameters>
+ <uniqueId>widgetContentsgetContentNames</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Content Piece</name>
+ <category>
+ <name>Actions</name>
+ <order>10</order>
+ <id>General_Actions</id>
+ </category>
+ <subcategory>
+ <name>Contents</name>
+ <order>45</order>
+ <id>Contents_Contents</id>
+ </subcategory>
+ <module>Contents</module>
+ <action>getContentPieces</action>
+ <order>136</order>
+ <parameters>
+ <module>Contents</module>
+ <action>getContentPieces</action>
+ </parameters>
+ <uniqueId>widgetContentsgetContentPieces</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Referrer Types</name>
+ <category>
+ <name>Referrers</name>
+ <order>15</order>
+ <id>Referrers_Referrers</id>
+ </category>
+ <subcategory>
+ <name>All Referrers</name>
+ <order>5</order>
+ <id>Referrers_WidgetGetAll</id>
+ </subcategory>
+ <module>Referrers</module>
+ <action>getReferrerType</action>
+ <order>101</order>
+ <parameters>
+ <viewDataTable>tableAllColumns</viewDataTable>
+ <module>Referrers</module>
+ <action>getReferrerType</action>
+ </parameters>
+ <uniqueId>widgetReferrersgetReferrerTypeviewDataTabletableAllColumns</uniqueId>
+ <viewDataTable>tableAllColumns</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Referrers</name>
+ <category>
+ <name>Referrers</name>
+ <order>15</order>
+ <id>Referrers_Referrers</id>
+ </category>
+ <subcategory>
+ <name>All Referrers</name>
+ <order>5</order>
+ <id>Referrers_WidgetGetAll</id>
+ </subcategory>
+ <module>Referrers</module>
+ <action>getAll</action>
+ <order>102</order>
+ <parameters>
+ <viewDataTable>tableAllColumns</viewDataTable>
+ <module>Referrers</module>
+ <action>getAll</action>
+ </parameters>
+ <uniqueId>widgetReferrersgetAllviewDataTabletableAllColumns</uniqueId>
+ <viewDataTable>tableAllColumns</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Search Engines</name>
+ <category>
+ <name>Referrers</name>
+ <order>15</order>
+ <id>Referrers_Referrers</id>
+ </category>
+ <subcategory>
+ <name>Search Engines &amp; Keywords</name>
+ <order>10</order>
+ <id>Referrers_SubmenuSearchEngines</id>
+ </subcategory>
+ <module>Referrers</module>
+ <action>getSearchEngines</action>
+ <order>107</order>
+ <parameters>
+ <module>Referrers</module>
+ <action>getSearchEngines</action>
+ </parameters>
+ <uniqueId>widgetReferrersgetSearchEngines</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Keywords</name>
+ <category>
+ <name>Referrers</name>
+ <order>15</order>
+ <id>Referrers_Referrers</id>
+ </category>
+ <subcategory>
+ <name>Search Engines &amp; Keywords</name>
+ <order>10</order>
+ <id>Referrers_SubmenuSearchEngines</id>
+ </subcategory>
+ <module>Referrers</module>
+ <action>getKeywords</action>
+ <order>103</order>
+ <parameters>
+ <module>Referrers</module>
+ <action>getKeywords</action>
+ </parameters>
+ <uniqueId>widgetReferrersgetKeywords</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Social Networks</name>
+ <category>
+ <name>Referrers</name>
+ <order>15</order>
+ <id>Referrers_Referrers</id>
+ </category>
+ <subcategory>
+ <name>Websites &amp; Social</name>
+ <order>15</order>
+ <id>Referrers_SubmenuWebsites</id>
+ </subcategory>
+ <module>Referrers</module>
+ <action>getSocials</action>
+ <order>111</order>
+ <parameters>
+ <viewDataTable>graphPie</viewDataTable>
+ <module>Referrers</module>
+ <action>getSocials</action>
+ </parameters>
+ <uniqueId>widgetReferrersgetSocialsviewDataTablegraphPie</uniqueId>
+ <viewDataTable>graphPie</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Websites</name>
+ <category>
+ <name>Referrers</name>
+ <order>15</order>
+ <id>Referrers_Referrers</id>
+ </category>
+ <subcategory>
+ <name>Websites &amp; Social</name>
+ <order>15</order>
+ <id>Referrers_SubmenuWebsites</id>
+ </subcategory>
+ <module>Referrers</module>
+ <action>getWebsites</action>
+ <order>105</order>
+ <parameters>
+ <module>Referrers</module>
+ <action>getWebsites</action>
+ </parameters>
+ <uniqueId>widgetReferrersgetWebsites</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Campaigns</name>
+ <category>
+ <name>Referrers</name>
+ <order>15</order>
+ <id>Referrers_Referrers</id>
+ </category>
+ <subcategory>
+ <name>Campaigns</name>
+ <order>20</order>
+ <id>Referrers_Campaigns</id>
+ </subcategory>
+ <module>Referrers</module>
+ <action>getCampaigns</action>
+ <order>109</order>
+ <parameters>
+ <module>Referrers</module>
+ <action>getCampaigns</action>
+ </parameters>
+ <uniqueId>widgetReferrersgetCampaigns</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Overview</name>
+ <category>
+ <name>Ecommerce</name>
+ <order>20</order>
+ <id>Goals_Ecommerce</id>
+ </category>
+ <subcategory>
+ <name>Overview</name>
+ <order>2</order>
+ <id>General_Overview</id>
+ </subcategory>
+ <module>CoreHome</module>
+ <action>renderWidgetContainer</action>
+ <order>9</order>
+ <parameters>
+ <module>CoreHome</module>
+ <action>renderWidgetContainer</action>
+ <containerId>EcommerceOverview</containerId>
+ </parameters>
+ <uniqueId>widgetEcommerceOverview</uniqueId>
+ <layout />
+ <isContainer>1</isContainer>
+ </row>
+ <row>
+ <name>Ecommerce Log</name>
+ <category>
+ <name>Ecommerce</name>
+ <order>20</order>
+ <id>Goals_Ecommerce</id>
+ </category>
+ <subcategory>
+ <name>Ecommerce Log</name>
+ <order>5</order>
+ <id>Goals_EcommerceLog</id>
+ </subcategory>
+ <module>Ecommerce</module>
+ <action>getEcommerceLog</action>
+ <order>99</order>
+ <parameters>
+ <module>Ecommerce</module>
+ <action>getEcommerceLog</action>
+ </parameters>
+ <uniqueId>widgetEcommercegetEcommerceLog</uniqueId>
+ </row>
+ <row>
+ <name>Product Name</name>
+ <category>
+ <name>Ecommerce</name>
+ <order>20</order>
+ <id>Goals_Ecommerce</id>
+ </category>
+ <subcategory>
+ <name>Products</name>
+ <order>10</order>
+ <id>Goals_Products</id>
+ </subcategory>
+ <module>Goals</module>
+ <action>getItemsName</action>
+ <order>131</order>
+ <parameters>
+ <module>Goals</module>
+ <action>getItemsName</action>
+ <abandonedCarts>1</abandonedCarts>
+ </parameters>
+ <uniqueId>widgetGoalsgetItemsNameabandonedCarts1</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Product Category</name>
+ <category>
+ <name>Ecommerce</name>
+ <order>20</order>
+ <id>Goals_Ecommerce</id>
+ </category>
+ <subcategory>
+ <name>Products</name>
+ <order>10</order>
+ <id>Goals_Products</id>
+ </subcategory>
+ <module>Goals</module>
+ <action>getItemsCategory</action>
+ <order>132</order>
+ <parameters>
+ <module>Goals</module>
+ <action>getItemsCategory</action>
+ <abandonedCarts>1</abandonedCarts>
+ </parameters>
+ <uniqueId>widgetGoalsgetItemsCategoryabandonedCarts1</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Product SKU</name>
+ <category>
+ <name>Ecommerce</name>
+ <order>20</order>
+ <id>Goals_Ecommerce</id>
+ </category>
+ <subcategory>
+ <name>Products</name>
+ <order>10</order>
+ <id>Goals_Products</id>
+ </subcategory>
+ <module>Goals</module>
+ <action>getItemsSku</action>
+ <order>130</order>
+ <parameters>
+ <module>Goals</module>
+ <action>getItemsSku</action>
+ <abandonedCarts>1</abandonedCarts>
+ </parameters>
+ <uniqueId>widgetGoalsgetItemsSkuabandonedCarts1</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Overview</name>
+ <category>
+ <name>Goals</name>
+ <order>25</order>
+ <id>Goals_Goals</id>
+ </category>
+ <subcategory>
+ <name>Overview</name>
+ <order>2</order>
+ <id>General_Overview</id>
+ </subcategory>
+ <module>CoreHome</module>
+ <action>renderWidgetContainer</action>
+ <order>6</order>
+ <parameters>
+ <module>CoreHome</module>
+ <action>renderWidgetContainer</action>
+ <containerId>GoalsOverview</containerId>
+ </parameters>
+ <uniqueId>widgetGoalsOverview</uniqueId>
+ <layout />
+ <isContainer>1</isContainer>
+ </row>
+ <row>
+ <name>Goal 1 - Thank you</name>
+ <category>
+ <name>Goals</name>
+ <order>25</order>
+ <id>Goals_Goals</id>
+ </category>
+ <subcategory>
+ <name>Goal 1 - Thank you</name>
+ <order>900</order>
+ <id>1</id>
+ </subcategory>
+ <module>CoreHome</module>
+ <action>renderWidgetContainer</action>
+ <order>13</order>
+ <parameters>
+ <module>CoreHome</module>
+ <action>renderWidgetContainer</action>
+ <containerId>Goal_1</containerId>
+ </parameters>
+ <uniqueId>widgetGoal_1</uniqueId>
+ <layout />
+ <isContainer>1</isContainer>
+ </row>
+ <row>
+ <name>Goal 2 - Hello</name>
+ <category>
+ <name>Goals</name>
+ <order>25</order>
+ <id>Goals_Goals</id>
+ </category>
+ <subcategory>
+ <name>Goal 2 - Hello</name>
+ <order>901</order>
+ <id>2</id>
+ </subcategory>
+ <module>CoreHome</module>
+ <action>renderWidgetContainer</action>
+ <order>17</order>
+ <parameters>
+ <module>CoreHome</module>
+ <action>renderWidgetContainer</action>
+ <containerId>Goal_2</containerId>
+ </parameters>
+ <uniqueId>widgetGoal_2</uniqueId>
+ <layout />
+ <isContainer>1</isContainer>
+ </row>
+ <row>
+ <name>triggered js</name>
+ <category>
+ <name>Goals</name>
+ <order>25</order>
+ <id>Goals_Goals</id>
+ </category>
+ <subcategory>
+ <name>triggered js</name>
+ <order>902</order>
+ <id>3</id>
+ </subcategory>
+ <module>CoreHome</module>
+ <action>renderWidgetContainer</action>
+ <order>22</order>
+ <parameters>
+ <module>CoreHome</module>
+ <action>renderWidgetContainer</action>
+ <containerId>Goal_3</containerId>
+ </parameters>
+ <uniqueId>widgetGoal_3</uniqueId>
+ <layout />
+ <isContainer>1</isContainer>
+ </row>
+ <row>
+ <name>Data tables</name>
+ <category>
+ <name>UI Framework</name>
+ <order>90</order>
+ <id>ExampleUI_UiFramework</id>
+ </category>
+ <subcategory>
+ <name>Data tables</name>
+ <order>99</order>
+ <id>ExampleUI_GetTemperaturesDataTable</id>
+ </subcategory>
+ <module>ExampleUI</module>
+ <action>getTemperatures</action>
+ <order>210</order>
+ <parameters>
+ <module>ExampleUI</module>
+ <action>getTemperatures</action>
+ </parameters>
+ <uniqueId>widgetExampleUIgetTemperatures</uniqueId>
+ <viewDataTable>table</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Data tables</name>
+ <category>
+ <name>UI Framework</name>
+ <order>90</order>
+ <id>ExampleUI_UiFramework</id>
+ </category>
+ <subcategory>
+ <name>Bar graph</name>
+ <order>99</order>
+ <id>Bar graph</id>
+ </subcategory>
+ <module>ExampleUI</module>
+ <action>getTemperatures</action>
+ <order>210</order>
+ <parameters>
+ <forceView>1</forceView>
+ <viewDataTable>graphVerticalBar</viewDataTable>
+ <module>ExampleUI</module>
+ <action>getTemperatures</action>
+ </parameters>
+ <uniqueId>widgetExampleUIgetTemperaturesforceView1viewDataTablegraphVerticalBar</uniqueId>
+ <viewDataTable>graphVerticalBar</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Temperatures evolution over time</name>
+ <category>
+ <name>UI Framework</name>
+ <order>90</order>
+ <id>ExampleUI_UiFramework</id>
+ </category>
+ <subcategory>
+ <name>Sparklines</name>
+ <order>99</order>
+ <id>Sparklines</id>
+ </subcategory>
+ <module>ExampleUI</module>
+ <action>getTemperaturesEvolution</action>
+ <order>211</order>
+ <parameters>
+ <forceView>1</forceView>
+ <viewDataTable>sparklines</viewDataTable>
+ <module>ExampleUI</module>
+ <action>getTemperaturesEvolution</action>
+ </parameters>
+ <uniqueId>widgetExampleUIgetTemperaturesEvolutionforceView1viewDataTablesparklines</uniqueId>
+ <viewDataTable>sparklines</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Treemap example</name>
+ <category>
+ <name>UI Framework</name>
+ <order>90</order>
+ <id>ExampleUI_UiFramework</id>
+ </category>
+ <subcategory>
+ <name>Treemap</name>
+ <order>99</order>
+ <id>Treemap</id>
+ </subcategory>
+ <module>ExampleUI</module>
+ <action>getTemperatures</action>
+ <order>210</order>
+ <parameters>
+ <forceView>1</forceView>
+ <viewDataTable>infoviz-treemap</viewDataTable>
+ <module>ExampleUI</module>
+ <action>getTemperatures</action>
+ </parameters>
+ <uniqueId>widgetExampleUIgetTemperaturesforceView1viewDataTableinfoviz-treemap</uniqueId>
+ <viewDataTable>infoviz-treemap</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Simple tag cloud</name>
+ <category>
+ <name>UI Framework</name>
+ <order>90</order>
+ <id>ExampleUI_UiFramework</id>
+ </category>
+ <subcategory>
+ <name>Tag clouds</name>
+ <order>99</order>
+ <id>Tag clouds</id>
+ </subcategory>
+ <module>ExampleUI</module>
+ <action>getPlanetRatios</action>
+ <order>5</order>
+ <parameters>
+ <forceView>1</forceView>
+ <viewDataTable>cloud</viewDataTable>
+ <module>ExampleUI</module>
+ <action>getPlanetRatios</action>
+ </parameters>
+ <uniqueId>widgetExampleUIgetPlanetRatiosforceView1viewDataTablecloud</uniqueId>
+ <viewDataTable>cloud</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Advanced tag cloud: with logos and links</name>
+ <category>
+ <name>UI Framework</name>
+ <order>90</order>
+ <id>ExampleUI_UiFramework</id>
+ </category>
+ <subcategory>
+ <name>Tag clouds</name>
+ <order>99</order>
+ <id>Tag clouds</id>
+ </subcategory>
+ <module>ExampleUI</module>
+ <action>getPlanetRatiosWithLogos</action>
+ <order>213</order>
+ <parameters>
+ <viewDataTable>cloud</viewDataTable>
+ <module>ExampleUI</module>
+ <action>getPlanetRatiosWithLogos</action>
+ </parameters>
+ <uniqueId>widgetExampleUIgetPlanetRatiosWithLogosviewDataTablecloud</uniqueId>
+ <viewDataTable>cloud</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Evolution of server temperatures over the last few days</name>
+ <category>
+ <name>UI Framework</name>
+ <order>90</order>
+ <id>ExampleUI_UiFramework</id>
+ </category>
+ <subcategory>
+ <name>Evolution Graph</name>
+ <order>99</order>
+ <id>Evolution Graph</id>
+ </subcategory>
+ <module>ExampleUI</module>
+ <action>getTemperaturesEvolution</action>
+ <order>211</order>
+ <parameters>
+ <forceView>1</forceView>
+ <viewDataTable>graphEvolution</viewDataTable>
+ <module>ExampleUI</module>
+ <action>getTemperaturesEvolution</action>
+ <columns>
+ <row>server1</row>
+ <row>server2</row>
+ </columns>
+ </parameters>
+ <uniqueId>widgetExampleUIgetTemperaturesEvolutionforceView1viewDataTablegraphEvolutioncolumnsArray</uniqueId>
+ <viewDataTable>graphEvolution</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Pie graph</name>
+ <category>
+ <name>UI Framework</name>
+ <order>90</order>
+ <id>ExampleUI_UiFramework</id>
+ </category>
+ <subcategory>
+ <name>Pie graph</name>
+ <order>99</order>
+ <id>Pie graph</id>
+ </subcategory>
+ <module>ExampleUI</module>
+ <action>getPlanetRatios</action>
+ <order>212</order>
+ <parameters>
+ <viewDataTable>graphPie</viewDataTable>
+ <module>ExampleUI</module>
+ <action>getPlanetRatios</action>
+ </parameters>
+ <uniqueId>widgetExampleUIgetPlanetRatiosviewDataTablegraphPie</uniqueId>
+ <viewDataTable>graphPie</viewDataTable>
+ <isReport>1</isReport>
+ </row>
+ <row>
+ <name>Insights Overview</name>
+ <category>
+ <name>Insights</name>
+ <order>99</order>
+ <id>Insights_WidgetCategory</id>
+ </category>
+ <subcategory />
+ <module>Insights</module>
+ <action>getInsightsOverview</action>
+ <order>99</order>
+ <parameters>
+ <module>Insights</module>
+ <action>getInsightsOverview</action>
+ </parameters>
+ <uniqueId>widgetInsightsgetInsightsOverview</uniqueId>
+ </row>
+ <row>
+ <name>Top Keywords for Page URL</name>
+ <category>
+ <name>SEO</name>
+ <order>99</order>
+ <id>SEO</id>
+ </category>
+ <subcategory />
+ <module>Referrers</module>
+ <action>getKeywordsForPage</action>
+ <order>99</order>
+ <parameters>
+ <module>Referrers</module>
+ <action>getKeywordsForPage</action>
+ </parameters>
+ <uniqueId>widgetReferrersgetKeywordsForPage</uniqueId>
+ </row>
+ <row>
+ <name>Piwik Changelog</name>
+ <category>
+ <name>Example Widgets</name>
+ <order>99</order>
+ <id>Example Widgets</id>
+ </category>
+ <subcategory />
+ <module>ExampleRssWidget</module>
+ <action>rssChangelog</action>
+ <order>99</order>
+ <parameters>
+ <module>ExampleRssWidget</module>
+ <action>rssChangelog</action>
+ </parameters>
+ <uniqueId>widgetExampleRssWidgetrssChangelog</uniqueId>
+ </row>
+ <row>
+ <name>Movers and Shakers</name>
+ <category>
+ <name>Insights</name>
+ <order>99</order>
+ <id>Insights_WidgetCategory</id>
+ </category>
+ <subcategory />
+ <module>Insights</module>
+ <action>getOverallMoversAndShakers</action>
+ <order>99</order>
+ <parameters>
+ <module>Insights</module>
+ <action>getOverallMoversAndShakers</action>
+ </parameters>
+ <uniqueId>widgetInsightsgetOverallMoversAndShakers</uniqueId>
+ </row>
+ <row>
+ <name>Example Widget Name</name>
+ <category>
+ <name>Example Widgets</name>
+ <order>99</order>
+ <id>Example Widgets</id>
+ </category>
+ <subcategory />
+ <module>ExamplePlugin</module>
+ <action>myExampleWidget</action>
+ <order>99</order>
+ <parameters>
+ <module>ExamplePlugin</module>
+ <action>myExampleWidget</action>
+ </parameters>
+ <uniqueId>widgetExamplePluginmyExampleWidget</uniqueId>
+ </row>
+ <row>
+ <name>SEO Rankings</name>
+ <category>
+ <name>SEO</name>
+ <order>99</order>
+ <id>SEO</id>
+ </category>
+ <subcategory />
+ <module>SEO</module>
+ <action>getRank</action>
+ <order>99</order>
+ <parameters>
+ <module>SEO</module>
+ <action>getRank</action>
+ </parameters>
+ <uniqueId>widgetSEOgetRank</uniqueId>
+ </row>
+ <row>
+ <name>Piwik.org Blog</name>
+ <category>
+ <name>Example Widgets</name>
+ <order>99</order>
+ <id>Example Widgets</id>
+ </category>
+ <subcategory />
+ <module>ExampleRssWidget</module>
+ <action>rssPiwik</action>
+ <order>99</order>
+ <parameters>
+ <module>ExampleRssWidget</module>
+ <action>rssPiwik</action>
+ </parameters>
+ <uniqueId>widgetExampleRssWidgetrssPiwik</uniqueId>
+ </row>
+ <row>
+ <name>Welcome!</name>
+ <category>
+ <name>Example Widgets</name>
+ <order>99</order>
+ <id>Example Widgets</id>
+ </category>
+ <subcategory />
+ <module>CoreHome</module>
+ <action>getPromoVideo</action>
+ <order>10</order>
+ <parameters>
+ <module>CoreHome</module>
+ <action>getPromoVideo</action>
+ </parameters>
+ <uniqueId>widgetCoreHomegetPromoVideo</uniqueId>
+ </row>
+ <row>
+ <name>Support Piwik!</name>
+ <category>
+ <name>Example Widgets</name>
+ <order>99</order>
+ <id>Example Widgets</id>
+ </category>
+ <subcategory />
+ <module>CoreHome</module>
+ <action>getDonateForm</action>
+ <order>5</order>
+ <parameters>
+ <module>CoreHome</module>
+ <action>getDonateForm</action>
+ </parameters>
+ <uniqueId>widgetCoreHomegetDonateForm</uniqueId>
+ </row>
+</result> \ No newline at end of file
diff --git a/tests/PHPUnit/System/expected/test_apiGetReportMetadata_showRawMetrics__API.getProcessedReport_day.xml b/tests/PHPUnit/System/expected/test_apiGetReportMetadata_showRawMetrics__API.getProcessedReport_day.xml
index 454018b7d3..e6a02bc533 100644
--- a/tests/PHPUnit/System/expected/test_apiGetReportMetadata_showRawMetrics__API.getProcessedReport_day.xml
+++ b/tests/PHPUnit/System/expected/test_apiGetReportMetadata_showRawMetrics__API.getProcessedReport_day.xml
@@ -4,6 +4,7 @@
<prettyDate>Sunday, January 4, 2009</prettyDate>
<metadata>
<category>Visitors</category>
+ <subcategory>Locations</subcategory>
<name>Country</name>
<module>UserCountry</module>
<action>getCountry</action>
diff --git a/tests/PHPUnit/System/expected/test_apiGetReportMetadata_year__API.getProcessedReport_year.xml b/tests/PHPUnit/System/expected/test_apiGetReportMetadata_year__API.getProcessedReport_year.xml
index 4dc81bddda..775bc1b478 100644
--- a/tests/PHPUnit/System/expected/test_apiGetReportMetadata_year__API.getProcessedReport_year.xml
+++ b/tests/PHPUnit/System/expected/test_apiGetReportMetadata_year__API.getProcessedReport_year.xml
@@ -4,6 +4,7 @@
<prettyDate>2009</prettyDate>
<metadata>
<category>Visiteurs</category>
+ <subcategory>Provenances géographiques</subcategory>
<name>Pays</name>
<module>UserCountry</module>
<action>getCountry</action>
diff --git a/tests/PHPUnit/System/expected/test_csvExport_xp0__CustomVariables.getCustomVariables_day.csv b/tests/PHPUnit/System/expected/test_csvExport_xp0__CustomVariables.getCustomVariables_day.csv
index d8449e77cd..d04f027adf 100644
--- a/tests/PHPUnit/System/expected/test_csvExport_xp0__CustomVariables.getCustomVariables_day.csv
+++ b/tests/PHPUnit/System/expected/test_csvExport_xp0__CustomVariables.getCustomVariables_day.csv
Binary files differ
diff --git a/tests/PHPUnit/System/expected/test_csvExport_xp1_inner1_trans-de__CustomVariables.getCustomVariables_day.csv b/tests/PHPUnit/System/expected/test_csvExport_xp1_inner1_trans-de__CustomVariables.getCustomVariables_day.csv
index 8372bb607e..489da99277 100644
--- a/tests/PHPUnit/System/expected/test_csvExport_xp1_inner1_trans-de__CustomVariables.getCustomVariables_day.csv
+++ b/tests/PHPUnit/System/expected/test_csvExport_xp1_inner1_trans-de__CustomVariables.getCustomVariables_day.csv
Binary files differ
diff --git a/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_Metadata_ItemsCategory__API.getProcessedReport_day.xml b/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_Metadata_ItemsCategory__API.getProcessedReport_day.xml
index 96a06e075f..697e009693 100644
--- a/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_Metadata_ItemsCategory__API.getProcessedReport_day.xml
+++ b/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_Metadata_ItemsCategory__API.getProcessedReport_day.xml
@@ -4,6 +4,7 @@
<prettyDate>Tuesday, April 5, 2011</prettyDate>
<metadata>
<category>Ecommerce</category>
+ <subcategory>Products</subcategory>
<name>Product Category</name>
<module>Goals</module>
<action>getItemsCategory</action>
diff --git a/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_Metadata_ItemsSku__API.getProcessedReport_day.xml b/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_Metadata_ItemsSku__API.getProcessedReport_day.xml
index 34a12b5b11..7ec412b5c4 100644
--- a/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_Metadata_ItemsSku__API.getProcessedReport_day.xml
+++ b/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_Metadata_ItemsSku__API.getProcessedReport_day.xml
@@ -4,6 +4,7 @@
<prettyDate>Tuesday, April 5, 2011</prettyDate>
<metadata>
<category>Ecommerce</category>
+ <subcategory>Products</subcategory>
<name>Product SKU</name>
<module>Goals</module>
<action>getItemsSku</action>
diff --git a/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_Metadata_VisitTime.getVisitInformationPerServerTime__API.getProcessedReport_day.xml b/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_Metadata_VisitTime.getVisitInformationPerServerTime__API.getProcessedReport_day.xml
index e885f8b006..26e64dd585 100755
--- a/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_Metadata_VisitTime.getVisitInformationPerServerTime__API.getProcessedReport_day.xml
+++ b/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_Metadata_VisitTime.getVisitInformationPerServerTime__API.getProcessedReport_day.xml
@@ -3,8 +3,9 @@
<website>Piwik test</website>
<prettyDate>Tuesday, April 5, 2011</prettyDate>
<metadata>
- <category>Visits Summary</category>
- <name>Visits by Server Time</name>
+ <category>Visitors</category>
+ <subcategory>Times</subcategory>
+ <name>Visits per server time</name>
<module>VisitTime</module>
<action>getVisitInformationPerServerTime</action>
<dimension>Server time</dimension>
diff --git a/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_SegmentPageUrlContains__Goals.getItemsName_day.xml b/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_SegmentPageUrlContains__Goals.getItemsName_day.xml
index adf6066750..4d8563a99e 100644
--- a/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_SegmentPageUrlContains__Goals.getItemsName_day.xml
+++ b/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_SegmentPageUrlContains__Goals.getItemsName_day.xml
@@ -31,20 +31,20 @@
<conversion_rate>0%</conversion_rate>
</row>
<row>
- <label>PRODUCT THREE LEFT in cart</label>
+ <label>PRODUCT TWO LEFT in cart</label>
<nb_uniq_visitors>1</nb_uniq_visitors>
<nb_visits>2</nb_visits>
- <nb_actions>4</nb_actions>
- <avg_price>666</avg_price>
+ <nb_actions>2</nb_actions>
+ <avg_price>0</avg_price>
<avg_quantity>0</avg_quantity>
<conversion_rate>0%</conversion_rate>
</row>
<row>
- <label>PRODUCT TWO LEFT in cart</label>
+ <label>PRODUCT THREE LEFT in cart</label>
<nb_uniq_visitors>1</nb_uniq_visitors>
<nb_visits>2</nb_visits>
- <nb_actions>2</nb_actions>
- <avg_price>0</avg_price>
+ <nb_actions>4</nb_actions>
+ <avg_price>666</avg_price>
<avg_quantity>0</avg_quantity>
<conversion_rate>0%</conversion_rate>
</row>
diff --git a/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_SegmentPageUrlContains__Goals.getItemsName_week.xml b/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_SegmentPageUrlContains__Goals.getItemsName_week.xml
index 735aff85e2..b413464bdb 100644
--- a/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_SegmentPageUrlContains__Goals.getItemsName_week.xml
+++ b/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_SegmentPageUrlContains__Goals.getItemsName_week.xml
@@ -31,20 +31,20 @@
<conversion_rate>0%</conversion_rate>
</row>
<row>
- <label>PRODUCT THREE LEFT in cart</label>
+ <label>PRODUCT TWO LEFT in cart</label>
<nb_visits>3</nb_visits>
- <nb_actions>6</nb_actions>
+ <nb_actions>3</nb_actions>
<sum_daily_nb_uniq_visitors>2</sum_daily_nb_uniq_visitors>
- <avg_price>1332</avg_price>
+ <avg_price>0</avg_price>
<avg_quantity>0</avg_quantity>
<conversion_rate>0%</conversion_rate>
</row>
<row>
- <label>PRODUCT TWO LEFT in cart</label>
+ <label>PRODUCT THREE LEFT in cart</label>
<nb_visits>3</nb_visits>
- <nb_actions>3</nb_actions>
+ <nb_actions>6</nb_actions>
<sum_daily_nb_uniq_visitors>2</sum_daily_nb_uniq_visitors>
- <avg_price>0</avg_price>
+ <avg_price>1332</avg_price>
<avg_quantity>0</avg_quantity>
<conversion_rate>0%</conversion_rate>
</row>
diff --git a/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems__API.getProcessedReport_day.xml b/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems__API.getProcessedReport_day.xml
index 05e7930247..67409015ee 100755
--- a/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems__API.getProcessedReport_day.xml
+++ b/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems__API.getProcessedReport_day.xml
@@ -4,6 +4,7 @@
<prettyDate>Tuesday, April 5, 2011</prettyDate>
<metadata>
<category>Visitors</category>
+ <subcategory>Locations</subcategory>
<name>Country</name>
<module>UserCountry</module>
<action>getCountry</action>
diff --git a/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems__Goals.getItemsName_day.xml b/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems__Goals.getItemsName_day.xml
index 80da495736..8beefcdba1 100644
--- a/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems__Goals.getItemsName_day.xml
+++ b/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems__Goals.getItemsName_day.xml
@@ -31,20 +31,20 @@
<conversion_rate>0%</conversion_rate>
</row>
<row>
- <label>PRODUCT THREE LEFT in cart</label>
+ <label>PRODUCT TWO LEFT in cart</label>
<nb_uniq_visitors>1</nb_uniq_visitors>
<nb_visits>2</nb_visits>
- <nb_actions>4</nb_actions>
- <avg_price>666</avg_price>
+ <nb_actions>2</nb_actions>
+ <avg_price>0</avg_price>
<avg_quantity>0</avg_quantity>
<conversion_rate>0%</conversion_rate>
</row>
<row>
- <label>PRODUCT TWO LEFT in cart</label>
+ <label>PRODUCT THREE LEFT in cart</label>
<nb_uniq_visitors>1</nb_uniq_visitors>
<nb_visits>2</nb_visits>
- <nb_actions>2</nb_actions>
- <avg_price>0</avg_price>
+ <nb_actions>4</nb_actions>
+ <avg_price>666</avg_price>
<avg_quantity>0</avg_quantity>
<conversion_rate>0%</conversion_rate>
</row>
diff --git a/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems__Goals.getItemsName_week.xml b/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems__Goals.getItemsName_week.xml
index 854349a01e..91beadc53c 100644
--- a/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems__Goals.getItemsName_week.xml
+++ b/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems__Goals.getItemsName_week.xml
@@ -40,20 +40,20 @@
<conversion_rate>0%</conversion_rate>
</row>
<row>
- <label>PRODUCT THREE LEFT in cart</label>
+ <label>PRODUCT TWO LEFT in cart</label>
<nb_visits>3</nb_visits>
- <nb_actions>6</nb_actions>
+ <nb_actions>3</nb_actions>
<sum_daily_nb_uniq_visitors>2</sum_daily_nb_uniq_visitors>
- <avg_price>1332</avg_price>
+ <avg_price>0</avg_price>
<avg_quantity>0</avg_quantity>
<conversion_rate>0%</conversion_rate>
</row>
<row>
- <label>PRODUCT TWO LEFT in cart</label>
+ <label>PRODUCT THREE LEFT in cart</label>
<nb_visits>3</nb_visits>
- <nb_actions>3</nb_actions>
+ <nb_actions>6</nb_actions>
<sum_daily_nb_uniq_visitors>2</sum_daily_nb_uniq_visitors>
- <avg_price>0</avg_price>
+ <avg_price>1332</avg_price>
<avg_quantity>0</avg_quantity>
<conversion_rate>0%</conversion_rate>
</row>
diff --git a/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_scheduled_report_in_csv__ScheduledReports.generateReport_week.original.csv b/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_scheduled_report_in_csv__ScheduledReports.generateReport_week.original.csv
index dd20771473..c13ba3af27 100644
--- a/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_scheduled_report_in_csv__ScheduledReports.generateReport_week.original.csv
+++ b/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_scheduled_report_in_csv__ScheduledReports.generateReport_week.original.csv
@@ -7,74 +7,52 @@ Visits Summary
nb_uniq_visitors,nb_visits,nb_actions,max_actions,nb_actions_per_visit,avg_time_on_site,bounce_rate
1,5,16,6,3.2,00:22:49,20%
-Visits by Server Time
+Custom Variables
label,nb_visits,nb_actions,revenue,nb_actions_per_visit,avg_time_on_site,bounce_rate
-0h,1,4,$ 10,4,00:12:01,0%
-1h,0,0,$ 0,0,00:00:00,0%
-2h,2,9,$ 3111.11,4.5,00:42:01,0%
-3h,0,0,$ 0,0,00:00:00,0%
-4h,0,0,$ 0,0,00:00:00,0%
-5h,0,0,$ 0,0,00:00:00,0%
-6h,1,0,$ 10240,0,00:06:03,100%
-7h,1,3,$ 0,3,00:12:01,0%
-8h,0,0,$ 0,0,00:00:00,0%
-9h,0,0,$ 0,0,00:00:00,0%
-10h,0,0,$ 0,0,00:00:00,0%
-11h,0,0,$ 0,0,00:00:00,0%
-12h,0,0,$ 0,0,00:00:00,0%
-13h,0,0,$ 0,0,00:00:00,0%
-14h,0,0,$ 0,0,00:00:00,0%
-15h,0,0,$ 0,0,00:00:00,0%
-16h,0,0,$ 0,0,00:00:00,0%
-17h,0,0,$ 0,0,00:00:00,0%
-18h,0,0,$ 0,0,00:00:00,0%
-19h,0,0,$ 0,0,00:00:00,0%
-20h,0,0,$ 0,0,00:00:00,0%
-21h,0,0,$ 0,0,00:00:00,0%
-22h,0,0,$ 0,0,00:00:00,0%
-23h,0,0,$ 0,0,00:00:00,0%
+ValueIsZero,5,16,$ 13361.11,3.2,00:22:49,20%
+VisitorType,5,16,$ 13361.11,3.2,00:22:49,20%
+VisitorName,4,12,$ 13351.11,3,00:25:32,25%
-Visits by Local Time
+Device type
label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate
-0h,0,0,0%,0,00:00:00,0%
-1h,0,0,0%,0,00:00:00,0%
-2h,0,0,0%,0,00:00:00,0%
-3h,0,0,0%,0,00:00:00,0%
-4h,0,0,0%,0,00:00:00,0%
-5h,0,0,0%,0,00:00:00,0%
-6h,0,0,0%,0,00:00:00,0%
-7h,0,0,0%,0,00:00:00,0%
-8h,0,0,0%,0,00:00:00,0%
-9h,0,0,0%,0,00:00:00,0%
-10h,0,0,0%,0,00:00:00,0%
-11h,0,0,0%,0,00:00:00,0%
-12h,5,16,80%,3.2,00:22:49,20%
-13h,0,0,0%,0,00:00:00,0%
-14h,0,0,0%,0,00:00:00,0%
-15h,0,0,0%,0,00:00:00,0%
-16h,0,0,0%,0,00:00:00,0%
-17h,0,0,0%,0,00:00:00,0%
-18h,0,0,0%,0,00:00:00,0%
-19h,0,0,0%,0,00:00:00,0%
-20h,0,0,0%,0,00:00:00,0%
-21h,0,0,0%,0,00:00:00,0%
-22h,0,0,0%,0,00:00:00,0%
-23h,0,0,0%,0,00:00:00,0%
+Desktop,5,16,80%,3.2,00:22:49,20%
-Visits by Day of Week
-label,nb_visits,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate,nb_actions
-Monday,0,0%,0,00:00:00,0%,0
-Tuesday,3,66.67%,4.3,00:30:01,0%,13
-Wednesday,2,100%,1.5,00:12:02,50%,3
-Thursday,0,0%,0,00:00:00,0%,0
-Friday,0,0%,0,00:00:00,0%,0
-Saturday,0,0%,0,00:00:00,0%,0
-Sunday,0,0%,0,00:00:00,0%,0
+Device model
+label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate
+Unknown,5,16,80%,3.2,00:22:49,20%
+
+Device brand
+label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate
+Unknown,5,16,80%,3.2,00:22:49,20%
Screen Resolution
label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate
1024x768,5,16,80%,3.2,00:22:49,20%
+Operating System versions
+label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate
+Windows XP,5,16,80%,3.2,00:22:49,20%
+
+Browsers
+label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate
+Firefox,5,16,80%,3.2,00:22:49,20%
+
+Browser version
+label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate
+Firefox 3.6,5,16,80%,3.2,00:22:49,20%
+
+Configurations
+label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate
+Windows / Firefox / 1024x768,5,16,80%,3.2,00:22:49,20%
+
+Operating System families
+label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate
+Windows,5,16,80%,3.2,00:22:49,20%
+
+Browser engines
+label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate
+Gecko (Firefox),5,16,80%,3.2,00:22:49,20%
+
Browser Plugins
label,nb_visits,nb_visits_percentage
Cookie,5,100%
@@ -88,80 +66,80 @@ Realplayer,0,0%
Silverlight,0,0%
Windowsmedia,0,0%
-Visitor Configuration
-label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate
-Windows / Firefox / 1024x768,5,16,80%,3.2,00:22:49,20%
+Country
+label,nb_visits,nb_actions,revenue,nb_actions_per_visit,avg_time_on_site,bounce_rate
+Poland,4,12,$ 13351.11,3,00:25:32,25%
+France,1,4,$ 10,4,00:12:01,0%
+
+Continent
+label,nb_visits,nb_actions,revenue,nb_actions_per_visit,avg_time_on_site,bounce_rate
+Europe,5,16,$ 13361.11,3.2,00:22:49,20%
+
+Region
+label,nb_visits,nb_actions,revenue,nb_actions_per_visit,avg_time_on_site,bounce_rate
+Unknown,5,16,$ 13361.11,3.2,00:22:49,20%
Browser language
label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate
Polish,4,12,75%,3,00:25:32,25%
French,1,4,100%,4,00:12:01,0%
+City
+label,nb_visits,nb_actions,revenue,nb_actions_per_visit,avg_time_on_site,bounce_rate
+Unknown,5,16,$ 13361.11,3.2,00:22:49,20%
+
Language code
label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate
Polish (pl),4,12,75%,3,00:25:32,25%
French (fr),1,4,100%,4,00:12:01,0%
-Ecommerce Orders
-nb_conversions,nb_visits_converted,revenue,revenue_subtotal,revenue_tax,revenue_shipping,revenue_discount,items,avg_order_revenue,conversion_rate
-4,2,$ 13351.11,$ 2700,$ 531,$ 120.11,$ 686,12,$ 3337.78,40%
-
-Ecommerce Orders - Visits to Conversion
-label,nb_conversions
-1 visit,2
-2 visits,2
-3 visits,0
-4 visits,0
-5 visits,0
-6 visits,0
-7 visits,0
-8 visits,0
-9-14 visits,0
-15-25 visits,0
-26-50 visits,0
-51-100 visits,0
-101+ visits,0
-
-Ecommerce Orders - Days to Conversion
-label,nb_conversions
-0 days,4
-1 day,0
-2 days,0
-3 days,0
-4 days,0
-5 days,0
-6 days,0
-7 days,0
-8-14 days,0
-15-30 days,0
-31-60 days,0
-61-120 days,0
-121-364 days,0
-365+ days,0
+Length of Visits
+label,nb_visits
+0-10s,0
+11-30s,0
+31-60s,0
+1-2 min,0
+2-4 min,0
+4-7 min,1
+7-10 min,0
+10-15 min,2
+15-30 min,1
+30+ min,1
-Abandoned Carts
-nb_conversions,revenue,items,avg_order_revenue,conversion_rate
-3,$ 7530.33,12,$ 2510.11,60%
+Pages per Visit
+label,nb_visits
+1 page,0
+2 pages,0
+3 pages,2
+4 pages,1
+5 pages,0
+6-7 pages,1
+8-10 pages,0
+11-14 pages,0
+15-20 pages,0
+21+ pages,0
-Abandoned Carts - Visits to Conversion
-label,nb_conversions
-1 visit,1
-2 visits,2
-3 visits,0
-4 visits,0
-5 visits,0
-6 visits,0
-7 visits,0
-8 visits,0
-9-14 visits,0
-15-25 visits,0
-26-50 visits,0
-51-100 visits,0
-101+ visits,0
+Visits by Visit Number
+label,nb_visits,nb_visits_percentage
+1 visit,3,60%
+2 visits,2,40%
+3 visits,0,0%
+4 visits,0,0%
+5 visits,0,0%
+6 visits,0,0%
+7 visits,0,0%
+8 visits,0,0%
+9-14 visits,0,0%
+15-25 visits,0,0%
+26-50 visits,0,0%
+51-100 visits,0,0%
+101-200 visits,0,0%
+201+ visits,0,0%
-Abandoned Carts - Days to Conversion
-label,nb_conversions
-0 days,3
+Visits by days since last visit
+label,nb_visits
+New visits,1
+0 days,1
1 day,0
2 days,0
3 days,0
@@ -176,37 +154,73 @@ label,nb_conversions
121-364 days,0
365+ days,0
-Product SKU
-label,revenue,quantity,orders,nb_visits,avg_price,avg_quantity,conversion_rate
-SKU2,$ 1500,1,1,1,$ 1500,1,100%
-SKU VERY nice indeed,$ 1011.22,3,2,4,$ 255.61,1.5,50%
-ANOTHER SKU HERE,$ 600,6,1,0,$ 100,6,0%
-TRIPOD SKU,$ 200,2,1,0,$ 100,2,0%
-SKU IN ABANDONED CART TWO,$ 0,0,0,3,$ 0,0,0%
+Returning Visits
+nb_uniq_visitors_returning,nb_users_returning,nb_visits_returning,nb_actions_returning,max_actions_returning,bounce_rate_returning,nb_actions_per_visit_returning,avg_time_on_site_returning
+1,0,4,12,6,25%,3,00:25:32
-Product Name
-label,revenue,quantity,orders,avg_price,avg_quantity,conversion_rate,nb_visits
-Canon SLR,$ 1500,1,1,$ 1500,1,0%,0
-PRODUCT name,$ 1011.22,3,2,$ 255.61,1.5,100%,2
-PRODUCT name BIS,$ 600,6,1,$ 100,6,0%,0
-TRIPOD - bought day after,$ 200,2,1,$ 100,2,0%,0
-PRODUCT THREE LEFT in cart,$ 0,0,0,$ 1332,0,0%,3
-PRODUCT TWO LEFT in cart,$ 0,0,0,$ 0,0,0%,3
+Visits per local time
+label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate
+0h,0,0,0%,0,00:00:00,0%
+1h,0,0,0%,0,00:00:00,0%
+2h,0,0,0%,0,00:00:00,0%
+3h,0,0,0%,0,00:00:00,0%
+4h,0,0,0%,0,00:00:00,0%
+5h,0,0,0%,0,00:00:00,0%
+6h,0,0,0%,0,00:00:00,0%
+7h,0,0,0%,0,00:00:00,0%
+8h,0,0,0%,0,00:00:00,0%
+9h,0,0,0%,0,00:00:00,0%
+10h,0,0,0%,0,00:00:00,0%
+11h,0,0,0%,0,00:00:00,0%
+12h,5,16,80%,3.2,00:22:49,20%
+13h,0,0,0%,0,00:00:00,0%
+14h,0,0,0%,0,00:00:00,0%
+15h,0,0,0%,0,00:00:00,0%
+16h,0,0,0%,0,00:00:00,0%
+17h,0,0,0%,0,00:00:00,0%
+18h,0,0,0%,0,00:00:00,0%
+19h,0,0,0%,0,00:00:00,0%
+20h,0,0,0%,0,00:00:00,0%
+21h,0,0,0%,0,00:00:00,0%
+22h,0,0,0%,0,00:00:00,0%
+23h,0,0,0%,0,00:00:00,0%
-Product Category
-label,revenue,quantity,orders,nb_visits,avg_price,avg_quantity,conversion_rate
-Electronics & Cameras,$ 2500,3,2,3,$ 1000,1.5,66.67%
-Multiple Category 1,$ 1000,2,1,1,$ 500,2,100%
-Multiple Category 2,$ 1000,2,1,1,$ 500,2,100%
-Multiple Category 4,$ 1000,2,1,1,$ 500,2,100%
-Multiple Category 5,$ 1000,2,1,1,$ 500,2,100%
-Product Category not defined,$ 611.22,7,2,4,$ 55.61,3.5,50%
-Tools,$ 200,2,1,0,$ 100,2,0%
-Category TWO LEFT in cart,$ 0,0,0,3,$ 0,0,0%
+Visits per server time
+label,nb_visits,nb_actions,revenue,nb_actions_per_visit,avg_time_on_site,bounce_rate
+0h,1,4,$ 10,4,00:12:01,0%
+1h,0,0,$ 0,0,00:00:00,0%
+2h,2,9,$ 3111.11,4.5,00:42:01,0%
+3h,0,0,$ 0,0,00:00:00,0%
+4h,0,0,$ 0,0,00:00:00,0%
+5h,0,0,$ 0,0,00:00:00,0%
+6h,1,0,$ 10240,0,00:06:03,100%
+7h,1,3,$ 0,3,00:12:01,0%
+8h,0,0,$ 0,0,00:00:00,0%
+9h,0,0,$ 0,0,00:00:00,0%
+10h,0,0,$ 0,0,00:00:00,0%
+11h,0,0,$ 0,0,00:00:00,0%
+12h,0,0,$ 0,0,00:00:00,0%
+13h,0,0,$ 0,0,00:00:00,0%
+14h,0,0,$ 0,0,00:00:00,0%
+15h,0,0,$ 0,0,00:00:00,0%
+16h,0,0,$ 0,0,00:00:00,0%
+17h,0,0,$ 0,0,00:00:00,0%
+18h,0,0,$ 0,0,00:00:00,0%
+19h,0,0,$ 0,0,00:00:00,0%
+20h,0,0,$ 0,0,00:00:00,0%
+21h,0,0,$ 0,0,00:00:00,0%
+22h,0,0,$ 0,0,00:00:00,0%
+23h,0,0,$ 0,0,00:00:00,0%
-Actions - Main metrics
-nb_pageviews,nb_uniq_pageviews,nb_downloads,nb_uniq_downloads,nb_outlinks,nb_uniq_outlinks,nb_searches,nb_keywords
-16,4,0,0,0,0,0,0
+Visits by Day of Week
+label,nb_visits,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate,nb_actions
+Monday,0,0%,0,00:00:00,0%,0
+Tuesday,3,66.67%,4.3,00:30:01,0%,13
+Wednesday,2,100%,1.5,00:12:02,50%,3
+Thursday,0,0%,0,00:00:00,0%,0
+Friday,0,0%,0,00:00:00,0%,0
+Saturday,0,0%,0,00:00:00,0%,0
+Sunday,0,0%,0,00:00:00,0%,0
Page URLs
label,nb_visits,nb_hits,bounce_rate,avg_time_on_page,exit_rate
@@ -231,27 +245,25 @@ label,nb_visits,nb_hits,bounce_rate,avg_time_on_page,exit_rate
Looking at Electronics & Cameras page with a page level custom variable,1,1,0%,00:06:00,0%
Looking at product page,1,1,0%,00:12:00,0%
-Entry page titles
-label,entry_nb_visits,entry_bounce_count,bounce_rate
- View product left in cart,1,0,0%
- incredible title!,1,0,0%
- Looking at Electronics & Cameras page with a page level custom variable,1,0,0%
+Site Search Keywords
+No data available
-Exit page titles
-label,nb_visits,exit_nb_visits,exit_rate
- View product left in cart,3,3,100%
- Another Product page with multiple categories,1,1,100%
+Pages Following a Site Search
+No data available
-Outlinks
+Search Keywords with No Results
No data available
-Downloads
+Page Titles Following a Site Search
No data available
-Content Name
+Search Categories
No data available
-Content Piece
+Outlinks
+No data available
+
+Downloads
No data available
Event Categories
@@ -263,20 +275,26 @@ No data available
Event Names
No data available
-Site Search Keywords
+Content Name
No data available
-Search Keywords with No Results
+Content Piece
No data available
-Search Categories
-No data available
+Actions - Main metrics
+nb_pageviews,nb_uniq_pageviews,nb_downloads,nb_uniq_downloads,nb_outlinks,nb_uniq_outlinks,nb_searches,nb_keywords
+16,4,0,0,0,0,0,0
-Pages Following a Site Search
-No data available
+Entry page titles
+label,entry_nb_visits,entry_bounce_count,bounce_rate
+ View product left in cart,1,0,0%
+ incredible title!,1,0,0%
+ Looking at Electronics & Cameras page with a page level custom variable,1,0,0%
-Page Titles Following a Site Search
-No data available
+Exit page titles
+label,nb_visits,exit_nb_visits,exit_rate
+ View product left in cart,3,3,100%
+ Another Product page with multiple categories,1,1,100%
Referrer Type
label,nb_visits,nb_actions,revenue,nb_actions_per_visit,avg_time_on_site,bounce_rate
@@ -288,17 +306,119 @@ No data available
Keywords
No data available
+Search Engines
+No data available
+
Websites
No data available
-Search Engines
+Social Networks
No data available
Campaigns
No data available
-Social Networks
-No data available
+Product SKU
+label,revenue,quantity,orders,nb_visits,avg_price,avg_quantity,conversion_rate
+SKU2,$ 1500,1,1,1,$ 1500,1,100%
+SKU VERY nice indeed,$ 1011.22,3,2,4,$ 255.61,1.5,50%
+ANOTHER SKU HERE,$ 600,6,1,0,$ 100,6,0%
+TRIPOD SKU,$ 200,2,1,0,$ 100,2,0%
+SKU IN ABANDONED CART TWO,$ 0,0,0,3,$ 0,0,0%
+
+Product Name
+label,revenue,quantity,orders,avg_price,avg_quantity,conversion_rate,nb_visits
+Canon SLR,$ 1500,1,1,$ 1500,1,0%,0
+PRODUCT name,$ 1011.22,3,2,$ 255.61,1.5,100%,2
+PRODUCT name BIS,$ 600,6,1,$ 100,6,0%,0
+TRIPOD - bought day after,$ 200,2,1,$ 100,2,0%,0
+PRODUCT TWO LEFT in cart,$ 0,0,0,$ 0,0,0%,3
+PRODUCT THREE LEFT in cart,$ 0,0,0,$ 1332,0,0%,3
+
+Product Category
+label,revenue,quantity,orders,nb_visits,avg_price,avg_quantity,conversion_rate
+Electronics & Cameras,$ 2500,3,2,3,$ 1000,1.5,66.67%
+Multiple Category 1,$ 1000,2,1,1,$ 500,2,100%
+Multiple Category 2,$ 1000,2,1,1,$ 500,2,100%
+Multiple Category 4,$ 1000,2,1,1,$ 500,2,100%
+Multiple Category 5,$ 1000,2,1,1,$ 500,2,100%
+Product Category not defined,$ 611.22,7,2,4,$ 55.61,3.5,50%
+Tools,$ 200,2,1,0,$ 100,2,0%
+Category TWO LEFT in cart,$ 0,0,0,3,$ 0,0,0%
+
+Ecommerce Orders
+nb_conversions,nb_visits_converted,revenue,revenue_subtotal,revenue_tax,revenue_shipping,revenue_discount,items,avg_order_revenue,conversion_rate
+4,2,$ 13351.11,$ 2700,$ 531,$ 120.11,$ 686,12,$ 3337.78,40%
+
+Ecommerce Orders - Visits to Conversion
+label,nb_conversions
+1 visit,2
+2 visits,2
+3 visits,0
+4 visits,0
+5 visits,0
+6 visits,0
+7 visits,0
+8 visits,0
+9-14 visits,0
+15-25 visits,0
+26-50 visits,0
+51-100 visits,0
+101+ visits,0
+
+Ecommerce Orders - Days to Conversion
+label,nb_conversions
+0 days,4
+1 day,0
+2 days,0
+3 days,0
+4 days,0
+5 days,0
+6 days,0
+7 days,0
+8-14 days,0
+15-30 days,0
+31-60 days,0
+61-120 days,0
+121-364 days,0
+365+ days,0
+
+Abandoned Carts
+nb_conversions,revenue,items,avg_order_revenue,conversion_rate
+3,$ 7530.33,12,$ 2510.11,60%
+
+Abandoned Carts - Visits to Conversion
+label,nb_conversions
+1 visit,1
+2 visits,2
+3 visits,0
+4 visits,0
+5 visits,0
+6 visits,0
+7 visits,0
+8 visits,0
+9-14 visits,0
+15-25 visits,0
+26-50 visits,0
+51-100 visits,0
+101+ visits,0
+
+Abandoned Carts - Days to Conversion
+label,nb_conversions
+0 days,3
+1 day,0
+2 days,0
+3 days,0
+4 days,0
+5 days,0
+6 days,0
+7 days,0
+8-14 days,0
+15-30 days,0
+31-60 days,0
+61-120 days,0
+121-364 days,0
+365+ days,0
Goals
nb_conversions,nb_visits_converted,revenue,conversion_rate
@@ -374,123 +494,15 @@ label,nb_conversions
121-364 days,0
365+ days,0
-Country
-label,nb_visits,nb_actions,revenue,nb_actions_per_visit,avg_time_on_site,bounce_rate
-Poland,4,12,$ 13351.11,3,00:25:32,25%
-France,1,4,$ 10,4,00:12:01,0%
-
-Continent
-label,nb_visits,nb_actions,revenue,nb_actions_per_visit,avg_time_on_site,bounce_rate
-Europe,5,16,$ 13361.11,3.2,00:22:49,20%
-
-Region
-label,nb_visits,nb_actions,revenue,nb_actions_per_visit,avg_time_on_site,bounce_rate
-Unknown,5,16,$ 13361.11,3.2,00:22:49,20%
-
-City
-label,nb_visits,nb_actions,revenue,nb_actions_per_visit,avg_time_on_site,bounce_rate
-Unknown,5,16,$ 13361.11,3.2,00:22:49,20%
-
-Custom Variables
-label,nb_visits,nb_actions,revenue,nb_actions_per_visit,avg_time_on_site,bounce_rate
-ValueIsZero,5,16,$ 13361.11,3.2,00:22:49,20%
-VisitorType,5,16,$ 13361.11,3.2,00:22:49,20%
-VisitorName,4,12,$ 13351.11,3,00:25:32,25%
-
-Length of Visits
-label,nb_visits
-0-10s,0
-11-30s,0
-31-60s,0
-1-2 min,0
-2-4 min,0
-4-7 min,1
-7-10 min,0
-10-15 min,2
-15-30 min,1
-30+ min,1
-
-Pages per Visit
-label,nb_visits
-1 page,0
-2 pages,0
-3 pages,2
-4 pages,1
-5 pages,0
-6-7 pages,1
-8-10 pages,0
-11-14 pages,0
-15-20 pages,0
-21+ pages,0
-
-Visits by Visit Number
-label,nb_visits,nb_visits_percentage
-1 visit,3,60%
-2 visits,2,40%
-3 visits,0,0%
-4 visits,0,0%
-5 visits,0,0%
-6 visits,0,0%
-7 visits,0,0%
-8 visits,0,0%
-9-14 visits,0,0%
-15-25 visits,0,0%
-26-50 visits,0,0%
-51-100 visits,0,0%
-101-200 visits,0,0%
-201+ visits,0,0%
-
-Visits by days since last visit
-label,nb_visits
-New visits,1
-0 days,1
-1 day,0
-2 days,0
-3 days,0
-4 days,0
-5 days,0
-6 days,0
-7 days,0
-8-14 days,0
-15-30 days,0
-31-60 days,0
-61-120 days,0
-121-364 days,0
-365+ days,0
-
-Returning Visits
-nb_uniq_visitors_returning,nb_users_returning,nb_visits_returning,nb_actions_returning,max_actions_returning,bounce_rate_returning,nb_actions_per_visit_returning,avg_time_on_site_returning
-1,0,4,12,6,25%,3,00:25:32
-
-Device type
-label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate
-Desktop,5,16,80%,3.2,00:22:49,20%
-
-Visitor Browser
-label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate
-Firefox,5,16,80%,3.2,00:22:49,20%
-
-Device brand
-label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate
-Unknown,5,16,80%,3.2,00:22:49,20%
-
-Browser version
-label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate
-Firefox 3.6,5,16,80%,3.2,00:22:49,20%
-
-Device model
-label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate
-Unknown,5,16,80%,3.2,00:22:49,20%
+Data tables
+No data available
-Operating System families
-label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate
-Windows,5,16,80%,3.2,00:22:49,20%
+Temperatures evolution over time
+No data available
-Operating System versions
-label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate
-Windows XP,5,16,80%,3.2,00:22:49,20%
+Pie graph
+No data available
-Browser engines
-label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate
-Gecko (Firefox),5,16,80%,3.2,00:22:49,20%
+Advanced tag cloud: with logos and links
+No data available
diff --git a/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_scheduled_report_in_html_tables_only__ScheduledReports.generateReport_week.original.html b/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_scheduled_report_in_html_tables_only__ScheduledReports.generateReport_week.original.html
index ecf0881055..7f70fb99c1 100644
--- a/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_scheduled_report_in_html_tables_only__ScheduledReports.generateReport_week.original.html
+++ b/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_scheduled_report_in_html_tables_only__ScheduledReports.generateReport_week.original.html
@@ -31,18 +31,23 @@
</a>
</li>
<li>
- <a href="#VisitTime_getVisitInformationPerServerTime" style="text-decoration:none; color: rgb(13,13,13);">
- Visits by Server Time
+ <a href="#CustomVariables_getCustomVariables" style="text-decoration:none; color: rgb(13,13,13);">
+ Custom Variables
</a>
</li>
<li>
- <a href="#VisitTime_getVisitInformationPerLocalTime" style="text-decoration:none; color: rgb(13,13,13);">
- Visits by Local Time
+ <a href="#DevicesDetection_getType" style="text-decoration:none; color: rgb(13,13,13);">
+ Device type
</a>
</li>
<li>
- <a href="#VisitTime_getByDayOfWeek" style="text-decoration:none; color: rgb(13,13,13);">
- Visits by Day of Week
+ <a href="#DevicesDetection_getModel" style="text-decoration:none; color: rgb(13,13,13);">
+ Device model
+ </a>
+ </li>
+ <li>
+ <a href="#DevicesDetection_getBrand" style="text-decoration:none; color: rgb(13,13,13);">
+ Device brand
</a>
</li>
<li>
@@ -51,73 +56,108 @@
</a>
</li>
<li>
+ <a href="#DevicesDetection_getOsVersions" style="text-decoration:none; color: rgb(13,13,13);">
+ Operating System versions
+ </a>
+ </li>
+ <li>
+ <a href="#DevicesDetection_getBrowsers" style="text-decoration:none; color: rgb(13,13,13);">
+ Browsers
+ </a>
+ </li>
+ <li>
+ <a href="#DevicesDetection_getBrowserVersions" style="text-decoration:none; color: rgb(13,13,13);">
+ Browser version
+ </a>
+ </li>
+ <li>
+ <a href="#Resolution_getConfiguration" style="text-decoration:none; color: rgb(13,13,13);">
+ Configurations
+ </a>
+ </li>
+ <li>
+ <a href="#DevicesDetection_getOsFamilies" style="text-decoration:none; color: rgb(13,13,13);">
+ Operating System families
+ </a>
+ </li>
+ <li>
+ <a href="#DevicesDetection_getBrowserEngines" style="text-decoration:none; color: rgb(13,13,13);">
+ Browser engines
+ </a>
+ </li>
+ <li>
<a href="#DevicePlugins_getPlugin" style="text-decoration:none; color: rgb(13,13,13);">
Browser Plugins
</a>
</li>
<li>
- <a href="#Resolution_getConfiguration" style="text-decoration:none; color: rgb(13,13,13);">
- Visitor Configuration
+ <a href="#UserCountry_getCountry" style="text-decoration:none; color: rgb(13,13,13);">
+ Country
</a>
</li>
<li>
- <a href="#UserLanguage_getLanguage" style="text-decoration:none; color: rgb(13,13,13);">
- Browser language
+ <a href="#UserCountry_getContinent" style="text-decoration:none; color: rgb(13,13,13);">
+ Continent
</a>
</li>
<li>
- <a href="#UserLanguage_getLanguageCode" style="text-decoration:none; color: rgb(13,13,13);">
- Language code
+ <a href="#UserCountry_getRegion" style="text-decoration:none; color: rgb(13,13,13);">
+ Region
</a>
</li>
<li>
- <a href="#Goals_get_idGoal--ecommerceOrder" style="text-decoration:none; color: rgb(13,13,13);">
- Ecommerce Orders
+ <a href="#UserLanguage_getLanguage" style="text-decoration:none; color: rgb(13,13,13);">
+ Browser language
</a>
</li>
<li>
- <a href="#Goals_getVisitsUntilConversion_idGoal--ecommerceOrder" style="text-decoration:none; color: rgb(13,13,13);">
- Ecommerce Orders - Visits to Conversion
+ <a href="#UserCountry_getCity" style="text-decoration:none; color: rgb(13,13,13);">
+ City
</a>
</li>
<li>
- <a href="#Goals_getDaysToConversion_idGoal--ecommerceOrder" style="text-decoration:none; color: rgb(13,13,13);">
- Ecommerce Orders - Days to Conversion
+ <a href="#UserLanguage_getLanguageCode" style="text-decoration:none; color: rgb(13,13,13);">
+ Language code
</a>
</li>
<li>
- <a href="#Goals_get_idGoal--ecommerceAbandonedCart" style="text-decoration:none; color: rgb(13,13,13);">
- Abandoned Carts
+ <a href="#VisitorInterest_getNumberOfVisitsPerVisitDuration" style="text-decoration:none; color: rgb(13,13,13);">
+ Length of Visits
</a>
</li>
<li>
- <a href="#Goals_getVisitsUntilConversion_idGoal--ecommerceAbandonedCart" style="text-decoration:none; color: rgb(13,13,13);">
- Abandoned Carts - Visits to Conversion
+ <a href="#VisitorInterest_getNumberOfVisitsPerPage" style="text-decoration:none; color: rgb(13,13,13);">
+ Pages per Visit
</a>
</li>
<li>
- <a href="#Goals_getDaysToConversion_idGoal--ecommerceAbandonedCart" style="text-decoration:none; color: rgb(13,13,13);">
- Abandoned Carts - Days to Conversion
+ <a href="#VisitorInterest_getNumberOfVisitsByVisitCount" style="text-decoration:none; color: rgb(13,13,13);">
+ Visits by Visit Number
</a>
</li>
<li>
- <a href="#Goals_getItemsSku" style="text-decoration:none; color: rgb(13,13,13);">
- Product SKU
+ <a href="#VisitorInterest_getNumberOfVisitsByDaysSinceLast" style="text-decoration:none; color: rgb(13,13,13);">
+ Visits by days since last visit
</a>
</li>
<li>
- <a href="#Goals_getItemsName" style="text-decoration:none; color: rgb(13,13,13);">
- Product Name
+ <a href="#VisitFrequency_get" style="text-decoration:none; color: rgb(13,13,13);">
+ Returning Visits
</a>
</li>
<li>
- <a href="#Goals_getItemsCategory" style="text-decoration:none; color: rgb(13,13,13);">
- Product Category
+ <a href="#VisitTime_getVisitInformationPerLocalTime" style="text-decoration:none; color: rgb(13,13,13);">
+ Visits per local time
</a>
</li>
<li>
- <a href="#Actions_get" style="text-decoration:none; color: rgb(13,13,13);">
- Actions - Main metrics
+ <a href="#VisitTime_getVisitInformationPerServerTime" style="text-decoration:none; color: rgb(13,13,13);">
+ Visits per server time
+ </a>
+ </li>
+ <li>
+ <a href="#VisitTime_getByDayOfWeek" style="text-decoration:none; color: rgb(13,13,13);">
+ Visits by Day of Week
</a>
</li>
<li>
@@ -141,33 +181,38 @@
</a>
</li>
<li>
- <a href="#Actions_getEntryPageTitles" style="text-decoration:none; color: rgb(13,13,13);">
- Entry page titles
+ <a href="#Actions_getSiteSearchKeywords" style="text-decoration:none; color: rgb(13,13,13);">
+ Site Search Keywords
</a>
</li>
<li>
- <a href="#Actions_getExitPageTitles" style="text-decoration:none; color: rgb(13,13,13);">
- Exit page titles
+ <a href="#Actions_getPageUrlsFollowingSiteSearch" style="text-decoration:none; color: rgb(13,13,13);">
+ Pages Following a Site Search
</a>
</li>
<li>
- <a href="#Actions_getOutlinks" style="text-decoration:none; color: rgb(13,13,13);">
- Outlinks
+ <a href="#Actions_getSiteSearchNoResultKeywords" style="text-decoration:none; color: rgb(13,13,13);">
+ Search Keywords with No Results
</a>
</li>
<li>
- <a href="#Actions_getDownloads" style="text-decoration:none; color: rgb(13,13,13);">
- Downloads
+ <a href="#Actions_getPageTitlesFollowingSiteSearch" style="text-decoration:none; color: rgb(13,13,13);">
+ Page Titles Following a Site Search
</a>
</li>
<li>
- <a href="#Contents_getContentNames" style="text-decoration:none; color: rgb(13,13,13);">
- Content Name
+ <a href="#Actions_getSiteSearchCategories" style="text-decoration:none; color: rgb(13,13,13);">
+ Search Categories
</a>
</li>
<li>
- <a href="#Contents_getContentPieces" style="text-decoration:none; color: rgb(13,13,13);">
- Content Piece
+ <a href="#Actions_getOutlinks" style="text-decoration:none; color: rgb(13,13,13);">
+ Outlinks
+ </a>
+ </li>
+ <li>
+ <a href="#Actions_getDownloads" style="text-decoration:none; color: rgb(13,13,13);">
+ Downloads
</a>
</li>
<li>
@@ -186,28 +231,28 @@
</a>
</li>
<li>
- <a href="#Actions_getSiteSearchKeywords" style="text-decoration:none; color: rgb(13,13,13);">
- Site Search Keywords
+ <a href="#Contents_getContentNames" style="text-decoration:none; color: rgb(13,13,13);">
+ Content Name
</a>
</li>
<li>
- <a href="#Actions_getSiteSearchNoResultKeywords" style="text-decoration:none; color: rgb(13,13,13);">
- Search Keywords with No Results
+ <a href="#Contents_getContentPieces" style="text-decoration:none; color: rgb(13,13,13);">
+ Content Piece
</a>
</li>
<li>
- <a href="#Actions_getSiteSearchCategories" style="text-decoration:none; color: rgb(13,13,13);">
- Search Categories
+ <a href="#Actions_get" style="text-decoration:none; color: rgb(13,13,13);">
+ Actions - Main metrics
</a>
</li>
<li>
- <a href="#Actions_getPageUrlsFollowingSiteSearch" style="text-decoration:none; color: rgb(13,13,13);">
- Pages Following a Site Search
+ <a href="#Actions_getEntryPageTitles" style="text-decoration:none; color: rgb(13,13,13);">
+ Entry page titles
</a>
</li>
<li>
- <a href="#Actions_getPageTitlesFollowingSiteSearch" style="text-decoration:none; color: rgb(13,13,13);">
- Page Titles Following a Site Search
+ <a href="#Actions_getExitPageTitles" style="text-decoration:none; color: rgb(13,13,13);">
+ Exit page titles
</a>
</li>
<li>
@@ -226,18 +271,13 @@
</a>
</li>
<li>
- <a href="#Referrers_getWebsites" style="text-decoration:none; color: rgb(13,13,13);">
- Websites
- </a>
- </li>
- <li>
<a href="#Referrers_getSearchEngines" style="text-decoration:none; color: rgb(13,13,13);">
Search Engines
</a>
</li>
<li>
- <a href="#Referrers_getCampaigns" style="text-decoration:none; color: rgb(13,13,13);">
- Campaigns
+ <a href="#Referrers_getWebsites" style="text-decoration:none; color: rgb(13,13,13);">
+ Websites
</a>
</li>
<li>
@@ -246,123 +286,103 @@
</a>
</li>
<li>
- <a href="#Goals_get" style="text-decoration:none; color: rgb(13,13,13);">
- Goals
- </a>
- </li>
- <li>
- <a href="#Goals_getVisitsUntilConversion" style="text-decoration:none; color: rgb(13,13,13);">
- Visits to Conversion
- </a>
- </li>
- <li>
- <a href="#Goals_getDaysToConversion" style="text-decoration:none; color: rgb(13,13,13);">
- Days to Conversion
- </a>
- </li>
- <li>
- <a href="#Goals_get_idGoal--1" style="text-decoration:none; color: rgb(13,13,13);">
- Goal title match, triggered ONCE
+ <a href="#Referrers_getCampaigns" style="text-decoration:none; color: rgb(13,13,13);">
+ Campaigns
</a>
</li>
<li>
- <a href="#Goals_getVisitsUntilConversion_idGoal--1" style="text-decoration:none; color: rgb(13,13,13);">
- title match, triggered ONCE - Visits to Conversion
+ <a href="#Goals_getItemsSku" style="text-decoration:none; color: rgb(13,13,13);">
+ Product SKU
</a>
</li>
<li>
- <a href="#Goals_getDaysToConversion_idGoal--1" style="text-decoration:none; color: rgb(13,13,13);">
- title match, triggered ONCE - Days to Conversion
+ <a href="#Goals_getItemsName" style="text-decoration:none; color: rgb(13,13,13);">
+ Product Name
</a>
</li>
<li>
- <a href="#UserCountry_getCountry" style="text-decoration:none; color: rgb(13,13,13);">
- Country
+ <a href="#Goals_getItemsCategory" style="text-decoration:none; color: rgb(13,13,13);">
+ Product Category
</a>
</li>
<li>
- <a href="#UserCountry_getContinent" style="text-decoration:none; color: rgb(13,13,13);">
- Continent
+ <a href="#Goals_get_idGoal--ecommerceOrder" style="text-decoration:none; color: rgb(13,13,13);">
+ Ecommerce Orders
</a>
</li>
<li>
- <a href="#UserCountry_getRegion" style="text-decoration:none; color: rgb(13,13,13);">
- Region
+ <a href="#Goals_getVisitsUntilConversion_idGoal--ecommerceOrder" style="text-decoration:none; color: rgb(13,13,13);">
+ Ecommerce Orders - Visits to Conversion
</a>
</li>
<li>
- <a href="#UserCountry_getCity" style="text-decoration:none; color: rgb(13,13,13);">
- City
+ <a href="#Goals_getDaysToConversion_idGoal--ecommerceOrder" style="text-decoration:none; color: rgb(13,13,13);">
+ Ecommerce Orders - Days to Conversion
</a>
</li>
<li>
- <a href="#CustomVariables_getCustomVariables" style="text-decoration:none; color: rgb(13,13,13);">
- Custom Variables
+ <a href="#Goals_get_idGoal--ecommerceAbandonedCart" style="text-decoration:none; color: rgb(13,13,13);">
+ Abandoned Carts
</a>
</li>
<li>
- <a href="#VisitorInterest_getNumberOfVisitsPerVisitDuration" style="text-decoration:none; color: rgb(13,13,13);">
- Length of Visits
+ <a href="#Goals_getVisitsUntilConversion_idGoal--ecommerceAbandonedCart" style="text-decoration:none; color: rgb(13,13,13);">
+ Abandoned Carts - Visits to Conversion
</a>
</li>
<li>
- <a href="#VisitorInterest_getNumberOfVisitsPerPage" style="text-decoration:none; color: rgb(13,13,13);">
- Pages per Visit
+ <a href="#Goals_getDaysToConversion_idGoal--ecommerceAbandonedCart" style="text-decoration:none; color: rgb(13,13,13);">
+ Abandoned Carts - Days to Conversion
</a>
</li>
<li>
- <a href="#VisitorInterest_getNumberOfVisitsByVisitCount" style="text-decoration:none; color: rgb(13,13,13);">
- Visits by Visit Number
+ <a href="#Goals_get" style="text-decoration:none; color: rgb(13,13,13);">
+ Goals
</a>
</li>
<li>
- <a href="#VisitorInterest_getNumberOfVisitsByDaysSinceLast" style="text-decoration:none; color: rgb(13,13,13);">
- Visits by days since last visit
+ <a href="#Goals_getVisitsUntilConversion" style="text-decoration:none; color: rgb(13,13,13);">
+ Visits to Conversion
</a>
</li>
<li>
- <a href="#VisitFrequency_get" style="text-decoration:none; color: rgb(13,13,13);">
- Returning Visits
+ <a href="#Goals_getDaysToConversion" style="text-decoration:none; color: rgb(13,13,13);">
+ Days to Conversion
</a>
</li>
<li>
- <a href="#DevicesDetection_getType" style="text-decoration:none; color: rgb(13,13,13);">
- Device type
+ <a href="#Goals_get_idGoal--1" style="text-decoration:none; color: rgb(13,13,13);">
+ Goal title match, triggered ONCE
</a>
</li>
<li>
- <a href="#DevicesDetection_getBrowsers" style="text-decoration:none; color: rgb(13,13,13);">
- Visitor Browser
+ <a href="#Goals_getVisitsUntilConversion_idGoal--1" style="text-decoration:none; color: rgb(13,13,13);">
+ title match, triggered ONCE - Visits to Conversion
</a>
</li>
<li>
- <a href="#DevicesDetection_getBrand" style="text-decoration:none; color: rgb(13,13,13);">
- Device brand
+ <a href="#Goals_getDaysToConversion_idGoal--1" style="text-decoration:none; color: rgb(13,13,13);">
+ title match, triggered ONCE - Days to Conversion
</a>
</li>
<li>
- <a href="#DevicesDetection_getBrowserVersions" style="text-decoration:none; color: rgb(13,13,13);">
- Browser version
+ <a href="#ExampleUI_getTemperatures" style="text-decoration:none; color: rgb(13,13,13);">
+ Data tables
</a>
</li>
<li>
- <a href="#DevicesDetection_getModel" style="text-decoration:none; color: rgb(13,13,13);">
- Device model
+ <a href="#ExampleUI_getTemperaturesEvolution" style="text-decoration:none; color: rgb(13,13,13);">
+ Temperatures evolution over time
</a>
</li>
<li>
- <a href="#DevicesDetection_getOsFamilies" style="text-decoration:none; color: rgb(13,13,13);">
- Operating System families
+ <a href="#ExampleUI_getPlanetRatios" style="text-decoration:none; color: rgb(13,13,13);">
+ Pie graph
</a>
</li>
<li>
- <a href="#DevicesDetection_getOsVersions" style="text-decoration:none; color: rgb(13,13,13);">
- Operating System versions
- </a>
- </li>
- <li>
- <a href="#DevicesDetection_getBrowserEngines" style="text-decoration:none; color: rgb(13,13,13);">
- Browser engines
+ <a href="#ExampleUI_getPlanetRatiosWithLogos" style="text-decoration:none; color: rgb(13,13,13);">
+ Advanced tag cloud: with logos and links
</a>
</li>
</ul>
@@ -536,8 +556,8 @@
<a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
Back to top
</a>
-<h2 id="VisitTime_getVisitInformationPerServerTime" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Visits by Server Time
+<h2 id="CustomVariables_getCustomVariables" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Custom Variables
</h2>
@@ -545,7 +565,7 @@
<table style="border-collapse:collapse; margin-left: 5px;">
<thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
<th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Server time&nbsp;&nbsp;
+ &nbsp;Custom Variable name&nbsp;&nbsp;
</th>
<th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
&nbsp;Visits&nbsp;&nbsp;
@@ -570,176 +590,915 @@
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0h </td>
+ ValueIsZero </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
+ 5
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 4
+ 16
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 4
+ 3.2
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:12:01
+ 00:22:49
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ 20%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 10
+ $ 13361.11
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1h </td>
+ VisitorType </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 5
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 16
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 3.2
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:00:00
+ 00:22:49
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ 20%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
+ $ 13361.11
</td>
</tr>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 2h </td>
+ VisitorName </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 2
+ 4
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 9
+ 12
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 4.5
+ 3
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:42:01
+ 00:25:32
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ 25%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 3111.11
+ $ 13351.11
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ <br/>
+ <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
+ Back to top
+ </a>
+<h2 id="DevicesDetection_getType" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Device type
+</h2>
+
+
+
+ <table style="border-collapse:collapse; margin-left: 5px;">
+ <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Device type&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Visits&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Actions&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Actions per Visit&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Avg. Time on Website&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Bounce Rate&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Conversion Rate&nbsp;&nbsp;
+ </th>
+ </thead>
+ <tbody>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicesDetection/images/screens/normal.gif'>
+ &nbsp;
+ Desktop </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 5
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 16
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 3.2
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 00:22:49
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 20%
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 80%
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ <br/>
+ <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
+ Back to top
+ </a>
+<h2 id="DevicesDetection_getModel" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Device model
+</h2>
+
+
+
+ <table style="border-collapse:collapse; margin-left: 5px;">
+ <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Device model&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Visits&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Actions&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Actions per Visit&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Avg. Time on Website&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Bounce Rate&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Conversion Rate&nbsp;&nbsp;
+ </th>
+ </thead>
+ <tbody>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ Unknown </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 5
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 16
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 3.2
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 00:22:49
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 20%
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 80%
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ <br/>
+ <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
+ Back to top
+ </a>
+<h2 id="DevicesDetection_getBrand" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Device brand
+</h2>
+
+
+
+ <table style="border-collapse:collapse; margin-left: 5px;">
+ <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Device brand&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Visits&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Actions&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Actions per Visit&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Avg. Time on Website&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Bounce Rate&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Conversion Rate&nbsp;&nbsp;
+ </th>
+ </thead>
+ <tbody>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicesDetection/images/brand/Unknown.ico'>
+ &nbsp;
+ Unknown </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 5
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 16
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 3.2
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 00:22:49
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 20%
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 80%
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ <br/>
+ <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
+ Back to top
+ </a>
+<h2 id="Resolution_getResolution" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Screen Resolution
+</h2>
+
+
+
+ <table style="border-collapse:collapse; margin-left: 5px;">
+ <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Resolution&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Visits&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Actions&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Actions per Visit&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Avg. Time on Website&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Bounce Rate&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Conversion Rate&nbsp;&nbsp;
+ </th>
+ </thead>
+ <tbody>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 1024x768 </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 5
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 16
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 3.2
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 00:22:49
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 20%
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 80%
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ <br/>
+ <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
+ Back to top
+ </a>
+<h2 id="DevicesDetection_getOsVersions" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Operating System versions
+</h2>
+
+
+
+ <table style="border-collapse:collapse; margin-left: 5px;">
+ <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Operating System versions&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Visits&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Actions&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Actions per Visit&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Avg. Time on Website&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Bounce Rate&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Conversion Rate&nbsp;&nbsp;
+ </th>
+ </thead>
+ <tbody>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicesDetection/images/os/WIN.gif'>
+ &nbsp;
+ Windows XP </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 5
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 16
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 3.2
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 00:22:49
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 20%
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 80%
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ <br/>
+ <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
+ Back to top
+ </a>
+<h2 id="DevicesDetection_getBrowsers" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Browsers
+</h2>
+
+
+
+ <table style="border-collapse:collapse; margin-left: 5px;">
+ <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Browser&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Visits&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Actions&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Actions per Visit&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Avg. Time on Website&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Bounce Rate&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Conversion Rate&nbsp;&nbsp;
+ </th>
+ </thead>
+ <tbody>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicesDetection/images/browsers/FF.gif'>
+ &nbsp;
+ Firefox </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 5
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 16
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 3.2
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 00:22:49
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 20%
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 80%
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ <br/>
+ <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
+ Back to top
+ </a>
+<h2 id="DevicesDetection_getBrowserVersions" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Browser version
+</h2>
+
+
+
+ <table style="border-collapse:collapse; margin-left: 5px;">
+ <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Browser version&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Visits&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Actions&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Actions per Visit&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Avg. Time on Website&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Bounce Rate&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Conversion Rate&nbsp;&nbsp;
+ </th>
+ </thead>
+ <tbody>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicesDetection/images/browsers/FF.gif'>
+ &nbsp;
+ Firefox 3.6 </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 5
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 16
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 3.2
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 00:22:49
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 20%
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 80%
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ <br/>
+ <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
+ Back to top
+ </a>
+<h2 id="Resolution_getConfiguration" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Configurations
+</h2>
+
+
+
+ <table style="border-collapse:collapse; margin-left: 5px;">
+ <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Configuration&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Visits&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Actions&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Actions per Visit&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Avg. Time on Website&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Bounce Rate&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Conversion Rate&nbsp;&nbsp;
+ </th>
+ </thead>
+ <tbody>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ Windows / Firefox / 1024x768 </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 5
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 16
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 3.2
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 00:22:49
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 20%
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 80%
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ <br/>
+ <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
+ Back to top
+ </a>
+<h2 id="DevicesDetection_getOsFamilies" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Operating System families
+</h2>
+
+
+
+ <table style="border-collapse:collapse; margin-left: 5px;">
+ <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Operating system family&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Visits&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Actions&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Actions per Visit&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Avg. Time on Website&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Bounce Rate&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Conversion Rate&nbsp;&nbsp;
+ </th>
+ </thead>
+ <tbody>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicesDetection/images/os/WIN.gif'>
+ &nbsp;
+ Windows </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 5
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 16
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 3.2
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 00:22:49
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 20%
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 80%
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ <br/>
+ <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
+ Back to top
+ </a>
+<h2 id="DevicesDetection_getBrowserEngines" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Browser engines
+</h2>
+
+
+
+ <table style="border-collapse:collapse; margin-left: 5px;">
+ <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Browser engine&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Visits&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Actions&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Actions per Visit&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Avg. Time on Website&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Bounce Rate&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Conversion Rate&nbsp;&nbsp;
+ </th>
+ </thead>
+ <tbody>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ Gecko (Firefox) </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 5
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 16
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 3.2
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 00:22:49
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 20%
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 80%
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ <br/>
+ <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
+ Back to top
+ </a>
+<h2 id="DevicePlugins_getPlugin" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Browser Plugins
+</h2>
+
+
+
+ <table style="border-collapse:collapse; margin-left: 5px;">
+ <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Plugin&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Visits&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;% Visits&nbsp;&nbsp;
+ </th>
+ </thead>
+ <tbody>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicePlugins/images/plugins/cookie.gif'>
+ &nbsp;
+ Cookie </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 5
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 100%
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 3h </td>
+ <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicePlugins/images/plugins/flash.gif'>
+ &nbsp;
+ Flash </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 5
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 100%
</td>
+ </tr>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicePlugins/images/plugins/java.gif'>
+ &nbsp;
+ Java </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 5
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:00:00
+ 100%
</td>
+ </tr>
+
+ <tr style=";line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicePlugins/images/plugins/director.gif'>
+ &nbsp;
+ Director </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
+ 0%
</td>
</tr>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 4h </td>
+ <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicePlugins/images/plugins/gears.gif'>
+ &nbsp;
+ Gears </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 0%
</td>
+ </tr>
+
+ <tr style=";line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicePlugins/images/plugins/pdf.gif'>
+ &nbsp;
+ Pdf </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:00:00
+ 0%
</td>
+ </tr>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicePlugins/images/plugins/quicktime.gif'>
+ &nbsp;
+ Quicktime </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
+ 0%
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 5h </td>
+ <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicePlugins/images/plugins/realplayer.gif'>
+ &nbsp;
+ Realplayer </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 0%
</td>
+ </tr>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicePlugins/images/plugins/silverlight.gif'>
+ &nbsp;
+ Silverlight </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:00:00
+ 0%
</td>
+ </tr>
+
+ <tr style=";line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicePlugins/images/plugins/windowsmedia.gif'>
+ &nbsp;
+ Windowsmedia </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
+ 0%
</td>
</tr>
-
+ </tbody>
+ </table>
+ <br/>
+ <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
+ Back to top
+ </a>
+<h2 id="UserCountry_getCountry" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Country
+</h2>
+
+
+
+ <table style="border-collapse:collapse; margin-left: 5px;">
+ <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Country&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Visits&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Actions&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Actions per Visit&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Avg. Time on Website&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Bounce Rate&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Revenue&nbsp;&nbsp;
+ </th>
+ </thead>
+ <tbody>
+
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 6h </td>
+ <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/UserCountry/images/flags/pl.png'>
+ &nbsp;
+ Poland </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
+ 4
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 12
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 3
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:06:03
+ 00:25:32
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 100%
+ 25%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 10240
+ $ 13351.11
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 7h </td>
+ <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/UserCountry/images/flags/fr.png'>
+ &nbsp;
+ France </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
1
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 3
+ 4
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 3
+ 4
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
00:12:01
@@ -748,375 +1507,968 @@
0%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
+ $ 10
</td>
</tr>
-
+ </tbody>
+ </table>
+ <br/>
+ <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
+ Back to top
+ </a>
+<h2 id="UserCountry_getContinent" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Continent
+</h2>
+
+
+
+ <table style="border-collapse:collapse; margin-left: 5px;">
+ <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Continent&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Visits&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Actions&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Actions per Visit&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Avg. Time on Website&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Bounce Rate&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Revenue&nbsp;&nbsp;
+ </th>
+ </thead>
+ <tbody>
+
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 8h </td>
+ Europe </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 5
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 16
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 3.2
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:00:00
+ 00:22:49
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ 20%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
+ $ 13361.11
</td>
</tr>
-
- <tr style=";line-height: 22px;">
+ </tbody>
+ </table>
+ <br/>
+ <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
+ Back to top
+ </a>
+<h2 id="UserCountry_getRegion" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Region
+</h2>
+
+
+
+ <table style="border-collapse:collapse; margin-left: 5px;">
+ <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Region&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Visits&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Actions&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Actions per Visit&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Avg. Time on Website&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Bounce Rate&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Revenue&nbsp;&nbsp;
+ </th>
+ </thead>
+ <tbody>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 9h </td>
+ <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/UserCountry/images/flags/xx.png'>
+ &nbsp;
+ Unknown </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 5
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 16
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 3.2
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:00:00
+ 00:22:49
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ 20%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
+ $ 13361.11
</td>
</tr>
-
+ </tbody>
+ </table>
+ <br/>
+ <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
+ Back to top
+ </a>
+<h2 id="UserLanguage_getLanguage" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Browser language
+</h2>
+
+
+
+ <table style="border-collapse:collapse; margin-left: 5px;">
+ <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Language&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Visits&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Actions&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Actions per Visit&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Avg. Time on Website&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Bounce Rate&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Conversion Rate&nbsp;&nbsp;
+ </th>
+ </thead>
+ <tbody>
+
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 10h </td>
+ Polish </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 4
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 12
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 3
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:00:00
+ 00:25:32
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ 25%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
+ 75%
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 11h </td>
+ French </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 1
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 4
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 4
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:00:00
+ 00:12:01
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
+ 100%
</td>
</tr>
-
+ </tbody>
+ </table>
+ <br/>
+ <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
+ Back to top
+ </a>
+<h2 id="UserCountry_getCity" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ City
+</h2>
+
+
+
+ <table style="border-collapse:collapse; margin-left: 5px;">
+ <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;City&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Visits&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Actions&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Actions per Visit&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Avg. Time on Website&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Bounce Rate&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Revenue&nbsp;&nbsp;
+ </th>
+ </thead>
+ <tbody>
+
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 12h </td>
+ <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/UserCountry/images/flags/xx.png'>
+ &nbsp;
+ Unknown </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 5
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 16
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 3.2
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:00:00
+ 00:22:49
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ 20%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
+ $ 13361.11
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ <br/>
+ <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
+ Back to top
+ </a>
+<h2 id="UserLanguage_getLanguageCode" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Language code
+</h2>
+
+
+
+ <table style="border-collapse:collapse; margin-left: 5px;">
+ <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Language&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Visits&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Actions&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Actions per Visit&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Avg. Time on Website&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Bounce Rate&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Conversion Rate&nbsp;&nbsp;
+ </th>
+ </thead>
+ <tbody>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ Polish (pl) </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 4
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 12
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 3
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 00:25:32
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 25%
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 75%
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 13h </td>
+ French (fr) </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 1
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 4
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 4
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:00:00
+ 00:12:01
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
+ 100%
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ <br/>
+ <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
+ Back to top
+ </a>
+<h2 id="VisitorInterest_getNumberOfVisitsPerVisitDuration" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Length of Visits
+</h2>
+
+
+
+ <table style="border-collapse:collapse; margin-left: 5px;">
+ <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Visit duration&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Visits&nbsp;&nbsp;
+ </th>
+ </thead>
+ <tbody>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0-10s </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0
+ </td>
+ </tr>
+
+ <tr style=";line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 11-30s </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0
</td>
</tr>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 14h </td>
+ 31-60s </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
+ </tr>
+
+ <tr style=";line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 1-2 min </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
+ </tr>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 2-4 min </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
+ </tr>
+
+ <tr style=";line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 4-7 min </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:00:00
+ 1
</td>
+ </tr>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 7-10 min </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ 0
</td>
+ </tr>
+
+ <tr style=";line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 10-15 min </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
+ 2
+ </td>
+ </tr>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 15-30 min </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 1
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 15h </td>
+ 30+ min </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 1
</td>
+ </tr>
+ </tbody>
+ </table>
+ <br/>
+ <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
+ Back to top
+ </a>
+<h2 id="VisitorInterest_getNumberOfVisitsPerPage" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Pages per Visit
+</h2>
+
+
+
+ <table style="border-collapse:collapse; margin-left: 5px;">
+ <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Pages per visit&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Visits&nbsp;&nbsp;
+ </th>
+ </thead>
+ <tbody>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 1 page </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
+ </tr>
+
+ <tr style=";line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 2 pages </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
+ </tr>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 3 pages </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 2
+ </td>
+ </tr>
+
+ <tr style=";line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 4 pages </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:00:00
+ 1
</td>
+ </tr>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 5 pages </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ 0
</td>
+ </tr>
+
+ <tr style=";line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 6-7 pages </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
+ 1
</td>
</tr>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 16h </td>
+ 8-10 pages </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
+ </tr>
+
+ <tr style=";line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 11-14 pages </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
+ </tr>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 15-20 pages </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
+ </tr>
+
+ <tr style=";line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 21+ pages </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:00:00
+ 0
</td>
+ </tr>
+ </tbody>
+ </table>
+ <br/>
+ <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
+ Back to top
+ </a>
+<h2 id="VisitorInterest_getNumberOfVisitsByVisitCount" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Visits by Visit Number
+</h2>
+
+
+
+ <table style="border-collapse:collapse; margin-left: 5px;">
+ <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Visits by Visit Number&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Visits&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;% Visits&nbsp;&nbsp;
+ </th>
+ </thead>
+ <tbody>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 1 visit </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ 3
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
+ 60%
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 17h </td>
+ 2 visits </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 2
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 40%
</td>
+ </tr>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 3 visits </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:00:00
+ 0%
</td>
+ </tr>
+
+ <tr style=";line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 4 visits </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
+ 0%
</td>
</tr>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 18h </td>
+ 5 visits </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 0%
</td>
+ </tr>
+
+ <tr style=";line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 6 visits </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:00:00
+ 0%
</td>
+ </tr>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 7 visits </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
+ 0%
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 19h </td>
+ 8 visits </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 0%
</td>
+ </tr>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 9-14 visits </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:00:00
+ 0%
</td>
+ </tr>
+
+ <tr style=";line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 15-25 visits </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
+ 0%
</td>
</tr>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 20h </td>
+ 26-50 visits </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0%
+ </td>
+ </tr>
+
+ <tr style=";line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 51-100 visits </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0%
+ </td>
+ </tr>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 101-200 visits </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:00:00
+ 0%
+ </td>
+ </tr>
+
+ <tr style=";line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 201+ visits </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0%
</td>
+ </tr>
+ </tbody>
+ </table>
+ <br/>
+ <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
+ Back to top
+ </a>
+<h2 id="VisitorInterest_getNumberOfVisitsByDaysSinceLast" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Visits by days since last visit
+</h2>
+
+
+
+ <table style="border-collapse:collapse; margin-left: 5px;">
+ <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Visits by days since last visit&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Visits&nbsp;&nbsp;
+ </th>
+ </thead>
+ <tbody>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ New visits </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
+ 1
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 21h </td>
+ 0 days </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 1
</td>
+ </tr>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 1 day </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
+ </tr>
+
+ <tr style=";line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 2 days </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
+ </tr>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 3 days </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:00:00
+ 0
</td>
+ </tr>
+
+ <tr style=";line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 4 days </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ 0
</td>
+ </tr>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 5 days </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
+ 0
</td>
</tr>
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 22h </td>
+ 6 days </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
+ </tr>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 7 days </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
+ </tr>
+
+ <tr style=";line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 8-14 days </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
+ </tr>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 15-30 days </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:00:00
+ 0
</td>
+ </tr>
+
+ <tr style=";line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 31-60 days </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ 0
</td>
+ </tr>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 61-120 days </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
+ 0
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 23h </td>
+ 121-364 days </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
+ </tr>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 365+ days </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
+ </tr>
+ </tbody>
+ </table>
+ <br/>
+ <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
+ Back to top
+ </a>
+<h2 id="VisitFrequency_get" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Returning Visits
+</h2>
+
+
+
+ <table style="border-collapse:collapse; margin-left: 5px;">
+ <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Name&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Value&nbsp;&nbsp;
+ </th>
+ </thead>
+ <tbody>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ Unique returning visitors </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 1
+ </td>
+ </tr>
+
+ <tr style=";line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ Returning Users </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
+ </tr>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ Returning Visits </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:00:00
+ 4
</td>
+ </tr>
+
+ <tr style=";line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ Actions by Returning Visits </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ 12
+ </td>
+ </tr>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ Maximum actions in one returning visit </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 6
</td>
+ </tr>
+
+ <tr style=";line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ Bounce Rate for Returning Visits </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
+ 25%
+ </td>
+ </tr>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ Avg. Actions per Returning Visit </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 3
+ </td>
+ </tr>
+
+ <tr style=";line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ Avg. Duration of a Returning Visit (in sec) </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 00:25:32
</td>
</tr>
</tbody>
@@ -1126,7 +2478,7 @@
Back to top
</a>
<h2 id="VisitTime_getVisitInformationPerLocalTime" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Visits by Local Time
+ Visits per local time
</h2>
@@ -1714,8 +3066,8 @@
<a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
Back to top
</a>
-<h2 id="VisitTime_getByDayOfWeek" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Visits by Day of Week
+<h2 id="VisitTime_getVisitInformationPerServerTime" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Visits per server time
</h2>
@@ -1723,7 +3075,7 @@
<table style="border-collapse:collapse; margin-left: 5px;">
<thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
<th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Day of the week&nbsp;&nbsp;
+ &nbsp;Server time&nbsp;&nbsp;
</th>
<th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
&nbsp;Visits&nbsp;&nbsp;
@@ -1741,83 +3093,83 @@
&nbsp;Bounce Rate&nbsp;&nbsp;
</th>
<th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Conversion Rate&nbsp;&nbsp;
+ &nbsp;Revenue&nbsp;&nbsp;
</th>
</thead>
<tbody>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Monday </td>
+ 0h </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 1
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 4
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 4
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:00:00
+ 00:12:01
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ $ 10
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Tuesday </td>
+ 1h </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 3
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 13
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 4.3
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:30:01
+ 00:00:00
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 66.67%
+ $ 0
</td>
</tr>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Wednesday </td>
+ 2h </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
2
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 3
+ 9
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1.5
+ 4.5
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:12:02
+ 00:42:01
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 50%
+ 0%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 100%
+ $ 3111.11
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Thursday </td>
+ 3h </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
@@ -1834,13 +3186,13 @@
0%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ $ 0
</td>
</tr>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Friday </td>
+ 4h </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
@@ -1857,13 +3209,13 @@
0%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ $ 0
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Saturday </td>
+ 5h </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
@@ -1880,13 +3232,59 @@
0%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ $ 0
+ </td>
+ </tr>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 6h </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 1
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 00:06:03
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 100%
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ $ 10240
+ </td>
+ </tr>
+
+ <tr style=";line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 7h </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 1
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 3
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 3
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 00:12:01
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0%
</td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ $ 0
+ </td>
</tr>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Sunday </td>
+ 8h </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
@@ -1903,365 +3301,352 @@
0%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ $ 0
</td>
</tr>
- </tbody>
- </table>
- <br/>
- <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
- Back to top
- </a>
-<h2 id="Resolution_getResolution" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Screen Resolution
-</h2>
-
-
-
- <table style="border-collapse:collapse; margin-left: 5px;">
- <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Resolution&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Visits&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Actions&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Actions per Visit&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Avg. Time on Website&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Bounce Rate&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Conversion Rate&nbsp;&nbsp;
- </th>
- </thead>
- <tbody>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+
+ <tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1024x768 </td>
+ 9h </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 5
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 16
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 3.2
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:22:49
+ 00:00:00
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 20%
+ 0%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 80%
+ $ 0
</td>
</tr>
- </tbody>
- </table>
- <br/>
- <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
- Back to top
- </a>
-<h2 id="DevicePlugins_getPlugin" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Browser Plugins
-</h2>
-
-
-
- <table style="border-collapse:collapse; margin-left: 5px;">
- <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Plugin&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Visits&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;% Visits&nbsp;&nbsp;
- </th>
- </thead>
- <tbody>
-
+
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicePlugins/images/plugins/cookie.gif'>
- &nbsp;
- Cookie </td>
+ 10h </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 5
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 100%
+ 0
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 00:00:00
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0%
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ $ 0
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicePlugins/images/plugins/flash.gif'>
- &nbsp;
- Flash </td>
+ 11h </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 5
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 100%
+ 0
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 00:00:00
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0%
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ $ 0
</td>
</tr>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicePlugins/images/plugins/java.gif'>
- &nbsp;
- Java </td>
+ 12h </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 5
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 100%
+ 0
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 00:00:00
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0%
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ $ 0
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicePlugins/images/plugins/director.gif'>
- &nbsp;
- Director </td>
+ 13h </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0
+ </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 00:00:00
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0%
</td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ $ 0
+ </td>
</tr>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicePlugins/images/plugins/gears.gif'>
- &nbsp;
- Gears </td>
+ 14h </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 00:00:00
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0%
</td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ $ 0
+ </td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicePlugins/images/plugins/pdf.gif'>
- &nbsp;
- Pdf </td>
+ 15h </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0
+ </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 00:00:00
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0%
</td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ $ 0
+ </td>
</tr>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicePlugins/images/plugins/quicktime.gif'>
- &nbsp;
- Quicktime </td>
+ 16h </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 00:00:00
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0%
</td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ $ 0
+ </td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicePlugins/images/plugins/realplayer.gif'>
- &nbsp;
- Realplayer </td>
+ 17h </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 00:00:00
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0%
</td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ $ 0
+ </td>
</tr>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicePlugins/images/plugins/silverlight.gif'>
- &nbsp;
- Silverlight </td>
+ 18h </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0
+ </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 00:00:00
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0%
</td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ $ 0
+ </td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicePlugins/images/plugins/windowsmedia.gif'>
- &nbsp;
- Windowsmedia </td>
+ 19h </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 00:00:00
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0%
</td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ $ 0
+ </td>
</tr>
- </tbody>
- </table>
- <br/>
- <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
- Back to top
- </a>
-<h2 id="Resolution_getConfiguration" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Visitor Configuration
-</h2>
-
-
-
- <table style="border-collapse:collapse; margin-left: 5px;">
- <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Configuration&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Visits&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Actions&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Actions per Visit&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Avg. Time on Website&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Bounce Rate&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Conversion Rate&nbsp;&nbsp;
- </th>
- </thead>
- <tbody>
-
+
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Windows / Firefox / 1024x768 </td>
+ 20h </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 5
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 16
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 3.2
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:22:49
+ 00:00:00
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 20%
+ 0%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 80%
+ $ 0
</td>
</tr>
- </tbody>
- </table>
- <br/>
- <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
- Back to top
- </a>
-<h2 id="UserLanguage_getLanguage" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Browser language
-</h2>
-
-
-
- <table style="border-collapse:collapse; margin-left: 5px;">
- <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Language&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Visits&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Actions&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Actions per Visit&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Avg. Time on Website&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Bounce Rate&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Conversion Rate&nbsp;&nbsp;
- </th>
- </thead>
- <tbody>
-
+
+ <tr style=";line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 21h </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 00:00:00
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0%
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ $ 0
+ </td>
+ </tr>
+
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Polish </td>
+ 22h </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 4
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 12
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 3
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:25:32
+ 00:00:00
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 25%
+ 0%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 75%
+ $ 0
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- French </td>
+ 23h </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 4
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 4
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:12:01
+ 00:00:00
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 100%
+ $ 0
</td>
</tr>
</tbody>
@@ -2270,8 +3655,8 @@
<a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
Back to top
</a>
-<h2 id="UserLanguage_getLanguageCode" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Language code
+<h2 id="VisitTime_getByDayOfWeek" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Visits by Day of Week
</h2>
@@ -2279,7 +3664,7 @@
<table style="border-collapse:collapse; margin-left: 5px;">
<thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
<th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Language&nbsp;&nbsp;
+ &nbsp;Day of the week&nbsp;&nbsp;
</th>
<th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
&nbsp;Visits&nbsp;&nbsp;
@@ -2304,149 +3689,162 @@
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Polish (pl) </td>
+ Monday </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 4
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 12
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 3
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:25:32
+ 00:00:00
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 25%
+ 0%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 75%
+ 0%
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- French (fr) </td>
+ Tuesday </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
+ 3
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 4
+ 13
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 4
+ 4.3
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:12:01
+ 00:30:01
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0%
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 100%
+ 66.67%
</td>
</tr>
- </tbody>
- </table>
- <br/>
- <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
- Back to top
- </a>
-<h2 id="Goals_get_idGoal--ecommerceOrder" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Ecommerce Orders
-</h2>
-
-
-
- <table style="border-collapse:collapse; margin-left: 5px;">
- <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Name&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Value&nbsp;&nbsp;
- </th>
- </thead>
- <tbody>
-
+
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Ecommerce Orders </td>
+ Wednesday </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 4
+ 2
</td>
- </tr>
-
- <tr style=";line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Visits with Conversions </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 2
+ 3
</td>
- </tr>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Revenue </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 13351.11
+ 1.5
</td>
- </tr>
-
- <tr style=";line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Subtotal </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 2700
+ 00:12:02
</td>
- </tr>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Tax </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 531
+ 50%
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 100%
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Shipping </td>
+ Thursday </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 120.11
+ 0
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 00:00:00
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0%
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0%
</td>
</tr>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Discount </td>
+ Friday </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 686
+ 0
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 00:00:00
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0%
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0%
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Purchased Products </td>
+ Saturday </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 12
+ 0
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 00:00:00
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0%
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0%
</td>
</tr>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Average Order Value </td>
+ Sunday </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 3337.78
+ 0
</td>
- </tr>
-
- <tr style=";line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Conversion Rate </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 40%
+ 0
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 00:00:00
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0%
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0%
</td>
</tr>
</tbody>
@@ -2455,8 +3853,8 @@
<a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
Back to top
</a>
-<h2 id="Goals_getVisitsUntilConversion_idGoal--ecommerceOrder" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Ecommerce Orders - Visits to Conversion
+<h2 id="Actions_getPageUrls" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Page URLs
</h2>
@@ -2464,115 +3862,133 @@
<table style="border-collapse:collapse; margin-left: 5px;">
<thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
<th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Visits to Conversion&nbsp;&nbsp;
+ &nbsp;Page URL&nbsp;&nbsp;
</th>
<th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Conversions&nbsp;&nbsp;
+ &nbsp;Pageviews&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Unique Pageviews&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Avg. time on page&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Bounce Rate&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Exit rate&nbsp;&nbsp;
</th>
</thead>
<tbody>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1 visit </td>
+ <a style="color: rgb(13,13,13);" href='http://example.org/index.htm'>
+ /index.htm </a>
+ </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 2
+ 16
</td>
- </tr>
-
- <tr style=";line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 2 visits </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 2
- </td>
- </tr>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 3 visits </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 4
</td>
- </tr>
-
- <tr style=";line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 4 visits </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 00:03:23
</td>
- </tr>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 5 visits </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 0%
</td>
- </tr>
-
- <tr style=";line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 6 visits </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 100%
</td>
</tr>
-
+ </tbody>
+ </table>
+ <br/>
+ <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
+ Back to top
+ </a>
+<h2 id="Actions_getEntryPageUrls" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Entry pages
+</h2>
+
+
+
+ <table style="border-collapse:collapse; margin-left: 5px;">
+ <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Entry Page URL&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Entrances&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Bounces&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Bounce Rate&nbsp;&nbsp;
+ </th>
+ </thead>
+ <tbody>
+
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 7 visits </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
- </td>
- </tr>
-
- <tr style=";line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 8 visits </td>
+ <a style="color: rgb(13,13,13);" href='http://example.org/index.htm'>
+ /index.htm </a>
+ </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 3
</td>
- </tr>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 9-14 visits </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
- </tr>
-
- <tr style=";line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 15-25 visits </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 0%
</td>
</tr>
-
+ </tbody>
+ </table>
+ <br/>
+ <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
+ Back to top
+ </a>
+<h2 id="Actions_getExitPageUrls" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Exit pages
+</h2>
+
+
+
+ <table style="border-collapse:collapse; margin-left: 5px;">
+ <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Exit Page URL&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Exits&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Unique Pageviews&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Exit rate&nbsp;&nbsp;
+ </th>
+ </thead>
+ <tbody>
+
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 26-50 visits </td>
+ <a style="color: rgb(13,13,13);" href='http://example.org/index.htm'>
+ /index.htm </a>
+ </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 4
</td>
- </tr>
-
- <tr style=";line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 51-100 visits </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 4
</td>
- </tr>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 101+ visits </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 100%
</td>
</tr>
</tbody>
@@ -2581,8 +3997,8 @@
<a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
Back to top
</a>
-<h2 id="Goals_getDaysToConversion_idGoal--ecommerceOrder" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Ecommerce Orders - Days to Conversion
+<h2 id="Actions_getPageTitles" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Page titles
</h2>
@@ -2590,185 +4006,183 @@
<table style="border-collapse:collapse; margin-left: 5px;">
<thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
<th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Days to Conversion&nbsp;&nbsp;
+ &nbsp;Page Name&nbsp;&nbsp;
</th>
<th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Conversions&nbsp;&nbsp;
+ &nbsp;Pageviews&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Unique Pageviews&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Avg. time on page&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Bounce Rate&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Exit rate&nbsp;&nbsp;
</th>
</thead>
<tbody>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0 days </td>
+ View product left in cart </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 4
+ 9
</td>
- </tr>
-
- <tr style=";line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1 day </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 3
</td>
- </tr>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 2 days </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 00:02:00
</td>
- </tr>
-
- <tr style=";line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 3 days </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 0%
</td>
- </tr>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 4 days </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 100%
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 5 days </td>
+ Another Product page </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 1
</td>
- </tr>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 6 days </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 1
</td>
- </tr>
-
- <tr style=";line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 7 days </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 00:06:00
</td>
- </tr>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 8-14 days </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 0%
</td>
- </tr>
-
- <tr style=";line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 15-30 days </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 0%
</td>
</tr>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 31-60 days </td>
+ Another Product page with multiple categories </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 1
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 1
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 00:00:00
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0%
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 100%
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 61-120 days </td>
+ Another Product page with no category </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 1
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 1
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 00:00:00
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0%
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0%
</td>
</tr>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 121-364 days </td>
+ incredible title! </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 1
</td>
- </tr>
-
- <tr style=";line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 365+ days </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 1
</td>
- </tr>
- </tbody>
- </table>
- <br/>
- <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
- Back to top
- </a>
-<h2 id="Goals_get_idGoal--ecommerceAbandonedCart" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Abandoned Carts
-</h2>
-
-
-
- <table style="border-collapse:collapse; margin-left: 5px;">
- <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Name&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Value&nbsp;&nbsp;
- </th>
- </thead>
- <tbody>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Abandoned Carts </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 3
+ 00:06:00
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0%
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0%
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Revenue left in cart </td>
+ Looking at Electronics &amp; Cameras page again </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 7530.33
+ 1
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 1
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 00:06:00
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0%
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0%
</td>
</tr>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Products left in cart </td>
+ Looking at Electronics &amp; Cameras page with a page level custom variable </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 12
+ 1
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 1
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 00:06:00
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0%
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0%
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Average Order Value </td>
+ Looking at product page </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 2510.11
+ 1
</td>
- </tr>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Conversion Rate </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 60%
+ 1
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 00:12:00
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0%
+ </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0%
</td>
</tr>
</tbody>
@@ -2777,8 +4191,68 @@
<a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
Back to top
</a>
-<h2 id="Goals_getVisitsUntilConversion_idGoal--ecommerceAbandonedCart" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Abandoned Carts - Visits to Conversion
+<h2 id="Actions_getSiteSearchKeywords" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Site Search Keywords
+</h2>
+
+ There is no data for this report.
+<h2 id="Actions_getPageUrlsFollowingSiteSearch" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Pages Following a Site Search
+</h2>
+
+ There is no data for this report.
+<h2 id="Actions_getSiteSearchNoResultKeywords" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Search Keywords with No Results
+</h2>
+
+ There is no data for this report.
+<h2 id="Actions_getPageTitlesFollowingSiteSearch" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Page Titles Following a Site Search
+</h2>
+
+ There is no data for this report.
+<h2 id="Actions_getSiteSearchCategories" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Search Categories
+</h2>
+
+ There is no data for this report.
+<h2 id="Actions_getOutlinks" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Outlinks
+</h2>
+
+ There is no data for this report.
+<h2 id="Actions_getDownloads" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Downloads
+</h2>
+
+ There is no data for this report.
+<h2 id="Events_getCategory" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Event Categories
+</h2>
+
+ There is no data for this report.
+<h2 id="Events_getAction" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Event Actions
+</h2>
+
+ There is no data for this report.
+<h2 id="Events_getName" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Event Names
+</h2>
+
+ There is no data for this report.
+<h2 id="Contents_getContentNames" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Content Name
+</h2>
+
+ There is no data for this report.
+<h2 id="Contents_getContentPieces" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Content Piece
+</h2>
+
+ There is no data for this report.
+<h2 id="Actions_get" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Actions - Main metrics
</h2>
@@ -2786,33 +4260,33 @@
<table style="border-collapse:collapse; margin-left: 5px;">
<thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
<th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Visits to Conversion&nbsp;&nbsp;
+ &nbsp;Name&nbsp;&nbsp;
</th>
<th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Conversions&nbsp;&nbsp;
+ &nbsp;Value&nbsp;&nbsp;
</th>
</thead>
<tbody>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1 visit </td>
+ Pageviews </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
+ 16
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 2 visits </td>
+ Unique Pageviews </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 2
+ 4
</td>
</tr>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 3 visits </td>
+ Downloads </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
@@ -2820,7 +4294,7 @@
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 4 visits </td>
+ Unique Downloads </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
@@ -2828,7 +4302,7 @@
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 5 visits </td>
+ Outlinks </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
@@ -2836,7 +4310,7 @@
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 6 visits </td>
+ Unique Outlinks </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
@@ -2844,7 +4318,7 @@
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 7 visits </td>
+ Searches </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
@@ -2852,50 +4326,80 @@
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 8 visits </td>
+ Unique Keywords </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
</tr>
-
+ </tbody>
+ </table>
+ <br/>
+ <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
+ Back to top
+ </a>
+<h2 id="Actions_getEntryPageTitles" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Entry page titles
+</h2>
+
+
+
+ <table style="border-collapse:collapse; margin-left: 5px;">
+ <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Entry Page title&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Entrances&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Bounces&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Bounce Rate&nbsp;&nbsp;
+ </th>
+ </thead>
+ <tbody>
+
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 9-14 visits </td>
+ View product left in cart </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 1
</td>
- </tr>
-
- <tr style=";line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 15-25 visits </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
- </tr>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 26-50 visits </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 0%
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 51-100 visits </td>
+ incredible title! </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 1
+ </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0%
+ </td>
</tr>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 101+ visits </td>
+ Looking at Electronics &amp; Cameras page with a page level custom variable </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 1
+ </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 0%
+ </td>
</tr>
</tbody>
</table>
@@ -2903,8 +4407,8 @@
<a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
Back to top
</a>
-<h2 id="Goals_getDaysToConversion_idGoal--ecommerceAbandonedCart" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Abandoned Carts - Days to Conversion
+<h2 id="Actions_getExitPageTitles" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Exit page titles
</h2>
@@ -2912,123 +4416,105 @@
<table style="border-collapse:collapse; margin-left: 5px;">
<thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
<th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Days to Conversion&nbsp;&nbsp;
+ &nbsp;Exit Page Title&nbsp;&nbsp;
</th>
<th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Conversions&nbsp;&nbsp;
+ &nbsp;Exits&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Unique Pageviews&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Exit rate&nbsp;&nbsp;
</th>
</thead>
<tbody>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0 days </td>
+ View product left in cart </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
3
</td>
- </tr>
-
- <tr style=";line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1 day </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
- </td>
- </tr>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 2 days </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
- </td>
- </tr>
-
- <tr style=";line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 3 days </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 3
</td>
- </tr>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 4 days </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 100%
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 5 days </td>
+ Another Product page with multiple categories </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 1
</td>
- </tr>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 6 days </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 1
</td>
- </tr>
-
- <tr style=";line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 7 days </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 100%
</td>
</tr>
-
+ </tbody>
+ </table>
+ <br/>
+ <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
+ Back to top
+ </a>
+<h2 id="Referrers_getReferrerType" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Referrer Type
+</h2>
+
+
+
+ <table style="border-collapse:collapse; margin-left: 5px;">
+ <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Referrer Type&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Visits&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Actions&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Actions per Visit&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Avg. Time on Website&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Bounce Rate&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Revenue&nbsp;&nbsp;
+ </th>
+ </thead>
+ <tbody>
+
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 8-14 days </td>
+ Direct Entry </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 5
</td>
- </tr>
-
- <tr style=";line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 15-30 days </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 16
</td>
- </tr>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 31-60 days </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 3.2
</td>
- </tr>
-
- <tr style=";line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 61-120 days </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 00:22:49
</td>
- </tr>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 121-364 days </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 20%
</td>
- </tr>
-
- <tr style=";line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 365+ days </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ $ 13361.11
</td>
</tr>
</tbody>
@@ -3037,6 +4523,36 @@
<a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
Back to top
</a>
+<h2 id="Referrers_getAll" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ All Referrers
+</h2>
+
+ There is no data for this report.
+<h2 id="Referrers_getKeywords" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Keywords
+</h2>
+
+ There is no data for this report.
+<h2 id="Referrers_getSearchEngines" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Search Engines
+</h2>
+
+ There is no data for this report.
+<h2 id="Referrers_getWebsites" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Websites
+</h2>
+
+ There is no data for this report.
+<h2 id="Referrers_getSocials" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Social Networks
+</h2>
+
+ There is no data for this report.
+<h2 id="Referrers_getCampaigns" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Campaigns
+</h2>
+
+ There is no data for this report.
<h2 id="Goals_getItemsSku" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
Product SKU
</h2>
@@ -3348,7 +4864,7 @@
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- PRODUCT THREE LEFT in cart </td>
+ PRODUCT TWO LEFT in cart </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
$ 0
</td>
@@ -3362,7 +4878,7 @@
3
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 1332
+ $ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
@@ -3374,7 +4890,7 @@
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- PRODUCT TWO LEFT in cart </td>
+ PRODUCT THREE LEFT in cart </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
$ 0
</td>
@@ -3388,7 +4904,7 @@
3
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
+ $ 1332
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
@@ -3651,8 +5167,8 @@
<a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
Back to top
</a>
-<h2 id="Actions_get" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Actions - Main metrics
+<h2 id="Goals_get_idGoal--ecommerceOrder" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Ecommerce Orders
</h2>
@@ -3670,725 +5186,73 @@
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Pageviews </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 16
- </td>
- </tr>
-
- <tr style=";line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Unique Pageviews </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 4
- </td>
- </tr>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Downloads </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
- </td>
- </tr>
-
- <tr style=";line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Unique Downloads </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
- </td>
- </tr>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Outlinks </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
- </td>
- </tr>
-
- <tr style=";line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Unique Outlinks </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
- </td>
- </tr>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Searches </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
- </td>
- </tr>
-
- <tr style=";line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Unique Keywords </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
- </td>
- </tr>
- </tbody>
- </table>
- <br/>
- <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
- Back to top
- </a>
-<h2 id="Actions_getPageUrls" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Page URLs
-</h2>
-
-
-
- <table style="border-collapse:collapse; margin-left: 5px;">
- <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Page URL&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Pageviews&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Unique Pageviews&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Avg. time on page&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Bounce Rate&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Exit rate&nbsp;&nbsp;
- </th>
- </thead>
- <tbody>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- <a style="color: rgb(13,13,13);" href='http://example.org/index.htm'>
- /index.htm </a>
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 16
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 4
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:03:23
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 100%
- </td>
- </tr>
- </tbody>
- </table>
- <br/>
- <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
- Back to top
- </a>
-<h2 id="Actions_getEntryPageUrls" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Entry pages
-</h2>
-
-
-
- <table style="border-collapse:collapse; margin-left: 5px;">
- <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Entry Page URL&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Entrances&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Bounces&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Bounce Rate&nbsp;&nbsp;
- </th>
- </thead>
- <tbody>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- <a style="color: rgb(13,13,13);" href='http://example.org/index.htm'>
- /index.htm </a>
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 3
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
- </td>
- </tr>
- </tbody>
- </table>
- <br/>
- <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
- Back to top
- </a>
-<h2 id="Actions_getExitPageUrls" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Exit pages
-</h2>
-
-
-
- <table style="border-collapse:collapse; margin-left: 5px;">
- <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Exit Page URL&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Exits&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Unique Pageviews&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Exit rate&nbsp;&nbsp;
- </th>
- </thead>
- <tbody>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- <a style="color: rgb(13,13,13);" href='http://example.org/index.htm'>
- /index.htm </a>
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 4
- </td>
+ Ecommerce Orders </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
4
</td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 100%
- </td>
- </tr>
- </tbody>
- </table>
- <br/>
- <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
- Back to top
- </a>
-<h2 id="Actions_getPageTitles" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Page titles
-</h2>
-
-
-
- <table style="border-collapse:collapse; margin-left: 5px;">
- <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Page Name&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Pageviews&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Unique Pageviews&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Avg. time on page&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Bounce Rate&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Exit rate&nbsp;&nbsp;
- </th>
- </thead>
- <tbody>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- View product left in cart </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 9
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 3
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:02:00
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 100%
- </td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Another Product page </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:06:00
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
- </td>
- </tr>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Another Product page with multiple categories </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:00:00
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 100%
- </td>
- </tr>
-
- <tr style=";line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Another Product page with no category </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:00:00
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
- </td>
+ Visits with Conversions </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ 2
</td>
</tr>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- incredible title! </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:06:00
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
- </td>
+ Revenue </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ $ 13351.11
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Looking at Electronics &amp; Cameras page again </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:06:00
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
- </td>
- </tr>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Looking at Electronics &amp; Cameras page with a page level custom variable </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:06:00
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
- </td>
+ Subtotal </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ $ 2700
</td>
</tr>
- <tr style=";line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Looking at product page </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:12:00
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
- </td>
- </tr>
- </tbody>
- </table>
- <br/>
- <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
- Back to top
- </a>
-<h2 id="Actions_getEntryPageTitles" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Entry page titles
-</h2>
-
-
-
- <table style="border-collapse:collapse; margin-left: 5px;">
- <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Entry Page title&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Entrances&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Bounces&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Bounce Rate&nbsp;&nbsp;
- </th>
- </thead>
- <tbody>
-
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- View product left in cart </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
- </td>
+ Tax </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ $ 531
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- incredible title! </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
- </td>
- </tr>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Looking at Electronics &amp; Cameras page with a page level custom variable </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
- </td>
- </tr>
- </tbody>
- </table>
- <br/>
- <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
- Back to top
- </a>
-<h2 id="Actions_getExitPageTitles" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Exit page titles
-</h2>
-
-
-
- <table style="border-collapse:collapse; margin-left: 5px;">
- <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Exit Page Title&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Exits&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Unique Pageviews&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Exit rate&nbsp;&nbsp;
- </th>
- </thead>
- <tbody>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- View product left in cart </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 3
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 3
- </td>
+ Shipping </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 100%
+ $ 120.11
</td>
</tr>
- <tr style=";line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Another Product page with multiple categories </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 100%
- </td>
- </tr>
- </tbody>
- </table>
- <br/>
- <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
- Back to top
- </a>
-<h2 id="Actions_getOutlinks" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Outlinks
-</h2>
-
- There is no data for this report.
-<h2 id="Actions_getDownloads" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Downloads
-</h2>
-
- There is no data for this report.
-<h2 id="Contents_getContentNames" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Content Name
-</h2>
-
- There is no data for this report.
-<h2 id="Contents_getContentPieces" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Content Piece
-</h2>
-
- There is no data for this report.
-<h2 id="Events_getCategory" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Event Categories
-</h2>
-
- There is no data for this report.
-<h2 id="Events_getAction" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Event Actions
-</h2>
-
- There is no data for this report.
-<h2 id="Events_getName" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Event Names
-</h2>
-
- There is no data for this report.
-<h2 id="Actions_getSiteSearchKeywords" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Site Search Keywords
-</h2>
-
- There is no data for this report.
-<h2 id="Actions_getSiteSearchNoResultKeywords" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Search Keywords with No Results
-</h2>
-
- There is no data for this report.
-<h2 id="Actions_getSiteSearchCategories" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Search Categories
-</h2>
-
- There is no data for this report.
-<h2 id="Actions_getPageUrlsFollowingSiteSearch" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Pages Following a Site Search
-</h2>
-
- There is no data for this report.
-<h2 id="Actions_getPageTitlesFollowingSiteSearch" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Page Titles Following a Site Search
-</h2>
-
- There is no data for this report.
-<h2 id="Referrers_getReferrerType" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Referrer Type
-</h2>
-
-
-
- <table style="border-collapse:collapse; margin-left: 5px;">
- <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Referrer Type&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Visits&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Actions&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Actions per Visit&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Avg. Time on Website&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Bounce Rate&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Revenue&nbsp;&nbsp;
- </th>
- </thead>
- <tbody>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Direct Entry </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 5
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 16
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 3.2
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:22:49
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 20%
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 13361.11
- </td>
- </tr>
- </tbody>
- </table>
- <br/>
- <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
- Back to top
- </a>
-<h2 id="Referrers_getAll" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- All Referrers
-</h2>
-
- There is no data for this report.
-<h2 id="Referrers_getKeywords" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Keywords
-</h2>
-
- There is no data for this report.
-<h2 id="Referrers_getWebsites" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Websites
-</h2>
-
- There is no data for this report.
-<h2 id="Referrers_getSearchEngines" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Search Engines
-</h2>
-
- There is no data for this report.
-<h2 id="Referrers_getCampaigns" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Campaigns
-</h2>
-
- There is no data for this report.
-<h2 id="Referrers_getSocials" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Social Networks
-</h2>
-
- There is no data for this report.
-<h2 id="Goals_get" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Goals
-</h2>
-
-
-
- <table style="border-collapse:collapse; margin-left: 5px;">
- <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Name&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Value&nbsp;&nbsp;
- </th>
- </thead>
- <tbody>
-
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Conversions </td>
+ Discount </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 5
+ $ 686
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Visits with Conversions </td>
+ Purchased Products </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 4
+ 12
</td>
</tr>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Revenue </td>
+ Average Order Value </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 13361.11
+ $ 3337.78
</td>
</tr>
@@ -4396,7 +5260,7 @@
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
Conversion Rate </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 80%
+ 40%
</td>
</tr>
</tbody>
@@ -4405,8 +5269,8 @@
<a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
Back to top
</a>
-<h2 id="Goals_getVisitsUntilConversion" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Visits to Conversion
+<h2 id="Goals_getVisitsUntilConversion_idGoal--ecommerceOrder" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Ecommerce Orders - Visits to Conversion
</h2>
@@ -4419,9 +5283,6 @@
<th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
&nbsp;Conversions&nbsp;&nbsp;
</th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Revenue&nbsp;&nbsp;
- </th>
</thead>
<tbody>
@@ -4429,10 +5290,7 @@
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
1 visit </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
+ 2
</td>
</tr>
@@ -4440,10 +5298,7 @@
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
2 visits </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
+ 2
</td>
</tr>
@@ -4453,9 +5308,6 @@
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
- </td>
</tr>
<tr style=";line-height: 22px;">
@@ -4464,9 +5316,6 @@
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
- </td>
</tr>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
@@ -4475,9 +5324,6 @@
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
- </td>
</tr>
<tr style=";line-height: 22px;">
@@ -4486,9 +5332,6 @@
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
- </td>
</tr>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
@@ -4497,9 +5340,6 @@
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
- </td>
</tr>
<tr style=";line-height: 22px;">
@@ -4508,9 +5348,6 @@
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
- </td>
</tr>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
@@ -4519,9 +5356,6 @@
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
- </td>
</tr>
<tr style=";line-height: 22px;">
@@ -4530,9 +5364,6 @@
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
- </td>
</tr>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
@@ -4541,9 +5372,6 @@
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
- </td>
</tr>
<tr style=";line-height: 22px;">
@@ -4552,9 +5380,6 @@
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
- </td>
</tr>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
@@ -4563,9 +5388,6 @@
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
- </td>
</tr>
</tbody>
</table>
@@ -4573,8 +5395,8 @@
<a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
Back to top
</a>
-<h2 id="Goals_getDaysToConversion" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Days to Conversion
+<h2 id="Goals_getDaysToConversion_idGoal--ecommerceOrder" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Ecommerce Orders - Days to Conversion
</h2>
@@ -4587,9 +5409,6 @@
<th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
&nbsp;Conversions&nbsp;&nbsp;
</th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Revenue&nbsp;&nbsp;
- </th>
</thead>
<tbody>
@@ -4597,10 +5416,7 @@
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0 days </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
+ 4
</td>
</tr>
@@ -4610,9 +5426,6 @@
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
- </td>
</tr>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
@@ -4621,9 +5434,6 @@
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
- </td>
</tr>
<tr style=";line-height: 22px;">
@@ -4632,9 +5442,6 @@
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
- </td>
</tr>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
@@ -4643,9 +5450,6 @@
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
- </td>
</tr>
<tr style=";line-height: 22px;">
@@ -4654,9 +5458,6 @@
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
- </td>
</tr>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
@@ -4665,9 +5466,6 @@
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
- </td>
</tr>
<tr style=";line-height: 22px;">
@@ -4676,9 +5474,6 @@
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
- </td>
</tr>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
@@ -4687,9 +5482,6 @@
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
- </td>
</tr>
<tr style=";line-height: 22px;">
@@ -4698,9 +5490,6 @@
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
- </td>
</tr>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
@@ -4709,9 +5498,6 @@
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
- </td>
</tr>
<tr style=";line-height: 22px;">
@@ -4720,9 +5506,6 @@
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
- </td>
</tr>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
@@ -4731,9 +5514,6 @@
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
- </td>
</tr>
<tr style=";line-height: 22px;">
@@ -4742,9 +5522,6 @@
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 0
- </td>
</tr>
</tbody>
</table>
@@ -4752,8 +5529,8 @@
<a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
Back to top
</a>
-<h2 id="Goals_get_idGoal--1" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Goal title match, triggered ONCE
+<h2 id="Goals_get_idGoal--ecommerceAbandonedCart" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Abandoned Carts
</h2>
@@ -4771,33 +5548,41 @@
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Conversions </td>
+ Abandoned Carts </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
+ 3
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Visits with Conversions </td>
+ Revenue left in cart </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
+ $ 7530.33
</td>
</tr>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Revenue </td>
+ Products left in cart </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 10
+ 12
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ Average Order Value </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ $ 2510.11
+ </td>
+ </tr>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
Conversion Rate </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 20%
+ 60%
</td>
</tr>
</tbody>
@@ -4806,8 +5591,8 @@
<a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
Back to top
</a>
-<h2 id="Goals_getVisitsUntilConversion_idGoal--1" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- title match, triggered ONCE - Visits to Conversion
+<h2 id="Goals_getVisitsUntilConversion_idGoal--ecommerceAbandonedCart" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Abandoned Carts - Visits to Conversion
</h2>
@@ -4835,7 +5620,7 @@
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
2 visits </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ 2
</td>
</tr>
@@ -4932,8 +5717,8 @@
<a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
Back to top
</a>
-<h2 id="Goals_getDaysToConversion_idGoal--1" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- title match, triggered ONCE - Days to Conversion
+<h2 id="Goals_getDaysToConversion_idGoal--ecommerceAbandonedCart" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Abandoned Carts - Days to Conversion
</h2>
@@ -4953,7 +5738,7 @@
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0 days </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
+ 3
</td>
</tr>
@@ -5066,8 +5851,8 @@
<a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
Back to top
</a>
-<h2 id="UserCountry_getCountry" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Country
+<h2 id="Goals_get" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Goals
</h2>
@@ -5075,260 +5860,43 @@
<table style="border-collapse:collapse; margin-left: 5px;">
<thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
<th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Country&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Visits&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Actions&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Actions per Visit&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Avg. Time on Website&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Bounce Rate&nbsp;&nbsp;
+ &nbsp;Name&nbsp;&nbsp;
</th>
<th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Revenue&nbsp;&nbsp;
+ &nbsp;Value&nbsp;&nbsp;
</th>
</thead>
<tbody>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/UserCountry/images/flags/pl.png'>
- &nbsp;
- Poland </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 4
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 12
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 3
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:25:32
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 25%
- </td>
+ Conversions </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 13351.11
+ 5
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/UserCountry/images/flags/fr.png'>
- &nbsp;
- France </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 4
- </td>
+ Visits with Conversions </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
4
</td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:12:01
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 10
- </td>
</tr>
- </tbody>
- </table>
- <br/>
- <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
- Back to top
- </a>
-<h2 id="UserCountry_getContinent" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Continent
-</h2>
-
-
-
- <table style="border-collapse:collapse; margin-left: 5px;">
- <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Continent&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Visits&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Actions&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Actions per Visit&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Avg. Time on Website&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Bounce Rate&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Revenue&nbsp;&nbsp;
- </th>
- </thead>
- <tbody>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Europe </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 5
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 16
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 3.2
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:22:49
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 20%
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 13361.11
- </td>
- </tr>
- </tbody>
- </table>
- <br/>
- <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
- Back to top
- </a>
-<h2 id="UserCountry_getRegion" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Region
-</h2>
-
-
-
- <table style="border-collapse:collapse; margin-left: 5px;">
- <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Region&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Visits&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Actions&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Actions per Visit&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Avg. Time on Website&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Bounce Rate&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Revenue&nbsp;&nbsp;
- </th>
- </thead>
- <tbody>
-
+
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/UserCountry/images/flags/xx.png'>
- &nbsp;
- Unknown </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 5
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 16
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 3.2
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:22:49
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 20%
- </td>
+ Revenue </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
$ 13361.11
</td>
</tr>
- </tbody>
- </table>
- <br/>
- <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
- Back to top
- </a>
-<h2 id="UserCountry_getCity" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- City
-</h2>
-
-
-
- <table style="border-collapse:collapse; margin-left: 5px;">
- <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;City&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Visits&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Actions&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Actions per Visit&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Avg. Time on Website&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Bounce Rate&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Revenue&nbsp;&nbsp;
- </th>
- </thead>
- <tbody>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+
+ <tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/UserCountry/images/flags/xx.png'>
- &nbsp;
- Unknown </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 5
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 16
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 3.2
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:22:49
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 20%
- </td>
+ Conversion Rate </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 13361.11
+ 80%
</td>
</tr>
</tbody>
@@ -5337,8 +5905,8 @@
<a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
Back to top
</a>
-<h2 id="CustomVariables_getCustomVariables" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Custom Variables
+<h2 id="Goals_getVisitsUntilConversion" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Visits to Conversion
</h2>
@@ -5346,22 +5914,10 @@
<table style="border-collapse:collapse; margin-left: 5px;">
<thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
<th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Custom Variable name&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Visits&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Actions&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Actions per Visit&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Avg. Time on Website&nbsp;&nbsp;
+ &nbsp;Visits to Conversion&nbsp;&nbsp;
</th>
<th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Bounce Rate&nbsp;&nbsp;
+ &nbsp;Conversions&nbsp;&nbsp;
</th>
<th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
&nbsp;Revenue&nbsp;&nbsp;
@@ -5371,274 +5927,144 @@
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- ValueIsZero </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 5
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 16
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 3.2
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:22:49
- </td>
+ 1 visit </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 20%
+ 1
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 13361.11
+ $ 0
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- VisitorType </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 5
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 16
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 3.2
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:22:49
- </td>
+ 2 visits </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 20%
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 13361.11
+ $ 0
</td>
</tr>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- VisitorName </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 4
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 12
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 3
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:25:32
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 25%
- </td>
+ 3 visits </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- $ 13351.11
+ 0
</td>
- </tr>
- </tbody>
- </table>
- <br/>
- <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
- Back to top
- </a>
-<h2 id="VisitorInterest_getNumberOfVisitsPerVisitDuration" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Length of Visits
-</h2>
-
-
-
- <table style="border-collapse:collapse; margin-left: 5px;">
- <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Visit duration&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Visits&nbsp;&nbsp;
- </th>
- </thead>
- <tbody>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0-10s </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ $ 0
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 11-30s </td>
+ 4 visits </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ $ 0
+ </td>
</tr>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 31-60s </td>
+ 5 visits </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
- </tr>
-
- <tr style=";line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1-2 min </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ $ 0
</td>
</tr>
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 2-4 min </td>
+ 6 visits </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
- </tr>
-
- <tr style=";line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 4-7 min </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
+ $ 0
</td>
</tr>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 7-10 min </td>
+ 7 visits </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
- </tr>
-
- <tr style=";line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 10-15 min </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 2
- </td>
- </tr>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 15-30 min </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
+ $ 0
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 30+ min </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
- </td>
- </tr>
- </tbody>
- </table>
- <br/>
- <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
- Back to top
- </a>
-<h2 id="VisitorInterest_getNumberOfVisitsPerPage" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Pages per Visit
-</h2>
-
-
-
- <table style="border-collapse:collapse; margin-left: 5px;">
- <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Pages per visit&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Visits&nbsp;&nbsp;
- </th>
- </thead>
- <tbody>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1 page </td>
+ 8 visits </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
- </tr>
-
- <tr style=";line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 2 pages </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ $ 0
</td>
</tr>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 3 pages </td>
+ 9-14 visits </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 2
+ 0
</td>
- </tr>
-
- <tr style=";line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 4 pages </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
+ $ 0
</td>
</tr>
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 5 pages </td>
+ 15-25 visits </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
- </tr>
-
- <tr style=";line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 6-7 pages </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1
+ $ 0
</td>
</tr>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 8-10 pages </td>
+ 26-50 visits </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ $ 0
+ </td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 11-14 pages </td>
+ 51-100 visits </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ $ 0
+ </td>
</tr>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 15-20 pages </td>
+ 101+ visits </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
- </tr>
-
- <tr style=";line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 21+ pages </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ $ 0
</td>
</tr>
</tbody>
@@ -5647,8 +6073,8 @@
<a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
Back to top
</a>
-<h2 id="VisitorInterest_getNumberOfVisitsByVisitCount" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Visits by Visit Number
+<h2 id="Goals_getDaysToConversion" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Days to Conversion
</h2>
@@ -5656,168 +6082,168 @@
<table style="border-collapse:collapse; margin-left: 5px;">
<thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
<th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Visits by Visit Number&nbsp;&nbsp;
+ &nbsp;Days to Conversion&nbsp;&nbsp;
</th>
<th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Visits&nbsp;&nbsp;
+ &nbsp;Conversions&nbsp;&nbsp;
</th>
<th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;% Visits&nbsp;&nbsp;
+ &nbsp;Revenue&nbsp;&nbsp;
</th>
</thead>
<tbody>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1 visit </td>
+ 0 days </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 3
+ 1
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 60%
+ $ 0
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 2 visits </td>
+ 1 day </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 2
+ 0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 40%
+ $ 0
</td>
</tr>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 3 visits </td>
+ 2 days </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ $ 0
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 4 visits </td>
+ 3 days </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ $ 0
</td>
</tr>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 5 visits </td>
+ 4 days </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ $ 0
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 6 visits </td>
+ 5 days </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ $ 0
</td>
</tr>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 7 visits </td>
+ 6 days </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ $ 0
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 8 visits </td>
+ 7 days </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ $ 0
</td>
</tr>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 9-14 visits </td>
+ 8-14 days </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ $ 0
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 15-25 visits </td>
+ 15-30 days </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ $ 0
</td>
</tr>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 26-50 visits </td>
+ 31-60 days </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ $ 0
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 51-100 visits </td>
+ 61-120 days </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ $ 0
</td>
</tr>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 101-200 visits </td>
+ 121-364 days </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ $ 0
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 201+ visits </td>
+ 365+ days </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0%
+ $ 0
</td>
</tr>
</tbody>
@@ -5826,8 +6252,8 @@
<a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
Back to top
</a>
-<h2 id="VisitorInterest_getNumberOfVisitsByDaysSinceLast" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Visits by days since last visit
+<h2 id="Goals_get_idGoal--1" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Goal title match, triggered ONCE
</h2>
@@ -5835,17 +6261,17 @@
<table style="border-collapse:collapse; margin-left: 5px;">
<thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
<th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Visits by days since last visit&nbsp;&nbsp;
+ &nbsp;Name&nbsp;&nbsp;
</th>
<th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Visits&nbsp;&nbsp;
+ &nbsp;Value&nbsp;&nbsp;
</th>
</thead>
<tbody>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- New visits </td>
+ Conversions </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
1
</td>
@@ -5853,7 +6279,7 @@
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0 days </td>
+ Visits with Conversions </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
1
</td>
@@ -5861,15 +6287,53 @@
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 1 day </td>
+ Revenue </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 0
+ $ 10
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 2 days </td>
+ Conversion Rate </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 20%
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ <br/>
+ <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
+ Back to top
+ </a>
+<h2 id="Goals_getVisitsUntilConversion_idGoal--1" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ title match, triggered ONCE - Visits to Conversion
+</h2>
+
+
+
+ <table style="border-collapse:collapse; margin-left: 5px;">
+ <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Visits to Conversion&nbsp;&nbsp;
+ </th>
+ <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
+ &nbsp;Conversions&nbsp;&nbsp;
+ </th>
+ </thead>
+ <tbody>
+
+ <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 1 visit </td>
+ <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 1
+ </td>
+ </tr>
+
+ <tr style=";line-height: 22px;">
+ <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
+ 2 visits </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
@@ -5877,7 +6341,7 @@
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 3 days </td>
+ 3 visits </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
@@ -5885,7 +6349,7 @@
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 4 days </td>
+ 4 visits </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
@@ -5893,7 +6357,7 @@
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 5 days </td>
+ 5 visits </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
@@ -5901,7 +6365,7 @@
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 6 days </td>
+ 6 visits </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
@@ -5909,7 +6373,7 @@
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 7 days </td>
+ 7 visits </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
@@ -5917,7 +6381,7 @@
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 8-14 days </td>
+ 8 visits </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
@@ -5925,7 +6389,7 @@
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 15-30 days </td>
+ 9-14 visits </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
@@ -5933,7 +6397,7 @@
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 31-60 days </td>
+ 15-25 visits </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
@@ -5941,7 +6405,7 @@
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 61-120 days </td>
+ 26-50 visits </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
@@ -5949,7 +6413,7 @@
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 121-364 days </td>
+ 51-100 visits </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
@@ -5957,7 +6421,7 @@
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 365+ days </td>
+ 101+ visits </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
@@ -5968,8 +6432,8 @@
<a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
Back to top
</a>
-<h2 id="VisitFrequency_get" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Returning Visits
+<h2 id="Goals_getDaysToConversion_idGoal--1" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ title match, triggered ONCE - Days to Conversion
</h2>
@@ -5977,17 +6441,17 @@
<table style="border-collapse:collapse; margin-left: 5px;">
<thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
<th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Name&nbsp;&nbsp;
+ &nbsp;Days to Conversion&nbsp;&nbsp;
</th>
<th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Value&nbsp;&nbsp;
+ &nbsp;Conversions&nbsp;&nbsp;
</th>
</thead>
<tbody>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Unique returning visitors </td>
+ 0 days </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
1
</td>
@@ -5995,7 +6459,7 @@
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Returning Users </td>
+ 1 day </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
0
</td>
@@ -6003,419 +6467,97 @@
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Returning Visits </td>
+ 2 days </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 4
+ 0
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Actions by Returning Visits </td>
+ 3 days </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 12
+ 0
</td>
</tr>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Maximum actions in one returning visit </td>
+ 4 days </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 6
+ 0
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Bounce Rate for Returning Visits </td>
+ 5 days </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 25%
+ 0
</td>
</tr>
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Avg. Actions per Returning Visit </td>
+ 6 days </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 3
+ 0
</td>
</tr>
<tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Avg. Duration of a Returning Visit (in sec) </td>
+ 7 days </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:25:32
+ 0
</td>
</tr>
- </tbody>
- </table>
- <br/>
- <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
- Back to top
- </a>
-<h2 id="DevicesDetection_getType" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Device type
-</h2>
-
-
-
- <table style="border-collapse:collapse; margin-left: 5px;">
- <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Device type&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Visits&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Actions&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Actions per Visit&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Avg. Time on Website&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Bounce Rate&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Conversion Rate&nbsp;&nbsp;
- </th>
- </thead>
- <tbody>
-
+
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicesDetection/images/screens/normal.gif'>
- &nbsp;
- Desktop </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 5
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 16
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 3.2
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:22:49
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 20%
- </td>
+ 8-14 days </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 80%
+ 0
</td>
</tr>
- </tbody>
- </table>
- <br/>
- <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
- Back to top
- </a>
-<h2 id="DevicesDetection_getBrowsers" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Visitor Browser
-</h2>
-
-
-
- <table style="border-collapse:collapse; margin-left: 5px;">
- <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Browser&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Visits&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Actions&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Actions per Visit&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Avg. Time on Website&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Bounce Rate&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Conversion Rate&nbsp;&nbsp;
- </th>
- </thead>
- <tbody>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+
+ <tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicesDetection/images/browsers/FF.gif'>
- &nbsp;
- Firefox </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 5
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 16
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 3.2
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:22:49
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 20%
- </td>
+ 15-30 days </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 80%
+ 0
</td>
</tr>
- </tbody>
- </table>
- <br/>
- <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
- Back to top
- </a>
-<h2 id="DevicesDetection_getBrand" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Device brand
-</h2>
-
-
-
- <table style="border-collapse:collapse; margin-left: 5px;">
- <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Device brand&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Visits&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Actions&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Actions per Visit&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Avg. Time on Website&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Bounce Rate&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Conversion Rate&nbsp;&nbsp;
- </th>
- </thead>
- <tbody>
-
+
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicesDetection/images/brand/Unknown.ico'>
- &nbsp;
- Unknown </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 5
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 16
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 3.2
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:22:49
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 20%
- </td>
+ 31-60 days </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 80%
+ 0
</td>
</tr>
- </tbody>
- </table>
- <br/>
- <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
- Back to top
- </a>
-<h2 id="DevicesDetection_getBrowserVersions" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Browser version
-</h2>
-
-
-
- <table style="border-collapse:collapse; margin-left: 5px;">
- <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Browser version&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Visits&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Actions&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Actions per Visit&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Avg. Time on Website&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Bounce Rate&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Conversion Rate&nbsp;&nbsp;
- </th>
- </thead>
- <tbody>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+
+ <tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicesDetection/images/browsers/FF.gif'>
- &nbsp;
- Firefox 3.6 </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 5
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 16
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 3.2
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:22:49
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 20%
- </td>
+ 61-120 days </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 80%
+ 0
</td>
</tr>
- </tbody>
- </table>
- <br/>
- <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
- Back to top
- </a>
-<h2 id="DevicesDetection_getModel" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Device model
-</h2>
-
-
-
- <table style="border-collapse:collapse; margin-left: 5px;">
- <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Device model&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Visits&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Actions&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Actions per Visit&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Avg. Time on Website&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Bounce Rate&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Conversion Rate&nbsp;&nbsp;
- </th>
- </thead>
- <tbody>
-
+
<tr style="background-color: rgb(242,242,242);line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Unknown </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 5
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 16
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 3.2
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:22:49
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 20%
- </td>
+ 121-364 days </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 80%
+ 0
</td>
</tr>
- </tbody>
- </table>
- <br/>
- <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
- Back to top
- </a>
-<h2 id="DevicesDetection_getOsFamilies" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Operating System families
-</h2>
-
-
-
- <table style="border-collapse:collapse; margin-left: 5px;">
- <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Operating system family&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Visits&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Actions&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Actions per Visit&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Avg. Time on Website&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Bounce Rate&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Conversion Rate&nbsp;&nbsp;
- </th>
- </thead>
- <tbody>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
+
+ <tr style=";line-height: 22px;">
<td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicesDetection/images/os/WIN.gif'>
- &nbsp;
- Windows </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 5
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 16
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 3.2
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:22:49
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 20%
- </td>
+ 365+ days </td>
<td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 80%
+ 0
</td>
</tr>
</tbody>
@@ -6424,127 +6566,25 @@
<a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
Back to top
</a>
-<h2 id="DevicesDetection_getOsVersions" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Operating System versions
+<h2 id="ExampleUI_getTemperatures" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Data tables
</h2>
-
-
- <table style="border-collapse:collapse; margin-left: 5px;">
- <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Operating System versions&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Visits&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Actions&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Actions per Visit&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Avg. Time on Website&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Bounce Rate&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Conversion Rate&nbsp;&nbsp;
- </th>
- </thead>
- <tbody>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- <img src='http://example.com/piwik/tests/PHPUnit/proxy/plugins/DevicesDetection/images/os/WIN.gif'>
- &nbsp;
- Windows XP </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 5
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 16
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 3.2
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:22:49
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 20%
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 80%
- </td>
- </tr>
- </tbody>
- </table>
- <br/>
- <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
- Back to top
- </a>
-<h2 id="DevicesDetection_getBrowserEngines" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
- Browser engines
+ There is no data for this report.
+<h2 id="ExampleUI_getTemperaturesEvolution" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Temperatures evolution over time
</h2>
-
-
- <table style="border-collapse:collapse; margin-left: 5px;">
- <thead style="background-color: rgb(255,255,255); color: rgb(13,13,13); font-size: 11pt; text-transform: uppercase; line-height:2.5em;">
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Browser engine&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Visits&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Actions&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Actions per Visit&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Avg. Time on Website&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Bounce Rate&nbsp;&nbsp;
- </th>
- <th style="font-weight: normal; font-size:10px; text-align:left; padding: 6px 0;">
- &nbsp;Conversion Rate&nbsp;&nbsp;
- </th>
- </thead>
- <tbody>
-
- <tr style="background-color: rgb(242,242,242);line-height: 22px;">
- <td style="font-size: 13px; border-right: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- Gecko (Firefox) </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 5
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 16
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 3.2
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 00:22:49
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 20%
- </td>
- <td style="font-size: 13px; border-left: 1px solid rgb(217,217,217); padding: 5px 0 5px 5px;">
- 80%
- </td>
- </tr>
- </tbody>
- </table>
- <br/>
- <a style="text-decoration:none; color: rgb(13,13,13); font-size: 9pt;" href="#reportTop">
- Back to top
- </a>
+ There is no data for this report.
+<h2 id="ExampleUI_getPlanetRatios" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Pie graph
+</h2>
+
+ There is no data for this report.
+<h2 id="ExampleUI_getPlanetRatiosWithLogos" style="color: rgb(13,13,13); font-size: 24pt; font-weight:normal;">
+ Advanced tag cloud: with logos and links
+</h2>
+
+ There is no data for this report.
</body>
</html> \ No newline at end of file
diff --git a/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_scheduled_report_in_pdf_tables_only__ScheduledReports.generateReport_week.original.pdf b/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_scheduled_report_in_pdf_tables_only__ScheduledReports.generateReport_week.original.pdf
index 81867deed1..ad4f004aaa 100644
--- a/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_scheduled_report_in_pdf_tables_only__ScheduledReports.generateReport_week.original.pdf
+++ b/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_scheduled_report_in_pdf_tables_only__ScheduledReports.generateReport_week.original.pdf
Binary files differ
diff --git a/tests/PHPUnit/System/expected/test_ecommerceOrderWithItemsmultipleDates__Goals.getItemsName_day.xml b/tests/PHPUnit/System/expected/test_ecommerceOrderWithItemsmultipleDates__Goals.getItemsName_day.xml
index bdc280c4c9..f48390dcdb 100644
--- a/tests/PHPUnit/System/expected/test_ecommerceOrderWithItemsmultipleDates__Goals.getItemsName_day.xml
+++ b/tests/PHPUnit/System/expected/test_ecommerceOrderWithItemsmultipleDates__Goals.getItemsName_day.xml
@@ -32,20 +32,20 @@
<conversion_rate>0%</conversion_rate>
</row>
<row>
- <label>PRODUCT THREE LEFT in cart</label>
+ <label>PRODUCT TWO LEFT in cart</label>
<nb_uniq_visitors>1</nb_uniq_visitors>
<nb_visits>2</nb_visits>
- <nb_actions>4</nb_actions>
- <avg_price>666</avg_price>
+ <nb_actions>2</nb_actions>
+ <avg_price>0</avg_price>
<avg_quantity>0</avg_quantity>
<conversion_rate>0%</conversion_rate>
</row>
<row>
- <label>PRODUCT TWO LEFT in cart</label>
+ <label>PRODUCT THREE LEFT in cart</label>
<nb_uniq_visitors>1</nb_uniq_visitors>
<nb_visits>2</nb_visits>
- <nb_actions>2</nb_actions>
- <avg_price>0</avg_price>
+ <nb_actions>4</nb_actions>
+ <avg_price>666</avg_price>
<avg_quantity>0</avg_quantity>
<conversion_rate>0%</conversion_rate>
</row>
diff --git a/tests/PHPUnit/System/expected/test_periodIsRange_dateIsLastN_MetadataAndNormalAPI__API.getProcessedReport_range.xml b/tests/PHPUnit/System/expected/test_periodIsRange_dateIsLastN_MetadataAndNormalAPI__API.getProcessedReport_range.xml
index 61d15c6685..c866fba5b5 100644
--- a/tests/PHPUnit/System/expected/test_periodIsRange_dateIsLastN_MetadataAndNormalAPI__API.getProcessedReport_range.xml
+++ b/tests/PHPUnit/System/expected/test_periodIsRange_dateIsLastN_MetadataAndNormalAPI__API.getProcessedReport_range.xml
@@ -4,6 +4,7 @@
<metadata>
<category>Visitors</category>
+ <subcategory>Locations</subcategory>
<name>Country</name>
<module>UserCountry</module>
<action>getCountry</action>
diff --git a/tests/PHPUnit/System/expected/test_periodIsRange_dateIsLastN_MetadataAndNormalAPI__CustomVariables.getCustomVariables_range.xml b/tests/PHPUnit/System/expected/test_periodIsRange_dateIsLastN_MetadataAndNormalAPI__CustomVariables.getCustomVariables_range.xml
index 8851c23d9a..ed926db9f7 100644
--- a/tests/PHPUnit/System/expected/test_periodIsRange_dateIsLastN_MetadataAndNormalAPI__CustomVariables.getCustomVariables_range.xml
+++ b/tests/PHPUnit/System/expected/test_periodIsRange_dateIsLastN_MetadataAndNormalAPI__CustomVariables.getCustomVariables_range.xml
@@ -124,35 +124,6 @@
</subtable>
</row>
<row>
- <label>Status user</label>
- <nb_actions>3</nb_actions>
- <slots>
- <row>
- <scope>page</scope>
- <index>4</index>
- </row>
- <row>
- <scope>page</scope>
- <index>5</index>
- </row>
- </slots>
- <segment>customVariableName==Status+user</segment>
- <subtable>
- <row>
- <label>looking at &quot;profile page&quot;</label>
- <nb_visits>2</nb_visits>
- <nb_actions>2</nb_actions>
- <sum_daily_nb_uniq_visitors>2</sum_daily_nb_uniq_visitors>
- </row>
- <row>
- <label>Loggedin</label>
- <nb_visits>1</nb_visits>
- <nb_actions>1</nb_actions>
- <sum_daily_nb_uniq_visitors>1</sum_daily_nb_uniq_visitors>
- </row>
- </subtable>
- </row>
- <row>
<label>Value will be VERY long and truncated</label>
<nb_visits>1</nb_visits>
<nb_actions>3</nb_actions>
@@ -200,6 +171,35 @@
</subtable>
</row>
<row>
+ <label>Status user</label>
+ <nb_actions>3</nb_actions>
+ <slots>
+ <row>
+ <scope>page</scope>
+ <index>4</index>
+ </row>
+ <row>
+ <scope>page</scope>
+ <index>5</index>
+ </row>
+ </slots>
+ <segment>customVariableName==Status+user</segment>
+ <subtable>
+ <row>
+ <label>looking at &quot;profile page&quot;</label>
+ <nb_visits>2</nb_visits>
+ <nb_actions>2</nb_actions>
+ <sum_daily_nb_uniq_visitors>2</sum_daily_nb_uniq_visitors>
+ </row>
+ <row>
+ <label>Loggedin</label>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ <sum_daily_nb_uniq_visitors>1</sum_daily_nb_uniq_visitors>
+ </row>
+ </subtable>
+ </row>
+ <row>
<label>Othercustom value which should be truncated abcdefghijklmnopqrstuvwxyz</label>
<nb_visits>2</nb_visits>
<nb_actions>2</nb_actions>
diff --git a/tests/PHPUnit/System/expected/test_periodIsRange_dateIsLastN_MetadataAndNormalAPI_pagesegment__API.getProcessedReport_range.xml b/tests/PHPUnit/System/expected/test_periodIsRange_dateIsLastN_MetadataAndNormalAPI_pagesegment__API.getProcessedReport_range.xml
index 61d15c6685..c866fba5b5 100644
--- a/tests/PHPUnit/System/expected/test_periodIsRange_dateIsLastN_MetadataAndNormalAPI_pagesegment__API.getProcessedReport_range.xml
+++ b/tests/PHPUnit/System/expected/test_periodIsRange_dateIsLastN_MetadataAndNormalAPI_pagesegment__API.getProcessedReport_range.xml
@@ -4,6 +4,7 @@
<metadata>
<category>Visitors</category>
+ <subcategory>Locations</subcategory>
<name>Country</name>
<module>UserCountry</module>
<action>getCountry</action>
diff --git a/tests/PHPUnit/System/expected/test_periodIsRange_dateIsLastN_MetadataAndNormalAPI_pagesegment__CustomVariables.getCustomVariables_range.xml b/tests/PHPUnit/System/expected/test_periodIsRange_dateIsLastN_MetadataAndNormalAPI_pagesegment__CustomVariables.getCustomVariables_range.xml
index 8851c23d9a..ed926db9f7 100644
--- a/tests/PHPUnit/System/expected/test_periodIsRange_dateIsLastN_MetadataAndNormalAPI_pagesegment__CustomVariables.getCustomVariables_range.xml
+++ b/tests/PHPUnit/System/expected/test_periodIsRange_dateIsLastN_MetadataAndNormalAPI_pagesegment__CustomVariables.getCustomVariables_range.xml
@@ -124,35 +124,6 @@
</subtable>
</row>
<row>
- <label>Status user</label>
- <nb_actions>3</nb_actions>
- <slots>
- <row>
- <scope>page</scope>
- <index>4</index>
- </row>
- <row>
- <scope>page</scope>
- <index>5</index>
- </row>
- </slots>
- <segment>customVariableName==Status+user</segment>
- <subtable>
- <row>
- <label>looking at &quot;profile page&quot;</label>
- <nb_visits>2</nb_visits>
- <nb_actions>2</nb_actions>
- <sum_daily_nb_uniq_visitors>2</sum_daily_nb_uniq_visitors>
- </row>
- <row>
- <label>Loggedin</label>
- <nb_visits>1</nb_visits>
- <nb_actions>1</nb_actions>
- <sum_daily_nb_uniq_visitors>1</sum_daily_nb_uniq_visitors>
- </row>
- </subtable>
- </row>
- <row>
<label>Value will be VERY long and truncated</label>
<nb_visits>1</nb_visits>
<nb_actions>3</nb_actions>
@@ -200,6 +171,35 @@
</subtable>
</row>
<row>
+ <label>Status user</label>
+ <nb_actions>3</nb_actions>
+ <slots>
+ <row>
+ <scope>page</scope>
+ <index>4</index>
+ </row>
+ <row>
+ <scope>page</scope>
+ <index>5</index>
+ </row>
+ </slots>
+ <segment>customVariableName==Status+user</segment>
+ <subtable>
+ <row>
+ <label>looking at &quot;profile page&quot;</label>
+ <nb_visits>2</nb_visits>
+ <nb_actions>2</nb_actions>
+ <sum_daily_nb_uniq_visitors>2</sum_daily_nb_uniq_visitors>
+ </row>
+ <row>
+ <label>Loggedin</label>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ <sum_daily_nb_uniq_visitors>1</sum_daily_nb_uniq_visitors>
+ </row>
+ </subtable>
+ </row>
+ <row>
<label>Othercustom value which should be truncated abcdefghijklmnopqrstuvwxyz</label>
<nb_visits>2</nb_visits>
<nb_actions>2</nb_actions>
diff --git a/tests/PHPUnit/System/expected/test_reportLimiting__CustomVariables.getCustomVariables_day.xml b/tests/PHPUnit/System/expected/test_reportLimiting__CustomVariables.getCustomVariables_day.xml
index c1ba006247..6ee02592b7 100644
--- a/tests/PHPUnit/System/expected/test_reportLimiting__CustomVariables.getCustomVariables_day.xml
+++ b/tests/PHPUnit/System/expected/test_reportLimiting__CustomVariables.getCustomVariables_day.xml
@@ -24,25 +24,25 @@
</subtable>
</row>
<row>
- <label>tweeted</label>
+ <label>name</label>
<nb_actions>20</nb_actions>
<slots>
<row>
<scope>page</scope>
- <index>3</index>
+ <index>1</index>
</row>
</slots>
- <segment>customVariableName==tweeted</segment>
+ <segment>customVariableName==name</segment>
<subtable>
<row>
- <label>n</label>
- <nb_visits>10</nb_visits>
- <nb_actions>10</nb_actions>
+ <label>thing0</label>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
</row>
<row>
<label>Others</label>
- <nb_visits>10</nb_visits>
- <nb_actions>10</nb_actions>
+ <nb_visits>19</nb_visits>
+ <nb_actions>19</nb_actions>
</row>
</subtable>
</row>
diff --git a/tests/PHPUnit/System/expected/test_reportLimiting__UserCountry.getCity_day.xml b/tests/PHPUnit/System/expected/test_reportLimiting__UserCountry.getCity_day.xml
index b9c8e33524..171e7338ad 100644
--- a/tests/PHPUnit/System/expected/test_reportLimiting__UserCountry.getCity_day.xml
+++ b/tests/PHPUnit/System/expected/test_reportLimiting__UserCountry.getCity_day.xml
@@ -19,7 +19,7 @@
<logo>plugins/UserCountry/images/flags/au.png</logo>
</row>
<row>
- <label>Nice, Provence-Alpes-Cote d&amp;#039;Azur, France</label>
+ <label>Nice, Provence-Alpes-Cote d'Azur, France</label>
<nb_uniq_visitors>4</nb_uniq_visitors>
<nb_visits>20</nb_visits>
<nb_actions>20</nb_actions>
diff --git a/tests/PHPUnit/System/expected/test_reportLimiting__UserCountry.getRegion_day.xml b/tests/PHPUnit/System/expected/test_reportLimiting__UserCountry.getRegion_day.xml
index 1ff2a7d168..cc6727dc54 100644
--- a/tests/PHPUnit/System/expected/test_reportLimiting__UserCountry.getRegion_day.xml
+++ b/tests/PHPUnit/System/expected/test_reportLimiting__UserCountry.getRegion_day.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8" ?>
<result>
<row>
- <label>Provence-Alpes-Cote d&amp;#039;Azur, France</label>
+ <label>Provence-Alpes-Cote d'Azur, France</label>
<nb_uniq_visitors>4</nb_uniq_visitors>
<nb_visits>20</nb_visits>
<nb_actions>20</nb_actions>
diff --git a/tests/PHPUnit/System/expected/test_reportLimiting_flattened__CustomVariables.getCustomVariables_day.xml b/tests/PHPUnit/System/expected/test_reportLimiting_flattened__CustomVariables.getCustomVariables_day.xml
index c90e3c1d29..a496ea54f0 100644
--- a/tests/PHPUnit/System/expected/test_reportLimiting_flattened__CustomVariables.getCustomVariables_day.xml
+++ b/tests/PHPUnit/System/expected/test_reportLimiting_flattened__CustomVariables.getCustomVariables_day.xml
@@ -5,23 +5,23 @@
<nb_actions>60</nb_actions>
</row>
<row>
+ <label>name - Others</label>
+ <nb_visits>19</nb_visits>
+ <nb_actions>19</nb_actions>
+ </row>
+ <row>
<label>liked - y</label>
<nb_visits>16</nb_visits>
<nb_actions>16</nb_actions>
</row>
<row>
- <label>tweeted - n</label>
- <nb_visits>10</nb_visits>
- <nb_actions>10</nb_actions>
- </row>
- <row>
- <label>tweeted - Others</label>
- <nb_visits>10</nb_visits>
- <nb_actions>10</nb_actions>
- </row>
- <row>
<label>liked - Others</label>
<nb_visits>4</nb_visits>
<nb_actions>4</nb_actions>
</row>
+ <row>
+ <label>name - thing0</label>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ </row>
</result> \ No newline at end of file
diff --git a/tests/PHPUnit/System/expected/test_reportLimiting_flattened__UserCountry.getCity_day.xml b/tests/PHPUnit/System/expected/test_reportLimiting_flattened__UserCountry.getCity_day.xml
index afe3519850..ff7ba019b4 100644
--- a/tests/PHPUnit/System/expected/test_reportLimiting_flattened__UserCountry.getCity_day.xml
+++ b/tests/PHPUnit/System/expected/test_reportLimiting_flattened__UserCountry.getCity_day.xml
@@ -31,7 +31,7 @@
<logo>plugins/UserCountry/images/flags/au.png</logo>
</row>
<row>
- <label>Nice, Provence-Alpes-Cote d&amp;#039;Azur, France</label>
+ <label>Nice, Provence-Alpes-Cote d'Azur, France</label>
<nb_uniq_visitors>4</nb_uniq_visitors>
<nb_visits>20</nb_visits>
<nb_actions>20</nb_actions>
diff --git a/tests/PHPUnit/System/expected/test_reportLimiting_flattened__UserCountry.getRegion_day.xml b/tests/PHPUnit/System/expected/test_reportLimiting_flattened__UserCountry.getRegion_day.xml
index 54b23a9e59..4680c84581 100644
--- a/tests/PHPUnit/System/expected/test_reportLimiting_flattened__UserCountry.getRegion_day.xml
+++ b/tests/PHPUnit/System/expected/test_reportLimiting_flattened__UserCountry.getRegion_day.xml
@@ -13,7 +13,7 @@
<logo>plugins/UserCountry/images/flags/xx.png</logo>
</row>
<row>
- <label>Provence-Alpes-Cote d&amp;#039;Azur, France</label>
+ <label>Provence-Alpes-Cote d'Azur, France</label>
<nb_uniq_visitors>4</nb_uniq_visitors>
<nb_visits>20</nb_visits>
<nb_actions>20</nb_actions>
diff --git a/tests/PHPUnit/System/expected/test_reportLimiting_rankingQuery__CustomVariables.getCustomVariables_day.xml b/tests/PHPUnit/System/expected/test_reportLimiting_rankingQuery__CustomVariables.getCustomVariables_day.xml
index c1ba006247..6ee02592b7 100644
--- a/tests/PHPUnit/System/expected/test_reportLimiting_rankingQuery__CustomVariables.getCustomVariables_day.xml
+++ b/tests/PHPUnit/System/expected/test_reportLimiting_rankingQuery__CustomVariables.getCustomVariables_day.xml
@@ -24,25 +24,25 @@
</subtable>
</row>
<row>
- <label>tweeted</label>
+ <label>name</label>
<nb_actions>20</nb_actions>
<slots>
<row>
<scope>page</scope>
- <index>3</index>
+ <index>1</index>
</row>
</slots>
- <segment>customVariableName==tweeted</segment>
+ <segment>customVariableName==name</segment>
<subtable>
<row>
- <label>n</label>
- <nb_visits>10</nb_visits>
- <nb_actions>10</nb_actions>
+ <label>thing0</label>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
</row>
<row>
<label>Others</label>
- <nb_visits>10</nb_visits>
- <nb_actions>10</nb_actions>
+ <nb_visits>19</nb_visits>
+ <nb_actions>19</nb_actions>
</row>
</subtable>
</row>
diff --git a/tests/PHPUnit/System/expected/test_reportLimiting_rankingQuery__UserCountry.getCity_day.xml b/tests/PHPUnit/System/expected/test_reportLimiting_rankingQuery__UserCountry.getCity_day.xml
index b9c8e33524..171e7338ad 100644
--- a/tests/PHPUnit/System/expected/test_reportLimiting_rankingQuery__UserCountry.getCity_day.xml
+++ b/tests/PHPUnit/System/expected/test_reportLimiting_rankingQuery__UserCountry.getCity_day.xml
@@ -19,7 +19,7 @@
<logo>plugins/UserCountry/images/flags/au.png</logo>
</row>
<row>
- <label>Nice, Provence-Alpes-Cote d&amp;#039;Azur, France</label>
+ <label>Nice, Provence-Alpes-Cote d'Azur, France</label>
<nb_uniq_visitors>4</nb_uniq_visitors>
<nb_visits>20</nb_visits>
<nb_actions>20</nb_actions>
diff --git a/tests/PHPUnit/System/expected/test_reportLimiting_rankingQuery__UserCountry.getRegion_day.xml b/tests/PHPUnit/System/expected/test_reportLimiting_rankingQuery__UserCountry.getRegion_day.xml
index 1ff2a7d168..cc6727dc54 100644
--- a/tests/PHPUnit/System/expected/test_reportLimiting_rankingQuery__UserCountry.getRegion_day.xml
+++ b/tests/PHPUnit/System/expected/test_reportLimiting_rankingQuery__UserCountry.getRegion_day.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8" ?>
<result>
<row>
- <label>Provence-Alpes-Cote d&amp;#039;Azur, France</label>
+ <label>Provence-Alpes-Cote d'Azur, France</label>
<nb_uniq_visitors>4</nb_uniq_visitors>
<nb_visits>20</nb_visits>
<nb_actions>20</nb_actions>
diff --git a/tests/PHPUnit/System/expected/test_twoVisitsWithCustomVariables__CustomVariables.getCustomVariables_day.xml b/tests/PHPUnit/System/expected/test_twoVisitsWithCustomVariables__CustomVariables.getCustomVariables_day.xml
index 7ffb6725e4..893b862eda 100644
--- a/tests/PHPUnit/System/expected/test_twoVisitsWithCustomVariables__CustomVariables.getCustomVariables_day.xml
+++ b/tests/PHPUnit/System/expected/test_twoVisitsWithCustomVariables__CustomVariables.getCustomVariables_day.xml
@@ -303,7 +303,7 @@
<segment>customVariableName==var2</segment>
<subtable>
<row>
- <label>&amp;#039;looking at &quot;\profile page&quot;&amp;#039;</label>
+ <label>'looking at &quot;\profile page&quot;'</label>
<nb_visits>1</nb_visits>
<nb_actions>1</nb_actions>
</row>
diff --git a/tests/PHPUnit/System/expected/test_twoVisitsWithCustomVariables__CustomVariables.getCustomVariables_week.xml b/tests/PHPUnit/System/expected/test_twoVisitsWithCustomVariables__CustomVariables.getCustomVariables_week.xml
index 0514b1d5d3..ed85668d5c 100644
--- a/tests/PHPUnit/System/expected/test_twoVisitsWithCustomVariables__CustomVariables.getCustomVariables_week.xml
+++ b/tests/PHPUnit/System/expected/test_twoVisitsWithCustomVariables__CustomVariables.getCustomVariables_week.xml
@@ -317,7 +317,7 @@
<segment>customVariableName==var2</segment>
<subtable>
<row>
- <label>&amp;#039;looking at &quot;\profile page&quot;&amp;#039;</label>
+ <label>'looking at &quot;\profile page&quot;'</label>
<nb_visits>1</nb_visits>
<nb_actions>1</nb_actions>
<sum_daily_nb_uniq_visitors>1</sum_daily_nb_uniq_visitors>
diff --git a/tests/PHPUnit/System/expected/test_twoVisitsWithCustomVariables_segmentMatchALL_noGoalData__CustomVariables.getCustomVariables_day.xml b/tests/PHPUnit/System/expected/test_twoVisitsWithCustomVariables_segmentMatchALL_noGoalData__CustomVariables.getCustomVariables_day.xml
index 1bfb23612e..ea1fd50aeb 100644
--- a/tests/PHPUnit/System/expected/test_twoVisitsWithCustomVariables_segmentMatchALL_noGoalData__CustomVariables.getCustomVariables_day.xml
+++ b/tests/PHPUnit/System/expected/test_twoVisitsWithCustomVariables_segmentMatchALL_noGoalData__CustomVariables.getCustomVariables_day.xml
@@ -121,33 +121,6 @@
</subtable>
</row>
<row>
- <label>Status user</label>
- <nb_actions>3</nb_actions>
- <slots>
- <row>
- <scope>page</scope>
- <index>4</index>
- </row>
- <row>
- <scope>page</scope>
- <index>5</index>
- </row>
- </slots>
- <segment>customVariableName==Status+user</segment>
- <subtable>
- <row>
- <label>looking at &quot;profile page&quot;</label>
- <nb_visits>2</nb_visits>
- <nb_actions>2</nb_actions>
- </row>
- <row>
- <label>Loggedin</label>
- <nb_visits>1</nb_visits>
- <nb_actions>1</nb_actions>
- </row>
- </subtable>
- </row>
- <row>
<label>Value will be VERY long and truncated</label>
<nb_visits>1</nb_visits>
<nb_actions>3</nb_actions>
@@ -193,6 +166,33 @@
</subtable>
</row>
<row>
+ <label>Status user</label>
+ <nb_actions>3</nb_actions>
+ <slots>
+ <row>
+ <scope>page</scope>
+ <index>4</index>
+ </row>
+ <row>
+ <scope>page</scope>
+ <index>5</index>
+ </row>
+ </slots>
+ <segment>customVariableName==Status+user</segment>
+ <subtable>
+ <row>
+ <label>looking at &quot;profile page&quot;</label>
+ <nb_visits>2</nb_visits>
+ <nb_actions>2</nb_actions>
+ </row>
+ <row>
+ <label>Loggedin</label>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ </row>
+ </subtable>
+ </row>
+ <row>
<label>Othercustom value which should be truncated abcdefghijklmnopqrstuvwxyz</label>
<nb_visits>2</nb_visits>
<nb_actions>2</nb_actions>
diff --git a/tests/PHPUnit/System/expected/test_twoVisitsWithCustomVariables_segmentMatchALL_noGoalData__CustomVariables.getCustomVariables_week.xml b/tests/PHPUnit/System/expected/test_twoVisitsWithCustomVariables_segmentMatchALL_noGoalData__CustomVariables.getCustomVariables_week.xml
index 4041ca8eac..ee4a001854 100644
--- a/tests/PHPUnit/System/expected/test_twoVisitsWithCustomVariables_segmentMatchALL_noGoalData__CustomVariables.getCustomVariables_week.xml
+++ b/tests/PHPUnit/System/expected/test_twoVisitsWithCustomVariables_segmentMatchALL_noGoalData__CustomVariables.getCustomVariables_week.xml
@@ -126,35 +126,6 @@
</subtable>
</row>
<row>
- <label>Status user</label>
- <nb_actions>3</nb_actions>
- <slots>
- <row>
- <scope>page</scope>
- <index>4</index>
- </row>
- <row>
- <scope>page</scope>
- <index>5</index>
- </row>
- </slots>
- <segment>customVariableName==Status+user</segment>
- <subtable>
- <row>
- <label>looking at &quot;profile page&quot;</label>
- <nb_visits>2</nb_visits>
- <nb_actions>2</nb_actions>
- <sum_daily_nb_uniq_visitors>2</sum_daily_nb_uniq_visitors>
- </row>
- <row>
- <label>Loggedin</label>
- <nb_visits>1</nb_visits>
- <nb_actions>1</nb_actions>
- <sum_daily_nb_uniq_visitors>1</sum_daily_nb_uniq_visitors>
- </row>
- </subtable>
- </row>
- <row>
<label>Value will be VERY long and truncated</label>
<nb_visits>1</nb_visits>
<nb_actions>3</nb_actions>
@@ -202,6 +173,35 @@
</subtable>
</row>
<row>
+ <label>Status user</label>
+ <nb_actions>3</nb_actions>
+ <slots>
+ <row>
+ <scope>page</scope>
+ <index>4</index>
+ </row>
+ <row>
+ <scope>page</scope>
+ <index>5</index>
+ </row>
+ </slots>
+ <segment>customVariableName==Status+user</segment>
+ <subtable>
+ <row>
+ <label>looking at &quot;profile page&quot;</label>
+ <nb_visits>2</nb_visits>
+ <nb_actions>2</nb_actions>
+ <sum_daily_nb_uniq_visitors>2</sum_daily_nb_uniq_visitors>
+ </row>
+ <row>
+ <label>Loggedin</label>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ <sum_daily_nb_uniq_visitors>1</sum_daily_nb_uniq_visitors>
+ </row>
+ </subtable>
+ </row>
+ <row>
<label>Othercustom value which should be truncated abcdefghijklmnopqrstuvwxyz</label>
<nb_visits>2</nb_visits>
<nb_actions>2</nb_actions>
diff --git a/tests/PHPUnit/System/expected/test_twoVisitsWithCustomVariables_segmentMatchVisitorType__CustomVariables.getCustomVariables_day.xml b/tests/PHPUnit/System/expected/test_twoVisitsWithCustomVariables_segmentMatchVisitorType__CustomVariables.getCustomVariables_day.xml
index 428f0180ae..b18fed5db3 100644
--- a/tests/PHPUnit/System/expected/test_twoVisitsWithCustomVariables_segmentMatchVisitorType__CustomVariables.getCustomVariables_day.xml
+++ b/tests/PHPUnit/System/expected/test_twoVisitsWithCustomVariables_segmentMatchVisitorType__CustomVariables.getCustomVariables_day.xml
@@ -48,33 +48,6 @@
</subtable>
</row>
<row>
- <label>Status user</label>
- <nb_actions>3</nb_actions>
- <slots>
- <row>
- <scope>page</scope>
- <index>4</index>
- </row>
- <row>
- <scope>page</scope>
- <index>5</index>
- </row>
- </slots>
- <segment>customVariableName==Status+user</segment>
- <subtable>
- <row>
- <label>looking at &quot;profile page&quot;</label>
- <nb_visits>2</nb_visits>
- <nb_actions>2</nb_actions>
- </row>
- <row>
- <label>Loggedin</label>
- <nb_visits>1</nb_visits>
- <nb_actions>1</nb_actions>
- </row>
- </subtable>
- </row>
- <row>
<label>Value will be VERY long and truncated</label>
<nb_visits>1</nb_visits>
<nb_actions>3</nb_actions>
@@ -183,6 +156,33 @@
</subtable>
</row>
<row>
+ <label>Status user</label>
+ <nb_actions>3</nb_actions>
+ <slots>
+ <row>
+ <scope>page</scope>
+ <index>4</index>
+ </row>
+ <row>
+ <scope>page</scope>
+ <index>5</index>
+ </row>
+ </slots>
+ <segment>customVariableName==Status+user</segment>
+ <subtable>
+ <row>
+ <label>looking at &quot;profile page&quot;</label>
+ <nb_visits>2</nb_visits>
+ <nb_actions>2</nb_actions>
+ </row>
+ <row>
+ <label>Loggedin</label>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ </row>
+ </subtable>
+ </row>
+ <row>
<label>Language</label>
<nb_actions>1</nb_actions>
<slots>
diff --git a/tests/PHPUnit/System/expected/test_twoVisitsWithCustomVariables_segmentMatchVisitorType__CustomVariables.getCustomVariables_week.xml b/tests/PHPUnit/System/expected/test_twoVisitsWithCustomVariables_segmentMatchVisitorType__CustomVariables.getCustomVariables_week.xml
index 4c0da8f95e..f11bfb8152 100644
--- a/tests/PHPUnit/System/expected/test_twoVisitsWithCustomVariables_segmentMatchVisitorType__CustomVariables.getCustomVariables_week.xml
+++ b/tests/PHPUnit/System/expected/test_twoVisitsWithCustomVariables_segmentMatchVisitorType__CustomVariables.getCustomVariables_week.xml
@@ -50,35 +50,6 @@
</subtable>
</row>
<row>
- <label>Status user</label>
- <nb_actions>3</nb_actions>
- <slots>
- <row>
- <scope>page</scope>
- <index>4</index>
- </row>
- <row>
- <scope>page</scope>
- <index>5</index>
- </row>
- </slots>
- <segment>customVariableName==Status+user</segment>
- <subtable>
- <row>
- <label>looking at &quot;profile page&quot;</label>
- <nb_visits>2</nb_visits>
- <nb_actions>2</nb_actions>
- <sum_daily_nb_uniq_visitors>2</sum_daily_nb_uniq_visitors>
- </row>
- <row>
- <label>Loggedin</label>
- <nb_visits>1</nb_visits>
- <nb_actions>1</nb_actions>
- <sum_daily_nb_uniq_visitors>1</sum_daily_nb_uniq_visitors>
- </row>
- </subtable>
- </row>
- <row>
<label>Value will be VERY long and truncated</label>
<nb_visits>1</nb_visits>
<nb_actions>3</nb_actions>
@@ -191,6 +162,35 @@
</subtable>
</row>
<row>
+ <label>Status user</label>
+ <nb_actions>3</nb_actions>
+ <slots>
+ <row>
+ <scope>page</scope>
+ <index>4</index>
+ </row>
+ <row>
+ <scope>page</scope>
+ <index>5</index>
+ </row>
+ </slots>
+ <segment>customVariableName==Status+user</segment>
+ <subtable>
+ <row>
+ <label>looking at &quot;profile page&quot;</label>
+ <nb_visits>2</nb_visits>
+ <nb_actions>2</nb_actions>
+ <sum_daily_nb_uniq_visitors>2</sum_daily_nb_uniq_visitors>
+ </row>
+ <row>
+ <label>Loggedin</label>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ <sum_daily_nb_uniq_visitors>1</sum_daily_nb_uniq_visitors>
+ </row>
+ </subtable>
+ </row>
+ <row>
<label>Language</label>
<nb_actions>1</nb_actions>
<slots>
diff --git a/tests/PHPUnit/Unit/Category/CategoryListTest.php b/tests/PHPUnit/Unit/Category/CategoryListTest.php
new file mode 100644
index 0000000000..53f5d9c42c
--- /dev/null
+++ b/tests/PHPUnit/Unit/Category/CategoryListTest.php
@@ -0,0 +1,92 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+
+namespace Piwik\Tests\Unit\Category;
+
+use Piwik\Category\CategoryList;
+use Piwik\Category\Category;
+
+/**
+ * @group Category
+ * @group CategoryList
+ * @group CategoryListTest
+ */
+class CategoryListTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * @var CategoryList
+ */
+ private $categoryList;
+
+ public function setUp()
+ {
+ $this->categoryList = new CategoryList();
+ }
+
+ public function test_getCategories_IsEmptyByDefault()
+ {
+ $this->assertSame(array(), $this->categoryList->getCategories());
+ }
+
+ public function test_addCategory_ShouldAddCategory_and_getCategories_shouldBeIndexedById()
+ {
+ $category = $this->addCategory('myTest');
+
+ $this->assertSame(array('myTest' => $category), $this->categoryList->getCategories());
+ }
+
+ /**
+ * @expectedException \Exception
+ * @expectedExceptionMessage Category myTest already exists
+ */
+ public function test_addCategory_shouldThrowException_IfAddingSameCategoryIdTwice()
+ {
+ $this->addCategory('myTest');
+ $this->addCategory('myTest');
+ }
+
+ public function test_hasCategory_ShouldDetectIfCategoryExists()
+ {
+ $this->assertFalse($this->categoryList->hasCategory('myTest'));
+
+ $this->addCategory('myTest');
+
+ $this->assertTrue($this->categoryList->hasCategory('myTest'));
+
+ $this->assertFalse($this->categoryList->hasCategory('myTest2'));
+ $this->assertFalse($this->categoryList->hasCategory('General_Visits'));
+ }
+
+ public function test_getCategory_ShouldReturnExistingCategoryIfPossible()
+ {
+ $this->assertNull($this->categoryList->getCategory('myTest'));
+
+ $category = $this->addCategory('myTest');
+
+ $this->assertSame($category, $this->categoryList->getCategory('myTest'));
+
+ $this->assertNull($this->categoryList->getCategory('myTest2'));
+ $this->assertNull($this->categoryList->getCategory('General_Visits'));
+ }
+
+ private function addCategory($id)
+ {
+ $category = $this->createCategory($id);
+ $this->categoryList->addCategory($category);
+
+ return $category;
+ }
+
+ private function createCategory($categoryId)
+ {
+ $config = new Category();
+ $config->setId($categoryId);
+
+ return $config;
+ }
+}
diff --git a/tests/PHPUnit/Unit/Category/CategoryTest.php b/tests/PHPUnit/Unit/Category/CategoryTest.php
new file mode 100644
index 0000000000..de4b931657
--- /dev/null
+++ b/tests/PHPUnit/Unit/Category/CategoryTest.php
@@ -0,0 +1,141 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+
+namespace Piwik\Tests\Unit\Category;
+
+use Piwik\Cache;
+use Piwik\Category\Category;
+use Piwik\Category\Subcategory;
+
+/**
+ * @group Category
+ * @group CategoryTest
+ */
+class CategoryTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * @var Category
+ */
+ private $category;
+
+ public function setUp()
+ {
+ parent::setUp();
+ $this->category = new Category();
+ }
+
+ public function test_order_set_get()
+ {
+ $this->category->setOrder(99);
+ $this->assertSame(99, $this->category->getOrder());
+
+ $this->category->setOrder('98');
+ $this->assertSame(98, $this->category->getOrder());
+ }
+
+ public function test_getOrder_shouldReturnADefaultValue()
+ {
+ $this->assertSame(99, $this->category->getOrder());
+ }
+
+ public function test_id_set_get()
+ {
+ $this->category->setId('myCustomId');
+ $this->assertSame('myCustomId', $this->category->getId());
+ }
+
+ public function test_getId_shouldBeEmptyStringByDefault()
+ {
+ $this->assertSame('', $this->category->getId());
+ }
+
+ public function test_getSubcategories_ShouldReturnAnEmptyArray_ByDefault()
+ {
+ $this->assertSame(array(), $this->category->getSubcategories());
+ }
+
+ public function test_addSubcategory_ShouldActuallyAddAndReturnSubcategories()
+ {
+ $subcategory1 = $this->createSubcategory('id1', 'name1');
+ $subcategory2 = $this->createSubcategory('id2', 'name2');
+
+ $this->category->addSubcategory($subcategory1);
+ $this->category->addSubcategory($subcategory2);
+
+ $this->assertSame(array($subcategory1, $subcategory2), $this->category->getSubcategories());
+ }
+
+ /**
+ * @expectedException \Exception
+ * @expectedExceptionMessage Subcategory id1 already exists
+ */
+ public function test_addSubcategory_ShouldThrowException_WhenAddingSubcategoryWithSameIdTwice()
+ {
+ $subcategory1 = $this->createSubcategory('id1', 'name1');
+ $subcategory2 = $this->createSubcategory('id1', 'name2');
+
+ $this->category->addSubcategory($subcategory1);
+ $this->category->addSubcategory($subcategory2);
+ }
+
+ public function test_hasSubcategories_ShouldDetectIfSubcategoriesArePresent()
+ {
+ $this->assertFalse($this->category->hasSubCategories());
+ $this->addSubcategories(array('myid' => 'myname'));
+ $this->assertTrue($this->category->hasSubCategories());
+ }
+
+ public function test_getSubcategory_ShouldNotFindASubCategoryById_IfSuchCategoryDoesNotExist()
+ {
+ $this->assertNull($this->category->getSubcategory('myid'));
+ }
+
+ public function test_getSubcategory_ShouldFindAnExistingSubCategoryById()
+ {
+ $this->addSubcategories(array('myid' => 'myname', 'myid2' => 'myname2'));
+
+ $subcategory = $this->category->getSubcategory('myid2');
+ $this->assertTrue($subcategory instanceof Subcategory);
+ $this->assertSame('myname2', $subcategory->getName());
+ }
+
+ public function test_getSubcategory_ShouldNotFindASubcategoryByName()
+ {
+ $this->addSubcategories(array('myid' => 'myname'));
+
+ $this->assertNull($this->category->getSubcategory('myname'));
+ }
+
+ public function test_hasSubcategory_ShouldActuallyAddTheConfig()
+ {
+ $this->assertFalse($this->category->hasSubcategory('myid2'));
+
+ $this->addSubcategories(array('myid' => 'myname', 'myid2' => 'myname2'));
+
+ $this->assertTrue($this->category->hasSubcategory('myid2'));
+ $this->assertFalse($this->category->hasSubcategory('myname'));
+ $this->assertFalse($this->category->hasSubcategory('myname2'));
+ $this->assertFalse($this->category->hasSubcategory('mySomething'));
+ }
+
+ private function addSubcategories($subcategories)
+ {
+ foreach ($subcategories as $id => $name) {
+ $this->category->addSubcategory($this->createSubcategory($id, $name));
+ }
+ }
+
+ private function createSubcategory($subcategoryId, $subcategoryName)
+ {
+ $config = new Subcategory();
+ $config->setId($subcategoryId);
+ $config->setName($subcategoryName);
+
+ return $config;
+ }
+}
diff --git a/tests/PHPUnit/Unit/Category/SubcategoryTest.php b/tests/PHPUnit/Unit/Category/SubcategoryTest.php
new file mode 100644
index 0000000000..463ea22b6d
--- /dev/null
+++ b/tests/PHPUnit/Unit/Category/SubcategoryTest.php
@@ -0,0 +1,89 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+
+namespace Piwik\Tests\Unit\Category;
+
+use Piwik\Cache;
+use Piwik\Category\Subcategory;
+
+/**
+ * @group Category
+ * @group Subcategory
+ * @group SubcategoryTest
+ */
+class SubcategoryTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * @var Subcategory
+ */
+ private $subcategory;
+
+ public function setUp()
+ {
+ parent::setUp();
+ $this->subcategory = new Subcategory();
+ }
+
+ public function test_categoryId_set_get()
+ {
+ $this->subcategory->setCategoryId('testCategory');
+
+ $this->assertSame('testCategory', $this->subcategory->getCategoryId());
+ }
+
+ public function test_getCategoryId_shouldBeEmptyStringByDefault()
+ {
+ $this->assertSame('', $this->subcategory->getCategoryId());
+ }
+
+ public function test_name_set_get()
+ {
+ $this->subcategory->setName('testName');
+
+ $this->assertSame('testName', $this->subcategory->getName());
+ }
+
+ public function test_getName_shouldBeEmptyStringByDefault()
+ {
+ $this->assertSame('', $this->subcategory->getName());
+ }
+
+ public function test_getName_ShouldDefaultToId_IfNoNameIsSet()
+ {
+ $this->subcategory->setId('myTestId');
+
+ $this->assertSame('myTestId', $this->subcategory->getName());
+ $this->assertSame('myTestId', $this->subcategory->getId());
+ }
+
+ public function test_order_set_get()
+ {
+ $this->subcategory->setOrder(99);
+ $this->assertSame(99, $this->subcategory->getOrder());
+
+ $this->subcategory->setOrder('98');
+ $this->assertSame(98, $this->subcategory->getOrder());
+ }
+
+ public function test_getOrder_shouldReturnADefaultValue()
+ {
+ $this->assertSame(99, $this->subcategory->getOrder());
+ }
+
+ public function test_id_set_get()
+ {
+ $this->subcategory->setId('myCustomId');
+ $this->assertSame('myCustomId', $this->subcategory->getId());
+ }
+
+ public function test_getId_shouldBeEmptyStringByDefault()
+ {
+ $this->assertSame('', $this->subcategory->getId());
+ }
+
+}
diff --git a/tests/PHPUnit/Unit/CommonTest.php b/tests/PHPUnit/Unit/CommonTest.php
index d8817ec3db..08931b6bfe 100644
--- a/tests/PHPUnit/Unit/CommonTest.php
+++ b/tests/PHPUnit/Unit/CommonTest.php
@@ -102,14 +102,6 @@ class CommonTest extends PHPUnit_Framework_TestCase
*/
public function testSanitizeInputValues($input, $output)
{
- if (version_compare(PHP_VERSION, '5.4') < 0) {
- $this->assertTrue(@set_magic_quotes_runtime(1));
- $this->assertEquals(1, @get_magic_quotes_runtime());
- $this->assertEquals($output, Common::sanitizeInputValues($input));
-
- $this->assertTrue(@set_magic_quotes_runtime(0));
- $this->assertEquals(0, @get_magic_quotes_runtime());
- }
$this->assertEquals($output, Common::sanitizeInputValues($input));
}
diff --git a/tests/PHPUnit/Unit/DataTable/Filter/SortTest.php b/tests/PHPUnit/Unit/DataTable/Filter/SortTest.php
index a1f173ba61..8a405b697a 100644
--- a/tests/PHPUnit/Unit/DataTable/Filter/SortTest.php
+++ b/tests/PHPUnit/Unit/DataTable/Filter/SortTest.php
@@ -14,8 +14,10 @@ use Piwik\DataTable\Row;
/**
* @group DataTableTest
+ * @group Core
+ * @group sort
*/
-class DataTable_Filter_SortTest extends \PHPUnit_Framework_TestCase
+class SortTest extends \PHPUnit_Framework_TestCase
{
public function testNormalSortDescending()
@@ -47,7 +49,6 @@ class DataTable_Filter_SortTest extends \PHPUnit_Framework_TestCase
$this->assertEquals($expectedOrder, $table->getColumn('label'));
}
-
public function testMissingColumnValuesShouldAppearLastAfterSortAsc()
{
$table = new DataTable();
@@ -83,8 +84,6 @@ class DataTable_Filter_SortTest extends \PHPUnit_Framework_TestCase
/**
* Test to sort by label
- *
- * @group Core
*/
public function testFilterSortString()
{
@@ -125,36 +124,31 @@ class DataTable_Filter_SortTest extends \PHPUnit_Framework_TestCase
/**
* Test to sort by visit
- *
- * @group Core
*/
public function testFilterSortNumeric()
{
- $idcol = Row::COLUMNS;
- $table = new DataTable();
- $rows = array(
- array($idcol => array('label' => 'google', 'nb_visits' => 897)), //0
- array($idcol => array('label' => 'ask', 'nb_visits' => -152)), //1
- array($idcol => array('label' => 'piwik', 'nb_visits' => 1.5)), //2
- array($idcol => array('label' => 'yahoo', 'nb_visits' => 154)), //3
- array($idcol => array('label' => 'amazon', 'nb_visits' => 30)), //4
- array($idcol => array('label' => '238949', 'nb_visits' => 0)), //5
- array($idcol => array('label' => 'Q*(%&*', 'nb_visits' => 1)) //6
- );
- $table->addRowsFromArray($rows);
- $expectedtable = new DataTable();
+ $table = $this->createDataTable(array(
+ array('label' => 'google', 'nb_visits' => 897), //0
+ array('label' => 'ask', 'nb_visits' => -152), //1
+ array('label' => 'piwik', 'nb_visits' => 1.5), //2
+ array('label' => 'yahoo', 'nb_visits' => 154), //3
+ array('label' => 'amazon', 'nb_visits' => 30), //4
+ array('label' => '238949', 'nb_visits' => 0), //5
+ array('label' => 'Q*(%&*', 'nb_visits' => 1) //6
+ ));
+
$rows = array(
- array($idcol => array('label' => 'ask', 'nb_visits' => -152)), //1
- array($idcol => array('label' => '238949', 'nb_visits' => 0)), //5
- array($idcol => array('label' => 'Q*(%&*', 'nb_visits' => 1)), //6
- array($idcol => array('label' => 'piwik', 'nb_visits' => 1.5)), //2
- array($idcol => array('label' => 'amazon', 'nb_visits' => 30)), //4
- array($idcol => array('label' => 'yahoo', 'nb_visits' => 154)), //3
- array($idcol => array('label' => 'google', 'nb_visits' => 897)) //0
+ array('label' => 'ask', 'nb_visits' => -152), //1
+ array('label' => '238949', 'nb_visits' => 0), //5
+ array('label' => 'Q*(%&*', 'nb_visits' => 1), //6
+ array('label' => 'piwik', 'nb_visits' => 1.5), //2
+ array('label' => 'amazon', 'nb_visits' => 30), //4
+ array('label' => 'yahoo', 'nb_visits' => 154), //3
+ array('label' => 'google', 'nb_visits' => 897) //0
);
- $expectedtable->addRowsFromArray($rows);
- $expectedtableReverse = new DataTable();
- $expectedtableReverse->addRowsFromArray(array_reverse($rows));
+
+ $expectedtable = $this->createDataTable($rows);
+ $expectedtableReverse = $this->createDataTable(array_reverse($rows));
$filter = new Sort($table, 'nb_visits', 'asc');
$filter->filter($table);
@@ -165,6 +159,47 @@ class DataTable_Filter_SortTest extends \PHPUnit_Framework_TestCase
$this->assertTrue(DataTable::isEqual($table, $expectedtableReverse));
}
+ /**
+ * Test to sort by visit
+ */
+ public function testFilterSortNumeric_withSecondaryColumnSortLabel()
+ {
+ $rows = array(
+ array('label' => 'google', 'nb_visits' => array()),
+ array('label' => 'ask', 'nb_visits' => false),
+ array('label' => 'piwik', 'nb_visits' => 143),
+ array('label' => 'yahoo', 'nb_visits' => 154),
+ array('label' => 'zzzzz', 'nb_visits' => false),
+ array('label' => 'amazon', 'nb_visits' => 154),
+ array('label' => '238949', 'nb_visits' => 154),
+ array('label' => 'Q*(%&*', 'nb_visits' => 1)
+ );
+ $table = $this->createDataTable($rows);
+
+ $rows = array(
+ array('label' => '238949', 'nb_visits' => 154),
+ array('label' => 'amazon', 'nb_visits' => 154),
+ array('label' => 'yahoo', 'nb_visits' => 154),
+ array('label' => 'piwik', 'nb_visits' => 143),
+ array('label' => 'Q*(%&*', 'nb_visits' => 1),
+ array('label' => 'ask', 'nb_visits' => false),
+ array('label' => 'google', 'nb_visits' => array()),
+ array('label' => 'zzzzz', 'nb_visits' => false)
+ );
+
+ $expectedtable = $this->createDataTable($rows);
+ $expectedtableReverse = $this->createDataTable(array_reverse($rows));
+
+ $filter = new Sort($table, 'nb_visits', 'desc', $natural = true, $reverse = false, $secondaryColumn = true);
+ $filter->filter($table);
+
+ $this->assertTrue(DataTable::isEqual($table, $expectedtable));
+
+ $filter = new Sort($table, 'nb_visits', 'asc', $natural = true, $reverse = false, $secondaryColumn = true);
+ $filter->filter($table);
+ $this->assertTrue(DataTable::isEqual($table, $expectedtableReverse));
+ }
+
public function test_sortingArrayValues_doesNotError()
{
$table = new DataTable();
@@ -180,4 +215,56 @@ class DataTable_Filter_SortTest extends \PHPUnit_Framework_TestCase
$filter->filter($table);
$this->assertTrue(DataTable::isEqual($tableOriginal, $table));
}
+
+
+ /**
+ * Test to sort by label
+ */
+ public function testFilter_shouldPickStringSearchEvenIfFirstLabelIsNumeric()
+ {
+ $table = $this->createDataTable(array(
+ array('label' => '238975247578949'),
+ array('label' => 'google'),
+ array('label' => '013494'),
+ array('label' => '9'),
+ array('label' => '999yahoo'),
+ array('label' => '494'),
+ array('label' => 'Q*(%&*("$&%*(&"$*")"))')
+ ));
+
+ $rows = array(
+ array('label' => '9'),
+ array('label' => '494'),
+ array('label' => '999yahoo'),
+ array('label' => '013494'),
+ array('label' => '238975247578949'),
+ array('label' => 'google'),
+ array('label' => 'Q*(%&*("$&%*(&"$*")"))')
+ );
+
+ $expectedtable = $this->createDataTable($rows);
+ $expectedtableReverse = $this->createDataTable(array_reverse($rows));
+
+ $filter = new Sort($table, 'label', 'asc', $natural = true);
+ $filter->filter($table);
+ $this->assertTrue(DataTable::isEqual($expectedtable, $table));
+
+ $filter = new Sort($table, 'label', 'desc');
+ $filter->filter($table);
+ $this->assertTrue(DataTable::isEqual($table, $expectedtableReverse));
+ }
+
+ private function createDataTable($rows)
+ {
+ $table = new DataTable();
+ foreach ($rows as $columns) {
+ $table->addRow($this->createRow($columns));
+ }
+ return $table;
+ }
+
+ private function createRow($columns)
+ {
+ return new Row(array(Row::COLUMNS => $columns));
+ }
}
diff --git a/tests/PHPUnit/Unit/Metrics/SorterTest.php b/tests/PHPUnit/Unit/Metrics/SorterTest.php
new file mode 100644
index 0000000000..103995e638
--- /dev/null
+++ b/tests/PHPUnit/Unit/Metrics/SorterTest.php
@@ -0,0 +1,405 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+namespace Piwik\Tests\Unit\Metrics;
+
+use Piwik\DataTable;
+use Piwik\DataTable\Row;
+use Piwik\Metrics;
+use Piwik\Metrics\Sorter;
+use Piwik\Metrics\Sorter\Config;
+use Piwik\Tests\Framework\TestCase\UnitTestCase;
+
+/**
+ * @group Core
+ * @group sort
+ */
+class SorterTest extends UnitTestCase
+{
+ /**
+ * @var Sorter
+ */
+ private $sorter;
+
+ /**
+ * @var Config
+ */
+ private $config;
+
+ public function setUp()
+ {
+ parent::setUp();
+
+ $this->config = new Config();
+ $this->config->primaryColumnToSort = 'nb_visits';
+ $this->config->primarySortOrder = SORT_DESC;
+ $this->config->primarySortFlags = SORT_NUMERIC;
+ $this->sorter = new Sorter($this->config);
+ }
+
+ public function test_getPrimarySortOrder_shouldReturnDescByDefault()
+ {
+ $this->assertSame(SORT_DESC, $this->sorter->getPrimarySortOrder(null));
+ $this->assertSame(SORT_DESC, $this->sorter->getPrimarySortOrder('whatever'));
+ $this->assertSame(SORT_DESC, $this->sorter->getPrimarySortOrder('desc'));
+ }
+
+ public function test_getPrimarySortOrder_shouldReturnAscIfRequestedLowerCase()
+ {
+ $this->assertSame(SORT_ASC, $this->sorter->getPrimarySortOrder('asc'));
+ $this->assertSame(SORT_DESC, $this->sorter->getPrimarySortOrder('AsC')); // we require 'asc' to be lowercase
+ }
+
+ public function test_getSecondarySortOrder_shouldReturnInvertedOrder_IfColumnIsLabel()
+ {
+ $this->assertSame(SORT_DESC, $this->sorter->getSecondarySortOrder('asc', 'label'));
+ $this->assertSame(SORT_ASC, $this->sorter->getSecondarySortOrder('whatever', 'label'));
+ $this->assertSame(SORT_ASC, $this->sorter->getSecondarySortOrder('desc', 'label'));
+ $this->assertSame(SORT_ASC, $this->sorter->getSecondarySortOrder('AsC', 'label'));
+ }
+ public function test_getPrimarySortOrder_shouldReturnDescByDefault_IfNotLabelColumnIsRequested()
+ {
+ $this->assertSame(SORT_DESC, $this->sorter->getSecondarySortOrder(null, 'nb_visits'));
+ $this->assertSame(SORT_DESC, $this->sorter->getSecondarySortOrder('whatever', 'nb_visits'));
+ $this->assertSame(SORT_DESC, $this->sorter->getSecondarySortOrder('desc', 'nb_visits'));
+ }
+
+ public function test_getSecondarySortOrder_shouldReturnAscIfRequestedLowerCase_IfNotLabelColumnIsRequested()
+ {
+ $this->assertSame(SORT_ASC, $this->sorter->getSecondarySortOrder('asc', 'nb_visits'));
+ $this->assertSame(SORT_DESC, $this->sorter->getSecondarySortOrder('AsC', 'nb_visits')); // we require 'asc' to be lowercase
+ }
+
+ /**
+ * @dataProvider getPrimaryColumnsToSort
+ */
+ public function test_getPrimaryColumnToSort_shouldPickCorrectPrimaryColumnAndMapMetricNameToIdIfNeededAndReverse($expectedUsedColumn, $columnToSortBy)
+ {
+ $table = $this->createDataTable(array(
+ array('label' => 'nintendo', 'nb_visits' => false, 'nb_hits' => 0, Metrics::INDEX_NB_VISITS_CONVERTED => false, Metrics::INDEX_BOUNCE_COUNT => 5)
+ ));
+
+ $this->assertSame($expectedUsedColumn, $this->sorter->getPrimaryColumnToSort($table, $columnToSortBy));
+ }
+
+ public function getPrimaryColumnsToSort()
+ {
+ return array(
+ array('nb_visits', 'nb_visits'), // it is present in the row and should be used even though the value is false
+ array('nb_hits', 'nb_hits'), // it is present in the row and should be used even though the value is zero
+ array(Metrics::INDEX_NB_VISITS_CONVERTED, 'nb_visits_converted'), // the column name is not present but it should find the column id even though the value is false
+ array(Metrics::INDEX_NB_VISITS_CONVERTED, Metrics::INDEX_NB_VISITS_CONVERTED), // if a column is present as id it should still be able to find it
+ array(Metrics::INDEX_BOUNCE_COUNT, 'bounce_count'), // should resolve column name to id, column has a value
+ array(Metrics::INDEX_BOUNCE_COUNT, Metrics::INDEX_BOUNCE_COUNT), // should find a column with a value
+ );
+ }
+
+ public function test_getPrimaryColumnToSort_shouldFallbackToNbVisitsIfPossible()
+ {
+ $table = $this->createDataTable(array(
+ array('label' => 'nintendo', 'nb_visits' => false)
+ ));
+
+ $this->assertSame('nb_visits', $this->sorter->getPrimaryColumnToSort($table, 'any_random_column_that_doesnt_exist'));
+ }
+
+ public function test_getPrimaryColumnToSort_shouldFallbackToThePassedColumnNameIfColumnCannotBeFoundAndNbVisitsDoesNotExist()
+ {
+ $table = $this->createDataTable(array(array('label' => 'nintendo')));
+
+ $this->assertSame('any_random_column_that_doesnt_exist', $this->sorter->getPrimaryColumnToSort($table, 'any_random_column_that_doesnt_exist'));
+ }
+
+ public function test_getSecondaryColumnToSort_shouldNotFindASecondaryColumnToSort_IfSortedByLabelButNoVisitsColumnPresent()
+ {
+ $row = $this->createRow(array('label' => 'nintendo'));
+
+ $this->assertNull($this->sorter->getSecondaryColumnToSort($row, 'label'));
+ }
+
+ public function test_getSecondaryColumnToSort_shouldPreferVisitsColumn_IfColumnIsPresent_EvenIfValueIsFalse()
+ {
+ $row = $this->createRow(array('label' => 'nintendo', 'nb_visits' => false, 'nb_hits' => 10));
+
+ $this->assertSame('nb_visits', $this->sorter->getSecondaryColumnToSort($row, 'nb_hits'));
+ $this->assertSame('nb_visits', $this->sorter->getSecondaryColumnToSort($row, 'label'));
+ }
+
+ public function test_getSecondaryColumnToSort_shouldPreferVisitsColumn_IfColumnIsPresent_EvenIfVisitsColumnIsId()
+ {
+ $row = $this->createRow(array('label' => 'nintendo', Metrics::INDEX_NB_VISITS => false, 'nb_hits' => 10));
+
+ $this->assertSame(Metrics::INDEX_NB_VISITS, $this->sorter->getSecondaryColumnToSort($row, 'nb_hits'));
+ $this->assertSame(Metrics::INDEX_NB_VISITS, $this->sorter->getSecondaryColumnToSort($row, 'label'));
+ }
+
+ public function test_getSecondaryColumnToSort_shouldUseLabelColumn_IfColumnIsPresentButNotNbVisitsColumn()
+ {
+ $row = $this->createRow(array('label' => 'nintendo', 'nb_hits' => 10));
+
+ $this->assertSame('label', $this->sorter->getSecondaryColumnToSort($row, 'nb_hits'));
+ }
+
+ public function test_getSecondaryColumnToSort_shouldUseLabelColumn_IfPrimaryColumnIsNbVisitsColumn()
+ {
+ $row = $this->createRow(array('label' => 'nintendo', 'nb_visits' => 10));
+
+ $this->assertSame('label', $this->sorter->getSecondaryColumnToSort($row, 'nb_visits'));
+ $this->assertSame('label', $this->sorter->getSecondaryColumnToSort($row, Metrics::INDEX_NB_VISITS));
+ }
+
+ public function test_getSecondaryColumnToSort_shouldNotBeAbleToFallback_IfVisitsColumnIsUsedButThereIsNoLabelColumn()
+ {
+ $row = $this->createRow(array('nb_visits' => 10, 'nb_hits' => 10));
+
+ $this->assertNull($this->sorter->getSecondaryColumnToSort($row, 'nb_visits'));
+ }
+
+ public function test_getSecondaryColumnToSort_shouldUseVisitsAsSecondaryColumn_IfLabelIsUsedAsPrimaryColumn()
+ {
+ $row = $this->createRow(array('label' => 'nintendo', 'nb_visits' => false));
+
+ $this->assertSame('nb_visits', $this->sorter->getSecondaryColumnToSort($row, 'label'));
+ }
+
+ /**
+ * @dataProvider getLabelsForNaturalSortTest
+ */
+ public function test_getBestSortFlags_shouldAlwaysPickStringOrNaturalSortCaseInsensitive($label)
+ {
+ $table = $this->createDataTable(array(array('label' => $label)));
+
+ $this->config->naturalSort = false; // even if natural sort is not preferred it should be still used
+ $this->assertSame(SORT_STRING | SORT_FLAG_CASE, $this->sorter->getBestSortFlags($table, 'label'));
+
+ $this->config->naturalSort = true;
+ $this->assertSame(SORT_NATURAL | SORT_FLAG_CASE, $this->sorter->getBestSortFlags($table, 'label'));
+ }
+
+ public function getLabelsForNaturalSortTest()
+ {
+ return array(array('nintendo'), array('2015'), array('240.4'), array(2015), array('/test'));
+ }
+
+ /**
+ * @dataProvider getColumnsForBestSortFlagsTest
+ */
+ public function test_getBestSortFlags($expectedSortFlags, $columnToReadFrom, $naturalSort = false)
+ {
+ $this->config->naturalSort = $naturalSort;
+
+ $table = $this->createDataTable(array(
+ array('label' => 'nintendo1', 'nb_visits' => false, 'nb_hits' => 0, Metrics::INDEX_NB_VISITS_CONVERTED => false, Metrics::INDEX_BOUNCE_COUNT => 5),
+ array('label' => 'nintendo2', 'nb_visits' => 100, 'nb_pageviews' => 100, Metrics::INDEX_NB_VISITS_CONVERTED => null, 'sum_visit_length' => '5.5s'),
+ array('label' => 'nintendo2', Metrics::INDEX_NB_VISITS_CONVERTED => array(), 'min_time_generation' => '5.5')
+ ));
+
+ $this->assertSame($expectedSortFlags, $this->sorter->getBestSortFlags($table, $columnToReadFrom));
+ }
+
+ public function getColumnsForBestSortFlagsTest()
+ {
+ return array(
+ array(SORT_NUMERIC, 'nb_visits'), // should find a numeric value in the first row
+ array(SORT_NUMERIC, 'nb_pageviews'), // should find a numeric value in the second row
+ array(SORT_STRING | SORT_FLAG_CASE, Metrics::INDEX_NB_VISITS_CONVERTED), // should not find any value in any row and use default value
+ array(SORT_NATURAL | SORT_FLAG_CASE, Metrics::INDEX_NB_VISITS_CONVERTED, true), // should not find any value in any row and use default value, natural preferred
+ array(SORT_STRING | SORT_FLAG_CASE, 'sum_visit_length'), // it is not numeric so should use string as natural is disabled
+ array(SORT_NATURAL | SORT_FLAG_CASE, 'sum_visit_length', true), // it is not numeric but natural is preferred so should use natural sort
+ array(SORT_NUMERIC, 'min_time_generation') // value is a string but numeric so should use numeric
+ );
+ }
+
+ public function test_sort_shouldNotFailIfNoRowsAreSet()
+ {
+ $table = $this->createDataTable(array());
+
+ $this->sorter->sort($table);
+
+ $this->assertSame(0, $table->getRowsCount());
+ }
+
+ public function test_sort_shouldSetTheSortedColumnNameOnTheTable()
+ {
+ $table = $this->createDataTable(array(array('nb_test' => 5)));
+ $this->config->primaryColumnToSort = 'nb_test';
+
+ $this->sorter->sort($table);
+
+ $this->assertSame('nb_test', $table->getSortedByColumnName());
+ }
+
+ public function test_sort_shouldKeepTheAmountOfColumns()
+ {
+ $table = $this->createDataTableFromValues(array(5, null));
+ $table->addSummaryRow($this->createRow(array('nb_test' => 10)));
+
+ $this->sorter->sort($table);
+
+ $this->assertSame(3, $table->getRowsCount());
+ $this->assertSame(2, $table->getRowsCountWithoutSummaryRow());
+ }
+
+ public function test_sort_shouldNotSortOrChangeTheSummaryRow()
+ {
+ $table = $this->createDataTableFromValues(array(5, null));
+ $table->addSummaryRow($this->createRow(array('nb_test' => 10)));
+
+ $this->sorter->sort($table);
+
+ $summaryRow = $table->getRowFromId(DataTable::ID_SUMMARY_ROW);
+
+ $this->assertSame(10, $summaryRow->getColumn('nb_test'));
+ }
+
+ public function test_sort_shouldSortNumeric_AndShouldAddEmptyValuesAlwaysAtTheEnd()
+ {
+ $table = $this->createDataTableFromValues(array(5, null, 61, array(), 10, false, 20, 15));
+
+ $this->config->primarySortFlags = SORT_NUMERIC;
+ $this->config->primarySortOrder = SORT_ASC;
+ $this->sorter->sort($table);
+
+ $expected = array(5, 10, 15, 20, 61, false, array(), false);
+ $this->assertExpectedRowsOrder($expected, $table);
+
+ $this->config->primarySortOrder = SORT_DESC;
+ $this->sorter->sort($table);
+
+ $expected = array(61, 20, 15, 10, 5, false, array(), false);
+ $this->assertExpectedRowsOrder($expected, $table);
+ }
+
+ public function test_sort_sortNatural_ShoudAddEmptyValuesAlwaysAtTheEnd()
+ {
+ $table = $this->createDataTableFromValues(array('nintendo', null, 'abc', array(), 'DeF', 'def', false, '1210', 'piwik'));
+
+ $this->config->primarySortFlags = SORT_NATURAL;
+ $this->config->primarySortOrder = SORT_ASC;
+ $this->sorter->sort($table);
+
+ $expected = array('1210', 'DeF', 'abc', 'def', 'nintendo', 'piwik', false, array(), false);
+ $this->assertExpectedRowsOrder($expected, $table);
+
+ $this->config->primarySortOrder = SORT_DESC;
+ $this->sorter->sort($table);
+
+ $expected = array('piwik', 'nintendo', 'def', 'abc', 'DeF', '1210', false, array(), false);
+ $this->assertExpectedRowsOrder($expected, $table);
+ }
+
+ public function test_sort_ShoudIgnoreASecondColumnSort_IfDisabled()
+ {
+ $table = $this->createDataTableFromValues(array('abc', 'abc', 'abc', 'abc', 'abc'));
+
+ $this->config->primarySortFlags = SORT_NATURAL;
+ $this->config->isSecondaryColumnSortEnabled = false;
+ $this->sorter->sort($table);
+
+ // we make sure the labels order did not change neither when ASC nor DESC
+ $expected = array('My Label 0', 'My Label 1', 'My Label 2', 'My Label 3', 'My Label 4');
+ $this->assertExpectedRowsOrder($expected, $table, 'label');
+
+ $this->config->secondarySortOrder = SORT_DESC;
+ $this->sorter->sort($table);
+
+ $this->assertExpectedRowsOrder($expected, $table, 'label');
+ }
+
+ public function test_sort_ShoudIgnoreASecondColumnSort_IfSortIsNumericButNoSecondaryColumnIsSet()
+ {
+ $table = $this->createDataTableFromValues(array('abc', 'abc', 'abc', 'abc', 'abc'));
+
+ $this->config->primarySortFlags = SORT_NUMERIC;
+ $this->sorter->sort($table);
+
+ // we make sure the labels order did not change neither when ASC nor DESC
+ $expected = array('My Label 0', 'My Label 1', 'My Label 2', 'My Label 3', 'My Label 4');
+ $this->assertExpectedRowsOrder($expected, $table, 'label');
+
+ $this->config->secondarySortOrder = SORT_DESC;
+ $this->sorter->sort($table);
+
+ $this->assertExpectedRowsOrder($expected, $table, 'label');
+ }
+
+ public function test_sort_ShoudSortBySecondColumn_IfSortedNumeric()
+ {
+ $table = $this->createDataTableFromValues(array('abc', 'abc', 'abc', 'abc', 'abc'));
+
+ $this->config->primarySortFlags = SORT_NUMERIC;
+ $this->config->secondaryColumnToSort = 'label';
+ $this->config->secondarySortOrder = SORT_ASC;
+ $this->config->secondarySortFlags = SORT_NATURAL;
+
+ $this->sorter->sort($table);
+
+ // we make sure the labels order did not change neither when ASC nor DESC
+ $expected = array('My Label 0', 'My Label 1', 'My Label 2', 'My Label 3', 'My Label 4');
+ $this->assertExpectedRowsOrder($expected, $table, 'label');
+
+ $this->config->secondarySortOrder = SORT_DESC;
+ $this->sorter->sort($table);
+
+ $expected = array_reverse($expected);
+ $this->assertExpectedRowsOrder($expected, $table, 'label');
+ }
+
+ public function test_sort_ShoudSortEmptyValues_BySecondColumn_IfSortedNumeric()
+ {
+ $table = $this->createDataTableFromValues(array(null, null, null, null, null));
+
+ $this->config->primarySortFlags = SORT_NUMERIC;
+ $this->config->secondaryColumnToSort = 'label';
+ $this->config->secondarySortOrder = SORT_ASC;
+ $this->config->secondarySortFlags = SORT_NATURAL;
+
+ $this->sorter->sort($table);
+
+ // we make sure the labels order did not change neither when ASC nor DESC
+ $expected = array('My Label 0', 'My Label 1', 'My Label 2', 'My Label 3', 'My Label 4');
+ $this->assertExpectedRowsOrder($expected, $table, 'label');
+
+ $this->config->secondarySortOrder = SORT_DESC;
+ $this->sorter->sort($table);
+
+ $expected = array_reverse($expected);
+ $this->assertExpectedRowsOrder($expected, $table, 'label');
+ }
+
+ private function assertExpectedRowsOrder($expectedValuesOrder, $table, $column = 'nb_visits')
+ {
+ foreach ($table->getRows() as $index => $row) {
+ $this->assertSame($expectedValuesOrder[$index], $row->getColumn($column));
+ }
+ }
+
+ private function createDataTableFromValues($values)
+ {
+ $rows = array();
+ foreach ($values as $index => $value) {
+ $rows[] = array('nb_visits' => $value, 'label' => 'My Label ' . $index);
+ }
+
+ return $this->createDataTable($rows);
+ }
+
+ private function createDataTable($rows)
+ {
+ $table = new DataTable();
+ foreach ($rows as $columns) {
+ $table->addRow($this->createRow($columns));
+ }
+ return $table;
+ }
+
+ private function createRow($columns)
+ {
+ return new Row(array(Row::COLUMNS => $columns));
+ }
+
+} \ No newline at end of file
diff --git a/tests/PHPUnit/Unit/Report/ReportWidgetConfigTest.php b/tests/PHPUnit/Unit/Report/ReportWidgetConfigTest.php
new file mode 100644
index 0000000000..d1ac8d4021
--- /dev/null
+++ b/tests/PHPUnit/Unit/Report/ReportWidgetConfigTest.php
@@ -0,0 +1,262 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+
+namespace Piwik\Tests\Unit\Report;
+
+use Piwik\Report\ReportWidgetConfig;
+
+/**
+ * @group Widget
+ * @group Report
+ * @group ReportWidgetConfig
+ * @group ReportWidgetConfigTest
+ */
+class ReportWidgetConfigTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * @var ReportWidgetConfig
+ */
+ private $config;
+
+ public function setUp()
+ {
+ parent::setUp();
+ $this->config = new ReportWidgetConfig();
+ }
+
+ public function test_getViewDataTable_ByDefaultThereShouldBeNoDefaultView()
+ {
+ $this->assertNull($this->config->getViewDataTable());
+ }
+
+ public function test_setDefaultViewDataTable()
+ {
+ $this->config->setDefaultViewDataTable('table');
+
+ $this->assertSame('table', $this->config->getViewDataTable());
+ $this->assertFalse($this->config->isViewDataTableForced());
+ }
+
+ public function test_forceViewDataTable()
+ {
+ $this->config->forceViewDataTable('table');
+
+ $this->assertSame('table', $this->config->getViewDataTable());
+ $this->assertTrue($this->config->isViewDataTableForced());
+ }
+
+ public function test_name_set_get()
+ {
+ $this->config->setName('testName');
+
+ $this->assertSame('testName', $this->config->getName());
+ }
+
+ public function test_getName_shouldBeEmptyStringByDefault()
+ {
+ $this->assertSame('', $this->config->getName());
+ }
+
+ public function test_categoryId_set_get()
+ {
+ $this->config->setCategoryId('testCat');
+
+ $this->assertSame('testCat', $this->config->getCategoryId());
+ }
+
+ public function test_getCategoryId_shouldBeEmptyStringByDefault()
+ {
+ $this->assertSame('', $this->config->getCategoryId());
+ }
+
+ public function test_subcategoryId_set_get()
+ {
+ $this->config->setSubcategoryId('testsubcat');
+
+ $this->assertSame('testsubcat', $this->config->getSubcategoryId());
+ }
+
+ public function test_getSubcategoryId_shouldBeEmptyStringByDefault()
+ {
+ $this->assertSame('', $this->config->getSubcategoryId());
+ }
+
+ public function test_module_set_get()
+ {
+ $this->config->setModule('CoreHome');
+
+ $this->assertSame('CoreHome', $this->config->getModule());
+ }
+
+ public function test_getModule_shouldBeEmptyStringByDefault()
+ {
+ $this->assertSame('', $this->config->getModule());
+ }
+
+ public function test_action_set_get()
+ {
+ $this->config->setAction('get');
+
+ $this->assertSame('get', $this->config->getAction());
+ }
+
+ public function test_getAction_shouldBeEmptyStringByDefault()
+ {
+ $this->assertSame('', $this->config->getAction());
+ }
+
+ public function test_order_set_get()
+ {
+ $this->config->setOrder(99);
+ $this->assertSame(99, $this->config->getOrder());
+
+ $this->config->setOrder('98');
+ $this->assertSame(98, $this->config->getOrder());
+ }
+
+ public function test_getOrder_shouldReturnADefaultValue()
+ {
+ $this->assertSame(99, $this->config->getOrder());
+ }
+
+ public function test_setMiddlewareParameters_set_get()
+ {
+ $this->config->setMiddlewareParameters(array(
+ 'module' => 'Goals',
+ 'action' => 'hasConversions'
+ ));
+
+ $this->assertSame(array(
+ 'module' => 'Goals',
+ 'action' => 'hasConversions'
+ ), $this->config->getMiddlewareParameters());
+ }
+
+ public function test_getMiddlewareParameters_shouldReturnADefaultValue()
+ {
+ $this->assertSame(array(), $this->config->getMiddlewareParameters());
+ }
+
+ public function test_getParameters_ShouldAddModuleAndAction()
+ {
+ $this->setModuleAndAction();
+ $this->assertSame(array('module' => 'CoreHome', 'action' => 'renderMe'), $this->config->getParameters());
+ }
+
+ public function test_getParameters_ShouldNotBePossibleToOverwriteModuleAndAction()
+ {
+ $this->setModuleAndAction();
+ $this->config->setParameters(array('module' => 'Actions', 'action' => 'index'));
+
+ $this->assertSame(array('module' => 'CoreHome', 'action' => 'renderMe'), $this->config->getParameters());
+ }
+
+ public function test_getParameters_ShouldReturnViewDataTableIfSet()
+ {
+ $this->setModuleAndAction();
+ $this->config->setDefaultViewDataTable('graph');
+
+ $this->assertSame(array('viewDataTable' => 'graph', 'module' => 'CoreHome', 'action' => 'renderMe'), $this->config->getParameters());
+ }
+
+ public function test_getParameters_ShouldForceViewDataTableIfSet()
+ {
+ $this->setModuleAndAction();
+ $this->config->forceViewDataTable('graph');
+
+ $this->assertSame(array('forceView' => '1', 'viewDataTable' => 'graph', 'module' => 'CoreHome', 'action' => 'renderMe'), $this->config->getParameters());
+ }
+
+ public function test_addParameters_ShouldAddMoreParams()
+ {
+ $this->setModuleAndAction();
+ $this->config->addParameters(array('test' => '1')); // should be removed by setParameters
+ $this->config->addParameters(array('forceView' => '1'));
+ $this->config->addParameters(array('test' => '3'));
+
+ $this->assertSame(array('module' => 'CoreHome', 'action' => 'renderMe', 'test' => '3', 'forceView' => '1'), $this->config->getParameters());
+ }
+
+ public function test_setParameters_ShouldOverwriteAnyExistingParameters()
+ {
+ $this->setModuleAndAction();
+ $this->config->addParameters(array('test' => '1')); // should be removed by setParameters
+ $this->config->setParameters(array('forceView' => '1'));
+
+ $this->assertSame(array('module' => 'CoreHome', 'action' => 'renderMe', 'forceView' => '1'), $this->config->getParameters());
+ }
+
+ public function test_shouldBeEnabledByDefault()
+ {
+ $this->assertTrue($this->config->isEnabled());
+ }
+
+ public function test_enable_disable()
+ {
+ $this->config->disable();
+ $this->assertFalse($this->config->isEnabled());
+ $this->config->enable();
+ $this->assertTrue($this->config->isEnabled());
+ }
+
+ public function test_setIsEnabled()
+ {
+ $this->config->setIsEnabled(false);
+ $this->assertFalse($this->config->isEnabled());
+ $this->config->setIsEnabled(true);
+ $this->assertTrue($this->config->isEnabled());
+ }
+
+ public function test_checkIsEnabled_shouldNotThrowException_IfEnabled()
+ {
+ $this->config->enable();
+ $this->config->checkIsEnabled();
+ }
+
+ /**
+ * @expectedException \Exception
+ */
+ public function test_checkIsEnabled_shouldThrowException_IfDisabled()
+ {
+ $this->config->disable();
+ $this->config->checkIsEnabled();
+ }
+
+ public function test_shouldBeWidgetizable_ByDefault()
+ {
+ $this->assertTrue($this->config->isWidgetizeable());
+ }
+
+ public function test_widgetizeable()
+ {
+ $this->config->setIsNotWidgetizable();
+ $this->assertFalse($this->config->isWidgetizeable());
+ $this->config->setIsWidgetizable();
+ $this->assertTrue($this->config->isWidgetizeable());
+ }
+
+ public function test_getUniqueId_withNoParameters()
+ {
+ $this->setModuleAndAction();
+ $this->assertSame('widgetCoreHomerenderMe', $this->config->getUniqueId());
+ }
+
+ public function test_getUniqueId_withParameters()
+ {
+ $this->setModuleAndAction();
+ $this->config->addParameters(array('viewDataTable' => 'table', 'forceView' => '1', 'mtest' => array('test')));
+ $this->assertSame('widgetCoreHomerenderMeviewDataTabletableforceView1mtestArray', $this->config->getUniqueId());
+ }
+
+ private function setModuleAndAction()
+ {
+ $this->config->setModule('CoreHome');
+ $this->config->setAction('renderMe');
+ }
+
+}
diff --git a/tests/PHPUnit/Unit/Report/ReportWidgetFactoryTest.php b/tests/PHPUnit/Unit/Report/ReportWidgetFactoryTest.php
new file mode 100644
index 0000000000..2f49fee3cb
--- /dev/null
+++ b/tests/PHPUnit/Unit/Report/ReportWidgetFactoryTest.php
@@ -0,0 +1,112 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+
+namespace Piwik\Tests\Unit\Report;
+
+use Piwik\Plugin\Report;
+use Piwik\Report\ReportWidgetConfig;
+use Piwik\Report\ReportWidgetFactory;
+use Piwik\Widget\WidgetConfig;
+use Piwik\Widget\WidgetContainerConfig;
+
+class GetBasicReport extends Report
+{
+ protected function init()
+ {
+ parent::init();
+
+ $this->name = 'Report_MyCustomReportName';
+ $this->order = 20;
+ $this->module = 'TestPlugin';
+ $this->action = 'getBasicReport';
+ $this->categoryId = 'Goals_Goals';
+ $this->subcategoryId = 'General_Overview';
+ $this->actionToLoadSubTables = 'invalidReport';
+ $this->parameters = array('idGoal' => '1');
+ }
+
+ public function getDefaultTypeViewDataTable()
+ {
+ return 'graph';
+ }
+}
+
+/**
+ * @group Widget
+ * @group Report
+ * @group ReportWidgetFactory
+ * @group ReportWidgetFactoryTest
+ */
+class ReportWidgetFactoryTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * @var ReportWidgetFactory
+ */
+ private $factory;
+
+ public function setUp()
+ {
+ parent::setUp();
+
+ $this->factory = new ReportWidgetFactory(new GetBasicReport());
+ }
+
+ public function test_createContainerWidget_ShouldCreateAContainerBasedOnReportWithGivenId()
+ {
+ $config = $this->factory->createContainerWidget('myId');
+
+ $this->assertTrue($config instanceof WidgetContainerConfig);
+ $this->assertSame('myId', $config->getId());
+ $this->assertSame('Goals_Goals', $config->getCategoryId());
+ $this->assertSame('General_Overview', $config->getSubcategoryId());
+ $this->assertSame(100 + 20, $config->getOrder());
+ }
+
+ public function test_createWidget_ShouldCreateAContainerBasedOnReportWithGivenId()
+ {
+ $config = $this->factory->createWidget();
+
+ $this->assertTrue($config instanceof ReportWidgetConfig);
+ $this->assertSame('Report_MyCustomReportName', $config->getName());
+ $this->assertSame('Goals_Goals', $config->getCategoryId());
+ $this->assertSame('General_Overview', $config->getSubcategoryId());
+ $this->assertSame('graph', $config->getViewDataTable());
+ $this->assertSame(100 + 20, $config->getOrder());
+ $this->assertSame('TestPlugin', $config->getModule());
+ $this->assertSame('getBasicReport', $config->getAction());
+
+ $this->assertSame(array(
+ 'viewDataTable' => 'graph',
+ 'module' => 'TestPlugin',
+ 'action' => 'getBasicReport',
+ 'idGoal' => '1'
+ ), $config->getParameters());
+ }
+
+ public function test_createCustomWidget_ShouldCreateAContainerBasedOnReportWithGivenId()
+ {
+ $config = $this->factory->createCustomWidget('customAction');
+
+ $this->assertTrue($config instanceof ReportWidgetConfig);
+ $this->assertSame('Report_MyCustomReportName', $config->getName());
+ $this->assertSame('Goals_Goals', $config->getCategoryId());
+ $this->assertSame('General_Overview', $config->getSubcategoryId());
+ $this->assertNull($config->getViewDataTable());
+ $this->assertSame(100 + 20, $config->getOrder());
+ $this->assertSame('TestPlugin', $config->getModule());
+ $this->assertSame('customAction', $config->getAction());
+
+ $this->assertSame(array(
+ 'module' => 'TestPlugin',
+ 'action' => 'customAction',
+ 'idGoal' => '1'
+ ), $config->getParameters());
+ }
+
+
+}
diff --git a/tests/PHPUnit/Unit/UrlHelperTest.php b/tests/PHPUnit/Unit/UrlHelperTest.php
index cc15d6eeb1..bfdf9959aa 100644
--- a/tests/PHPUnit/Unit/UrlHelperTest.php
+++ b/tests/PHPUnit/Unit/UrlHelperTest.php
@@ -189,14 +189,6 @@ class UrlHelperTest extends \PHPUnit_Framework_TestCase
$this->assertEquals('localhost', UrlHelper::getHostFromUrl('localhost/path'));
$this->assertEquals('sub.localhost', UrlHelper::getHostFromUrl('sub.localhost/path'));
$this->assertEquals('sub.localhost', UrlHelper::getHostFromUrl('http://sub.localhost/path/?query=test'));
-
- if(SystemTestCase::isPhpVersion53()) {
- //parse_url was fixed in 5,4,7
- // Fixed host recognition when scheme is omitted and a leading component separator is present.
- // http://php.net/parse_url
- return;
- }
-
$this->assertEquals('localhost', UrlHelper::getHostFromUrl('//localhost/path'));
$this->assertEquals('localhost', UrlHelper::getHostFromUrl('//localhost/path?test=test2'));
$this->assertEquals('example.org', UrlHelper::getHostFromUrl('//example.org/path'));
@@ -233,4 +225,4 @@ class UrlHelperTest extends \PHPUnit_Framework_TestCase
$this->assertEquals('add=foo', UrlHelper::getQueryFromUrl('/', array('add' => 'foo')));
$this->assertEquals('add[]=foo&add[]=test', UrlHelper::getQueryFromUrl('/', array('add' => array('foo', 'test'))));
}
-} \ No newline at end of file
+}
diff --git a/tests/PHPUnit/Unit/Widget/WidgetConfigTest.php b/tests/PHPUnit/Unit/Widget/WidgetConfigTest.php
new file mode 100644
index 0000000000..de6917ef0e
--- /dev/null
+++ b/tests/PHPUnit/Unit/Widget/WidgetConfigTest.php
@@ -0,0 +1,224 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+
+namespace Piwik\Tests\Unit\Widget;
+
+use Piwik\Widget\WidgetConfig;
+
+/**
+ * @group Widget
+ * @group WidgetConfig
+ * @group WidgetConfigTest
+ */
+class WidgetConfigTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * @var WidgetConfig
+ */
+ private $config;
+
+ public function setUp()
+ {
+ parent::setUp();
+ $this->config = new WidgetConfig();
+ }
+
+ public function test_name_set_get()
+ {
+ $this->config->setName('testName');
+
+ $this->assertSame('testName', $this->config->getName());
+ }
+
+ public function test_getName_shouldBeEmptyStringByDefault()
+ {
+ $this->assertSame('', $this->config->getName());
+ }
+
+ public function test_categoryId_set_get()
+ {
+ $this->config->setCategoryId('testCat');
+
+ $this->assertSame('testCat', $this->config->getCategoryId());
+ }
+
+ public function test_getCategoryId_shouldBeEmptyStringByDefault()
+ {
+ $this->assertSame('', $this->config->getCategoryId());
+ }
+
+ public function test_subcategoryId_set_get()
+ {
+ $this->config->setSubcategoryId('testsubcat');
+
+ $this->assertSame('testsubcat', $this->config->getSubcategoryId());
+ }
+
+ public function test_getSubcategoryId_shouldBeEmptyStringByDefault()
+ {
+ $this->assertSame('', $this->config->getSubcategoryId());
+ }
+
+ public function test_module_set_get()
+ {
+ $this->config->setModule('CoreHome');
+
+ $this->assertSame('CoreHome', $this->config->getModule());
+ }
+
+ public function test_getModule_shouldBeEmptyStringByDefault()
+ {
+ $this->assertSame('', $this->config->getModule());
+ }
+
+ public function test_action_set_get()
+ {
+ $this->config->setAction('get');
+
+ $this->assertSame('get', $this->config->getAction());
+ }
+
+ public function test_getAction_shouldBeEmptyStringByDefault()
+ {
+ $this->assertSame('', $this->config->getAction());
+ }
+
+ public function test_order_set_get()
+ {
+ $this->config->setOrder(99);
+ $this->assertSame(99, $this->config->getOrder());
+
+ $this->config->setOrder('98');
+ $this->assertSame(98, $this->config->getOrder());
+ }
+
+ public function test_getOrder_shouldReturnADefaultValue()
+ {
+ $this->assertSame(99, $this->config->getOrder());
+ }
+
+ public function test_setMiddlewareParameters_set_get()
+ {
+ $this->config->setMiddlewareParameters(array(
+ 'module' => 'Goals',
+ 'action' => 'hasConversions'
+ ));
+
+ $this->assertSame(array(
+ 'module' => 'Goals',
+ 'action' => 'hasConversions'
+ ), $this->config->getMiddlewareParameters());
+ }
+
+ public function test_getMiddlewareParameters_shouldReturnADefaultValue()
+ {
+ $this->assertSame(array(), $this->config->getMiddlewareParameters());
+ }
+
+ public function test_getParameters_ShouldAddModuleAndAction()
+ {
+ $this->setModuleAndAction();
+ $this->assertSame(array('module' => 'CoreHome', 'action' => 'renderMe'), $this->config->getParameters());
+ }
+
+ public function test_getParameters_ShouldNotBePossibleToOverwriteModuleAndAction()
+ {
+ $this->setModuleAndAction();
+ $this->config->setParameters(array('module' => 'Actions', 'action' => 'index'));
+
+ $this->assertSame(array('module' => 'CoreHome', 'action' => 'renderMe'), $this->config->getParameters());
+ }
+
+ public function test_addParameters_ShouldAddMoreParams()
+ {
+ $this->setModuleAndAction();
+ $this->config->addParameters(array('test' => '1')); // should be removed by setParameters
+ $this->config->addParameters(array('forceView' => '1'));
+ $this->config->addParameters(array('test' => '3'));
+
+ $this->assertSame(array('module' => 'CoreHome', 'action' => 'renderMe', 'test' => '3', 'forceView' => '1'), $this->config->getParameters());
+ }
+
+ public function test_setParameters_ShouldOverwriteAnyExistingParameters()
+ {
+ $this->setModuleAndAction();
+ $this->config->addParameters(array('test' => '1')); // should be removed by setParameters
+ $this->config->setParameters(array('forceView' => '1'));
+
+ $this->assertSame(array('module' => 'CoreHome', 'action' => 'renderMe', 'forceView' => '1'), $this->config->getParameters());
+ }
+
+ public function test_shouldBeEnabledByDefault()
+ {
+ $this->assertTrue($this->config->isEnabled());
+ }
+
+ public function test_enable_disable()
+ {
+ $this->config->disable();
+ $this->assertFalse($this->config->isEnabled());
+ $this->config->enable();
+ $this->assertTrue($this->config->isEnabled());
+ }
+
+ public function test_setIsEnabled()
+ {
+ $this->config->setIsEnabled(false);
+ $this->assertFalse($this->config->isEnabled());
+ $this->config->setIsEnabled(true);
+ $this->assertTrue($this->config->isEnabled());
+ }
+
+ public function test_checkIsEnabled_shouldNotThrowException_IfEnabled()
+ {
+ $this->config->enable();
+ $this->config->checkIsEnabled();
+ }
+
+ /**
+ * @expectedException \Exception
+ */
+ public function test_checkIsEnabled_shouldThrowException_IfDisabled()
+ {
+ $this->config->disable();
+ $this->config->checkIsEnabled();
+ }
+
+ public function test_shouldBeWidgetizable_ByDefault()
+ {
+ $this->assertTrue($this->config->isWidgetizeable());
+ }
+
+ public function test_widgetizeable()
+ {
+ $this->config->setIsNotWidgetizable();
+ $this->assertFalse($this->config->isWidgetizeable());
+ $this->config->setIsWidgetizable();
+ $this->assertTrue($this->config->isWidgetizeable());
+ }
+
+ public function test_getUniqueId_withNoParameters()
+ {
+ $this->setModuleAndAction();
+ $this->assertSame('widgetCoreHomerenderMe', $this->config->getUniqueId());
+ }
+
+ public function test_getUniqueId_withParameters()
+ {
+ $this->setModuleAndAction();
+ $this->config->addParameters(array('viewDataTable' => 'table', 'forceView' => '1', 'mtest' => array('test')));
+ $this->assertSame('widgetCoreHomerenderMeviewDataTabletableforceView1mtestArray', $this->config->getUniqueId());
+ }
+
+ private function setModuleAndAction()
+ {
+ $this->config->setModule('CoreHome');
+ $this->config->setAction('renderMe');
+ }
+
+}
diff --git a/tests/PHPUnit/Unit/Widget/WidgetContainerConfigTest.php b/tests/PHPUnit/Unit/Widget/WidgetContainerConfigTest.php
new file mode 100644
index 0000000000..7a2d3fedae
--- /dev/null
+++ b/tests/PHPUnit/Unit/Widget/WidgetContainerConfigTest.php
@@ -0,0 +1,280 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+
+namespace Piwik\Tests\Unit\Widget;
+
+use Piwik\Widget\WidgetConfig;
+use Piwik\Widget\WidgetContainerConfig;
+
+/**
+ * @group Widget
+ * @group WidgetContainerConfig
+ * @group WidgetContainerConfigTest
+ */
+class WidgetContainerConfigTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * @var WidgetContainerConfig
+ */
+ private $config;
+
+ private $id = 'MyTestContainer';
+
+ public function setUp()
+ {
+ parent::setUp();
+ $this->config = new WidgetContainerConfig();
+ $this->config->setId($this->id);
+ }
+
+ public function test_id_set_get()
+ {
+ $this->config->setId('testId');
+
+ $this->assertSame('testId', $this->config->getId());
+ }
+
+ public function test_name_set_get()
+ {
+ $this->config->setName('testName');
+
+ $this->assertSame('testName', $this->config->getName());
+ }
+
+ public function test_getName_shouldBeEmptyStringByDefault()
+ {
+ $this->assertSame('', $this->config->getName());
+ }
+
+ public function test_layout_set_get()
+ {
+ $this->config->setLayout('ByDimension');
+
+ $this->assertSame('ByDimension', $this->config->getLayout());
+ }
+
+ public function test_getLayout_shouldBeEmptyStringByDefault()
+ {
+ $this->assertSame('', $this->config->getLayout());
+ }
+
+ public function test_categoryId_set_get()
+ {
+ $this->config->setCategoryId('testCat');
+
+ $this->assertSame('testCat', $this->config->getCategoryId());
+ }
+
+ public function test_getCategoryId_shouldBeEmptyStringByDefault()
+ {
+ $this->assertSame('', $this->config->getCategoryId());
+ }
+
+ public function test_subcategoryId_set_get()
+ {
+ $this->config->setSubcategoryId('testsubcat');
+
+ $this->assertSame('testsubcat', $this->config->getSubcategoryId());
+ }
+
+ public function test_getSubcategoryId_shouldBeEmptyStringByDefault()
+ {
+ $this->assertSame('', $this->config->getSubcategoryId());
+ }
+
+ public function test_module_set_get()
+ {
+ $this->config->setModule('CoreHome');
+
+ $this->assertSame('CoreHome', $this->config->getModule());
+ }
+
+ public function test_getModule_shouldBeTheModuleToRenderItByDefault()
+ {
+ $this->assertSame('CoreHome', $this->config->getModule());
+ }
+
+ public function test_action_set_get()
+ {
+ $this->config->setAction('get');
+
+ $this->assertSame('get', $this->config->getAction());
+ }
+
+ public function test_getAction_shouldBeTheActionToRenderItByDefault()
+ {
+ $this->assertSame('renderWidgetContainer', $this->config->getAction());
+ }
+
+ public function test_order_set_get()
+ {
+ $this->config->setOrder(99);
+ $this->assertSame(99, $this->config->getOrder());
+
+ $this->config->setOrder('98');
+ $this->assertSame(98, $this->config->getOrder());
+ }
+
+ public function test_getOrder_shouldReturnADefaultValue()
+ {
+ $this->assertSame(99, $this->config->getOrder());
+ }
+
+ public function test_setMiddlewareParameters_set_get()
+ {
+ $this->config->setMiddlewareParameters(array(
+ 'module' => 'Goals',
+ 'action' => 'hasConversions'
+ ));
+
+ $this->assertSame(array(
+ 'module' => 'Goals',
+ 'action' => 'hasConversions'
+ ), $this->config->getMiddlewareParameters());
+ }
+
+ public function test_getMiddlewareParameters_shouldReturnADefaultValue()
+ {
+ $this->assertSame(array(), $this->config->getMiddlewareParameters());
+ }
+
+ public function test_getParameters_ShouldAddModuleAndAction()
+ {
+ $this->assertSame(array(
+ 'module' => 'CoreHome',
+ 'action' => 'renderWidgetContainer',
+ 'containerId' => $this->id
+ ), $this->config->getParameters());
+ }
+
+ public function test_getParameters_ShouldNotBePossibleToOverwriteModuleAndAction()
+ {
+ $this->config->setParameters(array('module' => 'Actions', 'action' => 'index', 'containerId' => 'test'));
+
+ $this->assertSame(array(
+ 'module' => 'CoreHome',
+ 'action' => 'renderWidgetContainer',
+ 'containerId' => $this->id
+ ), $this->config->getParameters());
+ }
+
+ public function test_addParameters_ShouldAddMoreParams()
+ {
+ $this->config->addParameters(array('test' => '1')); // should be removed by setParameters
+ $this->config->addParameters(array('forceView' => '1'));
+ $this->config->addParameters(array('test' => '3'));
+
+ $this->assertSame(array(
+ 'module' => 'CoreHome',
+ 'action' => 'renderWidgetContainer',
+ 'test' => '3',
+ 'forceView' => '1',
+ 'containerId' => $this->id
+ ), $this->config->getParameters());
+ }
+
+ public function test_setParameters_ShouldOverwriteAnyExistingParameters()
+ {
+ $this->config->addParameters(array('test' => '1')); // should be removed by setParameters
+ $this->config->setParameters(array('forceView' => '1'));
+
+ $this->assertSame(array(
+ 'module' => 'CoreHome',
+ 'action' => 'renderWidgetContainer',
+ 'forceView' => '1',
+ 'containerId' => $this->id
+ ), $this->config->getParameters());
+ }
+
+ public function test_shouldBeEnabledByDefault()
+ {
+ $this->assertTrue($this->config->isEnabled());
+ }
+
+ public function test_enable_disable()
+ {
+ $this->config->disable();
+ $this->assertFalse($this->config->isEnabled());
+ $this->config->enable();
+ $this->assertTrue($this->config->isEnabled());
+ }
+
+ public function test_setIsEnabled()
+ {
+ $this->config->setIsEnabled(false);
+ $this->assertFalse($this->config->isEnabled());
+ $this->config->setIsEnabled(true);
+ $this->assertTrue($this->config->isEnabled());
+ }
+
+ public function test_checkIsEnabled_shouldNotThrowException_IfEnabled()
+ {
+ $this->config->enable();
+ $this->config->checkIsEnabled();
+ }
+
+ /**
+ * @expectedException \Exception
+ */
+ public function test_checkIsEnabled_shouldThrowException_IfDisabled()
+ {
+ $this->config->disable();
+ $this->config->checkIsEnabled();
+ }
+
+ public function test_shouldNotBeWidgetizable_ByDefault()
+ {
+ $this->assertFalse($this->config->isWidgetizeable());
+ }
+
+ public function test_widgetizeable()
+ {
+ $this->config->setIsNotWidgetizable();
+ $this->assertFalse($this->config->isWidgetizeable());
+ $this->config->setIsWidgetizable();
+ $this->assertTrue($this->config->isWidgetizeable());
+ }
+
+ public function test_getUniqueId_shouldIncludeContainerId()
+ {
+ $this->assertSame('widgetMyTestContainer', $this->config->getUniqueId());
+ }
+
+ public function test_getUniqueId_withParameters()
+ {
+ $this->config->addParameters(array('viewDataTable' => 'table', 'forceView' => '1', 'mtest' => array('test')));
+ $this->assertSame('widgetMyTestContainerviewDataTabletableforceView1mtestArray', $this->config->getUniqueId());
+ }
+
+ public function test_getWidgetConfigs_shouldBeEmptyByDefault()
+ {
+ $this->assertSame(array(), $this->config->getWidgetConfigs());
+ }
+
+ public function test_widgetConfigs_shouldBeEmptyByDefault()
+ {
+ $this->config->addWidgetConfig($widget1 = $this->createWidgetConfig('widget1'));
+ $this->config->addWidgetConfig($widget2 = $this->createWidgetConfig('widget2'));
+ $this->config->addWidgetConfig($widget3 = $this->createWidgetConfig('widget3'));
+ $this->config->addWidgetConfig($widget4 = new WidgetContainerConfig()); // should be possible to add container to a container
+ $this->assertSame(array(
+ $widget1,
+ $widget2,
+ $widget3,
+ $widget4
+ ), $this->config->getWidgetConfigs());
+ }
+
+ private function createWidgetConfig($widgetName)
+ {
+ $config = new WidgetConfig();
+ $config->setName($widgetName);
+
+ return $config;
+ }
+}
diff --git a/tests/PHPUnit/Unit/Widget/WidgetsListTest.php b/tests/PHPUnit/Unit/Widget/WidgetsListTest.php
new file mode 100644
index 0000000000..050da65eaf
--- /dev/null
+++ b/tests/PHPUnit/Unit/Widget/WidgetsListTest.php
@@ -0,0 +1,177 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+
+namespace Piwik\Tests\Unit\Widget;
+
+use Piwik\Widget\WidgetConfig;
+use Piwik\Widget\WidgetContainerConfig;
+use Piwik\Widget\WidgetsList;
+
+/**
+ * @group Widget
+ * @group WidgetsList
+ * @group WidgetsListTest
+ */
+class WidgetsListTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * @var WidgetsList
+ */
+ private $list;
+
+ public function setUp()
+ {
+ parent::setUp();
+ $this->list = new WidgetsList();
+ }
+
+ public function test_getWidgetUniqueId_withoutParameters()
+ {
+ $id = WidgetsList::getWidgetUniqueId('CoreHome', 'render');
+ $this->assertSame('widgetCoreHomerender', $id);
+ }
+
+ public function test_getWidgetUniqueId_withParameters()
+ {
+ $id = WidgetsList::getWidgetUniqueId('CoreHome', 'render', array('test1' => 'value', 'key' => array('test'), 'test2' => '4k3k'));
+ $this->assertSame('widgetCoreHomerendertest1valuekeyArraytest24k3k', $id);
+ }
+
+ public function test_getWidgetConfigs_shouldBeEmptyByDefault()
+ {
+ $this->assertSame(array(), $this->list->getWidgetConfigs());
+ }
+
+ public function test_addWidget_shouldAddAnyWidgetConfigs()
+ {
+ $this->list->addWidgetConfig($widget1 = $this->createWidget('widget1'));
+ $this->list->addWidgetConfig($widget2 = $this->createWidgetContainer('widget2'));
+ $this->list->addWidgetConfig($widget3 = $this->createWidget('widget3'));
+
+ $this->assertSame(array($widget1, $widget2, $widget3), $this->list->getWidgetConfigs());
+ }
+
+ public function test_addWidgets_shouldAddAnyWidgetConfigs()
+ {
+ $this->list->addWidgetConfigs(array(
+ $widget1 = $this->createWidget('widget1'),
+ $widget2 = $this->createWidgetContainer('widget2'),
+ $widget3 = $this->createWidget('widget3'),
+ ));
+
+ $this->assertSame(array($widget1, $widget2, $widget3), $this->list->getWidgetConfigs());
+ }
+
+ public function test_addToContainerWidget_shouldAddWidgetToContainerImmediately_IfContainerAlreadyExistsInList()
+ {
+ $this->list->addWidgetConfigs(array(
+ $widget1 = $this->createWidget('widget1'),
+ $widget2 = $this->createWidgetContainer('widget2')->setId('testId'),
+ $widget3 = $this->createWidget('widget3'),
+ ));
+
+ $this->list->addToContainerWidget('testId', $widget4 = $this->createWidget('widget4'));
+
+ $this->assertSame(array($widget4), $widget2->getWidgetConfigs());
+
+ // widget4 should not be added to this widgetConfigs
+ $this->assertSame(array($widget1, $widget2, $widget3), $this->list->getWidgetConfigs());
+ }
+
+ public function test_addToContainerWidget_shouldAddWidgetToContainerAsSoonAsContainerAdded_IfContainerNotAlreadyExistsInList()
+ {
+ $this->list->addToContainerWidget('testId', $widget4 = $this->createWidget('widget4'));
+
+ $this->list->addWidgetConfigs(array(
+ $widget1 = $this->createWidget('widget1'),
+ $widget2 = $this->createWidgetContainer('widget2')->setId('testId'),
+ $widget3 = $this->createWidget('widget3'),
+ ));
+
+ $this->assertSame(array($widget4), $widget2->getWidgetConfigs());
+
+ // widget4 should not be added to this widgetConfigs
+ $this->assertSame(array($widget1, $widget2, $widget3), $this->list->getWidgetConfigs());
+ }
+
+ /**
+ * @dataProvider getWidgetsToRemove
+ */
+ public function test_remove($categoryId, $name, $expectedWidgetNamesInList)
+ {
+ $this->list->addWidgetConfigs(array(
+ $widget1 = $this->createWidget('widget1')->setCategoryId('Visits'),
+ $widget2 = $this->createWidgetContainer('widget2')->setCategoryId('Actions'),
+ $widget3 = $this->createWidget('widget3')->setCategoryId('Visits'),
+ ));
+
+ $this->list->remove($categoryId, $name);
+
+ $names = array();
+ foreach ($this->list->getWidgetConfigs() as $config) {
+ $names[] = $config->getName();
+ }
+
+ $this->assertSame($expectedWidgetNamesInList, $names);
+ }
+
+ public function getWidgetsToRemove()
+ {
+ return array(
+ array('Visits', false, array('widget2')),
+ array('Visits', 'widget3', array('widget1', 'widget2')),
+ array('Actions', false, array('widget1', 'widget3')),
+ array('Actions', 'widget2', array('widget1', 'widget3')),
+ array('Actions', 'notExist', array('widget1', 'widget2', 'widget3')),
+ array('NotExiSt', false, array('widget1', 'widget2', 'widget3')),
+ );
+ }
+
+ /**
+ * @dataProvider getWidgetsDefined
+ */
+ public function test_isDefined($module, $action, $exists)
+ {
+ $this->list->addWidgetConfigs(array(
+ $widget1 = $this->createWidget('widget1')->setModule('CoreHome')->setAction('renderMe'),
+ $widget2 = $this->createWidgetContainer('widget2')->setModule('CoreHome')->setAction('renderContainer'),
+ $widget3 = $this->createWidget('widget3')->setModule('Actions')->setAction('index'),
+ ));
+
+ $this->assertSame($exists, $this->list->isDefined($module, $action));
+ }
+
+ public function getWidgetsDefined()
+ {
+ return array(
+ array('CoreHome', 'renderMe', $isDefined = true),
+ array('CoreHome', 'renderContainer', $isDefined = true),
+ array('Actions', 'index', $isDefined = true),
+ array('Actions', 'renderMe', $isDefined = false),
+ array('AnyThiNg', 'renderMe', $isDefined = false),
+ array('CoreHome', 'index', $isDefined = false)
+ );
+ }
+
+ private function createWidget($name)
+ {
+ $config = new WidgetConfig();
+ $config->setName($name);
+
+ return $config;
+ }
+
+ private function createWidgetContainer($name)
+ {
+ $config = new WidgetContainerConfig();
+ $config->setName($name);
+
+ return $config;
+ }
+
+}
diff --git a/tests/UI/diff.png b/tests/UI/diff.png
new file mode 100644
index 0000000000..910fca0df3
--- /dev/null
+++ b/tests/UI/diff.png
Binary files differ
diff --git a/tests/UI/expected-ui-screenshots b/tests/UI/expected-ui-screenshots
-Subproject c8da5542432c1e1410f0330fcd612e93b1414a1
+Subproject 9ca952c6485f9e0d7a890a78720ca1365aaf67f
diff --git a/tests/UI/specs/DashboardManager_spec.js b/tests/UI/specs/DashboardManager_spec.js
index 8fb1435b8e..ae6e2eddc4 100644
--- a/tests/UI/specs/DashboardManager_spec.js
+++ b/tests/UI/specs/DashboardManager_spec.js
@@ -12,7 +12,9 @@ describe("DashboardManager", function () {
this.timeout(0);
var selectorToCapture = '.dashboard-manager';
- var url = "?module=CoreHome&action=index&idSite=1&period=day&date=2012-01-01";
+
+ var generalParams = 'idSite=1&period=day&date=2012-01-01';
+ var url = '?module=CoreHome&action=index&' + generalParams + '#?' + generalParams + '&category=Dashboard_Dashboard&subcategory=5';
it("should load correctly", function (done) {
expect.screenshot("loaded").to.be.captureSelector(selectorToCapture, function (page) {
@@ -29,7 +31,7 @@ describe("DashboardManager", function () {
it("should show widget for a category when category label hovered", function (done) {
expect.screenshot("widget_list_shown").to.be.captureSelector(selectorToCapture, function (page) {
page.mouseMove('.widgetpreview-categorylist>li:contains(Live!)'); // have to mouse move twice... otherwise Live! will just be highlighted
- page.mouseMove('.widgetpreview-categorylist>li:contains(Visits Summary)');
+ page.mouseMove('.widgetpreview-categorylist>li:contains(Visitors):first');
}, done);
});
diff --git a/tests/UI/specs/Dashboard_spec.js b/tests/UI/specs/Dashboard_spec.js
index f68197db0f..2489f69637 100644
--- a/tests/UI/specs/Dashboard_spec.js
+++ b/tests/UI/specs/Dashboard_spec.js
@@ -45,7 +45,7 @@ describe("Dashboard", function () {
var layout = [
[
{
- uniqueId: "widgetVisitsSummarygetEvolutionGraphcolumnsArray",
+ uniqueId: "widgetVisitsSummarygetEvolutionGraphforceView1viewDataTablegraphEvolution",
parameters: {module: "VisitsSummary", action: "getEvolutionGraph", columns: "nb_visits"}
}
],
@@ -122,18 +122,21 @@ describe("Dashboard", function () {
page.click('.dashboard-manager .title');
page.mouseMove('.widgetpreview-categorylist>li:contains(Live!)'); // have to mouse move twice... otherwise Live! will just be highlighted
- page.mouseMove('.widgetpreview-categorylist>li:contains(Visits Summary)');
+ page.mouseMove('.widgetpreview-categorylist>li:contains(Times):first');
- page.mouseMove('.widgetpreview-widgetlist>li:contains(Visits by Local Time)');
+ page.mouseMove('.widgetpreview-widgetlist>li:contains(Visits per local time)');
- page.click('.widgetpreview-widgetlist>li:contains(Visits by Local Time)');
+ page.click('.widgetpreview-widgetlist>li:contains(Visits per local time)');
}, done);
});
it("should remove widget when remove widget icon is clicked", function (done) {
expect.screenshot("widget_move_removed").to.be.capture(function (page) {
- page.mouseMove('#widgetVisitTimegetVisitInformationPerLocalTime .widgetTop');
- page.click('#widgetVisitTimegetVisitInformationPerLocalTime .button#close');
+ var widget = '[id="widgetVisitTimegetVisitInformationPerLocalTimeviewDataTablegraphVerticalBar"]';
+
+ page.mouseMove(widget + ' .widgetTop');
+ page.click(widget + ' .button#close');
+
page.click('.ui-dialog button>span:contains(Yes)');
page.mouseMove('.dashboard-manager');
}, done);
@@ -144,7 +147,7 @@ describe("Dashboard", function () {
page.click('.dashboard-manager .title');
page.click('li[data-action=showChangeDashboardLayoutDialog]');
page.click('div[layout=50-50]');
- page.click('.ui-dialog button>span:contains(Save)', 3000);
+ page.click('.ui-dialog button>span:contains(Save)');
}, done);
});
@@ -164,11 +167,11 @@ describe("Dashboard", function () {
page.click('.dashboard-manager .title');
page.click('li[data-action=copyDashboardToUser]');
page.evaluate(function () {
- $('#copyDashboardName').val('');
+ $('[id=copyDashboardName]:last').val('');
});
- page.sendKeys('#copyDashboardName', 'newdash');
+ page.sendKeys('[id=copyDashboardName]:last', 'newdash');
page.evaluate(function () {
- $('#copyDashboardUser').val('superUserLogin');
+ $('[id=copyDashboardUser]:last').val('superUserLogin');
});
page.click('.ui-dialog button>span:contains(Ok)');
@@ -180,7 +183,7 @@ describe("Dashboard", function () {
expect.screenshot("reset").to.be.capture(function (page) {
page.click('.dashboard-manager .title');
page.click('li[data-action=resetDashboard]');
- page.click('.ui-dialog button>span:contains(Yes)', 10000);
+ page.click('.ui-dialog button>span:contains(Yes)', 4000);
page.mouseMove('.dashboard-manager');
}, done);
});
@@ -206,11 +209,11 @@ describe("Dashboard", function () {
}, done);
});
- it("should create new dashboard with new default widget selection when create dashboard process completed", function (done) {
+ it.skip("should create new dashboard with new default widget selection when create dashboard process completed", function (done) {
expect.screenshot("create_new").to.be.capture(function (page) {
page.click('.dashboard-manager .title');
page.click('li[data-action=createDashboard]');
- page.sendKeys('#createDashboardName', 'newdash2');
+ page.sendKeys('#createDashboardName:visible', 'newdash2');
page.click('.ui-dialog[aria-describedby=createDashboardConfirm] button>span:contains(Yes)');
// toggle map widget to prevent failures
page.mouseMove('#widgetUserCountryMapvisitorMap .widgetTop', 3000);
diff --git a/tests/UI/specs/Menus_spec.js b/tests/UI/specs/Menus_spec.js
index 3124766e79..3e15888ecf 100644
--- a/tests/UI/specs/Menus_spec.js
+++ b/tests/UI/specs/Menus_spec.js
@@ -22,19 +22,19 @@ describe("Menus", function () {
// main menu tests
it('should load the main reporting menu correctly', function (done) {
expect.screenshot('mainmenu_loaded').to.be.captureSelector('#secondNavBar', function (page) {
- page.load("?" + urlBase + "#" + generalParams + "&module=Actions&action=menuGetPageUrls");
+ page.load("?" + urlBase + "#?" + generalParams + "&category=General_Actions&subcategory=General_Pages");
}, done);
});
it('should change the menu when a upper menu item is clicked in the main menu', function (done) {
expect.screenshot('mainmenu_upper_clicked').to.be.captureSelector('#secondNavBar', function (page) {
- page.click('#secondNavBar .navbar > li:eq(1) > a');
+ openMenuItem(page, 'Visitors');
}, done);
});
it('should change the menu when a lower menu item is clicked in the main menu', function (done) {
expect.screenshot('mainmenu_lower_clicked').to.be.captureSelector('#secondNavBar', function (page) {
- page.click('#secondNavBar .navbar > li:eq(1) > ul > li:eq(1) > a');
+ openMenuItem(page, 'Visitor Log');
}, done);
});
@@ -65,4 +65,4 @@ describe("Menus", function () {
openMenuItem(page, 'Websites');
}, done);
});
-}); \ No newline at end of file
+});
diff --git a/tests/UI/specs/Overlay_spec.js b/tests/UI/specs/Overlay_spec.js
index d4117627e3..c0adc30a43 100644
--- a/tests/UI/specs/Overlay_spec.js
+++ b/tests/UI/specs/Overlay_spec.js
@@ -22,7 +22,7 @@ describe("Overlay", function () {
before(function (done) {
var baseUrl = '?module=Overlay&period=year&date=today&idSite=3';
- var hash = '#l=' + encodeURIComponent(testEnvironment.overlayUrl).replace(/[%]/g, "$");
+ var hash = '#?l=' + encodeURIComponent(testEnvironment.overlayUrl).replace(/[%]/g, "$");
url = baseUrl + hash;
urlWithSegment = baseUrl + '&segment=' + encodeURIComponent('visitIp==20.56.34.67') + hash;
diff --git a/tests/UI/specs/PeriodSelector_spec.js b/tests/UI/specs/PeriodSelector_spec.js
index 0711ee55a8..7668d27375 100644
--- a/tests/UI/specs/PeriodSelector_spec.js
+++ b/tests/UI/specs/PeriodSelector_spec.js
@@ -10,7 +10,8 @@
describe("PeriodSelector", function () {
this.timeout(0);
- var url = "?module=CoreHome&action=index&idSite=1&period=day&date=2012-01-01";
+ var generalParams = 'idSite=1&period=day&date=2012-01-01';
+ var url = '?module=CoreHome&action=index&' + generalParams + '#?' + generalParams + '&category=General_Actions&subcategory=General_Pages';
it("should load correctly", function (done) {
expect.screenshot("loaded").to.be.captureSelector('#periodString', function (page) {
diff --git a/tests/UI/specs/PivotByDimension_spec.js b/tests/UI/specs/PivotByDimension_spec.js
index d04d420043..86a5815d53 100644
--- a/tests/UI/specs/PivotByDimension_spec.js
+++ b/tests/UI/specs/PivotByDimension_spec.js
@@ -10,9 +10,9 @@
describe("PivotByDimension", function () {
this.timeout(0);
- var eventsUrl = "?module=CoreHome&action=index&idSite=1&period=year&date=2012-08-09#/idSite=1&period=year&date=2012-08-09&module=Events&action=index",
- actionsUrl = "?module=CoreHome&action=index&idSite=1&period=year&date=2012-08-09#/idSite=1&period=year&date=2012-08-09&module=Actions&action=menuGetPageUrls",
- cvarsUrl = "?module=CoreHome&action=index&idSite=1&period=year&date=2012-08-09#/idSite=1&period=year&date=2012-08-09&module=CustomVariables&action=menuGetCustomVariables"
+ var eventsUrl = "?module=CoreHome&action=index&idSite=1&period=year&date=2012-08-09#?idSite=1&period=year&date=2012-08-09&category=General_Actions&subcategory=Events_Events",
+ actionsUrl = "?module=CoreHome&action=index&idSite=1&period=year&date=2012-08-09#?idSite=1&period=year&date=2012-08-09&category=General_Actions&subcategory=General_Pages",
+ cvarsUrl = "?module=CoreHome&action=index&idSite=1&period=year&date=2012-08-09#?idSite=1&period=year&date=2012-08-09&category=General_Visitors&subcategory=CustomVariables_CustomVariables"
;
it("should pivot a report correctly when the pivot cog option is selected", function (done) {
diff --git a/tests/UI/specs/ReportExporting_spec.js b/tests/UI/specs/ReportExporting_spec.js
index fc223edfcc..992dd18b4f 100644
--- a/tests/UI/specs/ReportExporting_spec.js
+++ b/tests/UI/specs/ReportExporting_spec.js
@@ -11,8 +11,8 @@ describe("ReportExporting", function () {
this.timeout(0);
var baseUrl = "?module=Widgetize&action=iframe&idSite=1&period=year&date=2012-08-09&isFooterExpandedInDashboard=1",
- referrersGetWebsitesUrl = baseUrl + "&moduleToWidgetize=Referrers&actionToWidgetize=getWebsites&viewDataTable=table&filter_limit=5",
- visitsSummaryGetUrl = baseUrl + "&moduleToWidgetize=VisitsSummary&actionToWidgetize=get&viewDataTable=graphEvolution";
+ referrersGetWebsitesUrl = baseUrl + "&moduleToWidgetize=Referrers&actionToWidgetize=getWebsites&filter_limit=5",
+ visitsSummaryGetUrl = baseUrl + "&moduleToWidgetize=VisitsSummary&actionToWidgetize=get&forceView=1&viewDataTable=graphEvolution";
function normalReportTest(format) {
it("should export a normal report correctly when the " + format + " export link is clicked", function (done) {
diff --git a/tests/UI/specs/RowEvolution_spec.js b/tests/UI/specs/RowEvolution_spec.js
index c6942fd714..00b3ec5c53 100644
--- a/tests/UI/specs/RowEvolution_spec.js
+++ b/tests/UI/specs/RowEvolution_spec.js
@@ -51,6 +51,7 @@ describe("RowEvolution", function () {
page.evaluate(function () {
$('select.multirowevoltion-metric').val($('select.multirowevoltion-metric option:nth-child(3)').val()).change();
});
+ page.wait(1000);
}, done);
});
diff --git a/tests/UI/specs/SegmentSelectorEditor_spec.js b/tests/UI/specs/SegmentSelectorEditor_spec.js
index c28c9e6cb4..2bb5721762 100644
--- a/tests/UI/specs/SegmentSelectorEditor_spec.js
+++ b/tests/UI/specs/SegmentSelectorEditor_spec.js
@@ -12,7 +12,8 @@ describe("SegmentSelectorEditorTest", function () {
this.timeout(0);
- var url = "?module=CoreHome&action=index&idSite=1&period=year&date=2012-08-09";
+ var generalParams = 'idSite=1&period=year&date=2012-08-09';
+ var url = '?module=CoreHome&action=index&' + generalParams + '#?' + generalParams + '&category=General_Actions&subcategory=General_Pages';
it("should load correctly", function (done) {
expect.screenshot("0_initial").to.be.captureSelector(selectorsToCapture, function (page) {
@@ -149,7 +150,9 @@ describe("SegmentSelectorEditorTest", function () {
});
});
- page.click('button.saveAndApply');
+ page.evaluate(function () {
+ $('button.saveAndApply').click();
+ });
page.click('.segmentationContainer');
}, done);
diff --git a/tests/UI/specs/Transitions_spec.js b/tests/UI/specs/Transitions_spec.js
index 7648b7c793..b0972775c9 100644
--- a/tests/UI/specs/Transitions_spec.js
+++ b/tests/UI/specs/Transitions_spec.js
@@ -16,7 +16,7 @@ describe("Transitions", function () {
it('should load the transitions popup correctly for the page titles report', function (done) {
expect.screenshot('transitions_popup_titles').to.be.captureSelector('.ui-dialog', function (page) {
- page.load("?" + urlBase + "#/" + generalParams + "&module=Actions&action=menuGetPageTitles");
+ page.load("?" + urlBase + "#?" + generalParams + "&category=General_Actions&subcategory=Actions_SubmenuPageTitles");
page.mouseMove('div.dataTable tbody tr:eq(2)');
page.mouseMove('a.actionTransitions:visible'); // necessary to get popover to display
@@ -26,7 +26,7 @@ describe("Transitions", function () {
it('should load the transitions popup correctly for the page urls report', function (done) {
expect.screenshot('transitions_popup_urls').to.be.captureSelector('.ui-dialog', function (page) {
- page.load("?" + urlBase + "#/" + generalParams + "&module=Actions&action=menuGetPageUrls&"
+ page.load("?" + urlBase + "#?" + generalParams + "&category=General_Actions&subcategory=General_Pages&"
+ "popover=RowAction$3ATransitions$3Aurl$3Ahttp$3A$2F$2Fpiwik.net$2Fdocs$2Fmanage-websites$2F");
page.mouseMove('.Transitions_CurveTextRight');
}, done);
diff --git a/tests/UI/specs/UIIntegration_spec.js b/tests/UI/specs/UIIntegration_spec.js
index 9703f28814..57bdb4c97c 100644
--- a/tests/UI/specs/UIIntegration_spec.js
+++ b/tests/UI/specs/UIIntegration_spec.js
@@ -43,11 +43,10 @@ describe("UIIntegrationTest", function () { // TODO: Rename to Piwik?
testEnvironment.save();
});
-
// dashboard tests
it("should load dashboard1 correctly", function (done) {
expect.screenshot("dashboard1").to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) {
- page.load("?" + urlBase + "#" + generalParams + "&module=Dashboard&action=embeddedIndex&idDashboard=1");
+ page.load("?" + urlBase + "#?" + generalParams + "&category=Dashboard_Dashboard&subcategory=1");
page.evaluate(function () {
// Prevent random sizing error eg. http://builds-artifacts.piwik.org/ui-tests.master/2301.1/screenshot-diffs/diffviewer.html
@@ -58,26 +57,26 @@ describe("UIIntegrationTest", function () { // TODO: Rename to Piwik?
it("should load dashboard2 correctly", function (done) {
expect.screenshot("dashboard2").to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) {
- page.load("?" + urlBase + "#" + generalParams + "&module=Dashboard&action=embeddedIndex&idDashboard=2");
+ page.load("?" + urlBase + "#?" + generalParams + "&category=Dashboard_Dashboard&subcategory=2");
}, done);
});
it("should load dashboard3 correctly", function (done) {
expect.screenshot("dashboard3").to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) {
- page.load("?" + urlBase + "#" + generalParams + "&module=Dashboard&action=embeddedIndex&idDashboard=3");
+ page.load("?" + urlBase + "#?" + generalParams + "&category=Dashboard_Dashboard&subcategory=3");
}, done);
});
it("should load dashboard4 correctly", function (done) {
expect.screenshot("dashboard4").to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) {
- page.load("?" + urlBase + "#" + generalParams + "&module=Dashboard&action=embeddedIndex&idDashboard=4");
+ page.load("?" + urlBase + "#?" + generalParams + "&category=Dashboard_Dashboard&subcategory=4");
}, done);
});
it("should display dashboard correctly on a mobile phone", function (done) {
expect.screenshot("dashboard5_mobile").to.be.capture(function (page) { // capture with menu
page.setViewportSize(480, 320);
- page.load("?" + urlBase + "#" + generalParams + "&module=Dashboard&action=embeddedIndex&idDashboard=5");
+ page.load("?" + urlBase + "#?" + generalParams + "&category=Dashboard_Dashboard&subcategory=5");
}, done);
});
@@ -85,7 +84,7 @@ describe("UIIntegrationTest", function () { // TODO: Rename to Piwik?
it('should load visitors > overview page correctly', function (done) {
expect.screenshot("visitors_overview").to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) {
// use columns query param to make sure columns works when supplied in URL fragment
- page.load("?" + urlBase + "#/?" + generalParams + "&module=VisitsSummary&action=index&columns=nb_visits,nb_actions");
+ page.load("?" + urlBase + "#?" + generalParams + "&category=General_Visitors&subcategory=General_Overview&columns=nb_visits,nb_actions");
}, done);
});
@@ -97,55 +96,49 @@ describe("UIIntegrationTest", function () { // TODO: Rename to Piwik?
it('should load visitors > visitor log page correctly', function (done) {
expect.screenshot("visitors_visitorlog").to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) {
- page.load("?" + urlBase + "#" + generalParams + "&module=Live&action=indexVisitorLog");
+ page.load("?" + urlBase + "#?" + generalParams + "&category=General_Visitors&subcategory=Live_VisitorLog");
}, done);
});
it('should load the visitors > devices page correctly', function (done) {
expect.screenshot("visitors_devices").to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) {
- page.load("?" + urlBase + "#" + generalParams + "&module=DevicesDetection&action=index");
+ page.load("?" + urlBase + "#?" + generalParams + "&category=General_Visitors&subcategory=DevicesDetection_Devices");
}, done);
});
it('should load visitors > locations & provider page correctly', function (done) {
expect.screenshot("visitors_locations_provider").to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) {
- page.load("?" + urlBase + "#" + generalParams + "&module=UserCountry&action=index");
+ page.load("?" + urlBase + "#?" + generalParams + "&category=General_Visitors&subcategory=UserCountry_SubmenuLocations");
}, done);
});
it('should load the visitors > software page correctly', function (done) {
expect.screenshot("visitors_software").to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) {
- page.load("?" + urlBase + "#" + generalParams + "&module=DevicesDetection&action=software");
- }, done);
- });
-
- it('should redirect the old UserSettings index to visitors > software', function (done) {
- expect.screenshot('usersettings_index').to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) {
- page.load("?" + urlBase + "#" + generalParams + "&module=UserSettings&action=index");
+ page.load("?" + urlBase + "#?" + generalParams + "&category=General_Visitors&subcategory=DevicesDetection_Software");
}, done);
});
it('should load the visitors > times page correctly', function (done) {
expect.screenshot("visitors_times").to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) {
- page.load("?" + urlBase + "#" + generalParams + "&module=VisitTime&action=index");
+ page.load("?" + urlBase + "#?" + generalParams + "&category=General_Visitors&subcategory=VisitTime_SubmenuTimes");
}, done);
});
it('should load the visitors > engagement page correctly', function (done) {
expect.screenshot("visitors_engagement").to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) {
- page.load("?" + urlBase + "#" + generalParams + "&module=VisitFrequency&action=index");
+ page.load("?" + urlBase + "#?" + generalParams + "&category=General_Visitors&subcategory=VisitorInterest_Engagement");
}, done);
});
it('should load the visitors > custom variables page correctly', function (done) {
expect.screenshot('visitors_custom_vars').to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) {
- page.load("?" + urlBase + "#" + generalParams + "&module=CustomVariables&action=menuGetCustomVariables");
+ page.load("?" + urlBase + "#?" + generalParams + "&category=General_Visitors&subcategory=CustomVariables_CustomVariables");
}, done);
});
it('should load the visitors > real-time map page correctly', function (done) {
expect.screenshot('visitors_realtime_map').to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) {
- page.load("?" + urlBase + "#" + idSite2Params + "&module=UserCountryMap&action=realtimeWorldMap"
+ page.load("?" + urlBase + "#?" + idSite2Params + "&category=General_Visitors&subcategory=UserCountryMap_RealTimeMap"
+ "&showDateTime=0&realtimeWindow=last2&changeVisitAlpha=0&enableAnimation=0&doNotRefreshVisits=1"
+ "&removeOldVisits=0");
}, done);
@@ -154,14 +147,14 @@ describe("UIIntegrationTest", function () { // TODO: Rename to Piwik?
// actions pages
it('should load the actions > pages page correctly', function (done) {
expect.screenshot('actions_pages').to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) {
- page.load("?" + urlBase + "#" + generalParams + "&module=Actions&action=menuGetPageUrls");
+ page.load("?" + urlBase + "#?" + generalParams + "&category=General_Actions&subcategory=General_Pages");
}, done);
});
// actions pages
it('should load the actions > pages help tooltip, including the "Report generated time"', function (done) {
expect.screenshot('actions_pages_tooltip_help').to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) {
- page.load("?" + urlBase + "#" + generalParams + "&module=Actions&action=menuGetPageUrls");
+ page.load("?" + urlBase + "#?" + generalParams + "&category=General_Actions&subcategory=General_Pages");
page.mouseMove('h2[piwik-enriched-headline]');
page.click(".helpIcon");
page.evaluate(function () {
@@ -172,43 +165,43 @@ describe("UIIntegrationTest", function () { // TODO: Rename to Piwik?
it('should load the actions > entry pages page correctly', function (done) {
expect.screenshot('actions_entry_pages').to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) {
- page.load("?" + urlBase + "#" + generalParams + "&module=Actions&action=menuGetEntryPageUrls");
+ page.load("?" + urlBase + "#?" + generalParams + "&category=General_Actions&subcategory=Actions_SubmenuPagesEntry");
}, done);
});
it('should load the actions > exit pages page correctly', function (done) {
expect.screenshot('actions_exit_pages').to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) {
- page.load("?" + urlBase + "#" + generalParams + "&module=Actions&action=menuGetExitPageUrls");
+ page.load("?" + urlBase + "#?" + generalParams + "&category=General_Actions&subcategory=Actions_SubmenuPagesExit");
}, done);
});
it('should load the actions > page titles page correctly', function (done) {
expect.screenshot('actions_page_titles').to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) {
- page.load("?" + urlBase + "#" + generalParams + "&module=Actions&action=menuGetPageTitles");
+ page.load("?" + urlBase + "#?" + generalParams + "&category=General_Actions&subcategory=Actions_SubmenuPageTitles");
}, done);
});
it('should load the actions > site search page correctly', function (done) {
expect.screenshot('actions_site_search').to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) {
- page.load("?" + urlBase + "#" + generalParams + "&module=Actions&action=indexSiteSearch");
+ page.load("?" + urlBase + "#?" + generalParams + "&category=General_Actions&subcategory=Actions_SubmenuSitesearch");
}, done);
});
it('should load the actions > outlinks page correctly', function (done) {
expect.screenshot('actions_outlinks').to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) {
- page.load("?" + urlBase + "#" + generalParams + "&module=Actions&action=menuGetOutlinks");
+ page.load("?" + urlBase + "#?" + generalParams + "&category=General_Actions&subcategory=General_Outlinks");
}, done);
});
it('should load the actions > downloads page correctly', function (done) {
expect.screenshot('actions_downloads').to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) {
- page.load("?" + urlBase + "#" + generalParams + "&module=Actions&action=menuGetDownloads");
+ page.load("?" + urlBase + "#?" + generalParams + "&category=General_Actions&subcategory=General_Downloads");
}, done);
});
it('should load the actions > contents page correctly', function (done) {
expect.screenshot('actions_contents').to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) {
- page.load("?" + urlBase + "#" + generalParams + "&module=Contents&action=index&period=day&date=2012-01-01");
+ page.load("?" + urlBase + "#?" + generalParams + "&category=General_Actions&subcategory=Contents_Contents&period=day&date=2012-01-01");
}, done);
});
@@ -233,115 +226,115 @@ describe("UIIntegrationTest", function () { // TODO: Rename to Piwik?
// referrers pages
it('should load the referrers > overview page correctly', function (done) {
expect.screenshot('referrers_overview').to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) {
- page.load("?" + urlBase + "#" + generalParams + "&module=Referrers&action=index");
+ page.load("?" + urlBase + "#?" + generalParams + "&category=Referrers_Referrers&subcategory=General_Overview");
}, done);
});
// referrers pages
it('should load the referrers > overview page correctly', function (done) {
expect.screenshot('referrers_allreferrers').to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) {
- page.load("?" + urlBase + "#" + generalParams + "&module=Referrers&action=allReferrers");
+ page.load("?" + urlBase + "#?" + generalParams + "&category=Referrers_Referrers&subcategory=Referrers_WidgetGetAll");
}, done);
});
it('should load the referrers > search engines & keywords page correctly', function (done) {
expect.screenshot('referrers_search_engines_keywords').to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) {
- page.load("?" + urlBase + "#" + generalParams + "&module=Referrers&action=getSearchEnginesAndKeywords");
+ page.load("?" + urlBase + "#?" + generalParams + "&category=Referrers_Referrers&subcategory=Referrers_SubmenuSearchEngines");
}, done);
});
it('should load the referrers > websites & social page correctly', function (done) {
expect.screenshot('referrers_websites_social').to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) {
- page.load("?" + urlBase + "#" + generalParams + "&module=Referrers&action=indexWebsites");
+ page.load("?" + urlBase + "#?" + generalParams + "&category=Referrers_Referrers&subcategory=Referrers_SubmenuWebsites");
}, done);
});
it('should load the referrers > campaigns page correctly', function (done) {
expect.screenshot('referrers_campaigns').to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) {
- page.load("?" + urlBase + "#" + generalParams + "&module=Referrers&action=menuGetCampaigns");
+ page.load("?" + urlBase + "#?" + generalParams + "&category=Referrers_Referrers&subcategory=Referrers_Campaigns");
}, done);
});
// goals pages
it('should load the goals > ecommerce page correctly', function (done) {
expect.screenshot('goals_ecommerce').to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer,.dataTable', function (page) {
- page.load("?" + urlBase + "#" + generalParams + "&module=Ecommerce&action=ecommerceReport&idGoal=ecommerceOrder");
+ page.load( "?" + urlBase + "#?" + generalParams + "&category=Goals_Ecommerce&subcategory=General_Overview")
}, done);
});
it('should load the goals > overview page correctly', function (done) {
expect.screenshot('goals_overview').to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer,.dataTable', function (page) {
- page.load( "?" + urlBase + "#" + generalParams + "&module=Goals&action=index");
+ page.load( "?" + urlBase + "#?" + generalParams + "&category=Goals_Goals&subcategory=General_Overview");
}, done);
});
it('should load the goals > management page correctly', function (done) {
- expect.screenshot('goals_manage').to.be.captureSelector('.centerLargeDiv,.top_bar_sites_selector,.entityContainer', function (page) {
- page.load( "?" + generalParams + "&module=Goals&action=manage");
+ expect.screenshot('goals_manage').to.be.captureSelector('#content,.top_bar_sites_selector,.entityContainer', function (page) {
+ page.load("?" + generalParams + "&module=Goals&action=manage");
page.wait(200);
}, done);
});
it('should load the goals > single goal page correctly', function (done) {
expect.screenshot('goals_individual_goal').to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer,.dataTable', function (page) {
- page.load("?" + urlBase + "#" + generalParams + "&module=Goals&action=goalReport&idGoal=1");
+ page.load("?" + urlBase + "#?" + generalParams + "&category=Goals_Goals&subcategory=1");
}, done);
});
// Events pages
it('should load the Events > index page correctly', function (done) {
expect.screenshot('events_overview').to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer,.dataTable', function (page) {
- page.load("?" + urlBase + "#" + generalParams + "&module=Events&action=index");
+ page.load("?" + urlBase + "#?" + generalParams + "&category=General_Actions&subcategory=Events_Events");
}, done);
});
// one page w/ segment
it('should load the visitors > overview page correctly when a segment is specified', function (done) {
expect.screenshot('visitors_overview_segment').to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) {
- page.load("?" + urlBase + "#" + generalParams + "&module=VisitsSummary&action=index&segment=" + segment);
+ page.load("?" + urlBase + "#?" + generalParams + "&category=General_Visitors&subcategory=General_Overview&segment=" + segment);
}, done);
});
// example ui pages
it('should load the example ui > dataTables page correctly', function (done) {
expect.screenshot('exampleui_dataTables').to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) {
- page.load("?" + urlBase + "#" + generalParams + "&module=ExampleUI&action=dataTables");
+ page.load("?" + urlBase + "#?" + generalParams + "&category=ExampleUI_UiFramework&subcategory=ExampleUI_GetTemperaturesDataTable");
}, done);
});
it('should load the example ui > barGraph page correctly', function (done) {
expect.screenshot('exampleui_barGraph').to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) {
- page.load("?" + urlBase + "#" + generalParams + "&module=ExampleUI&action=barGraph");
+ page.load("?" + urlBase + "#?" + generalParams + "&category=ExampleUI_UiFramework&subcategory=Bar%20graph");
}, done);
});
it('should load the example ui > pieGraph page correctly', function (done) {
expect.screenshot('exampleui_pieGraph').to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) {
- page.load("?" + urlBase + "#" + generalParams + "&module=ExampleUI&action=pieGraph");
+ page.load("?" + urlBase + "#?" + generalParams + "&category=ExampleUI_UiFramework&subcategory=Pie%20graph");
}, done);
});
it('should load the example ui > tagClouds page correctly', function (done) {
expect.screenshot('exampleui_tagClouds').to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) {
- page.load("?" + urlBase + "#" + generalParams + "&module=ExampleUI&action=tagClouds");
+ page.load("?" + urlBase + "#?" + generalParams + "&category=ExampleUI_UiFramework&subcategory=Tag%20clouds");
}, done);
});
it('should load the example ui > sparklines page correctly', function (done) {
expect.screenshot('exampleui_sparklines').to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) {
- page.load("?" + urlBase + "#" + generalParams + "&module=ExampleUI&action=sparklines");
+ page.load("?" + urlBase + "#?" + generalParams + "&category=ExampleUI_UiFramework&subcategory=Sparklines");
}, done);
});
it('should load the example ui > evolution graph page correctly', function (done) {
expect.screenshot('exampleui_evolutionGraph').to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) {
- page.load("?" + urlBase + "#" + generalParams + "&module=ExampleUI&action=evolutionGraph");
+ page.load("?" + urlBase + "#?" + generalParams + "&category=ExampleUI_UiFramework&subcategory=Evolution%20Graph");
}, done);
});
it('should load the example ui > treemap page correctly', function (done) {
expect.screenshot('exampleui_treemap').to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) {
- page.load("?" + urlBase + "#" + generalParams + "&module=ExampleUI&action=treemap");
+ page.load("?" + urlBase + "#?" + generalParams + "&category=ExampleUI_UiFramework&subcategory=Treemap");
page.wait(2000);
}, done);
});
@@ -377,32 +370,32 @@ describe("UIIntegrationTest", function () { // TODO: Rename to Piwik?
it('should not display API response in the content', function (done) {
expect.screenshot('menu_apidisallowed').to.be.captureSelector('#content', function (page) {
- page.load("?" + urlBase + "#" + generalParams + "&module=API&action=SitesManager.getImageTrackingCode");
+ page.load("?" + urlBase + "#?" + generalParams + "&module=API&action=SitesManager.getImageTrackingCode");
}, done);
});
// Ecommerce
it('should load the ecommerce overview page', function (done) {
expect.screenshot('ecommerce_overview').to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer,.dataTable', function (page) {
- page.load("?" + urlBase + "#" + generalParams + "&module=Ecommerce&action=ecommerceReport&idGoal=ecommerceOrder");
+ page.load("?" + urlBase + "#?" + generalParams + "&category=Goals_Ecommerce&subcategory=General_Overview");
}, done);
});
it('should load the ecommerce log page', function (done) {
expect.screenshot('ecommerce_log').to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) {
- page.load("?" + urlBase + "#" + generalParams + "&module=Ecommerce&action=ecommerceLogReport");
+ page.load("?" + urlBase + "#?" + generalParams + "&category=Goals_Ecommerce&subcategory=Goals_EcommerceLog");
}, done);
});
it('should load the ecommerce products page', function (done) {
expect.screenshot('ecommerce_products').to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer,.dataTable', function (page) {
- page.load("?" + urlBase + "#" + generalParams + "&module=Ecommerce&action=products&idGoal=ecommerceOrder");
+ page.load("?" + urlBase + "#?" + generalParams + "&category=Goals_Ecommerce&subcategory=Goals_Products");
}, done);
});
it('should load the ecommerce sales page', function (done) {
expect.screenshot('ecommerce_sales').to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer,.dataTable', function (page) {
- page.load("?" + urlBase + "#" + generalParams + "&module=Ecommerce&action=sales&idGoal=ecommerceOrder");
+ page.load("?" + urlBase + "#?" + generalParams + "&category=Goals_Ecommerce&subcategory=Ecommerce_Sales");
}, done);
});
@@ -571,8 +564,10 @@ describe("UIIntegrationTest", function () { // TODO: Rename to Piwik?
it('should load the widgets listing page correctly', function (done) {
expect.screenshot('widgets_listing').to.be.captureSelector('.pageWrap', function (page) {
page.load("?" + generalParams + "&module=Widgetize&action=index");
- page.mouseMove('.widgetpreview-categorylist>li:contains(Visits Summary)');
- page.mouseMove('li[uniqueid=widgetVisitsSummarygetEvolutionGraphcolumnsArray]');
+
+ page.mouseMove('.widgetpreview-categorylist>li:contains(Visitors)');
+ page.mouseMove('.widgetpreview-widgetlist li:contains(Visits Over Time)');
+ page.click('.widgetpreview-widgetlist li:contains(Visits Over Time)');
page.evaluate(function () {
$('.formEmbedCode').each(function () {
var val = $(this).val();
@@ -622,7 +617,7 @@ describe("UIIntegrationTest", function () { // TODO: Rename to Piwik?
// date range clicked
it('should reload to the correct date when a date range is selected in the period selector', function (done) {
expect.screenshot('period_select_date_range_click').to.be.capture(function (page) {
- page.load("?" + urlBase + "#" + generalParams + "&module=VisitTime&action=index");
+ page.load("?" + urlBase + "#?" + generalParams + "&category=General_Visitors&subcategory=VisitTime_SubmenuTimes");
page.wait(1000);
page.click('#date.title');
// we need to make sure there to wait for a bit till date is opened and period selected
@@ -677,7 +672,7 @@ describe("UIIntegrationTest", function () { // TODO: Rename to Piwik?
});
it('should load the segmented visitor log correctly when a segment is selected', function (done) {
- var url = "?module=CoreHome&action=index&idSite=1&period=year&date=2012-01-13#?module=CustomVariables&action=menuGetCustomVariables&idSite=1&period=year&date=2012-01-13";
+ var url = "?module=CoreHome&action=index&idSite=1&period=year&date=2012-01-13#?category=General_Visitors&subcategory=CustomVariables_CustomVariables&idSite=1&period=year&date=2012-01-13";
expect.page(url).contains('.ui-dialog > .ui-dialog-content > div.dataTableVizVisitorLog:visible', 'segmented_visitorlog', function (page) {
page.click('.segmentationTitle');
page.click('.segname:contains(From Europe)');
@@ -687,4 +682,4 @@ describe("UIIntegrationTest", function () { // TODO: Rename to Piwik?
page.click('a.actionSegmentVisitorLog:visible');
}, done);
});
-}); \ No newline at end of file
+});
diff --git a/tests/lib/screenshot-testing/support/chai-extras.js b/tests/lib/screenshot-testing/support/chai-extras.js
index 29c2d4f47b..576229946e 100644
--- a/tests/lib/screenshot-testing/support/chai-extras.js
+++ b/tests/lib/screenshot-testing/support/chai-extras.js
@@ -74,7 +74,7 @@ function capture(screenName, compareAgainst, selector, pageSetupFn, comparisonTh
processedScreenshotPath = getProcessedScreenshotPath(screenName);
- screenshotDiffDir = path.join(options['store-in-ui-tests-repo'] ? uiTestsDir : dirsBase, config.screenshotDiffDir);
+ screenshotDiffDir = path.join(options['store-in-ui-tests-repo'] ? uiTestsDir : dirsBase, config.screenshotDiffDir);
if (!fs.isDirectory(screenshotDiffDir)) {
fs.makeTree(screenshotDiffDir);
@@ -170,7 +170,7 @@ function capture(screenName, compareAgainst, selector, pageSetupFn, comparisonTh
} else {
testFailure += "(image magick error: " + numPxDifference;
}
-
+
testFailure += ")\n";
}
}
@@ -379,7 +379,7 @@ chai.Assertion.addChainableMethod('contains', function () {
stack += indent + "View the captured screenshot at '" + capturePath + "'.";
} else {
stack += indent + "NOTE: No screenshot name was supplied to this '.contains(' assertion. If the second argument is a screenshot name, "
- + "the screenshot will be saved so you can debug this failure.";
+ + "the screenshot will be saved so you can debug this failure.";
}
stack += getPageLogsString(pageRenderer.pageLogs, indent);
diff --git a/tests/lib/screenshot-testing/support/page-renderer.js b/tests/lib/screenshot-testing/support/page-renderer.js
index 81fa28e238..5c92abb276 100644
--- a/tests/lib/screenshot-testing/support/page-renderer.js
+++ b/tests/lib/screenshot-testing/support/page-renderer.js
@@ -457,11 +457,11 @@ PageRenderer.prototype.capture = function (outputPath, callback, selector) {
callback();
}, timeInMsToWaitForReRenderToFinish);
-
+
} else {
callback();
}
-
+
} catch (e) {
self.webpage.clipRect = previousClipRect;